Bicameral Engine
GPU-resident engine for a magic-research open-world game
Loading...
Searching...
No Matches
replay_file.h
Go to the documentation of this file.
1// replay_file.h — 再生ファイル(初期状態 + コマンドの列 + 刻みごとのハッシュ)の形と読み書き(T-0086、15 §2・06 §3)。
2//
3// 世界は「初期状態 + その刻みに当たるコマンド」だけで決まる(06 §1・D-205)ので、コマンドの列を持てば世界が再現できる。
4// 刻みごとの状態のハッシュ S(t) は検査用(再生して同じハッシュ列になれば同じ世界。間引いてよい)。
5// 書く: フレームのループ(--record)が、GPU のキューへ足したコマンドと、読み戻したハッシュを集めて終わりに書く。
6// 読む: フレームのループ(--replay)が、コマンドを刻みに間に合うように GPU のキューへ足し、読み戻したハッシュを突き合わせる。
7// 使い道はバグの再現・機種間の比較(04 §5)・発見の共有(D-110)・デモの撮影(15 §2)。
8//
9// ファイルの形(リトルエンディアン。形式の版を変えたら、古い版を読む変換とテストを足す。15 §1):
10// [0] "BCRP"(4 バイト) [4] 形式の版 u32 [8] 世界の種類 u32 [12] 予約 u32(0)
11// [16] 表の版 u64 [24] シード u64 [32] 初期状態の刻み u64
12// [40] 初期状態の差分のバイト数 u64 [48] コマンドの数 u64 [56] ハッシュの数 u64
13// [64] 初期状態の差分(8 バイトの境界まで 0 で埋める)→ コマンド × 64 バイト(sim/command.h)→ ハッシュ × 16 バイト(刻み u64・値 u64)
14// 読むときは大きさ・並び((targetTick, sequence) の昇順・ハッシュの刻みの昇順)を確かめ、合わなければ理由を返す。
15// ここは CPU だけ(GPU を知らない)。
16#pragma once
17
18#include <cstdint>
19#include <expected>
20#include <filesystem>
21#include <span>
22#include <string>
23#include <vector>
24
25#include "core/aliases.h"
26#include "sim/command.h"
27
28namespace bicameral::save {
29
30 inline constexpr uint32_t REPLAY_FORMAT_VERSION = 1;
31
32 // 世界の種類(どのシミュのコマンドと状態か)。ファイルには u32 で書く
33 enum class ReplayWorld : uint8_t {
34 Probe = 1, // 仮の世界(sim/probe_sim。T-0004〜)。初期状態は全部 0、表は無い
35 };
36
38 uint64_t tick = 0; // 状態 S(tick)(刻み tick の始め)
39 uint64_t hash = 0;
40
41 friend bool operator==(const ReplayTickHash&, const ReplayTickHash&) = default;
42 };
43
44 struct ReplayFile {
45 // --- どの世界の、どの状態から始まるか ---
47 uint64_t tableVersion = 0; // 反応表などの版(パッケージの一覧のハッシュ。13 §2)。仮の世界は 0
48 uint64_t seed = 0; // 世界の生成のシード(D-312)
49 uint64_t startTick = 0; // 初期状態の刻み
50 std::vector<std::byte> initialDelta; // シードからの差分(05 §6)。仮の世界は空
51
52 // --- 進め方と検査 ---
53 std::vector<sim::Command> commands; // (targetTick, sequence) の昇順
54 std::vector<ReplayTickHash> tickHashes; // 刻みの昇順
55
56 friend bool operator==(const ReplayFile&, const ReplayFile&) = default;
57 };
58
59 // バイト列との変換(ファイルを介さないテスト用にも)
60 [[nodiscard]] std::expected<std::vector<std::byte>, std::string> SerializeReplay(const ReplayFile& replay);
61 [[nodiscard]] std::expected<ReplayFile, std::string> ParseReplay(std::span<const std::byte> bytes);
62
63 [[nodiscard]] std::expected<void, std::string> WriteReplayFile(const fs::path& path, const ReplayFile& replay);
64 [[nodiscard]] std::expected<ReplayFile, std::string> ReadReplayFile(const fs::path& path);
65
66} // namespace bicameral::save
std::expected< ReplayFile, std::string > ReadReplayFile(const fs::path &path)
std::expected< std::vector< std::byte >, std::string > SerializeReplay(const ReplayFile &replay)
std::expected< void, std::string > WriteReplayFile(const fs::path &path, const ReplayFile &replay)
constexpr uint32_t REPLAY_FORMAT_VERSION
Definition replay_file.h:30
std::expected< ReplayFile, std::string > ParseReplay(std::span< const std::byte > bytes)
std::vector< sim::Command > commands
Definition replay_file.h:53
friend bool operator==(const ReplayFile &, const ReplayFile &)=default
std::vector< std::byte > initialDelta
Definition replay_file.h:50
std::vector< ReplayTickHash > tickHashes
Definition replay_file.h:54
friend bool operator==(const ReplayTickHash &, const ReplayTickHash &)=default