Verified over a live relay
Deterministic Lockstep Multiplayer
Two devices running the same battle, frame for frame
Making a single-player battle simulation compute the same result on two devices, forever, so it could be played 1v1 over a relay that never carries the world.
- 8,820
- frames bit-identical on both clients
Why lockstep, and what it costs
A battle in To The Trenches can hold hundreds of soldiers, each with position, orders, health and animation state. Sending that world across the network several times a second is not affordable on a phone, and it is not necessary either.
Lockstep sends the commands instead. Both devices run the same simulation and only exchange what the players did, which is tiny. The price is absolute: if the two machines ever compute one different number, they are playing different games from that frame on, and nothing in the protocol will tell them. Determinism stops being a nice property and becomes the entire contract.
The simulation was not deterministic, and it never had to be
None of this had ever mattered. Single player runs one simulation on one device, so the code reached for the engine's global random number generator freely: scatter on artillery, hit rolls, idle animation offsets, spawn jitter. There were roughly 170 of those call sites through the combat code.
Map generation was a second source of divergence, and animation and iteration order a third. Determinism is a property of a whole system, not of a module you can bolt on at the edge.
What I changed
Every random call was rerouted through a seeded generator both clients agree on, swapped in at all ~170 sites, so the sequence of rolls is a function of the seed rather than of the engine's internal state.
Battlefields were made premade and symmetric for the first version. Procedural generation is a large surface for divergence and it is not what a 1v1 match needed, so it was removed from the equation rather than made deterministic.
Then a checksum harness: sample the simulation state every frame on both clients and compare. That is the only thing that turns a belief about determinism into a measurement.
The result
Two clients played a full match over a live Photon relay with 8,820 consecutive frames bit-identical on both sides. Not statistically close, identical.
The desyncs found on the way there were catalogued as they were fixed, because each one is a category of mistake rather than a single bug, and the next person to touch the simulation needs the list more than they need the fixes.