koota 0.5.2 → 0.5.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.
- package/README.md +38 -4
- package/dist/{chunk-BQ2FKEYY.js → chunk-ULRUABHP.js} +144 -241
- package/dist/index.cjs +144 -241
- package/dist/index.js +1 -1
- package/dist/react.cjs +241 -254
- package/dist/react.d.cts +6 -2
- package/dist/react.d.ts +6 -2
- package/dist/react.js +88 -11
- package/package.json +8 -8
- package/react/index.cjs +241 -254
- package/react/index.d.cts +6 -2
- package/react/index.d.ts +6 -2
- package/react/index.js +88 -11
package/README.md
CHANGED
|
@@ -398,7 +398,7 @@ world.set(Time, { current: performance.now() })
|
|
|
398
398
|
|
|
399
399
|
### Select traits on queries for updates
|
|
400
400
|
|
|
401
|
-
Query filters entity results and `select` is used to choose what traits are fetched for `updateEach` and `
|
|
401
|
+
Query filters entity results and `select` is used to choose what traits are fetched for `updateEach` and `useStores`. This can be useful if your query is wider than the data you want to modify.
|
|
402
402
|
|
|
403
403
|
```js
|
|
404
404
|
// The query finds all entities with Position, Velocity and Mass
|
|
@@ -414,11 +414,11 @@ world.query(Position, Velocity, Mass)
|
|
|
414
414
|
|
|
415
415
|
### Modifying trait stores directly
|
|
416
416
|
|
|
417
|
-
For performance-critical operations, you can modify trait stores directly using the `
|
|
417
|
+
For performance-critical operations, you can modify trait stores directly using the `useStores` hook. This approach bypasses some of the safety checks and event triggers, so use it with caution. All stores are structure of arrays for performance purposes.
|
|
418
418
|
|
|
419
419
|
```js
|
|
420
420
|
// Returns the SoA stores
|
|
421
|
-
world.query(Position, Velocity).
|
|
421
|
+
world.query(Position, Velocity).useStores(([position, velocity], entities) => {
|
|
422
422
|
// Write our own loop over the stores
|
|
423
423
|
for (let i = 0; i < entities.length; i++) {
|
|
424
424
|
// Get the entity ID to use as the array index
|
|
@@ -748,7 +748,7 @@ const Attacker = trait<Pick<AttackerSchema, keyof AttackerSchema>>({
|
|
|
748
748
|
|
|
749
749
|
#### Accessing the store directly
|
|
750
750
|
|
|
751
|
-
The store can be accessed with `getStore`, but this low-level access is risky as it bypasses Koota's guard rails. However, this can be useful for debugging where direct introspection of the store is needed. For direct store mutations, use the [`
|
|
751
|
+
The store can be accessed with `getStore`, but this low-level access is risky as it bypasses Koota's guard rails. However, this can be useful for debugging where direct introspection of the store is needed. For direct store mutations, use the [`useStores` API](#modifying-trait-stores-direclty) instead.
|
|
752
752
|
|
|
753
753
|
```js
|
|
754
754
|
// Returns SoA or AoS depending on the trait
|
|
@@ -913,6 +913,40 @@ return (
|
|
|
913
913
|
)
|
|
914
914
|
```
|
|
915
915
|
|
|
916
|
+
### `useTag`
|
|
917
|
+
|
|
918
|
+
Observes an entity, or world, for a tag and reactively updates when it is added or removed. Returns `true` when the tag is present or `false` when absent. Use this instead of `useTrait` for tags. For tracking the presence of non-tag traits, use `useHas`.
|
|
919
|
+
|
|
920
|
+
```js
|
|
921
|
+
const IsActive = trait()
|
|
922
|
+
|
|
923
|
+
function ActiveIndicator({ entity }) {
|
|
924
|
+
// Returns true if the entity has the tag, false otherwise
|
|
925
|
+
const isActive = useTag(entity, IsActive)
|
|
926
|
+
|
|
927
|
+
if (!isActive) return null
|
|
928
|
+
|
|
929
|
+
return <div>🟢 Active</div>
|
|
930
|
+
}
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
### `useHas`
|
|
934
|
+
|
|
935
|
+
Observes an entity, or world, for any trait and reactively updates when it is added or removed. Returns `true` when the trait is present or `false` when absent. Unlike `useTrait`, this only tracks presence and not the trait's value.
|
|
936
|
+
|
|
937
|
+
```js
|
|
938
|
+
const Health = trait({ amount: 100 })
|
|
939
|
+
|
|
940
|
+
function HealthIndicator({ entity }) {
|
|
941
|
+
// Returns true if the entity has the trait, false otherwise
|
|
942
|
+
const hasHealth = useHas(entity, Health)
|
|
943
|
+
|
|
944
|
+
if (!hasHealth) return null
|
|
945
|
+
|
|
946
|
+
return <div>❤️ Has Health</div>
|
|
947
|
+
}
|
|
948
|
+
```
|
|
949
|
+
|
|
916
950
|
### `useTraitEffect`
|
|
917
951
|
|
|
918
952
|
Subscribes a callback to a trait on an entity. This callback fires as an effect whenever it is added, removed or changes value without rerendering.
|
|
@@ -40,6 +40,18 @@ function unpackEntity(entity) {
|
|
|
40
40
|
entityId: entity & ENTITY_ID_MASK
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
+
var getEntityId = (
|
|
44
|
+
/* @inline @pure */
|
|
45
|
+
(entity) => entity & ENTITY_ID_MASK
|
|
46
|
+
);
|
|
47
|
+
var getEntityWorldId = (
|
|
48
|
+
/* @inline @pure */
|
|
49
|
+
(entity) => entity >>> WORLD_ID_SHIFT
|
|
50
|
+
);
|
|
51
|
+
var getEntityGeneration = (
|
|
52
|
+
/* @inline @pure */
|
|
53
|
+
(entity) => entity >>> GENERATION_SHIFT & GENERATION_MASK
|
|
54
|
+
);
|
|
43
55
|
var incrementGeneration = (entity) => entity & ~(GENERATION_MASK << GENERATION_SHIFT) | // Clear current generation bits
|
|
44
56
|
((entity >>> GENERATION_SHIFT & GENERATION_MASK) + 1 & GENERATION_MASK) << GENERATION_SHIFT;
|
|
45
57
|
|
|
@@ -139,25 +151,11 @@ function createChanged() {
|
|
|
139
151
|
}
|
|
140
152
|
function setChanged(world, entity, trait2) {
|
|
141
153
|
const ctx = world[$internal];
|
|
142
|
-
|
|
143
|
-
const ctx_0_$f = world[$internal];
|
|
144
|
-
const data_0_$f = ctx_0_$f.traitData.get(trait2);
|
|
145
|
-
if (!data_0_$f) {
|
|
146
|
-
result_hasTrait_0_$f = false;
|
|
147
|
-
} else {
|
|
148
|
-
const {
|
|
149
|
-
generationId,
|
|
150
|
-
bitflag
|
|
151
|
-
} = data_0_$f;
|
|
152
|
-
const eid_0_$f = entity & ENTITY_ID_MASK;
|
|
153
|
-
const mask_0_$f = ctx_0_$f.entityMasks[generationId][eid_0_$f];
|
|
154
|
-
result_hasTrait_0_$f = (mask_0_$f & bitflag) === bitflag;
|
|
155
|
-
}
|
|
156
|
-
if (!result_hasTrait_0_$f) return;
|
|
154
|
+
if (!hasTrait(world, entity, trait2)) return;
|
|
157
155
|
if (!ctx.traitData.has(trait2)) registerTrait(world, trait2);
|
|
158
156
|
const data = ctx.traitData.get(trait2);
|
|
159
157
|
for (const changedMask of ctx.changedMasks.values()) {
|
|
160
|
-
const eid = entity
|
|
158
|
+
const eid = getEntityId(entity);
|
|
161
159
|
const data2 = ctx.traitData.get(trait2);
|
|
162
160
|
const {
|
|
163
161
|
generationId,
|
|
@@ -350,21 +348,7 @@ function addTrait(world, entity, ...traits) {
|
|
|
350
348
|
} else {
|
|
351
349
|
trait2 = traits[i];
|
|
352
350
|
}
|
|
353
|
-
|
|
354
|
-
const ctx_0_$f = world[$internal];
|
|
355
|
-
const data_0_$f = ctx_0_$f.traitData.get(trait2);
|
|
356
|
-
if (!data_0_$f) {
|
|
357
|
-
result_hasTrait_0_$f = false;
|
|
358
|
-
} else {
|
|
359
|
-
const {
|
|
360
|
-
generationId: generationId2,
|
|
361
|
-
bitflag: bitflag2
|
|
362
|
-
} = data_0_$f;
|
|
363
|
-
const eid_0_$f = entity & ENTITY_ID_MASK;
|
|
364
|
-
const mask_0_$f = ctx_0_$f.entityMasks[generationId2][eid_0_$f];
|
|
365
|
-
result_hasTrait_0_$f = (mask_0_$f & bitflag2) === bitflag2;
|
|
366
|
-
}
|
|
367
|
-
if (result_hasTrait_0_$f) continue;
|
|
351
|
+
if (hasTrait(world, entity, trait2)) continue;
|
|
368
352
|
const traitCtx = trait2[$internal];
|
|
369
353
|
if (!ctx.traitData.has(trait2)) registerTrait(world, trait2);
|
|
370
354
|
const data = ctx.traitData.get(trait2);
|
|
@@ -373,7 +357,7 @@ function addTrait(world, entity, ...traits) {
|
|
|
373
357
|
bitflag,
|
|
374
358
|
queries
|
|
375
359
|
} = data;
|
|
376
|
-
const eid = entity
|
|
360
|
+
const eid = getEntityId(entity);
|
|
377
361
|
ctx.entityMasks[generationId][eid] |= bitflag;
|
|
378
362
|
for (const dirtyMask of ctx.dirtyMasks.values()) {
|
|
379
363
|
if (!dirtyMask[generationId]) dirtyMask[generationId] = [];
|
|
@@ -429,21 +413,7 @@ function removeTrait(world, entity, ...traits) {
|
|
|
429
413
|
for (let i = 0; i < traits.length; i++) {
|
|
430
414
|
const trait2 = traits[i];
|
|
431
415
|
const traitCtx = trait2[$internal];
|
|
432
|
-
|
|
433
|
-
const ctx_3_$f = world[$internal];
|
|
434
|
-
const data_3_$f = ctx_3_$f.traitData.get(trait2);
|
|
435
|
-
if (!data_3_$f) {
|
|
436
|
-
result_hasTrait_3_$f = false;
|
|
437
|
-
} else {
|
|
438
|
-
const {
|
|
439
|
-
generationId: generationId2,
|
|
440
|
-
bitflag: bitflag2
|
|
441
|
-
} = data_3_$f;
|
|
442
|
-
const eid_3_$f = entity & ENTITY_ID_MASK;
|
|
443
|
-
const mask_3_$f = ctx_3_$f.entityMasks[generationId2][eid_3_$f];
|
|
444
|
-
result_hasTrait_3_$f = (mask_3_$f & bitflag2) === bitflag2;
|
|
445
|
-
}
|
|
446
|
-
if (!result_hasTrait_3_$f) continue;
|
|
416
|
+
if (!hasTrait(world, entity, trait2)) continue;
|
|
447
417
|
const data = ctx.traitData.get(trait2);
|
|
448
418
|
const {
|
|
449
419
|
generationId,
|
|
@@ -453,7 +423,7 @@ function removeTrait(world, entity, ...traits) {
|
|
|
453
423
|
for (const sub of data.removeSubscriptions) {
|
|
454
424
|
sub(entity);
|
|
455
425
|
}
|
|
456
|
-
const eid = entity
|
|
426
|
+
const eid = getEntityId(entity);
|
|
457
427
|
ctx.entityMasks[generationId][eid] &= ~bitflag;
|
|
458
428
|
for (const dirtyMask of ctx.dirtyMasks.values()) {
|
|
459
429
|
dirtyMask[generationId][eid] |= bitflag;
|
|
@@ -472,7 +442,9 @@ function removeTrait(world, entity, ...traits) {
|
|
|
472
442
|
ctx.relationTargetEntities.delete(entity);
|
|
473
443
|
}
|
|
474
444
|
const target = traitCtx.pairTarget;
|
|
475
|
-
|
|
445
|
+
if (!hasRelationToTarget(world, entity, target)) {
|
|
446
|
+
removeTrait(world, entity, Pair(Wildcard, target));
|
|
447
|
+
}
|
|
476
448
|
const relation2 = traitCtx.relation;
|
|
477
449
|
const otherTargets = getRelationTargets(world, relation2, entity);
|
|
478
450
|
if (otherTargets.length === 0) {
|
|
@@ -488,6 +460,18 @@ function removeTrait(world, entity, ...traits) {
|
|
|
488
460
|
}
|
|
489
461
|
}
|
|
490
462
|
}
|
|
463
|
+
function hasTrait(world, entity, trait2) {
|
|
464
|
+
const ctx = world[$internal];
|
|
465
|
+
const data = ctx.traitData.get(trait2);
|
|
466
|
+
if (!data) return false;
|
|
467
|
+
const {
|
|
468
|
+
generationId,
|
|
469
|
+
bitflag
|
|
470
|
+
} = data;
|
|
471
|
+
const eid = getEntityId(entity);
|
|
472
|
+
const mask = ctx.entityMasks[generationId][eid];
|
|
473
|
+
return (mask & bitflag) === bitflag;
|
|
474
|
+
}
|
|
491
475
|
function getStore(world, trait2) {
|
|
492
476
|
const ctx = world[$internal];
|
|
493
477
|
const data = ctx.traitData.get(trait2);
|
|
@@ -495,34 +479,18 @@ function getStore(world, trait2) {
|
|
|
495
479
|
}
|
|
496
480
|
function setTrait(world, entity, trait2, value, triggerChanged = true) {
|
|
497
481
|
const ctx = trait2[$internal];
|
|
498
|
-
const
|
|
499
|
-
const
|
|
500
|
-
const store = data_7_$f.store;
|
|
501
|
-
const index = entity & ENTITY_ID_MASK;
|
|
482
|
+
const store = getStore(world, trait2);
|
|
483
|
+
const index = getEntityId(entity);
|
|
502
484
|
value instanceof Function && (value = value(ctx.get(index, store)));
|
|
503
485
|
ctx.set(index, store, value);
|
|
504
486
|
triggerChanged && setChanged(world, entity, trait2);
|
|
505
487
|
}
|
|
506
488
|
function getTrait(world, entity, trait2) {
|
|
507
|
-
|
|
508
|
-
const ctx_9_$f = world[$internal];
|
|
509
|
-
const data_9_$f = ctx_9_$f.traitData.get(trait2);
|
|
510
|
-
if (!data_9_$f) {
|
|
511
|
-
result_hasTrait_9_$f = false;
|
|
512
|
-
} else {
|
|
513
|
-
const {
|
|
514
|
-
generationId,
|
|
515
|
-
bitflag
|
|
516
|
-
} = data_9_$f;
|
|
517
|
-
const eid_9_$f = entity & ENTITY_ID_MASK;
|
|
518
|
-
const mask_9_$f = ctx_9_$f.entityMasks[generationId][eid_9_$f];
|
|
519
|
-
result_hasTrait_9_$f = (mask_9_$f & bitflag) === bitflag;
|
|
520
|
-
}
|
|
521
|
-
const result = result_hasTrait_9_$f;
|
|
489
|
+
const result = hasTrait(world, entity, trait2);
|
|
522
490
|
if (!result) return void 0;
|
|
523
491
|
const traitCtx = trait2[$internal];
|
|
524
|
-
const store =
|
|
525
|
-
return traitCtx.get(entity
|
|
492
|
+
const store = getStore(world, trait2);
|
|
493
|
+
return traitCtx.get(getEntityId(entity), store);
|
|
526
494
|
}
|
|
527
495
|
|
|
528
496
|
// ../core/src/relation/relation.ts
|
|
@@ -568,6 +536,18 @@ var getRelationTargets = (world, relation2, entity) => {
|
|
|
568
536
|
}
|
|
569
537
|
return targets;
|
|
570
538
|
};
|
|
539
|
+
var hasRelationToTarget = (world, entity, target) => {
|
|
540
|
+
const ctx = world[$internal];
|
|
541
|
+
const traits = ctx.entityTraits.get(entity);
|
|
542
|
+
if (!traits) return false;
|
|
543
|
+
for (const trait2 of traits) {
|
|
544
|
+
const traitCtx = trait2[$internal];
|
|
545
|
+
if (traitCtx.isPairTrait && traitCtx.pairTarget === target && traitCtx.relation !== Wildcard) {
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return false;
|
|
550
|
+
};
|
|
571
551
|
var Pair = (relation2, target) => {
|
|
572
552
|
if (relation2 === void 0) throw Error("Relation is undefined");
|
|
573
553
|
if (target === void 0) throw Error("Relation target is undefined");
|
|
@@ -673,28 +653,11 @@ function createQueryResult(world, entities, query) {
|
|
|
673
653
|
const atomicSnapshots = [];
|
|
674
654
|
const trackedIndices = [];
|
|
675
655
|
const untrackedIndices = [];
|
|
676
|
-
|
|
677
|
-
const trait_0_$f = traits[i_0_$f];
|
|
678
|
-
const hasTracked_0_$f = world[$internal].trackedTraits.has(trait_0_$f);
|
|
679
|
-
const hasChanged_0_$f = query.hasChangedModifiers && query.changedTraits.has(trait_0_$f);
|
|
680
|
-
if (hasTracked_0_$f || hasChanged_0_$f) {
|
|
681
|
-
trackedIndices.push(i_0_$f);
|
|
682
|
-
} else {
|
|
683
|
-
untrackedIndices.push(i_0_$f);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
656
|
+
getTrackedTraits(traits, world, query, trackedIndices, untrackedIndices);
|
|
686
657
|
for (let i = 0; i < entities.length; i++) {
|
|
687
658
|
const entity = entities[i];
|
|
688
|
-
const eid = entity
|
|
689
|
-
|
|
690
|
-
const trait_2_$f = traits[j_2_$f];
|
|
691
|
-
const ctx_2_$f = trait_2_$f[$internal];
|
|
692
|
-
const value_2_$f = ctx_2_$f.get(eid, stores[j_2_$f]);
|
|
693
|
-
state[j_2_$f] = value_2_$f;
|
|
694
|
-
atomicSnapshots[j_2_$f] = ctx_2_$f.type === "aos" ? {
|
|
695
|
-
...value_2_$f
|
|
696
|
-
} : null;
|
|
697
|
-
}
|
|
659
|
+
const eid = getEntityId(entity);
|
|
660
|
+
createSnapshotsWithAtomic(eid, traits, stores, state, atomicSnapshots);
|
|
698
661
|
callback(state, entity, i);
|
|
699
662
|
if (!world.has(entity)) continue;
|
|
700
663
|
for (let j = 0; j < trackedIndices.length; j++) {
|
|
@@ -731,16 +694,8 @@ function createQueryResult(world, entities, query) {
|
|
|
731
694
|
const atomicSnapshots = [];
|
|
732
695
|
for (let i = 0; i < entities.length; i++) {
|
|
733
696
|
const entity = entities[i];
|
|
734
|
-
const eid = entity
|
|
735
|
-
|
|
736
|
-
const trait_4_$f = traits[j_4_$f];
|
|
737
|
-
const ctx_4_$f = trait_4_$f[$internal];
|
|
738
|
-
const value_4_$f = ctx_4_$f.get(eid, stores[j_4_$f]);
|
|
739
|
-
state[j_4_$f] = value_4_$f;
|
|
740
|
-
atomicSnapshots[j_4_$f] = ctx_4_$f.type === "aos" ? {
|
|
741
|
-
...value_4_$f
|
|
742
|
-
} : null;
|
|
743
|
-
}
|
|
697
|
+
const eid = getEntityId(entity);
|
|
698
|
+
createSnapshotsWithAtomic(eid, traits, stores, state, atomicSnapshots);
|
|
744
699
|
callback(state, entity, i);
|
|
745
700
|
if (!world.has(entity)) continue;
|
|
746
701
|
for (let j = 0; j < traits.length; j++) {
|
|
@@ -766,13 +721,8 @@ function createQueryResult(world, entities, query) {
|
|
|
766
721
|
} else if (options.changeDetection === "never") {
|
|
767
722
|
for (let i = 0; i < entities.length; i++) {
|
|
768
723
|
const entity = entities[i];
|
|
769
|
-
const eid = entity
|
|
770
|
-
|
|
771
|
-
const trait_6_$f = traits[i_6_$f];
|
|
772
|
-
const ctx_6_$f = trait_6_$f[$internal];
|
|
773
|
-
const value_6_$f = ctx_6_$f.get(eid, stores[i_6_$f]);
|
|
774
|
-
state[i_6_$f] = value_6_$f;
|
|
775
|
-
}
|
|
724
|
+
const eid = getEntityId(entity);
|
|
725
|
+
createSnapshots(eid, traits, stores, state);
|
|
776
726
|
callback(state, entity, i);
|
|
777
727
|
if (!world.has(entity)) continue;
|
|
778
728
|
for (let j = 0; j < traits.length; j++) {
|
|
@@ -791,44 +741,62 @@ function createQueryResult(world, entities, query) {
|
|
|
791
741
|
select(...params) {
|
|
792
742
|
traits.length = 0;
|
|
793
743
|
stores.length = 0;
|
|
794
|
-
|
|
795
|
-
const param_7_$f = params[i_7_$f];
|
|
796
|
-
if (isModifier(param_7_$f)) {
|
|
797
|
-
if (param_7_$f.type === "not") {
|
|
798
|
-
continue;
|
|
799
|
-
} else {
|
|
800
|
-
const modifierTraits_7_$f = param_7_$f.traits;
|
|
801
|
-
for (const trait_7_$f of modifierTraits_7_$f) {
|
|
802
|
-
if (trait_7_$f[$internal].isTag) {
|
|
803
|
-
continue;
|
|
804
|
-
} else {
|
|
805
|
-
traits.push(trait_7_$f);
|
|
806
|
-
const ctx_8_$f = world[$internal];
|
|
807
|
-
const data_8_$f = ctx_8_$f.traitData.get(trait_7_$f);
|
|
808
|
-
stores.push(data_8_$f.store);
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
} else {
|
|
813
|
-
if (param_7_$f[$internal].isTag) {
|
|
814
|
-
continue;
|
|
815
|
-
} else {
|
|
816
|
-
traits.push(param_7_$f);
|
|
817
|
-
const ctx_9_$f = world[$internal];
|
|
818
|
-
const data_9_$f = ctx_9_$f.traitData.get(param_7_$f);
|
|
819
|
-
stores.push(data_9_$f.store);
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
}
|
|
744
|
+
getQueryStores(params, traits, stores, world);
|
|
823
745
|
return results;
|
|
824
746
|
},
|
|
825
|
-
sort(callback = (a, b) => (a
|
|
747
|
+
sort(callback = (a, b) => getEntityId(a) - getEntityId(b)) {
|
|
826
748
|
Array.prototype.sort.call(entities, callback);
|
|
827
749
|
return results;
|
|
828
750
|
}
|
|
829
751
|
});
|
|
830
752
|
return results;
|
|
831
753
|
}
|
|
754
|
+
function getTrackedTraits(traits, world, query, trackedIndices, untrackedIndices) {
|
|
755
|
+
for (let i = 0; i < traits.length; i++) {
|
|
756
|
+
const trait2 = traits[i];
|
|
757
|
+
const hasTracked = world[$internal].trackedTraits.has(trait2);
|
|
758
|
+
const hasChanged = query.hasChangedModifiers && query.changedTraits.has(trait2);
|
|
759
|
+
if (hasTracked || hasChanged) trackedIndices.push(i);
|
|
760
|
+
else untrackedIndices.push(i);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
function createSnapshots(entityId, traits, stores, state) {
|
|
764
|
+
for (let i = 0; i < traits.length; i++) {
|
|
765
|
+
const trait2 = traits[i];
|
|
766
|
+
const ctx = trait2[$internal];
|
|
767
|
+
const value = ctx.get(entityId, stores[i]);
|
|
768
|
+
state[i] = value;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
function createSnapshotsWithAtomic(entityId, traits, stores, state, atomicSnapshots) {
|
|
772
|
+
for (let j = 0; j < traits.length; j++) {
|
|
773
|
+
const trait2 = traits[j];
|
|
774
|
+
const ctx = trait2[$internal];
|
|
775
|
+
const value = ctx.get(entityId, stores[j]);
|
|
776
|
+
state[j] = value;
|
|
777
|
+
atomicSnapshots[j] = ctx.type === "aos" ? {
|
|
778
|
+
...value
|
|
779
|
+
} : null;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
function getQueryStores(params, traits, stores, world) {
|
|
783
|
+
for (let i = 0; i < params.length; i++) {
|
|
784
|
+
const param = params[i];
|
|
785
|
+
if (isModifier(param)) {
|
|
786
|
+
if (param.type === "not") continue;
|
|
787
|
+
const modifierTraits = param.traits;
|
|
788
|
+
for (const trait2 of modifierTraits) {
|
|
789
|
+
if (trait2[$internal].isTag) continue;
|
|
790
|
+
traits.push(trait2);
|
|
791
|
+
stores.push(getStore(world, trait2));
|
|
792
|
+
}
|
|
793
|
+
} else {
|
|
794
|
+
if (param[$internal].isTag) continue;
|
|
795
|
+
traits.push(param);
|
|
796
|
+
stores.push(getStore(world, param));
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
832
800
|
function createEmptyQueryResult() {
|
|
833
801
|
const results = Object.assign([], {
|
|
834
802
|
updateEach: () => results,
|
|
@@ -869,7 +837,7 @@ var allocateEntity = (index) => {
|
|
|
869
837
|
if (index.aliveCount < index.dense.length) {
|
|
870
838
|
const recycledEntity = incrementGeneration(index.dense[index.aliveCount]);
|
|
871
839
|
index.dense[index.aliveCount] = recycledEntity;
|
|
872
|
-
index.sparse[recycledEntity
|
|
840
|
+
index.sparse[getEntityId(recycledEntity)] = index.aliveCount;
|
|
873
841
|
index.aliveCount++;
|
|
874
842
|
return recycledEntity;
|
|
875
843
|
}
|
|
@@ -881,92 +849,69 @@ var allocateEntity = (index) => {
|
|
|
881
849
|
return entity;
|
|
882
850
|
};
|
|
883
851
|
var releaseEntity = (index, entity) => {
|
|
884
|
-
const id = entity
|
|
852
|
+
const id = getEntityId(entity);
|
|
885
853
|
const denseIndex = index.sparse[id];
|
|
886
854
|
if (denseIndex === void 0 || denseIndex >= index.aliveCount) return;
|
|
887
855
|
const lastIndex = index.aliveCount - 1;
|
|
888
856
|
const lastEntity = index.dense[lastIndex];
|
|
889
|
-
const lastId = lastEntity
|
|
857
|
+
const lastId = getEntityId(lastEntity);
|
|
890
858
|
index.sparse[lastId] = denseIndex;
|
|
891
859
|
index.dense[denseIndex] = lastEntity;
|
|
892
860
|
index.sparse[id] = lastIndex;
|
|
893
861
|
index.dense[lastIndex] = entity;
|
|
894
862
|
index.aliveCount--;
|
|
895
863
|
};
|
|
864
|
+
var isEntityAlive = (
|
|
865
|
+
/* @inline @pure */
|
|
866
|
+
(index, entity) => {
|
|
867
|
+
const denseIndex = index.sparse[getEntityId(entity)];
|
|
868
|
+
if (denseIndex === void 0 || denseIndex >= index.aliveCount) return false;
|
|
869
|
+
const storedEntity = index.dense[denseIndex];
|
|
870
|
+
return getEntityGeneration(entity) === getEntityGeneration(storedEntity) && getEntityWorldId(entity) === index.worldId;
|
|
871
|
+
}
|
|
872
|
+
);
|
|
896
873
|
var getAliveEntities = (index) => {
|
|
897
874
|
return index.dense.slice(0, index.aliveCount);
|
|
898
875
|
};
|
|
899
876
|
|
|
900
877
|
// ../core/src/entity/entity-methods-patch.ts
|
|
901
878
|
Number.prototype.add = function(...traits) {
|
|
902
|
-
|
|
903
|
-
return addTrait(universe.worlds[worldId_0_$f], this, ...traits);
|
|
879
|
+
return addTrait(getEntityWorld(this), this, ...traits);
|
|
904
880
|
};
|
|
905
881
|
Number.prototype.remove = function(...traits) {
|
|
906
|
-
|
|
907
|
-
return removeTrait(universe.worlds[worldId_1_$f], this, ...traits);
|
|
882
|
+
return removeTrait(getEntityWorld(this), this, ...traits);
|
|
908
883
|
};
|
|
909
884
|
Number.prototype.has = function(trait2) {
|
|
910
|
-
|
|
911
|
-
const worldId_3_$f = this >>> WORLD_ID_SHIFT;
|
|
912
|
-
const ctx_2_$f = universe.worlds[worldId_3_$f][$internal];
|
|
913
|
-
const data_2_$f = ctx_2_$f.traitData.get(trait2);
|
|
914
|
-
if (!data_2_$f) {
|
|
915
|
-
result_hasTrait_2_$f = false;
|
|
916
|
-
} else {
|
|
917
|
-
const {
|
|
918
|
-
generationId,
|
|
919
|
-
bitflag
|
|
920
|
-
} = data_2_$f;
|
|
921
|
-
const eid_2_$f = this & ENTITY_ID_MASK;
|
|
922
|
-
const mask_2_$f = ctx_2_$f.entityMasks[generationId][eid_2_$f];
|
|
923
|
-
result_hasTrait_2_$f = (mask_2_$f & bitflag) === bitflag;
|
|
924
|
-
}
|
|
925
|
-
return result_hasTrait_2_$f;
|
|
885
|
+
return hasTrait(getEntityWorld(this), this, trait2);
|
|
926
886
|
};
|
|
927
887
|
Number.prototype.destroy = function() {
|
|
928
|
-
|
|
929
|
-
return destroyEntity(universe.worlds[worldId_4_$f], this);
|
|
888
|
+
return destroyEntity(getEntityWorld(this), this);
|
|
930
889
|
};
|
|
931
890
|
Number.prototype.changed = function(trait2) {
|
|
932
|
-
|
|
933
|
-
return setChanged(universe.worlds[worldId_5_$f], this, trait2);
|
|
891
|
+
return setChanged(getEntityWorld(this), this, trait2);
|
|
934
892
|
};
|
|
935
893
|
Number.prototype.get = function(trait2) {
|
|
936
|
-
|
|
937
|
-
return getTrait(universe.worlds[worldId_6_$f], this, trait2);
|
|
894
|
+
return getTrait(getEntityWorld(this), this, trait2);
|
|
938
895
|
};
|
|
939
896
|
Number.prototype.set = function(trait2, value, triggerChanged = true) {
|
|
940
|
-
|
|
941
|
-
setTrait(universe.worlds[worldId_7_$f], this, trait2, value, triggerChanged);
|
|
897
|
+
setTrait(getEntityWorld(this), this, trait2, value, triggerChanged);
|
|
942
898
|
};
|
|
943
899
|
Number.prototype.targetsFor = function(relation2) {
|
|
944
|
-
|
|
945
|
-
return getRelationTargets(universe.worlds[worldId_8_$f], relation2, this);
|
|
900
|
+
return getRelationTargets(getEntityWorld(this), relation2, this);
|
|
946
901
|
};
|
|
947
902
|
Number.prototype.targetFor = function(relation2) {
|
|
948
|
-
|
|
949
|
-
return getRelationTargets(universe.worlds[worldId_9_$f], relation2, this)[0];
|
|
903
|
+
return getRelationTargets(getEntityWorld(this), relation2, this)[0];
|
|
950
904
|
};
|
|
951
905
|
Number.prototype.id = function() {
|
|
952
|
-
return this
|
|
906
|
+
return getEntityId(this);
|
|
953
907
|
};
|
|
954
908
|
Number.prototype.generation = function() {
|
|
955
|
-
return this
|
|
909
|
+
return getEntityGeneration(this);
|
|
956
910
|
};
|
|
957
911
|
Number.prototype.isAlive = function() {
|
|
958
|
-
const
|
|
959
|
-
const world = universe.worlds[worldId_12_$f];
|
|
912
|
+
const world = getEntityWorld(this);
|
|
960
913
|
const entityIndex = world[$internal].entityIndex;
|
|
961
|
-
|
|
962
|
-
const denseIndex_13_$f = entityIndex.sparse[this & ENTITY_ID_MASK];
|
|
963
|
-
if (denseIndex_13_$f === void 0 || denseIndex_13_$f >= entityIndex.aliveCount) {
|
|
964
|
-
result_isEntityAlive_13_$f = false;
|
|
965
|
-
} else {
|
|
966
|
-
const storedEntity_13_$f = entityIndex.dense[denseIndex_13_$f];
|
|
967
|
-
result_isEntityAlive_13_$f = (this >>> GENERATION_SHIFT & GENERATION_MASK) === (storedEntity_13_$f >>> GENERATION_SHIFT & GENERATION_MASK) && this >>> WORLD_ID_SHIFT === entityIndex.worldId;
|
|
968
|
-
}
|
|
969
|
-
return result_isEntityAlive_13_$f;
|
|
914
|
+
return isEntityAlive(entityIndex, this);
|
|
970
915
|
};
|
|
971
916
|
|
|
972
917
|
// ../core/src/entity/entity.ts
|
|
@@ -976,7 +921,7 @@ function createEntity(world, ...traits) {
|
|
|
976
921
|
for (const query of ctx.notQueries) {
|
|
977
922
|
const match = query.check(world, entity);
|
|
978
923
|
if (match) query.add(entity);
|
|
979
|
-
query.resetTrackingBitmasks(entity
|
|
924
|
+
query.resetTrackingBitmasks(getEntityId(entity));
|
|
980
925
|
}
|
|
981
926
|
ctx.entityTraits.set(entity, /* @__PURE__ */ new Set());
|
|
982
927
|
addTrait(world, entity, ...traits);
|
|
@@ -1023,12 +968,16 @@ function destroyEntity(world, entity) {
|
|
|
1023
968
|
const allQuery = ctx.queriesHashMap.get("");
|
|
1024
969
|
if (allQuery) allQuery.remove(world, currentEntity);
|
|
1025
970
|
ctx.entityTraits.delete(entity);
|
|
1026
|
-
const eid = currentEntity
|
|
971
|
+
const eid = getEntityId(currentEntity);
|
|
1027
972
|
for (let i = 0; i < ctx.entityMasks.length; i++) {
|
|
1028
973
|
ctx.entityMasks[i][eid] = 0;
|
|
1029
974
|
}
|
|
1030
975
|
}
|
|
1031
976
|
}
|
|
977
|
+
function getEntityWorld(entity) {
|
|
978
|
+
const worldId = getEntityWorldId(entity);
|
|
979
|
+
return universe.worlds[worldId];
|
|
980
|
+
}
|
|
1032
981
|
|
|
1033
982
|
// ../core/src/world/world.ts
|
|
1034
983
|
var World = class {
|
|
@@ -1093,29 +1042,7 @@ var World = class {
|
|
|
1093
1042
|
return createEntity(this, ...traits);
|
|
1094
1043
|
}
|
|
1095
1044
|
has(target) {
|
|
1096
|
-
|
|
1097
|
-
const denseIndex_0_$f = this[$internal].entityIndex.sparse[target & ENTITY_ID_MASK];
|
|
1098
|
-
if (denseIndex_0_$f === void 0 || denseIndex_0_$f >= this[$internal].entityIndex.aliveCount) {
|
|
1099
|
-
result_isEntityAlive_0_$f = false;
|
|
1100
|
-
} else {
|
|
1101
|
-
const storedEntity_0_$f = this[$internal].entityIndex.dense[denseIndex_0_$f];
|
|
1102
|
-
result_isEntityAlive_0_$f = (target >>> GENERATION_SHIFT & GENERATION_MASK) === (storedEntity_0_$f >>> GENERATION_SHIFT & GENERATION_MASK) && target >>> WORLD_ID_SHIFT === this[$internal].entityIndex.worldId;
|
|
1103
|
-
}
|
|
1104
|
-
let result_hasTrait_1_$f;
|
|
1105
|
-
const ctx_1_$f = this[$internal];
|
|
1106
|
-
const data_1_$f = ctx_1_$f.traitData.get(target);
|
|
1107
|
-
if (!data_1_$f) {
|
|
1108
|
-
result_hasTrait_1_$f = false;
|
|
1109
|
-
} else {
|
|
1110
|
-
const {
|
|
1111
|
-
generationId,
|
|
1112
|
-
bitflag
|
|
1113
|
-
} = data_1_$f;
|
|
1114
|
-
const eid_1_$f = this[$internal].worldEntity & ENTITY_ID_MASK;
|
|
1115
|
-
const mask_1_$f = ctx_1_$f.entityMasks[generationId][eid_1_$f];
|
|
1116
|
-
result_hasTrait_1_$f = (mask_1_$f & bitflag) === bitflag;
|
|
1117
|
-
}
|
|
1118
|
-
return typeof target === "number" ? result_isEntityAlive_0_$f : result_hasTrait_1_$f;
|
|
1045
|
+
return typeof target === "number" ? isEntityAlive(this[$internal].entityIndex, target) : hasTrait(this, this[$internal].worldEntity, target);
|
|
1119
1046
|
}
|
|
1120
1047
|
add(...traits) {
|
|
1121
1048
|
addTrait(this, this[$internal].worldEntity, ...traits);
|
|
@@ -1160,6 +1087,10 @@ var World = class {
|
|
|
1160
1087
|
ctx.changedMasks.clear();
|
|
1161
1088
|
ctx.trackedTraits.clear();
|
|
1162
1089
|
ctx.worldEntity = createEntity(this, IsExcluded);
|
|
1090
|
+
for (const [hash, parameters] of universe.cachedQueries) {
|
|
1091
|
+
const query = createQuery(this, parameters);
|
|
1092
|
+
ctx.queriesHashMap.set(hash, query);
|
|
1093
|
+
}
|
|
1163
1094
|
for (const sub of ctx.resetSubscriptions) {
|
|
1164
1095
|
sub(this);
|
|
1165
1096
|
}
|
|
@@ -1314,7 +1245,7 @@ function checkQuery(world, query, entity, event) {
|
|
|
1314
1245
|
generations
|
|
1315
1246
|
} = query;
|
|
1316
1247
|
const ctx = world[$internal];
|
|
1317
|
-
const eid = entity
|
|
1248
|
+
const eid = getEntityId(entity);
|
|
1318
1249
|
if (query.traitData.all.length === 0) return false;
|
|
1319
1250
|
for (let i = 0; i < generations.length; i++) {
|
|
1320
1251
|
const generationId = generations[i];
|
|
@@ -1536,7 +1467,7 @@ function createQuery(world, parameters) {
|
|
|
1536
1467
|
const changedMask = ctx.changedMasks.get(id);
|
|
1537
1468
|
for (const entity of ctx.entityIndex.dense) {
|
|
1538
1469
|
let allTraitsMatch = true;
|
|
1539
|
-
const eid = entity
|
|
1470
|
+
const eid = getEntityId(entity);
|
|
1540
1471
|
for (const trait2 of traits) {
|
|
1541
1472
|
const {
|
|
1542
1473
|
generationId,
|
|
@@ -1576,35 +1507,7 @@ function createQuery(world, parameters) {
|
|
|
1576
1507
|
}
|
|
1577
1508
|
}
|
|
1578
1509
|
}
|
|
1579
|
-
|
|
1580
|
-
const param_2_$f = parameters[i_2_$f];
|
|
1581
|
-
if (isModifier(param_2_$f)) {
|
|
1582
|
-
if (param_2_$f.type === "not") {
|
|
1583
|
-
continue;
|
|
1584
|
-
} else {
|
|
1585
|
-
const modifierTraits_2_$f = param_2_$f.traits;
|
|
1586
|
-
for (const trait_2_$f of modifierTraits_2_$f) {
|
|
1587
|
-
if (trait_2_$f[$internal].isTag) {
|
|
1588
|
-
continue;
|
|
1589
|
-
} else {
|
|
1590
|
-
query.resultTraits.push(trait_2_$f);
|
|
1591
|
-
const ctx_3_$f = world[$internal];
|
|
1592
|
-
const data_3_$f = ctx_3_$f.traitData.get(trait_2_$f);
|
|
1593
|
-
query.resultStores.push(data_3_$f.store);
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1597
|
-
} else {
|
|
1598
|
-
if (param_2_$f[$internal].isTag) {
|
|
1599
|
-
continue;
|
|
1600
|
-
} else {
|
|
1601
|
-
query.resultTraits.push(param_2_$f);
|
|
1602
|
-
const ctx_4_$f = world[$internal];
|
|
1603
|
-
const data_4_$f = ctx_4_$f.traitData.get(param_2_$f);
|
|
1604
|
-
query.resultStores.push(data_4_$f.store);
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1510
|
+
getQueryStores(parameters, query.resultTraits, query.resultStores, world);
|
|
1608
1511
|
return query;
|
|
1609
1512
|
}
|
|
1610
1513
|
|