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:
@@ -1,4 +1,7 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
@@ -8,6 +11,8 @@
|
||||
#include "logging.h"
|
||||
#include "LogManager.h"
|
||||
#include "MainWindow.h"
|
||||
#include "ReplayReader.h"
|
||||
#include "ReplayRecorder.h"
|
||||
#include "Simulation.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -31,10 +36,54 @@ int main(int argc, char *argv[])
|
||||
QDir().mkdir(dataDir.dirName());
|
||||
}
|
||||
|
||||
GameConfig config = ConfigLoader::loadFromDirectory(CONFIG_DIR);
|
||||
std::unique_ptr<Simulation> sim = std::make_unique<Simulation>(std::move(config));
|
||||
// Optional "--replay <file>" launches view-only playback of a recorded run.
|
||||
std::optional<std::string> replayPath;
|
||||
for (int i = 1; i + 1 < argc; ++i)
|
||||
{
|
||||
if (std::string(argv[i]) == "--replay")
|
||||
{
|
||||
replayPath = argv[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MainWindow window(sim.get(), std::string(CONFIG_DIR));
|
||||
GameConfig config = ConfigLoader::loadFromDirectory(CONFIG_DIR);
|
||||
|
||||
unsigned int seed = 0;
|
||||
std::shared_ptr<ParsedReplay> replay;
|
||||
if (replayPath.has_value())
|
||||
{
|
||||
std::optional<ParsedReplay> parsed = readReplayFile(*replayPath);
|
||||
if (!parsed.has_value())
|
||||
{
|
||||
LOG_ERROR("Failed to read replay file: " + *replayPath);
|
||||
return 1;
|
||||
}
|
||||
// Warn (but proceed) on identity mismatches: a different config or build
|
||||
// can desync playback (see docs/replay_design.md).
|
||||
if (parsed->header.version != 1)
|
||||
{
|
||||
LOG_WARNING_STREAM(<< "Replay format version " << parsed->header.version
|
||||
<< " differs from 1; playback may fail");
|
||||
}
|
||||
if (computeReplayConfigHash(CONFIG_DIR) != parsed->header.configHash)
|
||||
{
|
||||
LOG_WARNING("Replay config hash mismatch; playback may desync");
|
||||
}
|
||||
seed = parsed->header.seed;
|
||||
replay = std::make_shared<ParsedReplay>(std::move(*parsed));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Random seed generated outside the sim so the Simulation stays a pure
|
||||
// function of (seed, config, commands); written to the replay header
|
||||
// (see docs/replay_design.md "Seed and config").
|
||||
seed = std::random_device{}();
|
||||
}
|
||||
|
||||
std::unique_ptr<Simulation> sim = std::make_unique<Simulation>(std::move(config), seed);
|
||||
|
||||
MainWindow window(sim.get(), std::string(CONFIG_DIR), replay);
|
||||
window.show();
|
||||
|
||||
const int ret = application.exec();
|
||||
|
||||
Reference in New Issue
Block a user