@diffenderfer-games/hub 2.0.0-next.0 → 2.0.0-next.10
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 +163 -0
- package/LICENSE +21 -21
- package/README.md +203 -139
- package/dist/auto.d.ts +8 -8
- package/dist/auto.js +3 -3
- package/dist/avatar-pixi.d.ts +165 -0
- package/dist/avatar-pixi.d.ts.map +1 -0
- package/dist/avatar-pixi.js +299 -0
- package/dist/avatar-pixi.js.map +1 -0
- package/dist/avatar-svg.d.ts +4 -0
- package/dist/avatar-svg.js +5 -0
- package/dist/avatar-three.d.ts +69 -0
- package/dist/avatar-three.d.ts.map +1 -0
- package/dist/avatar-three.js +49 -0
- package/dist/avatar-three.js.map +1 -0
- package/dist/avatar.d.ts +7 -0
- package/dist/avatar.js +500 -0
- package/dist/avatar.js.map +1 -0
- package/dist/daily.d.ts +2 -2
- package/dist/doctor/cli.mjs +119 -28
- package/dist/doctor/cli.mjs.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +3 -3
- package/dist/input.d.ts +2 -2
- package/dist/input.js +2 -2
- package/dist/mp.d.ts +3 -3
- package/dist/race.d.ts +1 -1
- package/dist/rooms.d.ts +3 -3
- package/dist/rooms.js +1 -1
- package/dist/shared/animator.d.ts +104 -0
- package/dist/shared/animator.d.ts.map +1 -0
- package/dist/shared/art.js +1946 -0
- package/dist/shared/art.js.map +1 -0
- package/dist/shared/atlas.d.ts +138 -0
- package/dist/shared/atlas.d.ts.map +1 -0
- package/dist/shared/avatar.d.ts +123 -0
- package/dist/shared/avatar.d.ts.map +1 -0
- package/dist/shared/bridge.js +18 -4
- package/dist/shared/bridge.js.map +1 -1
- package/dist/shared/client-version.gen.js +1 -1
- package/dist/shared/daily.d.ts +145 -19
- package/dist/shared/daily.d.ts.map +1 -1
- package/dist/shared/daily.js +138 -25
- package/dist/shared/daily.js.map +1 -1
- package/dist/shared/defineProperty.js +39 -0
- package/dist/shared/describe.d.ts +32 -0
- package/dist/shared/describe.d.ts.map +1 -0
- package/dist/shared/describe.js +109 -0
- package/dist/shared/describe.js.map +1 -0
- package/dist/shared/globals.js +9 -42
- package/dist/shared/globals.js.map +1 -1
- package/dist/shared/index.d.ts +1122 -46
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/input.d.ts +74 -14
- package/dist/shared/input.d.ts.map +1 -1
- package/dist/shared/input.js +179 -25
- package/dist/shared/input.js.map +1 -1
- package/dist/shared/json-guards.js +48 -0
- package/dist/shared/json-guards.js.map +1 -0
- package/dist/shared/latest-state.js +1 -1
- package/dist/shared/live-canvas.js +62 -0
- package/dist/shared/live-canvas.js.map +1 -0
- package/dist/shared/mp.js +10 -2
- package/dist/shared/mp.js.map +1 -1
- package/dist/shared/multiplayer-types.d.ts +15 -2
- package/dist/shared/multiplayer-types.d.ts.map +1 -1
- package/dist/shared/overlays.js +800 -0
- package/dist/shared/overlays.js.map +1 -0
- package/dist/shared/page-stack.js +2 -1
- package/dist/shared/page-stack.js.map +1 -1
- package/dist/shared/pose-key.js +249 -0
- package/dist/shared/pose-key.js.map +1 -0
- package/dist/shared/race-types.d.ts +1 -1
- package/dist/shared/race.js +1 -1
- package/dist/shared/room-types.d.ts +28 -3
- package/dist/shared/room-types.d.ts.map +1 -1
- package/dist/shared/rooms.d.ts.map +1 -1
- package/dist/shared/rooms.js +23 -4
- package/dist/shared/rooms.js.map +1 -1
- package/dist/shared/runtime-opener.js +1 -1
- package/dist/shared/scene.d.ts +90 -0
- package/dist/shared/scene.d.ts.map +1 -0
- package/dist/shared/social.d.ts +90 -9
- package/dist/shared/social.d.ts.map +1 -1
- package/dist/shared/social.js +6 -1
- package/dist/shared/social.js.map +1 -1
- package/dist/shared/src.js +4563 -667
- package/dist/shared/src.js.map +1 -1
- package/dist/shared/svg-markup.js +2354 -0
- package/dist/shared/svg-markup.js.map +1 -0
- package/dist/shared/svg.js +27 -0
- package/dist/shared/svg.js.map +1 -0
- package/dist/shared/types.d.ts +174 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/wire-types.d.ts +6 -2
- package/dist/shared/wire-types.d.ts.map +1 -1
- package/dist/social.d.ts +5 -5
- package/dist/social.js +2 -2
- package/dist/turns-rules.d.ts +2 -0
- package/dist/turns-rules.js +1 -0
- package/dist/turns.d.ts +61 -0
- package/dist/turns.d.ts.map +1 -0
- package/dist/turns.js +183 -0
- package/dist/turns.js.map +1 -0
- package/package.json +125 -89
- package/src/auto.ts +39 -39
- package/src/avatar/adapters/pixi-avatar.ts +73 -0
- package/src/avatar/adapters/pixi-crowd.ts +329 -0
- package/src/avatar/adapters/pixi-types.ts +84 -0
- package/src/avatar/adapters/three.ts +126 -0
- package/src/avatar/animator/animator.ts +285 -0
- package/src/avatar/animator/reactions.ts +44 -0
- package/src/avatar/animator/schedule.ts +73 -0
- package/src/avatar/art/beard.ts +49 -0
- package/src/avatar/art/glasses.ts +67 -0
- package/src/avatar/art/hair.ts +254 -0
- package/src/avatar/art/headwear.ts +75 -0
- package/src/avatar/art/index.ts +21 -0
- package/src/avatar/art/shape.ts +87 -0
- package/src/avatar/art-store.ts +36 -0
- package/src/avatar/atlas.ts +246 -0
- package/src/avatar/catalog-view.ts +14 -0
- package/src/avatar/colour.ts +109 -0
- package/src/avatar/describe.ts +79 -0
- package/src/avatar/face.ts +187 -0
- package/src/avatar/geom.ts +173 -0
- package/src/avatar/layout.ts +47 -0
- package/src/avatar/look-like.ts +52 -0
- package/src/avatar/outputs/bitmap.ts +75 -0
- package/src/avatar/outputs/canvas-paint.ts +177 -0
- package/src/avatar/outputs/canvas.ts +62 -0
- package/src/avatar/outputs/custom-element.ts +140 -0
- package/src/avatar/outputs/element.ts +58 -0
- package/src/avatar/outputs/live-canvas.ts +57 -0
- package/src/avatar/outputs/overlay-svg.ts +22 -0
- package/src/avatar/outputs/pose-key.ts +30 -0
- package/src/avatar/outputs/svg-markup.ts +113 -0
- package/src/avatar/outputs/svg.ts +41 -0
- package/src/avatar/overlays.ts +128 -0
- package/src/avatar/render/body.ts +116 -0
- package/src/avatar/render/colours.ts +81 -0
- package/src/avatar/render/compose.ts +320 -0
- package/src/avatar/render/context.ts +117 -0
- package/src/avatar/render/eyes.ts +78 -0
- package/src/avatar/render/eyewear.ts +118 -0
- package/src/avatar/render/frame.ts +73 -0
- package/src/avatar/render/head.ts +81 -0
- package/src/avatar/render/mouth.ts +86 -0
- package/src/avatar/render/props.ts +91 -0
- package/src/avatar/render/types.ts +93 -0
- package/src/avatar/render/walker-parts.ts +121 -0
- package/src/avatar/render/walker.ts +199 -0
- package/src/avatar/scene.ts +119 -0
- package/src/avatar-pixi.ts +20 -0
- package/src/avatar-svg.ts +21 -0
- package/src/avatar-three.ts +18 -0
- package/src/avatar.ts +63 -0
- package/src/core/avatar/avatar-cache.ts +95 -0
- package/src/core/avatar/avatar-ref.ts +34 -0
- package/src/core/avatar/avatar-types.ts +43 -0
- package/src/core/avatar/hub-avatar.ts +308 -0
- package/src/core/connection.ts +408 -299
- package/src/core/errors.ts +160 -147
- package/src/core/game-data.ts +40 -38
- package/src/core/hub-economy.ts +216 -179
- package/src/core/hub-progress.ts +269 -205
- package/src/core/hub.ts +352 -131
- package/src/core/menu-control.ts +61 -61
- package/src/core/offline/cloud-saves.ts +62 -0
- package/src/core/offline/events.ts +50 -50
- package/src/core/offline/favorites.ts +21 -21
- package/src/core/offline/hub-kinds/avatar-kind.ts +42 -0
- package/src/core/offline/hub-kinds/daily-kind.ts +68 -0
- package/src/core/offline/hub-kinds/economy-kinds.ts +86 -0
- package/src/core/offline/hub-kinds/game-fields.ts +2 -0
- package/src/core/offline/hub-kinds/index.ts +52 -0
- package/src/core/offline/hub-kinds/legacy-ops.ts +37 -0
- package/src/core/offline/hub-kinds/progress-kinds.ts +165 -0
- package/src/core/offline/hub-kinds/resume-kind.ts +108 -0
- package/src/core/offline/hub-kinds/saved-kind.ts +93 -0
- package/src/core/offline/kind-adapters.ts +48 -0
- package/src/core/offline/local-inventory.ts +64 -0
- package/src/core/offline/local-store.ts +304 -261
- package/src/core/offline/offline-api.ts +65 -0
- package/src/core/offline/outbox-entry.ts +59 -0
- package/src/core/offline/outbox-kinds.ts +78 -0
- package/src/core/offline/outbox-merge.ts +39 -0
- package/src/core/offline/outbox-replayer.ts +141 -0
- package/src/core/offline/outbox-store.ts +85 -0
- package/src/core/offline/outbox.ts +232 -0
- package/src/core/offline/queue.ts +126 -171
- package/src/core/offline/replay-lease.ts +87 -0
- package/src/core/offline/replay-policy.ts +52 -0
- package/src/core/page-account.ts +121 -0
- package/src/core/page.ts +87 -74
- package/src/core/rest/endpoint-types.ts +22 -22
- package/src/core/rest/rest-client.ts +163 -152
- package/src/core/rest/routes.gen.ts +144 -88
- package/src/core/resume/hub-resume.ts +286 -0
- package/src/core/resume/local-resume.ts +130 -0
- package/src/core/resume/resume-list.ts +65 -0
- package/src/core/resume/resume-request.ts +52 -0
- package/src/core/resume/resume-types.ts +64 -0
- package/src/core/saved/daily-saves.ts +196 -0
- package/src/core/saved/daily-seed.ts +16 -0
- package/src/core/saved/hub-saved.ts +221 -0
- package/src/core/saved/local-saved.ts +122 -0
- package/src/core/saved/saved-list.ts +129 -0
- package/src/core/saved/saved-open.ts +104 -0
- package/src/core/saved/saved-order.ts +49 -0
- package/src/core/saved/saved-types.ts +24 -0
- package/src/core/storage/json-guards.ts +80 -74
- package/src/core/storage/key-value.ts +66 -66
- package/src/core/ticket.ts +43 -43
- package/src/core/turns/hub-turns.ts +161 -0
- package/src/core/turns/turn-game.ts +510 -0
- package/src/core/turns/your-turn-buzz.ts +69 -0
- package/src/core/types.ts +134 -134
- package/src/core/version/client-version.gen.ts +2 -2
- package/src/core/version/hub-version.ts +62 -62
- package/src/core/version/semver.ts +97 -97
- package/src/daily/daily-system.ts +276 -161
- package/src/daily/page-daily.ts +36 -36
- package/src/daily/types.ts +105 -67
- package/src/daily.ts +10 -10
- package/src/doctor/checks.ts +86 -76
- package/src/doctor/cli.ts +101 -106
- package/src/doctor/hub-version-fetch.ts +43 -0
- package/src/doctor/tsconfig.json +12 -12
- package/src/doctor/world-check.ts +61 -0
- package/src/globals.ts +115 -110
- package/src/index.ts +68 -50
- package/src/input/device-state.ts +146 -146
- package/src/input/edges.ts +55 -55
- package/src/input/focus-ring.ts +13 -0
- package/src/input/gamepad.ts +61 -61
- package/src/input/input-events.ts +32 -32
- package/src/input/input-registry.ts +171 -164
- package/src/input/input-system.ts +406 -393
- package/src/input/legacy-controls.ts +64 -64
- package/src/input/modality.ts +122 -0
- package/src/input/nav-state.ts +200 -191
- package/src/input/navigator.ts +182 -171
- package/src/input/on-screen-controls.ts +101 -101
- package/src/input/page-control.ts +43 -43
- package/src/input/page-input.ts +193 -193
- package/src/input/player-remaps.ts +77 -77
- package/src/input/source-values.ts +116 -116
- package/src/input/spatial.ts +47 -47
- package/src/input/types.ts +331 -331
- package/src/input/zero-config.ts +164 -177
- package/src/input.ts +26 -22
- package/src/mp.ts +10 -10
- package/src/overlay/controls-panel.ts +163 -163
- package/src/overlay/dom.ts +46 -46
- package/src/overlay/layout-clusters.ts +162 -162
- package/src/overlay/layout-geometry.ts +136 -136
- package/src/overlay/layout.ts +203 -203
- package/src/overlay/listener-scope.ts +23 -23
- package/src/overlay/on-screen-keyboard.ts +137 -137
- package/src/overlay/overlay.ts +234 -208
- package/src/overlay/styles.ts +13 -12
- package/src/overlay/virtual-controls.ts +262 -262
- package/src/race.ts +10 -10
- package/src/realtime/bridge.ts +126 -121
- package/src/realtime/cross-bundle.ts +29 -29
- package/src/realtime/fallback-notice.ts +48 -48
- package/src/realtime/hub-link.ts +65 -65
- package/src/realtime/latest-state.ts +33 -33
- package/src/realtime/multiplayer-forwarder.ts +40 -28
- package/src/realtime/multiplayer-types.ts +66 -52
- package/src/realtime/page-runtime.ts +60 -60
- package/src/realtime/race-forwarder.ts +59 -59
- package/src/realtime/race-types.ts +132 -132
- package/src/realtime/room-types.ts +151 -125
- package/src/realtime/rooms-forwarder.ts +104 -79
- package/src/realtime/runtime-api.ts +74 -49
- package/src/realtime/runtime-opener.ts +61 -61
- package/src/realtime/social-forwarder.ts +77 -72
- package/src/realtime/social-types.ts +86 -78
- package/src/realtime/types.ts +54 -53
- package/src/realtime/wire-types.ts +79 -72
- package/src/realtime/world-types.ts +20 -0
- package/src/rooms.ts +10 -10
- package/src/social.ts +19 -18
- package/src/turns-kit/check-rules.ts +281 -0
- package/src/turns-rules.ts +12 -0
- package/src/turns.ts +14 -0
- package/src/types.ts +13 -13
- package/src/uistack/page-stack.ts +45 -45
- package/src/uistack/play-suspension.ts +82 -82
- package/src/uistack/types.ts +76 -76
- package/src/uistack/ui-stack.ts +144 -144
package/dist/turns.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { c as parseJsonText } from "./shared/json-guards.js";
|
|
2
|
+
import { createTurnRng, defineTurnRules, turnRngStateFromSeed } from "./turns-rules.js";
|
|
3
|
+
import { createTurnRng as createTurnRng$1, turnRngStateFromSeed as turnRngStateFromSeed$1 } from "@diffenderfer-games/hub-contract/turns-rules";
|
|
4
|
+
//#region src/turns-kit/check-rules.ts
|
|
5
|
+
/**
|
|
6
|
+
* The rules conformance kit (docs/multiplayer.md "Turn games: testing"):
|
|
7
|
+
* `checkTurnRules(rules, options)` plays many seeded games through a rules
|
|
8
|
+
* module the way the hub does and throws on the first broken promise:
|
|
9
|
+
*
|
|
10
|
+
* - every game reaches an outcome within `maxMoves`, and `toAct` is never
|
|
11
|
+
* empty before it; every seat in `toAct` gets to move (not only the
|
|
12
|
+
* first), and so do the seats in `mayAct` (out of turn: a jump-in, a
|
|
13
|
+
* catch) whose `autoReact` (or `options.reactMove`) has a move;
|
|
14
|
+
* - `toAct` and `mayAct` only name seats that exist;
|
|
15
|
+
* - the state survives a JSON round trip after every move, and the same seed
|
|
16
|
+
* plays the same game (no `Math.random`, no hidden globals);
|
|
17
|
+
* - `autoMove` and `autoReact` (when the rules have them) are always legal;
|
|
18
|
+
* - no seat's `view` or `eventView` shows another seat's secrets: markers
|
|
19
|
+
* planted with `options.plant` never appear in anyone else's view until
|
|
20
|
+
* the rules reveal them (`options.revealed`: a card played face up);
|
|
21
|
+
* - with `options.shuffleHidden` (the "twin table"): shuffling everything a
|
|
22
|
+
* seat may not see never changes that seat's view;
|
|
23
|
+
* - stored fixtures from older versions `migrate` to a state that views;
|
|
24
|
+
* - views, events and moves stay within the hub's size caps.
|
|
25
|
+
*
|
|
26
|
+
* It needs no hub: run it in a game's own unit tests (vitest, node:test).
|
|
27
|
+
*/
|
|
28
|
+
/** The hub's caps. */
|
|
29
|
+
const STATE_MAX_BYTES = 65536;
|
|
30
|
+
const MOVE_MAX_BYTES = 2048;
|
|
31
|
+
/** The UTF-8 bytes of a JSON text. */
|
|
32
|
+
function bytesOf(json) {
|
|
33
|
+
return new TextEncoder().encode(json).length;
|
|
34
|
+
}
|
|
35
|
+
/** Throw a kit failure. */
|
|
36
|
+
function fail(message) {
|
|
37
|
+
throw new Error(`checkTurnRules: ${message}`);
|
|
38
|
+
}
|
|
39
|
+
/** A JSON copy (what the hub stores and reads back). */
|
|
40
|
+
function roundTrip(value) {
|
|
41
|
+
const copy = parseJsonText(JSON.stringify(value));
|
|
42
|
+
if (copy === null && value !== null) fail("a state or move is not JSON");
|
|
43
|
+
return isGamesOwn(copy, value) ? copy : fail("a state or move is not JSON");
|
|
44
|
+
}
|
|
45
|
+
/** Always true: JSON a game's rules made is read back as the game's own type (the game vouches for it, as `toGameData` does). */
|
|
46
|
+
function isGamesOwn(_value, _like) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
/** A move for `seat`: the check's own chooser, else the rules' autoMove. */
|
|
50
|
+
function pickMove(rules, options, state, seat, rng) {
|
|
51
|
+
if (options.randomMove !== void 0) return options.randomMove(state, seat, rng);
|
|
52
|
+
if (rules.autoMove === void 0) return fail("the rules have no autoMove: pass options.randomMove");
|
|
53
|
+
return rules.autoMove(state, seat, rng);
|
|
54
|
+
}
|
|
55
|
+
/** An out-of-turn move for `seat`: the check's own chooser, else the rules' autoReact, else none. */
|
|
56
|
+
function pickReaction(rules, options, state, seat, rng) {
|
|
57
|
+
if (options.reactMove !== void 0) return options.reactMove(state, seat, rng);
|
|
58
|
+
return rules.autoReact?.(state, seat, rng) ?? null;
|
|
59
|
+
}
|
|
60
|
+
/** Fail unless every seat in `list` exists. */
|
|
61
|
+
function checkSeats(list, seats, what, seed) {
|
|
62
|
+
if (list.some((seat) => !Number.isInteger(seat) || seat < 0 || seat >= seats)) fail(`${what} named a seat that doesn't exist: [${list.join(", ")}] (seed ${String(seed)})`);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The next move of a game: half the time a seat in `mayAct` that has an
|
|
66
|
+
* out-of-turn move, else a seat in `toAct` (any of them, not only the
|
|
67
|
+
* first). The kit's own `pick` RNG chooses, so the game's RNG sees only
|
|
68
|
+
* the rules' own draws.
|
|
69
|
+
*/
|
|
70
|
+
function nextMove(rules, options, state, toAct, rng, pick) {
|
|
71
|
+
const optional = (rules.mayAct?.(state) ?? []).filter((seat) => !toAct.includes(seat));
|
|
72
|
+
if (optional.length > 0 && pick.int(2) === 0) {
|
|
73
|
+
const seat = pick.pick(optional);
|
|
74
|
+
const move = pickReaction(rules, options, state, seat, rng);
|
|
75
|
+
if (move !== null) return {
|
|
76
|
+
seat,
|
|
77
|
+
move,
|
|
78
|
+
by: options.reactMove === void 0 ? "autoReact" : "reactMove"
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const seat = toAct.length === 0 ? void 0 : pick.pick(toAct);
|
|
82
|
+
return seat === void 0 ? null : {
|
|
83
|
+
seat,
|
|
84
|
+
move: pickMove(rules, options, state, seat, rng),
|
|
85
|
+
by: options.randomMove === void 0 ? "autoMove" : "randomMove"
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Play one seeded game; answers its moves and a trace for the determinism check. */
|
|
89
|
+
function playGame(rules, seats, seed, options) {
|
|
90
|
+
const rng = createTurnRng$1(turnRngStateFromSeed$1(seed));
|
|
91
|
+
const pick = createTurnRng$1(turnRngStateFromSeed$1(seed ^ 1540483477));
|
|
92
|
+
const twinRng = createTurnRng$1(turnRngStateFromSeed$1(seed ^ 668265263));
|
|
93
|
+
const marker = `MARKER-${String(seed)}-`;
|
|
94
|
+
const markerOf = (owner) => `${marker}${String(owner)}`;
|
|
95
|
+
let state = rules.setup({
|
|
96
|
+
seats,
|
|
97
|
+
options: options.setupOptions ?? null,
|
|
98
|
+
mode: options.mode ?? null,
|
|
99
|
+
rng
|
|
100
|
+
});
|
|
101
|
+
if (options.plant !== void 0) for (let seat = 0; seat < seats; seat++) state = options.plant(state, seat, markerOf(seat));
|
|
102
|
+
const maxMoves = options.maxMoves ?? 2e3;
|
|
103
|
+
const trace = [];
|
|
104
|
+
let outOfTurn = 0;
|
|
105
|
+
/** The twin table: each seat's view is the same after what it can't see is shuffled. */
|
|
106
|
+
const checkTwin = () => {
|
|
107
|
+
if (options.shuffleHidden === void 0) return;
|
|
108
|
+
for (let viewer = 0; viewer < seats; viewer++) {
|
|
109
|
+
const real = JSON.stringify(rules.view(state, viewer));
|
|
110
|
+
if (JSON.stringify(rules.view(roundTrip(options.shuffleHidden(roundTrip(state), viewer, twinRng)), viewer)) !== real) fail(`seat ${String(viewer)}'s view changed when what it can't see was shuffled: it shows something hidden (seed ${String(seed)})`);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
/** The seats whose planted marker is still secret (the rules haven't revealed it). */
|
|
114
|
+
const secret = new Set(options.plant === void 0 ? [] : Array.from({ length: seats }, (_, seat) => seat));
|
|
115
|
+
const checkViews = (events) => {
|
|
116
|
+
for (const owner of secret) if (options.revealed?.(state, markerOf(owner)) === true) secret.delete(owner);
|
|
117
|
+
for (let viewer = 0; viewer < seats; viewer++) {
|
|
118
|
+
const seen = JSON.stringify(rules.view(state, viewer)) + JSON.stringify(events.map((event) => rules.eventView?.(event, viewer) ?? null));
|
|
119
|
+
for (const owner of secret) if (owner !== viewer && seen.includes(markerOf(owner))) fail(`seat ${String(viewer)} can see seat ${String(owner)}'s secret (seed ${String(seed)})`);
|
|
120
|
+
}
|
|
121
|
+
const shown = JSON.stringify(rules.view(state, null));
|
|
122
|
+
for (const owner of secret) if (shown.includes(markerOf(owner))) fail(`the public view shows seat ${String(owner)}'s secret (seed ${String(seed)})`);
|
|
123
|
+
checkTwin();
|
|
124
|
+
};
|
|
125
|
+
checkViews([]);
|
|
126
|
+
for (let moves = 0; moves < maxMoves; moves++) {
|
|
127
|
+
if (rules.outcome(state) !== null) return {
|
|
128
|
+
moves,
|
|
129
|
+
outOfTurn,
|
|
130
|
+
trace: trace.join("|")
|
|
131
|
+
};
|
|
132
|
+
const toAct = rules.toAct(state);
|
|
133
|
+
checkSeats(toAct, seats, "toAct", seed);
|
|
134
|
+
checkSeats(rules.mayAct?.(state) ?? [], seats, "mayAct", seed);
|
|
135
|
+
if (toAct.length === 0) fail(`toAct is empty but there is no outcome yet (seed ${String(seed)}, move ${String(moves)})`);
|
|
136
|
+
const next = nextMove(rules, options, state, toAct, rng, pick);
|
|
137
|
+
if (next === null) return fail(`no seat could move (seed ${String(seed)}, move ${String(moves)})`);
|
|
138
|
+
const { seat, move } = next;
|
|
139
|
+
outOfTurn += toAct.includes(seat) ? 0 : 1;
|
|
140
|
+
if (bytesOf(JSON.stringify(move)) > MOVE_MAX_BYTES) fail(`a move is over ${String(MOVE_MAX_BYTES)} bytes`);
|
|
141
|
+
const result = rules.apply(roundTrip(state), seat, roundTrip(move), rng);
|
|
142
|
+
if ("error" in result) fail(`${next.by} made an illegal move for seat ${String(seat)}: ${result.error} (seed ${String(seed)}, move ${String(moves)})`);
|
|
143
|
+
state = roundTrip(result.state);
|
|
144
|
+
if (bytesOf(JSON.stringify(state)) > STATE_MAX_BYTES) fail(`the state is over ${String(STATE_MAX_BYTES)} bytes`);
|
|
145
|
+
checkViews(result.events ?? []);
|
|
146
|
+
rules.progress(state, seat);
|
|
147
|
+
trace.push(`${String(seat)}:${JSON.stringify(move)}`);
|
|
148
|
+
}
|
|
149
|
+
return fail(`a game did not end within ${String(maxMoves)} moves (seed ${String(seed)})`);
|
|
150
|
+
}
|
|
151
|
+
/** Check a rules module (see the file comment); throws on the first failure. */
|
|
152
|
+
function checkTurnRules(rules, options = {}) {
|
|
153
|
+
if (!Number.isInteger(rules.version) || rules.version < 0) fail("rules.version must be a whole number");
|
|
154
|
+
let games = 0;
|
|
155
|
+
let moves = 0;
|
|
156
|
+
let longestGame = 0;
|
|
157
|
+
let outOfTurn = 0;
|
|
158
|
+
for (const seats of options.seats ?? [2]) for (let game = 0; game < (options.games ?? 25); game++) {
|
|
159
|
+
const seed = seats * 100003 + game;
|
|
160
|
+
const played = playGame(rules, seats, seed, options);
|
|
161
|
+
if (playGame(rules, seats, seed, options).trace !== played.trace) fail(`the same seed played a different game (seed ${String(seed)}): use the rng you are given, never Math.random`);
|
|
162
|
+
games += 1;
|
|
163
|
+
moves += played.moves;
|
|
164
|
+
longestGame = Math.max(longestGame, played.moves);
|
|
165
|
+
outOfTurn += played.outOfTurn;
|
|
166
|
+
}
|
|
167
|
+
for (const fixture of options.fixtures ?? []) if (fixture.version < rules.version) {
|
|
168
|
+
if (rules.migrate === void 0) fail(`a version ${String(fixture.version)} fixture needs rules.migrate`);
|
|
169
|
+
const migrated = rules.migrate(roundTrip(fixture.state), fixture.version);
|
|
170
|
+
rules.view(migrated, null);
|
|
171
|
+
rules.toAct(migrated);
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
games,
|
|
175
|
+
moves,
|
|
176
|
+
longestGame,
|
|
177
|
+
outOfTurn
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
//#endregion
|
|
181
|
+
export { checkTurnRules, createTurnRng, defineTurnRules, turnRngStateFromSeed };
|
|
182
|
+
|
|
183
|
+
//# sourceMappingURL=turns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turns.js","names":["createTurnRng","turnRngStateFromSeed"],"sources":["../src/turns-kit/check-rules.ts"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,89 +1,125 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@diffenderfer-games/hub",
|
|
3
|
-
"version": "2.0.0-next.
|
|
4
|
-
"description": "The diffenderfer.games hub client for games: accounts, saves, stats, leaderboards, inventory, daily challenges, the input system and the social/multiplayer forwarders, typed from the hub contract.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"sideEffects": [
|
|
8
|
-
"./dist/auto.js",
|
|
9
|
-
"./src/auto.ts"
|
|
10
|
-
],
|
|
11
|
-
"repository": {
|
|
12
|
-
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/diffenderfer-games/diffenderfer-games.git",
|
|
14
|
-
"directory": "
|
|
15
|
-
},
|
|
16
|
-
"engines": {
|
|
17
|
-
"node": ">=20"
|
|
18
|
-
},
|
|
19
|
-
"files": [
|
|
20
|
-
"dist",
|
|
21
|
-
"src",
|
|
22
|
-
"README.md",
|
|
23
|
-
"CHANGELOG.md",
|
|
24
|
-
"LICENSE"
|
|
25
|
-
],
|
|
26
|
-
"exports": {
|
|
27
|
-
".": {
|
|
28
|
-
"source": "./src/index.ts",
|
|
29
|
-
"types": "./dist/index.d.ts",
|
|
30
|
-
"default": "./dist/index.js"
|
|
31
|
-
},
|
|
32
|
-
"./input": {
|
|
33
|
-
"source": "./src/input.ts",
|
|
34
|
-
"types": "./dist/input.d.ts",
|
|
35
|
-
"default": "./dist/input.js"
|
|
36
|
-
},
|
|
37
|
-
"./daily": {
|
|
38
|
-
"source": "./src/daily.ts",
|
|
39
|
-
"types": "./dist/daily.d.ts",
|
|
40
|
-
"default": "./dist/daily.js"
|
|
41
|
-
},
|
|
42
|
-
"./race": {
|
|
43
|
-
"source": "./src/race.ts",
|
|
44
|
-
"types": "./dist/race.d.ts",
|
|
45
|
-
"default": "./dist/race.js"
|
|
46
|
-
},
|
|
47
|
-
"./social": {
|
|
48
|
-
"source": "./src/social.ts",
|
|
49
|
-
"types": "./dist/social.d.ts",
|
|
50
|
-
"default": "./dist/social.js"
|
|
51
|
-
},
|
|
52
|
-
"./mp": {
|
|
53
|
-
"source": "./src/mp.ts",
|
|
54
|
-
"types": "./dist/mp.d.ts",
|
|
55
|
-
"default": "./dist/mp.js"
|
|
56
|
-
},
|
|
57
|
-
"./rooms": {
|
|
58
|
-
"source": "./src/rooms.ts",
|
|
59
|
-
"types": "./dist/rooms.d.ts",
|
|
60
|
-
"default": "./dist/rooms.js"
|
|
61
|
-
},
|
|
62
|
-
"./
|
|
63
|
-
"source": "./src/
|
|
64
|
-
"types": "./dist/
|
|
65
|
-
"default": "./dist/
|
|
66
|
-
},
|
|
67
|
-
"./
|
|
68
|
-
"source": "./src/
|
|
69
|
-
"types": "./dist/
|
|
70
|
-
"default": "./dist/
|
|
71
|
-
},
|
|
72
|
-
"./
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
"
|
|
88
|
-
|
|
89
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@diffenderfer-games/hub",
|
|
3
|
+
"version": "2.0.0-next.10",
|
|
4
|
+
"description": "The diffenderfer.games hub client for games: accounts, saves, stats, leaderboards, inventory, daily challenges, the input system and the social/multiplayer forwarders, typed from the hub contract.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": [
|
|
8
|
+
"./dist/auto.js",
|
|
9
|
+
"./src/auto.ts"
|
|
10
|
+
],
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/diffenderfer-games/diffenderfer-games.git",
|
|
14
|
+
"directory": "packages/public/hub"
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=20"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"src",
|
|
22
|
+
"README.md",
|
|
23
|
+
"CHANGELOG.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"source": "./src/index.ts",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./input": {
|
|
33
|
+
"source": "./src/input.ts",
|
|
34
|
+
"types": "./dist/input.d.ts",
|
|
35
|
+
"default": "./dist/input.js"
|
|
36
|
+
},
|
|
37
|
+
"./daily": {
|
|
38
|
+
"source": "./src/daily.ts",
|
|
39
|
+
"types": "./dist/daily.d.ts",
|
|
40
|
+
"default": "./dist/daily.js"
|
|
41
|
+
},
|
|
42
|
+
"./race": {
|
|
43
|
+
"source": "./src/race.ts",
|
|
44
|
+
"types": "./dist/race.d.ts",
|
|
45
|
+
"default": "./dist/race.js"
|
|
46
|
+
},
|
|
47
|
+
"./social": {
|
|
48
|
+
"source": "./src/social.ts",
|
|
49
|
+
"types": "./dist/social.d.ts",
|
|
50
|
+
"default": "./dist/social.js"
|
|
51
|
+
},
|
|
52
|
+
"./mp": {
|
|
53
|
+
"source": "./src/mp.ts",
|
|
54
|
+
"types": "./dist/mp.d.ts",
|
|
55
|
+
"default": "./dist/mp.js"
|
|
56
|
+
},
|
|
57
|
+
"./rooms": {
|
|
58
|
+
"source": "./src/rooms.ts",
|
|
59
|
+
"types": "./dist/rooms.d.ts",
|
|
60
|
+
"default": "./dist/rooms.js"
|
|
61
|
+
},
|
|
62
|
+
"./turns": {
|
|
63
|
+
"source": "./src/turns.ts",
|
|
64
|
+
"types": "./dist/turns.d.ts",
|
|
65
|
+
"default": "./dist/turns.js"
|
|
66
|
+
},
|
|
67
|
+
"./turns-rules": {
|
|
68
|
+
"source": "./src/turns-rules.ts",
|
|
69
|
+
"types": "./dist/turns-rules.d.ts",
|
|
70
|
+
"default": "./dist/turns-rules.js"
|
|
71
|
+
},
|
|
72
|
+
"./types": {
|
|
73
|
+
"source": "./src/types.ts",
|
|
74
|
+
"types": "./dist/types.d.ts",
|
|
75
|
+
"default": "./dist/types.js"
|
|
76
|
+
},
|
|
77
|
+
"./avatar": {
|
|
78
|
+
"source": "./src/avatar.ts",
|
|
79
|
+
"types": "./dist/avatar.d.ts",
|
|
80
|
+
"default": "./dist/avatar.js"
|
|
81
|
+
},
|
|
82
|
+
"./avatar/pixi": {
|
|
83
|
+
"source": "./src/avatar-pixi.ts",
|
|
84
|
+
"types": "./dist/avatar-pixi.d.ts",
|
|
85
|
+
"default": "./dist/avatar-pixi.js"
|
|
86
|
+
},
|
|
87
|
+
"./avatar/three": {
|
|
88
|
+
"source": "./src/avatar-three.ts",
|
|
89
|
+
"types": "./dist/avatar-three.d.ts",
|
|
90
|
+
"default": "./dist/avatar-three.js"
|
|
91
|
+
},
|
|
92
|
+
"./avatar/svg": {
|
|
93
|
+
"source": "./src/avatar-svg.ts",
|
|
94
|
+
"types": "./dist/avatar-svg.d.ts",
|
|
95
|
+
"default": "./dist/avatar-svg.js"
|
|
96
|
+
},
|
|
97
|
+
"./auto": {
|
|
98
|
+
"source": "./src/auto.ts",
|
|
99
|
+
"types": "./dist/auto.d.ts",
|
|
100
|
+
"default": "./dist/auto.js"
|
|
101
|
+
},
|
|
102
|
+
"./package.json": "./package.json"
|
|
103
|
+
},
|
|
104
|
+
"types": "./dist/index.d.ts",
|
|
105
|
+
"bin": {
|
|
106
|
+
"hub-doctor": "dist/doctor/cli.mjs"
|
|
107
|
+
},
|
|
108
|
+
"scripts": {
|
|
109
|
+
"build": "tsx --conditions=source ../../../tools/hub-client/generate-cli.ts && tsdown",
|
|
110
|
+
"typecheck": "tsc -p tsconfig.json"
|
|
111
|
+
},
|
|
112
|
+
"dependencies": {
|
|
113
|
+
"@ayepi/core": "0.4.1",
|
|
114
|
+
"@diffenderfer-games/hub-contract": "2.0.0-next.10",
|
|
115
|
+
"@diffenderfer-games/world": "2.0.0-next.10"
|
|
116
|
+
},
|
|
117
|
+
"publishConfig": {
|
|
118
|
+
"access": "public"
|
|
119
|
+
},
|
|
120
|
+
"devDependencies": {
|
|
121
|
+
"@types/three": "0.186.0",
|
|
122
|
+
"pixi.js": "8.19.0",
|
|
123
|
+
"three": "0.186.1"
|
|
124
|
+
}
|
|
125
|
+
}
|
package/src/auto.ts
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `@diffenderfer-games/hub/auto`: everything the main entry exports, plus a
|
|
3
|
-
* side effect: it installs `window.HubSDK` (`{ hub, createHub, Hub, HubError,
|
|
4
|
-
* OfflineError, ContentRejectedError }`), exactly as the v1 `/_hub/hub.js`
|
|
5
|
-
* did. The host builds `/_hub/hub.js` from this entry, for games without a
|
|
6
|
-
* build step (`import('/_hub/hub.js')` or `window.HubSDK.hub`).
|
|
7
|
-
*
|
|
8
|
-
* @packageDocumentation
|
|
9
|
-
*/
|
|
10
|
-
import { ContentRejectedError, createHub, Hub, hub, HubError, OfflineError } from './index';
|
|
11
|
-
|
|
12
|
-
export * from './index';
|
|
13
|
-
|
|
14
|
-
/** What `window.HubSDK` holds. */
|
|
15
|
-
export interface HubSdkGlobal {
|
|
16
|
-
/** The page's client. */
|
|
17
|
-
readonly hub: Hub;
|
|
18
|
-
/** Create another client. */
|
|
19
|
-
readonly createHub: typeof createHub;
|
|
20
|
-
/** The client class. */
|
|
21
|
-
readonly Hub: typeof Hub;
|
|
22
|
-
/** The base error class. */
|
|
23
|
-
readonly HubError: typeof HubError;
|
|
24
|
-
/** The offline error class. */
|
|
25
|
-
readonly OfflineError: typeof OfflineError;
|
|
26
|
-
/** The content-rejected error class. */
|
|
27
|
-
readonly ContentRejectedError: typeof ContentRejectedError;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
declare global {
|
|
31
|
-
interface Window {
|
|
32
|
-
/** The hub client for games without a build step (installed by `@diffenderfer-games/hub/auto`). */
|
|
33
|
-
HubSDK?: HubSdkGlobal;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (typeof window !== 'undefined') {
|
|
38
|
-
window.HubSDK = { hub, createHub, Hub, HubError, OfflineError, ContentRejectedError };
|
|
39
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* `@diffenderfer-games/hub/auto`: everything the main entry exports, plus a
|
|
3
|
+
* side effect: it installs `window.HubSDK` (`{ hub, createHub, Hub, HubError,
|
|
4
|
+
* OfflineError, ContentRejectedError }`), exactly as the v1 `/_hub/hub.js`
|
|
5
|
+
* did. The host builds `/_hub/hub.js` from this entry, for games without a
|
|
6
|
+
* build step (`import('/_hub/hub.js')` or `window.HubSDK.hub`).
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import { ContentRejectedError, createHub, Hub, hub, HubError, OfflineError } from './index';
|
|
11
|
+
|
|
12
|
+
export * from './index';
|
|
13
|
+
|
|
14
|
+
/** What `window.HubSDK` holds. */
|
|
15
|
+
export interface HubSdkGlobal {
|
|
16
|
+
/** The page's client. */
|
|
17
|
+
readonly hub: Hub;
|
|
18
|
+
/** Create another client. */
|
|
19
|
+
readonly createHub: typeof createHub;
|
|
20
|
+
/** The client class. */
|
|
21
|
+
readonly Hub: typeof Hub;
|
|
22
|
+
/** The base error class. */
|
|
23
|
+
readonly HubError: typeof HubError;
|
|
24
|
+
/** The offline error class. */
|
|
25
|
+
readonly OfflineError: typeof OfflineError;
|
|
26
|
+
/** The content-rejected error class. */
|
|
27
|
+
readonly ContentRejectedError: typeof ContentRejectedError;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare global {
|
|
31
|
+
interface Window {
|
|
32
|
+
/** The hub client for games without a build step (installed by `@diffenderfer-games/hub/auto`). */
|
|
33
|
+
HubSDK?: HubSdkGlobal;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (typeof window !== 'undefined') {
|
|
38
|
+
window.HubSDK = { hub, createHub, Hub, HubError, OfflineError, ContentRejectedError };
|
|
39
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One live avatar in Pixi (§3.8): a sprite backed by a canvas that redraws
|
|
3
|
+
* only when the pose changes, so a dozen animated faces stay cheap. Pass the
|
|
4
|
+
* game's pixi namespace; the hub never imports pixi.
|
|
5
|
+
*/
|
|
6
|
+
import type { Animator } from '../animator/animator';
|
|
7
|
+
import { drawToCanvas } from '../outputs/bitmap';
|
|
8
|
+
import { liveCanvas } from '../outputs/live-canvas';
|
|
9
|
+
import type { LookLike, Pose, RenderOptions } from '../render/types';
|
|
10
|
+
import { refresh, type PixiNs, type PixiRectangle, type PixiSprite, type PixiTexture } from './pixi-types';
|
|
11
|
+
|
|
12
|
+
/** Options for {@link pixiAvatar}. */
|
|
13
|
+
export interface PixiAvatarOptions extends RenderOptions {
|
|
14
|
+
/** Drives the face each `update(t)`; without one the avatar is still. */
|
|
15
|
+
readonly animator?: Animator;
|
|
16
|
+
/** Texture pixels per CSS pixel (default 2). */
|
|
17
|
+
readonly resolution?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** A live Pixi avatar; `view` is the game's own pixi `Sprite`. */
|
|
21
|
+
export interface PixiAvatar<TSprite extends PixiSprite = PixiSprite> {
|
|
22
|
+
/** The sprite to add to the stage (anchored at its centre). */
|
|
23
|
+
readonly view: TSprite;
|
|
24
|
+
/** Renders the animator's pose at `t` (or a given pose). */
|
|
25
|
+
update(t: number | Pose): void;
|
|
26
|
+
/** Swaps the look. */
|
|
27
|
+
setLook(like: LookLike): void;
|
|
28
|
+
destroy(): void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** A live avatar sprite: `pixiAvatar(pixi, seat.look, { size: 64, animator })`. */
|
|
32
|
+
export function pixiAvatar<TTexture extends PixiTexture, TSprite extends PixiSprite<TTexture>, TRectangle extends PixiRectangle>(
|
|
33
|
+
pixi: PixiNs<TTexture, TSprite, TRectangle>,
|
|
34
|
+
like: LookLike,
|
|
35
|
+
opts: PixiAvatarOptions = {},
|
|
36
|
+
): PixiAvatar<TSprite> {
|
|
37
|
+
const resolution = opts.resolution ?? 2;
|
|
38
|
+
const live = liveCanvas(like, opts, resolution);
|
|
39
|
+
live.draw(opts.pose);
|
|
40
|
+
const texture = pixi.Texture.from(live.canvas);
|
|
41
|
+
const view = new pixi.Sprite(texture);
|
|
42
|
+
view.anchor.set(0.5);
|
|
43
|
+
view.scale.set(1 / resolution);
|
|
44
|
+
return {
|
|
45
|
+
view,
|
|
46
|
+
update(t) {
|
|
47
|
+
const pose = typeof t === 'number' ? opts.animator?.pose(t) : t;
|
|
48
|
+
if (live.draw(pose ?? opts.pose)) {
|
|
49
|
+
refresh(texture);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
setLook(next) {
|
|
53
|
+
live.setLook(next);
|
|
54
|
+
opts.animator?.setLook(next);
|
|
55
|
+
if (live.draw(opts.pose)) {
|
|
56
|
+
refresh(texture);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
destroy() {
|
|
60
|
+
view.destroy();
|
|
61
|
+
texture.destroy(true);
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** A still avatar texture (Pixi 7 games use this from a bitmap-like canvas). */
|
|
67
|
+
export function avatarTexture<TTexture extends PixiTexture, TSprite extends PixiSprite<TTexture>, TRectangle extends PixiRectangle>(
|
|
68
|
+
pixi: PixiNs<TTexture, TSprite, TRectangle>,
|
|
69
|
+
like: LookLike,
|
|
70
|
+
opts: RenderOptions = {},
|
|
71
|
+
): TTexture {
|
|
72
|
+
return pixi.Texture.from(drawToCanvas(like, opts));
|
|
73
|
+
}
|