@genex-ai/multiplayer 0.17.6 → 0.17.8

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.
Files changed (40) hide show
  1. package/PROTOCOL.md +101 -30
  2. package/README.md +35 -14
  3. package/WORLD-GLTF.md +109 -0
  4. package/WORLD-SCENE.md +135 -0
  5. package/dist/authority/fast-udp.d.ts +4 -2
  6. package/dist/authority/fast-udp.js +8 -46
  7. package/dist/authority/fast-webtransport.d.ts +26 -4
  8. package/dist/authority/fast-webtransport.js +12 -115
  9. package/dist/authority/index.d.ts +379 -41
  10. package/dist/authority/index.js +247 -47
  11. package/dist/authority/module.d.ts +2 -1
  12. package/dist/authority/module.js +1 -1
  13. package/dist/bridge-authority.d.ts +3 -2
  14. package/dist/bridge-authority.global.js +10 -9
  15. package/dist/bridge-authority.js +11 -6
  16. package/dist/bridge.global.js +5 -5
  17. package/dist/bridge.js +3 -3
  18. package/dist/chunk-2NGXXQDS.js +1916 -0
  19. package/dist/{chunk-ZSWF4VCN.js → chunk-CSQEEANB.js} +78 -2
  20. package/dist/{chunk-UX3F6YTV.js → chunk-FPWP22Y7.js} +1 -1
  21. package/dist/{chunk-5JGRFT2N.js → chunk-NFMGIKFZ.js} +879 -1898
  22. package/dist/{chunk-K3SF5VDS.js → chunk-OD6NRSX2.js} +3 -1
  23. package/dist/{chunk-7QVOIHJF.js → chunk-QY3QQNDJ.js} +2 -2
  24. package/dist/{chunk-Y6XHXDIK.js → chunk-QZOCUQJT.js} +820 -537
  25. package/dist/chunk-TSYEWPVO.js +44 -0
  26. package/dist/chunk-TVTVIMIH.js +675 -0
  27. package/dist/chunk-YWQ3ALYY.js +69 -0
  28. package/dist/{fast-client-CZ41v-oB.d.ts → fast-client--A88q0kk.d.ts} +85 -4
  29. package/dist/index.js +3 -3
  30. package/dist/level-build-CbRqrYJq.d.ts +140 -0
  31. package/dist/{module-DqtFb5wA.d.ts → module-CSpXrzFc.d.ts} +151 -400
  32. package/dist/{physics-predict-49udN3a1.d.ts → physics-predict-C7ZB1gDG.d.ts} +18 -3
  33. package/dist/protocol.d.ts +87 -2
  34. package/dist/protocol.js +15 -1
  35. package/dist/shot-world-D22tqOUT.d.ts +485 -0
  36. package/dist/world-fit/index.d.ts +549 -0
  37. package/dist/world-fit/index.js +4763 -0
  38. package/dist/world-fit/three.d.ts +77 -0
  39. package/dist/world-fit/three.js +140 -0
  40. package/package.json +15 -3
@@ -1,404 +1,36 @@
1
- /** Preset names. Append-only: a name, once published, keeps its step function forever. */
2
- declare const Preset: {
3
- /** Planar movement on x/y with an aim angle: the server-authority spike's arena. */
4
- readonly TOPDOWN: "topdown";
5
- /** Source-engine character movement through a static box-and-ramp world, z up (§17.7). */
6
- readonly FIRSTPERSON: "firstperson";
7
- /** An arcade car (Rocket League's ground and air handling, kept level) through the same world (§17.7). */
8
- readonly VEHICLE: "vehicle";
9
- };
10
- type PresetName = (typeof Preset)[keyof typeof Preset];
11
- /** The longest step a preset simulates; a longer dt (a stalled tab, a hostile value) is cut to it. */
12
- declare const PRESET_MAX_DT_S = 0.25;
13
- /** `topdown` parameters. */
14
- interface TopdownParams {
15
- /** Movement speed, world units per second. */
16
- speed: number;
17
- /** Half the arena's side: x and y stay within [-arena, arena]. */
18
- arena: number;
19
- }
20
- declare const TOPDOWN_DEFAULTS: Readonly<TopdownParams>;
21
- /** One parameter's accepted range: a finite number in [min, max], above 0 when `positive`, and an
22
- * integer when `integer` (absent = any number). */
23
- interface PresetParamRange {
24
- min: number;
25
- max: number;
26
- positive: boolean;
27
- integer?: true;
28
- }
29
- /** The fields a `topdown` step reads and writes. */
30
- interface TopdownBody {
31
- x: number;
32
- y: number;
33
- /** Aim, radians. */
34
- yaw: number;
35
- }
36
- /** The input fields a `topdown` step reads. */
37
- interface TopdownInput {
38
- moveX?: unknown;
39
- moveY?: unknown;
40
- yaw?: unknown;
41
- }
42
- /** Whether `name` is a known preset. */
43
- declare function isPresetName(name: unknown): name is PresetName;
44
- /** Whether `params` is acceptable for preset `name`: absent, or an object whose every key is one of
45
- * the preset's parameters with a finite number in its range. */
46
- declare function presetParamsValid(name: PresetName, params: unknown): boolean;
47
- /** Preset `name`'s parameters from a module's `preset.params`: its defaults for anything unset or
48
- * invalid, key by key in the order of its range table. */
49
- declare function resolvePresetParams(name: PresetName, params: unknown): Record<string, number>;
50
- /** `topdown` parameters from a module's `preset.params`: defaults for anything unset or invalid. */
51
- declare function resolveTopdownParams(params: unknown): TopdownParams;
52
- /**
53
- * One fixed `topdown` step. Pure: returns the next body.
54
- * - moveX, moveY: non-finite → 0, clamped to [-1, 1], float32; a vector longer than 1 is scaled to 1;
55
- * - dt: non-finite or ≤ 0 → 0, capped at {@link PRESET_MAX_DT_S};
56
- * - x' = fround(clamp(x + moveX * scale * speed * dt, -arena, arena)), y' likewise;
57
- * - yaw' = the input yaw wrapped to [-π, π) as float32, or the previous yaw when it is not usable.
58
- */
59
- declare function stepTopdown(body: TopdownBody, input: TopdownInput, dt: number, params: TopdownParams): TopdownBody;
60
- /** `firstperson` parameters (§17.7's table, in its order). Each is used as float32. */
61
- interface FirstpersonParams {
62
- /** Run speed, units/s, before the body's `cap`. */
63
- maxSpeed: number;
64
- /** Speed multiplier while walk is held. */
65
- walkSpeed: number;
66
- /** Speed multiplier while ducking (wins over walk). */
67
- crouchSpeed: number;
68
- accelerate: number;
69
- airAccelerate: number;
70
- /** Air wish speed is clamped to this before the projection (what makes air-strafing work). */
71
- airMaxWishSpeed: number;
72
- friction: number;
73
- /** Below this speed friction acts as if at this speed. */
74
- stopSpeed: number;
75
- /** Units/s² along −z. */
76
- gravity: number;
77
- /** The `vz` a jump sets. */
78
- jumpImpulse: number;
79
- /** Each velocity axis is clamped to ±this. */
80
- maxVelocity: number;
81
- /** Half the side of the hull's square footprint. */
82
- radius: number;
83
- standHeight: number;
84
- crouchHeight: number;
85
- /** Seconds to duck fully, and to stand back up. */
86
- duckTime: number;
87
- /** Highest ledge walked up without a jump. */
88
- stepHeight: number;
89
- /** Least z of a ramp top's unit normal that can be stood on. */
90
- standable: number;
91
- /** How far below the feet ground is found. */
92
- groundTrace: number;
93
- /** How far above the feet ground is found (a hull sunk that far is lifted out). */
94
- groundSnap: number;
95
- /** Clearance kept from a surface (Source's DIST_EPSILON). */
96
- skin: number;
97
- /** Largest |pitch|, radians. */
98
- pitchLimit: number;
99
- /** Button masks: any shared bit counts as held; 0 disables. */
100
- jumpBit: number;
101
- duckBit: number;
102
- walkBit: number;
103
- /** Sub-steps per step, an integer in [1, 8]. */
104
- substeps: number;
105
- /** The collision world's hash ({@link firstpersonWorld}), written by the sandbox. */
106
- world: number;
107
- }
108
- /** 32-bit FNV-1a of the empty world: two zero counts (§17.7). */
109
- declare const EMPTY_WORLD_HASH = 2615243109;
110
- declare const FIRSTPERSON_DEFAULTS: Readonly<FirstpersonParams>;
111
- /** `firstperson` parameters from a module's `preset.params`: defaults for anything unset or invalid. */
112
- declare function resolveFirstpersonParams(params: unknown): FirstpersonParams;
113
- /** `mstate` bits a `firstperson` step keeps. */
114
- declare const MoveState: {
115
- readonly ON_GROUND: 1;
116
- readonly DUCKING: 2;
117
- readonly JUMP_HELD: 4;
118
- };
119
- /** The fields a `firstperson` step reads (`cap` too, which it never writes). */
120
- interface FirstpersonBody {
121
- x: number;
122
- y: number;
123
- z: number;
124
- vx: number;
125
- vy: number;
126
- vz: number;
127
- /** Aim, radians: stored only. */
128
- yaw: number;
129
- pitch: number;
130
- /** 0 standing, 1 fully ducked. */
131
- duck: number;
132
- /** {@link MoveState} bits. */
133
- mstate: number;
134
- /** Speed multiplier the module writes (a weapon's or a wound's), [0, 4]. */
135
- cap?: number;
136
- }
137
- /** What a `firstperson` step writes: every body field but `cap`. */
138
- type FirstpersonStep = Omit<FirstpersonBody, 'cap'>;
139
- /** The input fields a `firstperson` step reads. `moveX`/`moveY` are WORLD axes. */
140
- interface FirstpersonInput {
141
- moveX?: unknown;
142
- moveY?: unknown;
143
- yaw?: unknown;
144
- pitch?: unknown;
145
- buttons?: unknown;
146
- }
147
- /** A box: `[minX, minY, minZ, maxX, maxY, maxZ]`. */
148
- type WorldBox = readonly [number, number, number, number, number, number];
149
- /** A ramp: a box whose top rises along x (`axis` 0) or y (`axis` 1), from `lo` at that axis's min
150
- * end to `hi` at its max end: `[minX, minY, minZ, maxX, maxY, maxZ, axis, lo, hi]`. */
151
- type WorldRamp = readonly [number, number, number, number, number, number, number, number, number];
152
- /** A world as a module and a game give it (§17.7): boxes, then ramps. */
153
- interface FirstpersonWorldSpec {
154
- boxes?: readonly (readonly number[])[];
155
- ramps?: readonly (readonly number[])[];
156
- }
157
- /** A validated world ({@link firstpersonWorld}): frozen, every value a float32 (−0 read as 0). */
158
- interface FirstpersonWorld {
159
- readonly boxes: readonly WorldBox[];
160
- readonly ramps: readonly WorldRamp[];
161
- /** 32-bit FNV-1a over its counts and values (§17.7): what `params.world` must equal. */
162
- readonly hash: number;
163
- /** Whether the step visits only the solids a bounding-volume tree over their boxes says could
164
- * matter (the results are bit-identical to visiting every one; only the cost changes). */
165
- readonly broadphase: boolean;
166
- }
167
- declare const WorldLimits: {
168
- readonly MAX_BOXES: 4096;
169
- readonly MAX_RAMPS: 512;
170
- /** Every world value's magnitude. */
171
- readonly MAX_ABS: 1000000000;
1
+ import { P as PresetName, d as FirstpersonWorldSpec, I as WorldKey, C as ClaimVerdict } from './shot-world-D22tqOUT.js';
2
+
3
+ /** What a room runs with, unless its module says otherwise, and the bounds of what it may say (seconds). */
4
+ declare const AuthorityLifetime: {
5
+ readonly IDLE_SEAT_S: number;
6
+ readonly IDLE_SEAT_MIN_S: 30;
7
+ readonly IDLE_SEAT_MAX_S: number;
8
+ readonly ROOM_AGE_S: number;
9
+ readonly ROOM_AGE_MIN_S: 60;
10
+ readonly ROOM_AGE_MAX_S: number;
172
11
  };
173
- /** Why a world was refused: the path of the first bad value. */
174
- declare class WorldError extends RangeError {
12
+ /** The resolved limits. */
13
+ interface LifetimePolicy {
14
+ /** A seat whose input has not changed for this long leaves. */
15
+ readonly idleSeatS: number;
16
+ /** A room this old drains and ends. */
17
+ readonly maxRoomAgeS: number;
18
+ }
19
+ declare const LIFETIME_DEFAULT: LifetimePolicy;
20
+ /** A refused `config.lifetime`: the path of the first bad value. */
21
+ declare class LifetimeConfigError extends Error {
175
22
  readonly path: string;
176
- constructor(path: string, message: string);
177
- }
178
- /**
179
- * Validates a collision world (§17.7) and returns it frozen, with its hash. Refused (a
180
- * {@link WorldError}) unless it has at most 4096 boxes and 512 ramps, each exactly six (box) or
181
- * nine (ramp) numbers, every one a float32 of magnitude at most 1e9, min < max on every axis, and
182
- * each ramp `axis` 0 or 1 with `minZ ≤ lo`, `minZ ≤ hi` and `maxZ = max(lo, hi)`. `undefined` is
183
- * the empty world; a missing `boxes` or `ramps` is none, and other keys are ignored. `broadphase`
184
- * (default true) builds the bounding-volume tree the step filters with; it never changes a result. A
185
- * world this function returned is returned as is.
186
- */
187
- declare function firstpersonWorld(raw: unknown, options?: {
188
- broadphase?: boolean;
189
- }): FirstpersonWorld;
190
- /** The empty world: no solids (a body in it falls until z reaches −1e9). */
191
- declare const EMPTY_WORLD: FirstpersonWorld;
192
- /** A solid posed for one tick beside the static world (a lift at its pose, a head slab): an
193
- * axis-aligned box `[min, max]`; a box of half extents `half` about centre `c` turned about z by the
194
- * angle whose sine and cosine are given (`obox`); or an upright disc of `radius` about `c`, `half` its
195
- * half height. Visited after the static solids, in order, never by the broad phase's tree. */
196
- type PosedSolid = {
197
- readonly kind: 'box';
198
- readonly min: readonly [number, number, number];
199
- readonly max: readonly [number, number, number];
200
- } | {
201
- readonly kind: 'obox';
202
- readonly c: readonly [number, number, number];
203
- readonly half: readonly [number, number, number];
204
- readonly sin: number;
205
- readonly cos: number;
206
- } | {
207
- readonly kind: 'disc';
208
- readonly c: readonly [number, number, number];
209
- readonly radius: number;
210
- readonly half: number;
211
- };
212
- /** Posed solids a tick may hold at most (32 lifts and a head slab for each of 64 seats). */
213
- declare const POSED_MAX = 96;
214
- /** The step's view of a tick's posed solids ({@link posedWorld}): one flat table per field. `min*`
215
- * and `max*` are each solid's bounds on x, y and z (an obox's or a disc's box around it). */
216
- interface PosedWorld {
217
- readonly count: number;
218
- readonly kind: Uint8Array;
219
- readonly minX: Float64Array;
220
- readonly minY: Float64Array;
221
- readonly minZ: Float64Array;
222
- readonly maxX: Float64Array;
223
- readonly maxY: Float64Array;
224
- readonly maxZ: Float64Array;
225
- readonly cx: Float64Array;
226
- readonly cy: Float64Array;
227
- readonly hx: Float64Array;
228
- readonly hy: Float64Array;
229
- readonly sin: Float64Array;
230
- readonly cos: Float64Array;
231
- readonly radius: Float64Array;
232
- }
233
- /** A tick's posed solids compiled for the step, in the order given. */
234
- declare function posedWorld(solids: readonly PosedSolid[]): PosedWorld;
235
- /** No posed solids. */
236
- declare const NO_POSED: PosedWorld;
237
- /** A seat's body as the lift slots read it. */
238
- interface HullBody {
239
- readonly x: number;
240
- readonly y: number;
241
- readonly z: number;
242
- readonly vz?: number;
243
- readonly duck?: number;
244
- }
245
- /** What the lift slots ask of a preset's hull, against the world and a tick's posed solids. */
246
- interface HullOps {
247
- /** The posed solid (its index) the hull stands on: the highest standable top under it in
248
- * [z − groundTrace, z + groundSnap] (`checkGround`'s test) when that top is a posed solid's (the
249
- * first such in order), else −1; −1 too while rising (`vz > 0.1`). */
250
- support(body: HullBody, solids: readonly PosedSolid[]): number;
251
- /** Whether the hull is more than skin inside posed solid `k` (§17.7 *Starting inside*'s `inside`). */
252
- inside(body: HullBody, solids: readonly PosedSolid[], k: number): boolean;
253
- /** §17.7 *Starting inside* as `slideMove` applies it, with no move: up to four times, out through the
254
- * face a zero-length sweep reports, by its depth then skin. `inside`: still inside some solid. */
255
- pushOut(body: HullBody, solids: readonly PosedSolid[]): {
256
- x: number;
257
- y: number;
258
- z: number;
259
- inside: boolean;
260
- };
261
- }
262
- /** The preset's hull among `world` and a tick's posed solids. */
263
- declare function hullOps(preset: 'firstperson' | 'vehicle', params: Readonly<Record<string, number>>, world?: FirstpersonWorld): HullOps;
264
- /**
265
- * One fixed `firstperson` step (§17.7) through `world` (default: the empty world). Pure: returns the
266
- * next `x y z vx vy vz yaw pitch duck mstate`; the body's `cap` is read, never written. `world` must
267
- * be the world whose hash is `params.world` for the result to be the server's; the step itself does
268
- * not compare them.
269
- */
270
- declare function stepFirstperson(body: Partial<FirstpersonBody>, input: FirstpersonInput, dt: number, params: FirstpersonParams, world?: FirstpersonWorld, posed?: PosedWorld): FirstpersonStep;
271
- /** `vehicle` parameters (§17.7's table, in its order). Each is used as float32 but the masks,
272
- * `substeps` and `world`. */
273
- interface VehicleParams {
274
- /** Top speed on the throttle, units/s, before the body's `cap`. */
275
- maxSpeed: number;
276
- /** Throttle acceleration, units/s². */
277
- accel: number;
278
- /** Deceleration while the throttle opposes the motion. */
279
- brake: number;
280
- /** Deceleration with no throttle, and down to the throttle's speed when above it without boost. */
281
- coast: number;
282
- /** Boost's acceleration along the heading, on top of the throttle's. */
283
- boostAccel: number;
284
- /** Top speed under boost, before `cap`. */
285
- boostMaxSpeed: number;
286
- /** Fuel burned per second of boost (a full tank is 1). */
287
- boostBurn: number;
288
- /** Deceleration of the sideways speed on the ground, units/s². */
289
- grip: number;
290
- /** The same, while drift is held. */
291
- driftGrip: number;
292
- /** Yaw rate at full steer on the ground, rad/s, at or above `turnSpeed`. */
293
- turnRate: number;
294
- /** The forward speed at which the full turn rate is reached. */
295
- turnSpeed: number;
296
- /** How fast the yaw rate follows the steering on the ground, rad/s². */
297
- spinAccel: number;
298
- /** Yaw rate at full steer in the air, rad/s. */
299
- airTurnRate: number;
300
- /** How fast the yaw rate follows the steering in the air, rad/s². */
301
- airSpinAccel: number;
302
- /** Units/s² along −z. */
303
- gravity: number;
304
- /** The `vz` a jump sets. */
305
- jumpImpulse: number;
306
- /** Each velocity axis is clamped to ±this. */
307
- maxVelocity: number;
308
- /** Half the side of the hull's square footprint. */
309
- radius: number;
310
- /** Hull height. */
311
- height: number;
312
- /** Highest ledge driven up without a jump, and the deepest drop a sub-step follows down. */
313
- stepHeight: number;
314
- /** Least z of a ramp top's unit normal that can be driven on. */
315
- standable: number;
316
- /** How far below the hull's base ground is found. */
317
- groundTrace: number;
318
- /** How far above the hull's base ground is found. */
319
- groundSnap: number;
320
- /** Clearance kept from a surface. */
321
- skin: number;
322
- /** Button masks: any shared bit counts as held; 0 disables. */
323
- jumpBit: number;
324
- boostBit: number;
325
- driftBit: number;
326
- /** Sub-steps per step, an integer in [1, 8]. */
327
- substeps: number;
328
- /** The collision world's hash ({@link firstpersonWorld}), written by the sandbox. */
329
- world: number;
330
- }
331
- declare const VEHICLE_DEFAULTS: Readonly<VehicleParams>;
332
- /** `vehicle` parameters from a module's `preset.params`: defaults for anything unset or invalid. */
333
- declare function resolveVehicleParams(params: unknown): VehicleParams;
334
- /** The fields a `vehicle` step reads (`cap` too, which it never writes; it never touches `pitch`
335
- * or `duck`). */
336
- interface VehicleBody {
337
- x: number;
338
- y: number;
339
- z: number;
340
- vx: number;
341
- vy: number;
342
- vz: number;
343
- /** Heading, radians, +yaw counterclockwise seen from above (z up): body state, not input. */
344
- yaw: number;
345
- /** Yaw rate, rad/s, positive toward +yaw, [−1000, 1000]. */
346
- spin: number;
347
- /** The boost tank, [0, 1]. The module writes it to refuel; the step only burns it. */
348
- fuel: number;
349
- /** {@link MoveState} bits: onGround and jumpHeld. */
350
- mstate: number;
351
- /** Multiplier of both top speeds the module writes, [0, 4]. */
352
- cap?: number;
23
+ constructor(path: string);
353
24
  }
354
- /** What a `vehicle` step writes: every body field but `cap`. */
355
- type VehicleStep = Omit<VehicleBody, 'cap'>;
356
- /** The input fields a `vehicle` step reads: `moveY` the throttle, `moveX` the steer (+1 turns
357
- * right, toward −yaw), `buttons` jump, boost and drift. */
358
- interface VehicleInput {
359
- moveX?: unknown;
360
- moveY?: unknown;
361
- buttons?: unknown;
25
+ /** `config.lifetime` as a module declares it: either limit, whole seconds. */
26
+ interface LifetimeDeclaration {
27
+ idleSeatS?: number;
28
+ maxRoomAgeS?: number;
362
29
  }
363
- /**
364
- * One fixed `vehicle` step (§17.7) through `world` (default: the empty world). Pure: returns the
365
- * next `x y z vx vy vz yaw spin fuel mstate`; the body's `cap` is read, never written, and `pitch`
366
- * and `duck` are never touched. `world` must be the world whose hash is `params.world` for the
367
- * result to be the server's; the step itself does not compare them.
368
- */
369
- declare function stepVehicle(body: Partial<VehicleBody>, input: VehicleInput, dt: number, params: VehicleParams, world?: FirstpersonWorld, posed?: PosedWorld): VehicleStep;
370
- /** A body field a preset step may read and write: the entity's float32 pose and velocity,
371
- * firstperson's aim pitch, duck amount, movement bits and speed cap, and vehicle's yaw rate and
372
- * boost fuel. */
373
- type PresetField = 'x' | 'y' | 'z' | 'vx' | 'vy' | 'vz' | 'yaw' | 'pitch' | 'duck' | 'mstate' | 'cap' | 'spin' | 'fuel';
374
- /** The body a preset step reads: any of the fields, a missing one read as the step says (0, or 1
375
- * for `cap`). */
376
- type PresetBody = Readonly<Partial<Record<PresetField, number>>>;
377
- /** The input a preset step reads (sanitized by the step itself). */
378
- type PresetInput = Readonly<Partial<Record<'moveX' | 'moveY' | 'moveZ' | 'yaw' | 'pitch' | 'buttons', unknown>>>;
379
- /** One preset, type-erased: what a validator, a reconciler and a test server need to run it by
380
- * name. `fields` are the body fields its step writes (and so the fields a client mirrors);
381
- * `reads` the further fields it only reads (a client mirrors those too, so a replay sees the
382
- * server's value); `world` whether it steps through a collision world. */
383
- interface PresetDefinition {
384
- readonly defaults: Readonly<Record<string, number>>;
385
- readonly ranges: Readonly<Record<string, PresetParamRange>>;
386
- readonly fields: readonly PresetField[];
387
- readonly reads: readonly PresetField[];
388
- readonly world: boolean;
389
- step(body: PresetBody, input: PresetInput, dt: number, params: Readonly<Record<string, number>>, world?: FirstpersonWorld, posed?: PosedWorld): Record<string, number>;
390
- }
391
- /** Every preset by name. A new preset is one entry here (plus its §17.7 text and vectors). */
392
- declare const PRESETS: {
393
- readonly [N in PresetName]: PresetDefinition;
394
- };
395
- /** Preset `name`'s table entry; undefined for a name not in the table (never one reached through
396
- * the prototype). */
397
- declare function definitionOf(name: unknown): PresetDefinition | undefined;
398
- /** One fixed step of preset `name` with already resolved `params` ({@link resolvePresetParams}),
399
- * through `world` for a preset that has one (default: the empty world). Pure: returns the next
400
- * values of the preset's `fields`. */
401
- declare function stepPreset(name: PresetName, body: PresetBody, input: PresetInput, dt: number, params: Readonly<Record<string, number>>, world?: FirstpersonWorld, posed?: PosedWorld): Record<string, number>;
30
+ /** `config.lifetime` resolved: what it gives, the defaults for the rest. Null when it is not declared (the
31
+ * host runs {@link LIFETIME_DEFAULT}). Throws a {@link LifetimeConfigError} naming the path of a value
32
+ * that is not an object, an unknown key, or a limit that is not a whole number inside its bounds. */
33
+ declare function resolveLifetime(given: unknown, path?: string): LifetimePolicy | null;
402
34
 
403
35
  /** How a client draws other seats by default (PROTOCOL.md §17.11 *Drawing other seats*): `predicted` on
404
36
  * your own clock (the Rocket League model), `separate` on the render timeline and moved only out of
@@ -655,10 +287,19 @@ declare const InputRepeat: {
655
287
  readonly Off: "off";
656
288
  };
657
289
  type InputRepeat = (typeof InputRepeat)[keyof typeof InputRepeat];
658
- /** The resolved input settings a room runs with. */
290
+ /** The resolved input settings a room runs with. `settleMs` is there only when set, so a room without it
291
+ * publishes the text it always did. */
659
292
  interface InputPolicy {
660
293
  readonly repeat: InputRepeat;
661
- }
294
+ /** §17.11 *A quiet seat*: after this long with no input the room steps a seat's body under a stick at
295
+ * rest until it lies still. Absent: the body holds where its last input left it. */
296
+ readonly settleMs?: number;
297
+ }
298
+ /** The range of `config.inputs.settleMs`, ms: above any hitch a game should sit through, below a long AFK. */
299
+ declare const INPUT_SETTLE_MS: {
300
+ readonly MIN: 100;
301
+ readonly MAX: 60000;
302
+ };
662
303
  /**
663
304
  * Each genre preset's input settings. Measured on the bench (interleaved runs, one-sided Mann–Whitney,
664
305
  * evidence folder input-repeat/ and R2): `vehicle-arena` is off, because on car-ball 3v3 at a clean
@@ -697,6 +338,7 @@ declare class InputConfigError extends Error {
697
338
  interface InputDeclaration {
698
339
  preset?: ContactPreset;
699
340
  repeat?: InputRepeat;
341
+ settleMs?: number;
700
342
  }
701
343
  /**
702
344
  * `config.inputs` resolved (§17.11 *Input pacing*): `repeat` as given, else the table of the genre preset
@@ -859,6 +501,8 @@ declare const LeaveReason: {
859
501
  readonly REVOKED: "revoked";
860
502
  /** The room is closing (drain, halt or fault). */
861
503
  readonly CLOSING: "closing";
504
+ /** The seat's input had not changed for the room's `config.lifetime.idleSeatS`. */
505
+ readonly IDLE: "idle";
862
506
  };
863
507
  type LeaveReason = (typeof LeaveReason)[keyof typeof LeaveReason];
864
508
  /** A seated player, as the server verified them. */
@@ -945,6 +589,12 @@ interface EntityApi {
945
589
  ownedBy(playerId: string): EntityData | undefined;
946
590
  all(): readonly EntityData[];
947
591
  }
592
+ /** An entity as the shooter saw it (`RewindApi.pose`): where it stood, which way it faced (radians)
593
+ * and how far it ducked (0 standing to 1 fully ducked; 0 for an entity that never ducks). */
594
+ interface RewoundPose extends Vec3 {
595
+ yaw: number;
596
+ duck: number;
597
+ }
948
598
  /** Lag compensation. Both calls read the snapshot of positions the current input's sender saw when
949
599
  * they pressed it (only while handling an input whose buttons match `config.lagComp.buttons`;
950
600
  * otherwise the current positions). */
@@ -963,6 +613,75 @@ interface RewindApi {
963
613
  * projectile or a physics body entity. For a module's own tests against things that are not
964
614
  * spheres (a door, a shutter): §17.5. */
965
615
  at(id: string): Vec3 | null;
616
+ /** `at` with the entity's `yaw` and `duck` at that same instant, live where `at` is live and null
617
+ * where `at` is null. For hit zones that depend on stance: a head lower on a ducking target. §17.5. */
618
+ pose(id: string): RewoundPose | null;
619
+ }
620
+ /** Where a ray entered the room's world (`WorldApi.ray`). */
621
+ interface WorldRayHit {
622
+ /** World units along the ray from its origin; 0 when it started inside or on the way in. */
623
+ dist: number;
624
+ point: Vec3;
625
+ /** The face it entered by, a unit vector against the ray; all zeros when it started `inside`. */
626
+ normal: Vec3;
627
+ /** The ray started inside the solid. */
628
+ inside: boolean;
629
+ /** Which solid, counting the module's `boxes` and then its `ramps`. */
630
+ solid: number;
631
+ }
632
+ /** A world only rays read: `FirstpersonWorldSpec` plus how far off its surfaces may be, as its fit stated. */
633
+ interface ShotWorldSpec extends FirstpersonWorldSpec {
634
+ /** Units a claimed stop may differ from this world: `ctx.world.claim`'s default. Default 0. */
635
+ tolerance?: number;
636
+ }
637
+ /** The room's collision world, for the module's own questions (§17.7 *Rays*). Static: it needs no
638
+ * rewinding, and it holds what bodies collide with, not what is drawn. */
639
+ interface WorldApi {
640
+ /** The first solid along the ray within `range` (default: no limit), or null: also null for a ray
641
+ * that is none (zero length, or a value that is not a finite number). Touching a face is no hit.
642
+ * Takes a hitscan's options as they are. Server only: no client SDK has it. */
643
+ ray(origin: Vec3, dir: Vec3, options?: WorldRayOptions): WorldRayHit | null;
644
+ /** A shooter's claimed stop, from its own render mesh, held to the shot world (§17.7 *A claimed stop*): the distance
645
+ * the shot flies, and why. Null for a ray that is none. Any `claimed` that is not a number means the shot flew on. A room with
646
+ * no shot world throws naming `no_shot_world`. */
647
+ claim(origin: Vec3, dir: Vec3, claimed: unknown, options?: WorldClaimOptions): WorldClaim | null;
648
+ }
649
+ /** What `WorldApi.ray` takes. */
650
+ interface WorldRayOptions {
651
+ range?: number;
652
+ /** `'shot'`: the module's `shotWorld`. A room that has none throws naming `no_shot_world`, and is never answered from its `world`. */
653
+ world?: WorldKey;
654
+ }
655
+ /** What `WorldApi.claim` takes: a weapon's rules. */
656
+ interface WorldClaimOptions {
657
+ range?: number;
658
+ /** How far off a surface a claim may be, either way: the cheat margin. Along a ray that grazes the surface it reads further. Default:
659
+ * the shot world's own `tolerance`. */
660
+ tolerance?: number;
661
+ /** One wall this weapon goes through, in units along the ray. Default none. */
662
+ pierce?: number;
663
+ /** The weapon's last word: a distance replaces `dist`. Called with the verdict as it stands, each claim. */
664
+ rule?: (claim: WorldClaim) => number | undefined;
665
+ }
666
+ /** What `WorldApi.claim` decided. */
667
+ interface WorldClaim {
668
+ /** How far the shot flies: judge targets inside this. The range, or Infinity without one, when nothing stops it. */
669
+ dist: number;
670
+ verdict: ClaimVerdict;
671
+ /** What was claimed, as read: Infinity for the shot flying on. */
672
+ claimed: number;
673
+ /** Where the shot world stops the ray, or null if nothing does in range. */
674
+ server: number | null;
675
+ tolerance: number;
676
+ /** How far either way of the world's stop this claim could stand, along this ray: the tolerance, grown by how much the ray grazes. */
677
+ slack: number;
678
+ /** The wall a piercing claim went through, or null. */
679
+ through: number | null;
680
+ /** Which solid and which face of the shot world stopped the ray, or null. */
681
+ solid: number | null;
682
+ normal: Vec3 | null;
683
+ /** Where the shot stops, or null when it flies on for ever. */
684
+ point: Vec3 | null;
966
685
  }
967
686
  /** What `projectiles.launch` takes: where and how fast the projectile starts. `g` (default 0) pulls
968
687
  * it down along −z; `id` is required outside a seat's input and refused inside one, where the id is
@@ -1343,6 +1062,9 @@ interface ModuleConfig {
1343
1062
  * repeated (`repeat`), else its genre `preset`'s setting, else the contact policy's preset's, else
1344
1063
  * on. A bad one is a bad config (input-config.ts `resolveInputConfig` names its path). */
1345
1064
  inputs?: InputDeclaration | null;
1065
+ /** How long a seat may sit idle and the room may live (§17.6 *Room lifetime*), whole seconds inside
1066
+ * their bounds; a bad one is a bad config (lifetime-config.ts `resolveLifetime` names its path). */
1067
+ lifetime?: LifetimeDeclaration | null;
1346
1068
  /** The room's lifts as data (§17.11 *Lifts*): platforms posed by an exact function of the tick,
1347
1069
  * which seats collide with and ride. Needs a `firstperson` or `vehicle` preset; a bad one is a bad
1348
1070
  * config (lifts-config.ts `resolveLifts` names its path). */
@@ -1369,14 +1091,26 @@ interface ResolvedModuleConfig {
1369
1091
  /** The declared lifts, resolved by the host (§17.11 *Lifts*); absent without. The host publishes
1370
1092
  * them in the state's `preset` text. */
1371
1093
  lifts?: LiftsPolicy | null;
1094
+ /** The declared limits on a seat's idling and the room's age, resolved by the host (§17.3 *Room
1095
+ * lifetime*); absent: the defaults. */
1096
+ lifetime?: LifetimePolicy | null;
1372
1097
  }
1373
1098
  /** What `init` gets. */
1374
1099
  interface InitContext {
1375
1100
  readonly config: ResolvedModuleConfig;
1376
1101
  /** The room's seed; `random()` is a PRNG seeded from it, so a replay is exact. */
1377
1102
  readonly seed: number;
1103
+ /** The key its first client asked for (§17.2 *Choosing a room*), to choose a mode by; '' for none.
1104
+ * A client chose it: treat a key you do not know as the default, never as an error. */
1105
+ readonly matchKey: string;
1106
+ /** What the room this one follows returned from `onDrain` (§17.13 *Drain and rejoin*), or null: a
1107
+ * room with no predecessor, a predecessor with nothing to hand on, or one in another region. Treat
1108
+ * it as written by an older version of your module: the module may have changed in the deploy. */
1109
+ readonly handoff: Json | null;
1378
1110
  random(): number;
1379
1111
  readonly entities: EntityApi;
1112
+ /** The room's collision world, from where it stands before tick 0 (§17.7 *Rays*). */
1113
+ readonly world: WorldApi;
1380
1114
  /** Projectiles. `launch` throws here: a launch's `t0` is the tick being stepped, and `init` runs
1381
1115
  * before the first tick. Launch from `step` or a hook instead. */
1382
1116
  readonly projectiles: ProjectileApi;
@@ -1396,6 +1130,8 @@ interface RoomContext<S> {
1396
1130
  random(): number;
1397
1131
  readonly entities: EntityApi;
1398
1132
  readonly rewind: RewindApi;
1133
+ /** The room's collision world (§17.7 *Rays*). */
1134
+ readonly world: WorldApi;
1399
1135
  readonly projectiles: ProjectileApi;
1400
1136
  /** Server physics (§17.10) in a room whose config asks for it. */
1401
1137
  readonly physics: PhysicsApi;
@@ -1422,6 +1158,15 @@ interface GenexRoomModule<S = unknown> {
1422
1158
  * `params.world`; the game client hands its SDK the same world (`session.setWorld`). Absent =
1423
1159
  * the empty world (no floor: add one box for open ground). */
1424
1160
  world?: FirstpersonWorldSpec;
1161
+ /** Several worlds, by match key (§17.2 *Choosing a room*): a room whose key the map names runs that
1162
+ * world, any other room `world`. At most 16, each name a match key, and one room compiles only its
1163
+ * own; `authority validate` loads them all. A module with this map leaves `params.world` unset. */
1164
+ worlds?: Readonly<Record<string, FirstpersonWorldSpec>>;
1165
+ /** What bullets meet where it differs from what bodies do (§17.7 *The shot world*): only `ctx.world`'s rays read it. Its own
1166
+ * tree, no hash, no client knows it, and it counts against the module's bytes and a load's cost. */
1167
+ shotWorld?: ShotWorldSpec;
1168
+ /** Several, by match key, as `worlds`: any other room `shotWorld`. */
1169
+ shotWorlds?: Readonly<Record<string, ShotWorldSpec>>;
1425
1170
  init(ctx: InitContext): S;
1426
1171
  onJoin(ctx: RoomContext<S>, player: PlayerInfo): void;
1427
1172
  onLeave(ctx: RoomContext<S>, player: PlayerInfo, reason: LeaveReason): void;
@@ -1429,8 +1174,14 @@ interface GenexRoomModule<S = unknown> {
1429
1174
  onInput(ctx: RoomContext<S>, playerId: string, input: InputData): void;
1430
1175
  /** Once per tick, after the tick's inputs. */
1431
1176
  step(ctx: RoomContext<S>): void;
1177
+ /** Optional. The server is about to close this room for a deploy (§17.13 *Drain and rejoin*): what to
1178
+ * hand the room that follows it, at most 256 KiB of JSON, which it reads as `ctx.handoff` in `init`.
1179
+ * Called once, right before the close, under `init`'s time limit. Its seats come back by themselves,
1180
+ * with new session ids: key what you keep by uid. Without this hook, or when it throws or returns
1181
+ * nothing, the successor starts clean. */
1182
+ onDrain?(ctx: RoomContext<S>): Json | undefined;
1432
1183
  }
1433
1184
  /** Identity helper that types a room module: `export default defineRoom({ ... })`. */
1434
1185
  declare const defineRoom: <S>(module: GenexRoomModule<S>) => GenexRoomModule<S>;
1435
1186
 
1436
- export { type InputPolicy as $, EMPTY_WORLD as A, EMPTY_WORLD_HASH as B, type ContactPolicy as C, type EntityApi as D, type EntityData as E, type FirstpersonWorld as F, type EntityInit as G, type HullBody as H, type InputData as I, type Json as J, FIRSTPERSON_DEFAULTS as K, LeaveReason as L, type FirstpersonBody as M, type FirstpersonInput as N, type FirstpersonParams as O, type PlayerInfo as P, type FirstpersonStep as Q, type ResolvedModuleConfig as R, type StandRule as S, type TickHz as T, type GenexRoomModule as U, HeadFriction as V, INPUTS_DEFAULT as W, INPUT_PRESETS as X, type InitContext as Y, InputConfigError as Z, type InputDeclaration as _, type PhysicsErrorCode as a, SHOOTER_CENTER as a$, LIFTS_MAX as a0, LIFT_ID_MAX as a1, LIFT_POINTS_MAX as a2, LIFT_SPIN_MIN_PERIOD as a3, LIFT_TICKS_MAX as a4, LIFT_VALUE_MAX as a5, LiftEase as a6, LiftImpart as a7, type LiftPath as a8, LiftPathMode as a9, type PhysicsJointDesc as aA, type PhysicsLimits as aB, type PhysicsMotor as aC, type PhysicsOverlap as aD, type PhysicsPose as aE, type PhysicsQueryFilter as aF, type PhysicsRefusal as aG, type PhysicsRequest as aH, type PhysicsSetPoseOptions as aI, type PhysicsShape as aJ, Preset as aK, type PresetBody as aL, type PresetDefinition as aM, type PresetField as aN, type PresetInput as aO, type PresetName as aP, type PresetParamRange as aQ, type PresetSpec as aR, type ProjectileApi as aS, type ProjectileField as aT, type ProjectileFlight as aU, type ProjectileHit as aV, type ProjectileInit as aW, type Quat as aX, type ResolvedPhysics as aY, type RewindApi as aZ, type RoomContext as a_, type LiftShape as aa, LiftShapeKind as ab, type LiftSpin as ac, type LiftTooFast as ad, type LiftsApi as ae, LiftsConfigError as af, MODULE_CONTRACT as ag, type ModuleConfig as ah, MoveState as ai, NO_LIFTS as aj, NO_POSED as ak, POSED_MAX as al, PRESETS as am, PRESET_MAX_DT_S as an, type PairRule as ao, type PhysicsAnswer as ap, type PhysicsApi as aq, type PhysicsBodyDesc as ar, type PhysicsBodyState as as, type PhysicsBodyType as at, type PhysicsColliderDesc as au, type PhysicsCommandResult as av, type PhysicsCommands as aw, type PhysicsEvent as ax, type PhysicsGroups as ay, type PhysicsHit as az, InputRepeat as b, type SlideRule as b0, TOPDOWN_DEFAULTS as b1, TopPolicy as b2, type TopdownBody as b3, type TopdownInput as b4, type TopdownParams as b5, VEHICLE_DEFAULTS as b6, type Vec3 as b7, type VehicleBody as b8, type VehicleInput as b9, type VehicleParams as ba, type VehicleStep as bb, type WorldBox as bc, WorldError as bd, WorldLimits as be, type WorldRamp as bf, defineRoom as bg, definitionOf as bh, firstpersonWorld as bi, hullOps as bj, isLiftId as bk, isPresetName as bl, posedWorld as bm, presetInputRepeat as bn, presetParamsValid as bo, resolveContactConfig as bp, resolveFirstpersonParams as bq, resolveInputConfig as br, resolveLifts as bs, resolvePresetParams as bt, resolveTopdownParams as bu, resolveVehicleParams as bv, stepFirstperson as bw, stepPreset as bx, stepTopdown as by, stepVehicle as bz, type LiftVec as c, type PosedSolid as d, type Lift as e, type LiftsPolicy as f, type HullOps as g, type PosedWorld as h, RemotePredict as i, type TopRule as j, type PropSlide as k, ContactDrawing as l, type FirstpersonWorldSpec as m, CONTACT_DEFAULTS as n, CONTACT_PAIRS_MAX as o, CONTACT_PASSES_MAX as p, CONTACT_PRESETS as q, CONTACT_TAG_MAX as r, CONTACT_VALUE_MAX as s, ContactConfigError as t, type ContactDeclaration as u, ContactPreset as v, type ContactPresetParams as w, ContactPush as x, type ContactShape as y, ContactShapeKind as z };
1187
+ export { LiftEase as $, AuthorityLifetime as A, INPUT_SETTLE_MS as B, type ContactPolicy as C, type InitContext as D, type EntityData as E, InputConfigError as F, type GenexRoomModule as G, HeadFriction as H, type InputData as I, type Json as J, type InputDeclaration as K, LeaveReason as L, type InputPolicy as M, LIFETIME_DEFAULT as N, LIFTS_MAX as O, type PlayerInfo as P, LIFT_ID_MAX as Q, type ResolvedModuleConfig as R, type StandRule as S, type TickHz as T, LIFT_POINTS_MAX as U, LIFT_SPIN_MIN_PERIOD as V, LIFT_TICKS_MAX as W, LIFT_VALUE_MAX as X, LifetimeConfigError as Y, type LifetimeDeclaration as Z, type LifetimePolicy as _, type PhysicsErrorCode as a, LiftImpart as a0, type LiftPath as a1, LiftPathMode as a2, type LiftShape as a3, LiftShapeKind as a4, type LiftSpin as a5, type LiftTooFast as a6, type LiftsApi as a7, LiftsConfigError as a8, MODULE_CONTRACT as a9, type ProjectileField as aA, type ProjectileFlight as aB, type ProjectileHit as aC, type ProjectileInit as aD, type Quat as aE, type ResolvedPhysics as aF, type RewindApi as aG, type RewoundPose as aH, type RoomContext as aI, SHOOTER_CENTER as aJ, type ShotWorldSpec as aK, type SlideRule as aL, TopPolicy as aM, type Vec3 as aN, type WorldApi as aO, type WorldClaim as aP, type WorldClaimOptions as aQ, type WorldRayHit as aR, type WorldRayOptions as aS, defineRoom as aT, isLiftId as aU, presetInputRepeat as aV, resolveContactConfig as aW, resolveInputConfig as aX, resolveLifetime as aY, resolveLifts as aZ, type ModuleConfig as aa, NO_LIFTS as ab, type PairRule as ac, type PhysicsAnswer as ad, type PhysicsApi as ae, type PhysicsBodyDesc as af, type PhysicsBodyState as ag, type PhysicsBodyType as ah, type PhysicsColliderDesc as ai, type PhysicsCommandResult as aj, type PhysicsCommands as ak, type PhysicsEvent as al, type PhysicsGroups as am, type PhysicsHit as an, type PhysicsJointDesc as ao, type PhysicsLimits as ap, type PhysicsMotor as aq, type PhysicsOverlap as ar, type PhysicsPose as as, type PhysicsQueryFilter as at, type PhysicsRefusal as au, type PhysicsRequest as av, type PhysicsSetPoseOptions as aw, type PhysicsShape as ax, type PresetSpec as ay, type ProjectileApi as az, InputRepeat as b, type LiftVec as c, type Lift as d, type LiftsPolicy as e, RemotePredict as f, type TopRule as g, type PropSlide as h, ContactDrawing as i, CONTACT_DEFAULTS as j, CONTACT_PAIRS_MAX as k, CONTACT_PASSES_MAX as l, CONTACT_PRESETS as m, CONTACT_TAG_MAX as n, CONTACT_VALUE_MAX as o, ContactConfigError as p, type ContactDeclaration as q, ContactPreset as r, type ContactPresetParams as s, ContactPush as t, type ContactShape as u, ContactShapeKind as v, type EntityApi as w, type EntityInit as x, INPUTS_DEFAULT as y, INPUT_PRESETS as z };