Skip to main content

Action Replay System

Record player input as timestamped frames and replay it at any speed. Use it for ghost racing, replays, AI training data, QA reproduction, or highlight clips.

Structure

ActionRecorder (pure C# instance)
- Adds InputFrame entries to ReplayData when input occurs

ActionPlayer (pure C# instance)
- Plays ReplayData through Tick(deltaTime) and emits OnFrame events

InputFrame (struct)
- Timestamp, ActionKey, Axis, IsPressed

ReplayData (class)
- TotalDuration + List<InputFrame>

Quick Start

1. Record

using AchUtils.ActionReplay;

private readonly ActionRecorder recorder = new();

recorder.StartRecording();

public void OnJumpPressed()
{
recorder.RecordButton("Jump", pressed: true);
// Run real jump logic...
}

public void OnMove(Vector2 axis)
{
recorder.RecordAxis("Move", axis);
}

ReplayData data = recorder.StopRecording();
SaveReplay(data);

2. Replay

private readonly ActionPlayer player = new();

void Update()
{
player.Tick(Time.deltaTime);
}

void PlayGhost(ReplayData data)
{
player.OnFrame += HandleFrame;
player.Play(data, speed: 1f);
}

void HandleFrame(InputFrame frame)
{
switch (frame.ActionKey)
{
case "Jump": ghost.Jump(); break;
case "Move": ghost.Move(frame.Axis); break;
case "Attack": ghost.Attack(); break;
}
}

player.OnCompleted += () =>
{
Debug.Log("Replay completed");
player.OnFrame -= HandleFrame;
};

API

ActionRecorder

bool IsRecording
ReplayData LastRecording

void StartRecording()
ReplayData StopRecording()

void RecordButton(string key, bool pressed)
void RecordAxis(string key, Vector2 axis)
void Record(string key, Vector2 axis = default, bool pressed = true)

ActionPlayer

bool IsPlaying

void Play(ReplayData data, float speed = 1f)
void Stop()
void Tick(float deltaTime)

event Action<InputFrame> OnFrame
event Action OnCompleted
event Action OnStopped

InputFrame

float Timestamp
string ActionKey
Vector2 Axis
bool IsPressed

Playback Speed

player.Play(data, speed: 0.5f); // Slow motion
player.Play(data, speed: 2.0f); // Double speed

Serialization

ReplayData is [Serializable], so it can be saved as JSON.

string json = JsonUtility.ToJson(data);
File.WriteAllText("replay.json", json);

string json = File.ReadAllText("replay.json");
ReplayData data = JsonUtility.FromJson<ReplayData>(json);

Use Cases

Use caseDescription
Ghost racingReplay a best run as a translucent object
Replay systemWatch the moments before death
AI training dataUse human input for imitation learning
Bug reproductionReproduce QA input exactly
Video clipsAuto-cut highlight moments

::: warning Networking Multiplayer replay sync requires a deterministic game loop. Physics-heavy games should drive physics manually, for example with Physics.simulationMode = Script. :::