5#include <simplesquirrel/simplesquirrel.hpp>
15struct ScriptWorkQueue {
21struct ScriptWorkTask {
28struct ScriptWorkEvent {
40template <
class Ref,
class Proxy,
class Release>
43 const Ref ref = std::move(
reference).takeValue();
44 auto object = eve::script::makeOwnedSquirrelInstance<Proxy>(
vm, std::make_unique<Proxy>(ref));
47 object.ignore(
"failed to create owned production proxy");
48 std::invoke(std::forward<Release>(
release), ref).ignore(
"rollback failed owned production allocation");
51 ssq::Object
owned = std::move(
object).takeValue();
53 result.set(
"ownership", std::string(
"owned"));
54 result.set(
"ownerEpoch",
static_cast<std::int64_t
>(ref.ownerEpoch));
55 result.set(
"handle",
static_cast<std::int64_t
>(ref.packed()));
61 if (!
vm)
return ssq::Object();
62 const SQInteger
top = sq_gettop(
vm);
65 pushed.ignore(
"failed to project a work-task Value payload");
67 return ssq::Object(
vm);
69 ssq::Object result(
vm);
70 if (SQ_SUCCEEDED(sq_getstackobj(
vm, -1, &result.getRaw()))) sq_addref(
vm, &result.getRaw());
79 return module->queues_.emplace(std::make_unique<WorkQueue>());
83 Production*
module = ModuleManager::getInstance<Production>("Production");
85 return productionBindingFailure<std::reference_wrapper<WorkQueue>>(
87 auto view =
module->queues_.resolve(reference);
90 "work queue handle is stale",
"queue");
95 Production*
module = ModuleManager::getInstance<Production>("Production");
99 return module->queues_.erase(reference);
104 Production*
module = ModuleManager::getInstance<Production>("Production");
105 return !
module || module->queues_.isStale(reference);
110void Production::expose(ssq::Table& table) {
113 table.addClass<ScriptWorkTask>(
"WorkTask", std::function<ScriptWorkTask*()>([] {
return nullptr; }),
true);
115 if (!proxy)
return {};
118 queue.ignore(
"stale work queue while reading a task proxy");
121 return queue.value().get().find(proxy->taskId);
123 task.addFunc(
"getId", [resolveTask](ScriptWorkTask*
v) {
124 auto value = resolveTask(
v);
125 return value ?
value->get().id : std::string{};
127 task.addFunc(
"getOwner", [resolveTask](ScriptWorkTask*
v) {
128 auto value = resolveTask(
v);
129 return value ?
value->get().owner : std::string{};
131 task.addFunc(
"getKind", [resolveTask](ScriptWorkTask*
v) {
132 auto value = resolveTask(
v);
133 return value ?
value->get().kind : std::string{};
135 task.addFunc(
"getProduct", [resolveTask](ScriptWorkTask*
v) {
136 auto value = resolveTask(
v);
137 return value ?
value->get().product : std::string{};
139 task.addFunc(
"getContext", [
vm, resolveTask](ScriptWorkTask*
v) {
140 auto value = resolveTask(
v);
143 task.addFunc(
"getDuration", [resolveTask](ScriptWorkTask*
v) {
144 auto value = resolveTask(
v);
145 return value ? float(
value->get().duration.seconds()) : 0.0f;
147 task.addFunc(
"getProgress", [resolveTask](ScriptWorkTask*
v) {
148 auto value = resolveTask(
v);
149 return value ? float(
value->get().progress.seconds()) : 0.0f;
151 task.addFunc(
"getPriority", [resolveTask](ScriptWorkTask*
v) {
152 auto value = resolveTask(
v);
155 task.addFunc(
"getState", [resolveTask](ScriptWorkTask*
v) {
156 auto value = resolveTask(
v);
159 task.addFunc(
"getReason", [resolveTask](ScriptWorkTask*
v) {
160 auto value = resolveTask(
v);
161 return value ?
value->get().reason : std::string{};
165 table.addClass<ScriptWorkEvent>(
"WorkEvent", std::function<ScriptWorkEvent*()>([] {
return nullptr; }),
true);
167 if (!proxy)
return {};
170 queue.ignore(
"stale work queue while reading an event proxy");
173 return queue.value().get().eventAt(proxy->index);
175 event.addFunc(
"getSequence", [resolveEvent](ScriptWorkEvent*
v) {
176 auto value = resolveEvent(
v);
177 return value ? int64_t(
value->get().sequence) : int64_t{0};
179 event.addFunc(
"getTick", [resolveEvent](ScriptWorkEvent*
v) {
180 auto value = resolveEvent(
v);
181 return value ? int64_t(
value->get().tick.value()) : int64_t{0};
183 event.addFunc(
"getKind", [resolveEvent](ScriptWorkEvent*
v) {
184 auto value = resolveEvent(
v);
187 event.addFunc(
"getTaskId", [resolveEvent](ScriptWorkEvent*
v) {
188 auto value = resolveEvent(
v);
189 return value ?
value->get().taskId : std::string{};
191 event.addFunc(
"getOwner", [resolveEvent](ScriptWorkEvent*
v) {
192 auto value = resolveEvent(
v);
193 return value ?
value->get().owner : std::string{};
195 event.addFunc(
"getTaskKind", [resolveEvent](ScriptWorkEvent*
v) {
196 auto value = resolveEvent(
v);
197 return value ?
value->get().taskKind : std::string{};
199 event.addFunc(
"getProduct", [resolveEvent](ScriptWorkEvent*
v) {
200 auto value = resolveEvent(
v);
201 return value ?
value->get().product : std::string{};
203 event.addFunc(
"getReason", [resolveEvent](ScriptWorkEvent*
v) {
204 auto value = resolveEvent(
v);
205 return value ?
value->get().reason : std::string{};
209 table.addClass<ScriptWorkQueue>(
"WorkQueue", std::function<ScriptWorkQueue*()>([] {
return nullptr; }),
true);
210 queue.addFunc(
"ownership", [](ScriptWorkQueue*) {
return std::string(
"owned"); });
211 queue.addFunc(
"ownerEpoch", [](ScriptWorkQueue*
value) {
212 return value ?
static_cast<int64_t
>(
value->reference.ownerEpoch) : int64_t{0};
214 queue.addFunc(
"handle", [](ScriptWorkQueue*
value) {
215 return value ?
static_cast<int64_t
>(
value->reference.packed()) : int64_t{0};
218 queue.addFunc(
"release", [
vm](ScriptWorkQueue*
value) {
222 "work queue proxy must not be null",
"queue"));
225 queue.addFunc(
"enqueue", [
vm](ScriptWorkQueue*
value,
const std::string& owner,
const std::string&
kind,
226 const std::string& product,
const std::string& contextJson,
float duration,
232 "work queue proxy must not be null",
"queue")
241 [](std::string
id) { return eve::Value(std::move(id)); });
243 queue.addFunc(
"pause", [
vm](ScriptWorkQueue*
value,
const std::string&
id) {
247 "work queue proxy must not be null",
"queue"));
252 queue.addFunc(
"resume", [
vm](ScriptWorkQueue*
value,
const std::string&
id) {
256 "work queue proxy must not be null",
"queue"));
261 queue.addFunc(
"cancel", [
vm](ScriptWorkQueue*
value,
const std::string&
id,
const std::string& reason) {
265 "work queue proxy must not be null",
"queue"));
270 queue.addFunc(
"fail", [
vm](ScriptWorkQueue*
value,
const std::string&
id,
const std::string& reason) {
274 "work queue proxy must not be null",
"queue"));
279 queue.addFunc(
"advance", [
vm](ScriptWorkQueue*
value, std::int64_t
tick,
float seconds) {
283 "work queue proxy must not be null",
"queue"));
289 vm, queueView.value().get().advance(
290 {eve::SimulationTick(static_cast<std::uint64_t>(tick)), std::move(delta).takeValue()}));
292 queue.addFunc(
"setSlotCount", [
vm](ScriptWorkQueue*
value,
const std::string& owner,
int slots) {
296 "work queue proxy must not be null",
"queue"));
301 queue.addFunc(
"slotCount", [](ScriptWorkQueue*
value,
const std::string& owner) {
305 if (!queueView.ok()) {
306 queueView.ignore(
"stale work queue while reading slot count");
309 return queueView.value().get().slotCount(owner);
311 queue.addFunc(
"runningCount", [](ScriptWorkQueue*
value,
const std::string& owner) {
315 if (!queueView.ok()) {
316 queueView.ignore(
"stale work queue while reading running count");
319 return queueView.value().get().runningCount(owner);
321 queue.addFunc(
"find", [
vm](ScriptWorkQueue*
value,
const std::string&
id) {
322 if (!
value)
return ssq::Object(
vm);
324 if (!queueView.ok()) {
325 queueView.ignore(
"stale work queue while finding a task");
326 return ssq::Object(
vm);
328 if (!queueView.value().get().find(
id))
return ssq::Object(
vm);
329 auto object = eve::script::makeOwnedSquirrelInstance<ScriptWorkTask>(
330 vm, std::make_unique<ScriptWorkTask>(
value->reference,
id));
332 object.ignore(
"failed to create work task proxy");
333 return ssq::Object(
vm);
335 return std::move(
object).takeValue();
337 queue.addFunc(
"taskCount", [](ScriptWorkQueue*
value) {
341 if (!queueView.ok()) {
342 queueView.ignore(
"stale work queue while reading task count");
345 return queueView.value().get().taskCount();
347 queue.addFunc(
"taskAt", [
vm](ScriptWorkQueue*
value,
int index) {
348 if (!
value)
return ssq::Object(
vm);
350 if (!queueView.ok() || !queueView.value().get().taskAt(
index)) {
351 queueView.ignore(
"work task lookup did not produce a task proxy");
352 return ssq::Object(
vm);
354 auto object = eve::script::makeOwnedSquirrelInstance<ScriptWorkTask>(
355 vm, std::make_unique<ScriptWorkTask>(
value->reference, queueView.value().get().taskAt(
index)->get().id));
357 object.ignore(
"failed to create work task proxy");
358 return ssq::Object(
vm);
360 return std::move(
object).takeValue();
362 queue.addFunc(
"ownerTaskCount", [](ScriptWorkQueue*
value,
const std::string& owner) {
366 if (!queueView.ok()) {
367 queueView.ignore(
"stale work queue while reading owner task count");
370 return queueView.value().get().ownerTaskCount(owner);
372 queue.addFunc(
"ownerTaskAt", [
vm](ScriptWorkQueue*
value,
const std::string& owner,
int index) {
373 if (!
value)
return ssq::Object(
vm);
375 if (!queueView.ok()) {
376 queueView.ignore(
"stale work queue while finding an owner task");
377 return ssq::Object(
vm);
379 auto taskRef = queueView.value().get().ownerTaskAt(owner,
index);
380 if (!taskRef)
return ssq::Object(
vm);
381 auto object = eve::script::makeOwnedSquirrelInstance<ScriptWorkTask>(
382 vm, std::make_unique<ScriptWorkTask>(
value->reference, taskRef->get().id));
384 object.ignore(
"failed to create work task proxy");
385 return ssq::Object(
vm);
387 return std::move(
object).takeValue();
389 queue.addFunc(
"eventCount", [](ScriptWorkQueue*
value) {
393 if (!queueView.ok()) {
394 queueView.ignore(
"stale work queue while reading event count");
397 return queueView.value().get().eventCount();
399 queue.addFunc(
"eventAt", [
vm](ScriptWorkQueue*
value,
int index) {
400 if (!
value)
return ssq::Object(
vm);
402 if (!queueView.ok() || !queueView.value().get().eventAt(
index)) {
403 queueView.ignore(
"work event lookup did not produce an event proxy");
404 return ssq::Object(
vm);
406 auto object = eve::script::makeOwnedSquirrelInstance<ScriptWorkEvent>(
407 vm, std::make_unique<ScriptWorkEvent>(
value->reference,
index));
409 object.ignore(
"failed to create work event proxy");
410 return ssq::Object(
vm);
412 return std::move(
object).takeValue();
414 queue.addFunc(
"clearEvents", [
vm](ScriptWorkQueue*
value) {
418 "work queue proxy must not be null",
"queue"));
421 queueView.value().get().clearEvents();
424 queue.addFunc(
"snapshot", [
vm](ScriptWorkQueue*
value) {
429 "work queue proxy must not be null",
"queue"),
438 "work queue handle is stale",
"queue"),
441 [](std::string
text) { return eve::Value(std::move(text)); });
443 queue.addFunc(
"restore", [
vm](ScriptWorkQueue*
value,
const std::string& json) {
447 "work queue proxy must not be null",
"queue"));
448 auto queueView = Production::resolve(
value->reference);
452 queue.addFunc(
"clear", [
vm](ScriptWorkQueue*
value) {
456 "work queue proxy must not be null",
"queue"));
457 auto queueView = Production::resolve(
value->reference);
459 queueView.value().get().clear();
462 auto cls =
table.addClass(
name, Production::create,
false);
466void Production::expose(ssq::Class&
cls) {
467 cls.addFunc(
"getName", &Production::getName);
468 cls.addFunc(
"newWorkQueue", [
vm =
cls.getHandle()](Production*) -> ssq::Table {
469 return makeOwnedProxy<WorkQueueHandleRef, ScriptWorkQueue>(
470 vm, Production::newQueueHandle(), [](WorkQueueHandleRef ref) { return Production::release(ref); },
"queue");
AuthorityStoreHandleRef reference
struct SQVM * HSQUIRRELVM
wgpu::PopErrorScopeStatus status
#define Module_IMPL(ModuleName, newExpr)
std::function< eve::Result< void >()> release
LocalPageCacheEntry slots[ShadowConfig::kLocalSlots]
The single Squirrel projection for common Result, Status and Value.
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.
static Result< Duration > fromSeconds(double seconds)
Convert finite seconds to the nearest nanosecond.
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
Structured status and zero or more diagnostics for an operation.
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
The canonical owning dynamic value used by data-facing protocols.
static Result< Value > fromJson(std::string_view json)
Parse one strict JSON value into an owning Value.
Script module factory for generic production queues.
static eve::Result< WorkQueueHandleRef > newQueueHandle()
Allocates a production queue and returns its ownership reference.
static bool isStale(WorkQueueHandleRef reference) noexcept
Reports whether a queue reference is stale for the current module.
static eve::Result< void > release(WorkQueueHandleRef reference)
Releases a module-owned queue.
static eve::ResultRef< WorkQueue > resolve(WorkQueueHandleRef reference)
Resolves a generation-qualified work-queue identity.
eve::Diagnostic Diagnostic
std::string_view eventKindName(ProductionEventKind kind)
Returns the stable lowercase name of an event kind.
std::string_view taskStateName(TaskState state)
Returns the stable lowercase name of a task state.
eve::script::RuntimeHandleRef< WorkQueueHandleTag > WorkQueueHandleRef
Generation- and module-epoch-qualified production work-queue reference.
std::unordered_map< std::string, SkillDefinition > & table()
Result< void > pushValue(HSQUIRRELVM vm, const Value &value, const SquirrelValueOptions &options)
Push a canonical Value into the active Squirrel VM.
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).
DiagnosticCode
Stable machine-readable diagnostic codes.
std::optional< std::reference_wrapper< T > > OptionalRef
Optional borrowed reference; it does not extend T's lifetime.
Result< std::reference_wrapper< T > > ResultRef
Checked borrowed reference carried by Result; it does not own T.
EVEngine ECS 集成层:底层实现使用 sunxfancy/ECS.hpp https://github.com/sunxfancy/ECS.hpp
Handle plus owner-lifetime epoch for a non-ECS registry object.