Question about network de-syncing

I’m creating a side-scrolling running race/obby type game. Players advance through the courses via the X-axis, so I am checking placements (of who is 1st, 2nd, 3rd, etc) by comparing their HumanoidRootPart’s X positions.

My issue that I found through brief testing is that clients see other clients in different positions, and that will cause people to become very frustrated when they thought they were in first place but the game awards the win to the person behind them.

Currently, when a value on the server is set to true, the clients recognize this, and then the clients move their character’s humanoids to the end location. There is already de-syncing since not every client is going to recognize the value change at the exact same time, so I’m really in a pickle right now.

My question is: what would be the most optimal way to sync positions and check placements?

Image of the game so far

3 Likes

Calculate other clients’ ping latency and make the client move other players ahead where they should be based on the latency time. This isn’t foolproof though, especially if a client’s connection isn’t stable (spiking ping times) or variable character speed.

1 Like

A while ago I wrote a module to handle network sensitive tasks such as this, you can find it here.

The module allows you to calculate the difference between tick on the server and the client to some degree of accuracy, which means by sending tick over with requests from the client, the server can estimate how long it took. Using this you can easily work out how far behind clients are appearing to other players and adjust their positions accordingly to compensate.

I also added in a way to verify the ticks sent over by the client are consistent, if they’re not you can use this to reject requests.

The readme should explain it in enough detail, but if you have any questions I’ll be happy to answer them.

5 Likes

But… Doesn’t os.time exist so you don’t have to do that complicated tick() comparison.

os.time() is not guaranteed to be the same value between clients and servers, or between clients. It is only guaranteed to be approximately the same value between servers. tick() and os.time() can both be faulty client-side if the player’s device has wrong time settings.

1 Like

Wow, this is awesome! I have a basic understanding of how this works, but forgive me - how would I go about implementing this to synchronize player positions? I’m just not exactly sure how to use this. I have the ModuleScript “Shift” currently in ServerScriptStorage and LocalScript “Responder” parented to Shift. The server has a BoolValue that tells the clients (via .Changed) when to start running (in a straight line on the X-axis). How would I incorporate this module to synchronize their positions? Thanks a bunch :slight_smile:

1 Like

Really it depends what you mean by synchronizing player positions, this is going to be the trickier part though. Of course it’s going to take sometime for a client’s position to reach the server then every other client which means you’ll need to predict where a player should be before you have even received the information.

Shift will allow you to determine how long each request takes, so if you send along the value of tick every time you replicate the players position you can use the ClientToServer method to convert that value of tick to what the value of tick would’ve been on the server when the request was sent. Taking this further you can then use the ServerToClient method, for each player, with the converted tick to return the time it would have been on that client when the original replication request was sent. By sending each of these values to their respective clients each client can subtract it from their current value of tick to work out how long ago the request was sent. Knowing how long ago the request was sent means you know how far ahead you need to predict this players movements for that client.

A naive method of prediction might be to take their position using their velocity, acceleration and the time taken for the request position them using SUVAT equations.

Some of that isn’t very easy to explain, but hopefully it all makes sense. It’s also worth seeing how other games deal with this.

1 Like

This is a little beyond me, but I’m also not sending the player positions to the server, technically, so I don’t really know how I would would incorporate those functions on your module. Specifically, when the BoolValue changes to true, a LocalScript on each client tells the character to move to the finish point (Vector3)

character.Humanoid:MoveTo(race.FinishPoint);

What I mean by synchronizing the positions is just to ensure that every client sees each other at the positions that the server sees.

I think I was a little tired when I initially read this post, and now I understand it better. It all makes sense now, however, I’m still not exactly sure how to utilize those functions in the module to make the adjustments to the player’s positions. I would appreciate you elaborating and possibly providing some examples. This type of stuff isn’t exactly my forte. Thanks