@forgeax/engine-ecs 0.0.0-dev.8d955ade1c79

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 (383) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +278 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__fixtures__/field-shape-fixture.d.ts +16 -0
  5. package/dist/__fixtures__/field-shape-fixture.d.ts.map +1 -0
  6. package/dist/__tests__/__fixtures__/inspect-scripts.snapshot.d.ts +3 -0
  7. package/dist/__tests__/__fixtures__/inspect-scripts.snapshot.d.ts.map +1 -0
  8. package/dist/__tests__/archetype.unit.test.d.ts +2 -0
  9. package/dist/__tests__/archetype.unit.test.d.ts.map +1 -0
  10. package/dist/__tests__/array-handle-element.test-d.d.ts +2 -0
  11. package/dist/__tests__/array-handle-element.test-d.d.ts.map +1 -0
  12. package/dist/__tests__/buffer-array-vocab.test-d.d.ts +2 -0
  13. package/dist/__tests__/buffer-array-vocab.test-d.d.ts.map +1 -0
  14. package/dist/__tests__/buffer-field-input-widen.unit.test.d.ts +2 -0
  15. package/dist/__tests__/buffer-field-input-widen.unit.test.d.ts.map +1 -0
  16. package/dist/__tests__/buffer-pool.test-d.d.ts +2 -0
  17. package/dist/__tests__/buffer-pool.test-d.d.ts.map +1 -0
  18. package/dist/__tests__/change-detection.unit.test.d.ts +2 -0
  19. package/dist/__tests__/change-detection.unit.test.d.ts.map +1 -0
  20. package/dist/__tests__/command-buffer.test.d.ts +2 -0
  21. package/dist/__tests__/command-buffer.test.d.ts.map +1 -0
  22. package/dist/__tests__/commands-deferred.unit.test.d.ts +2 -0
  23. package/dist/__tests__/commands-deferred.unit.test.d.ts.map +1 -0
  24. package/dist/__tests__/component-catalog.test.d.ts +2 -0
  25. package/dist/__tests__/component-catalog.test.d.ts.map +1 -0
  26. package/dist/__tests__/component-definition-identity.unit.test.d.ts +2 -0
  27. package/dist/__tests__/component-definition-identity.unit.test.d.ts.map +1 -0
  28. package/dist/__tests__/component-nan-preflight.unit.test.d.ts +2 -0
  29. package/dist/__tests__/component-nan-preflight.unit.test.d.ts.map +1 -0
  30. package/dist/__tests__/component-schema.test-d.d.ts +2 -0
  31. package/dist/__tests__/component-schema.test-d.d.ts.map +1 -0
  32. package/dist/__tests__/component-schema.test.d.ts +2 -0
  33. package/dist/__tests__/component-schema.test.d.ts.map +1 -0
  34. package/dist/__tests__/define-component-options.test-d.d.ts +2 -0
  35. package/dist/__tests__/define-component-options.test-d.d.ts.map +1 -0
  36. package/dist/__tests__/deprecated-vocab-rejection.unit.test.d.ts +2 -0
  37. package/dist/__tests__/deprecated-vocab-rejection.unit.test.d.ts.map +1 -0
  38. package/dist/__tests__/despawn-all.unit.test.d.ts +2 -0
  39. package/dist/__tests__/despawn-all.unit.test.d.ts.map +1 -0
  40. package/dist/__tests__/ecs-core-reduction.characterization.test.d.ts +2 -0
  41. package/dist/__tests__/ecs-core-reduction.characterization.test.d.ts.map +1 -0
  42. package/dist/__tests__/ecs-core-reduction.perf.test.d.ts +2 -0
  43. package/dist/__tests__/ecs-core-reduction.perf.test.d.ts.map +1 -0
  44. package/dist/__tests__/ecs-error-code-31.test-d.d.ts +2 -0
  45. package/dist/__tests__/ecs-error-code-31.test-d.d.ts.map +1 -0
  46. package/dist/__tests__/entity-disabling.unit.test.d.ts +2 -0
  47. package/dist/__tests__/entity-disabling.unit.test.d.ts.map +1 -0
  48. package/dist/__tests__/entity-handle-codec-parity.unit.test.d.ts +2 -0
  49. package/dist/__tests__/entity-handle-codec-parity.unit.test.d.ts.map +1 -0
  50. package/dist/__tests__/errors.unit.test.d.ts +2 -0
  51. package/dist/__tests__/errors.unit.test.d.ts.map +1 -0
  52. package/dist/__tests__/execution-conflict-boundary.unit.test.d.ts +2 -0
  53. package/dist/__tests__/execution-conflict-boundary.unit.test.d.ts.map +1 -0
  54. package/dist/__tests__/execution-shared-storage.unit.test.d.ts +2 -0
  55. package/dist/__tests__/execution-shared-storage.unit.test.d.ts.map +1 -0
  56. package/dist/__tests__/externalization-portable-value.unit.test.d.ts +2 -0
  57. package/dist/__tests__/externalization-portable-value.unit.test.d.ts.map +1 -0
  58. package/dist/__tests__/externalization-projection.unit.test.d.ts +2 -0
  59. package/dist/__tests__/externalization-projection.unit.test.d.ts.map +1 -0
  60. package/dist/__tests__/externalization-render-read-lease.test-d.d.ts +2 -0
  61. package/dist/__tests__/externalization-render-read-lease.test-d.d.ts.map +1 -0
  62. package/dist/__tests__/externalization-render-read-lease.unit.test.d.ts +2 -0
  63. package/dist/__tests__/externalization-render-read-lease.unit.test.d.ts.map +1 -0
  64. package/dist/__tests__/externalization-root-surface.unit.test.d.ts +2 -0
  65. package/dist/__tests__/externalization-root-surface.unit.test.d.ts.map +1 -0
  66. package/dist/__tests__/field-enum-labels-reflection.test.d.ts +2 -0
  67. package/dist/__tests__/field-enum-labels-reflection.test.d.ts.map +1 -0
  68. package/dist/__tests__/field-shape-fixture.test.d.ts +2 -0
  69. package/dist/__tests__/field-shape-fixture.test.d.ts.map +1 -0
  70. package/dist/__tests__/field-transient-reflection.test.d.ts +2 -0
  71. package/dist/__tests__/field-transient-reflection.test.d.ts.map +1 -0
  72. package/dist/__tests__/field-value-type.test-d.d.ts +2 -0
  73. package/dist/__tests__/field-value-type.test-d.d.ts.map +1 -0
  74. package/dist/__tests__/fixed-update.unit.test.d.ts +2 -0
  75. package/dist/__tests__/fixed-update.unit.test.d.ts.map +1 -0
  76. package/dist/__tests__/handle.test-d.d.ts +2 -0
  77. package/dist/__tests__/handle.test-d.d.ts.map +1 -0
  78. package/dist/__tests__/hierarchy.unit.test.d.ts +2 -0
  79. package/dist/__tests__/hierarchy.unit.test.d.ts.map +1 -0
  80. package/dist/__tests__/managed-array-vocab.test-d.d.ts +2 -0
  81. package/dist/__tests__/managed-array-vocab.test-d.d.ts.map +1 -0
  82. package/dist/__tests__/minimal-example.test-d.d.ts +2 -0
  83. package/dist/__tests__/minimal-example.test-d.d.ts.map +1 -0
  84. package/dist/__tests__/name-read-types.test-d.d.ts +2 -0
  85. package/dist/__tests__/name-read-types.test-d.d.ts.map +1 -0
  86. package/dist/__tests__/plugin-service.test.d.ts +2 -0
  87. package/dist/__tests__/plugin-service.test.d.ts.map +1 -0
  88. package/dist/__tests__/query-combinations.unit.test.d.ts +2 -0
  89. package/dist/__tests__/query-combinations.unit.test.d.ts.map +1 -0
  90. package/dist/__tests__/query-light-extract-flat-column-ratio.perf.test.d.ts +2 -0
  91. package/dist/__tests__/query-light-extract-flat-column-ratio.perf.test.d.ts.map +1 -0
  92. package/dist/__tests__/query-storage-trends.perf.test.d.ts +2 -0
  93. package/dist/__tests__/query-storage-trends.perf.test.d.ts.map +1 -0
  94. package/dist/__tests__/query-trs-flat-column-ratio.perf.test.d.ts +2 -0
  95. package/dist/__tests__/query-trs-flat-column-ratio.perf.test.d.ts.map +1 -0
  96. package/dist/__tests__/query.unit.test.d.ts +2 -0
  97. package/dist/__tests__/query.unit.test.d.ts.map +1 -0
  98. package/dist/__tests__/relationship-index.perf.test.d.ts +2 -0
  99. package/dist/__tests__/relationship-index.perf.test.d.ts.map +1 -0
  100. package/dist/__tests__/relationship-index.test.d.ts +2 -0
  101. package/dist/__tests__/relationship-index.test.d.ts.map +1 -0
  102. package/dist/__tests__/scalar-field-type-owner.test-d.d.ts +2 -0
  103. package/dist/__tests__/scalar-field-type-owner.test-d.d.ts.map +1 -0
  104. package/dist/__tests__/schedule-determinism.unit.test.d.ts +2 -0
  105. package/dist/__tests__/schedule-determinism.unit.test.d.ts.map +1 -0
  106. package/dist/__tests__/schedule-inspection.unit.test.d.ts +2 -0
  107. package/dist/__tests__/schedule-inspection.unit.test.d.ts.map +1 -0
  108. package/dist/__tests__/schedule-scope-error.unit.test.d.ts +2 -0
  109. package/dist/__tests__/schedule-scope-error.unit.test.d.ts.map +1 -0
  110. package/dist/__tests__/schedule-token.unit.test.d.ts +2 -0
  111. package/dist/__tests__/schedule-token.unit.test.d.ts.map +1 -0
  112. package/dist/__tests__/schema-vocab.test-d.d.ts +2 -0
  113. package/dist/__tests__/schema-vocab.test-d.d.ts.map +1 -0
  114. package/dist/__tests__/serialization.unit.test.d.ts +2 -0
  115. package/dist/__tests__/serialization.unit.test.d.ts.map +1 -0
  116. package/dist/__tests__/shared-kernel-eligibility.test-d.d.ts +2 -0
  117. package/dist/__tests__/shared-kernel-eligibility.test-d.d.ts.map +1 -0
  118. package/dist/__tests__/shared-kernel-eligibility.unit.test.d.ts +2 -0
  119. package/dist/__tests__/shared-kernel-eligibility.unit.test.d.ts.map +1 -0
  120. package/dist/__tests__/shared-ref-store.unit.test.d.ts +2 -0
  121. package/dist/__tests__/shared-ref-store.unit.test.d.ts.map +1 -0
  122. package/dist/__tests__/sparse-tag.unit.test.d.ts +2 -0
  123. package/dist/__tests__/sparse-tag.unit.test.d.ts.map +1 -0
  124. package/dist/__tests__/spawn-field-error.test-d.d.ts +2 -0
  125. package/dist/__tests__/spawn-field-error.test-d.d.ts.map +1 -0
  126. package/dist/__tests__/stale-error.test-d.d.ts +2 -0
  127. package/dist/__tests__/stale-error.test-d.d.ts.map +1 -0
  128. package/dist/__tests__/string-view-symmetry.test-d.d.ts +2 -0
  129. package/dist/__tests__/string-view-symmetry.test-d.d.ts.map +1 -0
  130. package/dist/__tests__/string-vocab.test-d.d.ts +2 -0
  131. package/dist/__tests__/string-vocab.test-d.d.ts.map +1 -0
  132. package/dist/__tests__/structure-epoch-boundaries.unit.test.d.ts +2 -0
  133. package/dist/__tests__/structure-epoch-boundaries.unit.test.d.ts.map +1 -0
  134. package/dist/__tests__/structure-epoch.unit.test.d.ts +2 -0
  135. package/dist/__tests__/structure-epoch.unit.test.d.ts.map +1 -0
  136. package/dist/__tests__/table-archetype-mapping.unit.test.d.ts +2 -0
  137. package/dist/__tests__/table-archetype-mapping.unit.test.d.ts.map +1 -0
  138. package/dist/__tests__/time.unit.test.d.ts +2 -0
  139. package/dist/__tests__/time.unit.test.d.ts.map +1 -0
  140. package/dist/__tests__/types.test-d.d.ts +2 -0
  141. package/dist/__tests__/types.test-d.d.ts.map +1 -0
  142. package/dist/__tests__/unique-ref-store.unit.test.d.ts +2 -0
  143. package/dist/__tests__/unique-ref-store.unit.test.d.ts.map +1 -0
  144. package/dist/__tests__/utils/handle-numeric.d.ts +14 -0
  145. package/dist/__tests__/utils/handle-numeric.d.ts.map +1 -0
  146. package/dist/__tests__/validation-root-surface.unit.test.d.ts +2 -0
  147. package/dist/__tests__/validation-root-surface.unit.test.d.ts.map +1 -0
  148. package/dist/__tests__/visibility-atomic-write.unit.test.d.ts +2 -0
  149. package/dist/__tests__/visibility-atomic-write.unit.test.d.ts.map +1 -0
  150. package/dist/__tests__/world-change-journal.unit.test.d.ts +2 -0
  151. package/dist/__tests__/world-change-journal.unit.test.d.ts.map +1 -0
  152. package/dist/__tests__/world-characterization.unit.test.d.ts +2 -0
  153. package/dist/__tests__/world-characterization.unit.test.d.ts.map +1 -0
  154. package/dist/__tests__/world-consumer-inference.test-d.d.ts +2 -0
  155. package/dist/__tests__/world-consumer-inference.test-d.d.ts.map +1 -0
  156. package/dist/__tests__/world-health.contract.test.d.ts +2 -0
  157. package/dist/__tests__/world-health.contract.test.d.ts.map +1 -0
  158. package/dist/__tests__/world-inspection.test.d.ts +2 -0
  159. package/dist/__tests__/world-inspection.test.d.ts.map +1 -0
  160. package/dist/__tests__/world-internal-identity.unit.test.d.ts +2 -0
  161. package/dist/__tests__/world-internal-identity.unit.test.d.ts.map +1 -0
  162. package/dist/__tests__/world-managed-roundtrip.unit.test.d.ts +2 -0
  163. package/dist/__tests__/world-managed-roundtrip.unit.test.d.ts.map +1 -0
  164. package/dist/__tests__/world-scheduling.m4.test.d.ts +2 -0
  165. package/dist/__tests__/world-scheduling.m4.test.d.ts.map +1 -0
  166. package/dist/__tests__/world-unique-roundtrip.unit.test.d.ts +2 -0
  167. package/dist/__tests__/world-unique-roundtrip.unit.test.d.ts.map +1 -0
  168. package/dist/__tests__/world.test-d.d.ts +2 -0
  169. package/dist/__tests__/world.test-d.d.ts.map +1 -0
  170. package/dist/buffer-pool.d.ts +109 -0
  171. package/dist/buffer-pool.d.ts.map +1 -0
  172. package/dist/commands.d.ts +93 -0
  173. package/dist/commands.d.ts.map +1 -0
  174. package/dist/component-default-fallback.d.ts +88 -0
  175. package/dist/component-default-fallback.d.ts.map +1 -0
  176. package/dist/component-schema.d.ts +34 -0
  177. package/dist/component-schema.d.ts.map +1 -0
  178. package/dist/component-value-validate.d.ts +29 -0
  179. package/dist/component-value-validate.d.ts.map +1 -0
  180. package/dist/component.d.ts +581 -0
  181. package/dist/component.d.ts.map +1 -0
  182. package/dist/entity-handle.d.ts +68 -0
  183. package/dist/entity-handle.d.ts.map +1 -0
  184. package/dist/entity.d.ts +86 -0
  185. package/dist/entity.d.ts.map +1 -0
  186. package/dist/errors/query-and-component-errors.d.ts +132 -0
  187. package/dist/errors/query-and-component-errors.d.ts.map +1 -0
  188. package/dist/errors/relationship-errors.d.ts +112 -0
  189. package/dist/errors/relationship-errors.d.ts.map +1 -0
  190. package/dist/errors/sprite-and-shared-errors.d.ts +107 -0
  191. package/dist/errors/sprite-and-shared-errors.d.ts.map +1 -0
  192. package/dist/errors/validation-errors.d.ts +229 -0
  193. package/dist/errors/validation-errors.d.ts.map +1 -0
  194. package/dist/errors.d.ts +763 -0
  195. package/dist/errors.d.ts.map +1 -0
  196. package/dist/execution/shared-kernel.d.ts +106 -0
  197. package/dist/execution/shared-kernel.d.ts.map +1 -0
  198. package/dist/externalization/index.d.ts +31 -0
  199. package/dist/externalization/index.d.ts.map +1 -0
  200. package/dist/externalization/index.mjs +298 -0
  201. package/dist/externalization/index.mjs.map +1 -0
  202. package/dist/index.d.ts +261 -0
  203. package/dist/index.d.ts.map +1 -0
  204. package/dist/index.mjs +7422 -0
  205. package/dist/index.mjs.map +1 -0
  206. package/dist/internal.mjs +479 -0
  207. package/dist/internal.mjs.map +1 -0
  208. package/dist/plugin-service.d.ts +11 -0
  209. package/dist/plugin-service.d.ts.map +1 -0
  210. package/dist/projection/index.d.ts +103 -0
  211. package/dist/projection/index.d.ts.map +1 -0
  212. package/dist/projection/index.mjs +615 -0
  213. package/dist/projection/index.mjs.map +1 -0
  214. package/dist/query/query.d.ts +58 -0
  215. package/dist/query/query.d.ts.map +1 -0
  216. package/dist/relationship-index.d.ts +81 -0
  217. package/dist/relationship-index.d.ts.map +1 -0
  218. package/dist/resource.d.ts +70 -0
  219. package/dist/resource.d.ts.map +1 -0
  220. package/dist/schedule-token.d.ts +16 -0
  221. package/dist/schedule-token.d.ts.map +1 -0
  222. package/dist/schedule.d.ts +271 -0
  223. package/dist/schedule.d.ts.map +1 -0
  224. package/dist/shared-ref-store.d.ts +144 -0
  225. package/dist/shared-ref-store.d.ts.map +1 -0
  226. package/dist/shared.d.ts +3 -0
  227. package/dist/shared.d.ts.map +1 -0
  228. package/dist/shared.mjs +364 -0
  229. package/dist/shared.mjs.map +1 -0
  230. package/dist/storage/archetype-graph.d.ts +54 -0
  231. package/dist/storage/archetype-graph.d.ts.map +1 -0
  232. package/dist/storage/archetype.d.ts +23 -0
  233. package/dist/storage/archetype.d.ts.map +1 -0
  234. package/dist/storage/change-detection.d.ts +40 -0
  235. package/dist/storage/change-detection.d.ts.map +1 -0
  236. package/dist/storage/column.d.ts +111 -0
  237. package/dist/storage/column.d.ts.map +1 -0
  238. package/dist/storage/table.d.ts +29 -0
  239. package/dist/storage/table.d.ts.map +1 -0
  240. package/dist/time.d.ts +57 -0
  241. package/dist/time.d.ts.map +1 -0
  242. package/dist/unique-ref-store.d.ts +105 -0
  243. package/dist/unique-ref-store.d.ts.map +1 -0
  244. package/dist/world-change-journal.d.ts +34 -0
  245. package/dist/world-change-journal.d.ts.map +1 -0
  246. package/dist/world-component-access.d.ts +265 -0
  247. package/dist/world-component-access.d.ts.map +1 -0
  248. package/dist/world-component-storage.d.ts +282 -0
  249. package/dist/world-component-storage.d.ts.map +1 -0
  250. package/dist/world-core.d.ts +39 -0
  251. package/dist/world-core.d.ts.map +1 -0
  252. package/dist/world-entity-lifecycle.d.ts +30 -0
  253. package/dist/world-entity-lifecycle.d.ts.map +1 -0
  254. package/dist/world-internal.d.ts +14 -0
  255. package/dist/world-internal.d.ts.map +1 -0
  256. package/dist/world-scheduling.d.ts +30 -0
  257. package/dist/world-scheduling.d.ts.map +1 -0
  258. package/dist/world.d.ts +620 -0
  259. package/dist/world.d.ts.map +1 -0
  260. package/package.json +77 -0
  261. package/src/__fixtures__/field-shape-fixture.ts +30 -0
  262. package/src/__tests__/__fixtures__/inspect-scripts.snapshot.ts +2 -0
  263. package/src/__tests__/archetype.unit.test.ts +1837 -0
  264. package/src/__tests__/array-handle-element.test-d.ts +34 -0
  265. package/src/__tests__/buffer-array-vocab.test-d.ts +53 -0
  266. package/src/__tests__/buffer-field-input-widen.unit.test.ts +99 -0
  267. package/src/__tests__/buffer-pool.test-d.ts +32 -0
  268. package/src/__tests__/change-detection.unit.test.ts +86 -0
  269. package/src/__tests__/command-buffer.test.ts +179 -0
  270. package/src/__tests__/commands-deferred.unit.test.ts +68 -0
  271. package/src/__tests__/component-catalog.test.ts +59 -0
  272. package/src/__tests__/component-definition-identity.unit.test.ts +24 -0
  273. package/src/__tests__/component-nan-preflight.unit.test.ts +186 -0
  274. package/src/__tests__/component-schema.test-d.ts +119 -0
  275. package/src/__tests__/component-schema.test.ts +55 -0
  276. package/src/__tests__/define-component-options.test-d.ts +35 -0
  277. package/src/__tests__/deprecated-vocab-rejection.unit.test.ts +59 -0
  278. package/src/__tests__/despawn-all.unit.test.ts +17 -0
  279. package/src/__tests__/ecs-core-reduction.characterization.test.ts +130 -0
  280. package/src/__tests__/ecs-core-reduction.perf.test.ts +260 -0
  281. package/src/__tests__/ecs-error-code-31.test-d.ts +42 -0
  282. package/src/__tests__/entity-disabling.unit.test.ts +37 -0
  283. package/src/__tests__/entity-handle-codec-parity.unit.test.ts +126 -0
  284. package/src/__tests__/errors.unit.test.ts +1456 -0
  285. package/src/__tests__/execution-conflict-boundary.unit.test.ts +123 -0
  286. package/src/__tests__/execution-shared-storage.unit.test.ts +40 -0
  287. package/src/__tests__/externalization-portable-value.unit.test.ts +275 -0
  288. package/src/__tests__/externalization-projection.unit.test.ts +325 -0
  289. package/src/__tests__/externalization-render-read-lease.test-d.ts +30 -0
  290. package/src/__tests__/externalization-render-read-lease.unit.test.ts +79 -0
  291. package/src/__tests__/externalization-root-surface.unit.test.ts +33 -0
  292. package/src/__tests__/field-enum-labels-reflection.test.ts +66 -0
  293. package/src/__tests__/field-shape-fixture.test.ts +61 -0
  294. package/src/__tests__/field-transient-reflection.test.ts +59 -0
  295. package/src/__tests__/field-value-type.test-d.ts +57 -0
  296. package/src/__tests__/fixed-update.unit.test.ts +78 -0
  297. package/src/__tests__/handle.test-d.ts +86 -0
  298. package/src/__tests__/hierarchy.unit.test.ts +2534 -0
  299. package/src/__tests__/managed-array-vocab.test-d.ts +137 -0
  300. package/src/__tests__/minimal-example.test-d.ts +42 -0
  301. package/src/__tests__/name-read-types.test-d.ts +72 -0
  302. package/src/__tests__/plugin-service.test.ts +13 -0
  303. package/src/__tests__/query-combinations.unit.test.ts +42 -0
  304. package/src/__tests__/query-light-extract-flat-column-ratio.perf.test.ts +252 -0
  305. package/src/__tests__/query-storage-trends.perf.test.ts +104 -0
  306. package/src/__tests__/query-trs-flat-column-ratio.perf.test.ts +194 -0
  307. package/src/__tests__/query.unit.test.ts +196 -0
  308. package/src/__tests__/relationship-index.perf.test.ts +126 -0
  309. package/src/__tests__/relationship-index.test.ts +70 -0
  310. package/src/__tests__/scalar-field-type-owner.test-d.ts +71 -0
  311. package/src/__tests__/schedule-determinism.unit.test.ts +36 -0
  312. package/src/__tests__/schedule-inspection.unit.test.ts +81 -0
  313. package/src/__tests__/schedule-scope-error.unit.test.ts +63 -0
  314. package/src/__tests__/schedule-token.unit.test.ts +54 -0
  315. package/src/__tests__/schema-vocab.test-d.ts +103 -0
  316. package/src/__tests__/serialization.unit.test.ts +2740 -0
  317. package/src/__tests__/shared-kernel-eligibility.test-d.ts +18 -0
  318. package/src/__tests__/shared-kernel-eligibility.unit.test.ts +78 -0
  319. package/src/__tests__/shared-ref-store.unit.test.ts +646 -0
  320. package/src/__tests__/sparse-tag.unit.test.ts +201 -0
  321. package/src/__tests__/spawn-field-error.test-d.ts +41 -0
  322. package/src/__tests__/stale-error.test-d.ts +208 -0
  323. package/src/__tests__/string-view-symmetry.test-d.ts +26 -0
  324. package/src/__tests__/string-vocab.test-d.ts +49 -0
  325. package/src/__tests__/structure-epoch-boundaries.unit.test.ts +39 -0
  326. package/src/__tests__/structure-epoch.unit.test.ts +48 -0
  327. package/src/__tests__/table-archetype-mapping.unit.test.ts +78 -0
  328. package/src/__tests__/time.unit.test.ts +79 -0
  329. package/src/__tests__/types.test-d.ts +38 -0
  330. package/src/__tests__/unique-ref-store.unit.test.ts +348 -0
  331. package/src/__tests__/utils/handle-numeric.ts +30 -0
  332. package/src/__tests__/validation-root-surface.unit.test.ts +15 -0
  333. package/src/__tests__/visibility-atomic-write.unit.test.ts +82 -0
  334. package/src/__tests__/world-change-journal.unit.test.ts +97 -0
  335. package/src/__tests__/world-characterization.unit.test.ts +408 -0
  336. package/src/__tests__/world-consumer-inference.test-d.ts +16 -0
  337. package/src/__tests__/world-health.contract.test.ts +87 -0
  338. package/src/__tests__/world-inspection.test.ts +37 -0
  339. package/src/__tests__/world-internal-identity.unit.test.ts +17 -0
  340. package/src/__tests__/world-managed-roundtrip.unit.test.ts +98 -0
  341. package/src/__tests__/world-scheduling.m4.test.ts +52 -0
  342. package/src/__tests__/world-unique-roundtrip.unit.test.ts +357 -0
  343. package/src/__tests__/world.test-d.ts +156 -0
  344. package/src/buffer-pool.ts +357 -0
  345. package/src/commands.ts +644 -0
  346. package/src/component-default-fallback.ts +236 -0
  347. package/src/component-schema.ts +92 -0
  348. package/src/component-value-validate.ts +135 -0
  349. package/src/component.ts +1268 -0
  350. package/src/entity-handle.ts +104 -0
  351. package/src/entity.ts +140 -0
  352. package/src/errors/query-and-component-errors.ts +200 -0
  353. package/src/errors/relationship-errors.ts +198 -0
  354. package/src/errors/sprite-and-shared-errors.ts +231 -0
  355. package/src/errors/validation-errors.ts +506 -0
  356. package/src/errors.ts +1464 -0
  357. package/src/execution/shared-kernel.ts +392 -0
  358. package/src/externalization/index.ts +170 -0
  359. package/src/index.ts +414 -0
  360. package/src/plugin-service.ts +35 -0
  361. package/src/projection/index.ts +318 -0
  362. package/src/query/query.ts +606 -0
  363. package/src/relationship-index.ts +175 -0
  364. package/src/resource.ts +106 -0
  365. package/src/schedule-token.ts +40 -0
  366. package/src/schedule.ts +846 -0
  367. package/src/shared-ref-store.ts +418 -0
  368. package/src/shared.ts +23 -0
  369. package/src/storage/archetype-graph.ts +166 -0
  370. package/src/storage/archetype.ts +78 -0
  371. package/src/storage/change-detection.ts +231 -0
  372. package/src/storage/column.ts +247 -0
  373. package/src/storage/table.ts +153 -0
  374. package/src/time.ts +122 -0
  375. package/src/unique-ref-store.ts +278 -0
  376. package/src/world-change-journal.ts +84 -0
  377. package/src/world-component-access.ts +1421 -0
  378. package/src/world-component-storage.ts +1178 -0
  379. package/src/world-core.ts +74 -0
  380. package/src/world-entity-lifecycle.ts +539 -0
  381. package/src/world-internal.ts +75 -0
  382. package/src/world-scheduling.ts +499 -0
  383. package/src/world.ts +1399 -0
@@ -0,0 +1,74 @@
1
+ import { BufferPool } from './buffer-pool';
2
+ import { createWorldIdentity } from './execution/shared-kernel';
3
+ import type { RelationshipIndex } from './relationship-index';
4
+ import type { SharedRefStore } from './shared-ref-store';
5
+ import { SharedRefStore as SharedRefStoreImpl } from './shared-ref-store';
6
+ import { type ArchetypeGraph, createArchetypeGraph } from './storage/archetype-graph';
7
+ import { WorldChangeJournal } from './storage/change-detection';
8
+ import type { UniqueRefStore } from './unique-ref-store';
9
+ import { UniqueRefStore as UniqueRefStoreImpl } from './unique-ref-store';
10
+ import type { EntityRecord } from './world';
11
+
12
+ interface WorldStorageCore {
13
+ readonly graph: ArchetypeGraph;
14
+ readonly records: EntityRecord[];
15
+ readonly freeIndices: number[];
16
+ readonly bufferPool: BufferPool;
17
+ readonly uniqueRefs: UniqueRefStore;
18
+ readonly sharedRefs: SharedRefStore;
19
+ }
20
+
21
+ function createWorldStorageCore(
22
+ shared: boolean,
23
+ refs: { readonly uniqueRefs: UniqueRefStore; readonly sharedRefs: SharedRefStore },
24
+ ): WorldStorageCore {
25
+ return {
26
+ graph: createArchetypeGraph(shared),
27
+ records: [],
28
+ freeIndices: [],
29
+ bufferPool: new BufferPool(),
30
+ uniqueRefs: refs.uniqueRefs,
31
+ sharedRefs: refs.sharedRefs,
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Package-private state authority for World. A World is the public facade;
37
+ * this object is the only owner of archetype storage, entity records, managed
38
+ * stores, epochs, and bounded change evidence.
39
+ */
40
+ export class WorldCore {
41
+ readonly identity: string = createWorldIdentity();
42
+ readonly uniqueRefs: UniqueRefStore = new UniqueRefStoreImpl();
43
+ readonly sharedRefs: SharedRefStore = new SharedRefStoreImpl();
44
+ readonly storage: WorldStorageCore;
45
+ readonly componentMutationEpochs: number[] = [];
46
+ readonly changeJournal = new WorldChangeJournal();
47
+ /** One packed reverse index per relationship source component. */
48
+ readonly relationshipIndexes = new Map<number, RelationshipIndex>();
49
+ mutationEpoch = 0;
50
+ structureEpoch = 0;
51
+
52
+ constructor(sharedStorage: boolean) {
53
+ this.storage = createWorldStorageCore(sharedStorage, {
54
+ uniqueRefs: this.uniqueRefs,
55
+ sharedRefs: this.sharedRefs,
56
+ });
57
+ }
58
+
59
+ get graph() {
60
+ return this.storage.graph;
61
+ }
62
+
63
+ get records() {
64
+ return this.storage.records;
65
+ }
66
+
67
+ get freeIndices() {
68
+ return this.storage.freeIndices;
69
+ }
70
+
71
+ get bufferPool() {
72
+ return this.storage.bufferPool;
73
+ }
74
+ }
@@ -0,0 +1,539 @@
1
+ // @forgeax/engine-ecs — world-entity-lifecycle: entity lifecycle and hierarchy.
2
+ //
3
+ // Owns entity materialization/retirement plus hierarchy orchestration. Component
4
+ // storage remains in WorldComponentAccess; this module composes its typed
5
+ // relationship mutations into public lifecycle behavior.
6
+
7
+ import { err, isRetiredSlot, ok, pack, type Result } from '@forgeax/engine-types';
8
+ import type { Component, ComponentSchema, InputShapeOf, ShapeOf } from './component';
9
+ import { componentId, componentSchema } from './component';
10
+ import { fillComponentDefaults, validateComponentDataKeys } from './component-default-fallback';
11
+ import { validateManagedArrayValues, validateSharedFieldValues } from './component-value-validate';
12
+ import { Entity } from './entity';
13
+ import {
14
+ ENTITY_NULL_RAW,
15
+ type EntityHandle,
16
+ encodeEntity,
17
+ entityGeneration,
18
+ entityIndex,
19
+ } from './entity-handle';
20
+ import {
21
+ ComponentNotPresentError,
22
+ RelationshipDetachMismatchError,
23
+ RelationshipSelfCycleError,
24
+ StaleEntityError,
25
+ validateEnumFieldValues,
26
+ } from './errors';
27
+ import { relationshipRole, relationshipSource } from './relationship-index';
28
+ import { type Archetype, appendArchetypeRow, removeArchetypeRow } from './storage/archetype';
29
+ import type { ArchetypeGraph } from './storage/archetype-graph';
30
+ import { getOrCreateArchetype, getTable } from './storage/archetype-graph';
31
+ import { removeSparseTag } from './storage/change-detection';
32
+ import { appendTableRow, removeTableRow } from './storage/table';
33
+ import type { EcsError, World } from './world';
34
+ import { worldInternal } from './world-internal';
35
+
36
+ function tableRow(world: World, record: { archetypeId: number; archetypeRow: number }): number {
37
+ const archetype = world[worldInternal].getGraph().archetypes[record.archetypeId];
38
+ return archetype?.rows[record.archetypeRow] ?? -1;
39
+ }
40
+
41
+ /**
42
+ * Core implementation of `spawn` with a relationship reentry guard.
43
+ *
44
+ * @param internal - `true` when relationship maintenance creates a mirror.
45
+ */
46
+ export function spawnCore(
47
+ world: World,
48
+ componentDatas: { component: Component; data: Partial<Record<string, unknown>> }[],
49
+ internal: boolean,
50
+ ): Result<EntityHandle, EcsError> {
51
+ const filledData: Record<string, unknown>[] = [];
52
+ for (const cd of componentDatas) {
53
+ const preflight = world[worldInternal].preflightComponentData(null, cd);
54
+ if (!preflight.ok) return preflight;
55
+ const keyErr = validateComponentDataKeys(cd.component, cd.data as Record<string, unknown>);
56
+ if (keyErr !== null) return err(keyErr as unknown as EcsError);
57
+ const arrayErr = validateManagedArrayValues(cd.component, cd.data as Record<string, unknown>);
58
+ if (arrayErr !== null) return err(arrayErr as unknown as EcsError);
59
+ const sharedErr = validateSharedFieldValues(cd.component, cd.data as Record<string, unknown>);
60
+ if (sharedErr !== null) return err(sharedErr as unknown as EcsError);
61
+ const filled = fillComponentDefaults(cd.component, cd.data as Record<string, unknown>);
62
+ const enumErr = validateEnumFieldValues(cd.component, filled);
63
+ if (enumErr !== null) return err(enumErr as unknown as EcsError);
64
+ filledData.push(filled as Record<string, unknown>);
65
+ }
66
+ const indexSlot = world[worldInternal].allocateIndex();
67
+ const record = world[worldInternal].getRecords()[indexSlot];
68
+ if (record === undefined)
69
+ return err(
70
+ new Error('Internal: allocateIndex did not initialize record') as unknown as EcsError,
71
+ );
72
+ const componentIds = componentDatas.map((cd) => componentId(cd.component));
73
+ const components = componentDatas.map((cd) => cd.component);
74
+ const graph = world[worldInternal].getGraph();
75
+ const arch = getOrCreateArchetype(graph, componentIds, components);
76
+ const table = getTable(graph, arch.tableId);
77
+ const spawnedEntity = encodeEntity(indexSlot, record.generation);
78
+ const tableRow = appendTableRow(table, spawnedEntity);
79
+ const archetypeRow = appendArchetypeRow(arch, tableRow);
80
+ record.archetypeId = arch.id;
81
+ record.archetypeRow = archetypeRow;
82
+ for (let i = 0; i < componentDatas.length; i++) {
83
+ const cdi = componentDatas[i];
84
+ const fdi = filledData[i];
85
+ if (cdi === undefined || fdi === undefined) continue;
86
+ world[worldInternal].writeRow(arch, cdi.component, tableRow, fdi as ShapeOf<ComponentSchema>);
87
+ }
88
+ world[worldInternal].writeEntitySelf(arch, tableRow, spawnedEntity);
89
+ world[worldInternal].markComponentsAdded(spawnedEntity, [
90
+ componentId(Entity),
91
+ ...componentDatas.map((cd) => componentId(cd.component)),
92
+ ]);
93
+ for (let i = 0; i < componentDatas.length; i++) {
94
+ const cd = componentDatas[i];
95
+ const filled = filledData[i];
96
+ if (!cd || filled === undefined) continue;
97
+ if (!internal && relationshipRole(cd.component as Component)?.kind === 'source') {
98
+ const relation = world[worldInternal].relationshipOnInsert(
99
+ spawnedEntity,
100
+ cd.component as Component,
101
+ filled,
102
+ );
103
+ if (!relation.ok) return relation;
104
+ }
105
+ }
106
+ world[worldInternal].markStructureChanged();
107
+ return ok(spawnedEntity);
108
+ }
109
+
110
+ /**
111
+ * Core implementation of `despawn` with a linked-spawn cascade guard.
112
+ *
113
+ * @param internal - `true` while recursively retiring linked children.
114
+ */
115
+ export function despawnCore(
116
+ world: World,
117
+ entity: EntityHandle,
118
+ internal: boolean,
119
+ ): Result<void, EcsError> {
120
+ const slot = entityIndex(entity);
121
+ const gen = entityGeneration(entity);
122
+ const record = world[worldInternal].getRecords()[slot];
123
+ if (!world[worldInternal].recordIsLive(record, gen)) return ok(undefined);
124
+ const arch = world[worldInternal].getGraph().archetypes[record?.archetypeId];
125
+ const linkedChildren = arch ? relationshipLinkedSpawnChildren(world, entity, arch) : [];
126
+ if (arch) {
127
+ const graph = world[worldInternal].getGraph();
128
+ const table = getTable(graph, arch.tableId);
129
+ const archetypeRow = record.archetypeRow;
130
+ const tableRow = arch.rows[archetypeRow] ?? 0;
131
+ for (const comp of arch.components) {
132
+ const role = relationshipRole(comp);
133
+ const needsOldValue = role?.kind === 'source' && !internal;
134
+ if (needsOldValue) {
135
+ const oldValue = world[worldInternal].readRow(arch, comp, tableRow) as Record<
136
+ string,
137
+ unknown
138
+ >;
139
+ if (role?.kind === 'source' && !internal) {
140
+ const relation = world[worldInternal].relationshipOnRemove(entity, comp, oldValue);
141
+ if (!relation.ok) return relation;
142
+ }
143
+ }
144
+ world[worldInternal].releaseManagedRefsOnRow(arch, comp, tableRow);
145
+ }
146
+ for (const component of arch.components) {
147
+ if (component.storage !== 'sparse') continue;
148
+ const set = graph.sparseTags.get(componentId(component));
149
+ if (set !== undefined) removeSparseTag(set, entity);
150
+ }
151
+ const archetypeSwap = removeArchetypeRow(arch, archetypeRow);
152
+ if (archetypeSwap !== null) {
153
+ const movedEntity = (table.storage.get(componentId(Entity))?.fields.get('self')?.view[
154
+ archetypeSwap.movedTableRow
155
+ ] ?? 0) as EntityHandle;
156
+ const movedRecord = world[worldInternal].getRecords()[entityIndex(movedEntity)];
157
+ if (movedRecord?.generation === entityGeneration(movedEntity)) {
158
+ movedRecord.archetypeRow = archetypeSwap.newRow;
159
+ }
160
+ }
161
+ const tableSwap = removeTableRow(table, tableRow);
162
+ if (tableSwap !== null) {
163
+ const movedRecord = world[worldInternal].getRecords()[entityIndex(tableSwap.movedEntity)];
164
+ if (movedRecord?.generation === entityGeneration(tableSwap.movedEntity)) {
165
+ const movedArchetype = graph.archetypes[movedRecord.archetypeId];
166
+ if (movedArchetype !== undefined) {
167
+ movedArchetype.rows[movedRecord.archetypeRow] = tableSwap.newRow;
168
+ }
169
+ }
170
+ }
171
+ }
172
+ if (record) {
173
+ world[worldInternal].removeEntityChanges(entity);
174
+ record.archetypeId = -1;
175
+ record.archetypeRow = -1;
176
+ record.generation += 1;
177
+ if (!isRetiredSlot(record.generation)) world[worldInternal].getFreeIndices().push(slot);
178
+ }
179
+ for (const child of linkedChildren) despawnCore(world, child, true);
180
+ world[worldInternal].markStructureChanged();
181
+ return ok(undefined);
182
+ }
183
+
184
+ /** Attach a child and maintain the relationship mirror through component storage. */
185
+ export function worldAddChild<S extends ComponentSchema>(
186
+ world: World,
187
+ parent: EntityHandle,
188
+ child: EntityHandle,
189
+ component: Component<string, S>,
190
+ data: Partial<InputShapeOf<S>>,
191
+ ): Result<void, EcsError> {
192
+ const holderComp = component as Component;
193
+ if (relationshipRole(holderComp)?.kind !== 'source') {
194
+ return err(new ComponentNotPresentError(child as number, component.name));
195
+ }
196
+
197
+ const parentSlot = entityIndex(parent);
198
+ const parentGeneration = entityGeneration(parent);
199
+ const parentRecord = world[worldInternal].getRecords()[parentSlot];
200
+ if (!world[worldInternal].recordIsLive(parentRecord, parentGeneration)) {
201
+ return err(
202
+ new StaleEntityError(parent as number, parentSlot, parentGeneration, {
203
+ operation: 'addChild',
204
+ component: component.name,
205
+ expectedGeneration: parentGeneration,
206
+ actualGeneration: world[worldInternal].getRecords()[parentSlot]?.generation ?? -1,
207
+ }),
208
+ );
209
+ }
210
+
211
+ const childSlot = entityIndex(child);
212
+ const childGeneration = entityGeneration(child);
213
+ const childRecord = world[worldInternal].getRecords()[childSlot];
214
+ if (!world[worldInternal].recordIsLive(childRecord, childGeneration)) {
215
+ return err(
216
+ new StaleEntityError(child as number, childSlot, childGeneration, {
217
+ operation: 'addChild',
218
+ component: component.name,
219
+ expectedGeneration: childGeneration,
220
+ actualGeneration: world[worldInternal].getRecords()[childSlot]?.generation ?? -1,
221
+ }),
222
+ );
223
+ }
224
+
225
+ const role = relationshipRole(holderComp);
226
+ if (child === parent && !(role?.kind === 'source' && role.allowSelf)) {
227
+ return err(new RelationshipSelfCycleError(component.name, child as number, child as number));
228
+ }
229
+ const cycleHit =
230
+ child === parent && role?.kind === 'source' && role.allowSelf
231
+ ? null
232
+ : relationshipChainCycleHit(world, holderComp, parentSlot, parentGeneration, childSlot);
233
+ if (cycleHit !== null) {
234
+ return err(new RelationshipSelfCycleError(component.name, child as number, cycleHit as number));
235
+ }
236
+
237
+ return world.addComponent(child, { component, data });
238
+ }
239
+
240
+ /** Detach a child only when its current relationship target matches `parent`. */
241
+ export function worldRemoveChild<S extends ComponentSchema>(
242
+ world: World,
243
+ parent: EntityHandle,
244
+ child: EntityHandle,
245
+ component: Component<string, S>,
246
+ ): Result<void, EcsError> {
247
+ const holderComp = component as Component;
248
+ const childResult = world[worldInternal].lookupAlive(child, 'removeChild', component.name);
249
+ if (!childResult.ok) return childResult;
250
+
251
+ const childRecord = childResult.value;
252
+ const childArch = (world[worldInternal].getGraph() as ArchetypeGraph).archetypes[
253
+ childRecord.archetypeId
254
+ ];
255
+ if (!childArch) {
256
+ return err(
257
+ new StaleEntityError(child as number, entityIndex(child), entityGeneration(child), {
258
+ operation: 'removeChild',
259
+ component: component.name,
260
+ expectedGeneration: entityGeneration(child),
261
+ actualGeneration: childRecord.generation,
262
+ }),
263
+ );
264
+ }
265
+ if (
266
+ !childArch.components.some((component) => componentId(component) === componentId(holderComp))
267
+ ) {
268
+ return err(
269
+ new RelationshipDetachMismatchError(component.name, child as number, parent as number, 0),
270
+ );
271
+ }
272
+
273
+ const oldValue = world[worldInternal].readRow(
274
+ childArch,
275
+ holderComp,
276
+ tableRow(world, childRecord),
277
+ ) as Record<string, unknown>;
278
+ const currentTarget = relationshipTargetEntity(holderComp, oldValue);
279
+ if (currentTarget !== parent) {
280
+ return err(
281
+ new RelationshipDetachMismatchError(
282
+ component.name,
283
+ child as number,
284
+ parent as number,
285
+ currentTarget ?? 0,
286
+ ),
287
+ );
288
+ }
289
+
290
+ return world.removeComponent(child, component);
291
+ }
292
+
293
+ /** Move a child to a new parent after cycle validation and old-mirror detachment. */
294
+ export function worldReparent<S extends ComponentSchema>(
295
+ world: World,
296
+ child: EntityHandle,
297
+ newParent: EntityHandle,
298
+ component: Component<string, S>,
299
+ data: Partial<InputShapeOf<S>>,
300
+ ): Result<void, EcsError> {
301
+ const holderComp = component as Component;
302
+ if (relationshipRole(holderComp)?.kind !== 'source') {
303
+ return err(new ComponentNotPresentError(child as number, component.name));
304
+ }
305
+ const role = relationshipRole(holderComp);
306
+ if (child === newParent && !(role?.kind === 'source' && role.allowSelf)) {
307
+ return err(
308
+ new RelationshipSelfCycleError(component.name, child as number, newParent as number),
309
+ );
310
+ }
311
+ const cycleHit =
312
+ child === newParent && role?.kind === 'source' && role.allowSelf
313
+ ? null
314
+ : relationshipChainCycleHit(
315
+ world,
316
+ holderComp,
317
+ entityIndex(newParent),
318
+ entityGeneration(newParent),
319
+ entityIndex(child),
320
+ );
321
+ if (cycleHit !== null) {
322
+ return err(new RelationshipSelfCycleError(component.name, child as number, cycleHit as number));
323
+ }
324
+
325
+ const childResult = world[worldInternal].lookupAlive(child, 'reparent', component.name);
326
+ if (!childResult.ok) return childResult;
327
+
328
+ const childRecord = childResult.value;
329
+ const childArch = (world[worldInternal].getGraph() as ArchetypeGraph).archetypes[
330
+ childRecord.archetypeId
331
+ ];
332
+ if (!childArch) {
333
+ return err(
334
+ new StaleEntityError(child as number, entityIndex(child), entityGeneration(child), {
335
+ operation: 'reparent',
336
+ component: component.name,
337
+ expectedGeneration: entityGeneration(child),
338
+ actualGeneration: childRecord.generation,
339
+ }),
340
+ );
341
+ }
342
+ if (
343
+ childArch.components.some((component) => componentId(component) === componentId(holderComp))
344
+ ) {
345
+ const removeResult = world.removeComponent(child, component);
346
+ if (!removeResult.ok) return removeResult;
347
+ }
348
+ return world.addComponent(child, { component, data });
349
+ }
350
+
351
+ /** Iterate ancestors in child-to-root order while safely terminating corrupt cycles. */
352
+ export function worldIterAncestors(world: World, entity: EntityHandle): Iterable<EntityHandle> {
353
+ return {
354
+ *[Symbol.iterator]() {
355
+ const records = world[worldInternal].getRecords();
356
+ const slot = entityIndex(entity);
357
+ const generation = entityGeneration(entity);
358
+ if (!world[worldInternal].recordIsLive(records[slot], generation)) return;
359
+
360
+ const visited = new Set<number>();
361
+ let currentSlot = slot;
362
+ let currentGeneration = generation;
363
+ while (true) {
364
+ const key = pack(currentSlot, currentGeneration);
365
+ if (visited.has(key)) return;
366
+ visited.add(key);
367
+
368
+ const currentRecord = records[currentSlot];
369
+ if (!world[worldInternal].recordIsLive(currentRecord, currentGeneration)) return;
370
+ const currentArch = (world[worldInternal].getGraph() as ArchetypeGraph).archetypes[
371
+ currentRecord.archetypeId
372
+ ];
373
+ if (!currentArch) return;
374
+
375
+ let foundParent = false;
376
+ for (const component of currentArch.components) {
377
+ if (
378
+ relationshipRole(component)?.kind !== 'source' ||
379
+ !currentArch.components.some(
380
+ (candidate) => componentId(candidate) === componentId(component),
381
+ )
382
+ )
383
+ continue;
384
+ const value = world[worldInternal].readRow(
385
+ currentArch,
386
+ component,
387
+ tableRow(world, currentRecord),
388
+ ) as Record<string, unknown>;
389
+ const target = relationshipTargetEntity(component, value);
390
+ if (target === null) continue;
391
+ yield target;
392
+ currentSlot = entityIndex(target);
393
+ currentGeneration = entityGeneration(target);
394
+ if (!world[worldInternal].recordIsLive(records[currentSlot], currentGeneration)) return;
395
+ foundParent = true;
396
+ break;
397
+ }
398
+ if (!foundParent) return;
399
+ }
400
+ },
401
+ };
402
+ }
403
+
404
+ /** Iterate descendants depth-first through relationship mirror lists. */
405
+ export function worldIterDescendants(world: World, entity: EntityHandle): Iterable<EntityHandle> {
406
+ return {
407
+ *[Symbol.iterator]() {
408
+ const records = world[worldInternal].getRecords();
409
+ const slot = entityIndex(entity);
410
+ const generation = entityGeneration(entity);
411
+ if (!world[worldInternal].recordIsLive(records[slot], generation)) return;
412
+
413
+ const visited = new Set<number>();
414
+ const stack: number[] = [slot];
415
+ while (stack.length > 0) {
416
+ const currentSlot = stack.pop();
417
+ if (currentSlot === undefined) break;
418
+ const currentRecord = records[currentSlot];
419
+ if (!currentRecord || currentRecord.archetypeId === -1) continue;
420
+ const currentArch = world[worldInternal].getGraph().archetypes[currentRecord.archetypeId];
421
+ if (!currentArch) continue;
422
+
423
+ for (const child of descendantChildren(
424
+ world,
425
+ currentArch,
426
+ tableRow(world, currentRecord),
427
+ )) {
428
+ const childSlot = entityIndex(child);
429
+ const childGeneration = entityGeneration(child);
430
+ const key = pack(childSlot, childGeneration);
431
+ if (
432
+ visited.has(key) ||
433
+ !world[worldInternal].recordIsLive(records[childSlot], childGeneration)
434
+ ) {
435
+ continue;
436
+ }
437
+ visited.add(key);
438
+ yield child;
439
+ stack.push(childSlot);
440
+ }
441
+ }
442
+ },
443
+ };
444
+ }
445
+
446
+ function descendantChildren(world: World, arch: Archetype, row: number): EntityHandle[] {
447
+ const children: EntityHandle[] = [];
448
+ for (const component of arch.components) {
449
+ if (!arch.components.some((candidate) => componentId(candidate) === componentId(component)))
450
+ continue;
451
+ const value = world[worldInternal].readRow(arch, component, row) as Record<string, unknown>;
452
+ for (const [fieldName, fieldType] of Object.entries(componentSchema(component))) {
453
+ if (fieldType !== 'array<entity>') continue;
454
+ const list = value[fieldName];
455
+ if (!(list instanceof Uint32Array)) continue;
456
+ for (const raw of list) children.push(raw as EntityHandle);
457
+ }
458
+ }
459
+ return children;
460
+ }
461
+
462
+ function relationshipTargetEntity(
463
+ component: Component,
464
+ value: Record<string, unknown>,
465
+ ): EntityHandle | null {
466
+ for (const [fieldName, fieldType] of Object.entries(componentSchema(component))) {
467
+ if (fieldType !== 'entity') continue;
468
+ const raw = value[fieldName];
469
+ if (raw === null || raw === undefined || raw === ENTITY_NULL_RAW) return null;
470
+ return raw as EntityHandle;
471
+ }
472
+ return null;
473
+ }
474
+
475
+ function relationshipChainCycleHit(
476
+ world: World,
477
+ holderComponent: Component,
478
+ startSlot: number,
479
+ startGeneration: number,
480
+ targetSlot: number,
481
+ ): EntityHandle | null {
482
+ const visited = new Set<number>();
483
+ let currentSlot = startSlot;
484
+ let currentGeneration = startGeneration;
485
+ while (true) {
486
+ const key = pack(currentSlot, currentGeneration);
487
+ if (visited.has(key)) return null;
488
+ visited.add(key);
489
+ const currentRecord = world[worldInternal].getRecords()[currentSlot];
490
+ if (!world[worldInternal].recordIsLive(currentRecord, currentGeneration)) return null;
491
+ const currentArchetype = (world[worldInternal].getGraph() as ArchetypeGraph).archetypes[
492
+ currentRecord.archetypeId
493
+ ];
494
+ if (
495
+ !currentArchetype?.components.some(
496
+ (candidate) => componentId(candidate) === componentId(holderComponent),
497
+ )
498
+ )
499
+ return null;
500
+ const value = world[worldInternal].readRow(
501
+ currentArchetype,
502
+ holderComponent,
503
+ tableRow(world, currentRecord),
504
+ ) as Record<string, unknown>;
505
+ const target = relationshipTargetEntity(holderComponent, value);
506
+ if (target === null) return null;
507
+ const targetEntitySlot = entityIndex(target);
508
+ if (targetEntitySlot === targetSlot) return target;
509
+ currentSlot = targetEntitySlot;
510
+ currentGeneration = entityGeneration(target);
511
+ }
512
+ }
513
+
514
+ function linkedSpawnMirrorField(mirror: Component): string | undefined {
515
+ const source = relationshipSource(mirror);
516
+ const role = source === undefined ? undefined : relationshipRole(source);
517
+ return role?.kind === 'source' && role.linkedSpawn ? role.targetField : undefined;
518
+ }
519
+
520
+ function relationshipLinkedSpawnChildren(
521
+ world: World,
522
+ entity: EntityHandle,
523
+ arch: Archetype,
524
+ ): EntityHandle[] {
525
+ const record = world[worldInternal].getRecords()[entityIndex(entity)];
526
+ const row = record === undefined ? -1 : tableRow(world, record);
527
+ const collected: EntityHandle[] = [];
528
+ for (const component of arch.components) {
529
+ const mirrorField = linkedSpawnMirrorField(component);
530
+ if (mirrorField === undefined) continue;
531
+ const snapshot = world[worldInternal].readRow(arch, component, row) as Record<string, unknown>;
532
+ const list = snapshot[mirrorField];
533
+ if (!(list instanceof Uint32Array)) continue;
534
+ for (const raw of list) {
535
+ if (raw !== ENTITY_NULL_RAW) collected.push(raw as EntityHandle);
536
+ }
537
+ }
538
+ return collected;
539
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * ECS package-internal World seam.
3
+ *
4
+ * This module is intentionally not re-exported by the package entry points.
5
+ * It keeps implementation access out of World's discoverable API while
6
+ * retaining direct bound calls for the hot query and structural paths.
7
+ */
8
+ // Bundled ECS entry points (`index` and `projection`) each include this module
9
+ // in their own closure. A plain Symbol() therefore gives World and projection
10
+ // different property keys at runtime even though their source imports agree.
11
+ // The registry is package-private by convention: no root/advanced export
12
+ // exposes this key, while Symbol.for keeps source/dist and split bundles on
13
+ // one identity.
14
+ export const worldInternal: unique symbol = Symbol.for(
15
+ 'forgeax.ecs.worldInternal',
16
+ ) as unknown as typeof worldInternal;
17
+
18
+ type InternalName =
19
+ | 'addComponentCore'
20
+ | 'allocateIndex'
21
+ | 'allocatePendingEntity'
22
+ | 'cancelPendingEntity'
23
+ | 'despawnCore'
24
+ | 'getArrayView'
25
+ | 'getBufferPool'
26
+ | 'getChangeCursor'
27
+ | 'getClockWriter'
28
+ | 'getComponentChange'
29
+ | 'getComponentMutationEpoch'
30
+ | 'getEntityArchetype'
31
+ | 'getFixedAccumulator'
32
+ | 'getFreeIndices'
33
+ | 'getGraph'
34
+ | 'getMutationEpoch'
35
+ | 'getQueryRow'
36
+ | 'getRecords'
37
+ | 'getRelationshipEpoch'
38
+ | 'getRelationshipTargetEntities'
39
+ | 'getResources'
40
+ | 'getSchedule'
41
+ | 'getSchedules'
42
+ | 'getSharedRefs'
43
+ | 'getStructureEpoch'
44
+ | 'getUniqueRefs'
45
+ | 'lookupAlive'
46
+ | 'markComponentAdded'
47
+ | 'markComponentChanged'
48
+ | 'markComponentRangeChanged'
49
+ | 'markComponentsAdded'
50
+ | 'markDerivedComponentChanges'
51
+ | 'markStructureChanged'
52
+ | 'materializePendingEntity'
53
+ | 'nextMutationEpoch'
54
+ | 'poisonExecution'
55
+ | 'preflightComponentData'
56
+ | 'readChangesSince'
57
+ | 'readRow'
58
+ | 'recordIsLive'
59
+ | 'relationshipOnInsert'
60
+ | 'relationshipOnRemove'
61
+ | 'releaseManagedRefsOnRow'
62
+ | 'removeComponentChange'
63
+ | 'removeComponentCore'
64
+ | 'removeEntityChanges'
65
+ | 'routeError'
66
+ | 'setFixedAccumulator'
67
+ | 'setQueryRow'
68
+ | 'spawnCore'
69
+ | 'writeEntitySelf'
70
+ | 'writeRow';
71
+
72
+ export type WorldInternal = {
73
+ // biome-ignore lint/suspicious/noExplicitAny: this closed package-internal seam preserves each method's existing inferred result type.
74
+ readonly [K in InternalName]: (...args: any[]) => any;
75
+ };