koota 0.2.2 → 0.2.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.
@@ -38,6 +38,137 @@ var getEntityGeneration = (entity) => entity >>> GENERATION_SHIFT & GENERATION_M
38
38
  var incrementGeneration = (entity) => entity & ~(GENERATION_MASK << GENERATION_SHIFT) | // Clear current generation bits
39
39
  ((entity >>> GENERATION_SHIFT & GENERATION_MASK) + 1 & GENERATION_MASK) << GENERATION_SHIFT;
40
40
 
41
+ // ../core/src/world/utils/world-index.ts
42
+ function createWorldIndex() {
43
+ return {
44
+ worldCursor: 0,
45
+ releasedWorldIds: [],
46
+ maxWorlds: 2 ** WORLD_ID_BITS
47
+ };
48
+ }
49
+ function allocateWorldId(index) {
50
+ if (index.releasedWorldIds.length > 0) {
51
+ return index.releasedWorldIds.pop();
52
+ }
53
+ if (index.worldCursor >= index.maxWorlds) {
54
+ throw new Error(`Koota: Too many worlds created. The maximum is ${index.maxWorlds}.`);
55
+ }
56
+ return index.worldCursor++;
57
+ }
58
+ function releaseWorldId(index, worldId) {
59
+ if (worldId < 0 || worldId >= index.maxWorlds) {
60
+ throw new Error(`Invalid world ID: ${worldId}`);
61
+ }
62
+ if (worldId === index.worldCursor - 1) {
63
+ index.worldCursor--;
64
+ } else if (worldId < index.worldCursor && !index.releasedWorldIds.includes(worldId)) {
65
+ index.releasedWorldIds.push(worldId);
66
+ }
67
+ }
68
+
69
+ // ../core/src/universe/universe.ts
70
+ var universe = {
71
+ worlds: new Array(WORLD_ID_BITS ** 2),
72
+ cachedQueries: /* @__PURE__ */ new Map(),
73
+ worldIndex: createWorldIndex(),
74
+ reset: () => {
75
+ universe.worlds = new Array(WORLD_ID_BITS ** 2);
76
+ universe.cachedQueries = /* @__PURE__ */ new Map();
77
+ universe.worldIndex = createWorldIndex();
78
+ }
79
+ };
80
+
81
+ // ../core/src/query/modifier.ts
82
+ var ModifierData = class {
83
+ constructor(type, id, traits) {
84
+ this.type = type;
85
+ this.id = id;
86
+ this.traits = traits;
87
+ __publicField(this, "traitIds");
88
+ this.traitIds = traits.map((trait2) => trait2[$internal].id);
89
+ }
90
+ };
91
+
92
+ // ../core/src/query/utils/tracking-cursor.ts
93
+ var cursor = 3;
94
+ function createTrackingId() {
95
+ return cursor++;
96
+ }
97
+ function getTrackingCursor() {
98
+ return cursor;
99
+ }
100
+ function setTrackingMasks(world, id) {
101
+ const ctx = world[$internal];
102
+ const snapshot = structuredClone(ctx.entityMasks);
103
+ ctx.trackingSnapshots.set(id, snapshot);
104
+ ctx.dirtyMasks.set(
105
+ id,
106
+ snapshot.map((mask) => mask.map(() => 0))
107
+ );
108
+ ctx.changedMasks.set(
109
+ id,
110
+ snapshot.map((mask) => mask.map(() => 0))
111
+ );
112
+ }
113
+
114
+ // ../core/src/relation/relation.ts
115
+ function defineRelation(definition) {
116
+ const pairsMap = /* @__PURE__ */ new Map();
117
+ const traitFactory = () => trait(definition?.store ?? {});
118
+ function relationFn(target) {
119
+ if (target === void 0) throw Error("Relation target is undefined");
120
+ if (target === "*") target = Wildcard;
121
+ return getRelationTrait(
122
+ relationFn,
123
+ traitFactory,
124
+ pairsMap,
125
+ target
126
+ );
127
+ }
128
+ return Object.assign(relationFn, {
129
+ [$internal]: {
130
+ pairsMap,
131
+ createTrait: traitFactory,
132
+ exclusive: definition?.exclusive ?? false,
133
+ autoRemoveTarget: definition?.autoRemoveTarget ?? false
134
+ }
135
+ });
136
+ }
137
+ var relation = defineRelation;
138
+ function getRelationTrait(relation2, traitFactory, pairsMap, target) {
139
+ if (!pairsMap.has(target)) {
140
+ const trait2 = traitFactory();
141
+ const tratCtx = trait2[$internal];
142
+ tratCtx.isPairTrait = true;
143
+ tratCtx.relation = relation2;
144
+ tratCtx.pairTarget = target;
145
+ pairsMap.set(target, trait2);
146
+ }
147
+ return pairsMap.get(target);
148
+ }
149
+ var getRelationTargets = (world, relation2, entity) => {
150
+ const ctx = world[$internal];
151
+ const traits = ctx.entityTraits.get(entity) || [];
152
+ const targets = [];
153
+ for (const trait2 of traits) {
154
+ const traitCtx = trait2[$internal];
155
+ if (traitCtx.relation === relation2 && traitCtx.pairTarget !== Wildcard) {
156
+ targets.push(traitCtx.pairTarget);
157
+ }
158
+ }
159
+ return targets;
160
+ };
161
+ var Pair = (relation2, target) => {
162
+ if (relation2 === void 0) throw Error("Relation is undefined");
163
+ if (target === void 0) throw Error("Relation target is undefined");
164
+ if (target === "*") target = Wildcard;
165
+ const ctx = relation2[$internal];
166
+ const pairsMap = ctx.pairsMap;
167
+ const traitFactory = ctx.createTrait;
168
+ return getRelationTrait(relation2, traitFactory, pairsMap, target);
169
+ };
170
+ var Wildcard = defineRelation();
171
+
41
172
  // ../core/src/world/utils/increment-world-bit-flag.ts
42
173
  var incrementWorldBitflag = (world) => {
43
174
  const ctx = world[$internal];
@@ -227,7 +358,7 @@ function addTrait(world, entity, ...traits) {
227
358
  } else {
228
359
  trait2 = traits[i];
229
360
  }
230
- if (entity.has(trait2)) return;
361
+ if (hasTrait(world, entity, trait2)) return;
231
362
  const traitCtx = trait2[$internal];
232
363
  if (!ctx.traitData.has(trait2)) registerTrait(world, trait2);
233
364
  const data = ctx.traitData.get(trait2);
@@ -249,8 +380,8 @@ function addTrait(world, entity, ...traits) {
249
380
  const target = traitCtx.pairTarget;
250
381
  if (traitCtx.isPairTrait && relation2 !== null && target !== null) {
251
382
  ctx.relationTargetEntities.add(target);
252
- entity.add(Pair(Wildcard, target));
253
- entity.add(Pair(relation2, Wildcard));
383
+ addTrait(world, entity, Pair(Wildcard, target));
384
+ addTrait(world, entity, Pair(relation2, Wildcard));
254
385
  if (relation2[$internal].exclusive === true && target !== Wildcard) {
255
386
  const oldTarget = getRelationTargets(world, relation2, entity)[0];
256
387
  if (oldTarget !== null && oldTarget !== void 0 && oldTarget !== target) {
@@ -267,10 +398,10 @@ function addTrait(world, entity, ...traits) {
267
398
  defaults[key] = data.schema[key];
268
399
  }
269
400
  }
270
- entity.set(trait2, { ...defaults, ...params }, false);
401
+ setTrait(world, entity, trait2, { ...defaults, ...params }, false);
271
402
  } else {
272
403
  const state = params ?? data.schema();
273
- entity.set(trait2, state, false);
404
+ setTrait(world, entity, trait2, state, false);
274
405
  }
275
406
  }
276
407
  }
@@ -279,7 +410,7 @@ function removeTrait(world, entity, ...traits) {
279
410
  for (let i = 0; i < traits.length; i++) {
280
411
  const trait2 = traits[i];
281
412
  const traitCtx = trait2[$internal];
282
- if (!entity.has(trait2)) return;
413
+ if (!hasTrait(world, entity, trait2)) return;
283
414
  const data = ctx.traitData.get(trait2);
284
415
  const { generationId, bitflag, queries } = data;
285
416
  const eid = getEntityId(entity);
@@ -322,136 +453,24 @@ function getStore(world, trait2) {
322
453
  const store = data.store;
323
454
  return store;
324
455
  }
325
-
326
- // ../core/src/relation/relation.ts
327
- function defineRelation(definition) {
328
- const pairsMap = /* @__PURE__ */ new Map();
329
- const traitFactory = () => trait(definition?.store ?? {});
330
- function relationFn(target) {
331
- if (target === void 0) throw Error("Relation target is undefined");
332
- if (target === "*") target = Wildcard;
333
- return getRelationTrait(
334
- relationFn,
335
- traitFactory,
336
- pairsMap,
337
- target
338
- );
339
- }
340
- return Object.assign(relationFn, {
341
- [$internal]: {
342
- pairsMap,
343
- createTrait: traitFactory,
344
- exclusive: definition?.exclusive ?? false,
345
- autoRemoveTarget: definition?.autoRemoveTarget ?? false
346
- }
347
- });
348
- }
349
- var relation = defineRelation;
350
- function getRelationTrait(relation2, traitFactory, pairsMap, target) {
351
- if (!pairsMap.has(target)) {
352
- const trait2 = traitFactory();
353
- const tratCtx = trait2[$internal];
354
- tratCtx.isPairTrait = true;
355
- tratCtx.relation = relation2;
356
- tratCtx.pairTarget = target;
357
- pairsMap.set(target, trait2);
358
- }
359
- return pairsMap.get(target);
360
- }
361
- var getRelationTargets = (world, relation2, entity) => {
362
- const ctx = world[$internal];
363
- const traits = ctx.entityTraits.get(entity) || [];
364
- const targets = [];
365
- for (const trait2 of traits) {
366
- const traitCtx = trait2[$internal];
367
- if (traitCtx.relation === relation2 && traitCtx.pairTarget !== Wildcard) {
368
- targets.push(traitCtx.pairTarget);
369
- }
370
- }
371
- return targets;
372
- };
373
- var Pair = (relation2, target) => {
374
- if (relation2 === void 0) throw Error("Relation is undefined");
375
- if (target === void 0) throw Error("Relation target is undefined");
376
- if (target === "*") target = Wildcard;
377
- const ctx = relation2[$internal];
378
- const pairsMap = ctx.pairsMap;
379
- const traitFactory = ctx.createTrait;
380
- return getRelationTrait(relation2, traitFactory, pairsMap, target);
381
- };
382
- var Wildcard = defineRelation();
383
-
384
- // ../core/src/world/utils/world-index.ts
385
- function createWorldIndex() {
386
- return {
387
- worldCursor: 0,
388
- releasedWorldIds: [],
389
- maxWorlds: 2 ** WORLD_ID_BITS
390
- };
391
- }
392
- function allocateWorldId(index) {
393
- if (index.releasedWorldIds.length > 0) {
394
- return index.releasedWorldIds.pop();
395
- }
396
- if (index.worldCursor >= index.maxWorlds) {
397
- throw new Error(`Koota: Too many worlds created. The maximum is ${index.maxWorlds}.`);
398
- }
399
- return index.worldCursor++;
400
- }
401
- function releaseWorldId(index, worldId) {
402
- if (worldId < 0 || worldId >= index.maxWorlds) {
403
- throw new Error(`Invalid world ID: ${worldId}`);
404
- }
405
- if (worldId === index.worldCursor - 1) {
406
- index.worldCursor--;
407
- } else if (worldId < index.worldCursor && !index.releasedWorldIds.includes(worldId)) {
408
- index.releasedWorldIds.push(worldId);
409
- }
410
- }
411
-
412
- // ../core/src/universe/universe.ts
413
- var universe = {
414
- worlds: new Array(WORLD_ID_BITS ** 2),
415
- cachedQueries: /* @__PURE__ */ new Map(),
416
- worldIndex: createWorldIndex(),
417
- reset: () => {
418
- universe.worlds = new Array(WORLD_ID_BITS ** 2);
419
- universe.cachedQueries = /* @__PURE__ */ new Map();
420
- universe.worldIndex = createWorldIndex();
421
- }
422
- };
423
-
424
- // ../core/src/query/modifier.ts
425
- var ModifierData = class {
426
- constructor(type, id, traits) {
427
- this.type = type;
428
- this.id = id;
429
- this.traits = traits;
430
- __publicField(this, "traitIds");
431
- this.traitIds = traits.map((trait2) => trait2[$internal].id);
432
- }
433
- };
434
-
435
- // ../core/src/query/utils/tracking-cursor.ts
436
- var cursor = 3;
437
- function createTrackingId() {
438
- return cursor++;
439
- }
440
- function getTrackingCursor() {
441
- return cursor;
456
+ function setTrait(world, entity, trait2, value, triggerChanged = true) {
457
+ const ctx = trait2[$internal];
458
+ const index = entity & ENTITY_ID_MASK;
459
+ const store = getStore(world, trait2);
460
+ value instanceof Function && (value = value(ctx.get(index, store)));
461
+ ctx.set(index, store, value);
462
+ triggerChanged && setChanged(world, entity, trait2);
442
463
  }
443
- function setTrackingMasks(world, id) {
444
- const ctx = world[$internal];
445
- const snapshot = structuredClone(ctx.entityMasks);
446
- ctx.trackingSnapshots.set(id, snapshot);
447
- ctx.dirtyMasks.set(
448
- id,
449
- snapshot.map((mask) => mask.map(() => 0))
450
- );
451
- ctx.changedMasks.set(
452
- id,
453
- snapshot.map((mask) => mask.map(() => 0))
454
- );
464
+ function getTrait(world, entity, trait2) {
465
+ const worldCtx = world[$internal];
466
+ const data = worldCtx.traitData.get(trait2);
467
+ if (!data) return void 0;
468
+ const index = getEntityId(entity);
469
+ const mask = worldCtx.entityMasks[data.generationId][index];
470
+ if ((mask & data.bitflag) !== data.bitflag) return void 0;
471
+ const traitCtx = trait2[$internal];
472
+ const store = getStore(world, trait2);
473
+ return traitCtx.get(index, store);
455
474
  }
456
475
 
457
476
  // ../core/src/query/modifiers/changed.ts
@@ -465,7 +484,7 @@ function createChanged() {
465
484
  }
466
485
  function setChanged(world, entity, trait2) {
467
486
  const ctx = world[$internal];
468
- if (!entity.has(trait2)) return;
487
+ if (!hasTrait(world, entity, trait2)) return;
469
488
  if (!ctx.traitData.has(trait2)) registerTrait(world, trait2);
470
489
  const data = ctx.traitData.get(trait2);
471
490
  for (const changedMask of ctx.changedMasks.values()) {
@@ -560,24 +579,12 @@ Number.prototype.changed = function(trait2) {
560
579
  Number.prototype.get = function(trait2) {
561
580
  const worldId = this >>> WORLD_ID_SHIFT;
562
581
  const world = universe.worlds[worldId];
563
- const worldCtx = world[$internal];
564
- const data = worldCtx.traitData.get(trait2);
565
- if (!data) return void 0;
566
- const index = this & ENTITY_ID_MASK;
567
- const mask = worldCtx.entityMasks[data.generationId][index];
568
- if ((mask & data.bitflag) !== data.bitflag) return void 0;
569
- const traitCtx = trait2[$internal];
570
- const store = traitCtx.stores[worldId];
571
- return traitCtx.get(index, store);
582
+ return getTrait(world, this, trait2);
572
583
  };
573
584
  Number.prototype.set = function(trait2, value, triggerChanged = true) {
574
- const ctx = trait2[$internal];
575
- const index = this & ENTITY_ID_MASK;
576
585
  const worldId = this >>> WORLD_ID_SHIFT;
577
- const store = ctx.stores[worldId];
578
- value instanceof Function && (value = value(ctx.get(index, store)));
579
- ctx.set(index, store, value);
580
- triggerChanged && setChanged(universe.worlds[worldId], this, trait2);
586
+ const world = universe.worlds[worldId];
587
+ setTrait(world, this, trait2, value, triggerChanged);
581
588
  };
582
589
  Number.prototype.targetsFor = function(relation2) {
583
590
  const worldId = this >>> WORLD_ID_SHIFT;
@@ -593,6 +600,11 @@ Number.prototype.id = function() {
593
600
  const id = this & ENTITY_ID_MASK;
594
601
  return id;
595
602
  };
603
+ Number.prototype.isAlive = function() {
604
+ const worldId = this >>> WORLD_ID_SHIFT;
605
+ const world = universe.worlds[worldId];
606
+ return isEntityAlive(world[$internal].entityIndex, this);
607
+ };
596
608
 
597
609
  // ../core/src/entity/entity.ts
598
610
  function createEntity(world, ...traits) {
@@ -601,10 +613,10 @@ function createEntity(world, ...traits) {
601
613
  for (const query of ctx.notQueries) {
602
614
  const match = query.check(world, entity);
603
615
  if (match) query.add(entity);
604
- query.resetTrackingBitmasks(entity.id());
616
+ query.resetTrackingBitmasks(getEntityId(entity));
605
617
  }
606
618
  ctx.entityTraits.set(entity, /* @__PURE__ */ new Set());
607
- entity.add(...traits);
619
+ addTrait(world, entity, ...traits);
608
620
  return entity;
609
621
  }
610
622
  var cachedSet = /* @__PURE__ */ new Set();
@@ -645,6 +657,8 @@ function destroyEntity(world, entity) {
645
657
  }
646
658
  }
647
659
  releaseEntity(ctx.entityIndex, currentEntity);
660
+ const allQuery = ctx.queriesHashMap.get("");
661
+ if (allQuery) allQuery.remove(world, currentEntity);
648
662
  ctx.entityTraits.delete(entity);
649
663
  const eid = getEntityId(currentEntity);
650
664
  for (let i = 0; i < ctx.entityMasks.length; i++) {
@@ -990,6 +1004,7 @@ var Query = class {
990
1004
  for (const sub of this.removeSubscriptions) {
991
1005
  sub(entity);
992
1006
  }
1007
+ this.version++;
993
1008
  }
994
1009
  check(world, entity, event) {
995
1010
  const { bitmasks, generations } = this;
@@ -1151,7 +1166,7 @@ function createQueryResult(query, world, params) {
1151
1166
  }
1152
1167
  for (let i = 0; i < changedPairs.length; i++) {
1153
1168
  const [entity, trait2] = changedPairs[i];
1154
- entity.changed(trait2);
1169
+ setChanged(world, entity, trait2);
1155
1170
  }
1156
1171
  } else if (options.changeDetection === "always") {
1157
1172
  const changedPairs = [];
@@ -1186,7 +1201,7 @@ function createQueryResult(query, world, params) {
1186
1201
  }
1187
1202
  for (let i = 0; i < changedPairs.length; i++) {
1188
1203
  const [entity, trait2] = changedPairs[i];
1189
- entity.changed(trait2);
1204
+ setChanged(world, entity, trait2);
1190
1205
  }
1191
1206
  } else if (options.changeDetection === "never") {
1192
1207
  for (let i = 0; i < entities.length; i++) {
@@ -1295,19 +1310,19 @@ var World = class {
1295
1310
  return createEntity(this, ...traits);
1296
1311
  }
1297
1312
  has(target) {
1298
- return typeof target === "number" ? isEntityAlive(this[$internal].entityIndex, target) : this[$internal].worldEntity.has(target);
1313
+ return typeof target === "number" ? isEntityAlive(this[$internal].entityIndex, target) : hasTrait(this, this[$internal].worldEntity, target);
1299
1314
  }
1300
1315
  add(...traits) {
1301
- this[$internal].worldEntity.add(...traits);
1316
+ addTrait(this, this[$internal].worldEntity, ...traits);
1302
1317
  }
1303
1318
  remove(...traits) {
1304
- this[$internal].worldEntity.remove(...traits);
1319
+ removeTrait(this, this[$internal].worldEntity, ...traits);
1305
1320
  }
1306
1321
  get(trait2) {
1307
- return this[$internal].worldEntity.get(trait2);
1322
+ return getTrait(this, this[$internal].worldEntity, trait2);
1308
1323
  }
1309
1324
  set(trait2, value) {
1310
- this[$internal].worldEntity.set(trait2, value);
1325
+ setTrait(this, this[$internal].worldEntity, trait2, value);
1311
1326
  }
1312
1327
  destroy() {
1313
1328
  destroyEntity(this, this[$internal].worldEntity);
@@ -1399,12 +1414,12 @@ function createWorld(...traits) {
1399
1414
 
1400
1415
  export {
1401
1416
  $internal,
1417
+ universe,
1418
+ createChanged,
1402
1419
  relation,
1403
1420
  Pair,
1404
1421
  Wildcard,
1405
1422
  trait,
1406
- universe,
1407
- createChanged,
1408
1423
  createWorld,
1409
1424
  createAdded,
1410
1425
  createRemoved,