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,799 +0,0 @@
1
- import { describe, expect, test, beforeEach } from "bun:test";
2
- import { ServerNetwork } from "./server";
3
- import { IntentRegistry } from "../protocol/intent/intent-registry";
4
- import { SnapshotRegistry } from "../protocol/snapshot/snapshot-registry";
5
- import { PooledCodec } from "../core/pooled-codec/pooled-codec";
6
- import { BinaryPrimitives } from "../core/binary-codec";
7
- import { defineIntent } from "../protocol/intent/define-intent";
8
- import type { TransportAdapter, ServerTransportAdapter } from "./types";
9
- import type { Snapshot } from "../protocol/snapshot/snapshot";
10
-
11
- // Define move intent using defineIntent
12
- const MoveIntent = defineIntent({
13
- kind: 1 as const,
14
- schema: {
15
- dx: BinaryPrimitives.f32,
16
- dy: BinaryPrimitives.f32,
17
- },
18
- });
19
-
20
- type MoveIntent = typeof MoveIntent.type;
21
-
22
- interface PlayerUpdate {
23
- x: number;
24
- y: number;
25
- health: number;
26
- }
27
-
28
- interface ScoreUpdate {
29
- score: number;
30
- }
31
-
32
- type GameSnapshots = PlayerUpdate | ScoreUpdate;
33
-
34
- // Mock peer transport
35
- class MockPeerTransport implements TransportAdapter {
36
- messageHandler: ((data: Uint8Array) => void) | null = null;
37
- private closeHandler: (() => void) | null = null;
38
- public sentMessages: Uint8Array[] = [];
39
- public closed = false;
40
-
41
- send(data: Uint8Array): void {
42
- this.sentMessages.push(new Uint8Array(data)); // Copy to avoid mutation
43
- }
44
-
45
- onMessage(handler: (data: Uint8Array) => void): void {
46
- this.messageHandler = handler;
47
- }
48
-
49
- onClose(handler: () => void): void {
50
- this.closeHandler = handler;
51
- }
52
-
53
- close(): void {
54
- this.closed = true;
55
- if (this.closeHandler) {
56
- this.closeHandler();
57
- }
58
- }
59
-
60
- // Test helper: simulate receiving a message
61
- simulateMessage(data: Uint8Array): void {
62
- if (this.messageHandler) {
63
- this.messageHandler(data);
64
- }
65
- }
66
- }
67
-
68
- // Mock server transport
69
- class MockServerTransport implements ServerTransportAdapter<MockPeerTransport> {
70
- private connectionHandler: ((peer: MockPeerTransport, peerId: string) => void) | null = null;
71
- private disconnectionHandler: ((peerId: string) => void) | null = null;
72
- private peers = new Map<string, MockPeerTransport>();
73
- public closed = false;
74
-
75
- onConnection(handler: (peer: MockPeerTransport, peerId: string) => void): void {
76
- this.connectionHandler = handler;
77
- }
78
-
79
- onDisconnection(handler: (peerId: string) => void): void {
80
- this.disconnectionHandler = handler;
81
- }
82
-
83
- getPeer(peerId: string): MockPeerTransport | undefined {
84
- return this.peers.get(peerId);
85
- }
86
-
87
- getPeerIds(): string[] {
88
- return Array.from(this.peers.keys());
89
- }
90
-
91
- close(): void {
92
- this.closed = true;
93
- }
94
-
95
- // Test helpers
96
- simulateConnection(peerId: string): MockPeerTransport {
97
- const peer = new MockPeerTransport();
98
- this.peers.set(peerId, peer);
99
- if (this.connectionHandler) {
100
- this.connectionHandler(peer, peerId);
101
- }
102
- return peer;
103
- }
104
-
105
- simulateDisconnection(peerId: string): void {
106
- this.peers.delete(peerId);
107
- if (this.disconnectionHandler) {
108
- this.disconnectionHandler(peerId);
109
- }
110
- }
111
- }
112
-
113
- describe("ServerNetwork", () => {
114
- let transport: MockServerTransport;
115
- let intentRegistry: IntentRegistry;
116
- let server: ServerNetwork<MockPeerTransport, GameSnapshots>;
117
-
118
- beforeEach(() => {
119
- transport = new MockServerTransport();
120
- intentRegistry = new IntentRegistry();
121
-
122
- // Register move intent
123
- intentRegistry.register(MoveIntent);
124
-
125
- server = new ServerNetwork<MockPeerTransport, GameSnapshots>({
126
- transport,
127
- intentRegistry,
128
- createPeerSnapshotRegistry: () => {
129
- const registry = new SnapshotRegistry<GameSnapshots>();
130
-
131
- const playerCodec = new PooledCodec({
132
- x: BinaryPrimitives.f32,
133
- y: BinaryPrimitives.f32,
134
- health: BinaryPrimitives.u8,
135
- });
136
- registry.register("player", playerCodec);
137
-
138
- const scoreCodec = new PooledCodec({
139
- score: BinaryPrimitives.u32,
140
- });
141
- registry.register("score", scoreCodec);
142
-
143
- return registry;
144
- },
145
- config: { debug: false },
146
- });
147
- });
148
-
149
- describe("Peer connection lifecycle", () => {
150
- test("should handle new peer connection", () => {
151
- const peer = transport.simulateConnection("peer1");
152
-
153
- expect(server.getPeerIds()).toEqual(["peer1"]);
154
- expect(server.getPeerState("peer1")).toBeDefined();
155
- expect(server.getPeerSnapshotRegistry("peer1")).toBeDefined();
156
- });
157
-
158
- test("should create peer-specific snapshot registry", () => {
159
- transport.simulateConnection("peer1");
160
- transport.simulateConnection("peer2");
161
-
162
- const registry1 = server.getPeerSnapshotRegistry("peer1");
163
- const registry2 = server.getPeerSnapshotRegistry("peer2");
164
-
165
- expect(registry1).toBeDefined();
166
- expect(registry2).toBeDefined();
167
- expect(registry1).not.toBe(registry2); // Each peer has own registry
168
- });
169
-
170
- test("should trigger onConnection handlers", () => {
171
- const connectedPeers: string[] = [];
172
- server.onConnection((peerId) => {
173
- connectedPeers.push(peerId);
174
- });
175
-
176
- transport.simulateConnection("peer1");
177
- transport.simulateConnection("peer2");
178
-
179
- expect(connectedPeers).toEqual(["peer1", "peer2"]);
180
- });
181
-
182
- test("should setup message handler for peer", () => {
183
- const peer = transport.simulateConnection("peer1");
184
- expect(peer.messageHandler).not.toBeNull();
185
- });
186
-
187
- test("should initialize peer state correctly", () => {
188
- transport.simulateConnection("peer1");
189
- const state = server.getPeerState("peer1");
190
-
191
- expect(state).toBeDefined();
192
- expect(state!.peerId).toBe("peer1");
193
- expect(state!.lastSentTick).toBe(0);
194
- expect(state!.connectedAt).toBeGreaterThan(0);
195
- expect(state!.metadata).toEqual({});
196
- });
197
-
198
- test("should handle peer disconnection", () => {
199
- transport.simulateConnection("peer1");
200
- expect(server.getPeerIds()).toHaveLength(1);
201
-
202
- transport.simulateDisconnection("peer1");
203
- expect(server.getPeerIds()).toHaveLength(0);
204
- expect(server.getPeerState("peer1")).toBeUndefined();
205
- expect(server.getPeerSnapshotRegistry("peer1")).toBeUndefined();
206
- });
207
-
208
- test("should trigger onDisconnection handlers", () => {
209
- const disconnectedPeers: string[] = [];
210
- server.onDisconnection((peerId) => {
211
- disconnectedPeers.push(peerId);
212
- });
213
-
214
- transport.simulateConnection("peer1");
215
- transport.simulateConnection("peer2");
216
- transport.simulateDisconnection("peer1");
217
-
218
- expect(disconnectedPeers).toEqual(["peer1"]);
219
- expect(server.getPeerIds()).toEqual(["peer2"]);
220
- });
221
-
222
- test("should handle multiple connection/disconnection handlers", () => {
223
- let connectCount = 0;
224
- let disconnectCount = 0;
225
-
226
- server.onConnection(() => connectCount++);
227
- server.onConnection(() => connectCount++);
228
- server.onDisconnection(() => disconnectCount++);
229
- server.onDisconnection(() => disconnectCount++);
230
-
231
- transport.simulateConnection("peer1");
232
- transport.simulateDisconnection("peer1");
233
-
234
- expect(connectCount).toBe(2);
235
- expect(disconnectCount).toBe(2);
236
- });
237
- });
238
-
239
- describe("Intent handling", () => {
240
- test("should receive and decode intent from peer", () => {
241
- const receivedIntents: Array<{ peerId: string; intent: MoveIntent }> = [];
242
- server.onIntent<MoveIntent>(MoveIntent, (peerId, intent) => {
243
- receivedIntents.push({ peerId, intent });
244
- });
245
-
246
- const peer = transport.simulateConnection("peer1");
247
-
248
- // Encode intent
249
- const intent: MoveIntent = {
250
- kind: 1,
251
- tick: 42,
252
- dx: 10.5,
253
- dy: -5.3,
254
- };
255
- const intentData = intentRegistry.encode(intent);
256
-
257
- // Wrap with message type header
258
- const message = new Uint8Array(1 + intentData.byteLength);
259
- message[0] = 0x01; // MessageType.INTENT
260
- message.set(intentData, 1);
261
-
262
- peer.simulateMessage(message);
263
-
264
- expect(receivedIntents).toHaveLength(1);
265
- expect(receivedIntents[0].peerId).toBe("peer1");
266
- expect(receivedIntents[0].intent.kind).toBe(1);
267
- expect(receivedIntents[0].intent.tick).toBe(42);
268
- expect(receivedIntents[0].intent.dx).toBeCloseTo(10.5, 2);
269
- expect(receivedIntents[0].intent.dy).toBeCloseTo(-5.3, 2);
270
- });
271
-
272
- test("should handle intents from multiple peers", () => {
273
- const receivedIntents: Array<{ peerId: string; intent: MoveIntent }> = [];
274
- server.onIntent<MoveIntent>(MoveIntent, (peerId, intent) => {
275
- receivedIntents.push({ peerId, intent });
276
- });
277
-
278
- const peer1 = transport.simulateConnection("peer1");
279
- const peer2 = transport.simulateConnection("peer2");
280
-
281
- // Send intent from peer1
282
- const intent1: MoveIntent = { kind: 1, tick: 1, dx: 1, dy: 1 };
283
- const intentData1 = intentRegistry.encode(intent1);
284
- const message1 = new Uint8Array(1 + intentData1.byteLength);
285
- message1[0] = 0x01;
286
- message1.set(intentData1, 1);
287
- peer1.simulateMessage(message1);
288
-
289
- // Send intent from peer2
290
- const intent2: MoveIntent = { kind: 1, tick: 2, dx: 2, dy: 2 };
291
- const intentData2 = intentRegistry.encode(intent2);
292
- const message2 = new Uint8Array(1 + intentData2.byteLength);
293
- message2[0] = 0x01;
294
- message2.set(intentData2, 1);
295
- peer2.simulateMessage(message2);
296
-
297
- expect(receivedIntents).toHaveLength(2);
298
- expect(receivedIntents[0].peerId).toBe("peer1");
299
- expect(receivedIntents[1].peerId).toBe("peer2");
300
- });
301
-
302
- test("should handle missing intent handler gracefully", () => {
303
- const peer = transport.simulateConnection("peer1");
304
-
305
- const intent: MoveIntent = { kind: 1, tick: 1, dx: 1, dy: 1 };
306
- const intentData = intentRegistry.encode(intent);
307
- const message = new Uint8Array(1 + intentData.byteLength);
308
- message[0] = 0x01;
309
- message.set(intentData, 1);
310
-
311
- // No handler registered - should not throw
312
- expect(() => peer.simulateMessage(message)).not.toThrow();
313
- });
314
-
315
- test("should handle malformed intent data gracefully", () => {
316
- server.onIntent<MoveIntent>(MoveIntent, () => {});
317
- const peer = transport.simulateConnection("peer1");
318
-
319
- // Send malformed intent
320
- const badMessage = new Uint8Array([0x01, 99, 88, 77]);
321
- expect(() => peer.simulateMessage(badMessage)).not.toThrow();
322
- });
323
- });
324
-
325
- describe("sendSnapshotToPeer", () => {
326
- test("should send snapshot to specific peer", () => {
327
- const peer = transport.simulateConnection("peer1");
328
-
329
- const snapshot: Snapshot<PlayerUpdate> = {
330
- tick: 100,
331
- updates: {
332
- x: 50.5,
333
- y: 100.2,
334
- health: 80,
335
- },
336
- };
337
-
338
- server.sendSnapshotToPeer("peer1", "player", snapshot);
339
-
340
- expect(peer.sentMessages).toHaveLength(1);
341
- const message = peer.sentMessages[0];
342
-
343
- // Check message type header
344
- expect(message[0]).toBe(0x02); // MessageType.SNAPSHOT
345
-
346
- // Decode and verify
347
- const snapshotData = message.subarray(1);
348
- const registry = server.getPeerSnapshotRegistry("peer1")!;
349
- const decoded = registry.decode<PlayerUpdate>(snapshotData);
350
-
351
- expect(decoded.type).toBe("player");
352
- expect(decoded.snapshot.tick).toBe(100);
353
- expect(decoded.snapshot.updates.x).toBeCloseTo(50.5, 2);
354
- expect(decoded.snapshot.updates.y).toBeCloseTo(100.2, 2);
355
- expect(decoded.snapshot.updates.health).toBe(80);
356
- });
357
-
358
- test("should update peer lastSentTick", () => {
359
- transport.simulateConnection("peer1");
360
-
361
- const snapshot: Snapshot<PlayerUpdate> = {
362
- tick: 100,
363
- updates: { x: 1, y: 2, health: 100 },
364
- };
365
-
366
- server.sendSnapshotToPeer("peer1", "player", snapshot);
367
-
368
- const state = server.getPeerState("peer1");
369
- expect(state!.lastSentTick).toBe(100);
370
- });
371
-
372
- test("should handle sending to unknown peer gracefully", () => {
373
- const snapshot: Snapshot<PlayerUpdate> = {
374
- tick: 100,
375
- updates: { x: 1, y: 2, health: 100 },
376
- };
377
-
378
- // Should not throw
379
- expect(() => server.sendSnapshotToPeer("unknown", "player", snapshot)).not.toThrow();
380
- });
381
-
382
- test("should throw if peer has no snapshot registry", () => {
383
- // This shouldn't happen in normal usage, but test defensive code
384
- const peer = transport.simulateConnection("peer1");
385
-
386
- // Manually remove registry to simulate edge case
387
- (server as any).peerSnapshotRegistries.delete("peer1");
388
-
389
- const snapshot: Snapshot<PlayerUpdate> = {
390
- tick: 100,
391
- updates: { x: 1, y: 2, health: 100 },
392
- };
393
-
394
- expect(() => server.sendSnapshotToPeer("peer1", "player", snapshot)).toThrow(
395
- "No snapshot registry registered for peer: peer1"
396
- );
397
- });
398
- });
399
-
400
- describe("broadcastSnapshot", () => {
401
- test("should send snapshot to all connected peers", () => {
402
- const peer1 = transport.simulateConnection("peer1");
403
- const peer2 = transport.simulateConnection("peer2");
404
- const peer3 = transport.simulateConnection("peer3");
405
-
406
- const snapshot: Snapshot<ScoreUpdate> = {
407
- tick: 50,
408
- updates: { score: 9999 },
409
- };
410
-
411
- server.broadcastSnapshot("score", snapshot);
412
-
413
- expect(peer1.sentMessages).toHaveLength(1);
414
- expect(peer2.sentMessages).toHaveLength(1);
415
- expect(peer3.sentMessages).toHaveLength(1);
416
-
417
- // Verify all peers received same snapshot
418
- for (const peer of [peer1, peer2, peer3]) {
419
- const message = peer.sentMessages[0];
420
- expect(message[0]).toBe(0x02); // MessageType.SNAPSHOT
421
- }
422
- });
423
-
424
- test("should use peer-specific registries for encoding", () => {
425
- const peer1 = transport.simulateConnection("peer1");
426
- const peer2 = transport.simulateConnection("peer2");
427
-
428
- const snapshot: Snapshot<PlayerUpdate> = {
429
- tick: 100,
430
- updates: { x: 10, y: 20, health: 100 },
431
- };
432
-
433
- server.broadcastSnapshot("player", snapshot);
434
-
435
- // Each peer should receive encoded snapshot
436
- const registry1 = server.getPeerSnapshotRegistry("peer1")!;
437
- const registry2 = server.getPeerSnapshotRegistry("peer2")!;
438
-
439
- const decoded1 = registry1.decode<PlayerUpdate>(peer1.sentMessages[0].subarray(1));
440
- const decoded2 = registry2.decode<PlayerUpdate>(peer2.sentMessages[0].subarray(1));
441
-
442
- expect(decoded1.snapshot.tick).toBe(100);
443
- expect(decoded2.snapshot.tick).toBe(100);
444
- });
445
-
446
- test("should respect filter function", () => {
447
- const peer1 = transport.simulateConnection("peer1");
448
- const peer2 = transport.simulateConnection("peer2");
449
- const peer3 = transport.simulateConnection("peer3");
450
-
451
- const snapshot: Snapshot<ScoreUpdate> = {
452
- tick: 50,
453
- updates: { score: 100 },
454
- };
455
-
456
- // Only send to peer2 and peer3
457
- server.broadcastSnapshot("score", snapshot, (peerId) => peerId !== "peer1");
458
-
459
- expect(peer1.sentMessages).toHaveLength(0);
460
- expect(peer2.sentMessages).toHaveLength(1);
461
- expect(peer3.sentMessages).toHaveLength(1);
462
- });
463
-
464
- test("should handle empty peer list gracefully", () => {
465
- const snapshot: Snapshot<ScoreUpdate> = {
466
- tick: 1,
467
- updates: { score: 0 },
468
- };
469
-
470
- // No peers connected - should not throw
471
- expect(() => server.broadcastSnapshot("score", snapshot)).not.toThrow();
472
- });
473
- });
474
-
475
- describe("broadcastSnapshotWithCustomization", () => {
476
- test("should customize snapshot for each peer", () => {
477
- const peer1 = transport.simulateConnection("peer1");
478
- const peer2 = transport.simulateConnection("peer2");
479
-
480
- const baseSnapshot: Snapshot<PlayerUpdate> = {
481
- tick: 100,
482
- updates: { x: 10, y: 20, health: 100 },
483
- };
484
-
485
- // Customize: double the x coordinate for each peer
486
- server.broadcastSnapshotWithCustomization("player", baseSnapshot, (peerId, snapshot) => {
487
- return {
488
- tick: snapshot.tick,
489
- updates: {
490
- ...snapshot.updates,
491
- x: snapshot.updates.x! * 2,
492
- },
493
- };
494
- });
495
-
496
- const registry1 = server.getPeerSnapshotRegistry("peer1")!;
497
- const registry2 = server.getPeerSnapshotRegistry("peer2")!;
498
-
499
- const decoded1 = registry1.decode<PlayerUpdate>(peer1.sentMessages[0].subarray(1));
500
- const decoded2 = registry2.decode<PlayerUpdate>(peer2.sentMessages[0].subarray(1));
501
-
502
- expect(decoded1.snapshot.updates.x).toBeCloseTo(20, 2); // 10 * 2
503
- expect(decoded2.snapshot.updates.x).toBeCloseTo(20, 2); // 10 * 2
504
- });
505
-
506
- test("should allow different customization per peer", () => {
507
- const peer1 = transport.simulateConnection("peer1");
508
- const peer2 = transport.simulateConnection("peer2");
509
-
510
- const baseSnapshot: Snapshot<ScoreUpdate> = {
511
- tick: 100,
512
- updates: { score: 100 },
513
- };
514
-
515
- // Give peer1 double score, peer2 triple score
516
- server.broadcastSnapshotWithCustomization("score", baseSnapshot, (peerId, snapshot) => {
517
- const multiplier = peerId === "peer1" ? 2 : 3;
518
- return {
519
- tick: snapshot.tick,
520
- updates: {
521
- score: snapshot.updates.score! * multiplier,
522
- },
523
- };
524
- });
525
-
526
- const registry1 = server.getPeerSnapshotRegistry("peer1")!;
527
- const registry2 = server.getPeerSnapshotRegistry("peer2")!;
528
-
529
- const decoded1 = registry1.decode<ScoreUpdate>(peer1.sentMessages[0].subarray(1));
530
- const decoded2 = registry2.decode<ScoreUpdate>(peer2.sentMessages[0].subarray(1));
531
-
532
- expect(decoded1.snapshot.updates.score).toBe(200); // 100 * 2
533
- expect(decoded2.snapshot.updates.score).toBe(300); // 100 * 3
534
- });
535
- });
536
-
537
- describe("Peer metadata", () => {
538
- test("should set and retrieve peer metadata", () => {
539
- transport.simulateConnection("peer1");
540
-
541
- server.setPeerMetadata("peer1", "username", "Alice");
542
- server.setPeerMetadata("peer1", "team", "blue");
543
-
544
- const state = server.getPeerState("peer1");
545
- expect(state!.metadata["username"]).toBe("Alice");
546
- expect(state!.metadata["team"]).toBe("blue");
547
- });
548
-
549
- test("should handle setting metadata for unknown peer", () => {
550
- // Should not throw
551
- expect(() => server.setPeerMetadata("unknown", "key", "value")).not.toThrow();
552
- });
553
- });
554
-
555
- describe("Peer queries", () => {
556
- test("should return all peer IDs", () => {
557
- transport.simulateConnection("peer1");
558
- transport.simulateConnection("peer2");
559
- transport.simulateConnection("peer3");
560
-
561
- const peerIds = server.getPeerIds();
562
- expect(peerIds).toHaveLength(3);
563
- expect(peerIds).toContain("peer1");
564
- expect(peerIds).toContain("peer2");
565
- expect(peerIds).toContain("peer3");
566
- });
567
-
568
- test("should return empty array when no peers", () => {
569
- expect(server.getPeerIds()).toEqual([]);
570
- });
571
-
572
- test("should return undefined for unknown peer state", () => {
573
- expect(server.getPeerState("unknown")).toBeUndefined();
574
- });
575
-
576
- test("should return undefined for unknown peer registry", () => {
577
- expect(server.getPeerSnapshotRegistry("unknown")).toBeUndefined();
578
- });
579
- });
580
-
581
- describe("Message handling", () => {
582
- test("should ignore empty messages", () => {
583
- const peer = transport.simulateConnection("peer1");
584
- expect(() => peer.simulateMessage(new Uint8Array(0))).not.toThrow();
585
- });
586
-
587
- test("should handle custom message type", () => {
588
- const peer = transport.simulateConnection("peer1");
589
- const message = new Uint8Array([0xff, 1, 2, 3]); // MessageType.CUSTOM
590
- expect(() => peer.simulateMessage(message)).not.toThrow();
591
- });
592
-
593
- test("should handle unknown message types", () => {
594
- const peer = transport.simulateConnection("peer1");
595
- const message = new Uint8Array([0x99, 1, 2, 3]); // Unknown type
596
- expect(() => peer.simulateMessage(message)).not.toThrow();
597
- });
598
-
599
- test("should reject messages exceeding max size", () => {
600
- const smallServer = new ServerNetwork<MockPeerTransport, GameSnapshots>({
601
- transport,
602
- intentRegistry,
603
- createPeerSnapshotRegistry: () => new SnapshotRegistry<GameSnapshots>(),
604
- config: { maxMessageSize: 10 },
605
- });
606
-
607
- const intentsReceived: MoveIntent[] = [];
608
- smallServer.onIntent<MoveIntent>(MoveIntent, (_, intent) => {
609
- intentsReceived.push(intent);
610
- });
611
-
612
- const peer = transport.simulateConnection("peer1");
613
-
614
- // Create large message
615
- const largeMessage = new Uint8Array(100);
616
- largeMessage[0] = 0x01; // MessageType.INTENT
617
-
618
- peer.simulateMessage(largeMessage);
619
- expect(intentsReceived).toHaveLength(0);
620
- });
621
- });
622
-
623
- describe("close", () => {
624
- test("should close server transport", () => {
625
- server.close();
626
- expect(transport.closed).toBe(true);
627
- });
628
- });
629
-
630
- describe("Debug logging", () => {
631
- test("should not log when debug is false", () => {
632
- const logs: string[] = [];
633
- const originalLog = console.log;
634
- console.log = (...args: any[]) => logs.push(args.join(" "));
635
-
636
- transport.simulateConnection("peer1");
637
-
638
- console.log = originalLog;
639
- expect(logs.filter((l) => l.includes("[ServerNetwork]"))).toHaveLength(0);
640
- });
641
-
642
- test("should log when debug is true", () => {
643
- const logs: string[] = [];
644
- const originalLog = console.log;
645
- console.log = (...args: any[]) => logs.push(args.join(" "));
646
-
647
- const debugServer = new ServerNetwork<MockPeerTransport, GameSnapshots>({
648
- transport,
649
- intentRegistry,
650
- createPeerSnapshotRegistry: () => new SnapshotRegistry<GameSnapshots>(),
651
- config: { debug: true },
652
- });
653
-
654
- transport.simulateConnection("peer1");
655
-
656
- console.log = originalLog;
657
- expect(logs.filter((l) => l.includes("[ServerNetwork]")).length).toBeGreaterThan(0);
658
- });
659
- });
660
-
661
- describe("Delta detection with sendSnapshotToPeerIfChanged", () => {
662
- test("should send snapshot on first call (no previous hash)", () => {
663
- const peer = transport.simulateConnection("peer1");
664
-
665
- const snapshot: Snapshot<PlayerUpdate> = {
666
- tick: 1,
667
- updates: { x: 10, y: 20, health: 100 },
668
- };
669
-
670
- const wasSent = server.sendSnapshotToPeerIfChanged("peer1", "player", snapshot);
671
-
672
- expect(wasSent).toBe(true);
673
- expect(peer.sentMessages.length).toBe(1);
674
- });
675
-
676
- test("should not send snapshot if data unchanged", () => {
677
- const peer = transport.simulateConnection("peer1");
678
-
679
- const snapshot: Snapshot<PlayerUpdate> = {
680
- tick: 1,
681
- updates: { x: 10, y: 20, health: 100 },
682
- };
683
-
684
- // First send
685
- server.sendSnapshotToPeerIfChanged("peer1", "player", snapshot);
686
- expect(peer.sentMessages.length).toBe(1);
687
-
688
- // Second send with same data (different tick, same updates)
689
- const snapshot2: Snapshot<PlayerUpdate> = {
690
- tick: 2,
691
- updates: { x: 10, y: 20, health: 100 },
692
- };
693
-
694
- const wasSent = server.sendSnapshotToPeerIfChanged("peer1", "player", snapshot2);
695
-
696
- expect(wasSent).toBe(false);
697
- expect(peer.sentMessages.length).toBe(1); // Still only 1 message
698
- });
699
-
700
- test("should send snapshot if data changed", () => {
701
- const peer = transport.simulateConnection("peer1");
702
-
703
- const snapshot1: Snapshot<PlayerUpdate> = {
704
- tick: 1,
705
- updates: { x: 10, y: 20, health: 100 },
706
- };
707
-
708
- server.sendSnapshotToPeerIfChanged("peer1", "player", snapshot1);
709
- expect(peer.sentMessages.length).toBe(1);
710
-
711
- // Send with changed position
712
- const snapshot2: Snapshot<PlayerUpdate> = {
713
- tick: 2,
714
- updates: { x: 15, y: 20, health: 100 }, // x changed
715
- };
716
-
717
- const wasSent = server.sendSnapshotToPeerIfChanged("peer1", "player", snapshot2);
718
-
719
- expect(wasSent).toBe(true);
720
- expect(peer.sentMessages.length).toBe(2);
721
- });
722
-
723
- test("should track hashes separately per peer", () => {
724
- const peer1 = transport.simulateConnection("peer1");
725
- const peer2 = transport.simulateConnection("peer2");
726
-
727
- const snapshot: Snapshot<PlayerUpdate> = {
728
- tick: 1,
729
- updates: { x: 10, y: 20, health: 100 },
730
- };
731
-
732
- // Send to peer1
733
- const sent1 = server.sendSnapshotToPeerIfChanged("peer1", "player", snapshot);
734
- expect(sent1).toBe(true);
735
- expect(peer1.sentMessages.length).toBe(1);
736
-
737
- // Send same snapshot to peer2 - should send because peer2 hasn't received it
738
- const sent2 = server.sendSnapshotToPeerIfChanged("peer2", "player", snapshot);
739
- expect(sent2).toBe(true);
740
- expect(peer2.sentMessages.length).toBe(1);
741
-
742
- // Send again to peer1 - should not send (duplicate)
743
- const sent3 = server.sendSnapshotToPeerIfChanged("peer1", "player", snapshot);
744
- expect(sent3).toBe(false);
745
- expect(peer1.sentMessages.length).toBe(1);
746
- });
747
-
748
- test("should track hashes separately per snapshot type", () => {
749
- const peer = transport.simulateConnection("peer1");
750
-
751
- const playerSnapshot: Snapshot<PlayerUpdate> = {
752
- tick: 1,
753
- updates: { x: 10, y: 20, health: 100 },
754
- };
755
-
756
- const scoreSnapshot: Snapshot<ScoreUpdate> = {
757
- tick: 1,
758
- updates: { score: 50 },
759
- };
760
-
761
- // Send player snapshot
762
- server.sendSnapshotToPeerIfChanged("peer1", "player", playerSnapshot);
763
- expect(peer.sentMessages.length).toBe(1);
764
-
765
- // Send score snapshot - different type, should send
766
- server.sendSnapshotToPeerIfChanged("peer1", "score", scoreSnapshot);
767
- expect(peer.sentMessages.length).toBe(2);
768
-
769
- // Send player snapshot again - should not send (duplicate)
770
- const sent = server.sendSnapshotToPeerIfChanged("peer1", "player", playerSnapshot);
771
- expect(sent).toBe(false);
772
- expect(peer.sentMessages.length).toBe(2);
773
- });
774
-
775
- test("should cleanup hashes on peer disconnect", () => {
776
- const peer = transport.simulateConnection("peer1");
777
-
778
- const snapshot: Snapshot<PlayerUpdate> = {
779
- tick: 1,
780
- updates: { x: 10, y: 20, health: 100 },
781
- };
782
-
783
- // Send snapshot
784
- server.sendSnapshotToPeerIfChanged("peer1", "player", snapshot);
785
- expect(peer.sentMessages.length).toBe(1);
786
-
787
- // Disconnect
788
- transport.simulateDisconnection("peer1");
789
-
790
- // Reconnect with same ID
791
- const newPeer = transport.simulateConnection("peer1");
792
-
793
- // Should send again (hash was cleared on disconnect)
794
- const wasSent = server.sendSnapshotToPeerIfChanged("peer1", "player", snapshot);
795
- expect(wasSent).toBe(true);
796
- expect(newPeer.sentMessages.length).toBe(1);
797
- });
798
- });
799
- });