@hopple/sdk 0.1.0-rc.3 → 1.0.0-next.12
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/README.md +220 -44
- package/index.d.ts +1093 -879
- package/index.js +2 -29
- package/manifest.d.ts +1107 -0
- package/manifest.js +906 -0
- package/manifest.md +134 -27
- package/package.json +9 -2
- package/config.schema.json +0 -784
package/index.d.ts
CHANGED
|
@@ -1,34 +1,4 @@
|
|
|
1
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
2
|
-
/**
|
|
3
|
-
* The largest value progress will carry.
|
|
4
|
-
*
|
|
5
|
-
* Spelled here *and* in `@hopple/manifest`, on purpose and with a test to keep
|
|
6
|
-
* them equal — the server checks the same rule and is not allowed to depend on
|
|
7
|
-
* this package.
|
|
8
|
-
*
|
|
9
|
-
* @group Achievements
|
|
10
|
-
*/
|
|
11
|
-
declare const ACHIEVEMENT_VALUE_MAX = 9007199254740991;
|
|
12
|
-
/**
|
|
13
|
-
* What the host says came of a report.
|
|
14
|
-
*
|
|
15
|
-
* `earned` is the transition and the only thing worth drawing a banner on: a
|
|
16
|
-
* game that unlocks the same achievement on every level-up gets it once. A host
|
|
17
|
-
* that took the report answers both fields from this player's own history, so
|
|
18
|
-
* unlike a score's rank there is nothing here a host might not know.
|
|
19
|
-
*
|
|
20
|
-
* @group Achievements
|
|
21
|
-
*/
|
|
22
|
-
type AchievementResult = {
|
|
23
|
-
/** Whether it is theirs, after this call. */
|
|
24
|
-
unlocked: boolean;
|
|
25
|
-
/** Whether *this call* is what unlocked it. False for one already held. */
|
|
26
|
-
earned: boolean;
|
|
27
|
-
/** The best value, after this call. Absent for a flagged achievement. */
|
|
28
|
-
progress?: number;
|
|
29
|
-
};
|
|
30
|
-
//#endregion
|
|
31
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-DAYaix/protocol/src/analytics.d.ts
|
|
1
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/protocol/src/analytics.d.ts
|
|
32
2
|
/**
|
|
33
3
|
* What a game says happened.
|
|
34
4
|
*
|
|
@@ -59,166 +29,77 @@ type AnalyticsValue = string | number | boolean;
|
|
|
59
29
|
/** @group Analytics */
|
|
60
30
|
type AnalyticsProps = Record<string, AnalyticsValue>;
|
|
61
31
|
//#endregion
|
|
62
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
63
|
-
/**
|
|
64
|
-
* How loud the game is allowed to be, which is the host's to decide and the
|
|
65
|
-
* game's to obey.
|
|
66
|
-
*
|
|
67
|
-
* **This is the one namespace where the host is not offering a service.** A
|
|
68
|
-
* save, a score, a link and an achievement are all things a game asks for and a
|
|
69
|
-
* host may refuse; audio runs the other way. The host states the volumes, and a
|
|
70
|
-
* game that ignores them is a game that plays music over a phone call, under an
|
|
71
|
-
* advertisement, and in a library. So there is no `unsupported` here and no way
|
|
72
|
-
* to decline: the only thing a game does with this is apply it.
|
|
73
|
-
*
|
|
74
|
-
* **Nothing about sound crosses the bridge.** The samples, the mixing and the
|
|
75
|
-
* decoding all happen in the frame, exactly as presses do — what travels is the
|
|
76
|
-
* three numbers the frame cannot know, because they belong to a player using a
|
|
77
|
-
* host rather than to a game.
|
|
78
|
-
*
|
|
79
|
-
* **The channels are named by the manifest and not described here.** What
|
|
80
|
-
* `music` means is the game's, and the host learned the id and its title from
|
|
81
|
-
* the file it was published with. So the wire carries volumes keyed by id and
|
|
82
|
-
* nothing else, and a host newer than a game — or a game whose next version
|
|
83
|
-
* renamed a channel — produces an id the other side simply has no fader for.
|
|
84
|
-
*/
|
|
32
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/protocol/src/errors.d.ts
|
|
85
33
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* A fraction rather than decibels, because it is what a fader hands over and
|
|
89
|
-
* what a gain node takes, and neither end of this wire is the place to decide
|
|
90
|
-
* on a curve. A host that wants one applies it before it says a number; a game
|
|
91
|
-
* that wants one applies it after. Both are right, and the wire stays a
|
|
92
|
-
* fraction either way.
|
|
34
|
+
* How a call fails.
|
|
93
35
|
*
|
|
94
|
-
*
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
* The channel every host has and no game declares. See `AUDIO_MASTER` in
|
|
99
|
-
* `@hopple/manifest`, which is the same word said where a manifest can be
|
|
100
|
-
* checked against it.
|
|
36
|
+
* Requests reject; nothing throws synchronously once a peer exists. The codes
|
|
37
|
+
* are the stable part — a game built against a newer SDK than the host it lands
|
|
38
|
+
* on must be able to tell why it was refused and degrade, rather than take an
|
|
39
|
+
* unhandled rejection into the player's face.
|
|
101
40
|
*
|
|
102
|
-
*
|
|
41
|
+
* Codes are added as something starts producing them, never in advance: a code
|
|
42
|
+
* nothing can emit tells a game to handle a case that cannot happen. Adding one
|
|
43
|
+
* is additive and safe.
|
|
103
44
|
*/
|
|
104
|
-
declare const AUDIO_MASTER = "master";
|
|
105
45
|
/**
|
|
106
|
-
*
|
|
46
|
+
* The codes a call fails with, as the keys of this interface.
|
|
107
47
|
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* that stored it as one would hand the player back silence.
|
|
48
|
+
* An interface rather than a union so that a preview can add the codes only
|
|
49
|
+
* its calls fail with, as it adds its own namespace to the SDK: a game is
|
|
50
|
+
* named the codes of what it uses.
|
|
112
51
|
*
|
|
113
|
-
*
|
|
114
|
-
* `layout.change` carries the whole layout: these are small, they arrive
|
|
115
|
-
* rarely, and a game that missed one — because it was loading, because a host
|
|
116
|
-
* coalesced two — must not end up mixing from halves.
|
|
117
|
-
*
|
|
118
|
-
* @group Audio
|
|
52
|
+
* @group Bridge
|
|
119
53
|
*/
|
|
120
|
-
|
|
54
|
+
interface ErrorCodes {
|
|
55
|
+
/** No handler on the other side. Usually means the host predates the method. */
|
|
56
|
+
unknown_method: true;
|
|
57
|
+
/** The handler rejected the shape of `params`. */
|
|
58
|
+
bad_params: true;
|
|
59
|
+
/** No reply inside the peer's timeout. Says nothing about whether it ran. */
|
|
60
|
+
timeout: true;
|
|
61
|
+
/** The peer was torn down with the call still in flight — a recycled slot. */
|
|
62
|
+
disposed: true;
|
|
121
63
|
/**
|
|
122
|
-
*
|
|
64
|
+
* The call belonged to a session that has ended: the game started over inside
|
|
65
|
+
* a frame the host still holds. Distinct from `disposed` because the bridge is
|
|
66
|
+
* alive and the next call will work — it is this one that has nobody left to
|
|
67
|
+
* answer it.
|
|
68
|
+
*/
|
|
69
|
+
stale: true;
|
|
70
|
+
/** The handshake asked for a protocol version this side cannot speak. */
|
|
71
|
+
unsupported_version: true;
|
|
72
|
+
/**
|
|
73
|
+
* This host does not do that at all — a site with no store answering
|
|
74
|
+
* `save.write`.
|
|
123
75
|
*
|
|
124
|
-
*
|
|
125
|
-
* the
|
|
126
|
-
*
|
|
76
|
+
* A different fact from `unknown_method`, which says the host is *older* than
|
|
77
|
+
* the method, and a game acts on the difference: one is a host that will
|
|
78
|
+
* never save and one is a host that would if it were newer. Neither is worth
|
|
79
|
+
* retrying, and both are worth saying honestly.
|
|
127
80
|
*/
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
|
|
81
|
+
unsupported: true;
|
|
82
|
+
/** Over this host's cap. Says trim, rather than go looking for a bug. */
|
|
83
|
+
too_large: true;
|
|
131
84
|
/**
|
|
132
|
-
*
|
|
85
|
+
* Faster than this host will take. The counterpart of the analytics refusal.
|
|
133
86
|
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
87
|
+
* Never what a host that *coalesced* two writes says: a write superseded by
|
|
88
|
+
* newer state from the same game has not been lost, and both promises
|
|
89
|
+
* resolve. This is for a host actually dropping writes, which usually means a
|
|
90
|
+
* game is saving from a render loop by mistake.
|
|
138
91
|
*/
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
* for it on every host that has one.
|
|
149
|
-
*
|
|
150
|
-
* @group Audio
|
|
151
|
-
*/
|
|
152
|
-
declare const AUDIO_FULL: AudioState;
|
|
153
|
-
/**
|
|
154
|
-
* How loud one channel actually comes out, which is the only number a game
|
|
155
|
-
* needs and the one both sides must agree on.
|
|
156
|
-
*
|
|
157
|
-
* Here rather than in the game's SDK because the dev shell draws it too — a
|
|
158
|
-
* developer reading *music: 0.35* off a panel and hearing something else has no
|
|
159
|
-
* way to tell which half is wrong. Multiplication and not the smaller of the
|
|
160
|
-
* two: a master fader is a fader over the mix, so halving it halves everything
|
|
161
|
-
* under it rather than capping the loudest.
|
|
162
|
-
*
|
|
163
|
-
* @group Audio
|
|
164
|
-
*/
|
|
165
|
-
declare function audioVolumeOf(state: AudioState, channel?: string): number;
|
|
166
|
-
//#endregion
|
|
167
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-DAYaix/protocol/src/errors.d.ts
|
|
168
|
-
/**
|
|
169
|
-
* How a call fails.
|
|
170
|
-
*
|
|
171
|
-
* Requests reject; nothing throws synchronously once a peer exists. The codes
|
|
172
|
-
* are the stable part — a game built against a newer SDK than the host it lands
|
|
173
|
-
* on must be able to tell why it was refused and degrade, rather than take an
|
|
174
|
-
* unhandled rejection into the player's face.
|
|
175
|
-
*
|
|
176
|
-
* Codes are added as something starts producing them, never in advance: a code
|
|
177
|
-
* nothing can emit tells a game to handle a case that cannot happen. Adding one
|
|
178
|
-
* is additive and safe.
|
|
179
|
-
*/
|
|
92
|
+
rate_limited: true;
|
|
93
|
+
/**
|
|
94
|
+
* Not now: what it needs can't be reached for the moment. Worth trying
|
|
95
|
+
* again shortly.
|
|
96
|
+
*/
|
|
97
|
+
unavailable: true;
|
|
98
|
+
/** The handler threw. The message is ours, never the thrown value's. */
|
|
99
|
+
internal: true;
|
|
100
|
+
}
|
|
180
101
|
/** @group Bridge */
|
|
181
|
-
type ErrorCode =
|
|
182
|
-
/** No handler on the other side. Usually means the host predates the method. */
|
|
183
|
-
'unknown_method' |
|
|
184
|
-
/** The handler rejected the shape of `params`. */
|
|
185
|
-
'bad_params' |
|
|
186
|
-
/** No reply inside the peer's timeout. Says nothing about whether it ran. */
|
|
187
|
-
'timeout' |
|
|
188
|
-
/** The peer was torn down with the call still in flight — a recycled slot. */
|
|
189
|
-
'disposed' |
|
|
190
|
-
/**
|
|
191
|
-
* The call belonged to a session that has ended: the game started over inside
|
|
192
|
-
* a frame the host still holds. Distinct from `disposed` because the bridge is
|
|
193
|
-
* alive and the next call will work — it is this one that has nobody left to
|
|
194
|
-
* answer it.
|
|
195
|
-
*/
|
|
196
|
-
'stale' |
|
|
197
|
-
/** The handshake asked for a protocol version this side cannot speak. */
|
|
198
|
-
'unsupported_version' |
|
|
199
|
-
/**
|
|
200
|
-
* This host does not do that at all — a site with no store answering
|
|
201
|
-
* `save.write`.
|
|
202
|
-
*
|
|
203
|
-
* A different fact from `unknown_method`, which says the host is *older* than
|
|
204
|
-
* the method, and a game acts on the difference: one is a host that will
|
|
205
|
-
* never save and one is a host that would if it were newer. Neither is worth
|
|
206
|
-
* retrying, and both are worth saying honestly.
|
|
207
|
-
*/
|
|
208
|
-
'unsupported' |
|
|
209
|
-
/** Over this host's cap. Says trim, rather than go looking for a bug. */
|
|
210
|
-
'too_large' |
|
|
211
|
-
/**
|
|
212
|
-
* Faster than this host will take. The counterpart of the analytics refusal.
|
|
213
|
-
*
|
|
214
|
-
* Never what a host that *coalesced* two writes says: a write superseded by
|
|
215
|
-
* newer state from the same game has not been lost, and both promises
|
|
216
|
-
* resolve. This is for a host actually dropping writes, which usually means a
|
|
217
|
-
* game is saving from a render loop by mistake.
|
|
218
|
-
*/
|
|
219
|
-
'rate_limited' |
|
|
220
|
-
/** The handler threw. The message is ours, never the thrown value's. */
|
|
221
|
-
'internal';
|
|
102
|
+
type ErrorCode = keyof ErrorCodes;
|
|
222
103
|
/** @group Bridge */
|
|
223
104
|
type ProtocolError = {
|
|
224
105
|
code: ErrorCode;
|
|
@@ -234,48 +115,7 @@ declare class BridgeError extends Error {
|
|
|
234
115
|
constructor(error: ProtocolError);
|
|
235
116
|
}
|
|
236
117
|
//#endregion
|
|
237
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
238
|
-
/**
|
|
239
|
-
* `p` is the protocol version, carried on every message rather than only at the
|
|
240
|
-
* handshake, because a message that arrives without context still has to be
|
|
241
|
-
* classifiable.
|
|
242
|
-
*
|
|
243
|
-
* There is deliberately no addressing. A bridge joins exactly one host to
|
|
244
|
-
* exactly one game: the game lives alone in its frame and has no way to name
|
|
245
|
-
* another game, and the host holds one frame and needs no way to name another.
|
|
246
|
-
* A host that runs several games at once — the app, the production site — runs
|
|
247
|
-
* several bridges, each with its own transport, and keeping their inboxes apart
|
|
248
|
-
* is that host's problem with its own frames. Putting a channel in the envelope
|
|
249
|
-
* would make every transport pay for a problem only one kind of host has.
|
|
250
|
-
*
|
|
251
|
-
* @group Bridge
|
|
252
|
-
*/
|
|
253
|
-
type Envelope = {
|
|
254
|
-
p: 1;
|
|
255
|
-
kind: 'req';
|
|
256
|
-
id: string;
|
|
257
|
-
method: string;
|
|
258
|
-
params: unknown;
|
|
259
|
-
} | {
|
|
260
|
-
p: 1;
|
|
261
|
-
kind: 'res';
|
|
262
|
-
id: string;
|
|
263
|
-
ok: true;
|
|
264
|
-
value: unknown;
|
|
265
|
-
} | {
|
|
266
|
-
p: 1;
|
|
267
|
-
kind: 'res';
|
|
268
|
-
id: string;
|
|
269
|
-
ok: false;
|
|
270
|
-
error: ProtocolError;
|
|
271
|
-
} | {
|
|
272
|
-
p: 1;
|
|
273
|
-
kind: 'evt';
|
|
274
|
-
topic: string;
|
|
275
|
-
data: unknown;
|
|
276
|
-
};
|
|
277
|
-
//#endregion
|
|
278
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-DAYaix/protocol/src/input.d.ts
|
|
118
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/protocol/src/input.d.ts
|
|
279
119
|
/**
|
|
280
120
|
* What the host says about how this game is being played.
|
|
281
121
|
*
|
|
@@ -312,8 +152,6 @@ type Envelope = {
|
|
|
312
152
|
* @group Input
|
|
313
153
|
*/
|
|
314
154
|
type InputScheme = 'keyboard' | 'mouse' | 'touch' | 'gamepad';
|
|
315
|
-
/** @group Input */
|
|
316
|
-
declare const INPUT_SCHEMES: readonly InputScheme[];
|
|
317
155
|
/**
|
|
318
156
|
* What presses one action, and what to call it in front of a player.
|
|
319
157
|
*
|
|
@@ -336,87 +174,8 @@ type InputBinding = {
|
|
|
336
174
|
/** What to show for the binding a player would actually use. See above. */
|
|
337
175
|
label?: string;
|
|
338
176
|
};
|
|
339
|
-
/**
|
|
340
|
-
* How a group of on-screen buttons is arranged. See `ControlShape` in
|
|
341
|
-
* `@hopple/manifest`, which a test keeps this in step with.
|
|
342
|
-
*
|
|
343
|
-
* @group Input
|
|
344
|
-
*/
|
|
345
|
-
type InputLayoutShape = 'row' | 'column' | 'diamond' | 'cluster';
|
|
346
|
-
/**
|
|
347
|
-
* Where on the screen a group of on-screen controls sits. See `ControlZone` in
|
|
348
|
-
* `@hopple/manifest`.
|
|
349
|
-
*
|
|
350
|
-
* @group Input
|
|
351
|
-
*/
|
|
352
|
-
type InputLayoutZone = 'left' | 'right' | 'full';
|
|
353
|
-
/**
|
|
354
|
-
* The one direction an on-screen thumbstick moves in. See `ControlAxis` in
|
|
355
|
-
* `@hopple/manifest`.
|
|
356
|
-
*
|
|
357
|
-
* @group Input
|
|
358
|
-
*/
|
|
359
|
-
type InputLayoutAxis = 'x' | 'y';
|
|
360
|
-
/**
|
|
361
|
-
* How an on-screen thumbstick meets a thumb: a player's setting, the same in
|
|
362
|
-
* every game they open.
|
|
363
|
-
*
|
|
364
|
-
* `floating` is marked where the layout puts it, as a sign that there is a
|
|
365
|
-
* stick, and comes to wherever a thumb lands on its side of the screen — so a
|
|
366
|
-
* player never has to find it, and the place they first touch is always the
|
|
367
|
-
* centre. A thumb that goes past its rim pulls it along, so turning back is
|
|
368
|
-
* never further than the stick is wide. `fixed` stays where it is drawn and is
|
|
369
|
-
* moved only from there.
|
|
370
|
-
*
|
|
371
|
-
* @group Input
|
|
372
|
-
*/
|
|
373
|
-
type InputSticks = 'floating' | 'fixed';
|
|
374
|
-
/**
|
|
375
|
-
* Why the mapping or the scheme is different from what the game was told before.
|
|
376
|
-
*
|
|
377
|
-
* @group Input
|
|
378
|
-
*/
|
|
379
|
-
type InputChangeCause =
|
|
380
|
-
/** A player changed a binding. */
|
|
381
|
-
'remap' |
|
|
382
|
-
/** They picked up a controller, or put one down. */
|
|
383
|
-
'scheme' |
|
|
384
|
-
/** The host revised it for its own reasons. */
|
|
385
|
-
'host' |
|
|
386
|
-
/** A player changed how the on-screen controls behave. */
|
|
387
|
-
'setting';
|
|
388
|
-
//#endregion
|
|
389
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-DAYaix/protocol/src/panel.d.ts
|
|
390
|
-
/**
|
|
391
|
-
* The pages of the panel this version of the protocol has a name for.
|
|
392
|
-
*
|
|
393
|
-
* **A vocabulary, not a capability.** Every one of these is a subject both ends
|
|
394
|
-
* already have words for elsewhere — a game's own description, its boards, its
|
|
395
|
-
* achievements, its bindings — so the names are the ones the hosts already use
|
|
396
|
-
* for the pages they draw, and a game author who reads "About" in the panel
|
|
397
|
-
* finds `about` here.
|
|
398
|
-
*
|
|
399
|
-
* It grows, and it only ever grows: a name means the same thing for ever,
|
|
400
|
-
* because a game ships and is never updated. A host older than a name answers
|
|
401
|
-
* `unsupported`, which is the same thing it says about a page it simply does
|
|
402
|
-
* not draw — and the right answer to both, because from the game's side they
|
|
403
|
-
* are one fact: that page is not going to open here.
|
|
404
|
-
*
|
|
405
|
-
* @group Panels
|
|
406
|
-
*/
|
|
407
|
-
type PageId =
|
|
408
|
-
/** What this game is: its title, its author, its description. */
|
|
409
|
-
'about' |
|
|
410
|
-
/** Who has scored what, on this game's boards. */
|
|
411
|
-
'scores' |
|
|
412
|
-
/** What has been unlocked, and how far along the rest is. */
|
|
413
|
-
'achievements' |
|
|
414
|
-
/** What this game is played with, and where a player rebinds it. */
|
|
415
|
-
'input';
|
|
416
|
-
/** @group Panels */
|
|
417
|
-
declare const PAGES: readonly PageId[];
|
|
418
177
|
//#endregion
|
|
419
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
178
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/protocol/src/pause.d.ts
|
|
420
179
|
/**
|
|
421
180
|
* Whether the game is holding still, which the host may ask for and only the
|
|
422
181
|
* game can answer.
|
|
@@ -473,23 +232,8 @@ type PauseState =
|
|
|
473
232
|
* that pressing it would do something.
|
|
474
233
|
*/
|
|
475
234
|
'unpausable';
|
|
476
|
-
/** @group Pause */
|
|
477
|
-
declare const PAUSE_STATES: readonly PauseState[];
|
|
478
|
-
/**
|
|
479
|
-
* The cautious reading, and the one every silence falls back to: a game that
|
|
480
|
-
* has said nothing cannot be paused.
|
|
481
|
-
*
|
|
482
|
-
* The opposite of the reading `AUDIO_FULL` takes, and for the same reason —
|
|
483
|
-
* both are the answer that claims the least. Guessing loud is safe for volume
|
|
484
|
-
* because a game that started silent would look broken; guessing `unpausable`
|
|
485
|
-
* is safe here because a host that drew Pause on a game with no pause would
|
|
486
|
-
* have promised a button that does nothing.
|
|
487
|
-
*
|
|
488
|
-
* @group Pause
|
|
489
|
-
*/
|
|
490
|
-
declare const PAUSE_NONE: PauseState;
|
|
491
235
|
//#endregion
|
|
492
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
236
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/protocol/src/save.d.ts
|
|
493
237
|
/**
|
|
494
238
|
* The one thing a game may keep.
|
|
495
239
|
*
|
|
@@ -511,7 +255,8 @@ declare const PAUSE_NONE: PauseState;
|
|
|
511
255
|
* game may assume anywhere, forever, because a game ships and is never updated.
|
|
512
256
|
*/
|
|
513
257
|
/**
|
|
514
|
-
* What a game may write anywhere, in bytes of `state` as UTF-8
|
|
258
|
+
* What a game may write anywhere, in bytes: of `state` as UTF-8, or of the
|
|
259
|
+
* bytes a game handed over where it handed bytes.
|
|
515
260
|
*
|
|
516
261
|
* The floor rather than the cap: a host that will take more says so in the
|
|
517
262
|
* welcome, and a game that never asks still knows this much is safe. 64 KiB is
|
|
@@ -540,45 +285,7 @@ type SaveStored = {
|
|
|
540
285
|
bytes: number;
|
|
541
286
|
};
|
|
542
287
|
//#endregion
|
|
543
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
544
|
-
/**
|
|
545
|
-
* What a player did, as one number.
|
|
546
|
-
*
|
|
547
|
-
* A game submits a score when a run ends; the host makes it durable and, if it
|
|
548
|
-
* has anywhere to send it, sends it. What comes back is what the player is
|
|
549
|
-
* shown: their own best, and where it stands.
|
|
550
|
-
*
|
|
551
|
-
* **The shape of this is not the shape of a save, and not the shape of
|
|
552
|
-
* analytics.** A save is one document rewritten in place, and losing one costs
|
|
553
|
-
* a player their progress. A score is an append — every run is its own fact, a
|
|
554
|
-
* later worse run does not erase a better one, and the collapsing into "your
|
|
555
|
-
* best" happens where the rows are rather than on the way in. Analytics is
|
|
556
|
-
* one-way because nothing waits for it; a score is a request because a game
|
|
557
|
-
* draws the answer.
|
|
558
|
-
*
|
|
559
|
-
* **The submission carries no player.** The game says which board and what
|
|
560
|
-
* number, and the host attaches who — which is the host being authoritative
|
|
561
|
-
* about the one fact a game must not be able to assert. It also means a game
|
|
562
|
-
* literally cannot submit on somebody else's behalf, which is free here and
|
|
563
|
-
* would be expensive to retrofit.
|
|
564
|
-
*
|
|
565
|
-
* **There is no anti-cheat and this file does not pretend otherwise.** A score
|
|
566
|
-
* is whatever the machine running the game says it is. What is checked is that
|
|
567
|
-
* the number is a number: finite, and inside the range where an integer still
|
|
568
|
-
* round-trips. The realistic thing that catches is an uninitialised variable.
|
|
569
|
-
*/
|
|
570
|
-
/**
|
|
571
|
-
* The largest score the wire will carry, and the smallest.
|
|
572
|
-
*
|
|
573
|
-
* Spelled here *and* in `@hopple/manifest`, on purpose and with a test to keep
|
|
574
|
-
* them equal. The server checks the same rule and is not allowed to depend on
|
|
575
|
-
* this package — "the server never talks to a game", made mechanical — so the
|
|
576
|
-
* rule is written down in the one package both sides may import and enforced on
|
|
577
|
-
* the wire here.
|
|
578
|
-
*
|
|
579
|
-
* @group Score
|
|
580
|
-
*/
|
|
581
|
-
declare const SCORE_VALUE_MAX = 9007199254740991;
|
|
288
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/protocol/src/score.d.ts
|
|
582
289
|
/**
|
|
583
290
|
* What the host says came of it.
|
|
584
291
|
*
|
|
@@ -616,7 +323,7 @@ type ScoreStanding = {
|
|
|
616
323
|
of?: number;
|
|
617
324
|
};
|
|
618
325
|
//#endregion
|
|
619
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
326
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/protocol/src/share.d.ts
|
|
620
327
|
/**
|
|
621
328
|
* A link to this game, offered to the player by the host.
|
|
622
329
|
*
|
|
@@ -670,7 +377,8 @@ type ScoreStanding = {
|
|
|
670
377
|
* its first frame. See `ShareWelcome`.
|
|
671
378
|
*/
|
|
672
379
|
/**
|
|
673
|
-
* What every host carries, in bytes of `data
|
|
380
|
+
* What every host carries, in bytes of `data`: as UTF-8, or the bytes a game
|
|
381
|
+
* handed over where it handed bytes.
|
|
674
382
|
*
|
|
675
383
|
* The floor rather than the cap: a host may take more and none may take less,
|
|
676
384
|
* so a game that stays under this is never refused for its size anywhere. It is
|
|
@@ -715,7 +423,7 @@ type ShareMeta = {
|
|
|
715
423
|
[key: string]: ShareMetaValue;
|
|
716
424
|
};
|
|
717
425
|
//#endregion
|
|
718
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
426
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/protocol/src/methods.d.ts
|
|
719
427
|
/**
|
|
720
428
|
* How far a game has got with its own preparation.
|
|
721
429
|
*
|
|
@@ -895,7 +603,7 @@ type DeviceInfo = {
|
|
|
895
603
|
tier: DeviceTier;
|
|
896
604
|
};
|
|
897
605
|
//#endregion
|
|
898
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
606
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/protocol/src/listeners.d.ts
|
|
899
607
|
/**
|
|
900
608
|
* The one way anything here is listened to: `on(listener)` hands back the
|
|
901
609
|
* function that stops it.
|
|
@@ -924,152 +632,17 @@ type DeviceInfo = {
|
|
|
924
632
|
*/
|
|
925
633
|
type Unsubscribe = () => void;
|
|
926
634
|
//#endregion
|
|
927
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
928
|
-
/** @group Bridge */
|
|
929
|
-
type Transport = {
|
|
930
|
-
send(message: Envelope): void;
|
|
931
|
-
/** Returns the unsubscribe. Calling `receive` twice is not defined behaviour. */
|
|
932
|
-
receive(handler: (message: Envelope) => void): () => void;
|
|
933
|
-
close(): void;
|
|
934
|
-
};
|
|
935
|
-
/**
|
|
936
|
-
* The name a platform leaves its shim under, and the name it calls if it is late.
|
|
937
|
-
*
|
|
938
|
-
* Declared here, in the package both ends import, so that a platform author and
|
|
939
|
-
* the SDK are reading the same two strings. Nothing in this package writes
|
|
940
|
-
* either of them: the shim is wholly the platform's, and this file is a target
|
|
941
|
-
* to hit rather than code we ship.
|
|
942
|
-
*
|
|
943
|
-
* @group Bridge
|
|
944
|
-
*/
|
|
945
|
-
declare const SHIM = "__HOPPLE_SHIM__";
|
|
946
|
-
/** @group Bridge */
|
|
947
|
-
declare const SET_SHIM = "__HOPPLE_SET_SHIM__";
|
|
948
|
-
/**
|
|
949
|
-
* What a native shell leaves for a game to talk through.
|
|
950
|
-
*
|
|
951
|
-
* A game in a browser frame has `window.parent` and needs none of this. A game
|
|
952
|
-
* in a WebView is a top-level document — its `parent` is itself — so there is no
|
|
953
|
-
* window above it to post to, and the platform has to hand it a channel instead.
|
|
954
|
-
* This is that channel, reduced to the least a platform can be asked for.
|
|
955
|
-
*
|
|
956
|
-
* **The SDK writes none of it.** It agrees on a name and a shape and finds
|
|
957
|
-
* whatever was left; how the bytes actually cross is the platform's business,
|
|
958
|
-
* and is different on every one. That is what keeps this package free of hosts
|
|
959
|
-
* it has never heard of.
|
|
960
|
-
*
|
|
961
|
-
* A shim has exactly two duties:
|
|
962
|
-
*
|
|
963
|
-
* - **Arrive.** Before the game's bundle runs is easiest, and is what our own
|
|
964
|
-
* hosts do — a document-start hook, `injectedJavaScriptBeforeContentLoaded`,
|
|
965
|
-
* a `WKUserScript` at `.atDocumentStart`. A platform that cannot manage that
|
|
966
|
-
* is late rather than broken: see the rendezvous below.
|
|
967
|
-
* - **Never throw.** A shim that throws breaks a game that did nothing wrong.
|
|
968
|
-
*
|
|
969
|
-
* And one duty it explicitly does *not* have: **it must not buffer.** Nothing
|
|
970
|
-
* arrives before the game is listening, because every host → game message is
|
|
971
|
-
* gated on the handshake and the game is the side that opens it. An array in
|
|
972
|
-
* every shim would be paying, on every platform, for a message that is never
|
|
973
|
-
* sent.
|
|
974
|
-
*
|
|
975
|
-
* **Two ways in, and a platform may use either**, because neither side may
|
|
976
|
-
* assume it is first:
|
|
977
|
-
*
|
|
978
|
-
* ```js
|
|
979
|
-
* // The whole of what a platform has to get right about ordering.
|
|
980
|
-
* if (w.__HOPPLE_SET_SHIM__) w.__HOPPLE_SET_SHIM__(shim);
|
|
981
|
-
* else w.__HOPPLE_SHIM__ = shim;
|
|
982
|
-
* ```
|
|
983
|
-
*
|
|
984
|
-
* A platform that installs early always takes the second branch; one that
|
|
985
|
-
* cannot takes the first, and the SDK — which has been waiting — connects. The
|
|
986
|
-
* setter only exists while the SDK is waiting, and is removed once it is used
|
|
987
|
-
* or the wait expires.
|
|
988
|
-
*
|
|
989
|
-
* **Strings, not envelopes.** Every native bridge carries strings, so that is
|
|
990
|
-
* the contract, and it means the SDK stays the trust boundary: `JSON.parse` and
|
|
991
|
-
* `isEnvelope` run in SDK code on both sides of the wire and never in a
|
|
992
|
-
* platform's. A shim cannot get validation wrong, because it does none.
|
|
993
|
-
*
|
|
994
|
-
* @group Bridge
|
|
995
|
-
*/
|
|
996
|
-
type HoppleShim = {
|
|
997
|
-
/**
|
|
998
|
-
* The contract version. `1` today.
|
|
999
|
-
*
|
|
1000
|
-
* A shim whose version the SDK does not know is ignored rather than guessed
|
|
1001
|
-
* at — which falls through to the frame branch, and then to the wait.
|
|
1002
|
-
*/
|
|
1003
|
-
v: 1;
|
|
1004
|
-
/** Send one already-serialised envelope to the host. Game → host. */
|
|
1005
|
-
send(message: string): void;
|
|
1006
|
-
/**
|
|
1007
|
-
* Take the SDK's inbound handler, and hand back the unsubscribe.
|
|
1008
|
-
*
|
|
1009
|
-
* Called once, by the SDK, and it is a subscription rather than a delivery:
|
|
1010
|
-
* how the platform later reaches the handler it was given — an eval into a
|
|
1011
|
-
* global, a real message channel — is the platform's problem and is not
|
|
1012
|
-
* described here.
|
|
1013
|
-
*/
|
|
1014
|
-
receive(handler: (message: string) => void): () => void;
|
|
1015
|
-
};
|
|
1016
|
-
/**
|
|
1017
|
-
* The two globals, so a platform's own TypeScript sees the same shape the SDK
|
|
1018
|
-
* reads. Neither is ever written by this package.
|
|
1019
|
-
*/
|
|
1020
|
-
declare global {
|
|
1021
|
-
var __HOPPLE_SHIM__: HoppleShim | undefined;
|
|
1022
|
-
var __HOPPLE_SET_SHIM__: ((shim: HoppleShim) => void) | undefined;
|
|
1023
|
-
}
|
|
1024
|
-
//#endregion
|
|
1025
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-DAYaix/manifest/src/manifest.d.ts
|
|
1026
|
-
/**
|
|
1027
|
-
* What a game says about itself.
|
|
1028
|
-
*
|
|
1029
|
-
* Written in the project's hopple config and uploaded beside the game's page
|
|
1030
|
-
* as `game.manifest.json`. It is the first thing the host learns: it is
|
|
1031
|
-
* published with the game, so a host holds it before it has anything to run —
|
|
1032
|
-
* from the server in the app, from the project in the dev server. It never
|
|
1033
|
-
* travels over the bridge. Not to be confused with `FeedEntry`, which is
|
|
1034
|
-
* what the *catalogue* says about a game.
|
|
1035
|
-
*
|
|
1036
|
-
* The core is deliberately tiny: identity, a name, and how the game wants to
|
|
1037
|
-
* be held. Everything a later API needs declared ahead of time
|
|
1038
|
-
* gets its own optional top-level key named after that API — `save`,
|
|
1039
|
-
* `achievements`, and so on — whose contents are designed by the milestone that
|
|
1040
|
-
* builds it. Most namespaces will never need one.
|
|
1041
|
-
*
|
|
1042
|
-
* **The types below are the only place a rule is written.** Their shapes and
|
|
1043
|
-
* the constraint tags in their comments — `@maxLength`, `@pattern` and the rest
|
|
1044
|
-
* — are compiled into `game.manifest.schema.json`, and `validateManifest` checks
|
|
1045
|
-
* a manifest by walking that schema. Change a type and the schema, the
|
|
1046
|
-
* validator and every editor that reads the schema follow. The only rules
|
|
1047
|
-
* written in code are the few no schema can state, and they are at the bottom
|
|
1048
|
-
* of this file.
|
|
1049
|
-
*
|
|
1050
|
-
* Validation lives here rather than in the host so that the publish CLI, the
|
|
1051
|
-
* dev server and the host all reach the same verdict about the same file.
|
|
1052
|
-
*
|
|
1053
|
-
* @module manifest
|
|
1054
|
-
*/
|
|
635
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/manifest/src/manifest.d.ts
|
|
1055
636
|
/**
|
|
1056
|
-
* The
|
|
637
|
+
* The API a game is written against: `M.m`, a major and the least minor it
|
|
638
|
+
* needs, or `next`, the pre-releases of the next stable release.
|
|
1057
639
|
*
|
|
1058
640
|
* @group Manifest
|
|
1059
|
-
* @category
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
/**
|
|
1063
|
-
* The manifest's own version, separate from the protocol's.
|
|
1064
|
-
*
|
|
1065
|
-
* Bumped only if the *core* changes meaning, which is a thing we intend never
|
|
1066
|
-
* to do — new keys are additive and need no bump. A host refuses a schema it
|
|
1067
|
-
* does not know, because a manifest it half-understands is worse than none.
|
|
1068
|
-
*
|
|
1069
|
-
* @group Manifest
|
|
1070
|
-
* @category Useful
|
|
641
|
+
* @category Important
|
|
642
|
+
* @pattern ^(?:(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)|next)$
|
|
643
|
+
* @errorMessage must be the API the game is written against, like "1.0", or "next"
|
|
1071
644
|
*/
|
|
1072
|
-
|
|
645
|
+
type ApiVersion = string;
|
|
1073
646
|
/**
|
|
1074
647
|
* How the game wants to be held. The host decides what to do about it.
|
|
1075
648
|
*
|
|
@@ -1100,7 +673,6 @@ type InsetMode =
|
|
|
1100
673
|
*/
|
|
1101
674
|
type LayoutDeclaration = {
|
|
1102
675
|
insets: InsetMode;
|
|
1103
|
-
[key: string]: unknown;
|
|
1104
676
|
};
|
|
1105
677
|
/**
|
|
1106
678
|
* What a prop may hold, as one word. The three the wire carries, and no more.
|
|
@@ -1152,7 +724,6 @@ type AnalyticsDeclaration = {
|
|
|
1152
724
|
* @propertyNames { pattern: '^[a-z0-9]+(?:[._-][a-z0-9]+)*$', maxLength: 48, not: { pattern: '^hopple\\.' }, errorMessage: 'must be lowercase letters, digits, dots, hyphens and underscores, and must not start with "hopple.", which the host uses' }
|
|
1153
725
|
*/
|
|
1154
726
|
events: Record<string, AnalyticsShape>;
|
|
1155
|
-
[key: string]: unknown;
|
|
1156
727
|
};
|
|
1157
728
|
/**
|
|
1158
729
|
* What a game expects to keep, in bytes.
|
|
@@ -1182,7 +753,6 @@ type SaveDeclaration = {
|
|
|
1182
753
|
* @maximum 1048576
|
|
1183
754
|
*/
|
|
1184
755
|
bytes: number;
|
|
1185
|
-
[key: string]: unknown;
|
|
1186
756
|
};
|
|
1187
757
|
/**
|
|
1188
758
|
* One thing a game makes noise with, as the player is offered it.
|
|
@@ -1204,7 +774,6 @@ type AudioChannel = {
|
|
|
1204
774
|
* @errorMessage must not be blank
|
|
1205
775
|
*/
|
|
1206
776
|
title: string;
|
|
1207
|
-
[key: string]: unknown;
|
|
1208
777
|
};
|
|
1209
778
|
/**
|
|
1210
779
|
* What this game makes noise with, so a host can offer a fader for each.
|
|
@@ -1245,7 +814,6 @@ type AudioDeclaration = {
|
|
|
1245
814
|
* @propertyNames { pattern: '^[a-z0-9]+(?:[._-][a-z0-9]+)*$', maxLength: 48, not: { const: 'master' }, errorMessage: 'must be lowercase letters, digits, dots, hyphens and underscores, and must not be "master", which every host adds itself' }
|
|
1246
815
|
*/
|
|
1247
816
|
channels?: Record<string, AudioChannel>;
|
|
1248
|
-
[key: string]: unknown;
|
|
1249
817
|
};
|
|
1250
818
|
/**
|
|
1251
819
|
* Which way a board sorts — the one thing about a score that cannot be guessed.
|
|
@@ -1283,7 +851,26 @@ type ScoreBoard = {
|
|
|
1283
851
|
direction: ScoreDirection;
|
|
1284
852
|
/** See `ScoreFormat`. Absent means `integer`. */
|
|
1285
853
|
format?: ScoreFormat;
|
|
1286
|
-
|
|
854
|
+
/**
|
|
855
|
+
* Which board, of the ones this id has named. Absent is `1`.
|
|
856
|
+
*
|
|
857
|
+
* **Raising it starts the board again from nobody.** The runs under the
|
|
858
|
+
* version before are kept and no longer counted, shown or ranked, so a board
|
|
859
|
+
* whose scores stopped being comparable — new levels, a new rule — begins
|
|
860
|
+
* again under the id the game already submits to.
|
|
861
|
+
*
|
|
862
|
+
* **Only a change to what a stored score means needs it.** The title changes
|
|
863
|
+
* freely, and so does the format between `integer` and `decimal`. Once the
|
|
864
|
+
* board holds scores, turning it around (`direction`) or writing it in
|
|
865
|
+
* another unit (to or from `duration-ms`) is refused at the same version.
|
|
866
|
+
* Going back to a version declared before brings its runs back, so it is
|
|
867
|
+
* held to what that version was.
|
|
868
|
+
*
|
|
869
|
+
* @asType integer
|
|
870
|
+
* @minimum 1
|
|
871
|
+
* @maximum 1000
|
|
872
|
+
*/
|
|
873
|
+
version?: number;
|
|
1287
874
|
};
|
|
1288
875
|
/**
|
|
1289
876
|
* The boards this game keeps a score on.
|
|
@@ -1314,7 +901,6 @@ type ScoreDeclaration = {
|
|
|
1314
901
|
* @propertyNames { pattern: '^[a-z0-9]+(?:[._-][a-z0-9]+)*$', maxLength: 48, errorMessage: 'must be lowercase letters, digits, dots, hyphens and underscores' }
|
|
1315
902
|
*/
|
|
1316
903
|
boards: Record<string, ScoreBoard>;
|
|
1317
|
-
[key: string]: unknown;
|
|
1318
904
|
};
|
|
1319
905
|
/**
|
|
1320
906
|
* One named step on the way to a measured achievement's target.
|
|
@@ -1353,7 +939,6 @@ type AchievementTier = {
|
|
|
1353
939
|
* @errorMessage must not be blank
|
|
1354
940
|
*/
|
|
1355
941
|
icon?: string;
|
|
1356
|
-
[key: string]: unknown;
|
|
1357
942
|
};
|
|
1358
943
|
/**
|
|
1359
944
|
* What makes an achievement measured rather than flagged.
|
|
@@ -1399,7 +984,6 @@ type AchievementProgress = {
|
|
|
1399
984
|
* @maxItems 8
|
|
1400
985
|
*/
|
|
1401
986
|
tiers?: AchievementTier[];
|
|
1402
|
-
[key: string]: unknown;
|
|
1403
987
|
};
|
|
1404
988
|
/**
|
|
1405
989
|
* One thing a player can be shown to have done.
|
|
@@ -1450,7 +1034,28 @@ type Achievement = {
|
|
|
1450
1034
|
secret?: boolean;
|
|
1451
1035
|
/** Present makes this measured rather than flagged. See `AchievementProgress`. */
|
|
1452
1036
|
progress?: AchievementProgress;
|
|
1453
|
-
|
|
1037
|
+
/**
|
|
1038
|
+
* Which achievement, of the ones this id has named. Absent is `1`.
|
|
1039
|
+
*
|
|
1040
|
+
* **Raising it starts the achievement again for everybody.** What players
|
|
1041
|
+
* reported and unlocked under the version before is kept and no longer
|
|
1042
|
+
* counted, so it is earned afresh under the id the game already reports to.
|
|
1043
|
+
*
|
|
1044
|
+
* **Only a change to what a stored value means needs it.** The words change
|
|
1045
|
+
* freely — title, detail, icon, secret — and so does the target, and a tier
|
|
1046
|
+
* added after the last one: progress is kept as the number reported, which
|
|
1047
|
+
* stays true when the goal moves, and a player who unlocked it keeps it. At
|
|
1048
|
+
* the same version, a published achievement may not turn from a flag into a
|
|
1049
|
+
* measure or back, turn its direction around, write its value in another
|
|
1050
|
+
* unit (to or from `duration-ms`), or move or drop a tier it already has.
|
|
1051
|
+
* Going back to a version declared before brings back what was earned under
|
|
1052
|
+
* it, so it is held to what that version was.
|
|
1053
|
+
*
|
|
1054
|
+
* @asType integer
|
|
1055
|
+
* @minimum 1
|
|
1056
|
+
* @maximum 1000
|
|
1057
|
+
*/
|
|
1058
|
+
version?: number;
|
|
1454
1059
|
};
|
|
1455
1060
|
/**
|
|
1456
1061
|
* The achievements this game keeps for a player.
|
|
@@ -1479,7 +1084,6 @@ type AchievementDeclaration = {
|
|
|
1479
1084
|
* @propertyNames { pattern: '^[a-z0-9]+(?:[._-][a-z0-9]+)*$', maxLength: 48, errorMessage: 'must be lowercase letters, digits, dots, hyphens and underscores' }
|
|
1480
1085
|
*/
|
|
1481
1086
|
list: Record<string, Achievement>;
|
|
1482
|
-
[key: string]: unknown;
|
|
1483
1087
|
};
|
|
1484
1088
|
/**
|
|
1485
1089
|
* A device a game can be played with, as one word.
|
|
@@ -1517,7 +1121,7 @@ type InputDeviceSet = InputDevice[];
|
|
|
1517
1121
|
* doubled. A thumbstick is not one of these; see `InputStick`.
|
|
1518
1122
|
*
|
|
1519
1123
|
* @group Input
|
|
1520
|
-
* @pattern ^(?:key\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|pointer\.(?:primary|secondary)|mouse\.(?:left|middle|right)|touch\.tap|controls\.(?=.{1,48}$)[a-z0-9]+(?:[_-][a-z0-9]+)*|pad\.(?:north|south|east|west|start|select)|pad\.(?:left|right)\.(?:north|south|east|west|bumper|trigger))$
|
|
1124
|
+
* @pattern ^(?:key\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|pointer\.(?:primary|secondary)|mouse\.(?:left|middle|right|wheelup|wheeldown)|touch\.tap|controls\.(?=.{1,48}$)[a-z0-9]+(?:[_-][a-z0-9]+)*|pad\.(?:north|south|east|west|start|select)|pad\.(?:left|right)\.(?:north|south|east|west|bumper|trigger))$
|
|
1521
1125
|
* @errorMessage is not a binding this SDK knows (a thumbstick is read rather than bound, and Escape is the host's key)
|
|
1522
1126
|
*/
|
|
1523
1127
|
type InputBinding$1 = string;
|
|
@@ -1577,7 +1181,115 @@ type InputAction = {
|
|
|
1577
1181
|
* @errorMessage must not be blank
|
|
1578
1182
|
*/
|
|
1579
1183
|
label?: string;
|
|
1580
|
-
|
|
1184
|
+
};
|
|
1185
|
+
/**
|
|
1186
|
+
* What presses a player's action on a pad or on the screen: a pad button, or
|
|
1187
|
+
* an on-screen control. Keys and mouse buttons are a keyboard set's, in
|
|
1188
|
+
* `PlayerInputDeclaration.keyboard`.
|
|
1189
|
+
*
|
|
1190
|
+
* @group Input
|
|
1191
|
+
* @pattern ^(?:controls\.(?=.{1,48}$)[a-z0-9]+(?:[_-][a-z0-9]+)*|pad\.(?:north|south|east|west|start|select)|pad\.(?:left|right)\.(?:north|south|east|west|bumper|trigger))$
|
|
1192
|
+
* @errorMessage must be a pad button or an on-screen control: a player's keys and mouse buttons go in input.player.keyboard
|
|
1193
|
+
*/
|
|
1194
|
+
type PlayerBinding = string;
|
|
1195
|
+
/**
|
|
1196
|
+
* What presses a player's action on their part of the keyboard: a key, or a
|
|
1197
|
+
* mouse button.
|
|
1198
|
+
*
|
|
1199
|
+
* @group Input
|
|
1200
|
+
* @pattern ^(?:key\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|mouse\.(?:left|middle|right|wheelup|wheeldown))$
|
|
1201
|
+
* @errorMessage must be a key or a mouse button (and Escape is the host's key)
|
|
1202
|
+
*/
|
|
1203
|
+
type KeyboardBinding = string;
|
|
1204
|
+
/**
|
|
1205
|
+
* One thing each player does: the same action for every local player, pressed
|
|
1206
|
+
* by their own pad, their own part of the keyboard, or the on-screen controls.
|
|
1207
|
+
*
|
|
1208
|
+
* @group Input
|
|
1209
|
+
*/
|
|
1210
|
+
type PlayerInputAction = {
|
|
1211
|
+
/**
|
|
1212
|
+
* What presses it on a pad, the same for every pad, and on the screen.
|
|
1213
|
+
* Leave it out for an action pressed only on the keyboard.
|
|
1214
|
+
*
|
|
1215
|
+
* @minItems 1
|
|
1216
|
+
* @maxItems 8
|
|
1217
|
+
*/
|
|
1218
|
+
bind?: PlayerBinding[];
|
|
1219
|
+
/**
|
|
1220
|
+
* What to call it in front of a player, in a remapping screen.
|
|
1221
|
+
*
|
|
1222
|
+
* @pattern \S
|
|
1223
|
+
* @maxLength 40
|
|
1224
|
+
* @errorMessage must not be blank
|
|
1225
|
+
*/
|
|
1226
|
+
title?: string;
|
|
1227
|
+
/**
|
|
1228
|
+
* What to draw on an on-screen button: a glyph, or a letter.
|
|
1229
|
+
*
|
|
1230
|
+
* @pattern \S
|
|
1231
|
+
* @maxLength 8
|
|
1232
|
+
* @errorMessage must not be blank
|
|
1233
|
+
*/
|
|
1234
|
+
label?: string;
|
|
1235
|
+
/**
|
|
1236
|
+
* Whether pressing it on a pad or a part of the keyboard nobody plays with
|
|
1237
|
+
* makes a new player, while the game is taking players. Left out on every
|
|
1238
|
+
* action, any of them does.
|
|
1239
|
+
*/
|
|
1240
|
+
join?: boolean;
|
|
1241
|
+
};
|
|
1242
|
+
/**
|
|
1243
|
+
* One part of the keyboard one player plays with: the keys and mouse buttons
|
|
1244
|
+
* that press each of the player actions there.
|
|
1245
|
+
*
|
|
1246
|
+
* @group Input
|
|
1247
|
+
*/
|
|
1248
|
+
type KeyboardSet = {
|
|
1249
|
+
/**
|
|
1250
|
+
* What the players call it: *Left keys*, *Arrows*.
|
|
1251
|
+
*
|
|
1252
|
+
* @pattern \S
|
|
1253
|
+
* @maxLength 40
|
|
1254
|
+
* @errorMessage must not be blank
|
|
1255
|
+
*/
|
|
1256
|
+
title?: string;
|
|
1257
|
+
/**
|
|
1258
|
+
* The keys and mouse buttons of each player action, by its id.
|
|
1259
|
+
*
|
|
1260
|
+
* @maxProperties 64
|
|
1261
|
+
* @propertyNames { pattern: '^[a-z0-9]+(?:[._-][a-z0-9]+)*$', maxLength: 48, errorMessage: 'must be a player action id' }
|
|
1262
|
+
*/
|
|
1263
|
+
bind: Record<string, KeyboardBinding[]>;
|
|
1264
|
+
};
|
|
1265
|
+
/**
|
|
1266
|
+
* What each local player does, and how they share the keyboard.
|
|
1267
|
+
*
|
|
1268
|
+
* **One set of actions for every player.** Each local player has their own
|
|
1269
|
+
* copy, pressed by the pad they hold, the part of the keyboard they play with,
|
|
1270
|
+
* or the on-screen controls. A pad's buttons are the same for every pad, so any
|
|
1271
|
+
* number of pads just works; the keyboard is split into sets, one player each,
|
|
1272
|
+
* so the number of sets is how many can share it.
|
|
1273
|
+
*
|
|
1274
|
+
* @group Input
|
|
1275
|
+
*/
|
|
1276
|
+
type PlayerInputDeclaration = {
|
|
1277
|
+
/**
|
|
1278
|
+
* The actions each player has, by id: never an id `actions` declares too.
|
|
1279
|
+
*
|
|
1280
|
+
* @maxProperties 32
|
|
1281
|
+
* @propertyNames { pattern: '^[a-z0-9]+(?:[._-][a-z0-9]+)*$', maxLength: 48, errorMessage: 'must be lowercase letters, digits, dots, hyphens and underscores' }
|
|
1282
|
+
*/
|
|
1283
|
+
actions: Record<string, PlayerInputAction>;
|
|
1284
|
+
/**
|
|
1285
|
+
* The parts of the keyboard players play with, one player each, in the
|
|
1286
|
+
* order they are offered. A player alone hears every one of them. Left out,
|
|
1287
|
+
* the keyboard presses no player's action.
|
|
1288
|
+
*
|
|
1289
|
+
* @minItems 1
|
|
1290
|
+
* @maxItems 4
|
|
1291
|
+
*/
|
|
1292
|
+
keyboard?: KeyboardSet[];
|
|
1581
1293
|
};
|
|
1582
1294
|
/**
|
|
1583
1295
|
* Where on the screen a group of on-screen controls sits.
|
|
@@ -1641,7 +1353,20 @@ type ControlSlot = {
|
|
|
1641
1353
|
as?: InputStick | Record<string, InputBinding$1>;
|
|
1642
1354
|
/** `thumbstick` only. See `ControlAxis`. Absent, the stick moves both ways. */
|
|
1643
1355
|
axis?: ControlAxis;
|
|
1644
|
-
|
|
1356
|
+
/**
|
|
1357
|
+
* How big this control is next to the layout's others: `1.25` for a jump
|
|
1358
|
+
* button a thumb lands on without looking, `0.8` for one pressed now and then.
|
|
1359
|
+
* Absent, 1.
|
|
1360
|
+
*
|
|
1361
|
+
* A size in the layout rather than in the game's stylesheet, because whether
|
|
1362
|
+
* the layout fits on a small screen is worked out from it before the
|
|
1363
|
+
* controls are drawn. A game's stylesheet changes how they look, never how
|
|
1364
|
+
* much of the screen they answer in.
|
|
1365
|
+
*
|
|
1366
|
+
* @minimum 0.75
|
|
1367
|
+
* @maximum 1.5
|
|
1368
|
+
*/
|
|
1369
|
+
scale?: number;
|
|
1645
1370
|
};
|
|
1646
1371
|
/**
|
|
1647
1372
|
* The one direction an on-screen thumbstick moves in: `x` across, `y` up and
|
|
@@ -1674,8 +1399,8 @@ type ControlZoneSlots = Record<string, ControlSlot>;
|
|
|
1674
1399
|
* A game may declare several and switch between them — a menu wants different
|
|
1675
1400
|
* controls from play, and a driving section different ones again — which is why
|
|
1676
1401
|
* they are named rather than there being one. A zone nobody knows is a layout
|
|
1677
|
-
* from a newer
|
|
1678
|
-
*
|
|
1402
|
+
* from a newer minor, which a host reads leniently, so whoever draws it simply
|
|
1403
|
+
* has nowhere to put it.
|
|
1679
1404
|
*
|
|
1680
1405
|
* @group Input
|
|
1681
1406
|
*/
|
|
@@ -1683,7 +1408,6 @@ type ControlLayout = {
|
|
|
1683
1408
|
left?: ControlZoneSlots;
|
|
1684
1409
|
right?: ControlZoneSlots;
|
|
1685
1410
|
full?: ControlZoneSlots;
|
|
1686
|
-
[key: string]: unknown;
|
|
1687
1411
|
};
|
|
1688
1412
|
/**
|
|
1689
1413
|
* What a game says about how it is played.
|
|
@@ -1733,20 +1457,99 @@ type InputDeclaration = {
|
|
|
1733
1457
|
* @propertyNames { pattern: '^[a-z0-9]+(?:[._-][a-z0-9]+)*$', maxLength: 48, errorMessage: 'must be a layout name of lowercase letters, digits, dots, hyphens and underscores' }
|
|
1734
1458
|
*/
|
|
1735
1459
|
controls?: Record<string, ControlLayout>;
|
|
1736
|
-
|
|
1460
|
+
/**
|
|
1461
|
+
* What each local player does, beside `actions`, which are everybody's. See
|
|
1462
|
+
* `PlayerInputDeclaration`.
|
|
1463
|
+
*/
|
|
1464
|
+
player?: PlayerInputDeclaration;
|
|
1465
|
+
};
|
|
1466
|
+
/**
|
|
1467
|
+
* How many people play a game on one device.
|
|
1468
|
+
*
|
|
1469
|
+
* Read by hosts before the game runs: a listing says *1–4 on one device*, and
|
|
1470
|
+
* the input panel offers a row for each player.
|
|
1471
|
+
*
|
|
1472
|
+
* @group Input
|
|
1473
|
+
* @category Useful
|
|
1474
|
+
*/
|
|
1475
|
+
type PlayersDeclaration = {
|
|
1476
|
+
/**
|
|
1477
|
+
* The most players on one device, each with their own copy of
|
|
1478
|
+
* `input.player`'s actions. 1 when left out.
|
|
1479
|
+
*
|
|
1480
|
+
* @minimum 1
|
|
1481
|
+
* @maximum 8
|
|
1482
|
+
* @asType integer
|
|
1483
|
+
*/
|
|
1484
|
+
local?: number;
|
|
1485
|
+
};
|
|
1486
|
+
/**
|
|
1487
|
+
* A preview's revision: a whole number from 1, the `R` of its package's
|
|
1488
|
+
* `0.R.p`. A breaking change to the preview is a new revision.
|
|
1489
|
+
*
|
|
1490
|
+
* @group Manifest
|
|
1491
|
+
* @category Useful
|
|
1492
|
+
* @minimum 1
|
|
1493
|
+
* @asType integer
|
|
1494
|
+
*/
|
|
1495
|
+
type PreviewRevision = number;
|
|
1496
|
+
/**
|
|
1497
|
+
* The previews a game is written against, each at the revision it needs.
|
|
1498
|
+
*
|
|
1499
|
+
* A preview is a part of the SDK that is not stable yet: its own `0.x`
|
|
1500
|
+
* package, versioned apart from `api`, and served only to the games that
|
|
1501
|
+
* declare it, at the revision they declare. A change to a preview reaches the
|
|
1502
|
+
* games written against it and nobody else.
|
|
1503
|
+
*
|
|
1504
|
+
* @group Manifest
|
|
1505
|
+
* @category Useful
|
|
1506
|
+
*/
|
|
1507
|
+
type PreviewsDeclaration = {
|
|
1508
|
+
/**
|
|
1509
|
+
* That this game plays over the network, in matches, at this revision of
|
|
1510
|
+
* `@hopple/sdk-preview-network`: `sdk.match`.
|
|
1511
|
+
*
|
|
1512
|
+
* The permission a reviewer grants, and what lets a host offer *Play with
|
|
1513
|
+
* friends* before the game has loaded. Nothing else about networking is
|
|
1514
|
+
* declared: the way a match is played, and its size, are chosen by the game
|
|
1515
|
+
* when it makes one. Absent, a game is never told about a match, and never
|
|
1516
|
+
* reaches one.
|
|
1517
|
+
*/
|
|
1518
|
+
network?: PreviewRevision;
|
|
1737
1519
|
};
|
|
1738
1520
|
/**
|
|
1739
|
-
*
|
|
1740
|
-
*
|
|
1741
|
-
*
|
|
1742
|
-
*
|
|
1521
|
+
* What kind of game this is, as one word from a list every game shares.
|
|
1522
|
+
*
|
|
1523
|
+
* A closed list, because a client files games under these and has to name each
|
|
1524
|
+
* one in front of a player: left to free text, one kind of game becomes three
|
|
1525
|
+
* spellings of it with a game each. The list only grows, since a published
|
|
1526
|
+
* manifest has to stay valid. Whoever reads one may be older than the game, and
|
|
1527
|
+
* ignores a word it does not know.
|
|
1528
|
+
*
|
|
1529
|
+
* `local-multiplayer` and `online-multiplayer` say how a game is played rather
|
|
1530
|
+
* than what it is, and only count where the manifest bears them out: see
|
|
1531
|
+
* `declaredGenres`.
|
|
1532
|
+
*
|
|
1533
|
+
* @group Manifest
|
|
1534
|
+
* @category Useful
|
|
1535
|
+
*/
|
|
1536
|
+
type GameGenre = 'racing' | 'shooter' | 'platformer' | 'puzzle' | 'arcade' | 'physics' | 'roguelike' | 'strategy' | 'building' | 'idle' | 'sports' | 'horror' | 'stealth' | 'fighting' | 'casual' | 'simulation' | 'adventure' | 'rhythm' | 'rpg' | 'local-multiplayer' | 'online-multiplayer';
|
|
1537
|
+
/**
|
|
1538
|
+
* Publishing refuses a key the manifest's API does not know; a host reading a
|
|
1539
|
+
* published one ignores it (see `validateManifest`).
|
|
1743
1540
|
*
|
|
1744
1541
|
* @group Manifest
|
|
1745
1542
|
* @category Important
|
|
1746
1543
|
*/
|
|
1747
1544
|
type GameManifest = {
|
|
1748
|
-
/**
|
|
1749
|
-
|
|
1545
|
+
/**
|
|
1546
|
+
* The API the game is written against. The major picks what the game is
|
|
1547
|
+
* served; the minor is the least it needs. The CLI fills it from the
|
|
1548
|
+
* installed `@hopple/sdk` when the config leaves it out.
|
|
1549
|
+
*
|
|
1550
|
+
* @category Important
|
|
1551
|
+
*/
|
|
1552
|
+
api: ApiVersion;
|
|
1750
1553
|
/**
|
|
1751
1554
|
* Stable across versions, and unique among its publisher's games: it is the
|
|
1752
1555
|
* second half of the address the game is published at, `owner/id`, and the
|
|
@@ -1770,8 +1573,19 @@ type GameManifest = {
|
|
|
1770
1573
|
* @errorMessage must be a handle: lowercase letters, digits and hyphens
|
|
1771
1574
|
*/
|
|
1772
1575
|
owner?: string;
|
|
1576
|
+
/**
|
|
1577
|
+
* `false` for a game that is never to be uploaded: an example, a test, a
|
|
1578
|
+
* game kept to one machine. `hopple dev` and `hopple check` still run it;
|
|
1579
|
+
* `hopple upload` and `hopple publish` refuse it, and so does a server it
|
|
1580
|
+
* is sent to another way. Absent, it may be published.
|
|
1581
|
+
*
|
|
1582
|
+
* @category Useful
|
|
1583
|
+
*/
|
|
1584
|
+
publishable?: boolean;
|
|
1773
1585
|
/**
|
|
1774
1586
|
* The game's own version, `MAJOR.MINOR.PATCH`. Ours to read, never to parse for meaning.
|
|
1587
|
+
* People see it beside the build the server numbers each upload with, and
|
|
1588
|
+
* each published version needs one no other published version of the game has.
|
|
1775
1589
|
*
|
|
1776
1590
|
* @category Important
|
|
1777
1591
|
* @pattern ^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$
|
|
@@ -1794,6 +1608,18 @@ type GameManifest = {
|
|
|
1794
1608
|
* @errorMessage must not be blank
|
|
1795
1609
|
*/
|
|
1796
1610
|
description?: string;
|
|
1611
|
+
/**
|
|
1612
|
+
* What kind of game it is, the main one first. Read by whoever files it in a
|
|
1613
|
+
* catalogue, which never runs it. At most `GENRE_MAX`, not counting
|
|
1614
|
+
* `local-multiplayer` and `online-multiplayer`: a game that is every kind
|
|
1615
|
+
* tells a player nothing. The publisher's claim, taken at its word, except
|
|
1616
|
+
* for those two. See `GameGenre`.
|
|
1617
|
+
*
|
|
1618
|
+
* @category Useful
|
|
1619
|
+
* @minItems 1
|
|
1620
|
+
* @maxItems 5
|
|
1621
|
+
*/
|
|
1622
|
+
genres?: GameGenre[];
|
|
1797
1623
|
/**
|
|
1798
1624
|
* A picture of the game, shown wherever a link to it is pasted — a chat, a
|
|
1799
1625
|
* post, a message.
|
|
@@ -1811,22 +1637,6 @@ type GameManifest = {
|
|
|
1811
1637
|
cover?: string;
|
|
1812
1638
|
/** @category Important */
|
|
1813
1639
|
orientation: Orientation;
|
|
1814
|
-
/**
|
|
1815
|
-
* The `@hopple/sdk` version the game was built against, optionally prefixed
|
|
1816
|
-
* with `^` or `~`.
|
|
1817
|
-
*
|
|
1818
|
-
* Recorded rather than enforced: what the host and the game actually have to
|
|
1819
|
-
* agree on is the protocol version, which the handshake settles. This is for
|
|
1820
|
-
* diagnostics — "every game that broke was built against 2.3" is a question
|
|
1821
|
-
* worth being able to ask. Deliberately far narrower than everything npm
|
|
1822
|
-
* accepts: a grammar we can read in one line is a grammar three packages can
|
|
1823
|
-
* agree on.
|
|
1824
|
-
*
|
|
1825
|
-
* @category Important
|
|
1826
|
-
* @pattern ^[\^~]?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$
|
|
1827
|
-
* @errorMessage must be a version like 1.0.0, ^1.0.0 or ~1.0.0
|
|
1828
|
-
*/
|
|
1829
|
-
sdk: string;
|
|
1830
1640
|
/**
|
|
1831
1641
|
* How the game wants the host's furniture handled. See `InsetMode`.
|
|
1832
1642
|
*
|
|
@@ -1864,62 +1674,38 @@ type GameManifest = {
|
|
|
1864
1674
|
*/
|
|
1865
1675
|
input?: InputDeclaration;
|
|
1866
1676
|
/**
|
|
1867
|
-
*
|
|
1868
|
-
* game that makes none. See `AudioDeclaration`.
|
|
1677
|
+
* How many play on one device. See `PlayersDeclaration`.
|
|
1869
1678
|
*
|
|
1870
|
-
* @category
|
|
1679
|
+
* @category Useful
|
|
1871
1680
|
*/
|
|
1872
|
-
|
|
1873
|
-
[key: string]: unknown;
|
|
1874
|
-
};
|
|
1875
|
-
/**
|
|
1876
|
-
* A game project's hopple config: `hopple.config.ts`, `hopple.config.js` or
|
|
1877
|
-
* `hopple.config.json`, beside the project's `package.json`.
|
|
1878
|
-
*
|
|
1879
|
-
* Everything the `hopple` command line needs to know about a project, in one
|
|
1880
|
-
* place: how to build the game, which built file is the game, and the manifest
|
|
1881
|
-
* that says what the game is. Only the manifest leaves the machine, uploaded
|
|
1882
|
-
* beside the page as `game.manifest.json`. A TypeScript or JavaScript config
|
|
1883
|
-
* default-exports one of these; a JSON config is one.
|
|
1884
|
-
*
|
|
1885
|
-
* ```ts
|
|
1886
|
-
* import type { HoppleConfig } from '@hopple/sdk';
|
|
1887
|
-
*
|
|
1888
|
-
* export default {
|
|
1889
|
-
* build: 'npm run build',
|
|
1890
|
-
* page: 'dist/index.html',
|
|
1891
|
-
* manifest: { schema: 1, id: 'my-game', version: '0.1.0', title: 'My Game', orientation: 'portrait', sdk: '^0.1.0', audio: null },
|
|
1892
|
-
* } satisfies HoppleConfig;
|
|
1893
|
-
* ```
|
|
1894
|
-
*
|
|
1895
|
-
* @group Manifest
|
|
1896
|
-
* @category Important
|
|
1897
|
-
*/
|
|
1898
|
-
type HoppleConfig = {
|
|
1899
|
-
/** Where an editor finds this file's schema, in a JSON config. Read by nothing else. */
|
|
1900
|
-
$schema?: string;
|
|
1681
|
+
players?: PlayersDeclaration;
|
|
1901
1682
|
/**
|
|
1902
|
-
*
|
|
1903
|
-
*
|
|
1904
|
-
* build. Leave it out for a game with nothing to build.
|
|
1683
|
+
* What this game makes noise with, one channel at a time, or `null` for a
|
|
1684
|
+
* game that makes none. See `AudioDeclaration`.
|
|
1905
1685
|
*
|
|
1906
|
-
* @
|
|
1907
|
-
* @errorMessage must be the command that builds the game, like "npm run build"
|
|
1686
|
+
* @category Important
|
|
1908
1687
|
*/
|
|
1909
|
-
|
|
1688
|
+
audio: AudioDeclaration | null;
|
|
1910
1689
|
/**
|
|
1911
|
-
* The
|
|
1912
|
-
*
|
|
1690
|
+
* The previews this game is written against, each at its revision. See
|
|
1691
|
+
* `PreviewsDeclaration`.
|
|
1913
1692
|
*
|
|
1914
|
-
* @
|
|
1915
|
-
* @errorMessage must be the built .html file, like "dist/index.html"
|
|
1693
|
+
* @category Useful
|
|
1916
1694
|
*/
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1695
|
+
previews?: PreviewsDeclaration;
|
|
1696
|
+
};
|
|
1697
|
+
/**
|
|
1698
|
+
* The manifest as a project's config holds it: `api` may be left out, for the
|
|
1699
|
+
* CLI to fill from the installed `@hopple/sdk`.
|
|
1700
|
+
*
|
|
1701
|
+
* @group Manifest
|
|
1702
|
+
* @category Useful
|
|
1703
|
+
*/
|
|
1704
|
+
type ProjectManifest = Omit<GameManifest, 'api'> & {
|
|
1705
|
+
api?: ApiVersion;
|
|
1920
1706
|
};
|
|
1921
1707
|
//#endregion
|
|
1922
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
1708
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/achievements.d.ts
|
|
1923
1709
|
/**
|
|
1924
1710
|
* Where this player stands on one achievement.
|
|
1925
1711
|
*
|
|
@@ -2017,7 +1803,7 @@ type Achievements<Id extends string = string, Measured extends string = Id> = {
|
|
|
2017
1803
|
progress(id: Measured, value: number): void;
|
|
2018
1804
|
};
|
|
2019
1805
|
//#endregion
|
|
2020
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
1806
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/analytics.d.ts
|
|
2021
1807
|
/**
|
|
2022
1808
|
* @group Analytics
|
|
2023
1809
|
* @category Important
|
|
@@ -2034,7 +1820,7 @@ type Analytics<Events extends object = Record<string, AnalyticsProps>> = {
|
|
|
2034
1820
|
track<Event extends keyof Events & string>(name: Event, props?: Events[Event]): void;
|
|
2035
1821
|
};
|
|
2036
1822
|
//#endregion
|
|
2037
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
1823
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/audio.d.ts
|
|
2038
1824
|
/**
|
|
2039
1825
|
* Something about the game's sound changed: the host's order, the player's
|
|
2040
1826
|
* mute, a fader. Read what you need — `volume(channel)`, `allowed` — and apply
|
|
@@ -2066,8 +1852,6 @@ type Audio<Channel extends string = string> = {
|
|
|
2066
1852
|
readonly muted: boolean;
|
|
2067
1853
|
/** The fader over the whole game, `0`–`1`, ignoring mute. */
|
|
2068
1854
|
readonly master: number;
|
|
2069
|
-
/** The whole of what the host last said. Frozen; a new object on every change. */
|
|
2070
|
-
readonly state: AudioState;
|
|
2071
1855
|
/**
|
|
2072
1856
|
* How loud one of this game's channels should actually come out, `0`–`1`.
|
|
2073
1857
|
*
|
|
@@ -2127,7 +1911,7 @@ type Audio<Channel extends string = string> = {
|
|
|
2127
1911
|
media(element: HTMLMediaElement, channel?: Channel): Unsubscribe;
|
|
2128
1912
|
};
|
|
2129
1913
|
//#endregion
|
|
2130
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
1914
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/info.d.ts
|
|
2131
1915
|
/**
|
|
2132
1916
|
* What the host said, frozen.
|
|
2133
1917
|
*
|
|
@@ -2145,7 +1929,7 @@ type Info = Readonly<{
|
|
|
2145
1929
|
device: Readonly<DeviceInfo>;
|
|
2146
1930
|
}>;
|
|
2147
1931
|
//#endregion
|
|
2148
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
1932
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/layout.d.ts
|
|
2149
1933
|
/**
|
|
2150
1934
|
* How much of each edge belongs to the host. CSS pixels.
|
|
2151
1935
|
*
|
|
@@ -2255,7 +2039,7 @@ type InsetPolicy = {
|
|
|
2255
2039
|
*/
|
|
2256
2040
|
declare function insetsFrom(obstructions: readonly Obstruction[], frame: Size, policy?: InsetPolicy): Insets;
|
|
2257
2041
|
//#endregion
|
|
2258
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
2042
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/names.d.ts
|
|
2259
2043
|
/**
|
|
2260
2044
|
* The keys of a declared map, or `string` where the map is not a literal one —
|
|
2261
2045
|
* which is what a manifest typed as the wide `GameManifest` gives — and
|
|
@@ -2274,6 +2058,19 @@ type ActionName<M> = M extends {
|
|
|
2274
2058
|
actions?: infer A;
|
|
2275
2059
|
};
|
|
2276
2060
|
} ? DeclaredNames<NonNullable<A>> : never;
|
|
2061
|
+
/**
|
|
2062
|
+
* An action each local player has, as the manifest declares it under
|
|
2063
|
+
* `input.player.actions`.
|
|
2064
|
+
*
|
|
2065
|
+
* @group Names
|
|
2066
|
+
*/
|
|
2067
|
+
type PlayerActionName<M> = M extends {
|
|
2068
|
+
input?: {
|
|
2069
|
+
player?: {
|
|
2070
|
+
actions?: infer A;
|
|
2071
|
+
};
|
|
2072
|
+
};
|
|
2073
|
+
} ? DeclaredNames<NonNullable<A>> : never;
|
|
2277
2074
|
/**
|
|
2278
2075
|
* An on-screen control layout the manifest declares under `input.controls`.
|
|
2279
2076
|
*
|
|
@@ -2362,7 +2159,7 @@ type EventProps<M> = M extends {
|
|
|
2362
2159
|
*/
|
|
2363
2160
|
type StickName = 'pad.left.stick' | 'pad.right.stick' | 'pad.stick' | `controls.${string}`;
|
|
2364
2161
|
//#endregion
|
|
2365
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
2162
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/input/state.d.ts
|
|
2366
2163
|
/**
|
|
2367
2164
|
* Where the pointer is, in the frame's own coordinates.
|
|
2368
2165
|
*
|
|
@@ -2423,246 +2220,453 @@ type InputSnapshot<Action extends string = string> = {
|
|
|
2423
2220
|
pointer: PointerState | null;
|
|
2424
2221
|
};
|
|
2425
2222
|
//#endregion
|
|
2426
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
2223
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/input/players.d.ts
|
|
2224
|
+
/**
|
|
2225
|
+
* What one player holds: a pad, one part of the keyboard, or the on-screen
|
|
2226
|
+
* controls.
|
|
2227
|
+
*
|
|
2228
|
+
* @group Input
|
|
2229
|
+
*/
|
|
2230
|
+
type Controller =
|
|
2231
|
+
/** One of the keyboard sets the game declared, from 0, with the title it gave it. */
|
|
2232
|
+
{
|
|
2233
|
+
kind: 'keyboard';
|
|
2234
|
+
set: number;
|
|
2235
|
+
title: string;
|
|
2236
|
+
} |
|
|
2237
|
+
/** A pad, by `Gamepad.index`. */
|
|
2238
|
+
{
|
|
2239
|
+
kind: 'gamepad';
|
|
2240
|
+
pad: number;
|
|
2241
|
+
} | {
|
|
2242
|
+
kind: 'touch';
|
|
2243
|
+
};
|
|
2244
|
+
//#endregion
|
|
2245
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/input/pointers.d.ts
|
|
2427
2246
|
/**
|
|
2428
|
-
*
|
|
2247
|
+
* Presses and groups of fingers on an element, recognised and meaning nothing:
|
|
2248
|
+
* what a game's tools, or a camera, are built on.
|
|
2429
2249
|
*
|
|
2430
|
-
*
|
|
2431
|
-
*
|
|
2432
|
-
*
|
|
2433
|
-
*
|
|
2434
|
-
*
|
|
2250
|
+
* What a press *is* is the same in every game, and every game that read
|
|
2251
|
+
* pointer events itself got some of it wrong, in the same few ways: a touch
|
|
2252
|
+
* the browser cancelled that counted as a tap, a drag that stuck when the mouse
|
|
2253
|
+
* was let go outside the frame, a view that jumped when a third finger came or
|
|
2254
|
+
* one of two went. What a press *means* is the game's, and differs per press:
|
|
2255
|
+
* one finger paints in an editor and pans in a map, and paints again once the
|
|
2256
|
+
* player picks the brush. So each layer of a game is asked, as a press goes
|
|
2257
|
+
* down, whether it is theirs, and the SDK tells its owner what it does.
|
|
2258
|
+
*/
|
|
2259
|
+
/**
|
|
2260
|
+
* A point on an element, in CSS pixels from its top left corner.
|
|
2435
2261
|
*
|
|
2436
2262
|
* @group Input
|
|
2437
2263
|
*/
|
|
2438
|
-
|
|
2264
|
+
type Point = {
|
|
2265
|
+
x: number;
|
|
2266
|
+
y: number;
|
|
2267
|
+
};
|
|
2439
2268
|
/**
|
|
2440
|
-
*
|
|
2269
|
+
* The modifier keys held.
|
|
2441
2270
|
*
|
|
2442
2271
|
* @group Input
|
|
2443
2272
|
*/
|
|
2444
|
-
type
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2273
|
+
type Modifiers = {
|
|
2274
|
+
shift: boolean;
|
|
2275
|
+
ctrl: boolean;
|
|
2276
|
+
alt: boolean;
|
|
2277
|
+
meta: boolean;
|
|
2278
|
+
};
|
|
2279
|
+
/**
|
|
2280
|
+
* What a press is made with.
|
|
2281
|
+
*
|
|
2282
|
+
* @group Input
|
|
2283
|
+
*/
|
|
2284
|
+
type PointerDevice = 'mouse' | 'touch' | 'pen';
|
|
2285
|
+
/**
|
|
2286
|
+
* A mouse button, by where it is. A pen's barrel button is `'right'`.
|
|
2287
|
+
*
|
|
2288
|
+
* @group Input
|
|
2289
|
+
*/
|
|
2290
|
+
type PointerButton = 'left' | 'middle' | 'right';
|
|
2291
|
+
/**
|
|
2292
|
+
* One finger, pen or mouse button on an element, from going down to coming up.
|
|
2293
|
+
* The same object throughout, kept up to date.
|
|
2294
|
+
*
|
|
2295
|
+
* @group Input
|
|
2296
|
+
*/
|
|
2297
|
+
type Press = {
|
|
2298
|
+
readonly id: number;
|
|
2299
|
+
readonly device: PointerDevice;
|
|
2300
|
+
/** The mouse button; `null` for a finger or a pen's tip. */
|
|
2301
|
+
readonly button: PointerButton | null;
|
|
2302
|
+
/** The modifier keys held as it went down. */
|
|
2303
|
+
readonly modifiers: Modifiers;
|
|
2304
|
+
readonly start: Point;
|
|
2305
|
+
readonly at: Point;
|
|
2306
|
+
/** Whether it has gone further than the layer's `slop` from `start`. */
|
|
2307
|
+
readonly moved: boolean;
|
|
2308
|
+
/** Whether it stayed still for the layer's `holdMs`. */
|
|
2309
|
+
readonly held: boolean;
|
|
2310
|
+
/** Milliseconds since it went down. */
|
|
2311
|
+
readonly age: number;
|
|
2312
|
+
};
|
|
2313
|
+
/**
|
|
2314
|
+
* What a layer does with a press it took. Exactly one of `tap`, `end` and
|
|
2315
|
+
* `cancel` finishes it.
|
|
2316
|
+
*
|
|
2317
|
+
* @group Input
|
|
2318
|
+
*/
|
|
2319
|
+
type PressHandler = {
|
|
2449
2320
|
/**
|
|
2450
|
-
*
|
|
2451
|
-
*
|
|
2321
|
+
* It moved, by this many CSS pixels: once it has gone past `slop`, the first
|
|
2322
|
+
* time from `start` so what was under it stays under it; from the first
|
|
2323
|
+
* pixel with `immediate`.
|
|
2452
2324
|
*/
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
/**
|
|
2459
|
-
|
|
2325
|
+
move?(press: Press, dx: number, dy: number): void;
|
|
2326
|
+
/** Let go without having moved or held. */
|
|
2327
|
+
tap?(press: Press): void;
|
|
2328
|
+
/** Stayed still for `holdMs`. It never taps after that. */
|
|
2329
|
+
hold?(press: Press): void;
|
|
2330
|
+
/** Let go after moving or holding, at this velocity in CSS pixels a second. */
|
|
2331
|
+
end?(press: Press, velocity: Point): void;
|
|
2460
2332
|
/**
|
|
2461
|
-
*
|
|
2462
|
-
*
|
|
2463
|
-
*
|
|
2333
|
+
* Taken away: by the browser (a scroll, a system gesture), by a second
|
|
2334
|
+
* finger that another layer made a group, or by the layer going. Undo
|
|
2335
|
+
* whatever it started.
|
|
2464
2336
|
*/
|
|
2465
|
-
|
|
2337
|
+
cancel?(press: Press): void;
|
|
2338
|
+
/** Hear moves from the first pixel rather than past `slop`: for drawing, or aiming. */
|
|
2339
|
+
immediate?: boolean;
|
|
2340
|
+
};
|
|
2341
|
+
/**
|
|
2342
|
+
* Two fingers or more on an element, from the second going down to the last
|
|
2343
|
+
* coming up. The same object throughout, kept up to date.
|
|
2344
|
+
*
|
|
2345
|
+
* @group Input
|
|
2346
|
+
*/
|
|
2347
|
+
type Group = {
|
|
2348
|
+
/** How many fingers are down now: one, once all but one have lifted. */
|
|
2349
|
+
readonly fingers: number;
|
|
2350
|
+
/** The most that were down at once: 2 for a two-finger tap. */
|
|
2351
|
+
readonly most: number;
|
|
2352
|
+
/** Midway between the first two fingers, or where the one left is; for a tap, where they were together. */
|
|
2353
|
+
readonly centre: Point;
|
|
2354
|
+
/** How far apart the first two fingers are, in CSS pixels; 0 with one. */
|
|
2355
|
+
readonly spread: number;
|
|
2356
|
+
/** The angle from the first finger to the second, in radians. */
|
|
2357
|
+
readonly angle: number;
|
|
2358
|
+
/** Whether any finger has gone further than `slop` from where it went down. */
|
|
2359
|
+
readonly moved: boolean;
|
|
2360
|
+
/** Milliseconds since the second finger went down. */
|
|
2361
|
+
readonly age: number;
|
|
2362
|
+
};
|
|
2363
|
+
/**
|
|
2364
|
+
* How a group moved since it last did: what a pinch, a two-finger drag and a
|
|
2365
|
+
* twist do, at once. A finger coming or going moves nothing.
|
|
2366
|
+
*
|
|
2367
|
+
* @group Input
|
|
2368
|
+
*/
|
|
2369
|
+
type GroupChange = {
|
|
2370
|
+
/** How far the centre moved, in CSS pixels. */
|
|
2371
|
+
dx: number;
|
|
2372
|
+
dy: number;
|
|
2373
|
+
/** How much further apart the first two fingers are, as a factor: above 1 is apart. */
|
|
2374
|
+
scale: number;
|
|
2375
|
+
/** How far they turned, in radians, clockwise. */
|
|
2376
|
+
rotate: number;
|
|
2466
2377
|
};
|
|
2467
2378
|
/**
|
|
2379
|
+
* What a layer does with a group it took. Exactly one of `tap`, `end` and
|
|
2380
|
+
* `cancel` finishes it.
|
|
2381
|
+
*
|
|
2468
2382
|
* @group Input
|
|
2469
2383
|
*/
|
|
2470
|
-
type
|
|
2471
|
-
|
|
2472
|
-
|
|
2384
|
+
type GroupHandler = {
|
|
2385
|
+
move?(group: Group, change: GroupChange): void;
|
|
2386
|
+
/** Every finger lifted, none having moved, quicker than `holdMs`. */
|
|
2387
|
+
tap?(group: Group): void;
|
|
2388
|
+
/** Every finger lifted otherwise, the centre leaving at this velocity in CSS pixels a second. */
|
|
2389
|
+
end?(group: Group, velocity: Point): void;
|
|
2390
|
+
/** Taken away: the browser took the last finger, or the layer went. */
|
|
2391
|
+
cancel?(group: Group): void;
|
|
2473
2392
|
};
|
|
2474
2393
|
/**
|
|
2475
|
-
*
|
|
2394
|
+
* One layer of a game's on an element: `input.pointers`.
|
|
2476
2395
|
*
|
|
2477
2396
|
* @group Input
|
|
2478
2397
|
*/
|
|
2479
|
-
type
|
|
2480
|
-
/** Which named layout this is. */
|
|
2481
|
-
layout: string;
|
|
2482
|
-
zones: readonly ControlModelZone[];
|
|
2483
|
-
/** The frame the controls are being drawn on, when it is known. */
|
|
2484
|
-
frame: Size;
|
|
2398
|
+
type PointerLayer = {
|
|
2485
2399
|
/**
|
|
2486
|
-
*
|
|
2487
|
-
*
|
|
2488
|
-
*
|
|
2489
|
-
* notch. Emphatically *not* the pad's own rectangles, which reach a game as
|
|
2490
|
-
* obstructions of kind `controls` and would, if they were projected in here,
|
|
2491
|
-
* inset the pad by the pad on every pass until it walked off the frame.
|
|
2492
|
-
* Whoever fills this in owes that filter; `index.ts` pays it.
|
|
2493
|
-
*
|
|
2494
|
-
* Zero is the ordinary answer and always a safe one: a host that reserved the
|
|
2495
|
-
* frame instead of drawing over it has already shrunk `frame` clear of its
|
|
2496
|
-
* own furniture, and a host too old to say anything has said nothing. Both
|
|
2497
|
-
* land here as four zeroes and the pad sits where it always sat.
|
|
2400
|
+
* Whether a press going down is this layer's: a handler takes it, for good;
|
|
2401
|
+
* `null` leaves it to the layers below. Asked of the newest layer first, and
|
|
2402
|
+
* of a camera last.
|
|
2498
2403
|
*/
|
|
2499
|
-
|
|
2404
|
+
press?(press: Press): PressHandler | null;
|
|
2500
2405
|
/**
|
|
2501
|
-
*
|
|
2502
|
-
*
|
|
2503
|
-
*
|
|
2504
|
-
* a stick, brought to wherever a thumb lands on its side of the screen, so
|
|
2505
|
-
* the place they first touch is the centre, and pulled along by a thumb that
|
|
2506
|
-
* goes past its rim. `fixed`: moved only from where it is drawn. A renderer
|
|
2507
|
-
* that ignores this draws `fixed`, which is still a stick a game can be
|
|
2508
|
-
* played with.
|
|
2406
|
+
* Whether fingers that make a group are this layer's, asked as the second
|
|
2407
|
+
* goes down. A layer that takes them cancels the press of every finger in
|
|
2408
|
+
* it. Taken by nobody, the new finger is a press of its own.
|
|
2509
2409
|
*/
|
|
2510
|
-
|
|
2410
|
+
group?(group: Group): GroupHandler | null;
|
|
2411
|
+
/** A mouse or a pen over the element with nothing pressed; `null` once it leaves. */
|
|
2412
|
+
hover?(at: Point | null, device: PointerDevice): void;
|
|
2413
|
+
/** How far a press may move, in CSS pixels, and still tap. 8 when left out. */
|
|
2414
|
+
slop?: number;
|
|
2415
|
+
/** How long a press stays still to hold, in milliseconds. 450 when left out. */
|
|
2416
|
+
holdMs?: number;
|
|
2511
2417
|
};
|
|
2512
2418
|
/**
|
|
2513
|
-
*
|
|
2514
|
-
*
|
|
2515
|
-
* The only way out of a renderer, replaced or not. A shim reports and the SDK
|
|
2516
|
-
* decides: that is what keeps a replaced renderer from being able to leave an
|
|
2517
|
-
* action held forever.
|
|
2419
|
+
* A layer of pointers, being read: `input.pointers`.
|
|
2518
2420
|
*
|
|
2519
2421
|
* @group Input
|
|
2520
2422
|
*/
|
|
2521
|
-
type
|
|
2522
|
-
/**
|
|
2523
|
-
|
|
2524
|
-
/**
|
|
2525
|
-
|
|
2423
|
+
type Pointers = {
|
|
2424
|
+
/** Whether a press or a group this layer took is down now. */
|
|
2425
|
+
readonly active: boolean;
|
|
2426
|
+
/** Take the layer off; whatever it holds is cancelled. */
|
|
2427
|
+
dispose(): void;
|
|
2526
2428
|
};
|
|
2429
|
+
//#endregion
|
|
2430
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/input/wheel.d.ts
|
|
2527
2431
|
/**
|
|
2528
|
-
*
|
|
2529
|
-
*
|
|
2530
|
-
* **Every hook is optional and every one is wrapped.** A shim that throws is
|
|
2531
|
-
* dropped back to the default for that hook and reported to `onError`, because
|
|
2532
|
-
* a replaceable renderer is otherwise a way for one host to ship a broken pad to
|
|
2533
|
-
* every game it runs at once.
|
|
2534
|
-
*
|
|
2535
|
-
* **The SDK declares the version and the shim adapts.** This file is frozen
|
|
2536
|
-
* inside bundles that shipped months before any given shim was written, so the
|
|
2537
|
-
* dangerous direction is a new shim meeting an old SDK — and it is safe by
|
|
2538
|
-
* construction if the shim is the side doing the adapting. A shim reads
|
|
2539
|
-
* `request.contract` and answers with what that version can carry.
|
|
2432
|
+
* One turn of a wheel, swipe of a trackpad, or pinch on one, the same in every
|
|
2433
|
+
* browser: `input.wheel`.
|
|
2540
2434
|
*
|
|
2541
2435
|
* @group Input
|
|
2542
2436
|
*/
|
|
2543
|
-
type
|
|
2544
|
-
/**
|
|
2545
|
-
|
|
2546
|
-
/**
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
* The host's half of the answer; the game's half is having asked. Returning
|
|
2550
|
-
* nothing leaves the decision alone, which is what a shim that only wanted to
|
|
2551
|
-
* restyle should do.
|
|
2552
|
-
*/
|
|
2553
|
-
decide?(request: {
|
|
2554
|
-
layout: string;
|
|
2555
|
-
frame: Size;
|
|
2556
|
-
/** What the host has taken along each edge — see `ControlModel.insets`. */
|
|
2557
|
-
insets: Insets;
|
|
2558
|
-
contract: number;
|
|
2559
|
-
}): boolean | undefined;
|
|
2560
|
-
/**
|
|
2561
|
-
* How far a stick must move before it counts, 0 to 1.
|
|
2562
|
-
*
|
|
2563
|
-
* The host's rather than the game's, because it is an accessibility setting
|
|
2564
|
-
* before it is a taste: a player whose hands shake needs a wider dead region
|
|
2565
|
-
* in every game they open, not in the ones that happened to think of it.
|
|
2566
|
-
*/
|
|
2567
|
-
deadzone?: number;
|
|
2568
|
-
/** A tick when a control is pressed. Absent where the platform has none. */
|
|
2569
|
-
haptic?(kind: 'press' | 'release'): void;
|
|
2570
|
-
/** Called with the root once, to set custom properties or add a stylesheet. */
|
|
2571
|
-
style?(root: ShadowRoot, request: {
|
|
2572
|
-
layout: string;
|
|
2573
|
-
frame: Size;
|
|
2574
|
-
}): void;
|
|
2437
|
+
type Wheel = {
|
|
2438
|
+
/** A mouse wheel's notches, a trackpad's scroll, or a trackpad's pinch (Ctrl and a wheel are one too). */
|
|
2439
|
+
kind: 'notch' | 'smooth' | 'pinch';
|
|
2440
|
+
/** How far, in CSS pixels, positive right and down. A notch is 100 in every browser. 0 for a pinch. */
|
|
2441
|
+
x: number;
|
|
2442
|
+
y: number;
|
|
2575
2443
|
/**
|
|
2576
|
-
*
|
|
2577
|
-
*
|
|
2578
|
-
*
|
|
2579
|
-
* which is called before the next render and when the controls are hidden.
|
|
2444
|
+
* Whole steps down, negative up: one for each notch, and on a trackpad one
|
|
2445
|
+
* as a swipe starts and another every 200 pixels after. What `mouse.wheelup`
|
|
2446
|
+
* and `mouse.wheeldown` press. 0 for a pinch.
|
|
2580
2447
|
*/
|
|
2581
|
-
|
|
2448
|
+
steps: number;
|
|
2449
|
+
/** A pinch's zoom, above 1 closer. 1 for anything else. */
|
|
2450
|
+
scale: number;
|
|
2451
|
+
/** A twist on Safari's trackpad, in radians, clockwise. 0 for anything else. */
|
|
2452
|
+
rotate: number;
|
|
2453
|
+
/** Where the pointer is, in CSS pixels from the element's top left corner. */
|
|
2454
|
+
at: Point;
|
|
2455
|
+
modifiers: Modifiers;
|
|
2582
2456
|
};
|
|
2583
2457
|
/**
|
|
2458
|
+
* The wheel being taken over an element: `input.wheel`.
|
|
2459
|
+
*
|
|
2584
2460
|
* @group Input
|
|
2585
2461
|
*/
|
|
2586
|
-
|
|
2462
|
+
type WheelTaker = {
|
|
2463
|
+
/** What was taken since the last read, added up: for a game that reads once a frame. */
|
|
2464
|
+
read(): {
|
|
2465
|
+
x: number;
|
|
2466
|
+
y: number;
|
|
2467
|
+
steps: number;
|
|
2468
|
+
};
|
|
2469
|
+
/** Stop taking it. */
|
|
2470
|
+
dispose(): void;
|
|
2471
|
+
};
|
|
2472
|
+
//#endregion
|
|
2473
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/input/camera.d.ts
|
|
2587
2474
|
/**
|
|
2588
|
-
*
|
|
2589
|
-
*
|
|
2590
|
-
* `2` added `insets` — to the model a renderer is given, to what `decide` is
|
|
2591
|
-
* asked, and as four custom properties the default sheet spends. Purely
|
|
2592
|
-
* additive: a `v: 1` shim that reads none of them behaves exactly as it did.
|
|
2593
|
-
*
|
|
2594
|
-
* `3` added `axis` to a thumbstick in the model. Additive again: a shim that
|
|
2595
|
-
* draws the stick moving both ways still gives the game one axis, because the
|
|
2596
|
-
* other is dropped from what it reports.
|
|
2597
|
-
*
|
|
2598
|
-
* `4` added `sticks` to the model: whether the player wants a thumbstick that
|
|
2599
|
-
* comes to their thumb. Additive: a shim that reads nothing of it draws the
|
|
2600
|
-
* stick where it always did.
|
|
2475
|
+
* What the camera should do: one for each move of a finger, a pair of them,
|
|
2476
|
+
* a wheel or a glide, whichever it was.
|
|
2601
2477
|
*
|
|
2602
2478
|
* @group Input
|
|
2603
2479
|
*/
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2480
|
+
type CameraChange = {
|
|
2481
|
+
/** Move what is shown by this, in CSS pixels: it follows the finger. */
|
|
2482
|
+
dx: number;
|
|
2483
|
+
dy: number;
|
|
2484
|
+
/** Zoom by this factor around `x`, `y`, above 1 closer; 1 when not zooming. */
|
|
2485
|
+
scale: number;
|
|
2486
|
+
/** Turn by this, in radians clockwise around `x`, `y`: two fingers, or Safari's trackpad. */
|
|
2487
|
+
rotate: number;
|
|
2488
|
+
/** The point zoomed and turned around, in CSS pixels from the element's top left corner. */
|
|
2489
|
+
x: number;
|
|
2490
|
+
y: number;
|
|
2491
|
+
/** What made it: so a game can treat a wheel differently from a finger. */
|
|
2492
|
+
source: 'drag' | 'pinch' | 'wheel' | 'trackpad' | 'glide';
|
|
2493
|
+
};
|
|
2607
2494
|
/**
|
|
2608
|
-
*
|
|
2495
|
+
* A press or a group of fingers the camera had that never moved.
|
|
2609
2496
|
*
|
|
2610
|
-
*
|
|
2611
|
-
|
|
2612
|
-
|
|
2497
|
+
* @group Input
|
|
2498
|
+
*/
|
|
2499
|
+
type Tap = {
|
|
2500
|
+
at: Point;
|
|
2501
|
+
device: PointerDevice;
|
|
2502
|
+
/** The mouse button; `null` for fingers and a pen's tip. */
|
|
2503
|
+
button: PointerButton | null;
|
|
2504
|
+
/** How many fingers: 2 or 3 for a tap of that many. */
|
|
2505
|
+
fingers: number;
|
|
2506
|
+
modifiers: Modifiers;
|
|
2507
|
+
};
|
|
2508
|
+
/**
|
|
2509
|
+
* What a wheel does to a camera.
|
|
2613
2510
|
*
|
|
2614
|
-
*
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
*
|
|
2511
|
+
* @group Input
|
|
2512
|
+
*/
|
|
2513
|
+
type WheelMode = 'zoom' | 'pan' | 'none';
|
|
2514
|
+
/**
|
|
2515
|
+
* @group Input
|
|
2516
|
+
*/
|
|
2517
|
+
type CameraOptions = {
|
|
2518
|
+
/** A view to move with every change. */
|
|
2519
|
+
view?: View;
|
|
2520
|
+
/** Hear every change, with or without a view: for a camera of the game's own. */
|
|
2521
|
+
move?(change: CameraChange): void;
|
|
2522
|
+
/** A drag or a pinch was let go, at this velocity in CSS pixels a second. */
|
|
2523
|
+
end?(velocity: Point): void;
|
|
2524
|
+
/** A press or a group of fingers the camera had, let go without moving. */
|
|
2525
|
+
tap?(tap: Tap): void;
|
|
2526
|
+
/** A press the camera had, held still. It never taps then. */
|
|
2527
|
+
hold?(tap: Tap): void;
|
|
2528
|
+
/** Which mouse buttons drag. A finger and a pen always do. `['left', 'middle']` when left out. */
|
|
2529
|
+
buttons?: readonly PointerButton[];
|
|
2530
|
+
/**
|
|
2531
|
+
* What the wheel does. Left out, a wheel's notch zooms around the pointer and
|
|
2532
|
+
* a trackpad pans, the way maps do; `'zoom'` or `'pan'` makes both do that,
|
|
2533
|
+
* and `'none'` leaves the wheel alone. A function decides for each turn: a
|
|
2534
|
+
* menu open, Shift held. A pinch on a trackpad zooms unless it says `'none'`.
|
|
2535
|
+
*/
|
|
2536
|
+
wheel?: WheelMode | ((wheel: Wheel) => WheelMode);
|
|
2537
|
+
/** Keep moving after a fling, slowing down, until the next press or wheel. */
|
|
2538
|
+
inertia?: boolean;
|
|
2539
|
+
/** How far a press may move, in CSS pixels, and still tap. 8 when left out. */
|
|
2540
|
+
slop?: number;
|
|
2541
|
+
/** How long a press stays still to hold, in milliseconds. 450 when left out. */
|
|
2542
|
+
holdMs?: number;
|
|
2543
|
+
};
|
|
2544
|
+
/**
|
|
2545
|
+
* A camera on an element: `input.camera`.
|
|
2619
2546
|
*
|
|
2620
2547
|
* @group Input
|
|
2621
2548
|
*/
|
|
2622
|
-
|
|
2549
|
+
type Camera = {
|
|
2550
|
+
/** Whether a press or fingers the camera has are down now. */
|
|
2551
|
+
readonly active: boolean;
|
|
2552
|
+
/** Stop: the element's presses and its wheel go back to whoever else wants them. */
|
|
2553
|
+
dispose(): void;
|
|
2554
|
+
};
|
|
2623
2555
|
/**
|
|
2624
|
-
*
|
|
2556
|
+
* A camera over a flat world: `input.view`.
|
|
2625
2557
|
*
|
|
2626
|
-
*
|
|
2627
|
-
*
|
|
2628
|
-
*
|
|
2629
|
-
*
|
|
2558
|
+
* The world is in a game's own units, with `y` down; `scale` is CSS pixels to
|
|
2559
|
+
* one of them, and `x`, `y` the world point at the element's top left corner.
|
|
2560
|
+
* A game draws with them, `screen = (world - x) * scale`, and may set any of
|
|
2561
|
+
* them; each move keeps them inside `min`, `max` and `bounds`.
|
|
2630
2562
|
*
|
|
2631
2563
|
* @group Input
|
|
2632
|
-
* @category Useful
|
|
2633
2564
|
*/
|
|
2634
|
-
|
|
2565
|
+
type View = {
|
|
2566
|
+
x: number;
|
|
2567
|
+
y: number;
|
|
2568
|
+
scale: number;
|
|
2569
|
+
/** The one axis it moves along, for a strip; `null` for both. */
|
|
2570
|
+
readonly axis: 'x' | 'y' | null;
|
|
2571
|
+
/** Drag the view by this many CSS pixels, the world following the finger. */
|
|
2572
|
+
pan(dx: number, dy: number): void;
|
|
2573
|
+
/** Zoom by this factor, the world point at `x`, `y` staying where it is. */
|
|
2574
|
+
zoom(factor: number, x: number, y: number): void;
|
|
2575
|
+
/** Put the world point `x`, `y` in the middle of the element, at `scale` if given. */
|
|
2576
|
+
look(x: number, y: number, scale?: number): void;
|
|
2577
|
+
/** The world point at a point on the element. */
|
|
2578
|
+
toWorld(x: number, y: number): Point;
|
|
2579
|
+
/** The point on the element a world point is drawn at. */
|
|
2580
|
+
toScreen(x: number, y: number): Point;
|
|
2581
|
+
/**
|
|
2582
|
+
* Say how big the element is, in CSS pixels: what `look` centres on and
|
|
2583
|
+
* `bounds` keeps filled. Call it whenever the element changes size.
|
|
2584
|
+
*/
|
|
2585
|
+
resize(width: number, height: number): void;
|
|
2586
|
+
};
|
|
2635
2587
|
/**
|
|
2636
|
-
* Whether a binding is one the player could press with what they are using.
|
|
2637
|
-
*
|
|
2638
2588
|
* @group Input
|
|
2639
|
-
* @category Useful
|
|
2640
2589
|
*/
|
|
2641
|
-
|
|
2590
|
+
type ViewOptions = {
|
|
2591
|
+
x?: number;
|
|
2592
|
+
y?: number;
|
|
2593
|
+
scale?: number;
|
|
2594
|
+
/** The least `scale` it zooms out to. */
|
|
2595
|
+
min?: number;
|
|
2596
|
+
/** The most `scale` it zooms in to. */
|
|
2597
|
+
max?: number;
|
|
2598
|
+
/**
|
|
2599
|
+
* Move along this axis only, for a strip: the other never pans nor shifts
|
|
2600
|
+
* as it zooms, and a camera turns a vertical wheel into a pan along it.
|
|
2601
|
+
*/
|
|
2602
|
+
axis?: 'x' | 'y';
|
|
2603
|
+
/**
|
|
2604
|
+
* The part of the world the view stays over, in world units: never scrolled
|
|
2605
|
+
* past an edge, and centred on it once all of it fits.
|
|
2606
|
+
*/
|
|
2607
|
+
bounds?: {
|
|
2608
|
+
x: number;
|
|
2609
|
+
y: number;
|
|
2610
|
+
width: number;
|
|
2611
|
+
height: number;
|
|
2612
|
+
};
|
|
2613
|
+
/** The element's size in CSS pixels, as `resize` takes it. */
|
|
2614
|
+
width?: number;
|
|
2615
|
+
height?: number;
|
|
2616
|
+
};
|
|
2617
|
+
//#endregion
|
|
2618
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/input/lock.d.ts
|
|
2642
2619
|
/**
|
|
2643
|
-
*
|
|
2644
|
-
*
|
|
2645
|
-
* **Best effort, and the host is allowed to do better.** Whether the south face
|
|
2646
|
-
* button says *A* or *B* depends on whose controller it is, and
|
|
2647
|
-
* `Gamepad.id` is free text that varies by browser and by operating system — so
|
|
2648
|
-
* a host that genuinely knows, because it is a native app, sends its own label
|
|
2649
|
-
* and this is what fills in when nobody did. Getting it slightly wrong is a
|
|
2650
|
-
* prompt a player can still follow; refusing to draw one is a game that never
|
|
2651
|
-
* says which button to press.
|
|
2620
|
+
* The mouse held to the game: `input.pointerLock`.
|
|
2652
2621
|
*
|
|
2653
2622
|
* @group Input
|
|
2654
|
-
* @category Useful
|
|
2655
2623
|
*/
|
|
2656
|
-
|
|
2624
|
+
type PointerLock = {
|
|
2625
|
+
/** Whether the mouse is locked to the game now. */
|
|
2626
|
+
readonly locked: boolean;
|
|
2627
|
+
/**
|
|
2628
|
+
* Lock the mouse to an element, the whole page when left out, now if the
|
|
2629
|
+
* browser allows it and on the player's next click or key if not.
|
|
2630
|
+
*
|
|
2631
|
+
* Asked again after the player has just left a lock, the browser makes them
|
|
2632
|
+
* wait about a second; the SDK waits with them. Ask from a press of the
|
|
2633
|
+
* player's where you can, a click on the game or the key that resumes it:
|
|
2634
|
+
* from a frame loop, the browser may not take it until they press something.
|
|
2635
|
+
*/
|
|
2636
|
+
request(element?: Element): void;
|
|
2637
|
+
/** Let the mouse go, and stop waiting to take it. */
|
|
2638
|
+
release(): void;
|
|
2639
|
+
/**
|
|
2640
|
+
* Run this when the lock is taken or lost. Lost without `release` is the
|
|
2641
|
+
* player leaving it, with Escape or by switching away: the time to pause.
|
|
2642
|
+
* The SDK does not take it back on its own; `request` again on resuming.
|
|
2643
|
+
*/
|
|
2644
|
+
on(listener: (locked: boolean) => void): Unsubscribe;
|
|
2645
|
+
/**
|
|
2646
|
+
* Run this for each move of the mouse while it is locked, in CSS pixels,
|
|
2647
|
+
* or in the mouse's own counts where the browser gives those
|
|
2648
|
+
* (`unadjustedMovement`). The jumps a browser sends as a lock starts are
|
|
2649
|
+
* left out.
|
|
2650
|
+
*/
|
|
2651
|
+
onMove(listener: (dx: number, dy: number) => void): Unsubscribe;
|
|
2652
|
+
/**
|
|
2653
|
+
* How far the mouse moved while locked since the last read, added up the way
|
|
2654
|
+
* `onMove` hears it: for a game that reads once a frame.
|
|
2655
|
+
*/
|
|
2656
|
+
read(): {
|
|
2657
|
+
x: number;
|
|
2658
|
+
y: number;
|
|
2659
|
+
};
|
|
2660
|
+
};
|
|
2657
2661
|
//#endregion
|
|
2658
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
2662
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/input/index.d.ts
|
|
2659
2663
|
/**
|
|
2660
|
-
*
|
|
2664
|
+
* A binding a game can name on its own, for a prompt about a button that is
|
|
2665
|
+
* not one of its actions: `pad.start`, `key.Space`.
|
|
2661
2666
|
*
|
|
2662
2667
|
* @group Input
|
|
2663
|
-
* @category Useful
|
|
2664
2668
|
*/
|
|
2665
|
-
|
|
2669
|
+
type ButtonName = `key.${string}` | `pad.${string}` | `mouse.${string}` | `pointer.${string}` | `touch.${string}`;
|
|
2666
2670
|
/**
|
|
2667
2671
|
* What presses each action, and what the player is pressing with: the part of
|
|
2668
2672
|
* input that is state rather than a stream of presses.
|
|
@@ -2673,11 +2677,12 @@ type InputState<Action extends string = string> = {
|
|
|
2673
2677
|
/**
|
|
2674
2678
|
* What presses each action, and what to call it in front of a player.
|
|
2675
2679
|
*
|
|
2676
|
-
* `mapping.shoot.label`
|
|
2677
|
-
*
|
|
2678
|
-
*
|
|
2679
|
-
*
|
|
2680
|
-
*
|
|
2680
|
+
* `mapping.shoot.label` names one binding in text: *Z* on a keyboard, a
|
|
2681
|
+
* letter for whatever pad the player picked up, and the label the manifest
|
|
2682
|
+
* gave the on-screen button on a touch screen. A prompt is better drawn with
|
|
2683
|
+
* `glyph`, which shows every binding, the same on every controller, and
|
|
2684
|
+
* follows a rebinding without being redrawn. An action can be missing, so
|
|
2685
|
+
* keep a fallback.
|
|
2681
2686
|
*/
|
|
2682
2687
|
readonly mapping: Readonly<Partial<Record<Action, InputBinding>>>;
|
|
2683
2688
|
/** What the player is using right now. */
|
|
@@ -2697,7 +2702,7 @@ type InputListener<Action extends string = string> = (now: InputState<Action>, p
|
|
|
2697
2702
|
* @group Input
|
|
2698
2703
|
* @category Important
|
|
2699
2704
|
*/
|
|
2700
|
-
type Input<Action extends string = string, Layout extends string = string> = InputState<Action> & {
|
|
2705
|
+
type Input<Action extends string = string, Layout extends string = string, PlayerAction extends string = Action> = InputState<Action> & {
|
|
2701
2706
|
/**
|
|
2702
2707
|
* Run this whenever an action goes down or comes up.
|
|
2703
2708
|
*
|
|
@@ -2737,6 +2742,49 @@ type Input<Action extends string = string, Layout extends string = string> = Inp
|
|
|
2737
2742
|
* The pointer's position needs `poll` set; presses and sticks do not.
|
|
2738
2743
|
*/
|
|
2739
2744
|
read(): InputSnapshot<Action>;
|
|
2745
|
+
/**
|
|
2746
|
+
* A character that draws what presses an action now, in the font `font`
|
|
2747
|
+
* names: every key or button bound to it, for the device in the player's
|
|
2748
|
+
* hands, as a keycap or a pad button.
|
|
2749
|
+
*
|
|
2750
|
+
* hint.textContent = `Press ${hopple.input.glyph('jump')} to jump`;
|
|
2751
|
+
* ctx.font = `20px 'My Font', sans-serif, ${hopple.input.font}`;
|
|
2752
|
+
*
|
|
2753
|
+
* The character is the same for the whole session; what changes is the font
|
|
2754
|
+
* the SDK draws it with, which follows the player's bindings and their
|
|
2755
|
+
* device. So text in the DOM is right without being touched again, and a
|
|
2756
|
+
* canvas is right the next time it is painted. A binding works too —
|
|
2757
|
+
* `glyph('pad.start')` — for a button that is no action of the game's.
|
|
2758
|
+
*
|
|
2759
|
+
* Only in a font stack that names `font`, and names it last: a box
|
|
2760
|
+
* otherwise. Under `hopple dev` a glyph printed anywhere else is reported to
|
|
2761
|
+
* `onError`.
|
|
2762
|
+
*/
|
|
2763
|
+
glyph(name: Action | ButtonName): string;
|
|
2764
|
+
/**
|
|
2765
|
+
* What `glyph` draws, in words: `Z or Space`, `bottom face button`. For an
|
|
2766
|
+
* `aria-label`, and for text drawn with no fonts at all. Empty for an action
|
|
2767
|
+
* with nothing bound for this device.
|
|
2768
|
+
*/
|
|
2769
|
+
describe(name: Action | ButtonName): string;
|
|
2770
|
+
/** The font family `glyph` draws in: name it, last, wherever a glyph is printed. */
|
|
2771
|
+
readonly font: string;
|
|
2772
|
+
/**
|
|
2773
|
+
* Draw an icon on an action's on-screen button instead of its label, or
|
|
2774
|
+
* `null` to go back to the label.
|
|
2775
|
+
*
|
|
2776
|
+
* hopple.input.icon('jump', 'M12 3 4 13h5v8h6v-8h5z');
|
|
2777
|
+
*
|
|
2778
|
+
* One SVG path, filled in the buttons' ink, in a 24 by 24 box: what icon
|
|
2779
|
+
* sets draw filled icons in. The label stays the button's name for a screen
|
|
2780
|
+
* reader. `glyph(action)` on a touch screen draws the same icon, so a prompt
|
|
2781
|
+
* matches the button. A path that cannot be read, or that leaves the box, is
|
|
2782
|
+
* reported to `onError` and the label is drawn instead.
|
|
2783
|
+
*
|
|
2784
|
+
* How the controls look otherwise is the game's stylesheet's: see the
|
|
2785
|
+
* skill's input guide.
|
|
2786
|
+
*/
|
|
2787
|
+
icon(action: Action, path: string | null): void;
|
|
2740
2788
|
/**
|
|
2741
2789
|
* Stop reading input and let go of everything held.
|
|
2742
2790
|
*
|
|
@@ -2748,6 +2796,112 @@ type Input<Action extends string = string, Layout extends string = string> = Inp
|
|
|
2748
2796
|
suspend(): void;
|
|
2749
2797
|
resume(): void;
|
|
2750
2798
|
readonly suspended: boolean;
|
|
2799
|
+
/**
|
|
2800
|
+
* Hear presses on an element, recognised and meaning nothing yet: a layer of
|
|
2801
|
+
* the game's, for its tools, its aim, its brush.
|
|
2802
|
+
*
|
|
2803
|
+
* hopple.input.pointers(canvas, {
|
|
2804
|
+
* press: (p) => tool === 'road' && p.button !== 'right' ? road(p) : null,
|
|
2805
|
+
* });
|
|
2806
|
+
*
|
|
2807
|
+
* Each press is offered to the layers on the element as it goes down, the
|
|
2808
|
+
* newest first and a `camera` last; the first to return a handler has it,
|
|
2809
|
+
* and hears it move, tap, hold, end or be cancelled. Two fingers or more are
|
|
2810
|
+
* offered as a group first: a layer that takes them cancels their presses.
|
|
2811
|
+
* A drag let go outside the frame still ends, a touch the browser took never
|
|
2812
|
+
* taps, and a finger coming or going moves nothing. The element gets
|
|
2813
|
+
* `touch-action: none` until its last layer is disposed.
|
|
2814
|
+
*/
|
|
2815
|
+
pointers(element: Element, layer: PointerLayer): Pointers;
|
|
2816
|
+
/**
|
|
2817
|
+
* Take the wheel over an element: a mouse wheel, a trackpad's scroll and its
|
|
2818
|
+
* pinch, the same in every browser, as an amount and as whole steps.
|
|
2819
|
+
*
|
|
2820
|
+
* const wheel = hopple.input.wheel(list, (w) => void (scroll += w.y));
|
|
2821
|
+
*
|
|
2822
|
+
* The page does not scroll under it, and `mouse.wheelup` / `mouse.wheeldown`
|
|
2823
|
+
* do not hear it, unless the listener returns `false` for that turn.
|
|
2824
|
+
* `read()` adds up what was taken since it was last read.
|
|
2825
|
+
*/
|
|
2826
|
+
wheel(element: Element, listener?: (wheel: Wheel) => boolean | void): WheelTaker;
|
|
2827
|
+
/**
|
|
2828
|
+
* A camera on an element, moved by whatever presses no other layer took:
|
|
2829
|
+
* one finger or a mouse button drags, two fingers pinch, pan and turn, a
|
|
2830
|
+
* mouse wheel zooms around the pointer and a trackpad pans and pinches, at
|
|
2831
|
+
* one speed in every browser.
|
|
2832
|
+
*
|
|
2833
|
+
* const view = hopple.input.view({ min: 0.5, max: 4, bounds: world });
|
|
2834
|
+
* hopple.input.camera(canvas, { view, tap: ({ at }) => select(view.toWorld(at.x, at.y)) });
|
|
2835
|
+
*
|
|
2836
|
+
* A `view` is moved for it; `move` hears every change, for a camera of the
|
|
2837
|
+
* game's own.
|
|
2838
|
+
*/
|
|
2839
|
+
camera(element: Element, options: CameraOptions): Camera;
|
|
2840
|
+
/**
|
|
2841
|
+
* A camera over a flat world that `camera` moves, kept between `min` and
|
|
2842
|
+
* `max` and over `bounds`. Nothing in it is drawn: a game reads `x`, `y`
|
|
2843
|
+
* and `scale` when it draws.
|
|
2844
|
+
*/
|
|
2845
|
+
view(options?: ViewOptions): View;
|
|
2846
|
+
/** The mouse held to the game, for a game that turns a camera with it. */
|
|
2847
|
+
readonly pointerLock: PointerLock;
|
|
2848
|
+
/**
|
|
2849
|
+
* The players on this device, each with their own copy of the actions
|
|
2850
|
+
* `input.player` declares, by `slot`. Empty for a game that declares none;
|
|
2851
|
+
* otherwise the first player is always there.
|
|
2852
|
+
*
|
|
2853
|
+
* Frozen and replaced when somebody joins or leaves. `read()`, `onAction`
|
|
2854
|
+
* and `glyph` on the input itself answer for a player action as if every
|
|
2855
|
+
* player pressed it: what a menu anybody may work reads.
|
|
2856
|
+
*/
|
|
2857
|
+
readonly players: readonly Player<PlayerAction>[];
|
|
2858
|
+
/** Run this when a player joins or leaves, claims a controller, or picks up another. */
|
|
2859
|
+
onPlayers(listener: (players: readonly Player<PlayerAction>[]) => void): Unsubscribe;
|
|
2860
|
+
/**
|
|
2861
|
+
* Whether a press of a join action on a controller nobody plays with seats
|
|
2862
|
+
* a new player: set it on the screen where players join, and clear it
|
|
2863
|
+
* before play.
|
|
2864
|
+
*
|
|
2865
|
+
* Setting it gives the first player the controller they last used, so the
|
|
2866
|
+
* others' presses on the rest make them players. The first player's first
|
|
2867
|
+
* press, if they have pressed nothing yet, is theirs.
|
|
2868
|
+
*/
|
|
2869
|
+
joining: boolean;
|
|
2870
|
+
/**
|
|
2871
|
+
* The most players this device may have now: what the manifest declares, or
|
|
2872
|
+
* fewer where the match being played has no room for more.
|
|
2873
|
+
*/
|
|
2874
|
+
readonly mostPlayers: number;
|
|
2875
|
+
};
|
|
2876
|
+
/**
|
|
2877
|
+
* One player on this device: their own actions, read from the controllers
|
|
2878
|
+
* they hold.
|
|
2879
|
+
*
|
|
2880
|
+
* @group Input
|
|
2881
|
+
* @category Important
|
|
2882
|
+
*/
|
|
2883
|
+
type Player<Action extends string = string> = {
|
|
2884
|
+
/** Their place, from 0: the lowest free one when they joined, kept until they leave. */
|
|
2885
|
+
readonly slot: number;
|
|
2886
|
+
/**
|
|
2887
|
+
* What they play with: the controller they claimed, or the one they last
|
|
2888
|
+
* used. `null` once their pad has gone away, until a free one is pressed.
|
|
2889
|
+
*/
|
|
2890
|
+
readonly controller: Controller | null;
|
|
2891
|
+
/** What they are using now, for what to draw: never which device to read. */
|
|
2892
|
+
readonly scheme: InputScheme;
|
|
2893
|
+
/** What presses each action for them, on the controllers they hear. */
|
|
2894
|
+
readonly mapping: Readonly<Partial<Record<Action, InputBinding>>>;
|
|
2895
|
+
/** Their actions now, and what happened since their last read: once a frame, as `input.read()`. */
|
|
2896
|
+
read(): InputSnapshot<Action>;
|
|
2897
|
+
onAction(action: Action, listener: ActionListener<Action>): Unsubscribe;
|
|
2898
|
+
/** Their sticks: their pad's, or the on-screen one when they hold the touch screen. */
|
|
2899
|
+
onStick(stick: StickName, listener: StickListener): Unsubscribe;
|
|
2900
|
+
/** A character drawing what presses an action for this player, as `input.glyph` draws it. */
|
|
2901
|
+
glyph(action: Action | ButtonName): string;
|
|
2902
|
+
describe(action: Action | ButtonName): string;
|
|
2903
|
+
/** Take them out: what they held is free again. The only player stays. */
|
|
2904
|
+
leave(): void;
|
|
2751
2905
|
};
|
|
2752
2906
|
/**
|
|
2753
2907
|
* The on-screen controls: shown when the game says so *and* the host says they
|
|
@@ -2791,7 +2945,7 @@ type Controls<Layout extends string = string> = {
|
|
|
2791
2945
|
readonly available: boolean;
|
|
2792
2946
|
};
|
|
2793
2947
|
//#endregion
|
|
2794
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
2948
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/lifecycle.d.ts
|
|
2795
2949
|
/** @group Lifecycle */
|
|
2796
2950
|
type LifecycleListener = (phase: Phase, previous: Phase) => void | Promise<void>;
|
|
2797
2951
|
/**
|
|
@@ -2810,7 +2964,7 @@ type Lifecycle = {
|
|
|
2810
2964
|
on(listener: LifecycleListener): Unsubscribe;
|
|
2811
2965
|
};
|
|
2812
2966
|
//#endregion
|
|
2813
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
2967
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/loop.d.ts
|
|
2814
2968
|
/**
|
|
2815
2969
|
* The host has let the game run its loop, or stopped it. Return a promise to
|
|
2816
2970
|
* make the host wait.
|
|
@@ -2864,7 +3018,36 @@ type Loop = {
|
|
|
2864
3018
|
tick(frame: FrameCallback): Unsubscribe;
|
|
2865
3019
|
};
|
|
2866
3020
|
//#endregion
|
|
2867
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
3021
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/panel.d.ts
|
|
3022
|
+
/**
|
|
3023
|
+
* The pages of the host's panel a game has a name for, as the keys of this
|
|
3024
|
+
* interface.
|
|
3025
|
+
*
|
|
3026
|
+
* An interface rather than a union so that a preview can add its own pages to
|
|
3027
|
+
* it, as it adds its own namespace to `GameSdk`: a page only a preview's games
|
|
3028
|
+
* are offered is named only where that preview is installed.
|
|
3029
|
+
*
|
|
3030
|
+
* @group Panels
|
|
3031
|
+
*/
|
|
3032
|
+
interface PanelPages {
|
|
3033
|
+
/** What this game is: its title, its author, its description. */
|
|
3034
|
+
about: true;
|
|
3035
|
+
/** Who has scored what, on this game's boards. */
|
|
3036
|
+
scores: true;
|
|
3037
|
+
/** What has been unlocked, and how far along the rest is. */
|
|
3038
|
+
achievements: true;
|
|
3039
|
+
/** What this game is played with, and where a player rebinds it. */
|
|
3040
|
+
input: true;
|
|
3041
|
+
}
|
|
3042
|
+
/**
|
|
3043
|
+
* A page of the host's panel: one of `PanelPages`.
|
|
3044
|
+
*
|
|
3045
|
+
* It grows, and it only ever grows: a name means the same thing for ever,
|
|
3046
|
+
* because a game ships and is never updated.
|
|
3047
|
+
*
|
|
3048
|
+
* @group Panels
|
|
3049
|
+
*/
|
|
3050
|
+
type PageId = keyof PanelPages;
|
|
2868
3051
|
/**
|
|
2869
3052
|
* Where the host's panel stands over the game.
|
|
2870
3053
|
*
|
|
@@ -2973,7 +3156,7 @@ type Panel = {
|
|
|
2973
3156
|
open(page: PageId): void;
|
|
2974
3157
|
};
|
|
2975
3158
|
//#endregion
|
|
2976
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
3159
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/pause.d.ts
|
|
2977
3160
|
/**
|
|
2978
3161
|
* The host has asked for a pause, or for the game to carry on.
|
|
2979
3162
|
*
|
|
@@ -3034,7 +3217,7 @@ type Pause = {
|
|
|
3034
3217
|
on(listener: PauseListener): Unsubscribe;
|
|
3035
3218
|
};
|
|
3036
3219
|
//#endregion
|
|
3037
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
3220
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/resources.d.ts
|
|
3038
3221
|
/**
|
|
3039
3222
|
* The host has let the game hold its resources again, or asked for them back.
|
|
3040
3223
|
* Return a promise to make the host wait until they have gone, or come back.
|
|
@@ -3064,7 +3247,7 @@ type Resources = {
|
|
|
3064
3247
|
on(listener: ResourcesListener): Unsubscribe;
|
|
3065
3248
|
};
|
|
3066
3249
|
//#endregion
|
|
3067
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
3250
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/save.d.ts
|
|
3068
3251
|
/**
|
|
3069
3252
|
* What a game gets back from a read: its own schema number, and its state.
|
|
3070
3253
|
*
|
|
@@ -3074,7 +3257,10 @@ type Resources = {
|
|
|
3074
3257
|
type SaveState = {
|
|
3075
3258
|
/** Whatever the game passed to `write`, or 1 where it never named one. */
|
|
3076
3259
|
version: number;
|
|
3077
|
-
/**
|
|
3260
|
+
/**
|
|
3261
|
+
* Parsed where it was written as a value, verbatim where it was a string, and
|
|
3262
|
+
* a `Uint8Array` where it was one.
|
|
3263
|
+
*/
|
|
3078
3264
|
state: unknown;
|
|
3079
3265
|
};
|
|
3080
3266
|
/**
|
|
@@ -3103,6 +3289,66 @@ type SaveStatus = {
|
|
|
3103
3289
|
* @category Useful
|
|
3104
3290
|
*/
|
|
3105
3291
|
type SaveListener = (now: SaveStatus, previous: SaveStatus) => void;
|
|
3292
|
+
/**
|
|
3293
|
+
* Make one save of two that went their own ways.
|
|
3294
|
+
*
|
|
3295
|
+
* `mine` is this device's, `theirs` one another device made meanwhile, and
|
|
3296
|
+
* neither was built on the other. Answer with the save to keep in place of
|
|
3297
|
+
* both, on whatever schema `version` it is written in. Throw where the two
|
|
3298
|
+
* cannot be merged — a schema this build does not know — and the host asks the
|
|
3299
|
+
* player which to keep.
|
|
3300
|
+
*
|
|
3301
|
+
* Pure: it is called with two states and must not touch the game's own. Run
|
|
3302
|
+
* while the game loads, its answer is what `read()` resolves with; run while
|
|
3303
|
+
* the game plays, its answer goes to `onChange` as well.
|
|
3304
|
+
*
|
|
3305
|
+
* @group Save
|
|
3306
|
+
* @category Useful
|
|
3307
|
+
*/
|
|
3308
|
+
type SaveMerger = (mine: SaveState, theirs: SaveState) => SaveState;
|
|
3309
|
+
/**
|
|
3310
|
+
* Why the save a game plays on changed under it.
|
|
3311
|
+
*
|
|
3312
|
+
* - `arrived`: another device's save, built on what the game had — a server
|
|
3313
|
+
* that answered after the game read, or another device that played on. Run
|
|
3314
|
+
* through the game's `merge` with what it last saved, where it has one.
|
|
3315
|
+
* - `merged`: the game's `merge` made one save of this device's and another
|
|
3316
|
+
* that went their own ways.
|
|
3317
|
+
* - `gone`: thrown away on another device, with nothing made here since. The
|
|
3318
|
+
* save is `null`.
|
|
3319
|
+
*
|
|
3320
|
+
* @group Save
|
|
3321
|
+
* @category Useful
|
|
3322
|
+
*/
|
|
3323
|
+
type SaveChangeReason = 'arrived' | 'merged' | 'gone';
|
|
3324
|
+
/**
|
|
3325
|
+
* Told the save the game now plays on, once it changed under it while it
|
|
3326
|
+
* played, and why: play on from this. `null` is a save thrown away on another
|
|
3327
|
+
* device (`gone`): start again.
|
|
3328
|
+
*
|
|
3329
|
+
* The host now holds what the listener is handed, and the game's next write
|
|
3330
|
+
* continues it. To keep the game's own instead — progress it has not saved
|
|
3331
|
+
* yet, or a New game the player has just chosen over a save that arrived
|
|
3332
|
+
* after — write it from the listener: it takes that save's place.
|
|
3333
|
+
*
|
|
3334
|
+
* @group Save
|
|
3335
|
+
* @category Useful
|
|
3336
|
+
*/
|
|
3337
|
+
type SaveChangeListener = (save: SaveState | null, why: SaveChangeReason) => void;
|
|
3338
|
+
/**
|
|
3339
|
+
* What a game says about its save at `init`, before the host has asked
|
|
3340
|
+
* anything.
|
|
3341
|
+
*
|
|
3342
|
+
* @group Save
|
|
3343
|
+
* @category Useful
|
|
3344
|
+
*/
|
|
3345
|
+
type SaveSetup = {
|
|
3346
|
+
/**
|
|
3347
|
+
* How to make one save of two. Left out, the host asks the player which of
|
|
3348
|
+
* the two to keep. See `SaveMerger`.
|
|
3349
|
+
*/
|
|
3350
|
+
merge?: SaveMerger | undefined;
|
|
3351
|
+
};
|
|
3106
3352
|
/**
|
|
3107
3353
|
* @group Save
|
|
3108
3354
|
* @category Important
|
|
@@ -3134,10 +3380,12 @@ type Save = {
|
|
|
3134
3380
|
/**
|
|
3135
3381
|
* Keep this. Resolves when the host says the record is durable.
|
|
3136
3382
|
*
|
|
3137
|
-
* A string is stored as it stands and comes back a string;
|
|
3138
|
-
*
|
|
3139
|
-
*
|
|
3140
|
-
*
|
|
3383
|
+
* A string is stored as it stands and comes back a string; a `Uint8Array` is
|
|
3384
|
+
* stored as its bytes and comes back a `Uint8Array`, `maxBytes` counting the
|
|
3385
|
+
* bytes themselves; anything else is `JSON.stringify`d and comes back parsed.
|
|
3386
|
+
* A value that cannot survive that at all — a cycle, a `BigInt` — rejects
|
|
3387
|
+
* with `bad_params` before anything reaches the bridge, and bytes on a host
|
|
3388
|
+
* older than keeping them reject with `unsupported`.
|
|
3141
3389
|
*
|
|
3142
3390
|
* `version` is the game's own schema number and means whatever the game says
|
|
3143
3391
|
* it means. There is no migration hook: a hook would be frozen game-side code
|
|
@@ -3149,11 +3397,32 @@ type Save = {
|
|
|
3149
3397
|
}): Promise<void>;
|
|
3150
3398
|
/** Throw the save away — a game resetting its own progress, at a player's asking. */
|
|
3151
3399
|
clear(): Promise<void>;
|
|
3400
|
+
/**
|
|
3401
|
+
* Told when the save the game plays on changed under it, and why: play on
|
|
3402
|
+
* from what the listener is handed.
|
|
3403
|
+
*
|
|
3404
|
+
* That is another device's save arriving after the game read — a server
|
|
3405
|
+
* that answered late, a page left open while another device played on —
|
|
3406
|
+
* (`arrived`), or the game's own `merge` run while it played (`merged`), or
|
|
3407
|
+
* the save thrown away on another device with nothing made here since
|
|
3408
|
+
* (`gone`, `null`). Without a merge, an arrival is handed over as it is: it
|
|
3409
|
+
* is built on what the game had.
|
|
3410
|
+
*
|
|
3411
|
+
* Listening is what lets a game start before its save is in hand: draw from
|
|
3412
|
+
* nothing at once, and take the player's save when it comes. Register it
|
|
3413
|
+
* before `read()`. A game that is not listening is never written over —
|
|
3414
|
+
* what it writes next is kept beside what arrived, for its merge or the
|
|
3415
|
+
* player to settle.
|
|
3416
|
+
*
|
|
3417
|
+
* To keep the game's own over what it is handed, write it from the
|
|
3418
|
+
* listener: that write takes the handed save's place.
|
|
3419
|
+
*/
|
|
3420
|
+
onChange(listener: SaveChangeListener): Unsubscribe;
|
|
3152
3421
|
/** The largest save this host will take, in bytes. `SAVE_BYTES` where it said nothing. */
|
|
3153
3422
|
readonly maxBytes: number;
|
|
3154
3423
|
};
|
|
3155
3424
|
//#endregion
|
|
3156
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
3425
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/score.d.ts
|
|
3157
3426
|
/**
|
|
3158
3427
|
* Where this player stands on every board, as far as anybody has said.
|
|
3159
3428
|
*
|
|
@@ -3230,7 +3499,7 @@ type Score<Board extends string = string> = {
|
|
|
3230
3499
|
}): Promise<ScoreResult>;
|
|
3231
3500
|
};
|
|
3232
3501
|
//#endregion
|
|
3233
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
3502
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/share.d.ts
|
|
3234
3503
|
/**
|
|
3235
3504
|
* @group Share
|
|
3236
3505
|
* @category Important
|
|
@@ -3257,9 +3526,18 @@ type Share = {
|
|
|
3257
3526
|
* check it — the same care `save.read` deserves, for a stronger reason.
|
|
3258
3527
|
*
|
|
3259
3528
|
* **`null` says nothing about whether a link can be offered.** It means
|
|
3260
|
-
* nobody arrived by one
|
|
3529
|
+
* nobody arrived by one, or that the link carried bytes, which are `bytes`;
|
|
3530
|
+
* `available` is what says whether one can be made.
|
|
3261
3531
|
*/
|
|
3262
3532
|
readonly data: string | null;
|
|
3533
|
+
/**
|
|
3534
|
+
* What the link that opened this game carried, where some run of this game
|
|
3535
|
+
* passed `offer` a `Uint8Array`: those bytes. `null` otherwise — a player who
|
|
3536
|
+
* arrived the ordinary way, or a link that carried a string, which is `data`.
|
|
3537
|
+
*
|
|
3538
|
+
* A stranger's input, exactly as `data` is.
|
|
3539
|
+
*/
|
|
3540
|
+
readonly bytes: Uint8Array | null;
|
|
3263
3541
|
/**
|
|
3264
3542
|
* Ask the host to put a link to this game in front of the player.
|
|
3265
3543
|
*
|
|
@@ -3269,23 +3547,26 @@ type Share = {
|
|
|
3269
3547
|
* may keep a sheet open as long as they like, and pressing Share again while
|
|
3270
3548
|
* one is up does not open a second.
|
|
3271
3549
|
*
|
|
3272
|
-
* `data` is the game's own and travels
|
|
3273
|
-
* to whoever opens it
|
|
3274
|
-
*
|
|
3275
|
-
*
|
|
3276
|
-
*
|
|
3277
|
-
* host
|
|
3550
|
+
* `data` is the game's own and travels with the link, opaque to the host,
|
|
3551
|
+
* back to whoever opens it: a string, which arrives as `share.data`, or a
|
|
3552
|
+
* `Uint8Array`, which arrives as `share.bytes`. The game reading it back is
|
|
3553
|
+
* the game that wrote it, so anything structured is the game's to encode and
|
|
3554
|
+
* the game's to parse — bytes pack a board far tighter than text does.
|
|
3555
|
+
* `SHARE_BYTES` is what every host carries, counted in bytes either way; more
|
|
3556
|
+
* than that is a host's own decision, and a host that will not carry it
|
|
3557
|
+
* refuses with `too_large`.
|
|
3278
3558
|
*
|
|
3279
3559
|
* `meta` is for the platform rather than for the game: why this link was made
|
|
3280
3560
|
* — the level, the score, which of the game's buttons — kept beside the
|
|
3281
3561
|
* host's own record of who made it and how, so a game's makers can learn
|
|
3282
3562
|
* which of its shares bring people in. Anything JSON can say, and
|
|
3283
3563
|
* `SHARE_META_BYTES` of it is what every host takes. Nobody who opens the link
|
|
3284
|
-
* is handed it
|
|
3564
|
+
* is handed it; the game's team reads it, with `data`, by `hopple share`.
|
|
3285
3565
|
*
|
|
3286
3566
|
* What goes wrong is reported to `onError` and sends nothing: `bad_params`
|
|
3287
|
-
* for a `data` that is
|
|
3288
|
-
* bugs in the game; `
|
|
3567
|
+
* for a `data` that is neither a string nor a `Uint8Array`, or a `meta` JSON
|
|
3568
|
+
* cannot carry, which are bugs in the game; `unsupported` for bytes on a host
|
|
3569
|
+
* older than carrying them; `too_large` from a host for more than it carries;
|
|
3289
3570
|
* `rate_limited` from one that will not offer a link right now. A host with
|
|
3290
3571
|
* no link to give does nothing, which a game checking `available` never asks
|
|
3291
3572
|
* of it. Every one of them is a game that carries on: nothing about a share
|
|
@@ -3297,12 +3578,12 @@ type Share = {
|
|
|
3297
3578
|
* sheet on screen comes from the player's own gesture.
|
|
3298
3579
|
*/
|
|
3299
3580
|
offer(options?: {
|
|
3300
|
-
data?: string;
|
|
3581
|
+
data?: string | Uint8Array;
|
|
3301
3582
|
meta?: ShareMeta;
|
|
3302
3583
|
}): void;
|
|
3303
3584
|
};
|
|
3304
3585
|
//#endregion
|
|
3305
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-
|
|
3586
|
+
//#region ../../../../../../../tmp/hopple-sdk-types-hbSZtA/game/src/init.d.ts
|
|
3306
3587
|
/**
|
|
3307
3588
|
* What `init` hands back: every namespace a game has, on one object.
|
|
3308
3589
|
*
|
|
@@ -3317,7 +3598,7 @@ type Share = {
|
|
|
3317
3598
|
* @group Bridge
|
|
3318
3599
|
* @category Useful
|
|
3319
3600
|
*/
|
|
3320
|
-
|
|
3601
|
+
interface GameSdk<M extends object = GameManifest> {
|
|
3321
3602
|
/**
|
|
3322
3603
|
* How far the game has got: `loading`, `ready`, `disposed`. The one thing
|
|
3323
3604
|
* here a game must actually call is `lifecycle.ready()`.
|
|
@@ -3433,7 +3714,7 @@ type GameSdk<M extends object = GameManifest> = {
|
|
|
3433
3714
|
*
|
|
3434
3715
|
* @category Useful
|
|
3435
3716
|
*/
|
|
3436
|
-
input: Input<ActionName<M>, LayoutName<M>>;
|
|
3717
|
+
input: Input<ActionName<M> | PlayerActionName<M>, LayoutName<M>, PlayerActionName<M>>;
|
|
3437
3718
|
/**
|
|
3438
3719
|
* How loud this game may be, which the host decides and the game obeys.
|
|
3439
3720
|
*
|
|
@@ -3526,19 +3807,17 @@ type GameSdk<M extends object = GameManifest> = {
|
|
|
3526
3807
|
*
|
|
3527
3808
|
* Resolves with the round trip in milliseconds, rejecting with a `BridgeError`
|
|
3528
3809
|
* whose code is `timeout` if the host never answers. This is the liveness
|
|
3529
|
-
* check
|
|
3810
|
+
* check, and what a game can measure the bridge with.
|
|
3530
3811
|
*/
|
|
3531
3812
|
ping(): Promise<number>;
|
|
3532
3813
|
/** Tear the bridge down. Calls in flight reject with `disposed`. */
|
|
3533
3814
|
dispose(): void;
|
|
3534
|
-
}
|
|
3815
|
+
}
|
|
3535
3816
|
/**
|
|
3536
3817
|
* @group Bridge
|
|
3537
3818
|
* @category Useful
|
|
3538
3819
|
*/
|
|
3539
3820
|
type InitOptions = {
|
|
3540
|
-
/** The window the game is running in. Defaults to the global one. */
|
|
3541
|
-
scope?: Window | undefined;
|
|
3542
3821
|
/**
|
|
3543
3822
|
* How long a call waits before rejecting with `timeout`.
|
|
3544
3823
|
*
|
|
@@ -3548,22 +3827,6 @@ type InitOptions = {
|
|
|
3548
3827
|
* in it.
|
|
3549
3828
|
*/
|
|
3550
3829
|
timeoutMs?: number | undefined;
|
|
3551
|
-
/**
|
|
3552
|
-
* The channel to talk over. Defaults to whatever the game turns out to be
|
|
3553
|
-
* running in — a shim a native shell left, or the frame that embedded us —
|
|
3554
|
-
* which is what every real game wants; a test, or a host that embeds a game
|
|
3555
|
-
* some other way, can hand over its own.
|
|
3556
|
-
*/
|
|
3557
|
-
transport?: Transport | undefined;
|
|
3558
|
-
/**
|
|
3559
|
-
* How long to wait for a host to turn up when there is neither a shim nor a
|
|
3560
|
-
* parent frame, before rejecting. Defaults to `SHIM_WAIT_MS`.
|
|
3561
|
-
*
|
|
3562
|
-
* Here from day one rather than when a platform first needs it: this is
|
|
3563
|
-
* game-side code, bundled into a game at build time, so it can never be added
|
|
3564
|
-
* later for games already published.
|
|
3565
|
-
*/
|
|
3566
|
-
shimWaitMs?: number | undefined;
|
|
3567
3830
|
/**
|
|
3568
3831
|
* Where a failure that belongs to nobody's promise goes — a lifecycle
|
|
3569
3832
|
* listener that threw, an event the SDK refused. Defaults to `console.error`.
|
|
@@ -3572,6 +3835,15 @@ type InitOptions = {
|
|
|
3572
3835
|
* them, as it is about any error the game throws and nothing catches.
|
|
3573
3836
|
*/
|
|
3574
3837
|
onError?: ((error: unknown) => void) | undefined;
|
|
3838
|
+
/**
|
|
3839
|
+
* What the game says about its save before the host asks anything: how to
|
|
3840
|
+
* merge two saves that went their own ways, on two devices. See `SaveSetup`.
|
|
3841
|
+
*
|
|
3842
|
+
* Here rather than on `sdk.save`, because the host may ask while the game is
|
|
3843
|
+
* still reading its save — the merge is what that read resolves with — and a
|
|
3844
|
+
* merge set after the read would be one the host never heard of.
|
|
3845
|
+
*/
|
|
3846
|
+
save?: SaveSetup | undefined;
|
|
3575
3847
|
};
|
|
3576
3848
|
/**
|
|
3577
3849
|
* Introduce the game to its host, and hand back the SDK once it has answered.
|
|
@@ -3607,62 +3879,4 @@ type InitOptions = {
|
|
|
3607
3879
|
*/
|
|
3608
3880
|
declare function init<M extends object = GameManifest>(options?: InitOptions): Promise<GameSdk<M>>;
|
|
3609
3881
|
//#endregion
|
|
3610
|
-
|
|
3611
|
-
/**
|
|
3612
|
-
* How long a game with no shim and no parent waits for one to turn up.
|
|
3613
|
-
*
|
|
3614
|
-
* Generous on purpose: a shim two seconds late is not coming, and the only game
|
|
3615
|
-
* made to wait is one that was never going to run.
|
|
3616
|
-
*
|
|
3617
|
-
* @group Bridge
|
|
3618
|
-
*/
|
|
3619
|
-
declare const SHIM_WAIT_MS = 2000;
|
|
3620
|
-
/** @group Bridge */
|
|
3621
|
-
type HostTransportOptions = {
|
|
3622
|
-
/** The window the game is running in. Defaults to the global one. */
|
|
3623
|
-
scope?: Window | undefined;
|
|
3624
|
-
/** How long to wait for a late shim before giving up. */
|
|
3625
|
-
shimWaitMs?: number | undefined;
|
|
3626
|
-
/** Where a shim that arrived wrongly, or twice, is reported. */
|
|
3627
|
-
onError?: ((error: unknown) => void) | undefined;
|
|
3628
|
-
};
|
|
3629
|
-
/**
|
|
3630
|
-
* Find something to talk over, waiting briefly if there is nothing yet.
|
|
3631
|
-
*
|
|
3632
|
-
* Asynchronous because of that last case alone. The two ordinary ones — a shim
|
|
3633
|
-
* already installed, a parent frame — resolve without yielding a turn.
|
|
3634
|
-
*
|
|
3635
|
-
* @group Bridge
|
|
3636
|
-
* @category Useful
|
|
3637
|
-
*/
|
|
3638
|
-
declare function hostTransport(options?: HostTransportOptions): Promise<Transport>;
|
|
3639
|
-
//#endregion
|
|
3640
|
-
//#region ../../../../../../../tmp/hopple-sdk-types-DAYaix/game/src/shim.d.ts
|
|
3641
|
-
/**
|
|
3642
|
-
* Whether an arbitrary value is a shim this SDK knows how to speak to.
|
|
3643
|
-
*
|
|
3644
|
-
* A version we do not know is a shim we must not guess at — a `v: 2` that moved
|
|
3645
|
-
* `send` to a different signature would be a channel we corrupt rather than one
|
|
3646
|
-
* we fail on. Refusing it falls through to the frame branch, and then to the
|
|
3647
|
-
* wait, which either connects or says clearly that nothing did.
|
|
3648
|
-
*
|
|
3649
|
-
* @group Bridge
|
|
3650
|
-
*/
|
|
3651
|
-
declare function isShim(value: unknown): value is HoppleShim;
|
|
3652
|
-
/**
|
|
3653
|
-
* What a platform left for us, or nothing — in which case we are in a frame.
|
|
3654
|
-
*
|
|
3655
|
-
* @group Bridge
|
|
3656
|
-
*/
|
|
3657
|
-
declare function findShim(scope: Window): HoppleShim | null;
|
|
3658
|
-
/**
|
|
3659
|
-
* A shim, seen by the peer as an ordinary channel.
|
|
3660
|
-
*
|
|
3661
|
-
* The trust boundary is in here, in SDK code, and never in the platform's: a
|
|
3662
|
-
* shim that cannot validate is a shim that cannot validate wrongly.
|
|
3663
|
-
*
|
|
3664
|
-
* @group Bridge
|
|
3665
|
-
*/
|
|
3666
|
-
declare function shimTransport(shim: HoppleShim): Transport;
|
|
3667
|
-
//#endregion
|
|
3668
|
-
export { ACHIEVEMENT_VALUE_MAX, AUDIO_FULL, AUDIO_MASTER, AUDIO_VOLUME_MAX, type Achievement, type AchievementDeclaration, type AchievementListener, type AchievementName, type AchievementProgress, type AchievementResult, type AchievementStanding, type AchievementStatus, type AchievementTier, type Achievements, type ActionListener, type ActionName, type Analytics, type AnalyticsDeclaration, type AnalyticsProps, type AnalyticsShape, type AnalyticsType, type AnalyticsValue, type AppInfo, type AppSurface, type Audio, type AudioChannel, type AudioDeclaration, type AudioListener, type AudioState, type BoardName, BridgeError, type ChannelName, type ControlLayout, type ControlModel, type ControlModelSlot, type ControlModelZone, type ControlReport, type ControlShape, type ControlSlot, type ControlZone, type Controls, DEADZONE, type DeclaredNames, type DeclaredValue, type DeviceInfo, type DeviceTier, type ErrorCode, type EventName, type EventProps, type FrameCallback, type GameInfo, type GameManifest, type GameSdk, type HoppleConfig, type HoppleShim, type HostTransportOptions, INPUT_CONTRACT, INPUT_SCHEMES, INPUT_SHIM, type Info, type InitOptions, type Input, type InputAction, type InputBinding, type InputChangeCause, type InputDeclaration, type InputDevice, type InputListener, type InputScheme, type InputShim, type InputSnapshot, type InputState, type InsetMode, type InsetPolicy, type Insets, type Layout, type LayoutDeclaration, type LayoutListener, type LayoutName, type LayoutState, type Lifecycle, type LifecycleListener, type Loop, type LoopListener, MANIFEST_FILE, MANIFEST_SCHEMA, MAX_STEP, type MeasuredName, type Obstruction, type ObstructionKind, type Orientation, PAD_BUTTONS, PAGES, PAUSE_NONE, PAUSE_STATES, type PageId, type Panel, type PanelListener, type PanelState, type Pause, type PauseListener, type PauseState, type Phase, type PlayerInfo, type PointerListener, type PointerState, type Rect, type Resources, type ResourcesListener, SAVE_BYTES, SCORE_VALUE_MAX, SET_SHIM, SHARE_BYTES, SHARE_META_BYTES, SHIM, SHIM_WAIT_MS, type Save, type SaveDeclaration, type SaveListener, type SaveState, type SaveStatus, type SaveStored, type Score, type ScoreBoard, type ScoreDeclaration, type ScoreDirection, type ScoreFormat, type ScoreListener, type ScoreResult, type ScoreStanding, type ScoreStandings, type Share, type ShareMeta, type ShareMetaValue, type Size, type StickListener, type StickName, type StickState, type Unsubscribe, audioVolumeOf, findShim, hostTransport, init, insetsFrom, isInputShim, isShim, labelFor, preferredBinding, servesScheme, shimTransport };
|
|
3882
|
+
export { type Achievement, type AchievementDeclaration, type AchievementListener, type AchievementName, type AchievementProgress, type AchievementStanding, type AchievementStatus, type AchievementTier, type Achievements, type ActionListener, type ActionName, type Analytics, type AnalyticsDeclaration, type AnalyticsProps, type AnalyticsShape, type AnalyticsType, type AnalyticsValue, type ApiVersion, type AppInfo, type AppSurface, type Audio, type AudioChannel, type AudioDeclaration, type AudioListener, type BoardName, BridgeError, type ButtonName, type Camera, type CameraChange, type CameraOptions, type ChannelName, type ControlLayout, type ControlShape, type ControlSlot, type ControlZone, type Controller, type Controls, type DeclaredNames, type DeclaredValue, type DeviceInfo, type DeviceTier, type ErrorCode, type ErrorCodes, type EventName, type EventProps, type FrameCallback, type GameInfo, type GameManifest, type GameSdk, type Group, type GroupChange, type GroupHandler, type Info, type InitOptions, type Input, type InputAction, type InputBinding, type InputDeclaration, type InputDevice, type InputListener, type InputScheme, type InputSnapshot, type InputState, type InsetMode, type InsetPolicy, type Insets, type Layout, type LayoutDeclaration, type LayoutListener, type LayoutName, type LayoutState, type Lifecycle, type LifecycleListener, type Loop, type LoopListener, MAX_STEP, type MeasuredName, type Modifiers, type Obstruction, type ObstructionKind, type Orientation, type PageId, type Panel, type PanelListener, type PanelPages, type PanelState, type Pause, type PauseListener, type PauseState, type Phase, type Player, type PlayerActionName, type PlayerInfo, type Point, type PointerButton, type PointerDevice, type PointerLayer, type PointerListener, type PointerLock, type PointerState, type Pointers, type Press, type PressHandler, type ProjectManifest, type Rect, type Resources, type ResourcesListener, SAVE_BYTES, SHARE_BYTES, SHARE_META_BYTES, type Save, type SaveChangeListener, type SaveChangeReason, type SaveDeclaration, type SaveListener, type SaveMerger, type SaveSetup, type SaveState, type SaveStatus, type SaveStored, type Score, type ScoreBoard, type ScoreDeclaration, type ScoreDirection, type ScoreFormat, type ScoreListener, type ScoreResult, type ScoreStanding, type ScoreStandings, type Share, type ShareMeta, type ShareMetaValue, type Size, type StickListener, type StickName, type StickState, type Tap, type Unsubscribe, type View, type ViewOptions, type Wheel, type WheelMode, type WheelTaker, init, insetsFrom };
|