@wasm-gaming/rsdkv4-wasm 0.1.4 → 0.2.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.
@@ -1,22 +1,361 @@
1
- import type { JSONSchema } from '@wasm-gaming/engine-specs';
2
- export interface Rsdkv4Options {
1
+ /**
2
+ * What this engine's four payloads accept, and the {@link RSDKV4_SPEC} that describes
3
+ * them to a host.
4
+ *
5
+ * ```ts
6
+ * import type { Rsdkv4Config, Rsdkv4Options } from '@wasm-gaming/rsdkv4-wasm/options';
7
+ * ```
8
+ *
9
+ * The contract's own module documents *how* the four payloads behave — they read as
10
+ * descriptors and write as patches, and `live` says whether a key reaches a running
11
+ * engine. This module is only the part that is RSDKv4's: which keys exist, what they
12
+ * mean here, and what the engine does with them.
13
+ *
14
+ * The split between the first two is the whole design:
15
+ *
16
+ * - {@link Rsdkv4Config} is **the engine**. It is serialized into RSDKv4's
17
+ * `settings.ini` and read once, at boot — so none of it is `live`.
18
+ * - {@link Rsdkv4Options} is **the session**: which character, which save slot, which
19
+ * stage. That is what a `restart()` reopens. It also carries the engine's own GAME
20
+ * OPTIONS rows, which *are* `live` — and which are not declared here at all, because
21
+ * they differ between Sonic 1 and Sonic 2 and are only knowable once the pack is
22
+ * loaded.
23
+ *
24
+ * @module
25
+ */
26
+ import type { EnginePayloads, EngineSpec } from '@wasm-gaming/engine-specs';
27
+ /** Bytes a host can hand over for an asset. */
28
+ export type Rsdkv4AssetData = Uint8Array | ArrayBuffer | ArrayBufferView | string;
29
+ /**
30
+ * An asset, eagerly or on demand.
31
+ *
32
+ * The thunk form is what the old `dataProvider` / `settingsProvider` config fields
33
+ * were: `assets({ data: () => fetch(url).then((r) => r.arrayBuffer()) })`. See
34
+ * {@link Rsdkv4Assets} for when each one is actually called — they differ, and the
35
+ * difference is tens of megabytes.
36
+ */
37
+ export type Rsdkv4Asset = Rsdkv4AssetData | (() => Rsdkv4AssetData | Promise<Rsdkv4AssetData>);
38
+ /**
39
+ * The engine, as `settings.ini` — read once at boot, which is why nothing here is
40
+ * `live`. Change any of it and the engine has to come back up: `destroy()` and a new
41
+ * factory, not `restart()`.
42
+ *
43
+ * Regenerated on every boot, and that is safe: RSDKv4's `writeSettings()` is inside
44
+ * `#ifndef __EMSCRIPTEN__`, so this build never writes the file back and there is
45
+ * nothing of the player's in it to overwrite. A host that wants its own file hands one
46
+ * over as `assets.settings` instead, and then this payload is ignored.
47
+ */
48
+ export interface Rsdkv4Config {
49
+ /**
50
+ * VSync the engine's SDL window.
51
+ *
52
+ * @defaultValue `true`
53
+ */
54
+ vsync?: boolean;
3
55
  /**
4
- * RSDKv4's native in-canvas Dev Menu. Kept off by default: the launcher owns
5
- * the debug/stage-select UI (via `instance.devMenu`), and leaving this on has
56
+ * RSDKv4's native in-canvas Dev Menu. Off by default: a host that wants a
57
+ * debug/stage-select UI draws it from `play.devMenu`, and leaving this on has
6
58
  * historically produced a native menu-like screen at boot.
59
+ *
60
+ * @defaultValue `false`
7
61
  */
8
62
  devMenu?: boolean;
9
- /** RSDKv4 EngineDebugMode — enables the web devmenu embind bridge hooks. */
63
+ /**
64
+ * RSDKv4 `EngineDebugMode`. In this build it gates the engine's log output and
65
+ * nothing else — `play.devMenu` and `play.game` are embind bridges the wasm installs
66
+ * unconditionally, so they work either way.
67
+ *
68
+ * @defaultValue `true`
69
+ */
10
70
  engineDebugMode?: boolean;
11
- /** VSync the engine's SDL window. */
12
- vsync?: boolean;
13
- /** Boot directly into a stage: 0-based stage-list category. */
14
- startingCategory?: number;
15
- /** Boot directly into a stage: 0-based scene within the category. */
16
- startingScene?: number;
17
- /** Starting player/character index. */
18
- startingPlayer?: number;
19
- }
20
- export declare const DEFAULT_RSDKV4_OPTIONS: Required<Rsdkv4Options>;
21
- export declare const RSDKV4_OPTIONS_SCHEMA: JSONSchema;
71
+ /**
72
+ * Who draws the save-select / character-select / game-options screens.
73
+ *
74
+ * `'native'` leaves RSDKv4's own in-canvas Start Menu on. `'host'` skips it, for a
75
+ * host that renders those screens itself from `play.game` — otherwise the engine's
76
+ * menu runs underneath the host's.
77
+ *
78
+ * This is the old `skipStartMenu` boolean, the right way up: the inverted name meant
79
+ * `false` had to be read twice to mean "yes, show it".
80
+ *
81
+ * @defaultValue `'native'`
82
+ */
83
+ startMenu?: 'native' | 'host';
84
+ /**
85
+ * Where to load the Emscripten glue from. Defaults to `./rsdkv4.js` next to the
86
+ * built SDK, which is where `make build` puts it.
87
+ */
88
+ jsUrl?: string;
89
+ /** Where to load the wasm from. Defaults to `./rsdkv4.wasm` next to the built SDK. */
90
+ wasmUrl?: string;
91
+ }
92
+ /**
93
+ * A stage, as the engine's two-level stage list indexes it.
94
+ *
95
+ * `name` is **read-only**: the descriptors {@link Rsdkv4Options.stage} reports back
96
+ * carry one so a host can paint a stage picker straight from `options()`, but writing
97
+ * it is ignored — `category` and `scene` are what reach the engine.
98
+ */
99
+ export interface Rsdkv4Stage {
100
+ /** 0-based category, as ordered by `play.devMenu.getStageList()`. */
101
+ category: number;
102
+ /** 0-based scene within the category. */
103
+ scene: number;
104
+ /** `"<Category> · <Scene>"`, filled in by the SDK. Ignored on write. */
105
+ name?: string;
106
+ }
107
+ /**
108
+ * RSDKv4's fourteen buttons, in the engine's own `InputButtons` order.
109
+ *
110
+ * The order is not cosmetic: it is the bit order of the mask the SDK hands the
111
+ * engine once per tick, so this array is the wire format and not merely a list.
112
+ *
113
+ * Sonic 1 and Sonic 2 read only the four directions, A, B, C and start. The other
114
+ * six exist in the engine and are free for a host to do as it likes with.
115
+ */
116
+ export declare const RSDKV4_BUTTONS: readonly ["up", "down", "left", "right", "a", "b", "c", "x", "y", "z", "l", "r", "start", "select"];
117
+ /**
118
+ * One button, spelled as {@link RSDKV4_BUTTONS} spells it.
119
+ *
120
+ * Derived from the array rather than declared beside it, so there is one list and
121
+ * not two to drift apart — and so a typo in a `buttons` literal is a compile error
122
+ * rather than a button that silently never fires.
123
+ */
124
+ export type Rsdkv4Button = (typeof RSDKV4_BUTTONS)[number];
125
+ /**
126
+ * Every button as a boolean — what a host hands over to {@link Rsdkv4Options.buttons}
127
+ * and keeps writing to for as long as it holds the claim.
128
+ *
129
+ * All fourteen are required. A key that is merely absent reads as `false` on every
130
+ * tick, which is a dead button and no error anywhere; requiring the whole set is what
131
+ * turns that into something the compiler catches.
132
+ */
133
+ export type Rsdkv4Buttons = Record<Rsdkv4Button, boolean>;
134
+ /**
135
+ * What the engine binds each button to by default, for a host that has taken input
136
+ * over and now has to bind them itself.
137
+ *
138
+ * Not engine configuration — nothing here is read by the engine, and writing to it
139
+ * changes nothing. It is a starting table, so a host that claims input can offer the
140
+ * bindings a player already knows instead of inventing its own.
141
+ */
142
+ export interface Rsdkv4InputDefaults {
143
+ /** `KeyboardEvent.code` values, as `settings.ini`'s `[Keyboard 1]` binds them. */
144
+ keyboard: Record<Rsdkv4Button, string>;
145
+ /**
146
+ * Indices into `Gamepad.buttons` under the browser's **standard mapping**.
147
+ *
148
+ * These are translated, not copied: `settings.ini`'s `[Controller 1]` holds
149
+ * SDL's `SDL_CONTROLLER_BUTTON_*` values, and those are different numbers — SDL's
150
+ * left shoulder is 9, where the browser's is 4. A host polling the Gamepad API
151
+ * wants the browser's, so that is what this carries.
152
+ *
153
+ * `null` where the engine's default has no standard-mapping button: `select` is
154
+ * bound to SDL's GUIDE, which this build's own web-gamepad mapping never wires
155
+ * up, so it is dead on a pad in the engine too. `y` and `z` are the analog
156
+ * triggers (the engine reads them past a deadzone, as ZL/ZR).
157
+ */
158
+ gamepad: Record<Rsdkv4Button, number | null>;
159
+ }
160
+ /**
161
+ * The engine's own default bindings. See {@link Rsdkv4InputDefaults}.
162
+ *
163
+ * This replaces the old `RSDKV4_KEYMAP`, which nothing read and which was wrong in
164
+ * three ways for want of ever being checked against the engine: it listed 9 of the
165
+ * 14 buttons, and bound `select` to `ShiftLeft` where the engine's default is `Tab`.
166
+ */
167
+ export declare const RSDKV4_INPUT: Rsdkv4InputDefaults;
168
+ /**
169
+ * The session — what a `restart()` reopens.
170
+ *
171
+ * **Absence is the neutral value.** The old `RSDKV4_UNSET = 255` sentinel is gone:
172
+ * leaving a key out means "boot the way the engine normally would", and there is no
173
+ * longer a number that quietly means something else. (In particular `player: 0` used
174
+ * to be indistinguishable from "unset" in the ini, which is why it was a footgun.)
175
+ *
176
+ * The index signature is not laziness. The engine's GAME OPTIONS rows — spin dash,
177
+ * item-box set, and whatever else the loaded pack declares — are keys neither this
178
+ * package nor the host can know ahead of time. They come back from `options()` as
179
+ * descriptors with their own labels and choices, `live: true`, and are written back
180
+ * the same way. That is what lets a host paint a settings screen without knowing a
181
+ * single key name.
182
+ */
183
+ export interface Rsdkv4Options {
184
+ /**
185
+ * The character to start a *new* game as, by the name the pack reports — the
186
+ * `enum` of this key's descriptor is exactly `play.game.players()`, so a host paints
187
+ * a character picker from it and writes one of the values straight back. Matched
188
+ * case-insensitively; an unknown name is an error rather than a silent Sonic.
189
+ *
190
+ * Continuing a slot that already has a save ignores this: the save carries its own
191
+ * character.
192
+ */
193
+ player?: string;
194
+ /**
195
+ * Which of RSDKv4's four save slots (0-3) the session runs on. `null` plays without
196
+ * saving, as the native menu's NO SAVE does.
197
+ *
198
+ * A slot with data continues it; an empty slot starts a new game as {@link player}.
199
+ */
200
+ slot?: number | null;
201
+ /**
202
+ * Jump straight to a stage, skipping wherever the session would otherwise open.
203
+ *
204
+ * Applied through the engine's own stage loader after boot, not through
205
+ * `settings.ini`'s `Starting*` trio — which is why it works on a `restart()` of a
206
+ * running engine and not only on the first one.
207
+ */
208
+ stage?: Rsdkv4Stage;
209
+ /**
210
+ * Take input over: hand the engine a live object of fourteen booleans and it stops
211
+ * polling SDL, reading yours instead — touch buttons, rebinding, netplay, a test
212
+ * that drives a stage from a script.
213
+ *
214
+ * ```ts
215
+ * const buttons = { up: false, down: false, ...rest, select: false }; // all 14
216
+ * play.options({ buttons }); // claim
217
+ * play.options({ buttons: null }); // release — the engine polls SDL again
218
+ * ```
219
+ *
220
+ * **Read once per tick, from wherever it lives.** The engine calls in at the top of
221
+ * its input pass and the SDK reads the object at that moment, so a plain object and
222
+ * a reactive store both work and neither one needs the SDK to know which it is.
223
+ * Whatever is `true` when the engine asks is what the engine sees.
224
+ *
225
+ * Three things become the host's the moment it claims:
226
+ *
227
+ * - **Keyup on focus loss.** SDL resets its keyboard when the window loses focus; a
228
+ * host that owns input inherits that job (`blur`, `visibilitychange`) or a held
229
+ * arrow strands the player mid-run.
230
+ * - **The gamepad, entirely.** The engine stops polling it, so a host that wants one
231
+ * polls the Gamepad API itself — deadzones and the D-pad-from-axes fallback
232
+ * included. {@link RSDKV4_INPUT} is the table to start from.
233
+ * - **Releasing.** Absence means "leave the claim as it is"; only `null` releases.
234
+ * A component that claims and then unmounts without releasing leaves the engine
235
+ * pulling at an object nobody writes to any more.
236
+ *
237
+ * Not persistable, and not a settings row: it reads back from `options()` as `null`
238
+ * whether or not a claim is held, so that `JSON.stringify(await play.options())`
239
+ * cannot sweep fourteen transient booleans into a host's saved settings. Ask
240
+ * `play.input.claimed` for the claim state.
241
+ *
242
+ * `play.input.claim(buttons)` and `play.input.release()` are the same thing, named.
243
+ */
244
+ buttons?: Rsdkv4Buttons | null;
245
+ /**
246
+ * The engine's GAME OPTIONS rows. See the note on the interface: these are declared
247
+ * by the loaded pack, not here.
248
+ *
249
+ * A `boolean` row reads and writes as a boolean, an enum row as one of its choice
250
+ * labels; the raw engine-side number is accepted on write too.
251
+ */
252
+ [key: string]: unknown;
253
+ }
254
+ /**
255
+ * The two files the engine reads out of its working directory.
256
+ *
257
+ * Neither is `live`: they are read while the engine comes up, so a patch after that
258
+ * lands in the state a *future* engine would boot from.
259
+ */
260
+ export interface Rsdkv4Assets {
261
+ /**
262
+ * The `Data.rsdk` pack — the whole game, and what decides *which* game: one
263
+ * game-agnostic wasm runs both Sonic 1 and Sonic 2, the pack is the difference.
264
+ *
265
+ * Precedence, and the reason the thunk form exists: bytes handed over here win;
266
+ * otherwise a copy already persisted in this storage namespace is reused; only if
267
+ * there is neither is a thunk called. That is what keeps a host from re-fetching
268
+ * tens of megabytes it already has. With none of the three, `start()` fails.
269
+ */
270
+ data?: Rsdkv4Asset;
271
+ /**
272
+ * A ready-made `settings.ini`, for a host that would rather write the file itself
273
+ * than describe it through {@link Rsdkv4Config}. Given one, the config payload is
274
+ * not serialized at all.
275
+ *
276
+ * Unlike `data`, a thunk here is called on **every** boot rather than only on a
277
+ * cache miss — the file is a few hundred bytes, and re-reading it is what makes the
278
+ * host's copy authoritative instead of whatever an earlier session left behind.
279
+ */
280
+ settings?: Rsdkv4Asset;
281
+ }
282
+ /** Where this engine's files live, and whether they outlive the page. */
283
+ export interface Rsdkv4Storage {
284
+ /**
285
+ * Per-game folder for the pack, the settings and the save file, so two games do not
286
+ * overwrite each other. Examples: `"sonic1"`, `"rsdkv4/Sonic2"`.
287
+ *
288
+ * It is a path under the engine's working root *and* the OPFS directory the SDK
289
+ * mirrors save data into, which is what lets a host read `<namespace>/SData.bin`
290
+ * itself. Anything that is not a usable relative path normalises to `"default"` —
291
+ * including the object you get from interpolating a game record by mistake.
292
+ *
293
+ * @defaultValue `"default"`
294
+ */
295
+ namespace?: string;
296
+ /**
297
+ * What the engine's working directory is backed by.
298
+ *
299
+ * `'opfs'` forces a persistent mount and warns if it cannot have one; `null` means
300
+ * the host wants nothing kept, which switches off the save mirror as well; leaving
301
+ * it out picks OPFS when the page is cross-origin isolated.
302
+ *
303
+ * Worth knowing: on every build without Asyncify/JSPI — today's included — the mount
304
+ * itself cannot be OPFS, so the working dir is in-memory whatever this says. Saves
305
+ * survive anyway, because the SDK mirrors `SData.bin` into
306
+ * `<namespace>/` through the host-side OPFS API. `null` is what turns that off.
307
+ */
308
+ persist?: 'opfs' | null;
309
+ }
310
+ /** One of RSDKv4's four save slots, as the engine's own save-select screen sees it. */
311
+ export interface RsdkSaveSlot {
312
+ /** 0-3. */
313
+ slot: number;
314
+ /** No game stored here — starting it means picking a character first. */
315
+ empty: boolean;
316
+ /** Character index into `play.game.players()`: 0 Sonic, 1 Tails, 2 Knuckles, 3 both. */
317
+ character: number;
318
+ lives: number;
319
+ score: number;
320
+ emeralds: number;
321
+ /** Stage list the save resumes into (1 regular, 3 special), or -1 when empty. */
322
+ list: number;
323
+ /** 0-based scene within `list` — index it against `play.devMenu.getStageList()`. */
324
+ zone: number;
325
+ }
326
+ /**
327
+ * What this engine announces on top of the contract's core set (`start`, `error`,
328
+ * `exit`, `pause`, `resume`).
329
+ */
330
+ export interface Rsdkv4Events {
331
+ /**
332
+ * The save file changed, with every slot as it now stands.
333
+ *
334
+ * Emitted when the SDK has just written `<namespace>/SData.bin` out of the wasm and
335
+ * the bytes are not what they were — on its slow timer, on a pause, and on the way
336
+ * down. A host painting save slots subscribes to this instead of polling.
337
+ */
338
+ saves: RsdkSaveSlot[];
339
+ }
340
+ /** The four payloads, closed — the single type parameter everything else takes. */
341
+ export interface Rsdkv4Payloads extends EnginePayloads {
342
+ config: Rsdkv4Config;
343
+ options: Rsdkv4Options;
344
+ assets: Rsdkv4Assets;
345
+ storage: Rsdkv4Storage;
346
+ events: Rsdkv4Events;
347
+ }
348
+ /**
349
+ * Everything the engine declares about its own properties, as data.
350
+ *
351
+ * `default` appears here and nowhere else: the contract's base class seeds the
352
+ * starting state from it, so there is no second table of defaults to drift out of
353
+ * agreement with this one — which is exactly what the old
354
+ * `DEFAULT_RSDKV4_OPTIONS`-alongside-a-JSON-Schema pair did.
355
+ *
356
+ * What is missing from `options` is deliberate: `player` and `stage` get their `enum`
357
+ * filled in from the loaded pack, and the GAME OPTIONS rows are added outright, when a
358
+ * running engine is asked to describe itself.
359
+ */
360
+ export declare const RSDKV4_SPEC: EngineSpec<Rsdkv4Payloads>;
22
361
  //# sourceMappingURL=rsdkv4.options.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rsdkv4.options.d.ts","sourceRoot":"","sources":["../../src/rsdkv4.options.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4EAA4E;IAC5E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,qCAAqC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,aAAa,CAO1D,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,UAoBnC,CAAC"}
1
+ {"version":3,"file":"rsdkv4.options.d.ts","sourceRoot":"","sources":["../../src/rsdkv4.options.ts"],"names":[],"mappings":"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"}
@@ -1,41 +1,180 @@
1
- // Engine-specific options for RSDKv4.
2
- //
3
- // This is the authoritative description of what `EngineConfig.options` accepts
4
- // for this engine. It provides both:
5
- // - `Rsdkv4Options` — the compile-time type (for TS hosts/launchers)
6
- // - `RSDKV4_OPTIONS_SCHEMA` — the JSON Schema mirrored into manifest.json's
7
- // `options` (for runtime host UI + validation)
8
- // - `DEFAULT_RSDKV4_OPTIONS` — defaults the SDK falls back to.
9
- //
10
- // At runtime these options are serialized into RSDKv4's `settings.ini` (see the
11
- // SDK's settings serializer) when the host does not pass an explicit `settings`
12
- // asset.
13
- export const DEFAULT_RSDKV4_OPTIONS = {
14
- devMenu: false,
15
- engineDebugMode: true,
16
- vsync: true,
17
- startingCategory: 0,
18
- startingScene: 0,
19
- startingPlayer: 0,
1
+ /**
2
+ * What this engine's four payloads accept, and the {@link RSDKV4_SPEC} that describes
3
+ * them to a host.
4
+ *
5
+ * ```ts
6
+ * import type { Rsdkv4Config, Rsdkv4Options } from '@wasm-gaming/rsdkv4-wasm/options';
7
+ * ```
8
+ *
9
+ * The contract's own module documents *how* the four payloads behave — they read as
10
+ * descriptors and write as patches, and `live` says whether a key reaches a running
11
+ * engine. This module is only the part that is RSDKv4's: which keys exist, what they
12
+ * mean here, and what the engine does with them.
13
+ *
14
+ * The split between the first two is the whole design:
15
+ *
16
+ * - {@link Rsdkv4Config} is **the engine**. It is serialized into RSDKv4's
17
+ * `settings.ini` and read once, at boot — so none of it is `live`.
18
+ * - {@link Rsdkv4Options} is **the session**: which character, which save slot, which
19
+ * stage. That is what a `restart()` reopens. It also carries the engine's own GAME
20
+ * OPTIONS rows, which *are* `live` — and which are not declared here at all, because
21
+ * they differ between Sonic 1 and Sonic 2 and are only knowable once the pack is
22
+ * loaded.
23
+ *
24
+ * @module
25
+ */
26
+ /**
27
+ * RSDKv4's fourteen buttons, in the engine's own `InputButtons` order.
28
+ *
29
+ * The order is not cosmetic: it is the bit order of the mask the SDK hands the
30
+ * engine once per tick, so this array is the wire format and not merely a list.
31
+ *
32
+ * Sonic 1 and Sonic 2 read only the four directions, A, B, C and start. The other
33
+ * six exist in the engine and are free for a host to do as it likes with.
34
+ */
35
+ export const RSDKV4_BUTTONS = [
36
+ 'up',
37
+ 'down',
38
+ 'left',
39
+ 'right',
40
+ 'a',
41
+ 'b',
42
+ 'c',
43
+ 'x',
44
+ 'y',
45
+ 'z',
46
+ 'l',
47
+ 'r',
48
+ 'start',
49
+ 'select',
50
+ ];
51
+ /**
52
+ * The engine's own default bindings. See {@link Rsdkv4InputDefaults}.
53
+ *
54
+ * This replaces the old `RSDKV4_KEYMAP`, which nothing read and which was wrong in
55
+ * three ways for want of ever being checked against the engine: it listed 9 of the
56
+ * 14 buttons, and bound `select` to `ShiftLeft` where the engine's default is `Tab`.
57
+ */
58
+ export const RSDKV4_INPUT = {
59
+ keyboard: {
60
+ up: 'ArrowUp',
61
+ down: 'ArrowDown',
62
+ left: 'ArrowLeft',
63
+ right: 'ArrowRight',
64
+ a: 'KeyZ',
65
+ b: 'KeyX',
66
+ c: 'KeyC',
67
+ x: 'KeyA',
68
+ y: 'KeyS',
69
+ z: 'KeyD',
70
+ l: 'KeyQ',
71
+ r: 'KeyE',
72
+ start: 'Enter',
73
+ select: 'Tab',
74
+ },
75
+ gamepad: {
76
+ up: 12,
77
+ down: 13,
78
+ left: 14,
79
+ right: 15,
80
+ a: 0,
81
+ b: 1,
82
+ c: 2,
83
+ x: 3,
84
+ y: 6,
85
+ z: 7,
86
+ l: 4,
87
+ r: 5,
88
+ start: 9,
89
+ select: null,
90
+ },
20
91
  };
21
- export const RSDKV4_OPTIONS_SCHEMA = {
22
- type: 'object',
23
- additionalProperties: false,
24
- properties: {
92
+ /**
93
+ * Everything the engine declares about its own properties, as data.
94
+ *
95
+ * `default` appears here and nowhere else: the contract's base class seeds the
96
+ * starting state from it, so there is no second table of defaults to drift out of
97
+ * agreement with this one — which is exactly what the old
98
+ * `DEFAULT_RSDKV4_OPTIONS`-alongside-a-JSON-Schema pair did.
99
+ *
100
+ * What is missing from `options` is deliberate: `player` and `stage` get their `enum`
101
+ * filled in from the loaded pack, and the GAME OPTIONS rows are added outright, when a
102
+ * running engine is asked to describe itself.
103
+ */
104
+ export const RSDKV4_SPEC = {
105
+ config: {
106
+ vsync: { default: true, live: false, description: 'VSync the engine window.' },
25
107
  devMenu: {
26
- type: 'boolean',
27
108
  default: false,
28
- description: "RSDKv4's native in-canvas Dev Menu. The launcher provides its own overlay via instance.devMenu, so keep this off.",
109
+ live: false,
110
+ description: "RSDKv4's native in-canvas Dev Menu. Hosts draw their own from play.devMenu.",
29
111
  },
30
112
  engineDebugMode: {
31
- type: 'boolean',
32
113
  default: true,
33
- description: 'Enables the web devmenu embind bridge (stage list / warp / pause).',
114
+ live: false,
115
+ description: "Gates the engine's log output. The embind bridges are installed either way.",
116
+ },
117
+ startMenu: {
118
+ default: 'native',
119
+ enum: ['native', 'host'],
120
+ live: false,
121
+ description: "Who draws save/character/options: the engine's own menu, or the host from play.game.",
122
+ },
123
+ jsUrl: { live: false, description: 'Emscripten glue URL. Defaults to ./rsdkv4.js.' },
124
+ wasmUrl: { live: false, description: 'WASM URL. Defaults to ./rsdkv4.wasm.' },
125
+ },
126
+ options: {
127
+ // No `default` on any of the three: absence is what "boot normally" means here,
128
+ // and a default would take that away.
129
+ player: {
130
+ live: false,
131
+ description: 'Character for a new game, by name. Choices arrive once the pack is loaded.',
132
+ },
133
+ slot: {
134
+ enum: [null, 0, 1, 2, 3],
135
+ live: false,
136
+ description: 'Save slot 0-3, or null to play without saving.',
137
+ },
138
+ stage: {
139
+ live: false,
140
+ description: 'Jump straight to a stage. Choices arrive once the pack is loaded.',
141
+ },
142
+ // No `default`, for the same reason as the three above: absence is what "the
143
+ // engine polls SDL as usual" means, and only `null` is a release.
144
+ //
145
+ // `live` because it is the one option that reaches a running engine directly
146
+ // rather than through a restart — and the description says the rest out loud,
147
+ // because the contract has no flag for "transient, do not paint, do not
148
+ // persist" and a host reading descriptors to build a settings screen would
149
+ // otherwise put fourteen booleans on it.
150
+ buttons: {
151
+ live: true,
152
+ description: 'Host-driven input: a live object of 14 booleans the engine reads once per tick, or null to hand input back. Transient — not a settings row, not persistable, and it always reads back as null.',
153
+ },
154
+ },
155
+ assets: {
156
+ data: {
157
+ allowedTypes: ['.rsdk'],
158
+ live: false,
159
+ description: 'The RSDKv4 game data pack. Selects the game; required to start.',
160
+ },
161
+ settings: {
162
+ allowedTypes: ['.ini'],
163
+ live: false,
164
+ description: 'A ready-made settings.ini. Omitted, one is generated from config.',
165
+ },
166
+ },
167
+ storage: {
168
+ namespace: {
169
+ default: 'default',
170
+ live: false,
171
+ description: "Folder for this game's pack, settings and save file.",
172
+ },
173
+ persist: {
174
+ enum: ['opfs', null],
175
+ live: false,
176
+ description: "'opfs' forces persistence, null keeps nothing, absent auto-detects.",
34
177
  },
35
- vsync: { type: 'boolean', default: true },
36
- startingCategory: { type: 'integer', minimum: 0, default: 0 },
37
- startingScene: { type: 'integer', minimum: 0, default: 0 },
38
- startingPlayer: { type: 'integer', minimum: 0, default: 0 },
39
178
  },
40
179
  };
41
180
  //# sourceMappingURL=rsdkv4.options.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rsdkv4.options.js","sourceRoot":"","sources":["../../src/rsdkv4.options.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,+EAA+E;AAC/E,qCAAqC;AACrC,+EAA+E;AAC/E,8EAA8E;AAC9E,6EAA6E;AAC7E,iEAAiE;AACjE,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,SAAS;AAuBT,MAAM,CAAC,MAAM,sBAAsB,GAA4B;IAC7D,OAAO,EAAE,KAAK;IACd,eAAe,EAAE,IAAI;IACrB,KAAK,EAAE,IAAI;IACX,gBAAgB,EAAE,CAAC;IACnB,aAAa,EAAE,CAAC;IAChB,cAAc,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAe;IAC/C,IAAI,EAAE,QAAQ;IACd,oBAAoB,EAAE,KAAK;IAC3B,UAAU,EAAE;QACV,OAAO,EAAE;YACP,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,KAAK;YACd,WAAW,EACT,mHAAmH;SACtH;QACD,eAAe,EAAE;YACf,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,oEAAoE;SAClF;QACD,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE;QACzC,gBAAgB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QAC7D,aAAa,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QAC1D,cAAc,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;KAC5D;CACF,CAAC"}
1
+ {"version":3,"file":"rsdkv4.options.js","sourceRoot":"","sources":["../../src/rsdkv4.options.ts"],"names":[],"mappings":"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"}