@woosh/meep-engine 3.45.0 → 3.47.0

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 (435) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/editor/actions/concrete/TransformModifyAction.d.ts.map +1 -1
  3. package/editor/actions/concrete/TransformModifyAction.js +10 -2
  4. package/editor/ecs/component/FieldDescriptor.js +15 -0
  5. package/editor/ecs/component/createObjectEditor.js +41 -12
  6. package/editor/ecs/component/editors/ecs/Transform64Editor.d.ts.map +1 -1
  7. package/editor/ecs/component/editors/ecs/Transform64Editor.js +77 -70
  8. package/editor/tools/TransformToolV2.d.ts.map +1 -1
  9. package/editor/tools/TransformToolV2.js +4 -0
  10. package/editor/tools/v2/TransformControls.d.ts.map +1 -1
  11. package/editor/tools/v2/TransformControls.js +7 -0
  12. package/editor/view/ecs/EntityEditor.d.ts.map +1 -1
  13. package/editor/view/ecs/EntityEditor.js +4 -2
  14. package/package.json +1 -1
  15. package/src/core/assert.d.ts.map +1 -1
  16. package/src/core/assert.js +5 -1
  17. package/src/core/binary/hash/XXH128Hash.d.ts +1 -37
  18. package/src/core/binary/hash/XXH128Hash.d.ts.map +1 -1
  19. package/src/core/binary/hash/XXH128Hash.js +4 -55
  20. package/src/core/binary/hash/XXH3_SECRET.d.ts +1 -12
  21. package/src/core/binary/hash/XXH3_SECRET.d.ts.map +1 -1
  22. package/src/core/binary/hash/XXH3_SECRET.js +4 -25
  23. package/src/core/binary/hash/crc32.d.ts +1 -15
  24. package/src/core/binary/hash/crc32.d.ts.map +1 -1
  25. package/src/core/binary/hash/crc32.js +4 -96
  26. package/src/core/binary/hash/xxh3_128.d.ts +1 -9
  27. package/src/core/binary/hash/xxh3_128.d.ts.map +1 -1
  28. package/src/core/binary/hash/xxh3_128.js +4 -341
  29. package/src/core/binary/hash/xxh3_64.d.ts +1 -8
  30. package/src/core/binary/hash/xxh3_64.d.ts.map +1 -1
  31. package/src/core/binary/hash/xxh3_64.js +4 -241
  32. package/src/core/binary/hash/xxh3_common.d.ts +1 -223
  33. package/src/core/binary/hash/xxh3_common.d.ts.map +1 -1
  34. package/src/core/binary/hash/xxh3_common.js +90 -476
  35. package/src/core/collection/array/array_insert_at.d.ts +16 -0
  36. package/src/core/collection/array/array_insert_at.d.ts.map +1 -0
  37. package/src/core/collection/array/array_insert_at.js +32 -0
  38. package/src/core/collection/array/array_remove_at.d.ts +15 -0
  39. package/src/core/collection/array/array_remove_at.d.ts.map +1 -0
  40. package/src/core/collection/array/array_remove_at.js +30 -0
  41. package/src/core/collection/array/combine_hash.d.ts +6 -0
  42. package/src/core/collection/array/combine_hash.d.ts.map +1 -1
  43. package/src/core/collection/array/combine_hash.js +6 -0
  44. package/src/core/function/FunctionCompiler.js +2 -2
  45. package/src/core/geom/3d/mat4/m4_multiply.d.ts +3 -0
  46. package/src/core/geom/3d/mat4/m4_multiply.d.ts.map +1 -1
  47. package/src/core/geom/3d/mat4/m4_multiply.js +3 -0
  48. package/src/core/geom/3d/mat4/m4_multiply_f64.d.ts +30 -0
  49. package/src/core/geom/3d/mat4/m4_multiply_f64.d.ts.map +1 -0
  50. package/src/core/geom/3d/mat4/m4_multiply_f64.js +106 -0
  51. package/src/core/geom/3d/quaternion/quat3_look_rotation.d.ts +37 -0
  52. package/src/core/geom/3d/quaternion/quat3_look_rotation.d.ts.map +1 -0
  53. package/src/core/geom/3d/quaternion/quat3_look_rotation.js +172 -0
  54. package/src/core/geom/ConicRay.js +2 -2
  55. package/src/core/geom/Quaternion.d.ts +1 -0
  56. package/src/core/geom/Quaternion.d.ts.map +1 -1
  57. package/src/core/geom/Quaternion.js +12 -48
  58. package/src/core/geom/Vector4.d.ts.map +1 -1
  59. package/src/core/geom/Vector4.js +8 -5
  60. package/src/core/math/hash/XXH128Hash.d.ts +38 -0
  61. package/src/core/math/hash/XXH128Hash.d.ts.map +1 -0
  62. package/src/core/math/hash/XXH128Hash.js +55 -0
  63. package/src/core/math/hash/XXH3_SECRET.d.ts +13 -0
  64. package/src/core/math/hash/XXH3_SECRET.d.ts.map +1 -0
  65. package/src/core/math/hash/XXH3_SECRET.js +25 -0
  66. package/src/core/math/hash/crc32.d.ts +16 -0
  67. package/src/core/math/hash/crc32.d.ts.map +1 -0
  68. package/src/core/math/hash/crc32.js +96 -0
  69. package/src/core/math/hash/xxh3_128.d.ts +10 -0
  70. package/src/core/math/hash/xxh3_128.d.ts.map +1 -0
  71. package/src/core/math/hash/xxh3_128.js +341 -0
  72. package/src/core/math/hash/xxh3_64.d.ts +9 -0
  73. package/src/core/math/hash/xxh3_64.d.ts.map +1 -0
  74. package/src/core/math/hash/xxh3_64.js +241 -0
  75. package/src/core/math/hash/xxh3_common.d.ts +224 -0
  76. package/src/core/math/hash/xxh3_common.d.ts.map +1 -0
  77. package/src/core/math/hash/xxh3_common.js +476 -0
  78. package/src/core/math/lookup/ParameterLookupTable.js +2 -2
  79. package/src/core/model/node-graph/node/NodeInstancePortReference.js +2 -2
  80. package/src/core/model/reactive/model/ReactiveBinaryExpression.js +2 -2
  81. package/src/core/model/reactive/model/terminal/ReactiveReference.js +2 -2
  82. package/src/engine/Engine.d.ts.map +1 -1
  83. package/src/engine/Engine.js +9 -4
  84. package/src/engine/asset/AssetDescription.js +2 -2
  85. package/src/engine/ecs/animation/Animation.js +2 -2
  86. package/src/engine/ecs/animation/AnimationClip.d.ts.map +1 -1
  87. package/src/engine/ecs/animation/AnimationClip.js +7 -5
  88. package/src/engine/ecs/gui/GUIElement.d.ts.map +1 -1
  89. package/src/engine/ecs/gui/GUIElement.js +7 -5
  90. package/src/engine/ecs/gui/hud/HeadsUpDisplay.js +2 -2
  91. package/src/engine/ecs/gui/position/ViewportPosition.d.ts.map +1 -1
  92. package/src/engine/ecs/gui/position/ViewportPosition.js +11 -7
  93. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  94. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +10 -0
  95. package/src/engine/ecs/transform/Transform64.d.ts +1 -1
  96. package/src/engine/ecs/transform/Transform64.d.ts.map +1 -1
  97. package/src/engine/ecs/transform/Transform64.js +5 -4
  98. package/src/engine/ecs/transform/t64_look_rotation.d.ts +4 -4
  99. package/src/engine/ecs/transform/t64_look_rotation.d.ts.map +1 -1
  100. package/src/engine/ecs/transform/t64_look_rotation.js +7 -18
  101. package/src/engine/graphics/ecs/animation/animator/AnimationClip.d.ts.map +1 -1
  102. package/src/engine/graphics/ecs/animation/animator/AnimationClip.js +8 -5
  103. package/src/engine/graphics/ecs/animation/animator/AnimationClipDefinition.js +2 -2
  104. package/src/engine/graphics/ecs/animation/animator/AnimationNotification.js +2 -2
  105. package/src/engine/graphics/ecs/animation/animator/AnimationNotificationDefinition.js +2 -2
  106. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationGraphDefinition.js +2 -2
  107. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationStateDefinition.js +2 -2
  108. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationTransitionDefinition.d.ts.map +1 -1
  109. package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationTransitionDefinition.js +8 -5
  110. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  111. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +30 -1
  112. package/src/engine/graphics/ecs/decal/v2/Decal.d.ts.map +1 -1
  113. package/src/engine/graphics/ecs/decal/v2/Decal.js +9 -8
  114. package/src/engine/graphics/render/frame_graph/resource/TextureResourceDescriptor.d.ts.map +1 -1
  115. package/src/engine/graphics/render/frame_graph/resource/TextureResourceDescriptor.js +9 -6
  116. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +6 -0
  117. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
  118. package/src/engine/graphics3/GPUParticleEmitterSystem.js +72 -29
  119. package/src/engine/graphics3/ParticipatingMedia.js +204 -204
  120. package/src/engine/graphics3/animation/AnimationClips.d.ts +5 -0
  121. package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -1
  122. package/src/engine/graphics3/animation/AnimationClips.js +5 -0
  123. package/src/engine/grid/obstacle/GridObstacle.js +2 -2
  124. package/src/engine/input/devices/KeyboardDevice.d.ts +1 -0
  125. package/src/engine/input/devices/KeyboardDevice.d.ts.map +1 -1
  126. package/src/engine/input/devices/KeyboardDevice.js +7 -6
  127. package/src/engine/intelligence/behavior/selector/WeightedElement.js +2 -2
  128. package/src/engine/interpolation/Interpolated.js +2 -2
  129. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
  130. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +15 -2
  131. package/src/engine/network/CONGESTION_CONTROL.md +9 -9
  132. package/src/engine/network/MESSAGE_TRANSPORT.md +364 -0
  133. package/src/engine/network/NetworkSession.d.ts +31 -11
  134. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  135. package/src/engine/network/NetworkSession.js +453 -286
  136. package/src/engine/network/README.md +77 -27
  137. package/src/engine/network/SMOOTHNESS_DESIGN.md +13 -5
  138. package/src/engine/network/diagnostics/BandwidthMeter.d.ts +1 -1
  139. package/src/engine/network/diagnostics/BandwidthMeter.js +1 -1
  140. package/src/engine/network/orchestrator/HostJoin.d.ts +111 -0
  141. package/src/engine/network/orchestrator/HostJoin.d.ts.map +1 -0
  142. package/src/engine/network/orchestrator/HostJoin.js +271 -0
  143. package/src/engine/network/orchestrator/NetworkPeer.d.ts +151 -112
  144. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  145. package/src/engine/network/orchestrator/NetworkPeer.js +450 -499
  146. package/src/engine/network/orchestrator/PendingSlices.d.ts +30 -0
  147. package/src/engine/network/orchestrator/PendingSlices.d.ts.map +1 -0
  148. package/src/engine/network/orchestrator/PendingSlices.js +83 -0
  149. package/src/engine/network/orchestrator/ReliableFrames.d.ts +34 -0
  150. package/src/engine/network/orchestrator/ReliableFrames.d.ts.map +1 -0
  151. package/src/engine/network/orchestrator/ReliableFrames.js +96 -0
  152. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +77 -10
  153. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  154. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +236 -61
  155. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +20 -6
  156. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
  157. package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +33 -8
  158. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  159. package/src/engine/network/replication/Replicator.js +7 -1
  160. package/src/engine/network/sim/ActionLog.d.ts +32 -5
  161. package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
  162. package/src/engine/network/sim/ActionLog.js +47 -5
  163. package/src/engine/network/sim/SimActionExecutor.d.ts +42 -2
  164. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  165. package/src/engine/network/sim/SimActionExecutor.js +100 -4
  166. package/src/engine/network/sim/Snapshotter.d.ts +12 -0
  167. package/src/engine/network/sim/Snapshotter.d.ts.map +1 -1
  168. package/src/engine/network/sim/Snapshotter.js +43 -0
  169. package/src/engine/network/state/Baseline.d.ts +1 -1
  170. package/src/engine/network/state/Baseline.js +1 -1
  171. package/src/engine/network/state/FrameBufferRing.d.ts +25 -6
  172. package/src/engine/network/state/FrameBufferRing.d.ts.map +1 -1
  173. package/src/engine/network/state/FrameBufferRing.js +51 -6
  174. package/src/engine/network/state/InputRing.d.ts +4 -0
  175. package/src/engine/network/state/InputRing.d.ts.map +1 -1
  176. package/src/engine/network/state/InputRing.js +7 -0
  177. package/src/engine/network/transport/DeferredTransport.d.ts.map +1 -1
  178. package/src/engine/network/transport/DeferredTransport.js +1 -0
  179. package/src/engine/network/transport/LoopbackTransport.d.ts.map +1 -1
  180. package/src/engine/network/transport/LoopbackTransport.js +4 -2
  181. package/src/engine/network/transport/Transport.d.ts +7 -0
  182. package/src/engine/network/transport/Transport.d.ts.map +1 -1
  183. package/src/engine/network/transport/Transport.js +8 -0
  184. package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
  185. package/src/engine/network/transport/adapters/NodeUDPTransport.js +20 -5
  186. package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.d.ts.map +1 -1
  187. package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.js +8 -0
  188. package/src/engine/network/transport/adapters/WebTransportTransport.d.ts.map +1 -1
  189. package/src/engine/network/transport/adapters/WebTransportTransport.js +6 -0
  190. package/src/engine/network/transport/connection/Connection.d.ts +191 -0
  191. package/src/engine/network/transport/connection/Connection.d.ts.map +1 -0
  192. package/src/engine/network/transport/connection/Connection.js +1262 -0
  193. package/src/engine/network/transport/connection/RangeSet.d.ts +94 -0
  194. package/src/engine/network/transport/connection/RangeSet.d.ts.map +1 -0
  195. package/src/engine/network/transport/connection/RangeSet.js +260 -0
  196. package/src/engine/network/transport/connection/RxStream.d.ts +48 -0
  197. package/src/engine/network/transport/connection/RxStream.d.ts.map +1 -0
  198. package/src/engine/network/transport/connection/RxStream.js +211 -0
  199. package/src/engine/network/transport/connection/TxStream.d.ts +90 -0
  200. package/src/engine/network/transport/connection/TxStream.d.ts.map +1 -0
  201. package/src/engine/network/transport/connection/TxStream.js +243 -0
  202. package/src/engine/network/transport/connection/bytes_copy.d.ts +17 -0
  203. package/src/engine/network/transport/connection/bytes_copy.d.ts.map +1 -0
  204. package/src/engine/network/transport/connection/bytes_copy.js +34 -0
  205. package/src/engine/network/transport/connection/varint.d.ts +46 -0
  206. package/src/engine/network/transport/connection/varint.d.ts.map +1 -0
  207. package/src/engine/network/transport/connection/varint.js +107 -0
  208. package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
  209. package/src/engine/physics/cloth/ecs/Cloth.js +7 -5
  210. package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -1
  211. package/src/engine/physics/cloth/ecs/ClothCollider.js +7 -5
  212. package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts.map +1 -1
  213. package/src/engine/physics/cloth/ecs/ClothDynamics.js +20 -11
  214. package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
  215. package/src/engine/physics/fluid/FluidField.js +7 -5
  216. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
  217. package/src/engine/physics/fluid/ecs/FluidComponent.js +19 -11
  218. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  219. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +2 -2
  220. package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +2 -2
  221. package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts.map +1 -1
  222. package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +11 -7
  223. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts.map +1 -1
  224. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +11 -7
  225. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
  226. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +16 -9
  227. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts +38 -7
  228. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts.map +1 -1
  229. package/src/engine/sound/ecs/audio/AudioEmitter.js +47 -14
  230. package/src/engine/sound/ecs/audio/AudioEmitterSerializationAdapter.d.ts.map +1 -1
  231. package/src/engine/sound/ecs/audio/AudioEmitterSerializationAdapter.js +5 -1
  232. package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.d.ts +18 -0
  233. package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.d.ts.map +1 -0
  234. package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.js +48 -0
  235. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts +12 -2
  236. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts.map +1 -1
  237. package/src/engine/sound/ecs/audio/AudioEmitterSystem.js +173 -9
  238. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts +9 -3
  239. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts.map +1 -1
  240. package/src/engine/sound/ecs/audio/LiveEmitterSet.js +28 -8
  241. package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts +8 -0
  242. package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts.map +1 -1
  243. package/src/engine/sound/ecs/trigger/AudioEventTrigger.js +192 -191
  244. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.d.ts.map +1 -1
  245. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.js +5 -1
  246. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.d.ts +18 -0
  247. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.d.ts.map +1 -0
  248. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.js +51 -0
  249. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.d.ts.map +1 -1
  250. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.js +15 -1
  251. package/src/engine/sound/simulation/core/AcousticMedium.js +2 -2
  252. package/src/engine/sound/simulation/definition/AcousticDirectivity.js +2 -2
  253. package/src/engine/sound/simulation/definition/AcousticMaterial.d.ts.map +1 -1
  254. package/src/engine/sound/simulation/definition/AcousticMaterial.js +11 -7
  255. package/src/engine/sound/sopra/README.md +768 -644
  256. package/src/engine/sound/sopra/SopraEngine.d.ts +104 -8
  257. package/src/engine/sound/sopra/SopraEngine.d.ts.map +1 -1
  258. package/src/engine/sound/sopra/SopraEngine.js +327 -12
  259. package/src/engine/sound/sopra/definition/BusDefinition.d.ts.map +1 -1
  260. package/src/engine/sound/sopra/definition/BusDefinition.js +5 -4
  261. package/src/engine/sound/sopra/definition/DuckingRule.d.ts.map +1 -1
  262. package/src/engine/sound/sopra/definition/DuckingRule.js +7 -5
  263. package/src/engine/sound/sopra/definition/EventDescription.d.ts +28 -2
  264. package/src/engine/sound/sopra/definition/EventDescription.d.ts.map +1 -1
  265. package/src/engine/sound/sopra/definition/EventDescription.js +77 -17
  266. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts +10 -0
  267. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts.map +1 -1
  268. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.js +77 -55
  269. package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.d.ts +31 -0
  270. package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.d.ts.map +1 -0
  271. package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.js +75 -0
  272. package/src/engine/sound/sopra/definition/MixerSnapshot.js +2 -2
  273. package/src/engine/sound/sopra/definition/ParameterDefinition.d.ts.map +1 -1
  274. package/src/engine/sound/sopra/definition/ParameterDefinition.js +7 -5
  275. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +2 -2
  276. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
  277. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.js +4 -3
  278. package/src/engine/sound/sopra/definition/clip/ContainerAudioClip.js +2 -2
  279. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +3 -3
  280. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
  281. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +16 -9
  282. package/src/engine/sound/sopra/definition/clip/SilenceAudioClip.js +2 -2
  283. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -1
  284. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
  285. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.js +2 -2
  286. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts +38 -9
  287. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts.map +1 -1
  288. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.js +34 -5
  289. package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts +7 -2
  290. package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts.map +1 -1
  291. package/src/engine/sound/sopra/definition/effect/CompressorEffect.js +137 -120
  292. package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts +3 -1
  293. package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts.map +1 -1
  294. package/src/engine/sound/sopra/definition/effect/EqEffect.js +146 -128
  295. package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts +1 -0
  296. package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts.map +1 -1
  297. package/src/engine/sound/sopra/definition/effect/ReverbEffect.js +8 -3
  298. package/src/engine/sound/sopra/legacy/SoundEmitter.d.ts.map +1 -1
  299. package/src/engine/sound/sopra/legacy/SoundEmitter.js +357 -352
  300. package/src/engine/sound/sopra/legacy/SoundTrack.d.ts.map +1 -1
  301. package/src/engine/sound/sopra/legacy/SoundTrack.js +281 -278
  302. package/src/engine/sound/sopra/runtime/BusGraph.d.ts +44 -2
  303. package/src/engine/sound/sopra/runtime/BusGraph.d.ts.map +1 -1
  304. package/src/engine/sound/sopra/runtime/BusGraph.js +83 -43
  305. package/src/engine/sound/sopra/runtime/EffectChain.d.ts +96 -0
  306. package/src/engine/sound/sopra/runtime/EffectChain.d.ts.map +1 -0
  307. package/src/engine/sound/sopra/runtime/EffectChain.js +286 -0
  308. package/src/engine/sound/sopra/runtime/EffectParamOverrides.d.ts +123 -0
  309. package/src/engine/sound/sopra/runtime/EffectParamOverrides.d.ts.map +1 -0
  310. package/src/engine/sound/sopra/runtime/EffectParamOverrides.js +320 -0
  311. package/src/engine/sound/sopra/runtime/EventInstance.d.ts +55 -5
  312. package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
  313. package/src/engine/sound/sopra/runtime/EventInstance.js +201 -26
  314. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts +2 -1
  315. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts.map +1 -1
  316. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.js +6 -1
  317. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts +15 -0
  318. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts.map +1 -1
  319. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.js +32 -0
  320. package/src/engine/sound/sopra/util/MockAudioContext.d.ts.map +1 -1
  321. package/src/engine/sound/sopra/util/MockAudioContext.js +3 -0
  322. package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts +13 -3
  323. package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts.map +1 -1
  324. package/src/engine/sound/sopra/util/fadeOutAndStop.js +25 -13
  325. package/src/format/image/png/PNGReader.js +644 -644
  326. package/src/format/image/png/crc32.d.ts +1 -1
  327. package/src/format/image/png/crc32.js +7 -8
  328. package/src/shade/RENDERER_CONTRACT.md +6 -3
  329. package/src/shade/descriptor/binding/BindGroupLayoutDescriptor.js +2 -2
  330. package/src/shade/descriptor/binding/BindGroupLayoutEntry.d.ts.map +1 -1
  331. package/src/shade/descriptor/binding/BindGroupLayoutEntry.js +12 -8
  332. package/src/shade/descriptor/binding/StorageTextureBindingLayout.js +2 -2
  333. package/src/shade/descriptor/binding/TextureBindingLayout.js +2 -2
  334. package/src/shade/descriptor/blend/BlendComponent.js +2 -2
  335. package/src/shade/descriptor/pipeline/PipelineDescriptorBase.js +2 -2
  336. package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.js +2 -2
  337. package/src/shade/descriptor/pipeline/ProgrammableStage.js +2 -2
  338. package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.js +2 -2
  339. package/src/shade/descriptor/pipeline/render/ColorTargetState.js +2 -2
  340. package/src/shade/descriptor/pipeline/render/FragmentState.js +2 -2
  341. package/src/shade/descriptor/pipeline/render/PrimitiveState.js +2 -2
  342. package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.d.ts.map +1 -1
  343. package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.js +8 -5
  344. package/src/shade/descriptor/pipeline/render/VertexAttribute.js +2 -2
  345. package/src/shade/descriptor/texture/SamplerDescriptor.d.ts.map +1 -1
  346. package/src/shade/descriptor/texture/SamplerDescriptor.js +20 -12
  347. package/src/shade/descriptor/texture/TextureDescriptor.d.ts.map +1 -1
  348. package/src/shade/descriptor/texture/TextureDescriptor.js +11 -7
  349. package/src/shade/device/SHADE_DEVICE_FLOOR.d.ts +24 -0
  350. package/src/shade/device/SHADE_DEVICE_FLOOR.d.ts.map +1 -0
  351. package/src/shade/device/SHADE_DEVICE_FLOOR.js +34 -0
  352. package/src/shade/device/ShadeDeviceFailure.d.ts +12 -5
  353. package/src/shade/device/ShadeDeviceFailure.d.ts.map +1 -1
  354. package/src/shade/device/ShadeDeviceFailure.js +17 -8
  355. package/src/shade/device/ShadeDeviceFailureReason.d.ts +1 -1
  356. package/src/shade/device/ShadeDeviceFailureReason.js +2 -2
  357. package/src/shade/device/graph/BufferResourceDescriptor.d.ts.map +1 -1
  358. package/src/shade/device/graph/BufferResourceDescriptor.js +196 -193
  359. package/src/shade/device/graph/TextureResourceDescriptor.d.ts.map +1 -1
  360. package/src/shade/device/graph/TextureResourceDescriptor.js +178 -173
  361. package/src/shade/device/shade_device_floor_unmet.d.ts +13 -0
  362. package/src/shade/device/shade_device_floor_unmet.d.ts.map +1 -0
  363. package/src/shade/device/shade_device_floor_unmet.js +32 -0
  364. package/src/shade/device/timing/profile/sgpt_read_header.js +1 -1
  365. package/src/shade/device/timing/profile/sgpt_read_records.js +1 -1
  366. package/src/shade/device/timing/profile/sgpt_write_header.js +1 -1
  367. package/src/shade/device/timing/profile/sgpt_write_record.js +1 -1
  368. package/src/shade/renderer/Renderer.d.ts +2 -0
  369. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  370. package/src/shade/renderer/Renderer.js +29 -55
  371. package/src/shade/renderer/binding/BufferBinding.js +2 -2
  372. package/src/shade/renderer/buffer/GPUBufferAllocator.d.ts.map +1 -1
  373. package/src/shade/renderer/buffer/GPUBufferAllocator.js +9 -0
  374. package/src/shade/renderer/buffer/buffer_pool_ops.d.ts +21 -12
  375. package/src/shade/renderer/buffer/buffer_pool_ops.d.ts.map +1 -1
  376. package/src/shade/renderer/buffer/buffer_pool_ops.js +18 -19
  377. package/src/shade/renderer/camera/Camera.js +2 -2
  378. package/src/shade/renderer/geometry/Attribute.js +2 -2
  379. package/src/shade/renderer/geometry/Geometry.js +2 -2
  380. package/src/shade/renderer/geometry/geometry_deduplicate_vertices.js +2 -2
  381. package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +2 -2
  382. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_asset_id.js +13 -13
  383. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_directory_block_checksum.js +41 -41
  384. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_frame_checksum.js +41 -41
  385. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_header_checksum.js +25 -25
  386. package/src/shade/renderer/gpu_primitive/test/gpu_test.d.ts.map +1 -1
  387. package/src/shade/renderer/gpu_primitive/test/gpu_test.js +8 -11
  388. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  389. package/src/shade/renderer/material/StandardShadeMaterial.d.ts.map +1 -1
  390. package/src/shade/renderer/material/StandardShadeMaterial.js +13 -8
  391. package/src/shade/renderer/pool/TransientResourcePool.d.ts +24 -0
  392. package/src/shade/renderer/pool/TransientResourcePool.d.ts.map +1 -1
  393. package/src/shade/renderer/pool/TransientResourcePool.js +41 -10
  394. package/src/shade/renderer/scene/optimization/geometry/internal/triangle_fingerprint_stream.d.ts.map +1 -1
  395. package/src/shade/renderer/scene/optimization/geometry/internal/triangle_fingerprint_stream.js +14 -5
  396. package/src/shade/renderer/scene/optimization/sampler2d_from_image_bitmap.js +1 -1
  397. package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
  398. package/src/shade/renderer/shader/ComputeShader.js +18 -2
  399. package/src/shade/renderer/shader/ImageShader.d.ts.map +1 -1
  400. package/src/shade/renderer/shader/ImageShader.js +230 -218
  401. package/src/shade/renderer/shader/type/WGSLStructField.js +2 -2
  402. package/src/shade/renderer/shader/type/WebGPUArray.js +2 -2
  403. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  404. package/src/shade/renderer/shader/type/WebGPUStruct.js +9 -6
  405. package/src/shade/renderer/texture/ShadeTexture.d.ts.map +1 -1
  406. package/src/shade/renderer/texture/ShadeTexture.js +17 -10
  407. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +2 -2
  408. package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +4 -4
  409. package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +6 -6
  410. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
  411. package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +46 -55
  412. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts +3 -3
  413. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -1
  414. package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +14 -4
  415. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +10 -1
  416. package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -1
  417. package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +82 -40
  418. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +4 -1
  419. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -1
  420. package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +8 -4
  421. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +98 -86
  422. package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -1
  423. package/src/shade/renderer/water/surface/particles/shader_water_particles.js +440 -298
  424. package/src/view/common/HTMLElementCacheKey.d.ts.map +1 -1
  425. package/src/view/common/HTMLElementCacheKey.js +4 -3
  426. package/src/view/graphics/GraphicsContextFailureView.d.ts +1 -2
  427. package/src/view/graphics/GraphicsContextFailureView.d.ts.map +1 -1
  428. package/src/view/graphics/GraphicsContextFailureView.js +1 -2
  429. package/src/view/minimap/MinimapMarker.js +2 -2
  430. package/src/engine/network/transport/Channel.js +0 -336
  431. package/src/engine/network/transport/ReliableCommandPipeline.js +0 -335
  432. package/src/engine/network/transport/fragments/FragmentAssembler.js +0 -350
  433. package/src/engine/network/transport/fragments/FragmentRetention.js +0 -191
  434. package/src/engine/network/transport/fragments/fragment_send.js +0 -157
  435. package/src/engine/network/transport/fragments/packet_size.js +0 -107
@@ -1,335 +0,0 @@
1
- import { assert } from "../../../core/assert.js";
2
- import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
3
- import Signal from "../../../core/events/signal/Signal.js";
4
- import { MalformedPacketError } from "../core/MalformedPacketError.js";
5
- import { MAX_CHANNEL_PAYLOAD_BYTES } from "./fragments/packet_size.js";
6
-
7
- /**
8
- * Largest reliable-command payload that fits in a single channel packet.
9
- *
10
- * A command's wire form is `uint8 packet_type + uintVar logical_seq + payload`.
11
- * The pipeline sends it through {@link Channel#send} directly — it does NOT
12
- * fragment — so the whole thing must fit one channel packet
13
- * ({@link MAX_CHANNEL_PAYLOAD_BYTES}). We reserve 11 bytes for the framing:
14
- * 1 packet-type byte + up to 10 bytes of `uintVar` for `logical_seq` (its
15
- * worst case; `logical_seq` grows over the session, so we budget the maximum
16
- * rather than the current value). Sending a larger payload on a UDP-style
17
- * transport would emit an over-MTU datagram that the network silently drops;
18
- * we reject it loudly instead.
19
- *
20
- * @type {number}
21
- */
22
- export const MAX_RELIABLE_COMMAND_PAYLOAD_BYTES = MAX_CHANNEL_PAYLOAD_BYTES - 11;
23
-
24
- /**
25
- * Reliable, at-least-once delivery layer over a {@link Channel}.
26
- *
27
- * Used for messages that must arrive: chat, lobby/room state changes,
28
- * level transitions, kick / disconnect notifications. Distinct from the
29
- * action-stream traffic the rest of the netcode uses, which is UDP-style
30
- * best-effort with per-frame back-fill compensating for losses.
31
- *
32
- * Wire layout (after the {@link Channel}'s 8-byte header and the
33
- * `packet_type` byte that {@link NetworkPeer}'s dispatcher consumes):
34
- *
35
- * uintVar logical_seq sender-assigned, monotonically increasing
36
- * bytes command_payload
37
- *
38
- * Reliability mechanism: each outgoing command goes out as one
39
- * Channel.send call. The returned channel-level seq is tracked in
40
- * `__unacked`. When the Channel later fires:
41
- * - `onPacketAcked(seq)`: drop the entry — the command was delivered
42
- * (the receiver de-duplicated by logical_seq, so a "duplicate" from
43
- * a previous retransmit is harmless).
44
- * - `onPacketLost(seq)`: the Channel's 33-packet ack window aged out
45
- * this seq without seeing it acked. Re-send the same logical
46
- * command on a fresh channel seq.
47
- *
48
- * Receiver side: a sliding-window de-dupe of recent `logical_seq` values.
49
- * Anything seen within the last `max_received_history` is silently
50
- * dropped; first-time arrivals fire `onCommand` with the payload bytes.
51
- *
52
- * Ordering: NOT guaranteed. Commands may arrive in any order. If you
53
- * need in-order delivery (level transitions before subsequent chat),
54
- * key payloads with a counter and reorder in the application handler.
55
- *
56
- * Lifecycle constraints:
57
- * - `max_unacked` caps outstanding commands. Send throws when full
58
- * (signals real backpressure — receiver gone or path is broken).
59
- * - `max_received_history` caps the de-dupe set. A retransmit older
60
- * than this window will be re-delivered as a duplicate to the
61
- * application; not a problem in practice because the sender's
62
- * `max_unacked` keeps the inflight set bounded too.
63
- *
64
- * Caveats:
65
- * - Loss detection relies on the Channel's seq window, which advances
66
- * when subsequent packets are sent. Under sustained no-traffic
67
- * conditions a single lost reliable command may stay unacked
68
- * indefinitely — by convention the action-stream's per-tick traffic
69
- * keeps the window moving even when the application is otherwise
70
- * idle. Real production code may want a timer-based retransmit
71
- * fallback layered on top of this.
72
- *
73
- * @author Alex Goldring
74
- * @copyright Company Named Limited (c) 2026
75
- */
76
- export class ReliableCommandPipeline {
77
- /**
78
- * Monotonic counter for outgoing logical seqs. Receiver dedups on
79
- * this value; sender retransmits use the SAME logical_seq with a
80
- * new channel_seq.
81
- * @type {number}
82
- * @private
83
- */
84
- #next_send_seq = 0;
85
- #unacked;
86
- #received_seqs;
87
- /**
88
- * FIFO order of received logical_seqs, for pruning when
89
- * `__received_seqs` exceeds `max_received_history`.
90
- * @type {number[]}
91
- * @private
92
- */
93
- #received_order = [];
94
- #send_scratch;
95
- #bound_acked;
96
- #bound_lost;
97
-
98
- /**
99
- * @param {{
100
- * channel: import("./Channel.js").Channel,
101
- * packet_type: number,
102
- * max_unacked?: number,
103
- * max_received_history?: number,
104
- * max_retries?: number,
105
- * }} options
106
- */
107
- constructor({
108
- channel,
109
- packet_type,
110
- max_unacked = 64,
111
- max_received_history = 64,
112
- max_retries = 16,
113
- }) {
114
- assert.ok(channel && typeof channel.send === 'function', 'channel must be a Channel');
115
- assert.isNonNegativeInteger(packet_type, 'packet_type');
116
- assert.ok(packet_type <= 0xFF, 'packet_type must fit in a uint8');
117
- assert.isPositiveInteger(max_unacked, 'max_unacked');
118
- assert.isPositiveInteger(max_received_history, 'max_received_history');
119
- assert.isPositiveInteger(max_retries, 'max_retries');
120
-
121
- /** @type {import("./Channel.js").Channel} */
122
- this.channel = channel;
123
- /** @type {number} @readonly */
124
- this.packet_type = packet_type;
125
- /** @type {number} @readonly */
126
- this.max_unacked = max_unacked;
127
- /** @type {number} @readonly */
128
- this.max_received_history = max_received_history;
129
- /**
130
- * Maximum retransmissions per logical command before it is dropped
131
- * and {@link onCommandAbandoned} fires. Bounded so a permanently-
132
- * black-holed peer can't pin retransmit traffic on the channel
133
- * forever. The default (16) tolerates roughly half a second of
134
- * sustained loss at typical channel cadences before giving up.
135
- * @type {number} @readonly
136
- */
137
- this.max_retries = max_retries;
138
-
139
- /**
140
- * Outstanding commands keyed by their CURRENT channel_seq. On
141
- * retransmit, the entry is moved to the new channel_seq.
142
- * `retries` counts how many times this logical command has been
143
- * resent; the entry is dropped when it exceeds `max_retries`.
144
- * @type {Map<number, {logical_seq: number, payload: Uint8Array, retries: number}>}
145
- * @private
146
- */
147
- this.#unacked = new Map();
148
-
149
- /**
150
- * Logical seqs received recently. Sliding window for dedup.
151
- * @type {Set<number>}
152
- * @private
153
- */
154
- this.#received_seqs = new Set();
155
-
156
- /**
157
- * Scratch buffer for assembling outgoing packets.
158
- * @type {BinaryBuffer}
159
- * @private
160
- */
161
- this.#send_scratch = new BinaryBuffer();
162
- this.#send_scratch.setCapacity(1024);
163
-
164
- /**
165
- * Fired when a brand-new logical command arrives (not a duplicate).
166
- * Args: `(buf, payload_offset, payload_length)`. The buffer is
167
- * shared scratch; consumers must copy bytes if they need them to
168
- * outlive the handler.
169
- * @type {Signal}
170
- */
171
- this.onCommand = new Signal();
172
-
173
- /**
174
- * Fired when a sent command has been retransmitted `max_retries`
175
- * times without an ack and is being given up on. Args:
176
- * `(logical_seq)`. Subscribers typically surface this as a "command
177
- * failed to deliver" event to the application, or treat it as a
178
- * hard signal to tear down the session.
179
- * @type {Signal}
180
- */
181
- this.onCommandAbandoned = new Signal();
182
-
183
- // Channel reliability notifications.
184
- this.#bound_acked = (seq) => this.#on_packet_acked(seq);
185
- this.#bound_lost = (seq) => this.#on_packet_lost(seq);
186
- channel.onPacketAcked.add(this.#bound_acked);
187
- channel.onPacketLost.add(this.#bound_lost);
188
- }
189
-
190
- /**
191
- * Send a logical command. Returns the assigned `logical_seq` (useful
192
- * for application-level diagnostics; the receiver dedups internally
193
- * regardless).
194
- *
195
- * @param {Uint8Array} payload
196
- * @param {number} length
197
- * @returns {number}
198
- */
199
- send(payload, length) {
200
- assert.isNonNegativeInteger(length, 'length');
201
- if (length > MAX_RELIABLE_COMMAND_PAYLOAD_BYTES) {
202
- // The pipeline does not fragment; an over-MTU command would be sent
203
- // as one oversized datagram that UDP-style transports silently drop.
204
- // Fail loudly so the caller chunks at the application layer (or uses
205
- // a stream transport) rather than losing the message on the wire.
206
- throw new Error(
207
- `ReliableCommandPipeline.send: payload of ${length} bytes exceeds the ` +
208
- `${MAX_RELIABLE_COMMAND_PAYLOAD_BYTES}-byte single-packet limit; this layer does not ` +
209
- `fragment — chunk the message at the application layer or send it over a stream transport`
210
- );
211
- }
212
- if (this.#unacked.size >= this.max_unacked) {
213
- throw new Error(
214
- `ReliableCommandPipeline.send: ${this.#unacked.size} commands unacked ` +
215
- `(max ${this.max_unacked}); receiver likely disconnected or path saturated`
216
- );
217
- }
218
- const logical_seq = this.#next_send_seq;
219
- this.#next_send_seq++;
220
-
221
- // Defensive copy: the caller's buffer may be reused after this call.
222
- const payload_copy = new Uint8Array(length);
223
- payload_copy.set(payload.subarray(0, length));
224
-
225
- const channel_seq = this.#transmit(logical_seq, payload_copy);
226
- this.#unacked.set(channel_seq, { logical_seq, payload: payload_copy, retries: 0 });
227
- return logical_seq;
228
- }
229
-
230
- /**
231
- * Called by the orchestrator (typically {@link NetworkPeer}'s
232
- * dispatcher) when a packet of this pipeline's type arrives. `buf`
233
- * is positioned just past the packet-type byte.
234
- *
235
- * @param {BinaryBuffer} buf
236
- * @param {number} total_length full transport-level payload length,
237
- * including the consumed packet-type byte
238
- */
239
- handle_inbound(buf, total_length) {
240
- // Bounds-checked before the read, like every other parse path in the dispatcher.
241
- //
242
- // `#recv_buffer` is a reused scratch: `writeBytes(bytes, 0, length)` overwrites only the
243
- // first `length` bytes, so everything past them is the previous, longer packet's content.
244
- // A truncated RELIABLE_COMMAND - just the type byte, from a peer or a truncating middlebox
245
- // - let `readUintVar` walk into those leftovers and produce a bogus `logical_seq`, which
246
- // was then recorded in the received set, so a genuine later command carrying that seq was
247
- // silently dropped as a duplicate.
248
- if (buf.position >= total_length) {
249
- throw new MalformedPacketError(`ReliableCommandPipeline: RELIABLE_COMMAND truncated before its sequence number`);
250
- }
251
-
252
- const logical_seq = buf.readUintVar();
253
-
254
- // ...and after it: `readUintVar` may have consumed bytes past the packet even when one was
255
- // available to start with. Subtracting gave a negative payload length and an offset into an
256
- // unrelated packet's bytes, handed straight to the application.
257
- if (buf.position > total_length) {
258
- throw new MalformedPacketError(`ReliableCommandPipeline: RELIABLE_COMMAND sequence number runs past the packet`);
259
- }
260
-
261
- if (this.#received_seqs.has(logical_seq)) {
262
- // Duplicate from a retransmit; ignore.
263
- return;
264
- }
265
- this.#received_seqs.add(logical_seq);
266
- this.#received_order.push(logical_seq);
267
- // Prune. Oldest-first.
268
- while (this.#received_order.length > this.max_received_history) {
269
- const oldest = this.#received_order.shift();
270
- this.#received_seqs.delete(oldest);
271
- }
272
-
273
- const payload_offset = buf.position;
274
- const payload_length = total_length - payload_offset;
275
- this.onCommand.send3(buf, payload_offset, payload_length);
276
- }
277
-
278
- /**
279
- * Number of commands sent that haven't yet been acked. Useful for
280
- * backpressure / progress UI.
281
- * @returns {number}
282
- */
283
- unacked_count() {
284
- return this.#unacked.size;
285
- }
286
-
287
- /**
288
- * Drop subscriptions and clear state. Required before discarding a
289
- * pipeline whose channel will outlive it.
290
- */
291
- dispose() {
292
- this.channel.onPacketAcked.remove(this.#bound_acked);
293
- this.channel.onPacketLost.remove(this.#bound_lost);
294
- this.#unacked.clear();
295
- this.#received_seqs.clear();
296
- this.#received_order.length = 0;
297
- }
298
-
299
- /** @private */
300
- #transmit(logical_seq, payload) {
301
- const buf = this.#send_scratch;
302
- // Worst-case capacity: type byte + 10 bytes for varint + payload.
303
- const needed = 1 + 10 + payload.length;
304
- if (buf.raw_bytes.length < needed) buf.setCapacity(needed);
305
- buf.position = 0;
306
- buf.writeUint8(this.packet_type);
307
- buf.writeUintVar(logical_seq);
308
- buf.writeBytes(payload, 0, payload.length);
309
- return this.channel.send(buf.raw_bytes, buf.position);
310
- }
311
-
312
- /** @private */
313
- #on_packet_acked(channel_seq) {
314
- this.#unacked.delete(channel_seq);
315
- }
316
-
317
- /** @private */
318
- #on_packet_lost(channel_seq) {
319
- const entry = this.#unacked.get(channel_seq);
320
- if (entry === undefined) return;
321
- this.#unacked.delete(channel_seq);
322
-
323
- if (entry.retries >= this.max_retries) {
324
- // Permanently black-holed peer or fundamentally broken path —
325
- // surface the failure to the application and stop retrying.
326
- this.onCommandAbandoned.send1(entry.logical_seq);
327
- return;
328
- }
329
-
330
- // Retransmit on a fresh channel_seq. Same logical_seq, same payload.
331
- entry.retries++;
332
- const new_channel_seq = this.#transmit(entry.logical_seq, entry.payload);
333
- this.#unacked.set(new_channel_seq, entry);
334
- }
335
- }
@@ -1,350 +0,0 @@
1
- import { assert } from "../../../../core/assert.js";
2
- import {
3
- FRAGMENT_NACK_INITIAL_DELAY_MS,
4
- FRAGMENT_NACK_MAX_ROUNDS,
5
- FRAGMENT_NACK_RESEND_INTERVAL_MS,
6
- MAX_CHUNKS_PER_MESSAGE,
7
- } from "./packet_size.js";
8
-
9
- /**
10
- * Per-peer reassembly buffer for fragmented packets.
11
- *
12
- * When a sender's logical payload exceeds the MTU it gets split into
13
- * multiple {@link NetworkPacketType.FRAGMENT} packets, each carrying a
14
- * `(message_id, chunk_index, total_chunks, chunk_bytes)` tuple. The
15
- * receiver feeds those tuples to {@link receive}; once all chunks for a
16
- * `message_id` have arrived, `receive` returns the reassembled bytes
17
- * for the upper layer to dispatch.
18
- *
19
- * Loss recovery via NACK: a partially-received message that doesn't
20
- * complete within `nack_initial_delay_ms` triggers a NACK back to the
21
- * sender listing the missing chunk indices. NACK rounds repeat at
22
- * `nack_resend_interval_ms` up to `nack_max_rounds`; after that the
23
- * receiver gives up on the message and the sender's retention ages
24
- * out independently. Wire the per-tick driver via {@link service}.
25
- *
26
- * Loss-of-last-resort model: if even the NACK retries fail (link is
27
- * dead, sender retention was evicted, etc.) the message never
28
- * completes and FIFO-evicts when the pending cap is hit. Upper layers
29
- * are still expected to tolerate occasional missing messages — NACK
30
- * recovers most loss, not all.
31
- *
32
- * @author Alex Goldring
33
- * @copyright Company Named Limited (c) 2026
34
- */
35
- export class FragmentAssembler {
36
- #pending;
37
- /**
38
- * FIFO of message_ids in insertion order, for eviction when the
39
- * pending map exceeds `max_pending_messages`.
40
- * @type {number[]}
41
- * @private
42
- */
43
- #order = [];
44
-
45
- /**
46
- * Message ids delivered recently, so a late or retransmitted chunk for one is dropped rather
47
- * than opening a fresh reassembly slot. See the note in {@link receive}.
48
- *
49
- * Bounded by {@link #completed_order}, which spans the same window `#order` does.
50
- *
51
- * @type {Set<number>}
52
- */
53
- #completed = new Set();
54
-
55
- /**
56
- * Insertion order of {@link #completed}, for FIFO eviction.
57
- * @type {number[]}
58
- */
59
- #completed_order = [];
60
- #nack_scratch;
61
- /**
62
- * Scratch for message_ids to drop after a {@link service} pass.
63
- * Collected during iteration so the underlying map isn't mutated
64
- * mid-iteration.
65
- * @type {number[]}
66
- * @private
67
- */
68
- #drop_scratch = [];
69
-
70
- /**
71
- * @param {{
72
- * max_pending_messages?: number,
73
- * max_message_size?: number,
74
- * nack_initial_delay_ms?: number,
75
- * nack_resend_interval_ms?: number,
76
- * nack_max_rounds?: number,
77
- * }} [options]
78
- * `max_pending_messages` caps the number of in-flight reassembly
79
- * slots; when full, the oldest pending message is evicted to make
80
- * room. `max_message_size` rejects reassembled messages larger than
81
- * this many bytes (defensive against a malicious peer or a wedged
82
- * sender). The `nack_*` knobs control the retransmit-request timer
83
- * driven by {@link service}.
84
- */
85
- constructor({
86
- max_pending_messages = 8,
87
- max_message_size = 65536,
88
- nack_initial_delay_ms = FRAGMENT_NACK_INITIAL_DELAY_MS,
89
- nack_resend_interval_ms = FRAGMENT_NACK_RESEND_INTERVAL_MS,
90
- nack_max_rounds = FRAGMENT_NACK_MAX_ROUNDS,
91
- } = {}) {
92
- assert.isPositiveInteger(max_pending_messages, 'max_pending_messages');
93
- assert.isPositiveInteger(max_message_size, 'max_message_size');
94
- assert.isPositiveInteger(nack_initial_delay_ms, 'nack_initial_delay_ms');
95
- assert.isPositiveInteger(nack_resend_interval_ms, 'nack_resend_interval_ms');
96
- assert.isPositiveInteger(nack_max_rounds, 'nack_max_rounds');
97
-
98
- /** @type {number} @readonly */
99
- this.max_pending_messages = max_pending_messages;
100
- /** @type {number} @readonly */
101
- this.max_message_size = max_message_size;
102
- /** @type {number} @readonly */
103
- this.nack_initial_delay_ms = nack_initial_delay_ms;
104
- /** @type {number} @readonly */
105
- this.nack_resend_interval_ms = nack_resend_interval_ms;
106
- /** @type {number} @readonly */
107
- this.nack_max_rounds = nack_max_rounds;
108
-
109
- /**
110
- * Pending reassembly state per `message_id`. Each entry:
111
- * total_chunks: uint8 — number of chunks expected
112
- * chunks: (Uint8Array | undefined)[] — chunk_index → bytes
113
- * received_count: number of distinct chunks present
114
- * total_bytes: sum of chunk lengths received so far
115
- * first_seen_at: ms timestamp of the first {@link service} tick
116
- * that observed this entry; -1 until stamped
117
- * last_nack_at: ms timestamp of the most recent NACK emitted
118
- * for this entry; -1 if never
119
- * nack_rounds: number of NACKs emitted for this entry
120
- * @type {Map<number, {total_chunks: number, chunks: Uint8Array[], received_count: number, total_bytes: number, first_seen_at: number, last_nack_at: number, nack_rounds: number}>}
121
- * @private
122
- */
123
- this.#pending = new Map();
124
-
125
- /**
126
- * Reusable scratch for the missing-index list passed to the NACK
127
- * callback. Sized to the wire maximum so the callback can always
128
- * iterate `count` entries safely.
129
- * @type {Uint8Array}
130
- * @private
131
- */
132
- this.#nack_scratch = new Uint8Array(MAX_CHUNKS_PER_MESSAGE);
133
- }
134
-
135
- /**
136
- * Process an incoming fragment. Returns the reassembled bytes when
137
- * the message is complete, or null otherwise.
138
- *
139
- * @param {number} message_id sender-assigned message id
140
- * @param {number} chunk_index 0-based
141
- * @param {number} total_chunks expected number of chunks (>= 1)
142
- * @param {Uint8Array} chunk_bytes source byte array
143
- * @param {number} chunk_offset start offset within `chunk_bytes`
144
- * @param {number} chunk_length number of bytes from `chunk_offset` to consume
145
- * @returns {Uint8Array|null}
146
- */
147
- receive(message_id, chunk_index, total_chunks, chunk_bytes, chunk_offset, chunk_length) {
148
- assert.isNonNegativeInteger(message_id, 'message_id');
149
- assert.isNonNegativeInteger(chunk_index, 'chunk_index');
150
- assert.isPositiveInteger(total_chunks, 'total_chunks');
151
- assert.isNonNegativeInteger(chunk_offset, 'chunk_offset');
152
- assert.isNonNegativeInteger(chunk_length, 'chunk_length');
153
-
154
- if (chunk_index >= total_chunks) {
155
- // Malformed; discard silently.
156
- return null;
157
- }
158
-
159
- if (this.#completed.has(message_id)) {
160
- // Already delivered. Without this the chunk misses the duplicate guard below - which
161
- // lives INSIDE an entry, and completion erases the entry - and opens a fresh, and
162
- // therefore incomplete, reassembly slot. `service()` then NACKs the sender for chunks
163
- // of a message it has already delivered, the sender's retention honours the NACK, and
164
- // the message completes and is dispatched a second time: STATE_BURST straight to the
165
- // application handler, INITIAL_SYNC re-applying a whole snapshot. It is the ordinary
166
- // NACK/late-chunk race, not an adversarial input - `packet_size.js` sizes the delay
167
- // expecting the receiver to "occasionally NACK chunks still in transit".
168
- return null;
169
- }
170
-
171
- let entry = this.#pending.get(message_id);
172
- if (entry === undefined) {
173
- if (this.#pending.size >= this.max_pending_messages) {
174
- // Evict the oldest pending message (FIFO).
175
- const oldest = this.#order.shift();
176
- if (oldest !== undefined) this.#pending.delete(oldest);
177
- }
178
- entry = {
179
- total_chunks,
180
- chunks: new Array(total_chunks),
181
- received_count: 0,
182
- total_bytes: 0,
183
- first_seen_at: -1,
184
- last_nack_at: -1,
185
- nack_rounds: 0,
186
- };
187
- this.#pending.set(message_id, entry);
188
- this.#order.push(message_id);
189
- }
190
-
191
- if (entry.total_chunks !== total_chunks) {
192
- // Conflicting metadata across fragments for the same message_id.
193
- // Drop the whole assembly — something is very wrong upstream.
194
- this.#delete(message_id);
195
- return null;
196
- }
197
-
198
- if (entry.chunks[chunk_index] !== undefined) {
199
- // Duplicate fragment; ignore (network may have retransmitted).
200
- return null;
201
- }
202
-
203
- // Defensive: refuse to allocate more memory than max_message_size for
204
- // this assembly. Check incrementally so a malicious sender can't
205
- // claim 255 chunks of 65 KB each.
206
- if (entry.total_bytes + chunk_length > this.max_message_size) {
207
- this.#delete(message_id);
208
- return null;
209
- }
210
-
211
- const copy = new Uint8Array(chunk_length);
212
- copy.set(chunk_bytes.subarray(chunk_offset, chunk_offset + chunk_length));
213
- entry.chunks[chunk_index] = copy;
214
- entry.received_count++;
215
- entry.total_bytes += chunk_length;
216
-
217
- if (entry.received_count < entry.total_chunks) return null;
218
-
219
- // Complete — assemble.
220
- const reassembled = new Uint8Array(entry.total_bytes);
221
- let offset = 0;
222
- for (let i = 0; i < entry.total_chunks; i++) {
223
- const c = entry.chunks[i];
224
- reassembled.set(c, offset);
225
- offset += c.length;
226
- }
227
- this.#delete(message_id);
228
-
229
- this.#remember_completed(message_id);
230
-
231
- return reassembled;
232
- }
233
-
234
- /**
235
- * Record a delivered message id, evicting the oldest when the window is full.
236
- *
237
- * The window is the same size as the pending one: a chunk arriving later than that many
238
- * distinct messages after its own completed is beyond anything the retransmit machinery
239
- * would still be holding.
240
- *
241
- * @param {number} message_id
242
- */
243
- #remember_completed(message_id) {
244
- if (this.#completed.has(message_id)) {
245
- return;
246
- }
247
-
248
- this.#completed.add(message_id);
249
- this.#completed_order.push(message_id);
250
-
251
- while (this.#completed_order.length > this.max_pending_messages) {
252
- const oldest = this.#completed_order.shift();
253
-
254
- this.#completed.delete(oldest);
255
- }
256
- }
257
-
258
- /**
259
- * Per-tick maintenance: drive NACK emission for pending messages
260
- * whose initial delay has elapsed and whose resend interval has
261
- * lapsed, and drop messages whose NACK budget is exhausted.
262
- *
263
- * On the first service tick that observes a pending entry, its
264
- * arrival is timestamped (so the initial delay is measured from
265
- * `now_ms` of that tick rather than from the actual wall-clock
266
- * arrival of the first chunk — at typical tick rates the difference
267
- * is one tick, negligible vs. the 100 ms initial delay).
268
- *
269
- * `on_nack` is invoked once per eligible message with
270
- * `(message_id, indices, count)`: the missing chunks in index order, but
271
- * never more of them than the message has delivered. The `indices` argument is a
272
- * reused internal Uint8Array; only `indices[0..count)` is valid
273
- * and only for the duration of the call.
274
- *
275
- * @param {number} now_ms
276
- * @param {function(number, Uint8Array, number): void} on_nack
277
- */
278
- service(now_ms, on_nack) {
279
- assert.isNumber(now_ms, 'now_ms');
280
- assert.isFunction(on_nack, 'on_nack');
281
- if (this.#pending.size === 0) return;
282
-
283
- this.#drop_scratch.length = 0;
284
-
285
- for (const [message_id, entry] of this.#pending) {
286
- if (entry.first_seen_at < 0) {
287
- entry.first_seen_at = now_ms;
288
- continue;
289
- }
290
- if (now_ms - entry.first_seen_at < this.nack_initial_delay_ms) continue;
291
- if (entry.last_nack_at >= 0
292
- && now_ms - entry.last_nack_at < this.nack_resend_interval_ms) continue;
293
-
294
- // Build the missing-chunk list, no longer than the chunks the
295
- // message has delivered. `total_chunks` is the sender's claim, so
296
- // it cannot bound the list by itself: one empty fragment claiming
297
- // 255 chunks drew a NACK of the other 254 each round, some fifty
298
- // times its own size. A message that has lost more than it has
299
- // delivered is asked for the rest over the following rounds.
300
- let missing_count = 0;
301
- for (let i = 0; i < entry.total_chunks && missing_count < entry.received_count; i++) {
302
- if (entry.chunks[i] === undefined) {
303
- this.#nack_scratch[missing_count++] = i;
304
- }
305
- }
306
- // Defensive: a fully-received entry should have been deleted
307
- // in `receive`, but a torn-down concurrent state could leave
308
- // a zero-missing slot here. Skip rather than emit an empty NACK.
309
- if (missing_count === 0) continue;
310
-
311
- on_nack(message_id, this.#nack_scratch, missing_count);
312
- entry.last_nack_at = now_ms;
313
- entry.nack_rounds++;
314
-
315
- if (entry.nack_rounds >= this.nack_max_rounds) {
316
- this.#drop_scratch.push(message_id);
317
- }
318
- }
319
-
320
- for (let i = 0; i < this.#drop_scratch.length; i++) {
321
- this.#delete(this.#drop_scratch[i]);
322
- }
323
- }
324
-
325
- /**
326
- * Number of in-flight reassembly slots currently held.
327
- * @returns {number}
328
- */
329
- pending_count() {
330
- return this.#pending.size;
331
- }
332
-
333
- /**
334
- * Drop all in-flight reassembly state. Useful on peer disconnect.
335
- */
336
- clear() {
337
- this.#pending.clear();
338
- this.#order.length = 0;
339
-
340
- this.#completed.clear();
341
- this.#completed_order.length = 0;
342
- }
343
-
344
- /** @private */
345
- #delete(message_id) {
346
- this.#pending.delete(message_id);
347
- const idx = this.#order.indexOf(message_id);
348
- if (idx >= 0) this.#order.splice(idx, 1);
349
- }
350
- }