@woosh/meep-engine 3.45.0 → 3.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/bundle-worker-terrain.js +1 -1
- package/editor/actions/concrete/TransformModifyAction.d.ts.map +1 -1
- package/editor/actions/concrete/TransformModifyAction.js +10 -2
- package/editor/ecs/component/FieldDescriptor.js +15 -0
- package/editor/ecs/component/createObjectEditor.js +41 -12
- package/editor/ecs/component/editors/ecs/Transform64Editor.d.ts.map +1 -1
- package/editor/ecs/component/editors/ecs/Transform64Editor.js +77 -70
- package/editor/tools/TransformToolV2.d.ts.map +1 -1
- package/editor/tools/TransformToolV2.js +4 -0
- package/editor/tools/v2/TransformControls.d.ts.map +1 -1
- package/editor/tools/v2/TransformControls.js +7 -0
- package/editor/view/ecs/EntityEditor.d.ts.map +1 -1
- package/editor/view/ecs/EntityEditor.js +4 -2
- package/package.json +1 -1
- package/src/core/assert.d.ts.map +1 -1
- package/src/core/assert.js +5 -1
- package/src/core/binary/hash/XXH128Hash.d.ts +1 -37
- package/src/core/binary/hash/XXH128Hash.d.ts.map +1 -1
- package/src/core/binary/hash/XXH128Hash.js +4 -55
- package/src/core/binary/hash/XXH3_SECRET.d.ts +1 -12
- package/src/core/binary/hash/XXH3_SECRET.d.ts.map +1 -1
- package/src/core/binary/hash/XXH3_SECRET.js +4 -25
- package/src/core/binary/hash/crc32.d.ts +1 -15
- package/src/core/binary/hash/crc32.d.ts.map +1 -1
- package/src/core/binary/hash/crc32.js +4 -96
- package/src/core/binary/hash/xxh3_128.d.ts +1 -9
- package/src/core/binary/hash/xxh3_128.d.ts.map +1 -1
- package/src/core/binary/hash/xxh3_128.js +4 -341
- package/src/core/binary/hash/xxh3_64.d.ts +1 -8
- package/src/core/binary/hash/xxh3_64.d.ts.map +1 -1
- package/src/core/binary/hash/xxh3_64.js +4 -241
- package/src/core/binary/hash/xxh3_common.d.ts +1 -223
- package/src/core/binary/hash/xxh3_common.d.ts.map +1 -1
- package/src/core/binary/hash/xxh3_common.js +90 -476
- package/src/core/collection/array/array_insert_at.d.ts +16 -0
- package/src/core/collection/array/array_insert_at.d.ts.map +1 -0
- package/src/core/collection/array/array_insert_at.js +32 -0
- package/src/core/collection/array/array_remove_at.d.ts +15 -0
- package/src/core/collection/array/array_remove_at.d.ts.map +1 -0
- package/src/core/collection/array/array_remove_at.js +30 -0
- package/src/core/collection/array/combine_hash.d.ts +6 -0
- package/src/core/collection/array/combine_hash.d.ts.map +1 -1
- package/src/core/collection/array/combine_hash.js +6 -0
- package/src/core/function/FunctionCompiler.js +2 -2
- package/src/core/geom/3d/mat4/m4_multiply.d.ts +3 -0
- package/src/core/geom/3d/mat4/m4_multiply.d.ts.map +1 -1
- package/src/core/geom/3d/mat4/m4_multiply.js +3 -0
- package/src/core/geom/3d/mat4/m4_multiply_f64.d.ts +30 -0
- package/src/core/geom/3d/mat4/m4_multiply_f64.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_multiply_f64.js +106 -0
- package/src/core/geom/3d/quaternion/quat3_look_rotation.d.ts +37 -0
- package/src/core/geom/3d/quaternion/quat3_look_rotation.d.ts.map +1 -0
- package/src/core/geom/3d/quaternion/quat3_look_rotation.js +172 -0
- package/src/core/geom/ConicRay.js +2 -2
- package/src/core/geom/Quaternion.d.ts +1 -0
- package/src/core/geom/Quaternion.d.ts.map +1 -1
- package/src/core/geom/Quaternion.js +12 -48
- package/src/core/geom/Vector4.d.ts.map +1 -1
- package/src/core/geom/Vector4.js +8 -5
- package/src/core/math/hash/XXH128Hash.d.ts +38 -0
- package/src/core/math/hash/XXH128Hash.d.ts.map +1 -0
- package/src/core/math/hash/XXH128Hash.js +55 -0
- package/src/core/math/hash/XXH3_SECRET.d.ts +13 -0
- package/src/core/math/hash/XXH3_SECRET.d.ts.map +1 -0
- package/src/core/math/hash/XXH3_SECRET.js +25 -0
- package/src/core/math/hash/crc32.d.ts +16 -0
- package/src/core/math/hash/crc32.d.ts.map +1 -0
- package/src/core/math/hash/crc32.js +96 -0
- package/src/core/math/hash/xxh3_128.d.ts +10 -0
- package/src/core/math/hash/xxh3_128.d.ts.map +1 -0
- package/src/core/math/hash/xxh3_128.js +341 -0
- package/src/core/math/hash/xxh3_64.d.ts +9 -0
- package/src/core/math/hash/xxh3_64.d.ts.map +1 -0
- package/src/core/math/hash/xxh3_64.js +241 -0
- package/src/core/math/hash/xxh3_common.d.ts +224 -0
- package/src/core/math/hash/xxh3_common.d.ts.map +1 -0
- package/src/core/math/hash/xxh3_common.js +476 -0
- package/src/core/math/lookup/ParameterLookupTable.js +2 -2
- package/src/core/model/node-graph/node/NodeInstancePortReference.js +2 -2
- package/src/core/model/reactive/model/ReactiveBinaryExpression.js +2 -2
- package/src/core/model/reactive/model/terminal/ReactiveReference.js +2 -2
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +9 -4
- package/src/engine/asset/AssetDescription.js +2 -2
- package/src/engine/ecs/animation/Animation.js +2 -2
- package/src/engine/ecs/animation/AnimationClip.d.ts.map +1 -1
- package/src/engine/ecs/animation/AnimationClip.js +7 -5
- package/src/engine/ecs/gui/GUIElement.d.ts.map +1 -1
- package/src/engine/ecs/gui/GUIElement.js +7 -5
- package/src/engine/ecs/gui/hud/HeadsUpDisplay.js +2 -2
- package/src/engine/ecs/gui/position/ViewportPosition.d.ts.map +1 -1
- package/src/engine/ecs/gui/position/ViewportPosition.js +11 -7
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
- package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +10 -0
- package/src/engine/ecs/transform/Transform64.d.ts +1 -1
- package/src/engine/ecs/transform/Transform64.d.ts.map +1 -1
- package/src/engine/ecs/transform/Transform64.js +5 -4
- package/src/engine/ecs/transform/t64_look_rotation.d.ts +4 -4
- package/src/engine/ecs/transform/t64_look_rotation.d.ts.map +1 -1
- package/src/engine/ecs/transform/t64_look_rotation.js +7 -18
- package/src/engine/graphics/ecs/animation/animator/AnimationClip.d.ts.map +1 -1
- package/src/engine/graphics/ecs/animation/animator/AnimationClip.js +8 -5
- package/src/engine/graphics/ecs/animation/animator/AnimationClipDefinition.js +2 -2
- package/src/engine/graphics/ecs/animation/animator/AnimationNotification.js +2 -2
- package/src/engine/graphics/ecs/animation/animator/AnimationNotificationDefinition.js +2 -2
- package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationGraphDefinition.js +2 -2
- package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationStateDefinition.js +2 -2
- package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationTransitionDefinition.d.ts.map +1 -1
- package/src/engine/graphics/ecs/animation/animator/graph/definition/AnimationTransitionDefinition.js +8 -5
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +30 -1
- package/src/engine/graphics/ecs/decal/v2/Decal.d.ts.map +1 -1
- package/src/engine/graphics/ecs/decal/v2/Decal.js +9 -8
- package/src/engine/graphics/render/frame_graph/resource/TextureResourceDescriptor.d.ts.map +1 -1
- package/src/engine/graphics/render/frame_graph/resource/TextureResourceDescriptor.js +9 -6
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +6 -0
- package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/GPUParticleEmitterSystem.js +72 -29
- package/src/engine/graphics3/ParticipatingMedia.js +204 -204
- package/src/engine/graphics3/animation/AnimationClips.d.ts +5 -0
- package/src/engine/graphics3/animation/AnimationClips.d.ts.map +1 -1
- package/src/engine/graphics3/animation/AnimationClips.js +5 -0
- package/src/engine/grid/obstacle/GridObstacle.js +2 -2
- package/src/engine/input/devices/KeyboardDevice.d.ts +1 -0
- package/src/engine/input/devices/KeyboardDevice.d.ts.map +1 -1
- package/src/engine/input/devices/KeyboardDevice.js +7 -6
- package/src/engine/intelligence/behavior/selector/WeightedElement.js +2 -2
- package/src/engine/interpolation/Interpolated.js +2 -2
- package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
- package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +15 -2
- package/src/engine/network/CONGESTION_CONTROL.md +9 -9
- package/src/engine/network/MESSAGE_TRANSPORT.md +364 -0
- package/src/engine/network/NetworkSession.d.ts +31 -11
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +453 -286
- package/src/engine/network/README.md +77 -27
- package/src/engine/network/SMOOTHNESS_DESIGN.md +13 -5
- package/src/engine/network/diagnostics/BandwidthMeter.d.ts +1 -1
- package/src/engine/network/diagnostics/BandwidthMeter.js +1 -1
- package/src/engine/network/orchestrator/HostJoin.d.ts +111 -0
- package/src/engine/network/orchestrator/HostJoin.d.ts.map +1 -0
- package/src/engine/network/orchestrator/HostJoin.js +271 -0
- package/src/engine/network/orchestrator/NetworkPeer.d.ts +151 -112
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +450 -499
- package/src/engine/network/orchestrator/PendingSlices.d.ts +30 -0
- package/src/engine/network/orchestrator/PendingSlices.d.ts.map +1 -0
- package/src/engine/network/orchestrator/PendingSlices.js +83 -0
- package/src/engine/network/orchestrator/ReliableFrames.d.ts +34 -0
- package/src/engine/network/orchestrator/ReliableFrames.d.ts.map +1 -0
- package/src/engine/network/orchestrator/ReliableFrames.js +96 -0
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +77 -10
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +236 -61
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +20 -6
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +33 -8
- package/src/engine/network/replication/Replicator.d.ts.map +1 -1
- package/src/engine/network/replication/Replicator.js +7 -1
- package/src/engine/network/sim/ActionLog.d.ts +32 -5
- package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
- package/src/engine/network/sim/ActionLog.js +47 -5
- package/src/engine/network/sim/SimActionExecutor.d.ts +42 -2
- package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
- package/src/engine/network/sim/SimActionExecutor.js +100 -4
- package/src/engine/network/sim/Snapshotter.d.ts +12 -0
- package/src/engine/network/sim/Snapshotter.d.ts.map +1 -1
- package/src/engine/network/sim/Snapshotter.js +43 -0
- package/src/engine/network/state/Baseline.d.ts +1 -1
- package/src/engine/network/state/Baseline.js +1 -1
- package/src/engine/network/state/FrameBufferRing.d.ts +25 -6
- package/src/engine/network/state/FrameBufferRing.d.ts.map +1 -1
- package/src/engine/network/state/FrameBufferRing.js +51 -6
- package/src/engine/network/state/InputRing.d.ts +4 -0
- package/src/engine/network/state/InputRing.d.ts.map +1 -1
- package/src/engine/network/state/InputRing.js +7 -0
- package/src/engine/network/transport/DeferredTransport.d.ts.map +1 -1
- package/src/engine/network/transport/DeferredTransport.js +1 -0
- package/src/engine/network/transport/LoopbackTransport.d.ts.map +1 -1
- package/src/engine/network/transport/LoopbackTransport.js +4 -2
- package/src/engine/network/transport/Transport.d.ts +7 -0
- package/src/engine/network/transport/Transport.d.ts.map +1 -1
- package/src/engine/network/transport/Transport.js +8 -0
- package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
- package/src/engine/network/transport/adapters/NodeUDPTransport.js +20 -5
- package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.d.ts.map +1 -1
- package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.js +8 -0
- package/src/engine/network/transport/adapters/WebTransportTransport.d.ts.map +1 -1
- package/src/engine/network/transport/adapters/WebTransportTransport.js +6 -0
- package/src/engine/network/transport/connection/Connection.d.ts +191 -0
- package/src/engine/network/transport/connection/Connection.d.ts.map +1 -0
- package/src/engine/network/transport/connection/Connection.js +1262 -0
- package/src/engine/network/transport/connection/RangeSet.d.ts +94 -0
- package/src/engine/network/transport/connection/RangeSet.d.ts.map +1 -0
- package/src/engine/network/transport/connection/RangeSet.js +260 -0
- package/src/engine/network/transport/connection/RxStream.d.ts +48 -0
- package/src/engine/network/transport/connection/RxStream.d.ts.map +1 -0
- package/src/engine/network/transport/connection/RxStream.js +211 -0
- package/src/engine/network/transport/connection/TxStream.d.ts +90 -0
- package/src/engine/network/transport/connection/TxStream.d.ts.map +1 -0
- package/src/engine/network/transport/connection/TxStream.js +243 -0
- package/src/engine/network/transport/connection/bytes_copy.d.ts +17 -0
- package/src/engine/network/transport/connection/bytes_copy.d.ts.map +1 -0
- package/src/engine/network/transport/connection/bytes_copy.js +34 -0
- package/src/engine/network/transport/connection/varint.d.ts +46 -0
- package/src/engine/network/transport/connection/varint.d.ts.map +1 -0
- package/src/engine/network/transport/connection/varint.js +107 -0
- package/src/engine/physics/cloth/ecs/Cloth.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/Cloth.js +7 -5
- package/src/engine/physics/cloth/ecs/ClothCollider.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothCollider.js +7 -5
- package/src/engine/physics/cloth/ecs/ClothDynamics.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothDynamics.js +20 -11
- package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
- package/src/engine/physics/fluid/FluidField.js +7 -5
- package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
- package/src/engine/physics/fluid/ecs/FluidComponent.js +19 -11
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +2 -2
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +2 -2
- package/src/engine/physics/fluid/effector/GlobalFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +11 -7
- package/src/engine/physics/fluid/effector/ImpulseFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +11 -7
- package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/WakeFluidEffector.js +16 -9
- package/src/engine/sound/ecs/audio/AudioEmitter.d.ts +38 -7
- package/src/engine/sound/ecs/audio/AudioEmitter.d.ts.map +1 -1
- package/src/engine/sound/ecs/audio/AudioEmitter.js +47 -14
- package/src/engine/sound/ecs/audio/AudioEmitterSerializationAdapter.d.ts.map +1 -1
- package/src/engine/sound/ecs/audio/AudioEmitterSerializationAdapter.js +5 -1
- package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.d.ts +18 -0
- package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.d.ts.map +1 -0
- package/src/engine/sound/ecs/audio/AudioEmitterSerializationUpgrader_0_1.js +48 -0
- package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts +12 -2
- package/src/engine/sound/ecs/audio/AudioEmitterSystem.d.ts.map +1 -1
- package/src/engine/sound/ecs/audio/AudioEmitterSystem.js +173 -9
- package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts +9 -3
- package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts.map +1 -1
- package/src/engine/sound/ecs/audio/LiveEmitterSet.js +28 -8
- package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts +8 -0
- package/src/engine/sound/ecs/trigger/AudioEventTrigger.d.ts.map +1 -1
- package/src/engine/sound/ecs/trigger/AudioEventTrigger.js +192 -191
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.d.ts.map +1 -1
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationAdapter.js +5 -1
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.d.ts +18 -0
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.d.ts.map +1 -0
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSerializationUpgrader_0_1.js +51 -0
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.d.ts.map +1 -1
- package/src/engine/sound/ecs/trigger/AudioEventTriggerSystem.js +15 -1
- package/src/engine/sound/simulation/core/AcousticMedium.js +2 -2
- package/src/engine/sound/simulation/definition/AcousticDirectivity.js +2 -2
- package/src/engine/sound/simulation/definition/AcousticMaterial.d.ts.map +1 -1
- package/src/engine/sound/simulation/definition/AcousticMaterial.js +11 -7
- package/src/engine/sound/sopra/README.md +768 -644
- package/src/engine/sound/sopra/SopraEngine.d.ts +104 -8
- package/src/engine/sound/sopra/SopraEngine.d.ts.map +1 -1
- package/src/engine/sound/sopra/SopraEngine.js +327 -12
- package/src/engine/sound/sopra/definition/BusDefinition.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/BusDefinition.js +5 -4
- package/src/engine/sound/sopra/definition/DuckingRule.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/DuckingRule.js +7 -5
- package/src/engine/sound/sopra/definition/EventDescription.d.ts +28 -2
- package/src/engine/sound/sopra/definition/EventDescription.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/EventDescription.js +77 -17
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts +10 -0
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.js +77 -55
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.d.ts +31 -0
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.d.ts.map +1 -0
- package/src/engine/sound/sopra/definition/EventDescriptionSerializationUpgrader_0_1.js +75 -0
- package/src/engine/sound/sopra/definition/MixerSnapshot.js +2 -2
- package/src/engine/sound/sopra/definition/ParameterDefinition.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/ParameterDefinition.js +7 -5
- package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +2 -2
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.js +4 -3
- package/src/engine/sound/sopra/definition/clip/ContainerAudioClip.js +2 -2
- package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +3 -3
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +16 -9
- package/src/engine/sound/sopra/definition/clip/SilenceAudioClip.js +2 -2
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -1
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.js +2 -2
- package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts +38 -9
- package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.js +34 -5
- package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts +7 -2
- package/src/engine/sound/sopra/definition/effect/CompressorEffect.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/effect/CompressorEffect.js +137 -120
- package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts +3 -1
- package/src/engine/sound/sopra/definition/effect/EqEffect.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/effect/EqEffect.js +146 -128
- package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts +1 -0
- package/src/engine/sound/sopra/definition/effect/ReverbEffect.d.ts.map +1 -1
- package/src/engine/sound/sopra/definition/effect/ReverbEffect.js +8 -3
- package/src/engine/sound/sopra/legacy/SoundEmitter.d.ts.map +1 -1
- package/src/engine/sound/sopra/legacy/SoundEmitter.js +357 -352
- package/src/engine/sound/sopra/legacy/SoundTrack.d.ts.map +1 -1
- package/src/engine/sound/sopra/legacy/SoundTrack.js +281 -278
- package/src/engine/sound/sopra/runtime/BusGraph.d.ts +44 -2
- package/src/engine/sound/sopra/runtime/BusGraph.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/BusGraph.js +83 -43
- package/src/engine/sound/sopra/runtime/EffectChain.d.ts +96 -0
- package/src/engine/sound/sopra/runtime/EffectChain.d.ts.map +1 -0
- package/src/engine/sound/sopra/runtime/EffectChain.js +286 -0
- package/src/engine/sound/sopra/runtime/EffectParamOverrides.d.ts +123 -0
- package/src/engine/sound/sopra/runtime/EffectParamOverrides.d.ts.map +1 -0
- package/src/engine/sound/sopra/runtime/EffectParamOverrides.js +320 -0
- package/src/engine/sound/sopra/runtime/EventInstance.d.ts +55 -5
- package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.js +201 -26
- package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts +2 -1
- package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.d.ts.map +1 -1
- package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.js +6 -1
- package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts +15 -0
- package/src/engine/sound/sopra/serialization/sopraSerializationHarness.d.ts.map +1 -1
- package/src/engine/sound/sopra/serialization/sopraSerializationHarness.js +32 -0
- package/src/engine/sound/sopra/util/MockAudioContext.d.ts.map +1 -1
- package/src/engine/sound/sopra/util/MockAudioContext.js +3 -0
- package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts +13 -3
- package/src/engine/sound/sopra/util/fadeOutAndStop.d.ts.map +1 -1
- package/src/engine/sound/sopra/util/fadeOutAndStop.js +25 -13
- package/src/format/image/png/PNGReader.js +644 -644
- package/src/format/image/png/crc32.d.ts +1 -1
- package/src/format/image/png/crc32.js +7 -8
- package/src/shade/RENDERER_CONTRACT.md +6 -3
- package/src/shade/descriptor/binding/BindGroupLayoutDescriptor.js +2 -2
- package/src/shade/descriptor/binding/BindGroupLayoutEntry.d.ts.map +1 -1
- package/src/shade/descriptor/binding/BindGroupLayoutEntry.js +12 -8
- package/src/shade/descriptor/binding/StorageTextureBindingLayout.js +2 -2
- package/src/shade/descriptor/binding/TextureBindingLayout.js +2 -2
- package/src/shade/descriptor/blend/BlendComponent.js +2 -2
- package/src/shade/descriptor/pipeline/PipelineDescriptorBase.js +2 -2
- package/src/shade/descriptor/pipeline/PipelineLayoutDescriptor.js +2 -2
- package/src/shade/descriptor/pipeline/ProgrammableStage.js +2 -2
- package/src/shade/descriptor/pipeline/compute/ComputePipelineDescriptor.js +2 -2
- package/src/shade/descriptor/pipeline/render/ColorTargetState.js +2 -2
- package/src/shade/descriptor/pipeline/render/FragmentState.js +2 -2
- package/src/shade/descriptor/pipeline/render/PrimitiveState.js +2 -2
- package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.d.ts.map +1 -1
- package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.js +8 -5
- package/src/shade/descriptor/pipeline/render/VertexAttribute.js +2 -2
- package/src/shade/descriptor/texture/SamplerDescriptor.d.ts.map +1 -1
- package/src/shade/descriptor/texture/SamplerDescriptor.js +20 -12
- package/src/shade/descriptor/texture/TextureDescriptor.d.ts.map +1 -1
- package/src/shade/descriptor/texture/TextureDescriptor.js +11 -7
- package/src/shade/device/SHADE_DEVICE_FLOOR.d.ts +24 -0
- package/src/shade/device/SHADE_DEVICE_FLOOR.d.ts.map +1 -0
- package/src/shade/device/SHADE_DEVICE_FLOOR.js +34 -0
- package/src/shade/device/ShadeDeviceFailure.d.ts +12 -5
- package/src/shade/device/ShadeDeviceFailure.d.ts.map +1 -1
- package/src/shade/device/ShadeDeviceFailure.js +17 -8
- package/src/shade/device/ShadeDeviceFailureReason.d.ts +1 -1
- package/src/shade/device/ShadeDeviceFailureReason.js +2 -2
- package/src/shade/device/graph/BufferResourceDescriptor.d.ts.map +1 -1
- package/src/shade/device/graph/BufferResourceDescriptor.js +196 -193
- package/src/shade/device/graph/TextureResourceDescriptor.d.ts.map +1 -1
- package/src/shade/device/graph/TextureResourceDescriptor.js +178 -173
- package/src/shade/device/shade_device_floor_unmet.d.ts +13 -0
- package/src/shade/device/shade_device_floor_unmet.d.ts.map +1 -0
- package/src/shade/device/shade_device_floor_unmet.js +32 -0
- package/src/shade/device/timing/profile/sgpt_read_header.js +1 -1
- package/src/shade/device/timing/profile/sgpt_read_records.js +1 -1
- package/src/shade/device/timing/profile/sgpt_write_header.js +1 -1
- package/src/shade/device/timing/profile/sgpt_write_record.js +1 -1
- package/src/shade/renderer/Renderer.d.ts +2 -0
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +29 -55
- package/src/shade/renderer/binding/BufferBinding.js +2 -2
- package/src/shade/renderer/buffer/GPUBufferAllocator.d.ts.map +1 -1
- package/src/shade/renderer/buffer/GPUBufferAllocator.js +9 -0
- package/src/shade/renderer/buffer/buffer_pool_ops.d.ts +21 -12
- package/src/shade/renderer/buffer/buffer_pool_ops.d.ts.map +1 -1
- package/src/shade/renderer/buffer/buffer_pool_ops.js +18 -19
- package/src/shade/renderer/camera/Camera.js +2 -2
- package/src/shade/renderer/geometry/Attribute.js +2 -2
- package/src/shade/renderer/geometry/Geometry.js +2 -2
- package/src/shade/renderer/geometry/geometry_deduplicate_vertices.js +2 -2
- package/src/shade/renderer/geometry/meshlet/MeshletBatch.js +2 -2
- package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_asset_id.js +13 -13
- package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_directory_block_checksum.js +41 -41
- package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_frame_checksum.js +41 -41
- package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_header_checksum.js +25 -25
- package/src/shade/renderer/gpu_primitive/test/gpu_test.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/test/gpu_test.js +8 -11
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/material/StandardShadeMaterial.d.ts.map +1 -1
- package/src/shade/renderer/material/StandardShadeMaterial.js +13 -8
- package/src/shade/renderer/pool/TransientResourcePool.d.ts +24 -0
- package/src/shade/renderer/pool/TransientResourcePool.d.ts.map +1 -1
- package/src/shade/renderer/pool/TransientResourcePool.js +41 -10
- package/src/shade/renderer/scene/optimization/geometry/internal/triangle_fingerprint_stream.d.ts.map +1 -1
- package/src/shade/renderer/scene/optimization/geometry/internal/triangle_fingerprint_stream.js +14 -5
- package/src/shade/renderer/scene/optimization/sampler2d_from_image_bitmap.js +1 -1
- package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ComputeShader.js +18 -2
- package/src/shade/renderer/shader/ImageShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ImageShader.js +230 -218
- package/src/shade/renderer/shader/type/WGSLStructField.js +2 -2
- package/src/shade/renderer/shader/type/WebGPUArray.js +2 -2
- package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/WebGPUStruct.js +9 -6
- package/src/shade/renderer/texture/ShadeTexture.d.ts.map +1 -1
- package/src/shade/renderer/texture/ShadeTexture.js +17 -10
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +2 -2
- package/src/shade/renderer/water/surface/chunk_water_surface_sample.d.ts +4 -4
- package/src/shade/renderer/water/surface/chunk_water_surface_sample.js +6 -6
- package/src/shade/renderer/water/surface/particles/GPUWaterParticles.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/GPUWaterParticles.js +46 -55
- package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts +3 -3
- package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/WATER_PARTICLE_STRUCT.js +14 -4
- package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts +10 -1
- package/src/shade/renderer/water/surface/particles/chunk_water_particle.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/chunk_water_particle.js +82 -40
- package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts +4 -1
- package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/chunk_water_particle_step.js +8 -4
- package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts +98 -86
- package/src/shade/renderer/water/surface/particles/shader_water_particles.d.ts.map +1 -1
- package/src/shade/renderer/water/surface/particles/shader_water_particles.js +440 -298
- package/src/view/common/HTMLElementCacheKey.d.ts.map +1 -1
- package/src/view/common/HTMLElementCacheKey.js +4 -3
- package/src/view/graphics/GraphicsContextFailureView.d.ts +1 -2
- package/src/view/graphics/GraphicsContextFailureView.d.ts.map +1 -1
- package/src/view/graphics/GraphicsContextFailureView.js +1 -2
- package/src/view/minimap/MinimapMarker.js +2 -2
- package/src/engine/network/transport/Channel.js +0 -336
- package/src/engine/network/transport/ReliableCommandPipeline.js +0 -335
- package/src/engine/network/transport/fragments/FragmentAssembler.js +0 -350
- package/src/engine/network/transport/fragments/FragmentRetention.js +0 -191
- package/src/engine/network/transport/fragments/fragment_send.js +0 -157
- package/src/engine/network/transport/fragments/packet_size.js +0 -107
|
@@ -7,14 +7,48 @@ server-authoritative rollback orchestrator, layered over a pluggable transport.
|
|
|
7
7
|
|
|
8
8
|
| Layer | Pieces | Responsibility |
|
|
9
9
|
| --- | --- | --- |
|
|
10
|
-
| Transport | `transport/adapters/*` (`WebRTCDataChannel`, `WebTransport`, `WebSocket`, `NodeUDP`, `Simulated`, `Loopback`) | Move opaque
|
|
11
|
-
|
|
|
12
|
-
| Reliability / fragmentation | `transport/ReliableCommandPipeline.js`, `transport/fragments/*` | At-least-once commands; MTU fragmentation + NACK retransmit. |
|
|
10
|
+
| Transport | `transport/adapters/*` (`WebRTCDataChannel`, `WebTransport`, `WebSocket`, `NodeUDP`, `Simulated`, `Loopback`) | Move opaque datagrams of at most `max_datagram_bytes`. UDP-style unless `reliable` says otherwise. |
|
|
11
|
+
| Connection | `transport/connection/*` (`Connection`, `TxStream`, `RxStream`, `RangeSet`) | Numbered packets acknowledged by ranges, loss detection and probe timeout after QUIC; unreliable messages of up to a datagram with a delivery notice; reliable lanes for messages of any size up to `max_message_bytes`, paced. Everything for a peer leaves in as few datagrams as fit, once a tick. Design: [`MESSAGE_TRANSPORT.md`](./MESSAGE_TRANSPORT.md). |
|
|
13
12
|
| Sim core | `sim/*` (`ActionLog`, `SimAction`, `SimActionExecutor`, `RewindEngine`, `Snapshotter`, registries) | Record/apply/rewind replicated state mutations. |
|
|
14
13
|
| Replication | `replication/Replicator.js`, `replication/ScopeFilter.js` | Pack/unpack action records per peer, scope-filtered. |
|
|
15
14
|
| Orchestrator | `orchestrator/NetworkPeer.js`, `orchestrator/ServerAuthoritative{Server,Client}.js` | Per-tick send/recv, rollback (server), predict-reconcile (client). |
|
|
16
15
|
| Facade | `NetworkSession.js` | One config + lifecycle surface; wires everything below. |
|
|
17
16
|
|
|
17
|
+
## What the session assumes, and what a tick costs
|
|
18
|
+
|
|
19
|
+
The stack is built for fully networked worlds of millions of objects. A tick's cost is in what
|
|
20
|
+
changed and what is owned — never in how many networked entities there are — and that holds only on
|
|
21
|
+
these terms, which the game has to keep:
|
|
22
|
+
|
|
23
|
+
- **Every replicated change goes through the host's action executor.** An action — `send`, a
|
|
24
|
+
client's input — carries its own change. A system that writes a replicated component directly
|
|
25
|
+
(physics moving its bodies, a controller) reports each write:
|
|
26
|
+
`dataset.sendEvent(entity, "net_mutate_component", { component_type })`. The host records the
|
|
27
|
+
component as it stands, at full precision — the wire's quantised image is never written back into
|
|
28
|
+
the host's state. **A write nobody reports stays on the host**: the session never looks for
|
|
29
|
+
changes by itself. (Until 2026-10-15 it compared every replicated component of every networked
|
|
30
|
+
entity at the end of each host step: 7–8 ms a tick for 20,000 entities with nothing changing.)
|
|
31
|
+
- **Ownership is set when a `NetworkIdentity` attaches, or by the join** — never by writing
|
|
32
|
+
`owner_peer_id` or `network_id` afterwards. Each peer's owned entities are indexed when ownership
|
|
33
|
+
is set; what a tick does per owned entity (AUTH_STATE to its owner, the client's record of what it
|
|
34
|
+
predicted) walks that index.
|
|
35
|
+
|
|
36
|
+
Measured (one-component trees, one client, 30 Hz, Node 22, ms per tick):
|
|
37
|
+
|
|
38
|
+
| | ms |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| Host, 20,000 entities, nothing changing, client synced | 0.01–0.02 (was 14–15) |
|
|
41
|
+
| Client, 20,000 entities, nothing changing | 0.02 (was 0.7) |
|
|
42
|
+
| Host, 100 / 1,000 actions a tick, building them included | 0.4 / 3.8 |
|
|
43
|
+
| Client, applying 100 / 1,000 actions a tick | 1.3 / 4.2 |
|
|
44
|
+
|
|
45
|
+
What does scale with the world, by design:
|
|
46
|
+
|
|
47
|
+
- **A join** sends every networked entity once per joining peer, paged and paced; host memory per
|
|
48
|
+
joiner is the lane's window and 12 bytes an entity (`MESSAGE_TRANSPORT.md` §3.7).
|
|
49
|
+
- **Interpolation**: every networked entity gets an `Interpolated`, and the `InterpolationSystem`
|
|
50
|
+
records and blends each one every frame (below). Not measured at this scale.
|
|
51
|
+
|
|
18
52
|
## Smooth by default
|
|
19
53
|
|
|
20
54
|
A game that wires a `NetworkSession` the obvious way renders smoothly at any display rate, with
|
|
@@ -47,10 +81,9 @@ nothing else to set up. What that takes, and where it lives:
|
|
|
47
81
|
`Interpolated.snap` for a teleport (`PhysicsSystem.setPose` sets it), or
|
|
48
82
|
`InterpolationSystem.restore()` / `session.normalize_if_dirty()` before writing the truth. A write
|
|
49
83
|
over a blend without either is a write to a drawn pose, and the next step puts the truth back.
|
|
50
|
-
- **
|
|
51
|
-
|
|
52
|
-
back — the host keeps full precision
|
|
53
|
-
`publish_changes: false` to publish by hand.
|
|
84
|
+
- **What travels is what goes through the executor** (see "What the session assumes" above):
|
|
85
|
+
actions, and direct writes reported with `net_mutate_component`, which the host records without
|
|
86
|
+
writing them back — the host keeps full precision.
|
|
54
87
|
- **Clients reconcile by comparison** (`reconcile: 'correct'`, the default): the host's state for
|
|
55
88
|
frame S is compared with what the client predicted for S, and a component that differs is
|
|
56
89
|
carried into the present by its `Correction` (`network/correction`) — the session knows no
|
|
@@ -94,34 +127,51 @@ connection:
|
|
|
94
127
|
is ever sent, on this connection or a later one that resumes it: that input was predicted on a
|
|
95
128
|
world that is gone. The client's input starts at the frame the snapshot sets its counter to.
|
|
96
129
|
|
|
97
|
-
The first answer is the answer.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
issued.
|
|
130
|
+
The first answer is the answer. A host that has finished with a client's old session readmits its
|
|
131
|
+
new connection as a fresh peer before it reads the `RESUME_HELLO` on it — so a `RESUME_REJECT` can
|
|
132
|
+
arrive after the snapshot it announces. The snapshot's first page is the answer: a client acts on no
|
|
133
|
+
later accept or reject on that connection, and the reconnect ladder stops there, so a join that takes
|
|
134
|
+
a while is not torn down and restarted by the next attempt.
|
|
103
135
|
|
|
104
136
|
The host keeps to the same rule from its side, because what a peer can make it do has to be bounded
|
|
105
137
|
by what the host decided, not by how often the peer asks. It answers a connection's `RESUME_HELLO`
|
|
106
|
-
once and ignores any later one on that connection, and it
|
|
107
|
-
the
|
|
108
|
-
|
|
109
|
-
number of claims buys another. A
|
|
138
|
+
once and ignores any later one on that connection, and it gives a connection one join, when it takes
|
|
139
|
+
the connection for a fresh peer: as it binds it, or after refusing the connection's claim to resume.
|
|
140
|
+
A join is the whole world, once, and then what changed while it was going out, for at most eight
|
|
141
|
+
rounds; no number of claims buys another. A peer that drops before its join finished is never
|
|
142
|
+
resumed: it holds part of a world. A connection here is a transport the host binds with `connect()`, so
|
|
110
143
|
a reconnect has to reach the host as a new one — the fresh transport a `transport_factory` returns,
|
|
111
144
|
bound once the host has seen the old one end. One that lands on a connection the host still holds
|
|
112
145
|
is a second claim on that connection, and is not sent the world again.
|
|
113
146
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
147
|
+
### Joining a world of any size
|
|
148
|
+
|
|
149
|
+
A join is pages of whole entities on the connection's paced BULK lane, each built when it is sent;
|
|
150
|
+
what is lost is re-sent by the lane. The host holds the joining peer's action stream and AUTH_STATE
|
|
151
|
+
meanwhile. A round that goes out within one tick is built at one frame D and is the last: the FINAL
|
|
152
|
+
page follows it, and the action stream is released from D + 1. The first round — the whole world —
|
|
153
|
+
gets one tick's budget (256 KiB); a larger world goes out over as many ticks as the lane's window
|
|
154
|
+
takes, and when it has all arrived, every entity changed since its page — by an action the host's
|
|
155
|
+
executor ran — or created since, is the next round, which may fill the lane. The client holds the
|
|
156
|
+
action stream and AUTH_STATE from `connect()` until its world is whole, applies each page as it
|
|
157
|
+
lands, and on FINAL seeks its frame counter to the host's newest frame, forgets what it predicted on
|
|
158
|
+
the partial world, applies what it held, releases its own input and fires `onSynced`. Host memory
|
|
159
|
+
per joining peer is the lane's window and 12 bytes per entity; client memory is a page and what it
|
|
160
|
+
holds, at most `max_queued_bytes`.
|
|
161
|
+
|
|
162
|
+
### A connection that breaks
|
|
163
|
+
|
|
164
|
+
A connection does not authenticate datagrams; its transport delivers only the peer's (DTLS, TLS, and
|
|
165
|
+
`NodeUDP` by source address). When a connection stops being whole — a peer past its limits, or an
|
|
166
|
+
acknowledgement of a packet never sent, the mark of a datagram that was not the peer's — the session
|
|
167
|
+
handles it as a dropped transport and closes the transport: the host puts the peer in its grace
|
|
168
|
+
window and the client resumes on a new connection. See [`MESSAGE_TRANSPORT.md`](./MESSAGE_TRANSPORT.md) §3.9.
|
|
119
169
|
|
|
120
170
|
## Wired automatically by `NetworkSession`
|
|
121
171
|
|
|
122
|
-
`NetworkPeer` (and through it `
|
|
123
|
-
`SimActionExecutor`, the registries, `ReplicationSlotTable`, `Baseline`,
|
|
124
|
-
|
|
172
|
+
`NetworkPeer` (and through it a `Connection` per peer, `Replicator`, `ActionLog`,
|
|
173
|
+
`SimActionExecutor`, the registries, `ReplicationSlotTable`, `Baseline`, and the
|
|
174
|
+
host's `HostJoin`s), the two orchestrators
|
|
125
175
|
(and through them `RewindEngine` and `InputRing`), plus `TimeDilation`,
|
|
126
176
|
`AdaptiveRenderDelay`, `RenderPlayout`, `InterpolationLog`, `NetworkSystem`,
|
|
127
177
|
`NetworkIdentity`, `Snapshotter`, `SmoothingState` (through the
|
|
@@ -149,7 +199,7 @@ If you wire one of these into the facade, move its row up to the section above.
|
|
|
149
199
|
|
|
150
200
|
## Deferred / known gaps
|
|
151
201
|
|
|
152
|
-
- **Congestion control
|
|
153
|
-
|
|
202
|
+
- **Congestion control** — the send rate is a fixed token bucket
|
|
203
|
+
(`send_rate_bytes_per_second`); nothing adapts it to the link. Masked on the browser transports (DTLS/SCTP, TLS/TCP do it underneath);
|
|
154
204
|
only matters for raw `NodeUDP` / `Simulated` on constrained links. Design and
|
|
155
205
|
rationale for the deferral are in [`CONGESTION_CONTROL.md`](./CONGESTION_CONTROL.md).
|
|
@@ -92,7 +92,15 @@ avoided is corrected again by the next AUTH_STATE).
|
|
|
92
92
|
The action-log rewind + replay path stays, as an opt-in (`reconcile: 'replay'`), for games whose
|
|
93
93
|
predicted state is entirely produced by deterministic `SimAction`s and that want exactness.
|
|
94
94
|
|
|
95
|
-
**
|
|
95
|
+
**Superseded 2026-10-15: the host no longer looks for changes.** What follows describes the
|
|
96
|
+
end-of-step comparison as built. It cost every host tick a pass over every networked entity — 7–8 ms
|
|
97
|
+
for 20,000 entities with nothing changing — and the stack is for worlds of millions. It is gone: what
|
|
98
|
+
travels is what goes through the executor, actions and direct writes reported with
|
|
99
|
+
`net_mutate_component`, which the host records (`executor.record`, no write-back, D9's second half
|
|
100
|
+
kept fixed). A direct write nobody reports stays on the host — D9's first half is the contract now,
|
|
101
|
+
stated in the README's "What the session assumes".
|
|
102
|
+
|
|
103
|
+
**The host publishes what changed** (as built, superseded above). At the end of every host step, each replicated component of
|
|
96
104
|
each networked entity is encoded with its replication adapter and compared with what was last
|
|
97
105
|
published; changed ones go out as `ReplaceComponentAction` records. They are recorded without
|
|
98
106
|
applying (the host's live state is not overwritten with its quantised wire image — D9) and
|
|
@@ -171,9 +179,9 @@ path stays for `ServerAuthoritativeServer` users and for `reconcile: 'replay'` s
|
|
|
171
179
|
no component type, and no physics. `POSE_CORRECTION` (Transform64, through physics for a body,
|
|
172
180
|
hidden by `InterpolationSystem.correct`), `VELOCITY_CORRECTION` and `HOST_VALUE_CORRECTION` are
|
|
173
181
|
given. `reconcile: 'correct' | 'replay'`, default `'correct'`.
|
|
174
|
-
- Host: publishes changed replicated state at the end of each step
|
|
175
|
-
|
|
176
|
-
`'apply'`.
|
|
182
|
+
- Host: ~~publishes changed replicated state at the end of each step~~ (removed 2026-10-15: what
|
|
183
|
+
travels is what goes through the executor; a reported direct write is recorded, not executed);
|
|
184
|
+
`late_input: 'apply' | 'rollback'`, default `'apply'`.
|
|
177
185
|
|
|
178
186
|
### Orchestrators
|
|
179
187
|
- `ServerAuthoritativeServer`: `begin_tick(frame)` / `end_tick()` split, so the EM's systems run
|
|
@@ -204,7 +212,7 @@ path stays for `ServerAuthoritativeServer` users and for `reconcile: 'replay'` s
|
|
|
204
212
|
the next step. This was the rule for interpolated physics bodies already; it now holds for every
|
|
205
213
|
`Interpolated` entity. **Behaviour change** for code that relied on the old absence of any restore
|
|
206
214
|
for non-physics entities.
|
|
207
|
-
- Peer ids are `[0,
|
|
215
|
+
- Peer ids are `[0, 251]`; 252 is `SENDER_CORRECTED`, 253 is `SENDER_RECORDED`.
|
|
208
216
|
- `PhysicsSystem.interpolationLog` is deprecated (ignored, warns once).
|
|
209
217
|
- Wire format: a new `FRAME_MARKER` packet; nothing else.
|
|
210
218
|
- `scene-editor`'s `RemotePresence` (the only in-repo `registerSource` user) needed one change: a
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Aggregates `getStats()` snapshots from one or more named sources (typically
|
|
3
|
-
* a `Transport`,
|
|
3
|
+
* a `Transport`, or `NetworkPeer.connection_for(peer)`) and reports
|
|
4
4
|
* recent throughput rates.
|
|
5
5
|
*
|
|
6
6
|
* Per-source stats are queried via the source's `getStats()` method. A "sample"
|
|
@@ -2,7 +2,7 @@ import { assert } from "../../../core/assert.js";
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Aggregates `getStats()` snapshots from one or more named sources (typically
|
|
5
|
-
* a `Transport`,
|
|
5
|
+
* a `Transport`, or `NetworkPeer.connection_for(peer)`) and reports
|
|
6
6
|
* recent throughput rates.
|
|
7
7
|
*
|
|
8
8
|
* Per-source stats are queried via the source's `getStats()` method. A "sample"
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bytes of entity records a page is filled to. A page is a BULK message, so this is also how much
|
|
3
|
+
* the receiver holds of a join at a time. An entity larger than this is a page by itself.
|
|
4
|
+
*/
|
|
5
|
+
export const JOIN_PAGE_BYTES: number;
|
|
6
|
+
/**
|
|
7
|
+
* Bytes of pages the first round — the whole world — may queue in one tick to finish there. A
|
|
8
|
+
* round that finishes in one tick is the join's last: every entity it carries is at the same
|
|
9
|
+
* frame, and every entity it leaves out is unchanged since its state went out, so the receiver
|
|
10
|
+
* holds the whole world at that frame. A world larger than this goes out over several ticks, paced
|
|
11
|
+
* by the lane's window, and a catch-up round follows.
|
|
12
|
+
*
|
|
13
|
+
* A catch-up round always tries to finish in its tick, with what the BULK lane may still hold as
|
|
14
|
+
* its budget: what changed while a world went out is a fraction of it, and a round that may only
|
|
15
|
+
* page would never shrink for a world that changes faster than a tick's budget.
|
|
16
|
+
*/
|
|
17
|
+
export const JOIN_FINAL_ROUND_BYTES: number;
|
|
18
|
+
/**
|
|
19
|
+
* Catch-up rounds a join may take before it is given up. A catch-up round finishes in its tick
|
|
20
|
+
* unless what changed outgrows what the BULK lane may hold, so a join that needs more than one or
|
|
21
|
+
* two is a world changing faster than a peer can be sent it.
|
|
22
|
+
*/
|
|
23
|
+
export const JOIN_MAX_ROUNDS: 8;
|
|
24
|
+
/**
|
|
25
|
+
* What a join has to say after {@link HostJoinadvance }.
|
|
26
|
+
*/
|
|
27
|
+
export type JoinProgress = number;
|
|
28
|
+
/**
|
|
29
|
+
* What a join has to say after {@link HostJoin#advance}.
|
|
30
|
+
* @readonly
|
|
31
|
+
* @enum {number}
|
|
32
|
+
*/
|
|
33
|
+
export const JoinProgress: Readonly<{
|
|
34
|
+
/** Pages are going out, or the host is waiting to hear they arrived. */
|
|
35
|
+
Sending: 0;
|
|
36
|
+
/**
|
|
37
|
+
* The FINAL page has arrived: the peer holds the whole world. (Its action stream was released
|
|
38
|
+
* when FINAL was queued.)
|
|
39
|
+
*/
|
|
40
|
+
Done: 1;
|
|
41
|
+
/** The world changed faster than it could be sent, round after round: drop the peer. */
|
|
42
|
+
DidNotConverge: 2;
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* The host's side of one peer joining: the world, sent as pages built when they go out, then what
|
|
46
|
+
* changed meanwhile, until the peer holds every entity's state at one frame. See
|
|
47
|
+
* `network/MESSAGE_TRANSPORT.md`, "Joining a world of any size".
|
|
48
|
+
*
|
|
49
|
+
* 1. The peer's action stream is held from the start (the caller holds it).
|
|
50
|
+
* 2. A round starts with a list of entities. If its pages fit {@link JOIN_FINAL_ROUND_BYTES}, they
|
|
51
|
+
* all go in the tick the round starts, at that frame D; the FINAL page follows them, and the
|
|
52
|
+
* peer's action stream is released from D + 1. The join is over. (The stream's datagrams can
|
|
53
|
+
* overtake the last pages; the peer holds the stream until FINAL — `NetworkPeer.hold_inbound`.)
|
|
54
|
+
* 3. Otherwise the round's pages go out over as many ticks as it takes, each built at the frame it
|
|
55
|
+
* is sent, while the BULK lane has less than {@link window_bytes} unacknowledged. Each entity's
|
|
56
|
+
* network id is noted with the frame its state was sent at. Host memory: the window, and 8
|
|
57
|
+
* bytes per entity.
|
|
58
|
+
* 4. When every page of such a round has arrived, every networked entity is checked: one changed
|
|
59
|
+
* since its state was sent (`NetworkPeer.last_changed_frame`), or created since, is the next
|
|
60
|
+
* round's list. An empty list ends the join with the FINAL page alone.
|
|
61
|
+
*
|
|
62
|
+
* The first round is the world. For a world that fits one tick's budget, the join is one tick.
|
|
63
|
+
*
|
|
64
|
+
* Built per join; allocates its id list and send-frame table once and grows them, nothing per tick.
|
|
65
|
+
*
|
|
66
|
+
* @author Alex Goldring
|
|
67
|
+
* @copyright Company Named Limited (c) 2026
|
|
68
|
+
*/
|
|
69
|
+
export class HostJoin {
|
|
70
|
+
/**
|
|
71
|
+
* @param {{
|
|
72
|
+
* peer: import("./NetworkPeer.js").NetworkPeer,
|
|
73
|
+
* peer_id: number,
|
|
74
|
+
* session_token: Uint8Array,
|
|
75
|
+
* world: import("../../ecs/EntityComponentDataset.js").EntityComponentDataset,
|
|
76
|
+
* for_each_entity: function(function(number): void): void,
|
|
77
|
+
* page_buffer: BinaryBuffer,
|
|
78
|
+
* window_bytes: number,
|
|
79
|
+
* }} options
|
|
80
|
+
* `for_each_entity(cb)` visits every networked entity id. `page_buffer` is scratch the caller
|
|
81
|
+
* may share between joins. `window_bytes` is how far ahead of the peer's acknowledgements
|
|
82
|
+
* pages are built.
|
|
83
|
+
*/
|
|
84
|
+
constructor({ peer, peer_id, session_token, world, for_each_entity, page_buffer, window_bytes }: {
|
|
85
|
+
peer: import("./NetworkPeer.js").NetworkPeer;
|
|
86
|
+
peer_id: number;
|
|
87
|
+
session_token: Uint8Array;
|
|
88
|
+
world: import("../../ecs/EntityComponentDataset.js").EntityComponentDataset;
|
|
89
|
+
for_each_entity: (arg0: (arg0: number) => void) => void;
|
|
90
|
+
page_buffer: BinaryBuffer;
|
|
91
|
+
window_bytes: number;
|
|
92
|
+
});
|
|
93
|
+
peer: import("./NetworkPeer.js").NetworkPeer;
|
|
94
|
+
peer_id: number;
|
|
95
|
+
session_token: Uint8Array;
|
|
96
|
+
world: import("../../ecs/EntityComponentDataset.js").EntityComponentDataset;
|
|
97
|
+
for_each_entity: (arg0: (arg0: number) => void) => void;
|
|
98
|
+
page_buffer: BinaryBuffer;
|
|
99
|
+
window_bytes: number;
|
|
100
|
+
/** Catch-up rounds taken so far. */
|
|
101
|
+
get round(): number;
|
|
102
|
+
/**
|
|
103
|
+
* One tick of the join, at `frame` — the frame just simulated and published.
|
|
104
|
+
* @param {number} frame
|
|
105
|
+
* @returns {JoinProgress}
|
|
106
|
+
*/
|
|
107
|
+
advance(frame: number): JoinProgress;
|
|
108
|
+
#private;
|
|
109
|
+
}
|
|
110
|
+
import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
|
|
111
|
+
//# sourceMappingURL=HostJoin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HostJoin.d.ts","sourceRoot":"","sources":["../../../../../src/engine/network/orchestrator/HostJoin.js"],"names":[],"mappings":"AAKA;;;GAGG;AACH,qCAAyC;AAEzC;;;;;;;;;;GAUG;AACH,4CAAiD;AAEjD;;;;GAIG;AACH,gCAAiC;;;;2BAKvB,MAAM;AAHhB;;;;GAIG;AACH;IACI,wEAAwE;;IAExE;;;OAGG;;IAEH,wFAAwF;;GAEzF;AAOH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH;IAcI;;;;;;;;;;;;;OAaG;IACH,iGAbW;QACV,IAAQ,EAAE,OAAO,kBAAkB,EAAE,WAAW,CAAC;QACjD,OAAW,EAAE,MAAM,CAAC;QACpB,aAAiB,EAAE,UAAU,CAAC;QAC9B,KAAS,EAAE,OAAO,qCAAqC,EAAE,sBAAsB,CAAC;QAChF,eAAmB,gBAAoB,MAAM,KAAG,IAAI,KAAG,IAAI,CAAC;QAC5D,WAAe,EAAE,YAAY,CAAC;QAC9B,YAAgB,EAAE,MAAM,CAAC;KACtB,EAgBH;IAVG,6CAAgB;IAChB,gBAAsB;IACtB,0BAAkC;IAClC,4EAAkB;IAClB,+BAboC,MAAM,KAAG,IAAI,KAAG,IAAI,CAalB;IACtC,0BAA8B;IAC9B,qBAAgC;IAMpC,oCAAoC;IACpC,oBAEC;IAED;;;;OAIG;IACH,eAHW,MAAM,GACJ,YAAY,CA6DxB;;CAkFJ;6BA9Q4B,sCAAsC"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
|
|
2
|
+
import { snapshotter_write_entity } from "../sim/Snapshotter.js";
|
|
3
|
+
import { Lane } from "../transport/connection/Connection.js";
|
|
4
|
+
import { InitialSyncPage } from "./NetworkPeer.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Bytes of entity records a page is filled to. A page is a BULK message, so this is also how much
|
|
8
|
+
* the receiver holds of a join at a time. An entity larger than this is a page by itself.
|
|
9
|
+
*/
|
|
10
|
+
export const JOIN_PAGE_BYTES = 16 * 1024;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Bytes of pages the first round — the whole world — may queue in one tick to finish there. A
|
|
14
|
+
* round that finishes in one tick is the join's last: every entity it carries is at the same
|
|
15
|
+
* frame, and every entity it leaves out is unchanged since its state went out, so the receiver
|
|
16
|
+
* holds the whole world at that frame. A world larger than this goes out over several ticks, paced
|
|
17
|
+
* by the lane's window, and a catch-up round follows.
|
|
18
|
+
*
|
|
19
|
+
* A catch-up round always tries to finish in its tick, with what the BULK lane may still hold as
|
|
20
|
+
* its budget: what changed while a world went out is a fraction of it, and a round that may only
|
|
21
|
+
* page would never shrink for a world that changes faster than a tick's budget.
|
|
22
|
+
*/
|
|
23
|
+
export const JOIN_FINAL_ROUND_BYTES = 256 * 1024;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Catch-up rounds a join may take before it is given up. A catch-up round finishes in its tick
|
|
27
|
+
* unless what changed outgrows what the BULK lane may hold, so a join that needs more than one or
|
|
28
|
+
* two is a world changing faster than a peer can be sent it.
|
|
29
|
+
*/
|
|
30
|
+
export const JOIN_MAX_ROUNDS = 8;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* What a join has to say after {@link HostJoin#advance}.
|
|
34
|
+
* @readonly
|
|
35
|
+
* @enum {number}
|
|
36
|
+
*/
|
|
37
|
+
export const JoinProgress = Object.freeze({
|
|
38
|
+
/** Pages are going out, or the host is waiting to hear they arrived. */
|
|
39
|
+
Sending: 0,
|
|
40
|
+
/**
|
|
41
|
+
* The FINAL page has arrived: the peer holds the whole world. (Its action stream was released
|
|
42
|
+
* when FINAL was queued.)
|
|
43
|
+
*/
|
|
44
|
+
Done: 1,
|
|
45
|
+
/** The world changed faster than it could be sent, round after round: drop the peer. */
|
|
46
|
+
DidNotConverge: 2,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const PHASE_PAGING = 0;
|
|
50
|
+
const PHASE_AWAITING = 1;
|
|
51
|
+
/** FINAL is queued and the stream released; the join is over once FINAL has arrived */
|
|
52
|
+
const PHASE_FINAL_SENT = 2;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The host's side of one peer joining: the world, sent as pages built when they go out, then what
|
|
56
|
+
* changed meanwhile, until the peer holds every entity's state at one frame. See
|
|
57
|
+
* `network/MESSAGE_TRANSPORT.md`, "Joining a world of any size".
|
|
58
|
+
*
|
|
59
|
+
* 1. The peer's action stream is held from the start (the caller holds it).
|
|
60
|
+
* 2. A round starts with a list of entities. If its pages fit {@link JOIN_FINAL_ROUND_BYTES}, they
|
|
61
|
+
* all go in the tick the round starts, at that frame D; the FINAL page follows them, and the
|
|
62
|
+
* peer's action stream is released from D + 1. The join is over. (The stream's datagrams can
|
|
63
|
+
* overtake the last pages; the peer holds the stream until FINAL — `NetworkPeer.hold_inbound`.)
|
|
64
|
+
* 3. Otherwise the round's pages go out over as many ticks as it takes, each built at the frame it
|
|
65
|
+
* is sent, while the BULK lane has less than {@link window_bytes} unacknowledged. Each entity's
|
|
66
|
+
* network id is noted with the frame its state was sent at. Host memory: the window, and 8
|
|
67
|
+
* bytes per entity.
|
|
68
|
+
* 4. When every page of such a round has arrived, every networked entity is checked: one changed
|
|
69
|
+
* since its state was sent (`NetworkPeer.last_changed_frame`), or created since, is the next
|
|
70
|
+
* round's list. An empty list ends the join with the FINAL page alone.
|
|
71
|
+
*
|
|
72
|
+
* The first round is the world. For a world that fits one tick's budget, the join is one tick.
|
|
73
|
+
*
|
|
74
|
+
* Built per join; allocates its id list and send-frame table once and grows them, nothing per tick.
|
|
75
|
+
*
|
|
76
|
+
* @author Alex Goldring
|
|
77
|
+
* @copyright Company Named Limited (c) 2026
|
|
78
|
+
*/
|
|
79
|
+
export class HostJoin {
|
|
80
|
+
/** entity ids still to send this round */
|
|
81
|
+
#entities;
|
|
82
|
+
#count = 0;
|
|
83
|
+
#cursor = 0;
|
|
84
|
+
/** network id → frame its state was last sent at, -1 for never */
|
|
85
|
+
#sent_frame = new Float64Array(256).fill(-1);
|
|
86
|
+
#round = 0;
|
|
87
|
+
#phase = PHASE_PAGING;
|
|
88
|
+
#mark = -1;
|
|
89
|
+
#first_sent = false;
|
|
90
|
+
/** the first round's list is the world as it is when the join first advances */
|
|
91
|
+
#started = false;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @param {{
|
|
95
|
+
* peer: import("./NetworkPeer.js").NetworkPeer,
|
|
96
|
+
* peer_id: number,
|
|
97
|
+
* session_token: Uint8Array,
|
|
98
|
+
* world: import("../../ecs/EntityComponentDataset.js").EntityComponentDataset,
|
|
99
|
+
* for_each_entity: function(function(number): void): void,
|
|
100
|
+
* page_buffer: BinaryBuffer,
|
|
101
|
+
* window_bytes: number,
|
|
102
|
+
* }} options
|
|
103
|
+
* `for_each_entity(cb)` visits every networked entity id. `page_buffer` is scratch the caller
|
|
104
|
+
* may share between joins. `window_bytes` is how far ahead of the peer's acknowledgements
|
|
105
|
+
* pages are built.
|
|
106
|
+
*/
|
|
107
|
+
constructor({ peer, peer_id, session_token, world, for_each_entity, page_buffer, window_bytes }) {
|
|
108
|
+
this.peer = peer;
|
|
109
|
+
this.peer_id = peer_id;
|
|
110
|
+
this.session_token = session_token;
|
|
111
|
+
this.world = world;
|
|
112
|
+
this.for_each_entity = for_each_entity;
|
|
113
|
+
this.page_buffer = page_buffer;
|
|
114
|
+
this.window_bytes = window_bytes;
|
|
115
|
+
|
|
116
|
+
this.#entities = new Int32Array(64);
|
|
117
|
+
this.#count = 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Catch-up rounds taken so far. */
|
|
121
|
+
get round() {
|
|
122
|
+
return this.#round;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* One tick of the join, at `frame` — the frame just simulated and published.
|
|
127
|
+
* @param {number} frame
|
|
128
|
+
* @returns {JoinProgress}
|
|
129
|
+
*/
|
|
130
|
+
advance(frame) {
|
|
131
|
+
const connection = this.peer.connection_for(this.peer_id);
|
|
132
|
+
if (connection === undefined) return JoinProgress.Sending;
|
|
133
|
+
|
|
134
|
+
if (!this.#started) {
|
|
135
|
+
// the world at the first frame the join runs on, not at connect: what is built between
|
|
136
|
+
// the two is part of it
|
|
137
|
+
this.#started = true;
|
|
138
|
+
this.for_each_entity(this.#push_entity);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (this.#phase === PHASE_FINAL_SENT) {
|
|
142
|
+
// Over only once FINAL has arrived: until then the peer holds part of a world, and a
|
|
143
|
+
// peer that drops now must not be resumed into it.
|
|
144
|
+
return connection.is_delivered(Lane.BULK, this.#mark) ? JoinProgress.Done : JoinProgress.Sending;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
for (; ;) {
|
|
148
|
+
if (this.#phase === PHASE_PAGING) {
|
|
149
|
+
if (this.#cursor === 0) {
|
|
150
|
+
// A round starting now: if it all goes in this tick, it is the last. The world
|
|
151
|
+
// is held to one tick's budget; a catch-up round may fill the lane, leaving
|
|
152
|
+
// room for one more page of the largest a message may be.
|
|
153
|
+
const lane_room = connection.max_queued_bytes - connection.unacked_bytes(Lane.BULK)
|
|
154
|
+
- connection.max_message_bytes;
|
|
155
|
+
const budget = this.#round === 0 ? Math.min(JOIN_FINAL_ROUND_BYTES, lane_room) : lane_room;
|
|
156
|
+
let queued = 0;
|
|
157
|
+
while (this.#cursor < this.#count && queued < budget) {
|
|
158
|
+
queued += this.#send_page(frame, 0);
|
|
159
|
+
}
|
|
160
|
+
if (this.#cursor >= this.#count) {
|
|
161
|
+
this.#send_page(frame, InitialSyncPage.FINAL);
|
|
162
|
+
this.peer.release_outbound(this.peer_id, frame + 1);
|
|
163
|
+
this.#phase = PHASE_FINAL_SENT;
|
|
164
|
+
return JoinProgress.Sending;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
while (this.#cursor < this.#count && connection.unacked_bytes(Lane.BULK) < this.window_bytes) {
|
|
168
|
+
this.#send_page(frame, 0);
|
|
169
|
+
}
|
|
170
|
+
if (this.#cursor < this.#count) return JoinProgress.Sending;
|
|
171
|
+
this.#phase = PHASE_AWAITING;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// every page of the round has been queued: has it all arrived?
|
|
175
|
+
if (!connection.is_delivered(Lane.BULK, this.#mark)) return JoinProgress.Sending;
|
|
176
|
+
|
|
177
|
+
this.#collect_changed();
|
|
178
|
+
if (this.#count === 0) {
|
|
179
|
+
this.#send_page(frame, InitialSyncPage.FINAL);
|
|
180
|
+
this.peer.release_outbound(this.peer_id, frame + 1);
|
|
181
|
+
this.#phase = PHASE_FINAL_SENT;
|
|
182
|
+
return JoinProgress.Sending;
|
|
183
|
+
}
|
|
184
|
+
this.#round++;
|
|
185
|
+
if (this.#round > JOIN_MAX_ROUNDS) return JoinProgress.DidNotConverge;
|
|
186
|
+
this.#cursor = 0;
|
|
187
|
+
this.#phase = PHASE_PAGING;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Fill and queue the next page from the cursor, or an empty one when `flags` asks for FINAL.
|
|
193
|
+
* @param {number} frame
|
|
194
|
+
* @param {number} flags
|
|
195
|
+
* @returns {number} bytes of entity records queued
|
|
196
|
+
*/
|
|
197
|
+
#send_page(frame, flags) {
|
|
198
|
+
const buffer = this.page_buffer;
|
|
199
|
+
const slot_table = this.peer.slot_table;
|
|
200
|
+
buffer.position = 0;
|
|
201
|
+
buffer.writeUint32(0); // entity count, written at the end
|
|
202
|
+
|
|
203
|
+
let written = 0;
|
|
204
|
+
if ((flags & InitialSyncPage.FINAL) === 0) {
|
|
205
|
+
while (this.#cursor < this.#count) {
|
|
206
|
+
const entity_id = this.#entities[this.#cursor];
|
|
207
|
+
const network_id = slot_table.network_for(entity_id);
|
|
208
|
+
if (network_id < 0) {
|
|
209
|
+
// gone since the round began
|
|
210
|
+
this.#cursor++;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (written > 0 && buffer.position >= JOIN_PAGE_BYTES) break;
|
|
214
|
+
snapshotter_write_entity(buffer, this.world, slot_table, this.peer.component_registry, entity_id);
|
|
215
|
+
this.#set_sent(network_id, frame);
|
|
216
|
+
written++;
|
|
217
|
+
this.#cursor++;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const end = buffer.position;
|
|
222
|
+
buffer.position = 0;
|
|
223
|
+
buffer.writeUint32(written);
|
|
224
|
+
buffer.position = end;
|
|
225
|
+
|
|
226
|
+
if (!this.#first_sent) {
|
|
227
|
+
flags |= InitialSyncPage.FIRST;
|
|
228
|
+
this.#first_sent = true;
|
|
229
|
+
}
|
|
230
|
+
this.#mark = this.peer.send_sync_page(this.peer_id, this.session_token, frame, flags, buffer.raw_bytes, end);
|
|
231
|
+
return end;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* The next round's list: networked entities changed since their state was sent, or never sent.
|
|
236
|
+
*/
|
|
237
|
+
#collect_changed() {
|
|
238
|
+
this.#count = 0;
|
|
239
|
+
this.for_each_entity(this.#push_if_changed);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** @type {function(number): void} */
|
|
243
|
+
#push_entity = (entity_id) => {
|
|
244
|
+
if (this.#count === this.#entities.length) {
|
|
245
|
+
const next = new Int32Array(this.#entities.length * 2);
|
|
246
|
+
next.set(this.#entities);
|
|
247
|
+
this.#entities = next;
|
|
248
|
+
}
|
|
249
|
+
this.#entities[this.#count++] = entity_id;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/** @type {function(number): void} */
|
|
253
|
+
#push_if_changed = (entity_id) => {
|
|
254
|
+
const network_id = this.peer.slot_table.network_for(entity_id);
|
|
255
|
+
if (network_id < 0) return;
|
|
256
|
+
const sent = network_id < this.#sent_frame.length ? this.#sent_frame[network_id] : -1;
|
|
257
|
+
if (sent >= 0 && this.peer.last_changed_frame(network_id) <= sent) return;
|
|
258
|
+
this.#push_entity(entity_id);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
#set_sent(network_id, frame) {
|
|
262
|
+
if (network_id >= this.#sent_frame.length) {
|
|
263
|
+
let size = this.#sent_frame.length * 2;
|
|
264
|
+
while (size <= network_id) size *= 2;
|
|
265
|
+
const next = new Float64Array(size).fill(-1);
|
|
266
|
+
next.set(this.#sent_frame);
|
|
267
|
+
this.#sent_frame = next;
|
|
268
|
+
}
|
|
269
|
+
this.#sent_frame[network_id] = frame;
|
|
270
|
+
}
|
|
271
|
+
}
|