@codehz/ecs 0.1.2 → 0.1.3

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 +114 -124
  2. package/package.json +1 -1
  3. package/world.d.ts +40 -38
package/index.js CHANGED
@@ -660,64 +660,94 @@ class SystemScheduler {
660
660
  class World {
661
661
  entityIdManager = new EntityIdManager;
662
662
  archetypes = [];
663
- archetypeMap = new Map;
663
+ archetypeBySignature = new Map;
664
664
  entityToArchetype = new Map;
665
- systemScheduler = new SystemScheduler;
665
+ archetypesByComponent = new Map;
666
+ entityReferences = new Map;
666
667
  queries = [];
667
668
  queryCache = new Map;
668
- commandBuffer;
669
- componentToArchetypes = new Map;
669
+ systemScheduler = new SystemScheduler;
670
+ commandBuffer = new CommandBuffer((entityId, commands) => this.executeEntityCommands(entityId, commands));
670
671
  lifecycleHooks = new Map;
671
- entityReverseIndex = new Map;
672
672
  exclusiveComponents = new Set;
673
- constructor(entityIdManager) {
674
- this.entityIdManager = entityIdManager || new EntityIdManager;
675
- this.commandBuffer = new CommandBuffer((entityId, commands) => this.executeEntityCommands(entityId, commands));
673
+ constructor(snapshot) {
674
+ if (snapshot && typeof snapshot === "object") {
675
+ if (snapshot.entityManager) {
676
+ this.entityIdManager.deserializeState(snapshot.entityManager);
677
+ }
678
+ if (Array.isArray(snapshot.exclusiveComponents)) {
679
+ for (const id of snapshot.exclusiveComponents) {
680
+ this.exclusiveComponents.add(id);
681
+ }
682
+ }
683
+ if (Array.isArray(snapshot.entities)) {
684
+ for (const entry of snapshot.entities) {
685
+ const entityId = entry.id;
686
+ const componentsArray = entry.components || [];
687
+ const componentMap = new Map;
688
+ const componentTypes = [];
689
+ for (const componentEntry of componentsArray) {
690
+ componentMap.set(componentEntry.type, componentEntry.value);
691
+ componentTypes.push(componentEntry.type);
692
+ }
693
+ const archetype = this.ensureArchetype(componentTypes);
694
+ archetype.addEntity(entityId, componentMap);
695
+ this.entityToArchetype.set(entityId, archetype);
696
+ for (const compType of componentTypes) {
697
+ const detailedType = getDetailedIdType(compType);
698
+ if (detailedType.type === "entity-relation") {
699
+ const targetEntityId = detailedType.targetId;
700
+ this.trackEntityReference(entityId, compType, targetEntityId);
701
+ } else if (detailedType.type === "entity") {
702
+ this.trackEntityReference(entityId, compType, compType);
703
+ }
704
+ }
705
+ }
706
+ }
707
+ }
676
708
  }
677
- getComponentTypesHash(componentTypes) {
709
+ createArchetypeSignature(componentTypes) {
678
710
  return componentTypes.join(",");
679
711
  }
680
712
  new() {
681
713
  const entityId = this.entityIdManager.allocate();
682
- let emptyArchetype = this.getOrCreateArchetype([]);
714
+ let emptyArchetype = this.ensureArchetype([]);
683
715
  emptyArchetype.addEntity(entityId, new Map);
684
716
  this.entityToArchetype.set(entityId, emptyArchetype);
685
717
  return entityId;
686
718
  }
687
- _destroyEntity(entityId) {
719
+ destroyEntityImmediate(entityId) {
688
720
  const archetype = this.entityToArchetype.get(entityId);
689
721
  if (!archetype) {
690
722
  return;
691
723
  }
692
- const componentReferences = this.getComponentReferences(entityId);
724
+ const componentReferences = this.getEntityReferences(entityId);
693
725
  for (const { sourceEntityId, componentType } of componentReferences) {
694
726
  const sourceArchetype = this.entityToArchetype.get(sourceEntityId);
695
727
  if (sourceArchetype) {
696
728
  const currentComponents = new Map;
697
- for (const compType of sourceArchetype.componentTypes) {
698
- if (compType !== componentType) {
699
- const data = sourceArchetype.get(sourceEntityId, compType);
700
- if (data !== undefined) {
701
- currentComponents.set(compType, data);
702
- }
729
+ for (const archetypeComponentType of sourceArchetype.componentTypes) {
730
+ if (archetypeComponentType !== componentType) {
731
+ const componentData = sourceArchetype.get(sourceEntityId, archetypeComponentType);
732
+ currentComponents.set(archetypeComponentType, componentData);
703
733
  }
704
734
  }
705
735
  const newComponentTypes = Array.from(currentComponents.keys()).sort((a, b) => a - b);
706
- const newArchetype = this.getOrCreateArchetype(newComponentTypes);
736
+ const newArchetype = this.ensureArchetype(newComponentTypes);
707
737
  sourceArchetype.removeEntity(sourceEntityId);
708
738
  if (sourceArchetype.getEntities().length === 0) {
709
- this.removeEmptyArchetype(sourceArchetype);
739
+ this.cleanupEmptyArchetype(sourceArchetype);
710
740
  }
711
741
  newArchetype.addEntity(sourceEntityId, currentComponents);
712
742
  this.entityToArchetype.set(sourceEntityId, newArchetype);
713
- this.removeComponentReference(sourceEntityId, componentType, entityId);
714
- this.executeComponentLifecycleHooks(sourceEntityId, new Map, new Set([componentType]));
743
+ this.untrackEntityReference(sourceEntityId, componentType, entityId);
744
+ this.triggerLifecycleHooks(sourceEntityId, new Map, new Set([componentType]));
715
745
  }
716
746
  }
717
- this.entityReverseIndex.delete(entityId);
747
+ this.entityReferences.delete(entityId);
718
748
  archetype.removeEntity(entityId);
719
749
  if (archetype.getEntities().length === 0) {
720
- this.removeEmptyArchetype(archetype);
750
+ this.cleanupEmptyArchetype(archetype);
721
751
  }
722
752
  this.entityToArchetype.delete(entityId);
723
753
  this.entityIdManager.deallocate(entityId);
@@ -796,7 +826,7 @@ class World {
796
826
  createQuery(componentTypes, filter = {}) {
797
827
  const sortedTypes = [...componentTypes].sort((a, b) => a - b);
798
828
  const filterKey = serializeQueryFilter(filter);
799
- const key = `${this.getComponentTypesHash(sortedTypes)}${filterKey ? `|${filterKey}` : ""}`;
829
+ const key = `${this.createArchetypeSignature(sortedTypes)}${filterKey ? `|${filterKey}` : ""}`;
800
830
  const cached = this.queryCache.get(key);
801
831
  if (cached) {
802
832
  cached.refCount++;
@@ -844,15 +874,15 @@ class World {
844
874
  }
845
875
  const regularComponents = [];
846
876
  const wildcardRelations = [];
847
- for (const type of componentTypes) {
848
- const detailedType = getDetailedIdType(type);
877
+ for (const componentType of componentTypes) {
878
+ const detailedType = getDetailedIdType(componentType);
849
879
  if (detailedType.type === "wildcard-relation") {
850
880
  wildcardRelations.push({
851
881
  componentId: detailedType.componentId,
852
- relationId: type
882
+ relationId: componentType
853
883
  });
854
884
  } else {
855
- regularComponents.push(type);
885
+ regularComponents.push(componentType);
856
886
  }
857
887
  }
858
888
  let matchingArchetypes = [];
@@ -860,15 +890,15 @@ class World {
860
890
  const sortedRegularTypes = [...regularComponents].sort((a, b) => a - b);
861
891
  if (sortedRegularTypes.length === 1) {
862
892
  const componentType = sortedRegularTypes[0];
863
- matchingArchetypes = this.componentToArchetypes.get(componentType) || [];
893
+ matchingArchetypes = this.archetypesByComponent.get(componentType) || [];
864
894
  } else {
865
- const archetypeLists = sortedRegularTypes.map((type) => this.componentToArchetypes.get(type) || []);
895
+ const archetypeLists = sortedRegularTypes.map((type) => this.archetypesByComponent.get(type) || []);
866
896
  const firstList = archetypeLists[0] || [];
867
897
  const intersection = new Set;
868
898
  for (const archetype of firstList) {
869
899
  let hasAllComponents = true;
870
- for (let i = 1;i < archetypeLists.length; i++) {
871
- const otherList = archetypeLists[i];
900
+ for (let listIndex = 1;listIndex < archetypeLists.length; listIndex++) {
901
+ const otherList = archetypeLists[listIndex];
872
902
  if (!otherList.includes(archetype)) {
873
903
  hasAllComponents = false;
874
904
  break;
@@ -884,12 +914,12 @@ class World {
884
914
  matchingArchetypes = [...this.archetypes];
885
915
  }
886
916
  for (const wildcard of wildcardRelations) {
887
- const componentArchetypes = this.componentToArchetypes.get(wildcard.componentId) || [];
917
+ const componentArchetypes = this.archetypesByComponent.get(wildcard.componentId) || [];
888
918
  matchingArchetypes = matchingArchetypes.filter((archetype) => componentArchetypes.includes(archetype));
889
919
  }
890
920
  return matchingArchetypes;
891
921
  }
892
- queryEntities(componentTypes, includeComponents) {
922
+ query(componentTypes, includeComponents) {
893
923
  const matchingArchetypes = this.getMatchingArchetypes(componentTypes);
894
924
  if (includeComponents) {
895
925
  const result = [];
@@ -910,7 +940,7 @@ class World {
910
940
  const changeset = new ComponentChangeset;
911
941
  const hasDestroy = commands.some((cmd) => cmd.type === "destroy");
912
942
  if (hasDestroy) {
913
- this._destroyEntity(entityId);
943
+ this.destroyEntityImmediate(entityId);
914
944
  return changeset;
915
945
  }
916
946
  const currentArchetype = this.entityToArchetype.get(entityId);
@@ -919,14 +949,14 @@ class World {
919
949
  }
920
950
  const currentComponents = new Map;
921
951
  for (const componentType of currentArchetype.componentTypes) {
922
- const data = currentArchetype.get(entityId, componentType);
923
- currentComponents.set(componentType, data);
952
+ const componentData = currentArchetype.get(entityId, componentType);
953
+ currentComponents.set(componentType, componentData);
924
954
  }
925
- for (const cmd of commands) {
926
- switch (cmd.type) {
955
+ for (const command of commands) {
956
+ switch (command.type) {
927
957
  case "set":
928
- if (cmd.componentType) {
929
- const detailedType = getDetailedIdType(cmd.componentType);
958
+ if (command.componentType) {
959
+ const detailedType = getDetailedIdType(command.componentType);
930
960
  if ((detailedType.type === "entity-relation" || detailedType.type === "component-relation") && this.exclusiveComponents.has(detailedType.componentId)) {
931
961
  for (const componentType of currentArchetype.componentTypes) {
932
962
  const componentDetailedType = getDetailedIdType(componentType);
@@ -935,12 +965,12 @@ class World {
935
965
  }
936
966
  }
937
967
  }
938
- changeset.set(cmd.componentType, cmd.component);
968
+ changeset.set(command.componentType, command.component);
939
969
  }
940
970
  break;
941
971
  case "delete":
942
- if (cmd.componentType) {
943
- const detailedType = getDetailedIdType(cmd.componentType);
972
+ if (command.componentType) {
973
+ const detailedType = getDetailedIdType(command.componentType);
944
974
  if (detailedType.type === "wildcard-relation") {
945
975
  const baseComponentId = detailedType.componentId;
946
976
  for (const componentType of currentArchetype.componentTypes) {
@@ -952,7 +982,7 @@ class World {
952
982
  }
953
983
  }
954
984
  } else {
955
- changeset.delete(cmd.componentType);
985
+ changeset.delete(command.componentType);
956
986
  }
957
987
  }
958
988
  break;
@@ -963,7 +993,7 @@ class World {
963
993
  const currentComponentTypes = currentArchetype.componentTypes.sort((a, b) => a - b);
964
994
  const needsArchetypeChange = finalComponentTypes.length !== currentComponentTypes.length || !finalComponentTypes.every((type, index) => type === currentComponentTypes[index]);
965
995
  if (needsArchetypeChange) {
966
- const newArchetype = this.getOrCreateArchetype(finalComponentTypes);
996
+ const newArchetype = this.ensureArchetype(finalComponentTypes);
967
997
  currentArchetype.removeEntity(entityId);
968
998
  newArchetype.addEntity(entityId, finalComponents);
969
999
  this.entityToArchetype.set(entityId, newArchetype);
@@ -976,33 +1006,33 @@ class World {
976
1006
  const detailedType = getDetailedIdType(componentType);
977
1007
  if (detailedType.type === "entity-relation") {
978
1008
  const targetEntityId = detailedType.targetId;
979
- this.removeComponentReference(entityId, componentType, targetEntityId);
1009
+ this.untrackEntityReference(entityId, componentType, targetEntityId);
980
1010
  } else if (detailedType.type === "entity") {
981
- this.removeComponentReference(entityId, componentType, componentType);
1011
+ this.untrackEntityReference(entityId, componentType, componentType);
982
1012
  }
983
1013
  }
984
1014
  for (const [componentType, component2] of changeset.adds) {
985
1015
  const detailedType = getDetailedIdType(componentType);
986
1016
  if (detailedType.type === "entity-relation") {
987
1017
  const targetEntityId = detailedType.targetId;
988
- this.addComponentReference(entityId, componentType, targetEntityId);
1018
+ this.trackEntityReference(entityId, componentType, targetEntityId);
989
1019
  } else if (detailedType.type === "entity") {
990
- this.addComponentReference(entityId, componentType, componentType);
1020
+ this.trackEntityReference(entityId, componentType, componentType);
991
1021
  }
992
1022
  }
993
- this.executeComponentLifecycleHooks(entityId, changeset.adds, changeset.removes);
1023
+ this.triggerLifecycleHooks(entityId, changeset.adds, changeset.removes);
994
1024
  return changeset;
995
1025
  }
996
- getOrCreateArchetype(componentTypes) {
1026
+ ensureArchetype(componentTypes) {
997
1027
  const sortedTypes = [...componentTypes].sort((a, b) => a - b);
998
- const hashKey = this.getComponentTypesHash(sortedTypes);
999
- return getOrCreateWithSideEffect(this.archetypeMap, hashKey, () => {
1028
+ const hashKey = this.createArchetypeSignature(sortedTypes);
1029
+ return getOrCreateWithSideEffect(this.archetypeBySignature, hashKey, () => {
1000
1030
  const newArchetype = new Archetype(sortedTypes);
1001
1031
  this.archetypes.push(newArchetype);
1002
1032
  for (const componentType of sortedTypes) {
1003
- const archetypes = this.componentToArchetypes.get(componentType) || [];
1033
+ const archetypes = this.archetypesByComponent.get(componentType) || [];
1004
1034
  archetypes.push(newArchetype);
1005
- this.componentToArchetypes.set(componentType, archetypes);
1035
+ this.archetypesByComponent.set(componentType, archetypes);
1006
1036
  }
1007
1037
  for (const query of this.queries) {
1008
1038
  query.checkNewArchetype(newArchetype);
@@ -1010,30 +1040,30 @@ class World {
1010
1040
  return newArchetype;
1011
1041
  });
1012
1042
  }
1013
- addComponentReference(sourceEntityId, componentType, targetEntityId) {
1014
- if (!this.entityReverseIndex.has(targetEntityId)) {
1015
- this.entityReverseIndex.set(targetEntityId, new Set);
1043
+ trackEntityReference(sourceEntityId, componentType, targetEntityId) {
1044
+ if (!this.entityReferences.has(targetEntityId)) {
1045
+ this.entityReferences.set(targetEntityId, new Set);
1016
1046
  }
1017
- this.entityReverseIndex.get(targetEntityId).add({ sourceEntityId, componentType });
1047
+ this.entityReferences.get(targetEntityId).add({ sourceEntityId, componentType });
1018
1048
  }
1019
- removeComponentReference(sourceEntityId, componentType, targetEntityId) {
1020
- const references = this.entityReverseIndex.get(targetEntityId);
1049
+ untrackEntityReference(sourceEntityId, componentType, targetEntityId) {
1050
+ const references = this.entityReferences.get(targetEntityId);
1021
1051
  if (references) {
1022
- references.forEach((ref) => {
1023
- if (ref.sourceEntityId === sourceEntityId && ref.componentType === componentType) {
1024
- references.delete(ref);
1052
+ references.forEach((reference) => {
1053
+ if (reference.sourceEntityId === sourceEntityId && reference.componentType === componentType) {
1054
+ references.delete(reference);
1025
1055
  }
1026
1056
  });
1027
1057
  if (references.size === 0) {
1028
- this.entityReverseIndex.delete(targetEntityId);
1058
+ this.entityReferences.delete(targetEntityId);
1029
1059
  }
1030
1060
  }
1031
1061
  }
1032
- getComponentReferences(targetEntityId) {
1033
- const references = this.entityReverseIndex.get(targetEntityId);
1062
+ getEntityReferences(targetEntityId) {
1063
+ const references = this.entityReferences.get(targetEntityId);
1034
1064
  return references ? Array.from(references) : [];
1035
1065
  }
1036
- removeEmptyArchetype(archetype) {
1066
+ cleanupEmptyArchetype(archetype) {
1037
1067
  if (archetype.getEntities().length > 0) {
1038
1068
  return;
1039
1069
  }
@@ -1041,28 +1071,28 @@ class World {
1041
1071
  if (index !== -1) {
1042
1072
  this.archetypes.splice(index, 1);
1043
1073
  }
1044
- const hashKey = this.getComponentTypesHash(archetype.componentTypes);
1045
- this.archetypeMap.delete(hashKey);
1074
+ const hashKey = this.createArchetypeSignature(archetype.componentTypes);
1075
+ this.archetypeBySignature.delete(hashKey);
1046
1076
  for (const componentType of archetype.componentTypes) {
1047
- const archetypes = this.componentToArchetypes.get(componentType);
1077
+ const archetypes = this.archetypesByComponent.get(componentType);
1048
1078
  if (archetypes) {
1049
1079
  const compIndex = archetypes.indexOf(archetype);
1050
1080
  if (compIndex !== -1) {
1051
1081
  archetypes.splice(compIndex, 1);
1052
1082
  if (archetypes.length === 0) {
1053
- this.componentToArchetypes.delete(componentType);
1083
+ this.archetypesByComponent.delete(componentType);
1054
1084
  }
1055
1085
  }
1056
1086
  }
1057
1087
  }
1058
1088
  }
1059
- executeComponentLifecycleHooks(entityId, addedComponents, removedComponents) {
1089
+ triggerLifecycleHooks(entityId, addedComponents, removedComponents) {
1060
1090
  for (const [componentType, component2] of addedComponents) {
1061
1091
  const directHooks = this.lifecycleHooks.get(componentType);
1062
1092
  if (directHooks) {
1063
- for (const hook of directHooks) {
1064
- if (hook.onAdded) {
1065
- hook.onAdded(entityId, componentType, component2);
1093
+ for (const lifecycleHook of directHooks) {
1094
+ if (lifecycleHook.onAdded) {
1095
+ lifecycleHook.onAdded(entityId, componentType, component2);
1066
1096
  }
1067
1097
  }
1068
1098
  }
@@ -1071,9 +1101,9 @@ class World {
1071
1101
  const wildcardRelationId = relation(detailedType.componentId, "*");
1072
1102
  const wildcardHooks = this.lifecycleHooks.get(wildcardRelationId);
1073
1103
  if (wildcardHooks) {
1074
- for (const hook of wildcardHooks) {
1075
- if (hook.onAdded) {
1076
- hook.onAdded(entityId, componentType, component2);
1104
+ for (const lifecycleHook of wildcardHooks) {
1105
+ if (lifecycleHook.onAdded) {
1106
+ lifecycleHook.onAdded(entityId, componentType, component2);
1077
1107
  }
1078
1108
  }
1079
1109
  }
@@ -1082,9 +1112,9 @@ class World {
1082
1112
  for (const componentType of removedComponents) {
1083
1113
  const directHooks = this.lifecycleHooks.get(componentType);
1084
1114
  if (directHooks) {
1085
- for (const hook of directHooks) {
1086
- if (hook.onRemoved) {
1087
- hook.onRemoved(entityId, componentType);
1115
+ for (const lifecycleHook of directHooks) {
1116
+ if (lifecycleHook.onRemoved) {
1117
+ lifecycleHook.onRemoved(entityId, componentType);
1088
1118
  }
1089
1119
  }
1090
1120
  }
@@ -1119,46 +1149,6 @@ class World {
1119
1149
  entities
1120
1150
  };
1121
1151
  }
1122
- static deserialize(obj) {
1123
- if (!obj || typeof obj !== "object") {
1124
- throw new Error("World.deserialize expects a snapshot object (not a JSON string)");
1125
- }
1126
- const entityManager = new EntityIdManager;
1127
- if (obj && obj.entityManager) {
1128
- entityManager.deserializeState(obj.entityManager);
1129
- }
1130
- const world = new World(entityManager);
1131
- if (obj && Array.isArray(obj.exclusiveComponents)) {
1132
- for (const id of obj.exclusiveComponents) {
1133
- world.exclusiveComponents.add(id);
1134
- }
1135
- }
1136
- if (obj && Array.isArray(obj.entities)) {
1137
- for (const entry of obj.entities) {
1138
- const entityId = entry.id;
1139
- const componentsArray = entry.components || [];
1140
- const componentMap = new Map;
1141
- const componentTypes = [];
1142
- for (const c of componentsArray) {
1143
- componentMap.set(c.type, c.value);
1144
- componentTypes.push(c.type);
1145
- }
1146
- const archetype = world.getOrCreateArchetype(componentTypes);
1147
- archetype.addEntity(entityId, componentMap);
1148
- world.entityToArchetype.set(entityId, archetype);
1149
- for (const compType of componentTypes) {
1150
- const detailedType = getDetailedIdType(compType);
1151
- if (detailedType.type === "entity-relation") {
1152
- const targetEntityId = detailedType.targetId;
1153
- world.addComponentReference(entityId, compType, targetEntityId);
1154
- } else if (detailedType.type === "entity") {
1155
- world.addComponentReference(entityId, compType, compType);
1156
- }
1157
- }
1158
- }
1159
- }
1160
- return world;
1161
- }
1162
1152
  }
1163
1153
  export {
1164
1154
  relation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codehz/ecs",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
package/world.d.ts CHANGED
@@ -2,7 +2,6 @@ import { Archetype } from "./archetype";
2
2
  import { ComponentChangeset } from "./changeset";
3
3
  import { type Command } from "./command-buffer";
4
4
  import type { EntityId, WildcardRelationId } from "./entity";
5
- import { EntityIdManager } from "./entity";
6
5
  import { Query } from "./query";
7
6
  import { type QueryFilter } from "./query-filter";
8
7
  import type { System } from "./system";
@@ -12,43 +11,50 @@ import type { ComponentTuple, LifecycleHook } from "./types";
12
11
  * Manages entities, components, and systems
13
12
  */
14
13
  export declare class World<UpdateParams extends any[] = []> {
14
+ /** Manages allocation and deallocation of entity IDs */
15
15
  private entityIdManager;
16
+ /** Array of all archetypes in the world */
16
17
  private archetypes;
17
- private archetypeMap;
18
+ /** Maps archetype signatures (component type signatures) to archetype instances */
19
+ private archetypeBySignature;
20
+ /** Maps entity IDs to their current archetype */
18
21
  private entityToArchetype;
19
- private systemScheduler;
22
+ /** Maps component types to arrays of archetypes that contain them */
23
+ private archetypesByComponent;
24
+ /** Tracks which entities reference each entity as a component type */
25
+ private entityReferences;
26
+ /** Array of all active queries for archetype change notifications */
20
27
  private queries;
28
+ /** Cache for queries keyed by component types and filter signatures */
21
29
  private queryCache;
30
+ /** Schedules and executes systems in dependency order */
31
+ private systemScheduler;
32
+ /** Buffers structural changes for deferred execution */
22
33
  private commandBuffer;
23
- private componentToArchetypes;
24
- /**
25
- * Hook storage for component and wildcard relation lifecycle events
26
- */
34
+ /** Stores lifecycle hooks for component and relation events */
27
35
  private lifecycleHooks;
36
+ /** Set of component IDs marked as exclusive relations */
37
+ private exclusiveComponents;
28
38
  /**
29
- * Reverse index tracking which entities use each entity as a component type
30
- * Maps entity ID to set of {sourceEntityId, componentType} pairs where componentType uses this entity
31
- * This includes both relation components and direct usage of entities as component types
39
+ * Create a new World.
40
+ * If an optional snapshot object is provided (previously produced by `world.serialize()`),
41
+ * the world will be restored from that snapshot. The snapshot may contain non-JSON values.
32
42
  */
33
- private entityReverseIndex;
43
+ constructor(snapshot?: any);
34
44
  /**
35
- * Set of component IDs that are marked as exclusive relations
36
- * For exclusive relations, an entity can have at most one relation per base component
45
+ * Generate a signature string for component types array
46
+ * @returns A string signature for the component types
37
47
  */
38
- private exclusiveComponents;
39
- constructor(entityIdManager?: EntityIdManager);
40
- /**
41
- * Generate a hash key for component types array
42
- */
43
- private getComponentTypesHash;
48
+ private createArchetypeSignature;
44
49
  /**
45
50
  * Create a new entity
51
+ * @returns The ID of the newly created entity
46
52
  */
47
53
  new(): EntityId;
48
54
  /**
49
55
  * Destroy an entity and remove all its components (immediate execution)
50
56
  */
51
- private _destroyEntity;
57
+ private destroyEntityImmediate;
52
58
  /**
53
59
  * Check if an entity exists
54
60
  */
@@ -75,12 +81,14 @@ export declare class World<UpdateParams extends any[] = []> {
75
81
  * Returns an array of all matching relation instances
76
82
  * @param entityId The entity
77
83
  * @param componentType The wildcard relation type
84
+ * @returns Array of [targetEntityId, componentData] pairs for all matching relations
78
85
  */
79
86
  get<T>(entityId: EntityId, componentType: WildcardRelationId<T>): [EntityId<unknown>, T][];
80
87
  /**
81
88
  * Get component data for a specific entity and component type
82
89
  * @param entityId The entity
83
90
  * @param componentType The component type
91
+ * @returns The component data
84
92
  */
85
93
  get<T>(entityId: EntityId, componentType: EntityId<T>): T;
86
94
  /**
@@ -110,6 +118,7 @@ export declare class World<UpdateParams extends any[] = []> {
110
118
  sync(): void;
111
119
  /**
112
120
  * Create a cached query for efficient entity lookups
121
+ * @returns A Query object for the specified component types and filter
113
122
  */
114
123
  createQuery(componentTypes: EntityId<any>[], filter?: QueryFilter): Query;
115
124
  /**
@@ -131,62 +140,55 @@ export declare class World<UpdateParams extends any[] = []> {
131
140
  getMatchingArchetypes(componentTypes: EntityId<any>[]): Archetype[];
132
141
  /**
133
142
  * Query entities with specific components
143
+ * @returns Array of entity IDs that have all the specified components
134
144
  */
135
- queryEntities(componentTypes: EntityId<any>[]): EntityId[];
136
- queryEntities<const T extends readonly EntityId<any>[]>(componentTypes: T, includeComponents: true): Array<{
145
+ query(componentTypes: EntityId<any>[]): EntityId[];
146
+ query<const T extends readonly EntityId<any>[]>(componentTypes: T, includeComponents: true): Array<{
137
147
  entity: EntityId;
138
148
  components: ComponentTuple<T>;
139
149
  }>;
140
150
  /**
141
151
  * @internal Execute commands for a single entity (for internal use by CommandBuffer)
152
+ * @returns ComponentChangeset describing the changes made
142
153
  */
143
154
  executeEntityCommands(entityId: EntityId, commands: Command[]): ComponentChangeset;
144
155
  /**
145
156
  * Get or create an archetype for the given component types
157
+ * @returns The archetype for the given component types
146
158
  */
147
- private getOrCreateArchetype;
159
+ private ensureArchetype;
148
160
  /**
149
161
  * Add a component reference to the reverse index when an entity is used as a component type
150
162
  * @param sourceEntityId The entity that has the component
151
163
  * @param componentType The component type (which may be an entity ID used as component type)
152
164
  * @param targetEntityId The entity being used as component type
153
165
  */
154
- private addComponentReference;
166
+ private trackEntityReference;
155
167
  /**
156
168
  * Remove a component reference from the reverse index
157
169
  * @param sourceEntityId The entity that has the component
158
170
  * @param componentType The component type
159
171
  * @param targetEntityId The entity being used as component type
160
172
  */
161
- private removeComponentReference;
173
+ private untrackEntityReference;
162
174
  /**
163
175
  * Get all component references where a target entity is used as a component type
164
176
  * @param targetEntityId The target entity
165
177
  * @returns Array of {sourceEntityId, componentType} pairs
166
178
  */
167
- private getComponentReferences;
179
+ private getEntityReferences;
168
180
  /**
169
181
  * Remove an empty archetype from all internal data structures
170
182
  */
171
- private removeEmptyArchetype;
183
+ private cleanupEmptyArchetype;
172
184
  /**
173
185
  * Execute component lifecycle hooks for added and removed components
174
186
  */
175
- private executeComponentLifecycleHooks;
176
- /**
177
- * Convert the world into a plain JSON-serializable object.
178
- * Note: component values must be JSON-serializable by the caller.
179
- */
187
+ private triggerLifecycleHooks;
180
188
  /**
181
189
  * Convert the world into a plain snapshot object.
182
190
  * This returns an in-memory structure and does not perform JSON stringification.
183
191
  * Component values are stored as-is (they may be non-JSON-serializable).
184
192
  */
185
193
  serialize(): any;
186
- /**
187
- * Deserialize a world from a previously-created snapshot object.
188
- * The snapshot must have been produced by `world.serialize()` and may contain
189
- * non-JSON values (they will be copied by reference).
190
- */
191
- static deserialize<T extends any[] = []>(obj: any): World<T>;
192
194
  }