@daneren2005/shared-memory-ecs 1.2.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./create-component-worker-Bd1BTUkq.js";
1
+ import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./create-component-worker-vbX3vEia.js";
2
2
  import s from "@daneren2005/shared-memory-objects/memory-heap";
3
3
  import { MAX_BYTE_OFFSET_LENGTH as c } from "@daneren2005/shared-memory-objects/utils/pointer";
4
4
  import l from "@daneren2005/shared-memory-objects/local-pool";
@@ -150,9 +150,16 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
150
150
  update(e) {
151
151
  if (this.currentDelta += e, this.currentDelta >= this.deltaBetweenRuns || this.firstRun) {
152
152
  let e = 0;
153
- return this.deltaBetweenRuns > 0 && (e = this.currentDelta % this.deltaBetweenRuns), this.run(this.currentDelta - e), this.currentDelta = e, this.firstRun = !1, !0;
153
+ return this.deltaBetweenRuns > 0 && (e = this.currentDelta % this.deltaBetweenRuns), this.run(this.currentDelta - e), this.currentDelta = e, this.firstRun = !1, this.onRunFinished(), !0;
154
154
  } else return !1;
155
155
  }
156
+ onRunFinished() {
157
+ this.world.notifySystemRunCompleted(this);
158
+ }
159
+ isCurrentlyRunning() {
160
+ return !1;
161
+ }
162
+ waitForRunToComplete() {}
156
163
  shouldRun() {
157
164
  return !0;
158
165
  }
@@ -171,12 +178,18 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
171
178
  super.clear(), this.remainingInstancesToRun = [], this.remainingInstancesStartTime = null;
172
179
  }
173
180
  update(e) {
174
- return this.remainingInstancesToRun.length ? (this.runIterables(this.remainingInstancesToRun, this.remainingInstancesStartTime ?? 0), this.currentDelta += e, !0) : super.update(e);
181
+ return this.remainingInstancesToRun.length ? (this.runIterables(this.remainingInstancesToRun, this.remainingInstancesStartTime ?? 0), this.currentDelta += e, this.remainingInstancesToRun.length || this.onRunFinished(), !0) : super.update(e);
175
182
  }
176
183
  run(e) {
177
184
  let t = this.getIterables();
178
185
  this.runIterables(t, e);
179
186
  }
187
+ onRunFinished() {
188
+ this.remainingInstancesToRun.length || super.onRunFinished();
189
+ }
190
+ isCurrentlyRunning() {
191
+ return this.remainingInstancesToRun.length > 0;
192
+ }
180
193
  runIterables(e, t) {
181
194
  let n = performance.now();
182
195
  this.beforeRunIterables();
@@ -229,12 +242,16 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
229
242
  updateFunction;
230
243
  entities = [];
231
244
  queryEntities = {};
245
+ worldExtension;
232
246
  constructor(e) {
233
247
  super(), this.updateFunction = e;
234
248
  }
235
249
  postMessage(e) {
236
- if (e.type === "init") this.onMessageTyped({ type: "loaded" });
250
+ if (e.type === "init") this.onMessageTyped({ type: "init-complete" });
251
+ else if (e.type === "load") this.worldExtension = this.updateFunction.init?.(e.data) ?? void 0, this.onMessageTyped({ type: "loaded" });
252
+ else if (e.type === "reset") this.entities = [], this.queryEntities = {};
237
253
  else if (e.type === "run") {
254
+ this.worldExtension && Object.assign(e.world, this.worldExtension);
238
255
  let t = performance.now(), n = [], r = {}, i = [];
239
256
  this.entities = a(this.entities, e.entities);
240
257
  let o = {};
@@ -281,6 +298,7 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
281
298
  let c = performance.now() - t;
282
299
  this.onMessageTyped({
283
300
  type: "run-complete",
301
+ generation: e.generation,
284
302
  runTime: c,
285
303
  events: n,
286
304
  systemEvents: r,
@@ -296,9 +314,12 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
296
314
  options;
297
315
  worker;
298
316
  isWorkerThread;
299
- loaded = !1;
317
+ initialized = !1;
318
+ initPromise = null;
300
319
  loadingPromise = null;
320
+ runCompletePromise = null;
301
321
  isRunning = !1;
322
+ generation = 0;
302
323
  queryEntities = {};
303
324
  queryDeltas = {};
304
325
  constructor(e, t) {
@@ -315,35 +336,75 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
315
336
  initWorker() {
316
337
  this.worker.onmessage = (e) => {
317
338
  let t = e.data;
318
- if (t.type === "loaded") this.loaded = !0, this.loadingPromise &&= (this.loadingPromise.resolve(), null);
339
+ if (t.type === "init-complete") this.initialized = !0, this.initPromise &&= (this.initPromise.resolve(), null);
340
+ else if (t.type === "loaded") this.loadingPromise &&= (this.loadingPromise.resolve(), null);
319
341
  else if (t.type === "run-complete") {
342
+ if (t.generation !== this.generation) return;
320
343
  this.isRunning = !1, this.world.emit(`system-${this.name}-worker-finished`, t.runTime);
321
344
  for (let e of Object.keys(t.systemEvents)) this.emit(e, t.systemEvents[e]);
322
345
  t.events.forEach((e) => {
323
346
  let t = this.world.getEntityByEid(e.entityId);
324
347
  if (!t) {
325
- console.warn(`Could not find entity with id ${e.entityId}`);
348
+ console.warn(`${this.name}-event ${e.event}: Could not find entity with id ${e.entityId}`);
326
349
  return;
327
350
  }
328
351
  t.emit(e.event, ...e.args);
329
352
  }), t.created.forEach((e) => {
330
353
  this.world.loadEntity(e);
331
- }), this.world.emit(`system-${this.name}-worker-events-finished`, t.runTime);
354
+ }), this.world.emit(`system-${this.name}-worker-events-finished`, t.runTime), this.world.notifySystemRunCompleted(this), this.runCompletePromise &&= (this.runCompletePromise.resolve(), null);
332
355
  }
333
356
  }, this.worker.postMessage({ type: "init" });
334
357
  }
335
358
  init() {
336
- if (this.loaded) return;
337
- if (this.loadingPromise) return this.loadingPromise.promise;
359
+ if (this.initialized) return;
360
+ if (this.initPromise) return this.initPromise.promise;
338
361
  let { promise: e, resolve: t } = Promise.withResolvers();
339
- return this.loadingPromise = {
362
+ return this.initPromise = {
340
363
  promise: e,
341
364
  resolve: t
342
365
  }, e;
343
366
  }
367
+ finishLoading() {
368
+ let { promise: e, resolve: t } = Promise.withResolvers();
369
+ this.loadingPromise = {
370
+ promise: e,
371
+ resolve: t
372
+ };
373
+ let n = {
374
+ type: "load",
375
+ data: this.options.getInitData?.()
376
+ };
377
+ return this.worker.postMessage(n), e;
378
+ }
379
+ clear() {
380
+ if (super.clear(), this.isRunning && !this.runCompletePromise) {
381
+ let { promise: e, resolve: t } = Promise.withResolvers();
382
+ this.runCompletePromise = {
383
+ promise: e,
384
+ resolve: t
385
+ };
386
+ }
387
+ this.isRunning = !1, this.generation++, this.entities.clear(), Object.values(this.queryEntities).forEach((e) => e.clear()), this.queryDeltas = {}, this.worker.postMessage({ type: "reset" });
388
+ }
344
389
  update(e) {
345
390
  return this.isRunning ? (this.currentDelta += e, !1) : super.update(e);
346
391
  }
392
+ onRunFinished() {}
393
+ isCurrentlyRunning() {
394
+ return this.isRunning;
395
+ }
396
+ waitForRunToComplete() {
397
+ if (this.isRunning) {
398
+ if (!this.runCompletePromise) {
399
+ let { promise: e, resolve: t } = Promise.withResolvers();
400
+ this.runCompletePromise = {
401
+ promise: e,
402
+ resolve: t
403
+ };
404
+ }
405
+ return this.runCompletePromise.promise;
406
+ }
407
+ }
347
408
  run(e) {
348
409
  let t = {
349
410
  gameTime: this.world.gameTime,
@@ -356,6 +417,7 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
356
417
  });
357
418
  let i = {
358
419
  type: "run",
420
+ generation: this.generation,
359
421
  world: t,
360
422
  entities: n,
361
423
  queries: r
@@ -442,7 +504,10 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
442
504
  }
443
505
  removeComponent(e) {
444
506
  let t = this.components[e];
445
- t && (this.world.registry[e].memoryComponent.delete(t.index), delete this.components[e], this.emit("component-removed", e));
507
+ if (t) {
508
+ let n = this.world.registry[e];
509
+ this.world.deferComponentMemoryFree(n.memoryComponent, t.index, n.free ? () => n.free(t) : void 0), delete this.components[e], this.emit("component-removed", e);
510
+ }
446
511
  }
447
512
  setComponent(e, t, n) {
448
513
  let r = this.components[e];
@@ -457,10 +522,10 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
457
522
  n && (delete n[t], this.emit("component-property-deleted", e, t));
458
523
  }
459
524
  deleteAllComponentMemory() {
460
- let e = this.world.registry;
461
- for (let t of Object.keys(this.components)) {
462
- let n = this.components[t];
463
- n && e[t].memoryComponent.delete(n.index);
525
+ let e = this.world.registry, t = this.components;
526
+ for (let n of Object.keys(t)) {
527
+ let r = e[n], i = t[n];
528
+ i && this.world.deferComponentMemoryFree(r.memoryComponent, i.index, r.free ? () => r.free(i) : void 0);
464
529
  }
465
530
  }
466
531
  load(e) {
@@ -513,7 +578,7 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
513
578
  createEntity(e) {
514
579
  return new D(this.world, e);
515
580
  }
516
- }, k = c, A = class extends v.default {
581
+ }, k = c, A = 1e4, j = class extends v.default {
517
582
  heap;
518
583
  registry;
519
584
  factory;
@@ -524,6 +589,17 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
524
589
  timeScale = 1;
525
590
  paused = !1;
526
591
  destroyed = !1;
592
+ pristine = !0;
593
+ activeFreeBuffer = {
594
+ frees: [],
595
+ waitingSystems: /* @__PURE__ */ new Set(),
596
+ waitElapsed: 0
597
+ };
598
+ nextFreeBuffer = {
599
+ frees: [],
600
+ waitingSystems: /* @__PURE__ */ new Set(),
601
+ waitElapsed: 0
602
+ };
527
603
  constructor(e, t = {}) {
528
604
  super(), this.heap = new s({ bufferSize: t.heapSize ?? k });
529
605
  let n = {
@@ -542,8 +618,11 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
542
618
  async init() {
543
619
  await Promise.all(this.systems.map((e) => e.init()).filter((e) => e instanceof Promise));
544
620
  }
621
+ finishLoadingSystems() {
622
+ return Promise.all(this.systems.map((e) => e.finishLoading()).filter((e) => e instanceof Promise));
623
+ }
545
624
  addEntity(e, t = !0) {
546
- return this.entities.set(e.eid, e), e.world = this, e.on("component-added", (t) => {
625
+ return this.entities.set(e.eid, e), e.world = this, this.pristine = !1, e.on("component-added", (t) => {
547
626
  this.addEntityToComponentSystem(e, t);
548
627
  }), e.on("component-removed", (t) => {
549
628
  this.removeEntityFromComponentSystem(e, t);
@@ -555,13 +634,21 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
555
634
  return this.factory.loadEntity(e, t);
556
635
  }
557
636
  load(e) {
558
- for (let e of Array.from(this.entities.values())) this.removeEntity(e);
559
- this.systems.forEach((e) => e.clear());
637
+ if (!this.pristine) {
638
+ for (let e of Array.from(this.entities.values())) this.removeEntity(e);
639
+ this.systems.forEach((e) => e.clear()), this.consolidateFreeBuffersForReload();
640
+ }
560
641
  let t = e.entities.map((e) => this.loadEntity(e, !1));
561
642
  for (let e of t) e.finishLoading(), this.emit("entity-added", e), e.on("death", () => {
562
643
  this.onEntityDied(e);
563
644
  });
564
- this.gameTime = e.gameTime ?? 0, this.playerTime = e.playerTime ?? 0, this.timeScale = e.timeScale ?? 1;
645
+ this.gameTime = e.gameTime ?? 0, this.playerTime = e.playerTime ?? 0, this.timeScale = e.timeScale ?? 1, this.finishLoadingSystems();
646
+ }
647
+ async clear() {
648
+ if (!this.pristine) {
649
+ for (let e of Array.from(this.entities.values())) this.removeEntity(e);
650
+ this.systems.forEach((e) => e.clear()), await Promise.all(this.systems.map((e) => e.waitForRunToComplete()).filter((e) => e instanceof Promise)), this.freeAllPendingBuffers(), this.pristine = !0;
651
+ }
565
652
  }
566
653
  removeEntity(e) {
567
654
  this.entities.delete(e.eid) && this.emit("entity-removed", e), e.deleteAllComponentMemory();
@@ -572,6 +659,43 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
572
659
  getEntityByEid(e) {
573
660
  return this.entities.get(e);
574
661
  }
662
+ deferComponentMemoryFree(e, t, n) {
663
+ this.nextFreeBuffer.frees.push({
664
+ memoryComponent: e,
665
+ index: t,
666
+ free: n
667
+ });
668
+ }
669
+ notifySystemRunCompleted(e) {
670
+ this.activeFreeBuffer.waitingSystems.delete(e) && this.activeFreeBuffer.waitingSystems.size === 0 && this.processFreeBuffers();
671
+ }
672
+ processFreeBuffers() {
673
+ for (; this.activeFreeBuffer.waitingSystems.size === 0 && (this.activeFreeBuffer.frees.length > 0 && this.performFrees(this.activeFreeBuffer), this.nextFreeBuffer.frees.length !== 0);) this.promoteNextFreeBuffer();
674
+ }
675
+ promoteNextFreeBuffer() {
676
+ let e = this.activeFreeBuffer;
677
+ this.activeFreeBuffer = this.nextFreeBuffer, this.nextFreeBuffer = e;
678
+ let t = this.activeFreeBuffer;
679
+ t.waitElapsed = 0, t.waitingSystems.clear();
680
+ for (let e of this.systems) (e.shouldRun() || e.isCurrentlyRunning()) && t.waitingSystems.add(e);
681
+ }
682
+ consolidateFreeBuffersForReload() {
683
+ this.activeFreeBuffer.frees.length > 0 && (this.nextFreeBuffer.frees.push(...this.activeFreeBuffer.frees), this.activeFreeBuffer.frees.length = 0), this.activeFreeBuffer.waitingSystems.clear(), this.activeFreeBuffer.waitElapsed = 0;
684
+ }
685
+ freeAllPendingBuffers() {
686
+ this.performFrees(this.activeFreeBuffer), this.performFrees(this.nextFreeBuffer), this.activeFreeBuffer.waitingSystems.clear(), this.activeFreeBuffer.waitElapsed = 0, this.nextFreeBuffer.waitingSystems.clear(), this.nextFreeBuffer.waitElapsed = 0;
687
+ }
688
+ performFrees(e) {
689
+ for (let t of e.frees) t.free?.(), t.memoryComponent.delete(t.index);
690
+ e.frees.length = 0;
691
+ }
692
+ checkFreeBufferTimeout(e) {
693
+ let t = this.activeFreeBuffer;
694
+ if (t.waitingSystems.size !== 0 && (t.waitElapsed += e, t.waitElapsed >= A)) {
695
+ let e = Array.from(t.waitingSystems).map((e) => e.name).join(", ");
696
+ console.warn(`shared-memory-ecs: deferred component free waited over ${A}ms on system(s): ${e}; freeing anyway`), t.waitingSystems.clear(), this.processFreeBuffers();
697
+ }
698
+ }
575
699
  addSystem(e) {
576
700
  return this.systems.push(e), this.emit("system-added", e), e;
577
701
  }
@@ -592,23 +716,24 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
592
716
  }
593
717
  runUpdate(e) {
594
718
  if (this.playerTime += e, this.paused) return {};
595
- e = this.timeScale * e, this.gameTime += e;
596
- let t = null;
597
- return this.systems.forEach((n) => {
719
+ let t = e;
720
+ e = this.timeScale * e, this.gameTime += e, this.processFreeBuffers();
721
+ let n = null;
722
+ return this.systems.forEach((t) => {
598
723
  let r = !0, i = !1, a = !1;
599
- this.emit(`system-${n.name}-started`);
724
+ this.emit(`system-${t.name}-started`);
600
725
  try {
601
- r = n.shouldRun(), r && (i = n.update(e));
726
+ r = t.shouldRun(), r && (i = t.update(e));
602
727
  } catch (e) {
603
- let n = e;
604
- console.error(n.message, n), a = !0, t = n;
728
+ let t = e;
729
+ console.error(t.message, t), a = !0, n = t;
605
730
  }
606
- this.emit(`system-${n.name}-finished`, {
731
+ this.emit(`system-${t.name}-finished`, {
607
732
  ran: i,
608
733
  shouldRun: r,
609
734
  failed: a
610
735
  });
611
- }), { lastSystemError: t };
736
+ }), this.checkFreeBufferTimeout(t), { lastSystemError: n };
612
737
  }
613
738
  pause() {
614
739
  this.paused = !0;
@@ -638,19 +763,19 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
638
763
  };
639
764
  //#endregion
640
765
  //#region src/actions/kill-entity.ts
641
- function j(e) {
766
+ function M(e) {
642
767
  e.components.entity.dead = !0, e.emit("death");
643
768
  }
644
769
  //#endregion
645
770
  //#region src/performance-timing.ts
646
- var M = 1e3, N = {
771
+ var N = 1e3, P = {
647
772
  avg: 0,
648
773
  min: 0,
649
774
  max: 0,
650
775
  samples: 0
651
776
  };
652
- function P(e) {
653
- if (!e.length) return { ...N };
777
+ function F(e) {
778
+ if (!e.length) return { ...P };
654
779
  let t = 0, n = Infinity, r = 0;
655
780
  for (let i of e) t += i, i < n && (n = i), i > r && (r = i);
656
781
  return {
@@ -660,13 +785,13 @@ function P(e) {
660
785
  samples: e.length
661
786
  };
662
787
  }
663
- var F = class extends v.default {
788
+ var I = class extends v.default {
664
789
  world;
665
790
  ticksBetweenUpdates;
666
791
  stats = {
667
- update: { ...N },
792
+ update: { ...P },
668
793
  systems: [],
669
- events: { ...N }
794
+ events: { ...P }
670
795
  };
671
796
  ticks = 0;
672
797
  updateStart = 0;
@@ -683,9 +808,9 @@ var F = class extends v.default {
683
808
  this.ticks = 0, this.updateTimes = [], this.systemTimings.forEach((e) => {
684
809
  e.run = [], e.events = [], e.eventStart = -1;
685
810
  }), this.stats = {
686
- update: { ...N },
811
+ update: { ...P },
687
812
  systems: [],
688
- events: { ...N }
813
+ events: { ...P }
689
814
  };
690
815
  }
691
816
  destroy() {
@@ -727,14 +852,14 @@ var F = class extends v.default {
727
852
  let t = this.systemTimings.get(e.name);
728
853
  return {
729
854
  name: e.name,
730
- run: P(t?.run ?? []),
731
- events: P(t?.events ?? [])
855
+ run: F(t?.run ?? []),
856
+ events: F(t?.events ?? [])
732
857
  };
733
- }), t = { ...N };
858
+ }), t = { ...P };
734
859
  e.forEach((e) => {
735
860
  t.avg += e.events.avg, t.min += e.events.min, t.max += e.events.max, t.samples += e.events.samples;
736
861
  }), this.stats = {
737
- update: P(this.updateTimes),
862
+ update: F(this.updateTimes),
738
863
  systems: e,
739
864
  events: t
740
865
  }, this.ticks = 0, this.updateTimes = [], this.systemTimings.forEach((e) => {
@@ -743,6 +868,6 @@ var F = class extends v.default {
743
868
  }
744
869
  };
745
870
  //#endregion
746
- export { D as BaseEntity, A as BaseWorld, E as ComponentSystem, w as ComponentWebWorker, t as DEAD_INDEX, M as DEFAULT_TICKS_BETWEEN_UPDATES, O as EntityFactory, S as EntitySystem, x as IterableSystem, y as MemoryComponent, F as PerformanceTiming, e as STATIC_INDEX, b as System, C as WebWorker, o as createComponentWorker, n as createEntityWorker, r as entityDefinition, j as killEntity, i as killEntityWorker };
871
+ export { D as BaseEntity, j as BaseWorld, E as ComponentSystem, w as ComponentWebWorker, t as DEAD_INDEX, N as DEFAULT_TICKS_BETWEEN_UPDATES, O as EntityFactory, S as EntitySystem, x as IterableSystem, y as MemoryComponent, I as PerformanceTiming, e as STATIC_INDEX, b as System, C as WebWorker, o as createComponentWorker, n as createEntityWorker, r as entityDefinition, M as killEntity, i as killEntityWorker };
747
872
 
748
873
  //# sourceMappingURL=index.js.map