@oasys/oecs 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +553 -0
- package/README.md +42 -31
- package/dist/core/ecs/access_check.d.cts +77 -0
- package/dist/core/ecs/access_check.d.ts +8 -8
- package/dist/core/ecs/access_check.d.ts.map +1 -1
- package/dist/core/ecs/archetype.d.cts +486 -0
- package/dist/core/ecs/archetype.d.ts +23 -11
- package/dist/core/ecs/archetype.d.ts.map +1 -1
- package/dist/core/ecs/archetype_graph.d.cts +96 -0
- package/dist/core/ecs/archetype_graph.d.ts +96 -0
- package/dist/core/ecs/archetype_graph.d.ts.map +1 -0
- package/dist/core/ecs/builtin_relations.d.cts +43 -0
- package/dist/core/ecs/builtin_relations.d.ts +8 -8
- package/dist/core/ecs/builtin_relations.d.ts.map +1 -1
- package/dist/core/ecs/command_log.d.cts +116 -0
- package/dist/core/ecs/command_log.d.ts +13 -10
- package/dist/core/ecs/command_log.d.ts.map +1 -1
- package/dist/core/ecs/component.d.cts +176 -0
- package/dist/core/ecs/component.d.ts +75 -5
- package/dist/core/ecs/component.d.ts.map +1 -1
- package/dist/core/ecs/compute_backend.d.cts +37 -0
- package/dist/core/ecs/compute_backend.d.ts +2 -2
- package/dist/core/ecs/debug_names.d.cts +7 -0
- package/dist/core/ecs/debug_names.d.ts +7 -0
- package/dist/core/ecs/debug_names.d.ts.map +1 -0
- package/dist/core/ecs/deferred_commands.d.cts +55 -0
- package/dist/core/ecs/deferred_commands.d.ts +55 -0
- package/dist/core/ecs/deferred_commands.d.ts.map +1 -0
- package/dist/core/ecs/dispatch_trace.d.cts +93 -0
- package/dist/core/ecs/dispatch_trace.d.ts +3 -3
- package/dist/core/ecs/ecs.d.cts +562 -0
- package/dist/core/ecs/ecs.d.ts +314 -285
- package/dist/core/ecs/ecs.d.ts.map +1 -1
- package/dist/core/ecs/ecs_memory.d.cts +179 -0
- package/dist/core/ecs/ecs_memory.d.ts +1 -1
- package/dist/core/ecs/entity.d.cts +34 -0
- package/dist/core/ecs/entity.d.ts +7 -1
- package/dist/core/ecs/entity.d.ts.map +1 -1
- package/dist/core/ecs/entity_allocator.d.cts +59 -0
- package/dist/core/ecs/entity_allocator.d.ts +59 -0
- package/dist/core/ecs/entity_allocator.d.ts.map +1 -0
- package/dist/core/ecs/event.d.cts +79 -0
- package/dist/core/ecs/event.d.ts +36 -11
- package/dist/core/ecs/event.d.ts.map +1 -1
- package/dist/core/ecs/event_registry.d.cts +22 -0
- package/dist/core/ecs/event_registry.d.ts +22 -0
- package/dist/core/ecs/event_registry.d.ts.map +1 -0
- package/dist/core/ecs/facades.d.cts +158 -0
- package/dist/core/ecs/facades.d.ts +158 -0
- package/dist/core/ecs/facades.d.ts.map +1 -0
- package/dist/core/ecs/frame_stepper.d.cts +58 -0
- package/dist/core/ecs/frame_stepper.d.ts +58 -0
- package/dist/core/ecs/frame_stepper.d.ts.map +1 -0
- package/dist/core/ecs/frame_trace.d.cts +133 -0
- package/dist/core/ecs/frame_trace.d.ts +5 -5
- package/dist/core/ecs/frame_trace.d.ts.map +1 -1
- package/dist/core/ecs/host_commands.d.cts +274 -0
- package/dist/core/ecs/host_commands.d.ts +53 -31
- package/dist/core/ecs/host_commands.d.ts.map +1 -1
- package/dist/core/ecs/index.d.cts +46 -0
- package/dist/core/ecs/index.d.ts +45 -40
- package/dist/core/ecs/index.d.ts.map +1 -1
- package/dist/core/ecs/observer.d.cts +173 -0
- package/dist/core/ecs/observer.d.ts +43 -12
- package/dist/core/ecs/observer.d.ts.map +1 -1
- package/dist/core/ecs/query.d.cts +718 -0
- package/dist/core/ecs/query.d.ts +251 -90
- package/dist/core/ecs/query.d.ts.map +1 -1
- package/dist/core/ecs/ref.d.cts +31 -0
- package/dist/core/ecs/ref.d.ts +3 -3
- package/dist/core/ecs/relation.d.cts +243 -0
- package/dist/core/ecs/relation.d.ts +26 -14
- package/dist/core/ecs/relation.d.ts.map +1 -1
- package/dist/core/ecs/relation_service.d.cts +235 -0
- package/dist/core/ecs/relation_service.d.ts +235 -0
- package/dist/core/ecs/relation_service.d.ts.map +1 -0
- package/dist/core/ecs/resource.d.cts +53 -0
- package/dist/core/ecs/resource.d.ts +25 -5
- package/dist/core/ecs/resource.d.ts.map +1 -1
- package/dist/core/ecs/resource_registry.d.cts +20 -0
- package/dist/core/ecs/resource_registry.d.ts +20 -0
- package/dist/core/ecs/resource_registry.d.ts.map +1 -0
- package/dist/core/ecs/resume.d.cts +85 -0
- package/dist/core/ecs/resume.d.ts +6 -6
- package/dist/core/ecs/resume.d.ts.map +1 -1
- package/dist/core/ecs/run_condition.d.cts +81 -0
- package/dist/core/ecs/run_condition.d.ts +15 -9
- package/dist/core/ecs/run_condition.d.ts.map +1 -1
- package/dist/core/ecs/schedule.d.cts +142 -0
- package/dist/core/ecs/schedule.d.ts +15 -6
- package/dist/core/ecs/schedule.d.ts.map +1 -1
- package/dist/core/ecs/snapshot_service.d.cts +94 -0
- package/dist/core/ecs/snapshot_service.d.ts +94 -0
- package/dist/core/ecs/snapshot_service.d.ts.map +1 -0
- package/dist/core/ecs/sparse_store.d.cts +110 -0
- package/dist/core/ecs/sparse_store.d.ts +5 -2
- package/dist/core/ecs/sparse_store.d.ts.map +1 -1
- package/dist/core/ecs/store.d.cts +950 -0
- package/dist/core/ecs/store.d.ts +143 -342
- package/dist/core/ecs/store.d.ts.map +1 -1
- package/dist/core/ecs/store_layout_listener.d.cts +23 -0
- package/dist/core/ecs/system.d.cts +250 -0
- package/dist/core/ecs/system.d.ts +138 -22
- package/dist/core/ecs/system.d.ts.map +1 -1
- package/dist/{utils/arrays.d.ts → core/ecs/utils/arrays.d.cts} +1 -0
- package/dist/core/ecs/utils/error.d.cts +61 -0
- package/dist/core/ecs/utils/error.d.ts +12 -2
- package/dist/core/ecs/utils/error.d.ts.map +1 -1
- package/dist/core/store/action_ring.d.cts +136 -0
- package/dist/core/store/allocator.d.cts +238 -0
- package/dist/core/store/allocator.d.ts.map +1 -1
- package/dist/core/store/buffer_backed_column.d.cts +69 -0
- package/dist/core/store/buffer_backed_column.d.ts +2 -2
- package/dist/core/store/column_store.d.cts +273 -0
- package/dist/core/store/column_store.d.ts +18 -10
- package/dist/core/store/column_store.d.ts.map +1 -1
- package/dist/core/store/command_dispatch.d.cts +52 -0
- package/dist/core/store/command_ring.d.cts +107 -0
- package/dist/core/store/descriptor.d.cts +80 -0
- package/dist/core/store/descriptor.d.ts +1 -1
- package/dist/core/store/descriptor.d.ts.map +1 -1
- package/dist/core/store/entity_index.d.cts +108 -0
- package/dist/core/store/event_ring.d.cts +95 -0
- package/dist/core/store/extend.d.cts +39 -0
- package/dist/core/store/extend.d.ts +3 -73
- package/dist/core/store/extend.d.ts.map +1 -1
- package/dist/core/store/grow.d.cts +34 -0
- package/dist/core/store/grow.d.ts +4 -9
- package/dist/core/store/grow.d.ts.map +1 -1
- package/dist/core/store/header.d.cts +64 -0
- package/dist/core/store/header.d.ts +1 -1
- package/dist/core/store/header.d.ts.map +1 -1
- package/dist/core/store/index.d.cts +17 -0
- package/dist/core/store/index.d.ts +16 -15
- package/dist/core/store/index.d.ts.map +1 -1
- package/dist/core/store/layout_ops.d.cts +152 -0
- package/dist/core/store/layout_ops.d.ts +152 -0
- package/dist/core/store/layout_ops.d.ts.map +1 -0
- package/dist/core/store/region_table.d.cts +74 -0
- package/dist/core/store/region_table.d.ts +1 -1
- package/dist/core/store/region_table.d.ts.map +1 -1
- package/dist/core/store/snapshot.d.cts +43 -0
- package/dist/core/store/snapshot.d.ts +2 -2
- package/dist/core/store/state_hash.d.cts +38 -0
- package/dist/core/store/state_hash.d.ts +1 -1
- package/dist/core/store/store_regions.d.cts +38 -0
- package/dist/core/store/store_regions.d.ts +1 -1
- package/dist/core/store/vendored_abi/abi.d.ts +43 -0
- package/dist/core/store/{__generated__ → vendored_abi}/abi.d.ts.map +1 -1
- package/dist/dev_flag.d.cts +17 -0
- package/dist/dev_flag.d.ts +17 -0
- package/dist/dev_flag.d.ts.map +1 -0
- package/dist/extensions/editor/editor.d.cts +170 -0
- package/dist/extensions/editor/editor.d.ts +43 -22
- package/dist/extensions/editor/editor.d.ts.map +1 -1
- package/dist/extensions/editor/field_handle.d.cts +40 -0
- package/dist/extensions/editor/field_handle.d.ts +8 -3
- package/dist/extensions/editor/field_handle.d.ts.map +1 -1
- package/dist/extensions/editor/index.cjs +1 -1
- package/dist/extensions/editor/index.d.cts +21 -0
- package/dist/extensions/editor/index.d.ts +2 -2
- package/dist/extensions/editor/index.js +116 -88
- package/dist/extensions/reactive/ecs_sync.d.cts +214 -0
- package/dist/extensions/reactive/ecs_sync.d.ts +26 -22
- package/dist/extensions/reactive/ecs_sync.d.ts.map +1 -1
- package/dist/extensions/reactive/index.cjs +1 -1
- package/dist/extensions/reactive/index.d.cts +23 -0
- package/dist/extensions/reactive/index.d.ts +1 -1
- package/dist/extensions/reactive/index.js +106 -116
- package/dist/extensions/solid/index.cjs +1 -1
- package/dist/extensions/solid/index.d.cts +6 -0
- package/dist/extensions/solid/index.d.ts +2 -2
- package/dist/extensions/solid/index.js +8 -4
- package/dist/extensions/solid/kernel_solid.d.cts +45 -0
- package/dist/extensions/solid/kernel_solid.d.ts +6 -3
- package/dist/extensions/solid/kernel_solid.d.ts.map +1 -1
- package/dist/host_commands-BF8QMi3c.cjs +1 -0
- package/dist/host_commands-i4cAeyL5.js +2318 -0
- package/dist/index.cjs +1 -2
- package/dist/index.d.cts +66 -0
- package/dist/index.d.ts +50 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4469 -5933
- package/dist/internal.cjs +2 -0
- package/dist/internal.d.cts +20 -0
- package/dist/internal.d.ts +20 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +141 -0
- package/dist/primitives.cjs +1 -1
- package/dist/primitives.d.cts +18 -0
- package/dist/primitives.d.ts +6 -6
- package/dist/primitives.js +24 -23
- package/dist/reactive/array.d.ts +24 -0
- package/dist/reactive/array.d.ts.map +1 -0
- package/dist/reactive/index.cjs +1 -0
- package/dist/reactive/index.d.cts +11 -0
- package/dist/reactive/index.d.ts +11 -0
- package/dist/reactive/index.d.ts.map +1 -0
- package/dist/reactive/index.js +18 -0
- package/dist/reactive/interop.d.cts +19 -0
- package/dist/{core/reactive → reactive}/interop.d.ts +1 -1
- package/dist/reactive/interop.d.ts.map +1 -0
- package/dist/reactive/kernel.d.cts +73 -0
- package/dist/{core/reactive → reactive}/kernel.d.ts +5 -3
- package/dist/reactive/kernel.d.ts.map +1 -0
- package/dist/reactive/map.d.ts +16 -0
- package/dist/reactive/map.d.ts.map +1 -0
- package/dist/reactive/shallow.d.cts +11 -0
- package/dist/reactive/shallow.d.ts +11 -0
- package/dist/reactive/shallow.d.ts.map +1 -0
- package/dist/reactive/struct.d.cts +10 -0
- package/dist/{core/reactive → reactive}/struct.d.ts +1 -1
- package/dist/reactive/struct.d.ts.map +1 -0
- package/dist/shallow-DQ8aG51_.cjs +1 -0
- package/dist/shallow-DfnAm9vG.js +150 -0
- package/dist/shared-BU1Cd40h.js +103 -0
- package/dist/shared-BymrGTyR.cjs +1 -0
- package/dist/shared.cjs +1 -1
- package/dist/shared.d.cts +22 -0
- package/dist/shared.d.ts +2 -2
- package/dist/shared.js +1 -1
- package/dist/topological_sort-BDvEyb9W.cjs +1 -0
- package/dist/topological_sort-DK6EjpWa.js +135 -0
- package/dist/type_primitives/assertions.d.cts +32 -0
- package/dist/type_primitives/assertions.d.ts +13 -1
- package/dist/type_primitives/assertions.d.ts.map +1 -1
- package/dist/type_primitives/binary_heap/binary_heap.d.cts +37 -0
- package/dist/type_primitives/bitset/bitset.d.cts +54 -0
- package/dist/type_primitives/brand.d.cts +23 -0
- package/dist/type_primitives/error.d.cts +16 -0
- package/dist/type_primitives/error.d.ts +4 -3
- package/dist/type_primitives/error.d.ts.map +1 -1
- package/dist/type_primitives/index.d.cts +13 -0
- package/dist/type_primitives/index.d.ts +9 -9
- package/dist/type_primitives/sparse_map/sparse_map.d.cts +30 -0
- package/dist/type_primitives/sparse_set/sparse_set.d.cts +28 -0
- package/dist/type_primitives/topological_sort/topological_sort.d.cts +29 -0
- package/dist/type_primitives/typed_arrays/typed_arrays.d.cts +127 -0
- package/dist/typed_arrays-BcXcnzB4.js +258 -0
- package/dist/typed_arrays-D3NmwtCG.cjs +1 -0
- package/dist/utils/error.d.cts +6 -0
- package/dist/version.d.cts +10 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +102 -19
- package/dist/array-CxbPyiHO.cjs +0 -1
- package/dist/array-uFR7Q8fU.js +0 -132
- package/dist/core/reactive/array.d.ts.map +0 -1
- package/dist/core/reactive/index.cjs +0 -1
- package/dist/core/reactive/index.d.ts +0 -10
- package/dist/core/reactive/index.d.ts.map +0 -1
- package/dist/core/reactive/index.js +0 -17
- package/dist/core/reactive/interop.d.ts.map +0 -1
- package/dist/core/reactive/kernel.d.ts.map +0 -1
- package/dist/core/reactive/map.d.ts.map +0 -1
- package/dist/core/reactive/struct.d.ts.map +0 -1
- package/dist/log/console_sink.d.ts +0 -4
- package/dist/log/console_sink.d.ts.map +0 -1
- package/dist/log/index.d.ts +0 -3
- package/dist/log/index.d.ts.map +0 -1
- package/dist/log/logger.d.ts +0 -27
- package/dist/log/logger.d.ts.map +0 -1
- package/dist/shared-BXSZnxx4.cjs +0 -1
- package/dist/shared-C678TAPY.js +0 -99
- package/dist/topological_sort-DlRpSrxu.js +0 -391
- package/dist/topological_sort-WAT-VHb-.cjs +0 -1
- package/dist/utils/arrays.d.ts.map +0 -1
- package/dist/utils/constants.d.ts.map +0 -1
- /package/dist/{utils/constants.d.ts → core/ecs/utils/constants.d.cts} +0 -0
- /package/dist/core/store/{__generated__/abi.d.ts → vendored_abi/abi.d.cts} +0 -0
- /package/dist/{core/reactive/array.d.ts → reactive/array.d.cts} +0 -0
- /package/dist/{core/reactive/map.d.ts → reactive/map.d.cts} +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { BitSet } from '../../type_primitives/index.cjs';
|
|
2
|
+
import { Archetype, ArchetypeColumnLayout, ArchetypeID } from './archetype.cjs';
|
|
3
|
+
import { ComponentID } from './component.cjs';
|
|
4
|
+
import { ComponentMeta } from './store.cjs';
|
|
5
|
+
import { ArchetypeSpec } from '../store/index.cjs';
|
|
6
|
+
/** What the graph needs from `Store` — closure-injected. `extendStore` and
|
|
7
|
+
* `materialize` bind the storage lifecycle (SAB extend + column-store views
|
|
8
|
+
* + grow handler) on the Store side; `fanIntoQueries` binds query-registry
|
|
9
|
+
* state. All are creation-path only — never called on an edge-cache hit. */
|
|
10
|
+
export interface ArchetypeGraphHost {
|
|
11
|
+
/** Component field metadata, indexed by ComponentID — for building a new
|
|
12
|
+
* archetype's column layouts. */
|
|
13
|
+
readonly componentMetas: () => readonly ComponentMeta[];
|
|
14
|
+
/** Row capacity for a new archetype's column region. */
|
|
15
|
+
readonly initialCapacity: () => number;
|
|
16
|
+
/** Extend the SAB with the new archetypes' column regions (one call for
|
|
17
|
+
* the whole batch — the bulk path's O(N²)→O(N) win, #213). */
|
|
18
|
+
readonly extendStore: (specs: ArchetypeSpec[]) => void;
|
|
19
|
+
/** Materialise the `Archetype` over the live column store and attach the
|
|
20
|
+
* store's grow handler. */
|
|
21
|
+
readonly materialize: (id: ArchetypeID, ownedMask: BitSet, layouts: ArchetypeColumnLayout[]) => Archetype;
|
|
22
|
+
/** Push a newly-installed archetype into every registered query whose
|
|
23
|
+
* masks it satisfies. */
|
|
24
|
+
readonly fanIntoQueries: (archetype: Archetype) => void;
|
|
25
|
+
}
|
|
26
|
+
export declare class ArchetypeGraph {
|
|
27
|
+
/** All archetypes, indexed by `ArchetypeID` (ids are minted monotonically
|
|
28
|
+
* and never removed). Store's flush loops hoist this array to a local. */
|
|
29
|
+
readonly archetypes: Archetype[];
|
|
30
|
+
/** Inverted index: ComponentID → ascending list of ArchetypeIDs that contain
|
|
31
|
+
* that component. Indexed POSITIONALLY by component id (a small, dense id
|
|
32
|
+
* space, 0..STORE_DESCRIPTOR_COMPONENT_LIMIT-1), so a lookup is an array
|
|
33
|
+
* index, not a Map hash. Used by `getMatchingArchetypes` to start the
|
|
34
|
+
* superset scan from the smallest bucket. Each bucket is a plain push-only
|
|
35
|
+
* array — NOT a Set — and deliberately does NOT dedup: a (component,
|
|
36
|
+
* archetype) pair can be inserted here at most once (see the "no duplicate
|
|
37
|
+
* pair" invariant on `install` + ADR-0015), so there is nothing for a Set
|
|
38
|
+
* to collapse. Archetypes are never removed from a Store, so buckets only
|
|
39
|
+
* grow, in ascending archetype-id order — which is canonical order,
|
|
40
|
+
* exploited by `_forEachChangedArchetype` to skip a sort. */
|
|
41
|
+
readonly componentIndex: ArchetypeID[][];
|
|
42
|
+
private readonly archetypeMap;
|
|
43
|
+
private nextArchetypeId;
|
|
44
|
+
private readonly host;
|
|
45
|
+
constructor(host: ArchetypeGraphHost);
|
|
46
|
+
get(id: ArchetypeID): Archetype;
|
|
47
|
+
/**
|
|
48
|
+
* Find or create an archetype for the given component mask.
|
|
49
|
+
* Also updates the componentIndex and pushes into matching registered queries.
|
|
50
|
+
*
|
|
51
|
+
* Hot single-mask path. The bulk batched variant — used by Phase C
|
|
52
|
+
* pre-warming at `ecs.startup()` — is `createManyFromMasks`;
|
|
53
|
+
* see #213 / `ECS.startup()` for how it gets called and why.
|
|
54
|
+
*/
|
|
55
|
+
getOrCreateFromMask(mask: BitSet): ArchetypeID;
|
|
56
|
+
/**
|
|
57
|
+
* Bulk variant of `getOrCreateFromMask` — Phase C of issue #213.
|
|
58
|
+
*
|
|
59
|
+
* Given a set of masks, creates Archetypes for the ones not already
|
|
60
|
+
* planted, in a SINGLE `extendColumnStore` call (instead of one per
|
|
61
|
+
* archetype). Single-mask creation is O(N) in archetypes-so-far because
|
|
62
|
+
* the extend has to copy every existing archetype's live rows forward;
|
|
63
|
+
* N such calls compound to O(N²). Batching collapses the per-archetype
|
|
64
|
+
* setup-and-copy down to one pass — the per-startup cost the design doc
|
|
65
|
+
* §5.2 calls out as "O(N²) → O(N)" for in-tree systems whose archetype
|
|
66
|
+
* set is known at registration time via `spawns` + `transitions`.
|
|
67
|
+
*
|
|
68
|
+
* Masks already in the map are skipped. Returns the resolved
|
|
69
|
+
* `ArchetypeID` per input mask in input order — callers that don't need
|
|
70
|
+
* the ids can ignore the return value.
|
|
71
|
+
*/
|
|
72
|
+
createManyFromMasks(masks: readonly BitSet[]): ArchetypeID[];
|
|
73
|
+
/** Hash-bucketed mask → ArchetypeID lookup; null when the mask isn't planted. */
|
|
74
|
+
private lookup;
|
|
75
|
+
/** Walk the mask's set bits and resolve each non-tag component to its
|
|
76
|
+
* layout. Used by both single and bulk archetype-create paths. */
|
|
77
|
+
private buildLayouts;
|
|
78
|
+
/** Materialise the `Archetype` for `id` (via the host, which binds the
|
|
79
|
+
* live column store + grow handler), register in the archetype map +
|
|
80
|
+
* component index, and fan into any matching registered queries.
|
|
81
|
+
*
|
|
82
|
+
* Clones `mask` before storing — callers may pass scratch BitSets that
|
|
83
|
+
* they intend to reuse (e.g. `addComponents` / `removeComponents`'s
|
|
84
|
+
* `_scratchTargetMask`). The Archetype and the archetypeMap bucket
|
|
85
|
+
* both keep references long-term, so the clone is required for
|
|
86
|
+
* correctness — and is the previously-implicit guarantee made by the
|
|
87
|
+
* mask-allocating callers (`copyWithSet`, `copyWithClear`, etc.). */
|
|
88
|
+
private install;
|
|
89
|
+
/** Resolve "add component_id to archetype_id" → target ArchetypeID. Caches the edge. */
|
|
90
|
+
resolveAdd(archetypeId: ArchetypeID, componentId: ComponentID): ArchetypeID;
|
|
91
|
+
/** Resolve "remove component_id from archetype_id" → target ArchetypeID. Caches the edge. */
|
|
92
|
+
resolveRemove(archetypeId: ArchetypeID, componentId: ComponentID): ArchetypeID;
|
|
93
|
+
/** Cache a bidirectional add/remove edge between two archetypes. */
|
|
94
|
+
private cacheEdge;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=archetype_graph.d.ts.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { BitSet } from '../../type_primitives/index.js';
|
|
2
|
+
import { Archetype, ArchetypeColumnLayout, ArchetypeID } from './archetype.js';
|
|
3
|
+
import { ComponentID } from './component.js';
|
|
4
|
+
import { ComponentMeta } from './store.js';
|
|
5
|
+
import { ArchetypeSpec } from '../store/index.js';
|
|
6
|
+
/** What the graph needs from `Store` — closure-injected. `extendStore` and
|
|
7
|
+
* `materialize` bind the storage lifecycle (SAB extend + column-store views
|
|
8
|
+
* + grow handler) on the Store side; `fanIntoQueries` binds query-registry
|
|
9
|
+
* state. All are creation-path only — never called on an edge-cache hit. */
|
|
10
|
+
export interface ArchetypeGraphHost {
|
|
11
|
+
/** Component field metadata, indexed by ComponentID — for building a new
|
|
12
|
+
* archetype's column layouts. */
|
|
13
|
+
readonly componentMetas: () => readonly ComponentMeta[];
|
|
14
|
+
/** Row capacity for a new archetype's column region. */
|
|
15
|
+
readonly initialCapacity: () => number;
|
|
16
|
+
/** Extend the SAB with the new archetypes' column regions (one call for
|
|
17
|
+
* the whole batch — the bulk path's O(N²)→O(N) win, #213). */
|
|
18
|
+
readonly extendStore: (specs: ArchetypeSpec[]) => void;
|
|
19
|
+
/** Materialise the `Archetype` over the live column store and attach the
|
|
20
|
+
* store's grow handler. */
|
|
21
|
+
readonly materialize: (id: ArchetypeID, ownedMask: BitSet, layouts: ArchetypeColumnLayout[]) => Archetype;
|
|
22
|
+
/** Push a newly-installed archetype into every registered query whose
|
|
23
|
+
* masks it satisfies. */
|
|
24
|
+
readonly fanIntoQueries: (archetype: Archetype) => void;
|
|
25
|
+
}
|
|
26
|
+
export declare class ArchetypeGraph {
|
|
27
|
+
/** All archetypes, indexed by `ArchetypeID` (ids are minted monotonically
|
|
28
|
+
* and never removed). Store's flush loops hoist this array to a local. */
|
|
29
|
+
readonly archetypes: Archetype[];
|
|
30
|
+
/** Inverted index: ComponentID → ascending list of ArchetypeIDs that contain
|
|
31
|
+
* that component. Indexed POSITIONALLY by component id (a small, dense id
|
|
32
|
+
* space, 0..STORE_DESCRIPTOR_COMPONENT_LIMIT-1), so a lookup is an array
|
|
33
|
+
* index, not a Map hash. Used by `getMatchingArchetypes` to start the
|
|
34
|
+
* superset scan from the smallest bucket. Each bucket is a plain push-only
|
|
35
|
+
* array — NOT a Set — and deliberately does NOT dedup: a (component,
|
|
36
|
+
* archetype) pair can be inserted here at most once (see the "no duplicate
|
|
37
|
+
* pair" invariant on `install` + ADR-0015), so there is nothing for a Set
|
|
38
|
+
* to collapse. Archetypes are never removed from a Store, so buckets only
|
|
39
|
+
* grow, in ascending archetype-id order — which is canonical order,
|
|
40
|
+
* exploited by `_forEachChangedArchetype` to skip a sort. */
|
|
41
|
+
readonly componentIndex: ArchetypeID[][];
|
|
42
|
+
private readonly archetypeMap;
|
|
43
|
+
private nextArchetypeId;
|
|
44
|
+
private readonly host;
|
|
45
|
+
constructor(host: ArchetypeGraphHost);
|
|
46
|
+
get(id: ArchetypeID): Archetype;
|
|
47
|
+
/**
|
|
48
|
+
* Find or create an archetype for the given component mask.
|
|
49
|
+
* Also updates the componentIndex and pushes into matching registered queries.
|
|
50
|
+
*
|
|
51
|
+
* Hot single-mask path. The bulk batched variant — used by Phase C
|
|
52
|
+
* pre-warming at `ecs.startup()` — is `createManyFromMasks`;
|
|
53
|
+
* see #213 / `ECS.startup()` for how it gets called and why.
|
|
54
|
+
*/
|
|
55
|
+
getOrCreateFromMask(mask: BitSet): ArchetypeID;
|
|
56
|
+
/**
|
|
57
|
+
* Bulk variant of `getOrCreateFromMask` — Phase C of issue #213.
|
|
58
|
+
*
|
|
59
|
+
* Given a set of masks, creates Archetypes for the ones not already
|
|
60
|
+
* planted, in a SINGLE `extendColumnStore` call (instead of one per
|
|
61
|
+
* archetype). Single-mask creation is O(N) in archetypes-so-far because
|
|
62
|
+
* the extend has to copy every existing archetype's live rows forward;
|
|
63
|
+
* N such calls compound to O(N²). Batching collapses the per-archetype
|
|
64
|
+
* setup-and-copy down to one pass — the per-startup cost the design doc
|
|
65
|
+
* §5.2 calls out as "O(N²) → O(N)" for in-tree systems whose archetype
|
|
66
|
+
* set is known at registration time via `spawns` + `transitions`.
|
|
67
|
+
*
|
|
68
|
+
* Masks already in the map are skipped. Returns the resolved
|
|
69
|
+
* `ArchetypeID` per input mask in input order — callers that don't need
|
|
70
|
+
* the ids can ignore the return value.
|
|
71
|
+
*/
|
|
72
|
+
createManyFromMasks(masks: readonly BitSet[]): ArchetypeID[];
|
|
73
|
+
/** Hash-bucketed mask → ArchetypeID lookup; null when the mask isn't planted. */
|
|
74
|
+
private lookup;
|
|
75
|
+
/** Walk the mask's set bits and resolve each non-tag component to its
|
|
76
|
+
* layout. Used by both single and bulk archetype-create paths. */
|
|
77
|
+
private buildLayouts;
|
|
78
|
+
/** Materialise the `Archetype` for `id` (via the host, which binds the
|
|
79
|
+
* live column store + grow handler), register in the archetype map +
|
|
80
|
+
* component index, and fan into any matching registered queries.
|
|
81
|
+
*
|
|
82
|
+
* Clones `mask` before storing — callers may pass scratch BitSets that
|
|
83
|
+
* they intend to reuse (e.g. `addComponents` / `removeComponents`'s
|
|
84
|
+
* `_scratchTargetMask`). The Archetype and the archetypeMap bucket
|
|
85
|
+
* both keep references long-term, so the clone is required for
|
|
86
|
+
* correctness — and is the previously-implicit guarantee made by the
|
|
87
|
+
* mask-allocating callers (`copyWithSet`, `copyWithClear`, etc.). */
|
|
88
|
+
private install;
|
|
89
|
+
/** Resolve "add component_id to archetype_id" → target ArchetypeID. Caches the edge. */
|
|
90
|
+
resolveAdd(archetypeId: ArchetypeID, componentId: ComponentID): ArchetypeID;
|
|
91
|
+
/** Resolve "remove component_id from archetype_id" → target ArchetypeID. Caches the edge. */
|
|
92
|
+
resolveRemove(archetypeId: ArchetypeID, componentId: ComponentID): ArchetypeID;
|
|
93
|
+
/** Cache a bidirectional add/remove edge between two archetypes. */
|
|
94
|
+
private cacheEdge;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=archetype_graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archetype_graph.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/archetype_graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,MAAM,EAAsB,MAAM,uBAAuB,CAAC;AACnE,OAAO,EACN,SAAS,EAGT,KAAK,qBAAqB,EAE1B,KAAK,WAAW,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG7C,OAAO,EAGN,KAAK,aAAa,EAElB,MAAM,UAAU,CAAC;AAGlB;;;4EAG4E;AAC5E,MAAM,WAAW,kBAAkB;IAClC;qCACiC;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,SAAS,aAAa,EAAE,CAAC;IACxD,wDAAwD;IACxD,QAAQ,CAAC,eAAe,EAAE,MAAM,MAAM,CAAC;IACvC;kEAC8D;IAC9D,QAAQ,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IACvD;+BAC2B;IAC3B,QAAQ,CAAC,WAAW,EAAE,CACrB,EAAE,EAAE,WAAW,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,qBAAqB,EAAE,KAC5B,SAAS,CAAC;IACf;6BACyB;IACzB,QAAQ,CAAC,cAAc,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;CACxD;AAED,qBAAa,cAAc;IAC1B;8EAC0E;IAC1E,SAAgB,UAAU,EAAE,SAAS,EAAE,CAAM;IAC7C;;;;;;;;;;iEAU6D;IAC7D,SAAgB,cAAc,EAAE,WAAW,EAAE,EAAE,CAAM;IAErD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyC;IACtE,OAAO,CAAC,eAAe,CAAK;IAE5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;gBAE9B,IAAI,EAAE,kBAAkB;IAI7B,GAAG,CAAC,EAAE,EAAE,WAAW,GAAG,SAAS;IAStC;;;;;;;OAOG;IACI,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAkBrD;;;;;;;;;;;;;;;OAeG;IACI,mBAAmB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,EAAE;IA4DnE,iFAAiF;IACjF,OAAO,CAAC,MAAM;IASd;sEACkE;IAClE,OAAO,CAAC,YAAY;IAkBpB;;;;;;;;;yEASqE;IACrE,OAAO,CAAC,OAAO;IA0Df,wFAAwF;IACjF,UAAU,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,GAAG,WAAW;IAYlF,6FAA6F;IACtF,aAAa,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,GAAG,WAAW;IAYrF,oEAAoE;IACpE,OAAO,CAAC,SAAS;CAuBjB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ECS } from './ecs.cjs';
|
|
2
|
+
import { OnDeleteTarget, RelationDef } from './relation.cjs';
|
|
3
|
+
/** Options for a built-in relation. `exclusive` / `multi` are fixed (always
|
|
4
|
+
* exclusive — required for the chain/tree traversal helpers), so only the
|
|
5
|
+
* target-deletion cleanup policy is tunable. */
|
|
6
|
+
export interface BuiltinRelationOptions {
|
|
7
|
+
/** What happens to a relation's sources when a target is destroyed.
|
|
8
|
+
* Defaults per relation (see each registrar). */
|
|
9
|
+
readonly onDeleteTarget?: OnDeleteTarget;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Register an **`IsA(instance → exemplar)`** relation — a thin instance-of link.
|
|
13
|
+
*
|
|
14
|
+
* - "all instances of exemplar E" is `ecs.relations.sourcesOf(E, IsA)`.
|
|
15
|
+
* - the IsA chain (`instance → exemplar → …`) is walked with
|
|
16
|
+
* `ecs.relations.ancestorsOf(instance, IsA)` / `rootOf` / `cascadeOf(exemplar, IsA)`.
|
|
17
|
+
* - **No component inheritance** — IsA records the link only; materialization of
|
|
18
|
+
* an instance from its exemplar stays a spawn-time copy (the template path,
|
|
19
|
+
* #462), deliberately decoupled (#477 / #478). An exemplar is a real entity,
|
|
20
|
+
* not a `Template` (a non-entity template can't be a relation target).
|
|
21
|
+
*
|
|
22
|
+
* Default `onDeleteTarget: "clear"` — destroying an exemplar drops its
|
|
23
|
+
* instances' IsA link but leaves the instances alive (the thin analog of
|
|
24
|
+
* flecs's `IsA`-remove, since there is no inherited data to strip). Pass
|
|
25
|
+
* `"delete"` for strong instance-of (exemplar death cascade-destroys instances).
|
|
26
|
+
*/
|
|
27
|
+
export declare function registerIsA(ecs: ECS, opts?: BuiltinRelationOptions): RelationDef<"exclusive">;
|
|
28
|
+
/**
|
|
29
|
+
* Register a **`ChildOf(child → parent)`** relation — a thin hierarchy link.
|
|
30
|
+
*
|
|
31
|
+
* - a parent's children are `ecs.relations.sourcesOf(parent, ChildOf)`.
|
|
32
|
+
* - the hierarchy is walked with `ecs.relations.ancestorsOf(child, ChildOf)` (up to the
|
|
33
|
+
* root), `rootOf`, and `cascadeOf(root, ChildOf)` (down, breadth-first,
|
|
34
|
+
* parents before children).
|
|
35
|
+
* - unlike flecs's `ChildOf`, this does **not** scope names/lookup — the engine
|
|
36
|
+
* has no name registry; it is purely the structural parent link.
|
|
37
|
+
*
|
|
38
|
+
* Default `onDeleteTarget: "delete"` — destroying a parent cascade-destroys
|
|
39
|
+
* its whole subtree (flecs's default). Pass `"clear"` to let children survive as
|
|
40
|
+
* roots, or `"orphan"` to leave a dangling `targetOf`.
|
|
41
|
+
*/
|
|
42
|
+
export declare function registerChildOf(ecs: ECS, opts?: BuiltinRelationOptions): RelationDef<"exclusive">;
|
|
43
|
+
//# sourceMappingURL=builtin_relations.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ECS } from './ecs';
|
|
2
|
-
import { OnDeleteTarget, RelationDef } from './relation';
|
|
1
|
+
import { ECS } from './ecs.js';
|
|
2
|
+
import { OnDeleteTarget, RelationDef } from './relation.js';
|
|
3
3
|
/** Options for a built-in relation. `exclusive` / `multi` are fixed (always
|
|
4
4
|
* exclusive — required for the chain/tree traversal helpers), so only the
|
|
5
5
|
* target-deletion cleanup policy is tunable. */
|
|
@@ -11,9 +11,9 @@ export interface BuiltinRelationOptions {
|
|
|
11
11
|
/**
|
|
12
12
|
* Register an **`IsA(instance → exemplar)`** relation — a thin instance-of link.
|
|
13
13
|
*
|
|
14
|
-
* - "all instances of exemplar E" is `
|
|
14
|
+
* - "all instances of exemplar E" is `ecs.relations.sourcesOf(E, IsA)`.
|
|
15
15
|
* - the IsA chain (`instance → exemplar → …`) is walked with
|
|
16
|
-
* `
|
|
16
|
+
* `ecs.relations.ancestorsOf(instance, IsA)` / `rootOf` / `cascadeOf(exemplar, IsA)`.
|
|
17
17
|
* - **No component inheritance** — IsA records the link only; materialization of
|
|
18
18
|
* an instance from its exemplar stays a spawn-time copy (the template path,
|
|
19
19
|
* #462), deliberately decoupled (#477 / #478). An exemplar is a real entity,
|
|
@@ -24,12 +24,12 @@ export interface BuiltinRelationOptions {
|
|
|
24
24
|
* flecs's `IsA`-remove, since there is no inherited data to strip). Pass
|
|
25
25
|
* `"delete"` for strong instance-of (exemplar death cascade-destroys instances).
|
|
26
26
|
*/
|
|
27
|
-
export declare function registerIsA(
|
|
27
|
+
export declare function registerIsA(ecs: ECS, opts?: BuiltinRelationOptions): RelationDef<"exclusive">;
|
|
28
28
|
/**
|
|
29
29
|
* Register a **`ChildOf(child → parent)`** relation — a thin hierarchy link.
|
|
30
30
|
*
|
|
31
|
-
* - a parent's children are `
|
|
32
|
-
* - the hierarchy is walked with `
|
|
31
|
+
* - a parent's children are `ecs.relations.sourcesOf(parent, ChildOf)`.
|
|
32
|
+
* - the hierarchy is walked with `ecs.relations.ancestorsOf(child, ChildOf)` (up to the
|
|
33
33
|
* root), `rootOf`, and `cascadeOf(root, ChildOf)` (down, breadth-first,
|
|
34
34
|
* parents before children).
|
|
35
35
|
* - unlike flecs's `ChildOf`, this does **not** scope names/lookup — the engine
|
|
@@ -39,5 +39,5 @@ export declare function registerIsA(world: ECS, opts?: BuiltinRelationOptions):
|
|
|
39
39
|
* its whole subtree (flecs's default). Pass `"clear"` to let children survive as
|
|
40
40
|
* roots, or `"orphan"` to leave a dangling `targetOf`.
|
|
41
41
|
*/
|
|
42
|
-
export declare function registerChildOf(
|
|
42
|
+
export declare function registerChildOf(ecs: ECS, opts?: BuiltinRelationOptions): RelationDef<"exclusive">;
|
|
43
43
|
//# sourceMappingURL=builtin_relations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtin_relations.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/builtin_relations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;KAsBK;AAEL,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9D;;gDAEgD;AAChD,MAAM,WAAW,sBAAsB;IACtC;qDACiD;IACjD,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;CACzC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"builtin_relations.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/builtin_relations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;KAsBK;AAEL,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9D;;gDAEgD;AAChD,MAAM,WAAW,sBAAsB;IACtC;qDACiD;IACjD,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;CACzC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,sBAAsB,GAAG,WAAW,CAAC,WAAW,CAAC,CAK7F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,sBAAsB,GAAG,WAAW,CAAC,WAAW,CAAC,CAKjG"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { ECS } from './ecs.cjs';
|
|
2
|
+
import { HostCommand, HostCommandQueue, HostCommandSink } from './host_commands.cjs';
|
|
3
|
+
/** One recorded update tick: the commands the apply system drained at this
|
|
4
|
+
* tick's update-phase head, plus the `dt` passed to `ecs.update(dt)`. Replay
|
|
5
|
+
* MUST re-issue `update(dt)` for every recorded tick — even an empty one — since
|
|
6
|
+
* `dt` itself drives the sim (movement, timers), not just the commands. */
|
|
7
|
+
export interface RecordedTick {
|
|
8
|
+
/** The ECS tick (`ctx.ecsTick`) this bucket belongs to. */
|
|
9
|
+
readonly tick: number;
|
|
10
|
+
/** The `dt` `ecs.update(dt)` was called with for this tick. */
|
|
11
|
+
readonly dt: number;
|
|
12
|
+
/** Commands applied this tick, in apply order (typed queue first, then ring),
|
|
13
|
+
* `onSpawned` stripped. */
|
|
14
|
+
readonly commands: readonly HostCommand[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A recorded session: the `seed` it ran under, the seed-time commands drained at
|
|
18
|
+
* startup, and the per-tick command stream. Plain, serializable data — the
|
|
19
|
+
* record-side mirror of the typed `HostCommand` vocabulary. Replay it with
|
|
20
|
+
* {@link replayCommandLog}; persist it with {@link serializeCommandLog}.
|
|
21
|
+
*/
|
|
22
|
+
export interface CommandLog {
|
|
23
|
+
/** Session seed — the implementer's deterministic input (e.g. an RNG seed).
|
|
24
|
+
* Opaque to the engine (the core tick takes only `dt`); carried so a replay
|
|
25
|
+
* rebuilds the world the same way the original was built. */
|
|
26
|
+
readonly seed: number;
|
|
27
|
+
/** Commands drained at the PRE_STARTUP head (seed-time edits), applied before
|
|
28
|
+
* the first update tick. Enqueued BEFORE `ecs.startup()` on replay. */
|
|
29
|
+
readonly startup: readonly HostCommand[];
|
|
30
|
+
/** One entry per update tick, in order. */
|
|
31
|
+
readonly ticks: readonly RecordedTick[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The record side of record/replay: a {@link HostCommandSink} the apply system
|
|
35
|
+
* feeds. Construct one with the session `seed`, hand it to
|
|
36
|
+
* `installHostCommandSeam(world, { recorder })`, and it accumulates the
|
|
37
|
+
* command stream as the ECS ticks. Read it back with {@link log} (a live view,
|
|
38
|
+
* ready to {@link serializeCommandLog serialize}).
|
|
39
|
+
*
|
|
40
|
+
* Bucketing: STARTUP-phase drains (which never call {@link openTick}) append to
|
|
41
|
+
* the {@link startup} bucket; each update-phase drain {@link openTick}s its tick
|
|
42
|
+
* — multiple update-phase drains in one tick reuse the same bucket (keyed by the
|
|
43
|
+
* ECS tick), so a frame's commands stay together. The apply system runs every
|
|
44
|
+
* tick, so every tick's `dt` is recorded even when no commands were applied.
|
|
45
|
+
*
|
|
46
|
+
* One recorder per session — don't share across worlds.
|
|
47
|
+
*/
|
|
48
|
+
export declare class HostCommandRecorder implements HostCommandSink {
|
|
49
|
+
/** Session seed, echoed into the produced {@link CommandLog}. */
|
|
50
|
+
readonly seed: number;
|
|
51
|
+
private readonly _startup;
|
|
52
|
+
private readonly _ticks;
|
|
53
|
+
/** Where {@link record} appends. Defaults to the startup bucket (seed-time
|
|
54
|
+
* drains happen before any `openTick`); each `openTick` repoints it. */
|
|
55
|
+
private sink;
|
|
56
|
+
constructor(seed?: number);
|
|
57
|
+
openTick(tick: number, dt: number): void;
|
|
58
|
+
readonly record: (cmd: HostCommand) => void;
|
|
59
|
+
/** A live {@link CommandLog} view over the accumulated stream — not a copy.
|
|
60
|
+
* Serialize it (which deep-copies through JSON) before mutating the world
|
|
61
|
+
* further if you need a stable snapshot, or use {@link snapshotLog}. */
|
|
62
|
+
log(): CommandLog;
|
|
63
|
+
/** A STABLE deep copy of the accumulated stream — safe to hold across
|
|
64
|
+
* further recording (the safe default; `log()` is the zero-copy live view). */
|
|
65
|
+
snapshotLog(): CommandLog;
|
|
66
|
+
}
|
|
67
|
+
/** Serialize a {@link CommandLog} to a JSON string. `EntityID` is a plain number
|
|
68
|
+
* and round-trips as-is; a `ComponentDef` is a callable, so the replacer writes
|
|
69
|
+
* it as `{ [DEF_TAG]: id }`. (The recorder already stripped `onSpawned`, the
|
|
70
|
+
* only other non-serializable member.)
|
|
71
|
+
*
|
|
72
|
+
* Throws {@link ECS_ERROR.COMMAND_LOG_TAG_COLLISION} if any non-def object in the
|
|
73
|
+
* log (i.e. a command's `values` map) owns a field named {@link DEF_TAG}: the
|
|
74
|
+
* reviver tags defs in-band, so such a value would be silently revived as a def,
|
|
75
|
+
* dropping the real field data. Field names are arbitrary, so this is reachable;
|
|
76
|
+
* failing here keeps the round-trip lossless instead of corrupting on parse. */
|
|
77
|
+
export declare function serializeCommandLog(log: CommandLog): string;
|
|
78
|
+
/** Parse a {@link CommandLog} from {@link serializeCommandLog} output. */
|
|
79
|
+
export declare function deserializeCommandLog(json: string): CommandLog;
|
|
80
|
+
/** Outcome of {@link replayCommandLog}. */
|
|
81
|
+
export interface ReplayResult {
|
|
82
|
+
/** Seed-time commands re-applied before the first tick. */
|
|
83
|
+
readonly startupCommands: number;
|
|
84
|
+
/** Update ticks replayed. */
|
|
85
|
+
readonly ticks: number;
|
|
86
|
+
/** Per-tick `stateHash` captured after each `update`, in tick order — empty
|
|
87
|
+
* unless the world is deterministic (or `hash` was forced). Compare against
|
|
88
|
+
* the original run's per-tick hashes to prove the replay matched (ADR-0020). */
|
|
89
|
+
readonly stateHashes: readonly number[];
|
|
90
|
+
}
|
|
91
|
+
/** Options for {@link replayCommandLog}. */
|
|
92
|
+
export interface ReplayOptions {
|
|
93
|
+
/** Capture `ecs.snapshots.stateHash()` after each tick. Defaults to the world's
|
|
94
|
+
* `deterministic` flag — a deterministic world is hashed, a non-deterministic
|
|
95
|
+
* one is not (its `stateHash` would throw, ADR-0020). Force `true` only on a
|
|
96
|
+
* deterministic world. */
|
|
97
|
+
readonly hash?: boolean;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Replay a recorded {@link CommandLog} against `world`, reproducing the original
|
|
101
|
+
* session tick-for-tick. `world` must be FRESH and NOT yet started, built
|
|
102
|
+
* identically to the recorded run (same components registered in the same order,
|
|
103
|
+
* same systems, same `seed` from `log.seed`) and seam-installed — pass the
|
|
104
|
+
* `HostCommandQueue` `installHostCommandSeam` returned as `queue`. The driver
|
|
105
|
+
* owns startup: it enqueues the seed-time commands, calls `ecs.startup()`
|
|
106
|
+
* (which drains them at PRE_STARTUP), then for each recorded tick enqueues that
|
|
107
|
+
* tick's commands and calls `ecs.update(dt)` with the recorded `dt`.
|
|
108
|
+
*
|
|
109
|
+
* Determinism (ADR-0020): with `{ deterministic: true }` the per-tick
|
|
110
|
+
* `stateHashes` this returns must equal the original run's — that equality is
|
|
111
|
+
* replay fidelity. Identity caveat (§85): a despawned-then-respawned entity gets
|
|
112
|
+
* a fresh id, but because spawn order is reproduced, every recorded id still
|
|
113
|
+
* resolves to the same entity on replay.
|
|
114
|
+
*/
|
|
115
|
+
export declare function replayCommandLog(ecs: ECS, queue: HostCommandQueue, log: CommandLog, opts?: ReplayOptions): ReplayResult;
|
|
116
|
+
//# sourceMappingURL=command_log.d.ts.map
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { ECS } from './ecs';
|
|
2
|
-
import { HostCommand, HostCommandQueue, HostCommandSink } from './host_commands';
|
|
1
|
+
import { ECS } from './ecs.js';
|
|
2
|
+
import { HostCommand, HostCommandQueue, HostCommandSink } from './host_commands.js';
|
|
3
3
|
/** One recorded update tick: the commands the apply system drained at this
|
|
4
|
-
* tick's update-phase head, plus the `dt` passed to `
|
|
4
|
+
* tick's update-phase head, plus the `dt` passed to `ecs.update(dt)`. Replay
|
|
5
5
|
* MUST re-issue `update(dt)` for every recorded tick — even an empty one — since
|
|
6
6
|
* `dt` itself drives the sim (movement, timers), not just the commands. */
|
|
7
7
|
export interface RecordedTick {
|
|
8
8
|
/** The ECS tick (`ctx.ecsTick`) this bucket belongs to. */
|
|
9
9
|
readonly tick: number;
|
|
10
|
-
/** The `dt` `
|
|
10
|
+
/** The `dt` `ecs.update(dt)` was called with for this tick. */
|
|
11
11
|
readonly dt: number;
|
|
12
12
|
/** Commands applied this tick, in apply order (typed queue first, then ring),
|
|
13
13
|
* `onSpawned` stripped. */
|
|
@@ -25,7 +25,7 @@ export interface CommandLog {
|
|
|
25
25
|
* rebuilds the world the same way the original was built. */
|
|
26
26
|
readonly seed: number;
|
|
27
27
|
/** Commands drained at the PRE_STARTUP head (seed-time edits), applied before
|
|
28
|
-
* the first update tick. Enqueued BEFORE `
|
|
28
|
+
* the first update tick. Enqueued BEFORE `ecs.startup()` on replay. */
|
|
29
29
|
readonly startup: readonly HostCommand[];
|
|
30
30
|
/** One entry per update tick, in order. */
|
|
31
31
|
readonly ticks: readonly RecordedTick[];
|
|
@@ -58,8 +58,11 @@ export declare class HostCommandRecorder implements HostCommandSink {
|
|
|
58
58
|
readonly record: (cmd: HostCommand) => void;
|
|
59
59
|
/** A live {@link CommandLog} view over the accumulated stream — not a copy.
|
|
60
60
|
* Serialize it (which deep-copies through JSON) before mutating the world
|
|
61
|
-
* further if you need a stable snapshot. */
|
|
61
|
+
* further if you need a stable snapshot, or use {@link snapshotLog}. */
|
|
62
62
|
log(): CommandLog;
|
|
63
|
+
/** A STABLE deep copy of the accumulated stream — safe to hold across
|
|
64
|
+
* further recording (the safe default; `log()` is the zero-copy live view). */
|
|
65
|
+
snapshotLog(): CommandLog;
|
|
63
66
|
}
|
|
64
67
|
/** Serialize a {@link CommandLog} to a JSON string. `EntityID` is a plain number
|
|
65
68
|
* and round-trips as-is; a `ComponentDef` is a callable, so the replacer writes
|
|
@@ -87,7 +90,7 @@ export interface ReplayResult {
|
|
|
87
90
|
}
|
|
88
91
|
/** Options for {@link replayCommandLog}. */
|
|
89
92
|
export interface ReplayOptions {
|
|
90
|
-
/** Capture `
|
|
93
|
+
/** Capture `ecs.snapshots.stateHash()` after each tick. Defaults to the world's
|
|
91
94
|
* `deterministic` flag — a deterministic world is hashed, a non-deterministic
|
|
92
95
|
* one is not (its `stateHash` would throw, ADR-0020). Force `true` only on a
|
|
93
96
|
* deterministic world. */
|
|
@@ -99,9 +102,9 @@ export interface ReplayOptions {
|
|
|
99
102
|
* identically to the recorded run (same components registered in the same order,
|
|
100
103
|
* same systems, same `seed` from `log.seed`) and seam-installed — pass the
|
|
101
104
|
* `HostCommandQueue` `installHostCommandSeam` returned as `queue`. The driver
|
|
102
|
-
* owns startup: it enqueues the seed-time commands, calls `
|
|
105
|
+
* owns startup: it enqueues the seed-time commands, calls `ecs.startup()`
|
|
103
106
|
* (which drains them at PRE_STARTUP), then for each recorded tick enqueues that
|
|
104
|
-
* tick's commands and calls `
|
|
107
|
+
* tick's commands and calls `ecs.update(dt)` with the recorded `dt`.
|
|
105
108
|
*
|
|
106
109
|
* Determinism (ADR-0020): with `{ deterministic: true }` the per-tick
|
|
107
110
|
* `stateHashes` this returns must equal the original run's — that equality is
|
|
@@ -109,5 +112,5 @@ export interface ReplayOptions {
|
|
|
109
112
|
* a fresh id, but because spawn order is reproduced, every recorded id still
|
|
110
113
|
* resolves to the same entity on replay.
|
|
111
114
|
*/
|
|
112
|
-
export declare function replayCommandLog(
|
|
115
|
+
export declare function replayCommandLog(ecs: ECS, queue: HostCommandQueue, log: CommandLog, opts?: ReplayOptions): ReplayResult;
|
|
113
116
|
//# sourceMappingURL=command_log.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command_log.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/command_log.ts"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEtF;;;2EAG2E;AAC3E,MAAM,WAAW,YAAY;IAC5B,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB
|
|
1
|
+
{"version":3,"file":"command_log.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/command_log.ts"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEtF;;;2EAG2E;AAC3E,MAAM,WAAW,YAAY;IAC5B,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;+BAC2B;IAC3B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;CAC1C;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B;;iEAE6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;2EACuE;IACvE,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;CACxC;AAiBD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IAC1D,iEAAiE;IACjE,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C;4EACwE;IACxE,OAAO,CAAC,IAAI,CAAgC;gBAEhC,IAAI,SAAI;IAIpB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAaxC,QAAQ,CAAC,MAAM,QAAS,WAAW,KAAG,IAAI,CAExC;IAEF;;4EAEwE;IACxE,GAAG,IAAI,UAAU;IAIjB;mFAC+E;IAC/E,WAAW,IAAI,UAAU;CAOzB;AAYD;;;;;;;;;gFASgF;AAChF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAqB3D;AAED,0EAA0E;AAC1E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAW9D;AAED,2CAA2C;AAC3C,MAAM,WAAW,YAAY;IAC5B,2DAA2D;IAC3D,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;oFAEgF;IAChF,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC7B;;;8BAG0B;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,UAAU,EACf,IAAI,CAAC,EAAE,aAAa,GAClB,YAAY,CAcd"}
|