@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
package/dist/world/walls.d.ts
CHANGED
|
@@ -50,6 +50,11 @@ export interface SurfacePaintStore {
|
|
|
50
50
|
}
|
|
51
51
|
/** @internal */
|
|
52
52
|
export declare function createSurfacePaint(): SurfacePaintStore;
|
|
53
|
+
/** Plain JSON state of a {@link WallDrawTool}: the drawn points and whether the loop is closed. */
|
|
54
|
+
export interface WallDrawToolState {
|
|
55
|
+
points: Vec2[];
|
|
56
|
+
closed: boolean;
|
|
57
|
+
}
|
|
53
58
|
export interface WallDrawTool {
|
|
54
59
|
addPoint(point: Vec2, snap?: number): Vec2;
|
|
55
60
|
undo(): void;
|
|
@@ -60,6 +65,8 @@ export interface WallDrawTool {
|
|
|
60
65
|
isClosed(): boolean;
|
|
61
66
|
footprint(): EnclosedFootprint | null;
|
|
62
67
|
roof(config?: RoofConfig): RoofPlan | null;
|
|
68
|
+
snapshot(): WallDrawToolState;
|
|
69
|
+
restore(next: WallDrawToolState): void;
|
|
63
70
|
}
|
|
64
71
|
/** @internal */
|
|
65
72
|
export declare function createWallDrawTool(config?: {
|
package/dist/world/walls.js
CHANGED
|
@@ -220,6 +220,13 @@ export function createWallDrawTool(config = {}) {
|
|
|
220
220
|
const fp = this.footprint();
|
|
221
221
|
return fp === null ? null : autoRoof(fp, roofConfig);
|
|
222
222
|
},
|
|
223
|
+
snapshot() {
|
|
224
|
+
return { points: pts.map((point) => [point[0], point[1]]), closed };
|
|
225
|
+
},
|
|
226
|
+
restore(next) {
|
|
227
|
+
pts = next.points.map((point) => [point[0], point[1]]);
|
|
228
|
+
closed = next.closed;
|
|
229
|
+
},
|
|
223
230
|
};
|
|
224
231
|
}
|
|
225
232
|
/** @internal */
|
package/dist/world/weather.d.ts
CHANGED
|
@@ -48,19 +48,34 @@ export interface FireGridConfig {
|
|
|
48
48
|
wind?: WindVector;
|
|
49
49
|
/** How strongly wind biases downwind vs upwind spread, 0..1. Default 0.6. */
|
|
50
50
|
windBias?: number;
|
|
51
|
+
/** Hard allocation bound; defaults to 65536 cells. */
|
|
52
|
+
maxCells?: number;
|
|
51
53
|
}
|
|
54
|
+
/** Live fire ignition, spread, consumption and wind policies; grid geometry stays fixed. */
|
|
55
|
+
export type FireGridTuning = Pick<FireGridConfig, "ignitionThreshold" | "spreadRate" | "burnRate" | "wind" | "windBias">;
|
|
52
56
|
export interface FireStepOptions {
|
|
53
57
|
/** Global spread multiplier this step (rain suppression from resolveWeather().spread). Default 1. */
|
|
54
58
|
spread?: number;
|
|
59
|
+
/** Live wind in metres/second along world X,Z, overriding configured wind this step. */
|
|
60
|
+
wind?: WindVector;
|
|
61
|
+
windAt?: (x: number, z: number) => WindVector;
|
|
55
62
|
/** Per-cell wetness 0..1 that resists ignition — from an environment field. */
|
|
56
63
|
wetnessAt?: (col: number, row: number) => number;
|
|
64
|
+
/** Heat removed per second at full wetness; 0 (default) leaves extinction to game policy. */
|
|
65
|
+
extinguishRate?: number;
|
|
57
66
|
}
|
|
58
67
|
export interface FireGrid {
|
|
59
68
|
readonly cols: number;
|
|
60
69
|
readonly rows: number;
|
|
70
|
+
readonly cellSize: number;
|
|
71
|
+
readonly origin: readonly [number, number];
|
|
61
72
|
/** Advance the cellular propagation by game-time `dt`. */
|
|
62
73
|
step(dt: number, options?: FireStepOptions): void;
|
|
63
74
|
igniteCell(col: number, row: number): void;
|
|
75
|
+
/** Cool a burning cell to unburnt without replacing its remaining fuel. */
|
|
76
|
+
extinguishCell(col: number, row: number): boolean;
|
|
77
|
+
/** Extinguish the cell under a world position; false outside the grid or when not burning. */
|
|
78
|
+
extinguish(x: number, z: number): boolean;
|
|
64
79
|
/** Ignite the cell under a world position; no-op if outside the grid. */
|
|
65
80
|
ignite(x: number, z: number): boolean;
|
|
66
81
|
cell(col: number, row: number): FireCell;
|
|
@@ -73,5 +88,7 @@ export interface FireGrid {
|
|
|
73
88
|
readonly burning: number;
|
|
74
89
|
/** Flat snapshot (row-major) for rendering. */
|
|
75
90
|
snapshot(): FireCell[];
|
|
91
|
+
restore(state: readonly FireCell[]): void;
|
|
92
|
+
retune(tuning: FireGridTuning): void;
|
|
76
93
|
}
|
|
77
94
|
export declare function createFireGrid(config: FireGridConfig): FireGrid;
|
package/dist/world/weather.js
CHANGED
|
@@ -29,39 +29,66 @@ const NEIGHBOURS = [
|
|
|
29
29
|
];
|
|
30
30
|
export function createFireGrid(config) {
|
|
31
31
|
const { cols, rows, cellSize } = config;
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
const maxCells = config.maxCells ?? 65_536;
|
|
33
|
+
if (!Number.isSafeInteger(maxCells) || maxCells < 1 || maxCells > 1_048_576)
|
|
34
|
+
throw new Error("createFireGrid: maxCells must be an integer in 1..1048576");
|
|
35
|
+
if (!Number.isSafeInteger(cols) || !Number.isSafeInteger(rows) || cols <= 0 || rows <= 0 || cols * rows > maxCells)
|
|
36
|
+
throw new Error("createFireGrid: cols/rows must be positive integers within maxCells");
|
|
37
|
+
if (!Number.isFinite(cellSize) || cellSize <= 0)
|
|
38
|
+
throw new Error("createFireGrid: cellSize must be finite and positive");
|
|
34
39
|
const originX = config.origin?.[0] ?? 0;
|
|
35
40
|
const originZ = config.origin?.[1] ?? 0;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
if (!Number.isFinite(originX) || !Number.isFinite(originZ))
|
|
42
|
+
throw new Error("createFireGrid: origin must be finite");
|
|
43
|
+
let ignitionThreshold = 1;
|
|
44
|
+
let spreadRate = 0.6;
|
|
45
|
+
let burnRate = 0.25;
|
|
46
|
+
let windBias = 0.6;
|
|
47
|
+
let wind;
|
|
48
|
+
function retune(tuning) {
|
|
49
|
+
for (const key of ["ignitionThreshold", "spreadRate", "burnRate", "windBias"]) {
|
|
50
|
+
const value = tuning[key];
|
|
51
|
+
if (value !== undefined && (!Number.isFinite(value) || value < 0 || (key === "windBias" && value > 1)))
|
|
52
|
+
throw new Error(`fire ${key} is invalid`);
|
|
53
|
+
}
|
|
54
|
+
if (tuning.wind !== undefined && (!Number.isFinite(tuning.wind[0]) || !Number.isFinite(tuning.wind[1])))
|
|
55
|
+
throw new Error("fire wind must be finite");
|
|
56
|
+
ignitionThreshold = tuning.ignitionThreshold ?? ignitionThreshold;
|
|
57
|
+
spreadRate = tuning.spreadRate ?? spreadRate;
|
|
58
|
+
burnRate = tuning.burnRate ?? burnRate;
|
|
59
|
+
windBias = tuning.windBias ?? windBias;
|
|
60
|
+
if (tuning.wind !== undefined)
|
|
61
|
+
wind = [tuning.wind[0], tuning.wind[1]];
|
|
62
|
+
}
|
|
63
|
+
retune(config);
|
|
44
64
|
const cells = new Array(cols * rows);
|
|
45
65
|
for (let row = 0; row < rows; row += 1) {
|
|
46
66
|
for (let col = 0; col < cols; col += 1) {
|
|
47
67
|
const fuel = config.fuelAt?.(col, row) ?? 1;
|
|
68
|
+
if (!Number.isFinite(fuel) || fuel < 0)
|
|
69
|
+
throw new Error("fire initial fuel must be finite and nonnegative");
|
|
48
70
|
cells[row * cols + col] = { fuel: Math.max(0, fuel), heat: 0, state: "unburnt" };
|
|
49
71
|
}
|
|
50
72
|
}
|
|
51
73
|
const index = (col, row) => row * cols + col;
|
|
52
|
-
const inBounds = (col, row) => col >= 0 && col < cols && row >= 0 && row < rows;
|
|
74
|
+
const inBounds = (col, row) => Number.isInteger(col) && Number.isInteger(row) && col >= 0 && col < cols && row >= 0 && row < rows;
|
|
53
75
|
const cellCoord = (x, z) => {
|
|
54
76
|
const col = Math.round((x - originX) / cellSize);
|
|
55
77
|
const row = Math.round((z - originZ) / cellSize);
|
|
56
78
|
return inBounds(col, row) ? { col, row } : null;
|
|
57
79
|
};
|
|
58
|
-
const directionalWeight = (dx, dz) => {
|
|
80
|
+
const directionalWeight = (dx, dz, vector) => {
|
|
81
|
+
if (vector === undefined)
|
|
82
|
+
return 1;
|
|
83
|
+
const windLen = Math.hypot(vector[0], vector[1]);
|
|
59
84
|
if (windLen === 0)
|
|
60
85
|
return 1;
|
|
61
86
|
const len = Math.hypot(dx, dz) || 1;
|
|
62
|
-
const alignment = (dx / len) *
|
|
87
|
+
const alignment = (dx / len) * vector[0] / windLen + (dz / len) * vector[1] / windLen;
|
|
63
88
|
return 1 + windBias * alignment;
|
|
64
89
|
};
|
|
90
|
+
const addedHeat = new Float64Array(cols * rows);
|
|
91
|
+
const wetness = new Float64Array(cols * rows);
|
|
65
92
|
let burning = 0;
|
|
66
93
|
for (const cell of cells)
|
|
67
94
|
if (cell.state === "burning")
|
|
@@ -77,20 +104,71 @@ export function createFireGrid(config) {
|
|
|
77
104
|
cell.state = "burning";
|
|
78
105
|
cell.heat = Math.max(cell.heat, ignitionThreshold);
|
|
79
106
|
};
|
|
107
|
+
const extinguishCell = (col, row) => {
|
|
108
|
+
if (!inBounds(col, row))
|
|
109
|
+
return false;
|
|
110
|
+
const cell = cells[index(col, row)];
|
|
111
|
+
if (cell.state !== "burning")
|
|
112
|
+
return false;
|
|
113
|
+
cell.state = "unburnt";
|
|
114
|
+
cell.heat = 0;
|
|
115
|
+
burning -= 1;
|
|
116
|
+
return true;
|
|
117
|
+
};
|
|
80
118
|
return {
|
|
81
119
|
cols,
|
|
82
120
|
rows,
|
|
121
|
+
cellSize,
|
|
122
|
+
origin: [originX, originZ],
|
|
123
|
+
retune,
|
|
124
|
+
restore(state) {
|
|
125
|
+
if (state.length !== cells.length)
|
|
126
|
+
throw new Error("fire snapshot dimensions do not match");
|
|
127
|
+
const next = state.map((cell) => {
|
|
128
|
+
if (!Number.isFinite(cell.fuel) || cell.fuel < 0 || !Number.isFinite(cell.heat) || cell.heat < 0 || !["unburnt", "burning", "burnt"].includes(cell.state) || (cell.state === "burning" && cell.fuel <= 0) || (cell.state === "burnt" && (cell.fuel !== 0 || cell.heat !== 0)))
|
|
129
|
+
throw new Error("invalid fire snapshot cell");
|
|
130
|
+
return { ...cell };
|
|
131
|
+
});
|
|
132
|
+
burning = 0;
|
|
133
|
+
for (let i = 0; i < cells.length; i += 1) {
|
|
134
|
+
cells[i] = next[i];
|
|
135
|
+
if (cells[i].state === "burning")
|
|
136
|
+
burning += 1;
|
|
137
|
+
}
|
|
138
|
+
},
|
|
83
139
|
step(dt, options) {
|
|
84
|
-
if (dt
|
|
140
|
+
if (!Number.isFinite(dt) || dt < 0)
|
|
141
|
+
throw new Error("fire dt must be finite and nonnegative");
|
|
142
|
+
if (dt === 0)
|
|
85
143
|
return;
|
|
86
144
|
const globalSpread = options?.spread ?? 1;
|
|
145
|
+
if (!Number.isFinite(globalSpread) || globalSpread < 0)
|
|
146
|
+
throw new Error("fire spread multiplier must be finite and nonnegative");
|
|
87
147
|
const wetnessAt = options?.wetnessAt;
|
|
88
|
-
const
|
|
148
|
+
const extinguishRate = options?.extinguishRate ?? 0;
|
|
149
|
+
if (!Number.isFinite(extinguishRate) || extinguishRate < 0)
|
|
150
|
+
throw new Error("fire extinguishRate must be finite and nonnegative");
|
|
151
|
+
const resolveWetness = (col, row) => {
|
|
152
|
+
const value = wetnessAt?.(col, row) ?? 0;
|
|
153
|
+
if (!Number.isFinite(value))
|
|
154
|
+
throw new Error("fire wetness must be finite");
|
|
155
|
+
return Math.max(0, Math.min(1, value));
|
|
156
|
+
};
|
|
157
|
+
addedHeat.fill(0);
|
|
158
|
+
wetness.fill(0);
|
|
89
159
|
for (let row = 0; row < rows; row += 1) {
|
|
90
160
|
for (let col = 0; col < cols; col += 1) {
|
|
91
161
|
const cell = cells[index(col, row)];
|
|
92
162
|
if (cell.state !== "burning")
|
|
93
163
|
continue;
|
|
164
|
+
const vector = options?.windAt?.(originX + col * cellSize, originZ + row * cellSize) ?? options?.wind ?? wind;
|
|
165
|
+
if (vector !== undefined && (!Number.isFinite(vector[0]) || !Number.isFinite(vector[1])))
|
|
166
|
+
throw new Error("fire step wind must be finite");
|
|
167
|
+
const i = index(col, row);
|
|
168
|
+
if (extinguishRate > 0)
|
|
169
|
+
wetness[i] = resolveWetness(col, row);
|
|
170
|
+
const coolingRate = extinguishRate * wetness[i];
|
|
171
|
+
const burningDt = Math.min(dt, burnRate === 0 ? Infinity : cell.fuel / burnRate, coolingRate === 0 ? Infinity : cell.heat / coolingRate);
|
|
94
172
|
for (const [dx, dz] of NEIGHBOURS) {
|
|
95
173
|
const nc = col + dx;
|
|
96
174
|
const nr = row + dz;
|
|
@@ -100,7 +178,7 @@ export function createFireGrid(config) {
|
|
|
100
178
|
if (neighbour.state === "burnt" || neighbour.fuel <= 0)
|
|
101
179
|
continue;
|
|
102
180
|
addedHeat[index(nc, nr)] +=
|
|
103
|
-
spreadRate * globalSpread * directionalWeight(dx, dz) *
|
|
181
|
+
spreadRate * globalSpread * directionalWeight(dx, dz, vector) * burningDt;
|
|
104
182
|
}
|
|
105
183
|
}
|
|
106
184
|
}
|
|
@@ -108,19 +186,32 @@ export function createFireGrid(config) {
|
|
|
108
186
|
for (let col = 0; col < cols; col += 1) {
|
|
109
187
|
const i = index(col, row);
|
|
110
188
|
const cell = cells[i];
|
|
189
|
+
if (cell.state === "unburnt" && (addedHeat[i] > 0 || (extinguishRate > 0 && cell.heat > 0)))
|
|
190
|
+
wetness[i] = resolveWetness(col, row);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
for (let row = 0; row < rows; row += 1) {
|
|
194
|
+
for (let col = 0; col < cols; col += 1) {
|
|
195
|
+
const i = index(col, row);
|
|
196
|
+
const cell = cells[i];
|
|
197
|
+
const coolingRate = extinguishRate * wetness[i];
|
|
111
198
|
if (cell.state === "burning") {
|
|
112
|
-
|
|
199
|
+
const burningDt = Math.min(dt, coolingRate === 0 ? Infinity : cell.heat / coolingRate);
|
|
200
|
+
cell.fuel = Math.max(0, cell.fuel - burnRate * burningDt);
|
|
201
|
+
cell.heat = Math.max(0, cell.heat - coolingRate * dt);
|
|
113
202
|
if (cell.fuel <= 0) {
|
|
114
203
|
cell.state = "burnt";
|
|
115
204
|
cell.heat = 0;
|
|
116
205
|
burning -= 1;
|
|
117
206
|
}
|
|
207
|
+
else if (coolingRate > 0 && cell.heat <= 0) {
|
|
208
|
+
extinguishCell(col, row);
|
|
209
|
+
}
|
|
118
210
|
continue;
|
|
119
211
|
}
|
|
120
|
-
if (cell.state !== "unburnt" || addedHeat[i] === 0)
|
|
212
|
+
if (cell.state !== "unburnt" || (addedHeat[i] === 0 && coolingRate === 0))
|
|
121
213
|
continue;
|
|
122
|
-
|
|
123
|
-
cell.heat += addedHeat[i] * (1 - resist);
|
|
214
|
+
cell.heat = Math.max(0, cell.heat + addedHeat[i] * (1 - wetness[i]) - coolingRate * dt);
|
|
124
215
|
if (cell.heat >= ignitionThreshold && cell.fuel > 0) {
|
|
125
216
|
cell.state = "burning";
|
|
126
217
|
burning += 1;
|
|
@@ -129,6 +220,11 @@ export function createFireGrid(config) {
|
|
|
129
220
|
}
|
|
130
221
|
},
|
|
131
222
|
igniteCell,
|
|
223
|
+
extinguishCell,
|
|
224
|
+
extinguish(x, z) {
|
|
225
|
+
const coord = cellCoord(x, z);
|
|
226
|
+
return coord !== null && extinguishCell(coord.col, coord.row);
|
|
227
|
+
},
|
|
132
228
|
ignite(x, z) {
|
|
133
229
|
const coord = cellCoord(x, z);
|
|
134
230
|
if (coord === null)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { GeneratedBuilding } from "./buildings.js";
|
|
2
|
+
import type { EnvironmentWorldFeature } from "./features.js";
|
|
3
|
+
import type { Aabb } from "./geometry.js";
|
|
4
|
+
import type { WallSegment } from "./walls.js";
|
|
5
|
+
/** One solid box in world space: the collision half of generated or authored world geometry. */
|
|
6
|
+
export interface WorldSolid {
|
|
7
|
+
center: readonly [number, number, number];
|
|
8
|
+
halfExtents: readonly [number, number, number];
|
|
9
|
+
/** Yaw about `center`, radians, in the engine's `rotationY` convention. Default `0`. */
|
|
10
|
+
rotationY?: number;
|
|
11
|
+
}
|
|
12
|
+
/** Serializable contents of a {@link WorldSolids}: every layer's solids by layer id. */
|
|
13
|
+
export interface WorldSolidsState {
|
|
14
|
+
layers: Record<string, readonly WorldSolid[]>;
|
|
15
|
+
}
|
|
16
|
+
/** Caller-owned work counters, reset by each world-solid ray candidate query. */
|
|
17
|
+
export interface WorldSolidRayWork {
|
|
18
|
+
/** Hash-grid cell lookups, including empty cells. */
|
|
19
|
+
cells: number;
|
|
20
|
+
/** Indexed entry visits, including duplicates removed before bounds tests. */
|
|
21
|
+
entries: number;
|
|
22
|
+
/** Cached AABB ray tests after deduplication. */
|
|
23
|
+
bounds: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Static collision for world geometry that is not a scene object: generated buildings, studio
|
|
27
|
+
* volumes like `city`, wall runs. Solids live in named layers so a feature can replace or drop its
|
|
28
|
+
* own set without touching the rest. `solidObstaclesNear` (player and NPC movement),
|
|
29
|
+
* `syncWorldColliders` (physics backends) and `populateNavGridFromSolids` all read this one store.
|
|
30
|
+
*/
|
|
31
|
+
export interface WorldSolids {
|
|
32
|
+
/** Replace a layer's solids; an empty list removes the layer. */
|
|
33
|
+
set(layer: string, solids: readonly WorldSolid[]): void;
|
|
34
|
+
remove(layer: string): void;
|
|
35
|
+
/** Run several `set`/`remove` calls as one change: one index rebuild, one notification. */
|
|
36
|
+
batch(apply: () => void): void;
|
|
37
|
+
/** Solids in one layer, empty when absent. */
|
|
38
|
+
layer(layer: string): readonly WorldSolid[];
|
|
39
|
+
layers(): readonly string[];
|
|
40
|
+
/** Every solid whose world AABB overlaps `min`..`max`. Bounded by a uniform XZ hash grid. */
|
|
41
|
+
inBox(min: readonly [number, number, number], max: readonly [number, number, number]): WorldSolid[];
|
|
42
|
+
/** Optional accelerated ray candidates; finite coordinates/direction and nonnegative finite distance, normalized internally. */
|
|
43
|
+
inRay?(origin: readonly [number, number, number], direction: readonly [number, number, number], maxDistance: number, work?: WorldSolidRayWork): WorldSolid[];
|
|
44
|
+
/** Every solid in every layer. */
|
|
45
|
+
all(): WorldSolid[];
|
|
46
|
+
count(): number;
|
|
47
|
+
/** Bumps on every change; cheap cache key for consumers. */
|
|
48
|
+
version(): number;
|
|
49
|
+
subscribe(listener: () => void): () => void;
|
|
50
|
+
snapshot(): WorldSolidsState;
|
|
51
|
+
restore(state: WorldSolidsState): void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Yaw-expanded world AABB of an oriented solid box.
|
|
55
|
+
* @capability world-solid-bounds world AABB and nav footprint of a world solid
|
|
56
|
+
*/
|
|
57
|
+
export declare function worldSolidBounds(solid: WorldSolid): {
|
|
58
|
+
min: [number, number, number];
|
|
59
|
+
max: [number, number, number];
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* XZ footprint of a solid's world AABB, for 2D consumers such as nav grids.
|
|
63
|
+
* @capability world-solid-bounds world AABB and nav footprint of a world solid
|
|
64
|
+
*/
|
|
65
|
+
export declare function worldSolidFootprint(solid: WorldSolid): Aabb;
|
|
66
|
+
/**
|
|
67
|
+
* A store of static world solids in named layers.
|
|
68
|
+
* @capability world-solids collision for generated and authored world geometry (buildings, city lots, walls)
|
|
69
|
+
*/
|
|
70
|
+
export declare function createWorldSolids(options?: {
|
|
71
|
+
cellSize?: number;
|
|
72
|
+
}): WorldSolids;
|
|
73
|
+
/**
|
|
74
|
+
* One solid per generated building: its `bounds` footprint turned by `rotationY` about `center`,
|
|
75
|
+
* from the ground under its center up through its floors. `groundHeight` defaults to flat `0`.
|
|
76
|
+
* @capability world-solids-from-data derive collision boxes from generated buildings and wall runs
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildingSolids(buildings: readonly GeneratedBuilding[], groundHeight?: (x: number, z: number) => number): WorldSolid[];
|
|
79
|
+
/**
|
|
80
|
+
* Solids for every `structures` descriptor on an environment feature, skipping any marked `solid: false`.
|
|
81
|
+
* @capability world-solids-from-data derive collision boxes from generated buildings and wall runs
|
|
82
|
+
*/
|
|
83
|
+
export declare function structureSolids(world: EnvironmentWorldFeature, groundHeight?: (x: number, z: number) => number): WorldSolid[];
|
|
84
|
+
/** Wall height, thickness and base for {@link wallSolids}. */
|
|
85
|
+
export interface WallSolidOptions {
|
|
86
|
+
height: number;
|
|
87
|
+
thickness: number;
|
|
88
|
+
/** Ground height under a point; the wall stands on it at each segment's midpoint. Default flat `0`. */
|
|
89
|
+
groundHeight?: (x: number, z: number) => number;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* One oriented solid per wall segment (see `wallSegments` in `world/walls`).
|
|
93
|
+
* @capability world-solids-from-data derive collision boxes from generated buildings and wall runs
|
|
94
|
+
*/
|
|
95
|
+
export declare function wallSolids(segments: readonly WallSegment[], options: WallSolidOptions): WorldSolid[];
|