I’m working on a multiplayer game, a Server Client model where the Server processes the inputs of the clients and sends the world state in a timely manner. The clients render the world 100ms in the past in order to be able to interpolate and extrapolate networked entities and make it work smoothly.
I need to validate the inputs of the players in the server, and since the player’s world is rendered 100ms in the past, when I get an input from the player sometimes I need to recreate the state of the world 100ms in the past in the server.
Some of these validations require physics validations, for example:
When the player pressed the grab button, was the object they wanted to pick colliding with the raycast that represents their reach a 100ms in the past?
When the player jumped from a moving platform, what was the resulting position of adding their movement and the platform’s momentum a 100ms in the past?
I’ve read that I’d have to use the PhysicsServer3D, but I’m struggling to find tutorials/advice/guides on how to use it. Are there any resources that talk a little bit more in depth about this? External blogs/tutorials are welcome, anything else than the basic Godot docs if that were possible.
I made a crude script to mess with the physics state using a multiplayer synchronizer. it could use some improvements but should get you started.
I want to adjust your perspective a little bit…
This is true so remember this…
The player will have a ping, and lets say this is a round-trip of 100 ms. half is 50 ms. (one-way server to client)
Even though client is using state 100ms old, the server won’t see the players response until 200 ms later. (100ms state delay + ping rt)
From the perspective of the server the client is ahead of the server in time. And it will be since the client is trying to predict the server to allow a more responsive client.
Wow! Thanks for all the useful links and references, I’ve been trying to digest everything but I’m still re-reading stuff to be sure I understand everything correctly.
I’ve got still a question though: I see in your script how to directly access the body state and alter position/rotation/etc.
However I still don’t quite see where or how to “simulate” the rest of the physics “ticks” between when the correction has to be applied and the current time.
If you watched the Overwatch video they provide an example where Tracer gets stun mid movement and the client applies correction, then re-simulate the rest of the ticks until the present moment (applying the player input in between those 2 points in time)
So apart from snapping the player back to the expected position at that point in time, I have something like “let the physics do their thing for 5 more ticks while reapplying the input from the player for those ticks”?
All of that within the same Godot frame, I think? That’s the part I don’t quite see how to do. Some method like “do physics update” that you can manually trigger?
Thanks for taking the time to read and respond btw, I truly appreciate it.
So that script is a bear bone. I was reading the gaffer on game articles. (Which has been awhile now)
I intend to let the client and server physics run independently from each other and fix any non deterministic physics events or dropped packet states on the fly.
so Godot’s network api is a little opaque in the sense that it isn’t well documented and the actual networking aspect is abstracted away inside the packetpeer class. When it creates a packet I’m not sure if it’s per RPC call, MultiplayerSynchronizer replication. Or do they smoosh as much as possible into the packet possibly fragmenting some update into two packets. … anyway
Regarding the validation stuff. The client side prediction and validation should happen on the client. Because the server should only receive player input. The server acts on that input and sends the game state back to the client. The client decides if they need to correct their position and how they should do it to not distract the users experience. To help with this you could expand the script to save the states for 5 frames from the server and the server could also add the player input it used in those frames. The client should can hold state for X frames of the past depending on the ping and server frame buffer size.
This way the client can delay the incoming server state to reduce network jitter and then check to see if it’s past frame relative to the server frame and input and actions matches up with what the client did and saw.
The client and server probably should have their clocks synchronized so they can determine what relative frame each is operating on and that clock state could be stored with each frame…
At this point it’s been too long since I read up on those things to remember how this should actually work. But I definitely need to revisit my script at some point in time to make these improvements, but I’m distracted with other tasks ATM.
Networking is hard and I’m still learning, I hope to be getting back into it. One thing I may get into is extending the packetpeer or making my own custom version. I’ll keep you posted when I get back to it.
Here is another resource in Godot 3 that I found useful.
He uses dictionaries, but I found them to be bandwidth heavy. He also uses RPCs but I think MultiplayerSynchronizers can easily substitute and are definitely easier to use and make the code cleaner.
Thanks for the response! So if i understood everything correctly, one shouldn’t really re-run the physics ticks locally in the client but rather, when mismatch is found, the client tries to apply the correction (or corrections) as smoothly as possible for some frames (to not distract the player, as you mentioned).
That makes more sense, I have yet to think how to implement all of this haha.
I will have to re-read everything more slowly trying to digest everything, as you said this is rather difficult xD
Yes don’t worry, you’ve helped me a lot, I’m more than satisfied at least I have a lot to process and work on from here onwards.
Yes I know them! This is the video series I followed to get started
Again thanks for all the help, hopefully I can update this in some time with my end result or something