@oasys/oecs 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +208 -14
- package/README.md +198 -145
- package/dist/core/ecs/access_check.d.cts +3 -3
- package/dist/core/ecs/access_check.d.ts +3 -3
- package/dist/core/ecs/archetype.d.cts +103 -43
- package/dist/core/ecs/archetype.d.ts +103 -43
- package/dist/core/ecs/archetype.d.ts.map +1 -1
- package/dist/core/ecs/archetype_graph.d.cts +8 -8
- package/dist/core/ecs/archetype_graph.d.ts +8 -8
- package/dist/core/ecs/archetype_graph.d.ts.map +1 -1
- package/dist/core/ecs/builtin_relations.d.cts +1 -1
- package/dist/core/ecs/builtin_relations.d.ts +1 -1
- package/dist/core/ecs/command_log.d.cts +4 -4
- package/dist/core/ecs/command_log.d.ts +4 -4
- package/dist/core/ecs/command_log.d.ts.map +1 -1
- package/dist/core/ecs/component.d.cts +4 -4
- package/dist/core/ecs/component.d.ts +4 -4
- package/dist/core/ecs/deferred_commands.d.cts +1 -1
- package/dist/core/ecs/deferred_commands.d.ts +1 -1
- package/dist/core/ecs/deferred_commands.d.ts.map +1 -1
- package/dist/core/ecs/ecs.d.cts +85 -43
- package/dist/core/ecs/ecs.d.ts +85 -43
- package/dist/core/ecs/ecs.d.ts.map +1 -1
- package/dist/core/ecs/ecs_memory.d.cts +15 -15
- package/dist/core/ecs/ecs_memory.d.ts +15 -15
- package/dist/core/ecs/ecs_memory.d.ts.map +1 -1
- package/dist/core/ecs/entity_allocator.d.cts +6 -6
- package/dist/core/ecs/entity_allocator.d.ts +6 -6
- package/dist/core/ecs/entity_allocator.d.ts.map +1 -1
- package/dist/core/ecs/event.d.cts +2 -2
- package/dist/core/ecs/event.d.ts +2 -2
- package/dist/core/ecs/event_registry.d.cts +1 -1
- package/dist/core/ecs/event_registry.d.ts +1 -1
- package/dist/core/ecs/event_registry.d.ts.map +1 -1
- package/dist/core/ecs/facades.d.cts +15 -15
- package/dist/core/ecs/facades.d.ts +15 -15
- package/dist/core/ecs/facades.d.ts.map +1 -1
- package/dist/core/ecs/frame_trace.d.cts +2 -2
- package/dist/core/ecs/frame_trace.d.ts +2 -2
- package/dist/core/ecs/host_commands.d.cts +12 -12
- package/dist/core/ecs/host_commands.d.ts +12 -12
- package/dist/core/ecs/host_commands.d.ts.map +1 -1
- package/dist/core/ecs/index.d.cts +1 -1
- package/dist/core/ecs/index.d.ts +1 -1
- package/dist/core/ecs/index.d.ts.map +1 -1
- package/dist/core/ecs/observer.d.cts +9 -9
- package/dist/core/ecs/observer.d.ts +9 -9
- package/dist/core/ecs/observer.d.ts.map +1 -1
- package/dist/core/ecs/query.d.cts +91 -70
- package/dist/core/ecs/query.d.ts +91 -70
- package/dist/core/ecs/query.d.ts.map +1 -1
- package/dist/core/ecs/ref.d.cts +53 -1
- package/dist/core/ecs/ref.d.ts +53 -1
- package/dist/core/ecs/ref.d.ts.map +1 -1
- package/dist/core/ecs/relation.d.cts +15 -15
- package/dist/core/ecs/relation.d.ts +15 -15
- package/dist/core/ecs/relation.d.ts.map +1 -1
- package/dist/core/ecs/relation_service.d.cts +14 -14
- package/dist/core/ecs/relation_service.d.ts +14 -14
- package/dist/core/ecs/relation_service.d.ts.map +1 -1
- package/dist/core/ecs/resource.d.cts +1 -1
- package/dist/core/ecs/resource.d.ts +1 -1
- package/dist/core/ecs/resource_registry.d.cts +2 -2
- package/dist/core/ecs/resource_registry.d.ts +2 -2
- package/dist/core/ecs/resume.d.cts +3 -3
- package/dist/core/ecs/resume.d.ts +3 -3
- package/dist/core/ecs/resume.d.ts.map +1 -1
- package/dist/core/ecs/schedule.d.cts +22 -9
- package/dist/core/ecs/schedule.d.ts +22 -9
- package/dist/core/ecs/schedule.d.ts.map +1 -1
- package/dist/core/ecs/snapshot_service.d.cts +3 -3
- package/dist/core/ecs/snapshot_service.d.ts +3 -3
- package/dist/core/ecs/sparse_store.d.cts +6 -6
- package/dist/core/ecs/sparse_store.d.ts +6 -6
- package/dist/core/ecs/sparse_store.d.ts.map +1 -1
- package/dist/core/ecs/store.d.cts +189 -110
- package/dist/core/ecs/store.d.ts +189 -110
- package/dist/core/ecs/store.d.ts.map +1 -1
- package/dist/core/ecs/store_layout_listener.d.cts +2 -2
- package/dist/core/ecs/store_layout_listener.d.ts +2 -2
- package/dist/core/ecs/system.d.cts +8 -8
- package/dist/core/ecs/system.d.ts +8 -8
- package/dist/core/ecs/system.d.ts.map +1 -1
- package/dist/core/ecs/utils/error.d.cts +7 -0
- package/dist/core/ecs/utils/error.d.ts +7 -0
- package/dist/core/ecs/utils/error.d.ts.map +1 -1
- package/dist/core/store/action_ring.d.cts +7 -8
- package/dist/core/store/action_ring.d.ts +7 -8
- package/dist/core/store/action_ring.d.ts.map +1 -1
- package/dist/core/store/allocator.d.cts +58 -35
- package/dist/core/store/allocator.d.ts +58 -35
- package/dist/core/store/allocator.d.ts.map +1 -1
- package/dist/core/store/buffer_backed_column.d.cts +5 -6
- package/dist/core/store/buffer_backed_column.d.ts +5 -6
- package/dist/core/store/buffer_backed_column.d.ts.map +1 -1
- package/dist/core/store/column_store.d.cts +23 -23
- package/dist/core/store/column_store.d.ts +23 -23
- package/dist/core/store/column_store.d.ts.map +1 -1
- package/dist/core/store/command_dispatch.d.cts +1 -1
- package/dist/core/store/command_dispatch.d.ts +1 -1
- package/dist/core/store/command_ring.d.cts +6 -7
- package/dist/core/store/command_ring.d.ts +6 -7
- package/dist/core/store/command_ring.d.ts.map +1 -1
- package/dist/core/store/descriptor.d.cts +2 -2
- package/dist/core/store/descriptor.d.ts +2 -2
- package/dist/core/store/entity_index.d.cts +3 -3
- package/dist/core/store/entity_index.d.ts +3 -3
- package/dist/core/store/event_ring.d.cts +7 -7
- package/dist/core/store/event_ring.d.ts +7 -7
- package/dist/core/store/extend.d.cts +2 -2
- package/dist/core/store/extend.d.ts +2 -2
- package/dist/core/store/extend.d.ts.map +1 -1
- package/dist/core/store/grow.d.cts +1 -1
- package/dist/core/store/grow.d.ts +1 -1
- package/dist/core/store/grow.d.ts.map +1 -1
- package/dist/core/store/header.d.cts +9 -9
- package/dist/core/store/header.d.ts +9 -9
- package/dist/core/store/header.d.ts.map +1 -1
- package/dist/core/store/layout_ops.d.cts +25 -7
- package/dist/core/store/layout_ops.d.ts +25 -7
- package/dist/core/store/layout_ops.d.ts.map +1 -1
- package/dist/core/store/state_hash.d.cts +3 -3
- package/dist/core/store/state_hash.d.ts +3 -3
- package/dist/extensions/editor/editor.d.cts +4 -4
- package/dist/extensions/editor/editor.d.ts +4 -4
- package/dist/extensions/editor/editor.d.ts.map +1 -1
- package/dist/extensions/editor/field_handle.d.cts +1 -1
- package/dist/extensions/editor/field_handle.d.ts +1 -1
- package/dist/extensions/editor/index.d.cts +2 -2
- package/dist/extensions/editor/index.d.ts +2 -2
- package/dist/extensions/editor/index.development.js +4 -4
- package/dist/extensions/editor/index.js +4 -4
- package/dist/extensions/reactive/ecs_sync.d.cts +4 -4
- package/dist/extensions/reactive/ecs_sync.d.ts +4 -4
- package/dist/extensions/reactive/index.d.cts +4 -4
- package/dist/extensions/reactive/index.d.ts +4 -4
- package/dist/extensions/reactive/index.development.js +3 -3
- package/dist/extensions/reactive/index.js +3 -3
- package/dist/extensions/solid/index.d.cts +1 -1
- package/dist/extensions/solid/index.d.ts +1 -1
- package/dist/extensions/solid/index.development.js +1 -1
- package/dist/extensions/solid/index.js +1 -1
- package/dist/extensions/solid/kernel_solid.d.cts +1 -1
- package/dist/extensions/solid/kernel_solid.d.ts +1 -1
- package/dist/extensions/solid/kernel_solid.d.ts.map +1 -1
- package/dist/{host_commands-BI8pEmjH.js → host_commands-BlR3oZ3x.js} +473 -393
- package/dist/host_commands-C2cpU3yC.cjs +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.development.cjs +1 -1
- package/dist/index.development.js +3345 -2963
- package/dist/index.js +1496 -1131
- package/dist/{internal-BMDgWZbt.js → internal-BoxWl4dG.js} +410 -330
- package/dist/internal-CGBEwfeB.cjs +2 -0
- package/dist/internal.cjs +1 -1
- package/dist/internal.development.cjs +1 -1
- package/dist/internal.development.js +1 -1
- package/dist/internal.js +1 -1
- package/dist/primitives.development.js +1 -1
- package/dist/primitives.js +1 -1
- package/dist/reactive/index.d.cts +2 -2
- package/dist/reactive/index.d.ts +2 -2
- package/dist/reactive/index.development.js +1 -1
- package/dist/reactive/index.js +1 -1
- package/dist/reactive/kernel.d.cts +5 -5
- package/dist/reactive/kernel.d.ts +5 -5
- package/dist/reactive/shallow.d.cts +1 -1
- package/dist/reactive/shallow.d.ts +1 -1
- package/dist/{shallow-DfnAm9vG.js → shallow-Bs39EPh1.js} +1 -1
- package/dist/{shallow-9S1pY_Iw.js → shallow-CiFC70Dz.js} +1 -1
- package/dist/{shared-BU1Cd40h.js → shared-B4v0L1cw.js} +41 -35
- package/dist/shared-DU78k0pU.cjs +1 -0
- package/dist/shared.cjs +1 -1
- package/dist/shared.d.cts +1 -1
- package/dist/shared.d.ts +1 -1
- package/dist/shared.development.cjs +1 -1
- package/dist/shared.development.js +1 -1
- package/dist/shared.js +1 -1
- package/dist/type_primitives/typed_arrays/typed_arrays.d.cts +2 -2
- package/dist/type_primitives/typed_arrays/typed_arrays.d.ts +2 -2
- package/dist/{typed_arrays-BcXcnzB4.js → typed_arrays-DIVwVy5_.js} +1 -1
- package/dist/version.d.cts +2 -2
- package/dist/version.d.ts +2 -2
- package/package.json +1 -1
- package/dist/host_commands-CxhpzMx9.cjs +0 -1
- package/dist/internal-LiTSB_tG.cjs +0 -2
- package/dist/shared-BymrGTyR.cjs +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as st, h as j, w as Ne, g as rt } from "./shared-
|
|
1
|
+
import { D as st, h as j, w as Ne, g as rt } from "./shared-B4v0L1cw.js";
|
|
2
2
|
import { S as ot, t as it } from "./topological_sort-DK6EjpWa.js";
|
|
3
3
|
class Ye extends Error {
|
|
4
4
|
constructor(e, n, r) {
|
|
@@ -29,25 +29,25 @@ function at(t, e) {
|
|
|
29
29
|
`Unhandled ${e}: ${String(t)}`
|
|
30
30
|
);
|
|
31
31
|
}
|
|
32
|
-
var
|
|
33
|
-
class
|
|
32
|
+
var y = /* @__PURE__ */ ((t) => (t.EID_MAX_INDEX_OVERFLOW = "EID_MAX_INDEX_OVERFLOW", t.EID_MAX_GEN_OVERFLOW = "EID_MAX_GEN_OVERFLOW", t.COMPONENT_NOT_REGISTERED = "COMPONENT_NOT_REGISTERED", t.COMPONENT_LIMIT_EXCEEDED = "COMPONENT_LIMIT_EXCEEDED", t.ENTITY_NOT_ALIVE = "ENTITY_NOT_ALIVE", t.CIRCULAR_SYSTEM_DEPENDENCY = "CIRCULAR_SYSTEM_DEPENDENCY", t.DUPLICATE_SYSTEM = "DUPLICATE_SYSTEM", t.ARCHETYPE_NOT_FOUND = "ARCHETYPE_NOT_FOUND", t.RESOURCE_NOT_REGISTERED = "RESOURCE_NOT_REGISTERED", t.RESOURCE_ALREADY_REGISTERED = "RESOURCE_ALREADY_REGISTERED", t.EVENT_ALREADY_REGISTERED = "EVENT_ALREADY_REGISTERED", t.EVENT_NOT_REGISTERED = "EVENT_NOT_REGISTERED", t.FIELD_NOT_REGISTERED = "FIELD_NOT_REGISTERED", t.RELATION_NOT_REGISTERED = "RELATION_NOT_REGISTERED", t.RELATION_MODE_INVALID = "RELATION_MODE_INVALID", t.RELATION_MODE_MISMATCH = "RELATION_MODE_MISMATCH", t.RELATION_CYCLE = "RELATION_CYCLE", t.SPARSE_CACHE_KEY_OVERFLOW = "SPARSE_CACHE_KEY_OVERFLOW", t.SPARSE_QUERY_DENSE_PATH = "SPARSE_QUERY_DENSE_PATH", t.HIERARCHY_ALREADY_SET = "HIERARCHY_ALREADY_SET", t.HIERARCHY_INVALID_MAX_DEPTH = "HIERARCHY_INVALID_MAX_DEPTH", t.OBSERVER_NON_CONVERGENT = "OBSERVER_NON_CONVERGENT", t.OBSERVER_INVALID_CONFIG = "OBSERVER_INVALID_CONFIG", t.OBSERVER_ONSET_EMIT = "OBSERVER_ONSET_EMIT", t.INVALID_FIXED_TIMESTEP = "INVALID_FIXED_TIMESTEP", t.INVALID_MAX_FIXED_STEPS = "INVALID_MAX_FIXED_STEPS", t.INVALID_RECORDER_SCHEDULE = "INVALID_RECORDER_SCHEDULE", t.EMPTY_ARCHETYPE_MATERIALIZE = "EMPTY_ARCHETYPE_MATERIALIZE", t.COMPONENT_INDEX_INVARIANT = "COMPONENT_INDEX_INVARIANT", t.ARCHETYPE_ROW_INVARIANT = "ARCHETYPE_ROW_INVARIANT", t.OPTIONAL_TERM_NOT_DECLARED = "OPTIONAL_TERM_NOT_DECLARED", t.QUERY_ACCESS_UNDECLARED = "QUERY_ACCESS_UNDECLARED", t.ACCESS_UNDECLARED = "ACCESS_UNDECLARED", t.QUERY_NOT_SINGLETON = "QUERY_NOT_SINGLETON", t.INVALID_RUN_CONDITION = "INVALID_RUN_CONDITION", t.SYSTEM_FN_ARITY = "SYSTEM_FN_ARITY", t.PARTITION_APPEND_NEEDS_ENTITY_ROW = "PARTITION_APPEND_NEEDS_ENTITY_ROW", t.PARTITION_BULK_INTO_DISABLED = "PARTITION_BULK_INTO_DISABLED", t.ENTITY_NOT_DISABLED = "ENTITY_NOT_DISABLED", t.STRUCTURAL_DURING_ITERATION = "STRUCTURAL_DURING_ITERATION", t.BACKEND_ALREADY_ATTACHED = "BACKEND_ALREADY_ATTACHED", t.DETERMINISM_DISABLED = "DETERMINISM_DISABLED", t.NON_DETERMINISTIC_COLUMN_TYPE = "NON_DETERMINISTIC_COLUMN_TYPE", t.INVALID_MEMORY_OPTIONS = "INVALID_MEMORY_OPTIONS", t.STORE_CAP_EXCEEDED = "STORE_CAP_EXCEEDED", t.REGION_NOT_DECLARED = "REGION_NOT_DECLARED", t.COMMAND_LOG_TAG_COLLISION = "COMMAND_LOG_TAG_COLLISION", t.INVALID_FRAME_STEP = "INVALID_FRAME_STEP", t))(y || {});
|
|
33
|
+
class T extends Ye {
|
|
34
34
|
constructor(e, n, r) {
|
|
35
35
|
super(n ?? e, !0, r), this.category = e;
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
function
|
|
39
|
-
return t instanceof
|
|
38
|
+
function Cn(t) {
|
|
39
|
+
return t instanceof T;
|
|
40
40
|
}
|
|
41
|
-
const
|
|
41
|
+
const bn = -1, vn = -1, Un = Object.freeze(/* @__PURE__ */ Object.create(null)), Ln = 2654435769, Mn = 1367130551, F = 1024, $n = 0, ct = 31, Pn = 1 / 60, xn = 4, dt = 0, z = 20, He = (1 << z) - 1, $ = He, lt = ct - z, oe = (1 << lt) - 1, Bn = oe, Fn = oe - 1, Re = oe << z | $, kn = (t, e) => {
|
|
42
42
|
{
|
|
43
43
|
if (t < 0 || t > $)
|
|
44
|
-
throw new y
|
|
44
|
+
throw new T(y.EID_MAX_INDEX_OVERFLOW);
|
|
45
45
|
if (e < 0 || e > oe)
|
|
46
|
-
throw new y
|
|
46
|
+
throw new T(y.EID_MAX_GEN_OVERFLOW);
|
|
47
47
|
}
|
|
48
48
|
return e << z | t;
|
|
49
|
-
}, L = (t) => t &
|
|
50
|
-
|
|
49
|
+
}, L = (t) => t & He, De = (t) => t >> z, Yn = (t, e, n) => new T(
|
|
50
|
+
y.ENTITY_NOT_ALIVE,
|
|
51
51
|
`${t}: entity ${e} (index ${L(e)}, generation ${De(
|
|
52
52
|
e
|
|
53
53
|
)}) is not alive${n ? ` — ${n}` : ""} (destroyed, never created, or a stale handle; guard with isAlive() first)`,
|
|
@@ -56,7 +56,7 @@ const Cn = -1, vn = -1, Un = Object.freeze(/* @__PURE__ */ Object.create(null)),
|
|
|
56
56
|
function Vn(t, e) {
|
|
57
57
|
ge.set(t, e);
|
|
58
58
|
}
|
|
59
|
-
function
|
|
59
|
+
function Hn(t) {
|
|
60
60
|
return ge.get(t);
|
|
61
61
|
}
|
|
62
62
|
function ut(t) {
|
|
@@ -98,7 +98,7 @@ const ft = 827148627, ht = 0, ee = 4, _t = 52, m = {
|
|
|
98
98
|
function mt(t, e) {
|
|
99
99
|
t.setUint32(m.magic, e.magic, !0), t.setUint32(m.sim_abi_version, e.simAbiVersion, !0), t.setUint32(m.view_stamp, e.viewStamp, !0), t.setUint32(m.capacity, e.capacity, !0), t.setUint32(m.archetype_count, e.archetypeCount, !0), t.setUint32(m.layout_descriptor_off, e.layoutDescriptorOff, !0), t.setUint32(m.command_ring_off, e.commandRingOff, !0), t.setUint32(m.action_ring_off, e.actionRingOff, !0), t.setUint32(m.entity_index_off, e.entityIndexOff, !0), t.setUint32(m.event_ring_off, e.eventRingOff, !0), t.setUint32(m.region_table_off, e.regionTableOff, !0), t.setUint32(m.region_table_count, e.regionTableCount, !0), t.setUint32(m.bindings_off, e.bindingsOff, !0);
|
|
100
100
|
}
|
|
101
|
-
function
|
|
101
|
+
function Gn(t) {
|
|
102
102
|
return {
|
|
103
103
|
magic: t.getUint32(m.magic, !0),
|
|
104
104
|
simAbiVersion: t.getUint32(m.sim_abi_version, !0),
|
|
@@ -133,7 +133,7 @@ const E = {
|
|
|
133
133
|
[E.i32]: 4,
|
|
134
134
|
[E.f32]: 4,
|
|
135
135
|
[E.f64]: 8
|
|
136
|
-
}),
|
|
136
|
+
}), Wn = {
|
|
137
137
|
u8: E.u8,
|
|
138
138
|
i8: E.i8,
|
|
139
139
|
u16: E.u16,
|
|
@@ -155,8 +155,8 @@ function Et(t, e) {
|
|
|
155
155
|
stride: t.getUint16(e + O.stride, !0)
|
|
156
156
|
};
|
|
157
157
|
}
|
|
158
|
-
const
|
|
159
|
-
function
|
|
158
|
+
const Xn = ee * 32;
|
|
159
|
+
function Ge(t) {
|
|
160
160
|
return pe + t * Ee;
|
|
161
161
|
}
|
|
162
162
|
function pt(t, e, n) {
|
|
@@ -204,24 +204,24 @@ function zn(t, e, n) {
|
|
|
204
204
|
let s = e;
|
|
205
205
|
for (let o = 0; o < n; o++) {
|
|
206
206
|
const i = yt(t, s);
|
|
207
|
-
r[o] = i, s +=
|
|
207
|
+
r[o] = i, s += Ge(i.columns.length);
|
|
208
208
|
}
|
|
209
209
|
return r;
|
|
210
210
|
}
|
|
211
211
|
function At(t) {
|
|
212
212
|
let e = 0;
|
|
213
213
|
for (let n = 0; n < t.length; n++)
|
|
214
|
-
e +=
|
|
214
|
+
e += Ge(t[n].columns.length);
|
|
215
215
|
return e;
|
|
216
216
|
}
|
|
217
|
-
const
|
|
217
|
+
const We = 16, P = 16, qn = 256, C = {
|
|
218
218
|
write_head: 0,
|
|
219
219
|
read_head: 4,
|
|
220
220
|
capacity_slots: 8,
|
|
221
221
|
overflow_flag: 12
|
|
222
222
|
}, ye = 0;
|
|
223
|
-
function
|
|
224
|
-
return
|
|
223
|
+
function Ce(t) {
|
|
224
|
+
return We + t * P;
|
|
225
225
|
}
|
|
226
226
|
function It(t) {
|
|
227
227
|
return t > 0 && (t & t - 1) === 0;
|
|
@@ -236,26 +236,26 @@ function wt(t, e, n) {
|
|
|
236
236
|
throw new v(
|
|
237
237
|
`command ring capacity_slots must be a positive power of two (got ${n})`
|
|
238
238
|
);
|
|
239
|
-
t.setUint32(e +
|
|
239
|
+
t.setUint32(e + C.write_head, 0, !0), t.setUint32(e + C.read_head, 0, !0), t.setUint32(e + C.capacity_slots, n, !0), t.setUint32(e + C.overflow_flag, 0, !0);
|
|
240
240
|
}
|
|
241
241
|
function St(t, e) {
|
|
242
|
-
return t.getUint32(e +
|
|
242
|
+
return t.getUint32(e + C.write_head, !0);
|
|
243
243
|
}
|
|
244
244
|
function Nt(t, e) {
|
|
245
|
-
return t.getUint32(e +
|
|
245
|
+
return t.getUint32(e + C.read_head, !0);
|
|
246
246
|
}
|
|
247
247
|
function Rt(t, e) {
|
|
248
|
-
return t.getUint32(e +
|
|
248
|
+
return t.getUint32(e + C.capacity_slots, !0);
|
|
249
249
|
}
|
|
250
250
|
function Dt(t, e, n) {
|
|
251
251
|
if (n.byteLength !== P - 1)
|
|
252
252
|
throw new v(
|
|
253
|
-
`
|
|
253
|
+
`outPayload must be ${P - 1} bytes (got ${n.byteLength})`
|
|
254
254
|
);
|
|
255
255
|
const r = St(t, e), s = Nt(t, e);
|
|
256
256
|
if (r === s) return ye;
|
|
257
|
-
const o = Rt(t, e), i = s & o - 1, a = e +
|
|
258
|
-
return n.set(
|
|
257
|
+
const o = Rt(t, e), i = s & o - 1, a = e + We + i * P, c = t.getUint8(a), d = new Uint8Array(t.buffer, a + 1, P - 1);
|
|
258
|
+
return n.set(d), t.setUint32(e + C.read_head, s + 1 >>> 0, !0), c;
|
|
259
259
|
}
|
|
260
260
|
function Ot(t, e, n) {
|
|
261
261
|
let r = 0;
|
|
@@ -271,38 +271,38 @@ const ie = 16, R = 12, te = {
|
|
|
271
271
|
capacity: 4
|
|
272
272
|
// 8..16: pad to 16-byte alignment so the i32 arrays start aligned.
|
|
273
273
|
}, U = 1 << 20;
|
|
274
|
-
function
|
|
274
|
+
function be(t) {
|
|
275
275
|
if (t < 0 || !Number.isInteger(t))
|
|
276
|
-
throw new
|
|
277
|
-
`
|
|
276
|
+
throw new Xe(
|
|
277
|
+
`entity index capacity must be a non-negative integer (got ${t})`
|
|
278
278
|
);
|
|
279
279
|
return ie + t * R;
|
|
280
280
|
}
|
|
281
|
-
function
|
|
281
|
+
function Ct(t) {
|
|
282
282
|
return t + ie;
|
|
283
283
|
}
|
|
284
|
-
function
|
|
284
|
+
function bt(t, e) {
|
|
285
285
|
return t + ie + e * 4;
|
|
286
286
|
}
|
|
287
287
|
function vt(t, e) {
|
|
288
288
|
return t + ie + e * 8;
|
|
289
289
|
}
|
|
290
|
-
class
|
|
290
|
+
class Xe extends Error {
|
|
291
291
|
constructor(e) {
|
|
292
292
|
super(e), this.name = "EntityIndexError";
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
function Ut(t, e, n) {
|
|
296
296
|
if (n < 0 || !Number.isInteger(n))
|
|
297
|
-
throw new
|
|
298
|
-
`
|
|
297
|
+
throw new Xe(
|
|
298
|
+
`entity index capacity must be a non-negative integer (got ${n})`
|
|
299
299
|
);
|
|
300
300
|
t.setUint32(e + te.length, 0, !0), t.setUint32(e + te.capacity, n, !0);
|
|
301
301
|
}
|
|
302
302
|
function jn(t, e, n) {
|
|
303
303
|
return {
|
|
304
|
-
generations: new Int32Array(t,
|
|
305
|
-
archetypes: new Int32Array(t,
|
|
304
|
+
generations: new Int32Array(t, Ct(e), n),
|
|
305
|
+
archetypes: new Int32Array(t, bt(e, n), n),
|
|
306
306
|
rows: new Int32Array(t, vt(e, n), n)
|
|
307
307
|
};
|
|
308
308
|
}
|
|
@@ -335,14 +335,14 @@ const Bt = 16, Ft = 16, Qn = 256, V = {
|
|
|
335
335
|
read_head: 4,
|
|
336
336
|
capacity_slots: 8,
|
|
337
337
|
overflow_flag: 12
|
|
338
|
-
}, kt = V.write_head / 4, Yt = V.read_head / 4, Vt = V.capacity_slots / 4,
|
|
339
|
-
function
|
|
338
|
+
}, kt = V.write_head / 4, Yt = V.read_head / 4, Vt = V.capacity_slots / 4, Ht = V.overflow_flag / 4;
|
|
339
|
+
function Gt(t, e) {
|
|
340
340
|
return new Int32Array(t.buffer, t.byteOffset + e, 4);
|
|
341
341
|
}
|
|
342
342
|
function Ue(t) {
|
|
343
343
|
return Bt + t * Ft;
|
|
344
344
|
}
|
|
345
|
-
function
|
|
345
|
+
function Wt(t) {
|
|
346
346
|
return t > 0 && (t & t - 1) === 0;
|
|
347
347
|
}
|
|
348
348
|
class Le extends Error {
|
|
@@ -350,28 +350,28 @@ class Le extends Error {
|
|
|
350
350
|
super(e), this.name = "ActionRingError";
|
|
351
351
|
}
|
|
352
352
|
}
|
|
353
|
-
function
|
|
354
|
-
if (!
|
|
353
|
+
function Xt(t, e, n) {
|
|
354
|
+
if (!Wt(n))
|
|
355
355
|
throw new Le(
|
|
356
356
|
`action ring capacity_slots must be a positive power of two (got ${n})`
|
|
357
357
|
);
|
|
358
358
|
if ((t.byteOffset + e) % 4 !== 0)
|
|
359
359
|
throw new Le(
|
|
360
|
-
`action ring header must be 4-byte aligned for Atomics (view.byteOffset ${t.byteOffset} +
|
|
360
|
+
`action ring header must be 4-byte aligned for Atomics (view.byteOffset ${t.byteOffset} + ringOff ${e} is not a multiple of 4)`
|
|
361
361
|
);
|
|
362
|
-
const r =
|
|
363
|
-
Atomics.store(r, kt, 0), Atomics.store(r, Yt, 0), Atomics.store(r, Vt, n), Atomics.store(r,
|
|
362
|
+
const r = Gt(t, e);
|
|
363
|
+
Atomics.store(r, kt, 0), Atomics.store(r, Yt, 0), Atomics.store(r, Vt, n), Atomics.store(r, Ht, 0);
|
|
364
364
|
}
|
|
365
365
|
const K = [
|
|
366
366
|
{
|
|
367
367
|
name: "command_ring",
|
|
368
368
|
headerOff: "command_ring_off",
|
|
369
|
-
sizeFromOptions: (t) => t.commandRingCapacitySlots !== void 0 ?
|
|
369
|
+
sizeFromOptions: (t) => t.commandRingCapacitySlots !== void 0 ? Ce(t.commandRingCapacitySlots) : 0,
|
|
370
370
|
init: (t, e, n) => wt(t, e, n.commandRingCapacitySlots),
|
|
371
|
-
regionBytes: (t, e) =>
|
|
371
|
+
regionBytes: (t, e) => Ce(t.getUint32(e + C.capacity_slots, !0)),
|
|
372
372
|
readOptions: (t, e, n) => {
|
|
373
373
|
n.commandRingCapacitySlots = t.getUint32(
|
|
374
|
-
e +
|
|
374
|
+
e + C.capacity_slots,
|
|
375
375
|
!0
|
|
376
376
|
);
|
|
377
377
|
}
|
|
@@ -379,9 +379,9 @@ const K = [
|
|
|
379
379
|
{
|
|
380
380
|
name: "entity_index",
|
|
381
381
|
headerOff: "entity_index_off",
|
|
382
|
-
sizeFromOptions: (t) => t.entityIndexCapacity !== void 0 ?
|
|
382
|
+
sizeFromOptions: (t) => t.entityIndexCapacity !== void 0 ? be(t.entityIndexCapacity) : 0,
|
|
383
383
|
init: (t, e, n) => Ut(t, e, n.entityIndexCapacity),
|
|
384
|
-
regionBytes: (t, e) =>
|
|
384
|
+
regionBytes: (t, e) => be(t.getUint32(e + te.capacity, !0)),
|
|
385
385
|
readOptions: (t, e, n) => {
|
|
386
386
|
n.entityIndexCapacity = t.getUint32(e + te.capacity, !0);
|
|
387
387
|
}
|
|
@@ -403,7 +403,7 @@ const K = [
|
|
|
403
403
|
name: "action_ring",
|
|
404
404
|
headerOff: "action_ring_off",
|
|
405
405
|
sizeFromOptions: (t) => t.actionRingCapacitySlots !== void 0 ? Ue(t.actionRingCapacitySlots) : 0,
|
|
406
|
-
init: (t, e, n) =>
|
|
406
|
+
init: (t, e, n) => Xt(t, e, n.actionRingCapacitySlots),
|
|
407
407
|
regionBytes: (t, e) => Ue(t.getUint32(e + V.capacity_slots, !0)),
|
|
408
408
|
readOptions: (t, e, n) => {
|
|
409
409
|
n.actionRingCapacitySlots = t.getUint32(
|
|
@@ -501,7 +501,7 @@ const Ae = 2 ** 31;
|
|
|
501
501
|
class je extends Error {
|
|
502
502
|
constructor(e) {
|
|
503
503
|
super(
|
|
504
|
-
`SAB column layout offset ${e} reaches or exceeds the 2³¹ (${Ae}-byte) ceiling. Past 2 GiB the signed-32-bit bitwise alignment math wraps to negative/misaligned offsets. This is a structural limit independent of the (default 256 MiB) allocator cap — a single SAB cannot back more than ~2 GiB of column data
|
|
504
|
+
`SAB column layout offset ${e} reaches or exceeds the 2³¹ (${Ae}-byte) ceiling. Past 2 GiB the signed-32-bit bitwise alignment math wraps to negative/misaligned offsets. This is a structural limit independent of the (default 256 MiB) allocator cap — a single SAB cannot back more than ~2 GiB of column data.`
|
|
505
505
|
), this.name = "StoreLayoutOverflowError";
|
|
506
506
|
}
|
|
507
507
|
}
|
|
@@ -550,10 +550,10 @@ function Jt(t, e, n = 0) {
|
|
|
550
550
|
let o = e + s;
|
|
551
551
|
const i = new Array(t.length);
|
|
552
552
|
for (let a = 0; a < t.length; a++) {
|
|
553
|
-
const c = t[a],
|
|
554
|
-
for (let
|
|
555
|
-
const f = c.columns[
|
|
556
|
-
o = Ke(o, h), l
|
|
553
|
+
const c = t[a], d = new Array(c.columns.length);
|
|
554
|
+
for (let l = 0; l < c.columns.length; l++) {
|
|
555
|
+
const f = c.columns[l], h = Oe[f.typeTag];
|
|
556
|
+
o = Ke(o, h), d[l] = {
|
|
557
557
|
componentId: f.componentId,
|
|
558
558
|
fieldId: f.fieldId,
|
|
559
559
|
typeTag: f.typeTag,
|
|
@@ -567,7 +567,7 @@ function Jt(t, e, n = 0) {
|
|
|
567
567
|
rowCount: 0,
|
|
568
568
|
enabledCount: 0,
|
|
569
569
|
rowCapacity: c.rowCapacity,
|
|
570
|
-
columns:
|
|
570
|
+
columns: d
|
|
571
571
|
};
|
|
572
572
|
}
|
|
573
573
|
if (o > Ae)
|
|
@@ -582,8 +582,8 @@ function ns(t, e = st, n = {}) {
|
|
|
582
582
|
const r = {};
|
|
583
583
|
let s = _t;
|
|
584
584
|
for (let w = 0; w < K.length; w++) {
|
|
585
|
-
const
|
|
586
|
-
r[
|
|
585
|
+
const b = K[w], G = b.sizeFromOptions(n);
|
|
586
|
+
r[b.headerOff] = G === 0 ? 0 : s, s += G;
|
|
587
587
|
}
|
|
588
588
|
const o = n.regions ?? [];
|
|
589
589
|
zt(o);
|
|
@@ -591,12 +591,12 @@ function ns(t, e = st, n = {}) {
|
|
|
591
591
|
s += ze(i);
|
|
592
592
|
const c = new Array(i);
|
|
593
593
|
for (let w = 0; w < o.length; w++) {
|
|
594
|
-
const
|
|
595
|
-
c[w] = { regionId:
|
|
594
|
+
const b = o[w];
|
|
595
|
+
c[w] = { regionId: b.id, byteOffset: s, byteLength: b.bytes }, s += b.bytes;
|
|
596
596
|
}
|
|
597
|
-
const
|
|
598
|
-
s +=
|
|
599
|
-
const f = s, { descriptors: h, totalBytes: g, regionBytes:
|
|
597
|
+
const d = n.bindingsRegionBytes ?? 0, l = d === 0 ? 0 : s;
|
|
598
|
+
s += d;
|
|
599
|
+
const f = s, { descriptors: h, totalBytes: g, regionBytes: p } = Jt(
|
|
600
600
|
t,
|
|
601
601
|
f,
|
|
602
602
|
n.reservedDescriptorBytes ?? 0
|
|
@@ -607,7 +607,7 @@ function ns(t, e = st, n = {}) {
|
|
|
607
607
|
capacity: g,
|
|
608
608
|
archetypeCount: t.length,
|
|
609
609
|
layoutDescriptorOff: f,
|
|
610
|
-
bindingsOff:
|
|
610
|
+
bindingsOff: l,
|
|
611
611
|
regionTableOff: a,
|
|
612
612
|
regionTableCount: i,
|
|
613
613
|
// `regionOffsets` stays keyed by the snake ABI field names (it also indexes
|
|
@@ -617,10 +617,10 @@ function ns(t, e = st, n = {}) {
|
|
|
617
617
|
eventRingOff: r.event_ring_off,
|
|
618
618
|
actionRingOff: r.action_ring_off
|
|
619
619
|
};
|
|
620
|
-
mt(_, I),
|
|
620
|
+
mt(_, I), d > 0 && new Uint8Array(u, l, d).fill(0);
|
|
621
621
|
for (let w = 0; w < K.length; w++) {
|
|
622
|
-
const
|
|
623
|
-
|
|
622
|
+
const b = K[w], G = r[b.headerOff];
|
|
623
|
+
G !== 0 && b.init(_, G, n);
|
|
624
624
|
}
|
|
625
625
|
a !== 0 && jt(_, a, c);
|
|
626
626
|
for (let w = 0; w < o.length; w++)
|
|
@@ -632,10 +632,10 @@ function ns(t, e = st, n = {}) {
|
|
|
632
632
|
view: _,
|
|
633
633
|
header: I,
|
|
634
634
|
archetypes: B,
|
|
635
|
-
_regionBytes:
|
|
635
|
+
_regionBytes: p,
|
|
636
636
|
_allocator: e,
|
|
637
637
|
// Carry the headroom policy with the store so the realloc slow path
|
|
638
|
-
// (`optionsFromOld`) can re-reserve the same margin
|
|
638
|
+
// (`optionsFromOld`) can re-reserve the same margin.
|
|
639
639
|
_reservedDescriptorBytes: n.reservedDescriptorBytes ?? 0
|
|
640
640
|
};
|
|
641
641
|
}
|
|
@@ -644,7 +644,7 @@ function en(t, e) {
|
|
|
644
644
|
for (let r = 0; r < e.length; r++) {
|
|
645
645
|
const s = e[r], o = new Array(s.columns.length), i = /* @__PURE__ */ new Map();
|
|
646
646
|
for (let a = 0; a < s.columns.length; a++) {
|
|
647
|
-
const c = s.columns[a],
|
|
647
|
+
const c = s.columns[a], d = {
|
|
648
648
|
componentId: c.componentId,
|
|
649
649
|
fieldId: c.fieldId,
|
|
650
650
|
typeTag: c.typeTag,
|
|
@@ -652,7 +652,7 @@ function en(t, e) {
|
|
|
652
652
|
stride: c.stride,
|
|
653
653
|
view: Zt(t, c.typeTag, c.byteOff, s.rowCapacity)
|
|
654
654
|
};
|
|
655
|
-
o[a] =
|
|
655
|
+
o[a] = d, i.set(Qt(c.componentId, c.fieldId), d);
|
|
656
656
|
}
|
|
657
657
|
n.set(s.archetypeId, {
|
|
658
658
|
archetypeId: s.archetypeId,
|
|
@@ -689,13 +689,13 @@ class rs {
|
|
|
689
689
|
}
|
|
690
690
|
/** Live entity indices that hold this component (dense, iteration order is
|
|
691
691
|
* SparseMap insertion/swap order — NOT canonical). Used by the hot query
|
|
692
|
-
* integration path
|
|
692
|
+
* integration path; for the determinism surface use
|
|
693
693
|
* `canonicalIndices` instead. */
|
|
694
694
|
get indices() {
|
|
695
695
|
return this._data.keys;
|
|
696
696
|
}
|
|
697
697
|
/** Live entity indices in **canonical** (ascending) order — the determinism
|
|
698
|
-
* ordering for `stateHash` + snapshot/restore
|
|
698
|
+
* ordering for `stateHash` + snapshot/restore. The native
|
|
699
699
|
* `indices` getter is insertion/swap order and would make two worlds with
|
|
700
700
|
* identical contents reached by different add/remove histories diverge, so
|
|
701
701
|
* the cold determinism paths sort here. Allocates a sorted copy each call;
|
|
@@ -749,12 +749,12 @@ class rs {
|
|
|
749
749
|
return s === void 0 ? !1 : (s[n] = r, !0);
|
|
750
750
|
}
|
|
751
751
|
}
|
|
752
|
-
class
|
|
752
|
+
class A extends Error {
|
|
753
753
|
constructor(e) {
|
|
754
754
|
super(e), this.name = "SparseRestoreError";
|
|
755
755
|
}
|
|
756
756
|
}
|
|
757
|
-
const Ie = 12, we = 4,
|
|
757
|
+
const Ie = 12, we = 4, H = 8;
|
|
758
758
|
function Se(t, e) {
|
|
759
759
|
let n = tn;
|
|
760
760
|
const r = (s) => {
|
|
@@ -768,7 +768,7 @@ function os(t) {
|
|
|
768
768
|
let e = 4;
|
|
769
769
|
for (let o = 0; o < t.length; o++) {
|
|
770
770
|
const i = t[o], a = i.fieldNames.length;
|
|
771
|
-
e += Ie + i.size * (we + a *
|
|
771
|
+
e += Ie + i.size * (we + a * H);
|
|
772
772
|
}
|
|
773
773
|
const n = new Uint8Array(e), r = new DataView(n.buffer);
|
|
774
774
|
let s = 0;
|
|
@@ -776,12 +776,12 @@ function os(t) {
|
|
|
776
776
|
for (let o = 0; o < t.length; o++) {
|
|
777
777
|
const i = t[o], a = i.fieldNames.length, c = i.canonicalIndices();
|
|
778
778
|
r.setUint32(s, a, !0), s += 4, r.setUint32(s, Se(i.fieldNames, i.fieldTypes), !0), s += 4, r.setUint32(s, c.length, !0), s += 4;
|
|
779
|
-
for (let
|
|
780
|
-
const
|
|
781
|
-
r.setUint32(s,
|
|
782
|
-
const f = i.getRow(
|
|
779
|
+
for (let d = 0; d < c.length; d++) {
|
|
780
|
+
const l = c[d];
|
|
781
|
+
r.setUint32(s, l, !0), s += 4;
|
|
782
|
+
const f = i.getRow(l);
|
|
783
783
|
for (let h = 0; h < a; h++)
|
|
784
|
-
r.setFloat64(s, f[h], !0), s +=
|
|
784
|
+
r.setFloat64(s, f[h], !0), s += H;
|
|
785
785
|
}
|
|
786
786
|
}
|
|
787
787
|
return n;
|
|
@@ -791,49 +791,49 @@ function is(t, e) {
|
|
|
791
791
|
let s = 0;
|
|
792
792
|
const o = (a) => {
|
|
793
793
|
if (s + a > r)
|
|
794
|
-
throw new
|
|
794
|
+
throw new A(
|
|
795
795
|
`sparse snapshot truncated: need ${a} more bytes at offset ${s}, have ${r - s}`
|
|
796
796
|
);
|
|
797
797
|
};
|
|
798
798
|
o(4);
|
|
799
799
|
const i = n.getUint32(s, !0);
|
|
800
800
|
if (s += 4, i !== t.length)
|
|
801
|
-
throw new
|
|
801
|
+
throw new A(
|
|
802
802
|
`sparse store count mismatch: snapshot=${i}, registered=${t.length}`
|
|
803
803
|
);
|
|
804
804
|
for (let a = 0; a < t.length; a++) {
|
|
805
805
|
const c = t[a];
|
|
806
806
|
o(Ie);
|
|
807
|
-
const l = n.getUint32(s, !0);
|
|
808
|
-
s += 4;
|
|
809
807
|
const d = n.getUint32(s, !0);
|
|
810
808
|
s += 4;
|
|
809
|
+
const l = n.getUint32(s, !0);
|
|
810
|
+
s += 4;
|
|
811
811
|
const f = n.getUint32(s, !0);
|
|
812
|
-
if (s += 4,
|
|
813
|
-
throw new
|
|
814
|
-
`sparse store ${a} field-count mismatch: snapshot=${
|
|
812
|
+
if (s += 4, d !== c.fieldNames.length)
|
|
813
|
+
throw new A(
|
|
814
|
+
`sparse store ${a} field-count mismatch: snapshot=${d}, registered=${c.fieldNames.length}`
|
|
815
815
|
);
|
|
816
816
|
const h = Se(c.fieldNames, c.fieldTypes);
|
|
817
|
-
if (
|
|
818
|
-
throw new
|
|
819
|
-
`sparse store ${a} schema identity mismatch: snapshot hash=${
|
|
817
|
+
if (l !== h)
|
|
818
|
+
throw new A(
|
|
819
|
+
`sparse store ${a} schema identity mismatch: snapshot hash=${l}, registered=${h} (same field count, different field names/types — likely a registration-order divergence between the snapshot and restore worlds)`
|
|
820
820
|
);
|
|
821
821
|
c.clear();
|
|
822
822
|
for (let g = 0; g < f; g++) {
|
|
823
|
-
o(we +
|
|
824
|
-
const
|
|
825
|
-
if (s += 4,
|
|
826
|
-
throw new
|
|
827
|
-
`sparse store ${a} member ${g} entity index ${
|
|
823
|
+
o(we + d * H);
|
|
824
|
+
const p = n.getUint32(s, !0);
|
|
825
|
+
if (s += 4, p > $)
|
|
826
|
+
throw new A(
|
|
827
|
+
`sparse store ${a} member ${g} entity index ${p} exceeds MAX_INDEX (${$})`
|
|
828
828
|
);
|
|
829
|
-
const u = new Array(
|
|
830
|
-
for (let _ = 0; _ <
|
|
831
|
-
u[_] = n.getFloat64(s, !0), s +=
|
|
832
|
-
c.setRawRow(
|
|
829
|
+
const u = new Array(d);
|
|
830
|
+
for (let _ = 0; _ < d; _++)
|
|
831
|
+
u[_] = n.getFloat64(s, !0), s += H;
|
|
832
|
+
c.setRawRow(p, u);
|
|
833
833
|
}
|
|
834
834
|
}
|
|
835
835
|
if (s !== r)
|
|
836
|
-
throw new
|
|
836
|
+
throw new A(
|
|
837
837
|
`sparse snapshot has ${r - s} trailing bytes after the last store (not a canonical encoding)`
|
|
838
838
|
);
|
|
839
839
|
}
|
|
@@ -842,45 +842,45 @@ function as(t, e) {
|
|
|
842
842
|
let s = 0;
|
|
843
843
|
const o = (a) => {
|
|
844
844
|
if (s + a > r)
|
|
845
|
-
throw new
|
|
845
|
+
throw new A(
|
|
846
846
|
`sparse snapshot truncated: need ${a} more bytes at offset ${s}, have ${r - s}`
|
|
847
847
|
);
|
|
848
848
|
};
|
|
849
849
|
o(4);
|
|
850
850
|
const i = n.getUint32(s, !0);
|
|
851
851
|
if (s += 4, i !== t.length)
|
|
852
|
-
throw new
|
|
852
|
+
throw new A(
|
|
853
853
|
`sparse store count mismatch: snapshot=${i}, registered=${t.length}`
|
|
854
854
|
);
|
|
855
855
|
for (let a = 0; a < t.length; a++) {
|
|
856
856
|
const c = t[a];
|
|
857
857
|
o(Ie);
|
|
858
|
-
const l = n.getUint32(s, !0);
|
|
859
|
-
s += 4;
|
|
860
858
|
const d = n.getUint32(s, !0);
|
|
861
859
|
s += 4;
|
|
860
|
+
const l = n.getUint32(s, !0);
|
|
861
|
+
s += 4;
|
|
862
862
|
const f = n.getUint32(s, !0);
|
|
863
|
-
if (s += 4,
|
|
864
|
-
throw new
|
|
865
|
-
`sparse store ${a} field-count mismatch: snapshot=${
|
|
863
|
+
if (s += 4, d !== c.fieldNames.length)
|
|
864
|
+
throw new A(
|
|
865
|
+
`sparse store ${a} field-count mismatch: snapshot=${d}, registered=${c.fieldNames.length}`
|
|
866
866
|
);
|
|
867
867
|
const h = Se(c.fieldNames, c.fieldTypes);
|
|
868
|
-
if (
|
|
869
|
-
throw new
|
|
870
|
-
`sparse store ${a} schema identity mismatch: snapshot hash=${
|
|
868
|
+
if (l !== h)
|
|
869
|
+
throw new A(
|
|
870
|
+
`sparse store ${a} schema identity mismatch: snapshot hash=${l}, registered=${h} (same field count, different field names/types — likely a registration-order divergence between the snapshot and restore worlds)`
|
|
871
871
|
);
|
|
872
872
|
for (let g = 0; g < f; g++) {
|
|
873
|
-
o(we +
|
|
874
|
-
const
|
|
875
|
-
if (s += 4,
|
|
876
|
-
throw new
|
|
877
|
-
`sparse store ${a} member ${g} entity index ${
|
|
873
|
+
o(we + d * H);
|
|
874
|
+
const p = n.getUint32(s, !0);
|
|
875
|
+
if (s += 4, p > $)
|
|
876
|
+
throw new A(
|
|
877
|
+
`sparse store ${a} member ${g} entity index ${p} exceeds MAX_INDEX (${$})`
|
|
878
878
|
);
|
|
879
|
-
s +=
|
|
879
|
+
s += d * H;
|
|
880
880
|
}
|
|
881
881
|
}
|
|
882
882
|
if (s !== r)
|
|
883
|
-
throw new
|
|
883
|
+
throw new A(
|
|
884
884
|
`sparse snapshot has ${r - s} trailing bytes after the last store (not a canonical encoding)`
|
|
885
885
|
);
|
|
886
886
|
}
|
|
@@ -895,12 +895,12 @@ class Ze {
|
|
|
895
895
|
* multi. Carries membership (and the target, when exclusive). */
|
|
896
896
|
sparse;
|
|
897
897
|
/** Cleanup policy applied to this relation's sources when a target is
|
|
898
|
-
* destroyed
|
|
898
|
+
* destroyed. `orphan` (the default) is a no-op — the link dangles
|
|
899
899
|
* safely. `Store` reads this at destroy-flush off `sourcesOf`. */
|
|
900
900
|
onDeleteTarget;
|
|
901
901
|
/** The backing sparse store instance. Owned for registration/liveness by
|
|
902
902
|
* `Store`, but the relation drives the forward/membership rows on it directly
|
|
903
|
-
* — that is the cardinality interaction this class now encapsulates
|
|
903
|
+
* — that is the cardinality interaction this class now encapsulates. */
|
|
904
904
|
_store;
|
|
905
905
|
/** target `EntityID` → set of source `EntityID`s. Keyed by the full id, not
|
|
906
906
|
* the index, so a recycled target slot can't alias a dead target's sources.
|
|
@@ -923,7 +923,7 @@ class Ze {
|
|
|
923
923
|
r !== void 0 && (r.delete(n), r.size === 0 && this._reverse.delete(e));
|
|
924
924
|
}
|
|
925
925
|
/** Drop every reverse-index entry whose **target** is no longer alive,
|
|
926
|
-
* returning the count dropped
|
|
926
|
+
* returning the count dropped. The `orphan` policy intentionally
|
|
927
927
|
* leaves a destroyed target's reverse entry intact (the link dangles
|
|
928
928
|
* safely), so a long-lived source that orphan-points at a stream of
|
|
929
929
|
* short-lived targets and never re-targets/dies accumulates dead-target keys
|
|
@@ -1019,7 +1019,7 @@ class rn extends Ze {
|
|
|
1019
1019
|
}
|
|
1020
1020
|
}
|
|
1021
1021
|
restoreAddTarget() {
|
|
1022
|
-
throw new
|
|
1022
|
+
throw new A(
|
|
1023
1023
|
"exclusive relation has no multi forward sources to restore (snapshot header should have guarded this)"
|
|
1024
1024
|
);
|
|
1025
1025
|
}
|
|
@@ -1103,9 +1103,9 @@ function ls(t) {
|
|
|
1103
1103
|
continue;
|
|
1104
1104
|
}
|
|
1105
1105
|
const c = [];
|
|
1106
|
-
a.forEachCanonicalTargetSet((
|
|
1107
|
-
for (let
|
|
1108
|
-
n += tt + c[
|
|
1106
|
+
a.forEachCanonicalTargetSet((d, l) => c.push([d, l])), e[i] = c, n += et;
|
|
1107
|
+
for (let d = 0; d < c.length; d++)
|
|
1108
|
+
n += tt + c[d][1].length * ne;
|
|
1109
1109
|
}
|
|
1110
1110
|
const r = new Uint8Array(n), s = new DataView(r.buffer);
|
|
1111
1111
|
let o = 0;
|
|
@@ -1116,10 +1116,10 @@ function ls(t) {
|
|
|
1116
1116
|
if (a !== null) {
|
|
1117
1117
|
s.setUint32(o, a.length, !0), o += 4;
|
|
1118
1118
|
for (let c = 0; c < a.length; c++) {
|
|
1119
|
-
const
|
|
1120
|
-
s.setUint32(o,
|
|
1121
|
-
for (let f = 0; f <
|
|
1122
|
-
s.setFloat64(o,
|
|
1119
|
+
const d = a[c][0], l = a[c][1];
|
|
1120
|
+
s.setUint32(o, d, !0), o += 4, s.setUint32(o, l.length, !0), o += 4;
|
|
1121
|
+
for (let f = 0; f < l.length; f++)
|
|
1122
|
+
s.setFloat64(o, l[f], !0), o += ne;
|
|
1123
1123
|
}
|
|
1124
1124
|
}
|
|
1125
1125
|
}
|
|
@@ -1130,7 +1130,7 @@ function us(t, e, n) {
|
|
|
1130
1130
|
let o = 0;
|
|
1131
1131
|
const i = (c) => {
|
|
1132
1132
|
if (o + c > s)
|
|
1133
|
-
throw new
|
|
1133
|
+
throw new A(
|
|
1134
1134
|
`relation snapshot truncated: need ${c} more bytes at offset ${o}, have ${s - o}`
|
|
1135
1135
|
);
|
|
1136
1136
|
};
|
|
@@ -1138,18 +1138,18 @@ function us(t, e, n) {
|
|
|
1138
1138
|
i(4);
|
|
1139
1139
|
const a = r.getUint32(o, !0);
|
|
1140
1140
|
if (o += 4, a !== t.length)
|
|
1141
|
-
throw new
|
|
1141
|
+
throw new A(
|
|
1142
1142
|
`relation count mismatch: snapshot=${a}, registered=${t.length}`
|
|
1143
1143
|
);
|
|
1144
1144
|
for (let c = 0; c < t.length; c++) {
|
|
1145
|
-
const
|
|
1145
|
+
const d = t[c];
|
|
1146
1146
|
i(Je);
|
|
1147
|
-
const
|
|
1148
|
-
if (o += 4,
|
|
1149
|
-
throw new
|
|
1150
|
-
`relation ${c} cardinality mismatch: snapshot ${
|
|
1147
|
+
const l = r.getUint32(o, !0);
|
|
1148
|
+
if (o += 4, l === 1 === d.exclusive)
|
|
1149
|
+
throw new A(
|
|
1150
|
+
`relation ${c} cardinality mismatch: snapshot ${l ? "multi" : "exclusive"}, registered ${d.exclusive ? "exclusive" : "multi"}`
|
|
1151
1151
|
);
|
|
1152
|
-
if (
|
|
1152
|
+
if (d.exclusive) continue;
|
|
1153
1153
|
i(et);
|
|
1154
1154
|
const f = r.getUint32(o, !0);
|
|
1155
1155
|
o += 4;
|
|
@@ -1157,33 +1157,33 @@ function us(t, e, n) {
|
|
|
1157
1157
|
i(tt);
|
|
1158
1158
|
const g = r.getUint32(o, !0);
|
|
1159
1159
|
o += 4;
|
|
1160
|
-
const
|
|
1160
|
+
const p = r.getUint32(o, !0);
|
|
1161
1161
|
if (o += 4, g > $)
|
|
1162
|
-
throw new
|
|
1162
|
+
throw new A(
|
|
1163
1163
|
`relation ${c} source index ${g} exceeds MAX_INDEX (${$})`
|
|
1164
1164
|
);
|
|
1165
|
-
i(
|
|
1165
|
+
i(p * ne);
|
|
1166
1166
|
const u = n(g);
|
|
1167
|
-
for (let _ = 0; _ <
|
|
1167
|
+
for (let _ = 0; _ < p; _++) {
|
|
1168
1168
|
const I = r.getFloat64(o, !0);
|
|
1169
1169
|
o += ne;
|
|
1170
1170
|
const B = I;
|
|
1171
1171
|
if (!Number.isInteger(B) || B < 0 || B > Re)
|
|
1172
|
-
throw new
|
|
1172
|
+
throw new A(
|
|
1173
1173
|
`relation ${c} target ${B} is not a well-formed packed EntityID (expected an integer in [0, ${Re}])`
|
|
1174
1174
|
);
|
|
1175
|
-
|
|
1175
|
+
d.restoreAddTarget(g, I, u);
|
|
1176
1176
|
}
|
|
1177
1177
|
}
|
|
1178
1178
|
}
|
|
1179
1179
|
if (o !== s)
|
|
1180
|
-
throw new
|
|
1180
|
+
throw new A(
|
|
1181
1181
|
`relation snapshot has ${s - o} trailing bytes after the last relation (not a canonical encoding)`
|
|
1182
1182
|
);
|
|
1183
1183
|
}
|
|
1184
1184
|
const $e = /* @__PURE__ */ new WeakMap();
|
|
1185
1185
|
function an(t) {
|
|
1186
|
-
const e = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set(),
|
|
1186
|
+
const e = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set(), d = /* @__PURE__ */ new Set(), l = /* @__PURE__ */ new Set();
|
|
1187
1187
|
for (let u = 0; u < t.writes.length; u++) {
|
|
1188
1188
|
const _ = t.writes[u].id;
|
|
1189
1189
|
n.add(_), e.add(_), r.add(_);
|
|
@@ -1225,12 +1225,12 @@ function an(t) {
|
|
|
1225
1225
|
if (g !== void 0)
|
|
1226
1226
|
for (let u = 0; u < g.length; u++) {
|
|
1227
1227
|
const _ = g[u];
|
|
1228
|
-
|
|
1228
|
+
l.add(_), d.add(_);
|
|
1229
1229
|
}
|
|
1230
|
-
const
|
|
1231
|
-
if (
|
|
1232
|
-
for (let u = 0; u <
|
|
1233
|
-
|
|
1230
|
+
const p = t.relationReads;
|
|
1231
|
+
if (p !== void 0)
|
|
1232
|
+
for (let u = 0; u < p.length; u++)
|
|
1233
|
+
d.add(p[u]);
|
|
1234
1234
|
return {
|
|
1235
1235
|
reads: e,
|
|
1236
1236
|
writes: n,
|
|
@@ -1241,8 +1241,8 @@ function an(t) {
|
|
|
1241
1241
|
resourceWrites: i,
|
|
1242
1242
|
sparseReads: a,
|
|
1243
1243
|
sparseWrites: c,
|
|
1244
|
-
relationReads:
|
|
1245
|
-
relationWrites:
|
|
1244
|
+
relationReads: d,
|
|
1245
|
+
relationWrites: l
|
|
1246
1246
|
};
|
|
1247
1247
|
}
|
|
1248
1248
|
function cn(t) {
|
|
@@ -1283,17 +1283,17 @@ class un {
|
|
|
1283
1283
|
active = null;
|
|
1284
1284
|
sets = null;
|
|
1285
1285
|
// The label used in violation messages. Tracks `active` for a system span,
|
|
1286
|
-
// but a run-condition span
|
|
1286
|
+
// but a run-condition span has no descriptor — only this name — so the
|
|
1287
1287
|
// failure helpers read the label here rather than off `active`.
|
|
1288
1288
|
activeName = null;
|
|
1289
|
-
// An `exclusive` system
|
|
1289
|
+
// An `exclusive` system has full world access: every check_* below
|
|
1290
1290
|
// passes for the whole span. Kept as an explicit flag (rather than leaving
|
|
1291
1291
|
// `sets` null) so `isActive()` stays truthful inside the span.
|
|
1292
1292
|
exclusive = !1;
|
|
1293
1293
|
enter(e) {
|
|
1294
1294
|
this.active = e, this.activeName = e.name ?? `system_${e.id}`, this.exclusive = e.exclusive === !0, this.sets = this.exclusive ? null : cn(e);
|
|
1295
1295
|
}
|
|
1296
|
-
/** Open a reads-only span for a run condition
|
|
1296
|
+
/** Open a reads-only span for a run condition. No descriptor — a
|
|
1297
1297
|
* condition can gate a whole SystemSet, so it isn't attributable to one
|
|
1298
1298
|
* system — just its declared reads/resource_reads and a name for diagnostics.
|
|
1299
1299
|
* Paired with `leave()`. */
|
|
@@ -1325,8 +1325,8 @@ class un {
|
|
|
1325
1325
|
checkDestroy() {
|
|
1326
1326
|
if (this.sets === null || this.sets.hasDespawns) return;
|
|
1327
1327
|
const e = this.activeName;
|
|
1328
|
-
throw new
|
|
1329
|
-
|
|
1328
|
+
throw new T(
|
|
1329
|
+
y.ACCESS_UNDECLARED,
|
|
1330
1330
|
`system '${e}' called despawn but didn't declare any despawns — declare the components this system removes via despawn in its 'despawns'`,
|
|
1331
1331
|
{ system: e, op: "despawn" }
|
|
1332
1332
|
);
|
|
@@ -1341,7 +1341,7 @@ class un {
|
|
|
1341
1341
|
const n = e;
|
|
1342
1342
|
this.sets.resourceWrites.has(n) || this.failResource("write", e, "resourceWrites");
|
|
1343
1343
|
}
|
|
1344
|
-
// --- Sparse component / relation checks
|
|
1344
|
+
// --- Sparse component / relation checks ---
|
|
1345
1345
|
// Keyed against the dedicated sparse/relation sets, NOT the dense
|
|
1346
1346
|
// `reads`/`writes` sets — the id spaces are disjoint by construction (see
|
|
1347
1347
|
// file header). `def as unknown as number` recovers the SparseComponentID /
|
|
@@ -1366,7 +1366,7 @@ class un {
|
|
|
1366
1366
|
const n = e;
|
|
1367
1367
|
this.sets.relationWrites.has(n) || this.failRelation("write", n, "relationWrites");
|
|
1368
1368
|
}
|
|
1369
|
-
/** A `(*, T)` wildcard (`Query.forEachRelatedTo
|
|
1369
|
+
/** A `(*, T)` wildcard (`Query.forEachRelatedTo`) reads every
|
|
1370
1370
|
* relation's reverse index, so it can't name a specific relation — it is
|
|
1371
1371
|
* authorised by the `ANY_RELATION` sentinel in `relationReads`. Honoured here
|
|
1372
1372
|
* exactly like a per-relation read, just keyed on the reserved sentinel id
|
|
@@ -1378,7 +1378,7 @@ class un {
|
|
|
1378
1378
|
"relationReads (as ANY_RELATION)"
|
|
1379
1379
|
));
|
|
1380
1380
|
}
|
|
1381
|
-
// --- Optional query-term scope
|
|
1381
|
+
// --- Optional query-term scope ---
|
|
1382
1382
|
// `Query.forEach` and `ChangedQuery.forEach` push the iterating query's
|
|
1383
1383
|
// `_optional` term list for the span of the callback;
|
|
1384
1384
|
// `Archetype.getOptionalColumnRead` then verifies the fetched component was
|
|
@@ -1392,7 +1392,7 @@ class un {
|
|
|
1392
1392
|
// `query.archetypes` walk can't be attributed to an optional declaration, so it
|
|
1393
1393
|
// isn't checked — mirroring the unchecked outside-of-system calls in the header.
|
|
1394
1394
|
//
|
|
1395
|
-
// CAVEAT
|
|
1395
|
+
// CAVEAT: the gate always attributes to the INNERMOST active
|
|
1396
1396
|
// `forEach`. If you nest `forEach` and call `getOptionalColumnRead` on an
|
|
1397
1397
|
// OUTER query's archetype inside the inner loop, it is checked against the inner
|
|
1398
1398
|
// query's terms (a false throw or false pass). Per-query attribution isn't worth
|
|
@@ -1411,39 +1411,39 @@ class un {
|
|
|
1411
1411
|
const r = this.optionalScopes[n - 1], s = e.id;
|
|
1412
1412
|
for (let o = 0; o < r.length; o++)
|
|
1413
1413
|
if (r[o] === s) return;
|
|
1414
|
-
throw new
|
|
1415
|
-
|
|
1414
|
+
throw new T(
|
|
1415
|
+
y.OPTIONAL_TERM_NOT_DECLARED,
|
|
1416
1416
|
`getOptionalColumnRead fetched optional component ${s} but the iterating query didn't declare it — add .optional(component) to the query before fetching it`
|
|
1417
1417
|
);
|
|
1418
1418
|
}
|
|
1419
1419
|
failComponent(e, n, r) {
|
|
1420
1420
|
const s = this.activeName, o = ut(n);
|
|
1421
|
-
throw new
|
|
1422
|
-
|
|
1421
|
+
throw new T(
|
|
1422
|
+
y.ACCESS_UNDECLARED,
|
|
1423
1423
|
`system '${s}' performed ${e} on ${o} but didn't declare it — add it to '${r}' (see docs/api/systems.md)`,
|
|
1424
1424
|
{ system: s, op: e, component: n.id }
|
|
1425
1425
|
);
|
|
1426
1426
|
}
|
|
1427
1427
|
failSparse(e, n, r) {
|
|
1428
1428
|
const s = this.activeName;
|
|
1429
|
-
throw new
|
|
1430
|
-
|
|
1429
|
+
throw new T(
|
|
1430
|
+
y.ACCESS_UNDECLARED,
|
|
1431
1431
|
`system '${s}' performed ${e} on sparse component ${n} but didn't declare it — add it to '${r}' (see docs/api/systems.md)`,
|
|
1432
1432
|
{ system: s, op: e, sparse: n }
|
|
1433
1433
|
);
|
|
1434
1434
|
}
|
|
1435
1435
|
failRelation(e, n, r) {
|
|
1436
1436
|
const s = this.activeName;
|
|
1437
|
-
throw new
|
|
1438
|
-
|
|
1437
|
+
throw new T(
|
|
1438
|
+
y.ACCESS_UNDECLARED,
|
|
1439
1439
|
`system '${s}' performed ${e} on relation ${n} but didn't declare it — add it to '${r}' (see docs/api/systems.md)`,
|
|
1440
1440
|
{ system: s, op: e, relation: n }
|
|
1441
1441
|
);
|
|
1442
1442
|
}
|
|
1443
1443
|
failResource(e, n, r) {
|
|
1444
1444
|
const s = this.activeName, o = n.description ?? "<unnamed>";
|
|
1445
|
-
throw new
|
|
1446
|
-
|
|
1445
|
+
throw new T(
|
|
1446
|
+
y.ACCESS_UNDECLARED,
|
|
1447
1447
|
`system '${s}' performed resource ${e} on '${o}' but didn't declare it — add the resource key to '${r}' (see docs/api/systems.md)`,
|
|
1448
1448
|
{ system: s, op: e, resource: o }
|
|
1449
1449
|
);
|
|
@@ -1511,8 +1511,8 @@ class hn {
|
|
|
1511
1511
|
for (const [n, r] of this.buf.entries()) {
|
|
1512
1512
|
const [s, o, i, a] = n.split(" ");
|
|
1513
1513
|
if (!s || !o || a === void 0) continue;
|
|
1514
|
-
const
|
|
1515
|
-
f && f.push(
|
|
1514
|
+
const d = { key: s === "actions" ? Number(i) : i, file: a, count: r }, f = e[s][o];
|
|
1515
|
+
f && f.push(d);
|
|
1516
1516
|
}
|
|
1517
1517
|
for (const n of Object.values(e))
|
|
1518
1518
|
for (const r of Object.values(n))
|
|
@@ -1584,50 +1584,86 @@ function hs(t) {
|
|
|
1584
1584
|
function En(t) {
|
|
1585
1585
|
return !("fn" in t);
|
|
1586
1586
|
}
|
|
1587
|
-
const
|
|
1587
|
+
const X = Object.freeze([]);
|
|
1588
1588
|
function fe(t) {
|
|
1589
|
-
return t === void 0 ?
|
|
1589
|
+
return t === void 0 ? X : Array.isArray(t) ? t : [t];
|
|
1590
1590
|
}
|
|
1591
1591
|
class _s {
|
|
1592
1592
|
labelSystems = /* @__PURE__ */ new Map();
|
|
1593
|
+
// Sorted descriptors for a phase, paired with the `systemLastRun` slot of each
|
|
1594
|
+
// — cached together so `runLabel` resolves both with the one `Map.get` it
|
|
1595
|
+
// already paid, and the per-system lookup inside the loop is array indexing.
|
|
1593
1596
|
sortedCache = /* @__PURE__ */ new Map();
|
|
1594
1597
|
systemIndex = /* @__PURE__ */ new Map();
|
|
1595
|
-
|
|
1596
|
-
//
|
|
1598
|
+
// Previous-run tick per scheduled system — a packed array, NOT a `Map` keyed
|
|
1599
|
+
// on the descriptor. `runLabel` reads it and writes it back once per system
|
|
1600
|
+
// per phase. A profile of a dispatch-bound schedule shows that those two `Map`
|
|
1601
|
+
// operations, and not the system bodies, are where most of the phase loop goes
|
|
1602
|
+
// — they hash an object identity twice for each system in each frame.
|
|
1603
|
+
//
|
|
1604
|
+
// Indexed by a SCHEDULE-LOCAL slot, not by `SystemDescriptor.id`. Ids come
|
|
1605
|
+
// from a per-world counter, so two descriptors registered with two different
|
|
1606
|
+
// worlds both get id 0 — scheduling them into a third world would alias them
|
|
1607
|
+
// onto one slot and let the system that runs more often overwrite the other's
|
|
1608
|
+
// last-run tick (silently widening its `changed()` window). Slots are handed
|
|
1609
|
+
// out per Schedule, so identity comes from this schedule's own numbering.
|
|
1610
|
+
systemLastRun = [];
|
|
1611
|
+
// Descriptor → its `systemLastRun` slot. Consulted only by `addSystems` /
|
|
1612
|
+
// `removeSystem`; the run loop never touches it (the slot travels in the
|
|
1613
|
+
// phase plan).
|
|
1614
|
+
//
|
|
1615
|
+
// `removeSystem` MUST delete from this map. It is the only strong reference
|
|
1616
|
+
// the Schedule keeps to a descriptor once its node is gone, and a descriptor
|
|
1617
|
+
// closes over whatever its `fn` captured — leaving the entry behind pins that
|
|
1618
|
+
// for the world's lifetime. (The `Map` this replaced was deleted on remove;
|
|
1619
|
+
// forgetting to do the same here leaked every descriptor ever scheduled.)
|
|
1620
|
+
lastRunSlots = /* @__PURE__ */ new Map();
|
|
1621
|
+
// Slots freed by `removeSystem`, handed back out by `_assignLastRunSlot`.
|
|
1622
|
+
// Without reuse the array would grow by one per `addSystems` call — unbounded
|
|
1623
|
+
// under a workload that toggles systems on and off each frame.
|
|
1624
|
+
freeLastRunSlots = [];
|
|
1625
|
+
// Nesting depth of a drive (`runStartup` / `runUpdate` / `runFixedUpdate`).
|
|
1626
|
+
// Non-zero means a phase plan is live and `runLabel`'s loop may still write
|
|
1627
|
+
// `systemLastRun` through the `slots` array it captured, which is what makes
|
|
1628
|
+
// recycling a freed slot unsafe right now — see `_assignLastRunSlot`.
|
|
1629
|
+
_driveDepth = 0;
|
|
1630
|
+
// Only systems carrying a run condition or set membership. The hot
|
|
1597
1631
|
// loop skips the per-system gate probe entirely when this is empty, so a
|
|
1598
|
-
// schedule that uses no conditions runs byte-for-byte the
|
|
1632
|
+
// schedule that uses no conditions runs byte-for-byte the original path.
|
|
1599
1633
|
gatedSystems = /* @__PURE__ */ new Map();
|
|
1600
1634
|
// Live set configuration, read at sort time (ordering) and run time
|
|
1601
1635
|
// (conditions) so `configureSet` is order-independent w.r.t. `addSystems`.
|
|
1602
1636
|
setConditions = /* @__PURE__ */ new Map();
|
|
1603
1637
|
setOrdering = /* @__PURE__ */ new Map();
|
|
1604
1638
|
nextInsertionOrder = 0;
|
|
1605
|
-
// The opt-in compute backend
|
|
1639
|
+
// The opt-in compute backend, or null (the default — pure-TS). When
|
|
1606
1640
|
// set, a scheduled system carrying a `backendHandle` runs `backend.run(...)`
|
|
1607
|
-
// instead of its `fn`. `null` is the byte-for-byte
|
|
1641
|
+
// instead of its `fn`. `null` is the byte-for-byte no-backend path: `runLabel`
|
|
1608
1642
|
// hoists this to a local and only reads `desc.backendHandle` when non-null,
|
|
1609
1643
|
// so a no-backend ECS never touches the routing field.
|
|
1610
1644
|
_backend = null;
|
|
1611
1645
|
/** Dev-diagnostic sink (`ECSOptions.onWarn`); defaults to `console.warn`.
|
|
1612
1646
|
* The only schedule diagnostic today is `warnDroppedEdge`. */
|
|
1613
1647
|
onWarn;
|
|
1648
|
+
/** The `FIXED_UPDATE` node list, held directly for `hasFixedSystems`. */
|
|
1649
|
+
_fixedNodes = [];
|
|
1614
1650
|
constructor(e) {
|
|
1615
1651
|
this.onWarn = e ?? ((n) => console.warn(n));
|
|
1616
1652
|
for (let n = 0; n < le.length; n++)
|
|
1617
1653
|
this.labelSystems.set(le[n], []);
|
|
1618
|
-
this.labelSystems.set("FIXED_UPDATE",
|
|
1654
|
+
this.labelSystems.set("FIXED_UPDATE", this._fixedNodes);
|
|
1619
1655
|
for (let n = 0; n < ue.length; n++)
|
|
1620
1656
|
this.labelSystems.set(ue[n], []);
|
|
1621
1657
|
}
|
|
1622
1658
|
addSystems(e, ...n) {
|
|
1623
1659
|
for (const r of n) {
|
|
1624
|
-
const s = "system" in r, o = s ? r.system : r, i = s ? r.ordering : void 0, a = s ? fe(r.runIf) :
|
|
1660
|
+
const s = "system" in r, o = s ? r.system : r, i = s ? r.ordering : void 0, a = s ? fe(r.runIf) : X, c = s ? fe(r.set) : X;
|
|
1625
1661
|
if (this.systemIndex.has(o))
|
|
1626
|
-
throw new
|
|
1627
|
-
|
|
1662
|
+
throw new T(
|
|
1663
|
+
y.DUPLICATE_SYSTEM,
|
|
1628
1664
|
`System ${o.name ?? o.id} is already scheduled`
|
|
1629
1665
|
);
|
|
1630
|
-
const
|
|
1666
|
+
const d = {
|
|
1631
1667
|
descriptor: o,
|
|
1632
1668
|
insertionOrder: this.nextInsertionOrder++,
|
|
1633
1669
|
before: new Set(i?.before ?? []),
|
|
@@ -1635,11 +1671,11 @@ class _s {
|
|
|
1635
1671
|
conditions: a,
|
|
1636
1672
|
sets: c
|
|
1637
1673
|
};
|
|
1638
|
-
this.labelSystems.get(e).push(
|
|
1674
|
+
this.labelSystems.get(e).push(d), this.systemIndex.set(o, e), this._assignLastRunSlot(o), (a.length > 0 || c.length > 0) && this.gatedSystems.set(o, d), this.sortedCache.delete(e);
|
|
1639
1675
|
}
|
|
1640
1676
|
}
|
|
1641
1677
|
/**
|
|
1642
|
-
* Configure a `SystemSet`
|
|
1678
|
+
* Configure a `SystemSet` — its shared run condition(s) and/or
|
|
1643
1679
|
* ordering, inherited by every member. Additive and order-independent w.r.t.
|
|
1644
1680
|
* `addSystems`: conditions accumulate (ANDed), ordering targets union, and
|
|
1645
1681
|
* a member added before or after this call picks the configuration up.
|
|
@@ -1653,45 +1689,72 @@ class _s {
|
|
|
1653
1689
|
if (n.before !== void 0 || n.after !== void 0) {
|
|
1654
1690
|
let s = this.setOrdering.get(e);
|
|
1655
1691
|
s === void 0 && (s = { before: /* @__PURE__ */ new Set(), after: /* @__PURE__ */ new Set() }, this.setOrdering.set(e, s));
|
|
1656
|
-
for (const o of n.before ??
|
|
1657
|
-
for (const o of n.after ??
|
|
1692
|
+
for (const o of n.before ?? X) s.before.add(o);
|
|
1693
|
+
for (const o of n.after ?? X) s.after.add(o);
|
|
1658
1694
|
this.sortedCache.clear();
|
|
1659
1695
|
}
|
|
1660
1696
|
}
|
|
1661
1697
|
removeSystem(e) {
|
|
1662
1698
|
const n = this.systemIndex.get(e);
|
|
1663
1699
|
if (n === void 0) return;
|
|
1664
|
-
const r = this.labelSystems.get(n), s = r.findIndex((
|
|
1700
|
+
const r = this.labelSystems.get(n), s = r.findIndex((i) => i.descriptor === e);
|
|
1665
1701
|
if (s !== -1) {
|
|
1666
|
-
const
|
|
1667
|
-
s !==
|
|
1668
|
-
for (const
|
|
1669
|
-
|
|
1702
|
+
const i = r.length - 1;
|
|
1703
|
+
s !== i && (r[s] = r[i]), r.pop();
|
|
1704
|
+
for (const a of r)
|
|
1705
|
+
a.before.delete(e), a.after.delete(e);
|
|
1670
1706
|
}
|
|
1671
|
-
this.systemIndex.delete(e)
|
|
1707
|
+
this.systemIndex.delete(e);
|
|
1708
|
+
const o = this.lastRunSlots.get(e);
|
|
1709
|
+
o !== void 0 && (this.systemLastRun[o] = 0, this.lastRunSlots.delete(e), this.freeLastRunSlots.push(o)), this.gatedSystems.delete(e), this.sortedCache.clear();
|
|
1672
1710
|
}
|
|
1673
|
-
/** Attach (or, with `null`, detach) the opt-in compute backend
|
|
1711
|
+
/** Attach (or, with `null`, detach) the opt-in compute backend. Driven
|
|
1674
1712
|
* by `ECS.attachBackend`; routes any scheduled system carrying a
|
|
1675
1713
|
* `backendHandle` to `backend.run(handle)` in place of its `fn`. */
|
|
1676
1714
|
setBackend(e) {
|
|
1677
1715
|
this._backend = e;
|
|
1678
1716
|
}
|
|
1717
|
+
// The three drive entry points each bracket their phases with `_driveDepth`,
|
|
1718
|
+
// so `_assignLastRunSlot` will not recycle a `systemLastRun` slot that a phase
|
|
1719
|
+
// plan captured by `runLabel`'s loop may still write to — see the guard there
|
|
1720
|
+
// for the hazard it closes.
|
|
1721
|
+
//
|
|
1722
|
+
// Held across the WHOLE drive, not per phase: one `try`/`finally` per frame
|
|
1723
|
+
// instead of one per phase (three, for an update). The difference is
|
|
1724
|
+
// measurable on a dispatch-bound schedule, where the system bodies do almost
|
|
1725
|
+
// no work. The wider window is also the more
|
|
1726
|
+
// conservative one, and slots still recycle freely between frames — the only
|
|
1727
|
+
// property `freeLastRunSlots` needs to stay bounded. Written out at each of
|
|
1728
|
+
// the three sites rather than wrapped in a helper taking a callback, which
|
|
1729
|
+
// would put a closure allocation and an indirect call on the per-frame path.
|
|
1679
1730
|
runStartup(e, n) {
|
|
1680
|
-
|
|
1681
|
-
|
|
1731
|
+
this._driveDepth++;
|
|
1732
|
+
try {
|
|
1733
|
+
for (const r of le)
|
|
1734
|
+
this.runLabel(r, e, dt, n);
|
|
1735
|
+
} finally {
|
|
1736
|
+
this._driveDepth--;
|
|
1737
|
+
}
|
|
1682
1738
|
}
|
|
1683
1739
|
runUpdate(e, n, r) {
|
|
1684
|
-
|
|
1685
|
-
|
|
1740
|
+
this._driveDepth++;
|
|
1741
|
+
try {
|
|
1742
|
+
for (const s of ue)
|
|
1743
|
+
this.runLabel(s, e, n, r);
|
|
1744
|
+
} finally {
|
|
1745
|
+
this._driveDepth--;
|
|
1746
|
+
}
|
|
1686
1747
|
}
|
|
1687
1748
|
runFixedUpdate(e, n, r) {
|
|
1688
|
-
this.
|
|
1749
|
+
this._driveDepth++;
|
|
1750
|
+
try {
|
|
1751
|
+
this.runLabel("FIXED_UPDATE", e, n, r);
|
|
1752
|
+
} finally {
|
|
1753
|
+
this._driveDepth--;
|
|
1754
|
+
}
|
|
1689
1755
|
}
|
|
1690
1756
|
hasFixedSystems() {
|
|
1691
|
-
return this.
|
|
1692
|
-
"FIXED_UPDATE"
|
|
1693
|
-
/* FIXED_UPDATE */
|
|
1694
|
-
).length > 0;
|
|
1757
|
+
return this._fixedNodes.length > 0;
|
|
1695
1758
|
}
|
|
1696
1759
|
getAllSystems() {
|
|
1697
1760
|
const e = [];
|
|
@@ -1703,28 +1766,43 @@ class _s {
|
|
|
1703
1766
|
hasSystem(e) {
|
|
1704
1767
|
return this.systemIndex.has(e);
|
|
1705
1768
|
}
|
|
1769
|
+
/** Hand `descriptor` its `systemLastRun` slot, keeping the array packed (no
|
|
1770
|
+
* holes ⇒ no undefined-check on the read in `runLabel`, which is the whole
|
|
1771
|
+
* point of it not being a `Map`). Idempotent for a descriptor already in this
|
|
1772
|
+
* schedule — `getSorted` re-asks for every system it sorts. A descriptor that
|
|
1773
|
+
* was removed and re-added gets a *fresh* slot starting at tick 0, which is
|
|
1774
|
+
* what the previous `Map`-based bookkeeping did (`delete` on remove, `set(…, 0)`
|
|
1775
|
+
* on re-add). */
|
|
1776
|
+
_assignLastRunSlot(e) {
|
|
1777
|
+
let n = this.lastRunSlots.get(e);
|
|
1778
|
+
if (n === void 0) {
|
|
1779
|
+
const r = this._driveDepth === 0 ? this.freeLastRunSlots.pop() : void 0;
|
|
1780
|
+
r !== void 0 ? (n = r, this.systemLastRun[n] = 0) : (n = this.systemLastRun.length, this.systemLastRun.push(0)), this.lastRunSlots.set(e, n);
|
|
1781
|
+
}
|
|
1782
|
+
return n;
|
|
1783
|
+
}
|
|
1706
1784
|
clear() {
|
|
1707
1785
|
for (const e of this.labelSystems.values())
|
|
1708
1786
|
e.length = 0;
|
|
1709
|
-
this.sortedCache.clear(), this.systemIndex.clear(), this.systemLastRun.clear(), this.gatedSystems.clear(), this.setConditions.clear(), this.setOrdering.clear();
|
|
1787
|
+
this.sortedCache.clear(), this.systemIndex.clear(), this._driveDepth === 0 ? this.systemLastRun.length = 0 : this.systemLastRun.fill(0), this.lastRunSlots.clear(), this.freeLastRunSlots.length = 0, this.gatedSystems.clear(), this.setConditions.clear(), this.setOrdering.clear();
|
|
1710
1788
|
}
|
|
1711
1789
|
runLabel(e, n, r, s) {
|
|
1712
|
-
const o = this.getSorted(e), i = this.gatedSystems.size > 0,
|
|
1713
|
-
for (let
|
|
1714
|
-
const
|
|
1715
|
-
if (
|
|
1716
|
-
const
|
|
1717
|
-
if (
|
|
1790
|
+
const o = this.getSorted(e), i = o.sorted, a = o.slots, c = this.gatedSystems.size > 0, d = this._backend, l = c ? /* @__PURE__ */ new Map() : void 0;
|
|
1791
|
+
for (let f = 0; f < i.length; f++) {
|
|
1792
|
+
const h = i[f];
|
|
1793
|
+
if (c) {
|
|
1794
|
+
const p = this.gatedSystems.get(h);
|
|
1795
|
+
if (p !== void 0 && !this.shouldRun(p, n, l)) continue;
|
|
1718
1796
|
}
|
|
1719
|
-
n.lastRunTick = this.systemLastRun
|
|
1720
|
-
const
|
|
1721
|
-
Q.enter(
|
|
1797
|
+
n.lastRunTick = this.systemLastRun[a[f]];
|
|
1798
|
+
const g = d !== null ? h.backendHandle : void 0;
|
|
1799
|
+
Q.enter(h), n._trace?.systemStart(h, e);
|
|
1722
1800
|
try {
|
|
1723
|
-
|
|
1801
|
+
g !== void 0 ? d.run(g) : h.fn?.(n, r);
|
|
1724
1802
|
} finally {
|
|
1725
|
-
n._trace?.systemEnd(
|
|
1803
|
+
n._trace?.systemEnd(h), Q.leave();
|
|
1726
1804
|
}
|
|
1727
|
-
this.systemLastRun
|
|
1805
|
+
this.systemLastRun[a[f]] = s;
|
|
1728
1806
|
}
|
|
1729
1807
|
n._trace?.flushBegin(e), n.flush(), n._trace?.flushEnd(e), n._trace?.phaseBoundary(e);
|
|
1730
1808
|
}
|
|
@@ -1736,7 +1814,7 @@ class _s {
|
|
|
1736
1814
|
* memo lives only for a single `runLabel` pass. Short-circuits on the first
|
|
1737
1815
|
* `false`. The system's own conditions evaluate per system, in canonical order.
|
|
1738
1816
|
*
|
|
1739
|
-
*
|
|
1817
|
+
* SEMANTIC NOTE: this evaluates a set's conditions once-per-set-per-phase
|
|
1740
1818
|
* rather than once-per-member. Equivalent for pure RunConditions; observably
|
|
1741
1819
|
* different only if a set condition reads state mutated earlier in the SAME
|
|
1742
1820
|
* phase (resources write immediately). That is intentional — the set gates as a
|
|
@@ -1776,8 +1854,10 @@ class _s {
|
|
|
1776
1854
|
getSorted(e) {
|
|
1777
1855
|
const n = this.sortedCache.get(e);
|
|
1778
1856
|
if (n !== void 0) return n;
|
|
1779
|
-
const r = this.labelSystems.get(e), s = this.sortSystems(r, e);
|
|
1780
|
-
|
|
1857
|
+
const r = this.labelSystems.get(e), s = this.sortSystems(r, e), o = new Int32Array(s.length);
|
|
1858
|
+
for (let a = 0; a < s.length; a++) o[a] = this._assignLastRunSlot(s[a]);
|
|
1859
|
+
const i = { sorted: s, slots: o };
|
|
1860
|
+
return this.sortedCache.set(e, i), i;
|
|
1781
1861
|
}
|
|
1782
1862
|
/**
|
|
1783
1863
|
* Delegates to the shared topologicalSort utility.
|
|
@@ -1787,31 +1867,31 @@ class _s {
|
|
|
1787
1867
|
sortSystems(e, n) {
|
|
1788
1868
|
if (e.length === 0) return [];
|
|
1789
1869
|
const r = [], s = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Map();
|
|
1790
|
-
for (const
|
|
1791
|
-
r.push(
|
|
1792
|
-
for (let f = 0; f <
|
|
1793
|
-
const h =
|
|
1870
|
+
for (const l of e) {
|
|
1871
|
+
r.push(l.descriptor), s.set(l.descriptor, l.insertionOrder), o.add(l.descriptor);
|
|
1872
|
+
for (let f = 0; f < l.sets.length; f++) {
|
|
1873
|
+
const h = l.sets[f];
|
|
1794
1874
|
let g = i.get(h);
|
|
1795
|
-
g === void 0 && (g = [], i.set(h, g)), g.push(
|
|
1875
|
+
g === void 0 && (g = [], i.set(h, g)), g.push(l.descriptor);
|
|
1796
1876
|
}
|
|
1797
1877
|
}
|
|
1798
1878
|
const a = /* @__PURE__ */ new Map();
|
|
1799
|
-
for (const
|
|
1800
|
-
a.set(
|
|
1801
|
-
for (const
|
|
1879
|
+
for (const l of e)
|
|
1880
|
+
a.set(l.descriptor, []);
|
|
1881
|
+
for (const l of e) {
|
|
1802
1882
|
this.resolveEdges(
|
|
1803
|
-
|
|
1804
|
-
|
|
1883
|
+
l.descriptor,
|
|
1884
|
+
l.before,
|
|
1805
1885
|
"before",
|
|
1806
1886
|
o,
|
|
1807
1887
|
i,
|
|
1808
1888
|
a,
|
|
1809
1889
|
n
|
|
1810
|
-
), this.resolveEdges(
|
|
1811
|
-
for (let f = 0; f <
|
|
1812
|
-
const h = this.setOrdering.get(
|
|
1890
|
+
), this.resolveEdges(l.descriptor, l.after, "after", o, i, a, n);
|
|
1891
|
+
for (let f = 0; f < l.sets.length; f++) {
|
|
1892
|
+
const h = this.setOrdering.get(l.sets[f]);
|
|
1813
1893
|
h !== void 0 && (this.resolveEdges(
|
|
1814
|
-
|
|
1894
|
+
l.descriptor,
|
|
1815
1895
|
h.before,
|
|
1816
1896
|
"before",
|
|
1817
1897
|
o,
|
|
@@ -1819,7 +1899,7 @@ class _s {
|
|
|
1819
1899
|
a,
|
|
1820
1900
|
n
|
|
1821
1901
|
), this.resolveEdges(
|
|
1822
|
-
|
|
1902
|
+
l.descriptor,
|
|
1823
1903
|
h.after,
|
|
1824
1904
|
"after",
|
|
1825
1905
|
o,
|
|
@@ -1829,18 +1909,18 @@ class _s {
|
|
|
1829
1909
|
));
|
|
1830
1910
|
}
|
|
1831
1911
|
}
|
|
1832
|
-
const c = (
|
|
1912
|
+
const c = (l, f) => s.get(l) - s.get(f), d = (l) => l.name ?? `system_${l.id}`;
|
|
1833
1913
|
try {
|
|
1834
|
-
return it(r, a, c,
|
|
1835
|
-
} catch (
|
|
1836
|
-
throw
|
|
1837
|
-
|
|
1838
|
-
`Circular system dependency detected in ${n}: ${
|
|
1839
|
-
) :
|
|
1914
|
+
return it(r, a, c, d);
|
|
1915
|
+
} catch (l) {
|
|
1916
|
+
throw l instanceof TypeError ? new T(
|
|
1917
|
+
y.CIRCULAR_SYSTEM_DEPENDENCY,
|
|
1918
|
+
`Circular system dependency detected in ${n}: ${l.message}`
|
|
1919
|
+
) : l;
|
|
1840
1920
|
}
|
|
1841
1921
|
}
|
|
1842
1922
|
/**
|
|
1843
|
-
* Add the topo edges for one ordering list
|
|
1923
|
+
* Add the topo edges for one ordering list. For `"before"` the source
|
|
1844
1924
|
* runs before each target (edge source→target); for `"after"` it runs after
|
|
1845
1925
|
* each target (edge target→source). A `SystemSet` target expands to every
|
|
1846
1926
|
* member within this phase (self-edges skipped, so a member ordered against
|
|
@@ -1851,10 +1931,10 @@ class _s {
|
|
|
1851
1931
|
resolveEdges(e, n, r, s, o, i, a) {
|
|
1852
1932
|
for (const c of n) {
|
|
1853
1933
|
if (En(c)) {
|
|
1854
|
-
const
|
|
1855
|
-
if (
|
|
1856
|
-
for (let
|
|
1857
|
-
const f = l
|
|
1934
|
+
const d = o.get(c);
|
|
1935
|
+
if (d === void 0) continue;
|
|
1936
|
+
for (let l = 0; l < d.length; l++) {
|
|
1937
|
+
const f = d[l];
|
|
1858
1938
|
f !== e && this.addDirectedEdge(e, f, r, i);
|
|
1859
1939
|
}
|
|
1860
1940
|
continue;
|
|
@@ -1890,11 +1970,11 @@ class _s {
|
|
|
1890
1970
|
);
|
|
1891
1971
|
}
|
|
1892
1972
|
}
|
|
1893
|
-
const se = 1024, re = 1024 * se, xe = 64 * se,
|
|
1973
|
+
const se = 1024, re = 1024 * se, xe = 64 * se, W = 256 * re, Be = 3, pn = 64, yn = 8, Fe = 4 * re, ke = (t) => 2 ** Math.ceil(Math.log2(Math.max(1, t))), Z = (t) => 2 ** Math.floor(Math.log2(Math.max(1, t))), k = (t, e, n) => Math.min(n, Math.max(e, t)), S = (t) => t >= re ? `${(t / re).toFixed(1)} MiB` : t >= se ? `${(t / se).toFixed(0)} KiB` : `${t} B`;
|
|
1894
1974
|
function D(t, e) {
|
|
1895
1975
|
if (!Number.isInteger(e) || e <= 0)
|
|
1896
|
-
throw new
|
|
1897
|
-
|
|
1976
|
+
throw new T(
|
|
1977
|
+
y.INVALID_MEMORY_OPTIONS,
|
|
1898
1978
|
`memory.${t} must be a positive integer (got ${e})`
|
|
1899
1979
|
);
|
|
1900
1980
|
}
|
|
@@ -1903,20 +1983,20 @@ function ms(t) {
|
|
|
1903
1983
|
(s) => t !== void 0 && t[s] !== void 0
|
|
1904
1984
|
);
|
|
1905
1985
|
if (e.length > 1)
|
|
1906
|
-
throw new
|
|
1907
|
-
|
|
1986
|
+
throw new T(
|
|
1987
|
+
y.INVALID_MEMORY_OPTIONS,
|
|
1908
1988
|
`memory takes at most one of budget | maxBytes | wasm | allocator | heap | shared (got: ${e.join(", ")})`
|
|
1909
1989
|
);
|
|
1910
1990
|
const n = t?.columnCapacity;
|
|
1911
|
-
if (n !== void 0 && D("
|
|
1991
|
+
if (n !== void 0 && D("columnCapacity", n), t?.budget !== void 0) {
|
|
1912
1992
|
const { entities: s } = t.budget, o = t.budget.archetypes ?? yn, i = t.budget.bytesPerEntity ?? pn;
|
|
1913
|
-
if (D("budget.entities", s), D("budget.archetypes", o), D("budget.
|
|
1914
|
-
throw new
|
|
1915
|
-
|
|
1993
|
+
if (D("budget.entities", s), D("budget.archetypes", o), D("budget.bytesPerEntity", i), s > 1 << 20)
|
|
1994
|
+
throw new T(
|
|
1995
|
+
y.INVALID_MEMORY_OPTIONS,
|
|
1916
1996
|
`memory.budget.entities=${s} exceeds the EntityID index space (1<<20 = ${1 << 20})`
|
|
1917
1997
|
);
|
|
1918
|
-
const a = n ?? k(ke(Math.ceil(s / o)), 64, 1 << 20), c = k(ke(s * 2), 4096, 1 << 20),
|
|
1919
|
-
Math.max(
|
|
1998
|
+
const a = n ?? k(ke(Math.ceil(s / o)), 64, 1 << 20), c = k(ke(s * 2), 4096, 1 << 20), d = c * R, l = s * i * Be, f = Ke(
|
|
1999
|
+
Math.max(d + l, Fe),
|
|
1920
2000
|
xe
|
|
1921
2001
|
);
|
|
1922
2002
|
return {
|
|
@@ -1928,9 +2008,9 @@ function ms(t) {
|
|
|
1928
2008
|
intentLabel: `budget of ${s} entities`,
|
|
1929
2009
|
budgetEntities: s,
|
|
1930
2010
|
derivation: [
|
|
1931
|
-
`
|
|
1932
|
-
`
|
|
1933
|
-
`columns = ${s} × ${i} B × ${Be} (double+holes headroom) = ${S(
|
|
2011
|
+
`columnCapacity = ${n !== void 0 ? `${a} (pinned)` : `pow2(${s}/${o} per archetype) = ${a}`}`,
|
|
2012
|
+
`entityIndex = pow2(2 × ${s}) = ${c} slots × ${R} B = ${S(d)}`,
|
|
2013
|
+
`columns = ${s} × ${i} B × ${Be} (double+holes headroom) = ${S(l)}`,
|
|
1934
2014
|
`cap = align64K(max(index + columns, ${S(Fe)} floor)) = ${S(f)}`
|
|
1935
2015
|
],
|
|
1936
2016
|
wasmMemory: null
|
|
@@ -1944,7 +2024,7 @@ function ms(t) {
|
|
|
1944
2024
|
U
|
|
1945
2025
|
);
|
|
1946
2026
|
return {
|
|
1947
|
-
source: "
|
|
2027
|
+
source: "maxBytes",
|
|
1948
2028
|
allocator: j(t.maxBytes),
|
|
1949
2029
|
columnCapacity: s,
|
|
1950
2030
|
entityIndexCapacity: o,
|
|
@@ -1953,8 +2033,8 @@ function ms(t) {
|
|
|
1953
2033
|
budgetEntities: null,
|
|
1954
2034
|
derivation: [
|
|
1955
2035
|
`cap = ${S(t.maxBytes)} (caller-declared)`,
|
|
1956
|
-
`
|
|
1957
|
-
`
|
|
2036
|
+
`columnCapacity = ${s} (${n !== void 0 ? "pinned" : "default"})`,
|
|
2037
|
+
`entityIndex = floor_pow2(cap/4 ÷ ${R} B) = ${o} slots`
|
|
1958
2038
|
],
|
|
1959
2039
|
wasmMemory: null
|
|
1960
2040
|
};
|
|
@@ -1963,9 +2043,9 @@ function ms(t) {
|
|
|
1963
2043
|
const s = t.wasm, o = n ?? F;
|
|
1964
2044
|
if (s.memory !== void 0) {
|
|
1965
2045
|
if (!(s.memory.buffer instanceof SharedArrayBuffer))
|
|
1966
|
-
throw new
|
|
1967
|
-
|
|
1968
|
-
"memory.wasm.memory must be constructed with `shared: true` — the SAB substrate requires a SharedArrayBuffer-backed WebAssembly.Memory
|
|
2046
|
+
throw new T(
|
|
2047
|
+
y.INVALID_MEMORY_OPTIONS,
|
|
2048
|
+
"memory.wasm.memory must be constructed with `shared: true` — the SAB substrate requires a SharedArrayBuffer-backed WebAssembly.Memory"
|
|
1969
2049
|
);
|
|
1970
2050
|
return {
|
|
1971
2051
|
source: "wasm",
|
|
@@ -1979,23 +2059,23 @@ function ms(t) {
|
|
|
1979
2059
|
derivation: [
|
|
1980
2060
|
"backing = wasm_memory_allocator(memory) — zero-copy with the sim (is_in_place ✓)",
|
|
1981
2061
|
"cap = the Memory's own `maximum` (declared by the caller; not readable from JS)",
|
|
1982
|
-
`
|
|
2062
|
+
`columnCapacity = ${o} (${n !== void 0 ? "pinned" : "default"})`
|
|
1983
2063
|
],
|
|
1984
2064
|
wasmMemory: s.memory
|
|
1985
2065
|
};
|
|
1986
2066
|
}
|
|
1987
|
-
D("wasm.
|
|
2067
|
+
D("wasm.maximumPages", s.maximumPages);
|
|
1988
2068
|
const i = s.initialPages ?? Math.min(32, s.maximumPages);
|
|
1989
|
-
if (D("wasm.
|
|
1990
|
-
throw new
|
|
1991
|
-
|
|
1992
|
-
`memory.wasm.
|
|
2069
|
+
if (D("wasm.initialPages", i), i > s.maximumPages)
|
|
2070
|
+
throw new T(
|
|
2071
|
+
y.INVALID_MEMORY_OPTIONS,
|
|
2072
|
+
`memory.wasm.initialPages (${i}) exceeds maximumPages (${s.maximumPages})`
|
|
1993
2073
|
);
|
|
1994
2074
|
const a = new WebAssembly.Memory({
|
|
1995
2075
|
initial: i,
|
|
1996
2076
|
maximum: s.maximumPages,
|
|
1997
2077
|
shared: !0
|
|
1998
|
-
}), c = s.maximumPages * xe,
|
|
2078
|
+
}), c = s.maximumPages * xe, d = k(
|
|
1999
2079
|
Z(c / 4 / R),
|
|
2000
2080
|
4096,
|
|
2001
2081
|
U
|
|
@@ -2004,27 +2084,27 @@ function ms(t) {
|
|
|
2004
2084
|
source: "wasm",
|
|
2005
2085
|
allocator: Ne(a),
|
|
2006
2086
|
columnCapacity: o,
|
|
2007
|
-
entityIndexCapacity:
|
|
2087
|
+
entityIndexCapacity: d,
|
|
2008
2088
|
capBytes: c,
|
|
2009
2089
|
intentLabel: `engine-constructed WebAssembly.Memory (max ${s.maximumPages} pages)`,
|
|
2010
2090
|
budgetEntities: null,
|
|
2011
2091
|
derivation: [
|
|
2012
2092
|
`cap = ${s.maximumPages} pages × 64 KiB = ${S(c)} (Memory maximum)`,
|
|
2013
2093
|
`initial = ${i} pages (${s.initialPages !== void 0 ? "declared" : "default"})`,
|
|
2014
|
-
`
|
|
2015
|
-
`
|
|
2094
|
+
`entityIndex = floor_pow2(cap/4 ÷ ${R} B) = ${d} slots`,
|
|
2095
|
+
`columnCapacity = ${o} (${n !== void 0 ? "pinned" : "default"})`
|
|
2016
2096
|
],
|
|
2017
2097
|
wasmMemory: a
|
|
2018
2098
|
};
|
|
2019
2099
|
}
|
|
2020
2100
|
if (t?.allocator !== void 0) {
|
|
2021
2101
|
if (t.allocator.isInPlace !== !0)
|
|
2022
|
-
throw new
|
|
2023
|
-
|
|
2024
|
-
"memory.allocator must declare `
|
|
2102
|
+
throw new T(
|
|
2103
|
+
y.INVALID_MEMORY_OPTIONS,
|
|
2104
|
+
"memory.allocator must declare `isInPlace: true`: a live Store's flush loops hoist entity-index views across grows, so a non-in-place allocator (e.g. DEFAULT_SAB_ALLOCATOR) corrupts the entity→row mapping. Use growableSabAllocator / wasmMemoryAllocator; non-in-place allocators are snapshot/test sizing only."
|
|
2025
2105
|
);
|
|
2026
2106
|
const s = n ?? F, o = t.capBytesHint;
|
|
2027
|
-
return o !== void 0 && D("
|
|
2107
|
+
return o !== void 0 && D("capBytesHint", o), {
|
|
2028
2108
|
source: "allocator",
|
|
2029
2109
|
allocator: t.allocator,
|
|
2030
2110
|
columnCapacity: s,
|
|
@@ -2035,14 +2115,14 @@ function ms(t) {
|
|
|
2035
2115
|
derivation: [
|
|
2036
2116
|
"backing = caller allocator (is_in_place ✓ checked at construction)",
|
|
2037
2117
|
o !== void 0 ? `cap = ${S(o)} (caller hint — diagnostics only; the allocator owns the real cap)` : "cap = allocator-owned (no hint)",
|
|
2038
|
-
`
|
|
2118
|
+
`columnCapacity = ${s} (${n !== void 0 ? "pinned" : "default"})`
|
|
2039
2119
|
],
|
|
2040
2120
|
wasmMemory: null
|
|
2041
2121
|
};
|
|
2042
2122
|
}
|
|
2043
2123
|
if (t?.heap !== void 0) {
|
|
2044
2124
|
t.heap.maxBytes !== void 0 && D("heap.maxBytes", t.heap.maxBytes);
|
|
2045
|
-
const s = t.heap.maxBytes ??
|
|
2125
|
+
const s = t.heap.maxBytes ?? W, o = n ?? F, i = k(
|
|
2046
2126
|
Z(s / 4 / R),
|
|
2047
2127
|
4096,
|
|
2048
2128
|
U
|
|
@@ -2056,17 +2136,17 @@ function ms(t) {
|
|
|
2056
2136
|
intentLabel: `pure-TS heap backing (${S(s)} growable cap, no SharedArrayBuffer)`,
|
|
2057
2137
|
budgetEntities: null,
|
|
2058
2138
|
derivation: [
|
|
2059
|
-
`backing = heap_arraybuffer_allocator(${S(s)}) —
|
|
2139
|
+
`backing = heap_arraybuffer_allocator(${S(s)}) — fixed ArrayBuffer reserved at the cap, no SAB / no COOP+COEP (is_in_place ✓)`,
|
|
2060
2140
|
"trade-off: no worker offload / no WASM backend (both need a transferable SharedArrayBuffer)",
|
|
2061
|
-
`
|
|
2062
|
-
`
|
|
2141
|
+
`columnCapacity = ${o} (${n !== void 0 ? "pinned" : "default"})`,
|
|
2142
|
+
`entityIndex = floor_pow2(cap/4 ÷ ${R} B) = ${i} slots`
|
|
2063
2143
|
],
|
|
2064
2144
|
wasmMemory: null
|
|
2065
2145
|
};
|
|
2066
2146
|
}
|
|
2067
2147
|
if (t?.shared !== void 0) {
|
|
2068
2148
|
t.shared.maxBytes !== void 0 && D("shared.maxBytes", t.shared.maxBytes);
|
|
2069
|
-
const s = t.shared.maxBytes ??
|
|
2149
|
+
const s = t.shared.maxBytes ?? W, o = n ?? F, i = k(
|
|
2070
2150
|
Z(s / 4 / R),
|
|
2071
2151
|
4096,
|
|
2072
2152
|
U
|
|
@@ -2082,8 +2162,8 @@ function ms(t) {
|
|
|
2082
2162
|
derivation: [
|
|
2083
2163
|
`backing = growable_sab_allocator(${S(s)}) — growable SharedArrayBuffer (is_in_place ✓); needs cross-origin isolation`,
|
|
2084
2164
|
"enables worker offload + a WASM compute backend (transferable SharedArrayBuffer)",
|
|
2085
|
-
`
|
|
2086
|
-
`
|
|
2165
|
+
`columnCapacity = ${o} (${n !== void 0 ? "pinned" : "default"})`,
|
|
2166
|
+
`entityIndex = floor_pow2(cap/4 ÷ ${R} B) = ${i} slots`
|
|
2087
2167
|
],
|
|
2088
2168
|
wasmMemory: null
|
|
2089
2169
|
};
|
|
@@ -2094,13 +2174,13 @@ function ms(t) {
|
|
|
2094
2174
|
allocator: j(),
|
|
2095
2175
|
columnCapacity: r,
|
|
2096
2176
|
entityIndexCapacity: U,
|
|
2097
|
-
capBytes:
|
|
2098
|
-
intentLabel: `default sizing (${S(
|
|
2177
|
+
capBytes: W,
|
|
2178
|
+
intentLabel: `default sizing (${S(W)} growable cap)`,
|
|
2099
2179
|
budgetEntities: null,
|
|
2100
2180
|
derivation: [
|
|
2101
|
-
`cap = ${S(
|
|
2102
|
-
`
|
|
2103
|
-
`
|
|
2181
|
+
`cap = ${S(W)} (heap_arraybuffer_allocator default)`,
|
|
2182
|
+
`columnCapacity = ${r} (${n !== void 0 ? "pinned" : "DEFAULT_COLUMN_CAPACITY"})`,
|
|
2183
|
+
`entityIndex = ${U} slots (full EntityID space, ~12 MiB virtual)`
|
|
2104
2184
|
],
|
|
2105
2185
|
wasmMemory: null
|
|
2106
2186
|
};
|
|
@@ -2127,9 +2207,9 @@ function he(t, e) {
|
|
|
2127
2207
|
return;
|
|
2128
2208
|
case "set_field":
|
|
2129
2209
|
if (!t.hasComponent(e.eid, e.def))
|
|
2130
|
-
throw new
|
|
2131
|
-
|
|
2132
|
-
`host set_field on entity ${e.eid} targets a component it does not have. If you added that component via a host command this same frame, the add is deferred to the phase flush while set_field is immediate — carry the value in add_component/
|
|
2210
|
+
throw new T(
|
|
2211
|
+
y.COMPONENT_NOT_REGISTERED,
|
|
2212
|
+
`host set_field on entity ${e.eid} targets a component it does not have. If you added that component via a host command this same frame, the add is deferred to the phase flush while set_field is immediate — carry the value in add_component/spawnEntry instead of a separate set_field, or set it next frame. (host write seam)`
|
|
2133
2213
|
);
|
|
2134
2214
|
t.setField(e.eid, e.def, e.field, e.value);
|
|
2135
2215
|
return;
|
|
@@ -2190,7 +2270,7 @@ class Tn {
|
|
|
2190
2270
|
get pending() {
|
|
2191
2271
|
return this.queued.length;
|
|
2192
2272
|
}
|
|
2193
|
-
/** Drop every buffered command without applying it
|
|
2273
|
+
/** Drop every buffered command without applying it — e.g. abandoning
|
|
2194
2274
|
* queued edits on a scene unload. Returns how many were dropped. Does not
|
|
2195
2275
|
* touch commands already drained into the world. */
|
|
2196
2276
|
clear() {
|
|
@@ -2205,7 +2285,7 @@ class Tn {
|
|
|
2205
2285
|
* `tap`, when present, is invoked with each command in apply order just before
|
|
2206
2286
|
* it is applied — the record/replay hook ({@link HostCommandRecorder}). It is
|
|
2207
2287
|
* an OPT-IN observer: the tap-free path keeps the original tight loop, so an
|
|
2208
|
-
* un-recorded drain pays nothing
|
|
2288
|
+
* un-recorded drain pays nothing.
|
|
2209
2289
|
*/
|
|
2210
2290
|
drain(e, n) {
|
|
2211
2291
|
const r = this.queued.length;
|
|
@@ -2224,10 +2304,10 @@ const nt = P - 1;
|
|
|
2224
2304
|
function An(t) {
|
|
2225
2305
|
if (t === ye)
|
|
2226
2306
|
throw new v(
|
|
2227
|
-
"cannot bind
|
|
2307
|
+
"cannot bind opCode 0 (reserved as the command-ring empty-slot marker)"
|
|
2228
2308
|
);
|
|
2229
2309
|
if (t < 0 || t > 255 || !Number.isInteger(t))
|
|
2230
|
-
throw new v(`command
|
|
2310
|
+
throw new v(`command opCode must be a u8 in [1, 255] (got ${t})`);
|
|
2231
2311
|
}
|
|
2232
2312
|
function ae(t) {
|
|
2233
2313
|
const e = new Uint8Array(nt);
|
|
@@ -2265,7 +2345,7 @@ function ps() {
|
|
|
2265
2345
|
encode(t) {
|
|
2266
2346
|
if (t.kind !== "despawn")
|
|
2267
2347
|
throw new v(
|
|
2268
|
-
`
|
|
2348
|
+
`ringDespawnCodec encodes a "despawn" command (got "${t.kind}")`
|
|
2269
2349
|
);
|
|
2270
2350
|
return ae(t.eid);
|
|
2271
2351
|
},
|
|
@@ -2277,7 +2357,7 @@ function ys() {
|
|
|
2277
2357
|
encode(t) {
|
|
2278
2358
|
if (t.kind !== "disable")
|
|
2279
2359
|
throw new v(
|
|
2280
|
-
`
|
|
2360
|
+
`ringDisableCodec encodes a "disable" command (got "${t.kind}")`
|
|
2281
2361
|
);
|
|
2282
2362
|
return ae(t.eid);
|
|
2283
2363
|
},
|
|
@@ -2289,7 +2369,7 @@ function Ts() {
|
|
|
2289
2369
|
encode(t) {
|
|
2290
2370
|
if (t.kind !== "enable")
|
|
2291
2371
|
throw new v(
|
|
2292
|
-
`
|
|
2372
|
+
`ringEnableCodec encodes an "enable" command (got "${t.kind}")`
|
|
2293
2373
|
);
|
|
2294
2374
|
return ae(t.eid);
|
|
2295
2375
|
},
|
|
@@ -2314,14 +2394,14 @@ class Is {
|
|
|
2314
2394
|
on(e, n) {
|
|
2315
2395
|
return An(e), this.appliers.set(e, n), this;
|
|
2316
2396
|
}
|
|
2317
|
-
/** Unbind `opCode
|
|
2397
|
+
/** Unbind `opCode`. Returns whether a binding was removed; subsequent
|
|
2318
2398
|
* slots carrying it hit the unknown-opcode path. */
|
|
2319
2399
|
off(e) {
|
|
2320
2400
|
return this.appliers.delete(e);
|
|
2321
2401
|
}
|
|
2322
2402
|
/** Bind a `HostCommand` codec to `opCode`: each matching slot is decoded and
|
|
2323
2403
|
* run through `applyHostCommand` — the SAME dispatch the typed queue uses.
|
|
2324
|
-
* A drain-time `tap` (record/replay
|
|
2404
|
+
* A drain-time `tap` (record/replay) sees the decoded command before it
|
|
2325
2405
|
* applies, so ring-sourced commands share one log with the typed transport. */
|
|
2326
2406
|
onCommand(e, n) {
|
|
2327
2407
|
return this.on(e, (r, s, o) => {
|
|
@@ -2332,7 +2412,7 @@ class Is {
|
|
|
2332
2412
|
/** Drain every pending slot, dispatching each to its bound applier. Unbound
|
|
2333
2413
|
* opcodes are skipped (the read head still advances — matching
|
|
2334
2414
|
* `drainCommandRing` / `CommandDispatcher`). Returns slots drained. `tap`,
|
|
2335
|
-
* when present, is forwarded to each applier as the record/replay hook
|
|
2415
|
+
* when present, is forwarded to each applier as the record/replay hook;
|
|
2336
2416
|
* only `onCommand`-bound (generic `HostCommand`) opcodes surface to it. */
|
|
2337
2417
|
drain(e, n, r, s) {
|
|
2338
2418
|
return Ot(n, r, (o, i) => {
|
|
@@ -2357,13 +2437,13 @@ function Ss(t, e) {
|
|
|
2357
2437
|
_e.set(n, r);
|
|
2358
2438
|
const s = e?.name ?? "host_command_apply", o = e?.ring, i = e?.recorder, a = i?.record, c = e?.schedules ?? [x.PRE_STARTUP, x.PRE_UPDATE];
|
|
2359
2439
|
if (i !== void 0 && c.includes(x.FIXED_UPDATE))
|
|
2360
|
-
throw new
|
|
2361
|
-
|
|
2440
|
+
throw new T(
|
|
2441
|
+
y.INVALID_RECORDER_SCHEDULE,
|
|
2362
2442
|
"install_host_command_seam: a recorder cannot drain on SCHEDULE.FIXED_UPDATE — it would log the fixed-step dt instead of the host update(dt) and diverge on replay. Use a variable-update phase (PRE_UPDATE/UPDATE/POST_UPDATE)."
|
|
2363
2443
|
);
|
|
2364
|
-
for (const
|
|
2365
|
-
const
|
|
2366
|
-
name: `${s}:${
|
|
2444
|
+
for (const d of c) {
|
|
2445
|
+
const l = !In.has(d), f = t.registerSystem({
|
|
2446
|
+
name: `${s}:${d}`,
|
|
2367
2447
|
// `reads`/`writes` are required by `SystemConfig` but empty here: the
|
|
2368
2448
|
// apply system declares nothing because it mutates components not known
|
|
2369
2449
|
// at registration. Full world access: the host may queue mutations to
|
|
@@ -2373,13 +2453,13 @@ function Ss(t, e) {
|
|
|
2373
2453
|
writes: [],
|
|
2374
2454
|
exclusive: !0,
|
|
2375
2455
|
fn: (h, g) => {
|
|
2376
|
-
if (i !== void 0 &&
|
|
2377
|
-
const
|
|
2378
|
-
u !== 0 && o.drain(h,
|
|
2456
|
+
if (i !== void 0 && l && i.openTick(h.ecsTick, g), n.drain(h, a), o !== void 0) {
|
|
2457
|
+
const p = t.columnStore, u = p.header.commandRingOff;
|
|
2458
|
+
u !== 0 && o.drain(h, p.view, u, a);
|
|
2379
2459
|
}
|
|
2380
2460
|
}
|
|
2381
2461
|
});
|
|
2382
|
-
t.addSystems(
|
|
2462
|
+
t.addSystems(d, f), r.push(f);
|
|
2383
2463
|
}
|
|
2384
2464
|
return n;
|
|
2385
2465
|
}
|
|
@@ -2389,23 +2469,23 @@ export {
|
|
|
2389
2469
|
N as B,
|
|
2390
2470
|
pt as C,
|
|
2391
2471
|
F as D,
|
|
2392
|
-
|
|
2393
|
-
|
|
2472
|
+
T as E,
|
|
2473
|
+
Ge as F,
|
|
2394
2474
|
ie as G,
|
|
2395
2475
|
te as H,
|
|
2396
2476
|
$n as I,
|
|
2397
2477
|
os as J,
|
|
2398
2478
|
ls as K,
|
|
2399
|
-
|
|
2479
|
+
A as L,
|
|
2400
2480
|
is as M,
|
|
2401
2481
|
vn as N,
|
|
2402
2482
|
us as O,
|
|
2403
2483
|
as as P,
|
|
2404
|
-
|
|
2484
|
+
Wn as Q,
|
|
2405
2485
|
nn as R,
|
|
2406
2486
|
m as S,
|
|
2407
2487
|
Oe as T,
|
|
2408
|
-
|
|
2488
|
+
bn as U,
|
|
2409
2489
|
ee as V,
|
|
2410
2490
|
U as W,
|
|
2411
2491
|
jn as X,
|
|
@@ -2418,8 +2498,8 @@ export {
|
|
|
2418
2498
|
Un as a2,
|
|
2419
2499
|
De as a3,
|
|
2420
2500
|
Re as a4,
|
|
2421
|
-
|
|
2422
|
-
|
|
2501
|
+
He as a5,
|
|
2502
|
+
Xn as a6,
|
|
2423
2503
|
Vn as a7,
|
|
2424
2504
|
rs as a8,
|
|
2425
2505
|
z as a9,
|
|
@@ -2450,8 +2530,8 @@ export {
|
|
|
2450
2530
|
Tn as aq,
|
|
2451
2531
|
gs as ar,
|
|
2452
2532
|
Me as as,
|
|
2453
|
-
|
|
2454
|
-
|
|
2533
|
+
Cn as at,
|
|
2534
|
+
W as au,
|
|
2455
2535
|
Be as av,
|
|
2456
2536
|
pn as aw,
|
|
2457
2537
|
yn as ax,
|
|
@@ -2461,19 +2541,19 @@ export {
|
|
|
2461
2541
|
ht as c,
|
|
2462
2542
|
zn as d,
|
|
2463
2543
|
en as e,
|
|
2464
|
-
|
|
2544
|
+
y as f,
|
|
2465
2545
|
L as g,
|
|
2466
2546
|
Q as h,
|
|
2467
2547
|
Rn as i,
|
|
2468
2548
|
Qt as j,
|
|
2469
|
-
|
|
2549
|
+
Hn as k,
|
|
2470
2550
|
cs as l,
|
|
2471
2551
|
ds as m,
|
|
2472
2552
|
Yn as n,
|
|
2473
2553
|
kn as o,
|
|
2474
2554
|
Bn as p,
|
|
2475
2555
|
ns as q,
|
|
2476
|
-
|
|
2556
|
+
Gn as r,
|
|
2477
2557
|
Ke as s,
|
|
2478
2558
|
Ae as t,
|
|
2479
2559
|
On as u,
|