@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
package/dist/core/ecs/store.d.ts
CHANGED
|
@@ -1,14 +1,36 @@
|
|
|
1
|
-
import { EntityID } from './entity';
|
|
2
|
-
import { FrameTraceSink } from './frame_trace';
|
|
3
|
-
import { ComponentDef, ComponentHandle, ComponentSchema, FieldValues } from './component';
|
|
4
|
-
import { SparseComponentDef, SparseComponentID } from './sparse_store';
|
|
5
|
-
import { RelationDef, RelationOptions } from './relation';
|
|
6
|
-
import { EmptyEventSchema, EventDef, EventReader,
|
|
7
|
-
import { BitSet, TypedArrayTag } from '../../type_primitives';
|
|
8
|
-
import { Archetype, ArchetypeID } from './archetype';
|
|
9
|
-
import { Query } from './query';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
1
|
+
import { EntityID } from './entity.js';
|
|
2
|
+
import { FrameTraceSink } from './frame_trace.js';
|
|
3
|
+
import { ComponentDef, ComponentHandle, ComponentSchema, FieldValues } from './component.js';
|
|
4
|
+
import { SparseComponentDef, SparseComponentID } from './sparse_store.js';
|
|
5
|
+
import { RelationDef, RelationOptions } from './relation.js';
|
|
6
|
+
import { EmptyEventSchema, EventDef, EventReader, EventShape } from './event.js';
|
|
7
|
+
import { BitSet, TypedArrayTag } from '../../type_primitives/index.js';
|
|
8
|
+
import { Archetype, ArchetypeID } from './archetype.js';
|
|
9
|
+
import { Query, QueryHost } from './query.js';
|
|
10
|
+
import { ObserverHost } from './observer.js';
|
|
11
|
+
import { InPlaceBufferAllocator, ColumnStoreRegionHandle, StoreRegionSpec, ColumnStore } from '../store/index.js';
|
|
12
|
+
import { ECSMemoryCapContext } from './ecs_memory.js';
|
|
13
|
+
export interface ComponentMeta {
|
|
14
|
+
/** Optional debug name from `registerComponent(schema, { name })` —
|
|
15
|
+
* diagnostic messages only, never behaviour. */
|
|
16
|
+
name?: string;
|
|
17
|
+
fieldNames: string[];
|
|
18
|
+
fieldIndex: Record<string, number>;
|
|
19
|
+
fieldTypes: TypedArrayTag[];
|
|
20
|
+
/** Has an onAdd observer — collect effective adds for this component. */
|
|
21
|
+
obsAdd: boolean;
|
|
22
|
+
/** Has an onRemove observer — collect effective removes for this component. */
|
|
23
|
+
obsRem: boolean;
|
|
24
|
+
/** Has an onDisable observer (#677) — collect effective disables for this
|
|
25
|
+
* component at the toggle drain. */
|
|
26
|
+
obsDisable: boolean;
|
|
27
|
+
/** Has an onEnable observer (#677) — collect effective enables for this
|
|
28
|
+
* component at the toggle drain. */
|
|
29
|
+
obsEnable: boolean;
|
|
30
|
+
/** Has a per-entity onSet observer — record dirty rows on the write path
|
|
31
|
+
* (the ADR-0012 opt-in dirty list). */
|
|
32
|
+
trackDirty: boolean;
|
|
33
|
+
}
|
|
12
34
|
/**
|
|
13
35
|
* Effective `(component, entity)` structural events for one fixed-point round,
|
|
14
36
|
* collected during `_flushAdds` / `_flushRemoves` and handed to the observer
|
|
@@ -38,8 +60,14 @@ export interface StructuralObserverEvents {
|
|
|
38
60
|
type SchemaOf<D extends ComponentDef> = D extends ComponentDef<infer S> ? S : ComponentSchema;
|
|
39
61
|
/** One typed template entry: `values` is checked against the def's schema —
|
|
40
62
|
* a misspelled field is a compile error. Fields may be omitted (they default
|
|
41
|
-
* to 0), so the map is `Partial`.
|
|
42
|
-
|
|
63
|
+
* to 0), so the map is `Partial`. Tag defs refuse `values` entirely — their
|
|
64
|
+
* `FieldValues` would otherwise degenerate to `Record<string, number>` (same
|
|
65
|
+
* pitfall as `ValuesArg`); a schema-erased `ComponentDef` falls into the
|
|
66
|
+
* valued branch, so untyped call sites keep the loose shape. */
|
|
67
|
+
export type TemplateEntry<D extends ComponentDef = ComponentDef> = SchemaOf<D> extends Record<string, never> ? {
|
|
68
|
+
readonly def: D;
|
|
69
|
+
readonly values?: undefined;
|
|
70
|
+
} : {
|
|
43
71
|
readonly def: D;
|
|
44
72
|
readonly values?: Partial<FieldValues<SchemaOf<D>>>;
|
|
45
73
|
};
|
|
@@ -55,7 +83,7 @@ export type TemplateEntries<Defs extends readonly ComponentDef[]> = readonly [
|
|
|
55
83
|
type TemplateFieldNames<Defs extends readonly ComponentDef[]> = Defs[number] extends ComponentDef<infer S> ? keyof S & string : never;
|
|
56
84
|
/** Flat per-instance override map for `ECS.spawn`: any field of any
|
|
57
85
|
* component in the template, each optional. A misspelled field is a compile
|
|
58
|
-
* error (and still a `
|
|
86
|
+
* error (and still a `DEV` throw at runtime for untyped call sites). */
|
|
59
87
|
export type TemplateOverrides<Defs extends readonly ComponentDef[]> = {
|
|
60
88
|
readonly [K in TemplateFieldNames<Defs>]?: number;
|
|
61
89
|
};
|
|
@@ -132,39 +160,26 @@ export interface StoreOptions {
|
|
|
132
160
|
* called per tick. */
|
|
133
161
|
deterministic?: boolean;
|
|
134
162
|
}
|
|
135
|
-
export declare class Store {
|
|
136
|
-
private
|
|
137
|
-
private entityHighWater;
|
|
138
|
-
private readonly entityFreeIndices;
|
|
139
|
-
private entityAliveCount;
|
|
163
|
+
export declare class Store implements ObserverHost, QueryHost {
|
|
164
|
+
private readonly entityAllocator;
|
|
140
165
|
private readonly componentMetas;
|
|
141
166
|
private componentCount;
|
|
142
167
|
private readonly sparseStores;
|
|
143
|
-
|
|
144
|
-
private
|
|
145
|
-
private readonly
|
|
146
|
-
private readonly
|
|
147
|
-
private
|
|
148
|
-
private readonly archetypes;
|
|
149
|
-
private readonly archetypeMap;
|
|
150
|
-
private nextArchetypeId;
|
|
151
|
-
private readonly componentIndex;
|
|
168
|
+
/** Debug names parallel to `sparseStores` — diagnostics only. */
|
|
169
|
+
private readonly sparseNames;
|
|
170
|
+
private readonly relationService;
|
|
171
|
+
private readonly events;
|
|
172
|
+
private readonly archGraph;
|
|
152
173
|
private readonly registeredQueries;
|
|
153
174
|
private emptyArchetypeId;
|
|
154
175
|
private entityArchetype;
|
|
155
176
|
private entityRow;
|
|
156
|
-
private readonly
|
|
157
|
-
private readonly
|
|
158
|
-
private readonly pendingAddDefs;
|
|
159
|
-
private readonly pendingAddValues;
|
|
160
|
-
private readonly pendingRemoveIds;
|
|
161
|
-
private readonly pendingRemoveDefs;
|
|
162
|
-
private readonly pendingToggleIds;
|
|
163
|
-
private readonly pendingToggleDisable;
|
|
177
|
+
private readonly _deferred;
|
|
178
|
+
private readonly _snapshots;
|
|
164
179
|
_tick: number;
|
|
165
180
|
/** Per-world frame-trace sink (ADR-0030), installed via `ECS.setTrace`.
|
|
166
181
|
* `null` unless a consumer attaches a recorder. Every call site is
|
|
167
|
-
* `if (
|
|
182
|
+
* `if (DEV) store._trace?.…`, so production builds dead-code-eliminate
|
|
168
183
|
* the seam and pay only this one nullable field. The sink observes; it never
|
|
169
184
|
* folds into `stateHash` (a scheduling artifact, like `_changedTick` / the
|
|
170
185
|
* observer state below). */
|
|
@@ -176,15 +191,14 @@ export declare class Store {
|
|
|
176
191
|
private _toggleObserverCount;
|
|
177
192
|
/** Reused effective-event scratch for the current flush round. */
|
|
178
193
|
private readonly _obsEvents;
|
|
179
|
-
/** Installed
|
|
180
|
-
* registry (ordering + callbacks), which may enqueue
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
|
|
187
|
-
private _flushingStructural;
|
|
194
|
+
/** Installed via `setStructuralObserverHook` — dispatches a round's collected
|
|
195
|
+
* events to the observer registry (ordering + callbacks), which may enqueue
|
|
196
|
+
* further structural ops. */
|
|
197
|
+
private _structuralObserverHook;
|
|
198
|
+
/** Install the structural-observer dispatch hook (called once by `ECS`
|
|
199
|
+
* during construction) — the named seam replacing direct writes to the
|
|
200
|
+
* previously-public field (M1). */
|
|
201
|
+
setStructuralObserverHook(fn: (ev: StructuralObserverEvents) => void): void;
|
|
188
202
|
private _collectDestroyEid;
|
|
189
203
|
private readonly _collectDestroyRemoveBit;
|
|
190
204
|
private _collectToggleEid;
|
|
@@ -210,7 +224,7 @@ export declare class Store {
|
|
|
210
224
|
/** Monotonic counter bumped by every membership-changing path (immediate
|
|
211
225
|
* `addComponent(s)`, `removeComponent(s)`, `destroyEntity`,
|
|
212
226
|
* `batchAddComponent`, `batchRemoveComponent`, `flushStructural`,
|
|
213
|
-
* `flushDestroyed`, and new-archetype installs in `
|
|
227
|
+
* `flushDestroyed`, and new-archetype installs in `ArchetypeGraph.install`).
|
|
214
228
|
* Read by `Query._nonEmpty()` via `QueryResolver._getQueryDirtyEpoch`
|
|
215
229
|
* — a query whose stored `_lastSeenEpoch` matches the current epoch
|
|
216
230
|
* reuses its cached non-empty list (#327). Replaces the previous walk
|
|
@@ -221,17 +235,7 @@ export declare class Store {
|
|
|
221
235
|
_queryDirtyEpoch: number;
|
|
222
236
|
private readonly initialCapacity;
|
|
223
237
|
private readonly _scratchTargetMask;
|
|
224
|
-
private readonly _hierarchyRadixOut;
|
|
225
|
-
private readonly _hierarchyRadixC0;
|
|
226
|
-
private readonly _hierarchyRadixC1;
|
|
227
238
|
private _columnStore;
|
|
228
|
-
/** Single-slot Uint32Array view over the entity-index region's `length`
|
|
229
|
-
* header field. `createEntity`'s hot path writes `entityHighWater`
|
|
230
|
-
* here on every high-water bump; using a pre-built typed-array view
|
|
231
|
-
* skips the DataView lookup + setUint32 dispatch that #368 traced to
|
|
232
|
-
* ~25 ns/op on `frame_loop_focused: createEntity` (closes the
|
|
233
|
-
* post-#361 gap to oecs entirely). Rebuilt on SAB resize. */
|
|
234
|
-
private _entityIndexLengthView;
|
|
235
239
|
/** Installed on every SAB-backed Archetype so the Archetype can
|
|
236
240
|
* request a SAB grow when an insertion would exceed its column
|
|
237
241
|
* capacity. Doubles the offending archetype's row capacity (or jumps
|
|
@@ -282,7 +286,7 @@ export declare class Store {
|
|
|
282
286
|
/** Guard the canonical-ordering determinism surface. Throws
|
|
283
287
|
* `DETERMINISM_DISABLED` when determinism wasn't opted into, naming the
|
|
284
288
|
* method so the caller knows to pass `{ deterministic: true }`. Always on
|
|
285
|
-
* (not `
|
|
289
|
+
* (not `DEV`-gated): the surface is cold (never per-tick) so one boolean
|
|
286
290
|
* check is free, and a silent non-canonical digest is the failure mode we're
|
|
287
291
|
* preventing. */
|
|
288
292
|
private _requireDeterministic;
|
|
@@ -338,7 +342,7 @@ export declare class Store {
|
|
|
338
342
|
*
|
|
339
343
|
* Lockstep walk: SAB descriptors are written by `extendColumnStore` in
|
|
340
344
|
* the order non-SAB archetypes are promoted, which is the same id-order
|
|
341
|
-
* those archetypes occupy in `this.archetypes`. Iterating that array
|
|
345
|
+
* those archetypes occupy in `this.archGraph.archetypes`. Iterating that array
|
|
342
346
|
* once, skipping non-SAB entries, and advancing an `archAddr` cursor
|
|
343
347
|
* by the descriptor's `column_count` lets us write `row_count` without
|
|
344
348
|
* the throwaway `Map<archId, length>` the previous version allocated
|
|
@@ -409,72 +413,42 @@ export declare class Store {
|
|
|
409
413
|
* happened mid-tick), both of which are bugs the parity test would
|
|
410
414
|
* surface. */
|
|
411
415
|
entityIdAtRow(archetypeId: number, row: number): EntityID;
|
|
412
|
-
/**
|
|
413
|
-
*
|
|
414
|
-
* Also updates the componentIndex and pushes into matching registered queries.
|
|
415
|
-
*
|
|
416
|
-
* Hot single-mask path. The bulk batched variant — used by Phase C
|
|
417
|
-
* pre-warming at `world.startup()` — is `archCreateManyFromMasks`;
|
|
418
|
-
* see #213 / `ECS.startup()` for how it gets called and why.
|
|
419
|
-
*/
|
|
416
|
+
/** Find or create an archetype for the given component mask — see
|
|
417
|
+
* `ArchetypeGraph.getOrCreateFromMask`. */
|
|
420
418
|
private archGetOrCreateFromMask;
|
|
421
|
-
/**
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
* Given a set of masks, creates Archetypes for the ones not already
|
|
425
|
-
* planted, in a SINGLE `extendColumnStore` call (instead of one per
|
|
426
|
-
* archetype). Single-mask creation is O(N) in archetypes-so-far because
|
|
427
|
-
* the extend has to copy every existing archetype's live rows forward;
|
|
428
|
-
* N such calls compound to O(N²). Batching collapses the per-archetype
|
|
429
|
-
* setup-and-copy down to one pass — the per-startup cost the design doc
|
|
430
|
-
* §5.2 calls out as "O(N²) → O(N)" for in-tree systems whose archetype
|
|
431
|
-
* set is known at registration time via `spawns` + `transitions`.
|
|
432
|
-
*
|
|
433
|
-
* Masks already in the map are skipped. Returns the resolved
|
|
434
|
-
* `ArchetypeID` per input mask in input order — callers that don't need
|
|
435
|
-
* the ids can ignore the return value.
|
|
436
|
-
*/
|
|
419
|
+
/** Bulk variant of `archGetOrCreateFromMask` — one `extendColumnStore`
|
|
420
|
+
* call for the whole batch (Phase C prewarm, #213). See
|
|
421
|
+
* `ArchetypeGraph.createManyFromMasks`. */
|
|
437
422
|
archCreateManyFromMasks(masks: readonly BitSet[]): ArchetypeID[];
|
|
438
|
-
/** Hash-bucketed mask → ArchetypeID lookup; null when the mask isn't planted. */
|
|
439
|
-
private archLookup;
|
|
440
|
-
/** Walk the mask's set bits and resolve each non-tag component to its
|
|
441
|
-
* layout. Used by both single and bulk archetype-create paths. */
|
|
442
|
-
private archBuildLayouts;
|
|
443
423
|
/** Snapshot every existing archetype's SAB rows, call `extendColumnStore`
|
|
444
424
|
* once with `newSpecs`, then refresh every pre-existing SAB-backed
|
|
445
425
|
* Archetype's TypedArray views. The single `existing` snapshot is the
|
|
446
426
|
* key win in the bulk variant — single-mask creation rebuilds it per
|
|
447
427
|
* call (i.e. N times for N new archetypes). */
|
|
448
|
-
private
|
|
449
|
-
/** Materialise the `Archetype` for
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
/** Resolve "add component_id to archetype_id" → target ArchetypeID. Caches the edge. */
|
|
428
|
+
private _archExtendStoreWithNewSpecs;
|
|
429
|
+
/** Materialise the `Archetype` object for a freshly-minted graph node —
|
|
430
|
+
* binds the graph's topology to THIS store's column backing and grow
|
|
431
|
+
* handler (`ArchetypeGraphHost.materialize`). Store-owned so the graph
|
|
432
|
+
* never touches `_columnStore`. */
|
|
433
|
+
private _materializeArchetype;
|
|
434
|
+
/** Push a newly-installed archetype into every registered query whose masks
|
|
435
|
+
* it satisfies (`ArchetypeGraphHost.fanIntoQueries`; the query registry
|
|
436
|
+
* stays on Store). No epoch bump — see the note in `ArchetypeGraph.install`. */
|
|
437
|
+
private _fanIntoQueries;
|
|
438
|
+
/** Resolve "add component_id to archetype_id" → target ArchetypeID (edge-cached). */
|
|
460
439
|
private archResolveAdd;
|
|
461
|
-
/** Resolve "remove component_id from archetype_id" → target ArchetypeID
|
|
440
|
+
/** Resolve "remove component_id from archetype_id" → target ArchetypeID (edge-cached). */
|
|
462
441
|
private archResolveRemove;
|
|
463
|
-
/** Cache a bidirectional add/remove edge between two archetypes. */
|
|
464
|
-
private archCacheEdge;
|
|
465
442
|
createEntity(): EntityID;
|
|
466
|
-
/** Slot index of the entity allocated by the most recent `_allocEntity`
|
|
467
|
-
* call. Read immediately after the call (alloc-free out-param). */
|
|
468
|
-
private _spawnIndex;
|
|
469
443
|
/** Allocate an entity slot WITHOUT placing it in the empty archetype, for
|
|
470
|
-
* the template spawn paths. Returns the packed `EntityID`; the slot index
|
|
471
|
-
* left in `
|
|
472
|
-
*
|
|
473
|
-
* + row).
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
*
|
|
444
|
+
* the template spawn paths. Returns the packed `EntityID`; the slot index
|
|
445
|
+
* is left in `entityAllocator.lastIndex`. Skips the empty-archetype
|
|
446
|
+
* membership write `createEntity` performs (the caller installs the real
|
|
447
|
+
* archetype + row). This *commits* the slot (bumps counts, stamps the
|
|
448
|
+
* generation so `isAlive` is already true), so the caller MUST have
|
|
449
|
+
* reserved the column capacity for the row first
|
|
450
|
+
* (`Archetype.ensureRowCapacity`) — otherwise a cap throw from the
|
|
451
|
+
* subsequent append leaves the slot phantom-alive (#775). */
|
|
478
452
|
private _allocEntity;
|
|
479
453
|
/** Pre-check that `count` fresh entity slots can be allocated without
|
|
480
454
|
* exhausting the entity-index space, so `spawnMany` commits all-or-nothing
|
|
@@ -490,9 +464,16 @@ export declare class Store {
|
|
|
490
464
|
* column index; `TEMPLATE_OVERRIDE_AMBIGUOUS` for a name shared by more than
|
|
491
465
|
* one component, which a flat override cannot target). */
|
|
492
466
|
resolveTemplate<Defs extends readonly ComponentDef[]>(entries: TemplateEntries<Defs>): Template<Defs>;
|
|
467
|
+
/** Resolve an override key to its flat column index, with the DEV guards
|
|
468
|
+
* for unknown and ambiguous field names; `-1` means skip (the production
|
|
469
|
+
* fallback where DEV would have thrown). */
|
|
470
|
+
private _resolveOverrideColumn;
|
|
493
471
|
/** Apply per-instance overrides to the freshly-spawned row. Each key is a
|
|
494
472
|
* field name resolved through the template's override index. */
|
|
495
473
|
private _applyOverrides;
|
|
474
|
+
/** Bulk variant of `_applyOverrides`: one `fill` per overridden column
|
|
475
|
+
* across the contiguous rows `[start, start + count)`. */
|
|
476
|
+
private _applyOverridesRange;
|
|
496
477
|
/** Spawn one entity directly into the template's archetype (zero archetype
|
|
497
478
|
* transitions). Writes the template defaults in a single append pass, then
|
|
498
479
|
* applies any per-instance overrides. */
|
|
@@ -501,7 +482,7 @@ export declare class Store {
|
|
|
501
482
|
* field writes are O(columns) — one `TypedArray.fill` per column via
|
|
502
483
|
* `addEntitiesWithValues` — not O(count×columns). Returns the new ids in
|
|
503
484
|
* spawn order. */
|
|
504
|
-
spawnMany(p: Template, count: number): EntityID[];
|
|
485
|
+
spawnMany(p: Template, count: number, overrides?: Record<string, number | undefined>): EntityID[];
|
|
505
486
|
/** Immediately destroy an entity, removing it from its archetype.
|
|
506
487
|
*
|
|
507
488
|
* With no `delete`/`clear` target-cleanup policy registered (the common
|
|
@@ -603,7 +584,7 @@ export declare class Store {
|
|
|
603
584
|
private _onArchEnabledChange;
|
|
604
585
|
/** Immediately disable an entity (idempotent). The entity must hold at least
|
|
605
586
|
* one component — a component-less entity occupies no archetype row, so it
|
|
606
|
-
* cannot be partitioned (a `
|
|
587
|
+
* cannot be partitioned (a `DEV` error; prod no-op). */
|
|
607
588
|
disableEntity(id: EntityID): void;
|
|
608
589
|
/** Immediately enable an entity (idempotent). */
|
|
609
590
|
enableEntity(id: EntityID): void;
|
|
@@ -665,17 +646,22 @@ export declare class Store {
|
|
|
665
646
|
* the identity of what was destroyed, not a live handle to read. The
|
|
666
647
|
* no-observer path is byte-for-byte unchanged (`collecting` gate). #531.
|
|
667
648
|
*
|
|
668
|
-
* Re-entrancy: while the observed fixed point owns the flush
|
|
669
|
-
*
|
|
670
|
-
* `
|
|
671
|
-
*
|
|
672
|
-
* mid-dispatch and corrupt it
|
|
649
|
+
* Re-entrancy: while the observed fixed point owns the flush, the loop
|
|
650
|
+
* drains destroys itself via `_drainDestroyed`, so a re-entrant
|
|
651
|
+
* `ctx.flush()` from a callback no-ops (the guard lives in
|
|
652
|
+
* `DeferredCommandBuffer.flushDestroyed`) — otherwise it would collect
|
|
653
|
+
* into the shared `_obsEvents` scratch mid-dispatch and corrupt it. */
|
|
673
654
|
flushDestroyed(): void;
|
|
674
655
|
private _drainDestroyed;
|
|
675
656
|
get pendingDestroyCount(): number;
|
|
676
657
|
addComponentDeferred(entityId: EntityID, def: ComponentDef<Record<string, never>>): void;
|
|
677
658
|
addComponentDeferred<S extends ComponentSchema>(entityId: EntityID, def: ComponentDef<S>, values: FieldValues<S>): void;
|
|
678
659
|
removeComponentDeferred(entityId: EntityID, def: ComponentDef): void;
|
|
660
|
+
/** Phase-boundary structural flush. The drain policy — no-observer fast
|
|
661
|
+
* path, observed fixed point (adds/removes → destroys → toggles),
|
|
662
|
+
* convergence guard, re-entrancy — lives in `DeferredCommandBuffer`
|
|
663
|
+
* (H1 step 4); the batch appliers it drives are the `_flush*` /
|
|
664
|
+
* `_drainDestroyed` methods below. */
|
|
679
665
|
flushStructural(): void;
|
|
680
666
|
/** Batch-apply all deferred component additions. */
|
|
681
667
|
private _flushAdds;
|
|
@@ -714,7 +700,10 @@ export declare class Store {
|
|
|
714
700
|
* absent at seed (the "delete on disable" semantics). Unordered here — the
|
|
715
701
|
* registry radix-sorts. */
|
|
716
702
|
_collectEntitiesWithComponent(cid: number): EntityID[];
|
|
717
|
-
registerComponent<S extends Record<string, TypedArrayTag>>(schema: S): ComponentDef<S>;
|
|
703
|
+
registerComponent<S extends Record<string, TypedArrayTag>>(schema: S, name?: string): ComponentDef<S>;
|
|
704
|
+
/** `'Pos' (component 5)` when the component was registered with a debug
|
|
705
|
+
* name, else `component 5` — the label diagnostics interpolate. */
|
|
706
|
+
componentLabel(cid: number): string;
|
|
718
707
|
/** Return the field index assigned to `(def, fieldName)` at component
|
|
719
708
|
* registration. Indexes are insertion-order, zero-based, and stable for
|
|
720
709
|
* the lifetime of the ECS. Used by systems that pass `(component_id,
|
|
@@ -724,7 +713,9 @@ export declare class Store {
|
|
|
724
713
|
* allocates from a separate id space and never touches the archetype mask,
|
|
725
714
|
* so it does **not** count against `STORE_DESCRIPTOR_COMPONENT_LIMIT`. See
|
|
726
715
|
* ADR-0011 and `sparse_store.ts`. */
|
|
727
|
-
registerSparseComponent<S extends Record<string, TypedArrayTag>>(schema: S): SparseComponentDef<S>;
|
|
716
|
+
registerSparseComponent<S extends Record<string, TypedArrayTag>>(schema: S, name?: string): SparseComponentDef<S>;
|
|
717
|
+
/** Sparse sibling of `componentLabel` — sparse ids are a separate id space. */
|
|
718
|
+
sparseLabel(sid: number): string;
|
|
728
719
|
/** Allocate the backing sparse store WITHOUT the #777 float guard, for
|
|
729
720
|
* engine-internal backings whose `f64` holds an EXACT integer rather than a
|
|
730
721
|
* user quantity: the exclusive-relation `{ target }` slot stores an `EntityID`
|
|
@@ -738,6 +729,7 @@ export declare class Store {
|
|
|
738
729
|
addSparse(entityId: EntityID, def: SparseComponentDef, values?: Record<string, number>): void;
|
|
739
730
|
/** Remove a sparse component from an entity. No-op if absent. */
|
|
740
731
|
removeSparse(entityId: EntityID, def: SparseComponentDef): void;
|
|
732
|
+
/** Total, like `hasComponent` — `false` for a dead entity, never a throw. */
|
|
741
733
|
hasSparse(entityId: EntityID, def: SparseComponentDef): boolean;
|
|
742
734
|
getSparseField(entityId: EntityID, def: SparseComponentDef, field: string): number;
|
|
743
735
|
setSparseField(entityId: EntityID, def: SparseComponentDef, field: string, value: number): void;
|
|
@@ -774,13 +766,6 @@ export declare class Store {
|
|
|
774
766
|
* Store was constructed with `{ deterministic: true }`; paired with
|
|
775
767
|
* `snapshotSparse`, which produces the canonical bytes restore consumes. */
|
|
776
768
|
restoreSparse(bytes: Uint8Array): void;
|
|
777
|
-
/** Rebuild every relation's derived side indices after the sparse stores have
|
|
778
|
-
* been restored. `restoreRelations` resets all relations, rebuilds the multi
|
|
779
|
-
* forward sets + their reverse edges from `relBytes`, and validates shape.
|
|
780
|
-
* The exclusive reverse index can't be carried in the bytes (it's derivable),
|
|
781
|
-
* so it's rebuilt here from the backing sparse store: every member row holds
|
|
782
|
-
* `(source index → target EntityID)`, which is exactly one reverse edge. */
|
|
783
|
-
private _rebuildRelationIndices;
|
|
784
769
|
/**
|
|
785
770
|
* Capture the full live world to one self-contained byte buffer that
|
|
786
771
|
* `restoreInto` can mount back onto a live, ticking world ("rewind a running
|
|
@@ -802,9 +787,6 @@ export declare class Store {
|
|
|
802
787
|
* are scheduling artifacts, never folded into `stateHash`. Take the snapshot
|
|
803
788
|
* at a tick boundary (between `update()`s). See the ADR. */
|
|
804
789
|
snapshot(): Uint8Array;
|
|
805
|
-
/** Gather the host-side state a snapshot carries alongside the dense + sparse
|
|
806
|
-
* bytes — see `snapshot()`. The free-list is copied (it's a live mutable). */
|
|
807
|
-
private _collectHostState;
|
|
808
790
|
/**
|
|
809
791
|
* Mount a `snapshot()` buffer onto this live world and leave it ready to keep
|
|
810
792
|
* ticking. Fails closed on a malformed frame or a registration mismatch
|
|
@@ -818,15 +800,12 @@ export declare class Store {
|
|
|
818
800
|
* entity-index capacity. **Opt-in (ADR-0020):** throws `DETERMINISM_DISABLED`
|
|
819
801
|
* unless `{ deterministic: true }`. See `snapshot()` for the v1 scope. */
|
|
820
802
|
restoreInto(bytes: Uint8Array): void;
|
|
821
|
-
/**
|
|
822
|
-
*
|
|
823
|
-
*
|
|
824
|
-
*
|
|
825
|
-
*
|
|
826
|
-
|
|
827
|
-
* differing relation set changes the sparse store count / schema. Throws
|
|
828
|
-
* `SparseRestoreError` on a mismatch. */
|
|
829
|
-
private _assertSparseSectionMatches;
|
|
803
|
+
/** Adopt a restored dense store (`SnapshotService.restoreInto`'s mount
|
|
804
|
+
* step): swap the live backing, refresh every buffer-backed archetype's
|
|
805
|
+
* views, recover the allocator high-water from the restored region, and
|
|
806
|
+
* republish (the grow tail). Store-owned because it assigns
|
|
807
|
+
* `_columnStore` — the service never writes Store fields. */
|
|
808
|
+
private _mountRestoredDense;
|
|
830
809
|
/** Rebuild each SAB-backed archetype's host-side `length` / `enabledCount` /
|
|
831
810
|
* `_entityIds` after the dense backing was swapped in `restoreInto`. `length`
|
|
832
811
|
* + the per-row entity-id back-reference come from a scan of the restored
|
|
@@ -834,167 +813,26 @@ export declare class Store {
|
|
|
834
813
|
* from the captured host-state (the #577 partition boundary is positional only
|
|
835
814
|
* — it has no per-entity byte source). */
|
|
836
815
|
private _reconstructHostRows;
|
|
837
|
-
/** Register a relation kind. `exclusive` (the default) → one target per
|
|
838
|
-
* source, stored in a backing `{ target: f64 }` sparse component, so the
|
|
839
|
-
* forward index rides the sparse store and inherits query membership (#469),
|
|
840
|
-
* `stateHash` + snapshot/restore (#470) for free. `multi` → a set of
|
|
841
|
-
* targets per source, backed by a sparse tag for membership plus a side
|
|
842
|
-
* forward index the relation owns. The two cardinalities are mutually
|
|
843
|
-
* exclusive. `onDeleteTarget` selects the cleanup policy run when a target
|
|
844
|
-
* is destroyed — `delete` (cascade-destroy sources), `clear` (drop the link,
|
|
845
|
-
* sources survive), or `orphan` (default: leave it dangling, #473). See
|
|
846
|
-
* ADR-0011 and `relation.ts`.
|
|
847
|
-
*
|
|
848
|
-
* The backing sparse store is resolved and handed to the relation so it can
|
|
849
|
-
* drive forward/membership rows directly — the cardinality-specific
|
|
850
|
-
* interaction is `ExclusiveRelationStore` / `MultiRelationStore`'s, not a
|
|
851
|
-
* branch here (#498). */
|
|
852
816
|
registerRelation(opts?: RelationOptions): RelationDef;
|
|
853
|
-
private relationOf;
|
|
854
817
|
/** Number of registered relations. Visible to tests asserting the
|
|
855
818
|
* no-transition invariant alongside `archetype_count`. */
|
|
856
819
|
get relationCount(): number;
|
|
857
|
-
/** Add a `(R, tgt)` pair to `src`. No archetype transition. Exclusive:
|
|
858
|
-
* replaces any existing target (engine-enforced one-per-source), a no-op if
|
|
859
|
-
* `tgt` is already the target. Multi: adds `tgt` to the set, a no-op if
|
|
860
|
-
* already present. A dead `src` *or* `tgt` is caller error: it throws in
|
|
861
|
-
* `__DEV__` and is a no-op in production — symmetric, so a production build
|
|
862
|
-
* never links a reverse-index entry keyed by a destroyed handle (#495). */
|
|
863
820
|
addRelation(src: EntityID, def: RelationDef, tgt: EntityID): void;
|
|
864
|
-
/** Remove a `(R, tgt)` pair from `src`. No archetype transition. Exclusive:
|
|
865
|
-
* `tgt` is optional and the removal is a no-op when it names a target other
|
|
866
|
-
* than the current one. Multi: omitting `tgt` removes *all* of `src`'s
|
|
867
|
-
* targets; passing one removes just that pair (dropping membership when the
|
|
868
|
-
* set empties). */
|
|
869
821
|
removeRelation(src: EntityID, def: RelationDef, tgt?: EntityID): void;
|
|
870
|
-
/** The single target of `src` under an exclusive relation, or `undefined`.
|
|
871
|
-
* Throws in `__DEV__` on a multi-target relation (use `targetsOf`). */
|
|
872
822
|
targetOf(src: EntityID, def: RelationDef): EntityID | undefined;
|
|
873
|
-
/** All targets of `src` under `R` — one or zero for exclusive, the full set
|
|
874
|
-
* for multi — ascending by id. */
|
|
875
823
|
targetsOf(src: EntityID, def: RelationDef): EntityID[];
|
|
876
|
-
|
|
877
|
-
* id; empty when none. */
|
|
878
|
-
sourcesOf(def: RelationDef, tgt: EntityID): EntityID[];
|
|
879
|
-
/** Whether `src` holds any pair under `R`. */
|
|
824
|
+
sourcesOf(tgt: EntityID, def: RelationDef): EntityID[];
|
|
880
825
|
hasRelation(src: EntityID, def: RelationDef): boolean;
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
* determinism convention): exclusive relations ride the backing sparse
|
|
884
|
-
* store's `canonicalIndices`, multi relations ride the same
|
|
885
|
-
* `forEachCanonicalTargetSet` traversal `stateHash` / `snapshotRelations`
|
|
886
|
-
* use; a multi source's targets follow ascending by id. Empty when the
|
|
887
|
-
* relation holds no pairs. Cold path — allocates the result array (and, for
|
|
888
|
-
* multi, sorts each source's target set); not for per-tick use. The
|
|
889
|
-
* point-query forms are `targetOf` / `targetsOf`. */
|
|
890
|
-
pairsOf(def: RelationDef): [EntityID, EntityID][];
|
|
891
|
-
/** Every `(relation, source)` pointing at `tgt`, across **all** registered
|
|
892
|
-
* relation kinds — the `(*, T)` wildcard (#472). Walks the relation registry
|
|
893
|
-
* in id order (each relation's reverse index already returns sources
|
|
894
|
-
* ascending by id), so the result is ordered by relation id then source id.
|
|
895
|
-
* Empty when nothing targets `tgt`. The single-relation form is
|
|
896
|
-
* `sourcesOf(def, tgt)`. */
|
|
897
|
-
sourcesOfAny(tgt: EntityID): [RelationDef, EntityID][];
|
|
898
|
-
/** The backing sparse component id of relation `R` — the membership store a
|
|
899
|
-
* `(R, *)` wildcard term (`Query.withRelation`) drives through the shared
|
|
900
|
-
* sparse-match path. Exclusive relations back a `{ target: f64 }` sparse
|
|
901
|
-
* component, multi a tag; both carry per-source membership, so "has any
|
|
902
|
-
* `(R, *)` pair" is exactly membership in this store (including an
|
|
903
|
-
* orphan-dangling source, whose membership row persists — consistent with
|
|
904
|
-
* `pairsOf`). The def is engine-owned and never handed to callers; this hands
|
|
905
|
-
* the query builder only its erased id for the `sparseInclude` list. */
|
|
826
|
+
pairsOf(def: RelationDef): readonly (readonly [EntityID, EntityID])[];
|
|
827
|
+
sourcesOfAny(tgt: EntityID): readonly (readonly [RelationDef, EntityID])[];
|
|
906
828
|
relationBackingSparseId(def: RelationDef): SparseComponentID;
|
|
907
|
-
/** Drive a `(*, T)` wildcard query (`Query.forEachRelatedTo`)
|
|
908
|
-
*
|
|
909
|
-
* dense mask + sparse require/exclude terms + the default enabled-row filter,
|
|
910
|
-
* each source yielded once. Unions `sourcesOf(R, target)` across every
|
|
911
|
-
* relation into a `Set` (dedup by full `EntityID` — a source related to `T`
|
|
912
|
-
* via two relations is yielded once), then sorts ascending: the cross-relation
|
|
913
|
-
* union has no inherent order, so one cold sort gives a deterministic,
|
|
914
|
-
* canonical `(*, T)` order matching `sourcesOf` / `sourcesOfAny` (which sort
|
|
915
|
-
* the same way). Cold/structural — not a per-tick hot loop over many targets.
|
|
916
|
-
* `sparseInclude`/`sparseExclude` carry both raw sparse terms and the backing
|
|
917
|
-
* stores of any composed `(R, *)` terms, so it intersects with them uniformly. */
|
|
829
|
+
/** Drive a `(*, T)` wildcard query (`Query.forEachRelatedTo`) — see
|
|
830
|
+
* `RelationService.forEachRelationTargetMatch`. */
|
|
918
831
|
_forEachRelationTargetMatch(target: EntityID, include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], includeDisabled: boolean, cb: (entityId: EntityID) => void): void;
|
|
919
|
-
/** Reclaim reverse-index memory: drop every relation's reverse entries whose
|
|
920
|
-
* **target** has been destroyed, returning the total dropped across all
|
|
921
|
-
* relations (#491). Under the default `orphan` policy a destroyed target
|
|
922
|
-
* leaves its reverse entry intact until each source re-targets or dies, so a
|
|
923
|
-
* long-lived source that orphan-points at a churn of short-lived targets and
|
|
924
|
-
* never re-targets accumulates dead-target keys without bound. This cold-path
|
|
925
|
-
* hook drops them on demand — call it at scene or snapshot boundaries.
|
|
926
|
-
*
|
|
927
|
-
* Purely a memory reclaim with no observable state change: forward links stay
|
|
928
|
-
* dangling (so `orphan`'s `targetOf`-returns-the-dead-handle contract is
|
|
929
|
-
* unchanged), `stateHash` is unaffected (the reverse index is derived, never
|
|
930
|
-
* folded), and the dropped entries are faithfully rebuilt by snapshot/restore
|
|
931
|
-
* from the surviving forward links (`_rebuildRelationIndices`). The only
|
|
932
|
-
* difference a caller can see is `sourcesOf(R, deadHandle)` going from the
|
|
933
|
-
* dangling sources to `[]` — both meaningless once the target is gone.
|
|
934
|
-
* No-op (returns 0) when no relations are registered. */
|
|
935
832
|
compactRelations(): number;
|
|
936
|
-
/** Walk exclusive relation `R` from `src` toward the root, returning the
|
|
937
|
-
* **up**-chain `[src, parent, grandparent, …, root]` (nearest-ancestor-first,
|
|
938
|
-
* inclusive of both endpoints). A source with no target returns `[src]`. The
|
|
939
|
-
* root is the first entity in the chain with no `R`-target, **or** a dangling
|
|
940
|
-
* dead target handle (see below). Throws `RELATION_MODE_MISMATCH` on a multi
|
|
941
|
-
* relation and `RELATION_CYCLE` on a cycle (both `__DEV__`-only; in production
|
|
942
|
-
* a cycle stops at the repeated node).
|
|
943
|
-
*
|
|
944
|
-
* **Dangling links terminate the chain.** Under the `orphan` policy a source
|
|
945
|
-
* keeps pointing at a destroyed target (a dead handle). The walk must *not*
|
|
946
|
-
* advance through such a handle: the backing store is keyed by entity
|
|
947
|
-
* **index**, so reading the dead handle's index would return whatever now
|
|
948
|
-
* occupies that recycled slot — splicing the chain onto an unrelated entity
|
|
949
|
-
* (the ABA the `EntityID`-keyed reverse index avoids for `cascadeOf`). So a
|
|
950
|
-
* dead next-hop is appended as the chain's (dangling) terminus and the walk
|
|
951
|
-
* stops; the caller can detect it with `isAlive`, exactly as `targetOf`
|
|
952
|
-
* returns a dead handle. */
|
|
953
833
|
ancestorsOf(src: EntityID, def: RelationDef): EntityID[];
|
|
954
|
-
/** The root of `src`'s exclusive-relation chain — the last entity of
|
|
955
|
-
* `ancestorsOf` (the one with no `R`-target). `src` itself when it has no
|
|
956
|
-
* target. If the chain ends in a dangling dead target handle (orphan policy),
|
|
957
|
-
* that handle is the root — `isAlive`-check the result if dangling links are
|
|
958
|
-
* possible. Same `__DEV__` guards as `ancestorsOf`. */
|
|
959
834
|
rootOf(src: EntityID, def: RelationDef): EntityID;
|
|
960
|
-
/** Walk exclusive relation `R` **down** from `root` over the reverse index,
|
|
961
|
-
* returning the subtree (including `root`) breadth-first — **parents before
|
|
962
|
-
* children** (the `cascade` order). Children of each node come from
|
|
963
|
-
* `sourcesOf` (ascending by id), so the traversal is deterministic. Throws
|
|
964
|
-
* `RELATION_MODE_MISMATCH` on a multi relation and `RELATION_CYCLE` on a cycle
|
|
965
|
-
* (both `__DEV__`-only; in production an already-visited node is skipped, so
|
|
966
|
-
* it never hangs). */
|
|
967
835
|
cascadeOf(root: EntityID, def: RelationDef): EntityID[];
|
|
968
|
-
/** Purge a destroyed entity from the relation indices — its **source** role
|
|
969
|
-
* only: drop its forward target(s) and unlink it from every target's reverse
|
|
970
|
-
* set. The backing sparse membership row is dropped separately by
|
|
971
|
-
* `_purgeSparse`, so this must run *before* it (it reads the sparse target
|
|
972
|
-
* field for exclusive relations). The entity's **target** role is left
|
|
973
|
-
* intact: the reverse index is keyed by full `EntityID`, so a recycled slot
|
|
974
|
-
* never aliases the dead target's sources. The destroyed entity's **target**
|
|
975
|
-
* role is handled separately by `_cleanupRelationTargets` per each
|
|
976
|
-
* relation's `OnDeleteTarget` policy (#473). Gated by the caller on
|
|
977
|
-
* `relations.length > 0`. */
|
|
978
|
-
private _purgeRelations;
|
|
979
|
-
/** Apply each relation's `OnDeleteTarget` policy for a destroyed **target**
|
|
980
|
-
* `targetId` (#473). Walks the registry; for every relation whose reverse
|
|
981
|
-
* index has sources pointing at the dead target:
|
|
982
|
-
*
|
|
983
|
-
* - **`delete`** — append each source to `cascade`; the caller destroys them
|
|
984
|
-
* through the same path, so chains/trees cascade recursively. The sources'
|
|
985
|
-
* own source-role purge (`_purgeRelations`) drops their forward link and
|
|
986
|
-
* unlinks them from `targetId`'s reverse set, so no reverse entry leaks.
|
|
987
|
-
* - **`clear`** — drop each source's link to the dead target in place via
|
|
988
|
-
* `rs.unlink(src, targetId)` (exclusive drops the row; multi removes the
|
|
989
|
-
* target from the set, dropping membership when it empties). Sources
|
|
990
|
-
* survive — the cardinality bookkeeping is the relation's, not branched here.
|
|
991
|
-
* - **`orphan`** — skipped (the link is left dangling; safe because the
|
|
992
|
-
* reverse key carries the generation).
|
|
993
|
-
*
|
|
994
|
-
* `sourcesOf` returns a fresh snapshot, so mutating the reverse index while
|
|
995
|
-
* iterating is safe. Gated by the caller on `_hasTargetCleanup`, so the
|
|
996
|
-
* whole walk is skipped when no relation opts into a non-`orphan` policy. */
|
|
997
|
-
private _cleanupRelationTargets;
|
|
998
836
|
/** Second query-match path (#469 / ADR-0011): iterate entities matching a
|
|
999
837
|
* dense mask **and** sparse-membership terms, invoking `cb` per entity.
|
|
1000
838
|
* Yields `EntityID`s, not archetype spans — sparse members are scattered
|
|
@@ -1013,44 +851,9 @@ export declare class Store {
|
|
|
1013
851
|
* Only reached via `Query.forEachEntity`; dense `forEach` never consults
|
|
1014
852
|
* the sparse stores, so dense-only queries are unaffected (#469 AC). */
|
|
1015
853
|
_forEachSparseMatch(include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], denseArchetypes: readonly Archetype[], cb: (entityId: EntityID) => void, includeDisabled: boolean): void;
|
|
1016
|
-
/** Fourth query-match path (#581):
|
|
1017
|
-
*
|
|
1018
|
-
* the default enabled-row filter) — in canonical **hierarchy depth order** over
|
|
1019
|
-
* exclusive relation `R`: depth ascending (parents before children), **entity
|
|
1020
|
-
* index ascending within each depth band**. Entities deeper than `maxDepth`
|
|
1021
|
-
* are skipped (`Infinity` = unbounded). Only reached via `Query.forEachEntity`
|
|
1022
|
-
* on a query carrying a `.hierarchy(R)` term.
|
|
1023
|
-
*
|
|
1024
|
-
* `.hierarchy(R)` does not narrow the matched set — it reorders it — so an
|
|
1025
|
-
* entity with no `R`-parent is a root (depth 0) and is yielded first. Depth is a
|
|
1026
|
-
* structural property of the *full* tree (an ancestor outside the matched set
|
|
1027
|
-
* still counts toward depth), computed by a memoised upward walk shared across
|
|
1028
|
-
* the whole batch, so a shared/deep chain costs O(nodes), not O(nodes²).
|
|
1029
|
-
*
|
|
1030
|
-
* The canonical order is produced without a comparator sort (which the observer
|
|
1031
|
-
* bench measured at 2–4× — `observer.ts`): (1) collect the matched ids via
|
|
1032
|
-
* `_forEachSparseMatch`; (2) `radixSortByIndex` → entity-index ascending;
|
|
1033
|
-
* (3) stable-bucket by depth — since the input is index-ascending and the bucket
|
|
1034
|
-
* append is stable, each depth band stays index-ascending. Tuned for the
|
|
1035
|
-
* motivating per-tick case (transform propagation): the radix scratch is reused
|
|
1036
|
-
* instance state (`_hierarchy_radix_*`), so a per-tick pass churns no histograms;
|
|
1037
|
-
* the working set (`matched` / `buckets` / `depthMemo` / `visiting`) is still
|
|
1038
|
-
* allocated per call, as it must stay call-local for re-entrancy.
|
|
1039
|
-
*
|
|
1040
|
-
* Exclusive-only — a multi relation throws `RELATION_MODE_MISMATCH` in `__DEV__`
|
|
1041
|
-
* (mirrors `cascadeOf` / `ancestorsOf`); a cycle is a loud `RELATION_CYCLE` in
|
|
1042
|
-
* `__DEV__` and a safe break in production. */
|
|
854
|
+
/** Fourth query-match path (#581): the matched set in hierarchy depth order
|
|
855
|
+
* (parents before children) — see `RelationService.forEachHierarchyMatch`. */
|
|
1043
856
|
_forEachHierarchyMatch(include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], denseArchetypes: readonly Archetype[], relation: RelationDef, maxDepth: number, includeDisabled: boolean, cb: (entityId: EntityID) => void): void;
|
|
1044
|
-
/** Depth of entity index `idx` in the exclusive-relation tree backing `store`
|
|
1045
|
-
* (root = 0), for `_forEachHierarchyMatch`. Memoised across the batch (`memo`),
|
|
1046
|
-
* so a shared ancestor chain is walked once. Walks upward via the backing store's
|
|
1047
|
-
* target field 0 (mirroring `ancestorsOf`), stopping at: a root (no target), an
|
|
1048
|
-
* already-memoised node, or a dangling/dead parent (the child is then treated as
|
|
1049
|
-
* a root — never advance through a recycled slot, the ABA `ancestorsOf` guards).
|
|
1050
|
-
* `visiting` flags the nodes on the current upward path to catch a cycle —
|
|
1051
|
-
* `RELATION_CYCLE` in `__DEV__`, treated as a root in production — and is emptied
|
|
1052
|
-
* on the way back down so it can be reused for the next entity. */
|
|
1053
|
-
private _hierarchyDepthOf;
|
|
1054
857
|
addComponent(entityId: EntityID, def: ComponentDef<Record<string, never>>): void;
|
|
1055
858
|
addComponent<S extends ComponentSchema>(entityId: EntityID, def: ComponentDef<S>, values: FieldValues<S>): void;
|
|
1056
859
|
/** Add multiple components in one transition (resolves final archetype, then moves once).
|
|
@@ -1066,7 +869,7 @@ export declare class Store {
|
|
|
1066
869
|
* archetypes the entity never visits.
|
|
1067
870
|
*
|
|
1068
871
|
* #659 — composite-add edge cache. The final-mask resolve, unlike the
|
|
1069
|
-
* single-add `edges[]` walk, re-pays a per-call `mask.hash()`, `
|
|
872
|
+
* single-add `edges[]` walk, re-pays a per-call `mask.hash()`, `ArchetypeGraph.lookup`
|
|
1070
873
|
* (the Map-of-buckets + `equals` scan), and `getBatchTransitionMap` on
|
|
1071
874
|
* every call — a ~2× gap vs a cached edge walk that the decomposition probe
|
|
1072
875
|
* pinned on the two `Map.get`s, not the hash. So a repeated (source, added-
|
|
@@ -1075,10 +878,7 @@ export declare class Store {
|
|
|
1075
878
|
* skip the union-mask build entirely. First call per key still resolves via
|
|
1076
879
|
* the final-mask path below (no intermediate planting) and plants the edge.
|
|
1077
880
|
* See docs/reports/bench/regressions/add-components-composite-edge.md. */
|
|
1078
|
-
addComponents(entityId: EntityID, entries:
|
|
1079
|
-
def: ComponentDef;
|
|
1080
|
-
values?: Record<string, number>;
|
|
1081
|
-
}[]): void;
|
|
881
|
+
addComponents<Defs extends readonly ComponentDef[]>(entityId: EntityID, entries: TemplateEntries<Defs>): void;
|
|
1082
882
|
/** Shared move+write tail of `addComponents` (#659): place the entity into
|
|
1083
883
|
* the already-resolved `targetArch` — a `moveEntityFrom` along the cached
|
|
1084
884
|
* `map` when it has a row, else a fresh append (the rowless empty-archetype
|
|
@@ -1095,7 +895,10 @@ export declare class Store {
|
|
|
1095
895
|
* removal path. Computing the difference mask up front and resolving
|
|
1096
896
|
* once avoids planting N-1 intermediates the entity never lives in. */
|
|
1097
897
|
removeComponents(entityId: EntityID, defs: ComponentDef[]): void;
|
|
1098
|
-
|
|
898
|
+
/** Total (POLISH_AUDIT #9): a dead/stale `entityId` returns `false` rather
|
|
899
|
+
* than throwing — a "has" probe is exactly what callers reach for to avoid
|
|
900
|
+
* touching dead entities, so it must be safe to ask. */
|
|
901
|
+
hasComponent(entityId: EntityID, def: ComponentHandle): boolean;
|
|
1099
902
|
/**
|
|
1100
903
|
* Bulk add a component to ALL entities in the given archetype.
|
|
1101
904
|
* Uses TypedArray.set() for O(columns) instead of O(N×columns).
|
|
@@ -1123,25 +926,23 @@ export declare class Store {
|
|
|
1123
926
|
registerQuery(include: BitSet, exclude?: BitSet, anyOf?: BitSet): Archetype[];
|
|
1124
927
|
updateQueryRef(result: Archetype[], query: Query<any>): void;
|
|
1125
928
|
get archetypeCount(): number;
|
|
1126
|
-
registerEvent<S extends
|
|
1127
|
-
emitEvent(def: EventDef
|
|
929
|
+
registerEvent<S extends EventShape<S>>(fields: readonly (keyof S & string)[]): EventDef<S>;
|
|
930
|
+
emitEvent(def: EventDef<any>, values: Record<string, number>): void;
|
|
1128
931
|
emitSignal(def: EventDef<EmptyEventSchema>): void;
|
|
1129
|
-
getEventReader<S extends
|
|
932
|
+
getEventReader<S extends EventShape<S>>(def: EventDef<S>): EventReader<S>;
|
|
1130
933
|
clearEvents(): void;
|
|
1131
|
-
/** `
|
|
1132
|
-
* `
|
|
1133
|
-
* observer emitted nothing — its emissions would be wiped by the tick-tail
|
|
1134
|
-
* `clearEvents` and break the empty-channel-at-boundary invariant snapshot /
|
|
1135
|
-
* restore relies on (#586). Walks only the dirty list, never the hot emit path. */
|
|
934
|
+
/** `DEV`-only mid-update emit detection — see
|
|
935
|
+
* `EventRegistry.devBufferedEventCount`. */
|
|
1136
936
|
_devBufferedEventCount(): number;
|
|
1137
|
-
|
|
1138
|
-
registerEventByKey<S extends EventSchema>(key: symbol, fields: readonly (keyof S & string)[]): EventDef<S>;
|
|
937
|
+
registerEventByKey<S extends EventShape<S>>(key: symbol, fields: readonly (keyof S & string)[]): EventDef<S>;
|
|
1139
938
|
getEventDefByKey(key: symbol): EventDef<any>;
|
|
1140
939
|
hasEventKey(key: symbol): boolean;
|
|
1141
|
-
private readonly
|
|
940
|
+
private readonly resources;
|
|
1142
941
|
registerResource(key: symbol, value: unknown): void;
|
|
1143
942
|
getResource(key: symbol): unknown;
|
|
1144
943
|
setResource(key: symbol, value: unknown): void;
|
|
944
|
+
/** Fails closed on a missing key; the present → absent → present
|
|
945
|
+
* lifecycle (#798) — see `ResourceRegistry.remove`. */
|
|
1145
946
|
removeResource(key: symbol): void;
|
|
1146
947
|
hasResource(key: symbol): boolean;
|
|
1147
948
|
}
|