murow 0.0.70 → 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.
- package/README.md +52 -37
- package/dist/cjs/core/binary-codec/binary-codec.js +1 -0
- package/dist/cjs/core/binary-codec/index.js +1 -0
- package/dist/cjs/core/driver/driver.js +1 -0
- package/dist/cjs/core/driver/drivers/immediate.js +1 -0
- package/dist/cjs/core/driver/drivers/index.js +1 -0
- package/dist/cjs/core/driver/drivers/raf.js +1 -0
- package/dist/cjs/core/driver/drivers/timeout.js +1 -0
- package/dist/cjs/core/driver/index.js +1 -0
- package/dist/cjs/core/events/event-system.js +1 -0
- package/dist/cjs/core/events/index.js +1 -0
- package/dist/cjs/core/fixed-ticker/fixed-ticker.js +1 -0
- package/dist/cjs/core/fixed-ticker/index.js +1 -0
- package/dist/cjs/core/free-list/free-list.js +1 -0
- package/dist/cjs/core/free-list/index.js +1 -0
- package/dist/cjs/core/generate-id/generate-id.js +1 -0
- package/dist/cjs/core/generate-id/index.js +1 -0
- package/dist/cjs/core/index.js +1 -0
- package/dist/cjs/core/input/index.js +1 -0
- package/dist/cjs/core/input/manager.js +1 -0
- package/dist/cjs/core/input/sources/browser.js +1 -0
- package/dist/cjs/core/input/sources/index.js +1 -0
- package/dist/cjs/core/input/types.js +1 -0
- package/dist/cjs/core/lerp/index.js +1 -0
- package/dist/cjs/core/lerp/lerp.js +1 -0
- package/dist/cjs/core/navmesh/index.js +1 -0
- package/dist/cjs/core/navmesh/navmesh-worker-pool.js +1 -0
- package/dist/cjs/core/navmesh/navmesh.js +1 -0
- package/dist/cjs/core/navmesh/navmesh.worker.js +1 -0
- package/dist/cjs/core/pooled-codec/index.js +1 -0
- package/dist/cjs/core/pooled-codec/pooled-codec.js +1 -0
- package/dist/cjs/core/prediction/index.js +1 -0
- package/dist/cjs/core/prediction/prediction.js +1 -0
- package/dist/cjs/core/ray/index.js +1 -0
- package/dist/cjs/core/ray/ray-2d.js +1 -0
- package/dist/cjs/core/ray/ray-3d.js +1 -0
- package/dist/cjs/core/simple-rng/index.js +1 -0
- package/dist/cjs/core/simple-rng/simple-rng.js +1 -0
- package/dist/cjs/core/sparse-batcher/index.js +1 -0
- package/dist/cjs/core/sparse-batcher/sparse-batcher.js +1 -0
- package/dist/cjs/ecs/component-store.js +1 -0
- package/dist/cjs/ecs/component.js +1 -0
- package/dist/cjs/ecs/entity-handle.js +1 -0
- package/dist/cjs/ecs/index.js +1 -0
- package/dist/cjs/ecs/system-builder.js +1 -0
- package/dist/cjs/ecs/world-systems.js +1 -0
- package/dist/cjs/ecs/world.js +1 -0
- package/dist/cjs/game/index.js +1 -0
- package/dist/cjs/game/loop/index.js +1 -0
- package/dist/cjs/game/loop/loop.js +1 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/net/adapters/browser-websocket.js +1 -0
- package/dist/cjs/net/adapters/bun-websocket.js +1 -0
- package/dist/cjs/net/buffer-pool.js +1 -0
- package/dist/cjs/net/client.js +1 -0
- package/dist/cjs/net/index.js +1 -0
- package/dist/cjs/net/server.js +1 -0
- package/dist/cjs/net/types.js +1 -0
- package/dist/cjs/net/validators.js +1 -0
- package/dist/cjs/protocol/index.js +1 -0
- package/dist/cjs/protocol/intent/define-intent.js +1 -0
- package/dist/cjs/protocol/intent/index.js +1 -0
- package/dist/cjs/protocol/intent/intent-registry.js +1 -0
- package/dist/cjs/protocol/intent/intent.js +1 -0
- package/dist/cjs/protocol/rpc/define-rpc.js +1 -0
- package/dist/cjs/protocol/rpc/index.js +1 -0
- package/dist/cjs/protocol/rpc/rpc-registry.js +1 -0
- package/dist/cjs/protocol/rpc/rpc.js +1 -0
- package/dist/cjs/protocol/snapshot/index.js +1 -0
- package/dist/cjs/protocol/snapshot/snapshot-codec.js +1 -0
- package/dist/cjs/protocol/snapshot/snapshot-registry.js +1 -0
- package/dist/cjs/protocol/snapshot/snapshot.js +1 -0
- package/dist/cjs/renderer/base-2d-renderer.js +1 -0
- package/dist/cjs/renderer/base-3d-renderer.js +1 -0
- package/dist/cjs/renderer/base-renderer.js +1 -0
- package/dist/cjs/renderer/index.js +1 -0
- package/dist/cjs/renderer/types.js +1 -0
- package/dist/esm/core/binary-codec/binary-codec.js +1 -0
- package/dist/esm/core/binary-codec/index.js +1 -0
- package/dist/esm/core/driver/driver.js +1 -0
- package/dist/esm/core/driver/drivers/immediate.js +1 -0
- package/dist/esm/core/driver/drivers/index.js +1 -0
- package/dist/esm/core/driver/drivers/raf.js +1 -0
- package/dist/esm/core/driver/drivers/timeout.js +1 -0
- package/dist/esm/core/driver/index.js +1 -0
- package/dist/esm/core/events/event-system.js +1 -0
- package/dist/esm/core/events/index.js +1 -0
- package/dist/esm/core/fixed-ticker/fixed-ticker.js +1 -0
- package/dist/esm/core/fixed-ticker/index.js +1 -0
- package/dist/esm/core/free-list/free-list.js +1 -0
- package/dist/esm/core/free-list/index.js +1 -0
- package/dist/esm/core/generate-id/generate-id.js +1 -0
- package/dist/esm/core/generate-id/index.js +1 -0
- package/dist/esm/core/index.js +1 -0
- package/dist/esm/core/input/index.js +1 -0
- package/dist/esm/core/input/manager.js +1 -0
- package/dist/esm/core/input/sources/browser.js +1 -0
- package/dist/esm/core/input/sources/index.js +1 -0
- package/dist/esm/core/input/types.js +0 -0
- package/dist/esm/core/lerp/index.js +1 -0
- package/dist/esm/core/lerp/lerp.js +1 -0
- package/dist/esm/core/navmesh/index.js +1 -0
- package/dist/esm/core/navmesh/navmesh-worker-pool.js +1 -0
- package/dist/esm/core/navmesh/navmesh.js +1 -0
- package/dist/esm/core/navmesh/navmesh.worker.js +1 -0
- package/dist/esm/core/pooled-codec/index.js +1 -0
- package/dist/esm/core/pooled-codec/pooled-codec.js +1 -0
- package/dist/esm/core/prediction/index.js +1 -0
- package/dist/esm/core/prediction/prediction.js +1 -0
- package/dist/esm/core/ray/index.js +1 -0
- package/dist/esm/core/ray/ray-2d.js +1 -0
- package/dist/esm/core/ray/ray-3d.js +1 -0
- package/dist/esm/core/simple-rng/index.js +1 -0
- package/dist/esm/core/simple-rng/simple-rng.js +1 -0
- package/dist/esm/core/sparse-batcher/index.js +1 -0
- package/dist/esm/core/sparse-batcher/sparse-batcher.js +1 -0
- package/dist/esm/ecs/component-store.js +1 -0
- package/dist/esm/ecs/component.js +1 -0
- package/dist/esm/ecs/entity-handle.js +1 -0
- package/dist/esm/ecs/index.js +1 -0
- package/dist/esm/ecs/system-builder.js +1 -0
- package/dist/esm/ecs/world-systems.js +1 -0
- package/dist/esm/ecs/world.js +1 -0
- package/dist/esm/game/index.js +1 -0
- package/dist/esm/game/loop/index.js +1 -0
- package/dist/esm/game/loop/loop.js +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/net/adapters/browser-websocket.js +1 -0
- package/dist/esm/net/adapters/bun-websocket.js +1 -0
- package/dist/esm/net/buffer-pool.js +1 -0
- package/dist/esm/net/client.js +1 -0
- package/dist/esm/net/index.js +1 -0
- package/dist/esm/net/server.js +1 -0
- package/dist/esm/net/types.js +1 -0
- package/dist/esm/net/validators.js +1 -0
- package/dist/esm/protocol/index.js +1 -0
- package/dist/esm/protocol/intent/define-intent.js +1 -0
- package/dist/esm/protocol/intent/index.js +1 -0
- package/dist/esm/protocol/intent/intent-registry.js +1 -0
- package/dist/esm/protocol/intent/intent.js +0 -0
- package/dist/esm/protocol/rpc/define-rpc.js +1 -0
- package/dist/esm/protocol/rpc/index.js +1 -0
- package/dist/esm/protocol/rpc/rpc-registry.js +1 -0
- package/dist/esm/protocol/rpc/rpc.js +0 -0
- package/dist/esm/protocol/snapshot/index.js +1 -0
- package/dist/esm/protocol/snapshot/snapshot-codec.js +1 -0
- package/dist/esm/protocol/snapshot/snapshot-registry.js +1 -0
- package/dist/esm/protocol/snapshot/snapshot.js +1 -0
- package/dist/esm/renderer/base-2d-renderer.js +1 -0
- package/dist/esm/renderer/base-3d-renderer.js +1 -0
- package/dist/esm/renderer/base-renderer.js +1 -0
- package/dist/esm/renderer/index.js +1 -0
- package/dist/esm/renderer/types.js +0 -0
- package/dist/{core → types/core}/binary-codec/binary-codec.d.ts +4 -0
- package/dist/{core → types/core}/events/event-system.d.ts +14 -33
- package/dist/types/core/free-list/free-list.d.ts +31 -0
- package/dist/types/core/free-list/index.d.ts +1 -0
- package/dist/{core → types/core}/index.d.ts +5 -0
- package/dist/{core → types/core}/input/index.d.ts +1 -0
- package/dist/{core → types/core}/input/manager.d.ts +2 -0
- package/dist/{core → types/core}/navmesh/navmesh.d.ts +1 -21
- package/dist/types/core/ray/index.d.ts +2 -0
- package/dist/types/core/ray/ray-2d.d.ts +37 -0
- package/dist/types/core/ray/ray-3d.d.ts +42 -0
- package/dist/types/core/simple-rng/index.d.ts +1 -0
- package/dist/types/core/simple-rng/simple-rng.d.ts +36 -0
- package/dist/types/core/sparse-batcher/index.d.ts +1 -0
- package/dist/types/core/sparse-batcher/sparse-batcher.d.ts +55 -0
- package/dist/{ecs → types/ecs}/world.d.ts +11 -0
- package/dist/{game → types/game}/loop/loop.d.ts +33 -29
- package/dist/{index.d.ts → types/index.d.ts} +1 -0
- package/dist/{net → types/net}/index.d.ts +2 -2
- package/dist/types/renderer/base-2d-renderer.d.ts +13 -0
- package/dist/types/renderer/base-3d-renderer.d.ts +10 -0
- package/dist/types/renderer/base-renderer.d.ts +21 -0
- package/dist/types/renderer/index.d.ts +4 -0
- package/dist/types/renderer/types.d.ts +79 -0
- package/dist/webgpu/cjs/index.js +6004 -0
- package/dist/webgpu/esm/index.js +5972 -0
- package/dist/webgpu/types/2d/animation.d.ts +97 -0
- package/dist/webgpu/types/2d/renderer.d.ts +55 -0
- package/dist/webgpu/types/2d/shader.d.ts +61 -0
- package/dist/webgpu/types/2d/sprite-accessor.d.ts +47 -0
- package/dist/webgpu/types/3d/gltf-skin-parser.d.ts +101 -0
- package/dist/webgpu/types/3d/morph-animation.d.ts +69 -0
- package/dist/webgpu/types/3d/morph-animation.test.d.ts +1 -0
- package/dist/webgpu/types/3d/renderer.d.ts +216 -0
- package/dist/webgpu/types/3d/shader.d.ts +136 -0
- package/dist/webgpu/types/3d/skeletal-animation-compute/index.d.ts +2 -0
- package/dist/webgpu/types/3d/skeletal-animation-compute/kernel.d.ts +8 -0
- package/dist/webgpu/types/3d/skeletal-animation-compute/packer.d.ts +32 -0
- package/dist/webgpu/types/3d/skeletal-animation.d.ts +90 -0
- package/dist/webgpu/types/camera/camera-2d.d.ts +53 -0
- package/dist/webgpu/types/camera/camera-2d.test.d.ts +1 -0
- package/dist/webgpu/types/camera/camera-3d.d.ts +81 -0
- package/dist/webgpu/types/camera/camera-3d.test.d.ts +1 -0
- package/dist/webgpu/types/camera/index.d.ts +2 -0
- package/dist/webgpu/types/compute/compute-builder.d.ts +123 -0
- package/dist/webgpu/types/compute/compute-builder.test.d.ts +1 -0
- package/dist/webgpu/types/core/constants.d.ts +59 -0
- package/dist/webgpu/types/core/constants.test.d.ts +1 -0
- package/dist/webgpu/types/core/index.d.ts +2 -0
- package/dist/webgpu/types/core/math.d.ts +37 -0
- package/dist/webgpu/types/core/types.d.ts +125 -0
- package/dist/webgpu/types/core/types.test.d.ts +1 -0
- package/dist/webgpu/types/geometry/built-in.d.ts +58 -0
- package/dist/webgpu/types/geometry/built-in.test.d.ts +1 -0
- package/dist/webgpu/types/geometry/geometry-builder.d.ts +281 -0
- package/dist/webgpu/types/geometry/geometry-builder.test.d.ts +1 -0
- package/dist/webgpu/types/geometry/index.d.ts +2 -0
- package/dist/webgpu/types/index.d.ts +32 -0
- package/dist/webgpu/types/particle/emitter.d.ts +36 -0
- package/dist/webgpu/types/shaders/index.d.ts +2 -0
- package/dist/webgpu/types/shaders/runtime-transpile.d.ts +18 -0
- package/dist/webgpu/types/shaders/sprite-2d.wgsl.d.ts +10 -0
- package/dist/webgpu/types/shaders/typegpu.d.ts +9 -0
- package/dist/webgpu/types/shaders/utils.d.ts +28 -0
- package/dist/webgpu/types/shaders/utils.test.d.ts +1 -0
- package/dist/webgpu/types/spritesheet/index.d.ts +1 -0
- package/dist/webgpu/types/spritesheet/spritesheet.d.ts +57 -0
- package/dist/webgpu/types/spritesheet/spritesheet.test.d.ts +1 -0
- package/package.json +96 -26
- package/dist/core/binary-codec/binary-codec.js +0 -354
- package/dist/core/binary-codec/index.js +0 -1
- package/dist/core/driver/driver.js +0 -47
- package/dist/core/driver/drivers/immediate.js +0 -61
- package/dist/core/driver/drivers/index.js +0 -3
- package/dist/core/driver/drivers/raf.js +0 -62
- package/dist/core/driver/drivers/timeout.js +0 -71
- package/dist/core/driver/index.js +0 -2
- package/dist/core/events/event-system.js +0 -88
- package/dist/core/events/index.js +0 -1
- package/dist/core/fixed-ticker/fixed-ticker.js +0 -105
- package/dist/core/fixed-ticker/index.js +0 -1
- package/dist/core/generate-id/generate-id.js +0 -25
- package/dist/core/generate-id/index.js +0 -1
- package/dist/core/index.js +0 -10
- package/dist/core/input/index.js +0 -2
- package/dist/core/input/manager.js +0 -211
- package/dist/core/input/sources/browser.js +0 -29
- package/dist/core/input/sources/index.js +0 -1
- package/dist/core/lerp/index.js +0 -1
- package/dist/core/lerp/lerp.js +0 -42
- package/dist/core/navmesh/index.js +0 -1
- package/dist/core/navmesh/navmesh-worker-pool.js +0 -180
- package/dist/core/navmesh/navmesh.js +0 -799
- package/dist/core/navmesh/navmesh.worker.js +0 -79
- package/dist/core/pooled-codec/index.js +0 -1
- package/dist/core/pooled-codec/pooled-codec.js +0 -410
- package/dist/core/prediction/index.js +0 -1
- package/dist/core/prediction/prediction.js +0 -99
- package/dist/core.esm.js +0 -1
- package/dist/core.js +0 -1
- package/dist/ecs/component-store.js +0 -175
- package/dist/ecs/component.js +0 -43
- package/dist/ecs/entity-handle.js +0 -515
- package/dist/ecs/example.js +0 -125
- package/dist/ecs/index.js +0 -4
- package/dist/ecs/system-builder.js +0 -249
- package/dist/ecs/world-systems.js +0 -79
- package/dist/ecs/world.js +0 -767
- package/dist/game/index.js +0 -1
- package/dist/game/loop/index.js +0 -1
- package/dist/game/loop/loop.js +0 -108
- package/dist/index.js +0 -26
- package/dist/net/adapters/browser-websocket.js +0 -74
- package/dist/net/adapters/bun-websocket.js +0 -245
- package/dist/net/buffer-pool.js +0 -89
- package/dist/net/client.js +0 -586
- package/dist/net/index.js +0 -58
- package/dist/net/server.js +0 -974
- package/dist/net/types.js +0 -31
- package/dist/net/validators.js +0 -88
- package/dist/protocol/index.js +0 -92
- package/dist/protocol/intent/define-intent.js +0 -125
- package/dist/protocol/intent/index.js +0 -91
- package/dist/protocol/intent/intent-registry.js +0 -91
- package/dist/protocol/rpc/define-rpc.js +0 -84
- package/dist/protocol/rpc/index.js +0 -3
- package/dist/protocol/rpc/rpc-registry.js +0 -159
- package/dist/protocol/rpc/rpc.js +0 -12
- package/dist/protocol/snapshot/index.js +0 -43
- package/dist/protocol/snapshot/snapshot-codec.js +0 -67
- package/dist/protocol/snapshot/snapshot-registry.js +0 -168
- package/dist/protocol/snapshot/snapshot.js +0 -30
- package/src/core/binary-codec/README.md +0 -60
- package/src/core/binary-codec/binary-codec.test.ts +0 -300
- package/src/core/binary-codec/binary-codec.ts +0 -448
- package/src/core/binary-codec/index.ts +0 -1
- package/src/core/driver/README.md +0 -97
- package/src/core/driver/driver.test.ts +0 -414
- package/src/core/driver/driver.ts +0 -71
- package/src/core/driver/drivers/immediate.ts +0 -66
- package/src/core/driver/drivers/index.ts +0 -3
- package/src/core/driver/drivers/raf.ts +0 -67
- package/src/core/driver/drivers/timeout.ts +0 -77
- package/src/core/driver/index.ts +0 -2
- package/src/core/events/README.md +0 -47
- package/src/core/events/event-system.test.ts +0 -243
- package/src/core/events/event-system.ts +0 -140
- package/src/core/events/index.ts +0 -1
- package/src/core/fixed-ticker/README.md +0 -77
- package/src/core/fixed-ticker/fixed-ticker.test.ts +0 -151
- package/src/core/fixed-ticker/fixed-ticker.ts +0 -174
- package/src/core/fixed-ticker/index.ts +0 -1
- package/src/core/generate-id/README.md +0 -18
- package/src/core/generate-id/generate-id.test.ts +0 -79
- package/src/core/generate-id/generate-id.ts +0 -37
- package/src/core/generate-id/index.ts +0 -1
- package/src/core/index.ts +0 -10
- package/src/core/input/README.md +0 -24
- package/src/core/input/index.ts +0 -2
- package/src/core/input/manager.ts +0 -259
- package/src/core/input/sources/browser.ts +0 -39
- package/src/core/input/sources/index.ts +0 -1
- package/src/core/input/types.ts +0 -40
- package/src/core/lerp/README.md +0 -79
- package/src/core/lerp/index.ts +0 -1
- package/src/core/lerp/lerp.test.ts +0 -90
- package/src/core/lerp/lerp.ts +0 -42
- package/src/core/navmesh/README.md +0 -164
- package/src/core/navmesh/index.ts +0 -1
- package/src/core/navmesh/navmesh-worker-pool.ts +0 -236
- package/src/core/navmesh/navmesh-workers.test.ts +0 -356
- package/src/core/navmesh/navmesh.test.ts +0 -344
- package/src/core/navmesh/navmesh.ts +0 -1047
- package/src/core/navmesh/navmesh.worker.ts +0 -147
- package/src/core/pooled-codec/README.md +0 -70
- package/src/core/pooled-codec/index.ts +0 -1
- package/src/core/pooled-codec/pooled-codec.test.ts +0 -862
- package/src/core/pooled-codec/pooled-codec.ts +0 -504
- package/src/core/prediction/README.md +0 -64
- package/src/core/prediction/index.ts +0 -1
- package/src/core/prediction/prediction.test.ts +0 -423
- package/src/core/prediction/prediction.ts +0 -112
- package/src/ecs/README.md +0 -427
- package/src/ecs/benchmark.test.ts +0 -1645
- package/src/ecs/component-store.ts +0 -198
- package/src/ecs/component.ts +0 -90
- package/src/ecs/entity-handle.test.ts +0 -393
- package/src/ecs/entity-handle.ts +0 -563
- package/src/ecs/example.ts +0 -152
- package/src/ecs/index.ts +0 -4
- package/src/ecs/system-builder.ts +0 -404
- package/src/ecs/world-systems.ts +0 -83
- package/src/ecs/world.test.ts +0 -310
- package/src/ecs/world.ts +0 -904
- package/src/game/index.ts +0 -1
- package/src/game/loop/README.md +0 -32
- package/src/game/loop/index.ts +0 -1
- package/src/game/loop/loop.ts +0 -236
- package/src/index.ts +0 -32
- package/src/net/README.md +0 -474
- package/src/net/adapters/browser-websocket.ts +0 -86
- package/src/net/adapters/bun-websocket.ts +0 -292
- package/src/net/buffer-pool.ts +0 -106
- package/src/net/client.test.ts +0 -807
- package/src/net/client.ts +0 -695
- package/src/net/index.ts +0 -60
- package/src/net/server.test.ts +0 -799
- package/src/net/server.ts +0 -1152
- package/src/net/types.ts +0 -228
- package/src/net/validators.ts +0 -104
- package/src/protocol/README.md +0 -469
- package/src/protocol/index.ts +0 -93
- package/src/protocol/intent/define-intent.test.ts +0 -397
- package/src/protocol/intent/define-intent.ts +0 -201
- package/src/protocol/intent/index.ts +0 -94
- package/src/protocol/intent/intent-registry.test.ts +0 -198
- package/src/protocol/intent/intent-registry.ts +0 -112
- package/src/protocol/intent/intent.ts +0 -12
- package/src/protocol/rpc/define-rpc.test.ts +0 -141
- package/src/protocol/rpc/define-rpc.ts +0 -113
- package/src/protocol/rpc/index.ts +0 -3
- package/src/protocol/rpc/rpc-registry.test.ts +0 -168
- package/src/protocol/rpc/rpc-registry.ts +0 -176
- package/src/protocol/rpc/rpc.ts +0 -37
- package/src/protocol/snapshot/index.ts +0 -45
- package/src/protocol/snapshot/snapshot-codec.test.ts +0 -138
- package/src/protocol/snapshot/snapshot-codec.ts +0 -87
- package/src/protocol/snapshot/snapshot-registry.test.ts +0 -310
- package/src/protocol/snapshot/snapshot-registry.ts +0 -201
- package/src/protocol/snapshot/snapshot.test.ts +0 -76
- package/src/protocol/snapshot/snapshot.ts +0 -41
- /package/dist/{core → types/core}/binary-codec/index.d.ts +0 -0
- /package/dist/{core → types/core}/driver/driver.d.ts +0 -0
- /package/dist/{core → types/core}/driver/drivers/immediate.d.ts +0 -0
- /package/dist/{core → types/core}/driver/drivers/index.d.ts +0 -0
- /package/dist/{core → types/core}/driver/drivers/raf.d.ts +0 -0
- /package/dist/{core → types/core}/driver/drivers/timeout.d.ts +0 -0
- /package/dist/{core → types/core}/driver/index.d.ts +0 -0
- /package/dist/{core → types/core}/events/index.d.ts +0 -0
- /package/dist/{core → types/core}/fixed-ticker/fixed-ticker.d.ts +0 -0
- /package/dist/{core → types/core}/fixed-ticker/index.d.ts +0 -0
- /package/dist/{core → types/core}/generate-id/generate-id.d.ts +0 -0
- /package/dist/{core → types/core}/generate-id/index.d.ts +0 -0
- /package/dist/{core → types/core}/input/sources/browser.d.ts +0 -0
- /package/dist/{core → types/core}/input/sources/index.d.ts +0 -0
- /package/dist/{core → types/core}/input/types.d.ts +0 -0
- /package/dist/{core → types/core}/lerp/index.d.ts +0 -0
- /package/dist/{core → types/core}/lerp/lerp.d.ts +0 -0
- /package/dist/{core → types/core}/navmesh/index.d.ts +0 -0
- /package/dist/{core → types/core}/navmesh/navmesh-worker-pool.d.ts +0 -0
- /package/dist/{core → types/core}/navmesh/navmesh.worker.d.ts +0 -0
- /package/dist/{core → types/core}/pooled-codec/index.d.ts +0 -0
- /package/dist/{core → types/core}/pooled-codec/pooled-codec.d.ts +0 -0
- /package/dist/{core → types/core}/prediction/index.d.ts +0 -0
- /package/dist/{core → types/core}/prediction/prediction.d.ts +0 -0
- /package/dist/{ecs → types/ecs}/component-store.d.ts +0 -0
- /package/dist/{ecs → types/ecs}/component.d.ts +0 -0
- /package/dist/{ecs → types/ecs}/entity-handle.d.ts +0 -0
- /package/dist/{ecs → types/ecs}/example.d.ts +0 -0
- /package/dist/{ecs → types/ecs}/index.d.ts +0 -0
- /package/dist/{ecs → types/ecs}/system-builder.d.ts +0 -0
- /package/dist/{ecs → types/ecs}/world-systems.d.ts +0 -0
- /package/dist/{game → types/game}/index.d.ts +0 -0
- /package/dist/{game → types/game}/loop/index.d.ts +0 -0
- /package/dist/{net → types/net}/adapters/browser-websocket.d.ts +0 -0
- /package/dist/{net → types/net}/adapters/bun-websocket.d.ts +0 -0
- /package/dist/{net → types/net}/buffer-pool.d.ts +0 -0
- /package/dist/{net → types/net}/client.d.ts +0 -0
- /package/dist/{net → types/net}/server.d.ts +0 -0
- /package/dist/{net → types/net}/types.d.ts +0 -0
- /package/dist/{net → types/net}/validators.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/index.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/intent/define-intent.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/intent/index.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/intent/intent-registry.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/intent/intent.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/rpc/define-rpc.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/rpc/index.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/rpc/rpc-registry.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/rpc/rpc.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/snapshot/index.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/snapshot/snapshot-codec.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/snapshot/snapshot-registry.d.ts +0 -0
- /package/dist/{protocol → types/protocol}/snapshot/snapshot.d.ts +0 -0
- /package/dist/{core/input/types.js → webgpu/types/2d/animation.test.d.ts} +0 -0
- /package/dist/{protocol/intent/intent.js → webgpu/types/2d/sprite-accessor.test.d.ts} +0 -0
package/src/net/server.test.ts
DELETED
|
@@ -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
|
-
});
|