@patterkit/runtime 0.23.0 → 0.24.0
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/CHANGELOG.md +12 -0
- package/README.md +4 -0
- package/dist/index.cjs +57 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +57 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ScalarValue } from '@wildwinter/expr';
|
|
2
2
|
import { ScopeRegistry, PropertyBag, ScopeDeclaration, LogMount, ScopeResolver, PropertyRow } from '@wildwinter/scoperegistry';
|
|
3
3
|
export { PropertyRow } from '@wildwinter/scoperegistry';
|
|
4
|
-
import { GameData, Bundle, CompiledGroup, CompiledSnippet, CompiledBlock, FlowSnapshot, EngineSave, SaveGame, SaveGameV2, PropertyType, ScalarValue as ScalarValue$1, GameDataNodeKind, GameDataField } from '@patterkit/model';
|
|
5
|
-
export { Bundle, DEFAULT_PAD_AFTER, EngineSave, FlowCursor, FlowSnapshot, SaveEnvelope, SaveGame, SavedChoice, SavedChoiceOption, SavedChoicePrompt, SelectorSnapshot, StackFrame } from '@patterkit/model';
|
|
4
|
+
import { GameData, Bundle, CompiledGroup, CompiledSnippet, CompiledBlock, FlowSnapshot, FlowState, EngineSave, SaveGame, SaveGameV2, PropertyType, ScalarValue as ScalarValue$1, GameDataNodeKind, GameDataField } from '@patterkit/model';
|
|
5
|
+
export { Bundle, DEFAULT_PAD_AFTER, EngineSave, FlowCursor, FlowSnapshot, FlowState, FlowValues, SaveEnvelope, SaveGame, SavedChoice, SavedChoiceOption, SavedChoicePrompt, SelectorSnapshot, StackFrame } from '@patterkit/model';
|
|
6
6
|
|
|
7
7
|
/** A beat's own `padAfter` (when it sets one) and its resolved one (always). */
|
|
8
8
|
interface BeatPad {
|
|
@@ -686,6 +686,20 @@ declare class Engine {
|
|
|
686
686
|
/** Let go of what a closed checkpoint recorded, so a handle the game keeps holds nothing. */
|
|
687
687
|
private static forget;
|
|
688
688
|
private refuseInCheckpoint;
|
|
689
|
+
/**
|
|
690
|
+
* Take flow `id` out of the engine as plain data, to be put back later with {@link restoreFlow}: its snapshot as
|
|
691
|
+
* `saveGame` writes it, and its own property values without its id (so it can come back under another). Shared
|
|
692
|
+
* state is never in it. Doesn't close the flow; close it with {@link closeFlow} AFTER capturing, since closing
|
|
693
|
+
* drops its values. Only reads, so it is allowed while a checkpoint is open.
|
|
694
|
+
*/
|
|
695
|
+
captureFlow(id: string): FlowState;
|
|
696
|
+
/**
|
|
697
|
+
* Open flow `id` from a {@link captureFlow} state, the per-flow half of `loadGame`: its values go into the
|
|
698
|
+
* registry as a load's do, and the flow is restored as a load restores each flow. `id` needn't be the id it was
|
|
699
|
+
* captured from. Against an edited bundle it re-finds its place by id, as a load does. Refused if a flow of
|
|
700
|
+
* that id is open, or while a checkpoint is.
|
|
701
|
+
*/
|
|
702
|
+
restoreFlow(id: string, state: FlowState): Flow;
|
|
689
703
|
/** Close (remove) a flow. The flow object is FINISHED, not merely unregistered, so a host still
|
|
690
704
|
* holding it cannot keep advancing it into the shared world (see {@link Flow.close}). */
|
|
691
705
|
closeFlow(id: string): void;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ScalarValue } from '@wildwinter/expr';
|
|
2
2
|
import { ScopeRegistry, PropertyBag, ScopeDeclaration, LogMount, ScopeResolver, PropertyRow } from '@wildwinter/scoperegistry';
|
|
3
3
|
export { PropertyRow } from '@wildwinter/scoperegistry';
|
|
4
|
-
import { GameData, Bundle, CompiledGroup, CompiledSnippet, CompiledBlock, FlowSnapshot, EngineSave, SaveGame, SaveGameV2, PropertyType, ScalarValue as ScalarValue$1, GameDataNodeKind, GameDataField } from '@patterkit/model';
|
|
5
|
-
export { Bundle, DEFAULT_PAD_AFTER, EngineSave, FlowCursor, FlowSnapshot, SaveEnvelope, SaveGame, SavedChoice, SavedChoiceOption, SavedChoicePrompt, SelectorSnapshot, StackFrame } from '@patterkit/model';
|
|
4
|
+
import { GameData, Bundle, CompiledGroup, CompiledSnippet, CompiledBlock, FlowSnapshot, FlowState, EngineSave, SaveGame, SaveGameV2, PropertyType, ScalarValue as ScalarValue$1, GameDataNodeKind, GameDataField } from '@patterkit/model';
|
|
5
|
+
export { Bundle, DEFAULT_PAD_AFTER, EngineSave, FlowCursor, FlowSnapshot, FlowState, FlowValues, SaveEnvelope, SaveGame, SavedChoice, SavedChoiceOption, SavedChoicePrompt, SelectorSnapshot, StackFrame } from '@patterkit/model';
|
|
6
6
|
|
|
7
7
|
/** A beat's own `padAfter` (when it sets one) and its resolved one (always). */
|
|
8
8
|
interface BeatPad {
|
|
@@ -686,6 +686,20 @@ declare class Engine {
|
|
|
686
686
|
/** Let go of what a closed checkpoint recorded, so a handle the game keeps holds nothing. */
|
|
687
687
|
private static forget;
|
|
688
688
|
private refuseInCheckpoint;
|
|
689
|
+
/**
|
|
690
|
+
* Take flow `id` out of the engine as plain data, to be put back later with {@link restoreFlow}: its snapshot as
|
|
691
|
+
* `saveGame` writes it, and its own property values without its id (so it can come back under another). Shared
|
|
692
|
+
* state is never in it. Doesn't close the flow; close it with {@link closeFlow} AFTER capturing, since closing
|
|
693
|
+
* drops its values. Only reads, so it is allowed while a checkpoint is open.
|
|
694
|
+
*/
|
|
695
|
+
captureFlow(id: string): FlowState;
|
|
696
|
+
/**
|
|
697
|
+
* Open flow `id` from a {@link captureFlow} state, the per-flow half of `loadGame`: its values go into the
|
|
698
|
+
* registry as a load's do, and the flow is restored as a load restores each flow. `id` needn't be the id it was
|
|
699
|
+
* captured from. Against an edited bundle it re-finds its place by id, as a load does. Refused if a flow of
|
|
700
|
+
* that id is open, or while a checkpoint is.
|
|
701
|
+
*/
|
|
702
|
+
restoreFlow(id: string, state: FlowState): Flow;
|
|
689
703
|
/** Close (remove) a flow. The flow object is FINISHED, not merely unregistered, so a host still
|
|
690
704
|
* holding it cannot keep advancing it into the shared world (see {@link Flow.close}). */
|
|
691
705
|
closeFlow(id: string): void;
|
package/dist/index.js
CHANGED
|
@@ -105,6 +105,7 @@ function tagsOf(host, id) {
|
|
|
105
105
|
}
|
|
106
106
|
var OWNER = "Patter";
|
|
107
107
|
var esc = (id) => id.replace(/%/g, "%25").replace(/\//g, "%2F");
|
|
108
|
+
var unesc = (key) => key.replace(/%2F/g, "/").replace(/%25/g, "%");
|
|
108
109
|
var OWNS_REGISTRY = /* @__PURE__ */ Symbol("ownsRegistry");
|
|
109
110
|
var keys = {
|
|
110
111
|
/** A scene's SHARED `@scene` props (one bag per scene, every flow's). */
|
|
@@ -733,6 +734,45 @@ var Engine = class _Engine {
|
|
|
733
734
|
refuseInCheckpoint(what) {
|
|
734
735
|
if (this.host.journal) throw new Error(`${what} can't be undone, so it isn't allowed while a checkpoint is open`);
|
|
735
736
|
}
|
|
737
|
+
/**
|
|
738
|
+
* Take flow `id` out of the engine as plain data, to be put back later with {@link restoreFlow}: its snapshot as
|
|
739
|
+
* `saveGame` writes it, and its own property values without its id (so it can come back under another). Shared
|
|
740
|
+
* state is never in it. Doesn't close the flow; close it with {@link closeFlow} AFTER capturing, since closing
|
|
741
|
+
* drops its values. Only reads, so it is allowed while a checkpoint is open.
|
|
742
|
+
*/
|
|
743
|
+
captureFlow(id) {
|
|
744
|
+
const flow = this.flowsById.get(id);
|
|
745
|
+
if (!flow) throw new Error(`no open flow '${id}' to capture`);
|
|
746
|
+
return { version: SAVE_VERSION, ...flow.snapshot(), ...flowValuesFrom(id, this.host.registry.save()) };
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Open flow `id` from a {@link captureFlow} state, the per-flow half of `loadGame`: its values go into the
|
|
750
|
+
* registry as a load's do, and the flow is restored as a load restores each flow. `id` needn't be the id it was
|
|
751
|
+
* captured from. Against an edited bundle it re-finds its place by id, as a load does. Refused if a flow of
|
|
752
|
+
* that id is open, or while a checkpoint is.
|
|
753
|
+
*/
|
|
754
|
+
restoreFlow(id, state) {
|
|
755
|
+
this.refuseInCheckpoint("restoreFlow");
|
|
756
|
+
const version = state.version;
|
|
757
|
+
if (version !== 2 && version !== SAVE_VERSION) throw new Error(`unsupported flow state version: ${String(version)}`);
|
|
758
|
+
const cursor = state.cursor;
|
|
759
|
+
if (typeof cursor !== "object" || cursor === null) throw new Error("malformed flow state: no cursor");
|
|
760
|
+
if (this.flowsById.has(id)) throw new Error(`a flow '${id}' is already open; close it before restoring another under that id`);
|
|
761
|
+
this.assertExternalScopes();
|
|
762
|
+
const parked = keys.flow(id);
|
|
763
|
+
this.host.registry.discardParked(parked);
|
|
764
|
+
this.host.registry.load(flowSections(id, state), { keepParked: true });
|
|
765
|
+
const flow = new Flow(id, this.host, this.defaultSeed);
|
|
766
|
+
try {
|
|
767
|
+
flow.restore(state);
|
|
768
|
+
} catch (e) {
|
|
769
|
+
flow.close();
|
|
770
|
+
this.host.registry.discardParked(parked);
|
|
771
|
+
throw e;
|
|
772
|
+
}
|
|
773
|
+
this.flowsById.set(id, flow);
|
|
774
|
+
return flow;
|
|
775
|
+
}
|
|
736
776
|
/** Close (remove) a flow. The flow object is FINISHED, not merely unregistered, so a host still
|
|
737
777
|
* holding it cannot keep advancing it into the shared world (see {@link Flow.close}). */
|
|
738
778
|
closeFlow(id) {
|
|
@@ -2136,9 +2176,23 @@ function sectionsFromV2(save) {
|
|
|
2136
2176
|
const out = {};
|
|
2137
2177
|
if (save.shared?.patter) out["patter"] = save.shared.patter;
|
|
2138
2178
|
for (const [s, v] of Object.entries(save.stageBags ?? {})) out[keys.stage(s)] = v;
|
|
2139
|
-
for (const [id, f] of Object.entries(save.flows ?? {}))
|
|
2140
|
-
|
|
2141
|
-
|
|
2179
|
+
for (const [id, f] of Object.entries(save.flows ?? {})) Object.assign(out, flowSections(id, f));
|
|
2180
|
+
return out;
|
|
2181
|
+
}
|
|
2182
|
+
function flowSections(id, f) {
|
|
2183
|
+
const out = {};
|
|
2184
|
+
if (f.scopes?.patter) out[keys.flowGlobals(id)] = f.scopes.patter;
|
|
2185
|
+
for (const [s, v] of Object.entries(f.sceneBags ?? {})) out[keys.flowScene(id, s)] = v;
|
|
2186
|
+
return out;
|
|
2187
|
+
}
|
|
2188
|
+
function flowValuesFrom(id, saved) {
|
|
2189
|
+
const out = { scopes: {}, sceneBags: {} };
|
|
2190
|
+
const prefix = keys.flow(id);
|
|
2191
|
+
for (const [key, values] of Object.entries(saved)) {
|
|
2192
|
+
if (!key.startsWith(prefix)) continue;
|
|
2193
|
+
const rest = key.slice(prefix.length);
|
|
2194
|
+
if (rest === "patter") out.scopes.patter = values;
|
|
2195
|
+
else if (rest.startsWith("scene/")) out.sceneBags[unesc(rest.slice("scene/".length))] = values;
|
|
2142
2196
|
}
|
|
2143
2197
|
return out;
|
|
2144
2198
|
}
|