@codehz/ecs 0.3.4 → 0.3.5

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.
Files changed (3) hide show
  1. package/index.js +37 -18
  2. package/package.json +1 -1
  3. package/world.d.ts +9 -0
package/index.js CHANGED
@@ -884,6 +884,7 @@ class World {
884
884
  commandBuffer = new CommandBuffer((entityId, commands) => this.executeEntityCommands(entityId, commands));
885
885
  hooks = new Map;
886
886
  exclusiveComponents = new Set;
887
+ cascadeDeleteComponents = new Set;
887
888
  constructor(snapshot) {
888
889
  if (snapshot && typeof snapshot === "object") {
889
890
  if (snapshot.entityManager) {
@@ -953,14 +954,29 @@ class World {
953
954
  return entityId;
954
955
  }
955
956
  destroyEntityImmediate(entityId) {
956
- const archetype = this.entityToArchetype.get(entityId);
957
- if (!archetype) {
958
- return;
959
- }
960
- const componentReferences = this.getEntityReferences(entityId);
961
- for (const [sourceEntityId, componentType] of componentReferences) {
962
- const sourceArchetype = this.entityToArchetype.get(sourceEntityId);
963
- if (sourceArchetype) {
957
+ const queue = [entityId];
958
+ const visited = new Set;
959
+ while (queue.length > 0) {
960
+ const cur = queue.shift();
961
+ if (visited.has(cur))
962
+ continue;
963
+ visited.add(cur);
964
+ const archetype = this.entityToArchetype.get(cur);
965
+ if (!archetype) {
966
+ continue;
967
+ }
968
+ const componentReferences = Array.from(this.getEntityReferences(cur));
969
+ for (const [sourceEntityId, componentType] of componentReferences) {
970
+ const sourceArchetype = this.entityToArchetype.get(sourceEntityId);
971
+ if (!sourceArchetype)
972
+ continue;
973
+ const detailedType = getDetailedIdType(componentType);
974
+ if (detailedType.type === "entity-relation" && this.cascadeDeleteComponents.has(detailedType.componentId)) {
975
+ if (!visited.has(sourceEntityId)) {
976
+ queue.push(sourceEntityId);
977
+ }
978
+ continue;
979
+ }
964
980
  const currentComponents = new Map;
965
981
  let removedComponent = sourceArchetype.get(sourceEntityId, componentType);
966
982
  for (const archetypeComponentType of sourceArchetype.componentTypes) {
@@ -976,17 +992,17 @@ class World {
976
992
  }
977
993
  newArchetype.addEntity(sourceEntityId, currentComponents);
978
994
  this.entityToArchetype.set(sourceEntityId, newArchetype);
979
- this.untrackEntityReference(sourceEntityId, componentType, entityId);
995
+ this.untrackEntityReference(sourceEntityId, componentType, cur);
980
996
  this.triggerLifecycleHooks(sourceEntityId, new Map, new Map([[componentType, removedComponent]]));
981
997
  }
998
+ this.entityReferences.delete(cur);
999
+ archetype.removeEntity(cur);
1000
+ if (archetype.getEntities().length === 0) {
1001
+ this.cleanupEmptyArchetype(archetype);
1002
+ }
1003
+ this.entityToArchetype.delete(cur);
1004
+ this.entityIdManager.deallocate(cur);
982
1005
  }
983
- this.entityReferences.delete(entityId);
984
- archetype.removeEntity(entityId);
985
- if (archetype.getEntities().length === 0) {
986
- this.cleanupEmptyArchetype(archetype);
987
- }
988
- this.entityToArchetype.delete(entityId);
989
- this.entityIdManager.deallocate(entityId);
990
1006
  }
991
1007
  exists(entityId) {
992
1008
  return this.entityToArchetype.has(entityId);
@@ -1066,6 +1082,9 @@ class World {
1066
1082
  setExclusive(componentId) {
1067
1083
  this.exclusiveComponents.add(componentId);
1068
1084
  }
1085
+ setCascadeDelete(componentId) {
1086
+ this.cascadeDeleteComponents.add(componentId);
1087
+ }
1069
1088
  update(...params) {
1070
1089
  const result = this.systemScheduler.update(...params);
1071
1090
  if (result instanceof Promise) {
@@ -1293,14 +1312,14 @@ class World {
1293
1312
  untrackEntityReference(sourceEntityId, componentType, targetEntityId) {
1294
1313
  const references = this.entityReferences.get(targetEntityId);
1295
1314
  if (references) {
1296
- references.get(sourceEntityId).delete(componentType);
1315
+ references.remove(sourceEntityId, componentType);
1297
1316
  if (references.keyCount === 0) {
1298
1317
  this.entityReferences.delete(targetEntityId);
1299
1318
  }
1300
1319
  }
1301
1320
  }
1302
1321
  getEntityReferences(targetEntityId) {
1303
- return this.entityReferences.get(targetEntityId) ?? [];
1322
+ return this.entityReferences.get(targetEntityId) ?? new MultiMap;
1304
1323
  }
1305
1324
  cleanupEmptyArchetype(archetype) {
1306
1325
  if (archetype.getEntities().length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codehz/ecs",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
package/world.d.ts CHANGED
@@ -35,6 +35,8 @@ export declare class World<UpdateParams extends any[] = []> {
35
35
  private hooks;
36
36
  /** Set of component IDs marked as exclusive relations */
37
37
  private exclusiveComponents;
38
+ /** Set of component IDs that will cascade delete when the relation target is deleted */
39
+ private cascadeDeleteComponents;
38
40
  /**
39
41
  * Create a new World.
40
42
  * If an optional snapshot object is provided (previously produced by `world.serialize()`),
@@ -108,6 +110,13 @@ export declare class World<UpdateParams extends any[] = []> {
108
110
  * For exclusive relations, an entity can have at most one relation per base component
109
111
  */
110
112
  setExclusive(componentId: EntityId): void;
113
+ /**
114
+ * Mark a component as cascade-delete relation
115
+ * For cascade relations, when the relation target entity is deleted,
116
+ * the referencing entity will also be deleted (cascade).
117
+ * Only applicable to entity-relation components
118
+ */
119
+ setCascadeDelete(componentId: EntityId): void;
111
120
  /**
112
121
  * Update the world (run all systems in dependency order)
113
122
  * This function is synchronous when all systems are synchronous,