@oasys/oecs 0.3.1 → 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 +207 -267
- package/dist/core/ecs/access_check.d.cts +77 -0
- package/dist/core/ecs/access_check.d.ts +77 -0
- package/dist/core/ecs/access_check.d.ts.map +1 -0
- package/dist/core/ecs/archetype.d.cts +486 -0
- package/dist/core/ecs/archetype.d.ts +486 -0
- package/dist/core/ecs/archetype.d.ts.map +1 -0
- 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 +43 -0
- package/dist/core/ecs/builtin_relations.d.ts.map +1 -0
- package/dist/core/ecs/command_log.d.cts +116 -0
- package/dist/core/ecs/command_log.d.ts +116 -0
- package/dist/core/ecs/command_log.d.ts.map +1 -0
- package/dist/core/ecs/component.d.cts +176 -0
- package/dist/core/ecs/component.d.ts +176 -0
- package/dist/core/ecs/component.d.ts.map +1 -0
- package/dist/core/ecs/compute_backend.d.cts +37 -0
- package/dist/core/ecs/compute_backend.d.ts +37 -0
- package/dist/core/ecs/compute_backend.d.ts.map +1 -0
- 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 +93 -0
- package/dist/core/ecs/dispatch_trace.d.ts.map +1 -0
- package/dist/core/ecs/ecs.d.cts +562 -0
- package/dist/core/ecs/ecs.d.ts +562 -0
- package/dist/core/ecs/ecs.d.ts.map +1 -0
- package/dist/core/ecs/ecs_memory.d.cts +179 -0
- package/dist/core/ecs/ecs_memory.d.ts +179 -0
- package/dist/core/ecs/ecs_memory.d.ts.map +1 -0
- package/dist/core/ecs/entity.d.cts +34 -0
- package/dist/core/ecs/entity.d.ts +34 -0
- package/dist/core/ecs/entity.d.ts.map +1 -0
- 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 +79 -0
- package/dist/core/ecs/event.d.ts.map +1 -0
- 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 +133 -0
- package/dist/core/ecs/frame_trace.d.ts.map +1 -0
- package/dist/core/ecs/host_commands.d.cts +274 -0
- package/dist/core/ecs/host_commands.d.ts +274 -0
- package/dist/core/ecs/host_commands.d.ts.map +1 -0
- package/dist/core/ecs/index.d.cts +46 -0
- package/dist/core/ecs/index.d.ts +46 -0
- package/dist/core/ecs/index.d.ts.map +1 -0
- package/dist/core/ecs/observer.d.cts +173 -0
- package/dist/core/ecs/observer.d.ts +173 -0
- package/dist/core/ecs/observer.d.ts.map +1 -0
- package/dist/core/ecs/query.d.cts +718 -0
- package/dist/core/ecs/query.d.ts +718 -0
- package/dist/core/ecs/query.d.ts.map +1 -0
- package/dist/core/ecs/ref.d.cts +31 -0
- package/dist/core/ecs/ref.d.ts +31 -0
- package/dist/core/ecs/ref.d.ts.map +1 -0
- package/dist/core/ecs/relation.d.cts +243 -0
- package/dist/core/ecs/relation.d.ts +243 -0
- package/dist/core/ecs/relation.d.ts.map +1 -0
- 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 +53 -0
- package/dist/core/ecs/resource.d.ts.map +1 -0
- 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 +85 -0
- package/dist/core/ecs/resume.d.ts.map +1 -0
- package/dist/core/ecs/run_condition.d.cts +81 -0
- package/dist/core/ecs/run_condition.d.ts +81 -0
- package/dist/core/ecs/run_condition.d.ts.map +1 -0
- package/dist/core/ecs/schedule.d.cts +142 -0
- package/dist/core/ecs/schedule.d.ts +142 -0
- package/dist/core/ecs/schedule.d.ts.map +1 -0
- 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 +110 -0
- package/dist/core/ecs/sparse_store.d.ts.map +1 -0
- package/dist/core/ecs/store.d.cts +950 -0
- package/dist/core/ecs/store.d.ts +950 -0
- package/dist/core/ecs/store.d.ts.map +1 -0
- package/dist/core/ecs/store_layout_listener.d.cts +23 -0
- package/dist/core/ecs/store_layout_listener.d.ts +23 -0
- package/dist/core/ecs/store_layout_listener.d.ts.map +1 -0
- package/dist/core/ecs/system.d.cts +250 -0
- package/dist/core/ecs/system.d.ts +250 -0
- package/dist/core/ecs/system.d.ts.map +1 -0
- package/dist/core/ecs/utils/arrays.d.cts +7 -0
- package/dist/{utils → core/ecs/utils}/arrays.d.ts +2 -1
- package/dist/core/ecs/utils/arrays.d.ts.map +1 -0
- package/dist/core/ecs/utils/constants.d.ts +12 -0
- package/dist/core/ecs/utils/constants.d.ts.map +1 -0
- package/dist/core/ecs/utils/error.d.cts +61 -0
- package/dist/core/ecs/utils/error.d.ts +61 -0
- package/dist/core/ecs/utils/error.d.ts.map +1 -0
- package/dist/core/store/action_ring.d.cts +136 -0
- package/dist/core/store/action_ring.d.ts +136 -0
- package/dist/core/store/action_ring.d.ts.map +1 -0
- package/dist/core/store/allocator.d.cts +238 -0
- package/dist/core/store/allocator.d.ts +238 -0
- package/dist/core/store/allocator.d.ts.map +1 -0
- package/dist/core/store/buffer_backed_column.d.cts +69 -0
- package/dist/core/store/buffer_backed_column.d.ts +69 -0
- package/dist/core/store/buffer_backed_column.d.ts.map +1 -0
- package/dist/core/store/column_store.d.cts +273 -0
- package/dist/core/store/column_store.d.ts +273 -0
- package/dist/core/store/column_store.d.ts.map +1 -0
- package/dist/core/store/command_dispatch.d.cts +52 -0
- package/dist/core/store/command_dispatch.d.ts +52 -0
- package/dist/core/store/command_dispatch.d.ts.map +1 -0
- package/dist/core/store/command_ring.d.cts +107 -0
- package/dist/core/store/command_ring.d.ts +107 -0
- package/dist/core/store/command_ring.d.ts.map +1 -0
- package/dist/core/store/descriptor.d.cts +80 -0
- package/dist/core/store/descriptor.d.ts +80 -0
- package/dist/core/store/descriptor.d.ts.map +1 -0
- package/dist/core/store/entity_index.d.cts +108 -0
- package/dist/core/store/entity_index.d.ts +108 -0
- package/dist/core/store/entity_index.d.ts.map +1 -0
- package/dist/core/store/event_ring.d.cts +95 -0
- package/dist/core/store/event_ring.d.ts +95 -0
- package/dist/core/store/event_ring.d.ts.map +1 -0
- package/dist/core/store/extend.d.cts +39 -0
- package/dist/core/store/extend.d.ts +39 -0
- package/dist/core/store/extend.d.ts.map +1 -0
- package/dist/core/store/grow.d.cts +34 -0
- package/dist/core/store/grow.d.ts +34 -0
- package/dist/core/store/grow.d.ts.map +1 -0
- package/dist/core/store/header.d.cts +64 -0
- package/dist/core/store/header.d.ts +64 -0
- package/dist/core/store/header.d.ts.map +1 -0
- package/dist/core/store/index.d.cts +17 -0
- package/dist/core/store/index.d.ts +17 -0
- package/dist/core/store/index.d.ts.map +1 -0
- 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 +74 -0
- package/dist/core/store/region_table.d.ts.map +1 -0
- package/dist/core/store/snapshot.d.cts +43 -0
- package/dist/core/store/snapshot.d.ts +43 -0
- package/dist/core/store/snapshot.d.ts.map +1 -0
- package/dist/core/store/state_hash.d.cts +38 -0
- package/dist/core/store/state_hash.d.ts +38 -0
- package/dist/core/store/state_hash.d.ts.map +1 -0
- package/dist/core/store/store_regions.d.cts +38 -0
- package/dist/core/store/store_regions.d.ts +38 -0
- package/dist/core/store/store_regions.d.ts.map +1 -0
- package/dist/core/store/vendored_abi/abi.d.cts +43 -0
- package/dist/core/store/vendored_abi/abi.d.ts +43 -0
- package/dist/core/store/vendored_abi/abi.d.ts.map +1 -0
- 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 +170 -0
- package/dist/extensions/editor/editor.d.ts.map +1 -0
- package/dist/extensions/editor/field_handle.d.cts +40 -0
- package/dist/extensions/editor/field_handle.d.ts +40 -0
- package/dist/extensions/editor/field_handle.d.ts.map +1 -0
- package/dist/extensions/editor/index.cjs +1 -0
- package/dist/extensions/editor/index.d.cts +21 -0
- package/dist/extensions/editor/index.d.ts +21 -0
- package/dist/extensions/editor/index.d.ts.map +1 -0
- package/dist/extensions/editor/index.js +237 -0
- package/dist/extensions/reactive/ecs_sync.d.cts +214 -0
- package/dist/extensions/reactive/ecs_sync.d.ts +214 -0
- package/dist/extensions/reactive/ecs_sync.d.ts.map +1 -0
- package/dist/extensions/reactive/index.cjs +1 -0
- package/dist/extensions/reactive/index.d.cts +23 -0
- package/dist/extensions/reactive/index.d.ts +23 -0
- package/dist/extensions/reactive/index.d.ts.map +1 -0
- package/dist/extensions/reactive/index.js +215 -0
- package/dist/extensions/solid/index.cjs +1 -0
- package/dist/extensions/solid/index.d.cts +6 -0
- package/dist/extensions/solid/index.d.ts +6 -0
- package/dist/extensions/solid/index.d.ts.map +1 -0
- package/dist/extensions/solid/index.js +36 -0
- package/dist/extensions/solid/kernel_solid.d.cts +45 -0
- package/dist/extensions/solid/kernel_solid.d.ts +45 -0
- package/dist/extensions/solid/kernel_solid.d.ts.map +1 -0
- package/dist/host_commands-BF8QMi3c.cjs +1 -0
- package/dist/host_commands-i4cAeyL5.js +2318 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +66 -0
- package/dist/index.d.ts +65 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7080 -1289
- 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/interop-CT-REx0W.cjs +1 -0
- package/dist/interop-CcY6ASQc.js +18 -0
- package/dist/kernel-DgyrLFjW.js +227 -0
- package/dist/kernel-yWV3XnAb.cjs +1 -0
- package/dist/primitives.cjs +1 -0
- package/dist/primitives.d.cts +18 -0
- package/dist/primitives.d.ts +18 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +45 -0
- package/dist/reactive/array.d.cts +24 -0
- 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/reactive/interop.d.ts +19 -0
- package/dist/reactive/interop.d.ts.map +1 -0
- package/dist/reactive/kernel.d.cts +73 -0
- package/dist/reactive/kernel.d.ts +73 -0
- package/dist/reactive/kernel.d.ts.map +1 -0
- package/dist/reactive/map.d.cts +16 -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/reactive/struct.d.ts +10 -0
- 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 -0
- package/dist/shared.d.cts +22 -0
- package/dist/shared.d.ts +22 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +7 -0
- 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 +25 -9
- 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/binary_heap/binary_heap.d.ts +6 -2
- package/dist/type_primitives/binary_heap/binary_heap.d.ts.map +1 -1
- package/dist/type_primitives/bitset/bitset.d.cts +54 -0
- package/dist/type_primitives/bitset/bitset.d.ts +16 -4
- package/dist/type_primitives/bitset/bitset.d.ts.map +1 -1
- package/dist/type_primitives/brand.d.cts +23 -0
- package/dist/type_primitives/brand.d.ts +6 -1
- package/dist/type_primitives/brand.d.ts.map +1 -1
- package/dist/type_primitives/error.d.cts +16 -0
- package/dist/type_primitives/error.d.ts +8 -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 +12 -9
- package/dist/type_primitives/index.d.ts.map +1 -1
- package/dist/type_primitives/sparse_map/sparse_map.d.cts +30 -0
- package/dist/type_primitives/sparse_map/sparse_map.d.ts +7 -3
- package/dist/type_primitives/sparse_map/sparse_map.d.ts.map +1 -1
- package/dist/type_primitives/sparse_set/sparse_set.d.cts +28 -0
- package/dist/type_primitives/sparse_set/sparse_set.d.ts +4 -0
- package/dist/type_primitives/sparse_set/sparse_set.d.ts.map +1 -1
- package/dist/type_primitives/topological_sort/topological_sort.d.cts +29 -0
- package/dist/type_primitives/topological_sort/topological_sort.d.ts +7 -3
- package/dist/type_primitives/topological_sort/topological_sort.d.ts.map +1 -1
- package/dist/type_primitives/typed_arrays/typed_arrays.d.cts +127 -0
- package/dist/type_primitives/typed_arrays/typed_arrays.d.ts +53 -16
- package/dist/type_primitives/typed_arrays/typed_arrays.d.ts.map +1 -1
- 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/utils/error.d.ts +2 -20
- package/dist/utils/error.d.ts.map +1 -1
- 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 +115 -5
- package/dist/archetype.d.ts +0 -108
- package/dist/archetype.d.ts.map +0 -1
- package/dist/component.d.ts +0 -45
- package/dist/component.d.ts.map +0 -1
- package/dist/ecs.d.ts +0 -104
- package/dist/ecs.d.ts.map +0 -1
- package/dist/entity.d.ts +0 -11
- package/dist/entity.d.ts.map +0 -1
- package/dist/event.d.ts +0 -30
- package/dist/event.d.ts.map +0 -1
- package/dist/query.d.ts +0 -94
- package/dist/query.d.ts.map +0 -1
- package/dist/ref.d.ts +0 -23
- package/dist/ref.d.ts.map +0 -1
- package/dist/resource.d.ts +0 -23
- package/dist/resource.d.ts.map +0 -1
- package/dist/schedule.d.ts +0 -45
- package/dist/schedule.d.ts.map +0 -1
- package/dist/store.d.ts +0 -118
- package/dist/store.d.ts.map +0 -1
- package/dist/system.d.ts +0 -16
- package/dist/system.d.ts.map +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
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
import { Store } from './store.cjs';
|
|
2
|
+
import { FrameTraceSink } from './frame_trace.cjs';
|
|
3
|
+
import { Archetype, ArchetypeView } from './archetype.cjs';
|
|
4
|
+
import { EntityID } from './entity.cjs';
|
|
5
|
+
import { ComponentDef, ComponentHandle, ComponentID, MutableColumnsForSchema, ColumnsForSchema, AttachValuesArg, SchemaOf, DeclaredQueryTerm } from './component.cjs';
|
|
6
|
+
import { SparseComponentDef, SparseComponentID, SparseSchemaOf } from './sparse_store.cjs';
|
|
7
|
+
import { RelationDef } from './relation.cjs';
|
|
8
|
+
import { SystemAccess, DeclaredRead, DeclaredWrite, DeclaredAdd, DeclaredRemove, DeclaredSparseRead, DeclaredSparseWrite, DeclaredRelationRead, DeclaredRelationWrite, DeclaredResourceRead, DeclaredResourceWrite, DespawnArg } from './system.cjs';
|
|
9
|
+
import { ComponentRef, ReadonlyComponentRef } from './ref.cjs';
|
|
10
|
+
import { EventKey, EventReader, EventShape, SignalKey } from './event.cjs';
|
|
11
|
+
import { ResourceKey, ResourceValueOf } from './resource.cjs';
|
|
12
|
+
import { BitSet } from '../../type_primitives/index.cjs';
|
|
13
|
+
/** The query-driver seam on `Store` — the typed contract behind the
|
|
14
|
+
* underscore members `ecs.ts` and the query internals reach (M1). `Store`
|
|
15
|
+
* implements this; when the cache/driver layer is extracted (M2/H1) the
|
|
16
|
+
* interface retargets at the collaborator without touching consumers.
|
|
17
|
+
* `_tick` / `_trace` are deliberately mutable: `ECS.update()` advances the
|
|
18
|
+
* change tick and `ECS.setTrace` installs the sink through this seam. */
|
|
19
|
+
export interface QueryHost {
|
|
20
|
+
/** Change tick — advanced by `ECS.update()` each frame. */
|
|
21
|
+
_tick: number;
|
|
22
|
+
/** Dev-only frame-trace sink (`ECS.setTrace`); always null in prod. */
|
|
23
|
+
_trace: FrameTraceSink | null;
|
|
24
|
+
/** True once any component observer opted into per-entity dirty tracking —
|
|
25
|
+
* gates `_noteSet` at every write site. */
|
|
26
|
+
readonly _anyDirtyTracked: boolean;
|
|
27
|
+
/** Bumped when an archetype crosses empty↔non-empty — cached query
|
|
28
|
+
* archetype lists rebuild when their observed epoch is stale (#327). */
|
|
29
|
+
readonly _queryDirtyEpoch: number;
|
|
30
|
+
/** Record a per-entity onSet dirty mark for `def` (gated by
|
|
31
|
+
* `_anyDirtyTracked` at the call site). */
|
|
32
|
+
_noteSet(def: ComponentHandle, eid: EntityID): void;
|
|
33
|
+
/** Dev-only: buffered event count across dirty channels (mid-update emit
|
|
34
|
+
* detection in `ECS.update()`). */
|
|
35
|
+
_devBufferedEventCount(): number;
|
|
36
|
+
/** Second query-match path: sparse-term intersection (#469 / ADR-0011). */
|
|
37
|
+
_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;
|
|
38
|
+
/** Third query-match path: the `(*, T)` wildcard (#579). */
|
|
39
|
+
_forEachRelationTargetMatch(target: EntityID, include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], includeDisabled: boolean, cb: (entityId: EntityID) => void): void;
|
|
40
|
+
/** Fourth query-match path: hierarchy depth ordering (#581). */
|
|
41
|
+
_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;
|
|
42
|
+
}
|
|
43
|
+
export interface QueryCacheEntry {
|
|
44
|
+
includeMask: BitSet;
|
|
45
|
+
excludeMask: BitSet | null;
|
|
46
|
+
anyOfMask: BitSet | null;
|
|
47
|
+
query: Query<any>;
|
|
48
|
+
}
|
|
49
|
+
/** One owner for every query-resolution cache (M2). Previously the dedup
|
|
50
|
+
* bucket map lived on `ECS` while `Query` populated eleven composition maps
|
|
51
|
+
* declared on the resolver interface — ownership split across two modules.
|
|
52
|
+
* All entries are structural (a query is minted once per unique term set and
|
|
53
|
+
* lives for the world's lifetime; components and queries are never
|
|
54
|
+
* unregistered), so there is no invalidation lifecycle — the maps are
|
|
55
|
+
* append-only. Key encodings are unchanged from the pre-extraction fields.
|
|
56
|
+
*
|
|
57
|
+
* The composition maps are exposed as readonly fields (not per-kind accessor
|
|
58
|
+
* pairs): the mutation protocol is uniform (`get` → miss → build → `set`) and
|
|
59
|
+
* hot enough that composition sites keep direct map access; the invariant
|
|
60
|
+
* this class carries is single ownership, not access mediation. */
|
|
61
|
+
export declare class QueryCache {
|
|
62
|
+
private readonly dedup;
|
|
63
|
+
readonly andSingle: Map<number, Query<any>>;
|
|
64
|
+
readonly notSingle: Map<number, Query<any>>;
|
|
65
|
+
readonly anyOfSingle: Map<number, Query<any>>;
|
|
66
|
+
readonly changedSingle: Map<number, ChangedQuery<any>>;
|
|
67
|
+
readonly optionalSingle: Map<number, Query<any>>;
|
|
68
|
+
readonly withSparseSingle: Map<number, Query<any>>;
|
|
69
|
+
readonly withoutSparseSingle: Map<number, Query<any>>;
|
|
70
|
+
readonly withRelationSingle: Map<number, Query<any>>;
|
|
71
|
+
readonly withoutRelationSingle: Map<number, Query<any>>;
|
|
72
|
+
readonly includeDisabledSingle: Map<number, Query<any>>;
|
|
73
|
+
readonly hierarchySingle: Map<number, Query<any>>;
|
|
74
|
+
/** Dedup lookup: bucket scan with full mask equality (buckets are
|
|
75
|
+
* typically 1–2 entries). */
|
|
76
|
+
findDedup(key: number, include: BitSet, exclude: BitSet | null, anyOf: BitSet | null): QueryCacheEntry | undefined;
|
|
77
|
+
/** Record a freshly minted query under its dedup key. */
|
|
78
|
+
addDedup(key: number, entry: QueryCacheEntry): void;
|
|
79
|
+
}
|
|
80
|
+
export interface QueryResolver {
|
|
81
|
+
_resolveQuery(include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, defs: readonly ComponentDef[]): Query<any>;
|
|
82
|
+
_getLastRunTick(): number;
|
|
83
|
+
/** Current ECS write tick — the tick `eachChunk` stamps via `cols.mut` (§eachChunk). */
|
|
84
|
+
_getCurrentTick(): number;
|
|
85
|
+
_getQueryDirtyEpoch(): number;
|
|
86
|
+
_nextQueryId(): number;
|
|
87
|
+
/** All query-resolution caches — dedup + composition (M2). One owner; see
|
|
88
|
+
* `QueryCache` for the per-map keying/id-space notes. */
|
|
89
|
+
readonly _caches: QueryCache;
|
|
90
|
+
/** Second query-match path (#469 / ADR-0011): drive iteration by sparse
|
|
91
|
+
* membership rather than the archetype mask, yielding entities — sparse
|
|
92
|
+
* members are scattered across archetypes, so there is no archetype-column
|
|
93
|
+
* span to hand back. With a sparse require term, drive from the smallest
|
|
94
|
+
* required store and filter; with only sparse excludes, drive the dense
|
|
95
|
+
* archetype list and skip excluded rows; with neither, walk dense entities.
|
|
96
|
+
* Only entered via `Query.forEachEntity`, so dense `forEach` never pays.
|
|
97
|
+
* `includeDisabled` widens the per-archetype row scan from enabled rows to
|
|
98
|
+
* all rows (#577). */
|
|
99
|
+
_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;
|
|
100
|
+
/** Backing sparse id of a relation — resolves a `(R, *)` wildcard term
|
|
101
|
+
* (`withRelation`, #579) to the membership store the sparse-match path
|
|
102
|
+
* already drives. */
|
|
103
|
+
_relationBackingSparseId(def: RelationDef): SparseComponentID;
|
|
104
|
+
/** Third query-match path (#579): `(*, T)` — drive iteration from the union of
|
|
105
|
+
* every relation's `sourcesOf(target)` (dedup + canonical sort), intersected
|
|
106
|
+
* with the dense mask + sparse terms + the enabled-row filter. Only entered via
|
|
107
|
+
* `Query.forEachRelatedTo`. */
|
|
108
|
+
_forEachRelationTargetMatch(target: EntityID, include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], includeDisabled: boolean, cb: (entityId: EntityID) => void): void;
|
|
109
|
+
/** Fourth query-match path (#581): yield the matched entities (dense mask +
|
|
110
|
+
* sparse terms + enabled-row filter, exactly the `_forEachSparseMatch`
|
|
111
|
+
* intersection) in canonical **hierarchy depth order** over exclusive relation
|
|
112
|
+
* `relation` — depth ascending (parents before children), entity index
|
|
113
|
+
* ascending within a depth band. Entities deeper than `maxDepth` are skipped
|
|
114
|
+
* (`HIERARCHY_UNBOUNDED` = no limit). Only entered via `Query.forEachEntity`
|
|
115
|
+
* on a query carrying a `.hierarchy(R)` term. */
|
|
116
|
+
_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;
|
|
117
|
+
}
|
|
118
|
+
/** No depth limit on a `.hierarchy(R)` term (#581) — yield every matched entity
|
|
119
|
+
* regardless of its depth in the tree. The default `maxDepth`. */
|
|
120
|
+
export declare const HIERARCHY_UNBOUNDED: number;
|
|
121
|
+
/** A `.hierarchy(R)` depth-ordering term (#581). Records the exclusive relation
|
|
122
|
+
* whose tree defines the order and the (optional) max depth to yield. Stored on
|
|
123
|
+
* the Query and consumed by the `forEachEntity` hierarchy match path; absent
|
|
124
|
+
* (`null`) for the common case. */
|
|
125
|
+
export interface HierarchyTerm {
|
|
126
|
+
/** The exclusive relation whose chain/tree defines the depth ordering. */
|
|
127
|
+
readonly relation: RelationDef;
|
|
128
|
+
/** Inclusive max depth to yield (root = 0); entities deeper than this are
|
|
129
|
+
* skipped. `HIERARCHY_UNBOUNDED` for no limit (bitECS `Hierarchy()` depth arg). */
|
|
130
|
+
readonly maxDepth: number;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* eachChunk cursor (§eachChunk). One instance is allocated per `eachChunk`
|
|
134
|
+
* pass and reused across every matched archetype in that pass — only `_arch`/
|
|
135
|
+
* `_tick` are re-pointed per archetype, so the inner loop allocates nothing.
|
|
136
|
+
* Per-call (not cached on the query) so a nested `eachChunk` on the same query
|
|
137
|
+
* gets its own cursor and can't re-point an outer pass's position. `.mut(def)` /
|
|
138
|
+
* `.read(def)` resolve a whole component's columns at once into a field-keyed
|
|
139
|
+
* object (a per-archetype-per-component cache refreshed in place), hiding the
|
|
140
|
+
* change tick. Destructure the group immediately; don't retain it across calls.
|
|
141
|
+
*/
|
|
142
|
+
export declare class ChunkColumns<out Defs extends readonly ComponentDef<any>[] = readonly ComponentDef<any>[]> {
|
|
143
|
+
/** @internal */ _arch: Archetype;
|
|
144
|
+
/** @internal */ _tick: number;
|
|
145
|
+
/** Mutable column group — `const { x, y } = cols.mut(Pos)`. Stamps the tick.
|
|
146
|
+
* `def` must be a term of the iterating query (POLISH_AUDIT #6). */
|
|
147
|
+
mut<D extends ComponentDef<any>>(def: D & DeclaredQueryTerm<Defs, D>): MutableColumnsForSchema<SchemaOf<D>>;
|
|
148
|
+
/** Read-only column group — `const { vx, vy } = cols.read(Vel)`. No tick bump.
|
|
149
|
+
* `def` must be a term of the iterating query (POLISH_AUDIT #6). */
|
|
150
|
+
read<D extends ComponentDef<any>>(def: D & DeclaredQueryTerm<Defs, D>): ColumnsForSchema<SchemaOf<D>>;
|
|
151
|
+
}
|
|
152
|
+
export declare class Query<Defs extends readonly ComponentDef[]> {
|
|
153
|
+
private readonly _archetypes;
|
|
154
|
+
readonly _defs: Defs;
|
|
155
|
+
private readonly _resolver;
|
|
156
|
+
readonly _include: BitSet;
|
|
157
|
+
private readonly _exclude;
|
|
158
|
+
private readonly _anyOf;
|
|
159
|
+
private _nonEmptyArchetypes;
|
|
160
|
+
private _lastSeenEpoch;
|
|
161
|
+
readonly _id: number;
|
|
162
|
+
readonly _sparseInclude: readonly SparseComponentID[];
|
|
163
|
+
readonly _sparseExclude: readonly SparseComponentID[];
|
|
164
|
+
readonly _optional: readonly ComponentID[];
|
|
165
|
+
readonly _includeDisabled: boolean;
|
|
166
|
+
readonly _relationIncludes: readonly RelationDef[];
|
|
167
|
+
readonly _relationExcludes: readonly RelationDef[];
|
|
168
|
+
readonly _hierarchy: HierarchyTerm | null;
|
|
169
|
+
constructor(archetypes: Archetype[], defs: Defs, resolver: QueryResolver, include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, id: number, sparseInclude?: readonly SparseComponentID[], sparseExclude?: readonly SparseComponentID[], optional?: readonly ComponentID[], includeDisabled?: boolean, relationIncludes?: readonly RelationDef[], relationExcludes?: readonly RelationDef[], hierarchy?: HierarchyTerm | null);
|
|
170
|
+
/** Guard the dense-only methods (`count` / `forEach` / `archetype_count`)
|
|
171
|
+
* against a query carrying sparse terms. These walk the dense archetype
|
|
172
|
+
* list and never consult `_sparseInclude` / `_sparseExclude`, so on a
|
|
173
|
+
* sparse-derived query they'd **fail open** — returning the unfiltered dense
|
|
174
|
+
* result instead of the sparse-filtered one. Throw in `DEV` (compiled
|
|
175
|
+
* out of prod) steering the caller to `forEachEntity`, the only path that
|
|
176
|
+
* honors sparse membership (#469). Mirrors `ChangedQuery`'s dev-guard on its
|
|
177
|
+
* include-mask invariant. */
|
|
178
|
+
private _assertDenseOnly;
|
|
179
|
+
/** Whether this query carries only dense terms — the precondition for the
|
|
180
|
+
* archetype-walk fast paths (`count`, `firstEntity`, `singleEntity`). */
|
|
181
|
+
private _isDenseOnly;
|
|
182
|
+
/** First matching entity, or `undefined` when the query matches none — the
|
|
183
|
+
* singleton read (`player`, `camera`) without hand-rolling a forEach +
|
|
184
|
+
* closure capture (POLISH_AUDIT M8). Dense-only queries answer from the
|
|
185
|
+
* first non-empty archetype in O(archetypes); queries with sparse /
|
|
186
|
+
* relation / hierarchy terms fall back to a full `forEachEntity` walk.
|
|
187
|
+
* "First" is iteration order, not spawn order — with more than one match
|
|
188
|
+
* the pick is arbitrary (use `singleEntity` to assert uniqueness). */
|
|
189
|
+
firstEntity(): EntityID | undefined;
|
|
190
|
+
/** The query's one matching entity. Dev-throws `QUERY_NOT_SINGLETON` when
|
|
191
|
+
* the match count is 0 or >1 — the singleton assertion for entities that
|
|
192
|
+
* must be unique (player, camera). Prod skips the count and returns the
|
|
193
|
+
* first match (`undefined` if none). */
|
|
194
|
+
singleEntity(): EntityID;
|
|
195
|
+
/** Count for non-dense queries — full `forEachEntity` walk. */
|
|
196
|
+
private _countViaWalk;
|
|
197
|
+
/** Number of matching archetypes (including empty ones). */
|
|
198
|
+
get archetypeCount(): number;
|
|
199
|
+
/** Total entity count across all matching archetypes — enabled rows only by
|
|
200
|
+
* default, or all rows when `includeDisabled()` (#577). Reads the partition
|
|
201
|
+
* fields directly (not the archetype's flag-dependent `entityCount`
|
|
202
|
+
* getter). */
|
|
203
|
+
get entityCount(): number;
|
|
204
|
+
get archetypes(): readonly ArchetypeView<Defs>[];
|
|
205
|
+
/** Carry this query's non-dense terms — optional fetch-if-present (#575) and
|
|
206
|
+
* sparse membership (#469) — onto a freshly composed dense query. `and` /
|
|
207
|
+
* `not` / `anyOf` build the new dense mask via `_resolveQuery`, which is
|
|
208
|
+
* keyed on the mask alone and so hands back a query carrying NONE of these
|
|
209
|
+
* terms; before #592 that silently dropped them, making composition
|
|
210
|
+
* order-dependent (`q.optional(V).and(H)` lost `V`; `q.and(H).optional(V)`
|
|
211
|
+
* kept it). When this query carries no non-dense terms (the common case)
|
|
212
|
+
* `base` is already correct and returned as-is, preserving the mask-cached
|
|
213
|
+
* singleton with zero allocation. Otherwise re-derive on top of `base`'s dense
|
|
214
|
+
* state, threading the terms forward so composition is symmetric regardless of
|
|
215
|
+
* order. Reading `base`'s private fields is allowed — same-class instance. */
|
|
216
|
+
private _carryNondense;
|
|
217
|
+
/** Extend required component set. Returns a new (cached) Query. */
|
|
218
|
+
and<D extends ComponentDef[]>(...comps: D): Query<[...Defs, ...D]>;
|
|
219
|
+
/** @internal — cold cache-miss path for single-arg `and`, split out (#649) so
|
|
220
|
+
* the hot `and` body is just key-compute + cache hit. The miss path runs once
|
|
221
|
+
* per unique composition, then every repeat is a cache hit; keeping it out of
|
|
222
|
+
* line shrinks `and`'s inlined footprint when several composes share one hot
|
|
223
|
+
* function (the `query_compose` shape). Same rationale for `_notMiss` /
|
|
224
|
+
* `_anyOfMiss` / `_changedMiss`. */
|
|
225
|
+
private _andMiss;
|
|
226
|
+
/** Exclude archetypes that have any of these components. */
|
|
227
|
+
without(...comps: ComponentDef[]): Query<Defs>;
|
|
228
|
+
/** @internal — cold cache-miss path for single-arg `not` (#649); see `_andMiss`. */
|
|
229
|
+
private _notMiss;
|
|
230
|
+
/** Require a sparse component (#469): match only entities that hold it,
|
|
231
|
+
* across every archetype. A sparse term doesn't touch the dense mask, so
|
|
232
|
+
* the returned (cached) query reuses this one's live archetype list; it is
|
|
233
|
+
* iterated via `forEachEntity`, never `forEach` (sparse members are
|
|
234
|
+
* scattered within archetypes, so there is no SoA column span to yield). */
|
|
235
|
+
withSparse(...defs: SparseComponentDef[]): Query<Defs>;
|
|
236
|
+
/** One-id `withSparse` composition, cached on `(parent_id, sparseId)` in
|
|
237
|
+
* the resolver's shared single-term map. Both the single- and multi-arg public
|
|
238
|
+
* forms fold over this, so all sparse-require composition is deduplicated. */
|
|
239
|
+
private _withSparseOne;
|
|
240
|
+
/** Exclude a sparse component (#469): drop entities that hold it. Same
|
|
241
|
+
* dense-list reuse and `forEachEntity` iteration as `withSparse`. */
|
|
242
|
+
withoutSparse(...defs: SparseComponentDef[]): Query<Defs>;
|
|
243
|
+
/** One-id `withoutSparse` composition, cached on `(parent_id, sparseId)`. The
|
|
244
|
+
* multi-arg form folds over this (#497) — mirrors `_withSparseOne`. */
|
|
245
|
+
private _withoutSparseOne;
|
|
246
|
+
/** Build a derived query carrying new sparse terms. Reuses this query's
|
|
247
|
+
* dense state by reference — the masks are never mutated in place (`and` /
|
|
248
|
+
* `not` / `anyOf` copy before mutating), and `_archetypes` is the same
|
|
249
|
+
* live array the store appends to, so the derived query stays live too.
|
|
250
|
+
* Carries the existing `_optional` terms through unchanged (the two axes
|
|
251
|
+
* compose). */
|
|
252
|
+
private _deriveSparse;
|
|
253
|
+
/** Require the `(R, *)` wildcard (#579): match only sources that hold **any**
|
|
254
|
+
* target under relation `R`. "Has any `(R, *)` pair" is exactly membership in
|
|
255
|
+
* R's backing sparse store (exclusive `{target}` row / multi tag), so this is a
|
|
256
|
+
* relation-typed front door over `withSparse` — it pushes R's backing sparse
|
|
257
|
+
* id onto `_sparseInclude` and reuses the `forEachEntity` sparse-match path
|
|
258
|
+
* (insertion order; canonical sorting is reserved for `stateHash`/snapshot, and
|
|
259
|
+
* costs 4–5× here for no determinism benefit — see the §579 bench report).
|
|
260
|
+
* Membership semantics: each source once; fetch its targets with
|
|
261
|
+
* `ctx.targetsOf(e, R)`. Requires `relationReads: [R]` (checked at iteration).
|
|
262
|
+
* Cached per `(parent_id, relation_id)` like the sparse terms (#497). */
|
|
263
|
+
withRelation(...defs: RelationDef[]): Query<Defs>;
|
|
264
|
+
private _withRelationOne;
|
|
265
|
+
/** Exclude the `(R, *)` wildcard (#579): drop sources that hold any target
|
|
266
|
+
* under `R`. Mirror of `withRelation` on the exclude side (pushes R's
|
|
267
|
+
* backing sparse id onto `_sparseExclude`). */
|
|
268
|
+
withoutRelation(...defs: RelationDef[]): Query<Defs>;
|
|
269
|
+
private _withoutRelationOne;
|
|
270
|
+
/** Build a derived query carrying new relation-wildcard terms. Threads the
|
|
271
|
+
* backing-sparse ids (which the driver actually consumes) plus the relation
|
|
272
|
+
* ids (which only the `DEV` access check consumes), reusing the dense /
|
|
273
|
+
* optional / disabled state by reference — same rationale as `_deriveSparse`. */
|
|
274
|
+
private _deriveRelation;
|
|
275
|
+
/** Order this query's matched entities in **hierarchy depth order** over the
|
|
276
|
+
* exclusive relation `R` — parents before children — and (optionally) drop any
|
|
277
|
+
* deeper than `maxDepth` (#581; flecs `cascade` / bitECS `Hierarchy()`). The
|
|
278
|
+
* matched *set* is unchanged (still the dense mask + sparse + `(R, *)` + disabled
|
|
279
|
+
* terms); `.hierarchy(R)` only **reorders** + depth-limits it, so an entity with
|
|
280
|
+
* no `R`-parent is a root at depth 0 and still yielded (first). The canonical
|
|
281
|
+
* order is depth ascending, then **entity index ascending within each depth
|
|
282
|
+
* band** — a total, insertion-order-independent order (identical across lockstep
|
|
283
|
+
* peers), produced by an O(K) radix on the entity index, never a comparator sort.
|
|
284
|
+
*
|
|
285
|
+
* Iterate with `forEachEntity`: members scatter across archetypes, so there is
|
|
286
|
+
* no SoA column span — `forEach` / `count` reject a hierarchy query (like a
|
|
287
|
+
* sparse term). **Exclusive relations only** (matches the traversal constraint
|
|
288
|
+
* #474); a multi relation throws `RELATION_MODE_MISMATCH` at iteration, and a
|
|
289
|
+
* cycle is a loud `RELATION_CYCLE` in `DEV` (a safe break in production).
|
|
290
|
+
* Requires `relationReads: [R]` (checked at iteration). Carried through
|
|
291
|
+
* `and`/`not`/`anyOf` like the sparse terms (`_carryNondense`).
|
|
292
|
+
*
|
|
293
|
+
* `Defs` is unchanged — `R` is an ordering, not a required component (like
|
|
294
|
+
* `not` / `anyOf`). Returns a new query; the unbounded form is cached. */
|
|
295
|
+
hierarchy(relation: RelationDef<"exclusive">, maxDepth?: number): Query<Defs>;
|
|
296
|
+
/** Build a derived query carrying a hierarchy ordering term. Reuses this
|
|
297
|
+
* query's dense / sparse / optional / disabled / relation-wildcard state by
|
|
298
|
+
* reference (the matched set is unchanged) — same rationale as `_deriveSparse`. */
|
|
299
|
+
private _deriveHierarchy;
|
|
300
|
+
/** Assert every `(R, *)` wildcard term on this query was declared in the
|
|
301
|
+
* system's `relationReads` (#579 / #496). Iteration-time (`forEachEntity` /
|
|
302
|
+
* `forEachRelatedTo`), not construction-time, so it is robust to queries
|
|
303
|
+
* built outside a system — same rationale as the data-op checks. `DEV` only;
|
|
304
|
+
* outside a system `checkRelationRead` is a no-op. */
|
|
305
|
+
private _checkRelationAccess;
|
|
306
|
+
/** Iterate every source related to `target` under **any** relation — the
|
|
307
|
+
* `(*, T)` wildcard (#579) — intersected with this query's dense + sparse +
|
|
308
|
+
* `(R, *)` + disabled predicate, each source yielded once in ascending-EntityID
|
|
309
|
+
* order (the `sourcesOf` / `sourcesOfAny` convention). `target` is supplied
|
|
310
|
+
* here rather than as a chained term because it is a runtime `EntityID`: baking
|
|
311
|
+
* it into a cached `Query` would key the cache on a recycled value and churn
|
|
312
|
+
* query-ids, and `(*, T)` is the rare/cold shape. Composes with
|
|
313
|
+
* `withRelation` / `withSparse` / dense terms on the receiver. Reads
|
|
314
|
+
* every relation's reverse index, so the system must declare
|
|
315
|
+
* `relationReads: [ANY_RELATION]` (plus `[R]` for any composed `withRelation`).
|
|
316
|
+
* Cold/structural — not a per-tick hot loop over many targets. */
|
|
317
|
+
forEachRelatedTo(target: EntityID, cb: (entityId: EntityID) => void): void;
|
|
318
|
+
/** Add optional fetch-if-present terms (#575). Does NOT narrow the matched
|
|
319
|
+
* set — the dense mask is untouched, so iteration still spans archetypes with
|
|
320
|
+
* and without each `T`. Read each column per archetype span via
|
|
321
|
+
* `arch.getOptionalColumnRead(T, field)` (column when present, `undefined`
|
|
322
|
+
* when absent). `.optional(T)` is the *declaration* that authorizes that fetch:
|
|
323
|
+
* inside `forEach`, `getOptionalColumnRead` throws in `DEV` if `T` was
|
|
324
|
+
* not declared here (#592) — the read-side analog of `reads:[T]`, which is also
|
|
325
|
+
* still required for access coverage (both checks fire, even on the absent
|
|
326
|
+
* span). The term is carried through `and`/`not`/`anyOf` (see
|
|
327
|
+
* `_carryNondense`), so it survives composition in any order. Returns a new
|
|
328
|
+
* (cached) Query.
|
|
329
|
+
*
|
|
330
|
+
* `Defs` is unchanged (the optional `T` is not a required component, like
|
|
331
|
+
* `not` / `anyOf`); column types come from the accessor's own generics. */
|
|
332
|
+
optional(...defs: ComponentDef[]): Query<Defs>;
|
|
333
|
+
/** One-id `optional` composition, cached on `(parent_id << 16) | cid` in the
|
|
334
|
+
* resolver's shared single-term map (dense cid <= 128, same packing as the
|
|
335
|
+
* `and` / `not` / `anyOf` caches). */
|
|
336
|
+
private _optionalOne;
|
|
337
|
+
/** Build a derived query carrying new optional terms. Reuses this query's
|
|
338
|
+
* dense state by reference (the matched set is unchanged) and carries the
|
|
339
|
+
* existing sparse terms through unchanged — same rationale as `_deriveSparse`. */
|
|
340
|
+
private _deriveOptional;
|
|
341
|
+
/** Opt this query back in to disabled entities (#577). By default a query
|
|
342
|
+
* excludes disabled entities (the iteration bound `arch.entityCount` is the
|
|
343
|
+
* enabled-row count). The returned (cached) query spans disabled rows too:
|
|
344
|
+
* `forEach` publishes the all-rows flag so the SoA loop's `arch.entityCount`
|
|
345
|
+
* reports `length`, and `count`/`forEachEntity` widen accordingly. Does NOT
|
|
346
|
+
* touch the dense mask, so it reuses this query's live archetype list and is
|
|
347
|
+
* carried through `and`/`not`/`anyOf` like the sparse/optional terms. */
|
|
348
|
+
includeDisabled(): Query<Defs>;
|
|
349
|
+
forEach(cb: (arch: ArchetypeView<Defs>) => void): void;
|
|
350
|
+
/** @internal — cold `includeDisabled` wrapper for `forEach` (#577), split out
|
|
351
|
+
* (#649) so the all-rows flag dance (`_setIterAllRows` + try/finally) stays
|
|
352
|
+
* out of `forEach`'s inlined hot body. The default (enabled-only) query never
|
|
353
|
+
* reaches here, so V8 leaves this uninlined and `forEach` shrinks accordingly. */
|
|
354
|
+
private _forEachIncludeDisabled;
|
|
355
|
+
/**
|
|
356
|
+
* Per-archetype destructured column iteration (§eachChunk) — the flecs
|
|
357
|
+
* `run()` / koota `useStores` model, and the recommended hot-path default for
|
|
358
|
+
* mutating systems:
|
|
359
|
+
*
|
|
360
|
+
* q.eachChunk((cols, count) => {
|
|
361
|
+
* const { x, y } = cols.mut(Pos); // whole group, tick stamped inside
|
|
362
|
+
* const { vx, vy } = cols.read(Vel); // read-only group
|
|
363
|
+
* for (let i = 0; i < count; i++) { x[i] += vx[i] * dt; y[i] += vy[i] * dt; }
|
|
364
|
+
* });
|
|
365
|
+
*
|
|
366
|
+
* vs the raw path it replaces (per-field `getColumn` + manual `ecsTick`
|
|
367
|
+
* thread + `entityCount` loop). It folds away: per-field fetches (one call
|
|
368
|
+
* per component), the `getColumn`/`getColumnRead` choice (→ `.mut`/`.read`),
|
|
369
|
+
* the manual tick arg (hidden in `.mut`), and the `.length`-vs-`entityCount`
|
|
370
|
+
* corruption trap (`count` is `entityCount`). It is also the only mutable
|
|
371
|
+
* column accessor reachable through the iteration path — the read-only
|
|
372
|
+
* `ArchetypeView` from `forEach` deliberately omits the mutable `getColumn`.
|
|
373
|
+
* The SoA inner loop is byte-identical, and the per-archetype group objects
|
|
374
|
+
* are cached (zero per-archetype allocation). One `ChunkColumns` cursor is
|
|
375
|
+
* allocated per pass and reused across that pass's archetypes. Honours
|
|
376
|
+
* `includeDisabled()` exactly like `forEach` (the bound widens to the
|
|
377
|
+
* disabled tail); dense-only like `forEach` (sparse/relation/hierarchy terms
|
|
378
|
+
* throw in `DEV` — iterate those with `forEachEntity`).
|
|
379
|
+
*/
|
|
380
|
+
eachChunk(cb: (cols: ChunkColumns<Defs>, count: number) => void): void;
|
|
381
|
+
/** @internal — shared body for `eachChunk`'s default and `includeDisabled`
|
|
382
|
+
* paths. The `ChunkColumns` cursor is allocated per call (a 2-field object whose
|
|
383
|
+
* cost doesn't scale with the per-row work) rather than cached on the query, so
|
|
384
|
+
* a nested `eachChunk` on the SAME query gets its own cursor instead of
|
|
385
|
+
* re-pointing the outer pass's `_arch`/`_tick`. The per-(archetype, component)
|
|
386
|
+
* column-group caches that actually matter for allocation live on the
|
|
387
|
+
* `Archetype`, untouched. */
|
|
388
|
+
private _eachChunkInner;
|
|
389
|
+
/**
|
|
390
|
+
* Early-exit iteration: like `forEach`, but stops as soon as `cb` returns
|
|
391
|
+
* `true`, and returns whether any callback did. The predicate analog for
|
|
392
|
+
* "does any matching row satisfy X?" — without it, callers hand-rolled a
|
|
393
|
+
* `query.archetypes` walk (re-implementing the empty-archetype skip) just
|
|
394
|
+
* to be able to `return` mid-scan. Deliberately a separate method:
|
|
395
|
+
* honouring return values on `forEach`'s existing `=> void` callback
|
|
396
|
+
* would silently change behaviour for arrow-expression bodies that happen
|
|
397
|
+
* to return a truthy value.
|
|
398
|
+
*/
|
|
399
|
+
forEachUntil(cb: (arch: ArchetypeView<Defs>) => boolean): boolean;
|
|
400
|
+
/** @internal — shared body for `forEachUntil`'s default and
|
|
401
|
+
* `includeDisabled` paths. Same dev-mode optional-term scope as
|
|
402
|
+
* `forEach` (#592). */
|
|
403
|
+
private _forEachUntilInner;
|
|
404
|
+
/** @internal — the `includeDisabled` delegate for `forEach` (#577). The
|
|
405
|
+
* default (enabled-only) path inlines this body directly into `forEach`
|
|
406
|
+
* (#608) to dodge a megamorphic delegate hop; this copy survives only for the
|
|
407
|
+
* rare all-rows path, which needs the `_setIterAllRows` try/finally wrap. */
|
|
408
|
+
private _forEachInner;
|
|
409
|
+
/** Iterate the entities this query matches, yielding each `EntityID`
|
|
410
|
+
* (#469 — the sparse-membership match path). Use this whenever the query
|
|
411
|
+
* carries a `withSparse` / `withoutSparse` term: members are scattered
|
|
412
|
+
* across archetypes, so there is no SoA column span to hand back — read
|
|
413
|
+
* fields via `ctx.getField` (dense) or `ctx.getSparseField` (sparse) on
|
|
414
|
+
* the yielded entity. A dense-only query also works here (it walks its
|
|
415
|
+
* archetypes' entity ids), but prefer `forEach` for the SoA hot loop.
|
|
416
|
+
*
|
|
417
|
+
* Iteration is read-mostly: mutating the *driving* sparse component's
|
|
418
|
+
* membership mid-iteration is unsafe. The walk drives off the store's live
|
|
419
|
+
* key array, so **adding** the driving component (the store `push`es a new
|
|
420
|
+
* key, which the `i < length` loop then visits) and **removing** it (the
|
|
421
|
+
* store swap-pops, shifting the index list under the walk) both corrupt the
|
|
422
|
+
* traversal. This is sharper than for dense `forEach`: `ctx.addSparse` /
|
|
423
|
+
* `ctx.addRelation` apply *immediately* (no archetype transition to defer),
|
|
424
|
+
* so unlike a deferred dense `addComponent` the mutation lands in the live
|
|
425
|
+
* array at once. Buffer such edits and apply them after the walk. */
|
|
426
|
+
forEachEntity(cb: (entityId: EntityID) => void): void;
|
|
427
|
+
/** @internal — used by ChangedQuery. Rebuild non-empty archetype list if the
|
|
428
|
+
* Store has bumped its dirty epoch since our last rebuild, return cached result.
|
|
429
|
+
*
|
|
430
|
+
* Rebuild allocates a *fresh* array and swaps it in rather than truncating
|
|
431
|
+
* the cached one in place (#431). `forEach`/`count`/`ChangedQuery.forEach`
|
|
432
|
+
* bind the returned array once and walk it; an in-place `dst.length = 0` +
|
|
433
|
+
* re-push would corrupt that walk if the query is re-entrantly iterated —
|
|
434
|
+
* i.e. the callback runs an immediate-mode mutation that crosses a
|
|
435
|
+
* 0↔non-zero entity boundary on the *same* Query (bumping the epoch) and
|
|
436
|
+
* then re-enters here via a nested `forEach`/`count`. Building fresh hands
|
|
437
|
+
* the inner call its own array and leaves the outer iterator's snapshot
|
|
438
|
+
* intact, so each archetype is visited exactly once. Cost is one array
|
|
439
|
+
* allocation per epoch advance (rare — only on boundary crossings); the
|
|
440
|
+
* steady-state path returns the cached array with zero allocation. In-system
|
|
441
|
+
* iteration never triggers a rebuild mid-loop: deferred mutations settle the
|
|
442
|
+
* epoch during `flushStructural`, between systems. */
|
|
443
|
+
_nonEmpty(): Archetype[];
|
|
444
|
+
/** @internal — cold rebuild path for `_nonEmpty`, split out (#649) so the
|
|
445
|
+
* hot `_nonEmpty` body is just an epoch check + cached return. Keeping the
|
|
446
|
+
* filter loops here shrinks `_nonEmpty`'s inlined bytecode footprint, which
|
|
447
|
+
* matters when several composed queries iterate inside one hot function (the
|
|
448
|
+
* `query_compose` shape): the leaner `_nonEmpty` keeps `forEach` under V8's
|
|
449
|
+
* per-function cumulative inlining budget. */
|
|
450
|
+
private _rebuildNonEmpty;
|
|
451
|
+
/** Require at least one of these components. */
|
|
452
|
+
anyOf(...comps: ComponentDef[]): Query<Defs>;
|
|
453
|
+
/** @internal — cold cache-miss path for single-arg `anyOf` (#649); see `_andMiss`. */
|
|
454
|
+
private _anyOfMiss;
|
|
455
|
+
/** Create a ChangedQuery that filters archetypes by change tick.
|
|
456
|
+
*
|
|
457
|
+
* Granularity is **archetype**, not row: the `_changedTick[cid]` is
|
|
458
|
+
* bumped per archetype on any write into that component's column
|
|
459
|
+
* (`Archetype._changedTick` in archetype.ts). A 1-row write in a
|
|
460
|
+
* 1000-row archetype trips `forEach` on the whole archetype next tick.
|
|
461
|
+
* Use cases that need row-level granularity should compare per-row
|
|
462
|
+
* state explicitly inside the callback.
|
|
463
|
+
*
|
|
464
|
+
* The returned ChangedQuery is composable (M6): `and`/`without`/`anyOf`/
|
|
465
|
+
* `optional` refine it further, so `q.changed(Pos).without(Dead)` works — and
|
|
466
|
+
* is the same set as `q.without(Dead).changed(Pos)`. */
|
|
467
|
+
changed(...defs: ComponentDef[]): ChangedQuery<Defs>;
|
|
468
|
+
/** @internal — cold cache-miss path for single-arg `changed` (#649); see `_andMiss`. */
|
|
469
|
+
private _changedMiss;
|
|
470
|
+
/** @internal — reads lastRunTick from the resolver (ECS). */
|
|
471
|
+
_ctxLastRunTick(): number;
|
|
472
|
+
}
|
|
473
|
+
export declare class QueryBuilder {
|
|
474
|
+
private readonly _resolver;
|
|
475
|
+
constructor(_resolver: QueryResolver);
|
|
476
|
+
with<T extends ComponentDef[]>(...defs: T): Query<T>;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* A `BundleOrDef` whose def is constrained to the enclosing system's declared
|
|
480
|
+
* add surface (§typestate). The bundle branch restates `Bundle`'s shape with
|
|
481
|
+
* the def slot narrowed — intersecting `Bundle<any> & { def: … }` instead
|
|
482
|
+
* would put two `ComponentDef` instantiations in one intersection, which TS
|
|
483
|
+
* relates leniently (see system.ts §typestate notes).
|
|
484
|
+
*
|
|
485
|
+
* The outer conditional is a deliberate no-op (`[D] extends [unknown]` is
|
|
486
|
+
* always true): it makes the variance of `D` — and therefore of the access
|
|
487
|
+
* param `A` threaded through `Commands` / `SystemContext` — UNMEASURABLE to
|
|
488
|
+
* the compiler. A measurable (plain-union) definition here gets `A` marked
|
|
489
|
+
* reliably contravariant, variance-based comparison then rejects
|
|
490
|
+
* `SystemContext<Narrow> → SystemContext` without the structural fallback,
|
|
491
|
+
* and every helper taking a bare `SystemContext` stops accepting typed
|
|
492
|
+
* contexts. Unmeasurable variance forces the structural path, where class
|
|
493
|
+
* methods compare bivariantly and the conversion holds.
|
|
494
|
+
*/
|
|
495
|
+
export type DeclaredBundleOrDef<D> = [D] extends [unknown] ? D | {
|
|
496
|
+
readonly def: D;
|
|
497
|
+
readonly values: Readonly<Partial<Record<string, number>>>;
|
|
498
|
+
} : never;
|
|
499
|
+
/**
|
|
500
|
+
* Deferred structural-command facade (§ctx.commands — Bevy `Commands`).
|
|
501
|
+
* Namespaces the deferred structural ops so the call site is self-documenting:
|
|
502
|
+
* `ctx.commands.add(e, …)` is *always* deferred (applied at the phase flush),
|
|
503
|
+
* ending the collision where `ecs.addComponent` (immediate) and a bare
|
|
504
|
+
* `ctx.addComponent` (deferred) would share a name with opposite timing. Takes
|
|
505
|
+
* varargs callable bundles, so one shape — `commands.spawn(bundle(Pos,{x,y}), bundle(Vel,{vx:1}))`
|
|
506
|
+
* — serves spawn and add. This is the ONLY deferred surface: the bare
|
|
507
|
+
* `ctx.addComponent` / `ctx.removeComponent` / `ctx.disable` / `ctx.enable`
|
|
508
|
+
* duplicates were removed in 0.5.0, completing the receiver-implies-timing
|
|
509
|
+
* rule (`ecs.*` immediate, `ctx.commands.*` deferred) that 0.5.0 started for
|
|
510
|
+
* spawn/despawn.
|
|
511
|
+
*
|
|
512
|
+
* `A` narrows the def-taking methods to the enclosing system's declared access
|
|
513
|
+
* (§typestate, system.ts); the default is fully permissive.
|
|
514
|
+
*
|
|
515
|
+
* `out A` (declared covariance) is deliberate: every use of `A` sits inside a
|
|
516
|
+
* declared-access conditional, whose variance the compiler cannot measure —
|
|
517
|
+
* left unannotated, the measured verdict rejects `Commands<Narrow> →
|
|
518
|
+
* Commands` (the direction every permissive consumer needs). Covariance is
|
|
519
|
+
* the honest direction: a context with MORE declared access is usable where
|
|
520
|
+
* one with less is expected. The checks themselves are per-instantiation, so
|
|
521
|
+
* the annotation does not weaken them.
|
|
522
|
+
*/
|
|
523
|
+
export declare class Commands<out A extends SystemAccess = SystemAccess> {
|
|
524
|
+
private readonly store;
|
|
525
|
+
constructor(store: Store);
|
|
526
|
+
/** Spawn from bundles. Create is immediate (the id is returned now); the
|
|
527
|
+
* component attaches are deferred to the phase flush — so until that flush the
|
|
528
|
+
* entity exists in its empty/partial archetype and a query running later in
|
|
529
|
+
* the same phase can observe it half-built. (Same semantics as
|
|
530
|
+
* `ctx.commands.spawn()` + `ctx.addComponent`; fully-deferred id-reservation
|
|
531
|
+
* spawn, à la Bevy, is a separate follow-up.) */
|
|
532
|
+
spawn(...items: DeclaredBundleOrDef<A["add"]>[]): EntityID;
|
|
533
|
+
/** Attach bundles to an existing entity (deferred). Bundles zero-fill
|
|
534
|
+
* omitted fields. */
|
|
535
|
+
add(entityId: EntityID, ...items: DeclaredBundleOrDef<A["add"]>[]): this;
|
|
536
|
+
/** Explicit complete-values attach (deferred) — the compile-checked shape
|
|
537
|
+
* where a typo'd or missing field is a compile error, mirroring the
|
|
538
|
+
* immediate `ecs.addComponent(e, def, values)`. Tags take no values
|
|
539
|
+
* argument (`AttachValuesArg`). */
|
|
540
|
+
add<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredAdd<A, D>, ...values: AttachValuesArg<SchemaOf<D>>): this;
|
|
541
|
+
/** Remove a component (deferred). */
|
|
542
|
+
remove<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredRemove<A, D>): this;
|
|
543
|
+
/** Destroy an entity (deferred). */
|
|
544
|
+
despawn(entityId: DespawnArg<A>): this;
|
|
545
|
+
/** Buffer `entityId` to be disabled at the phase flush (idempotent, #577).
|
|
546
|
+
* Deferred because a toggle is an in-archetype row swap, which would corrupt
|
|
547
|
+
* a `forEach` SoA loop iterating that archetype if applied mid-system (it
|
|
548
|
+
* reorders the dense columns being read). A disabled entity is excluded from
|
|
549
|
+
* default queries; opt back in per query with `.includeDisabled()`. The
|
|
550
|
+
* immediate read is `ctx.isDisabled`. */
|
|
551
|
+
disable(entityId: EntityID): this;
|
|
552
|
+
/** Buffer `entityId` to be re-enabled at the phase flush (idempotent).
|
|
553
|
+
* Deferred for the same row-swap reason as `disable`. */
|
|
554
|
+
enable(entityId: EntityID): this;
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* The per-system world facade. `A` is the system's declared access surface
|
|
558
|
+
* (§typestate, system.ts): the config-form `registerSystem` computes it from
|
|
559
|
+
* the literal `reads`/`writes`/… declarations and every guarded method below
|
|
560
|
+
* checks its handle argument against the matching union at compile time —
|
|
561
|
+
* the same rules `accessCheck` enforces at runtime in `DEV`. The default
|
|
562
|
+
* `A = SystemAccess` is fully permissive, so a bare `SystemContext` (helper
|
|
563
|
+
* functions, host-side code, explicitly-annotated escape hatches) behaves
|
|
564
|
+
* exactly as before, and every narrowed `SystemContext<…>` is assignable to
|
|
565
|
+
* it.
|
|
566
|
+
*
|
|
567
|
+
* `out A` (declared covariance) is deliberate — see `Commands` above: the
|
|
568
|
+
* declared-access conditionals are unmeasurable to the compiler, and the
|
|
569
|
+
* unannotated verdict rejects exactly the `SystemContext<Narrow> →
|
|
570
|
+
* SystemContext` conversion the whole design depends on.
|
|
571
|
+
*/
|
|
572
|
+
export declare class SystemContext<out A extends SystemAccess = SystemAccess> {
|
|
573
|
+
private readonly store;
|
|
574
|
+
lastRunTick: number;
|
|
575
|
+
/** Deferred structural-command facade (§ctx.commands). */
|
|
576
|
+
readonly commands: Commands<A>;
|
|
577
|
+
/** Current ECS tick. Use this for write ticks in getColumn. */
|
|
578
|
+
get ecsTick(): number;
|
|
579
|
+
/** The world's frame-trace sink (ADR-0030), or `null`. Lets the schedule
|
|
580
|
+
* fire `systemStart`/`flush*` without reaching into the private store.
|
|
581
|
+
* Read only under `if (DEV)`; the seam is dead-code-eliminated in prod. */
|
|
582
|
+
get _trace(): FrameTraceSink | null;
|
|
583
|
+
constructor(store: Store);
|
|
584
|
+
isAlive(entityId: EntityID): boolean;
|
|
585
|
+
hasComponent(entityId: EntityID, def: ComponentDef): boolean;
|
|
586
|
+
getField<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredRead<A, D>, field: string & keyof SchemaOf<D>): number;
|
|
587
|
+
/** Total sibling of {@link getField}, mirroring `ecs.tryGetField`
|
|
588
|
+
* (POLISH_AUDIT #9): `undefined` when the entity is dead or doesn't hold
|
|
589
|
+
* the component, instead of a dev throw / prod garbage read. The safe way
|
|
590
|
+
* to probe-and-read in one call: `ctx.tryGetField(e, Health, "current") ?? 0`. */
|
|
591
|
+
tryGetField<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredRead<A, D>, field: string & keyof SchemaOf<D>): number | undefined;
|
|
592
|
+
setField<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredWrite<A, D>, field: string & keyof SchemaOf<D>, value: number): void;
|
|
593
|
+
/** Read-modify-write one field: `updateField(e, Gold, "value", v => v - cost)`
|
|
594
|
+
* is the one-line form of the `getField` → compute → `setField` round trip.
|
|
595
|
+
* Returns the written value. Same access-check and observer semantics as the
|
|
596
|
+
* two calls it composes (inlined here: the declared-access conditionals on
|
|
597
|
+
* those methods only resolve per `A` instantiation, so a body where `A` is
|
|
598
|
+
* still generic cannot call them without casts). */
|
|
599
|
+
updateField<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredWrite<A, D>, field: string & keyof SchemaOf<D>, fn: (current: number) => number): number;
|
|
600
|
+
/**
|
|
601
|
+
* Record an entity as changed for a component's per-entity `onSet` observer
|
|
602
|
+
* (#517 §1 / ADR-0013). The SoA write idiom — `const col = arch.getColumn(D,
|
|
603
|
+
* f, tick); col[i] = v` in a tight loop — bypasses the deferred buffer and the
|
|
604
|
+
* engine never sees the per-element writes, so a per-entity `onSet` consumer
|
|
605
|
+
* pushes the row here (the bench's winning `tick+list`: raw write + an int
|
|
606
|
+
* push, fired batched at the post-update detection point — never a per-element
|
|
607
|
+
* observable setter). No-op for components without a per-entity onSet observer.
|
|
608
|
+
* `setField` records automatically; this is for the hot `getColumn` loop.
|
|
609
|
+
*/
|
|
610
|
+
markChanged(entityId: EntityID, def: ComponentDef): void;
|
|
611
|
+
/**
|
|
612
|
+
* Create a cached component reference for a single entity. Marks the
|
|
613
|
+
* component as changed (the mutable default — see `refRead` for the
|
|
614
|
+
* read-only variant to reach for when you are not mutating). See ref.ts.
|
|
615
|
+
*/
|
|
616
|
+
ref<D extends ComponentDef<any>>(def: D & DeclaredWrite<A, D>, entityId: EntityID): ComponentRef<SchemaOf<D>>;
|
|
617
|
+
/**
|
|
618
|
+
* Create a cached read-only component reference for a single entity. Use
|
|
619
|
+
* this when you are not mutating. The returned `ReadonlyComponentRef<S>`
|
|
620
|
+
* is an *advisory* compile-time barrier (no `_changedTick` bump): the
|
|
621
|
+
* `readonly` typing blocks field writes at the type layer, but the
|
|
622
|
+
* underlying accessor shares its prototype with `ref()` and can still be
|
|
623
|
+
* written through a §10c-policed cast. See ref.ts.
|
|
624
|
+
*/
|
|
625
|
+
refRead<D extends ComponentDef<any>>(def: D & DeclaredRead<A, D>, entityId: EntityID): ReadonlyComponentRef<SchemaOf<D>>;
|
|
626
|
+
/** Whether `entityId` is currently disabled (immediate read). Toggling is
|
|
627
|
+
* deferred — `ctx.commands.disable` / `ctx.commands.enable` (#577). */
|
|
628
|
+
isDisabled(entityId: EntityID): boolean;
|
|
629
|
+
/** Tags take no values argument; valued schemas require a complete one. */
|
|
630
|
+
addSparse<D extends SparseComponentDef<any>>(entityId: EntityID, def: D & DeclaredSparseWrite<A, D>, ...values: AttachValuesArg<SparseSchemaOf<D>>): this;
|
|
631
|
+
removeSparse<D extends SparseComponentDef<any>>(entityId: EntityID, def: D & DeclaredSparseWrite<A, D>): this;
|
|
632
|
+
hasSparse(entityId: EntityID, def: SparseComponentDef): boolean;
|
|
633
|
+
getSparseField<D extends SparseComponentDef<any>>(entityId: EntityID, def: D & DeclaredSparseRead<A, D>, field: string & keyof SparseSchemaOf<D>): number;
|
|
634
|
+
setSparseField<D extends SparseComponentDef<any>>(entityId: EntityID, def: D & DeclaredSparseWrite<A, D>, field: string & keyof SparseSchemaOf<D>, value: number): void;
|
|
635
|
+
/** Add a `(R, tgt)` pair to `src` (exclusive replaces, multi adds). */
|
|
636
|
+
addRelation<D extends RelationDef>(src: EntityID, def: D & DeclaredRelationWrite<A, D>, tgt: EntityID): this;
|
|
637
|
+
/** Remove a `(R, tgt)` pair from `src`; for multi, omitting `tgt` removes all. */
|
|
638
|
+
removeRelation<D extends RelationDef>(src: EntityID, def: D & DeclaredRelationWrite<A, D>, tgt?: EntityID): this;
|
|
639
|
+
/** The single target of `src` under an exclusive relation, or `undefined`. */
|
|
640
|
+
targetOf<D extends RelationDef<"exclusive">>(src: EntityID, def: D & DeclaredRelationRead<A, D>): EntityID | undefined;
|
|
641
|
+
/** All targets of `src` under `R`, ascending by id. */
|
|
642
|
+
targetsOf<D extends RelationDef>(src: EntityID, def: D & DeclaredRelationRead<A, D>): EntityID[];
|
|
643
|
+
/** Sources pointing at `tgt` under `R` (the reverse index), ascending by id.
|
|
644
|
+
* `(entity, def)` order, matching `targetOf` / `targetsOf`. */
|
|
645
|
+
sourcesOf<D extends RelationDef>(tgt: EntityID, def: D & DeclaredRelationRead<A, D>): EntityID[];
|
|
646
|
+
/** Whether `src` holds any pair under `R`. */
|
|
647
|
+
hasRelation(src: EntityID, def: RelationDef): boolean;
|
|
648
|
+
/** Flush all deferred changes: structural (add/remove) first, then
|
|
649
|
+
* destructions. Republishes archetype row counts into the SAB
|
|
650
|
+
* descriptor at the end so any WASM scan running in the next phase
|
|
651
|
+
* sees fresh `row_count` fields. This is one of two publish sites —
|
|
652
|
+
* `ECS.update()` also republishes once at tick start (see PATTERNS.md
|
|
653
|
+
* §60), covering host-side mutations between updates. The publish walks
|
|
654
|
+
* descriptors only — it doesn't touch column data — and benches at
|
|
655
|
+
* sub-microsecond per archetype, so paying it once per phase boundary
|
|
656
|
+
* is materially cheaper than the pre-#306 pattern of paying it per
|
|
657
|
+
* WASM-using system per tick. After #336 the descriptor walk is gated
|
|
658
|
+
* on a dirty flag, so read-only phases skip the walk entirely. */
|
|
659
|
+
flush(): void;
|
|
660
|
+
/**
|
|
661
|
+
* Emit an event (or a payload-less signal) onto its channel. The event is
|
|
662
|
+
* visible to every system that runs *later* in the same `update()` and is
|
|
663
|
+
* cleared at the tick's tail — events live exactly one tick, there is no
|
|
664
|
+
* ack/consume. The channel must have been registered at world setup via
|
|
665
|
+
* `ecs.events.register(key, fields)` / `registerSignal(key)`.
|
|
666
|
+
*
|
|
667
|
+
* @example
|
|
668
|
+
* const Damaged = eventKey<{ target: EntityID; amount: number }>("Damaged");
|
|
669
|
+
* ecs.events.register(Damaged, ["target", "amount"]);
|
|
670
|
+
* // inside a system:
|
|
671
|
+
* ctx.emit(Damaged, { target: e, amount: 10 });
|
|
672
|
+
*/
|
|
673
|
+
emit(key: SignalKey): void;
|
|
674
|
+
emit<S extends EventShape<S>>(key: EventKey<S>, values: NoInfer<S>): void;
|
|
675
|
+
/**
|
|
676
|
+
* Read this tick's events on a channel. Returns an SoA reader over
|
|
677
|
+
* everything emitted *earlier in the same `update()`* — order systems so
|
|
678
|
+
* readers run after emitters, or they see an empty reader.
|
|
679
|
+
*
|
|
680
|
+
* @example
|
|
681
|
+
* const dmg = ctx.read(Damaged); // SoA columns, one per field
|
|
682
|
+
* for (let i = 0; i < dmg.length; i++) {
|
|
683
|
+
* applyDamage(dmg.target[i], dmg.amount[i]);
|
|
684
|
+
* }
|
|
685
|
+
*/
|
|
686
|
+
read<S extends EventShape<S>>(key: EventKey<S>): EventReader<S>;
|
|
687
|
+
resource<K extends ResourceKey<any>>(key: K & DeclaredResourceRead<A, K>): ResourceValueOf<K>;
|
|
688
|
+
setResource<K extends ResourceKey<any>>(key: K & DeclaredResourceWrite<A, K>, value: ResourceValueOf<NoInfer<K>>): void;
|
|
689
|
+
/** Drop a resource mid-tick (#798). A lifecycle mutation, so it is access-
|
|
690
|
+
* checked as a *write* — the system must declare the key in `resourceWrites`,
|
|
691
|
+
* which serialises it against readers/writers of the same resource. Fails
|
|
692
|
+
* closed on a missing key. */
|
|
693
|
+
removeResource<K extends ResourceKey<any>>(key: K & DeclaredResourceWrite<A, K>): void;
|
|
694
|
+
hasResource<T>(key: ResourceKey<T>): boolean;
|
|
695
|
+
}
|
|
696
|
+
export declare class ChangedQuery<Defs extends readonly ComponentDef[]> {
|
|
697
|
+
private readonly _query;
|
|
698
|
+
private readonly _changedIds;
|
|
699
|
+
constructor(query: Query<Defs>, changedIds: number[]);
|
|
700
|
+
/** Also require these components (mirrors `Query.and`). */
|
|
701
|
+
and<D extends ComponentDef[]>(...comps: D): ChangedQuery<[...Defs, ...D]>;
|
|
702
|
+
/** Exclude archetypes holding any of these (mirrors `Query.without`). */
|
|
703
|
+
without(...comps: ComponentDef[]): ChangedQuery<Defs>;
|
|
704
|
+
/** Require at least one of these (mirrors `Query.anyOf`). */
|
|
705
|
+
anyOf(...comps: ComponentDef[]): ChangedQuery<Defs>;
|
|
706
|
+
/** Permit optional-component data access in the loop (mirrors `Query.optional`). */
|
|
707
|
+
optional(...defs: ComponentDef[]): ChangedQuery<Defs>;
|
|
708
|
+
forEach(cb: (arch: ArchetypeView<Defs>) => void): void;
|
|
709
|
+
/** @internal — cold `includeDisabled` wrapper (#577), split out of `forEach`
|
|
710
|
+
* (#649) so the all-rows flag dance stays out of the inlined hot body. */
|
|
711
|
+
private _forEachIncludeDisabled;
|
|
712
|
+
/** @internal — the `includeDisabled` delegate for `forEach` (#577). The
|
|
713
|
+
* default path inlines this body directly into `forEach` (#608) to dodge a
|
|
714
|
+
* megamorphic delegate hop; this copy survives only for the rare all-rows
|
|
715
|
+
* path, which needs the `_setIterAllRows` try/finally wrap. */
|
|
716
|
+
private _forEachInner;
|
|
717
|
+
}
|
|
718
|
+
//# sourceMappingURL=query.d.ts.map
|