@relu-interactives/spatial-ecs 0.2.8 → 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,22 +6158,34 @@ 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);
6155
6184
  }
6185
+ if (instanceCount === 0) {
6186
+ this.geometrySignatures.set(entityId, geometrySignature);
6187
+ continue;
6188
+ }
6156
6189
  if (comp.meshKind === "model") {
6157
6190
  if (comp.modelPath && !this.loadingSignatures.has(entityId)) {
6158
6191
  this.loadingSignatures.set(entityId, geometrySignature);
@@ -6230,6 +6263,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
6230
6263
  currentComp.instancedMesh = group;
6231
6264
  this.modelMeshEntries.set(targetEntityId, entries);
6232
6265
  this.geometrySignatures.set(targetEntityId, targetSignature);
6266
+ this.trackedMeshes.set(targetEntityId, group);
6233
6267
  this.loadingSignatures.delete(targetEntityId);
6234
6268
  }).catch(() => {
6235
6269
  this.loadingSignatures.delete(targetEntityId);
@@ -6237,7 +6271,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
6237
6271
  }
6238
6272
  continue;
6239
6273
  }
6240
- const count = Math.max(1, instanceCount);
6274
+ const count = instanceCount;
6241
6275
  const geometry = buildGeometry(comp);
6242
6276
  const material = new THREE34__namespace.MeshStandardMaterial({ color: "#ffffff" });
6243
6277
  const instancedMesh = new THREE34__namespace.InstancedMesh(geometry, material, count);
@@ -6256,6 +6290,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
6256
6290
  instancedMesh.instanceMatrix.needsUpdate = true;
6257
6291
  anchor.add(instancedMesh);
6258
6292
  comp.instancedMesh = instancedMesh;
6293
+ this.trackedMeshes.set(entityId, instancedMesh);
6259
6294
  this.geometrySignatures.set(entityId, geometrySignature);
6260
6295
  } else {
6261
6296
  if (comp.meshKind === "model") {