@irtio/runtime 0.9.0 → 0.10.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-ADZZEVJU.js → chunk-KGZEQTJR.js} +104 -17
- package/dist/{chunk-SBDZ45JG.js → chunk-MTBMGUGG.js} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/{room-C4RZJ2KO.d.ts → room-Db3iPBKM.d.ts} +4 -4
- package/dist/test/index.d.ts +2 -2
- package/dist/test/index.js +1 -1
- package/dist/worker/index.js +2 -2
- package/package.json +4 -4
|
@@ -1079,7 +1079,8 @@ var MatterRuntime = class {
|
|
|
1079
1079
|
const plainColl = plainEntity(this.core.plain, desc.name);
|
|
1080
1080
|
for (const id of plainColl.ids()) {
|
|
1081
1081
|
const attached = this.bodies.get(bodyKey(desc.name, id));
|
|
1082
|
-
if (attached)
|
|
1082
|
+
if (attached)
|
|
1083
|
+
fn(desc.name, id, attached.body, plainColl.get(id));
|
|
1083
1084
|
}
|
|
1084
1085
|
}
|
|
1085
1086
|
}
|
|
@@ -1534,7 +1535,7 @@ var PhysicsRuntime = class {
|
|
|
1534
1535
|
const plainColl = plainEntity(this.core.plain, desc.name);
|
|
1535
1536
|
for (const id of plainColl.ids()) {
|
|
1536
1537
|
const body = this.bodies.get(bodyKey2(desc.name, id));
|
|
1537
|
-
if (body) fn(desc.name, id, body);
|
|
1538
|
+
if (body) fn(desc.name, id, body, plainColl.get(id));
|
|
1538
1539
|
}
|
|
1539
1540
|
}
|
|
1540
1541
|
}
|
|
@@ -1939,7 +1940,7 @@ var Rapier2dRuntime = class {
|
|
|
1939
1940
|
const plainColl = plainEntity(this.core.plain, desc.name);
|
|
1940
1941
|
for (const id of plainColl.ids()) {
|
|
1941
1942
|
const body = this.bodies.get(bodyKey3(desc.name, id));
|
|
1942
|
-
if (body) fn(desc.name, id, body);
|
|
1943
|
+
if (body) fn(desc.name, id, body, plainColl.get(id));
|
|
1943
1944
|
}
|
|
1944
1945
|
}
|
|
1945
1946
|
}
|
|
@@ -2456,23 +2457,45 @@ import {
|
|
|
2456
2457
|
|
|
2457
2458
|
// src/core/history.ts
|
|
2458
2459
|
var HISTORY_MAX_TICKS = 240;
|
|
2460
|
+
var HISTORY_MAX_CHANNELS = 8;
|
|
2459
2461
|
var STRIDE = 13;
|
|
2460
2462
|
function emptyPose() {
|
|
2461
2463
|
return { x: 0, y: 0, z: 0, qx: 0, qy: 0, qz: 0, qw: 1, vx: 0, vy: 0, vz: 0, wx: 0, wy: 0, wz: 0 };
|
|
2462
2464
|
}
|
|
2463
2465
|
function newEntry() {
|
|
2464
|
-
return {
|
|
2466
|
+
return {
|
|
2467
|
+
tick: -1,
|
|
2468
|
+
count: 0,
|
|
2469
|
+
collections: [],
|
|
2470
|
+
ids: [],
|
|
2471
|
+
values: new Float64Array(0),
|
|
2472
|
+
channels: new Float32Array(0)
|
|
2473
|
+
};
|
|
2465
2474
|
}
|
|
2466
2475
|
var PoseHistory = class {
|
|
2467
2476
|
depth;
|
|
2477
|
+
/** Declared channels by collection. Empty in a room that declared none. */
|
|
2478
|
+
channels;
|
|
2479
|
+
/**
|
|
2480
|
+
* Slots per body in `entry.channels`: the widest declared count, so a body's channels sit at
|
|
2481
|
+
* `i * channelStride` under the same body index the pose uses. `0` when nothing is declared, and
|
|
2482
|
+
* that zero is what short-circuits the whole channel path per body.
|
|
2483
|
+
*/
|
|
2484
|
+
channelStride;
|
|
2468
2485
|
entries = [];
|
|
2469
2486
|
/** Index of the newest entry in `entries`, or -1 when nothing has been captured. */
|
|
2470
2487
|
head = -1;
|
|
2471
2488
|
size = 0;
|
|
2472
2489
|
/** Reused across every body of every capture: the capture path allocates nothing per body. */
|
|
2473
2490
|
scratchPose = emptyPose();
|
|
2474
|
-
|
|
2491
|
+
/** Collections whose `read` hook has already thrown, so the log is one line, not one per tick. */
|
|
2492
|
+
hookFailed = /* @__PURE__ */ new Set();
|
|
2493
|
+
constructor(depth, channels) {
|
|
2475
2494
|
this.depth = Math.max(1, Math.min(HISTORY_MAX_TICKS, Math.floor(depth)));
|
|
2495
|
+
this.channels = channels ?? /* @__PURE__ */ new Map();
|
|
2496
|
+
let stride = 0;
|
|
2497
|
+
for (const spec of this.channels.values()) stride = Math.max(stride, spec.count);
|
|
2498
|
+
this.channelStride = stride;
|
|
2476
2499
|
for (let i = 0; i < this.depth; i++) this.entries.push(newEntry());
|
|
2477
2500
|
}
|
|
2478
2501
|
get length() {
|
|
@@ -2502,14 +2525,14 @@ var PoseHistory = class {
|
|
|
2502
2525
|
entry.count = 0;
|
|
2503
2526
|
const pose = this.scratchPose;
|
|
2504
2527
|
const kind = physics.engineKind;
|
|
2505
|
-
physics.eachTrackedBody((collection, id, body) => {
|
|
2528
|
+
physics.eachTrackedBody((collection, id, body, instance) => {
|
|
2506
2529
|
if (kind === "rapier3d") readRapierPose(body, pose);
|
|
2507
2530
|
else if (kind === "rapier2d") readRapier2dPose(body, pose);
|
|
2508
2531
|
else readMatterPose(body, pose);
|
|
2509
|
-
this.push(entry, collection, id, pose);
|
|
2532
|
+
this.push(entry, collection, id, pose, instance);
|
|
2510
2533
|
});
|
|
2511
2534
|
}
|
|
2512
|
-
push(entry, collection, id, pose) {
|
|
2535
|
+
push(entry, collection, id, pose, instance) {
|
|
2513
2536
|
const i = entry.count;
|
|
2514
2537
|
const need = (i + 1) * STRIDE;
|
|
2515
2538
|
if (entry.values.length < need) {
|
|
@@ -2517,6 +2540,34 @@ var PoseHistory = class {
|
|
|
2517
2540
|
grown.set(entry.values);
|
|
2518
2541
|
entry.values = grown;
|
|
2519
2542
|
}
|
|
2543
|
+
const stride = this.channelStride;
|
|
2544
|
+
if (stride > 0) {
|
|
2545
|
+
const want = (i + 1) * stride;
|
|
2546
|
+
if (entry.channels.length < want) {
|
|
2547
|
+
const grown = new Float32Array(Math.max(want, entry.channels.length * 2, stride * 8));
|
|
2548
|
+
grown.set(entry.channels);
|
|
2549
|
+
entry.channels = grown;
|
|
2550
|
+
}
|
|
2551
|
+
const o2 = i * stride;
|
|
2552
|
+
entry.channels.fill(0, o2, o2 + stride);
|
|
2553
|
+
const spec = this.channels.get(collection);
|
|
2554
|
+
if (spec) {
|
|
2555
|
+
const scratch = spec.scratch;
|
|
2556
|
+
scratch.fill(0);
|
|
2557
|
+
try {
|
|
2558
|
+
spec.read(instance, scratch);
|
|
2559
|
+
entry.channels.set(scratch, o2);
|
|
2560
|
+
} catch (err) {
|
|
2561
|
+
if (!this.hookFailed.has(collection)) {
|
|
2562
|
+
this.hookFailed.add(collection);
|
|
2563
|
+
console.error(
|
|
2564
|
+
`physics.history.channels.${collection}.read threw; that body's channels are zeros`,
|
|
2565
|
+
err
|
|
2566
|
+
);
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2520
2571
|
entry.collections[i] = collection;
|
|
2521
2572
|
entry.ids[i] = id;
|
|
2522
2573
|
const v = entry.values;
|
|
@@ -2587,6 +2638,10 @@ function poseAt(entry, index, into) {
|
|
|
2587
2638
|
into.wy = v[o + 11];
|
|
2588
2639
|
into.wz = v[o + 12];
|
|
2589
2640
|
}
|
|
2641
|
+
function channelsAt(entry, index, stride, count) {
|
|
2642
|
+
const o = index * stride;
|
|
2643
|
+
return entry.channels.subarray(o, o + count);
|
|
2644
|
+
}
|
|
2590
2645
|
function readRapierPose(body, into) {
|
|
2591
2646
|
const t = body.translation();
|
|
2592
2647
|
const r = body.rotation();
|
|
@@ -2639,10 +2694,20 @@ function readMatterPose(body, into) {
|
|
|
2639
2694
|
into.wy = 0;
|
|
2640
2695
|
into.wz = body.angularVelocity;
|
|
2641
2696
|
}
|
|
2642
|
-
function
|
|
2697
|
+
function historyOf(config) {
|
|
2643
2698
|
const declared = config?.history;
|
|
2644
|
-
|
|
2645
|
-
|
|
2699
|
+
const raw = typeof declared === "number" ? declared : typeof declared === "object" && declared !== null ? declared.depth : void 0;
|
|
2700
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0) return void 0;
|
|
2701
|
+
const depth = Math.min(HISTORY_MAX_TICKS, Math.floor(raw));
|
|
2702
|
+
const channels = /* @__PURE__ */ new Map();
|
|
2703
|
+
if (typeof declared === "object" && declared !== null) {
|
|
2704
|
+
const spec = declared.channels;
|
|
2705
|
+
for (const [name, s] of Object.entries(spec ?? {})) {
|
|
2706
|
+
const count = Math.min(HISTORY_MAX_CHANNELS, Math.floor(s.count));
|
|
2707
|
+
channels.set(name, { count, read: s.read, scratch: new Float32Array(count) });
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
return { depth, channels };
|
|
2646
2711
|
}
|
|
2647
2712
|
function keyOf(collection, id) {
|
|
2648
2713
|
return `${collection} ${id}`;
|
|
@@ -2992,8 +3057,8 @@ var RewindState = class {
|
|
|
2992
3057
|
history;
|
|
2993
3058
|
scratch;
|
|
2994
3059
|
inside = false;
|
|
2995
|
-
constructor(
|
|
2996
|
-
this.history = new PoseHistory(depth);
|
|
3060
|
+
constructor(setup) {
|
|
3061
|
+
this.history = new PoseHistory(setup.depth, setup.channels);
|
|
2997
3062
|
}
|
|
2998
3063
|
free() {
|
|
2999
3064
|
this.scratch?.free();
|
|
@@ -3012,7 +3077,29 @@ var RewindState = class {
|
|
|
3012
3077
|
);
|
|
3013
3078
|
}
|
|
3014
3079
|
this.scratch ??= physics.engineKind === "rapier3d" ? new RapierScratch(physics, this.history.depth, tickNow) : physics.engineKind === "rapier2d" ? new Rapier2dScratch(physics, this.history.depth, tickNow) : new MatterScratch(physics, this.history.depth, tickNow);
|
|
3015
|
-
const
|
|
3080
|
+
const engineView = this.scratch.view(
|
|
3081
|
+
resolved.entry,
|
|
3082
|
+
resolved.tick,
|
|
3083
|
+
requested,
|
|
3084
|
+
resolved.clamped
|
|
3085
|
+
);
|
|
3086
|
+
const entry = resolved.entry;
|
|
3087
|
+
const history = this.history;
|
|
3088
|
+
const view = {
|
|
3089
|
+
...engineView,
|
|
3090
|
+
// A linear scan of the entry rather than an index: an entry holds one room's tracked bodies,
|
|
3091
|
+
// and building a map per rewind would cost more than the scan it saved.
|
|
3092
|
+
channels: (collection, id) => {
|
|
3093
|
+
const spec = history.channels.get(collection);
|
|
3094
|
+
if (!spec) return void 0;
|
|
3095
|
+
for (let i = 0; i < entry.count; i++) {
|
|
3096
|
+
if (entry.collections[i] === collection && entry.ids[i] === id) {
|
|
3097
|
+
return channelsAt(entry, i, history.channelStride, spec.count);
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
return void 0;
|
|
3101
|
+
}
|
|
3102
|
+
};
|
|
3016
3103
|
this.inside = true;
|
|
3017
3104
|
try {
|
|
3018
3105
|
return fn(view);
|
|
@@ -3896,8 +3983,8 @@ var RoomCore = class _RoomCore {
|
|
|
3896
3983
|
this.loop = new Loop(self);
|
|
3897
3984
|
this.api = createRoomApi(self, options.publicUrl ?? DEFAULT_PUBLIC_URL);
|
|
3898
3985
|
this.physics = this.buildPhysics(restored);
|
|
3899
|
-
const
|
|
3900
|
-
this.rewindState =
|
|
3986
|
+
const historySetup = this.physics ? historyOf(definition.config.physics) : void 0;
|
|
3987
|
+
this.rewindState = historySetup === void 0 ? void 0 : new RewindState(historySetup);
|
|
3901
3988
|
this.subscribeDeclaredChannels();
|
|
3902
3989
|
if (restored) {
|
|
3903
3990
|
const onWake = definition.config.onWake;
|
|
@@ -3984,7 +4071,7 @@ var RoomCore = class _RoomCore {
|
|
|
3984
4071
|
const engine4 = loadedPhysics();
|
|
3985
4072
|
if (!engine4) {
|
|
3986
4073
|
throw new Error(
|
|
3987
|
-
"RoomCore: this room declares physics but the engine is not initialized \u2014 the host must `await initPhysics()` (from '@irtio/
|
|
4074
|
+
"RoomCore: this room declares physics but the engine is not initialized \u2014 the host must `await initPhysics()` (in tests: from '@irtio/testing') before constructing the room; handlers are synchronous, so the WASM cannot be loaded later"
|
|
3988
4075
|
);
|
|
3989
4076
|
}
|
|
3990
4077
|
let section;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
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-C5aqs49-.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-
|
|
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-Db3iPBKM.js';
|
|
3
3
|
import { CollectionDesc, AnySchema, PlainState, DirtySet } from '@irtio/schema';
|
|
4
4
|
import '@irtio/protocol';
|
|
5
5
|
import '@irtio/server';
|
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-MTBMGUGG.js";
|
|
6
6
|
import {
|
|
7
7
|
CRASH_AFTER_THROWS,
|
|
8
8
|
DEFAULT_TIMELINE_MAX_RECORDS,
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
visibleNames,
|
|
48
48
|
visibleTo,
|
|
49
49
|
writeHibernationBlob
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-KGZEQTJR.js";
|
|
51
51
|
export {
|
|
52
52
|
CRASH_AFTER_THROWS,
|
|
53
53
|
DEFAULT_TIMELINE_MAX_RECORDS,
|
|
@@ -105,7 +105,7 @@ interface PhysicsApi {
|
|
|
105
105
|
* the only thing outside the engine runtimes that sees a live body other than through
|
|
106
106
|
* `bodyFor`, and it never hands out the map itself.
|
|
107
107
|
*/
|
|
108
|
-
eachTrackedBody(fn: (collection: string, id: string, body: unknown) => void): void;
|
|
108
|
+
eachTrackedBody(fn: (collection: string, id: string, body: unknown, instance: Record<string, unknown>) => void): void;
|
|
109
109
|
/** rapier3d and rapier2d: the engine namespace. `engineKind` says which module it is. */
|
|
110
110
|
readonly rapier: unknown;
|
|
111
111
|
/** rapier3d and rapier2d: the live `World`. */
|
|
@@ -363,7 +363,7 @@ declare class MatterRuntime {
|
|
|
363
363
|
* D72: every tracked body, in the order `sync()` walks them. The matter half of the same
|
|
364
364
|
* read-only accessor `PhysicsRuntime` carries; see its comment for what calls it and when.
|
|
365
365
|
*/
|
|
366
|
-
eachTrackedBody(fn: (collection: string, id: string, body: MatterBody) => void): void;
|
|
366
|
+
eachTrackedBody(fn: (collection: string, id: string, body: MatterBody, instance: Record<string, unknown>) => void): void;
|
|
367
367
|
private applyState;
|
|
368
368
|
private applyRecordToBody;
|
|
369
369
|
reconcile(): void;
|
|
@@ -533,7 +533,7 @@ declare class PhysicsRuntime {
|
|
|
533
533
|
* The pose history calls this once per tick and the rewind scratch calls it per rewind; a room
|
|
534
534
|
* that declares no `physics.history` never calls it at all.
|
|
535
535
|
*/
|
|
536
|
-
eachTrackedBody(fn: (collection: string, id: string, body: RapierRigidBody) => void): void;
|
|
536
|
+
eachTrackedBody(fn: (collection: string, id: string, body: RapierRigidBody, instance: Record<string, unknown>) => void): void;
|
|
537
537
|
private applyRecordToBody;
|
|
538
538
|
/**
|
|
539
539
|
* Creates bodies for new instances and destroys bodies whose instance is gone. Runs once per
|
|
@@ -650,7 +650,7 @@ declare class Rapier2dRuntime {
|
|
|
650
650
|
* D72: every tracked body, in the order `sync()` walks them (collection order, then instance
|
|
651
651
|
* order). The rapier2d third of the same read-only accessor the other two runtimes carry.
|
|
652
652
|
*/
|
|
653
|
-
eachTrackedBody(fn: (collection: string, id: string, body: Rapier2dRigidBody) => void): void;
|
|
653
|
+
eachTrackedBody(fn: (collection: string, id: string, body: Rapier2dRigidBody, instance: Record<string, unknown>) => void): void;
|
|
654
654
|
private applyRecordToBody;
|
|
655
655
|
/**
|
|
656
656
|
* Creates bodies for new instances and destroys bodies whose instance is gone. Runs once per
|
package/dist/test/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as RoomCore } from '../room-
|
|
2
|
-
export { m as initMatter, n as initPhysics, o as initRapier2d } from '../room-
|
|
1
|
+
import { R as RoomCore } from '../room-Db3iPBKM.js';
|
|
2
|
+
export { m as initMatter, n as initPhysics, o as initRapier2d } from '../room-Db3iPBKM.js';
|
|
3
3
|
import { ErrorCodeName, FrameType } from '@irtio/protocol';
|
|
4
4
|
import { NpcConfig, LeaveReason, Room, RoomDefinition } from '@irtio/server';
|
|
5
5
|
import { i as RoomHost, L as LogLevel, R as RoomCoreApi, b as HostCall, c as HostCallResult, k as RoomStats } from '../contract-C5aqs49-.js';
|
package/dist/test/index.js
CHANGED
package/dist/worker/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
migrateSnapshot
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-MTBMGUGG.js";
|
|
4
4
|
import {
|
|
5
5
|
RoomCore,
|
|
6
6
|
RoomFullError,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
initRapier2d,
|
|
10
10
|
onFirstRapierStep,
|
|
11
11
|
rapierHasStepped
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-KGZEQTJR.js";
|
|
13
13
|
|
|
14
14
|
// src/worker/index.ts
|
|
15
15
|
import { getHeapStatistics } from "v8";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@irtio/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "irtio room runtime: RoomCore, worker_threads host, in-process test harness",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"@dimforge/rapier2d-compat": "0.20.0",
|
|
32
32
|
"@dimforge/rapier3d-compat": "0.20.0",
|
|
33
33
|
"matter-js": "0.20.0",
|
|
34
|
-
"@irtio/
|
|
35
|
-
"@irtio/
|
|
36
|
-
"@irtio/
|
|
34
|
+
"@irtio/protocol": "0.10.0",
|
|
35
|
+
"@irtio/schema": "0.10.0",
|
|
36
|
+
"@irtio/server": "0.10.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/matter-js": "0.20.2"
|