@woosh/meep-engine 3.46.0 → 3.49.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/particles/effect/ParticleReferenceSimulation.d.ts +1 -2
- package/editor/particles/effect/ParticleReferenceSimulation.d.ts.map +1 -1
- package/editor/particles/effect/ParticleReferenceSimulation.js +2 -4
- 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/editor/view/particles/effect/ParticleGraphEditorView.js +1 -1
- package/package.json +1 -1
- 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/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/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/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +9 -4
- package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +27 -11
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +21 -0
- 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/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +30 -1
- package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts +2 -2
- package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts.map +1 -1
- package/src/engine/graphics/ecs/particles/ParticleEffect.js +7 -7
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts +8 -0
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.js +11 -3
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_1_2.d.ts +26 -0
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_1_2.d.ts.map +1 -0
- package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_1_2.js +91 -0
- 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/GraphicsEngine.d.ts.map +1 -1
- package/src/engine/graphics3/GraphicsEngine.js +8 -1
- package/src/engine/graphics3/ParticipatingMedia.d.ts +84 -1
- package/src/engine/graphics3/ParticipatingMedia.d.ts.map +1 -1
- package/src/engine/graphics3/ParticipatingMedia.js +139 -5
- package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.d.ts +6 -2
- package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.d.ts.map +1 -1
- package/src/engine/graphics3/ParticipatingMediaSerializationAdapter.js +29 -4
- package/src/engine/graphics3/ParticipatingMediaSerializationUpgrader_0_1.d.ts +10 -0
- package/src/engine/graphics3/ParticipatingMediaSerializationUpgrader_0_1.d.ts.map +1 -0
- package/src/engine/graphics3/ParticipatingMediaSerializationUpgrader_0_1.js +38 -0
- package/src/engine/graphics3/ParticipatingMediaSystem.d.ts.map +1 -1
- package/src/engine/graphics3/ParticipatingMediaSystem.js +46 -3
- 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/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 +47 -16
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +556 -292
- package/src/engine/network/README.md +104 -28
- 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 +59 -23
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +213 -198
- package/src/engine/network/replication/Replicator.d.ts +15 -4
- package/src/engine/network/replication/Replicator.d.ts.map +1 -1
- package/src/engine/network/replication/Replicator.js +57 -17
- 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/state/RecordArrivalRing.d.ts +57 -0
- package/src/engine/network/state/RecordArrivalRing.d.ts.map +1 -0
- package/src/engine/network/state/RecordArrivalRing.js +144 -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/MEASUREMENTS.md +354 -0
- package/src/engine/physics/cloth/PLAN.md +85 -5
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +0 -12
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.js +0 -13
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +2 -1
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothSystem.js +7 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +4 -15
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +2 -1
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +6 -1
- package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_build_rows.js +20 -10
- package/src/engine/physics/cloth/playground/collide.html +5 -3
- package/src/engine/physics/cloth/playground/collide_main.js +14 -13
- package/src/engine/physics/cloth/solver/ClothState.d.ts +30 -2
- package/src/engine/physics/cloth/solver/ClothState.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/ClothState.js +62 -4
- package/src/engine/physics/cloth/solver/cloth_self_find.d.ts +11 -3
- package/src/engine/physics/cloth/solver/cloth_self_find.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_self_find.js +52 -11
- package/src/engine/physics/cloth/solver/cloth_self_radius.d.ts +42 -0
- package/src/engine/physics/cloth/solver/cloth_self_radius.d.ts.map +1 -0
- package/src/engine/physics/cloth/solver/cloth_self_radius.js +64 -0
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +99 -24
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_solver_constants.js +102 -25
- package/src/engine/physics/cloth/solver/cloth_step.d.ts +5 -1
- package/src/engine/physics/cloth/solver/cloth_step.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_step.js +13 -3
- package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts +0 -1
- package/src/engine/physics/cloth/solver/cloth_step_instance.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_step_instance.js +12 -14
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts +23 -4
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/constraint/cloth_contact_row.js +36 -8
- package/src/engine/physics/cloth/solver/constraint/cloth_self_row.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/constraint/cloth_self_row.js +4 -2
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- 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 +35 -7
- 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/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/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/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 +55 -5
- 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/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 -122
- 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 -131
- 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 +6 -1
- 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/shade/RENDERER_CONTRACT.md +6 -3
- 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/mock/SoftwareGPUDevice.d.ts +15 -0
- package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUDevice.js +21 -0
- package/src/shade/device/pipeline/ComputePipelineManager.d.ts +20 -0
- package/src/shade/device/pipeline/ComputePipelineManager.d.ts.map +1 -1
- package/src/shade/device/pipeline/ComputePipelineManager.js +80 -6
- package/src/shade/device/pipeline/PipelineEnquiry.d.ts +52 -0
- package/src/shade/device/pipeline/PipelineEnquiry.d.ts.map +1 -0
- package/src/shade/device/pipeline/PipelineEnquiry.js +63 -0
- package/src/shade/device/pipeline/RenderPipelineManager.d.ts +21 -0
- package/src/shade/device/pipeline/RenderPipelineManager.d.ts.map +1 -1
- package/src/shade/device/pipeline/RenderPipelineManager.js +84 -4
- 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/playground/contact_shadows/ContactShadowLab.d.ts +137 -0
- package/src/shade/playground/contact_shadows/ContactShadowLab.d.ts.map +1 -0
- package/src/shade/playground/contact_shadows/ContactShadowLab.js +654 -0
- package/src/shade/playground/contact_shadows/README.md +126 -0
- package/src/shade/playground/contact_shadows/index.html +191 -0
- package/src/shade/playground/contact_shadows/main.d.ts +2 -0
- package/src/shade/playground/contact_shadows/main.d.ts.map +1 -0
- package/src/shade/playground/contact_shadows/main.js +888 -0
- package/src/shade/playground/contact_shadows/scenes.d.ts +48 -0
- package/src/shade/playground/contact_shadows/scenes.d.ts.map +1 -0
- package/src/shade/playground/contact_shadows/scenes.js +620 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_composite.d.ts +36 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_composite.d.ts.map +1 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_composite.js +245 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_reference.d.ts +15 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_reference.d.ts.map +1 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_reference.js +120 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_stats.d.ts +55 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_stats.d.ts.map +1 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_stats.js +216 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_view.d.ts +20 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_view.d.ts.map +1 -0
- package/src/shade/playground/contact_shadows/shader_contact_lab_view.js +114 -0
- package/src/shade/playground/contact_shadows/shader_contact_shadow_march.d.ts +11 -0
- package/src/shade/playground/contact_shadows/shader_contact_shadow_march.d.ts.map +1 -0
- package/src/shade/playground/contact_shadows/shader_contact_shadow_march.js +90 -0
- package/src/shade/playground/contact_shadows/textures.d.ts +16 -0
- package/src/shade/playground/contact_shadows/textures.d.ts.map +1 -0
- package/src/shade/playground/contact_shadows/textures.js +123 -0
- package/src/shade/playground/particle_ecs/README.md +1 -1
- package/src/shade/playground/particle_ecs/effects/flame.json +1932 -1881
- package/src/shade/playground/particle_ecs/effects/smoke.json +99 -1
- package/src/shade/playground/particle_ecs/effects/soot.json +152 -145
- package/src/shade/playground/tonemap_sdr/README.md +90 -0
- package/src/shade/playground/tonemap_sdr/ToneMapCompare.d.ts +105 -0
- package/src/shade/playground/tonemap_sdr/ToneMapCompare.d.ts.map +1 -0
- package/src/shade/playground/tonemap_sdr/ToneMapCompare.js +380 -0
- package/src/shade/playground/tonemap_sdr/chunk_tonemap_gt7_sdr_reference.d.ts +32 -0
- package/src/shade/playground/tonemap_sdr/chunk_tonemap_gt7_sdr_reference.d.ts.map +1 -0
- package/src/shade/playground/tonemap_sdr/chunk_tonemap_gt7_sdr_reference.js +104 -0
- package/src/shade/playground/tonemap_sdr/index.html +90 -0
- package/src/shade/playground/tonemap_sdr/main.d.ts +2 -0
- package/src/shade/playground/tonemap_sdr/main.d.ts.map +1 -0
- package/src/shade/playground/tonemap_sdr/main.js +306 -0
- package/src/shade/playground/tonemap_sdr/scenes.d.ts +26 -0
- package/src/shade/playground/tonemap_sdr/scenes.d.ts.map +1 -0
- package/src/shade/playground/tonemap_sdr/scenes.js +404 -0
- package/src/shade/playground/volumetrics_froxel/main.d.ts.map +1 -1
- package/src/shade/playground/volumetrics_froxel/main.js +85 -4
- package/src/shade/playground/water_refraction/README.md +26 -18
- package/src/shade/playground/water_refraction/index.html +1 -1
- package/src/shade/renderer/Renderer.d.ts +37 -3
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +237 -67
- package/src/shade/renderer/ShadeToneMappingMode.d.ts +14 -0
- package/src/shade/renderer/ShadeToneMappingMode.d.ts.map +1 -0
- package/src/shade/renderer/ShadeToneMappingMode.js +30 -0
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts +9 -0
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +14 -0
- package/src/shade/renderer/animation/skinning/shader_meshlet_apply_skinning.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/shader_meshlet_apply_skinning.js +5 -3
- 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/buffer/table/GPUDatabase.d.ts +7 -0
- package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUDatabase.js +12 -0
- package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts +8 -0
- package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +12 -0
- package/src/shade/renderer/camera/GPUCameraContext.d.ts.map +1 -1
- package/src/shade/renderer/camera/GPUCameraContext.js +19 -8
- package/src/shade/renderer/deferred/chunk_read_gBuffer_material.d.ts.map +1 -1
- package/src/shade/renderer/deferred/chunk_read_gBuffer_material.js +4 -0
- package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.d.ts.map +1 -1
- package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.js +4 -0
- package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_restir.d.ts.map +1 -1
- package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_restir.js +4 -0
- package/src/shade/renderer/deferred/shader_deferred_main.d.ts.map +1 -1
- package/src/shade/renderer/deferred/shader_deferred_main.js +3 -0
- package/src/shade/renderer/deferred/shader_tonemap_HDR.d.ts +6 -0
- package/src/shade/renderer/deferred/shader_tonemap_HDR.d.ts.map +1 -1
- package/src/shade/renderer/deferred/shader_tonemap_HDR.js +13 -3
- package/src/shade/renderer/deferred/shader_tonemap_HDR_none.d.ts +9 -0
- package/src/shade/renderer/deferred/shader_tonemap_HDR_none.d.ts.map +1 -0
- package/src/shade/renderer/deferred/shader_tonemap_HDR_none.js +63 -0
- package/src/shade/renderer/deferred/shader_tonemap_HDR_pbr_neutral.d.ts +10 -0
- package/src/shade/renderer/deferred/shader_tonemap_HDR_pbr_neutral.d.ts.map +1 -0
- package/src/shade/renderer/deferred/shader_tonemap_HDR_pbr_neutral.js +87 -0
- package/src/shade/renderer/deferred/shader_tonemap_LDR.d.ts +6 -0
- package/src/shade/renderer/deferred/shader_tonemap_LDR.d.ts.map +1 -1
- package/src/shade/renderer/deferred/shader_tonemap_LDR.js +23 -5
- package/src/shade/renderer/deferred/shader_tonemap_LDR_none.d.ts +9 -0
- package/src/shade/renderer/deferred/shader_tonemap_LDR_none.d.ts.map +1 -0
- package/src/shade/renderer/deferred/shader_tonemap_LDR_none.js +68 -0
- package/src/shade/renderer/deferred/shader_tonemap_LDR_pbr_neutral.d.ts +10 -0
- package/src/shade/renderer/deferred/shader_tonemap_LDR_pbr_neutral.d.ts.map +1 -0
- package/src/shade/renderer/deferred/shader_tonemap_LDR_pbr_neutral.js +73 -0
- package/src/shade/renderer/geometry/meshlet/MeshletBatch.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +58 -9
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +35 -25
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +97 -196
- package/src/shade/renderer/geometry/sdf/shader_build_sdf.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/shader_build_sdf.js +121 -129
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/brick4_bake_basic.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/brick4_bake_basic.js +3 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_probes.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/bake/shader_brick4_bake_probes.js +4 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/draw/shader_brick4_indirect_lighting.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/draw/shader_brick4_indirect_lighting.js +4 -0
- package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/lpv/bake/GPULightProbeVolumeRenderer.js +3 -0
- package/src/shade/renderer/global_illumination/lpv/deprecated/probe_trace_compute_shader_code.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/lpv/deprecated/probe_trace_compute_shader_code.js +4 -0
- package/src/shade/renderer/global_illumination/probe/octahedral/graph_sample_light_probes.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/graph_sample_light_probes.js +4 -0
- package/src/shade/renderer/global_illumination/shader_resolve_indirect_lighting.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/shader_resolve_indirect_lighting.js +4 -0
- package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +131 -1
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_delta.d.ts +7 -0
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_delta.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_delta.js +45 -38
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_determine_range.d.ts +2 -0
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_determine_range.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_determine_range.js +81 -79
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_find_split.d.ts +2 -0
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_find_split.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_find_split.js +5 -3
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_internal_children.d.ts +21 -0
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_internal_children.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_internal_children.js +42 -0
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_morton_code.d.ts +19 -0
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_morton_code.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh/chunk_bvh_morton_code.js +44 -0
- package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.d.ts +23 -5
- package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/graph_bvh_build_lbvh.js +139 -23
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_build_single_workgroup.d.ts +25 -0
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_build_single_workgroup.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_build_single_workgroup.js +179 -0
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.d.ts +2 -2
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_emit_hierarchy.js +7 -16
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.d.ts +3 -4
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/bvh/shader_bvh_morton.js +6 -23
- package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts +11 -0
- package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.js +14 -3
- package/src/shade/renderer/gpu_primitive/indirect/build_indirect_draw_command.d.ts +10 -0
- package/src/shade/renderer/gpu_primitive/indirect/build_indirect_draw_command.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/indirect/build_indirect_draw_command.js +13 -3
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts +10 -0
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/prefix_sum/v1/graph_prefix_scan_csdldf.js +14 -0
- package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_comparator.d.ts +26 -0
- package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_comparator.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_comparator.js +52 -0
- package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_workgroup.d.ts +32 -0
- package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_workgroup.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/sort/chunk_sort_bitonic_workgroup.js +89 -0
- package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts +10 -0
- package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/sort/graph_radix_sort.js +20 -1
- 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/hiz/HierarchicalZBuffer.d.ts +10 -0
- package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
- package/src/shade/renderer/hiz/HierarchicalZBuffer.js +294 -281
- package/src/shade/renderer/light/GPULightCollection.d.ts +8 -0
- package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
- package/src/shade/renderer/light/GPULightCollection.js +18 -1
- package/src/shade/renderer/light/cluster/cull/graph_cull_lights.d.ts +8 -0
- package/src/shade/renderer/light/cluster/cull/graph_cull_lights.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/cull/graph_cull_lights.js +234 -218
- package/src/shade/renderer/light/cluster/graph_assign_clsuters.d.ts +7 -0
- package/src/shade/renderer/light/cluster/graph_assign_clsuters.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/graph_assign_clsuters.js +13 -0
- package/src/shade/renderer/light/cluster/graph_build_light_clusters.d.ts +7 -0
- package/src/shade/renderer/light/cluster/graph_build_light_clusters.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/graph_build_light_clusters.js +16 -2
- package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts +10 -0
- package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/execute_filter_environment_map.js +13 -0
- package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/GPULightMap.js +3 -0
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_irradiance_flat.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_irradiance_flat.js +4 -0
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_sh.d.ts.map +1 -1
- package/src/shade/renderer/lightmap/bake/shader_lightmap_viz_to_sh.js +4 -0
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/material/GPUMaterialManager.d.ts +16 -4
- package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
- package/src/shade/renderer/material/GPUMaterialManager.js +38 -8
- package/src/shade/renderer/particles/DESIGN.md +49 -7
- package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +453 -0
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts +5 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +13 -5
- package/src/shade/renderer/particles/data/particle_emitter_record.js +2 -2
- package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/particle_builtin_groups.js +12 -0
- package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.d.ts +60 -0
- package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.d.ts.map +1 -1
- package/src/shade/renderer/particles/graph/groups/particle_groups_geometry.js +156 -0
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +2 -2
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/ParticleEmitter.js +8 -8
- package/src/shade/renderer/particles/shaders/chunk_particle_billboard_vertex.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_billboard_vertex.js +6 -4
- package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts +7 -6
- package/src/shade/renderer/particles/shaders/chunk_particle_render_math.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_render_math.js +91 -58
- package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/accumulating/AccumulatingPathTracer.js +10 -0
- package/src/shade/renderer/path_tracer/accumulating/shader_accumulating_path_tracer.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/accumulating/shader_accumulating_path_tracer.js +5 -1
- package/src/shade/renderer/path_tracer/graph_path_trace_scene.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/graph_path_trace_scene.js +6 -0
- 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/postprocess/bloom/graph_postprocess_bloom.d.ts +7 -0
- package/src/shade/renderer/postprocess/bloom/graph_postprocess_bloom.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/bloom/graph_postprocess_bloom.js +18 -0
- package/src/shade/renderer/postprocess/denoise/LigmaDenoiser.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/denoise/LigmaDenoiser.js +1 -0
- package/src/shade/renderer/postprocess/denoise/shader_temporal_reprojection_luma.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/denoise/shader_temporal_reprojection_luma.js +6 -4
- package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts +11 -0
- package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +16 -0
- package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +10 -0
- package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/GTAO.js +16 -0
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +32 -10
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +3 -0
- package/src/shade/renderer/postprocess/ssr/resolve/build_ssr_resolve_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/resolve/build_ssr_resolve_shader.js +6 -3
- package/src/shade/renderer/postprocess/taa/TAA.d.ts +12 -0
- package/src/shade/renderer/postprocess/taa/TAA.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/taa/TAA.js +15 -0
- package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts +7 -0
- package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.js +13 -0
- package/src/shade/renderer/rasterize/TemplatePassDescriptor.d.ts +31 -3
- package/src/shade/renderer/rasterize/TemplatePassDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/TemplatePassDescriptor.js +79 -4
- package/src/shade/renderer/rasterize/bucket/graph_meshlets_rasterize_by_bucket.d.ts +17 -0
- package/src/shade/renderer/rasterize/bucket/graph_meshlets_rasterize_by_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/graph_meshlets_rasterize_by_bucket.js +35 -4
- package/src/shade/renderer/rasterize/compute/graph_mesh_frustum_cull.d.ts +7 -0
- package/src/shade/renderer/rasterize/compute/graph_mesh_frustum_cull.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/compute/graph_mesh_frustum_cull.js +182 -169
- package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_meshes_classify_buckets.d.ts +10 -0
- package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_meshes_classify_buckets.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/mesh/graph_meshes_classify_buckets.js +20 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_extract_meshlets_from_bucket.d.ts +10 -0
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_extract_meshlets_from_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_extract_meshlets_from_bucket.js +18 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.d.ts +10 -0
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/graph_sort_meshlets_by_bucket_id.js +20 -1
- package/src/shade/renderer/rasterize/expand/graph_mesh_filter_one_way.d.ts +7 -0
- package/src/shade/renderer/rasterize/expand/graph_mesh_filter_one_way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/graph_mesh_filter_one_way.js +187 -170
- package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.d.ts +10 -0
- package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/graph_meshlets_filter_one_way.js +19 -1
- package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.d.ts +13 -0
- package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/graph_meshlets_rasterize.js +25 -1
- package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts +10 -0
- package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/mesh/graph_expand_meshes_to_meshlets.js +20 -0
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.js +6 -0
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.js +6 -0
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +3 -2
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +3 -2
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts +7 -2
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +12 -4
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.js +4 -3
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.js +4 -3
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts +2 -1
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +11 -3
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.js +4 -3
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.js +4 -3
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts +15 -0
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +35 -2
- package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts +14 -0
- package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +32 -4
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts +17 -0
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +34 -4
- package/src/shade/renderer/restir/di/chunk_restir_resolve.d.ts +5 -3
- package/src/shade/renderer/restir/di/chunk_restir_resolve.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/chunk_restir_resolve.js +8 -3
- package/src/shade/renderer/restir/di/graph_restir_di.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/graph_restir_di.js +1 -0
- package/src/shade/renderer/restir/di/shader_restir_di_resolve.d.ts.map +1 -1
- package/src/shade/renderer/restir/di/shader_restir_di_resolve.js +5 -1
- package/src/shade/renderer/restir/reservoir/shader.d.ts.map +1 -1
- package/src/shade/renderer/restir/reservoir/shader.js +7 -4
- package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts +7 -0
- package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUInstancesAccelerationStructure.js +13 -1
- package/src/shade/renderer/scene/GPUSceneContext.d.ts +10 -0
- package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUSceneContext.js +19 -0
- package/src/shade/renderer/scene/SceneManager.d.ts +9 -0
- package/src/shade/renderer/scene/SceneManager.d.ts.map +1 -1
- package/src/shade/renderer/scene/SceneManager.js +11 -0
- package/src/shade/renderer/scene/hierarchy/graph_nodes_update_transform_hierarchy.d.ts +11 -0
- package/src/shade/renderer/scene/hierarchy/graph_nodes_update_transform_hierarchy.d.ts.map +1 -1
- package/src/shade/renderer/scene/hierarchy/graph_nodes_update_transform_hierarchy.js +17 -0
- package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.d.ts +11 -0
- package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.d.ts.map +1 -1
- package/src/shade/renderer/scene/hierarchy/graph_scene_update_transform_hierarchy.js +18 -1
- package/src/shade/renderer/shader/ComputeShader.d.ts +12 -0
- package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ComputeShader.js +71 -2
- package/src/shade/renderer/shader/ImageShader.d.ts +27 -8
- package/src/shade/renderer/shader/ImageShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ImageShader.js +299 -218
- package/src/shade/renderer/shader/ShaderDescriptor.d.ts +21 -0
- package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/ShaderDescriptor.js +71 -1
- package/src/shade/renderer/shader/chunk/camera/chunk_project_view_position_from_depth.d.ts +17 -0
- package/src/shade/renderer/shader/chunk/camera/chunk_project_view_position_from_depth.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/camera/chunk_project_view_position_from_depth.js +45 -0
- package/src/shade/renderer/shader/chunk/camera/chunk_screen_coordinate_to_view.js +3 -3
- package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_eotf_st2084.d.ts +1 -1
- package/src/shade/renderer/shader/chunk/color/iCtCp/chunk_eotf_st2084.js +62 -62
- package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +318 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +237 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.d.ts +17 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_PAPER_WHITE_NITS.js +22 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_khronos_pbr.d.ts +14 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_khronos_pbr.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_khronos_pbr.js +28 -15
- package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.d.ts +12 -0
- package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/gt7/chunk_tonemap_gt7.js +128 -110
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_offset_ray_from_depth.d.ts +20 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_offset_ray_from_depth.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_offset_ray_from_depth.js +33 -0
- package/src/shade/renderer/shader/chunk/light/chunk_compute_multiscattering_specular.d.ts +4 -0
- package/src/shade/renderer/shader/chunk/light/chunk_compute_multiscattering_specular.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/light/chunk_compute_multiscattering_specular.js +12 -1
- package/src/shade/renderer/shader/chunk/material/MATERIAL_SHADING_INFO_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/material/MATERIAL_SHADING_INFO_STRUCT.js +7 -0
- package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +108 -0
- package/src/shade/renderer/shader/chunk/material/chunk_compute_indirect_specular.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/material/chunk_compute_indirect_specular.js +23 -4
- package/src/shade/renderer/shader/chunk/material/chunk_re_direct_multiscatter.d.ts +18 -0
- package/src/shade/renderer/shader/chunk/material/chunk_re_direct_multiscatter.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/material/chunk_re_direct_multiscatter.js +56 -0
- package/src/shade/renderer/shader/chunk/material/chunk_re_indirect_specular_physical.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/material/chunk_re_indirect_specular_physical.js +2 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_linear_ray.d.ts +43 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_linear_ray.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/screen_space/chunk_screen_space_linear_ray.js +319 -0
- package/src/shade/renderer/shader/compiler/CodeChunk.d.ts +33 -0
- package/src/shade/renderer/shader/compiler/CodeChunk.d.ts.map +1 -1
- package/src/shade/renderer/shader/compiler/CodeChunk.js +140 -0
- package/src/shade/renderer/shader/compiler/CodeChunkChoice.d.ts +74 -0
- package/src/shade/renderer/shader/compiler/CodeChunkChoice.d.ts.map +1 -0
- package/src/shade/renderer/shader/compiler/CodeChunkChoice.js +166 -0
- package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +680 -0
- package/src/shade/renderer/shader/compiler/ShaderSwitch.d.ts +86 -0
- package/src/shade/renderer/shader/compiler/ShaderSwitch.d.ts.map +1 -0
- package/src/shade/renderer/shader/compiler/ShaderSwitch.js +178 -0
- package/src/shade/renderer/shader/compiler/ShaderSwitchSet.d.ts +67 -0
- package/src/shade/renderer/shader/compiler/ShaderSwitchSet.d.ts.map +1 -0
- package/src/shade/renderer/shader/compiler/ShaderSwitchSet.js +205 -0
- package/src/shade/renderer/shadow/contact/CONTACT_SHADOW_WAVE_SIZE.d.ts +14 -0
- package/src/shade/renderer/shadow/contact/CONTACT_SHADOW_WAVE_SIZE.d.ts.map +1 -0
- package/src/shade/renderer/shadow/contact/CONTACT_SHADOW_WAVE_SIZE.js +13 -0
- package/src/shade/renderer/shadow/contact/ContactShadowDispatchList.d.ts +65 -0
- package/src/shade/renderer/shadow/contact/ContactShadowDispatchList.d.ts.map +1 -0
- package/src/shade/renderer/shadow/contact/ContactShadowDispatchList.js +252 -0
- package/src/shade/renderer/shadow/contact/FINDINGS.md +413 -0
- package/src/shade/renderer/shadow/contact/chunk_contact_shadow_wavefront_extents.d.ts +29 -0
- package/src/shade/renderer/shadow/contact/chunk_contact_shadow_wavefront_extents.d.ts.map +1 -0
- package/src/shade/renderer/shadow/contact/chunk_contact_shadow_wavefront_extents.js +105 -0
- package/src/shade/renderer/shadow/contact/graph_contact_shadow_linear.d.ts +29 -0
- package/src/shade/renderer/shadow/contact/graph_contact_shadow_linear.d.ts.map +1 -0
- package/src/shade/renderer/shadow/contact/graph_contact_shadow_linear.js +39 -0
- package/src/shade/renderer/shadow/contact/graph_contact_shadow_wavefront.d.ts +29 -0
- package/src/shade/renderer/shadow/contact/graph_contact_shadow_wavefront.d.ts.map +1 -0
- package/src/shade/renderer/shadow/contact/graph_contact_shadow_wavefront.js +92 -0
- package/src/shade/renderer/shadow/contact/shader_contact_shadow_linear.d.ts +29 -0
- package/src/shade/renderer/shadow/contact/shader_contact_shadow_linear.d.ts.map +1 -0
- package/src/shade/renderer/shadow/contact/shader_contact_shadow_linear.js +128 -0
- package/src/shade/renderer/shadow/contact/shader_contact_shadow_wavefront.d.ts +52 -0
- package/src/shade/renderer/shadow/contact/shader_contact_shadow_wavefront.d.ts.map +1 -0
- package/src/shade/renderer/shadow/contact/shader_contact_shadow_wavefront.js +358 -0
- package/src/shade/renderer/shadow/map/ShadowDirectionalTechnique.d.ts +10 -0
- package/src/shade/renderer/shadow/map/ShadowDirectionalTechnique.d.ts.map +1 -0
- package/src/shade/renderer/shadow/map/ShadowDirectionalTechnique.js +12 -0
- package/src/shade/renderer/shadow/map/shader/SHADOW_DIRECTIONAL_TECHNIQUE.d.ts +13 -0
- package/src/shade/renderer/shadow/map/shader/SHADOW_DIRECTIONAL_TECHNIQUE.d.ts.map +1 -0
- package/src/shade/renderer/shadow/map/shader/SHADOW_DIRECTIONAL_TECHNIQUE.js +14 -0
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts +14 -8
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional.js +20 -86
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional_cascades.d.ts +14 -0
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional_cascades.d.ts.map +1 -0
- package/src/shade/renderer/shadow/map/shader/chunk_shadowmap_sample_directional_cascades.js +79 -0
- package/src/shade/renderer/shadow/ray/shader_ray_shadow_code.d.ts.map +1 -1
- package/src/shade/renderer/shadow/ray/shader_ray_shadow_code.js +12 -12
- package/src/shade/renderer/shadow/ray/staged/gen/shader_generate_rays.d.ts.map +1 -1
- package/src/shade/renderer/shadow/ray/staged/gen/shader_generate_rays.js +153 -151
- package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_directional_virtual.d.ts +13 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_directional_virtual.d.ts.map +1 -0
- package/src/shade/renderer/shadow/vsm/shader/chunk_shadowmap_sample_directional_virtual.js +48 -0
- package/src/shade/renderer/texture/GPUTextureContext.d.ts +10 -0
- package/src/shade/renderer/texture/GPUTextureContext.d.ts.map +1 -1
- package/src/shade/renderer/texture/GPUTextureContext.js +24 -0
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts +219 -0
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.d.ts.map +1 -0
- package/src/shade/renderer/texture/atlas/GPUTileAtlas3D.js +671 -0
- package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.d.ts +26 -2
- package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/GPUSceneVolumetrics.js +108 -4
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +5 -1
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +6 -0
- package/src/shade/renderer/volumetrics/NOTES.md +50 -0
- package/src/shade/renderer/volumetrics/PARTICIPATING_MEDIA_VOLUME_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/PARTICIPATING_MEDIA_VOLUME_STRUCT.js +30 -1
- package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts +51 -13
- package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/ParticipatingMediaVolume.js +98 -13
- package/src/shade/renderer/volumetrics/SceneVolumetrics.d.ts +9 -0
- package/src/shade/renderer/volumetrics/SceneVolumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/SceneVolumetrics.js +78 -68
- package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +326 -0
- package/src/shade/renderer/volumetrics/chunk_participating_media_volume_sample.d.ts +7 -4
- package/src/shade/renderer/volumetrics/chunk_participating_media_volume_sample.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/chunk_participating_media_volume_sample.js +21 -9
- package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_uvw_from_clip.d.ts +19 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_uvw_from_clip.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_froxel_uvw_from_clip.js +53 -0
- package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.d.ts +12 -3
- package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/chunk_volumetrics_sample_froxel_extinction.js +85 -48
- package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts +4 -1
- package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/graph_build_froxel_irradiance.js +4 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts +4 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/graph_build_volumetrics.js +21 -1
- package/src/shade/renderer/volumetrics/noise/PARTICIPATING_MEDIA_NOISE.d.ts +98 -0
- package/src/shade/renderer/volumetrics/noise/PARTICIPATING_MEDIA_NOISE.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/noise/PARTICIPATING_MEDIA_NOISE.js +115 -0
- package/src/shade/renderer/volumetrics/noise/VOLUMETRICS_NOISE_TILE_BAKE_SETTINGS_STRUCT.d.ts +9 -0
- package/src/shade/renderer/volumetrics/noise/VOLUMETRICS_NOISE_TILE_BAKE_SETTINGS_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/noise/VOLUMETRICS_NOISE_TILE_BAKE_SETTINGS_STRUCT.js +24 -0
- package/src/shade/renderer/volumetrics/noise/bake_volumetrics_noise_tile.d.ts +27 -0
- package/src/shade/renderer/volumetrics/noise/bake_volumetrics_noise_tile.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/noise/bake_volumetrics_noise_tile.js +91 -0
- package/src/shade/renderer/volumetrics/noise/chunk_participating_media_noise.d.ts +35 -0
- package/src/shade/renderer/volumetrics/noise/chunk_participating_media_noise.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/noise/chunk_participating_media_noise.js +92 -0
- package/src/shade/renderer/volumetrics/noise/shader_volumetrics_noise_tile_bake.d.ts +10 -0
- package/src/shade/renderer/volumetrics/noise/shader_volumetrics_noise_tile_bake.d.ts.map +1 -0
- package/src/shade/renderer/volumetrics/noise/shader_volumetrics_noise_tile_bake.js +121 -0
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_participating_media.js +38 -3
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_sun_shadow_volume.js +311 -290
- package/src/shade/renderer/volumetrics/volumetrics_position_world_to_froxel_uvw.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/volumetrics_position_world_to_froxel_uvw.js +28 -49
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts +3 -1
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
- package/src/shade/renderer/water/GPUWaterRenderer.js +24 -18
- package/src/shade/renderer/water/chunk_water_transport.d.ts +0 -1
- package/src/shade/renderer/water/chunk_water_transport.d.ts.map +1 -1
- package/src/shade/renderer/water/chunk_water_transport.js +0 -17
- package/src/shade/renderer/water/shader_water.d.ts +4 -2
- package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
- package/src/shade/renderer/water/shader_water.js +27 -16
- package/src/shade/renderer/water/shader_water_avboit.d.ts +0 -4
- package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
- package/src/shade/renderer/water/shader_water_avboit.js +0 -63
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +43 -9
- 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/engine/network/transport/Channel.d.ts +0 -85
- package/src/engine/network/transport/Channel.d.ts.map +0 -1
- package/src/engine/network/transport/Channel.js +0 -336
- package/src/engine/network/transport/ReliableCommandPipeline.d.ts +0 -155
- package/src/engine/network/transport/ReliableCommandPipeline.d.ts.map +0 -1
- package/src/engine/network/transport/ReliableCommandPipeline.js +0 -335
- package/src/engine/network/transport/fragments/FragmentAssembler.d.ts +0 -105
- package/src/engine/network/transport/fragments/FragmentAssembler.d.ts.map +0 -1
- package/src/engine/network/transport/fragments/FragmentAssembler.js +0 -350
- package/src/engine/network/transport/fragments/FragmentRetention.d.ts +0 -103
- package/src/engine/network/transport/fragments/FragmentRetention.d.ts.map +0 -1
- package/src/engine/network/transport/fragments/FragmentRetention.js +0 -191
- package/src/engine/network/transport/fragments/fragment_send.d.ts +0 -61
- package/src/engine/network/transport/fragments/fragment_send.d.ts.map +0 -1
- package/src/engine/network/transport/fragments/fragment_send.js +0 -157
- package/src/engine/network/transport/fragments/packet_size.d.ts +0 -99
- package/src/engine/network/transport/fragments/packet_size.d.ts.map +0 -1
- package/src/engine/network/transport/fragments/packet_size.js +0 -107
- package/src/shade/renderer/shader/chunk/color/sRGB/chunk_RRTAndODTFit.d.ts +0 -6
- package/src/shade/renderer/shader/chunk/color/sRGB/chunk_RRTAndODTFit.d.ts.map +0 -1
- package/src/shade/renderer/shader/chunk/color/sRGB/chunk_RRTAndODTFit.js +0 -16
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_aces.d.ts +0 -7
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_aces.d.ts.map +0 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_aces.js +0 -46
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_agx.d.ts +0 -10
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_agx.d.ts.map +0 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_agx.js +0 -127
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_pbr_neutral.d.ts +0 -7
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_pbr_neutral.d.ts.map +0 -1
- package/src/shade/renderer/shader/chunk/color/tonemap/chunk_tonemap_pbr_neutral.js +0 -39
|
@@ -2,7 +2,6 @@ import { assert } from "../../../core/assert.js";
|
|
|
2
2
|
import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
|
|
3
3
|
import Signal from "../../../core/events/signal/Signal.js";
|
|
4
4
|
import { MalformedPacketError } from "../core/MalformedPacketError.js";
|
|
5
|
-
import { seq16_advance } from "../core/sequence/seq16.js";
|
|
6
5
|
import { Replicator } from "../replication/Replicator.js";
|
|
7
6
|
import { AlwaysRelevantScope } from "../replication/ScopeFilter.js";
|
|
8
7
|
import { ActionLog } from "../sim/ActionLog.js";
|
|
@@ -14,12 +13,9 @@ import { Baseline } from "../state/Baseline.js";
|
|
|
14
13
|
import { ChangedEntitySet } from "../state/ChangedEntitySet.js";
|
|
15
14
|
import { MutationLedger } from "../state/MutationLedger.js";
|
|
16
15
|
import { ReplicationSlotTable } from "../state/ReplicationSlotTable.js";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { FragmentRetention } from "../transport/fragments/FragmentRetention.js";
|
|
21
|
-
import { MAX_CHANNEL_PAYLOAD_BYTES, MAX_CHUNKS_PER_MESSAGE } from "../transport/fragments/packet_size.js";
|
|
22
|
-
import { ReliableCommandPipeline } from "../transport/ReliableCommandPipeline.js";
|
|
16
|
+
import { Connection, Lane } from "../transport/connection/Connection.js";
|
|
17
|
+
import { PendingSlices } from "./PendingSlices.js";
|
|
18
|
+
import { ReliableFrames } from "./ReliableFrames.js";
|
|
23
19
|
|
|
24
20
|
// DISCONNECT packets carry a short UTF-8 reason label. The encoder/decoder
|
|
25
21
|
// pair are stateless after construction; sharing module-level singletons
|
|
@@ -73,42 +69,18 @@ export const NetworkPacketType = {
|
|
|
73
69
|
* like this at frame F."
|
|
74
70
|
*/
|
|
75
71
|
AUTH_STATE: 3,
|
|
72
|
+
// 4 was FRAGMENT: messages of any size are the connection's business now
|
|
76
73
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* capacity. The fragment header (uint16 message_id, uint8 chunk_index,
|
|
80
|
-
* uint8 total_chunks) follows this type byte; the chunk payload follows
|
|
81
|
-
* that. The reassembled bytes are re-dispatched through this same
|
|
82
|
-
* switch (so any of the other packet types can be carried fragmented).
|
|
83
|
-
*/
|
|
84
|
-
FRAGMENT: 4,
|
|
85
|
-
/**
|
|
86
|
-
* Reliable command. Carries a uintVar logical_seq followed by a
|
|
87
|
-
* caller-defined payload. Delivered at-least-once with sender-side
|
|
88
|
-
* retransmit and receiver-side dedup via {@link ReliableCommandPipeline}.
|
|
89
|
-
* Used for chat, level transitions, lobby state — anything where
|
|
74
|
+
* Reliable command: a caller-defined payload, on the connection's USER lane. Arrives once, in
|
|
75
|
+
* order with the other commands. For chat, level transitions, lobby state — anything where
|
|
90
76
|
* loss-tolerance of the action-stream model isn't acceptable.
|
|
91
77
|
*/
|
|
92
78
|
RELIABLE_COMMAND: 5,
|
|
93
|
-
|
|
94
|
-
* Selective-retransmit request from the receiver of a fragmented
|
|
95
|
-
* message. Wire layout (after the leading type byte):
|
|
96
|
-
*
|
|
97
|
-
* uint16 message_id (LE)
|
|
98
|
-
* uint8 missing_count
|
|
99
|
-
* uint8 missing_indices[missing_count]
|
|
100
|
-
*
|
|
101
|
-
* The sender's {@link FragmentRetention} looks up the retained
|
|
102
|
-
* source bytes and re-emits the listed chunks via
|
|
103
|
-
* {@link resend_fragment_chunk} — each chunk of the message once,
|
|
104
|
-
* however many times the list names it, and nothing for an index the
|
|
105
|
-
* message does not have. Receiver drives NACK timing
|
|
106
|
-
* via {@link FragmentAssembler#service}.
|
|
107
|
-
*/
|
|
108
|
-
NACK_FRAGMENT: 6,
|
|
79
|
+
// 6 was NACK_FRAGMENT
|
|
109
80
|
/**
|
|
110
81
|
* Server → client time-dilation feedback. Wire layout:
|
|
111
82
|
* int16 buffer_depth (LE)
|
|
83
|
+
* varint frame_number the server's sim frame as it sent this
|
|
112
84
|
*
|
|
113
85
|
* `buffer_depth = max_received_frame - current_sim_frame` from the
|
|
114
86
|
* server's POV. Client feeds it to {@link TimeDilation} and dilates
|
|
@@ -116,15 +88,18 @@ export const NetworkPacketType = {
|
|
|
116
88
|
*/
|
|
117
89
|
TIME_DILATION: 7,
|
|
118
90
|
/**
|
|
119
|
-
* Server →
|
|
91
|
+
* Server → joining peer: one page of the world. Wire layout:
|
|
120
92
|
* 16 bytes session_token (UUID v1, identifies this peer-session
|
|
121
93
|
* for later RESUME_HELLO authentication)
|
|
122
|
-
* varint frame_number (server sim_frame
|
|
123
|
-
*
|
|
94
|
+
* varint frame_number (server sim_frame the page's state is from)
|
|
95
|
+
* uint8 flags ({@link InitialSyncPage})
|
|
96
|
+
* uint32 entity_count
|
|
97
|
+
* bytes entities (Snapshotter entity records)
|
|
124
98
|
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
99
|
+
* A join is a run of pages on the connection's BULK lane, each built when
|
|
100
|
+
* it is sent: the world once, then what changed while it was going out,
|
|
101
|
+
* then an empty FINAL page that names the frame the action stream resumes
|
|
102
|
+
* after. The first page carries FIRST.
|
|
128
103
|
*/
|
|
129
104
|
INITIAL_SYNC: 8,
|
|
130
105
|
/**
|
|
@@ -183,6 +158,18 @@ export const NetworkPacketType = {
|
|
|
183
158
|
FRAME_MARKER: 13,
|
|
184
159
|
};
|
|
185
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Flags of an INITIAL_SYNC page.
|
|
163
|
+
* @readonly
|
|
164
|
+
* @enum {number}
|
|
165
|
+
*/
|
|
166
|
+
export const InitialSyncPage = Object.freeze({
|
|
167
|
+
/** The first page of a join: it issues the session token, and replaces the receiver's world. */
|
|
168
|
+
FIRST: 1,
|
|
169
|
+
/** The last page: every entity's state at its frame is now with the receiver. */
|
|
170
|
+
FINAL: 2,
|
|
171
|
+
});
|
|
172
|
+
|
|
186
173
|
/**
|
|
187
174
|
* Reason codes for {@link NetworkPacketType.RESUME_REJECT}.
|
|
188
175
|
* @readonly @enum {number}
|
|
@@ -211,40 +198,20 @@ export const ResumeRejectReason = Object.freeze({
|
|
|
211
198
|
NoSessionToken: 5,
|
|
212
199
|
});
|
|
213
200
|
|
|
214
|
-
/**
|
|
215
|
-
* One outbound action-stream send, awaiting confirmation.
|
|
216
|
-
*
|
|
217
|
-
* A send occupies one transport seq when it fits the MTU and N consecutive
|
|
218
|
-
* seqs when it has to be fragmented. All of those seqs map to the SAME record:
|
|
219
|
-
* the receiver reassembles a fragmented message all-or-nothing, so the frame
|
|
220
|
-
* range is confirmed only when `unacked` reaches zero without `abandoned`
|
|
221
|
-
* having been set by a loss along the way.
|
|
222
|
-
*
|
|
223
|
-
* A tick may make several sends to one peer, each carrying the next slice of
|
|
224
|
-
* the owed range (see {@link NetworkPeer#flush_outbound}). They confirm
|
|
225
|
-
* independently, and the baseline advances only through slices confirmed in
|
|
226
|
-
* order — a later slice landing says nothing about an earlier one still in
|
|
227
|
-
* flight. `head` marks the first slice of a tick, whose start is the pack
|
|
228
|
-
* start itself; see {@link NetworkPeer#__credit_confirmed}.
|
|
229
|
-
*
|
|
230
|
-
* @typedef {{frame_start: number, frame_end: number, head: boolean, unacked: number, abandoned: boolean}} PendingAck
|
|
231
|
-
* @property {number} frame_start first frame in the packed range
|
|
232
|
-
* @property {number} frame_end last frame in the packed range
|
|
233
|
-
* @property {boolean} head this send began at the pack start, so nothing
|
|
234
|
-
* sendable lies before it and its confirmation credits outright
|
|
235
|
-
* @property {number} unacked seqs of this send not yet acked or declared lost
|
|
236
|
-
* @property {boolean} abandoned at least one seq was declared lost, so the
|
|
237
|
-
* message is forfeit and must never advance the baseline
|
|
238
|
-
*/
|
|
239
|
-
|
|
240
201
|
/**
|
|
241
202
|
* Per-tick orchestrator that wires the action infrastructure to one or more
|
|
242
203
|
* peers over a Transport.
|
|
243
204
|
*
|
|
244
205
|
* Holds a single world (`EntityComponentDataset`) plus the action machinery
|
|
245
206
|
* (executor, replicator, action log). For each connected peer it owns a
|
|
246
|
-
*
|
|
247
|
-
*
|
|
207
|
+
* {@link Connection} and the action-stream slices sent on it and not yet
|
|
208
|
+
* resolved ({@link PendingSlices}), so that their acknowledgements advance the
|
|
209
|
+
* `Baseline.last_acked(peer_id)` watermark.
|
|
210
|
+
*
|
|
211
|
+
* Every `send_*` queues; nothing reaches a transport until {@link send_queued}
|
|
212
|
+
* (or {@link flush_peer}), which {@link end_tick} calls last. One tick's
|
|
213
|
+
* traffic to a peer thereby leaves together, packed into as few datagrams as
|
|
214
|
+
* fit.
|
|
248
215
|
*
|
|
249
216
|
* Use as both server (many connected peers) and client (one peer = the server).
|
|
250
217
|
* The asymmetry is in *who* connects — the orchestrator itself is symmetric.
|
|
@@ -255,9 +222,9 @@ export const ResumeRejectReason = Object.freeze({
|
|
|
255
222
|
* - `begin_tick(frame_number)` — open the action log for this frame.
|
|
256
223
|
* - User code runs game logic, calling `executor.execute(action)` for each
|
|
257
224
|
* replicated state mutation. Inbound actions from peers also flow into
|
|
258
|
-
* the executor automatically (via the
|
|
225
|
+
* the executor automatically (via the connection's onMessage wiring).
|
|
259
226
|
* - `end_tick()` — close the frame and dispatch outgoing packets to every peer.
|
|
260
|
-
* 3. `disconnect_peer(peer_id)` — release the
|
|
227
|
+
* 3. `disconnect_peer(peer_id)` — release the connection + baseline state.
|
|
261
228
|
*
|
|
262
229
|
* @author Alex Goldring
|
|
263
230
|
* @copyright Company Named Limited (c) 2026
|
|
@@ -267,17 +234,35 @@ export class NetworkPeer {
|
|
|
267
234
|
#peers;
|
|
268
235
|
#send_buffer;
|
|
269
236
|
#recv_buffer;
|
|
270
|
-
|
|
237
|
+
/** @type {function(): number} */
|
|
238
|
+
#clock;
|
|
271
239
|
/**
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* state on this; collisions would only matter if more than 65536
|
|
275
|
-
* messages were in flight simultaneously, which is impossible
|
|
276
|
-
* under any realistic transport pressure.
|
|
277
|
-
* @type {number}
|
|
278
|
-
* @private
|
|
240
|
+
* Options every connection is made with; see the constructor.
|
|
241
|
+
* @type {{send_rate_bytes_per_second: number, max_message_bytes: number, receive_window_bytes: number, max_queued_bytes: number, max_ack_delay_ms: number}}
|
|
279
242
|
*/
|
|
280
|
-
#
|
|
243
|
+
#connection_options;
|
|
244
|
+
/**
|
|
245
|
+
* Frame each network id was last changed by an action this peer executed or applied, -1 for
|
|
246
|
+
* never. What a joining peer's catch-up compares the frame its state was sent at against.
|
|
247
|
+
* @type {Float64Array}
|
|
248
|
+
*/
|
|
249
|
+
#last_changed = new Float64Array(256).fill(-1);
|
|
250
|
+
/** frame {@link #stamp_changed} writes */
|
|
251
|
+
#stamp_frame = 0;
|
|
252
|
+
/**
|
|
253
|
+
* Bound once: stamps one changed network id with {@link #stamp_frame}.
|
|
254
|
+
* @type {function(number): void}
|
|
255
|
+
*/
|
|
256
|
+
#stamp_changed = (network_id) => {
|
|
257
|
+
if (network_id >= this.#last_changed.length) {
|
|
258
|
+
let size = this.#last_changed.length * 2;
|
|
259
|
+
while (size <= network_id) size *= 2;
|
|
260
|
+
const next = new Float64Array(size).fill(-1);
|
|
261
|
+
next.set(this.#last_changed);
|
|
262
|
+
this.#last_changed = next;
|
|
263
|
+
}
|
|
264
|
+
this.#last_changed[network_id] = this.#stamp_frame;
|
|
265
|
+
};
|
|
281
266
|
/** @type {boolean} @private */
|
|
282
267
|
#tick_open = false;
|
|
283
268
|
#current_frame;
|
|
@@ -291,16 +276,6 @@ export class NetworkPeer {
|
|
|
291
276
|
*/
|
|
292
277
|
#malformed_packets_dropped = 0;
|
|
293
278
|
|
|
294
|
-
/**
|
|
295
|
-
* Scratch list of the transport seqs one send produced — one entry for a
|
|
296
|
-
* single-packet send, one per fragment for a fragmented one. Reused across
|
|
297
|
-
* sends so the common path allocates nothing; only valid until the next
|
|
298
|
-
* `__send_to_peer` call.
|
|
299
|
-
* @type {number[]}
|
|
300
|
-
* @private
|
|
301
|
-
*/
|
|
302
|
-
#sent_seqs = [];
|
|
303
|
-
|
|
304
279
|
/**
|
|
305
280
|
* Scratch for the slice header of the ACTION_STREAM packet being
|
|
306
281
|
* dispatched, handed to `Replicator.unpack_from_peer`, which copies what
|
|
@@ -310,14 +285,6 @@ export class NetworkPeer {
|
|
|
310
285
|
*/
|
|
311
286
|
#slice = { frame_start: 0, frame_end: 0, head: false };
|
|
312
287
|
|
|
313
|
-
/**
|
|
314
|
-
* Scratch for the NACK_FRAGMENT being dispatched: 1 at a chunk index the
|
|
315
|
-
* NACK has already had re-sent. Only valid for the duration of that case.
|
|
316
|
-
* @type {Uint8Array}
|
|
317
|
-
* @private
|
|
318
|
-
*/
|
|
319
|
-
#nack_requested = new Uint8Array(MAX_CHUNKS_PER_MESSAGE);
|
|
320
|
-
|
|
321
288
|
/**
|
|
322
289
|
* @param {{
|
|
323
290
|
* world: EntityComponentDataset,
|
|
@@ -331,7 +298,18 @@ export class NetworkPeer {
|
|
|
331
298
|
* mutation_ledger_retention_frames?: number,
|
|
332
299
|
* changed_set_capacity?: number,
|
|
333
300
|
* max_packets_per_tick?: number,
|
|
301
|
+
* clock: function(): number,
|
|
302
|
+
* tick_period_ms: number,
|
|
303
|
+
* send_rate_bytes_per_second?: number,
|
|
304
|
+
* max_message_bytes?: number,
|
|
305
|
+
* receive_window_bytes?: number,
|
|
306
|
+
* max_queued_bytes?: number,
|
|
334
307
|
* }} options
|
|
308
|
+
* `clock` returns milliseconds and never runs backwards: every network timer (loss, probe,
|
|
309
|
+
* pacing) runs on it, and nothing in the stack reads a clock of its own. `tick_period_ms` is
|
|
310
|
+
* how often this peer sends: the longest it sits on an acknowledgement, and the resolution
|
|
311
|
+
* of its timers. The remaining four configure every {@link Connection}; see there.
|
|
312
|
+
* `max_message_bytes` and `receive_window_bytes` must be the same on both ends.
|
|
335
313
|
*/
|
|
336
314
|
constructor({
|
|
337
315
|
world,
|
|
@@ -345,12 +323,30 @@ export class NetworkPeer {
|
|
|
345
323
|
mutation_ledger_retention_frames = 600,
|
|
346
324
|
changed_set_capacity = 256,
|
|
347
325
|
max_packets_per_tick = 8,
|
|
326
|
+
clock,
|
|
327
|
+
tick_period_ms,
|
|
328
|
+
send_rate_bytes_per_second = 262144,
|
|
329
|
+
max_message_bytes = 1 << 20,
|
|
330
|
+
receive_window_bytes = 256 * 1024,
|
|
331
|
+
max_queued_bytes = 4 << 20,
|
|
348
332
|
}) {
|
|
349
333
|
assert.ok(world && typeof world.createEntity === 'function', 'world must be an EntityComponentDataset');
|
|
350
334
|
assert.ok(binary_registry, 'binary_registry required');
|
|
351
335
|
assert.isFunction(replicated_components.forEach, 'replicated_components must be iterable');
|
|
352
336
|
assert.isFunction(action_classes.forEach, 'action_classes must be iterable');
|
|
353
337
|
assert.isPositiveInteger(max_packets_per_tick, 'max_packets_per_tick');
|
|
338
|
+
assert.isFunction(clock, 'clock');
|
|
339
|
+
assert.isNumber(tick_period_ms, 'tick_period_ms');
|
|
340
|
+
assert.greaterThan(tick_period_ms, 0, 'tick_period_ms');
|
|
341
|
+
|
|
342
|
+
this.#clock = clock;
|
|
343
|
+
this.#connection_options = {
|
|
344
|
+
send_rate_bytes_per_second,
|
|
345
|
+
max_message_bytes,
|
|
346
|
+
receive_window_bytes,
|
|
347
|
+
max_queued_bytes,
|
|
348
|
+
max_ack_delay_ms: tick_period_ms,
|
|
349
|
+
};
|
|
354
350
|
|
|
355
351
|
/** @type {EntityComponentDataset} */
|
|
356
352
|
this.world = world;
|
|
@@ -384,17 +380,9 @@ export class NetworkPeer {
|
|
|
384
380
|
* fit one packet; past that the owed range grows until it meets the
|
|
385
381
|
* ring floor and frames are lost.
|
|
386
382
|
*
|
|
387
|
-
* It is also the bandwidth ceiling under catch-up — this many
|
|
388
|
-
* tick per peer
|
|
389
|
-
*
|
|
390
|
-
* replies once a tick, `33 / max_packets_per_tick` consecutive lost
|
|
391
|
-
* replies leave a delivered packet outside the window and it is
|
|
392
|
-
* declared lost: a wasted re-send rather than a defect, since the
|
|
393
|
-
* receiver skips frames it has already applied. Eight tolerates three
|
|
394
|
-
* such losses in a row (one tick in sixteen at 50% loss, one in ten
|
|
395
|
-
* thousand at 10%), and lets a 60 Hz stream at 100 ms RTT carry a full
|
|
396
|
-
* packet of actions per frame. Lower it for peers that reply less often
|
|
397
|
-
* than every tick.
|
|
383
|
+
* It is also the bandwidth ceiling under catch-up — this many datagrams
|
|
384
|
+
* of actions per tick per peer. Eight lets a 60 Hz stream at 100 ms RTT
|
|
385
|
+
* carry a full datagram of actions per frame.
|
|
398
386
|
*
|
|
399
387
|
* @type {number}
|
|
400
388
|
*/
|
|
@@ -424,15 +412,13 @@ export class NetworkPeer {
|
|
|
424
412
|
this.mutation_ledger_retention_frames = mutation_ledger_retention_frames;
|
|
425
413
|
|
|
426
414
|
/**
|
|
427
|
-
* Per-tick "what mutated this tick" sink
|
|
428
|
-
* {@link
|
|
429
|
-
*
|
|
430
|
-
* @type {ChangedEntitySet
|
|
415
|
+
* Per-tick "what mutated this tick" sink. Cleared at the start of each tick; at its end,
|
|
416
|
+
* folded into {@link #last_changed} and, when a {@link mutation_ledger} is set, compacted
|
|
417
|
+
* into the ledger.
|
|
418
|
+
* @type {ChangedEntitySet}
|
|
431
419
|
* @private
|
|
432
420
|
*/
|
|
433
|
-
this.#changed_entities =
|
|
434
|
-
? null
|
|
435
|
-
: new ChangedEntitySet({ capacity: changed_set_capacity });
|
|
421
|
+
this.#changed_entities = new ChangedEntitySet({ capacity: changed_set_capacity });
|
|
436
422
|
|
|
437
423
|
/** @type {SimActionExecutor} */
|
|
438
424
|
this.executor = new SimActionExecutor({
|
|
@@ -457,8 +443,8 @@ export class NetworkPeer {
|
|
|
457
443
|
this.baseline = new Baseline();
|
|
458
444
|
|
|
459
445
|
/**
|
|
460
|
-
* peer_id →
|
|
461
|
-
* @type {Map<number, {
|
|
446
|
+
* peer_id → its connection and action-stream bookkeeping.
|
|
447
|
+
* @type {Map<number, { connection: Connection, transport: Object, pending: PendingSlices, confirmed: Int32Array, on_receive: Function, inbound_count: number, outbound_floor: number, reliable_frames: ReliableFrames }>}
|
|
462
448
|
* @private
|
|
463
449
|
*/
|
|
464
450
|
this.#peers = new Map();
|
|
@@ -478,14 +464,6 @@ export class NetworkPeer {
|
|
|
478
464
|
*/
|
|
479
465
|
this.#recv_buffer = new BinaryBuffer();
|
|
480
466
|
|
|
481
|
-
/**
|
|
482
|
-
* Reusable scratch buffer for outgoing fragment packets. Sized for one
|
|
483
|
-
* channel-level packet (MTU minus channel header).
|
|
484
|
-
* @type {Uint8Array}
|
|
485
|
-
* @private
|
|
486
|
-
*/
|
|
487
|
-
this.#fragment_scratch = new Uint8Array(MAX_CHANNEL_PAYLOAD_BYTES);
|
|
488
|
-
|
|
489
467
|
/**
|
|
490
468
|
* Fired when an inbound packet is dropped as malformed. Args:
|
|
491
469
|
* `(peer_id, error)`. Lets callers log / rate-limit / disconnect an
|
|
@@ -495,6 +473,26 @@ export class NetworkPeer {
|
|
|
495
473
|
*/
|
|
496
474
|
this.onMalformedPacket = new Signal();
|
|
497
475
|
|
|
476
|
+
/**
|
|
477
|
+
* The connection to a peer is no longer whole: `(peer_id, reason)`. Its connection said so
|
|
478
|
+
* (Connection.onProtocolError: a reliable lane broke its limits and stopped, or the peer
|
|
479
|
+
* acknowledged a packet never sent), or more of the peer's action stream arrived during
|
|
480
|
+
* {@link hold_inbound} than may be held. Nothing more can be trusted to arrive whole on it:
|
|
481
|
+
* give the connection up.
|
|
482
|
+
* @type {Signal}
|
|
483
|
+
*/
|
|
484
|
+
this.onProtocolError = new Signal();
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* An action-stream frame larger than any message the connection may carry
|
|
488
|
+
* (`max_message_bytes`) was given up rather than sent: `(peer_id, frame_start, frame_end,
|
|
489
|
+
* bytes)`. It can never be delivered, so it is stepped over — the peer never applies it —
|
|
490
|
+
* and the stream goes on behind it. Raise `max_message_bytes` on both ends for frames that
|
|
491
|
+
* large.
|
|
492
|
+
* @type {Signal}
|
|
493
|
+
*/
|
|
494
|
+
this.onFrameTooLarge = new Signal();
|
|
495
|
+
|
|
498
496
|
/**
|
|
499
497
|
* Fired when an inbound packet is a `RECOVERY_REQUEST` (peer is asking
|
|
500
498
|
* which entities mutated in a tick range so it can request their state).
|
|
@@ -528,7 +526,8 @@ export class NetworkPeer {
|
|
|
528
526
|
|
|
529
527
|
/**
|
|
530
528
|
* Fires on TIME_DILATION packet arrival.
|
|
531
|
-
* Args: `(peer_id, buffer_depth)` — signed int16
|
|
529
|
+
* Args: `(peer_id, buffer_depth, frame_number)` — signed int16, and the sender's sim frame
|
|
530
|
+
* as it sent it: the freshest word of where the host is, every tick.
|
|
532
531
|
* @type {Signal}
|
|
533
532
|
*/
|
|
534
533
|
this.onTimeDilationFeedback = new Signal();
|
|
@@ -540,10 +539,11 @@ export class NetworkPeer {
|
|
|
540
539
|
this.onFrameMarker = new Signal();
|
|
541
540
|
|
|
542
541
|
/**
|
|
543
|
-
* Fires on INITIAL_SYNC
|
|
544
|
-
* Args: `(peer_id, session_token, frame_number, buffer, payload_end)`.
|
|
545
|
-
* `session_token` is a `Uint8Array(16)` (UUID v1 raw bytes);
|
|
546
|
-
* buffer is positioned at the
|
|
542
|
+
* Fires on each INITIAL_SYNC page.
|
|
543
|
+
* Args: `(peer_id, session_token, frame_number, flags, buffer, payload_end)`.
|
|
544
|
+
* `session_token` is a `Uint8Array(16)` (UUID v1 raw bytes); `flags`
|
|
545
|
+
* is {@link InitialSyncPage}; the buffer is positioned at the page's
|
|
546
|
+
* uint32 entity count.
|
|
547
547
|
* @type {Signal}
|
|
548
548
|
*/
|
|
549
549
|
this.onInitialSync = new Signal();
|
|
@@ -584,7 +584,7 @@ export class NetworkPeer {
|
|
|
584
584
|
|
|
585
585
|
/**
|
|
586
586
|
* Fired when a reliable command arrives from a peer (delivered via
|
|
587
|
-
*
|
|
587
|
+
* the connection's USER lane, once and in order).
|
|
588
588
|
*
|
|
589
589
|
* Args: `(peer_id, buffer, payload_offset, payload_length)`. The
|
|
590
590
|
* buffer is the per-peer scratch and may be reused after the handler
|
|
@@ -600,7 +600,7 @@ export class NetworkPeer {
|
|
|
600
600
|
}
|
|
601
601
|
|
|
602
602
|
/**
|
|
603
|
-
* Wire `transport` to the peer identified by `peer_id`. Creates a
|
|
603
|
+
* Wire `transport` to the peer identified by `peer_id`. Creates a Connection
|
|
604
604
|
* over the transport and connects ack/payload notifications to the local
|
|
605
605
|
* Baseline / Replicator.
|
|
606
606
|
*
|
|
@@ -616,69 +616,34 @@ export class NetworkPeer {
|
|
|
616
616
|
// first rollback replay of its frame, so refuse the connection rather
|
|
617
617
|
// than lose its input later. Real runtime check — asserts strip in prod.
|
|
618
618
|
if (peer_id > MAX_PEER_ID) {
|
|
619
|
-
throw new Error(`NetworkPeer.connect_peer: peer id ${peer_id} is out of range; must be in [0, ${MAX_PEER_ID}] —
|
|
619
|
+
throw new Error(`NetworkPeer.connect_peer: peer id ${peer_id} is out of range; must be in [0, ${MAX_PEER_ID}] — 252 to 255 are reserved provenance markers in the action log`);
|
|
620
620
|
}
|
|
621
621
|
if (this.#peers.has(peer_id)) {
|
|
622
622
|
throw new Error(`NetworkPeer.connect_peer: peer ${peer_id} already connected`);
|
|
623
623
|
}
|
|
624
624
|
|
|
625
|
-
const
|
|
626
|
-
|
|
625
|
+
const connection = new Connection({
|
|
626
|
+
transport,
|
|
627
|
+
clock: this.#clock,
|
|
628
|
+
...this.#connection_options,
|
|
629
|
+
});
|
|
630
|
+
const pending = new PendingSlices();
|
|
627
631
|
// Frames this peer has confirmed that the baseline has not reached yet,
|
|
628
632
|
// because a slice before them is still in flight. A ring indexed by
|
|
629
633
|
// frame modulo capacity holding the frame number — see
|
|
630
634
|
// __credit_confirmed.
|
|
631
635
|
const confirmed = new Int32Array(this.action_log.frame_capacity).fill(-1);
|
|
632
|
-
// The reassembly window is sized from the burst. A frame too big for
|
|
633
|
-
// one packet goes out as a fragmented slice, and a tick may send
|
|
634
|
-
// `max_packets_per_tick` of them; jitter that holds a message's later
|
|
635
|
-
// fragments behind the next ticks' first fragments leaves that many
|
|
636
|
-
// partial messages per tick in flight at once. The assembler evicts
|
|
637
|
-
// the oldest partial when its window is full, both fragments of the
|
|
638
|
-
// evicted message are still acked, and the sender credits the slice —
|
|
639
|
-
// a silent loss. Four ticks of burst keeps the window ahead of any
|
|
640
|
-
// jitter the NACK timer would not already have caught.
|
|
641
|
-
const fragment_assembler = new FragmentAssembler({
|
|
642
|
-
max_pending_messages: Math.max(8, 4 * this.max_packets_per_tick),
|
|
643
|
-
});
|
|
644
|
-
const fragment_retention = new FragmentRetention();
|
|
645
|
-
const reliable_pipeline = new ReliableCommandPipeline({
|
|
646
|
-
channel,
|
|
647
|
-
packet_type: NetworkPacketType.RELIABLE_COMMAND,
|
|
648
|
-
});
|
|
649
636
|
|
|
650
|
-
//
|
|
651
|
-
//
|
|
652
|
-
|
|
653
|
-
// peer's channel. `indices[0..count)` is a reused internal
|
|
654
|
-
// scratch from the assembler — only valid for the call.
|
|
655
|
-
const on_nack = (message_id, indices, count) => {
|
|
656
|
-
this.#send_buffer.position = 0;
|
|
657
|
-
this.#send_buffer.writeUint8(NetworkPacketType.NACK_FRAGMENT);
|
|
658
|
-
this.#send_buffer.writeUint16LE(message_id);
|
|
659
|
-
this.#send_buffer.writeUint8(count);
|
|
660
|
-
for (let i = 0; i < count; i++) {
|
|
661
|
-
this.#send_buffer.writeUint8(indices[i]);
|
|
662
|
-
}
|
|
663
|
-
channel.send(this.#send_buffer.raw_bytes, this.#send_buffer.position);
|
|
664
|
-
};
|
|
665
|
-
// Forward pipeline deliveries to the user-facing signal, attributing
|
|
666
|
-
// them to the originating peer.
|
|
667
|
-
reliable_pipeline.onCommand.add((buf, payload_offset, payload_length) => {
|
|
668
|
-
this.onReliableCommand.send4(peer_id, buf, payload_offset, payload_length);
|
|
669
|
-
});
|
|
670
|
-
|
|
671
|
-
// Recursive dispatch helper. Used for both incoming transport bytes
|
|
672
|
-
// AND for reassembled FRAGMENT payloads (so the same switch handles
|
|
673
|
-
// both transparent and fragmented delivery of any packet type).
|
|
674
|
-
const dispatch = (bytes, length) => {
|
|
637
|
+
// Every message the connection hands over, unreliable or from a lane, is one of
|
|
638
|
+
// NetworkPacketType: its first byte picks the path.
|
|
639
|
+
const dispatch = (bytes, offset, length) => {
|
|
675
640
|
if (length < 1) {
|
|
676
641
|
// malformed: no type byte
|
|
677
642
|
return;
|
|
678
643
|
}
|
|
679
644
|
|
|
680
645
|
this.#recv_buffer.position = 0;
|
|
681
|
-
this.#recv_buffer.writeBytes(bytes,
|
|
646
|
+
this.#recv_buffer.writeBytes(bytes, offset, length);
|
|
682
647
|
this.#recv_buffer.position = 0;
|
|
683
648
|
|
|
684
649
|
const packet_type = this.#recv_buffer.readUint8();
|
|
@@ -718,70 +683,14 @@ export class NetworkPeer {
|
|
|
718
683
|
this.onAuthState.send4(peer_id, frame_number, network_id, this.#recv_buffer);
|
|
719
684
|
break;
|
|
720
685
|
}
|
|
721
|
-
case NetworkPacketType.FRAGMENT: {
|
|
722
|
-
// Fragment header layout (after the leading type byte):
|
|
723
|
-
// uint16 message_id (LE), uint8 chunk_index, uint8 total_chunks
|
|
724
|
-
const message_id = this.#recv_buffer.readUint16LE();
|
|
725
|
-
const chunk_index = this.#recv_buffer.readUint8();
|
|
726
|
-
const total_chunks = this.#recv_buffer.readUint8();
|
|
727
|
-
const chunk_offset = this.#recv_buffer.position;
|
|
728
|
-
const chunk_length = length - chunk_offset;
|
|
729
|
-
const reassembled = fragment_assembler.receive(
|
|
730
|
-
message_id, chunk_index, total_chunks,
|
|
731
|
-
bytes, chunk_offset, chunk_length,
|
|
732
|
-
);
|
|
733
|
-
if (reassembled !== null) {
|
|
734
|
-
// Defence-in-depth: don't allow nested fragmentation
|
|
735
|
-
// (would indicate a sender bug; ignore silently).
|
|
736
|
-
if (reassembled[0] !== NetworkPacketType.FRAGMENT) {
|
|
737
|
-
dispatch(reassembled, reassembled.length);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
break;
|
|
741
|
-
}
|
|
742
|
-
case NetworkPacketType.NACK_FRAGMENT: {
|
|
743
|
-
// Receiver is asking for specific chunks of a
|
|
744
|
-
// previously-sent fragmented message.
|
|
745
|
-
// uint16 message_id (LE), uint8 missing_count,
|
|
746
|
-
// uint8 missing_indices[missing_count]
|
|
747
|
-
const message_id = this.#recv_buffer.readUint16LE();
|
|
748
|
-
const missing_count = this.#recv_buffer.readUint8();
|
|
749
|
-
const entry = fragment_retention.consume_nack(message_id);
|
|
750
|
-
if (entry === null) {
|
|
751
|
-
// Either we never retained this id (already evicted /
|
|
752
|
-
// never sent), or the retry budget for it is exhausted.
|
|
753
|
-
// Either way: nothing to retransmit. Drop silently.
|
|
754
|
-
break;
|
|
755
|
-
}
|
|
756
|
-
// The list is the peer's word. A NACK re-sends each chunk
|
|
757
|
-
// of the message at most once, and nothing for an index
|
|
758
|
-
// the message does not have: what one costs is bounded by
|
|
759
|
-
// the message we chose to send, not by what is asked. It
|
|
760
|
-
// used to re-send a chunk as often as it was named — 255
|
|
761
|
-
// times in one NACK, three NACKs for each INITIAL_SYNC.
|
|
762
|
-
const total_chunks = fragment_chunk_count(entry.length);
|
|
763
|
-
const requested = this.#nack_requested;
|
|
764
|
-
requested.fill(0, 0, total_chunks);
|
|
765
|
-
for (let i = 0; i < missing_count; i++) {
|
|
766
|
-
const chunk_index = this.#recv_buffer.readUint8();
|
|
767
|
-
if (chunk_index >= total_chunks || requested[chunk_index] !== 0) continue;
|
|
768
|
-
requested[chunk_index] = 1;
|
|
769
|
-
resend_fragment_chunk(
|
|
770
|
-
entry.payload, entry.length, message_id, chunk_index,
|
|
771
|
-
NetworkPacketType.FRAGMENT, this.#fragment_scratch,
|
|
772
|
-
(chunk_bytes, chunk_length) => channel.send(chunk_bytes, chunk_length),
|
|
773
|
-
);
|
|
774
|
-
}
|
|
775
|
-
break;
|
|
776
|
-
}
|
|
777
686
|
case NetworkPacketType.RELIABLE_COMMAND:
|
|
778
|
-
//
|
|
779
|
-
|
|
780
|
-
reliable_pipeline.handle_inbound(this.#recv_buffer, length);
|
|
687
|
+
// the payload is everything after the type byte
|
|
688
|
+
this.onReliableCommand.send4(peer_id, this.#recv_buffer, 1, length - 1);
|
|
781
689
|
break;
|
|
782
690
|
case NetworkPacketType.TIME_DILATION: {
|
|
783
691
|
const depth = this.#recv_buffer.readInt16();
|
|
784
|
-
this.
|
|
692
|
+
const frame_number = this.#recv_buffer.readUintVar();
|
|
693
|
+
this.onTimeDilationFeedback.send3(peer_id, depth, frame_number);
|
|
785
694
|
break;
|
|
786
695
|
}
|
|
787
696
|
case NetworkPacketType.INITIAL_SYNC: {
|
|
@@ -791,7 +700,8 @@ export class NetworkPeer {
|
|
|
791
700
|
const session_token = new Uint8Array(16);
|
|
792
701
|
this.#recv_buffer.readBytes(session_token, 0, 16);
|
|
793
702
|
const frame_number = this.#recv_buffer.readUintVar();
|
|
794
|
-
|
|
703
|
+
const flags = this.#recv_buffer.readUint8();
|
|
704
|
+
this.onInitialSync.send6(peer_id, session_token, frame_number, flags, this.#recv_buffer, length);
|
|
795
705
|
break;
|
|
796
706
|
}
|
|
797
707
|
case NetworkPacketType.RESUME_HELLO: {
|
|
@@ -840,61 +750,45 @@ export class NetworkPeer {
|
|
|
840
750
|
}
|
|
841
751
|
};
|
|
842
752
|
|
|
843
|
-
//
|
|
844
|
-
//
|
|
845
|
-
//
|
|
846
|
-
//
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
// __credit_confirmed.
|
|
851
|
-
const on_acked = (seq) => {
|
|
852
|
-
const pending = seq_to_pending.get(seq);
|
|
853
|
-
if (pending === undefined) return;
|
|
854
|
-
seq_to_pending.delete(seq);
|
|
855
|
-
pending.unacked--;
|
|
856
|
-
if (pending.unacked === 0 && !pending.abandoned) {
|
|
857
|
-
this.#credit_confirmed(peer_id, confirmed, pending);
|
|
858
|
-
}
|
|
753
|
+
// A slice is one unreliable message, so one datagram: its acknowledgement is its delivery.
|
|
754
|
+
// What a delivered slice credits to the baseline is decided in order, by
|
|
755
|
+
// #credit_confirmed. A lost one credits nothing: the frames stay owed and the back-fill
|
|
756
|
+
// packs them again. Every slice is resolved exactly once, acked or lost.
|
|
757
|
+
const on_acked = (token) => {
|
|
758
|
+
this.#credit_confirmed(peer_id, confirmed, pending.frame_start(token), pending.frame_end(token), pending.head(token));
|
|
759
|
+
pending.release(token);
|
|
859
760
|
};
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
// leaves a dead seq→record entry. The baseline must NOT advance (the
|
|
863
|
-
// frame range was never confirmed; the back-fill re-sends it under a
|
|
864
|
-
// fresh seq), and the record is marked abandoned so that siblings
|
|
865
|
-
// acking afterwards cannot complete it — one lost fragment forfeits the
|
|
866
|
-
// whole message. The mapping is reclaimed either way, otherwise
|
|
867
|
-
// lost-packet entries accumulate across the session until the seq value
|
|
868
|
-
// is reused on wrap.
|
|
869
|
-
//
|
|
870
|
-
// Every outstanding seq is resolved by Channel as exactly one of acked
|
|
871
|
-
// or lost — via the ack bitfield, the 33-seq window age-out, or the
|
|
872
|
-
// max_in_flight eviction — so no record can be stranded by a seq that
|
|
873
|
-
// never reports.
|
|
874
|
-
const on_lost = (seq) => {
|
|
875
|
-
const pending = seq_to_pending.get(seq);
|
|
876
|
-
if (pending === undefined) return;
|
|
877
|
-
seq_to_pending.delete(seq);
|
|
878
|
-
pending.unacked--;
|
|
879
|
-
pending.abandoned = true;
|
|
761
|
+
const on_lost = (token) => {
|
|
762
|
+
pending.release(token);
|
|
880
763
|
};
|
|
881
764
|
|
|
882
765
|
// Untrusted-input boundary. A structurally-malformed or truncated
|
|
883
|
-
//
|
|
884
|
-
//
|
|
885
|
-
//
|
|
886
|
-
//
|
|
887
|
-
//
|
|
888
|
-
//
|
|
889
|
-
//
|
|
890
|
-
const
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
766
|
+
// message (spoofed/corrupt bytes, mismatched peer build) is dropped and
|
|
767
|
+
// counted — the "discard the bad record, keep the connection" posture —
|
|
768
|
+
// rather than throwing out of the transport's receive callback and
|
|
769
|
+
// crashing the process. A RangeError is a BinaryBuffer read past its
|
|
770
|
+
// backing store, i.e. the same malformed-input symptom. Any OTHER error
|
|
771
|
+
// is a genuine bug in a packet handler and is rethrown so it is not
|
|
772
|
+
// silently swallowed.
|
|
773
|
+
const on_message = (bytes, offset, length) => {
|
|
774
|
+
const held = this.#peers.get(peer_id);
|
|
775
|
+
if (held !== undefined && held.inbound_held && length > 0) {
|
|
776
|
+
const type = bytes[offset];
|
|
777
|
+
if (type === NetworkPacketType.ACTION_STREAM || type === NetworkPacketType.AUTH_STATE) {
|
|
778
|
+
// about a world this peer is still being given: kept for release_inbound
|
|
779
|
+
if (held.inbound_held_bytes + length > this.#connection_options.max_queued_bytes) {
|
|
780
|
+
// Dropped, it would be a frame missing from the stream for good: the
|
|
781
|
+
// connection can no longer give this peer a whole world.
|
|
782
|
+
this.onProtocolError.send2(peer_id, `held action stream past max_queued_bytes ${this.#connection_options.max_queued_bytes} while the world arrives`);
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
held.inbound_queue.push(bytes.slice(offset, offset + length));
|
|
786
|
+
held.inbound_held_bytes += length;
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
896
790
|
try {
|
|
897
|
-
dispatch(bytes, length);
|
|
791
|
+
dispatch(bytes, offset, length);
|
|
898
792
|
} catch (e) {
|
|
899
793
|
if (e instanceof MalformedPacketError || e instanceof RangeError) {
|
|
900
794
|
this.#malformed_packets_dropped++;
|
|
@@ -905,23 +799,45 @@ export class NetworkPeer {
|
|
|
905
799
|
}
|
|
906
800
|
};
|
|
907
801
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
802
|
+
connection.onMessage.add(on_message);
|
|
803
|
+
connection.onMessageAcked.add(on_acked);
|
|
804
|
+
connection.onMessageLost.add(on_lost);
|
|
805
|
+
connection.onMalformedDatagram.add((reason) => {
|
|
806
|
+
this.#malformed_packets_dropped++;
|
|
807
|
+
this.onMalformedPacket.send2(peer_id, new MalformedPacketError(`NetworkPeer: datagram dropped: ${reason}`));
|
|
808
|
+
});
|
|
809
|
+
connection.onProtocolError.add((reason) => {
|
|
810
|
+
this.onProtocolError.send2(peer_id, reason);
|
|
811
|
+
});
|
|
911
812
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
813
|
+
// Liveness: any datagram at all — an ACK alone, a malformed one — is evidence the peer is
|
|
814
|
+
// there. Counted at the transport, ahead of the connection.
|
|
815
|
+
const conn = {
|
|
816
|
+
connection, transport, pending, confirmed,
|
|
817
|
+
on_receive: null,
|
|
917
818
|
inbound_count: 0,
|
|
918
819
|
// the first frame the action stream may carry to this peer; see hold_outbound
|
|
919
820
|
outbound_floor: 0,
|
|
920
|
-
|
|
821
|
+
// action-stream frames too large for a datagram, in flight on Lane.FRAMES
|
|
822
|
+
reliable_frames: new ReliableFrames(),
|
|
823
|
+
// see hold_inbound
|
|
824
|
+
inbound_held: false,
|
|
825
|
+
/** @type {Uint8Array[]} */
|
|
826
|
+
inbound_queue: [],
|
|
827
|
+
inbound_held_bytes: 0,
|
|
828
|
+
on_message,
|
|
829
|
+
};
|
|
830
|
+
conn.on_receive = () => {
|
|
831
|
+
conn.inbound_count++;
|
|
832
|
+
};
|
|
833
|
+
transport.onReceive.add(conn.on_receive);
|
|
834
|
+
|
|
835
|
+
this.#peers.set(peer_id, conn);
|
|
921
836
|
}
|
|
922
837
|
|
|
923
838
|
/**
|
|
924
|
-
* Unwire and forget a peer.
|
|
839
|
+
* Unwire and forget a peer. Sends nothing: the transport may already be gone. To say a last
|
|
840
|
+
* word first — a DISCONNECT — queue it and call {@link flush_peer}.
|
|
925
841
|
* @param {number} peer_id
|
|
926
842
|
*/
|
|
927
843
|
disconnect_peer(peer_id) {
|
|
@@ -929,25 +845,11 @@ export class NetworkPeer {
|
|
|
929
845
|
const conn = this.#peers.get(peer_id);
|
|
930
846
|
if (conn === undefined) return;
|
|
931
847
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
// without this, the orphaned channel keeps consuming inbound packets
|
|
938
|
-
// and corrupts ack state in parallel with whatever channel replaces it.
|
|
939
|
-
conn.channel.dispose();
|
|
940
|
-
|
|
941
|
-
// Drop any in-flight fragment reassemblies for this peer — a fresh
|
|
942
|
-
// connection on the same peer_id should start clean.
|
|
943
|
-
conn.fragment_assembler.clear();
|
|
944
|
-
// Same for the sender-side retention buffer: nothing about the
|
|
945
|
-
// previous connection's retransmit history should leak across.
|
|
946
|
-
conn.fragment_retention.clear();
|
|
947
|
-
|
|
948
|
-
// Detach the reliable pipeline (drops its channel subscriptions and
|
|
949
|
-
// any unacked / received state).
|
|
950
|
-
conn.reliable_pipeline.dispose();
|
|
848
|
+
// Detach from the transport — it may be reused by the next connection on this peer id,
|
|
849
|
+
// and an orphaned connection would keep consuming its packets — and drop everything queued
|
|
850
|
+
// or in flight. Safe from inside the connection's own dispatch: it stops at the next message.
|
|
851
|
+
conn.transport.onReceive.remove(conn.on_receive);
|
|
852
|
+
conn.connection.dispose();
|
|
951
853
|
|
|
952
854
|
this.#peers.delete(peer_id);
|
|
953
855
|
this.baseline.forget(peer_id);
|
|
@@ -989,28 +891,27 @@ export class NetworkPeer {
|
|
|
989
891
|
}
|
|
990
892
|
|
|
991
893
|
/**
|
|
992
|
-
* Number of
|
|
894
|
+
* Number of action-stream slices sent to `peer_id` still awaiting an
|
|
993
895
|
* ack-or-lost verdict. Returns 0 for an unknown peer.
|
|
994
896
|
*
|
|
995
|
-
* Diagnostics: this
|
|
996
|
-
*
|
|
997
|
-
* value that only grows is a leak in the ack accounting.
|
|
897
|
+
* Diagnostics: this must fall back to 0 once a stream of acks has resolved
|
|
898
|
+
* everything sent. A value that only grows is a leak in the ack accounting.
|
|
998
899
|
* @param {number} peer_id
|
|
999
900
|
* @returns {number}
|
|
1000
901
|
*/
|
|
1001
902
|
pending_ack_count(peer_id) {
|
|
1002
903
|
const conn = this.#peers.get(peer_id);
|
|
1003
|
-
return conn === undefined ? 0 : conn.
|
|
904
|
+
return conn === undefined ? 0 : conn.pending.size;
|
|
1004
905
|
}
|
|
1005
906
|
|
|
1006
907
|
/**
|
|
1007
|
-
*
|
|
908
|
+
* A peer's connection, for diagnostics: round-trip time, statistics, what is in flight.
|
|
1008
909
|
* @param {number} peer_id
|
|
1009
|
-
* @returns {
|
|
910
|
+
* @returns {Connection|undefined}
|
|
1010
911
|
*/
|
|
1011
|
-
|
|
912
|
+
connection_for(peer_id) {
|
|
1012
913
|
const conn = this.#peers.get(peer_id);
|
|
1013
|
-
return conn === undefined ? undefined : conn.
|
|
914
|
+
return conn === undefined ? undefined : conn.connection;
|
|
1014
915
|
}
|
|
1015
916
|
|
|
1016
917
|
/**
|
|
@@ -1049,6 +950,49 @@ export class NetworkPeer {
|
|
|
1049
950
|
conn.outbound_floor = from_frame;
|
|
1050
951
|
}
|
|
1051
952
|
|
|
953
|
+
/**
|
|
954
|
+
* Keep the action stream and AUTH_STATE that `peer_id` sends, unapplied, until
|
|
955
|
+
* {@link release_inbound}; everything else it sends is handled as ever.
|
|
956
|
+
*
|
|
957
|
+
* For a client being given a world in pages. The host releases its action stream from the frame
|
|
958
|
+
* after the last page, so the stream's datagrams can overtake the last pages on the way; what
|
|
959
|
+
* they carry is about entities the client may not hold yet. Held, they are applied after the
|
|
960
|
+
* world is complete, in the order they came.
|
|
961
|
+
*
|
|
962
|
+
* Held messages are copies, bounded by `max_queued_bytes`; past that the connection can no
|
|
963
|
+
* longer give the peer a whole stream, and says so on {@link onProtocolError}.
|
|
964
|
+
*
|
|
965
|
+
* @param {number} peer_id
|
|
966
|
+
*/
|
|
967
|
+
hold_inbound(peer_id) {
|
|
968
|
+
assert.isNonNegativeInteger(peer_id, 'peer_id');
|
|
969
|
+
const conn = this.#peers.get(peer_id);
|
|
970
|
+
if (conn === undefined) throw new Error(`NetworkPeer.hold_inbound: peer ${peer_id} not connected`);
|
|
971
|
+
|
|
972
|
+
conn.inbound_held = true;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* Stop holding `peer_id`'s action stream and AUTH_STATE, and handle what was held, in the order
|
|
977
|
+
* it arrived.
|
|
978
|
+
*
|
|
979
|
+
* @param {number} peer_id
|
|
980
|
+
*/
|
|
981
|
+
release_inbound(peer_id) {
|
|
982
|
+
assert.isNonNegativeInteger(peer_id, 'peer_id');
|
|
983
|
+
const conn = this.#peers.get(peer_id);
|
|
984
|
+
if (conn === undefined) throw new Error(`NetworkPeer.release_inbound: peer ${peer_id} not connected`);
|
|
985
|
+
|
|
986
|
+
conn.inbound_held = false;
|
|
987
|
+
const queue = conn.inbound_queue;
|
|
988
|
+
conn.inbound_queue = [];
|
|
989
|
+
conn.inbound_held_bytes = 0;
|
|
990
|
+
for (let i = 0; i < queue.length; i++) {
|
|
991
|
+
conn.on_message(queue[i], 0, queue[i].length);
|
|
992
|
+
if (!this.#peers.has(peer_id)) return;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
1052
996
|
/**
|
|
1053
997
|
* Open the action log for `frame_number`. Call before running game logic
|
|
1054
998
|
* for the tick. The user's code (or the engine's `EntityManager.simulate`)
|
|
@@ -1070,13 +1014,8 @@ export class NetworkPeer {
|
|
|
1070
1014
|
}
|
|
1071
1015
|
|
|
1072
1016
|
/**
|
|
1073
|
-
* Close the current tick
|
|
1074
|
-
*
|
|
1075
|
-
* and sends via the channel; records the seqs the send went out under so
|
|
1076
|
-
* that acks for all of them advance the baseline.
|
|
1077
|
-
*
|
|
1078
|
-
* If a {@link MutationLedger} was supplied at construction, this tick's
|
|
1079
|
-
* accumulated changed-entity set is also compacted into the ledger.
|
|
1017
|
+
* Close the current tick, queue the action stream for every peer (see
|
|
1018
|
+
* {@link flush_outbound}), and send everything queued ({@link send_queued}).
|
|
1080
1019
|
*/
|
|
1081
1020
|
end_tick() {
|
|
1082
1021
|
if (!this.#tick_open) {
|
|
@@ -1086,6 +1025,38 @@ export class NetworkPeer {
|
|
|
1086
1025
|
this.#tick_open = false;
|
|
1087
1026
|
|
|
1088
1027
|
this.flush_outbound(this.#current_frame);
|
|
1028
|
+
this.send_queued();
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
/**
|
|
1032
|
+
* Send what is queued for every peer: one flush of each connection, packing the tick's
|
|
1033
|
+
* messages into as few datagrams as fit, and running its loss and probe timers. Also sends a
|
|
1034
|
+
* bare acknowledgement to a peer that has sent something since the last one.
|
|
1035
|
+
*/
|
|
1036
|
+
send_queued() {
|
|
1037
|
+
for (const conn of this.#peers.values()) {
|
|
1038
|
+
conn.connection.flush();
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Send what is queued for one peer now. For a last word before {@link disconnect_peer}:
|
|
1044
|
+
* queue the DISCONNECT, flush, then disconnect.
|
|
1045
|
+
* @param {number} peer_id
|
|
1046
|
+
*/
|
|
1047
|
+
flush_peer(peer_id) {
|
|
1048
|
+
const conn = this.#peers.get(peer_id);
|
|
1049
|
+
if (conn !== undefined) conn.connection.flush();
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* The frame `network_id` was last changed by an action this peer executed or applied, or -1.
|
|
1054
|
+
* Stamped at the end of each tick, by {@link flush_outbound}.
|
|
1055
|
+
* @param {number} network_id
|
|
1056
|
+
* @returns {number}
|
|
1057
|
+
*/
|
|
1058
|
+
last_changed_frame(network_id) {
|
|
1059
|
+
return network_id < this.#last_changed.length ? this.#last_changed[network_id] : -1;
|
|
1089
1060
|
}
|
|
1090
1061
|
|
|
1091
1062
|
/**
|
|
@@ -1101,9 +1072,12 @@ export class NetworkPeer {
|
|
|
1101
1072
|
* MutationLedger (if configured), then packs frames
|
|
1102
1073
|
* `[last_acked+1, current_frame]` for each peer via
|
|
1103
1074
|
* `Replicator.pack_for_peer` into up to {@link max_packets_per_tick}
|
|
1104
|
-
*
|
|
1105
|
-
*
|
|
1106
|
-
*
|
|
1075
|
+
* slices, each the next part of that range and one datagram at most; a
|
|
1076
|
+
* frame too large for a datagram goes on {@link Lane.FRAMES}. Empty packs
|
|
1077
|
+
* (no in-scope actions) are not sent. Stamps and clears the per-tick
|
|
1078
|
+
* changed-entity set.
|
|
1079
|
+
*
|
|
1080
|
+
* Only queues: {@link send_queued} sends.
|
|
1107
1081
|
*
|
|
1108
1082
|
* @param {number} current_frame
|
|
1109
1083
|
*/
|
|
@@ -1114,7 +1088,10 @@ export class NetworkPeer {
|
|
|
1114
1088
|
// (Order doesn't strictly matter for correctness, but keeping the ledger
|
|
1115
1089
|
// up-to-date as soon as possible reduces edge-case race windows for
|
|
1116
1090
|
// recovery requests that arrive immediately after.)
|
|
1117
|
-
|
|
1091
|
+
this.#stamp_frame = current_frame;
|
|
1092
|
+
this.#changed_entities.for_each(this.#stamp_changed);
|
|
1093
|
+
|
|
1094
|
+
if (this.mutation_ledger !== null) {
|
|
1118
1095
|
this.mutation_ledger.record_tick(current_frame, this.#changed_entities);
|
|
1119
1096
|
|
|
1120
1097
|
// ...and trim. The ledger documents that "caller invokes drop_through periodically",
|
|
@@ -1175,7 +1152,7 @@ export class NetworkPeer {
|
|
|
1175
1152
|
//
|
|
1176
1153
|
// Last, the peer's outbound floor: nothing before it is ever sent,
|
|
1177
1154
|
// and a held peer's floor is past every frame (see hold_outbound).
|
|
1178
|
-
|
|
1155
|
+
let start = Math.max(
|
|
1179
1156
|
last_acked + 1,
|
|
1180
1157
|
current_frame - this.action_log.frame_capacity + 1,
|
|
1181
1158
|
0,
|
|
@@ -1183,42 +1160,62 @@ export class NetworkPeer {
|
|
|
1183
1160
|
);
|
|
1184
1161
|
if (start > current_frame) continue;
|
|
1185
1162
|
|
|
1186
|
-
//
|
|
1187
|
-
//
|
|
1163
|
+
// Frames too large for a datagram went on Lane.FRAMES, which delivers them in order:
|
|
1164
|
+
// credit each once it has arrived. Until then the pack skips the frames one covers.
|
|
1165
|
+
const reliable_frames = conn.reliable_frames;
|
|
1166
|
+
while (reliable_frames.count > 0 && conn.connection.is_delivered(Lane.FRAMES, reliable_frames.front_mark())) {
|
|
1167
|
+
this.#credit_confirmed(peer_id, conn.confirmed,
|
|
1168
|
+
reliable_frames.front_start(), reliable_frames.front_end(), reliable_frames.front_head());
|
|
1169
|
+
reliable_frames.shift();
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
let from = start;
|
|
1173
|
+
let at_pack_start = true;
|
|
1174
|
+
|
|
1175
|
+
// Up to `max_packets_per_tick` slices, each bounded to one datagram
|
|
1176
|
+
// and each taking the next part of the owed range.
|
|
1188
1177
|
//
|
|
1189
|
-
// Bounding a
|
|
1190
|
-
//
|
|
1178
|
+
// Bounding a slice to one datagram is load-bearing. A multi-datagram
|
|
1179
|
+
// unreliable message is confirmed only if EVERY datagram survives, so a
|
|
1191
1180
|
// send that grows with the owed range is self-defeating under
|
|
1192
|
-
// loss: one lost
|
|
1193
|
-
// pack, which raises the
|
|
1181
|
+
// loss: one lost datagram pins the baseline, which widens the next
|
|
1182
|
+
// pack, which raises the datagram count N, which drops
|
|
1194
1183
|
// P(all arrive) = (1-p)^N geometrically — the range then widens
|
|
1195
1184
|
// faster than it drains and delivery collapses. Split into whole
|
|
1196
|
-
//
|
|
1185
|
+
// datagrams instead, each slice is confirmed on its own and a loss
|
|
1197
1186
|
// forfeits one slice, not the tick.
|
|
1198
1187
|
//
|
|
1199
1188
|
// Sending more than one is what keeps the stream up with the
|
|
1200
1189
|
// simulation. A slice is re-sent every tick until its ack returns,
|
|
1201
1190
|
// so the baseline moves by at most a tick's worth of slices per
|
|
1202
|
-
// round trip, while the sim produces a frame per tick. One
|
|
1191
|
+
// round trip, while the sim produces a frame per tick. One datagram
|
|
1203
1192
|
// a tick therefore keeps up only while a round trip's frames fit
|
|
1204
|
-
// one
|
|
1193
|
+
// one datagram; past that the owed range grows until it meets the
|
|
1205
1194
|
// ring floor, a ring of frames is lost crossing it, and everything
|
|
1206
1195
|
// after arrives a ring late — on a link that loses nothing. The
|
|
1207
1196
|
// pack is oldest-owed-first, which is what the range order already
|
|
1208
1197
|
// gives.
|
|
1209
1198
|
//
|
|
1210
|
-
// The budget is what is left of one
|
|
1211
|
-
// the slice header, read from the buffer rather than
|
|
1212
|
-
// constant: `pack_for_peer` measures its budget from the
|
|
1213
|
-
// position
|
|
1214
|
-
|
|
1215
|
-
// each full pack one byte over the limit and quietly fragments it
|
|
1216
|
-
// again.
|
|
1217
|
-
let from = start;
|
|
1199
|
+
// The budget is what is left of one unreliable message after the
|
|
1200
|
+
// prefix and the slice header, read from the buffer rather than
|
|
1201
|
+
// written as a constant: `pack_for_peer` measures its budget from the
|
|
1202
|
+
// current position.
|
|
1203
|
+
const budget = conn.connection.max_unreliable_message_bytes;
|
|
1218
1204
|
for (let n = 0; n < this.max_packets_per_tick && from <= current_frame; n++) {
|
|
1205
|
+
// Skip what is already on its way reliably. Whatever follows it is not a
|
|
1206
|
+
// head: the receiver holds it until the reliable frame lands.
|
|
1207
|
+
for (let covered = reliable_frames.covering_end(from); covered >= 0; covered = reliable_frames.covering_end(from)) {
|
|
1208
|
+
from = covered + 1;
|
|
1209
|
+
at_pack_start = false;
|
|
1210
|
+
}
|
|
1211
|
+
if (from > current_frame) break;
|
|
1212
|
+
|
|
1213
|
+
// A slice is a head when it begins at the pack start: nothing the
|
|
1214
|
+
// sender can still send lies before it.
|
|
1215
|
+
const head = at_pack_start && from === start;
|
|
1219
1216
|
this.#send_buffer.position = 0;
|
|
1220
1217
|
// Packet-type prefix, then the slice header: the range this
|
|
1221
|
-
// packet covers and whether it is
|
|
1218
|
+
// packet covers and whether it is a head, which is
|
|
1222
1219
|
// what lets the receiver apply slices in frame order (see
|
|
1223
1220
|
// Replicator.unpack_from_peer). frame_end is back-patched once
|
|
1224
1221
|
// the pack has decided how far it got.
|
|
@@ -1226,10 +1223,10 @@ export class NetworkPeer {
|
|
|
1226
1223
|
this.#send_buffer.writeUint32(from);
|
|
1227
1224
|
const frame_end_position = this.#send_buffer.position;
|
|
1228
1225
|
this.#send_buffer.writeUint32(0);
|
|
1229
|
-
this.#send_buffer.writeUint8(
|
|
1226
|
+
this.#send_buffer.writeUint8(head ? 1 : 0);
|
|
1230
1227
|
const packed_through = this.replicator.pack_for_peer(
|
|
1231
1228
|
peer_id, from, current_frame, this.#send_buffer,
|
|
1232
|
-
|
|
1229
|
+
budget - this.#send_buffer.position,
|
|
1233
1230
|
);
|
|
1234
1231
|
const length = this.#send_buffer.position;
|
|
1235
1232
|
// Just the prefix and header → nothing in scope left to send
|
|
@@ -1239,35 +1236,44 @@ export class NetworkPeer {
|
|
|
1239
1236
|
this.#send_buffer.writeUint32(packed_through);
|
|
1240
1237
|
this.#send_buffer.position = length;
|
|
1241
1238
|
|
|
1242
|
-
|
|
1239
|
+
if (length > budget) {
|
|
1240
|
+
// One frame larger than a datagram: `pack_for_peer` writes a first group
|
|
1241
|
+
// that cannot fit anywhere, since no smaller pack could carry it. It goes
|
|
1242
|
+
// reliably on Lane.FRAMES, once: re-sending a frame of this size every tick
|
|
1243
|
+
// until its ack returns is what the back-fill would do with it. It keeps the
|
|
1244
|
+
// head flag the slice was given, so one that does not start the pack is held
|
|
1245
|
+
// by the receiver until the frames before it land. A lane already holding
|
|
1246
|
+
// all it may waits for room.
|
|
1247
|
+
if (length > conn.connection.max_message_bytes) {
|
|
1248
|
+
// Larger than any message: it can never be delivered. Given up — said so —
|
|
1249
|
+
// once it is the pack start, so the stream goes on behind it instead of
|
|
1250
|
+
// stopping at it until the ring retires it. Never a throw: one peer's
|
|
1251
|
+
// frame must not stop the tick for every other peer.
|
|
1252
|
+
if (!head) break;
|
|
1253
|
+
this.onFrameTooLarge.send4(peer_id, from, packed_through, length);
|
|
1254
|
+
this.#credit_confirmed(peer_id, conn.confirmed, from, packed_through, true);
|
|
1255
|
+
start = packed_through + 1;
|
|
1256
|
+
from = start;
|
|
1257
|
+
continue;
|
|
1258
|
+
}
|
|
1259
|
+
if (conn.connection.unacked_bytes(Lane.FRAMES) + length > this.#connection_options.max_queued_bytes) break;
|
|
1260
|
+
const mark = conn.connection.send_reliable(Lane.FRAMES, this.#send_buffer.raw_bytes, 0, length);
|
|
1261
|
+
reliable_frames.push(from, packed_through, head, mark);
|
|
1262
|
+
from = packed_through + 1;
|
|
1263
|
+
at_pack_start = false;
|
|
1264
|
+
continue;
|
|
1265
|
+
}
|
|
1243
1266
|
|
|
1244
|
-
// One record shared by every seq the send produced. Frames
|
|
1245
|
-
// [from, packed_through] are confirmed only when all of those
|
|
1246
|
-
// seqs ack; a loss on any of them abandons the record and
|
|
1247
|
-
// leaves the range owed, so a later tick's pack picks it up
|
|
1248
|
-
// again.
|
|
1249
|
-
//
|
|
1250
1267
|
// frame_end is what the pack actually held, NOT current_frame:
|
|
1251
1268
|
// the budget may have stopped it short, and crediting frames
|
|
1252
|
-
// that were left out of the
|
|
1253
|
-
// back-fill unsent
|
|
1254
|
-
// message to its first fragment, one layer up.
|
|
1269
|
+
// that were left out of the slice would retire them from the
|
|
1270
|
+
// back-fill unsent.
|
|
1255
1271
|
//
|
|
1256
|
-
// Only
|
|
1257
|
-
//
|
|
1258
|
-
//
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
const pending = {
|
|
1262
|
-
frame_start: from,
|
|
1263
|
-
frame_end: packed_through,
|
|
1264
|
-
head: n === 0,
|
|
1265
|
-
unacked: seq_count,
|
|
1266
|
-
abandoned: false,
|
|
1267
|
-
};
|
|
1268
|
-
for (let i = 0; i < seq_count; i++) {
|
|
1269
|
-
conn.seq_to_pending.set(this.#sent_seqs[i], pending);
|
|
1270
|
-
}
|
|
1272
|
+
// Only a head starts at the pack start. The rest start where the
|
|
1273
|
+
// previous slice stopped, and their confirmation is held until
|
|
1274
|
+
// everything before them is confirmed too — see #credit_confirmed.
|
|
1275
|
+
const token = conn.pending.acquire(from, packed_through, head);
|
|
1276
|
+
conn.connection.send_unreliable(this.#send_buffer.raw_bytes, 0, length, token);
|
|
1271
1277
|
|
|
1272
1278
|
from = packed_through + 1;
|
|
1273
1279
|
}
|
|
@@ -1275,41 +1281,25 @@ export class NetworkPeer {
|
|
|
1275
1281
|
|
|
1276
1282
|
// Reset the per-tick changed-entity set so the next tick starts clean.
|
|
1277
1283
|
// (begin_tick also clears it; the dual call is harmless.)
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
// Per-tick fragment maintenance: age out sender-side retention and drive NACK emission for
|
|
1281
|
-
// any incomplete inbound messages. Runs AFTER the action-stream send loop so the shared
|
|
1282
|
-
// #send_buffer is free for the on_nack closure to reuse.
|
|
1283
|
-
//
|
|
1284
|
-
// Here and not in `end_tick`: a host never calls `end_tick`. ServerAuthoritativeServer
|
|
1285
|
-
// bypasses it and drives `flush_outbound` directly because it manages action_log frames
|
|
1286
|
-
// itself across the rollback replay, so with these two calls one level up, NACK recovery and
|
|
1287
|
-
// retention age-out were inoperative in the client -> host direction — the direction that
|
|
1288
|
-
// carries player input.
|
|
1289
|
-
const now_ms = performance.now();
|
|
1290
|
-
for (const [, conn] of this.#peers) {
|
|
1291
|
-
conn.fragment_retention.service(now_ms);
|
|
1292
|
-
conn.fragment_assembler.service(now_ms, conn.on_nack);
|
|
1293
|
-
}
|
|
1284
|
+
this.#changed_entities.clear();
|
|
1294
1285
|
}
|
|
1295
1286
|
|
|
1296
1287
|
/**
|
|
1297
|
-
* A
|
|
1298
|
-
*
|
|
1299
|
-
*
|
|
1300
|
-
* confirmed so far run contiguously.
|
|
1288
|
+
* A slice has been delivered, so the receiver has applied every frame it
|
|
1289
|
+
* carried. Record those frames, then advance the peer's baseline as far as
|
|
1290
|
+
* the frames confirmed so far run contiguously.
|
|
1301
1291
|
*
|
|
1302
1292
|
* The order matters because a tick may send several slices and they
|
|
1303
1293
|
* confirm independently. A later slice landing while an earlier one is
|
|
1304
1294
|
* still in flight must not credit the earlier one's frames: they are
|
|
1305
1295
|
* still owed, and crediting them would retire them from the back-fill
|
|
1306
1296
|
* unsent. So a slice is credited only once the baseline has reached the
|
|
1307
|
-
* frame before it. The exception is
|
|
1308
|
-
*
|
|
1309
|
-
*
|
|
1310
|
-
*
|
|
1311
|
-
*
|
|
1312
|
-
*
|
|
1297
|
+
* frame before it. The exception is a head. Its start IS the pack start —
|
|
1298
|
+
* `last_acked + 1`, the ring floor or the peer's outbound floor, whichever
|
|
1299
|
+
* is newest — so nothing sendable lies before it and its confirmation
|
|
1300
|
+
* credits outright. That is also how the baseline gets past frames the ring
|
|
1301
|
+
* has already retired, and frames below the outbound floor, which no ack
|
|
1302
|
+
* could ever confirm.
|
|
1313
1303
|
*
|
|
1314
1304
|
* `confirmed` is a ring indexed by frame modulo capacity that stores the
|
|
1315
1305
|
* frame number, so a slot whose frame has since been overwritten reads as
|
|
@@ -1321,19 +1311,21 @@ export class NetworkPeer {
|
|
|
1321
1311
|
*
|
|
1322
1312
|
* @param {number} peer_id
|
|
1323
1313
|
* @param {Int32Array} confirmed the peer's confirmed-frame ring
|
|
1324
|
-
* @param {
|
|
1314
|
+
* @param {number} frame_start first frame of the delivered slice
|
|
1315
|
+
* @param {number} frame_end last frame of the delivered slice
|
|
1316
|
+
* @param {boolean} head the slice began at the pack start
|
|
1325
1317
|
* @private
|
|
1326
1318
|
*/
|
|
1327
|
-
#credit_confirmed(peer_id, confirmed,
|
|
1319
|
+
#credit_confirmed(peer_id, confirmed, frame_start, frame_end, head) {
|
|
1328
1320
|
const capacity = confirmed.length;
|
|
1329
|
-
for (let f =
|
|
1321
|
+
for (let f = frame_start; f <= frame_end; f++) {
|
|
1330
1322
|
confirmed[f % capacity] = f;
|
|
1331
1323
|
}
|
|
1332
1324
|
|
|
1333
1325
|
const before = this.baseline.last_acked(peer_id);
|
|
1334
1326
|
let last_acked = before;
|
|
1335
|
-
if (
|
|
1336
|
-
last_acked =
|
|
1327
|
+
if (head && frame_end > last_acked) {
|
|
1328
|
+
last_acked = frame_end;
|
|
1337
1329
|
}
|
|
1338
1330
|
while (confirmed[(last_acked + 1) % capacity] === last_acked + 1) {
|
|
1339
1331
|
last_acked++;
|
|
@@ -1343,60 +1335,13 @@ export class NetworkPeer {
|
|
|
1343
1335
|
}
|
|
1344
1336
|
}
|
|
1345
1337
|
|
|
1346
|
-
/**
|
|
1347
|
-
* Send a logical payload to a connected peer, fragmenting transparently
|
|
1348
|
-
* if it exceeds the channel's single-packet capacity.
|
|
1349
|
-
*
|
|
1350
|
-
* Fragments either all arrive (and the receiver reassembles) or the
|
|
1351
|
-
* message is lost — there is no partial delivery, and the receiver never
|
|
1352
|
-
* applies a message it could not reassemble.
|
|
1353
|
-
*
|
|
1354
|
-
* A caller that ties delivery state to the ack must therefore wait on
|
|
1355
|
-
* EVERY seq the send produced, not just the first. The action stream's
|
|
1356
|
-
* back-fill does recover a lost message, but only for as long as the
|
|
1357
|
-
* frames stay owed: crediting the range to the first fragment's ack
|
|
1358
|
-
* retires it from the back-fill, and a message whose later fragments were
|
|
1359
|
-
* dropped is then never re-sent and never applied. Pass `seqs_out` to
|
|
1360
|
-
* collect the seqs; {@link NetworkPeer#flush_outbound} does exactly that.
|
|
1361
|
-
*
|
|
1362
|
-
* @param {object} conn entry from __peers
|
|
1363
|
-
* @param {Uint8Array} payload starts with the packet-type byte
|
|
1364
|
-
* @param {number} length
|
|
1365
|
-
* @param {number[]} [seqs_out] when given, cleared and then filled with the
|
|
1366
|
-
* seq of every transport packet emitted, in send order
|
|
1367
|
-
* @private
|
|
1368
|
-
*/
|
|
1369
|
-
#send_to_peer(conn, payload, length, seqs_out = null) {
|
|
1370
|
-
if (seqs_out !== null) seqs_out.length = 0;
|
|
1371
|
-
if (length <= MAX_CHANNEL_PAYLOAD_BYTES) {
|
|
1372
|
-
const seq = conn.channel.send(payload, length);
|
|
1373
|
-
if (seqs_out !== null) seqs_out.push(seq);
|
|
1374
|
-
return;
|
|
1375
|
-
}
|
|
1376
|
-
const message_id = this.#next_fragment_message_id;
|
|
1377
|
-
this.#next_fragment_message_id = seq16_advance(this.#next_fragment_message_id);
|
|
1378
|
-
// Retain the source bytes so we can satisfy NACK retransmits.
|
|
1379
|
-
// Copy happens inside retain(); `payload` is the orchestrator's
|
|
1380
|
-
// shared send buffer and will be overwritten by the next call.
|
|
1381
|
-
conn.fragment_retention.retain(message_id, payload, length, performance.now());
|
|
1382
|
-
send_fragmented(
|
|
1383
|
-
payload, length, message_id,
|
|
1384
|
-
NetworkPacketType.FRAGMENT, this.#fragment_scratch,
|
|
1385
|
-
(chunk_bytes, chunk_length) => {
|
|
1386
|
-
const seq = conn.channel.send(chunk_bytes, chunk_length);
|
|
1387
|
-
if (seqs_out !== null) seqs_out.push(seq);
|
|
1388
|
-
},
|
|
1389
|
-
);
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
1338
|
/**
|
|
1393
1339
|
* Send a recovery request to `peer_id`: "tell me the current state of every
|
|
1394
1340
|
* entity that mutated between `start_tick` and `end_tick`." The peer's
|
|
1395
1341
|
* server-side handler ({@link onRecoveryRequest}) is expected to respond by
|
|
1396
1342
|
* calling {@link send_state_burst_for_range}.
|
|
1397
1343
|
*
|
|
1398
|
-
*
|
|
1399
|
-
* lost, the client is expected to retry.
|
|
1344
|
+
* Reliable, on the CONTROL lane.
|
|
1400
1345
|
*
|
|
1401
1346
|
* @param {number} peer_id
|
|
1402
1347
|
* @param {number} start_tick
|
|
@@ -1413,7 +1358,7 @@ export class NetworkPeer {
|
|
|
1413
1358
|
this.#send_buffer.writeUint8(NetworkPacketType.RECOVERY_REQUEST);
|
|
1414
1359
|
this.#send_buffer.writeUintVar(start_tick);
|
|
1415
1360
|
this.#send_buffer.writeUintVar(end_tick);
|
|
1416
|
-
|
|
1361
|
+
conn.connection.send_reliable(Lane.CONTROL, this.#send_buffer.raw_bytes, 0, this.#send_buffer.position);
|
|
1417
1362
|
}
|
|
1418
1363
|
|
|
1419
1364
|
/**
|
|
@@ -1470,10 +1415,9 @@ export class NetworkPeer {
|
|
|
1470
1415
|
});
|
|
1471
1416
|
},
|
|
1472
1417
|
});
|
|
1473
|
-
//
|
|
1474
|
-
//
|
|
1475
|
-
|
|
1476
|
-
this.#send_to_peer(conn, this.#send_buffer.raw_bytes, this.#send_buffer.position);
|
|
1418
|
+
// a recovery response covering many entities easily lands in the
|
|
1419
|
+
// multi-KB range: the BULK lane carries it at the paced rate
|
|
1420
|
+
return conn.connection.send_reliable(Lane.BULK, this.#send_buffer.raw_bytes, 0, this.#send_buffer.position);
|
|
1477
1421
|
}
|
|
1478
1422
|
|
|
1479
1423
|
/**
|
|
@@ -1506,34 +1450,37 @@ export class NetworkPeer {
|
|
|
1506
1450
|
this.#send_buffer.writeUintVar(frame_number);
|
|
1507
1451
|
this.#send_buffer.writeUintVar(network_id);
|
|
1508
1452
|
write_fn(this.#send_buffer);
|
|
1509
|
-
|
|
1453
|
+
conn.connection.send_unreliable(this.#send_buffer.raw_bytes, 0, this.#send_buffer.position, -1);
|
|
1510
1454
|
}
|
|
1511
1455
|
|
|
1512
1456
|
/**
|
|
1513
|
-
*
|
|
1514
|
-
*
|
|
1515
|
-
* header and writes the Snapshotter payload. Fragments transparently.
|
|
1457
|
+
* Queue one INITIAL_SYNC page on the BULK lane: the header, then `length` bytes of
|
|
1458
|
+
* `entities` — a uint32 entity count and that many Snapshotter entity records.
|
|
1516
1459
|
*
|
|
1517
1460
|
* @param {number} peer_id
|
|
1518
1461
|
* @param {Uint8Array} session_token 16-byte UUID v1 identifying this peer-session
|
|
1519
|
-
* @param {number} frame_number server sim frame
|
|
1520
|
-
* @param {
|
|
1462
|
+
* @param {number} frame_number server sim frame the page's state is from
|
|
1463
|
+
* @param {number} flags {@link InitialSyncPage}
|
|
1464
|
+
* @param {Uint8Array} entities
|
|
1465
|
+
* @param {number} length
|
|
1466
|
+
* @returns {number} delivery mark on {@link Lane.BULK}
|
|
1521
1467
|
*/
|
|
1522
|
-
|
|
1468
|
+
send_sync_page(peer_id, session_token, frame_number, flags, entities, length) {
|
|
1523
1469
|
assert.isNonNegativeInteger(peer_id, 'peer_id');
|
|
1524
1470
|
assert.ok(session_token instanceof Uint8Array && session_token.length === 16,
|
|
1525
1471
|
'session_token must be a 16-byte Uint8Array');
|
|
1526
1472
|
assert.isNonNegativeInteger(frame_number, 'frame_number');
|
|
1527
|
-
assert.
|
|
1473
|
+
assert.isNonNegativeInteger(flags, 'flags');
|
|
1528
1474
|
const conn = this.#peers.get(peer_id);
|
|
1529
|
-
if (conn === undefined) throw new Error(`NetworkPeer.
|
|
1475
|
+
if (conn === undefined) throw new Error(`NetworkPeer.send_sync_page: peer ${peer_id} not connected`);
|
|
1530
1476
|
|
|
1531
1477
|
this.#send_buffer.position = 0;
|
|
1532
1478
|
this.#send_buffer.writeUint8(NetworkPacketType.INITIAL_SYNC);
|
|
1533
1479
|
this.#send_buffer.writeBytes(session_token, 0, 16);
|
|
1534
1480
|
this.#send_buffer.writeUintVar(frame_number);
|
|
1535
|
-
|
|
1536
|
-
this.#
|
|
1481
|
+
this.#send_buffer.writeUint8(flags);
|
|
1482
|
+
this.#send_buffer.writeBytes(entities, 0, length);
|
|
1483
|
+
return conn.connection.send_reliable(Lane.BULK, this.#send_buffer.raw_bytes, 0, this.#send_buffer.position);
|
|
1537
1484
|
}
|
|
1538
1485
|
|
|
1539
1486
|
/**
|
|
@@ -1563,7 +1510,7 @@ export class NetworkPeer {
|
|
|
1563
1510
|
this.#send_buffer.writeUintVar(last_acked_frame);
|
|
1564
1511
|
this.#send_buffer.writeUint8(has_token ? 1 : 0);
|
|
1565
1512
|
this.#send_buffer.writeBytes(session_token, 0, 16);
|
|
1566
|
-
|
|
1513
|
+
conn.connection.send_reliable(Lane.CONTROL, this.#send_buffer.raw_bytes, 0, this.#send_buffer.position);
|
|
1567
1514
|
}
|
|
1568
1515
|
|
|
1569
1516
|
/**
|
|
@@ -1577,7 +1524,7 @@ export class NetworkPeer {
|
|
|
1577
1524
|
|
|
1578
1525
|
this.#send_buffer.position = 0;
|
|
1579
1526
|
this.#send_buffer.writeUint8(NetworkPacketType.RESUME_ACCEPT);
|
|
1580
|
-
|
|
1527
|
+
conn.connection.send_reliable(Lane.CONTROL, this.#send_buffer.raw_bytes, 0, this.#send_buffer.position);
|
|
1581
1528
|
}
|
|
1582
1529
|
|
|
1583
1530
|
/**
|
|
@@ -1594,7 +1541,7 @@ export class NetworkPeer {
|
|
|
1594
1541
|
this.#send_buffer.position = 0;
|
|
1595
1542
|
this.#send_buffer.writeUint8(NetworkPacketType.RESUME_REJECT);
|
|
1596
1543
|
this.#send_buffer.writeUint8(reason_code & 0xFF);
|
|
1597
|
-
|
|
1544
|
+
conn.connection.send_reliable(Lane.CONTROL, this.#send_buffer.raw_bytes, 0, this.#send_buffer.position);
|
|
1598
1545
|
}
|
|
1599
1546
|
|
|
1600
1547
|
/**
|
|
@@ -1617,7 +1564,7 @@ export class NetworkPeer {
|
|
|
1617
1564
|
this.#send_buffer.writeUint8(NetworkPacketType.DISCONNECT);
|
|
1618
1565
|
this.#send_buffer.writeUint8(len);
|
|
1619
1566
|
if (len > 0) this.#send_buffer.writeBytes(encoded, 0, len);
|
|
1620
|
-
|
|
1567
|
+
conn.connection.send_reliable(Lane.CONTROL, this.#send_buffer.raw_bytes, 0, this.#send_buffer.position);
|
|
1621
1568
|
}
|
|
1622
1569
|
|
|
1623
1570
|
/**
|
|
@@ -1627,10 +1574,12 @@ export class NetworkPeer {
|
|
|
1627
1574
|
*
|
|
1628
1575
|
* @param {number} peer_id
|
|
1629
1576
|
* @param {number} buffer_depth signed integer; clamped to int16
|
|
1577
|
+
* @param {number} frame_number this side's sim frame
|
|
1630
1578
|
*/
|
|
1631
|
-
send_time_dilation_feedback(peer_id, buffer_depth) {
|
|
1579
|
+
send_time_dilation_feedback(peer_id, buffer_depth, frame_number) {
|
|
1632
1580
|
assert.isNonNegativeInteger(peer_id, 'peer_id');
|
|
1633
1581
|
assert.isNumber(buffer_depth, 'buffer_depth');
|
|
1582
|
+
assert.isNonNegativeInteger(frame_number, 'frame_number');
|
|
1634
1583
|
const conn = this.#peers.get(peer_id);
|
|
1635
1584
|
if (conn === undefined) throw new Error(`NetworkPeer.send_time_dilation_feedback: peer ${peer_id} not connected`);
|
|
1636
1585
|
|
|
@@ -1641,13 +1590,14 @@ export class NetworkPeer {
|
|
|
1641
1590
|
this.#send_buffer.position = 0;
|
|
1642
1591
|
this.#send_buffer.writeUint8(NetworkPacketType.TIME_DILATION);
|
|
1643
1592
|
this.#send_buffer.writeInt16(depth);
|
|
1644
|
-
this.#
|
|
1593
|
+
this.#send_buffer.writeUintVar(frame_number);
|
|
1594
|
+
conn.connection.send_unreliable(this.#send_buffer.raw_bytes, 0, this.#send_buffer.position, -1);
|
|
1645
1595
|
}
|
|
1646
1596
|
|
|
1647
1597
|
/**
|
|
1648
1598
|
* Tell a peer which frame this one has just finished simulating. See
|
|
1649
1599
|
* {@link NetworkPacketType.FRAME_MARKER}. Also serves as the tick's keep-alive: it advances the
|
|
1650
|
-
*
|
|
1600
|
+
* connection's acknowledgements like any message.
|
|
1651
1601
|
*
|
|
1652
1602
|
* @param {number} peer_id
|
|
1653
1603
|
* @param {number} frame_number
|
|
@@ -1661,23 +1611,21 @@ export class NetworkPeer {
|
|
|
1661
1611
|
this.#send_buffer.position = 0;
|
|
1662
1612
|
this.#send_buffer.writeUint8(NetworkPacketType.FRAME_MARKER);
|
|
1663
1613
|
this.#send_buffer.writeUintVar(frame_number);
|
|
1664
|
-
|
|
1614
|
+
conn.connection.send_unreliable(this.#send_buffer.raw_bytes, 0, this.#send_buffer.position, -1);
|
|
1665
1615
|
}
|
|
1666
1616
|
|
|
1667
1617
|
/**
|
|
1668
|
-
*
|
|
1669
|
-
*
|
|
1670
|
-
*
|
|
1671
|
-
*
|
|
1672
|
-
*
|
|
1673
|
-
*
|
|
1674
|
-
* Returns the logical seq the pipeline assigned (diagnostic only; the
|
|
1675
|
-
* receiver dedups internally regardless).
|
|
1618
|
+
* Queue a reliable command for a connected peer, on the connection's USER
|
|
1619
|
+
* lane: it arrives once, whole, and in order with the peer's other
|
|
1620
|
+
* commands, unless the connection ends first. Up to the connection's
|
|
1621
|
+
* `max_message_bytes` (less the type byte). Use for messages where the
|
|
1622
|
+
* action-stream model (best-effort, per-frame back-fill) isn't suitable —
|
|
1623
|
+
* chat, lobby/room state, level transitions.
|
|
1676
1624
|
*
|
|
1677
1625
|
* @param {number} peer_id
|
|
1678
1626
|
* @param {Uint8Array} payload
|
|
1679
1627
|
* @param {number} length
|
|
1680
|
-
* @returns {number}
|
|
1628
|
+
* @returns {number} delivery mark: see {@link Connection#is_delivered} with {@link Lane.USER}
|
|
1681
1629
|
*/
|
|
1682
1630
|
send_reliable_command(peer_id, payload, length) {
|
|
1683
1631
|
assert.isNonNegativeInteger(peer_id, 'peer_id');
|
|
@@ -1686,6 +1634,9 @@ export class NetworkPeer {
|
|
|
1686
1634
|
if (conn === undefined) {
|
|
1687
1635
|
throw new Error(`NetworkPeer.send_reliable_command: peer ${peer_id} not connected`);
|
|
1688
1636
|
}
|
|
1689
|
-
|
|
1637
|
+
this.#send_buffer.position = 0;
|
|
1638
|
+
this.#send_buffer.writeUint8(NetworkPacketType.RELIABLE_COMMAND);
|
|
1639
|
+
this.#send_buffer.writeBytes(payload, 0, length);
|
|
1640
|
+
return conn.connection.send_reliable(Lane.USER, this.#send_buffer.raw_bytes, 0, this.#send_buffer.position);
|
|
1690
1641
|
}
|
|
1691
1642
|
}
|