@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
|
@@ -9,7 +9,8 @@ import { NetworkIdentity } from "./ecs/components/NetworkIdentity.js";
|
|
|
9
9
|
import { make_owner_authorization } from "./ecs/owner_authorization.js";
|
|
10
10
|
import { NetworkSystem } from "./ecs/NetworkSystem.js";
|
|
11
11
|
import { NetworkIdentitySerializationAdapter, } from "./ecs/serialization/NetworkIdentitySerializationAdapter.js";
|
|
12
|
-
import { NetworkPeer, ResumeRejectReason, } from "./orchestrator/NetworkPeer.js";
|
|
12
|
+
import { InitialSyncPage, NetworkPeer, ResumeRejectReason, } from "./orchestrator/NetworkPeer.js";
|
|
13
|
+
import { HostJoin, JoinProgress } from "./orchestrator/HostJoin.js";
|
|
13
14
|
import { ServerAuthoritativeClient } from "./orchestrator/ServerAuthoritativeClient.js";
|
|
14
15
|
import { LateInput, ServerAuthoritativeServer } from "./orchestrator/ServerAuthoritativeServer.js";
|
|
15
16
|
import { OwnerAwareScope } from "./replication/ScopeFilter.js";
|
|
@@ -19,7 +20,6 @@ import { Interpolated, INTERPOLATION_SOURCE_LOCAL } from "../interpolation/Inter
|
|
|
19
20
|
import { InterpolationLog } from "../interpolation/InterpolationLog.js";
|
|
20
21
|
import { InterpolationSystem } from "../interpolation/InterpolationSystem.js";
|
|
21
22
|
import { SimAction } from "./sim/SimAction.js";
|
|
22
|
-
import { snapshotter_emit } from "./sim/Snapshotter.js";
|
|
23
23
|
import { PredictionHistory } from "./state/PredictionHistory.js";
|
|
24
24
|
import { AdaptiveRenderDelay } from "./time/AdaptiveRenderDelay.js";
|
|
25
25
|
import { RenderPlayout } from "./time/RenderPlayout.js";
|
|
@@ -143,13 +143,15 @@ const ReconnectState = Object.freeze({
|
|
|
143
143
|
/**
|
|
144
144
|
* Client-side: how the host has answered the transport binding in use. A new binding does not know
|
|
145
145
|
* which world the client is in until the host says: the one it has been predicting on, which the
|
|
146
|
-
* host resumes (RESUME_ACCEPT), or the host's own, sent as a snapshot (INITIAL_SYNC). The
|
|
147
|
-
* answer is the answer; the host's handshake arriving after it is stale.
|
|
146
|
+
* host resumes (RESUME_ACCEPT), or the host's own, sent as pages of a snapshot (INITIAL_SYNC). The
|
|
147
|
+
* first answer is the answer; the host's handshake arriving after it is stale. The first page is
|
|
148
|
+
* the answer (Syncing); the FINAL page completes it (Synced).
|
|
148
149
|
* @readonly @enum {string}
|
|
149
150
|
*/
|
|
150
151
|
const BindingAnswer = Object.freeze({
|
|
151
152
|
Pending: 'pending',
|
|
152
153
|
Resumed: 'resumed',
|
|
154
|
+
Syncing: 'syncing',
|
|
153
155
|
Synced: 'synced',
|
|
154
156
|
});
|
|
155
157
|
|
|
@@ -229,6 +231,18 @@ function assert_copies_itself(method, name, ComponentClass) {
|
|
|
229
231
|
* @param {number} length
|
|
230
232
|
* @returns {boolean}
|
|
231
233
|
*/
|
|
234
|
+
/**
|
|
235
|
+
* Close a transport the session is giving up on. Best effort: one already closed, or failing to
|
|
236
|
+
* close, changes nothing about what follows.
|
|
237
|
+
* @param {{disconnect?: function(): void}} transport
|
|
238
|
+
*/
|
|
239
|
+
function close_transport(transport) {
|
|
240
|
+
try {
|
|
241
|
+
transport.disconnect();
|
|
242
|
+
} catch (_) { /* swallow */
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
232
246
|
function bytes_equal(a, b, length) {
|
|
233
247
|
for (let i = 0; i < length; i++) {
|
|
234
248
|
if (a[i] !== b[i]) return false;
|
|
@@ -255,8 +269,17 @@ function bytes_equal_lengths(a, a_length, b, b_length) {
|
|
|
255
269
|
*
|
|
256
270
|
* Replication is component-driven: attaching a {@link NetworkIdentity}
|
|
257
271
|
* to an entity registers it with the session via an `EntityObserver`.
|
|
258
|
-
*
|
|
259
|
-
*
|
|
272
|
+
*
|
|
273
|
+
* **What travels is what goes through the action executor**, and nothing
|
|
274
|
+
* else: actions (`send`, a client's input), and direct writes their writer
|
|
275
|
+
* reports — `dataset.sendEvent(entity, "net_mutate_component", payload)`.
|
|
276
|
+
* The session never looks for changes by itself. That is what keeps a tick's
|
|
277
|
+
* cost in what changed and what is owned, never in the size of the world;
|
|
278
|
+
* the stack is built for worlds of millions of networked objects. A
|
|
279
|
+
* replicated component written directly and not reported stays where it was
|
|
280
|
+
* written. Ownership is set when an identity attaches, or by the join, and
|
|
281
|
+
* `owner_peer_id` / `network_id` are not written afterwards. The README's
|
|
282
|
+
* "What the session assumes" has the whole contract and its measured costs.
|
|
260
283
|
*
|
|
261
284
|
* **The session runs on the engine's clock.** The `EntityManager`'s fixed
|
|
262
285
|
* step is the network tick: each step opens a network frame before any
|
|
@@ -329,6 +352,11 @@ export class NetworkSession {
|
|
|
329
352
|
#client = null;
|
|
330
353
|
/** @private @type {NetworkPeer|null} */
|
|
331
354
|
#peer = null;
|
|
355
|
+
/**
|
|
356
|
+
* The session's place in the engine loop, added by `start()` and removed by `stop()`.
|
|
357
|
+
* @private @type {NetworkSystem|null}
|
|
358
|
+
*/
|
|
359
|
+
#network_system = null;
|
|
332
360
|
/** @private @type {EntityObserver|null} */
|
|
333
361
|
#identity_observer = null;
|
|
334
362
|
/** @private @type {InterpolationLog|null} */
|
|
@@ -352,6 +380,22 @@ export class NetworkSession {
|
|
|
352
380
|
*/
|
|
353
381
|
#remote_entities = new Set();
|
|
354
382
|
|
|
383
|
+
/**
|
|
384
|
+
* Networked entities by owner: peer id → its entities. What a tick does per owned entity —
|
|
385
|
+
* the host's AUTH_STATE to each peer, the client's record of what it predicted — walks this,
|
|
386
|
+
* never every networked entity: the cost of a tick is in what is owned and what changed, not
|
|
387
|
+
* in the size of the world. Kept exact by attach, detach and {@link #apply_ownership}, the
|
|
388
|
+
* only places ownership is set.
|
|
389
|
+
* @private @type {Map<number, Set<number>>}
|
|
390
|
+
*/
|
|
391
|
+
#owned_by = new Map();
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Owner each networked entity is filed under in {@link #owned_by}.
|
|
395
|
+
* @private @type {Map<number, number>}
|
|
396
|
+
*/
|
|
397
|
+
#owner_of = new Map();
|
|
398
|
+
|
|
355
399
|
// ---- Render-frame interpolation state ----
|
|
356
400
|
|
|
357
401
|
/**
|
|
@@ -416,26 +460,11 @@ export class NetworkSession {
|
|
|
416
460
|
*/
|
|
417
461
|
#inbound = new Map();
|
|
418
462
|
|
|
419
|
-
// ---- Host
|
|
420
|
-
|
|
421
|
-
/** @private @type {boolean} */
|
|
422
|
-
#publish_changes;
|
|
463
|
+
// ---- Host ----
|
|
423
464
|
|
|
424
465
|
/** @private @type {string} */
|
|
425
466
|
#late_input;
|
|
426
467
|
|
|
427
|
-
/**
|
|
428
|
-
* What the peers hold for each networked entity, per replicated component type id, as the
|
|
429
|
-
* replication adapter's bytes — so "changed" means "changed on the wire". Updated by every
|
|
430
|
-
* record the host publishes and by every action it executes (the peers apply the action and
|
|
431
|
-
* arrive at the same value), and compared with the live state at the end of each step.
|
|
432
|
-
* @private @type {Map<number, Array<{bytes: Uint8Array, length: number}|null>>}
|
|
433
|
-
*/
|
|
434
|
-
#published = new Map();
|
|
435
|
-
|
|
436
|
-
/** @private @type {BinaryBuffer} */
|
|
437
|
-
#scratch_publish_buf = new BinaryBuffer();
|
|
438
|
-
|
|
439
468
|
// ---- Client: reconciliation by comparison ----
|
|
440
469
|
|
|
441
470
|
/** @private @type {string} */
|
|
@@ -491,6 +520,16 @@ export class NetworkSession {
|
|
|
491
520
|
*/
|
|
492
521
|
correction_skipped_count = 0;
|
|
493
522
|
|
|
523
|
+
/**
|
|
524
|
+
* Client: how many times it found itself more than the host's input window behind the frame the
|
|
525
|
+
* host last named, or was told by the host's depth feedback that its input lands below the
|
|
526
|
+
* host's window, and re-took the host's time. A tab in the background, a debugger, a laptop
|
|
527
|
+
* asleep — see {@link #retake_host_time_if_stalled}. Diagnostic: a game that sees these on a
|
|
528
|
+
* machine that never left the foreground has a client that cannot keep the step.
|
|
529
|
+
* @type {number}
|
|
530
|
+
*/
|
|
531
|
+
stall_count = 0;
|
|
532
|
+
|
|
494
533
|
/**
|
|
495
534
|
* Client, {@link NetworkSessionReconcile.Correct}: a component of an authoritative state
|
|
496
535
|
* differed from the prediction, and the present was corrected. Once per component corrected.
|
|
@@ -506,19 +545,21 @@ export class NetworkSession {
|
|
|
506
545
|
#connected_peers = new Set();
|
|
507
546
|
|
|
508
547
|
/**
|
|
509
|
-
* Host-only: peer_id →
|
|
510
|
-
* `#on_host_tick_complete
|
|
511
|
-
* for
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
* chunk of the sync at most once, for at most
|
|
517
|
-
* `FRAGMENT_RETENTION_MAX_RETRIES` NACKs, so it adds at most that many
|
|
518
|
-
* copies of each sync, however the peer asks.)
|
|
519
|
-
* @private @type {Map<number, number>}
|
|
548
|
+
* Host-only: peer_id → its join, while one is going on. Advanced in
|
|
549
|
+
* `#on_host_tick_complete`; created only by {@link #queue_initial_sync}, so never on the
|
|
550
|
+
* peer's say-so: a join the peer could ask for is one it could keep asking for. The pages ride
|
|
551
|
+
* the connection's BULK lane, which re-sends what is lost; what a join costs beyond the world
|
|
552
|
+
* once is the entities that changed while it was going out, for at most
|
|
553
|
+
* {@link JOIN_MAX_ROUNDS} rounds.
|
|
554
|
+
* @private @type {Map<number, HostJoin>}
|
|
520
555
|
*/
|
|
521
|
-
#
|
|
556
|
+
#joins = new Map();
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Host-only: scratch every join builds its pages in.
|
|
560
|
+
* @private @type {BinaryBuffer}
|
|
561
|
+
*/
|
|
562
|
+
#page_buffer = new BinaryBuffer();
|
|
522
563
|
|
|
523
564
|
/**
|
|
524
565
|
* Host-only: peers whose current connection has been given its
|
|
@@ -541,6 +582,13 @@ export class NetworkSession {
|
|
|
541
582
|
/** @private @type {boolean} */
|
|
542
583
|
#started = false;
|
|
543
584
|
|
|
585
|
+
/**
|
|
586
|
+
* {@link stop} has run. A session is one match: what it knew of its peers outlives the stop, so
|
|
587
|
+
* it does not start again.
|
|
588
|
+
* @private @type {boolean}
|
|
589
|
+
*/
|
|
590
|
+
#stopped = false;
|
|
591
|
+
|
|
544
592
|
// ---- Host-side: per-peer session token + grace state ----
|
|
545
593
|
|
|
546
594
|
/**
|
|
@@ -613,14 +661,47 @@ export class NetworkSession {
|
|
|
613
661
|
/**
|
|
614
662
|
* Client-side: how the host has answered the binding the last `connect()`
|
|
615
663
|
* made. Once it has, what the binding carries about the handshake is news
|
|
616
|
-
* no longer:
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
*
|
|
620
|
-
* after the resync it asks for.
|
|
664
|
+
* no longer: a host that has finished with our old session takes the new
|
|
665
|
+
* transport for a fresh peer and starts its join before reading the
|
|
666
|
+
* RESUME_HELLO the transport carried, so the RESUME_REJECT it answers that
|
|
667
|
+
* with arrives after the resync it asks for.
|
|
621
668
|
* @private @type {BindingAnswer|string}
|
|
622
669
|
*/
|
|
623
670
|
#binding_answer = BindingAnswer.Pending;
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Client: the newest sim frame the host has named on this binding — every TIME_DILATION
|
|
674
|
+
* carries it — or -1. A join's pages can take a while to arrive, and the frame a page names
|
|
675
|
+
* is as old as its trip; this is the freshest word of where the host is.
|
|
676
|
+
* @private @type {number}
|
|
677
|
+
*/
|
|
678
|
+
#host_frame_seen = -1;
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Client: the host's newest depth feedback — its latest sight of this client's frame minus its
|
|
682
|
+
* own sim frame, measured where this client's input lands — and that latest sight itself (the
|
|
683
|
+
* frame the host named plus the depth). The dilation steers by the depth; the stall rule reads
|
|
684
|
+
* it for what the host's window makes of our input, latency included. 0 and -1 on a new binding.
|
|
685
|
+
* @private @type {number}
|
|
686
|
+
*/
|
|
687
|
+
#host_depth_seen = 0;
|
|
688
|
+
/** @private @type {number} */
|
|
689
|
+
#host_marker_seen = -1;
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Client: the peer whose held inbound — action stream and AUTH_STATE, held from `connect()`
|
|
693
|
+
* until the binding's answer is whole — is to be released as the step's inbound is done, or -1.
|
|
694
|
+
* Released there rather than inside the answer's own dispatch: the release applies what was
|
|
695
|
+
* held, through the same receive buffer the answer is still being read from.
|
|
696
|
+
* @private @type {number}
|
|
697
|
+
*/
|
|
698
|
+
#inbound_release_peer = -1;
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Client: whether that release completes a join, so {@link onSynced} follows it.
|
|
702
|
+
* @private @type {boolean}
|
|
703
|
+
*/
|
|
704
|
+
#inbound_release_syncs = false;
|
|
624
705
|
/**
|
|
625
706
|
* Client-side: the first frame predicted on the world this client holds —
|
|
626
707
|
* where the last INITIAL_SYNC it applied set the frame counter, 0 before
|
|
@@ -671,6 +752,14 @@ export class NetworkSession {
|
|
|
671
752
|
*/
|
|
672
753
|
onReconnected = new Signal();
|
|
673
754
|
|
|
755
|
+
/**
|
|
756
|
+
* Client: a join has completed — the host's FINAL page has landed, every networked entity's
|
|
757
|
+
* state is here, and from now on this client's input is sent. No arguments. A world is sent
|
|
758
|
+
* as pages over as many ticks as its size takes; until this fires it is still arriving.
|
|
759
|
+
* @type {Signal}
|
|
760
|
+
*/
|
|
761
|
+
onSynced = new Signal();
|
|
762
|
+
|
|
674
763
|
/**
|
|
675
764
|
* Client: the reconnect ladder is exhausted, or the host explicitly
|
|
676
765
|
* kicked us with a DISCONNECT packet, or `reconnect.enabled` is
|
|
@@ -762,12 +851,6 @@ export class NetworkSession {
|
|
|
762
851
|
* - `reconnect` (client role): policy for the reconnect ladder. See
|
|
763
852
|
* {@link DEFAULT_RECONNECT_POLICY}. Set `enabled: false` to opt
|
|
764
853
|
* out entirely.
|
|
765
|
-
* - `publish_changes` (host role, default true): at the end of every
|
|
766
|
-
* step, send each replicated component the simulation changed — physics,
|
|
767
|
-
* controllers, anything that wrote it directly. Components an action
|
|
768
|
-
* wrote are already on the wire and are not sent twice. Publishing never
|
|
769
|
-
* writes back into the host's own state. Set false to publish by hand
|
|
770
|
-
* (`net_mutate_component`).
|
|
771
854
|
* - `reconcile` (client role): see {@link NetworkSessionReconcile}. Default
|
|
772
855
|
* `'correct'`.
|
|
773
856
|
* - `late_input` (host role): what to do with client input that arrives
|
|
@@ -791,7 +874,6 @@ export class NetworkSession {
|
|
|
791
874
|
server_resume_grace_ms = DEFAULT_SERVER_RESUME_GRACE_MS,
|
|
792
875
|
connection_timeout_ms = DEFAULT_CONNECTION_TIMEOUT_MS,
|
|
793
876
|
reconnect = null,
|
|
794
|
-
publish_changes = true,
|
|
795
877
|
late_input = LateInput.Apply,
|
|
796
878
|
reconcile = NetworkSessionReconcile.Correct,
|
|
797
879
|
} = {}) {
|
|
@@ -904,7 +986,6 @@ export class NetworkSession {
|
|
|
904
986
|
this.#connection_timeout_ms = connection_timeout_ms;
|
|
905
987
|
this.#reconnect_policy = Object.freeze({ ...DEFAULT_RECONNECT_POLICY, ...(reconnect || {}) });
|
|
906
988
|
this.#transport_factory = transport_factory;
|
|
907
|
-
this.#publish_changes = publish_changes;
|
|
908
989
|
this.#late_input = late_input;
|
|
909
990
|
if (reconcile !== NetworkSessionReconcile.Correct && reconcile !== NetworkSessionReconcile.Replay) {
|
|
910
991
|
throw new Error(`NetworkSession: reconcile must be one of ${Object.values(NetworkSessionReconcile).join(', ')}, got '${reconcile}'`);
|
|
@@ -1092,7 +1173,7 @@ export class NetworkSession {
|
|
|
1092
1173
|
/**
|
|
1093
1174
|
* Wire the session to the engine. After this, the EntityObserver
|
|
1094
1175
|
* is active, the right orchestrator is constructed, and a
|
|
1095
|
-
* {@link NetworkSystem} is attached. Subsequent `replicate_*`
|
|
1176
|
+
* {@link NetworkSystem} is attached until {@link stop}. Subsequent `replicate_*`
|
|
1096
1177
|
* / {@link defineAction} / {@link defineInputSampler} calls throw.
|
|
1097
1178
|
*
|
|
1098
1179
|
* Pre-condition: every replicated component class must already have a
|
|
@@ -1101,6 +1182,7 @@ export class NetworkSession {
|
|
|
1101
1182
|
*/
|
|
1102
1183
|
async start() {
|
|
1103
1184
|
if (this.#started) throw new Error("NetworkSession.start: already started");
|
|
1185
|
+
if (this.#stopped) throw new Error("NetworkSession.start: a stopped session does not start again; the next match is a new NetworkSession");
|
|
1104
1186
|
|
|
1105
1187
|
// Auto-register the NetworkIdentity adapter so initial-sync can
|
|
1106
1188
|
// ship it across the wire. Allow caller-supplied registrations
|
|
@@ -1156,6 +1238,11 @@ export class NetworkSession {
|
|
|
1156
1238
|
replicated_components,
|
|
1157
1239
|
action_classes,
|
|
1158
1240
|
frame_capacity: this.frame_capacity,
|
|
1241
|
+
// The session's one clock: render-paced, so the fixed steps one update runs all see
|
|
1242
|
+
// the same time, and a burst of catch-up steps cannot age packets whose
|
|
1243
|
+
// acknowledgements could not have arrived yet.
|
|
1244
|
+
clock: () => this.#clock_ms,
|
|
1245
|
+
tick_period_ms: this.tick_period_ms,
|
|
1159
1246
|
};
|
|
1160
1247
|
|
|
1161
1248
|
if (this.role === NetworkSessionRole.Host) {
|
|
@@ -1171,9 +1258,6 @@ export class NetworkSession {
|
|
|
1171
1258
|
identity_class: NetworkIdentity,
|
|
1172
1259
|
});
|
|
1173
1260
|
this.#server.onTickComplete.add((sim_frame) => this.#on_host_tick_complete(sim_frame));
|
|
1174
|
-
if (this.#publish_changes) {
|
|
1175
|
-
this.#server.onBeforeTickClose.add(() => this.#publish_simulated_changes());
|
|
1176
|
-
}
|
|
1177
1261
|
} else {
|
|
1178
1262
|
// Client role: covers both "playing" (input sampler registered)
|
|
1179
1263
|
// and "spectator" (no sampler — sampler-driven onPredict
|
|
@@ -1204,13 +1288,6 @@ export class NetworkSession {
|
|
|
1204
1288
|
// blended component on the first execute after a render pass.
|
|
1205
1289
|
this.#peer.executor.before_execute = this.#bound_normalize_if_dirty;
|
|
1206
1290
|
|
|
1207
|
-
if (this.role === NetworkSessionRole.Host && this.#publish_changes) {
|
|
1208
|
-
// an action carries its own change to the peers: what it wrote is what they will hold
|
|
1209
|
-
this.#peer.executor.on_component_written = (entity_id, component_class) => {
|
|
1210
|
-
this.#note_published(entity_id, component_class);
|
|
1211
|
-
};
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
1291
|
// Secure-by-default inbound authorization on the host: a remote client
|
|
1215
1292
|
// may only mutate entities it owns (NetworkIdentity.owner_peer_id ===
|
|
1216
1293
|
// sender); the authoritative server (sender === local_peer_id) may
|
|
@@ -1234,11 +1311,12 @@ export class NetworkSession {
|
|
|
1234
1311
|
//
|
|
1235
1312
|
// It is also the session's place in the engine loop: each fixed step opens a network frame
|
|
1236
1313
|
// and closes it, and every rendered frame runs the session's wall-paced work.
|
|
1237
|
-
|
|
1314
|
+
this.#network_system = new NetworkSystem(this.#peer, {
|
|
1238
1315
|
open_step: () => this.#open_step(),
|
|
1239
1316
|
close_step: () => this.#close_step(),
|
|
1240
1317
|
frame: (dt) => this.#on_frame(dt),
|
|
1241
|
-
})
|
|
1318
|
+
});
|
|
1319
|
+
await this.entity_manager.addSystem(this.#network_system);
|
|
1242
1320
|
|
|
1243
1321
|
// The network timeline: per-frame state of every remote entity, blended at render time on
|
|
1244
1322
|
// the render-delayed playout by the engine's InterpolationSystem.
|
|
@@ -1267,65 +1345,34 @@ export class NetworkSession {
|
|
|
1267
1345
|
// action-stream processing, and finalize any in-flight Tier-3
|
|
1268
1346
|
// resync state.
|
|
1269
1347
|
if (this.role === NetworkSessionRole.Client) {
|
|
1270
|
-
this.#peer.onInitialSync.add((peer_id, session_token, frame_number, buf, payload_end) => {
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1348
|
+
this.#peer.onInitialSync.add((peer_id, session_token, frame_number, flags, buf, payload_end) => {
|
|
1349
|
+
const first = (flags & InitialSyncPage.FIRST) !== 0;
|
|
1350
|
+
const final = (flags & InitialSyncPage.FINAL) !== 0;
|
|
1351
|
+
|
|
1352
|
+
if (first) {
|
|
1353
|
+
if (this.#binding_answer !== BindingAnswer.Pending) {
|
|
1354
|
+
// This binding has had its answer — a resume, or a join already under
|
|
1355
|
+
// way or done. The host starts one join per connection, so this is not
|
|
1356
|
+
// ours to act on: the client has been predicting on the world it holds.
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
this.#begin_sync(peer_id, session_token, frame_number);
|
|
1360
|
+
} else if (this.#binding_answer !== BindingAnswer.Syncing) {
|
|
1361
|
+
// a page of a join this binding is not in
|
|
1276
1362
|
return;
|
|
1277
1363
|
}
|
|
1278
1364
|
|
|
1279
|
-
const token = new UUID();
|
|
1280
|
-
token.data = session_token;
|
|
1281
|
-
this.session_token = token;
|
|
1282
|
-
|
|
1283
|
-
/*
|
|
1284
|
-
Align to the host's clock. This argument has always been on the wire and in this
|
|
1285
|
-
signature -- it was named `_frame_number` and dropped -- and without it a client
|
|
1286
|
-
joining a match in progress tags its inputs from 0 against a host at frame 6,000,
|
|
1287
|
-
which trims every one of them silently. GAP-042.
|
|
1288
|
-
|
|
1289
|
-
The lead is the buffer depth the time dilation is already steering toward: an
|
|
1290
|
-
input authored now arrives in the host's future, and this is how far ahead it has
|
|
1291
|
-
to be tagged to land in the window rather than behind it. It only has to be in the
|
|
1292
|
-
right neighbourhood -- `TimeDilation` converges on the real depth from the host's
|
|
1293
|
-
feedback within a second or two -- but starting six thousand frames out is not a
|
|
1294
|
-
neighbourhood, which is what made this total rather than approximate.
|
|
1295
|
-
*/
|
|
1296
|
-
this.seek_to_frame(frame_number + 1 + this.#time_dilation.target_buffer_depth);
|
|
1297
|
-
|
|
1298
|
-
// The world is about to be the host's. What this client predicted, sampled or was
|
|
1299
|
-
// told about the one it had is about a world, and a frame numbering, that is gone.
|
|
1300
|
-
this.#prediction_history.clear();
|
|
1301
|
-
this.#pending_auth.clear();
|
|
1302
|
-
this.#reconciled_frame.clear();
|
|
1303
|
-
this.#sampled_actions_per_frame.clear();
|
|
1304
|
-
|
|
1305
1365
|
this.#apply_initial_sync(buf, payload_end);
|
|
1306
|
-
this.#binding_answer = BindingAnswer.Synced;
|
|
1307
|
-
|
|
1308
|
-
// Input from here on is predicted on the host's world. What was predicted before —
|
|
1309
|
-
// held since this binding was made, or still in the log from before it — was
|
|
1310
|
-
// predicted on the world just replaced, and is never sent.
|
|
1311
|
-
this.#world_start_frame = this.#local_frame;
|
|
1312
|
-
this.#peer.release_outbound(peer_id, this.#world_start_frame);
|
|
1313
1366
|
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
// so the snapshot arrives with no RESUME_ACCEPT ahead of it.
|
|
1317
|
-
// That is the reconnection — staying in the ladder would burn
|
|
1318
|
-
// attempts while holding the world the host just sent, and
|
|
1319
|
-
// recovering later via RESUME_ACCEPT would report
|
|
1320
|
-
// `state_resynced: false` over a world that was wholly
|
|
1321
|
-
// replaced. `Lost` is excluded on purpose: the application has
|
|
1322
|
-
// already been told that session is over.
|
|
1323
|
-
if (this.#reconnect_state === ReconnectState.Resyncing
|
|
1324
|
-
|| this.#reconnect_state === ReconnectState.Reconnecting) {
|
|
1325
|
-
this.#enter_connected();
|
|
1326
|
-
this.onReconnected.send1({ state_resynced: true });
|
|
1367
|
+
if (final) {
|
|
1368
|
+
this.#finish_sync(peer_id, frame_number);
|
|
1327
1369
|
}
|
|
1328
1370
|
});
|
|
1371
|
+
this.#peer.onTimeDilationFeedback.add((_peer_id, depth, frame_number) => {
|
|
1372
|
+
if (frame_number > this.#host_frame_seen) this.#host_frame_seen = frame_number;
|
|
1373
|
+
this.#host_depth_seen = depth;
|
|
1374
|
+
this.#host_marker_seen = frame_number + depth;
|
|
1375
|
+
});
|
|
1329
1376
|
// Host's response to our RESUME_HELLO during reconnect.
|
|
1330
1377
|
this.#peer.onResumeAccept.add((peer_id) => {
|
|
1331
1378
|
if (this.#binding_answer !== BindingAnswer.Pending) {
|
|
@@ -1336,6 +1383,9 @@ export class NetworkSession {
|
|
|
1336
1383
|
// The host kept the world this client holds, so what the client predicted on it —
|
|
1337
1384
|
// while cut off, and since — is owed to the host like any input, late as it is.
|
|
1338
1385
|
this.#peer.release_outbound(peer_id, this.#world_start_frame);
|
|
1386
|
+
// and what the host sent on it meanwhile is about that world
|
|
1387
|
+
this.#inbound_release_peer = peer_id;
|
|
1388
|
+
this.#inbound_release_syncs = false;
|
|
1339
1389
|
if (this.#reconnect_state === ReconnectState.Reconnecting
|
|
1340
1390
|
|| this.#reconnect_state === ReconnectState.Resyncing) {
|
|
1341
1391
|
this.#enter_connected();
|
|
@@ -1370,6 +1420,7 @@ export class NetworkSession {
|
|
|
1370
1420
|
this.#peer.onDisconnectPacket.add((_peer_id, reason_label) => {
|
|
1371
1421
|
this.#permanently_lose_connection(reason_label || 'disconnected_by_host');
|
|
1372
1422
|
});
|
|
1423
|
+
this.#peer.onProtocolError.add((_peer_id, reason) => this.#on_client_protocol_error(reason));
|
|
1373
1424
|
} else {
|
|
1374
1425
|
// Host: RESUME_HELLO validation + peer-initiated disconnects.
|
|
1375
1426
|
this.#peer.onResumeHello.add((peer_id, local_peer_id, last_acked_frame, has_token, session_token) => {
|
|
@@ -1380,6 +1431,7 @@ export class NetworkSession {
|
|
|
1380
1431
|
// and free state immediately.
|
|
1381
1432
|
this.drop_peer(peer_id, reason_label || 'client_disconnect');
|
|
1382
1433
|
});
|
|
1434
|
+
this.#peer.onProtocolError.add((peer_id, reason) => this.#on_peer_protocol_error(peer_id, reason));
|
|
1383
1435
|
}
|
|
1384
1436
|
|
|
1385
1437
|
// EntityObserver for NetworkIdentity: patches owner/network_id on
|
|
@@ -1478,7 +1530,15 @@ export class NetworkSession {
|
|
|
1478
1530
|
// snapshot replaces must never reach the host. So what the client predicts meanwhile is
|
|
1479
1531
|
// held: sent on an accept, dropped on a sync.
|
|
1480
1532
|
this.#binding_answer = BindingAnswer.Pending;
|
|
1533
|
+
this.#host_frame_seen = -1;
|
|
1534
|
+
this.#host_depth_seen = 0;
|
|
1535
|
+
this.#host_marker_seen = -1;
|
|
1481
1536
|
this.#peer.hold_outbound(remote_peer_id);
|
|
1537
|
+
// Inbound too, until the answer is whole: an action stream that arrives ahead of it —
|
|
1538
|
+
// a join's stream can, when the pages are lost on the way — is about the world the
|
|
1539
|
+
// answer settles, a resumed one or a new one, and is applied once it is settled.
|
|
1540
|
+
this.#peer.hold_inbound(remote_peer_id);
|
|
1541
|
+
this.#inbound_release_peer = -1;
|
|
1482
1542
|
|
|
1483
1543
|
// Announce ourselves whenever this connect could be a claim on an
|
|
1484
1544
|
// id the host still holds a record for: we have a token to prove
|
|
@@ -1499,6 +1559,9 @@ export class NetworkSession {
|
|
|
1499
1559
|
remote_peer_id, this.local_peer_id, last_acked,
|
|
1500
1560
|
token !== null, token !== null ? token.data : NO_SESSION_TOKEN,
|
|
1501
1561
|
);
|
|
1562
|
+
// Out at once rather than with the next tick: a connect is an event, not part of
|
|
1563
|
+
// a frame, and the host can answer nothing until it has heard the claim.
|
|
1564
|
+
this.#peer.flush_peer(remote_peer_id);
|
|
1502
1565
|
}
|
|
1503
1566
|
this.#has_ever_connected = true;
|
|
1504
1567
|
}
|
|
@@ -1542,6 +1605,7 @@ export class NetworkSession {
|
|
|
1542
1605
|
// Best-effort notification — peer may have already dropped.
|
|
1543
1606
|
try {
|
|
1544
1607
|
this.#peer.send_disconnect(peer_id, reason);
|
|
1608
|
+
this.#peer.flush_peer(peer_id);
|
|
1545
1609
|
} catch (_) { /* swallow */
|
|
1546
1610
|
}
|
|
1547
1611
|
this.#server.disconnect_peer(peer_id);
|
|
@@ -1551,10 +1615,23 @@ export class NetworkSession {
|
|
|
1551
1615
|
this.#peer_inbound_mark.delete(peer_id);
|
|
1552
1616
|
this.#peer_grace_state.delete(peer_id);
|
|
1553
1617
|
this.#peer_session_tokens.delete(peer_id);
|
|
1554
|
-
this.#
|
|
1618
|
+
this.#joins.delete(peer_id);
|
|
1555
1619
|
this.onPeerPermanentlyDropped.send2(peer_id, reason);
|
|
1556
1620
|
}
|
|
1557
1621
|
|
|
1622
|
+
/**
|
|
1623
|
+
* Send what is queued for `peer_id` — a kick's RESUME_REJECT and DISCONNECT — before its
|
|
1624
|
+
* connection is torn down. One best-effort flush: a transport that refuses it (closed, say)
|
|
1625
|
+
* changes nothing about the teardown that follows.
|
|
1626
|
+
* @param {number} peer_id
|
|
1627
|
+
*/
|
|
1628
|
+
#flush_last_word(peer_id) {
|
|
1629
|
+
try {
|
|
1630
|
+
this.#peer.flush_peer(peer_id);
|
|
1631
|
+
} catch (_) { /* swallow */
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1558
1635
|
/**
|
|
1559
1636
|
* Client-only: voluntarily disconnect from the server. Sends a
|
|
1560
1637
|
* DISCONNECT packet so the host can free state immediately and
|
|
@@ -1570,6 +1647,7 @@ export class NetworkSession {
|
|
|
1570
1647
|
const peer_id = this.#remote_peer_id;
|
|
1571
1648
|
try {
|
|
1572
1649
|
this.#peer.send_disconnect(peer_id, reason);
|
|
1650
|
+
this.#peer.flush_peer(peer_id);
|
|
1573
1651
|
} catch (_) { /* swallow */
|
|
1574
1652
|
}
|
|
1575
1653
|
// Tear down the channel binding so a subsequent connect() with a
|
|
@@ -1598,9 +1676,19 @@ export class NetworkSession {
|
|
|
1598
1676
|
|
|
1599
1677
|
/**
|
|
1600
1678
|
* Tear down. Idempotent — safe to call from cleanup paths.
|
|
1679
|
+
*
|
|
1680
|
+
* Takes back from the engine what {@link start} put in it: the {@link NetworkSystem} is out of
|
|
1681
|
+
* the engine's loop when this returns, so another session can start on the same engine; this one
|
|
1682
|
+
* does not start again. The
|
|
1683
|
+
* networked entities stay in the world, and their `network_id`s are released — an id means
|
|
1684
|
+
* nothing without the session that gave it. The {@link InterpolationSystem} stays too, whoever
|
|
1685
|
+
* added it: it is the engine's, and blends whatever else is interpolated; the session only
|
|
1686
|
+
* withdraws its own source from it.
|
|
1687
|
+
*
|
|
1688
|
+
* @returns {Promise} resolves once the engine has shut the {@link NetworkSystem} down
|
|
1601
1689
|
*/
|
|
1602
1690
|
stop() {
|
|
1603
|
-
if (!this.#started) return;
|
|
1691
|
+
if (!this.#started) return Promise.resolve();
|
|
1604
1692
|
|
|
1605
1693
|
this.entity_manager.fixedStepTimeScale = 1;
|
|
1606
1694
|
|
|
@@ -1634,6 +1722,8 @@ export class NetworkSession {
|
|
|
1634
1722
|
}
|
|
1635
1723
|
this.#event_listeners.clear();
|
|
1636
1724
|
this.#remote_entities.clear();
|
|
1725
|
+
this.#owned_by.clear();
|
|
1726
|
+
this.#owner_of.clear();
|
|
1637
1727
|
this.#sampled_actions_per_frame.clear();
|
|
1638
1728
|
this.#peer_inbound_mark.clear();
|
|
1639
1729
|
for (const transport of this.#inbound.values()) {
|
|
@@ -1641,6 +1731,13 @@ export class NetworkSession {
|
|
|
1641
1731
|
}
|
|
1642
1732
|
this.#inbound.clear();
|
|
1643
1733
|
this.#started = false;
|
|
1734
|
+
this.#stopped = true;
|
|
1735
|
+
|
|
1736
|
+
// last: removing the system unlinks every networked entity, and nothing of the session's
|
|
1737
|
+
// may still be listening to that
|
|
1738
|
+
const network_system = this.#network_system;
|
|
1739
|
+
this.#network_system = null;
|
|
1740
|
+
return this.entity_manager.removeSystem(network_system);
|
|
1644
1741
|
}
|
|
1645
1742
|
|
|
1646
1743
|
// ----------------------------------------------------------------
|
|
@@ -1679,6 +1776,11 @@ export class NetworkSession {
|
|
|
1679
1776
|
this.#interpolation.settle();
|
|
1680
1777
|
|
|
1681
1778
|
this.#flush_inbound();
|
|
1779
|
+
this.#release_held_inbound();
|
|
1780
|
+
|
|
1781
|
+
if (this.#client !== null) {
|
|
1782
|
+
this.#retake_host_time_if_stalled();
|
|
1783
|
+
}
|
|
1682
1784
|
|
|
1683
1785
|
this.#apply_pending_interpolation();
|
|
1684
1786
|
|
|
@@ -1710,11 +1812,12 @@ export class NetworkSession {
|
|
|
1710
1812
|
|
|
1711
1813
|
try {
|
|
1712
1814
|
if (this.#server !== null) {
|
|
1713
|
-
// runs the frame's local sim, then
|
|
1815
|
+
// runs the frame's local sim, then closes it
|
|
1714
1816
|
this.#server.end_tick();
|
|
1715
1817
|
} else {
|
|
1716
|
-
|
|
1818
|
+
// queued before end_tick, which sends: the marker leaves with the tick's stream
|
|
1717
1819
|
this.#send_frame_marker(this.#local_frame);
|
|
1820
|
+
this.#client.end_tick();
|
|
1718
1821
|
if (this.#reconcile === NetworkSessionReconcile.Correct) {
|
|
1719
1822
|
this.#record_prediction(this.#local_frame);
|
|
1720
1823
|
}
|
|
@@ -1769,102 +1872,6 @@ export class NetworkSession {
|
|
|
1769
1872
|
return deferred;
|
|
1770
1873
|
}
|
|
1771
1874
|
|
|
1772
|
-
/**
|
|
1773
|
-
* Host, end of step: record every replicated component whose wire image differs from what the
|
|
1774
|
-
* peers hold, into the still-open frame, for the action stream to carry. Recorded, not
|
|
1775
|
-
* executed — see {@link SimActionExecutor#record}. A component an action wrote this step and
|
|
1776
|
-
* nothing changed since is not sent again: the peers apply the action.
|
|
1777
|
-
*/
|
|
1778
|
-
#publish_simulated_changes() {
|
|
1779
|
-
const world = this.world;
|
|
1780
|
-
const executor = this.#peer.executor;
|
|
1781
|
-
const scratch = this.#scratch_publish_buf;
|
|
1782
|
-
const changed_entities = executor.changed_entities;
|
|
1783
|
-
|
|
1784
|
-
for (const entity_id of this.#event_listeners.keys()) {
|
|
1785
|
-
const identity = world.getComponent(entity_id, NetworkIdentity);
|
|
1786
|
-
if (identity === undefined || identity.network_id < 0) continue;
|
|
1787
|
-
|
|
1788
|
-
for (const [ComponentClass, desc] of this.#replicated) {
|
|
1789
|
-
if (ComponentClass === NetworkIdentity) continue;
|
|
1790
|
-
|
|
1791
|
-
const live = world.getComponent(entity_id, ComponentClass);
|
|
1792
|
-
if (live === undefined) continue;
|
|
1793
|
-
|
|
1794
|
-
const type_id = desc.interp_type_id;
|
|
1795
|
-
|
|
1796
|
-
scratch.position = 0;
|
|
1797
|
-
this.binary_registry.getAdapter(ComponentClass.typeName).serialize(scratch, live);
|
|
1798
|
-
const length = scratch.position;
|
|
1799
|
-
|
|
1800
|
-
if (!this.#remember_published(entity_id, type_id, scratch.raw_bytes, length)) continue;
|
|
1801
|
-
|
|
1802
|
-
const action = this.#peer.action_registry.acquire(this.#ReplaceComponentAction);
|
|
1803
|
-
try {
|
|
1804
|
-
action.network_id = identity.network_id;
|
|
1805
|
-
action.component_type_id = type_id;
|
|
1806
|
-
action.payload_buf.position = 0;
|
|
1807
|
-
action.payload_buf.writeBytes(scratch.raw_bytes, 0, length);
|
|
1808
|
-
action.payload_length = length;
|
|
1809
|
-
executor.record(action);
|
|
1810
|
-
} finally {
|
|
1811
|
-
this.#peer.action_registry.release(action);
|
|
1812
|
-
}
|
|
1813
|
-
|
|
1814
|
-
if (changed_entities !== null) changed_entities.add(identity.network_id);
|
|
1815
|
-
}
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
/**
|
|
1820
|
-
* Host: an action wrote `ComponentClass` of `entity_id`; the peers will hold what it wrote.
|
|
1821
|
-
* @param {number} entity_id
|
|
1822
|
-
* @param {Function} ComponentClass
|
|
1823
|
-
*/
|
|
1824
|
-
#note_published(entity_id, ComponentClass) {
|
|
1825
|
-
const desc = this.#replicated.get(ComponentClass);
|
|
1826
|
-
if (desc === undefined || ComponentClass === NetworkIdentity) return;
|
|
1827
|
-
|
|
1828
|
-
const live = this.world.getComponent(entity_id, ComponentClass);
|
|
1829
|
-
if (live === undefined) return;
|
|
1830
|
-
|
|
1831
|
-
const scratch = this.#scratch_publish_buf;
|
|
1832
|
-
scratch.position = 0;
|
|
1833
|
-
this.binary_registry.getAdapter(ComponentClass.typeName).serialize(scratch, live);
|
|
1834
|
-
this.#remember_published(entity_id, desc.interp_type_id, scratch.raw_bytes, scratch.position);
|
|
1835
|
-
}
|
|
1836
|
-
|
|
1837
|
-
/**
|
|
1838
|
-
* Set what the peers hold for `(entity_id, type_id)`.
|
|
1839
|
-
* @param {number} entity_id
|
|
1840
|
-
* @param {number} type_id
|
|
1841
|
-
* @param {Uint8Array} bytes
|
|
1842
|
-
* @param {number} length
|
|
1843
|
-
* @returns {boolean} whether it differs from what was held before
|
|
1844
|
-
*/
|
|
1845
|
-
#remember_published(entity_id, type_id, bytes, length) {
|
|
1846
|
-
let published = this.#published.get(entity_id);
|
|
1847
|
-
if (published === undefined) {
|
|
1848
|
-
published = [];
|
|
1849
|
-
this.#published.set(entity_id, published);
|
|
1850
|
-
}
|
|
1851
|
-
while (published.length <= type_id) published.push(null);
|
|
1852
|
-
|
|
1853
|
-
let held = published[type_id];
|
|
1854
|
-
if (held !== null && held.length === length && bytes_equal(bytes, held.bytes, length)) {
|
|
1855
|
-
return false;
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
if (held === null || held.bytes.length < length) {
|
|
1859
|
-
held = { bytes: new Uint8Array(Math.max(length, 32)), length: 0 };
|
|
1860
|
-
published[type_id] = held;
|
|
1861
|
-
}
|
|
1862
|
-
held.bytes.set(bytes.subarray(0, length), 0);
|
|
1863
|
-
held.length = length;
|
|
1864
|
-
|
|
1865
|
-
return true;
|
|
1866
|
-
}
|
|
1867
|
-
|
|
1868
1875
|
/**
|
|
1869
1876
|
* Once per rendered frame: the work paced by wall time rather than by the simulation.
|
|
1870
1877
|
* @param {number} dt_seconds
|
|
@@ -2056,9 +2063,9 @@ export class NetworkSession {
|
|
|
2056
2063
|
* frame 6,000; a client has to start tagging its inputs near 6,000 or the host discards every
|
|
2057
2064
|
* one of them — `ServerAuthoritativeServer.tick` trims pending actions older than
|
|
2058
2065
|
* `sim_frame - frame_capacity + 1`, and a client tagging frame 0 against a host at 6,000 has
|
|
2059
|
-
* every input dropped
|
|
2060
|
-
* no signal
|
|
2061
|
-
*
|
|
2066
|
+
* every input dropped. It moves on its own screen and never moves on the host's — and until
|
|
2067
|
+
* 2026-10-15 no signal fired; the host's `onPendingActionDropped` now reports each such drop
|
|
2068
|
+
* as `'window'`.
|
|
2062
2069
|
*
|
|
2063
2070
|
* Everything needed was already there except the setter. INITIAL_SYNC carries the host's frame,
|
|
2064
2071
|
* `NetworkPeer` writes it, and `onInitialSync` dispatches it — and the handler named it
|
|
@@ -2067,8 +2074,10 @@ export class NetworkSession {
|
|
|
2067
2074
|
* with the input sampler silenced until its counter caught up: 28,801 calls and 62 ms of wall
|
|
2068
2075
|
* clock for an hour-old host. Reported as GAP-042.
|
|
2069
2076
|
*
|
|
2070
|
-
* A client now seeks automatically on INITIAL_SYNC
|
|
2071
|
-
*
|
|
2077
|
+
* A client now seeks automatically on INITIAL_SYNC, and again whenever it finds itself more than
|
|
2078
|
+
* the host's input window behind the frame the host last named — a stall, see
|
|
2079
|
+
* {@link #retake_host_time_if_stalled}. This is the manual door, for a caller that computes its
|
|
2080
|
+
* own lead.
|
|
2072
2081
|
*
|
|
2073
2082
|
* A client sends the host nothing it predicted before its last sync, and knows it by frame: its
|
|
2074
2083
|
* input starts at the frame the sync sought to. A caller whose own lead is shorter moves that
|
|
@@ -2109,6 +2118,7 @@ export class NetworkSession {
|
|
|
2109
2118
|
if (identity.owner_peer_id !== this.local_peer_id) {
|
|
2110
2119
|
this.#remote_entities.add(entity_id);
|
|
2111
2120
|
}
|
|
2121
|
+
this.#file_owner(entity_id, identity.owner_peer_id);
|
|
2112
2122
|
this.#interpolation_pending.add(entity_id);
|
|
2113
2123
|
// Per-entity event listener for net_mutate_component.
|
|
2114
2124
|
const listener = (payload) => this.#on_net_mutate_component(entity_id, payload);
|
|
@@ -2123,23 +2133,26 @@ export class NetworkSession {
|
|
|
2123
2133
|
this.#event_listeners.delete(entity_id);
|
|
2124
2134
|
}
|
|
2125
2135
|
this.#remote_entities.delete(entity_id);
|
|
2126
|
-
this.#
|
|
2136
|
+
this.#file_owner(entity_id, -1);
|
|
2127
2137
|
this.#prediction_history.forget(entity_id);
|
|
2128
2138
|
// take back our Interpolated at the next step or frame, if the entity outlives its identity
|
|
2129
2139
|
this.#interpolation_pending.add(entity_id);
|
|
2130
2140
|
}
|
|
2131
2141
|
|
|
2132
2142
|
/**
|
|
2133
|
-
* Handler for `"net_mutate_component"` events
|
|
2134
|
-
*
|
|
2143
|
+
* Handler for `"net_mutate_component"` events: a replicated component changed outside an
|
|
2144
|
+
* action, and goes through the executor as a `ReplaceComponentAction`. The session finds no
|
|
2145
|
+
* change by itself (see the README, "What travels"); this is the door for a system that writes
|
|
2146
|
+
* replicated state directly — physics publishing its moving bodies, say — at a cost per
|
|
2147
|
+
* change, never per entity.
|
|
2135
2148
|
*
|
|
2136
2149
|
* Payload:
|
|
2137
|
-
* - `{ component_type, new_state }` —
|
|
2138
|
-
*
|
|
2139
|
-
*
|
|
2140
|
-
*
|
|
2141
|
-
*
|
|
2142
|
-
*
|
|
2150
|
+
* - `{ component_type, new_state }` — the engine captures the current bytes as prior, then
|
|
2151
|
+
* applies `new_state` through the replication adapter.
|
|
2152
|
+
* - `{ component_type }` — the caller has already written live. On the host it is recorded,
|
|
2153
|
+
* not executed ({@link SimActionExecutor#record}): live is the truth, at full precision,
|
|
2154
|
+
* and executing would write the wire's quantised image back over it. On a client it is
|
|
2155
|
+
* executed, so prediction and rewind keep their prior state.
|
|
2143
2156
|
*/
|
|
2144
2157
|
#on_net_mutate_component(entity_id, payload) {
|
|
2145
2158
|
const { component_type, new_state } = payload || {};
|
|
@@ -2174,8 +2187,15 @@ export class NetworkSession {
|
|
|
2174
2187
|
}
|
|
2175
2188
|
action.payload_length = action.payload_buf.position;
|
|
2176
2189
|
|
|
2190
|
+
const executor = this.#peer.executor;
|
|
2177
2191
|
try {
|
|
2178
|
-
this.#
|
|
2192
|
+
if (this.#server !== null && (new_state === undefined || new_state === null)) {
|
|
2193
|
+
executor.record(action);
|
|
2194
|
+
// recorded writes are changes too: a join re-sends an entity changed after its page
|
|
2195
|
+
if (executor.changed_entities !== null) executor.changed_entities.add(network_id);
|
|
2196
|
+
} else {
|
|
2197
|
+
executor.execute(action, this.local_peer_id);
|
|
2198
|
+
}
|
|
2179
2199
|
} finally {
|
|
2180
2200
|
this.#peer.action_registry.release(action);
|
|
2181
2201
|
}
|
|
@@ -2280,41 +2300,31 @@ export class NetworkSession {
|
|
|
2280
2300
|
* @param {number} sim_frame
|
|
2281
2301
|
*/
|
|
2282
2302
|
#on_host_tick_complete(sim_frame) {
|
|
2283
|
-
//
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
if (sends_remaining <= 1) {
|
|
2292
|
-
this.#pending_initial_sync.delete(peer_id);
|
|
2293
|
-
} else {
|
|
2294
|
-
this.#pending_initial_sync.set(peer_id, sends_remaining - 1);
|
|
2303
|
+
// Joins first: a page is the state at this frame, which has just closed.
|
|
2304
|
+
if (this.#joins.size > 0) {
|
|
2305
|
+
for (const [peer_id, join] of this.#joins) {
|
|
2306
|
+
const progress = join.advance(sim_frame);
|
|
2307
|
+
if (progress === JoinProgress.Done) {
|
|
2308
|
+
this.#joins.delete(peer_id);
|
|
2309
|
+
} else if (progress === JoinProgress.DidNotConverge) {
|
|
2310
|
+
this.drop_peer(peer_id, 'join_did_not_converge');
|
|
2295
2311
|
}
|
|
2296
|
-
|
|
2297
2312
|
}
|
|
2298
|
-
|
|
2299
2313
|
}
|
|
2300
2314
|
|
|
2301
2315
|
// AUTH_STATE per owned entity, then time-dilation feedback, to
|
|
2302
|
-
// every connected peer.
|
|
2316
|
+
// every connected peer. A peer still joining gets no AUTH_STATE: it
|
|
2317
|
+
// does not hold the world the state would correct yet.
|
|
2303
2318
|
for (const peer_id of this.#connected_peers) {
|
|
2304
2319
|
|
|
2305
|
-
|
|
2320
|
+
const owned = this.#joins.has(peer_id) ? undefined : this.#owned_by.get(peer_id);
|
|
2306
2321
|
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
continue;
|
|
2322
|
+
if (owned !== undefined) {
|
|
2323
|
+
for (const entity_id of owned) {
|
|
2324
|
+
const identity = this.world.getComponent(entity_id, NetworkIdentity);
|
|
2325
|
+
if (identity === undefined) continue;
|
|
2326
|
+
this.#send_auth_state_for_entity(peer_id, sim_frame, entity_id, identity);
|
|
2311
2327
|
}
|
|
2312
|
-
if (identity.owner_peer_id !== peer_id) {
|
|
2313
|
-
continue;
|
|
2314
|
-
}
|
|
2315
|
-
|
|
2316
|
-
this.#send_auth_state_for_entity(peer_id, sim_frame, entity_id, identity);
|
|
2317
|
-
|
|
2318
2328
|
}
|
|
2319
2329
|
|
|
2320
2330
|
this.#server.send_time_dilation_feedback(peer_id);
|
|
@@ -2323,49 +2333,215 @@ export class NetworkSession {
|
|
|
2323
2333
|
|
|
2324
2334
|
|
|
2325
2335
|
/**
|
|
2326
|
-
*
|
|
2327
|
-
*
|
|
2328
|
-
*
|
|
2329
|
-
*
|
|
2330
|
-
*
|
|
2331
|
-
*
|
|
2336
|
+
* Start `peer_id`'s join, unless its connection has been given one already — started, or
|
|
2337
|
+
* finished. These are the host's only whole-world sends, so how many a connection gets is the
|
|
2338
|
+
* host's decision: one, when it takes the connection for a fresh peer — as `connect()` binds
|
|
2339
|
+
* it, or after refusing its claim to resume. Nothing the peer sends afterwards earns it another.
|
|
2340
|
+
*
|
|
2341
|
+
* The peer's action stream is held from here until the join's FINAL page: what it would carry
|
|
2342
|
+
* is about a world the peer does not hold yet. The session token is issued here, and goes out
|
|
2343
|
+
* with every page; the receiver echoes it back via RESUME_HELLO to authenticate a later
|
|
2344
|
+
* reconnect.
|
|
2332
2345
|
* @param {number} peer_id
|
|
2333
2346
|
*/
|
|
2334
2347
|
#queue_initial_sync(peer_id) {
|
|
2335
2348
|
if (this.#initial_sync_given.has(peer_id)) return;
|
|
2336
2349
|
this.#initial_sync_given.add(peer_id);
|
|
2337
|
-
|
|
2350
|
+
|
|
2351
|
+
let token = this.#peer_session_tokens.get(peer_id);
|
|
2352
|
+
if (token === undefined) {
|
|
2353
|
+
token = UUID.v1();
|
|
2354
|
+
this.#peer_session_tokens.set(peer_id, token);
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
this.#peer.hold_outbound(peer_id);
|
|
2358
|
+
this.#joins.set(peer_id, new HostJoin({
|
|
2359
|
+
peer: this.#peer,
|
|
2360
|
+
peer_id,
|
|
2361
|
+
session_token: token.data,
|
|
2362
|
+
world: this.world,
|
|
2363
|
+
for_each_entity: this.#for_each_networked_entity,
|
|
2364
|
+
page_buffer: this.#page_buffer,
|
|
2365
|
+
window_bytes: 128 * 1024,
|
|
2366
|
+
}));
|
|
2338
2367
|
}
|
|
2339
2368
|
|
|
2340
2369
|
/**
|
|
2341
|
-
*
|
|
2342
|
-
*
|
|
2343
|
-
|
|
2344
|
-
|
|
2370
|
+
* Visits every networked entity: those whose NetworkIdentity the session is listening to.
|
|
2371
|
+
* @type {function(function(number): void): void}
|
|
2372
|
+
*/
|
|
2373
|
+
#for_each_networked_entity = (visit) => {
|
|
2374
|
+
for (const entity_id of this.#event_listeners.keys()) {
|
|
2375
|
+
visit(entity_id);
|
|
2376
|
+
}
|
|
2377
|
+
};
|
|
2378
|
+
|
|
2379
|
+
/**
|
|
2380
|
+
* Client: the first page of a join. It is this binding's answer: the world is about to be the
|
|
2381
|
+
* host's, so what was predicted, sampled or told about the one the client had goes, and the
|
|
2382
|
+
* reconnect ladder stops — a join of a large world takes a while, and an attempt that tore the
|
|
2383
|
+
* binding down would restart it from the first page.
|
|
2384
|
+
*
|
|
2345
2385
|
* @param {number} peer_id
|
|
2346
|
-
* @param {
|
|
2386
|
+
* @param {Uint8Array} session_token
|
|
2387
|
+
* @param {number} frame_number the frame the page's state is from
|
|
2388
|
+
*/
|
|
2389
|
+
#begin_sync(peer_id, session_token, frame_number) {
|
|
2390
|
+
const token = new UUID();
|
|
2391
|
+
token.data = session_token;
|
|
2392
|
+
this.session_token = token;
|
|
2393
|
+
|
|
2394
|
+
this.#align_to_host(frame_number);
|
|
2395
|
+
this.#forget_predicted_world();
|
|
2396
|
+
this.#binding_answer = BindingAnswer.Syncing;
|
|
2397
|
+
// The host releases its action stream, and its AUTH_STATE, from the frame after the last
|
|
2398
|
+
// page; their datagrams can overtake the pages. The binding's inbound hold, taken at
|
|
2399
|
+
// `connect()`, keeps them until the world is whole.
|
|
2400
|
+
|
|
2401
|
+
// Reconnecting counts as well as Resyncing: a host that has
|
|
2402
|
+
// finished with our old session readmits us as a fresh peer,
|
|
2403
|
+
// so the snapshot arrives with no RESUME_ACCEPT ahead of it.
|
|
2404
|
+
// That is the reconnection — staying in the ladder would burn
|
|
2405
|
+
// attempts while holding the world the host is sending, and
|
|
2406
|
+
// recovering later via RESUME_ACCEPT would report
|
|
2407
|
+
// `state_resynced: false` over a world that was wholly
|
|
2408
|
+
// replaced. `Lost` is excluded on purpose: the application has
|
|
2409
|
+
// already been told that session is over.
|
|
2410
|
+
if (this.#reconnect_state === ReconnectState.Resyncing
|
|
2411
|
+
|| this.#reconnect_state === ReconnectState.Reconnecting) {
|
|
2412
|
+
this.#enter_connected();
|
|
2413
|
+
this.onReconnected.send1({ state_resynced: true });
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
/**
|
|
2418
|
+
* Client: the FINAL page. Every entity's state at `frame_number` is here, and the host's action
|
|
2419
|
+
* stream resumes after it. The client predicted on a partial world while the pages came in, and
|
|
2420
|
+
* against the frame the first page named, which is as old as the join is long: both are put
|
|
2421
|
+
* right here, and only then does the client's input go out.
|
|
2422
|
+
*
|
|
2423
|
+
* @param {number} peer_id
|
|
2424
|
+
* @param {number} frame_number
|
|
2347
2425
|
*/
|
|
2348
|
-
#
|
|
2349
|
-
|
|
2426
|
+
#finish_sync(peer_id, frame_number) {
|
|
2427
|
+
this.#align_to_host(frame_number);
|
|
2428
|
+
this.#forget_predicted_world();
|
|
2429
|
+
this.#binding_answer = BindingAnswer.Synced;
|
|
2350
2430
|
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2431
|
+
// Input from here on is predicted on the host's world. What was predicted before —
|
|
2432
|
+
// held since this binding was made, or still in the log from before it — was
|
|
2433
|
+
// predicted on a world that is gone, or half-built, and is never sent.
|
|
2434
|
+
this.#world_start_frame = this.#local_frame;
|
|
2435
|
+
this.#peer.release_outbound(peer_id, this.#world_start_frame);
|
|
2436
|
+
|
|
2437
|
+
// what the host sent after the last page, applied as the step's inbound is done, now that
|
|
2438
|
+
// the world it is about is here; then onSynced
|
|
2439
|
+
this.#inbound_release_peer = peer_id;
|
|
2440
|
+
this.#inbound_release_syncs = true;
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
/**
|
|
2444
|
+
* Client: apply what the binding held, once its answer is whole (see {@link #inbound_release_peer}).
|
|
2445
|
+
*/
|
|
2446
|
+
#release_held_inbound() {
|
|
2447
|
+
const peer_id = this.#inbound_release_peer;
|
|
2448
|
+
if (peer_id < 0) return;
|
|
2449
|
+
this.#inbound_release_peer = -1;
|
|
2450
|
+
if (!this.#peer.is_connected(peer_id)) return;
|
|
2451
|
+
this.#peer.release_inbound(peer_id);
|
|
2452
|
+
if (this.#inbound_release_syncs) {
|
|
2453
|
+
this.#inbound_release_syncs = false;
|
|
2454
|
+
this.onSynced.send0();
|
|
2354
2455
|
}
|
|
2456
|
+
}
|
|
2355
2457
|
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2458
|
+
/**
|
|
2459
|
+
* Seek the frame counter to the host's `frame_number` — or the newer frame a TIME_DILATION
|
|
2460
|
+
* has named since — plus the lead input needs.
|
|
2461
|
+
*
|
|
2462
|
+
* The frame has always been on the wire — it was named `_frame_number` and dropped — and
|
|
2463
|
+
* without it a client joining a match in progress tags its inputs from 0 against a host at
|
|
2464
|
+
* frame 6,000, which trims every one of them silently. GAP-042.
|
|
2465
|
+
*
|
|
2466
|
+
* The lead is the buffer depth the time dilation is already steering toward: an input
|
|
2467
|
+
* authored now arrives in the host's future, and this is how far ahead it has to be tagged to
|
|
2468
|
+
* land in the window rather than behind it. It only has to be in the right neighbourhood —
|
|
2469
|
+
* `TimeDilation` converges on the real depth from the host's feedback within a second or two —
|
|
2470
|
+
* but starting six thousand frames out is not a neighbourhood, which is what made this total
|
|
2471
|
+
* rather than approximate.
|
|
2472
|
+
*
|
|
2473
|
+
* @param {number} frame_number
|
|
2474
|
+
*/
|
|
2475
|
+
#align_to_host(frame_number) {
|
|
2476
|
+
const host_frame = Math.max(frame_number, this.#host_frame_seen);
|
|
2477
|
+
this.seek_to_frame(host_frame + 1 + this.#time_dilation.target_buffer_depth);
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
/**
|
|
2481
|
+
* Drop what this client predicted, sampled or was told about the world it held: it is about a
|
|
2482
|
+
* world, and a frame numbering, that is being replaced.
|
|
2483
|
+
*/
|
|
2484
|
+
#forget_predicted_world() {
|
|
2485
|
+
this.#prediction_history.clear();
|
|
2486
|
+
this.#pending_auth.clear();
|
|
2487
|
+
this.#reconciled_frame.clear();
|
|
2488
|
+
this.#sampled_actions_per_frame.clear();
|
|
2489
|
+
this.#client.forget_timeline();
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
/**
|
|
2493
|
+
* Client, as a step opens: more than the host's input window behind, the client re-takes the
|
|
2494
|
+
* host's time.
|
|
2495
|
+
*
|
|
2496
|
+
* A client stops stepping when its tab goes to the background (`Ticker` suspends, and discards
|
|
2497
|
+
* the gap when the tab returns), under a debugger, or with the lid shut; the host runs on, and
|
|
2498
|
+
* what it sent meanwhile is waiting in the held transport. Nothing told the session. Behind by N
|
|
2499
|
+
* frames, the time dilation closed the gap at 5% — 20 × N frames, 190 s for a 10 s stall — and
|
|
2500
|
+
* until the gap was inside the window `ServerAuthoritativeServer.begin_tick` trimmed every input
|
|
2501
|
+
* the client sent, silently: the client's own entities ran off on its screen, and were yanked
|
|
2502
|
+
* back by the corrections once its input landed again. Measured 2026-10-15; the spec is
|
|
2503
|
+
* `NetworkSession.stall.spec.js`.
|
|
2504
|
+
*
|
|
2505
|
+
* The host names its frame in every TIME_DILATION packet (`#host_frame_seen`), so the gap is
|
|
2506
|
+
* known the moment the held packets are applied. Past the window — where the host drops input
|
|
2507
|
+
* rather than applying it late — it is a discontinuity, not something to steer: the counter is
|
|
2508
|
+
* re-taken as INITIAL_SYNC takes it, and what was predicted on the old numbering is dropped.
|
|
2509
|
+
* Inside the window the dilation is left to it, with the input applied late meanwhile (a 31-frame
|
|
2510
|
+
* stall costs 9.8 s of that). The window is the host's; the client's own `frame_capacity` stands
|
|
2511
|
+
* for it here, the host never names it, and the two default alike.
|
|
2512
|
+
*
|
|
2513
|
+
* The gap is exact only at zero latency: the frame the host named is a one-way trip old, and
|
|
2514
|
+
* input tagged now lands a one-way trip later, so a client behind by a little less than the
|
|
2515
|
+
* window as it sees it is behind by more than the window as the host does — every input
|
|
2516
|
+
* dropped, and the gap never says so, for the 20 × 2 × latency frames the dilation takes to
|
|
2517
|
+
* close the band (2 s at 50 ms one way). The host's depth feedback says so exactly: it is its
|
|
2518
|
+
* latest sight of our frame minus its sim frame, measured where our input lands, latency
|
|
2519
|
+
* included. At or past the window's depth the host is dropping our input, and the client
|
|
2520
|
+
* re-takes its time — once the host has seen input from the time last taken, since the reports
|
|
2521
|
+
* in flight after a re-align still carry the old depth.
|
|
2522
|
+
*
|
|
2523
|
+
* Keyed on the gap and on the host's word, never on the page's visibility: a debugger pause, a
|
|
2524
|
+
* GC stall and a sleeping laptop look the same from here, and the session never sees the ticker.
|
|
2525
|
+
*/
|
|
2526
|
+
#retake_host_time_if_stalled() {
|
|
2527
|
+
if (this.#binding_answer !== BindingAnswer.Synced && this.#binding_answer !== BindingAnswer.Resumed) return;
|
|
2528
|
+
|
|
2529
|
+
const behind = this.#host_frame_seen - this.#local_frame;
|
|
2530
|
+
const trimmed = this.#host_depth_seen <= -this.frame_capacity
|
|
2531
|
+
&& this.#host_marker_seen >= this.#world_start_frame;
|
|
2532
|
+
if (behind < this.frame_capacity && !trimmed) return;
|
|
2533
|
+
|
|
2534
|
+
this.stall_count++;
|
|
2535
|
+
|
|
2536
|
+
this.#align_to_host(this.#host_frame_seen);
|
|
2537
|
+
this.#forget_predicted_world();
|
|
2538
|
+
|
|
2539
|
+
// Input from here on is predicted on the host's time. What was predicted before it is below
|
|
2540
|
+
// the host's window and would be trimmed on arrival, so it is not sent.
|
|
2541
|
+
this.#world_start_frame = this.#local_frame;
|
|
2542
|
+
if (this.#peer.is_connected(this.#remote_peer_id)) {
|
|
2543
|
+
this.#peer.release_outbound(this.#remote_peer_id, this.#world_start_frame);
|
|
2544
|
+
}
|
|
2369
2545
|
}
|
|
2370
2546
|
|
|
2371
2547
|
/**
|
|
@@ -2382,7 +2558,7 @@ export class NetworkSession {
|
|
|
2382
2558
|
// written over the truth, not over a render blend that a restore would then put back
|
|
2383
2559
|
this.normalize_if_dirty();
|
|
2384
2560
|
|
|
2385
|
-
const entity_count = buffer.
|
|
2561
|
+
const entity_count = buffer.readUint32();
|
|
2386
2562
|
for (let i = 0; i < entity_count; i++) {
|
|
2387
2563
|
const network_id = buffer.readUintVar();
|
|
2388
2564
|
const component_count = buffer.readUint8();
|
|
@@ -2471,9 +2647,35 @@ export class NetworkSession {
|
|
|
2471
2647
|
} else {
|
|
2472
2648
|
this.#remote_entities.add(entity_id);
|
|
2473
2649
|
}
|
|
2650
|
+
this.#file_owner(entity_id, owner_peer_id);
|
|
2474
2651
|
this.#interpolation_pending.add(entity_id);
|
|
2475
2652
|
}
|
|
2476
2653
|
|
|
2654
|
+
/**
|
|
2655
|
+
* File `entity_id` under `owner_peer_id` in {@link #owned_by}, out of wherever it was; -1 files
|
|
2656
|
+
* it nowhere.
|
|
2657
|
+
* @param {number} entity_id
|
|
2658
|
+
* @param {number} owner_peer_id
|
|
2659
|
+
*/
|
|
2660
|
+
#file_owner(entity_id, owner_peer_id) {
|
|
2661
|
+
const previous = this.#owner_of.get(entity_id);
|
|
2662
|
+
if (previous === owner_peer_id) return;
|
|
2663
|
+
if (previous !== undefined) {
|
|
2664
|
+
const set = this.#owned_by.get(previous);
|
|
2665
|
+
set.delete(entity_id);
|
|
2666
|
+
if (set.size === 0) this.#owned_by.delete(previous);
|
|
2667
|
+
this.#owner_of.delete(entity_id);
|
|
2668
|
+
}
|
|
2669
|
+
if (owner_peer_id < 0) return;
|
|
2670
|
+
let set = this.#owned_by.get(owner_peer_id);
|
|
2671
|
+
if (set === undefined) {
|
|
2672
|
+
set = new Set();
|
|
2673
|
+
this.#owned_by.set(owner_peer_id, set);
|
|
2674
|
+
}
|
|
2675
|
+
set.add(entity_id);
|
|
2676
|
+
this.#owner_of.set(entity_id, owner_peer_id);
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2477
2679
|
/**
|
|
2478
2680
|
*
|
|
2479
2681
|
* @param {number} peer_id
|
|
@@ -2551,7 +2753,7 @@ export class NetworkSession {
|
|
|
2551
2753
|
// session. Both calls are no-ops when there is nothing to release.
|
|
2552
2754
|
this.#server.disconnect_peer(peer_id);
|
|
2553
2755
|
this.#unwire_peer_transport_disconnect(peer_id);
|
|
2554
|
-
this.#
|
|
2756
|
+
this.#joins.delete(peer_id);
|
|
2555
2757
|
return;
|
|
2556
2758
|
}
|
|
2557
2759
|
const last_acked = this.#peer.baseline.last_acked(peer_id);
|
|
@@ -2563,15 +2765,32 @@ export class NetworkSession {
|
|
|
2563
2765
|
// from `#on_host_tick_complete` and throws — before AUTH_STATE and
|
|
2564
2766
|
// time-dilation feedback go out to *any* peer, and without ever
|
|
2565
2767
|
// draining the entry, so every later tick throws the same way.
|
|
2566
|
-
|
|
2768
|
+
// a peer that drops before its join finished holds half a world: it may not resume it
|
|
2769
|
+
const join_complete = !this.#joins.has(peer_id);
|
|
2770
|
+
this.#joins.delete(peer_id);
|
|
2567
2771
|
this.#unwire_peer_transport_disconnect(peer_id);
|
|
2568
2772
|
this.#peer_grace_state.set(peer_id, {
|
|
2569
2773
|
deadline_ms: this.#clock_ms + this.#server_resume_grace_ms,
|
|
2570
2774
|
last_acked,
|
|
2775
|
+
join_complete,
|
|
2571
2776
|
});
|
|
2572
2777
|
this.onPeerLost.send2(peer_id, reason);
|
|
2573
2778
|
}
|
|
2574
2779
|
|
|
2780
|
+
/**
|
|
2781
|
+
* Host: `peer_id`'s connection is no longer whole (see Connection.onProtocolError) and can
|
|
2782
|
+
* carry nothing more. Handled as its transport dropping — the peer goes into the grace window
|
|
2783
|
+
* and may resume on a new connection — and the transport is closed, so the client hears of it
|
|
2784
|
+
* now rather than when silence reaps it.
|
|
2785
|
+
* @param {number} peer_id
|
|
2786
|
+
* @param {string} reason
|
|
2787
|
+
*/
|
|
2788
|
+
#on_peer_protocol_error(peer_id, reason) {
|
|
2789
|
+
const entry = this.#peer_transport_listeners.get(peer_id);
|
|
2790
|
+
this.#on_peer_transport_disconnected(peer_id, `protocol_error: ${reason}`);
|
|
2791
|
+
if (entry !== undefined) close_transport(entry.transport);
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2575
2794
|
/**
|
|
2576
2795
|
* Validate a RESUME_HELLO and either welcome the peer back (restore
|
|
2577
2796
|
* baseline + send RESUME_ACCEPT) or reject with a reason code. A claim
|
|
@@ -2603,6 +2822,7 @@ export class NetworkSession {
|
|
|
2603
2822
|
if (transport_peer_id !== claimed_peer_id) {
|
|
2604
2823
|
this.#peer.send_resume_reject(transport_peer_id, ResumeRejectReason.PeerIdCollision);
|
|
2605
2824
|
this.#peer.send_disconnect(transport_peer_id, 'peer_id_collision');
|
|
2825
|
+
this.#flush_last_word(transport_peer_id);
|
|
2606
2826
|
this.#server.disconnect_peer(transport_peer_id);
|
|
2607
2827
|
this.#unwire_peer_transport_disconnect(transport_peer_id);
|
|
2608
2828
|
// The transport may have been added to the live set in connect()
|
|
@@ -2611,7 +2831,7 @@ export class NetworkSession {
|
|
|
2611
2831
|
// serializes AUTH_STATE / time-dilation to a now-disposed conn and
|
|
2612
2832
|
// throws "peer not connected", taking down the tick for all peers.
|
|
2613
2833
|
this.#connected_peers.delete(transport_peer_id);
|
|
2614
|
-
this.#
|
|
2834
|
+
this.#joins.delete(transport_peer_id);
|
|
2615
2835
|
this.#peer_inbound_mark.delete(transport_peer_id);
|
|
2616
2836
|
return;
|
|
2617
2837
|
}
|
|
@@ -2639,6 +2859,7 @@ export class NetworkSession {
|
|
|
2639
2859
|
// INITIAL_SYNC queue.
|
|
2640
2860
|
this.#peer.send_resume_reject(transport_peer_id, ResumeRejectReason.NoSessionToken);
|
|
2641
2861
|
this.#peer.send_disconnect(transport_peer_id, 'no_session_token');
|
|
2862
|
+
this.#flush_last_word(transport_peer_id);
|
|
2642
2863
|
this.#server.disconnect_peer(transport_peer_id);
|
|
2643
2864
|
this.#unwire_peer_transport_disconnect(transport_peer_id);
|
|
2644
2865
|
return;
|
|
@@ -2679,16 +2900,28 @@ export class NetworkSession {
|
|
|
2679
2900
|
// a new peer_id from the matchmaking layer.
|
|
2680
2901
|
this.#peer.send_resume_reject(transport_peer_id, ResumeRejectReason.TokenMismatch);
|
|
2681
2902
|
this.#peer.send_disconnect(transport_peer_id, 'token_mismatch');
|
|
2903
|
+
this.#flush_last_word(transport_peer_id);
|
|
2682
2904
|
this.#server.disconnect_peer(transport_peer_id);
|
|
2683
2905
|
this.#unwire_peer_transport_disconnect(transport_peer_id);
|
|
2684
2906
|
// Same cleanup as the collision branch above: if this transport was
|
|
2685
2907
|
// a fresh peer added to the live set, drop it from both iterated
|
|
2686
2908
|
// maps so the next host tick doesn't address a disposed conn.
|
|
2687
2909
|
this.#connected_peers.delete(transport_peer_id);
|
|
2688
|
-
this.#
|
|
2910
|
+
this.#joins.delete(transport_peer_id);
|
|
2689
2911
|
this.#peer_inbound_mark.delete(transport_peer_id);
|
|
2690
2912
|
return;
|
|
2691
2913
|
}
|
|
2914
|
+
// A join that never finished. The client holds whatever pages reached it — part of a
|
|
2915
|
+
// world — and resuming would keep it. Refused like a stale frame: the client falls through
|
|
2916
|
+
// to a full resync.
|
|
2917
|
+
if (grace.join_complete === false) {
|
|
2918
|
+
this.#peer.send_resume_reject(transport_peer_id, ResumeRejectReason.StaleFrame);
|
|
2919
|
+
this.#peer_grace_state.delete(claimed_peer_id);
|
|
2920
|
+
this.#queue_initial_sync(transport_peer_id);
|
|
2921
|
+
this.#connected_peers.add(transport_peer_id);
|
|
2922
|
+
return;
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2692
2925
|
// Ring-floor gate. The client asks to resume from `last_acked_frame + 1`,
|
|
2693
2926
|
// but the action-log ring only still holds frames back to
|
|
2694
2927
|
// `current_sim_frame - frame_capacity + 1`. If the requested frame
|
|
@@ -2733,7 +2966,7 @@ export class NetworkSession {
|
|
|
2733
2966
|
// so release it here or the id stays unconnectable forever.
|
|
2734
2967
|
this.#server.disconnect_peer(peer_id);
|
|
2735
2968
|
this.#unwire_peer_transport_disconnect(peer_id);
|
|
2736
|
-
this.#
|
|
2969
|
+
this.#joins.delete(peer_id);
|
|
2737
2970
|
this.onPeerPermanentlyDropped.send2(peer_id, 'grace_expired');
|
|
2738
2971
|
}
|
|
2739
2972
|
}
|
|
@@ -2748,6 +2981,13 @@ export class NetworkSession {
|
|
|
2748
2981
|
* pinned forever (host) or never noticed (client). The per-tick keepalive
|
|
2749
2982
|
* traffic the facade sends both directions keeps a live connection well
|
|
2750
2983
|
* clear of the budget. Called from `tick()` only when the budget is > 0.
|
|
2984
|
+
*
|
|
2985
|
+
* The host closes a reaped peer's transport as well. A silent peer is not always a gone one: a
|
|
2986
|
+
* client whose tab went to the background stops stepping and keeps its socket, and when it steps
|
|
2987
|
+
* again the close is waiting behind the packets it was sent, so it learns of the reap then — not
|
|
2988
|
+
* a whole silence budget later, on a clock that stood still with it (its budget runs on frame
|
|
2989
|
+
* time). A transport with no close of its own (`NodeUDP`) leaves it to that budget.
|
|
2990
|
+
* `NetworkSession.stall.spec.js`.
|
|
2751
2991
|
* @private
|
|
2752
2992
|
*/
|
|
2753
2993
|
#reap_silent_peers() {
|
|
@@ -2759,7 +2999,11 @@ export class NetworkSession {
|
|
|
2759
2999
|
}
|
|
2760
3000
|
if (to_reap !== null) {
|
|
2761
3001
|
for (let i = 0; i < to_reap.length; i++) {
|
|
2762
|
-
|
|
3002
|
+
const peer_id = to_reap[i];
|
|
3003
|
+
// unwired by the reap before it is closed, so the close is not taken for a second loss
|
|
3004
|
+
const entry = this.#peer_transport_listeners.get(peer_id);
|
|
3005
|
+
this.#on_peer_transport_disconnected(peer_id, 'timeout');
|
|
3006
|
+
if (entry !== undefined) close_transport(entry.transport);
|
|
2763
3007
|
}
|
|
2764
3008
|
}
|
|
2765
3009
|
} else if (this.#reconnect_state === ReconnectState.Connected && this.#remote_peer_id >= 0) {
|
|
@@ -2813,6 +3057,25 @@ export class NetworkSession {
|
|
|
2813
3057
|
this.#current_transport_listener = listener;
|
|
2814
3058
|
}
|
|
2815
3059
|
|
|
3060
|
+
/**
|
|
3061
|
+
* Client: the connection to the host is no longer whole (see Connection.onProtocolError) and
|
|
3062
|
+
* can carry nothing more. Given up as a dropped transport is — the reconnect ladder resumes on
|
|
3063
|
+
* a new one — and closed, so the host hears of it now rather than when silence reaps it.
|
|
3064
|
+
* @param {string} reason
|
|
3065
|
+
*/
|
|
3066
|
+
#on_client_protocol_error(reason) {
|
|
3067
|
+
const transport = this.#current_transport;
|
|
3068
|
+
// unhooked first: the close must not be taken for a second loss
|
|
3069
|
+
if (transport !== null && this.#current_transport_listener !== null) {
|
|
3070
|
+
try {
|
|
3071
|
+
transport.onDisconnect.remove(this.#current_transport_listener);
|
|
3072
|
+
} catch (_) { /* swallow */
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
this.#on_client_transport_disconnected(`protocol_error: ${reason}`);
|
|
3076
|
+
if (transport !== null) close_transport(transport);
|
|
3077
|
+
}
|
|
3078
|
+
|
|
2816
3079
|
#on_client_transport_disconnected(reason) {
|
|
2817
3080
|
if (this.#reconnect_state === ReconnectState.Lost) return;
|
|
2818
3081
|
// Tear down the dead peer/channel binding so a fresh transport
|
|
@@ -3001,9 +3264,10 @@ export class NetworkSession {
|
|
|
3001
3264
|
const scratch = this.#scratch_send_buf;
|
|
3002
3265
|
const world = this.world;
|
|
3003
3266
|
|
|
3004
|
-
|
|
3005
|
-
|
|
3267
|
+
const owned = this.#owned_by.get(this.local_peer_id);
|
|
3268
|
+
if (owned === undefined) return;
|
|
3006
3269
|
|
|
3270
|
+
for (const entity_id of owned) {
|
|
3007
3271
|
const identity = world.getComponent(entity_id, NetworkIdentity);
|
|
3008
3272
|
if (identity === undefined || identity.network_id < 0) continue;
|
|
3009
3273
|
|