My Client and Server is not Synchronized. Common Pitfalls to watch out for?

Started by
9 comments, last by Sirisian 16 years, 2 months ago
Hi, I'm in the midst of writing a multiplayer action game, and I've been debugging my client and server for a few days now. They start out fine, but end up becoming unsynchronized. I'm really pretty stuck. If anyone can point out some pitfalls to watch out for, I'd be really grateful. Network concept: Client generates input, and sends to server. Server recieves input, and sends to Client, along with time received. Client receives input from server, and saves into a buffer. The client rewinds the game until the input time, and then replays it. Things I've been noticing: There's no lost packets. All packets are in order (I'm using TCP for now) Thanks a lot for helping -Cuppo
Advertisement
Floating point precision issues dealing with rolling backwards and forwards frequently. Only thing that comes to mind.

How long does it take for the two to become unsynchronized? Also to help with debugging send full state updates every 10 seconds or something to check for discrepancies. Then just check against what the client has at that time and what the server has.

without knowing much more about how you set things up it's hard to pin point problems.
Debugging lockstep style networking can be a pain. I find it helpful to generate a hash of the game state each frame, then send these between the client and server and halt / assert if they differ. Bonus points for sending world state between the two when this happens so you can tell what caused the problem.
Quote:Server recieves input, and sends to Client


That sounds like the server is just forwarding input on to the clients, and then each client processes it and updates/maintains their own game state. If that is the case, then I think it will become unsynchronized quite easily. Wouldn't it be better if the server processes the input, updates its game state, and then sends the updated game state to the clients? Since the game state is maintained by a single computer, the problem just goes away. Of course, you still have to deal with latency, but that is a different issue.
"When you die, if you get a choice between going to regular heaven or pie heaven, choose pie heaven. It might be a trick, but if it's not, mmmmmmm, boy."
How to Ask Questions the Smart Way.
Quote:Original post by CuppoJava
Network concept:
Client generates input, and sends to server.
Server recieves input, and sends to Client, along with time received.
Client receives input from server, and saves into a buffer.
The client rewinds the game until the input time, and then replays it.


What benefits due you expect from this architecture? In particular, why did you choose the client-side for performing state-rollback?
Finally, Thanks for your help.
I sent the gamestate hash periodically to pinpoint the problem. It turned out that my state buffer was overflowing. Thanks a lot.

To answer some questions:
My server is forwarding inputs, instead of gamestates, because inputs take less bandwidth. A complete game state would be way too big to send to all the clients.

My client is doing the state rollbacks, because I want my server to be authoritative over the game state. Thus, if my client receives an input from the server and it's happened at an earlier time (ie. a time before the current client simulation time), then the client needs to rollback.

Thank you for the techniques. If it wasn't for that, it would have taken well over another week.
-Cuppo
Quote:Original post by CuppoJava
My server is forwarding inputs, instead of gamestates, because inputs take less bandwidth. A complete game state would be way too big to send to all the clients.

Yeah you'll figure this out later, but you don't send full game states. Sending only the changed data (reason they are called delta packets) works just fine. Full states are only sent to players when the server detects that the player has never seen them before. This might seem CPU intensive to keep list (dictionarys/maps are actually used) but it's actually very cheap if you are good at creating efficient spatial partitioning. Also having the server keep track of 100% what the player can or cannot see is awesome when it comes to dynamic content loading. (I've strayed into MMO stuff, but you get the idea). :)

Sending input is alright for small games, but when players are going in and out of each other's camera bounds it becomes more efficient to just send delta and keep track of things that way. Tons of other reasons (like keeping the client ignorant to things until they need to know them) like if a player is walking around in a building and your culling has detected that a player in a closet is an unseen target. Less chance of hacking when the server only gives them the coordinates only when they need them instead of, "here's all of player 1's input, you know where he is, and I can't stop sending input or I'll have to spam the input to you when you see him or do a full state update" :) Not to mention if the server has to roll random numbers and give them players. Your input system has to have additions to it then since input isn't the only changes. This is true for inventory/game state changes not related to input that the players must be informed about. (they can be handled with input, but :/ )
Thanks for the response Sirisian,
Yeah, I'm using delta packets (forwarding inputs, is kind of like a quick and dirty delta packet). My client and server side code is still very new, and I want to see something work first before optimizing my net code.

How's your MMO coming?

This is my first network game, and I kind of jumped into it without knowing how much work it was gonna be. I got single player working, and I thought I could just slap on multiplayer with minimal coding.... oi....
Quote:Original post by CuppoJava
This is my first network game, and I kind of jumped into it without knowing how much work it was gonna be. I got single player working, and I thought I could just slap on multiplayer with minimal coding.... oi....


Yeah that's what a lot of people think. For multiplayer to be incorporated well it needs to be implemented from the start. This means either coding the server alongside the client or if there isn't much of a difference between the server and client a few preprocessor commands can be used to separate the two. Meaning that the same code base makes both the client and server.

I'm still skeptical about your whole sending only input from the server. In theory it should work, but implementing a normal client server design will work also. If bandwidth is a problem I can show you some tricks to lay your fears somewhat to rest:
C# binary packet you can convert to your language of choice
(try not to give that to anyone as it's highly in development and I just wrote it quickly to take care of serialization). Then read this:
Binary Packet tutorial, with how to use one efficiently
(it's old and I need to update it, but it's still applicable)

Quote:Original post by CuppoJava
How's your MMO coming?

slowly, been working on the theory for 3 or something years. Lot of creating original algorithms from scratch. Put it this way my server and client are two separate engines due to the complexity of the extra M. (C# server engine converted to Flash AS3, some of the core ideas are already in both the server and client). Not enough time in a day.
Quote:I'm still skeptical about your whole sending only input from the server. In theory it should work


It works in practice, too. I know for a fact that games such as Starcraft, Warcraft III, Age of Empires, City of Heroes and There.com use that method, or a variant thereof.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement