@daneren2005/shared-memory-ecs 1.8.1 → 1.9.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,17 +1,17 @@
1
- import { _ as e, a as t, c as n, d as r, f as i, g as a, h as o, i as s, l as c, m as l, n as u, o as d, p as f, r as p, s as m, t as h, u as g, v as _ } from "./create-system-worker-C4aS3-3R.js";
2
- import v from "@daneren2005/shared-memory-objects/memory-heap";
3
- import { MAX_BYTE_OFFSET_LENGTH as y } from "@daneren2005/shared-memory-objects/utils/pointer";
1
+ import { _ as e, a as t, c as n, d as r, f as i, g as a, h as o, i as s, l as c, m as l, n as u, o as d, p as f, r as p, s as m, t as h, u as g, v as _, y as v } from "./create-system-worker-CNpRs2FO.js";
2
+ import y from "@daneren2005/shared-memory-objects/memory-heap";
3
+ import { MAX_BYTE_OFFSET_LENGTH as b } from "@daneren2005/shared-memory-objects/utils/pointer";
4
4
  //#region \0rolldown/runtime.js
5
- var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescriptor, C = Object.getOwnPropertyNames, w = Object.getPrototypeOf, T = Object.prototype.hasOwnProperty, E = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), D = (e, t, n, r) => {
6
- if (t && typeof t == "object" || typeof t == "function") for (var i = C(t), a = 0, o = i.length, s; a < o; a++) s = i[a], !T.call(e, s) && s !== n && x(e, s, {
5
+ var x = Object.create, S = Object.defineProperty, C = Object.getOwnPropertyDescriptor, w = Object.getOwnPropertyNames, T = Object.getPrototypeOf, E = Object.prototype.hasOwnProperty, D = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), O = (e, t, n, r) => {
6
+ if (t && typeof t == "object" || typeof t == "function") for (var i = w(t), a = 0, o = i.length, s; a < o; a++) s = i[a], !E.call(e, s) && s !== n && S(e, s, {
7
7
  get: ((e) => t[e]).bind(null, s),
8
- enumerable: !(r = S(t, s)) || r.enumerable
8
+ enumerable: !(r = C(t, s)) || r.enumerable
9
9
  });
10
10
  return e;
11
- }, O = /* @__PURE__ */ ((e, t, n) => (n = e == null ? {} : b(w(e)), D(t || !e || !e.__esModule || !T.call(e, "default") ? x(n, "default", {
11
+ }, k = /* @__PURE__ */ ((e, t, n) => (n = e == null ? {} : x(T(e)), O(t || !e || !e.__esModule || !E.call(e, "default") ? S(n, "default", {
12
12
  value: e,
13
13
  enumerable: !0
14
- }) : n, e)))((/* @__PURE__ */ E(((e, t) => {
14
+ }) : n, e)))((/* @__PURE__ */ D(((e, t) => {
15
15
  var n = Object.prototype.hasOwnProperty, r = "~";
16
16
  function i() {}
17
17
  Object.create && (i.prototype = Object.create(null), new i().__proto__ || (r = !1));
@@ -98,14 +98,18 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
98
98
  var t;
99
99
  return e ? (t = r ? r + e : e, this._events[t] && s(this, t)) : (this._events = new i(), this._eventsCount = 0), this;
100
100
  }, c.prototype.off = c.prototype.removeListener, c.prototype.addListener = c.prototype.on, c.prefixed = r, c.EventEmitter = c, t !== void 0 && (t.exports = c);
101
- })))(), 1), k = class extends O.default {
101
+ })))(), 1), A = class extends k.default {
102
102
  world;
103
103
  name;
104
104
  currentDelta = 0;
105
105
  deltaBetweenRuns;
106
106
  firstRun;
107
+ reads;
108
+ writes;
109
+ exclusive;
110
+ scheduledGameTime;
107
111
  constructor(e, t = { name: "System" }) {
108
- super(), this.name = t.name, this.world = e, this.deltaBetweenRuns = t.deltaBetweenRuns ?? 0, this.firstRun = t.firstRun !== void 0 && t.firstRun;
112
+ super(), this.name = t.name, this.world = e, this.reads = t.reads, this.writes = t.writes, this.exclusive = t.exclusive ?? !1, this.deltaBetweenRuns = t.deltaBetweenRuns ?? 0, this.firstRun = t.firstRun !== void 0 && t.firstRun;
109
113
  }
110
114
  init() {}
111
115
  clear() {
@@ -113,6 +117,18 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
113
117
  }
114
118
  finishLoading() {}
115
119
  addEntities(e) {}
120
+ get gameTime() {
121
+ return this.scheduledGameTime ?? this.world.gameTime;
122
+ }
123
+ withGameTime(e, t) {
124
+ let n = this.scheduledGameTime;
125
+ this.scheduledGameTime = e;
126
+ try {
127
+ return t();
128
+ } finally {
129
+ this.scheduledGameTime = n;
130
+ }
131
+ }
116
132
  update(e) {
117
133
  if (this.currentDelta += e, this.currentDelta >= this.deltaBetweenRuns || this.firstRun) {
118
134
  let e = 0;
@@ -141,17 +157,30 @@ var b = Object.create, x = Object.defineProperty, S = Object.getOwnPropertyDescr
141
157
  shouldRun() {
142
158
  return !0;
143
159
  }
160
+ get readComponents() {
161
+ return this.reads;
162
+ }
163
+ get requiresExclusiveScheduling() {
164
+ return this.exclusive;
165
+ }
166
+ get createdComponents() {
167
+ return [];
168
+ }
169
+ get creationReadComponents() {
170
+ return this.readComponents;
171
+ }
172
+ get creationReadQueries() {}
144
173
  destroy() {
145
174
  this.removeAllListeners();
146
175
  }
147
176
  };
148
- function A(e, t, n) {
177
+ function j(e, t, n) {
149
178
  let r = e.groups.map(t);
150
179
  for (let t = 0; t < e.entities.length; t++) r[e.groupIndexes[t]] && n(e.entities[t]);
151
180
  }
152
181
  //#endregion
153
182
  //#region src/systems/iterable-system.ts
154
- var j = class extends k {
183
+ var M = class extends A {
155
184
  remainingInstancesToRun = [];
156
185
  remainingInstancesStartTime = null;
157
186
  iterationsPerCheck;
@@ -201,7 +230,7 @@ var j = class extends k {
201
230
  }
202
231
  beforeRunIterables() {}
203
232
  getIterableEntityId(e) {}
204
- }, M = class e extends j {
233
+ }, N = class e extends M {
205
234
  entities = /* @__PURE__ */ new Map();
206
235
  options;
207
236
  constructor(e, t = { name: "EntitySystem" }) {
@@ -239,7 +268,7 @@ var j = class extends k {
239
268
  t.entities.forEach((e) => this.onEntityAdded(e));
240
269
  return;
241
270
  }
242
- A(t, (e) => this.hasComponents(e), (e) => {
271
+ j(t, (e) => this.hasComponents(e), (e) => {
243
272
  this.filterEntity(e) && (this.entities.set(e.eid, e), this.options.updateEntityOnAdd && this.updateEntity(e, 0));
244
273
  });
245
274
  }
@@ -255,11 +284,28 @@ var j = class extends k {
255
284
  shouldRun() {
256
285
  return this.isCurrentlyRunning() || this.entities.size > 0;
257
286
  }
258
- }, N = class {
287
+ get creationReadComponents() {
288
+ if (!this.options.components) return this.reads ? ["entity", ...this.reads] : void 0;
289
+ let e = this.options.components.filter((e) => e !== "entity");
290
+ return [...this.reads ?? [], ...e.length ? e : ["entity"]];
291
+ }
292
+ get creationReadQueries() {
293
+ if (this.checkAddEntity === e.prototype.checkAddEntity) return [this.options.components ?? []];
294
+ }
295
+ get readComponents() {
296
+ let e = this.options.components ?? this.reads;
297
+ return e ? [
298
+ "entity",
299
+ ...e,
300
+ ...this.reads ?? []
301
+ ] : void 0;
302
+ }
303
+ }, P = class {
259
304
  onmessage(e, t = []) {}
260
- }, P = class extends N {
305
+ }, F = class extends P {
261
306
  updateFunction;
262
307
  entities = [];
308
+ workState = new a();
263
309
  queryEntities = {};
264
310
  worldExtension;
265
311
  world;
@@ -274,57 +320,67 @@ var j = class extends k {
274
320
  allocateComponentBlock: (e, t) => i[e].memoryComponent.create(t)
275
321
  };
276
322
  }
277
- postMessage(e) {
278
- if (e.type === "init") this.onMessageTyped({ type: "init-complete" });
279
- else if (e.type === "load") this.worldExtension = this.updateFunction.init?.(e.data) ?? void 0, this.onMessageTyped({ type: "loaded" });
280
- else if (e.type === "reset") this.entities = [], this.queryEntities = {};
281
- else if (e.type === "run") {
282
- if (this.worldExtension && Object.assign(e.world, this.worldExtension), e.world.getString = (e) => this.world.constantStrings.getString(e) ?? "", e.world.heap = this.world.heap, e.world.allocate = this.allocator, this.createsEntities) {
283
- let t = this.world.registry;
284
- e.world.buildEntityDescriptor = (e) => o(e, this.world.factory.configs, t, this.allocator, this.world.factory.getWorkerClasses());
323
+ getString = (e) => this.world.constantStrings.getString(e) ?? "";
324
+ postMessage(t) {
325
+ if (t.type === "init") this.onMessageTyped({ type: "init-complete" });
326
+ else if (t.type === "load") {
327
+ this.entities = e(this.entities, t.entities), Object.entries(t.queries).forEach(([t, n]) => {
328
+ this.queryEntities[t] = e(this.queryEntities[t] ?? [], n);
329
+ });
330
+ let n = {
331
+ gameTime: t.gameTime,
332
+ getString: this.getString,
333
+ heap: this.world.heap
334
+ };
335
+ this.worldExtension = this.updateFunction.init?.(n, t.data, this.entities, this.queryEntities) ?? void 0, this.onMessageTyped({ type: "loaded" });
336
+ } else if (t.type === "reset") this.workState.clear(), this.entities = [], this.queryEntities = {};
337
+ else if (t.type === "run") {
338
+ if (t.world = this.workState.getWorld(t.world, t.workBatch), this.worldExtension && Object.assign(t.world, this.worldExtension), t.world.getString = this.getString, t.world.heap = this.world.heap, t.world.allocate = this.allocator, this.createsEntities) {
339
+ let e = this.world.registry;
340
+ t.world.buildEntityDescriptor = (t) => o(t, this.world.factory.configs, e, this.allocator, this.world.factory.getWorkerClasses());
285
341
  }
286
342
  if (this.addsComponents) {
287
- let t = this.world.registry;
288
- e.world.buildComponentDescriptor = (e, n) => l(e, n, t, this.allocator);
343
+ let e = this.world.registry;
344
+ t.world.buildComponentDescriptor = (t, n) => l(t, n, e, this.allocator);
289
345
  }
290
- let t = performance.now(), n = [], r = {}, i = [], s = [], c = [];
291
- this.entities = a(this.entities, e.entities);
292
- let u = {};
293
- Object.entries(e.queries).forEach(([e, t]) => {
294
- let n = a(this.queryEntities[e] ?? [], t);
295
- this.queryEntities[e] = n, u[e] = n;
346
+ let n = performance.now(), r = [], i = {}, a = [], s = [], c = [];
347
+ this.entities = e(this.entities, t.entities);
348
+ let u = this.workState.getEntities(this.entities, t.entities, t.workBatch), d = {};
349
+ Object.entries(t.queries).forEach(([t, n]) => {
350
+ let r = e(this.queryEntities[t] ?? [], n);
351
+ this.queryEntities[t] = r, d[t] = r;
296
352
  });
297
- let d = {
298
- entityComponentChanged(e, t, r, i) {
299
- n.push({
353
+ let f = {
354
+ entityComponentChanged(e, t, n, i) {
355
+ r.push({
300
356
  entityId: e,
301
357
  event: "component-property-updated",
302
358
  args: [
303
359
  t,
304
- r,
360
+ n,
305
361
  i
306
362
  ]
307
363
  });
308
364
  },
309
- emitEntityEvent(e, t, ...r) {
310
- n.push({
365
+ emitEntityEvent(e, t, ...n) {
366
+ r.push({
311
367
  entityId: e,
312
368
  event: t,
313
- args: r
369
+ args: n
314
370
  });
315
371
  },
316
372
  emitSystemEvent(e, t) {
317
- (r[e] ?? (r[e] = [])).push(t);
373
+ (i[e] ?? (i[e] = [])).push(t);
318
374
  },
319
375
  entityDied(e) {
320
- n.push({
376
+ r.push({
321
377
  entityId: e,
322
378
  event: "death",
323
379
  args: []
324
380
  });
325
381
  },
326
382
  createEntity(e) {
327
- i.push(e);
383
+ a.push(e);
328
384
  },
329
385
  addComponent(e, t) {
330
386
  s.push({
@@ -342,8 +398,8 @@ var j = class extends k {
342
398
  }
343
399
  };
344
400
  if (this.updateFunction.queryChanged) {
345
- for (let [t, n] of Object.entries(e.queries)) if (n.added.length || n.removed.length) try {
346
- this.updateFunction.queryChanged(e.world, t, n, d);
401
+ for (let [e, n] of Object.entries(t.queries)) if (n.added.length || n.removed.length) try {
402
+ this.updateFunction.queryChanged(t.world, e, n, f);
347
403
  } catch (e) {
348
404
  c.push({
349
405
  error: e,
@@ -351,65 +407,80 @@ var j = class extends k {
351
407
  });
352
408
  }
353
409
  }
354
- let f = !1;
355
- if (this.updateFunction.preRun) try {
356
- this.updateFunction.preRun(e.world, this.entities, u, d);
410
+ let p = !1;
411
+ if (this.updateFunction.preRun && (!t.workBatch || t.workBatch.first)) try {
412
+ this.updateFunction.preRun(t.world, this.entities, d, f);
357
413
  } catch (e) {
358
- f = !0, c.push({
414
+ p = !0, c.push({
359
415
  error: e,
360
416
  phase: "preRun"
361
417
  });
362
418
  }
363
- if (f || this.entities.forEach((t) => {
419
+ if (!p && this.updateFunction.preBatch) try {
420
+ this.updateFunction.preBatch(t.world, u, d, f);
421
+ } catch (e) {
422
+ p = !0, c.push({
423
+ error: e,
424
+ phase: "preBatch"
425
+ });
426
+ }
427
+ if (p || u.forEach((e) => {
364
428
  try {
365
- this.updateFunction(e.world, t.entityId, t.components, u, d);
366
- } catch (e) {
429
+ this.updateFunction(t.world, e.entityId, e.components, d, f);
430
+ } catch (t) {
367
431
  c.push({
368
- error: e,
432
+ error: t,
369
433
  phase: "update",
370
- entityId: t.entityId
434
+ entityId: e.entityId
371
435
  });
372
436
  }
373
- }), this.updateFunction.entityRemoved) for (let t of e.entities.removed) try {
374
- this.updateFunction.entityRemoved(e.world, t, d);
375
- } catch (e) {
437
+ }), this.updateFunction.entityRemoved) for (let e of t.entities.removed) try {
438
+ this.updateFunction.entityRemoved(t.world, e, f);
439
+ } catch (t) {
376
440
  c.push({
377
- error: e,
441
+ error: t,
378
442
  phase: "entityRemoved",
379
- entityId: t
443
+ entityId: e
380
444
  });
381
445
  }
382
- let p = performance.now() - t;
383
- this.onMessageTyped({
446
+ let m = performance.now() - n;
447
+ this.workState.finish(t.workBatch, p), this.onMessageTyped({
384
448
  type: "run-complete",
385
- generation: e.generation,
386
- runTime: p,
387
- events: n,
388
- systemEvents: r,
389
- created: i,
449
+ generation: t.generation,
450
+ runTime: m,
451
+ events: r,
452
+ systemEvents: i,
453
+ created: a,
390
454
  componentChanges: s,
391
- errors: c
455
+ errors: c,
456
+ workFailed: p
392
457
  });
393
458
  }
394
459
  }
395
460
  onMessageTyped(e) {
396
461
  this.onmessage({ data: e });
397
462
  }
398
- }, F = "___main", I = class e extends k {
463
+ }, I = "___main", L = class e extends A {
399
464
  entities = /* @__PURE__ */ new Map();
400
465
  options;
401
466
  worker;
402
467
  isWorkerThread;
403
468
  initialized = !1;
404
469
  initPromise = null;
470
+ initError = null;
405
471
  loadingPromise = null;
406
472
  runCompletePromise = null;
407
473
  isRunning = !1;
474
+ workPass;
475
+ timingBatch;
476
+ pendingEffects;
477
+ completeEffects;
408
478
  generation = 0;
409
479
  queryEntities = {};
410
480
  queryDeltas = {};
411
481
  constructor(e, t) {
412
- super(e, t), this.options = t, Object.keys(this.options.queries ?? {}).forEach((e) => {
482
+ if (super(e, t), t.workBatchSize !== void 0 && (!Number.isSafeInteger(t.workBatchSize) || t.workBatchSize <= 0)) throw Error("workBatchSize must be a positive safe integer");
483
+ this.options = t, Object.keys(this.options.queries ?? {}).forEach((e) => {
413
484
  this.queryEntities[e] = /* @__PURE__ */ new Map();
414
485
  }), e.on("entity-added", (t) => {
415
486
  e.isBulkLoading || this.checkAddEntity(t);
@@ -422,55 +493,102 @@ var j = class extends k {
422
493
  type: "grow-buffer",
423
494
  buffer: e
424
495
  });
425
- })) : (this.worker = new P(t.updateFunction, e, !!t.createsEntities, !!t.addsComponents), this.isWorkerThread = !1), this.initWorker();
496
+ })) : (this.worker = new F(t.updateFunction, e, !!t.createsEntities, !!t.addsComponents), this.isWorkerThread = !1), this.initWorker();
426
497
  }
427
498
  initWorker() {
428
- this.worker.onmessage = (e) => {
429
- let t = e.data;
430
- if (t.type === "init-complete") this.initialized = !0, this.initPromise &&= (this.initPromise.resolve(), null);
431
- else if (t.type === "loaded") this.loadingPromise &&= (this.loadingPromise.resolve(), null);
432
- else if (t.type === "grow-buffer-from-worker") this.world.addGrownBuffer(t.buffer);
433
- else if (t.type === "run-complete") {
434
- if (t.generation !== this.generation) return;
435
- this.isRunning = !1, this.world.emit(`system-${this.name}-worker-finished`, t.runTime), t.errors.forEach(({ error: e, entityId: t, phase: n }) => {
436
- this.onError(e, {
437
- entityId: t,
438
- phase: n
439
- });
440
- }), (t.componentChanges ?? []).forEach((e) => {
441
- let t = this.world.getEntityByEid(e.entityId);
442
- if (e.type === "add") {
443
- let n = this.world.registry[e.component.name];
444
- if (!t || !n || e.component.name === "entity") {
445
- n?.memoryComponent.delete(e.component.index);
446
- return;
499
+ let e = (e) => {
500
+ console.error(e, e.cause), this.initialized || (this.initError = e, this.initPromise?.reject(e));
501
+ };
502
+ if (!(this.worker instanceof F)) {
503
+ let t = (t) => {
504
+ e(Error(`Worker ${this.name} failed to load`, { cause: t }));
505
+ };
506
+ this.worker.onerror = t, this.worker.onmessageerror = t;
507
+ }
508
+ this.worker.onmessage = (t) => {
509
+ let n = t.data;
510
+ if (n.type === "unhandled-rejection") e(Error(`Worker ${this.name} had an unhandled promise rejection`, { cause: n.error }));
511
+ else if (n.type === "init-complete") this.initialized = !0, this.initPromise &&= (this.initPromise.resolve(), null);
512
+ else if (n.type === "loaded") this.loadingPromise &&= (this.loadingPromise.resolve(), null);
513
+ else if (n.type === "grow-buffer-from-worker") this.world.addGrownBuffer(n.buffer);
514
+ else if (n.type === "run-complete") {
515
+ if (n.generation !== this.generation) {
516
+ this.world.scheduler.prepareEffects && this.discardWorkerAllocations(n);
517
+ return;
518
+ }
519
+ let e = this.timingBatch && {
520
+ ...this.timingBatch,
521
+ last: this.timingBatch.last || !!n.workFailed
522
+ };
523
+ if (n.workFailed && (this.workPass = void 0), !this.completeEffects) {
524
+ this.applyWorkerEffects(n, !0, e);
525
+ return;
526
+ }
527
+ this.world.emit(`system-${this.name}-worker-finished`, n.runTime, e);
528
+ let t = this.generation, r = !1, i = () => {
529
+ this.pendingEffects = void 0, this.isRunning = !1, this.runCompletePromise?.resolve(), this.runCompletePromise = null;
530
+ }, a = {
531
+ apply: () => {
532
+ if (!r) {
533
+ if (t !== this.generation) {
534
+ a.discard();
535
+ return;
536
+ }
537
+ r = !0, this.pendingEffects = void 0;
538
+ try {
539
+ this.applyWorkerEffects(n, !1, e);
540
+ } catch (e) {
541
+ this.onError(e, { phase: "run" }), this.world.notifySystemRunCompleted(this);
542
+ } finally {
543
+ i();
544
+ }
447
545
  }
448
- let r = e.component.name;
449
- t.removeComponent(r), t.attachComponent(r, e.component.index, !0);
450
- } else t && e.componentName !== "entity" && t.removeComponent(e.componentName);
451
- });
452
- for (let e of Object.keys(t.systemEvents)) this.emit(e, t.systemEvents[e]);
453
- t.events.forEach((e) => {
454
- let t = this.world.getEntityByEid(e.entityId);
455
- if (!t) {
456
- console.warn(`${this.name}-event ${e.event}: Could not find entity with id ${e.entityId}`);
457
- return;
546
+ },
547
+ discard: () => {
548
+ r || (r = !0, this.discardWorkerAllocations(n), i());
458
549
  }
459
- t.emit(e.event, ...e.args);
460
- }), t.created.forEach((e) => {
461
- this.world.adoptEntity(e);
462
- }), this.world.emit(`system-${this.name}-worker-events-finished`, t.runTime), this.world.notifySystemRunCompleted(this), this.runCompletePromise &&= (this.runCompletePromise.resolve(), null);
550
+ };
551
+ this.pendingEffects = a, this.completeEffects(a);
463
552
  }
464
553
  }, this.worker.postMessage({ type: "init" });
465
554
  }
555
+ applyWorkerEffects(e, t, n) {
556
+ this.isRunning = !1, t && this.world.emit(`system-${this.name}-worker-finished`, e.runTime, n), e.errors.forEach(({ error: e, entityId: t, phase: n }) => {
557
+ this.onError(e, {
558
+ entityId: t,
559
+ phase: n
560
+ });
561
+ }), (e.componentChanges ?? []).forEach((e) => {
562
+ let t = this.world.getEntityByEid(e.entityId);
563
+ if (e.type === "add") {
564
+ let n = this.world.registry[e.component.name];
565
+ if (!t || !n || e.component.name === "entity") {
566
+ n?.memoryComponent.delete(e.component.index);
567
+ return;
568
+ }
569
+ let r = e.component.name;
570
+ t.removeComponent(r), t.attachComponent(r, e.component.index, !0);
571
+ } else t && e.componentName !== "entity" && t.removeComponent(e.componentName);
572
+ });
573
+ for (let t of Object.keys(e.systemEvents)) this.emit(t, e.systemEvents[t]);
574
+ e.events.forEach((e) => {
575
+ let t = this.world.getEntityByEid(e.entityId);
576
+ if (!t) {
577
+ console.warn(`${this.name}-event ${e.event}: Could not find entity with id ${e.entityId}`);
578
+ return;
579
+ }
580
+ t.emit(e.event, ...e.args);
581
+ }), e.created.forEach((e) => {
582
+ this.world.adoptEntity(e);
583
+ }), this.world.emit(`system-${this.name}-worker-events-finished`, e.runTime, n), this.world.notifySystemRunCompleted(this), this.runCompletePromise &&= (this.runCompletePromise.resolve(), null);
584
+ }
585
+ discardWorkerAllocations(e) {
586
+ for (let t of e.created) for (let [e, n] of Object.entries(t.components)) this.world.registry[e]?.memoryComponent.delete(n);
587
+ for (let t of e.componentChanges ?? []) t.type === "add" && this.world.registry[t.component.name]?.memoryComponent.delete(t.component.index);
588
+ }
466
589
  init() {
467
- if (this.initialized) return;
468
- if (this.initPromise) return this.initPromise.promise;
469
- let { promise: e, resolve: t } = Promise.withResolvers();
470
- return this.initPromise = {
471
- promise: e,
472
- resolve: t
473
- }, e;
590
+ if (this.initError) return Promise.reject(this.initError);
591
+ if (!this.initialized) return this.initPromise ||= Promise.withResolvers(), this.initPromise.promise;
474
592
  }
475
593
  finishLoading() {
476
594
  let { promise: e, resolve: t } = Promise.withResolvers();
@@ -478,34 +596,72 @@ var j = class extends k {
478
596
  promise: e,
479
597
  resolve: t
480
598
  };
481
- let n = {
599
+ let n = {};
600
+ Object.entries(this.options.queries ?? {}).forEach(([e, t]) => {
601
+ n[e] = this.buildQueryDelta(e, t);
602
+ });
603
+ let r = {
482
604
  type: "load",
483
605
  data: this.options.getInitData?.(),
606
+ gameTime: this.gameTime,
607
+ entities: this.buildQueryDelta(I, this.options),
608
+ queries: n,
484
609
  heap: this.isWorkerThread ? this.world.heap.getSharedMemory() : void 0,
485
610
  sharedMemory: this.isWorkerThread ? this.world.getSharedComponentMemory() : void 0,
486
611
  factoryConfigs: this.isWorkerThread && this.options.createsEntities ? this.world.factory.configs : void 0,
487
612
  factoryClasses: this.isWorkerThread && this.options.createsEntities ? this.world.factory.getWorkerClasses() : void 0,
488
613
  addsComponents: !!this.options.addsComponents
489
614
  };
490
- return this.worker.postMessage(n), e;
615
+ return this.worker.postMessage(r), e;
491
616
  }
492
617
  clear() {
493
- if (super.clear(), this.isRunning && !this.runCompletePromise) {
618
+ if (super.clear(), this.pendingEffects?.discard(), this.isRunning && !this.runCompletePromise) {
494
619
  let { promise: e, resolve: t } = Promise.withResolvers();
495
620
  this.runCompletePromise = {
496
621
  promise: e,
497
622
  resolve: t
498
623
  };
499
624
  }
500
- this.isRunning = !1, this.generation++, this.entities.clear(), Object.values(this.queryEntities).forEach((e) => e.clear()), this.queryDeltas = {}, this.worker.postMessage({ type: "reset" });
625
+ this.isRunning = !1, this.generation++, this.entities.clear(), Object.values(this.queryEntities).forEach((e) => e.clear()), this.queryDeltas = {}, this.workPass = void 0, this.timingBatch = void 0, this.worker.postMessage({ type: "reset" });
501
626
  }
502
627
  update(e) {
503
- return this.isRunning ? (this.currentDelta += e, !1) : super.update(e);
628
+ return this.isRunning ? (this.currentDelta += e, !1) : this.workPass ? (this.currentDelta += e, this.run(this.workPass.elapsedTime), !0) : super.update(e);
504
629
  }
505
630
  onRunFinished() {}
506
631
  isCurrentlyRunning() {
507
632
  return this.isRunning;
508
633
  }
634
+ get readComponents() {
635
+ let e = [this.options, ...Object.values(this.options.queries ?? {})];
636
+ return [
637
+ "entity",
638
+ ...this.reads ?? [],
639
+ ...e.flatMap((e) => [...e.required, ...e.optional ?? []])
640
+ ];
641
+ }
642
+ get requiresExclusiveScheduling() {
643
+ return super.requiresExclusiveScheduling || this.options.createsEntities === !0 || !!this.options.addsComponents;
644
+ }
645
+ get createdComponents() {
646
+ let e = this.options.createsEntities;
647
+ return e && typeof e != "boolean" ? ["entity", ...e] : [];
648
+ }
649
+ get creationReadComponents() {
650
+ let e = Object.values(this.options.queries ?? {});
651
+ return this.tracksMainQuery && e.push(this.options), [...this.reads ?? [], ...e.flatMap((e) => {
652
+ let t = e.required.filter((e) => e !== "entity"), n = e.optional?.filter((e) => e !== "entity") ?? [];
653
+ return [
654
+ ...t.length ? t : ["entity"],
655
+ ...n,
656
+ ...e.not ?? []
657
+ ];
658
+ })];
659
+ }
660
+ get creationReadQueries() {
661
+ if (this.checkAddEntity !== e.prototype.checkAddEntity || this.matchesQuery !== e.prototype.matchesQuery) return;
662
+ let t = Object.values(this.options.queries ?? {});
663
+ return this.tracksMainQuery && t.push(this.options), t.map((e) => e.required);
664
+ }
509
665
  waitForRunToComplete() {
510
666
  if (this.isRunning) {
511
667
  if (!this.runCompletePromise) {
@@ -519,23 +675,48 @@ var j = class extends k {
519
675
  }
520
676
  }
521
677
  run(e) {
522
- let t = {
523
- gameTime: this.world.gameTime,
678
+ let t, n = this.gameTime;
679
+ if (this.options.workBatchSize !== void 0 && this.tracksMainQuery) {
680
+ let r = !this.workPass, i = this.workPass ??= {
681
+ entities: Array.from(this.entities.values()),
682
+ cursor: 0,
683
+ elapsedTime: e,
684
+ gameTime: n
685
+ };
686
+ n = i.gameTime, e = i.elapsedTime;
687
+ let a = Math.min(i.cursor + this.options.workBatchSize, i.entities.length), o = [];
688
+ for (; i.cursor < a; i.cursor++) {
689
+ let e = i.entities[i.cursor];
690
+ this.entities.get(e.eid) === e && o.push(e.eid);
691
+ }
692
+ let s = i.cursor === i.entities.length;
693
+ t = {
694
+ entityIds: o,
695
+ first: r,
696
+ last: s
697
+ }, s && (this.workPass = void 0);
698
+ }
699
+ let r = {
700
+ gameTime: n,
524
701
  elapsedTime: e
525
702
  };
526
- this.addDataToWorld?.(t), this.isRunning = !0;
527
- let n = this.buildQueryDelta(F, this.options), r = {};
703
+ (!t || t.first) && this.addDataToWorld?.(r), this.timingBatch = t && {
704
+ first: t.first,
705
+ last: t.last
706
+ }, this.isRunning = !0, this.completeEffects = this.world.scheduler.prepareEffects?.(this.world, this);
707
+ let i = this.buildQueryDelta(I, this.options), a = {};
528
708
  Object.entries(this.options.queries ?? {}).forEach(([e, t]) => {
529
- r[e] = this.buildQueryDelta(e, t);
709
+ a[e] = this.buildQueryDelta(e, t);
530
710
  });
531
- let i = {
711
+ let o = {
532
712
  type: "run",
533
713
  generation: this.generation,
534
- world: t,
535
- entities: n,
536
- queries: r
714
+ world: r,
715
+ entities: i,
716
+ queries: a,
717
+ workBatch: t
537
718
  };
538
- this.worker.postMessage(i);
719
+ this.worker.postMessage(o);
539
720
  }
540
721
  buildQueryDelta(e, t) {
541
722
  let n = this.getQueryDelta(e), r = [];
@@ -592,7 +773,7 @@ var j = class extends k {
592
773
  }
593
774
  checkAddEntity(e) {
594
775
  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]) => {
776
+ return this.updateEntityList(I, this.entities, e, t), Object.entries(this.options.queries ?? {}).forEach(([t, n]) => {
596
777
  let r = this.queryEntities[t] ?? (this.queryEntities[t] = /* @__PURE__ */ new Map());
597
778
  this.updateEntityList(t, r, e, this.matchesQuery(e, n));
598
779
  }), t;
@@ -602,19 +783,19 @@ var j = class extends k {
602
783
  t.entities.forEach((e) => this.checkAddEntity(e));
603
784
  return;
604
785
  }
605
- this.tracksMainQuery && this.addBatchToQuery(F, this.entities, this.options, t), Object.entries(this.options.queries ?? {}).forEach(([e, n]) => {
786
+ this.tracksMainQuery && this.addBatchToQuery(I, this.entities, this.options, t), Object.entries(this.options.queries ?? {}).forEach(([e, n]) => {
606
787
  let r = this.queryEntities[e] ?? (this.queryEntities[e] = /* @__PURE__ */ new Map());
607
788
  this.addBatchToQuery(e, r, n, t);
608
789
  });
609
790
  }
610
791
  addBatchToQuery(e, t, n, r) {
611
792
  let i = this.getQueryDelta(e);
612
- A(r, (e) => this.matchesComponents(e, n), (e) => {
793
+ j(r, (e) => this.matchesComponents(e, n), (e) => {
613
794
  e.components.entity.dead || n.filter && !n.filter(e) || (t.set(e.eid, e), this.markAdded(i, e));
614
795
  });
615
796
  }
616
797
  removeEntity(e) {
617
- this.updateEntityList(F, this.entities, e, !1), Object.entries(this.queryEntities).forEach(([t, n]) => {
798
+ this.updateEntityList(I, this.entities, e, !1), Object.entries(this.queryEntities).forEach(([t, n]) => {
618
799
  this.updateEntityList(t, n, e, !1);
619
800
  });
620
801
  }
@@ -624,12 +805,12 @@ var j = class extends k {
624
805
  });
625
806
  }
626
807
  shouldRun() {
627
- return this.entities.size > 0;
808
+ return this.workPass !== void 0 || this.entities.size > 0;
628
809
  }
629
810
  destroy() {
630
- super.destroy(), "terminate" in this.worker && this.worker.terminate();
811
+ super.destroy(), this.pendingEffects?.discard(), "terminate" in this.worker && this.worker.terminate();
631
812
  }
632
- }, L = class extends O.default {
813
+ }, R = class extends k.default {
633
814
  eid;
634
815
  config;
635
816
  world;
@@ -730,7 +911,7 @@ var j = class extends k {
730
911
  assertComponentPropertyMutable(e, t) {
731
912
  if (e === "entity" && (t === "type" || t === "class")) throw Error(`Entity ${t} is immutable`);
732
913
  }
733
- }, R = class e {
914
+ }, z = class e {
734
915
  world;
735
916
  configs;
736
917
  classes;
@@ -747,7 +928,7 @@ var j = class extends k {
747
928
  this.world = e, this.forbiddenProperties.clear();
748
929
  for (let t of Object.keys(this.classes)) {
749
930
  let n = this.classes[t].entity;
750
- if (n !== L && !(n.prototype instanceof L)) throw Error(`Entity class ${t} must extend BaseEntity`);
931
+ if (n !== R && !(n.prototype instanceof R)) throw Error(`Entity class ${t} must extend BaseEntity`);
751
932
  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}`);
752
933
  }
753
934
  for (let e of Object.keys(this.configs)) this.validateTemplate(e, this.configs[e]);
@@ -773,7 +954,7 @@ var j = class extends k {
773
954
  createAdoptedEntity(e, t, n) {
774
955
  if (!t) {
775
956
  if (this.hasClasses) throw Error(`Entity type ${e} has no class`);
776
- return new L(this.world, void 0, n);
957
+ return new R(this.world, void 0, n);
777
958
  }
778
959
  let r = this.classes[t];
779
960
  if (!r) throw Error(`Unknown entity class: ${t}`);
@@ -799,7 +980,7 @@ var j = class extends k {
799
980
  return e ? this.getAllowedComponents(e) : void 0;
800
981
  }
801
982
  createEntity(e) {
802
- return new L(this.world, e);
983
+ return new R(this.world, e);
803
984
  }
804
985
  get hasClasses() {
805
986
  return this.allowedComponents.size > 0;
@@ -864,7 +1045,30 @@ var j = class extends k {
864
1045
  }
865
1046
  throw Error(`Entity type ${e} class ${t} loads a component outside its class`);
866
1047
  }
867
- }, z = y, B = 1e4, V = class extends O.default {
1048
+ }, B = class {
1049
+ update(e, t) {
1050
+ let n = null;
1051
+ return e.systems.forEach((r) => {
1052
+ let i = !0, a = !1, o = !1;
1053
+ e.emit(`system-${r.name}-started`);
1054
+ try {
1055
+ i = r.shouldRun(), i && (a = r.update(t));
1056
+ } catch (t) {
1057
+ let i = t;
1058
+ console.error(i.message, i), o = !0, n = i, e.emit("system-error", {
1059
+ system: r.name,
1060
+ error: i,
1061
+ phase: "run"
1062
+ });
1063
+ }
1064
+ e.emit(`system-${r.name}-finished`, {
1065
+ ran: a,
1066
+ shouldRun: i,
1067
+ failed: o
1068
+ });
1069
+ }), { lastSystemError: n };
1070
+ }
1071
+ }, V = b, H = 1e4, U = class extends k.default {
868
1072
  heap;
869
1073
  constantStrings;
870
1074
  eidCounter;
@@ -872,10 +1076,11 @@ var j = class extends k {
872
1076
  factory;
873
1077
  entities = /* @__PURE__ */ new Map();
874
1078
  systems = [];
1079
+ scheduler;
875
1080
  gameTime = 0;
876
1081
  playerTime = 0;
877
1082
  timeScale = 1;
878
- paused = !1;
1083
+ isPaused = !1;
879
1084
  destroyed = !1;
880
1085
  pristine = !0;
881
1086
  isBulkLoading = !1;
@@ -889,20 +1094,21 @@ var j = class extends k {
889
1094
  waitingSystems: /* @__PURE__ */ new Set(),
890
1095
  waitElapsed: 0
891
1096
  };
892
- constructor(t, n = {}) {
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));
894
- let r = {
895
- ...t,
1097
+ clearing = !1;
1098
+ constructor(e, t = {}) {
1099
+ super(), this.scheduler = t.scheduler ?? new B(), this.heap = new y({ bufferSize: t.heapSize ?? V }), this.constantStrings = new _(this.heap), this.eidCounter = this.heap.allocUI32(1), this.heap.addOnGrowBufferHandlers((e) => this.emit("grow-buffer", e));
1100
+ let n = {
1101
+ ...e,
896
1102
  entity: i
897
- }, a = {};
898
- for (let e of Object.keys(r)) {
899
- let t = r[e];
900
- a[e] = {
1103
+ }, r = {};
1104
+ for (let e of Object.keys(n)) {
1105
+ let t = n[e];
1106
+ r[e] = {
901
1107
  ...t,
902
- memoryComponent: new _(this.heap, t.type, t.size)
1108
+ memoryComponent: new v(this.heap, t.type, t.size)
903
1109
  };
904
1110
  }
905
- this.registry = a, this.factory = n.factory ?? new R(), this.factory.setWorld(this);
1111
+ this.registry = r, this.factory = t.factory ?? new z(), this.factory.setWorld(this);
906
1112
  }
907
1113
  allocateEid() {
908
1114
  return Atomics.add(this.eidCounter.data, 0, 1) + 1;
@@ -919,13 +1125,13 @@ var j = class extends k {
919
1125
  this.heap.buffers[e.bufferPosition] === void 0 && this.heap.addSharedBuffer(e), this.emit("grow-buffer", e);
920
1126
  }
921
1127
  get needsSpareBuffer() {
922
- return this.systems.some((e) => e instanceof I && e.isWorkerThread && (!!e.options.createsEntities || !!e.options.addsComponents));
1128
+ return this.systems.some((e) => e instanceof L && e.isWorkerThread && (!!e.options.createsEntities || !!e.options.addsComponents));
923
1129
  }
924
1130
  async init() {
925
1131
  await Promise.all(this.systems.map((e) => e.init()).filter((e) => e instanceof Promise));
926
1132
  }
927
- finishLoadingSystems() {
928
- return Promise.all(this.systems.map((e) => e.finishLoading()).filter((e) => e instanceof Promise));
1133
+ async finishLoadingSystems() {
1134
+ await Promise.all(this.systems.map((e) => e.finishLoading()).filter((e) => e instanceof Promise));
929
1135
  }
930
1136
  addEntity(e, t = !0) {
931
1137
  return this.entities.set(e.eid, e), e.world = this, this.pristine = !1, e.on("component-added", (t) => {
@@ -960,9 +1166,9 @@ var j = class extends k {
960
1166
  }
961
1167
  }
962
1168
  load(e) {
963
- if (!this.pristine) {
1169
+ if (!this.pristine || this.scheduler.prepareEffects && this.systems.some((e) => e.isCurrentlyRunning())) {
964
1170
  for (let e of Array.from(this.entities.values())) this.removeEntity(e);
965
- this.systems.forEach((e) => e.clear()), this.consolidateFreeBuffersForReload();
1171
+ this.systems.forEach((e) => e.clear()), this.scheduler.reset?.(this), this.consolidateFreeBuffersForReload();
966
1172
  }
967
1173
  for (let e of Object.keys(this.factory.configs)) this.constantStrings.getOrCreate(e);
968
1174
  for (let e of Object.keys(this.factory.classes)) this.constantStrings.getOrCreate(e);
@@ -975,14 +1181,19 @@ var j = class extends k {
975
1181
  } finally {
976
1182
  this.isBulkLoading = !1;
977
1183
  }
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();
1184
+ let t = W(this.entities.values());
1185
+ return this.systems.forEach((e) => e.addEntities(t)), this.gameTime = e.gameTime ?? 0, this.playerTime = e.playerTime ?? 0, this.timeScale = e.timeScale ?? 1, this.finishLoadingSystems();
980
1186
  }
981
1187
  async clear() {
982
- if (!this.pristine) {
983
- await Promise.all(this.systems.map((e) => e.waitForRunToComplete()).filter((e) => e instanceof Promise));
984
- for (let e of Array.from(this.entities.values())) this.removeEntity(e);
985
- this.systems.forEach((e) => e.clear()), this.freeAllPendingBuffers(), this.pristine = !0;
1188
+ if (!this.pristine || this.scheduler.beforeClear) {
1189
+ this.clearing = !0;
1190
+ try {
1191
+ this.scheduler.beforeClear?.(this), await Promise.all(this.systems.map((e) => e.waitForRunToComplete()).filter((e) => e instanceof Promise));
1192
+ for (let e of Array.from(this.entities.values())) this.removeEntity(e);
1193
+ this.systems.forEach((e) => e.clear()), this.scheduler.reset?.(this), this.freeAllPendingBuffers(), this.pristine = !0;
1194
+ } finally {
1195
+ this.clearing = !1;
1196
+ }
986
1197
  }
987
1198
  }
988
1199
  removeEntity(e) {
@@ -1018,7 +1229,7 @@ var j = class extends k {
1018
1229
  });
1019
1230
  }
1020
1231
  notifySystemRunCompleted(e) {
1021
- this.activeFreeBuffer.waitingSystems.delete(e) && this.activeFreeBuffer.waitingSystems.size === 0 && this.processFreeBuffers();
1232
+ this.activeFreeBuffer.waitingSystems.delete(e) && this.activeFreeBuffer.waitingSystems.size === 0 && this.processFreeBuffers(), this.scheduler.runCompleted?.(this, e);
1022
1233
  }
1023
1234
  processFreeBuffers() {
1024
1235
  for (; this.activeFreeBuffer.waitingSystems.size === 0 && (this.activeFreeBuffer.frees.length > 0 && this.performFrees(this.activeFreeBuffer), this.nextFreeBuffer.frees.length !== 0);) this.promoteNextFreeBuffer();
@@ -1042,22 +1253,22 @@ var j = class extends k {
1042
1253
  }
1043
1254
  checkFreeBufferTimeout(e) {
1044
1255
  let t = this.activeFreeBuffer;
1045
- if (t.waitingSystems.size !== 0 && (t.waitElapsed += e, t.waitElapsed >= B)) {
1256
+ if (t.waitingSystems.size !== 0 && (t.waitElapsed += e, t.waitElapsed >= H)) {
1046
1257
  let e = Array.from(t.waitingSystems).map((e) => e.name).join(", ");
1047
- console.warn(`shared-memory-ecs: deferred component free waited over ${B}ms on system(s): ${e}; freeing anyway`), t.waitingSystems.clear(), this.processFreeBuffers();
1258
+ console.warn(`shared-memory-ecs: deferred component free waited over ${H}ms on system(s): ${e}; freeing anyway`), t.waitingSystems.clear(), this.processFreeBuffers();
1048
1259
  }
1049
1260
  }
1050
1261
  addSystem(e) {
1051
- return this.systems.push(e), this.emit("system-added", e), e;
1262
+ return this.systems.push(e), this.scheduler.systemAdded?.(this, e), this.emit("system-added", e), e;
1052
1263
  }
1053
1264
  addSystemIfNotExists(e) {
1054
- this.systems.findIndex((t) => e.name === t.name) === -1 && (this.systems.push(e), this.emit("system-added", e));
1265
+ this.systems.findIndex((t) => e.name === t.name) === -1 && (this.systems.push(e), this.scheduler.systemAdded?.(this, e), this.emit("system-added", e));
1055
1266
  }
1056
1267
  removeSystem(e) {
1057
1268
  let t = this.systems.findIndex((t) => t.name === e);
1058
1269
  if (t !== -1) {
1059
1270
  let [e] = this.systems.splice(t, 1);
1060
- this.emit("system-removed", e);
1271
+ this.scheduler.systemRemoved?.(this, e), this.emit("system-removed", e);
1061
1272
  }
1062
1273
  }
1063
1274
  update(e) {
@@ -1069,41 +1280,35 @@ var j = class extends k {
1069
1280
  if (this.playerTime += e, this.paused) return {};
1070
1281
  let t = e;
1071
1282
  e = this.timeScale * e, this.gameTime += e, this.processFreeBuffers(), this.needsSpareBuffer && this.heap.ensureSpareBuffer();
1072
- let n = null;
1073
- return this.systems.forEach((t) => {
1074
- let r = !0, i = !1, a = !1;
1075
- this.emit(`system-${t.name}-started`);
1076
- try {
1077
- r = t.shouldRun(), r && (i = t.update(e));
1078
- } catch (e) {
1079
- let r = e;
1080
- console.error(r.message, r), a = !0, n = r, this.emit("system-error", {
1081
- system: t.name,
1082
- error: r,
1083
- phase: "run"
1084
- });
1085
- }
1086
- this.emit(`system-${t.name}-finished`, {
1087
- ran: i,
1088
- shouldRun: r,
1089
- failed: a
1090
- });
1091
- }), this.checkFreeBufferTimeout(t), { lastSystemError: n };
1283
+ let n = this.scheduler.update(this, e);
1284
+ return this.checkFreeBufferTimeout(t), n;
1092
1285
  }
1093
1286
  pause() {
1094
1287
  this.paused = !0;
1095
1288
  }
1289
+ get paused() {
1290
+ return this.isPaused;
1291
+ }
1292
+ set paused(e) {
1293
+ this.isPaused !== e && (this.isPaused = e, e && this.scheduler.pause?.(this));
1294
+ }
1295
+ prepareForSystemDispatch() {
1296
+ return this.dispatchAllowed ? (this.needsSpareBuffer && this.heap.ensureSpareBuffer(), !0) : !1;
1297
+ }
1298
+ get dispatchAllowed() {
1299
+ return !this.clearing && !this.destroyed;
1300
+ }
1096
1301
  resume() {
1097
1302
  this.paused = !1;
1098
1303
  }
1099
1304
  addEntityToEntityWorkerSystem(e, t) {
1100
1305
  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);
1306
+ (n instanceof N && n.options.components?.includes(t) || n instanceof L && this.componentAffectsEntityWorkerSystem(n, t)) && n.checkAddEntity(e);
1102
1307
  });
1103
1308
  }
1104
1309
  removeEntityFromEntityWorkerSystem(e, t) {
1105
1310
  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);
1311
+ n instanceof N && n.options.components?.includes(t) ? n.removeEntity(e) : n instanceof L && this.componentAffectsEntityWorkerSystem(n, t) && n.checkAddEntity(e);
1107
1312
  });
1108
1313
  }
1109
1314
  componentAffectsEntityWorkerSystem(e, t) {
@@ -1113,10 +1318,10 @@ var j = class extends k {
1113
1318
  destroy() {
1114
1319
  this.destroyed ||= (this.systems.forEach((e) => {
1115
1320
  e.destroy();
1116
- }), !0);
1321
+ }), this.scheduler.destroy?.(this), !0);
1117
1322
  }
1118
1323
  };
1119
- function H(e) {
1324
+ function W(e) {
1120
1325
  let t = {
1121
1326
  entities: [],
1122
1327
  groupIndexes: [],
@@ -1129,28 +1334,279 @@ function H(e) {
1129
1334
  return t;
1130
1335
  }
1131
1336
  //#endregion
1337
+ //#region src/scheduling/conflict-scheduler.ts
1338
+ var G = class {
1339
+ compiled = Object.freeze({
1340
+ order: Object.freeze([]),
1341
+ batches: Object.freeze([])
1342
+ });
1343
+ registeredSystems = [];
1344
+ access = /* @__PURE__ */ new Map();
1345
+ nodes = /* @__PURE__ */ new Set();
1346
+ tails = /* @__PURE__ */ new Map();
1347
+ frontiers = /* @__PURE__ */ new Map();
1348
+ creators = /* @__PURE__ */ new Map();
1349
+ creationReaders = /* @__PURE__ */ new Map();
1350
+ exclusiveTail;
1351
+ running = /* @__PURE__ */ new Map();
1352
+ ready = [];
1353
+ readyIndex = 0;
1354
+ gameTime = 0;
1355
+ pumping = !1;
1356
+ resumeQueued = !1;
1357
+ continuationTimer;
1358
+ generation = 0;
1359
+ publications = /* @__PURE__ */ new Set();
1360
+ publicationReady = [];
1361
+ publishing = !1;
1362
+ get schedule() {
1363
+ return this.compiled;
1364
+ }
1365
+ rebuild(e) {
1366
+ let t = Array.from(new Set(e.systems)), n = t.map((e) => {
1367
+ let t = e.readComponents, n = e.creationReadQueries;
1368
+ return {
1369
+ reads: new Set(t),
1370
+ creationReads: new Set(n === void 0 ? e.creationReadComponents : e.reads),
1371
+ creationQueries: n?.map((e) => Array.from(e)),
1372
+ writes: new Set(e.writes),
1373
+ creates: new Set(e.createdComponents),
1374
+ exclusive: e.requiresExclusiveScheduling || t === void 0 || e.writes === void 0
1375
+ };
1376
+ });
1377
+ this.access = new Map(t.map((e, t) => [e, n[t]]));
1378
+ let r = [], i = [];
1379
+ for (let e = 0; e < t.length; e++) {
1380
+ let a = 0;
1381
+ for (let t = 0; t < e; t++) this.conflicts(n[t], n[e]) && (a = Math.max(a, i[t] + 1));
1382
+ i.push(a), (r[a] ??= []).push(t[e]);
1383
+ }
1384
+ return this.registeredSystems = e.systems.slice(), this.compiled = Object.freeze({
1385
+ order: Object.freeze(r.flat()),
1386
+ batches: Object.freeze(r.map((e) => Object.freeze(e)))
1387
+ }), this.compiled;
1388
+ }
1389
+ systemAdded(e) {
1390
+ this.rebuild(e);
1391
+ }
1392
+ systemRemoved(e) {
1393
+ this.rebuild(e);
1394
+ }
1395
+ update(e, t) {
1396
+ if (this.pumping) throw Error("ConflictScheduler does not support reentrant updates");
1397
+ this.refreshMembership(e), this.gameTime = e.gameTime ?? this.gameTime + t;
1398
+ for (let n of new Set(e.systems)) this.enqueue(n, this.access.get(n), t, this.gameTime);
1399
+ return this.pump(e, !0);
1400
+ }
1401
+ runCompleted(e, t) {
1402
+ let n = this.running.get(t);
1403
+ if (!n || (this.complete(n), this.pumping || this.resumeQueued)) return;
1404
+ this.resumeQueued = !0;
1405
+ let r = this.generation;
1406
+ queueMicrotask(() => {
1407
+ r === this.generation && (this.resumeQueued = !1, this.pump(e, !1));
1408
+ });
1409
+ }
1410
+ pause(e) {
1411
+ this.scheduleContinuation(e);
1412
+ }
1413
+ scheduleContinuation(e) {
1414
+ if (this.continuationTimer !== void 0 || !e.paused || !this.dispatchAllowed(e) || !Array.from(this.running.values()).some((e) => this.isSliced(e))) return;
1415
+ let t = this.generation;
1416
+ this.continuationTimer = setTimeout(() => {
1417
+ t === this.generation && (this.continuationTimer = void 0, e.paused && this.pump(e, "sliced"));
1418
+ }, 0);
1419
+ }
1420
+ isSliced(e) {
1421
+ return e.system instanceof M && e.system.remainingInstancesToRun.length > 0;
1422
+ }
1423
+ reset() {
1424
+ this.continuationTimer !== void 0 && (clearTimeout(this.continuationTimer), this.continuationTimer = void 0);
1425
+ let e = Array.from(this.publications, (e) => e.effects);
1426
+ this.publications.clear(), this.publicationReady = [], this.nodes.clear(), this.tails.clear(), this.frontiers.clear(), this.creators.clear(), this.creationReaders.clear(), this.exclusiveTail = void 0, this.running.clear(), this.ready = [], this.readyIndex = 0, this.gameTime = 0, this.resumeQueued = !1, this.generation++, e.forEach((e) => e.discard());
1427
+ }
1428
+ beforeClear() {
1429
+ this.reset();
1430
+ }
1431
+ prepareEffects(e, t) {
1432
+ let n = this.running.get(t), r = this.generation;
1433
+ return (e) => {
1434
+ if (!n || r !== this.generation || !this.nodes.has(n)) {
1435
+ e.discard();
1436
+ return;
1437
+ }
1438
+ n.effects = e, this.publications.add(n), n.publicationDependencies === 0 && this.publicationReady.push(n), this.publish();
1439
+ };
1440
+ }
1441
+ publish() {
1442
+ if (this.publishing) return;
1443
+ this.publishing = !0;
1444
+ let e = this.generation;
1445
+ try {
1446
+ for (; this.publicationReady.length && e === this.generation;) {
1447
+ let e = this.publicationReady.pop();
1448
+ this.publications.delete(e);
1449
+ let t = e.effects;
1450
+ e.effects = void 0, t.apply();
1451
+ }
1452
+ } finally {
1453
+ this.publishing = !1;
1454
+ }
1455
+ }
1456
+ destroy() {
1457
+ this.reset();
1458
+ }
1459
+ refreshMembership(e) {
1460
+ (e.systems.length !== this.registeredSystems.length || e.systems.some((e, t) => e !== this.registeredSystems[t])) && this.rebuild(e);
1461
+ }
1462
+ pump(e, t) {
1463
+ this.pumping = !0;
1464
+ let n = null, r = this.generation;
1465
+ try {
1466
+ if (t) for (let i of Array.from(this.running.values())) {
1467
+ if (!i.system.isCurrentlyRunning() || t === "sliced" && !this.isSliced(i)) continue;
1468
+ if (!this.prepare(e)) return { lastSystemError: n };
1469
+ let a = this.dispatch(e, i, !0);
1470
+ if (n = a?.lastSystemError ?? n, !a || r !== this.generation) return { lastSystemError: n };
1471
+ }
1472
+ for (; this.readyIndex < this.ready.length && r === this.generation && this.prepare(e);) {
1473
+ let t = this.ready[this.readyIndex++], r = this.dispatch(e, t, !1);
1474
+ if (n = r?.lastSystemError ?? n, !r) {
1475
+ this.nodes.has(t) && t.state === "pending" && this.ready.push(t);
1476
+ break;
1477
+ }
1478
+ }
1479
+ } finally {
1480
+ this.ready = this.ready.slice(this.readyIndex), this.readyIndex = 0, this.pumping = !1, this.scheduleContinuation(e);
1481
+ }
1482
+ return { lastSystemError: n };
1483
+ }
1484
+ enqueue(e, t, n, r) {
1485
+ let i = {
1486
+ system: e,
1487
+ access: t,
1488
+ elapsedTime: n,
1489
+ gameTime: r,
1490
+ state: "pending",
1491
+ dependencies: 0,
1492
+ dependents: [],
1493
+ publicationDependencies: 0,
1494
+ publicationDependents: []
1495
+ }, a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Set(), s = (e) => {
1496
+ e && e.state !== "complete" && a.add(e);
1497
+ };
1498
+ if (s(this.tails.get(e)), s(this.exclusiveTail), t.exclusive) this.tails.forEach(s), this.exclusiveTail = i;
1499
+ else {
1500
+ let n = (e) => {
1501
+ e && e.state !== "complete" && o.add(e);
1502
+ };
1503
+ for (let e of t.creates) {
1504
+ let t = this.frontier(e);
1505
+ n(t.writer), n(t.creator);
1506
+ }
1507
+ if (t.creates.size) for (let e of this.creationReaders.values()) this.observesCreation(t, e.access) && n(e);
1508
+ for (let n of t.reads) if (!t.writes.has(n)) {
1509
+ let t = this.frontier(n);
1510
+ s(t.writer), t.readers.set(e, i);
1511
+ }
1512
+ for (let e of this.creators.values()) this.observesCreation(e.access, t) && s(e);
1513
+ (t.creationReads.size || t.creationQueries?.length) && this.creationReaders.set(t, i);
1514
+ for (let e of t.writes) {
1515
+ let t = this.frontier(e);
1516
+ s(t.writer), s(t.creator), t.readers.forEach(s), t.readers.clear(), t.writer = i;
1517
+ }
1518
+ for (let e of t.creates) this.frontier(e).creator = i;
1519
+ t.creates.size && this.creators.set(t, i);
1520
+ }
1521
+ for (let e of a) e.dependents.push(i);
1522
+ i.dependencies = a.size;
1523
+ for (let e of o) e.publicationDependents.push(i);
1524
+ i.publicationDependencies = o.size, this.nodes.add(i), this.tails.set(e, i), i.dependencies || this.ready.push(i);
1525
+ }
1526
+ frontier(e) {
1527
+ let t = this.frontiers.get(e);
1528
+ return t || (t = { readers: /* @__PURE__ */ new Map() }, this.frontiers.set(e, t)), t;
1529
+ }
1530
+ complete(e) {
1531
+ if (e.state !== "complete") {
1532
+ e.state = "complete", this.nodes.delete(e), this.running.delete(e.system), this.tails.get(e.system) === e && this.tails.delete(e.system), this.exclusiveTail === e && (this.exclusiveTail = void 0), this.creators.get(e.access) === e && this.creators.delete(e.access), this.creationReaders.get(e.access) === e && this.creationReaders.delete(e.access);
1533
+ for (let t of /* @__PURE__ */ new Set([
1534
+ ...e.access.reads,
1535
+ ...e.access.writes,
1536
+ ...e.access.creates
1537
+ ])) {
1538
+ let n = this.frontiers.get(t);
1539
+ n?.writer === e && (n.writer = void 0), n?.creator === e && (n.creator = void 0), n?.readers.get(e.system) === e && n.readers.delete(e.system), n && !n.writer && !n.creator && !n.readers.size && this.frontiers.delete(t);
1540
+ }
1541
+ for (let t of e.dependents) --t.dependencies === 0 && this.ready.push(t);
1542
+ e.dependents.length = 0;
1543
+ for (let t of e.publicationDependents) t.publicationDependencies--, t.publicationDependencies === 0 && t.effects && this.publicationReady.push(t);
1544
+ e.publicationDependents.length = 0, this.publish();
1545
+ }
1546
+ }
1547
+ dispatch(e, t, n) {
1548
+ let r = t.system;
1549
+ if (!n && !e.systems.includes(r)) return this.complete(t), {};
1550
+ let i = this.generation, a = !0, o = !1, s = !1, c = null;
1551
+ if (e.emit(`system-${r.name}-started`), this.nodes.has(t) && this.dispatchAllowed(e)) {
1552
+ try {
1553
+ if (!r.withGameTime(t.gameTime, () => (a = n || r.shouldRun(), !this.nodes.has(t) || !this.dispatchAllowed(e) ? !1 : (a ? (t.state = "running", this.running.set(r, t), o = r.update(n ? 0 : t.elapsedTime), i === this.generation && !r.isCurrentlyRunning() && this.complete(t)) : this.complete(t), !0)))) return;
1554
+ } catch (n) {
1555
+ let a = n;
1556
+ console.error(a.message, a), s = !0, c = a, i === this.generation && (r.isCurrentlyRunning() ? (t.state = "running", this.running.set(r, t)) : this.complete(t)), e.emit("system-error", {
1557
+ system: r.name,
1558
+ error: a,
1559
+ phase: "run"
1560
+ });
1561
+ }
1562
+ return e.emit(`system-${r.name}-finished`, {
1563
+ ran: o,
1564
+ shouldRun: a,
1565
+ failed: s
1566
+ }), { lastSystemError: c };
1567
+ }
1568
+ }
1569
+ prepare(e) {
1570
+ return this.dispatchAllowed(e) && e.prepareForSystemDispatch?.() !== !1;
1571
+ }
1572
+ dispatchAllowed(e) {
1573
+ return e.dispatchAllowed !== !1;
1574
+ }
1575
+ observesCreation(e, t) {
1576
+ for (let n of t.creationReads) if (e.creates.has(n)) return !0;
1577
+ return t.creationQueries?.some((t) => t.every((t) => e.creates.has(t))) ?? !1;
1578
+ }
1579
+ conflicts(e, t) {
1580
+ if (e.exclusive || t.exclusive) return !0;
1581
+ for (let n of e.writes) if (t.reads.has(n) || t.writes.has(n)) return !0;
1582
+ for (let n of t.writes) if (e.reads.has(n)) return !0;
1583
+ for (let n of e.creates) if (t.writes.has(n)) return !0;
1584
+ return e.creates.size > 0 && this.observesCreation(e, t);
1585
+ }
1586
+ };
1587
+ //#endregion
1132
1588
  //#region src/entity-class.ts
1133
- function U(e, t) {
1589
+ function K(e, t) {
1134
1590
  return t;
1135
1591
  }
1136
- function W(e, t) {
1592
+ function q(e, t) {
1137
1593
  return t;
1138
1594
  }
1139
1595
  //#endregion
1140
1596
  //#region src/actions/kill-entity.ts
1141
- function G(e) {
1597
+ function J(e) {
1142
1598
  e.components.entity.dead = !0, e.emit("death");
1143
1599
  }
1144
1600
  //#endregion
1145
1601
  //#region src/performance-timing.ts
1146
- var K = 1e3, q = {
1602
+ var Y = 1e3, X = {
1147
1603
  avg: 0,
1148
1604
  min: 0,
1149
1605
  max: 0,
1150
1606
  samples: 0
1151
1607
  };
1152
- function J(e) {
1153
- if (!e.length) return { ...q };
1608
+ function Z(e) {
1609
+ if (!e.length) return { ...X };
1154
1610
  let t = 0, n = Infinity, r = 0;
1155
1611
  for (let i of e) t += i, i < n && (n = i), i > r && (r = i);
1156
1612
  return {
@@ -1160,32 +1616,33 @@ function J(e) {
1160
1616
  samples: e.length
1161
1617
  };
1162
1618
  }
1163
- var Y = class extends O.default {
1619
+ var Q = class extends k.default {
1164
1620
  world;
1165
1621
  ticksBetweenUpdates;
1166
1622
  stats = {
1167
- update: { ...q },
1623
+ update: { ...X },
1168
1624
  systems: [],
1169
- events: { ...q }
1625
+ events: { ...X }
1170
1626
  };
1627
+ autoUpdate;
1171
1628
  ticks = 0;
1172
1629
  updateStart = 0;
1173
1630
  updateTimes = [];
1174
1631
  systemTimings = /* @__PURE__ */ new Map();
1175
1632
  destroyed = !1;
1176
1633
  constructor(e, t = {}) {
1177
- 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));
1634
+ 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));
1178
1635
  }
1179
1636
  getSystemStats(e) {
1180
1637
  return this.stats.systems.find((t) => t.name === e);
1181
1638
  }
1182
1639
  reset() {
1183
1640
  this.ticks = 0, this.updateTimes = [], this.systemTimings.forEach((e) => {
1184
- e.run = [], e.events = [], e.eventStart = -1;
1641
+ e.run = [], e.events = [], e.eventStart = -1, e.pendingRun = 0, e.pendingEvents = 0;
1185
1642
  }), this.stats = {
1186
- update: { ...q },
1643
+ update: { ...X },
1187
1644
  systems: [],
1188
- events: { ...q }
1645
+ events: { ...X }
1189
1646
  };
1190
1647
  }
1191
1648
  destroy() {
@@ -1195,7 +1652,7 @@ var Y = class extends O.default {
1195
1652
  this.updateStart = performance.now();
1196
1653
  };
1197
1654
  onUpdateFinished = (e) => {
1198
- this.world.paused || (this.updateTimes.push(performance.now() - this.updateStart), this.ticks += e, this.ticks >= this.ticksBetweenUpdates && this.recalculate());
1655
+ this.world.paused || (this.updateTimes.push(performance.now() - this.updateStart), this.ticks += e, this.autoUpdate && this.ticks >= this.ticksBetweenUpdates && this.flush());
1199
1656
  };
1200
1657
  onSystemAdded = (e) => {
1201
1658
  this.trackSystem(e);
@@ -1209,11 +1666,13 @@ var Y = class extends O.default {
1209
1666
  run: [],
1210
1667
  events: [],
1211
1668
  eventStart: -1,
1212
- onRunFinished: (e) => {
1213
- t.run.push(e), t.eventStart = performance.now();
1669
+ pendingRun: 0,
1670
+ pendingEvents: 0,
1671
+ onRunFinished: (e, n) => {
1672
+ (!n || n.first) && (t.pendingRun = 0, t.pendingEvents = 0), t.pendingRun += e, (!n || n.last) && (t.run.push(t.pendingRun), t.pendingRun = 0), t.eventStart = performance.now();
1214
1673
  },
1215
- onEventsFinished: () => {
1216
- t.eventStart < 0 || (t.events.push(performance.now() - t.eventStart), t.eventStart = -1);
1674
+ onEventsFinished: (e, n) => {
1675
+ t.eventStart < 0 || (t.pendingEvents += performance.now() - t.eventStart, (!n || n.last) && (t.events.push(t.pendingEvents), t.pendingEvents = 0), t.eventStart = -1);
1217
1676
  }
1218
1677
  };
1219
1678
  this.world.on(`system-${e.name}-worker-finished`, t.onRunFinished), this.world.on(`system-${e.name}-worker-events-finished`, t.onEventsFinished), this.systemTimings.set(e.name, t);
@@ -1222,26 +1681,27 @@ var Y = class extends O.default {
1222
1681
  let t = this.systemTimings.get(e);
1223
1682
  t && (this.world.off(`system-${e}-worker-finished`, t.onRunFinished), this.world.off(`system-${e}-worker-events-finished`, t.onEventsFinished), this.systemTimings.delete(e));
1224
1683
  }
1225
- recalculate() {
1684
+ flush() {
1685
+ if (this.destroyed) return this.stats;
1226
1686
  let e = this.world.systems.map((e) => {
1227
1687
  let t = this.systemTimings.get(e.name);
1228
1688
  return {
1229
1689
  name: e.name,
1230
- run: J(t?.run ?? []),
1231
- events: J(t?.events ?? [])
1690
+ run: Z(t?.run ?? []),
1691
+ events: Z(t?.events ?? [])
1232
1692
  };
1233
- }), t = { ...q };
1234
- e.forEach((e) => {
1693
+ }), t = { ...X };
1694
+ return e.forEach((e) => {
1235
1695
  t.avg += e.events.avg, t.min += e.events.min, t.max += e.events.max, t.samples += e.events.samples;
1236
1696
  }), this.stats = {
1237
- update: J(this.updateTimes),
1697
+ update: Z(this.updateTimes),
1238
1698
  systems: e,
1239
1699
  events: t
1240
1700
  }, this.ticks = 0, this.updateTimes = [], this.systemTimings.forEach((e) => {
1241
1701
  e.run = [], e.events = [];
1242
- }), this.emit("stats-updated", this.stats);
1702
+ }), this.emit("stats-updated", this.stats), this.stats;
1243
1703
  }
1244
- }, X = class extends I {
1704
+ }, $ = class extends L {
1245
1705
  constructor(e, t) {
1246
1706
  super(e, {
1247
1707
  ...t,
@@ -1257,6 +1717,6 @@ var Y = class extends O.default {
1257
1717
  }
1258
1718
  };
1259
1719
  //#endregion
1260
- 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 };
1720
+ export { R as BaseEntity, U as BaseWorld, n as CLASS_INDEX, f as Component, G as ConflictScheduler, _ as ConstantStringCache, c as DEAD_INDEX, Y as DEFAULT_TICKS_BETWEEN_UPDATES, B as DefaultScheduler, z as EntityFactory, N as EntitySystem, F as EntitySystemWebWorker, L as EntityWorkerSystem, M as IterableSystem, v as MemoryComponent, Q as PerformanceTiming, g as STATIC_INDEX, A as System, r as TYPE_INDEX, P as WebWorker, $ as WorkerSystem, t as addComponentWorker, p as createEntitySystemWorker, d as createEntityWorker, h as createSystemWorker, K as defineEntityClasses, q as defineEntityConfigs, i as entityDefinition, J as killEntity, m as killEntityWorker, s as removeComponentWorker };
1261
1721
 
1262
1722
  //# sourceMappingURL=index.js.map