@daneren2005/shared-memory-ecs 1.8.0 → 1.8.2

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 CHANGED
@@ -687,6 +687,12 @@ the following updates, as above). `await world.clear()` instead tears the world
687
687
  empty, reusable state: it waits for every system's in-flight worker run to finish so nothing is still reading
688
688
  the memory, frees the held blocks immediately, and resolves once the world is ready to load into again.
689
689
 
690
+ Prefer `world.load()` over looping `world.loadEntity()` for a large batch. It still emits `entity-added` for every
691
+ entity, but systems ignore those while `world.isBulkLoading` is set and instead join the whole batch once at the end
692
+ through `system.addEntities(batch)`. Entities with the same component keys are grouped, so each query's component
693
+ test runs once per group instead of once per entity; system membership keeps load order. A system that overrides
694
+ `checkAddEntity` (or an `EntityWorkerSystem` that overrides `matchesQuery`) still has it called for each entity.
695
+
690
696
  ## Measuring performance
691
697
 
692
698
  `PerformanceTiming` watches a world and reports what running it costs. Hand it the world and it hooks itself
@@ -715,6 +721,12 @@ Every entry is an `{ avg, min, max, samples }` over the window just closed:
715
721
  than on a frame boundary, so there is no per-frame combined sample to take; these are the per-system figures
716
722
  summed at the end of the window, giving what a run of every system costs the main thread between them.
717
723
 
724
+ To coordinate reporting with an external clock, construct with `{ autoUpdate: false }` and call
725
+ `timing.flush()` at each reporting boundary. It publishes and returns a snapshot of all collected update,
726
+ worker, and event samples, then starts a fresh window. This also works while paused: windows without work
727
+ report zeroes. Worker results belong to the window in which they arrive. Automatic reporting remains
728
+ enabled by default.
729
+
718
730
  `getSystemStats(name)` pulls one system out of the latest snapshot, `reset()` throws away everything collected
719
731
  so far (worth doing after loading a new scene, when the samples either side are not comparable), and
720
732
  `destroy()` unhooks it from the world.
@@ -9,6 +9,7 @@ export default class EntityFactory<C extends ComponentMap = ComponentMap, Cfg =
9
9
  };
10
10
  classes: EntityClassRegistry;
11
11
  private allowedComponents;
12
+ private forbiddenProperties;
12
13
  constructor(configs?: {
13
14
  [type: string]: Cfg;
14
15
  }, classes?: EntityClassRegistry);
@@ -29,4 +30,6 @@ export default class EntityFactory<C extends ComponentMap = ComponentMap, Cfg =
29
30
  private validateResolvedConfig;
30
31
  private validateTypeClass;
31
32
  private validateComponentTriggers;
33
+ private getForbiddenProperties;
34
+ private throwComponentTriggerError;
32
35
  }
package/dist/index.d.ts CHANGED
@@ -19,7 +19,7 @@ export type { ComponentTypedArray } from './memory-component';
19
19
  export { default as Component } from './component';
20
20
  export type { BaseComponent, ComponentMap, ComponentDefinition, ComponentDefinitionMap, ComponentRegistry, ComponentsOf, EntityConfigOf, RegisteredComponentDefinition, RegisteredComponentRegistry, } from './component-definition';
21
21
  export { default as System } from './systems/system';
22
- export type { SystemConfig, SystemError, SystemErrorPhase } from './systems/system';
22
+ export type { EntityBatch, SystemConfig, SystemError, SystemErrorPhase } from './systems/system';
23
23
  export { default as IterableSystem } from './systems/iterable-system';
24
24
  export type { IterableSystemConfig } from './systems/iterable-system';
25
25
  export { default as EntitySystem } from './systems/entity-system';
package/dist/index.js CHANGED
@@ -112,6 +112,7 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
112
112
  this.currentDelta = 0;
113
113
  }
114
114
  finishLoading() {}
115
+ addEntities(e) {}
115
116
  update(e) {
116
117
  if (this.currentDelta += e, this.currentDelta >= this.deltaBetweenRuns || this.firstRun) {
117
118
  let e = 0;
@@ -143,7 +144,14 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
143
144
  destroy() {
144
145
  this.removeAllListeners();
145
146
  }
146
- }, A = class extends k {
147
+ };
148
+ function A(e, t, n) {
149
+ let r = e.groups.map(t);
150
+ for (let t = 0; t < e.entities.length; t++) r[e.groupIndexes[t]] && n(e.entities[t]);
151
+ }
152
+ //#endregion
153
+ //#region src/systems/iterable-system.ts
154
+ var j = class extends k {
147
155
  remainingInstancesToRun = [];
148
156
  remainingInstancesStartTime = null;
149
157
  iterationsPerCheck;
@@ -193,12 +201,12 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
193
201
  }
194
202
  beforeRunIterables() {}
195
203
  getIterableEntityId(e) {}
196
- }, j = class extends A {
204
+ }, M = class e extends j {
197
205
  entities = /* @__PURE__ */ new Map();
198
206
  options;
199
207
  constructor(e, t = { name: "EntitySystem" }) {
200
- t.iterationsPerCheck ||= 10, t.maxMsPerFrame ||= 4, super(e, t), this.options = t, e.on("entity-added", (e) => {
201
- this.checkAddEntity(e) && this.options.updateEntityOnAdd && this.updateEntity(e, 0);
208
+ t.iterationsPerCheck ||= 10, t.maxMsPerFrame ||= 4, super(e, t), this.options = t, e.on("entity-added", (t) => {
209
+ e.isBulkLoading || this.onEntityAdded(t);
202
210
  }), e.on("entity-removed", (e) => {
203
211
  this.removeEntity(e);
204
212
  }), e.entities.forEach((e) => {
@@ -223,8 +231,23 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
223
231
  isEntityInSystem(e) {
224
232
  return this.entities.has(e.eid);
225
233
  }
234
+ onEntityAdded(e) {
235
+ this.checkAddEntity(e) && this.options.updateEntityOnAdd && this.updateEntity(e, 0);
236
+ }
237
+ addEntities(t) {
238
+ if (this.checkAddEntity !== e.prototype.checkAddEntity) {
239
+ t.entities.forEach((e) => this.onEntityAdded(e));
240
+ return;
241
+ }
242
+ A(t, (e) => this.hasComponents(e), (e) => {
243
+ this.filterEntity(e) && (this.entities.set(e.eid, e), this.options.updateEntityOnAdd && this.updateEntity(e, 0));
244
+ });
245
+ }
246
+ hasComponents(e) {
247
+ return !this.options.components || this.options.components.every((t) => !!e.components[t]);
248
+ }
226
249
  checkAddEntity(e) {
227
- return this.options.components && this.options.components.filter((t) => !!e.components[t]).length !== this.options.components.length ? !1 : this.filterEntity(e) ? (this.entities.set(e.eid, e), !0) : !1;
250
+ return this.hasComponents(e) && this.filterEntity(e) ? (this.entities.set(e.eid, e), !0) : !1;
228
251
  }
229
252
  removeEntity(e) {
230
253
  this.entities.delete(e.eid);
@@ -232,9 +255,9 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
232
255
  shouldRun() {
233
256
  return this.isCurrentlyRunning() || this.entities.size > 0;
234
257
  }
235
- }, M = class {
258
+ }, N = class {
236
259
  onmessage(e, t = []) {}
237
- }, N = class extends M {
260
+ }, P = class extends N {
238
261
  updateFunction;
239
262
  entities = [];
240
263
  queryEntities = {};
@@ -372,7 +395,7 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
372
395
  onMessageTyped(e) {
373
396
  this.onmessage({ data: e });
374
397
  }
375
- }, P = "___main", F = class extends k {
398
+ }, F = "___main", I = class e extends k {
376
399
  entities = /* @__PURE__ */ new Map();
377
400
  options;
378
401
  worker;
@@ -388,8 +411,8 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
388
411
  constructor(e, t) {
389
412
  super(e, t), this.options = t, Object.keys(this.options.queries ?? {}).forEach((e) => {
390
413
  this.queryEntities[e] = /* @__PURE__ */ new Map();
391
- }), e.on("entity-added", (e) => {
392
- this.checkAddEntity(e);
414
+ }), e.on("entity-added", (t) => {
415
+ e.isBulkLoading || this.checkAddEntity(t);
393
416
  }), e.on("entity-removed", (e) => {
394
417
  this.removeEntity(e);
395
418
  }), e.entities.forEach((e) => {
@@ -399,7 +422,7 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
399
422
  type: "grow-buffer",
400
423
  buffer: e
401
424
  });
402
- })) : (this.worker = new N(t.updateFunction, e, !!t.createsEntities, !!t.addsComponents), this.isWorkerThread = !1), this.initWorker();
425
+ })) : (this.worker = new P(t.updateFunction, e, !!t.createsEntities, !!t.addsComponents), this.isWorkerThread = !1), this.initWorker();
403
426
  }
404
427
  initWorker() {
405
428
  this.worker.onmessage = (e) => {
@@ -501,7 +524,7 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
501
524
  elapsedTime: e
502
525
  };
503
526
  this.addDataToWorld?.(t), this.isRunning = !0;
504
- let n = this.buildQueryDelta(P, this.options), r = {};
527
+ let n = this.buildQueryDelta(F, this.options), r = {};
505
528
  Object.entries(this.options.queries ?? {}).forEach(([e, t]) => {
506
529
  r[e] = this.buildQueryDelta(e, t);
507
530
  });
@@ -542,7 +565,10 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
542
565
  return this.entities.has(e.eid);
543
566
  }
544
567
  matchesQuery(e, t) {
545
- return !(e.components.entity.dead || t.required.find((t) => !e.components[t]) || t.not?.find((t) => !!e.components[t]) || t.filter && !t.filter(e));
568
+ return !(e.components.entity.dead || !this.matchesComponents(e, t) || t.filter && !t.filter(e));
569
+ }
570
+ matchesComponents(e, t) {
571
+ return !(t.required.find((t) => !e.components[t]) || t.not?.find((t) => !!e.components[t]));
546
572
  }
547
573
  getQueryDelta(e) {
548
574
  let t = this.queryDeltas[e];
@@ -561,15 +587,34 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
561
587
  let i = this.getQueryDelta(e);
562
588
  r ? (t.set(n.eid, n), this.markAdded(i, n)) : t.delete(n.eid) && this.markRemoved(i, n);
563
589
  }
590
+ get tracksMainQuery() {
591
+ return !0;
592
+ }
564
593
  checkAddEntity(e) {
565
- let t = this.matchesQuery(e, this.options);
566
- return this.updateEntityList(P, this.entities, e, t), Object.entries(this.options.queries ?? {}).forEach(([t, n]) => {
594
+ let t = this.tracksMainQuery && this.matchesQuery(e, this.options);
595
+ return this.updateEntityList(F, this.entities, e, t), Object.entries(this.options.queries ?? {}).forEach(([t, n]) => {
567
596
  let r = this.queryEntities[t] ?? (this.queryEntities[t] = /* @__PURE__ */ new Map());
568
597
  this.updateEntityList(t, r, e, this.matchesQuery(e, n));
569
598
  }), t;
570
599
  }
600
+ addEntities(t) {
601
+ if (this.checkAddEntity !== e.prototype.checkAddEntity || this.matchesQuery !== e.prototype.matchesQuery) {
602
+ t.entities.forEach((e) => this.checkAddEntity(e));
603
+ return;
604
+ }
605
+ this.tracksMainQuery && this.addBatchToQuery(F, this.entities, this.options, t), Object.entries(this.options.queries ?? {}).forEach(([e, n]) => {
606
+ let r = this.queryEntities[e] ?? (this.queryEntities[e] = /* @__PURE__ */ new Map());
607
+ this.addBatchToQuery(e, r, n, t);
608
+ });
609
+ }
610
+ addBatchToQuery(e, t, n, r) {
611
+ let i = this.getQueryDelta(e);
612
+ A(r, (e) => this.matchesComponents(e, n), (e) => {
613
+ e.components.entity.dead || n.filter && !n.filter(e) || (t.set(e.eid, e), this.markAdded(i, e));
614
+ });
615
+ }
571
616
  removeEntity(e) {
572
- this.updateEntityList(P, this.entities, e, !1), Object.entries(this.queryEntities).forEach(([t, n]) => {
617
+ this.updateEntityList(F, this.entities, e, !1), Object.entries(this.queryEntities).forEach(([t, n]) => {
573
618
  this.updateEntityList(t, n, e, !1);
574
619
  });
575
620
  }
@@ -584,7 +629,7 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
584
629
  destroy() {
585
630
  super.destroy(), "terminate" in this.worker && this.worker.terminate();
586
631
  }
587
- }, I = class extends O.default {
632
+ }, L = class extends O.default {
588
633
  eid;
589
634
  config;
590
635
  world;
@@ -685,11 +730,12 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
685
730
  assertComponentPropertyMutable(e, t) {
686
731
  if (e === "entity" && (t === "type" || t === "class")) throw Error(`Entity ${t} is immutable`);
687
732
  }
688
- }, L = class {
733
+ }, R = class e {
689
734
  world;
690
735
  configs;
691
736
  classes;
692
737
  allowedComponents = /* @__PURE__ */ new Map();
738
+ forbiddenProperties = /* @__PURE__ */ new Map();
693
739
  constructor(e = {}, t = {}) {
694
740
  this.configs = e, this.classes = t;
695
741
  for (let e of Object.keys(t)) this.allowedComponents.set(e, new Set(t[e].components));
@@ -698,10 +744,10 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
698
744
  this.world && this.validateTemplate(e, t), this.configs[e] = t;
699
745
  }
700
746
  setWorld(e) {
701
- this.world = e;
747
+ this.world = e, this.forbiddenProperties.clear();
702
748
  for (let t of Object.keys(this.classes)) {
703
749
  let n = this.classes[t].entity;
704
- if (n !== I && !(n.prototype instanceof I)) throw Error(`Entity class ${t} must extend BaseEntity`);
750
+ if (n !== L && !(n.prototype instanceof L)) throw Error(`Entity class ${t} must extend BaseEntity`);
705
751
  for (let n of this.classes[t].components) if (n === "entity" || !(n in e.registry)) throw Error(`Entity class ${t} contains unknown or reserved component ${n}`);
706
752
  }
707
753
  for (let e of Object.keys(this.configs)) this.validateTemplate(e, this.configs[e]);
@@ -718,16 +764,16 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
718
764
  } : e;
719
765
  return this.hasClasses && n && this.validateResolvedConfig(n, i), i;
720
766
  }
721
- loadEntity(e, t = !0) {
722
- let n = e.type, r = this.getConfig(e);
723
- this.hasClasses && n && this.validateResolvedConfig(n, r);
724
- let i = this.getClassDefinition(r), a = i ? this.constructEntity(i, r) : this.createEntity(r);
725
- return this.world.addEntity(a, t);
767
+ loadEntity(t, n = !0) {
768
+ let r = t.type, i = this.getConfig(t);
769
+ this.hasClasses && r && this.getConfig !== e.prototype.getConfig && this.validateResolvedConfig(r, i);
770
+ let a = this.getClassDefinition(i), o = a ? this.constructEntity(a, i) : this.createEntity(i);
771
+ return this.world.addEntity(o, n);
726
772
  }
727
773
  createAdoptedEntity(e, t, n) {
728
774
  if (!t) {
729
775
  if (this.hasClasses) throw Error(`Entity type ${e} has no class`);
730
- return new I(this.world, void 0, n);
776
+ return new L(this.world, void 0, n);
731
777
  }
732
778
  let r = this.classes[t];
733
779
  if (!r) throw Error(`Unknown entity class: ${t}`);
@@ -753,7 +799,7 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
753
799
  return e ? this.getAllowedComponents(e) : void 0;
754
800
  }
755
801
  createEntity(e) {
756
- return new I(this.world, e);
802
+ return new L(this.world, e);
757
803
  }
758
804
  get hasClasses() {
759
805
  return this.allowedComponents.size > 0;
@@ -793,6 +839,21 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
793
839
  if (!n || n.class !== t) throw Error(`Entity type ${e} does not belong to class ${t}`);
794
840
  }
795
841
  validateComponentTriggers(e, t, n) {
842
+ let r = this.getForbiddenProperties(t);
843
+ for (let i in n) r.has(i) && this.throwComponentTriggerError(e, t, n);
844
+ }
845
+ getForbiddenProperties(e) {
846
+ let t = this.forbiddenProperties.get(e);
847
+ if (!t) {
848
+ let n = this.allowedComponents.get(e), r = /* @__PURE__ */ new Set();
849
+ for (let e of n) for (let t of this.world.registry[e].loadProperties) r.add(t);
850
+ let i = /* @__PURE__ */ new Set();
851
+ for (let e of Object.keys(this.world.registry)) if (!(e === "entity" || n.has(e))) for (let t of this.world.registry[e].loadProperties) r.has(t) || i.add(t);
852
+ t = i, this.forbiddenProperties.set(e, t);
853
+ }
854
+ return t;
855
+ }
856
+ throwComponentTriggerError(e, t, n) {
796
857
  let r = this.allowedComponents.get(t), i = /* @__PURE__ */ new Set();
797
858
  for (let e of r) for (let t of this.world.registry[e].loadProperties) i.add(t);
798
859
  let a = n;
@@ -801,8 +862,9 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
801
862
  let o = this.world.registry[n].loadProperties.find((e) => e in a && !i.has(e));
802
863
  if (o) throw Error(`Entity type ${e} class ${t} cannot load component ${n} from property ${o}`);
803
864
  }
865
+ throw Error(`Entity type ${e} class ${t} loads a component outside its class`);
804
866
  }
805
- }, R = y, z = 1e4, B = class extends O.default {
867
+ }, z = y, B = 1e4, V = class extends O.default {
806
868
  heap;
807
869
  constantStrings;
808
870
  eidCounter;
@@ -816,6 +878,7 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
816
878
  paused = !1;
817
879
  destroyed = !1;
818
880
  pristine = !0;
881
+ isBulkLoading = !1;
819
882
  activeFreeBuffer = {
820
883
  frees: [],
821
884
  waitingSystems: /* @__PURE__ */ new Set(),
@@ -827,7 +890,7 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
827
890
  waitElapsed: 0
828
891
  };
829
892
  constructor(t, n = {}) {
830
- super(), this.heap = new v({ bufferSize: n.heapSize ?? R }), this.constantStrings = new e(this.heap), this.eidCounter = this.heap.allocUI32(1), this.heap.addOnGrowBufferHandlers((e) => this.emit("grow-buffer", e));
893
+ super(), this.heap = new v({ bufferSize: n.heapSize ?? z }), this.constantStrings = new e(this.heap), this.eidCounter = this.heap.allocUI32(1), this.heap.addOnGrowBufferHandlers((e) => this.emit("grow-buffer", e));
831
894
  let r = {
832
895
  ...t,
833
896
  entity: i
@@ -839,7 +902,7 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
839
902
  memoryComponent: new _(this.heap, t.type, t.size)
840
903
  };
841
904
  }
842
- this.registry = a, this.factory = n.factory ?? new L(), this.factory.setWorld(this);
905
+ this.registry = a, this.factory = n.factory ?? new R(), this.factory.setWorld(this);
843
906
  }
844
907
  allocateEid() {
845
908
  return Atomics.add(this.eidCounter.data, 0, 1) + 1;
@@ -856,7 +919,7 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
856
919
  this.heap.buffers[e.bufferPosition] === void 0 && this.heap.addSharedBuffer(e), this.emit("grow-buffer", e);
857
920
  }
858
921
  get needsSpareBuffer() {
859
- return this.systems.some((e) => e instanceof F && e.isWorkerThread && (!!e.options.createsEntities || !!e.options.addsComponents));
922
+ return this.systems.some((e) => e instanceof I && e.isWorkerThread && (!!e.options.createsEntities || !!e.options.addsComponents));
860
923
  }
861
924
  async init() {
862
925
  await Promise.all(this.systems.map((e) => e.init()).filter((e) => e instanceof Promise));
@@ -903,11 +966,17 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
903
966
  }
904
967
  for (let e of Object.keys(this.factory.configs)) this.constantStrings.getOrCreate(e);
905
968
  for (let e of Object.keys(this.factory.classes)) this.constantStrings.getOrCreate(e);
906
- let t = e.entities.map((e) => this.loadEntity(e, !1));
907
- for (let e of t) e.finishLoading(), this.emit("entity-added", e), e.on("death", () => {
908
- this.onEntityDied(e);
909
- });
910
- this.gameTime = e.gameTime ?? 0, this.playerTime = e.playerTime ?? 0, this.timeScale = e.timeScale ?? 1, this.finishLoadingSystems();
969
+ this.isBulkLoading = !0;
970
+ try {
971
+ let t = e.entities.map((e) => this.loadEntity(e, !1));
972
+ for (let e of t) e.finishLoading(), this.emit("entity-added", e), e.on("death", () => {
973
+ this.onEntityDied(e);
974
+ });
975
+ } finally {
976
+ this.isBulkLoading = !1;
977
+ }
978
+ let t = H(this.entities.values());
979
+ this.systems.forEach((e) => e.addEntities(t)), this.gameTime = e.gameTime ?? 0, this.playerTime = e.playerTime ?? 0, this.timeScale = e.timeScale ?? 1, this.finishLoadingSystems();
911
980
  }
912
981
  async clear() {
913
982
  if (!this.pristine) {
@@ -973,9 +1042,9 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
973
1042
  }
974
1043
  checkFreeBufferTimeout(e) {
975
1044
  let t = this.activeFreeBuffer;
976
- if (t.waitingSystems.size !== 0 && (t.waitElapsed += e, t.waitElapsed >= z)) {
1045
+ if (t.waitingSystems.size !== 0 && (t.waitElapsed += e, t.waitElapsed >= B)) {
977
1046
  let e = Array.from(t.waitingSystems).map((e) => e.name).join(", ");
978
- console.warn(`shared-memory-ecs: deferred component free waited over ${z}ms on system(s): ${e}; freeing anyway`), t.waitingSystems.clear(), this.processFreeBuffers();
1047
+ console.warn(`shared-memory-ecs: deferred component free waited over ${B}ms on system(s): ${e}; freeing anyway`), t.waitingSystems.clear(), this.processFreeBuffers();
979
1048
  }
980
1049
  }
981
1050
  addSystem(e) {
@@ -1028,13 +1097,13 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
1028
1097
  this.paused = !1;
1029
1098
  }
1030
1099
  addEntityToEntityWorkerSystem(e, t) {
1031
- this.systems.forEach((n) => {
1032
- (n instanceof j && n.options.components?.includes(t) || n instanceof F && this.componentAffectsEntityWorkerSystem(n, t)) && n.checkAddEntity(e);
1100
+ this.isBulkLoading || this.systems.forEach((n) => {
1101
+ (n instanceof M && n.options.components?.includes(t) || n instanceof I && this.componentAffectsEntityWorkerSystem(n, t)) && n.checkAddEntity(e);
1033
1102
  });
1034
1103
  }
1035
1104
  removeEntityFromEntityWorkerSystem(e, t) {
1036
- this.systems.forEach((n) => {
1037
- n instanceof j && n.options.components?.includes(t) ? n.removeEntity(e) : n instanceof F && this.componentAffectsEntityWorkerSystem(n, t) && n.checkAddEntity(e);
1105
+ this.isBulkLoading || this.systems.forEach((n) => {
1106
+ n instanceof M && n.options.components?.includes(t) ? n.removeEntity(e) : n instanceof I && this.componentAffectsEntityWorkerSystem(n, t) && n.checkAddEntity(e);
1038
1107
  });
1039
1108
  }
1040
1109
  componentAffectsEntityWorkerSystem(e, t) {
@@ -1047,29 +1116,41 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
1047
1116
  }), !0);
1048
1117
  }
1049
1118
  };
1119
+ function H(e) {
1120
+ let t = {
1121
+ entities: [],
1122
+ groupIndexes: [],
1123
+ groups: []
1124
+ }, n = /* @__PURE__ */ new Map();
1125
+ for (let r of e) {
1126
+ let e = Object.keys(r.components).sort().join(","), i = n.get(e);
1127
+ i === void 0 && (i = t.groups.push(r) - 1, n.set(e, i)), t.entities.push(r), t.groupIndexes.push(i);
1128
+ }
1129
+ return t;
1130
+ }
1050
1131
  //#endregion
1051
1132
  //#region src/entity-class.ts
1052
- function V(e, t) {
1133
+ function U(e, t) {
1053
1134
  return t;
1054
1135
  }
1055
- function H(e, t) {
1136
+ function W(e, t) {
1056
1137
  return t;
1057
1138
  }
1058
1139
  //#endregion
1059
1140
  //#region src/actions/kill-entity.ts
1060
- function U(e) {
1141
+ function G(e) {
1061
1142
  e.components.entity.dead = !0, e.emit("death");
1062
1143
  }
1063
1144
  //#endregion
1064
1145
  //#region src/performance-timing.ts
1065
- var W = 1e3, G = {
1146
+ var K = 1e3, q = {
1066
1147
  avg: 0,
1067
1148
  min: 0,
1068
1149
  max: 0,
1069
1150
  samples: 0
1070
1151
  };
1071
- function K(e) {
1072
- if (!e.length) return { ...G };
1152
+ function J(e) {
1153
+ if (!e.length) return { ...q };
1073
1154
  let t = 0, n = Infinity, r = 0;
1074
1155
  for (let i of e) t += i, i < n && (n = i), i > r && (r = i);
1075
1156
  return {
@@ -1079,21 +1160,22 @@ function K(e) {
1079
1160
  samples: e.length
1080
1161
  };
1081
1162
  }
1082
- var q = class extends O.default {
1163
+ var Y = class extends O.default {
1083
1164
  world;
1084
1165
  ticksBetweenUpdates;
1085
1166
  stats = {
1086
- update: { ...G },
1167
+ update: { ...q },
1087
1168
  systems: [],
1088
- events: { ...G }
1169
+ events: { ...q }
1089
1170
  };
1171
+ autoUpdate;
1090
1172
  ticks = 0;
1091
1173
  updateStart = 0;
1092
1174
  updateTimes = [];
1093
1175
  systemTimings = /* @__PURE__ */ new Map();
1094
1176
  destroyed = !1;
1095
1177
  constructor(e, t = {}) {
1096
- super(), this.world = e, this.ticksBetweenUpdates = t.ticksBetweenUpdates ?? 1e3, e.on("update-started", this.onUpdateStarted), e.on("update-finished", this.onUpdateFinished), e.on("system-added", this.onSystemAdded), e.on("system-removed", this.onSystemRemoved), e.systems.forEach((e) => this.trackSystem(e));
1178
+ super(), this.world = e, this.autoUpdate = t.autoUpdate ?? !0, this.ticksBetweenUpdates = t.ticksBetweenUpdates ?? 1e3, e.on("update-started", this.onUpdateStarted), e.on("update-finished", this.onUpdateFinished), e.on("system-added", this.onSystemAdded), e.on("system-removed", this.onSystemRemoved), e.systems.forEach((e) => this.trackSystem(e));
1097
1179
  }
1098
1180
  getSystemStats(e) {
1099
1181
  return this.stats.systems.find((t) => t.name === e);
@@ -1102,9 +1184,9 @@ var q = class extends O.default {
1102
1184
  this.ticks = 0, this.updateTimes = [], this.systemTimings.forEach((e) => {
1103
1185
  e.run = [], e.events = [], e.eventStart = -1;
1104
1186
  }), this.stats = {
1105
- update: { ...G },
1187
+ update: { ...q },
1106
1188
  systems: [],
1107
- events: { ...G }
1189
+ events: { ...q }
1108
1190
  };
1109
1191
  }
1110
1192
  destroy() {
@@ -1114,7 +1196,7 @@ var q = class extends O.default {
1114
1196
  this.updateStart = performance.now();
1115
1197
  };
1116
1198
  onUpdateFinished = (e) => {
1117
- this.world.paused || (this.updateTimes.push(performance.now() - this.updateStart), this.ticks += e, this.ticks >= this.ticksBetweenUpdates && this.recalculate());
1199
+ this.world.paused || (this.updateTimes.push(performance.now() - this.updateStart), this.ticks += e, this.autoUpdate && this.ticks >= this.ticksBetweenUpdates && this.flush());
1118
1200
  };
1119
1201
  onSystemAdded = (e) => {
1120
1202
  this.trackSystem(e);
@@ -1141,26 +1223,27 @@ var q = class extends O.default {
1141
1223
  let t = this.systemTimings.get(e);
1142
1224
  t && (this.world.off(`system-${e}-worker-finished`, t.onRunFinished), this.world.off(`system-${e}-worker-events-finished`, t.onEventsFinished), this.systemTimings.delete(e));
1143
1225
  }
1144
- recalculate() {
1226
+ flush() {
1227
+ if (this.destroyed) return this.stats;
1145
1228
  let e = this.world.systems.map((e) => {
1146
1229
  let t = this.systemTimings.get(e.name);
1147
1230
  return {
1148
1231
  name: e.name,
1149
- run: K(t?.run ?? []),
1150
- events: K(t?.events ?? [])
1232
+ run: J(t?.run ?? []),
1233
+ events: J(t?.events ?? [])
1151
1234
  };
1152
- }), t = { ...G };
1153
- e.forEach((e) => {
1235
+ }), t = { ...q };
1236
+ return e.forEach((e) => {
1154
1237
  t.avg += e.events.avg, t.min += e.events.min, t.max += e.events.max, t.samples += e.events.samples;
1155
1238
  }), this.stats = {
1156
- update: K(this.updateTimes),
1239
+ update: J(this.updateTimes),
1157
1240
  systems: e,
1158
1241
  events: t
1159
1242
  }, this.ticks = 0, this.updateTimes = [], this.systemTimings.forEach((e) => {
1160
1243
  e.run = [], e.events = [];
1161
- }), this.emit("stats-updated", this.stats);
1244
+ }), this.emit("stats-updated", this.stats), this.stats;
1162
1245
  }
1163
- }, J = class extends F {
1246
+ }, X = class extends I {
1164
1247
  constructor(e, t) {
1165
1248
  super(e, {
1166
1249
  ...t,
@@ -1168,17 +1251,14 @@ var q = class extends O.default {
1168
1251
  updateFunction: u(t.updateFunction)
1169
1252
  });
1170
1253
  }
1171
- checkAddEntity(e) {
1172
- return Object.entries(this.options.queries ?? {}).forEach(([t, n]) => {
1173
- let r = this.queryEntities[t] ?? (this.queryEntities[t] = /* @__PURE__ */ new Map());
1174
- this.updateEntityList(t, r, e, this.matchesQuery(e, n));
1175
- }), !1;
1254
+ get tracksMainQuery() {
1255
+ return !1;
1176
1256
  }
1177
1257
  shouldRun() {
1178
1258
  return !0;
1179
1259
  }
1180
1260
  };
1181
1261
  //#endregion
1182
- export { I as BaseEntity, B as BaseWorld, n as CLASS_INDEX, f as Component, e as ConstantStringCache, c as DEAD_INDEX, W as DEFAULT_TICKS_BETWEEN_UPDATES, L as EntityFactory, j as EntitySystem, N as EntitySystemWebWorker, F as EntityWorkerSystem, A as IterableSystem, _ as MemoryComponent, q as PerformanceTiming, g as STATIC_INDEX, k as System, r as TYPE_INDEX, M as WebWorker, J as WorkerSystem, t as addComponentWorker, p as createEntitySystemWorker, d as createEntityWorker, h as createSystemWorker, V as defineEntityClasses, H as defineEntityConfigs, i as entityDefinition, U as killEntity, m as killEntityWorker, s as removeComponentWorker };
1262
+ export { L as BaseEntity, V as BaseWorld, n as CLASS_INDEX, f as Component, e as ConstantStringCache, c as DEAD_INDEX, K as DEFAULT_TICKS_BETWEEN_UPDATES, R as EntityFactory, M as EntitySystem, P as EntitySystemWebWorker, I as EntityWorkerSystem, j as IterableSystem, _ as MemoryComponent, Y as PerformanceTiming, g as STATIC_INDEX, k as System, r as TYPE_INDEX, N as WebWorker, X as WorkerSystem, t as addComponentWorker, p as createEntitySystemWorker, d as createEntityWorker, h as createSystemWorker, U as defineEntityClasses, W as defineEntityConfigs, i as entityDefinition, G as killEntity, m as killEntityWorker, s as removeComponentWorker };
1183
1263
 
1184
1264
  //# sourceMappingURL=index.js.map