@oasys/oecs 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/README.md +196 -267
  2. package/dist/array-CxbPyiHO.cjs +1 -0
  3. package/dist/array-uFR7Q8fU.js +132 -0
  4. package/dist/core/ecs/access_check.d.ts +77 -0
  5. package/dist/core/ecs/access_check.d.ts.map +1 -0
  6. package/dist/core/ecs/archetype.d.ts +474 -0
  7. package/dist/core/ecs/archetype.d.ts.map +1 -0
  8. package/dist/core/ecs/builtin_relations.d.ts +43 -0
  9. package/dist/core/ecs/builtin_relations.d.ts.map +1 -0
  10. package/dist/core/ecs/command_log.d.ts +113 -0
  11. package/dist/core/ecs/command_log.d.ts.map +1 -0
  12. package/dist/core/ecs/component.d.ts +106 -0
  13. package/dist/core/ecs/component.d.ts.map +1 -0
  14. package/dist/core/ecs/compute_backend.d.ts +37 -0
  15. package/dist/core/ecs/compute_backend.d.ts.map +1 -0
  16. package/dist/core/ecs/dispatch_trace.d.ts +93 -0
  17. package/dist/core/ecs/dispatch_trace.d.ts.map +1 -0
  18. package/dist/core/ecs/ecs.d.ts +533 -0
  19. package/dist/core/ecs/ecs.d.ts.map +1 -0
  20. package/dist/core/ecs/ecs_memory.d.ts +179 -0
  21. package/dist/core/ecs/ecs_memory.d.ts.map +1 -0
  22. package/dist/core/ecs/entity.d.ts +28 -0
  23. package/dist/core/ecs/entity.d.ts.map +1 -0
  24. package/dist/core/ecs/event.d.ts +54 -0
  25. package/dist/core/ecs/event.d.ts.map +1 -0
  26. package/dist/core/ecs/frame_trace.d.ts +133 -0
  27. package/dist/core/ecs/frame_trace.d.ts.map +1 -0
  28. package/dist/core/ecs/host_commands.d.ts +252 -0
  29. package/dist/core/ecs/host_commands.d.ts.map +1 -0
  30. package/dist/core/ecs/index.d.ts +41 -0
  31. package/dist/core/ecs/index.d.ts.map +1 -0
  32. package/dist/core/ecs/observer.d.ts +142 -0
  33. package/dist/core/ecs/observer.d.ts.map +1 -0
  34. package/dist/core/ecs/query.d.ts +557 -0
  35. package/dist/core/ecs/query.d.ts.map +1 -0
  36. package/dist/core/ecs/ref.d.ts +31 -0
  37. package/dist/core/ecs/ref.d.ts.map +1 -0
  38. package/dist/core/ecs/relation.d.ts +231 -0
  39. package/dist/core/ecs/relation.d.ts.map +1 -0
  40. package/dist/core/ecs/resource.d.ts +33 -0
  41. package/dist/core/ecs/resource.d.ts.map +1 -0
  42. package/dist/core/ecs/resume.d.ts +85 -0
  43. package/dist/core/ecs/resume.d.ts.map +1 -0
  44. package/dist/core/ecs/run_condition.d.ts +75 -0
  45. package/dist/core/ecs/run_condition.d.ts.map +1 -0
  46. package/dist/core/ecs/schedule.d.ts +133 -0
  47. package/dist/core/ecs/schedule.d.ts.map +1 -0
  48. package/dist/core/ecs/sparse_store.d.ts +107 -0
  49. package/dist/core/ecs/sparse_store.d.ts.map +1 -0
  50. package/dist/core/ecs/store.d.ts +1149 -0
  51. package/dist/core/ecs/store.d.ts.map +1 -0
  52. package/dist/core/ecs/store_layout_listener.d.ts +23 -0
  53. package/dist/core/ecs/store_layout_listener.d.ts.map +1 -0
  54. package/dist/core/ecs/system.d.ts +134 -0
  55. package/dist/core/ecs/system.d.ts.map +1 -0
  56. package/dist/core/ecs/utils/arrays.d.ts +7 -0
  57. package/dist/core/ecs/utils/arrays.d.ts.map +1 -0
  58. package/dist/core/ecs/utils/constants.d.ts +12 -0
  59. package/dist/core/ecs/utils/constants.d.ts.map +1 -0
  60. package/dist/core/ecs/utils/error.d.ts +51 -0
  61. package/dist/core/ecs/utils/error.d.ts.map +1 -0
  62. package/dist/core/reactive/array.d.ts +24 -0
  63. package/dist/core/reactive/array.d.ts.map +1 -0
  64. package/dist/core/reactive/index.cjs +1 -0
  65. package/dist/core/reactive/index.d.ts +10 -0
  66. package/dist/core/reactive/index.d.ts.map +1 -0
  67. package/dist/core/reactive/index.js +17 -0
  68. package/dist/core/reactive/interop.d.ts +19 -0
  69. package/dist/core/reactive/interop.d.ts.map +1 -0
  70. package/dist/core/reactive/kernel.d.ts +71 -0
  71. package/dist/core/reactive/kernel.d.ts.map +1 -0
  72. package/dist/core/reactive/map.d.ts +16 -0
  73. package/dist/core/reactive/map.d.ts.map +1 -0
  74. package/dist/core/reactive/struct.d.ts +10 -0
  75. package/dist/core/reactive/struct.d.ts.map +1 -0
  76. package/dist/core/store/__generated__/abi.d.ts +43 -0
  77. package/dist/core/store/__generated__/abi.d.ts.map +1 -0
  78. package/dist/core/store/action_ring.d.ts +136 -0
  79. package/dist/core/store/action_ring.d.ts.map +1 -0
  80. package/dist/core/store/allocator.d.ts +238 -0
  81. package/dist/core/store/allocator.d.ts.map +1 -0
  82. package/dist/core/store/buffer_backed_column.d.ts +69 -0
  83. package/dist/core/store/buffer_backed_column.d.ts.map +1 -0
  84. package/dist/core/store/column_store.d.ts +265 -0
  85. package/dist/core/store/column_store.d.ts.map +1 -0
  86. package/dist/core/store/command_dispatch.d.ts +52 -0
  87. package/dist/core/store/command_dispatch.d.ts.map +1 -0
  88. package/dist/core/store/command_ring.d.ts +107 -0
  89. package/dist/core/store/command_ring.d.ts.map +1 -0
  90. package/dist/core/store/descriptor.d.ts +80 -0
  91. package/dist/core/store/descriptor.d.ts.map +1 -0
  92. package/dist/core/store/entity_index.d.ts +108 -0
  93. package/dist/core/store/entity_index.d.ts.map +1 -0
  94. package/dist/core/store/event_ring.d.ts +95 -0
  95. package/dist/core/store/event_ring.d.ts.map +1 -0
  96. package/dist/core/store/extend.d.ts +109 -0
  97. package/dist/core/store/extend.d.ts.map +1 -0
  98. package/dist/core/store/grow.d.ts +39 -0
  99. package/dist/core/store/grow.d.ts.map +1 -0
  100. package/dist/core/store/header.d.ts +64 -0
  101. package/dist/core/store/header.d.ts.map +1 -0
  102. package/dist/core/store/index.d.ts +16 -0
  103. package/dist/core/store/index.d.ts.map +1 -0
  104. package/dist/core/store/region_table.d.ts +74 -0
  105. package/dist/core/store/region_table.d.ts.map +1 -0
  106. package/dist/core/store/snapshot.d.ts +43 -0
  107. package/dist/core/store/snapshot.d.ts.map +1 -0
  108. package/dist/core/store/state_hash.d.ts +38 -0
  109. package/dist/core/store/state_hash.d.ts.map +1 -0
  110. package/dist/core/store/store_regions.d.ts +38 -0
  111. package/dist/core/store/store_regions.d.ts.map +1 -0
  112. package/dist/extensions/editor/editor.d.ts +149 -0
  113. package/dist/extensions/editor/editor.d.ts.map +1 -0
  114. package/dist/extensions/editor/field_handle.d.ts +35 -0
  115. package/dist/extensions/editor/field_handle.d.ts.map +1 -0
  116. package/dist/extensions/editor/index.cjs +1 -0
  117. package/dist/extensions/editor/index.d.ts +21 -0
  118. package/dist/extensions/editor/index.d.ts.map +1 -0
  119. package/dist/extensions/editor/index.js +209 -0
  120. package/dist/extensions/reactive/ecs_sync.d.ts +210 -0
  121. package/dist/extensions/reactive/ecs_sync.d.ts.map +1 -0
  122. package/dist/extensions/reactive/index.cjs +1 -0
  123. package/dist/extensions/reactive/index.d.ts +23 -0
  124. package/dist/extensions/reactive/index.d.ts.map +1 -0
  125. package/dist/extensions/reactive/index.js +225 -0
  126. package/dist/extensions/solid/index.cjs +1 -0
  127. package/dist/extensions/solid/index.d.ts +6 -0
  128. package/dist/extensions/solid/index.d.ts.map +1 -0
  129. package/dist/extensions/solid/index.js +32 -0
  130. package/dist/extensions/solid/kernel_solid.d.ts +42 -0
  131. package/dist/extensions/solid/kernel_solid.d.ts.map +1 -0
  132. package/dist/index.cjs +2 -1
  133. package/dist/index.d.ts +16 -12
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +8565 -1310
  136. package/dist/interop-CT-REx0W.cjs +1 -0
  137. package/dist/interop-CcY6ASQc.js +18 -0
  138. package/dist/kernel-DgyrLFjW.js +227 -0
  139. package/dist/kernel-yWV3XnAb.cjs +1 -0
  140. package/dist/log/console_sink.d.ts +4 -0
  141. package/dist/log/console_sink.d.ts.map +1 -0
  142. package/dist/log/index.d.ts +3 -0
  143. package/dist/log/index.d.ts.map +1 -0
  144. package/dist/log/logger.d.ts +27 -0
  145. package/dist/log/logger.d.ts.map +1 -0
  146. package/dist/primitives.cjs +1 -0
  147. package/dist/primitives.d.ts +18 -0
  148. package/dist/primitives.d.ts.map +1 -0
  149. package/dist/primitives.js +44 -0
  150. package/dist/shared-BXSZnxx4.cjs +1 -0
  151. package/dist/shared-C678TAPY.js +99 -0
  152. package/dist/shared.cjs +1 -0
  153. package/dist/shared.d.ts +22 -0
  154. package/dist/shared.d.ts.map +1 -0
  155. package/dist/shared.js +7 -0
  156. package/dist/topological_sort-DlRpSrxu.js +391 -0
  157. package/dist/topological_sort-WAT-VHb-.cjs +1 -0
  158. package/dist/type_primitives/assertions.d.ts +12 -8
  159. package/dist/type_primitives/assertions.d.ts.map +1 -1
  160. package/dist/type_primitives/binary_heap/binary_heap.d.ts +6 -2
  161. package/dist/type_primitives/binary_heap/binary_heap.d.ts.map +1 -1
  162. package/dist/type_primitives/bitset/bitset.d.ts +16 -4
  163. package/dist/type_primitives/bitset/bitset.d.ts.map +1 -1
  164. package/dist/type_primitives/brand.d.ts +6 -1
  165. package/dist/type_primitives/brand.d.ts.map +1 -1
  166. package/dist/type_primitives/error.d.ts +4 -0
  167. package/dist/type_primitives/error.d.ts.map +1 -1
  168. package/dist/type_primitives/index.d.ts +3 -0
  169. package/dist/type_primitives/index.d.ts.map +1 -1
  170. package/dist/type_primitives/sparse_map/sparse_map.d.ts +7 -3
  171. package/dist/type_primitives/sparse_map/sparse_map.d.ts.map +1 -1
  172. package/dist/type_primitives/sparse_set/sparse_set.d.ts +4 -0
  173. package/dist/type_primitives/sparse_set/sparse_set.d.ts.map +1 -1
  174. package/dist/type_primitives/topological_sort/topological_sort.d.ts +7 -3
  175. package/dist/type_primitives/topological_sort/topological_sort.d.ts.map +1 -1
  176. package/dist/type_primitives/typed_arrays/typed_arrays.d.ts +53 -16
  177. package/dist/type_primitives/typed_arrays/typed_arrays.d.ts.map +1 -1
  178. package/dist/utils/arrays.d.ts +1 -1
  179. package/dist/utils/arrays.d.ts.map +1 -1
  180. package/dist/utils/error.d.ts +2 -20
  181. package/dist/utils/error.d.ts.map +1 -1
  182. package/package.json +36 -9
  183. package/dist/archetype.d.ts +0 -108
  184. package/dist/archetype.d.ts.map +0 -1
  185. package/dist/component.d.ts +0 -45
  186. package/dist/component.d.ts.map +0 -1
  187. package/dist/ecs.d.ts +0 -104
  188. package/dist/ecs.d.ts.map +0 -1
  189. package/dist/entity.d.ts +0 -11
  190. package/dist/entity.d.ts.map +0 -1
  191. package/dist/event.d.ts +0 -30
  192. package/dist/event.d.ts.map +0 -1
  193. package/dist/query.d.ts +0 -94
  194. package/dist/query.d.ts.map +0 -1
  195. package/dist/ref.d.ts +0 -23
  196. package/dist/ref.d.ts.map +0 -1
  197. package/dist/resource.d.ts +0 -23
  198. package/dist/resource.d.ts.map +0 -1
  199. package/dist/schedule.d.ts +0 -45
  200. package/dist/schedule.d.ts.map +0 -1
  201. package/dist/store.d.ts +0 -118
  202. package/dist/store.d.ts.map +0 -1
  203. package/dist/system.d.ts +0 -16
  204. package/dist/system.d.ts.map +0 -1
@@ -0,0 +1,231 @@
1
+ import { Brand } from '../../type_primitives';
2
+ import { EntityID } from './entity';
3
+ import { SparseComponentDef, SparseComponentStore } from './sparse_store';
4
+ /** Relation handle id. A separate id space from `ComponentID` and
5
+ * `SparseComponentID` — it indexes `Store`'s relation registry. The numeric
6
+ * value is the registration order, stable for the lifetime of the ECS. */
7
+ export type RelationID = Brand<number, "relation_id">;
8
+ declare const __relationBrand: unique symbol;
9
+ export type RelationDef = RelationID & {
10
+ readonly [__relationBrand]: "relation";
11
+ };
12
+ /** Access sentinel for the `(*, T)` wildcard query iteration
13
+ * (`Query.forEachRelatedTo`, #579). A `(*, T)` term reads **every** registered
14
+ * relation's reverse index to find sources of `T`, so it can't name a specific
15
+ * relation in `relationReads` the way `withRelation(R)` (`(R, *)`) can. A
16
+ * system that iterates a `(*, T)` wildcard lists `ANY_RELATION` in `relationReads`
17
+ * instead; `accessCheck.checkRelationReadAny` honors it. The numeric value is a
18
+ * reserved sentinel far past any real registration-order relation id (relations are
19
+ * minted from 0 upward), so it can never collide with a registered relation. */
20
+ export declare const ANY_RELATION: RelationDef;
21
+ /** Cleanup policy applied to a relation's **sources** when one of its
22
+ * **targets** is destroyed (#473). Chosen per-relation at registration, run at
23
+ * destroy-flush (and the immediate-destroy path) off the reverse index:
24
+ *
25
+ * - **`delete`** — cascade: destroy every source of the dead target too,
26
+ * recursively for chains/trees (the canonical ChildOf case).
27
+ * - **`clear`** — remove the relation from every source; the sources survive.
28
+ * - **`orphan`** — leave the link intact but dangling. Reads stay safe (the
29
+ * reverse index is `EntityID`-keyed, so the dead handle never aliases a
30
+ * recycled slot); `targetOf` returns a dead handle until the source
31
+ * re-targets or is removed. This is the pre-#473 behaviour and the default.
32
+ */
33
+ export type OnDeleteTarget = "delete" | "clear" | "orphan";
34
+ /** Default on-target-delete policy: leave the link dangling (pre-#473
35
+ * behaviour, zero change for callers that don't opt in). */
36
+ export declare const DEFAULT_ON_DELETE_TARGET: OnDeleteTarget;
37
+ /** Registration options. `exclusive` (one target per source) is the default;
38
+ * pass `{ multi: true }` for a multi-target relation. The two are mutually
39
+ * exclusive — passing both throws. `onDeleteTarget` selects the cleanup
40
+ * policy applied to sources when a target is destroyed (default `orphan`). */
41
+ export interface RelationOptions {
42
+ readonly exclusive?: boolean;
43
+ readonly multi?: boolean;
44
+ readonly onDeleteTarget?: OnDeleteTarget;
45
+ }
46
+ /** Field name carrying the target `EntityID` on an exclusive relation's backing
47
+ * sparse component. Field 0 of a single-field schema. */
48
+ export declare const RELATION_TARGET_FIELD = "target";
49
+ /** Receives one canonical `(source index, sorted targets)` set during a fold
50
+ * over a multi relation's forward sets. Targets are ascending by id; empty sets
51
+ * are never yielded (see `forEachCanonicalTargetSet`). */
52
+ export type CanonicalTargetSetFn = (sourceIndex: number, targets: readonly EntityID[]) => void;
53
+ /** Receives one canonical `(source, target)` pair during a fold over a
54
+ * relation's forward links. Sources ascend by entity index, each source's
55
+ * targets ascend by id — the #470 determinism order. */
56
+ export type CanonicalPairFn = (source: EntityID, target: EntityID) => void;
57
+ /** Maps a source entity **index** to its full `EntityID` (generation from the
58
+ * live slot). Supplied by `Store`, which owns entity generations. */
59
+ export type MakeSourceID = (index: number) => EntityID;
60
+ /** One relation's derived side state. **Abstract over cardinality (#498):** the
61
+ * base owns the cardinality-agnostic **reverse index** (target → sources, keyed
62
+ * by full `EntityID` so a recycled slot can't alias a dead target's sources) and
63
+ * a handle on the backing `SparseComponentStore`; the forward representation and
64
+ * its sparse interaction are owned by the concrete `ExclusiveRelationStore` /
65
+ * `MultiRelationStore` (built by `makeRelationStore`).
66
+ *
67
+ * `Store` owns what is genuinely its own — entity liveness, registration, and
68
+ * destroy orchestration — and drives a relation through the virtual `link` /
69
+ * `unlink` / `purgeSource` / `forEachCanonicalPair` / … without ever
70
+ * branching on cardinality. Each cardinality keeps forward link + reverse index
71
+ * + sparse membership in lockstep inside one method on one class, so the
72
+ * lockstep can't be broken by missing a scattered `if (rs.exclusive)` site. */
73
+ export declare abstract class RelationStore {
74
+ /** `true` → one target per source (target in the sparse field); `false` →
75
+ * a set of targets per source. The cardinality discriminant survives as a
76
+ * field because it is part of the snapshot header and the traversal/`targetOf`
77
+ * mode guards — but the forward *mechanics* are virtual, not branched on it. */
78
+ readonly exclusive: boolean;
79
+ /** Backing sparse component def: `{ target: f64 }` when exclusive, a tag when
80
+ * multi. Carries membership (and the target, when exclusive). */
81
+ readonly sparse: SparseComponentDef;
82
+ /** Cleanup policy applied to this relation's sources when a target is
83
+ * destroyed (#473). `orphan` (the default) is a no-op — the link dangles
84
+ * safely. `Store` reads this at destroy-flush off `sourcesOf`. */
85
+ readonly onDeleteTarget: OnDeleteTarget;
86
+ /** The backing sparse store instance. Owned for registration/liveness by
87
+ * `Store`, but the relation drives the forward/membership rows on it directly
88
+ * — that is the cardinality interaction this class now encapsulates (#498). */
89
+ protected readonly _store: SparseComponentStore;
90
+ /** target `EntityID` → set of source `EntityID`s. Keyed by the full id, not
91
+ * the index, so a recycled target slot can't alias a dead target's sources.
92
+ * An entry is dropped the moment its set empties (`unlinkReverse`). */
93
+ private readonly _reverse;
94
+ constructor(exclusive: boolean, sparse: SparseComponentDef, store: SparseComponentStore, onDeleteTarget: OnDeleteTarget);
95
+ /** Record that `src` points at `tgt` in the reverse index. */
96
+ protected linkReverse(tgt: EntityID, src: EntityID): void;
97
+ /** Drop the `src → tgt` edge from the reverse index, removing the target's
98
+ * entry entirely once its last source is gone (so a dead-target key doesn't
99
+ * linger with an empty set). */
100
+ protected unlinkReverse(tgt: EntityID, src: EntityID): void;
101
+ /** Drop every reverse-index entry whose **target** is no longer alive,
102
+ * returning the count dropped (#491). The `orphan` policy intentionally
103
+ * leaves a destroyed target's reverse entry intact (the link dangles
104
+ * safely), so a long-lived source that orphan-points at a stream of
105
+ * short-lived targets and never re-targets/dies accumulates dead-target keys
106
+ * without bound. This is the reclaim primitive behind `Store.compactRelations`
107
+ * — a cold path the host calls at scene/snapshot boundaries. It is
108
+ * cardinality-free (reverse-index only), so it lives on the base unchanged.
109
+ *
110
+ * Pure index reclaim: the **forward** links (the exclusive sparse target
111
+ * field, the multi forward set) are left untouched, so `targetOf` /
112
+ * `targetsOf` still return the dangling dead handle exactly as `orphan`
113
+ * promises. The reverse index is derived, so dropping a dead-target entry
114
+ * changes nothing observable except `sourcesOf` on that dead handle (which
115
+ * goes from the dangling sources to `[]` — meaningless either way, the target
116
+ * is gone) and is faithfully rebuilt by snapshot/restore from the surviving
117
+ * forward links. Only the **target** role can leak here: a destroyed *source*
118
+ * is already unlinked from every reverse set by `purgeSource`, so a live
119
+ * target's set never holds a dead source. `isAlive` is supplied by `Store`,
120
+ * which owns entity liveness. Deleting during `Map` key iteration is
121
+ * well-defined — already-visited and not-yet-reached keys are unaffected. */
122
+ pruneDeadReverse(isAlive: (id: EntityID) => boolean): number;
123
+ /** Sources that point at `tgt`, ascending by id (deterministic, cold-path
124
+ * sort) — empty when none. */
125
+ sourcesOf(tgt: EntityID): EntityID[];
126
+ /** Drop every derived side index — the reverse index and (for multi) the
127
+ * forward target sets. Restore path only (`restoreRelations`): the side
128
+ * indices are rebuilt from scratch, so they're cleared first to stay
129
+ * idempotent when restoring into a dirty world. The backing sparse store is
130
+ * cleared separately by `restoreSparseStores`. */
131
+ resetIndices(): void;
132
+ /** Clear this relation's forward representation (multi: the side map;
133
+ * exclusive: nothing — its forward links live in the sparse store, cleared by
134
+ * `restoreSparseStores`). */
135
+ protected abstract _resetForward(): void;
136
+ /** Add a `(R, tgt)` link from `src`, keeping forward link + membership +
137
+ * reverse index in lockstep. Exclusive: replaces any existing target
138
+ * (idempotent if `tgt` is already the target). Multi: adds to the set
139
+ * (idempotent on a duplicate), establishing the membership tag on the first
140
+ * target. `src` must be live — `Store` checks before delegating (#495). */
141
+ abstract link(src: EntityID, tgt: EntityID): void;
142
+ /** Remove `(R, tgt)` from `src` — or, when `tgt` is omitted, every target of
143
+ * `src` — keeping forward link + membership + reverse index in lockstep. A
144
+ * no-op when the link isn't present. */
145
+ abstract unlink(src: EntityID, tgt?: EntityID): void;
146
+ /** Purge a destroyed **source**: drop its forward link(s) and unlink it from
147
+ * every target's reverse set, but leave the sparse **membership** row alone —
148
+ * `Store._purgeSparse` drops that (for every store) right after, so this
149
+ * runs first and must not double-remove. */
150
+ abstract purgeSource(src: EntityID): void;
151
+ /** The single target of source `index`, or `undefined`. Exclusive reads the
152
+ * sparse field; multi has no single target and returns `undefined` (matching
153
+ * the production `targetOf`-on-multi read, which the `__DEV__` guard rejects). */
154
+ abstract singleTarget(index: number): EntityID | undefined;
155
+ /** All targets of source `index`, ascending by id — one or zero for
156
+ * exclusive, the full sorted set for multi. The symmetric counterpart to
157
+ * `sourcesOf` (#498 item 4). */
158
+ abstract targetsOf(index: number): EntityID[];
159
+ /** Whether source `index` holds any target under this relation (sparse
160
+ * membership). */
161
+ abstract has(index: number): boolean;
162
+ /** Fold `cb` over this relation's **multi** forward target sets in canonical
163
+ * order (sources ascending by index, each source's targets ascending by id),
164
+ * skipping empty sets. The single source of truth for the canonical multi
165
+ * traversal shared by `stateHash`, `snapshotRelations`, and `pairsOf`
166
+ * (#498 item 1). Exclusive relations contribute via the sparse store, so this
167
+ * is a no-op for them. */
168
+ abstract forEachCanonicalTargetSet(cb: CanonicalTargetSetFn): void;
169
+ /** Fold `cb` over every `(source, target)` pair of this relation in canonical
170
+ * order — the `(R, *)` wildcard drive order (#472). `makeId` maps a source
171
+ * index to its full `EntityID`. Exclusive rides the backing store's
172
+ * `canonicalIndices`; multi rides `forEachCanonicalTargetSet`. */
173
+ abstract forEachCanonicalPair(makeId: MakeSourceID, cb: CanonicalPairFn): void;
174
+ /** Rebuild the reverse index from the forward links after a restore.
175
+ * Exclusive reads it back from the just-restored sparse target field (the
176
+ * reverse index is never serialized); multi already rebuilt its reverse edges
177
+ * in `restoreAddTarget`, so this is a no-op for it. `makeId` maps a source
178
+ * index to its full `EntityID`. */
179
+ abstract rebuildReverseFromForward(makeId: MakeSourceID): void;
180
+ /** Restore one decoded multi forward edge `(source index → tgt)` plus its
181
+ * reverse edge (the source's full `EntityID` is `src`). Multi only — the
182
+ * snapshot header guards exclusive relations out before this is reached, so
183
+ * the exclusive override throws defensively. */
184
+ abstract restoreAddTarget(index: number, tgt: EntityID, src: EntityID): void;
185
+ }
186
+ /** Build the right `RelationStore` for a cardinality. The only construction
187
+ * site is `Store.registerRelation`, which resolves the backing sparse store and
188
+ * hands it in so the relation can drive forward/membership rows directly. */
189
+ export declare function makeRelationStore(exclusive: boolean, sparse: SparseComponentDef, store: SparseComponentStore, onDeleteTarget: OnDeleteTarget): RelationStore;
190
+ /** Serialize the relation side data that does **not** live in the sparse store
191
+ * — i.e. each **multi** relation's forward target sets (`Map<source index,
192
+ * Set<target>>`). Exclusive relations store their target in the backing sparse
193
+ * field, so they ride `snapshotSparseStores` and contribute only a header
194
+ * here. The reverse index is fully derivable (from the sparse store for
195
+ * exclusive, from these sets for multi), so it is never serialized — it is
196
+ * rebuilt by `restoreRelations` + the caller's exclusive-reverse pass.
197
+ *
198
+ * Members are emitted in canonical order (sources ascending by entity index,
199
+ * each source's targets ascending by id) so the bytes are independent of
200
+ * add/remove history — the same byte-level determinism invariant the sparse
201
+ * snapshot holds (#470). Layout (integers little-endian):
202
+ *
203
+ * u32 relationCount
204
+ * repeat relationCount times (registration / id order):
205
+ * u32 isMulti
206
+ * if multi:
207
+ * u32 sourceCount
208
+ * repeat sourceCount times (ascending source index):
209
+ * u32 sourceIndex
210
+ * u32 targetCount
211
+ * f64 × targetCount (target EntityIDs, ascending) */
212
+ export declare function snapshotRelations(relations: readonly RelationStore[]): Uint8Array;
213
+ /** Rebuild every relation's side indices from a `snapshotRelations` buffer and
214
+ * the already-restored sparse stores. Each relation's indices are reset first
215
+ * (idempotent into a dirty world), then:
216
+ *
217
+ * - **multi** — forward target sets and their reverse edges are rebuilt from
218
+ * `bytes` (the sets aren't in the sparse store, so the bytes are the only
219
+ * source). `makeId` maps a source entity index to its full `EntityID`
220
+ * (generation from the live slot) so reverse edges key correctly.
221
+ * - **exclusive** — only the reset happens here; the reverse index is rebuilt
222
+ * by the caller from the backing sparse store (which already round-tripped
223
+ * through `restoreSparseStores`), since this function can't read it.
224
+ *
225
+ * Throws `SparseRestoreError` on any shape mismatch (relation count, an
226
+ * exclusive/multi flag that disagrees with the registered relation, a multi
227
+ * source index past `MAX_INDEX`, or a truncated / over-long buffer) rather than
228
+ * silently building a corrupt index. */
229
+ export declare function restoreRelations(relations: readonly RelationStore[], bytes: Uint8Array, makeId: (index: number) => EntityID): void;
230
+ export {};
231
+ //# sourceMappingURL=relation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relation.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/relation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /***
2
+ * Resource — Typed singleton key-value storage.
3
+ *
4
+ * Resources are global singletons that don't belong to any entity.
5
+ * Think: time, input state, camera config, game settings.
6
+ *
7
+ * Each resource is identified by a unique symbol (ResourceKey<T>) and
8
+ * stores an arbitrary typed value. The key carries the value type as a
9
+ * phantom type parameter, so reads are type-safe at compile time.
10
+ *
11
+ * Lifecycle (#798). A resource is register-once *until removed*: a second
12
+ * `registerResource` for a live key throws RESOURCE_ALREADY_REGISTERED, but
13
+ * `removeResource(key)` drops it (failing closed on a missing key) and frees the
14
+ * key to be registered again — the present → absent → present axis. Removal is
15
+ * access-checked as a *write* (a system must declare the key in `resourceWrites`),
16
+ * and resources stay out of `stateHash` and snapshot/resume regardless, so a
17
+ * lifecycle change never perturbs the determinism hash.
18
+ *
19
+ * Usage:
20
+ *
21
+ * const TimeRes = resourceKey<{ delta: number; elapsed: number }>("Time");
22
+ * world.registerResource(TimeRes, { delta: 0, elapsed: 0 });
23
+ * const time = world.resource(TimeRes);
24
+ * // time.delta → number, time.elapsed → number
25
+ * world.removeResource(TimeRes); // present → absent
26
+ * world.registerResource(TimeRes, { delta: 0, elapsed: 0 }); // → present again
27
+ *
28
+ ***/
29
+ export type ResourceKey<T> = symbol & {
30
+ readonly __phantom: T;
31
+ };
32
+ export declare function resourceKey<T>(name: string): ResourceKey<T>;
33
+ //# sourceMappingURL=resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2BK;AAIL,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,MAAM,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAA;CAAE,CAAC;AAEhE,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAE3D"}
@@ -0,0 +1,85 @@
1
+ import { ArchetypeViews } from '../store';
2
+ /** Magic for the combined world-snapshot frame (`"WRS0"` little-endian). Distinct
3
+ * from the SAB `STORE_MAGIC` so a bare dense snapshot fed to `restoreInto` is
4
+ * rejected with a clear error instead of being mis-parsed as a combined frame. */
5
+ export declare const WORLD_SNAPSHOT_MAGIC = 810766935;
6
+ /** Combined-frame format version. Bumped if the section framing or host-state
7
+ * layout changes. Independent of `SIM_ABI_VERSION` (which gates the dense bytes). */
8
+ export declare const WORLD_SNAPSHOT_VERSION = 1;
9
+ /** Thrown by `Store.restoreInto` (and the helpers here) when a combined snapshot
10
+ * is malformed, carries the wrong magic/version, or targets a world whose
11
+ * archetype/component registration doesn't match the snapshot. Mirrors
12
+ * `StoreRestoreError` / `SparseRestoreError` so callers see one error class per
13
+ * restore failure mode. */
14
+ export declare class WorldRestoreError extends Error {
15
+ constructor(message: string);
16
+ }
17
+ /** Per-archetype host-side row bookkeeping the SAB doesn't carry authoritatively. */
18
+ export interface ArchetypeRowState {
19
+ readonly archetypeId: number;
20
+ /** Total live rows (enabled + disabled). */
21
+ readonly length: number;
22
+ /** Enabled-row partition boundary (#577): rows `[0, enabledCount)` enabled. */
23
+ readonly enabledCount: number;
24
+ }
25
+ /** The host-side state a snapshot captures alongside the dense + sparse bytes. */
26
+ export interface HostState {
27
+ /** World tick at snapshot time (`Store._tick`). */
28
+ readonly tick: number;
29
+ /** Entity-index high-water (count of slots ever issued). Also mirrored in the
30
+ * SAB region's `length` header; carried here for a cross-check on restore. */
31
+ readonly entityHighWater: number;
32
+ /** Live entity count. */
33
+ readonly entityAliveCount: number;
34
+ /** Recycle free-list in live order (LIFO: the last element is the next slot
35
+ * `createEntity` hands out). */
36
+ readonly freeIndices: readonly number[];
37
+ /** Per-archetype row state, one entry per SAB-backed archetype. */
38
+ readonly archetypeRows: readonly ArchetypeRowState[];
39
+ }
40
+ /** Serialize host-state to a self-contained little-endian byte buffer. Layout:
41
+ *
42
+ * [u32 tick][u32 highWater][u32 alive_count]
43
+ * [u32 freeCount][u32 free_index × freeCount]
44
+ * [u32 archCount][(u32 id, u32 length, u32 enabled_count) × archCount]
45
+ */
46
+ export declare function serializeHostState(hs: HostState): Uint8Array;
47
+ /** Parse host-state bytes produced by `serializeHostState`. Throws
48
+ * `WorldRestoreError` on truncation or a trailing-byte (non-canonical) buffer. */
49
+ export declare function parseHostState(bytes: Uint8Array): HostState;
50
+ /** Assemble the combined world-snapshot frame from its three sections. Layout:
51
+ *
52
+ * [u32 magic][u32 version][u32 denseLen][u32 sparseLen][u32 hostLen]
53
+ * [dense][sparse][host]
54
+ */
55
+ export declare function frameWorldSnapshot(dense: Uint8Array, sparse: Uint8Array, host: Uint8Array): Uint8Array;
56
+ /** The three sections of a combined frame, as zero-copy subviews over `bytes`. */
57
+ export interface WorldSnapshotSections {
58
+ readonly dense: Uint8Array;
59
+ readonly sparse: Uint8Array;
60
+ readonly host: Uint8Array;
61
+ }
62
+ /** Split a combined frame back into its sections. Validates magic, version, and
63
+ * an exact (no trailing bytes) frame; throws `WorldRestoreError` otherwise. */
64
+ export declare function unframeWorldSnapshot(bytes: Uint8Array): WorldSnapshotSections;
65
+ /**
66
+ * Fail-closed registration guard, read **directly from the snapshot's dense
67
+ * bytes** so it can run BEFORE the dense backing is touched. `restoreInto`
68
+ * builds the restored store through the live world's in-place allocator
69
+ * (ADR-0008), which reuses the live backing buffer — so validating a
70
+ * *materialised* `ColumnStore` would already have overwritten live column data
71
+ * (the buffer is overwritten inside `restoreColumnStore`, before any post-build
72
+ * check could run). Parsing the descriptors off the raw `dense` `Uint8Array`
73
+ * keeps the check non-mutating, so a mismatch leaves the live world untouched.
74
+ *
75
+ * Asserts: the dense section's SAB magic + ABI, that its archetype set +
76
+ * per-archetype `componentMask` + per-column `(componentId, fieldId, typeTag)`
77
+ * match the live store's exactly (so every live `Archetype.refreshViews` finds
78
+ * its region and no snapshot archetype is orphaned), and that the entity-index
79
+ * capacity matches (the region is sized once at construction). The archetype
80
+ * graph is rebuilt from registration code, not the snapshot (mirroring
81
+ * `restoreSparse`'s "registered in the same order" contract). Throws
82
+ * `WorldRestoreError` on any mismatch / malformed section.
83
+ */
84
+ export declare function assertDenseLayoutMatchesLive(dense: Uint8Array, live: ReadonlyMap<number, ArchetypeViews>, liveEntityIndexCapacity: number): void;
85
+ //# sourceMappingURL=resume.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/resume.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAUN,KAAK,cAAc,EACnB,MAAM,UAAU,CAAC;AAElB;;kFAEkF;AAClF,eAAO,MAAM,oBAAoB,YAAa,CAAC;AAE/C;qFACqF;AACrF,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;;2BAI2B;AAC3B,qBAAa,iBAAkB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI3B;AAED,qFAAqF;AACrF,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAED,kFAAkF;AAClF,MAAM,WAAW,SAAS;IACzB,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;kFAC8E;IAC9E,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,yBAAyB;IACzB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC;oCACgC;IAChC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,mEAAmE;IACnE,QAAQ,CAAC,aAAa,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACrD;AAID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,SAAS,GAAG,UAAU,CAwB5D;AAED;kFACkF;AAClF,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CAqC3D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CACjC,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,UAAU,GACd,UAAU,CAaZ;AAED,kFAAkF;AAClF,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC1B;AAED;+EAC+E;AAC/E,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,qBAAqB,CAuC7E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,4BAA4B,CAC3C,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,EACzC,uBAAuB,EAAE,MAAM,GAC7B,IAAI,CAoGN"}
@@ -0,0 +1,75 @@
1
+ import { ComponentDef } from './component';
2
+ import { ResourceKey } from './resource';
3
+ import { Query } from './query';
4
+ /**
5
+ * The read-only slice of `SystemContext` a run condition is handed. Deliberately
6
+ * narrow — a condition can read the ECS tick and resources, but has no path to
7
+ * mutate the world or read component columns directly (component reads go
8
+ * through a captured `Query`). `SystemContext` structurally satisfies this, so
9
+ * the schedule passes the live context unchanged.
10
+ */
11
+ export interface ConditionContext {
12
+ /** Current ECS tick — the deterministic clock built-ins key off. */
13
+ readonly ecsTick: number;
14
+ /** Read a resource value (checked against `resourceReads` in `__DEV__`). */
15
+ resource<T>(key: ResourceKey<T>): T;
16
+ /** Membership probe for a resource — unchecked, mirrors `hasComponent`. */
17
+ hasResource<T>(key: ResourceKey<T>): boolean;
18
+ }
19
+ /**
20
+ * A per-tick gate. `evaluate` returns `true` to run the gated system(s), `false`
21
+ * to skip them this tick. `reads` / `resourceReads` declare the predicate's
22
+ * read surface for `accessCheck` (dev) and the future parallel scheduler's
23
+ * read-edge graph; both are optional (absent reads as empty).
24
+ */
25
+ export interface RunCondition {
26
+ /** Human-readable label, surfaced in dev access-violation diagnostics. */
27
+ readonly name: string;
28
+ /** Pure, deterministic predicate. See the two hard rules in the file header. */
29
+ readonly evaluate: (ctx: ConditionContext) => boolean;
30
+ /** Components the predicate reads (via a captured query). Forward-looking
31
+ * metadata — `ConditionContext` exposes no direct column read, so this is
32
+ * not runtime-checkable today, but it is the read-edge a parallel scheduler
33
+ * will consume. */
34
+ readonly reads?: readonly ComponentDef[];
35
+ /** Resources the predicate reads. Validated at runtime in `__DEV__` when the
36
+ * condition evaluates inside `accessCheck.enterCondition`. */
37
+ readonly resourceReads?: readonly ResourceKey<unknown>[];
38
+ }
39
+ /**
40
+ * Run the gated system(s) only while a resource equals `expected` (strict `===`,
41
+ * so reference identity for objects). The canonical "feature flag / game phase"
42
+ * gate — flip `world.setResource(key, …)` and the whole group toggles.
43
+ */
44
+ export declare function runIfResourceEq<T>(key: ResourceKey<T>, expected: T): RunCondition;
45
+ /**
46
+ * Run the gated system(s) once every `n` ticks — on ticks congruent to `offset`
47
+ * mod `n`. Keyed off the deterministic ECS tick, so it carries no private
48
+ * state and replays bit-identically. `offset` is a **phase shift taken mod `n`**
49
+ * (default `0` ⇒ fires on tick 0, n, 2n, …; `offset` and `offset + n` are the
50
+ * same phase, and a negative offset wraps), normalized once here into `[0, n)`.
51
+ * `n` must be a positive integer and `offset` an integer.
52
+ *
53
+ * The normalization isn't cosmetic: `(ecsTick - offset) % n` with a raw
54
+ * `offset ≥ n` (or negative) leans on JS's signed `%` yielding `-0` for a
55
+ * negative multiple (and `-0 === 0`) to stay congruent — correct, but load-
56
+ * bearing on a quirk. Folding `offset` into `[0, n)` up front makes the phase
57
+ * explicit: the per-tick dividend `ecsTick - phase` may still be negative
58
+ * (when `ecsTick < phase`), but with `phase ∈ [0, n)` it is never a *negative
59
+ * multiple* of `n` — it lands in `[-(n-1), -1]`, which holds no multiple of `n`
60
+ * — so `%` never produces `-0` and the check needs no signed-zero reliance.
61
+ */
62
+ export declare function runEveryNTicks(n: number, offset?: number): RunCondition;
63
+ /**
64
+ * Run the gated system(s) only when a query matches at least one (enabled)
65
+ * entity — flecs `runIf` over a query. The query is captured at config time;
66
+ * its component defs are declared as `reads`. `count()` is a membership sum over
67
+ * matching archetypes (no column reads), so it trips no `accessCheck` read.
68
+ *
69
+ * The query must be **dense-only**: `count()` asserts this in `__DEV__`
70
+ * (`_assertDenseOnly`), so pass a plain `world.query(...)` — a query carrying
71
+ * `.optional(...)` or sparse terms throws. Gate on sparse membership with a
72
+ * custom predicate over `forEachEntity` instead.
73
+ */
74
+ export declare function runIfAnyMatch(query: Query<readonly ComponentDef[]>): RunCondition;
75
+ //# sourceMappingURL=run_condition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run_condition.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/run_condition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8BK;AAEL,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAChC,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,4EAA4E;IAC5E,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACpC,2EAA2E;IAC3E,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CAC7C;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC;IACtD;;;wBAGoB;IACpB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACzC;mEAC+D;IAC/D,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;CACzD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,YAAY,CAMjF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,YAAY,CAclE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,YAAY,EAAE,CAAC,GAAG,YAAY,CAMjF"}
@@ -0,0 +1,133 @@
1
+ import { SystemContext } from './query';
2
+ import { SystemDescriptor } from './system';
3
+ import { ComputeBackend } from './compute_backend';
4
+ import { RunCondition } from './run_condition';
5
+ export declare enum SCHEDULE {
6
+ PRE_STARTUP = "PRE_STARTUP",
7
+ STARTUP = "STARTUP",
8
+ POST_STARTUP = "POST_STARTUP",
9
+ FIXED_UPDATE = "FIXED_UPDATE",
10
+ PRE_UPDATE = "PRE_UPDATE",
11
+ UPDATE = "UPDATE",
12
+ POST_UPDATE = "POST_UPDATE"
13
+ }
14
+ /**
15
+ * An opaque handle for a named group of systems (#576). A set carries a shared
16
+ * run condition and shared ordering that every member inherits. Sets are
17
+ * identified by **object identity**, not by name — create one with
18
+ * `systemSet(name)`, hold the handle, and reuse it across `addSystems`
19
+ * (`SystemEntry.set`) and `Schedule.configureSet`. The `name` is for
20
+ * diagnostics only.
21
+ */
22
+ export interface SystemSet {
23
+ readonly name: string;
24
+ }
25
+ /** Create a `SystemSet` handle (#576). Two calls with the same name are two
26
+ * distinct sets — keep the returned handle and pass it around. */
27
+ export declare function systemSet(name: string): SystemSet;
28
+ /** A `before`/`after` ordering target: either a concrete system or a whole set
29
+ * (expanded to its members within the same phase at sort time). */
30
+ export type SystemOrderingTarget = SystemDescriptor | SystemSet;
31
+ /** Shared configuration applied to a `SystemSet` via `configureSet` (#576).
32
+ * Accumulates across calls — conditions AND together, ordering targets union. */
33
+ export interface SystemSetConfig {
34
+ /** Condition(s) every member is gated by (ANDed with each member's own). */
35
+ runIf?: RunCondition | readonly RunCondition[];
36
+ /** Every member runs before each of these targets. */
37
+ before?: readonly SystemOrderingTarget[];
38
+ /** Every member runs after each of these targets. */
39
+ after?: readonly SystemOrderingTarget[];
40
+ }
41
+ export interface SystemOrdering {
42
+ before?: readonly SystemOrderingTarget[];
43
+ after?: readonly SystemOrderingTarget[];
44
+ }
45
+ export interface SystemEntry {
46
+ system: SystemDescriptor;
47
+ ordering?: SystemOrdering;
48
+ /** Run condition(s) gating just this system — ANDed with any set conditions
49
+ * it inherits (#576). A `false` verdict skips the body that tick. */
50
+ runIf?: RunCondition | readonly RunCondition[];
51
+ /** Set membership — the system inherits each set's shared condition and
52
+ * ordering (#576). */
53
+ set?: SystemSet | readonly SystemSet[];
54
+ }
55
+ export declare class Schedule {
56
+ private readonly labelSystems;
57
+ private readonly sortedCache;
58
+ private readonly systemIndex;
59
+ private readonly systemLastRun;
60
+ private readonly gatedSystems;
61
+ private readonly setConditions;
62
+ private readonly setOrdering;
63
+ private nextInsertionOrder;
64
+ private _backend;
65
+ constructor();
66
+ addSystems(label: SCHEDULE, ...entries: (SystemDescriptor | SystemEntry)[]): void;
67
+ /**
68
+ * Configure a `SystemSet` (#576) — its shared run condition(s) and/or
69
+ * ordering, inherited by every member. Additive and order-independent w.r.t.
70
+ * `addSystems`: conditions accumulate (ANDed), ordering targets union, and
71
+ * a member added before or after this call picks the configuration up.
72
+ */
73
+ configureSet(set: SystemSet, config: SystemSetConfig): void;
74
+ removeSystem(system: SystemDescriptor): void;
75
+ /** Attach (or, with `null`, detach) the opt-in compute backend (#622). Driven
76
+ * by `ECS.attachBackend`; routes any scheduled system carrying a
77
+ * `backendHandle` to `backend.run(handle)` in place of its `fn`. */
78
+ setBackend(backend: ComputeBackend | null): void;
79
+ runStartup(ctx: SystemContext, tick: number): void;
80
+ runUpdate(ctx: SystemContext, deltaTime: number, tick: number): void;
81
+ runFixedUpdate(ctx: SystemContext, fixedDt: number, tick: number): void;
82
+ hasFixedSystems(): boolean;
83
+ getAllSystems(): SystemDescriptor[];
84
+ hasSystem(system: SystemDescriptor): boolean;
85
+ clear(): void;
86
+ private runLabel;
87
+ /**
88
+ * Whether a gated system runs this tick — the AND of its own conditions and
89
+ * every set it belongs to. A set's conditions are evaluated at most once per
90
+ * phase (memoized in `setVerdicts`) and the verdict gates every member of the
91
+ * set uniformly; a `configureSet` between phases is still honored because the
92
+ * memo lives only for a single `runLabel` pass. Short-circuits on the first
93
+ * `false`. The system's own conditions evaluate per system, in canonical order.
94
+ */
95
+ private shouldRun;
96
+ /** Evaluate a condition list with AND semantics. Each predicate runs inside a
97
+ * reads-only `accessCheck` span (dev), so a condition that reads an
98
+ * undeclared resource — or attempts any mutation — throws. */
99
+ private evalConditions;
100
+ private getSorted;
101
+ /**
102
+ * Delegates to the shared topologicalSort utility.
103
+ * Builds the dependency edge map from before/after constraints, then
104
+ * catches any cycle TypeError and re-throws as ECSError.
105
+ */
106
+ private sortSystems;
107
+ /**
108
+ * Add the topo edges for one ordering list (#576). For `"before"` the source
109
+ * runs before each target (edge source→target); for `"after"` it runs after
110
+ * each target (edge target→source). A `SystemSet` target expands to every
111
+ * member within this phase (self-edges skipped, so a member ordered against
112
+ * its own set is a no-op); a descriptor target absent from this phase is
113
+ * dropped — with a dev warning only for a concrete system, since a set
114
+ * legitimately expands to nothing when its members live in another phase.
115
+ */
116
+ private resolveEdges;
117
+ /** Push one directed edge into the adjacency map. Both endpoints are known to
118
+ * be in this phase (callers guard), so `edges.get(...)` is non-null. */
119
+ private addDirectedEdge;
120
+ /**
121
+ * Dev-only diagnostic for an ordering edge that was dropped during sort.
122
+ *
123
+ * Cross-label ordering is impossible by design (`nodeSet` is per-label), so
124
+ * a target registered in *another* phase is skipped silently — that's the
125
+ * intended isolation. But a target unknown to *every* phase is almost
126
+ * certainly a typo or a system that was never scheduled; without this warning
127
+ * the constraint vanishes and the system runs in insertion-order tiebreak as
128
+ * if unconstrained, with nothing to distinguish mistake from intent. Compiled
129
+ * out of production builds by the `__DEV__` guards at the call sites.
130
+ */
131
+ private warnDroppedEdge;
132
+ }
133
+ //# sourceMappingURL=schedule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/schedule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmCK;AAIL,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKpD,oBAAY,QAAQ;IACnB,WAAW,gBAAgB;IAC3B,OAAO,YAAY;IACnB,YAAY,iBAAiB;IAC7B,YAAY,iBAAiB;IAC7B,UAAU,eAAe;IACzB,MAAM,WAAW;IACjB,WAAW,gBAAgB;CAC3B;AAMD;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED;kEACkE;AAClE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAEjD;AAED;mEACmE;AACnE,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,SAAS,CAAC;AAEhE;iFACiF;AACjF,MAAM,WAAW,eAAe;IAC/B,4EAA4E;IAC5E,KAAK,CAAC,EAAE,YAAY,GAAG,SAAS,YAAY,EAAE,CAAC;IAC/C,sDAAsD;IACtD,MAAM,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACzC,qDAAqD;IACrD,KAAK,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,cAAc;IAC9B,MAAM,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACzC,KAAK,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,WAAW;IAC3B,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;yEACqE;IACrE,KAAK,CAAC,EAAE,YAAY,GAAG,SAAS,YAAY,EAAE,CAAC;IAC/C;0BACsB;IACtB,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE,CAAC;CACvC;AA8BD,qBAAa,QAAQ;IACpB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0C;IACvE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgD;IAC5E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA8C;IAC1E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA4C;IAI1E,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgD;IAG7E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6C;IAC3E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAGd;IACd,OAAO,CAAC,kBAAkB,CAAK;IAM/B,OAAO,CAAC,QAAQ,CAA+B;;IAYxC,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC,gBAAgB,GAAG,WAAW,CAAC,EAAE,GAAG,IAAI;IAwCxF;;;;;OAKG;IACI,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI;IA0B3D,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IA+BnD;;wEAEoE;IAC7D,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI;IAIhD,UAAU,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAMlD,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAMpE,cAAc,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAIvE,eAAe,IAAI,OAAO;IAK1B,aAAa,IAAI,gBAAgB,EAAE;IAUnC,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO;IAI5C,KAAK,IAAI,IAAI;IAYpB,OAAO,CAAC,QAAQ;IA6DhB;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;IAwBjB;;kEAE8D;IAC9D,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,SAAS;IAWjB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IA2FnB;;;;;;;;OAQG;IACH,OAAO,CAAC,YAAY;IA4BpB;4EACwE;IACxE,OAAO,CAAC,eAAe;IAevB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,eAAe;CAiBvB"}