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:
55
src/lib/sim/StateChecksum.h
Normal file
55
src/lib/sim/StateChecksum.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include <QPoint>
|
||||
#include <QPointF>
|
||||
#include <QVector2D>
|
||||
|
||||
// FNV-1a 64-bit accumulator used to fingerprint simulation state for
|
||||
// determinism verification (see docs/replay_design.md "Determinism").
|
||||
//
|
||||
// Subsystems contribute their own state through appendChecksum(Hasher&) so the
|
||||
// hash stays close to the data it covers and no state knowledge is duplicated.
|
||||
// The accumulator is order-sensitive; callers fold state in a deterministic
|
||||
// order (sorted containers, fixed view iteration).
|
||||
class Hasher
|
||||
{
|
||||
public:
|
||||
// Folds raw bytes into the running hash.
|
||||
void appendBytes(const void* data, std::size_t byteCount);
|
||||
|
||||
// Trivially-copyable scalars (ints, enums) are hashed by object representation.
|
||||
// Floating-point and Qt types have dedicated overloads below and bypass this.
|
||||
template <typename T>
|
||||
void append(const T& value)
|
||||
{
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Hasher::append requires a trivially copyable type "
|
||||
"(add a dedicated overload otherwise)");
|
||||
appendBytes(&value, sizeof(T));
|
||||
}
|
||||
|
||||
// Floats are hashed by bit pattern so equal values always hash equally;
|
||||
// negative zero is normalized so -0.0 and +0.0 collapse to one value.
|
||||
void append(float value);
|
||||
void append(double value);
|
||||
void append(const QPoint& point);
|
||||
void append(const QPointF& point);
|
||||
void append(const QVector2D& vector);
|
||||
void append(const std::string& text);
|
||||
|
||||
std::uint64_t value() const { return m_state; }
|
||||
|
||||
private:
|
||||
std::uint64_t m_state = 14695981039346656037ull; // FNV-1a 64-bit offset basis
|
||||
};
|
||||
|
||||
// Folds the full mt19937 internal state into a 64-bit fingerprint. mt19937 has a
|
||||
// portable, bit-identical text serialization, so this fingerprint is stable
|
||||
// across platforms (see docs/replay_design.md "Cross-platform").
|
||||
std::uint64_t fingerprintRng(const std::mt19937& rng);
|
||||
Reference in New Issue
Block a user