@woosh/meep-engine 3.46.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 (230) hide show
  1. package/editor/actions/concrete/TransformModifyAction.d.ts.map +1 -1
  2. package/editor/actions/concrete/TransformModifyAction.js +10 -2
  3. package/editor/ecs/component/FieldDescriptor.js +15 -0
  4. package/editor/ecs/component/createObjectEditor.js +41 -12
  5. package/editor/ecs/component/editors/ecs/Transform64Editor.d.ts.map +1 -1
  6. package/editor/ecs/component/editors/ecs/Transform64Editor.js +77 -70
  7. package/editor/tools/TransformToolV2.d.ts.map +1 -1
  8. package/editor/tools/TransformToolV2.js +4 -0
  9. package/editor/tools/v2/TransformControls.d.ts.map +1 -1
  10. package/editor/tools/v2/TransformControls.js +7 -0
  11. package/editor/view/ecs/EntityEditor.d.ts.map +1 -1
  12. package/editor/view/ecs/EntityEditor.js +4 -2
  13. package/package.json +1 -1
  14. package/src/core/collection/array/array_insert_at.d.ts +16 -0
  15. package/src/core/collection/array/array_insert_at.d.ts.map +1 -0
  16. package/src/core/collection/array/array_insert_at.js +32 -0
  17. package/src/core/collection/array/array_remove_at.d.ts +15 -0
  18. package/src/core/collection/array/array_remove_at.d.ts.map +1 -0
  19. package/src/core/collection/array/array_remove_at.js +30 -0
  20. package/src/core/geom/3d/quaternion/quat3_look_rotation.d.ts +37 -0
  21. package/src/core/geom/3d/quaternion/quat3_look_rotation.d.ts.map +1 -0
  22. package/src/core/geom/3d/quaternion/quat3_look_rotation.js +172 -0
  23. package/src/core/geom/Quaternion.d.ts +1 -0
  24. package/src/core/geom/Quaternion.d.ts.map +1 -1
  25. package/src/core/geom/Quaternion.js +12 -48
  26. package/src/engine/Engine.d.ts.map +1 -1
  27. package/src/engine/Engine.js +9 -4
  28. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  29. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +10 -0
  30. package/src/engine/ecs/transform/t64_look_rotation.d.ts +4 -4
  31. package/src/engine/ecs/transform/t64_look_rotation.d.ts.map +1 -1
  32. package/src/engine/ecs/transform/t64_look_rotation.js +7 -18
  33. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  34. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +30 -1
  35. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +6 -0
  36. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
  37. package/src/engine/graphics3/GPUParticleEmitterSystem.js +72 -29
  38. package/src/engine/input/devices/KeyboardDevice.d.ts +1 -0
  39. package/src/engine/input/devices/KeyboardDevice.d.ts.map +1 -1
  40. package/src/engine/input/devices/KeyboardDevice.js +7 -6
  41. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
  42. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +15 -2
  43. package/src/engine/network/CONGESTION_CONTROL.md +9 -9
  44. package/src/engine/network/MESSAGE_TRANSPORT.md +364 -0
  45. package/src/engine/network/NetworkSession.d.ts +31 -11
  46. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  47. package/src/engine/network/NetworkSession.js +453 -286
  48. package/src/engine/network/README.md +77 -27
  49. package/src/engine/network/SMOOTHNESS_DESIGN.md +13 -5
  50. package/src/engine/network/diagnostics/BandwidthMeter.d.ts +1 -1
  51. package/src/engine/network/diagnostics/BandwidthMeter.js +1 -1
  52. package/src/engine/network/orchestrator/HostJoin.d.ts +111 -0
  53. package/src/engine/network/orchestrator/HostJoin.d.ts.map +1 -0
  54. package/src/engine/network/orchestrator/HostJoin.js +271 -0
  55. package/src/engine/network/orchestrator/NetworkPeer.d.ts +151 -112
  56. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  57. package/src/engine/network/orchestrator/NetworkPeer.js +450 -499
  58. package/src/engine/network/orchestrator/PendingSlices.d.ts +30 -0
  59. package/src/engine/network/orchestrator/PendingSlices.d.ts.map +1 -0
  60. package/src/engine/network/orchestrator/PendingSlices.js +83 -0
  61. package/src/engine/network/orchestrator/ReliableFrames.d.ts +34 -0
  62. package/src/engine/network/orchestrator/ReliableFrames.d.ts.map +1 -0
  63. package/src/engine/network/orchestrator/ReliableFrames.js +96 -0
  64. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +77 -10
  65. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  66. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +236 -61
  67. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +20 -6
  68. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
  69. package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +33 -8
  70. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  71. package/src/engine/network/replication/Replicator.js +7 -1
  72. package/src/engine/network/sim/ActionLog.d.ts +32 -5
  73. package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
  74. package/src/engine/network/sim/ActionLog.js +47 -5
  75. package/src/engine/network/sim/SimActionExecutor.d.ts +42 -2
  76. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  77. package/src/engine/network/sim/SimActionExecutor.js +100 -4
  78. package/src/engine/network/sim/Snapshotter.d.ts +12 -0
  79. package/src/engine/network/sim/Snapshotter.d.ts.map +1 -1
  80. package/src/engine/network/sim/Snapshotter.js +43 -0
  81. package/src/engine/network/state/Baseline.d.ts +1 -1
  82. package/src/engine/network/state/Baseline.js +1 -1
  83. package/src/engine/network/state/FrameBufferRing.d.ts +25 -6
  84. package/src/engine/network/state/FrameBufferRing.d.ts.map +1 -1
  85. package/src/engine/network/state/FrameBufferRing.js +51 -6
  86. package/src/engine/network/state/InputRing.d.ts +4 -0
  87. package/src/engine/network/state/InputRing.d.ts.map +1 -1
  88. package/src/engine/network/state/InputRing.js +7 -0
  89. package/src/engine/network/transport/DeferredTransport.d.ts.map +1 -1
  90. package/src/engine/network/transport/DeferredTransport.js +1 -0
  91. package/src/engine/network/transport/LoopbackTransport.d.ts.map +1 -1
  92. package/src/engine/network/transport/LoopbackTransport.js +4 -2
  93. package/src/engine/network/transport/Transport.d.ts +7 -0
  94. package/src/engine/network/transport/Transport.d.ts.map +1 -1
  95. package/src/engine/network/transport/Transport.js +8 -0
  96. package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
  97. package/src/engine/network/transport/adapters/NodeUDPTransport.js +20 -5
  98. package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.d.ts.map +1 -1
  99. package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.js +8 -0
  100. package/src/engine/network/transport/adapters/WebTransportTransport.d.ts.map +1 -1
  101. package/src/engine/network/transport/adapters/WebTransportTransport.js +6 -0
  102. package/src/engine/network/transport/connection/Connection.d.ts +191 -0
  103. package/src/engine/network/transport/connection/Connection.d.ts.map +1 -0
  104. package/src/engine/network/transport/connection/Connection.js +1262 -0
  105. package/src/engine/network/transport/connection/RangeSet.d.ts +94 -0
  106. package/src/engine/network/transport/connection/RangeSet.d.ts.map +1 -0
  107. package/src/engine/network/transport/connection/RangeSet.js +260 -0
  108. package/src/engine/network/transport/connection/RxStream.d.ts +48 -0
  109. package/src/engine/network/transport/connection/RxStream.d.ts.map +1 -0
  110. package/src/engine/network/transport/connection/RxStream.js +211 -0
  111. package/src/engine/network/transport/connection/TxStream.d.ts +90 -0
  112. package/src/engine/network/transport/connection/TxStream.d.ts.map +1 -0
  113. package/src/engine/network/transport/connection/TxStream.js +243 -0
  114. package/src/engine/network/transport/connection/bytes_copy.d.ts +17 -0
  115. package/src/engine/network/transport/connection/bytes_copy.d.ts.map +1 -0
  116. package/src/engine/network/transport/connection/bytes_copy.js +34 -0
  117. package/src/engine/network/transport/connection/varint.d.ts +46 -0
  118. package/src/engine/network/transport/connection/varint.d.ts.map +1 -0
  119. package/src/engine/network/transport/connection/varint.js +107 -0
  120. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  121. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts +38 -7
  122. package/src/engine/sound/ecs/audio/AudioEmitter.d.ts.map +1 -1
  123. package/src/engine/sound/ecs/audio/AudioEmitter.js +35 -7
  124. package/src/engine/sound/ecs/audio/AudioEmitterSerializationAdapter.d.ts.map +1 -1
  125. package/src/engine/sound/ecs/audio/AudioEmitterSerializationAdapter.js +5 -1
  126. package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.d.ts +18 -0
  127. package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.d.ts.map +1 -0
  128. package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.js +48 -0
  129. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts +12 -2
  130. package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts.map +1 -1
  131. package/src/engine/sound/ecs/audio/AudioEmitterSystem.js +173 -9
  132. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts +9 -3
  133. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts.map +1 -1
  134. package/src/engine/sound/ecs/audio/LiveEmitterSet.js +28 -8
  135. package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts +8 -0
  136. package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts.map +1 -1
  137. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.d.ts.map +1 -1
  138. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.js +5 -1
  139. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.d.ts +18 -0
  140. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.d.ts.map +1 -0
  141. package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.js +51 -0
  142. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.d.ts.map +1 -1
  143. package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.js +15 -1
  144. package/src/engine/sound/sopra/README.md +768 -644
  145. package/src/engine/sound/sopra/SopraEngine.d.ts +104 -8
  146. package/src/engine/sound/sopra/SopraEngine.d.ts.map +1 -1
  147. package/src/engine/sound/sopra/SopraEngine.js +327 -12
  148. package/src/engine/sound/sopra/definition/EventDescription.d.ts +28 -2
  149. package/src/engine/sound/sopra/definition/EventDescription.d.ts.map +1 -1
  150. package/src/engine/sound/sopra/definition/EventDescription.js +55 -5
  151. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts +10 -0
  152. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts.map +1 -1
  153. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.js +77 -55
  154. package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.d.ts +31 -0
  155. package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.d.ts.map +1 -0
  156. package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.js +75 -0
  157. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts +38 -9
  158. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts.map +1 -1
  159. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.js +34 -5
  160. package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts +7 -2
  161. package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts.map +1 -1
  162. package/src/engine/sound/sopra/definition/effect/CompressorEffect.js +137 -122
  163. package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts +3 -1
  164. package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts.map +1 -1
  165. package/src/engine/sound/sopra/definition/effect/EqEffect.js +146 -131
  166. package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts +1 -0
  167. package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts.map +1 -1
  168. package/src/engine/sound/sopra/definition/effect/ReverbEffect.js +6 -1
  169. package/src/engine/sound/sopra/runtime/BusGraph.d.ts +44 -2
  170. package/src/engine/sound/sopra/runtime/BusGraph.d.ts.map +1 -1
  171. package/src/engine/sound/sopra/runtime/BusGraph.js +83 -43
  172. package/src/engine/sound/sopra/runtime/EffectChain.d.ts +96 -0
  173. package/src/engine/sound/sopra/runtime/EffectChain.d.ts.map +1 -0
  174. package/src/engine/sound/sopra/runtime/EffectChain.js +286 -0
  175. package/src/engine/sound/sopra/runtime/EffectParamOverrides.d.ts +123 -0
  176. package/src/engine/sound/sopra/runtime/EffectParamOverrides.d.ts.map +1 -0
  177. package/src/engine/sound/sopra/runtime/EffectParamOverrides.js +320 -0
  178. package/src/engine/sound/sopra/runtime/EventInstance.d.ts +55 -5
  179. package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
  180. package/src/engine/sound/sopra/runtime/EventInstance.js +201 -26
  181. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts +2 -1
  182. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts.map +1 -1
  183. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.js +6 -1
  184. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts +15 -0
  185. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts.map +1 -1
  186. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.js +32 -0
  187. package/src/engine/sound/sopra/util/MockAudioContext.d.ts.map +1 -1
  188. package/src/engine/sound/sopra/util/MockAudioContext.js +3 -0
  189. package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts +13 -3
  190. package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts.map +1 -1
  191. package/src/engine/sound/sopra/util/fadeOutAndStop.js +25 -13
  192. package/src/shade/RENDERER_CONTRACT.md +6 -3
  193. package/src/shade/device/SHADE_DEVICE_FLOOR.d.ts +24 -0
  194. package/src/shade/device/SHADE_DEVICE_FLOOR.d.ts.map +1 -0
  195. package/src/shade/device/SHADE_DEVICE_FLOOR.js +34 -0
  196. package/src/shade/device/ShadeDeviceFailure.d.ts +12 -5
  197. package/src/shade/device/ShadeDeviceFailure.d.ts.map +1 -1
  198. package/src/shade/device/ShadeDeviceFailure.js +17 -8
  199. package/src/shade/device/ShadeDeviceFailureReason.d.ts +1 -1
  200. package/src/shade/device/ShadeDeviceFailureReason.js +2 -2
  201. package/src/shade/device/shade_device_floor_unmet.d.ts +13 -0
  202. package/src/shade/device/shade_device_floor_unmet.d.ts.map +1 -0
  203. package/src/shade/device/shade_device_floor_unmet.js +32 -0
  204. package/src/shade/renderer/Renderer.d.ts +2 -0
  205. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  206. package/src/shade/renderer/Renderer.js +29 -55
  207. package/src/shade/renderer/buffer/GPUBufferAllocator.d.ts.map +1 -1
  208. package/src/shade/renderer/buffer/GPUBufferAllocator.js +9 -0
  209. package/src/shade/renderer/buffer/buffer_pool_ops.d.ts +21 -12
  210. package/src/shade/renderer/buffer/buffer_pool_ops.d.ts.map +1 -1
  211. package/src/shade/renderer/buffer/buffer_pool_ops.js +18 -19
  212. package/src/shade/renderer/gpu_primitive/test/gpu_test.d.ts.map +1 -1
  213. package/src/shade/renderer/gpu_primitive/test/gpu_test.js +8 -11
  214. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  215. package/src/shade/renderer/pool/TransientResourcePool.d.ts +24 -0
  216. package/src/shade/renderer/pool/TransientResourcePool.d.ts.map +1 -1
  217. package/src/shade/renderer/pool/TransientResourcePool.js +41 -10
  218. package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
  219. package/src/shade/renderer/shader/ComputeShader.js +18 -2
  220. package/src/shade/renderer/shader/ImageShader.d.ts.map +1 -1
  221. package/src/shade/renderer/shader/ImageShader.js +230 -218
  222. package/src/view/graphics/GraphicsContextFailureView.d.ts +1 -2
  223. package/src/view/graphics/GraphicsContextFailureView.d.ts.map +1 -1
  224. package/src/view/graphics/GraphicsContextFailureView.js +1 -2
  225. package/src/engine/network/transport/Channel.js +0 -336
  226. package/src/engine/network/transport/ReliableCommandPipeline.js +0 -335
  227. package/src/engine/network/transport/fragments/FragmentAssembler.js +0 -350
  228. package/src/engine/network/transport/fragments/FragmentRetention.js +0 -191
  229. package/src/engine/network/transport/fragments/fragment_send.js +0 -157
  230. package/src/engine/network/transport/fragments/packet_size.js +0 -107
@@ -0,0 +1,94 @@
1
+ /**
2
+ * A set of non-negative integers held as sorted, disjoint, non-adjacent half-open ranges
3
+ * `[start, end)`. Packet numbers a receiver has seen, stream bytes it holds, bytes a sender must
4
+ * re-send: each is a few long runs, so a range list is both the compact and the cheap form.
5
+ *
6
+ * Values are doubles, exact to 2^53, so neither a packet number nor a stream offset ever wraps.
7
+ * Storage is one `Float64Array` of `[start, end]` pairs that grows to a high-watermark and stays:
8
+ * nothing is allocated once it is big enough.
9
+ *
10
+ * Operations are linear in the number of ranges. Every user bounds that number (an ACK reports at
11
+ * most a few dozen; a stream's holes are bounded by its window), so linear is the fast form too.
12
+ *
13
+ * @author Alex Goldring
14
+ * @copyright Company Named Limited (c) 2026
15
+ */
16
+ export class RangeSet {
17
+ /**
18
+ * @param {number} [initial_capacity] ranges to make room for up front
19
+ */
20
+ constructor(initial_capacity?: number);
21
+ /**
22
+ * Number of disjoint ranges.
23
+ * @returns {number}
24
+ */
25
+ get count(): number;
26
+ /**
27
+ * @param {number} i range index, `[0, count)`
28
+ * @returns {number} inclusive start
29
+ */
30
+ start(i: number): number;
31
+ /**
32
+ * @param {number} i range index, `[0, count)`
33
+ * @returns {number} exclusive end
34
+ */
35
+ end(i: number): number;
36
+ /**
37
+ * @returns {boolean}
38
+ */
39
+ is_empty(): boolean;
40
+ /**
41
+ * Smallest value held. Only meaningful when not empty.
42
+ * @returns {number}
43
+ */
44
+ min(): number;
45
+ /**
46
+ * One past the largest value held. Only meaningful when not empty.
47
+ * @returns {number}
48
+ */
49
+ max_end(): number;
50
+ clear(): void;
51
+ /**
52
+ * @param {number} value
53
+ * @returns {boolean}
54
+ */
55
+ contains(value: number): boolean;
56
+ /**
57
+ * Whether every value of `[start, end)` is held.
58
+ * @param {number} start
59
+ * @param {number} end
60
+ * @returns {boolean}
61
+ */
62
+ contains_range(start: number, end: number): boolean;
63
+ /**
64
+ * End of the run that starts at `value`: the largest `e` with `[value, e)` held, or `value`
65
+ * itself when `value` is not held.
66
+ * @param {number} value
67
+ * @returns {number}
68
+ */
69
+ run_end(value: number): number;
70
+ /**
71
+ * Add `[start, end)`, merging with whatever it touches.
72
+ * @param {number} start
73
+ * @param {number} end
74
+ */
75
+ add(start: number, end: number): void;
76
+ /**
77
+ * Remove `[start, end)`, splitting a range it lands inside.
78
+ * @param {number} start
79
+ * @param {number} end
80
+ */
81
+ remove(start: number, end: number): void;
82
+ /**
83
+ * Remove everything below `value`.
84
+ * @param {number} value
85
+ */
86
+ remove_below(value: number): void;
87
+ /**
88
+ * Drop whole ranges from the bottom until at most `max_count` remain.
89
+ * @param {number} max_count
90
+ */
91
+ keep_highest(max_count: number): void;
92
+ #private;
93
+ }
94
+ //# sourceMappingURL=RangeSet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RangeSet.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/network/transport/connection/RangeSet.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH;IAaI;;OAEG;IACH,+BAFW,MAAM,EAKhB;IAED;;;OAGG;IACH,oBAEC;IAED;;;OAGG;IACH,SAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;OAGG;IACH,OAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;OAEG;IACH,YAFa,OAAO,CAInB;IAED;;;OAGG;IACH,OAFa,MAAM,CAIlB;IAED;;;OAGG;IACH,WAFa,MAAM,CAIlB;IAED,cAEC;IAED;;;OAGG;IACH,gBAHW,MAAM,GACJ,OAAO,CAUnB;IAED;;;;;OAKG;IACH,sBAJW,MAAM,OACN,MAAM,GACJ,OAAO,CAWnB;IAED;;;;;OAKG;IACH,eAHW,MAAM,GACJ,MAAM,CAWlB;IAED;;;;OAIG;IACH,WAHW,MAAM,OACN,MAAM,QA0ChB;IAED;;;;OAIG;IACH,cAHW,MAAM,OACN,MAAM,QAwChB;IAED;;;OAGG;IACH,oBAFW,MAAM,QAKhB;IAED;;;OAGG;IACH,wBAFW,MAAM,QAQhB;;CAWJ"}
@@ -0,0 +1,260 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+
3
+ /**
4
+ * A set of non-negative integers held as sorted, disjoint, non-adjacent half-open ranges
5
+ * `[start, end)`. Packet numbers a receiver has seen, stream bytes it holds, bytes a sender must
6
+ * re-send: each is a few long runs, so a range list is both the compact and the cheap form.
7
+ *
8
+ * Values are doubles, exact to 2^53, so neither a packet number nor a stream offset ever wraps.
9
+ * Storage is one `Float64Array` of `[start, end]` pairs that grows to a high-watermark and stays:
10
+ * nothing is allocated once it is big enough.
11
+ *
12
+ * Operations are linear in the number of ranges. Every user bounds that number (an ACK reports at
13
+ * most a few dozen; a stream's holes are bounded by its window), so linear is the fast form too.
14
+ *
15
+ * @author Alex Goldring
16
+ * @copyright Company Named Limited (c) 2026
17
+ */
18
+ export class RangeSet {
19
+ /**
20
+ * `[start0, end0, start1, end1, ...]`, ascending, disjoint and non-adjacent.
21
+ * @type {Float64Array}
22
+ */
23
+ #data;
24
+
25
+ /**
26
+ * Number of ranges held.
27
+ * @type {number}
28
+ */
29
+ #count = 0;
30
+
31
+ /**
32
+ * @param {number} [initial_capacity] ranges to make room for up front
33
+ */
34
+ constructor(initial_capacity = 8) {
35
+ assert.isPositiveInteger(initial_capacity, 'initial_capacity');
36
+ this.#data = new Float64Array(initial_capacity * 2);
37
+ }
38
+
39
+ /**
40
+ * Number of disjoint ranges.
41
+ * @returns {number}
42
+ */
43
+ get count() {
44
+ return this.#count;
45
+ }
46
+
47
+ /**
48
+ * @param {number} i range index, `[0, count)`
49
+ * @returns {number} inclusive start
50
+ */
51
+ start(i) {
52
+ return this.#data[i * 2];
53
+ }
54
+
55
+ /**
56
+ * @param {number} i range index, `[0, count)`
57
+ * @returns {number} exclusive end
58
+ */
59
+ end(i) {
60
+ return this.#data[i * 2 + 1];
61
+ }
62
+
63
+ /**
64
+ * @returns {boolean}
65
+ */
66
+ is_empty() {
67
+ return this.#count === 0;
68
+ }
69
+
70
+ /**
71
+ * Smallest value held. Only meaningful when not empty.
72
+ * @returns {number}
73
+ */
74
+ min() {
75
+ return this.#data[0];
76
+ }
77
+
78
+ /**
79
+ * One past the largest value held. Only meaningful when not empty.
80
+ * @returns {number}
81
+ */
82
+ max_end() {
83
+ return this.#data[this.#count * 2 - 1];
84
+ }
85
+
86
+ clear() {
87
+ this.#count = 0;
88
+ }
89
+
90
+ /**
91
+ * @param {number} value
92
+ * @returns {boolean}
93
+ */
94
+ contains(value) {
95
+ const data = this.#data;
96
+ for (let i = 0; i < this.#count; i++) {
97
+ const s = data[i * 2];
98
+ if (value < s) return false;
99
+ if (value < data[i * 2 + 1]) return true;
100
+ }
101
+ return false;
102
+ }
103
+
104
+ /**
105
+ * Whether every value of `[start, end)` is held.
106
+ * @param {number} start
107
+ * @param {number} end
108
+ * @returns {boolean}
109
+ */
110
+ contains_range(start, end) {
111
+ if (end <= start) return true;
112
+ const data = this.#data;
113
+ for (let i = 0; i < this.#count; i++) {
114
+ const s = data[i * 2];
115
+ if (start < s) return false;
116
+ if (start < data[i * 2 + 1]) return end <= data[i * 2 + 1];
117
+ }
118
+ return false;
119
+ }
120
+
121
+ /**
122
+ * End of the run that starts at `value`: the largest `e` with `[value, e)` held, or `value`
123
+ * itself when `value` is not held.
124
+ * @param {number} value
125
+ * @returns {number}
126
+ */
127
+ run_end(value) {
128
+ const data = this.#data;
129
+ for (let i = 0; i < this.#count; i++) {
130
+ const s = data[i * 2];
131
+ if (value < s) return value;
132
+ const e = data[i * 2 + 1];
133
+ if (value < e) return e;
134
+ }
135
+ return value;
136
+ }
137
+
138
+ /**
139
+ * Add `[start, end)`, merging with whatever it touches.
140
+ * @param {number} start
141
+ * @param {number} end
142
+ */
143
+ add(start, end) {
144
+ if (end <= start) return;
145
+ const data = this.#data;
146
+ const n = this.#count;
147
+
148
+ // first range whose end reaches `start` (touching counts: they merge); a binary search, so
149
+ // the common add — at or past the top — costs nothing for the ranges below it
150
+ let lo = 0;
151
+ let top = n;
152
+ while (lo < top) {
153
+ const mid = (lo + top) >>> 1;
154
+ if (data[mid * 2 + 1] < start) lo = mid + 1;
155
+ else top = mid;
156
+ }
157
+
158
+ // first range that starts strictly past `end`
159
+ let hi = lo;
160
+ while (hi < n && data[hi * 2] <= end) hi++;
161
+
162
+ if (lo === hi) {
163
+ // touches nothing: insert at lo
164
+ this.#ensure_capacity(n + 1);
165
+ const d = this.#data;
166
+ d.copyWithin((lo + 1) * 2, lo * 2, n * 2);
167
+ d[lo * 2] = start;
168
+ d[lo * 2 + 1] = end;
169
+ this.#count = n + 1;
170
+ return;
171
+ }
172
+
173
+ // merge ranges [lo, hi) with [start, end) into slot lo
174
+ const merged_start = Math.min(start, data[lo * 2]);
175
+ const merged_end = Math.max(end, data[(hi - 1) * 2 + 1]);
176
+ data[lo * 2] = merged_start;
177
+ data[lo * 2 + 1] = merged_end;
178
+ const removed = hi - lo - 1;
179
+ if (removed > 0) {
180
+ data.copyWithin((lo + 1) * 2, hi * 2, n * 2);
181
+ this.#count = n - removed;
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Remove `[start, end)`, splitting a range it lands inside.
187
+ * @param {number} start
188
+ * @param {number} end
189
+ */
190
+ remove(start, end) {
191
+ if (end <= start) return;
192
+ let i = 0;
193
+ while (i < this.#count) {
194
+ const data = this.#data;
195
+ const s = data[i * 2];
196
+ const e = data[i * 2 + 1];
197
+ if (e <= start) {
198
+ i++;
199
+ continue;
200
+ }
201
+ if (s >= end) return;
202
+
203
+ if (s < start && e > end) {
204
+ // split in two
205
+ const n = this.#count;
206
+ this.#ensure_capacity(n + 1);
207
+ const d = this.#data;
208
+ d.copyWithin((i + 2) * 2, (i + 1) * 2, n * 2);
209
+ d[i * 2 + 1] = start;
210
+ d[(i + 1) * 2] = end;
211
+ d[(i + 1) * 2 + 1] = e;
212
+ this.#count = n + 1;
213
+ return;
214
+ }
215
+ if (s < start) {
216
+ data[i * 2 + 1] = start;
217
+ i++;
218
+ continue;
219
+ }
220
+ if (e > end) {
221
+ data[i * 2] = end;
222
+ return;
223
+ }
224
+ // fully covered: delete range i
225
+ data.copyWithin(i * 2, (i + 1) * 2, this.#count * 2);
226
+ this.#count--;
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Remove everything below `value`.
232
+ * @param {number} value
233
+ */
234
+ remove_below(value) {
235
+ if (this.#count === 0) return;
236
+ this.remove(this.#data[0], value);
237
+ }
238
+
239
+ /**
240
+ * Drop whole ranges from the bottom until at most `max_count` remain.
241
+ * @param {number} max_count
242
+ */
243
+ keep_highest(max_count) {
244
+ const n = this.#count;
245
+ if (n <= max_count) return;
246
+ const drop = n - max_count;
247
+ this.#data.copyWithin(0, drop * 2, n * 2);
248
+ this.#count = max_count;
249
+ }
250
+
251
+ /**
252
+ * @param {number} ranges
253
+ */
254
+ #ensure_capacity(ranges) {
255
+ if (ranges * 2 <= this.#data.length) return;
256
+ const next = new Float64Array(Math.max(ranges * 2, this.#data.length * 2));
257
+ next.set(this.#data.subarray(0, this.#count * 2));
258
+ this.#data = next;
259
+ }
260
+ }
@@ -0,0 +1,48 @@
1
+ /** {@link RxStream#next_message}: nothing whole yet. */
2
+ export const RX_NONE: -1;
3
+ /** {@link RxStream#next_message}: the stream broke the protocol; stop reading it. */
4
+ export const RX_ERROR: -2;
5
+ export class RxStream {
6
+ /**
7
+ * @param {number} max_message_bytes largest message this lane accepts
8
+ * @param {number} window bytes past the delivered point the sender may have in flight
9
+ */
10
+ constructor(max_message_bytes: number, window: number);
11
+ /** @type {number} @readonly */
12
+ readonly max_message_bytes: number;
13
+ /** @type {number} @readonly */
14
+ readonly window: number;
15
+ /**
16
+ * Most disjoint ranges held out of order: one per 256 bytes of window, and never fewer
17
+ * than 1,024.
18
+ * @type {number} @readonly
19
+ */
20
+ readonly max_ranges: number;
21
+ /** Whether the stream has broken the protocol. */
22
+ get failed(): boolean;
23
+ /** How the stream broke the protocol; empty while it has not. */
24
+ get failure(): string;
25
+ /**
26
+ * Take one segment.
27
+ *
28
+ * @param {number} offset stream offset of the segment's first byte
29
+ * @param {Uint8Array} bytes
30
+ * @param {number} from index of the first byte in `bytes`
31
+ * @param {number} length
32
+ * @returns {boolean} false when the segment breaks the protocol
33
+ */
34
+ receive(offset: number, bytes: Uint8Array, from: number, length: number): boolean;
35
+ /**
36
+ * The next whole message, consumed. Writes its position in {@link bytes} into `out[0]`; valid until
37
+ * the next {@link receive}.
38
+ *
39
+ * @param {Float64Array|number[]} out
40
+ * @returns {number} message length, {@link RX_NONE} or {@link RX_ERROR}
41
+ */
42
+ next_message(out: Float64Array | number[]): number;
43
+ /** The buffer {@link next_message} positions are in. */
44
+ get bytes(): Uint8Array;
45
+ clear(): void;
46
+ #private;
47
+ }
48
+ //# sourceMappingURL=RxStream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RxStream.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/network/transport/connection/RxStream.js"],"names":[],"mappings":"AAyBA,wDAAwD;AACxD,yBAA0B;AAE1B,qFAAqF;AACrF,0BAA2B;AAE3B;IAuCI;;;OAGG;IACH,+BAHW,MAAM,UACN,MAAM,EAchB;IAXG,+BAA+B;IAC/B,4BADW,MAAM,CACyB;IAC1C,+BAA+B;IAC/B,iBADW,MAAM,CACG;IACpB;;;;OAIG;IACH,qBAFU,MAAM,CAEyC;IAI7D,kDAAkD;IAClD,sBAEC;IAED,iEAAiE;IACjE,sBAEC;IAED;;;;;;;;OAQG;IACH,gBANW,MAAM,SACN,UAAU,QACV,MAAM,UACN,MAAM,GACJ,OAAO,CAqBnB;IAYD;;;;;;OAMG;IACH,kBAHW,YAAY,GAAC,MAAM,EAAE,GACnB,MAAM,CA+BlB;IAED,wDAAwD;IACxD,wBAEC;IAED,cAKC;;CAwBJ"}
@@ -0,0 +1,211 @@
1
+ import { bytes_copy } from "./bytes_copy.js";
2
+ import { RangeSet } from "./RangeSet.js";
3
+ import { varint_read } from "./varint.js";
4
+
5
+ /**
6
+ * Receive half of one reliable lane: puts stream segments back in order and hands out whole
7
+ * `[varint length][bytes]` messages as soon as their bytes are contiguous.
8
+ *
9
+ * Memory is bounded by configuration, never by what the peer claims. A segment reaching past
10
+ * `consumed + max_message_bytes + header + window` cannot come from a sender keeping to its window
11
+ * (see {@link TxStream}), and a message declaring more than `max_message_bytes` is refused: both
12
+ * are protocol errors, and the lane stops.
13
+ *
14
+ * So is time. What a segment costs to take in grows with the holes held, and a peer sending
15
+ * one-byte segments two bytes apart would have the receiver hold half a window of them. An honest
16
+ * sender's holes are packets it lost and has not re-sent yet: a few hundred at the most in a
17
+ * 256 KiB window, even over small datagrams. More than {@link max_ranges} is a protocol error.
18
+ *
19
+ * @author Alex Goldring
20
+ * @copyright Company Named Limited (c) 2026
21
+ */
22
+
23
+ /** Largest header a message length can have. */
24
+ const MAX_HEADER_BYTES = 8;
25
+
26
+ /** {@link RxStream#next_message}: nothing whole yet. */
27
+ export const RX_NONE = -1;
28
+
29
+ /** {@link RxStream#next_message}: the stream broke the protocol; stop reading it. */
30
+ export const RX_ERROR = -2;
31
+
32
+ export class RxStream {
33
+ /**
34
+ * Stream bytes from {@link #buffer_base} on.
35
+ * @type {Uint8Array}
36
+ */
37
+ #buffer;
38
+
39
+ /**
40
+ * Stream offset of `#buffer[0]`.
41
+ * @type {number}
42
+ */
43
+ #buffer_base = 0;
44
+
45
+ /**
46
+ * Every byte below this offset has been handed out.
47
+ * @type {number}
48
+ */
49
+ #consumed = 0;
50
+
51
+ /**
52
+ * Ranges held at or above {@link #consumed}.
53
+ * @type {RangeSet}
54
+ */
55
+ #received = new RangeSet();
56
+
57
+ /**
58
+ * Set once the stream has broken the protocol.
59
+ * @type {boolean}
60
+ */
61
+ #failed = false;
62
+
63
+ /**
64
+ * How it broke the protocol, once {@link #failed}.
65
+ * @type {string}
66
+ */
67
+ #failure = '';
68
+
69
+ #cursor = { position: 0 };
70
+
71
+ /**
72
+ * @param {number} max_message_bytes largest message this lane accepts
73
+ * @param {number} window bytes past the delivered point the sender may have in flight
74
+ */
75
+ constructor(max_message_bytes, window) {
76
+ /** @type {number} @readonly */
77
+ this.max_message_bytes = max_message_bytes;
78
+ /** @type {number} @readonly */
79
+ this.window = window;
80
+ /**
81
+ * Most disjoint ranges held out of order: one per 256 bytes of window, and never fewer
82
+ * than 1,024.
83
+ * @type {number} @readonly
84
+ */
85
+ this.max_ranges = Math.max(1024, Math.ceil(window / 256));
86
+ this.#buffer = new Uint8Array(1024);
87
+ }
88
+
89
+ /** Whether the stream has broken the protocol. */
90
+ get failed() {
91
+ return this.#failed;
92
+ }
93
+
94
+ /** How the stream broke the protocol; empty while it has not. */
95
+ get failure() {
96
+ return this.#failure;
97
+ }
98
+
99
+ /**
100
+ * Take one segment.
101
+ *
102
+ * @param {number} offset stream offset of the segment's first byte
103
+ * @param {Uint8Array} bytes
104
+ * @param {number} from index of the first byte in `bytes`
105
+ * @param {number} length
106
+ * @returns {boolean} false when the segment breaks the protocol
107
+ */
108
+ receive(offset, bytes, from, length) {
109
+ if (this.#failed) return false;
110
+ let start = offset;
111
+ const end = offset + length;
112
+ if (end <= this.#consumed) return true; // all of it handed out already
113
+ if (start < this.#consumed) {
114
+ from += this.#consumed - start;
115
+ start = this.#consumed;
116
+ }
117
+ if (end > this.#consumed + this.max_message_bytes + MAX_HEADER_BYTES + this.window) {
118
+ return this.#fail('segment past the receive window');
119
+ }
120
+ this.#reserve(end);
121
+ bytes_copy(bytes, from, this.#buffer, start - this.#buffer_base, end - start);
122
+ this.#received.add(start, end);
123
+ if (this.#received.count > this.max_ranges) {
124
+ return this.#fail(`more than ${this.max_ranges} holes held out of order`);
125
+ }
126
+ return true;
127
+ }
128
+
129
+ /**
130
+ * @param {string} reason
131
+ * @returns {boolean} false
132
+ */
133
+ #fail(reason) {
134
+ this.#failed = true;
135
+ this.#failure = reason;
136
+ return false;
137
+ }
138
+
139
+ /**
140
+ * The next whole message, consumed. Writes its position in {@link bytes} into `out[0]`; valid until
141
+ * the next {@link receive}.
142
+ *
143
+ * @param {Float64Array|number[]} out
144
+ * @returns {number} message length, {@link RX_NONE} or {@link RX_ERROR}
145
+ */
146
+ next_message(out) {
147
+ if (this.#failed) return RX_ERROR;
148
+ const received = this.#received;
149
+ if (received.is_empty() || received.min() > this.#consumed) return RX_NONE;
150
+ const contiguous = received.end(0);
151
+
152
+ const read = this.#consumed - this.#buffer_base;
153
+ const cursor = this.#cursor;
154
+ cursor.position = read;
155
+ const length = varint_read(this.#buffer, cursor, contiguous - this.#buffer_base);
156
+ if (length < 0) {
157
+ // header not all here yet - unless it is already as long as a header can be
158
+ if (contiguous - this.#consumed >= MAX_HEADER_BYTES) {
159
+ this.#fail('message length is not a varint');
160
+ return RX_ERROR;
161
+ }
162
+ return RX_NONE;
163
+ }
164
+ if (length > this.max_message_bytes) {
165
+ this.#fail(`message larger than max_message_bytes ${this.max_message_bytes}`);
166
+ return RX_ERROR;
167
+ }
168
+ const body = cursor.position;
169
+ if (body + length > contiguous - this.#buffer_base) return RX_NONE;
170
+
171
+ out[0] = body;
172
+ this.#consumed = this.#buffer_base + body + length;
173
+ received.remove_below(this.#consumed);
174
+ return length;
175
+ }
176
+
177
+ /** The buffer {@link next_message} positions are in. */
178
+ get bytes() {
179
+ return this.#buffer;
180
+ }
181
+
182
+ clear() {
183
+ this.#buffer_base = this.#consumed = 0;
184
+ this.#received.clear();
185
+ this.#failed = false;
186
+ this.#failure = '';
187
+ }
188
+
189
+ /**
190
+ * Make the buffer reach stream offset `end`: first by dropping what has been handed out, then
191
+ * by growing. Bounded by the caller's check against the window.
192
+ * @param {number} end
193
+ */
194
+ #reserve(end) {
195
+ if (end - this.#buffer_base <= this.#buffer.length) return;
196
+ const drop = this.#consumed - this.#buffer_base;
197
+ if (drop > 0) {
198
+ const held_end = this.#received.is_empty() ? this.#consumed : this.#received.max_end();
199
+ const kept = held_end - this.#consumed;
200
+ if (kept > 0) this.#buffer.copyWithin(0, drop, drop + kept);
201
+ this.#buffer_base = this.#consumed;
202
+ }
203
+ const needed = end - this.#buffer_base;
204
+ if (needed <= this.#buffer.length) return;
205
+ let size = this.#buffer.length * 2;
206
+ while (size < needed) size *= 2;
207
+ const next = new Uint8Array(size);
208
+ next.set(this.#buffer);
209
+ this.#buffer = next;
210
+ }
211
+ }