Replay: deterministic record & playback (#4)
Add deterministic record/playback for a run. Recording captures `(seed, config hash, ordered tick-tagged commands)` and re-simulates on playback — no state snapshots. `DotaFactory.exe --replay <file>` re-plays a recorded run view-only with manual speed/pause. Reviewed-on: #4 Co-authored-by: Malte Langkabel <malte.langkabel@gmail.com> Co-committed-by: Malte Langkabel <malte.langkabel@gmail.com>
This commit was merged in pull request #4.
This commit is contained in:
55
src/lib/sim/CommandManager.h
Normal file
55
src/lib/sim/CommandManager.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
struct Command;
|
||||
class ReplayRecorder;
|
||||
class Simulation;
|
||||
|
||||
// Ordered queue that funnels every player command into the single
|
||||
// Simulation::apply chokepoint (see docs/replay_design.md). This is deliberately
|
||||
// NOT the EventManager pub/sub bus: sim mutations must apply in a strict,
|
||||
// tick-pinned, recordable order to a single recipient.
|
||||
//
|
||||
// Live play pushes commands via enqueue(); they are applied at the next drain(),
|
||||
// which runs once per frame before the tick batch. Draining before the tick
|
||||
// (even at 0x game speed) lets a paused player see placed construction sites
|
||||
// immediately while staying deterministic — replay applies each command at its
|
||||
// recorded tick regardless of frame cadence.
|
||||
class CommandManager
|
||||
{
|
||||
public:
|
||||
explicit CommandManager(Simulation& simulation);
|
||||
// Defined out-of-line so the unique_ptr<ReplayRecorder> member can be
|
||||
// destroyed where ReplayRecorder is a complete type.
|
||||
~CommandManager();
|
||||
|
||||
// Append a command for application at the next drain (FIFO order).
|
||||
void enqueue(std::shared_ptr<const Command> command);
|
||||
|
||||
// Apply all queued commands in FIFO order through Simulation::apply, then
|
||||
// clear the queue. If a recorder is attached, each applied command is recorded
|
||||
// (a Reset rolls the recorder to a new file).
|
||||
void drain();
|
||||
|
||||
bool hasPending() const;
|
||||
|
||||
// Attach a recorder and start recording the current run. Ownership is taken.
|
||||
// Passing nullptr detaches/stops recording.
|
||||
void setRecorder(std::unique_ptr<ReplayRecorder> recorder);
|
||||
|
||||
// In replay mode, enqueue() is a no-op: the queue is driven by the recorded
|
||||
// stream (ReplayPlayer), so stray live input produces nothing.
|
||||
void setReplayMode(bool replayMode);
|
||||
|
||||
// Record a periodic RNG checksum if the current tick is on the checksum
|
||||
// cadence. Call once per simulated tick (from the tick loop).
|
||||
void recordTickCheckpoint();
|
||||
|
||||
private:
|
||||
Simulation& m_simulation;
|
||||
std::vector<std::shared_ptr<const Command>> m_queue;
|
||||
std::unique_ptr<ReplayRecorder> m_recorder;
|
||||
bool m_replayMode = false;
|
||||
};
|
||||
Reference in New Issue
Block a user