Multiplayer Inventory - should server handle inventory to prevent cheating?

Hi, I’m thinking of working on a multiplayer inventory system… I wanted to confirm my thoughts on potential cheating.

Here’s how I understand it: if you have the server handle a players inventory, for example: player picks up item → server updates that players inventory using the item… then that would prevent cheating, yes?

Or another example: if a player swaps two items in the inventory, the server would also have to handle that change, otherwise someone could mess with the item values…

Am I understanding how this works correctly?

That sounds about right, and in my experience, if you try to do something with an item that the server doesn’t think you have, it won’t replicate its effects.

There is also a set of networked inventory tutorials on the community content section of the forum I believe. :slight_smile:

Is there? Well, I’ll check it out of needed, but I’m wanting to do this 100% from scratch on my own. Hope it goes well.

Thanks for the reply. I wish I knew how to cheat so I could try to break my own stuff…

Yes, if you don’t want a player to cheat, you will need to keep all the inventory actions on the server. So even if a player changes its inventory somehow, the server has the valid one
and the server will decide if there is an item or not.

If a player picks up an item, the server adds it to the inventory and tells the client to update its own one too (or replicate it). If the client now packs an item into his inventory by cheating,
it will only exist on his inventory. If he wants to use it, the server will check if the item is really in that slot, if not, he won’t do anything, or maybe kick the player.

But you need to be strict here. If you, for example, only let the Inventory adding be done by the server, but not the pickup trace, the client could tell the server “hey i picked this item up,
even though it is not at this place on your end”. So you need to let the server do EVERYTHING that would make cheating possible.

So if the player wants to pick up an item, then the server does the line trace on it’s end to see if the item is actually there?

Yeb basically the client can be seen as a remote control to the character on the server create stuff with that in mind.

I’m wondering this too… Right now I have the client create its own line trace → server picks up item. Does the line trace need to be creating by the server, too? For every client?

Actually it’d be fine to allow the client to add the item, and then the server would check… this would reduce overall laggyness for the client when he’s not doing anything wrong, and if the server detects a problem then it would not only not update it serverside but also tell the client to remove it… I hope that makes sense.

The easiest way is to think of inventory as a two-part entity. It has ‘contents’ which are the server’s responsibility to maintain and the UI part which is the client’s one. You do all the actions on the server which updates the ‘contents’. And then you can have a RepNotify which will update the UI on the client on ‘contents’ change. This way you have two separate parts which can be maintained on its own.

I’m finishing working on my networked persistent inventory and will put out the design and implementation in the nearest future.

Thanks for your reply! Just a couple of questions…

Currently I have my inventory information stored in playerState… However now I’m not sure whether I should have the server update the clients UI, or the client itself.

Perhaps I fundamentally still don’t understand how cheating would work… But, if I had the client do it… Would the client first have to gain access to the playerState info… And then wouldn’t someone be able to change the information? And now that I think about it… Doesn’t the client already have access to the playerState information? Am I storing it in the wrong place?

Second question… How can I use RepNotify to update the UI? I was going to simply have a function that is called that would update the UI using the info in playerState.

EDIT: Something I haven’t used is “Switch has Authority”. I have a feeling I should be using this to prevent the things I am worried about. I just don’t understand the difference between that and simply “Run on Server”…

I do most of my coding in C++, so I’m not exactly sure how you do RepNotify in Blueprints, but I think this page has the answer - 1.4 - Variable Replication [RepNotify] | Unreal Engine Documentation

Conceptualy, you just have some variable, TArray<YourInventoryItemThing>. You make it replicated, using RepNotify. This is your actual inventory, you only work with it using server RPC calls or direct calls on the server. Then you would have some UI generation function, which you will launch when your inventory is replicated to the client. I would put this variable on you pawn, for instance. Because it has both server and client representations. And you don’t usually want other players to know about your inventory contents. So you can make your inventory replicated only to owner (= your pawn).

UI generation function in pseudo-code:

for item in inventory
get item properties
if new item
create UI widget
update existing widget properties

As for cheating, the client can make UI show something else, like 1 000 000 $ instead of a 1 000 $, but it doesn’t matter because when he tries to use his money, he would call a server RPC and the server knows that the player has 1 000 $. Replication only works server -> client. So as long as you don’t run gameplay logic on your client, you don’t really care what happens there.

I made a custom Component and added this to my PlayerState and not the PlayerPawn. Although it shouldn’t matter.

I also have a RepNotify on my Inventory and if it gets called, i delete all Item Widgets in my Inventory and recreate the
based on the new InventoryArray.

It’s pretty straight forward once you started.

And no, you don’t need to let the Server do the trace if you don’t want. But that would just be an extra + for anti cheating.
Who knows what cheaters come up with (: