@oasys/oecs 0.5.4 → 0.6.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 +1223 -266
- package/README.md +217 -112
- package/dist/core/ecs/access_check.d.cts +29 -29
- package/dist/core/ecs/access_check.d.ts +29 -29
- package/dist/core/ecs/access_check.d.ts.map +1 -1
- package/dist/core/ecs/archetype.d.cts +217 -209
- package/dist/core/ecs/archetype.d.ts +217 -209
- package/dist/core/ecs/archetype.d.ts.map +1 -1
- package/dist/core/ecs/archetype_closure.d.cts +23 -0
- package/dist/core/ecs/archetype_closure.d.ts +23 -0
- package/dist/core/ecs/archetype_closure.d.ts.map +1 -0
- package/dist/core/ecs/archetype_graph.d.cts +33 -33
- package/dist/core/ecs/archetype_graph.d.ts +33 -33
- package/dist/core/ecs/archetype_graph.d.ts.map +1 -1
- package/dist/core/ecs/archetype_types.d.cts +55 -0
- package/dist/core/ecs/archetype_types.d.ts +55 -0
- package/dist/core/ecs/archetype_types.d.ts.map +1 -0
- package/dist/core/ecs/change_feed.d.cts +53 -0
- package/dist/core/ecs/change_feed.d.ts +53 -0
- package/dist/core/ecs/change_feed.d.ts.map +1 -0
- package/dist/core/ecs/changed_query.d.cts +36 -0
- package/dist/core/ecs/changed_query.d.ts +36 -0
- package/dist/core/ecs/changed_query.d.ts.map +1 -0
- package/dist/core/ecs/chunk_columns.d.cts +49 -0
- package/dist/core/ecs/chunk_columns.d.ts +49 -0
- package/dist/core/ecs/chunk_columns.d.ts.map +1 -0
- package/dist/core/ecs/command_log.d.cts +26 -26
- package/dist/core/ecs/command_log.d.ts +26 -26
- package/dist/core/ecs/command_log.d.ts.map +1 -1
- package/dist/core/ecs/component.d.cts +43 -42
- package/dist/core/ecs/component.d.ts +43 -42
- package/dist/core/ecs/component.d.ts.map +1 -1
- package/dist/core/ecs/component_registry.d.cts +53 -0
- package/dist/core/ecs/component_registry.d.ts +53 -0
- package/dist/core/ecs/component_registry.d.ts.map +1 -0
- package/dist/core/ecs/compute_backend.d.cts +18 -7
- package/dist/core/ecs/compute_backend.d.ts +18 -7
- package/dist/core/ecs/compute_backend.d.ts.map +1 -1
- package/dist/core/ecs/deferred_commands.d.cts +15 -14
- package/dist/core/ecs/deferred_commands.d.ts +15 -14
- package/dist/core/ecs/deferred_commands.d.ts.map +1 -1
- package/dist/core/ecs/dispatch_trace.d.cts +32 -31
- package/dist/core/ecs/dispatch_trace.d.ts +32 -31
- package/dist/core/ecs/dispatch_trace.d.ts.map +1 -1
- package/dist/core/ecs/ecs.d.cts +289 -270
- package/dist/core/ecs/ecs.d.ts +289 -270
- package/dist/core/ecs/ecs.d.ts.map +1 -1
- package/dist/core/ecs/ecs_memory.d.cts +134 -136
- package/dist/core/ecs/ecs_memory.d.ts +134 -136
- package/dist/core/ecs/ecs_memory.d.ts.map +1 -1
- package/dist/core/ecs/ecs_options.d.cts +89 -0
- package/dist/core/ecs/ecs_options.d.ts +89 -0
- package/dist/core/ecs/ecs_options.d.ts.map +1 -0
- package/dist/core/ecs/entity.d.cts +4 -4
- package/dist/core/ecs/entity.d.ts +4 -4
- package/dist/core/ecs/entity_allocator.d.cts +20 -18
- package/dist/core/ecs/entity_allocator.d.ts +20 -18
- package/dist/core/ecs/entity_allocator.d.ts.map +1 -1
- package/dist/core/ecs/event.d.cts +36 -22
- package/dist/core/ecs/event.d.ts +36 -22
- package/dist/core/ecs/event.d.ts.map +1 -1
- package/dist/core/ecs/facades.d.cts +12 -126
- package/dist/core/ecs/facades.d.ts +12 -126
- package/dist/core/ecs/facades.d.ts.map +1 -1
- package/dist/core/ecs/frame_stepper.d.cts +12 -12
- package/dist/core/ecs/frame_stepper.d.ts +12 -12
- package/dist/core/ecs/frame_stepper.d.ts.map +1 -1
- package/dist/core/ecs/frame_trace.d.cts +32 -32
- package/dist/core/ecs/frame_trace.d.ts +32 -32
- package/dist/core/ecs/frame_trace.d.ts.map +1 -1
- package/dist/core/ecs/host_commands.d.cts +103 -85
- package/dist/core/ecs/host_commands.d.ts +103 -85
- package/dist/core/ecs/host_commands.d.ts.map +1 -1
- package/dist/core/ecs/index.d.cts +21 -11
- package/dist/core/ecs/index.d.ts +21 -11
- package/dist/core/ecs/index.d.ts.map +1 -1
- package/dist/core/ecs/observer.d.cts +39 -120
- package/dist/core/ecs/observer.d.ts +39 -120
- package/dist/core/ecs/observer.d.ts.map +1 -1
- package/dist/core/ecs/phase.d.cts +79 -0
- package/dist/core/ecs/phase.d.ts +79 -0
- package/dist/core/ecs/phase.d.ts.map +1 -0
- package/dist/core/ecs/plugin.d.cts +125 -0
- package/dist/core/ecs/plugin.d.ts +125 -0
- package/dist/core/ecs/plugin.d.ts.map +1 -0
- package/dist/core/ecs/plugin_slots.d.cts +26 -0
- package/dist/core/ecs/plugin_slots.d.ts +26 -0
- package/dist/core/ecs/plugin_slots.d.ts.map +1 -0
- package/dist/core/ecs/query.d.cts +208 -578
- package/dist/core/ecs/query.d.ts +208 -578
- package/dist/core/ecs/query.d.ts.map +1 -1
- package/dist/core/ecs/query_cache.d.cts +130 -0
- package/dist/core/ecs/query_cache.d.ts +130 -0
- package/dist/core/ecs/query_cache.d.ts.map +1 -0
- package/dist/core/ecs/query_registry.d.cts +47 -0
- package/dist/core/ecs/query_registry.d.ts +47 -0
- package/dist/core/ecs/query_registry.d.ts.map +1 -0
- package/dist/core/ecs/query_terms.d.cts +126 -0
- package/dist/core/ecs/query_terms.d.ts +126 -0
- package/dist/core/ecs/query_terms.d.ts.map +1 -0
- package/dist/core/ecs/ref.d.cts +100 -39
- package/dist/core/ecs/ref.d.ts +100 -39
- package/dist/core/ecs/ref.d.ts.map +1 -1
- package/dist/core/ecs/relation.d.cts +101 -182
- package/dist/core/ecs/relation.d.ts +101 -182
- package/dist/core/ecs/relation.d.ts.map +1 -1
- package/dist/core/ecs/resource.d.cts +13 -13
- package/dist/core/ecs/resource.d.ts +13 -13
- package/dist/core/ecs/resource_registry.d.cts +5 -5
- package/dist/core/ecs/resource_registry.d.ts +5 -5
- package/dist/core/ecs/resource_registry.d.ts.map +1 -1
- package/dist/core/ecs/row_kinds.d.cts +24 -0
- package/dist/core/ecs/row_kinds.d.ts +24 -0
- package/dist/core/ecs/row_kinds.d.ts.map +1 -0
- package/dist/core/ecs/run_condition.d.cts +23 -23
- package/dist/core/ecs/run_condition.d.ts +23 -23
- package/dist/core/ecs/run_condition.d.ts.map +1 -1
- package/dist/core/ecs/schedule.d.cts +91 -120
- package/dist/core/ecs/schedule.d.ts +91 -120
- package/dist/core/ecs/schedule.d.ts.map +1 -1
- package/dist/core/ecs/schedule_plan.d.cts +33 -0
- package/dist/core/ecs/schedule_plan.d.ts +33 -0
- package/dist/core/ecs/schedule_plan.d.ts.map +1 -0
- package/dist/core/ecs/snapshot.d.cts +77 -0
- package/dist/core/ecs/snapshot.d.ts +77 -0
- package/dist/core/ecs/snapshot.d.ts.map +1 -0
- package/dist/core/ecs/snapshot_mount.d.cts +42 -0
- package/dist/core/ecs/snapshot_mount.d.ts +42 -0
- package/dist/core/ecs/snapshot_mount.d.ts.map +1 -0
- package/dist/core/ecs/sparse_store.d.cts +108 -51
- package/dist/core/ecs/sparse_store.d.ts +108 -51
- package/dist/core/ecs/sparse_store.d.ts.map +1 -1
- package/dist/core/ecs/store.d.cts +527 -473
- package/dist/core/ecs/store.d.ts +527 -473
- package/dist/core/ecs/store.d.ts.map +1 -1
- package/dist/core/ecs/store_layout_listener.d.cts +6 -6
- package/dist/core/ecs/store_layout_listener.d.ts +6 -6
- package/dist/core/ecs/store_types.d.cts +122 -0
- package/dist/core/ecs/store_types.d.ts +122 -0
- package/dist/core/ecs/store_types.d.ts.map +1 -0
- package/dist/core/ecs/system.d.cts +146 -61
- package/dist/core/ecs/system.d.ts +146 -61
- package/dist/core/ecs/system.d.ts.map +1 -1
- package/dist/core/ecs/system_context.d.cts +296 -0
- package/dist/core/ecs/system_context.d.ts +296 -0
- package/dist/core/ecs/system_context.d.ts.map +1 -0
- package/dist/core/ecs/system_set.d.cts +48 -0
- package/dist/core/ecs/system_set.d.ts +48 -0
- package/dist/core/ecs/system_set.d.ts.map +1 -0
- package/dist/core/ecs/utils/arrays.d.cts +15 -1
- package/dist/core/ecs/utils/arrays.d.ts +15 -1
- package/dist/core/ecs/utils/arrays.d.ts.map +1 -1
- package/dist/core/ecs/utils/error.d.cts +82 -6
- package/dist/core/ecs/utils/error.d.ts +82 -6
- package/dist/core/ecs/utils/error.d.ts.map +1 -1
- package/dist/core/ecs/utils/plugin_error.d.cts +10 -0
- package/dist/core/ecs/utils/plugin_error.d.ts +10 -0
- package/dist/core/ecs/utils/plugin_error.d.ts.map +1 -0
- package/dist/core/restore_errors.d.cts +30 -0
- package/dist/core/restore_errors.d.ts +30 -0
- package/dist/core/restore_errors.d.ts.map +1 -0
- package/dist/core/store/action_ring.d.cts +44 -44
- package/dist/core/store/action_ring.d.ts +44 -44
- package/dist/core/store/action_ring.d.ts.map +1 -1
- package/dist/core/store/allocator.d.cts +149 -95
- package/dist/core/store/allocator.d.ts +149 -95
- package/dist/core/store/allocator.d.ts.map +1 -1
- package/dist/core/store/buffer_backed_column.d.cts +17 -17
- package/dist/core/store/buffer_backed_column.d.ts +17 -17
- package/dist/core/store/buffer_backed_column.d.ts.map +1 -1
- package/dist/core/store/column_store.d.cts +124 -86
- package/dist/core/store/column_store.d.ts +124 -86
- package/dist/core/store/column_store.d.ts.map +1 -1
- package/dist/core/store/command_dispatch.d.cts +14 -15
- package/dist/core/store/command_dispatch.d.ts +14 -15
- package/dist/core/store/command_dispatch.d.ts.map +1 -1
- package/dist/core/store/command_ring.d.cts +36 -39
- package/dist/core/store/command_ring.d.ts +36 -39
- package/dist/core/store/command_ring.d.ts.map +1 -1
- package/dist/core/store/descriptor.d.cts +34 -17
- package/dist/core/store/descriptor.d.ts +34 -17
- package/dist/core/store/descriptor.d.ts.map +1 -1
- package/dist/core/store/entity_index.d.cts +34 -35
- package/dist/core/store/entity_index.d.ts +34 -35
- package/dist/core/store/entity_index.d.ts.map +1 -1
- package/dist/core/store/event_ring.d.cts +36 -38
- package/dist/core/store/event_ring.d.ts +36 -38
- package/dist/core/store/event_ring.d.ts.map +1 -1
- package/dist/core/store/extend.d.cts +13 -7
- package/dist/core/store/extend.d.ts +13 -7
- package/dist/core/store/extend.d.ts.map +1 -1
- package/dist/core/store/grow.d.cts +2 -2
- package/dist/core/store/grow.d.ts +2 -2
- package/dist/core/store/grow.d.ts.map +1 -1
- package/dist/core/store/header.d.cts +31 -27
- package/dist/core/store/header.d.ts +31 -27
- package/dist/core/store/header.d.ts.map +1 -1
- package/dist/core/store/index.d.cts +10 -10
- package/dist/core/store/index.d.ts +10 -10
- package/dist/core/store/index.d.ts.map +1 -1
- package/dist/core/store/layout_ops.d.cts +71 -62
- package/dist/core/store/layout_ops.d.ts +71 -62
- package/dist/core/store/layout_ops.d.ts.map +1 -1
- package/dist/core/store/region_table.d.cts +28 -21
- package/dist/core/store/region_table.d.ts +28 -21
- package/dist/core/store/region_table.d.ts.map +1 -1
- package/dist/core/store/snapshot.d.cts +31 -16
- package/dist/core/store/snapshot.d.ts +31 -16
- package/dist/core/store/snapshot.d.ts.map +1 -1
- package/dist/core/store/state_hash.d.cts +12 -12
- package/dist/core/store/state_hash.d.ts +12 -12
- package/dist/core/store/state_hash.d.ts.map +1 -1
- package/dist/core/store/store_regions.d.cts +10 -10
- package/dist/core/store/store_regions.d.ts +10 -10
- package/dist/core/store/store_regions.d.ts.map +1 -1
- package/dist/core/store/vendored_abi/abi.d.cts +27 -2
- package/dist/core/store/vendored_abi/abi.d.ts +27 -2
- package/dist/core/store/vendored_abi/abi.d.ts.map +1 -1
- package/dist/host_commands-B2KMx8O2.cjs +1 -0
- package/dist/host_commands-ClVPvhSa.cjs +2 -0
- package/dist/host_commands-CwxVQS1z.js +1524 -0
- package/dist/host_commands-nJvTy88E.js +1667 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +15 -10
- package/dist/index.d.ts +15 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.development.cjs +1 -1
- package/dist/index.development.js +5804 -5203
- package/dist/index.js +5323 -4764
- package/dist/internal.cjs +2 -2
- package/dist/internal.d.cts +5 -2
- package/dist/internal.d.ts +5 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.development.cjs +1 -1
- package/dist/internal.development.js +70 -20
- package/dist/internal.js +138 -83
- package/dist/plugins/abi-D3V-QUSf.cjs +1 -0
- package/dist/plugins/abi-NP8pNxpd.js +42 -0
- package/dist/plugins/arrays-Dr_1hCjL.js +28 -0
- package/dist/plugins/arrays-Dt-Joc4i.cjs +1 -0
- package/dist/plugins/assertions-gtDVfbnQ.js +6 -0
- package/dist/plugins/assertions-z5GQd_bB.cjs +1 -0
- package/dist/{extensions → plugins}/editor/editor.d.cts +54 -54
- package/dist/{extensions → plugins}/editor/editor.d.ts +54 -54
- package/dist/plugins/editor/editor.d.ts.map +1 -0
- package/dist/{extensions → plugins}/editor/field_handle.d.cts +12 -12
- package/dist/{extensions → plugins}/editor/field_handle.d.ts +12 -12
- package/dist/plugins/editor/field_handle.d.ts.map +1 -0
- package/dist/plugins/editor/index.d.cts +22 -0
- package/dist/plugins/editor/index.d.ts +22 -0
- package/dist/plugins/editor/index.d.ts.map +1 -0
- package/dist/plugins/editor.cjs +1 -0
- package/dist/plugins/editor.d.cts +1 -0
- package/dist/plugins/editor.d.ts +1 -0
- package/dist/plugins/editor.development.cjs +1 -0
- package/dist/{extensions/editor/index.development.js → plugins/editor.development.js} +81 -64
- package/dist/{extensions/editor/index.js → plugins/editor.js} +81 -64
- package/dist/plugins/events/event_channel.d.cts +13 -0
- package/dist/plugins/events/event_channel.d.ts +13 -0
- package/dist/plugins/events/event_channel.d.ts.map +1 -0
- package/dist/plugins/events/event_registry.d.cts +22 -0
- package/dist/plugins/events/event_registry.d.ts +22 -0
- package/dist/plugins/events/event_registry.d.ts.map +1 -0
- package/dist/plugins/events/facade.d.cts +26 -0
- package/dist/plugins/events/facade.d.ts +26 -0
- package/dist/plugins/events/facade.d.ts.map +1 -0
- package/dist/plugins/events/index.d.cts +10 -0
- package/dist/plugins/events/index.d.ts +10 -0
- package/dist/plugins/events/index.d.ts.map +1 -0
- package/dist/plugins/events.cjs +1 -0
- package/dist/plugins/events.d.cts +1 -0
- package/dist/plugins/events.d.ts +1 -0
- package/dist/plugins/events.development.cjs +1 -0
- package/dist/plugins/events.development.js +174 -0
- package/dist/plugins/events.js +159 -0
- package/dist/plugins/observers/index.d.cts +23 -0
- package/dist/plugins/observers/index.d.ts +23 -0
- package/dist/plugins/observers/index.d.ts.map +1 -0
- package/dist/plugins/observers/observer_registry.d.cts +101 -0
- package/dist/plugins/observers/observer_registry.d.ts +101 -0
- package/dist/plugins/observers/observer_registry.d.ts.map +1 -0
- package/dist/plugins/observers.cjs +1 -0
- package/dist/plugins/observers.d.cts +1 -0
- package/dist/plugins/observers.d.ts +1 -0
- package/dist/plugins/observers.development.cjs +1 -0
- package/dist/plugins/observers.development.js +431 -0
- package/dist/plugins/observers.js +403 -0
- package/dist/plugins/relation_store-BsoegrZh.js +313 -0
- package/dist/plugins/relation_store-DQKSnxsm.cjs +1 -0
- package/dist/plugins/relation_store-RBhpcE28.cjs +1 -0
- package/dist/plugins/relation_store-RqW5Snx6.js +328 -0
- package/dist/plugins/relations/builtin_relations.d.cts +48 -0
- package/dist/plugins/relations/builtin_relations.d.ts +48 -0
- package/dist/plugins/relations/builtin_relations.d.ts.map +1 -0
- package/dist/plugins/relations/facade.d.cts +73 -0
- package/dist/plugins/relations/facade.d.ts +73 -0
- package/dist/plugins/relations/facade.d.ts.map +1 -0
- package/dist/plugins/relations/index.d.cts +11 -0
- package/dist/plugins/relations/index.d.ts +11 -0
- package/dist/plugins/relations/index.d.ts.map +1 -0
- package/dist/{core/ecs → plugins/relations}/relation_service.d.cts +85 -97
- package/dist/{core/ecs → plugins/relations}/relation_service.d.ts +85 -97
- package/dist/plugins/relations/relation_service.d.ts.map +1 -0
- package/dist/plugins/relations/relation_store.d.cts +177 -0
- package/dist/plugins/relations/relation_store.d.ts +177 -0
- package/dist/plugins/relations/relation_store.d.ts.map +1 -0
- package/dist/plugins/relations.cjs +1 -0
- package/dist/plugins/relations.d.cts +1 -0
- package/dist/plugins/relations.d.ts +1 -0
- package/dist/plugins/relations.development.cjs +1 -0
- package/dist/plugins/relations.development.js +603 -0
- package/dist/plugins/relations.js +553 -0
- package/dist/plugins/snapshots/index.d.cts +33 -0
- package/dist/plugins/snapshots/index.d.ts +33 -0
- package/dist/plugins/snapshots/index.d.ts.map +1 -0
- package/dist/plugins/snapshots/resume.d.cts +57 -0
- package/dist/plugins/snapshots/resume.d.ts +57 -0
- package/dist/plugins/snapshots/resume.d.ts.map +1 -0
- package/dist/plugins/snapshots/snapshot_service.d.cts +59 -0
- package/dist/plugins/snapshots/snapshot_service.d.ts +59 -0
- package/dist/plugins/snapshots/snapshot_service.d.ts.map +1 -0
- package/dist/plugins/snapshots.cjs +1 -0
- package/dist/plugins/snapshots.d.cts +1 -0
- package/dist/plugins/snapshots.d.ts +1 -0
- package/dist/plugins/snapshots.development.cjs +1 -0
- package/dist/plugins/snapshots.development.js +737 -0
- package/dist/plugins/snapshots.js +737 -0
- package/dist/plugins/solid/index.d.cts +8 -0
- package/dist/plugins/solid/index.d.ts +8 -0
- package/dist/plugins/solid/index.d.ts.map +1 -0
- package/dist/plugins/solid/solid.d.cts +97 -0
- package/dist/plugins/solid/solid.d.ts +97 -0
- package/dist/plugins/solid/solid.d.ts.map +1 -0
- package/dist/plugins/solid.cjs +1 -0
- package/dist/plugins/solid.d.cts +1 -0
- package/dist/plugins/solid.d.ts +1 -0
- package/dist/plugins/solid.development.cjs +1 -0
- package/dist/plugins/solid.development.js +319 -0
- package/dist/plugins/solid.js +319 -0
- package/dist/plugins/workers/index.d.cts +75 -0
- package/dist/plugins/workers/index.d.ts +75 -0
- package/dist/plugins/workers/index.d.ts.map +1 -0
- package/dist/plugins/workers/node_threads.d.cts +25 -0
- package/dist/plugins/workers/node_threads.d.ts +25 -0
- package/dist/plugins/workers/node_threads.d.ts.map +1 -0
- package/dist/plugins/workers/plan.d.cts +61 -0
- package/dist/plugins/workers/plan.d.ts +61 -0
- package/dist/plugins/workers/plan.d.ts.map +1 -0
- package/dist/plugins/workers/pool.d.cts +144 -0
- package/dist/plugins/workers/pool.d.ts +144 -0
- package/dist/plugins/workers/pool.d.ts.map +1 -0
- package/dist/plugins/workers/protocol.d.cts +112 -0
- package/dist/plugins/workers/protocol.d.ts +112 -0
- package/dist/plugins/workers/protocol.d.ts.map +1 -0
- package/dist/plugins/workers/worker_bind.d.cts +64 -0
- package/dist/plugins/workers/worker_bind.d.ts +64 -0
- package/dist/plugins/workers/worker_bind.d.ts.map +1 -0
- package/dist/plugins/workers/worker_loop.d.cts +14 -0
- package/dist/plugins/workers/worker_loop.d.ts +14 -0
- package/dist/plugins/workers/worker_loop.d.ts.map +1 -0
- package/dist/plugins/workers.cjs +1 -0
- package/dist/plugins/workers.d.cts +1 -0
- package/dist/plugins/workers.d.ts +1 -0
- package/dist/plugins/workers.development.cjs +1 -0
- package/dist/plugins/workers.development.js +596 -0
- package/dist/plugins/workers.js +474 -0
- package/dist/primitives.cjs +1 -1
- package/dist/primitives.d.cts +4 -4
- package/dist/primitives.d.ts +4 -4
- package/dist/primitives.development.cjs +1 -1
- package/dist/primitives.development.js +66 -22
- package/dist/primitives.js +66 -22
- package/dist/shared-BKl12xF1.js +132 -0
- package/dist/shared-Dk-pACZT.cjs +1 -0
- package/dist/shared.cjs +1 -1
- package/dist/shared.d.cts +7 -7
- package/dist/shared.d.ts +7 -7
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.development.cjs +1 -1
- package/dist/shared.development.js +4 -3
- package/dist/shared.js +4 -3
- package/dist/topological_sort-Cc_yXqPT.js +346 -0
- package/dist/topological_sort-vp1imU6D.cjs +1 -0
- package/dist/type_primitives/assertions.d.cts +12 -16
- package/dist/type_primitives/assertions.d.ts +12 -16
- package/dist/type_primitives/assertions.d.ts.map +1 -1
- package/dist/type_primitives/binary_heap/binary_heap.d.cts +2 -6
- package/dist/type_primitives/binary_heap/binary_heap.d.ts +2 -6
- package/dist/type_primitives/binary_heap/binary_heap.d.ts.map +1 -1
- package/dist/type_primitives/bitset/bitset.d.cts +7 -11
- package/dist/type_primitives/bitset/bitset.d.ts +7 -11
- package/dist/type_primitives/bitset/bitset.d.ts.map +1 -1
- package/dist/type_primitives/brand.d.cts +2 -7
- package/dist/type_primitives/brand.d.ts +2 -7
- package/dist/type_primitives/brand.d.ts.map +1 -1
- package/dist/type_primitives/error.d.cts +1 -2
- package/dist/type_primitives/error.d.ts +1 -2
- package/dist/type_primitives/error.d.ts.map +1 -1
- package/dist/type_primitives/index.d.cts +1 -1
- package/dist/type_primitives/index.d.ts +1 -1
- package/dist/type_primitives/sparse_map/sparse_map.d.cts +3 -7
- package/dist/type_primitives/sparse_map/sparse_map.d.ts +3 -7
- package/dist/type_primitives/sparse_map/sparse_map.d.ts.map +1 -1
- package/dist/type_primitives/sparse_set/sparse_set.d.cts +2 -6
- package/dist/type_primitives/sparse_set/sparse_set.d.ts +2 -6
- package/dist/type_primitives/sparse_set/sparse_set.d.ts.map +1 -1
- package/dist/type_primitives/topological_sort/topological_sort.d.cts +1 -5
- package/dist/type_primitives/topological_sort/topological_sort.d.ts +1 -5
- package/dist/type_primitives/topological_sort/topological_sort.d.ts.map +1 -1
- package/dist/type_primitives/typed_arrays/typed_arrays.d.cts +16 -15
- package/dist/type_primitives/typed_arrays/typed_arrays.d.ts +16 -15
- package/dist/type_primitives/typed_arrays/typed_arrays.d.ts.map +1 -1
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/version.d.cts +3 -3
- package/dist/version.d.ts +3 -3
- package/dist/worker.cjs +1 -0
- package/dist/worker.d.cts +17 -0
- package/dist/worker.d.ts +17 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.development.cjs +1 -0
- package/dist/worker.development.js +253 -0
- package/dist/worker.js +253 -0
- package/package.json +363 -191
- package/dist/core/ecs/builtin_relations.d.cts +0 -43
- package/dist/core/ecs/builtin_relations.d.ts +0 -43
- package/dist/core/ecs/builtin_relations.d.ts.map +0 -1
- package/dist/core/ecs/event_registry.d.cts +0 -22
- package/dist/core/ecs/event_registry.d.ts +0 -22
- package/dist/core/ecs/event_registry.d.ts.map +0 -1
- package/dist/core/ecs/relation_service.d.ts.map +0 -1
- package/dist/core/ecs/resume.d.cts +0 -85
- package/dist/core/ecs/resume.d.ts +0 -85
- package/dist/core/ecs/resume.d.ts.map +0 -1
- package/dist/core/ecs/snapshot_service.d.cts +0 -94
- package/dist/core/ecs/snapshot_service.d.ts +0 -94
- package/dist/core/ecs/snapshot_service.d.ts.map +0 -1
- package/dist/extensions/editor/editor.d.ts.map +0 -1
- package/dist/extensions/editor/field_handle.d.ts.map +0 -1
- package/dist/extensions/editor/index.cjs +0 -1
- package/dist/extensions/editor/index.d.cts +0 -21
- package/dist/extensions/editor/index.d.ts +0 -21
- package/dist/extensions/editor/index.d.ts.map +0 -1
- package/dist/extensions/editor/index.development.cjs +0 -1
- package/dist/extensions/reactive/ecs_sync.d.cts +0 -214
- package/dist/extensions/reactive/ecs_sync.d.ts +0 -214
- package/dist/extensions/reactive/ecs_sync.d.ts.map +0 -1
- package/dist/extensions/reactive/index.cjs +0 -1
- package/dist/extensions/reactive/index.d.cts +0 -23
- package/dist/extensions/reactive/index.d.ts +0 -23
- package/dist/extensions/reactive/index.d.ts.map +0 -1
- package/dist/extensions/reactive/index.development.cjs +0 -1
- package/dist/extensions/reactive/index.development.js +0 -215
- package/dist/extensions/reactive/index.js +0 -215
- package/dist/extensions/solid/index.cjs +0 -1
- package/dist/extensions/solid/index.d.cts +0 -6
- package/dist/extensions/solid/index.d.ts +0 -6
- package/dist/extensions/solid/index.d.ts.map +0 -1
- package/dist/extensions/solid/index.development.cjs +0 -1
- package/dist/extensions/solid/index.development.js +0 -40
- package/dist/extensions/solid/index.js +0 -36
- package/dist/extensions/solid/kernel_solid.d.cts +0 -45
- package/dist/extensions/solid/kernel_solid.d.ts +0 -45
- package/dist/extensions/solid/kernel_solid.d.ts.map +0 -1
- package/dist/host_commands-BlR3oZ3x.js +0 -2406
- package/dist/host_commands-C2cpU3yC.cjs +0 -1
- package/dist/internal-BoxWl4dG.js +0 -2565
- package/dist/internal-CGBEwfeB.cjs +0 -2
- package/dist/interop-CT-REx0W.cjs +0 -1
- package/dist/interop-CcY6ASQc.js +0 -18
- package/dist/interop-DqxleBo7.js +0 -18
- package/dist/interop-T1HZ-Dpa.cjs +0 -1
- package/dist/kernel-Cz2Kxlwl.js +0 -240
- package/dist/kernel-DgyrLFjW.js +0 -227
- package/dist/kernel-sw7ScKWu.cjs +0 -1
- package/dist/kernel-yWV3XnAb.cjs +0 -1
- package/dist/reactive/array.d.cts +0 -24
- package/dist/reactive/array.d.ts +0 -24
- package/dist/reactive/array.d.ts.map +0 -1
- package/dist/reactive/index.cjs +0 -1
- package/dist/reactive/index.d.cts +0 -11
- package/dist/reactive/index.d.ts +0 -11
- package/dist/reactive/index.d.ts.map +0 -1
- package/dist/reactive/index.development.cjs +0 -1
- package/dist/reactive/index.development.js +0 -18
- package/dist/reactive/index.js +0 -18
- package/dist/reactive/interop.d.cts +0 -19
- package/dist/reactive/interop.d.ts +0 -19
- package/dist/reactive/interop.d.ts.map +0 -1
- package/dist/reactive/kernel.d.cts +0 -73
- package/dist/reactive/kernel.d.ts +0 -73
- package/dist/reactive/kernel.d.ts.map +0 -1
- package/dist/reactive/map.d.cts +0 -16
- package/dist/reactive/map.d.ts +0 -16
- package/dist/reactive/map.d.ts.map +0 -1
- package/dist/reactive/shallow.d.cts +0 -11
- package/dist/reactive/shallow.d.ts +0 -11
- package/dist/reactive/shallow.d.ts.map +0 -1
- package/dist/reactive/struct.d.cts +0 -10
- package/dist/reactive/struct.d.ts +0 -10
- package/dist/reactive/struct.d.ts.map +0 -1
- package/dist/shallow-Bs39EPh1.js +0 -150
- package/dist/shallow-C5YmTbtb.cjs +0 -1
- package/dist/shallow-CiFC70Dz.js +0 -159
- package/dist/shallow-DQ8aG51_.cjs +0 -1
- package/dist/shared-B4v0L1cw.js +0 -109
- package/dist/shared-DU78k0pU.cjs +0 -1
- package/dist/topological_sort-BDvEyb9W.cjs +0 -1
- package/dist/topological_sort-DK6EjpWa.js +0 -135
- package/dist/typed_arrays-D3NmwtCG.cjs +0 -1
- package/dist/typed_arrays-DIVwVy5_.js +0 -258
package/dist/core/ecs/store.d.ts
CHANGED
|
@@ -1,67 +1,30 @@
|
|
|
1
1
|
import { EntityID } from './entity.js';
|
|
2
|
-
import { CursorBinder } from './ref.js';
|
|
2
|
+
import { AccessorColumns, CursorBinder, SparseCursorCheck } from './ref.js';
|
|
3
3
|
import { FrameTraceSink } from './frame_trace.js';
|
|
4
4
|
import { ComponentDef, ComponentHandle, ComponentSchema, FieldValues } from './component.js';
|
|
5
|
-
import { SparseComponentDef, SparseComponentID } from './sparse_store.js';
|
|
6
|
-
import { RelationDef,
|
|
7
|
-
import {
|
|
5
|
+
import { SparseComponentStore, SparseComponentDef, SparseComponentID } from './sparse_store.js';
|
|
6
|
+
import { RelationDef, RelationHooks, RelationServiceHost } from './relation.js';
|
|
7
|
+
import { EventHooks } from './event.js';
|
|
8
|
+
import { ResourceRegistry } from './resource_registry.js';
|
|
8
9
|
import { BitSet, TypedArrayTag } from '../../type_primitives/index.js';
|
|
9
10
|
import { Archetype, ArchetypeID } from './archetype.js';
|
|
10
|
-
import { Query
|
|
11
|
+
import { Query } from './query.js';
|
|
12
|
+
import { QueryHost } from './query_cache.js';
|
|
13
|
+
import { QueryTerms } from './query_terms.js';
|
|
14
|
+
import { DrainResult, ObservationFlags, StructuralObserverEvents, Template } from './store_types.js';
|
|
11
15
|
import { ObserverHost } from './observer.js';
|
|
16
|
+
import { ChangeFeed } from './change_feed.js';
|
|
17
|
+
import { EntityAllocator } from './entity_allocator.js';
|
|
18
|
+
import { SnapshotHooks, SnapshotHost } from './snapshot.js';
|
|
12
19
|
import { InPlaceBufferAllocator, ColumnStoreRegionHandle, StoreRegionSpec, ColumnStore } from '../store/index.js';
|
|
13
20
|
import { ECSMemoryCapContext } from './ecs_memory.js';
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/** Has an onAdd observer — collect effective adds for this component. */
|
|
22
|
-
obsAdd: boolean;
|
|
23
|
-
/** Has an onRemove observer — collect effective removes for this component. */
|
|
24
|
-
obsRem: boolean;
|
|
25
|
-
/** Has an onDisable observer — collect effective disables for this
|
|
26
|
-
* component at the toggle drain. */
|
|
27
|
-
obsDisable: boolean;
|
|
28
|
-
/** Has an onEnable observer — collect effective enables for this
|
|
29
|
-
* component at the toggle drain. */
|
|
30
|
-
obsEnable: boolean;
|
|
31
|
-
/** Has a per-entity onSet observer — record dirty rows on the write path
|
|
32
|
-
* (the opt-in dirty list). */
|
|
33
|
-
trackDirty: boolean;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Effective `(component, entity)` structural events for one fixed-point round,
|
|
37
|
-
* collected during `_flushAdds` / `_flushRemoves` and handed to the observer
|
|
38
|
-
* dispatch hook. Flat parallel arrays, count-bounded (`*_len`), reused across
|
|
39
|
-
* rounds — never reallocated in the flush. This is a scheduling artifact: it is
|
|
40
|
-
* NOT part of `stateHash` or snapshot. See `observer.ts`.
|
|
41
|
-
*/
|
|
42
|
-
export interface StructuralObserverEvents {
|
|
43
|
-
addComp: number[];
|
|
44
|
-
addEid: number[];
|
|
45
|
-
addLen: number;
|
|
46
|
-
remComp: number[];
|
|
47
|
-
remEid: number[];
|
|
48
|
-
remLen: number;
|
|
49
|
-
/** Effective disable events — collected during the toggle drain
|
|
50
|
-
* (`_flushToggles`), one per `(component, entity)` of each net-disabled
|
|
51
|
-
* entity's mask. Empty on a structural (add/remove/destroy) round. */
|
|
52
|
-
disComp: number[];
|
|
53
|
-
disEid: number[];
|
|
54
|
-
disLen: number;
|
|
55
|
-
/** Effective enable events, symmetric with the disable arrays. */
|
|
56
|
-
enaComp: number[];
|
|
57
|
-
enaEid: number[];
|
|
58
|
-
enaLen: number;
|
|
59
|
-
}
|
|
60
|
-
/** Runtime shape of one template / `addComponents` entry: a def plus optional
|
|
61
|
-
* field values (omitted fields zero-fill). The public authoring surface is
|
|
62
|
-
* callable-bundle varargs, schema-checked per item by `StrictBundles`
|
|
63
|
-
* (component.ts); the `ECS` facade normalizes those bundles into this erased
|
|
64
|
-
* array before calling the store, so the store stays schema-agnostic. */
|
|
21
|
+
export type { ComponentMeta, DrainResult, ObservationFlags, StructuralObserverEvents, Template } from './store_types.js';
|
|
22
|
+
/** Runtime shape of one template entry or `addComponents` entry: a def plus
|
|
23
|
+
* optional field values (an omitted field zero-fills). The public authoring
|
|
24
|
+
* surface is callable-bundle varargs, schema-checked for each item by
|
|
25
|
+
* `StrictBundles` in `component.ts`. The `ECS` facade normalizes those bundles
|
|
26
|
+
* into this erased array before it calls the store, so the store stays
|
|
27
|
+
* schema-agnostic. */
|
|
65
28
|
type TemplateEntryData = {
|
|
66
29
|
readonly def: ComponentDef;
|
|
67
30
|
readonly values?: Readonly<Record<string, number>>;
|
|
@@ -75,155 +38,210 @@ type TemplateFieldNames<Defs extends readonly ComponentDef[]> = Defs[number] ext
|
|
|
75
38
|
export type TemplateOverrides<Defs extends readonly ComponentDef[]> = {
|
|
76
39
|
readonly [K in TemplateFieldNames<Defs>]?: number;
|
|
77
40
|
};
|
|
78
|
-
declare const __templateDefs: unique symbol;
|
|
79
|
-
/** A resolved template — an archetype template produced by
|
|
80
|
-
* `ECS.template(...)`. **Opaque** apart from `defs`: callers hold it and pass
|
|
81
|
-
* it to `ECS.spawn` / `ECS.spawnMany` (and may reference it in a system's
|
|
82
|
-
* `spawns` / `despawns` access declaration — the scheduler expands it to
|
|
83
|
-
* `defs`); the remaining fields are engine-internal and may change. `spawn`
|
|
84
|
-
* lands an entity directly in `archetype_id` with zero archetype transitions,
|
|
85
|
-
* writing `flatValues` (defaults in `_flatColumns` order) in one append
|
|
86
|
-
* pass. */
|
|
87
|
-
export interface Template<Defs extends readonly ComponentDef[] = readonly ComponentDef[]> {
|
|
88
|
-
readonly archetypeId: ArchetypeID;
|
|
89
|
-
readonly flatValues: number[];
|
|
90
|
-
readonly overrideIndex: Map<string, number>;
|
|
91
|
-
/** The component set this template spawns into, in entry order. */
|
|
92
|
-
readonly defs: readonly ComponentDef[];
|
|
93
|
-
readonly [__templateDefs]?: Defs;
|
|
94
|
-
}
|
|
95
41
|
export interface StoreOptions {
|
|
96
42
|
initialCapacity?: number;
|
|
97
43
|
/** Pluggable SAB buffer source. When provided, `createColumnStore`,
|
|
98
44
|
* `extendColumnStore`, and `growColumnStore` route through it. Default is
|
|
99
45
|
* `growableSabAllocator`. Typed `InPlaceBufferAllocator`: a live
|
|
100
46
|
* Store's flush loops hoist entity-index views across grows, so only
|
|
101
|
-
* in-place allocators may back one
|
|
47
|
+
* in-place allocators may back one, the constructor also
|
|
102
48
|
* runtime-asserts the marker for untyped JS callers. Consumers normally
|
|
103
|
-
* don't touch this directly
|
|
49
|
+
* don't touch this directly. `ECSOptions.memory` resolves to it. */
|
|
104
50
|
bufferAllocator?: InPlaceBufferAllocator;
|
|
105
51
|
/** Sizing intent the world was constructed with, used to phrase
|
|
106
52
|
* allocator-cap and entity-index-overflow errors in the caller's own
|
|
107
|
-
* terms (
|
|
108
|
-
* `ECS` from `resolveECSMemory
|
|
53
|
+
* terms (a multiple of the declared budget) instead of raw bytes. Wired by
|
|
54
|
+
* `ECS` from `resolveECSMemory`. Absent for bare test Stores. */
|
|
109
55
|
capContext?: ECSMemoryCapContext;
|
|
110
56
|
/** Fired after every SAB resize (extend or grow). The new SAB has
|
|
111
57
|
* already been built and archetypes have already refreshed their
|
|
112
|
-
* views by the time this fires.
|
|
113
|
-
*
|
|
114
|
-
|
|
58
|
+
* views by the time this fires. `ECS` uses it to call `setLayout` on every
|
|
59
|
+
* subscribed layout listener, so a WASM-side cached pointer re-walks. */
|
|
60
|
+
onBufferReplaced?: () => void;
|
|
115
61
|
/** Max live entities the SAB entity-index region holds.
|
|
116
|
-
* Default `ENTITY_INDEX_DEFAULT_CAPACITY` (`1 << 20
|
|
62
|
+
* Default `ENTITY_INDEX_DEFAULT_CAPACITY` (`1 << 20`, the full EntityID
|
|
117
63
|
* index space). Exceeding this at runtime throws `EID_MAX_INDEX_OVERFLOW`.
|
|
118
|
-
* Tests with small entity counts may set lower to
|
|
119
|
-
*
|
|
120
|
-
* comfortably in the default. */
|
|
64
|
+
* Tests with small entity counts may set lower to shrink the SAB region or
|
|
65
|
+
* to make index exhaustion reachable. */
|
|
121
66
|
entityIndexCapacity?: number;
|
|
67
|
+
/** Byte offset inside the backing where the store header goes. Default 0.
|
|
68
|
+
* Forwarded verbatim to `createColumnStore`, and every offset in the bytes
|
|
69
|
+
* is relative to it. `ECSOptions.memory.storeBase` resolves to it. */
|
|
70
|
+
storeBase?: number;
|
|
122
71
|
/** Consumer-declared SAB regions, forwarded verbatim to
|
|
123
72
|
* `createColumnStore`. Each `StoreRegionSpec` carries an opaque `region_id`,
|
|
124
|
-
* a precomputed byte size, and an `init` closure
|
|
125
|
-
* generically and exposes them
|
|
126
|
-
* A
|
|
127
|
-
*
|
|
73
|
+
* a precomputed byte size, and an `init` closure. The engine lays them out
|
|
74
|
+
* generically and exposes them through `regionHandle(id)` and
|
|
75
|
+
* `regionOffset(id)`. A consumer supplies the specs. The engine ships no
|
|
76
|
+
* region of its own. Omitted ⇒ none. */
|
|
128
77
|
regions?: readonly StoreRegionSpec[];
|
|
129
78
|
/** Byte size of the opt-in sim-bindings region, forwarded verbatim to
|
|
130
79
|
* `createColumnStore`. A consumer that attaches a WASM backend passes its own
|
|
131
|
-
* size
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* drift an engine golden. */
|
|
80
|
+
* size, computed from its own binding manifest. The host then writes the
|
|
81
|
+
* `(component_id, field_id)` ids into the region. Omitted or 0 ⇒ no region,
|
|
82
|
+
* so a pure-TS world pays nothing for the WASM seam. The size stays out of
|
|
83
|
+
* the engine ABI, so a manifest edit does not drift an engine golden. */
|
|
136
84
|
bindingsRegionBytes?: number;
|
|
137
85
|
/** Opt into the **determinism surface**. Default `false`.
|
|
138
|
-
* Gates the three methods that fold
|
|
86
|
+
* Gates the three methods that fold and serialize state in canonical (sorted)
|
|
139
87
|
* order: `stateHash`, `snapshotSparse`, `restoreSparse`. When `false`
|
|
140
|
-
* those throw `DETERMINISM_DISABLED
|
|
88
|
+
* those throw `DETERMINISM_DISABLED`, the canonical-ordering tax (sparse
|
|
141
89
|
* `canonicalIndices` sort + relation target-set sort) is never paid, and a
|
|
142
90
|
* consumer can't accidentally read a non-canonical digest. When `true`,
|
|
143
|
-
* today's behavior is reproduced bit-for-bit. This is the
|
|
91
|
+
* today's behavior is reproduced bit-for-bit. This is the only effect of the
|
|
144
92
|
* flag: it does not touch the per-tick path, the in-place-allocator invariant
|
|
145
93
|
* (a memory-safety requirement that holds regardless), or the
|
|
146
94
|
* always-on `enabled_count` partition maintenance. The flag's value is a
|
|
147
|
-
*
|
|
148
|
-
* called per tick. */
|
|
95
|
+
* plugin gate, not a hot-path switch. `stateHash` and the snapshot are
|
|
96
|
+
* never called per tick. */
|
|
149
97
|
deterministic?: boolean;
|
|
150
98
|
}
|
|
151
|
-
export declare class Store implements ObserverHost, QueryHost {
|
|
152
|
-
private readonly
|
|
153
|
-
private readonly
|
|
154
|
-
private
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
private readonly
|
|
160
|
-
private
|
|
161
|
-
private
|
|
162
|
-
private
|
|
163
|
-
private
|
|
164
|
-
private
|
|
99
|
+
export declare class Store implements ChangeFeed, ObserverHost, QueryHost {
|
|
100
|
+
private readonly _entityAllocator;
|
|
101
|
+
private readonly _componentMetas;
|
|
102
|
+
private readonly _sparseStores;
|
|
103
|
+
/** Debug names parallel to `_sparseStores`, diagnostics only. */
|
|
104
|
+
private readonly _sparseNames;
|
|
105
|
+
/** The reused result of `drainSparseSet`, parallel to `_sparseStores`,
|
|
106
|
+
* allocated for a sparse component with an entity-level onSet. */
|
|
107
|
+
private readonly _sparseDrains;
|
|
108
|
+
private _relations;
|
|
109
|
+
private _events;
|
|
110
|
+
private readonly _archGraph;
|
|
111
|
+
private _emptyArchetypeId;
|
|
112
|
+
private _entityArchetypes;
|
|
113
|
+
private _entityRows;
|
|
114
|
+
private readonly _queries;
|
|
165
115
|
private readonly _deferred;
|
|
166
|
-
private
|
|
167
|
-
|
|
116
|
+
private _snapshots;
|
|
117
|
+
get relations(): RelationHooks;
|
|
118
|
+
/** The relation service, for a caller that is not `ecs.relations`.
|
|
119
|
+
*
|
|
120
|
+
* The getter above names `ecs.relations` in its fault. That is the wrong
|
|
121
|
+
* remedy when a system context or a query term reached the service. Every
|
|
122
|
+
* seam a user can reach passes its own name here. Error path only. The
|
|
123
|
+
* successful read is the same field read the getter makes. */
|
|
124
|
+
requireRelations(api: string): RelationHooks;
|
|
125
|
+
/** Build the host the relation service needs. Closures, not field
|
|
126
|
+
* references: `generations`, `entityArchetypes` and `entityRows` are
|
|
127
|
+
* reallocated when capacity grows, so each accessor re-reads the live
|
|
128
|
+
* field. */
|
|
129
|
+
relationHost(): RelationServiceHost;
|
|
130
|
+
/** Install the relations plugin. Called once, by the plugin. */
|
|
131
|
+
installRelations(service: RelationHooks): void;
|
|
132
|
+
get events(): EventHooks;
|
|
133
|
+
/** The event registry, for a caller that is not `ecs.events`. Names the
|
|
134
|
+
* seam the user reached, the way `requireRelations` does. */
|
|
135
|
+
requireEvents(api: string): EventHooks;
|
|
136
|
+
/** Whether the events plugin is installed. Read once per frame by the
|
|
137
|
+
* tick-tail clear, which must be a no-op on a world without channels. */
|
|
138
|
+
get hasEvents(): boolean;
|
|
139
|
+
/** Install the events plugin. Called once, by the plugin. */
|
|
140
|
+
installEvents(registry: EventHooks): void;
|
|
141
|
+
/** Build the host a snapshot plugin needs. Only the store can reach
|
|
142
|
+
* these fields, so it builds the record and the plugin owns the service.
|
|
143
|
+
* The accessors re-read live fields per call: the column store and the
|
|
144
|
+
* entity-index views are replaced on a restore. All cold path. */
|
|
145
|
+
snapshotHost(): SnapshotHost;
|
|
146
|
+
/** The allocator, which is its own snapshot seam. Handed to the plugin
|
|
147
|
+
* so the store need not construct the service itself. */
|
|
148
|
+
get entityAllocator(): EntityAllocator;
|
|
149
|
+
/** Install the snapshot plugin. Called once, by the plugin. */
|
|
150
|
+
installSnapshots(service: SnapshotHooks): void;
|
|
151
|
+
get snapshots(): SnapshotHooks;
|
|
152
|
+
get resources(): ResourceRegistry;
|
|
153
|
+
tick: number;
|
|
154
|
+
/** The change tick. A monotonic counter that the schedule advances before
|
|
155
|
+
* each system run, before each phase flush, before the onSet dispatch and
|
|
156
|
+
* at the end of each update. Every write stamps it on the archetype column
|
|
157
|
+
* it touches, and a consumer compares against the value of its own last
|
|
158
|
+
* run. The frame tick above cannot order a writer and a reader inside one
|
|
159
|
+
* frame, so a write by an earlier system was reported on two frames. This
|
|
160
|
+
* counter orders them. It starts above the initial column stamp, so the
|
|
161
|
+
* first run of a system sees every row that exists. A scheduling artifact:
|
|
162
|
+
* not in `stateHash` or the snapshot, and monotonic across a restore. */
|
|
163
|
+
changeTick: number;
|
|
164
|
+
/** Advance the change tick and return the new value, the stamp for the
|
|
165
|
+
* run that follows. Hot path: one increment per system run. */
|
|
166
|
+
advanceChangeTick(): number;
|
|
168
167
|
/** Per-world frame-trace sink, installed via `ECS.setTrace`.
|
|
169
168
|
* `null` unless a consumer attaches a recorder. Every call site is
|
|
170
|
-
* `if (DEV) store.
|
|
171
|
-
* the seam and pay only this one nullable field. The sink observes
|
|
172
|
-
* folds into `stateHash
|
|
173
|
-
* observer state below
|
|
174
|
-
|
|
169
|
+
* `if (DEV) store.trace?.…`, so production builds dead-code-eliminate
|
|
170
|
+
* the seam and pay only this one nullable field. The sink observes. It never
|
|
171
|
+
* folds into `stateHash`. It is a scheduling artifact, like `_changedTick`
|
|
172
|
+
* and like the observer state below. */
|
|
173
|
+
trace: FrameTraceSink | null;
|
|
175
174
|
private _structuralObserverCount;
|
|
176
|
-
/** Count of components with any onDisable
|
|
175
|
+
/** Count of components with any onDisable and onEnable observer. While 0
|
|
177
176
|
* (with `_structuralObserverCount` also 0), `flushStructural` takes the
|
|
178
177
|
* byte-for-byte fast path and the toggle drain skips event collection. */
|
|
179
178
|
private _toggleObserverCount;
|
|
179
|
+
/** One flag record for each consumer of the change feed, keyed by the
|
|
180
|
+
* plugin name, each array indexed by component id and sparse. The
|
|
181
|
+
* store merges by OR across the records, so the flags a component carries
|
|
182
|
+
* are the union of what every consumer asked for. Cold: written when a
|
|
183
|
+
* consumer gains or loses an observer, read on the same call. */
|
|
184
|
+
private readonly _observationFlags;
|
|
185
|
+
/** The sparse half of the record above, one boolean for each sparse
|
|
186
|
+
* component a consumer wants the entity grain of. */
|
|
187
|
+
private readonly _sparseObservationFlags;
|
|
180
188
|
/** Reused effective-event scratch for the current flush round. */
|
|
181
189
|
private readonly _obsEvents;
|
|
182
|
-
/** Installed via `
|
|
183
|
-
* events to
|
|
184
|
-
* further structural ops.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
*
|
|
189
|
-
|
|
190
|
+
/** Installed via `addStructuralHook`, each one dispatches a round's
|
|
191
|
+
* collected events to one consumer of the change feed, which may enqueue
|
|
192
|
+
* further structural ops. Empty on a world that installed no consumer, and
|
|
193
|
+
* the flush reads it once per round. */
|
|
194
|
+
private readonly _structuralHooks;
|
|
195
|
+
/** Add a consumer of the structural event batches. Each round of the
|
|
196
|
+
* observed flush hands its effective events to every hook, in install
|
|
197
|
+
* order. The events scratch is store-owned and reused, so a hook reads it
|
|
198
|
+
* during the call and copies whatever it keeps. Cold path. */
|
|
199
|
+
addStructuralHook(fn: (ev: StructuralObserverEvents) => void): void;
|
|
190
200
|
private _collectDestroyEid;
|
|
191
201
|
private readonly _collectDestroyRemoveBit;
|
|
192
202
|
private _collectToggleEid;
|
|
193
203
|
private readonly _collectDisableBit;
|
|
194
204
|
private readonly _collectEnableBit;
|
|
195
205
|
/** Net-transition snapshot for the toggle drain: entity → its disabled
|
|
196
|
-
* state at the
|
|
206
|
+
* state at the start of the drain. Reused, cleared each drain. Lets
|
|
197
207
|
* `_flushToggles` emit one event per *net* transition (disable→enable→disable
|
|
198
|
-
* within a tick = a single onDisable) instead of one per buffered op
|
|
208
|
+
* within a tick = a single onDisable) instead of one per buffered op, required
|
|
199
209
|
* because the radix canonical-order pass would otherwise reorder duplicate eids
|
|
200
|
-
* and mis-sequence a consumer's delete
|
|
210
|
+
* and mis-sequence a consumer's delete and republish. */
|
|
201
211
|
private readonly _toggleInitial;
|
|
202
|
-
|
|
212
|
+
/** True once any component has row ticks. Gates the record at every write
|
|
213
|
+
* site, so a world without one pays a load and a branch there. */
|
|
214
|
+
anyDirtyTracked: boolean;
|
|
215
|
+
/** The components with row ticks, for the archetypes born later. */
|
|
203
216
|
private readonly _dirtyTrackedCids;
|
|
204
217
|
private readonly _dirtyLists;
|
|
205
|
-
private readonly
|
|
218
|
+
private readonly _drainResults;
|
|
206
219
|
/** Set by any path that changes a SAB-backed archetype's live row count
|
|
207
|
-
* (`flushStructural
|
|
220
|
+
* (`flushStructural` and `flushDestroys` when they did work, immediate
|
|
208
221
|
* `destroyEntity`, `addComponent(s)`, `removeComponent(s)` on the
|
|
209
|
-
* Store). Cleared by `
|
|
222
|
+
* Store). Cleared by `publishRowCounts`. Lets read-only
|
|
210
223
|
* phases' `ctx.flush` skip the descriptor walk entirely. */
|
|
211
224
|
private _rowCountsDirty;
|
|
212
225
|
/** Monotonic counter bumped by every membership-changing path (immediate
|
|
213
226
|
* `addComponent(s)`, `removeComponent(s)`, `destroyEntity`,
|
|
214
227
|
* `batchAddComponent`, `batchRemoveComponent`, `flushStructural`,
|
|
215
|
-
* `
|
|
216
|
-
* Read by `Query.
|
|
217
|
-
*
|
|
228
|
+
* `flushDestroys`, and new-archetype installs in `ArchetypeGraph.install`).
|
|
229
|
+
* Read by `Query.nonEmptyArchs()` via `QueryResolver.getQueryDirtyEpoch`.
|
|
230
|
+
* A query whose stored `_lastSeenEpoch` matches the current epoch
|
|
218
231
|
* reuses its cached non-empty list. Replaces the previous walk
|
|
219
|
-
* over `
|
|
220
|
-
* mutation
|
|
221
|
-
*
|
|
222
|
-
* its `QueryResolver` impl
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
private readonly _scratchTargetMask;
|
|
232
|
+
* over `_registeredQueries` that wrote one dirty bit per query per
|
|
233
|
+
* mutation. A startup that adds many rows used to write one bit for each
|
|
234
|
+
* query at each mutation. Now it writes one integer increment. Public, so
|
|
235
|
+
* ECS can forward through its `QueryResolver` impl. It is not part of the
|
|
236
|
+
* user-facing API. */
|
|
237
|
+
queryDirtyEpoch: number;
|
|
226
238
|
private _columnStore;
|
|
239
|
+
/** Row capacity every new archetype's columns start with. Taken from
|
|
240
|
+
* `StoreOptions.initialCapacity` at construction, read again by the
|
|
241
|
+
* archetype graph's `initialCapacity` host closure whenever it plants a
|
|
242
|
+
* new archetype. It sat under the row-grain banner, which owns the change
|
|
243
|
+
* detection state, and it sizes the backing instead. */
|
|
244
|
+
private readonly _initialCapacity;
|
|
227
245
|
/** Installed on every SAB-backed Archetype so the Archetype can
|
|
228
246
|
* request a SAB grow when an insertion would exceed its column
|
|
229
247
|
* capacity. Doubles the offending archetype's row capacity (or jumps
|
|
@@ -233,43 +251,46 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
233
251
|
* SAB-backed archetype. */
|
|
234
252
|
private readonly _growHandler;
|
|
235
253
|
/** Build the intent-aware fatal for an allocator cap hit. The
|
|
236
|
-
* allocator can only name raw bytes
|
|
254
|
+
* allocator can only name raw bytes. The Store knows what the caller
|
|
237
255
|
* declared (`capContext`) and how many entities are live, so the error
|
|
238
|
-
*
|
|
256
|
+
* names the live count as a multiple of the declared budget instead
|
|
239
257
|
* of leaving the caller to reverse-engineer byte counts. Fatality is
|
|
240
258
|
* unchanged (no grow-beyond-cap fallback). */
|
|
241
259
|
private _capExceededError;
|
|
242
260
|
private readonly _bufferAllocator;
|
|
243
261
|
private readonly _capContext;
|
|
244
262
|
private readonly _onBufferResized;
|
|
245
|
-
/** Construct with an `
|
|
263
|
+
/** Construct with an `_initialCapacity` number (legacy form) or an
|
|
246
264
|
* options object (adds `bufferAllocator` and
|
|
247
|
-
* `
|
|
265
|
+
* `onBufferReplaced` callback). Both signatures coexist so test fixtures
|
|
248
266
|
* that pass `new Store(4)` keep working. */
|
|
249
267
|
constructor(arg?: number | StoreOptions);
|
|
250
268
|
/** Capacity of the entity-index SAB region (max slots ≈ max live
|
|
251
|
-
* entities). Fixed at construction
|
|
269
|
+
* entities). Fixed at construction. A future
|
|
252
270
|
* follow-up will grow it via `growColumnStore` when `entityHighWater`
|
|
253
271
|
* hits the cap. */
|
|
254
272
|
private readonly _entityIndexCapacity;
|
|
273
|
+
/** Byte offset of the store header inside the backing. Fixed at
|
|
274
|
+
* construction, and every offset in the bytes is relative to it. */
|
|
275
|
+
private readonly _storeBase;
|
|
255
276
|
/** Consumer-declared SAB regions, captured so the realloc path
|
|
256
277
|
* re-lays them out. `undefined` when no consumer regions were declared.
|
|
257
278
|
* The region contents survive a grow via the self-describing region table
|
|
258
|
-
* (`extend.ts` snapshot
|
|
279
|
+
* (`extend.ts` snapshot and restore), so this is only the layout recipe. */
|
|
259
280
|
private readonly _regions;
|
|
260
281
|
/** Byte size of the opt-in sim-bindings region. 0 ⇒ no region (the
|
|
261
|
-
* pure-TS default). Captured so the initial `createColumnStore` reserves it
|
|
262
|
-
*
|
|
263
|
-
* `optionsFromOld`, so it is not threaded through the grow
|
|
282
|
+
* pure-TS default). Captured so the initial `createColumnStore` reserves it.
|
|
283
|
+
* Across a realloc the size is re-derived from the old header by
|
|
284
|
+
* `optionsFromOld`, so it is not threaded through the grow and extend path. */
|
|
264
285
|
private readonly _bindingsRegionBytes;
|
|
265
|
-
/** Determinism opt-in. When `false` (the default), the
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
* `enabled_count` partition
|
|
286
|
+
/** Determinism opt-in. When `false` (the default), the canonical-ordering
|
|
287
|
+
* determinism surface throws `DETERMINISM_DISABLED` rather than run its
|
|
288
|
+
* sort. That surface is `stateHash`, `snapshotSparse` and `restoreSparse`.
|
|
289
|
+
* The memory-safety invariant of the in-place allocator and the
|
|
290
|
+
* `enabled_count` partition hold regardless. */
|
|
270
291
|
private readonly _deterministic;
|
|
271
|
-
/** Whether the determinism surface is enabled. `false` ⇒ `stateHash
|
|
272
|
-
*
|
|
292
|
+
/** Whether the determinism surface is enabled. `false` ⇒ `stateHash`,
|
|
293
|
+
* `snapshotSparse` and `restoreSparse` throw `DETERMINISM_DISABLED`. */
|
|
273
294
|
get deterministic(): boolean;
|
|
274
295
|
/** Guard the canonical-ordering determinism surface. Throws
|
|
275
296
|
* `DETERMINISM_DISABLED` when determinism wasn't opted into, naming the
|
|
@@ -277,72 +298,62 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
277
298
|
* (not `DEV`-gated): the surface is cold (never per-tick) so one boolean
|
|
278
299
|
* check is free, and a silent non-canonical digest is the failure mode we're
|
|
279
300
|
* preventing. */
|
|
280
|
-
private
|
|
281
|
-
/** Reject `f32`/`f64` fields on a `deterministic: true` world at registration.
|
|
282
|
-
* IEEE-754 rounds differently across V8 / Bun / Zig at the 1-ULP
|
|
283
|
-
* level, so a float column in a fixed-update path is a silent per-tick
|
|
284
|
-
* `stateHash` divergence between client and server — the one thing the
|
|
285
|
-
* determinism opt-in exists to prevent. Non-deterministic worlds
|
|
286
|
-
* skip this entirely (floats stay allowed), so it costs the default path
|
|
287
|
-
* nothing. `kind` names the storage class in the error ("component" /
|
|
288
|
-
* "sparse component"); the array shorthand's `f64` default lands here too, so
|
|
289
|
-
* a deterministic world must pass an explicit integer type. */
|
|
290
|
-
private _rejectNonDeterministicFields;
|
|
301
|
+
private _assertDeterministic;
|
|
291
302
|
/** Rebuild the Int32Array views over the SAB entity-index region
|
|
292
|
-
* after a host-side SAB realloc (extend
|
|
293
|
-
* `_handleBufferResized
|
|
294
|
-
* callback fires so any downstream reader sees coherent views. */
|
|
303
|
+
* after a host-side SAB realloc (extend and grow). Called from
|
|
304
|
+
* `_handleBufferResized`, before the user-supplied `onBufferReplaced`
|
|
305
|
+
* callback fires, so any downstream reader sees coherent views. */
|
|
295
306
|
private _refreshEntityIndexViews;
|
|
296
|
-
/** Centralised "SAB was
|
|
297
|
-
* Int32Array views
|
|
307
|
+
/** Centralised "SAB was only reallocated" handler. Refreshes the
|
|
308
|
+
* Int32Array views first (so user callbacks observe valid views),
|
|
298
309
|
* then mirrors `entityHighWater` into the region's length header,
|
|
299
310
|
* then fires the user-supplied callback. */
|
|
300
311
|
private _handleBufferResized;
|
|
301
|
-
/** SAB backing every archetype's column views. Read-only handle
|
|
302
|
-
* live mutation happens through `
|
|
303
|
-
* Exposed for tests, snapshot
|
|
304
|
-
*
|
|
312
|
+
/** SAB backing every archetype's column views. Read-only handle. The
|
|
313
|
+
* live mutation happens through `_archGetOrCreateFromMask`.
|
|
314
|
+
* Exposed for tests, snapshot and restore, and `columnStoreStateHash`.
|
|
315
|
+
* Production reads of column data should
|
|
305
316
|
* still go through `Archetype.getColumnRead` (which sources from this
|
|
306
317
|
* SAB under the hood). */
|
|
307
318
|
get columnStore(): ColumnStore;
|
|
308
319
|
/** Resolve a consumer-declared SAB region's byte offset by `region_id`, or
|
|
309
320
|
* 0 when the region is absent (no region was declared with that id). The
|
|
310
|
-
* generic
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
321
|
+
* generic replacement for the removed game-named accessors, such as
|
|
322
|
+
* `terrain_view` and `spatial_grid_view`. A consumer pairs this with its own
|
|
323
|
+
* region module to materialise a typed view. It is the TS twin of the
|
|
324
|
+
* `abi.find_region` a WASM backend calls. */
|
|
314
325
|
regionOffset(regionId: number): number;
|
|
315
326
|
/** A handle to a consumer-declared SAB region resolved by `region_id`, or
|
|
316
|
-
* `null` when absent. Carries the live `buffer
|
|
327
|
+
* `null` when absent. Carries the live `buffer` and `view` plus the region's byte
|
|
317
328
|
* `offset` and `bytes`, so a consumer's region module can build a TypedArray
|
|
318
329
|
* view over exactly the region's span without re-reading the directory.
|
|
319
|
-
* Re-fetch after a SAB grow (the offset
|
|
330
|
+
* Re-fetch after a SAB grow (the offset and view may have moved). */
|
|
320
331
|
regionHandle(regionId: number): ColumnStoreRegionHandle | null;
|
|
321
332
|
/**
|
|
322
333
|
* Stamp every SAB-backed archetype's live `length` into its descriptor's
|
|
323
|
-
* `row_count` field. `extendColumnStore`
|
|
334
|
+
* `row_count` field. `extendColumnStore` and
|
|
324
335
|
* `growColumnStore` are the only other writers of `row_count`, and they
|
|
325
|
-
* record the count at the moment of the resize
|
|
336
|
+
* record the count at the moment of the resize, `Archetype.addEntity`
|
|
326
337
|
* does not update it, so any insertion after the most recent resize
|
|
327
|
-
* leaves the descriptor stale.
|
|
328
|
-
* off `
|
|
329
|
-
*
|
|
338
|
+
* leaves the descriptor stale. A compute backend that drives its per-row
|
|
339
|
+
* loop off the descriptor's `row_count` reads those stale bytes and
|
|
340
|
+
* silently skips the newly spawned rows.
|
|
330
341
|
*
|
|
331
342
|
* Lockstep walk: SAB descriptors are written by `extendColumnStore` in
|
|
332
343
|
* the order non-SAB archetypes are promoted, which is the same id-order
|
|
333
|
-
* those archetypes occupy in `this.
|
|
344
|
+
* those archetypes occupy in `this._archGraph.archetypes`. Iterating that array
|
|
334
345
|
* once, skipping non-SAB entries, and advancing an `archAddr` cursor
|
|
335
346
|
* by the descriptor's `column_count` lets us write `row_count` without
|
|
336
347
|
* the throwaway `Map<archId, length>` the previous version allocated
|
|
337
348
|
* on every call. Cheap: descriptor-region seeks only, no column
|
|
338
349
|
* I/O.
|
|
339
350
|
*
|
|
340
|
-
* Gated by `_rowCountsDirty
|
|
341
|
-
* (`flushStructural`, `
|
|
342
|
-
* `addComponent(s)`, `removeComponent(s)`) set the flag
|
|
351
|
+
* Gated by `_rowCountsDirty`, mutation paths
|
|
352
|
+
* (`flushStructural`, `flushDestroys`, immediate `destroyEntity`,
|
|
353
|
+
* `addComponent(s)`, `removeComponent(s)`) set the flag. This method
|
|
343
354
|
* clears it. Read-only phases that flush only to drain empty buffers
|
|
344
355
|
* pay nothing. */
|
|
345
|
-
|
|
356
|
+
publishRowCounts(): void;
|
|
346
357
|
/** FNV-1a-style 32-bit digest over (archetype_id, live_row_count, live
|
|
347
358
|
* column bytes) for each archetype in id order, followed by the sparse
|
|
348
359
|
* stores (out-of-identity components) in registration order.
|
|
@@ -350,90 +361,86 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
350
361
|
* determinism. It replaces the earlier per-networked-component fold.
|
|
351
362
|
*
|
|
352
363
|
* **Sparse coverage.** Sparse data lives outside the archetype
|
|
353
|
-
* graph, so it is folded separately after the archetype loop
|
|
364
|
+
* graph, so it is folded separately after the archetype loop, per store:
|
|
354
365
|
* the sparse-component id, the member count, then each member's source
|
|
355
|
-
* entity index + f64 field words, walked in
|
|
366
|
+
* entity index + f64 field words, walked in canonical ascending-index order
|
|
356
367
|
* (`SparseComponentStore.canonicalIndices`). Canonical order is what makes
|
|
357
368
|
* the digest insertion-order-independent: two worlds with identical sparse
|
|
358
|
-
* contents built by different add
|
|
369
|
+
* contents built by different add and remove sequences agree. Keyed by entity
|
|
359
370
|
* index, and destruction purges the slot, so a recycled index never carries
|
|
360
371
|
* a stale occupant's data into the hash.
|
|
361
372
|
*
|
|
362
373
|
* It is strictly broader than the prior per-networked-component fold
|
|
363
|
-
* (covers every column, not
|
|
374
|
+
* (covers every column, not only a hand-picked subset of networked
|
|
364
375
|
* components), and strictly tighter than `columnStoreStateHash(...)`
|
|
365
376
|
* which scans the full SAB including trailing unused capacity.
|
|
366
377
|
*
|
|
367
378
|
* **Per-word fold.** The inner column loop folds one 32-bit
|
|
368
|
-
* word at a time using FNV-1a's `xor + imul(PRIME)` step. This is
|
|
369
|
-
* byte-for-byte FNV-1a-32 of the column bytes
|
|
379
|
+
* word at a time using FNV-1a's `xor + imul(PRIME)` step. This is not
|
|
380
|
+
* byte-for-byte FNV-1a-32 of the column bytes. It's a deterministic
|
|
370
381
|
* digest with the same equality semantics, and much quicker than the
|
|
371
|
-
* per-byte loop it replaces. Trailing 0
|
|
372
|
-
* u8
|
|
382
|
+
* per-byte loop it replaces. Trailing 0 to 3 tail bytes (only possible for
|
|
383
|
+
* u8 or u16 columns at odd row counts) are folded together as a single
|
|
373
384
|
* little-endian word so the algorithm stays branch-free in the inner
|
|
374
385
|
* loop. The 4-byte `id` and `len` headers are folded as words for the
|
|
375
386
|
* same reason. Byte order is little-endian to match the platform's
|
|
376
|
-
* native TypedArray layout
|
|
387
|
+
* native TypedArray layout. The digest is opaque (no consumer compares
|
|
377
388
|
* against a literal value), so endianness is an implementation detail
|
|
378
389
|
* rather than wire contract.
|
|
379
390
|
*
|
|
380
391
|
* Determinism: same store ⇒ same digest within a process, and across
|
|
381
|
-
* processes on the same architecture
|
|
382
|
-
* needs
|
|
392
|
+
* processes on the same architecture, which is all a lockstep replay
|
|
393
|
+
* needs, because both replays run the same algorithm on the same words.
|
|
383
394
|
*
|
|
384
395
|
* **Opt-in.** Throws `DETERMINISM_DISABLED` unless the
|
|
385
396
|
* Store was constructed with `{ deterministic: true }`. The canonical
|
|
386
397
|
* ordering this fold relies on (sparse `canonicalIndices`, sorted relation
|
|
387
398
|
* target sets) is the determinism tax the flag gates. */
|
|
388
399
|
stateHash(): number;
|
|
389
|
-
private
|
|
390
|
-
/** Look up the `EntityID` at `row` in archetype `archetype_id`.
|
|
391
|
-
*
|
|
392
|
-
* `
|
|
393
|
-
* `(
|
|
394
|
-
* and TS bridges it back through `ctx.emit(...)` via this method.
|
|
400
|
+
private _archGet;
|
|
401
|
+
/** Look up the `EntityID` at `row` in archetype `archetype_id`. A compute
|
|
402
|
+
* backend resolves an `EntityID` from an event-ring payload through it. The
|
|
403
|
+
* backend writes `(archId, row, …)` to the event ring, and TS bridges it
|
|
404
|
+
* back through `ctx.emit(...)` via this method.
|
|
395
405
|
*
|
|
396
406
|
* Throws `ECSError` if `archetype_id` is out of range or `row` is
|
|
397
|
-
* past the archetype's live row count
|
|
398
|
-
* ring
|
|
399
|
-
*
|
|
400
|
-
* surface. */
|
|
407
|
+
* past the archetype's live row count. Either one means a corrupt
|
|
408
|
+
* ring payload or a stale row index (an extend or a grow happened
|
|
409
|
+
* mid-tick), and both are defects. */
|
|
401
410
|
entityIdAtRow(archetypeId: number, row: number): EntityID;
|
|
402
|
-
/** Find or create an archetype for the given component mask
|
|
411
|
+
/** Find or create an archetype for the given component mask, see
|
|
403
412
|
* `ArchetypeGraph.getOrCreateFromMask`. */
|
|
404
|
-
private
|
|
405
|
-
/** Bulk variant of `
|
|
413
|
+
private _archGetOrCreateFromMask;
|
|
414
|
+
/** Bulk variant of `_archGetOrCreateFromMask`, one `extendColumnStore`
|
|
406
415
|
* call for the whole batch (the prewarm pass). See
|
|
407
|
-
* `ArchetypeGraph.
|
|
416
|
+
* `ArchetypeGraph.getOrCreateFromMasks`. */
|
|
408
417
|
archCreateManyFromMasks(masks: readonly BitSet[]): ArchetypeID[];
|
|
409
|
-
/**
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
*
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
418
|
+
/** Call `extendColumnStore` once with `newSpecs`, then refresh every
|
|
419
|
+
* pre-existing SAB-backed Archetype's TypedArray views when the extend had
|
|
420
|
+
* to realloc. The `existing` row counts are built only when that realloc
|
|
421
|
+
* path runs: the in-place path moves no rows and reads no list, and to walk
|
|
422
|
+
* every archetype on every extend made the cost of the N-th archetype grow
|
|
423
|
+
* with N. The bulk variant makes one extend for many archetypes, so the
|
|
424
|
+
* list is built at most one time for them all. */
|
|
425
|
+
private _extendStore;
|
|
426
|
+
/** Materialise the `Archetype` object for a freshly-minted graph node,
|
|
427
|
+
* binds the graph's topology to this store's column backing and grow
|
|
417
428
|
* handler (`ArchetypeGraphHost.materialize`). Store-owned so the graph
|
|
418
429
|
* never touches `_columnStore`. */
|
|
419
430
|
private _materializeArchetype;
|
|
420
|
-
/** Push a newly-installed archetype into every registered query whose masks
|
|
421
|
-
* it satisfies (`ArchetypeGraphHost.fanIntoQueries`; the query registry
|
|
422
|
-
* stays on Store). No epoch bump — see the note in `ArchetypeGraph.install`. */
|
|
423
|
-
private _fanIntoQueries;
|
|
424
431
|
/** Resolve "add component_id to archetype_id" → target ArchetypeID (edge-cached). */
|
|
425
|
-
private
|
|
432
|
+
private _archResolveAdd;
|
|
426
433
|
/** Resolve "remove component_id from archetype_id" → target ArchetypeID (edge-cached). */
|
|
427
|
-
private
|
|
434
|
+
private _archResolveRemove;
|
|
428
435
|
createEntity(): EntityID;
|
|
429
|
-
/** Allocate an entity slot
|
|
430
|
-
* the template spawn paths. Returns the packed `EntityID
|
|
431
|
-
* is left in `
|
|
436
|
+
/** Allocate an entity slot without placing it in the empty archetype, for
|
|
437
|
+
* the template spawn paths. Returns the packed `EntityID`. The slot index
|
|
438
|
+
* is left in `_entityAllocator.lastIndex`. Skips the empty-archetype
|
|
432
439
|
* membership write `createEntity` performs (the caller installs the real
|
|
433
440
|
* archetype + row). This *commits* the slot (bumps counts, stamps the
|
|
434
|
-
* generation so `isAlive` is already true), so the caller
|
|
441
|
+
* generation so `isAlive` is already true), so the caller must have
|
|
435
442
|
* reserved the column capacity for the row first
|
|
436
|
-
* (`Archetype.
|
|
443
|
+
* (`Archetype.reserveRows`), otherwise a cap throw from the
|
|
437
444
|
* subsequent append leaves the slot phantom-alive. */
|
|
438
445
|
private _allocEntity;
|
|
439
446
|
/** Pre-check that `count` fresh entity slots can be allocated without
|
|
@@ -441,17 +448,17 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
441
448
|
* `_allocEntity`'s own per-call high-water guard would otherwise
|
|
442
449
|
* throw `EID_MAX_INDEX_OVERFLOW` partway through the alloc loop, leaving the
|
|
443
450
|
* slots it already committed phantom-alive. Free-list reuse covers the first
|
|
444
|
-
* `entityFreeIndices.length` slots
|
|
451
|
+
* `entityFreeIndices.length` slots. Only the remainder draws down the
|
|
445
452
|
* high-water headroom. */
|
|
446
|
-
private
|
|
447
|
-
/**
|
|
453
|
+
private _assertEntityIndexCapacity;
|
|
454
|
+
/** Build a template: compute the target archetype (creating it if absent,
|
|
448
455
|
* fits the prewarm model), pre-flatten default field values into
|
|
449
456
|
* `_flatColumns` order, and build the override index (field name → flat
|
|
450
|
-
* column index
|
|
457
|
+
* column index. `TEMPLATE_OVERRIDE_AMBIGUOUS` for a name shared by more than
|
|
451
458
|
* one component, which a flat override cannot target). */
|
|
452
|
-
|
|
459
|
+
createTemplate(entries: readonly TemplateEntryData[]): Template;
|
|
453
460
|
/** Resolve an override key to its flat column index, with the DEV guards
|
|
454
|
-
* for unknown and ambiguous field names
|
|
461
|
+
* for unknown and ambiguous field names. `-1` means skip (the production
|
|
455
462
|
* fallback where DEV would have thrown). */
|
|
456
463
|
private _resolveOverrideColumn;
|
|
457
464
|
/** Apply per-instance overrides to the freshly-spawned row. Each key is a
|
|
@@ -465,20 +472,20 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
465
472
|
* applies any per-instance overrides. */
|
|
466
473
|
spawn(p: Template, overrides?: Record<string, number | undefined>): EntityID;
|
|
467
474
|
/** Bulk-spawn `count` identical entities into the template's archetype. The
|
|
468
|
-
* field writes are O(columns)
|
|
469
|
-
* `addEntitiesWithValues
|
|
475
|
+
* field writes are O(columns), one `TypedArray.fill` per column via
|
|
476
|
+
* `addEntitiesWithValues`, not O(count×columns). Returns the new ids in
|
|
470
477
|
* spawn order. */
|
|
471
478
|
spawnMany(p: Template, count: number, overrides?: Record<string, number | undefined>): EntityID[];
|
|
472
479
|
/** Immediately destroy an entity, removing it from its archetype.
|
|
473
480
|
*
|
|
474
|
-
* With no `delete
|
|
475
|
-
* case) this tears the one entity down and returns
|
|
481
|
+
* With no `delete` or `clear` target-cleanup policy registered (the common
|
|
482
|
+
* case) this tears the one entity down and returns, no allocation. When a
|
|
476
483
|
* policy is in play, a `delete`-target's sources are appended to a local
|
|
477
484
|
* work-list this method then drains in the same iterative pass:
|
|
478
485
|
* the `work.length` re-read drives chains and trees out without recursion, so
|
|
479
486
|
* depth is bounded by entity count, not tree depth. This mirrors the deferred
|
|
480
|
-
* `
|
|
481
|
-
* identical end state
|
|
487
|
+
* `flushDestroys` buffer mechanism, both paths are iterative and reach the
|
|
488
|
+
* identical end state. The only difference is the shared `pendingDestroy`
|
|
482
489
|
* buffer there vs. a local work-list here. `isAlive` dedups a source reached
|
|
483
490
|
* twice (diamonds) and terminates cycles, exactly as the generation guard does
|
|
484
491
|
* in the deferred loop. */
|
|
@@ -487,20 +494,20 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
487
494
|
* then recycle (or retire) its slot. Shared by both immediate-destroy entry
|
|
488
495
|
* points (the fast no-cascade path and the work-list driver in
|
|
489
496
|
* `destroyEntity`). When `cascade` is non-null, a `delete`-policy target's
|
|
490
|
-
* surviving sources are appended to it for the driver to drain
|
|
497
|
+
* surviving sources are appended to it for the driver to drain.
|
|
491
498
|
* `null` skips that collection for callers that cannot cascade. The caller
|
|
492
499
|
* must have already confirmed `id` is alive. */
|
|
493
500
|
private _destroyOne;
|
|
494
501
|
/**
|
|
495
|
-
* Liveness check, **fail-closed** against forged
|
|
502
|
+
* Liveness check, **fail-closed** against a forged, retired or out-of-bounds
|
|
496
503
|
* handles. For a general-purpose engine that may receive a handle from
|
|
497
|
-
* serialization,
|
|
504
|
+
* serialization, ipc, or any untrusted caller, three malformed inputs must read
|
|
498
505
|
* dead rather than alias a slot:
|
|
499
|
-
* - **Out of range
|
|
506
|
+
* - **Out of range**, an `id` outside the 31-bit packed space (`< 0` or
|
|
500
507
|
* `> MAX_ENTITY_ID`). Without this, the 20-bit index mask below silently
|
|
501
|
-
* folds garbage high bits onto a valid slot. (
|
|
502
|
-
* postMessage decode
|
|
503
|
-
* - **Tombstone generation
|
|
508
|
+
* folds garbage high bits onto a valid slot. (The snapshot decode and the
|
|
509
|
+
* `postMessage` decode apply the same bound.)
|
|
510
|
+
* - **Tombstone generation**, a handle carrying `RETIRED_GENERATION`, which
|
|
504
511
|
* the allocator stamps into a retired slot and never issues to a live
|
|
505
512
|
* entity, would otherwise match a retired slot's parked generation and read
|
|
506
513
|
* alive (the ABA tombstone, previously documented as a known gap).
|
|
@@ -511,18 +518,18 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
511
518
|
/**
|
|
512
519
|
* Liveness and the packed index in one result: the entity index if `id` is
|
|
513
520
|
* live, else `-1`. Same three fail-closed guards as `isAlive` (documented
|
|
514
|
-
* above), and the sole implementation of them
|
|
521
|
+
* above), and the sole implementation of them, `isAlive` is a comparison on
|
|
515
522
|
* top of this.
|
|
516
523
|
*
|
|
517
524
|
* Why it returns the index instead of a boolean: every by-id caller needs
|
|
518
|
-
*
|
|
519
|
-
* `hasComponent` called `isAlive(id)
|
|
520
|
-
* internally
|
|
521
|
-
* `
|
|
525
|
+
* both answers, and the pair used to cost two derivations of the same index.
|
|
526
|
+
* `hasComponent` called `isAlive(id)`, which computed `getEntityIndex(id)`
|
|
527
|
+
* internally, and then computed `getEntityIndex(id)` again to reach
|
|
528
|
+
* `_entityArchetypes`. The generational check has already touched the index. A
|
|
522
529
|
* caller that is about to index a parallel array with it should be handed the
|
|
523
530
|
* one that was computed, not re-derive it. The generations read is inlined
|
|
524
531
|
* here for the same reason, rather than delegated to
|
|
525
|
-
* `
|
|
532
|
+
* `_entityAllocator.isAliveIndex`, which stays as the index-domain entry point
|
|
526
533
|
* for callers that already hold an index.
|
|
527
534
|
*
|
|
528
535
|
* **This gives much less than it appears to give.** The estimate for this
|
|
@@ -531,7 +538,7 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
531
538
|
* the estimate. The work that we removed was truly not necessary. But V8
|
|
532
539
|
* already made both one-line functions inline, and it already removed most of
|
|
533
540
|
* the duplicated calculation. Therefore "the work is plainly not necessary" is
|
|
534
|
-
* not an argument about performance for a
|
|
541
|
+
* not an argument about performance for a jit compiler. This note stops the
|
|
535
542
|
* next reader from making the same estimate again.
|
|
536
543
|
*/
|
|
537
544
|
private _liveIndex;
|
|
@@ -539,32 +546,33 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
539
546
|
/** An archetype's row count moved from `preLen` to its current
|
|
540
547
|
* `arch.length` on a **shrink** (rows removed: the source of a transition, a
|
|
541
548
|
* destroy, a batch-source drain). Always marks SAB row counts dirty
|
|
542
|
-
* (the descriptor walk
|
|
543
|
-
* epoch only
|
|
549
|
+
* (the descriptor walk only needs "something moved"). It bumps the
|
|
550
|
+
* query-dirty epoch only when `length` crosses zero, the only case where
|
|
544
551
|
* `Query._nonEmptyArchetypes` can change on a shrink. Mutations that
|
|
545
552
|
* move row counts within the same side (6→5) leave the non-empty set unchanged
|
|
546
553
|
* and skip the bump.
|
|
547
554
|
*
|
|
548
|
-
* A shrink does **not** need the `enabledCount` crossing test
|
|
549
|
-
*
|
|
550
|
-
* archetype that keeps disabled rows
|
|
551
|
-
* query's non-empty list as a harmless stale *inclusion
|
|
552
|
-
* bound on `enabledCount` (now 0) iterate it zero times.
|
|
555
|
+
* A shrink does **not** need the `enabledCount` crossing test. The only
|
|
556
|
+
* enabled-count move it can make is 1→0, when the last enabled row leaves an
|
|
557
|
+
* archetype that keeps disabled rows. That leaves the archetype in a default
|
|
558
|
+
* query's non-empty list as a harmless stale *inclusion*. `count` and
|
|
559
|
+
* `forEach` bound on `enabledCount` (now 0), so they iterate it zero times.
|
|
560
|
+
* Only a **grow** into
|
|
553
561
|
* an all-disabled archetype can stale-*exclude* a live row, so the enabled
|
|
554
562
|
* crossing lives in `_onArchGrow`, off this path.
|
|
555
563
|
*
|
|
556
|
-
*
|
|
557
|
-
* once or twice
|
|
558
|
-
*
|
|
559
|
-
* An earlier change added an `if (
|
|
560
|
-
* gate to skip the bump for no-query workloads. The
|
|
561
|
-
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
private
|
|
566
|
-
/** An archetype **grew
|
|
567
|
-
* spawn, a batch-target fill). Like `
|
|
564
|
+
* Inlining-sensitive, keep the body tiny. Each immediate-mode `addComponent`
|
|
565
|
+
* or `removeComponent` calls it once or twice. The mutation hot path depends
|
|
566
|
+
* on the inline at every call site.
|
|
567
|
+
* An earlier change added an `if (_registeredQueries.length === 0) return;`
|
|
568
|
+
* gate to skip the bump for no-query workloads. The mutation churn loop got
|
|
569
|
+
* far slower, because the extra statement pushed the function past V8's
|
|
570
|
+
* per-call inlining budget. The gate is no longer in the code. Measure the
|
|
571
|
+
* mutation hot path before you merge a change here. Code review alone is
|
|
572
|
+
* not sufficient. */
|
|
573
|
+
private _onArchShrink;
|
|
574
|
+
/** An archetype **grew**, rows were appended (the target of a transition, a
|
|
575
|
+
* spawn, a batch-target fill). Like `_onArchShrink` it marks row counts
|
|
568
576
|
* dirty and bumps the query-dirty epoch on a `length` 0/non-zero crossing
|
|
569
577
|
* (`includeDisabled` membership), but it *also* bumps on an `enabledCount`
|
|
570
578
|
* 0→1 crossing. The non-empty filter is field-split: a default
|
|
@@ -573,12 +581,12 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
573
581
|
* enabledCount == 0`) crosses `enabledCount` 0→1 without touching `length`,
|
|
574
582
|
* so the `preLen` test alone (the earlier proxy, valid only while
|
|
575
583
|
* `enabledCount === length`) misses it and a cached default query keeps a stale
|
|
576
|
-
* `
|
|
584
|
+
* `nonEmptyArchs` list. Only grows can do this, so only grow sites carry the test.
|
|
577
585
|
*
|
|
578
586
|
* **Precondition: ≥1 row was appended** (every caller adds at least one row),
|
|
579
|
-
* so `arch.length > 0` afterward
|
|
580
|
-
* body stays inlinable (the inlining caveat on `
|
|
581
|
-
* here too
|
|
587
|
+
* so `arch.length > 0` afterward, which is why the crossings simplify and the
|
|
588
|
+
* body stays inlinable (the inlining caveat on `_onArchShrink` applies
|
|
589
|
+
* here too). The general
|
|
582
590
|
* `(pre === 0) !== (post === 0)` boundary test collapses given the post side:
|
|
583
591
|
* - `length`: post > 0 always ⇒ a crossing iff `preLen === 0`.
|
|
584
592
|
* - `enabledCount`: non-decreasing on a grow ⇒ a 0-crossing iff it was 0
|
|
@@ -587,17 +595,17 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
587
595
|
* read is short-circuited away on the hot path (`preLen` or `preEnabled`
|
|
588
596
|
* non-zero), so a no-disabled workload pays only two scalar compares. */
|
|
589
597
|
private _onArchGrow;
|
|
590
|
-
/** Dirty bookkeeping for an enable
|
|
591
|
-
* unchanged (no row added
|
|
592
|
-
* row counts
|
|
593
|
-
* snapshot see the new partition
|
|
594
|
-
* *enabled* count crossed 0
|
|
595
|
-
* a query's non-empty set
|
|
596
|
-
* is now `enabled_count
|
|
598
|
+
/** Dirty bookkeeping for an enable and disable toggle. `length` is
|
|
599
|
+
* unchanged (no row added or removed) but `enabled_count` moved, so: republish
|
|
600
|
+
* row counts, because the descriptor's `enabled_count` changed and a compute
|
|
601
|
+
* backend and the snapshot must see the new partition. Bump the query epoch only when
|
|
602
|
+
* the *enabled* count crossed 0. That is the boundary at which an archetype
|
|
603
|
+
* enters and leaves a query's non-empty set, because `Query.nonEmptyArchs`
|
|
604
|
+
* filters on `entityCount`, which is now `enabled_count`. */
|
|
597
605
|
private _onArchEnabledChange;
|
|
598
606
|
/** Immediately disable an entity (idempotent). The entity must hold at least
|
|
599
|
-
* one component
|
|
600
|
-
* cannot be partitioned (a `DEV` error
|
|
607
|
+
* one component, a component-less entity occupies no archetype row, so it
|
|
608
|
+
* cannot be partitioned (a `DEV` error, prod no-op). */
|
|
601
609
|
disableEntity(id: EntityID): void;
|
|
602
610
|
/** Immediately enable an entity (idempotent). */
|
|
603
611
|
enableEntity(id: EntityID): void;
|
|
@@ -605,53 +613,53 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
605
613
|
* disabled (it has no row to partition). */
|
|
606
614
|
isDisabled(id: EntityID): boolean;
|
|
607
615
|
/** 0-crossing detection for the per-entity flush paths (`_flushAdds`,
|
|
608
|
-
* `_flushRemoves`) without per-entity Map traffic
|
|
616
|
+
* `_flushRemoves`) without per-entity Map traffic, the same cost the
|
|
609
617
|
* destroy drain also avoids. Each touched archetype is stamped with the
|
|
610
618
|
* current flush epoch (`Archetype._flushSeenEpoch`), its pre-length and
|
|
611
|
-
* pre-enabled-count recorded on first sight (`_flushPreLen`
|
|
612
|
-
* `_flushPreEnabled`), and pushed onto this scratch list
|
|
619
|
+
* pre-enabled-count recorded on first sight (`_flushPreLen` and
|
|
620
|
+
* `_flushPreEnabled`), and pushed onto this scratch list
|
|
613
621
|
* `_settleFlushDirty` walks the list once after the loop. The field
|
|
614
622
|
* accesses per entity replace a `Map.has` + `Map.set` hash probe pair. The
|
|
615
623
|
* epoch is bumped at settle so the next flush re-records. */
|
|
616
624
|
private _flushEpoch;
|
|
617
625
|
private readonly _flushTouched;
|
|
618
626
|
/** Resolve dirty flags for a per-entity batch flush from the captured
|
|
619
|
-
* pre-counts. Marks row counts dirty if any archetype was touched
|
|
627
|
+
* pre-counts. Marks row counts dirty if any archetype was touched. Bumps
|
|
620
628
|
* the query epoch once if any touched archetype crossed the 0 boundary on
|
|
621
629
|
* *either* `length` (includeDisabled membership) or `enabledCount`
|
|
622
|
-
* (default-query membership)
|
|
623
|
-
* `
|
|
630
|
+
* (default-query membership), the deferred analog of the immediate
|
|
631
|
+
* `_onArchShrink` two-field check. A single bump is sufficient
|
|
624
632
|
* (queries only need to know "something changed"). Clears the touched list
|
|
625
633
|
* and advances the flush epoch on exit. */
|
|
626
634
|
private _settleFlushDirty;
|
|
627
635
|
destroyEntityDeferred(id: EntityID): void;
|
|
628
|
-
/** Buffer an enable
|
|
636
|
+
/** Buffer an enable and disable toggle for the phase flush. The row swap a
|
|
629
637
|
* toggle performs would corrupt a `forEach` over that archetype if applied
|
|
630
|
-
* mid-system, so it is deferred like add
|
|
638
|
+
* mid-system, so it is deferred like an add and a remove. */
|
|
631
639
|
disableEntityDeferred(id: EntityID): void;
|
|
632
640
|
enableEntityDeferred(id: EntityID): void;
|
|
633
|
-
/** Drain buffered enable
|
|
641
|
+
/** Drain buffered enable and disable toggles, applying each in operation order via
|
|
634
642
|
* the immediate path (which is idempotent and updates dirty flags). Called at
|
|
635
|
-
* the flush boundary after structural adds
|
|
643
|
+
* the flush boundary after structural adds and removes settle, so a toggle sees the
|
|
636
644
|
* entity's final archetype placement for the tick.
|
|
637
645
|
*
|
|
638
|
-
* When an onDisable
|
|
646
|
+
* When an onDisable and onEnable observer is registered (`_toggleObserverCount >
|
|
639
647
|
* 0`) this also collects effective toggle events into `_obsEvents` for
|
|
640
648
|
* the dispatch hook, collapsed to one event per *net* transition across the
|
|
641
649
|
* drain (see `_toggleInitial`). The no-observer path is byte-for-byte the
|
|
642
650
|
* earlier drain. */
|
|
643
651
|
private _flushToggles;
|
|
644
|
-
/** Fan one entity's net toggle transition out to an onDisable
|
|
652
|
+
/** Fan one entity's net toggle transition out to an onDisable and onEnable event
|
|
645
653
|
* per carried component. Walks the entity's archetype mask through the
|
|
646
|
-
* matching pre-bound bit visitor
|
|
654
|
+
* matching pre-bound bit visitor. A component-less entity (no row) carries
|
|
647
655
|
* nothing and is skipped. */
|
|
648
656
|
private _collectToggle;
|
|
649
657
|
get pendingToggleCount(): number;
|
|
650
658
|
/** Flush all buffered entity destructions in batch.
|
|
651
659
|
*
|
|
652
660
|
* When onRemove observers are registered (`_structuralObserverCount > 0`),
|
|
653
|
-
* a destroy fires onRemove for every component the entity carried
|
|
654
|
-
* *is* a remove of the whole mask
|
|
661
|
+
* a destroy fires onRemove for every component the entity carried, a destroy
|
|
662
|
+
* *is* a remove of the whole mask, collected here and dispatched by the
|
|
655
663
|
* `flushStructural` fixed-point loop, the only caller in that mode (it drains
|
|
656
664
|
* `pendingDestroy` each round so the trailing `ctx.flush()` call is a no-op).
|
|
657
665
|
* Same commit-then-observe discipline as `_flushRemoves`: the entity is fully
|
|
@@ -660,151 +668,227 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
660
668
|
* no-observer path is byte-for-byte unchanged (`collecting` gate).
|
|
661
669
|
*
|
|
662
670
|
* Re-entrancy: while the observed fixed point owns the flush, the loop
|
|
663
|
-
* drains destroys itself via `
|
|
671
|
+
* drains destroys itself via `_flushDestroys`, so a re-entrant
|
|
664
672
|
* `ctx.flush()` from a callback no-ops (the guard lives in
|
|
665
|
-
* `DeferredCommandBuffer.
|
|
673
|
+
* `DeferredCommandBuffer.flushDestroys`), otherwise it would collect
|
|
666
674
|
* into the shared `_obsEvents` scratch mid-dispatch and corrupt it. */
|
|
667
|
-
|
|
668
|
-
private
|
|
675
|
+
flushDestroys(): void;
|
|
676
|
+
private _flushDestroys;
|
|
669
677
|
get pendingDestroyCount(): number;
|
|
670
678
|
addComponentDeferred(entityId: EntityID, def: ComponentDef<Record<string, never>>): void;
|
|
671
679
|
addComponentDeferred<S extends ComponentSchema>(entityId: EntityID, def: ComponentDef<S>, values: FieldValues<S>): void;
|
|
672
680
|
removeComponentDeferred(entityId: EntityID, def: ComponentDef): void;
|
|
673
|
-
/** Phase-boundary structural flush. The drain policy
|
|
674
|
-
* path, observed fixed point (adds
|
|
675
|
-
* convergence guard, re-entrancy
|
|
676
|
-
|
|
677
|
-
* `
|
|
681
|
+
/** Phase-boundary structural flush. The drain policy, no-observer fast
|
|
682
|
+
* path, observed fixed point (adds and removes → destroys → toggles),
|
|
683
|
+
* convergence guard, re-entrancy, lives in `DeferredCommandBuffer`.
|
|
684
|
+
* The batch appliers it drives are the `_flush*` and
|
|
685
|
+
* `_flushDestroys` methods below. */
|
|
678
686
|
flushStructural(): void;
|
|
679
687
|
/** Batch-apply all deferred component additions. */
|
|
680
688
|
private _flushAdds;
|
|
681
689
|
/** Batch-apply all deferred component removals. */
|
|
682
690
|
private _flushRemoves;
|
|
683
691
|
get pendingStructuralCount(): number;
|
|
684
|
-
/**
|
|
685
|
-
*
|
|
692
|
+
/** Record what one consumer of the change feed asks the store to collect
|
|
693
|
+
* for `cid`, then apply the OR of every consumer's ask.
|
|
694
|
+
*
|
|
695
|
+
* `consumer` is the plugin name. The observer registry passes
|
|
696
|
+
* `"observers"`. One consumer dropping a flag never takes that flag away
|
|
697
|
+
* from another, which is why the merge sits in front of the transition
|
|
698
|
+
* logic. All-false is the same as absent. Cold path: a consumer calls this
|
|
699
|
+
* when it gains or loses an observer. */
|
|
700
|
+
configureObservation(consumer: string, cid: number, flags: ObservationFlags): void;
|
|
701
|
+
/** Set the per-component observation flags from the merged ask of every
|
|
702
|
+
* consumer for `cid`. Maintains `_structuralObserverCount` and
|
|
686
703
|
* `_toggleObserverCount` (the fast-path gates) and lazily allocates the
|
|
687
704
|
* dirty list when per-entity onSet tracking turns on. */
|
|
688
|
-
|
|
689
|
-
/**
|
|
690
|
-
*
|
|
691
|
-
*
|
|
692
|
-
*
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
*
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
*
|
|
703
|
-
|
|
705
|
+
private _applyObservation;
|
|
706
|
+
/** Give `cid` a row tick plane: one change tick for each row of every
|
|
707
|
+
* archetype that holds it, stamped by every write path. The row grain of
|
|
708
|
+
* change detection. An entity-level onSet observer calls this. Idempotent,
|
|
709
|
+
* and never undone. Cold. */
|
|
710
|
+
trackRows(def: ComponentHandle | SparseComponentDef): void;
|
|
711
|
+
/** Record what one consumer of the change feed asks the store to collect
|
|
712
|
+
* for sparse component `sid`, then apply the OR of every consumer's ask.
|
|
713
|
+
* Same merge rule as the dense form. Cold path. */
|
|
714
|
+
configureSparseObservation(consumer: string, sid: number, hasSet: boolean): void;
|
|
715
|
+
/** Row ticks on for sparse component `sid`, or the pending records dropped
|
|
716
|
+
* when the last consumer of its change feed leaves. */
|
|
717
|
+
private _applySparseObservation;
|
|
718
|
+
/** Collect the members of sparse component `sid` recorded since the last
|
|
719
|
+
* drain, for the entity-level onSet dispatch. `run` is the change tick of
|
|
720
|
+
* the dispatch. A member is alive by construction, because a destroy purges
|
|
721
|
+
* it, and the walk skips a disabled one, which default queries hide. The
|
|
722
|
+
* component-level change tick gates the walk, so an idle component costs
|
|
723
|
+
* one compare. Member order. The result array is reused. */
|
|
724
|
+
drainSparseSet(sid: number, run: number): EntityID[];
|
|
725
|
+
/** The row tick of `entityId`'s sparse component, 0 for a non-member, for
|
|
726
|
+
* `ctx.sparseChanged`. Throws when the component keeps no row ticks. */
|
|
727
|
+
sparseTickOf(def: SparseComponentDef, entityId: EntityID): number;
|
|
728
|
+
/** The store a mutable sparse cursor stamps through on each `at()`
|
|
729
|
+
* (ref.ts `createSparseCursor`). */
|
|
730
|
+
sparseTickPlane(def: SparseComponentDef): SparseComponentStore;
|
|
731
|
+
/** `trackRows` by component id, for the observer registry, which holds
|
|
732
|
+
* the id alone. */
|
|
733
|
+
private _trackRowsById;
|
|
734
|
+
/** The list length past which a frame switches to the scan. A list entry
|
|
735
|
+
* costs a push, three checks and a sort slot. A scan costs one compare per
|
|
736
|
+
* row of each stamped archetype, and those rows are at most the live
|
|
737
|
+
* entities, so a cap of a fraction of the live count keeps the list cost
|
|
738
|
+
* paid below the scan cost that replaces it, whatever the world's size. */
|
|
739
|
+
private _listCap;
|
|
740
|
+
/** Record a row for the entity-level onSet of `cid`, from a path that has
|
|
741
|
+
* resolved the archetype and the row (`setField`, `ref`, a cursor). Gated
|
|
742
|
+
* by the caller on `anyDirtyTracked`. Stamps the row tick, and pushes the
|
|
743
|
+
* entity onto the dirty list when the row's previous stamp lay at or below
|
|
744
|
+
* the last drain: the row is then new to the list. Hot path on the by-id
|
|
745
|
+
* writes of a tracked component: two loads, one compare, one store. */
|
|
746
|
+
noteSet(cid: number, arch: Archetype, row: number, eid: EntityID): void;
|
|
747
|
+
/** `noteSet` for a caller that holds the entity alone (`ctx.markChanged`).
|
|
748
|
+
* A dead entity, and one that does not hold the component, record nothing. */
|
|
749
|
+
noteSetEntity(def: ComponentHandle, eid: EntityID): void;
|
|
750
|
+
/** A chunk loop took the row tick column of `cid` (`cols.ticks`). Its
|
|
751
|
+
* stores make no list entry, so the next drain scans the plane. */
|
|
752
|
+
noteScan(cid: number): void;
|
|
753
|
+
/** Collect the rows recorded for `cid` since the last drain, for the
|
|
754
|
+
* entity-level onSet dispatch. `run` is the change tick of the dispatch.
|
|
755
|
+
*
|
|
756
|
+
* Two sources. `scanned` comes from a walk of the tick plane of every
|
|
757
|
+
* archetype stamped since the last drain, taken only in a frame where a
|
|
758
|
+
* chunk loop took `cols.ticks(def)`. A row inside the enabled partition is
|
|
759
|
+
* alive, a member and enabled by construction, so the dispatch fires these
|
|
760
|
+
* with no check, and the walk costs one compare per row of each stamped
|
|
761
|
+
* archetype. `listed` comes from the dirty list the by-id paths keep, minus
|
|
762
|
+
* the entries a scan covers. A listed entity may have died, lost the
|
|
763
|
+
* component or been disabled since its record, so the dispatch checks
|
|
764
|
+
* each. Both come back in row order, and the result object is reused. */
|
|
765
|
+
drainSet(cid: number, run: number): DrainResult;
|
|
704
766
|
/** Visit every non-empty archetype containing `cid` whose component-column
|
|
705
|
-
* changed
|
|
706
|
-
*
|
|
707
|
-
* per-archetype change tick (free
|
|
708
|
-
|
|
767
|
+
* changed after `baseline`, in canonical (ascending archetype-id) order,
|
|
768
|
+
* the archetype-granular onSet detection point. Reuses the existing
|
|
769
|
+
* per-archetype change tick (free, no write-path cost). `baseline` is the
|
|
770
|
+
* change tick of the consumer's previous visit, so a stamp equal to it was
|
|
771
|
+
* made by that visit and is not reported again. */
|
|
772
|
+
forEachChangedArchetype(cid: number, baseline: number, cb: (arch: Archetype) => void): void;
|
|
709
773
|
/** Enabled live entities currently carrying `cid`, used by `yieldExisting` to
|
|
710
774
|
* replay onAdd on registration. Bounded by `enabled_count`: a disabled
|
|
711
775
|
* entity is excluded from default queries, so seeding it via onAdd would
|
|
712
|
-
* publish a row that an immediate onDisable should have removed
|
|
713
|
-
* absent at seed (the "delete on disable" semantics). Unordered here
|
|
776
|
+
* publish a row that an immediate onDisable should have removed. It is
|
|
777
|
+
* absent at seed (the "delete on disable" semantics). Unordered here, the
|
|
714
778
|
* registry radix-sorts. */
|
|
715
|
-
|
|
779
|
+
collectEnabledWith(cid: number): EntityID[];
|
|
716
780
|
registerComponent<S extends Record<string, TypedArrayTag>>(schema: S, name?: string): ComponentDef<S>;
|
|
717
781
|
/** `'Pos' (component 5)` when the component was registered with a debug
|
|
718
|
-
* name, else `component 5
|
|
782
|
+
* name, else `component 5`, the label diagnostics interpolate. */
|
|
719
783
|
componentLabel(cid: number): string;
|
|
720
|
-
/**
|
|
721
|
-
*
|
|
722
|
-
*
|
|
723
|
-
* field_id)` pairs across the WASM FFI. */
|
|
784
|
+
/** The field index assigned to `(def, fieldName)` at registration. A system
|
|
785
|
+
* that passes `(component_id, field_id)` pairs across the WASM FFI resolves
|
|
786
|
+
* them once, at setup. */
|
|
724
787
|
fieldIdOf(def: ComponentHandle, fieldName: string): number;
|
|
725
788
|
/** Register a sparse component or tag. Unlike `registerComponent`, this
|
|
726
789
|
* allocates from a separate id space and never touches the archetype mask,
|
|
727
790
|
* so it does **not** count against `STORE_DESCRIPTOR_COMPONENT_LIMIT`. See
|
|
728
791
|
* `sparse_store.ts`. */
|
|
729
792
|
registerSparseComponent<S extends Record<string, TypedArrayTag>>(schema: S, name?: string): SparseComponentDef<S>;
|
|
730
|
-
/** Sparse sibling of `componentLabel
|
|
793
|
+
/** Sparse sibling of `componentLabel`, sparse ids are a separate id space. */
|
|
731
794
|
sparseLabel(sid: number): string;
|
|
732
|
-
/** Allocate the backing sparse store
|
|
733
|
-
* engine-internal backings whose `f64` holds an
|
|
795
|
+
/** Allocate the backing sparse store without the float guard, for
|
|
796
|
+
* engine-internal backings whose `f64` holds an exact integer rather than a
|
|
734
797
|
* user quantity: the exclusive-relation `{ target }` slot stores an `EntityID`
|
|
735
|
-
* (≤ 2^53, so f64 is bit-exact and cross-host identical
|
|
798
|
+
* (≤ 2^53, so f64 is bit-exact and cross-host identical, the ban targets float
|
|
736
799
|
* *arithmetic* rounding, which a target slot never undergoes). User schemas go
|
|
737
800
|
* through `registerSparseComponent`, which guards first. */
|
|
738
801
|
private _pushSparseStore;
|
|
739
|
-
private
|
|
802
|
+
private _sparseStoreOf;
|
|
740
803
|
/** Add (or overwrite) a sparse component on an entity. No archetype
|
|
741
|
-
* transition, no row copy
|
|
804
|
+
* transition, no row copy, the entity's `archetype_id` is unchanged. */
|
|
742
805
|
addSparse(entityId: EntityID, def: SparseComponentDef, values?: Record<string, number>): void;
|
|
743
806
|
/** Remove a sparse component from an entity. No-op if absent. */
|
|
744
807
|
removeSparse(entityId: EntityID, def: SparseComponentDef): void;
|
|
745
|
-
/** Total, like `hasComponent
|
|
808
|
+
/** Total, like `hasComponent`, `false` for a dead entity, never a throw. */
|
|
746
809
|
hasSparse(entityId: EntityID, def: SparseComponentDef): boolean;
|
|
747
810
|
getSparseField(entityId: EntityID, def: SparseComponentDef, field: string): number;
|
|
748
811
|
setSparseField(entityId: EntityID, def: SparseComponentDef, field: string, value: number): void;
|
|
749
812
|
/** Drop all sparse data for a destroyed entity index so a recycled slot
|
|
750
|
-
* can't inherit it. Gated by the caller on `
|
|
813
|
+
* can't inherit it. Gated by the caller on `_sparseStores.length > 0` to
|
|
751
814
|
* keep the destroy hot path free when sparse storage is unused. */
|
|
752
815
|
private _purgeSparse;
|
|
816
|
+
/** A sparse component's field names in schema order, the cursor's reserved
|
|
817
|
+
* name check (ref.ts). */
|
|
818
|
+
sparseFieldNames(def: SparseComponentDef): readonly string[];
|
|
819
|
+
/** A sparse component's accessor column array (ref.ts). Its identity is
|
|
820
|
+
* stable for the life of the store, so a cursor holds it from creation. */
|
|
821
|
+
sparseAccessorColumns(def: SparseComponentDef): AccessorColumns;
|
|
822
|
+
/**
|
|
823
|
+
* The DEV-only check a sparse cursor runs on every `at()` (ref.ts
|
|
824
|
+
* `createSparseCursor`): the access declaration (the same reason
|
|
825
|
+
* `cursorBinder` checks on `at()`), the liveness of the entity, and its
|
|
826
|
+
* membership. Production code never calls it, so a read of a non-member
|
|
827
|
+
* there gives whatever the column holds at that index, test with
|
|
828
|
+
* `hasSparse` first when the component can be absent, as `getSparseField`
|
|
829
|
+
* asks too.
|
|
830
|
+
*/
|
|
831
|
+
sparseCursorCheck(def: SparseComponentDef, write: boolean): SparseCursorCheck;
|
|
753
832
|
/** Serialize the sparse stores **and** relation side data to a self-contained
|
|
754
|
-
* byte buffer
|
|
755
|
-
* SAB snapshot). Two framed sections: the sparse stores
|
|
756
|
-
*
|
|
757
|
-
*
|
|
833
|
+
* byte buffer, the sparse half of a world snapshot (the dense half is the
|
|
834
|
+
* SAB snapshot). Two framed sections: the sparse stores
|
|
835
|
+
* (`snapshotSparseStores`, exclusive relation targets and multi membership
|
|
836
|
+
* ride here) followed
|
|
837
|
+
* by the relation side data (`snapshotRelations`, multi forward target
|
|
758
838
|
* sets, which live outside the sparse store). Both are written in canonical
|
|
759
839
|
* entity-index order, so two worlds with identical contents inserted in
|
|
760
840
|
* different orders snapshot byte-for-byte the same. The reverse index
|
|
761
|
-
* is derived and never serialized
|
|
841
|
+
* is derived and never serialized, `restoreSparse` rebuilds it. Pairs with
|
|
762
842
|
* `restoreSparse`.
|
|
763
843
|
*
|
|
764
844
|
* **Opt-in.** Throws `DETERMINISM_DISABLED` unless the
|
|
765
|
-
* Store was constructed with `{ deterministic: true }
|
|
845
|
+
* Store was constructed with `{ deterministic: true }`, the canonical
|
|
766
846
|
* entity-index ordering is the determinism tax the flag gates. */
|
|
767
847
|
snapshotSparse(): Uint8Array;
|
|
768
848
|
/** Repopulate the sparse stores from `snapshotSparse` bytes, replacing all
|
|
769
849
|
* current sparse data (full-equality round-trip of membership + data), then
|
|
770
850
|
* rebuild every relation's derived side indices: multi forward sets from the
|
|
771
851
|
* relation section, and the reverse index for both cardinalities (exclusive
|
|
772
|
-
* from the
|
|
852
|
+
* from the newly restored sparse target field, multi from the rebuilt forward
|
|
773
853
|
* sets). The sparse components and relations must already be registered in
|
|
774
|
-
* the same order
|
|
854
|
+
* the same order, restore carries data, not the registration (which is
|
|
775
855
|
* code). Throws `SparseRestoreError` if the snapshot's shape, field identity,
|
|
776
856
|
* entity-index bounds, or frame length don't validate.
|
|
777
857
|
*
|
|
778
858
|
* **Opt-in.** Throws `DETERMINISM_DISABLED` unless the
|
|
779
|
-
* Store was constructed with `{ deterministic: true }
|
|
859
|
+
* Store was constructed with `{ deterministic: true }`. Paired with
|
|
780
860
|
* `snapshotSparse`, which produces the canonical bytes restore consumes. */
|
|
781
861
|
restoreSparse(bytes: Uint8Array): void;
|
|
862
|
+
/** The members and their values are the snapshot's now, so no record made
|
|
863
|
+
* before the restore names a write of theirs. */
|
|
864
|
+
private _resetSparseTicks;
|
|
782
865
|
/**
|
|
783
866
|
* Capture the full live world to one self-contained byte buffer that
|
|
784
|
-
* `
|
|
785
|
-
* world and keep ticking"). Three sections
|
|
786
|
-
*
|
|
787
|
-
* (`
|
|
788
|
-
*
|
|
867
|
+
* `restore` can mount back onto a live, ticking world ("rewind a running
|
|
868
|
+
* world and keep ticking"). Three sections, which the snapshots plugin
|
|
869
|
+
* frames: the dense SAB
|
|
870
|
+
* column bytes (`columnStoreBytesView`), the sparse + relation bytes
|
|
871
|
+
* (`snapshotSparse`), and the host-side bookkeeping the SAB omits, the world
|
|
872
|
+
* tick, the entity recycle free-list (in live order, no byte source, and its
|
|
789
873
|
* order is load-bearing for byte-identical resume), the alive count, and each
|
|
790
|
-
* archetype's `length`
|
|
874
|
+
* archetype's `length` and `enabledCount`.
|
|
791
875
|
*
|
|
792
876
|
* **Opt-in.** Throws `DETERMINISM_DISABLED` unless constructed with
|
|
793
|
-
* `{ deterministic: true }
|
|
877
|
+
* `{ deterministic: true }`, the sparse section rides the canonical-ordering
|
|
794
878
|
* surface and byte-identical resume is a determinism property. Pairs with
|
|
795
|
-
* `
|
|
879
|
+
* `restore`.
|
|
796
880
|
*
|
|
797
|
-
*
|
|
798
|
-
* resource-free per-tick state
|
|
799
|
-
*
|
|
800
|
-
* are scheduling artifacts, never
|
|
801
|
-
* at a tick boundary
|
|
881
|
+
* Scope. It captures no resource and no event, because resume requires
|
|
882
|
+
* resource-free per-tick state and the tick clears events. It captures no
|
|
883
|
+
* change-detection baseline either, so a `changed()` query starts fresh.
|
|
884
|
+
* Those are scheduling artifacts, and never fold into `stateHash`. Take the
|
|
885
|
+
* snapshot at a tick boundary, between two `update()` calls. */
|
|
802
886
|
snapshot(): Uint8Array;
|
|
803
887
|
/**
|
|
804
888
|
* Mount a `snapshot()` buffer onto this live world and leave it ready to keep
|
|
805
889
|
* ticking. Fails closed on a malformed frame or a registration mismatch
|
|
806
|
-
*
|
|
807
|
-
* from code, not the snapshot
|
|
890
|
+
* before any live state is touched (the archetype and component graph is rebuilt
|
|
891
|
+
* from code, not the snapshot, same contract as `restoreSparse`). On
|
|
808
892
|
* success the world's dense + sparse state, entity allocator, and tick are
|
|
809
893
|
* exactly the captured world's.
|
|
810
894
|
*
|
|
@@ -812,43 +896,23 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
812
896
|
* snapshot's exactly (prewarm so the archetype set is stable) and the same
|
|
813
897
|
* entity-index capacity. **Opt-in:** throws `DETERMINISM_DISABLED`
|
|
814
898
|
* unless `{ deterministic: true }`. See `snapshot()` for the v1 scope. */
|
|
815
|
-
|
|
816
|
-
/** Adopt a restored dense store (
|
|
899
|
+
restore(bytes: Uint8Array): void;
|
|
900
|
+
/** Adopt a restored dense store (the snapshot service's restore mount
|
|
817
901
|
* step): swap the live backing, refresh every buffer-backed archetype's
|
|
818
902
|
* views, recover the allocator high-water from the restored region, and
|
|
819
903
|
* republish (the grow tail). Store-owned because it assigns
|
|
820
|
-
* `_columnStore
|
|
904
|
+
* `_columnStore`, the service never writes Store fields. */
|
|
821
905
|
private _mountRestoredDense;
|
|
822
|
-
/** Rebuild each SAB-backed archetype's host-side `length
|
|
823
|
-
* `_entityIds` after the dense backing
|
|
824
|
-
*
|
|
825
|
-
* entity-index region
|
|
826
|
-
* from the captured host
|
|
827
|
-
*
|
|
906
|
+
/** Rebuild each SAB-backed archetype's host-side `length`, `enabledCount`
|
|
907
|
+
* and `_entityIds` after `restore` swapped the dense backing. `length` and
|
|
908
|
+
* the per-row entity-id back-reference come from a scan of the restored
|
|
909
|
+
* entity-index region, which says what entity occupies what row.
|
|
910
|
+
* `enabledCount` comes from the captured host state, because the partition
|
|
911
|
+
* boundary is positional and has no per-entity byte source. */
|
|
828
912
|
private _reconstructHostRows;
|
|
829
|
-
registerRelation(opts?: RelationOptions): RelationDef;
|
|
830
|
-
/** Number of registered relations. Visible to tests asserting the
|
|
831
|
-
* no-transition invariant alongside `archetype_count`. */
|
|
832
|
-
get relationCount(): number;
|
|
833
|
-
addRelation(src: EntityID, def: RelationDef, tgt: EntityID): void;
|
|
834
|
-
removeRelation(src: EntityID, def: RelationDef, tgt?: EntityID): void;
|
|
835
|
-
targetOf(src: EntityID, def: RelationDef): EntityID | undefined;
|
|
836
|
-
targetsOf(src: EntityID, def: RelationDef): EntityID[];
|
|
837
|
-
sourcesOf(tgt: EntityID, def: RelationDef): EntityID[];
|
|
838
|
-
hasRelation(src: EntityID, def: RelationDef): boolean;
|
|
839
|
-
pairsOf(def: RelationDef): readonly (readonly [EntityID, EntityID])[];
|
|
840
|
-
sourcesOfAny(tgt: EntityID): readonly (readonly [RelationDef, EntityID])[];
|
|
841
|
-
relationBackingSparseId(def: RelationDef): SparseComponentID;
|
|
842
|
-
/** Drive a `(*, T)` wildcard query (`Query.forEachRelatedTo`) — see
|
|
843
|
-
* `RelationService.forEachRelationTargetMatch`. */
|
|
844
|
-
_forEachRelationTargetMatch(target: EntityID, include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], includeDisabled: boolean, cb: (entityId: EntityID) => void): void;
|
|
845
|
-
compactRelations(): number;
|
|
846
|
-
ancestorsOf(src: EntityID, def: RelationDef): EntityID[];
|
|
847
|
-
rootOf(src: EntityID, def: RelationDef): EntityID;
|
|
848
|
-
cascadeOf(root: EntityID, def: RelationDef): EntityID[];
|
|
849
913
|
/** Second query-match path: iterate entities matching a
|
|
850
914
|
* dense mask **and** sparse-membership terms, invoking `cb` per entity.
|
|
851
|
-
* Yields `EntityID`s, not archetype spans
|
|
915
|
+
* Yields `EntityID`s, not archetype spans, sparse members are scattered
|
|
852
916
|
* across archetypes, so there is no SoA column to hand back. Driven by the
|
|
853
917
|
* cheapest candidate set:
|
|
854
918
|
*
|
|
@@ -861,36 +925,44 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
861
925
|
* store.
|
|
862
926
|
* - **neither** → walk `denseArchetypes`' entity ids (dense-only fallback).
|
|
863
927
|
*
|
|
864
|
-
* Only reached via `Query.forEachEntity
|
|
928
|
+
* Only reached via `Query.forEachEntity`. Dense `forEach` never consults
|
|
865
929
|
* the sparse stores, so dense-only queries are unaffected. */
|
|
866
|
-
|
|
930
|
+
forEachSparseMatch(include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, terms: QueryTerms, denseArchetypes: readonly Archetype[], cb: (entityId: EntityID) => void): void;
|
|
867
931
|
/** Fourth query-match path: the matched set in hierarchy depth order
|
|
868
|
-
* (parents before children)
|
|
869
|
-
|
|
932
|
+
* (parents before children), see `forEachHierarchyMatch` on the relation service. */
|
|
933
|
+
forEachHierarchyMatch(include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, terms: QueryTerms, denseArchetypes: readonly Archetype[], relation: RelationDef, maxDepth: number, cb: (entityId: EntityID) => void): void;
|
|
934
|
+
/** Third query-match path: the `(*, T)` wildcard, every source pointing at
|
|
935
|
+
* one target. `Query.forEachRelatedTo` is the seam the user reaches. */
|
|
936
|
+
forEachTargetMatch(target: EntityID, include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, terms: QueryTerms, cb: (entityId: EntityID) => void): void;
|
|
937
|
+
/** The sparse membership store a relation rides, which is how a query turns
|
|
938
|
+
* a `(R, *)` term into a sparse term. `api` names the query verb the user
|
|
939
|
+
* called, because `andRelation` and `notRelation` both land here. */
|
|
940
|
+
relationBackingSparseId(def: RelationDef, api: string): SparseComponentID;
|
|
941
|
+
private readonly _scratchTargetMask;
|
|
870
942
|
addComponent(entityId: EntityID, def: ComponentDef<Record<string, never>>): void;
|
|
871
943
|
addComponent<S extends ComponentSchema>(entityId: EntityID, def: ComponentDef<S>, values: FieldValues<S>): void;
|
|
872
|
-
/** @internal
|
|
944
|
+
/** @internal, cold tail of `addComponent`: the entity already holds `def`
|
|
873
945
|
* (overwrite in place, no transition), or the (source, component) add edge
|
|
874
|
-
* has not been cached yet (first time this pair is seen
|
|
946
|
+
* has not been cached yet (first time this pair is seen, resolve, which
|
|
875
947
|
* plants the edge, then re-enter the hot body). Split out so the edge-hit
|
|
876
|
-
* path above stays a straight line with one holey-array probe
|
|
948
|
+
* path above stays a straight line with one holey-array probe. This runs at
|
|
877
949
|
* most once per (archetype, component) pair plus on in-place overwrites. */
|
|
878
950
|
private _addComponentCold;
|
|
879
951
|
/** Add multiple components in one transition (resolves final archetype, then moves once).
|
|
880
952
|
*
|
|
881
953
|
* Final-mask resolve, not graph walk. The previous implementation called
|
|
882
|
-
* `
|
|
883
|
-
* intermediate archetype on the path
|
|
954
|
+
* `_archResolveAdd` once per entry, which threaded through every
|
|
955
|
+
* intermediate archetype on the path, and each unseen intermediate
|
|
884
956
|
* triggered a fresh `extendColumnStore` even though no entity ever lived
|
|
885
957
|
* there. Computing the union mask up front and resolving once via
|
|
886
|
-
* `
|
|
958
|
+
* `_archGetOrCreateFromMask` collapses N-1 intermediate-archetype
|
|
887
959
|
* creations into zero for the batched case. The lazy
|
|
888
|
-
* single-mask path remains the same
|
|
960
|
+
* single-mask path remains the same. This only avoids feeding it
|
|
889
961
|
* archetypes the entity never visits.
|
|
890
962
|
*
|
|
891
963
|
* Composite-add edge cache. The final-mask resolve, unlike the
|
|
892
964
|
* single-add `edges[]` walk, re-pays a per-call `mask.hash()`, `ArchetypeGraph.lookup`
|
|
893
|
-
* (the Map-of-buckets + `equals` scan), and `
|
|
965
|
+
* (the Map-of-buckets + `equals` scan), and `transitionMapTo` on
|
|
894
966
|
* every call. That is much slower than a cached edge walk, and a probe put the
|
|
895
967
|
* cost on the two `Map.get` calls, and not on the hash. So a repeated (source,
|
|
896
968
|
* added-set) add now resolves through `currentArch`'s composite-add cache: one
|
|
@@ -899,37 +971,37 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
899
971
|
* the final-mask path below (no intermediate planting) and plants the edge. */
|
|
900
972
|
addComponents(entityId: EntityID, entries: readonly TemplateEntryData[]): void;
|
|
901
973
|
/** Shared move+write tail of `addComponents`: place the entity into
|
|
902
|
-
* the already-resolved `targetArch
|
|
974
|
+
* the already-resolved `targetArch`, a `moveEntityFrom` along the cached
|
|
903
975
|
* `map` when it has a row, else a fresh append (the rowless empty-archetype
|
|
904
|
-
* source ignores `map`)
|
|
976
|
+
* source ignores `map`), then write every entry's fields. Both the
|
|
905
977
|
* composite-edge-cache hit and the final-mask cold path funnel through here so
|
|
906
978
|
* the placement logic lives once. */
|
|
907
979
|
private _addComponentsInto;
|
|
908
980
|
removeComponent(entityId: EntityID, def: ComponentDef): void;
|
|
909
|
-
/** @internal
|
|
981
|
+
/** @internal, cold tail of `removeComponent`: the entity doesn't hold `def`
|
|
910
982
|
* (no-op), or the (source, component) remove edge has not been cached yet.
|
|
911
|
-
* Mirror of `_addComponentCold
|
|
983
|
+
* Mirror of `_addComponentCold`. Same depth-1 re-entry argument. */
|
|
912
984
|
private _removeComponentCold;
|
|
913
985
|
/** Remove multiple components in one transition (resolves final archetype, then moves once).
|
|
914
986
|
*
|
|
915
987
|
* Final-mask resolve, not graph walk. Same rationale as `addComponents`
|
|
916
|
-
* above
|
|
988
|
+
* above, the previous per-step path threaded `_archResolveRemove`
|
|
917
989
|
* once per def, which materialised every intermediate archetype on the
|
|
918
990
|
* removal path. Computing the difference mask up front and resolving
|
|
919
991
|
* once avoids planting N-1 intermediates the entity never lives in. */
|
|
920
992
|
removeComponents(entityId: EntityID, defs: ComponentDef[]): void;
|
|
921
|
-
/** Total: a dead
|
|
922
|
-
* than throwing
|
|
993
|
+
/** Total: a dead or stale `entityId` returns `false` rather
|
|
994
|
+
* than throwing, a "has" probe is exactly what callers reach for to avoid
|
|
923
995
|
* touching dead entities, so it must be safe to ask. */
|
|
924
996
|
hasComponent(entityId: EntityID, def: ComponentHandle): boolean;
|
|
925
997
|
/**
|
|
926
|
-
* Bulk add a component to
|
|
998
|
+
* Bulk add a component to all entities in the given archetype.
|
|
927
999
|
* Uses TypedArray.set() for O(columns) instead of O(N×columns).
|
|
928
1000
|
* The archetype must not already contain this component.
|
|
929
1001
|
*/
|
|
930
1002
|
batchAddComponent(src: ArchetypeID, def: ComponentDef, values?: Record<string, number>): void;
|
|
931
1003
|
/**
|
|
932
|
-
* Bulk remove a component from
|
|
1004
|
+
* Bulk remove a component from all entities in the given archetype.
|
|
933
1005
|
* Uses TypedArray.set() for O(columns) instead of O(N×columns).
|
|
934
1006
|
* The archetype must contain this component.
|
|
935
1007
|
*/
|
|
@@ -937,23 +1009,23 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
937
1009
|
getEntityArchetype(entityId: EntityID): Archetype;
|
|
938
1010
|
getEntityRow(entityId: EntityID): number;
|
|
939
1011
|
/**
|
|
940
|
-
* The row `resolveEntity` placed the entity at
|
|
1012
|
+
* The row `resolveEntity` placed the entity at, the alloc-free second
|
|
941
1013
|
* return value of a resolve, read immediately after the call. Same out-param
|
|
942
|
-
* pattern as `EntityAllocator.lastIndex` and `_moveResult
|
|
1014
|
+
* pattern as `EntityAllocator.lastIndex` and `_moveResult`. Returning a
|
|
943
1015
|
* `{ arch, row }` pair instead would allocate on every by-id read.
|
|
944
1016
|
*/
|
|
945
1017
|
resolvedRow: number;
|
|
946
1018
|
/**
|
|
947
|
-
* (archetype, row) for a by-id access, derived from
|
|
1019
|
+
* (archetype, row) for a by-id access, derived from one index computation.
|
|
948
1020
|
*
|
|
949
1021
|
* `getEntityArchetype` and `getEntityRow` are each one line, and every by-id
|
|
950
|
-
* caller needs both
|
|
1022
|
+
* caller needs both, so the pair cost two derivations of the same packed
|
|
951
1023
|
* index and two call frames to read two elements of two parallel arrays
|
|
952
1024
|
* addressed identically. This is that pair, fused: index once, publish the
|
|
953
1025
|
* row on `resolvedRow`, return the archetype.
|
|
954
1026
|
*
|
|
955
|
-
* The two single-purpose accessors stay above
|
|
956
|
-
* time
|
|
1027
|
+
* The two single-purpose accessors stay above, tests reach for one half at a
|
|
1028
|
+
* time, but no runtime path uses them in a pair any more.
|
|
957
1029
|
*/
|
|
958
1030
|
resolveEntity(entityId: EntityID): Archetype;
|
|
959
1031
|
/**
|
|
@@ -965,52 +1037,34 @@ export declare class Store implements ObserverHost, QueryHost {
|
|
|
965
1037
|
* `at()`: a mutable cursor bumps the component's change tick on every
|
|
966
1038
|
* repoint (matching `ctx.ref`), a read-only one never does.
|
|
967
1039
|
*
|
|
968
|
-
* The access check lives
|
|
1040
|
+
* The access check lives here, in the binder, and not only at the call that
|
|
969
1041
|
* creates the cursor. A cursor is made one time and then kept, so it outlives
|
|
970
|
-
* the span that made it
|
|
971
|
-
*
|
|
972
|
-
*
|
|
973
|
-
*
|
|
1042
|
+
* the span that made it. A cursor made at host level writes an undeclared
|
|
1043
|
+
* component when a system body uses it, because no system is active at
|
|
1044
|
+
* creation and the check there passes. A `ctx.cursor` that a system stores in
|
|
1045
|
+
* an outer variable does the same in the next system. Both slip
|
|
974
1046
|
* past a check that only runs at creation. `at()` is the point of use, so the
|
|
975
1047
|
* check belongs on it. The creation-site check stays as well: it fails early,
|
|
976
1048
|
* and its stack names the line that made the cursor.
|
|
977
1049
|
*/
|
|
978
1050
|
cursorBinder(def: ComponentHandle, stampTick: boolean): CursorBinder;
|
|
979
|
-
/** A component's field names in schema order
|
|
1051
|
+
/** A component's field names in schema order, the cursor prototype key and
|
|
980
1052
|
* ordinal source (ref.ts). One array per component, owned by its meta. */
|
|
981
1053
|
componentFieldNames(def: ComponentHandle): readonly string[];
|
|
982
1054
|
/**
|
|
983
|
-
* Find all archetypes matching the given masks.
|
|
984
|
-
*
|
|
985
|
-
*
|
|
1055
|
+
* Find all archetypes matching the given masks. Delegates to
|
|
1056
|
+
* `QueryRegistry`, which starts the superset scan from the smallest
|
|
1057
|
+
* component bucket. Query mint path only.
|
|
986
1058
|
*/
|
|
987
1059
|
getMatchingArchetypes(required: BitSet, excluded?: BitSet, anyOf?: BitSet): readonly Archetype[];
|
|
988
1060
|
/**
|
|
989
|
-
* Register a live query. Returns a mutable Archetype[] that
|
|
990
|
-
*
|
|
1061
|
+
* Register a live query. Returns a mutable Archetype[] that the registry
|
|
1062
|
+
* pushes newly-created matching archetypes into, keeping the query always
|
|
1063
|
+
* up-to-date.
|
|
991
1064
|
*/
|
|
992
1065
|
registerQuery(include: BitSet, exclude?: BitSet, anyOf?: BitSet): Archetype[];
|
|
993
1066
|
updateQueryRef(result: Archetype[], query: Query<any>): void;
|
|
994
1067
|
get archetypeCount(): number;
|
|
995
|
-
|
|
996
|
-
emitEvent(def: EventDef<any>, values: Record<string, number>): void;
|
|
997
|
-
emitSignal(def: EventDef<EmptyEventSchema>): void;
|
|
998
|
-
getEventReader<S extends EventShape<S>>(def: EventDef<S>): EventReader<S>;
|
|
999
|
-
clearEvents(): void;
|
|
1000
|
-
/** `DEV`-only mid-update emit detection — see
|
|
1001
|
-
* `EventRegistry.devBufferedEventCount`. */
|
|
1002
|
-
_devBufferedEventCount(): number;
|
|
1003
|
-
registerEventByKey<S extends EventShape<S>>(key: symbol, fields: readonly (keyof S & string)[]): EventDef<S>;
|
|
1004
|
-
getEventDefByKey(key: symbol): EventDef<any>;
|
|
1005
|
-
hasEventKey(key: symbol): boolean;
|
|
1006
|
-
private readonly resources;
|
|
1007
|
-
registerResource(key: symbol, value: unknown): void;
|
|
1008
|
-
getResource(key: symbol): unknown;
|
|
1009
|
-
setResource(key: symbol, value: unknown): void;
|
|
1010
|
-
/** Fails closed on a missing key; the present → absent → present
|
|
1011
|
-
* lifecycle — see `ResourceRegistry.remove`. */
|
|
1012
|
-
removeResource(key: symbol): void;
|
|
1013
|
-
hasResource(key: symbol): boolean;
|
|
1068
|
+
private readonly _resources;
|
|
1014
1069
|
}
|
|
1015
|
-
export {};
|
|
1016
1070
|
//# sourceMappingURL=store.d.ts.map
|