@jgengine/core 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -2
- package/LICENSE +203 -661
- package/README.md +1 -1
- package/dist/ai/crowd.d.ts +55 -0
- package/dist/ai/crowd.js +114 -0
- package/dist/ai/flock.d.ts +5 -2
- package/dist/ai/flock.js +5 -2
- package/dist/ai/groupAssist.d.ts +1 -0
- package/dist/ai/groupAssist.js +1 -0
- package/dist/ai/heatSystem.d.ts +76 -0
- package/dist/ai/heatSystem.js +97 -0
- package/dist/ai/interestScheduler.d.ts +107 -0
- package/dist/ai/interestScheduler.js +118 -0
- package/dist/ai/jobBoard.d.ts +1 -0
- package/dist/ai/jobBoard.js +1 -0
- package/dist/ai/laneSelect.d.ts +5 -2
- package/dist/ai/laneSelect.js +5 -2
- package/dist/ai/mobBrain.d.ts +1 -0
- package/dist/ai/mobBrain.js +1 -0
- package/dist/ai/spawnDirector.d.ts +7 -2
- package/dist/ai/spawnDirector.js +18 -15
- package/dist/ai/spawnPoint.d.ts +3 -1
- package/dist/ai/spawnPoint.js +3 -1
- package/dist/ai/targetAcquisition.d.ts +84 -0
- package/dist/ai/targetAcquisition.js +92 -0
- package/dist/anim/easing.d.ts +19 -0
- package/dist/anim/easing.js +19 -0
- package/dist/anim/oscillator.d.ts +12 -0
- package/dist/anim/oscillator.js +25 -0
- package/dist/area/areaEffectField.d.ts +127 -0
- package/dist/area/areaEffectField.js +175 -0
- package/dist/area/stackPolicy.d.ts +47 -0
- package/dist/area/stackPolicy.js +99 -0
- package/dist/authoring.d.ts +1 -0
- package/dist/authoring.js +1 -0
- package/dist/board/laneBoard.d.ts +13 -0
- package/dist/board/laneBoard.js +13 -0
- package/dist/board/timelineBoard.d.ts +10 -0
- package/dist/board/timelineBoard.js +10 -0
- package/dist/combat/abilityKit.d.ts +18 -0
- package/dist/combat/abilityKit.js +24 -9
- package/dist/combat/animationState.d.ts +5 -0
- package/dist/combat/animationState.js +5 -0
- package/dist/combat/breakMeters.d.ts +10 -0
- package/dist/combat/breakMeters.js +10 -0
- package/dist/combat/castRunner.d.ts +5 -0
- package/dist/combat/castRunner.js +5 -0
- package/dist/combat/comboPoints.d.ts +5 -0
- package/dist/combat/comboPoints.js +5 -0
- package/dist/combat/comboString.d.ts +5 -0
- package/dist/combat/comboString.js +5 -0
- package/dist/combat/damageInterceptors.d.ts +192 -0
- package/dist/combat/damageInterceptors.js +251 -0
- package/dist/combat/damageMatchup.d.ts +68 -0
- package/dist/combat/damageMatchup.js +42 -0
- package/dist/combat/damageResolution.d.ts +63 -0
- package/dist/combat/damageResolution.js +50 -0
- package/dist/combat/death.d.ts +7 -1
- package/dist/combat/death.js +5 -0
- package/dist/combat/deathReason.d.ts +14 -0
- package/dist/combat/deathReason.js +1 -0
- package/dist/combat/defensiveWindow.d.ts +5 -0
- package/dist/combat/defensiveWindow.js +5 -0
- package/dist/combat/dotField.d.ts +5 -1
- package/dist/combat/dotField.js +5 -1
- package/dist/combat/downed.d.ts +5 -0
- package/dist/combat/downed.js +5 -0
- package/dist/combat/effects.d.ts +5 -0
- package/dist/combat/effects.js +5 -0
- package/dist/combat/encounterSequence.d.ts +258 -0
- package/dist/combat/encounterSequence.js +426 -0
- package/dist/combat/hitReaction.d.ts +57 -1
- package/dist/combat/hitReaction.js +45 -5
- package/dist/combat/magazine.d.ts +54 -0
- package/dist/combat/magazine.js +96 -0
- package/dist/combat/projectiles.d.ts +5 -0
- package/dist/combat/projectiles.js +32 -14
- package/dist/combat/receivedDamage.d.ts +117 -0
- package/dist/combat/receivedDamage.js +92 -0
- package/dist/combat/regenShield.d.ts +5 -1
- package/dist/combat/regenShield.js +5 -1
- package/dist/combat/renderCues.d.ts +51 -0
- package/dist/combat/renderCues.js +44 -0
- package/dist/combat/resourcePool.d.ts +5 -0
- package/dist/combat/resourcePool.js +5 -0
- package/dist/combat/rewardAllocation.d.ts +121 -0
- package/dist/combat/rewardAllocation.js +251 -0
- package/dist/combat/shotOrigin.d.ts +18 -1
- package/dist/combat/shotOrigin.js +39 -0
- package/dist/combat/statusApplication.d.ts +96 -0
- package/dist/combat/statusApplication.js +81 -0
- package/dist/combat/telegraph.d.ts +11 -2
- package/dist/combat/telegraph.js +11 -2
- package/dist/combat/thresholdCrossings.d.ts +85 -0
- package/dist/combat/thresholdCrossings.js +116 -0
- package/dist/combat.d.ts +34 -0
- package/dist/combat.js +34 -0
- package/dist/commands/commandRegistry.d.ts +11 -0
- package/dist/commands/commandRegistry.js +9 -2
- package/dist/crafting/crop.d.ts +18 -0
- package/dist/crafting/crop.js +18 -0
- package/dist/crafting/production.d.ts +5 -0
- package/dist/crafting/production.js +5 -0
- package/dist/devtools/rewriteTunables.d.ts +17 -0
- package/dist/devtools/rewriteTunables.js +276 -0
- package/dist/devtools/saveEndpoint.d.ts +46 -0
- package/dist/devtools/saveEndpoint.js +48 -0
- package/dist/devtools/transformTunables.d.ts +3 -0
- package/dist/devtools/transformTunables.js +3 -0
- package/dist/devtools/tunableSchema.d.ts +31 -0
- package/dist/devtools/tunableSchema.js +31 -0
- package/dist/economy/currency.d.ts +12 -1
- package/dist/economy/currency.js +12 -1
- package/dist/economy/listingBook.d.ts +91 -0
- package/dist/economy/listingBook.js +144 -0
- package/dist/economy/resourceLedger.d.ts +222 -0
- package/dist/economy/resourceLedger.js +353 -0
- package/dist/economy/sharedWallet.d.ts +14 -0
- package/dist/economy/sharedWallet.js +14 -0
- package/dist/economy/techTree.d.ts +12 -0
- package/dist/economy/techTree.js +12 -0
- package/dist/economy/wallet.d.ts +26 -2
- package/dist/economy/wallet.js +35 -6
- package/dist/editor/commands.d.ts +190 -7
- package/dist/editor/commands.js +727 -55
- package/dist/editor/document.d.ts +159 -13
- package/dist/editor/document.js +750 -19
- package/dist/editor/grid.d.ts +229 -0
- package/dist/editor/grid.js +366 -0
- package/dist/editor/gridAdapters.d.ts +80 -0
- package/dist/editor/gridAdapters.js +134 -0
- package/dist/editor/index.d.ts +73 -6
- package/dist/editor/index.js +6 -2
- package/dist/editor/liveSync.d.ts +127 -0
- package/dist/editor/liveSync.js +249 -0
- package/dist/editor/runtimeInspector.d.ts +88 -0
- package/dist/editor/runtimeInspector.js +239 -0
- package/dist/editor/types.d.ts +107 -1
- package/dist/faction/reputation.d.ts +5 -0
- package/dist/faction/reputation.js +5 -0
- package/dist/format/distance.d.ts +17 -0
- package/dist/format/distance.js +18 -0
- package/dist/format/duration.d.ts +27 -0
- package/dist/format/duration.js +45 -0
- package/dist/format/speed.d.ts +17 -0
- package/dist/format/speed.js +25 -0
- package/dist/game/connectedPlayers.d.ts +6 -4
- package/dist/game/connectedPlayers.js +2 -2
- package/dist/game/cosmetics.d.ts +9 -0
- package/dist/game/cosmetics.js +16 -0
- package/dist/game/defineGame.d.ts +100 -2
- package/dist/game/defineGame.js +39 -2
- package/dist/game/defineSystem.d.ts +88 -0
- package/dist/game/defineSystem.js +45 -0
- package/dist/game/dialogue.d.ts +33 -0
- package/dist/game/dialogue.js +21 -0
- package/dist/game/events.d.ts +35 -13
- package/dist/game/events.js +5 -0
- package/dist/game/feed.d.ts +33 -0
- package/dist/game/feed.js +35 -2
- package/dist/game/gamePhase.d.ts +11 -0
- package/dist/game/gamePhase.js +16 -0
- package/dist/game/leaderboard.d.ts +5 -0
- package/dist/game/leaderboard.js +5 -0
- package/dist/game/loadout.d.ts +5 -0
- package/dist/game/loadout.js +5 -0
- package/dist/game/lootFilter.d.ts +2 -0
- package/dist/game/lootFilter.js +2 -0
- package/dist/game/lootPipeline.d.ts +164 -0
- package/dist/game/lootPipeline.js +216 -0
- package/dist/game/lootTable.d.ts +19 -2
- package/dist/game/lootTable.js +15 -5
- package/dist/game/objectives.d.ts +43 -0
- package/dist/game/objectives.js +36 -0
- package/dist/game/paramLayers.d.ts +148 -0
- package/dist/game/paramLayers.js +185 -0
- package/dist/game/ping.d.ts +5 -0
- package/dist/game/ping.js +5 -0
- package/dist/game/playableGame.d.ts +92 -7
- package/dist/game/quest.d.ts +8 -0
- package/dist/game/quest.js +29 -0
- package/dist/game/race.d.ts +141 -0
- package/dist/game/race.js +169 -0
- package/dist/game/recordBook.d.ts +3 -1
- package/dist/game/recordBook.js +4 -1
- package/dist/game/ruleSelection.d.ts +75 -0
- package/dist/game/ruleSelection.js +127 -0
- package/dist/game/runDraft.d.ts +5 -0
- package/dist/game/runDraft.js +5 -0
- package/dist/game/saveStore.d.ts +111 -0
- package/dist/game/saveStore.js +312 -0
- package/dist/game/snapshotHistory.d.ts +67 -0
- package/dist/game/snapshotHistory.js +95 -0
- package/dist/game/social.d.ts +38 -1
- package/dist/game/social.js +71 -0
- package/dist/game/spawnPoints.d.ts +5 -0
- package/dist/game/spawnPoints.js +5 -0
- package/dist/game/systemRuntime.d.ts +50 -0
- package/dist/game/systemRuntime.js +157 -0
- package/dist/game/systemSchedule.d.ts +72 -0
- package/dist/game/systemSchedule.js +242 -0
- package/dist/game/toasts.d.ts +43 -0
- package/dist/game/toasts.js +44 -0
- package/dist/game/trade.d.ts +10 -0
- package/dist/game/trade.js +10 -0
- package/dist/game/unlocks.d.ts +8 -0
- package/dist/game/unlocks.js +16 -0
- package/dist/game/vfxInstance.d.ts +138 -0
- package/dist/game/vfxInstance.js +96 -0
- package/dist/game/worldItem.d.ts +17 -4
- package/dist/game/worldItem.js +17 -4
- package/dist/gameplay.d.ts +91 -0
- package/dist/gameplay.js +91 -0
- package/dist/index.d.ts +5 -14
- package/dist/index.js +5 -14
- package/dist/input/actionBindings.d.ts +23 -6
- package/dist/input/actionBindings.js +23 -6
- package/dist/input/axisInput.d.ts +7 -2
- package/dist/input/axisInput.js +7 -2
- package/dist/input/controlGroups.d.ts +67 -0
- package/dist/input/controlGroups.js +41 -0
- package/dist/input/touchScheme.d.ts +82 -6
- package/dist/input/touchScheme.js +123 -10
- package/dist/interaction/lockpick.d.ts +61 -0
- package/dist/interaction/lockpick.js +168 -0
- package/dist/interaction/proximityPrompt.d.ts +2 -0
- package/dist/interaction/proximityPrompt.js +2 -0
- package/dist/interaction/qte.d.ts +5 -0
- package/dist/interaction/qte.js +5 -0
- package/dist/interaction/skillCheck.d.ts +5 -0
- package/dist/interaction/skillCheck.js +5 -0
- package/dist/inventory/inventoryModel.d.ts +12 -0
- package/dist/inventory/inventoryModel.js +12 -0
- package/dist/inventory/shapedGrid.d.ts +16 -0
- package/dist/inventory/shapedGrid.js +16 -0
- package/dist/inventory/slotModel.d.ts +10 -0
- package/dist/inventory/slotModel.js +10 -0
- package/dist/item/durability.d.ts +5 -0
- package/dist/item/durability.js +5 -0
- package/dist/item/itemIdentity.d.ts +171 -0
- package/dist/item/itemIdentity.js +138 -0
- package/dist/item/itemInstanceRegistry.d.ts +32 -0
- package/dist/item/itemInstanceRegistry.js +34 -0
- package/dist/item/itemgen.d.ts +163 -0
- package/dist/item/itemgen.js +151 -0
- package/dist/item/modularItem.d.ts +5 -0
- package/dist/item/modularItem.js +5 -0
- package/dist/item/use.d.ts +5 -0
- package/dist/item/use.js +5 -0
- package/dist/item/useBehavior.d.ts +142 -0
- package/dist/item/useBehavior.js +105 -0
- package/dist/item/weapon.d.ts +5 -0
- package/dist/item/weapon.js +5 -0
- package/dist/math/scalar.d.ts +25 -0
- package/dist/math/scalar.js +47 -0
- package/dist/meta/changelog.d.ts +4 -1
- package/dist/meta/changelog.js +16 -2
- package/dist/movement/avoidance.d.ts +45 -0
- package/dist/movement/avoidance.js +123 -0
- package/dist/movement/cameraRig.d.ts +8 -0
- package/dist/movement/cameraRig.js +8 -0
- package/dist/movement/dash.d.ts +11 -0
- package/dist/movement/dash.js +11 -0
- package/dist/movement/formation.d.ts +135 -0
- package/dist/movement/formation.js +194 -0
- package/dist/movement/glideModel.d.ts +5 -0
- package/dist/movement/glideModel.js +5 -0
- package/dist/movement/grappleSwing.d.ts +5 -0
- package/dist/movement/grappleSwing.js +5 -0
- package/dist/movement/leaderTrail.d.ts +5 -0
- package/dist/movement/leaderTrail.js +5 -0
- package/dist/movement/movementModel.d.ts +35 -8
- package/dist/movement/movementModel.js +42 -14
- package/dist/movement/playerMovement.js +65 -10
- package/dist/movement/poseState.d.ts +13 -0
- package/dist/movement/poseState.js +16 -0
- package/dist/movement/steering.d.ts +8 -0
- package/dist/movement/steering.js +18 -0
- package/dist/multiplayer/combatSnapshot.d.ts +3 -0
- package/dist/multiplayer/combatSnapshot.js +3 -0
- package/dist/multiplayer/lagCompensation.d.ts +5 -0
- package/dist/multiplayer/lagCompensation.js +5 -0
- package/dist/multiplayer/presenceModel.d.ts +9 -1
- package/dist/multiplayer/presenceModel.js +9 -1
- package/dist/multiplayer/simultaneousCommit.d.ts +3 -0
- package/dist/multiplayer/simultaneousCommit.js +3 -0
- package/dist/multiplayer.d.ts +11 -0
- package/dist/multiplayer.js +11 -0
- package/dist/nav/pathFollow.d.ts +57 -0
- package/dist/nav/pathFollow.js +109 -0
- package/dist/orders/orderKinds.d.ts +156 -0
- package/dist/orders/orderKinds.js +197 -0
- package/dist/orders/orderQueue.d.ts +208 -0
- package/dist/orders/orderQueue.js +211 -0
- package/dist/physics/drivableVehicle.d.ts +29 -0
- package/dist/physics/drivableVehicle.js +16 -0
- package/dist/physics/kinematicVehicle.d.ts +21 -1
- package/dist/physics/kinematicVehicle.js +23 -8
- package/dist/physics/physicsWorld.d.ts +24 -12
- package/dist/physics/physicsWorld.js +11 -5
- package/dist/physics/radialImpulse.d.ts +25 -0
- package/dist/physics/radialImpulse.js +27 -0
- package/dist/procedural.d.ts +3 -0
- package/dist/procedural.js +3 -0
- package/dist/progression/statGraph.d.ts +116 -0
- package/dist/progression/statGraph.js +318 -0
- package/dist/puzzle/cellGrid.d.ts +9 -0
- package/dist/puzzle/cellGrid.js +9 -0
- package/dist/puzzle/fallingPiece.d.ts +9 -0
- package/dist/puzzle/fallingPiece.js +9 -0
- package/dist/puzzle/nonogram.d.ts +39 -0
- package/dist/puzzle/nonogram.js +136 -0
- package/dist/random/nameGen.d.ts +5 -0
- package/dist/random/nameGen.js +5 -0
- package/dist/random/pick.d.ts +8 -0
- package/dist/random/pick.js +31 -0
- package/dist/random/rng.d.ts +22 -0
- package/dist/random/rng.js +28 -8
- package/dist/random/seedLink.d.ts +4 -0
- package/dist/random/seedLink.js +4 -0
- package/dist/relation/keyedValues.d.ts +54 -0
- package/dist/relation/keyedValues.js +115 -0
- package/dist/relation/thresholds.d.ts +62 -0
- package/dist/relation/thresholds.js +62 -0
- package/dist/render/color.d.ts +12 -0
- package/dist/render/color.js +26 -0
- package/dist/render/lookPreset.d.ts +41 -0
- package/dist/render/lookPreset.js +29 -0
- package/dist/render/postProcessing.d.ts +20 -0
- package/dist/render/postProcessing.js +21 -1
- package/dist/rules/predicate.d.ts +53 -0
- package/dist/rules/predicate.js +64 -0
- package/dist/rules/ruleEffects.d.ts +38 -0
- package/dist/rules/ruleEffects.js +37 -0
- package/dist/rules/triggeredRules.d.ts +160 -0
- package/dist/rules/triggeredRules.js +241 -0
- package/dist/runtime/adapter.d.ts +42 -3
- package/dist/runtime/adapter.js +44 -1
- package/dist/runtime/cameraDirector.d.ts +1 -0
- package/dist/runtime/cameraDirector.js +1 -0
- package/dist/runtime/commandRunner.d.ts +1 -0
- package/dist/runtime/commandRunner.js +1 -0
- package/dist/runtime/context/combatFx.d.ts +23 -0
- package/dist/runtime/context/combatFx.js +161 -0
- package/dist/runtime/context/registries.d.ts +13 -0
- package/dist/runtime/context/registries.js +84 -0
- package/dist/runtime/context/worldItems.d.ts +21 -0
- package/dist/runtime/context/worldItems.js +37 -0
- package/dist/runtime/descriptors/baseline.d.ts +48 -0
- package/dist/runtime/descriptors/baseline.js +134 -0
- package/dist/runtime/descriptors/features.d.ts +74 -0
- package/dist/runtime/descriptors/features.js +281 -0
- package/dist/runtime/gameContext.d.ts +114 -13
- package/dist/runtime/gameContext.js +303 -395
- package/dist/runtime/gameRuntime.d.ts +1 -0
- package/dist/runtime/gameRuntime.js +1 -0
- package/dist/runtime/headlessRunner.d.ts +60 -0
- package/dist/runtime/headlessRunner.js +44 -0
- package/dist/runtime/hostPersistence.d.ts +12 -0
- package/dist/runtime/hostPersistence.js +12 -0
- package/dist/runtime/hostedGameRunner.d.ts +8 -3
- package/dist/runtime/hostedGameRunner.js +26 -3
- package/dist/runtime/hostedWorldSession.d.ts +12 -4
- package/dist/runtime/hostedWorldSession.js +11 -4
- package/dist/runtime/inputSnapshot.d.ts +8 -3
- package/dist/runtime/inputSnapshot.js +6 -2
- package/dist/runtime/motionIntents.d.ts +11 -2
- package/dist/runtime/motionIntents.js +16 -2
- package/dist/runtime/perContext.d.ts +15 -0
- package/dist/runtime/perContext.js +21 -0
- package/dist/runtime/runtimeSave.d.ts +79 -0
- package/dist/runtime/runtimeSave.js +105 -0
- package/dist/runtime/save.d.ts +4 -0
- package/dist/runtime/save.js +4 -0
- package/dist/runtime/snapshot.d.ts +7 -0
- package/dist/runtime/snapshot.js +7 -0
- package/dist/runtime/visibility.d.ts +2 -1
- package/dist/runtime/visibility.js +2 -1
- package/dist/runtime/worldChannel.d.ts +7 -3
- package/dist/runtime/worldChannel.js +51 -6
- package/dist/runtime/worldMirror.d.ts +14 -2
- package/dist/runtime/worldMirror.js +15 -2
- package/dist/runtime/worldProjection.d.ts +47 -0
- package/dist/runtime/worldProjection.js +52 -0
- package/dist/runtime/worldReplication.d.ts +30 -7
- package/dist/runtime/worldReplication.js +41 -9
- package/dist/runtime/worldSnapshot.d.ts +30 -3
- package/dist/runtime/worldSnapshot.js +20 -5
- package/dist/scene/assetCatalog.d.ts +21 -0
- package/dist/scene/assetCatalog.js +4 -0
- package/dist/scene/assetDiagnostics.d.ts +69 -0
- package/dist/scene/assetDiagnostics.js +110 -0
- package/dist/scene/assetGenerator.d.ts +65 -0
- package/dist/scene/assetGenerator.js +64 -0
- package/dist/scene/assetSpace.d.ts +137 -0
- package/dist/scene/assetSpace.js +259 -0
- package/dist/scene/authoredTriggers.d.ts +169 -0
- package/dist/scene/authoredTriggers.js +340 -0
- package/dist/scene/behaviorRuntime.d.ts +75 -0
- package/dist/scene/behaviorRuntime.js +217 -0
- package/dist/scene/behaviors.d.ts +14 -2
- package/dist/scene/behaviors.js +7 -2
- package/dist/scene/bodyBind.d.ts +60 -0
- package/dist/scene/bodyBind.js +51 -0
- package/dist/scene/builtinSceneKinds.d.ts +5 -0
- package/dist/scene/builtinSceneKinds.js +62 -0
- package/dist/scene/colliders.d.ts +13 -1
- package/dist/scene/colliders.js +37 -1
- package/dist/scene/entityStats.d.ts +11 -2
- package/dist/scene/entityStats.js +11 -2
- package/dist/scene/entityStore.d.ts +12 -1
- package/dist/scene/entityStore.js +15 -0
- package/dist/scene/facing.d.ts +18 -0
- package/dist/scene/facing.js +26 -0
- package/dist/scene/modelSockets.d.ts +33 -0
- package/dist/scene/modelSockets.js +29 -0
- package/dist/scene/objectQuery.d.ts +2 -0
- package/dist/scene/objectQuery.js +2 -0
- package/dist/scene/objectStore.d.ts +4 -0
- package/dist/scene/objectStore.js +6 -0
- package/dist/scene/possession.d.ts +8 -0
- package/dist/scene/possession.js +14 -0
- package/dist/scene/roster.d.ts +3 -0
- package/dist/scene/roster.js +12 -0
- package/dist/scene/sceneKinds.d.ts +240 -0
- package/dist/scene/sceneKinds.js +214 -0
- package/dist/scene/sceneOwnership.d.ts +169 -0
- package/dist/scene/sceneOwnership.js +179 -0
- package/dist/scene/selectionBookmarks.d.ts +93 -0
- package/dist/scene/selectionBookmarks.js +122 -0
- package/dist/scene/vehicleSeat.d.ts +68 -0
- package/dist/scene/vehicleSeat.js +59 -0
- package/dist/sensor/concealment.d.ts +3 -0
- package/dist/sensor/concealment.js +3 -0
- package/dist/sensor/freezeMonitor.d.ts +1 -0
- package/dist/sensor/freezeMonitor.js +1 -0
- package/dist/sensor/frustumSensor.d.ts +7 -3
- package/dist/sensor/frustumSensor.js +7 -3
- package/dist/sensor/hiddenStateProbe.d.ts +5 -2
- package/dist/sensor/hiddenStateProbe.js +5 -2
- package/dist/sensor/recordingBuffer.d.ts +2 -1
- package/dist/sensor/recordingBuffer.js +2 -1
- package/dist/sensor/replayLoop.d.ts +6 -2
- package/dist/sensor/replayLoop.js +6 -2
- package/dist/sensor/revealQuery.d.ts +2 -1
- package/dist/sensor/revealQuery.js +2 -1
- package/dist/sensor/visionCone.d.ts +10 -3
- package/dist/sensor/visionCone.js +10 -3
- package/dist/session/contestedChannel.d.ts +1 -0
- package/dist/session/contestedChannel.js +1 -0
- package/dist/session/extraction.d.ts +1 -0
- package/dist/session/extraction.js +1 -0
- package/dist/session/roles.d.ts +6 -0
- package/dist/session/roles.js +6 -0
- package/dist/session/roundState.d.ts +8 -0
- package/dist/session/roundState.js +2 -0
- package/dist/settings/settingsModel.d.ts +1 -0
- package/dist/settings/settingsModel.js +1 -0
- package/dist/stats/accumulatorMeter.d.ts +6 -0
- package/dist/stats/accumulatorMeter.js +6 -0
- package/dist/stats/eventMeter.d.ts +5 -0
- package/dist/stats/eventMeter.js +5 -0
- package/dist/stats/rollCheck.d.ts +5 -0
- package/dist/stats/rollCheck.js +5 -0
- package/dist/stats/statModifiers.d.ts +5 -0
- package/dist/stats/statModifiers.js +5 -0
- package/dist/store/defineKeyedStore.d.ts +38 -0
- package/dist/store/defineKeyedStore.js +42 -0
- package/dist/store/defineStore.d.ts +33 -0
- package/dist/store/defineStore.js +35 -0
- package/dist/store/observableKeyedStore.d.ts +5 -0
- package/dist/store/observableKeyedStore.js +34 -2
- package/dist/survival/decayMeter.d.ts +55 -0
- package/dist/survival/decayMeter.js +130 -55
- package/dist/survival/moodle.d.ts +2 -0
- package/dist/survival/regionHealth.d.ts +6 -0
- package/dist/survival/regionHealth.js +5 -0
- package/dist/tactics/fallingGrid.d.ts +4 -2
- package/dist/tactics/fallingGrid.js +4 -2
- package/dist/tactics/predictiveQuery.d.ts +3 -0
- package/dist/tactics/predictiveQuery.js +3 -0
- package/dist/tactics/snapshot.d.ts +2 -0
- package/dist/tactics/snapshot.js +2 -0
- package/dist/tactics/surface.d.ts +1 -0
- package/dist/tactics/surface.js +1 -0
- package/dist/tactics/tacticalGrid.d.ts +1 -0
- package/dist/tactics/tacticalGrid.js +1 -0
- package/dist/time/beatClock.d.ts +14 -4
- package/dist/time/beatClock.js +14 -4
- package/dist/time/calendarClock.d.ts +3 -0
- package/dist/time/calendarClock.js +3 -0
- package/dist/time/idleProgress.d.ts +4 -0
- package/dist/time/idleProgress.js +4 -0
- package/dist/time/simClock.d.ts +2 -0
- package/dist/time/simClock.js +20 -5
- package/dist/ui/actionModel.d.ts +110 -0
- package/dist/ui/actionModel.js +159 -0
- package/dist/ui/gameLayout.d.ts +30 -11
- package/dist/ui/gameLayout.js +30 -11
- package/dist/ui/hudDocument.d.ts +114 -0
- package/dist/ui/hudDocument.js +220 -0
- package/dist/ui/hudLayout.d.ts +33 -1
- package/dist/ui/hudLayout.js +204 -17
- package/dist/ui/selectionModel.d.ts +92 -0
- package/dist/ui/selectionModel.js +88 -0
- package/dist/ui/tooltipModel.d.ts +63 -0
- package/dist/ui/tooltipModel.js +82 -0
- package/dist/ui.d.ts +15 -0
- package/dist/ui.js +15 -0
- package/dist/visibility/bounds.d.ts +8 -1
- package/dist/visibility/bounds.js +8 -1
- package/dist/visibility/frustum.d.ts +12 -3
- package/dist/visibility/frustum.js +12 -3
- package/dist/work/jobQueue.d.ts +201 -0
- package/dist/work/jobQueue.js +253 -0
- package/dist/work/unitTraining.d.ts +58 -0
- package/dist/work/unitTraining.js +52 -0
- package/dist/world/authoredObjects.d.ts +58 -0
- package/dist/world/authoredObjects.js +69 -0
- package/dist/world/buildingGenerator.d.ts +18 -0
- package/dist/world/buildingGenerator.js +62 -0
- package/dist/world/buildings.d.ts +5 -0
- package/dist/world/buildings.js +5 -0
- package/dist/world/catenary.d.ts +22 -0
- package/dist/world/catenary.js +69 -0
- package/dist/world/features.d.ts +115 -7
- package/dist/world/features.js +56 -5
- package/dist/world/footprintGrid.d.ts +59 -0
- package/dist/world/footprintGrid.js +141 -0
- package/dist/world/geometry.d.ts +64 -0
- package/dist/world/geometry.js +94 -0
- package/dist/world/grassKind.d.ts +51 -0
- package/dist/world/grassKind.js +101 -0
- package/dist/world/pathInstances.d.ts +27 -0
- package/dist/world/pathInstances.js +27 -0
- package/dist/world/pathTerrain.d.ts +80 -0
- package/dist/world/pathTerrain.js +142 -0
- package/dist/world/placeAsset.d.ts +81 -0
- package/dist/world/placeAsset.js +77 -0
- package/dist/world/placement.d.ts +4 -0
- package/dist/world/placement.js +4 -0
- package/dist/world/placementController.d.ts +6 -0
- package/dist/world/placementController.js +6 -0
- package/dist/world/polyline.d.ts +34 -0
- package/dist/world/polyline.js +81 -0
- package/dist/world/roads.d.ts +8 -0
- package/dist/world/roads.js +38 -0
- package/dist/world/scatterRegion.d.ts +164 -0
- package/dist/world/scatterRegion.js +409 -0
- package/dist/world/sceneShapes.d.ts +43 -0
- package/dist/world/sceneShapes.js +1 -0
- package/dist/world/segment.d.ts +27 -0
- package/dist/world/segment.js +43 -0
- package/dist/world/soilKind.d.ts +48 -0
- package/dist/world/soilKind.js +92 -0
- package/dist/world/spatialSample.d.ts +241 -0
- package/dist/world/spatialSample.js +465 -0
- package/dist/world/terraform.d.ts +213 -1
- package/dist/world/terraform.js +655 -20
- package/dist/world/terrain.d.ts +119 -20
- package/dist/world/terrain.js +247 -41
- package/dist/world/terrainGuides.d.ts +182 -0
- package/dist/world/terrainGuides.js +343 -0
- package/dist/world/vec2.d.ts +81 -0
- package/dist/world/vec2.js +128 -0
- package/dist/world/vec3.d.ts +49 -0
- package/dist/world/vec3.js +76 -0
- package/dist/world/vegetation.d.ts +71 -0
- package/dist/world/vegetation.js +151 -0
- package/dist/world/visibilityField.d.ts +154 -0
- package/dist/world/visibilityField.js +271 -0
- package/dist/world/volumetricClouds.d.ts +52 -0
- package/dist/world/volumetricClouds.js +43 -0
- package/dist/world/walls.d.ts +9 -0
- package/dist/world/walls.js +9 -0
- package/dist/world/waterKind.d.ts +55 -0
- package/dist/world/waterKind.js +99 -0
- package/dist/world.d.ts +132 -0
- package/dist/world.js +132 -0
- package/package.json +32 -8
- package/skills/jgengine/SKILL.md +51 -0
- package/skills/jgengine/api.md +434 -0
- package/skills/jgengine/capabilities.md +29 -0
- package/skills/jgengine/reference-cartridge.md +72 -0
- package/skills/jgengine-combat/SKILL.md +34 -0
- package/skills/jgengine-combat/api.md +549 -0
- package/skills/jgengine-combat/capabilities.md +169 -0
- package/skills/jgengine-combat/reference.md +98 -0
- package/skills/jgengine-gameplay/SKILL.md +39 -0
- package/skills/jgengine-gameplay/api.md +1794 -0
- package/skills/jgengine-gameplay/capabilities.md +378 -0
- package/skills/jgengine-gameplay/reference-systems.md +60 -0
- package/skills/jgengine-world/SKILL.md +38 -0
- package/skills/jgengine-world/api.md +2652 -0
- package/skills/jgengine-world/capabilities.md +370 -0
- package/skills/jgengine-world/reference.md +222 -0
- package/dist/cartridge/runtime.d.ts +0 -15
- package/dist/cartridge/runtime.js +0 -556
- package/dist/cartridge/spec.d.ts +0 -188
- package/dist/cartridge/spec.js +0 -19
- package/dist/cartridge/validate.d.ts +0 -2
- package/dist/cartridge/validate.js +0 -78
- package/dist/store/engineStore.d.ts +0 -22
- package/dist/store/engineStore.js +0 -50
- package/dist/store/features.d.ts +0 -10
- package/dist/store/features.js +0 -23
- package/llms.txt +0 -5389
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { type Aabb, type AvoidMasks, type AvoidZone, type Vec2 } from "./geometry.js";
|
|
2
|
+
import type { SceneDocumentLike, ScenePathLike } from "./sceneShapes.js";
|
|
3
|
+
import type { TerrainNormal } from "./terrain.js";
|
|
4
|
+
/** The editor path kind that marks a closed polyline as a foliage/scatter region. */
|
|
5
|
+
export declare const SCATTER_PATH_KIND = "scatter";
|
|
6
|
+
/** One species/prop in a scatter region's palette, with a relative spawn weight. */
|
|
7
|
+
export interface ScatterPaletteEntry {
|
|
8
|
+
item: string;
|
|
9
|
+
weight: number;
|
|
10
|
+
}
|
|
11
|
+
/** How a scatter region fills its polygon: density, spacing, variation, and masking rules. */
|
|
12
|
+
export interface ScatterRegionRules {
|
|
13
|
+
/** Items per square meter across the region's footprint. */
|
|
14
|
+
density: number;
|
|
15
|
+
/** Minimum spacing between placements in meters; 0 allows clumping. */
|
|
16
|
+
minSpacing: number;
|
|
17
|
+
/** Seed string — same seed reproduces the same field. */
|
|
18
|
+
seed: string;
|
|
19
|
+
minScale: number;
|
|
20
|
+
maxScale: number;
|
|
21
|
+
/** Yaw range in radians applied per placement. */
|
|
22
|
+
minYaw: number;
|
|
23
|
+
maxYaw: number;
|
|
24
|
+
/** Lift every instance by this many meters off the ground. */
|
|
25
|
+
verticalOffset: number;
|
|
26
|
+
/** Orient instances to the terrain normal instead of straight up. */
|
|
27
|
+
alignToNormal: boolean;
|
|
28
|
+
/** Reject placements on ground steeper than this slope (rise/run); 0 disables. */
|
|
29
|
+
maxSlope: number;
|
|
30
|
+
minHeight: number;
|
|
31
|
+
maxHeight: number;
|
|
32
|
+
/** Thin placements out within this many meters of the region edge; 0 disables. */
|
|
33
|
+
edgeFalloff: number;
|
|
34
|
+
/** Grid jitter 0..1 — 0 is a rigid lattice, 1 fully scattered. */
|
|
35
|
+
jitter: number;
|
|
36
|
+
/** Weighted species palette; falls back to a single `grass` entry. */
|
|
37
|
+
palette: readonly ScatterPaletteEntry[];
|
|
38
|
+
/** Explicit no-scatter clearance discs this region always honors (manual exclusion). */
|
|
39
|
+
avoid: readonly AvoidZone[];
|
|
40
|
+
/** Honor document-wide clearance zones (tagged markers/paths) too; false = manual `avoid` only. */
|
|
41
|
+
autoAvoid: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** Defaults a bare scatter region fills with: sparse grass, lightly spaced. */
|
|
44
|
+
export declare const SCATTER_DEFAULTS: ScatterRegionRules;
|
|
45
|
+
/** Default clearance radius (m) for an auto-avoided gameplay marker with no explicit `meta.clearance`. */
|
|
46
|
+
export declare const DEFAULT_MARKER_CLEARANCE = 3.5;
|
|
47
|
+
/** Marker/volume kinds that repel scatter and flatten terrain by default (spawns, objectives, vendors). */
|
|
48
|
+
export declare const DEFAULT_CLEARANCE_KINDS: readonly string[];
|
|
49
|
+
/** A resolvable scatter region: a closed polygon footprint plus its fill rules. */
|
|
50
|
+
export interface ScatterRegion {
|
|
51
|
+
id: string;
|
|
52
|
+
polygon: readonly Vec2[];
|
|
53
|
+
rules: ScatterRegionRules;
|
|
54
|
+
}
|
|
55
|
+
/** A single placed scatter instance — grounded world position plus per-instance variation. */
|
|
56
|
+
export interface ScatterInstance {
|
|
57
|
+
id: string;
|
|
58
|
+
regionId: string;
|
|
59
|
+
item: string;
|
|
60
|
+
x: number;
|
|
61
|
+
y: number;
|
|
62
|
+
z: number;
|
|
63
|
+
rotationY: number;
|
|
64
|
+
scale: number;
|
|
65
|
+
normal?: TerrainNormal;
|
|
66
|
+
}
|
|
67
|
+
/** Ground sampler a scatter resolve reads height/normal from (the sculpt terrain or the game's ground). */
|
|
68
|
+
export interface ScatterTerrain {
|
|
69
|
+
sampleHeight(x: number, z: number): number;
|
|
70
|
+
sampleNormal(x: number, z: number): TerrainNormal;
|
|
71
|
+
}
|
|
72
|
+
/** Ray-casting point-in-polygon test on the XZ plane. */
|
|
73
|
+
export declare function pointInPolygon(point: Vec2, polygon: readonly Vec2[]): boolean;
|
|
74
|
+
/** Shortest distance from a point to a polygon's boundary. */
|
|
75
|
+
export declare function distanceToPolygonEdge(point: Vec2, polygon: readonly Vec2[]): number;
|
|
76
|
+
/** Axis-aligned bounds of a polygon, or null if it has no points. */
|
|
77
|
+
export declare function polygonBounds(polygon: readonly Vec2[]): Aabb | null;
|
|
78
|
+
/** Shoelace area of a polygon (always non-negative), in square meters. */
|
|
79
|
+
export declare function polygonArea(polygon: readonly Vec2[]): number;
|
|
80
|
+
/**
|
|
81
|
+
* Deterministic placements for one scatter region: scatter its polygon footprint at `density`
|
|
82
|
+
* items/m² (respecting `minSpacing`), clip to the polygon, thin near the edge, drop placements
|
|
83
|
+
* outside the slope/height mask, and derive item/scale/yaw from the region id + seed — so the same
|
|
84
|
+
* saved region always grows the same field. Grounds each instance on `terrain` when provided.
|
|
85
|
+
*/
|
|
86
|
+
export declare function resolveScatterRegion(region: ScatterRegion, terrain?: ScatterTerrain, avoid?: AvoidMasks): ScatterInstance[];
|
|
87
|
+
/** Parses a scatter region's palette from meta: a weighted `palette` array, else a single `item`. */
|
|
88
|
+
export declare function readScatterPalette(meta: Record<string, unknown> | undefined): ScatterPaletteEntry[];
|
|
89
|
+
/** True when an editor path is a foliage/scatter region. */
|
|
90
|
+
export declare function isScatterPath(path: ScenePathLike): boolean;
|
|
91
|
+
/** The path's scatter rules with defaults filled in; null for non-scatter paths. */
|
|
92
|
+
export declare function readScatterRules(path: ScenePathLike): ScatterRegionRules | null;
|
|
93
|
+
/**
|
|
94
|
+
* Parses a region's manual clearance discs from `meta.avoid` (array of {x,z,radius,feather?}).
|
|
95
|
+
* @internal — used by `readScatterRules`; games author `avoid` through the region inspector.
|
|
96
|
+
*/
|
|
97
|
+
export declare function readAvoidZones(meta: Record<string, unknown> | undefined): AvoidZone[];
|
|
98
|
+
/** Builds a resolvable {@link ScatterRegion} from a scatter path (XZ polygon + rules), or null. */
|
|
99
|
+
export declare function scatterRegionFromPath(path: ScenePathLike): ScatterRegion | null;
|
|
100
|
+
/** Estimated placement count for a scatter path — density × polygon area, for a live UI readout. */
|
|
101
|
+
export declare function scatterRegionEstimate(path: ScenePathLike): {
|
|
102
|
+
area: number;
|
|
103
|
+
count: number;
|
|
104
|
+
};
|
|
105
|
+
/** Controls which gameplay objects auto-repel scatter (and, for markers, flatten terrain). */
|
|
106
|
+
export interface ClearanceOptions {
|
|
107
|
+
/** Marker/volume/path kinds that auto-clear even without a `meta.clearance` tag. Default {@link DEFAULT_CLEARANCE_KINDS}. */
|
|
108
|
+
kinds?: readonly string[];
|
|
109
|
+
/** Restrict auto-clearing to these object ids only (any kind); overrides `kinds` when set. */
|
|
110
|
+
ids?: readonly string[];
|
|
111
|
+
/** Clearance radius (m) for a kind-matched object with no explicit tag. Default {@link DEFAULT_MARKER_CLEARANCE}. */
|
|
112
|
+
defaultClearance?: number;
|
|
113
|
+
/** Soft outer band (m) on every derived zone/corridor. Default 2. */
|
|
114
|
+
feather?: number;
|
|
115
|
+
/** Include a corridor along non-scatter paths (roads/routes) in {@link clearanceMasksFrom}. Default true. */
|
|
116
|
+
includePaths?: boolean;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Point-pad clearance **discs** from a document's markers/volumes — the terrain-flatten set (spawns,
|
|
120
|
+
* plots, POIs get a level pad). A marker/volume contributes a disc when it carries `meta.clearance`
|
|
121
|
+
* or its kind is in `kinds`. Paths are *not* included (they render draped, never flattened — see
|
|
122
|
+
* {@link clearanceMasksFrom} for their foliage corridor). Pass `ids`/`kinds` to scope it.
|
|
123
|
+
*/
|
|
124
|
+
export declare function clearanceZonesFrom(doc: SceneDocumentLike, options?: ClearanceOptions): AvoidZone[];
|
|
125
|
+
/**
|
|
126
|
+
* The full clearance region for scatter avoidance: point-pad {@link clearanceZonesFrom} **discs**
|
|
127
|
+
* plus clean-edged **corridors** along non-scatter paths (each `halfWidth` = `path.width/2 +
|
|
128
|
+
* clearance`). Corridors give a straight tree-line along a road instead of a scalloped disc chain —
|
|
129
|
+
* this is what `resolveScatter` auto-avoids. Set `includePaths: false` to drop the path corridors.
|
|
130
|
+
* @internal — `resolveScatter` builds these automatically; games rarely call it directly.
|
|
131
|
+
*/
|
|
132
|
+
export declare function clearanceMasksFrom(doc: SceneDocumentLike, options?: ClearanceOptions): AvoidMasks;
|
|
133
|
+
/** Extra inputs for {@link resolveScatter}: manual discs plus the auto-clearance toggle/scoping. */
|
|
134
|
+
export interface ResolveScatterOptions extends ClearanceOptions {
|
|
135
|
+
/** Additional clearance discs applied to every region regardless of per-region `autoAvoid`. */
|
|
136
|
+
avoid?: readonly AvoidZone[];
|
|
137
|
+
/** Master switch for document-derived auto-clearance; false = per-region `avoid` (and `options.avoid`) only. */
|
|
138
|
+
autoAvoid?: boolean;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Every scatter region's placements across a document, grounded on `terrain` when provided. Regions
|
|
142
|
+
* honor clearance masks: their own manual `avoid` discs, plus (when the region's `autoAvoid` is on and
|
|
143
|
+
* `options.autoAvoid !== false`) the document-wide discs + path corridors from {@link clearanceMasksFrom}
|
|
144
|
+
* — so foliage auto-clears spawns, plots, and paths without hand-carving the polygon.
|
|
145
|
+
*/
|
|
146
|
+
export declare function resolveScatter(doc: SceneDocumentLike, terrain?: ScatterTerrain, options?: ResolveScatterOptions): ScatterInstance[];
|
|
147
|
+
/** A spatial bucket of scatter instances — one draw unit the renderer can frustum-cull as a whole. */
|
|
148
|
+
export interface ScatterChunk {
|
|
149
|
+
/** `gx:gz` grid key of the chunk. */
|
|
150
|
+
key: string;
|
|
151
|
+
/** Chunk minimum XZ corner in world space. */
|
|
152
|
+
min: Vec2;
|
|
153
|
+
/** Chunk edge length in meters. */
|
|
154
|
+
size: number;
|
|
155
|
+
instances: ScatterInstance[];
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Buckets scatter instances into a uniform XZ grid of `chunkSize`-meter cells, so a dense region
|
|
159
|
+
* renders as many small draw units instead of one huge mesh — each chunk carries its own bounds and
|
|
160
|
+
* is frustum-culled independently, and offscreen chunks cost nothing. Empty chunks are omitted;
|
|
161
|
+
* order is deterministic (row-major by grid coordinate).
|
|
162
|
+
* @internal — the chunking behind the `InstancedScatter` renderer; not called directly by games.
|
|
163
|
+
*/
|
|
164
|
+
export declare function chunkScatterInstances(instances: readonly ScatterInstance[], chunkSize: number): ScatterChunk[];
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import { masksInfluence, } from "./geometry.js";
|
|
2
|
+
import { scatter } from "./scatter.js";
|
|
3
|
+
/** The editor path kind that marks a closed polyline as a foliage/scatter region. */
|
|
4
|
+
export const SCATTER_PATH_KIND = "scatter";
|
|
5
|
+
/** Defaults a bare scatter region fills with: sparse grass, lightly spaced. */
|
|
6
|
+
export const SCATTER_DEFAULTS = {
|
|
7
|
+
density: 0.15,
|
|
8
|
+
minSpacing: 1.5,
|
|
9
|
+
seed: "",
|
|
10
|
+
minScale: 0.8,
|
|
11
|
+
maxScale: 1.3,
|
|
12
|
+
minYaw: 0,
|
|
13
|
+
maxYaw: Math.PI * 2,
|
|
14
|
+
verticalOffset: 0,
|
|
15
|
+
alignToNormal: false,
|
|
16
|
+
maxSlope: 0,
|
|
17
|
+
minHeight: Number.NEGATIVE_INFINITY,
|
|
18
|
+
maxHeight: Number.POSITIVE_INFINITY,
|
|
19
|
+
edgeFalloff: 0,
|
|
20
|
+
jitter: 1,
|
|
21
|
+
palette: [{ item: "grass", weight: 1 }],
|
|
22
|
+
avoid: [],
|
|
23
|
+
autoAvoid: true,
|
|
24
|
+
};
|
|
25
|
+
/** Default clearance radius (m) for an auto-avoided gameplay marker with no explicit `meta.clearance`. */
|
|
26
|
+
export const DEFAULT_MARKER_CLEARANCE = 3.5;
|
|
27
|
+
/** Marker/volume kinds that repel scatter and flatten terrain by default (spawns, objectives, vendors). */
|
|
28
|
+
export const DEFAULT_CLEARANCE_KINDS = [
|
|
29
|
+
"player_spawn",
|
|
30
|
+
"spawn",
|
|
31
|
+
"boss",
|
|
32
|
+
"goal",
|
|
33
|
+
"keep",
|
|
34
|
+
"vendor",
|
|
35
|
+
"chest",
|
|
36
|
+
"travel",
|
|
37
|
+
];
|
|
38
|
+
function hash(text) {
|
|
39
|
+
let h = 2166136261 >>> 0;
|
|
40
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
41
|
+
h ^= text.charCodeAt(i);
|
|
42
|
+
h = Math.imul(h, 16777619);
|
|
43
|
+
}
|
|
44
|
+
return (h >>> 0) / 4294967296;
|
|
45
|
+
}
|
|
46
|
+
/** Ray-casting point-in-polygon test on the XZ plane. */
|
|
47
|
+
export function pointInPolygon(point, polygon) {
|
|
48
|
+
let inside = false;
|
|
49
|
+
const [px, pz] = point;
|
|
50
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i, i += 1) {
|
|
51
|
+
const [xi, zi] = polygon[i];
|
|
52
|
+
const [xj, zj] = polygon[j];
|
|
53
|
+
if (zi > pz !== zj > pz && px < ((xj - xi) * (pz - zi)) / (zj - zi) + xi)
|
|
54
|
+
inside = !inside;
|
|
55
|
+
}
|
|
56
|
+
return inside;
|
|
57
|
+
}
|
|
58
|
+
function distanceToSegment(px, pz, ax, az, bx, bz) {
|
|
59
|
+
const dx = bx - ax;
|
|
60
|
+
const dz = bz - az;
|
|
61
|
+
const lenSq = dx * dx + dz * dz || 1;
|
|
62
|
+
let t = ((px - ax) * dx + (pz - az) * dz) / lenSq;
|
|
63
|
+
t = t < 0 ? 0 : t > 1 ? 1 : t;
|
|
64
|
+
return Math.hypot(px - (ax + dx * t), pz - (az + dz * t));
|
|
65
|
+
}
|
|
66
|
+
/** Shortest distance from a point to a polygon's boundary. */
|
|
67
|
+
export function distanceToPolygonEdge(point, polygon) {
|
|
68
|
+
let best = Number.POSITIVE_INFINITY;
|
|
69
|
+
const [px, pz] = point;
|
|
70
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i, i += 1) {
|
|
71
|
+
const [xi, zi] = polygon[i];
|
|
72
|
+
const [xj, zj] = polygon[j];
|
|
73
|
+
best = Math.min(best, distanceToSegment(px, pz, xi, zi, xj, zj));
|
|
74
|
+
}
|
|
75
|
+
return best;
|
|
76
|
+
}
|
|
77
|
+
/** Axis-aligned bounds of a polygon, or null if it has no points. */
|
|
78
|
+
export function polygonBounds(polygon) {
|
|
79
|
+
if (polygon.length === 0)
|
|
80
|
+
return null;
|
|
81
|
+
let minX = Infinity;
|
|
82
|
+
let minZ = Infinity;
|
|
83
|
+
let maxX = -Infinity;
|
|
84
|
+
let maxZ = -Infinity;
|
|
85
|
+
for (const [x, z] of polygon) {
|
|
86
|
+
if (x < minX)
|
|
87
|
+
minX = x;
|
|
88
|
+
if (x > maxX)
|
|
89
|
+
maxX = x;
|
|
90
|
+
if (z < minZ)
|
|
91
|
+
minZ = z;
|
|
92
|
+
if (z > maxZ)
|
|
93
|
+
maxZ = z;
|
|
94
|
+
}
|
|
95
|
+
return { minX, minZ, maxX, maxZ };
|
|
96
|
+
}
|
|
97
|
+
/** Shoelace area of a polygon (always non-negative), in square meters. */
|
|
98
|
+
export function polygonArea(polygon) {
|
|
99
|
+
if (polygon.length < 3)
|
|
100
|
+
return 0;
|
|
101
|
+
let sum = 0;
|
|
102
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i, i += 1) {
|
|
103
|
+
const [xi, zi] = polygon[i];
|
|
104
|
+
const [xj, zj] = polygon[j];
|
|
105
|
+
sum += xj * zi - xi * zj;
|
|
106
|
+
}
|
|
107
|
+
return Math.abs(sum) / 2;
|
|
108
|
+
}
|
|
109
|
+
function pickWeighted(palette, roll) {
|
|
110
|
+
if (palette.length === 0)
|
|
111
|
+
return "grass";
|
|
112
|
+
const total = palette.reduce((sum, entry) => sum + Math.max(0, entry.weight), 0);
|
|
113
|
+
if (total <= 0)
|
|
114
|
+
return palette[0].item;
|
|
115
|
+
let acc = roll * total;
|
|
116
|
+
for (const entry of palette) {
|
|
117
|
+
acc -= Math.max(0, entry.weight);
|
|
118
|
+
if (acc <= 0)
|
|
119
|
+
return entry.item;
|
|
120
|
+
}
|
|
121
|
+
return palette[palette.length - 1].item;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Deterministic placements for one scatter region: scatter its polygon footprint at `density`
|
|
125
|
+
* items/m² (respecting `minSpacing`), clip to the polygon, thin near the edge, drop placements
|
|
126
|
+
* outside the slope/height mask, and derive item/scale/yaw from the region id + seed — so the same
|
|
127
|
+
* saved region always grows the same field. Grounds each instance on `terrain` when provided.
|
|
128
|
+
*/
|
|
129
|
+
export function resolveScatterRegion(region, terrain, avoid) {
|
|
130
|
+
const rules = region.rules;
|
|
131
|
+
const bounds = polygonBounds(region.polygon);
|
|
132
|
+
if (bounds === null || region.polygon.length < 3 || rules.density <= 0)
|
|
133
|
+
return [];
|
|
134
|
+
const ownDiscs = rules.avoid ?? [];
|
|
135
|
+
const masks = {
|
|
136
|
+
discs: avoid === undefined ? ownDiscs : ownDiscs.length === 0 ? avoid.discs : [...ownDiscs, ...avoid.discs],
|
|
137
|
+
corridors: avoid?.corridors ?? [],
|
|
138
|
+
};
|
|
139
|
+
const hasMasks = masks.discs.length > 0 || masks.corridors.length > 0;
|
|
140
|
+
const points = scatter({
|
|
141
|
+
area: bounds,
|
|
142
|
+
density: rules.density,
|
|
143
|
+
minDistance: rules.minSpacing,
|
|
144
|
+
jitter: rules.jitter,
|
|
145
|
+
seed: `${region.id}:${rules.seed}`,
|
|
146
|
+
});
|
|
147
|
+
const instances = [];
|
|
148
|
+
for (const point of points) {
|
|
149
|
+
const p = [point.x, point.z];
|
|
150
|
+
if (!pointInPolygon(p, region.polygon))
|
|
151
|
+
continue;
|
|
152
|
+
// Clearance masks repel scatter: hard reject in the solid core, thin probabilistically in the feather.
|
|
153
|
+
if (hasMasks) {
|
|
154
|
+
const influence = masksInfluence(point.x, point.z, masks);
|
|
155
|
+
if (influence >= 1)
|
|
156
|
+
continue;
|
|
157
|
+
if (influence > 0 && hash(`${region.id}:avoid:${point.index}`) < influence)
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (rules.edgeFalloff > 0) {
|
|
161
|
+
const edge = distanceToPolygonEdge(p, region.polygon);
|
|
162
|
+
if (edge < rules.edgeFalloff && hash(`${region.id}:edge:${point.index}`) > edge / rules.edgeFalloff)
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
let y = rules.verticalOffset;
|
|
166
|
+
let normal;
|
|
167
|
+
if (terrain !== undefined) {
|
|
168
|
+
const height = terrain.sampleHeight(point.x, point.z);
|
|
169
|
+
if (height < rules.minHeight || height > rules.maxHeight)
|
|
170
|
+
continue;
|
|
171
|
+
const n = terrain.sampleNormal(point.x, point.z);
|
|
172
|
+
if (rules.maxSlope > 0) {
|
|
173
|
+
const slope = Math.hypot(n[0], n[2]) / Math.max(n[1], 1e-9);
|
|
174
|
+
if (slope > rules.maxSlope)
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
y = height + rules.verticalOffset;
|
|
178
|
+
if (rules.alignToNormal)
|
|
179
|
+
normal = n;
|
|
180
|
+
}
|
|
181
|
+
const scaleRoll = hash(`${region.id}:${rules.seed}:scale:${point.index}`);
|
|
182
|
+
const yawRoll = hash(`${region.id}:${rules.seed}:yaw:${point.index}`);
|
|
183
|
+
const itemRoll = hash(`${region.id}:${rules.seed}:item:${point.index}`);
|
|
184
|
+
instances.push({
|
|
185
|
+
id: `${region.id}/${point.index}`,
|
|
186
|
+
regionId: region.id,
|
|
187
|
+
item: pickWeighted(rules.palette, itemRoll),
|
|
188
|
+
x: point.x,
|
|
189
|
+
y,
|
|
190
|
+
z: point.z,
|
|
191
|
+
rotationY: rules.minYaw + (rules.maxYaw - rules.minYaw) * yawRoll,
|
|
192
|
+
scale: rules.minScale + (rules.maxScale - rules.minScale) * scaleRoll,
|
|
193
|
+
...(normal === undefined ? {} : { normal }),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
return instances;
|
|
197
|
+
}
|
|
198
|
+
function metaNumber(meta, key, fallback) {
|
|
199
|
+
const value = meta?.[key];
|
|
200
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
201
|
+
}
|
|
202
|
+
function metaString(meta, key, fallback) {
|
|
203
|
+
const value = meta?.[key];
|
|
204
|
+
return typeof value === "string" ? value : fallback;
|
|
205
|
+
}
|
|
206
|
+
function metaBool(meta, key, fallback) {
|
|
207
|
+
const value = meta?.[key];
|
|
208
|
+
return typeof value === "boolean" ? value : fallback;
|
|
209
|
+
}
|
|
210
|
+
/** Parses a scatter region's palette from meta: a weighted `palette` array, else a single `item`. */
|
|
211
|
+
export function readScatterPalette(meta) {
|
|
212
|
+
const raw = meta?.["palette"];
|
|
213
|
+
if (Array.isArray(raw)) {
|
|
214
|
+
const entries = raw
|
|
215
|
+
.filter((entry) => typeof entry === "object" && entry !== null)
|
|
216
|
+
.map((entry) => ({
|
|
217
|
+
item: typeof entry.item === "string" ? entry.item : "grass",
|
|
218
|
+
weight: typeof entry.weight === "number" && Number.isFinite(entry.weight) ? Math.max(0, entry.weight) : 1,
|
|
219
|
+
}))
|
|
220
|
+
.filter((entry) => entry.item.length > 0);
|
|
221
|
+
if (entries.length > 0)
|
|
222
|
+
return entries;
|
|
223
|
+
}
|
|
224
|
+
const single = metaString(meta, "item", "");
|
|
225
|
+
if (single.length > 0)
|
|
226
|
+
return [{ item: single, weight: 1 }];
|
|
227
|
+
return [...SCATTER_DEFAULTS.palette];
|
|
228
|
+
}
|
|
229
|
+
/** True when an editor path is a foliage/scatter region. */
|
|
230
|
+
export function isScatterPath(path) {
|
|
231
|
+
return path.kind === SCATTER_PATH_KIND;
|
|
232
|
+
}
|
|
233
|
+
/** The path's scatter rules with defaults filled in; null for non-scatter paths. */
|
|
234
|
+
export function readScatterRules(path) {
|
|
235
|
+
if (!isScatterPath(path))
|
|
236
|
+
return null;
|
|
237
|
+
const meta = path.meta;
|
|
238
|
+
return {
|
|
239
|
+
density: Math.max(0, metaNumber(meta, "density", SCATTER_DEFAULTS.density)),
|
|
240
|
+
minSpacing: Math.max(0, metaNumber(meta, "minSpacing", SCATTER_DEFAULTS.minSpacing)),
|
|
241
|
+
seed: metaString(meta, "seed", SCATTER_DEFAULTS.seed),
|
|
242
|
+
minScale: metaNumber(meta, "minScale", SCATTER_DEFAULTS.minScale),
|
|
243
|
+
maxScale: metaNumber(meta, "maxScale", SCATTER_DEFAULTS.maxScale),
|
|
244
|
+
minYaw: metaNumber(meta, "minYaw", SCATTER_DEFAULTS.minYaw),
|
|
245
|
+
maxYaw: metaNumber(meta, "maxYaw", SCATTER_DEFAULTS.maxYaw),
|
|
246
|
+
verticalOffset: metaNumber(meta, "verticalOffset", SCATTER_DEFAULTS.verticalOffset),
|
|
247
|
+
alignToNormal: metaBool(meta, "alignToNormal", SCATTER_DEFAULTS.alignToNormal),
|
|
248
|
+
maxSlope: Math.max(0, metaNumber(meta, "maxSlope", SCATTER_DEFAULTS.maxSlope)),
|
|
249
|
+
minHeight: metaNumber(meta, "minHeight", SCATTER_DEFAULTS.minHeight),
|
|
250
|
+
maxHeight: metaNumber(meta, "maxHeight", SCATTER_DEFAULTS.maxHeight),
|
|
251
|
+
edgeFalloff: Math.max(0, metaNumber(meta, "edgeFalloff", SCATTER_DEFAULTS.edgeFalloff)),
|
|
252
|
+
jitter: metaNumber(meta, "jitter", SCATTER_DEFAULTS.jitter),
|
|
253
|
+
palette: readScatterPalette(meta),
|
|
254
|
+
avoid: readAvoidZones(meta),
|
|
255
|
+
autoAvoid: metaBool(meta, "autoAvoid", SCATTER_DEFAULTS.autoAvoid),
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Parses a region's manual clearance discs from `meta.avoid` (array of {x,z,radius,feather?}).
|
|
260
|
+
* @internal — used by `readScatterRules`; games author `avoid` through the region inspector.
|
|
261
|
+
*/
|
|
262
|
+
export function readAvoidZones(meta) {
|
|
263
|
+
const raw = meta?.["avoid"];
|
|
264
|
+
if (!Array.isArray(raw))
|
|
265
|
+
return [];
|
|
266
|
+
const zones = [];
|
|
267
|
+
for (const entry of raw) {
|
|
268
|
+
if (typeof entry !== "object" || entry === null)
|
|
269
|
+
continue;
|
|
270
|
+
const e = entry;
|
|
271
|
+
if (typeof e.x !== "number" || typeof e.z !== "number" || typeof e.radius !== "number")
|
|
272
|
+
continue;
|
|
273
|
+
zones.push({
|
|
274
|
+
x: e.x,
|
|
275
|
+
z: e.z,
|
|
276
|
+
radius: Math.max(0, e.radius),
|
|
277
|
+
...(typeof e.feather === "number" ? { feather: Math.max(0, e.feather) } : {}),
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return zones;
|
|
281
|
+
}
|
|
282
|
+
/** Builds a resolvable {@link ScatterRegion} from a scatter path (XZ polygon + rules), or null. */
|
|
283
|
+
export function scatterRegionFromPath(path) {
|
|
284
|
+
const rules = readScatterRules(path);
|
|
285
|
+
if (rules === null || path.points.length < 3)
|
|
286
|
+
return null;
|
|
287
|
+
return {
|
|
288
|
+
id: path.id,
|
|
289
|
+
polygon: path.points.map((point) => [point.x, point.z]),
|
|
290
|
+
rules,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/** Estimated placement count for a scatter path — density × polygon area, for a live UI readout. */
|
|
294
|
+
export function scatterRegionEstimate(path) {
|
|
295
|
+
const rules = readScatterRules(path);
|
|
296
|
+
if (rules === null)
|
|
297
|
+
return { area: 0, count: 0 };
|
|
298
|
+
const area = polygonArea(path.points.map((point) => [point.x, point.z]));
|
|
299
|
+
return { area, count: Math.floor(area * rules.density) };
|
|
300
|
+
}
|
|
301
|
+
/** Reads a gameplay object's clearance radius: explicit `meta.clearance`, else a kind default, else 0. */
|
|
302
|
+
function clearanceOf(kind, meta, kinds, defaultClearance) {
|
|
303
|
+
const explicit = meta?.["clearance"];
|
|
304
|
+
if (typeof explicit === "number" && Number.isFinite(explicit))
|
|
305
|
+
return Math.max(0, explicit);
|
|
306
|
+
return kinds.includes(kind) ? defaultClearance : 0;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Point-pad clearance **discs** from a document's markers/volumes — the terrain-flatten set (spawns,
|
|
310
|
+
* plots, POIs get a level pad). A marker/volume contributes a disc when it carries `meta.clearance`
|
|
311
|
+
* or its kind is in `kinds`. Paths are *not* included (they render draped, never flattened — see
|
|
312
|
+
* {@link clearanceMasksFrom} for their foliage corridor). Pass `ids`/`kinds` to scope it.
|
|
313
|
+
*/
|
|
314
|
+
export function clearanceZonesFrom(doc, options = {}) {
|
|
315
|
+
const kinds = options.ids !== undefined ? [] : options.kinds ?? DEFAULT_CLEARANCE_KINDS;
|
|
316
|
+
const idSet = options.ids === undefined ? null : new Set(options.ids);
|
|
317
|
+
const defaultClearance = options.defaultClearance ?? DEFAULT_MARKER_CLEARANCE;
|
|
318
|
+
const feather = options.feather ?? 2;
|
|
319
|
+
const zones = [];
|
|
320
|
+
const consider = (id, kind, x, z, meta, extra) => {
|
|
321
|
+
if (idSet !== null && !idSet.has(id))
|
|
322
|
+
return;
|
|
323
|
+
const clearance = idSet !== null ? defaultClearance : clearanceOf(kind, meta, kinds, defaultClearance);
|
|
324
|
+
if (clearance <= 0)
|
|
325
|
+
return;
|
|
326
|
+
zones.push({ x, z, radius: clearance + extra, feather });
|
|
327
|
+
};
|
|
328
|
+
for (const marker of doc.markers)
|
|
329
|
+
consider(marker.id, marker.kind, marker.position.x, marker.position.z, marker.meta, 0);
|
|
330
|
+
for (const volume of doc.volumes)
|
|
331
|
+
consider(volume.id, volume.kind, volume.center.x, volume.center.z, volume.meta, volume.radius ?? 0);
|
|
332
|
+
return zones;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* The full clearance region for scatter avoidance: point-pad {@link clearanceZonesFrom} **discs**
|
|
336
|
+
* plus clean-edged **corridors** along non-scatter paths (each `halfWidth` = `path.width/2 +
|
|
337
|
+
* clearance`). Corridors give a straight tree-line along a road instead of a scalloped disc chain —
|
|
338
|
+
* this is what `resolveScatter` auto-avoids. Set `includePaths: false` to drop the path corridors.
|
|
339
|
+
* @internal — `resolveScatter` builds these automatically; games rarely call it directly.
|
|
340
|
+
*/
|
|
341
|
+
export function clearanceMasksFrom(doc, options = {}) {
|
|
342
|
+
const kinds = options.ids !== undefined ? [] : options.kinds ?? DEFAULT_CLEARANCE_KINDS;
|
|
343
|
+
const idSet = options.ids === undefined ? null : new Set(options.ids);
|
|
344
|
+
const defaultClearance = options.defaultClearance ?? DEFAULT_MARKER_CLEARANCE;
|
|
345
|
+
const feather = options.feather ?? 2;
|
|
346
|
+
const includePaths = options.includePaths ?? true;
|
|
347
|
+
const corridors = [];
|
|
348
|
+
if (includePaths) {
|
|
349
|
+
for (const path of doc.paths) {
|
|
350
|
+
if (isScatterPath(path) || path.points.length < 2)
|
|
351
|
+
continue;
|
|
352
|
+
if (idSet !== null && !idSet.has(path.id))
|
|
353
|
+
continue;
|
|
354
|
+
const clearance = idSet !== null ? defaultClearance : clearanceOf(path.kind, path.meta, kinds, defaultClearance);
|
|
355
|
+
const explicit = typeof path.meta?.["clearance"] === "number";
|
|
356
|
+
if (clearance <= 0 && !explicit)
|
|
357
|
+
continue;
|
|
358
|
+
const half = (path.width ?? 4) / 2 + (clearance > 0 ? clearance : defaultClearance);
|
|
359
|
+
corridors.push({ points: path.points.map((point) => [point.x, point.z]), halfWidth: half, feather });
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return { discs: clearanceZonesFrom(doc, options), corridors };
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Every scatter region's placements across a document, grounded on `terrain` when provided. Regions
|
|
366
|
+
* honor clearance masks: their own manual `avoid` discs, plus (when the region's `autoAvoid` is on and
|
|
367
|
+
* `options.autoAvoid !== false`) the document-wide discs + path corridors from {@link clearanceMasksFrom}
|
|
368
|
+
* — so foliage auto-clears spawns, plots, and paths without hand-carving the polygon.
|
|
369
|
+
*/
|
|
370
|
+
export function resolveScatter(doc, terrain, options = {}) {
|
|
371
|
+
const baseDiscs = options.avoid ?? [];
|
|
372
|
+
const auto = options.autoAvoid === false ? { discs: [], corridors: [] } : clearanceMasksFrom(doc, options);
|
|
373
|
+
const out = [];
|
|
374
|
+
for (const path of doc.paths) {
|
|
375
|
+
const region = scatterRegionFromPath(path);
|
|
376
|
+
if (region === null)
|
|
377
|
+
continue;
|
|
378
|
+
const useAuto = region.rules.autoAvoid && options.autoAvoid !== false;
|
|
379
|
+
const masks = {
|
|
380
|
+
discs: useAuto ? [...baseDiscs, ...auto.discs] : baseDiscs,
|
|
381
|
+
corridors: useAuto ? auto.corridors : [],
|
|
382
|
+
};
|
|
383
|
+
out.push(...resolveScatterRegion(region, terrain, masks));
|
|
384
|
+
}
|
|
385
|
+
return out;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Buckets scatter instances into a uniform XZ grid of `chunkSize`-meter cells, so a dense region
|
|
389
|
+
* renders as many small draw units instead of one huge mesh — each chunk carries its own bounds and
|
|
390
|
+
* is frustum-culled independently, and offscreen chunks cost nothing. Empty chunks are omitted;
|
|
391
|
+
* order is deterministic (row-major by grid coordinate).
|
|
392
|
+
* @internal — the chunking behind the `InstancedScatter` renderer; not called directly by games.
|
|
393
|
+
*/
|
|
394
|
+
export function chunkScatterInstances(instances, chunkSize) {
|
|
395
|
+
const size = chunkSize > 0 ? chunkSize : 32;
|
|
396
|
+
const byKey = new Map();
|
|
397
|
+
for (const instance of instances) {
|
|
398
|
+
const gx = Math.floor(instance.x / size);
|
|
399
|
+
const gz = Math.floor(instance.z / size);
|
|
400
|
+
const key = `${gx}:${gz}`;
|
|
401
|
+
let chunk = byKey.get(key);
|
|
402
|
+
if (chunk === undefined) {
|
|
403
|
+
chunk = { key, min: [gx * size, gz * size], size, instances: [] };
|
|
404
|
+
byKey.set(key, chunk);
|
|
405
|
+
}
|
|
406
|
+
chunk.instances.push(instance);
|
|
407
|
+
}
|
|
408
|
+
return [...byKey.values()].sort((a, b) => a.key.localeCompare(b.key));
|
|
409
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** A world-space point — structurally compatible with the editor's `EditorVec3`. */
|
|
2
|
+
export interface ScenePoint3 {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
z: number;
|
|
6
|
+
}
|
|
7
|
+
/** The minimal polyline shape {@link resolveScatterRegion} et al. read; any `EditorPath` satisfies it. */
|
|
8
|
+
export interface ScenePathLike {
|
|
9
|
+
id: string;
|
|
10
|
+
kind: string;
|
|
11
|
+
points: readonly ScenePoint3[];
|
|
12
|
+
width?: number;
|
|
13
|
+
meta?: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
/** The minimal point-object shape clearance reads from a document's markers; any `EditorMarker` satisfies it. */
|
|
16
|
+
export interface SceneMarkerLike {
|
|
17
|
+
id: string;
|
|
18
|
+
kind: string;
|
|
19
|
+
position: ScenePoint3;
|
|
20
|
+
meta?: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
/** The minimal volume shape vegetation/clearance/triggers read; any `EditorVolume` satisfies it. */
|
|
23
|
+
export interface SceneVolumeLike {
|
|
24
|
+
id: string;
|
|
25
|
+
kind: string;
|
|
26
|
+
shape: "sphere" | "cylinder" | "box";
|
|
27
|
+
center: ScenePoint3;
|
|
28
|
+
radius?: number;
|
|
29
|
+
/** Cylinder height (m); containment and editors use this when shape is `cylinder`. */
|
|
30
|
+
height?: number;
|
|
31
|
+
halfExtents?: ScenePoint3;
|
|
32
|
+
meta?: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The minimal document shape scatter/vegetation resolve against — markers, volumes, and paths only.
|
|
36
|
+
* Any `EditorDocument` satisfies it structurally; this module never imports the editor domain, so
|
|
37
|
+
* world stays the one-directional dependency editor already builds on.
|
|
38
|
+
*/
|
|
39
|
+
export interface SceneDocumentLike {
|
|
40
|
+
markers: readonly SceneMarkerLike[];
|
|
41
|
+
volumes: readonly SceneVolumeLike[];
|
|
42
|
+
paths: readonly ScenePathLike[];
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Vec2 } from "./geometry.js";
|
|
2
|
+
/** Closest point on segment `a`→`b` to `p`, and the clamped parameter `t` in [0,1] where it lies. */
|
|
3
|
+
export interface ClosestOnSegment {
|
|
4
|
+
point: Vec2;
|
|
5
|
+
t: number;
|
|
6
|
+
}
|
|
7
|
+
/** Closest point on the segment `a`→`b` to point `p`, with the clamped parameter `t` (0 at `a`, 1 at `b`). */
|
|
8
|
+
export declare function closestPointOnSegment(p: Vec2, a: Vec2, b: Vec2): ClosestOnSegment;
|
|
9
|
+
/** A resolved circle-vs-segment contact. */
|
|
10
|
+
export interface CircleSegmentHit {
|
|
11
|
+
/** Unit surface normal pointing from the segment toward the circle center — the axis to bounce off. */
|
|
12
|
+
normal: Vec2;
|
|
13
|
+
/** Penetration depth; push the center out by `normal · depth` to separate. */
|
|
14
|
+
depth: number;
|
|
15
|
+
/** Closest point on the segment (the contact point). */
|
|
16
|
+
contact: Vec2;
|
|
17
|
+
/** Circle center pushed just outside the segment — a tunnel-proof resolved position. */
|
|
18
|
+
resolved: Vec2;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Circle (center + `radius`) against a capsule segment `a`→`b` of half-thickness `thickness` (0 for a thin
|
|
22
|
+
* wall). Returns the contact — surface normal, penetration depth, contact point, and the separated center —
|
|
23
|
+
* or `null` when they do not overlap. Endpoints are rounded (the segment is a capsule), so a ball never
|
|
24
|
+
* catches on a corner. Reflect the velocity across `normal` for the bounce; the pure geometry every 2D
|
|
25
|
+
* ball game (pinball, breakout, air hockey) reimplemented per wall, bumper, and paddle.
|
|
26
|
+
*/
|
|
27
|
+
export declare function circleVsSegment(center: Vec2, radius: number, a: Vec2, b: Vec2, thickness?: number): CircleSegmentHit | null;
|