appsinacup/godot-rapier-physics

Investigate Cross Platform Determinsim

Ughuuu opened this issue · 6 comments

Right now the plugin isn't cross platform deterministic. The issues could be from:

  • The internal state of the plugin
  • The wrapper of rapier
  • Something else

From my investigation the plugin uses .length(), as it uses Vector2 of godot-cpp, which in turn uses sqrt, which isn't cross platform deterministic.

Need to investigate other possible things as well. After asking on chat.godotengine.com about it, got some helpful tips as well:

AThousandShips:

Then it isn't related to the extension code itself, and the only possible cause is the cross-platform differences in sqrt etc.
As the built-in types like those are entirely self-contained on extensions, for performance reasons
But I'd suggest just testing the output of various simple operations across platforms just to see, generate a bunch of vectors for example and run the operations on them on both systems, just create a data file to store them in and load them on both machines
If they yield the same results then it's going to be the way you've translated this library to the language in question, it's easy to make mistakes when translating between languages
And of course make sure you're actually setting up a test that ensures determinism, because floating point mathematics isn't deterministic when out of order due to rounding, so it's important that your testing conditions are actually such that they test for determinism
And, and this is really important, make sure the data for the tests are dynamic, no compile time tests, it has to be loaded, because that's a classic trap
Especially with floating point math compile time and runtime is a mess

Can refer to this:
https://gitlab.com/snopek-games/sg-physics-2d

Doesn't support rigid bodies and is written from scratch but the author has created a separate vector implementation

Running the following code:

extends Node2D


func _ready():
	var angle_start = -PI
	var steps = 1000
	var step_increase = 1.0 / steps
	var hash_final :int = 0
	for step in 1000:
		var angle :float= angle_start + step * step_increase * 2 * PI
		var value :float= step * step_increase * 10
		var str1 :String= "angle: " + str(angle) + " sin: " + str(sin(angle))+ " cos: "+ str(cos(angle))+ " tan: "+ str(tan(angle))
		var str2 :String= "value: " + str(value) + " sqrt: " + str(sqrt(value))
		hash_final += str1.hash()
		hash_final += str2.hash()
	print(hash_final)

on both mac and web, I get the following hashes:

  • mac: 4235844765204
  • web: 4233582584233

So it seems the sin/cos/tan/sqrt implementations are indeed not cross platform deterministic.

For me it gives same hash:

Web: 4233582584233
Linux: 4233582584233

has there been any progress on this front?

With the new rewrite itll be possible and easier to do this, add in rust it's easier to save state of objects, and also to build for web.

Removing it from issues as it is in readme as limitation. Better to not track it in issues also.