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>
56 lines
2.2 KiB
C++
56 lines
2.2 KiB
C++
#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;
|
|
};
|