Building a multi player asteroids game where ships compete with each other. Using UDP.
Wanted to minimize traffic sent to server. Which would you do:

Send periodic keyboard state samples every from client every to match server physics update rate e.g. 50 times per second. Highly resilient to packet loss and other reliabilty problems. Out of date packets disacarded by server. Generates a lot of unnuecessary traffic.

Only send keyboard state when it changes (key up, key down). Radically less traffic sent from client to server. However, UDP can lose packets without you being informed. So the latter method could result in the vital packet never being resent unless I detect and resend this in a timely manner.

3 Answers
3

I'd say 2: as you state, solution 1 would generate too much traffic. There's a chance it works in the beginnings, but then when you'll add other things to send you might have to reduce the input updates frequency and thus you game reactivity. As a rule of thumb, sending deltas instead of complete states is most of the time The Right Thing to do.

You're right in telling that:

UDP can lose packets without you being informed

But any proper networking subsystem, even built on UDP, will allow you to choose to send your infos with some form of acknowledgement. So you could send critical keyboard inputs reliably, and the rest not-so-reliably.

I'm still not experienced with networking systems so I'd like to ask - what does it usually mean to be able to send part of the data reliably? Is the data automatically resent if it doesn't get an acknowledgement within a certain time limit? And what if the data arrived, but the acknowledgement didn't?
–
David GouveiaApr 5 '12 at 16:54

It's UDP, there isn't anything like that. He is suggesting you should implement those yourself on top of UDP. Which I think is a very bad idea anyway.
–
LohorisApr 5 '12 at 17:02

I'm no expert with networking systems either. For hints about acknowledgments, check this for instance. And yes, my suggestion is to implement this on top of UDP. There are libraries around that are already doing it, like Zoidcom. This one is commercial and closed source, but you might find open source alternatives with a bit of research.
–
Laurent CouvidouApr 5 '12 at 17:10

A common alternative is to open one TCP port to handle the critical data and use a second, UDP port for everything else.
–
Patrick HughesApr 5 '12 at 17:32

@Lohoris how is fine-tuning your reliable data transfer a bad idea? If you don't need full-fledged TCP it's just a waste using it (and you CAN'T read OOO packets, which sucks.) That's why mostly all commercial games use UDP with some form of reliable transfer or packet-loss correction (like syncing when getting out of sync.)
–
kaoDApr 5 '12 at 21:19

Since the server is authoritative on position, this means that you will have significant perceived lag and an extremely poor user experience under many realistically sub-par network conditions.

While your situation is not as complex, I recommend reading older articles about the development of Unreal, Quake, and Counter Strike. I'm having trouble tracking them down now, and I apologize for my lack of Google-Fu, but all three engines had some excellent articles written by the developers back in the day on the precise difficulties they had creating smooth online play and how they resolved them.

Some points that I remember:

When you take an input event, record the time of the event as related to the timestamp of the world that the player is seeing. So if the player is seeing frame 33271 when they press the shoot button, the event might be 33271:shoot that is returned to the server. This allows the server to take latency into account, and calculate things like 'at that moment, the player was aiming right at the enemy, even though 0.2 seconds later when I got the event they no longer were'. Without this, the player presses shoot and 0.2 seconds later a missile starts shooting from their ship. With this type of prediction, a player presses shoot and 0.2 seconds later the missile appears on their screen, but farther out as if it had already been traveling for 0.2 seconds. This allows for precise and responsive controls regardless of latency.

Repeat important events until you get an acknowledgement. In the above example, every packet from the player to the server will include 33271:shoot until the client receives an acknowledgement of that event. If the first and second packet are lost, it will still get there in the third to be acknowledged. In addition, since the event is timestamped the server can still treat the attack as if it happened at the correct time, rather than being delayed due to network packet loss.

The server should keep a state queue of the last second or so, so that it can determine the proper result of actions that happen in the past... 0.5 seconds ago, was the asteroid lined up with the laser blast? This reduces or eliminates conflicts between the player thinking they hit, but the server thinking they missed. Depends on the first point to work.

Interpolate values on the client. Client side prediction is hard to get right, and can cause some warping effects, but is essential in creating a smooth experience for the player. Asteroids that are rotating will continue to rotate until disturbed obviously, and the client shouldn't need to get the location of the asteroid every tick. In the same way that client input is repeated until acknowledged, important game state changes should do the same from the server to the client.

I'm sure there are other considerations I've forgotten, and I apologize for not having links to the excellent and informative articles I've read in the past. Some (such as the ones I read about Quake World) are over 15 years old, when online gameplay was a new field. I suspect some of the articles I read were via the old finger protocol on Unix systems, a popular way for developers to interact with fans in the early days.

+1 This is basically how streaming video codecs do it, with complete keyframes at certain intervals and the rest delta-encoded. Of course, that case is mainly to support seeking, but the principle is the same.
–
Jon PurdyApr 5 '12 at 16:59