Currently working on a multiplayer game where players are able to pick up tools to use. I understand that all gameplay logic should run on the server for validation purposes, however, this also feels kind of wrong because it feels like there will be visible latency for the player grabbing the object.
My current code basically has the player send out a server rpc to grab an object and then the server sends out a multicast to all the clients basically telling the clients to attach the object to the player.
Would it be better if the player just grabbed the object client-side first then sent out a server rpc confirming this is valid and if it wasn’t valid just reversing it? If so how would I go about reversing it? would it be a client RPC from the server to the client telling it.
And more importantly is it worth it to do it that way?
You can check the necessity by setting an imitation of a bad Internet connection in the project settings. If, with a ping of 100-300 ms, the result suits you, then, in my opinion, you should not unnecessarily complicate the logic, but most likely it will look very jagged.
In this case, the algorithm you described with prediction of the result from the server and subsequent confirmation is what you need.
The response from the server must contain a reference to the actor to which the object that was raised should be attached, the name of the socket or local coordinates.
If the reference is not valid, then you need to unpin the object and set its world coordinates to those received from the server.
I’m not sure if this is an ideal solution, but that’s what I would do. At least for starters.
The way I do it is client attempts interaction. If Valid (something can be interacted with), RPC the server to interact, then play an pickup/grab etc montage. This facilitates responsiveness to the client. “Hey my character is attempting to do something”.
Server attempts interaction, IF valid it spawns and attaches the item, and sets replicated vars as needed for the new state.
Pickup/drop actors are set to replicate. This in turn means there’s no need to Multicast.
Ok thank you both for the answer, one more question though. So if one of my clients had an invalid interaction would I just use a Client RPC to tell the client to detach the picked up object and move it back to it’s original position?
I know that I should probably be only using Client RPCs for transient information so is there a better way to resync the client with the server?
As the Rev0verDrive said instead (together) of RPC it is better to use RepNotify variable. In this case, the structure will contain a reference to the actor to which you need to attach, and the binding coordinates.
This way you can set up the binding correctly if a player joins after you pick up the item.
However, if we add the ability for the client to take an item based on client data, then a client RPC to unbind is still necessary. Otherwise, it will cause visual bugs.
They will be corrected the moment the player tries to take another item.
It seems to me that it would be worthwhile to make a universal component that would manage actor replication and attachment.
Personally I wouldn’t have the client do any “Authoritative” actions… attaching items it doesn’t yet own. This just bloats the codebase where it isn’t warranted.
Have to remember we are talking about milliseconds for RPC’s to reach the server. Then typically one server tick (33.333ms @30Hz) for processing and sending the result.
Average human blink is 300-400ms.
This is why I use a montage to fill the wait time. The pickup montage is roughly 2s. That’s 2,000ms.
Even with a 500ms ping the player will be updated before the montage ends.