To preface, my understanding of networking is mostly from Source Multiplayer Networking and 1000 Archers on a 28.8. For various reasons I have decided to go with a client-server model instead of peer-to-peer.

My C#/Unity multiplayer game is ruled by an authoritarian server, which uses UDP. Each network instruction has a time index, and is inserted into PlayoutBuffer's data collection. The buffer executes stored commands at the correct local time index, based on a fixed update loop.

The server is slightly ahead of time, and clients will pause if they have not received any regular update from the server, allowing them to catch up.

Each client will simulate object movement and this movement is corrected by the server (ten times a second). I've got the basic system working, but when I'm testing it in two windows on the same machine sometimes input arrives late, and is dropped.

Usually the late message is 1 time index too late. The fixed loop is 50 ticks per second. The server is 5 ahead of time, and commands are scheduled 5 ahead of time (assuming negligible lag, since ping hasn't been implemented yet and is on the same machine).

This is a problem. Inputs from server are grouped into a few specific channels: Ping, Serialise, Inputs, Criticals, Corrections.

Ping has yet to be implemented. Serialise packs and unpacks mostly pregame multiplayer lobby stuff. Inputs are player commands; select unit, issue move order, etc. Criticals are essential updates; create unit, shoot unit's weapon, damage unit, etc. Corrections are mostly movement updates.

All channels are unordered and with the exception of Corrections all channels are "Reliable" in Unity terms (see Unity documentation). Given that movement updates happen regularly, if a few are dropped or arrive late this is not a critical system failure. But if a critical is lost, this would effectively result in a desync.

How can I prevent and handle critical data arriving late from the server?
My first thought is to implement a custom ping. This is used to set the time index for the data relative to the time the last ping took to get back from the client, plus server time index.

But I doubt that would be enough... and if it fails? Should the client pause or catch up based on the difference between local time index and the time index in the late critical? Does the PlayoutBuffer need to become an AdaptivePlayoutBuffer to resolve these issues to handle CPU and network lag? If so, how so? Any other ideas welcome!

EDIT: The reason inputs were arriving one time index too late sometimes was because the buffer's for loop which read inputs counted from 0 to list.count, and removed items as it iterated... when I changed it to reading from list.count to 0, it fixed the issue and no inputs arrived late. Whoops.

  • \$\begingroup\$ Speaking from my experience as a player, I feel like when client starts missing critical packets game freezes on a client side. It may be "Network problem" message thrown into face. Sometimes, user is still able to perform controls input, but this data is not getting sent(e.g., when connection gets better, player suddenly finds out that he was actually killed 20 meters away from where he is standing right now). If criticals are missed sometimes, guess that is okay. If they are missed constantly, probably some measures are necessary. \$\endgroup\$ – metamorphling Dec 1 '17 at 1:44
  • \$\begingroup\$ UDP and "critical data" is an oxymoron. UDP does not require delivery or order of packets sent, you may get packets in reverse order or not at all. You need to layer a custom protocol on top of UDP or use the standard TCP. \$\endgroup\$ – Patrick Hughes Dec 1 '17 at 7:34
  • 2
    \$\begingroup\$ @PatrickHughes Actually it is not that difficult to reimplement some of the reliability features of TCP on top of UDP. Many game network libraries do that. You might wonder why these don't use TCP in the first place. The reason is that full-fledged TCP simply has too bad realtime properties for most games. Using UDP and adding some reliability features on top is usually a good middle-ground for games. \$\endgroup\$ – Philipp Dec 1 '17 at 11:44
  • 1
    \$\begingroup\$ @PatrickHughes I agree with Philipp, which is why I have used Unity's network reliability settings... and edited the question to add this link. \$\endgroup\$ – inappropriateCode Dec 1 '17 at 12:35
  • \$\begingroup\$ If it's just one time index too late, can't you just hold on to the other packets that arrive and process them all in sequence once the packet that was late arrives? \$\endgroup\$ – John Hamilton Dec 4 '17 at 10:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.