I am currently working on an input based replay system for my project. During the game, all player input is stored and saved to a JSON file. When a replay is viewed, these inputs are replayed in correct order. Everything in my game (ideally) runs on a fixed timestep (some workarounds were required—things like Destroy() don’t run in the fixed loop, and a custom random class is used). I’ve found an issue where Unity is not executing scripts in the same order for each playthrough of a scene in the editor.
When a scene is run from the editor, in the first playthrough objects scripts will be executed bottom to top in the hierarchy. If the scene is reloaded (via a call to SceneManager.LoadScene), any subsequent playthroughs will have objects executed top to bottom. I’ve included a project that replicates this behaviour.
Anyways, this is the physics forum, so the tl;dr is that this has implications for determinism. I’m guessing objects are also inserted into the physics engine in reverse order too, as I’m seeing immediate desyncs (different positions in the replay than what was recorded in the original game) on all objects that have any interaction on scene start (stacks of objects, for example).
PhysX does have Enable Enhanced Determinism, but this won’t be effective if Unity inserts the objects in a different order. Is this a known issue, and is there a fix/workaround? I can ofc just force a reload on scene start, but I’d like to get to the bottom of this, since random desyncs aren’t a ton of fun.
The only reliable way I know to record and replay a physics system in Unity is to record the position and rotation of every Rigidbody in every fixed timestep. Playing a recorded sequence re-applies the positions and rotations with Rigidbody.MovePosition and Rigidbody.MoveRotation. Using the input alone results in a complete desync after a few seconds.
Recording positions and rotations is also more reliable, as makes the recorded sequences much more solid against changes and updates in the project.
I’ve captured replays that are over 5 minutes that stay consistent, with a very large number of rigidbodies, even at 10x speed, so it is possible (as stated above, there is a pretty wide variety of things Unity does at the end of Update that need hacks/workarounds).
Oh! Good to know, thanks for pointing it out. I guess the evident non-deterministic issues are applicable to vehicles and WheelColliders only. Basically there’s no deterministic way to know/reproduce the actual state of the WheelCollider consistently.
Still, personally I wouldn’t use input-based replays no matter how consistent they look. The smallest change in any sensitive area either in Unity or in the game code itself would render them unusable. Replays based on recording position and rotation can easily survive most code changes. They may use more memory, but it’s in the same order of magnitude and workarounds are easily applicable (i.e. don’t record values for rigidbodies that aren’t moving).
I looked into using serialization with delta compression, but overall I didn’t mind going the path of inputs since most of the stuff you need to do (ensuring your game operates on a fixed timestep) would be valuable down the line for networking. It also allows some neat functionality, like being able to analyze bugs that occur via the replays.
It’s not for the faint of heart though, had to make a system that does error checking constantly, too stressful to just watch and hope it doesn’t desync