@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.
- package/build/bundle-worker-terrain.js +1 -1
- package/editor/actions/concrete/TransformModifyAction.d.ts.map +1 -1
- package/editor/actions/concrete/TransformModifyAction.js +10 -2
- package/editor/ecs/component/FieldDescriptor.js +15 -0
- package/editor/ecs/component/createObjectEditor.js +41 -12
- package/editor/ecs/component/editors/ecs/Transform64Editor.d.ts.map +1 -1
- package/editor/ecs/component/editors/ecs/Transform64Editor.js +77 -70
- package/editor/tools/TransformToolV2.d.ts.map +1 -1
- package/editor/tools/TransformToolV2.js +4 -0
- package/editor/tools/v2/TransformControls.d.ts.map +1 -1
- package/editor/tools/v2/TransformControls.js +7 -0
- package/editor/view/ecs/EntityEditor.d.ts.map +1 -1
- package/editor/view/ecs/EntityEditor.js +4 -2
- package/package.json +1 -1
- package/src/core/assert.d.ts.map +1 -1
- package/src/core/assert.js +5 -1
- package/src/core/binary/hash/XXH128Hash.d.ts +1 -37
- package/src/core/binary/hash/XXH128Hash.d.ts.map +1 -1
- package/src/core/binary/hash/XXH128Hash.js +4 -55
- package/src/core/binary/hash/XXH3_SECRET.d.ts +1 -12
- package/src/core/binary/hash/XXH3_SECRET.d.ts.map +1 -1
- package/src/core/binary/hash/XXH3_SECRET.js +4 -25
- package/src/core/binary/hash/crc32.d.ts +1 -15
- package/src/core/binary/hash/crc32.d.ts.map +1 -1
- package/src/core/binary/hash/crc32.js +4 -96
- package/src/core/binary/hash/xxh3_128.d.ts +1 -9
- package/src/core/binary/hash/xxh3_128.d.ts.map +1 -1
- package/src/core/binary/hash/xxh3_128.js +4 -341
- package/src/core/binary/hash/xxh3_64.d.ts +1 -8
- package/src/core/binary/hash/xxh3_64.d.ts.map +1 -1
- package/src/core/binary/hash/xxh3_64.js +4 -241
- package/src/core/binary/hash/xxh3_common.d.ts +1 -223
- package/src/core/binary/hash/xxh3_common.d.ts.map +1 -1
- package/src/core/binary/hash/xxh3_common.js +90 -476
- package/src/core/collection/array/array_insert_at.d.ts +16 -0
- package/src/core/collection/array/array_insert_at.d.ts.map +1 -0
- package/src/core/collection/array/array_insert_at.js +32 -0
- package/src/core/collection/array/array_remove_at.d.ts +15 -0
- package/src/core/collection/array/array_remove_at.d.ts.map +1 -0
- package/src/core/collection/array/array_remove_at.js +30 -0
- package/src/core/collection/array/combine_hash.d.ts +6 -0
- package/src/core/collection/array/combine_hash.d.ts.map +1 -1
- package/src/core/collection/array/combine_hash.js +6 -0
- package/src/core/function/FunctionCompiler.js +2 -2
- package/src/core/geom/3d/mat4/m4_multiply.d.ts +3 -0
- package/src/core/geom/3d/mat4/m4_multiply.d.ts.map +1 -1
- package/src/core/geom/3d/mat4/m4_multiply.js +3 -0
- package/src/core/geom/3d/mat4/m4_multiply_f64.d.ts +30 -0
- package/src/core/geom/3d/mat4/m4_multiply_f64.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_multiply_f64.js +106 -0
- package/src/core/geom/3d/quaternion/quat3_look_rotation.d.ts +37 -0
- package/src/core/geom/3d/quaternion/quat3_look_rotation.d.ts.map +1 -0
- package/src/core/geom/3d/quaternion/quat3_look_rotation.js +172 -0
- package/src/core/geom/ConicRay.js +2 -2
- package/src/core/geom/Quaternion.d.ts +1 -0
- package/src/core/geom/Quaternion.d.ts.map +1 -1
- package/src/core/geom/Quaternion.js +12 -48
- package/src/core/geom/Vector4.d.ts.map +1 -1
- package/src/core/geom/Vector4.js +8 -5
- package/src/core/math/hash/XXH128Hash.d.ts +38 -0
- package/src/core/math/hash/XXH128Hash.d.ts.map +1 -0
- package/src/core/math/hash/XXH128Hash.js +55 -0
- package/src/core/math/hash/XXH3_SECRET.d.ts +13 -0
- package/src/core/math/hash/XXH3_SECRET.d.ts.map +1 -0
- package/src/core/math/hash/XXH3_SECRET.js +25 -0
- package/src/core/math/hash/crc32.d.ts +16 -0
- package/src/core/math/hash/crc32.d.ts.map +1 -0
- package/src/core/math/hash/crc32.js +96 -0
- package/src/core/math/hash/xxh3_128.d.ts +10 -0
- package/src/core/math/hash/xxh3_128.d.ts.map +1 -0
- package/src/core/math/hash/xxh3_128.js +341 -0
- package/src/core/math/hash/xxh3_64.d.ts +9 -0
- package/src/core/math/hash/xxh3_64.d.ts.map +1 -0
- package/src/core/math/hash/xxh3_64.js +241 -0
- package/src/core/math/hash/xxh3_common.d.ts +224 -0
- package/src/core/math/hash/xxh3_common.d.ts.map +1 -0
- package/src/core/math/hash/xxh3_common.js +476 -0
- package/src/core/math/lookup/ParameterLookupTable.js +2 -2
- package/src/core/model/node-graph/node/NodeInstancePortReference.js +2 -2
- package/src/core/model/reactive/model/ReactiveBinaryExpression.js +2 -2
- package/src/core/model/reactive/model/terminal/ReactiveReference.js +2 -2
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +9 -4
- package/src/engine/asset/AssetDescription.js +2 -2
- package/src/engine/ecs/animation/Animation.js +2 -2
- package/src/engine/ecs/animation/AnimationClip.d.ts.map +1 -1
- package/src/engine/ecs/animation/AnimationClip.js +7 -5
- package/src/engine/ecs/gui/GUIElement.d.ts.map +1 -1
- package/src/engine/ecs/gui/GUIElement.js +7 -5
- package/src/engine/ecs/gui/hud/HeadsUpDisplay.js +2 -2
- package/src/engine/ecs/gui/position/ViewportPosition.d.ts.map +1 -1
- package/src/engine/ecs/gui/position/ViewportPosition.js +11 -7
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +10 -0
- package/src/engine/ecs/transform/Transform64.d.ts +1 -1
- package/src/engine/ecs/transform/Transform64.d.ts.map +1 -1
- package/src/engine/ecs/transform/Transform64.js +5 -4
- package/src/engine/ecs/transform/t64_look_rotation.d.ts +4 -4
- package/src/engine/ecs/transform/t64_look_rotation.d.ts.map +1 -1
- package/src/engine/ecs/transform/t64_look_rotation.js +7 -18
- package/src/engine/graphics/ecs/animation/animator/AnimationClip.d.ts.map +1 -1
- package/src/engine/graphics/ecs/animation/animator/AnimationClip.js +8 -5
- package/src/engine/graphics/ecs/animation/animator/AnimationClipDefinition.js +2 -2
- package/src/engine/graphics/ecs/animation/animator/AnimationNotification.js +2 -2
- package/src/engine/graphics/ecs/animation/animator/AnimationNotificationDefinition.js +2 -2
- package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationGraphDefinition.js +2 -2
- package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationStateDefinition.js +2 -2
- package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationTransitionDefinition.d.ts.map +1 -1
- package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationTransitionDefinition.js +8 -5
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +30 -1
- package/src/engine/graphics/ecs/decal/v2/Decal.d.ts.map +1 -1
- package/src/engine/graphics/ecs/decal/v2/Decal.js +9 -8
- package/src/engine/graphics/render/frame_graph/resource/TextureResourceDescriptor.d.ts.map +1 -1
- package/src/engine/graphics/render/frame_graph/resource/TextureResourceDescriptor.js +9 -6
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +6 -0
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/GPUParticleEmitterSystem.js +72 -29
- package/src/engine/graphics3/ParticipatingMedia.js +204 -204
- package/src/engine/graphics3/animation/AnimationClips.d.ts +5 -0
- package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -1
- package/src/engine/graphics3/animation/AnimationClips.js +5 -0
- package/src/engine/grid/obstacle/GridObstacle.js +2 -2
- package/src/engine/input/devices/KeyboardDevice.d.ts +1 -0
- package/src/engine/input/devices/KeyboardDevice.d.ts.map +1 -1
- package/src/engine/input/devices/KeyboardDevice.js +7 -6
- package/src/engine/intelligence/behavior/selector/WeightedElement.js +2 -2
- package/src/engine/interpolation/Interpolated.js +2 -2
- package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
- package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +15 -2
- package/src/engine/network/CONGESTION_CONTROL.md +9 -9
- package/src/engine/network/MESSAGE_TRANSPORT.md +364 -0
- package/src/engine/network/NetworkSession.d.ts +31 -11
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +453 -286
- package/src/engine/network/README.md +77 -27
- package/src/engine/network/SMOOTHNESS_DESIGN.md +13 -5
- package/src/engine/network/diagnostics/BandwidthMeter.d.ts +1 -1
- package/src/engine/network/diagnostics/BandwidthMeter.js +1 -1
- package/src/engine/network/orchestrator/HostJoin.d.ts +111 -0
- package/src/engine/network/orchestrator/HostJoin.d.ts.map +1 -0
- package/src/engine/network/orchestrator/HostJoin.js +271 -0
- package/src/engine/network/orchestrator/NetworkPeer.d.ts +151 -112
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +450 -499
- package/src/engine/network/orchestrator/PendingSlices.d.ts +30 -0
- package/src/engine/network/orchestrator/PendingSlices.d.ts.map +1 -0
- package/src/engine/network/orchestrator/PendingSlices.js +83 -0
- package/src/engine/network/orchestrator/ReliableFrames.d.ts +34 -0
- package/src/engine/network/orchestrator/ReliableFrames.d.ts.map +1 -0
- package/src/engine/network/orchestrator/ReliableFrames.js +96 -0
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +77 -10
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +236 -61
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +20 -6
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +33 -8
- package/src/engine/network/replication/Replicator.d.ts.map +1 -1
- package/src/engine/network/replication/Replicator.js +7 -1
- package/src/engine/network/sim/ActionLog.d.ts +32 -5
- package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
- package/src/engine/network/sim/ActionLog.js +47 -5
- package/src/engine/network/sim/SimActionExecutor.d.ts +42 -2
- package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
- package/src/engine/network/sim/SimActionExecutor.js +100 -4
- package/src/engine/network/sim/Snapshotter.d.ts +12 -0
- package/src/engine/network/sim/Snapshotter.d.ts.map +1 -1
- package/src/engine/network/sim/Snapshotter.js +43 -0
- package/src/engine/network/state/Baseline.d.ts +1 -1
- package/src/engine/network/state/Baseline.js +1 -1
- package/src/engine/network/state/FrameBufferRing.d.ts +25 -6
- package/src/engine/network/state/FrameBufferRing.d.ts.map +1 -1
- package/src/engine/network/state/FrameBufferRing.js +51 -6
- package/src/engine/network/state/InputRing.d.ts +4 -0
- package/src/engine/network/state/InputRing.d.ts.map +1 -1
- package/src/engine/network/state/InputRing.js +7 -0
- package/src/engine/network/transport/DeferredTransport.d.ts.map +1 -1
- package/src/engine/network/transport/DeferredTransport.js +1 -0
- package/src/engine/network/transport/LoopbackTransport.d.ts.map +1 -1
- package/src/engine/network/transport/LoopbackTransport.js +4 -2
- package/src/engine/network/transport/Transport.d.ts +7 -0
- package/src/engine/network/transport/Transport.d.ts.map +1 -1
- package/src/engine/network/transport/Transport.js +8 -0
- package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
- package/src/engine/network/transport/adapters/NodeUDPTransport.js +20 -5
- package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.d.ts.map +1 -1
- package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.js +8 -0
- package/src/engine/network/transport/adapters/WebTransportTransport.d.ts.map +1 -1
- package/src/engine/network/transport/adapters/WebTransportTransport.js +6 -0
- package/src/engine/network/transport/connection/Connection.d.ts +191 -0
- package/src/engine/network/transport/connection/Connection.d.ts.map +1 -0
- package/src/engine/network/transport/connection/Connection.js +1262 -0
- package/src/engine/network/transport/connection/RangeSet.d.ts +94 -0
- package/src/engine/network/transport/connection/RangeSet.d.ts.map +1 -0
- package/src/engine/network/transport/connection/RangeSet.js +260 -0
- package/src/engine/network/transport/connection/RxStream.d.ts +48 -0
- package/src/engine/network/transport/connection/RxStream.d.ts.map +1 -0
- package/src/engine/network/transport/connection/RxStream.js +211 -0
- package/src/engine/network/transport/connection/TxStream.d.ts +90 -0
- package/src/engine/network/transport/connection/TxStream.d.ts.map +1 -0
- package/src/engine/network/transport/connection/TxStream.js +243 -0
- package/src/engine/network/transport/connection/bytes_copy.d.ts +17 -0
- package/src/engine/network/transport/connection/bytes_copy.d.ts.map +1 -0
- package/src/engine/network/transport/connection/bytes_copy.js +34 -0
- package/src/engine/network/transport/connection/varint.d.ts +46 -0
- package/src/engine/network/transport/connection/varint.d.ts.map +1 -0
- package/src/engine/network/transport/connection/varint.js +107 -0
- package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/Cloth.js +7 -5
- package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothCollider.js +7 -5
- package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothDynamics.js +20 -11
- package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidField.js +7 -5
- package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
- package/src/engine/physics/fluid/ecs/FluidComponent.js +19 -11
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +2 -2
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +2 -2
- package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +11 -7
- package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +11 -7
- package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/WakeFluidEffector.js +16 -9
- package/src/engine/sound/ecs/audio/AudioEmitter.d.ts +38 -7
- package/src/engine/sound/ecs/audio/AudioEmitter.d.ts.map +1 -1
- package/src/engine/sound/ecs/audio/AudioEmitter.js +47 -14
- package/src/engine/sound/ecs/audio/AudioEmitterSerializationAdapter.d.ts.map +1 -1
- package/src/engine/sound/ecs/audio/AudioEmitterSerializationAdapter.js +5 -1
- package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.d.ts +18 -0
- package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.d.ts.map +1 -0
- package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.js +48 -0
- package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts +12 -2
- package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts.map +1 -1
- package/src/engine/sound/ecs/audio/AudioEmitterSystem.js +173 -9
- package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts +9 -3
- package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts.map +1 -1
- package/src/engine/sound/ecs/audio/LiveEmitterSet.js +28 -8
- package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts +8 -0
- package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts.map +1 -1
- package/src/engine/sound/ecs/trigger/AudioEventTrigger.js +192 -191
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.d.ts.map +1 -1
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.js +5 -1
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.d.ts +18 -0
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.d.ts.map +1 -0
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.js +51 -0
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.d.ts.map +1 -1
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.js +15 -1
- package/src/engine/sound/simulation/core/AcousticMedium.js +2 -2
- package/src/engine/sound/simulation/definition/AcousticDirectivity.js +2 -2
- package/src/engine/sound/simulation/definition/AcousticMaterial.d.ts.map +1 -1
- package/src/engine/sound/simulation/definition/AcousticMaterial.js +11 -7
- package/src/engine/sound/sopra/README.md +768 -644
- package/src/engine/sound/sopra/SopraEngine.d.ts +104 -8
- package/src/engine/sound/sopra/SopraEngine.d.ts.map +1 -1
- package/src/engine/sound/sopra/SopraEngine.js +327 -12
- package/src/engine/sound/sopra/definition/BusDefinition.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/BusDefinition.js +5 -4
- package/src/engine/sound/sopra/definition/DuckingRule.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/DuckingRule.js +7 -5
- package/src/engine/sound/sopra/definition/EventDescription.d.ts +28 -2
- package/src/engine/sound/sopra/definition/EventDescription.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/EventDescription.js +77 -17
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts +10 -0
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.js +77 -55
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.d.ts +31 -0
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.d.ts.map +1 -0
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.js +75 -0
- package/src/engine/sound/sopra/definition/MixerSnapshot.js +2 -2
- package/src/engine/sound/sopra/definition/ParameterDefinition.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/ParameterDefinition.js +7 -5
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +2 -2
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.js +4 -3
- package/src/engine/sound/sopra/definition/clip/ContainerAudioClip.js +2 -2
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +3 -3
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +16 -9
- package/src/engine/sound/sopra/definition/clip/SilenceAudioClip.js +2 -2
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -1
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.js +2 -2
- package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts +38 -9
- package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.js +34 -5
- package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts +7 -2
- package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/effect/CompressorEffect.js +137 -120
- package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts +3 -1
- package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/effect/EqEffect.js +146 -128
- package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts +1 -0
- package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/effect/ReverbEffect.js +8 -3
- package/src/engine/sound/sopra/legacy/SoundEmitter.d.ts.map +1 -1
- package/src/engine/sound/sopra/legacy/SoundEmitter.js +357 -352
- package/src/engine/sound/sopra/legacy/SoundTrack.d.ts.map +1 -1
- package/src/engine/sound/sopra/legacy/SoundTrack.js +281 -278
- package/src/engine/sound/sopra/runtime/BusGraph.d.ts +44 -2
- package/src/engine/sound/sopra/runtime/BusGraph.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/BusGraph.js +83 -43
- package/src/engine/sound/sopra/runtime/EffectChain.d.ts +96 -0
- package/src/engine/sound/sopra/runtime/EffectChain.d.ts.map +1 -0
- package/src/engine/sound/sopra/runtime/EffectChain.js +286 -0
- package/src/engine/sound/sopra/runtime/EffectParamOverrides.d.ts +123 -0
- package/src/engine/sound/sopra/runtime/EffectParamOverrides.d.ts.map +1 -0
- package/src/engine/sound/sopra/runtime/EffectParamOverrides.js +320 -0
- package/src/engine/sound/sopra/runtime/EventInstance.d.ts +55 -5
- package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.js +201 -26
- package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts +2 -1
- package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts.map +1 -1
- package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.js +6 -1
- package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts +15 -0
- package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts.map +1 -1
- package/src/engine/sound/sopra/serialization/sopraSerializationHarness.js +32 -0
- package/src/engine/sound/sopra/util/MockAudioContext.d.ts.map +1 -1
- package/src/engine/sound/sopra/util/MockAudioContext.js +3 -0
- package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts +13 -3
- package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts.map +1 -1
- package/src/engine/sound/sopra/util/fadeOutAndStop.js +25 -13
- package/src/format/image/png/PNGReader.js +644 -644
- package/src/format/image/png/crc32.d.ts +1 -1
- package/src/format/image/png/crc32.js +7 -8
- package/src/shade/RENDERER_CONTRACT.md +6 -3
- package/src/shade/descriptor/binding/BindGroupLayoutDescriptor.js +2 -2
- package/src/shade/descriptor/binding/BindGroupLayoutEntry.d.ts.map +1 -1
- package/src/shade/descriptor/binding/BindGroupLayoutEntry.js +12 -8
- package/src/shade/descriptor/binding/StorageTextureBindingLayout.js +2 -2
- package/src/shade/descriptor/binding/TextureBindingLayout.js +2 -2
- package/src/shade/descriptor/blend/BlendComponent.js +2 -2
- package/src/shade/descriptor/pipeline/PipelineDescriptorBase.js +2 -2
- package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.js +2 -2
- package/src/shade/descriptor/pipeline/ProgrammableStage.js +2 -2
- package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.js +2 -2
- package/src/shade/descriptor/pipeline/render/ColorTargetState.js +2 -2
- package/src/shade/descriptor/pipeline/render/FragmentState.js +2 -2
- package/src/shade/descriptor/pipeline/render/PrimitiveState.js +2 -2
- package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.d.ts.map +1 -1
- package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.js +8 -5
- package/src/shade/descriptor/pipeline/render/VertexAttribute.js +2 -2
- package/src/shade/descriptor/texture/SamplerDescriptor.d.ts.map +1 -1
- package/src/shade/descriptor/texture/SamplerDescriptor.js +20 -12
- package/src/shade/descriptor/texture/TextureDescriptor.d.ts.map +1 -1
- package/src/shade/descriptor/texture/TextureDescriptor.js +11 -7
- package/src/shade/device/SHADE_DEVICE_FLOOR.d.ts +24 -0
- package/src/shade/device/SHADE_DEVICE_FLOOR.d.ts.map +1 -0
- package/src/shade/device/SHADE_DEVICE_FLOOR.js +34 -0
- package/src/shade/device/ShadeDeviceFailure.d.ts +12 -5
- package/src/shade/device/ShadeDeviceFailure.d.ts.map +1 -1
- package/src/shade/device/ShadeDeviceFailure.js +17 -8
- package/src/shade/device/ShadeDeviceFailureReason.d.ts +1 -1
- package/src/shade/device/ShadeDeviceFailureReason.js +2 -2
- package/src/shade/device/graph/BufferResourceDescriptor.d.ts.map +1 -1
- package/src/shade/device/graph/BufferResourceDescriptor.js +196 -193
- package/src/shade/device/graph/TextureResourceDescriptor.d.ts.map +1 -1
- package/src/shade/device/graph/TextureResourceDescriptor.js +178 -173
- package/src/shade/device/shade_device_floor_unmet.d.ts +13 -0
- package/src/shade/device/shade_device_floor_unmet.d.ts.map +1 -0
- package/src/shade/device/shade_device_floor_unmet.js +32 -0
- package/src/shade/device/timing/profile/sgpt_read_header.js +1 -1
- package/src/shade/device/timing/profile/sgpt_read_records.js +1 -1
- package/src/shade/device/timing/profile/sgpt_write_header.js +1 -1
- package/src/shade/device/timing/profile/sgpt_write_record.js +1 -1
- package/src/shade/renderer/Renderer.d.ts +2 -0
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +29 -55
- package/src/shade/renderer/binding/BufferBinding.js +2 -2
- package/src/shade/renderer/buffer/GPUBufferAllocator.d.ts.map +1 -1
- package/src/shade/renderer/buffer/GPUBufferAllocator.js +9 -0
- package/src/shade/renderer/buffer/buffer_pool_ops.d.ts +21 -12
- package/src/shade/renderer/buffer/buffer_pool_ops.d.ts.map +1 -1
- package/src/shade/renderer/buffer/buffer_pool_ops.js +18 -19
- package/src/shade/renderer/camera/Camera.js +2 -2
- package/src/shade/renderer/geometry/Attribute.js +2 -2
- package/src/shade/renderer/geometry/Geometry.js +2 -2
- package/src/shade/renderer/geometry/geometry_deduplicate_vertices.js +2 -2
- package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +2 -2
- package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_asset_id.js +13 -13
- package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_directory_block_checksum.js +41 -41
- package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_frame_checksum.js +41 -41
- package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_header_checksum.js +25 -25
- package/src/shade/renderer/gpu_primitive/test/gpu_test.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/test/gpu_test.js +8 -11
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/material/StandardShadeMaterial.d.ts.map +1 -1
- package/src/shade/renderer/material/StandardShadeMaterial.js +13 -8
- package/src/shade/renderer/pool/TransientResourcePool.d.ts +24 -0
- package/src/shade/renderer/pool/TransientResourcePool.d.ts.map +1 -1
- package/src/shade/renderer/pool/TransientResourcePool.js +41 -10
- package/src/shade/renderer/scene/optimization/geometry/internal/triangle_fingerprint_stream.d.ts.map +1 -1
- package/src/shade/renderer/scene/optimization/geometry/internal/triangle_fingerprint_stream.js +14 -5
- package/src/shade/renderer/scene/optimization/sampler2d_from_image_bitmap.js +1 -1
- package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ComputeShader.js +18 -2
- package/src/shade/renderer/shader/ImageShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ImageShader.js +230 -218
- package/src/shade/renderer/shader/type/WGSLStructField.js +2 -2
- package/src/shade/renderer/shader/type/WebGPUArray.js +2 -2
- package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/WebGPUStruct.js +9 -6
- package/src/shade/renderer/texture/ShadeTexture.d.ts.map +1 -1
- package/src/shade/renderer/texture/ShadeTexture.js +17 -10
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +2 -2
- package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +4 -4
- package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +6 -6
- package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +46 -55
- package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts +3 -3
- package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +14 -4
- package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +10 -1
- package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +82 -40
- package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +4 -1
- package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +8 -4
- package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +98 -86
- package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/shader_water_particles.js +440 -298
- package/src/view/common/HTMLElementCacheKey.d.ts.map +1 -1
- package/src/view/common/HTMLElementCacheKey.js +4 -3
- package/src/view/graphics/GraphicsContextFailureView.d.ts +1 -2
- package/src/view/graphics/GraphicsContextFailureView.d.ts.map +1 -1
- package/src/view/graphics/GraphicsContextFailureView.js +1 -2
- package/src/view/minimap/MinimapMarker.js +2 -2
- package/src/engine/network/transport/Channel.js +0 -336
- package/src/engine/network/transport/ReliableCommandPipeline.js +0 -335
- package/src/engine/network/transport/fragments/FragmentAssembler.js +0 -350
- package/src/engine/network/transport/fragments/FragmentRetention.js +0 -191
- package/src/engine/network/transport/fragments/fragment_send.js +0 -157
- package/src/engine/network/transport/fragments/packet_size.js +0 -107
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PathFollowingSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/navigation/ecs/path_following/PathFollowingSystem.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"PathFollowingSystem.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/navigation/ecs/path_following/PathFollowingSystem.js"],"names":[],"mappings":";AAyJA;;IACI,sCAA8B;IAC9B,mKAIE;IAEF;;;;OAIG;IACH,qBAAiB;IAEjB;;;;;;OAMG;IACH,6BALW,YAAY,aACZ,WAAW,QACX,IAAI,UACJ,MAAM,QA4BhB;CAgBJ;uBApNsB,wBAAwB;yBAItB,mBAAmB;4BAFhB,uCAAuC;4CAHvB,uDAAuD;iBAIlF,uBAAuB"}
|
|
@@ -4,6 +4,7 @@ import { min2 } from "../../../../core/math/min2.js";
|
|
|
4
4
|
import { ResourceAccessKind } from "../../../../core/model/ResourceAccessKind.js";
|
|
5
5
|
import { ResourceAccessSpecification } from "../../../../core/model/ResourceAccessSpecification.js";
|
|
6
6
|
import { System } from '../../../ecs/System.js';
|
|
7
|
+
import { t64_announce_change } from "../../../ecs/transform/t64_announce_change.js";
|
|
7
8
|
import { Transform64 } from '../../../ecs/transform/Transform64.js';
|
|
8
9
|
import Path from '../components/Path.js';
|
|
9
10
|
import PathFollower from './PathFollower.js';
|
|
@@ -25,11 +26,14 @@ const scratch_quaternion = new Quaternion();
|
|
|
25
26
|
* @param {Path} path
|
|
26
27
|
* @param {Transform64} transform
|
|
27
28
|
* @param {number} timeDelta
|
|
29
|
+
* @returns {boolean} whether the transform was written, which its writer then has to announce
|
|
28
30
|
*/
|
|
29
31
|
function performStep(pathFollower, path, transform, timeDelta) {
|
|
30
32
|
let remainingDistance = pathFollower.speed.getValue() * timeDelta;
|
|
31
33
|
const path_length = path.length;
|
|
32
34
|
|
|
35
|
+
let moved = false;
|
|
36
|
+
|
|
33
37
|
while (remainingDistance > 0) {
|
|
34
38
|
|
|
35
39
|
let stepLimit = pathFollower.maxMoveDistance;
|
|
@@ -138,9 +142,13 @@ function performStep(pathFollower, path, transform, timeDelta) {
|
|
|
138
142
|
position[0] = nextPosition[0];
|
|
139
143
|
position[1] = nextPosition[1];
|
|
140
144
|
position[2] = nextPosition[2];
|
|
145
|
+
|
|
146
|
+
moved = true;
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
}
|
|
150
|
+
|
|
151
|
+
return moved;
|
|
144
152
|
}
|
|
145
153
|
|
|
146
154
|
class PathFollowingSystem extends System {
|
|
@@ -177,13 +185,18 @@ class PathFollowingSystem extends System {
|
|
|
177
185
|
return;
|
|
178
186
|
}
|
|
179
187
|
|
|
180
|
-
|
|
188
|
+
const dataset = this.entityManager.dataset;
|
|
189
|
+
|
|
190
|
+
if (performStep(pathFollower, path, transform, this.__time_delta)) {
|
|
191
|
+
// a Transform64 cannot say it was written, so the writer does: this is what moves the
|
|
192
|
+
// entity's rendered row, its sound, and whatever else follows it by its transform
|
|
193
|
+
t64_announce_change(dataset, entity);
|
|
194
|
+
}
|
|
181
195
|
|
|
182
196
|
if (pathFollower.getFlag(PathFollowerFlags.Finished)) {
|
|
183
197
|
//deactivate
|
|
184
198
|
pathFollower.clearFlag(PathFollowerFlags.Active);
|
|
185
199
|
|
|
186
|
-
const dataset = this.entityManager.dataset
|
|
187
200
|
dataset.sendEvent(entity, PathFollowerEventType.EndReached);
|
|
188
201
|
}
|
|
189
202
|
}
|
|
@@ -6,14 +6,14 @@ against Valve GameNetworkingSockets (GNS), 2026-06.
|
|
|
6
6
|
|
|
7
7
|
## The gap
|
|
8
8
|
|
|
9
|
-
There is no congestion control
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
There is no congestion control on the meep-owned send path. Each peer's `Connection`
|
|
10
|
+
(`MESSAGE_TRANSPORT.md`) paces its reliable USER and BULK lanes with a token bucket at a fixed
|
|
11
|
+
rate — a ceiling, but not one that learns: loss never reduces it. The action stream, AUTH_STATE and
|
|
12
|
+
the CONTROL lane are not paced at all. `NetworkPeer.flush_outbound` packs
|
|
13
|
+
`[last_acked+1 .. current]` for every peer every tick, so under a constrained link output *rises*
|
|
14
|
+
exactly when the path sheds load (the repacked unacked frames plus reliable re-sends stack on top) —
|
|
15
|
+
classic self-inflicted bufferbloat with no AIMD backoff. The token bucket is where a governor would
|
|
16
|
+
set the rate.
|
|
17
17
|
|
|
18
18
|
GNS, by contrast, paces every packet through `SNP_TokenBucket_Accumulate` at a
|
|
19
19
|
`m_nCurrentSendRateEstimate` that is RFC3390-seeded, shrinks on loss, grows on
|
|
@@ -80,7 +80,7 @@ not the obstacle.
|
|
|
80
80
|
which bytes go out this tick and defer the rest (`BandwidthMeter` can verify
|
|
81
81
|
the achieved rate). These primitives already exist and are correct — they are
|
|
82
82
|
intentionally unwired opt-in surface, **not** dead code.
|
|
83
|
-
- Do NOT add a cipher/sliding-window or any of this to `
|
|
83
|
+
- Do NOT add a cipher/sliding-window or any of this to `Connection`'s packet layer; congestion
|
|
84
84
|
control belongs above the seq/ack layer, on the transport-facing send path.
|
|
85
85
|
|
|
86
86
|
@author Alex Goldring
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# Message transport
|
|
2
|
+
|
|
3
|
+
Status: LANDED, design record. Planned 2026-10-15, revised after two adversarial reviews of the plan (§9),
|
|
4
|
+
implemented, then reviewed adversarially again (§10). Replaced `transport/Channel.js`, `transport/fragments/*`
|
|
5
|
+
and `transport/ReliableCommandPipeline.js` with one connection layer that carries messages of any size, for
|
|
6
|
+
every message type the engine sends and for user messages.
|
|
7
|
+
|
|
8
|
+
## 1. Why
|
|
9
|
+
|
|
10
|
+
All engine traffic leaves `NetworkPeer` through one function, `#send_to_peer`. A message was one datagram, or
|
|
11
|
+
it was cut into fragments by `fragment_send.js`. That path had five independent ceilings, all measured
|
|
12
|
+
(2026-10-14, probes `zz_probe_join` / `zz_probe_wire`):
|
|
13
|
+
|
|
14
|
+
| Ceiling | Effect |
|
|
15
|
+
|---|---|
|
|
16
|
+
| `FragmentAssembler.max_message_size` 65,536 B | larger messages dropped silently: a world of 2,990 one-component entities could never be joined |
|
|
17
|
+
| uint8 chunk count, 255 × 1,186 B ≈ 302 KB | send throws; for INITIAL_SYNC on every tick forever, for a 20k-entity spawn frame every tick in `closeFixedStep` |
|
|
18
|
+
| `Channel` acks: latest + 32-bit bitfield, only on packets the receiver sends anyway | a message of 34+ fragments sent in one tick is never fully acked; its fragments age out as lost though they arrived (one spawn frame re-sent 32×) |
|
|
19
|
+
| NACK / retention timers on `performance.now()` | repair ignores the simulation clock; a spec ticking faster than wall time gets no repair |
|
|
20
|
+
| no pacing | a 447 KB snapshot leaves in one tick |
|
|
21
|
+
|
|
22
|
+
Steady-state wire cost was also poor: host → client sent `2 + owned entities` datagrams per tick (each
|
|
23
|
+
AUTH_STATE, TIME_DILATION and FRAME_MARKER its own datagram with a 9 B channel header). 16 owned entities: 17
|
|
24
|
+
datagrams, 346 B payload, 822 B on the wire with UDP/IPv4 headers.
|
|
25
|
+
|
|
26
|
+
**Measured after** (same probe, 16 owned entities): host → client 1 datagram, 237 B payload, 265 B on the wire
|
|
27
|
+
per tick (3.1× less); client → host 2 datagrams → 1. A 5,000-entity world joins over Loopback; 20,000 joins
|
|
28
|
+
paced, including while it grows by 1,000 entities a tick (`initial_sync_large_world.spec.js`).
|
|
29
|
+
|
|
30
|
+
## 2. Requirements
|
|
31
|
+
|
|
32
|
+
1. Any message type, engine or user, up to a configured size, survives loss and arrives intact.
|
|
33
|
+
2. Receiver memory per connection is bounded by configuration, never by what a peer claims; so is the
|
|
34
|
+
sender's (queues are capped; a join's pages are built only as the window frees). So is receiver time (§3.9).
|
|
35
|
+
3. What a peer can make the sender do is bounded by what the sender chose to send (README, "Connecting").
|
|
36
|
+
4. One datagram per peer per tick in steady state; per-message overhead of a few bytes.
|
|
37
|
+
5. No per-packet or per-message allocation in steady state (buffers grow to a high-watermark and stay; §4).
|
|
38
|
+
6. Every timer runs on a clock the caller supplies; the network stack never reads wall time itself.
|
|
39
|
+
7. Large transfers never delay latency-critical traffic.
|
|
40
|
+
8. The action stream keeps its contract: confirm a slice only when every packet carrying it is acked, abandon
|
|
41
|
+
it when any is lost (never credit what was not delivered).
|
|
42
|
+
|
|
43
|
+
## 3. Design
|
|
44
|
+
|
|
45
|
+
One class per peer, `Connection` (`transport/connection/`), used by `NetworkPeer` in place of `Channel` +
|
|
46
|
+
fragments + `ReliableCommandPipeline`. A message is still `[NetworkPacketType byte][payload]`; `NetworkPeer`'s
|
|
47
|
+
dispatch is unchanged except that FRAGMENT and NACK_FRAGMENT are gone, RELIABLE_COMMAND lost its logical seq,
|
|
48
|
+
INITIAL_SYNC is a page, and TIME_DILATION carries the host's frame.
|
|
49
|
+
|
|
50
|
+
### 3.1 Packet layer (after QUIC, RFC 9000 §12–13, §17.1, §19.3; RFC 9002)
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
u8 flags bit0 ACK present, bit1 4-byte packet number, bits 4–7 protocol version (1)
|
|
54
|
+
u16|u32 packet number truncated; the full number increases monotonically and is never reused
|
|
55
|
+
[ACK] varint largest acknowledged (full number)
|
|
56
|
+
varint ack delay (8 µs units)
|
|
57
|
+
varint additional range count (≤ 63)
|
|
58
|
+
varint first range
|
|
59
|
+
count × (varint gap, varint range length)
|
|
60
|
+
frames to the end of the datagram
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- **Packet numbers are never reused**; a retransmission is new frames in a new packet. Encoded in 2 bytes while
|
|
64
|
+
`number − largest acknowledged < 16,384`, else 4 (RFC 9000 §17.1), expanded by Appendix A.3.
|
|
65
|
+
- **Acks are ranges**: one ACK covers any burst. The receiver tracks at most `max_ack_ranges` (32, at most 64);
|
|
66
|
+
everything below its floor is dropped as a duplicate or too old. The floor rises when an ACK frame of its own
|
|
67
|
+
is acknowledged (§13.2.4) or when the oldest range is pushed out by the cap. A side that sends only ACKs adds
|
|
68
|
+
a PING once per RTT so that it ever hears which ACKs arrived. The ACK takes at most half a datagram; ranges
|
|
69
|
+
that do not fit wait for a later ACK.
|
|
70
|
+
- **Loss** (RFC 9002 §6.1): packet threshold 3, time threshold `9/8 × max(srtt, latest_rtt)`, floored at the
|
|
71
|
+
timer granularity. **Lost means not confirmed**, as in QUIC: a packet that arrived but whose acknowledgement
|
|
72
|
+
never got through — every ACK carrying it lost, or crowded out by newer ranges past `max_ack_ranges` holes —
|
|
73
|
+
is reported lost. The action stream's contract (requirement 8) is exactly this: never credit the unconfirmed.
|
|
74
|
+
- **Probe timeout** (§6.2) doubles per expiry. On expiry the oldest outstanding packet whose reliable bytes are
|
|
75
|
+
still unacknowledged has them queued again (never declared lost); a packet whose bytes were all acknowledged
|
|
76
|
+
by another — the one it re-sent, an earlier probe — is passed over; with none, a PING. A probe may pass an
|
|
77
|
+
empty token bucket once.
|
|
78
|
+
- **Notices are deferred.** `onMessageAcked` / `onMessageLost` are told after the walk that settled them —
|
|
79
|
+
the end of a flush, or of an ACK's processing — never in the middle of one. A handler may send, flush
|
|
80
|
+
(which tells the rest, in order) or dispose (after which nothing more is told).
|
|
81
|
+
- **RTT** from ack delay, clamped to `max_ack_delay`; Karn-free since numbers are never reused.
|
|
82
|
+
- **Timer granularity and `max_ack_delay` are one tick.** All sends and receives happen at fixed-step
|
|
83
|
+
boundaries, so nothing finer is real.
|
|
84
|
+
- **Validation before action.** A datagram is parsed whole before any of it is acted on; a malformed one is
|
|
85
|
+
dropped unacknowledged (`onMalformedDatagram`). An ACK naming a packet never sent is a protocol error (§3.9).
|
|
86
|
+
- **Transports that are already reliable** (`transport.reliable`: WebSocket) never declare loss and never
|
|
87
|
+
probe: on TCP a re-send queues behind the original and makes a stall worse. Loopback is *not* reliable: its
|
|
88
|
+
`drop_next` loses packets, and the specs need the loss path.
|
|
89
|
+
- **Datagram size per transport**: `Transport.max_datagram_bytes`, in [64, 16,383]. 1,200 by default; WebRTC
|
|
90
|
+
1,150 so a full datagram fits one SCTP packet (§8); WebTransport reads `datagrams.maxDatagramSize` once.
|
|
91
|
+
|
|
92
|
+
### 3.2 Messages
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
0x01 MESSAGE varint length, bytes unreliable, at most one datagram
|
|
96
|
+
0x02 PING asks for an ACK
|
|
97
|
+
0x10|lane varint offset, varint length, bytes STREAM, reliable lane 0..3
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Unreliable messages fit one datagram** (1,192 B at the default size). There is no segmented unreliable tier:
|
|
101
|
+
a segmented message evicted from reassembly after its packets were acked would be credited by the action
|
|
102
|
+
stream without being applied — exactly the old fragment-eviction defect. Larger is refused (throws); a caller
|
|
103
|
+
with more goes reliable. Each carries an optional token, and the connection reports `acked(token)` or
|
|
104
|
+
`lost(token)` with its packet, exactly once. When the ACK opening a flush leaves too little room for the
|
|
105
|
+
largest message, the ACK goes alone.
|
|
106
|
+
|
|
107
|
+
**Reliable lanes**, after QUIC streams: each lane is an ordered byte stream of `[varint length][bytes]`.
|
|
108
|
+
- Sender: the message is copied once into the lane's buffer; segments are ranges of it; each packet records the
|
|
109
|
+
ranges it carried; a lost range is queued again minus anything acknowledged since. Bytes are released when
|
|
110
|
+
room is needed, not per ack (a large message's tail is not slid down once per packet).
|
|
111
|
+
- **Flow control without frames**: a sender never sends a byte at or past `acked_prefix + receive_window`. The
|
|
112
|
+
receiver delivers each message the moment its bytes are contiguous, so its contiguous point is never behind
|
|
113
|
+
the sender's acked prefix, and what it holds is at most `max_message_bytes + receive_window`. This holds only
|
|
114
|
+
if both ends use the same `max_message_bytes` and `receive_window_bytes`; a segment past the receiver's bound,
|
|
115
|
+
a message declaring more than its maximum, or more holes than an honest sender makes (§3.9) is a **protocol
|
|
116
|
+
error that ends the connection** (QUIC's FLOW_CONTROL_ERROR), never a silent drop of acknowledged data.
|
|
117
|
+
- **Queue cap**: `max_queued_bytes` per lane; `send_reliable` throws past it.
|
|
118
|
+
- **Delivery mark**: `send_reliable` returns the offset past the message; `is_delivered(lane, mark)` asks
|
|
119
|
+
whether the acked prefix has reached it.
|
|
120
|
+
|
|
121
|
+
Lanes, in scheduling order:
|
|
122
|
+
|
|
123
|
+
| Lane | Carries | Paced |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| CONTROL | RESUME_HELLO/ACCEPT/REJECT, DISCONNECT, RECOVERY_REQUEST — engine-only, one datagram each | no |
|
|
126
|
+
| (unreliable) | ACTION_STREAM slices, AUTH_STATE, TIME_DILATION, FRAME_MARKER | no |
|
|
127
|
+
| FRAMES | action-stream frames larger than a datagram | no — the stream waits on them |
|
|
128
|
+
| USER | `send_reliable_command`, up to `max_message_bytes` | yes |
|
|
129
|
+
| BULK | INITIAL_SYNC pages, STATE_BURST | yes |
|
|
130
|
+
|
|
131
|
+
### 3.3 Scheduler
|
|
132
|
+
|
|
133
|
+
Every message for a peer is queued; `flush` sends them packed into as few datagrams as fit, in the order above,
|
|
134
|
+
the ACK in the first datagram. A token bucket per connection at `send_rate_bytes_per_second` (default 256 KiB/s)
|
|
135
|
+
paces USER and BULK; unpaced traffic is counted against it and may take it at most one burst below zero. The
|
|
136
|
+
burst is two ticks of rate (at least two datagrams). Paced lanes always get at least one datagram a flush, so a
|
|
137
|
+
peer that owns many entities cannot starve a join. Congestion control, when built (`CONGESTION_CONTROL.md`),
|
|
138
|
+
sets the rate; transport backpressure (`bufferedAmount`) is a follow-up.
|
|
139
|
+
|
|
140
|
+
**When things go out.** `NetworkPeer.send_*` only queue. `NetworkPeer.send_queued()` flushes every connection.
|
|
141
|
+
`NetworkPeer.end_tick`, `ServerAuthoritativeServer.end_tick` (after `onTickComplete`) and
|
|
142
|
+
`ServerAuthoritativeClient.end_tick` call it last, so one tick's traffic — the action stream, AUTH_STATE,
|
|
143
|
+
TIME_DILATION, join pages; the client's FRAME_MARKER, queued before `end_tick` — leaves in one flush. A send
|
|
144
|
+
outside a tick is flushed where it is made: RESUME_HELLO by `connect()`, a kick's last word by the kick.
|
|
145
|
+
`flush_outbound` only queues.
|
|
146
|
+
|
|
147
|
+
**Closing.** `disconnect_peer` never sends. An explicit close (`drop_peer`, `disconnect`, a kick) calls
|
|
148
|
+
`NetworkPeer.flush_peer(id)` after queueing DISCONNECT and tears down in `finally`: one best-effort datagram.
|
|
149
|
+
A transport that has already died is never flushed. Teardown from inside a connection's own dispatch is safe:
|
|
150
|
+
the receive loop stops at the first message after disposal.
|
|
151
|
+
|
|
152
|
+
### 3.4 Clock
|
|
153
|
+
|
|
154
|
+
`NetworkPeer` takes a required `clock: () => number` (ms) and `tick_period_ms`. `NetworkSession` passes its own
|
|
155
|
+
`#clock_ms`, the render-paced clock that already drives timeouts, grace and reconnects: one clock, and the fixed
|
|
156
|
+
steps of one update all see the same time, so a burst of catch-up steps cannot age packets whose acks could not
|
|
157
|
+
have arrived.
|
|
158
|
+
|
|
159
|
+
### 3.5 What moved where
|
|
160
|
+
|
|
161
|
+
| Message | Before | After |
|
|
162
|
+
|---|---|---|
|
|
163
|
+
| ACTION_STREAM slice ≤ datagram | own datagram + notice | unreliable message + notice, coalesced |
|
|
164
|
+
| ACTION_STREAM frame > datagram | fragments, ≤ 64 KiB, 33-window | FRAMES, reliable, once (§3.6) |
|
|
165
|
+
| AUTH_STATE, TIME_DILATION, FRAME_MARKER | own datagram each | unreliable, coalesced; AUTH_STATE > datagram throws |
|
|
166
|
+
| RECOVERY_REQUEST, RESUME_*, DISCONNECT | unreliable datagram | CONTROL |
|
|
167
|
+
| STATE_BURST | fragments | BULK |
|
|
168
|
+
| INITIAL_SYNC | one message ≤ 64 KiB, sent twice | lazily built pages on BULK, catch-up rounds, then FINAL (§3.7) |
|
|
169
|
+
| RELIABLE_COMMAND | `ReliableCommandPipeline`, ≤ 1,178 B | USER, ≤ `max_message_bytes` |
|
|
170
|
+
|
|
171
|
+
### 3.6 Oversized action-stream frames
|
|
172
|
+
|
|
173
|
+
A frame whose group does not fit one datagram goes on FRAMES, unpaced, once, keeping the head flag it was
|
|
174
|
+
packed with. While it is in flight the pack skips it and sends what follows as further slices, which the
|
|
175
|
+
receiver holds until it lands; it does not stall the stream. It is credited when delivered, like any slice,
|
|
176
|
+
through `#credit_confirmed`. Unpaced because the action stream cannot outlast the 32-frame ring: a frame that
|
|
177
|
+
takes longer to deliver than the ring holds loses the frames after it.
|
|
178
|
+
|
|
179
|
+
A frame larger than `max_message_bytes` can never be delivered. Once it is the pack start it is given up and
|
|
180
|
+
said so (`NetworkPeer.onFrameTooLarge(peer_id, frame_start, frame_end, bytes)`), credited, and the stream goes
|
|
181
|
+
on behind it — never a throw, which would stop the tick for every peer.
|
|
182
|
+
|
|
183
|
+
### 3.7 Joining a world of any size
|
|
184
|
+
|
|
185
|
+
Host, per joining peer (`orchestrator/HostJoin.js`):
|
|
186
|
+
1. **Hold** the peer's action stream (`hold_outbound`); skip its AUTH_STATE.
|
|
187
|
+
2. **First round.** At the first tick, collect the networked entities. If the whole world fits
|
|
188
|
+
`JOIN_FINAL_ROUND_BYTES` (256 KiB) and the lane's room, it goes in that tick and the round is the last:
|
|
189
|
+
every entity is at the same frame. Otherwise pages of whole entities (`JOIN_PAGE_BYTES`, 16 KiB; a bigger
|
|
190
|
+
entity is a page by itself) are built only as BULK's window (128 KiB for a join) frees, each at the current
|
|
191
|
+
frame, noting each entity's frame sent. Host memory per joiner: the window plus 12 bytes per entity (its
|
|
192
|
+
frame sent, and its place in the list).
|
|
193
|
+
3. **Catch-up rounds.** When every page is delivered, compare each networked entity's last-changed frame
|
|
194
|
+
(`NetworkPeer.last_changed_frame`, stamped for everything its executor executes or records — a
|
|
195
|
+
direct write reported with `net_mutate_component` included; a write nobody reports is not a
|
|
196
|
+
change the join can know of) with the frame its state
|
|
197
|
+
was sent; entities changed since, or created since, go out as a round at the current frame. A catch-up
|
|
198
|
+
round always tries to finish in its tick, with what BULK may still hold (`max_queued_bytes − unacked −
|
|
199
|
+
max_message_bytes`) as its budget: what changed while a world went out is a fraction of it, and a round
|
|
200
|
+
that may only page would never shrink for a world that changes faster than a tick's budget.
|
|
201
|
+
4. **Release.** A round that finishes in its tick leaves the client with the whole world at that frame D: every
|
|
202
|
+
entity it carries is at D, every entity it leaves out unchanged since its state went out. The FINAL page
|
|
203
|
+
(frame D) goes after it, and the peer's stream is released from D + 1 (still in the ring — the next frame).
|
|
204
|
+
The join is over once FINAL is *delivered*: until then a peer that drops holds part of a world and is synced
|
|
205
|
+
afresh rather than resumed.
|
|
206
|
+
5. **Bounded.** At most `JOIN_MAX_ROUNDS` (8) rounds; a join that has not converged is dropped
|
|
207
|
+
(`join_did_not_converge`). Pages are only built as the window frees, so a peer that never acknowledges costs
|
|
208
|
+
the window and nothing else.
|
|
209
|
+
|
|
210
|
+
Client:
|
|
211
|
+
- From `connect()` until its binding's answer is whole, the client **holds inbound** action stream and
|
|
212
|
+
AUTH_STATE (`hold_inbound`): a stream that overtakes the pages is about a world the client does not hold yet.
|
|
213
|
+
Bounded by `max_queued_bytes`; past it the connection is broken (§3.9) and the client joins again.
|
|
214
|
+
- The FIRST page issues the token, seeks the frame counter, clears prediction state and forgets the timeline,
|
|
215
|
+
and puts the binding in **Syncing**, which counts as the binding's answer: a later RESUME_ACCEPT/REJECT is
|
|
216
|
+
stale, the reconnect ladder stops.
|
|
217
|
+
- Each page is applied as it lands (creating entities as INITIAL_SYNC did).
|
|
218
|
+
- FINAL seeks again, repeats the clears and `forget_timeline` (prediction ran on a partial world meanwhile),
|
|
219
|
+
sets the world start frame, releases outbound, and makes the binding **Synced**. The held inbound is applied
|
|
220
|
+
once the step's inbound is done (not inside the page's dispatch, which shares the receive buffer), then
|
|
221
|
+
`NetworkSession.onSynced` fires. RESUME_ACCEPT releases the hold the same way.
|
|
222
|
+
- **Seeking.** A page's frame can be old when it lands — a late FINAL — so the client seeks to
|
|
223
|
+
`max(page frame, host frame seen) + 1 + depth`, where the host's frame comes with every TIME_DILATION.
|
|
224
|
+
|
|
225
|
+
### 3.8 Deleted
|
|
226
|
+
|
|
227
|
+
`Channel.js`, `ReliableCommandPipeline.js`, `fragments/*`, FRAGMENT / NACK_FRAGMENT, `NetworkPeer.channel_for`
|
|
228
|
+
(now `connection_for`), `#pending_initial_sync`'s resend count. Hard break, no shims.
|
|
229
|
+
|
|
230
|
+
### 3.9 Trust, and a connection that breaks
|
|
231
|
+
|
|
232
|
+
The connection does not authenticate datagrams; its transport delivers only the peer's. WebRTC (DTLS) and
|
|
233
|
+
WebTransport / WebSocket (TLS) do; `NodeUDPTransport` drops datagrams from any source but its remote (by port
|
|
234
|
+
alone when the remote is a host name); Loopback and Simulated are in-process. Before this was stated, one stray
|
|
235
|
+
datagram numbered ahead of the peer's wedged a connection for good: the receiver acknowledged it, and the
|
|
236
|
+
sender dropped every datagram carrying that ACK, silently (measured: 0 of 300 messages through, for a stray
|
|
237
|
+
1,000 ahead or 2^30 ahead).
|
|
238
|
+
|
|
239
|
+
`Connection.onProtocolError` says the connection is no longer whole:
|
|
240
|
+
- a reliable lane broke its limits (past the window, a message over `max_message_bytes`, a bad length);
|
|
241
|
+
- more than `max(1,024, window / 256)` holes held out of order on a lane: an honest sender's holes are packets
|
|
242
|
+
it lost and has not re-sent, a few hundred at most in a 256 KiB window, while a peer sending one-byte
|
|
243
|
+
segments two bytes apart had the receiver spend 46 ms a datagram at 512k ranges (measured; now refused after
|
|
244
|
+
6 datagrams, the worst taking 1.5 ms; ranges are added by binary search);
|
|
245
|
+
- the peer acknowledged a packet this side never sent: it took in a datagram that was not ours.
|
|
246
|
+
|
|
247
|
+
`NetworkPeer.onProtocolError` adds the client's inbound hold overflowing (§3.7). `NetworkSession` handles
|
|
248
|
+
every one as a dropped transport and closes the transport so the other end hears of it at once: on the host
|
|
249
|
+
the peer goes into the grace window; on the client the reconnect ladder resumes on a new connection. A stray
|
|
250
|
+
datagram on either side now costs a resume (the specs allow 30 ticks), where it cost the connection.
|
|
251
|
+
|
|
252
|
+
## 4. Allocation and copies
|
|
253
|
+
|
|
254
|
+
- Outbound: unreliable bytes are copied once into a staging buffer, reliable bytes once into the lane buffer, and
|
|
255
|
+
from either straight into the datagram. The transport's own copy is the last.
|
|
256
|
+
- Inbound: a datagram is parsed in place; an unreliable message is dispatched as a view into it; stream bytes are
|
|
257
|
+
copied once into the lane's receive buffer and dispatched as a view.
|
|
258
|
+
- Per-packet state is struct-of-arrays (packet table, record ring, notice queue) grown to a high-watermark.
|
|
259
|
+
- `NetworkPeer`'s per-slice `PendingAck` objects are a typed-array pool keyed by token (`PendingSlices`).
|
|
260
|
+
- Copies go through `bytes_copy`: a loop up to 64 bytes, `set` over a `subarray` view past that. Measured (Node
|
|
261
|
+
22): the loop costs ~1.2 ns a byte, the view 50–70 ns flat, so a loop for all sizes made 1 KB copies 20×
|
|
262
|
+
slower. Two connections exchanging ten tokened messages a tick plus ACKs, 200k ticks: with `subarray` on every
|
|
263
|
+
copy, 236 scavenges at 100 B messages; now 13 at 20 B, 212 at 100 B and 226 at 1,000 B, where each copy is one
|
|
264
|
+
short-lived view.
|
|
265
|
+
|
|
266
|
+
## 5. Phases
|
|
267
|
+
|
|
268
|
+
All landed: **P1** Connection; **P2** NetworkPeer on Connection, old layers deleted; **P3** oversized frames,
|
|
269
|
+
the join, resume/disconnect paths, forest specs; **P4** README "Connecting", the packet table, this record.
|
|
270
|
+
|
|
271
|
+
## 6. Defaults
|
|
272
|
+
|
|
273
|
+
| Option | Default | Why |
|
|
274
|
+
|---|---|---|
|
|
275
|
+
| `send_rate_bytes_per_second` | 262,144 | GNS's default clamp; a 447 KB join in ~1.8 s |
|
|
276
|
+
| `max_message_bytes` | 1 MiB | largest USER/BULK/FRAMES message; pages are far smaller |
|
|
277
|
+
| `receive_window_bytes` | 256 KiB | ≥ rate × 1 s RTT, so the window never limits the paced rate |
|
|
278
|
+
| `max_queued_bytes` | 4 MiB per lane | a lane this far behind is a peer that is gone |
|
|
279
|
+
| `max_ack_ranges` | 32 (≤ 64) | QUIC implementations keep a few dozen |
|
|
280
|
+
| `JOIN_PAGE_BYTES` | 16 KiB | small enough that a page is one tick of rate |
|
|
281
|
+
| `JOIN_FINAL_ROUND_BYTES` | 256 KiB | a first round this size finishes in one tick |
|
|
282
|
+
| `JOIN_MAX_ROUNDS` | 8 | a join that needs more is a world changing faster than a peer can be sent it |
|
|
283
|
+
|
|
284
|
+
## 7. Not in scope
|
|
285
|
+
|
|
286
|
+
Congestion control and transport backpressure; encryption, handshakes and anti-spoofing tokens (§3.9 states
|
|
287
|
+
what is assumed of transports); level-baseline identity; the open action-stream issues in
|
|
288
|
+
`netcode-open-defects` (silent watermark skip at `max_packets_per_tick = 1`, silent loss past the ring floor).
|
|
289
|
+
|
|
290
|
+
## 8. Open
|
|
291
|
+
|
|
292
|
+
Stated, not measured:
|
|
293
|
+
- A client that spawns networked entities locally *during* a join can take a network id a later page carries.
|
|
294
|
+
Clients pre-build pools before connecting (GAP-038); spawning mid-join is not guarded.
|
|
295
|
+
- The WebRTC datagram size (1,150) is from Chrome's source as remembered, not a device measurement.
|
|
296
|
+
- A stray from the remote's own address and port — a previous connection's packet on a reused socket pair — is
|
|
297
|
+
not filtered by `NodeUDPTransport`; it costs a resume (§3.9), and a lower-numbered one can mark a lost packet
|
|
298
|
+
acknowledged. A connection id would close it.
|
|
299
|
+
|
|
300
|
+
From the implementation review, kept open (§10):
|
|
301
|
+
- **I5** An oversized non-head frame behind a frame lost past the ring floor is never applied while the stream
|
|
302
|
+
stays quiet. The same class as the ring-floor loss in §7.
|
|
303
|
+
- **I7** A tokenless reconnect after an incomplete join is refused (NoSessionToken). Tokenless claims are
|
|
304
|
+
refused on purpose: they are what an id-squatter looks like.
|
|
305
|
+
|
|
306
|
+
Measured in passing: 1,500 entities created a tick outrun the action stream itself (the forest spec runs 1,000);
|
|
307
|
+
not a join defect.
|
|
308
|
+
|
|
309
|
+
## 9. Plan review dispositions
|
|
310
|
+
|
|
311
|
+
Protocol review (R1) and integration review (R2) of the plan, 2026-10-15.
|
|
312
|
+
|
|
313
|
+
| # | Finding | Disposition |
|
|
314
|
+
|---|---|---|
|
|
315
|
+
| R1.1, R2.8 | segmented unreliable message evicted after its packets were acked is credited | **removed the tier**: unreliable ≤ one datagram |
|
|
316
|
+
| R1.2 | 16-bit packet numbers wrap under a silent peer; ring overwrites live entries | 2/4-byte encoding by distance; packet table grows, never wraps; ACK of an unsent number refused (now a protocol error, §3.9) |
|
|
317
|
+
| R1.3, R2.13 | steps × period clock: catch-up steps fake losses; RTT quantised | session `#clock_ms`; granularity and `max_ack_delay` one tick |
|
|
318
|
+
| R1.4 | probe timeout without backoff, behind the bucket | doubles per expiry; one probe passes an empty bucket; never declares loss |
|
|
319
|
+
| R1.5 | frameless flow control assumes matching config | violation is a connection-ending protocol error, documented; no silent drop |
|
|
320
|
+
| R1.6, R2.10 | unbounded queues; unpaced traffic starves BULK; user messages unpaced | per-lane queue cap; bucket floor; paced lanes get ≥ 1 datagram a flush; USER lane paced |
|
|
321
|
+
| R1.7, R2.3 | frozen snapshot = world-sized memory per joiner; ledger missing, retention-bound, empty-burst deadlock | **lazy pages + per-entity change stamps**; no ledger; catch-up as pages; FINAL page even when nothing changed |
|
|
322
|
+
| R1.8 | one code path misbehaves on TCP | reliable transports never declare loss or probe |
|
|
323
|
+
| R1.9 | 1,200 B datagram = two SCTP packets on WebRTC | WebRTC declares 1,150 (§8) |
|
|
324
|
+
| R1.10, R2.2 | oversized frame behind BULK; stall past ring; re-pack re-sends it | FRAMES lane ahead of paced lanes, unpaced; skipped while in flight |
|
|
325
|
+
| R1.11 | ack-only side can never prune ranges | PING once per RTT in ack-only packets; floor rule stated |
|
|
326
|
+
| R1.12 | ACK frames unvalidated | range count ≤ 63, numbers < next sent, delay clamped |
|
|
327
|
+
| R1.13 | no version | 4-bit version in every datagram; anti-spoofing out of scope (§7) |
|
|
328
|
+
| R1.14 | burst of 22 datagrams | burst = two ticks of rate |
|
|
329
|
+
| R1.15 | exactly one outcome per packet | first wins; a late ACK of a lost packet is ignored |
|
|
330
|
+
| R2.1 | paged join is not the binding's answer; ladder restarts it; stale reject acted on | **Syncing** binding state on page 0 |
|
|
331
|
+
| R2.4 | page-by-page apply breaks clear-on-sync | clears and `forget_timeline` repeated at FINAL; host holds AUTH_STATE until release |
|
|
332
|
+
| R2.5 | id collision from client spawns mid-join | stated (§8) |
|
|
333
|
+
| R2.6 | flush placement; spec breaks | single flush at the end of each `end_tick`; FRAME_MARKER queued before it |
|
|
334
|
+
| R2.7 | flushing in `disconnect_peer` sends on dead transports | `disconnect_peer` never sends; explicit `flush_peer` on explicit close only |
|
|
335
|
+
| R2.9 | peer withholds BULK acks to make the host re-serialize forever | at most 8 rounds; pages only as the window frees |
|
|
336
|
+
| R2.11 | resume accepted over a half-applied world | incomplete join → StaleFrame, fresh sync |
|
|
337
|
+
| R2.12 | release checked outside the flush that applies it | release from D + 1, the next frame, by construction |
|
|
338
|
+
| R2.14 | forest spec budget too small for the default rate | spec budget states the rate |
|
|
339
|
+
| R2.15 | README contradictions | P4 |
|
|
340
|
+
|
|
341
|
+
## 10. Implementation review dispositions
|
|
342
|
+
|
|
343
|
+
Connection review (C) and peer/session integration review (I) of the implementation, 2026-10-15. Each fix was
|
|
344
|
+
pinned by a spec that failed first.
|
|
345
|
+
|
|
346
|
+
| # | Finding | Disposition |
|
|
347
|
+
|---|---|---|
|
|
348
|
+
| C1 | one stray datagram wedges the connection for good | ACK of an unsent packet is a protocol error; session resumes on a new connection; NodeUDP filters by source (§3.9) |
|
|
349
|
+
| C2 | `flush` throws `RangeError` for a full-size unreliable message when an ACK is owed | the ACK goes alone |
|
|
350
|
+
| C3 | a handler flushing from an ACK notice made acked messages report lost (23 of 200) | notices deferred to the end of the walk |
|
|
351
|
+
| C4 | `dispose()` in `onMessageLost` did not stop the walk; later notices still told | deferred notices stop at dispose |
|
|
352
|
+
| C5 | a probe whose bytes were acked elsewhere sent nothing; a tail loss then never recovered (> 1 h) | probes pass over such packets; PING when none has bytes |
|
|
353
|
+
| C6 | one-byte segments two bytes apart: 46 ms a datagram at 512k ranges | hole cap, protocol error; binary-search insert |
|
|
354
|
+
| C7 | delivered messages reported lost past `max_ack_ranges` holes | lost = not confirmed, documented (§3.1); the action stream's contract |
|
|
355
|
+
| C8 | `max_ack_ranges` above 64 made the peer reject every ACK | asserted ≤ 64 |
|
|
356
|
+
| I1 | actions arriving before the FIRST page applied to the old world | inbound held from `connect()` |
|
|
357
|
+
| I2 | a frame over `max_message_bytes` threw every tick, for every peer | given up, `onFrameTooLarge` |
|
|
358
|
+
| I3 | join counted complete when FINAL was queued, not delivered | FINAL_SENT until delivered |
|
|
359
|
+
| I4 | a world changing more than 256 KiB a round could never be joined | catch-up budget is the lane's room |
|
|
360
|
+
| I5 | non-head oversized frame behind a frame lost past the ring floor | open (§8) |
|
|
361
|
+
| I6 | inbound-hold overflow dropped acknowledged frames silently | protocol error; session wiring (§3.9) |
|
|
362
|
+
| I7 | tokenless reconnect after an incomplete join refused | open, by design (§8) |
|
|
363
|
+
| I8 | `release_inbound` ran inside the INITIAL_SYNC dispatch | released after the step's inbound (with I1) |
|
|
364
|
+
| — | `subarray` views were 2.3 of 2.5 KB a tick of the layer's allocation | `bytes_copy` (§4) |
|
|
@@ -71,8 +71,17 @@ export const NetworkSessionReconcile: Readonly<{
|
|
|
71
71
|
*
|
|
72
72
|
* Replication is component-driven: attaching a {@link NetworkIdentity}
|
|
73
73
|
* to an entity registers it with the session via an `EntityObserver`.
|
|
74
|
-
*
|
|
75
|
-
*
|
|
74
|
+
*
|
|
75
|
+
* **What travels is what goes through the action executor**, and nothing
|
|
76
|
+
* else: actions (`send`, a client's input), and direct writes their writer
|
|
77
|
+
* reports — `dataset.sendEvent(entity, "net_mutate_component", payload)`.
|
|
78
|
+
* The session never looks for changes by itself. That is what keeps a tick's
|
|
79
|
+
* cost in what changed and what is owned, never in the size of the world;
|
|
80
|
+
* the stack is built for worlds of millions of networked objects. A
|
|
81
|
+
* replicated component written directly and not reported stays where it was
|
|
82
|
+
* written. Ownership is set when an identity attaches, or by the join, and
|
|
83
|
+
* `owner_peer_id` / `network_id` are not written afterwards. The README's
|
|
84
|
+
* "What the session assumes" has the whole contract and its measured costs.
|
|
76
85
|
*
|
|
77
86
|
* **The session runs on the engine's clock.** The `EntityManager`'s fixed
|
|
78
87
|
* step is the network tick: each step opens a network frame before any
|
|
@@ -155,12 +164,6 @@ export class NetworkSession {
|
|
|
155
164
|
* - `reconnect` (client role): policy for the reconnect ladder. See
|
|
156
165
|
* {@link DEFAULT_RECONNECT_POLICY}. Set `enabled: false` to opt
|
|
157
166
|
* out entirely.
|
|
158
|
-
* - `publish_changes` (host role, default true): at the end of every
|
|
159
|
-
* step, send each replicated component the simulation changed — physics,
|
|
160
|
-
* controllers, anything that wrote it directly. Components an action
|
|
161
|
-
* wrote are already on the wire and are not sent twice. Publishing never
|
|
162
|
-
* writes back into the host's own state. Set false to publish by hand
|
|
163
|
-
* (`net_mutate_component`).
|
|
164
167
|
* - `reconcile` (client role): see {@link NetworkSessionReconcile}. Default
|
|
165
168
|
* `'correct'`.
|
|
166
169
|
* - `late_input` (host role): what to do with client input that arrives
|
|
@@ -168,7 +171,7 @@ export class NetworkSession {
|
|
|
168
171
|
* `'apply'`: fold it into the current frame. `'rollback'` rewinds and
|
|
169
172
|
* replays, which re-executes actions only, never the engine's systems.
|
|
170
173
|
*/
|
|
171
|
-
constructor({ entity_manager, transport, transport_factory, role, local_peer_id, simulation_delay_ticks, tick_rate_hz, frame_capacity, binary_registry, scope_filter, time_dilation, adaptive_render_delay, server_resume_grace_ms, connection_timeout_ms, reconnect,
|
|
174
|
+
constructor({ entity_manager, transport, transport_factory, role, local_peer_id, simulation_delay_ticks, tick_rate_hz, frame_capacity, binary_registry, scope_filter, time_dilation, adaptive_render_delay, server_resume_grace_ms, connection_timeout_ms, reconnect, late_input, reconcile, }?: {
|
|
172
175
|
entity_manager: EntityManager;
|
|
173
176
|
transport?: object;
|
|
174
177
|
transport_factory?: (() => object);
|
|
@@ -260,6 +263,13 @@ export class NetworkSession {
|
|
|
260
263
|
* @type {Signal}
|
|
261
264
|
*/
|
|
262
265
|
onReconnected: Signal;
|
|
266
|
+
/**
|
|
267
|
+
* Client: a join has completed — the host's FINAL page has landed, every networked entity's
|
|
268
|
+
* state is here, and from now on this client's input is sent. No arguments. A world is sent
|
|
269
|
+
* as pages over as many ticks as its size takes; until this fires it is still arriving.
|
|
270
|
+
* @type {Signal}
|
|
271
|
+
*/
|
|
272
|
+
onSynced: Signal;
|
|
263
273
|
/**
|
|
264
274
|
* Client: the reconnect ladder is exhausted, or the host explicitly
|
|
265
275
|
* kicked us with a DISCONNECT packet, or `reconnect.enabled` is
|
|
@@ -400,7 +410,7 @@ export class NetworkSession {
|
|
|
400
410
|
/**
|
|
401
411
|
* Wire the session to the engine. After this, the EntityObserver
|
|
402
412
|
* is active, the right orchestrator is constructed, and a
|
|
403
|
-
* {@link NetworkSystem} is attached. Subsequent `replicate_*`
|
|
413
|
+
* {@link NetworkSystem} is attached until {@link stop}. Subsequent `replicate_*`
|
|
404
414
|
* / {@link defineAction} / {@link defineInputSampler} calls throw.
|
|
405
415
|
*
|
|
406
416
|
* Pre-condition: every replicated component class must already have a
|
|
@@ -464,8 +474,18 @@ export class NetworkSession {
|
|
|
464
474
|
disconnect(reason?: string): void;
|
|
465
475
|
/**
|
|
466
476
|
* Tear down. Idempotent — safe to call from cleanup paths.
|
|
477
|
+
*
|
|
478
|
+
* Takes back from the engine what {@link start} put in it: the {@link NetworkSystem} is out of
|
|
479
|
+
* the engine's loop when this returns, so another session can start on the same engine; this one
|
|
480
|
+
* does not start again. The
|
|
481
|
+
* networked entities stay in the world, and their `network_id`s are released — an id means
|
|
482
|
+
* nothing without the session that gave it. The {@link InterpolationSystem} stays too, whoever
|
|
483
|
+
* added it: it is the engine's, and blends whatever else is interpolated; the session only
|
|
484
|
+
* withdraws its own source from it.
|
|
485
|
+
*
|
|
486
|
+
* @returns {Promise} resolves once the engine has shut the {@link NetworkSystem} down
|
|
467
487
|
*/
|
|
468
|
-
stop():
|
|
488
|
+
stop(): Promise<any>;
|
|
469
489
|
/**
|
|
470
490
|
* **Deprecated; does nothing.** The session used to run its own fixed-step clock here, next to
|
|
471
491
|
* the engine's: two clocks, so network frame N and the engine's step N were unrelated, and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkSession.d.ts","sourceRoot":"","sources":["../../../../src/engine/network/NetworkSession.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;iCA6CoB,MAAM;AAhB1B;;;;;;;;;;;;;;;;;GAiBG;AACH;;;GAGG;;;;sCAKiB,MAAM;AAH1B;;;;GAIG;AACH;IACI;;;;;;;OAOG;;IAEH;;;;OAIG;;GAEJ;
|
|
1
|
+
{"version":3,"file":"NetworkSession.d.ts","sourceRoot":"","sources":["../../../../src/engine/network/NetworkSession.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;iCA6CoB,MAAM;AAhB1B;;;;;;;;;;;;;;;;;GAiBG;AACH;;;GAGG;;;;sCAKiB,MAAM;AAH1B;;;;GAIG;AACH;IACI;;;;;;;OAOG;;IAEH;;;;OAIG;;GAEJ;AA8LH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH;IAqdI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4DG;IACH,iSA5DW;QACV,cAAkB,gBAAgB;QAClC,SAAa,CAAC,EAAE,MAAM,CAAC;QACvB,iBAAqB,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,CAAC;QACvC,IAAQ,CAAC,EAAE,QAAQ,GAAC,MAAM,CAAC;QAC3B,aAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,sBAA0B,CAAC,EAAE,MAAM,CAAC;QACpC,YAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,eAAmB,CAAC,EAAE,2BAA2B,CAAC;QAClD,YAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,aAAiB,CAAC,EAAE,YAAY,CAAC;QACjC,qBAAyB,CAAC,EAAE,mBAAmB,CAAC;QAChD,sBAA0B,CAAC,EAAE,MAAM,CAAC;QACpC,qBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,SAAa,CAAC,EAAE;YAChB,OAAa,CAAC,EAAE,OAAO,CAAC;YACxB,YAAkB,CAAC,EAAE,MAAM,CAAC;YAC5B,aAAmB,CAAC,EAAE,MAAM,CAAC;YAC7B,YAAkB,CAAC,EAAE,MAAM,CAAC;YAC5B,kBAAwB,CAAC,EAAE,MAAM,CAAC;YAClC,gBAAsB,CAAC,EAAE,MAAM,CAAC;YAChC,mBAAyB,CAAC,EAAE,OAAO,CAAC;SAC/B,CAAC;KACH,EA0KH;IArjBD;;;;OAIG;IACH,cAFU,OAAO,CAEI;IAiGrB;;;OAGG;IACH,kBAFU,MAAM,CAEK;IAErB;;;;OAIG;IACH,0BAFU,MAAM,CAEa;IAE7B;;;;;;;;OAQG;IACH,cAFU,MAAM,CAEY;IAsF5B;;;;;;OAMG;IACH,eAFU,IAAI,GAAC,IAAI,CAEE;IAuErB;;;;OAIG;IACH,YAFU,MAAM,CAEU;IAE1B;;;;;OAKG;IACH,0BAFU,MAAM,CAEwB;IAExC;;;;OAIG;IACH,kBAFU,MAAM,CAEgB;IAEhC;;;;OAIG;IACH,oBAFU,MAAM,CAEkB;IAElC;;;;;;OAMG;IACH,eAFU,MAAM,CAEa;IAE7B;;;;;OAKG;IACH,UAFU,MAAM,CAEQ;IAExB;;;;;OAKG;IACH,6BAFU,MAAM,CAE2B;IA2HvC;;;OAGG;IACH,uCAAoC;IAEpC;;;OAGG;IACH,uCAAmC;IAEnC;;;OAGG;IACH,eAFU,kBAAkB,GAAC,MAAM,CAEnB;IAQhB;;;;OAIG;IACH,yBAFU,MAAM,CAE+C;IAE/D;;;OAGG;IACH,iCAFU,MAAM,CAIT;IAEP;;;;;;OAMG;IACH,yBAFU,MAAM,CAEoB;IAEpC;;;OAGG;IACH,wBAFU,MAAM,CAIgC;IAEhD;;;OAGG;IACH,0BAFU,2BAA2B,CAEsC;IAgD/E;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,8DAHW,WAAW,gCAkBrB;IAED;;;;;;;;;;;;;;OAcG;IACH,2EAMC;IAED;;;;;;;;;;;;OAYG;IACH,mDAFW,0BAA0B,GAAC,IAAI,QAsBzC;IA0BD;;;;;;;;OAQG;IACH,6CAIC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,+BAFW,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,SAAS,CAAC,GAAC,IAAI,QAWlD;IAMD;;;;;;;;;OASG;IACH,uBAuQC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,wBAHW,MAAM,aACN,MAAM,QA+FhB;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,mBAHW,MAAM,WACN,MAAM,QA+BhB;IAeD;;;;;;OAMG;IACH,oBAFW,MAAM,QAmChB;IAED;;;;;;;;;;;;OAYG;IACH,qBAmDC;IAMD;;;;;;;;;;;OAWG;IACH,kBAFW,MAAM,QAOhB;IA6ID;;;;;;;;;OASG;IACH,2BAKC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,sBAFW,SAAS,QAYnB;IAMD;;OAEG;IACH,wCAEC;IAED;;OAEG;IACH,wCAEC;IAED;;OAEG;IACH,wBAEC;IAED;;OAEG;IACH,0CAEC;IAED;;OAEG;IACH,iDAEC;IAED;;OAEG;IACH,kCAEC;IAED;;;;;;;;;;OAUG;IACH,kCAEC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,wBAHW,MAAM,GACJ;QAAC,iBAAiB,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAC,CAIlE;IAED;;OAEG;IACH,4BAGC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,qBAFW,MAAM,QAahB;;CAyjDJ;mBA1kHkB,oCAAoC;qBAElC,qBAAqB;4CACG,sDAAsD;4BAYvE,iCAAiC;2CADE,gDAAgD;0BAKrF,oBAAoB;0CAPO,6CAA6C;0CADxD,6CAA6C;4BAFrB,+BAA+B;iCAQhE,sCAAsC;oCAInC,+BAA+B;6BAEtC,wBAAwB"}
|