@jgengine/core 0.18.1 → 0.21.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 +504 -7
- package/dist/ai/decisionGraph.d.ts +50 -4
- package/dist/ai/decisionGraph.js +159 -23
- package/dist/ai/flock.d.ts +1 -1
- package/dist/ai/flock.js +7 -4
- package/dist/ai/groupAssist.d.ts +10 -0
- package/dist/ai/groupAssist.js +11 -0
- package/dist/ai/pursuit.d.ts +1 -1
- package/dist/ai/pursuit.js +1 -1
- package/dist/ai/threat.d.ts +8 -0
- package/dist/ai/threat.js +10 -0
- package/dist/anim/animGraph.d.ts +43 -1
- package/dist/anim/animGraph.js +326 -10
- package/dist/anim/boneTexture.d.ts +55 -0
- package/dist/anim/boneTexture.js +43 -0
- package/dist/anim/footPlacement.d.ts +57 -0
- package/dist/anim/footPlacement.js +67 -0
- package/dist/anim/locomotionGraph.d.ts +18 -1
- package/dist/anim/locomotionGraph.js +42 -3
- package/dist/audio/audioFalloff.d.ts +6 -0
- package/dist/audio/doppler.d.ts +21 -0
- package/dist/audio/doppler.js +32 -0
- package/dist/audio/engineLayers.d.ts +83 -0
- package/dist/audio/engineLayers.js +115 -0
- package/dist/audio/voiceAllocator.d.ts +46 -0
- package/dist/audio/voiceAllocator.js +76 -0
- package/dist/combat/abilityKit.d.ts +20 -0
- package/dist/combat/abilityKit.js +41 -4
- package/dist/combat/death.d.ts +11 -3
- package/dist/combat/death.js +3 -3
- package/dist/combat/magazine.d.ts +9 -0
- package/dist/combat/magazine.js +24 -2
- package/dist/combat/projectiles.d.ts +94 -2
- package/dist/combat/projectiles.js +282 -61
- package/dist/combat/regenShield.d.ts +14 -0
- package/dist/combat/regenShield.js +23 -7
- package/dist/combat/shotOrigin.d.ts +6 -0
- package/dist/combat/shotOrigin.js +6 -0
- package/dist/combat/weaponFeedback.d.ts +36 -0
- package/dist/combat/weaponFeedback.js +42 -0
- package/dist/combat/weaponHandling.d.ts +161 -0
- package/dist/combat/weaponHandling.js +202 -0
- package/dist/combat/weaponPresentation.d.ts +115 -0
- package/dist/combat/weaponPresentation.js +96 -0
- package/dist/crafting/recipeCatalog.d.ts +16 -0
- package/dist/crafting/recipeCatalog.js +55 -0
- package/dist/devtools/warnOnce.d.ts +8 -0
- package/dist/devtools/warnOnce.js +18 -0
- package/dist/economy/auctionBook.d.ts +1 -1
- package/dist/economy/auctionBook.js +11 -1
- package/dist/economy/listingBook.d.ts +1 -1
- package/dist/economy/listingBook.js +11 -1
- package/dist/economy/resourceLedger.js +3 -3
- package/dist/economy/shopStock.js +7 -6
- package/dist/economy/techTree.js +7 -6
- package/dist/economy/unlockPoints.js +3 -6
- package/dist/editor/commandApply.js +89 -16
- package/dist/editor/commands.d.ts +38 -1
- package/dist/editor/commands.js +320 -3
- package/dist/editor/creatorStorage.d.ts +59 -0
- package/dist/editor/creatorStorage.js +164 -0
- package/dist/editor/document.d.ts +4 -0
- package/dist/editor/document.js +119 -18
- package/dist/editor/environment.js +8 -0
- package/dist/editor/index.d.ts +2 -0
- package/dist/editor/liveSync.d.ts +4 -1
- package/dist/editor/liveSync.js +26 -10
- package/dist/editor/materialAuthoring.d.ts +14 -0
- package/dist/editor/materialAuthoring.js +38 -0
- package/dist/editor/modelNodeVisibility.d.ts +11 -0
- package/dist/editor/modelNodeVisibility.js +29 -0
- package/dist/editor/movementCatalog.d.ts +90 -0
- package/dist/editor/movementCatalog.js +144 -0
- package/dist/editor/simulation.d.ts +60 -0
- package/dist/editor/simulation.js +202 -0
- package/dist/editor/staticPrefab.d.ts +17 -0
- package/dist/editor/staticPrefab.js +51 -0
- package/dist/editor/types.d.ts +15 -0
- package/dist/faction/reputation.d.ts +6 -0
- package/dist/faction/reputation.js +11 -0
- package/dist/game/cameraConfig.d.ts +54 -2
- package/dist/game/clipRoles.d.ts +2 -1
- package/dist/game/clipRoles.js +7 -3
- package/dist/game/contentValidation.d.ts +69 -0
- package/dist/game/contentValidation.js +118 -0
- package/dist/game/controlGate.d.ts +8 -0
- package/dist/game/controlGate.js +43 -6
- package/dist/game/defineGame.d.ts +32 -3
- package/dist/game/dialogueGraph.d.ts +20 -0
- package/dist/game/dialogueGraph.js +107 -0
- package/dist/game/events.d.ts +11 -0
- package/dist/game/keyValueStore.d.ts +17 -4
- package/dist/game/keyValueStore.js +35 -23
- package/dist/game/lootModifiers.d.ts +17 -0
- package/dist/game/lootModifiers.js +26 -0
- package/dist/game/lootTable.d.ts +4 -0
- package/dist/game/lootTable.js +16 -0
- package/dist/game/narrativeAuthoring.d.ts +67 -0
- package/dist/game/narrativeAuthoring.js +122 -0
- package/dist/game/playableGame.d.ts +134 -35
- package/dist/game/quest.d.ts +15 -0
- package/dist/game/quest.js +209 -63
- package/dist/game/questCatalog.d.ts +50 -0
- package/dist/game/questCatalog.js +205 -0
- package/dist/game/saveStore.d.ts +6 -5
- package/dist/game/saveStore.js +57 -57
- package/dist/game/systemRuntime.d.ts +2 -2
- package/dist/game/systemRuntime.js +84 -33
- package/dist/game/toasts.d.ts +8 -0
- package/dist/game/toasts.js +7 -0
- package/dist/game/vfxInstance.d.ts +9 -0
- package/dist/game/vfxInstance.js +12 -1
- package/dist/game/viewports.d.ts +43 -0
- package/dist/game/viewports.js +46 -0
- package/dist/game/worldItem.d.ts +5 -1
- package/dist/game/worldItem.js +0 -1
- package/dist/gameplay.d.ts +3 -0
- package/dist/gameplay.js +3 -0
- package/dist/input/actionBindings.d.ts +15 -1
- package/dist/input/actionBindings.js +14 -3
- package/dist/input/actionContexts.d.ts +25 -1
- package/dist/input/actionContexts.js +82 -25
- package/dist/input/axisInput.d.ts +4 -0
- package/dist/input/axisInput.js +4 -0
- package/dist/input/axisShaper.d.ts +73 -0
- package/dist/input/axisShaper.js +105 -0
- package/dist/input/gamepadModel.d.ts +36 -2
- package/dist/input/gamepadModel.js +69 -30
- package/dist/input/haptics.d.ts +50 -0
- package/dist/input/haptics.js +74 -0
- package/dist/input/inputBuffer.d.ts +40 -0
- package/dist/input/inputBuffer.js +59 -0
- package/dist/input/lookChannel.d.ts +10 -0
- package/dist/input/lookChannel.js +6 -0
- package/dist/input/pointer.d.ts +2 -0
- package/dist/input/pointer.js +4 -0
- package/dist/interaction/promptRegistry.d.ts +5 -4
- package/dist/interaction/promptRegistry.js +8 -2
- package/dist/inventory/inventoryModel.js +9 -6
- package/dist/inventory/shapedGrid.d.ts +48 -9
- package/dist/inventory/shapedGrid.js +69 -10
- package/dist/item/affix.d.ts +6 -0
- package/dist/item/affix.js +6 -0
- package/dist/item/durability.js +4 -0
- package/dist/item/itemInstanceRegistry.d.ts +32 -1
- package/dist/item/itemInstanceRegistry.js +111 -7
- package/dist/item/itemgen.d.ts +1 -1
- package/dist/item/itemgen.js +1 -1
- package/dist/item/modularItem.js +7 -1
- package/dist/material/appearanceSignals.d.ts +53 -0
- package/dist/material/appearanceSignals.js +47 -0
- package/dist/material/hairCards.d.ts +47 -0
- package/dist/material/hairCards.js +136 -0
- package/dist/material/materialAsset.d.ts +162 -0
- package/dist/material/materialAsset.js +382 -0
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +444 -1
- package/dist/movement/characterController.d.ts +5 -2
- package/dist/movement/characterController.js +50 -23
- package/dist/movement/freeFlight.d.ts +2 -2
- package/dist/movement/freeFlight.js +3 -3
- package/dist/movement/glideModel.d.ts +3 -0
- package/dist/movement/glideModel.js +6 -0
- package/dist/movement/grappleSwing.d.ts +2 -0
- package/dist/movement/grappleSwing.js +5 -1
- package/dist/movement/movementModel.d.ts +63 -1
- package/dist/movement/movementModel.js +136 -26
- package/dist/movement/movementProbe.d.ts +51 -0
- package/dist/movement/movementProbe.js +119 -0
- package/dist/movement/playerMovement.d.ts +48 -2
- package/dist/movement/playerMovement.js +493 -87
- package/dist/movement/poseState.d.ts +2 -0
- package/dist/movement/poseState.js +29 -1
- package/dist/movement/solidObstacles.d.ts +11 -1
- package/dist/movement/solidObstacles.js +48 -3
- package/dist/movement/terrainGrade.d.ts +13 -0
- package/dist/movement/terrainGrade.js +33 -0
- package/dist/movement/voxelController.d.ts +2 -2
- package/dist/movement/voxelController.js +10 -10
- package/dist/nav/navFromEnvironment.d.ts +9 -3
- package/dist/nav/navFromEnvironment.js +18 -12
- package/dist/nav/navGrid.d.ts +19 -1
- package/dist/nav/navGrid.js +26 -10
- package/dist/nav/navMesh.d.ts +43 -2
- package/dist/nav/navMesh.js +534 -128
- package/dist/nav/solidRoute.d.ts +50 -0
- package/dist/nav/solidRoute.js +144 -0
- package/dist/physics/aircraftDynamics.d.ts +390 -0
- package/dist/physics/aircraftDynamics.js +704 -0
- package/dist/physics/ballisticSweep.d.ts +10 -3
- package/dist/physics/ballisticSweep.js +53 -29
- package/dist/physics/boatDynamics.d.ts +116 -0
- package/dist/physics/boatDynamics.js +160 -0
- package/dist/physics/drivableVehicle.d.ts +22 -8
- package/dist/physics/drivableVehicle.js +4 -2
- package/dist/physics/flightDynamics.d.ts +21 -4
- package/dist/physics/flightDynamics.js +28 -5
- package/dist/physics/forceVolume.d.ts +41 -0
- package/dist/physics/forceVolume.js +88 -0
- package/dist/physics/handlingProbe.d.ts +249 -0
- package/dist/physics/handlingProbe.js +606 -0
- package/dist/physics/kinematicVehicle.d.ts +40 -5
- package/dist/physics/kinematicVehicle.js +17 -2
- package/dist/physics/physicsBackend.d.ts +12 -0
- package/dist/physics/physicsBackendConformance.js +34 -0
- package/dist/physics/physicsWorldBackend.d.ts +1 -0
- package/dist/physics/physicsWorldBackend.js +52 -3
- package/dist/physics/spatialGrid.d.ts +1 -1
- package/dist/physics/spatialGrid.js +8 -9
- package/dist/physics/vehicleBackendLink.d.ts +49 -0
- package/dist/physics/vehicleBackendLink.js +102 -0
- package/dist/physics/vehicleDynamics.d.ts +375 -0
- package/dist/physics/vehicleDynamics.js +737 -0
- package/dist/physics/vehicleObstacles.d.ts +3 -2
- package/dist/physics/vehicleObstacles.js +29 -5
- package/dist/physics/worldColliders.d.ts +1 -1
- package/dist/physics/worldColliders.js +35 -3
- package/dist/puzzle/cellGrid.d.ts +15 -9
- package/dist/puzzle/cellGrid.js +13 -9
- package/dist/render/lookPreset.d.ts +9 -2
- package/dist/render/lookPreset.js +29 -2
- package/dist/render/postProcessing.d.ts +30 -0
- package/dist/render/postProcessing.js +1 -1
- package/dist/runtime/cameraDirector.d.ts +54 -3
- package/dist/runtime/cameraDirector.js +187 -0
- package/dist/runtime/commandDispatch.d.ts +14 -0
- package/dist/runtime/commandDispatch.js +19 -0
- package/dist/runtime/commandInput.d.ts +37 -0
- package/dist/runtime/commandInput.js +58 -0
- package/dist/runtime/commandRunner.d.ts +27 -0
- package/dist/runtime/commandRunner.js +31 -3
- package/dist/runtime/context/combat.d.ts +12 -4
- package/dist/runtime/context/combat.js +179 -11
- package/dist/runtime/context/deathLoot.d.ts +11 -8
- package/dist/runtime/context/deathLoot.js +17 -16
- package/dist/runtime/context/scene.d.ts +2 -0
- package/dist/runtime/context/scene.js +13 -21
- package/dist/runtime/descriptors/baseline.js +34 -3
- package/dist/runtime/descriptors/features.d.ts +2 -1
- package/dist/runtime/descriptors/features.js +18 -0
- package/dist/runtime/gameContext.js +86 -13
- package/dist/runtime/gameContextTypes.d.ts +33 -3
- package/dist/runtime/gameRuntime.d.ts +3 -1
- package/dist/runtime/gameRuntime.js +4 -0
- package/dist/runtime/headlessRunner.d.ts +3 -1
- package/dist/runtime/headlessRunner.js +11 -11
- package/dist/runtime/hostedGameRunner.d.ts +24 -1
- package/dist/runtime/hostedGameRunner.js +156 -10
- package/dist/runtime/hostedWorldSession.d.ts +17 -5
- package/dist/runtime/hostedWorldSession.js +154 -16
- package/dist/runtime/hostedWorldStore.d.ts +2 -2
- package/dist/runtime/inputRecorder.d.ts +1 -1
- package/dist/runtime/inputRecorder.js +21 -1
- package/dist/runtime/inputSnapshot.d.ts +22 -4
- package/dist/runtime/inputSnapshot.js +41 -3
- package/dist/runtime/localPlayers.d.ts +73 -0
- package/dist/runtime/localPlayers.js +119 -0
- package/dist/runtime/runtimeSave.d.ts +10 -6
- package/dist/runtime/runtimeSave.js +11 -5
- package/dist/runtime/simContext.d.ts +8 -3
- package/dist/runtime/simContext.js +7 -3
- package/dist/runtime/simSnapshot.js +2 -0
- package/dist/runtime/transport.d.ts +9 -0
- package/dist/runtime/transport.js +7 -1
- package/dist/runtime/worldReplication.d.ts +2 -0
- package/dist/runtime/worldReplication.js +1 -1
- package/dist/scene/assetCatalog.d.ts +2 -0
- package/dist/scene/behaviorRuntime.d.ts +38 -7
- package/dist/scene/behaviorRuntime.js +293 -30
- package/dist/scene/behaviors.d.ts +35 -2
- package/dist/scene/behaviors.js +29 -0
- package/dist/scene/entityStore.d.ts +14 -3
- package/dist/scene/entityStore.js +45 -9
- package/dist/scene/mount.d.ts +9 -0
- package/dist/scene/mount.js +35 -0
- package/dist/scene/possession.d.ts +2 -0
- package/dist/scene/possession.js +21 -1
- package/dist/scene/sceneKinds.d.ts +9 -0
- package/dist/scene/sceneRaycast.d.ts +7 -0
- package/dist/scene/sceneRaycast.js +55 -0
- package/dist/scene/spatial.d.ts +20 -1
- package/dist/scene/spatial.js +94 -2
- package/dist/scene/vehicleSeat.d.ts +41 -3
- package/dist/scene/vehicleSeat.js +94 -3
- package/dist/sensor/concealment.d.ts +6 -0
- package/dist/sensor/concealment.js +8 -0
- package/dist/sensor/freezeMonitor.d.ts +6 -0
- package/dist/sensor/freezeMonitor.js +8 -0
- package/dist/sensor/perception.d.ts +11 -1
- package/dist/sensor/perception.js +57 -10
- package/dist/sensor/recordingBuffer.d.ts +3 -0
- package/dist/sensor/recordingBuffer.js +8 -0
- package/dist/session/roundState.d.ts +4 -0
- package/dist/session/roundState.js +11 -0
- package/dist/settings/frameRateLimit.d.ts +16 -0
- package/dist/settings/frameRateLimit.js +37 -0
- package/dist/settings/graphicsProfile.d.ts +2 -0
- package/dist/settings/graphicsProfile.js +12 -0
- package/dist/settings/graphicsSettings.d.ts +40 -0
- package/dist/settings/graphicsSettings.js +81 -0
- package/dist/settings/settingsModel.d.ts +9 -1
- package/dist/settings/settingsModel.js +10 -0
- package/dist/stats/accumulatorMeter.d.ts +10 -0
- package/dist/stats/accumulatorMeter.js +6 -0
- package/dist/stats/eventMeter.d.ts +10 -3
- package/dist/stats/eventMeter.js +6 -3
- package/dist/store/defineStore.d.ts +3 -1
- package/dist/store/defineStore.js +3 -1
- package/dist/store/observableKeyedStore.d.ts +1 -1
- package/dist/store/observableKeyedStore.js +8 -6
- package/dist/time/simClock.d.ts +6 -2
- package/dist/time/simClock.js +5 -0
- package/dist/vfx/feedbackMixer.d.ts +61 -0
- package/dist/vfx/feedbackMixer.js +106 -0
- package/dist/vfx/particleDirector.d.ts +58 -6
- package/dist/vfx/particleDirector.js +113 -22
- package/dist/vfx/particles.d.ts +68 -5
- package/dist/vfx/particles.js +284 -32
- package/dist/visibility/assetStreaming.d.ts +21 -3
- package/dist/visibility/assetStreaming.js +108 -24
- package/dist/visibility/settings.d.ts +8 -2
- package/dist/visibility/settings.js +3 -0
- package/dist/visibility/simulationCulling.d.ts +8 -1
- package/dist/visibility/simulationCulling.js +7 -0
- package/dist/visibility/spatialIndex.d.ts +21 -0
- package/dist/visibility/spatialIndex.js +16 -0
- package/dist/visibility/visibilitySystem.js +1 -0
- package/dist/work/expedition.d.ts +110 -0
- package/dist/work/expedition.js +195 -0
- package/dist/work/staffedStation.d.ts +29 -0
- package/dist/work/staffedStation.js +27 -0
- package/dist/world/authoredAnimation.d.ts +38 -0
- package/dist/world/authoredAnimation.js +99 -0
- package/dist/world/authoredObjects.d.ts +24 -4
- package/dist/world/authoredObjects.js +43 -16
- package/dist/world/authoredSimulation.d.ts +74 -0
- package/dist/world/authoredSimulation.js +302 -0
- package/dist/world/authoredSolids.d.ts +46 -0
- package/dist/world/authoredSolids.js +75 -0
- package/dist/world/authoredWeather.d.ts +120 -0
- package/dist/world/authoredWeather.js +314 -0
- package/dist/world/buildingGenerator.js +2 -2
- package/dist/world/buildingKit.d.ts +11 -4
- package/dist/world/buildingKit.js +21 -8
- package/dist/world/buildings.d.ts +34 -2
- package/dist/world/buildings.js +11 -1
- package/dist/world/cityKind.d.ts +7 -0
- package/dist/world/cityKind.js +52 -1
- package/dist/world/environmentForces.d.ts +21 -0
- package/dist/world/environmentForces.js +42 -0
- package/dist/world/features.d.ts +32 -5
- package/dist/world/features.js +6 -0
- package/dist/world/footprintGrid.d.ts +62 -0
- package/dist/world/footprintGrid.js +217 -0
- package/dist/world/interiors.d.ts +1 -0
- package/dist/world/interiors.js +5 -3
- package/dist/world/lod.d.ts +6 -0
- package/dist/world/lod.js +8 -0
- package/dist/world/pathTerrain.d.ts +1 -1
- package/dist/world/terraform.d.ts +9 -1
- package/dist/world/terraform.js +53 -18
- package/dist/world/walls.d.ts +7 -0
- package/dist/world/walls.js +7 -0
- package/dist/world/weather.d.ts +17 -0
- package/dist/world/weather.js +116 -20
- package/dist/world/worldSolids.d.ts +95 -0
- package/dist/world/worldSolids.js +351 -0
- package/dist/world.d.ts +6 -6
- package/dist/world.js +5 -5
- package/package.json +1 -1
- package/skills/ce-handoff/SKILL.md +2 -2
- package/skills/game-design/SKILL.md +2 -2
- package/skills/jgengine/SKILL.md +28 -6
- package/skills/jgengine/api.md +139 -99
- package/skills/jgengine/capabilities.md +28 -0
- package/skills/jgengine/recipes/minimal-game.md +10 -2
- package/skills/jgengine-combat/SKILL.md +13 -2
- package/skills/jgengine-combat/api.md +150 -103
- package/skills/jgengine-combat/capabilities.md +29 -1
- package/skills/jgengine-combat/recipes/portable-runtime-state.md +60 -6
- package/skills/jgengine-combat/recipes/portable-weapon-plumbing.md +37 -3
- package/skills/jgengine-combat/recipes/weapon-feel.md +50 -0
- package/skills/jgengine-combat/reference.md +24 -2
- package/skills/jgengine-gameplay/SKILL.md +63 -0
- package/skills/jgengine-gameplay/api.md +583 -463
- package/skills/jgengine-gameplay/capabilities.md +92 -0
- package/skills/jgengine-gameplay/recipes/device-save-status.md +46 -0
- package/skills/jgengine-gameplay/recipes/expeditions.md +108 -0
- package/skills/jgengine-gameplay/recipes/narrative-authoring.md +76 -0
- package/skills/jgengine-gameplay/recipes/paged-item-storage.md +101 -0
- package/skills/jgengine-gameplay/recipes/quest-authoring.md +63 -0
- package/skills/jgengine-gameplay/recipes/shaped-inventory.md +50 -0
- package/skills/jgengine-gameplay/reference-content-validation.md +74 -0
- package/skills/jgengine-gameplay/reference-systems.md +123 -0
- package/skills/jgengine-world/SKILL.md +25 -4
- package/skills/jgengine-world/api.md +1045 -655
- package/skills/jgengine-world/capabilities.md +246 -9
- package/skills/jgengine-world/recipes/character-animation.md +62 -0
- package/skills/jgengine-world/recipes/controls.md +48 -0
- package/skills/jgengine-world/recipes/flight-feel.md +76 -0
- package/skills/jgengine-world/recipes/npc-senses.md +55 -0
- package/skills/jgengine-world/recipes/vehicle-feel.md +87 -0
- package/skills/jgengine-world/reference.md +180 -4
- package/skills/jgengine-world/visibility.md +139 -0
|
@@ -1,14 +1,31 @@
|
|
|
1
1
|
import { DEFAULT_STREAMING_SETTINGS, mergeStreamingSettings } from "./settings.js";
|
|
2
2
|
import { nowMs } from "./diagnostics.js";
|
|
3
|
+
/** Stream shared resources with bounded load concurrency, per-tick resident-byte eviction, and explicit inactive-history cleanup. */
|
|
3
4
|
export function createAssetStreamingSystem(options) {
|
|
4
|
-
|
|
5
|
+
function mergeSettings(base, patch) {
|
|
6
|
+
const next = mergeStreamingSettings(base, patch);
|
|
7
|
+
if (!Number.isSafeInteger(next.maxConcurrentLoads) || next.maxConcurrentLoads < 0) {
|
|
8
|
+
throw new RangeError("AssetStreamingSystem: maxConcurrentLoads must be a nonnegative safe integer");
|
|
9
|
+
}
|
|
10
|
+
if (next.maxResidentBytes !== Infinity && (!Number.isFinite(next.maxResidentBytes) || next.maxResidentBytes < 0)) {
|
|
11
|
+
throw new RangeError("AssetStreamingSystem: maxResidentBytes must be nonnegative and finite, or Infinity");
|
|
12
|
+
}
|
|
13
|
+
if (next.residentEvictionOrder !== "oldest" && next.residentEvictionOrder !== "largest") {
|
|
14
|
+
throw new RangeError("AssetStreamingSystem: residentEvictionOrder must be oldest or largest");
|
|
15
|
+
}
|
|
16
|
+
return next;
|
|
17
|
+
}
|
|
18
|
+
let settings = mergeSettings(DEFAULT_STREAMING_SETTINGS, options.settings ?? {});
|
|
5
19
|
const clock = options.now ?? nowMs;
|
|
6
20
|
const records = new Map();
|
|
7
21
|
const queued = new Set();
|
|
22
|
+
const residents = new Set();
|
|
23
|
+
const unknownSizes = new Set();
|
|
8
24
|
const signals = new Map();
|
|
9
25
|
const inFlight = new Set();
|
|
10
26
|
let unloadedTotal = 0;
|
|
11
27
|
let cancelledTotal = 0;
|
|
28
|
+
let budgetEvictedTotal = 0;
|
|
12
29
|
function ensure(id) {
|
|
13
30
|
let record = records.get(id);
|
|
14
31
|
if (record === undefined) {
|
|
@@ -31,29 +48,56 @@ export function createAssetStreamingSystem(options) {
|
|
|
31
48
|
record.state = "loading";
|
|
32
49
|
const signal = { cancelled: false };
|
|
33
50
|
signals.set(record.id, signal);
|
|
34
|
-
|
|
35
|
-
|
|
51
|
+
let loading;
|
|
52
|
+
try {
|
|
53
|
+
loading = options.load(record.id, signal);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
loading = Promise.reject(error);
|
|
57
|
+
}
|
|
58
|
+
const promise = loading
|
|
36
59
|
.then((result) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
record.state = "unloaded";
|
|
60
|
+
if (signal.cancelled || records.get(record.id) !== record) {
|
|
61
|
+
options.unload?.(record.id);
|
|
40
62
|
return;
|
|
41
63
|
}
|
|
42
64
|
record.state = "loaded";
|
|
43
|
-
|
|
65
|
+
const knownSize = typeof result.bytes === "number" && Number.isFinite(result.bytes) && result.bytes >= 0;
|
|
66
|
+
record.bytes = knownSize ? result.bytes : 0;
|
|
67
|
+
if (!knownSize)
|
|
68
|
+
unknownSizes.add(record);
|
|
44
69
|
record.value = result.value;
|
|
45
70
|
record.lastActiveMs = clock();
|
|
71
|
+
residents.add(record);
|
|
46
72
|
})
|
|
47
73
|
.catch(() => {
|
|
48
|
-
|
|
49
|
-
if (!signal.cancelled)
|
|
74
|
+
if (!signal.cancelled && records.get(record.id) === record)
|
|
50
75
|
record.state = "error";
|
|
51
76
|
})
|
|
52
77
|
.finally(() => {
|
|
78
|
+
if (signals.get(record.id) === signal)
|
|
79
|
+
signals.delete(record.id);
|
|
53
80
|
inFlight.delete(promise);
|
|
54
81
|
});
|
|
55
82
|
inFlight.add(promise);
|
|
56
83
|
}
|
|
84
|
+
function unprotected(record) {
|
|
85
|
+
return record.state === "loaded" && !record.pinned && record.refCount === 0;
|
|
86
|
+
}
|
|
87
|
+
function compareEviction(a, b) {
|
|
88
|
+
if (settings.residentEvictionOrder === "largest" && a.bytes !== b.bytes)
|
|
89
|
+
return b.bytes - a.bytes;
|
|
90
|
+
return a.lastActiveMs - b.lastActiveMs || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
91
|
+
}
|
|
92
|
+
function unload(record) {
|
|
93
|
+
options.unload?.(record.id);
|
|
94
|
+
residents.delete(record);
|
|
95
|
+
unknownSizes.delete(record);
|
|
96
|
+
record.state = "unloaded";
|
|
97
|
+
record.bytes = 0;
|
|
98
|
+
record.value = undefined;
|
|
99
|
+
unloadedTotal += 1;
|
|
100
|
+
}
|
|
57
101
|
function evictable(record, now) {
|
|
58
102
|
if (record.state !== "loaded")
|
|
59
103
|
return false;
|
|
@@ -92,29 +136,45 @@ export function createAssetStreamingSystem(options) {
|
|
|
92
136
|
},
|
|
93
137
|
tick() {
|
|
94
138
|
const now = clock();
|
|
95
|
-
if (queued.size > 0) {
|
|
139
|
+
if (queued.size > 0 && signals.size < settings.maxConcurrentLoads) {
|
|
96
140
|
const pending = [];
|
|
97
141
|
for (const id of queued) {
|
|
98
142
|
const record = records.get(id);
|
|
99
|
-
if (record !== undefined)
|
|
143
|
+
if (record !== undefined && !signals.has(id))
|
|
100
144
|
pending.push(record);
|
|
101
145
|
}
|
|
102
146
|
pending.sort((a, b) => b.priority - a.priority);
|
|
103
|
-
const budget = Math.min(settings.maxLoadsPerFrame, pending.length);
|
|
104
|
-
for (let i = 0; i < budget; i += 1)
|
|
105
|
-
|
|
147
|
+
const budget = Math.min(settings.maxLoadsPerFrame, settings.maxConcurrentLoads - signals.size, pending.length);
|
|
148
|
+
for (let i = 0; i < budget && signals.size < settings.maxConcurrentLoads; i += 1) {
|
|
149
|
+
const record = pending[i];
|
|
150
|
+
if (queued.has(record.id) && records.get(record.id) === record && !signals.has(record.id))
|
|
151
|
+
startLoad(record);
|
|
152
|
+
}
|
|
106
153
|
}
|
|
154
|
+
let bytes = 0;
|
|
155
|
+
for (const record of residents)
|
|
156
|
+
bytes += record.bytes;
|
|
107
157
|
let unloads = 0;
|
|
108
|
-
|
|
158
|
+
while (bytes > settings.maxResidentBytes && unloads < settings.maxUnloadsPerFrame) {
|
|
159
|
+
let candidate;
|
|
160
|
+
for (const record of residents) {
|
|
161
|
+
if (record.bytes > 0 && unprotected(record) && (candidate === undefined || compareEviction(record, candidate) < 0))
|
|
162
|
+
candidate = record;
|
|
163
|
+
}
|
|
164
|
+
if (candidate === undefined)
|
|
165
|
+
break;
|
|
166
|
+
const releasedBytes = candidate.bytes;
|
|
167
|
+
unload(candidate);
|
|
168
|
+
bytes -= releasedBytes;
|
|
169
|
+
budgetEvictedTotal += 1;
|
|
170
|
+
unloads += 1;
|
|
171
|
+
}
|
|
172
|
+
for (const record of residents) {
|
|
109
173
|
if (unloads >= settings.maxUnloadsPerFrame)
|
|
110
174
|
break;
|
|
111
175
|
if (!evictable(record, now))
|
|
112
176
|
continue;
|
|
113
|
-
|
|
114
|
-
record.state = "unloaded";
|
|
115
|
-
record.bytes = 0;
|
|
116
|
-
record.value = undefined;
|
|
117
|
-
unloadedTotal += 1;
|
|
177
|
+
unload(record);
|
|
118
178
|
unloads += 1;
|
|
119
179
|
}
|
|
120
180
|
},
|
|
@@ -127,7 +187,7 @@ export function createAssetStreamingSystem(options) {
|
|
|
127
187
|
return;
|
|
128
188
|
}
|
|
129
189
|
const signal = signals.get(assetId);
|
|
130
|
-
if (signal !== undefined) {
|
|
190
|
+
if (signal !== undefined && !signal.cancelled) {
|
|
131
191
|
signal.cancelled = true;
|
|
132
192
|
const record = records.get(assetId);
|
|
133
193
|
if (record !== undefined)
|
|
@@ -135,6 +195,9 @@ export function createAssetStreamingSystem(options) {
|
|
|
135
195
|
cancelledTotal += 1;
|
|
136
196
|
}
|
|
137
197
|
},
|
|
198
|
+
retune(patch) {
|
|
199
|
+
settings = mergeSettings(settings, patch);
|
|
200
|
+
},
|
|
138
201
|
stateOf(assetId) {
|
|
139
202
|
return records.get(assetId)?.state;
|
|
140
203
|
},
|
|
@@ -144,8 +207,16 @@ export function createAssetStreamingSystem(options) {
|
|
|
144
207
|
record(assetId) {
|
|
145
208
|
return records.get(assetId);
|
|
146
209
|
},
|
|
210
|
+
forget(assetId) {
|
|
211
|
+
const record = records.get(assetId);
|
|
212
|
+
if (record === undefined || record.pinned || record.refCount > 0 || signals.has(assetId) || queued.has(assetId))
|
|
213
|
+
return false;
|
|
214
|
+
if (record.state !== "unloaded" && record.state !== "error")
|
|
215
|
+
return false;
|
|
216
|
+
return records.delete(assetId);
|
|
217
|
+
},
|
|
147
218
|
stats() {
|
|
148
|
-
let queuedCount = 0, loading = 0, loaded = 0, errored = 0, bytes = 0;
|
|
219
|
+
let queuedCount = 0, loading = 0, loaded = 0, errored = 0, bytes = 0, protectedBytes = 0, unknownSizeLoaded = 0;
|
|
149
220
|
for (const record of records.values()) {
|
|
150
221
|
switch (record.state) {
|
|
151
222
|
case "queued":
|
|
@@ -157,6 +228,10 @@ export function createAssetStreamingSystem(options) {
|
|
|
157
228
|
case "loaded":
|
|
158
229
|
loaded += 1;
|
|
159
230
|
bytes += record.bytes;
|
|
231
|
+
if (record.pinned || record.refCount > 0)
|
|
232
|
+
protectedBytes += record.bytes;
|
|
233
|
+
if (unknownSizes.has(record))
|
|
234
|
+
unknownSizeLoaded += 1;
|
|
160
235
|
break;
|
|
161
236
|
case "error":
|
|
162
237
|
errored += 1;
|
|
@@ -172,6 +247,11 @@ export function createAssetStreamingSystem(options) {
|
|
|
172
247
|
inFlight: inFlight.size,
|
|
173
248
|
cancelled: cancelledTotal,
|
|
174
249
|
bytes,
|
|
250
|
+
records: records.size,
|
|
251
|
+
protectedBytes,
|
|
252
|
+
unknownSizeLoaded,
|
|
253
|
+
overBudgetBytes: Math.max(0, bytes - settings.maxResidentBytes),
|
|
254
|
+
budgetEvicted: budgetEvictedTotal,
|
|
175
255
|
};
|
|
176
256
|
},
|
|
177
257
|
applyTo(stats) {
|
|
@@ -190,12 +270,16 @@ export function createAssetStreamingSystem(options) {
|
|
|
190
270
|
clear() {
|
|
191
271
|
for (const signal of signals.values())
|
|
192
272
|
signal.cancelled = true;
|
|
273
|
+
const loaded = [...records.values()].filter((record) => record.state === "loaded").map((record) => record.id);
|
|
193
274
|
records.clear();
|
|
194
275
|
queued.clear();
|
|
195
|
-
|
|
196
|
-
|
|
276
|
+
residents.clear();
|
|
277
|
+
unknownSizes.clear();
|
|
278
|
+
budgetEvictedTotal = 0;
|
|
197
279
|
unloadedTotal = 0;
|
|
198
280
|
cancelledTotal = 0;
|
|
281
|
+
for (const id of loaded)
|
|
282
|
+
options.unload?.(id);
|
|
199
283
|
},
|
|
200
284
|
};
|
|
201
285
|
}
|
|
@@ -23,11 +23,17 @@ export interface StreamingSettings {
|
|
|
23
23
|
readonly enabled: boolean;
|
|
24
24
|
/** Extra world units around the camera whose assets are preloaded ahead of visibility. */
|
|
25
25
|
readonly preloadMargin: number;
|
|
26
|
-
/**
|
|
26
|
+
/** Idle unload delay; resident-byte pressure can evict unprotected assets sooner. */
|
|
27
27
|
readonly unloadGraceSeconds: number;
|
|
28
28
|
readonly maxLoadsPerFrame: number;
|
|
29
|
+
/** Maximum unresolved loads, including cancelled work until its loader settles. Zero pauses new loads. */
|
|
30
|
+
readonly maxConcurrentLoads: number;
|
|
29
31
|
readonly maxUnloadsPerFrame: number;
|
|
30
|
-
/**
|
|
32
|
+
/** Resident-byte target, enforced on ticks within maxUnloadsPerFrame; protected assets may exceed it. */
|
|
33
|
+
readonly maxResidentBytes: number;
|
|
34
|
+
/** Budget eviction order. Ties use oldest activity then asset id for deterministic selection. */
|
|
35
|
+
readonly residentEvictionOrder: "oldest" | "largest";
|
|
36
|
+
/** Small shared assets survive idle unloading, but remain eligible under resident-byte pressure. */
|
|
31
37
|
readonly keepResidentBytes: number;
|
|
32
38
|
}
|
|
33
39
|
export declare const DEFAULT_STREAMING_SETTINGS: StreamingSettings;
|
|
@@ -13,8 +13,11 @@ export const DEFAULT_STREAMING_SETTINGS = {
|
|
|
13
13
|
preloadMargin: 32,
|
|
14
14
|
unloadGraceSeconds: 10,
|
|
15
15
|
maxLoadsPerFrame: 4,
|
|
16
|
+
maxConcurrentLoads: 4,
|
|
16
17
|
maxUnloadsPerFrame: 2,
|
|
17
18
|
keepResidentBytes: 64 * 1024,
|
|
19
|
+
maxResidentBytes: Infinity,
|
|
20
|
+
residentEvictionOrder: "oldest",
|
|
18
21
|
};
|
|
19
22
|
const EMPTY = {};
|
|
20
23
|
/** Merge override layers by precedence: earlier arguments win. Pass object, then layer, then scene, then global. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LodBand } from "../world/lod.js";
|
|
1
|
+
import type { LodBand, LodSchedulerState } from "../world/lod.js";
|
|
2
2
|
/**
|
|
3
3
|
* Simulation culling is a SEPARATE, opt-in system from render culling. Render culling only
|
|
4
4
|
* decides what is drawn; this decides whether a low-priority off-screen entity updates this
|
|
@@ -23,6 +23,11 @@ export interface SimulationDecision {
|
|
|
23
23
|
/** Seconds of accumulated time delivered when `update` is true (for catch-up integration). */
|
|
24
24
|
elapsed: number;
|
|
25
25
|
}
|
|
26
|
+
/** Plain JSON state of a {@link SimulationCuller}: the enabled flag and each id's throttle accumulator. */
|
|
27
|
+
export interface SimulationCullerState {
|
|
28
|
+
enabled: boolean;
|
|
29
|
+
scheduler: LodSchedulerState;
|
|
30
|
+
}
|
|
26
31
|
export interface SimulationCuller {
|
|
27
32
|
enabled(): boolean;
|
|
28
33
|
setEnabled(value: boolean): void;
|
|
@@ -30,5 +35,7 @@ export interface SimulationCuller {
|
|
|
30
35
|
step(id: string, distance: number, dt: number): SimulationDecision;
|
|
31
36
|
forget(id: string): void;
|
|
32
37
|
clear(): void;
|
|
38
|
+
snapshot(): SimulationCullerState;
|
|
39
|
+
restore(next: SimulationCullerState): void;
|
|
33
40
|
}
|
|
34
41
|
export declare function createSimulationCuller(options?: SimulationCullingOptions): SimulationCuller;
|
|
@@ -32,5 +32,12 @@ export function createSimulationCuller(options = {}) {
|
|
|
32
32
|
clear() {
|
|
33
33
|
scheduler.clear();
|
|
34
34
|
},
|
|
35
|
+
snapshot() {
|
|
36
|
+
return { enabled, scheduler: scheduler.snapshot() };
|
|
37
|
+
},
|
|
38
|
+
restore(next) {
|
|
39
|
+
enabled = next.enabled;
|
|
40
|
+
scheduler.restore(next.scheduler);
|
|
41
|
+
},
|
|
35
42
|
};
|
|
36
43
|
}
|
|
@@ -10,6 +10,25 @@ export interface SpatialIndexOptions {
|
|
|
10
10
|
*/
|
|
11
11
|
readonly maxCellSpan?: number;
|
|
12
12
|
}
|
|
13
|
+
/** Integer cell bounds an object covers, inclusive on both ends. */
|
|
14
|
+
export interface SpatialCellRange {
|
|
15
|
+
x0: number;
|
|
16
|
+
y0: number;
|
|
17
|
+
z0: number;
|
|
18
|
+
x1: number;
|
|
19
|
+
y1: number;
|
|
20
|
+
z1: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Plain JSON state of a {@link SpatialIndex}. Cells and their ids keep insertion order, so a restored
|
|
24
|
+
* index returns query results in the same order.
|
|
25
|
+
*/
|
|
26
|
+
export interface SpatialIndexState {
|
|
27
|
+
/** Per object: its cell range (`null` when oversized) and whether it was inserted as dynamic. */
|
|
28
|
+
entries: [id: string, range: SpatialCellRange | null, dynamic: boolean][];
|
|
29
|
+
cells: [x: number, y: number, z: number, ids: string[]][];
|
|
30
|
+
oversized: string[];
|
|
31
|
+
}
|
|
13
32
|
/**
|
|
14
33
|
* A uniform 3D spatial hash the renderer and streaming system query for potentially-visible
|
|
15
34
|
* objects instead of scanning the whole scene. Objects are keyed by their world AABB into
|
|
@@ -39,6 +58,8 @@ export interface SpatialIndex {
|
|
|
39
58
|
}[];
|
|
40
59
|
cellSize(): number;
|
|
41
60
|
clear(): void;
|
|
61
|
+
snapshot(): SpatialIndexState;
|
|
62
|
+
restore(next: SpatialIndexState): void;
|
|
42
63
|
}
|
|
43
64
|
export declare function createSpatialIndex(options?: SpatialIndexOptions): SpatialIndex;
|
|
44
65
|
/** Precise AABB-vs-AABB test re-exported for callers refining a broad-phase result. */
|
|
@@ -206,6 +206,22 @@ export function createSpatialIndex(options = {}) {
|
|
|
206
206
|
entries.clear();
|
|
207
207
|
stamps.clear();
|
|
208
208
|
},
|
|
209
|
+
snapshot() {
|
|
210
|
+
return {
|
|
211
|
+
entries: [...entries].map(([id, entry]) => [id, entry.range === null ? null : { ...entry.range }, entry.dynamic]),
|
|
212
|
+
cells: [...cells.values()].map((bucket) => [bucket.x, bucket.y, bucket.z, [...bucket.ids]]),
|
|
213
|
+
oversized: [...oversized],
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
restore(next) {
|
|
217
|
+
this.clear();
|
|
218
|
+
for (const [id, range, dynamic] of next.entries)
|
|
219
|
+
entries.set(id, { range: range === null ? null : { ...range }, dynamic });
|
|
220
|
+
for (const [x, y, z, ids] of next.cells)
|
|
221
|
+
cells.set(packCell(x, y, z), { x, y, z, ids: new Set(ids) });
|
|
222
|
+
for (const id of next.oversized)
|
|
223
|
+
oversized.add(id);
|
|
224
|
+
},
|
|
209
225
|
};
|
|
210
226
|
}
|
|
211
227
|
/** Precise AABB-vs-AABB test re-exported for callers refining a broad-phase result. */
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { LootPipeline, LootResolution } from "../game/lootPipeline.js";
|
|
2
|
+
import type { Drop } from "../game/lootTable.js";
|
|
3
|
+
import { type RandomSeed } from "../random/rng.js";
|
|
4
|
+
/** Timestamped serializable event. `at` is epoch milliseconds, compatible with `appendFeed`. */
|
|
5
|
+
export interface ExpeditionEvent {
|
|
6
|
+
at: number;
|
|
7
|
+
/** Lifecycle kinds are loot/hazard/supply/death/recall/return; encounter notices may use caller kinds. */
|
|
8
|
+
kind: string;
|
|
9
|
+
text: string;
|
|
10
|
+
/** Accepted drops; `loot.drops` records the full roll before the item-unit capacity bound. */
|
|
11
|
+
drops?: readonly Drop[];
|
|
12
|
+
loot?: LootResolution;
|
|
13
|
+
hpDelta?: number;
|
|
14
|
+
exposureDelta?: number;
|
|
15
|
+
supply?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Plain saveable expedition data. Persist this whole value, including the RNG cursor and tick frontier. */
|
|
18
|
+
export interface ExpeditionState {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly status: "exploring" | "returning" | "home" | "dead";
|
|
21
|
+
readonly startedAtMs: number;
|
|
22
|
+
/** Last completed event tick (arrival time after return), never an unprocessed catch-up target. */
|
|
23
|
+
readonly lastSettledMs: number;
|
|
24
|
+
readonly elapsedMs: number;
|
|
25
|
+
readonly returnUntilMs: number | null;
|
|
26
|
+
readonly hp: number;
|
|
27
|
+
/** Caller-interpreted hazard meter; its meaning and effective max-HP policy are injected. */
|
|
28
|
+
readonly exposure: number;
|
|
29
|
+
readonly supplies: Readonly<Record<string, number>>;
|
|
30
|
+
/** Counts are merged by item/currency id; currency does not consume item capacity. */
|
|
31
|
+
readonly carried: readonly Drop[];
|
|
32
|
+
readonly log: readonly ExpeditionEvent[];
|
|
33
|
+
readonly seed: string;
|
|
34
|
+
readonly cursor: RandomSeed;
|
|
35
|
+
}
|
|
36
|
+
/** Dispatch data, detached from the caller's supply record. All timestamps are epoch milliseconds. */
|
|
37
|
+
export interface ExpeditionDispatch {
|
|
38
|
+
id: string;
|
|
39
|
+
startAtMs: number;
|
|
40
|
+
hp: number;
|
|
41
|
+
exposure?: number;
|
|
42
|
+
supplies?: Readonly<Record<string, number>>;
|
|
43
|
+
seed: string;
|
|
44
|
+
}
|
|
45
|
+
/** One encounter's mechanical effects and optional caller-authored notices. */
|
|
46
|
+
export interface ExpeditionHazard {
|
|
47
|
+
damage?: number;
|
|
48
|
+
exposure?: number;
|
|
49
|
+
notices?: readonly {
|
|
50
|
+
kind: string;
|
|
51
|
+
text: string;
|
|
52
|
+
}[];
|
|
53
|
+
}
|
|
54
|
+
/** Ordered auto-consumption rule: spends one finite supply only when its declared effect changes a vital. */
|
|
55
|
+
export interface ExpeditionSupplyRule {
|
|
56
|
+
key: string;
|
|
57
|
+
when: (state: ExpeditionState) => boolean;
|
|
58
|
+
restoreHp?: number;
|
|
59
|
+
clearExposure?: number;
|
|
60
|
+
}
|
|
61
|
+
/** Runtime policy, supplied on each transition and never saved. Callbacks must be pure. */
|
|
62
|
+
export interface ExpeditionConfig<TCtx> {
|
|
63
|
+
/** Positive whole milliseconds between events; cadence retuning anchors at the last completed tick. */
|
|
64
|
+
tickMs: number;
|
|
65
|
+
loot: LootPipeline<TCtx>;
|
|
66
|
+
lootCtx: (state: ExpeditionState) => TCtx;
|
|
67
|
+
maxHp: (state: ExpeditionState) => number;
|
|
68
|
+
hazard?: (state: ExpeditionState, rng: () => number) => ExpeditionHazard;
|
|
69
|
+
supplies?: readonly ExpeditionSupplyRule[];
|
|
70
|
+
/** Nonnegative fraction of exploring elapsed time spent returning. */
|
|
71
|
+
returnFraction: number;
|
|
72
|
+
/** Positive whole item units; currency is carried without consuming item slots. */
|
|
73
|
+
carryCap: number;
|
|
74
|
+
/** Bounded work per call, default 10,000; excess ticks remain unsettled for the next call. */
|
|
75
|
+
maxTicksPerSettle?: number;
|
|
76
|
+
/** Newest event count retained by appendFeed, default 200; rewards and RNG are retained separately. */
|
|
77
|
+
logLimit?: number;
|
|
78
|
+
/** Optional alternative persisted RNG recurrence; returns a [0,1) value and its next cursor. */
|
|
79
|
+
randomStep?: (cursor: RandomSeed) => readonly [number, RandomSeed];
|
|
80
|
+
/** All lifecycle prose is caller-authored; omit for headless logs with empty text. */
|
|
81
|
+
describe?: (event: Omit<ExpeditionEvent, "text">, state: ExpeditionState) => string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Dispatch plain expedition state with a persisted seeded cursor; no clock, scheduler or storage is owned.
|
|
85
|
+
*
|
|
86
|
+
* @capability expedition-dispatch dispatch a saveable timed away mission with finite supplies and a seeded RNG cursor
|
|
87
|
+
*/
|
|
88
|
+
export declare function dispatchExpedition(input: ExpeditionDispatch): ExpeditionState;
|
|
89
|
+
/**
|
|
90
|
+
* Replay due event ticks using the existing stepped catch-up primitive. Order is loot → hazard → ordered
|
|
91
|
+
* supplies → death → capacity recall. Unprocessed ticks retain their frontier; returning never rolls or
|
|
92
|
+
* takes damage. Auto-recall uses the triggering tick's time, including offline arrival in the same call.
|
|
93
|
+
*
|
|
94
|
+
* @capability expedition-settle settle bounded offline expedition ticks without losing supplies rewards or RNG continuity
|
|
95
|
+
*/
|
|
96
|
+
export declare function settleExpedition<TCtx>(config: ExpeditionConfig<TCtx>, state: ExpeditionState, nowMs: number): ExpeditionState;
|
|
97
|
+
/**
|
|
98
|
+
* Settle first, then recall safely. If the catch-up budget leaves due exploring ticks, return that state
|
|
99
|
+
* without recalling; repeat at the same target until the frontier catches up. Dead state never revives.
|
|
100
|
+
*
|
|
101
|
+
* @capability expedition-recall begin a safe fractional-time return after settling the pending expedition frontier
|
|
102
|
+
*/
|
|
103
|
+
export declare function recallExpedition<TCtx>(config: ExpeditionConfig<TCtx>, state: ExpeditionState, nowMs: number): ExpeditionState;
|
|
104
|
+
/**
|
|
105
|
+
* Settle first, then complete a live return instantly. Caller owns payment/authorization; pending ticks
|
|
106
|
+
* remain unsettled when the budget is exhausted, and dead/home state is never changed.
|
|
107
|
+
*
|
|
108
|
+
* @capability expedition-return complete an authorized instant return without skipping unsettled ticks or reviving death
|
|
109
|
+
*/
|
|
110
|
+
export declare function returnExpeditionNow<TCtx>(config: ExpeditionConfig<TCtx>, state: ExpeditionState, nowMs: number): ExpeditionState;
|