#include "ReplayPlayer.h" #include #include "Command.h" #include "Simulation.h" ReplayPlayer::ReplayPlayer(Simulation& simulation, std::vector 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 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; } } }