@moku-labs/game 0.13.2 → 0.13.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/page.d.mts +1 -1
- package/dist/app/system.d.mts +3 -3
- package/dist/app.d.mts +2 -2
- package/dist/app.mjs +1 -1
- package/dist/assets.d.mts +1 -1
- package/dist/{capture-fpd83Mi5.mjs → capture-D7XvoHdH.mjs} +78 -1
- package/dist/{commands-BrgeMP5y.d.mts → commands-DRhJ_LIH.d.mts} +5 -5
- package/dist/control.d.mts +4 -4
- package/dist/control.mjs +1 -1
- package/dist/{define-ZmWbWxon.d.mts → define-Ckp70_GR.d.mts} +2 -2
- package/dist/{headless-BsNdJs9W.mjs → headless-BA6ffzqD.mjs} +30 -9
- package/dist/{headless-Dgxvp6Ym.d.mts → headless-CYgYzro0.d.mts} +1 -1
- package/dist/{index-CdbE_jGs.d.mts → index-CjuObHhF.d.mts} +4 -4
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +1 -1
- package/dist/inspect.d.mts +7 -7
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/{memory-DJ2sPExv.d.mts → memory-DKo9rRWW.d.mts} +1 -1
- package/dist/{run-wYty_Lwo.mjs → run-BtyrJjmW.mjs} +130 -40
- package/dist/{runtime-6qakboTm.d.mts → runtime-iTxTcukZ.d.mts} +1 -1
- package/dist/{src-CltFFKtc.mjs → src-DlyYl_9X.mjs} +412 -122
- package/dist/testing.d.mts +4 -4
- package/dist/testing.mjs +2 -2
- package/dist/{types-C6y8EfEB.d.mts → types-BSMmnpFm.d.mts} +84 -24
- package/dist/{types-zRGJdFGX.d.mts → types-B_Bp2tWK.d.mts} +2 -2
- package/dist/{types-D57SntUt.d.mts → types-Bonifz5M.d.mts} +2 -2
- package/dist/{types-DGIkfZB7.d.mts → types-DkO3s9YX.d.mts} +4 -4
- package/dist/{types-CmuwAjkV.d.mts → types-Dm5Oh5bH.d.mts} +1 -1
- package/dist/{types-B3T2X6To.d.mts → types-dJMOXXL3.d.mts} +15 -11
- package/dist/visual.d.mts +6 -6
- package/dist/visual.mjs +1 -1
- package/llms.txt +4 -3
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
|
|
2
2
|
import { r as systemSource, t as memory } from "./memory-CWlqhS7l.mjs";
|
|
3
3
|
import { a as finishDrafts, i as enableDraftPatches, n as deepFreeze, o as openDrafts, r as dropDrafts } from "./drafts-BawpSaVp.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { d as graphHash, f as isRestCheckpoint, h as pushEntry, i as servePaused, l as findNode, m as compact, n as captureFrame, o as collectFlows, p as slotNames, r as serveCaptures, s as describeGraph, t as cancelCaptures, u as framePath } from "./capture-D7XvoHdH.mjs";
|
|
5
5
|
import { A as system, C as Exiting, D as component, E as Tree, T as Order, _ as Parent, a as visualOf$1, b as Transform, c as Text, g as NineSlice, h as Display, j as tag, k as resource, m as textFor, n as fitScaleOf, o as visualRectOf, p as readStyle, r as samePose, s as Countdown, t as CONTENT, u as builtInStyles, v as Shape, w as Layer, x as componentsFor, y as Sprite } from "./visual-dMW8iqAE.mjs";
|
|
6
6
|
import { n as isDev } from "./dev-Cc50Dk7H.mjs";
|
|
7
7
|
import { i as isComponentDefinition, n as flatten, r as defineComponent } from "./flatten-BkXuscAV.mjs";
|
|
@@ -1933,19 +1933,6 @@ function connectFlow(ctx) {
|
|
|
1933
1933
|
registerSchedule(flowCtx, fx);
|
|
1934
1934
|
}
|
|
1935
1935
|
//#endregion
|
|
1936
|
-
//#region src/plugins/flow/runner/loop-types.ts
|
|
1937
|
-
/** The stages of entering a node, in the order they run. */
|
|
1938
|
-
const stages = ["load", "scene"];
|
|
1939
|
-
/**
|
|
1940
|
-
* Does nothing. It stands in for an unsubscribe function until the real one arrives.
|
|
1941
|
-
*
|
|
1942
|
-
* @example
|
|
1943
|
-
* ```ts
|
|
1944
|
-
* const watch = { off: noop };
|
|
1945
|
-
* ```
|
|
1946
|
-
*/
|
|
1947
|
-
function noop() {}
|
|
1948
|
-
//#endregion
|
|
1949
1936
|
//#region src/plugins/flow/runner/validate.ts
|
|
1950
1937
|
/** Nodes of one flow above which `validate` warns. A flow holds 7 to 15 nodes. */
|
|
1951
1938
|
const MAX_NODES = 15;
|
|
@@ -2400,6 +2387,16 @@ function collectGraph(ctx, features) {
|
|
|
2400
2387
|
return graph.flows;
|
|
2401
2388
|
}
|
|
2402
2389
|
/**
|
|
2390
|
+
* Renders the whole graph as JSON. It reads the flows as data, so it works before `run()`.
|
|
2391
|
+
*
|
|
2392
|
+
* @param ctx - Domain context of the flow plugin.
|
|
2393
|
+
* @param features - Features API: owners and slot contributions.
|
|
2394
|
+
* @returns The graph.
|
|
2395
|
+
*/
|
|
2396
|
+
function graphOf(ctx, features) {
|
|
2397
|
+
return describeGraph(collectGraph(ctx, features), features);
|
|
2398
|
+
}
|
|
2399
|
+
/**
|
|
2403
2400
|
* Validates the collected graph. Warnings are logged, problems stop `run()` in one error.
|
|
2404
2401
|
*
|
|
2405
2402
|
* @param ctx - Domain context of the flow plugin.
|
|
@@ -2412,6 +2409,169 @@ function checkGraph(ctx, features) {
|
|
|
2412
2409
|
if (report.problems.length > 0) throw new Error(report.problems.join("\n"));
|
|
2413
2410
|
}
|
|
2414
2411
|
//#endregion
|
|
2412
|
+
//#region src/plugins/flow/runner/bookmark.ts
|
|
2413
|
+
/**
|
|
2414
|
+
* Reads the main flow of the config.
|
|
2415
|
+
*
|
|
2416
|
+
* @param ctx - Domain context of the flow plugin.
|
|
2417
|
+
* @param method - Name of the API method that needs it, for the message.
|
|
2418
|
+
* @returns The top-level flow.
|
|
2419
|
+
* @throws {Error} When no main flow was configured.
|
|
2420
|
+
*/
|
|
2421
|
+
function mainFlow(ctx, method) {
|
|
2422
|
+
const main = ctx.config.mainFlow;
|
|
2423
|
+
if (main === void 0) throw new Error(`[game] flow.${method}() needs a main flow.\n Pass it as pluginConfigs.flow.mainFlow.`);
|
|
2424
|
+
return main;
|
|
2425
|
+
}
|
|
2426
|
+
/**
|
|
2427
|
+
* Names a checkpoint of the graph, for the message of a refused bookmark. Only a rest node is
|
|
2428
|
+
* one: a transit node that carries the flag is no place a restore may be sent to.
|
|
2429
|
+
*
|
|
2430
|
+
* @param ctx - Domain context of the flow plugin.
|
|
2431
|
+
* @param modules - Injected sibling APIs.
|
|
2432
|
+
* @returns The path of the first rest checkpoint, or the start of the main flow.
|
|
2433
|
+
*/
|
|
2434
|
+
function someCheckpoint(ctx, modules) {
|
|
2435
|
+
const main = mainFlow(ctx, "restore");
|
|
2436
|
+
for (const flow of collectGraph(ctx, modules.features).values()) for (const [name, entry] of Object.entries(flow.nodes)) if (isRestCheckpoint(entry)) return flow.id === main.id ? name : `${flow.id}/${name}`;
|
|
2437
|
+
return main.start;
|
|
2438
|
+
}
|
|
2439
|
+
/**
|
|
2440
|
+
* Looks up the node at a path. A sub-flow and a slot are no nodes: nothing runs at them.
|
|
2441
|
+
*
|
|
2442
|
+
* @param ctx - Domain context of the flow plugin.
|
|
2443
|
+
* @param modules - Injected sibling APIs.
|
|
2444
|
+
* @param path - Path of a bookmark, or of its rest point.
|
|
2445
|
+
* @returns The node there, a rest node or a transit node, or `undefined` when the path names none.
|
|
2446
|
+
*/
|
|
2447
|
+
function nodeAt(ctx, modules, path) {
|
|
2448
|
+
const entry = findNode(mainFlow(ctx, "restore"), path, modules.features.contributions)?.entry;
|
|
2449
|
+
return entry?.kind === "node" ? entry : void 0;
|
|
2450
|
+
}
|
|
2451
|
+
/**
|
|
2452
|
+
* Finds the node a bookmark names.
|
|
2453
|
+
*
|
|
2454
|
+
* @param ctx - Domain context of the flow plugin.
|
|
2455
|
+
* @param modules - Injected sibling APIs.
|
|
2456
|
+
* @param bookmark - The bookmark to enter.
|
|
2457
|
+
* @returns The node at the bookmark's path, a rest node or a transit node.
|
|
2458
|
+
* @throws {Error} When the path names no node of the graph.
|
|
2459
|
+
*/
|
|
2460
|
+
function bookmarkNode(ctx, modules, bookmark) {
|
|
2461
|
+
const node = nodeAt(ctx, modules, bookmark.path);
|
|
2462
|
+
if (node === void 0) throw new Error(`[game] The bookmark "${bookmark.path}" is not a node of the graph.\n Restore a rest node, for example the checkpoint "${someCheckpoint(ctx, modules)}".`);
|
|
2463
|
+
return node;
|
|
2464
|
+
}
|
|
2465
|
+
/**
|
|
2466
|
+
* Tells whether the graph is the one a bookmark was made for. The answer costs a description and
|
|
2467
|
+
* a hash of the whole graph, so one acceptance works it out once: see `askedOnce`.
|
|
2468
|
+
*
|
|
2469
|
+
* @param ctx - Domain context of the flow plugin.
|
|
2470
|
+
* @param modules - Injected sibling APIs.
|
|
2471
|
+
* @param bookmark - The bookmark to compare with.
|
|
2472
|
+
* @returns True while the hash of `describe()` is the bookmark's.
|
|
2473
|
+
*/
|
|
2474
|
+
function sameGraph(ctx, modules, bookmark) {
|
|
2475
|
+
return graphHash(graphOf(ctx, modules.features)) === bookmark.graph;
|
|
2476
|
+
}
|
|
2477
|
+
/**
|
|
2478
|
+
* Makes a question that is worked out at most once: at the first ask, and never when nobody asks.
|
|
2479
|
+
*
|
|
2480
|
+
* @param ask - Works the answer out.
|
|
2481
|
+
* @returns The question. Every ask after the first gets the first answer.
|
|
2482
|
+
* @example
|
|
2483
|
+
* ```ts
|
|
2484
|
+
* const same = askedOnce(() => true);
|
|
2485
|
+
* same() && same(); // true, and the answer was worked out once
|
|
2486
|
+
* ```
|
|
2487
|
+
*/
|
|
2488
|
+
function askedOnce(ask) {
|
|
2489
|
+
const answer = { value: void 0 };
|
|
2490
|
+
return () => {
|
|
2491
|
+
answer.value ??= ask();
|
|
2492
|
+
return answer.value;
|
|
2493
|
+
};
|
|
2494
|
+
}
|
|
2495
|
+
/**
|
|
2496
|
+
* Checks that a bookmark may be entered: a rest checkpoint always, any other node only while the
|
|
2497
|
+
* graph is the one the bookmark was made for. A transit node is never taken for a checkpoint,
|
|
2498
|
+
* whatever its flag says: it is a place inside a transition, not a place a save may stand on.
|
|
2499
|
+
*
|
|
2500
|
+
* @param ctx - Domain context of the flow plugin.
|
|
2501
|
+
* @param modules - Injected sibling APIs.
|
|
2502
|
+
* @param bookmark - The bookmark to enter.
|
|
2503
|
+
* @param unchanged - Asks whether the graph is the bookmark's own. Not asked for a checkpoint.
|
|
2504
|
+
* @returns The node the bookmark names.
|
|
2505
|
+
* @throws {Error} When the path is no node, or the graph changed since the bookmark.
|
|
2506
|
+
*/
|
|
2507
|
+
function checkBookmark(ctx, modules, bookmark, unchanged) {
|
|
2508
|
+
const node = bookmarkNode(ctx, modules, bookmark);
|
|
2509
|
+
if (isRestCheckpoint(node)) return node;
|
|
2510
|
+
if (unchanged()) return node;
|
|
2511
|
+
throw new Error(`[game] The bookmark "${bookmark.path}" was made for another graph.\n Restore the checkpoint "${someCheckpoint(ctx, modules)}" instead.`);
|
|
2512
|
+
}
|
|
2513
|
+
/**
|
|
2514
|
+
* Builds the bookmark of the rest point before a transit node, for a bookmark that carries `rest`
|
|
2515
|
+
* and was made for another graph. That is one whose path names a transit node while the hash
|
|
2516
|
+
* differs, and one whose path names no node any more: a renamed or removed node is a changed
|
|
2517
|
+
* graph too. Only the position changes: the state stays the bookmark's.
|
|
2518
|
+
*
|
|
2519
|
+
* @param ctx - Domain context of the flow plugin.
|
|
2520
|
+
* @param modules - Injected sibling APIs.
|
|
2521
|
+
* @param bookmark - The bookmark to enter.
|
|
2522
|
+
* @param unchanged - Asks whether the graph is the bookmark's own. Asked for a transit node only.
|
|
2523
|
+
* @returns The bookmark to enter instead, or `undefined` when the bookmark stands for itself.
|
|
2524
|
+
*/
|
|
2525
|
+
function restFallback(ctx, modules, bookmark, unchanged) {
|
|
2526
|
+
const rest = bookmark.rest;
|
|
2527
|
+
if (rest === void 0) return void 0;
|
|
2528
|
+
const node = nodeAt(ctx, modules, bookmark.path);
|
|
2529
|
+
if (node !== void 0 && (node.rest || unchanged())) return void 0;
|
|
2530
|
+
return {
|
|
2531
|
+
...bookmark,
|
|
2532
|
+
path: rest.path,
|
|
2533
|
+
input: rest.input
|
|
2534
|
+
};
|
|
2535
|
+
}
|
|
2536
|
+
/**
|
|
2537
|
+
* Decides what the loop enters for a bookmark: the bookmark itself, or the rest point before it
|
|
2538
|
+
* when the graph changed under a bookmark that has one. Either one passes the same check, so the
|
|
2539
|
+
* fallback is entered only when it is a checkpoint, and the log says that it was taken.
|
|
2540
|
+
*
|
|
2541
|
+
* @param ctx - Domain context of the flow plugin.
|
|
2542
|
+
* @param modules - Injected sibling APIs.
|
|
2543
|
+
* @param bookmark - The bookmark to enter.
|
|
2544
|
+
* @returns The bookmark the loop enters, and whether its node is a rest node.
|
|
2545
|
+
* @throws {Error} When neither the bookmark nor its rest point may be entered.
|
|
2546
|
+
*/
|
|
2547
|
+
function acceptBookmark(ctx, modules, bookmark) {
|
|
2548
|
+
const unchanged = askedOnce(() => sameGraph(ctx, modules, bookmark));
|
|
2549
|
+
const fallback = restFallback(ctx, modules, bookmark, unchanged);
|
|
2550
|
+
const entered = fallback ?? bookmark;
|
|
2551
|
+
const node = checkBookmark(ctx, modules, entered, unchanged);
|
|
2552
|
+
if (fallback !== void 0) ctx.log.info("flow:restore-fell-back", {
|
|
2553
|
+
from: bookmark.path,
|
|
2554
|
+
to: fallback.path
|
|
2555
|
+
});
|
|
2556
|
+
return {
|
|
2557
|
+
bookmark: entered,
|
|
2558
|
+
rest: node.rest
|
|
2559
|
+
};
|
|
2560
|
+
}
|
|
2561
|
+
//#endregion
|
|
2562
|
+
//#region src/plugins/flow/runner/loop-types.ts
|
|
2563
|
+
/** The stages of entering a node, in the order they run. */
|
|
2564
|
+
const stages = ["load", "scene"];
|
|
2565
|
+
/**
|
|
2566
|
+
* Does nothing. It stands in for an unsubscribe function until the real one arrives.
|
|
2567
|
+
*
|
|
2568
|
+
* @example
|
|
2569
|
+
* ```ts
|
|
2570
|
+
* const watch = { off: noop };
|
|
2571
|
+
* ```
|
|
2572
|
+
*/
|
|
2573
|
+
function noop() {}
|
|
2574
|
+
//#endregion
|
|
2415
2575
|
//#region src/plugins/flow/runner/position.ts
|
|
2416
2576
|
/**
|
|
2417
2577
|
* Resolves what the deepest frame points at.
|
|
@@ -3075,8 +3235,27 @@ function guideAllow(payload) {
|
|
|
3075
3235
|
};
|
|
3076
3236
|
}
|
|
3077
3237
|
/**
|
|
3238
|
+
* Refuses an effect a body starts after its node was aborted. The rejection counts as handled
|
|
3239
|
+
* from the start: a body that does not await the effect leaves no unhandled rejection behind,
|
|
3240
|
+
* and a body that awaits it still gets the reason.
|
|
3241
|
+
*
|
|
3242
|
+
* @param signal - The aborted signal of the node.
|
|
3243
|
+
* @returns A promise rejected with the abort reason.
|
|
3244
|
+
* @example
|
|
3245
|
+
* ```ts
|
|
3246
|
+
* refuseEffect(AbortSignal.abort("restore")); // a promise rejected with "restore"
|
|
3247
|
+
* ```
|
|
3248
|
+
*/
|
|
3249
|
+
function refuseEffect(signal) {
|
|
3250
|
+
const refused = Promise.reject(abortReason(signal));
|
|
3251
|
+
refused.catch(noop);
|
|
3252
|
+
return refused;
|
|
3253
|
+
}
|
|
3254
|
+
/**
|
|
3078
3255
|
* Builds the `fx` of a node context: awaited effects by call, cosmetic hints by `emit`. A `guide`
|
|
3079
|
-
* narrows the gate while it runs; the runner lifts the narrow when the node is left.
|
|
3256
|
+
* narrows the gate while it runs; the runner lifts the narrow when the node is left. A body that
|
|
3257
|
+
* was aborted keeps running, since the loop only stops waiting for it, so its `fx` starts nothing
|
|
3258
|
+
* any more: the gate and the narrow belong to the node the loop entered after it.
|
|
3080
3259
|
*
|
|
3081
3260
|
* @param modules - Injected sibling APIs.
|
|
3082
3261
|
* @param step - The node run in progress.
|
|
@@ -3084,12 +3263,13 @@ function guideAllow(payload) {
|
|
|
3084
3263
|
*/
|
|
3085
3264
|
function nodeFx(modules, step) {
|
|
3086
3265
|
/**
|
|
3087
|
-
* Awaits one effect.
|
|
3266
|
+
* Awaits one effect. After the abort of the node it rejects with the abort reason instead.
|
|
3088
3267
|
*
|
|
3089
3268
|
* @param descriptor - The descriptor the node awaits.
|
|
3090
3269
|
* @returns The answer, the handler's value, or `undefined`.
|
|
3091
3270
|
*/
|
|
3092
3271
|
const run = (descriptor) => {
|
|
3272
|
+
if (step.signal.aborted) return refuseEffect(step.signal);
|
|
3093
3273
|
if (descriptor.kind === "guide") {
|
|
3094
3274
|
const allow = guideAllow(descriptor.payload);
|
|
3095
3275
|
if (allow !== void 0) modules.gate.narrow(allow);
|
|
@@ -3599,19 +3779,23 @@ function enterSlot(ctx, modules, location, slot, safe) {
|
|
|
3599
3779
|
return "continue";
|
|
3600
3780
|
}
|
|
3601
3781
|
/**
|
|
3602
|
-
* Enters the node of a bookmark: the state is replaced, the rest
|
|
3603
|
-
* becomes the bookmark's path.
|
|
3782
|
+
* Enters the node of a bookmark, a rest node or a transit node: the state is replaced, the rest
|
|
3783
|
+
* point is marked and the position becomes the bookmark's path. The mark is made for a transit
|
|
3784
|
+
* node too. A restore leaves the whole document waiting for the provider, and a rollback of the
|
|
3785
|
+
* node would drop it unsent; and the frames of the transit node are what a failure of it must
|
|
3786
|
+
* retry, since the restored state belongs to them. `flow:rest` and the rest seam fire once for
|
|
3787
|
+
* every node entered here; only a rest node is announced as a checkpoint.
|
|
3604
3788
|
*
|
|
3605
3789
|
* @param ctx - Domain context of the flow plugin.
|
|
3606
3790
|
* @param modules - Injected sibling APIs; the features API resolves a path through a slot.
|
|
3607
3791
|
* @param bookmark - The bookmark to enter.
|
|
3608
3792
|
* @throws {Error} When the graph has no node at the bookmark's path.
|
|
3609
3793
|
*/
|
|
3610
|
-
function enterBookmark
|
|
3794
|
+
function enterBookmark(ctx, modules, bookmark) {
|
|
3611
3795
|
const state = ctx.state.runner;
|
|
3612
3796
|
const location = findNode(requireMainFlow(ctx), bookmark.path, modules.features.contributions);
|
|
3613
3797
|
loopSeam(state).restoring = void 0;
|
|
3614
|
-
if (location === void 0) throw new Error(`[game] The bookmark names no node "${bookmark.path}".\n Bookmark a
|
|
3798
|
+
if (location === void 0) throw new Error(`[game] The bookmark names no node "${bookmark.path}".\n Bookmark a node of the running graph.`);
|
|
3615
3799
|
ctx.deps.model.store.restore({
|
|
3616
3800
|
player: bookmark.player,
|
|
3617
3801
|
session: bookmark.session,
|
|
@@ -3622,10 +3806,9 @@ function enterBookmark$1(ctx, modules, bookmark) {
|
|
|
3622
3806
|
state.slotAfter = void 0;
|
|
3623
3807
|
state.restFrame = [...state.stack];
|
|
3624
3808
|
state.failures = 0;
|
|
3625
|
-
const entry = location.entry;
|
|
3626
3809
|
ctx.emit("flow:rest", {
|
|
3627
3810
|
path: bookmark.path,
|
|
3628
|
-
checkpoint:
|
|
3811
|
+
checkpoint: isRestCheckpoint(location.entry)
|
|
3629
3812
|
});
|
|
3630
3813
|
notifyRest(state, bookmark.path);
|
|
3631
3814
|
}
|
|
@@ -3643,7 +3826,7 @@ async function advance(ctx, modules, safe) {
|
|
|
3643
3826
|
if (stopped(state)) return "stop";
|
|
3644
3827
|
const restoring = state.seam?.restoring;
|
|
3645
3828
|
if (restoring !== void 0) {
|
|
3646
|
-
enterBookmark
|
|
3829
|
+
enterBookmark(ctx, modules, restoring);
|
|
3647
3830
|
return "continue";
|
|
3648
3831
|
}
|
|
3649
3832
|
const location = locateFrames(ctx, state.stack);
|
|
@@ -3685,12 +3868,15 @@ async function runLoop(ctx, modules) {
|
|
|
3685
3868
|
}
|
|
3686
3869
|
/**
|
|
3687
3870
|
* Restores a bookmark through the running loop: the active node is aborted with reason
|
|
3688
|
-
* `"restore"`, its transaction is discarded, the state is replaced and the node is entered.
|
|
3871
|
+
* `"restore"`, its transaction is discarded, the state is replaced and the node is entered. An
|
|
3872
|
+
* edge that was already committed still arrives first, and the rest point it reaches is not the
|
|
3873
|
+
* bookmark's: the promise waits for the turn in which the loop takes the bookmark.
|
|
3689
3874
|
*
|
|
3690
3875
|
* @param ctx - Domain context of the flow plugin.
|
|
3691
3876
|
* @param _modules - Injected sibling APIs.
|
|
3692
3877
|
* @param bookmark - The bookmark to enter.
|
|
3693
|
-
* @returns A promise that resolves once the loop
|
|
3878
|
+
* @returns A promise that resolves once the loop entered the bookmark's node, before that node
|
|
3879
|
+
* ran: the rest seam fired.
|
|
3694
3880
|
* @throws {Error} When the loop is not running.
|
|
3695
3881
|
*/
|
|
3696
3882
|
function restorePosition(ctx, _modules, bookmark) {
|
|
@@ -3702,6 +3888,7 @@ function restorePosition(ctx, _modules, bookmark) {
|
|
|
3702
3888
|
* Resolves once, when the loop rests at the restored node.
|
|
3703
3889
|
*/
|
|
3704
3890
|
const listener = () => {
|
|
3891
|
+
if (seam.restoring !== void 0) return;
|
|
3705
3892
|
const index = seam.rest.indexOf(listener);
|
|
3706
3893
|
if (index !== -1) seam.rest.splice(index, 1);
|
|
3707
3894
|
resolve();
|
|
@@ -3871,24 +4058,37 @@ function watchEnd(running) {
|
|
|
3871
4058
|
return end;
|
|
3872
4059
|
}
|
|
3873
4060
|
/**
|
|
3874
|
-
*
|
|
3875
|
-
* that ended
|
|
4061
|
+
* Watches for the next gate the loop opens. The listener leaves the seam when a gate wakes it. A
|
|
4062
|
+
* wait that something else ended calls `off()`: the gate that would take the listener off may
|
|
4063
|
+
* never come.
|
|
3876
4064
|
*
|
|
3877
4065
|
* @param seam - The seam of the running loop.
|
|
3878
|
-
* @returns
|
|
4066
|
+
* @returns The promise of the next open gate, and the way to stop watching.
|
|
3879
4067
|
*/
|
|
3880
4068
|
function nextGateOpen(seam) {
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
4069
|
+
const watch = { wake: void 0 };
|
|
4070
|
+
/**
|
|
4071
|
+
* Takes the listener off the seam. It may be gone already.
|
|
4072
|
+
*/
|
|
4073
|
+
const off = () => {
|
|
4074
|
+
const index = seam.gateOpen.indexOf(listener);
|
|
4075
|
+
if (index !== -1) seam.gateOpen.splice(index, 1);
|
|
4076
|
+
};
|
|
4077
|
+
/**
|
|
4078
|
+
* Wakes the waiting side once the loop opened a gate, and leaves.
|
|
4079
|
+
*/
|
|
4080
|
+
function listener() {
|
|
4081
|
+
off();
|
|
4082
|
+
watch.wake?.();
|
|
4083
|
+
}
|
|
4084
|
+
const promise = new Promise((resolve) => {
|
|
4085
|
+
watch.wake = resolve;
|
|
3891
4086
|
});
|
|
4087
|
+
seam.gateOpen.push(listener);
|
|
4088
|
+
return {
|
|
4089
|
+
promise,
|
|
4090
|
+
off
|
|
4091
|
+
};
|
|
3892
4092
|
}
|
|
3893
4093
|
/**
|
|
3894
4094
|
* Waits until the loop opens its gate. Between the edge it commits and the gate of the rest node
|
|
@@ -3902,7 +4102,40 @@ function nextGateOpen(seam) {
|
|
|
3902
4102
|
async function reachGate(ctx, seam, ended) {
|
|
3903
4103
|
if (ctx.state.gate.open !== void 0) return;
|
|
3904
4104
|
if (ended.done) return;
|
|
3905
|
-
|
|
4105
|
+
const opened = nextGateOpen(seam);
|
|
4106
|
+
try {
|
|
4107
|
+
await Promise.race([opened.promise, ended.settled]);
|
|
4108
|
+
} finally {
|
|
4109
|
+
opened.off();
|
|
4110
|
+
}
|
|
4111
|
+
}
|
|
4112
|
+
/**
|
|
4113
|
+
* Waits until a transit node the loop was sent into shows what it waits for: the gate it opens,
|
|
4114
|
+
* or, when it opens none, the next rest point or the end of the loop. `restore` waits here after
|
|
4115
|
+
* it entered a transit bookmark, so its caller reads a state with the open gate in it. There is no
|
|
4116
|
+
* timeout: a node that opens no gate, never rests and never ends keeps the wait pending, as its
|
|
4117
|
+
* body would. Call it only after the loop entered the node: a gate opened before that belongs to
|
|
4118
|
+
* the node the restore aborted.
|
|
4119
|
+
*
|
|
4120
|
+
* @param ctx - Domain context of the flow plugin.
|
|
4121
|
+
* @returns A promise that resolves at the open gate, at a rest point or at the end of the loop.
|
|
4122
|
+
*/
|
|
4123
|
+
async function reachGateOrRest(ctx) {
|
|
4124
|
+
const running = ctx.state.runner.running;
|
|
4125
|
+
if (running === void 0 || ctx.state.gate.open !== void 0) return;
|
|
4126
|
+
const seam = loopSeam(ctx.state.runner);
|
|
4127
|
+
const opened = nextGateOpen(seam);
|
|
4128
|
+
const rested = watchRest(seam);
|
|
4129
|
+
try {
|
|
4130
|
+
await Promise.race([
|
|
4131
|
+
opened.promise,
|
|
4132
|
+
rested.next(),
|
|
4133
|
+
watchEnd(running).settled
|
|
4134
|
+
]);
|
|
4135
|
+
} finally {
|
|
4136
|
+
opened.off();
|
|
4137
|
+
rested.off();
|
|
4138
|
+
}
|
|
3906
4139
|
}
|
|
3907
4140
|
/**
|
|
3908
4141
|
* The error of a step the loop never reached, naming where it stands instead.
|
|
@@ -4020,14 +4253,17 @@ async function playRoute(ctx, modules, route, running) {
|
|
|
4020
4253
|
/**
|
|
4021
4254
|
* Walks a route through the running loop: restores `from` when given, switches to fast mode,
|
|
4022
4255
|
* waits until the loop rests at each step's `at` and answers through the gate, and substitutes
|
|
4023
|
-
* the result of every sub-flow node the route skips.
|
|
4024
|
-
*
|
|
4025
|
-
* it
|
|
4256
|
+
* the result of every sub-flow node the route skips. A rest node `from` names is entered before
|
|
4257
|
+
* the switch: the stages of that node see the mode of the caller. A transit node is entered
|
|
4258
|
+
* after the switch, so it never starts live and never shows its popup. The mode of the caller
|
|
4259
|
+
* is put back afterwards, also when the bookmark is refused or a step rejects, and a
|
|
4260
|
+
* substitution the route never reached is disarmed: it must not skip a sub-flow in the live play
|
|
4261
|
+
* that follows.
|
|
4026
4262
|
*
|
|
4027
4263
|
* @param ctx - Domain context of the flow plugin.
|
|
4028
4264
|
* @param modules - Injected sibling APIs: features, fx, gate, inbox.
|
|
4029
4265
|
* @param route - The player's answers and substituted results, in order.
|
|
4030
|
-
* @param start - Bookmark to enter first
|
|
4266
|
+
* @param start - Bookmark to enter first, the restore that enters it and the kind of its node.
|
|
4031
4267
|
* @returns The state the walk ended in.
|
|
4032
4268
|
* @throws {Error} Before `run()` was called, when the bookmark is refused, and when a step's `at`
|
|
4033
4269
|
* is never reached.
|
|
@@ -4035,10 +4271,13 @@ async function playRoute(ctx, modules, route, running) {
|
|
|
4035
4271
|
async function walkRoute(ctx, modules, route, start) {
|
|
4036
4272
|
const running = ctx.state.runner.running;
|
|
4037
4273
|
if (running === void 0) throw new Error("[game] flow.walk() needs a running graph.\n Call flow.run() from the createApp onStart callback first.");
|
|
4038
|
-
|
|
4274
|
+
const entersBeforeSwitch = start !== void 0 && !start.transit;
|
|
4275
|
+
const entersAfterSwitch = start !== void 0 && !entersBeforeSwitch;
|
|
4276
|
+
if (entersBeforeSwitch) await start.restore(start.from);
|
|
4039
4277
|
const previous = ctx.state.fx.mode;
|
|
4040
4278
|
modules.fx.setMode("fast");
|
|
4041
4279
|
try {
|
|
4280
|
+
if (entersAfterSwitch) await start.restore(start.from);
|
|
4042
4281
|
await playRoute(ctx, modules, route, running);
|
|
4043
4282
|
} finally {
|
|
4044
4283
|
loopSeam(ctx.state.runner).substitutions.clear();
|
|
@@ -4050,69 +4289,71 @@ async function walkRoute(ctx, modules, route, start) {
|
|
|
4050
4289
|
//#region src/plugins/flow/runner/api.ts
|
|
4051
4290
|
const noPayload = null;
|
|
4052
4291
|
/**
|
|
4053
|
-
*
|
|
4292
|
+
* Tells whether a frame points at a rest node.
|
|
4054
4293
|
*
|
|
4055
4294
|
* @param ctx - Domain context of the flow plugin.
|
|
4056
|
-
* @param
|
|
4057
|
-
* @returns
|
|
4058
|
-
* @throws {Error} When no main flow was configured.
|
|
4295
|
+
* @param frame - One level of a position.
|
|
4296
|
+
* @returns True when the entry of that frame is a node with `rest`.
|
|
4059
4297
|
*/
|
|
4060
|
-
function
|
|
4061
|
-
const
|
|
4062
|
-
|
|
4063
|
-
return main;
|
|
4298
|
+
function restsAt(ctx, frame) {
|
|
4299
|
+
const entry = ctx.state.runner.flows.get(frame.flow)?.nodes[frame.node];
|
|
4300
|
+
return entry !== void 0 && entry.kind === "node" && entry.rest;
|
|
4064
4301
|
}
|
|
4065
4302
|
/**
|
|
4066
|
-
*
|
|
4303
|
+
* Tells whether the graph stands on a rest node. `setMode` is legal there and before `run()`.
|
|
4067
4304
|
*
|
|
4068
4305
|
* @param ctx - Domain context of the flow plugin.
|
|
4069
|
-
* @
|
|
4070
|
-
* @returns The graph.
|
|
4306
|
+
* @returns True while the position is empty or points at a rest node.
|
|
4071
4307
|
*/
|
|
4072
|
-
function
|
|
4073
|
-
|
|
4308
|
+
function resting(ctx) {
|
|
4309
|
+
const frame = ctx.state.runner.stack.at(-1);
|
|
4310
|
+
return frame === void 0 || restsAt(ctx, frame);
|
|
4074
4311
|
}
|
|
4075
4312
|
/**
|
|
4076
|
-
*
|
|
4313
|
+
* Tells whether a transit node waits at the gate: an effect that takes answers is open inside
|
|
4314
|
+
* it. A rest node with its own gate open rests, so it does not count.
|
|
4077
4315
|
*
|
|
4078
4316
|
* @param ctx - Domain context of the flow plugin.
|
|
4079
|
-
* @
|
|
4080
|
-
* @returns The path of the first checkpoint, or the start of the main flow.
|
|
4317
|
+
* @returns True while the gate is open and the position is no rest node.
|
|
4081
4318
|
*/
|
|
4082
|
-
function
|
|
4083
|
-
|
|
4084
|
-
for (const flow of collectGraph(ctx, modules.features).values()) for (const [name, entry] of Object.entries(flow.nodes)) if (entry.kind === "node" && entry.checkpoint) return flow.id === main.id ? name : `${flow.id}/${name}`;
|
|
4085
|
-
return main.start;
|
|
4319
|
+
function waitsInTransit(ctx) {
|
|
4320
|
+
return ctx.state.gate.open !== void 0 && !resting(ctx);
|
|
4086
4321
|
}
|
|
4087
4322
|
/**
|
|
4088
|
-
*
|
|
4089
|
-
*
|
|
4323
|
+
* Reads the rest point before the transit node the graph stands in. The rest frame names a
|
|
4324
|
+
* transit node when the graph started at one or a restore entered one: no rest point came
|
|
4325
|
+
* before it then.
|
|
4090
4326
|
*
|
|
4091
4327
|
* @param ctx - Domain context of the flow plugin.
|
|
4092
|
-
* @
|
|
4093
|
-
* @param bookmark - The bookmark to enter.
|
|
4094
|
-
* @throws {Error} When the path is no rest node, or the graph changed since the bookmark.
|
|
4328
|
+
* @returns The last rest node and its input, or `undefined` when the rest frame names none.
|
|
4095
4329
|
*/
|
|
4096
|
-
function
|
|
4097
|
-
const
|
|
4098
|
-
|
|
4099
|
-
if (
|
|
4100
|
-
|
|
4101
|
-
|
|
4330
|
+
function restBefore(ctx) {
|
|
4331
|
+
const frames = ctx.state.runner.restFrame ?? [];
|
|
4332
|
+
const frame = frames.at(-1);
|
|
4333
|
+
if (frame === void 0 || !restsAt(ctx, frame)) return void 0;
|
|
4334
|
+
return {
|
|
4335
|
+
path: framePath(frames),
|
|
4336
|
+
input: frame.input
|
|
4337
|
+
};
|
|
4102
4338
|
}
|
|
4103
4339
|
/**
|
|
4104
|
-
* Makes a bookmark of the
|
|
4340
|
+
* Makes a bookmark of where the graph stands. While a transit node waits at the gate for the
|
|
4341
|
+
* answer of an effect it is that node, with the rest point before it; in every other moment it is
|
|
4342
|
+
* the last rest point. The state is the committed one in both cases: for a waiting transit node
|
|
4343
|
+
* that is the state it was entered with, since its own writes are still in the open transaction.
|
|
4105
4344
|
*
|
|
4106
4345
|
* @param ctx - Domain context of the flow plugin.
|
|
4107
4346
|
* @param modules - Injected sibling APIs.
|
|
4108
|
-
* @returns A
|
|
4347
|
+
* @returns A node plus a state that really existed there.
|
|
4109
4348
|
* @throws {Error} When the graph has no position yet.
|
|
4110
4349
|
*/
|
|
4111
4350
|
function makeBookmark(ctx, modules) {
|
|
4112
4351
|
const state = ctx.state.runner;
|
|
4113
|
-
const
|
|
4352
|
+
const waiting = waitsInTransit(ctx);
|
|
4353
|
+
const frames = waiting ? state.stack : state.restFrame ?? state.stack;
|
|
4114
4354
|
if (frames.length === 0) throw new Error("[game] flow.bookmark() needs a position.\n Call it while the graph rests at a node.");
|
|
4115
4355
|
const snapshot = ctx.deps.model.store.snapshot();
|
|
4356
|
+
const rest = waiting ? restBefore(ctx) : void 0;
|
|
4116
4357
|
return {
|
|
4117
4358
|
path: framePath(frames),
|
|
4118
4359
|
input: frames.at(-1)?.input ?? noPayload,
|
|
@@ -4122,35 +4363,68 @@ function makeBookmark(ctx, modules) {
|
|
|
4122
4363
|
seed: snapshot.rng.seed,
|
|
4123
4364
|
streams: { ...snapshot.rng.streams }
|
|
4124
4365
|
},
|
|
4125
|
-
graph: graphHash(graphOf(ctx, modules))
|
|
4366
|
+
graph: graphHash(graphOf(ctx, modules.features)),
|
|
4367
|
+
...rest === void 0 ? {} : { rest }
|
|
4126
4368
|
};
|
|
4127
4369
|
}
|
|
4128
4370
|
/**
|
|
4129
|
-
*
|
|
4130
|
-
*
|
|
4131
|
-
*
|
|
4371
|
+
* Sends the running loop to a bookmark that passed the check, the short way a walk needs: the
|
|
4372
|
+
* promise resolves as soon as the loop stands at the node, before the node ran. It stays an
|
|
4373
|
+
* `async` function of its own: the microtask turn it adds lets the loop start the stages of a
|
|
4374
|
+
* rest node before the walk goes on and switches to fast mode.
|
|
4132
4375
|
*
|
|
4133
4376
|
* @param ctx - Domain context of the flow plugin.
|
|
4134
4377
|
* @param modules - Injected sibling APIs.
|
|
4135
|
-
* @param bookmark - The bookmark
|
|
4136
|
-
* @returns A promise that resolves once the loop
|
|
4137
|
-
* @throws {Error} When the bookmark names no rest node of this graph.
|
|
4378
|
+
* @param bookmark - The accepted bookmark.
|
|
4379
|
+
* @returns A promise that resolves once the loop entered the node.
|
|
4138
4380
|
*/
|
|
4139
|
-
async function
|
|
4140
|
-
checkBookmark(ctx, modules, bookmark);
|
|
4381
|
+
async function enterAccepted(ctx, modules, bookmark) {
|
|
4141
4382
|
await restorePosition(ctx, modules, bookmark);
|
|
4142
4383
|
}
|
|
4143
4384
|
/**
|
|
4144
|
-
*
|
|
4385
|
+
* Walks a route from a bookmark. The bookmark passes the check `restore` runs, so both ways into
|
|
4386
|
+
* a position refuse the same bookmarks and take the same fallback. The walk is told which kind of
|
|
4387
|
+
* node it enters: a rest node is entered before the switch to fast mode, a transit node after it.
|
|
4145
4388
|
*
|
|
4146
4389
|
* @param ctx - Domain context of the flow plugin.
|
|
4147
|
-
* @
|
|
4390
|
+
* @param modules - Injected sibling APIs.
|
|
4391
|
+
* @param route - The player's answers and substituted results, in order.
|
|
4392
|
+
* @param from - The bookmark to enter first.
|
|
4393
|
+
* @returns The state the walk ended in.
|
|
4394
|
+
* @throws {Error} When the bookmark may not be entered, and when a step's `at` is never reached.
|
|
4148
4395
|
*/
|
|
4149
|
-
function
|
|
4150
|
-
const
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4396
|
+
async function walkFrom(ctx, modules, route, from) {
|
|
4397
|
+
const accepted = acceptBookmark(ctx, modules, from);
|
|
4398
|
+
return walkRoute(ctx, modules, route, {
|
|
4399
|
+
/**
|
|
4400
|
+
* Enters the accepted bookmark. The walk never waits for a gate here: it answers the gates
|
|
4401
|
+
* of its own route.
|
|
4402
|
+
*
|
|
4403
|
+
* @param bookmark - The bookmark to enter.
|
|
4404
|
+
* @returns A promise that resolves once the loop entered its node.
|
|
4405
|
+
*/
|
|
4406
|
+
restore: (bookmark) => enterAccepted(ctx, modules, bookmark),
|
|
4407
|
+
from: accepted.bookmark,
|
|
4408
|
+
transit: !accepted.rest
|
|
4409
|
+
});
|
|
4410
|
+
}
|
|
4411
|
+
/**
|
|
4412
|
+
* Restores a bookmark, the way the plugin's `restore` does. A rest node is entered as `walk`
|
|
4413
|
+
* enters it. A transit node shows nothing until it ran up to its gate, so for one the promise
|
|
4414
|
+
* waits on: for the gate the node opens, or the rest point or the end of the loop it reaches
|
|
4415
|
+
* without one. The wait starts only after the loop entered the node, so a gate the aborted old
|
|
4416
|
+
* node still opened is not taken for the new one.
|
|
4417
|
+
*
|
|
4418
|
+
* @param ctx - Domain context of the flow plugin.
|
|
4419
|
+
* @param modules - Injected sibling APIs.
|
|
4420
|
+
* @param bookmark - The bookmark to enter.
|
|
4421
|
+
* @returns A promise that resolves once a rest node is entered, or a transit node waits.
|
|
4422
|
+
* @throws {Error} When the bookmark may not be entered, and before `run()`.
|
|
4423
|
+
*/
|
|
4424
|
+
async function restoreBookmark(ctx, modules, bookmark) {
|
|
4425
|
+
const accepted = acceptBookmark(ctx, modules, bookmark);
|
|
4426
|
+
await restorePosition(ctx, modules, accepted.bookmark);
|
|
4427
|
+
if (!accepted.rest) await reachGateOrRest(ctx);
|
|
4154
4428
|
}
|
|
4155
4429
|
/**
|
|
4156
4430
|
* Creates the runner API: `run` owns the one loop, `walk` and `restore` enter a position through
|
|
@@ -4179,21 +4453,12 @@ function createRunnerApi(ctx, modules) {
|
|
|
4179
4453
|
},
|
|
4180
4454
|
walk: (route, options) => {
|
|
4181
4455
|
const from = options?.from;
|
|
4182
|
-
if (from === void 0) return walkRoute(ctx, modules, route);
|
|
4183
|
-
return
|
|
4184
|
-
/**
|
|
4185
|
-
* Enters the bookmark the walk starts from, checked the way `restore` checks it.
|
|
4186
|
-
*
|
|
4187
|
-
* @param bookmark - The bookmark to enter.
|
|
4188
|
-
* @returns A promise that resolves once the loop rests at its node.
|
|
4189
|
-
*/
|
|
4190
|
-
restore: (bookmark) => enterBookmark(ctx, modules, bookmark),
|
|
4191
|
-
from
|
|
4192
|
-
});
|
|
4456
|
+
if (from === void 0 || state.running === void 0) return walkRoute(ctx, modules, route);
|
|
4457
|
+
return walkFrom(ctx, modules, route, from);
|
|
4193
4458
|
},
|
|
4194
4459
|
bookmark: () => makeBookmark(ctx, modules),
|
|
4195
|
-
restore: (bookmark) =>
|
|
4196
|
-
describe: () => graphOf(ctx, modules),
|
|
4460
|
+
restore: (bookmark) => restoreBookmark(ctx, modules, bookmark),
|
|
4461
|
+
describe: () => graphOf(ctx, modules.features),
|
|
4197
4462
|
state: () => readState(ctx),
|
|
4198
4463
|
history: () => [...state.journal],
|
|
4199
4464
|
setMode: (mode) => {
|
|
@@ -4521,7 +4786,7 @@ const flowPlugin = /*#__PURE__*/ createPlugin$1("flow", {
|
|
|
4521
4786
|
},
|
|
4522
4787
|
events: (register) => register.map({
|
|
4523
4788
|
"flow:edge": "An edge was taken and its state committed",
|
|
4524
|
-
"flow:rest": "The graph reached a rest node",
|
|
4789
|
+
"flow:rest": "The graph reached a rest node, or entered the node of a bookmark",
|
|
4525
4790
|
"flow:error": "A node failed and the graph rolled back"
|
|
4526
4791
|
}),
|
|
4527
4792
|
createState: createFlowState,
|
|
@@ -17236,8 +17501,32 @@ async function untilAborted(ctx, bundle, signal) {
|
|
|
17236
17501
|
if (load.failed && !signal.aborted) throw load.error;
|
|
17237
17502
|
}
|
|
17238
17503
|
/**
|
|
17504
|
+
* Takes the expected scene and clears the record, so one `expect` mounts one scene.
|
|
17505
|
+
*
|
|
17506
|
+
* @param ctx - Domain context of the plugin.
|
|
17507
|
+
* @returns The scene id that was recorded or expected, or `undefined` when there was none.
|
|
17508
|
+
*/
|
|
17509
|
+
function takePending(ctx) {
|
|
17510
|
+
const target = ctx.state.pending;
|
|
17511
|
+
ctx.state.pending = void 0;
|
|
17512
|
+
return target;
|
|
17513
|
+
}
|
|
17514
|
+
/**
|
|
17515
|
+
* Tells whether the node is a transit node of a fast walk: the walk passes through it and builds
|
|
17516
|
+
* no scene there.
|
|
17517
|
+
*
|
|
17518
|
+
* @param node - The node being entered.
|
|
17519
|
+
* @param run - The runner's mode and signal.
|
|
17520
|
+
* @returns True for a node without `rest` entered in fast mode.
|
|
17521
|
+
*/
|
|
17522
|
+
function isFastTransit(node, run) {
|
|
17523
|
+
return run.mode === "fast" && !node.rest;
|
|
17524
|
+
}
|
|
17525
|
+
/**
|
|
17239
17526
|
* Reads the scene the node asks for. In fast mode a transit node only records it: the walk passes
|
|
17240
|
-
* through many of them and the picture is built once, at the rest point.
|
|
17527
|
+
* through many of them and the picture is built once, at the rest point. In live mode a transit
|
|
17528
|
+
* node without a scene of its own takes the expected one, so a restore at a popup that waits for
|
|
17529
|
+
* its answer builds the scene under it; one with its own scene leaves the record alone.
|
|
17241
17530
|
*
|
|
17242
17531
|
* @param ctx - Domain context of the plugin.
|
|
17243
17532
|
* @param node - The node being entered.
|
|
@@ -17246,32 +17535,33 @@ async function untilAborted(ctx, bundle, signal) {
|
|
|
17246
17535
|
*/
|
|
17247
17536
|
function targetOf(ctx, node, run) {
|
|
17248
17537
|
const state = ctx.state;
|
|
17249
|
-
if (run
|
|
17250
|
-
|
|
17538
|
+
if (isFastTransit(node, run)) {
|
|
17539
|
+
state.pending = node.scene ?? state.pending;
|
|
17251
17540
|
return;
|
|
17252
17541
|
}
|
|
17253
|
-
if (!node.rest) return node.scene;
|
|
17542
|
+
if (!node.rest) return node.scene ?? takePending(ctx);
|
|
17254
17543
|
const target = node.scene ?? state.pending;
|
|
17255
17544
|
state.pending = void 0;
|
|
17256
17545
|
if (target === void 0 && state.current === void 0) ctx.log.warn("scenes: a rest node was entered with no scene", { path: node.path });
|
|
17257
17546
|
return target;
|
|
17258
17547
|
}
|
|
17259
17548
|
/**
|
|
17260
|
-
* Reads the scene an `over` node asks for. An over node never switches a mounted scene;
|
|
17261
|
-
*
|
|
17262
|
-
*
|
|
17549
|
+
* Reads the scene an `over` node asks for. An over node never switches a mounted scene; it takes
|
|
17550
|
+
* the expected scene while nothing is mounted, so a restore at a popup builds the scene under it,
|
|
17551
|
+
* whether the popup rests or waits for its answer. In fast mode an over transit node takes
|
|
17552
|
+
* nothing and leaves the record alone: a walk builds no scene on the way. A scene the over node
|
|
17553
|
+
* names itself is only warned about.
|
|
17263
17554
|
*
|
|
17264
17555
|
* @param ctx - Domain context of the plugin.
|
|
17265
17556
|
* @param node - The over node being entered.
|
|
17557
|
+
* @param run - The runner's mode and signal.
|
|
17266
17558
|
* @returns The expected scene id, or `undefined` when nothing has to happen.
|
|
17267
17559
|
*/
|
|
17268
|
-
function overTargetOf(ctx, node) {
|
|
17269
|
-
const state = ctx.state;
|
|
17560
|
+
function overTargetOf(ctx, node, run) {
|
|
17270
17561
|
if (node.scene !== void 0) ctx.log.warn("scenes: an over node cannot name a scene", { path: node.path });
|
|
17271
|
-
if (
|
|
17272
|
-
|
|
17273
|
-
|
|
17274
|
-
return target;
|
|
17562
|
+
if (isFastTransit(node, run)) return void 0;
|
|
17563
|
+
if (ctx.state.current !== void 0) return void 0;
|
|
17564
|
+
return takePending(ctx);
|
|
17275
17565
|
}
|
|
17276
17566
|
/**
|
|
17277
17567
|
* Builds the scene in one synchronous block: the layers, then the projections of the old scene
|
|
@@ -17317,7 +17607,7 @@ function apply(ctx, scene) {
|
|
|
17317
17607
|
* ```
|
|
17318
17608
|
*/
|
|
17319
17609
|
async function enterScene(ctx, node, run) {
|
|
17320
|
-
const target = node.over ? overTargetOf(ctx, node) : targetOf(ctx, node, run);
|
|
17610
|
+
const target = node.over ? overTargetOf(ctx, node, run) : targetOf(ctx, node, run);
|
|
17321
17611
|
if (target === void 0 || target === ctx.state.current) return;
|
|
17322
17612
|
const scene = ctx.state.scenes.get(target);
|
|
17323
17613
|
if (scene === void 0) throw new Error(`[game] Scene "${target}" is not registered.\n List it in the scenes of a feature.`);
|