@genex-ai/multiplayer 0.17.1 → 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.
- package/PROTOCOL.md +761 -9
- package/README.md +285 -1
- package/WORLD-GLTF.md +109 -0
- package/WORLD-SCENE.md +135 -0
- package/dist/authority/fast-udp.d.ts +15 -0
- package/dist/authority/fast-udp.js +14 -0
- package/dist/authority/fast-webtransport.d.ts +67 -0
- package/dist/authority/fast-webtransport.js +21 -0
- package/dist/authority/index.d.ts +2671 -0
- package/dist/authority/index.js +958 -0
- package/dist/authority/module.d.ts +2 -0
- package/dist/authority/module.js +12 -0
- package/dist/bridge-authority.d.ts +101 -0
- package/dist/bridge-authority.global.js +15 -0
- package/dist/bridge-authority.js +291 -0
- package/dist/bridge-core-Dhc73GC8.d.ts +27 -0
- package/dist/bridge.d.ts +26 -20
- package/dist/bridge.global.js +7 -7
- package/dist/bridge.js +17 -48
- package/dist/chunk-2NGXXQDS.js +1916 -0
- package/dist/chunk-4R7C2TLH.js +68 -0
- package/dist/{chunk-C52XFIB6.js → chunk-CSQEEANB.js} +217 -4
- package/dist/chunk-FPWP22Y7.js +143 -0
- package/dist/chunk-NFMGIKFZ.js +2627 -0
- package/dist/chunk-OD6NRSX2.js +29 -0
- package/dist/{chunk-3ZUPU3GT.js → chunk-QY3QQNDJ.js} +13 -122
- package/dist/chunk-QZOCUQJT.js +6900 -0
- package/dist/chunk-TSYEWPVO.js +44 -0
- package/dist/chunk-TVTVIMIH.js +675 -0
- package/dist/chunk-YWQ3ALYY.js +69 -0
- package/dist/fast-client--A88q0kk.d.ts +546 -0
- package/dist/index.d.ts +3 -5
- package/dist/index.js +3 -2
- package/dist/join-CGoInvUM.d.ts +6 -0
- package/dist/level-build-CbRqrYJq.d.ts +140 -0
- package/dist/module-CSpXrzFc.d.ts +1187 -0
- package/dist/physics-predict-C7ZB1gDG.d.ts +1223 -0
- package/dist/protocol.d.ts +222 -2
- package/dist/protocol.js +47 -1
- package/dist/shot-world-D22tqOUT.d.ts +485 -0
- package/dist/world-fit/index.d.ts +549 -0
- package/dist/world-fit/index.js +4763 -0
- package/dist/world-fit/three.d.ts +77 -0
- package/dist/world-fit/three.js +140 -0
- package/package.json +46 -4
|
@@ -0,0 +1,1223 @@
|
|
|
1
|
+
import { ap as PhysicsLimits, T as TickHz, a as PhysicsErrorCode, aF as ResolvedPhysics, ay as PresetSpec, f as RemotePredict, h as PropSlide, e as LiftsPolicy } from './module-CSpXrzFc.js';
|
|
2
|
+
|
|
3
|
+
/** The contract version a physics room's world is created with (C§4 `WorldDesc.contract`). */
|
|
4
|
+
declare const PHYSICS_CONTRACT = "1.0";
|
|
5
|
+
/** C§11's default limits. `worldExtent` and `maxSpeed` are given per unit of `lengthUnit` (their
|
|
6
|
+
* default at lengthUnit 1): the contract's defaults are 100_000 · lengthUnit and 1_000 · lengthUnit. */
|
|
7
|
+
declare const PHYSICS_DEFAULT_LIMITS: Readonly<PhysicsLimits>;
|
|
8
|
+
/** Every limit name, in C§11's order. */
|
|
9
|
+
declare const PHYSICS_LIMIT_NAMES: readonly (keyof PhysicsLimits)[];
|
|
10
|
+
/** The limits measured in room units: their default and their ceiling scale with `lengthUnit`. */
|
|
11
|
+
declare const PHYSICS_SCALED_LIMITS: readonly (keyof PhysicsLimits)[];
|
|
12
|
+
/** The limits that may be any number above 0; every other limit is an integer above 0. */
|
|
13
|
+
declare const PHYSICS_REAL_LIMITS: readonly (keyof PhysicsLimits)[];
|
|
14
|
+
/** A paid tier raises a limit at most to this many times its default (C§11). */
|
|
15
|
+
declare const PHYSICS_CEILING_FACTOR = 4;
|
|
16
|
+
/** What a world past the default `staticPieces` adds to the room's `memoryBytes`, per piece: above the core's model of
|
|
17
|
+
* any piece (C§11.1: a box 1,568 bytes, an 8-point ramp 1,954), so the world leaves a room the bodies and contacts the
|
|
18
|
+
* default gives one. */
|
|
19
|
+
declare const PHYSICS_STATIC_PIECE_BYTES = 2048;
|
|
20
|
+
/** The largest world a predicting room holds (§17.11): what every shipped client's core imports. Past it the client's
|
|
21
|
+
* core refuses the world, so the host draws the bodies from the server for every seat rather than leave each to find out. */
|
|
22
|
+
declare const PHYSICS_PREDICT_MAX_BOXES = 4096;
|
|
23
|
+
declare const PHYSICS_PREDICT_MAX_RAMPS = 512;
|
|
24
|
+
/** Whether a room with this static world predicts when it asks to. */
|
|
25
|
+
declare const physicsWorldPredicts: (boxes: number, ramps: number) => boolean;
|
|
26
|
+
/** A room's limits for a static world of `pieces` solids (§17.10 *The static world*). A world the limits hold changes
|
|
27
|
+
* nothing: the description, and with it `physicsHash`, stay as they were. A larger one is the module's map, not a
|
|
28
|
+
* paid extra: `staticPieces` rises to it and `memoryBytes` by its size, up to the core's ceiling. A module that lowered
|
|
29
|
+
* `staticPieces` asked for less, and the core refuses its world. */
|
|
30
|
+
declare function physicsLimitsForWorld(limits: PhysicsLimits, pieces: number): PhysicsLimits;
|
|
31
|
+
/** A room's limit ceiling as its admission grants it, with `worldExtent` and `maxSpeed` per unit
|
|
32
|
+
* of `lengthUnit`, like {@link PHYSICS_DEFAULT_LIMITS}. Each limit is between its default and
|
|
33
|
+
* {@link PHYSICS_CEILING_FACTOR} times it. In release 1 every room's ceiling is the default. */
|
|
34
|
+
type PhysicsCeiling = Readonly<PhysicsLimits>;
|
|
35
|
+
/** Release 1's ceiling: the contract's defaults. */
|
|
36
|
+
declare const PHYSICS_DEFAULT_CEILING: PhysicsCeiling;
|
|
37
|
+
/** Whether `ceiling` is one admission may grant: every limit present, each between its default and
|
|
38
|
+
* 4× it (`worldExtent` and `maxSpeed` per unit of `lengthUnit`). */
|
|
39
|
+
declare function physicsCeilingValid(ceiling: unknown): ceiling is PhysicsCeiling;
|
|
40
|
+
/** Limits given per unit of `lengthUnit` (a ceiling, or the defaults) at the room's `lengthUnit`:
|
|
41
|
+
* `worldExtent` and `maxSpeed` multiplied by it in float64, the rest as they are. */
|
|
42
|
+
declare function physicsLimitsAt(perUnit: Readonly<PhysicsLimits>, lengthUnit: number): PhysicsLimits;
|
|
43
|
+
/** The ranges of `config.physics` (§17.10 *Opt-in*). */
|
|
44
|
+
declare const PhysicsConfigRange: {
|
|
45
|
+
/** `lengthUnit` is in (0, MAX_LENGTH_UNIT]. */
|
|
46
|
+
readonly MAX_LENGTH_UNIT: 1000000;
|
|
47
|
+
/** `gravity` is in [0, MAX_GRAVITY]; a default is never refused. */
|
|
48
|
+
readonly MAX_GRAVITY: 10000000;
|
|
49
|
+
/** Gravity without a world-stepping preset: this many metres per second squared. */
|
|
50
|
+
readonly EARTH_GRAVITY: 9.81;
|
|
51
|
+
readonly MIN_ITERATIONS: 1;
|
|
52
|
+
readonly MAX_ITERATIONS: 16;
|
|
53
|
+
readonly DEFAULT_ITERATIONS: 4;
|
|
54
|
+
/** Distinct physics kinds `subscribe` may name. */
|
|
55
|
+
readonly MAX_SUBSCRIBE_KINDS: 8;
|
|
56
|
+
/** `player.radius` and `player.height` are in (0, MAX_PLAYER_SIZE]. */
|
|
57
|
+
readonly MAX_PLAYER_SIZE: 1000000;
|
|
58
|
+
};
|
|
59
|
+
/** The `lengthUnit` a preset implies when the module gives none: its units are inches (Source's
|
|
60
|
+
* `firstperson`) or centimetres (`vehicle`); anything else is metres. */
|
|
61
|
+
declare const PHYSICS_PRESET_LENGTH_UNITS: Readonly<Partial<Record<string, number>>>;
|
|
62
|
+
/** The keyframe rates a predicting room may ask for (`config.physics.patchHz`). */
|
|
63
|
+
declare const PHYSICS_PATCH_HZ: readonly number[];
|
|
64
|
+
/** `patchHz` when the module names none: K 1 at 20 Hz, 3 at 60 Hz, 6 at 120 Hz, and (15 Hz) 2 at
|
|
65
|
+
* 30 Hz. A car-ball room asks for 60 (K 2 at 120 Hz). */
|
|
66
|
+
declare const PHYSICS_DEFAULT_PATCH_HZ = 20;
|
|
67
|
+
/** The client prediction knobs a module may set (§17.11): their defaults and ranges. */
|
|
68
|
+
declare const PhysicsPredictRange: {
|
|
69
|
+
readonly DEFAULT_REMOTE_PREDICT: "extrapolate";
|
|
70
|
+
readonly DEFAULT_REMOTE_DECAY_MS: 50;
|
|
71
|
+
readonly MAX_REMOTE_DECAY_MS: 1000;
|
|
72
|
+
readonly DEFAULT_LEAD_MS: 250;
|
|
73
|
+
readonly MIN_LEAD_MS: 50;
|
|
74
|
+
readonly MAX_LEAD_MS: 1000;
|
|
75
|
+
};
|
|
76
|
+
/** Whether `v` is a keyframe rate a module may ask for. */
|
|
77
|
+
declare function isPhysicsPatchHz(v: unknown): v is number;
|
|
78
|
+
/** The keyframe rate a room at `tickHz` runs for a requested `patchHz`: the largest allowed rate at
|
|
79
|
+
* or below it that divides the tick rate (20 at 30 Hz is 15). */
|
|
80
|
+
declare function effectivePatchHz(tickHz: TickHz, patchHz: number): number;
|
|
81
|
+
/** K, the ticks between two keyframes: tickHz / the effective patchHz, a whole number ≥ 1. A
|
|
82
|
+
* keyframe is the state after every tick t with t ≡ 0 (mod K). */
|
|
83
|
+
declare function keyframeTicks(tickHz: TickHz, patchHz: number): number;
|
|
84
|
+
/** In a predicting room every dynamic body's speed is clamped, by magnitude and every tick, to the
|
|
85
|
+
* wire's velocity range: linear to this many metres per second (× lengthUnit), angular to this many
|
|
86
|
+
* rad/s (§17.11 *The tick*). */
|
|
87
|
+
declare const PHYSICS_PREDICT_MAX_LINEAR = 64;
|
|
88
|
+
declare const PHYSICS_PREDICT_MAX_ANGULAR = 64;
|
|
89
|
+
/**
|
|
90
|
+
* The stacking hook (§17.11): the solver iterations a predicting room runs at least. Canonicalizing
|
|
91
|
+
* drops warm starts, and the R2-0b experiment measured stacks of 10 and more falling over at 4
|
|
92
|
+
* iterations. The engine lane's stacking rule sets this; until then (null) a predicting room runs the
|
|
93
|
+
* module's own `iterations`.
|
|
94
|
+
*/
|
|
95
|
+
declare const PHYSICS_PREDICT_MIN_ITERATIONS: number | null;
|
|
96
|
+
/** The solver iterations a room runs: the module's, raised to the stacking hook when it predicts. */
|
|
97
|
+
declare function solverIterationsOf(physics: ResolvedPhysics, predicting: boolean): number;
|
|
98
|
+
/** A contract key is at most this many bytes, a physics kind at most this many. */
|
|
99
|
+
declare const PHYSICS_KEY_MAX_BYTES = 64;
|
|
100
|
+
declare const PHYSICS_KIND_MAX_BYTES = 32;
|
|
101
|
+
/** The prefix the contract keeps for static pieces (C§6.5): no body, collider or joint key has it. */
|
|
102
|
+
declare const PHYSICS_STATIC_PREFIX = "static:";
|
|
103
|
+
/** Whether `v` is a contract key fit to be a body's key: 1-64 bytes of `[A-Za-z0-9_.:-]` (ASCII, so
|
|
104
|
+
* a byte is a character), not `__proto__`, `constructor` or `prototype`, not starting `static:`.
|
|
105
|
+
* An entity with a body must have such an id; any other is refused with `invalid-key`. */
|
|
106
|
+
declare function isPhysicsKey(v: unknown): v is string;
|
|
107
|
+
/** Whether `v` is a physics kind: 1-32 bytes of the key charset. '' (or absent) means none and is
|
|
108
|
+
* not a kind; the host passes it to the core absent. */
|
|
109
|
+
declare function isPhysicsKind(v: unknown): v is string;
|
|
110
|
+
/** A resolved `config.physics` (null = no physics), or the path of the first bad value. */
|
|
111
|
+
type PhysicsResolution = {
|
|
112
|
+
ok: true;
|
|
113
|
+
value: ResolvedPhysics | null;
|
|
114
|
+
} | {
|
|
115
|
+
ok: false;
|
|
116
|
+
path: string;
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Resolves a module's `config.physics` (§17.10 *Opt-in*, *The resolved config*): `true` is `{}`;
|
|
120
|
+
* absent, `false` and `null` are no physics. Defaults are filled in (`lengthUnit` and `gravity` from
|
|
121
|
+
* the resolved `preset`), every limit is set and clamped to `ceiling` at the room's `lengthUnit`.
|
|
122
|
+
* `ceiling` is the room's admission: null when it was admitted without physics, which refuses a
|
|
123
|
+
* module that asks for it, as a ceiling refuses a module that does not. This is the reference the
|
|
124
|
+
* sandbox prelude ports.
|
|
125
|
+
*/
|
|
126
|
+
declare function resolvePhysicsConfig(request: unknown, preset: PresetSpec | null, ceiling: PhysicsCeiling | null): PhysicsResolution;
|
|
127
|
+
/** Checks the sandbox's resolved `config.physics` from `InitOut`: null, or every key present and
|
|
128
|
+
* in range, no limit above `ceiling` at its `lengthUnit`. Returns a fresh copy. */
|
|
129
|
+
declare function checkResolvedPhysics(resolved: unknown, preset: PresetSpec | null, ceiling: PhysicsCeiling | null): PhysicsResolution;
|
|
130
|
+
/** The core's sub-steps per tick at each tick rate: about 60 Hz of inner steps. */
|
|
131
|
+
declare const PHYSICS_SUBSTEPS: Readonly<Record<TickHz, number>>;
|
|
132
|
+
/** The contract's `WorldDesc` (C§4) as the host builds it for a room: z up, `dt` one tick. */
|
|
133
|
+
interface PhysicsWorldDesc {
|
|
134
|
+
contract: typeof PHYSICS_CONTRACT;
|
|
135
|
+
dt: number;
|
|
136
|
+
substeps: number;
|
|
137
|
+
gravity: [number, number, number];
|
|
138
|
+
upAxis: 'z';
|
|
139
|
+
lengthUnit: number;
|
|
140
|
+
limits: PhysicsLimits;
|
|
141
|
+
solver: {
|
|
142
|
+
iterations: number;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/** The world a room with `physics` at `tickHz` creates; a predicting room's solver iterations follow
|
|
146
|
+
* the stacking hook ({@link solverIterationsOf}). */
|
|
147
|
+
declare function physicsWorldDesc(physics: ResolvedPhysics, tickHz: TickHz, predicting?: boolean, worldPieces?: number): PhysicsWorldDesc;
|
|
148
|
+
/** `physEv`'s kind codes. */
|
|
149
|
+
declare const PhysEvKind: {
|
|
150
|
+
readonly CONTACT_BEGIN: 0;
|
|
151
|
+
readonly CONTACT_END: 1;
|
|
152
|
+
readonly TRIGGER_ENTER: 2;
|
|
153
|
+
readonly TRIGGER_EXIT: 3;
|
|
154
|
+
};
|
|
155
|
+
type PhysEvKind = (typeof PhysEvKind)[keyof typeof PhysEvKind];
|
|
156
|
+
/** A `contactBegin` event: kind code, the two bodies, their colliders, their kinds ('' = none), the
|
|
157
|
+
* impulse, the contact point and the normal. */
|
|
158
|
+
type PhysEvContactBegin = [
|
|
159
|
+
kind: typeof PhysEvKind.CONTACT_BEGIN,
|
|
160
|
+
a: string,
|
|
161
|
+
b: string,
|
|
162
|
+
ca: string,
|
|
163
|
+
cb: string,
|
|
164
|
+
ka: string,
|
|
165
|
+
kb: string,
|
|
166
|
+
impulse: number,
|
|
167
|
+
px: number,
|
|
168
|
+
py: number,
|
|
169
|
+
pz: number,
|
|
170
|
+
nx: number,
|
|
171
|
+
ny: number,
|
|
172
|
+
nz: number
|
|
173
|
+
];
|
|
174
|
+
/** Every other event ends after the kinds. A trigger puts `sensor, other, sc, oc, ks, ko` in the
|
|
175
|
+
* places of `a, b, ca, cb, ka, kb`. */
|
|
176
|
+
type PhysEvOther = [
|
|
177
|
+
kind: Exclude<PhysEvKind, typeof PhysEvKind.CONTACT_BEGIN>,
|
|
178
|
+
a: string,
|
|
179
|
+
b: string,
|
|
180
|
+
ca: string,
|
|
181
|
+
cb: string,
|
|
182
|
+
ka: string,
|
|
183
|
+
kb: string
|
|
184
|
+
];
|
|
185
|
+
type PhysEvRow = PhysEvContactBegin | PhysEvOther;
|
|
186
|
+
/** A ray or shape-cast hit: body, collider, distance, point, normal. */
|
|
187
|
+
type PhysHitRow = [body: string, collider: string, dist: number, px: number, py: number, pz: number, nx: number, ny: number, nz: number];
|
|
188
|
+
/** An overlap: `more` (1 when the core found more than the keys listed, else 0), then the keys. */
|
|
189
|
+
type PhysOverlapRow = [more: 0 | 1, ...keys: string[]];
|
|
190
|
+
/** One answer: null (no hit), a hit, an overlap, or a refused query's C§14 code. */
|
|
191
|
+
type PhysAnswerRow = PhysHitRow | PhysOverlapRow | PhysicsErrorCode | null;
|
|
192
|
+
/** A subscribed body's state: key, position, rotation, linear and angular velocity, sleeping. */
|
|
193
|
+
type PhysBodyRow = [
|
|
194
|
+
key: string,
|
|
195
|
+
px: number,
|
|
196
|
+
py: number,
|
|
197
|
+
pz: number,
|
|
198
|
+
qx: number,
|
|
199
|
+
qy: number,
|
|
200
|
+
qz: number,
|
|
201
|
+
qw: number,
|
|
202
|
+
vx: number,
|
|
203
|
+
vy: number,
|
|
204
|
+
vz: number,
|
|
205
|
+
wx: number,
|
|
206
|
+
wy: number,
|
|
207
|
+
wz: number,
|
|
208
|
+
sleeping: 0 | 1
|
|
209
|
+
];
|
|
210
|
+
/** An overlap answer lists at most this many keys. */
|
|
211
|
+
declare const PHYSICS_OVERLAP_MAX_KEYS = 64;
|
|
212
|
+
/** The physics fields of `AuthorityEntity`, which the host writes on body entities only. */
|
|
213
|
+
declare const PHYSICS_BODY_FIELDS: readonly ["qx", "qy", "qz", "qw", "lvx", "lvy", "lvz", "avx", "avy", "avz", "sleep"];
|
|
214
|
+
type PhysicsBodyField = (typeof PHYSICS_BODY_FIELDS)[number];
|
|
215
|
+
/** Every field the host owns on a body entity: its position and its physics fields. A module that
|
|
216
|
+
* writes one of these on a body entity is refused. */
|
|
217
|
+
declare const HOST_BODY_FIELDS: readonly string[];
|
|
218
|
+
/** A quantized body field's range. Each is 16 bits, clamped; its span is 65534 (the range is
|
|
219
|
+
* symmetric about 0, so 0 is exact). */
|
|
220
|
+
interface QuantizedRange {
|
|
221
|
+
readonly min: number;
|
|
222
|
+
readonly max: number;
|
|
223
|
+
}
|
|
224
|
+
declare const BodyQuantization: {
|
|
225
|
+
readonly BITS: 16;
|
|
226
|
+
/** Integer steps across a symmetric range (2^16 − 2). */
|
|
227
|
+
readonly SPAN: 65534;
|
|
228
|
+
/** `qx qy qz qw`. */
|
|
229
|
+
readonly ORIENTATION: QuantizedRange;
|
|
230
|
+
/** `lvx lvy lvz` (metres per second: velocity divided by lengthUnit) and `avx avy avz` (rad/s). */
|
|
231
|
+
readonly VELOCITY: QuantizedRange;
|
|
232
|
+
};
|
|
233
|
+
/** The uint16 a quantized field sends for `v` (Colyseus schema 5's clamp rule): out of range
|
|
234
|
+
* clamps, NaN is `min`. */
|
|
235
|
+
declare function quantizeBodyValue(v: number, range: QuantizedRange): number;
|
|
236
|
+
/** The value a client decodes from the uint16 `q`, in float64. */
|
|
237
|
+
declare function dequantizeBodyValue(q: number, range: QuantizedRange): number;
|
|
238
|
+
/** In a predicting room a body within this many metres (× lengthUnit) of any seat's own entity is
|
|
239
|
+
* contested: it is in every client's view at every keyframe, asleep or not, ahead of every other
|
|
240
|
+
* (§17.11 *Interest*; a ball at rest that no update reaches is the "phantom ball"). */
|
|
241
|
+
declare const PHYSICS_CONTESTED_METRES = 6;
|
|
242
|
+
/** Body entities each client receives at full rate per patch, then the rotating ones after them. */
|
|
243
|
+
declare const PHYSICS_FULL_RATE_BODIES = 100;
|
|
244
|
+
declare const PHYSICS_ROTATING_BODIES = 25;
|
|
245
|
+
/** A client extrapolates a body at most this far past its latest state. */
|
|
246
|
+
declare const BODY_EXTRAPOLATE_MAX_MS = 250;
|
|
247
|
+
/** A state that arrives before its own tick is moved back at most this many ticks (it lands up to
|
|
248
|
+
* one early: tick t is stepped at its instant and its state is the body at t + 1). */
|
|
249
|
+
declare const BODY_EXTRAPOLATE_BACK_TICKS = 1;
|
|
250
|
+
/** A correction's offset decays as e^(−age / BODY_CORRECTION_TAU_MS). */
|
|
251
|
+
declare const BODY_CORRECTION_TAU_MS = 100;
|
|
252
|
+
/** A correction over this many metres (times lengthUnit, in room units) snaps instead. */
|
|
253
|
+
declare const BODY_SNAP_METRES = 1;
|
|
254
|
+
|
|
255
|
+
type DrawVec3 = readonly [number, number, number];
|
|
256
|
+
type DrawQuat = readonly [number, number, number, number];
|
|
257
|
+
/** A body's pose as drawn: position in room units, unit orientation [x, y, z, w]. */
|
|
258
|
+
interface BodyPose {
|
|
259
|
+
p: DrawVec3;
|
|
260
|
+
q: DrawQuat;
|
|
261
|
+
}
|
|
262
|
+
/** A body entity's §17.10 fields as a decoder holds them (quantized fields already decoded to
|
|
263
|
+
* float64, a field never received read as 0 / false). */
|
|
264
|
+
interface BodyFields {
|
|
265
|
+
x: number;
|
|
266
|
+
y: number;
|
|
267
|
+
z: number;
|
|
268
|
+
qx: number;
|
|
269
|
+
qy: number;
|
|
270
|
+
qz: number;
|
|
271
|
+
qw: number;
|
|
272
|
+
lvx: number;
|
|
273
|
+
lvy: number;
|
|
274
|
+
lvz: number;
|
|
275
|
+
avx: number;
|
|
276
|
+
avy: number;
|
|
277
|
+
avz: number;
|
|
278
|
+
sleep: boolean;
|
|
279
|
+
epoch: number;
|
|
280
|
+
}
|
|
281
|
+
/** One body state off one patch. */
|
|
282
|
+
interface BodyState {
|
|
283
|
+
/** The tick this state is the body at: the patch's `tick` + 1. */
|
|
284
|
+
tick: number;
|
|
285
|
+
/** Position, room units (the server's float32). */
|
|
286
|
+
p: DrawVec3;
|
|
287
|
+
/** Orientation, normalized. */
|
|
288
|
+
q: DrawQuat;
|
|
289
|
+
/** Linear velocity, metres per second (multiply by lengthUnit for room units). */
|
|
290
|
+
lv: DrawVec3;
|
|
291
|
+
/** Angular velocity in world axes, rad/s. */
|
|
292
|
+
av: DrawVec3;
|
|
293
|
+
sleep: boolean;
|
|
294
|
+
epoch: number;
|
|
295
|
+
}
|
|
296
|
+
/** The room facts drawing reads: its tick rate, the room clock at tick 0 (`tickOrigin`) and the
|
|
297
|
+
* world's `lengthUnit`. Read fresh per call: `tickOrigin` moves when the server drops steps. */
|
|
298
|
+
interface DrawClock {
|
|
299
|
+
tickHz: number;
|
|
300
|
+
tickOrigin: number;
|
|
301
|
+
lengthUnit: number;
|
|
302
|
+
}
|
|
303
|
+
/** Hamilton product a ⊗ b. */
|
|
304
|
+
declare function quatMul(a: DrawQuat, b: DrawQuat): DrawQuat;
|
|
305
|
+
/** `q` scaled to unit length; a quaternion of length 0 is the identity. */
|
|
306
|
+
declare function quatNormalize(q: DrawQuat): DrawQuat;
|
|
307
|
+
/** slerp(identity, dq, k) for a `dq` with w ≥ 0: the rotation by k·θ about dq's axis, where
|
|
308
|
+
* θ = 2·atan2(|v|, w) is dq's own angle. */
|
|
309
|
+
declare function slerpFromIdentity(dq: DrawQuat, k: number): DrawQuat;
|
|
310
|
+
/** The state a patch whose `tick` was `patchTick` carries for a body. */
|
|
311
|
+
declare function bodyStateOf(fields: BodyFields, patchTick: number): BodyState;
|
|
312
|
+
/** How far past its own tick `state` is extrapolated at room-clock instant `at` (ms): seconds in
|
|
313
|
+
* [−BODY_EXTRAPOLATE_BACK_TICKS / tickHz, BODY_EXTRAPOLATE_MAX_MS / 1000], and 0 while it sleeps.
|
|
314
|
+
* Before its tick (the patch after a step lands up to a tick early) it is moved back, so the body is
|
|
315
|
+
* drawn at the present: held there, it was drawn ahead and every state eased in a tick's travel off. */
|
|
316
|
+
declare function extrapolationSeconds(state: BodyState, at: number, clock: DrawClock): number;
|
|
317
|
+
/** `state` extrapolated to room-clock instant `at`: p + (lv · lengthUnit) · Δ, and the orientation
|
|
318
|
+
* turned by |av| · Δ about av / |av| (world axes, so on the left), normalized. */
|
|
319
|
+
declare function extrapolateBody(state: BodyState, at: number, clock: DrawClock): BodyPose;
|
|
320
|
+
/** One body as a client draws it: its latest state, and the correction its arrival started. */
|
|
321
|
+
interface BodyDrawing {
|
|
322
|
+
readonly state: BodyState;
|
|
323
|
+
/** Room-clock instant the state arrived, ms. */
|
|
324
|
+
readonly arrivedAt: number;
|
|
325
|
+
/** Position offset at arrival (older drawn − newer extrapolated), room units. */
|
|
326
|
+
readonly dp: DrawVec3;
|
|
327
|
+
/** Orientation offset at arrival (older drawn ⊗ newer⁻¹, w ≥ 0). */
|
|
328
|
+
readonly dq: DrawQuat;
|
|
329
|
+
}
|
|
330
|
+
/** Why the last state was not eased in. */
|
|
331
|
+
declare const BodySnap: {
|
|
332
|
+
/** Its first state since it got its descriptor. */
|
|
333
|
+
readonly SPAWNED: "spawned";
|
|
334
|
+
readonly EPOCH: "epoch";
|
|
335
|
+
/** The offset was over one metre. */
|
|
336
|
+
readonly DISTANCE: "distance";
|
|
337
|
+
};
|
|
338
|
+
type BodySnap = (typeof BodySnap)[keyof typeof BodySnap];
|
|
339
|
+
/** Where `drawing` draws its body at room-clock instant `at`. */
|
|
340
|
+
declare function drawBody(drawing: BodyDrawing, at: number, clock: DrawClock): BodyPose;
|
|
341
|
+
/**
|
|
342
|
+
* The drawing after `state` arrives at room-clock instant `at`. `previous` is the body's drawing
|
|
343
|
+
* until now (null when it just got its descriptor, `spawned`). Returns the new drawing and, when it
|
|
344
|
+
* snapped instead of easing, why.
|
|
345
|
+
*/
|
|
346
|
+
declare function receiveBodyState(previous: BodyDrawing | null, state: BodyState, at: number, clock: DrawClock): {
|
|
347
|
+
drawing: BodyDrawing;
|
|
348
|
+
snap: BodySnap | null;
|
|
349
|
+
};
|
|
350
|
+
/** Whether two states are the same body state (every field, the tick aside): a patch that did not
|
|
351
|
+
* change the body carries no new state. */
|
|
352
|
+
declare function sameBodyState(a: BodyState, b: BodyState): boolean;
|
|
353
|
+
|
|
354
|
+
/** Numbers per body in a wire row (C§20.2). */
|
|
355
|
+
declare const WIRE_ROW_STRIDE = 15;
|
|
356
|
+
/** The largest sleep timer a row carries, in inner steps. */
|
|
357
|
+
declare const WIRE_REST_MAX = 65535;
|
|
358
|
+
/** The room's `physDesc` (§17.11 *State*): what a client needs to build the room's world exactly. */
|
|
359
|
+
interface PhysDesc {
|
|
360
|
+
/** The contract's world description, as the server created the world. */
|
|
361
|
+
world: PhysicsWorldDesc;
|
|
362
|
+
/** K: a keyframe is the state after every tick t ≡ 0 (mod K). */
|
|
363
|
+
keyframeTicks: number;
|
|
364
|
+
/** The speed clamp: metres per second (× lengthUnit) and rad/s. */
|
|
365
|
+
maxLinear: number;
|
|
366
|
+
maxAngular: number;
|
|
367
|
+
/** The seats' preset bodies (§17.10 *Preset bodies*): a kinematic box of these half-extents,
|
|
368
|
+
* `events` its collider's opt-in; null in a room without them. */
|
|
369
|
+
presetBody: PresetBodyShape | null;
|
|
370
|
+
/** How the client moves other players' preset bodies (`config.physics.remotePredict`). */
|
|
371
|
+
remotePredict: RemotePredict;
|
|
372
|
+
/** `inputDecay`: ms until a repeated input's axes reach 0. */
|
|
373
|
+
remoteDecayMs: number;
|
|
374
|
+
/** The lead cap, ms past a keyframe's ack. */
|
|
375
|
+
leadMs: number;
|
|
376
|
+
}
|
|
377
|
+
/** The client knobs of a predicting room, as `physDesc` carries them. */
|
|
378
|
+
type PhysDescPredict = Pick<PhysDesc, 'remotePredict' | 'remoteDecayMs' | 'leadMs'>;
|
|
379
|
+
/** A preset body's collider as the host spawns it. */
|
|
380
|
+
interface PresetBodyShape {
|
|
381
|
+
half: [number, number, number];
|
|
382
|
+
events: boolean;
|
|
383
|
+
}
|
|
384
|
+
/** The state's `physDesc` text: the keys in this order, numbers as JavaScript prints them. */
|
|
385
|
+
declare function physDescText(world: PhysicsWorldDesc, keyframeTicks: number, presetBody: PresetBodyShape | null, predict: PhysDescPredict): string;
|
|
386
|
+
/** Reads `physDesc` text; null when it is absent or not one. */
|
|
387
|
+
declare function parsePhysDesc(text: string | undefined): PhysDesc | null;
|
|
388
|
+
/** One inner step, as the core computes it: `dt / substeps` in float32 (C§20.2). */
|
|
389
|
+
declare function innerDtOf(world: Pick<PhysicsWorldDesc, 'dt' | 'substeps'>): number;
|
|
390
|
+
/** A sleep timer (seconds, float32) in whole inner steps, rounded, at most {@link WIRE_REST_MAX}:
|
|
391
|
+
* `min(65535, floor(rest / innerDt + 0.5))` in float64 (C§20.2). */
|
|
392
|
+
declare function restStepsOf(rest: number, innerDt: number): number;
|
|
393
|
+
/** A body entity's fields as a decoder holds them (§17.10 *State*, §17.11's `rest`). */
|
|
394
|
+
interface WireFields {
|
|
395
|
+
x: number;
|
|
396
|
+
y: number;
|
|
397
|
+
z: number;
|
|
398
|
+
qx: number;
|
|
399
|
+
qy: number;
|
|
400
|
+
qz: number;
|
|
401
|
+
qw: number;
|
|
402
|
+
lvx: number;
|
|
403
|
+
lvy: number;
|
|
404
|
+
lvz: number;
|
|
405
|
+
avx: number;
|
|
406
|
+
avy: number;
|
|
407
|
+
avz: number;
|
|
408
|
+
sleep: boolean;
|
|
409
|
+
rest: number;
|
|
410
|
+
}
|
|
411
|
+
/** The wire row of a body entity's decoded fields, written into `out` at `offset`: a decoded
|
|
412
|
+
* quantized value quantizes back to the integer the wire sent (`dequantize` then `quantize` is the
|
|
413
|
+
* identity on integers), so the row is exactly what the server's canonical state was. */
|
|
414
|
+
declare function writeWireRow(fields: WireFields, out: Float32Array | number[], offset: number): void;
|
|
415
|
+
/** A core export (`exportChanged(…, { rest: true })`, 15 numbers a body) as the wire row the host
|
|
416
|
+
* sends for it, at `lengthUnit` (the world's, as float32): what a client imports. */
|
|
417
|
+
declare function wireRowOfExport(d: ArrayLike<number>, o: number, lengthUnit: number, innerDt: number, out: number[], at: number): void;
|
|
418
|
+
/** A body's replicated state as the core's `exportBodyState(key, { rest: true })` gives it. */
|
|
419
|
+
interface WireBodyState {
|
|
420
|
+
p: ArrayLike<number>;
|
|
421
|
+
q: ArrayLike<number>;
|
|
422
|
+
v: ArrayLike<number>;
|
|
423
|
+
w: ArrayLike<number>;
|
|
424
|
+
sleeping: boolean;
|
|
425
|
+
rest?: number;
|
|
426
|
+
}
|
|
427
|
+
/** A body state as its wire row (the same numbers {@link wireRowOfExport} gives for its export). */
|
|
428
|
+
declare function wireRowOfState(st: WireBodyState, lengthUnit: number, innerDt: number): number[];
|
|
429
|
+
/** A wire row's decoded fields (what a client's decoder would hold for it). */
|
|
430
|
+
declare function wireFieldsOf(row: ArrayLike<number>, o?: number): WireFields;
|
|
431
|
+
type Vec3 = [number, number, number];
|
|
432
|
+
/**
|
|
433
|
+
* The clamp of one dynamic body's velocities (float32 values off an export): null when neither is
|
|
434
|
+
* over its bound, else the `setVelocity` arguments that bring the longer ones to it by magnitude,
|
|
435
|
+
* the other passed as it is. Linear is bounded at `maxLinear · lengthUnit` (lengthUnit the world's
|
|
436
|
+
* float32), angular at `maxAngular`.
|
|
437
|
+
*/
|
|
438
|
+
declare function clampedVelocity(linvel: readonly number[], angvel: readonly number[], lengthUnit: number, maxLinear?: number, maxAngular?: number): {
|
|
439
|
+
linvel: Vec3;
|
|
440
|
+
angvel: Vec3;
|
|
441
|
+
} | null;
|
|
442
|
+
/** The shape kinds that travel by reference: their size grows with their data. */
|
|
443
|
+
declare const SHAPE_REF_KINDS: ReadonlySet<string>;
|
|
444
|
+
/** A room holds at most this many distinct referenced shapes, each at most this many characters of
|
|
445
|
+
* JSON; a body whose shape does not fit has no descriptor text and is drawn, never predicted. */
|
|
446
|
+
declare const PHYSICS_SHAPES_MAX = 32;
|
|
447
|
+
declare const PHYSICS_SHAPE_MAX_CHARS: number;
|
|
448
|
+
/** A canonical body descriptor (C§20.5) parsed, its shapes inlined from `shapes` (reference → JSON
|
|
449
|
+
* text). Null when the text is not a descriptor or names a shape `shapes` lacks. */
|
|
450
|
+
declare function inlineShapes(descText: string, shapes: (ref: string) => string | undefined): Record<string, unknown> | null;
|
|
451
|
+
/** Islands join bodies whose bounding spheres come within this many metres (× lengthUnit). */
|
|
452
|
+
declare const ISLAND_MARGIN_METRES = 0.5;
|
|
453
|
+
/** A body's bounding radius about its origin, from its (inlined) descriptor: every collider's
|
|
454
|
+
* offset plus its shape's radius. */
|
|
455
|
+
declare function bodyRadiusOf(desc: Record<string, unknown>): number;
|
|
456
|
+
/** One body as islands see it: its key, origin and bounding radius (room units). */
|
|
457
|
+
interface IslandBody {
|
|
458
|
+
key: string;
|
|
459
|
+
x: number;
|
|
460
|
+
y: number;
|
|
461
|
+
z: number;
|
|
462
|
+
radius: number;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Proximity islands: body key → island id (the island's first key in code-unit order). Two bodies
|
|
466
|
+
* are joined when the distance between their origins is at most the sum of their radii plus
|
|
467
|
+
* `margin`, or when a joint links them. Sweeps along x, so it costs about n log n for spread bodies.
|
|
468
|
+
*/
|
|
469
|
+
declare function proximityIslands(bodies: readonly IslandBody[], links: readonly (readonly [string, string])[], margin: number): Map<string, string>;
|
|
470
|
+
/** A motor's canonical text: its keys sorted, every number its float32 (§17.11 *State*). */
|
|
471
|
+
declare function motorText(motor: unknown): string;
|
|
472
|
+
/** A seat's last applied input, as a keyframe carries it (`AuthorityPlayer`'s `in*` fields). */
|
|
473
|
+
interface RemoteInput {
|
|
474
|
+
moveX: number;
|
|
475
|
+
moveY: number;
|
|
476
|
+
moveZ: number;
|
|
477
|
+
yaw: number;
|
|
478
|
+
pitch: number;
|
|
479
|
+
buttons: number;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* `inputDecay`: the weight of a remote seat's repeated input on the `j`-th tick after the keyframe
|
|
483
|
+
* (j ≥ 1): whole on the first tick, then falling linearly to 0 at `decayMs`, as
|
|
484
|
+
* clamp(1 − (j − 1) · (1000 / tickHz) / decayMs, 0, 1); with `decayMs` 0, the first tick only.
|
|
485
|
+
* The movement axes are scaled by it; aim (yaw, pitch) and held buttons are repeated as they are, so
|
|
486
|
+
* a button's press edge (a jump, a flip, a boost start) is never predicted.
|
|
487
|
+
*/
|
|
488
|
+
declare function remoteInputWeight(j: number, tickHz: number, decayMs: number): number;
|
|
489
|
+
/** The input a remote seat is stepped with on the `j`-th tick after the keyframe. */
|
|
490
|
+
declare function decayedInput(input: RemoteInput, j: number, tickHz: number, decayMs: number): RemoteInput;
|
|
491
|
+
/** A replay's correction decays with τ by its size: TAU_SMALL_MS up to SMALL_METRES, TAU_LARGE_MS from
|
|
492
|
+
* LARGE_METRES, linear between; it snaps over SNAP_PLAYER_METRES for a player or vehicle body (its
|
|
493
|
+
* physics kind in PLAYER_KINDS) and over SNAP_OTHER_METRES for any other. Physics always takes the
|
|
494
|
+
* exact state; only the drawn offset decays. Another seat drawn `predicted` (§17.11 *Drawing other
|
|
495
|
+
* seats*) returns its correction to 0 critically damped at 1 / SEAT_TAU_MS (1 / SEAT_CONTACT_TAU_MS
|
|
496
|
+
* while it touches your entity in the prediction): it settles to a tenth in about 4 τ (280 ms, a
|
|
497
|
+
* first-order τ of 120 ms) without ever jumping the drawn place or velocity, and snaps over
|
|
498
|
+
* SEAT_SNAP_METRES or at a new life (epoch). It never pulls a seat drawn moving faster than
|
|
499
|
+
* SEAT_MOVING_UNITS_PER_MS (200 u/s) back against that motion while its prediction goes on that way:
|
|
500
|
+
* the seat stops instead, and returns from rest once it has stood SEAT_HOLD_MS. Other seats are drawn
|
|
501
|
+
* at an input moved on with the frame's time and pulled toward yours at 1 / SEAT_CLOCK_TAU_MS
|
|
502
|
+
* (`seatClock`), taken at once past SEAT_CLOCK_SNAP_INPUTS; a seat touching yours is blended onto
|
|
503
|
+
* your exact input over SEAT_CLOCK_TAU_MS (§17.11 *Touching*). */
|
|
504
|
+
declare const PredictSmoothing: {
|
|
505
|
+
readonly TAU_SMALL_MS: 300;
|
|
506
|
+
readonly TAU_LARGE_MS: 100;
|
|
507
|
+
readonly SMALL_METRES: 0.25;
|
|
508
|
+
readonly LARGE_METRES: 1;
|
|
509
|
+
readonly SNAP_PLAYER_METRES: 2;
|
|
510
|
+
readonly SNAP_OTHER_METRES: 6;
|
|
511
|
+
readonly PLAYER_KINDS: readonly string[];
|
|
512
|
+
readonly SEAT_TAU_MS: 70;
|
|
513
|
+
readonly SEAT_CONTACT_TAU_MS: 100;
|
|
514
|
+
readonly SEAT_SNAP_METRES: 6;
|
|
515
|
+
readonly SEAT_HOLD_MS: 120;
|
|
516
|
+
readonly SEAT_MOVING_UNITS_PER_MS: 0.2;
|
|
517
|
+
readonly SEAT_CLOCK_TAU_MS: 100;
|
|
518
|
+
readonly SEAT_CLOCK_SNAP_INPUTS: 1.5;
|
|
519
|
+
};
|
|
520
|
+
/** The share of a correction still drawn `age` ms after it started, τ `tauMs`: critically damped from
|
|
521
|
+
* rest, (1 + age/τ)·e^(−age/τ), so the frame it starts on draws the body where it was drawn (a body
|
|
522
|
+
* moving between the predictor's drawing and §17.10's, `DrawHandoff`). */
|
|
523
|
+
declare function correctionShare(age: number, tauMs: number): number;
|
|
524
|
+
/** A replay's correction of one axis `age` ms after it started from offset `o0` (room units) and rate
|
|
525
|
+
* `r0` (units per ms), τ `tauMs`, critically damped at h = τ/2 (§17.11 *Drawing*; it trails a steady
|
|
526
|
+
* drift by as much as a first-order τ did): the offset (o0 + (r0 + o0/h)·t)·e^(−t/h) and its rate
|
|
527
|
+
* (r0 − (r0 + o0/h)·t/h)·e^(−t/h). A new correction starts
|
|
528
|
+
* from where the body was drawn and keeps the rate the last one had, so a body corrected on every
|
|
529
|
+
* keyframe still comes home, and none is drawn jumping on the frame its correction starts. */
|
|
530
|
+
declare function correctionAt(o0: number, r0: number, age: number, tauMs: number): [number, number];
|
|
531
|
+
/** The τ (ms) of a correction of `metres`. */
|
|
532
|
+
declare function correctionTauMs(metres: number): number;
|
|
533
|
+
/**
|
|
534
|
+
* §17.11 *Drawing*: a body that moves between the predictor's drawing (the client world's timeline,
|
|
535
|
+
* ahead) and §17.10's (the server's present) — it entered or left the simulated set — starts a
|
|
536
|
+
* correction from where it was last drawn, eased like a replay's (τ by its size, snapped past
|
|
537
|
+
* `snapMetres`), so it never jumps by its velocity times the lead. A new epoch never eases.
|
|
538
|
+
*/
|
|
539
|
+
declare class DrawHandoff {
|
|
540
|
+
private last;
|
|
541
|
+
private offset;
|
|
542
|
+
/** The pose to draw at room-clock `now` (ms) for `pose`, drawn by the predictor or not. */
|
|
543
|
+
draw(pose: BodyPose, predicted: boolean, epoch: number, now: number, snapMetres: number, lengthUnit: number): BodyPose;
|
|
544
|
+
private startFrom;
|
|
545
|
+
private apply;
|
|
546
|
+
}
|
|
547
|
+
/** The distance, metres, past which a body of physics `kind` snaps instead of easing. */
|
|
548
|
+
declare function snapMetresOf(kind: unknown): number;
|
|
549
|
+
|
|
550
|
+
/** A seat's entity as a seat contact rule sees and changes it (room units, per second). */
|
|
551
|
+
interface ContactBody {
|
|
552
|
+
id: string;
|
|
553
|
+
x: number;
|
|
554
|
+
y: number;
|
|
555
|
+
z: number;
|
|
556
|
+
vx: number;
|
|
557
|
+
vy: number;
|
|
558
|
+
vz: number;
|
|
559
|
+
yaw: number;
|
|
560
|
+
spin?: number;
|
|
561
|
+
/** The entity's `flags` (a declared contact policy's pair rules read them as `flag:k` tags). */
|
|
562
|
+
flags?: number;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* A seat contact rule: what the room module does to two seats' entities after every tick's preset
|
|
566
|
+
* steps (a car-to-car bump), as a pure function of the two, `a` the lower id. It changes their fields
|
|
567
|
+
* in place. The module must run this very function on the same pairs.
|
|
568
|
+
*/
|
|
569
|
+
type AuthorityContactRule = (a: ContactBody, b: ContactBody) => void;
|
|
570
|
+
/** The fields of your own entity a seat contact rule may change. */
|
|
571
|
+
declare const CONTACT_FIELDS: readonly ["x", "y", "z", "vx", "vy", "vz", "yaw", "spin"];
|
|
572
|
+
type ContactField = (typeof CONTACT_FIELDS)[number];
|
|
573
|
+
/**
|
|
574
|
+
* One client's seat contacts. A pass is the inputs stepped from one state: `apply` for input `seq`
|
|
575
|
+
* under the state that consumed your inputs through `ack` starts a new pass when `ack` changed or
|
|
576
|
+
* `seq` is not after the last input stepped (a replay), taking the other seats from `others()`.
|
|
577
|
+
*/
|
|
578
|
+
declare class SeatContacts {
|
|
579
|
+
private pass;
|
|
580
|
+
private readonly rule;
|
|
581
|
+
/** The other seats' entities in the latest state. */
|
|
582
|
+
private readonly others;
|
|
583
|
+
constructor(rule: AuthorityContactRule, others: () => readonly ContactBody[]);
|
|
584
|
+
/**
|
|
585
|
+
* After your input `seq` was stepped into `own`: the rule against every other seat, moved on by its
|
|
586
|
+
* velocity to that input's tick (`seq − ack` ticks after the state, `tickHz` a second), in id order,
|
|
587
|
+
* `a` the lower id. A seat the rule changed moves on from there. Your fields it changed are written
|
|
588
|
+
* back as float32 (the entity's wire type).
|
|
589
|
+
*/
|
|
590
|
+
apply(seq: number, ack: number, own: ContactBody, tickHz: number): void;
|
|
591
|
+
/**
|
|
592
|
+
* Another seat `id` where your inputs through `ack + j` meet it (§17.11 *Seat contacts*): the current
|
|
593
|
+
* pass's seat, moved on by its velocity from the input the rule last changed it at, or the latest
|
|
594
|
+
* state's when no pass of that `ack` has run. `j` may be fractional (your drawn car is rendered
|
|
595
|
+
* between two inputs). Undefined for a seat the latest state does not have. (The `predicted` drawing
|
|
596
|
+
* takes other seats from seat-predict.ts' `SeatWorld` instead.)
|
|
597
|
+
*/
|
|
598
|
+
seatAt(id: string, ack: number, j: number, tickHz: number): ContactBody | undefined;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Another seat's drawn pose `seat` moved out of your drawn entity `you` (§17.11 *Drawing other seats*:
|
|
602
|
+
* a draw-only separation, never your entity, never the state): the contact rule run on copies of the
|
|
603
|
+
* two at rest, and the seat moved by its own change less yours, so the whole push is the seat's. A rule
|
|
604
|
+
* that leaves two resting seats as they are (the two do not touch) leaves the seat where it is.
|
|
605
|
+
*/
|
|
606
|
+
declare function separateDrawn(rule: AuthorityContactRule, you: ContactBody, seat: ContactBody): {
|
|
607
|
+
x: number;
|
|
608
|
+
y: number;
|
|
609
|
+
z: number;
|
|
610
|
+
};
|
|
611
|
+
/** A seat drawn against your entity that would go straight across it goes round it instead, at least
|
|
612
|
+
* this fast (radians a second about your entity's centre: half a turn in a third of a second), and as
|
|
613
|
+
* fast as its own pose moves past yours times ROUND_PER_STRAIGHT (half a circle over its diameter: the
|
|
614
|
+
* way round takes as long as the way through). */
|
|
615
|
+
declare const SEAT_ROUND_RATE: number;
|
|
616
|
+
/** Where a seat was drawn against your entity last frame (`separateAround`'s memory, one a seat): its
|
|
617
|
+
* offset from your drawn entity, whether it was drawn off its own pose (`held`: moved out of yours or
|
|
618
|
+
* going round it), its own pose's offset (`bx`, `by`) and the frame's time (ms). */
|
|
619
|
+
type SeatSide = {
|
|
620
|
+
dx: number;
|
|
621
|
+
dy: number;
|
|
622
|
+
dz: number;
|
|
623
|
+
held: boolean;
|
|
624
|
+
bx: number;
|
|
625
|
+
by: number;
|
|
626
|
+
at: number;
|
|
627
|
+
pair?: PairPush;
|
|
628
|
+
};
|
|
629
|
+
/** Two other seats drawn pushed apart (`separateSeats`' memory of a pair that touches, kept with its
|
|
630
|
+
* `SeatSide`): the horizontal side the higher id's seat is pushed to from the lower's (`nx`, `ny`, a
|
|
631
|
+
* unit vector), chosen once when the two first touch and kept until they part, and how much further
|
|
632
|
+
* apart along it the two were drawn last frame than their own poses are (`push`, units). */
|
|
633
|
+
type PairPush = {
|
|
634
|
+
nx: number;
|
|
635
|
+
ny: number;
|
|
636
|
+
push: number;
|
|
637
|
+
};
|
|
638
|
+
/** A seat drawn resting on your entity's roof (or yours on its), its floor a unit or two through it
|
|
639
|
+
* from frame to frame as both drawings move, is lifted off it (or let down off it) by up to this much
|
|
640
|
+
* (units) rather than pushed out across the ground: a push across from a roof is the whole footprint,
|
|
641
|
+
* a pop every frame its floor dips under (the owner's 2026-10-30 report). */
|
|
642
|
+
declare const SEAT_LIFT_MAX = 4;
|
|
643
|
+
/**
|
|
644
|
+
* `seat` lifted off `you` along z (up when its centre is at or above yours, else down) by the least
|
|
645
|
+
* amount up to SEAT_LIFT_MAX that leaves the rule nothing to push, or `seat` itself when it does not
|
|
646
|
+
* touch you or no such lift does (it is beside you, not on you).
|
|
647
|
+
*/
|
|
648
|
+
declare function liftOff(rule: AuthorityContactRule, you: ContactBody, seat: ContactBody): ContactBody;
|
|
649
|
+
/**
|
|
650
|
+
* Another seat's drawn pose `seat` moved out of your drawn entity `you` without ever being drawn across
|
|
651
|
+
* it (§17.11 *Drawing other seats*, draw-only), given where it was drawn last frame (`prev`, undefined
|
|
652
|
+
* for a seat not drawn against yours a frame ago) at `now` (ms). `separateDrawn` pushes the seat out on
|
|
653
|
+
* the side the rule finds nearest; while the seat the render timeline draws passes through yours, that
|
|
654
|
+
* side flips when it passes your entity's middle, and the seat leapt across your car between two frames.
|
|
655
|
+
* So when the straight move from last frame's drawn seat to this frame's separated one goes through your
|
|
656
|
+
* entity:
|
|
657
|
+
* - a seat that was drawn off its own pose (`held`) goes round your entity instead, its heading about
|
|
658
|
+
* your centre turning toward the separated one's along an arc ROUND_PER_STRAIGHT times as long as its
|
|
659
|
+
* own pose moved past yours since last frame, at least at SEAT_ROUND_RATE, its distance and height
|
|
660
|
+
* moving by the same share and never closer than where it stops touching yours;
|
|
661
|
+
* - a seat that was drawn on its own pose (it came over your roof, or from far in one frame) is pushed
|
|
662
|
+
* out on the side it came from instead, when the separated one is on the other side.
|
|
663
|
+
* `blocked` (`separateSeats`: the move would sweep it through another seat drawn last frame) takes the
|
|
664
|
+
* same way as a move through yours. Your entity and the state are never changed. Returns the drawn
|
|
665
|
+
* position and this frame's memory.
|
|
666
|
+
*/
|
|
667
|
+
declare function separateAround(rule: AuthorityContactRule, you: ContactBody, drawnSeat: ContactBody, prev: SeatSide | undefined, now: number, blocked?: boolean): {
|
|
668
|
+
x: number;
|
|
669
|
+
y: number;
|
|
670
|
+
z: number;
|
|
671
|
+
side: SeatSide;
|
|
672
|
+
};
|
|
673
|
+
/** The memory key of two other seats' pair in `separateSeats` (where the higher id's seat was drawn
|
|
674
|
+
* from the lower's). */
|
|
675
|
+
declare const seatPairKey: (a: string, b: string) => string;
|
|
676
|
+
type Point = {
|
|
677
|
+
x: number;
|
|
678
|
+
y: number;
|
|
679
|
+
z: number;
|
|
680
|
+
};
|
|
681
|
+
/** Two other seats drawn pushed apart ease back toward their own poses at most this fast once less
|
|
682
|
+
* push keeps them apart (units a second of the pair's push, half each: 6 units a car in a 60 Hz frame).
|
|
683
|
+
* Pushed on whichever side the rule found nearest, two seats the prediction draws a few units from one
|
|
684
|
+
* centre were drawn flipping sides every frame, each car 27 u off its pose one way, then the other (the
|
|
685
|
+
* contact fix's round 1, 18 of one rtt-200 run's 30 contact jumps). */
|
|
686
|
+
declare const SEAT_PAIR_EASE = 720;
|
|
687
|
+
/**
|
|
688
|
+
* Every other seat's drawn pose `seats` (the render timeline's) moved out of your drawn entity `you`,
|
|
689
|
+
* never across it, and out of each other, never across each other (§17.11 *Drawing other seats*,
|
|
690
|
+
* draw-only), given last frame's memory `prev` (each seat's `SeatSide` by its id, each pair's by
|
|
691
|
+
* `seatPairKey`) at `now` (ms):
|
|
692
|
+
* 1. each seat moved out of yours by `separateAround`;
|
|
693
|
+
* 2. each pair kept on its sides of each other from last frame (`keepSide`): a seat let go off yours
|
|
694
|
+
* jumped back to its own pose over the car it was pressed against;
|
|
695
|
+
* 3. a pile of up to PILE_PASSES passes, until no two touch: each seat drawn into yours moved back
|
|
696
|
+
* out of it by the rule, unless that move would cross yours from where step 1 drew it (then it is
|
|
697
|
+
* drawn there), then every two seats that touch pushed apart by the rule, half each; the last
|
|
698
|
+
* pass ends with the step out of yours.
|
|
699
|
+
* A seat moved out of yours could otherwise land in a third car (two cars the timeline draws inside
|
|
700
|
+
* yours are both pushed to your side; one taken round your car swept through one against it). Your
|
|
701
|
+
* entity and the state are never changed, and no seat is left inside yours. Returns each seat's drawn
|
|
702
|
+
* position by id and this frame's memory (a seat is `held` when drawn off its own pose).
|
|
703
|
+
*/
|
|
704
|
+
declare function separateSeats(rule: AuthorityContactRule, you: ContactBody, seats: readonly ContactBody[], prev: ReadonlyMap<string, SeatSide>, now: number): {
|
|
705
|
+
drawn: Map<string, Point>;
|
|
706
|
+
sides: Map<string, SeatSide>;
|
|
707
|
+
};
|
|
708
|
+
/**
|
|
709
|
+
* A seat rule (§17.11 *Seat rules*): what the room module does to a seat's own entity at a tick it
|
|
710
|
+
* announced in advance (a kickoff that releases held cars on tick `go`), as a function of the entity's
|
|
711
|
+
* fields and the tick that seat's input is applied on. It changes the fields in place, before that
|
|
712
|
+
* input's step. The client runs it on your own entity before each predicted input, with that input's
|
|
713
|
+
* sequence `seq` (so a rule can key what it predicts to one of your inputs: an input fired at `s` was
|
|
714
|
+
* applied on `tick − (seq − s)`), and, in an `inputDecay` room, on each other seat's body before each
|
|
715
|
+
* of its steps (no `seq`).
|
|
716
|
+
*/
|
|
717
|
+
type AuthoritySeatRule = (seat: Record<string, number>, tick: number, seq?: number) => void;
|
|
718
|
+
/** The tick your input `seq` is applied on, predicted from a state of tick `stateTick` that consumed
|
|
719
|
+
* your inputs through `ack`: a predicting room feeds one input a tick (§17.11 *Input pacing*). */
|
|
720
|
+
declare const seatRuleTick: (stateTick: number, ack: number, seq: number) => number;
|
|
721
|
+
|
|
722
|
+
type PredictResult<T extends object = Record<never, never>> = ({
|
|
723
|
+
ok: true;
|
|
724
|
+
} & T) | {
|
|
725
|
+
ok: false;
|
|
726
|
+
code: string;
|
|
727
|
+
detail?: string;
|
|
728
|
+
};
|
|
729
|
+
type V3 = [number, number, number];
|
|
730
|
+
type Q4 = [number, number, number, number];
|
|
731
|
+
/** One world of the game's core. */
|
|
732
|
+
interface PredictWorld {
|
|
733
|
+
readonly tick: number;
|
|
734
|
+
addStaticWorld(world: {
|
|
735
|
+
boxes: number[][];
|
|
736
|
+
ramps: number[][];
|
|
737
|
+
}): PredictResult;
|
|
738
|
+
spawn(desc: unknown): PredictResult;
|
|
739
|
+
remove(key: string): PredictResult;
|
|
740
|
+
addJoint(desc: unknown): PredictResult;
|
|
741
|
+
removeJoint(key: string): PredictResult;
|
|
742
|
+
setMotor(key: string, motor: unknown): PredictResult;
|
|
743
|
+
setVelocity(key: string, linvel?: V3, angvel?: V3): PredictResult;
|
|
744
|
+
setNextKinematicPose(key: string, pose: {
|
|
745
|
+
p: V3;
|
|
746
|
+
q: Q4;
|
|
747
|
+
}): PredictResult;
|
|
748
|
+
importWire(keys: string[], rows: Float32Array | number[]): PredictResult;
|
|
749
|
+
canonicalize(options?: {
|
|
750
|
+
quantize?: boolean;
|
|
751
|
+
}): PredictResult;
|
|
752
|
+
step(): PredictResult<{
|
|
753
|
+
escaped: string[];
|
|
754
|
+
}>;
|
|
755
|
+
exportChanged(sinceTick: number, options?: {
|
|
756
|
+
rest?: boolean;
|
|
757
|
+
}): {
|
|
758
|
+
keys: string[];
|
|
759
|
+
data: Float32Array;
|
|
760
|
+
};
|
|
761
|
+
exportBodyState(key: string, options?: {
|
|
762
|
+
rest?: boolean;
|
|
763
|
+
}): WireBodyState | null;
|
|
764
|
+
stateHash(): string;
|
|
765
|
+
physicsHash(): string;
|
|
766
|
+
free(): void;
|
|
767
|
+
}
|
|
768
|
+
/** The game's loaded core: `@genex-ai/physics` after `init()`. */
|
|
769
|
+
interface PredictCore {
|
|
770
|
+
buildId(): string;
|
|
771
|
+
World: {
|
|
772
|
+
create(desc: unknown): PredictResult<{
|
|
773
|
+
world: PredictWorld;
|
|
774
|
+
}>;
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
/** A module body in the client's view at the keyframe. */
|
|
778
|
+
interface KeyframeBody {
|
|
779
|
+
key: string;
|
|
780
|
+
/** The canonical descriptor with its shapes inlined (C§20.5), or null: drawn, never predicted. */
|
|
781
|
+
desc: Record<string, unknown> | null;
|
|
782
|
+
/** The wire row (15 numbers, `importWire`'s form). */
|
|
783
|
+
row: ArrayLike<number>;
|
|
784
|
+
/** Its entity's epoch: a body the module respawned (a bump) is a deliberate discontinuity, never a
|
|
785
|
+
* sample of the canary. */
|
|
786
|
+
epoch?: number;
|
|
787
|
+
}
|
|
788
|
+
/** A body the client knows but that is out of its view: where it last was (for islands only). */
|
|
789
|
+
interface KeyframeOutside {
|
|
790
|
+
key: string;
|
|
791
|
+
x: number;
|
|
792
|
+
y: number;
|
|
793
|
+
z: number;
|
|
794
|
+
radius: number;
|
|
795
|
+
}
|
|
796
|
+
/** A seat's own entity (its preset body's pose, §17.10 *Preset bodies*). */
|
|
797
|
+
interface KeyframeSeat {
|
|
798
|
+
/** The entity id: the preset body's key. */
|
|
799
|
+
key: string;
|
|
800
|
+
/** The entity's float32 position, and velocity in room units per second. */
|
|
801
|
+
x: number;
|
|
802
|
+
y: number;
|
|
803
|
+
z: number;
|
|
804
|
+
vx: number;
|
|
805
|
+
vy: number;
|
|
806
|
+
vz: number;
|
|
807
|
+
epoch: number;
|
|
808
|
+
/** This client's own entity. */
|
|
809
|
+
own: boolean;
|
|
810
|
+
/** The seat's last applied input at the keyframe (`inputDecay` rooms; absent: extrapolated). */
|
|
811
|
+
input?: RemoteInput;
|
|
812
|
+
/** The entity's fields a {@link RemoteStep} reads (its x, y, z at least); absent: x, y, z. */
|
|
813
|
+
body?: Record<string, number>;
|
|
814
|
+
}
|
|
815
|
+
/** `inputDecay`: one fixed step of a remote seat's entity under `input` (the room preset's own step,
|
|
816
|
+
* or a game's), mutating `body`; the predictor reads its x, y and z. */
|
|
817
|
+
/** A remote seat's step under its held or decayed input, in the tick `tick` it runs in (a lift's carry
|
|
818
|
+
* reads it: §17.11 *Lifts*). */
|
|
819
|
+
type RemoteStep = (body: Record<string, number>, input: RemoteInput, dt: number, tick: number) => void;
|
|
820
|
+
/** A room's declared lifts as a client world poses them (§17.11 *Lifts* step 9): the policy and the
|
|
821
|
+
* called lifts' starts as the latest state has them. */
|
|
822
|
+
interface PredictLifts {
|
|
823
|
+
readonly policy: LiftsPolicy;
|
|
824
|
+
readonly starts: ReadonlyMap<string, number> | undefined;
|
|
825
|
+
}
|
|
826
|
+
/** A joint (§17.11 *State*), its descriptor and the motor last set, parsed. */
|
|
827
|
+
interface KeyframeJoint {
|
|
828
|
+
key: string;
|
|
829
|
+
desc: Record<string, unknown>;
|
|
830
|
+
motor: Record<string, unknown> | null;
|
|
831
|
+
}
|
|
832
|
+
/** One keyframe: the room state after tick `tick`, and how many of this client's inputs the server had
|
|
833
|
+
* consumed by then. */
|
|
834
|
+
interface PredictKeyframe {
|
|
835
|
+
tick: number;
|
|
836
|
+
ack: number;
|
|
837
|
+
bodies: readonly KeyframeBody[];
|
|
838
|
+
outside: readonly KeyframeOutside[];
|
|
839
|
+
joints: readonly KeyframeJoint[];
|
|
840
|
+
seats: readonly KeyframeSeat[];
|
|
841
|
+
}
|
|
842
|
+
/** Your predicted entity's position after input `seq` (room units), or undefined when unknown. */
|
|
843
|
+
type OwnPoseOf = (seq: number) => DrawVec3 | undefined;
|
|
844
|
+
/** A seat's entity at one predicted tick, as a body rule reads it: position (room units) and velocity
|
|
845
|
+
* (room units per second). */
|
|
846
|
+
interface RuleSeat {
|
|
847
|
+
key: string;
|
|
848
|
+
x: number;
|
|
849
|
+
y: number;
|
|
850
|
+
z: number;
|
|
851
|
+
vx: number;
|
|
852
|
+
vy: number;
|
|
853
|
+
vz: number;
|
|
854
|
+
/** The heading, radians, where the seat's body carries one (the contact pass reads it). */
|
|
855
|
+
yaw?: number;
|
|
856
|
+
}
|
|
857
|
+
/** What a body rule reads at a predicted tick: every seat's entity at that tick (key order) and a
|
|
858
|
+
* simulated dynamic body's state after the previous tick's step (room units, per second). */
|
|
859
|
+
interface RuleTick {
|
|
860
|
+
tick: number;
|
|
861
|
+
seats: readonly RuleSeat[];
|
|
862
|
+
body(key: string): {
|
|
863
|
+
p: DrawVec3;
|
|
864
|
+
v: DrawVec3;
|
|
865
|
+
} | null;
|
|
866
|
+
}
|
|
867
|
+
/** A velocity a body rule sets (room units per second), as the module's `setVelocity` would. */
|
|
868
|
+
interface RuleVelocity {
|
|
869
|
+
key: string;
|
|
870
|
+
v: DrawVec3;
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* A body rule (§17.11 *Body rules*): what the room module does each tick to its dynamic bodies'
|
|
874
|
+
* velocities from the seats' entities and the bodies' states (a scripted hit on a ball), as a pure
|
|
875
|
+
* function. The module runs this very function in its `step` and sends what it returns as
|
|
876
|
+
* `setVelocity` commands; the client world runs it before every predicted step.
|
|
877
|
+
*/
|
|
878
|
+
type PredictBodyRule = (tick: RuleTick) => readonly RuleVelocity[];
|
|
879
|
+
/**
|
|
880
|
+
* A kinematic rule (§17.11 *Kinematic rules*): where the room module poses one of its kinematic bodies
|
|
881
|
+
* (a door, a platform, a moving floor) at tick `tick`, as a pure function of the body's key and the tick
|
|
882
|
+
* (its keyframed schedule), or null for a body it does not pose. The module issues
|
|
883
|
+
* `setNextKinematicPose(key, rule(key, t + 1))` in its step of tick t; the client world does the same
|
|
884
|
+
* before every predicted step and draws the body as a predicted one.
|
|
885
|
+
*/
|
|
886
|
+
type PredictKinematicRule = (key: string, tick: number) => {
|
|
887
|
+
p: DrawVec3;
|
|
888
|
+
q: DrawQuat;
|
|
889
|
+
} | null;
|
|
890
|
+
/** §17.11 *Kinematic rules*: where `rule` poses `key` at room-clock instant `at` on the server's own
|
|
891
|
+
* timeline (its pose for tick T stands at `tickOrigin + T / tickHz`), between the two ticks around `at`;
|
|
892
|
+
* null when the rule does not pose `key`. What a client draws for a ruled body whenever the predictor
|
|
893
|
+
* does not draw it (no core, `cpu`, any fallback level), in place of §17.10's extrapolation. */
|
|
894
|
+
declare function ruledPoseAt(rule: PredictKinematicRule, key: string, at: number, clock: {
|
|
895
|
+
tickHz: number;
|
|
896
|
+
tickOrigin: number;
|
|
897
|
+
}): BodyPose | null;
|
|
898
|
+
/** A ruled body outside the simulated set follows the world's timeline at a rate within this share of
|
|
899
|
+
* the room clock's (§17.11 *Kinematic rules*): a 3-tick shift is absorbed in 30 ticks. */
|
|
900
|
+
declare const RULED_SLEW = 0.1;
|
|
901
|
+
/** Past this many ticks off the world's timeline the ruled clock snaps to it. */
|
|
902
|
+
declare const RULED_SNAP_TICKS = 30;
|
|
903
|
+
/** A replay's budget, ms, desktop and mobile: what the rolling window of replay costs is judged
|
|
904
|
+
* against (§17.11 *Budgets*). */
|
|
905
|
+
declare const PHYS_RESIM_BUDGET_MS: {
|
|
906
|
+
readonly desktop: 4;
|
|
907
|
+
readonly mobile: 5;
|
|
908
|
+
};
|
|
909
|
+
/** The replay budget in use: `override` (the connect option `physicsBudgetMs`) when it is a finite
|
|
910
|
+
* number over 0, else the device's `deviceMs`. Anything else is ignored, never thrown: a bench or CI
|
|
911
|
+
* holds every engine to one budget this way; a game leaves it unset. */
|
|
912
|
+
declare function physicsBudgetMs(override: unknown, deviceMs: number): number;
|
|
913
|
+
/** The simulated set's sizes: the next one that chooses fewer bodies is taken when replays run over
|
|
914
|
+
* budget; with none left, `cpu`. */
|
|
915
|
+
declare const PHYS_PREDICT_SET_SIZES: readonly number[];
|
|
916
|
+
/** The rolling window of replay costs (wall clock around the rebuild and replay only): the latest
|
|
917
|
+
* this many replays, judged once it holds PHYS_BUDGET_MIN_SAMPLES. */
|
|
918
|
+
declare const PHYS_BUDGET_WINDOW = 60;
|
|
919
|
+
declare const PHYS_BUDGET_MIN_SAMPLES = 20;
|
|
920
|
+
/** Over budget: the window's median over the budget, or its p90 over this many budgets. A single
|
|
921
|
+
* replay (a GC pause, the OS taking the thread) never decides. */
|
|
922
|
+
declare const PHYS_BUDGET_P90_FACTOR = 2;
|
|
923
|
+
/** Calm: the window's p90 (or a probe) at or under this share of the budget. A smaller set grows back
|
|
924
|
+
* one size after a full calm window; `cpu` turns on again after PHYS_CPU_CALM_PROBES calm probes. */
|
|
925
|
+
declare const PHYS_BUDGET_CALM_SHARE = 0.5;
|
|
926
|
+
/** In `cpu`, one keyframe in this many ms is adopted by a full replay (a probe, never drawn). */
|
|
927
|
+
declare const PHYS_CPU_PROBE_MS = 500;
|
|
928
|
+
/** Calm probes in a row that turn prediction on again. */
|
|
929
|
+
declare const PHYS_CPU_CALM_PROBES = 4;
|
|
930
|
+
/** The set size to shrink to from `current` when the last choice took `chosen` bodies: the next size
|
|
931
|
+
* under `chosen` (a size at or over it would choose the same bodies), or null when none is left. */
|
|
932
|
+
declare function nextPredictSetSize(current: number, chosen: number): number | null;
|
|
933
|
+
/** The runtime canary: over this many pure body-keyframes, more than this share mismatched is `diverged`. */
|
|
934
|
+
declare const PHYS_CANARY_WINDOW = 500;
|
|
935
|
+
declare const PHYS_CANARY_MAX_MISMATCH = 0.02;
|
|
936
|
+
/** The canary judges no window smaller than this. */
|
|
937
|
+
declare const PHYS_CANARY_MIN_SAMPLES = 200;
|
|
938
|
+
/** Why bodies are (not) predicted. */
|
|
939
|
+
declare const PredictStatus: {
|
|
940
|
+
/** Predicting. */
|
|
941
|
+
readonly ON: "on";
|
|
942
|
+
/** Turned off: by the client (`predictPhysics: false`), the room or the operator. */
|
|
943
|
+
readonly OFF: "off";
|
|
944
|
+
/** Waiting for the core or the first keyframe. */
|
|
945
|
+
readonly LOADING: "loading";
|
|
946
|
+
/** No core was handed over, or it failed to load. */
|
|
947
|
+
readonly UNAVAILABLE: "unavailable";
|
|
948
|
+
/** Level 1: the room's physicsHash or world description is not this client's. */
|
|
949
|
+
readonly MISMATCH: "mismatch";
|
|
950
|
+
/** Level 2: the core failed its self-test scene at load. */
|
|
951
|
+
readonly SELF_TEST: "self_test";
|
|
952
|
+
/** Level 3: the runtime canary saw more than 2% of pure bodies mismatch. */
|
|
953
|
+
readonly DIVERGED: "diverged";
|
|
954
|
+
/** Replays run over budget at the smallest set that helps: drawn §17.10's way, probing every
|
|
955
|
+
* PHYS_CPU_PROBE_MS until calm, then on again. */
|
|
956
|
+
readonly CPU: "cpu";
|
|
957
|
+
};
|
|
958
|
+
type PredictStatus = (typeof PredictStatus)[keyof typeof PredictStatus];
|
|
959
|
+
interface PredictorOptions {
|
|
960
|
+
/** The room's physDesc. */
|
|
961
|
+
desc: PhysDesc;
|
|
962
|
+
/** The static world (§17.7's `{ boxes, ramps }`); none is the empty world. */
|
|
963
|
+
staticWorld?: {
|
|
964
|
+
boxes: number[][];
|
|
965
|
+
ramps: number[][];
|
|
966
|
+
} | null;
|
|
967
|
+
/** The room's physicsHash: the client world must have it. */
|
|
968
|
+
physicsHash: string;
|
|
969
|
+
/** The room's tick rate. */
|
|
970
|
+
tickHz: number;
|
|
971
|
+
/** A replay's budget, ms (default the desktop one). */
|
|
972
|
+
budgetMs?: number;
|
|
973
|
+
/** The clock replays are timed on, ms (default `performance.now`). */
|
|
974
|
+
clock?: () => number;
|
|
975
|
+
/** How a remote seat steps under its decayed input (`physDesc.remotePredict` `inputDecay`); without
|
|
976
|
+
* one every remote seat is extrapolated. */
|
|
977
|
+
remoteStep?: RemoteStep;
|
|
978
|
+
/** The lead cap, ms (default `physDesc.leadMs`). */
|
|
979
|
+
leadMs?: number;
|
|
980
|
+
/** The room module's seat rule (§17.11 *Seat rules*), run on each other seat's body before each of
|
|
981
|
+
* its `inputDecay` steps (the step's tick: the keyframe's plus j). */
|
|
982
|
+
seatRule?: AuthoritySeatRule;
|
|
983
|
+
/** The room module's body rule (§17.11 *Body rules*); none: module commands arrive as corrections. */
|
|
984
|
+
bodyRule?: PredictBodyRule;
|
|
985
|
+
/** The room's declared `propSlide` under `headFriction: slide` (§17.11 *Contact policy*), else null:
|
|
986
|
+
* preset hulls are then frictionless and the built-in prop rule runs after the module's. */
|
|
987
|
+
headSlide?: () => PropSlide | null;
|
|
988
|
+
/** The room module's kinematic rule (§17.11 *Kinematic rules*); none: every module kinematic body
|
|
989
|
+
* holds the keyframe's pose and is drawn from the server's states. */
|
|
990
|
+
kinematicRule?: PredictKinematicRule;
|
|
991
|
+
/** The room's declared lifts (§17.11 *Lifts* step 9), else null: each a kinematic body `lift.<id>`
|
|
992
|
+
* the client world poses at P(t + 1) in each predicted tick t (at P(keyframe + 1) on a rebuild), and
|
|
993
|
+
* the built-in conveyor rule after the module's body rule. */
|
|
994
|
+
lifts?: () => PredictLifts | null;
|
|
995
|
+
/** Another seat's entity after the tick of your input `seq`, as the session's seat prediction has it
|
|
996
|
+
* (§17.11 *Drawing other seats* `predicted`: stepped under its held input with the room's contact
|
|
997
|
+
* pass); when it answers, it poses that seat's preset body, else the seat is moved as
|
|
998
|
+
* `remotePredict` says. */
|
|
999
|
+
seatPose?: (key: string, seq: number) => RuleSeat | undefined;
|
|
1000
|
+
/** The room's seat contact pass (§17.11 *Contact policy*, the declared one or the module's), run on
|
|
1001
|
+
* each predicted tick's seats in id order before they pose their preset bodies, on ticks where the
|
|
1002
|
+
* session's seat prediction posed none of them (that prediction runs the pass itself). */
|
|
1003
|
+
contactPass?: (seats: ContactBody[]) => void;
|
|
1004
|
+
/** How many of the latest per-tick stateHashes `hashes` keeps (default {@link PHYS_PREDICT_HASHES_KEPT};
|
|
1005
|
+
* a conformance run keeps all). */
|
|
1006
|
+
hashesKept?: number;
|
|
1007
|
+
}
|
|
1008
|
+
/** The per-tick client stateHashes a predictor keeps by default (diagnostics only). */
|
|
1009
|
+
declare const PHYS_PREDICT_HASHES_KEPT = 600;
|
|
1010
|
+
/** What one keyframe's adoption did. */
|
|
1011
|
+
interface AdoptReport {
|
|
1012
|
+
/** `match`: skip-on-match; `replay`: imported and replayed; `none`: not predicting. */
|
|
1013
|
+
kind: 'match' | 'replay' | 'none';
|
|
1014
|
+
/** Inputs replayed. */
|
|
1015
|
+
replayed: number;
|
|
1016
|
+
/** Replay time, ms. */
|
|
1017
|
+
ms: number;
|
|
1018
|
+
/** Pure bodies compared and mismatched (the canary's sample). */
|
|
1019
|
+
pure: number;
|
|
1020
|
+
mismatched: number;
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* One room's predictor. `adopt` each keyframe, `advance` once per input you send (with your predicted
|
|
1024
|
+
* pose after it), and `draw` a body at render time; `stateHash` reads the client world.
|
|
1025
|
+
*/
|
|
1026
|
+
declare class PhysicsPredictor {
|
|
1027
|
+
status: PredictStatus;
|
|
1028
|
+
private readonly core;
|
|
1029
|
+
private readonly desc;
|
|
1030
|
+
private readonly tickHz;
|
|
1031
|
+
private readonly innerDt;
|
|
1032
|
+
private readonly lengthUnit;
|
|
1033
|
+
private readonly leadMax;
|
|
1034
|
+
private readonly budgetMs;
|
|
1035
|
+
private readonly clock;
|
|
1036
|
+
private readonly remoteStep;
|
|
1037
|
+
private readonly hashesKept;
|
|
1038
|
+
private world;
|
|
1039
|
+
/** The keyframe the world was last rebuilt from or matched: its tick and ack. */
|
|
1040
|
+
private base;
|
|
1041
|
+
/** The last input stepped (the world is at base.tick + (seq − base.ack)). */
|
|
1042
|
+
private seq;
|
|
1043
|
+
/** Simulated module bodies: key → its type, and the descriptors they were spawned from. */
|
|
1044
|
+
private simulated;
|
|
1045
|
+
/** Seats' preset bodies: key → their keyframe pose and velocity (remotes are extrapolated). */
|
|
1046
|
+
private seats;
|
|
1047
|
+
/** Module kinematic bodies' keyframe rows, extrapolated each tick. */
|
|
1048
|
+
private kinematic;
|
|
1049
|
+
private joints;
|
|
1050
|
+
/** Wire rows the world predicted at each keyframe tick it stepped through. */
|
|
1051
|
+
private ring;
|
|
1052
|
+
/** Bodies in islands with nothing but module dynamic bodies (the canary's sample). */
|
|
1053
|
+
private pure;
|
|
1054
|
+
private drawn;
|
|
1055
|
+
/** Simulated bodies' physics kinds (their snap distance). */
|
|
1056
|
+
private kinds;
|
|
1057
|
+
/** The fractional tick ruled bodies outside the simulated set are drawn at (§17.11 *Kinematic rules*):
|
|
1058
|
+
* the world's timeline, slewed so a replay that moves it never jumps or reverses them. */
|
|
1059
|
+
private ruledClock;
|
|
1060
|
+
private ownPose;
|
|
1061
|
+
private ownVelocity;
|
|
1062
|
+
private readonly bodyRule;
|
|
1063
|
+
private readonly headSlide;
|
|
1064
|
+
/** The prop rule's view of the dynamic bodies after the last step (the clamp's export, its clamped
|
|
1065
|
+
* velocities), as the host keeps it; null after a rebuild until read whole once. */
|
|
1066
|
+
private propStates;
|
|
1067
|
+
/** Whether a keyframe's canonicalize quantized the velocities since `propStates` was read (its places
|
|
1068
|
+
* are float32 on the wire, so they stand): the bodies a rule's place test picks are read again. */
|
|
1069
|
+
private propStale;
|
|
1070
|
+
private readonly kinematicRule;
|
|
1071
|
+
private readonly lifts;
|
|
1072
|
+
/** The lift bodies this world holds, by key, and the policy they were spawned from. */
|
|
1073
|
+
private liftBodies;
|
|
1074
|
+
private readonly seatRule;
|
|
1075
|
+
private readonly seatPose;
|
|
1076
|
+
private readonly contactPass;
|
|
1077
|
+
/** Whether the seat `seatAt` last gave came from the session's seat prediction. */
|
|
1078
|
+
private posedBySeats;
|
|
1079
|
+
/** `inputDecay`: each remote seat's body as last stepped, `j` ticks from the keyframe seat `from`. */
|
|
1080
|
+
private remoteBodies;
|
|
1081
|
+
private setSize;
|
|
1082
|
+
/** The latest replay costs, ms (the budget's rolling window). */
|
|
1083
|
+
private costs;
|
|
1084
|
+
/** In `cpu`: when the last probe ran (the clock `adopt` is given), and calm probes in a row. */
|
|
1085
|
+
private probedAt;
|
|
1086
|
+
private calmProbes;
|
|
1087
|
+
/** How many bodies the last choice took. */
|
|
1088
|
+
private chosenCount;
|
|
1089
|
+
/** How many times the budget turned prediction off, and on again. */
|
|
1090
|
+
fallbacks: number;
|
|
1091
|
+
recoveries: number;
|
|
1092
|
+
/** When the world last stepped (the clock `adopt`, `advance` and `draw` are given), ms. */
|
|
1093
|
+
private steppedAt;
|
|
1094
|
+
private canary;
|
|
1095
|
+
/** Each body's epoch at the last keyframe (the canary skips a body whose epoch moved). */
|
|
1096
|
+
private epochs;
|
|
1097
|
+
/** The client stateHash after each predicted tick, newest last (the conformance runner reads it). */
|
|
1098
|
+
readonly hashes: {
|
|
1099
|
+
tick: number;
|
|
1100
|
+
hash: string;
|
|
1101
|
+
}[];
|
|
1102
|
+
constructor(core: PredictCore, options: PredictorOptions);
|
|
1103
|
+
/** Whether bodies are predicted now (else the session draws them §17.10's way). */
|
|
1104
|
+
get predicting(): boolean;
|
|
1105
|
+
/** Whether the predictor stopped for good (its world freed): every status but `on`, `loading` and
|
|
1106
|
+
* `cpu`, which probes its way back. */
|
|
1107
|
+
get stopped(): boolean;
|
|
1108
|
+
/** Whether `key` is a body this predictor draws. */
|
|
1109
|
+
draws(key: string): boolean;
|
|
1110
|
+
/** A body the room's kinematic rule poses that the world does not simulate (out of view, or its
|
|
1111
|
+
* island not chosen): drawn by the rule on the world's timeline all the same (§17.11 *Kinematic
|
|
1112
|
+
* rules*), so it never jumps between the client's timeline and the server's present. */
|
|
1113
|
+
private ruledElsewhere;
|
|
1114
|
+
/** The client world's stateHash (C§10.1), '' without a world. */
|
|
1115
|
+
stateHash(): string;
|
|
1116
|
+
/** Stops predicting for good (a fallback, or the session ended). */
|
|
1117
|
+
stop(status: PredictStatus): void;
|
|
1118
|
+
/**
|
|
1119
|
+
* Adopts a keyframe. `sent` is your last input's sequence; `ownPose` your predicted position after
|
|
1120
|
+
* each of them, `ownVelocity` your predicted velocity (room units per second; a body rule reads it,
|
|
1121
|
+
* absent: your entity's keyframe velocity). Returns what it did.
|
|
1122
|
+
*/
|
|
1123
|
+
adopt(kf: PredictKeyframe, sent: number, ownPose: OwnPoseOf, now: number, ownVelocity?: OwnPoseOf): AdoptReport;
|
|
1124
|
+
/** One predicted tick for input `seq`, sent at `now` (call it after sending that input): nothing
|
|
1125
|
+
* past the lead cap or before the first keyframe. */
|
|
1126
|
+
advance(seq: number, now: number): void;
|
|
1127
|
+
/** Where a predicted body is drawn at `now` (the clock `adopt` and `advance` were given): its present
|
|
1128
|
+
* pose moved on by its velocities for the time since the world last stepped (at most one tick, none
|
|
1129
|
+
* while it sleeps), plus the decaying correction. */
|
|
1130
|
+
draw(key: string, now: number): BodyPose | null;
|
|
1131
|
+
/** The bodies this client simulates: whole proximity islands of bodies in view with a descriptor,
|
|
1132
|
+
* none of whose members is out of view, nearest your own entity first, up to the set size. */
|
|
1133
|
+
private choose;
|
|
1134
|
+
/** Skip-on-match: the keyframe is exactly what the world predicted for its tick. */
|
|
1135
|
+
private compare;
|
|
1136
|
+
private sameJoints;
|
|
1137
|
+
/** Every seat's preset body is where the world had it at the keyframe tick. */
|
|
1138
|
+
private sameSeats;
|
|
1139
|
+
private noteCanary;
|
|
1140
|
+
/** §17.11 *Budgets*: the replay's cost joins the rolling window; once it holds enough, a window
|
|
1141
|
+
* over budget shrinks the set to the next size that chooses fewer bodies, or falls back to `cpu`,
|
|
1142
|
+
* and a full calm window grows a shrunken set back one size. */
|
|
1143
|
+
private judgeBudget;
|
|
1144
|
+
/** `cpu`: bodies are drawn §17.10's way; the world stays for the probes. */
|
|
1145
|
+
private fallBack;
|
|
1146
|
+
/** A probe's cost: PHYS_CPU_CALM_PROBES calm ones in a row turn prediction on again. */
|
|
1147
|
+
private judgeProbe;
|
|
1148
|
+
private jointsOf;
|
|
1149
|
+
/** The bodies the last `choose` picked. */
|
|
1150
|
+
private chosenKeys;
|
|
1151
|
+
private chosenHas;
|
|
1152
|
+
/** The seats whose preset bodies the room has: inside the world (§17.10 *Preset bodies*). */
|
|
1153
|
+
private seatsOf;
|
|
1154
|
+
/** A preset body's centre for an entity at float32 (x, y, z): half its height up, as float32. */
|
|
1155
|
+
private presetPosition;
|
|
1156
|
+
/** The world brought to the keyframe: bodies, joints and seats spawned or removed to match, every
|
|
1157
|
+
* state imported, then canonicalized. False when the core refused what the server accepted. */
|
|
1158
|
+
private rebuild;
|
|
1159
|
+
/** The room's lift bodies brought to the keyframe (§17.11 *Lifts* step 9): spawned once (again when
|
|
1160
|
+
* the policy changes), each with its wire row at P(tick + 1), still; null when the core refused one. */
|
|
1161
|
+
private rebuildLifts;
|
|
1162
|
+
private rebuildSeats;
|
|
1163
|
+
private stepOnce;
|
|
1164
|
+
/** A seat's entity `j` ticks after the keyframe: yours from your prediction; a remote one from the
|
|
1165
|
+
* session's seat prediction when it has it, else by its last input held (`hold`) or repeated and
|
|
1166
|
+
* decayed (`inputDecay`), else extrapolated by its velocity. */
|
|
1167
|
+
private seatAt;
|
|
1168
|
+
/** The room's contact pass on this tick's seats (copies, ids ascending), their poses and velocities
|
|
1169
|
+
* taken from what it left (§17.11 *Contact policy*: the replay runs the server's pass). */
|
|
1170
|
+
private passSeats;
|
|
1171
|
+
/** §17.11 *Body rules*: the room's rule on this tick's seats and the bodies as the last step left
|
|
1172
|
+
* them, its velocities set on the simulated dynamic bodies it names, in its order, before the step. */
|
|
1173
|
+
private applyBodyRule;
|
|
1174
|
+
/** After a keyframe's canonicalize: the bodies the built-in rules pick by place (over a seat's top,
|
|
1175
|
+
* over a conveyor) read again, so their quantized velocities are the host's; the rest keep theirs
|
|
1176
|
+
* until the step's export (a 128-body read every keyframe was a third of a replay's cost). */
|
|
1177
|
+
private freshenPicked;
|
|
1178
|
+
/** The speed clamp, on the simulated dynamic bodies, in key order (the export's). */
|
|
1179
|
+
private clamp;
|
|
1180
|
+
/** The wire rows of every simulated body and seat after a keyframe tick's canonicalize (seats under
|
|
1181
|
+
* `seat:<key>`), each read on its own: an export lists no body asleep since before the tick. */
|
|
1182
|
+
private rowsNow;
|
|
1183
|
+
/** A ruled body outside the world as drawn at `now`: the rule's pose at the ruled clock's tick. */
|
|
1184
|
+
private ruledDrawn;
|
|
1185
|
+
/** The ruled clock at `now`: it runs with the room clock and slews toward the world's timeline (the
|
|
1186
|
+
* last stepped tick plus one, toward the next by the time since that step, at most one tick) by
|
|
1187
|
+
* at most RULED_SLEW of the time passed, so a replay that moves the timeline (the server ran a tick
|
|
1188
|
+
* without your input, or took two in one) is absorbed without a jump or a reversal; past
|
|
1189
|
+
* RULED_SNAP_TICKS it snaps. */
|
|
1190
|
+
private ruledTick;
|
|
1191
|
+
/** Whether the room's kinematic rule poses module kinematic body `key` (at the world's tick). */
|
|
1192
|
+
private ruled;
|
|
1193
|
+
/** Keeps only the ring's keyframes after `tick`. */
|
|
1194
|
+
private prune;
|
|
1195
|
+
/** The simulated bodies' present states, from the bodies changed after `since`. */
|
|
1196
|
+
private readDrawn;
|
|
1197
|
+
/** Each predicted body's present pose with its correction at `now` (no extrapolation): where a
|
|
1198
|
+
* replay's correction starts from. The decay is memoryless, so a replay that changes nothing leaves
|
|
1199
|
+
* the drawing as it was. */
|
|
1200
|
+
/** Every simulated body's present state, each read on its own (after a rebuild). */
|
|
1201
|
+
/** Whether a built-in body rule runs (the prop rule under `headFriction: slide`, the conveyor rule). */
|
|
1202
|
+
private builtInRules;
|
|
1203
|
+
private readAll;
|
|
1204
|
+
private snapshotDrawn;
|
|
1205
|
+
/** A body's snap distance, room units, by its physics kind (§17.11 *Drawing*). */
|
|
1206
|
+
private snapOf;
|
|
1207
|
+
/** After a replay: each body that moved starts a correction from where it was drawn: `dp = old −
|
|
1208
|
+
* new`, `dq = old ⊗ new⁻¹` the short way, its τ by its size in metres, snapped past its snap
|
|
1209
|
+
* distance (§17.11 *Drawing*); a body in `respawned` (a new life) snaps. The world itself always holds
|
|
1210
|
+
* the exact state. */
|
|
1211
|
+
private ease;
|
|
1212
|
+
}
|
|
1213
|
+
/**
|
|
1214
|
+
* Whether the core keeps the promise prediction rests on, on this device: a world stepped, then
|
|
1215
|
+
* canonicalized with `quantize`, and a second world built from the same descriptors that imports its
|
|
1216
|
+
* wire rows and canonicalizes, step on with equal stateHashes. False also when the core refuses any of it.
|
|
1217
|
+
*/
|
|
1218
|
+
declare function selfTestPredictCore(core: PredictCore): boolean;
|
|
1219
|
+
/** Whether this runtime runs WebAssembly SIMD (every current browser; Safari since 16.4). Where it
|
|
1220
|
+
* does not, load the core with its non-SIMD module (`init({ module })`): the same stateHashes. */
|
|
1221
|
+
declare function wasmSimdSupported(): boolean;
|
|
1222
|
+
|
|
1223
|
+
export { PHYSICS_PREDICT_MAX_RAMPS as $, type AuthorityContactRule as A, BODY_CORRECTION_TAU_MS as B, type ContactBody as C, type DrawClock as D, type KeyframeSeat as E, PHYSICS_BODY_FIELDS as F, PHYSICS_CEILING_FACTOR as G, HOST_BODY_FIELDS as H, ISLAND_MARGIN_METRES as I, PHYSICS_CONTESTED_METRES as J, type KeyframeBody as K, PHYSICS_CONTRACT as L, PHYSICS_DEFAULT_CEILING as M, PHYSICS_DEFAULT_LIMITS as N, type OwnPoseOf as O, type PhysicsCeiling as P, PHYSICS_DEFAULT_PATCH_HZ as Q, type RemoteInput as R, PHYSICS_FULL_RATE_BODIES as S, PHYSICS_KEY_MAX_BYTES as T, PHYSICS_KIND_MAX_BYTES as U, PHYSICS_LIMIT_NAMES as V, PHYSICS_OVERLAP_MAX_KEYS as W, PHYSICS_PATCH_HZ as X, PHYSICS_PREDICT_MAX_ANGULAR as Y, PHYSICS_PREDICT_MAX_BOXES as Z, PHYSICS_PREDICT_MAX_LINEAR as _, type PhysEvRow as a, clampedVelocity as a$, PHYSICS_PREDICT_MIN_ITERATIONS as a0, PHYSICS_PRESET_LENGTH_UNITS as a1, PHYSICS_REAL_LIMITS as a2, PHYSICS_ROTATING_BODIES as a3, PHYSICS_SCALED_LIMITS as a4, PHYSICS_SHAPES_MAX as a5, PHYSICS_SHAPE_MAX_CHARS as a6, PHYSICS_STATIC_PIECE_BYTES as a7, PHYSICS_STATIC_PREFIX as a8, PHYSICS_SUBSTEPS as a9, type PredictKeyframe as aA, type PredictLifts as aB, type PredictResult as aC, PredictSmoothing as aD, type PredictWorld as aE, type PredictorOptions as aF, type PresetBodyShape as aG, type QuantizedRange as aH, RULED_SLEW as aI, RULED_SNAP_TICKS as aJ, type RemoteStep as aK, type RuleSeat as aL, type RuleTick as aM, type RuleVelocity as aN, SEAT_LIFT_MAX as aO, SEAT_PAIR_EASE as aP, SEAT_ROUND_RATE as aQ, SHAPE_REF_KINDS as aR, SeatContacts as aS, type SeatSide as aT, WIRE_REST_MAX as aU, WIRE_ROW_STRIDE as aV, type WireBodyState as aW, type WireFields as aX, bodyRadiusOf as aY, bodyStateOf as aZ, checkResolvedPhysics as a_, PHYS_BUDGET_CALM_SHARE as aa, PHYS_BUDGET_MIN_SAMPLES as ab, PHYS_BUDGET_P90_FACTOR as ac, PHYS_BUDGET_WINDOW as ad, PHYS_CANARY_MAX_MISMATCH as ae, PHYS_CANARY_MIN_SAMPLES as af, PHYS_CANARY_WINDOW as ag, PHYS_CPU_CALM_PROBES as ah, PHYS_CPU_PROBE_MS as ai, PHYS_PREDICT_HASHES_KEPT as aj, PHYS_PREDICT_SET_SIZES as ak, PHYS_RESIM_BUDGET_MS as al, type PairPush as am, type PhysDesc as an, type PhysDescPredict as ao, type PhysEvContactBegin as ap, PhysEvKind as aq, type PhysEvOther as ar, type PhysHitRow as as, type PhysOverlapRow as at, type PhysicsBodyField as au, PhysicsConfigRange as av, PhysicsPredictRange as aw, PhysicsPredictor as ax, type PhysicsResolution as ay, type PhysicsWorldDesc as az, type PhysAnswerRow as b, correctionAt as b0, correctionShare as b1, correctionTauMs as b2, decayedInput as b3, dequantizeBodyValue as b4, drawBody as b5, effectivePatchHz as b6, extrapolateBody as b7, extrapolationSeconds as b8, inlineShapes as b9, seatPairKey as bA, seatRuleTick as bB, selfTestPredictCore as bC, separateAround as bD, separateDrawn as bE, separateSeats as bF, slerpFromIdentity as bG, snapMetresOf as bH, solverIterationsOf as bI, wasmSimdSupported as bJ, wireFieldsOf as bK, wireRowOfExport as bL, wireRowOfState as bM, writeWireRow as bN, innerDtOf as ba, isPhysicsKey as bb, isPhysicsKind as bc, isPhysicsPatchHz as bd, keyframeTicks as be, liftOff as bf, motorText as bg, nextPredictSetSize as bh, parsePhysDesc as bi, physDescText as bj, physicsBudgetMs as bk, physicsCeilingValid as bl, physicsLimitsAt as bm, physicsLimitsForWorld as bn, physicsWorldDesc as bo, physicsWorldPredicts as bp, proximityIslands as bq, quantizeBodyValue as br, quatMul as bs, quatNormalize as bt, receiveBodyState as bu, remoteInputWeight as bv, resolvePhysicsConfig as bw, restStepsOf as bx, ruledPoseAt as by, sameBodyState as bz, type PhysBodyRow as c, PredictStatus as d, type AuthoritySeatRule as e, type PredictCore as f, type PredictBodyRule as g, type PredictKinematicRule as h, type AdoptReport as i, BODY_EXTRAPOLATE_BACK_TICKS as j, BODY_EXTRAPOLATE_MAX_MS as k, BODY_SNAP_METRES as l, type BodyDrawing as m, type BodyFields as n, type BodyPose as o, BodyQuantization as p, BodySnap as q, type BodyState as r, CONTACT_FIELDS as s, type ContactField as t, DrawHandoff as u, type DrawQuat as v, type DrawVec3 as w, type IslandBody as x, type KeyframeJoint as y, type KeyframeOutside as z };
|