@codehz/ecs 0.3.8 → 0.3.9
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.d.mts +161 -151
- package/index.mjs +391 -174
- package/index.mjs.map +1 -1
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
//#region src/entity.ts
|
|
2
|
-
/**
|
|
3
|
-
* Constants for ID ranges
|
|
4
|
-
*/
|
|
5
|
-
const INVALID_COMPONENT_ID = 0;
|
|
6
2
|
const COMPONENT_ID_MAX = 1023;
|
|
7
3
|
const ENTITY_ID_START = 1024;
|
|
8
4
|
/**
|
|
@@ -10,23 +6,6 @@ const ENTITY_ID_START = 1024;
|
|
|
10
6
|
*/
|
|
11
7
|
const RELATION_SHIFT = 2 ** 42;
|
|
12
8
|
const WILDCARD_TARGET_ID = 0;
|
|
13
|
-
/**
|
|
14
|
-
* Create a component ID
|
|
15
|
-
* @param id Component identifier (1-1023)
|
|
16
|
-
* @see component
|
|
17
|
-
*/
|
|
18
|
-
function createComponentId(id) {
|
|
19
|
-
if (id < 1 || id > COMPONENT_ID_MAX) throw new Error(`Component ID must be between 1 and ${COMPONENT_ID_MAX}`);
|
|
20
|
-
return id;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Create an entity ID
|
|
24
|
-
* @param id Entity identifier (starting from 1024)
|
|
25
|
-
*/
|
|
26
|
-
function createEntityId(id) {
|
|
27
|
-
if (id < ENTITY_ID_START) throw new Error(`Entity ID must be ${ENTITY_ID_START} or greater`);
|
|
28
|
-
return id;
|
|
29
|
-
}
|
|
30
9
|
function relation(componentId, targetId) {
|
|
31
10
|
if (!isComponentId(componentId)) throw new Error("First argument must be a valid component ID");
|
|
32
11
|
let actualTargetId;
|
|
@@ -142,24 +121,6 @@ function getDetailedIdType(id) {
|
|
|
142
121
|
return { type: "invalid" };
|
|
143
122
|
}
|
|
144
123
|
/**
|
|
145
|
-
* Inspect an EntityId and return a human-readable string representation
|
|
146
|
-
* @param id The EntityId to inspect
|
|
147
|
-
* @returns A friendly string representation of the ID
|
|
148
|
-
*/
|
|
149
|
-
function inspectEntityId(id) {
|
|
150
|
-
if (id === INVALID_COMPONENT_ID) return "Invalid Component ID (0)";
|
|
151
|
-
if (isComponentId(id)) return `Component ID (${id})`;
|
|
152
|
-
if (isEntityId(id)) return `Entity ID (${id})`;
|
|
153
|
-
if (isRelationId(id)) try {
|
|
154
|
-
const decoded = decodeRelationId(id);
|
|
155
|
-
if (!isComponentId(decoded.componentId) || decoded.type !== "wildcard" && !isEntityId(decoded.targetId) && !isComponentId(decoded.targetId)) return `Invalid Relation ID (${id})`;
|
|
156
|
-
return `Relation ID: ${`Component ID (${decoded.componentId})`} -> ${decoded.type === "entity" ? `Entity ID (${decoded.targetId})` : decoded.type === "component" ? `Component ID (${decoded.targetId})` : "Wildcard (*)"}`;
|
|
157
|
-
} catch (error) {
|
|
158
|
-
return `Invalid Relation ID (${id})`;
|
|
159
|
-
}
|
|
160
|
-
return `Unknown ID (${id})`;
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
124
|
* Entity ID Manager for automatic allocation and freelist recycling
|
|
164
125
|
*/
|
|
165
126
|
var EntityIdManager = class {
|
|
@@ -254,20 +215,36 @@ var ComponentIdAllocator = class {
|
|
|
254
215
|
const globalComponentIdAllocator = new ComponentIdAllocator();
|
|
255
216
|
const ComponentNames = /* @__PURE__ */ new Map();
|
|
256
217
|
const ComponentIdForNames = /* @__PURE__ */ new Map();
|
|
218
|
+
const ComponentOptions = /* @__PURE__ */ new Map();
|
|
257
219
|
/**
|
|
258
220
|
* Allocate a new component ID from the global allocator.
|
|
259
|
-
*
|
|
260
|
-
* The name is only for serialization/debugging and does not affect base functionality.
|
|
261
|
-
* @param name Optional name for the component
|
|
221
|
+
* @param nameOrOptions Optional name for the component (for serialization/debugging) or options object
|
|
262
222
|
* @returns The allocated component ID
|
|
223
|
+
* @example
|
|
224
|
+
* // Just a name
|
|
225
|
+
* const Position = component<Position>("Position");
|
|
226
|
+
*
|
|
227
|
+
* // With options
|
|
228
|
+
* const ChildOf = component({ exclusive: true, cascadeDelete: true });
|
|
229
|
+
*
|
|
230
|
+
* // With name and options
|
|
231
|
+
* const ChildOf = component({ name: "ChildOf", exclusive: true });
|
|
263
232
|
*/
|
|
264
|
-
function component(
|
|
233
|
+
function component(nameOrOptions) {
|
|
265
234
|
const id = globalComponentIdAllocator.allocate();
|
|
235
|
+
let name;
|
|
236
|
+
let options;
|
|
237
|
+
if (typeof nameOrOptions === "string") name = nameOrOptions;
|
|
238
|
+
else if (typeof nameOrOptions === "object" && nameOrOptions !== null) {
|
|
239
|
+
options = nameOrOptions;
|
|
240
|
+
name = options.name;
|
|
241
|
+
}
|
|
266
242
|
if (name) {
|
|
267
243
|
if (ComponentIdForNames.has(name)) throw new Error(`Component name "${name}" is already registered`);
|
|
268
244
|
ComponentNames.set(id, name);
|
|
269
245
|
ComponentIdForNames.set(name, id);
|
|
270
246
|
}
|
|
247
|
+
if (options) ComponentOptions.set(id, options);
|
|
271
248
|
return id;
|
|
272
249
|
}
|
|
273
250
|
/**
|
|
@@ -285,6 +262,30 @@ function getComponentIdByName(name) {
|
|
|
285
262
|
function getComponentNameById(id) {
|
|
286
263
|
return ComponentNames.get(id);
|
|
287
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Check if a component is marked as exclusive
|
|
267
|
+
* @param id The component ID
|
|
268
|
+
* @returns true if the component is exclusive, false otherwise
|
|
269
|
+
*/
|
|
270
|
+
function isExclusiveComponent(id) {
|
|
271
|
+
return ComponentOptions.get(id)?.exclusive ?? false;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Check if a component is marked as cascade delete
|
|
275
|
+
* @param id The component ID
|
|
276
|
+
* @returns true if the component is cascade delete, false otherwise
|
|
277
|
+
*/
|
|
278
|
+
function isCascadeDeleteComponent(id) {
|
|
279
|
+
return ComponentOptions.get(id)?.cascadeDelete ?? false;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Check if a component is marked as dontFragment
|
|
283
|
+
* @param id The component ID
|
|
284
|
+
* @returns true if the component is dontFragment, false otherwise
|
|
285
|
+
*/
|
|
286
|
+
function isDontFragmentComponent(id) {
|
|
287
|
+
return ComponentOptions.get(id)?.dontFragment ?? false;
|
|
288
|
+
}
|
|
288
289
|
|
|
289
290
|
//#endregion
|
|
290
291
|
//#region src/types.ts
|
|
@@ -358,6 +359,12 @@ var Archetype = class {
|
|
|
358
359
|
*/
|
|
359
360
|
entityToIndex = /* @__PURE__ */ new Map();
|
|
360
361
|
/**
|
|
362
|
+
* Reference to dontFragment relations storage from World
|
|
363
|
+
* This allows entities with different relation targets to share the same archetype
|
|
364
|
+
* Stored in World to avoid migration overhead when entities change archetypes
|
|
365
|
+
*/
|
|
366
|
+
dontFragmentRelations;
|
|
367
|
+
/**
|
|
361
368
|
* Cache for pre-computed component data sources to avoid repeated calculations
|
|
362
369
|
* For regular components: data array
|
|
363
370
|
* For wildcards: matching relation types array
|
|
@@ -366,9 +373,11 @@ var Archetype = class {
|
|
|
366
373
|
/**
|
|
367
374
|
* Create a new archetype with the specified component types
|
|
368
375
|
* @param componentTypes The component types that define this archetype
|
|
376
|
+
* @param dontFragmentRelations Reference to the World's dontFragmentRelations storage
|
|
369
377
|
*/
|
|
370
|
-
constructor(componentTypes) {
|
|
378
|
+
constructor(componentTypes, dontFragmentRelations) {
|
|
371
379
|
this.componentTypes = [...componentTypes].sort((a, b) => a - b);
|
|
380
|
+
this.dontFragmentRelations = dontFragmentRelations;
|
|
372
381
|
for (const componentType of this.componentTypes) this.componentData.set(componentType, []);
|
|
373
382
|
}
|
|
374
383
|
/**
|
|
@@ -389,7 +398,7 @@ var Archetype = class {
|
|
|
389
398
|
/**
|
|
390
399
|
* Add an entity to this archetype with initial component data
|
|
391
400
|
* @param entityId The entity to add
|
|
392
|
-
* @param componentData Map of component type to component data
|
|
401
|
+
* @param componentData Map of component type to component data (includes both regular and dontFragment components)
|
|
393
402
|
*/
|
|
394
403
|
addEntity(entityId, componentData) {
|
|
395
404
|
if (this.entityToIndex.has(entityId)) throw new Error(`Entity ${entityId} is already in this archetype`);
|
|
@@ -400,11 +409,18 @@ var Archetype = class {
|
|
|
400
409
|
const data = componentData.get(componentType);
|
|
401
410
|
this.getComponentData(componentType).push(data === void 0 ? MISSING_COMPONENT : data);
|
|
402
411
|
}
|
|
412
|
+
const dontFragmentData = /* @__PURE__ */ new Map();
|
|
413
|
+
for (const [componentType, data] of componentData) {
|
|
414
|
+
if (this.componentTypes.includes(componentType)) continue;
|
|
415
|
+
const detailedType = getDetailedIdType(componentType);
|
|
416
|
+
if ((detailedType.type === "entity-relation" || detailedType.type === "component-relation") && isDontFragmentComponent(detailedType.componentId)) dontFragmentData.set(componentType, data);
|
|
417
|
+
}
|
|
418
|
+
if (dontFragmentData.size > 0) this.dontFragmentRelations.set(entityId, dontFragmentData);
|
|
403
419
|
}
|
|
404
420
|
/**
|
|
405
421
|
* Get all component data for a specific entity
|
|
406
422
|
* @param entityId The entity to get data for
|
|
407
|
-
* @returns Map of component type to component data
|
|
423
|
+
* @returns Map of component type to component data (includes both regular and dontFragment components)
|
|
408
424
|
*/
|
|
409
425
|
getEntity(entityId) {
|
|
410
426
|
const index = this.entityToIndex.get(entityId);
|
|
@@ -414,11 +430,13 @@ var Archetype = class {
|
|
|
414
430
|
const data = this.getComponentData(componentType)[index];
|
|
415
431
|
entityData.set(componentType, data === MISSING_COMPONENT ? void 0 : data);
|
|
416
432
|
}
|
|
433
|
+
const dontFragmentData = this.dontFragmentRelations.get(entityId);
|
|
434
|
+
if (dontFragmentData) for (const [componentType, data] of dontFragmentData) entityData.set(componentType, data);
|
|
417
435
|
return entityData;
|
|
418
436
|
}
|
|
419
437
|
/**
|
|
420
438
|
* Dump all entities and their component data in this archetype
|
|
421
|
-
* @returns Array of objects with entity and component data
|
|
439
|
+
* @returns Array of objects with entity and component data (includes both regular and dontFragment components)
|
|
422
440
|
*/
|
|
423
441
|
dump() {
|
|
424
442
|
const result = [];
|
|
@@ -429,6 +447,8 @@ var Archetype = class {
|
|
|
429
447
|
const data = this.getComponentData(componentType)[i];
|
|
430
448
|
components.set(componentType, data === MISSING_COMPONENT ? void 0 : data);
|
|
431
449
|
}
|
|
450
|
+
const dontFragmentData = this.dontFragmentRelations.get(entity);
|
|
451
|
+
if (dontFragmentData) for (const [componentType, data] of dontFragmentData) components.set(componentType, data);
|
|
432
452
|
result.push({
|
|
433
453
|
entity,
|
|
434
454
|
components
|
|
@@ -439,7 +459,7 @@ var Archetype = class {
|
|
|
439
459
|
/**
|
|
440
460
|
* Remove an entity from this archetype
|
|
441
461
|
* @param entityId The entity to remove
|
|
442
|
-
* @returns The component data of the removed entity
|
|
462
|
+
* @returns The component data of the removed entity (includes both regular and dontFragment components)
|
|
443
463
|
*/
|
|
444
464
|
removeEntity(entityId) {
|
|
445
465
|
const index = this.entityToIndex.get(entityId);
|
|
@@ -449,6 +469,11 @@ var Archetype = class {
|
|
|
449
469
|
const dataArray = this.getComponentData(componentType);
|
|
450
470
|
removedData.set(componentType, dataArray[index]);
|
|
451
471
|
}
|
|
472
|
+
const dontFragmentData = this.dontFragmentRelations.get(entityId);
|
|
473
|
+
if (dontFragmentData) {
|
|
474
|
+
for (const [componentType, data] of dontFragmentData) removedData.set(componentType, data);
|
|
475
|
+
this.dontFragmentRelations.delete(entityId);
|
|
476
|
+
}
|
|
452
477
|
this.entityToIndex.delete(entityId);
|
|
453
478
|
const lastIndex = this.entities.length - 1;
|
|
454
479
|
if (index !== lastIndex) {
|
|
@@ -487,10 +512,20 @@ var Archetype = class {
|
|
|
487
512
|
}
|
|
488
513
|
}
|
|
489
514
|
}
|
|
515
|
+
const dontFragmentData = this.dontFragmentRelations.get(entityId);
|
|
516
|
+
if (dontFragmentData) for (const [relType, data] of dontFragmentData) {
|
|
517
|
+
const relDetailed = getDetailedIdType(relType);
|
|
518
|
+
if ((relDetailed.type === "entity-relation" || relDetailed.type === "component-relation") && relDetailed.componentId === componentId) relations.push([relDetailed.targetId, data]);
|
|
519
|
+
}
|
|
490
520
|
return relations;
|
|
491
521
|
} else {
|
|
492
|
-
|
|
493
|
-
|
|
522
|
+
if (this.componentTypes.includes(componentType)) {
|
|
523
|
+
const data = this.getComponentData(componentType)[index];
|
|
524
|
+
return data === MISSING_COMPONENT ? void 0 : data;
|
|
525
|
+
}
|
|
526
|
+
const dontFragmentData = this.dontFragmentRelations.get(entityId);
|
|
527
|
+
if (dontFragmentData && dontFragmentData.has(componentType)) return dontFragmentData.get(componentType);
|
|
528
|
+
throw new Error(`Component type ${componentType} not found for entity ${entityId}`);
|
|
494
529
|
}
|
|
495
530
|
}
|
|
496
531
|
/**
|
|
@@ -500,11 +535,24 @@ var Archetype = class {
|
|
|
500
535
|
* @param data The component data
|
|
501
536
|
*/
|
|
502
537
|
set(entityId, componentType, data) {
|
|
503
|
-
if (!this.componentData.has(componentType)) throw new Error(`Component type ${componentType} is not in this archetype`);
|
|
504
538
|
const index = this.entityToIndex.get(entityId);
|
|
505
539
|
if (index === void 0) throw new Error(`Entity ${entityId} is not in this archetype`);
|
|
506
|
-
|
|
507
|
-
|
|
540
|
+
if (this.componentData.has(componentType)) {
|
|
541
|
+
const dataArray = this.getComponentData(componentType);
|
|
542
|
+
dataArray[index] = data;
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
const detailedType = getDetailedIdType(componentType);
|
|
546
|
+
if ((detailedType.type === "entity-relation" || detailedType.type === "component-relation") && isDontFragmentComponent(detailedType.componentId)) {
|
|
547
|
+
let dontFragmentData = this.dontFragmentRelations.get(entityId);
|
|
548
|
+
if (!dontFragmentData) {
|
|
549
|
+
dontFragmentData = /* @__PURE__ */ new Map();
|
|
550
|
+
this.dontFragmentRelations.set(entityId, dontFragmentData);
|
|
551
|
+
}
|
|
552
|
+
dontFragmentData.set(componentType, data);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
throw new Error(`Component type ${componentType} is not in this archetype`);
|
|
508
556
|
}
|
|
509
557
|
/**
|
|
510
558
|
* Get all entities in this archetype
|
|
@@ -539,59 +587,82 @@ var Archetype = class {
|
|
|
539
587
|
* Helper: compute or return cached data sources for provided componentTypes
|
|
540
588
|
*/
|
|
541
589
|
getCachedComponentDataSources(componentTypes) {
|
|
542
|
-
const cacheKey =
|
|
543
|
-
return getOrComputeCache(this.componentDataSourcesCache, cacheKey, () =>
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
590
|
+
const cacheKey = this.buildCacheKey(componentTypes);
|
|
591
|
+
return getOrComputeCache(this.componentDataSourcesCache, cacheKey, () => componentTypes.map((compType) => this.getComponentDataSource(compType)));
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Build cache key for component types
|
|
595
|
+
*/
|
|
596
|
+
buildCacheKey(componentTypes) {
|
|
597
|
+
return componentTypes.map((id) => isOptionalEntityId(id) ? `opt(${id.optional})` : `${id}`).join(",");
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Get data source for a single component type
|
|
601
|
+
*/
|
|
602
|
+
getComponentDataSource(compType) {
|
|
603
|
+
const optional = isOptionalEntityId(compType);
|
|
604
|
+
const actualType = optional ? compType.optional : compType;
|
|
605
|
+
const detailedType = getDetailedIdType(actualType);
|
|
606
|
+
if (detailedType.type === "wildcard-relation") return this.getWildcardRelationDataSource(detailedType.componentId, optional);
|
|
607
|
+
else return optional ? this.getOptionalComponentData(actualType) : this.getComponentData(actualType);
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Get data source for wildcard relations
|
|
611
|
+
*/
|
|
612
|
+
getWildcardRelationDataSource(componentId, optional) {
|
|
613
|
+
const matchingRelations = this.componentTypes.filter((ct) => {
|
|
614
|
+
const detailedCt = getDetailedIdType(ct);
|
|
615
|
+
return (detailedCt.type === "entity-relation" || detailedCt.type === "component-relation") && detailedCt.componentId === componentId;
|
|
561
616
|
});
|
|
617
|
+
return optional ? matchingRelations.length > 0 ? matchingRelations : void 0 : matchingRelations;
|
|
562
618
|
}
|
|
563
619
|
/**
|
|
564
620
|
* Helper: build component tuples for a specific entity index using precomputed data sources
|
|
565
621
|
*/
|
|
566
622
|
buildComponentsForIndex(componentTypes, componentDataSources, entityIndex) {
|
|
567
623
|
return componentDataSources.map((dataSource, i) => {
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
if (isOptionalEntityId(compType)) {
|
|
571
|
-
compType = compType.optional;
|
|
572
|
-
optional = true;
|
|
573
|
-
}
|
|
574
|
-
if (getIdType(compType) === "wildcard-relation") {
|
|
575
|
-
if (dataSource === void 0) if (optional) return;
|
|
576
|
-
else throw new Error(`No matching relations found for mandatory wildcard relation component type`);
|
|
577
|
-
const matchingRelations = dataSource;
|
|
578
|
-
const relations = [];
|
|
579
|
-
for (const relType of matchingRelations) {
|
|
580
|
-
const data = this.getComponentData(relType)[entityIndex];
|
|
581
|
-
const decodedRel = decodeRelationId(relType);
|
|
582
|
-
relations.push([decodedRel.targetId, data === MISSING_COMPONENT ? void 0 : data]);
|
|
583
|
-
}
|
|
584
|
-
return optional ? { value: relations } : relations;
|
|
585
|
-
} else {
|
|
586
|
-
if (dataSource === void 0) if (optional) return;
|
|
587
|
-
else throw new Error(`No matching relations found for mandatory wildcard relation component type`);
|
|
588
|
-
const data = dataSource[entityIndex];
|
|
589
|
-
const result = data === MISSING_COMPONENT ? void 0 : data;
|
|
590
|
-
return optional ? { value: result } : result;
|
|
591
|
-
}
|
|
624
|
+
const compType = componentTypes[i];
|
|
625
|
+
return this.buildSingleComponent(compType, dataSource, entityIndex);
|
|
592
626
|
});
|
|
593
627
|
}
|
|
594
628
|
/**
|
|
629
|
+
* Build a single component value from its data source
|
|
630
|
+
*/
|
|
631
|
+
buildSingleComponent(compType, dataSource, entityIndex) {
|
|
632
|
+
const optional = isOptionalEntityId(compType);
|
|
633
|
+
if (getIdType(optional ? compType.optional : compType) === "wildcard-relation") return this.buildWildcardRelationValue(dataSource, entityIndex, optional);
|
|
634
|
+
else return this.buildRegularComponentValue(dataSource, entityIndex, optional);
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Build wildcard relation value from matching relations
|
|
638
|
+
*/
|
|
639
|
+
buildWildcardRelationValue(dataSource, entityIndex, optional) {
|
|
640
|
+
if (dataSource === void 0) {
|
|
641
|
+
if (optional) return;
|
|
642
|
+
throw new Error(`No matching relations found for mandatory wildcard relation component type`);
|
|
643
|
+
}
|
|
644
|
+
const matchingRelations = dataSource;
|
|
645
|
+
const relations = [];
|
|
646
|
+
for (const relType of matchingRelations) {
|
|
647
|
+
const data = this.getComponentData(relType)[entityIndex];
|
|
648
|
+
const decodedRel = decodeRelationId(relType);
|
|
649
|
+
relations.push([decodedRel.targetId, data === MISSING_COMPONENT ? void 0 : data]);
|
|
650
|
+
}
|
|
651
|
+
return optional ? { value: relations } : relations;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Build regular component value from data source
|
|
655
|
+
*/
|
|
656
|
+
buildRegularComponentValue(dataSource, entityIndex, optional) {
|
|
657
|
+
if (dataSource === void 0) {
|
|
658
|
+
if (optional) return;
|
|
659
|
+
throw new Error(`Component data not found for mandatory component type`);
|
|
660
|
+
}
|
|
661
|
+
const data = dataSource[entityIndex];
|
|
662
|
+
const result = data === MISSING_COMPONENT ? void 0 : data;
|
|
663
|
+
return optional ? { value: result } : result;
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
595
666
|
* Get entities with their component data for specified component types
|
|
596
667
|
* Optimized for bulk component access with pre-computed indices
|
|
597
668
|
* @param componentTypes Array of component types to retrieve
|
|
@@ -926,10 +997,16 @@ var Query = class {
|
|
|
926
997
|
world._registerQuery(this);
|
|
927
998
|
}
|
|
928
999
|
/**
|
|
1000
|
+
* Check if query is disposed and throw error if so
|
|
1001
|
+
*/
|
|
1002
|
+
ensureNotDisposed() {
|
|
1003
|
+
if (this.isDisposed) throw new Error("Query has been disposed");
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
929
1006
|
* Get all entities matching the query
|
|
930
1007
|
*/
|
|
931
1008
|
getEntities() {
|
|
932
|
-
|
|
1009
|
+
this.ensureNotDisposed();
|
|
933
1010
|
const result = [];
|
|
934
1011
|
for (const archetype of this.cachedArchetypes) result.push(...archetype.getEntities());
|
|
935
1012
|
return result;
|
|
@@ -940,7 +1017,7 @@ var Query = class {
|
|
|
940
1017
|
* @returns Array of objects with entity and component data
|
|
941
1018
|
*/
|
|
942
1019
|
getEntitiesWithComponents(componentTypes) {
|
|
943
|
-
|
|
1020
|
+
this.ensureNotDisposed();
|
|
944
1021
|
const result = [];
|
|
945
1022
|
for (const archetype of this.cachedArchetypes) {
|
|
946
1023
|
const entitiesWithData = archetype.getEntitiesWithComponents(componentTypes);
|
|
@@ -954,7 +1031,7 @@ var Query = class {
|
|
|
954
1031
|
* @param callback Function called for each entity with its components
|
|
955
1032
|
*/
|
|
956
1033
|
forEach(componentTypes, callback) {
|
|
957
|
-
|
|
1034
|
+
this.ensureNotDisposed();
|
|
958
1035
|
for (const archetype of this.cachedArchetypes) archetype.forEachWithComponents(componentTypes, callback);
|
|
959
1036
|
}
|
|
960
1037
|
/**
|
|
@@ -962,7 +1039,7 @@ var Query = class {
|
|
|
962
1039
|
* @param componentTypes Array of component types to retrieve
|
|
963
1040
|
*/
|
|
964
1041
|
*iterate(componentTypes) {
|
|
965
|
-
|
|
1042
|
+
this.ensureNotDisposed();
|
|
966
1043
|
for (const archetype of this.cachedArchetypes) yield* archetype.iterateWithComponents(componentTypes);
|
|
967
1044
|
}
|
|
968
1045
|
/**
|
|
@@ -971,7 +1048,7 @@ var Query = class {
|
|
|
971
1048
|
* @returns Array of component data for all matching entities
|
|
972
1049
|
*/
|
|
973
1050
|
getComponentData(componentType) {
|
|
974
|
-
|
|
1051
|
+
this.ensureNotDisposed();
|
|
975
1052
|
const result = [];
|
|
976
1053
|
for (const archetype of this.cachedArchetypes) result.push(...archetype.getComponentData(componentType));
|
|
977
1054
|
return result;
|
|
@@ -1119,6 +1196,8 @@ var World = class {
|
|
|
1119
1196
|
archetypesByComponent = /* @__PURE__ */ new Map();
|
|
1120
1197
|
/** Tracks which entities reference each entity as a component type */
|
|
1121
1198
|
entityReferences = /* @__PURE__ */ new Map();
|
|
1199
|
+
/** Storage for dontFragment relations - maps entity ID to a map of relation type to component data */
|
|
1200
|
+
dontFragmentRelations = /* @__PURE__ */ new Map();
|
|
1122
1201
|
/** Array of all active queries for archetype change notifications */
|
|
1123
1202
|
queries = [];
|
|
1124
1203
|
/** Cache for queries keyed by component types and filter signatures */
|
|
@@ -1129,10 +1208,6 @@ var World = class {
|
|
|
1129
1208
|
commandBuffer = new CommandBuffer((entityId, commands) => this.executeEntityCommands(entityId, commands));
|
|
1130
1209
|
/** Stores lifecycle hooks for component and relation events */
|
|
1131
1210
|
hooks = /* @__PURE__ */ new Map();
|
|
1132
|
-
/** Set of component IDs marked as exclusive relations */
|
|
1133
|
-
exclusiveComponents = /* @__PURE__ */ new Set();
|
|
1134
|
-
/** Set of component IDs that will cascade delete when the relation target is deleted */
|
|
1135
|
-
cascadeDeleteComponents = /* @__PURE__ */ new Set();
|
|
1136
1211
|
/**
|
|
1137
1212
|
* Create a new World.
|
|
1138
1213
|
* If an optional snapshot object is provided (previously produced by `world.serialize()`),
|
|
@@ -1214,7 +1289,7 @@ var World = class {
|
|
|
1214
1289
|
const sourceArchetype = this.entityToArchetype.get(sourceEntityId);
|
|
1215
1290
|
if (!sourceArchetype) continue;
|
|
1216
1291
|
const detailedType = getDetailedIdType(componentType);
|
|
1217
|
-
if (detailedType.type === "entity-relation" &&
|
|
1292
|
+
if (detailedType.type === "entity-relation" && isCascadeDeleteComponent(detailedType.componentId)) {
|
|
1218
1293
|
if (!visited.has(sourceEntityId)) queue.push(sourceEntityId);
|
|
1219
1294
|
continue;
|
|
1220
1295
|
}
|
|
@@ -1271,13 +1346,20 @@ var World = class {
|
|
|
1271
1346
|
*/
|
|
1272
1347
|
has(entityId, componentType) {
|
|
1273
1348
|
const archetype = this.entityToArchetype.get(entityId);
|
|
1274
|
-
|
|
1349
|
+
if (!archetype) return false;
|
|
1350
|
+
if (archetype.componentTypes.includes(componentType)) return true;
|
|
1351
|
+
const detailedType = getDetailedIdType(componentType);
|
|
1352
|
+
if ((detailedType.type === "entity-relation" || detailedType.type === "component-relation") && isDontFragmentComponent(detailedType.componentId)) return this.dontFragmentRelations.get(entityId)?.has(componentType) ?? false;
|
|
1353
|
+
return false;
|
|
1275
1354
|
}
|
|
1276
1355
|
get(entityId, componentType) {
|
|
1277
1356
|
const archetype = this.entityToArchetype.get(entityId);
|
|
1278
1357
|
if (!archetype) throw new Error(`Entity ${entityId} does not exist`);
|
|
1279
|
-
|
|
1280
|
-
|
|
1358
|
+
const detailedType = getDetailedIdType(componentType);
|
|
1359
|
+
if (detailedType.type !== "wildcard-relation") {
|
|
1360
|
+
const inArchetype = archetype.componentTypes.includes(componentType);
|
|
1361
|
+
const isDontFragment = (detailedType.type === "entity-relation" || detailedType.type === "component-relation") && isDontFragmentComponent(detailedType.componentId);
|
|
1362
|
+
if (!(inArchetype || isDontFragment && this.dontFragmentRelations.get(entityId)?.has(componentType))) throw new Error(`Entity ${entityId} does not have component ${componentType}. Use has() to check component existence before calling get().`);
|
|
1281
1363
|
}
|
|
1282
1364
|
return archetype.get(entityId, componentType);
|
|
1283
1365
|
}
|
|
@@ -1315,19 +1397,19 @@ var World = class {
|
|
|
1315
1397
|
}
|
|
1316
1398
|
/**
|
|
1317
1399
|
* Mark a component as exclusive relation
|
|
1318
|
-
*
|
|
1400
|
+
* @deprecated This method has been removed. Use component options instead: component({ exclusive: true })
|
|
1401
|
+
* @throws Always throws an error directing to the new API
|
|
1319
1402
|
*/
|
|
1320
1403
|
setExclusive(componentId) {
|
|
1321
|
-
|
|
1404
|
+
throw new Error("setExclusive has been removed. Use component options instead: component({ exclusive: true })");
|
|
1322
1405
|
}
|
|
1323
1406
|
/**
|
|
1324
1407
|
* Mark a component as cascade-delete relation
|
|
1325
|
-
*
|
|
1326
|
-
*
|
|
1327
|
-
* Only applicable to entity-relation components
|
|
1408
|
+
* @deprecated This method has been removed. Use component options instead: component({ cascadeDelete: true })
|
|
1409
|
+
* @throws Always throws an error directing to the new API
|
|
1328
1410
|
*/
|
|
1329
1411
|
setCascadeDelete(componentId) {
|
|
1330
|
-
|
|
1412
|
+
throw new Error("setCascadeDelete has been removed. Use component options instead: component({ cascadeDelete: true })");
|
|
1331
1413
|
}
|
|
1332
1414
|
/**
|
|
1333
1415
|
* Update the world (run all systems in dependency order)
|
|
@@ -1462,76 +1544,187 @@ var World = class {
|
|
|
1462
1544
|
}
|
|
1463
1545
|
const currentArchetype = this.entityToArchetype.get(entityId);
|
|
1464
1546
|
if (!currentArchetype) return changeset;
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1547
|
+
this.processCommands(entityId, currentArchetype, commands, changeset);
|
|
1548
|
+
const removedComponents = this.applyChangeset(entityId, currentArchetype, changeset);
|
|
1549
|
+
this.updateEntityReferences(entityId, changeset);
|
|
1550
|
+
this.triggerLifecycleHooks(entityId, changeset.adds, removedComponents);
|
|
1551
|
+
return changeset;
|
|
1552
|
+
}
|
|
1553
|
+
/**
|
|
1554
|
+
* Process commands and populate the changeset
|
|
1555
|
+
*/
|
|
1556
|
+
processCommands(entityId, currentArchetype, commands, changeset) {
|
|
1557
|
+
for (const command of commands) if (command.type === "set" && command.componentType) this.processSetCommand(entityId, currentArchetype, command.componentType, command.component, changeset);
|
|
1558
|
+
else if (command.type === "delete" && command.componentType) this.processDeleteCommand(entityId, currentArchetype, command.componentType, changeset);
|
|
1559
|
+
}
|
|
1560
|
+
/**
|
|
1561
|
+
* Process a set command, handling exclusive relations
|
|
1562
|
+
*/
|
|
1563
|
+
processSetCommand(entityId, currentArchetype, componentType, component$1, changeset) {
|
|
1564
|
+
const detailedType = getDetailedIdType(componentType);
|
|
1565
|
+
if ((detailedType.type === "entity-relation" || detailedType.type === "component-relation") && isExclusiveComponent(detailedType.componentId)) this.removeExclusiveRelations(entityId, currentArchetype, detailedType.componentId, changeset);
|
|
1566
|
+
changeset.set(componentType, component$1);
|
|
1567
|
+
}
|
|
1568
|
+
/**
|
|
1569
|
+
* Remove all relations with the same base component (for exclusive relations)
|
|
1570
|
+
*/
|
|
1571
|
+
removeExclusiveRelations(entityId, currentArchetype, baseComponentId, changeset) {
|
|
1572
|
+
for (const componentType of currentArchetype.componentTypes) if (this.isRelationWithComponent(componentType, baseComponentId)) changeset.delete(componentType);
|
|
1573
|
+
const entityData = currentArchetype.getEntity(entityId);
|
|
1574
|
+
if (entityData) for (const [componentType] of entityData) {
|
|
1575
|
+
if (currentArchetype.componentTypes.includes(componentType)) continue;
|
|
1576
|
+
if (this.isRelationWithComponent(componentType, baseComponentId)) changeset.delete(componentType);
|
|
1490
1577
|
}
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1578
|
+
}
|
|
1579
|
+
/**
|
|
1580
|
+
* Check if a component type is a relation with the given base component
|
|
1581
|
+
*/
|
|
1582
|
+
isRelationWithComponent(componentType, baseComponentId) {
|
|
1583
|
+
const detailedType = getDetailedIdType(componentType);
|
|
1584
|
+
return (detailedType.type === "entity-relation" || detailedType.type === "component-relation") && detailedType.componentId === baseComponentId;
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* Process a delete command, handling wildcard relations
|
|
1588
|
+
*/
|
|
1589
|
+
processDeleteCommand(entityId, currentArchetype, componentType, changeset) {
|
|
1590
|
+
const detailedType = getDetailedIdType(componentType);
|
|
1591
|
+
if (detailedType.type === "wildcard-relation") this.removeWildcardRelations(entityId, currentArchetype, detailedType.componentId, changeset);
|
|
1592
|
+
else changeset.delete(componentType);
|
|
1593
|
+
}
|
|
1594
|
+
/**
|
|
1595
|
+
* Remove all relations matching a wildcard component ID
|
|
1596
|
+
*/
|
|
1597
|
+
removeWildcardRelations(entityId, currentArchetype, baseComponentId, changeset) {
|
|
1598
|
+
for (const componentType of currentArchetype.componentTypes) if (this.isRelationWithComponent(componentType, baseComponentId)) changeset.delete(componentType);
|
|
1599
|
+
const entityData = currentArchetype.getEntity(entityId);
|
|
1600
|
+
if (entityData) for (const [componentType] of entityData) {
|
|
1601
|
+
if (currentArchetype.componentTypes.includes(componentType)) continue;
|
|
1602
|
+
if (this.isRelationWithComponent(componentType, baseComponentId)) changeset.delete(componentType);
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
/**
|
|
1606
|
+
* Apply changeset to entity, moving to new archetype if needed
|
|
1607
|
+
* @returns Map of removed components with their data
|
|
1608
|
+
*/
|
|
1609
|
+
applyChangeset(entityId, currentArchetype, changeset) {
|
|
1610
|
+
const currentEntityData = currentArchetype.getEntity(entityId);
|
|
1611
|
+
const allCurrentComponentTypes = currentEntityData ? Array.from(currentEntityData.keys()) : currentArchetype.componentTypes;
|
|
1612
|
+
const finalComponentTypes = changeset.getFinalComponentTypes(allCurrentComponentTypes);
|
|
1613
|
+
const removedComponents = /* @__PURE__ */ new Map();
|
|
1614
|
+
if (finalComponentTypes) this.moveEntityToNewArchetype(entityId, currentArchetype, finalComponentTypes, changeset, removedComponents);
|
|
1615
|
+
else this.updateEntityInSameArchetype(entityId, currentArchetype, changeset, removedComponents);
|
|
1616
|
+
return removedComponents;
|
|
1617
|
+
}
|
|
1618
|
+
/**
|
|
1619
|
+
* Move entity to a new archetype with updated components
|
|
1620
|
+
*/
|
|
1621
|
+
moveEntityToNewArchetype(entityId, currentArchetype, finalComponentTypes, changeset, removedComponents) {
|
|
1622
|
+
const newArchetype = this.ensureArchetype(finalComponentTypes);
|
|
1623
|
+
const currentComponents = currentArchetype.removeEntity(entityId);
|
|
1624
|
+
for (const componentType of changeset.removes) removedComponents.set(componentType, currentComponents.get(componentType));
|
|
1625
|
+
newArchetype.addEntity(entityId, changeset.applyTo(currentComponents));
|
|
1626
|
+
this.entityToArchetype.set(entityId, newArchetype);
|
|
1627
|
+
if (currentArchetype.getEntities().length === 0) this.cleanupEmptyArchetype(currentArchetype);
|
|
1628
|
+
}
|
|
1629
|
+
/**
|
|
1630
|
+
* Update entity in same archetype (no archetype change needed)
|
|
1631
|
+
*/
|
|
1632
|
+
updateEntityInSameArchetype(entityId, currentArchetype, changeset, removedComponents) {
|
|
1633
|
+
const currentComponents = currentArchetype.getEntity(entityId);
|
|
1634
|
+
const hasDontFragmentChanges = this.hasDontFragmentChanges(changeset);
|
|
1635
|
+
if (hasDontFragmentChanges) for (const componentType of changeset.removes) {
|
|
1636
|
+
const detailedType = getDetailedIdType(componentType);
|
|
1637
|
+
if ((detailedType.type === "entity-relation" || detailedType.type === "component-relation") && isDontFragmentComponent(detailedType.componentId)) removedComponents.set(componentType, currentComponents.get(componentType));
|
|
1638
|
+
}
|
|
1639
|
+
if (hasDontFragmentChanges) this.readdEntityWithUpdatedComponents(entityId, currentArchetype, currentComponents, changeset);
|
|
1640
|
+
else for (const [componentType, component$1] of changeset.adds) currentArchetype.set(entityId, componentType, component$1);
|
|
1641
|
+
}
|
|
1642
|
+
/**
|
|
1643
|
+
* Check if changeset contains dontFragment relation changes
|
|
1644
|
+
*/
|
|
1645
|
+
hasDontFragmentChanges(changeset) {
|
|
1500
1646
|
for (const componentType of changeset.removes) {
|
|
1501
1647
|
const detailedType = getDetailedIdType(componentType);
|
|
1502
|
-
if (detailedType.type === "entity-relation")
|
|
1503
|
-
const targetEntityId = detailedType.targetId;
|
|
1504
|
-
this.untrackEntityReference(entityId, componentType, targetEntityId);
|
|
1505
|
-
} else if (detailedType.type === "entity") this.untrackEntityReference(entityId, componentType, componentType);
|
|
1648
|
+
if ((detailedType.type === "entity-relation" || detailedType.type === "component-relation") && isDontFragmentComponent(detailedType.componentId)) return true;
|
|
1506
1649
|
}
|
|
1507
|
-
for (const [componentType
|
|
1650
|
+
for (const [componentType] of changeset.adds) {
|
|
1508
1651
|
const detailedType = getDetailedIdType(componentType);
|
|
1509
|
-
if (detailedType.type === "entity-relation")
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1652
|
+
if ((detailedType.type === "entity-relation" || detailedType.type === "component-relation") && isDontFragmentComponent(detailedType.componentId)) return true;
|
|
1653
|
+
}
|
|
1654
|
+
return false;
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* Remove and re-add entity with updated components (for dontFragment changes)
|
|
1658
|
+
*/
|
|
1659
|
+
readdEntityWithUpdatedComponents(entityId, archetype, currentComponents, changeset) {
|
|
1660
|
+
const newComponents = /* @__PURE__ */ new Map();
|
|
1661
|
+
for (const [ct, value] of currentComponents) if (!changeset.removes.has(ct)) newComponents.set(ct, value);
|
|
1662
|
+
for (const [ct, value] of changeset.adds) newComponents.set(ct, value);
|
|
1663
|
+
archetype.removeEntity(entityId);
|
|
1664
|
+
archetype.addEntity(entityId, newComponents);
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Update entity reference tracking based on changeset
|
|
1668
|
+
*/
|
|
1669
|
+
updateEntityReferences(entityId, changeset) {
|
|
1670
|
+
for (const componentType of changeset.removes) {
|
|
1671
|
+
const detailedType = getDetailedIdType(componentType);
|
|
1672
|
+
if (detailedType.type === "entity-relation") this.untrackEntityReference(entityId, componentType, detailedType.targetId);
|
|
1673
|
+
else if (detailedType.type === "entity") this.untrackEntityReference(entityId, componentType, componentType);
|
|
1674
|
+
}
|
|
1675
|
+
for (const [componentType] of changeset.adds) {
|
|
1676
|
+
const detailedType = getDetailedIdType(componentType);
|
|
1677
|
+
if (detailedType.type === "entity-relation") this.trackEntityReference(entityId, componentType, detailedType.targetId);
|
|
1678
|
+
else if (detailedType.type === "entity") this.trackEntityReference(entityId, componentType, componentType);
|
|
1513
1679
|
}
|
|
1514
|
-
this.triggerLifecycleHooks(entityId, changeset.adds, removedCompoents);
|
|
1515
|
-
return changeset;
|
|
1516
1680
|
}
|
|
1517
1681
|
/**
|
|
1518
1682
|
* Get or create an archetype for the given component types
|
|
1519
|
-
*
|
|
1683
|
+
* Filters out dontFragment relations from the archetype signature
|
|
1684
|
+
* @returns The archetype for the given component types (excluding dontFragment relations)
|
|
1520
1685
|
*/
|
|
1521
1686
|
ensureArchetype(componentTypes) {
|
|
1522
|
-
const sortedTypes =
|
|
1687
|
+
const sortedTypes = this.filterRegularComponentTypes(componentTypes).sort((a, b) => a - b);
|
|
1523
1688
|
const hashKey = this.createArchetypeSignature(sortedTypes);
|
|
1524
|
-
return getOrCreateWithSideEffect(this.archetypeBySignature, hashKey, () =>
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1689
|
+
return getOrCreateWithSideEffect(this.archetypeBySignature, hashKey, () => this.createNewArchetype(sortedTypes));
|
|
1690
|
+
}
|
|
1691
|
+
/**
|
|
1692
|
+
* Filter out dontFragment relations from component types
|
|
1693
|
+
*/
|
|
1694
|
+
filterRegularComponentTypes(componentTypes) {
|
|
1695
|
+
const regularTypes = [];
|
|
1696
|
+
for (const componentType of componentTypes) {
|
|
1697
|
+
const detailedType = getDetailedIdType(componentType);
|
|
1698
|
+
if ((detailedType.type === "entity-relation" || detailedType.type === "component-relation") && isDontFragmentComponent(detailedType.componentId)) continue;
|
|
1699
|
+
regularTypes.push(componentType);
|
|
1700
|
+
}
|
|
1701
|
+
return regularTypes;
|
|
1702
|
+
}
|
|
1703
|
+
/**
|
|
1704
|
+
* Create a new archetype and register it with all tracking structures
|
|
1705
|
+
*/
|
|
1706
|
+
createNewArchetype(componentTypes) {
|
|
1707
|
+
const newArchetype = new Archetype(componentTypes, this.dontFragmentRelations);
|
|
1708
|
+
this.archetypes.push(newArchetype);
|
|
1709
|
+
this.registerArchetypeInComponentIndex(newArchetype, componentTypes);
|
|
1710
|
+
this.notifyQueriesOfNewArchetype(newArchetype);
|
|
1711
|
+
return newArchetype;
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Register archetype in the component-to-archetype index
|
|
1715
|
+
*/
|
|
1716
|
+
registerArchetypeInComponentIndex(archetype, componentTypes) {
|
|
1717
|
+
for (const componentType of componentTypes) {
|
|
1718
|
+
const archetypes = this.archetypesByComponent.get(componentType) || [];
|
|
1719
|
+
archetypes.push(archetype);
|
|
1720
|
+
this.archetypesByComponent.set(componentType, archetypes);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
/**
|
|
1724
|
+
* Notify all queries to check the new archetype
|
|
1725
|
+
*/
|
|
1726
|
+
notifyQueriesOfNewArchetype(archetype) {
|
|
1727
|
+
for (const query of this.queries) query.checkNewArchetype(archetype);
|
|
1535
1728
|
}
|
|
1536
1729
|
/**
|
|
1537
1730
|
* Add a component reference to the reverse index when an entity is used as a component type
|
|
@@ -1569,10 +1762,29 @@ var World = class {
|
|
|
1569
1762
|
*/
|
|
1570
1763
|
cleanupEmptyArchetype(archetype) {
|
|
1571
1764
|
if (archetype.getEntities().length > 0) return;
|
|
1765
|
+
this.removeArchetypeFromList(archetype);
|
|
1766
|
+
this.removeArchetypeFromSignatureMap(archetype);
|
|
1767
|
+
this.removeArchetypeFromComponentIndex(archetype);
|
|
1768
|
+
this.removeArchetypeFromQueries(archetype);
|
|
1769
|
+
}
|
|
1770
|
+
/**
|
|
1771
|
+
* Remove archetype from the main archetypes list
|
|
1772
|
+
*/
|
|
1773
|
+
removeArchetypeFromList(archetype) {
|
|
1572
1774
|
const index = this.archetypes.indexOf(archetype);
|
|
1573
1775
|
if (index !== -1) this.archetypes.splice(index, 1);
|
|
1776
|
+
}
|
|
1777
|
+
/**
|
|
1778
|
+
* Remove archetype from the signature-to-archetype map
|
|
1779
|
+
*/
|
|
1780
|
+
removeArchetypeFromSignatureMap(archetype) {
|
|
1574
1781
|
const hashKey = this.createArchetypeSignature(archetype.componentTypes);
|
|
1575
1782
|
this.archetypeBySignature.delete(hashKey);
|
|
1783
|
+
}
|
|
1784
|
+
/**
|
|
1785
|
+
* Remove archetype from the component-to-archetypes index
|
|
1786
|
+
*/
|
|
1787
|
+
removeArchetypeFromComponentIndex(archetype) {
|
|
1576
1788
|
for (const componentType of archetype.componentTypes) {
|
|
1577
1789
|
const archetypes = this.archetypesByComponent.get(componentType);
|
|
1578
1790
|
if (archetypes) {
|
|
@@ -1583,6 +1795,11 @@ var World = class {
|
|
|
1583
1795
|
}
|
|
1584
1796
|
}
|
|
1585
1797
|
}
|
|
1798
|
+
}
|
|
1799
|
+
/**
|
|
1800
|
+
* Remove archetype from all queries
|
|
1801
|
+
*/
|
|
1802
|
+
removeArchetypeFromQueries(archetype) {
|
|
1586
1803
|
for (const query of this.queries) query.removeArchetype(archetype);
|
|
1587
1804
|
}
|
|
1588
1805
|
/**
|
|
@@ -1660,5 +1877,5 @@ var World = class {
|
|
|
1660
1877
|
};
|
|
1661
1878
|
|
|
1662
1879
|
//#endregion
|
|
1663
|
-
export {
|
|
1880
|
+
export { Query, World, component, decodeRelationId, getComponentIdByName, getComponentNameById, isComponentId, isEntityId, isRelationId, isWildcardRelationId, relation };
|
|
1664
1881
|
//# sourceMappingURL=index.mjs.map
|