@typeonce/ritmo-browser 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +106 -0
- package/README.md +6 -1
- package/dist/Controls.d.ts +496 -0
- package/dist/Controls.d.ts.map +1 -0
- package/dist/Controls.js +343 -0
- package/dist/Controls.js.map +1 -0
- package/dist/Gamepad.d.ts +376 -0
- package/dist/Gamepad.d.ts.map +1 -0
- package/dist/Gamepad.js +459 -0
- package/dist/Gamepad.js.map +1 -0
- package/dist/InputCapture.d.ts +46 -16
- package/dist/InputCapture.d.ts.map +1 -1
- package/dist/InputCapture.js +1 -1
- package/dist/InputCapture.js.map +1 -1
- package/dist/Keyboard.d.ts +177 -25
- package/dist/Keyboard.d.ts.map +1 -1
- package/dist/Keyboard.js +257 -91
- package/dist/Keyboard.js.map +1 -1
- package/dist/Pointer.d.ts +233 -64
- package/dist/Pointer.d.ts.map +1 -1
- package/dist/Pointer.js +205 -145
- package/dist/Pointer.js.map +1 -1
- package/dist/Touch.d.ts +75 -33
- package/dist/Touch.d.ts.map +1 -1
- package/dist/Touch.js +25 -30
- package/dist/Touch.js.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/buttons.d.ts +52 -0
- package/dist/internal/buttons.d.ts.map +1 -0
- package/dist/internal/buttons.js +211 -0
- package/dist/internal/buttons.js.map +1 -0
- package/dist/internal/introspect.d.ts +14 -0
- package/dist/internal/introspect.d.ts.map +1 -0
- package/dist/internal/introspect.js +19 -0
- package/dist/internal/introspect.js.map +1 -0
- package/dist/internal/state.d.ts +13 -0
- package/dist/internal/state.d.ts.map +1 -0
- package/dist/internal/state.js +2 -0
- package/dist/internal/state.js.map +1 -0
- package/dist/internal/used.d.ts +8 -0
- package/dist/internal/used.d.ts.map +1 -0
- package/dist/internal/used.js +14 -0
- package/dist/internal/used.js.map +1 -0
- package/dist/internal/vectors.d.ts +29 -0
- package/dist/internal/vectors.d.ts.map +1 -0
- package/dist/internal/vectors.js +22 -0
- package/dist/internal/vectors.js.map +1 -0
- package/package.json +4 -3
- package/src/Controls.ts +800 -0
- package/src/Gamepad.ts +752 -0
- package/src/InputCapture.ts +43 -24
- package/src/Keyboard.ts +387 -72
- package/src/Pointer.ts +392 -166
- package/src/Touch.ts +113 -61
- package/src/index.ts +10 -1
- package/src/internal/buttons.ts +222 -0
- package/src/internal/introspect.ts +23 -0
- package/src/internal/state.ts +12 -0
- package/src/internal/used.ts +14 -0
- package/src/internal/vectors.ts +41 -0
package/dist/Gamepad.js
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import * as Result from "@typeonce/ritmo/Result";
|
|
2
|
+
import * as ButtonsInternal from "./internal/buttons.js";
|
|
3
|
+
import { buttonTracker, flattenButtons, idleActions, idleButtons, idleVectors, splitActions } from "./internal/buttons.js";
|
|
4
|
+
import { digital, isVectorBinding, longer } from "./internal/vectors.js";
|
|
5
|
+
import { anyUsed } from "./internal/used.js";
|
|
6
|
+
/**
|
|
7
|
+
* The buttons of the browser's standard mapping, in index order: face
|
|
8
|
+
* buttons by compass position, bumpers and triggers, the two small center
|
|
9
|
+
* buttons, the stick clicks, the d-pad, and the home button.
|
|
10
|
+
*/
|
|
11
|
+
export const buttonNames = [
|
|
12
|
+
"south",
|
|
13
|
+
"east",
|
|
14
|
+
"west",
|
|
15
|
+
"north",
|
|
16
|
+
"leftBumper",
|
|
17
|
+
"rightBumper",
|
|
18
|
+
"leftTrigger",
|
|
19
|
+
"rightTrigger",
|
|
20
|
+
"select",
|
|
21
|
+
"start",
|
|
22
|
+
"leftStick",
|
|
23
|
+
"rightStick",
|
|
24
|
+
"dpadUp",
|
|
25
|
+
"dpadDown",
|
|
26
|
+
"dpadLeft",
|
|
27
|
+
"dpadRight",
|
|
28
|
+
"home"
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* Binds a vector action to a stick, to buttons for its four directions, or
|
|
32
|
+
* to both. The snapshot's `vectors` reports the longer of the two: the
|
|
33
|
+
* stick keeps its tilt (after the dead zone), and the buttons give length 1
|
|
34
|
+
* (a diagonal is not faster).
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* const bindings = {
|
|
39
|
+
* move: Gamepad.vector({ stick: "left", up: ["dpadUp"], down: ["dpadDown"], left: ["dpadLeft"], right: ["dpadRight"] }),
|
|
40
|
+
* jump: ["south"]
|
|
41
|
+
* } as const
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export const vector = (binding) => ({ _tag: "Vector", ...binding });
|
|
45
|
+
const zero = { x: 0, y: 0 };
|
|
46
|
+
/**
|
|
47
|
+
* A snapshot with nothing held and no pad, for initializing an input
|
|
48
|
+
* resource before the first capture.
|
|
49
|
+
*/
|
|
50
|
+
export const idle = (bindings) => {
|
|
51
|
+
return { actions: idleActions(bindings), vectors: idleVectors(bindings), buttons: idleButtons(buttonNames), left: zero, right: zero, leftTrigger: 0, rightTrigger: 0, used: false, connected: false, id: null };
|
|
52
|
+
};
|
|
53
|
+
const sameVector = (a, b) => a.x === b.x && a.y === b.y;
|
|
54
|
+
/** Removes the dead zone and rescales, so the stick goes from zero to full tilt smoothly. */
|
|
55
|
+
const stick = (x, y, deadZone) => {
|
|
56
|
+
const length = Math.sqrt(x * x + y * y);
|
|
57
|
+
if (length <= deadZone)
|
|
58
|
+
return zero;
|
|
59
|
+
const scaled = Math.min(1, (length - deadZone) / (1 - deadZone));
|
|
60
|
+
return { x: (x / length) * scaled, y: (y / length) * scaled };
|
|
61
|
+
};
|
|
62
|
+
/** The button tracker with the pad's analog state, shared by live and scripted actions. */
|
|
63
|
+
const tracker = (initial) => {
|
|
64
|
+
// Vector actions are tracked as their four directions, next to the button actions.
|
|
65
|
+
let bindings = initial;
|
|
66
|
+
const buttons = buttonTracker(buttonNames, flattenButtons(initial));
|
|
67
|
+
return {
|
|
68
|
+
held: buttons.held,
|
|
69
|
+
down: buttons.down,
|
|
70
|
+
up: buttons.up,
|
|
71
|
+
upAll: buttons.upAll,
|
|
72
|
+
rebind(next) {
|
|
73
|
+
bindings = next;
|
|
74
|
+
buttons.rebind(flattenButtons(next));
|
|
75
|
+
},
|
|
76
|
+
snapshot(analog) {
|
|
77
|
+
const taken = buttons.take();
|
|
78
|
+
// The actions are fixed at creation; a rebind only changes how each is bound.
|
|
79
|
+
const { actions, held } = splitActions(initial, taken.actions);
|
|
80
|
+
const vectors = {};
|
|
81
|
+
for (const [name, entry] of Object.entries(initial)) {
|
|
82
|
+
if (!isVectorBinding(entry))
|
|
83
|
+
continue;
|
|
84
|
+
const binding = bindings[name];
|
|
85
|
+
const pad = digital(held(name, "up"), held(name, "down"), held(name, "left"), held(name, "right"));
|
|
86
|
+
vectors[name] = binding.stick === undefined ? pad : longer(analog[binding.stick], pad);
|
|
87
|
+
}
|
|
88
|
+
const used = anyUsed(taken.buttons) || !sameVector(analog.left, zero) || !sameVector(analog.right, zero);
|
|
89
|
+
return { actions, vectors, buttons: taken.buttons, ...analog, used };
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
/** Whether a pad is being touched: a button down or a stick past the dead zone. */
|
|
94
|
+
const inUse = (pad, deadZone, triggerThreshold) => pad.buttons.some((button, index) => isDown(button, index, triggerThreshold)) ||
|
|
95
|
+
// Only the sticks' axes: some pads report their triggers as extra axes resting at -1.
|
|
96
|
+
pad.axes.slice(0, 4).some((axis) => Math.abs(axis) > deadZone);
|
|
97
|
+
const triggerIndices = new Set([6, 7]);
|
|
98
|
+
const isDown = (button, index, triggerThreshold) => triggerIndices.has(index) ? button.value >= triggerThreshold : button.pressed;
|
|
99
|
+
/** Reads the pads, treating a host that throws (a blocked permission policy) as having none. */
|
|
100
|
+
const readPads = (host) => {
|
|
101
|
+
try {
|
|
102
|
+
return host.navigator.getGamepads();
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Starts reading pads from `host`, usually `window`, on every animation
|
|
110
|
+
* frame until `dispose()`. With several pads connected it follows the one
|
|
111
|
+
* used last; switching pads, or the followed pad disconnecting, releases
|
|
112
|
+
* everything it held. Use {@link pads} to give each pad its own player.
|
|
113
|
+
*/
|
|
114
|
+
export const actions = (host, bindings, options = {}) => {
|
|
115
|
+
const deadZone = options.deadZone ?? 0.15;
|
|
116
|
+
const triggerThreshold = options.triggerThreshold ?? 0.5;
|
|
117
|
+
const state = tracker(bindings);
|
|
118
|
+
let followed = null;
|
|
119
|
+
let disposed = false;
|
|
120
|
+
let reading = null;
|
|
121
|
+
let frame = 0;
|
|
122
|
+
const poll = () => {
|
|
123
|
+
if (disposed)
|
|
124
|
+
return;
|
|
125
|
+
const pads = readPads(host).filter((pad) => pad !== null && pad.connected);
|
|
126
|
+
const current = pads.find((pad) => pad.index === followed);
|
|
127
|
+
// Keep the followed pad while it is in use; otherwise switch to another one being used, or keep the first there is.
|
|
128
|
+
const used = current !== undefined && inUse(current, deadZone, triggerThreshold)
|
|
129
|
+
? current
|
|
130
|
+
: pads.find((pad) => pad.index !== followed && inUse(pad, deadZone, triggerThreshold));
|
|
131
|
+
const next = used ?? current ?? pads[0];
|
|
132
|
+
if (next?.index !== followed)
|
|
133
|
+
state.upAll();
|
|
134
|
+
followed = next?.index ?? null;
|
|
135
|
+
reading = next ?? null;
|
|
136
|
+
if (next === undefined)
|
|
137
|
+
return;
|
|
138
|
+
readButtons(state, next, triggerThreshold);
|
|
139
|
+
};
|
|
140
|
+
const onFrame = () => {
|
|
141
|
+
if (disposed)
|
|
142
|
+
return;
|
|
143
|
+
poll();
|
|
144
|
+
frame = host.requestAnimationFrame(onFrame);
|
|
145
|
+
};
|
|
146
|
+
frame = host.requestAnimationFrame(onFrame);
|
|
147
|
+
return {
|
|
148
|
+
snapshot() {
|
|
149
|
+
poll();
|
|
150
|
+
const pad = reading;
|
|
151
|
+
if (pad === null)
|
|
152
|
+
return state.snapshot({ ...resting, connected: false, id: null });
|
|
153
|
+
return state.snapshot({ ...analogOf(pad, deadZone), connected: true, id: pad.id });
|
|
154
|
+
},
|
|
155
|
+
rebind: state.rebind,
|
|
156
|
+
dispose() {
|
|
157
|
+
if (disposed)
|
|
158
|
+
return;
|
|
159
|
+
disposed = true;
|
|
160
|
+
host.cancelAnimationFrame(frame);
|
|
161
|
+
reading = null;
|
|
162
|
+
state.upAll();
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
/** Presses and releases `state`'s buttons as `pad` reads now. */
|
|
167
|
+
const readButtons = (state, pad, triggerThreshold) => {
|
|
168
|
+
for (let index = 0; index < buttonNames.length; index++) {
|
|
169
|
+
const button = pad.buttons[index];
|
|
170
|
+
const name = buttonNames[index];
|
|
171
|
+
if (button !== undefined && isDown(button, index, triggerThreshold))
|
|
172
|
+
state.down(name);
|
|
173
|
+
else
|
|
174
|
+
state.up(name);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
/** A pad's sticks (dead zone removed) and triggers. */
|
|
178
|
+
const analogOf = (pad, deadZone) => {
|
|
179
|
+
const axis = (index) => pad.axes[index] ?? 0;
|
|
180
|
+
const trigger = (index) => Math.min(1, Math.max(0, pad.buttons[index]?.value ?? 0));
|
|
181
|
+
return {
|
|
182
|
+
left: stick(axis(0), axis(1), deadZone),
|
|
183
|
+
right: stick(axis(2), axis(3), deadZone),
|
|
184
|
+
leftTrigger: trigger(6),
|
|
185
|
+
rightTrigger: trigger(7)
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
const resting = { left: zero, right: zero, leftTrigger: 0, rightTrigger: 0 };
|
|
189
|
+
/**
|
|
190
|
+
* Starts reading every pad on `host`, usually `window`, up to `max` of
|
|
191
|
+
* them, each with its own presses and sticks; pads beyond `max` are
|
|
192
|
+
* ignored. A pad keeps its place in the list while unplugged; one that comes
|
|
193
|
+
* back at the same browser index continues it, and a different pad at that
|
|
194
|
+
* index takes the place over with nothing held. `max` is a whole number
|
|
195
|
+
* literal, 1 or more: the most players the game seats on pads.
|
|
196
|
+
*/
|
|
197
|
+
export const pads = (host, bindings, max, options = {}) => {
|
|
198
|
+
const limit = max;
|
|
199
|
+
const deadZone = options.deadZone ?? 0.15;
|
|
200
|
+
const triggerThreshold = options.triggerThreshold ?? 0.5;
|
|
201
|
+
const seen = [];
|
|
202
|
+
let disposed = false;
|
|
203
|
+
let frame = 0;
|
|
204
|
+
const poll = () => {
|
|
205
|
+
if (disposed)
|
|
206
|
+
return;
|
|
207
|
+
const connected = readPads(host).filter((pad) => pad !== null && pad.connected);
|
|
208
|
+
for (const pad of connected) {
|
|
209
|
+
if (seen.length < limit && !seen.some((entry) => entry.index === pad.index)) {
|
|
210
|
+
seen.push({ index: pad.index, state: tracker(bindings), id: pad.id, reading: null });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
for (const entry of seen) {
|
|
214
|
+
const pad = connected.find((reading) => reading.index === entry.index);
|
|
215
|
+
// Unplugged, or another pad took the index: everything it held is released.
|
|
216
|
+
if (pad === undefined || pad.id !== entry.id) {
|
|
217
|
+
if (entry.reading !== null)
|
|
218
|
+
entry.state.upAll();
|
|
219
|
+
entry.reading = null;
|
|
220
|
+
if (pad === undefined)
|
|
221
|
+
continue;
|
|
222
|
+
entry.id = pad.id;
|
|
223
|
+
}
|
|
224
|
+
entry.reading = pad;
|
|
225
|
+
readButtons(entry.state, pad, triggerThreshold);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const onFrame = () => {
|
|
229
|
+
if (disposed)
|
|
230
|
+
return;
|
|
231
|
+
poll();
|
|
232
|
+
frame = host.requestAnimationFrame(onFrame);
|
|
233
|
+
};
|
|
234
|
+
frame = host.requestAnimationFrame(onFrame);
|
|
235
|
+
return {
|
|
236
|
+
_tag: "Pads",
|
|
237
|
+
max: limit,
|
|
238
|
+
snapshot() {
|
|
239
|
+
poll();
|
|
240
|
+
return seen.map((entry) => entry.state.snapshot(entry.reading === null
|
|
241
|
+
? { ...resting, connected: false, id: entry.id }
|
|
242
|
+
: { ...analogOf(entry.reading, deadZone), connected: true, id: entry.id }));
|
|
243
|
+
},
|
|
244
|
+
rebind(next) {
|
|
245
|
+
for (const entry of seen)
|
|
246
|
+
entry.state.rebind(next);
|
|
247
|
+
// Pads that appear later start with the new bindings too.
|
|
248
|
+
bindings = next;
|
|
249
|
+
},
|
|
250
|
+
dispose() {
|
|
251
|
+
if (disposed)
|
|
252
|
+
return;
|
|
253
|
+
disposed = true;
|
|
254
|
+
host.cancelAnimationFrame(frame);
|
|
255
|
+
for (const entry of seen)
|
|
256
|
+
entry.state.upAll();
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* Pads driven by timelines instead of a host, one timeline per pad (as
|
|
262
|
+
* {@link scripted}), each with the id `scripted <n>` (from `scripted 1`)
|
|
263
|
+
* and `max` the number of timelines: for tests of games where every player
|
|
264
|
+
* has a pad.
|
|
265
|
+
*
|
|
266
|
+
* Unlike {@link pads}, every timeline is in the list from the first
|
|
267
|
+
* snapshot, with its id even while unplugged. Each pad connects at its
|
|
268
|
+
* timeline's first entry, so a pad plugged in later is a timeline that
|
|
269
|
+
* starts later, and an entry with `connected: false` unplugs it.
|
|
270
|
+
*/
|
|
271
|
+
export const scriptedPads = (bindings, timelines) => {
|
|
272
|
+
const each = timelines.map((timeline) => scripted(bindings, timeline));
|
|
273
|
+
return {
|
|
274
|
+
_tag: "Pads",
|
|
275
|
+
max: each.length,
|
|
276
|
+
snapshot: () => each.map((pad, index) => ({ ...pad.snapshot(), id: `scripted ${index + 1}` })),
|
|
277
|
+
rebind(next) {
|
|
278
|
+
for (const pad of each)
|
|
279
|
+
pad.rebind(next);
|
|
280
|
+
},
|
|
281
|
+
dispose() { }
|
|
282
|
+
};
|
|
283
|
+
};
|
|
284
|
+
/**
|
|
285
|
+
* Plays `timeline`: before the snapshot at index `frame`, every entry for
|
|
286
|
+
* that frame is applied. A pad counts as connected (with the id
|
|
287
|
+
* `"scripted"`) from the first entry on, until an entry says
|
|
288
|
+
* `connected: false`; `scripted(bindings, [])` is a pad that never connects.
|
|
289
|
+
* Buttons stay held from their press until their release; pressing a held
|
|
290
|
+
* button is not a new press.
|
|
291
|
+
*/
|
|
292
|
+
export const scripted = (bindings, timeline) => {
|
|
293
|
+
const state = tracker(bindings);
|
|
294
|
+
const byFrame = new Map();
|
|
295
|
+
for (const entry of timeline) {
|
|
296
|
+
const entries = byFrame.get(entry.frame);
|
|
297
|
+
if (entries)
|
|
298
|
+
entries.push(entry);
|
|
299
|
+
else
|
|
300
|
+
byFrame.set(entry.frame, [entry]);
|
|
301
|
+
}
|
|
302
|
+
const first = timeline.reduce((earliest, entry) => Math.min(earliest, entry.frame), Number.POSITIVE_INFINITY);
|
|
303
|
+
const resting = { left: zero, right: zero, leftTrigger: 0, rightTrigger: 0 };
|
|
304
|
+
let analog = resting;
|
|
305
|
+
let connected = false;
|
|
306
|
+
let frame = 0;
|
|
307
|
+
return {
|
|
308
|
+
snapshot() {
|
|
309
|
+
for (const entry of byFrame.get(frame) ?? []) {
|
|
310
|
+
const releases = new Set(entry.release ?? []);
|
|
311
|
+
for (const button of entry.press ?? []) {
|
|
312
|
+
if (state.held.has(button) && releases.has(button)) {
|
|
313
|
+
// Released and pressed again within the frame.
|
|
314
|
+
releases.delete(button);
|
|
315
|
+
state.up(button);
|
|
316
|
+
}
|
|
317
|
+
state.down(button);
|
|
318
|
+
}
|
|
319
|
+
for (const button of releases)
|
|
320
|
+
state.up(button);
|
|
321
|
+
analog = {
|
|
322
|
+
left: entry.left ?? analog.left,
|
|
323
|
+
right: entry.right ?? analog.right,
|
|
324
|
+
leftTrigger: entry.leftTrigger ?? analog.leftTrigger,
|
|
325
|
+
rightTrigger: entry.rightTrigger ?? analog.rightTrigger
|
|
326
|
+
};
|
|
327
|
+
connected = entry.connected ?? (frame === first ? true : connected);
|
|
328
|
+
if (!connected) {
|
|
329
|
+
state.upAll();
|
|
330
|
+
analog = resting;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
frame += 1;
|
|
334
|
+
return state.snapshot({ ...analog, connected, id: connected ? "scripted" : null });
|
|
335
|
+
},
|
|
336
|
+
rebind: state.rebind,
|
|
337
|
+
dispose() { },
|
|
338
|
+
frames: () => frame
|
|
339
|
+
};
|
|
340
|
+
};
|
|
341
|
+
/**
|
|
342
|
+
* Wraps `actions` and records, for every snapshot, the buttons pressed and
|
|
343
|
+
* released since the previous one and the sticks and triggers that moved.
|
|
344
|
+
*/
|
|
345
|
+
export const recording = (actions) => {
|
|
346
|
+
const entries = [];
|
|
347
|
+
let previous = { buttons: idleButtons(buttonNames), left: zero, right: zero, leftTrigger: 0, rightTrigger: 0, connected: false };
|
|
348
|
+
let frame = 0;
|
|
349
|
+
return {
|
|
350
|
+
snapshot() {
|
|
351
|
+
const snapshot = actions.snapshot();
|
|
352
|
+
const press = buttonNames.filter((name) => snapshot.buttons[name].pressed);
|
|
353
|
+
// A press of a button held at the previous snapshot means it was released in between.
|
|
354
|
+
const release = buttonNames.filter((name) => snapshot.buttons[name].released || (snapshot.buttons[name].pressed && previous.buttons[name].held));
|
|
355
|
+
const entry = {
|
|
356
|
+
...(press.length > 0 ? { press } : {}),
|
|
357
|
+
...(release.length > 0 ? { release } : {}),
|
|
358
|
+
...(sameVector(snapshot.left, previous.left) ? {} : { left: snapshot.left }),
|
|
359
|
+
...(sameVector(snapshot.right, previous.right) ? {} : { right: snapshot.right }),
|
|
360
|
+
...(snapshot.leftTrigger === previous.leftTrigger ? {} : { leftTrigger: snapshot.leftTrigger }),
|
|
361
|
+
...(snapshot.rightTrigger === previous.rightTrigger ? {} : { rightTrigger: snapshot.rightTrigger }),
|
|
362
|
+
// The first entry connects the pad by itself; later changes are written out.
|
|
363
|
+
...(snapshot.connected === previous.connected || entries.length === 0 ? {} : { connected: snapshot.connected })
|
|
364
|
+
};
|
|
365
|
+
// The first entry also marks when a pad appeared, so a replay connects on the same frame.
|
|
366
|
+
if (Object.keys(entry).length > 0 || (entries.length === 0 && snapshot.connected))
|
|
367
|
+
entries.push({ frame, ...entry });
|
|
368
|
+
previous = snapshot;
|
|
369
|
+
frame += 1;
|
|
370
|
+
return snapshot;
|
|
371
|
+
},
|
|
372
|
+
rebind: (bindings) => actions.rebind(bindings),
|
|
373
|
+
dispose: () => actions.dispose(),
|
|
374
|
+
timeline: () => [...entries]
|
|
375
|
+
};
|
|
376
|
+
};
|
|
377
|
+
const buttonSet = new Set(buttonNames);
|
|
378
|
+
/** Whether `name` is a button of the standard mapping, for validating stored bindings. */
|
|
379
|
+
export const isButton = (name) => typeof name === "string" && buttonSet.has(name);
|
|
380
|
+
/**
|
|
381
|
+
* Validates untrusted data, such as a parsed JSON file, as a timeline: an
|
|
382
|
+
* array of entries with a non-negative integer `frame`, optional
|
|
383
|
+
* `press`/`release` arrays of button names, optional `left`/`right` vectors
|
|
384
|
+
* of length at most 1, optional triggers from 0 to 1, and an optional
|
|
385
|
+
* boolean `connected`.
|
|
386
|
+
*/
|
|
387
|
+
export const parseTimeline = (data) => {
|
|
388
|
+
const invalid = (path, message) => Result.failure({ _tag: "InvalidTimeline", path, message });
|
|
389
|
+
if (!Array.isArray(data))
|
|
390
|
+
return invalid("", "expected an array of entries");
|
|
391
|
+
const entries = [];
|
|
392
|
+
for (let index = 0; index < data.length; index++) {
|
|
393
|
+
const entry = data[index];
|
|
394
|
+
const path = `[${index}]`;
|
|
395
|
+
if (typeof entry !== "object" || entry === null)
|
|
396
|
+
return invalid(path, "expected an object");
|
|
397
|
+
const fields = entry;
|
|
398
|
+
const frame = fields["frame"];
|
|
399
|
+
if (typeof frame !== "number" || !Number.isInteger(frame) || frame < 0)
|
|
400
|
+
return invalid(`${path}.frame`, "expected a non-negative integer");
|
|
401
|
+
const parsed = { frame };
|
|
402
|
+
for (const field of ["press", "release"]) {
|
|
403
|
+
const value = fields[field];
|
|
404
|
+
if (value === undefined)
|
|
405
|
+
continue;
|
|
406
|
+
if (!Array.isArray(value))
|
|
407
|
+
return invalid(`${path}.${field}`, "expected an array of button names");
|
|
408
|
+
for (let offset = 0; offset < value.length; offset++) {
|
|
409
|
+
if (!isButton(value[offset]))
|
|
410
|
+
return invalid(`${path}.${field}[${offset}]`, `expected one of ${buttonNames.join(", ")}`);
|
|
411
|
+
}
|
|
412
|
+
parsed[field] = [...value];
|
|
413
|
+
}
|
|
414
|
+
for (const field of ["left", "right"]) {
|
|
415
|
+
const value = fields[field];
|
|
416
|
+
if (value === undefined)
|
|
417
|
+
continue;
|
|
418
|
+
const { x, y } = (typeof value === "object" && value !== null ? value : {});
|
|
419
|
+
if (typeof x !== "number" || typeof y !== "number" || !Number.isFinite(x) || !Number.isFinite(y) || x * x + y * y > 1 + 1e-9) {
|
|
420
|
+
return invalid(`${path}.${field}`, "expected { x, y } of length at most 1");
|
|
421
|
+
}
|
|
422
|
+
parsed[field] = { x, y };
|
|
423
|
+
}
|
|
424
|
+
for (const field of ["leftTrigger", "rightTrigger"]) {
|
|
425
|
+
const value = fields[field];
|
|
426
|
+
if (value === undefined)
|
|
427
|
+
continue;
|
|
428
|
+
if (typeof value !== "number" || !(value >= 0 && value <= 1))
|
|
429
|
+
return invalid(`${path}.${field}`, "expected a number from 0 to 1");
|
|
430
|
+
parsed[field] = value;
|
|
431
|
+
}
|
|
432
|
+
const connected = fields["connected"];
|
|
433
|
+
if (connected !== undefined) {
|
|
434
|
+
if (typeof connected !== "boolean")
|
|
435
|
+
return invalid(`${path}.connected`, "expected a boolean");
|
|
436
|
+
parsed["connected"] = connected;
|
|
437
|
+
}
|
|
438
|
+
entries.push(parsed);
|
|
439
|
+
}
|
|
440
|
+
return Result.success(entries);
|
|
441
|
+
};
|
|
442
|
+
/**
|
|
443
|
+
* Validates untrusted data, such as saved settings parsed from JSON, as new
|
|
444
|
+
* buttons for `bindings`: an object with exactly the same action names, each
|
|
445
|
+
* mapped to a non-empty array of button names (for a vector action, an
|
|
446
|
+
* object with an optional `stick` and buttons for all four directions or
|
|
447
|
+
* none, as `Gamepad.vector` saves). Pass the result to
|
|
448
|
+
* {@link Actions.rebind}; on failure, keep the defaults.
|
|
449
|
+
*
|
|
450
|
+
* @example
|
|
451
|
+
* ```ts
|
|
452
|
+
* const saved = Gamepad.parseRebinding(bindings, JSON.parse(stored))
|
|
453
|
+
* if (saved.ok) pad.rebind(saved.value)
|
|
454
|
+
* ```
|
|
455
|
+
*/
|
|
456
|
+
export const parseRebinding = (bindings, data) =>
|
|
457
|
+
// The checked names and buttons are exactly `Rebinding<B>`.
|
|
458
|
+
ButtonsInternal.parseButtonRebinding(buttonNames, bindings, data, ["left", "right"]);
|
|
459
|
+
//# sourceMappingURL=Gamepad.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Gamepad.js","sourceRoot":"","sources":["../src/Gamepad.ts"],"names":[],"mappings":"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"}
|
package/dist/InputCapture.d.ts
CHANGED
|
@@ -8,12 +8,22 @@
|
|
|
8
8
|
* every system in that run reads the same snapshot and press edges are
|
|
9
9
|
* observed exactly once per run.
|
|
10
10
|
*
|
|
11
|
-
* The source is any service with `snapshot()`:
|
|
12
|
-
*
|
|
13
|
-
* resource's
|
|
11
|
+
* The source is any service with `snapshot()`: one device such as
|
|
12
|
+
* `Keyboard.actions(...)`, a `Controls` merge of several, or a
|
|
13
|
+
* `Controls.players(...)` pool. The resource's
|
|
14
|
+
* value type must be exactly the snapshot type (declare it as
|
|
15
|
+
* `InputCapture.SnapshotOf<typeof Source>`): not a wider type, and not one
|
|
16
|
+
* with extra optional fields.
|
|
14
17
|
*
|
|
15
|
-
*
|
|
16
|
-
* `Game.System.thisTick(...)`
|
|
18
|
+
* The system declares its access like any other: it writes the resource, so
|
|
19
|
+
* a reader declared with `Game.System.thisTick(...)` placed before it does
|
|
20
|
+
* not compile, and it consumes the source (`Game.System.consumeService`), so
|
|
21
|
+
* `describe()` warns with `service-consumed-twice` when one source is
|
|
22
|
+
* captured at more than one placement (in named schedules, or wherever a
|
|
23
|
+
* debug runtime saw it run). Every input source marks `snapshot()` with
|
|
24
|
+
* `System.Consumes`, so another system that declares the source with
|
|
25
|
+
* `Game.System.service` (to rebind it, say) cannot call `snapshot()`.
|
|
26
|
+
* Capture each source once and read the resource everywhere else.
|
|
17
27
|
*
|
|
18
28
|
* @module InputCapture
|
|
19
29
|
* @docGroup browser
|
|
@@ -34,13 +44,16 @@
|
|
|
34
44
|
* }).value
|
|
35
45
|
* ```
|
|
36
46
|
*/
|
|
47
|
+
import type * as System from "@typeonce/ritmo/System";
|
|
37
48
|
import type { Descriptor } from "@typeonce/ritmo/Descriptor";
|
|
38
|
-
import type { Condition
|
|
49
|
+
import type { Condition } from "@typeonce/ritmo/Machine";
|
|
39
50
|
import type { Schema } from "@typeonce/ritmo/Schema";
|
|
40
51
|
/**
|
|
41
|
-
* Anything that produces one input snapshot per call.
|
|
52
|
+
* Anything that produces one input snapshot per call. `snapshot()` drains
|
|
53
|
+
* the source, so only a system that declares it with
|
|
54
|
+
* `Game.System.consumeService` (like `InputCapture.system`) calls it.
|
|
42
55
|
*/
|
|
43
|
-
export interface Source<Value> {
|
|
56
|
+
export interface Source<Value> extends System.Consumes<"snapshot"> {
|
|
44
57
|
readonly snapshot: () => Value;
|
|
45
58
|
}
|
|
46
59
|
type ServiceDescriptor = Descriptor<"service", string, any>;
|
|
@@ -50,13 +63,18 @@ type ResourceDescriptor = Descriptor<"resource", string, any>;
|
|
|
50
63
|
* service has no `snapshot()`.
|
|
51
64
|
*/
|
|
52
65
|
export type SnapshotOf<Service extends ServiceDescriptor> = Descriptor.Value<Service> extends Source<infer Value> ? Value : never;
|
|
53
|
-
|
|
66
|
+
/** Whether `A` and `B` are the same type, not merely assignable both ways. */
|
|
67
|
+
type Same<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false;
|
|
68
|
+
/** The resource when its value type is exactly the source's snapshot type, otherwise an error naming the fix. */
|
|
69
|
+
type MatchingResource<Resource extends ResourceDescriptor, Service extends ServiceDescriptor> = Same<Descriptor.Value<Resource>, SnapshotOf<Service>> extends true ? Resource : "The resource's value type must be exactly the source's snapshot type: declare it with InputCapture.SnapshotOf<typeof Source>";
|
|
70
|
+
/** Options for {@link system}. */
|
|
71
|
+
export interface Options<S extends Schema.Any, Service extends ServiceDescriptor, Resource extends Schema.ResourceDescriptor<S>, When extends ReadonlyArray<Condition> = readonly [], Name extends string = string> {
|
|
54
72
|
/** The system name. */
|
|
55
|
-
readonly name:
|
|
73
|
+
readonly name: Name;
|
|
56
74
|
/** The service to read snapshots from; its value must have `snapshot()`. */
|
|
57
75
|
readonly source: Descriptor.Value<Service> extends Source<any> ? Service : "The source service must provide snapshot()";
|
|
58
76
|
/** The resource to write each snapshot into; its value type must be exactly the snapshot type. */
|
|
59
|
-
readonly resource: Resource
|
|
77
|
+
readonly resource: MatchingResource<Resource, Service>;
|
|
60
78
|
/**
|
|
61
79
|
* Run conditions, like a system's `when`. While they fail, snapshots are
|
|
62
80
|
* not taken, so presses stay in the device until capture resumes (for
|
|
@@ -64,13 +82,25 @@ export interface Options<S extends Schema.Any, Service extends ServiceDescriptor
|
|
|
64
82
|
*/
|
|
65
83
|
readonly when?: When;
|
|
66
84
|
}
|
|
67
|
-
/**
|
|
68
|
-
* The generated system. It requires the source service and the resource.
|
|
69
|
-
*/
|
|
70
|
-
export type CaptureSystem<S extends Schema.Any, Root, Needs extends ServiceDescriptor | ResourceDescriptor | ConditionNeedsFromConditions<ReadonlyArray<Condition>>> = Schema.BoundSystem<S, Root, any, never, string, Needs>;
|
|
71
85
|
/**
|
|
72
86
|
* Builds the system that writes `source.snapshot()` into `resource`.
|
|
73
87
|
*/
|
|
74
|
-
export declare const system: <S extends Schema.Any, Root, const Service extends ServiceDescriptor, const Resource extends Schema.ResourceDescriptor<S>, const When extends ReadonlyArray<Condition<Root>> = readonly []>(Game: Schema.Game<S, Root>, options: Options<S, Service, Resource, When>) =>
|
|
88
|
+
export declare const system: <S extends Schema.Any, Root, const Service extends ServiceDescriptor, const Resource extends Schema.ResourceDescriptor<S>, const When extends ReadonlyArray<Condition<Root>> = readonly [], const Name extends string = string>(Game: Schema.Game<S, Root>, options: Options<S, Service, Resource, When, Name>) => Schema.BoundSystem<S, Root, System.SystemSpec<S, {
|
|
89
|
+
readonly resources: {
|
|
90
|
+
input: System.ResourceWrite<Resource>;
|
|
91
|
+
};
|
|
92
|
+
readonly services: {
|
|
93
|
+
source: System.ServiceRead<Service, true>;
|
|
94
|
+
};
|
|
95
|
+
readonly when: When;
|
|
96
|
+
}, Root>, never, Name, System.SystemAccessNeeds<{
|
|
97
|
+
readonly resources: {
|
|
98
|
+
input: System.ResourceWrite<Resource>;
|
|
99
|
+
};
|
|
100
|
+
readonly services: {
|
|
101
|
+
source: System.ServiceRead<Service, true>;
|
|
102
|
+
};
|
|
103
|
+
readonly when: When;
|
|
104
|
+
}>>;
|
|
75
105
|
export {};
|
|
76
106
|
//# sourceMappingURL=InputCapture.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputCapture.d.ts","sourceRoot":"","sources":["../src/InputCapture.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"InputCapture.d.ts","sourceRoot":"","sources":["../src/InputCapture.ts"],"names":[],"mappings":"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"}
|
package/dist/InputCapture.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const system = (Game, options) => Game.System(options.name, {
|
|
5
5
|
resources: { input: Game.System.writeResource(options.resource) },
|
|
6
|
-
services: { source: Game.System.
|
|
6
|
+
services: { source: Game.System.consumeService(options.source) },
|
|
7
7
|
when: (options.when ?? [])
|
|
8
8
|
}, ({ resources, services }) => {
|
|
9
9
|
resources.input.set(services.source.snapshot());
|
package/dist/InputCapture.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputCapture.js","sourceRoot":"","sources":["../src/InputCapture.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InputCapture.js","sourceRoot":"","sources":["../src/InputCapture.ts"],"names":[],"mappings":"AAqGA;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAQpB,IAA0B,EAC1B,OAAkD,EAClD,EAAE,CACF,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE;IACxB,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,QAAoB,CAAC,EAAE;IAC7E,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,MAAiB,CAAC,EAAE;IAC3E,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAS;CACnC,EAAE,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC7B,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAW,CAAC,CAAA;AAC1D,CAAC,CAAC,CAAA"}
|