7
\$\begingroup\$

I am aware of snapshot interpolation with the use of delta compression as being a technique used to minimise the amount of data sent in a modern FPS game like Quake 3, but what other techniques are there?

\$\endgroup\$
2
  • 1
    \$\begingroup\$ This is an extremely vague question- giving more details about what data you need to send, and why you feel it's not already optimized, will help you get better answers (or maybe answer your question for you), but as-is, this question is too open-ended. How you can minimize data depends on what data your game relies on, which is completely determined by how you design it. \$\endgroup\$ Nov 6 '15 at 17:23
  • \$\begingroup\$ It sounds like you need to do some background research to be able to ask more specific questions. As-written right now, this is likely to generate just lists of techniques, and those types of questions tend to be closed as off-topic because there's no way to select one correct answer. I'd suggest starting with Jonathan Blow's Inner Product articles on networking, archived here which go from the very basics to some pretty advanced techniques. \$\endgroup\$
    – DMGregory
    Nov 6 '15 at 18:04
6
\$\begingroup\$

When we implemented our networking engine we exploited a number of compression techniques:

  1. First we write all of our snapshot bit-wise: bools are only 1 bit instead of 1 byte (or more depending on compiler). We wrote a bitstream class that reads and writes data to a stream. This saves a fair bit of data all alone when packing flags down. For an example of a decent C++ BitStream class have a look at the RakNet source recently made available by Occulus here: https://github.com/OculusVR/RakNet
  2. We found the smallest way to represent data, bitwise - if an integer can only be in the range of 0 to 15, for example, we only store it in the snapshot as 4 bits. We perform this range packing on signed and unsigned integers, minimizing the amount of data being sent at the cost of having to write the data to our snapshot stream bit-wise. There is CPU cost here, but the data bandwidth is greatly reduced. We do this for enumerations as well - if there are only two states, it only takes one bit, for example. We exploit templates here to make this easy to write in code.
  3. We establish some data types that can be quantized - data that we are satisfied to lose some decimal precision to reduce the over-the-wire bandwidth. Combined with the range packing we can compress floating point numbers down from 32 bits to a smaller, range and precision specific level. Again we exploit templates here to make this easy to write in code.
  4. Delta compression - you have identified this already, but it makes a significant impact.
  5. We group blocks of data where the delta compression allows us to group a number of related, unchanging fields under a single dirty bit to indicate if they have changed or not. This reduces the cost of sending a bit for each field indicating it has NOT changed. There is less of a win here, and one has to be careful about how you group them, but infrequently changing fields that generally change in tandem are good candidates.
  6. We take the entire packet and compress it using a quick compression engine - lz4, for example. This reduces the data even more - every thing helps.
  7. We don't send ANY data for objects that are too far away to be part of the local player's simulation and bulk-synchronize those objects when the player enters proximity. Some objects are excluded from this system such as mission objects, keys and locks, for example.
  8. We don't send ANY data that can be reliably reproduced on the client. For example, we send animation state and time instead of the position of each bone - the client can reliably pose the character with that information, saving us the bandwidth of sending the transform of every bone (and anything attached to those bones - hit boxes, effects, etc). We extend this out as far as we can. As one comment pointed out, "the best compression is not sending it at all".

I'm sure there are others, but these ideas should help.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ The big one I'd add is that you should only send data that the client can't reliably reproduce on its own. That is, send only the non-derivable state changes. Compressing data that you don't need to send is still way worse than not sending it at all. :) \$\endgroup\$ Nov 27 '15 at 19:29
  • \$\begingroup\$ @SeanMiddleditch Good point - I'll add that to the answer \$\endgroup\$
    – Steven
    Nov 27 '15 at 19:40

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.