@relu-interactives/spatial-ecs 0.2.9 → 0.2.10

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/index.cjs CHANGED
@@ -306,10 +306,19 @@ function cloneHistoryValue(value, seen = /* @__PURE__ */ new WeakMap()) {
306
306
  return cloneArray;
307
307
  }
308
308
  const prototype = Object.getPrototypeOf(objectValue);
309
+ const constructorName = objectValue.constructor?.name;
309
310
  const shouldCloneWithPrototype = objectValue instanceof Component || prototype === Object.prototype || prototype === null;
310
311
  if (!shouldCloneWithPrototype) {
311
312
  return value;
312
313
  }
314
+ if (constructorName === "InstancedMeshComponent") {
315
+ const cloneObject2 = Object.create(prototype);
316
+ seen.set(objectValue, cloneObject2);
317
+ for (const key of Object.keys(objectValue)) {
318
+ cloneObject2[key] = key === "instancedMesh" ? null : cloneHistoryValue(objectValue[key], seen);
319
+ }
320
+ return cloneObject2;
321
+ }
313
322
  const cloneObject = Object.create(prototype);
314
323
  seen.set(objectValue, cloneObject);
315
324
  for (const key of Object.keys(objectValue)) {
@@ -6113,6 +6122,15 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
6113
6122
  this.loadingSignatures = /* @__PURE__ */ new Map();
6114
6123
  /** Per-mesh data for model kind, populated after GLTF load. */
6115
6124
  this.modelMeshEntries = /* @__PURE__ */ new Map();
6125
+ /**
6126
+ * System-internal ref to the Three.js mesh/group most recently placed on
6127
+ * the anchor by this system. Used for cleanup on rebuild instead of
6128
+ * `comp.instancedMesh`, which can be stale (pointing to a disposed mesh)
6129
+ * after an undo/redo restores a history snapshot captured at an earlier
6130
+ * geometry configuration. Relying on the stale comp ref would skip removal
6131
+ * of the current live mesh → ghost mesh in the scene.
6132
+ */
6133
+ this.trackedMeshes = /* @__PURE__ */ new Map();
6116
6134
  }
6117
6135
  update(world) {
6118
6136
  const entityIds = world.query(InstancedMeshComponent);
@@ -6126,6 +6144,9 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
6126
6144
  for (const trackedId of this.modelMeshEntries.keys()) {
6127
6145
  if (!alive.has(trackedId)) this.modelMeshEntries.delete(trackedId);
6128
6146
  }
6147
+ for (const trackedId of this.trackedMeshes.keys()) {
6148
+ if (!alive.has(trackedId)) this.trackedMeshes.delete(trackedId);
6149
+ }
6129
6150
  for (const entityId of entityIds) {
6130
6151
  const comp = world.getComponent(
6131
6152
  entityId,
@@ -6137,18 +6158,26 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
6137
6158
  if (!anchor) continue;
6138
6159
  const instanceCount = comp.instanceEntityIds.length;
6139
6160
  const geometrySignature = comp.meshKind === "model" ? `model:${comp.modelPath}:${instanceCount}` : `${comp.meshKind}:${JSON.stringify(comp.meshParameters)}:${instanceCount}`;
6161
+ if (comp.instancedMesh === null) {
6162
+ const tracked = this.trackedMeshes.get(entityId);
6163
+ if (tracked) {
6164
+ comp.instancedMesh = tracked;
6165
+ }
6166
+ }
6140
6167
  const pendingLoadSignature = this.loadingSignatures.get(entityId);
6141
- const needsRebuild = (comp.instancedMesh === null || this.geometrySignatures.get(entityId) !== geometrySignature) && pendingLoadSignature !== geometrySignature;
6168
+ const needsRebuild = (!this.trackedMeshes.has(entityId) || this.geometrySignatures.get(entityId) !== geometrySignature) && pendingLoadSignature !== geometrySignature;
6142
6169
  if (needsRebuild) {
6143
- if (comp.instancedMesh) {
6144
- anchor.remove(comp.instancedMesh);
6145
- if (comp.instancedMesh.isInstancedMesh) {
6146
- disposePrimitiveInstancedMesh(comp.instancedMesh);
6170
+ const trackedMesh = this.trackedMeshes.get(entityId);
6171
+ if (trackedMesh) {
6172
+ anchor.remove(trackedMesh);
6173
+ if (trackedMesh.isInstancedMesh) {
6174
+ disposePrimitiveInstancedMesh(trackedMesh);
6147
6175
  } else {
6148
- disposeModelGroup(comp.instancedMesh);
6176
+ disposeModelGroup(trackedMesh);
6149
6177
  }
6150
- comp.instancedMesh = null;
6178
+ this.trackedMeshes.delete(entityId);
6151
6179
  }
6180
+ comp.instancedMesh = null;
6152
6181
  if (pendingLoadSignature !== void 0 && pendingLoadSignature !== geometrySignature) {
6153
6182
  this.loadingSignatures.delete(entityId);
6154
6183
  this.modelMeshEntries.delete(entityId);
@@ -6234,6 +6263,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
6234
6263
  currentComp.instancedMesh = group;
6235
6264
  this.modelMeshEntries.set(targetEntityId, entries);
6236
6265
  this.geometrySignatures.set(targetEntityId, targetSignature);
6266
+ this.trackedMeshes.set(targetEntityId, group);
6237
6267
  this.loadingSignatures.delete(targetEntityId);
6238
6268
  }).catch(() => {
6239
6269
  this.loadingSignatures.delete(targetEntityId);
@@ -6260,6 +6290,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
6260
6290
  instancedMesh.instanceMatrix.needsUpdate = true;
6261
6291
  anchor.add(instancedMesh);
6262
6292
  comp.instancedMesh = instancedMesh;
6293
+ this.trackedMeshes.set(entityId, instancedMesh);
6263
6294
  this.geometrySignatures.set(entityId, geometrySignature);
6264
6295
  } else {
6265
6296
  if (comp.meshKind === "model") {