6
\$\begingroup\$

I am working on a multiplayer RTS game in Java. It uses lockstep for networking, which requires that both computers can deterministically.

These are the 2 closest/more viable approaches I could come up with- but both have issues:

  • The first is to just use int and long for all my player positions and stuff, and get any use of floating point math totally out of the game model. I like this concept- but the problem is what happens when I need a square root, or a cosine? I would have to basically make an entire math library!

  • I also found that I can use the strictfp modifier and StrictMath class to do deterministic math with doubles... Which I could see using this to create deterministic math within my games model. It would be very prone to bugs as it would be very easy to accidentally go outside of the "strict" scope though.

Also I cant seem to figure out if serializing a float or double causes it to lose its determinism. I'm using Kryo/Kryonet right now, but I cant seem to find any information on if it is deterministic with floats or not (I cant seem to find any information on the built in java serialization either, or any other serialization library)

Does anyone have any suggestions on how I could tackle this problem?

\$\endgroup\$
3
\$\begingroup\$

Like you say, it is technically possible to get determinism out of floating point, and some well known RTSs have used floating point in the deterministic simulation, but it is easy to get wrong leading to bugs that are hard to find and reproduce and hard to solve.

A good link on floating point determinism is here: https://randomascii.wordpress.com/2013/07/16/floating-point-determinism/

A much simpler solution is to use fixed point math, and is also found in well known RTSs (SC2 for example).

Fixed point math stores values in integer types, using an implicit decimal point.

For instance if you had a uint32 that was in 24.8 format, you'd have 24 bits for the integer part, and 8 bits for the fractional part.

That means you can store fractions of $N/256$.

Adding and subtracting fixed point numbers is easy - you just add and subtract the integers.

Multiplication involves multiplying the ints and then right shifting by the number of fractional bits.

Division involves left shifting the divisor by the number of fractional bits and then doing the integer division.

Converting from float to fixed point is simply multiplying the floating point number by $2^F$ where F is the number of fractional bits, and then storing that number in the int.

Converting from fixed to float involves storing your int in a float and then dividing by $2^F$ to get the floating point value back.

Once you have a fixed point number class, you do need to implement things like pow, cos, sin etc if you need them.

Make sure and not use ANY floating point values in the simulation though.

All numbers in your game data for instance (like, how much damage a unit does) should be already be in the data file as fixed point.

Any mixing of fixed and float could cause two clients to fall out of sync and is no good.

\$\endgroup\$

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.