14
\$\begingroup\$

I'm working on a 2D server-client multiplayer game engine (which you can try here). It uses WebRTC DataChannels. (The connections are peer-to-peer, but the host peer still acts as a server.)

The biggest problem (apart from connectivity) is the local input prediction. We do the usual: On key press, players move instantly, tell the host what keys are pressed, receive data back from the host and compare it to the historical position. The position is corrected over time if there is a difference. This works well with low packet loss or PDV, even if the ping is high.

If there is loss or PDV, the deviation can be larger. I think this is because if the first packet indicating a change of input is delayed or dropped, the host finds out later, and starts changing that player later than their local input prediciton shows.

If the player is moving, we crank up the amount of applied correction, since it's less noticable. This seems to cover up gaps when starting to move and while moving. However, any correction is more noticable if they come to an abrupt stop. Then if the PDV or loss means the host thinks they stopped later, the host overshoots, sends back data saying they're a bit further ahead, and the correction makes the player drift a little. On flaky connections, players often noticably drift after coming to a stop.

I've not noticed this in other games. How can this be mitigated?

\$\endgroup\$
5
  • 3
    \$\begingroup\$ A P2P game that has a server? There is something wrong here. \$\endgroup\$
    – API-Beast
    Feb 20, 2014 at 16:36
  • \$\begingroup\$ Oops, by 'server' I mean 'the host peer'. \$\endgroup\$ Feb 20, 2014 at 16:56
  • 2
    \$\begingroup\$ Well, that doesn't look like a peer-to-peer model either, just because one of the players is posing as the server doesn't make it peer to peer. The technique you are employing is definitely a Client-Server technique. In P2P you either trust all clients completely (e.g. each peer asks each other peer where their player is) or you trust none (e.g. you delay the input until all peers have received it). \$\endgroup\$
    – API-Beast
    Feb 21, 2014 at 7:08
  • \$\begingroup\$ Ah... that's a good point actually... I got mixed up: the connections are peer-to-peer (which is what WebRTC does), but the engine itself is server-client (one of the peers is just the server). Good point. \$\endgroup\$ Feb 21, 2014 at 13:26
  • 2
    \$\begingroup\$ What this makes me think of is our very own Andrew Russell's Stick Ninjas dev logs on YouTube, particularly this one on fixing prediction errors. The drifting you describe sounds very similar to what's happening in that video and Andrew narrates the details. Are these related, or perhaps even the same issue? \$\endgroup\$
    – Anko
    Feb 21, 2014 at 14:08

2 Answers 2

8
+50
\$\begingroup\$

The network layer needs to have an agreed-upon clock. They can agree upon a clock value early in the game (and resync it periodically in case of drift) so the host knows how long any particular packet took to actually arrive and when the client did the action, and vice versa.

See this article for one possible way to synchronize clocks in games. There are others. The specific means don't matter.

The second half of the problem is that the server is applying input past the time the client stopped applying input. This requires a buffer of past movements on the server and some logic on the client to ignore movement inputs from the server past the last known movement.

First, the server buffer. The server needs to keep track of the clock stamp of the last input received from the player. It also needs all movements it applies to a player, the clock stamp of the movement. If an input is received, all recent movements applied with a clock stamp newer than the input packet are dropped and all movement is re-applied from the input packet. Hence if the server over-moves the player based on some input, the updated input will cancel out those moves and the player's new position will be based upon the most recent input knowledge the server has.

On the client side, the client knows when it last sent input to the server. Since each player update from the server should have been tagged with the clock of the last input the server knew about, the client can ignore server updates that have an expired input tag and just stick with the client prediction. Eventually new server updates will arrive with up-to-date input and the client can correct against those.

The server needs to validate the input clocks and make sure they're not drifing from expectations too much to prevent cheating. The input clock should not be drastically larger than the half-round-trip time you should be calculating. Clamp any that are to a reasonable range ([Now-2*RTT,Now] for instance).

Clients will see a lot of jitter of other players' avatars if latency is high since they'll get updates from the server based on stale input but have no way to know that it's stale and then the server could start sending fairly different locations based on the updated input it received (and its dropping of some portion of its history and replaying it with the new input). This last issue with other players seeing your avatar jitter is not really fixable. Latency sucks and gamers stuck on high-latency connections are going to see a lot of jittering of other players, even if their own player is moving smoothly. The only correction is to play on better connections or with peers/servers with less latency.

\$\endgroup\$
1
\$\begingroup\$

I've used reliable UDP messages to indicate button state changes and unreliable UDP messages for position correction. Basicaly, the following articles helped me very much: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking

It says about movement prediction by storing player states in constant time intervals according to position correction messages arrival for about 20 or 30 state saves. So it looks like your remote players will live in a not so far "past" actualy by constantly applying prediction technique :) Based on the net message latency you can get your object position approx in time when message was just sent from host.

Current "on-screen" position can be then smoothly translated into the predicted position using Lerp (linear interpolation) math. The idea is to interpolate values in the time gaps between the correction packages. So it looks like that displayed object is always moving towards some predicted position. For interpolation value i take the 1 divided by "medium message latency" divided by "medium frame rendering time" so the movement looks smooth.

In this scenario the game calculates on all of the clients and server corrects the values such as velocity and position from time to time.

The one more thing that helps a lot in this case: optimize your game logic so you can easily negate latency effects by ensuring that server and clients can emulate near similar behaviour based on player input.

I've described the whole scheme i've used in my project so i hope you'll find the answer to your question.

\$\endgroup\$

You must log in to answer this question.

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