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
@@ -1,807 +0,0 @@
1
- import { describe, expect, test, beforeEach } from "bun:test";
2
- import { ClientNetwork } from "./client";
3
- import { IntentRegistry } from "../protocol/intent/intent-registry";
4
- import { SnapshotRegistry } from "../protocol/snapshot/snapshot-registry";
5
- import { RpcRegistry } from "../protocol/rpc/rpc-registry";
6
- import { PooledCodec } from "../core/pooled-codec/pooled-codec";
7
- import { BinaryPrimitives } from "../core/binary-codec";
8
- import { defineIntent } from "../protocol/intent/define-intent";
9
- import { defineRPC } from "../protocol/rpc/define-rpc";
10
- import type { TransportAdapter } from "./types";
11
- import { MessageType } from "./types";
12
- import type { Snapshot } from "../protocol/snapshot/snapshot";
13
-
14
- // Define move intent using defineIntent
15
- const MoveIntent = defineIntent({
16
- kind: 1 as const,
17
- schema: {
18
- dx: BinaryPrimitives.f32,
19
- dy: BinaryPrimitives.f32,
20
- },
21
- });
22
-
23
- type MoveIntent = typeof MoveIntent.type;
24
-
25
- interface PlayerUpdate {
26
- x: number;
27
- y: number;
28
- health: number;
29
- }
30
-
31
- interface ScoreUpdate {
32
- score: number;
33
- }
34
-
35
- type GameSnapshots = PlayerUpdate | ScoreUpdate;
36
-
37
- // Mock transport adapter
38
- class MockTransportAdapter implements TransportAdapter {
39
- messageHandler: ((data: Uint8Array) => void) | null = null;
40
- closeHandler: (() => void) | null = null;
41
- openHandler: (() => void) | null = null;
42
- public sentMessages: Uint8Array[] = [];
43
- public closed = false;
44
-
45
- send(data: Uint8Array): void {
46
- this.sentMessages.push(new Uint8Array(data)); // Copy to avoid mutation
47
- }
48
-
49
- onMessage(handler: (data: Uint8Array) => void): void {
50
- this.messageHandler = handler;
51
- }
52
-
53
- onClose(handler: () => void): void {
54
- this.closeHandler = handler;
55
- }
56
-
57
- onOpen(handler: () => void): void {
58
- this.openHandler = handler;
59
- }
60
-
61
- close(): void {
62
- this.closed = true;
63
- if (this.closeHandler) {
64
- this.closeHandler();
65
- }
66
- }
67
-
68
- // Test helper: simulate receiving a message
69
- simulateMessage(data: Uint8Array): void {
70
- if (this.messageHandler) {
71
- this.messageHandler(data);
72
- }
73
- }
74
-
75
- // Test helper: simulate disconnection
76
- simulateDisconnect(): void {
77
- if (this.closeHandler) {
78
- this.closeHandler();
79
- }
80
- }
81
- }
82
-
83
- describe("ClientNetwork", () => {
84
- let transport: MockTransportAdapter;
85
- let intentRegistry: IntentRegistry;
86
- let snapshotRegistry: SnapshotRegistry<GameSnapshots>;
87
- let client: ClientNetwork<GameSnapshots>;
88
-
89
- beforeEach(() => {
90
- transport = new MockTransportAdapter();
91
- intentRegistry = new IntentRegistry();
92
- snapshotRegistry = new SnapshotRegistry<GameSnapshots>();
93
-
94
- // Register move intent
95
- intentRegistry.register(MoveIntent);
96
-
97
- // Register snapshot codecs
98
- const playerCodec = new PooledCodec({
99
- x: BinaryPrimitives.f32,
100
- y: BinaryPrimitives.f32,
101
- health: BinaryPrimitives.u8,
102
- });
103
- snapshotRegistry.register("player", playerCodec);
104
-
105
- const scoreCodec = new PooledCodec({
106
- score: BinaryPrimitives.u32,
107
- });
108
- snapshotRegistry.register("score", scoreCodec);
109
-
110
- client = new ClientNetwork<GameSnapshots>({
111
- transport,
112
- intentRegistry,
113
- snapshotRegistry,
114
- config: { debug: false },
115
- });
116
-
117
- // Simulate connection opened
118
- if (transport.openHandler) {
119
- transport.openHandler();
120
- }
121
- });
122
-
123
- describe("Construction", () => {
124
- test("should initialize and mark as connected", () => {
125
- expect(client.isConnected()).toBe(true);
126
- });
127
-
128
- test("should setup transport handlers", () => {
129
- expect(transport.messageHandler).not.toBeNull();
130
- expect(transport.closeHandler).not.toBeNull();
131
- });
132
-
133
- test("should trigger onConnect handlers", () => {
134
- let connectCalled = false;
135
- const newTransport = new MockTransportAdapter();
136
- const newClient = new ClientNetwork<GameSnapshots>({
137
- transport: newTransport,
138
- intentRegistry,
139
- snapshotRegistry,
140
- });
141
-
142
- newClient.onConnect(() => {
143
- connectCalled = true;
144
- });
145
-
146
- // Connection happens during constructor
147
- expect(connectCalled).toBe(false); // Handler registered after construction
148
- });
149
- });
150
-
151
- describe("sendIntent", () => {
152
- test("should encode and send intent to server", () => {
153
- const intent: MoveIntent = {
154
- kind: 1,
155
- tick: 100,
156
- dx: 5.5,
157
- dy: -3.2,
158
- };
159
-
160
- client.sendIntent(intent);
161
-
162
- expect(transport.sentMessages).toHaveLength(1);
163
- const message = transport.sentMessages[0];
164
-
165
- // Check message type header
166
- expect(message[0]).toBe(0x01); // MessageType.INTENT
167
-
168
- // Verify intent data (skip message type byte)
169
- const intentData = message.subarray(1);
170
- const decoded = intentRegistry.decode(intentData) as MoveIntent;
171
- expect(decoded.kind).toBe(1);
172
- expect(decoded.tick).toBe(100);
173
- expect(decoded.dx).toBeCloseTo(5.5, 2);
174
- expect(decoded.dy).toBeCloseTo(-3.2, 2);
175
- });
176
-
177
- test("should not send intent when disconnected", () => {
178
- transport.simulateDisconnect();
179
-
180
- const intent: MoveIntent = {
181
- kind: 1,
182
- tick: 100,
183
- dx: 1,
184
- dy: 1,
185
- };
186
-
187
- client.sendIntent(intent);
188
- expect(transport.sentMessages).toHaveLength(0);
189
- });
190
-
191
- test("should handle encoding errors gracefully", () => {
192
- const badIntentRegistry = new IntentRegistry();
193
- const badClient = new ClientNetwork<GameSnapshots>({
194
- transport: new MockTransportAdapter(),
195
- intentRegistry: badIntentRegistry,
196
- snapshotRegistry,
197
- });
198
-
199
- const intent: MoveIntent = {
200
- kind: 99 as 1, // Not registered
201
- tick: 100,
202
- dx: 1,
203
- dy: 1,
204
- };
205
-
206
- // Should not throw
207
- expect(() => badClient.sendIntent(intent)).not.toThrow();
208
- });
209
- });
210
-
211
- describe("onSnapshot", () => {
212
- test("should receive and decode player snapshot", () => {
213
- let receivedSnapshot: Snapshot<PlayerUpdate> | null = null;
214
-
215
- client.onSnapshot<PlayerUpdate>("player", (snapshot) => {
216
- receivedSnapshot = snapshot;
217
- });
218
-
219
- // Create snapshot
220
- const snapshot: Snapshot<PlayerUpdate> = {
221
- tick: 42,
222
- updates: {
223
- x: 10.5,
224
- y: 20.3,
225
- health: 100,
226
- },
227
- };
228
-
229
- // Encode and send
230
- const snapshotData = snapshotRegistry.encode("player", snapshot);
231
- const message = new Uint8Array(1 + snapshotData.byteLength);
232
- message[0] = 0x02; // MessageType.SNAPSHOT
233
- message.set(snapshotData, 1);
234
-
235
- transport.simulateMessage(message);
236
-
237
- expect(receivedSnapshot).not.toBeNull();
238
- expect(receivedSnapshot!.tick).toBe(42);
239
- expect(receivedSnapshot!.updates.x).toBeCloseTo(10.5, 2);
240
- expect(receivedSnapshot!.updates.y).toBeCloseTo(20.3, 2);
241
- expect(receivedSnapshot!.updates.health).toBe(100);
242
- });
243
-
244
- test("should receive and decode score snapshot", () => {
245
- let receivedSnapshot: Snapshot<ScoreUpdate> | null = null;
246
-
247
- client.onSnapshot<ScoreUpdate>("score", (snapshot) => {
248
- receivedSnapshot = snapshot;
249
- });
250
-
251
- const snapshot: Snapshot<ScoreUpdate> = {
252
- tick: 100,
253
- updates: {
254
- score: 9999,
255
- },
256
- };
257
-
258
- const snapshotData = snapshotRegistry.encode("score", snapshot);
259
- const message = new Uint8Array(1 + snapshotData.byteLength);
260
- message[0] = 0x02; // MessageType.SNAPSHOT
261
- message.set(snapshotData, 1);
262
-
263
- transport.simulateMessage(message);
264
-
265
- expect(receivedSnapshot).not.toBeNull();
266
- expect(receivedSnapshot!.tick).toBe(100);
267
- expect(receivedSnapshot!.updates.score).toBe(9999);
268
- });
269
-
270
- test("should handle multiple snapshot types independently", () => {
271
- const playerSnapshots: Snapshot<PlayerUpdate>[] = [];
272
- const scoreSnapshots: Snapshot<ScoreUpdate>[] = [];
273
-
274
- client.onSnapshot<PlayerUpdate>("player", (s) => playerSnapshots.push(s));
275
- client.onSnapshot<ScoreUpdate>("score", (s) => scoreSnapshots.push(s));
276
-
277
- // Send player snapshot
278
- const playerSnapshot: Snapshot<PlayerUpdate> = {
279
- tick: 1,
280
- updates: { x: 1, y: 2, health: 50 },
281
- };
282
- const playerData = snapshotRegistry.encode("player", playerSnapshot);
283
- const playerMsg = new Uint8Array(1 + playerData.byteLength);
284
- playerMsg[0] = 0x02;
285
- playerMsg.set(playerData, 1);
286
- transport.simulateMessage(playerMsg);
287
-
288
- // Send score snapshot
289
- const scoreSnapshot: Snapshot<ScoreUpdate> = {
290
- tick: 2,
291
- updates: { score: 123 },
292
- };
293
- const scoreData = snapshotRegistry.encode("score", scoreSnapshot);
294
- const scoreMsg = new Uint8Array(1 + scoreData.byteLength);
295
- scoreMsg[0] = 0x02;
296
- scoreMsg.set(scoreData, 1);
297
- transport.simulateMessage(scoreMsg);
298
-
299
- expect(playerSnapshots).toHaveLength(1);
300
- expect(scoreSnapshots).toHaveLength(1);
301
- expect(playerSnapshots[0].tick).toBe(1);
302
- expect(scoreSnapshots[0].tick).toBe(2);
303
- });
304
-
305
- test("should return unsubscribe function", () => {
306
- let callCount = 0;
307
- const unsubscribe = client.onSnapshot<PlayerUpdate>("player", () => {
308
- callCount++;
309
- });
310
-
311
- const snapshot: Snapshot<PlayerUpdate> = {
312
- tick: 1,
313
- updates: { x: 1, y: 1, health: 100 },
314
- };
315
- const snapshotData = snapshotRegistry.encode("player", snapshot);
316
- const message = new Uint8Array(1 + snapshotData.byteLength);
317
- message[0] = 0x02;
318
- message.set(snapshotData, 1);
319
-
320
- transport.simulateMessage(message);
321
- expect(callCount).toBe(1);
322
-
323
- // Unsubscribe
324
- unsubscribe();
325
-
326
- // Send another snapshot
327
- transport.simulateMessage(message);
328
- expect(callCount).toBe(1); // Should not increase
329
- });
330
-
331
- test("should handle unknown snapshot types gracefully", () => {
332
- // Register handler for "player" only
333
- let called = false;
334
- client.onSnapshot<PlayerUpdate>("player", () => {
335
- called = true;
336
- });
337
-
338
- // Send snapshot for unhandled type "score" (registered but no handler)
339
- const snapshot: Snapshot<ScoreUpdate> = {
340
- tick: 1,
341
- updates: { score: 42 },
342
- };
343
- const snapshotData = snapshotRegistry.encode("score", snapshot);
344
- const message = new Uint8Array(1 + snapshotData.byteLength);
345
- message[0] = 0x02;
346
- message.set(snapshotData, 1);
347
-
348
- // Should not throw or call the player handler
349
- expect(() => transport.simulateMessage(message)).not.toThrow();
350
- expect(called).toBe(false);
351
- });
352
- });
353
-
354
- describe("Connection lifecycle", () => {
355
- test("should trigger onConnect handler when connection opens", () => {
356
- let connectCalled = false;
357
- const newTransport = new MockTransportAdapter();
358
-
359
- const newClient = new ClientNetwork<GameSnapshots>({
360
- transport: newTransport,
361
- intentRegistry,
362
- snapshotRegistry,
363
- });
364
-
365
- newClient.onConnect(() => {
366
- connectCalled = true;
367
- });
368
-
369
- // Not connected yet - waiting for transport to open
370
- expect(connectCalled).toBe(false);
371
- expect(newClient.isConnected()).toBe(false);
372
-
373
- // Trigger open event
374
- if (newTransport.openHandler) {
375
- newTransport.openHandler();
376
- }
377
-
378
- // Now should be connected and handler should have been called
379
- expect(connectCalled).toBe(true);
380
- expect(newClient.isConnected()).toBe(true);
381
- });
382
-
383
- test("should trigger onDisconnect handler", () => {
384
- let disconnectCalled = false;
385
- client.onDisconnect(() => {
386
- disconnectCalled = true;
387
- });
388
-
389
- transport.simulateDisconnect();
390
-
391
- expect(disconnectCalled).toBe(true);
392
- expect(client.isConnected()).toBe(false);
393
- });
394
-
395
- test("should handle multiple disconnect handlers", () => {
396
- let count = 0;
397
- client.onDisconnect(() => count++);
398
- client.onDisconnect(() => count++);
399
- client.onDisconnect(() => count++);
400
-
401
- transport.simulateDisconnect();
402
- expect(count).toBe(3);
403
- });
404
-
405
- test("should return unsubscribe function for onConnect", () => {
406
- let callCount = 0;
407
- const unsub = client.onConnect(() => callCount++);
408
- unsub();
409
-
410
- // Create new client to trigger connect
411
- const newTransport = new MockTransportAdapter();
412
- const newClient = new ClientNetwork<GameSnapshots>({
413
- transport: newTransport,
414
- intentRegistry,
415
- snapshotRegistry,
416
- });
417
-
418
- expect(callCount).toBe(0);
419
- });
420
-
421
- test("should return unsubscribe function for onDisconnect", () => {
422
- let callCount = 0;
423
- const unsub = client.onDisconnect(() => callCount++);
424
-
425
- transport.simulateDisconnect();
426
- expect(callCount).toBe(1);
427
-
428
- unsub();
429
- // Can't trigger disconnect again on same transport, but verifies unsubscribe works
430
- });
431
- });
432
-
433
- describe("disconnect", () => {
434
- test("should close transport connection", () => {
435
- client.disconnect();
436
- expect(transport.closed).toBe(true);
437
- });
438
-
439
- test("should trigger disconnect handlers when calling disconnect", () => {
440
- let disconnectCalled = false;
441
- client.onDisconnect(() => {
442
- disconnectCalled = true;
443
- });
444
-
445
- client.disconnect();
446
- expect(disconnectCalled).toBe(true);
447
- expect(client.isConnected()).toBe(false);
448
- });
449
- });
450
-
451
- describe("Message handling", () => {
452
- test("should ignore empty messages", () => {
453
- let snapshotReceived = false;
454
- client.onSnapshot<PlayerUpdate>("player", () => {
455
- snapshotReceived = true;
456
- });
457
-
458
- transport.simulateMessage(new Uint8Array(0));
459
- expect(snapshotReceived).toBe(false);
460
- });
461
-
462
- test("should handle custom message type gracefully", () => {
463
- const message = new Uint8Array([0xff]); // MessageType.CUSTOM
464
- expect(() => transport.simulateMessage(message)).not.toThrow();
465
- });
466
-
467
- test("should handle unknown message types gracefully", () => {
468
- const message = new Uint8Array([0x99, 1, 2, 3]); // Unknown type
469
- expect(() => transport.simulateMessage(message)).not.toThrow();
470
- });
471
-
472
- test("should reject messages exceeding max size", () => {
473
- const smallClient = new ClientNetwork<GameSnapshots>({
474
- transport,
475
- intentRegistry,
476
- snapshotRegistry,
477
- config: { maxMessageSize: 10 },
478
- });
479
-
480
- let snapshotReceived = false;
481
- smallClient.onSnapshot<PlayerUpdate>("player", () => {
482
- snapshotReceived = true;
483
- });
484
-
485
- // Create large message
486
- const largeMessage = new Uint8Array(100);
487
- largeMessage[0] = 0x02; // MessageType.SNAPSHOT
488
-
489
- transport.simulateMessage(largeMessage);
490
- expect(snapshotReceived).toBe(false);
491
- });
492
-
493
- test("should handle malformed snapshot data gracefully", () => {
494
- let snapshotReceived = false;
495
- client.onSnapshot<PlayerUpdate>("player", () => {
496
- snapshotReceived = true;
497
- });
498
-
499
- // Send malformed data
500
- const badMessage = new Uint8Array([0x02, 99, 88, 77]); // Invalid snapshot
501
- expect(() => transport.simulateMessage(badMessage)).not.toThrow();
502
- expect(snapshotReceived).toBe(false);
503
- });
504
- });
505
-
506
- describe("Debug logging", () => {
507
- test("should not log when debug is false", () => {
508
- const logs: string[] = [];
509
- const originalLog = console.log;
510
- console.log = (...args: any[]) => logs.push(args.join(" "));
511
-
512
- const intent: MoveIntent = {
513
- kind: 1,
514
- tick: 1,
515
- dx: 1,
516
- dy: 1,
517
- };
518
- client.sendIntent(intent);
519
-
520
- console.log = originalLog;
521
- expect(logs.filter((l) => l.includes("[ClientNetwork]"))).toHaveLength(0);
522
- });
523
-
524
- test("should log when debug is true", () => {
525
- const logs: string[] = [];
526
- const originalLog = console.log;
527
- console.log = (...args: any[]) => logs.push(args.join(" "));
528
-
529
- const debugClient = new ClientNetwork<GameSnapshots>({
530
- transport: new MockTransportAdapter(),
531
- intentRegistry,
532
- snapshotRegistry,
533
- config: { debug: true },
534
- });
535
-
536
- const intent: MoveIntent = {
537
- kind: 1,
538
- tick: 1,
539
- dx: 1,
540
- dy: 1,
541
- };
542
- debugClient.sendIntent(intent);
543
-
544
- console.log = originalLog;
545
- expect(logs.filter((l) => l.includes("[ClientNetwork]")).length).toBeGreaterThan(0);
546
- });
547
- });
548
-
549
- describe("Memory pooling", () => {
550
- test("should reuse pooled objects across snapshots (zero-copy)", () => {
551
- const transport = new MockTransportAdapter();
552
- const client = new ClientNetwork<GameSnapshots>({
553
- transport,
554
- intentRegistry,
555
- snapshotRegistry,
556
- config: { debug: false },
557
- });
558
-
559
- // Extract data immediately (correct pattern for zero-copy)
560
- const extractedData: Array<{ tick: number; x: number; y: number; health: number }> = [];
561
-
562
- client.onSnapshot<PlayerUpdate>("player", (snapshot) => {
563
- // CORRECT: Extract data immediately, don't store references
564
- extractedData.push({
565
- tick: snapshot.tick,
566
- x: snapshot.updates.x!,
567
- y: snapshot.updates.y!,
568
- health: snapshot.updates.health!,
569
- });
570
- });
571
-
572
- // Simulate opening connection
573
- if (transport.openHandler) transport.openHandler();
574
-
575
- // Send first snapshot (wrap with MessageType.SNAPSHOT header)
576
- const snapshot1Data = snapshotRegistry.encode("player", {
577
- tick: 1,
578
- updates: { x: 10, y: 20, health: 100 },
579
- });
580
- const snapshot1 = new Uint8Array(1 + snapshot1Data.byteLength);
581
- snapshot1[0] = MessageType.SNAPSHOT;
582
- snapshot1.set(snapshot1Data, 1);
583
- if (transport.messageHandler) transport.messageHandler(snapshot1);
584
-
585
- // Send second snapshot with different data
586
- const snapshot2Data = snapshotRegistry.encode("player", {
587
- tick: 2,
588
- updates: { x: 15, y: 25, health: 90 },
589
- });
590
- const snapshot2 = new Uint8Array(1 + snapshot2Data.byteLength);
591
- snapshot2[0] = MessageType.SNAPSHOT;
592
- snapshot2.set(snapshot2Data, 1);
593
- if (transport.messageHandler) transport.messageHandler(snapshot2);
594
-
595
- // Verify both snapshots were received correctly
596
- expect(extractedData.length).toBe(2);
597
-
598
- // First snapshot data should be correct
599
- expect(extractedData[0].tick).toBe(1);
600
- expect(extractedData[0].x).toBe(10);
601
- expect(extractedData[0].y).toBe(20);
602
- expect(extractedData[0].health).toBe(100);
603
-
604
- // Second snapshot data should be correct
605
- expect(extractedData[1].tick).toBe(2);
606
- expect(extractedData[1].x).toBe(15);
607
- expect(extractedData[1].y).toBe(25);
608
- expect(extractedData[1].health).toBe(90);
609
- });
610
-
611
- test("handlers must extract data immediately (zero-copy pattern)", () => {
612
- const transport = new MockTransportAdapter();
613
- const client = new ClientNetwork<GameSnapshots>({
614
- transport,
615
- intentRegistry,
616
- snapshotRegistry,
617
- config: { debug: false },
618
- });
619
-
620
- // Simulate a reconciliator-like usage pattern (correct way)
621
- interface ExtractedState {
622
- x: number;
623
- y: number;
624
- health: number;
625
- }
626
- let extractedState: ExtractedState | null = null;
627
-
628
- client.onSnapshot<PlayerUpdate>("player", (snapshot) => {
629
- // CORRECT: Extract data immediately instead of storing references
630
- extractedState = {
631
- x: snapshot.updates.x!,
632
- y: snapshot.updates.y!,
633
- health: snapshot.updates.health!,
634
- };
635
- });
636
-
637
- // Simulate opening connection
638
- if (transport.openHandler) transport.openHandler();
639
-
640
- // Send first snapshot (wrap with MessageType.SNAPSHOT header)
641
- const snapshot1Data = snapshotRegistry.encode("player", {
642
- tick: 1,
643
- updates: { x: 10, y: 20, health: 100 },
644
- });
645
- const snapshot1 = new Uint8Array(1 + snapshot1Data.byteLength);
646
- snapshot1[0] = MessageType.SNAPSHOT;
647
- snapshot1.set(snapshot1Data, 1);
648
- if (transport.messageHandler) transport.messageHandler(snapshot1);
649
-
650
- const firstState = extractedState!;
651
- expect(firstState.x).toBe(10);
652
- expect(firstState.y).toBe(20);
653
- expect(firstState.health).toBe(100);
654
-
655
- // Send second snapshot (wrap with MessageType.SNAPSHOT header)
656
- const snapshot2Data = snapshotRegistry.encode("player", {
657
- tick: 2,
658
- updates: { x: 99, y: 99, health: 50 },
659
- });
660
- const snapshot2 = new Uint8Array(1 + snapshot2Data.byteLength);
661
- snapshot2[0] = MessageType.SNAPSHOT;
662
- snapshot2.set(snapshot2Data, 1);
663
- if (transport.messageHandler) transport.messageHandler(snapshot2);
664
-
665
- // First extracted state should NOT be mutated (we extracted primitives)
666
- expect(firstState.x).toBe(10);
667
- expect(firstState.y).toBe(20);
668
- expect(firstState.health).toBe(100);
669
-
670
- // New extracted state should have the new values
671
- expect(extractedState!.x).toBe(99);
672
- expect(extractedState!.y).toBe(99);
673
- expect(extractedState!.health).toBe(50);
674
- });
675
- });
676
-
677
- describe("RPC Memory pooling", () => {
678
- // Define RPC for testing
679
- const TestRPC = defineRPC({
680
- method: "testRpc",
681
- schema: {
682
- value: BinaryPrimitives.u32,
683
- message: BinaryPrimitives.string(32),
684
- },
685
- });
686
-
687
- interface TestRPCData {
688
- value: number;
689
- message: string;
690
- }
691
-
692
- test("should reuse pooled objects across RPC calls", () => {
693
- const rpcRegistry = new RpcRegistry();
694
- rpcRegistry.register(TestRPC);
695
-
696
- const transport = new MockTransportAdapter();
697
- const client = new ClientNetwork<GameSnapshots>({
698
- transport,
699
- intentRegistry,
700
- snapshotRegistry,
701
- rpcRegistry,
702
- config: { debug: false },
703
- });
704
-
705
- const receivedRpcs: Array<TestRPCData> = [];
706
-
707
- client.onRPC(TestRPC, (data) => {
708
- // Store the RPC data - this should be safe due to shallow copy
709
- receivedRpcs.push(data);
710
- });
711
-
712
- // Simulate opening connection
713
- if (transport.openHandler) transport.openHandler();
714
-
715
- // Send first RPC
716
- const rpc1Data = rpcRegistry.encode(TestRPC, {
717
- value: 100,
718
- message: "first",
719
- });
720
- const rpc1 = new Uint8Array(1 + rpc1Data.byteLength);
721
- rpc1[0] = MessageType.CUSTOM;
722
- rpc1.set(rpc1Data, 1);
723
- if (transport.messageHandler) transport.messageHandler(rpc1);
724
-
725
- // Send second RPC with different data
726
- const rpc2Data = rpcRegistry.encode(TestRPC, {
727
- value: 200,
728
- message: "second",
729
- });
730
- const rpc2 = new Uint8Array(1 + rpc2Data.byteLength);
731
- rpc2[0] = MessageType.CUSTOM;
732
- rpc2.set(rpc2Data, 1);
733
- if (transport.messageHandler) transport.messageHandler(rpc2);
734
-
735
- // Verify both RPCs were received correctly
736
- expect(receivedRpcs.length).toBe(2);
737
-
738
- // First RPC should maintain its original values
739
- expect(receivedRpcs[0].value).toBe(100);
740
- expect(receivedRpcs[0].message).toBe("first");
741
-
742
- // Second RPC should have its own values
743
- expect(receivedRpcs[1].value).toBe(200);
744
- expect(receivedRpcs[1].message).toBe("second");
745
-
746
- // The data objects should be different references (shallow copy worked)
747
- expect(receivedRpcs[0]).not.toBe(receivedRpcs[1]);
748
- });
749
-
750
- test("handlers can safely store references to RPC data", () => {
751
- const rpcRegistry = new RpcRegistry();
752
- rpcRegistry.register(TestRPC);
753
-
754
- const transport = new MockTransportAdapter();
755
- const client = new ClientNetwork<GameSnapshots>({
756
- transport,
757
- intentRegistry,
758
- snapshotRegistry,
759
- rpcRegistry,
760
- config: { debug: false },
761
- });
762
-
763
- // Simulate storing RPC data (common pattern)
764
- let storedData: TestRPCData | null = null;
765
-
766
- client.onRPC(TestRPC, (data) => {
767
- // Store the data directly
768
- storedData = data;
769
- });
770
-
771
- // Simulate opening connection
772
- if (transport.openHandler) transport.openHandler();
773
-
774
- // Send first RPC
775
- const rpc1Data = rpcRegistry.encode(TestRPC, {
776
- value: 42,
777
- message: "hello",
778
- });
779
- const rpc1 = new Uint8Array(1 + rpc1Data.byteLength);
780
- rpc1[0] = MessageType.CUSTOM;
781
- rpc1.set(rpc1Data, 1);
782
- if (transport.messageHandler) transport.messageHandler(rpc1);
783
-
784
- const firstData = storedData;
785
- expect((firstData as unknown as TestRPCData)?.value).toBe(42);
786
- expect((firstData as unknown as TestRPCData)?.message).toBe("hello");
787
-
788
- // Send second RPC
789
- const rpc2Data = rpcRegistry.encode(TestRPC, {
790
- value: 999,
791
- message: "world",
792
- });
793
- const rpc2 = new Uint8Array(1 + rpc2Data.byteLength);
794
- rpc2[0] = MessageType.CUSTOM;
795
- rpc2.set(rpc2Data, 1);
796
- if (transport.messageHandler) transport.messageHandler(rpc2);
797
-
798
- // First stored data should NOT be mutated by the second RPC
799
- expect((firstData as unknown as TestRPCData)?.value).toBe(42);
800
- expect((firstData as unknown as TestRPCData)?.message).toBe("hello");
801
-
802
- // New stored data should have the new values
803
- expect((storedData as unknown as TestRPCData)?.value).toBe(999);
804
- expect((storedData as unknown as TestRPCData)?.message).toBe("world");
805
- });
806
- });
807
- });