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>
57 lines
1.3 KiB
C++
57 lines
1.3 KiB
C++
#include "ReplayPlayer.h"
|
|
|
|
#include <utility>
|
|
|
|
#include "Command.h"
|
|
#include "Simulation.h"
|
|
|
|
ReplayPlayer::ReplayPlayer(Simulation& simulation, std::vector<ReplayEntry> entries)
|
|
: m_simulation(simulation)
|
|
, m_entries(std::move(entries))
|
|
{
|
|
}
|
|
|
|
void ReplayPlayer::start()
|
|
{
|
|
processEntriesAt(0);
|
|
}
|
|
|
|
void ReplayPlayer::advanceTo(Tick tick)
|
|
{
|
|
processEntriesAt(tick);
|
|
}
|
|
|
|
bool ReplayPlayer::isFinished() const
|
|
{
|
|
return m_desyncTick.has_value() || m_cursor >= m_entries.size();
|
|
}
|
|
|
|
std::optional<Tick> ReplayPlayer::getDesyncTick() const
|
|
{
|
|
return m_desyncTick;
|
|
}
|
|
|
|
void ReplayPlayer::processEntriesAt(Tick tick)
|
|
{
|
|
// Consume entries for this tick in file order. The recording writes, at a
|
|
// given tick: the periodic checksum (if any) first, then command lines each
|
|
// followed by their post-apply checksum — so applying/verifying in file order
|
|
// reproduces the original sequence exactly.
|
|
while (!m_desyncTick.has_value()
|
|
&& m_cursor < m_entries.size()
|
|
&& m_entries[m_cursor].tick == tick)
|
|
{
|
|
const ReplayEntry& entry = m_entries[m_cursor];
|
|
++m_cursor;
|
|
|
|
if (entry.isCommand)
|
|
{
|
|
m_simulation.apply(*entry.command);
|
|
}
|
|
else if (m_simulation.rngFingerprint() != entry.fingerprint)
|
|
{
|
|
m_desyncTick = tick;
|
|
}
|
|
}
|
|
}
|