@codehz/ecs 0.7.5 → 0.8.0
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/builder.d.mts +15 -12
- package/dist/index.mjs +1 -2
- package/dist/testing.d.mts +0 -1
- package/dist/testing.mjs +63 -2
- package/dist/testing.mjs.map +1 -1
- package/dist/world.mjs +65 -81
- package/dist/world.mjs.map +1 -1
- package/package.json +4 -4
- package/src/__tests__/world/wildcard-relation-hooks.test.ts +41 -0
- package/src/world/hooks.ts +5 -0
- package/src/world/world.ts +13 -10
package/dist/world.mjs
CHANGED
|
@@ -5,18 +5,17 @@ const ENTITY_ID_START = 1024;
|
|
|
5
5
|
* Constants for relation ID encoding
|
|
6
6
|
*/
|
|
7
7
|
const RELATION_SHIFT = 2 ** 42;
|
|
8
|
-
const WILDCARD_TARGET_ID = 0;
|
|
9
8
|
/**
|
|
10
9
|
* Check if a component ID is valid (1-1023)
|
|
11
10
|
*/
|
|
12
11
|
function isValidComponentId(componentId) {
|
|
13
|
-
return componentId >= 1 && componentId <=
|
|
12
|
+
return componentId >= 1 && componentId <= 1023;
|
|
14
13
|
}
|
|
15
14
|
/**
|
|
16
15
|
* Check if an ID is a component ID
|
|
17
16
|
*/
|
|
18
17
|
function isComponentId(id) {
|
|
19
|
-
return id >= 1 && id <=
|
|
18
|
+
return id >= 1 && id <= 1023;
|
|
20
19
|
}
|
|
21
20
|
/**
|
|
22
21
|
* Check if an ID is an entity ID
|
|
@@ -30,7 +29,6 @@ function isEntityId(id) {
|
|
|
30
29
|
function isRelationId(id) {
|
|
31
30
|
return id < 0;
|
|
32
31
|
}
|
|
33
|
-
|
|
34
32
|
//#endregion
|
|
35
33
|
//#region src/entity/relation.ts
|
|
36
34
|
/**
|
|
@@ -49,7 +47,7 @@ function decodeRelationRaw(id) {
|
|
|
49
47
|
function relation(componentId, targetId) {
|
|
50
48
|
if (!isComponentId(componentId)) throw new Error("First argument must be a valid component ID");
|
|
51
49
|
let actualTargetId;
|
|
52
|
-
if (targetId === "*") actualTargetId =
|
|
50
|
+
if (targetId === "*") actualTargetId = 0;
|
|
53
51
|
else {
|
|
54
52
|
if (!isEntityId(targetId) && !isComponentId(targetId)) throw new Error("Second argument must be a valid entity ID, component ID, or '*'");
|
|
55
53
|
actualTargetId = targetId;
|
|
@@ -64,7 +62,7 @@ function relation(componentId, targetId) {
|
|
|
64
62
|
*/
|
|
65
63
|
function isWildcardRelationId(id) {
|
|
66
64
|
const decoded = decodeRelationRaw(id);
|
|
67
|
-
return decoded !== null && decoded.targetId ===
|
|
65
|
+
return decoded !== null && decoded.targetId === 0;
|
|
68
66
|
}
|
|
69
67
|
/**
|
|
70
68
|
* Decode a relation ID into component and target IDs
|
|
@@ -78,7 +76,7 @@ function decodeRelationId(relationId) {
|
|
|
78
76
|
if (!isValidComponentId(rawComponentId)) throw new Error("Invalid component ID in relation");
|
|
79
77
|
const componentId = rawComponentId;
|
|
80
78
|
const targetId = rawTargetId;
|
|
81
|
-
if (targetId ===
|
|
79
|
+
if (targetId === 0) return {
|
|
82
80
|
componentId,
|
|
83
81
|
targetId,
|
|
84
82
|
type: "wildcard"
|
|
@@ -106,7 +104,7 @@ function getIdType(id) {
|
|
|
106
104
|
if (decoded === null) return "invalid";
|
|
107
105
|
const { componentId: rawComponentId, targetId: rawTargetId } = decoded;
|
|
108
106
|
if (!isValidComponentId(rawComponentId)) return "invalid";
|
|
109
|
-
if (rawTargetId ===
|
|
107
|
+
if (rawTargetId === 0) return "wildcard-relation";
|
|
110
108
|
else if (isEntityId(rawTargetId)) return "entity-relation";
|
|
111
109
|
else if (isComponentId(rawTargetId)) return "component-relation";
|
|
112
110
|
else return "invalid";
|
|
@@ -128,7 +126,7 @@ function getDetailedIdType(id) {
|
|
|
128
126
|
if (!isValidComponentId(rawComponentId)) return { type: "invalid" };
|
|
129
127
|
const componentId = rawComponentId;
|
|
130
128
|
const targetId = rawTargetId;
|
|
131
|
-
if (targetId ===
|
|
129
|
+
if (targetId === 0) return {
|
|
132
130
|
type: "wildcard-relation",
|
|
133
131
|
componentId,
|
|
134
132
|
targetId
|
|
@@ -168,9 +166,8 @@ function getTargetIdFromRelationId(id) {
|
|
|
168
166
|
*/
|
|
169
167
|
function isEntityRelation(id) {
|
|
170
168
|
const decoded = decodeRelationRaw(id);
|
|
171
|
-
return decoded !== null && decoded.targetId >=
|
|
169
|
+
return decoded !== null && decoded.targetId >= 1024;
|
|
172
170
|
}
|
|
173
|
-
|
|
174
171
|
//#endregion
|
|
175
172
|
//#region src/entity/manager.ts
|
|
176
173
|
/**
|
|
@@ -248,7 +245,7 @@ var ComponentIdAllocator = class {
|
|
|
248
245
|
* Increments counter sequentially from 1
|
|
249
246
|
*/
|
|
250
247
|
allocate() {
|
|
251
|
-
if (this.nextId >
|
|
248
|
+
if (this.nextId > 1023) throw new Error(`Component ID overflow: maximum ${COMPONENT_ID_MAX} components allowed`);
|
|
252
249
|
const id = this.nextId;
|
|
253
250
|
this.nextId++;
|
|
254
251
|
return id;
|
|
@@ -266,7 +263,6 @@ var ComponentIdAllocator = class {
|
|
|
266
263
|
return this.nextId <= COMPONENT_ID_MAX;
|
|
267
264
|
}
|
|
268
265
|
};
|
|
269
|
-
|
|
270
266
|
//#endregion
|
|
271
267
|
//#region src/utils/bit-set.ts
|
|
272
268
|
var BitSet = class {
|
|
@@ -363,7 +359,6 @@ var BitSet = class {
|
|
|
363
359
|
}
|
|
364
360
|
}
|
|
365
361
|
};
|
|
366
|
-
|
|
367
362
|
//#endregion
|
|
368
363
|
//#region src/component/registry.ts
|
|
369
364
|
const globalComponentIdAllocator = new ComponentIdAllocator();
|
|
@@ -535,7 +530,7 @@ function checkRelationFlag(id, flagBitSet, targetCondition) {
|
|
|
535
530
|
* @see {@link ComponentOptions.dontFragment} for the full explanation.
|
|
536
531
|
*/
|
|
537
532
|
function isDontFragmentRelation(id) {
|
|
538
|
-
return checkRelationFlag(id, dontFragmentFlags, (targetId) => targetId !==
|
|
533
|
+
return checkRelationFlag(id, dontFragmentFlags, (targetId) => targetId !== 0);
|
|
539
534
|
}
|
|
540
535
|
/**
|
|
541
536
|
* Check if an ID is a wildcard relation (`relation(Comp, "*")`) backed by a
|
|
@@ -559,7 +554,7 @@ function isDontFragmentRelation(id) {
|
|
|
559
554
|
* @see {@link ComponentOptions.dontFragment} for the full explanation.
|
|
560
555
|
*/
|
|
561
556
|
function isDontFragmentWildcard(id) {
|
|
562
|
-
return checkRelationFlag(id, dontFragmentFlags, (targetId) => targetId ===
|
|
557
|
+
return checkRelationFlag(id, dontFragmentFlags, (targetId) => targetId === 0);
|
|
563
558
|
}
|
|
564
559
|
/**
|
|
565
560
|
* Check if a relation ID is a cascade delete entity-relation.
|
|
@@ -578,9 +573,8 @@ function isDontFragmentWildcard(id) {
|
|
|
578
573
|
* @see {@link ComponentOptions.cascadeDelete}
|
|
579
574
|
*/
|
|
580
575
|
function isCascadeDeleteRelation(id) {
|
|
581
|
-
return checkRelationFlag(id, cascadeDeleteFlags, (targetId) => targetId !==
|
|
576
|
+
return checkRelationFlag(id, cascadeDeleteFlags, (targetId) => targetId !== 0 && targetId >= 1024);
|
|
582
577
|
}
|
|
583
|
-
|
|
584
578
|
//#endregion
|
|
585
579
|
//#region src/world/builder.ts
|
|
586
580
|
/**
|
|
@@ -639,7 +633,6 @@ var EntityBuilder = class {
|
|
|
639
633
|
return entity;
|
|
640
634
|
}
|
|
641
635
|
};
|
|
642
|
-
|
|
643
636
|
//#endregion
|
|
644
637
|
//#region src/component/type-utils.ts
|
|
645
638
|
/**
|
|
@@ -649,13 +642,11 @@ var EntityBuilder = class {
|
|
|
649
642
|
function normalizeComponentTypes(componentTypes) {
|
|
650
643
|
return [...componentTypes].sort((a, b) => a - b);
|
|
651
644
|
}
|
|
652
|
-
|
|
653
645
|
//#endregion
|
|
654
646
|
//#region src/types/index.ts
|
|
655
647
|
function isOptionalEntityId(type) {
|
|
656
648
|
return typeof type === "object" && type !== null && "optional" in type;
|
|
657
649
|
}
|
|
658
|
-
|
|
659
650
|
//#endregion
|
|
660
651
|
//#region src/utils/utils.ts
|
|
661
652
|
/**
|
|
@@ -676,7 +667,6 @@ function getOrCompute(cache, key, compute) {
|
|
|
676
667
|
}
|
|
677
668
|
return value;
|
|
678
669
|
}
|
|
679
|
-
|
|
680
670
|
//#endregion
|
|
681
671
|
//#region src/archetype/helpers.ts
|
|
682
672
|
/**
|
|
@@ -770,7 +760,6 @@ function buildSingleComponent(compType, dataSource, entityIndex, entityId, getCo
|
|
|
770
760
|
if (getIdType(actualType) === "wildcard-relation") return buildWildcardRelationValue(actualType, dataSource, (relType) => getComponentData(relType)[entityIndex], dontFragmentRelations.get(entityId), entityId, optional);
|
|
771
761
|
else return buildRegularComponentValue(dataSource, entityIndex, optional);
|
|
772
762
|
}
|
|
773
|
-
|
|
774
763
|
//#endregion
|
|
775
764
|
//#region src/archetype/archetype.ts
|
|
776
765
|
/**
|
|
@@ -1060,7 +1049,6 @@ var Archetype = class {
|
|
|
1060
1049
|
return false;
|
|
1061
1050
|
}
|
|
1062
1051
|
};
|
|
1063
|
-
|
|
1064
1052
|
//#endregion
|
|
1065
1053
|
//#region src/archetype/store.ts
|
|
1066
1054
|
/**
|
|
@@ -1079,7 +1067,6 @@ var DontFragmentStoreImpl = class {
|
|
|
1079
1067
|
this.data.delete(entityId);
|
|
1080
1068
|
}
|
|
1081
1069
|
};
|
|
1082
|
-
|
|
1083
1070
|
//#endregion
|
|
1084
1071
|
//#region src/commands/buffer.ts
|
|
1085
1072
|
/**
|
|
@@ -1101,12 +1088,12 @@ var CommandBuffer = class {
|
|
|
1101
1088
|
constructor(executeEntityCommands) {
|
|
1102
1089
|
this.executeEntityCommands = executeEntityCommands;
|
|
1103
1090
|
}
|
|
1104
|
-
set(entityId, componentType, component
|
|
1091
|
+
set(entityId, componentType, component) {
|
|
1105
1092
|
this.commands.push({
|
|
1106
1093
|
type: "set",
|
|
1107
1094
|
entityId,
|
|
1108
1095
|
componentType,
|
|
1109
|
-
component
|
|
1096
|
+
component
|
|
1110
1097
|
});
|
|
1111
1098
|
}
|
|
1112
1099
|
/**
|
|
@@ -1163,7 +1150,6 @@ var CommandBuffer = class {
|
|
|
1163
1150
|
this.commands = [];
|
|
1164
1151
|
}
|
|
1165
1152
|
};
|
|
1166
|
-
|
|
1167
1153
|
//#endregion
|
|
1168
1154
|
//#region src/commands/changeset.ts
|
|
1169
1155
|
/**
|
|
@@ -1175,8 +1161,8 @@ var ComponentChangeset = class {
|
|
|
1175
1161
|
/**
|
|
1176
1162
|
* Add a component to the changeset
|
|
1177
1163
|
*/
|
|
1178
|
-
set(componentType, component
|
|
1179
|
-
this.adds.set(componentType, component
|
|
1164
|
+
set(componentType, component) {
|
|
1165
|
+
this.adds.set(componentType, component);
|
|
1180
1166
|
this.removes.delete(componentType);
|
|
1181
1167
|
}
|
|
1182
1168
|
/**
|
|
@@ -1203,8 +1189,8 @@ var ComponentChangeset = class {
|
|
|
1203
1189
|
* Merge another changeset into this one
|
|
1204
1190
|
*/
|
|
1205
1191
|
merge(other) {
|
|
1206
|
-
for (const [componentType, component
|
|
1207
|
-
this.adds.set(componentType, component
|
|
1192
|
+
for (const [componentType, component] of other.adds) {
|
|
1193
|
+
this.adds.set(componentType, component);
|
|
1208
1194
|
this.removes.delete(componentType);
|
|
1209
1195
|
}
|
|
1210
1196
|
for (const componentType of other.removes) {
|
|
@@ -1217,7 +1203,7 @@ var ComponentChangeset = class {
|
|
|
1217
1203
|
*/
|
|
1218
1204
|
applyTo(existingComponents) {
|
|
1219
1205
|
for (const componentType of this.removes) existingComponents.delete(componentType);
|
|
1220
|
-
for (const [componentType, component
|
|
1206
|
+
for (const [componentType, component] of this.adds) existingComponents.set(componentType, component);
|
|
1221
1207
|
return existingComponents;
|
|
1222
1208
|
}
|
|
1223
1209
|
/**
|
|
@@ -1244,7 +1230,6 @@ var ComponentChangeset = class {
|
|
|
1244
1230
|
return changed ? Array.from(finalComponentTypes) : void 0;
|
|
1245
1231
|
}
|
|
1246
1232
|
};
|
|
1247
|
-
|
|
1248
1233
|
//#endregion
|
|
1249
1234
|
//#region src/component/entity-store.ts
|
|
1250
1235
|
/**
|
|
@@ -1411,7 +1396,6 @@ var ComponentEntityStore = class {
|
|
|
1411
1396
|
if (existing.size === 0) this.relationEntityIdsByTarget.delete(targetId);
|
|
1412
1397
|
}
|
|
1413
1398
|
};
|
|
1414
|
-
|
|
1415
1399
|
//#endregion
|
|
1416
1400
|
//#region src/query/filter.ts
|
|
1417
1401
|
/**
|
|
@@ -1452,7 +1436,6 @@ function matchesFilter(archetype, filter) {
|
|
|
1452
1436
|
else return !archetype.componentTypeSet.has(type);
|
|
1453
1437
|
});
|
|
1454
1438
|
}
|
|
1455
|
-
|
|
1456
1439
|
//#endregion
|
|
1457
1440
|
//#region src/query/query.ts
|
|
1458
1441
|
/**
|
|
@@ -1518,9 +1501,9 @@ var Query = class {
|
|
|
1518
1501
|
getEntities() {
|
|
1519
1502
|
this.ensureNotDisposed();
|
|
1520
1503
|
if (this.wildcardTypes.length === 0 && this.specificDontFragmentTypes.length === 0) {
|
|
1521
|
-
const result
|
|
1522
|
-
for (const archetype of this.cachedArchetypes) for (const entity of archetype.getEntities()) result
|
|
1523
|
-
return result
|
|
1504
|
+
const result = [];
|
|
1505
|
+
for (const archetype of this.cachedArchetypes) for (const entity of archetype.getEntities()) result.push(entity);
|
|
1506
|
+
return result;
|
|
1524
1507
|
}
|
|
1525
1508
|
const result = [];
|
|
1526
1509
|
for (const archetype of this.cachedArchetypes) for (const entity of archetype.getEntities()) if (this.entityMatchesQuery(archetype, entity)) result.push(entity);
|
|
@@ -1659,7 +1642,6 @@ var Query = class {
|
|
|
1659
1642
|
return this.isDisposed;
|
|
1660
1643
|
}
|
|
1661
1644
|
};
|
|
1662
|
-
|
|
1663
1645
|
//#endregion
|
|
1664
1646
|
//#region src/query/registry.ts
|
|
1665
1647
|
/**
|
|
@@ -1747,14 +1729,13 @@ var QueryRegistry = class {
|
|
|
1747
1729
|
for (const query of this.queries) query.removeArchetype(archetype);
|
|
1748
1730
|
}
|
|
1749
1731
|
};
|
|
1750
|
-
|
|
1751
1732
|
//#endregion
|
|
1752
1733
|
//#region src/world/commands.ts
|
|
1753
1734
|
function processCommands(entityId, currentArchetype, commands, changeset, handleExclusiveRelation) {
|
|
1754
1735
|
for (const command of commands) if (command.type === "set") processSetCommand(entityId, currentArchetype, command.componentType, command.component, changeset, handleExclusiveRelation);
|
|
1755
1736
|
else if (command.type === "delete") processDeleteCommand(entityId, currentArchetype, command.componentType, changeset);
|
|
1756
1737
|
}
|
|
1757
|
-
function processSetCommand(entityId, currentArchetype, componentType, component
|
|
1738
|
+
function processSetCommand(entityId, currentArchetype, componentType, component, changeset, handleExclusiveRelation) {
|
|
1758
1739
|
const componentId = getComponentIdFromRelationId(componentType);
|
|
1759
1740
|
if (componentId !== void 0) {
|
|
1760
1741
|
handleExclusiveRelation(entityId, currentArchetype, componentId);
|
|
@@ -1766,10 +1747,10 @@ function processSetCommand(entityId, currentArchetype, componentType, component$
|
|
|
1766
1747
|
const merge = getComponentMerge(componentType);
|
|
1767
1748
|
if (merge !== void 0 && changeset.adds.has(componentType)) {
|
|
1768
1749
|
const prev = changeset.adds.get(componentType);
|
|
1769
|
-
changeset.set(componentType, merge(prev, component
|
|
1750
|
+
changeset.set(componentType, merge(prev, component));
|
|
1770
1751
|
return;
|
|
1771
1752
|
}
|
|
1772
|
-
changeset.set(componentType, component
|
|
1753
|
+
changeset.set(componentType, component);
|
|
1773
1754
|
}
|
|
1774
1755
|
function processDeleteCommand(entityId, currentArchetype, componentType, changeset) {
|
|
1775
1756
|
const componentId = getComponentIdFromRelationId(componentType);
|
|
@@ -1846,9 +1827,9 @@ function applyChangeset(ctx, entityId, currentArchetype, changeset, entityToArch
|
|
|
1846
1827
|
}
|
|
1847
1828
|
if (removedComponents !== null) applyDontFragmentChanges(ctx.dontFragmentStore, entityId, changeset, removedComponents);
|
|
1848
1829
|
else applyDontFragmentChangesNoHooks(ctx.dontFragmentStore, entityId, changeset);
|
|
1849
|
-
for (const [componentType, component
|
|
1830
|
+
for (const [componentType, component] of changeset.adds) {
|
|
1850
1831
|
if (isDontFragmentRelation(componentType)) continue;
|
|
1851
|
-
currentArchetype.set(entityId, componentType, component
|
|
1832
|
+
currentArchetype.set(entityId, componentType, component);
|
|
1852
1833
|
}
|
|
1853
1834
|
return currentArchetype;
|
|
1854
1835
|
}
|
|
@@ -1866,12 +1847,12 @@ function applyDontFragmentChanges(dontFragmentRelations, entityId, changeset, re
|
|
|
1866
1847
|
}
|
|
1867
1848
|
}
|
|
1868
1849
|
}
|
|
1869
|
-
for (const [componentType, component
|
|
1850
|
+
for (const [componentType, component] of changeset.adds) if (isDontFragmentRelation(componentType)) {
|
|
1870
1851
|
if (!entityRelations) {
|
|
1871
1852
|
entityRelations = /* @__PURE__ */ new Map();
|
|
1872
1853
|
dontFragmentRelations.set(entityId, entityRelations);
|
|
1873
1854
|
}
|
|
1874
|
-
entityRelations.set(componentType, component
|
|
1855
|
+
entityRelations.set(componentType, component);
|
|
1875
1856
|
}
|
|
1876
1857
|
if (entityRelations && entityRelations.size === 0) dontFragmentRelations.delete(entityId);
|
|
1877
1858
|
}
|
|
@@ -1880,12 +1861,12 @@ function applyDontFragmentChangesNoHooks(dontFragmentRelations, entityId, change
|
|
|
1880
1861
|
for (const componentType of changeset.removes) if (isDontFragmentRelation(componentType)) {
|
|
1881
1862
|
if (entityRelations) entityRelations.delete(componentType);
|
|
1882
1863
|
}
|
|
1883
|
-
for (const [componentType, component
|
|
1864
|
+
for (const [componentType, component] of changeset.adds) if (isDontFragmentRelation(componentType)) {
|
|
1884
1865
|
if (!entityRelations) {
|
|
1885
1866
|
entityRelations = /* @__PURE__ */ new Map();
|
|
1886
1867
|
dontFragmentRelations.set(entityId, entityRelations);
|
|
1887
1868
|
}
|
|
1888
|
-
entityRelations.set(componentType, component
|
|
1869
|
+
entityRelations.set(componentType, component);
|
|
1889
1870
|
}
|
|
1890
1871
|
if (entityRelations && entityRelations.size === 0) dontFragmentRelations.delete(entityId);
|
|
1891
1872
|
}
|
|
@@ -1901,7 +1882,6 @@ function filterRegularComponentTypes(componentTypes) {
|
|
|
1901
1882
|
}
|
|
1902
1883
|
return regularTypes;
|
|
1903
1884
|
}
|
|
1904
|
-
|
|
1905
1885
|
//#endregion
|
|
1906
1886
|
//#region src/world/hooks.ts
|
|
1907
1887
|
/**
|
|
@@ -2019,9 +1999,12 @@ function reconstructWildcardWithRemoved(ctx, entityId, wildcardId, removedCompon
|
|
|
2019
1999
|
const currentData = ctx.get(entityId, wildcardId);
|
|
2020
2000
|
if (!Array.isArray(currentData)) throw new Error(`Expected wildcard relation data to be an array, but got ${typeof currentData} for entity ${entityId} and wildcard ${wildcardId}. This indicates a HooksContext implementation that does not conform to the expected contract.`);
|
|
2021
2001
|
const result = [...currentData];
|
|
2022
|
-
for (const [removedCompId, removedValue] of removedComponents.entries())
|
|
2023
|
-
|
|
2024
|
-
if (
|
|
2002
|
+
for (const [removedCompId, removedValue] of removedComponents.entries()) {
|
|
2003
|
+
if (isWildcardRelationId(removedCompId)) continue;
|
|
2004
|
+
if (componentMatchesHookType(removedCompId, wildcardId)) {
|
|
2005
|
+
const targetId = getTargetIdFromRelationId(removedCompId);
|
|
2006
|
+
if (targetId !== void 0) result.push([targetId, removedValue]);
|
|
2007
|
+
}
|
|
2025
2008
|
}
|
|
2026
2009
|
return result;
|
|
2027
2010
|
}
|
|
@@ -2033,8 +2016,8 @@ function collectMultiHookComponentsWithRemoved(ctx, entityId, componentTypes, re
|
|
|
2033
2016
|
const result = reconstructWildcardWithRemoved(ctx, entityId, optionalId, removedComponents);
|
|
2034
2017
|
return result.length > 0 ? { value: result } : void 0;
|
|
2035
2018
|
}
|
|
2036
|
-
const match
|
|
2037
|
-
return match
|
|
2019
|
+
const match = findMatchingComponent(removedComponents, optionalId);
|
|
2020
|
+
return match ? { value: match[1] } : ctx.getOptional(entityId, optionalId);
|
|
2038
2021
|
}
|
|
2039
2022
|
const compId = ct;
|
|
2040
2023
|
if (isWildcardRelationId(compId)) return reconstructWildcardWithRemoved(ctx, entityId, compId, removedComponents);
|
|
@@ -2054,8 +2037,8 @@ function collectComponentsFromRemoved(componentTypes, removedComponents) {
|
|
|
2054
2037
|
const result = collectWildcardFromRemoved(optionalId, removedComponents);
|
|
2055
2038
|
return result.length > 0 ? { value: result } : void 0;
|
|
2056
2039
|
}
|
|
2057
|
-
const match
|
|
2058
|
-
return match
|
|
2040
|
+
const match = findMatchingComponent(removedComponents, optionalId);
|
|
2041
|
+
return match ? { value: match[1] } : void 0;
|
|
2059
2042
|
}
|
|
2060
2043
|
const compId = ct;
|
|
2061
2044
|
if (isWildcardRelationId(compId)) return collectWildcardFromRemoved(compId, removedComponents);
|
|
@@ -2068,13 +2051,15 @@ function collectComponentsFromRemoved(componentTypes, removedComponents) {
|
|
|
2068
2051
|
*/
|
|
2069
2052
|
function collectWildcardFromRemoved(wildcardId, removedComponents) {
|
|
2070
2053
|
const result = [];
|
|
2071
|
-
for (const [removedCompId, removedValue] of removedComponents.entries())
|
|
2072
|
-
|
|
2073
|
-
if (
|
|
2054
|
+
for (const [removedCompId, removedValue] of removedComponents.entries()) {
|
|
2055
|
+
if (isWildcardRelationId(removedCompId)) continue;
|
|
2056
|
+
if (componentMatchesHookType(removedCompId, wildcardId)) {
|
|
2057
|
+
const targetId = getTargetIdFromRelationId(removedCompId);
|
|
2058
|
+
if (targetId !== void 0) result.push([targetId, removedValue]);
|
|
2059
|
+
}
|
|
2074
2060
|
}
|
|
2075
2061
|
return result;
|
|
2076
2062
|
}
|
|
2077
|
-
|
|
2078
2063
|
//#endregion
|
|
2079
2064
|
//#region src/utils/multi-map.ts
|
|
2080
2065
|
const _MISSING = Symbol("missing");
|
|
@@ -2144,7 +2129,6 @@ var MultiMap = class {
|
|
|
2144
2129
|
this._valueCount = 0;
|
|
2145
2130
|
}
|
|
2146
2131
|
};
|
|
2147
|
-
|
|
2148
2132
|
//#endregion
|
|
2149
2133
|
//#region src/world/references.ts
|
|
2150
2134
|
function trackEntityReference(entityReferences, sourceEntityId, componentType, targetEntityId) {
|
|
@@ -2161,7 +2145,6 @@ function untrackEntityReference(entityReferences, sourceEntityId, componentType,
|
|
|
2161
2145
|
function getEntityReferences(entityReferences, targetEntityId) {
|
|
2162
2146
|
return entityReferences.get(targetEntityId) ?? new MultiMap();
|
|
2163
2147
|
}
|
|
2164
|
-
|
|
2165
2148
|
//#endregion
|
|
2166
2149
|
//#region src/storage/serialization.ts
|
|
2167
2150
|
/**
|
|
@@ -2239,7 +2222,6 @@ function decodeSerializedId(sid) {
|
|
|
2239
2222
|
}
|
|
2240
2223
|
throw new Error(`Invalid ID in snapshot: ${JSON.stringify(sid)}`);
|
|
2241
2224
|
}
|
|
2242
|
-
|
|
2243
2225
|
//#endregion
|
|
2244
2226
|
//#region src/world/serialization.ts
|
|
2245
2227
|
/**
|
|
@@ -2309,7 +2291,6 @@ function deserializeWorld(ctx, snapshot) {
|
|
|
2309
2291
|
}
|
|
2310
2292
|
}
|
|
2311
2293
|
}
|
|
2312
|
-
|
|
2313
2294
|
//#endregion
|
|
2314
2295
|
//#region src/world/world.ts
|
|
2315
2296
|
/**
|
|
@@ -2505,8 +2486,8 @@ var World = class {
|
|
|
2505
2486
|
};
|
|
2506
2487
|
}
|
|
2507
2488
|
set(entityId, componentTypeOrComponent, maybeComponent) {
|
|
2508
|
-
const { entityId: targetEntityId, componentType, component
|
|
2509
|
-
this.commandBuffer.set(targetEntityId, componentType, component
|
|
2489
|
+
const { entityId: targetEntityId, componentType, component } = this.resolveSetOperation(entityId, componentTypeOrComponent, maybeComponent);
|
|
2490
|
+
this.commandBuffer.set(targetEntityId, componentType, component);
|
|
2510
2491
|
}
|
|
2511
2492
|
remove(entityId, componentType) {
|
|
2512
2493
|
const { entityId: targetEntityId, componentType: targetComponentType } = this.resolveRemoveOperation(entityId, componentType);
|
|
@@ -2631,25 +2612,28 @@ var World = class {
|
|
|
2631
2612
|
* **Important:** Store the query reference and reuse it across frames for optimal performance.
|
|
2632
2613
|
* Creating a new query each frame defeats the caching mechanism.
|
|
2633
2614
|
*
|
|
2634
|
-
*
|
|
2635
|
-
*
|
|
2615
|
+
* **Note on optional components:** Only **required** (non-optional) component types should be
|
|
2616
|
+
* passed to `createQuery`. Optional components (wrapped with `{ optional: ... }`) must be
|
|
2617
|
+
* specified at **iteration time** via {@link Query.forEach}, {@link Query.getEntitiesWithComponents},
|
|
2618
|
+
* or {@link Query.iterate} — NOT here. Including optional wrappers in `createQuery` will cause
|
|
2619
|
+
* undefined behavior because the internal normalization relies on numeric sorting of component IDs.
|
|
2620
|
+
*
|
|
2621
|
+
* @param componentTypes - Array of **required** component types to match (do not include optional wrappers)
|
|
2622
|
+
* @param filter - Optional filter for additional constraints (e.g., exclude entities with certain components)
|
|
2636
2623
|
* @returns A Query instance that can be used to iterate matching entities
|
|
2637
2624
|
*
|
|
2638
2625
|
* @example
|
|
2639
|
-
* // Create once, reuse many times
|
|
2626
|
+
* // Create once, reuse many times (required components only)
|
|
2640
2627
|
* const movementQuery = world.createQuery([Position, Velocity]);
|
|
2641
2628
|
*
|
|
2642
|
-
* //
|
|
2643
|
-
* movementQuery.forEach((entity) => {
|
|
2644
|
-
*
|
|
2645
|
-
* const vel = world.get(entity, Velocity);
|
|
2646
|
-
* pos.x += vel.x;
|
|
2647
|
-
* pos.y += vel.y;
|
|
2629
|
+
* // Optional components are passed at iteration time, not creation time:
|
|
2630
|
+
* movementQuery.forEach([Position, { optional: Velocity }], (entity, pos, vel) => {
|
|
2631
|
+
* pos.x += vel?.value?.x ?? 0;
|
|
2648
2632
|
* });
|
|
2649
2633
|
*
|
|
2650
2634
|
* // With filter
|
|
2651
2635
|
* const activeQuery = world.createQuery([Position], {
|
|
2652
|
-
*
|
|
2636
|
+
* negativeComponentTypes: [Disabled]
|
|
2653
2637
|
* });
|
|
2654
2638
|
*/
|
|
2655
2639
|
createQuery(componentTypes, filter = {}) {
|
|
@@ -2821,11 +2805,11 @@ var World = class {
|
|
|
2821
2805
|
for (const componentType of changeset.removes) if (isEntityRelation(componentType)) {
|
|
2822
2806
|
const targetId = getTargetIdFromRelationId(componentType);
|
|
2823
2807
|
untrackEntityReference(this.entityReferences, entityId, componentType, targetId);
|
|
2824
|
-
} else if (componentType >=
|
|
2808
|
+
} else if (componentType >= 1024) untrackEntityReference(this.entityReferences, entityId, componentType, componentType);
|
|
2825
2809
|
for (const [componentType] of changeset.adds) if (isEntityRelation(componentType)) {
|
|
2826
2810
|
const targetId = getTargetIdFromRelationId(componentType);
|
|
2827
2811
|
trackEntityReference(this.entityReferences, entityId, componentType, targetId);
|
|
2828
|
-
} else if (componentType >=
|
|
2812
|
+
} else if (componentType >= 1024) trackEntityReference(this.entityReferences, entityId, componentType, componentType);
|
|
2829
2813
|
}
|
|
2830
2814
|
ensureArchetype(componentTypes) {
|
|
2831
2815
|
const sortedTypes = normalizeComponentTypes(filterRegularComponentTypes(componentTypes));
|
|
@@ -2942,7 +2926,7 @@ var World = class {
|
|
|
2942
2926
|
return serializeWorld(this.archetypes, this.componentEntities, this.entityIdManager);
|
|
2943
2927
|
}
|
|
2944
2928
|
};
|
|
2945
|
-
|
|
2946
2929
|
//#endregion
|
|
2947
2930
|
export { getComponentIdByName as a, isWildcardRelationId as c, isEntityId as d, isRelationId as f, component as i, relation as l, Query as n, getComponentNameById as o, EntityBuilder as r, decodeRelationId as s, World as t, isComponentId as u };
|
|
2931
|
+
|
|
2948
2932
|
//# sourceMappingURL=world.mjs.map
|