6
\$\begingroup\$

In watching the GDC talk about Overwatch netcode, it mentions that the client is always ahead of the server, that the "current tick" on the server is behind that of the client.

From their explanation this makes sense. If the client is ahead of the server, then by the time the client messages arrive at the server, the server will have caught up and can handle them when it wants them.

But how does this get setup to begin with? The client connects to the server, the server starts a game... does the client jump ahead of it's own accord? (Server says "game is starting, I'm at tick 0", and the client is like "okay, well, based on my ping I'm going to be tick 20 then")

  • If the server is in charge of what's going on in the game, how does the client even know what's going on in that future tick? I would assume constant extrapolation of game events from the last server update would be bad. Having the client in the past to allow it to interpolate between server updates would make a lot more sense to me.

  • Or am I wrong in assuming that client and server tick times need to remain in sync, and it is instead more loosely based on server updates and the number of client events that happened since that update was received, rather than the client actually caring about what tick they're on compared to the server?

It's the time/tick synchronization, despite one or the other having to be in the past, that I can't wrap my head around...

\$\endgroup\$
2
  • \$\begingroup\$ Haven’t watched this talk, but it sounds like some form of rollback netcode. My understanding of rollback is that the game actually does extrapolate events based on the last server update. If you have a ping of a few tens of milliseconds, the difference between the client’s “guess” as to what will happen and what actually does happen will rarely differ enough to disrupt gameplay or be visually jarring. \$\endgroup\$ Commented Nov 6, 2020 at 6:26
  • \$\begingroup\$ @FluffytheTogekiss Not quite. Extrapolation happens when your ping is so high (hundreds of ms) that it would be unfair to rewind the victim as much. The difference between the maximum rewind time and the shooter's ping is the time that's extrapolated, so that you don't have to lead the target based on latency. \$\endgroup\$ Commented Aug 5, 2022 at 15:07

1 Answer 1

5
+200
\$\begingroup\$

But how does this get setup to begin with? The client connects to the server, the server starts a game... does the client jump ahead of it's own accord? (Server says "game is starting, I'm at tick 0", and the client is like "okay, well, based on my ping I'm going to be tick 20 then")

No. Once the connection is established, the client just starts running, and starts sending messages (input) to the server immediately. But the messages take time to reach the server (network latency). And by the time the first message arrives at the server, the client is already 10 ticks ahead (let's say), "predicting" what's happening based on its own state of the game world. The client is not in the future, the client just runs its own simulation in real time; it's the server that's always late (because of the time it takes for them to exchange messages).

If the server is in charge of what's going on in the game, how does the client even know what's going on in that future tick?

It doesn't. It maintains its own state of the game world, and it tries to predict what is going on based on that. Here "predict" just means "run the game based on my own state and hope that the server will eventually come up with the same answers." For this to work the behavior of the game needs to be made as deterministic as possible (see the talk for details). Again, for the client, this is not a future tick, it's the current tick; the client just doesn't have the most up-to-date state of the world. E.g. it may not know yet that someone fired a gun at you a couple of milliseconds ago.

The server computes the same kinds of updates as the input arrives, and then sends the results back. That takes time to arrive as well. To the client, that's now some 20+ ticks ago (roundtrip time). The client maintains the past state (and past inputs), and if the state obtained from the server is different, it will throw away everything after it, and re-predict from that point on, all the way up to the current frame.

At least, that's a general/conceptual overview; in the talk you'll see that in practice there are some subtleties that need to be taken into account.

Having the client in the past to allow it to interpolate between server updates would make a lot more sense to me.

Well, the problem is that the game needs to feel responsive. In this type of game, when a player clicks a button to shoot, or whatever, you can't wait for the input to get to the server, be processed, and then to come back. So it's a compromise - the input feels very responsive, but when an occasional misprediction happens, the client does extrapolate from a past state, and just replaces whatever was on the screen with the new thing. Luckily, this usually isn't very noticeable.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ +1 As an example, I have worked on an Android app which behaves as described. The device (because it's a battery-limited handheld) performs some rough rendering so that the user is happy while waiting 10+ seconds for the (high-quality) server rendering to download. 15 year old very profitable app. \$\endgroup\$
    – Vorac
    Commented Nov 10, 2020 at 3:54
  • \$\begingroup\$ I'm almost certain this answer is incorrect. OW:s network model explicitly places the client ahead of the server so that messages arrive at the server before it needs to be processed. If the server is at frame 100, the client will simulate frame 100 + 2 (buffer) + 5 (half RTT) which hopefully means that when client frame 107 arrives the server will be at 105 (100 + half RTT) so the server has access to it when frame 107 arrives. If the message arrives too late (e.g. client 107 arrives at server 112) the server will not process it since the frame number is lower than the server's current frame. \$\endgroup\$
    – Charanor
    Commented Jan 23 at 2:55
  • \$\begingroup\$ Periodically the server will send a message "I am at frame 120". If the client notices that it cannot keep up the desired buffer size (e.g. server is at 120, client is at 118, but we want to be at 120 + 2 (buffer) + 5 (half RTT) = 127) it will speed up its simulation until it is caught up. This catch-up is necessary because otherwise the client will probably drop inputs since they will be arriving too late (118 + 5 = 123, server will be at 125). \$\endgroup\$
    – Charanor
    Commented Jan 23 at 2:59
  • \$\begingroup\$ @Charanor - this was 3+ years ago, I don't remember what I wrote, or the details of the talk mentioned in the question; it's possible that the answer became incorrect in some way, or was perhaps always so (in case there was a misunderstanding on my part). Note also that the answer, and to some extent, the question itself, are not necessarily about OW implementation specifically, I think the OP was more interested in the general concepts. However if you want to, feel free to write another answer. \$\endgroup\$ Commented Jan 23 at 3:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .