murow 0.0.60 → 0.0.71

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 (425) hide show
  1. package/README.md +52 -37
  2. package/dist/cjs/core/binary-codec/binary-codec.js +1 -0
  3. package/dist/cjs/core/binary-codec/index.js +1 -0
  4. package/dist/cjs/core/driver/driver.js +1 -0
  5. package/dist/cjs/core/driver/drivers/immediate.js +1 -0
  6. package/dist/cjs/core/driver/drivers/index.js +1 -0
  7. package/dist/cjs/core/driver/drivers/raf.js +1 -0
  8. package/dist/cjs/core/driver/drivers/timeout.js +1 -0
  9. package/dist/cjs/core/driver/index.js +1 -0
  10. package/dist/cjs/core/events/event-system.js +1 -0
  11. package/dist/cjs/core/events/index.js +1 -0
  12. package/dist/cjs/core/fixed-ticker/fixed-ticker.js +1 -0
  13. package/dist/cjs/core/fixed-ticker/index.js +1 -0
  14. package/dist/cjs/core/free-list/free-list.js +1 -0
  15. package/dist/cjs/core/free-list/index.js +1 -0
  16. package/dist/cjs/core/generate-id/generate-id.js +1 -0
  17. package/dist/cjs/core/generate-id/index.js +1 -0
  18. package/dist/cjs/core/index.js +1 -0
  19. package/dist/cjs/core/input/index.js +1 -0
  20. package/dist/cjs/core/input/manager.js +1 -0
  21. package/dist/cjs/core/input/sources/browser.js +1 -0
  22. package/dist/cjs/core/input/sources/index.js +1 -0
  23. package/dist/cjs/core/input/types.js +1 -0
  24. package/dist/cjs/core/lerp/index.js +1 -0
  25. package/dist/cjs/core/lerp/lerp.js +1 -0
  26. package/dist/cjs/core/navmesh/index.js +1 -0
  27. package/dist/cjs/core/navmesh/navmesh-worker-pool.js +1 -0
  28. package/dist/cjs/core/navmesh/navmesh.js +1 -0
  29. package/dist/cjs/core/navmesh/navmesh.worker.js +1 -0
  30. package/dist/cjs/core/pooled-codec/index.js +1 -0
  31. package/dist/cjs/core/pooled-codec/pooled-codec.js +1 -0
  32. package/dist/cjs/core/prediction/index.js +1 -0
  33. package/dist/cjs/core/prediction/prediction.js +1 -0
  34. package/dist/cjs/core/ray/index.js +1 -0
  35. package/dist/cjs/core/ray/ray-2d.js +1 -0
  36. package/dist/cjs/core/ray/ray-3d.js +1 -0
  37. package/dist/cjs/core/simple-rng/index.js +1 -0
  38. package/dist/cjs/core/simple-rng/simple-rng.js +1 -0
  39. package/dist/cjs/core/sparse-batcher/index.js +1 -0
  40. package/dist/cjs/core/sparse-batcher/sparse-batcher.js +1 -0
  41. package/dist/cjs/ecs/component-store.js +1 -0
  42. package/dist/cjs/ecs/component.js +1 -0
  43. package/dist/cjs/ecs/entity-handle.js +1 -0
  44. package/dist/cjs/ecs/index.js +1 -0
  45. package/dist/cjs/ecs/system-builder.js +1 -0
  46. package/dist/cjs/ecs/world-systems.js +1 -0
  47. package/dist/cjs/ecs/world.js +1 -0
  48. package/dist/cjs/game/index.js +1 -0
  49. package/dist/cjs/game/loop/index.js +1 -0
  50. package/dist/cjs/game/loop/loop.js +1 -0
  51. package/dist/cjs/index.js +1 -0
  52. package/dist/cjs/net/adapters/browser-websocket.js +1 -0
  53. package/dist/cjs/net/adapters/bun-websocket.js +1 -0
  54. package/dist/cjs/net/buffer-pool.js +1 -0
  55. package/dist/cjs/net/client.js +1 -0
  56. package/dist/cjs/net/index.js +1 -0
  57. package/dist/cjs/net/server.js +1 -0
  58. package/dist/cjs/net/types.js +1 -0
  59. package/dist/cjs/net/validators.js +1 -0
  60. package/dist/cjs/protocol/index.js +1 -0
  61. package/dist/cjs/protocol/intent/define-intent.js +1 -0
  62. package/dist/cjs/protocol/intent/index.js +1 -0
  63. package/dist/cjs/protocol/intent/intent-registry.js +1 -0
  64. package/dist/cjs/protocol/intent/intent.js +1 -0
  65. package/dist/cjs/protocol/rpc/define-rpc.js +1 -0
  66. package/dist/cjs/protocol/rpc/index.js +1 -0
  67. package/dist/cjs/protocol/rpc/rpc-registry.js +1 -0
  68. package/dist/cjs/protocol/rpc/rpc.js +1 -0
  69. package/dist/cjs/protocol/snapshot/index.js +1 -0
  70. package/dist/cjs/protocol/snapshot/snapshot-codec.js +1 -0
  71. package/dist/cjs/protocol/snapshot/snapshot-registry.js +1 -0
  72. package/dist/cjs/protocol/snapshot/snapshot.js +1 -0
  73. package/dist/cjs/renderer/base-2d-renderer.js +1 -0
  74. package/dist/cjs/renderer/base-3d-renderer.js +1 -0
  75. package/dist/cjs/renderer/base-renderer.js +1 -0
  76. package/dist/cjs/renderer/index.js +1 -0
  77. package/dist/cjs/renderer/types.js +1 -0
  78. package/dist/esm/core/binary-codec/binary-codec.js +1 -0
  79. package/dist/esm/core/binary-codec/index.js +1 -0
  80. package/dist/esm/core/driver/driver.js +1 -0
  81. package/dist/esm/core/driver/drivers/immediate.js +1 -0
  82. package/dist/esm/core/driver/drivers/index.js +1 -0
  83. package/dist/esm/core/driver/drivers/raf.js +1 -0
  84. package/dist/esm/core/driver/drivers/timeout.js +1 -0
  85. package/dist/esm/core/driver/index.js +1 -0
  86. package/dist/esm/core/events/event-system.js +1 -0
  87. package/dist/esm/core/events/index.js +1 -0
  88. package/dist/esm/core/fixed-ticker/fixed-ticker.js +1 -0
  89. package/dist/esm/core/fixed-ticker/index.js +1 -0
  90. package/dist/esm/core/free-list/free-list.js +1 -0
  91. package/dist/esm/core/free-list/index.js +1 -0
  92. package/dist/esm/core/generate-id/generate-id.js +1 -0
  93. package/dist/esm/core/generate-id/index.js +1 -0
  94. package/dist/esm/core/index.js +1 -0
  95. package/dist/esm/core/input/index.js +1 -0
  96. package/dist/esm/core/input/manager.js +1 -0
  97. package/dist/esm/core/input/sources/browser.js +1 -0
  98. package/dist/esm/core/input/sources/index.js +1 -0
  99. package/dist/esm/core/input/types.js +0 -0
  100. package/dist/esm/core/lerp/index.js +1 -0
  101. package/dist/esm/core/lerp/lerp.js +1 -0
  102. package/dist/esm/core/navmesh/index.js +1 -0
  103. package/dist/esm/core/navmesh/navmesh-worker-pool.js +1 -0
  104. package/dist/esm/core/navmesh/navmesh.js +1 -0
  105. package/dist/esm/core/navmesh/navmesh.worker.js +1 -0
  106. package/dist/esm/core/pooled-codec/index.js +1 -0
  107. package/dist/esm/core/pooled-codec/pooled-codec.js +1 -0
  108. package/dist/esm/core/prediction/index.js +1 -0
  109. package/dist/esm/core/prediction/prediction.js +1 -0
  110. package/dist/esm/core/ray/index.js +1 -0
  111. package/dist/esm/core/ray/ray-2d.js +1 -0
  112. package/dist/esm/core/ray/ray-3d.js +1 -0
  113. package/dist/esm/core/simple-rng/index.js +1 -0
  114. package/dist/esm/core/simple-rng/simple-rng.js +1 -0
  115. package/dist/esm/core/sparse-batcher/index.js +1 -0
  116. package/dist/esm/core/sparse-batcher/sparse-batcher.js +1 -0
  117. package/dist/esm/ecs/component-store.js +1 -0
  118. package/dist/esm/ecs/component.js +1 -0
  119. package/dist/esm/ecs/entity-handle.js +1 -0
  120. package/dist/esm/ecs/index.js +1 -0
  121. package/dist/esm/ecs/system-builder.js +1 -0
  122. package/dist/esm/ecs/world-systems.js +1 -0
  123. package/dist/esm/ecs/world.js +1 -0
  124. package/dist/esm/game/index.js +1 -0
  125. package/dist/esm/game/loop/index.js +1 -0
  126. package/dist/esm/game/loop/loop.js +1 -0
  127. package/dist/esm/index.js +1 -0
  128. package/dist/esm/net/adapters/browser-websocket.js +1 -0
  129. package/dist/esm/net/adapters/bun-websocket.js +1 -0
  130. package/dist/esm/net/buffer-pool.js +1 -0
  131. package/dist/esm/net/client.js +1 -0
  132. package/dist/esm/net/index.js +1 -0
  133. package/dist/esm/net/server.js +1 -0
  134. package/dist/esm/net/types.js +1 -0
  135. package/dist/esm/net/validators.js +1 -0
  136. package/dist/esm/protocol/index.js +1 -0
  137. package/dist/esm/protocol/intent/define-intent.js +1 -0
  138. package/dist/esm/protocol/intent/index.js +1 -0
  139. package/dist/esm/protocol/intent/intent-registry.js +1 -0
  140. package/dist/esm/protocol/intent/intent.js +0 -0
  141. package/dist/esm/protocol/rpc/define-rpc.js +1 -0
  142. package/dist/esm/protocol/rpc/index.js +1 -0
  143. package/dist/esm/protocol/rpc/rpc-registry.js +1 -0
  144. package/dist/esm/protocol/rpc/rpc.js +0 -0
  145. package/dist/esm/protocol/snapshot/index.js +1 -0
  146. package/dist/esm/protocol/snapshot/snapshot-codec.js +1 -0
  147. package/dist/esm/protocol/snapshot/snapshot-registry.js +1 -0
  148. package/dist/esm/protocol/snapshot/snapshot.js +1 -0
  149. package/dist/esm/renderer/base-2d-renderer.js +1 -0
  150. package/dist/esm/renderer/base-3d-renderer.js +1 -0
  151. package/dist/esm/renderer/base-renderer.js +1 -0
  152. package/dist/esm/renderer/index.js +1 -0
  153. package/dist/esm/renderer/types.js +0 -0
  154. package/dist/{core → types/core}/binary-codec/binary-codec.d.ts +4 -0
  155. package/dist/{core/loop → types/core/driver}/drivers/immediate.d.ts +1 -1
  156. package/dist/{core/loop → types/core/driver}/drivers/raf.d.ts +1 -1
  157. package/dist/{core/loop → types/core/driver}/drivers/timeout.d.ts +1 -1
  158. package/dist/{core/loop → types/core/driver}/index.d.ts +1 -1
  159. package/dist/{core → types/core}/events/event-system.d.ts +14 -33
  160. package/dist/{core → types/core}/fixed-ticker/fixed-ticker.d.ts +1 -1
  161. package/dist/types/core/free-list/free-list.d.ts +31 -0
  162. package/dist/types/core/free-list/index.d.ts +1 -0
  163. package/dist/{core → types/core}/index.d.ts +7 -1
  164. package/dist/types/core/input/index.d.ts +3 -0
  165. package/dist/types/core/input/manager.d.ts +56 -0
  166. package/dist/types/core/input/sources/browser.d.ts +9 -0
  167. package/dist/types/core/input/sources/index.d.ts +1 -0
  168. package/dist/types/core/input/types.d.ts +36 -0
  169. package/dist/{core → types/core}/navmesh/navmesh.d.ts +1 -21
  170. package/dist/types/core/ray/index.d.ts +2 -0
  171. package/dist/types/core/ray/ray-2d.d.ts +37 -0
  172. package/dist/types/core/ray/ray-3d.d.ts +42 -0
  173. package/dist/types/core/simple-rng/index.d.ts +1 -0
  174. package/dist/types/core/simple-rng/simple-rng.d.ts +36 -0
  175. package/dist/types/core/sparse-batcher/index.d.ts +1 -0
  176. package/dist/types/core/sparse-batcher/sparse-batcher.d.ts +55 -0
  177. package/dist/{ecs → types/ecs}/system-builder.d.ts +20 -9
  178. package/dist/{ecs → types/ecs}/world.d.ts +11 -0
  179. package/dist/types/game/index.d.ts +1 -0
  180. package/dist/types/game/loop/index.d.ts +1 -0
  181. package/dist/types/game/loop/loop.d.ts +175 -0
  182. package/dist/{index.d.ts → types/index.d.ts} +2 -0
  183. package/dist/{net → types/net}/index.d.ts +2 -2
  184. package/dist/{net → types/net}/server.d.ts +39 -19
  185. package/dist/{protocol → types/protocol}/intent/define-intent.d.ts +15 -0
  186. package/dist/{protocol → types/protocol}/intent/index.d.ts +1 -1
  187. package/dist/types/renderer/base-2d-renderer.d.ts +13 -0
  188. package/dist/types/renderer/base-3d-renderer.d.ts +10 -0
  189. package/dist/types/renderer/base-renderer.d.ts +21 -0
  190. package/dist/types/renderer/index.d.ts +4 -0
  191. package/dist/types/renderer/types.d.ts +79 -0
  192. package/dist/webgpu/cjs/index.js +6004 -0
  193. package/dist/webgpu/esm/index.js +5972 -0
  194. package/dist/webgpu/types/2d/animation.d.ts +97 -0
  195. package/dist/webgpu/types/2d/renderer.d.ts +55 -0
  196. package/dist/webgpu/types/2d/shader.d.ts +61 -0
  197. package/dist/webgpu/types/2d/sprite-accessor.d.ts +47 -0
  198. package/dist/webgpu/types/2d/sprite-accessor.test.d.ts +1 -0
  199. package/dist/webgpu/types/3d/gltf-skin-parser.d.ts +101 -0
  200. package/dist/webgpu/types/3d/morph-animation.d.ts +69 -0
  201. package/dist/webgpu/types/3d/morph-animation.test.d.ts +1 -0
  202. package/dist/webgpu/types/3d/renderer.d.ts +216 -0
  203. package/dist/webgpu/types/3d/shader.d.ts +136 -0
  204. package/dist/webgpu/types/3d/skeletal-animation-compute/index.d.ts +2 -0
  205. package/dist/webgpu/types/3d/skeletal-animation-compute/kernel.d.ts +8 -0
  206. package/dist/webgpu/types/3d/skeletal-animation-compute/packer.d.ts +32 -0
  207. package/dist/webgpu/types/3d/skeletal-animation.d.ts +90 -0
  208. package/dist/webgpu/types/camera/camera-2d.d.ts +53 -0
  209. package/dist/webgpu/types/camera/camera-2d.test.d.ts +1 -0
  210. package/dist/webgpu/types/camera/camera-3d.d.ts +81 -0
  211. package/dist/webgpu/types/camera/camera-3d.test.d.ts +1 -0
  212. package/dist/webgpu/types/camera/index.d.ts +2 -0
  213. package/dist/webgpu/types/compute/compute-builder.d.ts +123 -0
  214. package/dist/webgpu/types/compute/compute-builder.test.d.ts +1 -0
  215. package/dist/webgpu/types/core/constants.d.ts +59 -0
  216. package/dist/webgpu/types/core/constants.test.d.ts +1 -0
  217. package/dist/webgpu/types/core/index.d.ts +2 -0
  218. package/dist/webgpu/types/core/math.d.ts +37 -0
  219. package/dist/webgpu/types/core/types.d.ts +125 -0
  220. package/dist/webgpu/types/core/types.test.d.ts +1 -0
  221. package/dist/webgpu/types/geometry/built-in.d.ts +58 -0
  222. package/dist/webgpu/types/geometry/built-in.test.d.ts +1 -0
  223. package/dist/webgpu/types/geometry/geometry-builder.d.ts +281 -0
  224. package/dist/webgpu/types/geometry/geometry-builder.test.d.ts +1 -0
  225. package/dist/webgpu/types/geometry/index.d.ts +2 -0
  226. package/dist/webgpu/types/index.d.ts +32 -0
  227. package/dist/webgpu/types/particle/emitter.d.ts +36 -0
  228. package/dist/webgpu/types/shaders/index.d.ts +2 -0
  229. package/dist/webgpu/types/shaders/runtime-transpile.d.ts +18 -0
  230. package/dist/webgpu/types/shaders/sprite-2d.wgsl.d.ts +10 -0
  231. package/dist/webgpu/types/shaders/typegpu.d.ts +9 -0
  232. package/dist/webgpu/types/shaders/utils.d.ts +28 -0
  233. package/dist/webgpu/types/shaders/utils.test.d.ts +1 -0
  234. package/dist/webgpu/types/spritesheet/index.d.ts +1 -0
  235. package/dist/webgpu/types/spritesheet/spritesheet.d.ts +57 -0
  236. package/dist/webgpu/types/spritesheet/spritesheet.test.d.ts +1 -0
  237. package/package.json +96 -26
  238. package/dist/core/binary-codec/binary-codec.js +0 -354
  239. package/dist/core/binary-codec/index.js +0 -1
  240. package/dist/core/events/event-system.js +0 -88
  241. package/dist/core/events/index.js +0 -1
  242. package/dist/core/fixed-ticker/fixed-ticker.js +0 -101
  243. package/dist/core/fixed-ticker/index.js +0 -1
  244. package/dist/core/generate-id/generate-id.js +0 -25
  245. package/dist/core/generate-id/index.js +0 -1
  246. package/dist/core/index.js +0 -9
  247. package/dist/core/lerp/index.js +0 -1
  248. package/dist/core/lerp/lerp.js +0 -42
  249. package/dist/core/loop/drivers/immediate.js +0 -61
  250. package/dist/core/loop/drivers/index.js +0 -3
  251. package/dist/core/loop/drivers/raf.js +0 -62
  252. package/dist/core/loop/drivers/timeout.js +0 -71
  253. package/dist/core/loop/index.js +0 -2
  254. package/dist/core/loop/loop.js +0 -47
  255. package/dist/core/navmesh/index.js +0 -1
  256. package/dist/core/navmesh/navmesh-worker-pool.js +0 -180
  257. package/dist/core/navmesh/navmesh.js +0 -799
  258. package/dist/core/navmesh/navmesh.worker.js +0 -79
  259. package/dist/core/pooled-codec/index.js +0 -1
  260. package/dist/core/pooled-codec/pooled-codec.js +0 -410
  261. package/dist/core/prediction/index.js +0 -1
  262. package/dist/core/prediction/prediction.js +0 -99
  263. package/dist/core.esm.js +0 -1
  264. package/dist/core.js +0 -1
  265. package/dist/ecs/component-store.js +0 -175
  266. package/dist/ecs/component.js +0 -43
  267. package/dist/ecs/entity-handle.js +0 -515
  268. package/dist/ecs/example.js +0 -125
  269. package/dist/ecs/index.js +0 -4
  270. package/dist/ecs/system-builder.js +0 -180
  271. package/dist/ecs/system.d.ts +0 -63
  272. package/dist/ecs/system.js +0 -92
  273. package/dist/ecs/world-systems.js +0 -79
  274. package/dist/ecs/world.js +0 -684
  275. package/dist/index.js +0 -24
  276. package/dist/net/adapters/browser-websocket.js +0 -74
  277. package/dist/net/adapters/bun-websocket.js +0 -245
  278. package/dist/net/buffer-pool.js +0 -89
  279. package/dist/net/client.js +0 -586
  280. package/dist/net/index.js +0 -58
  281. package/dist/net/server.js +0 -938
  282. package/dist/net/types.js +0 -31
  283. package/dist/net/validators.js +0 -88
  284. package/dist/protocol/index.js +0 -92
  285. package/dist/protocol/intent/define-intent.js +0 -125
  286. package/dist/protocol/intent/index.js +0 -91
  287. package/dist/protocol/intent/intent-registry.js +0 -91
  288. package/dist/protocol/rpc/define-rpc.js +0 -84
  289. package/dist/protocol/rpc/index.js +0 -3
  290. package/dist/protocol/rpc/rpc-registry.js +0 -159
  291. package/dist/protocol/rpc/rpc.js +0 -12
  292. package/dist/protocol/snapshot/index.js +0 -43
  293. package/dist/protocol/snapshot/snapshot-codec.js +0 -67
  294. package/dist/protocol/snapshot/snapshot-registry.js +0 -168
  295. package/dist/protocol/snapshot/snapshot.js +0 -30
  296. package/src/core/binary-codec/README.md +0 -60
  297. package/src/core/binary-codec/binary-codec.test.ts +0 -300
  298. package/src/core/binary-codec/binary-codec.ts +0 -448
  299. package/src/core/binary-codec/index.ts +0 -1
  300. package/src/core/events/README.md +0 -47
  301. package/src/core/events/event-system.test.ts +0 -243
  302. package/src/core/events/event-system.ts +0 -140
  303. package/src/core/events/index.ts +0 -1
  304. package/src/core/fixed-ticker/README.md +0 -77
  305. package/src/core/fixed-ticker/fixed-ticker.test.ts +0 -151
  306. package/src/core/fixed-ticker/fixed-ticker.ts +0 -169
  307. package/src/core/fixed-ticker/index.ts +0 -1
  308. package/src/core/generate-id/README.md +0 -18
  309. package/src/core/generate-id/generate-id.test.ts +0 -79
  310. package/src/core/generate-id/generate-id.ts +0 -37
  311. package/src/core/generate-id/index.ts +0 -1
  312. package/src/core/index.ts +0 -9
  313. package/src/core/lerp/README.md +0 -79
  314. package/src/core/lerp/index.ts +0 -1
  315. package/src/core/lerp/lerp.test.ts +0 -90
  316. package/src/core/lerp/lerp.ts +0 -42
  317. package/src/core/loop/README.md +0 -97
  318. package/src/core/loop/drivers/immediate.ts +0 -66
  319. package/src/core/loop/drivers/index.ts +0 -3
  320. package/src/core/loop/drivers/raf.ts +0 -67
  321. package/src/core/loop/drivers/timeout.ts +0 -77
  322. package/src/core/loop/index.ts +0 -2
  323. package/src/core/loop/loop.test.ts +0 -414
  324. package/src/core/loop/loop.ts +0 -71
  325. package/src/core/navmesh/README.md +0 -164
  326. package/src/core/navmesh/index.ts +0 -1
  327. package/src/core/navmesh/navmesh-worker-pool.ts +0 -236
  328. package/src/core/navmesh/navmesh-workers.test.ts +0 -356
  329. package/src/core/navmesh/navmesh.test.ts +0 -344
  330. package/src/core/navmesh/navmesh.ts +0 -1047
  331. package/src/core/navmesh/navmesh.worker.ts +0 -147
  332. package/src/core/pooled-codec/README.md +0 -70
  333. package/src/core/pooled-codec/index.ts +0 -1
  334. package/src/core/pooled-codec/pooled-codec.test.ts +0 -862
  335. package/src/core/pooled-codec/pooled-codec.ts +0 -504
  336. package/src/core/prediction/README.md +0 -64
  337. package/src/core/prediction/index.ts +0 -1
  338. package/src/core/prediction/prediction.test.ts +0 -423
  339. package/src/core/prediction/prediction.ts +0 -112
  340. package/src/ecs/README.md +0 -427
  341. package/src/ecs/benchmark.test.ts +0 -1645
  342. package/src/ecs/component-store.ts +0 -198
  343. package/src/ecs/component.ts +0 -90
  344. package/src/ecs/entity-handle.test.ts +0 -393
  345. package/src/ecs/entity-handle.ts +0 -563
  346. package/src/ecs/example.ts +0 -152
  347. package/src/ecs/index.ts +0 -4
  348. package/src/ecs/system-builder.ts +0 -309
  349. package/src/ecs/system.ts +0 -111
  350. package/src/ecs/world-systems.ts +0 -83
  351. package/src/ecs/world.test.ts +0 -310
  352. package/src/ecs/world.ts +0 -828
  353. package/src/index.ts +0 -28
  354. package/src/net/README.md +0 -474
  355. package/src/net/adapters/browser-websocket.ts +0 -86
  356. package/src/net/adapters/bun-websocket.ts +0 -292
  357. package/src/net/buffer-pool.ts +0 -106
  358. package/src/net/client.test.ts +0 -807
  359. package/src/net/client.ts +0 -695
  360. package/src/net/index.ts +0 -60
  361. package/src/net/server.test.ts +0 -799
  362. package/src/net/server.ts +0 -1116
  363. package/src/net/types.ts +0 -228
  364. package/src/net/validators.ts +0 -104
  365. package/src/protocol/README.md +0 -469
  366. package/src/protocol/index.ts +0 -93
  367. package/src/protocol/intent/define-intent.test.ts +0 -397
  368. package/src/protocol/intent/define-intent.ts +0 -182
  369. package/src/protocol/intent/index.ts +0 -94
  370. package/src/protocol/intent/intent-registry.test.ts +0 -198
  371. package/src/protocol/intent/intent-registry.ts +0 -112
  372. package/src/protocol/intent/intent.ts +0 -12
  373. package/src/protocol/rpc/define-rpc.test.ts +0 -141
  374. package/src/protocol/rpc/define-rpc.ts +0 -113
  375. package/src/protocol/rpc/index.ts +0 -3
  376. package/src/protocol/rpc/rpc-registry.test.ts +0 -168
  377. package/src/protocol/rpc/rpc-registry.ts +0 -176
  378. package/src/protocol/rpc/rpc.ts +0 -37
  379. package/src/protocol/snapshot/index.ts +0 -45
  380. package/src/protocol/snapshot/snapshot-codec.test.ts +0 -138
  381. package/src/protocol/snapshot/snapshot-codec.ts +0 -87
  382. package/src/protocol/snapshot/snapshot-registry.test.ts +0 -310
  383. package/src/protocol/snapshot/snapshot-registry.ts +0 -201
  384. package/src/protocol/snapshot/snapshot.test.ts +0 -76
  385. package/src/protocol/snapshot/snapshot.ts +0 -41
  386. /package/dist/{core → types/core}/binary-codec/index.d.ts +0 -0
  387. /package/dist/{core/loop/loop.d.ts → types/core/driver/driver.d.ts} +0 -0
  388. /package/dist/{core/loop → types/core/driver}/drivers/index.d.ts +0 -0
  389. /package/dist/{core → types/core}/events/index.d.ts +0 -0
  390. /package/dist/{core → types/core}/fixed-ticker/index.d.ts +0 -0
  391. /package/dist/{core → types/core}/generate-id/generate-id.d.ts +0 -0
  392. /package/dist/{core → types/core}/generate-id/index.d.ts +0 -0
  393. /package/dist/{core → types/core}/lerp/index.d.ts +0 -0
  394. /package/dist/{core → types/core}/lerp/lerp.d.ts +0 -0
  395. /package/dist/{core → types/core}/navmesh/index.d.ts +0 -0
  396. /package/dist/{core → types/core}/navmesh/navmesh-worker-pool.d.ts +0 -0
  397. /package/dist/{core → types/core}/navmesh/navmesh.worker.d.ts +0 -0
  398. /package/dist/{core → types/core}/pooled-codec/index.d.ts +0 -0
  399. /package/dist/{core → types/core}/pooled-codec/pooled-codec.d.ts +0 -0
  400. /package/dist/{core → types/core}/prediction/index.d.ts +0 -0
  401. /package/dist/{core → types/core}/prediction/prediction.d.ts +0 -0
  402. /package/dist/{ecs → types/ecs}/component-store.d.ts +0 -0
  403. /package/dist/{ecs → types/ecs}/component.d.ts +0 -0
  404. /package/dist/{ecs → types/ecs}/entity-handle.d.ts +0 -0
  405. /package/dist/{ecs → types/ecs}/example.d.ts +0 -0
  406. /package/dist/{ecs → types/ecs}/index.d.ts +0 -0
  407. /package/dist/{ecs → types/ecs}/world-systems.d.ts +0 -0
  408. /package/dist/{net → types/net}/adapters/browser-websocket.d.ts +0 -0
  409. /package/dist/{net → types/net}/adapters/bun-websocket.d.ts +0 -0
  410. /package/dist/{net → types/net}/buffer-pool.d.ts +0 -0
  411. /package/dist/{net → types/net}/client.d.ts +0 -0
  412. /package/dist/{net → types/net}/types.d.ts +0 -0
  413. /package/dist/{net → types/net}/validators.d.ts +0 -0
  414. /package/dist/{protocol → types/protocol}/index.d.ts +0 -0
  415. /package/dist/{protocol → types/protocol}/intent/intent-registry.d.ts +0 -0
  416. /package/dist/{protocol → types/protocol}/intent/intent.d.ts +0 -0
  417. /package/dist/{protocol → types/protocol}/rpc/define-rpc.d.ts +0 -0
  418. /package/dist/{protocol → types/protocol}/rpc/index.d.ts +0 -0
  419. /package/dist/{protocol → types/protocol}/rpc/rpc-registry.d.ts +0 -0
  420. /package/dist/{protocol → types/protocol}/rpc/rpc.d.ts +0 -0
  421. /package/dist/{protocol → types/protocol}/snapshot/index.d.ts +0 -0
  422. /package/dist/{protocol → types/protocol}/snapshot/snapshot-codec.d.ts +0 -0
  423. /package/dist/{protocol → types/protocol}/snapshot/snapshot-registry.d.ts +0 -0
  424. /package/dist/{protocol → types/protocol}/snapshot/snapshot.d.ts +0 -0
  425. /package/dist/{protocol/intent/intent.js → webgpu/types/2d/animation.test.d.ts} +0 -0
package/src/ecs/world.ts DELETED
@@ -1,828 +0,0 @@
1
- import { generateId } from "../core/generate-id";
2
- import { Component } from "./component";
3
- import { ComponentStore } from "./component-store";
4
- import { EntityHandle } from "./entity-handle";
5
- import { WorldSystems } from "./world-systems";
6
-
7
- /**
8
- * Configuration for creating a World
9
- */
10
- export interface WorldConfig {
11
- /** Maximum number of entities that can exist simultaneously */
12
- maxEntities?: number;
13
-
14
- /** Component types to register */
15
- components: Component<any>[];
16
- }
17
-
18
- /**
19
- * Entity ID type (just a number, indexing into component arrays)
20
- */
21
- export type Entity = number;
22
-
23
- /**
24
- * World manages entities and their components.
25
- * Provides efficient ECS storage using typed arrays.
26
- *
27
- * Performance optimizations:
28
- * - Array iteration instead of Set for 2-5x faster queries
29
- * - Query bitmask caching for repeated queries
30
- * - Array-indexed component stores for O(1) access
31
- * - Pre-allocated ring buffer for entity ID reuse
32
- *
33
- * @example
34
- * ```typescript
35
- * const world = new World({
36
- * maxEntities: 10000,
37
- * components: [Transform, Health, Velocity]
38
- * });
39
- *
40
- * const entity = world.spawn();
41
- * world.add(entity, Transform, { x: 100, y: 200, rotation: 0 });
42
- * world.add(entity, Health, { current: 100, max: 100 });
43
- *
44
- * // Query entities
45
- * for (const entity of world.query(Transform, Velocity)) {
46
- * const transform = world.get(entity, Transform);
47
- * const velocity = world.get(entity, Velocity);
48
- * // transform is readonly, use update() to modify
49
- * world.update(entity, Transform, {
50
- * x: transform.x + velocity.vx,
51
- * y: transform.y + velocity.vy
52
- * });
53
- * }
54
- * ```
55
- */
56
- export class World extends WorldSystems {
57
- private maxEntities: number;
58
- private nextEntityId: number = 0;
59
-
60
- // Entity ID reuse (ring buffer for O(1) push/pop)
61
- private freeEntityIds: Uint32Array;
62
- private freeEntityHead: number = 0;
63
- private freeEntityTail: number = 0;
64
- private freeEntityCount: number = 0;
65
- private freeEntityMask: number = 0; // Bitwise AND mask for power-of-2 modulo
66
-
67
- // Entity storage: Array for fast iteration, bitmask for O(1) alive checks
68
- private aliveEntitiesArray: Entity[] = [];
69
- private aliveEntitiesIndices: Uint32Array; // Index lookup for O(1) despawn
70
- private aliveEntityFlags: Uint8Array; // 1 byte per entity for alive check
71
-
72
- // Component system (array-indexed for O(1) access)
73
- public componentStoresArray: (ComponentStore<any> | undefined)[];
74
- private componentMasks: Uint32Array[]; // Dynamic array of bitmask words (32 components per word)
75
- private componentMasks0!: Uint32Array; // Fast path: cached reference to first word (most common case)
76
- private numMaskWords: number = 0; // Number of allocated mask words
77
-
78
- // Component registry (direct index stored on component - zero lookup cost!)
79
- private components: Component<any>[] = [];
80
-
81
- // Query result cache (reusable buffers for zero allocations)
82
- private queryResultBuffers: Record<string, Entity[]> = {}; // Now keyed by string hash
83
-
84
- // Persistent query cache (invalidated only on archetype changes)
85
- private archetypeVersion: number = 0; // Increments on spawn/despawn/add/remove
86
- private queryCacheVersions: Record<string, number> = {}; // Keyed by mask hash
87
-
88
- // Query mask cache (avoid recomputing masks for same component combinations)
89
- private queryMaskCache: Record<string, number[]> = {};
90
-
91
- // Debug ID
92
- private worldId = generateId({ prefix: "world_" });
93
-
94
- constructor(config: WorldConfig) {
95
- super();
96
- this.maxEntities = config.maxEntities ?? 10000;
97
-
98
- // Calculate number of mask words needed (1 word per 32 components)
99
- this.numMaskWords = Math.ceil(config.components.length / 32);
100
-
101
- // Allocate separate Uint32Array for each mask word
102
- this.componentMasks = [];
103
- for (let i = 0; i < this.numMaskWords; i++) {
104
- this.componentMasks.push(new Uint32Array(this.maxEntities));
105
- }
106
-
107
- // Cache first word for fast path (most games use <32 components)
108
- if (this.numMaskWords > 0) {
109
- this.componentMasks0 = this.componentMasks[0];
110
- }
111
-
112
- // Round up to next power of 2 for ring buffer (enables bitwise modulo)
113
- const ringBufferSize = Math.pow(2, Math.ceil(Math.log2(this.maxEntities)));
114
- this.freeEntityIds = new Uint32Array(ringBufferSize);
115
- this.freeEntityMask = ringBufferSize - 1; // For x % size → x & mask
116
-
117
- // Pre-allocate index lookup for O(1) despawn
118
- this.aliveEntitiesIndices = new Uint32Array(this.maxEntities);
119
-
120
- // Pre-allocate alive flags for O(1) alive checks
121
- this.aliveEntityFlags = new Uint8Array(this.maxEntities);
122
-
123
- // Pre-allocate arrays for component stores
124
- this.componentStoresArray = new Array(config.components.length);
125
-
126
- // Register components
127
- config.components.forEach((component, index) => {
128
- this.components.push(component);
129
- // Store index directly on component for O(1) access (no Map lookup!)
130
- component.__worldIndex = index;
131
-
132
- // Create component store with selected backend
133
- const store = new ComponentStore(component, this.maxEntities);
134
- this.componentStoresArray[index] = store;
135
- });
136
- }
137
-
138
- /**
139
- * Get component index (O(1) - stored directly on component)
140
- */
141
- private getComponentIndex(component: Component<any>): number {
142
- const index = component.__worldIndex;
143
- if (index === undefined) {
144
- const registered = this.components.map((c) => c.name).join(", ");
145
- throw new Error(
146
- `Component ${component.name} not registered in World[${this.worldId}]. ` +
147
- `Registered components: [${registered}]. ` +
148
- `Did you forget to include it in the WorldConfig?`
149
- );
150
- }
151
- return index;
152
- }
153
-
154
- /**
155
- * Set a bit in the bitmask for an entity
156
- */
157
- private setComponentBit(entity: Entity, componentIndex: number): void {
158
- const wordIndex = componentIndex >>> 5; // Which word (div 32)
159
- const bitIndex = componentIndex & 31; // Which bit in word (mod 32)
160
- this.componentMasks[wordIndex][entity] |= 1 << bitIndex;
161
- }
162
-
163
- /**
164
- * Clear a bit in the bitmask for an entity
165
- */
166
- private clearComponentBit(entity: Entity, componentIndex: number): void {
167
- const wordIndex = componentIndex >>> 5; // Which word (div 32)
168
- const bitIndex = componentIndex & 31; // Which bit in word (mod 32)
169
- this.componentMasks[wordIndex][entity] &= ~(1 << bitIndex);
170
- }
171
-
172
- /**
173
- * Check if a bit is set in the bitmask for an entity
174
- */
175
- private hasComponentBit(entity: Entity, componentIndex: number): boolean {
176
- const wordIndex = componentIndex >>> 5; // Which word (div 32)
177
- const bitIndex = componentIndex & 31; // Which bit in word (mod 32)
178
- return (this.componentMasks[wordIndex][entity] & (1 << bitIndex)) !== 0;
179
- }
180
-
181
- /**
182
- * Clear all component bits for an entity
183
- */
184
- private clearAllComponentBits(entity: Entity): void {
185
- for (let i = 0; i < this.numMaskWords; i++) {
186
- this.componentMasks[i][entity] = 0;
187
- }
188
- }
189
-
190
- /**
191
- * Check if entity matches the required component mask
192
- * Returns true if entity has all required components
193
- *
194
- * Optimized for common case: most games use <32 components,
195
- * so we only need to check the first word
196
- */
197
- private matchesComponentMask(entity: Entity, mask: number[]): boolean {
198
- const len = mask.length;
199
-
200
- // Fast path: single word (most common - <32 components)
201
- if (len === 1) {
202
- return (this.componentMasks0[entity] & mask[0]) === mask[0];
203
- }
204
-
205
- // Unrolled for 2 words (32-63 components)
206
- if (len === 2) {
207
- return (this.componentMasks0[entity] & mask[0]) === mask[0] &&
208
- (this.componentMasks[1][entity] & mask[1]) === mask[1];
209
- }
210
-
211
- // Unrolled for 3 words (64-95 components)
212
- if (len === 3) {
213
- return (this.componentMasks0[entity] & mask[0]) === mask[0] &&
214
- (this.componentMasks[1][entity] & mask[1]) === mask[1] &&
215
- (this.componentMasks[2][entity] & mask[2]) === mask[2];
216
- }
217
-
218
- // Unrolled for 4 words (96-127 components)
219
- if (len === 4) {
220
- return (this.componentMasks0[entity] & mask[0]) === mask[0] &&
221
- (this.componentMasks[1][entity] & mask[1]) === mask[1] &&
222
- (this.componentMasks[2][entity] & mask[2]) === mask[2] &&
223
- (this.componentMasks[3][entity] & mask[3]) === mask[3];
224
- }
225
-
226
- // General case for 5+ words (rare)
227
- for (let i = 0; i < len; i++) {
228
- if ((this.componentMasks[i][entity] & mask[i]) !== mask[i]) {
229
- return false;
230
- }
231
- }
232
- return true;
233
- }
234
-
235
- /**
236
- * Get or compute query bitmask
237
- * Returns array of numbers (one 32-bit mask per word)
238
- *
239
- * Caches masks to avoid recomputation for frequently used component combinations
240
- */
241
- private getQueryMask(components: Component<any>[]): number[] | null {
242
- // Create cache key from component names (sorted for consistency)
243
- const cacheKey = components.map(c => c.name).sort().join(',');
244
-
245
- // Check cache first
246
- const cached = this.queryMaskCache[cacheKey];
247
- if (cached) return cached;
248
-
249
- // Find max component index to determine how many words we need
250
- let maxIndex = -1;
251
- const indices: number[] = [];
252
-
253
- for (const component of components) {
254
- const index = component.__worldIndex;
255
- if (index === undefined) return null; // Invalid mask sentinel
256
- indices.push(index);
257
- if (index > maxIndex) maxIndex = index;
258
- }
259
-
260
- // Calculate number of words needed
261
- const numWords = Math.floor(maxIndex / 32) + 1;
262
- const requiredMask: number[] = new Array(numWords).fill(0);
263
-
264
- // Set bits for each component (direct index access - no lookups!)
265
- for (const index of indices) {
266
- const wordIndex = index >>> 5; // div 32
267
- const bitIndex = index & 31; // mod 32
268
- requiredMask[wordIndex] |= 1 << bitIndex;
269
- }
270
-
271
- // Cache the mask for future queries
272
- this.queryMaskCache[cacheKey] = requiredMask;
273
-
274
- return requiredMask;
275
- }
276
-
277
- /**
278
- * Convert mask array to a hash key for caching
279
- */
280
- private maskToKey(mask: number[]): string {
281
- let key = '';
282
- for (let i = 0; i < mask.length; i++) {
283
- if (mask[i] !== 0) {
284
- key += `${i}:${mask[i].toString(36)},`;
285
- }
286
- }
287
- return key;
288
- }
289
-
290
- /**
291
- * Internal: Get query mask key for a set of components.
292
- * Used by SystemBuilder for precomputing query keys.
293
- * @internal
294
- */
295
- private _getQueryMaskKey(components: Component<any>[]): string {
296
- const mask = this.getQueryMask(components);
297
- return mask ? this.maskToKey(mask) : '';
298
- }
299
-
300
- /**
301
- * Internal: Query entities by precomputed mask key and mask.
302
- * Used by ExecutableSystem for fast queries without mask recomputation.
303
- * @internal
304
- */
305
- private _queryByMaskKey(maskKey: string, requiredMask: number[]): readonly Entity[] {
306
- // Get or create reusable buffer for this query mask
307
- let buffer = this.queryResultBuffers[maskKey];
308
- if (!buffer) {
309
- buffer = [];
310
- this.queryResultBuffers[maskKey] = buffer;
311
- }
312
-
313
- // Check if cache is valid (persistent query caching)
314
- if (this.queryCacheVersions[maskKey] === this.archetypeVersion) {
315
- // Cache is valid! Return cached result (FAST PATH - no iteration!)
316
- return buffer;
317
- }
318
-
319
- // Cache is stale - rebuild by iterating alive entities
320
- const aliveEntities = this.aliveEntitiesArray;
321
- const length = aliveEntities.length;
322
- const numWords = requiredMask.length;
323
- let writeIdx = 0;
324
-
325
- // Fast path for single-word masks (most common case, <32 components)
326
- if (numWords === 1) {
327
- const mask0 = requiredMask[0];
328
- const componentMasks0 = this.componentMasks0;
329
- for (let i = 0; i < length; i++) {
330
- const entity = aliveEntities[i]!;
331
- if ((componentMasks0[entity] & mask0) === mask0) {
332
- buffer[writeIdx++] = entity;
333
- }
334
- }
335
- } else {
336
- // Multi-word mask path
337
- const componentMasks = this.componentMasks;
338
- outer: for (let i = 0; i < length; i++) {
339
- const entity = aliveEntities[i]!;
340
- for (let w = 0; w < numWords; w++) {
341
- if ((componentMasks[w][entity] & requiredMask[w]) !== requiredMask[w]) {
342
- continue outer;
343
- }
344
- }
345
- buffer[writeIdx++] = entity;
346
- }
347
- }
348
-
349
- // Truncate buffer to actual size (zero allocations)
350
- buffer.length = writeIdx;
351
-
352
- // Mark cache as valid for this archetype version
353
- this.queryCacheVersions[maskKey] = this.archetypeVersion;
354
-
355
- return buffer;
356
- }
357
-
358
- /**
359
- * Spawn a new entity.
360
- * Returns the entity ID.
361
- */
362
- spawn(): Entity {
363
- // Hot path: allocate new ID (most common case, no branching)
364
- let id = this.nextEntityId;
365
-
366
- // Cold path: reuse freed ID if available
367
- if (this.freeEntityCount > 0) {
368
- id = this.freeEntityIds[this.freeEntityTail];
369
- this.freeEntityTail = (this.freeEntityTail + 1) & this.freeEntityMask;
370
- this.freeEntityCount--;
371
- } else {
372
- this.nextEntityId++;
373
- }
374
-
375
- // Bounds check (unlikely to fail in normal operation)
376
- if (id >= this.maxEntities) {
377
- throw new Error(
378
- `Maximum entities (${this.maxEntities}) reached. ` +
379
- `Current alive: ${this.aliveEntitiesArray.length}, ` +
380
- `Free list: ${this.freeEntityCount}`
381
- );
382
- }
383
-
384
- // Fast path: setup entity (no branches)
385
- this.aliveEntityFlags[id] = 1;
386
- this.aliveEntitiesIndices[id] = this.aliveEntitiesArray.length;
387
- this.aliveEntitiesArray.push(id);
388
- this.clearAllComponentBits(id);
389
-
390
- // Invalidate query cache since entity count changed
391
- this.invalidateQueryCache();
392
-
393
- return id;
394
- }
395
-
396
- /**
397
- * Despawn an entity, removing all its components.
398
- * The entity ID will be reused.
399
- */
400
- despawn(entity: Entity): void {
401
- if (this.aliveEntityFlags[entity] === 0) {
402
- return; // Already despawned
403
- }
404
-
405
- this.aliveEntityFlags[entity] = 0;
406
-
407
- // Remove from array (swap with last for O(1) removal)
408
- const idx = this.aliveEntitiesIndices[entity];
409
- const last = this.aliveEntitiesArray.length - 1;
410
-
411
- if (idx !== last) {
412
- // Swap with last element
413
- const lastEntity = this.aliveEntitiesArray[last];
414
- this.aliveEntitiesArray[idx] = lastEntity;
415
- this.aliveEntitiesIndices[lastEntity] = idx;
416
- }
417
-
418
- this.aliveEntitiesArray.pop();
419
-
420
- // Clear all components for this entity
421
- for (let i = 0; i < this.components.length; i++) {
422
- if (this.hasComponentBit(entity, i)) {
423
- this.componentStoresArray[i]!.clear(entity);
424
- }
425
- }
426
-
427
- this.clearAllComponentBits(entity);
428
-
429
- // Push to free list
430
- this.freeEntityIds[this.freeEntityHead] = entity;
431
- this.freeEntityHead = (this.freeEntityHead + 1) & this.freeEntityMask; // Bitwise AND instead of modulo
432
- this.freeEntityCount++;
433
-
434
- // Invalidate query cache since entity count changed
435
- this.invalidateQueryCache();
436
- }
437
-
438
- /**
439
- * Check if an entity is alive
440
- */
441
- isAlive(entity: Entity): boolean {
442
- return this.aliveEntityFlags[entity] === 1;
443
- }
444
-
445
- /**
446
- * Invalidate all query caches (called on archetype changes).
447
- */
448
- private invalidateQueryCache(): void {
449
- this.archetypeVersion++;
450
- }
451
-
452
- /**
453
- * Add a component to an entity with initial data.
454
- */
455
- add<T extends object>(entity: Entity, component: Component<T>, data: T): void {
456
- if (this.aliveEntityFlags[entity] === 0) {
457
- throw new Error(
458
- `Cannot add component ${component.name} to entity ${entity}: ` +
459
- `entity is not alive (was it despawned?). ` +
460
- `Current alive entities: ${this.aliveEntitiesArray.length}`
461
- );
462
- }
463
-
464
- const index = this.getComponentIndex(component);
465
- const store = this.componentStoresArray[index]!;
466
-
467
- this.setComponentBit(entity, index);
468
- store.set(entity, data);
469
-
470
- // Invalidate query cache since archetype changed
471
- this.invalidateQueryCache();
472
- }
473
-
474
- /**
475
- * Remove a component from an entity.
476
- */
477
- remove<T extends object>(entity: Entity, component: Component<T>): void {
478
- const index = component.__worldIndex;
479
- if (index === undefined) return;
480
-
481
- this.clearComponentBit(entity, index);
482
-
483
- const store = this.componentStoresArray[index];
484
- if (store) {
485
- store.clear(entity);
486
- }
487
-
488
- // Invalidate query cache since archetype changed
489
- this.invalidateQueryCache();
490
- }
491
-
492
- /**
493
- * Check if an entity has a component.
494
- */
495
- has<T extends object>(entity: Entity, component: Component<T>): boolean {
496
- const index = component.__worldIndex;
497
- if (index === undefined) return false;
498
-
499
- return this.hasComponentBit(entity, index);
500
- }
501
-
502
- /**
503
- * Get a component's data for an entity.
504
- * Returns a READONLY reusable object (zero allocations).
505
- *
506
- * ⚠️ IMPORTANT: The returned object is reused and will be overwritten on the next get().
507
- * To modify, use set() or update() instead.
508
- * To keep multiple components, use getMutable() or spread operator.
509
- *
510
- * @example
511
- * // ✅ CORRECT: Use immediately
512
- * const t = world.get(entity, Transform);
513
- * console.log(t.x, t.y);
514
- *
515
- * // ❌ WRONG: Storing reference
516
- * const t1 = world.get(entity1, Transform);
517
- * const t2 = world.get(entity2, Transform); // t1 is now corrupted!
518
- *
519
- * // ✅ CORRECT: Copy if you need to keep
520
- * const t1 = { ...world.get(entity1, Transform) };
521
- * const t2 = { ...world.get(entity2, Transform) };
522
- */
523
- get<T extends object>(entity: Entity, component: Component<T>): Readonly<T> {
524
- const index = this.getComponentIndex(component);
525
-
526
- if (!this.hasComponentBit(entity, index)) {
527
- const entityComponents = this.getEntityComponentNames(entity);
528
- throw new Error(
529
- `Cannot get component ${component.name} from entity ${entity}: ` +
530
- `entity does not have this component. ` +
531
- `Entity has: [${entityComponents.join(", ")}]. ` +
532
- `Did you forget to call world.add()?`
533
- );
534
- }
535
-
536
- return this.componentStoresArray[index]!.get(entity);
537
- }
538
-
539
- /**
540
- * Get a mutable copy of component data.
541
- * Use this when you need to modify and keep the data.
542
- *
543
- * Note: This allocates a new object. Use sparingly in hot paths.
544
- */
545
- getMutable<T extends object>(entity: Entity, component: Component<T>): T {
546
- const index = this.getComponentIndex(component);
547
-
548
- if (!this.hasComponentBit(entity, index)) {
549
- throw new Error(`Entity ${entity} does not have component ${component.name}`);
550
- }
551
-
552
- return this.componentStoresArray[index]!.getMutable(entity);
553
- }
554
-
555
- /**
556
- * Set a component's data for an entity.
557
- * Overwrites all fields.
558
- */
559
- set<T extends object>(entity: Entity, component: Component<T>, data: T): void {
560
- const index = this.getComponentIndex(component);
561
-
562
- if (!this.hasComponentBit(entity, index)) {
563
- throw new Error(
564
- `Cannot set component ${component.name} on entity ${entity}: ` +
565
- `entity does not have this component. Use add() first.`
566
- );
567
- }
568
-
569
- this.componentStoresArray[index]!.set(entity, data);
570
- }
571
-
572
- /**
573
- * Update specific fields of a component.
574
- * More efficient than get + modify + set.
575
- *
576
- * @example
577
- * // ✅ GOOD: Partial update
578
- * world.update(entity, Transform, { x: 150 });
579
- *
580
- * // ❌ BAD: Full get/set for single field
581
- * const t = world.getMutable(entity, Transform);
582
- * t.x = 150;
583
- * world.set(entity, Transform, t);
584
- */
585
- update<T extends object>(entity: Entity, component: Component<T>, partial: Partial<T>): void {
586
- const index = this.getComponentIndex(component);
587
-
588
- if (!this.hasComponentBit(entity, index)) {
589
- throw new Error(`Entity ${entity} does not have component ${component.name}`);
590
- }
591
-
592
- this.componentStoresArray[index]!.update(entity, partial);
593
- }
594
-
595
- /**
596
- * Query entities that have all specified components.
597
- * Returns a readonly array for zero-allocation iteration.
598
- *
599
- * Uses reusable buffers and direct bitmask checks for maximum performance.
600
- * The returned array is reused on subsequent queries with the same mask.
601
- *
602
- * @example
603
- * ```typescript
604
- * for (const entity of world.query(Transform, Velocity)) {
605
- * const t = world.get(entity, Transform);
606
- * const v = world.get(entity, Velocity);
607
- * world.update(entity, Transform, {
608
- * x: t.x + v.vx * dt,
609
- * y: t.y + v.vy * dt
610
- * });
611
- * }
612
- * ```
613
- */
614
- query(...components: Component<any>[]): readonly Entity[] {
615
- const requiredMask = this.getQueryMask(components);
616
- if (requiredMask === null) return []; // Component not registered
617
-
618
- const maskKey = this.maskToKey(requiredMask);
619
-
620
- // Get or create reusable buffer for this query mask
621
- let buffer = this.queryResultBuffers[maskKey];
622
- if (!buffer) {
623
- buffer = [];
624
- this.queryResultBuffers[maskKey] = buffer;
625
- }
626
-
627
- // Check if cache is valid (persistent query caching)
628
- if (this.queryCacheVersions[maskKey] === this.archetypeVersion) {
629
- // Cache is valid! Return cached result (FAST PATH - no iteration!)
630
- return buffer;
631
- }
632
-
633
- // Cache miss or stale - recompute query results
634
- const entities = this.aliveEntitiesArray;
635
- const length = entities.length;
636
-
637
- // Use write cursor pattern instead of buffer.length = 0 + push
638
- let writeIdx = 0;
639
-
640
- // Process entities (checking 128-bit bitmask: 4 x 32-bit words)
641
- for (let i = 0; i < length; i++) {
642
- const entity = entities[i];
643
- if (this.matchesComponentMask(entity, requiredMask)) {
644
- buffer[writeIdx++] = entity;
645
- }
646
- }
647
-
648
- // Truncate buffer to actual size
649
- buffer.length = writeIdx;
650
-
651
- // Mark cache as valid for this archetype version
652
- this.queryCacheVersions[maskKey] = this.archetypeVersion;
653
-
654
- return buffer;
655
- }
656
-
657
- /**
658
- * Get all alive entity IDs.
659
- *
660
- * ⚠️ WARNING: The returned array is a direct reference and should not be modified.
661
- * For a safe copy, use [...world.getEntities()].
662
- */
663
- getEntities(): readonly Entity[] {
664
- return this.aliveEntitiesArray;
665
- }
666
-
667
- /**
668
- * Get the number of alive entities.
669
- */
670
- getEntityCount(): number {
671
- return this.aliveEntitiesArray.length;
672
- }
673
-
674
- /**
675
- * Get the maximum number of entities.
676
- */
677
- getMaxEntities(): number {
678
- return this.maxEntities;
679
- }
680
-
681
- /**
682
- * Get all registered components.
683
- */
684
- getComponents(): readonly Component<any>[] {
685
- return this.components;
686
- }
687
-
688
- /**
689
- * Get component names for an entity (for debugging)
690
- */
691
- private getEntityComponentNames(entity: Entity): string[] {
692
- const result: string[] = [];
693
-
694
- for (let i = 0; i < this.components.length; i++) {
695
- if (this.hasComponentBit(entity, i)) {
696
- result.push(this.components[i].name);
697
- }
698
- }
699
-
700
- return result;
701
- }
702
-
703
- /**
704
- * Serialize entities with specific components to binary.
705
- * Uses PooledCodec internally for efficient encoding.
706
- *
707
- * @param components Components to include in the snapshot
708
- * @param entities Optional list of entities to serialize (defaults to all)
709
- * @returns Binary buffer with serialized data
710
- */
711
- serialize(components: Component<any>[], entities?: Entity[]): Uint8Array {
712
- const entityList = entities ?? Array.from(this.aliveEntitiesArray);
713
-
714
- // Build data structure for each component
715
- const componentArrays: any[] = [];
716
-
717
- for (const component of components) {
718
- const index = component.__worldIndex;
719
- if (index === undefined) continue;
720
-
721
- const store = this.componentStoresArray[index];
722
- if (!store) continue;
723
-
724
- const items: any[] = [];
725
-
726
- for (const entity of entityList) {
727
- if (this.has(entity, component)) {
728
- items.push({
729
- entity,
730
- ...store.getMutable(entity),
731
- });
732
- }
733
- }
734
-
735
- if (items.length > 0) {
736
- // Use the component's arrayCodec (PooledCodec.array) to encode
737
- const encoded = component.arrayCodec.encode(items);
738
- componentArrays.push(encoded);
739
- }
740
- }
741
-
742
- // Combine all buffers
743
- // TODO: Could optimize this with a proper multi-buffer format
744
- const totalSize = componentArrays.reduce((sum, buf) => sum + buf.length, 0);
745
- const result = new Uint8Array(totalSize);
746
- let offset = 0;
747
- for (const buf of componentArrays) {
748
- result.set(buf, offset);
749
- offset += buf.length;
750
- }
751
-
752
- return result;
753
- }
754
-
755
- /**
756
- * Deserialize binary data into entities.
757
- * Uses PooledCodec internally for efficient decoding.
758
- *
759
- * Note: This is a basic implementation. For production use,
760
- * you'd want a more sophisticated format with component IDs, etc.
761
- */
762
- deserialize(components: Component<any>[], buffer: Uint8Array): void {
763
- // TODO: Implement proper deserialization with component IDs
764
- // For now, this is a placeholder
765
- throw new Error("Deserialization not yet implemented");
766
- }
767
-
768
- /**
769
- * Get direct access to a component field's TypedArray for maximum performance.
770
- * This bypasses the get/update API for ~3-4x faster access in hot paths.
771
- *
772
- * ⚠️ ADVANCED API: Use with caution!
773
- * - No bounds checking
774
- * - No type safety
775
- * - You must ensure entities have the component
776
- * - Direct array mutation bypasses any safety mechanisms
777
- *
778
- * @example
779
- * ```typescript
780
- * // High-performance system (bitECS-style)
781
- * const transformX = world.getFieldArray(Transform, 'x');
782
- * const transformY = world.getFieldArray(Transform, 'y');
783
- * const velocityVx = world.getFieldArray(Velocity, 'vx');
784
- * const velocityVy = world.getFieldArray(Velocity, 'vy');
785
- *
786
- * for (const entity of world.query(Transform, Velocity)) {
787
- * transformX[entity] += velocityVx[entity] * dt;
788
- * transformY[entity] += velocityVy[entity] * dt;
789
- * }
790
- * ```
791
- */
792
- getFieldArray<T extends object>(
793
- component: Component<T>,
794
- fieldName: keyof T
795
- ): Float32Array | Int32Array | Uint32Array | Uint16Array | Uint8Array {
796
- const index = this.getComponentIndex(component);
797
- return this.componentStoresArray[index]!.getFieldArray(fieldName);
798
- }
799
-
800
- /**
801
- * Create an EntityHandle wrapper for fluent API usage.
802
- *
803
- * EntityHandle provides a chainable interface for entity operations with zero runtime overhead.
804
- * Modern JIT compilers inline these simple method calls, making them identical to raw World API.
805
- *
806
- * @param entityId - Entity ID to wrap
807
- * @returns EntityHandle for fluent operations
808
- *
809
- * @example
810
- * ```typescript
811
- * // Fluent API with chaining
812
- * const player = world.entity(world.spawn())
813
- * .add(Transform, { x: 0, y: 0, rotation: 0 })
814
- * .add(Health, { current: 100, max: 100 })
815
- * .add(Velocity, { vx: 0, vy: 0 });
816
- *
817
- * // Use the handle
818
- * player.update(Transform, { x: 10 });
819
- * const health = player.get(Health);
820
- *
821
- * // Mix with raw API
822
- * world.add(player.id, Armor, { value: 50 });
823
- * ```
824
- */
825
- entity(entityId: Entity): EntityHandle {
826
- return new EntityHandle(this, entityId);
827
- }
828
- }