@jgengine/core 0.10.0 → 0.12.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 +39 -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/populationDirector.d.ts +103 -0
- package/dist/ai/populationDirector.js +190 -0
- package/dist/ai/pursuit.d.ts +56 -0
- package/dist/ai/pursuit.js +53 -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 +2 -1
- package/dist/authoring.js +2 -1
- 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 +35 -0
- package/dist/combat.js +35 -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/controls.d.ts +38 -0
- package/dist/devtools/controls.js +181 -0
- package/dist/devtools/devtools.d.ts +5 -197
- package/dist/devtools/devtools.js +38 -774
- package/dist/devtools/discover.d.ts +32 -0
- package/dist/devtools/discover.js +240 -0
- package/dist/devtools/fallbackSeams.d.ts +50 -0
- package/dist/devtools/fallbackSeams.js +111 -0
- package/dist/devtools/frame.d.ts +15 -0
- package/dist/devtools/frame.js +247 -0
- package/dist/devtools/logs.d.ts +15 -0
- package/dist/devtools/logs.js +86 -0
- package/dist/devtools/overrides.d.ts +16 -0
- package/dist/devtools/overrides.js +66 -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/devtools/types.d.ts +212 -0
- package/dist/devtools/types.js +1 -0
- package/dist/economy/auctionBook.d.ts +122 -0
- package/dist/economy/auctionBook.js +213 -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/priceHistory.d.ts +44 -0
- package/dist/economy/priceHistory.js +89 -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/unlockPoints.d.ts +92 -0
- package/dist/economy/unlockPoints.js +103 -0
- package/dist/economy/wallet.d.ts +26 -2
- package/dist/economy/wallet.js +35 -6
- package/dist/editor/commandApply.d.ts +5 -0
- package/dist/editor/commandApply.js +755 -0
- package/dist/editor/commands.d.ts +235 -7
- package/dist/editor/commands.js +82 -124
- package/dist/editor/directives.d.ts +94 -0
- package/dist/editor/directives.js +206 -0
- package/dist/editor/document.d.ts +194 -13
- package/dist/editor/document.js +1166 -19
- package/dist/editor/entityCatalog.d.ts +42 -0
- package/dist/editor/entityCatalog.js +101 -0
- package/dist/editor/environment.d.ts +74 -0
- package/dist/editor/environment.js +169 -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 +98 -6
- package/dist/editor/index.js +13 -2
- package/dist/editor/liveSync.d.ts +127 -0
- package/dist/editor/liveSync.js +249 -0
- package/dist/editor/minimap.d.ts +31 -0
- package/dist/editor/minimap.js +73 -0
- package/dist/editor/runtimeInspector.d.ts +88 -0
- package/dist/editor/runtimeInspector.js +239 -0
- package/dist/editor/streamer.d.ts +66 -0
- package/dist/editor/streamer.js +68 -0
- package/dist/editor/types.d.ts +250 -1
- package/dist/editor/world.d.ts +136 -0
- package/dist/editor/world.js +303 -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/breeding.d.ts +161 -0
- package/dist/game/breeding.js +181 -0
- package/dist/game/cameraConfig.d.ts +451 -0
- package/dist/game/cameraConfig.js +1 -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 +110 -5
- package/dist/game/defineGame.js +49 -4
- package/dist/game/defineSystem.d.ts +90 -0
- package/dist/game/defineSystem.js +47 -0
- package/dist/game/dialogue.d.ts +33 -0
- package/dist/game/dialogue.js +21 -0
- package/dist/game/events.d.ts +63 -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 +116 -432
- package/dist/game/playableGame.js +1 -1
- package/dist/game/progression.d.ts +35 -0
- package/dist/game/progression.js +19 -0
- package/dist/game/quest.d.ts +8 -0
- package/dist/game/quest.js +30 -3
- 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/tribe.d.ts +184 -0
- package/dist/game/tribe.js +432 -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 +93 -0
- package/dist/gameplay.js +93 -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/encumbrance.d.ts +69 -0
- package/dist/inventory/encumbrance.js +68 -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 +6 -3
- 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 +39 -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 +50 -9
- package/dist/movement/movementModel.js +75 -29
- package/dist/movement/playerMovement.js +167 -12
- 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 +16 -8
- package/dist/multiplayer/lagCompensation.d.ts +5 -0
- package/dist/multiplayer/lagCompensation.js +5 -0
- package/dist/multiplayer/presenceModel.d.ts +11 -1
- package/dist/multiplayer/presenceModel.js +17 -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 +31 -0
- package/dist/physics/drivableVehicle.js +16 -0
- package/dist/physics/flightDynamics.d.ts +82 -0
- package/dist/physics/flightDynamics.js +165 -0
- package/dist/physics/gravityField.d.ts +25 -0
- package/dist/physics/gravityField.js +41 -0
- package/dist/physics/kinematicVehicle.d.ts +108 -1
- package/dist/physics/kinematicVehicle.js +212 -15
- package/dist/physics/physicsWorld.d.ts +50 -12
- package/dist/physics/physicsWorld.js +120 -122
- package/dist/physics/radialImpulse.d.ts +25 -0
- package/dist/physics/radialImpulse.js +27 -0
- package/dist/physics/vehicleObstacles.d.ts +44 -0
- package/dist/physics/vehicleObstacles.js +115 -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 +26 -1
- package/dist/random/rng.js +32 -9
- 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 +55 -3
- package/dist/runtime/adapter.js +57 -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/combat.d.ts +51 -0
- package/dist/runtime/context/combat.js +130 -0
- package/dist/runtime/context/combatFx.d.ts +23 -0
- package/dist/runtime/context/combatFx.js +161 -0
- package/dist/runtime/context/deathLoot.d.ts +30 -0
- package/dist/runtime/context/deathLoot.js +39 -0
- package/dist/runtime/context/player.d.ts +48 -0
- package/dist/runtime/context/player.js +125 -0
- package/dist/runtime/context/registries.d.ts +13 -0
- package/dist/runtime/context/registries.js +84 -0
- package/dist/runtime/context/scene.d.ts +59 -0
- package/dist/runtime/context/scene.js +291 -0
- package/dist/runtime/context/snapshotCodecs.d.ts +12 -0
- package/dist/runtime/context/snapshotCodecs.js +26 -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 +157 -0
- package/dist/runtime/descriptors/features.d.ts +79 -0
- package/dist/runtime/descriptors/features.js +299 -0
- package/dist/runtime/gameContext.d.ts +2 -327
- package/dist/runtime/gameContext.js +273 -778
- package/dist/runtime/gameContextTypes.d.ts +467 -0
- package/dist/runtime/gameContextTypes.js +1 -0
- package/dist/runtime/gameRuntime.d.ts +1 -0
- package/dist/runtime/gameRuntime.js +1 -0
- package/dist/runtime/headlessRunner.d.ts +62 -0
- package/dist/runtime/headlessRunner.js +45 -0
- package/dist/runtime/hostPersistence.d.ts +12 -0
- package/dist/runtime/hostPersistence.js +12 -0
- package/dist/runtime/hostPolicy.d.ts +51 -0
- package/dist/runtime/hostPolicy.js +68 -0
- package/dist/runtime/hostedGameRunner.d.ts +11 -4
- package/dist/runtime/hostedGameRunner.js +27 -3
- package/dist/runtime/hostedWorldSession.d.ts +15 -5
- package/dist/runtime/hostedWorldSession.js +12 -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 +42 -3
- package/dist/runtime/worldSnapshot.js +34 -7
- package/dist/scene/assetCatalog.d.ts +26 -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 +257 -0
- package/dist/scene/authoredTriggers.d.ts +219 -0
- package/dist/scene/authoredTriggers.js +454 -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 +67 -0
- package/dist/scene/colliders.d.ts +71 -1
- package/dist/scene/colliders.js +145 -1
- package/dist/scene/collisionMesh.d.ts +94 -0
- package/dist/scene/collisionMesh.js +699 -0
- package/dist/scene/companion.d.ts +147 -0
- package/dist/scene/companion.js +193 -0
- package/dist/scene/entityStats.d.ts +18 -11
- package/dist/scene/entityStats.js +21 -16
- 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 +256 -0
- package/dist/scene/sceneKinds.js +218 -0
- package/dist/scene/sceneOwnership.d.ts +169 -0
- package/dist/scene/sceneOwnership.js +179 -0
- package/dist/scene/sceneRaycast.js +15 -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/spawnLevelStats.d.ts +110 -0
- package/dist/stats/spawnLevelStats.js +140 -0
- package/dist/stats/statModifiers.d.ts +5 -0
- package/dist/stats/statModifiers.js +5 -0
- package/dist/stats/statPool.d.ts +70 -0
- package/dist/stats/statPool.js +59 -0
- package/dist/store/changeSignal.d.ts +3 -0
- package/dist/store/changeSignal.js +2 -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 +7 -0
- package/dist/store/observableKeyedStore.js +35 -2
- package/dist/survival/decayMeter.d.ts +55 -0
- package/dist/survival/decayMeter.js +130 -57
- package/dist/survival/moodle.d.ts +2 -0
- package/dist/survival/regionHealth.d.ts +6 -0
- package/dist/survival/regionHealth.js +6 -3
- 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 +38 -1
- package/dist/ui/hudLayout.js +220 -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/authoredEntities.d.ts +29 -0
- package/dist/world/authoredEntities.js +29 -0
- package/dist/world/authoredObjects.d.ts +72 -0
- package/dist/world/authoredObjects.js +81 -0
- package/dist/world/authoredSpawn.d.ts +39 -0
- package/dist/world/authoredSpawn.js +37 -0
- package/dist/world/buildSockets.d.ts +152 -0
- package/dist/world/buildSockets.js +188 -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/cityBlocks.d.ts +152 -0
- package/dist/world/cityBlocks.js +670 -0
- package/dist/world/cityContent.d.ts +77 -0
- package/dist/world/cityContent.js +261 -0
- package/dist/world/cityGeometry.d.ts +114 -0
- package/dist/world/cityGeometry.js +573 -0
- package/dist/world/cityKind.d.ts +314 -0
- package/dist/world/cityKind.js +1578 -0
- package/dist/world/features.d.ts +133 -10
- package/dist/world/features.js +66 -6
- 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/markers.d.ts +50 -4
- package/dist/world/markers.js +49 -0
- package/dist/world/massing.js +1 -1
- package/dist/world/minimapBake.d.ts +78 -0
- package/dist/world/minimapBake.js +208 -0
- package/dist/world/minimapTrack.d.ts +17 -0
- package/dist/world/minimapTrack.js +22 -0
- package/dist/world/pathInstances.d.ts +27 -0
- package/dist/world/pathInstances.js +27 -0
- package/dist/world/pathNetwork.d.ts +159 -0
- package/dist/world/pathNetwork.js +684 -0
- package/dist/world/pathTerrain.d.ts +80 -0
- package/dist/world/pathTerrain.js +142 -0
- package/dist/world/place.d.ts +166 -0
- package/dist/world/place.js +96 -0
- package/dist/world/placeAsset.d.ts +81 -0
- package/dist/world/placeAsset.js +79 -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/poleLineKind.d.ts +40 -0
- package/dist/world/poleLineKind.js +97 -0
- package/dist/world/polyline.d.ts +34 -0
- package/dist/world/polyline.js +88 -0
- package/dist/world/resourceNode.d.ts +109 -0
- package/dist/world/resourceNode.js +140 -0
- package/dist/world/roads.d.ts +8 -0
- package/dist/world/roads.js +38 -0
- package/dist/world/scatter.js +2 -20
- 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 +29 -0
- package/dist/world/streets.js +55 -0
- package/dist/world/terraform.d.ts +213 -1
- package/dist/world/terraform.js +627 -22
- package/dist/world/terrain.d.ts +164 -20
- package/dist/world/terrain.js +325 -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 +141 -0
- package/dist/world.js +141 -0
- package/package.json +32 -8
- package/skills/game-design/SKILL.md +28 -0
- package/skills/game-design/agents/openai.yaml +4 -0
- package/skills/game-design/references/application-playbook.md +170 -0
- package/skills/game-design/references/field-guide.md +288 -0
- package/skills/jgengine/SKILL.md +54 -0
- package/skills/jgengine/api.md +527 -0
- package/skills/jgengine/capabilities.md +131 -0
- package/skills/jgengine/recipes/minimal-game.md +88 -0
- package/skills/jgengine-combat/SKILL.md +38 -0
- package/skills/jgengine-combat/api.md +585 -0
- package/skills/jgengine-combat/capabilities.md +213 -0
- package/skills/jgengine-combat/recipes/portable-stat-pools.md +122 -0
- package/skills/jgengine-combat/reference.md +108 -0
- package/skills/jgengine-gameplay/SKILL.md +39 -0
- package/skills/jgengine-gameplay/api.md +1920 -0
- package/skills/jgengine-gameplay/capabilities.md +454 -0
- package/skills/jgengine-gameplay/reference-systems.md +56 -0
- package/skills/jgengine-world/SKILL.md +51 -0
- package/skills/jgengine-world/api.md +3056 -0
- package/skills/jgengine-world/capabilities.md +476 -0
- package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
- package/skills/jgengine-world/reference.md +261 -0
- package/dist/cartridge/runtime.d.ts +0 -15
- package/dist/cartridge/runtime.js +0 -556
- package/dist/cartridge/spec.d.ts +0 -188
- package/dist/cartridge/spec.js +0 -19
- package/dist/cartridge/validate.d.ts +0 -2
- package/dist/cartridge/validate.js +0 -78
- package/dist/store/engineStore.d.ts +0 -22
- package/dist/store/engineStore.js +0 -50
- package/dist/store/features.d.ts +0 -10
- package/dist/store/features.js +0 -23
- package/llms.txt +0 -5389
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seeded rule selection over a tagged pool.
|
|
3
|
+
*
|
|
4
|
+
* A {@link RuleDef} is a caller-owned selectable — a mutator, game mode, event, or challenge modifier
|
|
5
|
+
* — carrying tags, an optional weight, compatibility (`requires`) and exclusion (`conflicts`)
|
|
6
|
+
* constraints, and any {@link ParamLayer}s it contributes when active. {@link selectRules} draws a
|
|
7
|
+
* requested count from the eligible pool using injected, deterministic randomness: the same seed and
|
|
8
|
+
* pool always yield the same rules, so a host can reproduce a session from `{ seed, count }` alone and
|
|
9
|
+
* every peer agrees without replicating the roll.
|
|
10
|
+
*
|
|
11
|
+
* Core never branches on known rule names — selection is driven entirely by tags and the caller's
|
|
12
|
+
* constraint data, and a selected rule's behavior is read back through its `layers`/`payload`. That
|
|
13
|
+
* keeps the seam genre-agnostic and lets games install rules through {@link createRuleRegistry}
|
|
14
|
+
* without the primitive knowing what any mutator "means".
|
|
15
|
+
*/
|
|
16
|
+
import { pickWeighted } from "../random/pick.js";
|
|
17
|
+
import { seededStreams } from "../random/rng.js";
|
|
18
|
+
import {} from "./paramLayers.js";
|
|
19
|
+
function tokensOf(rule) {
|
|
20
|
+
return [rule.id, ...(rule.tags ?? [])];
|
|
21
|
+
}
|
|
22
|
+
function passesTagFilter(rule, config) {
|
|
23
|
+
const tags = rule.tags ?? [];
|
|
24
|
+
if (config.excludeTags?.some((tag) => tags.includes(tag)))
|
|
25
|
+
return false;
|
|
26
|
+
if (config.includeTags && config.includeTags.length > 0) {
|
|
27
|
+
return config.includeTags.some((tag) => tags.includes(tag));
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
function isCompatible(rule, selected) {
|
|
32
|
+
const selectedTokens = new Set(selected.flatMap(tokensOf));
|
|
33
|
+
if (rule.requires && !rule.requires.every((token) => selectedTokens.has(token)))
|
|
34
|
+
return false;
|
|
35
|
+
if (rule.conflicts?.some((token) => selectedTokens.has(token)))
|
|
36
|
+
return false;
|
|
37
|
+
const ruleTokens = new Set(tokensOf(rule));
|
|
38
|
+
for (const other of selected) {
|
|
39
|
+
if (other.conflicts?.some((token) => ruleTokens.has(token)))
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Select up to `count` rules from `pool` deterministically from `config.seed`. Locked ids are placed
|
|
46
|
+
* first (in order), then remaining slots are filled by weighted draw from tag-filtered, still-eligible
|
|
47
|
+
* candidates, honoring `requires`/`conflicts` after each pick. Each slot draws from an independent
|
|
48
|
+
* seed stream keyed by slot index, so a later slot's outcome never shifts an earlier one. Selection
|
|
49
|
+
* stops early when no compatible candidate remains. Pure given `pool` + `config`.
|
|
50
|
+
*
|
|
51
|
+
* @capability rule-selection deterministically select rules from a tagged pool under compatibility/exclusion constraints
|
|
52
|
+
*/
|
|
53
|
+
export function selectRules(pool, config) {
|
|
54
|
+
const byId = new Map(pool.map((rule) => [rule.id, rule]));
|
|
55
|
+
const chosen = [];
|
|
56
|
+
const chosenIds = new Set();
|
|
57
|
+
for (const id of config.locked ?? []) {
|
|
58
|
+
const rule = byId.get(id);
|
|
59
|
+
if (rule && !chosenIds.has(id)) {
|
|
60
|
+
chosen.push(rule);
|
|
61
|
+
chosenIds.add(id);
|
|
62
|
+
}
|
|
63
|
+
if (chosen.length >= config.count)
|
|
64
|
+
return { rules: chosen, ids: chosen.map((r) => r.id) };
|
|
65
|
+
}
|
|
66
|
+
const streams = seededStreams(config.seed);
|
|
67
|
+
let slot = chosen.length;
|
|
68
|
+
while (chosen.length < config.count) {
|
|
69
|
+
const candidates = pool.filter((rule) => !chosenIds.has(rule.id) && passesTagFilter(rule, config) && isCompatible(rule, chosen));
|
|
70
|
+
if (candidates.length === 0)
|
|
71
|
+
break;
|
|
72
|
+
const picked = pickWeighted(streams(`slot:${slot}`), candidates, (rule) => rule.weight !== undefined && rule.weight > 0 ? rule.weight : 1);
|
|
73
|
+
if (!picked)
|
|
74
|
+
break;
|
|
75
|
+
chosen.push(picked);
|
|
76
|
+
chosenIds.add(picked.id);
|
|
77
|
+
slot += 1;
|
|
78
|
+
}
|
|
79
|
+
return { rules: chosen, ids: chosen.map((r) => r.id) };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Reroll a prior selection: keep `keepIds` (the locked slots) and re-draw the rest under a fresh,
|
|
83
|
+
* still-deterministic stream derived from `config.seed` and `salt`. The same seed + salt + keep set
|
|
84
|
+
* reproduce the same reroll, so reroll history stays replayable.
|
|
85
|
+
*
|
|
86
|
+
* @capability rule-selection reroll unlocked slots of a selection deterministically from seed and salt
|
|
87
|
+
*/
|
|
88
|
+
export function rerollRules(pool, config, keepIds, salt = 0) {
|
|
89
|
+
return selectRules(pool, {
|
|
90
|
+
...config,
|
|
91
|
+
locked: keepIds,
|
|
92
|
+
seed: `${config.seed}:reroll:${salt}`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create a {@link RuleRegistry}. Rules install through `register` (duplicate ids throw); selection and
|
|
97
|
+
* `layersFor` are data-driven, so the core never branches on which mutators exist.
|
|
98
|
+
*
|
|
99
|
+
* @capability rule-selection register rules and bridge a selection to its contributed parameter layers
|
|
100
|
+
*/
|
|
101
|
+
export function createRuleRegistry(initial) {
|
|
102
|
+
const rules = new Map();
|
|
103
|
+
const register = (rule) => {
|
|
104
|
+
if (rules.has(rule.id))
|
|
105
|
+
throw new Error(`rule "${rule.id}" is already registered`);
|
|
106
|
+
rules.set(rule.id, rule);
|
|
107
|
+
};
|
|
108
|
+
if (initial)
|
|
109
|
+
for (const rule of initial)
|
|
110
|
+
register(rule);
|
|
111
|
+
return {
|
|
112
|
+
register,
|
|
113
|
+
has: (id) => rules.has(id),
|
|
114
|
+
get: (id) => rules.get(id),
|
|
115
|
+
all: () => [...rules.values()],
|
|
116
|
+
select: (config) => selectRules([...rules.values()], config),
|
|
117
|
+
layersFor(ids) {
|
|
118
|
+
const layers = [];
|
|
119
|
+
for (const id of ids) {
|
|
120
|
+
const rule = rules.get(id);
|
|
121
|
+
if (rule?.layers)
|
|
122
|
+
layers.push(...rule.layers);
|
|
123
|
+
}
|
|
124
|
+
return layers;
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
package/dist/game/runDraft.d.ts
CHANGED
|
@@ -31,4 +31,9 @@ export interface RunDraft<TStat extends string = string, TData = unknown> {
|
|
|
31
31
|
choose(offerId: string): boolean;
|
|
32
32
|
stack(): RunModifierStack<TStat, TData>;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* A roguelike run built from stacking drafted modifier picks that reshape the run.
|
|
36
|
+
*
|
|
37
|
+
* @capability run-modifiers a roguelike run built from stacking drafted modifier picks
|
|
38
|
+
*/
|
|
34
39
|
export declare function createRunDraft<TStat extends string = string, TData = unknown>(config: RunDraftConfig<TStat, TData>): RunDraft<TStat, TData>;
|
package/dist/game/runDraft.js
CHANGED
|
@@ -68,6 +68,11 @@ export function createRunModifierStack(offers) {
|
|
|
68
68
|
},
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* A roguelike run built from stacking drafted modifier picks that reshape the run.
|
|
73
|
+
*
|
|
74
|
+
* @capability run-modifiers a roguelike run built from stacking drafted modifier picks
|
|
75
|
+
*/
|
|
71
76
|
export function createRunDraft(config) {
|
|
72
77
|
const stack = createRunModifierStack(config.offers);
|
|
73
78
|
const defaultRng = config.rng ?? Math.random;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { type KeyValueStorage } from "./keyValueStore.js";
|
|
2
|
+
/**
|
|
3
|
+
* The one async storage seam a save store persists through. Every backend
|
|
4
|
+
* satisfies this same three-method shape — the browser's `localStorage`
|
|
5
|
+
* (offline), an in-memory map (tests/SSR), or a database/Convex/HTTP endpoint
|
|
6
|
+
* (cloud) — so a game switches offline saves for cloud saves by swapping the
|
|
7
|
+
* backend and changing nothing else. Keys are opaque namespaced strings; values
|
|
8
|
+
* are already-serialized strings, so a backend never needs to know the save
|
|
9
|
+
* shape.
|
|
10
|
+
*/
|
|
11
|
+
export interface SaveBackend {
|
|
12
|
+
read(key: string): Promise<string | null>;
|
|
13
|
+
write(key: string, value: string): Promise<void>;
|
|
14
|
+
remove(key: string): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A {@link SaveBackend} over a synchronous {@link KeyValueStorage} — the
|
|
18
|
+
* browser's `localStorage` by default (offline, on-device saves), a test stub,
|
|
19
|
+
* or `null` for memory-only. Storage errors (quota exceeded, private mode, no
|
|
20
|
+
* DOM) degrade to no-ops, so a save never throws into a game tick.
|
|
21
|
+
*
|
|
22
|
+
* @capability local-save persist a game to on-device localStorage (offline)
|
|
23
|
+
*/
|
|
24
|
+
export declare function localSaveBackend(storage?: KeyValueStorage | null): SaveBackend;
|
|
25
|
+
/** A memory-only {@link SaveBackend} — saves survive a reload only within the same session. For tests, SSR, or a "no persistence" mode that still exercises the same save code path. */
|
|
26
|
+
export declare function memorySaveBackend(): SaveBackend;
|
|
27
|
+
/** Adopt any async `read`/`write`/`remove` trio as a {@link SaveBackend} — the seam for cloud saves backed by a database, an HTTP endpoint, or Convex (see `@jgengine/convex/convexSaveBackend`). Reads/writes may reject; the save store surfaces the failure as `"error"` status instead of throwing. */
|
|
28
|
+
export declare function remoteSaveBackend(backend: SaveBackend): SaveBackend;
|
|
29
|
+
/** Lifecycle of the last save/load — drive a "Saving…"/"Saved" indicator or a loading gate off it. `"error"` means the backend rejected a read or write. */
|
|
30
|
+
export type SaveStatus = "idle" | "loading" | "saving" | "saved" | "error";
|
|
31
|
+
/** Autosave cadence: debounce writes `debounceMs` after the last edit, but never wait longer than `maxWaitMs` while edits keep coming (`0` removes the ceiling). `autosave: true` uses `{ debounceMs: 1000, maxWaitMs: 15000 }`. */
|
|
32
|
+
export interface SaveAutoConfig {
|
|
33
|
+
debounceMs?: number;
|
|
34
|
+
maxWaitMs?: number;
|
|
35
|
+
}
|
|
36
|
+
/** The timer seam autosave schedules through — defaults to the ambient `setTimeout`/`clearTimeout`; inject fakes in tests. */
|
|
37
|
+
export interface SaveTimers {
|
|
38
|
+
set(handler: () => void, ms: number): unknown;
|
|
39
|
+
clear(handle: unknown): void;
|
|
40
|
+
}
|
|
41
|
+
/** The versioned envelope written to the backend — `version` lets a later game build detect and {@link SaveStoreConfig.migrate | migrate} an older payload. */
|
|
42
|
+
export interface SaveEnvelope<T> {
|
|
43
|
+
version: number;
|
|
44
|
+
savedAt: number;
|
|
45
|
+
value: T;
|
|
46
|
+
}
|
|
47
|
+
/** How a {@link createSaveStore} is wired — the backend it persists through, the initial value, and optional slot/versioning/autosave/serialization knobs. */
|
|
48
|
+
export interface SaveStoreConfig<T> {
|
|
49
|
+
/** Where saves live — {@link localSaveBackend}, {@link memorySaveBackend}, or a {@link remoteSaveBackend}. */
|
|
50
|
+
backend: SaveBackend;
|
|
51
|
+
/** The value a fresh save starts from (nothing stored yet, or after `clear`). */
|
|
52
|
+
initial: T;
|
|
53
|
+
/** Storage namespace, joined with the slot into the backend key. Default `"save"`. */
|
|
54
|
+
key?: string;
|
|
55
|
+
/** Active save slot — pass distinct slots for multiple parallel saves. Default `"default"`. */
|
|
56
|
+
slot?: string;
|
|
57
|
+
/** Current save-format version. Default `1`. Bump it on a breaking shape change and pass {@link migrate}. */
|
|
58
|
+
version?: number;
|
|
59
|
+
/** Upgrade an older payload to the current shape. Receives the stored value and the version it was written at (`0` for a pre-versioned/raw payload). */
|
|
60
|
+
migrate?: (data: unknown, fromVersion: number) => T;
|
|
61
|
+
/** Autosave on every `set`/`patch`. `false` (default) saves only on an explicit `save()`. */
|
|
62
|
+
autosave?: boolean | SaveAutoConfig;
|
|
63
|
+
serialize?: (envelope: SaveEnvelope<T>) => string;
|
|
64
|
+
deserialize?: (raw: string) => unknown;
|
|
65
|
+
/** Injectable clock (ms). Default `Date.now`. */
|
|
66
|
+
now?: () => number;
|
|
67
|
+
/** Injectable timers for autosave. Default ambient `setTimeout`/`clearTimeout`. */
|
|
68
|
+
timers?: SaveTimers;
|
|
69
|
+
/** Notified on any backend read/write failure — status is already `"error"` when it runs. */
|
|
70
|
+
onError?: (error: unknown) => void;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A pluggable-backend game save with autosave, named slots, and versioned
|
|
74
|
+
* migration. `value()`/`patch()` hold the live state; `load()` hydrates it from
|
|
75
|
+
* the backend; `save()` (or autosave) writes it back. Backend failures surface
|
|
76
|
+
* as `"error"` status and through `onError` — a save never throws into a tick.
|
|
77
|
+
*/
|
|
78
|
+
export interface SaveStore<T> {
|
|
79
|
+
value(): T;
|
|
80
|
+
status(): SaveStatus;
|
|
81
|
+
slot(): string;
|
|
82
|
+
/** Monotonic change counter — bumps on any value or status change; drive `useSyncExternalStore` off it. */
|
|
83
|
+
revision(): number;
|
|
84
|
+
/** Hydrate the active slot from the backend into `value()`; corrupt payloads fall back to `initial`. */
|
|
85
|
+
load(): Promise<T>;
|
|
86
|
+
/** Replace the value and mark it dirty (schedules autosave). */
|
|
87
|
+
set(value: T): void;
|
|
88
|
+
/** Read-modify-write the value and mark it dirty; returns the next value. */
|
|
89
|
+
patch(mutate: (previous: T) => T): T;
|
|
90
|
+
/** Flush the current value to the backend now (serialized against in-flight saves). */
|
|
91
|
+
save(): Promise<void>;
|
|
92
|
+
/** Delete the active slot and reset `value()` to `initial`. */
|
|
93
|
+
clear(): Promise<void>;
|
|
94
|
+
/** Flush any dirty state, switch to `slot`, and load it. */
|
|
95
|
+
switchSlot(slot: string): Promise<T>;
|
|
96
|
+
/** The slots this store has written (for a load/save menu). */
|
|
97
|
+
slots(): Promise<string[]>;
|
|
98
|
+
subscribe(listener: () => void): () => void;
|
|
99
|
+
/** Stop autosave timers and drop listeners. */
|
|
100
|
+
dispose(): void;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Create a {@link SaveStore}. Same call for offline and cloud — only the
|
|
104
|
+
* `backend` differs (localStorage, memory, or an async DB/Convex endpoint). Turn
|
|
105
|
+
* on `autosave` and every `set`/`patch` persists on a debounce; leave it off and
|
|
106
|
+
* call `save()` at checkpoints. Bump `version` + pass `migrate` when the save
|
|
107
|
+
* shape changes so old players keep their progress.
|
|
108
|
+
*
|
|
109
|
+
* @capability game-save save/load game state with a pluggable backend, autosave, slots, and migration
|
|
110
|
+
*/
|
|
111
|
+
export declare function createSaveStore<T>(config: SaveStoreConfig<T>): SaveStore<T>;
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { defaultKeyValueStorage } from "./keyValueStore.js";
|
|
2
|
+
function readSafe(storage, key) {
|
|
3
|
+
if (storage === null)
|
|
4
|
+
return null;
|
|
5
|
+
try {
|
|
6
|
+
return storage.getItem(key);
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A {@link SaveBackend} over a synchronous {@link KeyValueStorage} — the
|
|
14
|
+
* browser's `localStorage` by default (offline, on-device saves), a test stub,
|
|
15
|
+
* or `null` for memory-only. Storage errors (quota exceeded, private mode, no
|
|
16
|
+
* DOM) degrade to no-ops, so a save never throws into a game tick.
|
|
17
|
+
*
|
|
18
|
+
* @capability local-save persist a game to on-device localStorage (offline)
|
|
19
|
+
*/
|
|
20
|
+
export function localSaveBackend(storage) {
|
|
21
|
+
const store = storage === undefined ? defaultKeyValueStorage() : storage;
|
|
22
|
+
return {
|
|
23
|
+
read: (key) => Promise.resolve(readSafe(store, key)),
|
|
24
|
+
write: (key, value) => {
|
|
25
|
+
if (store !== null) {
|
|
26
|
+
try {
|
|
27
|
+
store.setItem(key, value);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// storage rejected the write; the store keeps the value in memory
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return Promise.resolve();
|
|
34
|
+
},
|
|
35
|
+
remove: (key) => {
|
|
36
|
+
if (store !== null) {
|
|
37
|
+
try {
|
|
38
|
+
store.removeItem(key);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// ignore removal failure
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return Promise.resolve();
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** A memory-only {@link SaveBackend} — saves survive a reload only within the same session. For tests, SSR, or a "no persistence" mode that still exercises the same save code path. */
|
|
49
|
+
export function memorySaveBackend() {
|
|
50
|
+
const map = new Map();
|
|
51
|
+
return {
|
|
52
|
+
read: (key) => Promise.resolve(map.get(key) ?? null),
|
|
53
|
+
write: (key, value) => {
|
|
54
|
+
map.set(key, value);
|
|
55
|
+
return Promise.resolve();
|
|
56
|
+
},
|
|
57
|
+
remove: (key) => {
|
|
58
|
+
map.delete(key);
|
|
59
|
+
return Promise.resolve();
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Adopt any async `read`/`write`/`remove` trio as a {@link SaveBackend} — the seam for cloud saves backed by a database, an HTTP endpoint, or Convex (see `@jgengine/convex/convexSaveBackend`). Reads/writes may reject; the save store surfaces the failure as `"error"` status instead of throwing. */
|
|
64
|
+
export function remoteSaveBackend(backend) {
|
|
65
|
+
return backend;
|
|
66
|
+
}
|
|
67
|
+
function defaultTimers() {
|
|
68
|
+
return {
|
|
69
|
+
set: (handler, ms) => globalThis.setTimeout(handler, ms),
|
|
70
|
+
clear: (handle) => globalThis.clearTimeout(handle),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function normalizeAuto(config) {
|
|
74
|
+
if (config === undefined || config === false)
|
|
75
|
+
return null;
|
|
76
|
+
if (config === true)
|
|
77
|
+
return { debounceMs: 1000, maxWaitMs: 15000 };
|
|
78
|
+
return { debounceMs: config.debounceMs ?? 1000, maxWaitMs: config.maxWaitMs ?? 15000 };
|
|
79
|
+
}
|
|
80
|
+
function isEnvelope(value) {
|
|
81
|
+
return (typeof value === "object" &&
|
|
82
|
+
value !== null &&
|
|
83
|
+
typeof value.version === "number" &&
|
|
84
|
+
"value" in value);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Create a {@link SaveStore}. Same call for offline and cloud — only the
|
|
88
|
+
* `backend` differs (localStorage, memory, or an async DB/Convex endpoint). Turn
|
|
89
|
+
* on `autosave` and every `set`/`patch` persists on a debounce; leave it off and
|
|
90
|
+
* call `save()` at checkpoints. Bump `version` + pass `migrate` when the save
|
|
91
|
+
* shape changes so old players keep their progress.
|
|
92
|
+
*
|
|
93
|
+
* @capability game-save save/load game state with a pluggable backend, autosave, slots, and migration
|
|
94
|
+
*/
|
|
95
|
+
export function createSaveStore(config) {
|
|
96
|
+
const namespace = config.key ?? "save";
|
|
97
|
+
const formatVersion = config.version ?? 1;
|
|
98
|
+
const initial = config.initial;
|
|
99
|
+
const backend = config.backend;
|
|
100
|
+
const clock = config.now ?? (() => Date.now());
|
|
101
|
+
const timers = config.timers ?? defaultTimers();
|
|
102
|
+
const auto = normalizeAuto(config.autosave);
|
|
103
|
+
const serialize = config.serialize ?? ((envelope) => JSON.stringify(envelope));
|
|
104
|
+
const deserialize = config.deserialize ?? ((raw) => JSON.parse(raw));
|
|
105
|
+
const onError = config.onError;
|
|
106
|
+
let currentSlot = config.slot ?? "default";
|
|
107
|
+
let current = initial;
|
|
108
|
+
let status = "idle";
|
|
109
|
+
let revision = 0;
|
|
110
|
+
let dirty = false;
|
|
111
|
+
let firstDirtyAt = null;
|
|
112
|
+
let pendingTimer = null;
|
|
113
|
+
let saveChain = Promise.resolve();
|
|
114
|
+
let disposed = false;
|
|
115
|
+
const listeners = new Set();
|
|
116
|
+
function emit() {
|
|
117
|
+
revision += 1;
|
|
118
|
+
for (const listener of listeners)
|
|
119
|
+
listener();
|
|
120
|
+
}
|
|
121
|
+
function setStatus(next) {
|
|
122
|
+
if (status === next)
|
|
123
|
+
return;
|
|
124
|
+
status = next;
|
|
125
|
+
emit();
|
|
126
|
+
}
|
|
127
|
+
function reportError(error) {
|
|
128
|
+
onError?.(error);
|
|
129
|
+
}
|
|
130
|
+
const dataKey = (slot) => `${namespace}:${slot}`;
|
|
131
|
+
const indexKey = () => `${namespace}:__slots__`;
|
|
132
|
+
function decode(raw) {
|
|
133
|
+
const parsed = deserialize(raw);
|
|
134
|
+
if (isEnvelope(parsed)) {
|
|
135
|
+
if (parsed.version === formatVersion)
|
|
136
|
+
return parsed.value;
|
|
137
|
+
if (config.migrate)
|
|
138
|
+
return config.migrate(parsed.value, parsed.version);
|
|
139
|
+
return parsed.value;
|
|
140
|
+
}
|
|
141
|
+
if (config.migrate)
|
|
142
|
+
return config.migrate(parsed, 0);
|
|
143
|
+
return parsed;
|
|
144
|
+
}
|
|
145
|
+
async function readSlots() {
|
|
146
|
+
try {
|
|
147
|
+
const raw = await backend.read(indexKey());
|
|
148
|
+
if (raw === null)
|
|
149
|
+
return [];
|
|
150
|
+
const parsed = JSON.parse(raw);
|
|
151
|
+
return Array.isArray(parsed) ? parsed.filter((entry) => typeof entry === "string") : [];
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async function rememberSlot(slot) {
|
|
158
|
+
try {
|
|
159
|
+
const list = await readSlots();
|
|
160
|
+
if (list.includes(slot))
|
|
161
|
+
return;
|
|
162
|
+
await backend.write(indexKey(), JSON.stringify([...list, slot]));
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
reportError(error);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async function forgetSlot(slot) {
|
|
169
|
+
try {
|
|
170
|
+
const list = await readSlots();
|
|
171
|
+
if (!list.includes(slot))
|
|
172
|
+
return;
|
|
173
|
+
await backend.write(indexKey(), JSON.stringify(list.filter((entry) => entry !== slot)));
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
reportError(error);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function clearTimer() {
|
|
180
|
+
if (pendingTimer !== null) {
|
|
181
|
+
timers.clear(pendingTimer);
|
|
182
|
+
pendingTimer = null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function markDirty() {
|
|
186
|
+
dirty = true;
|
|
187
|
+
if (auto === null)
|
|
188
|
+
return;
|
|
189
|
+
const now = clock();
|
|
190
|
+
if (firstDirtyAt === null)
|
|
191
|
+
firstDirtyAt = now;
|
|
192
|
+
if (auto.maxWaitMs > 0 && now - firstDirtyAt >= auto.maxWaitMs) {
|
|
193
|
+
clearTimer();
|
|
194
|
+
void save();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
clearTimer();
|
|
198
|
+
pendingTimer = timers.set(() => {
|
|
199
|
+
pendingTimer = null;
|
|
200
|
+
void save();
|
|
201
|
+
}, auto.debounceMs);
|
|
202
|
+
}
|
|
203
|
+
async function flush() {
|
|
204
|
+
if (disposed)
|
|
205
|
+
return;
|
|
206
|
+
clearTimer();
|
|
207
|
+
const slot = currentSlot;
|
|
208
|
+
const value = current;
|
|
209
|
+
setStatus("saving");
|
|
210
|
+
try {
|
|
211
|
+
const envelope = { version: formatVersion, savedAt: clock(), value };
|
|
212
|
+
await backend.write(dataKey(slot), serialize(envelope));
|
|
213
|
+
await rememberSlot(slot);
|
|
214
|
+
if (current === value) {
|
|
215
|
+
dirty = false;
|
|
216
|
+
firstDirtyAt = null;
|
|
217
|
+
}
|
|
218
|
+
setStatus("saved");
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
setStatus("error");
|
|
222
|
+
reportError(error);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function save() {
|
|
226
|
+
const run = saveChain.then(() => flush());
|
|
227
|
+
saveChain = run.catch(() => undefined);
|
|
228
|
+
return run;
|
|
229
|
+
}
|
|
230
|
+
async function load() {
|
|
231
|
+
setStatus("loading");
|
|
232
|
+
try {
|
|
233
|
+
const raw = await backend.read(dataKey(currentSlot));
|
|
234
|
+
let value;
|
|
235
|
+
try {
|
|
236
|
+
value = raw === null ? initial : decode(raw);
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
value = initial;
|
|
240
|
+
}
|
|
241
|
+
current = value;
|
|
242
|
+
dirty = false;
|
|
243
|
+
firstDirtyAt = null;
|
|
244
|
+
setStatus("idle");
|
|
245
|
+
emit();
|
|
246
|
+
void rememberSlot(currentSlot);
|
|
247
|
+
return current;
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
setStatus("error");
|
|
251
|
+
reportError(error);
|
|
252
|
+
return current;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
value: () => current,
|
|
257
|
+
status: () => status,
|
|
258
|
+
slot: () => currentSlot,
|
|
259
|
+
revision: () => revision,
|
|
260
|
+
load,
|
|
261
|
+
set(value) {
|
|
262
|
+
current = value;
|
|
263
|
+
emit();
|
|
264
|
+
markDirty();
|
|
265
|
+
},
|
|
266
|
+
patch(mutate) {
|
|
267
|
+
current = mutate(current);
|
|
268
|
+
emit();
|
|
269
|
+
markDirty();
|
|
270
|
+
return current;
|
|
271
|
+
},
|
|
272
|
+
save,
|
|
273
|
+
async clear() {
|
|
274
|
+
clearTimer();
|
|
275
|
+
const slot = currentSlot;
|
|
276
|
+
setStatus("saving");
|
|
277
|
+
try {
|
|
278
|
+
await backend.remove(dataKey(slot));
|
|
279
|
+
await forgetSlot(slot);
|
|
280
|
+
current = initial;
|
|
281
|
+
dirty = false;
|
|
282
|
+
firstDirtyAt = null;
|
|
283
|
+
setStatus("idle");
|
|
284
|
+
emit();
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
setStatus("error");
|
|
288
|
+
reportError(error);
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
async switchSlot(slot) {
|
|
292
|
+
if (dirty)
|
|
293
|
+
await save();
|
|
294
|
+
clearTimer();
|
|
295
|
+
currentSlot = slot;
|
|
296
|
+
current = initial;
|
|
297
|
+
dirty = false;
|
|
298
|
+
firstDirtyAt = null;
|
|
299
|
+
return load();
|
|
300
|
+
},
|
|
301
|
+
slots: readSlots,
|
|
302
|
+
subscribe(listener) {
|
|
303
|
+
listeners.add(listener);
|
|
304
|
+
return () => listeners.delete(listener);
|
|
305
|
+
},
|
|
306
|
+
dispose() {
|
|
307
|
+
disposed = true;
|
|
308
|
+
clearTimer();
|
|
309
|
+
listeners.clear();
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** Bounded past/future snapshot stacks — a serializable undo/redo record for any state `T`. */
|
|
2
|
+
export interface HistoryStacks<T> {
|
|
3
|
+
/** Prior states, oldest first; the last entry is the step an undo restores. */
|
|
4
|
+
readonly past: readonly T[];
|
|
5
|
+
/** Undone states awaiting redo, oldest first; the last entry is the step a redo restores. */
|
|
6
|
+
readonly future: readonly T[];
|
|
7
|
+
}
|
|
8
|
+
/** The snapshot an undo/redo restores plus the advanced stacks. */
|
|
9
|
+
export interface HistoryStep<T> {
|
|
10
|
+
/** State to apply as the new present. */
|
|
11
|
+
snapshot: T;
|
|
12
|
+
/** Stacks after the step. */
|
|
13
|
+
stacks: HistoryStacks<T>;
|
|
14
|
+
}
|
|
15
|
+
/** Empty history stacks for state `T`.
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export declare function emptyHistory<T>(): HistoryStacks<T>;
|
|
19
|
+
/** True when there is a prior state to undo to.
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare function canUndo<T>(stacks: HistoryStacks<T>): boolean;
|
|
23
|
+
/** True when there is an undone state to redo.
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export declare function canRedo<T>(stacks: HistoryStacks<T>): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Record `present` as the newest undo step and clear the redo future (a fresh action forks history).
|
|
29
|
+
* The oldest past entries beyond `limit` are dropped so the stack stays bounded for save/transport.
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export declare function recordSnapshot<T>(stacks: HistoryStacks<T>, present: T, limit?: number): HistoryStacks<T>;
|
|
33
|
+
/**
|
|
34
|
+
* Step back: pop the newest past snapshot to apply as the new present, and push the given `present`
|
|
35
|
+
* onto the future for a later redo. Returns `null` when there is nothing to undo.
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
export declare function undoSnapshot<T>(stacks: HistoryStacks<T>, present: T): HistoryStep<T> | null;
|
|
39
|
+
/**
|
|
40
|
+
* Step forward: pop the newest future snapshot to apply as the new present, and push the given
|
|
41
|
+
* `present` back onto the past. Returns `null` when there is nothing to redo.
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
export declare function redoSnapshot<T>(stacks: HistoryStacks<T>, present: T): HistoryStep<T> | null;
|
|
45
|
+
/** Stateful undo/redo handle over {@link HistoryStacks}, holding the stacks in a closure. */
|
|
46
|
+
export interface SnapshotHistory<T> {
|
|
47
|
+
/** Record `present` as a new undo step and clear the redo future. */
|
|
48
|
+
record(present: T): void;
|
|
49
|
+
/** Undo, returning the restored snapshot or `null` if there is nothing to undo. */
|
|
50
|
+
undo(present: T): T | null;
|
|
51
|
+
/** Redo, returning the restored snapshot or `null` if there is nothing to redo. */
|
|
52
|
+
redo(present: T): T | null;
|
|
53
|
+
/** True when an undo is available. */
|
|
54
|
+
canUndo(): boolean;
|
|
55
|
+
/** True when a redo is available. */
|
|
56
|
+
canRedo(): boolean;
|
|
57
|
+
/** Drop all history. */
|
|
58
|
+
clear(): void;
|
|
59
|
+
/** Current immutable stacks (for serialization). */
|
|
60
|
+
stacks(): HistoryStacks<T>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Stateful undo/redo handle wrapping the pure snapshot functions. Call `record(state)` before each
|
|
64
|
+
* mutation; `undo`/`redo` return the state to apply. `limit` bounds the past stack.
|
|
65
|
+
* @internal
|
|
66
|
+
*/
|
|
67
|
+
export declare function createSnapshotHistory<T>(limit?: number): SnapshotHistory<T>;
|