@oasys/oecs 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/CHANGELOG.md +553 -0
  2. package/README.md +207 -267
  3. package/dist/core/ecs/access_check.d.cts +77 -0
  4. package/dist/core/ecs/access_check.d.ts +77 -0
  5. package/dist/core/ecs/access_check.d.ts.map +1 -0
  6. package/dist/core/ecs/archetype.d.cts +486 -0
  7. package/dist/core/ecs/archetype.d.ts +486 -0
  8. package/dist/core/ecs/archetype.d.ts.map +1 -0
  9. package/dist/core/ecs/archetype_graph.d.cts +96 -0
  10. package/dist/core/ecs/archetype_graph.d.ts +96 -0
  11. package/dist/core/ecs/archetype_graph.d.ts.map +1 -0
  12. package/dist/core/ecs/builtin_relations.d.cts +43 -0
  13. package/dist/core/ecs/builtin_relations.d.ts +43 -0
  14. package/dist/core/ecs/builtin_relations.d.ts.map +1 -0
  15. package/dist/core/ecs/command_log.d.cts +116 -0
  16. package/dist/core/ecs/command_log.d.ts +116 -0
  17. package/dist/core/ecs/command_log.d.ts.map +1 -0
  18. package/dist/core/ecs/component.d.cts +176 -0
  19. package/dist/core/ecs/component.d.ts +176 -0
  20. package/dist/core/ecs/component.d.ts.map +1 -0
  21. package/dist/core/ecs/compute_backend.d.cts +37 -0
  22. package/dist/core/ecs/compute_backend.d.ts +37 -0
  23. package/dist/core/ecs/compute_backend.d.ts.map +1 -0
  24. package/dist/core/ecs/debug_names.d.cts +7 -0
  25. package/dist/core/ecs/debug_names.d.ts +7 -0
  26. package/dist/core/ecs/debug_names.d.ts.map +1 -0
  27. package/dist/core/ecs/deferred_commands.d.cts +55 -0
  28. package/dist/core/ecs/deferred_commands.d.ts +55 -0
  29. package/dist/core/ecs/deferred_commands.d.ts.map +1 -0
  30. package/dist/core/ecs/dispatch_trace.d.cts +93 -0
  31. package/dist/core/ecs/dispatch_trace.d.ts +93 -0
  32. package/dist/core/ecs/dispatch_trace.d.ts.map +1 -0
  33. package/dist/core/ecs/ecs.d.cts +562 -0
  34. package/dist/core/ecs/ecs.d.ts +562 -0
  35. package/dist/core/ecs/ecs.d.ts.map +1 -0
  36. package/dist/core/ecs/ecs_memory.d.cts +179 -0
  37. package/dist/core/ecs/ecs_memory.d.ts +179 -0
  38. package/dist/core/ecs/ecs_memory.d.ts.map +1 -0
  39. package/dist/core/ecs/entity.d.cts +34 -0
  40. package/dist/core/ecs/entity.d.ts +34 -0
  41. package/dist/core/ecs/entity.d.ts.map +1 -0
  42. package/dist/core/ecs/entity_allocator.d.cts +59 -0
  43. package/dist/core/ecs/entity_allocator.d.ts +59 -0
  44. package/dist/core/ecs/entity_allocator.d.ts.map +1 -0
  45. package/dist/core/ecs/event.d.cts +79 -0
  46. package/dist/core/ecs/event.d.ts +79 -0
  47. package/dist/core/ecs/event.d.ts.map +1 -0
  48. package/dist/core/ecs/event_registry.d.cts +22 -0
  49. package/dist/core/ecs/event_registry.d.ts +22 -0
  50. package/dist/core/ecs/event_registry.d.ts.map +1 -0
  51. package/dist/core/ecs/facades.d.cts +158 -0
  52. package/dist/core/ecs/facades.d.ts +158 -0
  53. package/dist/core/ecs/facades.d.ts.map +1 -0
  54. package/dist/core/ecs/frame_stepper.d.cts +58 -0
  55. package/dist/core/ecs/frame_stepper.d.ts +58 -0
  56. package/dist/core/ecs/frame_stepper.d.ts.map +1 -0
  57. package/dist/core/ecs/frame_trace.d.cts +133 -0
  58. package/dist/core/ecs/frame_trace.d.ts +133 -0
  59. package/dist/core/ecs/frame_trace.d.ts.map +1 -0
  60. package/dist/core/ecs/host_commands.d.cts +274 -0
  61. package/dist/core/ecs/host_commands.d.ts +274 -0
  62. package/dist/core/ecs/host_commands.d.ts.map +1 -0
  63. package/dist/core/ecs/index.d.cts +46 -0
  64. package/dist/core/ecs/index.d.ts +46 -0
  65. package/dist/core/ecs/index.d.ts.map +1 -0
  66. package/dist/core/ecs/observer.d.cts +173 -0
  67. package/dist/core/ecs/observer.d.ts +173 -0
  68. package/dist/core/ecs/observer.d.ts.map +1 -0
  69. package/dist/core/ecs/query.d.cts +718 -0
  70. package/dist/core/ecs/query.d.ts +718 -0
  71. package/dist/core/ecs/query.d.ts.map +1 -0
  72. package/dist/core/ecs/ref.d.cts +31 -0
  73. package/dist/core/ecs/ref.d.ts +31 -0
  74. package/dist/core/ecs/ref.d.ts.map +1 -0
  75. package/dist/core/ecs/relation.d.cts +243 -0
  76. package/dist/core/ecs/relation.d.ts +243 -0
  77. package/dist/core/ecs/relation.d.ts.map +1 -0
  78. package/dist/core/ecs/relation_service.d.cts +235 -0
  79. package/dist/core/ecs/relation_service.d.ts +235 -0
  80. package/dist/core/ecs/relation_service.d.ts.map +1 -0
  81. package/dist/core/ecs/resource.d.cts +53 -0
  82. package/dist/core/ecs/resource.d.ts +53 -0
  83. package/dist/core/ecs/resource.d.ts.map +1 -0
  84. package/dist/core/ecs/resource_registry.d.cts +20 -0
  85. package/dist/core/ecs/resource_registry.d.ts +20 -0
  86. package/dist/core/ecs/resource_registry.d.ts.map +1 -0
  87. package/dist/core/ecs/resume.d.cts +85 -0
  88. package/dist/core/ecs/resume.d.ts +85 -0
  89. package/dist/core/ecs/resume.d.ts.map +1 -0
  90. package/dist/core/ecs/run_condition.d.cts +81 -0
  91. package/dist/core/ecs/run_condition.d.ts +81 -0
  92. package/dist/core/ecs/run_condition.d.ts.map +1 -0
  93. package/dist/core/ecs/schedule.d.cts +142 -0
  94. package/dist/core/ecs/schedule.d.ts +142 -0
  95. package/dist/core/ecs/schedule.d.ts.map +1 -0
  96. package/dist/core/ecs/snapshot_service.d.cts +94 -0
  97. package/dist/core/ecs/snapshot_service.d.ts +94 -0
  98. package/dist/core/ecs/snapshot_service.d.ts.map +1 -0
  99. package/dist/core/ecs/sparse_store.d.cts +110 -0
  100. package/dist/core/ecs/sparse_store.d.ts +110 -0
  101. package/dist/core/ecs/sparse_store.d.ts.map +1 -0
  102. package/dist/core/ecs/store.d.cts +950 -0
  103. package/dist/core/ecs/store.d.ts +950 -0
  104. package/dist/core/ecs/store.d.ts.map +1 -0
  105. package/dist/core/ecs/store_layout_listener.d.cts +23 -0
  106. package/dist/core/ecs/store_layout_listener.d.ts +23 -0
  107. package/dist/core/ecs/store_layout_listener.d.ts.map +1 -0
  108. package/dist/core/ecs/system.d.cts +250 -0
  109. package/dist/core/ecs/system.d.ts +250 -0
  110. package/dist/core/ecs/system.d.ts.map +1 -0
  111. package/dist/core/ecs/utils/arrays.d.cts +7 -0
  112. package/dist/{utils → core/ecs/utils}/arrays.d.ts +2 -1
  113. package/dist/core/ecs/utils/arrays.d.ts.map +1 -0
  114. package/dist/core/ecs/utils/constants.d.ts +12 -0
  115. package/dist/core/ecs/utils/constants.d.ts.map +1 -0
  116. package/dist/core/ecs/utils/error.d.cts +61 -0
  117. package/dist/core/ecs/utils/error.d.ts +61 -0
  118. package/dist/core/ecs/utils/error.d.ts.map +1 -0
  119. package/dist/core/store/action_ring.d.cts +136 -0
  120. package/dist/core/store/action_ring.d.ts +136 -0
  121. package/dist/core/store/action_ring.d.ts.map +1 -0
  122. package/dist/core/store/allocator.d.cts +238 -0
  123. package/dist/core/store/allocator.d.ts +238 -0
  124. package/dist/core/store/allocator.d.ts.map +1 -0
  125. package/dist/core/store/buffer_backed_column.d.cts +69 -0
  126. package/dist/core/store/buffer_backed_column.d.ts +69 -0
  127. package/dist/core/store/buffer_backed_column.d.ts.map +1 -0
  128. package/dist/core/store/column_store.d.cts +273 -0
  129. package/dist/core/store/column_store.d.ts +273 -0
  130. package/dist/core/store/column_store.d.ts.map +1 -0
  131. package/dist/core/store/command_dispatch.d.cts +52 -0
  132. package/dist/core/store/command_dispatch.d.ts +52 -0
  133. package/dist/core/store/command_dispatch.d.ts.map +1 -0
  134. package/dist/core/store/command_ring.d.cts +107 -0
  135. package/dist/core/store/command_ring.d.ts +107 -0
  136. package/dist/core/store/command_ring.d.ts.map +1 -0
  137. package/dist/core/store/descriptor.d.cts +80 -0
  138. package/dist/core/store/descriptor.d.ts +80 -0
  139. package/dist/core/store/descriptor.d.ts.map +1 -0
  140. package/dist/core/store/entity_index.d.cts +108 -0
  141. package/dist/core/store/entity_index.d.ts +108 -0
  142. package/dist/core/store/entity_index.d.ts.map +1 -0
  143. package/dist/core/store/event_ring.d.cts +95 -0
  144. package/dist/core/store/event_ring.d.ts +95 -0
  145. package/dist/core/store/event_ring.d.ts.map +1 -0
  146. package/dist/core/store/extend.d.cts +39 -0
  147. package/dist/core/store/extend.d.ts +39 -0
  148. package/dist/core/store/extend.d.ts.map +1 -0
  149. package/dist/core/store/grow.d.cts +34 -0
  150. package/dist/core/store/grow.d.ts +34 -0
  151. package/dist/core/store/grow.d.ts.map +1 -0
  152. package/dist/core/store/header.d.cts +64 -0
  153. package/dist/core/store/header.d.ts +64 -0
  154. package/dist/core/store/header.d.ts.map +1 -0
  155. package/dist/core/store/index.d.cts +17 -0
  156. package/dist/core/store/index.d.ts +17 -0
  157. package/dist/core/store/index.d.ts.map +1 -0
  158. package/dist/core/store/layout_ops.d.cts +152 -0
  159. package/dist/core/store/layout_ops.d.ts +152 -0
  160. package/dist/core/store/layout_ops.d.ts.map +1 -0
  161. package/dist/core/store/region_table.d.cts +74 -0
  162. package/dist/core/store/region_table.d.ts +74 -0
  163. package/dist/core/store/region_table.d.ts.map +1 -0
  164. package/dist/core/store/snapshot.d.cts +43 -0
  165. package/dist/core/store/snapshot.d.ts +43 -0
  166. package/dist/core/store/snapshot.d.ts.map +1 -0
  167. package/dist/core/store/state_hash.d.cts +38 -0
  168. package/dist/core/store/state_hash.d.ts +38 -0
  169. package/dist/core/store/state_hash.d.ts.map +1 -0
  170. package/dist/core/store/store_regions.d.cts +38 -0
  171. package/dist/core/store/store_regions.d.ts +38 -0
  172. package/dist/core/store/store_regions.d.ts.map +1 -0
  173. package/dist/core/store/vendored_abi/abi.d.cts +43 -0
  174. package/dist/core/store/vendored_abi/abi.d.ts +43 -0
  175. package/dist/core/store/vendored_abi/abi.d.ts.map +1 -0
  176. package/dist/dev_flag.d.cts +17 -0
  177. package/dist/dev_flag.d.ts +17 -0
  178. package/dist/dev_flag.d.ts.map +1 -0
  179. package/dist/extensions/editor/editor.d.cts +170 -0
  180. package/dist/extensions/editor/editor.d.ts +170 -0
  181. package/dist/extensions/editor/editor.d.ts.map +1 -0
  182. package/dist/extensions/editor/field_handle.d.cts +40 -0
  183. package/dist/extensions/editor/field_handle.d.ts +40 -0
  184. package/dist/extensions/editor/field_handle.d.ts.map +1 -0
  185. package/dist/extensions/editor/index.cjs +1 -0
  186. package/dist/extensions/editor/index.d.cts +21 -0
  187. package/dist/extensions/editor/index.d.ts +21 -0
  188. package/dist/extensions/editor/index.d.ts.map +1 -0
  189. package/dist/extensions/editor/index.js +237 -0
  190. package/dist/extensions/reactive/ecs_sync.d.cts +214 -0
  191. package/dist/extensions/reactive/ecs_sync.d.ts +214 -0
  192. package/dist/extensions/reactive/ecs_sync.d.ts.map +1 -0
  193. package/dist/extensions/reactive/index.cjs +1 -0
  194. package/dist/extensions/reactive/index.d.cts +23 -0
  195. package/dist/extensions/reactive/index.d.ts +23 -0
  196. package/dist/extensions/reactive/index.d.ts.map +1 -0
  197. package/dist/extensions/reactive/index.js +215 -0
  198. package/dist/extensions/solid/index.cjs +1 -0
  199. package/dist/extensions/solid/index.d.cts +6 -0
  200. package/dist/extensions/solid/index.d.ts +6 -0
  201. package/dist/extensions/solid/index.d.ts.map +1 -0
  202. package/dist/extensions/solid/index.js +36 -0
  203. package/dist/extensions/solid/kernel_solid.d.cts +45 -0
  204. package/dist/extensions/solid/kernel_solid.d.ts +45 -0
  205. package/dist/extensions/solid/kernel_solid.d.ts.map +1 -0
  206. package/dist/host_commands-BF8QMi3c.cjs +1 -0
  207. package/dist/host_commands-i4cAeyL5.js +2318 -0
  208. package/dist/index.cjs +1 -1
  209. package/dist/index.d.cts +66 -0
  210. package/dist/index.d.ts +65 -12
  211. package/dist/index.d.ts.map +1 -1
  212. package/dist/index.js +7080 -1289
  213. package/dist/internal.cjs +2 -0
  214. package/dist/internal.d.cts +20 -0
  215. package/dist/internal.d.ts +20 -0
  216. package/dist/internal.d.ts.map +1 -0
  217. package/dist/internal.js +141 -0
  218. package/dist/interop-CT-REx0W.cjs +1 -0
  219. package/dist/interop-CcY6ASQc.js +18 -0
  220. package/dist/kernel-DgyrLFjW.js +227 -0
  221. package/dist/kernel-yWV3XnAb.cjs +1 -0
  222. package/dist/primitives.cjs +1 -0
  223. package/dist/primitives.d.cts +18 -0
  224. package/dist/primitives.d.ts +18 -0
  225. package/dist/primitives.d.ts.map +1 -0
  226. package/dist/primitives.js +45 -0
  227. package/dist/reactive/array.d.cts +24 -0
  228. package/dist/reactive/array.d.ts +24 -0
  229. package/dist/reactive/array.d.ts.map +1 -0
  230. package/dist/reactive/index.cjs +1 -0
  231. package/dist/reactive/index.d.cts +11 -0
  232. package/dist/reactive/index.d.ts +11 -0
  233. package/dist/reactive/index.d.ts.map +1 -0
  234. package/dist/reactive/index.js +18 -0
  235. package/dist/reactive/interop.d.cts +19 -0
  236. package/dist/reactive/interop.d.ts +19 -0
  237. package/dist/reactive/interop.d.ts.map +1 -0
  238. package/dist/reactive/kernel.d.cts +73 -0
  239. package/dist/reactive/kernel.d.ts +73 -0
  240. package/dist/reactive/kernel.d.ts.map +1 -0
  241. package/dist/reactive/map.d.cts +16 -0
  242. package/dist/reactive/map.d.ts +16 -0
  243. package/dist/reactive/map.d.ts.map +1 -0
  244. package/dist/reactive/shallow.d.cts +11 -0
  245. package/dist/reactive/shallow.d.ts +11 -0
  246. package/dist/reactive/shallow.d.ts.map +1 -0
  247. package/dist/reactive/struct.d.cts +10 -0
  248. package/dist/reactive/struct.d.ts +10 -0
  249. package/dist/reactive/struct.d.ts.map +1 -0
  250. package/dist/shallow-DQ8aG51_.cjs +1 -0
  251. package/dist/shallow-DfnAm9vG.js +150 -0
  252. package/dist/shared-BU1Cd40h.js +103 -0
  253. package/dist/shared-BymrGTyR.cjs +1 -0
  254. package/dist/shared.cjs +1 -0
  255. package/dist/shared.d.cts +22 -0
  256. package/dist/shared.d.ts +22 -0
  257. package/dist/shared.d.ts.map +1 -0
  258. package/dist/shared.js +7 -0
  259. package/dist/topological_sort-BDvEyb9W.cjs +1 -0
  260. package/dist/topological_sort-DK6EjpWa.js +135 -0
  261. package/dist/type_primitives/assertions.d.cts +32 -0
  262. package/dist/type_primitives/assertions.d.ts +25 -9
  263. package/dist/type_primitives/assertions.d.ts.map +1 -1
  264. package/dist/type_primitives/binary_heap/binary_heap.d.cts +37 -0
  265. package/dist/type_primitives/binary_heap/binary_heap.d.ts +6 -2
  266. package/dist/type_primitives/binary_heap/binary_heap.d.ts.map +1 -1
  267. package/dist/type_primitives/bitset/bitset.d.cts +54 -0
  268. package/dist/type_primitives/bitset/bitset.d.ts +16 -4
  269. package/dist/type_primitives/bitset/bitset.d.ts.map +1 -1
  270. package/dist/type_primitives/brand.d.cts +23 -0
  271. package/dist/type_primitives/brand.d.ts +6 -1
  272. package/dist/type_primitives/brand.d.ts.map +1 -1
  273. package/dist/type_primitives/error.d.cts +16 -0
  274. package/dist/type_primitives/error.d.ts +8 -3
  275. package/dist/type_primitives/error.d.ts.map +1 -1
  276. package/dist/type_primitives/index.d.cts +13 -0
  277. package/dist/type_primitives/index.d.ts +12 -9
  278. package/dist/type_primitives/index.d.ts.map +1 -1
  279. package/dist/type_primitives/sparse_map/sparse_map.d.cts +30 -0
  280. package/dist/type_primitives/sparse_map/sparse_map.d.ts +7 -3
  281. package/dist/type_primitives/sparse_map/sparse_map.d.ts.map +1 -1
  282. package/dist/type_primitives/sparse_set/sparse_set.d.cts +28 -0
  283. package/dist/type_primitives/sparse_set/sparse_set.d.ts +4 -0
  284. package/dist/type_primitives/sparse_set/sparse_set.d.ts.map +1 -1
  285. package/dist/type_primitives/topological_sort/topological_sort.d.cts +29 -0
  286. package/dist/type_primitives/topological_sort/topological_sort.d.ts +7 -3
  287. package/dist/type_primitives/topological_sort/topological_sort.d.ts.map +1 -1
  288. package/dist/type_primitives/typed_arrays/typed_arrays.d.cts +127 -0
  289. package/dist/type_primitives/typed_arrays/typed_arrays.d.ts +53 -16
  290. package/dist/type_primitives/typed_arrays/typed_arrays.d.ts.map +1 -1
  291. package/dist/typed_arrays-BcXcnzB4.js +258 -0
  292. package/dist/typed_arrays-D3NmwtCG.cjs +1 -0
  293. package/dist/utils/error.d.cts +6 -0
  294. package/dist/utils/error.d.ts +2 -20
  295. package/dist/utils/error.d.ts.map +1 -1
  296. package/dist/version.d.cts +10 -0
  297. package/dist/version.d.ts +10 -0
  298. package/dist/version.d.ts.map +1 -0
  299. package/package.json +115 -5
  300. package/dist/archetype.d.ts +0 -108
  301. package/dist/archetype.d.ts.map +0 -1
  302. package/dist/component.d.ts +0 -45
  303. package/dist/component.d.ts.map +0 -1
  304. package/dist/ecs.d.ts +0 -104
  305. package/dist/ecs.d.ts.map +0 -1
  306. package/dist/entity.d.ts +0 -11
  307. package/dist/entity.d.ts.map +0 -1
  308. package/dist/event.d.ts +0 -30
  309. package/dist/event.d.ts.map +0 -1
  310. package/dist/query.d.ts +0 -94
  311. package/dist/query.d.ts.map +0 -1
  312. package/dist/ref.d.ts +0 -23
  313. package/dist/ref.d.ts.map +0 -1
  314. package/dist/resource.d.ts +0 -23
  315. package/dist/resource.d.ts.map +0 -1
  316. package/dist/schedule.d.ts +0 -45
  317. package/dist/schedule.d.ts.map +0 -1
  318. package/dist/store.d.ts +0 -118
  319. package/dist/store.d.ts.map +0 -1
  320. package/dist/system.d.ts +0 -16
  321. package/dist/system.d.ts.map +0 -1
  322. package/dist/utils/arrays.d.ts.map +0 -1
  323. package/dist/utils/constants.d.ts.map +0 -1
  324. /package/dist/{utils/constants.d.ts → core/ecs/utils/constants.d.cts} +0 -0
@@ -0,0 +1,273 @@
1
+ import { StoreHeader } from './header.cjs';
2
+ import { ArchetypeDescriptor, TypeTagValue } from './descriptor.cjs';
3
+ import { BufferAllocator } from './allocator.cjs';
4
+ import { COMMAND_RING_DEFAULT_CAPACITY_SLOTS } from './command_ring.cjs';
5
+ import { ENTITY_INDEX_DEFAULT_CAPACITY } from './entity_index.cjs';
6
+ import { EVENT_RING_DEFAULT_CAPACITY_SLOTS } from './event_ring.cjs';
7
+ import { StoreRegionSpec } from './region_table.cjs';
8
+ /** Caller-facing column spec — no `byte_off` yet, the store computes it. */
9
+ export interface ColumnSpec {
10
+ readonly componentId: number;
11
+ readonly fieldId: number;
12
+ readonly typeTag: TypeTagValue;
13
+ }
14
+ /** Caller-facing archetype spec — no `column_count` (derived) and no
15
+ * `byte_off`s in the columns; both are computed during sizing. */
16
+ export interface ArchetypeSpec {
17
+ readonly archetypeId: number;
18
+ /** Component bitmask, `COMPONENT_MASK_WORDS` little-endian u32 words. */
19
+ readonly componentMask: readonly number[];
20
+ readonly rowCapacity: number;
21
+ readonly columns: readonly ColumnSpec[];
22
+ }
23
+ /** A single column's view after allocation. The `byte_off` matches what
24
+ * was recorded in the layout descriptor; `view` is a TypedArray of the
25
+ * right element type, length `row_capacity`, backed by the SAB. */
26
+ export interface ColumnView {
27
+ readonly componentId: number;
28
+ readonly fieldId: number;
29
+ readonly typeTag: TypeTagValue;
30
+ readonly byteOff: number;
31
+ readonly stride: number;
32
+ readonly view: AnyTypedArray;
33
+ }
34
+ /** Views for all columns in a single archetype, indexed by a numeric
35
+ * key encoding `(component_id, field_id)` so a (cid, fid) pair maps to
36
+ * its column in O(1). The encoding (see `columnKey`) is dense over
37
+ * (cid: 0..65535, fid: 0..65535), letting V8 keep this as a
38
+ * Number-keyed `Map` — meaningfully faster than the previous string
39
+ * keys (no per-lookup template-string allocation, no string hashing).
40
+ * The row order matches `ArchetypeSpec.columns`. The
41
+ * `component_mask` words mirror what's in the SAB layout descriptor so
42
+ * `growColumnStore` (and any other carry-forward path) doesn't have to
43
+ * re-parse the descriptor region. */
44
+ export interface ArchetypeViews {
45
+ readonly archetypeId: number;
46
+ /** Component bitmask, `COMPONENT_MASK_WORDS` little-endian u32 words. */
47
+ readonly componentMask: readonly number[];
48
+ readonly rowCapacity: number;
49
+ readonly columns: ReadonlyMap<number, ColumnView>;
50
+ readonly columnsInOrder: readonly ColumnView[];
51
+ }
52
+ export interface ColumnStore {
53
+ /** The backing buffer. `ArrayBufferLike` because the store is backing-agnostic:
54
+ * a `SharedArrayBuffer` for the SAB/WASM/worker profile, or a plain resizable
55
+ * `ArrayBuffer` for the pure-TS heap profile (`heapArraybufferAllocator`).
56
+ * Consumers that genuinely require sharing (worker transfer, WASM memory)
57
+ * narrow back to `SharedArrayBuffer` at their boundary. */
58
+ readonly buffer: ArrayBufferLike;
59
+ readonly view: DataView;
60
+ readonly header: StoreHeader;
61
+ /** Indexed by `archetype_id`. */
62
+ readonly archetypes: ReadonlyMap<number, ArchetypeViews>;
63
+ }
64
+ export type AnyTypedArray = Uint8Array | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array | Float64Array;
65
+ /** Pack `(component_id, field_id)` into a single non-negative integer so
66
+ * `ArchetypeViews.columns` can be a `Map<number, ColumnView>` instead of
67
+ * `Map<string, ColumnView>`. V8's number-keyed `Map` skips the
68
+ * string-hash + string-equality every lookup pays, and template-string
69
+ * keys (`"${cid}:${fid}"`) allocated a fresh string on every call. On
70
+ * the lazy-registration ramp-up the per-extend `refreshViews`
71
+ * walks `N` × `cols` of these lookups for `N` archetypes, so the saving
72
+ * compounds quadratically.
73
+ *
74
+ * Encoding: `(component_id << 16) | field_id`. `component_id` is bounded
75
+ * by `STORE_DESCRIPTOR_COMPONENT_LIMIT` (the registration cap, 128), well
76
+ * below 65536. `field_id` is bounded by the component's schema width,
77
+ * single digits in practice. */
78
+ export declare function columnKey(componentId: number, fieldId: number): number;
79
+ /** First byte offset the SAB layout math cannot represent: 2³¹.
80
+ *
81
+ * `alignUp` rounds with `& ~(align-1)`, and JS bitwise operators coerce
82
+ * their operands to **signed** 32-bit integers (`ToInt32`). Once an offset
83
+ * reaches 2³¹ the result wraps to a negative number (or, for some inputs, a
84
+ * misaligned positive one), which then flows straight into
85
+ * `new Uint8Array(buffer, byte_off, …)` — either a thrown `RangeError` deep in
86
+ * the TypedArray ctor or, worse, a silently wrong view overlapping another
87
+ * column. The 256 MiB default allocator cap (`growableSabAllocator`) keeps
88
+ * real matches three orders of magnitude below this, but the cap is tunable
89
+ * and callers are invited to raise it for bigger worlds — so the layout step
90
+ * guards the hard 2³¹ ceiling explicitly rather than relying on the policy
91
+ * cap to stay in front of it (#382). */
92
+ export declare const STORE_MAX_BYTE_OFFSET: number;
93
+ /** Thrown when a SAB column layout would place an offset at or beyond
94
+ * {@link STORE_MAX_BYTE_OFFSET} (2³¹), past which the signed-32-bit bitwise
95
+ * `alignUp` can no longer produce correct offsets. This is a hard ceiling,
96
+ * not the (tunable, much lower) 256 MiB allocator cap — see #382. */
97
+ export declare class StoreLayoutOverflowError extends Error {
98
+ constructor(byteOff: number);
99
+ }
100
+ /** Round `off` up to the next multiple of `align`. `align` must be a power
101
+ * of two (1/2/4/8 here, all `TYPE_TAG_STRIDE` values).
102
+ *
103
+ * Throws {@link StoreLayoutOverflowError} when the rounded offset would reach
104
+ * {@link STORE_MAX_BYTE_OFFSET}, because the `& ~(align-1)` step coerces to a
105
+ * signed 32-bit int and wraps past 2³¹ (#382). The guard fires before the
106
+ * bitwise op so any returned offset is always a correct, in-range value.
107
+ * Shared by `extend.ts` and `grow.ts`, whose in-place paths compute tail
108
+ * byte_offs without going through `planLayout`. */
109
+ export declare function alignUp(off: number, align: number): number;
110
+ /** Build the layout-descriptor-region descriptors (with `byte_off` and
111
+ * `stride` filled in) and return both them and the byte offset just past
112
+ * the last column — i.e. the total SAB size.
113
+ *
114
+ * `headroomBytes` reserves slack at the end of the descriptor region — ON
115
+ * TOP OF the natural size for `specs` — so future extends can append new
116
+ * descriptor entries without shifting existing column byte_offs. Used by
117
+ * the growable-SAB path (#237 Option A) — column views stay valid across
118
+ * `extendColumnStore` because their byte_offs don't move.
119
+ *
120
+ * Additive, not a floor (#541): `regionSize = natural + headroom`, NOT
121
+ * `max(natural, headroom)`. A floor only yields slack while `natural` is
122
+ * below it; the moment the descriptor region outgrows the floor (the #237
123
+ * headroom exhausts and a realloc re-plans the merged spec set), a floor
124
+ * would size the region to exactly `natural` — zero slack — and every
125
+ * subsequent extend would take the slow realloc path forever after. The
126
+ * additive form re-creates the same `headroom` margin on every realloc.
127
+ * For the engine's empty-seed store (`createColumnStore([], …)`, where
128
+ * `natural === 0`) the two forms coincide, so this is behaviour-identical
129
+ * for the only production caller. */
130
+ declare function planLayout(specs: readonly ArchetypeSpec[], regionOff: number, headroomBytes?: number): {
131
+ descriptors: ArchetypeDescriptor[];
132
+ totalBytes: number;
133
+ regionBytes: number;
134
+ };
135
+ /** Exported for the layout tests' overflow-guard coverage; the in-place
136
+ * resize paths use `layoutColumnsAtTail` (layout_ops.ts), not this. */
137
+ export { planLayout };
138
+ /** Optional configuration for `createColumnStore`. */
139
+ export interface CreateColumnStoreOptions {
140
+ /** Extra slack to reserve at the end of the layout descriptor region,
141
+ * ON TOP OF the natural size for `specs` (#541 — additive, not a floor).
142
+ * The descriptor region is padded with this many unused bytes so future
143
+ * `extendColumnStore` calls can append new archetype descriptors into the
144
+ * slack without shifting existing column byte_offs. Pairs with
145
+ * `growableSabAllocator` to give the #237 Option A fast path: existing
146
+ * TypedArray column views stay valid across extends because their offsets
147
+ * and the underlying buffer both stay put.
148
+ *
149
+ * Carried forward as a policy across the realloc-and-republish path: the
150
+ * value lives on `ColumnStoreInternal._reservedDescriptorBytes` and
151
+ * `optionsFromOld` re-applies it, so a store that exhausts its headroom
152
+ * and reallocs gets a fresh margin rather than dropping to zero slack and
153
+ * going permanently slow (#541). */
154
+ readonly reservedDescriptorBytes?: number;
155
+ /** When provided, allocates a command ring (#171 §7.5, Phase 4) inside
156
+ * the SAB at a stable offset right after the 48-byte header. Slot
157
+ * count MUST be a power of two; `COMMAND_RING_DEFAULT_CAPACITY_SLOTS`
158
+ * (256) is the canonical value. Omitted ⇒ no ring; `command_ring_off`
159
+ * stays at 0 ("absent"); existing test fixtures with hand-rolled SABs
160
+ * see the legacy layout (descriptor region immediately after header).
161
+ *
162
+ * Sizing the ring this way — between header and descriptor region —
163
+ * keeps `command_ring_off` stable across `extendColumnStore` /
164
+ * `growColumnStore` calls, since those grow the descriptor region and
165
+ * the column tail but never the bytes between header and descriptor. */
166
+ readonly commandRingCapacitySlots?: number;
167
+ /** When provided, allocates the entity-index region (#245 / Phase 4
168
+ * PR 4B) inside the SAB at a stable offset between the command ring
169
+ * (or header) and the descriptor region. Holds `(generations,
170
+ * archetypes, rows)` triples indexed by entity slot; the engine's
171
+ * `Store` populates them as entities are created/moved/destroyed,
172
+ * and Zig systems read them to resolve cross-entity targets without
173
+ * a callback. Capacity is in *slots* (entities), not bytes; each
174
+ * slot is 12 bytes. Omitted ⇒ no region; `entity_index_off` stays
175
+ * at 0 ("absent"). The engine's Store always sets it to
176
+ * `ENTITY_INDEX_DEFAULT_CAPACITY`; bare-SAB tests can leave it
177
+ * absent. */
178
+ readonly entityIndexCapacity?: number;
179
+ /** When provided, allocates the event ring (#247 / Phase 4 PR 4C)
180
+ * inside the SAB at a stable offset between the entity-index region
181
+ * and the descriptor region. Same SPSC shape as the command ring;
182
+ * carries ECS signal payloads so Zig systems can emit and consume
183
+ * them during `tick()` without callbacks into TS.
184
+ *
185
+ * Slot count MUST be a power of two; `EVENT_RING_DEFAULT_CAPACITY_SLOTS`
186
+ * (256) is the canonical value. Omitted ⇒ no ring; `event_ring_off`
187
+ * stays at 0 ("absent"); existing test fixtures with hand-rolled
188
+ * SABs see the pre-#247 layout. */
189
+ readonly eventRingCapacitySlots?: number;
190
+ /** When provided, allocates the action ring (#291 / Phase 5 PR 5L)
191
+ * inside the SAB at a stable offset between the entity-index/event-ring
192
+ * and the region-table directory. Main writes encoded actions to it;
193
+ * the sim worker drains them on each apply.
194
+ *
195
+ * Slot count MUST be a power of two; `ACTION_RING_DEFAULT_CAPACITY_SLOTS`
196
+ * (256) is the canonical value. Omitted ⇒ no ring; `action_ring_off`
197
+ * stays at 0 ("absent"); bare-SAB tests skip it. (Engine mechanism — the
198
+ * `Store` allocates one always-on; it is no longer a public ECS option.) */
199
+ readonly actionRingCapacitySlots?: number;
200
+ /** Consumer-declared SAB regions (#623). Each `StoreRegionSpec` carries an
201
+ * opaque `region_id`, a precomputed byte size, and an `init` closure; the
202
+ * engine lays them out after the mechanism regions, writes a generic
203
+ * region-table directory (`region_table.ts`) keyed by `region_id`, and
204
+ * snapshots/restores them across a grow/extend. The engine never
205
+ * interprets `region_id` — a game (e.g. `@internal/sim`'s region specs)
206
+ * owns it. Omitted ⇒ no consumer regions; `region_table_off` stays 0. */
207
+ readonly regions?: readonly StoreRegionSpec[];
208
+ /** Byte size of the always-before-descriptor sim-bindings region (v5 /
209
+ * "SAB-is-the-interface"). A consumer that opts into a WASM backend supplies
210
+ * its own size here — `@internal/sim`'s `SIM_BINDINGS_BYTES`, computed from
211
+ * the game's binding manifest. The engine treats the region as opaque bytes:
212
+ * it reserves the block at `bindings_off` (right before the descriptor
213
+ * region, so the offset is stable across grow/extend) and the host writes the
214
+ * `(component_id, field_id)` IDs into it via `write_sim_bindings`.
215
+ *
216
+ * Omitted / 0 ⇒ NO bindings region (`bindings_off` stays 0, "absent") — the
217
+ * default for a pure-TS game that pays nothing for the WASM seam. This used
218
+ * to be the engine-baked `SIM_BINDINGS_BYTES` ABI constant reflected from the
219
+ * game's Zig struct; #625 de-welded it so a manifest edit no longer dirties
220
+ * the engine ABI golden. Re-derived across realloc by `optionsFromOld`
221
+ * (= `layout_descriptor_off - bindings_off`), so it survives grow/extend
222
+ * without a carried policy field. */
223
+ readonly bindingsRegionBytes?: number;
224
+ }
225
+ /** Internal `ColumnStore` extension carrying the descriptor-region byte
226
+ * size. Used by the in-place extend path to know where the next
227
+ * descriptor entry should be written (= `regionOff + region_bytes_used`,
228
+ * tracked separately) and how much headroom remains. */
229
+ export interface ColumnStoreInternal extends ColumnStore {
230
+ readonly _regionBytes: number;
231
+ readonly _allocator: BufferAllocator;
232
+ /** The `reservedDescriptorBytes` policy this store was created with
233
+ * (the additive descriptor-region headroom margin; 0 when none). Carried
234
+ * with the store — NOT re-derivable from the SAB bytes, since `_regionBytes`
235
+ * holds the absolute region size (natural + this), and once `natural`
236
+ * outgrows the margin the two are indistinguishable. The realloc slow path
237
+ * reads it via `optionsFromOld` and re-reserves the same margin, so a
238
+ * store that exhausts its headroom and reallocs keeps taking the #237
239
+ * in-place fast path instead of going permanently slow (#541). The
240
+ * `*_in_place` paths carry it forward verbatim. */
241
+ readonly _reservedDescriptorBytes: number;
242
+ }
243
+ /** Typed recovery of `ColumnStoreInternal` from a public `ColumnStore` (M8).
244
+ * Not every store is internal: `restoreColumnStore` deliberately returns a
245
+ * plain `{ buffer, view, header, archetypes }` (a snapshot carries no JS-side
246
+ * allocator or headroom policy), and grow/extend must send such a store down
247
+ * the realloc slow path. This guard is the ONE place that discrimination
248
+ * happens — grow/extend previously re-derived the internal type via
249
+ * structural `as`-casts at six sites. */
250
+ export declare function isColumnStoreInternal(store: ColumnStore): store is ColumnStoreInternal;
251
+ /** Allocate a SAB sized for `specs`, write the header + layout descriptor,
252
+ * and construct one TypedArray view per column.
253
+ *
254
+ * The returned `ColumnStore` is the source of truth for "where every column
255
+ * lives in this SAB". `view_stamp` is initialised to 0 — a Phase 4 SAB
256
+ * grow flow will bump it. (#171 §6.1.4 / §8.1) */
257
+ export declare function createColumnStore(specs: readonly ArchetypeSpec[], allocator?: BufferAllocator, options?: CreateColumnStoreOptions): ColumnStore;
258
+ /** Default command-ring slot count used by `ECS.Store` when constructing
259
+ * its SAB. Re-exported here so the Store doesn't reach across modules. */
260
+ export { COMMAND_RING_DEFAULT_CAPACITY_SLOTS };
261
+ /** Default entity-index capacity used by `ECS.Store` when constructing
262
+ * its SAB. Re-exported alongside `COMMAND_RING_DEFAULT_CAPACITY_SLOTS`. */
263
+ export { ENTITY_INDEX_DEFAULT_CAPACITY };
264
+ /** Default event-ring slot count used by `ECS.Store` when constructing
265
+ * its SAB. Re-exported alongside the other defaults. */
266
+ export { EVENT_RING_DEFAULT_CAPACITY_SLOTS };
267
+ /** Build the `ArchetypeViews` map from a SAB and its parsed descriptors.
268
+ * Shared by `createColumnStore` (fresh allocation, byte_offs just computed)
269
+ * and `restoreColumnStore` (existing allocation, byte_offs read out of the
270
+ * snapshot). Either way the views land at the byte_offs the descriptors
271
+ * already carry — this helper does not plan layout. */
272
+ export declare function buildArchetypeViews(buffer: ArrayBufferLike, descriptors: readonly ArchetypeDescriptor[]): Map<number, ArchetypeViews>;
273
+ //# sourceMappingURL=column_store.d.ts.map
@@ -0,0 +1,273 @@
1
+ import { StoreHeader } from './header.js';
2
+ import { ArchetypeDescriptor, TypeTagValue } from './descriptor.js';
3
+ import { BufferAllocator } from './allocator.js';
4
+ import { COMMAND_RING_DEFAULT_CAPACITY_SLOTS } from './command_ring.js';
5
+ import { ENTITY_INDEX_DEFAULT_CAPACITY } from './entity_index.js';
6
+ import { EVENT_RING_DEFAULT_CAPACITY_SLOTS } from './event_ring.js';
7
+ import { StoreRegionSpec } from './region_table.js';
8
+ /** Caller-facing column spec — no `byte_off` yet, the store computes it. */
9
+ export interface ColumnSpec {
10
+ readonly componentId: number;
11
+ readonly fieldId: number;
12
+ readonly typeTag: TypeTagValue;
13
+ }
14
+ /** Caller-facing archetype spec — no `column_count` (derived) and no
15
+ * `byte_off`s in the columns; both are computed during sizing. */
16
+ export interface ArchetypeSpec {
17
+ readonly archetypeId: number;
18
+ /** Component bitmask, `COMPONENT_MASK_WORDS` little-endian u32 words. */
19
+ readonly componentMask: readonly number[];
20
+ readonly rowCapacity: number;
21
+ readonly columns: readonly ColumnSpec[];
22
+ }
23
+ /** A single column's view after allocation. The `byte_off` matches what
24
+ * was recorded in the layout descriptor; `view` is a TypedArray of the
25
+ * right element type, length `row_capacity`, backed by the SAB. */
26
+ export interface ColumnView {
27
+ readonly componentId: number;
28
+ readonly fieldId: number;
29
+ readonly typeTag: TypeTagValue;
30
+ readonly byteOff: number;
31
+ readonly stride: number;
32
+ readonly view: AnyTypedArray;
33
+ }
34
+ /** Views for all columns in a single archetype, indexed by a numeric
35
+ * key encoding `(component_id, field_id)` so a (cid, fid) pair maps to
36
+ * its column in O(1). The encoding (see `columnKey`) is dense over
37
+ * (cid: 0..65535, fid: 0..65535), letting V8 keep this as a
38
+ * Number-keyed `Map` — meaningfully faster than the previous string
39
+ * keys (no per-lookup template-string allocation, no string hashing).
40
+ * The row order matches `ArchetypeSpec.columns`. The
41
+ * `component_mask` words mirror what's in the SAB layout descriptor so
42
+ * `growColumnStore` (and any other carry-forward path) doesn't have to
43
+ * re-parse the descriptor region. */
44
+ export interface ArchetypeViews {
45
+ readonly archetypeId: number;
46
+ /** Component bitmask, `COMPONENT_MASK_WORDS` little-endian u32 words. */
47
+ readonly componentMask: readonly number[];
48
+ readonly rowCapacity: number;
49
+ readonly columns: ReadonlyMap<number, ColumnView>;
50
+ readonly columnsInOrder: readonly ColumnView[];
51
+ }
52
+ export interface ColumnStore {
53
+ /** The backing buffer. `ArrayBufferLike` because the store is backing-agnostic:
54
+ * a `SharedArrayBuffer` for the SAB/WASM/worker profile, or a plain resizable
55
+ * `ArrayBuffer` for the pure-TS heap profile (`heapArraybufferAllocator`).
56
+ * Consumers that genuinely require sharing (worker transfer, WASM memory)
57
+ * narrow back to `SharedArrayBuffer` at their boundary. */
58
+ readonly buffer: ArrayBufferLike;
59
+ readonly view: DataView;
60
+ readonly header: StoreHeader;
61
+ /** Indexed by `archetype_id`. */
62
+ readonly archetypes: ReadonlyMap<number, ArchetypeViews>;
63
+ }
64
+ export type AnyTypedArray = Uint8Array | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array | Float64Array;
65
+ /** Pack `(component_id, field_id)` into a single non-negative integer so
66
+ * `ArchetypeViews.columns` can be a `Map<number, ColumnView>` instead of
67
+ * `Map<string, ColumnView>`. V8's number-keyed `Map` skips the
68
+ * string-hash + string-equality every lookup pays, and template-string
69
+ * keys (`"${cid}:${fid}"`) allocated a fresh string on every call. On
70
+ * the lazy-registration ramp-up the per-extend `refreshViews`
71
+ * walks `N` × `cols` of these lookups for `N` archetypes, so the saving
72
+ * compounds quadratically.
73
+ *
74
+ * Encoding: `(component_id << 16) | field_id`. `component_id` is bounded
75
+ * by `STORE_DESCRIPTOR_COMPONENT_LIMIT` (the registration cap, 128), well
76
+ * below 65536. `field_id` is bounded by the component's schema width,
77
+ * single digits in practice. */
78
+ export declare function columnKey(componentId: number, fieldId: number): number;
79
+ /** First byte offset the SAB layout math cannot represent: 2³¹.
80
+ *
81
+ * `alignUp` rounds with `& ~(align-1)`, and JS bitwise operators coerce
82
+ * their operands to **signed** 32-bit integers (`ToInt32`). Once an offset
83
+ * reaches 2³¹ the result wraps to a negative number (or, for some inputs, a
84
+ * misaligned positive one), which then flows straight into
85
+ * `new Uint8Array(buffer, byte_off, …)` — either a thrown `RangeError` deep in
86
+ * the TypedArray ctor or, worse, a silently wrong view overlapping another
87
+ * column. The 256 MiB default allocator cap (`growableSabAllocator`) keeps
88
+ * real matches three orders of magnitude below this, but the cap is tunable
89
+ * and callers are invited to raise it for bigger worlds — so the layout step
90
+ * guards the hard 2³¹ ceiling explicitly rather than relying on the policy
91
+ * cap to stay in front of it (#382). */
92
+ export declare const STORE_MAX_BYTE_OFFSET: number;
93
+ /** Thrown when a SAB column layout would place an offset at or beyond
94
+ * {@link STORE_MAX_BYTE_OFFSET} (2³¹), past which the signed-32-bit bitwise
95
+ * `alignUp` can no longer produce correct offsets. This is a hard ceiling,
96
+ * not the (tunable, much lower) 256 MiB allocator cap — see #382. */
97
+ export declare class StoreLayoutOverflowError extends Error {
98
+ constructor(byteOff: number);
99
+ }
100
+ /** Round `off` up to the next multiple of `align`. `align` must be a power
101
+ * of two (1/2/4/8 here, all `TYPE_TAG_STRIDE` values).
102
+ *
103
+ * Throws {@link StoreLayoutOverflowError} when the rounded offset would reach
104
+ * {@link STORE_MAX_BYTE_OFFSET}, because the `& ~(align-1)` step coerces to a
105
+ * signed 32-bit int and wraps past 2³¹ (#382). The guard fires before the
106
+ * bitwise op so any returned offset is always a correct, in-range value.
107
+ * Shared by `extend.ts` and `grow.ts`, whose in-place paths compute tail
108
+ * byte_offs without going through `planLayout`. */
109
+ export declare function alignUp(off: number, align: number): number;
110
+ /** Build the layout-descriptor-region descriptors (with `byte_off` and
111
+ * `stride` filled in) and return both them and the byte offset just past
112
+ * the last column — i.e. the total SAB size.
113
+ *
114
+ * `headroomBytes` reserves slack at the end of the descriptor region — ON
115
+ * TOP OF the natural size for `specs` — so future extends can append new
116
+ * descriptor entries without shifting existing column byte_offs. Used by
117
+ * the growable-SAB path (#237 Option A) — column views stay valid across
118
+ * `extendColumnStore` because their byte_offs don't move.
119
+ *
120
+ * Additive, not a floor (#541): `regionSize = natural + headroom`, NOT
121
+ * `max(natural, headroom)`. A floor only yields slack while `natural` is
122
+ * below it; the moment the descriptor region outgrows the floor (the #237
123
+ * headroom exhausts and a realloc re-plans the merged spec set), a floor
124
+ * would size the region to exactly `natural` — zero slack — and every
125
+ * subsequent extend would take the slow realloc path forever after. The
126
+ * additive form re-creates the same `headroom` margin on every realloc.
127
+ * For the engine's empty-seed store (`createColumnStore([], …)`, where
128
+ * `natural === 0`) the two forms coincide, so this is behaviour-identical
129
+ * for the only production caller. */
130
+ declare function planLayout(specs: readonly ArchetypeSpec[], regionOff: number, headroomBytes?: number): {
131
+ descriptors: ArchetypeDescriptor[];
132
+ totalBytes: number;
133
+ regionBytes: number;
134
+ };
135
+ /** Exported for the layout tests' overflow-guard coverage; the in-place
136
+ * resize paths use `layoutColumnsAtTail` (layout_ops.ts), not this. */
137
+ export { planLayout };
138
+ /** Optional configuration for `createColumnStore`. */
139
+ export interface CreateColumnStoreOptions {
140
+ /** Extra slack to reserve at the end of the layout descriptor region,
141
+ * ON TOP OF the natural size for `specs` (#541 — additive, not a floor).
142
+ * The descriptor region is padded with this many unused bytes so future
143
+ * `extendColumnStore` calls can append new archetype descriptors into the
144
+ * slack without shifting existing column byte_offs. Pairs with
145
+ * `growableSabAllocator` to give the #237 Option A fast path: existing
146
+ * TypedArray column views stay valid across extends because their offsets
147
+ * and the underlying buffer both stay put.
148
+ *
149
+ * Carried forward as a policy across the realloc-and-republish path: the
150
+ * value lives on `ColumnStoreInternal._reservedDescriptorBytes` and
151
+ * `optionsFromOld` re-applies it, so a store that exhausts its headroom
152
+ * and reallocs gets a fresh margin rather than dropping to zero slack and
153
+ * going permanently slow (#541). */
154
+ readonly reservedDescriptorBytes?: number;
155
+ /** When provided, allocates a command ring (#171 §7.5, Phase 4) inside
156
+ * the SAB at a stable offset right after the 48-byte header. Slot
157
+ * count MUST be a power of two; `COMMAND_RING_DEFAULT_CAPACITY_SLOTS`
158
+ * (256) is the canonical value. Omitted ⇒ no ring; `command_ring_off`
159
+ * stays at 0 ("absent"); existing test fixtures with hand-rolled SABs
160
+ * see the legacy layout (descriptor region immediately after header).
161
+ *
162
+ * Sizing the ring this way — between header and descriptor region —
163
+ * keeps `command_ring_off` stable across `extendColumnStore` /
164
+ * `growColumnStore` calls, since those grow the descriptor region and
165
+ * the column tail but never the bytes between header and descriptor. */
166
+ readonly commandRingCapacitySlots?: number;
167
+ /** When provided, allocates the entity-index region (#245 / Phase 4
168
+ * PR 4B) inside the SAB at a stable offset between the command ring
169
+ * (or header) and the descriptor region. Holds `(generations,
170
+ * archetypes, rows)` triples indexed by entity slot; the engine's
171
+ * `Store` populates them as entities are created/moved/destroyed,
172
+ * and Zig systems read them to resolve cross-entity targets without
173
+ * a callback. Capacity is in *slots* (entities), not bytes; each
174
+ * slot is 12 bytes. Omitted ⇒ no region; `entity_index_off` stays
175
+ * at 0 ("absent"). The engine's Store always sets it to
176
+ * `ENTITY_INDEX_DEFAULT_CAPACITY`; bare-SAB tests can leave it
177
+ * absent. */
178
+ readonly entityIndexCapacity?: number;
179
+ /** When provided, allocates the event ring (#247 / Phase 4 PR 4C)
180
+ * inside the SAB at a stable offset between the entity-index region
181
+ * and the descriptor region. Same SPSC shape as the command ring;
182
+ * carries ECS signal payloads so Zig systems can emit and consume
183
+ * them during `tick()` without callbacks into TS.
184
+ *
185
+ * Slot count MUST be a power of two; `EVENT_RING_DEFAULT_CAPACITY_SLOTS`
186
+ * (256) is the canonical value. Omitted ⇒ no ring; `event_ring_off`
187
+ * stays at 0 ("absent"); existing test fixtures with hand-rolled
188
+ * SABs see the pre-#247 layout. */
189
+ readonly eventRingCapacitySlots?: number;
190
+ /** When provided, allocates the action ring (#291 / Phase 5 PR 5L)
191
+ * inside the SAB at a stable offset between the entity-index/event-ring
192
+ * and the region-table directory. Main writes encoded actions to it;
193
+ * the sim worker drains them on each apply.
194
+ *
195
+ * Slot count MUST be a power of two; `ACTION_RING_DEFAULT_CAPACITY_SLOTS`
196
+ * (256) is the canonical value. Omitted ⇒ no ring; `action_ring_off`
197
+ * stays at 0 ("absent"); bare-SAB tests skip it. (Engine mechanism — the
198
+ * `Store` allocates one always-on; it is no longer a public ECS option.) */
199
+ readonly actionRingCapacitySlots?: number;
200
+ /** Consumer-declared SAB regions (#623). Each `StoreRegionSpec` carries an
201
+ * opaque `region_id`, a precomputed byte size, and an `init` closure; the
202
+ * engine lays them out after the mechanism regions, writes a generic
203
+ * region-table directory (`region_table.ts`) keyed by `region_id`, and
204
+ * snapshots/restores them across a grow/extend. The engine never
205
+ * interprets `region_id` — a game (e.g. `@internal/sim`'s region specs)
206
+ * owns it. Omitted ⇒ no consumer regions; `region_table_off` stays 0. */
207
+ readonly regions?: readonly StoreRegionSpec[];
208
+ /** Byte size of the always-before-descriptor sim-bindings region (v5 /
209
+ * "SAB-is-the-interface"). A consumer that opts into a WASM backend supplies
210
+ * its own size here — `@internal/sim`'s `SIM_BINDINGS_BYTES`, computed from
211
+ * the game's binding manifest. The engine treats the region as opaque bytes:
212
+ * it reserves the block at `bindings_off` (right before the descriptor
213
+ * region, so the offset is stable across grow/extend) and the host writes the
214
+ * `(component_id, field_id)` IDs into it via `write_sim_bindings`.
215
+ *
216
+ * Omitted / 0 ⇒ NO bindings region (`bindings_off` stays 0, "absent") — the
217
+ * default for a pure-TS game that pays nothing for the WASM seam. This used
218
+ * to be the engine-baked `SIM_BINDINGS_BYTES` ABI constant reflected from the
219
+ * game's Zig struct; #625 de-welded it so a manifest edit no longer dirties
220
+ * the engine ABI golden. Re-derived across realloc by `optionsFromOld`
221
+ * (= `layout_descriptor_off - bindings_off`), so it survives grow/extend
222
+ * without a carried policy field. */
223
+ readonly bindingsRegionBytes?: number;
224
+ }
225
+ /** Internal `ColumnStore` extension carrying the descriptor-region byte
226
+ * size. Used by the in-place extend path to know where the next
227
+ * descriptor entry should be written (= `regionOff + region_bytes_used`,
228
+ * tracked separately) and how much headroom remains. */
229
+ export interface ColumnStoreInternal extends ColumnStore {
230
+ readonly _regionBytes: number;
231
+ readonly _allocator: BufferAllocator;
232
+ /** The `reservedDescriptorBytes` policy this store was created with
233
+ * (the additive descriptor-region headroom margin; 0 when none). Carried
234
+ * with the store — NOT re-derivable from the SAB bytes, since `_regionBytes`
235
+ * holds the absolute region size (natural + this), and once `natural`
236
+ * outgrows the margin the two are indistinguishable. The realloc slow path
237
+ * reads it via `optionsFromOld` and re-reserves the same margin, so a
238
+ * store that exhausts its headroom and reallocs keeps taking the #237
239
+ * in-place fast path instead of going permanently slow (#541). The
240
+ * `*_in_place` paths carry it forward verbatim. */
241
+ readonly _reservedDescriptorBytes: number;
242
+ }
243
+ /** Typed recovery of `ColumnStoreInternal` from a public `ColumnStore` (M8).
244
+ * Not every store is internal: `restoreColumnStore` deliberately returns a
245
+ * plain `{ buffer, view, header, archetypes }` (a snapshot carries no JS-side
246
+ * allocator or headroom policy), and grow/extend must send such a store down
247
+ * the realloc slow path. This guard is the ONE place that discrimination
248
+ * happens — grow/extend previously re-derived the internal type via
249
+ * structural `as`-casts at six sites. */
250
+ export declare function isColumnStoreInternal(store: ColumnStore): store is ColumnStoreInternal;
251
+ /** Allocate a SAB sized for `specs`, write the header + layout descriptor,
252
+ * and construct one TypedArray view per column.
253
+ *
254
+ * The returned `ColumnStore` is the source of truth for "where every column
255
+ * lives in this SAB". `view_stamp` is initialised to 0 — a Phase 4 SAB
256
+ * grow flow will bump it. (#171 §6.1.4 / §8.1) */
257
+ export declare function createColumnStore(specs: readonly ArchetypeSpec[], allocator?: BufferAllocator, options?: CreateColumnStoreOptions): ColumnStore;
258
+ /** Default command-ring slot count used by `ECS.Store` when constructing
259
+ * its SAB. Re-exported here so the Store doesn't reach across modules. */
260
+ export { COMMAND_RING_DEFAULT_CAPACITY_SLOTS };
261
+ /** Default entity-index capacity used by `ECS.Store` when constructing
262
+ * its SAB. Re-exported alongside `COMMAND_RING_DEFAULT_CAPACITY_SLOTS`. */
263
+ export { ENTITY_INDEX_DEFAULT_CAPACITY };
264
+ /** Default event-ring slot count used by `ECS.Store` when constructing
265
+ * its SAB. Re-exported alongside the other defaults. */
266
+ export { EVENT_RING_DEFAULT_CAPACITY_SLOTS };
267
+ /** Build the `ArchetypeViews` map from a SAB and its parsed descriptors.
268
+ * Shared by `createColumnStore` (fresh allocation, byte_offs just computed)
269
+ * and `restoreColumnStore` (existing allocation, byte_offs read out of the
270
+ * snapshot). Either way the views land at the byte_offs the descriptors
271
+ * already carry — this helper does not plan layout. */
272
+ export declare function buildArchetypeViews(buffer: ArrayBufferLike, descriptors: readonly ArchetypeDescriptor[]): Map<number, ArchetypeViews>;
273
+ //# sourceMappingURL=column_store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column_store.d.ts","sourceRoot":"","sources":["../../../src/core/store/column_store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Command dispatch — the generic drain surface a consumer registers against
3
+ * (#624, game-agnostic ECS / epic #616).
4
+ *
5
+ * The command ring (`command_ring.ts`) carries opaque `(opCode, payload)`
6
+ * slots; the engine never interprets a code. This module is the thin,
7
+ * game-free glue that lets a consumer bind a payload codec + typed handler to
8
+ * each opcode and drain the ring in one call. The opcode enum and the codecs
9
+ * themselves stay consumer-owned — for our game they live in
10
+ * `@internal/sim`'s `command_payloads.ts` (`COMMAND_OP`, `SpawnUnitFields`,
11
+ * `encode/decode_spawn_unit_payload`); the engine knows none of those names.
12
+ *
13
+ * Usage:
14
+ *
15
+ * const dispatcher = new CommandDispatcher()
16
+ * .on(COMMAND_OP.spawn_unit, spawn_unit_codec, (fields) => spawn(fields));
17
+ * dispatcher.drain(view, ringOff); // runs after wasm.tick() returns
18
+ *
19
+ * Unregistered opcodes are skipped (the same forward-compatible stance as the
20
+ * raw `drainCommandRing` handler that ignores codes it doesn't know).
21
+ */
22
+ /** Decode (and, symmetrically, encode) the 15-byte payload region of a
23
+ * command slot into a typed value. A consumer supplies one per opcode it
24
+ * cares about; the engine only ever calls `decode` during a drain, but the
25
+ * `encode` half keeps the codec a single round-trippable unit (and is what
26
+ * test/host producers use to push). */
27
+ export interface PayloadCodec<T> {
28
+ /** Encode `value` into a fresh `COMMAND_RING_SLOT_BYTES - 1` (15) byte
29
+ * payload, ready for `pushCommand(view, off, op, payload)`. */
30
+ encode(value: T): Uint8Array;
31
+ /** Decode a 15-byte payload back into the typed value. */
32
+ decode(payload: Uint8Array): T;
33
+ }
34
+ /**
35
+ * Registry mapping command opcodes to a payload codec + handler. Generic over
36
+ * the consumer's opcodes — the engine ships the mechanism; the game supplies
37
+ * the codes and codecs.
38
+ */
39
+ export declare class CommandDispatcher {
40
+ private readonly bindings;
41
+ /** Register `handler` for `opCode`, decoding each slot with `codec`.
42
+ * Re-registering an opcode replaces its binding. `opCode` must be a u8 in
43
+ * `[1, 255]` — `0` is the reserved empty-slot marker and can never carry a
44
+ * command. Returns `this` for chaining. */
45
+ on<T>(opCode: number, codec: PayloadCodec<T>, handler: (value: T) => void): this;
46
+ /** Drain every pending command, decoding + dispatching each to its
47
+ * registered handler. Commands with no registered opcode are skipped.
48
+ * Returns the number of slots drained (including skipped ones — the ring is
49
+ * advanced regardless, matching `drainCommandRing`). */
50
+ drain(view: DataView, ringOff: number): number;
51
+ }
52
+ //# sourceMappingURL=command_dispatch.d.ts.map