载入中...
搜索中...
未找到
Emergence.cpp
浏览该文件的文档.
2
3#include "common/Diagnostic.h"
5#include "common/Value.h"
6
7#include <simplesquirrel/simplesquirrel.hpp>
8
9#include <algorithm>
10#include <cstdint>
11#include <functional>
12#include <memory>
13#include <utility>
14
15namespace eve::emergence {
16namespace {
17
19struct ScriptRuleEngine {
20 explicit ScriptRuleEngine(RuleEngineHandleRef value) : reference(value) {}
21 ~ScriptRuleEngine() noexcept { Emergence::release(reference).ignore("script emergence engine proxy destruction"); }
23};
24
25template <class Ref, class Proxy, class Release>
26ssq::Table makeOwnedProxy(HSQUIRRELVM vm, eve::Result<Ref>&& reference, Release&& release) {
27 if (!reference) {
29 }
30 const Ref ref = std::move(reference).takeValue();
31 auto object = eve::script::makeOwnedSquirrelInstance<Proxy>(vm, std::make_unique<Proxy>(ref));
32 if (!object) {
33 const eve::Status status = object.status();
34 object.ignore("failed to create owned emergence proxy");
35 std::invoke(std::forward<Release>(release), ref).ignore("rollback failed owned emergence allocation");
37 }
38 ssq::Object owned = std::move(object).takeValue();
40 result.set("value", owned);
41 result.set("ownership", std::string("owned"));
42 result.set("ownerEpoch", static_cast<std::int64_t>(ref.ownerEpoch));
43 result.set("handle", static_cast<std::int64_t>(ref.packed()));
44 return result;
45}
46
47eve::script::Borrowed<RuleEngine> resolveOrEmpty(ScriptRuleEngine* value) {
48 return value ? Emergence::resolve(value->reference) : eve::script::Borrowed<RuleEngine>();
49}
50
51} // namespace
52
54 Emergence* module = Emergence::create();
55 return module->engines_.emplace(std::make_unique<RuleEngine>());
56}
57
59 Emergence* module = ModuleManager::getInstance<Emergence>("Emergence");
60 if (!module) return {};
61 return module->engines_.resolve(reference);
62}
63
65 Emergence* module = ModuleManager::getInstance<Emergence>("Emergence");
66 if (!module)
68 eve::DiagnosticCode::StaleHandle, "Emergence module is no longer loaded", "engine", {}, "emergence"));
69 return module->engines_.erase(reference);
70}
71
73 if (!reference.isValid()) return false;
74 Emergence* module = ModuleManager::getInstance<Emergence>("Emergence");
75 return !module || module->engines_.isStale(reference);
76}
77
79
80void Emergence::expose(ssq::Table& t) {
81 const HSQUIRRELVM vm = t.getHandle();
82 auto asBool = [](bool value) { return eve::Value(value); };
83 auto asInt = [](int value) { return eve::Value(static_cast<std::int64_t>(value)); };
84 auto staleBool = [vm, asBool]() {
86 vm,
88 eve::DiagnosticCode::StaleHandle, "owned rule engine handle is stale", "engine", {}, "emergence")),
89 asBool);
90 };
91 auto staleInt = [vm, asInt]() {
93 vm,
95 eve::DiagnosticCode::StaleHandle, "owned rule engine handle is stale", "engine", {}, "emergence")),
96 asInt);
97 };
98
99 auto owned =
100 t.addClass<ScriptRuleEngine>("RuleEngine", std::function<ScriptRuleEngine*()>([]() { return nullptr; }), false);
101 owned.addFunc("ownership", [](ScriptRuleEngine*) { return std::string("owned"); });
102 owned.addFunc("isStale", [](ScriptRuleEngine* value) { return !value || Emergence::isStale(value->reference); });
103 owned.addFunc("release", [vm](ScriptRuleEngine* value) {
104 if (!value)
107 "rule engine must not be null", "engine", {}, "emergence")));
109 });
110 owned.addFunc("replaceCatalogueJson", [vm, staleInt, asInt](ScriptRuleEngine* value, const std::string& json) {
111 auto view = resolveOrEmpty(value);
112 if (!view.isBound()) return staleInt();
113 return eve::script::projectResult(vm, view->replaceCatalogueJson(json), asInt);
114 });
115 owned.addFunc("ruleCount", [](ScriptRuleEngine* value) {
116 auto view = resolveOrEmpty(value);
117 return view.isBound() ? view->ruleCount() : 0;
118 });
119 owned.addFunc("setValue", [vm, staleBool, asBool](ScriptRuleEngine* value, const std::string& key,
120 const std::string& valueJson) {
121 auto view = resolveOrEmpty(value);
122 if (!view.isBound()) return staleBool();
123 auto parsed = eve::Value::fromJson(valueJson);
124 if (!parsed) return eve::script::projectResult(vm, eve::Result<bool>::failure(parsed.status()), asBool);
125 return eve::script::projectResult(vm, view->setValue(key, std::move(parsed).takeValue()), asBool);
126 });
127 owned.addFunc("setTag", [vm, staleBool, asBool](ScriptRuleEngine* value, const std::string& tag, bool present) {
128 auto view = resolveOrEmpty(value);
129 if (!view.isBound()) return staleBool();
130 return eve::script::projectResult(vm, view->setTag(tag, present), asBool);
131 });
132 owned.addFunc("setResource",
133 [vm, staleBool, asBool](ScriptRuleEngine* value, const std::string& key, std::int64_t amount) {
134 auto view = resolveOrEmpty(value);
135 if (!view.isBound()) return staleBool();
136 return eve::script::projectResult(vm, view->setResource(key, eve::Value(amount)), asBool);
137 });
138 owned.addFunc("setState", [vm, staleBool, asBool](ScriptRuleEngine* value, const std::string& key,
139 const std::string& valueJson) {
140 auto view = resolveOrEmpty(value);
141 if (!view.isBound()) return staleBool();
142 auto parsed = eve::Value::fromJson(valueJson);
143 if (!parsed) return eve::script::projectResult(vm, eve::Result<bool>::failure(parsed.status()), asBool);
144 return eve::script::projectResult(vm, view->setState(key, std::move(parsed).takeValue()), asBool);
145 });
146 owned.addFunc("drain", [vm, staleInt, asInt](ScriptRuleEngine* value, std::int64_t tick) {
147 auto view = resolveOrEmpty(value);
148 if (!view.isBound()) return staleInt();
149 return eve::script::projectResult(vm, view->drain(static_cast<std::uint64_t>(std::max<std::int64_t>(0, tick))),
150 asInt);
151 });
152 owned.addFunc("activationCount", [](ScriptRuleEngine* value) {
153 auto view = resolveOrEmpty(value);
154 return view.isBound() ? view->activationCount() : 0;
155 });
156 owned.addFunc("activationRuleId", [](ScriptRuleEngine* value, int index) {
157 auto view = resolveOrEmpty(value);
158 if (!view.isBound()) return std::string{};
159 const auto* activation = view->activationAt(index);
160 return activation ? activation->ruleId : std::string{};
161 });
162 owned.addFunc("clearActivations", [](ScriptRuleEngine* value) {
163 auto view = resolveOrEmpty(value);
164 if (view.isBound()) view->clearActivations();
165 });
166 owned.addFunc("lastDrainEvaluations", [](ScriptRuleEngine* value) {
167 auto view = resolveOrEmpty(value);
168 return view.isBound() ? static_cast<std::int64_t>(view->lastDrainEvaluations()) : std::int64_t{0};
169 });
170 owned.addFunc("snapshotJson", [](ScriptRuleEngine* value) {
171 auto view = resolveOrEmpty(value);
172 return view.isBound() ? view->snapshotJson() : std::string{};
173 });
174 owned.addFunc("restoreJson", [vm](ScriptRuleEngine* value, const std::string& json) {
175 auto view = resolveOrEmpty(value);
176 if (!view.isBound())
179 "owned rule engine handle is stale", "engine", {}, "emergence")));
180 return eve::script::projectResult(vm, view->restoreJson(json));
181 });
182
183 auto c = t.addClass(name, Emergence::create, false);
184 expose(c);
185}
186
187void Emergence::expose(ssq::Class& c) {
188 c.addFunc("getName", &Emergence::getName);
189 c.addFunc("newEngine", [vm = c.getHandle()](Emergence*) -> ssq::Table {
190 return makeOwnedProxy<RuleEngineHandleRef, ScriptRuleEngine>(
191 vm, Emergence::newEngine(), [](RuleEngineHandleRef ref) { return Emergence::release(ref); });
192 });
193}
194
195} // namespace eve::emergence
double value
ActiveSource owned
AuthorityStoreHandleRef reference
Definition Authority.cpp:24
struct SQVM * HSQUIRRELVM
Stable, structured diagnostics shared by engine modules.
HSQUIRRELVM vm
Definition ECS.cpp:20
Script module factory for indexed emergent rule engines.
std::uint32_t key
wgpu::PopErrorScopeStatus status
std::int32_t c
std::string name
const std::string * tag
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
std::string script
Definition PlayHost.cpp:116
std::function< eve::Result< void >()> release
Definition Procgen.cpp:86
float t
glm::mat4 view
The single Squirrel projection for common Result, Status and Value.
SimulationTick tick
uint32_t index
Owning, renderer-independent dynamic values.
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
virtual std::string getName() const =0
Returns the name.
void ignore(std::string_view reason={}) const noexcept
Explicitly discard this result after documenting the reason.
Definition Result.h:537
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Structured status and zero or more diagnostics for an operation.
Definition Status.h:68
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
static Result< Value > fromJson(std::string_view json)
Parse one strict JSON value into an owning Value.
Definition Value.cpp:57
Script-facing module that owns RuleEngine instances.
Definition Emergence.h:23
Emergence()=default
Emergence.
static eve::Result< RuleEngineHandleRef > newEngine()
Allocate a module-owned rule engine.
Definition Emergence.cpp:53
static eve::script::Borrowed< RuleEngine > resolve(RuleEngineHandleRef reference) noexcept
Resolve a live engine as a non-owning observation. @ownership Borrowed from the module registry....
Definition Emergence.cpp:58
static bool isStale(RuleEngineHandleRef reference) noexcept
Report whether a handle is stale.
Definition Emergence.cpp:72
static eve::Result< void > release(RuleEngineHandleRef reference)
Release a module-owned engine.
Definition Emergence.cpp:64
Non-owning C++ observation with no implicit lifetime extension.
eve::script::RuntimeHandleRef< RuleEngineHandleTag > RuleEngineHandleRef
Generation-qualified reference to a module-owned RuleEngine.
Definition RuleEngine.h:27
ssq::Table projectStatusResult(HSQUIRRELVM vm, const Status &status)
Project a checked native status that carries no payload.
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
Build metadata (engine git commit, build time, third-party version).
Definition Build.cpp:16
Handle plus owner-lifetime epoch for a non-ECS registry object.