@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
|
@@ -1,132 +1,132 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Races as games see them through `hub.race` (docs/plans/race.md): a hub
|
|
3
|
-
* room with a referee. Everyone gets the same puzzle (shared seed and
|
|
4
|
-
* params), live status, and the first valid finish wins.
|
|
5
|
-
*/
|
|
6
|
-
import type { RaceParams, RaceResult, RaceStats, RoomInfo } from '@diffenderfer-games/hub-contract';
|
|
7
|
-
import type { RaceHistory, RaceStatusEvent } from './wire-types';
|
|
8
|
-
import type { JoinOptions } from './room-types';
|
|
9
|
-
|
|
10
|
-
/** What a race game's `start` receives: build the puzzle from `seed` and `params`. */
|
|
11
|
-
export interface RaceStart {
|
|
12
|
-
/** The race room. */
|
|
13
|
-
roomId: string;
|
|
14
|
-
/** 1 for the first race in the room, +1 per rematch. */
|
|
15
|
-
round: number;
|
|
16
|
-
/** The shared seed, revealed at the countdown. */
|
|
17
|
-
seed: number;
|
|
18
|
-
/** The creator's choices. */
|
|
19
|
-
params: RaceParams;
|
|
20
|
-
/** The go, on THIS page's clock (`Date.now()` ms). The hub draws the 3-2-1. */
|
|
21
|
-
startAt: number;
|
|
22
|
-
/** Racer user ids. */
|
|
23
|
-
players: number[];
|
|
24
|
-
/** Watching: don't let a spectator play. */
|
|
25
|
-
spectator: boolean;
|
|
26
|
-
/** A re-join after a reload or reconnect (the race was already running). */
|
|
27
|
-
resumed: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Options for `hub.race.create`. */
|
|
31
|
-
export interface RaceCreateOptions {
|
|
32
|
-
/** The race params (defaults from the manifest). */
|
|
33
|
-
params?: RaceParams;
|
|
34
|
-
/** Public (default true): shows in Open races and can alert friends who follow the game. */
|
|
35
|
-
public?: boolean;
|
|
36
|
-
/** Seats (default the manifest's minimum). The race starts when they're all filled. */
|
|
37
|
-
maxPlayers?: number;
|
|
38
|
-
/** Race this party. */
|
|
39
|
-
partyId?: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Where the hub's race HUD sits. */
|
|
43
|
-
export type RaceHudPlace = 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
44
|
-
|
|
45
|
-
/** `hub.race.define`: how the hub drives a race game. */
|
|
46
|
-
export interface RaceDefinition {
|
|
47
|
-
/** The countdown began: build the puzzle from `seed` and `params` now and let the player move at `startAt`. */
|
|
48
|
-
start(race: RaceStart): void;
|
|
49
|
-
/** The race was decided (stop input; the hub shows the result card). */
|
|
50
|
-
end?(result: RaceResult): void;
|
|
51
|
-
/** The player left the race screen (Done, cancelled, the room closed): go back to your menu. */
|
|
52
|
-
exit?(): void;
|
|
53
|
-
/** The hub's live race HUD (default on, top). `false` if you draw your own from `hub.race.on('status')`. */
|
|
54
|
-
hud?: false | { place?: RaceHudPlace };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** Events `hub.race.on` delivers, name → payload. */
|
|
58
|
-
export interface RaceEvents {
|
|
59
|
-
/** The race room changed (roster, phase, statuses folded in). */
|
|
60
|
-
room: RoomInfo;
|
|
61
|
-
/** The countdown began. */
|
|
62
|
-
start: RaceStart;
|
|
63
|
-
/** Another racer's live status. */
|
|
64
|
-
status: RaceStatusEvent;
|
|
65
|
-
/** The race was decided. */
|
|
66
|
-
result: RaceResult;
|
|
67
|
-
/** The race room is gone for this page (left, closed, kicked). */
|
|
68
|
-
closed: { reason: string };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** Filters for the race history. */
|
|
72
|
-
export interface RaceHistoryQuery {
|
|
73
|
-
/** A game slug (default: every game). */
|
|
74
|
-
game?: string;
|
|
75
|
-
/** Only races with this player. */
|
|
76
|
-
with?: number;
|
|
77
|
-
/** Only races older than this race id (paging). */
|
|
78
|
-
before?: number;
|
|
79
|
-
/** Page size, 1 to 50. */
|
|
80
|
-
limit?: number;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** Options for `hub.race.openHistory`. */
|
|
84
|
-
export interface RaceHistoryViewOptions {
|
|
85
|
-
/** This game (default), another slug, or `null` for every game. */
|
|
86
|
-
game?: string | null;
|
|
87
|
-
/** Only races with this player. */
|
|
88
|
-
with?: number;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* `hub.race`: races (docs/multiplayer.md "Races"). Declare `game.race` in
|
|
93
|
-
* package.json, call `define` at boot, put a Race button on your menu that
|
|
94
|
-
* calls `create({ params })` (or `browse()`), and report `status`, `finish`
|
|
95
|
-
* and `lose`. The hub does the matching, the waiting card, invites, the
|
|
96
|
-
* countdown, the live HUD, the referee, the result card and the history.
|
|
97
|
-
*/
|
|
98
|
-
export interface HubRaceApi {
|
|
99
|
-
/** Register how the hub starts and ends your race. Call once at boot (works before the runtime loads). */
|
|
100
|
-
define(definition: RaceDefinition): void;
|
|
101
|
-
/** Create a race (you're seated; the hub shows the waiting card). Rejects with `HubError` or `OfflineError`. */
|
|
102
|
-
create(options?: RaceCreateOptions): Promise<RoomInfo>;
|
|
103
|
-
/** Join a race by its 5-character code (or watch: `{ spectate: true }`). */
|
|
104
|
-
join(code: string, options?: JoinOptions): Promise<RoomInfo>;
|
|
105
|
-
/** Public races in this game waiting for racers. */
|
|
106
|
-
list(): Promise<RoomInfo[]>;
|
|
107
|
-
/** Open the hub's "Open races" sheet (join one, or type a code). */
|
|
108
|
-
browse(): void;
|
|
109
|
-
/** Open the hub's race history (this game by default). */
|
|
110
|
-
openHistory(options?: RaceHistoryViewOptions): void;
|
|
111
|
-
/** The signed-in player's races. */
|
|
112
|
-
history(query?: RaceHistoryQuery): Promise<RaceHistory>;
|
|
113
|
-
/** Live stats for the HUD (and optional 0..1 progress). Throttled and coalesced: call it on every change. */
|
|
114
|
-
status(stats: RaceStats, progress?: number): void;
|
|
115
|
-
/** I finished: resolves with the result if I won, `null` if someone was first. */
|
|
116
|
-
finish(stats?: RaceStats): Promise<RaceResult | null>;
|
|
117
|
-
/** I'm out (game over, no lives): the others race on, the last one in wins. */
|
|
118
|
-
lose(stats?: RaceStats): Promise<void>;
|
|
119
|
-
/** Give up. */
|
|
120
|
-
forfeit(): Promise<void>;
|
|
121
|
-
/** Leave the race room (a forfeit if it's running). */
|
|
122
|
-
leave(): Promise<void>;
|
|
123
|
-
/** Ask for another round after a race. */
|
|
124
|
-
rematch(params?: RaceParams): Promise<void>;
|
|
125
|
-
/** The race room this page is in (its `RoomInfo` has `race`), or `null`. */
|
|
126
|
-
current(): RoomInfo | null;
|
|
127
|
-
/** Subscribe to race events; works before the runtime loads. Returns the unsubscribe function. */
|
|
128
|
-
on<Name extends keyof RaceEvents>(event: Name, listener: (payload: RaceEvents[Name]) => void): () => void;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** What the runtime's `race` section implements (the same surface `hub.race` forwards). */
|
|
132
|
-
export type RaceRuntimeApi = HubRaceApi;
|
|
1
|
+
/**
|
|
2
|
+
* Races as games see them through `hub.race` (docs/plans/race.md): a hub
|
|
3
|
+
* room with a referee. Everyone gets the same puzzle (shared seed and
|
|
4
|
+
* params), live status, and the first valid finish wins.
|
|
5
|
+
*/
|
|
6
|
+
import type { RaceParams, RaceResult, RaceStats, RoomInfo } from '@diffenderfer-games/hub-contract';
|
|
7
|
+
import type { RaceHistory, RaceStatusEvent } from './wire-types';
|
|
8
|
+
import type { JoinOptions } from './room-types';
|
|
9
|
+
|
|
10
|
+
/** What a race game's `start` receives: build the puzzle from `seed` and `params`. */
|
|
11
|
+
export interface RaceStart {
|
|
12
|
+
/** The race room. */
|
|
13
|
+
roomId: string;
|
|
14
|
+
/** 1 for the first race in the room, +1 per rematch. */
|
|
15
|
+
round: number;
|
|
16
|
+
/** The shared seed, revealed at the countdown. */
|
|
17
|
+
seed: number;
|
|
18
|
+
/** The creator's choices. */
|
|
19
|
+
params: RaceParams;
|
|
20
|
+
/** The go, on THIS page's clock (`Date.now()` ms). The hub draws the 3-2-1. */
|
|
21
|
+
startAt: number;
|
|
22
|
+
/** Racer user ids. */
|
|
23
|
+
players: number[];
|
|
24
|
+
/** Watching: don't let a spectator play. */
|
|
25
|
+
spectator: boolean;
|
|
26
|
+
/** A re-join after a reload or reconnect (the race was already running). */
|
|
27
|
+
resumed: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Options for `hub.race.create`. */
|
|
31
|
+
export interface RaceCreateOptions {
|
|
32
|
+
/** The race params (defaults from the manifest). */
|
|
33
|
+
params?: RaceParams;
|
|
34
|
+
/** Public (default true): shows in Open races and can alert friends who follow the game. */
|
|
35
|
+
public?: boolean;
|
|
36
|
+
/** Seats (default the manifest's minimum). The race starts when they're all filled. */
|
|
37
|
+
maxPlayers?: number;
|
|
38
|
+
/** Race this party. */
|
|
39
|
+
partyId?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Where the hub's race HUD sits. */
|
|
43
|
+
export type RaceHudPlace = 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
44
|
+
|
|
45
|
+
/** `hub.race.define`: how the hub drives a race game. */
|
|
46
|
+
export interface RaceDefinition {
|
|
47
|
+
/** The countdown began: build the puzzle from `seed` and `params` now and let the player move at `startAt`. */
|
|
48
|
+
start(race: RaceStart): void;
|
|
49
|
+
/** The race was decided (stop input; the hub shows the result card). */
|
|
50
|
+
end?(result: RaceResult): void;
|
|
51
|
+
/** The player left the race screen (Done, cancelled, the room closed): go back to your menu. */
|
|
52
|
+
exit?(): void;
|
|
53
|
+
/** The hub's live race HUD (default on, top). `false` if you draw your own from `hub.race.on('status')`. */
|
|
54
|
+
hud?: false | { place?: RaceHudPlace };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Events `hub.race.on` delivers, name → payload. */
|
|
58
|
+
export interface RaceEvents {
|
|
59
|
+
/** The race room changed (roster, phase, statuses folded in). */
|
|
60
|
+
room: RoomInfo;
|
|
61
|
+
/** The countdown began. */
|
|
62
|
+
start: RaceStart;
|
|
63
|
+
/** Another racer's live status. */
|
|
64
|
+
status: RaceStatusEvent;
|
|
65
|
+
/** The race was decided. */
|
|
66
|
+
result: RaceResult;
|
|
67
|
+
/** The race room is gone for this page (left, closed, kicked). */
|
|
68
|
+
closed: { reason: string };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Filters for the race history. */
|
|
72
|
+
export interface RaceHistoryQuery {
|
|
73
|
+
/** A game slug (default: every game). */
|
|
74
|
+
game?: string;
|
|
75
|
+
/** Only races with this player. */
|
|
76
|
+
with?: number;
|
|
77
|
+
/** Only races older than this race id (paging). */
|
|
78
|
+
before?: number;
|
|
79
|
+
/** Page size, 1 to 50. */
|
|
80
|
+
limit?: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Options for `hub.race.openHistory`. */
|
|
84
|
+
export interface RaceHistoryViewOptions {
|
|
85
|
+
/** This game (default), another slug, or `null` for every game. */
|
|
86
|
+
game?: string | null;
|
|
87
|
+
/** Only races with this player. */
|
|
88
|
+
with?: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* `hub.race`: races (docs/multiplayer.md "Races"). Declare `game.race` in
|
|
93
|
+
* package.json, call `define` at boot, put a Race button on your menu that
|
|
94
|
+
* calls `create({ params })` (or `browse()`), and report `status`, `finish`
|
|
95
|
+
* and `lose`. The hub does the matching, the waiting card, invites, the
|
|
96
|
+
* countdown, the live HUD, the referee, the result card and the history.
|
|
97
|
+
*/
|
|
98
|
+
export interface HubRaceApi {
|
|
99
|
+
/** Register how the hub starts and ends your race. Call once at boot (works before the runtime loads). */
|
|
100
|
+
define(definition: RaceDefinition): void;
|
|
101
|
+
/** Create a race (you're seated; the hub shows the waiting card). Rejects with `HubError` or `OfflineError`. */
|
|
102
|
+
create(options?: RaceCreateOptions): Promise<RoomInfo>;
|
|
103
|
+
/** Join a race by its 5-character code (or watch: `{ spectate: true }`). */
|
|
104
|
+
join(code: string, options?: JoinOptions): Promise<RoomInfo>;
|
|
105
|
+
/** Public races in this game waiting for racers. */
|
|
106
|
+
list(): Promise<RoomInfo[]>;
|
|
107
|
+
/** Open the hub's "Open races" sheet (join one, or type a code). */
|
|
108
|
+
browse(): void;
|
|
109
|
+
/** Open the hub's race history (this game by default). */
|
|
110
|
+
openHistory(options?: RaceHistoryViewOptions): void;
|
|
111
|
+
/** The signed-in player's races. */
|
|
112
|
+
history(query?: RaceHistoryQuery): Promise<RaceHistory>;
|
|
113
|
+
/** Live stats for the HUD (and optional 0..1 progress). Throttled and coalesced: call it on every change. */
|
|
114
|
+
status(stats: RaceStats, progress?: number): void;
|
|
115
|
+
/** I finished: resolves with the result if I won, `null` if someone was first. */
|
|
116
|
+
finish(stats?: RaceStats): Promise<RaceResult | null>;
|
|
117
|
+
/** I'm out (game over, no lives): the others race on, the last one in wins. */
|
|
118
|
+
lose(stats?: RaceStats): Promise<void>;
|
|
119
|
+
/** Give up. */
|
|
120
|
+
forfeit(): Promise<void>;
|
|
121
|
+
/** Leave the race room (a forfeit if it's running). */
|
|
122
|
+
leave(): Promise<void>;
|
|
123
|
+
/** Ask for another round after a race. */
|
|
124
|
+
rematch(params?: RaceParams): Promise<void>;
|
|
125
|
+
/** The race room this page is in (its `RoomInfo` has `race`), or `null`. */
|
|
126
|
+
current(): RoomInfo | null;
|
|
127
|
+
/** Subscribe to race events; works before the runtime loads. Returns the unsubscribe function. */
|
|
128
|
+
on<Name extends keyof RaceEvents>(event: Name, listener: (payload: RaceEvents[Name]) => void): () => void;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** What the runtime's `race` section implements (the same surface `hub.race` forwards). */
|
|
132
|
+
export type RaceRuntimeApi = HubRaceApi;
|
|
@@ -1,125 +1,151 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hub relay rooms as games see them through `hub.rooms`: realtime
|
|
3
|
-
* multiplayer for static games, relayed (never refereed) by the hub.
|
|
4
|
-
*/
|
|
5
|
-
import type { Json, RoomInfo } from '@diffenderfer-games/hub-contract';
|
|
6
|
-
import type { RoomChatLine, RoomMessage } from './wire-types';
|
|
7
|
-
|
|
8
|
-
/** The shared room state (a JSON object, at most 32 KB). */
|
|
9
|
-
export type RoomState = Record<string, Json>;
|
|
10
|
-
|
|
11
|
-
/** Options for `hub.rooms.create`. `game` defaults to the current slug. */
|
|
12
|
-
export interface RoomCreateOptions {
|
|
13
|
-
/** The game slug (default: this page's game). */
|
|
14
|
-
game?: string;
|
|
15
|
-
/** The game mode. */
|
|
16
|
-
mode?: string;
|
|
17
|
-
/** Listed in `hub.rooms.list` (default false). */
|
|
18
|
-
public?: boolean;
|
|
19
|
-
/** Seats. */
|
|
20
|
-
maxPlayers?: number;
|
|
21
|
-
/** `host` (default): guests' unaddressed sends reach the host only. `relay`: everyone hears every send. */
|
|
22
|
-
model?: 'host' | 'relay';
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
|
|
125
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Hub relay rooms as games see them through `hub.rooms`: realtime
|
|
3
|
+
* multiplayer for static games, relayed (never refereed) by the hub.
|
|
4
|
+
*/
|
|
5
|
+
import type { Json, RoomInfo } from '@diffenderfer-games/hub-contract';
|
|
6
|
+
import type { RoomChatLine, RoomMessage, RoomSeat, RoomSeatChange } from './wire-types';
|
|
7
|
+
|
|
8
|
+
/** The shared room state (a JSON object, at most 32 KB). */
|
|
9
|
+
export type RoomState = Record<string, Json>;
|
|
10
|
+
|
|
11
|
+
/** Options for `hub.rooms.create`. `game` defaults to the current slug. */
|
|
12
|
+
export interface RoomCreateOptions {
|
|
13
|
+
/** The game slug (default: this page's game). */
|
|
14
|
+
game?: string;
|
|
15
|
+
/** The game mode. */
|
|
16
|
+
mode?: string;
|
|
17
|
+
/** Listed in `hub.rooms.list` (default false). */
|
|
18
|
+
public?: boolean;
|
|
19
|
+
/** Seats. */
|
|
20
|
+
maxPlayers?: number;
|
|
21
|
+
/** `host` (default): guests' unaddressed sends reach the host only. `relay`: everyone hears every send. */
|
|
22
|
+
model?: 'host' | 'relay';
|
|
23
|
+
/**
|
|
24
|
+
* When the host role moves on mid-game: `grace` (default) once the host's
|
|
25
|
+
* seat is freed (left, or 3 minutes away), so a host holding hidden state
|
|
26
|
+
* can come back; `drop` as soon as the host drops, for games whose truth is
|
|
27
|
+
* all in `setState`.
|
|
28
|
+
*/
|
|
29
|
+
hostMigration?: 'grace' | 'drop';
|
|
30
|
+
/** Seat this party in the room. */
|
|
31
|
+
partyId?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Options for joining a room or race. */
|
|
35
|
+
export interface JoinOptions {
|
|
36
|
+
/** Watch instead of taking a seat (if the game allows spectators). */
|
|
37
|
+
spectate?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Events a {@link HubRoom} emits, name → payload. */
|
|
41
|
+
export interface RoomEvents {
|
|
42
|
+
/** The room changed: roster, ready flags, phase, host. */
|
|
43
|
+
room: RoomInfo;
|
|
44
|
+
/** A relayed game message. */
|
|
45
|
+
msg: RoomMessage;
|
|
46
|
+
/** The shared state after a change. */
|
|
47
|
+
state: RoomState;
|
|
48
|
+
/** A moderated chat line. */
|
|
49
|
+
chat: RoomChatLine;
|
|
50
|
+
/** The host removed me. */
|
|
51
|
+
kicked: { roomId: string };
|
|
52
|
+
/**
|
|
53
|
+
* The room is gone for this tab. `reason`: empty, ended, host_left,
|
|
54
|
+
* other_tab, moved, removed, or `gone` (client-side: the seat couldn't be
|
|
55
|
+
* reclaimed after a reconnect, e.g. the host restarted).
|
|
56
|
+
*/
|
|
57
|
+
closed: { reason: string };
|
|
58
|
+
/** The host ended the match (phase → `ended`); `results` is what it passed to `end()`. Fires once. */
|
|
59
|
+
ended: { room: RoomInfo; results?: Json };
|
|
60
|
+
/** A player left mid-game (or their reconnect grace ran out). */
|
|
61
|
+
abandoned: { userId: number; reason?: string };
|
|
62
|
+
/**
|
|
63
|
+
* A seat changed: `away` (dropped; held until `graceEndsAt`, so hand it to
|
|
64
|
+
* your computer player), `back` (reclaimed: give control back) or `gone`
|
|
65
|
+
* (freed: left, kicked or the grace ran out). The game never ends on its
|
|
66
|
+
* own because of this; `info.hostId` may have moved to another player.
|
|
67
|
+
*/
|
|
68
|
+
seat: RoomSeatChange;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Who I am in a room. */
|
|
72
|
+
export interface RoomSelf {
|
|
73
|
+
/** My user id. */
|
|
74
|
+
userId: number;
|
|
75
|
+
/** I host the room. */
|
|
76
|
+
host: boolean;
|
|
77
|
+
/** I'm watching, not seated. */
|
|
78
|
+
spectator: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Options for {@link HubRoom.send}. */
|
|
82
|
+
export interface RoomSendOptions {
|
|
83
|
+
/** Send to this seat only. */
|
|
84
|
+
to?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Options for {@link HubRoom.setState}. */
|
|
88
|
+
export interface RoomStateOptions {
|
|
89
|
+
/** Replace the whole state instead of shallow-merging the patch. */
|
|
90
|
+
replace?: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** A live hub relay room, as games see it. */
|
|
94
|
+
export interface HubRoom {
|
|
95
|
+
/** The room as last reported. */
|
|
96
|
+
readonly info: RoomInfo;
|
|
97
|
+
/** The shared room state (at most 32 KB). */
|
|
98
|
+
readonly state: RoomState;
|
|
99
|
+
/** Who I am in this room. */
|
|
100
|
+
readonly me: RoomSelf;
|
|
101
|
+
/** The seats as last reported; `connected: false` while a seat is away. */
|
|
102
|
+
seats(): RoomSeat[];
|
|
103
|
+
/** Subscribe to a room event. Returns the unsubscribe function. */
|
|
104
|
+
on<Name extends keyof RoomEvents>(event: Name, listener: (payload: RoomEvents[Name]) => void): () => void;
|
|
105
|
+
/** Mark my seat ready (or not). */
|
|
106
|
+
ready(isReady: boolean): Promise<void>;
|
|
107
|
+
/** Set my seat's small game data (team, colour…), at most 2 KB. */
|
|
108
|
+
seat(seatData: Json): Promise<void>;
|
|
109
|
+
/** Host: start the match. */
|
|
110
|
+
start(): Promise<void>;
|
|
111
|
+
/** Relay a game message. */
|
|
112
|
+
send(message: Json, options?: RoomSendOptions): Promise<void>;
|
|
113
|
+
/** Change the shared state. */
|
|
114
|
+
setState(patch: RoomState, options?: RoomStateOptions): Promise<void>;
|
|
115
|
+
/** Free-text chat; resolves with the delivered (maybe softened) text, rejects with a content rejection. */
|
|
116
|
+
chat(text: string): Promise<string>;
|
|
117
|
+
/** Send a quick-chat phrase. */
|
|
118
|
+
quick(phraseId: string): Promise<void>;
|
|
119
|
+
/** Host: remove a player. */
|
|
120
|
+
kick(userId: number): Promise<void>;
|
|
121
|
+
/** Leave the room. */
|
|
122
|
+
leave(): Promise<void>;
|
|
123
|
+
/** Host: end the match, with optional results for everyone. */
|
|
124
|
+
end(results?: Json): Promise<void>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Options for `hub.rooms.list`. */
|
|
128
|
+
export interface RoomListOptions {
|
|
129
|
+
/** Only rooms in this mode. */
|
|
130
|
+
mode?: string;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** What feature version 3 added to `hub.rooms`. */
|
|
134
|
+
export interface RoomReclaimMethods {
|
|
135
|
+
/**
|
|
136
|
+
* Take back the seat I still hold in this game (after a reload, from
|
|
137
|
+
* another tab): the room, or `null` when I hold none. The hub also does
|
|
138
|
+
* this on its own at boot, as a `join` launch with `via: 'rejoin'`.
|
|
139
|
+
*/
|
|
140
|
+
reclaim(): Promise<HubRoom | null>;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** `hub.rooms`: hub relay rooms (static games, no server). */
|
|
144
|
+
export interface HubRoomsApi extends RoomReclaimMethods {
|
|
145
|
+
/** Create a room and take its first seat. */
|
|
146
|
+
create(options?: RoomCreateOptions): Promise<HubRoom>;
|
|
147
|
+
/** Join a room by its 5-character code or its id. */
|
|
148
|
+
join(codeOrId: string, options?: JoinOptions): Promise<HubRoom>;
|
|
149
|
+
/** Public rooms in the lobby phase for this game. */
|
|
150
|
+
list(options?: RoomListOptions): Promise<RoomInfo[]>;
|
|
151
|
+
}
|