Monday, September 2, 2013

Networking in Source

The Source Engine, and by extension Team Fortress 2 and company, handle networking over UDP.

There is an authoritative server that handles all game logic, physics simulation, etc. It runs at a fixed rate of either 30 or 66 ticks per second, although this number can be changed. Not every tick is sent to clients as a snapshot, each client has setting to keep the data sent to them within their bandwidth restrictions to avoid dropped packets. In practice, this means that a client gets about 20 updates per second, which is clearly a good bit lower than the frame rate of the client. To avoid the game looking choppy, the client doesn't render in real-time. Instead, it renders at a (configurable) 100ms delay behind the game state it has actually received, and interpolates between the two snapshots on either side of that delay point. (100ms allows for one dropped snapshot at 20 snapshots per second without a stutter, but doesn't introduce input lag that is noticeable to most players.)

Clients send input to the server in smaller snapshots containing only player input, at a higher rate. Latency, or Ping, is the amount of time it takes for a client to take an input snapshot, send it to the server, and receive a game snapshot with that input taken into account. Ping delays are inevitable, and there is nothing that can really be done to prevent them. However, the engine has a simple trick to disguise them from the client, greatly increasing playability. Each client machine runs the game simulation for the player and things they control in real-time, letting players move with zero latency. Of course, the server is still authoritative, and that means that sometimes the local player position is wrong. Every time a new snapshot is received, the local simulation is corrected, either instantly or over the course of a few frames.

This isn't good enough to do quality hit detection, though. Because it's so important, the server keeps a log of player positions for one second, and whenever a hit is called for (i.e. a weapon is shot) it estimates what time the shot actually occurred, based on the client's specific latency and interpolation, and 'rewinds' the server to check the hit, then applies it retroactively to the current gamestate. Essentially, this means that you don't have to lead an enemy with a hitscan weapon if you have high ping.

No comments:

Post a Comment