Sunday, January 9, 2011

Synchronizing clients with a server and with each other

What is the best way for keeping all clients synchronized with a server and with each other?

Currently, we have two approaches in mind:

  1. When a client sends something to the server, the server immediately sends out messages to all clients, which react immediately.
  2. Introducing some time delay, whereby the server sends out messages to all clients, with the directive, "act upon this at time t.

The second approach seems like it would more likely keep the clients all in better synchronization (since it caters for some degree of lag); but I wonder whether responsiveness would be lost to too high a degree (i.e. the user clicks 'jump' and there is a noticeable gap between pressing the button and actually jumping).

There is also the possibility of having clients calculate their own position (and not wait for servers to say "you have jumped"); but because of the inevitable lag, clients would get very out-of-sync.

Then there's the whole TCP vs. UDP question; because we want it fast, but I'd also hate for the server to say you're in a completely different location than you thought you were.

With all of these competing demands, it all gets very uncertain how we should approach this issue. Which of these approaches (or any other) would be best for keeping clients and server all in sync? Which ones are actually used in the industry?

  • The quick answer is: there is no best approach.

    Games all contain different architecture; every game will choose different sets of data to send in order to synchronize itself with other machines, which will affect the choices that you can make when choosing how to deal with lag.

    What you specify in option #2 -- that clients send messages to be acted on at a future time -- is definitely one approach. In fact, the Source engine uses a variant of this approach, where rendering is always 100ms behind local client actions; all machines attempt to operate on the same actions at the same time. This adds an artificial, imperceptible lag to the game in order to hide actual network latency.

    If you can't take this approach, you can also choose option #1, simply sending the most up-to-date data and upon receipt, use interpolation and extrapolation (client-side prediction) to try to hide latency. I've used this approach in at least one shipping game -- but again, it all depends on your game; there may be other approaches you can take.

    Finally, when choosing between TCP and UDP -- you probably want UDP. There are scenarios where TCP is a viable option for networking your game, but when you're making an action game, you want the latest data as soon as possible. If you can deal with dropped packets yourself, UDP is the better choice. (There are libraries, such as ENet, that provide a wrapper around UDP to replace functionality from TCP, such as reliable packets.)

    coderanger : You really don't want to use UDP. The overhead of a correctly configured TCP connection is minimal and the hell that is out-of-order delivery is something no one should have to live through.
    Blair Holloway : It's not a matter of overhead, though TCP adds some - the way TCP deals with dropped packets is fundamentally not good in games where a large latency between action and reaction can make a *huge* difference in playability. For a game like WoW, where actions are relatively infrequent, TCP works, but it would fall over flat in a game like CounterStrike, as a single dropped packet will throttle your connection and potentially make you "lag out" for a second or more.
    Blair Holloway : If you're going to use UDP, it really is best not to write it yourself; use a wrapper like ENet that does the hard work for you. But my original answer still stands -- UDP is the best way to go if you're making a game with any sort of fast-paced action.
    BarakatX2 : For me, RakNet made running a UDP connection for my game engine extremely easy. It has many options for how you want to send your packet ie. how to order them, should the packet be resent if dropped etc.
  • Since you mention Clients and Servers, i'm going to assume that you're talking about a Client/Server architecture where the Server is the authority on the state of all objects.

    Note: The alternative is a Peer-To-Peer architecture where the owner of an object is the authority for that object.

    There is already a well proven method for synchronizing moving objects using Client-Server architecture. It's called Dead Reckoning..

    A good way to implement this in a game would be like this:

    1. Clients send inputs to the server.
    2. Server updates the game objects (accelerations & directions) and sends them back to Clients.
    3. Clients use these updated values to simulate the movement of the objects locally.
    4. Occasionally, the server sends a position correction to avoid drift.
    5. Rinse; repeat.
    From JanSolo
  • Here's a couple of good links which cover an awful lot of game networking.

    And this is the first part of the more hands on networking series. http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/

    For the history. 'we're sorry, but as a spam prevention mechanism, new users can only post a maximum of one hyperlink. Earn 10 reputation to post more hyperlinks.' Just look around his website, anyway.

0 comments:

Post a Comment