GDScript determinism

I’m trying to create a multiplayer framework as a plugin using GDScript.

Server and client communication is done using only inputs, so it is fundamental that scripts produce the same results in all builds across different hardware, compiler, OS, etc.

To over-simplify:

class_name SimulationState

# variables defining simulation state
# ..

func serialize(data: PackedByteArray) -> void:
    # serialize state
    pass

func deserialize(data: PackedByteArray) -> void:
    # deserialize state (i.e. with data sent from server)
    pass

func step(input) -> void:
    # Update simulation with a set of inputs (i.e. client button state, server-generated inputs)
    pass

Scope of my questions is only for GDScript itself, without considering things like physics. SimulationState will only ever change when step function is called and is otherwise considered immutable.

I know that using floating points can lead to different results so let’s assume that I’m using a fixed-point extension instead.

Given the same initial state, same number of steps with identical inputs, can I assume that serialize() will produce the same PackedByteArray? If not, what are some things that can cause a de-sync?

2 Likes

You can test it. Serialize in one device and deserialize in other and see the results.

Make one of the players (or the server) have authority over the simulation and just distribute the results.
Players can run their own speculative simulations to make the visuals smooth, but once in a while (1s?) do a reset from the authority.

If you are really concerned, you can convert floats to binary coded decimal (BCD) during serialization and back during deserialzation.