@jgengine/core 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -2
- package/LICENSE +203 -661
- package/README.md +1 -1
- package/dist/ai/crowd.d.ts +55 -0
- package/dist/ai/crowd.js +114 -0
- package/dist/ai/flock.d.ts +5 -2
- package/dist/ai/flock.js +5 -2
- package/dist/ai/groupAssist.d.ts +1 -0
- package/dist/ai/groupAssist.js +1 -0
- package/dist/ai/heatSystem.d.ts +76 -0
- package/dist/ai/heatSystem.js +97 -0
- package/dist/ai/interestScheduler.d.ts +107 -0
- package/dist/ai/interestScheduler.js +118 -0
- package/dist/ai/jobBoard.d.ts +1 -0
- package/dist/ai/jobBoard.js +1 -0
- package/dist/ai/laneSelect.d.ts +5 -2
- package/dist/ai/laneSelect.js +5 -2
- package/dist/ai/mobBrain.d.ts +1 -0
- package/dist/ai/mobBrain.js +1 -0
- package/dist/ai/spawnDirector.d.ts +7 -2
- package/dist/ai/spawnDirector.js +18 -15
- package/dist/ai/spawnPoint.d.ts +3 -1
- package/dist/ai/spawnPoint.js +3 -1
- package/dist/ai/targetAcquisition.d.ts +84 -0
- package/dist/ai/targetAcquisition.js +92 -0
- package/dist/anim/easing.d.ts +19 -0
- package/dist/anim/easing.js +19 -0
- package/dist/anim/oscillator.d.ts +12 -0
- package/dist/anim/oscillator.js +25 -0
- package/dist/area/areaEffectField.d.ts +127 -0
- package/dist/area/areaEffectField.js +175 -0
- package/dist/area/stackPolicy.d.ts +47 -0
- package/dist/area/stackPolicy.js +99 -0
- package/dist/authoring.d.ts +1 -0
- package/dist/authoring.js +1 -0
- package/dist/board/laneBoard.d.ts +13 -0
- package/dist/board/laneBoard.js +13 -0
- package/dist/board/timelineBoard.d.ts +10 -0
- package/dist/board/timelineBoard.js +10 -0
- package/dist/combat/abilityKit.d.ts +18 -0
- package/dist/combat/abilityKit.js +24 -9
- package/dist/combat/animationState.d.ts +5 -0
- package/dist/combat/animationState.js +5 -0
- package/dist/combat/breakMeters.d.ts +10 -0
- package/dist/combat/breakMeters.js +10 -0
- package/dist/combat/castRunner.d.ts +5 -0
- package/dist/combat/castRunner.js +5 -0
- package/dist/combat/comboPoints.d.ts +5 -0
- package/dist/combat/comboPoints.js +5 -0
- package/dist/combat/comboString.d.ts +5 -0
- package/dist/combat/comboString.js +5 -0
- package/dist/combat/damageInterceptors.d.ts +192 -0
- package/dist/combat/damageInterceptors.js +251 -0
- package/dist/combat/damageMatchup.d.ts +68 -0
- package/dist/combat/damageMatchup.js +42 -0
- package/dist/combat/damageResolution.d.ts +63 -0
- package/dist/combat/damageResolution.js +50 -0
- package/dist/combat/death.d.ts +7 -1
- package/dist/combat/death.js +5 -0
- package/dist/combat/deathReason.d.ts +14 -0
- package/dist/combat/deathReason.js +1 -0
- package/dist/combat/defensiveWindow.d.ts +5 -0
- package/dist/combat/defensiveWindow.js +5 -0
- package/dist/combat/dotField.d.ts +5 -1
- package/dist/combat/dotField.js +5 -1
- package/dist/combat/downed.d.ts +5 -0
- package/dist/combat/downed.js +5 -0
- package/dist/combat/effects.d.ts +5 -0
- package/dist/combat/effects.js +5 -0
- package/dist/combat/encounterSequence.d.ts +258 -0
- package/dist/combat/encounterSequence.js +426 -0
- package/dist/combat/hitReaction.d.ts +57 -1
- package/dist/combat/hitReaction.js +45 -5
- package/dist/combat/magazine.d.ts +54 -0
- package/dist/combat/magazine.js +96 -0
- package/dist/combat/projectiles.d.ts +5 -0
- package/dist/combat/projectiles.js +32 -14
- package/dist/combat/receivedDamage.d.ts +117 -0
- package/dist/combat/receivedDamage.js +92 -0
- package/dist/combat/regenShield.d.ts +5 -1
- package/dist/combat/regenShield.js +5 -1
- package/dist/combat/renderCues.d.ts +51 -0
- package/dist/combat/renderCues.js +44 -0
- package/dist/combat/resourcePool.d.ts +5 -0
- package/dist/combat/resourcePool.js +5 -0
- package/dist/combat/rewardAllocation.d.ts +121 -0
- package/dist/combat/rewardAllocation.js +251 -0
- package/dist/combat/shotOrigin.d.ts +18 -1
- package/dist/combat/shotOrigin.js +39 -0
- package/dist/combat/statusApplication.d.ts +96 -0
- package/dist/combat/statusApplication.js +81 -0
- package/dist/combat/telegraph.d.ts +11 -2
- package/dist/combat/telegraph.js +11 -2
- package/dist/combat/thresholdCrossings.d.ts +85 -0
- package/dist/combat/thresholdCrossings.js +116 -0
- package/dist/combat.d.ts +34 -0
- package/dist/combat.js +34 -0
- package/dist/commands/commandRegistry.d.ts +11 -0
- package/dist/commands/commandRegistry.js +9 -2
- package/dist/crafting/crop.d.ts +18 -0
- package/dist/crafting/crop.js +18 -0
- package/dist/crafting/production.d.ts +5 -0
- package/dist/crafting/production.js +5 -0
- package/dist/devtools/rewriteTunables.d.ts +17 -0
- package/dist/devtools/rewriteTunables.js +276 -0
- package/dist/devtools/saveEndpoint.d.ts +46 -0
- package/dist/devtools/saveEndpoint.js +48 -0
- package/dist/devtools/transformTunables.d.ts +3 -0
- package/dist/devtools/transformTunables.js +3 -0
- package/dist/devtools/tunableSchema.d.ts +31 -0
- package/dist/devtools/tunableSchema.js +31 -0
- package/dist/economy/currency.d.ts +12 -1
- package/dist/economy/currency.js +12 -1
- package/dist/economy/listingBook.d.ts +91 -0
- package/dist/economy/listingBook.js +144 -0
- package/dist/economy/resourceLedger.d.ts +222 -0
- package/dist/economy/resourceLedger.js +353 -0
- package/dist/economy/sharedWallet.d.ts +14 -0
- package/dist/economy/sharedWallet.js +14 -0
- package/dist/economy/techTree.d.ts +12 -0
- package/dist/economy/techTree.js +12 -0
- package/dist/economy/wallet.d.ts +26 -2
- package/dist/economy/wallet.js +35 -6
- package/dist/editor/commands.d.ts +190 -7
- package/dist/editor/commands.js +727 -55
- package/dist/editor/document.d.ts +159 -13
- package/dist/editor/document.js +750 -19
- package/dist/editor/grid.d.ts +229 -0
- package/dist/editor/grid.js +366 -0
- package/dist/editor/gridAdapters.d.ts +80 -0
- package/dist/editor/gridAdapters.js +134 -0
- package/dist/editor/index.d.ts +73 -6
- package/dist/editor/index.js +6 -2
- package/dist/editor/liveSync.d.ts +127 -0
- package/dist/editor/liveSync.js +249 -0
- package/dist/editor/runtimeInspector.d.ts +88 -0
- package/dist/editor/runtimeInspector.js +239 -0
- package/dist/editor/types.d.ts +107 -1
- package/dist/faction/reputation.d.ts +5 -0
- package/dist/faction/reputation.js +5 -0
- package/dist/format/distance.d.ts +17 -0
- package/dist/format/distance.js +18 -0
- package/dist/format/duration.d.ts +27 -0
- package/dist/format/duration.js +45 -0
- package/dist/format/speed.d.ts +17 -0
- package/dist/format/speed.js +25 -0
- package/dist/game/connectedPlayers.d.ts +6 -4
- package/dist/game/connectedPlayers.js +2 -2
- package/dist/game/cosmetics.d.ts +9 -0
- package/dist/game/cosmetics.js +16 -0
- package/dist/game/defineGame.d.ts +100 -2
- package/dist/game/defineGame.js +39 -2
- package/dist/game/defineSystem.d.ts +88 -0
- package/dist/game/defineSystem.js +45 -0
- package/dist/game/dialogue.d.ts +33 -0
- package/dist/game/dialogue.js +21 -0
- package/dist/game/events.d.ts +35 -13
- package/dist/game/events.js +5 -0
- package/dist/game/feed.d.ts +33 -0
- package/dist/game/feed.js +35 -2
- package/dist/game/gamePhase.d.ts +11 -0
- package/dist/game/gamePhase.js +16 -0
- package/dist/game/leaderboard.d.ts +5 -0
- package/dist/game/leaderboard.js +5 -0
- package/dist/game/loadout.d.ts +5 -0
- package/dist/game/loadout.js +5 -0
- package/dist/game/lootFilter.d.ts +2 -0
- package/dist/game/lootFilter.js +2 -0
- package/dist/game/lootPipeline.d.ts +164 -0
- package/dist/game/lootPipeline.js +216 -0
- package/dist/game/lootTable.d.ts +19 -2
- package/dist/game/lootTable.js +15 -5
- package/dist/game/objectives.d.ts +43 -0
- package/dist/game/objectives.js +36 -0
- package/dist/game/paramLayers.d.ts +148 -0
- package/dist/game/paramLayers.js +185 -0
- package/dist/game/ping.d.ts +5 -0
- package/dist/game/ping.js +5 -0
- package/dist/game/playableGame.d.ts +92 -7
- package/dist/game/quest.d.ts +8 -0
- package/dist/game/quest.js +29 -0
- package/dist/game/race.d.ts +141 -0
- package/dist/game/race.js +169 -0
- package/dist/game/recordBook.d.ts +3 -1
- package/dist/game/recordBook.js +4 -1
- package/dist/game/ruleSelection.d.ts +75 -0
- package/dist/game/ruleSelection.js +127 -0
- package/dist/game/runDraft.d.ts +5 -0
- package/dist/game/runDraft.js +5 -0
- package/dist/game/saveStore.d.ts +111 -0
- package/dist/game/saveStore.js +312 -0
- package/dist/game/snapshotHistory.d.ts +67 -0
- package/dist/game/snapshotHistory.js +95 -0
- package/dist/game/social.d.ts +38 -1
- package/dist/game/social.js +71 -0
- package/dist/game/spawnPoints.d.ts +5 -0
- package/dist/game/spawnPoints.js +5 -0
- package/dist/game/systemRuntime.d.ts +50 -0
- package/dist/game/systemRuntime.js +157 -0
- package/dist/game/systemSchedule.d.ts +72 -0
- package/dist/game/systemSchedule.js +242 -0
- package/dist/game/toasts.d.ts +43 -0
- package/dist/game/toasts.js +44 -0
- package/dist/game/trade.d.ts +10 -0
- package/dist/game/trade.js +10 -0
- package/dist/game/unlocks.d.ts +8 -0
- package/dist/game/unlocks.js +16 -0
- package/dist/game/vfxInstance.d.ts +138 -0
- package/dist/game/vfxInstance.js +96 -0
- package/dist/game/worldItem.d.ts +17 -4
- package/dist/game/worldItem.js +17 -4
- package/dist/gameplay.d.ts +91 -0
- package/dist/gameplay.js +91 -0
- package/dist/index.d.ts +5 -14
- package/dist/index.js +5 -14
- package/dist/input/actionBindings.d.ts +23 -6
- package/dist/input/actionBindings.js +23 -6
- package/dist/input/axisInput.d.ts +7 -2
- package/dist/input/axisInput.js +7 -2
- package/dist/input/controlGroups.d.ts +67 -0
- package/dist/input/controlGroups.js +41 -0
- package/dist/input/touchScheme.d.ts +82 -6
- package/dist/input/touchScheme.js +123 -10
- package/dist/interaction/lockpick.d.ts +61 -0
- package/dist/interaction/lockpick.js +168 -0
- package/dist/interaction/proximityPrompt.d.ts +2 -0
- package/dist/interaction/proximityPrompt.js +2 -0
- package/dist/interaction/qte.d.ts +5 -0
- package/dist/interaction/qte.js +5 -0
- package/dist/interaction/skillCheck.d.ts +5 -0
- package/dist/interaction/skillCheck.js +5 -0
- package/dist/inventory/inventoryModel.d.ts +12 -0
- package/dist/inventory/inventoryModel.js +12 -0
- package/dist/inventory/shapedGrid.d.ts +16 -0
- package/dist/inventory/shapedGrid.js +16 -0
- package/dist/inventory/slotModel.d.ts +10 -0
- package/dist/inventory/slotModel.js +10 -0
- package/dist/item/durability.d.ts +5 -0
- package/dist/item/durability.js +5 -0
- package/dist/item/itemIdentity.d.ts +171 -0
- package/dist/item/itemIdentity.js +138 -0
- package/dist/item/itemInstanceRegistry.d.ts +32 -0
- package/dist/item/itemInstanceRegistry.js +34 -0
- package/dist/item/itemgen.d.ts +163 -0
- package/dist/item/itemgen.js +151 -0
- package/dist/item/modularItem.d.ts +5 -0
- package/dist/item/modularItem.js +5 -0
- package/dist/item/use.d.ts +5 -0
- package/dist/item/use.js +5 -0
- package/dist/item/useBehavior.d.ts +142 -0
- package/dist/item/useBehavior.js +105 -0
- package/dist/item/weapon.d.ts +5 -0
- package/dist/item/weapon.js +5 -0
- package/dist/math/scalar.d.ts +25 -0
- package/dist/math/scalar.js +47 -0
- package/dist/meta/changelog.d.ts +4 -1
- package/dist/meta/changelog.js +16 -2
- package/dist/movement/avoidance.d.ts +45 -0
- package/dist/movement/avoidance.js +123 -0
- package/dist/movement/cameraRig.d.ts +8 -0
- package/dist/movement/cameraRig.js +8 -0
- package/dist/movement/dash.d.ts +11 -0
- package/dist/movement/dash.js +11 -0
- package/dist/movement/formation.d.ts +135 -0
- package/dist/movement/formation.js +194 -0
- package/dist/movement/glideModel.d.ts +5 -0
- package/dist/movement/glideModel.js +5 -0
- package/dist/movement/grappleSwing.d.ts +5 -0
- package/dist/movement/grappleSwing.js +5 -0
- package/dist/movement/leaderTrail.d.ts +5 -0
- package/dist/movement/leaderTrail.js +5 -0
- package/dist/movement/movementModel.d.ts +35 -8
- package/dist/movement/movementModel.js +42 -14
- package/dist/movement/playerMovement.js +65 -10
- package/dist/movement/poseState.d.ts +13 -0
- package/dist/movement/poseState.js +16 -0
- package/dist/movement/steering.d.ts +8 -0
- package/dist/movement/steering.js +18 -0
- package/dist/multiplayer/combatSnapshot.d.ts +3 -0
- package/dist/multiplayer/combatSnapshot.js +3 -0
- package/dist/multiplayer/lagCompensation.d.ts +5 -0
- package/dist/multiplayer/lagCompensation.js +5 -0
- package/dist/multiplayer/presenceModel.d.ts +9 -1
- package/dist/multiplayer/presenceModel.js +9 -1
- package/dist/multiplayer/simultaneousCommit.d.ts +3 -0
- package/dist/multiplayer/simultaneousCommit.js +3 -0
- package/dist/multiplayer.d.ts +11 -0
- package/dist/multiplayer.js +11 -0
- package/dist/nav/pathFollow.d.ts +57 -0
- package/dist/nav/pathFollow.js +109 -0
- package/dist/orders/orderKinds.d.ts +156 -0
- package/dist/orders/orderKinds.js +197 -0
- package/dist/orders/orderQueue.d.ts +208 -0
- package/dist/orders/orderQueue.js +211 -0
- package/dist/physics/drivableVehicle.d.ts +29 -0
- package/dist/physics/drivableVehicle.js +16 -0
- package/dist/physics/kinematicVehicle.d.ts +21 -1
- package/dist/physics/kinematicVehicle.js +23 -8
- package/dist/physics/physicsWorld.d.ts +24 -12
- package/dist/physics/physicsWorld.js +11 -5
- package/dist/physics/radialImpulse.d.ts +25 -0
- package/dist/physics/radialImpulse.js +27 -0
- package/dist/procedural.d.ts +3 -0
- package/dist/procedural.js +3 -0
- package/dist/progression/statGraph.d.ts +116 -0
- package/dist/progression/statGraph.js +318 -0
- package/dist/puzzle/cellGrid.d.ts +9 -0
- package/dist/puzzle/cellGrid.js +9 -0
- package/dist/puzzle/fallingPiece.d.ts +9 -0
- package/dist/puzzle/fallingPiece.js +9 -0
- package/dist/puzzle/nonogram.d.ts +39 -0
- package/dist/puzzle/nonogram.js +136 -0
- package/dist/random/nameGen.d.ts +5 -0
- package/dist/random/nameGen.js +5 -0
- package/dist/random/pick.d.ts +8 -0
- package/dist/random/pick.js +31 -0
- package/dist/random/rng.d.ts +22 -0
- package/dist/random/rng.js +28 -8
- package/dist/random/seedLink.d.ts +4 -0
- package/dist/random/seedLink.js +4 -0
- package/dist/relation/keyedValues.d.ts +54 -0
- package/dist/relation/keyedValues.js +115 -0
- package/dist/relation/thresholds.d.ts +62 -0
- package/dist/relation/thresholds.js +62 -0
- package/dist/render/color.d.ts +12 -0
- package/dist/render/color.js +26 -0
- package/dist/render/lookPreset.d.ts +41 -0
- package/dist/render/lookPreset.js +29 -0
- package/dist/render/postProcessing.d.ts +20 -0
- package/dist/render/postProcessing.js +21 -1
- package/dist/rules/predicate.d.ts +53 -0
- package/dist/rules/predicate.js +64 -0
- package/dist/rules/ruleEffects.d.ts +38 -0
- package/dist/rules/ruleEffects.js +37 -0
- package/dist/rules/triggeredRules.d.ts +160 -0
- package/dist/rules/triggeredRules.js +241 -0
- package/dist/runtime/adapter.d.ts +42 -3
- package/dist/runtime/adapter.js +44 -1
- package/dist/runtime/cameraDirector.d.ts +1 -0
- package/dist/runtime/cameraDirector.js +1 -0
- package/dist/runtime/commandRunner.d.ts +1 -0
- package/dist/runtime/commandRunner.js +1 -0
- package/dist/runtime/context/combatFx.d.ts +23 -0
- package/dist/runtime/context/combatFx.js +161 -0
- package/dist/runtime/context/registries.d.ts +13 -0
- package/dist/runtime/context/registries.js +84 -0
- package/dist/runtime/context/worldItems.d.ts +21 -0
- package/dist/runtime/context/worldItems.js +37 -0
- package/dist/runtime/descriptors/baseline.d.ts +48 -0
- package/dist/runtime/descriptors/baseline.js +134 -0
- package/dist/runtime/descriptors/features.d.ts +74 -0
- package/dist/runtime/descriptors/features.js +281 -0
- package/dist/runtime/gameContext.d.ts +114 -13
- package/dist/runtime/gameContext.js +303 -395
- package/dist/runtime/gameRuntime.d.ts +1 -0
- package/dist/runtime/gameRuntime.js +1 -0
- package/dist/runtime/headlessRunner.d.ts +60 -0
- package/dist/runtime/headlessRunner.js +44 -0
- package/dist/runtime/hostPersistence.d.ts +12 -0
- package/dist/runtime/hostPersistence.js +12 -0
- package/dist/runtime/hostedGameRunner.d.ts +8 -3
- package/dist/runtime/hostedGameRunner.js +26 -3
- package/dist/runtime/hostedWorldSession.d.ts +12 -4
- package/dist/runtime/hostedWorldSession.js +11 -4
- package/dist/runtime/inputSnapshot.d.ts +8 -3
- package/dist/runtime/inputSnapshot.js +6 -2
- package/dist/runtime/motionIntents.d.ts +11 -2
- package/dist/runtime/motionIntents.js +16 -2
- package/dist/runtime/perContext.d.ts +15 -0
- package/dist/runtime/perContext.js +21 -0
- package/dist/runtime/runtimeSave.d.ts +79 -0
- package/dist/runtime/runtimeSave.js +105 -0
- package/dist/runtime/save.d.ts +4 -0
- package/dist/runtime/save.js +4 -0
- package/dist/runtime/snapshot.d.ts +7 -0
- package/dist/runtime/snapshot.js +7 -0
- package/dist/runtime/visibility.d.ts +2 -1
- package/dist/runtime/visibility.js +2 -1
- package/dist/runtime/worldChannel.d.ts +7 -3
- package/dist/runtime/worldChannel.js +51 -6
- package/dist/runtime/worldMirror.d.ts +14 -2
- package/dist/runtime/worldMirror.js +15 -2
- package/dist/runtime/worldProjection.d.ts +47 -0
- package/dist/runtime/worldProjection.js +52 -0
- package/dist/runtime/worldReplication.d.ts +30 -7
- package/dist/runtime/worldReplication.js +41 -9
- package/dist/runtime/worldSnapshot.d.ts +30 -3
- package/dist/runtime/worldSnapshot.js +20 -5
- package/dist/scene/assetCatalog.d.ts +21 -0
- package/dist/scene/assetCatalog.js +4 -0
- package/dist/scene/assetDiagnostics.d.ts +69 -0
- package/dist/scene/assetDiagnostics.js +110 -0
- package/dist/scene/assetGenerator.d.ts +65 -0
- package/dist/scene/assetGenerator.js +64 -0
- package/dist/scene/assetSpace.d.ts +137 -0
- package/dist/scene/assetSpace.js +259 -0
- package/dist/scene/authoredTriggers.d.ts +169 -0
- package/dist/scene/authoredTriggers.js +340 -0
- package/dist/scene/behaviorRuntime.d.ts +75 -0
- package/dist/scene/behaviorRuntime.js +217 -0
- package/dist/scene/behaviors.d.ts +14 -2
- package/dist/scene/behaviors.js +7 -2
- package/dist/scene/bodyBind.d.ts +60 -0
- package/dist/scene/bodyBind.js +51 -0
- package/dist/scene/builtinSceneKinds.d.ts +5 -0
- package/dist/scene/builtinSceneKinds.js +62 -0
- package/dist/scene/colliders.d.ts +13 -1
- package/dist/scene/colliders.js +37 -1
- package/dist/scene/entityStats.d.ts +11 -2
- package/dist/scene/entityStats.js +11 -2
- package/dist/scene/entityStore.d.ts +12 -1
- package/dist/scene/entityStore.js +15 -0
- package/dist/scene/facing.d.ts +18 -0
- package/dist/scene/facing.js +26 -0
- package/dist/scene/modelSockets.d.ts +33 -0
- package/dist/scene/modelSockets.js +29 -0
- package/dist/scene/objectQuery.d.ts +2 -0
- package/dist/scene/objectQuery.js +2 -0
- package/dist/scene/objectStore.d.ts +4 -0
- package/dist/scene/objectStore.js +6 -0
- package/dist/scene/possession.d.ts +8 -0
- package/dist/scene/possession.js +14 -0
- package/dist/scene/roster.d.ts +3 -0
- package/dist/scene/roster.js +12 -0
- package/dist/scene/sceneKinds.d.ts +240 -0
- package/dist/scene/sceneKinds.js +214 -0
- package/dist/scene/sceneOwnership.d.ts +169 -0
- package/dist/scene/sceneOwnership.js +179 -0
- package/dist/scene/selectionBookmarks.d.ts +93 -0
- package/dist/scene/selectionBookmarks.js +122 -0
- package/dist/scene/vehicleSeat.d.ts +68 -0
- package/dist/scene/vehicleSeat.js +59 -0
- package/dist/sensor/concealment.d.ts +3 -0
- package/dist/sensor/concealment.js +3 -0
- package/dist/sensor/freezeMonitor.d.ts +1 -0
- package/dist/sensor/freezeMonitor.js +1 -0
- package/dist/sensor/frustumSensor.d.ts +7 -3
- package/dist/sensor/frustumSensor.js +7 -3
- package/dist/sensor/hiddenStateProbe.d.ts +5 -2
- package/dist/sensor/hiddenStateProbe.js +5 -2
- package/dist/sensor/recordingBuffer.d.ts +2 -1
- package/dist/sensor/recordingBuffer.js +2 -1
- package/dist/sensor/replayLoop.d.ts +6 -2
- package/dist/sensor/replayLoop.js +6 -2
- package/dist/sensor/revealQuery.d.ts +2 -1
- package/dist/sensor/revealQuery.js +2 -1
- package/dist/sensor/visionCone.d.ts +10 -3
- package/dist/sensor/visionCone.js +10 -3
- package/dist/session/contestedChannel.d.ts +1 -0
- package/dist/session/contestedChannel.js +1 -0
- package/dist/session/extraction.d.ts +1 -0
- package/dist/session/extraction.js +1 -0
- package/dist/session/roles.d.ts +6 -0
- package/dist/session/roles.js +6 -0
- package/dist/session/roundState.d.ts +8 -0
- package/dist/session/roundState.js +2 -0
- package/dist/settings/settingsModel.d.ts +1 -0
- package/dist/settings/settingsModel.js +1 -0
- package/dist/stats/accumulatorMeter.d.ts +6 -0
- package/dist/stats/accumulatorMeter.js +6 -0
- package/dist/stats/eventMeter.d.ts +5 -0
- package/dist/stats/eventMeter.js +5 -0
- package/dist/stats/rollCheck.d.ts +5 -0
- package/dist/stats/rollCheck.js +5 -0
- package/dist/stats/statModifiers.d.ts +5 -0
- package/dist/stats/statModifiers.js +5 -0
- package/dist/store/defineKeyedStore.d.ts +38 -0
- package/dist/store/defineKeyedStore.js +42 -0
- package/dist/store/defineStore.d.ts +33 -0
- package/dist/store/defineStore.js +35 -0
- package/dist/store/observableKeyedStore.d.ts +5 -0
- package/dist/store/observableKeyedStore.js +34 -2
- package/dist/survival/decayMeter.d.ts +55 -0
- package/dist/survival/decayMeter.js +130 -55
- package/dist/survival/moodle.d.ts +2 -0
- package/dist/survival/regionHealth.d.ts +6 -0
- package/dist/survival/regionHealth.js +5 -0
- package/dist/tactics/fallingGrid.d.ts +4 -2
- package/dist/tactics/fallingGrid.js +4 -2
- package/dist/tactics/predictiveQuery.d.ts +3 -0
- package/dist/tactics/predictiveQuery.js +3 -0
- package/dist/tactics/snapshot.d.ts +2 -0
- package/dist/tactics/snapshot.js +2 -0
- package/dist/tactics/surface.d.ts +1 -0
- package/dist/tactics/surface.js +1 -0
- package/dist/tactics/tacticalGrid.d.ts +1 -0
- package/dist/tactics/tacticalGrid.js +1 -0
- package/dist/time/beatClock.d.ts +14 -4
- package/dist/time/beatClock.js +14 -4
- package/dist/time/calendarClock.d.ts +3 -0
- package/dist/time/calendarClock.js +3 -0
- package/dist/time/idleProgress.d.ts +4 -0
- package/dist/time/idleProgress.js +4 -0
- package/dist/time/simClock.d.ts +2 -0
- package/dist/time/simClock.js +20 -5
- package/dist/ui/actionModel.d.ts +110 -0
- package/dist/ui/actionModel.js +159 -0
- package/dist/ui/gameLayout.d.ts +30 -11
- package/dist/ui/gameLayout.js +30 -11
- package/dist/ui/hudDocument.d.ts +114 -0
- package/dist/ui/hudDocument.js +220 -0
- package/dist/ui/hudLayout.d.ts +33 -1
- package/dist/ui/hudLayout.js +204 -17
- package/dist/ui/selectionModel.d.ts +92 -0
- package/dist/ui/selectionModel.js +88 -0
- package/dist/ui/tooltipModel.d.ts +63 -0
- package/dist/ui/tooltipModel.js +82 -0
- package/dist/ui.d.ts +15 -0
- package/dist/ui.js +15 -0
- package/dist/visibility/bounds.d.ts +8 -1
- package/dist/visibility/bounds.js +8 -1
- package/dist/visibility/frustum.d.ts +12 -3
- package/dist/visibility/frustum.js +12 -3
- package/dist/work/jobQueue.d.ts +201 -0
- package/dist/work/jobQueue.js +253 -0
- package/dist/work/unitTraining.d.ts +58 -0
- package/dist/work/unitTraining.js +52 -0
- package/dist/world/authoredObjects.d.ts +58 -0
- package/dist/world/authoredObjects.js +69 -0
- package/dist/world/buildingGenerator.d.ts +18 -0
- package/dist/world/buildingGenerator.js +62 -0
- package/dist/world/buildings.d.ts +5 -0
- package/dist/world/buildings.js +5 -0
- package/dist/world/catenary.d.ts +22 -0
- package/dist/world/catenary.js +69 -0
- package/dist/world/features.d.ts +115 -7
- package/dist/world/features.js +56 -5
- package/dist/world/footprintGrid.d.ts +59 -0
- package/dist/world/footprintGrid.js +141 -0
- package/dist/world/geometry.d.ts +64 -0
- package/dist/world/geometry.js +94 -0
- package/dist/world/grassKind.d.ts +51 -0
- package/dist/world/grassKind.js +101 -0
- package/dist/world/pathInstances.d.ts +27 -0
- package/dist/world/pathInstances.js +27 -0
- package/dist/world/pathTerrain.d.ts +80 -0
- package/dist/world/pathTerrain.js +142 -0
- package/dist/world/placeAsset.d.ts +81 -0
- package/dist/world/placeAsset.js +77 -0
- package/dist/world/placement.d.ts +4 -0
- package/dist/world/placement.js +4 -0
- package/dist/world/placementController.d.ts +6 -0
- package/dist/world/placementController.js +6 -0
- package/dist/world/polyline.d.ts +34 -0
- package/dist/world/polyline.js +81 -0
- package/dist/world/roads.d.ts +8 -0
- package/dist/world/roads.js +38 -0
- package/dist/world/scatterRegion.d.ts +164 -0
- package/dist/world/scatterRegion.js +409 -0
- package/dist/world/sceneShapes.d.ts +43 -0
- package/dist/world/sceneShapes.js +1 -0
- package/dist/world/segment.d.ts +27 -0
- package/dist/world/segment.js +43 -0
- package/dist/world/soilKind.d.ts +48 -0
- package/dist/world/soilKind.js +92 -0
- package/dist/world/spatialSample.d.ts +241 -0
- package/dist/world/spatialSample.js +465 -0
- package/dist/world/terraform.d.ts +213 -1
- package/dist/world/terraform.js +655 -20
- package/dist/world/terrain.d.ts +119 -20
- package/dist/world/terrain.js +247 -41
- package/dist/world/terrainGuides.d.ts +182 -0
- package/dist/world/terrainGuides.js +343 -0
- package/dist/world/vec2.d.ts +81 -0
- package/dist/world/vec2.js +128 -0
- package/dist/world/vec3.d.ts +49 -0
- package/dist/world/vec3.js +76 -0
- package/dist/world/vegetation.d.ts +71 -0
- package/dist/world/vegetation.js +151 -0
- package/dist/world/visibilityField.d.ts +154 -0
- package/dist/world/visibilityField.js +271 -0
- package/dist/world/volumetricClouds.d.ts +52 -0
- package/dist/world/volumetricClouds.js +43 -0
- package/dist/world/walls.d.ts +9 -0
- package/dist/world/walls.js +9 -0
- package/dist/world/waterKind.d.ts +55 -0
- package/dist/world/waterKind.js +99 -0
- package/dist/world.d.ts +132 -0
- package/dist/world.js +132 -0
- package/package.json +32 -8
- package/skills/jgengine/SKILL.md +51 -0
- package/skills/jgengine/api.md +434 -0
- package/skills/jgengine/capabilities.md +29 -0
- package/skills/jgengine/reference-cartridge.md +72 -0
- package/skills/jgengine-combat/SKILL.md +34 -0
- package/skills/jgengine-combat/api.md +549 -0
- package/skills/jgengine-combat/capabilities.md +169 -0
- package/skills/jgengine-combat/reference.md +98 -0
- package/skills/jgengine-gameplay/SKILL.md +39 -0
- package/skills/jgengine-gameplay/api.md +1794 -0
- package/skills/jgengine-gameplay/capabilities.md +378 -0
- package/skills/jgengine-gameplay/reference-systems.md +60 -0
- package/skills/jgengine-world/SKILL.md +38 -0
- package/skills/jgengine-world/api.md +2652 -0
- package/skills/jgengine-world/capabilities.md +370 -0
- package/skills/jgengine-world/reference.md +222 -0
- package/dist/cartridge/runtime.d.ts +0 -15
- package/dist/cartridge/runtime.js +0 -556
- package/dist/cartridge/spec.d.ts +0 -188
- package/dist/cartridge/spec.js +0 -19
- package/dist/cartridge/validate.d.ts +0 -2
- package/dist/cartridge/validate.js +0 -78
- package/dist/store/engineStore.d.ts +0 -22
- package/dist/store/engineStore.js +0 -50
- package/dist/store/features.d.ts +0 -10
- package/dist/store/features.js +0 -23
- package/llms.txt +0 -5389
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group destination assignment: slot a moving group into a formation around a
|
|
3
|
+
* target point, then match members to slots. Shape is caller data — a
|
|
4
|
+
* {@link FormationSlotGenerator} emits slot offsets in the group's local frame
|
|
5
|
+
* ("right" = +x, "forward" = +y) and the engine ships line/box/wedge/circle
|
|
6
|
+
* only as samples; a custom generator needs no engine change. Placement and
|
|
7
|
+
* matching are pure and deterministic so the same inputs always yield the same
|
|
8
|
+
* world slots and the same assignment, which keeps them replay- and
|
|
9
|
+
* network-safe. Route planning and local collision avoidance are deliberately
|
|
10
|
+
* separate seams (`movement/avoidance`, `nav/pathFollow`): this module answers
|
|
11
|
+
* only "where should each member stand", not "how does it get there".
|
|
12
|
+
*/
|
|
13
|
+
import { yawForward, yawRight } from "./steering.js";
|
|
14
|
+
/**
|
|
15
|
+
* Engine yaw (`rotationY`, radians) that faces from `from` toward `to` on the
|
|
16
|
+
* XZ plane, matching the `forward = (sin yaw, cos yaw)` convention. Feed the
|
|
17
|
+
* result as the `facing` of {@link placeFormation} to orient a formation along
|
|
18
|
+
* its travel direction. Returns `0` when the points coincide.
|
|
19
|
+
*
|
|
20
|
+
* @capability formation-facing group facing yaw from a travel direction on the XZ plane
|
|
21
|
+
* @consumer squad and crowd movement — orient a destination formation along its heading
|
|
22
|
+
*/
|
|
23
|
+
export function facingYaw(from, to) {
|
|
24
|
+
const dx = to[0] - from[0];
|
|
25
|
+
const dz = to[1] - from[1];
|
|
26
|
+
if (dx * dx + dz * dz <= 1e-18)
|
|
27
|
+
return 0;
|
|
28
|
+
return Math.atan2(dx, dz);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Transform a generator's local slot offsets into world XZ positions around a
|
|
32
|
+
* `destination`, rotated by `facing` (engine yaw). Slot `i` in the returned
|
|
33
|
+
* array is `generator(count)[i]` mapped through the group frame, so it stays
|
|
34
|
+
* aligned with {@link assignFormationSlots}' slot indices. Pure and allocation-
|
|
35
|
+
* light: one array of `count` points, no per-call closures retained.
|
|
36
|
+
*
|
|
37
|
+
* @capability formation-placement place a group formation's world slots around a destination
|
|
38
|
+
* @consumer squad/party/convoy movement — generate per-member destination slots around a target
|
|
39
|
+
*/
|
|
40
|
+
export function placeFormation(destination, facing, count, generator) {
|
|
41
|
+
if (count <= 0)
|
|
42
|
+
return [];
|
|
43
|
+
const forward = yawForward(facing);
|
|
44
|
+
const right = yawRight(facing);
|
|
45
|
+
const local = generator(count);
|
|
46
|
+
const slots = [];
|
|
47
|
+
for (let i = 0; i < count; i += 1) {
|
|
48
|
+
const offset = local[i] ?? ZERO;
|
|
49
|
+
const r = offset[0];
|
|
50
|
+
const f = offset[1];
|
|
51
|
+
slots.push([
|
|
52
|
+
destination[0] + right[0] * r + forward[0] * f,
|
|
53
|
+
destination[1] + right[1] * r + forward[1] * f,
|
|
54
|
+
]);
|
|
55
|
+
}
|
|
56
|
+
return slots;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Match `members` to `slots` by a deterministic greedy nearest assignment:
|
|
60
|
+
* every (member, slot) pair is ranked by squared travel distance (minus a
|
|
61
|
+
* stickiness bonus for a member's previous slot) and assigned in order while
|
|
62
|
+
* both ends are free. Returns `assignment[member] = slot`, or `-1` for members
|
|
63
|
+
* left unmatched when there are fewer slots than members. Ties break by member
|
|
64
|
+
* then slot index, so the result is stable across runs and independent of input
|
|
65
|
+
* ordering — the property replay and lockstep multiplayer rely on. Groups are
|
|
66
|
+
* bounded, so the `O(members·slots·log)` sort is fine; this is not a per-frame
|
|
67
|
+
* whole-world pass.
|
|
68
|
+
*
|
|
69
|
+
* @capability formation-assignment stable deterministic member-to-slot matching for a group formation
|
|
70
|
+
* @consumer squad/party movement — assign each member a destination slot with low reshuffle churn
|
|
71
|
+
*/
|
|
72
|
+
export function assignFormationSlots(members, slots, options = {}) {
|
|
73
|
+
const memberCount = members.length;
|
|
74
|
+
const slotCount = slots.length;
|
|
75
|
+
const assignment = new Array(memberCount).fill(-1);
|
|
76
|
+
if (memberCount === 0 || slotCount === 0)
|
|
77
|
+
return assignment;
|
|
78
|
+
const previous = options.previous;
|
|
79
|
+
const stickiness = options.stickiness ?? 0;
|
|
80
|
+
const pairs = [];
|
|
81
|
+
for (let m = 0; m < memberCount; m += 1) {
|
|
82
|
+
const member = members[m];
|
|
83
|
+
const keepSlot = previous?.[m];
|
|
84
|
+
for (let s = 0; s < slotCount; s += 1) {
|
|
85
|
+
const slot = slots[s];
|
|
86
|
+
const dx = slot[0] - member[0];
|
|
87
|
+
const dz = slot[1] - member[1];
|
|
88
|
+
let cost = dx * dx + dz * dz;
|
|
89
|
+
if (stickiness > 0 && keepSlot === s)
|
|
90
|
+
cost -= stickiness;
|
|
91
|
+
pairs.push({ member: m, slot: s, cost });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
pairs.sort((a, b) => a.cost !== b.cost ? a.cost - b.cost : a.member !== b.member ? a.member - b.member : a.slot - b.slot);
|
|
95
|
+
const slotTaken = new Array(slotCount).fill(false);
|
|
96
|
+
let filled = 0;
|
|
97
|
+
const need = Math.min(memberCount, slotCount);
|
|
98
|
+
for (let p = 0; p < pairs.length && filled < need; p += 1) {
|
|
99
|
+
const pair = pairs[p];
|
|
100
|
+
if (assignment[pair.member] !== -1 || slotTaken[pair.slot])
|
|
101
|
+
continue;
|
|
102
|
+
assignment[pair.member] = pair.slot;
|
|
103
|
+
slotTaken[pair.slot] = true;
|
|
104
|
+
filled += 1;
|
|
105
|
+
}
|
|
106
|
+
return assignment;
|
|
107
|
+
}
|
|
108
|
+
const ZERO = [0, 0];
|
|
109
|
+
/**
|
|
110
|
+
* A single rank abreast, centered on the destination and facing forward — a
|
|
111
|
+
* skirmish line or a chorus row. Slots run left→right along the group's right
|
|
112
|
+
* axis.
|
|
113
|
+
*
|
|
114
|
+
* @capability formation-line line (abreast) slot generator for group destinations
|
|
115
|
+
* @consumer squad movement — line formation sample policy for {@link placeFormation}
|
|
116
|
+
*/
|
|
117
|
+
export function lineFormation(options) {
|
|
118
|
+
const spacing = options.spacing;
|
|
119
|
+
return (count) => {
|
|
120
|
+
const slots = [];
|
|
121
|
+
const mid = (count - 1) / 2;
|
|
122
|
+
for (let i = 0; i < count; i += 1)
|
|
123
|
+
slots.push([(i - mid) * spacing, 0]);
|
|
124
|
+
return slots;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* A rectangular grid centered on the destination, front row toward `+forward` —
|
|
129
|
+
* a marching block or a phalanx. Rows fill front-to-back, left-to-right.
|
|
130
|
+
*
|
|
131
|
+
* @capability formation-box box/grid slot generator for group destinations
|
|
132
|
+
* @consumer squad movement — box formation sample policy for {@link placeFormation}
|
|
133
|
+
*/
|
|
134
|
+
export function boxFormation(options) {
|
|
135
|
+
const spacing = options.spacing;
|
|
136
|
+
const fixedColumns = options.columns;
|
|
137
|
+
return (count) => {
|
|
138
|
+
const columns = Math.max(1, fixedColumns ?? Math.ceil(Math.sqrt(count)));
|
|
139
|
+
const rows = Math.ceil(count / columns);
|
|
140
|
+
const midCol = (columns - 1) / 2;
|
|
141
|
+
const midRow = (rows - 1) / 2;
|
|
142
|
+
const slots = [];
|
|
143
|
+
for (let i = 0; i < count; i += 1) {
|
|
144
|
+
const row = Math.floor(i / columns);
|
|
145
|
+
const col = i % columns;
|
|
146
|
+
slots.push([(col - midCol) * spacing, (midRow - row) * spacing]);
|
|
147
|
+
}
|
|
148
|
+
return slots;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* A "V"/arrowhead with the apex at the destination and arms trailing back — a
|
|
153
|
+
* flying-wedge charge or a goose skein. Slot 0 is the tip; later slots alternate
|
|
154
|
+
* right then left, each rank stepping one `spacing` outward and backward.
|
|
155
|
+
*
|
|
156
|
+
* @capability formation-wedge wedge/arrowhead slot generator for group destinations
|
|
157
|
+
* @consumer squad movement — wedge formation sample policy for {@link placeFormation}
|
|
158
|
+
*/
|
|
159
|
+
export function wedgeFormation(options) {
|
|
160
|
+
const spacing = options.spacing;
|
|
161
|
+
return (count) => {
|
|
162
|
+
const slots = [];
|
|
163
|
+
for (let i = 0; i < count; i += 1) {
|
|
164
|
+
if (i === 0) {
|
|
165
|
+
slots.push([0, 0]);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
const rank = Math.ceil(i / 2);
|
|
169
|
+
const side = i % 2 === 1 ? 1 : -1;
|
|
170
|
+
slots.push([side * rank * spacing, -rank * spacing]);
|
|
171
|
+
}
|
|
172
|
+
return slots;
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* An evenly spaced ring around the destination — a guard cordon, a huddle, or a
|
|
177
|
+
* surround. Slot 0 sits `startAngle` from forward; slots advance evenly around
|
|
178
|
+
* the circle.
|
|
179
|
+
*
|
|
180
|
+
* @capability formation-circle ring/cordon slot generator for group destinations
|
|
181
|
+
* @consumer squad/crowd movement — circle formation sample policy for {@link placeFormation}
|
|
182
|
+
*/
|
|
183
|
+
export function circleFormation(options) {
|
|
184
|
+
const radius = options.radius;
|
|
185
|
+
const startAngle = options.startAngle ?? 0;
|
|
186
|
+
return (count) => {
|
|
187
|
+
const slots = [];
|
|
188
|
+
for (let i = 0; i < count; i += 1) {
|
|
189
|
+
const angle = startAngle + (2 * Math.PI * i) / count;
|
|
190
|
+
slots.push([radius * Math.sin(angle), radius * Math.cos(angle)]);
|
|
191
|
+
}
|
|
192
|
+
return slots;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
@@ -41,4 +41,9 @@ export interface GlideModel {
|
|
|
41
41
|
pose(): GlideStep;
|
|
42
42
|
launch(position: GlideVec3, heading: number, initialSpeed?: number): void;
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Gliding/wingsuit descent control — lift, drag, and steering from a launch.
|
|
46
|
+
*
|
|
47
|
+
* @capability glide gliding/wingsuit descent control from a launch
|
|
48
|
+
*/
|
|
44
49
|
export declare function createGlideModel(config?: GlideModelConfig): GlideModel;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gliding/wingsuit descent control — lift, drag, and steering from a launch.
|
|
3
|
+
*
|
|
4
|
+
* @capability glide gliding/wingsuit descent control from a launch
|
|
5
|
+
*/
|
|
1
6
|
export function createGlideModel(config = {}) {
|
|
2
7
|
const gravity = (config.gravity ?? 20) * (config.gravityScale ?? 0.25);
|
|
3
8
|
const thrustAccel = config.thrustAccel ?? 10;
|
|
@@ -31,4 +31,9 @@ export interface GrappleSwing {
|
|
|
31
31
|
/** Constrain one frame. `reeling` shortens the rope; returns the corrected position/velocity. */
|
|
32
32
|
step(position: SwingVec3, velocity: SwingVec3, dt: number, reeling?: boolean): GrappleSwingStep;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Grappling-hook rope swing physics with anchor, pendulum motion, and reel-in.
|
|
36
|
+
*
|
|
37
|
+
* @capability grapple-swing grappling-hook rope swing physics with reel-in
|
|
38
|
+
*/
|
|
34
39
|
export declare function createGrappleSwing(config?: GrappleSwingConfig): GrappleSwing;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grappling-hook rope swing physics with anchor, pendulum motion, and reel-in.
|
|
3
|
+
*
|
|
4
|
+
* @capability grapple-swing grappling-hook rope swing physics with reel-in
|
|
5
|
+
*/
|
|
1
6
|
export function createGrappleSwing(config = {}) {
|
|
2
7
|
const reelSpeed = config.reelSpeed ?? 0;
|
|
3
8
|
const minLength = config.minLength ?? 1;
|
|
@@ -26,4 +26,9 @@ export interface LeaderTrail {
|
|
|
26
26
|
/** Drop all history (teleport, respawn) and optionally restart from a position. */
|
|
27
27
|
reset(position?: TrailPoint): void;
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* A trailing follower formation that chases a leader along its past path — snake/convoy trails.
|
|
31
|
+
*
|
|
32
|
+
* @capability follow-trail trailing follower/snake formation that chases a leader
|
|
33
|
+
*/
|
|
29
34
|
export declare function createLeaderTrail(config: LeaderTrailConfig): LeaderTrail;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A trailing follower formation that chases a leader along its past path — snake/convoy trails.
|
|
3
|
+
*
|
|
4
|
+
* @capability follow-trail trailing follower/snake formation that chases a leader
|
|
5
|
+
*/
|
|
1
6
|
export function createLeaderTrail(config) {
|
|
2
7
|
if (!(config.spacing > 0))
|
|
3
8
|
throw new Error(`leader trail spacing must be positive, got ${config.spacing}`);
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
export type MovementKey = "w" | "a" | "s" | "d" | "shift" | "control" | "c" | "space";
|
|
14
14
|
export type MovementKeysState = Record<MovementKey, boolean>;
|
|
15
|
+
/** @internal */
|
|
15
16
|
export declare function createEmptyMovementKeys(): MovementKeysState;
|
|
16
17
|
/**
|
|
17
18
|
* Frame-independent description of what the player is asking the avatar to do.
|
|
@@ -31,7 +32,8 @@ export interface MovementIntent {
|
|
|
31
32
|
* Translate the set of held keys into an intent. When `canMove` is false (a
|
|
32
33
|
* menu is open, the world is paused) the avatar is fully idle so it never
|
|
33
34
|
* drifts behind an overlay.
|
|
34
|
-
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
35
37
|
export declare function resolveMovementIntent(keys: MovementKeysState, canMove: boolean): MovementIntent;
|
|
36
38
|
/**
|
|
37
39
|
* Kinematics + feel tuning for the first-person controller. Centralised here so
|
|
@@ -43,6 +45,8 @@ export declare const MOVEMENT_TUNING: {
|
|
|
43
45
|
readonly walkSpeedMultiplier: 1.75;
|
|
44
46
|
readonly runSpeedMultiplier: 2.25;
|
|
45
47
|
readonly crouchSpeedMultiplier: 0.45;
|
|
48
|
+
/** Backward (S) travels this fraction of walk speed so retreating reads slower than advancing. */
|
|
49
|
+
readonly backpedalSpeedMultiplier: 0.65;
|
|
46
50
|
readonly groundAcceleration: 26;
|
|
47
51
|
readonly airAcceleration: 12;
|
|
48
52
|
readonly groundFriction: 18;
|
|
@@ -74,6 +78,7 @@ export interface PlayerMotionState {
|
|
|
74
78
|
grounded: boolean;
|
|
75
79
|
jumpHeld: boolean;
|
|
76
80
|
}
|
|
81
|
+
/** @internal */
|
|
77
82
|
export declare function createPlayerMotionState(): PlayerMotionState;
|
|
78
83
|
/** Horizontal step (world units) the avatar should commit this frame. */
|
|
79
84
|
export interface MovementFrameStep {
|
|
@@ -87,6 +92,19 @@ export interface MovementFrameStep {
|
|
|
87
92
|
export interface MovementTuningOverrides {
|
|
88
93
|
gravityAcceleration?: number;
|
|
89
94
|
jumpVelocity?: number;
|
|
95
|
+
/** Fraction of walk speed while backpedalling; overrides {@link MOVEMENT_TUNING.backpedalSpeedMultiplier}. */
|
|
96
|
+
backpedalSpeedMultiplier?: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Per-frame dynamic modifiers for {@link advancePlayerMotion} — state the caller
|
|
100
|
+
* recomputes each tick (unlike the static {@link MovementTuningOverrides}). Omitted
|
|
101
|
+
* fields leave the integrator at its default behavior.
|
|
102
|
+
*/
|
|
103
|
+
export interface MotionFrameOptions {
|
|
104
|
+
/** Extra multiplier applied on top of the resolved target speed (e.g. swimming). Default 1. */
|
|
105
|
+
speedScale?: number;
|
|
106
|
+
/** Suppress gravity/jump integration and hold the avatar afloat this frame (e.g. swimming). Default false. */
|
|
107
|
+
floating?: boolean;
|
|
90
108
|
}
|
|
91
109
|
/**
|
|
92
110
|
* Advance one frame of avatar kinematics. Mutates `motion` (velocity, jump,
|
|
@@ -97,8 +115,9 @@ export interface MovementTuningOverrides {
|
|
|
97
115
|
* (need not be normalized); the avatar's right axis is derived from it. Pulling
|
|
98
116
|
* this out of the render loop is what lets us assert "held forward for N frames
|
|
99
117
|
* crosses the room" in a unit test instead of only in the live game.
|
|
100
|
-
|
|
101
|
-
|
|
118
|
+
* @internal
|
|
119
|
+
*/
|
|
120
|
+
export declare function advancePlayerMotion(motion: PlayerMotionState, intent: MovementIntent, forwardX: number, forwardZ: number, baseSpeed: number, rawDeltaSeconds: number, tuning?: MovementTuningOverrides, options?: MotionFrameOptions): MovementFrameStep;
|
|
102
121
|
/** A placed scene object the walking player collides against as a circle-vs-AABB obstacle. */
|
|
103
122
|
export interface CollisionObstacle {
|
|
104
123
|
position: readonly [number, number, number];
|
|
@@ -113,21 +132,29 @@ export interface CollisionObstacle {
|
|
|
113
132
|
* by `playerRadius`; an obstacle whose vertical span misses the player's
|
|
114
133
|
* feet-to-head span is skipped entirely. Callers should pre-filter to nearby
|
|
115
134
|
* objects — this also early-exits per obstacle on horizontal distance.
|
|
116
|
-
|
|
135
|
+
* @internal
|
|
136
|
+
*/
|
|
117
137
|
export declare function resolveObstacleStep(current: readonly [number, number, number], stepX: number, stepZ: number, obstacles: readonly CollisionObstacle[], playerRadius?: number): MovementFrameStep;
|
|
118
|
-
/** Placed objects within `radius` (XZ) of `center`, as {@link CollisionObstacle}s to pre-filter for {@link resolveObstacleStep}.
|
|
138
|
+
/** Placed objects within `radius` (XZ) of `center`, as {@link CollisionObstacle}s to pre-filter for {@link resolveObstacleStep}.
|
|
139
|
+
* @internal
|
|
140
|
+
*/
|
|
119
141
|
export declare function nearbyObstacles(objects: readonly {
|
|
120
142
|
position: readonly [number, number, number];
|
|
121
143
|
}[], center: readonly [number, number, number], radius?: number): CollisionObstacle[];
|
|
122
|
-
/** Zeroes the off-axis component so travel is locked to a single world axis (`PlayerMovementConfig.mode: "axis"`).
|
|
144
|
+
/** Zeroes the off-axis component so travel is locked to a single world axis (`PlayerMovementConfig.mode: "axis"`).
|
|
145
|
+
* @internal
|
|
146
|
+
*/
|
|
123
147
|
export declare function constrainStepToAxis(stepX: number, stepZ: number, axis: "x" | "z"): MovementFrameStep;
|
|
124
148
|
/**
|
|
125
149
|
* Snap a world position to its containing cell's center, matching the
|
|
126
150
|
* bounds-free form of `navGrid`'s and `tacticalGrid`'s `floor` + half-cell
|
|
127
151
|
* convention (`PlayerMovementConfig.mode: "grid"`).
|
|
128
|
-
|
|
152
|
+
* @internal
|
|
153
|
+
*/
|
|
129
154
|
export declare function snapPositionToGrid(x: number, z: number, cellSize: number): [number, number];
|
|
130
155
|
/** Peak jump height from MOVEMENT_TUNING.jumpVelocity + gravity, with small buffer. */
|
|
131
156
|
export declare const MAX_JUMP_OFFSET = 1.15;
|
|
132
|
-
/** Camera yaw looks along -Z; character mesh faces +Z at body rotation.y = 0.
|
|
157
|
+
/** Camera yaw looks along -Z; character mesh faces +Z at body rotation.y = 0.
|
|
158
|
+
* @internal
|
|
159
|
+
*/
|
|
133
160
|
export declare function cameraYawToAvatarBodyYaw(cameraYaw: number): number;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* touch controls) and its camera rigs (pointer lock, the per-frame look
|
|
11
11
|
* channel).
|
|
12
12
|
*/
|
|
13
|
+
/** @internal */
|
|
13
14
|
export function createEmptyMovementKeys() {
|
|
14
15
|
return { w: false, a: false, s: false, d: false, shift: false, control: false, c: false, space: false };
|
|
15
16
|
}
|
|
@@ -25,7 +26,8 @@ const IDLE_INTENT = {
|
|
|
25
26
|
* Translate the set of held keys into an intent. When `canMove` is false (a
|
|
26
27
|
* menu is open, the world is paused) the avatar is fully idle so it never
|
|
27
28
|
* drifts behind an overlay.
|
|
28
|
-
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
29
31
|
export function resolveMovementIntent(keys, canMove) {
|
|
30
32
|
if (!canMove)
|
|
31
33
|
return IDLE_INTENT;
|
|
@@ -52,6 +54,8 @@ export const MOVEMENT_TUNING = {
|
|
|
52
54
|
walkSpeedMultiplier: 1.75,
|
|
53
55
|
runSpeedMultiplier: 2.25,
|
|
54
56
|
crouchSpeedMultiplier: 0.45,
|
|
57
|
+
/** Backward (S) travels this fraction of walk speed so retreating reads slower than advancing. */
|
|
58
|
+
backpedalSpeedMultiplier: 0.65,
|
|
55
59
|
groundAcceleration: 26,
|
|
56
60
|
airAcceleration: 12,
|
|
57
61
|
groundFriction: 18,
|
|
@@ -70,15 +74,24 @@ export const MOVEMENT_TUNING = {
|
|
|
70
74
|
/** Largest physics step we integrate so a stalled tab can't teleport the player. */
|
|
71
75
|
maxFrameSeconds: 0.05,
|
|
72
76
|
};
|
|
73
|
-
/**
|
|
74
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Speed (units/s) the avatar should target given the active intent. Crouch and run
|
|
79
|
+
* take precedence over backpedal; a plain backward intent (`forward < 0`) slows to
|
|
80
|
+
* {@link MOVEMENT_TUNING.backpedalSpeedMultiplier} (overridable via `tuning`), while a
|
|
81
|
+
* pure strafe keeps full speed.
|
|
82
|
+
*/
|
|
83
|
+
function resolveTargetSpeed(intent, baseSpeed, tuning) {
|
|
84
|
+
const backpedal = tuning?.backpedalSpeedMultiplier ?? MOVEMENT_TUNING.backpedalSpeedMultiplier;
|
|
75
85
|
const speedMultiplier = intent.crouching
|
|
76
86
|
? MOVEMENT_TUNING.crouchSpeedMultiplier
|
|
77
87
|
: intent.running
|
|
78
88
|
? MOVEMENT_TUNING.runSpeedMultiplier
|
|
79
|
-
:
|
|
89
|
+
: intent.forward < 0
|
|
90
|
+
? backpedal
|
|
91
|
+
: 1;
|
|
80
92
|
return baseSpeed * MOVEMENT_TUNING.walkSpeedMultiplier * speedMultiplier;
|
|
81
93
|
}
|
|
94
|
+
/** @internal */
|
|
82
95
|
export function createPlayerMotionState() {
|
|
83
96
|
return {
|
|
84
97
|
horizontalVelocityX: 0,
|
|
@@ -98,10 +111,11 @@ export function createPlayerMotionState() {
|
|
|
98
111
|
* (need not be normalized); the avatar's right axis is derived from it. Pulling
|
|
99
112
|
* this out of the render loop is what lets us assert "held forward for N frames
|
|
100
113
|
* crosses the room" in a unit test instead of only in the live game.
|
|
101
|
-
|
|
102
|
-
|
|
114
|
+
* @internal
|
|
115
|
+
*/
|
|
116
|
+
export function advancePlayerMotion(motion, intent, forwardX, forwardZ, baseSpeed, rawDeltaSeconds, tuning, options) {
|
|
103
117
|
const deltaSeconds = Math.min(rawDeltaSeconds, MOVEMENT_TUNING.maxFrameSeconds);
|
|
104
|
-
const targetSpeed = resolveTargetSpeed(intent, baseSpeed);
|
|
118
|
+
const targetSpeed = resolveTargetSpeed(intent, baseSpeed, tuning) * (options?.speedScale ?? 1);
|
|
105
119
|
const gravityAcceleration = tuning?.gravityAcceleration ?? MOVEMENT_TUNING.gravityAcceleration;
|
|
106
120
|
const jumpVelocity = tuning?.jumpVelocity ?? MOVEMENT_TUNING.jumpVelocity;
|
|
107
121
|
let targetVelocityX = 0;
|
|
@@ -146,13 +160,19 @@ export function advancePlayerMotion(motion, intent, forwardX, forwardZ, baseSpee
|
|
|
146
160
|
motion.horizontalVelocityX *= friction;
|
|
147
161
|
motion.horizontalVelocityZ *= friction;
|
|
148
162
|
}
|
|
163
|
+
const floating = options?.floating === true;
|
|
149
164
|
const jumpPressed = intent.jumping;
|
|
150
|
-
if (jumpPressed && !motion.jumpHeld && motion.grounded && !intent.crouching) {
|
|
165
|
+
if (jumpPressed && !motion.jumpHeld && motion.grounded && !intent.crouching && !floating) {
|
|
151
166
|
motion.verticalVelocity = jumpVelocity;
|
|
152
167
|
motion.grounded = false;
|
|
153
168
|
}
|
|
154
169
|
motion.jumpHeld = jumpPressed;
|
|
155
|
-
if (
|
|
170
|
+
if (floating) {
|
|
171
|
+
motion.verticalVelocity = 0;
|
|
172
|
+
motion.jumpOffset = 0;
|
|
173
|
+
motion.grounded = true;
|
|
174
|
+
}
|
|
175
|
+
else if (!motion.grounded || motion.verticalVelocity > 0) {
|
|
156
176
|
motion.verticalVelocity -= gravityAcceleration * deltaSeconds;
|
|
157
177
|
motion.jumpOffset += motion.verticalVelocity * deltaSeconds;
|
|
158
178
|
if (motion.jumpOffset <= 0) {
|
|
@@ -188,7 +208,8 @@ function clampAxisStep(originalCoord, step, min, max) {
|
|
|
188
208
|
* by `playerRadius`; an obstacle whose vertical span misses the player's
|
|
189
209
|
* feet-to-head span is skipped entirely. Callers should pre-filter to nearby
|
|
190
210
|
* objects — this also early-exits per obstacle on horizontal distance.
|
|
191
|
-
|
|
211
|
+
* @internal
|
|
212
|
+
*/
|
|
192
213
|
export function resolveObstacleStep(current, stepX, stepZ, obstacles, playerRadius = DEFAULT_OBSTACLE_PLAYER_RADIUS) {
|
|
193
214
|
const feetY = current[1];
|
|
194
215
|
const headY = feetY + OBSTACLE_PLAYER_HEIGHT;
|
|
@@ -228,7 +249,9 @@ export function resolveObstacleStep(current, stepX, stepZ, obstacles, playerRadi
|
|
|
228
249
|
return { stepX: resultX, stepZ: resultZ };
|
|
229
250
|
}
|
|
230
251
|
const OBSTACLE_GATHER_RADIUS = 3;
|
|
231
|
-
/** Placed objects within `radius` (XZ) of `center`, as {@link CollisionObstacle}s to pre-filter for {@link resolveObstacleStep}.
|
|
252
|
+
/** Placed objects within `radius` (XZ) of `center`, as {@link CollisionObstacle}s to pre-filter for {@link resolveObstacleStep}.
|
|
253
|
+
* @internal
|
|
254
|
+
*/
|
|
232
255
|
export function nearbyObstacles(objects, center, radius = OBSTACLE_GATHER_RADIUS) {
|
|
233
256
|
const radiusSq = radius * radius;
|
|
234
257
|
const result = [];
|
|
@@ -240,7 +263,9 @@ export function nearbyObstacles(objects, center, radius = OBSTACLE_GATHER_RADIUS
|
|
|
240
263
|
}
|
|
241
264
|
return result;
|
|
242
265
|
}
|
|
243
|
-
/** Zeroes the off-axis component so travel is locked to a single world axis (`PlayerMovementConfig.mode: "axis"`).
|
|
266
|
+
/** Zeroes the off-axis component so travel is locked to a single world axis (`PlayerMovementConfig.mode: "axis"`).
|
|
267
|
+
* @internal
|
|
268
|
+
*/
|
|
244
269
|
export function constrainStepToAxis(stepX, stepZ, axis) {
|
|
245
270
|
return axis === "x" ? { stepX, stepZ: 0 } : { stepX: 0, stepZ };
|
|
246
271
|
}
|
|
@@ -248,13 +273,16 @@ export function constrainStepToAxis(stepX, stepZ, axis) {
|
|
|
248
273
|
* Snap a world position to its containing cell's center, matching the
|
|
249
274
|
* bounds-free form of `navGrid`'s and `tacticalGrid`'s `floor` + half-cell
|
|
250
275
|
* convention (`PlayerMovementConfig.mode: "grid"`).
|
|
251
|
-
|
|
276
|
+
* @internal
|
|
277
|
+
*/
|
|
252
278
|
export function snapPositionToGrid(x, z, cellSize) {
|
|
253
279
|
return [(Math.floor(x / cellSize) + 0.5) * cellSize, (Math.floor(z / cellSize) + 0.5) * cellSize];
|
|
254
280
|
}
|
|
255
281
|
/** Peak jump height from MOVEMENT_TUNING.jumpVelocity + gravity, with small buffer. */
|
|
256
282
|
export const MAX_JUMP_OFFSET = 1.15;
|
|
257
|
-
/** Camera yaw looks along -Z; character mesh faces +Z at body rotation.y = 0.
|
|
283
|
+
/** Camera yaw looks along -Z; character mesh faces +Z at body rotation.y = 0.
|
|
284
|
+
* @internal
|
|
285
|
+
*/
|
|
258
286
|
export function cameraYawToAvatarBodyYaw(cameraYaw) {
|
|
259
287
|
return cameraYaw + Math.PI;
|
|
260
288
|
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { applyHorizontalImpulses, applyMotionImpulses } from "../runtime/motionIntents.js";
|
|
2
|
-
import { groundFieldFor, hasEnvironmentTerrain } from "../world/terrain.js";
|
|
2
|
+
import { groundFieldFor, hasEnvironmentTerrain, sampleSlope } from "../world/terrain.js";
|
|
3
3
|
import { advancePlayerMotion, constrainStepToAxis, createEmptyMovementKeys, createPlayerMotionState, nearbyObstacles, resolveMovementIntent, resolveObstacleStep, snapPositionToGrid, } from "./movementModel.js";
|
|
4
|
-
import { steerYaw } from "./steering.js";
|
|
4
|
+
import { approachYaw, steerYaw } from "./steering.js";
|
|
5
5
|
import { advanceVoxelPlayer, createVoxelPlayerBody, } from "./voxelController.js";
|
|
6
6
|
const DEFAULT_TURN_SPEED = 2.4;
|
|
7
7
|
const DEFAULT_WALK_SPEED = 2;
|
|
8
|
+
const DEFAULT_SWIM_SPEED_MULTIPLIER = 0.65;
|
|
9
|
+
/** Minimum ground-normal `y` the player can stand on before slope-slide kicks in — cos(50°) ≈ 0.643. */
|
|
10
|
+
const DEFAULT_MAX_CLIMB_NORMAL_Y = Math.cos((50 * Math.PI) / 180);
|
|
11
|
+
/** Downhill slide speed (units/s) per unit of slope steepness while on too-steep ground. */
|
|
12
|
+
const SLOPE_SLIDE_SPEED = 4;
|
|
8
13
|
/**
|
|
9
14
|
* Maps a game's declared `physics` onto the movement controllers' tuning. `PhysicsConfig.gravity` is a signed
|
|
10
15
|
* world acceleration (negative points down), but the controllers integrate `velocityY -= gravityAcceleration * dt`
|
|
@@ -25,10 +30,12 @@ export function resolvePhysicsTuning(physics) {
|
|
|
25
30
|
/** Gather a game's collision/movement/physics/world config into a {@link PlayerMovementTuning} — call once per world; both the shell and a host pass the result to {@link stepPlayerMovement}. */
|
|
26
31
|
export function resolvePlayerMovementTuning(opts) {
|
|
27
32
|
const physics = resolvePhysicsTuning(opts.physics);
|
|
33
|
+
const backpedal = opts.movement?.backpedalMult;
|
|
34
|
+
const overrides = backpedal === undefined ? physics : { ...(physics ?? {}), backpedalSpeedMultiplier: backpedal };
|
|
28
35
|
return {
|
|
29
36
|
...(opts.collision === undefined ? {} : { collision: opts.collision }),
|
|
30
37
|
...(opts.movement === undefined ? {} : { movement: opts.movement }),
|
|
31
|
-
...(
|
|
38
|
+
...(overrides === undefined ? {} : { physics: overrides }),
|
|
32
39
|
ground: groundFieldFor(opts.world),
|
|
33
40
|
hasTerrain: hasEnvironmentTerrain(opts.world),
|
|
34
41
|
};
|
|
@@ -45,7 +52,7 @@ function storeFor(ctx) {
|
|
|
45
52
|
function stateFor(store, userId) {
|
|
46
53
|
let state = store.players.get(userId);
|
|
47
54
|
if (state === undefined) {
|
|
48
|
-
state = { heading: 0, voxelBody: null, motion: null };
|
|
55
|
+
state = { heading: 0, facing: null, voxelBody: null, motion: null };
|
|
49
56
|
store.players.set(userId, state);
|
|
50
57
|
}
|
|
51
58
|
return state;
|
|
@@ -58,6 +65,25 @@ export function playerMovementHeading(ctx, userId) {
|
|
|
58
65
|
export function forgetPlayerMovement(ctx, userId) {
|
|
59
66
|
stores.get(ctx)?.players.delete(userId);
|
|
60
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Rendered body yaw to commit this frame. With `turnSpeed` unset the body snaps
|
|
70
|
+
* to its movement heading exactly as before (no opt-in, no behavior change); with
|
|
71
|
+
* `turnSpeed` set it rotates toward that heading at `turnSpeed` rad/s along the
|
|
72
|
+
* shortest arc, so strafing and backpedalling read as a turning body rather than
|
|
73
|
+
* an instant flip. Retained per player so the smoothing is continuous across frames.
|
|
74
|
+
*/
|
|
75
|
+
function resolveBodyFacing(state, moving, velocityX, velocityZ, fallbackYaw, turnSpeed, dt) {
|
|
76
|
+
if (turnSpeed === undefined) {
|
|
77
|
+
const snapped = moving ? Math.atan2(velocityX, velocityZ) : fallbackYaw;
|
|
78
|
+
state.facing = snapped;
|
|
79
|
+
return snapped;
|
|
80
|
+
}
|
|
81
|
+
const from = state.facing ?? fallbackYaw;
|
|
82
|
+
const target = moving ? Math.atan2(velocityX, velocityZ) : from;
|
|
83
|
+
const next = approachYaw(from, target, turnSpeed, dt);
|
|
84
|
+
state.facing = next;
|
|
85
|
+
return next;
|
|
86
|
+
}
|
|
61
87
|
/**
|
|
62
88
|
* Integrate one player's movement for a tick from their held-input frame and commit the pose — the single
|
|
63
89
|
* genre-agnostic controller both the shell (its local player) and a host (each connected player in `onTick`) call,
|
|
@@ -80,8 +106,9 @@ export function stepPlayerMovement(ctx, userId, input, dt, tuning, heading) {
|
|
|
80
106
|
}
|
|
81
107
|
else {
|
|
82
108
|
const turnInput = (isDown("turnRight") ? 1 : 0) - (isDown("turnLeft") ? 1 : 0);
|
|
109
|
+
const turnSpeed = tuning.movement?.turnSpeed ?? DEFAULT_TURN_SPEED;
|
|
83
110
|
if (turnInput !== 0)
|
|
84
|
-
state.heading = steerYaw(state.heading, turnInput,
|
|
111
|
+
state.heading = steerYaw(state.heading, turnInput, turnSpeed, dt);
|
|
85
112
|
}
|
|
86
113
|
const forwardX = Math.sin(state.heading);
|
|
87
114
|
const forwardZ = Math.cos(state.heading);
|
|
@@ -120,7 +147,7 @@ export function stepPlayerMovement(ctx, userId, input, dt, tuning, heading) {
|
|
|
120
147
|
body.y = motionBatch.y;
|
|
121
148
|
ctx.scene.entity.setPose(playerId, {
|
|
122
149
|
position: [body.x, body.y, body.z],
|
|
123
|
-
rotationY: intent.moving
|
|
150
|
+
rotationY: resolveBodyFacing(state, intent.moving, body.velocityX, body.velocityZ, player.rotationY, tuning.movement?.turnSpeed, dt),
|
|
124
151
|
dt,
|
|
125
152
|
});
|
|
126
153
|
return;
|
|
@@ -132,7 +159,19 @@ export function stepPlayerMovement(ctx, userId, input, dt, tuning, heading) {
|
|
|
132
159
|
}
|
|
133
160
|
motion.verticalVelocity = applyMotionImpulses(motion.verticalVelocity, motionBatch);
|
|
134
161
|
[motion.horizontalVelocityX, motion.horizontalVelocityZ] = applyHorizontalImpulses(motion.horizontalVelocityX, motion.horizontalVelocityZ, motionBatch);
|
|
135
|
-
const
|
|
162
|
+
const swimCfg = tuning.movement?.swim;
|
|
163
|
+
const swimEnabled = swimCfg === true || (typeof swimCfg === "object" && swimCfg !== null);
|
|
164
|
+
const swimSpeedMultiplier = typeof swimCfg === "object" && swimCfg !== null
|
|
165
|
+
? swimCfg.speedMultiplier ?? DEFAULT_SWIM_SPEED_MULTIPLIER
|
|
166
|
+
: DEFAULT_SWIM_SPEED_MULTIPLIER;
|
|
167
|
+
const waterLevel = tuning.ground.waterLevel;
|
|
168
|
+
const submerged = swimEnabled &&
|
|
169
|
+
waterLevel !== undefined &&
|
|
170
|
+
tuning.ground.sampleHeight(player.position[0], player.position[2]) < waterLevel;
|
|
171
|
+
const motionOptions = submerged
|
|
172
|
+
? { speedScale: swimSpeedMultiplier, floating: true }
|
|
173
|
+
: undefined;
|
|
174
|
+
const step = advancePlayerMotion(motion, intent, forwardX, forwardZ, walkSpeed, dt, tuning.physics, motionOptions);
|
|
136
175
|
let stepX = step.stepX;
|
|
137
176
|
let stepZ = step.stepZ;
|
|
138
177
|
if (tuning.movement?.mode === "axis") {
|
|
@@ -153,10 +192,26 @@ export function stepPlayerMovement(ctx, userId, input, dt, tuning, heading) {
|
|
|
153
192
|
nextX = snapped[0];
|
|
154
193
|
nextZ = snapped[1];
|
|
155
194
|
}
|
|
156
|
-
|
|
195
|
+
const slideCfg = tuning.movement?.slopeSlide;
|
|
196
|
+
if (slideCfg === true || (typeof slideCfg === "object" && slideCfg !== null)) {
|
|
197
|
+
const maxClimbNormalY = typeof slideCfg === "object" && slideCfg.maxClimbSlope !== undefined
|
|
198
|
+
? slideCfg.maxClimbSlope
|
|
199
|
+
: DEFAULT_MAX_CLIMB_NORMAL_Y;
|
|
200
|
+
if (tuning.ground.sampleNormal(nextX, nextZ)[1] < maxClimbNormalY) {
|
|
201
|
+
const slope = sampleSlope(tuning.ground, nextX, nextZ);
|
|
202
|
+
const slide = SLOPE_SLIDE_SPEED * slope.steepness * dt;
|
|
203
|
+
nextX += slope.downhill[0] * slide;
|
|
204
|
+
nextZ += slope.downhill[1] * slide;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const groundAtNext = tuning.ground.sampleHeight(nextX, nextZ);
|
|
208
|
+
let nextY = groundAtNext + motion.jumpOffset;
|
|
157
209
|
if (motionBatch !== null && motionBatch.y !== null) {
|
|
158
210
|
nextY = motionBatch.y;
|
|
159
|
-
motion.jumpOffset = motionBatch.y -
|
|
211
|
+
motion.jumpOffset = motionBatch.y - groundAtNext;
|
|
212
|
+
}
|
|
213
|
+
else if (swimEnabled && waterLevel !== undefined && groundAtNext < waterLevel) {
|
|
214
|
+
nextY = waterLevel;
|
|
160
215
|
}
|
|
161
216
|
if (tuning.movement?.beforeCommit !== undefined) {
|
|
162
217
|
const frame = {
|
|
@@ -175,7 +230,7 @@ export function stepPlayerMovement(ctx, userId, input, dt, tuning, heading) {
|
|
|
175
230
|
}
|
|
176
231
|
ctx.scene.entity.setPose(playerId, {
|
|
177
232
|
position: [nextX, nextY, nextZ],
|
|
178
|
-
rotationY: intent.moving
|
|
233
|
+
rotationY: resolveBodyFacing(state, intent.moving, motion.horizontalVelocityX, motion.horizontalVelocityZ, player.rotationY, tuning.movement?.turnSpeed, dt),
|
|
179
234
|
dt,
|
|
180
235
|
});
|
|
181
236
|
}
|
|
@@ -13,11 +13,24 @@ export interface PoseAllowedStates {
|
|
|
13
13
|
export interface PoseRejection {
|
|
14
14
|
reason: string;
|
|
15
15
|
}
|
|
16
|
+
export interface PoseSnapshot {
|
|
17
|
+
poses: Record<string, MovementPose>;
|
|
18
|
+
aims: Record<string, AimMode>;
|
|
19
|
+
}
|
|
16
20
|
export interface PoseState {
|
|
17
21
|
getPose(instanceId: string): MovementPose;
|
|
18
22
|
setPose(instanceId: string, pose: MovementPose): PoseRejection | null;
|
|
19
23
|
getAim(instanceId: string): AimMode;
|
|
20
24
|
setAim(instanceId: string, mode: AimMode): PoseRejection | null;
|
|
21
25
|
clear(instanceId: string): void;
|
|
26
|
+
/** Snapshot every entity's pose and aim for a whole-world save. */
|
|
27
|
+
snapshotAll(): PoseSnapshot;
|
|
28
|
+
/** Restore every entity's pose and aim from a {@link snapshotAll} payload. */
|
|
29
|
+
hydrateAll(state: PoseSnapshot): void;
|
|
22
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Stance/pose transitions — stand, crouch, prone — that change the hitbox and movement.
|
|
33
|
+
*
|
|
34
|
+
* @capability crouch-prone stance/pose transitions that change the hitbox
|
|
35
|
+
*/
|
|
23
36
|
export declare function createPoseState(resolveAllowed: (instanceId: string) => PoseAllowedStates | null | undefined): PoseState;
|