@oasys/oecs 0.2.1 → 0.3.1

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.
Files changed (46) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +169 -182
  3. package/dist/archetype.d.ts +19 -9
  4. package/dist/archetype.d.ts.map +1 -1
  5. package/dist/component.d.ts +10 -0
  6. package/dist/component.d.ts.map +1 -1
  7. package/dist/ecs.d.ts +14 -14
  8. package/dist/ecs.d.ts.map +1 -1
  9. package/dist/entity.d.ts.map +1 -1
  10. package/dist/event.d.ts +6 -0
  11. package/dist/event.d.ts.map +1 -1
  12. package/dist/index.cjs +1 -1
  13. package/dist/index.d.ts +8 -6
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +761 -524
  16. package/dist/query.d.ts +40 -16
  17. package/dist/query.d.ts.map +1 -1
  18. package/dist/ref.d.ts +4 -0
  19. package/dist/ref.d.ts.map +1 -1
  20. package/dist/resource.d.ts +21 -21
  21. package/dist/resource.d.ts.map +1 -1
  22. package/dist/schedule.d.ts +8 -6
  23. package/dist/schedule.d.ts.map +1 -1
  24. package/dist/store.d.ts +13 -6
  25. package/dist/store.d.ts.map +1 -1
  26. package/dist/system.d.ts.map +1 -1
  27. package/dist/type_primitives/assertions.d.ts +1 -0
  28. package/dist/type_primitives/assertions.d.ts.map +1 -1
  29. package/dist/type_primitives/binary_heap/binary_heap.d.ts +33 -0
  30. package/dist/type_primitives/binary_heap/binary_heap.d.ts.map +1 -0
  31. package/dist/type_primitives/bitset/bitset.d.ts +5 -0
  32. package/dist/type_primitives/bitset/bitset.d.ts.map +1 -1
  33. package/dist/type_primitives/error.d.ts +2 -1
  34. package/dist/type_primitives/error.d.ts.map +1 -1
  35. package/dist/type_primitives/index.d.ts +2 -0
  36. package/dist/type_primitives/index.d.ts.map +1 -1
  37. package/dist/type_primitives/topological_sort/topological_sort.d.ts +25 -0
  38. package/dist/type_primitives/topological_sort/topological_sort.d.ts.map +1 -0
  39. package/dist/type_primitives/typed_arrays/typed_arrays.d.ts +2 -0
  40. package/dist/type_primitives/typed_arrays/typed_arrays.d.ts.map +1 -1
  41. package/dist/utils/arrays.d.ts.map +1 -1
  42. package/dist/utils/constants.d.ts +0 -8
  43. package/dist/utils/constants.d.ts.map +1 -1
  44. package/dist/utils/error.d.ts +4 -1
  45. package/dist/utils/error.d.ts.map +1 -1
  46. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,80 +1,80 @@
1
- class H extends Error {
1
+ class Z extends Error {
2
2
  constructor(t, e, s) {
3
3
  super(t), this.is_operational = e, this.context = s, this.name = this.constructor.name, Error.captureStackTrace(this, this.constructor);
4
4
  }
5
5
  }
6
- var z = /* @__PURE__ */ ((l) => (l.EID_MAX_INDEX_OVERFLOW = "EID_MAX_INDEX_OVERFLOW", l.EID_MAX_GEN_OVERFLOW = "EID_MAX_GEN_OVERFLOW", l.COMPONENT_NOT_REGISTERED = "COMPONENT_NOT_REGISTERED", l.ENTITY_NOT_ALIVE = "ENTITY_NOT_ALIVE", l.CIRCULAR_SYSTEM_DEPENDENCY = "CIRCULAR_SYSTEM_DEPENDENCY", l.DUPLICATE_SYSTEM = "DUPLICATE_SYSTEM", l.ARCHETYPE_NOT_FOUND = "ARCHETYPE_NOT_FOUND", l.RESOURCE_NOT_REGISTERED = "RESOURCE_NOT_REGISTERED", l))(z || {});
7
- class Q extends H {
6
+ var D = /* @__PURE__ */ ((a) => (a.EID_MAX_INDEX_OVERFLOW = "EID_MAX_INDEX_OVERFLOW", a.EID_MAX_GEN_OVERFLOW = "EID_MAX_GEN_OVERFLOW", a.COMPONENT_NOT_REGISTERED = "COMPONENT_NOT_REGISTERED", a.ENTITY_NOT_ALIVE = "ENTITY_NOT_ALIVE", a.CIRCULAR_SYSTEM_DEPENDENCY = "CIRCULAR_SYSTEM_DEPENDENCY", a.DUPLICATE_SYSTEM = "DUPLICATE_SYSTEM", a.ARCHETYPE_NOT_FOUND = "ARCHETYPE_NOT_FOUND", a.RESOURCE_NOT_REGISTERED = "RESOURCE_NOT_REGISTERED", a.RESOURCE_ALREADY_REGISTERED = "RESOURCE_ALREADY_REGISTERED", a.EVENT_ALREADY_REGISTERED = "EVENT_ALREADY_REGISTERED", a.EVENT_NOT_REGISTERED = "EVENT_NOT_REGISTERED", a))(D || {});
7
+ class O extends Z {
8
8
  constructor(t, e, s) {
9
9
  super(e ?? t, !0, s), this.category = t;
10
10
  }
11
11
  }
12
- function N(l, t, e) {
13
- return l;
12
+ function F(a, t, e) {
13
+ return a;
14
14
  }
15
- const v = -1, y = -1, D = Object.freeze(/* @__PURE__ */ Object.create(null)), k = 5, I = 31, J = 2166136261, Z = 16777619, tt = 2654435769, et = 1367130551, b = 16, C = 2, V = 1024, R = 0, j = 0, st = 31, nt = 1 / 60, rt = 4, it = 0, ot = 4;
16
- class x {
15
+ const I = 5, S = 31, tt = 2166136261, et = 16777619, st = 4;
16
+ class p {
17
17
  _words;
18
18
  constructor(t) {
19
- this._words = t ?? new Array(ot).fill(0);
19
+ this._words = t ?? new Array(st).fill(0);
20
20
  }
21
21
  has(t) {
22
- const e = t >>> k;
23
- return e >= this._words.length ? !1 : (this._words[e] & 1 << (t & I)) !== 0;
22
+ const e = t >>> I;
23
+ return e >= this._words.length ? !1 : (this._words[e] & 1 << (t & S)) !== 0;
24
24
  }
25
25
  set(t) {
26
- const e = t >>> k;
27
- e >= this._words.length && this.grow(e + 1), this._words[e] |= 1 << (t & I);
26
+ const e = t >>> I;
27
+ e >= this._words.length && this.grow(e + 1), this._words[e] |= 1 << (t & S);
28
28
  }
29
29
  clear(t) {
30
- const e = t >>> k;
31
- e >= this._words.length || (this._words[e] &= ~(1 << (t & I)));
30
+ const e = t >>> I;
31
+ e >= this._words.length || (this._words[e] &= ~(1 << (t & S)));
32
32
  }
33
33
  /** True if any bit is set in both this and other (non-empty intersection). */
34
34
  overlaps(t) {
35
35
  const e = this._words, s = t._words, n = e.length < s.length ? e.length : s.length;
36
- for (let r = 0; r < n; r++)
37
- if ((e[r] & s[r]) !== 0) return !0;
36
+ for (let i = 0; i < n; i++)
37
+ if ((e[i] & s[i]) !== 0) return !0;
38
38
  return !1;
39
39
  }
40
40
  /** True if this is a superset of other (all bits in other are set in this). */
41
41
  contains(t) {
42
42
  const e = t._words, s = this._words, n = s.length;
43
- for (let r = 0; r < e.length; r++) {
44
- const i = e[r];
45
- if (i !== 0 && (r >= n || (s[r] & i) !== i))
43
+ for (let i = 0; i < e.length; i++) {
44
+ const r = e[i];
45
+ if (r !== 0 && (i >= n || (s[i] & r) !== r))
46
46
  return !1;
47
47
  }
48
48
  return !0;
49
49
  }
50
50
  equals(t) {
51
51
  const e = this._words, s = t._words, n = e.length > s.length ? e.length : s.length;
52
- for (let r = 0; r < n; r++) {
53
- const i = r < e.length ? e[r] : 0, _ = r < s.length ? s[r] : 0;
54
- if (i !== _) return !1;
52
+ for (let i = 0; i < n; i++) {
53
+ const r = i < e.length ? e[i] : 0, c = i < s.length ? s[i] : 0;
54
+ if (r !== c) return !1;
55
55
  }
56
56
  return !0;
57
57
  }
58
58
  copy() {
59
- return new x(this._words.slice());
59
+ return new p(this._words.slice());
60
60
  }
61
61
  copy_with_set(t) {
62
- const e = t >>> k, s = e + 1, n = this._words.length > s ? this._words.length : s, r = new Array(n).fill(0);
63
- for (let i = 0; i < this._words.length; i++) r[i] = this._words[i];
64
- return r[e] |= 1 << (t & I), new x(r);
62
+ const e = t >>> I, s = e + 1, n = this._words.length > s ? this._words.length : s, i = new Array(n).fill(0);
63
+ for (let r = 0; r < this._words.length; r++) i[r] = this._words[r];
64
+ return i[e] |= 1 << (t & S), new p(i);
65
65
  }
66
66
  copy_with_clear(t) {
67
- const e = this._words.slice(), s = t >>> k;
68
- return s < e.length && (e[s] &= ~(1 << (t & I))), new x(e);
67
+ const e = this._words.slice(), s = t >>> I;
68
+ return s < e.length && (e[s] &= ~(1 << (t & S))), new p(e);
69
69
  }
70
70
  /** FNV-1a hash. Skips trailing zero words so differently-sized arrays with the same bits hash equally. */
71
71
  hash() {
72
- let t = J;
72
+ let t = tt;
73
73
  const e = this._words;
74
74
  let s = e.length - 1;
75
75
  for (; s >= 0 && e[s] === 0; ) s--;
76
76
  for (let n = 0; n <= s; n++)
77
- t ^= e[n], t = Math.imul(t, Z);
77
+ t ^= e[n], t = Math.imul(t, et);
78
78
  return t;
79
79
  }
80
80
  /** Iterate all set bits via lowest-set-bit extraction. */
@@ -83,10 +83,10 @@ class x {
83
83
  for (let s = 0; s < e.length; s++) {
84
84
  let n = e[s];
85
85
  if (n === 0) continue;
86
- const r = s << k;
86
+ const i = s << I;
87
87
  for (; n !== 0; ) {
88
- const i = n & -n >>> 0, _ = I - Math.clz32(i);
89
- t(r + _), n ^= i;
88
+ const r = n & -n >>> 0, c = S - Math.clz32(r);
89
+ t(i + c), n ^= r;
90
90
  }
91
91
  }
92
92
  }
@@ -98,8 +98,9 @@ class x {
98
98
  this._words = s;
99
99
  }
100
100
  }
101
+ const b = 16, X = 2;
101
102
  class A {
102
- constructor(t, e = b) {
103
+ constructor(t, e = 16) {
103
104
  this._ctor = t, this._buf = new t(e);
104
105
  }
105
106
  _buf;
@@ -158,7 +159,7 @@ class A {
158
159
  ensure_capacity(t) {
159
160
  if (t <= this._buf.length) return;
160
161
  let e = this._buf.length || 1;
161
- for (; e < t; ) e *= C;
162
+ for (; e < t; ) e *= X;
162
163
  const s = new this._ctor(e);
163
164
  s.set(this._buf.subarray(0, this._len)), this._buf = s;
164
165
  }
@@ -174,65 +175,151 @@ class A {
174
175
  this.ensure_capacity(this._len + t), this._buf.fill(0, this._len, this._len + t), this._len += t;
175
176
  }
176
177
  _grow() {
177
- const t = new this._ctor(this._buf.length * C);
178
+ const t = new this._ctor(this._buf.length * X);
178
179
  t.set(this._buf), this._buf = t;
179
180
  }
180
181
  }
181
- class _t extends A {
182
+ class nt extends A {
182
183
  constructor(t = b) {
183
184
  super(Float32Array, t);
184
185
  }
185
186
  }
186
- class ct extends A {
187
+ class it extends A {
187
188
  constructor(t = b) {
188
189
  super(Float64Array, t);
189
190
  }
190
191
  }
191
- class ht extends A {
192
+ class rt extends A {
192
193
  constructor(t = b) {
193
194
  super(Int8Array, t);
194
195
  }
195
196
  }
196
- class lt extends A {
197
+ class _t extends A {
197
198
  constructor(t = b) {
198
199
  super(Int16Array, t);
199
200
  }
200
201
  }
201
- class at extends A {
202
+ class ot extends A {
202
203
  constructor(t = b) {
203
204
  super(Int32Array, t);
204
205
  }
205
206
  }
206
- class dt extends A {
207
+ class ct extends A {
207
208
  constructor(t = b) {
208
209
  super(Uint8Array, t);
209
210
  }
210
211
  }
211
- class ut extends A {
212
+ class ht extends A {
212
213
  constructor(t = b) {
213
214
  super(Uint16Array, t);
214
215
  }
215
216
  }
216
- class B extends A {
217
+ class H extends A {
217
218
  constructor(t = b) {
218
219
  super(Uint32Array, t);
219
220
  }
220
221
  }
221
- const ft = {
222
- f32: _t,
223
- f64: ct,
224
- i8: ht,
225
- i16: lt,
226
- i32: at,
227
- u8: dt,
228
- u16: ut,
229
- u32: B
230
- }, P = 20, F = (1 << P) - 1, gt = st - P, X = (1 << gt) - 1, mt = (l, t) => t << P | l, m = (l) => l & F, Y = (l) => l >> P, yt = (l) => N(
231
- l
232
- ), pt = (l) => N(
233
- l
222
+ const at = {
223
+ f32: nt,
224
+ f64: it,
225
+ i8: rt,
226
+ i16: _t,
227
+ i32: ot,
228
+ u8: ct,
229
+ u16: ht,
230
+ u32: H
231
+ };
232
+ class lt {
233
+ _compare;
234
+ _data = [];
235
+ constructor(t) {
236
+ this._compare = t;
237
+ }
238
+ get size() {
239
+ return this._data.length;
240
+ }
241
+ /** Returns the highest-priority element without removing it, or undefined if empty. */
242
+ peek() {
243
+ return this._data[0];
244
+ }
245
+ /** Inserts a value and restores heap order by sifting up. O(log n). */
246
+ push(t) {
247
+ this._data.push(t), this._sift_up(this._data.length - 1);
248
+ }
249
+ /** Removes and returns the highest-priority element, or undefined if empty. O(log n). */
250
+ pop() {
251
+ const t = this._data;
252
+ if (t.length === 0) return;
253
+ const s = t[0], n = t.pop();
254
+ return t.length > 0 && (t[0] = n, this._sift_down(0)), s;
255
+ }
256
+ /** Removes all elements. O(1). */
257
+ clear() {
258
+ this._data.length = 0;
259
+ }
260
+ /** Moves a node up toward the root until heap order is restored. */
261
+ _sift_up(t) {
262
+ const e = this._data, s = this._compare, n = e[t];
263
+ for (; t > 0; ) {
264
+ const i = t - 1 >> 1;
265
+ if (s(n, e[i]) >= 0) break;
266
+ e[t] = e[i], t = i;
267
+ }
268
+ e[t] = n;
269
+ }
270
+ /** Moves a node down away from the root until heap order is restored. */
271
+ _sift_down(t) {
272
+ const e = this._data, s = this._compare, n = e.length, i = n >> 1, r = e[t];
273
+ for (; t < i; ) {
274
+ let c = (t << 1) + 1;
275
+ const o = c + 1;
276
+ if (o < n && s(e[o], e[c]) < 0 && (c = o), s(e[c], r) >= 0) break;
277
+ e[t] = e[c], t = c;
278
+ }
279
+ e[t] = r;
280
+ }
281
+ }
282
+ function dt(a, t, e, s) {
283
+ const n = s ?? ((o) => String(o)), i = /* @__PURE__ */ new Map();
284
+ for (let o = 0; o < a.length; o++)
285
+ i.set(a[o], 0);
286
+ for (const [, o] of t)
287
+ for (let _ = 0; _ < o.length; _++) {
288
+ const h = o[_];
289
+ i.has(h) && i.set(h, i.get(h) + 1);
290
+ }
291
+ const r = new lt(e);
292
+ for (let o = 0; o < a.length; o++)
293
+ i.get(a[o]) === 0 && r.push(a[o]);
294
+ const c = [];
295
+ for (; r.size > 0; ) {
296
+ const o = r.pop();
297
+ c.push(o);
298
+ const _ = t.get(o);
299
+ if (_ !== void 0)
300
+ for (let h = 0; h < _.length; h++) {
301
+ const l = _[h];
302
+ if (!i.has(l)) continue;
303
+ const d = i.get(l) - 1;
304
+ i.set(l, d), d === 0 && r.push(l);
305
+ }
306
+ }
307
+ if (c.length !== a.length) {
308
+ const o = [];
309
+ for (const [_, h] of i)
310
+ h > 0 && o.push(n(_));
311
+ throw new globalThis.TypeError(
312
+ `Cycle detected in topological sort. Nodes still pending: ${o.join(", ")}`
313
+ );
314
+ }
315
+ return c;
316
+ }
317
+ const k = -1, m = -1, q = Object.freeze(/* @__PURE__ */ Object.create(null)), ut = 2654435769, ft = 1367130551, K = 1024, j = 0, gt = 31, yt = 1 / 60, mt = 4, pt = 0, R = 20, M = (1 << R) - 1, wt = gt - R, V = (1 << wt) - 1, vt = (a, t) => t << R | a, y = (a) => a & M, z = (a) => a >> R, Et = (a) => F(
318
+ a
319
+ ), kt = (a) => F(
320
+ a
234
321
  );
235
- class wt {
322
+ class Tt {
236
323
  field_names;
237
324
  columns;
238
325
  // any: type-erased storage — channel is stored in Map<number, EventChannel>, F is lost
@@ -263,53 +350,26 @@ class wt {
263
350
  t[e].length = 0;
264
351
  }
265
352
  }
266
- const vt = (l) => N(
267
- l
268
- );
269
- class xt {
270
- field_names;
271
- field_index;
272
- columns;
273
- // any: type-erased storage — channel is stored in Map<number, ResourceChannel>, F is lost
274
- reader;
275
- constructor(t, e) {
276
- this.field_names = t, this.field_index = /* @__PURE__ */ Object.create(null), this.columns = [];
277
- for (let r = 0; r < t.length; r++)
278
- this.field_index[t[r]] = r, this.columns.push([e[t[r]] ?? 0]);
279
- const s = /* @__PURE__ */ Object.create(null), n = this.columns;
280
- for (let r = 0; r < t.length; r++) {
281
- const i = n[r];
282
- Object.defineProperty(s, t[r], {
283
- get() {
284
- return i[R];
285
- },
286
- enumerable: !0
287
- });
288
- }
289
- this.reader = s;
290
- }
291
- write(t) {
292
- const e = this.field_names, s = this.columns;
293
- for (let n = 0; n < e.length; n++)
294
- e[n] in t && (s[n][R] = t[e[n]]);
295
- }
296
- read_field(t) {
297
- return this.columns[t][R];
298
- }
299
- write_field(t, e) {
300
- this.columns[t][R] = e;
301
- }
353
+ function Ot(a) {
354
+ return Symbol(a);
302
355
  }
303
- const bt = (l) => N(
304
- l
356
+ function qt(a) {
357
+ return Symbol(a);
358
+ }
359
+ const bt = (a) => F(
360
+ a
305
361
  );
306
- class Tt {
362
+ class At {
307
363
  id;
308
364
  mask;
309
365
  has_columns;
310
366
  _entity_ids;
311
367
  length = 0;
312
368
  edges = [];
369
+ // Cache for multi-component transition maps (from this archetype to another).
370
+ // Covers add_components / remove_components where the (src, dst) pair is not
371
+ // a single-component edge and therefore not covered by `edges[].add_map/remove_map`.
372
+ batch_transition_maps = /* @__PURE__ */ new Map();
313
373
  // --- Flat column storage ---
314
374
  // Dense array of ALL columns across all components in this archetype.
315
375
  _flat_columns = [];
@@ -325,17 +385,19 @@ class Tt {
325
385
  column_groups = [];
326
386
  // Dense list of ComponentIDs that have columns — used for copy_shared_from.
327
387
  _column_ids = [];
328
- constructor(t, e, s, n = V) {
329
- if (this.id = t, this.mask = e, this._entity_ids = new B(n), s) {
330
- let r = 0;
331
- for (let i = 0; i < s.length; i++) {
332
- const _ = s[i], c = _.component_id, o = new Array(_.field_names.length);
333
- this._col_offset[c] = r, this._field_count[c] = _.field_names.length, this._field_index[c] = _.field_index, this._field_names[c] = _.field_names;
334
- for (let h = 0; h < _.field_names.length; h++) {
335
- const a = new ft[_.field_types[h]](n);
336
- o[h] = a, this._flat_columns[r++] = a;
388
+ // Sparse by ComponentID last tick that modified this component's columns.
389
+ _changed_tick = [];
390
+ constructor(t, e, s, n = K) {
391
+ if (this.id = t, this.mask = e, this._entity_ids = new H(n), s) {
392
+ let i = 0;
393
+ for (let r = 0; r < s.length; r++) {
394
+ const c = s[r], o = c.component_id, _ = new Array(c.field_names.length);
395
+ this._col_offset[o] = i, this._field_count[o] = c.field_names.length, this._field_index[o] = c.field_index, this._field_names[o] = c.field_names;
396
+ for (let h = 0; h < c.field_names.length; h++) {
397
+ const l = new at[c.field_types[h]](n);
398
+ _[h] = l, this._flat_columns[i++] = l;
337
399
  }
338
- this.column_groups[c] = { layout: _, columns: o }, this._column_ids.push(c);
400
+ this.column_groups[o] = { layout: c, columns: _ }, this._column_ids.push(o), this._changed_tick[o] = 0;
339
401
  }
340
402
  }
341
403
  this.has_columns = this._column_ids.length > 0;
@@ -356,41 +418,51 @@ class Tt {
356
418
  matches(t) {
357
419
  return this.mask.contains(t);
358
420
  }
359
- /** Get a single field's column. Valid data: indices 0..entity_count-1. */
421
+ /** Get a single field's column (read-only). Valid data: indices 0..entity_count-1. */
360
422
  get_column(t, e) {
361
423
  const s = t, n = this._field_index[s][e];
362
424
  return this._flat_columns[this._col_offset[s] + n].buf;
363
425
  }
364
- write_fields(t, e, s) {
365
- const n = e, r = this._col_offset[n];
426
+ /** Get a single field's column (mutable). Marks the component as changed at the given tick. */
427
+ get_column_mut(t, e, s) {
428
+ const n = t;
429
+ this._changed_tick[n] = s;
430
+ const i = this._field_index[n][e];
431
+ return this._flat_columns[this._col_offset[n] + i].buf;
432
+ }
433
+ write_fields(t, e, s, n) {
434
+ const i = e, r = this._col_offset[i];
366
435
  if (r === void 0) return;
367
- const i = this._field_names[n], _ = this._flat_columns;
368
- for (let c = 0; c < i.length; c++)
369
- _[r + c].buf[t] = s[i[c]];
436
+ this._changed_tick[i] = n;
437
+ const c = this._field_names[i], o = this._flat_columns;
438
+ for (let _ = 0; _ < c.length; _++)
439
+ o[r + _].buf[t] = s[c[_]];
370
440
  }
371
441
  /** Fast positional write: values[i] → field[i] in declaration order. No string lookup. */
372
- write_fields_positional(t, e, s) {
373
- const n = e, r = this._col_offset[n];
442
+ write_fields_positional(t, e, s, n) {
443
+ const i = e, r = this._col_offset[i];
374
444
  if (r === void 0) return;
375
- const i = this._flat_columns;
376
- for (let _ = 0; _ < s.length; _++)
377
- i[r + _].buf[t] = s[_];
445
+ this._changed_tick[i] = n;
446
+ const c = this._flat_columns;
447
+ for (let o = 0; o < s.length; o++)
448
+ c[r + o].buf[t] = s[o];
378
449
  }
379
450
  read_field(t, e, s) {
380
- const n = e, r = this._col_offset[n];
381
- if (r === void 0) return NaN;
382
- const i = this._field_index[n][s];
383
- return i === void 0 ? NaN : this._flat_columns[r + i].buf[t];
451
+ const n = e, i = this._col_offset[n];
452
+ if (i === void 0) return NaN;
453
+ const r = this._field_index[n][s];
454
+ return r === void 0 ? NaN : this._flat_columns[i + r].buf[t];
384
455
  }
385
456
  /** Copy all shared component columns from source archetype at src_row into dst_row. */
386
- copy_shared_from(t, e, s) {
387
- const n = t._col_offset, r = t._field_count, i = t._flat_columns, _ = this._flat_columns, c = this._column_ids;
388
- for (let o = 0; o < c.length; o++) {
389
- const h = c[o], a = n[h];
390
- if (a === void 0) continue;
391
- const u = this._col_offset[h], d = r[h];
392
- for (let g = 0; g < d; g++)
393
- _[u + g].buf[s] = i[a + g].buf[e];
457
+ copy_shared_from(t, e, s, n) {
458
+ const i = t._col_offset, r = t._field_count, c = t._flat_columns, o = this._flat_columns, _ = this._column_ids;
459
+ for (let h = 0; h < _.length; h++) {
460
+ const l = _[h], d = i[l];
461
+ if (d === void 0) continue;
462
+ this._changed_tick[l] = n;
463
+ const u = this._col_offset[l], g = r[l];
464
+ for (let w = 0; w < g; w++)
465
+ o[u + w].buf[s] = c[d + w].buf[e];
394
466
  }
395
467
  }
396
468
  /**
@@ -412,15 +484,15 @@ class Tt {
412
484
  */
413
485
  remove_entity(t) {
414
486
  const e = this.length - 1;
415
- let s = y;
416
- const n = this._flat_columns, r = this._entity_ids.buf;
487
+ let s = m;
488
+ const n = this._flat_columns, i = this._entity_ids.buf;
417
489
  if (t !== e) {
418
- r[t] = r[e], s = m(r[t]);
419
- for (let i = 0; i < n.length; i++)
420
- n[i].swap_remove(t);
490
+ i[t] = i[e], s = y(i[t]);
491
+ for (let r = 0; r < n.length; r++)
492
+ n[r].swap_remove(t);
421
493
  } else
422
- for (let i = 0; i < n.length; i++)
423
- n[i].pop();
494
+ for (let r = 0; r < n.length; r++)
495
+ n[r].pop();
424
496
  return this._entity_ids.pop(), this.length--, s;
425
497
  }
426
498
  /** Tag-optimized add: skip column push entirely (no data to store). */
@@ -431,9 +503,9 @@ class Tt {
431
503
  /** Tag-optimized remove via swap-and-pop: skip column swap/pop entirely. */
432
504
  remove_entity_tag(t) {
433
505
  const e = this.length - 1;
434
- let s = y;
506
+ let s = m;
435
507
  const n = this._entity_ids.buf;
436
- return t !== e && (n[t] = n[e], s = m(n[t])), this._entity_ids.pop(), this.length--, s;
508
+ return t !== e && (n[t] = n[e], s = y(n[t])), this._entity_ids.pop(), this.length--, s;
437
509
  }
438
510
  /**
439
511
  * Move an entity from src archetype into this archetype in a single pass.
@@ -441,17 +513,20 @@ class Tt {
441
513
  * Uses a pre-computed transition map for branchless column copy.
442
514
  * Writes dst_row to _move_result[0], swapped entity index to _move_result[1].
443
515
  */
444
- move_entity_from(t, e, s, n) {
516
+ move_entity_from(t, e, s, n, i) {
445
517
  const r = this.length;
446
518
  this._entity_ids.push(s);
447
- const i = this._flat_columns, _ = t._flat_columns;
448
- for (let o = 0; o < i.length; o++) {
449
- const h = n[o];
450
- i[o].push(h >= 0 ? _[h].buf[e] : 0);
519
+ const c = this._flat_columns, o = t._flat_columns;
520
+ for (let l = 0; l < c.length; l++) {
521
+ const d = n[l];
522
+ c[l].push(d >= 0 ? o[d].buf[e] : 0);
451
523
  }
524
+ const _ = this._column_ids;
525
+ for (let l = 0; l < _.length; l++)
526
+ this._changed_tick[_[l]] = i;
452
527
  this.length++;
453
- const c = t.has_columns ? t.remove_entity(e) : t.remove_entity_tag(e);
454
- f[0] = r, f[1] = c;
528
+ const h = t.has_columns ? t.remove_entity(e) : t.remove_entity_tag(e);
529
+ f[0] = r, f[1] = h;
455
530
  }
456
531
  /**
457
532
  * Move an entity from src into this archetype (tag-only: no columns to copy).
@@ -460,27 +535,30 @@ class Tt {
460
535
  move_entity_from_tag(t, e, s) {
461
536
  const n = this.length;
462
537
  this._entity_ids.push(s), this.length++;
463
- const r = t.remove_entity_tag(e);
464
- f[0] = n, f[1] = r;
538
+ const i = t.remove_entity_tag(e);
539
+ f[0] = n, f[1] = i;
465
540
  }
466
541
  /**
467
542
  * Bulk-move ALL entities from src into this archetype using TypedArray.set().
468
543
  * Much faster than per-entity move_entity_from when the entire source is moving.
469
544
  * After this call, src is empty. Returns the starting dst_row for the batch.
470
545
  */
471
- bulk_move_all_from(t, e) {
472
- const s = t.length;
473
- if (s === 0) return this.length;
474
- const n = this.length, r = this._flat_columns, i = t._flat_columns;
475
- this._entity_ids.bulk_append(t._entity_ids.buf, 0, s);
546
+ bulk_move_all_from(t, e, s) {
547
+ const n = t.length;
548
+ if (n === 0) return this.length;
549
+ const i = this.length, r = this._flat_columns, c = t._flat_columns;
550
+ this._entity_ids.bulk_append(t._entity_ids.buf, 0, n);
476
551
  for (let _ = 0; _ < r.length; _++) {
477
- const c = e[_];
478
- c >= 0 ? r[_].bulk_append(i[c].buf, 0, s) : r[_].bulk_append_zeroes(s);
552
+ const h = e[_];
553
+ h >= 0 ? r[_].bulk_append(c[h].buf, 0, n) : r[_].bulk_append_zeroes(n);
479
554
  }
480
- this.length += s, t.length = 0, t._entity_ids.clear();
481
- for (let _ = 0; _ < i.length; _++)
482
- i[_].clear();
483
- return n;
555
+ const o = this._column_ids;
556
+ for (let _ = 0; _ < o.length; _++)
557
+ this._changed_tick[o[_]] = s;
558
+ this.length += n, t.length = 0, t._entity_ids.clear();
559
+ for (let _ = 0; _ < c.length; _++)
560
+ c[_].clear();
561
+ return i;
484
562
  }
485
563
  get_edge(t) {
486
564
  return this.edges[t];
@@ -488,26 +566,35 @@ class Tt {
488
566
  set_edge(t, e) {
489
567
  this.edges[t] = e;
490
568
  }
569
+ /**
570
+ * Get the cached transition map from this archetype to `target`, building
571
+ * and caching it on miss. Archetypes live for the lifetime of the Store,
572
+ * so entries never need invalidation.
573
+ */
574
+ get_batch_transition_map(t) {
575
+ let e = this.batch_transition_maps.get(t.id);
576
+ return e === void 0 && (e = G(this, t), this.batch_transition_maps.set(t.id, e)), e;
577
+ }
491
578
  }
492
- const f = [0, y];
493
- function M(l, t) {
494
- const e = t._flat_columns, s = new Int16Array(e.length), n = t._column_ids, r = l._col_offset, i = t._col_offset, _ = t._field_count;
495
- for (let c = 0; c < n.length; c++) {
496
- const o = n[c], h = i[o], a = _[o], u = r[o];
497
- if (u !== void 0)
498
- for (let d = 0; d < a; d++)
499
- s[h + d] = u + d;
579
+ const f = [0, m];
580
+ function G(a, t) {
581
+ const e = t._flat_columns, s = new Int16Array(e.length), n = t._column_ids, i = a._col_offset, r = t._col_offset, c = t._field_count;
582
+ for (let o = 0; o < n.length; o++) {
583
+ const _ = n[o], h = r[_], l = c[_], d = i[_];
584
+ if (d !== void 0)
585
+ for (let u = 0; u < l; u++)
586
+ s[h + u] = d + u;
500
587
  else
501
- for (let d = 0; d < a; d++)
502
- s[h + d] = -1;
588
+ for (let u = 0; u < l; u++)
589
+ s[h + u] = -1;
503
590
  }
504
591
  return s;
505
592
  }
506
- function K(l, t, e) {
507
- const s = l.get(t);
508
- s !== void 0 ? s.push(e) : l.set(t, [e]);
593
+ function Q(a, t, e) {
594
+ const s = a.get(t);
595
+ s !== void 0 ? s.push(e) : a.set(t, [e]);
509
596
  }
510
- class At {
597
+ class xt {
511
598
  // --- Entity ID management ---
512
599
  // Generational slot allocator: entity_generations[index] holds the current
513
600
  // generation for that slot. Free indices are recycled via a stack.
@@ -524,10 +611,6 @@ class At {
524
611
  // Parallel array indexed by EventID: each channel holds SoA columns + reader.
525
612
  event_channels = [];
526
613
  event_count = 0;
527
- // --- Resource channels ---
528
- // Parallel array indexed by ResourceID: each channel holds a single row of SoA columns.
529
- resource_channels = [];
530
- resource_count = 0;
531
614
  // --- Archetype management ---
532
615
  archetypes = [];
533
616
  // Hash-bucketed lookup: BitSet.hash() → ArchetypeID[] for deduplication
@@ -553,9 +636,10 @@ class At {
553
636
  pending_add_values = [];
554
637
  pending_remove_ids = [];
555
638
  pending_remove_defs = [];
639
+ _tick = 0;
556
640
  initial_capacity;
557
641
  constructor(t) {
558
- this.initial_capacity = t ?? V, this.empty_archetype_id = this.arch_get_or_create_from_mask(new x());
642
+ this.initial_capacity = t ?? K, this.empty_archetype_id = this.arch_get_or_create_from_mask(new p());
559
643
  }
560
644
  // =======================================================
561
645
  // Archetype graph
@@ -570,30 +654,30 @@ class At {
570
654
  arch_get_or_create_from_mask(t) {
571
655
  const e = t.hash(), s = this.archetype_map.get(e);
572
656
  if (s !== void 0) {
573
- for (let c = 0; c < s.length; c++)
574
- if (this.archetypes[s[c]].mask.equals(t))
575
- return s[c];
657
+ for (let o = 0; o < s.length; o++)
658
+ if (this.archetypes[s[o]].mask.equals(t))
659
+ return s[o];
576
660
  }
577
- const n = bt(this.next_archetype_id++), r = [];
578
- t.for_each((c) => {
579
- const o = c, h = this.component_metas[o];
580
- h && h.field_names.length > 0 && r.push({
581
- component_id: o,
661
+ const n = bt(this.next_archetype_id++), i = [];
662
+ t.for_each((o) => {
663
+ const _ = o, h = this.component_metas[_];
664
+ h && h.field_names.length > 0 && i.push({
665
+ component_id: _,
582
666
  field_names: h.field_names,
583
667
  field_index: h.field_index,
584
668
  field_types: h.field_types
585
669
  });
586
670
  });
587
- const i = new Tt(n, t, r, this.initial_capacity);
588
- this.archetypes.push(i), K(this.archetype_map, e, n), t.for_each((c) => {
589
- const o = c;
590
- let h = this.component_index.get(o);
591
- h || (h = /* @__PURE__ */ new Set(), this.component_index.set(o, h)), h.add(n);
671
+ const r = new At(n, t, i, this.initial_capacity);
672
+ this.archetypes.push(r), Q(this.archetype_map, e, n), t.for_each((o) => {
673
+ const _ = o;
674
+ let h = this.component_index.get(_);
675
+ h || (h = /* @__PURE__ */ new Set(), this.component_index.set(_, h)), h.add(n);
592
676
  });
593
- const _ = this.registered_queries;
594
- for (let c = 0; c < _.length; c++) {
595
- const o = _[c];
596
- i.matches(o.include_mask) && (!o.exclude_mask || !i.mask.overlaps(o.exclude_mask)) && (!o.any_of_mask || i.mask.overlaps(o.any_of_mask)) && o.result.push(i);
677
+ const c = this.registered_queries;
678
+ for (let o = 0; o < c.length; o++) {
679
+ const _ = c[o];
680
+ r.matches(_.include_mask) && (!_.exclude_mask || !r.mask.overlaps(_.exclude_mask)) && (!_.any_of_mask || r.mask.overlaps(_.any_of_mask)) && (_.result.push(r), _.query?.mark_non_empty_dirty());
597
681
  }
598
682
  return n;
599
683
  }
@@ -603,10 +687,10 @@ class At {
603
687
  if (s.mask.has(e)) return t;
604
688
  const n = s.get_edge(e);
605
689
  if (n?.add != null) return n.add;
606
- const r = this.arch_get_or_create_from_mask(
690
+ const i = this.arch_get_or_create_from_mask(
607
691
  s.mask.copy_with_set(e)
608
692
  );
609
- return this.arch_cache_edge(s, this.arch_get(r), e), r;
693
+ return this.arch_cache_edge(s, this.arch_get(i), e), i;
610
694
  }
611
695
  /** Resolve "remove component_id from archetype_id" → target ArchetypeID. Caches the edge. */
612
696
  arch_resolve_remove(t, e) {
@@ -614,10 +698,10 @@ class At {
614
698
  if (!s.mask.has(e)) return t;
615
699
  const n = s.get_edge(e);
616
700
  if (n?.remove != null) return n.remove;
617
- const r = this.arch_get_or_create_from_mask(
701
+ const i = this.arch_get_or_create_from_mask(
618
702
  s.mask.copy_with_clear(e)
619
703
  );
620
- return this.arch_cache_edge(this.arch_get(r), s, e), r;
704
+ return this.arch_cache_edge(this.arch_get(i), s, e), i;
621
705
  }
622
706
  /** Cache a bidirectional add/remove edge between two archetypes. */
623
707
  arch_cache_edge(t, e, s) {
@@ -627,14 +711,14 @@ class At {
627
711
  add_map: null,
628
712
  remove_map: null
629
713
  };
630
- n.add = e.id, n.add_map = M(t, e), t.set_edge(s, n);
631
- const r = e.get_edge(s) ?? {
714
+ n.add = e.id, n.add_map = G(t, e), t.set_edge(s, n);
715
+ const i = e.get_edge(s) ?? {
632
716
  add: null,
633
717
  remove: null,
634
718
  add_map: null,
635
719
  remove_map: null
636
720
  };
637
- r.remove = t.id, r.remove_map = M(e, t), e.set_edge(s, r);
721
+ i.remove = t.id, i.remove_map = G(e, t), e.set_edge(s, i);
638
722
  }
639
723
  // =======================================================
640
724
  // Entity lifecycle
@@ -642,29 +726,34 @@ class At {
642
726
  create_entity() {
643
727
  let t, e;
644
728
  this.entity_free_indices.length > 0 ? (t = this.entity_free_indices.pop(), e = this.entity_generations[t]) : (t = this.entity_high_water++, this.entity_generations[t] = j, e = j), this.entity_alive_count++;
645
- const s = mt(t, e);
646
- return this.entity_archetype[t] = this.empty_archetype_id, this.entity_row[t] = v, s;
729
+ const s = vt(t, e);
730
+ return this.entity_archetype[t] = this.empty_archetype_id, this.entity_row[t] = k, s;
647
731
  }
648
732
  /** Immediately destroy an entity, removing it from its archetype. */
649
733
  destroy_entity(t) {
650
734
  if (!this.is_alive(t))
651
735
  return;
652
- const e = m(t), s = this.entity_row[e];
653
- if (s !== v) {
654
- const i = this.arch_get(this.entity_archetype[e]).remove_entity(s);
655
- i !== y && (this.entity_row[i] = s);
736
+ const e = y(t), s = this.entity_row[e];
737
+ if (s !== k) {
738
+ const r = this.arch_get(this.entity_archetype[e]).remove_entity(s);
739
+ r !== m && (this.entity_row[r] = s);
656
740
  }
657
- this.entity_archetype[e] = v, this.entity_row[e] = v;
658
- const n = Y(t);
659
- this.entity_generations[e] = n + 1 & X, this.entity_free_indices.push(e), this.entity_alive_count--;
741
+ this.entity_archetype[e] = k, this.entity_row[e] = k;
742
+ const n = z(t);
743
+ this.entity_generations[e] = n + 1 & V, this.entity_free_indices.push(e), this.entity_alive_count--;
660
744
  }
661
745
  is_alive(t) {
662
- const e = m(t);
663
- return e < this.entity_high_water && this.entity_generations[e] === Y(t);
746
+ const e = y(t);
747
+ return e < this.entity_high_water && this.entity_generations[e] === z(t);
664
748
  }
665
749
  get entity_count() {
666
750
  return this.entity_alive_count;
667
751
  }
752
+ _mark_queries_dirty() {
753
+ const t = this.registered_queries;
754
+ for (let e = 0; e < t.length; e++)
755
+ t[e].query?.mark_non_empty_dirty();
756
+ }
668
757
  // =======================================================
669
758
  // Deferred destruction
670
759
  // =======================================================
@@ -675,74 +764,75 @@ class At {
675
764
  flush_destroyed() {
676
765
  const t = this.pending_destroy;
677
766
  if (t.length === 0) return;
678
- const e = this.entity_archetype, s = this.entity_row, n = this.entity_generations, r = this.archetypes, i = this.entity_high_water;
679
- for (let _ = 0; _ < t.length; _++) {
680
- const c = t[_], o = c & F, h = c >> P;
681
- if (o >= i || n[o] !== h) continue;
682
- const a = s[o];
683
- if (a !== v) {
684
- const u = r[e[o]], d = u.has_columns ? u.remove_entity(a) : u.remove_entity_tag(a);
685
- d !== y && (s[d] = a);
767
+ const e = this.entity_archetype, s = this.entity_row, n = this.entity_generations, i = this.archetypes, r = this.entity_high_water;
768
+ for (let c = 0; c < t.length; c++) {
769
+ const o = t[c], _ = o & M, h = o >> R;
770
+ if (_ >= r || n[_] !== h) continue;
771
+ const l = s[_];
772
+ if (l !== k) {
773
+ const d = i[e[_]], u = d.has_columns ? d.remove_entity(l) : d.remove_entity_tag(l);
774
+ u !== m && (s[u] = l);
686
775
  }
687
- e[o] = v, s[o] = v, n[o] = h + 1 & X, this.entity_free_indices.push(o), this.entity_alive_count--;
776
+ e[_] = k, s[_] = k, n[_] = h + 1 & V, this.entity_free_indices.push(_), this.entity_alive_count--;
688
777
  }
689
- t.length = 0;
778
+ t.length = 0, this._mark_queries_dirty();
690
779
  }
691
780
  get pending_destroy_count() {
692
781
  return this.pending_destroy.length;
693
782
  }
694
783
  add_component_deferred(t, e, s) {
695
- this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ?? D);
784
+ this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ?? q);
696
785
  }
697
786
  remove_component_deferred(t, e) {
698
787
  this.pending_remove_ids.push(t), this.pending_remove_defs.push(e);
699
788
  }
700
789
  flush_structural() {
701
- this.pending_add_ids.length > 0 && this._flush_adds(), this.pending_remove_ids.length > 0 && this._flush_removes();
790
+ const t = this.pending_add_ids.length > 0, e = this.pending_remove_ids.length > 0;
791
+ t && this._flush_adds(), e && this._flush_removes(), (t || e) && this._mark_queries_dirty();
702
792
  }
703
793
  /** Batch-apply all deferred component additions. */
704
794
  _flush_adds() {
705
- const t = this.pending_add_ids, e = this.pending_add_defs, s = this.pending_add_values, n = t.length, r = this.entity_archetype, i = this.entity_row, _ = this.entity_generations, c = this.archetypes, o = this.component_metas, h = this.entity_high_water;
706
- for (let a = 0; a < n; a++) {
707
- const u = t[a], d = u & F, g = u >> P;
708
- if (d >= h || _[d] !== g) continue;
709
- const T = r[d], p = e[a], w = c[T];
710
- if (w.mask.has(p)) {
711
- o[p].field_names.length > 0 && w.write_fields(i[d], p, s[a]);
795
+ const t = this.pending_add_ids, e = this.pending_add_defs, s = this.pending_add_values, n = t.length, i = this.entity_archetype, r = this.entity_row, c = this.entity_generations, o = this.archetypes, _ = this.component_metas, h = this.entity_high_water, l = this._tick;
796
+ for (let d = 0; d < n; d++) {
797
+ const u = t[d], g = u & M, w = u >> R;
798
+ if (g >= h || c[g] !== w) continue;
799
+ const T = i[g], v = e[d], E = o[T];
800
+ if (E.mask.has(v)) {
801
+ _[v].field_names.length > 0 && E.write_fields(r[g], v, s[d], l);
712
802
  continue;
713
803
  }
714
- const S = this.arch_resolve_add(T, p), E = c[S], O = i[d], L = !E.has_columns && !w.has_columns;
804
+ const N = this.arch_resolve_add(T, v), x = o[N], P = r[g], Y = !x.has_columns && !E.has_columns;
715
805
  let U;
716
- if (O !== v) {
717
- if (L)
718
- E.move_entity_from_tag(w, O, u);
806
+ if (P !== k) {
807
+ if (Y)
808
+ x.move_entity_from_tag(E, P, u);
719
809
  else {
720
- const $ = w.get_edge(p);
721
- E.move_entity_from(w, O, u, $.add_map);
810
+ const J = E.get_edge(v);
811
+ x.move_entity_from(E, P, u, J.add_map, l);
722
812
  }
723
- U = f[0], f[1] !== y && (i[f[1]] = O);
813
+ U = f[0], f[1] !== m && (r[f[1]] = P);
724
814
  } else
725
- U = L ? E.add_entity_tag(u) : E.add_entity(u);
726
- o[p].field_names.length > 0 && E.write_fields(U, p, s[a]), r[d] = S, i[d] = U;
815
+ U = Y ? x.add_entity_tag(u) : x.add_entity(u);
816
+ _[v].field_names.length > 0 && x.write_fields(U, v, s[d], l), i[g] = N, r[g] = U;
727
817
  }
728
818
  t.length = 0, e.length = 0, s.length = 0;
729
819
  }
730
820
  /** Batch-apply all deferred component removals. */
731
821
  _flush_removes() {
732
- const t = this.pending_remove_ids, e = this.pending_remove_defs, s = t.length, n = this.entity_archetype, r = this.entity_row, i = this.entity_generations, _ = this.archetypes, c = this.entity_high_water;
733
- for (let o = 0; o < s; o++) {
734
- const h = t[o], a = h & F, u = h >> P;
735
- if (a >= c || i[a] !== u) continue;
736
- const d = n[a], g = e[o], T = _[d];
737
- if (!T.mask.has(g)) continue;
738
- const p = this.arch_resolve_remove(d, g), w = _[p], S = r[a];
739
- if (!w.has_columns && !T.has_columns)
740
- w.move_entity_from_tag(T, S, h);
822
+ const t = this.pending_remove_ids, e = this.pending_remove_defs, s = t.length, n = this.entity_archetype, i = this.entity_row, r = this.entity_generations, c = this.archetypes, o = this.entity_high_water, _ = this._tick;
823
+ for (let h = 0; h < s; h++) {
824
+ const l = t[h], d = l & M, u = l >> R;
825
+ if (d >= o || r[d] !== u) continue;
826
+ const g = n[d], w = e[h], T = c[g];
827
+ if (!T.mask.has(w)) continue;
828
+ const v = this.arch_resolve_remove(g, w), E = c[v], N = i[d];
829
+ if (!E.has_columns && !T.has_columns)
830
+ E.move_entity_from_tag(T, N, l);
741
831
  else {
742
- const O = T.get_edge(g);
743
- w.move_entity_from(T, S, h, O.remove_map);
832
+ const P = T.get_edge(w);
833
+ E.move_entity_from(T, N, l, P.remove_map, _);
744
834
  }
745
- f[1] !== y && (r[f[1]] = S), n[a] = p, r[a] = f[0];
835
+ f[1] !== m && (i[f[1]] = N), n[d] = v, i[d] = f[0];
746
836
  }
747
837
  t.length = 0, e.length = 0;
748
838
  }
@@ -753,108 +843,101 @@ class At {
753
843
  // Component registration
754
844
  // =======================================================
755
845
  register_component(t) {
756
- const e = yt(this.component_count++), s = Object.keys(t), n = new Array(s.length), r = /* @__PURE__ */ Object.create(null);
757
- for (let i = 0; i < s.length; i++)
758
- r[s[i]] = i, n[i] = t[s[i]];
759
- return this.component_metas.push({ field_names: s, field_index: r, field_types: n }), e;
846
+ const e = Et(this.component_count++), s = Object.keys(t), n = new Array(s.length), i = /* @__PURE__ */ Object.create(null);
847
+ for (let r = 0; r < s.length; r++)
848
+ i[s[r]] = r, n[r] = t[s[r]];
849
+ return this.component_metas.push({ field_names: s, field_index: i, field_types: n }), e;
760
850
  }
761
851
  add_component(t, e, s) {
762
852
  if (!this.is_alive(t))
763
853
  return;
764
- const n = m(t), r = this.entity_archetype[n], i = this.arch_get(r);
765
- if (i.has_component(e)) {
766
- i.write_fields(
854
+ const n = y(t), i = this.entity_archetype[n], r = this.arch_get(i);
855
+ if (r.has_component(e)) {
856
+ r.write_fields(
767
857
  this.entity_row[n],
768
858
  e,
769
- s
859
+ s,
860
+ this._tick
770
861
  );
771
862
  return;
772
863
  }
773
- const _ = this.arch_resolve_add(
774
- r,
775
- e
776
- ), c = this.arch_get(_), o = this.entity_row[n];
864
+ const c = this.arch_resolve_add(i, e), o = this.arch_get(c), _ = this.entity_row[n];
777
865
  let h;
778
- if (o !== v) {
779
- const a = i.get_edge(e);
780
- !c.has_columns && !i.has_columns ? c.move_entity_from_tag(i, o, t) : c.move_entity_from(i, o, t, a.add_map), h = f[0], f[1] !== y && (this.entity_row[f[1]] = o);
866
+ if (_ !== k) {
867
+ const l = r.get_edge(e);
868
+ !o.has_columns && !r.has_columns ? o.move_entity_from_tag(r, _, t) : o.move_entity_from(r, _, t, l.add_map, this._tick), h = f[0], f[1] !== m && (this.entity_row[f[1]] = _);
781
869
  } else
782
- h = c.has_columns ? c.add_entity(t) : c.add_entity_tag(t);
783
- c.write_fields(
870
+ h = o.has_columns ? o.add_entity(t) : o.add_entity_tag(t);
871
+ o.write_fields(
784
872
  h,
785
873
  e,
786
- s
787
- ), this.entity_archetype[n] = _, this.entity_row[n] = h;
874
+ s,
875
+ this._tick
876
+ ), this.entity_archetype[n] = c, this.entity_row[n] = h, this._mark_queries_dirty();
788
877
  }
789
878
  /** Add multiple components in one transition (resolves final archetype, then moves once). */
790
879
  add_components(t, e) {
791
880
  if (!this.is_alive(t))
792
881
  return;
793
- const s = m(t), n = this.entity_archetype[s];
794
- let r = n;
795
- for (let i = 0; i < e.length; i++)
796
- r = this.arch_resolve_add(
797
- r,
798
- e[i].def
799
- );
800
- if (r !== n) {
801
- const i = this.arch_get(n), _ = this.arch_get(r), c = this.entity_row[s];
802
- let o;
803
- if (c !== v) {
804
- const h = M(i, _);
805
- _.move_entity_from(i, c, t, h), o = f[0], f[1] !== y && (this.entity_row[f[1]] = c);
882
+ const s = y(t), n = this.entity_archetype[s];
883
+ let i = n;
884
+ for (let r = 0; r < e.length; r++)
885
+ i = this.arch_resolve_add(i, e[r].def);
886
+ if (i !== n) {
887
+ const r = this.arch_get(n), c = this.arch_get(i), o = this.entity_row[s];
888
+ let _;
889
+ if (o !== k) {
890
+ const h = r.get_batch_transition_map(c);
891
+ c.move_entity_from(r, o, t, h, this._tick), _ = f[0], f[1] !== m && (this.entity_row[f[1]] = o);
806
892
  } else
807
- o = _.add_entity(t);
893
+ _ = c.add_entity(t);
808
894
  for (let h = 0; h < e.length; h++)
809
- _.write_fields(
810
- o,
895
+ c.write_fields(
896
+ _,
811
897
  e[h].def,
812
- e[h].values ?? D
898
+ e[h].values ?? q,
899
+ this._tick
813
900
  );
814
- this.entity_archetype[s] = r, this.entity_row[s] = o;
901
+ this.entity_archetype[s] = i, this.entity_row[s] = _, this._mark_queries_dirty();
815
902
  } else {
816
- const i = this.arch_get(n), _ = this.entity_row[s];
817
- for (let c = 0; c < e.length; c++)
818
- i.write_fields(
819
- _,
820
- e[c].def,
821
- e[c].values ?? D
903
+ const r = this.arch_get(n), c = this.entity_row[s];
904
+ for (let o = 0; o < e.length; o++)
905
+ r.write_fields(
906
+ c,
907
+ e[o].def,
908
+ e[o].values ?? q,
909
+ this._tick
822
910
  );
823
911
  }
824
912
  }
825
913
  remove_component(t, e) {
826
914
  if (!this.is_alive(t))
827
915
  return;
828
- const s = m(t), n = this.entity_archetype[s], r = this.arch_get(n);
829
- if (!r.has_component(e)) return;
830
- const i = this.arch_resolve_remove(
831
- n,
832
- e
833
- ), _ = this.arch_get(i), c = this.entity_row[s], o = r.get_edge(e);
834
- !_.has_columns && !r.has_columns ? _.move_entity_from_tag(r, c, t) : _.move_entity_from(r, c, t, o.remove_map), f[1] !== y && (this.entity_row[f[1]] = c), this.entity_archetype[s] = i, this.entity_row[s] = f[0];
916
+ const s = y(t), n = this.entity_archetype[s], i = this.arch_get(n);
917
+ if (!i.has_component(e)) return;
918
+ const r = this.arch_resolve_remove(n, e), c = this.arch_get(r), o = this.entity_row[s], _ = i.get_edge(e);
919
+ !c.has_columns && !i.has_columns ? c.move_entity_from_tag(i, o, t) : c.move_entity_from(i, o, t, _.remove_map, this._tick), f[1] !== m && (this.entity_row[f[1]] = o), this.entity_archetype[s] = r, this.entity_row[s] = f[0], this._mark_queries_dirty();
835
920
  }
836
921
  /** Remove multiple components in one transition (resolves final archetype, then moves once). */
837
922
  remove_components(t, e) {
838
923
  if (!this.is_alive(t))
839
924
  return;
840
- const s = m(t), n = this.entity_archetype[s];
841
- let r = n;
925
+ const s = y(t), n = this.entity_archetype[s];
926
+ let i = n;
842
927
  for (let h = 0; h < e.length; h++)
843
- r = this.arch_resolve_remove(
844
- r,
928
+ i = this.arch_resolve_remove(
929
+ i,
845
930
  e[h]
846
931
  );
847
- if (r === n) return;
848
- const i = this.arch_get(n), _ = this.arch_get(r), c = this.entity_row[s], o = M(i, _);
849
- _.move_entity_from(i, c, t, o), f[1] !== y && (this.entity_row[f[1]] = c), this.entity_archetype[s] = r, this.entity_row[s] = f[0];
932
+ if (i === n) return;
933
+ const r = this.arch_get(n), c = this.arch_get(i), o = this.entity_row[s], _ = G(r, c);
934
+ c.move_entity_from(r, o, t, _, this._tick), f[1] !== m && (this.entity_row[f[1]] = o), this.entity_archetype[s] = i, this.entity_row[s] = f[0], this._mark_queries_dirty();
850
935
  }
851
936
  has_component(t, e) {
852
937
  if (!this.is_alive(t))
853
938
  return !1;
854
- const s = m(t);
855
- return this.arch_get(
856
- this.entity_archetype[s]
857
- ).has_component(e);
939
+ const s = y(t);
940
+ return this.arch_get(this.entity_archetype[s]).has_component(e);
858
941
  }
859
942
  /**
860
943
  * Bulk add a component to ALL entities in the given archetype.
@@ -865,14 +948,15 @@ class At {
865
948
  if (t.length === 0) return;
866
949
  const n = e;
867
950
  if (t.mask.has(n)) return;
868
- const r = this.arch_resolve_add(t.id, n), i = this.arch_get(r), _ = t.get_edge(n), c = t.length, o = this.entity_archetype, h = this.entity_row, a = i.bulk_move_all_from(t, _.add_map);
869
- for (let d = 0; d < c; d++) {
870
- const g = m(i.entity_ids[a + d]);
871
- o[g] = r, h[g] = a + d;
951
+ const i = this.arch_resolve_add(t.id, n), r = this.arch_get(i), c = t.get_edge(n), o = t.length, _ = this.entity_archetype, h = this.entity_row, l = r.bulk_move_all_from(t, c.add_map, this._tick);
952
+ for (let u = 0; u < o; u++) {
953
+ const g = y(r.entity_ids[l + u]);
954
+ _[g] = i, h[g] = l + u;
872
955
  }
873
956
  if (this.component_metas[n].field_names.length > 0 && s)
874
- for (let d = 0; d < c; d++)
875
- i.write_fields(a + d, n, s);
957
+ for (let u = 0; u < o; u++)
958
+ r.write_fields(l + u, n, s, this._tick);
959
+ this._mark_queries_dirty();
876
960
  }
877
961
  /**
878
962
  * Bulk remove a component from ALL entities in the given archetype.
@@ -883,22 +967,21 @@ class At {
883
967
  if (t.length === 0) return;
884
968
  const s = e;
885
969
  if (!t.mask.has(s)) return;
886
- const n = this.arch_resolve_remove(t.id, s), r = this.arch_get(n), i = t.get_edge(s), _ = t.length, c = r.bulk_move_all_from(t, i.remove_map), o = this.entity_archetype, h = this.entity_row;
887
- for (let a = 0; a < _; a++) {
888
- const u = m(r.entity_ids[c + a]);
889
- o[u] = n, h[u] = c + a;
970
+ const n = this.arch_resolve_remove(t.id, s), i = this.arch_get(n), r = t.get_edge(s), c = t.length, o = i.bulk_move_all_from(t, r.remove_map, this._tick), _ = this.entity_archetype, h = this.entity_row;
971
+ for (let l = 0; l < c; l++) {
972
+ const d = y(i.entity_ids[o + l]);
973
+ _[d] = n, h[d] = o + l;
890
974
  }
975
+ this._mark_queries_dirty();
891
976
  }
892
977
  // =======================================================
893
978
  // Direct data access (used by SystemContext)
894
979
  // =======================================================
895
980
  get_entity_archetype(t) {
896
- return this.arch_get(
897
- this.entity_archetype[m(t)]
898
- );
981
+ return this.arch_get(this.entity_archetype[y(t)]);
899
982
  }
900
983
  get_entity_row(t) {
901
- return this.entity_row[m(t)];
984
+ return this.entity_row[y(t)];
902
985
  }
903
986
  // =======================================================
904
987
  // Query support
@@ -910,58 +993,63 @@ class At {
910
993
  */
911
994
  get_matching_archetypes(t, e, s) {
912
995
  const n = t._words;
913
- let r = !1;
914
- for (let o = 0; o < n.length; o++)
915
- if (n[o] !== 0) {
916
- r = !0;
996
+ let i = !1;
997
+ for (let _ = 0; _ < n.length; _++)
998
+ if (n[_] !== 0) {
999
+ i = !0;
917
1000
  break;
918
1001
  }
919
- if (!r)
1002
+ if (!i)
920
1003
  return this.archetypes.filter(
921
- (o) => (!e || !o.mask.overlaps(e)) && (!s || o.mask.overlaps(s))
1004
+ (_) => (!e || !_.mask.overlaps(e)) && (!s || _.mask.overlaps(s))
922
1005
  );
923
- let i, _ = !1;
924
- for (let o = 0; o < n.length; o++) {
925
- let h = n[o];
1006
+ let r, c = !1;
1007
+ for (let _ = 0; _ < n.length; _++) {
1008
+ let h = n[_];
926
1009
  if (h === 0) continue;
927
- const a = o << k;
1010
+ const l = _ << I;
928
1011
  for (; h !== 0; ) {
929
- const u = h & -h >>> 0, d = a + (I - Math.clz32(u));
930
- h ^= u;
931
- const g = this.component_index.get(d);
1012
+ const d = h & -h >>> 0, u = l + (S - Math.clz32(d));
1013
+ h ^= d;
1014
+ const g = this.component_index.get(u);
932
1015
  if (!g || g.size === 0) {
933
- _ = !0;
1016
+ c = !0;
934
1017
  break;
935
1018
  }
936
- (!i || g.size < i.size) && (i = g);
1019
+ (!r || g.size < r.size) && (r = g);
937
1020
  }
938
- if (_) break;
1021
+ if (c) break;
939
1022
  }
940
- if (_ || !i) return [];
941
- const c = [];
942
- for (const o of i) {
943
- const h = this.arch_get(o);
944
- h.matches(t) && (!e || !h.mask.overlaps(e)) && (!s || h.mask.overlaps(s)) && c.push(h);
1023
+ if (c || !r) return [];
1024
+ const o = [];
1025
+ for (const _ of r) {
1026
+ const h = this.arch_get(_);
1027
+ h.matches(t) && (!e || !h.mask.overlaps(e)) && (!s || h.mask.overlaps(s)) && o.push(h);
945
1028
  }
946
- return c;
1029
+ return o;
947
1030
  }
948
1031
  /**
949
1032
  * Register a live query. Returns a mutable Archetype[] that this Store will
950
1033
  * push newly-created matching archetypes into, keeping the query always up-to-date.
951
1034
  */
952
1035
  register_query(t, e, s) {
953
- const n = this.get_matching_archetypes(
954
- t,
955
- e,
956
- s
957
- );
1036
+ const n = this.get_matching_archetypes(t, e, s);
958
1037
  return this.registered_queries.push({
959
1038
  include_mask: t.copy(),
960
1039
  exclude_mask: e ? e.copy() : null,
961
1040
  any_of_mask: s ? s.copy() : null,
962
- result: n
1041
+ result: n,
1042
+ query: null
963
1043
  }), n;
964
1044
  }
1045
+ update_query_ref(t, e) {
1046
+ const s = this.registered_queries;
1047
+ for (let n = 0; n < s.length; n++)
1048
+ if (s[n].result === t) {
1049
+ s[n].query = e;
1050
+ return;
1051
+ }
1052
+ }
965
1053
  get archetype_count() {
966
1054
  return this.archetypes.length;
967
1055
  }
@@ -969,7 +1057,7 @@ class At {
969
1057
  // Event channels
970
1058
  // =======================================================
971
1059
  register_event(t) {
972
- const e = pt(this.event_count++), s = new wt(t);
1060
+ const e = kt(this.event_count++), s = new Tt(t);
973
1061
  return this.event_channels.push(s), e;
974
1062
  }
975
1063
  emit_event(t, e) {
@@ -987,76 +1075,107 @@ class At {
987
1075
  t[e].clear();
988
1076
  }
989
1077
  // =======================================================
990
- // Resource channels
1078
+ // Event key storage
1079
+ // =======================================================
1080
+ // any: type-erased — EventDef<F> phantom is lost in the map, recovered by callers via EventKey<F>
1081
+ event_key_map = /* @__PURE__ */ new Map();
1082
+ register_event_by_key(t, e) {
1083
+ if (this.event_key_map.has(t))
1084
+ throw new O(D.EVENT_ALREADY_REGISTERED, "Event key already registered");
1085
+ const s = this.register_event(e);
1086
+ return this.event_key_map.set(t, s), s;
1087
+ }
1088
+ // any: type-erased — caller recovers F from EventKey<F>
1089
+ get_event_def_by_key(t) {
1090
+ const e = this.event_key_map.get(t);
1091
+ if (e === void 0)
1092
+ throw new O(D.EVENT_NOT_REGISTERED, "Event key not registered");
1093
+ return e;
1094
+ }
1095
+ has_event_key(t) {
1096
+ return this.event_key_map.has(t);
1097
+ }
1098
+ // =======================================================
1099
+ // Resource storage
991
1100
  // =======================================================
1101
+ resource_key_map = /* @__PURE__ */ new Map();
992
1102
  register_resource(t, e) {
993
- const s = vt(this.resource_count++), n = new xt(t, e);
994
- return this.resource_channels.push(n), s;
1103
+ if (this.resource_key_map.has(t))
1104
+ throw new O(D.RESOURCE_ALREADY_REGISTERED, "Resource key already registered");
1105
+ this.resource_key_map.set(t, e);
995
1106
  }
996
- get_resource_reader(t) {
997
- return this.resource_channels[t].reader;
1107
+ get_resource(t) {
1108
+ if (!this.resource_key_map.has(t))
1109
+ throw new O(D.RESOURCE_NOT_REGISTERED, "Resource key not registered");
1110
+ return this.resource_key_map.get(t);
1111
+ }
1112
+ set_resource(t, e) {
1113
+ if (!this.resource_key_map.has(t))
1114
+ throw new O(D.RESOURCE_NOT_REGISTERED, "Resource key not registered");
1115
+ this.resource_key_map.set(t, e);
998
1116
  }
999
- get_resource_channel(t) {
1000
- return this.resource_channels[t];
1117
+ has_resource(t) {
1118
+ return this.resource_key_map.has(t);
1001
1119
  }
1002
1120
  }
1003
- var Et = /* @__PURE__ */ ((l) => (l.PRE_STARTUP = "PRE_STARTUP", l.STARTUP = "STARTUP", l.POST_STARTUP = "POST_STARTUP", l.FIXED_UPDATE = "FIXED_UPDATE", l.PRE_UPDATE = "PRE_UPDATE", l.UPDATE = "UPDATE", l.POST_UPDATE = "POST_UPDATE", l))(Et || {});
1004
- const q = [
1121
+ var It = /* @__PURE__ */ ((a) => (a.PRE_STARTUP = "PRE_STARTUP", a.STARTUP = "STARTUP", a.POST_STARTUP = "POST_STARTUP", a.FIXED_UPDATE = "FIXED_UPDATE", a.PRE_UPDATE = "PRE_UPDATE", a.UPDATE = "UPDATE", a.POST_UPDATE = "POST_UPDATE", a))(It || {});
1122
+ const L = [
1005
1123
  "PRE_STARTUP",
1006
1124
  "STARTUP",
1007
1125
  "POST_STARTUP"
1008
1126
  /* POST_STARTUP */
1009
- ], G = [
1127
+ ], C = [
1010
1128
  "PRE_UPDATE",
1011
1129
  "UPDATE",
1012
1130
  "POST_UPDATE"
1013
1131
  /* POST_UPDATE */
1014
1132
  ];
1015
- class kt {
1133
+ class St {
1016
1134
  label_systems = /* @__PURE__ */ new Map();
1017
1135
  sorted_cache = /* @__PURE__ */ new Map();
1018
1136
  system_index = /* @__PURE__ */ new Map();
1137
+ system_last_run = /* @__PURE__ */ new Map();
1019
1138
  next_insertion_order = 0;
1020
1139
  constructor() {
1021
- for (let t = 0; t < q.length; t++)
1022
- this.label_systems.set(q[t], []);
1140
+ for (let t = 0; t < L.length; t++)
1141
+ this.label_systems.set(L[t], []);
1023
1142
  this.label_systems.set("FIXED_UPDATE", []);
1024
- for (let t = 0; t < G.length; t++)
1025
- this.label_systems.set(G[t], []);
1143
+ for (let t = 0; t < C.length; t++)
1144
+ this.label_systems.set(C[t], []);
1026
1145
  }
1027
1146
  add_systems(t, ...e) {
1028
1147
  for (const s of e) {
1029
- const n = "system" in s ? s.system : s, r = "system" in s ? s.ordering : void 0, i = {
1148
+ const n = "system" in s ? s.system : s, i = "system" in s ? s.ordering : void 0, r = {
1030
1149
  descriptor: n,
1031
1150
  insertion_order: this.next_insertion_order++,
1032
- before: new Set(r?.before ?? []),
1033
- after: new Set(r?.after ?? [])
1151
+ before: new Set(i?.before ?? []),
1152
+ after: new Set(i?.after ?? [])
1034
1153
  };
1035
- this.label_systems.get(t).push(i), this.system_index.set(n, t), this.sorted_cache.delete(t);
1154
+ this.label_systems.get(t).push(r), this.system_index.set(n, t), this.system_last_run.set(n, 0), this.sorted_cache.delete(t);
1036
1155
  }
1037
1156
  }
1038
1157
  remove_system(t) {
1039
1158
  const e = this.system_index.get(t);
1040
1159
  if (e === void 0) return;
1041
- const s = this.label_systems.get(e), n = s.findIndex((r) => r.descriptor === t);
1160
+ const s = this.label_systems.get(e), n = s.findIndex((i) => i.descriptor === t);
1042
1161
  if (n !== -1) {
1043
- const r = s.length - 1;
1044
- n !== r && (s[n] = s[r]), s.pop();
1045
- for (const i of s)
1046
- i.before.delete(t), i.after.delete(t);
1162
+ const i = s.length - 1;
1163
+ n !== i && (s[n] = s[i]), s.pop();
1164
+ for (const r of s)
1165
+ r.before.delete(t), r.after.delete(t);
1047
1166
  }
1048
- this.system_index.delete(t), this.sorted_cache.delete(e);
1167
+ this.system_index.delete(t), this.system_last_run.delete(t), this.sorted_cache.delete(e);
1049
1168
  }
1050
- run_startup(t) {
1051
- for (const e of q)
1052
- this.run_label(e, t, it);
1169
+ run_startup(t, e) {
1170
+ for (const s of L)
1171
+ this.run_label(s, t, pt, e);
1053
1172
  }
1054
- run_update(t, e) {
1055
- for (const s of G)
1056
- this.run_label(s, t, e);
1173
+ run_update(t, e, s) {
1174
+ for (const n of C)
1175
+ this.run_label(n, t, e, s);
1057
1176
  }
1058
- run_fixed_update(t, e) {
1059
- this.run_label("FIXED_UPDATE", t, e);
1177
+ run_fixed_update(t, e, s) {
1178
+ this.run_label("FIXED_UPDATE", t, e, s);
1060
1179
  }
1061
1180
  has_fixed_systems() {
1062
1181
  return this.label_systems.get(
@@ -1077,93 +1196,96 @@ class kt {
1077
1196
  clear() {
1078
1197
  for (const t of this.label_systems.values())
1079
1198
  t.length = 0;
1080
- this.sorted_cache.clear(), this.system_index.clear();
1199
+ this.sorted_cache.clear(), this.system_index.clear(), this.system_last_run.clear();
1081
1200
  }
1082
- run_label(t, e, s) {
1083
- const n = this.get_sorted(t);
1084
- for (let r = 0; r < n.length; r++)
1085
- n[r].fn(e, s);
1201
+ run_label(t, e, s, n) {
1202
+ const i = this.get_sorted(t);
1203
+ for (let r = 0; r < i.length; r++)
1204
+ this.system_last_run.set(i[r], n), e.last_run_tick = n, i[r].fn(e, s);
1086
1205
  e.flush();
1087
1206
  }
1088
1207
  get_sorted(t) {
1089
1208
  const e = this.sorted_cache.get(t);
1090
1209
  if (e !== void 0) return e;
1091
- const s = this.label_systems.get(t), n = this.topological_sort(s, t);
1210
+ const s = this.label_systems.get(t), n = this.sort_systems(s, t);
1092
1211
  return this.sorted_cache.set(t, n), n;
1093
1212
  }
1094
1213
  /**
1095
- * Kahn's algorithm: BFS-based topological sort.
1096
- * Uses insertion_order as a stable tiebreaker (lower insertion order runs first).
1214
+ * Delegates to the shared topological_sort utility.
1215
+ * Builds the dependency edge map from before/after constraints, then
1216
+ * catches any cycle TypeError and re-throws as ECSError.
1097
1217
  */
1098
- topological_sort(t, e) {
1218
+ sort_systems(t, e) {
1099
1219
  if (t.length === 0) return [];
1100
- const s = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set();
1101
- for (const o of t)
1102
- s.set(o.descriptor, /* @__PURE__ */ new Set()), n.set(o.descriptor, 0), r.set(o.descriptor, o.insertion_order), i.add(o.descriptor);
1103
- for (const o of t) {
1104
- for (const h of o.before)
1105
- i.has(h) && (s.get(o.descriptor).add(h), n.set(h, n.get(h) + 1));
1106
- for (const h of o.after)
1107
- i.has(h) && (s.get(h).add(o.descriptor), n.set(o.descriptor, n.get(o.descriptor) + 1));
1108
- }
1109
- let _ = [];
1110
- for (const o of t)
1111
- n.get(o.descriptor) === 0 && _.push(o.descriptor);
1112
- _.sort((o, h) => r.get(h) - r.get(o));
1113
- const c = [];
1114
- for (; _.length > 0; ) {
1115
- const o = _.pop();
1116
- c.push(o);
1117
- for (const h of s.get(o)) {
1118
- const a = n.get(h) - 1;
1119
- n.set(h, a), a === 0 && _.push(h);
1120
- }
1121
- _.sort((h, a) => r.get(a) - r.get(h));
1220
+ const s = [], n = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set();
1221
+ for (const _ of t)
1222
+ s.push(_.descriptor), n.set(_.descriptor, _.insertion_order), i.add(_.descriptor);
1223
+ const r = /* @__PURE__ */ new Map();
1224
+ for (const _ of t)
1225
+ r.set(_.descriptor, []);
1226
+ for (const _ of t) {
1227
+ for (const h of _.before)
1228
+ i.has(h) && r.get(_.descriptor).push(h);
1229
+ for (const h of _.after)
1230
+ i.has(h) && r.get(h).push(_.descriptor);
1122
1231
  }
1123
- if (c.length !== t.length) {
1124
- const o = new Set(c), h = t.filter((a) => !o.has(a.descriptor)).map((a) => a.descriptor.name ?? `system_${a.descriptor.id}`);
1125
- throw new Q(
1126
- z.CIRCULAR_SYSTEM_DEPENDENCY,
1127
- `Circular system dependency detected in ${e}: [${h.join(", ")}]`
1128
- );
1232
+ const c = (_, h) => n.get(_) - n.get(h), o = (_) => _.name ?? `system_${_.id}`;
1233
+ try {
1234
+ return dt(s, r, c, o);
1235
+ } catch (_) {
1236
+ throw _ instanceof TypeError ? new O(
1237
+ D.CIRCULAR_SYSTEM_DEPENDENCY,
1238
+ `Circular system dependency detected in ${e}: ${_.message}`
1239
+ ) : _;
1129
1240
  }
1130
- return c;
1131
1241
  }
1132
1242
  }
1133
1243
  const W = /* @__PURE__ */ new WeakMap();
1134
- function It(l, t) {
1135
- let e = W.get(l);
1244
+ function B(a, t) {
1245
+ let e = W.get(a);
1136
1246
  if (!e) {
1137
1247
  e = /* @__PURE__ */ Object.create(null);
1138
- const { field_names: r } = l.layout;
1139
- for (let i = 0; i < r.length; i++) {
1140
- const _ = i;
1141
- Object.defineProperty(e, r[i], {
1248
+ const { field_names: i } = a.layout;
1249
+ for (let r = 0; r < i.length; r++) {
1250
+ const c = r;
1251
+ Object.defineProperty(e, i[r], {
1142
1252
  get() {
1143
- return this._columns[_][this._row];
1253
+ return this._columns[c][this._row];
1144
1254
  },
1145
- set(c) {
1146
- this._columns[_][this._row] = c;
1255
+ set(o) {
1256
+ this._columns[c][this._row] = o;
1147
1257
  },
1148
1258
  enumerable: !0,
1149
1259
  configurable: !1
1150
1260
  });
1151
1261
  }
1152
- W.set(l, e);
1262
+ W.set(a, e);
1153
1263
  }
1154
- const s = Object.create(e), n = new Array(l.columns.length);
1155
- for (let r = 0; r < l.columns.length; r++) n[r] = l.columns[r].buf;
1264
+ const s = Object.create(e), n = new Array(a.columns.length);
1265
+ for (let i = 0; i < a.columns.length; i++) n[i] = a.columns[i].buf;
1156
1266
  return s._columns = n, s._row = t, s;
1157
1267
  }
1158
- class Pt {
1268
+ class Dt {
1159
1269
  _archetypes;
1160
1270
  _defs;
1161
1271
  _resolver;
1162
1272
  _include;
1163
1273
  _exclude;
1164
1274
  _any_of;
1165
- constructor(t, e, s, n, r, i) {
1166
- this._archetypes = t, this._defs = e, this._resolver = s, this._include = n, this._exclude = r, this._any_of = i;
1275
+ _non_empty_archetypes = [];
1276
+ _non_empty_dirty = !0;
1277
+ // Per-Query composition caches — single-component fast path.
1278
+ // The final Query produced by _resolve_query is already cached by the
1279
+ // resolver, but the caller pays a BitSet copy + defs slice per call
1280
+ // before the resolver can hash and hit that cache. These caches
1281
+ // short-circuit that allocation path for the common single-component
1282
+ // composition shape (q.and(X), q.changed(X), etc).
1283
+ _and_cache_single = null;
1284
+ _not_cache_single = null;
1285
+ _any_of_cache_single = null;
1286
+ _changed_cache_single = null;
1287
+ constructor(t, e, s, n, i, r) {
1288
+ this._archetypes = t, this._defs = e, this._resolver = s, this._include = n, this._exclude = i, this._any_of = r;
1167
1289
  }
1168
1290
  /** Number of matching archetypes (including empty ones). */
1169
1291
  get archetype_count() {
@@ -1179,27 +1301,43 @@ class Pt {
1179
1301
  get archetypes() {
1180
1302
  return this._archetypes;
1181
1303
  }
1182
- /** Iterate non-empty archetypes. Skips archetypes with zero entities. */
1183
- *[Symbol.iterator]() {
1184
- const t = this._archetypes;
1185
- for (let e = 0; e < t.length; e++)
1186
- t[e].entity_count > 0 && (yield t[e]);
1187
- }
1188
1304
  /** Extend required component set. Returns a new (cached) Query. */
1189
1305
  and(...t) {
1306
+ if (t.length === 1) {
1307
+ const n = t[0], i = this._and_cache_single;
1308
+ if (i !== null) {
1309
+ const _ = i.get(n);
1310
+ if (_ !== void 0) return _;
1311
+ }
1312
+ const r = this._include.copy(), c = this._defs.slice();
1313
+ r.has(n) || (r.set(n), c.push(t[0]));
1314
+ const o = this._resolver._resolve_query(r, this._exclude, this._any_of, c);
1315
+ return (this._and_cache_single ??= /* @__PURE__ */ new Map()).set(n, o), o;
1316
+ }
1190
1317
  const e = this._include.copy(), s = this._defs.slice();
1191
1318
  for (let n = 0; n < t.length; n++)
1192
1319
  e.has(t[n]) || (e.set(t[n]), s.push(t[n]));
1193
- return this._resolver._resolve_query(
1194
- e,
1195
- this._exclude,
1196
- this._any_of,
1197
- s
1198
- );
1320
+ return this._resolver._resolve_query(e, this._exclude, this._any_of, s);
1199
1321
  }
1200
1322
  /** Exclude archetypes that have any of these components. */
1201
1323
  not(...t) {
1202
- const e = this._exclude ? this._exclude.copy() : new x();
1324
+ if (t.length === 1) {
1325
+ const s = t[0], n = this._not_cache_single;
1326
+ if (n !== null) {
1327
+ const c = n.get(s);
1328
+ if (c !== void 0) return c;
1329
+ }
1330
+ const i = this._exclude ? this._exclude.copy() : new p();
1331
+ i.set(s);
1332
+ const r = this._resolver._resolve_query(
1333
+ this._include,
1334
+ i,
1335
+ this._any_of,
1336
+ this._defs
1337
+ );
1338
+ return (this._not_cache_single ??= /* @__PURE__ */ new Map()).set(s, r), r;
1339
+ }
1340
+ const e = this._exclude ? this._exclude.copy() : new p();
1203
1341
  for (let s = 0; s < t.length; s++) e.set(t[s]);
1204
1342
  return this._resolver._resolve_query(
1205
1343
  this._include,
@@ -1208,9 +1346,45 @@ class Pt {
1208
1346
  this._defs
1209
1347
  );
1210
1348
  }
1349
+ for_each(t) {
1350
+ const e = this._non_empty();
1351
+ for (let s = 0; s < e.length; s++)
1352
+ t(e[s]);
1353
+ }
1354
+ /** @internal — called by Store after flush and archetype push. */
1355
+ mark_non_empty_dirty() {
1356
+ this._non_empty_dirty = !0;
1357
+ }
1358
+ /** @internal — used by ChangedQuery. Rebuild non-empty archetype list if dirty, return cached result. */
1359
+ _non_empty() {
1360
+ if (this._non_empty_dirty) {
1361
+ const t = this._archetypes, e = this._non_empty_archetypes;
1362
+ e.length = 0;
1363
+ for (let s = 0; s < t.length; s++)
1364
+ t[s].entity_count > 0 && e.push(t[s]);
1365
+ this._non_empty_dirty = !1;
1366
+ }
1367
+ return this._non_empty_archetypes;
1368
+ }
1211
1369
  /** Require at least one of these components. */
1212
1370
  any_of(...t) {
1213
- const e = this._any_of ? this._any_of.copy() : new x();
1371
+ if (t.length === 1) {
1372
+ const s = t[0], n = this._any_of_cache_single;
1373
+ if (n !== null) {
1374
+ const c = n.get(s);
1375
+ if (c !== void 0) return c;
1376
+ }
1377
+ const i = this._any_of ? this._any_of.copy() : new p();
1378
+ i.set(s);
1379
+ const r = this._resolver._resolve_query(
1380
+ this._include,
1381
+ this._exclude,
1382
+ i,
1383
+ this._defs
1384
+ );
1385
+ return (this._any_of_cache_single ??= /* @__PURE__ */ new Map()).set(s, r), r;
1386
+ }
1387
+ const e = this._any_of ? this._any_of.copy() : new p();
1214
1388
  for (let s = 0; s < t.length; s++) e.set(t[s]);
1215
1389
  return this._resolver._resolve_query(
1216
1390
  this._include,
@@ -1219,19 +1393,43 @@ class Pt {
1219
1393
  this._defs
1220
1394
  );
1221
1395
  }
1396
+ /** Create a ChangedQuery that filters archetypes by change tick. */
1397
+ changed(...t) {
1398
+ if (t.length === 1) {
1399
+ const s = t[0], n = this._changed_cache_single;
1400
+ if (n !== null) {
1401
+ const r = n.get(s);
1402
+ if (r !== void 0) return r;
1403
+ }
1404
+ const i = new $(this, [s]);
1405
+ return (this._changed_cache_single ??= /* @__PURE__ */ new Map()).set(s, i), i;
1406
+ }
1407
+ const e = new Array(t.length);
1408
+ for (let s = 0; s < t.length; s++) e[s] = t[s];
1409
+ return new $(this, e);
1410
+ }
1411
+ /** @internal — reads last_run_tick from the resolver (ECS). */
1412
+ _ctx_last_run_tick() {
1413
+ return this._resolver._get_last_run_tick();
1414
+ }
1222
1415
  }
1223
- class St {
1416
+ class Rt {
1224
1417
  constructor(t) {
1225
1418
  this._resolver = t;
1226
1419
  }
1227
1420
  every(...t) {
1228
- const e = new x();
1421
+ const e = new p();
1229
1422
  for (let s = 0; s < t.length; s++) e.set(t[s]);
1230
1423
  return this._resolver._resolve_query(e, null, null, t);
1231
1424
  }
1232
1425
  }
1233
- class Ot {
1426
+ class Nt {
1234
1427
  store;
1428
+ last_run_tick = 0;
1429
+ /** Current world tick. Use this for write ticks in get_column_mut. */
1430
+ get world_tick() {
1431
+ return this.store._tick;
1432
+ }
1235
1433
  constructor(t) {
1236
1434
  this.store = t;
1237
1435
  }
@@ -1239,24 +1437,29 @@ class Ot {
1239
1437
  return this.store.create_entity();
1240
1438
  }
1241
1439
  get_field(t, e, s) {
1242
- const n = this.store.get_entity_archetype(t), r = this.store.get_entity_row(t);
1243
- return n.read_field(r, e, s);
1440
+ const n = this.store.get_entity_archetype(t), i = this.store.get_entity_row(t);
1441
+ return n.read_field(i, e, s);
1244
1442
  }
1245
1443
  set_field(t, e, s, n) {
1246
- const r = this.store.get_entity_archetype(t), i = this.store.get_entity_row(t), _ = r.get_column(e, s);
1247
- _[i] = n;
1444
+ const i = this.store.get_entity_archetype(t), r = this.store.get_entity_row(t), c = i.get_column_mut(e, s, this.store._tick);
1445
+ c[r] = n;
1248
1446
  }
1249
- /** Create a cached component reference for a single entity. See ref.ts. */
1447
+ /** Create a cached read-only component reference for a single entity. See ref.ts. */
1250
1448
  ref(t, e) {
1251
1449
  const s = this.store.get_entity_archetype(e), n = this.store.get_entity_row(e);
1252
- return It(s.column_groups[t], n);
1450
+ return B(s.column_groups[t], n);
1451
+ }
1452
+ /** Create a cached mutable component reference. Marks the component as changed. */
1453
+ ref_mut(t, e) {
1454
+ const s = this.store.get_entity_archetype(e), n = this.store.get_entity_row(e);
1455
+ return s._changed_tick[t] = this.store._tick, B(s.column_groups[t], n);
1253
1456
  }
1254
1457
  /** Buffer an entity for deferred destruction (applied at phase flush). */
1255
1458
  destroy_entity(t) {
1256
1459
  return this.store.destroy_entity_deferred(t), this;
1257
1460
  }
1258
1461
  add_component(t, e, s) {
1259
- return this.store.add_component_deferred(t, e, s ?? D), this;
1462
+ return this.store.add_component_deferred(t, e, s ?? q), this;
1260
1463
  }
1261
1464
  remove_component(t, e) {
1262
1465
  return this.store.remove_component_deferred(t, e), this;
@@ -1266,30 +1469,55 @@ class Ot {
1266
1469
  this.store.flush_structural(), this.store.flush_destroyed();
1267
1470
  }
1268
1471
  emit(t, e) {
1269
- e === void 0 ? this.store.emit_signal(t) : this.store.emit_event(t, e);
1472
+ const s = this.store.get_event_def_by_key(t);
1473
+ e === void 0 ? this.store.emit_signal(s) : this.store.emit_event(s, e);
1270
1474
  }
1271
1475
  read(t) {
1272
- return this.store.get_event_reader(t);
1476
+ const e = this.store.get_event_def_by_key(t);
1477
+ return this.store.get_event_reader(e);
1273
1478
  }
1274
1479
  // =======================================================
1275
1480
  // Resources
1276
1481
  // =======================================================
1277
1482
  resource(t) {
1278
- return this.store.get_resource_reader(t);
1483
+ return this.store.get_resource(t);
1279
1484
  }
1280
1485
  set_resource(t, e) {
1281
- this.store.get_resource_channel(t).write(e);
1486
+ this.store.set_resource(t, e);
1487
+ }
1488
+ has_resource(t) {
1489
+ return this.store.has_resource(t);
1282
1490
  }
1283
1491
  }
1284
- const Dt = (l) => N(
1285
- l
1492
+ class $ {
1493
+ _query;
1494
+ _changed_ids;
1495
+ constructor(t, e) {
1496
+ this._query = t, this._changed_ids = e;
1497
+ }
1498
+ for_each(t) {
1499
+ const e = this._query._ctx_last_run_tick(), s = this._query._non_empty(), n = this._changed_ids;
1500
+ for (let i = 0; i < s.length; i++) {
1501
+ const r = s[i];
1502
+ for (let c = 0; c < n.length; c++)
1503
+ if (r._changed_tick[n[c]] >= e) {
1504
+ t(r);
1505
+ break;
1506
+ }
1507
+ }
1508
+ }
1509
+ }
1510
+ const Pt = (a) => F(
1511
+ a
1286
1512
  );
1287
- class Nt {
1513
+ class Ut {
1288
1514
  store;
1289
1515
  schedule;
1290
1516
  ctx;
1291
1517
  systems = /* @__PURE__ */ new Set();
1292
1518
  next_system_id = 0;
1519
+ // Tick counter for change detection
1520
+ _tick = 0;
1293
1521
  // Fixed timestep accumulator
1294
1522
  _fixed_timestep;
1295
1523
  _accumulator = 0;
@@ -1298,9 +1526,9 @@ class Nt {
1298
1526
  // Multiple queries can share the same hash (collision), so each bucket is an array.
1299
1527
  query_cache = /* @__PURE__ */ new Map();
1300
1528
  // Reusable BitSet for building query masks — avoids allocation per query() call
1301
- scratch_mask = new x();
1529
+ scratch_mask = new p();
1302
1530
  constructor(t) {
1303
- this.store = new At(t?.initial_capacity), this.schedule = new kt(), this.ctx = new Ot(this.store), this._fixed_timestep = t?.fixed_timestep ?? nt, this._max_fixed_steps = t?.max_fixed_steps ?? rt;
1531
+ this.store = new xt(t?.initial_capacity), this.schedule = new St(), this.ctx = new Nt(this.store), this._fixed_timestep = t?.fixed_timestep ?? yt, this._max_fixed_steps = t?.max_fixed_steps ?? mt;
1304
1532
  }
1305
1533
  get fixed_timestep() {
1306
1534
  return this._fixed_timestep;
@@ -1315,7 +1543,7 @@ class Nt {
1315
1543
  register_component(t, e) {
1316
1544
  if (Array.isArray(t)) {
1317
1545
  const s = e ?? "f64", n = /* @__PURE__ */ Object.create(null);
1318
- for (const r of t) n[r] = s;
1546
+ for (const i of t) n[i] = s;
1319
1547
  return this.store.register_component(n);
1320
1548
  }
1321
1549
  return this.store.register_component(t);
@@ -1323,23 +1551,23 @@ class Nt {
1323
1551
  register_tag() {
1324
1552
  return this.store.register_component({});
1325
1553
  }
1326
- register_event(t) {
1327
- return this.store.register_event(t);
1554
+ register_event(t, e) {
1555
+ this.store.register_event_by_key(t, e);
1328
1556
  }
1329
- register_signal() {
1330
- return this.store.register_event([]);
1557
+ register_signal(t) {
1558
+ this.store.register_event_by_key(t, []);
1331
1559
  }
1332
1560
  register_resource(t, e) {
1333
- return this.store.register_resource(
1334
- t,
1335
- e
1336
- );
1561
+ this.store.register_resource(t, e);
1337
1562
  }
1338
1563
  resource(t) {
1339
- return this.store.get_resource_reader(t);
1564
+ return this.store.get_resource(t);
1340
1565
  }
1341
1566
  set_resource(t, e) {
1342
- this.store.get_resource_channel(t).write(e);
1567
+ this.store.set_resource(t, e);
1568
+ }
1569
+ has_resource(t) {
1570
+ return this.store.has_resource(t);
1343
1571
  }
1344
1572
  create_entity() {
1345
1573
  return this.store.create_entity();
@@ -1354,7 +1582,7 @@ class Nt {
1354
1582
  return this.store.entity_count;
1355
1583
  }
1356
1584
  add_component(t, e, s) {
1357
- return this.store.add_component(t, e, s ?? D), this;
1585
+ return this.store.add_component(t, e, s ?? q), this;
1358
1586
  }
1359
1587
  add_components(t, e) {
1360
1588
  this.store.add_components(t, e);
@@ -1379,15 +1607,20 @@ class Nt {
1379
1607
  this.store.batch_remove_component(t, e);
1380
1608
  }
1381
1609
  get_field(t, e, s) {
1382
- const n = this.store.get_entity_archetype(t), r = this.store.get_entity_row(t);
1383
- return n.read_field(r, e, s);
1610
+ const n = this.store.get_entity_archetype(t), i = this.store.get_entity_row(t);
1611
+ return n.read_field(i, e, s);
1384
1612
  }
1385
1613
  set_field(t, e, s, n) {
1386
- const r = this.store.get_entity_archetype(t), i = this.store.get_entity_row(t), _ = r.get_column(e, s);
1387
- _[i] = n;
1614
+ const i = this.store.get_entity_archetype(t), r = this.store.get_entity_row(t), c = i.get_column_mut(e, s, this.store._tick);
1615
+ c[r] = n;
1388
1616
  }
1389
1617
  emit(t, e) {
1390
- e === void 0 ? this.store.emit_signal(t) : this.store.emit_event(t, e);
1618
+ const s = this.store.get_event_def_by_key(t);
1619
+ e === void 0 ? this.store.emit_signal(s) : this.store.emit_event(s, e);
1620
+ }
1621
+ read(t) {
1622
+ const e = this.store.get_event_def_by_key(t);
1623
+ return this.store.get_event_reader(e);
1391
1624
  }
1392
1625
  query(...t) {
1393
1626
  const e = this.scratch_mask;
@@ -1396,15 +1629,14 @@ class Nt {
1396
1629
  e.set(t[s]);
1397
1630
  return this._resolve_query(e.copy(), null, null, t);
1398
1631
  }
1632
+ _get_last_run_tick() {
1633
+ return this.ctx.last_run_tick;
1634
+ }
1399
1635
  /** QueryResolver implementation — creates or retrieves a cached Query. */
1400
1636
  _resolve_query(t, e, s, n) {
1401
- const r = t.hash(), i = e ? e.hash() : 0, _ = s ? s.hash() : 0, c = r ^ Math.imul(i, tt) ^ Math.imul(_, et) | 0, o = this._find_cached(c, t, e, s);
1402
- if (o !== void 0) return o.query;
1403
- const h = this.store.register_query(
1404
- t,
1405
- e ?? void 0,
1406
- s ?? void 0
1407
- ), a = new Pt(
1637
+ const i = t.hash(), r = e ? e.hash() : 0, c = s ? s.hash() : 0, o = i ^ Math.imul(r, ut) ^ Math.imul(c, ft) | 0, _ = this._find_cached(o, t, e, s);
1638
+ if (_ !== void 0) return _.query;
1639
+ const h = this.store.register_query(t, e ?? void 0, s ?? void 0), l = new Dt(
1408
1640
  h,
1409
1641
  n,
1410
1642
  this,
@@ -1412,20 +1644,20 @@ class Nt {
1412
1644
  e?.copy() ?? null,
1413
1645
  s?.copy() ?? null
1414
1646
  );
1415
- return K(this.query_cache, c, {
1647
+ return this.store.update_query_ref(h, l), Q(this.query_cache, o, {
1416
1648
  include_mask: t.copy(),
1417
1649
  exclude_mask: e?.copy() ?? null,
1418
1650
  any_of_mask: s?.copy() ?? null,
1419
- query: a
1420
- }), a;
1651
+ query: l
1652
+ }), l;
1421
1653
  }
1422
1654
  _find_cached(t, e, s, n) {
1423
- const r = this.query_cache.get(t);
1424
- if (r)
1425
- for (let i = 0; i < r.length; i++) {
1426
- const _ = r[i];
1427
- if (!(!_.include_mask.equals(e) || !(s === null ? _.exclude_mask === null : _.exclude_mask !== null && _.exclude_mask.equals(s)) || !(n === null ? _.any_of_mask === null : _.any_of_mask !== null && _.any_of_mask.equals(n))))
1428
- return _;
1655
+ const i = this.query_cache.get(t);
1656
+ if (i)
1657
+ for (let r = 0; r < i.length; r++) {
1658
+ const c = i[r];
1659
+ if (!(!c.include_mask.equals(e) || !(s === null ? c.exclude_mask === null : c.exclude_mask !== null && c.exclude_mask.equals(s)) || !(n === null ? c.any_of_mask === null : c.any_of_mask !== null && c.any_of_mask.equals(n))))
1660
+ return c;
1429
1661
  }
1430
1662
  }
1431
1663
  // any: overload implementation must unify bare fn, (fn, query_fn), and SystemConfig
@@ -1433,16 +1665,14 @@ class Nt {
1433
1665
  let s;
1434
1666
  if (typeof t == "function")
1435
1667
  if (e !== void 0) {
1436
- const i = e(new St(this)), _ = this.ctx, c = t;
1437
- s = { fn: (o, h) => c(i, _, h) };
1668
+ const r = e(new Rt(this)), c = this.ctx, o = t;
1669
+ s = { fn: (_, h) => o(r, c, h) };
1438
1670
  } else
1439
1671
  s = { fn: t };
1440
1672
  else
1441
1673
  s = t;
1442
- const n = Dt(this.next_system_id++), r = Object.freeze(
1443
- Object.assign({ id: n }, s)
1444
- );
1445
- return this.systems.add(r), r;
1674
+ const n = Pt(this.next_system_id++), i = Object.freeze(Object.assign({ id: n }, s));
1675
+ return this.systems.add(i), i;
1446
1676
  }
1447
1677
  add_systems(t, ...e) {
1448
1678
  return this.schedule.add_systems(t, ...e), this;
@@ -1456,16 +1686,16 @@ class Nt {
1456
1686
  startup() {
1457
1687
  for (const t of this.systems.values())
1458
1688
  t.on_added?.(this.ctx);
1459
- this.schedule.run_startup(this.ctx);
1689
+ this.schedule.run_startup(this.ctx, this._tick);
1460
1690
  }
1461
1691
  update(t) {
1462
- if (this.schedule.has_fixed_systems()) {
1692
+ if (this.store._tick = this._tick, this.schedule.has_fixed_systems()) {
1463
1693
  this._accumulator += t;
1464
1694
  const e = this._max_fixed_steps * this._fixed_timestep;
1465
1695
  for (this._accumulator > e && (this._accumulator = e); this._accumulator >= this._fixed_timestep; )
1466
- this.schedule.run_fixed_update(this.ctx, this._fixed_timestep), this._accumulator -= this._fixed_timestep;
1696
+ this.schedule.run_fixed_update(this.ctx, this._fixed_timestep, this._tick), this._accumulator -= this._fixed_timestep;
1467
1697
  }
1468
- this.schedule.run_update(this.ctx, t), this.store.clear_events();
1698
+ this.schedule.run_update(this.ctx, t, this._tick), this.store.clear_events(), this._tick++;
1469
1699
  }
1470
1700
  flush() {
1471
1701
  this.ctx.flush();
@@ -1476,10 +1706,17 @@ class Nt {
1476
1706
  this.systems.clear(), this.schedule.clear();
1477
1707
  }
1478
1708
  }
1709
+ function Mt(a) {
1710
+ return Symbol(a);
1711
+ }
1479
1712
  export {
1480
- Nt as ECS,
1481
- Pt as Query,
1482
- St as QueryBuilder,
1483
- Et as SCHEDULE,
1484
- Ot as SystemContext
1713
+ $ as ChangedQuery,
1714
+ Ut as ECS,
1715
+ Dt as Query,
1716
+ Rt as QueryBuilder,
1717
+ It as SCHEDULE,
1718
+ Nt as SystemContext,
1719
+ Ot as event_key,
1720
+ Mt as resource_key,
1721
+ qt as signal_key
1485
1722
  };