🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Basics of Game Networking, Need Some Help Understanding

Started by
4 comments, last by rs131 8 years, 8 months ago

I've been studying on different methods to use for networking movements on multiplayer gaming. I'm currently going with Photon Server & Unity, which I know both very well now. However, my main problem is understanding how to sync these movements (inputs,positions) between the client/server.

I've read some of the articles on Quake 3 and others that are linked here, but it's just not the easiest thing to understand. I've been testing out many different solutions and end up beating my head against the wall because I can't seem to get things in sync.

My project is a 3D Virtual Chat. It won't have much action besides moving/traveling in the world and chatting. Other than that, nothing major.

Currently, from what I've read I've thought about doing this:

  1. Include a sequence # in each packet. On the server store the last sequence # received for the client. When client sends the next one, update that and forward it to an outgoing queue.
  2. Send the event out with a delay of 100-200ms from when it was received. It will be checked to make sure the move is "legal" then process it and send it in the next 100ms interval.
  3. When the client receives it, it checks to make sure that sequence # is the next one to be applied, if so, it'll apply it.
  4. The packets will include movement type (forward,back,left,right) and position & rotation.

But I'm a little skeptical on it just due to the fact it's not based on times and instead relies on things to hopefully come in properly (with an extra delay for safety) and if the client's character has moved forward a little too much because it was late receiving that packet, it will just shoot the player backwards a little due to the position/rotation it received.

Any advice or guidance on this would be majorly appreciated.

Check out my blog & portfolio www.ryanshinny.info.
Advertisement

I've been studying on different methods to use for networking movements on multiplayer gaming. I'm currently going with Photon Server & Unity, which I know both very well now. However, my main problem is understanding how to sync these movements (inputs,positions) between the client/server.


Read the article series at http://gafferongames.com/networking-for-game-programmers/ and see if that clears things up for you.

When the client receives it, it checks to make sure that sequence # is the next one to be applied, if so, it'll apply it.


Next, or any later, depending on the type of messages in the packet. For ordered messages, yes, you only want to apply the _next_ set of messages expected. For data with a high rate-of-change, like position information, you just want the newest data. You don't care if you skip packets, you just want to make sure you don't apply old packets (since they can in come in out of order, or you can even get duplicates).

The packets will include movement type (forward,back,left,right) and position & rotation.


Sort of. From the client to the server, you might send the action the player wants to perform.

From the server to the client, you probably just want to send the resulting state (e.g. position), with maybe some data about actions (to trigger VFX and the like). And this is where things get fun, as the ordered/unordered and reliable/unreliable attributes of the position update may well be different than the information about actions performed, and you probably still want to send them in the same packet, so you can't just do all your high-level processing at the packet level.

But I'm a little skeptical on it just due to the fact it's not based on times and instead relies on things to hopefully come in properly (with an extra delay for safety)


OK, first, what does adding an extra delay have to do with safety??

Times aren't something you can use in networking in any case. The server and client are running two entirely different clocks. The delays of network communication can be predicted but not guaranteed. You can't really talk about time over the network. At most you can talk about time _spans_ ("the player held down this key for 5 seconds") but never points in time ("the player pressed this button at time T").

and if the client's character has moved forward a little too much because it was late receiving that packet, it will just shoot the player backwards a little due to the position/rotation it received.


This is called rubberbanding. It's part of practically every networked real-time action game ever. You just have to mask it as best you can.

You can do all kinds of fancy interpolation, extrapolation, correction, etc. to mitigate the problems, but you'll never be able to eliminate them entirely.

Most of those mitigations cause yet other problems of their own, too.

Then there's all the fun of latency masking. It's impossible for client A to know what client B is doing immediately, but in a fast-paced action game both players have to make decisions based on what the other is doing in that instance. That requires you to do all kinds of game design tricks to hide the fact that the players are playing in two diverged timelines... which, again, is impossible to do perfectly.

Networking games is hard.

Sean Middleditch – Game Systems Engineer – Join my team!

You don't want to talk about time, but you DO want to talk about time steps.
Specifically, if the world simulates at a fixed frequency on the servers, say at 60 Hz, then there will be 60 time steps per second.
You should run the simulation at the same rate on the client.
If the client has fast graphics, you may be able to render more than 60 fps -- if so, save the user's battery. (Or use interpolation for render state)
If the client has slow graphics, you will not be able to render that many frames per second -- instead, step physics/simulation multiple times per rendered frame.

In networking, you include all commands for each time step. If you send a packet 10 times a second, then you will include commands for 6 time steps in each packet. This goes both for client->server, and server->client.

Now, when a player presses down "move forward," you record the time step at which the player started doing this.
Keep sending "moving forward" for each time step until the cilent releases the button.

When the client first connects, the server sends what the "current time step number" is, and the client jumps ahead to that timestep.
Then, the client sends its current time step with each command to the server. If the server receives the command too late to be applied, it should send "you are behind by X steps" to the client, and the client will adjust to send steps "more in the future" to the server.
Similarly, if the client is way too far into the future (more than 10 steps?) the server can start sending "you are ahead by X steps" to the client, and the client will adjust to send steps "less in the future" to the server.

Now, when the server sends commands, or states, or both in some combination, to other clients, they will receive the data "after the actual time," which you can work around by either doing forward extrapolation, or by simply displaying things "behind time" on each client.
enum Bool { True, False, FileNotFound };

You don't want to talk about time, but you DO want to talk about time steps.
Specifically, if the world simulates at a fixed frequency on the servers, say at 60 Hz, then there will be 60 time steps per second.
You should run the simulation at the same rate on the client.
If the client has fast graphics, you may be able to render more than 60 fps -- if so, save the user's battery. (Or use interpolation for render state)
If the client has slow graphics, you will not be able to render that many frames per second -- instead, step physics/simulation multiple times per rendered frame.

In networking, you include all commands for each time step. If you send a packet 10 times a second, then you will include commands for 6 time steps in each packet. This goes both for client->server, and server->client.

Now, when a player presses down "move forward," you record the time step at which the player started doing this.
Keep sending "moving forward" for each time step until the cilent releases the button.

When the client first connects, the server sends what the "current time step number" is, and the client jumps ahead to that timestep.
Then, the client sends its current time step with each command to the server. If the server receives the command too late to be applied, it should send "you are behind by X steps" to the client, and the client will adjust to send steps "more in the future" to the server.
Similarly, if the client is way too far into the future (more than 10 steps?) the server can start sending "you are ahead by X steps" to the client, and the client will adjust to send steps "less in the future" to the server.

Now, when the server sends commands, or states, or both in some combination, to other clients, they will receive the data "after the actual time," which you can work around by either doing forward extrapolation, or by simply displaying things "behind time" on each client.

Hey Thanks HPlus, actually this is one of the first things I tried doing, my problem however was doing a fixed interval of say 16ms on both the client & server, they start out the same. Player joined at timestep 30, so his client starts counting from timestep 30 and up. However, the server ended up getting 100 time steps ahead, then 200, then 300, and so on until it was thousands of time steps ahead. So when new players joined they'd actually be 1000 timesteps in the future compared to ones who joined before them.

Check out my blog & portfolio www.ryanshinny.info.

doing a fixed interval of say 16ms on both the client & server, they start out the same. Player joined at timestep 30, so his client starts counting from timestep 30 and up


You need to compensate for clock drift. The good news is that, with the algorithm that I indicated, that will happen automatically.

Also, it's usually better to "render as fast as possible" and then, between each render frame, figure out what time it actually is, and step simulation 0, 1, or more steps to keep in sync. Keep fractional time in an accumulator as well, to avoid rounding errors accumulating.

Here's an example of how you'd structure your main loop: http://www.mindcontrol.org/~hplus/graphics/game_loop.html
enum Bool { True, False, FileNotFound };

Aha! Ok I just reread everything and it makes sense. I like this approach. Thanks so much HPlus, I will try it out :)

Check out my blog & portfolio www.ryanshinny.info.

This topic is closed to new replies.

Advertisement