@oasys/oecs 0.1.1 → 0.2.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.
Files changed (41) hide show
  1. package/README.md +131 -164
  2. package/dist/archetype.d.ts +50 -13
  3. package/dist/archetype.d.ts.map +1 -1
  4. package/dist/component.d.ts +27 -10
  5. package/dist/component.d.ts.map +1 -1
  6. package/dist/ecs.d.ts +104 -0
  7. package/dist/ecs.d.ts.map +1 -0
  8. package/dist/entity.d.ts.map +1 -1
  9. package/dist/event.d.ts +2 -2
  10. package/dist/event.d.ts.map +1 -1
  11. package/dist/index.cjs +1 -1
  12. package/dist/index.d.ts +8 -7
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +680 -400
  15. package/dist/query.d.ts +28 -31
  16. package/dist/query.d.ts.map +1 -1
  17. package/dist/ref.d.ts +19 -0
  18. package/dist/ref.d.ts.map +1 -0
  19. package/dist/resource.d.ts +23 -0
  20. package/dist/resource.d.ts.map +1 -0
  21. package/dist/schedule.d.ts +3 -3
  22. package/dist/schedule.d.ts.map +1 -1
  23. package/dist/store.d.ts +48 -29
  24. package/dist/store.d.ts.map +1 -1
  25. package/dist/system.d.ts +2 -2
  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/bitset/bitset.d.ts +2 -2
  30. package/dist/type_primitives/bitset/bitset.d.ts.map +1 -1
  31. package/dist/type_primitives/sparse_map/sparse_map.d.ts.map +1 -1
  32. package/dist/type_primitives/sparse_set/sparse_set.d.ts.map +1 -1
  33. package/dist/type_primitives/typed_arrays/typed_arrays.d.ts +9 -0
  34. package/dist/type_primitives/typed_arrays/typed_arrays.d.ts.map +1 -1
  35. package/dist/utils/constants.d.ts +20 -0
  36. package/dist/utils/constants.d.ts.map +1 -0
  37. package/dist/utils/error.d.ts +2 -9
  38. package/dist/utils/error.d.ts.map +1 -1
  39. package/package.json +2 -1
  40. package/dist/world.d.ts +0 -73
  41. package/dist/world.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -1,46 +1,34 @@
1
- class R extends Error {
1
+ class H 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 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))(d || {});
7
- class u extends R {
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 {
8
8
  constructor(t, e, s) {
9
9
  super(e ?? t, !0, s), this.category = t;
10
10
  }
11
11
  }
12
- var Y = /* @__PURE__ */ ((a) => (a.ASSERTION_FAIL_CONDITION = "ASSERTION_FAIL_CONDITION", a.VALIDATION_FAIL_CONDITION = "VALIDATION_FAIL_CONDITION", a))(Y || {});
13
- class X extends R {
14
- constructor(t, e, s) {
15
- super(e, !1, s), this.category = t;
16
- }
17
- }
18
- const P = (a) => Number.isInteger(a) && a >= 0;
19
- function b(a, t, e) {
20
- if (process.env.NODE_ENV !== "production" && !t(a))
21
- throw new X(
22
- Y.VALIDATION_FAIL_CONDITION,
23
- `Expected value to meet validation: ${e}`
24
- );
25
- return a;
12
+ function N(l, t, e) {
13
+ return l;
26
14
  }
27
- const C = 4;
28
- class N {
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 {
29
17
  _words;
30
18
  constructor(t) {
31
- this._words = t ?? new Array(C).fill(0);
19
+ this._words = t ?? new Array(ot).fill(0);
32
20
  }
33
21
  has(t) {
34
- const e = t >>> 5;
35
- return e >= this._words.length ? !1 : (this._words[e] & 1 << (t & 31)) !== 0;
22
+ const e = t >>> k;
23
+ return e >= this._words.length ? !1 : (this._words[e] & 1 << (t & I)) !== 0;
36
24
  }
37
25
  set(t) {
38
- const e = t >>> 5;
39
- e >= this._words.length && this.grow(e + 1), this._words[e] |= 1 << (t & 31);
26
+ const e = t >>> k;
27
+ e >= this._words.length && this.grow(e + 1), this._words[e] |= 1 << (t & I);
40
28
  }
41
29
  clear(t) {
42
- const e = t >>> 5;
43
- e >= this._words.length || (this._words[e] &= ~(1 << (t & 31)));
30
+ const e = t >>> k;
31
+ e >= this._words.length || (this._words[e] &= ~(1 << (t & I)));
44
32
  }
45
33
  /** True if any bit is set in both this and other (non-empty intersection). */
46
34
  overlaps(t) {
@@ -68,25 +56,25 @@ class N {
68
56
  return !0;
69
57
  }
70
58
  copy() {
71
- return new N(this._words.slice());
59
+ return new x(this._words.slice());
72
60
  }
73
61
  copy_with_set(t) {
74
- const e = t >>> 5, s = e + 1, n = this._words.length > s ? this._words.length : s, r = new Array(n).fill(0);
62
+ const e = t >>> k, s = e + 1, n = this._words.length > s ? this._words.length : s, r = new Array(n).fill(0);
75
63
  for (let i = 0; i < this._words.length; i++) r[i] = this._words[i];
76
- return r[e] |= 1 << (t & 31), new N(r);
64
+ return r[e] |= 1 << (t & I), new x(r);
77
65
  }
78
66
  copy_with_clear(t) {
79
- const e = this._words.slice(), s = t >>> 5;
80
- return s < e.length && (e[s] &= ~(1 << (t & 31))), new N(e);
67
+ const e = this._words.slice(), s = t >>> k;
68
+ return s < e.length && (e[s] &= ~(1 << (t & I))), new x(e);
81
69
  }
82
70
  /** FNV-1a hash. Skips trailing zero words so differently-sized arrays with the same bits hash equally. */
83
71
  hash() {
84
- let t = 2166136261;
72
+ let t = J;
85
73
  const e = this._words;
86
74
  let s = e.length - 1;
87
75
  for (; s >= 0 && e[s] === 0; ) s--;
88
76
  for (let n = 0; n <= s; n++)
89
- t ^= e[n], t = Math.imul(t, 16777619);
77
+ t ^= e[n], t = Math.imul(t, Z);
90
78
  return t;
91
79
  }
92
80
  /** Iterate all set bits via lowest-set-bit extraction. */
@@ -95,9 +83,9 @@ class N {
95
83
  for (let s = 0; s < e.length; s++) {
96
84
  let n = e[s];
97
85
  if (n === 0) continue;
98
- const r = s << 5;
86
+ const r = s << k;
99
87
  for (; n !== 0; ) {
100
- const i = n & -n >>> 0, _ = 31 - Math.clz32(i);
88
+ const i = n & -n >>> 0, _ = I - Math.clz32(i);
101
89
  t(r + _), n ^= i;
102
90
  }
103
91
  }
@@ -110,26 +98,144 @@ class N {
110
98
  this._words = s;
111
99
  }
112
100
  }
113
- const I = 20, k = (1 << I) - 1, j = k, G = 31 - I, D = (1 << G) - 1, $ = (a, t) => {
114
- if (process.env.NODE_ENV !== "production") {
115
- if (a < 0 || a > j)
116
- throw new u(d.EID_MAX_INDEX_OVERFLOW);
117
- if (t < 0 || t > D)
118
- throw new u(d.EID_MAX_GEN_OVERFLOW);
119
- }
120
- return t << I | a;
121
- }, y = (a) => a & k, q = (a) => a >> I, z = (a) => b(
122
- a,
123
- P,
124
- "ComponentID must be a non-negative integer"
125
- ), W = (a) => b(
126
- a,
127
- P,
128
- "EventID must be a non-negative integer"
101
+ class A {
102
+ constructor(t, e = b) {
103
+ this._ctor = t, this._buf = new t(e);
104
+ }
105
+ _buf;
106
+ _len = 0;
107
+ get length() {
108
+ return this._len;
109
+ }
110
+ push(t) {
111
+ this._len >= this._buf.length && this._grow(), this._buf[this._len++] = t;
112
+ }
113
+ pop() {
114
+ return this._buf[--this._len];
115
+ }
116
+ get(t) {
117
+ return this._buf[t];
118
+ }
119
+ set_at(t, e) {
120
+ this._buf[t] = e;
121
+ }
122
+ /**
123
+ * Move the last element into slot i, decrement length.
124
+ * Returns the value that was removed from slot i.
125
+ */
126
+ swap_remove(t) {
127
+ const e = this._buf[t];
128
+ return this._buf[t] = this._buf[--this._len], e;
129
+ }
130
+ clear() {
131
+ this._len = 0;
132
+ }
133
+ /**
134
+ * Raw backing buffer. Valid data: indices 0..length-1.
135
+ * This reference is stable until the next push() that triggers a grow —
136
+ * do not cache across entity additions.
137
+ */
138
+ get buf() {
139
+ return this._buf;
140
+ }
141
+ /**
142
+ * Zero-copy subarray view of valid data (0..length-1).
143
+ * Shares the backing buffer — invalidated if a subsequent push() grows.
144
+ */
145
+ view() {
146
+ return this._buf.subarray(0, this._len);
147
+ }
148
+ [Symbol.iterator]() {
149
+ let t = 0;
150
+ const e = this._buf, s = this._len;
151
+ return {
152
+ next() {
153
+ return t < s ? { value: e[t++], done: !1 } : { value: 0, done: !0 };
154
+ }
155
+ };
156
+ }
157
+ /** Ensure the backing buffer can hold at least `capacity` elements without growing. */
158
+ ensure_capacity(t) {
159
+ if (t <= this._buf.length) return;
160
+ let e = this._buf.length || 1;
161
+ for (; e < t; ) e *= C;
162
+ const s = new this._ctor(e);
163
+ s.set(this._buf.subarray(0, this._len)), this._buf = s;
164
+ }
165
+ /**
166
+ * Append `count` elements from `src` starting at `src_offset`.
167
+ * Grows if needed. Equivalent to push() in a loop but uses TypedArray.set().
168
+ */
169
+ bulk_append(t, e, s) {
170
+ this.ensure_capacity(this._len + s), this._buf.set(t.subarray(e, e + s), this._len), this._len += s;
171
+ }
172
+ /** Append `count` zeroes. Grows if needed. */
173
+ bulk_append_zeroes(t) {
174
+ this.ensure_capacity(this._len + t), this._buf.fill(0, this._len, this._len + t), this._len += t;
175
+ }
176
+ _grow() {
177
+ const t = new this._ctor(this._buf.length * C);
178
+ t.set(this._buf), this._buf = t;
179
+ }
180
+ }
181
+ class _t extends A {
182
+ constructor(t = b) {
183
+ super(Float32Array, t);
184
+ }
185
+ }
186
+ class ct extends A {
187
+ constructor(t = b) {
188
+ super(Float64Array, t);
189
+ }
190
+ }
191
+ class ht extends A {
192
+ constructor(t = b) {
193
+ super(Int8Array, t);
194
+ }
195
+ }
196
+ class lt extends A {
197
+ constructor(t = b) {
198
+ super(Int16Array, t);
199
+ }
200
+ }
201
+ class at extends A {
202
+ constructor(t = b) {
203
+ super(Int32Array, t);
204
+ }
205
+ }
206
+ class dt extends A {
207
+ constructor(t = b) {
208
+ super(Uint8Array, t);
209
+ }
210
+ }
211
+ class ut extends A {
212
+ constructor(t = b) {
213
+ super(Uint16Array, t);
214
+ }
215
+ }
216
+ class B extends A {
217
+ constructor(t = b) {
218
+ super(Uint32Array, t);
219
+ }
220
+ }
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
129
234
  );
130
- class B {
235
+ class wt {
131
236
  field_names;
132
237
  columns;
238
+ // any: type-erased storage — channel is stored in Map<number, EventChannel>, F is lost
133
239
  reader;
134
240
  constructor(t) {
135
241
  this.field_names = t, this.columns = [];
@@ -157,46 +263,92 @@ class B {
157
263
  t[e].length = 0;
158
264
  }
159
265
  }
160
- const Q = (a) => b(
161
- a,
162
- P,
163
- "ArchetypeID must be a non-negative integer"
266
+ const vt = (l) => N(
267
+ l
164
268
  );
165
- class K {
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
+ }
302
+ }
303
+ const bt = (l) => N(
304
+ l
305
+ );
306
+ class Tt {
166
307
  id;
167
308
  mask;
168
309
  has_columns;
169
- entity_ids = [];
310
+ _entity_ids;
170
311
  length = 0;
171
312
  edges = [];
172
- // Sparse array indexed by ComponentID — undefined for absent components.
173
- // Allows O(1) column group lookup by component.
313
+ // --- Flat column storage ---
314
+ // Dense array of ALL columns across all components in this archetype.
315
+ _flat_columns = [];
316
+ // Sparse by ComponentID → starting index into _flat_columns.
317
+ _col_offset = [];
318
+ // Sparse by ComponentID → number of fields for that component.
319
+ _field_count = [];
320
+ // Sparse by ComponentID → field_index record (field name → offset within component).
321
+ _field_index = [];
322
+ // Sparse by ComponentID → field_names array.
323
+ _field_names = [];
324
+ // Sparse array indexed by ComponentID — kept for create_ref compatibility.
174
325
  column_groups = [];
175
- // Dense list of ComponentIDs that have columns — used to iterate only
176
- // data-bearing components in copy/add/remove operations.
326
+ // Dense list of ComponentIDs that have columns — used for copy_shared_from.
177
327
  _column_ids = [];
178
- constructor(t, e, s) {
179
- if (this.id = t, this.mask = e, s)
180
- for (let n = 0; n < s.length; n++) {
181
- const r = s[n], i = new Array(r.field_names.length);
182
- for (let h = 0; h < r.field_names.length; h++)
183
- i[h] = [];
184
- const _ = /* @__PURE__ */ Object.create(null);
185
- for (let h = 0; h < r.field_names.length; h++)
186
- _[r.field_names[h]] = i[h];
187
- this.column_groups[r.component_id] = {
188
- layout: r,
189
- columns: i,
190
- record: _
191
- }, this._column_ids.push(r.component_id);
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;
337
+ }
338
+ this.column_groups[c] = { layout: _, columns: o }, this._column_ids.push(c);
192
339
  }
340
+ }
193
341
  this.has_columns = this._column_ids.length > 0;
194
342
  }
195
343
  get entity_count() {
196
344
  return this.length;
197
345
  }
346
+ /** Raw entity ID buffer. Valid data at indices 0..entity_count-1. */
347
+ get entity_ids() {
348
+ return this._entity_ids.buf;
349
+ }
198
350
  get entity_list() {
199
- return this.entity_ids;
351
+ return this._entity_ids.view();
200
352
  }
201
353
  has_component(t) {
202
354
  return this.mask.has(t);
@@ -206,47 +358,39 @@ class K {
206
358
  }
207
359
  /** Get a single field's column. Valid data: indices 0..entity_count-1. */
208
360
  get_column(t, e) {
209
- const s = this.column_groups[t];
210
- if (process.env.NODE_ENV !== "production" && !s)
211
- throw new u(
212
- d.COMPONENT_NOT_REGISTERED,
213
- `Component ${t} not in archetype ${this.id}`
214
- );
215
- const n = s.layout.field_index[e];
216
- if (process.env.NODE_ENV !== "production" && n === void 0)
217
- throw new u(
218
- d.COMPONENT_NOT_REGISTERED,
219
- `Field "${e}" does not exist on component`
220
- );
221
- return s.columns[n];
222
- }
223
- /** Get all columns for a component as { fieldName: number[] }. */
224
- get_column_group(t) {
225
- const e = this.column_groups[t];
226
- return e ? e.record : {};
361
+ const s = t, n = this._field_index[s][e];
362
+ return this._flat_columns[this._col_offset[s] + n].buf;
227
363
  }
228
364
  write_fields(t, e, s) {
229
- const n = this.column_groups[e];
230
- if (!n) return;
231
- const { field_names: r } = n.layout;
232
- for (let i = 0; i < r.length; i++)
233
- n.columns[i][t] = s[r[i]];
365
+ const n = e, r = this._col_offset[n];
366
+ 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]];
370
+ }
371
+ /** 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];
374
+ if (r === void 0) return;
375
+ const i = this._flat_columns;
376
+ for (let _ = 0; _ < s.length; _++)
377
+ i[r + _].buf[t] = s[_];
234
378
  }
235
379
  read_field(t, e, s) {
236
- const n = this.column_groups[e];
237
- if (!n) return NaN;
238
- const r = n.layout.field_index[s];
239
- return r === void 0 ? NaN : n.columns[r][t] ?? NaN;
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];
240
384
  }
241
385
  /** Copy all shared component columns from source archetype at src_row into dst_row. */
242
386
  copy_shared_from(t, e, s) {
243
- const n = t.column_groups, r = this._column_ids;
244
- for (let i = 0; i < r.length; i++) {
245
- const _ = r[i], h = n[_];
246
- if (!h) continue;
247
- const o = this.column_groups[_];
248
- for (let c = 0; c < o.columns.length; c++)
249
- o.columns[c][s] = h.columns[c][e];
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];
250
394
  }
251
395
  }
252
396
  /**
@@ -255,49 +399,88 @@ class K {
255
399
  */
256
400
  add_entity(t) {
257
401
  const e = this.length;
258
- this.entity_ids.push(t);
259
- const s = this._column_ids;
260
- for (let n = 0; n < s.length; n++) {
261
- const r = this.column_groups[s[n]];
262
- for (let i = 0; i < r.columns.length; i++)
263
- r.columns[i].push(0);
264
- }
402
+ this._entity_ids.push(t);
403
+ const s = this._flat_columns;
404
+ for (let n = 0; n < s.length; n++)
405
+ s[n].push(0);
265
406
  return this.length++, e;
266
407
  }
267
408
  /**
268
409
  * Remove entity at row via swap-and-pop. Swaps the last entity into the
269
410
  * vacated row to keep data dense. Returns the entity_index of the swapped
270
- * entity (so Store can update its row), or -1 if no swap was needed.
411
+ * entity (so Store can update its row), or NO_SWAP if no swap was needed.
271
412
  */
272
413
  remove_entity(t) {
273
414
  const e = this.length - 1;
274
- let s = -1;
275
- const n = this._column_ids;
415
+ let s = y;
416
+ const n = this._flat_columns, r = this._entity_ids.buf;
276
417
  if (t !== e) {
277
- this.entity_ids[t] = this.entity_ids[e], s = y(this.entity_ids[t]);
278
- for (let r = 0; r < n.length; r++) {
279
- const i = this.column_groups[n[r]];
280
- for (let _ = 0; _ < i.columns.length; _++)
281
- i.columns[_][t] = i.columns[_][e], i.columns[_].pop();
282
- }
418
+ r[t] = r[e], s = m(r[t]);
419
+ for (let i = 0; i < n.length; i++)
420
+ n[i].swap_remove(t);
283
421
  } else
284
- for (let r = 0; r < n.length; r++) {
285
- const i = this.column_groups[n[r]];
286
- for (let _ = 0; _ < i.columns.length; _++)
287
- i.columns[_].pop();
288
- }
289
- return this.entity_ids.pop(), this.length--, s;
422
+ for (let i = 0; i < n.length; i++)
423
+ n[i].pop();
424
+ return this._entity_ids.pop(), this.length--, s;
290
425
  }
291
426
  /** Tag-optimized add: skip column push entirely (no data to store). */
292
427
  add_entity_tag(t) {
293
428
  const e = this.length;
294
- return this.entity_ids.push(t), this.length++, e;
429
+ return this._entity_ids.push(t), this.length++, e;
295
430
  }
296
431
  /** Tag-optimized remove via swap-and-pop: skip column swap/pop entirely. */
297
432
  remove_entity_tag(t) {
298
433
  const e = this.length - 1;
299
- let s = -1;
300
- return t !== e && (this.entity_ids[t] = this.entity_ids[e], s = y(this.entity_ids[t])), this.entity_ids.pop(), this.length--, s;
434
+ let s = y;
435
+ 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;
437
+ }
438
+ /**
439
+ * Move an entity from src archetype into this archetype in a single pass.
440
+ * Combines add_entity + copy_shared_from + remove_entity(src).
441
+ * Uses a pre-computed transition map for branchless column copy.
442
+ * Writes dst_row to _move_result[0], swapped entity index to _move_result[1].
443
+ */
444
+ move_entity_from(t, e, s, n) {
445
+ const r = this.length;
446
+ 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);
451
+ }
452
+ this.length++;
453
+ const c = t.has_columns ? t.remove_entity(e) : t.remove_entity_tag(e);
454
+ f[0] = r, f[1] = c;
455
+ }
456
+ /**
457
+ * Move an entity from src into this archetype (tag-only: no columns to copy).
458
+ * Writes dst_row to _move_result[0], swapped entity index to _move_result[1].
459
+ */
460
+ move_entity_from_tag(t, e, s) {
461
+ const n = this.length;
462
+ this._entity_ids.push(s), this.length++;
463
+ const r = t.remove_entity_tag(e);
464
+ f[0] = n, f[1] = r;
465
+ }
466
+ /**
467
+ * Bulk-move ALL entities from src into this archetype using TypedArray.set().
468
+ * Much faster than per-entity move_entity_from when the entire source is moving.
469
+ * After this call, src is empty. Returns the starting dst_row for the batch.
470
+ */
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);
476
+ 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);
479
+ }
480
+ this.length += s, t.length = 0, t._entity_ids.clear();
481
+ for (let _ = 0; _ < i.length; _++)
482
+ i[_].clear();
483
+ return n;
301
484
  }
302
485
  get_edge(t) {
303
486
  return this.edges[t];
@@ -306,12 +489,25 @@ class K {
306
489
  this.edges[t] = e;
307
490
  }
308
491
  }
309
- function F(a, t, e) {
310
- const s = a.get(t);
311
- s !== void 0 ? s.push(e) : a.set(t, [e]);
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;
500
+ else
501
+ for (let d = 0; d < a; d++)
502
+ s[h + d] = -1;
503
+ }
504
+ return s;
505
+ }
506
+ function K(l, t, e) {
507
+ const s = l.get(t);
508
+ s !== void 0 ? s.push(e) : l.set(t, [e]);
312
509
  }
313
- const m = -1, V = Object.freeze(/* @__PURE__ */ Object.create(null));
314
- class J {
510
+ class At {
315
511
  // --- Entity ID management ---
316
512
  // Generational slot allocator: entity_generations[index] holds the current
317
513
  // generation for that slot. Free indices are recycled via a stack.
@@ -320,7 +516,7 @@ class J {
320
516
  entity_free_indices = [];
321
517
  entity_alive_count = 0;
322
518
  // --- Component metadata ---
323
- // Parallel array indexed by ComponentID: field_names and field_index
519
+ // Parallel array indexed by ComponentID: field_names, field_index, and field_types
324
520
  // for building archetype column layouts.
325
521
  component_metas = [];
326
522
  component_count = 0;
@@ -328,6 +524,10 @@ class J {
328
524
  // Parallel array indexed by EventID: each channel holds SoA columns + reader.
329
525
  event_channels = [];
330
526
  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;
331
531
  // --- Archetype management ---
332
532
  archetypes = [];
333
533
  // Hash-bucketed lookup: BitSet.hash() → ArchetypeID[] for deduplication
@@ -353,18 +553,14 @@ class J {
353
553
  pending_add_values = [];
354
554
  pending_remove_ids = [];
355
555
  pending_remove_defs = [];
356
- constructor() {
357
- this.empty_archetype_id = this.arch_get_or_create_from_mask(new N());
556
+ initial_capacity;
557
+ constructor(t) {
558
+ this.initial_capacity = t ?? V, this.empty_archetype_id = this.arch_get_or_create_from_mask(new x());
358
559
  }
359
560
  // =======================================================
360
561
  // Archetype graph
361
562
  // =======================================================
362
563
  arch_get(t) {
363
- if (process.env.NODE_ENV !== "production" && (t < 0 || t >= this.archetypes.length))
364
- throw new u(
365
- d.ARCHETYPE_NOT_FOUND,
366
- `Archetype with ID ${t} not found`
367
- );
368
564
  return this.archetypes[t];
369
565
  }
370
566
  /**
@@ -374,28 +570,29 @@ class J {
374
570
  arch_get_or_create_from_mask(t) {
375
571
  const e = t.hash(), s = this.archetype_map.get(e);
376
572
  if (s !== void 0) {
377
- for (let h = 0; h < s.length; h++)
378
- if (this.archetypes[s[h]].mask.equals(t))
379
- return s[h];
573
+ for (let c = 0; c < s.length; c++)
574
+ if (this.archetypes[s[c]].mask.equals(t))
575
+ return s[c];
380
576
  }
381
- const n = Q(this.next_archetype_id++), r = [];
382
- t.for_each((h) => {
383
- const o = h, c = this.component_metas[o];
384
- c && c.field_names.length > 0 && r.push({
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({
385
581
  component_id: o,
386
- field_names: c.field_names,
387
- field_index: c.field_index
582
+ field_names: h.field_names,
583
+ field_index: h.field_index,
584
+ field_types: h.field_types
388
585
  });
389
586
  });
390
- const i = new K(n, t, r);
391
- this.archetypes.push(i), F(this.archetype_map, e, n), t.for_each((h) => {
392
- const o = h;
393
- let c = this.component_index.get(o);
394
- c || (c = /* @__PURE__ */ new Set(), this.component_index.set(o, c)), c.add(n);
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);
395
592
  });
396
593
  const _ = this.registered_queries;
397
- for (let h = 0; h < _.length; h++) {
398
- const o = _[h];
594
+ for (let c = 0; c < _.length; c++) {
595
+ const o = _[c];
399
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);
400
597
  }
401
598
  return n;
@@ -426,41 +623,44 @@ class J {
426
623
  arch_cache_edge(t, e, s) {
427
624
  const n = t.get_edge(s) ?? {
428
625
  add: null,
429
- remove: null
626
+ remove: null,
627
+ add_map: null,
628
+ remove_map: null
430
629
  };
431
- n.add = e.id, t.set_edge(s, n);
432
- const r = e.get_edge(s) ?? { add: null, remove: null };
433
- r.remove = t.id, e.set_edge(s, r);
630
+ n.add = e.id, n.add_map = M(t, e), t.set_edge(s, n);
631
+ const r = e.get_edge(s) ?? {
632
+ add: null,
633
+ remove: null,
634
+ add_map: null,
635
+ remove_map: null
636
+ };
637
+ r.remove = t.id, r.remove_map = M(e, t), e.set_edge(s, r);
434
638
  }
435
639
  // =======================================================
436
640
  // Entity lifecycle
437
641
  // =======================================================
438
642
  create_entity() {
439
643
  let t, e;
440
- 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] = 0, e = 0), this.entity_alive_count++;
441
- const s = $(t, e);
442
- return this.entity_archetype[t] = this.empty_archetype_id, this.entity_row[t] = m, s;
644
+ 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;
443
647
  }
444
648
  /** Immediately destroy an entity, removing it from its archetype. */
445
649
  destroy_entity(t) {
446
- if (!this.is_alive(t)) {
447
- if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
650
+ if (!this.is_alive(t))
448
651
  return;
449
- }
450
- const e = y(t), s = this.entity_row[e];
451
- if (s !== m) {
652
+ const e = m(t), s = this.entity_row[e];
653
+ if (s !== v) {
452
654
  const i = this.arch_get(this.entity_archetype[e]).remove_entity(s);
453
- i !== -1 && (this.entity_row[i] = s);
655
+ i !== y && (this.entity_row[i] = s);
454
656
  }
455
- this.entity_archetype[e] = m, this.entity_row[e] = m;
456
- const n = q(t);
457
- if (process.env.NODE_ENV !== "production" && n >= D)
458
- throw new u(d.EID_MAX_GEN_OVERFLOW);
459
- this.entity_generations[e] = n + 1 & D, this.entity_free_indices.push(e), this.entity_alive_count--;
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--;
460
660
  }
461
661
  is_alive(t) {
462
- const e = y(t);
463
- return e < this.entity_high_water && this.entity_generations[e] === q(t);
662
+ const e = m(t);
663
+ return e < this.entity_high_water && this.entity_generations[e] === Y(t);
464
664
  }
465
665
  get entity_count() {
466
666
  return this.entity_alive_count;
@@ -469,8 +669,6 @@ class J {
469
669
  // Deferred destruction
470
670
  // =======================================================
471
671
  destroy_entity_deferred(t) {
472
- if (process.env.NODE_ENV !== "production" && !this.is_alive(t))
473
- throw new u(d.ENTITY_NOT_ALIVE);
474
672
  this.pending_destroy.push(t);
475
673
  }
476
674
  /** Flush all buffered entity destructions in batch. */
@@ -479,16 +677,14 @@ class J {
479
677
  if (t.length === 0) return;
480
678
  const e = this.entity_archetype, s = this.entity_row, n = this.entity_generations, r = this.archetypes, i = this.entity_high_water;
481
679
  for (let _ = 0; _ < t.length; _++) {
482
- const h = t[_], o = h & k, c = h >> I;
483
- if (o >= i || n[o] !== c) continue;
484
- const l = s[o];
485
- if (l !== m) {
486
- const p = r[e[o]], g = p.has_columns ? p.remove_entity(l) : p.remove_entity_tag(l);
487
- g !== -1 && (s[g] = l);
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);
488
686
  }
489
- if (e[o] = m, s[o] = m, process.env.NODE_ENV !== "production" && c >= D)
490
- throw new u(d.EID_MAX_GEN_OVERFLOW);
491
- n[o] = c + 1 & D, this.entity_free_indices.push(o), this.entity_alive_count--;
687
+ e[o] = v, s[o] = v, n[o] = h + 1 & X, this.entity_free_indices.push(o), this.entity_alive_count--;
492
688
  }
493
689
  t.length = 0;
494
690
  }
@@ -496,13 +692,9 @@ class J {
496
692
  return this.pending_destroy.length;
497
693
  }
498
694
  add_component_deferred(t, e, s) {
499
- if (process.env.NODE_ENV !== "production" && !this.is_alive(t))
500
- throw new u(d.ENTITY_NOT_ALIVE);
501
- this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ?? V);
695
+ this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ?? D);
502
696
  }
503
697
  remove_component_deferred(t, e) {
504
- if (process.env.NODE_ENV !== "production" && !this.is_alive(t))
505
- throw new u(d.ENTITY_NOT_ALIVE);
506
698
  this.pending_remove_ids.push(t), this.pending_remove_defs.push(e);
507
699
  }
508
700
  flush_structural() {
@@ -510,37 +702,47 @@ class J {
510
702
  }
511
703
  /** Batch-apply all deferred component additions. */
512
704
  _flush_adds() {
513
- 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, h = this.archetypes, o = this.component_metas, c = this.entity_high_water;
514
- for (let l = 0; l < n; l++) {
515
- const p = t[l], g = p & k, w = p >> I;
516
- if (g >= c || _[g] !== w) continue;
517
- const T = r[g], v = e[l], f = h[T];
518
- if (f.mask.has(v)) {
519
- o[v].field_names.length > 0 && f.write_fields(i[g], v, s[l]);
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]);
520
712
  continue;
521
713
  }
522
- const O = this.arch_resolve_add(T, v), E = h[O], x = i[g], A = !E.has_columns && !f.has_columns, S = A ? E.add_entity_tag(p) : E.add_entity(p);
523
- if (x !== m) {
524
- A || E.copy_shared_from(f, x, S);
525
- const U = A ? f.remove_entity_tag(x) : f.remove_entity(x);
526
- U !== -1 && (i[U] = x);
527
- }
528
- o[v].field_names.length > 0 && E.write_fields(S, v, s[l]), r[g] = O, i[g] = S;
714
+ const S = this.arch_resolve_add(T, p), E = c[S], O = i[d], L = !E.has_columns && !w.has_columns;
715
+ let U;
716
+ if (O !== v) {
717
+ if (L)
718
+ E.move_entity_from_tag(w, O, u);
719
+ else {
720
+ const $ = w.get_edge(p);
721
+ E.move_entity_from(w, O, u, $.add_map);
722
+ }
723
+ U = f[0], f[1] !== y && (i[f[1]] = O);
724
+ } 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;
529
727
  }
530
728
  t.length = 0, e.length = 0, s.length = 0;
531
729
  }
532
730
  /** Batch-apply all deferred component removals. */
533
731
  _flush_removes() {
534
- 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, h = this.entity_high_water;
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;
535
733
  for (let o = 0; o < s; o++) {
536
- const c = t[o], l = c & k, p = c >> I;
537
- if (l >= h || i[l] !== p) continue;
538
- const g = n[l], w = e[o], T = _[g];
539
- if (!T.mask.has(w)) continue;
540
- const v = this.arch_resolve_remove(g, w), f = _[v], O = r[l], E = !f.has_columns && !T.has_columns, x = E ? f.add_entity_tag(c) : f.add_entity(c);
541
- E || f.copy_shared_from(T, O, x);
542
- const A = E ? T.remove_entity_tag(O) : T.remove_entity(O);
543
- A !== -1 && (r[A] = O), n[l] = v, r[l] = x;
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);
741
+ else {
742
+ const O = T.get_edge(g);
743
+ w.move_entity_from(T, S, h, O.remove_map);
744
+ }
745
+ f[1] !== y && (r[f[1]] = S), n[a] = p, r[a] = f[0];
544
746
  }
545
747
  t.length = 0, e.length = 0;
546
748
  }
@@ -551,17 +753,15 @@ class J {
551
753
  // Component registration
552
754
  // =======================================================
553
755
  register_component(t) {
554
- const e = z(this.component_count++), s = t, n = /* @__PURE__ */ Object.create(null);
555
- for (let r = 0; r < s.length; r++)
556
- n[s[r]] = r;
557
- return this.component_metas.push({ field_names: s, field_index: n }), e;
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;
558
760
  }
559
761
  add_component(t, e, s) {
560
- if (!this.is_alive(t)) {
561
- if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
762
+ if (!this.is_alive(t))
562
763
  return;
563
- }
564
- const n = y(t), r = this.entity_archetype[n], i = this.arch_get(r);
764
+ const n = m(t), r = this.entity_archetype[n], i = this.arch_get(r);
565
765
  if (i.has_component(e)) {
566
766
  i.write_fields(
567
767
  this.entity_row[n],
@@ -573,25 +773,24 @@ class J {
573
773
  const _ = this.arch_resolve_add(
574
774
  r,
575
775
  e
576
- ), h = this.arch_get(_), o = this.entity_row[n], c = h.add_entity(t);
577
- if (o !== m) {
578
- h.copy_shared_from(i, o, c);
579
- const l = i.remove_entity(o);
580
- l !== -1 && (this.entity_row[l] = o);
581
- }
582
- h.write_fields(
583
- c,
776
+ ), c = this.arch_get(_), o = this.entity_row[n];
777
+ 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);
781
+ } else
782
+ h = c.has_columns ? c.add_entity(t) : c.add_entity_tag(t);
783
+ c.write_fields(
784
+ h,
584
785
  e,
585
786
  s
586
- ), this.entity_archetype[n] = _, this.entity_row[n] = c;
787
+ ), this.entity_archetype[n] = _, this.entity_row[n] = h;
587
788
  }
588
789
  /** Add multiple components in one transition (resolves final archetype, then moves once). */
589
790
  add_components(t, e) {
590
- if (!this.is_alive(t)) {
591
- if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
791
+ if (!this.is_alive(t))
592
792
  return;
593
- }
594
- const s = y(t), n = this.entity_archetype[s];
793
+ const s = m(t), n = this.entity_archetype[s];
595
794
  let r = n;
596
795
  for (let i = 0; i < e.length; i++)
597
796
  r = this.arch_resolve_add(
@@ -599,83 +798,107 @@ class J {
599
798
  e[i].def
600
799
  );
601
800
  if (r !== n) {
602
- const i = this.arch_get(n), _ = this.arch_get(r), h = this.entity_row[s], o = _.add_entity(t);
603
- if (h !== m) {
604
- _.copy_shared_from(i, h, o);
605
- const c = i.remove_entity(h);
606
- c !== -1 && (this.entity_row[c] = h);
607
- }
608
- for (let c = 0; c < e.length; c++)
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);
806
+ } else
807
+ o = _.add_entity(t);
808
+ for (let h = 0; h < e.length; h++)
609
809
  _.write_fields(
610
810
  o,
611
- e[c].def,
612
- e[c].values ?? V
811
+ e[h].def,
812
+ e[h].values ?? D
613
813
  );
614
814
  this.entity_archetype[s] = r, this.entity_row[s] = o;
615
815
  } else {
616
816
  const i = this.arch_get(n), _ = this.entity_row[s];
617
- for (let h = 0; h < e.length; h++)
817
+ for (let c = 0; c < e.length; c++)
618
818
  i.write_fields(
619
819
  _,
620
- e[h].def,
621
- e[h].values ?? V
820
+ e[c].def,
821
+ e[c].values ?? D
622
822
  );
623
823
  }
624
824
  }
625
825
  remove_component(t, e) {
626
- if (!this.is_alive(t)) {
627
- if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
826
+ if (!this.is_alive(t))
628
827
  return;
629
- }
630
- const s = y(t), n = this.entity_archetype[s], r = this.arch_get(n);
828
+ const s = m(t), n = this.entity_archetype[s], r = this.arch_get(n);
631
829
  if (!r.has_component(e)) return;
632
830
  const i = this.arch_resolve_remove(
633
831
  n,
634
832
  e
635
- ), _ = this.arch_get(i), h = this.entity_row[s], o = _.add_entity(t);
636
- _.copy_shared_from(r, h, o);
637
- const c = r.remove_entity(h);
638
- c !== -1 && (this.entity_row[c] = h), this.entity_archetype[s] = i, this.entity_row[s] = o;
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];
639
835
  }
640
836
  /** Remove multiple components in one transition (resolves final archetype, then moves once). */
641
837
  remove_components(t, e) {
642
- if (!this.is_alive(t)) {
643
- if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
838
+ if (!this.is_alive(t))
644
839
  return;
645
- }
646
- const s = y(t), n = this.entity_archetype[s];
840
+ const s = m(t), n = this.entity_archetype[s];
647
841
  let r = n;
648
- for (let l = 0; l < e.length; l++)
842
+ for (let h = 0; h < e.length; h++)
649
843
  r = this.arch_resolve_remove(
650
844
  r,
651
- e[l]
845
+ e[h]
652
846
  );
653
847
  if (r === n) return;
654
- const i = this.arch_get(n), _ = this.arch_get(r), h = this.entity_row[s], o = _.add_entity(t);
655
- _.copy_shared_from(i, h, o);
656
- const c = i.remove_entity(h);
657
- c !== -1 && (this.entity_row[c] = h), this.entity_archetype[s] = r, this.entity_row[s] = o;
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];
658
850
  }
659
851
  has_component(t, e) {
660
- if (!this.is_alive(t)) {
661
- if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
852
+ if (!this.is_alive(t))
662
853
  return !1;
663
- }
664
- const s = y(t);
854
+ const s = m(t);
665
855
  return this.arch_get(
666
856
  this.entity_archetype[s]
667
857
  ).has_component(e);
668
858
  }
859
+ /**
860
+ * Bulk add a component to ALL entities in the given archetype.
861
+ * Uses TypedArray.set() for O(columns) instead of O(N×columns).
862
+ * The archetype must not already contain this component.
863
+ */
864
+ batch_add_component(t, e, s) {
865
+ if (t.length === 0) return;
866
+ const n = e;
867
+ 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;
872
+ }
873
+ 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);
876
+ }
877
+ /**
878
+ * Bulk remove a component from ALL entities in the given archetype.
879
+ * Uses TypedArray.set() for O(columns) instead of O(N×columns).
880
+ * The archetype must contain this component.
881
+ */
882
+ batch_remove_component(t, e) {
883
+ if (t.length === 0) return;
884
+ const s = e;
885
+ 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;
890
+ }
891
+ }
669
892
  // =======================================================
670
893
  // Direct data access (used by SystemContext)
671
894
  // =======================================================
672
895
  get_entity_archetype(t) {
673
896
  return this.arch_get(
674
- this.entity_archetype[y(t)]
897
+ this.entity_archetype[m(t)]
675
898
  );
676
899
  }
677
900
  get_entity_row(t) {
678
- return this.entity_row[y(t)];
901
+ return this.entity_row[m(t)];
679
902
  }
680
903
  // =======================================================
681
904
  // Query support
@@ -699,28 +922,28 @@ class J {
699
922
  );
700
923
  let i, _ = !1;
701
924
  for (let o = 0; o < n.length; o++) {
702
- let c = n[o];
703
- if (c === 0) continue;
704
- const l = o << 5;
705
- for (; c !== 0; ) {
706
- const p = c & -c >>> 0, g = l + (31 - Math.clz32(p));
707
- c ^= p;
708
- const w = this.component_index.get(g);
709
- if (!w || w.size === 0) {
925
+ let h = n[o];
926
+ if (h === 0) continue;
927
+ const a = o << k;
928
+ 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);
932
+ if (!g || g.size === 0) {
710
933
  _ = !0;
711
934
  break;
712
935
  }
713
- (!i || w.size < i.size) && (i = w);
936
+ (!i || g.size < i.size) && (i = g);
714
937
  }
715
938
  if (_) break;
716
939
  }
717
940
  if (_ || !i) return [];
718
- const h = [];
941
+ const c = [];
719
942
  for (const o of i) {
720
- const c = this.arch_get(o);
721
- c.matches(t) && (!e || !c.mask.overlaps(e)) && (!s || c.mask.overlaps(s)) && h.push(c);
943
+ const h = this.arch_get(o);
944
+ h.matches(t) && (!e || !h.mask.overlaps(e)) && (!s || h.mask.overlaps(s)) && c.push(h);
722
945
  }
723
- return h;
946
+ return c;
724
947
  }
725
948
  /**
726
949
  * Register a live query. Returns a mutable Archetype[] that this Store will
@@ -746,7 +969,7 @@ class J {
746
969
  // Event channels
747
970
  // =======================================================
748
971
  register_event(t) {
749
- const e = W(this.event_count++), s = new B(t);
972
+ const e = pt(this.event_count++), s = new wt(t);
750
973
  return this.event_channels.push(s), e;
751
974
  }
752
975
  emit_event(t, e) {
@@ -763,40 +986,47 @@ class J {
763
986
  for (let e = 0; e < t.length; e++)
764
987
  t[e].clear();
765
988
  }
989
+ // =======================================================
990
+ // Resource channels
991
+ // =======================================================
992
+ register_resource(t, e) {
993
+ const s = vt(this.resource_count++), n = new xt(t, e);
994
+ return this.resource_channels.push(n), s;
995
+ }
996
+ get_resource_reader(t) {
997
+ return this.resource_channels[t].reader;
998
+ }
999
+ get_resource_channel(t) {
1000
+ return this.resource_channels[t];
1001
+ }
766
1002
  }
767
- var Z = /* @__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))(Z || {});
768
- const M = [
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 = [
769
1005
  "PRE_STARTUP",
770
1006
  "STARTUP",
771
1007
  "POST_STARTUP"
772
1008
  /* POST_STARTUP */
773
- ], L = [
1009
+ ], G = [
774
1010
  "PRE_UPDATE",
775
1011
  "UPDATE",
776
1012
  "POST_UPDATE"
777
1013
  /* POST_UPDATE */
778
1014
  ];
779
- class H {
1015
+ class kt {
780
1016
  label_systems = /* @__PURE__ */ new Map();
781
1017
  sorted_cache = /* @__PURE__ */ new Map();
782
1018
  system_index = /* @__PURE__ */ new Map();
783
1019
  next_insertion_order = 0;
784
1020
  constructor() {
785
- for (let t = 0; t < M.length; t++)
786
- this.label_systems.set(M[t], []);
1021
+ for (let t = 0; t < q.length; t++)
1022
+ this.label_systems.set(q[t], []);
787
1023
  this.label_systems.set("FIXED_UPDATE", []);
788
- for (let t = 0; t < L.length; t++)
789
- this.label_systems.set(L[t], []);
1024
+ for (let t = 0; t < G.length; t++)
1025
+ this.label_systems.set(G[t], []);
790
1026
  }
791
1027
  add_systems(t, ...e) {
792
1028
  for (const s of e) {
793
- const n = "system" in s ? s.system : s, r = "system" in s ? s.ordering : void 0;
794
- if (process.env.NODE_ENV !== "production" && this.system_index.has(n))
795
- throw new u(
796
- d.DUPLICATE_SYSTEM,
797
- `System ${n.id} is already scheduled`
798
- );
799
- const i = {
1029
+ const n = "system" in s ? s.system : s, r = "system" in s ? s.ordering : void 0, i = {
800
1030
  descriptor: n,
801
1031
  insertion_order: this.next_insertion_order++,
802
1032
  before: new Set(r?.before ?? []),
@@ -818,11 +1048,11 @@ class H {
818
1048
  this.system_index.delete(t), this.sorted_cache.delete(e);
819
1049
  }
820
1050
  run_startup(t) {
821
- for (const e of M)
822
- this.run_label(e, t, 0);
1051
+ for (const e of q)
1052
+ this.run_label(e, t, it);
823
1053
  }
824
1054
  run_update(t, e) {
825
- for (const s of L)
1055
+ for (const s of G)
826
1056
  this.run_label(s, t, e);
827
1057
  }
828
1058
  run_fixed_update(t, e) {
@@ -871,51 +1101,72 @@ class H {
871
1101
  for (const o of t)
872
1102
  s.set(o.descriptor, /* @__PURE__ */ new Set()), n.set(o.descriptor, 0), r.set(o.descriptor, o.insertion_order), i.add(o.descriptor);
873
1103
  for (const o of t) {
874
- for (const c of o.before)
875
- i.has(c) && (s.get(o.descriptor).add(c), n.set(c, n.get(c) + 1));
876
- for (const c of o.after)
877
- i.has(c) && (s.get(c).add(o.descriptor), n.set(o.descriptor, n.get(o.descriptor) + 1));
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));
878
1108
  }
879
1109
  let _ = [];
880
1110
  for (const o of t)
881
1111
  n.get(o.descriptor) === 0 && _.push(o.descriptor);
882
- _.sort((o, c) => r.get(c) - r.get(o));
883
- const h = [];
1112
+ _.sort((o, h) => r.get(h) - r.get(o));
1113
+ const c = [];
884
1114
  for (; _.length > 0; ) {
885
1115
  const o = _.pop();
886
- h.push(o);
887
- for (const c of s.get(o)) {
888
- const l = n.get(c) - 1;
889
- n.set(c, l), l === 0 && _.push(c);
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);
890
1120
  }
891
- _.sort((c, l) => r.get(l) - r.get(c));
1121
+ _.sort((h, a) => r.get(a) - r.get(h));
892
1122
  }
893
- if (h.length !== t.length) {
894
- const o = new Set(h), c = t.filter((l) => !o.has(l.descriptor)).map((l) => `system_${l.descriptor.id}`);
895
- throw new u(
896
- d.CIRCULAR_SYSTEM_DEPENDENCY,
897
- `Circular system dependency detected in ${e}: [${c.join(", ")}]`
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(", ")}]`
898
1128
  );
899
1129
  }
900
- return h;
1130
+ return c;
901
1131
  }
902
1132
  }
903
- const tt = Object.freeze(/* @__PURE__ */ Object.create(null));
904
- class et {
1133
+ const W = /* @__PURE__ */ new WeakMap();
1134
+ function It(l, t) {
1135
+ let e = W.get(l);
1136
+ if (!e) {
1137
+ 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], {
1142
+ get() {
1143
+ return this._columns[_][this._row];
1144
+ },
1145
+ set(c) {
1146
+ this._columns[_][this._row] = c;
1147
+ },
1148
+ enumerable: !0,
1149
+ configurable: !1
1150
+ });
1151
+ }
1152
+ W.set(l, e);
1153
+ }
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;
1156
+ return s._columns = n, s._row = t, s;
1157
+ }
1158
+ class Pt {
905
1159
  _archetypes;
906
1160
  _defs;
907
1161
  _resolver;
908
1162
  _include;
909
1163
  _exclude;
910
1164
  _any_of;
911
- // Pre-allocated args buffer for each() — avoids allocating a new array per
912
- // archetype. Holds [columnGroup0, columnGroup1, ..., entityCount].
913
- _args_buf;
914
1165
  constructor(t, e, s, n, r, i) {
915
- this._archetypes = t, this._defs = e, this._resolver = s, this._include = n, this._exclude = r, this._any_of = i, this._args_buf = new Array(e.length + 1);
1166
+ this._archetypes = t, this._defs = e, this._resolver = s, this._include = n, this._exclude = r, this._any_of = i;
916
1167
  }
917
1168
  /** Number of matching archetypes (including empty ones). */
918
- get length() {
1169
+ get archetype_count() {
919
1170
  return this._archetypes.length;
920
1171
  }
921
1172
  /** Total entity count across all matching archetypes. */
@@ -934,22 +1185,6 @@ class et {
934
1185
  for (let e = 0; e < t.length; e++)
935
1186
  t[e].entity_count > 0 && (yield t[e]);
936
1187
  }
937
- /**
938
- * Typed per-archetype iteration. Calls fn once per non-empty archetype
939
- * with column groups for each queried component, plus the entity count.
940
- * The system is responsible for the inner loop over entities.
941
- */
942
- each(t) {
943
- const e = this._archetypes, s = this._defs, n = this._args_buf;
944
- for (let r = 0; r < e.length; r++) {
945
- const i = e[r], _ = i.entity_count;
946
- if (_ !== 0) {
947
- for (let h = 0; h < s.length; h++)
948
- n[h] = i.get_column_group(s[h]);
949
- n[s.length] = _, t.apply(null, n);
950
- }
951
- }
952
- }
953
1188
  /** Extend required component set. Returns a new (cached) Query. */
954
1189
  and(...t) {
955
1190
  const e = this._include.copy(), s = this._defs.slice();
@@ -964,7 +1199,7 @@ class et {
964
1199
  }
965
1200
  /** Exclude archetypes that have any of these components. */
966
1201
  not(...t) {
967
- const e = this._exclude ? this._exclude.copy() : new N();
1202
+ const e = this._exclude ? this._exclude.copy() : new x();
968
1203
  for (let s = 0; s < t.length; s++) e.set(t[s]);
969
1204
  return this._resolver._resolve_query(
970
1205
  this._include,
@@ -974,8 +1209,8 @@ class et {
974
1209
  );
975
1210
  }
976
1211
  /** Require at least one of these components. */
977
- or(...t) {
978
- const e = this._any_of ? this._any_of.copy() : new N();
1212
+ any_of(...t) {
1213
+ const e = this._any_of ? this._any_of.copy() : new x();
979
1214
  for (let s = 0; s < t.length; s++) e.set(t[s]);
980
1215
  return this._resolver._resolve_query(
981
1216
  this._include,
@@ -985,17 +1220,17 @@ class et {
985
1220
  );
986
1221
  }
987
1222
  }
988
- class st {
1223
+ class St {
989
1224
  constructor(t) {
990
1225
  this._resolver = t;
991
1226
  }
992
1227
  every(...t) {
993
- const e = new N();
1228
+ const e = new x();
994
1229
  for (let s = 0; s < t.length; s++) e.set(t[s]);
995
1230
  return this._resolver._resolve_query(e, null, null, t);
996
1231
  }
997
1232
  }
998
- class nt {
1233
+ class Ot {
999
1234
  store;
1000
1235
  constructor(t) {
1001
1236
  this.store = t;
@@ -1004,22 +1239,24 @@ class nt {
1004
1239
  return this.store.create_entity();
1005
1240
  }
1006
1241
  get_field(t, e, s) {
1007
- const n = this.store.get_entity_archetype(e), r = this.store.get_entity_row(e);
1008
- return n.read_field(r, t, 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);
1009
1244
  }
1010
1245
  set_field(t, e, s, n) {
1011
- const r = this.store.get_entity_archetype(e), i = this.store.get_entity_row(e), _ = r.get_column(t, s);
1246
+ const r = this.store.get_entity_archetype(t), i = this.store.get_entity_row(t), _ = r.get_column(e, s);
1012
1247
  _[i] = n;
1013
1248
  }
1249
+ /** Create a cached component reference for a single entity. See ref.ts. */
1250
+ ref(t, e) {
1251
+ const s = this.store.get_entity_archetype(e), n = this.store.get_entity_row(e);
1252
+ return It(s.column_groups[t], n);
1253
+ }
1014
1254
  /** Buffer an entity for deferred destruction (applied at phase flush). */
1015
1255
  destroy_entity(t) {
1016
1256
  return this.store.destroy_entity_deferred(t), this;
1017
1257
  }
1018
- flush_destroyed() {
1019
- this.store.flush_destroyed();
1020
- }
1021
1258
  add_component(t, e, s) {
1022
- return this.store.add_component_deferred(t, e, s ?? tt), this;
1259
+ return this.store.add_component_deferred(t, e, s ?? D), this;
1023
1260
  }
1024
1261
  remove_component(t, e) {
1025
1262
  return this.store.remove_component_deferred(t, e), this;
@@ -1034,13 +1271,20 @@ class nt {
1034
1271
  read(t) {
1035
1272
  return this.store.get_event_reader(t);
1036
1273
  }
1274
+ // =======================================================
1275
+ // Resources
1276
+ // =======================================================
1277
+ resource(t) {
1278
+ return this.store.get_resource_reader(t);
1279
+ }
1280
+ set_resource(t, e) {
1281
+ this.store.get_resource_channel(t).write(e);
1282
+ }
1037
1283
  }
1038
- const rt = (a) => b(
1039
- a,
1040
- P,
1041
- "SystemID must be a non-negative integer"
1042
- ), it = Object.freeze(/* @__PURE__ */ Object.create(null));
1043
- class ot {
1284
+ const Dt = (l) => N(
1285
+ l
1286
+ );
1287
+ class Nt {
1044
1288
  store;
1045
1289
  schedule;
1046
1290
  ctx;
@@ -1054,9 +1298,9 @@ class ot {
1054
1298
  // Multiple queries can share the same hash (collision), so each bucket is an array.
1055
1299
  query_cache = /* @__PURE__ */ new Map();
1056
1300
  // Reusable BitSet for building query masks — avoids allocation per query() call
1057
- scratch_mask = new N();
1301
+ scratch_mask = new x();
1058
1302
  constructor(t) {
1059
- this.store = new J(), this.schedule = new H(), this.ctx = new nt(this.store), this._fixed_timestep = t?.fixed_timestep ?? 1 / 60, this._max_fixed_steps = t?.max_fixed_steps ?? 4;
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;
1060
1304
  }
1061
1305
  get fixed_timestep() {
1062
1306
  return this._fixed_timestep;
@@ -1067,11 +1311,17 @@ class ot {
1067
1311
  get fixed_alpha() {
1068
1312
  return this._accumulator / this._fixed_timestep;
1069
1313
  }
1070
- register_component(t) {
1314
+ // Implementation
1315
+ register_component(t, e) {
1316
+ if (Array.isArray(t)) {
1317
+ const s = e ?? "f64", n = /* @__PURE__ */ Object.create(null);
1318
+ for (const r of t) n[r] = s;
1319
+ return this.store.register_component(n);
1320
+ }
1071
1321
  return this.store.register_component(t);
1072
1322
  }
1073
1323
  register_tag() {
1074
- return this.store.register_component([]);
1324
+ return this.store.register_component({});
1075
1325
  }
1076
1326
  register_event(t) {
1077
1327
  return this.store.register_event(t);
@@ -1079,10 +1329,22 @@ class ot {
1079
1329
  register_signal() {
1080
1330
  return this.store.register_event([]);
1081
1331
  }
1332
+ register_resource(t, e) {
1333
+ return this.store.register_resource(
1334
+ t,
1335
+ e
1336
+ );
1337
+ }
1338
+ resource(t) {
1339
+ return this.store.get_resource_reader(t);
1340
+ }
1341
+ set_resource(t, e) {
1342
+ this.store.get_resource_channel(t).write(e);
1343
+ }
1082
1344
  create_entity() {
1083
1345
  return this.store.create_entity();
1084
1346
  }
1085
- destroy_entity(t) {
1347
+ destroy_entity_deferred(t) {
1086
1348
  this.store.destroy_entity_deferred(t);
1087
1349
  }
1088
1350
  is_alive(t) {
@@ -1092,7 +1354,7 @@ class ot {
1092
1354
  return this.store.entity_count;
1093
1355
  }
1094
1356
  add_component(t, e, s) {
1095
- this.store.add_component(t, e, s ?? it);
1357
+ return this.store.add_component(t, e, s ?? D), this;
1096
1358
  }
1097
1359
  add_components(t, e) {
1098
1360
  this.store.add_components(t, e);
@@ -1106,9 +1368,23 @@ class ot {
1106
1368
  has_component(t, e) {
1107
1369
  return this.store.has_component(t, e);
1108
1370
  }
1371
+ batch_add_component(t, e, s) {
1372
+ this.store.batch_add_component(t, e, s);
1373
+ }
1374
+ /**
1375
+ * Bulk remove a component from ALL entities in the given archetype.
1376
+ * O(columns) via TypedArray.set() instead of O(N×columns).
1377
+ */
1378
+ batch_remove_component(t, e) {
1379
+ this.store.batch_remove_component(t, e);
1380
+ }
1109
1381
  get_field(t, e, s) {
1110
- const n = this.store.get_entity_archetype(e), r = this.store.get_entity_row(e);
1111
- return n.read_field(r, t, 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);
1384
+ }
1385
+ 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;
1112
1388
  }
1113
1389
  emit(t, e) {
1114
1390
  e === void 0 ? this.store.emit_signal(t) : this.store.emit_event(t, e);
@@ -1122,26 +1398,26 @@ class ot {
1122
1398
  }
1123
1399
  /** QueryResolver implementation — creates or retrieves a cached Query. */
1124
1400
  _resolve_query(t, e, s, n) {
1125
- const r = t.hash(), i = e ? e.hash() : 0, _ = s ? s.hash() : 0, h = r ^ Math.imul(i, 2654435769) ^ Math.imul(_, 1367130551) | 0, o = this._find_cached(h, t, e, s);
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);
1126
1402
  if (o !== void 0) return o.query;
1127
- const c = this.store.register_query(
1403
+ const h = this.store.register_query(
1128
1404
  t,
1129
1405
  e ?? void 0,
1130
1406
  s ?? void 0
1131
- ), l = new et(
1132
- c,
1407
+ ), a = new Pt(
1408
+ h,
1133
1409
  n,
1134
1410
  this,
1135
1411
  t.copy(),
1136
1412
  e?.copy() ?? null,
1137
1413
  s?.copy() ?? null
1138
1414
  );
1139
- return F(this.query_cache, h, {
1415
+ return K(this.query_cache, c, {
1140
1416
  include_mask: t.copy(),
1141
1417
  exclude_mask: e?.copy() ?? null,
1142
1418
  any_of_mask: s?.copy() ?? null,
1143
- query: l
1144
- }), l;
1419
+ query: a
1420
+ }), a;
1145
1421
  }
1146
1422
  _find_cached(t, e, s, n) {
1147
1423
  const r = this.query_cache.get(t);
@@ -1152,14 +1428,18 @@ class ot {
1152
1428
  return _;
1153
1429
  }
1154
1430
  }
1431
+ // any: overload implementation must unify bare fn, (fn, query_fn), and SystemConfig
1155
1432
  register_system(t, e) {
1156
1433
  let s;
1157
- if (typeof t == "function") {
1158
- const i = e(new st(this)), _ = this.ctx;
1159
- s = { fn: (h, o) => t(i, _, o) };
1160
- } else
1434
+ if (typeof t == "function")
1435
+ if (e !== void 0) {
1436
+ const i = e(new St(this)), _ = this.ctx, c = t;
1437
+ s = { fn: (o, h) => c(i, _, h) };
1438
+ } else
1439
+ s = { fn: t };
1440
+ else
1161
1441
  s = t;
1162
- const n = rt(this.next_system_id++), r = Object.freeze(
1442
+ const n = Dt(this.next_system_id++), r = Object.freeze(
1163
1443
  Object.assign({ id: n }, s)
1164
1444
  );
1165
1445
  return this.systems.add(r), r;
@@ -1175,17 +1455,17 @@ class ot {
1175
1455
  }
1176
1456
  startup() {
1177
1457
  for (const t of this.systems.values())
1178
- t.on_added?.(this.store);
1458
+ t.on_added?.(this.ctx);
1179
1459
  this.schedule.run_startup(this.ctx);
1180
1460
  }
1181
1461
  update(t) {
1182
- if (this.store.clear_events(), this.schedule.has_fixed_systems()) {
1462
+ if (this.schedule.has_fixed_systems()) {
1183
1463
  this._accumulator += t;
1184
1464
  const e = this._max_fixed_steps * this._fixed_timestep;
1185
1465
  for (this._accumulator > e && (this._accumulator = e); this._accumulator >= this._fixed_timestep; )
1186
1466
  this.schedule.run_fixed_update(this.ctx, this._fixed_timestep), this._accumulator -= this._fixed_timestep;
1187
1467
  }
1188
- this.schedule.run_update(this.ctx, t);
1468
+ this.schedule.run_update(this.ctx, t), this.store.clear_events();
1189
1469
  }
1190
1470
  flush() {
1191
1471
  this.ctx.flush();
@@ -1197,9 +1477,9 @@ class ot {
1197
1477
  }
1198
1478
  }
1199
1479
  export {
1200
- et as Query,
1201
- st as QueryBuilder,
1202
- Z as SCHEDULE,
1203
- nt as SystemContext,
1204
- ot as World
1480
+ Nt as ECS,
1481
+ Pt as Query,
1482
+ St as QueryBuilder,
1483
+ Et as SCHEDULE,
1484
+ Ot as SystemContext
1205
1485
  };