1681-engine 0.0.0-stage → 0.5.8
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/CHANGELOG.md +304 -0
- package/LICENSE +21 -0
- package/README.md +164 -2
- package/dist/1681-engine.js +417 -0
- package/dist/1681-engine.js.map +1 -0
- package/dist/ambient/ColorGrade.js +41 -0
- package/dist/ambient/ColorGrade.js.map +1 -0
- package/dist/ambient/DayClock.js +57 -0
- package/dist/ambient/DayClock.js.map +1 -0
- package/dist/ambient/WeatherLayer.js +91 -0
- package/dist/ambient/WeatherLayer.js.map +1 -0
- package/dist/ambient/grade.js +13 -0
- package/dist/ambient/grade.js.map +1 -0
- package/dist/ambient/weather.js +52 -0
- package/dist/ambient/weather.js.map +1 -0
- package/dist/anim/AnimStateMachine.js +164 -0
- package/dist/anim/AnimStateMachine.js.map +1 -0
- package/dist/anim/Animator.js +67 -0
- package/dist/anim/Animator.js.map +1 -0
- package/dist/anim/animStateCompile.js +113 -0
- package/dist/anim/animStateCompile.js.map +1 -0
- package/dist/anim/animStateSystem.js +17 -0
- package/dist/anim/animStateSystem.js.map +1 -0
- package/dist/anim/animationSystem.js +15 -0
- package/dist/anim/animationSystem.js.map +1 -0
- package/dist/anim/asepriteSlices.js +22 -0
- package/dist/anim/asepriteSlices.js.map +1 -0
- package/dist/anim/asepriteTags.js +35 -0
- package/dist/anim/asepriteTags.js.map +1 -0
- package/dist/anim/parseAseprite.js +83 -0
- package/dist/anim/parseAseprite.js.map +1 -0
- package/dist/assets/AssetLoader.js +104 -0
- package/dist/assets/AssetLoader.js.map +1 -0
- package/dist/assets/loadAseprite.js +50 -0
- package/dist/assets/loadAseprite.js.map +1 -0
- package/dist/assets/takeCleanerWorker-DTcI_Jqr.js +31 -0
- package/dist/assets/takeCleanerWorker-DTcI_Jqr.js.map +1 -0
- package/dist/audio/Footsteps.js +26 -0
- package/dist/audio/Footsteps.js.map +1 -0
- package/dist/audio/MusicPlayer.js +78 -0
- package/dist/audio/MusicPlayer.js.map +1 -0
- package/dist/audio/SoundEngine.js +119 -0
- package/dist/audio/SoundEngine.js.map +1 -0
- package/dist/audio/cleanTake.js +30 -0
- package/dist/audio/cleanTake.js.map +1 -0
- package/dist/audio/music/ElementVoice.js +35 -0
- package/dist/audio/music/ElementVoice.js.map +1 -0
- package/dist/audio/music/GraphVoice.js +39 -0
- package/dist/audio/music/GraphVoice.js.map +1 -0
- package/dist/audio/music/MusicChannel.js +58 -0
- package/dist/audio/music/MusicChannel.js.map +1 -0
- package/dist/audio/music/musicVoice.js +13 -0
- package/dist/audio/music/musicVoice.js.map +1 -0
- package/dist/audio/sampleBank.js +82 -0
- package/dist/audio/sampleBank.js.map +1 -0
- package/dist/audio/soundTable.js +9 -0
- package/dist/audio/soundTable.js.map +1 -0
- package/dist/audio/synth.js +36 -0
- package/dist/audio/synth.js.map +1 -0
- package/dist/core/BitmapLabel.js +49 -0
- package/dist/core/BitmapLabel.js.map +1 -0
- package/dist/core/Camera.js +150 -0
- package/dist/core/Camera.js.map +1 -0
- package/dist/core/Clock.js +30 -0
- package/dist/core/Clock.js.map +1 -0
- package/dist/core/Graphics.js +69 -0
- package/dist/core/Graphics.js.map +1 -0
- package/dist/core/Group.js +29 -0
- package/dist/core/Group.js.map +1 -0
- package/dist/core/Image.js +51 -0
- package/dist/core/Image.js.map +1 -0
- package/dist/core/ObjectFactory.js +55 -0
- package/dist/core/ObjectFactory.js.map +1 -0
- package/dist/core/Pointer.js +58 -0
- package/dist/core/Pointer.js.map +1 -0
- package/dist/core/Rectangle.js +51 -0
- package/dist/core/Rectangle.js.map +1 -0
- package/dist/core/Stage.js +86 -0
- package/dist/core/Stage.js.map +1 -0
- package/dist/core/Text.js +22 -0
- package/dist/core/Text.js.map +1 -0
- package/dist/core/TextureRegistry.js +111 -0
- package/dist/core/TextureRegistry.js.map +1 -0
- package/dist/core/Timeline.js +211 -0
- package/dist/core/Timeline.js.map +1 -0
- package/dist/core/TimelineBuilder.js +73 -0
- package/dist/core/TimelineBuilder.js.map +1 -0
- package/dist/core/TimelineChild.js +84 -0
- package/dist/core/TimelineChild.js.map +1 -0
- package/dist/core/Tweener.js +136 -0
- package/dist/core/Tweener.js.map +1 -0
- package/dist/core/atlas.js +38 -0
- package/dist/core/atlas.js.map +1 -0
- package/dist/core/atlasPlan.js +22 -0
- package/dist/core/atlasPlan.js.map +1 -0
- package/dist/core/eases.js +21 -0
- package/dist/core/eases.js.map +1 -0
- package/dist/core/gameObject.js +115 -0
- package/dist/core/gameObject.js.map +1 -0
- package/dist/core/pixiPatches.js +18 -0
- package/dist/core/pixiPatches.js.map +1 -0
- package/dist/core/timelinePlace.js +24 -0
- package/dist/core/timelinePlace.js.map +1 -0
- package/dist/core/tweenProps.js +12 -0
- package/dist/core/tweenProps.js.map +1 -0
- package/dist/debug/DebugOverlay.js +94 -0
- package/dist/debug/DebugOverlay.js.map +1 -0
- package/dist/debug/DrawCallCounter.js +41 -0
- package/dist/debug/DrawCallCounter.js.map +1 -0
- package/dist/debug/ErrorLog.js +22 -0
- package/dist/debug/ErrorLog.js.map +1 -0
- package/dist/debug/FrameStats.js +42 -0
- package/dist/debug/FrameStats.js.map +1 -0
- package/dist/debug/inspectWorld.js +29 -0
- package/dist/debug/inspectWorld.js.map +1 -0
- package/dist/diagnostics/ErrorDeduper.js +27 -0
- package/dist/diagnostics/ErrorDeduper.js.map +1 -0
- package/dist/diagnostics/FrameSampler.js +42 -0
- package/dist/diagnostics/FrameSampler.js.map +1 -0
- package/dist/diagnostics/bootWatch.js +21 -0
- package/dist/diagnostics/bootWatch.js.map +1 -0
- package/dist/diagnostics/captureErrors.js +27 -0
- package/dist/diagnostics/captureErrors.js.map +1 -0
- package/dist/diagnostics/contextLoss.js +25 -0
- package/dist/diagnostics/contextLoss.js.map +1 -0
- package/dist/diagnostics/frameStats.js +31 -0
- package/dist/diagnostics/frameStats.js.map +1 -0
- package/dist/diagnostics/gpuInfo.js +22 -0
- package/dist/diagnostics/gpuInfo.js.map +1 -0
- package/dist/diagnostics/renderGuard.js +24 -0
- package/dist/diagnostics/renderGuard.js.map +1 -0
- package/dist/ecs/SparseSet.js +55 -0
- package/dist/ecs/SparseSet.js.map +1 -0
- package/dist/ecs/World.js +307 -0
- package/dist/ecs/World.js.map +1 -0
- package/dist/ecs/fields.js +26 -0
- package/dist/ecs/fields.js.map +1 -0
- package/dist/engine/Engine.js +82 -0
- package/dist/engine/Engine.js.map +1 -0
- package/dist/engine/FixedLoop.js +37 -0
- package/dist/engine/FixedLoop.js.map +1 -0
- package/dist/engine/Scene.js +79 -0
- package/dist/engine/Scene.js.map +1 -0
- package/dist/engine/SceneManager.js +73 -0
- package/dist/engine/SceneManager.js.map +1 -0
- package/dist/events/EventBus.js +42 -0
- package/dist/events/EventBus.js.map +1 -0
- package/dist/fx/FloatingText.js +72 -0
- package/dist/fx/FloatingText.js.map +1 -0
- package/dist/fx/hitStop.js +28 -0
- package/dist/fx/hitStop.js.map +1 -0
- package/dist/fx/viewCull.js +10 -0
- package/dist/fx/viewCull.js.map +1 -0
- package/dist/i18n/Translator.js +72 -0
- package/dist/i18n/Translator.js.map +1 -0
- package/dist/i18n/extractStrings.js +58 -0
- package/dist/i18n/extractStrings.js.map +1 -0
- package/dist/i18n/formatMessage.js +19 -0
- package/dist/i18n/formatMessage.js.map +1 -0
- package/dist/input/Actions.js +131 -0
- package/dist/input/Actions.js.map +1 -0
- package/dist/input/AimGesture.js +75 -0
- package/dist/input/AimGesture.js.map +1 -0
- package/dist/input/Keyboard.js +54 -0
- package/dist/input/Keyboard.js.map +1 -0
- package/dist/input/Keymap.js +171 -0
- package/dist/input/Keymap.js.map +1 -0
- package/dist/input/TargetLock.js +73 -0
- package/dist/input/TargetLock.js.map +1 -0
- package/dist/input/aimAxis.js +8 -0
- package/dist/input/aimAxis.js.map +1 -0
- package/dist/input/keyChord.js +29 -0
- package/dist/input/keyChord.js.map +1 -0
- package/dist/input/longPress.js +32 -0
- package/dist/input/longPress.js.map +1 -0
- package/dist/input/stickAxis.js +23 -0
- package/dist/input/stickAxis.js.map +1 -0
- package/dist/input/touchDetect.js +7 -0
- package/dist/input/touchDetect.js.map +1 -0
- package/dist/light/LightLayer.js +84 -0
- package/dist/light/LightLayer.js.map +1 -0
- package/dist/nav/MinHeap.js +39 -0
- package/dist/nav/MinHeap.js.map +1 -0
- package/dist/nav/findPath.js +78 -0
- package/dist/nav/findPath.js.map +1 -0
- package/dist/nav/navGrid.js +36 -0
- package/dist/nav/navGrid.js.map +1 -0
- package/dist/nav/nearestOpen.js +19 -0
- package/dist/nav/nearestOpen.js.map +1 -0
- package/dist/nav/straightenPath.js +51 -0
- package/dist/nav/straightenPath.js.map +1 -0
- package/dist/net/Connection.js +84 -0
- package/dist/net/Connection.js.map +1 -0
- package/dist/net/InterpolationBuffer.js +57 -0
- package/dist/net/InterpolationBuffer.js.map +1 -0
- package/dist/net/PredictedMover.js +61 -0
- package/dist/net/PredictedMover.js.map +1 -0
- package/dist/net/Room.js +92 -0
- package/dist/net/Room.js.map +1 -0
- package/dist/net/RoomHost.js +101 -0
- package/dist/net/RoomHost.js.map +1 -0
- package/dist/net/cadence.js +22 -0
- package/dist/net/cadence.js.map +1 -0
- package/dist/net/constants.js +11 -0
- package/dist/net/constants.js.map +1 -0
- package/dist/net/lobby/LobbyClient.js +124 -0
- package/dist/net/lobby/LobbyClient.js.map +1 -0
- package/dist/net/lobby/LobbyHost.js +366 -0
- package/dist/net/lobby/LobbyHost.js.map +1 -0
- package/dist/net/lobby/LobbyRooms.js +66 -0
- package/dist/net/lobby/LobbyRooms.js.map +1 -0
- package/dist/net/lobby/Matchmaker.js +106 -0
- package/dist/net/lobby/Matchmaker.js.map +1 -0
- package/dist/net/movement.js +83 -0
- package/dist/net/movement.js.map +1 -0
- package/dist/net/protocol.js +11 -0
- package/dist/net/protocol.js.map +1 -0
- package/dist/net/serverClock.js +22 -0
- package/dist/net/serverClock.js.map +1 -0
- package/dist/net/snapshotCodec.js +92 -0
- package/dist/net/snapshotCodec.js.map +1 -0
- package/dist/parallax/Parallax.js +32 -0
- package/dist/parallax/Parallax.js.map +1 -0
- package/dist/parallax/ParallaxLayer.js +70 -0
- package/dist/parallax/ParallaxLayer.js.map +1 -0
- package/dist/parallax/parallaxMath.js +27 -0
- package/dist/parallax/parallaxMath.js.map +1 -0
- package/dist/particles/Emitter.js +108 -0
- package/dist/particles/Emitter.js.map +1 -0
- package/dist/particles/ParticleBudget.js +32 -0
- package/dist/particles/ParticleBudget.js.map +1 -0
- package/dist/particles/ParticleSim.js +60 -0
- package/dist/particles/ParticleSim.js.map +1 -0
- package/dist/particles/particleCurves.js +48 -0
- package/dist/particles/particleCurves.js.map +1 -0
- package/dist/particles/particleSampling.js +30 -0
- package/dist/particles/particleSampling.js.map +1 -0
- package/dist/physics/Body.js +202 -0
- package/dist/physics/Body.js.map +1 -0
- package/dist/physics/BroadPhase.js +56 -0
- package/dist/physics/BroadPhase.js.map +1 -0
- package/dist/physics/Contact.js +76 -0
- package/dist/physics/Contact.js.map +1 -0
- package/dist/physics/ContactSolver.js +70 -0
- package/dist/physics/ContactSolver.js.map +1 -0
- package/dist/physics/PhysicsWorld.js +221 -0
- package/dist/physics/PhysicsWorld.js.map +1 -0
- package/dist/physics/SpatialHash.js +39 -0
- package/dist/physics/SpatialHash.js.map +1 -0
- package/dist/physics/collide.js +76 -0
- package/dist/physics/collide.js.map +1 -0
- package/dist/physics/collidePolygon.js +94 -0
- package/dist/physics/collidePolygon.js.map +1 -0
- package/dist/physics/contactReport.js +14 -0
- package/dist/physics/contactReport.js.map +1 -0
- package/dist/physics/drawColliders.js +31 -0
- package/dist/physics/drawColliders.js.map +1 -0
- package/dist/physics/physicsSystem.js +8 -0
- package/dist/physics/physicsSystem.js.map +1 -0
- package/dist/physics/polygon.js +80 -0
- package/dist/physics/polygon.js.map +1 -0
- package/dist/physics/raycast.js +62 -0
- package/dist/physics/raycast.js.map +1 -0
- package/dist/physics/syncToBody.js +19 -0
- package/dist/physics/syncToBody.js.map +1 -0
- package/dist/physics/tileBodies.js +59 -0
- package/dist/physics/tileBodies.js.map +1 -0
- package/dist/physics/types.js +8 -0
- package/dist/physics/types.js.map +1 -0
- package/dist/pixel/Darkness.js +166 -0
- package/dist/pixel/Darkness.js.map +1 -0
- package/dist/pixel/DitherVignette.js +57 -0
- package/dist/pixel/DitherVignette.js.map +1 -0
- package/dist/pixel/Evaporation.js +85 -0
- package/dist/pixel/Evaporation.js.map +1 -0
- package/dist/pixel/NightShade.js +34 -0
- package/dist/pixel/NightShade.js.map +1 -0
- package/dist/pixel/PixelLayer.js +211 -0
- package/dist/pixel/PixelLayer.js.map +1 -0
- package/dist/pixel/SwayProp.js +75 -0
- package/dist/pixel/SwayProp.js.map +1 -0
- package/dist/pixel/lights.js +44 -0
- package/dist/pixel/lights.js.map +1 -0
- package/dist/pixel/nineSlice.js +62 -0
- package/dist/pixel/nineSlice.js.map +1 -0
- package/dist/pixel/paintLayer.js +36 -0
- package/dist/pixel/paintLayer.js.map +1 -0
- package/dist/pixel/palette.js +57 -0
- package/dist/pixel/palette.js.map +1 -0
- package/dist/pixel/pixel.js +278 -0
- package/dist/pixel/pixel.js.map +1 -0
- package/dist/pixel/pixelPaint.js +194 -0
- package/dist/pixel/pixelPaint.js.map +1 -0
- package/dist/pixel/pixelTone.js +164 -0
- package/dist/pixel/pixelTone.js.map +1 -0
- package/dist/pixel/propKit.js +41 -0
- package/dist/pixel/propKit.js.map +1 -0
- package/dist/pixel/ramp.js +102 -0
- package/dist/pixel/ramp.js.map +1 -0
- package/dist/pixel/selout.js +35 -0
- package/dist/pixel/selout.js.map +1 -0
- package/dist/pixel/spritePixels.js +59 -0
- package/dist/pixel/spritePixels.js.map +1 -0
- package/dist/pixel/swayRig.js +87 -0
- package/dist/pixel/swayRig.js.map +1 -0
- package/dist/pixel/vignetteMask.js +24 -0
- package/dist/pixel/vignetteMask.js.map +1 -0
- package/dist/pixel/weatherArt.js +61 -0
- package/dist/pixel/weatherArt.js.map +1 -0
- package/dist/pixel.js +90 -0
- package/dist/pixel.js.map +1 -0
- package/dist/platform/touch.js +33 -0
- package/dist/platform/touch.js.map +1 -0
- package/dist/postfx/BloomFilter.js +65 -0
- package/dist/postfx/BloomFilter.js.map +1 -0
- package/dist/postfx/ChromaticAberrationFilter.js +25 -0
- package/dist/postfx/ChromaticAberrationFilter.js.map +1 -0
- package/dist/postfx/ColorAdjustFilter.js +76 -0
- package/dist/postfx/ColorAdjustFilter.js.map +1 -0
- package/dist/postfx/CrtFilter.js +42 -0
- package/dist/postfx/CrtFilter.js.map +1 -0
- package/dist/postfx/PixelateFilter.js +27 -0
- package/dist/postfx/PixelateFilter.js.map +1 -0
- package/dist/postfx/PostFx.js +123 -0
- package/dist/postfx/PostFx.js.map +1 -0
- package/dist/postfx/ShockwaveFilter.js +49 -0
- package/dist/postfx/ShockwaveFilter.js.map +1 -0
- package/dist/postfx/VignetteFilter.js +37 -0
- package/dist/postfx/VignetteFilter.js.map +1 -0
- package/dist/postfx/fxAnimator.js +38 -0
- package/dist/postfx/fxAnimator.js.map +1 -0
- package/dist/postfx/fxShader.js +128 -0
- package/dist/postfx/fxShader.js.map +1 -0
- package/dist/postfx.js +26 -0
- package/dist/postfx.js.map +1 -0
- package/dist/react/ChoiceDialog.js +51 -0
- package/dist/react/ChoiceDialog.js.map +1 -0
- package/dist/react/ConfirmDialog.js +53 -0
- package/dist/react/ConfirmDialog.js.map +1 -0
- package/dist/react/Glyph.js +63 -0
- package/dist/react/Glyph.js.map +1 -0
- package/dist/react/Modal.js +38 -0
- package/dist/react/Modal.js.map +1 -0
- package/dist/react/Panel.js +24 -0
- package/dist/react/Panel.js.map +1 -0
- package/dist/react/PixelImage.js +24 -0
- package/dist/react/PixelImage.js.map +1 -0
- package/dist/react/Select.js +99 -0
- package/dist/react/Select.js.map +1 -0
- package/dist/react/Slider.js +62 -0
- package/dist/react/Slider.js.map +1 -0
- package/dist/react/SplitPane.js +24 -0
- package/dist/react/SplitPane.js.map +1 -0
- package/dist/react/TabStrip.js +32 -0
- package/dist/react/TabStrip.js.map +1 -0
- package/dist/react/TitleTips.js +42 -0
- package/dist/react/TitleTips.js.map +1 -0
- package/dist/react/Tooltip.js +28 -0
- package/dist/react/Tooltip.js.map +1 -0
- package/dist/react/UiProvider.js +50 -0
- package/dist/react/UiProvider.js.map +1 -0
- package/dist/react/baseCss.js +222 -0
- package/dist/react/baseCss.js.map +1 -0
- package/dist/react/choiceStore.js +23 -0
- package/dist/react/choiceStore.js.map +1 -0
- package/dist/react/classNames.js +19 -0
- package/dist/react/classNames.js.map +1 -0
- package/dist/react/confirmStore.js +30 -0
- package/dist/react/confirmStore.js.map +1 -0
- package/dist/react/labels.js +18 -0
- package/dist/react/labels.js.map +1 -0
- package/dist/react/placement.js +49 -0
- package/dist/react/placement.js.map +1 -0
- package/dist/react/useFillSheet.js +23 -0
- package/dist/react/useFillSheet.js.map +1 -0
- package/dist/react/useFitToViewport.js +29 -0
- package/dist/react/useFitToViewport.js.map +1 -0
- package/dist/react/usePicked.js +13 -0
- package/dist/react/usePicked.js.map +1 -0
- package/dist/react/useStore.js +9 -0
- package/dist/react/useStore.js.map +1 -0
- package/dist/react/useViewport.js +17 -0
- package/dist/react/useViewport.js.map +1 -0
- package/dist/react.js +78 -0
- package/dist/react.js.map +1 -0
- package/dist/rig/PosePlayer.js +92 -0
- package/dist/rig/PosePlayer.js.map +1 -0
- package/dist/rig/RigView.js +125 -0
- package/dist/rig/RigView.js.map +1 -0
- package/dist/rig/Skeleton.js +31 -0
- package/dist/rig/Skeleton.js.map +1 -0
- package/dist/rig/humanoid.js +6 -0
- package/dist/rig/humanoid.js.map +1 -0
- package/dist/rig/humanoid.json.js +30 -0
- package/dist/rig/humanoid.json.js.map +1 -0
- package/dist/rig/humanoidPoses.js +30 -0
- package/dist/rig/humanoidPoses.js.map +1 -0
- package/dist/rig/poseMath.js +54 -0
- package/dist/rig/poseMath.js.map +1 -0
- package/dist/rig/poses.json.js +150 -0
- package/dist/rig/poses.json.js.map +1 -0
- package/dist/save/Autosaver.js +54 -0
- package/dist/save/Autosaver.js.map +1 -0
- package/dist/save/MemoryBackend.js +19 -0
- package/dist/save/MemoryBackend.js.map +1 -0
- package/dist/save/SaveStore.js +103 -0
- package/dist/save/SaveStore.js.map +1 -0
- package/dist/save/WebStorageBackend.js +27 -0
- package/dist/save/WebStorageBackend.js.map +1 -0
- package/dist/save/checksum.js +10 -0
- package/dist/save/checksum.js.map +1 -0
- package/dist/save/migrateSave.js +27 -0
- package/dist/save/migrateSave.js.map +1 -0
- package/dist/settings.js +27 -0
- package/dist/settings.js.map +1 -0
- package/dist/tilemap/TilemapView.js +69 -0
- package/dist/tilemap/TilemapView.js.map +1 -0
- package/dist/tilemap/collision.js +25 -0
- package/dist/tilemap/collision.js.map +1 -0
- package/dist/tilemap/tiled.js +138 -0
- package/dist/tilemap/tiled.js.map +1 -0
- package/dist/transitions/CrossfadeTransition.js +24 -0
- package/dist/transitions/CrossfadeTransition.js.map +1 -0
- package/dist/transitions/DitherWipeTransition.js +70 -0
- package/dist/transitions/DitherWipeTransition.js.map +1 -0
- package/dist/transitions/FadeTransition.js +34 -0
- package/dist/transitions/FadeTransition.js.map +1 -0
- package/dist/transitions/Letterbox.js +42 -0
- package/dist/transitions/Letterbox.js.map +1 -0
- package/dist/transitions/ditherMask.js +15 -0
- package/dist/transitions/ditherMask.js.map +1 -0
- package/dist/transitions/transitionTo.js +28 -0
- package/dist/transitions/transitionTo.js.map +1 -0
- package/dist/transitions/tweenDone.js +15 -0
- package/dist/transitions/tweenDone.js.map +1 -0
- package/dist/types/ambient/ColorGrade.d.ts +41 -0
- package/dist/types/ambient/ColorGrade.d.ts.map +1 -0
- package/dist/types/ambient/DayClock.d.ts +80 -0
- package/dist/types/ambient/DayClock.d.ts.map +1 -0
- package/dist/types/ambient/WeatherLayer.d.ts +78 -0
- package/dist/types/ambient/WeatherLayer.d.ts.map +1 -0
- package/dist/types/ambient/grade.d.ts +22 -0
- package/dist/types/ambient/grade.d.ts.map +1 -0
- package/dist/types/ambient/weather.d.ts +49 -0
- package/dist/types/ambient/weather.d.ts.map +1 -0
- package/dist/types/anim/AnimStateMachine.d.ts +80 -0
- package/dist/types/anim/AnimStateMachine.d.ts.map +1 -0
- package/dist/types/anim/Animator.d.ts +50 -0
- package/dist/types/anim/Animator.d.ts.map +1 -0
- package/dist/types/anim/animStateCompile.d.ts +52 -0
- package/dist/types/anim/animStateCompile.d.ts.map +1 -0
- package/dist/types/anim/animStateSystem.d.ts +10 -0
- package/dist/types/anim/animStateSystem.d.ts.map +1 -0
- package/dist/types/anim/animStateTypes.d.ts +50 -0
- package/dist/types/anim/animStateTypes.d.ts.map +1 -0
- package/dist/types/anim/animationSystem.d.ts +13 -0
- package/dist/types/anim/animationSystem.d.ts.map +1 -0
- package/dist/types/anim/asepriteSlices.d.ts +19 -0
- package/dist/types/anim/asepriteSlices.d.ts.map +1 -0
- package/dist/types/anim/asepriteTags.d.ts +16 -0
- package/dist/types/anim/asepriteTags.d.ts.map +1 -0
- package/dist/types/anim/asepriteTypes.d.ts +159 -0
- package/dist/types/anim/asepriteTypes.d.ts.map +1 -0
- package/dist/types/anim/parseAseprite.d.ts +21 -0
- package/dist/types/anim/parseAseprite.d.ts.map +1 -0
- package/dist/types/assets/AssetLoader.d.ts +85 -0
- package/dist/types/assets/AssetLoader.d.ts.map +1 -0
- package/dist/types/assets/loadAseprite.d.ts +27 -0
- package/dist/types/assets/loadAseprite.d.ts.map +1 -0
- package/dist/types/audio/Footsteps.d.ts +33 -0
- package/dist/types/audio/Footsteps.d.ts.map +1 -0
- package/dist/types/audio/MusicPlayer.d.ts +65 -0
- package/dist/types/audio/MusicPlayer.d.ts.map +1 -0
- package/dist/types/audio/SoundEngine.d.ts +42 -0
- package/dist/types/audio/SoundEngine.d.ts.map +1 -0
- package/dist/types/audio/cleanTake.d.ts +3 -0
- package/dist/types/audio/cleanTake.d.ts.map +1 -0
- package/dist/types/audio/music/ElementVoice.d.ts +14 -0
- package/dist/types/audio/music/ElementVoice.d.ts.map +1 -0
- package/dist/types/audio/music/GraphVoice.d.ts +22 -0
- package/dist/types/audio/music/GraphVoice.d.ts.map +1 -0
- package/dist/types/audio/music/MusicChannel.d.ts +35 -0
- package/dist/types/audio/music/MusicChannel.d.ts.map +1 -0
- package/dist/types/audio/music/musicVoice.d.ts +26 -0
- package/dist/types/audio/music/musicVoice.d.ts.map +1 -0
- package/dist/types/audio/sampleBank.d.ts +27 -0
- package/dist/types/audio/sampleBank.d.ts.map +1 -0
- package/dist/types/audio/soundTable.d.ts +14 -0
- package/dist/types/audio/soundTable.d.ts.map +1 -0
- package/dist/types/audio/synth.d.ts +34 -0
- package/dist/types/audio/synth.d.ts.map +1 -0
- package/dist/types/audio/takeCleanerWorker.d.ts +2 -0
- package/dist/types/audio/takeCleanerWorker.d.ts.map +1 -0
- package/dist/types/core/BitmapLabel.d.ts +36 -0
- package/dist/types/core/BitmapLabel.d.ts.map +1 -0
- package/dist/types/core/Camera.d.ts +115 -0
- package/dist/types/core/Camera.d.ts.map +1 -0
- package/dist/types/core/Clock.d.ts +11 -0
- package/dist/types/core/Clock.d.ts.map +1 -0
- package/dist/types/core/Graphics.d.ts +37 -0
- package/dist/types/core/Graphics.d.ts.map +1 -0
- package/dist/types/core/Group.d.ts +15 -0
- package/dist/types/core/Group.d.ts.map +1 -0
- package/dist/types/core/Image.d.ts +25 -0
- package/dist/types/core/Image.d.ts.map +1 -0
- package/dist/types/core/ObjectFactory.d.ts +34 -0
- package/dist/types/core/ObjectFactory.d.ts.map +1 -0
- package/dist/types/core/Pointer.d.ts +27 -0
- package/dist/types/core/Pointer.d.ts.map +1 -0
- package/dist/types/core/Rectangle.d.ts +26 -0
- package/dist/types/core/Rectangle.d.ts.map +1 -0
- package/dist/types/core/Stage.d.ts +58 -0
- package/dist/types/core/Stage.d.ts.map +1 -0
- package/dist/types/core/Text.d.ts +22 -0
- package/dist/types/core/Text.d.ts.map +1 -0
- package/dist/types/core/TextureRegistry.d.ts +51 -0
- package/dist/types/core/TextureRegistry.d.ts.map +1 -0
- package/dist/types/core/Timeline.d.ts +115 -0
- package/dist/types/core/Timeline.d.ts.map +1 -0
- package/dist/types/core/TimelineBuilder.d.ts +53 -0
- package/dist/types/core/TimelineBuilder.d.ts.map +1 -0
- package/dist/types/core/TimelineChild.d.ts +51 -0
- package/dist/types/core/TimelineChild.d.ts.map +1 -0
- package/dist/types/core/Tweener.d.ts +70 -0
- package/dist/types/core/Tweener.d.ts.map +1 -0
- package/dist/types/core/atlas.d.ts +16 -0
- package/dist/types/core/atlas.d.ts.map +1 -0
- package/dist/types/core/atlasPlan.d.ts +34 -0
- package/dist/types/core/atlasPlan.d.ts.map +1 -0
- package/dist/types/core/eases.d.ts +3 -0
- package/dist/types/core/eases.d.ts.map +1 -0
- package/dist/types/core/gameObject.d.ts +42 -0
- package/dist/types/core/gameObject.d.ts.map +1 -0
- package/dist/types/core/pixiPatches.d.ts +9 -0
- package/dist/types/core/pixiPatches.d.ts.map +1 -0
- package/dist/types/core/timelinePlace.d.ts +23 -0
- package/dist/types/core/timelinePlace.d.ts.map +1 -0
- package/dist/types/core/tweenProps.d.ts +8 -0
- package/dist/types/core/tweenProps.d.ts.map +1 -0
- package/dist/types/core/types.d.ts +4 -0
- package/dist/types/core/types.d.ts.map +1 -0
- package/dist/types/debug/DebugOverlay.d.ts +63 -0
- package/dist/types/debug/DebugOverlay.d.ts.map +1 -0
- package/dist/types/debug/DrawCallCounter.d.ts +20 -0
- package/dist/types/debug/DrawCallCounter.d.ts.map +1 -0
- package/dist/types/debug/ErrorLog.d.ts +20 -0
- package/dist/types/debug/ErrorLog.d.ts.map +1 -0
- package/dist/types/debug/FrameStats.d.ts +21 -0
- package/dist/types/debug/FrameStats.d.ts.map +1 -0
- package/dist/types/debug/inspectWorld.d.ts +14 -0
- package/dist/types/debug/inspectWorld.d.ts.map +1 -0
- package/dist/types/diagnostics/ErrorDeduper.d.ts +17 -0
- package/dist/types/diagnostics/ErrorDeduper.d.ts.map +1 -0
- package/dist/types/diagnostics/FrameSampler.d.ts +37 -0
- package/dist/types/diagnostics/FrameSampler.d.ts.map +1 -0
- package/dist/types/diagnostics/bootWatch.d.ts +25 -0
- package/dist/types/diagnostics/bootWatch.d.ts.map +1 -0
- package/dist/types/diagnostics/captureErrors.d.ts +24 -0
- package/dist/types/diagnostics/captureErrors.d.ts.map +1 -0
- package/dist/types/diagnostics/contextLoss.d.ts +35 -0
- package/dist/types/diagnostics/contextLoss.d.ts.map +1 -0
- package/dist/types/diagnostics/frameStats.d.ts +30 -0
- package/dist/types/diagnostics/frameStats.d.ts.map +1 -0
- package/dist/types/diagnostics/gpuInfo.d.ts +9 -0
- package/dist/types/diagnostics/gpuInfo.d.ts.map +1 -0
- package/dist/types/diagnostics/renderGuard.d.ts +12 -0
- package/dist/types/diagnostics/renderGuard.d.ts.map +1 -0
- package/dist/types/ecs/SparseSet.d.ts +25 -0
- package/dist/types/ecs/SparseSet.d.ts.map +1 -0
- package/dist/types/ecs/World.d.ts +137 -0
- package/dist/types/ecs/World.d.ts.map +1 -0
- package/dist/types/ecs/fields.d.ts +34 -0
- package/dist/types/ecs/fields.d.ts.map +1 -0
- package/dist/types/engine/Engine.d.ts +80 -0
- package/dist/types/engine/Engine.d.ts.map +1 -0
- package/dist/types/engine/FixedLoop.d.ts +32 -0
- package/dist/types/engine/FixedLoop.d.ts.map +1 -0
- package/dist/types/engine/Scene.d.ts +67 -0
- package/dist/types/engine/Scene.d.ts.map +1 -0
- package/dist/types/engine/SceneManager.d.ts +36 -0
- package/dist/types/engine/SceneManager.d.ts.map +1 -0
- package/dist/types/events/EventBus.d.ts +20 -0
- package/dist/types/events/EventBus.d.ts.map +1 -0
- package/dist/types/fx/FloatingText.d.ts +71 -0
- package/dist/types/fx/FloatingText.d.ts.map +1 -0
- package/dist/types/fx/hitStop.d.ts +20 -0
- package/dist/types/fx/hitStop.d.ts.map +1 -0
- package/dist/types/fx/viewCull.d.ts +14 -0
- package/dist/types/fx/viewCull.d.ts.map +1 -0
- package/dist/types/i18n/Translator.d.ts +52 -0
- package/dist/types/i18n/Translator.d.ts.map +1 -0
- package/dist/types/i18n/extractStrings.d.ts +25 -0
- package/dist/types/i18n/extractStrings.d.ts.map +1 -0
- package/dist/types/i18n/formatMessage.d.ts +10 -0
- package/dist/types/i18n/formatMessage.d.ts.map +1 -0
- package/dist/types/index.d.ts +149 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/input/Actions.d.ts +94 -0
- package/dist/types/input/Actions.d.ts.map +1 -0
- package/dist/types/input/AimGesture.d.ts +106 -0
- package/dist/types/input/AimGesture.d.ts.map +1 -0
- package/dist/types/input/Keyboard.d.ts +30 -0
- package/dist/types/input/Keyboard.d.ts.map +1 -0
- package/dist/types/input/Keymap.d.ts +85 -0
- package/dist/types/input/Keymap.d.ts.map +1 -0
- package/dist/types/input/TargetLock.d.ts +56 -0
- package/dist/types/input/TargetLock.d.ts.map +1 -0
- package/dist/types/input/aimAxis.d.ts +9 -0
- package/dist/types/input/aimAxis.d.ts.map +1 -0
- package/dist/types/input/keyChord.d.ts +15 -0
- package/dist/types/input/keyChord.d.ts.map +1 -0
- package/dist/types/input/longPress.d.ts +21 -0
- package/dist/types/input/longPress.d.ts.map +1 -0
- package/dist/types/input/stickAxis.d.ts +26 -0
- package/dist/types/input/stickAxis.d.ts.map +1 -0
- package/dist/types/input/touchDetect.d.ts +18 -0
- package/dist/types/input/touchDetect.d.ts.map +1 -0
- package/dist/types/light/LightLayer.d.ts +65 -0
- package/dist/types/light/LightLayer.d.ts.map +1 -0
- package/dist/types/nav/MinHeap.d.ts +15 -0
- package/dist/types/nav/MinHeap.d.ts.map +1 -0
- package/dist/types/nav/findPath.d.ts +38 -0
- package/dist/types/nav/findPath.d.ts.map +1 -0
- package/dist/types/nav/navGrid.d.ts +48 -0
- package/dist/types/nav/navGrid.d.ts.map +1 -0
- package/dist/types/nav/nearestOpen.d.ts +8 -0
- package/dist/types/nav/nearestOpen.d.ts.map +1 -0
- package/dist/types/nav/straightenPath.d.ts +13 -0
- package/dist/types/nav/straightenPath.d.ts.map +1 -0
- package/dist/types/net/Connection.d.ts +66 -0
- package/dist/types/net/Connection.d.ts.map +1 -0
- package/dist/types/net/InterpolationBuffer.d.ts +36 -0
- package/dist/types/net/InterpolationBuffer.d.ts.map +1 -0
- package/dist/types/net/PredictedMover.d.ts +43 -0
- package/dist/types/net/PredictedMover.d.ts.map +1 -0
- package/dist/types/net/Room.d.ts +69 -0
- package/dist/types/net/Room.d.ts.map +1 -0
- package/dist/types/net/RoomHost.d.ts +74 -0
- package/dist/types/net/RoomHost.d.ts.map +1 -0
- package/dist/types/net/cadence.d.ts +22 -0
- package/dist/types/net/cadence.d.ts.map +1 -0
- package/dist/types/net/constants.d.ts +24 -0
- package/dist/types/net/constants.d.ts.map +1 -0
- package/dist/types/net/lobby/LobbyClient.d.ts +107 -0
- package/dist/types/net/lobby/LobbyClient.d.ts.map +1 -0
- package/dist/types/net/lobby/LobbyHost.d.ts +147 -0
- package/dist/types/net/lobby/LobbyHost.d.ts.map +1 -0
- package/dist/types/net/lobby/LobbyRooms.d.ts +56 -0
- package/dist/types/net/lobby/LobbyRooms.d.ts.map +1 -0
- package/dist/types/net/lobby/Matchmaker.d.ts +57 -0
- package/dist/types/net/lobby/Matchmaker.d.ts.map +1 -0
- package/dist/types/net/lobby/index.d.ts +6 -0
- package/dist/types/net/lobby/index.d.ts.map +1 -0
- package/dist/types/net/lobby/lobbyProtocol.d.ts +143 -0
- package/dist/types/net/lobby/lobbyProtocol.d.ts.map +1 -0
- package/dist/types/net/movement.d.ts +50 -0
- package/dist/types/net/movement.d.ts.map +1 -0
- package/dist/types/net/protocol.d.ts +59 -0
- package/dist/types/net/protocol.d.ts.map +1 -0
- package/dist/types/net/serverClock.d.ts +14 -0
- package/dist/types/net/serverClock.d.ts.map +1 -0
- package/dist/types/net/snapshotCodec.d.ts +55 -0
- package/dist/types/net/snapshotCodec.d.ts.map +1 -0
- package/dist/types/parallax/Parallax.d.ts +37 -0
- package/dist/types/parallax/Parallax.d.ts.map +1 -0
- package/dist/types/parallax/ParallaxLayer.d.ts +80 -0
- package/dist/types/parallax/ParallaxLayer.d.ts.map +1 -0
- package/dist/types/parallax/parallaxMath.d.ts +50 -0
- package/dist/types/parallax/parallaxMath.d.ts.map +1 -0
- package/dist/types/particles/Emitter.d.ts +97 -0
- package/dist/types/particles/Emitter.d.ts.map +1 -0
- package/dist/types/particles/ParticleBudget.d.ts +28 -0
- package/dist/types/particles/ParticleBudget.d.ts.map +1 -0
- package/dist/types/particles/ParticleSim.d.ts +38 -0
- package/dist/types/particles/ParticleSim.d.ts.map +1 -0
- package/dist/types/particles/particleCurves.d.ts +21 -0
- package/dist/types/particles/particleCurves.d.ts.map +1 -0
- package/dist/types/particles/particleSampling.d.ts +20 -0
- package/dist/types/particles/particleSampling.d.ts.map +1 -0
- package/dist/types/physics/Body.d.ts +130 -0
- package/dist/types/physics/Body.d.ts.map +1 -0
- package/dist/types/physics/BroadPhase.d.ts +26 -0
- package/dist/types/physics/BroadPhase.d.ts.map +1 -0
- package/dist/types/physics/Contact.d.ts +62 -0
- package/dist/types/physics/Contact.d.ts.map +1 -0
- package/dist/types/physics/ContactSolver.d.ts +29 -0
- package/dist/types/physics/ContactSolver.d.ts.map +1 -0
- package/dist/types/physics/PhysicsWorld.d.ts +78 -0
- package/dist/types/physics/PhysicsWorld.d.ts.map +1 -0
- package/dist/types/physics/PhysicsWorldOptions.d.ts +24 -0
- package/dist/types/physics/PhysicsWorldOptions.d.ts.map +1 -0
- package/dist/types/physics/SpatialHash.d.ts +23 -0
- package/dist/types/physics/SpatialHash.d.ts.map +1 -0
- package/dist/types/physics/collide.d.ts +27 -0
- package/dist/types/physics/collide.d.ts.map +1 -0
- package/dist/types/physics/collidePolygon.d.ts +14 -0
- package/dist/types/physics/collidePolygon.d.ts.map +1 -0
- package/dist/types/physics/contactReport.d.ts +8 -0
- package/dist/types/physics/contactReport.d.ts.map +1 -0
- package/dist/types/physics/drawColliders.d.ts +43 -0
- package/dist/types/physics/drawColliders.d.ts.map +1 -0
- package/dist/types/physics/physicsSystem.d.ts +5 -0
- package/dist/types/physics/physicsSystem.d.ts.map +1 -0
- package/dist/types/physics/polygon.d.ts +28 -0
- package/dist/types/physics/polygon.d.ts.map +1 -0
- package/dist/types/physics/raycast.d.ts +19 -0
- package/dist/types/physics/raycast.d.ts.map +1 -0
- package/dist/types/physics/syncToBody.d.ts +16 -0
- package/dist/types/physics/syncToBody.d.ts.map +1 -0
- package/dist/types/physics/tileBodies.d.ts +36 -0
- package/dist/types/physics/tileBodies.d.ts.map +1 -0
- package/dist/types/physics/types.d.ts +116 -0
- package/dist/types/physics/types.d.ts.map +1 -0
- package/dist/types/pixel/Darkness.d.ts +78 -0
- package/dist/types/pixel/Darkness.d.ts.map +1 -0
- package/dist/types/pixel/DitherVignette.d.ts +35 -0
- package/dist/types/pixel/DitherVignette.d.ts.map +1 -0
- package/dist/types/pixel/Evaporation.d.ts +30 -0
- package/dist/types/pixel/Evaporation.d.ts.map +1 -0
- package/dist/types/pixel/NightShade.d.ts +38 -0
- package/dist/types/pixel/NightShade.d.ts.map +1 -0
- package/dist/types/pixel/PixelLayer.d.ts +85 -0
- package/dist/types/pixel/PixelLayer.d.ts.map +1 -0
- package/dist/types/pixel/SwayProp.d.ts +52 -0
- package/dist/types/pixel/SwayProp.d.ts.map +1 -0
- package/dist/types/pixel/index.d.ts +31 -0
- package/dist/types/pixel/index.d.ts.map +1 -0
- package/dist/types/pixel/lights.d.ts +34 -0
- package/dist/types/pixel/lights.d.ts.map +1 -0
- package/dist/types/pixel/nineSlice.d.ts +71 -0
- package/dist/types/pixel/nineSlice.d.ts.map +1 -0
- package/dist/types/pixel/paintLayer.d.ts +35 -0
- package/dist/types/pixel/paintLayer.d.ts.map +1 -0
- package/dist/types/pixel/palette.d.ts +58 -0
- package/dist/types/pixel/palette.d.ts.map +1 -0
- package/dist/types/pixel/pixel.d.ts +80 -0
- package/dist/types/pixel/pixel.d.ts.map +1 -0
- package/dist/types/pixel/pixelPaint.d.ts +43 -0
- package/dist/types/pixel/pixelPaint.d.ts.map +1 -0
- package/dist/types/pixel/pixelTone.d.ts +51 -0
- package/dist/types/pixel/pixelTone.d.ts.map +1 -0
- package/dist/types/pixel/propKit.d.ts +26 -0
- package/dist/types/pixel/propKit.d.ts.map +1 -0
- package/dist/types/pixel/ramp.d.ts +57 -0
- package/dist/types/pixel/ramp.d.ts.map +1 -0
- package/dist/types/pixel/selout.d.ts +3 -0
- package/dist/types/pixel/selout.d.ts.map +1 -0
- package/dist/types/pixel/spritePixels.d.ts +29 -0
- package/dist/types/pixel/spritePixels.d.ts.map +1 -0
- package/dist/types/pixel/swayRig.d.ts +72 -0
- package/dist/types/pixel/swayRig.d.ts.map +1 -0
- package/dist/types/pixel/vignetteMask.d.ts +16 -0
- package/dist/types/pixel/vignetteMask.d.ts.map +1 -0
- package/dist/types/pixel/weatherArt.d.ts +29 -0
- package/dist/types/pixel/weatherArt.d.ts.map +1 -0
- package/dist/types/platform/touch.d.ts +10 -0
- package/dist/types/platform/touch.d.ts.map +1 -0
- package/dist/types/postfx/BloomFilter.d.ts +33 -0
- package/dist/types/postfx/BloomFilter.d.ts.map +1 -0
- package/dist/types/postfx/ChromaticAberrationFilter.d.ts +11 -0
- package/dist/types/postfx/ChromaticAberrationFilter.d.ts.map +1 -0
- package/dist/types/postfx/ColorAdjustFilter.d.ts +32 -0
- package/dist/types/postfx/ColorAdjustFilter.d.ts.map +1 -0
- package/dist/types/postfx/CrtFilter.d.ts +16 -0
- package/dist/types/postfx/CrtFilter.d.ts.map +1 -0
- package/dist/types/postfx/PixelateFilter.d.ts +8 -0
- package/dist/types/postfx/PixelateFilter.d.ts.map +1 -0
- package/dist/types/postfx/PostFx.d.ts +92 -0
- package/dist/types/postfx/PostFx.d.ts.map +1 -0
- package/dist/types/postfx/ShockwaveFilter.d.ts +20 -0
- package/dist/types/postfx/ShockwaveFilter.d.ts.map +1 -0
- package/dist/types/postfx/VignetteFilter.d.ts +19 -0
- package/dist/types/postfx/VignetteFilter.d.ts.map +1 -0
- package/dist/types/postfx/fxAnimator.d.ts +32 -0
- package/dist/types/postfx/fxAnimator.d.ts.map +1 -0
- package/dist/types/postfx/fxShader.d.ts +49 -0
- package/dist/types/postfx/fxShader.d.ts.map +1 -0
- package/dist/types/postfx/index.d.ts +11 -0
- package/dist/types/postfx/index.d.ts.map +1 -0
- package/dist/types/react/ChoiceDialog.d.ts +8 -0
- package/dist/types/react/ChoiceDialog.d.ts.map +1 -0
- package/dist/types/react/ConfirmDialog.d.ts +9 -0
- package/dist/types/react/ConfirmDialog.d.ts.map +1 -0
- package/dist/types/react/Glyph.d.ts +54 -0
- package/dist/types/react/Glyph.d.ts.map +1 -0
- package/dist/types/react/Modal.d.ts +22 -0
- package/dist/types/react/Modal.d.ts.map +1 -0
- package/dist/types/react/Panel.d.ts +29 -0
- package/dist/types/react/Panel.d.ts.map +1 -0
- package/dist/types/react/PixelImage.d.ts +19 -0
- package/dist/types/react/PixelImage.d.ts.map +1 -0
- package/dist/types/react/Select.d.ts +27 -0
- package/dist/types/react/Select.d.ts.map +1 -0
- package/dist/types/react/Slider.d.ts +24 -0
- package/dist/types/react/Slider.d.ts.map +1 -0
- package/dist/types/react/SplitPane.d.ts +26 -0
- package/dist/types/react/SplitPane.d.ts.map +1 -0
- package/dist/types/react/TabStrip.d.ts +31 -0
- package/dist/types/react/TabStrip.d.ts.map +1 -0
- package/dist/types/react/TitleTips.d.ts +15 -0
- package/dist/types/react/TitleTips.d.ts.map +1 -0
- package/dist/types/react/Tooltip.d.ts +22 -0
- package/dist/types/react/Tooltip.d.ts.map +1 -0
- package/dist/types/react/UiProvider.d.ts +52 -0
- package/dist/types/react/UiProvider.d.ts.map +1 -0
- package/dist/types/react/baseCss.d.ts +27 -0
- package/dist/types/react/baseCss.d.ts.map +1 -0
- package/dist/types/react/choiceStore.d.ts +34 -0
- package/dist/types/react/choiceStore.d.ts.map +1 -0
- package/dist/types/react/classNames.d.ts +12 -0
- package/dist/types/react/classNames.d.ts.map +1 -0
- package/dist/types/react/confirmStore.d.ts +30 -0
- package/dist/types/react/confirmStore.d.ts.map +1 -0
- package/dist/types/react/index.d.ts +33 -0
- package/dist/types/react/index.d.ts.map +1 -0
- package/dist/types/react/labels.d.ts +24 -0
- package/dist/types/react/labels.d.ts.map +1 -0
- package/dist/types/react/placement.d.ts +59 -0
- package/dist/types/react/placement.d.ts.map +1 -0
- package/dist/types/react/useFillSheet.d.ts +9 -0
- package/dist/types/react/useFillSheet.d.ts.map +1 -0
- package/dist/types/react/useFitToViewport.d.ts +20 -0
- package/dist/types/react/useFitToViewport.d.ts.map +1 -0
- package/dist/types/react/usePicked.d.ts +9 -0
- package/dist/types/react/usePicked.d.ts.map +1 -0
- package/dist/types/react/useStore.d.ts +8 -0
- package/dist/types/react/useStore.d.ts.map +1 -0
- package/dist/types/react/useViewport.d.ts +4 -0
- package/dist/types/react/useViewport.d.ts.map +1 -0
- package/dist/types/rig/PosePlayer.d.ts +64 -0
- package/dist/types/rig/PosePlayer.d.ts.map +1 -0
- package/dist/types/rig/RigView.d.ts +68 -0
- package/dist/types/rig/RigView.d.ts.map +1 -0
- package/dist/types/rig/Skeleton.d.ts +14 -0
- package/dist/types/rig/Skeleton.d.ts.map +1 -0
- package/dist/types/rig/humanoid.d.ts +4 -0
- package/dist/types/rig/humanoid.d.ts.map +1 -0
- package/dist/types/rig/humanoidPoses.d.ts +117 -0
- package/dist/types/rig/humanoidPoses.d.ts.map +1 -0
- package/dist/types/rig/poseMath.d.ts +14 -0
- package/dist/types/rig/poseMath.d.ts.map +1 -0
- package/dist/types/rig/rigTypes.d.ts +82 -0
- package/dist/types/rig/rigTypes.d.ts.map +1 -0
- package/dist/types/save/Autosaver.d.ts +43 -0
- package/dist/types/save/Autosaver.d.ts.map +1 -0
- package/dist/types/save/MemoryBackend.d.ts +10 -0
- package/dist/types/save/MemoryBackend.d.ts.map +1 -0
- package/dist/types/save/SaveBackend.d.ts +14 -0
- package/dist/types/save/SaveBackend.d.ts.map +1 -0
- package/dist/types/save/SaveStore.d.ts +73 -0
- package/dist/types/save/SaveStore.d.ts.map +1 -0
- package/dist/types/save/WebStorageBackend.d.ts +14 -0
- package/dist/types/save/WebStorageBackend.d.ts.map +1 -0
- package/dist/types/save/checksum.d.ts +7 -0
- package/dist/types/save/checksum.d.ts.map +1 -0
- package/dist/types/save/migrateSave.d.ts +17 -0
- package/dist/types/save/migrateSave.d.ts.map +1 -0
- package/dist/types/settings.d.ts +25 -0
- package/dist/types/settings.d.ts.map +1 -0
- package/dist/types/tilemap/TilemapView.d.ts +42 -0
- package/dist/types/tilemap/TilemapView.d.ts.map +1 -0
- package/dist/types/tilemap/collision.d.ts +16 -0
- package/dist/types/tilemap/collision.d.ts.map +1 -0
- package/dist/types/tilemap/tiled.d.ts +104 -0
- package/dist/types/tilemap/tiled.d.ts.map +1 -0
- package/dist/types/transitions/CrossfadeTransition.d.ts +20 -0
- package/dist/types/transitions/CrossfadeTransition.d.ts.map +1 -0
- package/dist/types/transitions/DitherWipeTransition.d.ts +35 -0
- package/dist/types/transitions/DitherWipeTransition.d.ts.map +1 -0
- package/dist/types/transitions/FadeTransition.d.ts +20 -0
- package/dist/types/transitions/FadeTransition.d.ts.map +1 -0
- package/dist/types/transitions/Letterbox.d.ts +33 -0
- package/dist/types/transitions/Letterbox.d.ts.map +1 -0
- package/dist/types/transitions/Transition.d.ts +22 -0
- package/dist/types/transitions/Transition.d.ts.map +1 -0
- package/dist/types/transitions/ditherMask.d.ts +13 -0
- package/dist/types/transitions/ditherMask.d.ts.map +1 -0
- package/dist/types/transitions/transitionTo.d.ts +16 -0
- package/dist/types/transitions/transitionTo.d.ts.map +1 -0
- package/dist/types/transitions/tweenDone.d.ts +5 -0
- package/dist/types/transitions/tweenDone.d.ts.map +1 -0
- package/dist/types/ui/Bar.d.ts +41 -0
- package/dist/types/ui/Bar.d.ts.map +1 -0
- package/dist/types/ui/Button.d.ts +47 -0
- package/dist/types/ui/Button.d.ts.map +1 -0
- package/dist/types/ui/Dialog.d.ts +47 -0
- package/dist/types/ui/Dialog.d.ts.map +1 -0
- package/dist/types/ui/FocusManager.d.ts +53 -0
- package/dist/types/ui/FocusManager.d.ts.map +1 -0
- package/dist/types/ui/Label.d.ts +24 -0
- package/dist/types/ui/Label.d.ts.map +1 -0
- package/dist/types/ui/List.d.ts +23 -0
- package/dist/types/ui/List.d.ts.map +1 -0
- package/dist/types/ui/Panel.d.ts +38 -0
- package/dist/types/ui/Panel.d.ts.map +1 -0
- package/dist/types/ui/ScrollView.d.ts +56 -0
- package/dist/types/ui/ScrollView.d.ts.map +1 -0
- package/dist/types/ui/Slider.d.ts +47 -0
- package/dist/types/ui/Slider.d.ts.map +1 -0
- package/dist/types/ui/Stack.d.ts +16 -0
- package/dist/types/ui/Stack.d.ts.map +1 -0
- package/dist/types/ui/Toggle.d.ts +31 -0
- package/dist/types/ui/Toggle.d.ts.map +1 -0
- package/dist/types/ui/UiHost.d.ts +18 -0
- package/dist/types/ui/UiHost.d.ts.map +1 -0
- package/dist/types/ui/UiPointerGate.d.ts +17 -0
- package/dist/types/ui/UiPointerGate.d.ts.map +1 -0
- package/dist/types/ui/UiRoot.d.ts +73 -0
- package/dist/types/ui/UiRoot.d.ts.map +1 -0
- package/dist/types/ui/Widget.d.ts +56 -0
- package/dist/types/ui/Widget.d.ts.map +1 -0
- package/dist/types/ui/dom/DomOverlay.d.ts +52 -0
- package/dist/types/ui/dom/DomOverlay.d.ts.map +1 -0
- package/dist/types/ui/dom/DomWorldAnchors.d.ts +50 -0
- package/dist/types/ui/dom/DomWorldAnchors.d.ts.map +1 -0
- package/dist/types/ui/dom/InputShield.d.ts +20 -0
- package/dist/types/ui/dom/InputShield.d.ts.map +1 -0
- package/dist/types/ui/dom/createStore.d.ts +22 -0
- package/dist/types/ui/dom/createStore.d.ts.map +1 -0
- package/dist/types/ui/dom/shieldDecision.d.ts +34 -0
- package/dist/types/ui/dom/shieldDecision.d.ts.map +1 -0
- package/dist/types/ui/dom/worldToScreen.d.ts +24 -0
- package/dist/types/ui/dom/worldToScreen.d.ts.map +1 -0
- package/dist/types/ui/index.d.ts +38 -0
- package/dist/types/ui/index.d.ts.map +1 -0
- package/dist/types/ui/layout/anchor.d.ts +9 -0
- package/dist/types/ui/layout/anchor.d.ts.map +1 -0
- package/dist/types/ui/layout/barDrain.d.ts +25 -0
- package/dist/types/ui/layout/barDrain.d.ts.map +1 -0
- package/dist/types/ui/layout/fitToViewport.d.ts +32 -0
- package/dist/types/ui/layout/fitToViewport.d.ts.map +1 -0
- package/dist/types/ui/layout/focusNav.d.ts +13 -0
- package/dist/types/ui/layout/focusNav.d.ts.map +1 -0
- package/dist/types/ui/layout/geometry.d.ts +35 -0
- package/dist/types/ui/layout/geometry.d.ts.map +1 -0
- package/dist/types/ui/layout/listWidth.d.ts +13 -0
- package/dist/types/ui/layout/listWidth.d.ts.map +1 -0
- package/dist/types/ui/layout/placeTooltip.d.ts +23 -0
- package/dist/types/ui/layout/placeTooltip.d.ts.map +1 -0
- package/dist/types/ui/layout/scroll.d.ts +17 -0
- package/dist/types/ui/layout/scroll.d.ts.map +1 -0
- package/dist/types/ui/layout/slider.d.ts +7 -0
- package/dist/types/ui/layout/slider.d.ts.map +1 -0
- package/dist/types/ui/layout/stack.d.ts +26 -0
- package/dist/types/ui/layout/stack.d.ts.map +1 -0
- package/dist/types/ui/layout/wrapRow.d.ts +6 -0
- package/dist/types/ui/layout/wrapRow.d.ts.map +1 -0
- package/dist/ui/Bar.js +54 -0
- package/dist/ui/Bar.js.map +1 -0
- package/dist/ui/Button.js +58 -0
- package/dist/ui/Button.js.map +1 -0
- package/dist/ui/Dialog.js +56 -0
- package/dist/ui/Dialog.js.map +1 -0
- package/dist/ui/FocusManager.js +97 -0
- package/dist/ui/FocusManager.js.map +1 -0
- package/dist/ui/Label.js +36 -0
- package/dist/ui/Label.js.map +1 -0
- package/dist/ui/List.js +45 -0
- package/dist/ui/List.js.map +1 -0
- package/dist/ui/Panel.js +38 -0
- package/dist/ui/Panel.js.map +1 -0
- package/dist/ui/ScrollView.js +96 -0
- package/dist/ui/ScrollView.js.map +1 -0
- package/dist/ui/Slider.js +55 -0
- package/dist/ui/Slider.js.map +1 -0
- package/dist/ui/Stack.js +28 -0
- package/dist/ui/Stack.js.map +1 -0
- package/dist/ui/Toggle.js +37 -0
- package/dist/ui/Toggle.js.map +1 -0
- package/dist/ui/UiHost.js +9 -0
- package/dist/ui/UiHost.js.map +1 -0
- package/dist/ui/UiPointerGate.js +25 -0
- package/dist/ui/UiPointerGate.js.map +1 -0
- package/dist/ui/UiRoot.js +93 -0
- package/dist/ui/UiRoot.js.map +1 -0
- package/dist/ui/Widget.js +90 -0
- package/dist/ui/Widget.js.map +1 -0
- package/dist/ui/dom/DomOverlay.js +59 -0
- package/dist/ui/dom/DomOverlay.js.map +1 -0
- package/dist/ui/dom/DomWorldAnchors.js +59 -0
- package/dist/ui/dom/DomWorldAnchors.js.map +1 -0
- package/dist/ui/dom/InputShield.js +27 -0
- package/dist/ui/dom/InputShield.js.map +1 -0
- package/dist/ui/dom/createStore.js +42 -0
- package/dist/ui/dom/createStore.js.map +1 -0
- package/dist/ui/dom/shieldDecision.js +36 -0
- package/dist/ui/dom/shieldDecision.js.map +1 -0
- package/dist/ui/dom/worldToScreen.js +11 -0
- package/dist/ui/dom/worldToScreen.js.map +1 -0
- package/dist/ui/layout/anchor.js +20 -0
- package/dist/ui/layout/anchor.js.map +1 -0
- package/dist/ui/layout/barDrain.js +25 -0
- package/dist/ui/layout/barDrain.js.map +1 -0
- package/dist/ui/layout/fitToViewport.js +17 -0
- package/dist/ui/layout/fitToViewport.js.map +1 -0
- package/dist/ui/layout/focusNav.js +42 -0
- package/dist/ui/layout/focusNav.js.map +1 -0
- package/dist/ui/layout/geometry.js +21 -0
- package/dist/ui/layout/geometry.js.map +1 -0
- package/dist/ui/layout/listWidth.js +10 -0
- package/dist/ui/layout/listWidth.js.map +1 -0
- package/dist/ui/layout/placeTooltip.js +28 -0
- package/dist/ui/layout/placeTooltip.js.map +1 -0
- package/dist/ui/layout/scroll.js +24 -0
- package/dist/ui/layout/scroll.js.map +1 -0
- package/dist/ui/layout/slider.js +20 -0
- package/dist/ui/layout/slider.js.map +1 -0
- package/dist/ui/layout/stack.js +27 -0
- package/dist/ui/layout/stack.js.map +1 -0
- package/dist/ui/layout/wrapRow.js +13 -0
- package/dist/ui/layout/wrapRow.js.map +1 -0
- package/dist/ui.js +85 -0
- package/dist/ui.js.map +1 -0
- package/package.json +115 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Connection.js","sources":["../../src/net/Connection.ts"],"sourcesContent":["import { EventBus } from '../events/EventBus';\nimport type { InputStep } from './constants';\nimport { noteServerTime } from './serverClock';\nimport { decodeSnapshotFrame } from './snapshotCodec';\nimport type { ClientMessage, ServerMessage, Snapshot } from './protocol';\n\nexport interface ConnectionEvents {\n open: undefined;\n /** The socket closed; `willRetry` when it will reconnect by itself. */\n close: { code: number; reason: string; willRetry: boolean };\n welcome: Extract<ServerMessage, { t: 'welcome' }>;\n snapshot: Snapshot;\n /** Any message the engine does not handle: the game's own. */\n message: { t: string; [k: string]: unknown };\n}\n\nexport interface ConnectionOptions {\n /** Reconnect after the socket drops (default true), waiting longer each time up to `maxBackoffMs`. */\n reconnect?: boolean;\n maxBackoffMs?: number;\n /** Ping interval for the server clock and the round-trip time (default 1000 ms). */\n pingMs?: number;\n /** Sent on every (re)connect as `hello.data`. */\n hello?: () => unknown;\n /** The WebSocket class (default the global one; Node 22+ and browsers have it). */\n WebSocket?: typeof WebSocket;\n}\n\n/**\n * The client side of the engine's netcode over a WebSocket: hello on open, input steps batched and sent once a frame\n * (`queueInput` then `flush`), snapshots decoded (binary or JSON) onto `events`, pings that keep the server clock\n * (`serverNow`) and `rtt` up to date, and reconnection with backoff.\n */\nexport class Connection {\n readonly events = new EventBus<ConnectionEvents>();\n /** The last measured round trip, ms. */\n rtt = 0;\n private socket: WebSocket | null = null;\n private batch: { seq: number; steps: InputStep[] } | null = null;\n private closedByUs = false;\n private attempt = 0;\n private pingTimer: ReturnType<typeof setInterval> | null = null;\n private retryTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(\n readonly url: string,\n private readonly options: ConnectionOptions = {},\n ) {}\n\n get open(): boolean {\n return this.socket?.readyState === 1;\n }\n\n connect(): this {\n this.closedByUs = false;\n const Impl = this.options.WebSocket ?? globalThis.WebSocket;\n if (!Impl) throw new Error('Connection: no WebSocket in this environment');\n const ws = new Impl(this.url);\n ws.binaryType = 'arraybuffer';\n this.socket = ws;\n ws.onopen = () => {\n this.attempt = 0;\n this.send({ t: 'hello', data: this.options.hello?.() });\n this.ping();\n this.pingTimer = setInterval(() => this.ping(), this.options.pingMs ?? 1000);\n this.events.emit('open', undefined);\n };\n ws.onmessage = (e) => this.receive(e.data);\n ws.onclose = (e) => {\n if (this.pingTimer) clearInterval(this.pingTimer);\n this.pingTimer = null;\n this.socket = null;\n const willRetry = !this.closedByUs && this.options.reconnect !== false;\n this.events.emit('close', { code: e.code, reason: e.reason, willRetry });\n if (willRetry) {\n const wait = Math.min(this.options.maxBackoffMs ?? 10_000, 250 * 2 ** this.attempt++);\n this.retryTimer = setTimeout(() => this.connect(), wait);\n }\n };\n return this;\n }\n\n /** Sends a message now (dropped while closed: input is resent by the prediction's own state, not by the socket). */\n send(msg: ClientMessage | { t: string; [k: string]: unknown }): void {\n if (this.socket?.readyState === 1) this.socket.send(JSON.stringify(msg));\n }\n\n /** Adds one input step to this frame's batch; `flush` sends it. Steps must come in sequence order. */\n queueInput(seq: number, step: InputStep): void {\n if (!this.batch) this.batch = { seq, steps: [] };\n this.batch.steps.push([step[0], step[1], step[2]]);\n }\n\n /** Sends this frame's input steps as one message. Call once a frame. */\n flush(): void {\n if (!this.batch) return;\n this.send({ t: 'input', seq: this.batch.seq, steps: this.batch.steps });\n this.batch = null;\n }\n\n close(): void {\n this.closedByUs = true;\n if (this.retryTimer) clearTimeout(this.retryTimer);\n if (this.pingTimer) clearInterval(this.pingTimer);\n this.socket?.close();\n this.socket = null;\n }\n\n private ping(): void {\n this.send({ t: 'ping', c: Date.now() });\n }\n\n private receive(data: unknown): void {\n let msg: ServerMessage | { t: string; [k: string]: unknown };\n try {\n msg = typeof data === 'string' ? JSON.parse(data) : (decodeSnapshotFrame<Snapshot>(data as ArrayBuffer) as Snapshot);\n } catch (err) {\n console.error('[net] could not read a message', err);\n return;\n }\n switch (msg.t) {\n case 'pong': {\n const m = msg as Extract<ServerMessage, { t: 'pong' }>;\n this.rtt = Date.now() - m.c;\n noteServerTime(m.st, this.rtt);\n return;\n }\n case 'welcome':\n this.events.emit('welcome', msg as Extract<ServerMessage, { t: 'welcome' }>);\n return;\n case 'snap':\n this.events.emit('snapshot', msg as Snapshot);\n return;\n default:\n this.events.emit('message', msg as { t: string; [k: string]: unknown });\n }\n }\n}\n"],"names":["Connection","url","options","EventBus","Impl","ws","e","willRetry","wait","msg","seq","step","data","decodeSnapshotFrame","err","m","noteServerTime"],"mappings":";;;AAiCO,MAAMA,EAAW;AAAA,EAWtB,YACWC,GACQC,IAA6B,IAC9C;AAFS,SAAA,MAAAD,GACQ,KAAA,UAAAC;AAAA,EAChB;AAAA,EAFQ;AAAA,EACQ;AAAA,EAZV,SAAS,IAAIC,EAAA;AAAA;AAAA,EAEtB,MAAM;AAAA,EACE,SAA2B;AAAA,EAC3B,QAAoD;AAAA,EACpD,aAAa;AAAA,EACb,UAAU;AAAA,EACV,YAAmD;AAAA,EACnD,aAAmD;AAAA,EAO3D,IAAI,OAAgB;AAClB,WAAO,KAAK,QAAQ,eAAe;AAAA,EACrC;AAAA,EAEA,UAAgB;AACd,SAAK,aAAa;AAClB,UAAMC,IAAO,KAAK,QAAQ,aAAa,WAAW;AAClD,QAAI,CAACA,EAAM,OAAM,IAAI,MAAM,8CAA8C;AACzE,UAAMC,IAAK,IAAID,EAAK,KAAK,GAAG;AAC5B,WAAAC,EAAG,aAAa,eAChB,KAAK,SAASA,GACdA,EAAG,SAAS,MAAM;AAChB,WAAK,UAAU,GACf,KAAK,KAAK,EAAE,GAAG,SAAS,MAAM,KAAK,QAAQ,QAAA,GAAW,GACtD,KAAK,KAAA,GACL,KAAK,YAAY,YAAY,MAAM,KAAK,QAAQ,KAAK,QAAQ,UAAU,GAAI,GAC3E,KAAK,OAAO,KAAK,QAAQ,MAAS;AAAA,IACpC,GACAA,EAAG,YAAY,CAACC,MAAM,KAAK,QAAQA,EAAE,IAAI,GACzCD,EAAG,UAAU,CAACC,MAAM;AAClB,MAAI,KAAK,aAAW,cAAc,KAAK,SAAS,GAChD,KAAK,YAAY,MACjB,KAAK,SAAS;AACd,YAAMC,IAAY,CAAC,KAAK,cAAc,KAAK,QAAQ,cAAc;AAEjE,UADA,KAAK,OAAO,KAAK,SAAS,EAAE,MAAMD,EAAE,MAAM,QAAQA,EAAE,QAAQ,WAAAC,EAAA,CAAW,GACnEA,GAAW;AACb,cAAMC,IAAO,KAAK,IAAI,KAAK,QAAQ,gBAAgB,KAAQ,MAAM,KAAK,KAAK,SAAS;AACpF,aAAK,aAAa,WAAW,MAAM,KAAK,QAAA,GAAWA,CAAI;AAAA,MACzD;AAAA,IACF,GACO;AAAA,EACT;AAAA;AAAA,EAGA,KAAKC,GAAgE;AACnE,IAAI,KAAK,QAAQ,eAAe,KAAG,KAAK,OAAO,KAAK,KAAK,UAAUA,CAAG,CAAC;AAAA,EACzE;AAAA;AAAA,EAGA,WAAWC,GAAaC,GAAuB;AAC7C,IAAK,KAAK,UAAO,KAAK,QAAQ,EAAE,KAAAD,GAAK,OAAO,GAAC,IAC7C,KAAK,MAAM,MAAM,KAAK,CAACC,EAAK,CAAC,GAAGA,EAAK,CAAC,GAAGA,EAAK,CAAC,CAAC,CAAC;AAAA,EACnD;AAAA;AAAA,EAGA,QAAc;AACZ,IAAK,KAAK,UACV,KAAK,KAAK,EAAE,GAAG,SAAS,KAAK,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,MAAA,CAAO,GACtE,KAAK,QAAQ;AAAA,EACf;AAAA,EAEA,QAAc;AACZ,SAAK,aAAa,IACd,KAAK,cAAY,aAAa,KAAK,UAAU,GAC7C,KAAK,aAAW,cAAc,KAAK,SAAS,GAChD,KAAK,QAAQ,MAAA,GACb,KAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,OAAa;AACnB,SAAK,KAAK,EAAE,GAAG,QAAQ,GAAG,KAAK,IAAA,GAAO;AAAA,EACxC;AAAA,EAEQ,QAAQC,GAAqB;AACnC,QAAIH;AACJ,QAAI;AACF,MAAAA,IAAM,OAAOG,KAAS,WAAW,KAAK,MAAMA,CAAI,IAAKC,EAA8BD,CAAmB;AAAA,IACxG,SAASE,GAAK;AACZ,cAAQ,MAAM,kCAAkCA,CAAG;AACnD;AAAA,IACF;AACA,YAAQL,EAAI,GAAA;AAAA,MACV,KAAK,QAAQ;AACX,cAAMM,IAAIN;AACV,aAAK,MAAM,KAAK,IAAA,IAAQM,EAAE,GAC1BC,EAAeD,EAAE,IAAI,KAAK,GAAG;AAC7B;AAAA,MACF;AAAA,MACA,KAAK;AACH,aAAK,OAAO,KAAK,WAAWN,CAA+C;AAC3E;AAAA,MACF,KAAK;AACH,aAAK,OAAO,KAAK,YAAYA,CAAe;AAC5C;AAAA,MACF;AACE,aAAK,OAAO,KAAK,WAAWA,CAA0C;AAAA,IAAA;AAAA,EAE5E;AACF;"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
class x {
|
|
2
|
+
constructor(s = 100, a = 120, t = 30) {
|
|
3
|
+
this.delayMs = s, this.maxExtrapolateMs = a, this.keep = t;
|
|
4
|
+
}
|
|
5
|
+
delayMs;
|
|
6
|
+
maxExtrapolateMs;
|
|
7
|
+
keep;
|
|
8
|
+
samples = /* @__PURE__ */ new Map();
|
|
9
|
+
/** Records every body of a snapshot taken at `time`. */
|
|
10
|
+
push(s, a) {
|
|
11
|
+
for (const [t, n, o, h, m, p, c] of a) {
|
|
12
|
+
let i = this.samples.get(t);
|
|
13
|
+
i || (i = [], this.samples.set(t, i));
|
|
14
|
+
const l = i[i.length - 1];
|
|
15
|
+
l && s <= l.time || (i.push({ time: s, x: n, y: o, aim: h, anim: m, hp: p, flags: c }), i.length > this.keep && i.splice(0, i.length - this.keep));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Forgets a body (it left view). */
|
|
19
|
+
remove(s) {
|
|
20
|
+
this.samples.delete(s);
|
|
21
|
+
}
|
|
22
|
+
has(s) {
|
|
23
|
+
return this.samples.has(s);
|
|
24
|
+
}
|
|
25
|
+
ids() {
|
|
26
|
+
return this.samples.keys();
|
|
27
|
+
}
|
|
28
|
+
/** Where body `id` should be drawn at server time `now`, or null if nothing is known of it. */
|
|
29
|
+
sample(s, a) {
|
|
30
|
+
const t = this.samples.get(s);
|
|
31
|
+
if (!t || t.length === 0) return null;
|
|
32
|
+
const n = a - this.delayMs, o = t[0];
|
|
33
|
+
if (n <= o.time || t.length === 1) return g(o);
|
|
34
|
+
for (let i = t.length - 1; i > 0; i--) {
|
|
35
|
+
const l = t[i - 1], r = t[i];
|
|
36
|
+
if (n >= l.time && n <= r.time) {
|
|
37
|
+
const u = r.time === l.time ? 1 : (n - l.time) / (r.time - l.time);
|
|
38
|
+
return f(l, r, u);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const h = t[t.length - 2], m = t[t.length - 1], p = Math.min(n - m.time, this.maxExtrapolateMs), c = m.time === h.time ? 1 : 1 + p / (m.time - h.time);
|
|
42
|
+
return f(h, m, c);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function g(e) {
|
|
46
|
+
return { x: e.x, y: e.y, aim: e.aim, anim: e.anim, hp: e.hp, flags: e.flags };
|
|
47
|
+
}
|
|
48
|
+
function f(e, s, a) {
|
|
49
|
+
let t = s.aim - e.aim;
|
|
50
|
+
t > Math.PI && (t -= Math.PI * 2), t < -Math.PI && (t += Math.PI * 2);
|
|
51
|
+
const n = a < 1 ? e : s;
|
|
52
|
+
return { x: e.x + (s.x - e.x) * a, y: e.y + (s.y - e.y) * a, aim: e.aim + t * a, anim: n.anim, hp: n.hp, flags: n.flags };
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
x as InterpolationBuffer
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=InterpolationBuffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InterpolationBuffer.js","sources":["../../src/net/InterpolationBuffer.ts"],"sourcesContent":["import type { EntityUpdate } from './constants';\n\n/** One body's state at one server time. */\ninterface Sample {\n time: number;\n x: number;\n y: number;\n aim: number;\n anim: number;\n hp: number;\n flags: number;\n}\n\nexport interface InterpolatedState {\n x: number;\n y: number;\n aim: number;\n /** Discrete fields come from the older of the two samples until the newer one is reached. */\n anim: number;\n hp: number;\n flags: number;\n}\n\n/**\n * Smooth motion for bodies the server moves (other players, monsters): snapshots arrive 10–30 times a second and\n * jittered, so each body is drawn a little in the past (`delayMs`) between the two snapshots around that moment.\n * Past the newest snapshot it extrapolates for at most `maxExtrapolateMs`, then holds.\n *\n * Times are server times (`Snapshot.time`); render at `serverNow()`.\n */\nexport class InterpolationBuffer {\n private readonly samples = new Map<number, Sample[]>();\n\n constructor(\n /** How far in the past bodies are drawn (default 100 ms: two snapshots at 20 Hz, so one may be late). */\n readonly delayMs = 100,\n private readonly maxExtrapolateMs = 120,\n private readonly keep = 30,\n ) {}\n\n /** Records every body of a snapshot taken at `time`. */\n push(time: number, updates: readonly EntityUpdate[]): void {\n for (const [id, x, y, aim, anim, hp, flags] of updates) {\n let list = this.samples.get(id);\n if (!list) {\n list = [];\n this.samples.set(id, list);\n }\n const last = list[list.length - 1];\n // out of order or repeated: a newer sample is already here\n if (last && time <= last.time) continue;\n list.push({ time, x, y, aim, anim, hp, flags });\n if (list.length > this.keep) list.splice(0, list.length - this.keep);\n }\n }\n\n /** Forgets a body (it left view). */\n remove(id: number): void {\n this.samples.delete(id);\n }\n\n has(id: number): boolean {\n return this.samples.has(id);\n }\n\n ids(): IterableIterator<number> {\n return this.samples.keys();\n }\n\n /** Where body `id` should be drawn at server time `now`, or null if nothing is known of it. */\n sample(id: number, now: number): InterpolatedState | null {\n const list = this.samples.get(id);\n if (!list || list.length === 0) return null;\n const t = now - this.delayMs;\n const first = list[0]!;\n if (t <= first.time || list.length === 1) return pick(first);\n for (let i = list.length - 1; i > 0; i--) {\n const a = list[i - 1]!;\n const b = list[i]!;\n if (t >= a.time && t <= b.time) {\n const k = b.time === a.time ? 1 : (t - a.time) / (b.time - a.time);\n return blend(a, b, k);\n }\n }\n // newer than every sample: carry on along the last motion, for a short while only\n const a = list[list.length - 2]!;\n const b = list[list.length - 1]!;\n const over = Math.min(t - b.time, this.maxExtrapolateMs);\n const k = b.time === a.time ? 1 : 1 + over / (b.time - a.time);\n return blend(a, b, k);\n }\n}\n\nfunction pick(s: Sample): InterpolatedState {\n return { x: s.x, y: s.y, aim: s.aim, anim: s.anim, hp: s.hp, flags: s.flags };\n}\n\nfunction blend(a: Sample, b: Sample, k: number): InterpolatedState {\n let d = b.aim - a.aim;\n if (d > Math.PI) d -= Math.PI * 2;\n if (d < -Math.PI) d += Math.PI * 2;\n const older = k < 1 ? a : b;\n return { x: a.x + (b.x - a.x) * k, y: a.y + (b.y - a.y) * k, aim: a.aim + d * k, anim: older.anim, hp: older.hp, flags: older.flags };\n}\n"],"names":["InterpolationBuffer","delayMs","maxExtrapolateMs","keep","time","updates","id","x","y","aim","anim","hp","flags","list","last","now","t","first","pick","a","b","k","blend","over","s","d","older"],"mappings":"AA8BO,MAAMA,EAAoB;AAAA,EAG/B,YAEWC,IAAU,KACFC,IAAmB,KACnBC,IAAO,IACxB;AAHS,SAAA,UAAAF,GACQ,KAAA,mBAAAC,GACA,KAAA,OAAAC;AAAA,EAChB;AAAA,EAHQ;AAAA,EACQ;AAAA,EACA;AAAA,EANF,8BAAc,IAAA;AAAA;AAAA,EAU/B,KAAKC,GAAcC,GAAwC;AACzD,eAAW,CAACC,GAAIC,GAAGC,GAAGC,GAAKC,GAAMC,GAAIC,CAAK,KAAKP,GAAS;AACtD,UAAIQ,IAAO,KAAK,QAAQ,IAAIP,CAAE;AAC9B,MAAKO,MACHA,IAAO,CAAA,GACP,KAAK,QAAQ,IAAIP,GAAIO,CAAI;AAE3B,YAAMC,IAAOD,EAAKA,EAAK,SAAS,CAAC;AAEjC,MAAIC,KAAQV,KAAQU,EAAK,SACzBD,EAAK,KAAK,EAAE,MAAAT,GAAM,GAAAG,GAAG,GAAAC,GAAG,KAAAC,GAAK,MAAAC,GAAM,IAAAC,GAAI,OAAAC,GAAO,GAC1CC,EAAK,SAAS,KAAK,QAAMA,EAAK,OAAO,GAAGA,EAAK,SAAS,KAAK,IAAI;AAAA,IACrE;AAAA,EACF;AAAA;AAAA,EAGA,OAAOP,GAAkB;AACvB,SAAK,QAAQ,OAAOA,CAAE;AAAA,EACxB;AAAA,EAEA,IAAIA,GAAqB;AACvB,WAAO,KAAK,QAAQ,IAAIA,CAAE;AAAA,EAC5B;AAAA,EAEA,MAAgC;AAC9B,WAAO,KAAK,QAAQ,KAAA;AAAA,EACtB;AAAA;AAAA,EAGA,OAAOA,GAAYS,GAAuC;AACxD,UAAMF,IAAO,KAAK,QAAQ,IAAIP,CAAE;AAChC,QAAI,CAACO,KAAQA,EAAK,WAAW,EAAG,QAAO;AACvC,UAAMG,IAAID,IAAM,KAAK,SACfE,IAAQJ,EAAK,CAAC;AACpB,QAAIG,KAAKC,EAAM,QAAQJ,EAAK,WAAW,EAAG,QAAOK,EAAKD,CAAK;AAC3D,aAAS,IAAIJ,EAAK,SAAS,GAAG,IAAI,GAAG,KAAK;AACxC,YAAMM,IAAIN,EAAK,IAAI,CAAC,GACdO,IAAIP,EAAK,CAAC;AAChB,UAAIG,KAAKG,EAAE,QAAQH,KAAKI,EAAE,MAAM;AAC9B,cAAMC,IAAID,EAAE,SAASD,EAAE,OAAO,KAAKH,IAAIG,EAAE,SAASC,EAAE,OAAOD,EAAE;AAC7D,eAAOG,EAAMH,GAAGC,GAAGC,CAAC;AAAA,MACtB;AAAA,IACF;AAEA,UAAMF,IAAIN,EAAKA,EAAK,SAAS,CAAC,GACxBO,IAAIP,EAAKA,EAAK,SAAS,CAAC,GACxBU,IAAO,KAAK,IAAIP,IAAII,EAAE,MAAM,KAAK,gBAAgB,GACjDC,IAAID,EAAE,SAASD,EAAE,OAAO,IAAI,IAAII,KAAQH,EAAE,OAAOD,EAAE;AACzD,WAAOG,EAAMH,GAAGC,GAAGC,CAAC;AAAA,EACtB;AACF;AAEA,SAASH,EAAKM,GAA8B;AAC1C,SAAO,EAAE,GAAGA,EAAE,GAAG,GAAGA,EAAE,GAAG,KAAKA,EAAE,KAAK,MAAMA,EAAE,MAAM,IAAIA,EAAE,IAAI,OAAOA,EAAE,MAAA;AACxE;AAEA,SAASF,EAAMH,GAAWC,GAAWC,GAA8B;AACjE,MAAII,IAAIL,EAAE,MAAMD,EAAE;AAClB,EAAIM,IAAI,KAAK,OAAIA,KAAK,KAAK,KAAK,IAC5BA,IAAI,CAAC,KAAK,OAAIA,KAAK,KAAK,KAAK;AACjC,QAAMC,IAAQL,IAAI,IAAIF,IAAIC;AAC1B,SAAO,EAAE,GAAGD,EAAE,KAAKC,EAAE,IAAID,EAAE,KAAKE,GAAG,GAAGF,EAAE,KAAKC,EAAE,IAAID,EAAE,KAAKE,GAAG,KAAKF,EAAE,MAAMM,IAAIJ,GAAG,MAAMK,EAAM,MAAM,IAAIA,EAAM,IAAI,OAAOA,EAAM,MAAA;AAChI;"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createMover as c, stepMover as n } from "./movement.js";
|
|
2
|
+
import { moverFromWire as m } from "./protocol.js";
|
|
3
|
+
class g {
|
|
4
|
+
constructor(t, s, i, o) {
|
|
5
|
+
this.params = i, this.grid = o, this.mover = c(t, s);
|
|
6
|
+
}
|
|
7
|
+
params;
|
|
8
|
+
grid;
|
|
9
|
+
mover;
|
|
10
|
+
pending = [];
|
|
11
|
+
nextSeq = 0;
|
|
12
|
+
/** The jump the last reconciliation made, still being eased out (world px). */
|
|
13
|
+
offsetX = 0;
|
|
14
|
+
offsetY = 0;
|
|
15
|
+
/** How big the last correction was (0 when the prediction was right). */
|
|
16
|
+
correction = 0;
|
|
17
|
+
/** Share of a visual correction left after each 60th of a second (default 0.8). */
|
|
18
|
+
smoothing = 0.8;
|
|
19
|
+
/** Applies one input step now and keeps it for replay; returns its sequence number (send it with the step). */
|
|
20
|
+
step(t) {
|
|
21
|
+
const s = this.nextSeq++;
|
|
22
|
+
return this.pending.push({ seq: s, step: [t[0], t[1], t[2]] }), n(this.mover, t, this.params, this.grid), s;
|
|
23
|
+
}
|
|
24
|
+
/** Steps sent but not yet acknowledged. */
|
|
25
|
+
get unacknowledged() {
|
|
26
|
+
return this.pending.length;
|
|
27
|
+
}
|
|
28
|
+
/** The server's word: the body as of step `ack`. Rewinds there and replays the rest. */
|
|
29
|
+
reconcile(t, s) {
|
|
30
|
+
const i = this.mover.x, o = this.mover.y;
|
|
31
|
+
let e = 0;
|
|
32
|
+
for (; e < this.pending.length && this.pending[e].seq <= t; ) e++;
|
|
33
|
+
e && (this.pending = this.pending.slice(e)), m(s, this.mover);
|
|
34
|
+
for (const f of this.pending) n(this.mover, f.step, this.params, this.grid);
|
|
35
|
+
const r = i - this.mover.x, h = o - this.mover.y;
|
|
36
|
+
this.correction = Math.hypot(r, h), this.correction > 0.01 && this.correction < 64 ? (this.offsetX += r, this.offsetY += h) : this.correction >= 64 && (this.offsetX = this.offsetY = 0);
|
|
37
|
+
}
|
|
38
|
+
/** Eases the visual correction out; call once a frame with its length in seconds. */
|
|
39
|
+
smooth(t) {
|
|
40
|
+
const s = Math.pow(this.smoothing, t * 60);
|
|
41
|
+
this.offsetX *= s, this.offsetY *= s, Math.abs(this.offsetX) < 0.01 && (this.offsetX = 0), Math.abs(this.offsetY) < 0.01 && (this.offsetY = 0);
|
|
42
|
+
}
|
|
43
|
+
/** Where to draw the body: the predicted place plus the correction still being eased out. */
|
|
44
|
+
get drawX() {
|
|
45
|
+
return this.mover.x + this.offsetX;
|
|
46
|
+
}
|
|
47
|
+
get drawY() {
|
|
48
|
+
return this.mover.y + this.offsetY;
|
|
49
|
+
}
|
|
50
|
+
/** New movement rules (a buff, a slow): applied to future steps and to replays. */
|
|
51
|
+
setParams(t) {
|
|
52
|
+
this.params = t;
|
|
53
|
+
}
|
|
54
|
+
setGrid(t) {
|
|
55
|
+
this.grid = t;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
g as PredictedMover
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=PredictedMover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PredictedMover.js","sources":["../../src/net/PredictedMover.ts"],"sourcesContent":["import type { InputStep, MovementParams } from './constants';\nimport { createMover, stepMover, type CollisionGrid, type MoverState } from './movement';\nimport { moverFromWire, type MoverWire } from './protocol';\n\n/**\n * Client-side prediction for the local player's body. Every input step is applied at once (the player sees their\n * own move with no lag) and kept until the server acknowledges it. When a snapshot says where the server has the\n * body as of step `ack`, the body is put there and every step after `ack` is replayed on top.\n *\n * Movement is deterministic (`stepMover`), so with the same steps, params and grid the replay lands exactly where\n * the prediction was and nothing moves. When it does not (the server refused a step, a collision only it knew of),\n * the difference is `correction`: draw the body at `drawX/drawY`, which ease that jump out over a few frames instead\n * of snapping.\n */\nexport class PredictedMover {\n readonly mover: MoverState;\n private pending: { seq: number; step: InputStep }[] = [];\n private nextSeq = 0;\n /** The jump the last reconciliation made, still being eased out (world px). */\n private offsetX = 0;\n private offsetY = 0;\n /** How big the last correction was (0 when the prediction was right). */\n correction = 0;\n /** Share of a visual correction left after each 60th of a second (default 0.8). */\n smoothing = 0.8;\n\n constructor(\n x: number,\n y: number,\n private params: MovementParams,\n private grid: CollisionGrid,\n ) {\n this.mover = createMover(x, y);\n }\n\n /** Applies one input step now and keeps it for replay; returns its sequence number (send it with the step). */\n step(step: InputStep): number {\n const seq = this.nextSeq++;\n this.pending.push({ seq, step: [step[0], step[1], step[2]] });\n stepMover(this.mover, step, this.params, this.grid);\n return seq;\n }\n\n /** Steps sent but not yet acknowledged. */\n get unacknowledged(): number {\n return this.pending.length;\n }\n\n /** The server's word: the body as of step `ack`. Rewinds there and replays the rest. */\n reconcile(ack: number, server: MoverWire): void {\n const beforeX = this.mover.x;\n const beforeY = this.mover.y;\n let drop = 0;\n while (drop < this.pending.length && this.pending[drop]!.seq <= ack) drop++;\n if (drop) this.pending = this.pending.slice(drop);\n moverFromWire(server, this.mover);\n for (const p of this.pending) stepMover(this.mover, p.step, this.params, this.grid);\n const dx = beforeX - this.mover.x;\n const dy = beforeY - this.mover.y;\n this.correction = Math.hypot(dx, dy);\n // a correction this small is float noise; one this large is a teleport, shown at once\n if (this.correction > 0.01 && this.correction < 64) {\n this.offsetX += dx;\n this.offsetY += dy;\n } else if (this.correction >= 64) {\n this.offsetX = this.offsetY = 0;\n }\n }\n\n /** Eases the visual correction out; call once a frame with its length in seconds. */\n smooth(dt: number): void {\n const k = Math.pow(this.smoothing, dt * 60);\n this.offsetX *= k;\n this.offsetY *= k;\n if (Math.abs(this.offsetX) < 0.01) this.offsetX = 0;\n if (Math.abs(this.offsetY) < 0.01) this.offsetY = 0;\n }\n\n /** Where to draw the body: the predicted place plus the correction still being eased out. */\n get drawX(): number {\n return this.mover.x + this.offsetX;\n }\n\n get drawY(): number {\n return this.mover.y + this.offsetY;\n }\n\n /** New movement rules (a buff, a slow): applied to future steps and to replays. */\n setParams(params: MovementParams): void {\n this.params = params;\n }\n\n setGrid(grid: CollisionGrid): void {\n this.grid = grid;\n }\n}\n"],"names":["PredictedMover","x","y","params","grid","createMover","step","seq","stepMover","ack","server","beforeX","beforeY","drop","moverFromWire","p","dx","dy","dt","k"],"mappings":";;AAcO,MAAMA,EAAe;AAAA,EAY1B,YACEC,GACAC,GACQC,GACAC,GACR;AAFQ,SAAA,SAAAD,GACA,KAAA,OAAAC,GAER,KAAK,QAAQC,EAAYJ,GAAGC,CAAC;AAAA,EAC/B;AAAA,EAJU;AAAA,EACA;AAAA,EAfD;AAAA,EACD,UAA8C,CAAA;AAAA,EAC9C,UAAU;AAAA;AAAA,EAEV,UAAU;AAAA,EACV,UAAU;AAAA;AAAA,EAElB,aAAa;AAAA;AAAA,EAEb,YAAY;AAAA;AAAA,EAYZ,KAAKI,GAAyB;AAC5B,UAAMC,IAAM,KAAK;AACjB,gBAAK,QAAQ,KAAK,EAAE,KAAAA,GAAK,MAAM,CAACD,EAAK,CAAC,GAAGA,EAAK,CAAC,GAAGA,EAAK,CAAC,CAAC,GAAG,GAC5DE,EAAU,KAAK,OAAOF,GAAM,KAAK,QAAQ,KAAK,IAAI,GAC3CC;AAAA,EACT;AAAA;AAAA,EAGA,IAAI,iBAAyB;AAC3B,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA,EAGA,UAAUE,GAAaC,GAAyB;AAC9C,UAAMC,IAAU,KAAK,MAAM,GACrBC,IAAU,KAAK,MAAM;AAC3B,QAAIC,IAAO;AACX,WAAOA,IAAO,KAAK,QAAQ,UAAU,KAAK,QAAQA,CAAI,EAAG,OAAOJ,IAAK,CAAAI;AACrE,IAAIA,MAAM,KAAK,UAAU,KAAK,QAAQ,MAAMA,CAAI,IAChDC,EAAcJ,GAAQ,KAAK,KAAK;AAChC,eAAWK,KAAK,KAAK,QAAS,CAAAP,EAAU,KAAK,OAAOO,EAAE,MAAM,KAAK,QAAQ,KAAK,IAAI;AAClF,UAAMC,IAAKL,IAAU,KAAK,MAAM,GAC1BM,IAAKL,IAAU,KAAK,MAAM;AAChC,SAAK,aAAa,KAAK,MAAMI,GAAIC,CAAE,GAE/B,KAAK,aAAa,QAAQ,KAAK,aAAa,MAC9C,KAAK,WAAWD,GAChB,KAAK,WAAWC,KACP,KAAK,cAAc,OAC5B,KAAK,UAAU,KAAK,UAAU;AAAA,EAElC;AAAA;AAAA,EAGA,OAAOC,GAAkB;AACvB,UAAMC,IAAI,KAAK,IAAI,KAAK,WAAWD,IAAK,EAAE;AAC1C,SAAK,WAAWC,GAChB,KAAK,WAAWA,GACZ,KAAK,IAAI,KAAK,OAAO,IAAI,cAAW,UAAU,IAC9C,KAAK,IAAI,KAAK,OAAO,IAAI,cAAW,UAAU;AAAA,EACpD;AAAA;AAAA,EAGA,IAAI,QAAgB;AAClB,WAAO,KAAK,MAAM,IAAI,KAAK;AAAA,EAC7B;AAAA,EAEA,IAAI,QAAgB;AAClB,WAAO,KAAK,MAAM,IAAI,KAAK;AAAA,EAC7B;AAAA;AAAA,EAGA,UAAUhB,GAA8B;AACtC,SAAK,SAASA;AAAA,EAChB;AAAA,EAEA,QAAQC,GAA2B;AACjC,SAAK,OAAOA;AAAA,EACd;AACF;"}
|
package/dist/net/Room.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { createMover as l, stepMover as p } from "./movement.js";
|
|
2
|
+
import { moverToWire as c } from "./protocol.js";
|
|
3
|
+
class g {
|
|
4
|
+
constructor(e) {
|
|
5
|
+
this.options = e, this.maxQueue = e.maxQueue ?? 30, this.maxSteps = e.maxStepsPerTick ?? 3, this.backlog = e.backlog ?? 4;
|
|
6
|
+
}
|
|
7
|
+
options;
|
|
8
|
+
players = /* @__PURE__ */ new Map();
|
|
9
|
+
tick = 0;
|
|
10
|
+
known = /* @__PURE__ */ new Map();
|
|
11
|
+
maxQueue;
|
|
12
|
+
maxSteps;
|
|
13
|
+
backlog;
|
|
14
|
+
join(e, i) {
|
|
15
|
+
if (this.players.has(e)) throw new Error(`Room: player ${e} has already joined`);
|
|
16
|
+
const r = this.options.spawn(e, i), t = {
|
|
17
|
+
id: e,
|
|
18
|
+
mover: l(r.x, r.y),
|
|
19
|
+
data: i,
|
|
20
|
+
params: { ...this.options.params },
|
|
21
|
+
ack: -1,
|
|
22
|
+
queue: [],
|
|
23
|
+
aim: 0,
|
|
24
|
+
anim: 0,
|
|
25
|
+
hp: 0,
|
|
26
|
+
flags: 0,
|
|
27
|
+
strikes: 0
|
|
28
|
+
};
|
|
29
|
+
return this.players.set(e, t), this.known.set(e, /* @__PURE__ */ new Set()), t;
|
|
30
|
+
}
|
|
31
|
+
leave(e) {
|
|
32
|
+
this.players.delete(e), this.known.delete(e);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Input steps `seq`, `seq + 1`, … from a player. Steps already received are skipped (a resend), any step with
|
|
36
|
+
* numbers no client sends refuses the whole message, and steps past a full queue are dropped. Returns false when
|
|
37
|
+
* something was refused.
|
|
38
|
+
*/
|
|
39
|
+
input(e, i, r) {
|
|
40
|
+
const t = this.players.get(e);
|
|
41
|
+
if (!t) return !1;
|
|
42
|
+
if (!Number.isInteger(i) || i < 0 || !Array.isArray(r) || r.length > this.maxQueue)
|
|
43
|
+
return t.strikes++, !1;
|
|
44
|
+
for (const s of r)
|
|
45
|
+
if (!Array.isArray(s) || s.length !== 3 || !s.every((u) => Number.isFinite(u)) || Math.abs(s[0]) > 1 || Math.abs(s[1]) > 1 || !Number.isInteger(s[2]))
|
|
46
|
+
return t.strikes++, !1;
|
|
47
|
+
const n = t.ack + 1 + t.queue.length, o = i - n;
|
|
48
|
+
if (o > this.maxQueue)
|
|
49
|
+
return t.strikes++, !1;
|
|
50
|
+
for (let s = 0; s < o; s++) t.queue.push([0, 0, 0]);
|
|
51
|
+
let h = !0;
|
|
52
|
+
for (let s = 0; s < r.length; s++)
|
|
53
|
+
if (!(i + s < n)) {
|
|
54
|
+
if (t.queue.length >= this.maxQueue) {
|
|
55
|
+
h = !1, t.strikes++;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
t.queue.push([r[s][0], r[s][1], r[s][2]]);
|
|
59
|
+
}
|
|
60
|
+
return h;
|
|
61
|
+
}
|
|
62
|
+
/** One simulation step for everyone. */
|
|
63
|
+
step() {
|
|
64
|
+
this.tick++;
|
|
65
|
+
for (const e of this.players.values()) {
|
|
66
|
+
const i = e.queue.length;
|
|
67
|
+
if (i === 0) continue;
|
|
68
|
+
const r = i > this.backlog ? Math.min(this.maxSteps, i - this.backlog + 1) : 1;
|
|
69
|
+
for (let t = 0; t < r; t++) {
|
|
70
|
+
const n = e.queue.shift();
|
|
71
|
+
p(e.mover, n, e.params, this.options.grid), e.ack++, this.options.onStep?.(e, n);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** The snapshot player `id` should get now. `time` is the server's wall clock (ms). */
|
|
76
|
+
snapshotFor(e, i) {
|
|
77
|
+
const r = this.players.get(e), t = this.known.get(e);
|
|
78
|
+
if (!r || !t) return null;
|
|
79
|
+
const n = [], o = [], h = /* @__PURE__ */ new Set();
|
|
80
|
+
for (const a of this.players.values())
|
|
81
|
+
h.add(a.id), n.push([a.id, a.mover.x, a.mover.y, a.aim, a.anim, a.hp, a.flags]), t.has(a.id) || (t.add(a.id), o.push({ id: a.id, data: a.data }));
|
|
82
|
+
const s = [];
|
|
83
|
+
for (const a of t)
|
|
84
|
+
h.has(a) || (t.delete(a), s.push(a));
|
|
85
|
+
const u = { t: "snap", tick: this.tick, time: i, ack: r.ack, me: c(r.mover), up: n };
|
|
86
|
+
return o.length && (u.sp = o), s.length && (u.rm = s), u;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
g as Room
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=Room.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Room.js","sources":["../../src/net/Room.ts"],"sourcesContent":["import type { EntityUpdate, InputStep, MovementParams } from './constants';\nimport { createMover, stepMover, type CollisionGrid, type MoverState } from './movement';\nimport { moverToWire, type Snapshot } from './protocol';\n\nexport interface RoomPlayer<D = unknown> {\n readonly id: number;\n readonly mover: MoverState;\n /** The game's own data for this player (sent to others in `sp` when they first see it). */\n data: D;\n params: MovementParams;\n /** The last input step applied (-1 before any): what snapshots acknowledge. */\n ack: number;\n /** Steps received and not yet applied. */\n readonly queue: InputStep[];\n /** What the snapshot's update record carries beside the position; the game sets them. */\n aim: number;\n anim: number;\n hp: number;\n flags: number;\n /** Refused inputs (nonsense numbers, a flood): a game may kick past some count. */\n strikes: number;\n}\n\nexport interface RoomOptions<D> {\n grid: CollisionGrid;\n /** Movement rules a new player starts with. */\n params: MovementParams;\n /** Where a player who joins stands. */\n spawn: (id: number, data: D) => { x: number; y: number };\n /** Steps a player may have waiting before more are refused (default 30: half a second at 60). */\n maxQueue?: number;\n /** A player with more than `backlog` waiting catches up by running up to `maxStepsPerTick` a tick (default 3, 4). */\n maxStepsPerTick?: number;\n backlog?: number;\n /** Called after each step a player takes (set aim, anim, flags from it). */\n onStep?: (player: RoomPlayer<D>, step: InputStep) => void;\n}\n\n/**\n * An authoritative room for a server: players send input steps, the room applies them with the same `stepMover` the\n * clients predict with, and builds each player a snapshot of everyone (with their own body whole, so their\n * prediction can rewind to it). Transport-free: wire `input`, `step` and `snapshotFor` to any socket library.\n *\n * Every step a player sends is applied once, in order; a client cannot move faster by sending more (the queue is\n * capped and drained at most `maxStepsPerTick` a tick), and nonsense input is refused and counted.\n */\nexport class Room<D = unknown> {\n readonly players = new Map<number, RoomPlayer<D>>();\n tick = 0;\n private readonly known = new Map<number, Set<number>>();\n private readonly maxQueue: number;\n private readonly maxSteps: number;\n private readonly backlog: number;\n\n constructor(private readonly options: RoomOptions<D>) {\n this.maxQueue = options.maxQueue ?? 30;\n this.maxSteps = options.maxStepsPerTick ?? 3;\n this.backlog = options.backlog ?? 4;\n }\n\n join(id: number, data: D): RoomPlayer<D> {\n if (this.players.has(id)) throw new Error(`Room: player ${id} has already joined`);\n const at = this.options.spawn(id, data);\n const player: RoomPlayer<D> = {\n id,\n mover: createMover(at.x, at.y),\n data,\n params: { ...this.options.params },\n ack: -1,\n queue: [],\n aim: 0,\n anim: 0,\n hp: 0,\n flags: 0,\n strikes: 0,\n };\n this.players.set(id, player);\n this.known.set(id, new Set());\n return player;\n }\n\n leave(id: number): void {\n this.players.delete(id);\n this.known.delete(id);\n }\n\n /**\n * Input steps `seq`, `seq + 1`, … from a player. Steps already received are skipped (a resend), any step with\n * numbers no client sends refuses the whole message, and steps past a full queue are dropped. Returns false when\n * something was refused.\n */\n input(id: number, seq: number, steps: readonly InputStep[]): boolean {\n const p = this.players.get(id);\n if (!p) return false;\n if (!Number.isInteger(seq) || seq < 0 || !Array.isArray(steps) || steps.length > this.maxQueue) {\n p.strikes++;\n return false;\n }\n for (const s of steps) {\n if (!Array.isArray(s) || s.length !== 3 || !s.every((v) => Number.isFinite(v)) || Math.abs(s[0]) > 1 || Math.abs(s[1]) > 1 || !Number.isInteger(s[2])) {\n p.strikes++;\n return false;\n }\n }\n const next = p.ack + 1 + p.queue.length;\n // a gap (steps this room refused earlier) is filled with standing still, so sequence numbers stay the client's\n const gap = seq - next;\n if (gap > this.maxQueue) {\n p.strikes++;\n return false;\n }\n for (let i = 0; i < gap; i++) p.queue.push([0, 0, 0]);\n let ok = true;\n for (let i = 0; i < steps.length; i++) {\n if (seq + i < next) continue; // already have it: a resend\n if (p.queue.length >= this.maxQueue) {\n ok = false;\n p.strikes++;\n break;\n }\n p.queue.push([steps[i]![0], steps[i]![1], steps[i]![2]]);\n }\n return ok;\n }\n\n /** One simulation step for everyone. */\n step(): void {\n this.tick++;\n for (const p of this.players.values()) {\n const waiting = p.queue.length;\n if (waiting === 0) continue;\n const n = waiting > this.backlog ? Math.min(this.maxSteps, waiting - this.backlog + 1) : 1;\n for (let i = 0; i < n; i++) {\n const s = p.queue.shift()!;\n stepMover(p.mover, s, p.params, this.options.grid);\n p.ack++;\n this.options.onStep?.(p, s);\n }\n }\n }\n\n /** The snapshot player `id` should get now. `time` is the server's wall clock (ms). */\n snapshotFor(id: number, time: number): Snapshot | null {\n const me = this.players.get(id);\n const known = this.known.get(id);\n if (!me || !known) return null;\n const up: EntityUpdate[] = [];\n const sp: { id: number; data?: unknown }[] = [];\n const seen = new Set<number>();\n for (const p of this.players.values()) {\n seen.add(p.id);\n up.push([p.id, p.mover.x, p.mover.y, p.aim, p.anim, p.hp, p.flags]);\n if (!known.has(p.id)) {\n known.add(p.id);\n sp.push({ id: p.id, data: p.data });\n }\n }\n const rm: number[] = [];\n for (const k of known) {\n if (!seen.has(k)) {\n known.delete(k);\n rm.push(k);\n }\n }\n const snap: Snapshot = { t: 'snap', tick: this.tick, time, ack: me.ack, me: moverToWire(me.mover), up };\n if (sp.length) snap.sp = sp;\n if (rm.length) snap.rm = rm;\n return snap;\n }\n}\n"],"names":["Room","options","id","data","at","player","createMover","seq","steps","p","v","next","gap","i","ok","waiting","n","s","stepMover","time","me","known","up","sp","seen","rm","k","snap","moverToWire"],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { encodeSnapshotFrame as n } from "./snapshotCodec.js";
|
|
2
|
+
class p {
|
|
3
|
+
constructor(t, s = {}) {
|
|
4
|
+
this.room = t, this.options = s, this.stepMs = 1e3 / (s.stepRate ?? 60), this.snapEvery = Math.max(1, Math.round((s.stepRate ?? 60) / (s.snapRate ?? 20))), this.now = s.now ?? Date.now;
|
|
5
|
+
}
|
|
6
|
+
room;
|
|
7
|
+
options;
|
|
8
|
+
sockets = /* @__PURE__ */ new Map();
|
|
9
|
+
joined = /* @__PURE__ */ new Set();
|
|
10
|
+
nextId = 1;
|
|
11
|
+
stepTimer = null;
|
|
12
|
+
lastStepAt = 0;
|
|
13
|
+
stepsDue = 0;
|
|
14
|
+
stepMs;
|
|
15
|
+
snapEvery;
|
|
16
|
+
now;
|
|
17
|
+
/** A socket connected; returns the id its messages and its close are reported under. */
|
|
18
|
+
connect(t) {
|
|
19
|
+
const s = this.nextId++;
|
|
20
|
+
return this.sockets.set(s, t), s;
|
|
21
|
+
}
|
|
22
|
+
/** A message arrived from socket `id` (text as a string, binary as bytes). */
|
|
23
|
+
message(t, s) {
|
|
24
|
+
if (typeof s != "string") return;
|
|
25
|
+
let e;
|
|
26
|
+
try {
|
|
27
|
+
e = JSON.parse(s);
|
|
28
|
+
} catch {
|
|
29
|
+
return this.strike(t);
|
|
30
|
+
}
|
|
31
|
+
if (!e || typeof e != "object" || typeof e.t != "string") return this.strike(t);
|
|
32
|
+
switch (e.t) {
|
|
33
|
+
case "hello": {
|
|
34
|
+
if (this.joined.has(t)) return;
|
|
35
|
+
let i;
|
|
36
|
+
try {
|
|
37
|
+
i = this.options.admit ? this.options.admit(e.data, t) : e.data;
|
|
38
|
+
} catch (o) {
|
|
39
|
+
this.sockets.get(t)?.close(4003, o instanceof Error ? o.message : "refused");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this.room.join(t, i), this.joined.add(t), this.sendTo(t, { t: "welcome", id: t, tick: this.room.tick, stepRate: 1e3 / this.stepMs, snapRate: 1e3 / this.stepMs / this.snapEvery }), this.options.onJoin?.(t);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
case "input": {
|
|
46
|
+
const i = e;
|
|
47
|
+
if (!this.joined.has(t)) return;
|
|
48
|
+
this.room.input(t, i.seq, i.steps) || this.checkStrikes(t);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
case "ping": {
|
|
52
|
+
const i = e.c;
|
|
53
|
+
typeof i == "number" && Number.isFinite(i) && this.sendTo(t, { t: "pong", c: i, st: this.now() });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
default:
|
|
57
|
+
this.joined.has(t) && this.options.onMessage?.(t, e);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Socket `id` closed. */
|
|
61
|
+
disconnect(t) {
|
|
62
|
+
this.sockets.delete(t), this.joined.delete(t) && (this.room.leave(t), this.options.onLeave?.(t));
|
|
63
|
+
}
|
|
64
|
+
/** Sends one of the game's own messages to a player. */
|
|
65
|
+
sendTo(t, s) {
|
|
66
|
+
const e = this.sockets.get(t);
|
|
67
|
+
e && (s.t === "snap" && s.up?.length ? e.send(n(s)) : e.send(JSON.stringify(s)));
|
|
68
|
+
}
|
|
69
|
+
/** Starts stepping on a timer. Steps are counted by the clock, so a late timer runs the steps it owes. */
|
|
70
|
+
start() {
|
|
71
|
+
this.stepTimer || (this.lastStepAt = this.now(), this.stepTimer = setInterval(() => {
|
|
72
|
+
const t = this.now();
|
|
73
|
+
for (this.stepsDue += (t - this.lastStepAt) / this.stepMs, this.lastStepAt = t, this.stepsDue = Math.min(this.stepsDue, 60); this.stepsDue >= 1; )
|
|
74
|
+
this.stepsDue--, this.stepOnce();
|
|
75
|
+
}, this.stepMs / 2));
|
|
76
|
+
}
|
|
77
|
+
stop() {
|
|
78
|
+
this.stepTimer && clearInterval(this.stepTimer), this.stepTimer = null;
|
|
79
|
+
}
|
|
80
|
+
/** One step, and the snapshots when they are due. Exposed for tests and for servers that drive their own loop. */
|
|
81
|
+
stepOnce() {
|
|
82
|
+
if (this.room.step(), this.room.tick % this.snapEvery !== 0) return;
|
|
83
|
+
const t = this.now();
|
|
84
|
+
for (const s of this.joined) {
|
|
85
|
+
const e = this.room.snapshotFor(s, t);
|
|
86
|
+
e && this.sendTo(s, e);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
strike(t) {
|
|
90
|
+
const s = this.room.players.get(t);
|
|
91
|
+
s && (s.strikes++, this.checkStrikes(t));
|
|
92
|
+
}
|
|
93
|
+
checkStrikes(t) {
|
|
94
|
+
const s = this.room.players.get(t);
|
|
95
|
+
s && s.strikes >= (this.options.maxStrikes ?? 20) && (this.sockets.get(t)?.close(4008, "too much invalid input"), this.disconnect(t));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export {
|
|
99
|
+
p as RoomHost
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=RoomHost.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RoomHost.js","sources":["../../src/net/RoomHost.ts"],"sourcesContent":["import type { Room } from './Room';\nimport { encodeSnapshotFrame } from './snapshotCodec';\nimport type { ClientMessage, ServerMessage, Snapshot } from './protocol';\n\n/** The least a server socket must do; a `ws` WebSocket, a uWebSockets one or a test double all fit. */\nexport interface HostSocket {\n send(data: string | Uint8Array): void;\n close(code?: number, reason?: string): void;\n}\n\nexport interface RoomHostOptions<D> {\n /** Simulation steps a second (default 60) and snapshots a second (default 20). */\n stepRate?: number;\n snapRate?: number;\n /** Turns a hello's data into the player's data (validate it here); throw to refuse the player. */\n admit?: (data: unknown, id: number) => D;\n /** Refused inputs before the player is disconnected (default 20). */\n maxStrikes?: number;\n /** The game's own messages (anything the engine does not handle). */\n onMessage?: (id: number, msg: { t: string; [k: string]: unknown }) => void;\n /** Called when a player joins or leaves. */\n onJoin?: (id: number) => void;\n onLeave?: (id: number) => void;\n /** Wall clock, for tests (default Date.now). */\n now?: () => number;\n}\n\n/**\n * Runs a `Room` for connected sockets: a socket says hello and joins, its input goes to the room, the room steps at\n * `stepRate`, and every player gets its own snapshot at `snapRate` (binary when it carries bodies). Pings are\n * answered with the server's time. A player who keeps sending nonsense is disconnected.\n *\n * ```ts\n * const host = new RoomHost(room);\n * wss.on('connection', (ws) => {\n * const id = host.connect(ws);\n * ws.on('message', (data, binary) => host.message(id, binary ? data : data.toString()));\n * ws.on('close', () => host.disconnect(id));\n * });\n * host.start();\n * ```\n */\nexport class RoomHost<D = unknown> {\n private readonly sockets = new Map<number, HostSocket>();\n private readonly joined = new Set<number>();\n private nextId = 1;\n private stepTimer: ReturnType<typeof setInterval> | null = null;\n private lastStepAt = 0;\n private stepsDue = 0;\n private readonly stepMs: number;\n private readonly snapEvery: number;\n private readonly now: () => number;\n\n constructor(\n readonly room: Room<D>,\n private readonly options: RoomHostOptions<D> = {},\n ) {\n this.stepMs = 1000 / (options.stepRate ?? 60);\n this.snapEvery = Math.max(1, Math.round((options.stepRate ?? 60) / (options.snapRate ?? 20)));\n this.now = options.now ?? Date.now;\n }\n\n /** A socket connected; returns the id its messages and its close are reported under. */\n connect(socket: HostSocket): number {\n const id = this.nextId++;\n this.sockets.set(id, socket);\n return id;\n }\n\n /** A message arrived from socket `id` (text as a string, binary as bytes). */\n message(id: number, data: string | ArrayBuffer | Uint8Array): void {\n if (typeof data !== 'string') return; // clients send JSON only\n let msg: ClientMessage | { t: string; [k: string]: unknown };\n try {\n msg = JSON.parse(data);\n } catch {\n return this.strike(id);\n }\n if (!msg || typeof msg !== 'object' || typeof msg.t !== 'string') return this.strike(id);\n switch (msg.t) {\n case 'hello': {\n if (this.joined.has(id)) return;\n let data: D;\n try {\n data = this.options.admit ? this.options.admit((msg as { data?: unknown }).data, id) : ((msg as { data?: unknown }).data as D);\n } catch (err) {\n this.sockets.get(id)?.close(4003, err instanceof Error ? err.message : 'refused');\n return;\n }\n this.room.join(id, data);\n this.joined.add(id);\n this.sendTo(id, { t: 'welcome', id, tick: this.room.tick, stepRate: 1000 / this.stepMs, snapRate: (1000 / this.stepMs) / this.snapEvery });\n this.options.onJoin?.(id);\n return;\n }\n case 'input': {\n const m = msg as Extract<ClientMessage, { t: 'input' }>;\n if (!this.joined.has(id)) return;\n if (!this.room.input(id, m.seq, m.steps)) this.checkStrikes(id);\n return;\n }\n case 'ping': {\n const c = (msg as { c?: unknown }).c;\n if (typeof c === 'number' && Number.isFinite(c)) this.sendTo(id, { t: 'pong', c, st: this.now() });\n return;\n }\n default:\n if (this.joined.has(id)) this.options.onMessage?.(id, msg as { t: string; [k: string]: unknown });\n }\n }\n\n /** Socket `id` closed. */\n disconnect(id: number): void {\n this.sockets.delete(id);\n if (this.joined.delete(id)) {\n this.room.leave(id);\n this.options.onLeave?.(id);\n }\n }\n\n /** Sends one of the game's own messages to a player. */\n sendTo(id: number, msg: ServerMessage | { t: string; [k: string]: unknown }): void {\n const s = this.sockets.get(id);\n if (!s) return;\n if ((msg as Snapshot).t === 'snap' && (msg as Snapshot).up?.length) s.send(encodeSnapshotFrame(msg as Snapshot));\n else s.send(JSON.stringify(msg));\n }\n\n /** Starts stepping on a timer. Steps are counted by the clock, so a late timer runs the steps it owes. */\n start(): void {\n if (this.stepTimer) return;\n this.lastStepAt = this.now();\n this.stepTimer = setInterval(() => {\n const now = this.now();\n this.stepsDue += (now - this.lastStepAt) / this.stepMs;\n this.lastStepAt = now;\n // a stall longer than a second is not caught up: the room just carries on\n this.stepsDue = Math.min(this.stepsDue, 60);\n while (this.stepsDue >= 1) {\n this.stepsDue--;\n this.stepOnce();\n }\n }, this.stepMs / 2);\n }\n\n stop(): void {\n if (this.stepTimer) clearInterval(this.stepTimer);\n this.stepTimer = null;\n }\n\n /** One step, and the snapshots when they are due. Exposed for tests and for servers that drive their own loop. */\n stepOnce(): void {\n this.room.step();\n if (this.room.tick % this.snapEvery !== 0) return;\n const now = this.now();\n for (const id of this.joined) {\n const snap = this.room.snapshotFor(id, now);\n if (snap) this.sendTo(id, snap);\n }\n }\n\n private strike(id: number): void {\n const p = this.room.players.get(id);\n if (p) {\n p.strikes++;\n this.checkStrikes(id);\n }\n }\n\n private checkStrikes(id: number): void {\n const p = this.room.players.get(id);\n if (p && p.strikes >= (this.options.maxStrikes ?? 20)) {\n this.sockets.get(id)?.close(4008, 'too much invalid input');\n this.disconnect(id);\n }\n }\n}\n"],"names":["RoomHost","room","options","socket","id","data","msg","err","m","c","s","encodeSnapshotFrame","now","snap","p"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const n = {
|
|
2
|
+
/** A basic attack may arrive this share of its interval early. */
|
|
3
|
+
attackEarlyShare: 0.2,
|
|
4
|
+
/** The cast lock and the attack lock a cast leaves may be cut this short. */
|
|
5
|
+
lockSlackMs: 60,
|
|
6
|
+
/** A skill may be cast this long before its cooldown ends. */
|
|
7
|
+
cooldownSlackMs: 40,
|
|
8
|
+
/** A potion may be drunk this long before its kind's cooldown ends. */
|
|
9
|
+
potionSlackMs: 150
|
|
10
|
+
};
|
|
11
|
+
function o(c, a, t) {
|
|
12
|
+
return a !== void 0 && c < a - t;
|
|
13
|
+
}
|
|
14
|
+
function e(c, a, t) {
|
|
15
|
+
return Math.max(c, a ?? c) + t;
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
n as CADENCE,
|
|
19
|
+
o as cadenceEarly,
|
|
20
|
+
e as cadenceNext
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=cadence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cadence.js","sources":["../../src/net/cadence.ts"],"sourcesContent":["/**\n * Every repeated player action with a timer — the basic attack, a skill's cooldown, the cast and attack locks, a\n * potion — runs on a **schedule**, not on \"the last time plus some slack\". An action may arrive up to its slack\n * early (network jitter bunches packets), but the next one is then due a whole interval after the later of the\n * arrival and the time this one was due, so the slack never adds up: a client sending every 0.8 of an interval\n * lands at most one per interval (67 in 100), not 100. A server must run the same arithmetic.\n */\nexport const CADENCE = {\n /** A basic attack may arrive this share of its interval early. */\n attackEarlyShare: 0.2,\n /** The cast lock and the attack lock a cast leaves may be cut this short. */\n lockSlackMs: 60,\n /** A skill may be cast this long before its cooldown ends. */\n cooldownSlackMs: 40,\n /** A potion may be drunk this long before its kind's cooldown ends. */\n potionSlackMs: 150,\n} as const;\n\n/** Whether an action arriving at `now` is earlier than its slack allows; `due` undefined = never taken, due at once. */\nexport function cadenceEarly(now: number, due: number | undefined, slack: number): boolean {\n return due !== undefined && now < due - slack;\n}\n\n/** When the action after one accepted at `now` is due: a whole interval after the later of `now` and `due`. */\nexport function cadenceNext(now: number, due: number | undefined, interval: number): number {\n return Math.max(now, due ?? now) + interval;\n}\n"],"names":["CADENCE","cadenceEarly","now","due","slack","cadenceNext","interval"],"mappings":"AAOO,MAAMA,IAAU;AAAA;AAAA,EAErB,kBAAkB;AAAA;AAAA,EAElB,aAAa;AAAA;AAAA,EAEb,iBAAiB;AAAA;AAAA,EAEjB,eAAe;AACjB;AAGO,SAASC,EAAaC,GAAaC,GAAyBC,GAAwB;AACzF,SAAOD,MAAQ,UAAaD,IAAMC,IAAMC;AAC1C;AAGO,SAASC,EAAYH,GAAaC,GAAyBG,GAA0B;AAC1F,SAAO,KAAK,IAAIJ,GAAKC,KAAOD,CAAG,IAAII;AACrC;"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const _ = 16, T = 60, I = 0.016666666666666666, E = 1, o = 5, t = 3, P = 0.01;
|
|
2
|
+
export {
|
|
3
|
+
t as BODY_HALF_HEIGHT,
|
|
4
|
+
o as BODY_HALF_WIDTH,
|
|
5
|
+
P as COLLISION_EPSILON,
|
|
6
|
+
E as INPUT_FLAG_DASH,
|
|
7
|
+
I as INPUT_STEP_DT,
|
|
8
|
+
T as INPUT_STEP_RATE,
|
|
9
|
+
_ as TILE_SIZE
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sources":["../../src/net/constants.ts"],"sourcesContent":["/** World and movement constants. A game that needs other numbers forks these; client and server must agree. */\n\nexport const TILE_SIZE = 16;\n\n/** Fixed input steps a second; movement is simulated per step on both sides. */\nexport const INPUT_STEP_RATE = 60;\nexport const INPUT_STEP_DT = 1 / INPUT_STEP_RATE;\n\n/** Bit of an input step's flags that asks for a dodge roll. */\nexport const INPUT_FLAG_DASH = 1;\n\n/** The body's collision box, half extents (px). */\nexport const BODY_HALF_WIDTH = 5;\nexport const BODY_HALF_HEIGHT = 3;\nexport const COLLISION_EPSILON = 0.01;\n\n/** One fixed input step: [axisX, axisY, flags]. */\nexport type InputStep = [number, number, number];\n\nexport interface MovementParams {\n speed: number;\n dashSpeed: number;\n dashSteps: number;\n dashCooldownSteps: number;\n canMove: boolean;\n canDash: boolean;\n}\n\n/** One body's state in a snapshot: [id, x, y, aim, anim, hp, flags]. */\nexport type EntityUpdate = [number, number, number, number, number, number, number];\n"],"names":["TILE_SIZE","INPUT_STEP_RATE","INPUT_STEP_DT","INPUT_FLAG_DASH","BODY_HALF_WIDTH","BODY_HALF_HEIGHT","COLLISION_EPSILON"],"mappings":"AAEO,MAAMA,IAAY,IAGZC,IAAkB,IAClBC,IAAgB,sBAGhBC,IAAkB,GAGlBC,IAAkB,GAClBC,IAAmB,GACnBC,IAAoB;"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { EventBus as s } from "../../events/EventBus.js";
|
|
2
|
+
class o {
|
|
3
|
+
constructor(e) {
|
|
4
|
+
this.link = e, this.off = e.events.on("message", (t) => this.receive(t));
|
|
5
|
+
}
|
|
6
|
+
link;
|
|
7
|
+
events = new s();
|
|
8
|
+
/** Your id in the lobby (-1 until welcomed). */
|
|
9
|
+
id = -1;
|
|
10
|
+
modes = [];
|
|
11
|
+
rooms = [];
|
|
12
|
+
room = null;
|
|
13
|
+
/** Your queue: the mode, since when (server ms) and how many other groups wait for it. */
|
|
14
|
+
queued = null;
|
|
15
|
+
/** Kept out of the queue until then (server ms), after a declined match. */
|
|
16
|
+
lockedUntil = 0;
|
|
17
|
+
match = null;
|
|
18
|
+
off;
|
|
19
|
+
get isHost() {
|
|
20
|
+
return this.room !== null && this.room.host === this.id;
|
|
21
|
+
}
|
|
22
|
+
/** Every member of your room but the host has said ready. */
|
|
23
|
+
get roomReady() {
|
|
24
|
+
return this.room !== null && this.room.members.every((e) => e.ready);
|
|
25
|
+
}
|
|
26
|
+
list() {
|
|
27
|
+
this.send({ t: "lobby/list" });
|
|
28
|
+
}
|
|
29
|
+
create(e = {}) {
|
|
30
|
+
this.send({ t: "lobby/create", ...e });
|
|
31
|
+
}
|
|
32
|
+
join(e) {
|
|
33
|
+
this.send({ t: "lobby/join", room: e });
|
|
34
|
+
}
|
|
35
|
+
joinByCode(e) {
|
|
36
|
+
this.send({ t: "lobby/join", code: e.trim().toUpperCase() });
|
|
37
|
+
}
|
|
38
|
+
leave() {
|
|
39
|
+
this.send({ t: "lobby/leave" });
|
|
40
|
+
}
|
|
41
|
+
setReady(e) {
|
|
42
|
+
this.send({ t: "lobby/ready", ready: e });
|
|
43
|
+
}
|
|
44
|
+
kick(e) {
|
|
45
|
+
this.send({ t: "lobby/kick", player: e });
|
|
46
|
+
}
|
|
47
|
+
promote(e) {
|
|
48
|
+
this.send({ t: "lobby/promote", player: e });
|
|
49
|
+
}
|
|
50
|
+
setSettings(e) {
|
|
51
|
+
this.send({ t: "lobby/settings", settings: e });
|
|
52
|
+
}
|
|
53
|
+
chat(e) {
|
|
54
|
+
this.send({ t: "lobby/chat", text: e });
|
|
55
|
+
}
|
|
56
|
+
startRoom() {
|
|
57
|
+
this.send({ t: "lobby/start" });
|
|
58
|
+
}
|
|
59
|
+
queue(e) {
|
|
60
|
+
this.send({ t: "queue/join", mode: e });
|
|
61
|
+
}
|
|
62
|
+
leaveQueue() {
|
|
63
|
+
this.send({ t: "queue/leave" });
|
|
64
|
+
}
|
|
65
|
+
accept() {
|
|
66
|
+
this.match && (this.match.answered = !0), this.send({ t: "match/accept" }), this.events.emit("change", void 0);
|
|
67
|
+
}
|
|
68
|
+
decline() {
|
|
69
|
+
this.match && (this.match.answered = !0), this.send({ t: "match/decline" });
|
|
70
|
+
}
|
|
71
|
+
destroy() {
|
|
72
|
+
this.off(), this.events.clear();
|
|
73
|
+
}
|
|
74
|
+
send(e) {
|
|
75
|
+
this.link.send(e);
|
|
76
|
+
}
|
|
77
|
+
receive(e) {
|
|
78
|
+
switch (e.t) {
|
|
79
|
+
case "lobby/welcome":
|
|
80
|
+
this.id = e.id, this.modes = e.modes;
|
|
81
|
+
break;
|
|
82
|
+
case "lobby/rooms":
|
|
83
|
+
this.rooms = e.rooms;
|
|
84
|
+
break;
|
|
85
|
+
case "lobby/room":
|
|
86
|
+
this.room = e.room;
|
|
87
|
+
break;
|
|
88
|
+
case "lobby/chat":
|
|
89
|
+
this.events.emit("chat", { from: e.from, text: e.text });
|
|
90
|
+
return;
|
|
91
|
+
case "lobby/kicked":
|
|
92
|
+
this.room = null, this.events.emit("kicked", void 0);
|
|
93
|
+
break;
|
|
94
|
+
case "lobby/error":
|
|
95
|
+
this.events.emit("error", { code: e.code, message: e.message });
|
|
96
|
+
return;
|
|
97
|
+
case "queue/status":
|
|
98
|
+
this.queued = e.mode ? { mode: e.mode, since: e.since, waiting: e.waiting } : null;
|
|
99
|
+
break;
|
|
100
|
+
case "queue/locked":
|
|
101
|
+
this.lockedUntil = e.until;
|
|
102
|
+
break;
|
|
103
|
+
case "match/found":
|
|
104
|
+
this.queued = null, this.match = { id: e.match, mode: e.mode, players: e.players, expiresAt: e.expiresAt, accepted: [], answered: !1 }, this.events.emit("found", this.match);
|
|
105
|
+
break;
|
|
106
|
+
case "match/accepted":
|
|
107
|
+
this.match?.id === e.match && (this.match.accepted = e.accepted);
|
|
108
|
+
break;
|
|
109
|
+
case "match/cancelled":
|
|
110
|
+
this.match?.id === e.match && (this.match = null), this.events.emit("cancelled", { match: e.match, reason: e.reason, requeued: e.requeued });
|
|
111
|
+
break;
|
|
112
|
+
case "match/start":
|
|
113
|
+
this.match = null, this.queued = null, this.events.emit("start", { match: e.match, mode: e.mode, players: e.players, data: e.data });
|
|
114
|
+
break;
|
|
115
|
+
default:
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
this.events.emit("change", void 0);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
export {
|
|
122
|
+
o as LobbyClient
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=LobbyClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LobbyClient.js","sources":["../../../src/net/lobby/LobbyClient.ts"],"sourcesContent":["import { EventBus } from '../../events/EventBus';\nimport type { LobbyClientMessage, LobbyErrorCode, LobbyServerMessage, MatchPlayer, RoomState, RoomSummary } from './lobbyProtocol';\n\n/** What a `LobbyClient` sends through and hears from: a `Connection` fits. */\nexport interface LobbyLink {\n send(msg: { t: string; [k: string]: unknown }): void;\n readonly events: { on(event: 'message', fn: (msg: { t: string; [k: string]: unknown }) => void): () => void };\n}\n\nexport interface PendingMatch {\n id: string;\n mode: string;\n players: MatchPlayer[];\n expiresAt: number;\n accepted: number[];\n /** You answered already. */\n answered: boolean;\n}\n\nexport interface LobbyClientEvents {\n /** Anything in the client's state changed: redraw the lobby screen. */\n change: undefined;\n chat: { from: number; text: string };\n error: { code: LobbyErrorCode; message: string };\n kicked: undefined;\n found: PendingMatch;\n cancelled: { match: string; reason: 'declined' | 'timeout' | 'left'; requeued: boolean };\n /** Go and play: `data` is what the server's `onStart` gave you. */\n start: { match: string; mode: string; players: MatchPlayer[]; data: unknown };\n}\n\n/**\n * The lobby as a client sees it: the room list, your room, your place in the queue and a match waiting for your\n * answer, kept up to date from the server's messages, with a method for everything a lobby screen does. Hand it the\n * game's `Connection` (or anything that sends JSON and emits the messages it does not handle):\n *\n * ```ts\n * const conn = new Connection('wss://lobby.example.com', { hello: () => ({ name }) }).connect();\n * const lobby = new LobbyClient(conn);\n * lobby.events.on('change', () => drawLobby(lobby));\n * lobby.events.on('start', ({ data }) => joinGame(data));\n * lobby.queue('duel');\n * ```\n */\nexport class LobbyClient {\n readonly events = new EventBus<LobbyClientEvents>();\n /** Your id in the lobby (-1 until welcomed). */\n id = -1;\n modes: string[] = [];\n rooms: RoomSummary[] = [];\n room: RoomState | null = null;\n /** Your queue: the mode, since when (server ms) and how many other groups wait for it. */\n queued: { mode: string; since: number; waiting: number } | null = null;\n /** Kept out of the queue until then (server ms), after a declined match. */\n lockedUntil = 0;\n match: PendingMatch | null = null;\n private readonly off: () => void;\n\n constructor(private readonly link: LobbyLink) {\n this.off = link.events.on('message', (msg) => this.receive(msg as LobbyServerMessage));\n }\n\n get isHost(): boolean {\n return this.room !== null && this.room.host === this.id;\n }\n\n /** Every member of your room but the host has said ready. */\n get roomReady(): boolean {\n return this.room !== null && this.room.members.every((m) => m.ready);\n }\n\n list(): void {\n this.send({ t: 'lobby/list' });\n }\n create(options: Omit<Extract<LobbyClientMessage, { t: 'lobby/create' }>, 't'> = {}): void {\n this.send({ t: 'lobby/create', ...options });\n }\n join(room: string): void {\n this.send({ t: 'lobby/join', room });\n }\n joinByCode(code: string): void {\n this.send({ t: 'lobby/join', code: code.trim().toUpperCase() });\n }\n leave(): void {\n this.send({ t: 'lobby/leave' });\n }\n setReady(ready: boolean): void {\n this.send({ t: 'lobby/ready', ready });\n }\n kick(player: number): void {\n this.send({ t: 'lobby/kick', player });\n }\n promote(player: number): void {\n this.send({ t: 'lobby/promote', player });\n }\n setSettings(settings: unknown): void {\n this.send({ t: 'lobby/settings', settings });\n }\n chat(text: string): void {\n this.send({ t: 'lobby/chat', text });\n }\n startRoom(): void {\n this.send({ t: 'lobby/start' });\n }\n queue(mode: string): void {\n this.send({ t: 'queue/join', mode });\n }\n leaveQueue(): void {\n this.send({ t: 'queue/leave' });\n }\n accept(): void {\n if (this.match) this.match.answered = true;\n this.send({ t: 'match/accept' });\n this.events.emit('change', undefined);\n }\n decline(): void {\n if (this.match) this.match.answered = true;\n this.send({ t: 'match/decline' });\n }\n\n destroy(): void {\n this.off();\n this.events.clear();\n }\n\n private send(msg: LobbyClientMessage): void {\n this.link.send(msg as unknown as { t: string; [k: string]: unknown });\n }\n\n private receive(msg: LobbyServerMessage): void {\n switch (msg.t) {\n case 'lobby/welcome':\n this.id = msg.id;\n this.modes = msg.modes;\n break;\n case 'lobby/rooms':\n this.rooms = msg.rooms;\n break;\n case 'lobby/room':\n this.room = msg.room;\n break;\n case 'lobby/chat':\n this.events.emit('chat', { from: msg.from, text: msg.text });\n return;\n case 'lobby/kicked':\n this.room = null;\n this.events.emit('kicked', undefined);\n break;\n case 'lobby/error':\n this.events.emit('error', { code: msg.code, message: msg.message });\n return;\n case 'queue/status':\n this.queued = msg.mode ? { mode: msg.mode, since: msg.since, waiting: msg.waiting } : null;\n break;\n case 'queue/locked':\n this.lockedUntil = msg.until;\n break;\n case 'match/found':\n this.queued = null;\n this.match = { id: msg.match, mode: msg.mode, players: msg.players, expiresAt: msg.expiresAt, accepted: [], answered: false };\n this.events.emit('found', this.match);\n break;\n case 'match/accepted':\n if (this.match?.id === msg.match) this.match.accepted = msg.accepted;\n break;\n case 'match/cancelled':\n if (this.match?.id === msg.match) this.match = null;\n this.events.emit('cancelled', { match: msg.match, reason: msg.reason, requeued: msg.requeued });\n break;\n case 'match/start':\n this.match = null;\n this.queued = null;\n this.events.emit('start', { match: msg.match, mode: msg.mode, players: msg.players, data: msg.data });\n break;\n default:\n return;\n }\n this.events.emit('change', undefined);\n }\n}\n"],"names":["LobbyClient","link","msg","EventBus","m","options","room","code","ready","player","settings","text","mode"],"mappings":"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"}
|