@irtio/runtime 0.10.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.
@@ -2715,6 +2715,9 @@ function keyOf(collection, id) {
2715
2715
  function angleOf(qz, qw) {
2716
2716
  return 2 * Math.atan2(qz, qw);
2717
2717
  }
2718
+ function mixSignature(h, v) {
2719
+ return Math.imul(h ^ (Math.round(v * 1024) | 0), 2654435761);
2720
+ }
2718
2721
  var BaseScratch = class {
2719
2722
  constructor(physics, depth, tickNow) {
2720
2723
  this.physics = physics;
@@ -2745,7 +2748,8 @@ var BaseScratch = class {
2745
2748
  }
2746
2749
  /**
2747
2750
  * Brings the scratch's body set in step with the live world: a double for every live body that
2748
- * 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
2749
2753
  * has been gone longer than the history is deep and so can no longer appear in any entry.
2750
2754
  *
2751
2755
  * The prune is conservative rather than exact: `lastLive` only advances when a rewind happens,
@@ -2758,9 +2762,9 @@ var BaseScratch = class {
2758
2762
  this.physics.eachTrackedBody((collection, id, body) => {
2759
2763
  const key = keyOf(collection, id);
2760
2764
  seen.add(key);
2761
- const parts = this.partsOf(body);
2765
+ const signature = this.signatureOf(body);
2762
2766
  const existing = this.bodies.get(key);
2763
- if (existing && existing.parts === parts) {
2767
+ if (existing && existing.signature === signature) {
2764
2768
  existing.lastLive = now;
2765
2769
  return;
2766
2770
  }
@@ -2768,7 +2772,7 @@ var BaseScratch = class {
2768
2772
  this.bodies.delete(key);
2769
2773
  this.destroy(existing);
2770
2774
  }
2771
- const made = this.clone(collection, id, body, parts);
2775
+ const made = this.clone(collection, id, body, signature);
2772
2776
  if (!made) return;
2773
2777
  made.lastLive = now;
2774
2778
  this.bodies.set(key, made);
@@ -2809,16 +2813,46 @@ var RapierScratch = class extends BaseScratch {
2809
2813
  this.world = new this.rapier.World({ x: 0, y: 0, z: 0 });
2810
2814
  this.world.timestep = 0;
2811
2815
  }
2812
- partsOf(body) {
2813
- 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;
2814
2847
  }
2815
- clone(collection, id, body, parts) {
2848
+ clone(collection, id, body, signature) {
2816
2849
  const live = body;
2817
2850
  this.trackedLive.add(live.handle);
2818
2851
  const made = this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed());
2819
2852
  const origin = live.translation();
2820
2853
  const rot = live.rotation();
2821
2854
  const inv = qConj(rot);
2855
+ const parts = live.numColliders();
2822
2856
  for (let i = 0; i < parts; i++) {
2823
2857
  const c = live.collider(i);
2824
2858
  const desc = new this.rapier.ColliderDesc(c.shape);
@@ -2830,7 +2864,7 @@ var RapierScratch = class extends BaseScratch {
2830
2864
  this.world.createCollider(desc, made);
2831
2865
  }
2832
2866
  this.owners.set(made.handle, { collection, id });
2833
- return { collection, id, body: made, parts, lastLive: -1 };
2867
+ return { collection, id, body: made, signature, lastLive: -1 };
2834
2868
  }
2835
2869
  place(entry, pose) {
2836
2870
  const b = entry.body;
@@ -2906,10 +2940,36 @@ var Rapier2dScratch = class extends BaseScratch {
2906
2940
  this.world = new this.rapier.World({ x: 0, y: 0 });
2907
2941
  this.world.timestep = 0;
2908
2942
  }
2909
- partsOf(body) {
2910
- 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;
2911
2971
  }
2912
- clone(collection, id, body, parts) {
2972
+ clone(collection, id, body, signature) {
2913
2973
  const live = body;
2914
2974
  this.trackedLive.add(live.handle);
2915
2975
  const made = this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed());
@@ -2917,6 +2977,7 @@ var Rapier2dScratch = class extends BaseScratch {
2917
2977
  const angle = live.rotation();
2918
2978
  const cos = Math.cos(-angle);
2919
2979
  const sin = Math.sin(-angle);
2980
+ const parts = live.numColliders();
2920
2981
  for (let i = 0; i < parts; i++) {
2921
2982
  const c = live.collider(i);
2922
2983
  const desc = new this.rapier.ColliderDesc(c.shape);
@@ -2929,7 +2990,7 @@ var Rapier2dScratch = class extends BaseScratch {
2929
2990
  this.world.createCollider(desc, made);
2930
2991
  }
2931
2992
  this.owners.set(made.handle, { collection, id });
2932
- return { collection, id, body: made, parts, lastLive: -1 };
2993
+ return { collection, id, body: made, signature, lastLive: -1 };
2933
2994
  }
2934
2995
  place(entry, pose) {
2935
2996
  const b = entry.body;
@@ -2991,10 +3052,23 @@ var MatterScratch = class extends BaseScratch {
2991
3052
  super(physics, depth, tickNow);
2992
3053
  this.matter = physics.matter;
2993
3054
  }
2994
- partsOf(body) {
2995
- return body.parts.length;
2996
- }
2997
- 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) {
2998
3072
  const M = this.matter;
2999
3073
  const live = body;
3000
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);
@@ -3002,7 +3076,7 @@ var MatterScratch = class extends BaseScratch {
3002
3076
  made.angle = 0;
3003
3077
  for (const p of made.parts) p.angle = 0;
3004
3078
  this.owners.set(made, { collection, id });
3005
- return { collection, id, body: made, parts, lastLive: -1 };
3079
+ return { collection, id, body: made, signature, lastLive: -1 };
3006
3080
  }
3007
3081
  /** One part, un-rotated by the parent's angle so the double starts at angle 0. */
3008
3082
  clonePart(part, parentAngle) {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  parseHibernationBlob,
3
3
  writeHibernationBlob
4
- } from "./chunk-KGZEQTJR.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.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  fromMigrationState,
3
3
  migrateSnapshot,
4
4
  toMigrationState
5
- } from "./chunk-MTBMGUGG.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-KGZEQTJR.js";
50
+ } from "./chunk-EENJ37KK.js";
51
51
  export {
52
52
  CRASH_AFTER_THROWS,
53
53
  DEFAULT_TIMELINE_MAX_RECORDS,
@@ -5,7 +5,7 @@ import {
5
5
  initPhysics,
6
6
  initRapier2d,
7
7
  visibleNames
8
- } from "../chunk-KGZEQTJR.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-MTBMGUGG.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-KGZEQTJR.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.10.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/protocol": "0.10.0",
35
- "@irtio/schema": "0.10.0",
36
- "@irtio/server": "0.10.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"