@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,40 @@
|
|
|
1
|
+
import { ComponentDef, ComponentSchema, EntityID } from '../../core/ecs/index.js';
|
|
2
|
+
import { Editor } from './editor.js';
|
|
3
|
+
/**
|
|
4
|
+
* A two-way handle on one `(entity, component, field)` slot. `value` reads the
|
|
5
|
+
* reactive channel (tracked, if read in a tracking scope); `set` enqueues an
|
|
6
|
+
* undoable `setField` command via the editor.
|
|
7
|
+
*/
|
|
8
|
+
export interface FieldHandle {
|
|
9
|
+
/**
|
|
10
|
+
* The field's current value through the reactive read channel — `undefined`
|
|
11
|
+
* until the channel has it (e.g. before the spawn's first commit). Read inside
|
|
12
|
+
* a tracking scope to subscribe to the channel; the value reflects the last
|
|
13
|
+
* COMMITTED tick, so a fresh `set` shows up on the next tick.
|
|
14
|
+
*/
|
|
15
|
+
readonly value: number | undefined;
|
|
16
|
+
/** Enqueue an undoable `setField` for this slot; applied at the next tick. */
|
|
17
|
+
set(value: number): void;
|
|
18
|
+
/**
|
|
19
|
+
* The editor's pending (not-yet-committed) value for this slot, or `undefined`
|
|
20
|
+
* if none — a NON-reactive read of the editor shadow, for an optimistic echo
|
|
21
|
+
* between the `set` and its commit. Self-resolves to `undefined` once the read
|
|
22
|
+
* channel catches up, so it does not outlive the edit. Not a substitute for
|
|
23
|
+
* `value` in a tracking scope (it does not subscribe); `value` is the source of
|
|
24
|
+
* truth.
|
|
25
|
+
*/
|
|
26
|
+
readonly pending: number | undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build a {@link FieldHandle} for one `(eid, def, field)` slot. `read` is the
|
|
30
|
+
* tracked read of the reactive channel for this field (e.g.
|
|
31
|
+
* `() => sync.map.get(eid)?.x`); `set` routes through `editor.setField`, so the
|
|
32
|
+
* edit is queued, batched, and undoable.
|
|
33
|
+
*
|
|
34
|
+
* `read` is optional (M11): omitted, the handle reads through the editor's own
|
|
35
|
+
* committed-channel reader (`editor.committedField`). That default is correct
|
|
36
|
+
* but NOT reactive — supply the channel thunk when the handle's `value` must
|
|
37
|
+
* subscribe inside a tracking scope.
|
|
38
|
+
*/
|
|
39
|
+
export declare function fieldHandle<S extends ComponentSchema>(editor: Editor, eid: EntityID, def: ComponentDef<S>, field: string & keyof S, read?: () => number | undefined): FieldHandle;
|
|
40
|
+
//# sourceMappingURL=field_handle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field_handle.d.ts","sourceRoot":"","sources":["../../../src/extensions/editor/field_handle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,8EAA8E;IAC9E,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,eAAe,EACpD,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,EACpB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,EACvB,IAAI,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,GAC7B,WAAW,CAYb"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function d(r,t,e){return`${r}:${t.id}:${e}`}const a=new WeakMap;class h{constructor(t,e){this.readField=t,this.shadow=e,a.set(this,{forward:[],inverse:[]})}staged=new Map;get _txn(){return a.get(this)}spawn(t,e){const n={kind:"despawn",eid:0};return this._txn.inverse.push(n),this._txn.forward.push({kind:"spawn",components:t,onSpawned:s=>{n.eid=s,e?.(s)}}),this}despawn(t,e){const n={kind:"despawn",eid:t};return this._txn.forward.push(n),this._txn.inverse.push({kind:"spawn",components:e,onSpawned:s=>{n.eid=s}}),this}setField(t,e,n,s){const i=d(t,e,n),o=this.staged.get(i)??this.shadow.get(i)??this.readField(t,e,n)??0;return this.staged.set(i,s),this._txn.forward.push({kind:"set_field",eid:t,def:e,field:n,value:s}),this._txn.inverse.push({kind:"set_field",eid:t,def:e,field:n,value:o}),this}addComponent(t,e,n){return this._txn.forward.push({kind:"add_component",eid:t,def:e,values:n}),this._txn.inverse.push({kind:"remove_component",eid:t,def:e}),this}removeComponent(t,e,n){return this._txn.forward.push({kind:"remove_component",eid:t,def:e}),this._txn.inverse.push({kind:"add_component",eid:t,def:e,values:n}),this}disable(t){return this._txn.forward.push({kind:"disable",eid:t}),this._txn.inverse.push({kind:"enable",eid:t}),this}enable(t){return this._txn.forward.push({kind:"enable",eid:t}),this._txn.inverse.push({kind:"disable",eid:t}),this}}class u{constructor(t,e){this.queue=t,this.readField=e}undoStack=[];redoStack=[];listeners=[];shadow=new Map;transaction(t){const e=new h(this.readField,this.shadow);return t(e),this.commit(a.get(e))}spawn(t,e){return this.transaction(n=>n.spawn(t,e))}despawn(t,e){return this.transaction(n=>n.despawn(t,e))}setField(t,e,n,s){return this.transaction(i=>i.setField(t,e,n,s))}addComponent(t,e,n){return this.transaction(s=>s.addComponent(t,e,n))}removeComponent(t,e,n){return this.transaction(s=>s.removeComponent(t,e,n))}disable(t){return this.transaction(e=>e.disable(t))}enable(t){return this.transaction(e=>e.enable(t))}undo(){const t=this.undoStack.pop();if(t===void 0)return!1;const e=t.inverse.slice().reverse();for(const n of e)this.queue.push(n);return this.applyShadow(e),this.redoStack.push(t),this.notify(),!0}redo(){const t=this.redoStack.pop();if(t===void 0)return!1;for(const e of t.forward)this.queue.push(e);return this.applyShadow(t.forward),this.undoStack.push(t),this.notify(),!0}clear(){this.undoStack.length=0,this.redoStack.length=0,this.shadow.clear(),this.notify()}depths(){return{undo:this.undoStack.length,redo:this.redoStack.length}}get canUndo(){return this.undoStack.length>0}get canRedo(){return this.redoStack.length>0}onChange(t){return this.listeners.push(t),()=>{const e=this.listeners.indexOf(t);e!==-1&&this.listeners.splice(e,1)}}notify(){for(const t of this.listeners.slice())t()}committedField(t,e,n){return this.readField(t,e,n)}pendingField(t,e,n){const s=d(t,e,n),i=this.shadow.get(s);if(i===void 0)return;const o=this.readField(t,e,n);if(o===i||o===void 0){this.shadow.delete(s);return}return i}commit(t){if(t.forward.length===0)return t;for(const e of t.forward)this.queue.push(e);return this.applyShadow(t.forward),this.undoStack.push(t),this.redoStack.length=0,this.notify(),t}applyShadow(t){for(const e of t)e.kind==="set_field"&&this.shadow.set(d(e.eid,e.def,e.field),e.value)}}function c(r,t,e,n,s){return{get value(){return s!==void 0?s():r.committedField(t,e,n)},set(i){r.setField(t,e,n,i)},get pending(){return r.pendingField(t,e,n)}}}exports.Editor=u;exports.TransactionBuilder=h;exports.fieldHandle=c;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host write seam's EDITOR layer (#701) — layer 2 of #681 / PATTERNS §85.
|
|
3
|
+
*
|
|
4
|
+
* Reified undo/redo + the inspector field-handle, built on the shipped typed
|
|
5
|
+
* `HostCommandQueue` (#698). Application policy, so it lives here in
|
|
6
|
+
* `engine-extensions`, not engine core — and it pulls NO third-party / framework
|
|
7
|
+
* dependency (the field-handle reads through a caller-supplied thunk).
|
|
8
|
+
*
|
|
9
|
+
* - `Editor` — reified `EditorTransaction`s on undo/redo stacks, with
|
|
10
|
+
* transaction grouping; `undo()`/`redo()` enqueue the inverse/forward on the
|
|
11
|
+
* SAME bus, applied at the next schedule head (undo is just another command).
|
|
12
|
+
* - `fieldHandle` — pairs a reactive-channel read with a `setField` command, so
|
|
13
|
+
* an inspector field feels two-way while staying safe and undoable.
|
|
14
|
+
*
|
|
15
|
+
* Reachable as `@oasys/oecs/editor`. Pair it with
|
|
16
|
+
* `@oasys/oecs/reactive-sync`'s `syncFieldsToMap` /
|
|
17
|
+
* `syncSingletonToStruct` for the read channel the field-handle reads through.
|
|
18
|
+
*/
|
|
19
|
+
export { Editor, TransactionBuilder, type EditorTransaction, type FieldReader } from './editor.cjs';
|
|
20
|
+
export { fieldHandle, type FieldHandle } from './field_handle.cjs';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host write seam's EDITOR layer (#701) — layer 2 of #681 / PATTERNS §85.
|
|
3
|
+
*
|
|
4
|
+
* Reified undo/redo + the inspector field-handle, built on the shipped typed
|
|
5
|
+
* `HostCommandQueue` (#698). Application policy, so it lives here in
|
|
6
|
+
* `engine-extensions`, not engine core — and it pulls NO third-party / framework
|
|
7
|
+
* dependency (the field-handle reads through a caller-supplied thunk).
|
|
8
|
+
*
|
|
9
|
+
* - `Editor` — reified `EditorTransaction`s on undo/redo stacks, with
|
|
10
|
+
* transaction grouping; `undo()`/`redo()` enqueue the inverse/forward on the
|
|
11
|
+
* SAME bus, applied at the next schedule head (undo is just another command).
|
|
12
|
+
* - `fieldHandle` — pairs a reactive-channel read with a `setField` command, so
|
|
13
|
+
* an inspector field feels two-way while staying safe and undoable.
|
|
14
|
+
*
|
|
15
|
+
* Reachable as `@oasys/oecs/editor`. Pair it with
|
|
16
|
+
* `@oasys/oecs/reactive-sync`'s `syncFieldsToMap` /
|
|
17
|
+
* `syncSingletonToStruct` for the read channel the field-handle reads through.
|
|
18
|
+
*/
|
|
19
|
+
export { Editor, TransactionBuilder, type EditorTransaction, type FieldReader } from './editor.js';
|
|
20
|
+
export { fieldHandle, type FieldHandle } from './field_handle.js';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/editor/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
function a(r, t, e) {
|
|
2
|
+
return `${r}:${t.id}:${e}`;
|
|
3
|
+
}
|
|
4
|
+
const d = /* @__PURE__ */ new WeakMap();
|
|
5
|
+
class h {
|
|
6
|
+
/** @internal */
|
|
7
|
+
constructor(t, e) {
|
|
8
|
+
this.readField = t, this.shadow = e, d.set(this, { forward: [], inverse: [] });
|
|
9
|
+
}
|
|
10
|
+
/** Values staged by THIS build, layered over the editor's shared shadow. Kept
|
|
11
|
+
* transaction-local so an aborted build (the callback throws before commit)
|
|
12
|
+
* leaves the shared shadow untouched — a phantom staged value would poison
|
|
13
|
+
* `pendingField` and seed the NEXT edit's inverse with a value the world never
|
|
14
|
+
* held. The one merge point into the shared shadow is commit's `applyShadow`. */
|
|
15
|
+
staged = /* @__PURE__ */ new Map();
|
|
16
|
+
get _txn() {
|
|
17
|
+
return d.get(this);
|
|
18
|
+
}
|
|
19
|
+
spawn(t, e) {
|
|
20
|
+
const n = {
|
|
21
|
+
kind: "despawn",
|
|
22
|
+
eid: 0
|
|
23
|
+
};
|
|
24
|
+
return this._txn.inverse.push(n), this._txn.forward.push({
|
|
25
|
+
kind: "spawn",
|
|
26
|
+
components: t,
|
|
27
|
+
onSpawned: (s) => {
|
|
28
|
+
n.eid = s, e?.(s);
|
|
29
|
+
}
|
|
30
|
+
}), this;
|
|
31
|
+
}
|
|
32
|
+
despawn(t, e) {
|
|
33
|
+
const n = { kind: "despawn", eid: t };
|
|
34
|
+
return this._txn.forward.push(n), this._txn.inverse.push({
|
|
35
|
+
kind: "spawn",
|
|
36
|
+
components: e,
|
|
37
|
+
onSpawned: (s) => {
|
|
38
|
+
n.eid = s;
|
|
39
|
+
}
|
|
40
|
+
}), this;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Set `field` of `def` on `eid` to `value`. Inverse: set it back to the value
|
|
44
|
+
* this edit replaced — read from the staged overlay / shadow (so stacked edits,
|
|
45
|
+
* within one build or before a commit, invert correctly) or, failing that, the
|
|
46
|
+
* read channel (`0` if unknown).
|
|
47
|
+
*/
|
|
48
|
+
setField(t, e, n, s) {
|
|
49
|
+
const i = a(t, e, n), o = this.staged.get(i) ?? this.shadow.get(i) ?? this.readField(t, e, n) ?? 0;
|
|
50
|
+
return this.staged.set(i, s), this._txn.forward.push({ kind: "set_field", eid: t, def: e, field: n, value: s }), this._txn.inverse.push({ kind: "set_field", eid: t, def: e, field: n, value: o }), this;
|
|
51
|
+
}
|
|
52
|
+
/** Add `def` (with complete `values`) to `eid`. Inverse: remove it. */
|
|
53
|
+
addComponent(t, e, n) {
|
|
54
|
+
return this._txn.forward.push({ kind: "add_component", eid: t, def: e, values: n }), this._txn.inverse.push({ kind: "remove_component", eid: t, def: e }), this;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Remove `def` from `eid`. Inverse: re-add it from `restore` (the field values
|
|
58
|
+
* to recreate — read them from the channel before removing).
|
|
59
|
+
*/
|
|
60
|
+
removeComponent(t, e, n) {
|
|
61
|
+
return this._txn.forward.push({ kind: "remove_component", eid: t, def: e }), this._txn.inverse.push({
|
|
62
|
+
kind: "add_component",
|
|
63
|
+
eid: t,
|
|
64
|
+
def: e,
|
|
65
|
+
values: n
|
|
66
|
+
}), this;
|
|
67
|
+
}
|
|
68
|
+
/** Disable `eid`. Inverse: enable it. */
|
|
69
|
+
disable(t) {
|
|
70
|
+
return this._txn.forward.push({ kind: "disable", eid: t }), this._txn.inverse.push({ kind: "enable", eid: t }), this;
|
|
71
|
+
}
|
|
72
|
+
/** Enable `eid`. Inverse: disable it. */
|
|
73
|
+
enable(t) {
|
|
74
|
+
return this._txn.forward.push({ kind: "enable", eid: t }), this._txn.inverse.push({ kind: "disable", eid: t }), this;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
class u {
|
|
78
|
+
constructor(t, e) {
|
|
79
|
+
this.queue = t, this.readField = e;
|
|
80
|
+
}
|
|
81
|
+
undoStack = [];
|
|
82
|
+
redoStack = [];
|
|
83
|
+
/** onChange subscribers — see {@link onChange}. */
|
|
84
|
+
listeners = [];
|
|
85
|
+
/** Per-`(entity, component, field)` shadow of edited values, for inverse correctness. */
|
|
86
|
+
shadow = /* @__PURE__ */ new Map();
|
|
87
|
+
/**
|
|
88
|
+
* Group several actions into ONE undo entry. Build them on the passed
|
|
89
|
+
* {@link TransactionBuilder}; the whole group commits (enqueues its forward
|
|
90
|
+
* commands) and lands on the undo stack atomically, clearing the redo stack.
|
|
91
|
+
*/
|
|
92
|
+
transaction(t) {
|
|
93
|
+
const e = new h(this.readField, this.shadow);
|
|
94
|
+
return t(e), this.commit(d.get(e));
|
|
95
|
+
}
|
|
96
|
+
spawn(t, e) {
|
|
97
|
+
return this.transaction((n) => n.spawn(t, e));
|
|
98
|
+
}
|
|
99
|
+
despawn(t, e) {
|
|
100
|
+
return this.transaction((n) => n.despawn(t, e));
|
|
101
|
+
}
|
|
102
|
+
/** Set one field as its own undo entry. */
|
|
103
|
+
setField(t, e, n, s) {
|
|
104
|
+
return this.transaction((i) => i.setField(t, e, n, s));
|
|
105
|
+
}
|
|
106
|
+
/** Add a component as its own undo entry. */
|
|
107
|
+
addComponent(t, e, n) {
|
|
108
|
+
return this.transaction((s) => s.addComponent(t, e, n));
|
|
109
|
+
}
|
|
110
|
+
/** Remove a component as its own undo entry; `restore` re-adds it on undo. */
|
|
111
|
+
removeComponent(t, e, n) {
|
|
112
|
+
return this.transaction((s) => s.removeComponent(t, e, n));
|
|
113
|
+
}
|
|
114
|
+
/** Disable `eid` as its own undo entry. */
|
|
115
|
+
disable(t) {
|
|
116
|
+
return this.transaction((e) => e.disable(t));
|
|
117
|
+
}
|
|
118
|
+
/** Enable `eid` as its own undo entry. */
|
|
119
|
+
enable(t) {
|
|
120
|
+
return this.transaction((e) => e.enable(t));
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Undo the most recent transaction: enqueue its inverse commands (in reverse
|
|
124
|
+
* order — a group unwinds last-action-first) on the bus and move it to the redo
|
|
125
|
+
* stack. Returns `false` if the undo stack is empty.
|
|
126
|
+
*/
|
|
127
|
+
undo() {
|
|
128
|
+
const t = this.undoStack.pop();
|
|
129
|
+
if (t === void 0) return !1;
|
|
130
|
+
const e = t.inverse.slice().reverse();
|
|
131
|
+
for (const n of e) this.queue.push(n);
|
|
132
|
+
return this.applyShadow(e), this.redoStack.push(t), this.notify(), !0;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Redo the most recently undone transaction: re-enqueue its forward commands on
|
|
136
|
+
* the bus and move it back to the undo stack. Returns `false` if the redo stack
|
|
137
|
+
* is empty.
|
|
138
|
+
*/
|
|
139
|
+
redo() {
|
|
140
|
+
const t = this.redoStack.pop();
|
|
141
|
+
if (t === void 0) return !1;
|
|
142
|
+
for (const e of t.forward) this.queue.push(e);
|
|
143
|
+
return this.applyShadow(t.forward), this.undoStack.push(t), this.notify(), !0;
|
|
144
|
+
}
|
|
145
|
+
/** Drop both stacks (e.g. on load). Does not touch the world. */
|
|
146
|
+
clear() {
|
|
147
|
+
this.undoStack.length = 0, this.redoStack.length = 0, this.shadow.clear(), this.notify();
|
|
148
|
+
}
|
|
149
|
+
/** Current stack depths — for an "Undo (3)" / "Redo" affordance. */
|
|
150
|
+
depths() {
|
|
151
|
+
return { undo: this.undoStack.length, redo: this.redoStack.length };
|
|
152
|
+
}
|
|
153
|
+
/** `true` when `undo()` would do something — allocation-free (M10). */
|
|
154
|
+
get canUndo() {
|
|
155
|
+
return this.undoStack.length > 0;
|
|
156
|
+
}
|
|
157
|
+
/** `true` when `redo()` would do something — allocation-free (M10). */
|
|
158
|
+
get canRedo() {
|
|
159
|
+
return this.redoStack.length > 0;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Subscribe to undo/redo-stack changes: fires after every commit, undo,
|
|
163
|
+
* redo, and clear — the push signal an "Undo (3)" affordance needs instead
|
|
164
|
+
* of polling `depths()` per frame (M10). Returns an unsubscribe function.
|
|
165
|
+
* Callbacks run synchronously in subscription order; read `canUndo` /
|
|
166
|
+
* `canRedo` / `depths()` inside.
|
|
167
|
+
*/
|
|
168
|
+
onChange(t) {
|
|
169
|
+
return this.listeners.push(t), () => {
|
|
170
|
+
const e = this.listeners.indexOf(t);
|
|
171
|
+
e !== -1 && this.listeners.splice(e, 1);
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
notify() {
|
|
175
|
+
for (const t of this.listeners.slice()) t();
|
|
176
|
+
}
|
|
177
|
+
/** Read one committed `(entity, component, field)` slot through the reader
|
|
178
|
+
* this editor was constructed with — the default read for `fieldHandle`
|
|
179
|
+
* when no channel thunk is supplied (M11). */
|
|
180
|
+
committedField(t, e, n) {
|
|
181
|
+
return this.readField(t, e, n);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* The pending value the editor believes for a field that the committed read
|
|
185
|
+
* channel has NOT caught up to yet (the shadow), or `undefined` if none. Lets an
|
|
186
|
+
* inspector echo an edit between the `set` and the tick that commits it.
|
|
187
|
+
*
|
|
188
|
+
* Self-resolving: once the read channel reports the shadowed value (the edit
|
|
189
|
+
* landed) — or reports `undefined` (the slot is gone: entity despawned or
|
|
190
|
+
* component removed) — the entry is dropped and this returns `undefined`, so
|
|
191
|
+
* `pending` does not outlive its set→commit window and shadow a later external
|
|
192
|
+
* write, nor a dead slot's lifetime. The one
|
|
193
|
+
* residual: if an external write changes the field to a *different* value within
|
|
194
|
+
* the same window before this is next consulted, `pending` can read stale until
|
|
195
|
+
* the next edit to the slot. `value` (the read channel) is always the source of
|
|
196
|
+
* truth; `pending` is only the optimistic bridge.
|
|
197
|
+
*/
|
|
198
|
+
pendingField(t, e, n) {
|
|
199
|
+
const s = a(t, e, n), i = this.shadow.get(s);
|
|
200
|
+
if (i === void 0) return;
|
|
201
|
+
const o = this.readField(t, e, n);
|
|
202
|
+
if (o === i || o === void 0) {
|
|
203
|
+
this.shadow.delete(s);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
return i;
|
|
207
|
+
}
|
|
208
|
+
/** Enqueue forward commands, record the transaction, clear redo, sync shadow. */
|
|
209
|
+
commit(t) {
|
|
210
|
+
if (t.forward.length === 0) return t;
|
|
211
|
+
for (const e of t.forward) this.queue.push(e);
|
|
212
|
+
return this.applyShadow(t.forward), this.undoStack.push(t), this.redoStack.length = 0, this.notify(), t;
|
|
213
|
+
}
|
|
214
|
+
/** Keep the setField shadow in step with the commands just enqueued. */
|
|
215
|
+
applyShadow(t) {
|
|
216
|
+
for (const e of t)
|
|
217
|
+
e.kind === "set_field" && this.shadow.set(a(e.eid, e.def, e.field), e.value);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function c(r, t, e, n, s) {
|
|
221
|
+
return {
|
|
222
|
+
get value() {
|
|
223
|
+
return s !== void 0 ? s() : r.committedField(t, e, n);
|
|
224
|
+
},
|
|
225
|
+
set(i) {
|
|
226
|
+
r.setField(t, e, n, i);
|
|
227
|
+
},
|
|
228
|
+
get pending() {
|
|
229
|
+
return r.pendingField(t, e, n);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
export {
|
|
234
|
+
u as Editor,
|
|
235
|
+
h as TransactionBuilder,
|
|
236
|
+
c as fieldHandle
|
|
237
|
+
};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { ReactiveArray, ReactiveMap, StructSetters, StructEq } from '../../reactive/index.cjs';
|
|
2
|
+
import { ComponentDef, ComponentSchema, ECS, EntityID, SystemAccessDeclaration } from '../../core/ecs/index.cjs';
|
|
3
|
+
import { shallow } from '../../reactive/shallow.cjs';
|
|
4
|
+
export { shallow };
|
|
5
|
+
/**
|
|
6
|
+
* A read cursor over one entity's single-component state, handed to a single-
|
|
7
|
+
* component `Projection`. `field` is column-backed under "column" grain
|
|
8
|
+
* (sequential), random-access (`getField`) under "entity" grain.
|
|
9
|
+
*
|
|
10
|
+
* Lifetime: the cursor is a reused, mutable singleton valid ONLY during the
|
|
11
|
+
* synchronous `project` call for the current row. Read what you need and return —
|
|
12
|
+
* never capture `row` (or stash its `field` reads keyed off a later closure): the
|
|
13
|
+
* next row/tick mutates it in place, so a captured cursor reads stale data.
|
|
14
|
+
*/
|
|
15
|
+
export interface RowReader<S extends ComponentSchema> {
|
|
16
|
+
/** The current entity (the row being projected). */
|
|
17
|
+
readonly eid: EntityID;
|
|
18
|
+
/** Read a field of the synced component for the current row. */
|
|
19
|
+
field<K extends string & keyof S>(name: K): number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A read cursor over a JOINED entity (it carries every component in the join), for
|
|
23
|
+
* a `JoinProjection`. `field(def, name)` reads any field of any joined component
|
|
24
|
+
* for the current entity (random-access; the join subscribes to all of them so the
|
|
25
|
+
* read can never go stale).
|
|
26
|
+
*
|
|
27
|
+
* Lifetime: like `RowReader`, a reused mutable singleton valid ONLY during the
|
|
28
|
+
* synchronous `project` call — never capture it; the next dispatch mutates it.
|
|
29
|
+
*/
|
|
30
|
+
export interface JoinReader<Schemas extends readonly ComponentSchema[] = readonly ComponentSchema[]> {
|
|
31
|
+
/** The current entity (it has all joined components). */
|
|
32
|
+
readonly eid: EntityID;
|
|
33
|
+
/** Read a field of one joined component for the current entity. `def` is
|
|
34
|
+
* constrained to the join's own component set — reading a def outside the
|
|
35
|
+
* join is the stale-read footgun the module header warns about (its changes
|
|
36
|
+
* aren't subscribed), so it's a compile error. */
|
|
37
|
+
field<S extends Schemas[number], K extends string & keyof S>(def: ComponentDef<S>, name: K): number;
|
|
38
|
+
}
|
|
39
|
+
/** Map one single-component row to the value a UI cell reads. */
|
|
40
|
+
export type Projection<S extends ComponentSchema, V> = (row: RowReader<S>) => V;
|
|
41
|
+
/** Map one joined entity to the value a UI cell reads. */
|
|
42
|
+
export type JoinProjection<V, Schemas extends readonly ComponentSchema[] = readonly ComponentSchema[]> = (row: JoinReader<Schemas>) => V;
|
|
43
|
+
/** Per-component dirty grain. See the module header for the measured crossover. */
|
|
44
|
+
export type SyncGrain = "entity" | "column";
|
|
45
|
+
export interface EcsMapSyncOptions<V> {
|
|
46
|
+
/** Dirty grain (default `"entity"`). Use `"column"` for high-churn components. */
|
|
47
|
+
grain?: SyncGrain;
|
|
48
|
+
/**
|
|
49
|
+
* Value equality for the map's per-key no-op skip (default `Object.is`). Pass
|
|
50
|
+
* `shallow` for object projections, or a content comparator. A fresh object
|
|
51
|
+
* every tick under the default reference eq wakes the row every frame.
|
|
52
|
+
*/
|
|
53
|
+
eq?: (a: V, b: V) => boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Access surface the projection touches, merged over the synced components'
|
|
56
|
+
* `reads`. `DEV` access-checks the observer callbacks exactly like a system.
|
|
57
|
+
*/
|
|
58
|
+
access?: Partial<SystemAccessDeclaration>;
|
|
59
|
+
/**
|
|
60
|
+
* Replay current matches on registration (default `true`), so a bridge attached
|
|
61
|
+
* to an already-populated world seeds the map with present state instead of
|
|
62
|
+
* waking only on the next change. flecs `yieldExisting`.
|
|
63
|
+
*/
|
|
64
|
+
seedExisting?: boolean;
|
|
65
|
+
}
|
|
66
|
+
export interface EcsMapSync<V> {
|
|
67
|
+
/** The live channel: a reader of key `eid` subscribes to that entity alone. */
|
|
68
|
+
readonly map: ReactiveMap<EntityID, V>;
|
|
69
|
+
/** Unregister the observer(s) and stop publishing. Safe to call more than once. */
|
|
70
|
+
dispose(): void;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Sync ONE component's change detection into a `reactiveMap`, keyed by `EntityID`.
|
|
74
|
+
* A value change publishes the changed rows; a spawn inserts a row and a despawn
|
|
75
|
+
* deletes it. Returns the map + a disposer. Drive with `batchedUpdate(world, dt)`.
|
|
76
|
+
*
|
|
77
|
+
* To read more than one component per row, use `syncJoinToMap` — reading a second
|
|
78
|
+
* component here goes stale (its changes aren't subscribed).
|
|
79
|
+
*/
|
|
80
|
+
export declare function syncComponentToMap<S extends ComponentSchema, V>(ecs: ECS, def: ComponentDef<S>, project: Projection<S, V>, opts?: EcsMapSyncOptions<V>): EcsMapSync<V>;
|
|
81
|
+
/**
|
|
82
|
+
* Sugar over `syncComponentToMap`: project a fixed FIELD LIST into a `{ field:
|
|
83
|
+
* value }` snapshot, with an automatic `shallow` eq so an unchanged row wakes
|
|
84
|
+
* nobody. The declarative-field-list model from WatermelonDB `observeWithColumns` /
|
|
85
|
+
* TanStack `select` — the common "mirror these fields" case without hand-writing
|
|
86
|
+
* the projection + comparator.
|
|
87
|
+
*
|
|
88
|
+
* Allocation note: this builds a fresh object per dirty row and `shallow` does two
|
|
89
|
+
* `Object.keys` per compare — fine for low-churn. For a HIGH-churn component (the
|
|
90
|
+
* case you'd pick `grain:"column"` for), prefer `syncComponentToMap` with a scalar
|
|
91
|
+
* or hand-written-`eq` projection, so the hot path doesn't allocate exactly where
|
|
92
|
+
* the column grain is meant to keep it cheap.
|
|
93
|
+
*/
|
|
94
|
+
export declare function syncFieldsToMap<S extends ComponentSchema, const F extends readonly (string & keyof S)[]>(ecs: ECS, def: ComponentDef<S>, fields: F, opts?: Omit<EcsMapSyncOptions<{
|
|
95
|
+
[K in F[number]]: number;
|
|
96
|
+
}>, "eq">): EcsMapSync<{
|
|
97
|
+
[K in F[number]]: number;
|
|
98
|
+
}>;
|
|
99
|
+
/**
|
|
100
|
+
* Sync a multi-component JOIN into a `reactiveMap`. An entity is a member iff it
|
|
101
|
+
* has EVERY component in `defs`; the projection reads any of them via
|
|
102
|
+
* `row.field(def, name)`. Change detection subscribes to ALL joined components, so
|
|
103
|
+
* a write to ANY of them republishes the row — the join can never go stale (the
|
|
104
|
+
* bug a single-component sync + manual secondary read would have). Spawns/removes
|
|
105
|
+
* of any joined component re-evaluate membership.
|
|
106
|
+
*
|
|
107
|
+
* Entity grain only: a join spans archetypes, so there is no single column to
|
|
108
|
+
* sweep. Drive with `batchedUpdate(world, dt)`.
|
|
109
|
+
*/
|
|
110
|
+
export declare function syncJoinToMap<Schemas extends readonly ComponentSchema[], V>(ecs: ECS, defs: readonly [...{
|
|
111
|
+
[I in keyof Schemas]: ComponentDef<Schemas[I]>;
|
|
112
|
+
}], project: JoinProjection<V, Schemas>, opts?: Omit<EcsMapSyncOptions<V>, "grain">): EcsMapSync<V>;
|
|
113
|
+
export interface SingletonStructSync<V extends object> {
|
|
114
|
+
/** The live per-field channel: reading `struct.field` in a tracked scope
|
|
115
|
+
* subscribes to that field alone (pair with `fromKernelStruct` to render). */
|
|
116
|
+
readonly struct: V;
|
|
117
|
+
/** Unregister the observer and stop publishing. Safe to call more than once. */
|
|
118
|
+
dispose(): void;
|
|
119
|
+
}
|
|
120
|
+
export interface SingletonSyncOptions<V extends object = Record<string, number>> {
|
|
121
|
+
/**
|
|
122
|
+
* Access surface the publish touches, merged over the synced def's read.
|
|
123
|
+
* `DEV` access-checks the observer callbacks exactly like a system.
|
|
124
|
+
*/
|
|
125
|
+
access?: Partial<SystemAccessDeclaration>;
|
|
126
|
+
/** Replay current state on registration (default `true`). flecs `yieldExisting`. */
|
|
127
|
+
seedExisting?: boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Drive a PRE-CREATED `reactiveStruct` (its `[proxy, set]` pair) instead of
|
|
130
|
+
* creating a fresh one. Lets the consumer keep the struct at module scope as a
|
|
131
|
+
* stable "channel" with initial values present before the sync attaches (the
|
|
132
|
+
* client UI seam: panels import the eager proxy; the sync, set up at world build,
|
|
133
|
+
* republishes into it via the observer). The seed (`yieldExisting`) overwrites
|
|
134
|
+
* the eager initials with the entity's current values on registration.
|
|
135
|
+
*/
|
|
136
|
+
into?: readonly [V, StructSetters<V>];
|
|
137
|
+
/** Per-field equality overrides for the created struct (parity with
|
|
138
|
+
* `SingletonArraySyncOptions.eq`). Ignored when `into` supplies a
|
|
139
|
+
* pre-created struct — that struct already carries its own `eq`. */
|
|
140
|
+
eq?: StructEq<V>;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Sync ONE singleton entity's single-component state into a `reactiveStruct`,
|
|
144
|
+
* keyless — the singleton/resource shape (ADR-0024). This is how heterogeneous
|
|
145
|
+
* ephemeral UI state (net status + latency, FPS/mem, wave timer, hovered hex) joins
|
|
146
|
+
* the same reactive view as per-entity components: model it as components on a
|
|
147
|
+
* reserved singleton entity (the flecs / Unity-DOTS "singleton-as-entity" model)
|
|
148
|
+
* and read it through per-field channels — NOT a separate reactive-resource
|
|
149
|
+
* subsystem. Resources stay non-reactive internal singletons.
|
|
150
|
+
*
|
|
151
|
+
* It reuses the entity-grain ADR-0013 component observer verbatim, filtered to the
|
|
152
|
+
* one target eid: an `onSet` (or seed `onAdd`) republishes the entity's field values
|
|
153
|
+
* into the struct via per-field setters. The per-field `Object.is` eq means an
|
|
154
|
+
* unchanged field writes nothing — "equal write → 0 renders" — and per-field signals
|
|
155
|
+
* give "1-of-N FIELD → 1 re-render"; drive with `batchedUpdate` for "one tick → one
|
|
156
|
+
* commit". Because the component change-detection fires on `ctx.setField`, the
|
|
157
|
+
* in-place write pattern that defeats a `setResource`-keyed resource observer is
|
|
158
|
+
* handled for free.
|
|
159
|
+
*
|
|
160
|
+
* `fields` is explicit: a `ComponentDef` is a branded number at runtime (its schema
|
|
161
|
+
* is a phantom type), so the field names must be passed — same contract as
|
|
162
|
+
* `syncFieldsToMap`. Project a subset to channel only what the UI reads.
|
|
163
|
+
*
|
|
164
|
+
* A `reactiveStruct` has a fixed field set and no `delete`, so the map adapter's
|
|
165
|
+
* delete-on-disable (#677 / ADR-0023) has no struct analog: `onRemove`/`onDisable`
|
|
166
|
+
* **reset the fields to the channel's declared initial values** (`onSet` skips
|
|
167
|
+
* disabled entities), `onEnable` republishes. The defaults are the channel's own
|
|
168
|
+
* initials — the eager `into` struct's declared values (e.g. `NetStats.latency = -1`),
|
|
169
|
+
* or the zeros of a freshly-created one — captured (untracked) at registration, NOT a
|
|
170
|
+
* blind 0. A singleton is rarely despawned; this keeps the channel well-defined if it is.
|
|
171
|
+
*/
|
|
172
|
+
export declare function syncSingletonToStruct<S extends ComponentSchema, const F extends readonly (string & keyof S)[]>(ecs: ECS, def: ComponentDef<S>, eid: EntityID, fields: F, opts?: SingletonSyncOptions<{
|
|
173
|
+
[K in F[number]]: number;
|
|
174
|
+
}>): SingletonStructSync<{
|
|
175
|
+
[K in F[number]]: number;
|
|
176
|
+
}>;
|
|
177
|
+
export interface SingletonArraySync<T> {
|
|
178
|
+
/** The live ordered channel: a reader of slot `i` subscribes to that slot alone. */
|
|
179
|
+
readonly array: ReactiveArray<T>;
|
|
180
|
+
/** Unregister the observer and stop publishing. Safe to call more than once. */
|
|
181
|
+
dispose(): void;
|
|
182
|
+
}
|
|
183
|
+
export interface SingletonArraySyncOptions<T> {
|
|
184
|
+
access?: Partial<SystemAccessDeclaration>;
|
|
185
|
+
seedExisting?: boolean;
|
|
186
|
+
/** Drive a PRE-CREATED `reactiveArray` (the module-scope channel) instead of a fresh one. */
|
|
187
|
+
into?: ReactiveArray<T>;
|
|
188
|
+
/** Per-slot equality for the array's no-op skip (default `Object.is`). */
|
|
189
|
+
eq?: (a: T, b: T) => boolean;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Sync ONE singleton entity's component into a `reactiveArray`, one slot per field
|
|
193
|
+
* in `fields` order (#685 / ADR-0024) — the ORDERED sibling of `syncSingletonToStruct`,
|
|
194
|
+
* for positional UI state (the army slots). On every change to the component it
|
|
195
|
+
* `reconcile`s the array from the field values: a slot whose value is unchanged keeps
|
|
196
|
+
* its reference (structural sharing), only changed slots wake. `onRemove`/`onDisable`
|
|
197
|
+
* reset the slots to the channel's DECLARED initial slots (a reactiveArray has no row
|
|
198
|
+
* delete) — captured (untracked) at registration, so the army channel resets to its
|
|
199
|
+
* empty sentinel (`EMPTY_SLOT`), NOT a blind 0 that would read as unit type 0.
|
|
200
|
+
*
|
|
201
|
+
* `fields` is explicit (a `ComponentDef` is a branded number at runtime). Pair with
|
|
202
|
+
* `@oasys/oecs/solid`'s `fromKernelArray` + a Solid `<Index>`.
|
|
203
|
+
*/
|
|
204
|
+
export declare function syncSingletonToArray<S extends ComponentSchema>(ecs: ECS, def: ComponentDef<S>, eid: EntityID, fields: readonly (string & keyof S)[], opts?: SingletonArraySyncOptions<number>): SingletonArraySync<number>;
|
|
205
|
+
/**
|
|
206
|
+
* Advance the world one tick with every bridge publish coalesced into a single UI
|
|
207
|
+
* flush. onAdd/onRemove fire mid-tick at flush boundaries and onSet fires at the
|
|
208
|
+
* tick tail; wrapping the whole update in `batch` defers the effect flush until the
|
|
209
|
+
* tick completes, so a frame that touched K entities (across any number of syncs on
|
|
210
|
+
* this world) wakes its readers once, not once per observer dispatch point.
|
|
211
|
+
* Equivalent to `batch(() => ecs.update(dt))`.
|
|
212
|
+
*/
|
|
213
|
+
export declare function batchedUpdate(ecs: ECS, dt: number): void;
|
|
214
|
+
//# sourceMappingURL=ecs_sync.d.ts.map
|