93 lines
2.4 KiB
C++
93 lines
2.4 KiB
C++
#include "CommandManager.h"
|
|
|
|
#include <utility>
|
|
|
|
#include "Command.h"
|
|
#include "ReplayRecorder.h"
|
|
#include "Simulation.h"
|
|
#include "Tick.h"
|
|
|
|
namespace
|
|
{
|
|
// Periodic RNG checksum cadence (see docs/replay_design.md "Cadence").
|
|
constexpr Tick kChecksumIntervalTicks = 30;
|
|
} // namespace
|
|
|
|
CommandManager::CommandManager(Simulation& simulation)
|
|
: m_simulation(simulation)
|
|
{
|
|
}
|
|
|
|
CommandManager::~CommandManager() = default;
|
|
|
|
void CommandManager::enqueue(std::shared_ptr<const Command> command)
|
|
{
|
|
if (m_replayMode)
|
|
{
|
|
return; // playback is driven by the recorded stream; ignore live input
|
|
}
|
|
if (command)
|
|
{
|
|
m_queue.push_back(std::move(command));
|
|
}
|
|
}
|
|
|
|
void CommandManager::drain()
|
|
{
|
|
// Apply in FIFO order. A queued ResetCommand reinitializes the simulation in
|
|
// place; the reference stays valid and any commands after it apply to the
|
|
// fresh state.
|
|
for (const std::shared_ptr<const Command>& command : m_queue)
|
|
{
|
|
if (command->kind == CommandKind::Reset)
|
|
{
|
|
m_simulation.apply(*command);
|
|
if (m_recorder)
|
|
{
|
|
// Restart is a file boundary: a fresh file with the new seed.
|
|
m_recorder->startNewRun(m_simulation.getSeed(),
|
|
m_simulation.getRngFingerprint());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Commands drain before the tick batch, so currentTick is the count of
|
|
// completed ticks the command is pinned to.
|
|
const Tick tick = m_simulation.getCurrentTick();
|
|
m_simulation.apply(*command);
|
|
if (m_recorder)
|
|
{
|
|
m_recorder->recordCommand(tick, *command, m_simulation.getRngFingerprint());
|
|
}
|
|
}
|
|
}
|
|
m_queue.clear();
|
|
}
|
|
|
|
bool CommandManager::hasPending() const
|
|
{
|
|
return !m_queue.empty();
|
|
}
|
|
|
|
void CommandManager::setRecorder(std::unique_ptr<ReplayRecorder> recorder)
|
|
{
|
|
m_recorder = std::move(recorder);
|
|
if (m_recorder)
|
|
{
|
|
m_recorder->startNewRun(m_simulation.getSeed(), m_simulation.getRngFingerprint());
|
|
}
|
|
}
|
|
|
|
void CommandManager::setReplayMode(bool replayMode)
|
|
{
|
|
m_replayMode = replayMode;
|
|
}
|
|
|
|
void CommandManager::recordTickCheckpoint()
|
|
{
|
|
if (m_recorder && (m_simulation.getCurrentTick() % kChecksumIntervalTicks == 0))
|
|
{
|
|
m_recorder->recordChecksum(m_simulation.getCurrentTick(), m_simulation.getRngFingerprint());
|
|
}
|
|
}
|