How to check DragDrop state on server?

Hello,

I have a box in my game world, and anyone can use it to store something, and the box have more than one grid. I use the UDragDropOperation (parent class is UObject) to handle user drag operation.

And I encounter a multi-player problem:
If two players handle the same grid, the item in box will be duplicated for both of them. So I just want to know how to check whether the current box slot is draged by others?

Firstly, I cannot use the rpc to check it, becouse the rpc method has not return value, I cannot know the rpc result at first time.

Anyone can tell me if there has more effective method to check it?

I’m really not particularly familiar with how the modern Unreal UI stuff works, but I can almost guarantee that the UI is not replicated over the network.

Without knowing anything about your class structure, or anything else in your project, how I’d probably tackle a problem like that, is by creating a AGameState subclass, and using that to keep track of whatever is in the box, and replicating whatever information is necessary across the network. Then whatever UI is in place will have access to that information at all times.

Thank you for your reply.

The Box actor is replicated, and it record the box slot index and the item id which be stored.

And my problem is, if someone drag the box slot, others cannot drag it. The drag behavior performed locally, and I must check it on server. In other words, The UDragDropOperation Instantiate after server check passed. But RPC method have not return value so that I cannot know the check result on time.

In general, Replicated functions tell the receiver “do something”, replicated properties are good for getting information between client and server.

@eblade is right: UI is not replicated. UI is for letting the player express what they want.

It sounds like you need a server-to-client replication stream of updates to contents-of-slot of the box. This would presumably run whenever the box changes, no matter whether the user has the box open or not.

If the user happens to have the box open, and slots come and go, then the user will see them update.

Then you want a client-to-server request saying “put thing A in slot B.”

The server would then respond with a message that says "putting thing A in slot B succeeded, " or “putting thing A in slot B failed.”

So, the flow for the client is:

  1. drag-and-drop shows “red” when a slot is already occupied ON THE CLIENT, but allows dropping when a slot is not occupied ON THE CLIENT
  2. after drop, the item disappears from the cursor, and should be marked “not currently available for use,” but doesn’t YET appear in the slot. Perhaps some simple animation is played on the cursor.
  3. when the server responds “item put succeeded,” then the not-currently-available item is removed from the player inventory, and some “success” effect (like a sound and particle system) is played
  4. when the server responds “item put failed,” then some animation/sound/effect is played to deny the action, and the item is again marked “can be used” in local inventory.

The specific animations/effects you use while the item is in indeterminate state, is up to your game design – could be some kind of flying/zooming animation, could be particle systems, could be sounds, could just be some text in a box on the screen.

The flow on the server is:

  1. Receive “put item A in slot B” from player P
  2. Verify that player P has item A. If not, ignore request.
  3. Verify that slot B is available.
  4. If it is, put item A there, and send the success response.
  5. If it is not, send the failure response.
  6. Regular replication will also let all players know what’s actually in the slots of the box.

Note that the “putting” player may get both “success” messages, and “box contents updated” messages, and may get them OUT OF ORDER, so be prepared to appropriately merge those updates (basically, if the object is already in the slot when you try to put it there, remove it from inventory without needing to update the slot further.)

1 Like

@jwatte Actually, I do that like you said, but it also has some problem, such as:

  1. The box slot 1 has the item 1, and slot 2 has item 2.
  2. Player A and Player B drag the same box slot 1 at the same time (both them can be drag sucessfully, because both rpc and property replicate need some time).
  3. Server get Player A request and marked this slot “Player A use it”, Player B request ignored (but Player B doesn’t know his request is ignored locally).
  4. Player A drop the item to box slot 2, and slot 2 already has something, so slot 1 and slot 2 switched the items (slot 1 has item 2, slot 2 has item 1).
  5. Player A swich slot 1 and slot 2 item like operation 4 (slot 1 has item 1, slot 2 has item 2).
  6. At this time, Player B drop the item to slot 2(slot 1 and slot 2 already “can be use”), so slot 1 and slot 2 has the same item, both slot 1 and slot 2 have item 1, and item 2 disappeared.

So I think, if I want to slove this problem, I must check from server whether the slot can be use when I drag.

@jwatte Could you give me some idea about this scene? I cannot find the way to solve this. Thank you very much.

That’s not what I said. I said player B should get a negative acknowledge when the RCP to “put thing from player B into slot” comes in.

If you support moving things between slots then you will need to additionally model that out in your interaction model. What I suggested was the basics for going to/from player inventory.

That being said:

  • Make each “box operation” RPC be a transaction, that can succeed or fail.
  • The three kinds of operations you’ve suggested exist so far are “move from inventory to box,” “move from box to inventory,” and “move between slots in inventory,” so each of those need a separate RPC request kind.
  • When the player sends this request (attempts to do the thing in the UI) then you DO NOT immediately update the local state. Instead, you put the player in a “don’t know the outcome yet” state.
  • When the server gets the request, it checks the entire transaction for whether it can succeed, or fail. This means checking server-side inventory, checking box slot state, etc.
  • If it can’t succeed, you send back a negative acknowledge to the player, which plays a “sorry” effect and lifts the “pending” state.
  • If it will succeed, you send back a positive acknowledge to the player, which plays a “success” effect and lifts the “pending” state.

If you model “moving” as a single operation, then if player 2 tries to move item X from slot 2 to slot 1, and item X doesn’t exist in slot 2 when the RPC comes in, that transaction should fail. Each player can click on the item and try to do something with it, but whoever commits first, will succeed, and the other, will fail, because the source is no longer what they claim it was. Yes, this means that item operations need to include “source” as well as “destination.”

If you instead model moving things in slots as “take one item out when starting to move” followed by a separate “put one item in when stopping to move,” then the “start moving a thing” CAN FAIL – e g, you can’t drop an item before you’ve taken it out, so it’s impossible for A and B to move the same item at the same time.

@jwatte Thank you so much for reply, and I will try to do it with transaction like you said.
But I search the document of unreal engine 4.26, and cannot find anything about Transaction, Where can I find the usage of it?

it’s more of a concept, than some existing code. like a database transaction, when you put something to a remote database, you begin a transaction which locks the tables from other people changing them, then put your information in, and then end the transaction, allowing others to make changes to that table again.

Yes, I may be misunderstand the @jwatte meaning. But is it possible to use Transaction like do/undo in editor?

Transaction for do/undo is different from what I meant by “transaction” above.
What I meant by “transaction” above was simply an operation (invoked by RPC) that either completes fully, or does nothing.
Typically, in Blueprint, you can implement these as a function, because blueprint functions do not get interrupted / threaded. If you instead use event flows, those graphs can pause and let other things run (which is necessary for nodes like Delay)

The server should never know whether a user’s cursor currently “has” an object. The server just needs to know what’s in the user’s inventory, and what’s in the box-slots. The tree operations (transactions) you need to expose through RPC are:

  1. Take item PI from player inventory, and put in box slot BS. On the server, if the player-inventory doesn’t contain the item, or the box-slot is not empty, this fails, else the operation is completed.
  2. Take item BI from box slot BS and put in player inventory. On the server, if the item BI is not in slot BS, then the operation fails, else it is completed.
  3. Swap box-slot-item BI1 from slot BS1 and box-slot-item BI2 in slot BS2. One of these items may be “None” for empty slots. If the box slots BS1 and BS2 contain the items indicated, then the operation succeeds, else it fails.

Player should be told about success/failure, and it’s up to you to implement the “operation is currently pending” logic in your UI, until you hear success/failure.