@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
|
@@ -67,10 +67,18 @@ export declare const SETTING_IDS: {
|
|
|
67
67
|
readonly graphicsQuality: "graphics.quality";
|
|
68
68
|
readonly graphicsShadows: "graphics.shadows";
|
|
69
69
|
readonly graphicsUiScale: "graphics.uiScale";
|
|
70
|
+
readonly graphicsRenderScale: "graphics.renderScale";
|
|
71
|
+
readonly graphicsPostAo: "graphics.post.ao";
|
|
72
|
+
readonly graphicsPostBloom: "graphics.post.bloom";
|
|
73
|
+
readonly graphicsPostDof: "graphics.post.dof";
|
|
74
|
+
readonly graphicsPostSmaa: "graphics.post.smaa";
|
|
75
|
+
readonly graphicsFrameRateLimit: "graphics.frameRateLimit";
|
|
76
|
+
readonly graphicsAnisotropy: "graphics.anisotropy";
|
|
77
|
+
readonly graphicsShowFps: "graphics.showFps";
|
|
70
78
|
readonly touchStyle: "controls.touchStyle";
|
|
71
79
|
readonly touchJoystick: "controls.touchJoystick";
|
|
72
80
|
};
|
|
73
|
-
export type GraphicsQuality = "low" | "medium" | "high";
|
|
81
|
+
export type GraphicsQuality = "low" | "medium" | "high" | "ultra";
|
|
74
82
|
export declare const GRAPHICS_QUALITY_OPTIONS: readonly SettingOption[];
|
|
75
83
|
export declare const DEFAULT_MASTER_VOLUME = 1;
|
|
76
84
|
export declare const DEFAULT_GRAPHICS_QUALITY: GraphicsQuality;
|
|
@@ -11,6 +11,14 @@ export const SETTING_IDS = {
|
|
|
11
11
|
graphicsQuality: "graphics.quality",
|
|
12
12
|
graphicsShadows: "graphics.shadows",
|
|
13
13
|
graphicsUiScale: "graphics.uiScale",
|
|
14
|
+
graphicsRenderScale: "graphics.renderScale",
|
|
15
|
+
graphicsPostAo: "graphics.post.ao",
|
|
16
|
+
graphicsPostBloom: "graphics.post.bloom",
|
|
17
|
+
graphicsPostDof: "graphics.post.dof",
|
|
18
|
+
graphicsPostSmaa: "graphics.post.smaa",
|
|
19
|
+
graphicsFrameRateLimit: "graphics.frameRateLimit",
|
|
20
|
+
graphicsAnisotropy: "graphics.anisotropy",
|
|
21
|
+
graphicsShowFps: "graphics.showFps",
|
|
14
22
|
touchStyle: "controls.touchStyle",
|
|
15
23
|
touchJoystick: "controls.touchJoystick",
|
|
16
24
|
};
|
|
@@ -18,6 +26,7 @@ export const GRAPHICS_QUALITY_OPTIONS = [
|
|
|
18
26
|
{ value: "low", label: "Low" },
|
|
19
27
|
{ value: "medium", label: "Medium" },
|
|
20
28
|
{ value: "high", label: "High" },
|
|
29
|
+
{ value: "ultra", label: "Ultra" },
|
|
21
30
|
];
|
|
22
31
|
export const DEFAULT_MASTER_VOLUME = 1;
|
|
23
32
|
export const DEFAULT_GRAPHICS_QUALITY = "high";
|
|
@@ -31,6 +40,7 @@ export const GRAPHICS_QUALITY_DPR = {
|
|
|
31
40
|
low: 1,
|
|
32
41
|
medium: 1.5,
|
|
33
42
|
high: 2,
|
|
43
|
+
ultra: 2,
|
|
34
44
|
};
|
|
35
45
|
export function busVolumeSettingId(busId) {
|
|
36
46
|
return `sound.bus.${busId}`;
|
|
@@ -17,7 +17,17 @@ export interface MeterAddResult {
|
|
|
17
17
|
tier: string | null;
|
|
18
18
|
tierChanged: boolean;
|
|
19
19
|
}
|
|
20
|
+
/** Mutable meter value, hold latch, and time since the last gain. */
|
|
21
|
+
export interface AccumulatorMeterState {
|
|
22
|
+
value: number;
|
|
23
|
+
broken: boolean;
|
|
24
|
+
idleMs: number;
|
|
25
|
+
}
|
|
20
26
|
export interface AccumulatorMeter {
|
|
27
|
+
/** Detached state for persistence and deterministic continuation. */
|
|
28
|
+
state(): AccumulatorMeterState;
|
|
29
|
+
/** Restore using the caller's existing configuration. */
|
|
30
|
+
restore(next: AccumulatorMeterState): void;
|
|
21
31
|
value(): number;
|
|
22
32
|
fraction(): number;
|
|
23
33
|
tier(): string | null;
|
|
@@ -31,6 +31,12 @@ export function createAccumulatorMeter(config) {
|
|
|
31
31
|
return Math.max(0, Math.min(config.max, next));
|
|
32
32
|
}
|
|
33
33
|
return {
|
|
34
|
+
state: () => ({ value, broken, idleMs }),
|
|
35
|
+
restore(next) {
|
|
36
|
+
value = clamp(next.value);
|
|
37
|
+
broken = next.broken;
|
|
38
|
+
idleMs = Math.max(0, next.idleMs);
|
|
39
|
+
},
|
|
34
40
|
value() {
|
|
35
41
|
return value;
|
|
36
42
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type MeterMode, type MeterTier } from "./accumulatorMeter.js";
|
|
1
|
+
import { type AccumulatorMeterState, type MeterMode, type MeterTier } from "./accumulatorMeter.js";
|
|
2
2
|
export interface EventMeterConfig {
|
|
3
3
|
max: number;
|
|
4
4
|
mode?: MeterMode;
|
|
@@ -20,7 +20,13 @@ export interface EventMeterFeedResult {
|
|
|
20
20
|
tier: string | null;
|
|
21
21
|
tierChanged: boolean;
|
|
22
22
|
}
|
|
23
|
+
/** Event meter persistence uses the underlying accumulator's complete state. */
|
|
24
|
+
export type EventMeterState = AccumulatorMeterState;
|
|
23
25
|
export interface EventMeter {
|
|
26
|
+
/** Detached value, hold latch, and decay-delay timer. */
|
|
27
|
+
state(): EventMeterState;
|
|
28
|
+
/** Restore using the caller's existing event and decay configuration. */
|
|
29
|
+
restore(next: EventMeterState): void;
|
|
24
30
|
value(): number;
|
|
25
31
|
fraction(): number;
|
|
26
32
|
tier(): string | null;
|
|
@@ -29,11 +35,12 @@ export interface EventMeter {
|
|
|
29
35
|
consume(): boolean;
|
|
30
36
|
drain(amount: number): void;
|
|
31
37
|
reset(): void;
|
|
32
|
-
|
|
38
|
+
/** Advance decay and its delay; pass false to pause both while a source is visible. */
|
|
39
|
+
tick(dtSeconds: number, decayEnabled?: boolean): void;
|
|
33
40
|
}
|
|
34
41
|
/**
|
|
35
42
|
* A heat/hype gauge that rises as tagged events land and cools between them, firing when it fills or breaks — the streak/overdrive meter shooters and fighters hand-roll.
|
|
36
43
|
*
|
|
37
|
-
* @capability event-meter a heat/streak gauge that builds from repeated
|
|
44
|
+
* @capability event-meter a heat/streak/alert gauge (wanted level, rage, combo) that builds from repeated events and cools down over time
|
|
38
45
|
*/
|
|
39
46
|
export declare function createEventMeter(config: EventMeterConfig): EventMeter;
|
package/dist/stats/eventMeter.js
CHANGED
|
@@ -5,7 +5,7 @@ function readyOf(meter, mode) {
|
|
|
5
5
|
/**
|
|
6
6
|
* A heat/hype gauge that rises as tagged events land and cools between them, firing when it fills or breaks — the streak/overdrive meter shooters and fighters hand-roll.
|
|
7
7
|
*
|
|
8
|
-
* @capability event-meter a heat/streak gauge that builds from repeated
|
|
8
|
+
* @capability event-meter a heat/streak/alert gauge (wanted level, rage, combo) that builds from repeated events and cools down over time
|
|
9
9
|
*/
|
|
10
10
|
export function createEventMeter(config) {
|
|
11
11
|
const mode = config.mode ?? "hold";
|
|
@@ -18,6 +18,8 @@ export function createEventMeter(config) {
|
|
|
18
18
|
tiers: config.tiers,
|
|
19
19
|
});
|
|
20
20
|
return {
|
|
21
|
+
state: meter.state,
|
|
22
|
+
restore: meter.restore,
|
|
21
23
|
value() {
|
|
22
24
|
return meter.value();
|
|
23
25
|
},
|
|
@@ -74,8 +76,9 @@ export function createEventMeter(config) {
|
|
|
74
76
|
reset() {
|
|
75
77
|
meter.reset();
|
|
76
78
|
},
|
|
77
|
-
tick(dtSeconds) {
|
|
78
|
-
|
|
79
|
+
tick(dtSeconds, decayEnabled = true) {
|
|
80
|
+
if (decayEnabled)
|
|
81
|
+
meter.tick(dtSeconds);
|
|
79
82
|
},
|
|
80
83
|
};
|
|
81
84
|
}
|
|
@@ -26,7 +26,9 @@ export interface StoreHandle<T> {
|
|
|
26
26
|
* with the value type it means, and the `unknown → T` cast lives once, here, behind the boundary. Pass
|
|
27
27
|
* a factory for `initial` when the fallback is a fresh mutable object; the factory runs at most once and
|
|
28
28
|
* its result is reused, so an unwritten slot keeps a stable identity across reads (no per-read churn for
|
|
29
|
-
* a React selector, no allocation on a hot path).
|
|
29
|
+
* a React selector, no allocation on a hot path). A value that carries functions (a closure-based run
|
|
30
|
+
* store, an input handle) is runtime-only: snapshots, saves and replication skip it and hydration keeps
|
|
31
|
+
* it in place. Hold such objects with `perContext` when they need no store notifications.
|
|
30
32
|
*
|
|
31
33
|
* @capability typed-store a cast-free typed handle onto one reactive game-store slot, replayable and host-authoritative
|
|
32
34
|
*/
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* with the value type it means, and the `unknown → T` cast lives once, here, behind the boundary. Pass
|
|
4
4
|
* a factory for `initial` when the fallback is a fresh mutable object; the factory runs at most once and
|
|
5
5
|
* its result is reused, so an unwritten slot keeps a stable identity across reads (no per-read churn for
|
|
6
|
-
* a React selector, no allocation on a hot path).
|
|
6
|
+
* a React selector, no allocation on a hot path). A value that carries functions (a closure-based run
|
|
7
|
+
* store, an input handle) is runtime-only: snapshots, saves and replication skip it and hydration keeps
|
|
8
|
+
* it in place. Hold such objects with `perContext` when they need no store notifications.
|
|
7
9
|
*
|
|
8
10
|
* @capability typed-store a cast-free typed handle onto one reactive game-store slot, replayable and host-authoritative
|
|
9
11
|
*/
|
|
@@ -18,4 +18,4 @@ export interface ObservableKeyedStore<T> {
|
|
|
18
18
|
hydrate(data: readonly (readonly [string, T])[]): void;
|
|
19
19
|
}
|
|
20
20
|
/** @internal */
|
|
21
|
-
export declare function createObservableKeyedStore<T>(areEqual?: (previous: T, next: T) => boolean): ObservableKeyedStore<T>;
|
|
21
|
+
export declare function createObservableKeyedStore<T>(areEqual?: (previous: T, next: T) => boolean, beforeNotify?: (key: string | undefined, membershipChanged: boolean) => void): ObservableKeyedStore<T>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @internal */
|
|
2
|
-
export function createObservableKeyedStore(areEqual) {
|
|
2
|
+
export function createObservableKeyedStore(areEqual, beforeNotify) {
|
|
3
3
|
const store = new Map();
|
|
4
4
|
const listeners = new Set();
|
|
5
5
|
const membershipListeners = new Set();
|
|
@@ -11,14 +11,16 @@ export function createObservableKeyedStore(areEqual) {
|
|
|
11
11
|
let keysDirty = false;
|
|
12
12
|
let mapCache = new Map();
|
|
13
13
|
let mapDirty = false;
|
|
14
|
-
function emit() {
|
|
14
|
+
function emit(key, membershipChanged) {
|
|
15
15
|
arrayDirty = true;
|
|
16
16
|
mapDirty = true;
|
|
17
|
+
if (membershipChanged)
|
|
18
|
+
keysDirty = true;
|
|
19
|
+
beforeNotify?.(key, membershipChanged);
|
|
17
20
|
for (const listener of listeners)
|
|
18
21
|
listener();
|
|
19
22
|
}
|
|
20
23
|
function emitMembership() {
|
|
21
|
-
keysDirty = true;
|
|
22
24
|
for (const listener of membershipListeners)
|
|
23
25
|
listener();
|
|
24
26
|
}
|
|
@@ -30,7 +32,7 @@ export function createObservableKeyedStore(areEqual) {
|
|
|
30
32
|
return;
|
|
31
33
|
if (previous !== value)
|
|
32
34
|
store.set(key, value);
|
|
33
|
-
emit();
|
|
35
|
+
emit(key, !had);
|
|
34
36
|
if (!had)
|
|
35
37
|
emitMembership();
|
|
36
38
|
},
|
|
@@ -38,7 +40,7 @@ export function createObservableKeyedStore(areEqual) {
|
|
|
38
40
|
if (!store.has(key))
|
|
39
41
|
return;
|
|
40
42
|
store.delete(key);
|
|
41
|
-
emit();
|
|
43
|
+
emit(key, true);
|
|
42
44
|
emitMembership();
|
|
43
45
|
},
|
|
44
46
|
get(key) {
|
|
@@ -83,7 +85,7 @@ export function createObservableKeyedStore(areEqual) {
|
|
|
83
85
|
store.clear();
|
|
84
86
|
for (const [key, value] of data)
|
|
85
87
|
store.set(key, value);
|
|
86
|
-
emit();
|
|
88
|
+
emit(undefined, true);
|
|
87
89
|
emitMembership();
|
|
88
90
|
},
|
|
89
91
|
};
|
package/dist/time/simClock.d.ts
CHANGED
|
@@ -47,9 +47,11 @@ export interface ClockSnapshot {
|
|
|
47
47
|
calendar: CalendarTime;
|
|
48
48
|
}
|
|
49
49
|
export interface SimClock {
|
|
50
|
-
/** Advance the
|
|
50
|
+
/** Advance the clock directly when used alone. A GameContext's `ctx.sim.advance` owns this call once per step and passes scaled dt to its callback; game loops must not advance it again. */
|
|
51
51
|
advance(realDt: number): number;
|
|
52
52
|
now(): number;
|
|
53
|
+
/** Local accepted advance seconds × play speed × timescale, excluding calendar scale and saved offsets. Never hydrated or serialized; optional for external clocks. */
|
|
54
|
+
advancedSeconds?(): number;
|
|
53
55
|
snapshot(): ClockSnapshot;
|
|
54
56
|
/** Restore clock position — game-time, pause state, and speed multipliers — from a {@link ClockSnapshot} for whole-world save/load. Live timers registered via `after`/`every`/`at` are unaffected. */
|
|
55
57
|
hydrate(snapshot: ClockSnapshot): void;
|
|
@@ -85,4 +87,6 @@ export interface SimClockOptions {
|
|
|
85
87
|
/** Called on control changes and once per displayed in-game minute so UI can rebind; never fires per frame. */
|
|
86
88
|
onChange?: () => void;
|
|
87
89
|
}
|
|
88
|
-
export declare function createSimClock(options?: SimClockOptions): SimClock
|
|
90
|
+
export declare function createSimClock(options?: SimClockOptions): SimClock & {
|
|
91
|
+
advancedSeconds(): number;
|
|
92
|
+
};
|
package/dist/time/simClock.js
CHANGED
|
@@ -16,6 +16,7 @@ export function createSimClock(options = {}) {
|
|
|
16
16
|
const daysPerYear = config.daysPerYear !== undefined && config.daysPerYear > 0 ? config.daysPerYear : 365;
|
|
17
17
|
const seasons = config.seasons;
|
|
18
18
|
let now = config.start !== undefined && config.start > 0 ? config.start : 0;
|
|
19
|
+
let advancedSeconds = 0;
|
|
19
20
|
let paused = config.startPaused ?? false;
|
|
20
21
|
let playSpeed = speeds[0];
|
|
21
22
|
let timescale = 1;
|
|
@@ -76,7 +77,10 @@ export function createSimClock(options = {}) {
|
|
|
76
77
|
if (paused || realDt <= 0 || timescale === 0)
|
|
77
78
|
return 0;
|
|
78
79
|
const gameDt = realDt * scale * playSpeed * timescale;
|
|
80
|
+
const localDt = realDt * playSpeed * timescale;
|
|
79
81
|
now += gameDt;
|
|
82
|
+
if (Number.isFinite(localDt) && localDt > 0)
|
|
83
|
+
advancedSeconds += localDt;
|
|
80
84
|
fireDueTimers();
|
|
81
85
|
const minute = minuteIndex(now, dayLength);
|
|
82
86
|
if (minute !== displayMinute) {
|
|
@@ -138,6 +142,7 @@ export function createSimClock(options = {}) {
|
|
|
138
142
|
return {
|
|
139
143
|
advance,
|
|
140
144
|
now: () => now,
|
|
145
|
+
advancedSeconds: () => advancedSeconds,
|
|
141
146
|
calendar,
|
|
142
147
|
hydrate,
|
|
143
148
|
snapshot: () => ({
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** Piecewise-linear map from a signal value to an output value; points in ascending input order, ends clamp. */
|
|
2
|
+
export type FeedbackCurve = readonly (readonly [number, number])[];
|
|
3
|
+
/** One wire from a sim signal to a named output. */
|
|
4
|
+
export interface FeedbackRoute<TSignal extends string, TTarget extends string> {
|
|
5
|
+
signal: TSignal;
|
|
6
|
+
target: TTarget;
|
|
7
|
+
/** Signal → output mapping (default identity). */
|
|
8
|
+
curve?: FeedbackCurve;
|
|
9
|
+
/** Units/s the routed value may rise (default `Infinity`: follows instantly). */
|
|
10
|
+
attack?: number;
|
|
11
|
+
/** Units/s the routed value may fall (default `attack`). */
|
|
12
|
+
release?: number;
|
|
13
|
+
}
|
|
14
|
+
/** A one-shot fired when a signal crosses a threshold (landing thud, gear-change clunk, impact rumble). */
|
|
15
|
+
export interface FeedbackEvent<TSignal extends string> {
|
|
16
|
+
id: string;
|
|
17
|
+
signal: TSignal;
|
|
18
|
+
/** Fires when the signal rises to or above this value from below it. */
|
|
19
|
+
threshold: number;
|
|
20
|
+
/** Seconds before the same event may fire again (default `0`). */
|
|
21
|
+
cooldown?: number;
|
|
22
|
+
}
|
|
23
|
+
/** Config for {@link createFeedbackMixer}. */
|
|
24
|
+
export interface FeedbackMixerConfig<TSignal extends string, TTarget extends string> {
|
|
25
|
+
routes: readonly FeedbackRoute<TSignal, TTarget>[];
|
|
26
|
+
/** How routes landing on the same target combine (default `"sum"`). */
|
|
27
|
+
combine?: Partial<Record<TTarget, "sum" | "max">>;
|
|
28
|
+
/** Value a target starts from before routes add to it (default `0`). */
|
|
29
|
+
base?: Partial<Record<TTarget, number>>;
|
|
30
|
+
events?: readonly FeedbackEvent<TSignal>[];
|
|
31
|
+
}
|
|
32
|
+
/** Serializable mixer state: smoothed route values, last signal per event, and event cooldowns. */
|
|
33
|
+
export interface FeedbackMixerState {
|
|
34
|
+
routes: number[];
|
|
35
|
+
eventSignals: number[];
|
|
36
|
+
cooldowns: number[];
|
|
37
|
+
}
|
|
38
|
+
/** Maps sim telemetry to presentation parameters through declared routes, curves and smoothing. */
|
|
39
|
+
export interface FeedbackMixer<TSignal extends string, TTarget extends string> {
|
|
40
|
+
/**
|
|
41
|
+
* Advance by `dt` with this tick's signals and return every target's value. The returned record is reused
|
|
42
|
+
* between calls, so read it before the next update. Missing signals read as `0`.
|
|
43
|
+
*/
|
|
44
|
+
update(dt: number, signals: Readonly<Partial<Record<TSignal, number>>>): Readonly<Record<TTarget, number>>;
|
|
45
|
+
/** True when event `id` fired on the last update. */
|
|
46
|
+
fired(id: string): boolean;
|
|
47
|
+
value(): Readonly<Record<TTarget, number>>;
|
|
48
|
+
retune(next: FeedbackMixerConfig<TSignal, TTarget>): void;
|
|
49
|
+
snapshot(): FeedbackMixerState;
|
|
50
|
+
restore(state: FeedbackMixerState): void;
|
|
51
|
+
reset(): void;
|
|
52
|
+
}
|
|
53
|
+
/** Sample a {@link FeedbackCurve}; an empty curve is the identity. */
|
|
54
|
+
export declare function sampleFeedbackCurve(curve: FeedbackCurve | undefined, x: number): number;
|
|
55
|
+
/**
|
|
56
|
+
* Creates a {@link FeedbackMixer}: the one place a game declares how sim telemetry drives presentation —
|
|
57
|
+
* rpm to engine pitch, tire saturation to squeal and rumble, speed to FOV, landing speed to a thud — instead
|
|
58
|
+
* of hand-writing that glue per vehicle, aircraft or weapon. Deterministic, allocation-free per update.
|
|
59
|
+
* @capability feedback-mixer map sim telemetry to camera, audio and haptic parameters through curves, smoothing and threshold events
|
|
60
|
+
*/
|
|
61
|
+
export declare function createFeedbackMixer<TSignal extends string, TTarget extends string>(initial: FeedbackMixerConfig<TSignal, TTarget>): FeedbackMixer<TSignal, TTarget>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/** Sample a {@link FeedbackCurve}; an empty curve is the identity. */
|
|
2
|
+
export function sampleFeedbackCurve(curve, x) {
|
|
3
|
+
if (curve === undefined || curve.length === 0)
|
|
4
|
+
return x;
|
|
5
|
+
const first = curve[0];
|
|
6
|
+
if (x <= first[0])
|
|
7
|
+
return first[1];
|
|
8
|
+
for (let i = 1; i < curve.length; i += 1) {
|
|
9
|
+
const [x1, y1] = curve[i];
|
|
10
|
+
if (x <= x1) {
|
|
11
|
+
const [x0, y0] = curve[i - 1];
|
|
12
|
+
const span = x1 - x0;
|
|
13
|
+
return span <= 0 ? y1 : y0 + ((y1 - y0) * (x - x0)) / span;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return curve[curve.length - 1][1];
|
|
17
|
+
}
|
|
18
|
+
function approach(current, target, attack, release, dt) {
|
|
19
|
+
const rate = target > current ? attack : release;
|
|
20
|
+
if (!Number.isFinite(rate))
|
|
21
|
+
return target;
|
|
22
|
+
const step = Math.max(0, rate) * dt;
|
|
23
|
+
return Math.abs(target - current) <= step ? target : current + Math.sign(target - current) * step;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Creates a {@link FeedbackMixer}: the one place a game declares how sim telemetry drives presentation —
|
|
27
|
+
* rpm to engine pitch, tire saturation to squeal and rumble, speed to FOV, landing speed to a thud — instead
|
|
28
|
+
* of hand-writing that glue per vehicle, aircraft or weapon. Deterministic, allocation-free per update.
|
|
29
|
+
* @capability feedback-mixer map sim telemetry to camera, audio and haptic parameters through curves, smoothing and threshold events
|
|
30
|
+
*/
|
|
31
|
+
export function createFeedbackMixer(initial) {
|
|
32
|
+
let config = initial;
|
|
33
|
+
let routeValues = [];
|
|
34
|
+
let eventSignals = [];
|
|
35
|
+
let cooldowns = [];
|
|
36
|
+
let firedNow = new Set();
|
|
37
|
+
const output = {};
|
|
38
|
+
const touched = new Set();
|
|
39
|
+
function shapeState() {
|
|
40
|
+
routeValues = config.routes.map((_, i) => routeValues[i] ?? 0);
|
|
41
|
+
eventSignals = (config.events ?? []).map((_, i) => eventSignals[i] ?? 0);
|
|
42
|
+
cooldowns = (config.events ?? []).map((_, i) => cooldowns[i] ?? 0);
|
|
43
|
+
for (const route of config.routes)
|
|
44
|
+
output[route.target] ??= 0;
|
|
45
|
+
for (const key of Object.keys(config.base ?? {}))
|
|
46
|
+
output[key] ??= config.base?.[key] ?? 0;
|
|
47
|
+
}
|
|
48
|
+
shapeState();
|
|
49
|
+
return {
|
|
50
|
+
update(dt, signals) {
|
|
51
|
+
const step = Math.max(0, dt);
|
|
52
|
+
for (const key of Object.keys(output))
|
|
53
|
+
output[key] = config.base?.[key] ?? 0;
|
|
54
|
+
touched.clear();
|
|
55
|
+
for (let i = 0; i < config.routes.length; i += 1) {
|
|
56
|
+
const route = config.routes[i];
|
|
57
|
+
const target = sampleFeedbackCurve(route.curve, signals[route.signal] ?? 0);
|
|
58
|
+
const attack = route.attack ?? Number.POSITIVE_INFINITY;
|
|
59
|
+
const value = approach(routeValues[i], target, attack, route.release ?? attack, step);
|
|
60
|
+
routeValues[i] = value;
|
|
61
|
+
const mode = config.combine?.[route.target] ?? "sum";
|
|
62
|
+
if (mode === "max") {
|
|
63
|
+
const current = touched.has(route.target) ? output[route.target] : Number.NEGATIVE_INFINITY;
|
|
64
|
+
output[route.target] = Math.max(current, value);
|
|
65
|
+
}
|
|
66
|
+
else
|
|
67
|
+
output[route.target] += value;
|
|
68
|
+
touched.add(route.target);
|
|
69
|
+
}
|
|
70
|
+
firedNow.clear();
|
|
71
|
+
const events = config.events ?? [];
|
|
72
|
+
for (let i = 0; i < events.length; i += 1) {
|
|
73
|
+
const event = events[i];
|
|
74
|
+
const value = signals[event.signal] ?? 0;
|
|
75
|
+
cooldowns[i] = Math.max(0, cooldowns[i] - step);
|
|
76
|
+
if (value >= event.threshold && eventSignals[i] < event.threshold && cooldowns[i] === 0) {
|
|
77
|
+
firedNow.add(event.id);
|
|
78
|
+
cooldowns[i] = event.cooldown ?? 0;
|
|
79
|
+
}
|
|
80
|
+
eventSignals[i] = value;
|
|
81
|
+
}
|
|
82
|
+
return output;
|
|
83
|
+
},
|
|
84
|
+
fired: (id) => firedNow.has(id),
|
|
85
|
+
value: () => output,
|
|
86
|
+
retune(next) {
|
|
87
|
+
config = next;
|
|
88
|
+
shapeState();
|
|
89
|
+
},
|
|
90
|
+
snapshot: () => ({ routes: [...routeValues], eventSignals: [...eventSignals], cooldowns: [...cooldowns] }),
|
|
91
|
+
restore(state) {
|
|
92
|
+
routeValues = [...state.routes];
|
|
93
|
+
eventSignals = [...state.eventSignals];
|
|
94
|
+
cooldowns = [...state.cooldowns];
|
|
95
|
+
shapeState();
|
|
96
|
+
},
|
|
97
|
+
reset() {
|
|
98
|
+
routeValues = routeValues.map(() => 0);
|
|
99
|
+
eventSignals = eventSignals.map(() => 0);
|
|
100
|
+
cooldowns = cooldowns.map(() => 0);
|
|
101
|
+
firedNow = new Set();
|
|
102
|
+
for (const key of Object.keys(output))
|
|
103
|
+
output[key] = config.base?.[key] ?? 0;
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type EmitterConfig, type ParticleEvent, type Vec3 } from "./particles.js";
|
|
2
2
|
/** How a particle effect composites on screen: `additive` for sparks/fire/glow, `normal` for smoke/dust. */
|
|
3
3
|
export type ParticleBlendHint = "additive" | "normal";
|
|
4
|
+
/** Render output selected independently of particle spawn and simulation. */
|
|
5
|
+
export interface ParticleRenderHint {
|
|
6
|
+
shape: "point" | "streak" | "flake" | "flame" | "smoke" | "ribbon" | "ripple";
|
|
7
|
+
/** Velocity streak length in seconds. Default 0.08. */
|
|
8
|
+
stretch?: number;
|
|
9
|
+
}
|
|
4
10
|
/** A one-shot burst request — consumed once by the renderer, never serialized. */
|
|
5
11
|
export interface ParticleBurst {
|
|
6
12
|
/** Monotonic sequence id so a renderer can consume each burst exactly once. */
|
|
@@ -9,6 +15,15 @@ export interface ParticleBurst {
|
|
|
9
15
|
/** Particles to emit immediately. */
|
|
10
16
|
count: number;
|
|
11
17
|
blending?: ParticleBlendHint;
|
|
18
|
+
emitterId?: string;
|
|
19
|
+
options?: ParticleAttachOptions;
|
|
20
|
+
}
|
|
21
|
+
/** A bounded collision child effect; children cannot spawn further collision children. */
|
|
22
|
+
export interface ParticleCollisionEffect {
|
|
23
|
+
config: EmitterConfig;
|
|
24
|
+
count: number;
|
|
25
|
+
render?: ParticleRenderHint;
|
|
26
|
+
blending?: ParticleBlendHint;
|
|
12
27
|
}
|
|
13
28
|
/** Options for {@link ParticleDirector.attach}. */
|
|
14
29
|
export interface ParticleAttachOptions {
|
|
@@ -17,15 +32,36 @@ export interface ParticleAttachOptions {
|
|
|
17
32
|
/** World offset from the followed entity (or from the config position when unfollowed). */
|
|
18
33
|
offset?: Vec3;
|
|
19
34
|
blending?: ParticleBlendHint;
|
|
35
|
+
/** Local particles move with the followed pose; world particles retain their emitted positions. */
|
|
36
|
+
space?: "world" | "local";
|
|
37
|
+
active?: boolean;
|
|
38
|
+
render?: ParticleRenderHint;
|
|
39
|
+
collisionEffect?: ParticleCollisionEffect;
|
|
40
|
+
/** Explicit environment influence: windResponse in 1/second, maxAcceleration in metres/second², both 0..1e12. */
|
|
41
|
+
environment?: {
|
|
42
|
+
windResponse?: number;
|
|
43
|
+
maxAcceleration?: number;
|
|
44
|
+
mask?: number;
|
|
45
|
+
};
|
|
20
46
|
}
|
|
21
47
|
/** A keyed continuous emitter owned by the director until detached. */
|
|
22
|
-
export interface ParticleEmitterSpec {
|
|
48
|
+
export interface ParticleEmitterSpec extends ParticleAttachOptions {
|
|
23
49
|
id: string;
|
|
24
50
|
config: EmitterConfig;
|
|
25
51
|
follow?: string;
|
|
26
52
|
offset?: Vec3;
|
|
27
53
|
blending?: ParticleBlendHint;
|
|
28
54
|
}
|
|
55
|
+
/** A cosmetic simulation event, labelled with its emitting effect. */
|
|
56
|
+
export interface ParticleDirectorEvent extends ParticleEvent {
|
|
57
|
+
emitterId: string;
|
|
58
|
+
}
|
|
59
|
+
/** Bounded storage policy for transient effects and event exchange. */
|
|
60
|
+
export interface ParticleDirectorOptions {
|
|
61
|
+
maxEmitters?: number;
|
|
62
|
+
maxBursts?: number;
|
|
63
|
+
maxEvents?: number;
|
|
64
|
+
}
|
|
29
65
|
/** Serializable director state: the standing emitters (bursts are transient by nature). */
|
|
30
66
|
export interface ParticleDirectorState {
|
|
31
67
|
nextSeq: number;
|
|
@@ -40,17 +76,28 @@ export interface ParticleDirectorState {
|
|
|
40
76
|
*/
|
|
41
77
|
export interface ParticleDirector {
|
|
42
78
|
/** Queue a one-shot burst (impact puff, debris, muzzle smoke). */
|
|
43
|
-
burst(config: EmitterConfig, count: number, blending?: ParticleBlendHint): void;
|
|
79
|
+
burst(config: EmitterConfig, count: number, blending?: ParticleBlendHint, options?: ParticleAttachOptions): void;
|
|
44
80
|
/** Create or replace a standing emitter under `id` (exhaust, dust plume, torch smoke). */
|
|
45
81
|
attach(id: string, config: EmitterConfig, options?: ParticleAttachOptions): void;
|
|
46
82
|
/** Patch a standing emitter's config in place (e.g. scale exhaust rate with speed). */
|
|
47
|
-
retune(id: string, patch: Partial<EmitterConfig>): void;
|
|
83
|
+
retune(id: string, patch: Partial<EmitterConfig>, options?: Partial<ParticleAttachOptions>): void;
|
|
84
|
+
/** Resume a named emitter while preserving its live particles. */
|
|
85
|
+
start(id: string): void;
|
|
86
|
+
/** Stop spawning; the renderer lets existing particles finish. */
|
|
87
|
+
stop(id: string): void;
|
|
88
|
+
/** Emit once through a named emitter's existing pool, including when stopped. */
|
|
89
|
+
burstNamed(id: string, count: number): void;
|
|
90
|
+
/** Renderer-to-game cosmetic event exchange, bounded by the director's event limit. */
|
|
91
|
+
reportEvents(id: string, events: readonly ParticleEvent[]): void;
|
|
92
|
+
drainEvents(): ParticleDirectorEvent[];
|
|
48
93
|
/** Remove a standing emitter. Unknown ids are ignored. */
|
|
49
94
|
detach(id: string): void;
|
|
50
95
|
/** Drop every standing emitter and any unconsumed bursts. */
|
|
51
96
|
clear(): void;
|
|
52
97
|
/** The standing emitters, for renderers and assertions. */
|
|
53
98
|
emitters(): readonly ParticleEmitterSpec[];
|
|
99
|
+
/** Fixed registry and transient queue capacities for transactional preflight. */
|
|
100
|
+
limits(): Required<ParticleDirectorOptions>;
|
|
54
101
|
/** Return and forget the queued bursts — the renderer's consume-once read. */
|
|
55
102
|
drainBursts(): ParticleBurst[];
|
|
56
103
|
subscribe(listener: () => void): () => void;
|
|
@@ -63,6 +110,11 @@ export interface ParticleDirector {
|
|
|
63
110
|
* queued bursts are transient. The renderer subscribes, drains bursts, and mirrors
|
|
64
111
|
* the emitter list — the director never allocates particle pools itself.
|
|
65
112
|
*
|
|
66
|
-
* @capability particle-director
|
|
113
|
+
* @capability particle-director named particle start/stop/burst/retune lifecycle, local/world following, render outputs, bounded cosmetic event exchange, and serializable emitter definitions
|
|
114
|
+
*/
|
|
115
|
+
export declare function createParticleDirector(options?: ParticleDirectorOptions): ParticleDirector;
|
|
116
|
+
/**
|
|
117
|
+
* Validate serializable binding, output, and bounded collision-child descriptors.
|
|
118
|
+
* @capability particle-binding-validation validate named particle follow spaces, render outputs, environment influence, and bounded collision child effects
|
|
67
119
|
*/
|
|
68
|
-
export declare function
|
|
120
|
+
export declare function validateParticleAttachOptions(value: unknown): string[];
|