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:
54
src/lib/sim/ReplayRecorder.h
Normal file
54
src/lib/sim/ReplayRecorder.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include "Tick.h"
|
||||
|
||||
struct Command;
|
||||
|
||||
// 64-bit hash (16-char hex) over the *.toml files in configDir. Stored in the
|
||||
// replay header and recomputed on playback to detect a config mismatch.
|
||||
std::string computeReplayConfigHash(const std::string& configDir);
|
||||
|
||||
// Writes a replay file as the game runs (see docs/replay_design.md). The format
|
||||
// is line-oriented append-friendly text: a small keyed header, then one line per
|
||||
// command (tick-tagged) interleaved with RNG-state checksum lines for desync
|
||||
// detection. Each line is flushed so a crash mid-run still leaves a valid partial
|
||||
// file.
|
||||
//
|
||||
// One file = one run between Reset boundaries; startNewRun() closes the current
|
||||
// file and opens a fresh one.
|
||||
class ReplayRecorder
|
||||
{
|
||||
public:
|
||||
// configDir: hashed (its *.toml files) into the header for config-mismatch
|
||||
// detection on playback. outputDir: where .replay files are written.
|
||||
ReplayRecorder(std::string configDir, std::string outputDir);
|
||||
~ReplayRecorder();
|
||||
|
||||
ReplayRecorder(const ReplayRecorder&) = delete;
|
||||
ReplayRecorder& operator=(const ReplayRecorder&) = delete;
|
||||
|
||||
// Close any current file, then open a fresh one (named <timestamp>_<seed>),
|
||||
// write the header, and record an initial tick-0 checksum. A run boundary.
|
||||
void startNewRun(unsigned int seed, std::uint64_t initialRngFingerprint);
|
||||
|
||||
// Append one command line tagged with the tick it was applied at, followed by
|
||||
// the post-apply RNG checksum.
|
||||
void recordCommand(Tick tick, const Command& command, std::uint64_t rngFingerprint);
|
||||
|
||||
// Append a periodic RNG checksum line.
|
||||
void recordChecksum(Tick tick, std::uint64_t rngFingerprint);
|
||||
|
||||
void close();
|
||||
bool isOpen() const;
|
||||
const std::string& currentFilePath() const;
|
||||
|
||||
private:
|
||||
std::string m_configDir;
|
||||
std::string m_outputDir;
|
||||
std::string m_filePath;
|
||||
std::ofstream m_stream;
|
||||
};
|
||||
Reference in New Issue
Block a user