I am developing the game Remnants of Naezith for around 2.5 years and the backbone of this game is the leaderboard which has replays. Game is fully deterministic so same inputs lead to same simulation every single time. Game is fully written from scratch in C++ and SFML.
Months ago I changed my gcc compiler from 64bit to 32bit or reverse, I don't remember correctly but the problem was, old replays were not working in the new compiler. When I searched about it, floating point math were being different between two.
I fixed it by putting -msse2 -mfpmath=sse. Then it was working same.
Today I compiled and ran the game in Debug mode and for first time I saw some of the replays desync again. When I searched about it, it's caused by the -Ofast flag I use at Release build. Because -Ofast flag has -ffast-math in it. That makes a difference in calculations, so simulation also differs.
Currently using this -Ofast flag does not cause any issues because everyone plays in the build which has that flag.
In future I'd like to port my game to Mac, Linux, PS4, Xbox or something else. My leaderboards are on my own server so I want to use the same leaderboards shared for all platforms. That's why I need the game to work exactly the same on every platform.
My doubt is that if I keep this -Ofast, everyone will play with it and when I need to port my game to another platform, I might need to change my compiler and that compiler might not have the same flag, or the math may be working differently in that compiler.
Which flags should I avoid and which flags should I choose to make sure it will simulate the same replay, same in every platform?
Edit: Avoiding -Ofast to get rid of -ffast-math sounds obvious but what else should I use and will it be fine after that?
This will be very difficult to achieve.
Certainly if you are targeting 32bit and 64bit x86/amd64 architectures you want to use SSE for both, otherwise on 32 bit x86 you may end up using x87 which will definitely cause differences.
Even if you can iron out any differences in your own compiled code, you are likely to encounter differences in the standard library. For instance, I've come across differences in the implementation of std::pow() between FreeBSD/Solaris and Linux.
I suppose that using a fixed point representation is out of the question?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With