@jgengine/core 0.9.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 +34 -3
- 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 +19 -1
- package/dist/ai/spawnDirector.js +53 -26
- package/dist/ai/spawnPoint.d.ts +7 -0
- package/dist/ai/spawnPoint.js +7 -0
- 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/audio/audioFalloff.d.ts +5 -2
- package/dist/audio/music.d.ts +53 -0
- package/dist/audio/music.js +34 -0
- package/dist/audio/synth.d.ts +60 -0
- package/dist/audio/synth.js +8 -0
- package/dist/authoring.d.ts +15 -0
- package/dist/authoring.js +15 -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 +47 -0
- package/dist/combat/dotField.js +52 -0
- 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 +7 -2
- package/dist/combat/projectiles.js +48 -17
- package/dist/combat/receivedDamage.d.ts +117 -0
- package/dist/combat/receivedDamage.js +92 -0
- package/dist/combat/regenShield.d.ts +39 -0
- package/dist/combat/regenShield.js +49 -0
- 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 +30 -1
- package/dist/combat/shotOrigin.js +70 -2
- 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 +248 -0
- package/dist/editor/commands.js +865 -0
- package/dist/editor/document.d.ts +186 -0
- package/dist/editor/document.js +884 -0
- 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 +97 -0
- package/dist/editor/index.js +10 -0
- 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 +175 -0
- package/dist/editor/types.js +29 -0
- 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 +30 -0
- package/dist/game/connectedPlayers.js +21 -0
- package/dist/game/cosmetics.d.ts +9 -0
- package/dist/game/cosmetics.js +16 -0
- package/dist/game/defineGame.d.ts +141 -2
- package/dist/game/defineGame.js +39 -1
- 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 +50 -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/keyValueStore.d.ts +25 -0
- package/dist/game/keyValueStore.js +61 -0
- package/dist/game/leaderboard.d.ts +5 -0
- package/dist/game/leaderboard.js +5 -0
- package/dist/game/levelSequence.d.ts +24 -2
- package/dist/game/levelSequence.js +51 -2
- 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 +21 -0
- package/dist/game/lootTable.js +15 -4
- package/dist/game/modelAnimation.d.ts +8 -0
- package/dist/game/modelAnimation.js +18 -0
- 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 +160 -12
- 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 +5 -5
- 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 -7
- package/dist/index.js +5 -7
- package/dist/input/actionBindings.d.ts +24 -5
- package/dist/input/actionBindings.js +23 -5
- package/dist/input/axisInput.d.ts +13 -1
- package/dist/input/axisInput.js +22 -1
- 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/contextMenu.d.ts +1 -0
- package/dist/interaction/contextMenu.js +1 -0
- package/dist/interaction/lockpick.d.ts +61 -0
- package/dist/interaction/lockpick.js +168 -0
- package/dist/interaction/proximityPrompt.d.ts +5 -1
- package/dist/interaction/proximityPrompt.js +5 -3
- 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 +36 -1
- 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 +38 -7
- package/dist/movement/movementModel.js +54 -13
- package/dist/movement/playerMovement.d.ts +41 -0
- package/dist/movement/playerMovement.js +236 -0
- 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 +24 -0
- package/dist/random/rng.js +30 -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 +76 -0
- package/dist/render/postProcessing.js +21 -0
- 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 +58 -0
- package/dist/runtime/adapter.js +54 -5
- 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 +163 -19
- package/dist/runtime/gameContext.js +385 -339
- 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 +54 -0
- package/dist/runtime/hostedGameRunner.js +85 -0
- package/dist/runtime/hostedWorldSession.d.ts +73 -0
- package/dist/runtime/hostedWorldSession.js +64 -0
- package/dist/runtime/inputSnapshot.d.ts +21 -3
- package/dist/runtime/inputSnapshot.js +8 -2
- package/dist/runtime/motionIntents.d.ts +12 -1
- package/dist/runtime/motionIntents.js +26 -1
- 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 +62 -0
- package/dist/runtime/worldChannel.js +114 -0
- package/dist/runtime/worldMirror.d.ts +36 -0
- package/dist/runtime/worldMirror.js +44 -0
- package/dist/runtime/worldProjection.d.ts +47 -0
- package/dist/runtime/worldProjection.js +52 -0
- package/dist/runtime/worldReplication.d.ts +69 -0
- package/dist/runtime/worldReplication.js +217 -0
- package/dist/runtime/worldSnapshot.d.ts +44 -0
- package/dist/runtime/worldSnapshot.js +30 -0
- package/dist/scene/assetCatalog.d.ts +22 -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 +18 -0
- package/dist/scene/colliders.js +61 -1
- package/dist/scene/entityStats.d.ts +13 -0
- package/dist/scene/entityStats.js +30 -0
- package/dist/scene/entityStore.d.ts +41 -1
- package/dist/scene/entityStore.js +75 -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 +9 -0
- package/dist/store/observableKeyedStore.js +43 -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 +6 -4
- package/dist/tactics/fallingGrid.js +6 -4
- 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 +144 -0
- package/dist/ui/gameLayout.js +148 -0
- 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/orientation.d.ts +39 -0
- package/dist/ui/orientation.js +49 -0
- package/dist/ui/selectionModel.d.ts +92 -0
- package/dist/ui/selectionModel.js +88 -0
- package/dist/ui/swingTimer.d.ts +42 -0
- package/dist/ui/swingTimer.js +38 -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/visibility/spatialIndex.js +34 -20
- 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/environmentSummary.d.ts +11 -2
- package/dist/world/environmentSummary.js +11 -1
- package/dist/world/features.d.ts +244 -7
- package/dist/world/features.js +92 -4
- 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 +55 -0
- package/dist/world/roads.js +184 -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/streets.d.ts +80 -0
- package/dist/world/streets.js +144 -0
- package/dist/world/terraform.d.ts +213 -1
- package/dist/world/terraform.js +655 -20
- package/dist/world/terrain.d.ts +138 -12
- package/dist/world/terrain.js +346 -28
- 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 -4983
|
@@ -43,4 +43,5 @@ export type GameRuntime = {
|
|
|
43
43
|
joinPlayer: (snapshot: GameRuntimeSnapshot, userId: string, isNew: boolean) => GameRuntimeSnapshot;
|
|
44
44
|
toProfileRow: (snapshot: GameRuntimeSnapshot, userId: string) => RuntimeProfileRow | null;
|
|
45
45
|
};
|
|
46
|
+
/** @internal */
|
|
46
47
|
export declare function createGameRuntime(definition: GameRuntimeDefinition): GameRuntime;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { GameDefinition, GameLoop } from "../game/defineGame.js";
|
|
2
|
+
import type { PointerAxisState } from "../input/pointerAxis.js";
|
|
3
|
+
import type { ModelAssetRef } from "../scene/assetCatalog.js";
|
|
4
|
+
import { type GameContext, type GameContextContent } from "./gameContext.js";
|
|
5
|
+
import type { InputSnapshot } from "./inputSnapshot.js";
|
|
6
|
+
/** One step's worth of player intent handed to {@link HeadlessRunner.step} — the held-action set and pointer state the shell would otherwise publish from the browser each frame. */
|
|
7
|
+
export interface HeadlessInput {
|
|
8
|
+
/** Replaces the held-action set for this step; edge detection (`justPressed`/`justReleased`) rolls the previous set forward. Omit to keep the last published set. */
|
|
9
|
+
held?: readonly string[];
|
|
10
|
+
/** Replaces the normalized pointer state; omit to leave the last pointer unchanged (pass `null` to clear it). */
|
|
11
|
+
pointer?: PointerAxisState | null;
|
|
12
|
+
}
|
|
13
|
+
export interface HeadlessRunnerOptions<TAssetRef extends ModelAssetRef, TMultiplayer> {
|
|
14
|
+
definition: GameDefinition<TAssetRef, TMultiplayer>;
|
|
15
|
+
/** Catalog resolvers (`entityById`/`objectById`) the context uses; defaults to an empty catalog. */
|
|
16
|
+
content?: GameContextContent;
|
|
17
|
+
/** Lifecycle hooks — `onInit`/`onNewPlayer` fire at construction, `onTick` on every {@link HeadlessRunner.step}. The shell keeps this separate from `definition` (presentation wraps it); a headless caller passes it directly. */
|
|
18
|
+
loop?: GameLoop<GameContext>;
|
|
19
|
+
/** The single local player; defaults to `{ userId: "player", isNew: true }`. */
|
|
20
|
+
player?: {
|
|
21
|
+
userId: string;
|
|
22
|
+
isNew: boolean;
|
|
23
|
+
};
|
|
24
|
+
/** Wall-clock source for the sim clock — inject a deterministic counter for reproducible runs. */
|
|
25
|
+
now?: () => number;
|
|
26
|
+
/** Per-step real-dt clamp in seconds, matching the shell's frame cap so one long stall can't fast-forward the sim. Default `0.05`. */
|
|
27
|
+
maxStepSeconds?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Drive the built-in keyboard player-movement controller from the held-action set each step, exactly as the shell's
|
|
30
|
+
* FrameDriver does for pose-driven games. Off by default — cartridge/tick-driven games move their own entities inside
|
|
31
|
+
* `onTick` and don't need it.
|
|
32
|
+
*/
|
|
33
|
+
playerMovement?: boolean;
|
|
34
|
+
/** Yaw heading (radians) fed to the movement controller when `playerMovement` is on; the shell supplies its camera yaw. */
|
|
35
|
+
heading?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A renderer-free driver for a game loop: builds a {@link GameContext} from a {@link GameDefinition}, runs the init
|
|
39
|
+
* hooks, then advances the simulation one step at a time from injected input. No React, R3F, or three.js — the whole
|
|
40
|
+
* play path (time, input, `onTick`, behaviour nav, optional player movement) runs from `core` primitives alone, so a
|
|
41
|
+
* non-React host (a server tick, a test, a CLI replay) can play a real game and read its world snapshot. The shell's
|
|
42
|
+
* FrameDriver is one such driver bolted to `useFrame`; this is the same step distilled out of the render tree.
|
|
43
|
+
*
|
|
44
|
+
* @capability headless-runner play a real game loop with no renderer — tick, feed input, read the world snapshot
|
|
45
|
+
*/
|
|
46
|
+
export interface HeadlessRunner {
|
|
47
|
+
/** The live game context — read `ctx.scene.entity.list()`, `ctx.game.store`, `ctx.subscribe`/`ctx.version()` for the world snapshot. */
|
|
48
|
+
readonly ctx: GameContext;
|
|
49
|
+
/** The per-frame input the loop reads; the same object exposed as `ctx.input`. */
|
|
50
|
+
readonly input: InputSnapshot;
|
|
51
|
+
readonly userId: string;
|
|
52
|
+
/**
|
|
53
|
+
* Advance the simulation one step. Publishes `input` (if given), advances the sim clock by the clamped real dt,
|
|
54
|
+
* runs optional player movement, then `loop.onTick` and behaviour nav. Returns the scaled game dt `onTick` saw.
|
|
55
|
+
*/
|
|
56
|
+
step(dtSeconds: number, input?: HeadlessInput): number;
|
|
57
|
+
/** Publish input without advancing — for pre-seeding the held set before the first {@link step}. */
|
|
58
|
+
publishInput(input: HeadlessInput): void;
|
|
59
|
+
}
|
|
60
|
+
export declare function createHeadlessRunner<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HeadlessRunnerOptions<TAssetRef, TMultiplayer>): HeadlessRunner;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { resolvePlayerMovementTuning, stepPlayerMovement, } from "../movement/playerMovement.js";
|
|
2
|
+
import { advanceBehaviors } from "../scene/behaviorRuntime.js";
|
|
3
|
+
import { createGameContext } from "./gameContext.js";
|
|
4
|
+
export function createHeadlessRunner(options) {
|
|
5
|
+
const { definition, loop } = options;
|
|
6
|
+
const content = options.content ?? {};
|
|
7
|
+
const player = options.player ?? { userId: "player", isNew: true };
|
|
8
|
+
const maxStep = options.maxStepSeconds ?? 0.05;
|
|
9
|
+
const ctx = createGameContext({
|
|
10
|
+
definition,
|
|
11
|
+
content,
|
|
12
|
+
player,
|
|
13
|
+
...(options.now === undefined ? {} : { now: options.now }),
|
|
14
|
+
});
|
|
15
|
+
loop?.onInit?.(ctx);
|
|
16
|
+
loop?.onNewPlayer?.(ctx);
|
|
17
|
+
const tuning = options.playerMovement === true
|
|
18
|
+
? resolvePlayerMovementTuning({ physics: definition.physics, world: definition.world })
|
|
19
|
+
: null;
|
|
20
|
+
function publishInput(input) {
|
|
21
|
+
if (input.held !== undefined)
|
|
22
|
+
ctx.input.publish(input.held);
|
|
23
|
+
if (input.pointer !== undefined)
|
|
24
|
+
ctx.input.publishPointer(input.pointer);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
ctx,
|
|
28
|
+
input: ctx.input,
|
|
29
|
+
userId: player.userId,
|
|
30
|
+
publishInput,
|
|
31
|
+
step(dtSeconds, input) {
|
|
32
|
+
if (input !== undefined)
|
|
33
|
+
publishInput(input);
|
|
34
|
+
const dt = Math.min(dtSeconds, maxStep);
|
|
35
|
+
const gameDt = ctx.time.advance(dt);
|
|
36
|
+
if (tuning !== null) {
|
|
37
|
+
stepPlayerMovement(ctx, player.userId, { held: ctx.input.held(), pointer: ctx.input.pointer() }, dt, tuning, options.heading);
|
|
38
|
+
}
|
|
39
|
+
loop?.onTick?.(ctx, gameDt);
|
|
40
|
+
advanceBehaviors(ctx, gameDt);
|
|
41
|
+
return gameDt;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -58,11 +58,13 @@ export type LeaderboardEntry = {
|
|
|
58
58
|
value: number;
|
|
59
59
|
};
|
|
60
60
|
export declare const LEADERBOARD_PENDING_KEY = "leaderboardPending";
|
|
61
|
+
/** @internal */
|
|
61
62
|
export declare function drainPendingLeaderboardIncrements(session: Record<string, unknown>): {
|
|
62
63
|
increments: LeaderboardIncrement[];
|
|
63
64
|
session: Record<string, unknown>;
|
|
64
65
|
};
|
|
65
66
|
export declare const LEADERBOARD_TOP_LIMIT = 100;
|
|
67
|
+
/** @internal */
|
|
66
68
|
export declare function clampLimit(value: number | undefined, fallback: number, max: number): number;
|
|
67
69
|
export type LeaderboardRow = {
|
|
68
70
|
gameId: string;
|
|
@@ -73,8 +75,11 @@ export type LeaderboardRow = {
|
|
|
73
75
|
value: number;
|
|
74
76
|
updatedAt: number;
|
|
75
77
|
};
|
|
78
|
+
/** @internal */
|
|
76
79
|
export declare function leaderboardRowKey(row: Omit<LeaderboardRow, "value" | "updatedAt">): string;
|
|
80
|
+
/** @internal */
|
|
77
81
|
export declare function applyLeaderboardRows(rows: Map<string, LeaderboardRow>, gameId: string, entries: LeaderboardIncrement[], now: number): void;
|
|
82
|
+
/** @internal */
|
|
78
83
|
export declare function topLeaderboardRows(rows: Iterable<LeaderboardRow>, args: {
|
|
79
84
|
gameId: string;
|
|
80
85
|
stat: string;
|
|
@@ -82,9 +87,12 @@ export declare function topLeaderboardRows(rows: Iterable<LeaderboardRow>, args:
|
|
|
82
87
|
serverId?: string;
|
|
83
88
|
limit?: number;
|
|
84
89
|
}): LeaderboardEntry[];
|
|
90
|
+
/** @internal */
|
|
85
91
|
export declare function profileLeaderboardStats(rows: Iterable<LeaderboardRow>, gameId: string, userId: string): Record<string, number>;
|
|
86
92
|
export declare const FEED_RING_LIMIT = 20;
|
|
93
|
+
/** @internal */
|
|
87
94
|
export declare function trimFeedEntries<T>(entries: T[], limit?: number): T[];
|
|
95
|
+
/** @internal */
|
|
88
96
|
export declare function shouldAutoSave(save: SaveConfig, dirtyAt: number | undefined, lastSavedAt: number | undefined, now: number): boolean;
|
|
89
97
|
export type ServerListing = {
|
|
90
98
|
serverId: string;
|
|
@@ -101,9 +109,11 @@ export type ServerListing = {
|
|
|
101
109
|
export type ToServerListingOptions = {
|
|
102
110
|
includeJoinCode?: boolean;
|
|
103
111
|
};
|
|
112
|
+
/** @internal */
|
|
104
113
|
export declare function toServerListing(record: GameServerRecord, options?: ToServerListingOptions): ServerListing;
|
|
105
114
|
export declare const OPEN_SERVER_LISTING_LIMIT = 20;
|
|
106
115
|
export declare const OPEN_SERVER_LISTING_MAX = 100;
|
|
116
|
+
/** @internal */
|
|
107
117
|
export declare function toOpenServerListings(listings: Iterable<ServerListing>, limit?: number): ServerListing[];
|
|
108
118
|
export type HostPersistence = {
|
|
109
119
|
savePlan?: (plan: ServerPersistPlan) => Promise<void>;
|
|
@@ -141,6 +151,7 @@ export type HostPersistence = {
|
|
|
141
151
|
userId: string;
|
|
142
152
|
}) => Promise<Record<string, number>>;
|
|
143
153
|
};
|
|
154
|
+
/** @internal */
|
|
144
155
|
export declare function buildHydratePlayers(server: GameServerRecord, profiles: Record<string, PlayerProfileRecord | null>): Record<string, RuntimePlayerRow>;
|
|
145
156
|
export type ServerPersistPlan = {
|
|
146
157
|
server: GameServerRecord;
|
|
@@ -149,4 +160,5 @@ export type ServerPersistPlan = {
|
|
|
149
160
|
deletedChunks: string[];
|
|
150
161
|
leaderboard: LeaderboardIncrement[];
|
|
151
162
|
};
|
|
163
|
+
/** @internal */
|
|
152
164
|
export declare function planServerPersist(server: GameServerRecord, snapshot: GameRuntimeSnapshot, save: SaveConfig, now: number): ServerPersistPlan;
|
|
@@ -11,6 +11,7 @@ function isLeaderboardIncrement(value) {
|
|
|
11
11
|
typeof candidate.by === "number" &&
|
|
12
12
|
(candidate.serverId === undefined || typeof candidate.serverId === "string"));
|
|
13
13
|
}
|
|
14
|
+
/** @internal */
|
|
14
15
|
export function drainPendingLeaderboardIncrements(session) {
|
|
15
16
|
const raw = session[LEADERBOARD_PENDING_KEY];
|
|
16
17
|
if (!Array.isArray(raw) || raw.length === 0) {
|
|
@@ -21,15 +22,18 @@ export function drainPendingLeaderboardIncrements(session) {
|
|
|
21
22
|
return { increments: raw.filter(isLeaderboardIncrement), session: rest };
|
|
22
23
|
}
|
|
23
24
|
export const LEADERBOARD_TOP_LIMIT = 100;
|
|
25
|
+
/** @internal */
|
|
24
26
|
export function clampLimit(value, fallback, max) {
|
|
25
27
|
const candidate = value ?? fallback;
|
|
26
28
|
if (!Number.isFinite(candidate))
|
|
27
29
|
return fallback;
|
|
28
30
|
return Math.min(Math.max(Math.floor(candidate), 1), max);
|
|
29
31
|
}
|
|
32
|
+
/** @internal */
|
|
30
33
|
export function leaderboardRowKey(row) {
|
|
31
34
|
return [row.gameId, row.scope, row.stat, row.serverId ?? "", row.userId].join("|");
|
|
32
35
|
}
|
|
36
|
+
/** @internal */
|
|
33
37
|
export function applyLeaderboardRows(rows, gameId, entries, now) {
|
|
34
38
|
for (const entry of entries) {
|
|
35
39
|
const key = leaderboardRowKey({ ...entry, gameId });
|
|
@@ -50,6 +54,7 @@ export function applyLeaderboardRows(rows, gameId, entries, now) {
|
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
}
|
|
57
|
+
/** @internal */
|
|
53
58
|
export function topLeaderboardRows(rows, args) {
|
|
54
59
|
const limit = clampLimit(args.limit, LEADERBOARD_TOP_LIMIT, LEADERBOARD_TOP_LIMIT);
|
|
55
60
|
return [...rows]
|
|
@@ -61,6 +66,7 @@ export function topLeaderboardRows(rows, args) {
|
|
|
61
66
|
.slice(0, limit)
|
|
62
67
|
.map((row) => ({ userId: row.userId, value: row.value }));
|
|
63
68
|
}
|
|
69
|
+
/** @internal */
|
|
64
70
|
export function profileLeaderboardStats(rows, gameId, userId) {
|
|
65
71
|
const profile = {};
|
|
66
72
|
for (const row of rows) {
|
|
@@ -71,11 +77,13 @@ export function profileLeaderboardStats(rows, gameId, userId) {
|
|
|
71
77
|
return profile;
|
|
72
78
|
}
|
|
73
79
|
export const FEED_RING_LIMIT = 20;
|
|
80
|
+
/** @internal */
|
|
74
81
|
export function trimFeedEntries(entries, limit = FEED_RING_LIMIT) {
|
|
75
82
|
if (entries.length <= limit)
|
|
76
83
|
return entries;
|
|
77
84
|
return entries.slice(entries.length - limit);
|
|
78
85
|
}
|
|
86
|
+
/** @internal */
|
|
79
87
|
export function shouldAutoSave(save, dirtyAt, lastSavedAt, now) {
|
|
80
88
|
if (!isSaveEnabled(save))
|
|
81
89
|
return false;
|
|
@@ -85,6 +93,7 @@ export function shouldAutoSave(save, dirtyAt, lastSavedAt, now) {
|
|
|
85
93
|
const anchor = lastSavedAt ?? 0;
|
|
86
94
|
return now - anchor >= intervalMs;
|
|
87
95
|
}
|
|
96
|
+
/** @internal */
|
|
88
97
|
export function toServerListing(record, options = {}) {
|
|
89
98
|
return {
|
|
90
99
|
serverId: record.serverId,
|
|
@@ -103,12 +112,14 @@ export function toServerListing(record, options = {}) {
|
|
|
103
112
|
}
|
|
104
113
|
export const OPEN_SERVER_LISTING_LIMIT = 20;
|
|
105
114
|
export const OPEN_SERVER_LISTING_MAX = 100;
|
|
115
|
+
/** @internal */
|
|
106
116
|
export function toOpenServerListings(listings, limit = OPEN_SERVER_LISTING_LIMIT) {
|
|
107
117
|
return [...listings]
|
|
108
118
|
.filter((listing) => listing.status === "running")
|
|
109
119
|
.sort((a, b) => b.updatedAt - a.updatedAt)
|
|
110
120
|
.slice(0, clampLimit(limit, OPEN_SERVER_LISTING_LIMIT, OPEN_SERVER_LISTING_MAX));
|
|
111
121
|
}
|
|
122
|
+
/** @internal */
|
|
112
123
|
export function buildHydratePlayers(server, profiles) {
|
|
113
124
|
const players = {};
|
|
114
125
|
for (const userId of server.memberUserIds) {
|
|
@@ -129,6 +140,7 @@ export function buildHydratePlayers(server, profiles) {
|
|
|
129
140
|
}
|
|
130
141
|
return players;
|
|
131
142
|
}
|
|
143
|
+
/** @internal */
|
|
132
144
|
export function planServerPersist(server, snapshot, save, now) {
|
|
133
145
|
const drained = drainPendingLeaderboardIncrements(snapshot.server.session);
|
|
134
146
|
const serverState = drained.increments.length > 0 ? { ...snapshot.server, session: drained.session } : snapshot.server;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { CommandResult } from "../commands/commandRegistry.js";
|
|
2
|
+
import type { GameDefinition, LoopPlayer } from "../game/defineGame.js";
|
|
3
|
+
import type { ModelAssetRef } from "../scene/assetCatalog.js";
|
|
4
|
+
import { type GameContext, type GameContextContent } from "./gameContext.js";
|
|
5
|
+
import { type InputFrame } from "./inputSnapshot.js";
|
|
6
|
+
import { type WorldDiff } from "./worldReplication.js";
|
|
7
|
+
import type { SnapshotViewer, WorldSnapshot } from "./worldSnapshot.js";
|
|
8
|
+
export type { InputFrame };
|
|
9
|
+
/** Reserved command name the authoritative host intercepts on the existing `runCommand` transport to route a client's {@link InputFrame} to `session.input`, so per-tick input needs no separate wire. */
|
|
10
|
+
export declare const INPUT_COMMAND = "engine.input";
|
|
11
|
+
/** Config for {@link createHostedGameRunner}: the game definition, its content lookup, and an optional host identity. */
|
|
12
|
+
export interface HostedGameRunnerOptions<TAssetRef extends ModelAssetRef, TMultiplayer> {
|
|
13
|
+
definition: GameDefinition<TAssetRef, TMultiplayer>;
|
|
14
|
+
content: GameContextContent;
|
|
15
|
+
/** The world's own authoritative identity (`ctx.player` server-side); real players join as members. */
|
|
16
|
+
host?: LoopPlayer;
|
|
17
|
+
now?: () => number;
|
|
18
|
+
/**
|
|
19
|
+
* Rehydrate a persisted world instead of booting a fresh one — for stateless hosts (Convex) that reconstruct
|
|
20
|
+
* the runner each invocation. `onInit` still runs (so commands and systems it registers exist), then this
|
|
21
|
+
* snapshot overlays the world state it seeded. Omit for a long-lived stateful host (ws) that keeps one runner.
|
|
22
|
+
*/
|
|
23
|
+
restore?: WorldSnapshot;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The GameContext-loop equivalent of the pure-reducer `createGameHost`: one authoritative `createGameContext`
|
|
27
|
+
* per world, driven server-side. `onInit` runs once at construction; `onNewPlayer`/`onPlayerLeave` fire per
|
|
28
|
+
* join/leave; `tick` advances `onTick` then commits a revision. Clients pull a full {@link WorldSnapshot}
|
|
29
|
+
* baseline once, then per-tick {@link WorldDiff}s from their last revision. Games ship only normal GameContext
|
|
30
|
+
* code — the runner adds no per-game surface.
|
|
31
|
+
*/
|
|
32
|
+
export interface HostedGameRunner {
|
|
33
|
+
join(userId: string, isNew: boolean): void;
|
|
34
|
+
/** Re-attach an already-joined member on a reconstructed runner — restores membership and `ctx.game.players` without re-firing `onNewPlayer`. Stateless hosts call it once per persisted member after `restore`. */
|
|
35
|
+
resume(userId: string): void;
|
|
36
|
+
leave(userId: string): void;
|
|
37
|
+
/** Record a client's latest input frame — stashed for {@link heldInput} and mirrored onto `ctx.game.players` so the movement seam reads each player's intent in `onTick`. */
|
|
38
|
+
input(userId: string, frame: InputFrame): void;
|
|
39
|
+
heldInput(userId: string): InputFrame | null;
|
|
40
|
+
command(userId: string, name: string, input: unknown): CommandResult<GameContext>;
|
|
41
|
+
tick(dt: number): number;
|
|
42
|
+
diff(sinceRevision: number): WorldDiff;
|
|
43
|
+
revision(): number;
|
|
44
|
+
/** The full world baseline — projected to only what `viewer` may see when the context carries a replication policy, else the whole world. */
|
|
45
|
+
snapshot(viewer?: SnapshotViewer): WorldSnapshot;
|
|
46
|
+
/** True when {@link snapshot} is viewer-dependent (a replication policy projects private/AOI state); a host must then serve each viewer its own frame. */
|
|
47
|
+
projectsViewers(): boolean;
|
|
48
|
+
members(): readonly string[];
|
|
49
|
+
context(): GameContext;
|
|
50
|
+
}
|
|
51
|
+
/** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop.
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
export declare function createHostedGameRunner<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HostedGameRunnerOptions<TAssetRef, TMultiplayer>): HostedGameRunner;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { syncLifecyclePhase } from "../game/gamePhase.js";
|
|
2
|
+
import { advanceBehaviors } from "../scene/behaviorRuntime.js";
|
|
3
|
+
import { createGameContext } from "./gameContext.js";
|
|
4
|
+
import {} from "./inputSnapshot.js";
|
|
5
|
+
import { createWorldReplicator } from "./worldReplication.js";
|
|
6
|
+
/** Reserved command name the authoritative host intercepts on the existing `runCommand` transport to route a client's {@link InputFrame} to `session.input`, so per-tick input needs no separate wire. */
|
|
7
|
+
export const INPUT_COMMAND = "engine.input";
|
|
8
|
+
/** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop.
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export function createHostedGameRunner(options) {
|
|
12
|
+
const { definition, content, host, now, restore } = options;
|
|
13
|
+
const ctx = createGameContext({
|
|
14
|
+
definition,
|
|
15
|
+
content,
|
|
16
|
+
player: host ?? { userId: "host", isNew: true },
|
|
17
|
+
...(now === undefined ? {} : { now }),
|
|
18
|
+
...(definition.replication === undefined ? {} : { replication: definition.replication }),
|
|
19
|
+
});
|
|
20
|
+
const loop = definition.loop ?? {};
|
|
21
|
+
const replicator = createWorldReplicator(() => ctx.snapshot(), {
|
|
22
|
+
worldVersion: () => ctx.replicationVersion(),
|
|
23
|
+
});
|
|
24
|
+
const members = new Map();
|
|
25
|
+
const inputs = new Map();
|
|
26
|
+
const inputSeq = new Map();
|
|
27
|
+
loop.onInit?.(ctx);
|
|
28
|
+
syncLifecyclePhase(ctx, definition.lifecycle);
|
|
29
|
+
if (restore !== undefined)
|
|
30
|
+
ctx.hydrate(restore);
|
|
31
|
+
return {
|
|
32
|
+
join(userId, isNew) {
|
|
33
|
+
if (members.has(userId))
|
|
34
|
+
return;
|
|
35
|
+
const player = { userId, isNew };
|
|
36
|
+
members.set(userId, player);
|
|
37
|
+
ctx.game.players?.join(userId, isNew);
|
|
38
|
+
loop.onNewPlayer?.(ctx, player);
|
|
39
|
+
syncLifecyclePhase(ctx, definition.lifecycle);
|
|
40
|
+
},
|
|
41
|
+
resume(userId) {
|
|
42
|
+
members.set(userId, { userId, isNew: false });
|
|
43
|
+
ctx.game.players?.join(userId, false);
|
|
44
|
+
},
|
|
45
|
+
leave(userId) {
|
|
46
|
+
const player = members.get(userId);
|
|
47
|
+
if (player === undefined)
|
|
48
|
+
return;
|
|
49
|
+
members.delete(userId);
|
|
50
|
+
inputs.delete(userId);
|
|
51
|
+
inputSeq.delete(userId);
|
|
52
|
+
loop.onPlayerLeave?.(ctx, player);
|
|
53
|
+
ctx.game.players?.leave(userId);
|
|
54
|
+
},
|
|
55
|
+
input(userId, frame) {
|
|
56
|
+
const seq = frame.seq;
|
|
57
|
+
if (seq !== undefined) {
|
|
58
|
+
const lastSeq = inputSeq.get(userId);
|
|
59
|
+
if (lastSeq !== undefined && seq <= lastSeq)
|
|
60
|
+
return;
|
|
61
|
+
inputSeq.set(userId, seq);
|
|
62
|
+
}
|
|
63
|
+
inputs.set(userId, frame);
|
|
64
|
+
ctx.game.players?.setInput(userId, frame);
|
|
65
|
+
},
|
|
66
|
+
heldInput(userId) {
|
|
67
|
+
return inputs.get(userId) ?? null;
|
|
68
|
+
},
|
|
69
|
+
command(userId, name, input) {
|
|
70
|
+
return ctx.game.commands.runAs(userId, name, input);
|
|
71
|
+
},
|
|
72
|
+
tick(dt) {
|
|
73
|
+
loop.onTick?.(ctx, dt);
|
|
74
|
+
advanceBehaviors(ctx, dt);
|
|
75
|
+
syncLifecyclePhase(ctx, definition.lifecycle);
|
|
76
|
+
return replicator.commit();
|
|
77
|
+
},
|
|
78
|
+
diff: (sinceRevision) => replicator.diff(sinceRevision),
|
|
79
|
+
revision: () => replicator.revision(),
|
|
80
|
+
snapshot: (viewer) => ctx.snapshot(viewer),
|
|
81
|
+
projectsViewers: () => ctx.replicatesPerViewer(),
|
|
82
|
+
members: () => Array.from(members.keys()),
|
|
83
|
+
context: () => ctx,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { CommandResult } from "../commands/commandRegistry.js";
|
|
2
|
+
import type { ModelAssetRef } from "../scene/assetCatalog.js";
|
|
3
|
+
import type { GameContext, GameContextContent } from "./gameContext.js";
|
|
4
|
+
import type { GameDefinition, LoopPlayer } from "../game/defineGame.js";
|
|
5
|
+
import { type HostedGameRunner, type InputFrame } from "./hostedGameRunner.js";
|
|
6
|
+
import type { WorldDiff } from "./worldReplication.js";
|
|
7
|
+
import type { SnapshotViewer, WorldSnapshot } from "./worldSnapshot.js";
|
|
8
|
+
/** One hosted world's persisted authoritative state — the unit a {@link HostedWorldStore} loads and saves. */
|
|
9
|
+
export interface HostedWorldRecord {
|
|
10
|
+
snapshot: WorldSnapshot;
|
|
11
|
+
revision: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Narrow persistence seam for a hosted world — the {@link HostedWorldRecord} counterpart of `HostPersistence`.
|
|
15
|
+
* Backends implement it (memory/file/sql/convex); the session never names one. A stateful host loads once and
|
|
16
|
+
* saves on a cadence; a stateless host reconstructs from `load()` each invocation.
|
|
17
|
+
*/
|
|
18
|
+
export interface HostedWorldStore {
|
|
19
|
+
load(): HostedWorldRecord | null;
|
|
20
|
+
save(record: HostedWorldRecord): void;
|
|
21
|
+
}
|
|
22
|
+
/** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host.
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export declare function memoryWorldStore(seed?: HostedWorldRecord): HostedWorldStore;
|
|
26
|
+
/** A client replication pull: a full baseline (first sync / fell behind) or a diff since the client's cursor. */
|
|
27
|
+
export type HostedWorldSync = {
|
|
28
|
+
kind: "baseline";
|
|
29
|
+
revision: number;
|
|
30
|
+
snapshot: WorldSnapshot;
|
|
31
|
+
} | {
|
|
32
|
+
kind: "diff";
|
|
33
|
+
diff: WorldDiff;
|
|
34
|
+
};
|
|
35
|
+
/** Config for {@link createHostedWorldSession}: the game, its persistence store, and the auto-save cadence. */
|
|
36
|
+
export interface HostedWorldSessionOptions<TAssetRef extends ModelAssetRef, TMultiplayer> {
|
|
37
|
+
definition: GameDefinition<TAssetRef, TMultiplayer>;
|
|
38
|
+
content: GameContextContent;
|
|
39
|
+
host?: LoopPlayer;
|
|
40
|
+
now?: () => number;
|
|
41
|
+
/** Where the authoritative snapshot persists; defaults to {@link memoryWorldStore}. */
|
|
42
|
+
store?: HostedWorldStore;
|
|
43
|
+
/** Minimum elapsed ms between auto-saves on tick, measured against `now` (defaults to `Date.now` when omitted). Default `0` — persist on every revision-changing tick. */
|
|
44
|
+
saveIntervalMs?: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The stateful host substrate a long-lived backend binds (ws server, browser P2P host): a live
|
|
48
|
+
* {@link HostedGameRunner} loaded from a {@link HostedWorldStore}, auto-persisted on tick, serving each client a
|
|
49
|
+
* baseline then diffs. The stateless Convex path doesn't use this — it reconstructs a runner from the same store
|
|
50
|
+
* per invocation and diffs with `diffSnapshots`. Either way the store seam and the game code are identical.
|
|
51
|
+
*/
|
|
52
|
+
export interface HostedWorldSession {
|
|
53
|
+
join(userId: string, isNew: boolean): void;
|
|
54
|
+
leave(userId: string): void;
|
|
55
|
+
input(userId: string, frame: InputFrame): void;
|
|
56
|
+
command(userId: string, name: string, input: unknown): CommandResult<GameContext>;
|
|
57
|
+
tick(dt: number): number;
|
|
58
|
+
/** Replication pull: `null`/`0` cursor → full baseline; a prior revision → a diff since it. */
|
|
59
|
+
sync(sinceRevision: number | null): HostedWorldSync;
|
|
60
|
+
/** The full world baseline projected for one viewer (private/AOI). Identity when no replication policy is set. */
|
|
61
|
+
snapshotFor(viewer: SnapshotViewer): WorldSnapshot;
|
|
62
|
+
/** True when {@link snapshotFor} is viewer-dependent — a host must serve each connection its own projected frame instead of a shared diff. */
|
|
63
|
+
projectsViewers(): boolean;
|
|
64
|
+
revision(): number;
|
|
65
|
+
members(): readonly string[];
|
|
66
|
+
/** Force-persist the current world to the store. */
|
|
67
|
+
save(): void;
|
|
68
|
+
runner(): HostedGameRunner;
|
|
69
|
+
}
|
|
70
|
+
/** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick.
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
73
|
+
export declare function createHostedWorldSession<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HostedWorldSessionOptions<TAssetRef, TMultiplayer>): HostedWorldSession;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { createHostedGameRunner } from "./hostedGameRunner.js";
|
|
2
|
+
/** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
export function memoryWorldStore(seed) {
|
|
6
|
+
let record = seed ?? null;
|
|
7
|
+
return {
|
|
8
|
+
load: () => record,
|
|
9
|
+
save(next) {
|
|
10
|
+
record = { snapshot: next.snapshot, revision: next.revision };
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick.
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export function createHostedWorldSession(options) {
|
|
18
|
+
const { definition, content, host, now, saveIntervalMs = 0 } = options;
|
|
19
|
+
const clock = now ?? Date.now;
|
|
20
|
+
const store = options.store ?? memoryWorldStore();
|
|
21
|
+
const loaded = store.load();
|
|
22
|
+
const runner = createHostedGameRunner({
|
|
23
|
+
definition,
|
|
24
|
+
content,
|
|
25
|
+
...(host === undefined ? {} : { host }),
|
|
26
|
+
...(now === undefined ? {} : { now }),
|
|
27
|
+
...(loaded === null ? {} : { restore: loaded.snapshot }),
|
|
28
|
+
});
|
|
29
|
+
let savedRevision = loaded?.revision ?? 0;
|
|
30
|
+
let lastSaveAt = clock();
|
|
31
|
+
function persist() {
|
|
32
|
+
savedRevision = runner.revision();
|
|
33
|
+
store.save({ snapshot: runner.snapshot(), revision: savedRevision });
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
join: (userId, isNew) => runner.join(userId, isNew),
|
|
37
|
+
leave: (userId) => runner.leave(userId),
|
|
38
|
+
input: (userId, frame) => runner.input(userId, frame),
|
|
39
|
+
command: (userId, name, input) => runner.command(userId, name, input),
|
|
40
|
+
tick(dt) {
|
|
41
|
+
const revision = runner.tick(dt);
|
|
42
|
+
if (revision !== savedRevision) {
|
|
43
|
+
const at = clock();
|
|
44
|
+
if (saveIntervalMs <= 0 || at - lastSaveAt >= saveIntervalMs) {
|
|
45
|
+
lastSaveAt = at;
|
|
46
|
+
persist();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return revision;
|
|
50
|
+
},
|
|
51
|
+
sync(sinceRevision) {
|
|
52
|
+
if (sinceRevision === null || sinceRevision <= 0) {
|
|
53
|
+
return { kind: "baseline", revision: runner.revision(), snapshot: runner.snapshot() };
|
|
54
|
+
}
|
|
55
|
+
return { kind: "diff", diff: runner.diff(sinceRevision) };
|
|
56
|
+
},
|
|
57
|
+
snapshotFor: (viewer) => runner.snapshot(viewer),
|
|
58
|
+
projectsViewers: () => runner.projectsViewers(),
|
|
59
|
+
revision: () => runner.revision(),
|
|
60
|
+
members: () => runner.members(),
|
|
61
|
+
save: persist,
|
|
62
|
+
runner: () => runner,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
import type { PointerAxisState } from "../input/pointerAxis.js";
|
|
2
|
+
import { type AxisBinding, type AxisRange } from "../input/axisInput.js";
|
|
3
|
+
/** One client's input for a tick — the semantic held-action set plus pointer state, the serializable, over-the-wire counterpart of {@link InputSnapshot} the host stores per connected player. */
|
|
4
|
+
export interface InputFrame {
|
|
5
|
+
held: readonly string[];
|
|
6
|
+
pointer: PointerAxisState | null;
|
|
7
|
+
}
|
|
2
8
|
export interface InputSnapshot {
|
|
3
|
-
/** Replaces the held-action set for this frame. Called by the shell before `onTick` each frame; does not bump `ctx.version()` or notify `ctx.subscribe` listeners — per-frame publishes would storm subscribers. */
|
|
9
|
+
/** Replaces the held-action set for this frame, rolling the previous held set forward for edge detection (#671). Called by the shell before `onTick` each frame; does not bump `ctx.version()` or notify `ctx.subscribe` listeners — per-frame publishes would storm subscribers. */
|
|
4
10
|
publish(held: readonly string[]): void;
|
|
5
11
|
/** Replaces the normalized pointer-position state for this frame (#293). Same no-notify contract as `publish`. */
|
|
6
12
|
publishPointer(state: PointerAxisState | null): void;
|
|
7
13
|
isDown(action: string): boolean;
|
|
14
|
+
/** The held-action set for this frame — an owned, frozen array; the array {@link publish} was called with is never aliased or returned. */
|
|
8
15
|
held(): readonly string[];
|
|
9
|
-
/**
|
|
10
|
-
|
|
16
|
+
/** True only on the frame `action` transitions from up to down (#671) — derived from the last two published held sets, so it stays replay-safe. */
|
|
17
|
+
justPressed(action: string): boolean;
|
|
18
|
+
/** True only on the frame `action` transitions from down to up (#671); mirrors {@link justPressed}. */
|
|
19
|
+
justReleased(action: string): boolean;
|
|
20
|
+
/** Pointer position over the play surface, `[-1, 1]` per axis with `+y` down, published by the shell each frame; `null` until the first pointer move. Frozen — an owned copy of what {@link publishPointer} was called with. */
|
|
21
|
+
pointer(): Readonly<PointerAxisState> | null;
|
|
22
|
+
/**
|
|
23
|
+
* Instantaneous analog axis sample against the held-action set and current pointer (#533.7) — bind
|
|
24
|
+
* throttle/steer/handbrake (or any axes) to *action names*, not raw key codes, since the held set is
|
|
25
|
+
* semantic actions. Feed the result into an `AxisChannel` for smoothing; unlisted ranges default to
|
|
26
|
+
* bipolar `[-1, 1]`, so pass `{ min: 0, max: 1 }` for one-directional pedals.
|
|
27
|
+
*/
|
|
28
|
+
axis<TAxes extends string>(bindings: Record<TAxes, AxisBinding>, ranges?: Partial<Record<TAxes, AxisRange>>): Record<TAxes, number>;
|
|
11
29
|
}
|
|
12
30
|
export declare function createInputSnapshot(): InputSnapshot;
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
+
import { sampleAxisBindings } from "../input/axisInput.js";
|
|
1
2
|
export function createInputSnapshot() {
|
|
2
3
|
let heldSet = new Set();
|
|
4
|
+
let previousHeldSet = new Set();
|
|
3
5
|
let heldList = [];
|
|
4
6
|
let pointerState = null;
|
|
5
7
|
return {
|
|
6
8
|
publish(held) {
|
|
7
|
-
|
|
9
|
+
previousHeldSet = heldSet;
|
|
10
|
+
heldList = Object.freeze([...held]);
|
|
8
11
|
heldSet = new Set(held);
|
|
9
12
|
},
|
|
10
13
|
publishPointer(state) {
|
|
11
|
-
pointerState = state;
|
|
14
|
+
pointerState = state === null ? null : Object.freeze({ ...state });
|
|
12
15
|
},
|
|
13
16
|
isDown: (action) => heldSet.has(action),
|
|
14
17
|
held: () => heldList,
|
|
15
18
|
pointer: () => pointerState,
|
|
19
|
+
axis: (bindings, ranges) => sampleAxisBindings(bindings, (action) => heldSet.has(action), pointerState, ranges),
|
|
20
|
+
justPressed: (action) => heldSet.has(action) && !previousHeldSet.has(action),
|
|
21
|
+
justReleased: (action) => !heldSet.has(action) && previousHeldSet.has(action),
|
|
16
22
|
};
|
|
17
23
|
}
|
|
@@ -21,6 +21,10 @@ export interface MotionIntents {
|
|
|
21
21
|
setVerticalVelocity(velocityY: number): void;
|
|
22
22
|
setY(y: number): void;
|
|
23
23
|
takePending(): MotionIntentBatch | null;
|
|
24
|
+
/** Non-draining copy of the pending intents for a whole-world save; unlike `takePending` it leaves the queue intact. */
|
|
25
|
+
snapshot(): MotionIntentBatch;
|
|
26
|
+
/** Replace the pending intents from a {@link snapshot} payload on save load. */
|
|
27
|
+
hydrate(batch: MotionIntentBatch): void;
|
|
24
28
|
}
|
|
25
29
|
export interface MotionIntentBatch {
|
|
26
30
|
impulses: readonly number[];
|
|
@@ -28,6 +32,13 @@ export interface MotionIntentBatch {
|
|
|
28
32
|
verticalVelocity: number | null;
|
|
29
33
|
y: number | null;
|
|
30
34
|
}
|
|
35
|
+
/** @internal */
|
|
31
36
|
export declare function createMotionIntents(): MotionIntents;
|
|
32
|
-
/** Fold a batch's
|
|
37
|
+
/** Fold a batch's vertical impulses into a controller's velocity, then apply an outright `setVerticalVelocity` override — the vertical counterpart of {@link applyHorizontalImpulses}.
|
|
38
|
+
* @internal
|
|
39
|
+
*/
|
|
40
|
+
export declare function applyMotionImpulses(currentVelocity: number, batch: MotionIntentBatch | null): number;
|
|
41
|
+
/** Fold a batch's horizontal pushes into a controller's velocity pair — shared by the walk and voxel drivers.
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
33
44
|
export declare function applyHorizontalImpulses(velocityX: number, velocityZ: number, batch: MotionIntentBatch | null): readonly [number, number];
|