Bicameral Engine
GPU-resident engine for a magic-research open-world game
Loading...
Searching...
No Matches
reaction_table_loader.cpp
Go to the documentation of this file.
1// reaction_table_loader.cpp — データのフォルダのパッケージ → 反応表のベイク(reaction_table_loader.h。T-0157・ADR-0033)。
2// 失敗の出し方: どの段で落ちたか(フォルダ・パッケージの読み込み・形・ベイクの検査)を頭に付けて 1 行で返す。
4
5#include <algorithm>
6#include <format>
7#include <utility>
8
9#include "core/paths.h"
10#include "script/luau_sandbox.h"
13
14namespace bicameral::script {
15
16 namespace {
17
18 std::string PathText(const fs::path& path) {
19 const std::u8string text = path.generic_u8string();
20
21 return {text.begin(), text.end()};
22 }
23
24 // ゲーム本体が読めたか。読めなかったら理由(rejected にあればそれ、無ければ「見つからない」)
25 std::expected<void, std::string> CheckBasePackage(const PackageSetResult& loaded,
26 std::string_view basePackage) {
27 if (std::ranges::contains(loaded.loadOrder, basePackage))
28 return {};
29
30 const auto rejection = std::ranges::find(loaded.rejected, basePackage, &PackageRejection::package);
31 if (rejection != loaded.rejected.end())
32 return std::unexpected(
33 std::format("ゲーム本体のパッケージ {} を読めない: {}", basePackage, rejection->reason));
34
35 return std::unexpected(std::format("ゲーム本体のパッケージ {} が見つからない", basePackage));
36 }
37
38 // パッケージ群を型検査してから殻で読んで合わせる(ホストの関数は無い。反応表は値だけ)
39 std::expected<PackageSetResult, std::string> LoadPackageSet(std::span<const PackageSource> packages,
40 const ReactionTableSource& source) {
41 const fs::path definitions = source.typeDefinitions.empty() ? DefaultTypeDefinitionsPath()
42 : source.typeDefinitions;
43 auto checker = CreateTypeCheckerFromFile(definitions);
44 if (!checker)
45 return std::unexpected(checker.error());
46
47 auto sandbox = LuauSandbox::Create(SandboxLimits{});
48 if (!sandbox)
49 return std::unexpected(sandbox.error());
50
51 (*sandbox)->Seal();
52
53 return LoadPackages(
54 **sandbox, packages,
56 .mergeMode = source.mergeMode, .basePackage = source.basePackage, .typeChecker = checker->get()});
57 }
58
59 } // namespace
60
61 fs::path DefaultPackageRoot() {
62 return ExecutableDirectory() / "data" / "packages";
63 }
64
65 std::expected<LoadedReactionTable, std::string> LoadReactionTable(const ReactionTableSource& source) {
66 const fs::path root = source.packageRoot.empty() ? DefaultPackageRoot() : source.packageRoot;
67 const std::string where = std::format("反応表のパッケージ({})", PathText(root));
68
69 // --- フォルダ → パッケージ → 合わせた表 ---
70 const auto packages = ReadPackageRoot(root);
71 if (!packages)
72 return std::unexpected(std::format("{}: {}", where, packages.error()));
73
74 const auto loaded = LoadPackageSet(*packages, source);
75 if (!loaded)
76 return std::unexpected(std::format("{}: {}", where, loaded.error()));
77
78 if (const auto base = CheckBasePackage(*loaded, source.basePackage); !base)
79 return std::unexpected(std::format("{}: {}", where, base.error()));
80
81 // --- 定義 → ベイク(元素の釣り合い・知らない物質・係数・速度の範囲の検査)---
82 const auto definition = ReadReactionTableDefinition(*loaded);
83 if (!definition)
84 return std::unexpected(std::format("{}: {}", where, definition.error()));
85
86 auto baked = sim::BakeReactionTable(*definition);
87 if (!baked)
88 return std::unexpected(std::format("{}: ベイクの検査で落ちた: {}", where, baked.error()));
89
90 return LoadedReactionTable{.table = std::move(*baked),
91 .packageRoot = root,
92 .loadOrder = loaded->loadOrder,
93 .rejected = loaded->rejected,
94 .overrides = loaded->overrides,
95 .modifiedWorld = loaded->modifiedWorld,
96 .tableVersion = TableVersion(*loaded)};
97 }
98
99} // namespace bicameral::script
static std::expected< std::unique_ptr< LuauSandbox >, std::string > Create(SandboxLimits limits)
std::expected< PackageSetResult, std::string > LoadPackageSet(std::span< const PackageSource > packages, const ReactionTableSource &source)
std::expected< void, std::string > CheckBasePackage(const PackageSetResult &loaded, std::string_view basePackage)
std::expected< std::vector< PackageSource >, std::string > ReadPackageRoot(const fs::path &root)
std::expected< PackageSetResult, std::string > LoadPackages(LuauSandbox &sandbox, std::span< const PackageSource > packages, const PackageLoadOptions &options)
std::expected< ReactionTableDefinition, std::string > ReadReactionTableDefinition(const PackageSetResult &packages)
fs::path DefaultTypeDefinitionsPath()
std::expected< std::unique_ptr< LuauTypeChecker >, std::string > CreateTypeCheckerFromFile(const fs::path &definitionsFile)
uint64_t TableVersion(const PackageSetResult &result)
std::expected< LoadedReactionTable, std::string > LoadReactionTable(const ReactionTableSource &source)
std::expected< BakedReactionTable, std::string > BakeReactionTable(const ReactionTableDefinition &definition)
fs::path ExecutableDirectory()
Definition paths.cpp:12
std::vector< std::string > loadOrder
std::vector< PackageRejection > rejected