C# – Sync one thousand vector3 across network with minimal bytes

csynchronizationunity3d

I am making a game with Unity, and am having problems attempting network synchronisation. Deterministic simulation is impossible because Unity's internal logic is float based. I am trying to make a solution which works on an authoritative client-server model, in which the position of every soldier is corrected by the server 5-10 times a second. This is achieved by sending UDP datagrams, and measures will be implemented to ensure delivery. Between corrections the client simulates the game as best it can.

Soldiers do not often move in straight lines. They engage in flocking and will encounter many obstacles which they have to navigate. Soldiers exist as individuals and do not exist as part of a squad object.

There are things which can be done to reduce bandwidth consumption which are not the focus here, because they are at best temporary improvements. Like only sending the positions of soldiers who are moving and/or observed, and compressing the data before transmission.

The problem is simple. If I have ten soldiers running about that's fine, but if I have one thousand then bandwidth use becomes unreasonable. At the very least we need to send a soldier id (ushort) and position (float, float, float) per soldier. Right now that's 2 + 4 + 4 + 4 = 14 bytes. More data maybe required, for instance the direction of facing (soldiers never look up or down).

14 * 10 * 1000 = 140kb/s … way too much!

The question is this:

How can we reduce the number of bytes sent per soldier to an absolute minimum and still have a synchronised result?

POSSIBLE SOLUTIONS:

1.
One idea I had was that since a soldier's max speed will not change, this allows us to correct the position of any soldier by an absolute value relative to the last known position. But that may suffer from desync too.

Instead of sending a float for the XYZ axis of the position, we send a sbyte. Since this is -128 to 127, we can read/write it to say that the new position is a percent of the soldier's max speed from the last position. If it worked that'd reduce the data sent from 14 bytes to 5. But even 36% is still 50kb/s for 1000 soldiers.

Potentially that could be reduced to 4 bytes some of the time, as soldiers do not always move up or down (Y axis). But that is, like ignoring soldiers who are not moving, not the issue.

2.
Another idea I had was to reduce the XYZ axis to 12 bits (1.5 bytes). Each axis has 4 bits, 3 of which are used to find a distance value. 3 bits allows us to count from 0 to 8. There are six values between either end of zero or maximum speed. We have a range of values which can be used as they are "close enough". The other bit determines whether this is positive or negative. The server then forces a correction upon soldiers before it sends their positions to the client, forcing their distance from the last position to conform to one of the "close enough" values.

Additionally, if there won't be more than a thousand soldiers alive at any one time, we can assign soldiers to a living ID, and so shorten the network ID from 16 bits to 10, allowing us to count to 1024.

In total this would reduce the data sent per soldier from 14 bytes to 22 bits (2.75 bytes). I suspect this would be even less likely than the first idea to maintain synchronisation. The result may simply be too jittery. If it did work it'd be 20% of the original bandwidth at 28kb/s.

Any ideas are welcome at this point. I've been focusing on making smaller and smaller vector3's, but there may be a much better way of doing this which does something completely different.

Best Answer

Standard compression algorithms are pretty efficient even at the fastest setting. As a quick test I filled a text file with 34k bytes. Compressing with 7-zip on fastest setting gave me a file of 1k. That is ~3% of the original size. Granted my numbers was stored as ascii but it goes to show that similar values can be reduced to a small fraction.

Using standard algorithms can probably be outdone by special techniques discussed in other answers but standard compression techniques should be much faster to implement and less error prone to use well-tested algorithms but if the result is "good enough ®" you can choose if you want to use the gained time to go to market faster or make a sweeter game in areas the user can actually feel.

Related Topic