Is this a good solution for Grid Inventory exploiters/lag?

I am developing a grid style inventory, which already has some functions like stacking items and chest opening:

The problem is that cheaters could mess up the inventory on client side. Also, if two players try to move the same item on a chest both would collect them, because the server wouldn’t have noticed it.

I tried this solution: the client checks if the inventory operation is possible (like moving an item to a chest). If it is, then the operation is finished on the client. After that, it sends an information of the slots used, chests used if any, and the items involved in it with its id and info like stack size, to the server. There, the operation is put on a queue, in order for the server to follow the events that happened on the client in the same order. The server then rechecks the operations. If they are possible on the server, the changes also happen on it. If it isn’t, the server returns a result of false, which then forces the client to reupdate the inventory grids to the version of the server.

Is this correct, or is there something wrong with this solution? I think games like minecraft also do this, because when it lags a lot and the server doesn’t register some inventory changes my inventory would go back to a previous state too.

Yeah it seems like you’ve pretty much got it right by not trusting the client to manage any important data and also keeping the client’s view up-to-date when it inevitably messes something up because of latency causing impossible item-movement requests to be denied by the server. Hard to say for sure without seeing code, but at least I can confirm you’ve got the right idea.

Why should the server which inventory slot the item used to be in, or the size of a stack of items? Seems to me the worst that could happen is that a cheater moves items from one item slot to another. No sense in preventing cheaters from doing things that are already legitimately possible and easy to do. If you’re talking about stack size limits then you shouldn’t allow the client to tell the server about that, the server should be the authority on that.

This won’t make a difference if the queue is ordered by the time-of-arrival for the requests to move items around. The only way you can get close to guaranteeing that these requests are processed in order of when the requests were sent is to have a synchronized clock between the server and all the clients, and having clients send timing information along with requests. This might be important if you want players to have the experience of rushing over to a chest and quickly grabbing the best loot before the other players. In that case it matters a lot that item movement requests are processed in a fair order, in addition to making it a much more likely event that the requests will arrive out of order (because they happen close to each other in time).

If that’s not part of your game, you probably shouldn’t worry about this at all.

Besides, item-movement requests shouldn’t really take any amount of time to process and even if they did you don’t need to hold them in any kind of data structure. If there’s a need for a queue to hold request information then it’s already handled by whatever RemoteEvent.OnServerEvent does. You will never get “dropped events” using those, and they will never be processed concurrently unless your code yields, so no race conditions to worry about either.

Oh and it’d open you up to cheaters sending requests with false timing info or whatever. Having your game depend on the client’s clock means the server is no longer 100% authoritative.

1 Like

Well, the the info is about the slots that are used so the server doesn’t need to make interation on the inventory to find them, and the id and stack of an item is just so the server check if it got the information right. The queue is more of a security measure, because I also believe that the remoteevents/functions fire in order of arrival, and I use that order to make the queue, because maybe the code I made to check on the server takes more time in some cases than in others because of its specific conditions? (that’s what I think at least). I got some sync errors before doing that so I went ahead and made the queue system and it seemed to fix this issue.

1 Like

I’m actually working on a similar system like this!

On the client side, what I’m doing is making the inventory management and movement entirely local. If a player moves an item from one slot to the other in their own inventory, that change is not replicated to the server. However, if the client wants to move an item in a server-owned inventory (ex: a chest), that change is replicated.

On the server, each player’s inventory is just a list of items and their quantity, with no slot attached to each. If the client wants to pick something up off the ground, here is what would happen:

  • The client tells the server it wants to pick up an item
  • The server looks at the player’s server-sided inventory and checks to see if it’s possible to pick up an item with the current amount of items in the player’s inventory (as well as basic anticheat measures)
  • The server then asks the client how much they want to pick up, if they have any space (players may have organized their inventory to where they may be able to pick up a certain amount)
  • If the client has space, the client tells the server how much of the item it can pick up
  • The server finalizes everything, telling the client that it may pick up those items
    (These steps can be optimized a little, I just made sure there was detail and clarity)

The server has to be a little more strict when it comes to server-sided inventories (ex: chests again). These inventories are similar to the player’s inventories, but instead have slots associated with each item:

  • The client tells the server what items it wants to move
  • The server checks to see if the slot is empty/can be filled
  • If possible, the server tells that client that the movement is allowed (this step is to prevent players from having latency issues)
  • Finally, the server replicates that action to each client. If that action was not allowed, the server tells the client who performed the action and gives it an updated table of items.

Your system may potentially be laggy because when one slot changes, it replicates the entire inventory, then updates the entire GUI. If possible, make it so that only the changes are reflected in the inventory.

1 Like

Yeah It’s similar to mine. My Inventory have these subsections: HotBar(10 slots), Storage (30 slots), Equips(6 special slots for, 1 for each equip type) and Chest(updates when a chest is opened, can’t be edited if you get away from them).
On the server side inventory, there’s just Folders that represent thos subsections (except chest, which is located inside the physical chests). Inside those folders are values named after the respective position an item is (for example, the 23 stack of logs would be inside the HotBar folder with a name of “5” that represents its slot. Attributes were set to indicate the item id and stack amount. A module sets the details each item id has in case I need them, like the item type, maximum stack size, description, etc. If I do want to make a storage increase feature (like backpacks idk) I can always set the Storage slot amount on the server to whatever I want, and then I just make it generate the slots on the client.

1 Like