@irtio/runtime 0.9.0 → 0.10.1

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.
@@ -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) fn(desc.name, id, attached.body);
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 { tick: -1, count: 0, collections: [], ids: [], values: new Float64Array(0) };
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
- constructor(depth) {
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 historyDepthOf(config) {
2697
+ function historyOf(config) {
2643
2698
  const declared = config?.history;
2644
- if (typeof declared !== "number" || !Number.isFinite(declared) || declared <= 0) return void 0;
2645
- return Math.min(HISTORY_MAX_TICKS, Math.floor(declared));
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}`;
@@ -2650,6 +2715,9 @@ function keyOf(collection, id) {
2650
2715
  function angleOf(qz, qw) {
2651
2716
  return 2 * Math.atan2(qz, qw);
2652
2717
  }
2718
+ function mixSignature(h, v) {
2719
+ return Math.imul(h ^ (Math.round(v * 1024) | 0), 2654435761);
2720
+ }
2653
2721
  var BaseScratch = class {
2654
2722
  constructor(physics, depth, tickNow) {
2655
2723
  this.physics = physics;
@@ -2680,7 +2748,8 @@ var BaseScratch = class {
2680
2748
  }
2681
2749
  /**
2682
2750
  * Brings the scratch's body set in step with the live world: a double for every live body that
2683
- * has none, a rebuild for one whose collider (or part) count changed, and a prune for one that
2751
+ * has none, a rebuild for one whose collider layout changed (count, handles, body-local
2752
+ * offsets, shape type or extents, sensor flags — see `signatureOf`), and a prune for one that
2684
2753
  * has been gone longer than the history is deep and so can no longer appear in any entry.
2685
2754
  *
2686
2755
  * The prune is conservative rather than exact: `lastLive` only advances when a rewind happens,
@@ -2693,9 +2762,9 @@ var BaseScratch = class {
2693
2762
  this.physics.eachTrackedBody((collection, id, body) => {
2694
2763
  const key = keyOf(collection, id);
2695
2764
  seen.add(key);
2696
- const parts = this.partsOf(body);
2765
+ const signature = this.signatureOf(body);
2697
2766
  const existing = this.bodies.get(key);
2698
- if (existing && existing.parts === parts) {
2767
+ if (existing && existing.signature === signature) {
2699
2768
  existing.lastLive = now;
2700
2769
  return;
2701
2770
  }
@@ -2703,7 +2772,7 @@ var BaseScratch = class {
2703
2772
  this.bodies.delete(key);
2704
2773
  this.destroy(existing);
2705
2774
  }
2706
- const made = this.clone(collection, id, body, parts);
2775
+ const made = this.clone(collection, id, body, signature);
2707
2776
  if (!made) return;
2708
2777
  made.lastLive = now;
2709
2778
  this.bodies.set(key, made);
@@ -2744,16 +2813,46 @@ var RapierScratch = class extends BaseScratch {
2744
2813
  this.world = new this.rapier.World({ x: 0, y: 0, z: 0 });
2745
2814
  this.world.timestep = 0;
2746
2815
  }
2747
- partsOf(body) {
2748
- return body.numColliders();
2816
+ signatureOf(body) {
2817
+ const live = body;
2818
+ const n = live.numColliders();
2819
+ const origin = live.translation();
2820
+ const inv = qConj(live.rotation());
2821
+ let h = mixSignature(0, n);
2822
+ for (let i = 0; i < n; i++) {
2823
+ const c = live.collider(i);
2824
+ h = mixSignature(h, c.handle);
2825
+ h = mixSignature(h, c.isSensor() ? 1 : 0);
2826
+ const w = c.translation();
2827
+ const local = qRotate(inv, { x: w.x - origin.x, y: w.y - origin.y, z: w.z - origin.z });
2828
+ h = mixSignature(h, local.x);
2829
+ h = mixSignature(h, local.y);
2830
+ h = mixSignature(h, local.z);
2831
+ const r = qMul(inv, c.rotation());
2832
+ h = mixSignature(h, r.x);
2833
+ h = mixSignature(h, r.y);
2834
+ h = mixSignature(h, r.z);
2835
+ h = mixSignature(h, r.w);
2836
+ const s = c.shape;
2837
+ h = mixSignature(h, s.type);
2838
+ h = mixSignature(h, s.radius ?? 0);
2839
+ h = mixSignature(h, s.halfHeight ?? 0);
2840
+ if (s.halfExtents) {
2841
+ h = mixSignature(h, s.halfExtents.x);
2842
+ h = mixSignature(h, s.halfExtents.y);
2843
+ h = mixSignature(h, s.halfExtents.z);
2844
+ }
2845
+ }
2846
+ return h;
2749
2847
  }
2750
- clone(collection, id, body, parts) {
2848
+ clone(collection, id, body, signature) {
2751
2849
  const live = body;
2752
2850
  this.trackedLive.add(live.handle);
2753
2851
  const made = this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed());
2754
2852
  const origin = live.translation();
2755
2853
  const rot = live.rotation();
2756
2854
  const inv = qConj(rot);
2855
+ const parts = live.numColliders();
2757
2856
  for (let i = 0; i < parts; i++) {
2758
2857
  const c = live.collider(i);
2759
2858
  const desc = new this.rapier.ColliderDesc(c.shape);
@@ -2765,7 +2864,7 @@ var RapierScratch = class extends BaseScratch {
2765
2864
  this.world.createCollider(desc, made);
2766
2865
  }
2767
2866
  this.owners.set(made.handle, { collection, id });
2768
- return { collection, id, body: made, parts, lastLive: -1 };
2867
+ return { collection, id, body: made, signature, lastLive: -1 };
2769
2868
  }
2770
2869
  place(entry, pose) {
2771
2870
  const b = entry.body;
@@ -2841,10 +2940,36 @@ var Rapier2dScratch = class extends BaseScratch {
2841
2940
  this.world = new this.rapier.World({ x: 0, y: 0 });
2842
2941
  this.world.timestep = 0;
2843
2942
  }
2844
- partsOf(body) {
2845
- return body.numColliders();
2943
+ signatureOf(body) {
2944
+ const live = body;
2945
+ const n = live.numColliders();
2946
+ const origin = live.translation();
2947
+ const angle = live.rotation();
2948
+ const cos = Math.cos(-angle);
2949
+ const sin = Math.sin(-angle);
2950
+ let h = mixSignature(0, n);
2951
+ for (let i = 0; i < n; i++) {
2952
+ const c = live.collider(i);
2953
+ h = mixSignature(h, c.handle);
2954
+ h = mixSignature(h, c.isSensor() ? 1 : 0);
2955
+ const w = c.translation();
2956
+ const dx = w.x - origin.x;
2957
+ const dy = w.y - origin.y;
2958
+ h = mixSignature(h, dx * cos - dy * sin);
2959
+ h = mixSignature(h, dx * sin + dy * cos);
2960
+ h = mixSignature(h, c.rotation() - angle);
2961
+ const s = c.shape;
2962
+ h = mixSignature(h, s.type);
2963
+ h = mixSignature(h, s.radius ?? 0);
2964
+ h = mixSignature(h, s.halfHeight ?? 0);
2965
+ if (s.halfExtents) {
2966
+ h = mixSignature(h, s.halfExtents.x);
2967
+ h = mixSignature(h, s.halfExtents.y);
2968
+ }
2969
+ }
2970
+ return h;
2846
2971
  }
2847
- clone(collection, id, body, parts) {
2972
+ clone(collection, id, body, signature) {
2848
2973
  const live = body;
2849
2974
  this.trackedLive.add(live.handle);
2850
2975
  const made = this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed());
@@ -2852,6 +2977,7 @@ var Rapier2dScratch = class extends BaseScratch {
2852
2977
  const angle = live.rotation();
2853
2978
  const cos = Math.cos(-angle);
2854
2979
  const sin = Math.sin(-angle);
2980
+ const parts = live.numColliders();
2855
2981
  for (let i = 0; i < parts; i++) {
2856
2982
  const c = live.collider(i);
2857
2983
  const desc = new this.rapier.ColliderDesc(c.shape);
@@ -2864,7 +2990,7 @@ var Rapier2dScratch = class extends BaseScratch {
2864
2990
  this.world.createCollider(desc, made);
2865
2991
  }
2866
2992
  this.owners.set(made.handle, { collection, id });
2867
- return { collection, id, body: made, parts, lastLive: -1 };
2993
+ return { collection, id, body: made, signature, lastLive: -1 };
2868
2994
  }
2869
2995
  place(entry, pose) {
2870
2996
  const b = entry.body;
@@ -2926,10 +3052,23 @@ var MatterScratch = class extends BaseScratch {
2926
3052
  super(physics, depth, tickNow);
2927
3053
  this.matter = physics.matter;
2928
3054
  }
2929
- partsOf(body) {
2930
- return body.parts.length;
2931
- }
2932
- clone(collection, id, body, parts) {
3055
+ signatureOf(body) {
3056
+ const live = body;
3057
+ const cos = Math.cos(-live.angle);
3058
+ const sin = Math.sin(-live.angle);
3059
+ let h = mixSignature(0, live.parts.length);
3060
+ for (const p of live.parts) {
3061
+ h = mixSignature(h, p.area);
3062
+ h = mixSignature(h, p.vertices.length);
3063
+ h = mixSignature(h, p.isSensor ? 1 : 0);
3064
+ const dx = p.position.x - live.position.x;
3065
+ const dy = p.position.y - live.position.y;
3066
+ h = mixSignature(h, dx * cos - dy * sin);
3067
+ h = mixSignature(h, dx * sin + dy * cos);
3068
+ }
3069
+ return h;
3070
+ }
3071
+ clone(collection, id, body, signature) {
2933
3072
  const M = this.matter;
2934
3073
  const live = body;
2935
3074
  const made = live.parts.length > 1 ? M.Body.create({ parts: live.parts.slice(1).map((p) => this.clonePart(p, live.angle)) }) : this.clonePart(live, live.angle);
@@ -2937,7 +3076,7 @@ var MatterScratch = class extends BaseScratch {
2937
3076
  made.angle = 0;
2938
3077
  for (const p of made.parts) p.angle = 0;
2939
3078
  this.owners.set(made, { collection, id });
2940
- return { collection, id, body: made, parts, lastLive: -1 };
3079
+ return { collection, id, body: made, signature, lastLive: -1 };
2941
3080
  }
2942
3081
  /** One part, un-rotated by the parent's angle so the double starts at angle 0. */
2943
3082
  clonePart(part, parentAngle) {
@@ -2992,8 +3131,8 @@ var RewindState = class {
2992
3131
  history;
2993
3132
  scratch;
2994
3133
  inside = false;
2995
- constructor(depth) {
2996
- this.history = new PoseHistory(depth);
3134
+ constructor(setup) {
3135
+ this.history = new PoseHistory(setup.depth, setup.channels);
2997
3136
  }
2998
3137
  free() {
2999
3138
  this.scratch?.free();
@@ -3012,7 +3151,29 @@ var RewindState = class {
3012
3151
  );
3013
3152
  }
3014
3153
  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 view = this.scratch.view(resolved.entry, resolved.tick, requested, resolved.clamped);
3154
+ const engineView = this.scratch.view(
3155
+ resolved.entry,
3156
+ resolved.tick,
3157
+ requested,
3158
+ resolved.clamped
3159
+ );
3160
+ const entry = resolved.entry;
3161
+ const history = this.history;
3162
+ const view = {
3163
+ ...engineView,
3164
+ // A linear scan of the entry rather than an index: an entry holds one room's tracked bodies,
3165
+ // and building a map per rewind would cost more than the scan it saved.
3166
+ channels: (collection, id) => {
3167
+ const spec = history.channels.get(collection);
3168
+ if (!spec) return void 0;
3169
+ for (let i = 0; i < entry.count; i++) {
3170
+ if (entry.collections[i] === collection && entry.ids[i] === id) {
3171
+ return channelsAt(entry, i, history.channelStride, spec.count);
3172
+ }
3173
+ }
3174
+ return void 0;
3175
+ }
3176
+ };
3016
3177
  this.inside = true;
3017
3178
  try {
3018
3179
  return fn(view);
@@ -3896,8 +4057,8 @@ var RoomCore = class _RoomCore {
3896
4057
  this.loop = new Loop(self);
3897
4058
  this.api = createRoomApi(self, options.publicUrl ?? DEFAULT_PUBLIC_URL);
3898
4059
  this.physics = this.buildPhysics(restored);
3899
- const historyDepth = this.physics ? historyDepthOf(definition.config.physics) : void 0;
3900
- this.rewindState = historyDepth === void 0 ? void 0 : new RewindState(historyDepth);
4060
+ const historySetup = this.physics ? historyOf(definition.config.physics) : void 0;
4061
+ this.rewindState = historySetup === void 0 ? void 0 : new RewindState(historySetup);
3901
4062
  this.subscribeDeclaredChannels();
3902
4063
  if (restored) {
3903
4064
  const onWake = definition.config.onWake;
@@ -3984,7 +4145,7 @@ var RoomCore = class _RoomCore {
3984
4145
  const engine4 = loadedPhysics();
3985
4146
  if (!engine4) {
3986
4147
  throw new Error(
3987
- "RoomCore: this room declares physics but the engine is not initialized \u2014 the host must `await initPhysics()` (from '@irtio/runtime') before constructing the room; handlers are synchronous, so the WASM cannot be loaded later"
4148
+ "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
4149
  );
3989
4150
  }
3990
4151
  let section;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  parseHibernationBlob,
3
3
  writeHibernationBlob
4
- } from "./chunk-ADZZEVJU.js";
4
+ } from "./chunk-EENJ37KK.js";
5
5
 
6
6
  // src/migrate.ts
7
7
  import { PRESENCE_COLLECTION, withBuiltins } from "@irtio/protocol";
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-C4RZJ2KO.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-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-SBDZ45JG.js";
5
+ } from "./chunk-WNAEE4EP.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-ADZZEVJU.js";
50
+ } from "./chunk-EENJ37KK.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
@@ -1,5 +1,5 @@
1
- import { R as RoomCore } from '../room-C4RZJ2KO.js';
2
- export { m as initMatter, n as initPhysics, o as initRapier2d } from '../room-C4RZJ2KO.js';
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';
@@ -5,7 +5,7 @@ import {
5
5
  initPhysics,
6
6
  initRapier2d,
7
7
  visibleNames
8
- } from "../chunk-ADZZEVJU.js";
8
+ } from "../chunk-EENJ37KK.js";
9
9
 
10
10
  // src/test/clock.ts
11
11
  var FakeClock = class {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  migrateSnapshot
3
- } from "../chunk-SBDZ45JG.js";
3
+ } from "../chunk-WNAEE4EP.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-ADZZEVJU.js";
12
+ } from "../chunk-EENJ37KK.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.9.0",
3
+ "version": "0.10.1",
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/schema": "0.9.0",
35
- "@irtio/server": "0.9.0",
36
- "@irtio/protocol": "0.9.0"
34
+ "@irtio/protocol": "0.10.1",
35
+ "@irtio/schema": "0.10.1",
36
+ "@irtio/server": "0.10.1"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/matter-js": "0.20.2"