narraleaf-react 1.2.0 → 1.3.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.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ServiceHandlerCtx } from "../elements/service";
|
|
1
|
+
import { ServiceHandlerCtx, ServiceSkipRequest, ServiceSkipSignal } from "../elements/service";
|
|
2
2
|
import { Origins } from "../elements/story";
|
|
3
3
|
import { TransformDefinitions } from "../elements/transform/type";
|
|
4
4
|
import { IGamePluginRegistry } from "../game/plugin/plugin";
|
|
@@ -14,5 +14,5 @@ import { StorableType } from "../elements/persistent/type";
|
|
|
14
14
|
import { ScriptCtx } from "../elements/script";
|
|
15
15
|
import { IStoryConfig } from "../elements/story";
|
|
16
16
|
export * from "../elements/type";
|
|
17
|
-
export type { GameHistory, IGamePluginRegistry, LiveGameEventToken, Origins, ServiceHandlerCtx, TransformDefinitions, GameConfig, SavedGame, NotificationToken, SavedGameMetaData, LayoutRouter, KeyBindingValue, WebKeyboardKey, StorableType, ScriptCtx, IStoryConfig, SoundBusId };
|
|
17
|
+
export type { GameHistory, IGamePluginRegistry, LiveGameEventToken, Origins, ServiceHandlerCtx, ServiceSkipRequest, ServiceSkipSignal, TransformDefinitions, GameConfig, SavedGame, NotificationToken, SavedGameMetaData, LayoutRouter, KeyBindingValue, WebKeyboardKey, StorableType, ScriptCtx, IStoryConfig, SoundBusId };
|
|
18
18
|
export { KeyBindingType, SoundType, };
|
|
@@ -1,18 +1,101 @@
|
|
|
1
1
|
import { Actionable } from "../action/actionable";
|
|
2
|
-
import { SerializableData, StringKeyOf } from "../../../util/data";
|
|
2
|
+
import { EventToken, SerializableData, StringKeyOf } from "../../../util/data";
|
|
3
3
|
import { Chained, Proxied } from "../action/chain";
|
|
4
4
|
import { ServiceAction } from "../action/serviceAction";
|
|
5
5
|
import { ScriptCtx } from "../elements/script";
|
|
6
6
|
type ServiceContentType = {
|
|
7
7
|
[K in string]: any[];
|
|
8
8
|
};
|
|
9
|
+
/**
|
|
10
|
+
* One request from the player to hurry a running service handler.
|
|
11
|
+
*/
|
|
12
|
+
export interface ServiceSkipRequest {
|
|
13
|
+
/**
|
|
14
|
+
* `true` for the skip mode - the skip key held, {@link LiveGame.skipDialog}, and
|
|
15
|
+
* {@link LiveGame.fastForward} - and `false` for a single press of the skip key.
|
|
16
|
+
*
|
|
17
|
+
* The same distinction a line of dialogue draws: a single press reveals a line up to its next
|
|
18
|
+
* pause, the skip mode walks past the pauses too.
|
|
19
|
+
*/
|
|
20
|
+
readonly forced: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The player asking a running handler to hurry, and the handler's answer.
|
|
24
|
+
*
|
|
25
|
+
* A request does not end the handler. The handler decides what being skipped means for it:
|
|
26
|
+
* - **finish now** - put whatever it was doing into its final state and return, in
|
|
27
|
+
* {@link onRequest};
|
|
28
|
+
* - **ignore it** - carry on; the skip mode waits for the handler, and
|
|
29
|
+
* {@link LiveGame.fastForward} waits up to its `stepTimeout` before reporting `"stalled"`.
|
|
30
|
+
* This is what a handler that never looks at `ctx.skip` does;
|
|
31
|
+
* - **refuse** - {@link refuse}: the skip mode still waits, and a fast-forward stops at this step
|
|
32
|
+
* at once and reports `"refused"`.
|
|
33
|
+
*
|
|
34
|
+
* Requests are broadcast: a handler running in a `Control.all` branch or an async branch is asked
|
|
35
|
+
* whenever the player skips anything, the way a sprite's transition running beside a line is.
|
|
36
|
+
*
|
|
37
|
+
* Only an asynchronous handler is ever asked. A synchronous one has already finished by the time
|
|
38
|
+
* the player could ask.
|
|
39
|
+
*/
|
|
40
|
+
export interface ServiceSkipSignal {
|
|
41
|
+
/** Whether the player has asked this handler to hurry yet. */
|
|
42
|
+
readonly requested: boolean;
|
|
43
|
+
/** Whether the player has asked it in the skip mode yet. */
|
|
44
|
+
readonly forced: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Whether the game is in {@link LiveGame.fastForward} right now. A handler that checks it on
|
|
47
|
+
* entry can go straight to its final state.
|
|
48
|
+
*/
|
|
49
|
+
readonly fastForwarding: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Listen for the player asking this handler to hurry.
|
|
52
|
+
*
|
|
53
|
+
* Called once for the first request, and once more the first time a request is
|
|
54
|
+
* {@link ServiceSkipRequest.forced | forced} - not for every repeat, which the skip mode sends
|
|
55
|
+
* many times a second. Registering after a request has already arrived calls the listener at
|
|
56
|
+
* once.
|
|
57
|
+
*/
|
|
58
|
+
onRequest(listener: (request: ServiceSkipRequest) => void): EventToken;
|
|
59
|
+
/**
|
|
60
|
+
* Refuse to be fast-forwarded past until the returned function is called.
|
|
61
|
+
*
|
|
62
|
+
* Refusals stack: the step can be skipped again once every one has been released. The message
|
|
63
|
+
* is for people - it is logged, and handed back by {@link LiveGame.fastForward} for a host to
|
|
64
|
+
* show - and nothing in the engine reads it to decide anything.
|
|
65
|
+
*/
|
|
66
|
+
refuse(message?: string): () => void;
|
|
67
|
+
}
|
|
9
68
|
export type ServiceHandlerCtx = ScriptCtx & {
|
|
69
|
+
/**
|
|
70
|
+
* Aborted when this run is cancelled: the player stepped back past it, the story jumped away
|
|
71
|
+
* from it, a `Control.any` it ran in was won by another branch, or the game was reset or loaded.
|
|
72
|
+
*
|
|
73
|
+
* A cancellation cannot be refused, and it does not wait for the handler: by the time the
|
|
74
|
+
* signal fires the game has already moved on. Pass the signal to whatever the handler is
|
|
75
|
+
* waiting on (`fetch(url, {signal})`), and check `signal.aborted` after each `await` before
|
|
76
|
+
* touching the game again.
|
|
77
|
+
*/
|
|
78
|
+
signal: AbortSignal;
|
|
79
|
+
/** The player asking this handler to hurry. See {@link ServiceSkipSignal}. */
|
|
80
|
+
skip: ServiceSkipSignal;
|
|
81
|
+
/**
|
|
82
|
+
* Run `handler` when this run is cancelled. Registering after the cancellation runs it at once.
|
|
83
|
+
* @deprecated Use {@link ServiceHandlerCtx.signal}, which fires on the same occasions.
|
|
84
|
+
*/
|
|
10
85
|
onAbort: (handler: () => void) => void;
|
|
11
86
|
};
|
|
12
87
|
export type ServiceHandler<Args extends any[]> = (ctx: ServiceHandlerCtx, ...args: Args) => void | Promise<void>;
|
|
13
88
|
export declare class ServiceSkeleton<Content extends ServiceContentType = ServiceContentType, RawData extends Record<string, SerializableData> | null = never> extends Actionable<RawData, ServiceSkeleton> {
|
|
14
89
|
/**
|
|
15
90
|
* Register an action handler.
|
|
91
|
+
*
|
|
92
|
+
* A handler that returns a promise holds the story until the promise settles, the way a line
|
|
93
|
+
* of dialogue does; one that returns anything else lets it carry on at once. If the promise
|
|
94
|
+
* rejects, the story stops at this action and the error is reported.
|
|
95
|
+
*
|
|
96
|
+
* While it holds the story, a handler hears about the player through its context:
|
|
97
|
+
* `ctx.skip` when the player asks it to hurry, which it may answer or refuse, and `ctx.signal`
|
|
98
|
+
* when its run is cancelled, which it may not.
|
|
16
99
|
* @param key - The action key to handle.
|
|
17
100
|
* @param handler - Callback invoked when the action fires.
|
|
18
101
|
* @example
|
|
@@ -20,6 +103,25 @@ export declare class ServiceSkeleton<Content extends ServiceContentType = Servic
|
|
|
20
103
|
* this.on("add", (ctx, name) => {
|
|
21
104
|
* console.log("Adding", name);
|
|
22
105
|
* });
|
|
106
|
+
*
|
|
107
|
+
* this.on("countdown", async (ctx, seconds: number) => {
|
|
108
|
+
* // Skipping finishes the countdown at once.
|
|
109
|
+
* const done = new Promise<void>(resolve => {
|
|
110
|
+
* const timer = setTimeout(resolve, seconds * 1000);
|
|
111
|
+
* ctx.skip.onRequest(() => {
|
|
112
|
+
* clearTimeout(timer);
|
|
113
|
+
* resolve();
|
|
114
|
+
* });
|
|
115
|
+
* ctx.signal.addEventListener("abort", () => clearTimeout(timer));
|
|
116
|
+
* });
|
|
117
|
+
* await done;
|
|
118
|
+
* });
|
|
119
|
+
*
|
|
120
|
+
* this.on("minigame", async (ctx) => {
|
|
121
|
+
* // A fast-forward cannot play the minigame for the player, so it stops here.
|
|
122
|
+
* ctx.skip.refuse("waiting for the minigame");
|
|
123
|
+
* await playMinigame(ctx.signal);
|
|
124
|
+
* });
|
|
23
125
|
* ```
|
|
24
126
|
*/
|
|
25
127
|
on<K extends StringKeyOf<Content>>(key: K, handler: ServiceHandler<Content[K]>): this;
|
|
@@ -184,7 +184,8 @@ export declare class LiveGame {
|
|
|
184
184
|
* Skipping a line is a *request* to the renderer, not a synchronous state change: it is
|
|
185
185
|
* re-issued until the line settles. A line that never responds (an unskippable in-flight
|
|
186
186
|
* media/transition step) ends the run with `"stalled"` rather than hanging — this method always
|
|
187
|
-
* settles.
|
|
187
|
+
* settles. A step that answers by refusing to be skipped (a user service calling
|
|
188
|
+
* `ctx.skip.refuse()`) ends it at once with `"refused"`, and is left running where it is.
|
|
188
189
|
*
|
|
189
190
|
* Because history accumulates the whole way, {@link getHistory} and
|
|
190
191
|
* {@link restoreToHistory} cover the fast-forwarded span just like normal play.
|
|
@@ -207,9 +208,11 @@ export declare class LiveGame {
|
|
|
207
208
|
* reports `"stalled"`. Defaults to 10000. Raise it if the story
|
|
208
209
|
* fast-forwards through long unskippable media.
|
|
209
210
|
* @returns why it stopped: `"action"` (reached `until.actionId`), `"menu"`, `"end"` (the stack
|
|
210
|
-
* drained), `"maxSteps"`,
|
|
211
|
-
* `
|
|
212
|
-
* `"action"`).
|
|
211
|
+
* drained), `"maxSteps"`, `"stalled"` (a line did not settle within `stepTimeout`), or
|
|
212
|
+
* `"refused"` (a line refused to be skipped). When an `actionId` target was requested,
|
|
213
|
+
* `reachedTarget` is also set (`true` only for reason `"action"`). With `"refused"`,
|
|
214
|
+
* `refusal` carries the message the step gave, if it gave one: it is for showing to a
|
|
215
|
+
* person, not for deciding what to do next.
|
|
213
216
|
*
|
|
214
217
|
* Note: only the root execution stack is scanned for the target — an id buried inside an
|
|
215
218
|
* in-flight parallel (`Control.all`/`any`) or async branch is not a stop point.
|
|
@@ -221,8 +224,9 @@ export declare class LiveGame {
|
|
|
221
224
|
maxSteps?: number;
|
|
222
225
|
stepTimeout?: number;
|
|
223
226
|
}): Promise<{
|
|
224
|
-
reason: "menu" | "end" | "maxSteps" | "action" | "stalled";
|
|
227
|
+
reason: "menu" | "end" | "maxSteps" | "action" | "stalled" | "refused";
|
|
225
228
|
reachedTarget?: boolean;
|
|
229
|
+
refusal?: string;
|
|
226
230
|
}>;
|
|
227
231
|
private assertScreenshot;
|
|
228
232
|
/**
|