Build a deterministic gameplay record/replay test artefact for Unity, Unreal, or Godot - record a player session, save it to disk, replay it bit-for-bit, and assert that the resulting game state matches the original. Covers Unity Input System's InputEventTrace API (Enable / Disable / WriteTo / ReadFrom / Replay) for input-level capture, Unreal's Replay System (DemoRec / DemoPlay / DemoStop console commands plus DemoNetDriver + NetworkReplayStreamer, default storage at %LOCALAPPDATA%/{Project}/Saved/Demos) for replication-stream capture, and Godot's community-pattern deterministic-RNG + input-script replay since Godot ships no first-party replay system. Use when authoring a regression-test artefact for player-recorded sessions, building a netcode replay for spectator / esports, or producing reproducible bug repros for cert teams.
79
99%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
A deterministic replay artefact is a recorded session of player input or replicated state that can be played back to recreate the original game state. Three reasons games invest in replays:
This is a workflow that produces, per engine, a working record/replay setup plus a CI regression test that runs it. The full per-engine record, replay, and CI code lives in references/engine-record-replay-apis.md; this file is the cross-engine decision surface.
The three engine surfaces differ:
| Engine | Recording surface | Stability of public docs |
|---|---|---|
| Unity | Input System's InputEventTrace (input-level) | Public - com.unity.inputsystem@1.8 API |
| Unreal | Replay System (replication-stream level) - DemoRec / DemoPlay / DemoStop | Public - Replays in Unreal Engine |
| Godot | No first-party replay - community pattern: deterministic RNG seed + recorded InputEvent script | Community - Godot documentation does not ship a replay subsystem [author opinion, per docs.godotengine.org] |
Composes with:
unity-test-framework,
unreal-automation-system,
godot-gut-tests - the host test
framework the replay runs inside.multiplayer-state-machine-coverage -
Unreal's Replay system shares NetworkReplayStreamer with its
multiplayer stack; multiplayer fixtures can replay captured
sessions.platform-cert-overview-reference -
replays are evidence artefacts for cert (Xbox XR-003 title
quality, attaching a repro to a CFR).Gather before walking the workflow:
| Input | Where | Why |
|---|---|---|
| Engine + version | Project | Determines which API surface applies |
| Determinism baseline | Game design - is fixed-tick physics on? RNG seeded? AI deterministic? | Replays only work when the game's per-frame outputs are functions of (state + input) |
| Recording scope | Input-only? Full replication stream? | Trades off file size against determinism guarantees |
| Target storage location | Application.persistentDataPath, %LOCALAPPDATA%/<Project>/Saved/Demos, etc. | Where replay files land |
| Replay length budget | Seconds / minutes | InputEventTrace buffer sizing |
| Assertion model | Final-state hash? Per-frame? Checkpoint-only? | Drives the test harness shape |
Replays are worthless if the game is non-deterministic. Before any recording work, lock down:
| Source of non-determinism | Lock-down |
|---|---|
Variable timestep / Time.deltaTime | Run physics on FixedUpdate (Unity) / TickGroup (Unreal) with a fixed delta |
Unseeded Random | Seed every RNG at session start; record the seed in the replay header |
| Async load timing | Force synchronous load during replay (SceneManager.LoadScene sync; AssetRegistry::Tick to drain) |
| Multithreaded game logic | Pin to one thread or commit to ordered consumption of results |
| Frame-rate-dependent FX | Tag visual-only systems and skip them in headless replay runs |
If you can't lock determinism, replay can still be useful as a visual debug artefact, but it won't drive regression assertions.
Each engine captures at a different level, with a different determinism contract. Pick the row that matches your engine, then lift the working record + replay code from references/engine-record-replay-apis.md.
| Engine | Capture level | Default storage | Determinism contract |
|---|---|---|---|
| Unity | Input events (InputEventTrace, buffer-sized) | Application.persistentDataPath / repo test/ | Needs Step 1 - replay reproduces input; state matches only if the sim is a pure function of state + input |
| Unreal | Replication stream (DemoNetDriver + NetworkReplayStreamer) | %LOCALAPPDATA%/<Project>/Saved/Demos | Reconstructs the server's streamed view - does not require local determinism |
| Godot | Input events + RNG seed (community pattern) | FileAccess path of choice | Same contract as Unity - needs Step 1 |
The key split: input-level replay (Unity, Godot) depends on determinism; replication-stream replay (Unreal) does not, because the Unreal simulation already ran on the server and the replay just re-streams its output. This is why Unreal replays handle full multiplayer matches while Unity/Godot replays are for pinned single-player.
Per engine, the CI loop is:
test/replays/.The per-engine harness code (Unity [UnityTest] PlayMode fixture,
Unreal LatentIt latent command, Godot GUT fixture) is in
references/engine-record-replay-apis.md.
Real-world replays drift when:
Random).The harness must distinguish bug-in-build from
replay-stale. Encode the build hash + replay format version
in the replay header; CI rejects replays whose replay_format < current_format, then either re-records (acceptable for visual
replays) or fails the build (regression test replays).
Inputs:
FixedUpdate, 60 Hz; RNG seeded
from replay header; AI scripted via deterministic state
machines.Assets/Tests/Replays/level1.trace (committed to
the repo).recordFrameMarkers = true per the
API page).GameStateRoot.Serialize() at
T=90 s.Step 1 - physics on FixedUpdate, RNG seeded from replay header, async loads forced synchronous in headless mode.
Step 2 - recorder MonoBehaviour creates InputEventTrace, enables
on level start, writes to level1.trace on first level completion.
Step 3 - CI fixture (UTF [UnityTest]) reads the trace, replays
it, hashes the final GameStateRoot, compares to the baseline
hash committed in Assets/Tests/Baselines/level1.hash.
Step 4 - replay header includes replay_format = 2 and
build_hash = <git-sha>. CI fails the build with a clear "replay
stale" message when format < 2 rather than silently passing.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Recording input without seeding RNG | Replay diverges by frame ~30 | Step 1 - every RNG seeded; seed in replay header |
InputEventTrace without Dispose() | Memory leak per API page - "must be disposed of … or they will leak memory on the unmanaged (C++) memory heap" | Always using / Dispose() |
InputEventTrace without recordFrameMarkers = true | Replay reissues events back-to-back instead of respecting timing per API page | Set recordFrameMarkers = true before Enable() |
| Comparing per-frame state instead of checkpoints | False-positive failures from float-precision drift | Hash at coarse-grained checkpoints (every N seconds or per level) |
| Treating Unreal replays as deterministic input replays | They're replication-stream replays - different determinism contract per Replays page | Document the contract; don't assume input-level determinism |
| Storing replay format version implicitly | Replay-stale failures get misdiagnosed as bugs | Embed replay_format + build_hash in the header |
| Replays committed without their baselines | Asserting nothing | Commit replay.trace + baseline.hash as a pair |
| Replays > 30 min in CI | Replay run time dominates total job time | Split into checkpointed mini-replays |
| Replay scrubbing in test fixtures | Many engines don't expose deterministic scrubbing for tests | Linear playback only in regression fixtures; scrubbing is a feature, not a test surface |
| Replays storing PII | Saved player names / chat messages in attached repros | Strip PII from replay headers before sharing |
.replay file under
%LOCALAPPDATA%/<Project>/Saved/Demos
grows with replicated-property volume - large open-world games
produce GB-scale replays. Use checkpoint-only replays for
long sessions.DemoNetDriver replay completion
in public docs - the spec / latent-command harness must poll
the demo time and time-out. See
Replays in Unreal Engine.InputEventTrace API -
com.unity.inputsystem@1.8.unity-test-framework,
unreal-automation-system,
godot-gut-tests.multiplayer-state-machine-coverage.platform-cert-overview-reference.