@irtio/runtime 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-VMCE3LRO.js → chunk-DBGMG2S3.js} +1 -1
- package/dist/{chunk-K42HA75G.js → chunk-ZCD2TBXB.js} +1253 -26
- package/dist/{contract-BjMsoJIV.d.ts → contract-CRilLVdx.d.ts} +29 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +12 -2
- package/dist/{room-CfnEjlcg.d.ts → room-YJGz6Caw.d.ts} +179 -10
- package/dist/test/index.d.ts +14 -3
- package/dist/test/index.js +11 -3
- package/dist/worker/index.d.ts +9 -1
- package/dist/worker/index.js +14 -3
- package/package.json +5 -4
|
@@ -136,6 +136,10 @@ type HostCall = {
|
|
|
136
136
|
readonly board: string;
|
|
137
137
|
readonly playerId: string;
|
|
138
138
|
readonly score: number;
|
|
139
|
+
/** M6 lane B (D69-c): the cohort of a bucketed board. Absent on every board that declares
|
|
140
|
+
* no buckets, which is every board that existed before M6. There is deliberately no
|
|
141
|
+
* `period` beside it: rotation is control's clock, never the room's. */
|
|
142
|
+
readonly bucket?: string;
|
|
139
143
|
}
|
|
140
144
|
/**
|
|
141
145
|
* D59: `room.bus.send(roomId, payload)` — directed, durable, at-least-once delivery to one room
|
|
@@ -246,6 +250,24 @@ interface RoomHost {
|
|
|
246
250
|
* A host with no room list (the in-process test harness) records it and does nothing else.
|
|
247
251
|
*/
|
|
248
252
|
setBackfill(open: boolean): void;
|
|
253
|
+
/**
|
|
254
|
+
* D75: `room.lobby.setPublic(v)`, and the terminal deregistration a game start performs.
|
|
255
|
+
*
|
|
256
|
+
* Fire-and-forget, and host state rather than room state, for exactly `setBackfill`'s reason:
|
|
257
|
+
* the supervisor holds it, reports it on the room list the agent already polls, and control
|
|
258
|
+
* turns that report into a registry row. None of which the room could arrange for itself and
|
|
259
|
+
* none of which belongs in the hibernation blob.
|
|
260
|
+
*
|
|
261
|
+
* `started` is a one-way door. A room that reports it is deregistered terminally, and no later
|
|
262
|
+
* report — raced, stale or forged — can put it back in front of a stranger.
|
|
263
|
+
*
|
|
264
|
+
* A host with no room list (the in-process test harness) records it and does nothing else.
|
|
265
|
+
*/
|
|
266
|
+
setLobby(update: {
|
|
267
|
+
readonly public?: boolean;
|
|
268
|
+
readonly queue?: string;
|
|
269
|
+
readonly started?: boolean;
|
|
270
|
+
}): void;
|
|
249
271
|
/**
|
|
250
272
|
* D44: `room.spawnNPC(config)`. The host opens a loopback client session under `clientId` and
|
|
251
273
|
* runs the named entry of the room definition's `npcs` map against it. The room minted the id,
|
|
@@ -340,6 +362,13 @@ interface RoomStats {
|
|
|
340
362
|
membershipEnters: number;
|
|
341
363
|
membershipLeaves: number;
|
|
342
364
|
corrections: number;
|
|
365
|
+
/**
|
|
366
|
+
* D70: typed peer messages this room refused to hand to `onMessage` — an index its schema does
|
|
367
|
+
* not have, or a payload the codec would not decode. Every one of them is a peer sending
|
|
368
|
+
* something this room's schema does not describe, so a number climbing here means a client on a
|
|
369
|
+
* stale build or one probing, and never a room bug.
|
|
370
|
+
*/
|
|
371
|
+
messagesDropped: number;
|
|
343
372
|
}
|
|
344
373
|
/** The surface the worker host and the harness drive. Implemented by `RoomCore`. */
|
|
345
374
|
interface RoomCoreApi<S extends AnySchema = AnySchema> {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { D as DEFAULT_TIMELINE_MAX_RECORDS, a as DEFAULT_TIMELINE_MAX_TICKS, E as EVENT_RING_SIZE, H as HOST_CALL_TIMEOUT_MS, b as HostCall, c as HostCallResult, J as JoinOptions, d as JoinResult, L as LogLevel, R as RoomCoreApi, e as RoomCoreOptions, f as RoomEvent, g as RoomEventKind, h as RoomFullError, i as RoomHost, j as RoomInspection, k as RoomStats, T as TimelineDump, l as TimelineFrame, m as TimelineRecorder, n as TimelineRecorderOptions, o as inspectState } from './contract-
|
|
2
|
-
export { C as CRASH_AFTER_THROWS, M as MAX_CATCHUP, a as MatterBodyRecord, b as MatterSection, c as Mulberry32, P as PhysicsEngineTag, d as PhysicsSection, R as RoomCore, e as decodeMatterBodies, f as decodeMatterSectionEnvelope, g as decodePhysicsSection, h as
|
|
1
|
+
export { D as DEFAULT_TIMELINE_MAX_RECORDS, a as DEFAULT_TIMELINE_MAX_TICKS, E as EVENT_RING_SIZE, H as HOST_CALL_TIMEOUT_MS, b as HostCall, c as HostCallResult, J as JoinOptions, d as JoinResult, L as LogLevel, R as RoomCoreApi, e as RoomCoreOptions, f as RoomEvent, g as RoomEventKind, h as RoomFullError, i as RoomHost, j as RoomInspection, k as RoomStats, T as TimelineDump, l as TimelineFrame, m as TimelineRecorder, n as TimelineRecorderOptions, o as inspectState } from './contract-CRilLVdx.js';
|
|
2
|
+
export { C as CRASH_AFTER_THROWS, M as MAX_CATCHUP, a as MatterBodyRecord, b as MatterSection, c as Mulberry32, P as PhysicsEngineTag, d as PhysicsSection, R as RoomCore, e as decodeMatterBodies, f as decodeMatterSectionEnvelope, g as decodePhysicsSection, h as decodeRapier2dSectionEnvelope, i as encodeMatterBodies, j as encodeMatterSectionEnvelope, k as encodePhysicsSection, l as encodeRapier2dSectionEnvelope, m as initMatter, n as initPhysics, o as initRapier2d, p as loadedMatter, q as loadedPhysics, r as loadedRapier2d, s as physicsSectionEngine, t as resetMatterForTests, u as resetPhysicsForTests, v as resetRapier2dForTests } from './room-YJGz6Caw.js';
|
|
3
3
|
import { CollectionDesc, AnySchema, PlainState, DirtySet } from '@irtio/schema';
|
|
4
4
|
import '@irtio/protocol';
|
|
5
5
|
import '@irtio/server';
|
|
@@ -121,7 +121,7 @@ interface DecodedSave extends SnapshotHeader {
|
|
|
121
121
|
* there is no section at all. A pre-D45 blob has no discriminant and reads as `'rapier3d'`,
|
|
122
122
|
* which is what it is.
|
|
123
123
|
*/
|
|
124
|
-
readonly physicsEngine: 'rapier3d' | 'matter2d' | undefined;
|
|
124
|
+
readonly physicsEngine: 'rapier3d' | 'matter2d' | 'rapier2d' | undefined;
|
|
125
125
|
/**
|
|
126
126
|
* The room's authoritative state, in exactly the shape `inspectState` and the recorded
|
|
127
127
|
* timeline use: entity collections as `{ id: { owner, value } }`, singletons as their value.
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
fromMigrationState,
|
|
3
3
|
migrateSnapshot,
|
|
4
4
|
toMigrationState
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-DBGMG2S3.js";
|
|
6
6
|
import {
|
|
7
7
|
CRASH_AFTER_THROWS,
|
|
8
8
|
DEFAULT_TIMELINE_MAX_RECORDS,
|
|
@@ -22,27 +22,32 @@ import {
|
|
|
22
22
|
decodeMatterBodies,
|
|
23
23
|
decodeMatterSectionEnvelope,
|
|
24
24
|
decodePhysicsSection,
|
|
25
|
+
decodeRapier2dSectionEnvelope,
|
|
25
26
|
decodeSave,
|
|
26
27
|
encodeMatterBodies,
|
|
27
28
|
encodeMatterSectionEnvelope,
|
|
28
29
|
encodePhysicsSection,
|
|
30
|
+
encodeRapier2dSectionEnvelope,
|
|
29
31
|
encodeViewDelta,
|
|
30
32
|
encodeViewSnapshot,
|
|
31
33
|
initMatter,
|
|
32
34
|
initPhysics,
|
|
35
|
+
initRapier2d,
|
|
33
36
|
inspectState,
|
|
34
37
|
isVisible,
|
|
35
38
|
loadedMatter,
|
|
36
39
|
loadedPhysics,
|
|
40
|
+
loadedRapier2d,
|
|
37
41
|
parseHibernationBlob,
|
|
38
42
|
physicsSectionEngine,
|
|
39
43
|
resetMatterForTests,
|
|
40
44
|
resetPhysicsForTests,
|
|
45
|
+
resetRapier2dForTests,
|
|
41
46
|
viewKeyFor,
|
|
42
47
|
visibleNames,
|
|
43
48
|
visibleTo,
|
|
44
49
|
writeHibernationBlob
|
|
45
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-ZCD2TBXB.js";
|
|
46
51
|
export {
|
|
47
52
|
CRASH_AFTER_THROWS,
|
|
48
53
|
DEFAULT_TIMELINE_MAX_RECORDS,
|
|
@@ -62,24 +67,29 @@ export {
|
|
|
62
67
|
decodeMatterBodies,
|
|
63
68
|
decodeMatterSectionEnvelope,
|
|
64
69
|
decodePhysicsSection,
|
|
70
|
+
decodeRapier2dSectionEnvelope,
|
|
65
71
|
decodeSave,
|
|
66
72
|
encodeMatterBodies,
|
|
67
73
|
encodeMatterSectionEnvelope,
|
|
68
74
|
encodePhysicsSection,
|
|
75
|
+
encodeRapier2dSectionEnvelope,
|
|
69
76
|
encodeViewDelta,
|
|
70
77
|
encodeViewSnapshot,
|
|
71
78
|
fromMigrationState,
|
|
72
79
|
initMatter,
|
|
73
80
|
initPhysics,
|
|
81
|
+
initRapier2d,
|
|
74
82
|
inspectState,
|
|
75
83
|
isVisible,
|
|
76
84
|
loadedMatter,
|
|
77
85
|
loadedPhysics,
|
|
86
|
+
loadedRapier2d,
|
|
78
87
|
migrateSnapshot,
|
|
79
88
|
parseHibernationBlob,
|
|
80
89
|
physicsSectionEngine,
|
|
81
90
|
resetMatterForTests,
|
|
82
91
|
resetPhysicsForTests,
|
|
92
|
+
resetRapier2dForTests,
|
|
83
93
|
toMigrationState,
|
|
84
94
|
viewKeyFor,
|
|
85
95
|
visibleNames,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AttributeOptions, ProfileSnapshot } from '@irtio/protocol';
|
|
2
2
|
import { DirtySet, AnySchema, PlainState, Tracked, State } from '@irtio/schema';
|
|
3
|
-
import { RoomDefinition, RoomMode, Room, Ctx, MatterModule, MatterEngine, MatterBody, RapierModule, RapierWorld, RapierRigidBody, ResolvedRoomConfig, LeaveReason } from '@irtio/server';
|
|
4
|
-
import { i as RoomHost, k as RoomStats, L as LogLevel, R as RoomCoreApi, e as RoomCoreOptions, g as RoomEventKind, n as TimelineRecorderOptions, T as TimelineDump, j as RoomInspection, J as JoinOptions, d as JoinResult, c as HostCallResult } from './contract-
|
|
3
|
+
import { RoomDefinition, RoomMode, Room, RewindView, Ctx, MatterModule, MatterEngine, MatterBody, RapierModule, RapierWorld, RapierRigidBody, Rapier2dModule, Rapier2dWorld, Rapier2dRigidBody, ResolvedRoomConfig, LeaveReason } from '@irtio/server';
|
|
4
|
+
import { i as RoomHost, k as RoomStats, L as LogLevel, R as RoomCoreApi, e as RoomCoreOptions, g as RoomEventKind, n as TimelineRecorderOptions, T as TimelineDump, j as RoomInspection, J as JoinOptions, d as JoinResult, c as HostCallResult } from './contract-CRilLVdx.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* `room.random()` — mulberry32 over a u32 seed. Deterministic, tiny, and serializable: the
|
|
@@ -93,8 +93,8 @@ interface QueuedFrame {
|
|
|
93
93
|
}
|
|
94
94
|
/** What the core modules may do with the physics world (`core/physics.ts` implements it). */
|
|
95
95
|
interface PhysicsApi {
|
|
96
|
-
/** D45: which of the
|
|
97
|
-
readonly engineKind: 'rapier3d' | 'matter2d';
|
|
96
|
+
/** D45: which of the blessed engines this room is running. */
|
|
97
|
+
readonly engineKind: 'rapier3d' | 'matter2d' | 'rapier2d';
|
|
98
98
|
readonly timestep: number;
|
|
99
99
|
/** Creates bodies for new instances, destroys bodies whose instance is gone. */
|
|
100
100
|
reconcile(): void;
|
|
@@ -102,9 +102,17 @@ interface PhysicsApi {
|
|
|
102
102
|
/** Body → schema, through the tracked proxies. */
|
|
103
103
|
sync(): void;
|
|
104
104
|
bodyFor(collection: string, id: string): unknown;
|
|
105
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* D72: every body this runtime tracks, in the same collection-then-instance order `sync()`
|
|
107
|
+
* walks. Read-only and allocation-free: the pose history calls it once per tick to copy poses
|
|
108
|
+
* out, and the rewind scratch calls it to keep its doubles in step with the live world. It is
|
|
109
|
+
* the only thing outside the engine runtimes that sees a live body other than through
|
|
110
|
+
* `bodyFor`, and it never hands out the map itself.
|
|
111
|
+
*/
|
|
112
|
+
eachTrackedBody(fn: (collection: string, id: string, body: unknown) => void): void;
|
|
113
|
+
/** rapier3d and rapier2d: the engine namespace. `engineKind` says which module it is. */
|
|
106
114
|
readonly rapier: unknown;
|
|
107
|
-
/** rapier3d
|
|
115
|
+
/** rapier3d and rapier2d: the live `World`. */
|
|
108
116
|
readonly world: unknown;
|
|
109
117
|
/** matter2d only: the `matter-js` namespace. */
|
|
110
118
|
readonly matter: unknown;
|
|
@@ -151,6 +159,13 @@ interface RoomInternals {
|
|
|
151
159
|
guard<T>(name: string, fn: () => T): T | undefined;
|
|
152
160
|
/** D41: record this tick on the authoritative timeline. A no-op while the recorder is unarmed. */
|
|
153
161
|
captureTimeline(): void;
|
|
162
|
+
/**
|
|
163
|
+
* D72: record this tick's body poses. A no-op — and, more to the point, a call that never
|
|
164
|
+
* reaches the engine runtime at all — in a room whose config declares no `physics.history`.
|
|
165
|
+
*/
|
|
166
|
+
captureHistory(): void;
|
|
167
|
+
/** D72: `room.rewind(tick, fn)`. Throws when the room declares no `physics.history`. */
|
|
168
|
+
rewind<T>(tick: number, fn: (past: RewindView) => T): T;
|
|
154
169
|
recordEvent(kind: 'join' | 'leave' | 'write' | 'write-rejected' | 'correct' | 'call' | 'reply' | 'msg' | 'alarm' | 'bus' | 'error', clientId?: string, detail?: string): void;
|
|
155
170
|
/** `guard` that also reports whether the handler threw (the tick loop needs this). */
|
|
156
171
|
tryRun<T>(name: string, fn: () => T): GuardResult<T>;
|
|
@@ -337,6 +352,11 @@ declare class MatterRuntime {
|
|
|
337
352
|
free(): void;
|
|
338
353
|
bodyFor(collection: string, id: string): MatterBody | undefined;
|
|
339
354
|
private create;
|
|
355
|
+
/**
|
|
356
|
+
* D72: every tracked body, in the order `sync()` walks them. The matter half of the same
|
|
357
|
+
* read-only accessor `PhysicsRuntime` carries; see its comment for what calls it and when.
|
|
358
|
+
*/
|
|
359
|
+
eachTrackedBody(fn: (collection: string, id: string, body: MatterBody) => void): void;
|
|
340
360
|
private applyState;
|
|
341
361
|
private applyRecordToBody;
|
|
342
362
|
reconcile(): void;
|
|
@@ -411,9 +431,27 @@ declare function encodePhysicsSection(section: PhysicsSection): Uint8Array;
|
|
|
411
431
|
* pre-D45 blob is therefore byte-identical and reads as Rapier without a version bump, which is
|
|
412
432
|
* what the recommendation in the plan asked for and why format 3 was not needed.
|
|
413
433
|
*/
|
|
414
|
-
type PhysicsEngineTag = 'rapier3d' | 'matter2d';
|
|
415
|
-
/**
|
|
434
|
+
type PhysicsEngineTag = 'rapier3d' | 'matter2d' | 'rapier2d';
|
|
435
|
+
/**
|
|
436
|
+
* Reads the engine out of an encoded section without decoding the rest of it.
|
|
437
|
+
*
|
|
438
|
+
* The `else` is deliberately bare rather than a third tag comparison: a pre-D45 blob has no
|
|
439
|
+
* discriminant at all, and every byte sequence that is not the zero-length-world envelope is a
|
|
440
|
+
* rapier3d world snapshot. Adding rapier2d must not change that, or every blob written before
|
|
441
|
+
* this engine existed stops decoding.
|
|
442
|
+
*/
|
|
416
443
|
declare function physicsSectionEngine(bytes: Uint8Array): PhysicsEngineTag;
|
|
444
|
+
/**
|
|
445
|
+
* Wraps a rapier2d section in the same discriminated envelope, under its own tag.
|
|
446
|
+
*
|
|
447
|
+
* The payload is an ordinary {@link encodePhysicsSection} — rapier2d has a real
|
|
448
|
+
* `world.takeSnapshot()`, so unlike matter2d it has a world to write, and the only thing the
|
|
449
|
+
* envelope buys is telling the two Rapiers apart. Restoring a 2D snapshot into a 3D world (or the
|
|
450
|
+
* reverse) does not fail cleanly, which is exactly why the discriminant is not optional here.
|
|
451
|
+
*/
|
|
452
|
+
declare function encodeRapier2dSectionEnvelope(payload: Uint8Array): Uint8Array;
|
|
453
|
+
/** The payload inside a rapier2d envelope. Throws if the section was written by another engine. */
|
|
454
|
+
declare function decodeRapier2dSectionEnvelope(bytes: Uint8Array): Uint8Array;
|
|
417
455
|
/** Wraps a matter2d body-state payload in the discriminated envelope. */
|
|
418
456
|
declare function encodeMatterSectionEnvelope(payload: Uint8Array): Uint8Array;
|
|
419
457
|
/** The payload inside a matter2d envelope. Throws if the section is a Rapier one. */
|
|
@@ -458,6 +496,13 @@ declare class PhysicsRuntime {
|
|
|
458
496
|
/** The body behind an instance, created on demand so a handler's own `add` is usable at once. */
|
|
459
497
|
bodyFor(collection: string, id: string): RapierRigidBody | undefined;
|
|
460
498
|
private create;
|
|
499
|
+
/**
|
|
500
|
+
* D72: every tracked body, in the order `sync()` walks them (collection order, then instance
|
|
501
|
+
* order). Read-only: it hands out the live bodies and nothing else, and the map stays private.
|
|
502
|
+
* The pose history calls this once per tick and the rewind scratch calls it per rewind; a room
|
|
503
|
+
* that declares no `physics.history` never calls it at all.
|
|
504
|
+
*/
|
|
505
|
+
eachTrackedBody(fn: (collection: string, id: string, body: RapierRigidBody) => void): void;
|
|
461
506
|
private applyRecordToBody;
|
|
462
507
|
/**
|
|
463
508
|
* Creates bodies for new instances and destroys bodies whose instance is gone. Runs once per
|
|
@@ -474,6 +519,106 @@ declare class PhysicsRuntime {
|
|
|
474
519
|
serialize(): PhysicsSection;
|
|
475
520
|
}
|
|
476
521
|
|
|
522
|
+
/**
|
|
523
|
+
* The rapier2d world inside the room: Rapier, held in a plane.
|
|
524
|
+
*
|
|
525
|
+
* It is modelled on `core/physics.ts` rather than on `core/matter.ts`, and the choice is the whole
|
|
526
|
+
* point of the engine existing. Everything that made the Rapier path good is kept:
|
|
527
|
+
*
|
|
528
|
+
* - **A real engine snapshot.** `world.takeSnapshot()` / `World.restoreSnapshot()` exist in the 2D
|
|
529
|
+
* build too, so a woken room is byte-for-byte the world that went to sleep, contacts and sleep
|
|
530
|
+
* timers included, and `setup` runs only on a genuine rebuild. matter2d has no equivalent and
|
|
531
|
+
* rebuilds every wake; that difference is why a settled pile can jolt there and does not here.
|
|
532
|
+
* - **The world applies gravity.** It goes into the `World` constructor and dynamic bodies fall
|
|
533
|
+
* without the room lifting a finger. A matter2d room's hooks apply gravity themselves; a
|
|
534
|
+
* rapier2d room that copied that would fall twice as fast.
|
|
535
|
+
* - **Velocities are per second.** `linvel()` is metres per second, not matter's per-step
|
|
536
|
+
* displacement, so nothing here rescales anything.
|
|
537
|
+
*
|
|
538
|
+
* What it takes from the 2D side is only the plane: `{ x, y }` gravity, and the channel mapping in
|
|
539
|
+
* `@irtio/schema` (`channelOf2d` / `applyChannel2d` / `angleFrom2d`), which is the single place the
|
|
540
|
+
* six planar quantities are written onto the thirteen 3D wire channels. A second copy of that
|
|
541
|
+
* mapping here would be a way for the two sides to disagree by a sign, so there is not one.
|
|
542
|
+
*
|
|
543
|
+
* There is no planar-lock warning in this file. Bug 6's friction trap needs a third axis to lock,
|
|
544
|
+
* and this engine does not have one.
|
|
545
|
+
*
|
|
546
|
+
* ## Async init
|
|
547
|
+
*
|
|
548
|
+
* Rapier's WASM needs `await RAPIER.init()`, and room handlers are synchronous, so the engine is
|
|
549
|
+
* initialized before the room is constructed — by the worker host at bundle-load time, and by
|
|
550
|
+
* `initRapier2d()` in the test harness. This is `initPhysics()`'s twin, against the 2D module.
|
|
551
|
+
*/
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Loads and initializes `@dimforge/rapier2d-compat` once per process. Idempotent and safe to call
|
|
555
|
+
* concurrently. It is a *separate* WASM module from the 3D build — the two do not share an
|
|
556
|
+
* instance and loading one does not load the other — so a rapier2d room pays the 2D module's
|
|
557
|
+
* footprint and nothing else.
|
|
558
|
+
*/
|
|
559
|
+
declare function initRapier2d(): Promise<Rapier2dModule>;
|
|
560
|
+
/** The initialized engine, or `undefined` when `initRapier2d()` has not resolved yet. */
|
|
561
|
+
declare function loadedRapier2d(): Rapier2dModule | undefined;
|
|
562
|
+
/** Test seam: forget the loaded engine (never used in production paths). */
|
|
563
|
+
declare function resetRapier2dForTests(): void;
|
|
564
|
+
interface Rapier2dRuntimeOptions {
|
|
565
|
+
/** From a v2 hibernation blob's rapier2d section. Absent → a fresh world, and `setup` runs. */
|
|
566
|
+
readonly restore?: PhysicsSection;
|
|
567
|
+
/** Seconds per step when the config does not name one (the tick interval). */
|
|
568
|
+
readonly defaultTimestep: number;
|
|
569
|
+
}
|
|
570
|
+
declare class Rapier2dRuntime {
|
|
571
|
+
readonly engineKind: "rapier2d";
|
|
572
|
+
/** matter2d only; present so every runtime satisfies one internal shape. */
|
|
573
|
+
readonly matter: undefined;
|
|
574
|
+
readonly matterEngine: undefined;
|
|
575
|
+
readonly rapier: Rapier2dModule;
|
|
576
|
+
readonly world: Rapier2dWorld;
|
|
577
|
+
/** `true` when the world was built from scratch and `setup` has to run. */
|
|
578
|
+
readonly rebuilt: boolean;
|
|
579
|
+
/** Rapier restores a whole world, contacts included, so `setup` runs only on a rebuild. */
|
|
580
|
+
get needsSetup(): boolean;
|
|
581
|
+
private readonly core;
|
|
582
|
+
private readonly config;
|
|
583
|
+
/** Physics-backed collections, in schema (name-sorted) order. */
|
|
584
|
+
private readonly collections;
|
|
585
|
+
private readonly bodies;
|
|
586
|
+
/** See `PhysicsRuntime.sleepSynced`: the one extra sync a body owes on the tick it sleeps. */
|
|
587
|
+
private readonly sleepSynced;
|
|
588
|
+
constructor(core: RoomInternals, rapier: Rapier2dModule, options: Rapier2dRuntimeOptions);
|
|
589
|
+
get timestep(): number;
|
|
590
|
+
/** Runs the room's `setup` — static geometry — on a world that was built rather than restored. */
|
|
591
|
+
runSetup(room: Room): void;
|
|
592
|
+
free(): void;
|
|
593
|
+
/** The body behind an instance, created on demand so a handler's own `add` is usable at once. */
|
|
594
|
+
bodyFor(collection: string, id: string): Rapier2dRigidBody | undefined;
|
|
595
|
+
private create;
|
|
596
|
+
/**
|
|
597
|
+
* D72: every tracked body, in the order `sync()` walks them (collection order, then instance
|
|
598
|
+
* order). The rapier2d third of the same read-only accessor the other two runtimes carry.
|
|
599
|
+
*/
|
|
600
|
+
eachTrackedBody(fn: (collection: string, id: string, body: Rapier2dRigidBody) => void): void;
|
|
601
|
+
private applyRecordToBody;
|
|
602
|
+
/**
|
|
603
|
+
* Creates bodies for new instances and destroys bodies whose instance is gone. Runs once per
|
|
604
|
+
* tick, right before the step, in collection order then instance order.
|
|
605
|
+
*/
|
|
606
|
+
reconcile(): void;
|
|
607
|
+
step(): void;
|
|
608
|
+
/**
|
|
609
|
+
* Body → schema, through the tracked proxies, so movement leaves the room as an ordinary delta.
|
|
610
|
+
* Values are `Math.fround`ed for f32 fields, so room code reads exactly what the wire carries.
|
|
611
|
+
*/
|
|
612
|
+
sync(): void;
|
|
613
|
+
/**
|
|
614
|
+
* The same `PhysicsSection` the 3D runtime writes — a real engine snapshot plus the
|
|
615
|
+
* entity↔handle map, whose handles must ride as f64 for the reason spelled out on
|
|
616
|
+
* {@link PhysicsSection}. What tells the two apart on the way back in is the envelope
|
|
617
|
+
* `core/physics.ts` wraps this in, not anything in here.
|
|
618
|
+
*/
|
|
619
|
+
serialize(): PhysicsSection;
|
|
620
|
+
}
|
|
621
|
+
|
|
477
622
|
/**
|
|
478
623
|
* `RoomCore` — the host-agnostic room runtime. It owns the extended schema, the
|
|
479
624
|
* tracked authority state, presence, the loop, and the frame dispatch; everything outside comes
|
|
@@ -494,7 +639,7 @@ declare class RoomCore<S extends AnySchema = AnySchema> implements RoomCoreApi<S
|
|
|
494
639
|
readonly clients: Map<string, ClientEntry>;
|
|
495
640
|
readonly loop: Loop;
|
|
496
641
|
/** D22: the Rapier world, or `undefined` in a room whose config declares no physics. */
|
|
497
|
-
readonly physics: PhysicsRuntime | MatterRuntime | undefined;
|
|
642
|
+
readonly physics: PhysicsRuntime | MatterRuntime | Rapier2dRuntime | undefined;
|
|
498
643
|
readonly stats: RoomStats;
|
|
499
644
|
tick: number;
|
|
500
645
|
stopped: boolean;
|
|
@@ -516,6 +661,13 @@ declare class RoomCore<S extends AnySchema = AnySchema> implements RoomCoreApi<S
|
|
|
516
661
|
* cost the profiler has is behind this `undefined`.
|
|
517
662
|
*/
|
|
518
663
|
private readonly ledger;
|
|
664
|
+
/**
|
|
665
|
+
* D72: the pose history and the rewind scratch, present only when the room's physics config
|
|
666
|
+
* declares `history`. Every cost this lane has is behind this `undefined`, and it is
|
|
667
|
+
* deliberately not in the hibernation blob: a woken room starts with an empty buffer and fills
|
|
668
|
+
* it again over its next `history` ticks.
|
|
669
|
+
*/
|
|
670
|
+
private readonly rewindState;
|
|
519
671
|
private readonly seed;
|
|
520
672
|
private readonly api;
|
|
521
673
|
private readonly internals;
|
|
@@ -562,6 +714,12 @@ declare class RoomCore<S extends AnySchema = AnySchema> implements RoomCoreApi<S
|
|
|
562
714
|
* worth logging.
|
|
563
715
|
*/
|
|
564
716
|
private buildMatter;
|
|
717
|
+
/**
|
|
718
|
+
* The rapier2d half. It follows the *rapier3d* shape rather than matter2d's, because the 2D
|
|
719
|
+
* build has a real `takeSnapshot()`: a restored world comes back whole and `setup` does not run
|
|
720
|
+
* again. The only thing that differs from `buildPhysics` is which engine and which envelope.
|
|
721
|
+
*/
|
|
722
|
+
private buildRapier2d;
|
|
565
723
|
/** Convenience for hosts: `RoomCore.restore(def, bytes, host, opts)`. */
|
|
566
724
|
static restore<S2 extends AnySchema>(definition: RoomDefinition<S2>, bytes: Uint8Array, host: RoomHost, options: Omit<RoomCoreOptions, 'restoreFrom'>): RoomCore<S2>;
|
|
567
725
|
get schema(): S;
|
|
@@ -581,6 +739,17 @@ declare class RoomCore<S extends AnySchema = AnySchema> implements RoomCoreApi<S
|
|
|
581
739
|
recording(): TimelineDump | undefined;
|
|
582
740
|
/** D41: called at the end of every tick (and every event-mode flush). No-op when unarmed. */
|
|
583
741
|
captureTimeline(): void;
|
|
742
|
+
/**
|
|
743
|
+
* D72: record this tick's body poses, right after `physics.sync()` — the poses the clients are
|
|
744
|
+
* about to be told about, under the tick number they will be told it under, which is the tick a
|
|
745
|
+
* client later stamps its `CALL` with.
|
|
746
|
+
*/
|
|
747
|
+
captureHistory(): void;
|
|
748
|
+
/**
|
|
749
|
+
* D72: `room.rewind(tick, fn)`. The live world is not touched and nothing is re-simulated; `fn`
|
|
750
|
+
* queries a scratch world holding every tracked body at its pose at `tick`.
|
|
751
|
+
*/
|
|
752
|
+
rewind<T>(tick: number, fn: (past: RewindView) => T): T;
|
|
584
753
|
/** Live JSON view of the room for the dev page / supervisor admin API. */
|
|
585
754
|
inspect(): RoomInspection;
|
|
586
755
|
guard<T>(name: string, fn: () => T): T | undefined;
|
|
@@ -662,4 +831,4 @@ declare class RoomCore<S extends AnySchema = AnySchema> implements RoomCoreApi<S
|
|
|
662
831
|
flush(): void;
|
|
663
832
|
}
|
|
664
833
|
|
|
665
|
-
export { CRASH_AFTER_THROWS as C, MAX_CATCHUP as M, type PhysicsEngineTag as P, RoomCore as R, type MatterBodyRecord as a, type MatterSection as b, Mulberry32 as c, type PhysicsSection as d, decodeMatterBodies as e, decodeMatterSectionEnvelope as f, decodePhysicsSection as g,
|
|
834
|
+
export { CRASH_AFTER_THROWS as C, MAX_CATCHUP as M, type PhysicsEngineTag as P, RoomCore as R, type MatterBodyRecord as a, type MatterSection as b, Mulberry32 as c, type PhysicsSection as d, decodeMatterBodies as e, decodeMatterSectionEnvelope as f, decodePhysicsSection as g, decodeRapier2dSectionEnvelope as h, encodeMatterBodies as i, encodeMatterSectionEnvelope as j, encodePhysicsSection as k, encodeRapier2dSectionEnvelope as l, initMatter as m, initPhysics as n, initRapier2d as o, loadedMatter as p, loadedPhysics as q, loadedRapier2d as r, physicsSectionEngine as s, resetMatterForTests as t, resetPhysicsForTests as u, resetRapier2dForTests as v };
|
package/dist/test/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { R as RoomCore } from '../room-
|
|
2
|
-
export {
|
|
1
|
+
import { R as RoomCore } from '../room-YJGz6Caw.js';
|
|
2
|
+
export { m as initMatter, n as initPhysics, o as initRapier2d } from '../room-YJGz6Caw.js';
|
|
3
3
|
import { ErrorCodeName, FrameType } from '@irtio/protocol';
|
|
4
4
|
import { NpcConfig, LeaveReason, Room, RoomDefinition } from '@irtio/server';
|
|
5
|
-
import { i as RoomHost, L as LogLevel, R as RoomCoreApi, b as HostCall, c as HostCallResult, k as RoomStats } from '../contract-
|
|
5
|
+
import { i as RoomHost, L as LogLevel, R as RoomCoreApi, b as HostCall, c as HostCallResult, k as RoomStats } from '../contract-CRilLVdx.js';
|
|
6
6
|
import { AnySchema, PlainState, EntityCollection, State } from '@irtio/schema';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -166,6 +166,17 @@ declare class HarnessHost implements RoomHost {
|
|
|
166
166
|
/** D63-e: the harness has no room list to report on, so it records the value and stops. */
|
|
167
167
|
backfillOpen: boolean | undefined;
|
|
168
168
|
setBackfill(open: boolean): void;
|
|
169
|
+
/** D75: recorded, like the backfill flag, and for the same reason — no room list to report on. */
|
|
170
|
+
lobby: {
|
|
171
|
+
public?: boolean;
|
|
172
|
+
queue?: string;
|
|
173
|
+
started?: boolean;
|
|
174
|
+
};
|
|
175
|
+
setLobby(update: {
|
|
176
|
+
readonly public?: boolean;
|
|
177
|
+
readonly queue?: string;
|
|
178
|
+
readonly started?: boolean;
|
|
179
|
+
}): void;
|
|
169
180
|
busPublish(channel: string, payload: string): void;
|
|
170
181
|
busSubscribe(channel: string, subscribed: boolean): void;
|
|
171
182
|
setAlarm(name: string, atMs: number | undefined): void;
|
package/dist/test/index.js
CHANGED
|
@@ -3,8 +3,9 @@ import {
|
|
|
3
3
|
createVisibilityPolicy,
|
|
4
4
|
initMatter,
|
|
5
5
|
initPhysics,
|
|
6
|
+
initRapier2d,
|
|
6
7
|
visibleNames
|
|
7
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-ZCD2TBXB.js";
|
|
8
9
|
|
|
9
10
|
// src/test/clock.ts
|
|
10
11
|
var FakeClock = class {
|
|
@@ -197,7 +198,7 @@ var HarnessHost = class {
|
|
|
197
198
|
return { ok: true };
|
|
198
199
|
}
|
|
199
200
|
case "lbSubmit": {
|
|
200
|
-
const key = `${call.board} ${call.playerId}`;
|
|
201
|
+
const key = call.bucket === void 0 ? `${call.board} ${call.playerId}` : `${call.board} ${call.bucket} ${call.playerId}`;
|
|
201
202
|
const existing = this.scores.get(key);
|
|
202
203
|
if (existing === void 0 || call.score > existing) this.scores.set(key, call.score);
|
|
203
204
|
return { ok: true };
|
|
@@ -235,6 +236,12 @@ var HarnessHost = class {
|
|
|
235
236
|
setBackfill(open) {
|
|
236
237
|
this.backfillOpen = open;
|
|
237
238
|
}
|
|
239
|
+
// ---- M6 lane H: lobby front door ----
|
|
240
|
+
/** D75: recorded, like the backfill flag, and for the same reason — no room list to report on. */
|
|
241
|
+
lobby = {};
|
|
242
|
+
setLobby(update) {
|
|
243
|
+
this.lobby = { ...this.lobby, ...update };
|
|
244
|
+
}
|
|
238
245
|
busPublish(channel, payload) {
|
|
239
246
|
this.busPublishes.push({ channel, payload });
|
|
240
247
|
}
|
|
@@ -974,5 +981,6 @@ export {
|
|
|
974
981
|
createRoomHarness,
|
|
975
982
|
frameTypeName,
|
|
976
983
|
initMatter,
|
|
977
|
-
initPhysics
|
|
984
|
+
initPhysics,
|
|
985
|
+
initRapier2d
|
|
978
986
|
};
|
package/dist/worker/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as LogLevel, T as TimelineDump, k as RoomStats, b as HostCall, c as HostCallResult, R as RoomCoreApi, i as RoomHost } from '../contract-
|
|
1
|
+
import { L as LogLevel, T as TimelineDump, k as RoomStats, b as HostCall, c as HostCallResult, R as RoomCoreApi, i as RoomHost } from '../contract-CRilLVdx.js';
|
|
2
2
|
import { ErrorCodeName, ProfileSnapshot } from '@irtio/protocol';
|
|
3
3
|
import { NpcConfig, LeaveReason } from '@irtio/server';
|
|
4
4
|
import '@irtio/schema';
|
|
@@ -151,6 +151,9 @@ type FromWorker = {
|
|
|
151
151
|
/** D63-e: the room type's declared backfill eligibility. The ceiling on
|
|
152
152
|
* `room.backfill.set`, and `false` for every room that declares nothing. */
|
|
153
153
|
backfill?: boolean;
|
|
154
|
+
/** D75: the room type declared a lobby. The ceiling on `setLobby`, and the supervisor
|
|
155
|
+
* re-checks it for exactly the reason it re-checks `backfill`. */
|
|
156
|
+
lobby?: boolean;
|
|
154
157
|
/** D47: the physics engine this room runs, when it declares one. Reported so room-hours
|
|
155
158
|
* rows carry the engine as a dimension; the supervisor never acts on it. */
|
|
156
159
|
engine?: string;
|
|
@@ -289,6 +292,11 @@ type FromWorker = {
|
|
|
289
292
|
| {
|
|
290
293
|
t: 'setBackfill';
|
|
291
294
|
open: boolean;
|
|
295
|
+
} | {
|
|
296
|
+
t: 'setLobby';
|
|
297
|
+
public?: boolean;
|
|
298
|
+
queue?: string;
|
|
299
|
+
started?: boolean;
|
|
292
300
|
}
|
|
293
301
|
/**
|
|
294
302
|
* D59: `room.bus.publish(channel, payload)`. Fire-and-forget by design — the room gets no
|
package/dist/worker/index.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
migrateSnapshot
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-DBGMG2S3.js";
|
|
4
4
|
import {
|
|
5
5
|
RoomCore,
|
|
6
6
|
RoomFullError,
|
|
7
7
|
initMatter,
|
|
8
8
|
initPhysics,
|
|
9
|
+
initRapier2d,
|
|
9
10
|
onFirstRapierStep,
|
|
10
11
|
rapierHasStepped
|
|
11
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-ZCD2TBXB.js";
|
|
12
13
|
|
|
13
14
|
// src/worker/index.ts
|
|
14
15
|
import { getHeapStatistics } from "v8";
|
|
@@ -79,6 +80,10 @@ function createWorkerHost(post) {
|
|
|
79
80
|
setBackfill(open) {
|
|
80
81
|
post({ t: "setBackfill", open });
|
|
81
82
|
},
|
|
83
|
+
// ---- M6 lane H: lobby front door ----
|
|
84
|
+
setLobby(update) {
|
|
85
|
+
post({ t: "setLobby", ...update });
|
|
86
|
+
},
|
|
82
87
|
setAlarm(name, atMs) {
|
|
83
88
|
if (atMs === void 0) {
|
|
84
89
|
post({ t: "setAlarm", name });
|
|
@@ -153,7 +158,8 @@ async function handleMessage(state, host, post, msg) {
|
|
|
153
158
|
try {
|
|
154
159
|
if (def.config.physics.engine === "matter2d") await initMatter();
|
|
155
160
|
else {
|
|
156
|
-
await
|
|
161
|
+
if (def.config.physics.engine === "rapier2d") await initRapier2d();
|
|
162
|
+
else await initPhysics();
|
|
157
163
|
onFirstRapierStep(() => {
|
|
158
164
|
const core = state.core;
|
|
159
165
|
if (core) post(statsPayload(core.stats, void 0, core.profile()));
|
|
@@ -211,6 +217,11 @@ async function handleMessage(state, host, post, msg) {
|
|
|
211
217
|
// `engine` is: `ready.config` replaces the supervisor's copy, so a flag threaded
|
|
212
218
|
// only through `loadBundle` would be dropped the moment a worker started.
|
|
213
219
|
backfill: c.backfill === true,
|
|
220
|
+
// ---- M6 lane H: lobby front door ----
|
|
221
|
+
// D75: the declared ceiling on `setLobby`, carried for exactly `backfill`'s reason.
|
|
222
|
+
// The supervisor re-checks it, because a check only the tenant's own worker makes is
|
|
223
|
+
// advice rather than a boundary.
|
|
224
|
+
lobby: c.lobby !== void 0,
|
|
214
225
|
// D47: `ready.config` REPLACES the supervisor's copy of the bundle config, so an
|
|
215
226
|
// engine threaded only through `loadBundle` would be dropped here the moment a
|
|
216
227
|
// worker started. That is exactly how the first known-shape run read `engine: none`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@irtio/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "irtio room runtime: RoomCore, worker_threads host, in-process test harness",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -28,11 +28,12 @@
|
|
|
28
28
|
"dist"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
+
"@dimforge/rapier2d-compat": "0.20.0",
|
|
31
32
|
"@dimforge/rapier3d-compat": "0.20.0",
|
|
32
33
|
"matter-js": "0.20.0",
|
|
33
|
-
"@irtio/protocol": "0.
|
|
34
|
-
"@irtio/schema": "0.
|
|
35
|
-
"@irtio/server": "0.
|
|
34
|
+
"@irtio/protocol": "0.8.0",
|
|
35
|
+
"@irtio/schema": "0.8.0",
|
|
36
|
+
"@irtio/server": "0.8.0"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@types/matter-js": "0.20.2"
|