@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
|
@@ -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;
|
|
@@ -4,7 +4,7 @@ import type { ModelAssetRef } from "../scene/assetCatalog.js";
|
|
|
4
4
|
import { type GameContext, type GameContextContent } from "./gameContext.js";
|
|
5
5
|
import { type InputFrame } from "./inputSnapshot.js";
|
|
6
6
|
import { type WorldDiff } from "./worldReplication.js";
|
|
7
|
-
import type { WorldSnapshot } from "./worldSnapshot.js";
|
|
7
|
+
import type { SnapshotViewer, WorldSnapshot } from "./worldSnapshot.js";
|
|
8
8
|
export type { InputFrame };
|
|
9
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
10
|
export declare const INPUT_COMMAND = "engine.input";
|
|
@@ -41,9 +41,14 @@ export interface HostedGameRunner {
|
|
|
41
41
|
tick(dt: number): number;
|
|
42
42
|
diff(sinceRevision: number): WorldDiff;
|
|
43
43
|
revision(): number;
|
|
44
|
-
|
|
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;
|
|
45
48
|
members(): readonly string[];
|
|
46
49
|
context(): GameContext;
|
|
47
50
|
}
|
|
48
|
-
/** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop.
|
|
51
|
+
/** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop.
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
49
54
|
export declare function createHostedGameRunner<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HostedGameRunnerOptions<TAssetRef, TMultiplayer>): HostedGameRunner;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { syncLifecyclePhase } from "../game/gamePhase.js";
|
|
2
|
+
import { advanceBehaviors } from "../scene/behaviorRuntime.js";
|
|
1
3
|
import { createGameContext } from "./gameContext.js";
|
|
2
4
|
import {} from "./inputSnapshot.js";
|
|
3
5
|
import { createWorldReplicator } from "./worldReplication.js";
|
|
4
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. */
|
|
5
7
|
export const INPUT_COMMAND = "engine.input";
|
|
6
|
-
/** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop.
|
|
8
|
+
/** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop.
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
7
11
|
export function createHostedGameRunner(options) {
|
|
8
12
|
const { definition, content, host, now, restore } = options;
|
|
9
13
|
const ctx = createGameContext({
|
|
@@ -11,20 +15,28 @@ export function createHostedGameRunner(options) {
|
|
|
11
15
|
content,
|
|
12
16
|
player: host ?? { userId: "host", isNew: true },
|
|
13
17
|
...(now === undefined ? {} : { now }),
|
|
18
|
+
...(definition.replication === undefined ? {} : { replication: definition.replication }),
|
|
14
19
|
});
|
|
15
20
|
const loop = definition.loop ?? {};
|
|
16
|
-
const replicator = createWorldReplicator(() => ctx.snapshot()
|
|
21
|
+
const replicator = createWorldReplicator(() => ctx.snapshot(), {
|
|
22
|
+
worldVersion: () => ctx.replicationVersion(),
|
|
23
|
+
});
|
|
17
24
|
const members = new Map();
|
|
18
25
|
const inputs = new Map();
|
|
26
|
+
const inputSeq = new Map();
|
|
19
27
|
loop.onInit?.(ctx);
|
|
28
|
+
syncLifecyclePhase(ctx, definition.lifecycle);
|
|
20
29
|
if (restore !== undefined)
|
|
21
30
|
ctx.hydrate(restore);
|
|
22
31
|
return {
|
|
23
32
|
join(userId, isNew) {
|
|
33
|
+
if (members.has(userId))
|
|
34
|
+
return;
|
|
24
35
|
const player = { userId, isNew };
|
|
25
36
|
members.set(userId, player);
|
|
26
37
|
ctx.game.players?.join(userId, isNew);
|
|
27
38
|
loop.onNewPlayer?.(ctx, player);
|
|
39
|
+
syncLifecyclePhase(ctx, definition.lifecycle);
|
|
28
40
|
},
|
|
29
41
|
resume(userId) {
|
|
30
42
|
members.set(userId, { userId, isNew: false });
|
|
@@ -36,10 +48,18 @@ export function createHostedGameRunner(options) {
|
|
|
36
48
|
return;
|
|
37
49
|
members.delete(userId);
|
|
38
50
|
inputs.delete(userId);
|
|
51
|
+
inputSeq.delete(userId);
|
|
39
52
|
loop.onPlayerLeave?.(ctx, player);
|
|
40
53
|
ctx.game.players?.leave(userId);
|
|
41
54
|
},
|
|
42
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
|
+
}
|
|
43
63
|
inputs.set(userId, frame);
|
|
44
64
|
ctx.game.players?.setInput(userId, frame);
|
|
45
65
|
},
|
|
@@ -51,11 +71,14 @@ export function createHostedGameRunner(options) {
|
|
|
51
71
|
},
|
|
52
72
|
tick(dt) {
|
|
53
73
|
loop.onTick?.(ctx, dt);
|
|
74
|
+
advanceBehaviors(ctx, dt);
|
|
75
|
+
syncLifecyclePhase(ctx, definition.lifecycle);
|
|
54
76
|
return replicator.commit();
|
|
55
77
|
},
|
|
56
78
|
diff: (sinceRevision) => replicator.diff(sinceRevision),
|
|
57
79
|
revision: () => replicator.revision(),
|
|
58
|
-
snapshot: () => ctx.snapshot(),
|
|
80
|
+
snapshot: (viewer) => ctx.snapshot(viewer),
|
|
81
|
+
projectsViewers: () => ctx.replicatesPerViewer(),
|
|
59
82
|
members: () => Array.from(members.keys()),
|
|
60
83
|
context: () => ctx,
|
|
61
84
|
};
|
|
@@ -4,7 +4,7 @@ import type { GameContext, GameContextContent } from "./gameContext.js";
|
|
|
4
4
|
import type { GameDefinition, LoopPlayer } from "../game/defineGame.js";
|
|
5
5
|
import { type HostedGameRunner, type InputFrame } from "./hostedGameRunner.js";
|
|
6
6
|
import type { WorldDiff } from "./worldReplication.js";
|
|
7
|
-
import type { WorldSnapshot } from "./worldSnapshot.js";
|
|
7
|
+
import type { SnapshotViewer, WorldSnapshot } from "./worldSnapshot.js";
|
|
8
8
|
/** One hosted world's persisted authoritative state — the unit a {@link HostedWorldStore} loads and saves. */
|
|
9
9
|
export interface HostedWorldRecord {
|
|
10
10
|
snapshot: WorldSnapshot;
|
|
@@ -19,7 +19,9 @@ export interface HostedWorldStore {
|
|
|
19
19
|
load(): HostedWorldRecord | null;
|
|
20
20
|
save(record: HostedWorldRecord): void;
|
|
21
21
|
}
|
|
22
|
-
/** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host.
|
|
22
|
+
/** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host.
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
23
25
|
export declare function memoryWorldStore(seed?: HostedWorldRecord): HostedWorldStore;
|
|
24
26
|
/** A client replication pull: a full baseline (first sync / fell behind) or a diff since the client's cursor. */
|
|
25
27
|
export type HostedWorldSync = {
|
|
@@ -38,7 +40,7 @@ export interface HostedWorldSessionOptions<TAssetRef extends ModelAssetRef, TMul
|
|
|
38
40
|
now?: () => number;
|
|
39
41
|
/** Where the authoritative snapshot persists; defaults to {@link memoryWorldStore}. */
|
|
40
42
|
store?: HostedWorldStore;
|
|
41
|
-
/** Minimum elapsed
|
|
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. */
|
|
42
44
|
saveIntervalMs?: number;
|
|
43
45
|
}
|
|
44
46
|
/**
|
|
@@ -55,11 +57,17 @@ export interface HostedWorldSession {
|
|
|
55
57
|
tick(dt: number): number;
|
|
56
58
|
/** Replication pull: `null`/`0` cursor → full baseline; a prior revision → a diff since it. */
|
|
57
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;
|
|
58
64
|
revision(): number;
|
|
59
65
|
members(): readonly string[];
|
|
60
66
|
/** Force-persist the current world to the store. */
|
|
61
67
|
save(): void;
|
|
62
68
|
runner(): HostedGameRunner;
|
|
63
69
|
}
|
|
64
|
-
/** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick.
|
|
70
|
+
/** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick.
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
65
73
|
export declare function createHostedWorldSession<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HostedWorldSessionOptions<TAssetRef, TMultiplayer>): HostedWorldSession;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createHostedGameRunner } from "./hostedGameRunner.js";
|
|
2
|
-
/** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host.
|
|
2
|
+
/** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
3
5
|
export function memoryWorldStore(seed) {
|
|
4
6
|
let record = seed ?? null;
|
|
5
7
|
return {
|
|
@@ -9,9 +11,12 @@ export function memoryWorldStore(seed) {
|
|
|
9
11
|
},
|
|
10
12
|
};
|
|
11
13
|
}
|
|
12
|
-
/** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick.
|
|
14
|
+
/** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick.
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
13
17
|
export function createHostedWorldSession(options) {
|
|
14
18
|
const { definition, content, host, now, saveIntervalMs = 0 } = options;
|
|
19
|
+
const clock = now ?? Date.now;
|
|
15
20
|
const store = options.store ?? memoryWorldStore();
|
|
16
21
|
const loaded = store.load();
|
|
17
22
|
const runner = createHostedGameRunner({
|
|
@@ -22,7 +27,7 @@ export function createHostedWorldSession(options) {
|
|
|
22
27
|
...(loaded === null ? {} : { restore: loaded.snapshot }),
|
|
23
28
|
});
|
|
24
29
|
let savedRevision = loaded?.revision ?? 0;
|
|
25
|
-
let lastSaveAt =
|
|
30
|
+
let lastSaveAt = clock();
|
|
26
31
|
function persist() {
|
|
27
32
|
savedRevision = runner.revision();
|
|
28
33
|
store.save({ snapshot: runner.snapshot(), revision: savedRevision });
|
|
@@ -35,7 +40,7 @@ export function createHostedWorldSession(options) {
|
|
|
35
40
|
tick(dt) {
|
|
36
41
|
const revision = runner.tick(dt);
|
|
37
42
|
if (revision !== savedRevision) {
|
|
38
|
-
const at =
|
|
43
|
+
const at = clock();
|
|
39
44
|
if (saveIntervalMs <= 0 || at - lastSaveAt >= saveIntervalMs) {
|
|
40
45
|
lastSaveAt = at;
|
|
41
46
|
persist();
|
|
@@ -49,6 +54,8 @@ export function createHostedWorldSession(options) {
|
|
|
49
54
|
}
|
|
50
55
|
return { kind: "diff", diff: runner.diff(sinceRevision) };
|
|
51
56
|
},
|
|
57
|
+
snapshotFor: (viewer) => runner.snapshot(viewer),
|
|
58
|
+
projectsViewers: () => runner.projectsViewers(),
|
|
52
59
|
revision: () => runner.revision(),
|
|
53
60
|
members: () => runner.members(),
|
|
54
61
|
save: persist,
|
|
@@ -6,14 +6,19 @@ export interface InputFrame {
|
|
|
6
6
|
pointer: PointerAxisState | null;
|
|
7
7
|
}
|
|
8
8
|
export interface InputSnapshot {
|
|
9
|
-
/** 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. */
|
|
10
10
|
publish(held: readonly string[]): void;
|
|
11
11
|
/** Replaces the normalized pointer-position state for this frame (#293). Same no-notify contract as `publish`. */
|
|
12
12
|
publishPointer(state: PointerAxisState | null): void;
|
|
13
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. */
|
|
14
15
|
held(): readonly string[];
|
|
15
|
-
/**
|
|
16
|
-
|
|
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;
|
|
17
22
|
/**
|
|
18
23
|
* Instantaneous analog axis sample against the held-action set and current pointer (#533.7) — bind
|
|
19
24
|
* throttle/steer/handbrake (or any axes) to *action names*, not raw key codes, since the held set is
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { sampleAxisBindings } from "../input/axisInput.js";
|
|
2
2
|
export function createInputSnapshot() {
|
|
3
3
|
let heldSet = new Set();
|
|
4
|
+
let previousHeldSet = new Set();
|
|
4
5
|
let heldList = [];
|
|
5
6
|
let pointerState = null;
|
|
6
7
|
return {
|
|
7
8
|
publish(held) {
|
|
8
|
-
|
|
9
|
+
previousHeldSet = heldSet;
|
|
10
|
+
heldList = Object.freeze([...held]);
|
|
9
11
|
heldSet = new Set(held);
|
|
10
12
|
},
|
|
11
13
|
publishPointer(state) {
|
|
12
|
-
pointerState = state;
|
|
14
|
+
pointerState = state === null ? null : Object.freeze({ ...state });
|
|
13
15
|
},
|
|
14
16
|
isDown: (action) => heldSet.has(action),
|
|
15
17
|
held: () => heldList,
|
|
16
18
|
pointer: () => pointerState,
|
|
17
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),
|
|
18
22
|
};
|
|
19
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,8 +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 vertical impulses into a controller's velocity, then apply an outright `setVerticalVelocity` override — the vertical counterpart of {@link applyHorizontalImpulses}.
|
|
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
|
+
*/
|
|
33
40
|
export declare function applyMotionImpulses(currentVelocity: number, batch: MotionIntentBatch | null): number;
|
|
34
|
-
/** Fold a batch's horizontal pushes into a controller's velocity pair — shared by the walk and voxel drivers.
|
|
41
|
+
/** Fold a batch's horizontal pushes into a controller's velocity pair — shared by the walk and voxel drivers.
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
35
44
|
export declare function applyHorizontalImpulses(velocityX: number, velocityZ: number, batch: MotionIntentBatch | null): readonly [number, number];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** @internal */
|
|
1
2
|
export function createMotionIntents() {
|
|
2
3
|
let impulses = [];
|
|
3
4
|
let horizontalImpulses = [];
|
|
@@ -27,9 +28,20 @@ export function createMotionIntents() {
|
|
|
27
28
|
y = null;
|
|
28
29
|
return batch;
|
|
29
30
|
},
|
|
31
|
+
snapshot() {
|
|
32
|
+
return { impulses: [...impulses], horizontalImpulses: [...horizontalImpulses], verticalVelocity, y };
|
|
33
|
+
},
|
|
34
|
+
hydrate(batch) {
|
|
35
|
+
impulses = [...batch.impulses];
|
|
36
|
+
horizontalImpulses = batch.horizontalImpulses.map(([x, z]) => [x, z]);
|
|
37
|
+
verticalVelocity = batch.verticalVelocity;
|
|
38
|
+
y = batch.y;
|
|
39
|
+
},
|
|
30
40
|
};
|
|
31
41
|
}
|
|
32
|
-
/** Fold a batch's vertical impulses into a controller's velocity, then apply an outright `setVerticalVelocity` override — the vertical counterpart of {@link applyHorizontalImpulses}.
|
|
42
|
+
/** Fold a batch's vertical impulses into a controller's velocity, then apply an outright `setVerticalVelocity` override — the vertical counterpart of {@link applyHorizontalImpulses}.
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
33
45
|
export function applyMotionImpulses(currentVelocity, batch) {
|
|
34
46
|
if (batch === null)
|
|
35
47
|
return currentVelocity;
|
|
@@ -40,7 +52,9 @@ export function applyMotionImpulses(currentVelocity, batch) {
|
|
|
40
52
|
velocity = batch.verticalVelocity;
|
|
41
53
|
return velocity;
|
|
42
54
|
}
|
|
43
|
-
/** Fold a batch's horizontal pushes into a controller's velocity pair — shared by the walk and voxel drivers.
|
|
55
|
+
/** Fold a batch's horizontal pushes into a controller's velocity pair — shared by the walk and voxel drivers.
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
44
58
|
export function applyHorizontalImpulses(velocityX, velocityZ, batch) {
|
|
45
59
|
if (batch === null || batch.horizontalImpulses.length === 0)
|
|
46
60
|
return [velocityX, velocityZ];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { GameContext } from "./gameContext.js";
|
|
2
|
+
/**
|
|
3
|
+
* Per-`GameContext` lazy state, keyed by context identity through a `WeakMap` so it is reclaimed when
|
|
4
|
+
* the context is — the seam a game uses instead of a module-global `Map`, which is process-global and
|
|
5
|
+
* bleeds across worlds when one host serves several `serverId`s (#632). `init` runs once per distinct
|
|
6
|
+
* context on first access; the same context always resolves to the same value. This mirrors the engine's
|
|
7
|
+
* built-in per-ctx pattern (`ctx.player.motion`, `stepPlayerMovement`).
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const heroRuntimes = perContext(() => new Map<string, HeroRuntime>());
|
|
11
|
+
* // per world:
|
|
12
|
+
* heroRuntimes(ctx).set(userId, runtime);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function perContext<T>(init: (ctx: GameContext) => T): (ctx: GameContext) => T;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-`GameContext` lazy state, keyed by context identity through a `WeakMap` so it is reclaimed when
|
|
3
|
+
* the context is — the seam a game uses instead of a module-global `Map`, which is process-global and
|
|
4
|
+
* bleeds across worlds when one host serves several `serverId`s (#632). `init` runs once per distinct
|
|
5
|
+
* context on first access; the same context always resolves to the same value. This mirrors the engine's
|
|
6
|
+
* built-in per-ctx pattern (`ctx.player.motion`, `stepPlayerMovement`).
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const heroRuntimes = perContext(() => new Map<string, HeroRuntime>());
|
|
10
|
+
* // per world:
|
|
11
|
+
* heroRuntimes(ctx).set(userId, runtime);
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export function perContext(init) {
|
|
15
|
+
const byContext = new WeakMap();
|
|
16
|
+
return (ctx) => {
|
|
17
|
+
if (!byContext.has(ctx))
|
|
18
|
+
byContext.set(ctx, init(ctx));
|
|
19
|
+
return byContext.get(ctx);
|
|
20
|
+
};
|
|
21
|
+
}
|