@codehz/ecs 0.3.2 → 0.3.4

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/index.js CHANGED
@@ -594,6 +594,86 @@ class CommandBuffer {
594
594
  }
595
595
  }
596
596
 
597
+ // src/multi-map.ts
598
+ class MultiMap {
599
+ map = new Map;
600
+ _valueCount = 0;
601
+ get valueCount() {
602
+ return this._valueCount;
603
+ }
604
+ get keyCount() {
605
+ return this.map.size;
606
+ }
607
+ hasKey(key) {
608
+ return this.map.has(key);
609
+ }
610
+ has(key, value) {
611
+ const set = this.map.get(key);
612
+ if (!set)
613
+ return false;
614
+ if (arguments.length === 1)
615
+ return true;
616
+ return set.has(value);
617
+ }
618
+ add(key, value) {
619
+ let set = this.map.get(key);
620
+ if (!set) {
621
+ set = new Set;
622
+ this.map.set(key, set);
623
+ }
624
+ if (!set.has(value)) {
625
+ set.add(value);
626
+ this._valueCount++;
627
+ }
628
+ }
629
+ remove(key, value) {
630
+ const set = this.map.get(key);
631
+ if (!set)
632
+ return false;
633
+ if (!set.has(value))
634
+ return false;
635
+ set.delete(value);
636
+ this._valueCount--;
637
+ if (set.size === 0)
638
+ this.map.delete(key);
639
+ return true;
640
+ }
641
+ deleteKey(key) {
642
+ const set = this.map.get(key);
643
+ if (!set)
644
+ return false;
645
+ this._valueCount -= set.size;
646
+ this.map.delete(key);
647
+ return true;
648
+ }
649
+ get(key) {
650
+ const set = this.map.get(key);
651
+ return set ? new Set(set) : new Set;
652
+ }
653
+ *keys() {
654
+ yield* this.map.keys();
655
+ }
656
+ *values() {
657
+ for (const set of this.map.values()) {
658
+ for (const v of set)
659
+ yield v;
660
+ }
661
+ }
662
+ [Symbol.iterator]() {
663
+ return this.entries();
664
+ }
665
+ *entries() {
666
+ for (const [k, set] of this.map.entries()) {
667
+ for (const v of set)
668
+ yield [k, v];
669
+ }
670
+ }
671
+ clear() {
672
+ this.map.clear();
673
+ this._valueCount = 0;
674
+ }
675
+ }
676
+
597
677
  // src/query-filter.ts
598
678
  function serializeQueryFilter(filter = {}) {
599
679
  const negative = (filter.negativeComponentTypes || []).slice().sort((a, b) => a - b);
@@ -809,11 +889,6 @@ class World {
809
889
  if (snapshot.entityManager) {
810
890
  this.entityIdManager.deserializeState(snapshot.entityManager);
811
891
  }
812
- if (Array.isArray(snapshot.exclusiveComponents)) {
813
- for (const id of snapshot.exclusiveComponents) {
814
- this.exclusiveComponents.add(id);
815
- }
816
- }
817
892
  if (Array.isArray(snapshot.entities)) {
818
893
  for (const entry of snapshot.entities) {
819
894
  const entityId = entry.id;
@@ -883,7 +958,7 @@ class World {
883
958
  return;
884
959
  }
885
960
  const componentReferences = this.getEntityReferences(entityId);
886
- for (const { sourceEntityId, componentType } of componentReferences) {
961
+ for (const [sourceEntityId, componentType] of componentReferences) {
887
962
  const sourceArchetype = this.entityToArchetype.get(sourceEntityId);
888
963
  if (sourceArchetype) {
889
964
  const currentComponents = new Map;
@@ -1083,8 +1158,12 @@ class World {
1083
1158
  matchingArchetypes = [...this.archetypes];
1084
1159
  }
1085
1160
  for (const wildcard of wildcardRelations) {
1086
- const componentArchetypes = this.archetypesByComponent.get(wildcard.componentId) || [];
1087
- matchingArchetypes = matchingArchetypes.filter((archetype) => componentArchetypes.includes(archetype));
1161
+ matchingArchetypes = matchingArchetypes.filter((archetype) => archetype.componentTypes.some((archetypeType) => {
1162
+ if (!isRelationId(archetypeType))
1163
+ return false;
1164
+ const decoded = decodeRelationId(archetypeType);
1165
+ return decoded.componentId === wildcard.componentId;
1166
+ }));
1088
1167
  }
1089
1168
  return matchingArchetypes;
1090
1169
  }
@@ -1207,26 +1286,21 @@ class World {
1207
1286
  }
1208
1287
  trackEntityReference(sourceEntityId, componentType, targetEntityId) {
1209
1288
  if (!this.entityReferences.has(targetEntityId)) {
1210
- this.entityReferences.set(targetEntityId, new Set);
1289
+ this.entityReferences.set(targetEntityId, new MultiMap);
1211
1290
  }
1212
- this.entityReferences.get(targetEntityId).add({ sourceEntityId, componentType });
1291
+ this.entityReferences.get(targetEntityId).add(sourceEntityId, componentType);
1213
1292
  }
1214
1293
  untrackEntityReference(sourceEntityId, componentType, targetEntityId) {
1215
1294
  const references = this.entityReferences.get(targetEntityId);
1216
1295
  if (references) {
1217
- references.forEach((reference) => {
1218
- if (reference.sourceEntityId === sourceEntityId && reference.componentType === componentType) {
1219
- references.delete(reference);
1220
- }
1221
- });
1222
- if (references.size === 0) {
1296
+ references.get(sourceEntityId).delete(componentType);
1297
+ if (references.keyCount === 0) {
1223
1298
  this.entityReferences.delete(targetEntityId);
1224
1299
  }
1225
1300
  }
1226
1301
  }
1227
1302
  getEntityReferences(targetEntityId) {
1228
- const references = this.entityReferences.get(targetEntityId);
1229
- return references ? Array.from(references) : [];
1303
+ return this.entityReferences.get(targetEntityId) ?? [];
1230
1304
  }
1231
1305
  cleanupEmptyArchetype(archetype) {
1232
1306
  if (archetype.getEntities().length > 0) {
@@ -1331,7 +1405,6 @@ class World {
1331
1405
  return {
1332
1406
  version: 1,
1333
1407
  entityManager: this.entityIdManager.serializeState(),
1334
- exclusiveComponents: Array.from(this.exclusiveComponents),
1335
1408
  entities
1336
1409
  };
1337
1410
  }
package/multi-map.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ declare class MultiMap<K, V> {
2
+ private map;
3
+ private _valueCount;
4
+ get valueCount(): number;
5
+ get keyCount(): number;
6
+ hasKey(key: K): boolean;
7
+ has(key: K, value?: V): boolean;
8
+ add(key: K, value: V): void;
9
+ remove(key: K, value: V): boolean;
10
+ deleteKey(key: K): boolean;
11
+ get(key: K): Set<V>;
12
+ keys(): IterableIterator<K>;
13
+ values(): IterableIterator<V>;
14
+ [Symbol.iterator](): IterableIterator<[K, V]>;
15
+ entries(): IterableIterator<[K, V]>;
16
+ clear(): void;
17
+ }
18
+ export { MultiMap };
19
+ export type { MultiMap as MultiMapType };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codehz/ecs",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
package/world.d.ts CHANGED
@@ -176,7 +176,7 @@ export declare class World<UpdateParams extends any[] = []> {
176
176
  /**
177
177
  * Get all component references where a target entity is used as a component type
178
178
  * @param targetEntityId The target entity
179
- * @returns Array of {sourceEntityId, componentType} pairs
179
+ * @returns A MultiMap of sourceEntityId to componentTypes that reference the target entity
180
180
  */
181
181
  private getEntityReferences;
182
182
  /**
@@ -197,7 +197,6 @@ export declare class World<UpdateParams extends any[] = []> {
197
197
  export type SerializedWorld = {
198
198
  version: number;
199
199
  entityManager: any;
200
- exclusiveComponents: EntityId[];
201
200
  entities: SerializedEntity[];
202
201
  };
203
202
  export type SerializedEntity = {