@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,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authored behavior triggers on editor volumes and markers — a small `on`/`action` meta vocabulary
|
|
3
|
+
* so "when player enters this volume, spawn wave 2" is scene data, not game code. Games declare
|
|
4
|
+
* actions (typed via ParamSchema); the editor inspector renders their fields; a pure runtime
|
|
5
|
+
* watches membership and dispatches to handlers.
|
|
6
|
+
*/
|
|
7
|
+
import { parseParams } from "./sceneKinds.js";
|
|
8
|
+
/** Reserved meta keys for the trigger vocabulary — action params use every other schema field. @internal */
|
|
9
|
+
export const TRIGGER_ON_KEY = "on";
|
|
10
|
+
/** @internal */
|
|
11
|
+
export const TRIGGER_ACTION_KEY = "action";
|
|
12
|
+
/** @internal */
|
|
13
|
+
export const TRIGGER_RADIUS_KEY = "triggerRadius";
|
|
14
|
+
/** @internal */
|
|
15
|
+
export const TRIGGER_LIST_KEY = "triggers";
|
|
16
|
+
const TRIGGER_EVENTS = ["enter", "exit", "interact"];
|
|
17
|
+
/** Default proximity radius (m) for marker enter/exit/interact when neither triggerRadius nor radius is set. @internal */
|
|
18
|
+
export const DEFAULT_TRIGGER_RADIUS = 2.5;
|
|
19
|
+
const actionRegistry = new Map();
|
|
20
|
+
/**
|
|
21
|
+
* Declare a game action the editor can assign to volume/marker triggers. Idempotent per `id`
|
|
22
|
+
* (last registration wins). Call at module load next to catalogs.
|
|
23
|
+
*
|
|
24
|
+
* @capability authored-triggers schema'd on/action vocabulary on volumes and markers with runtime dispatch
|
|
25
|
+
*/
|
|
26
|
+
export function registerTriggerAction(definition) {
|
|
27
|
+
actionRegistry.set(definition.id, definition);
|
|
28
|
+
}
|
|
29
|
+
/** Registered definition for an action id, or undefined when the game never declared it. */
|
|
30
|
+
export function getTriggerAction(id) {
|
|
31
|
+
return actionRegistry.get(id);
|
|
32
|
+
}
|
|
33
|
+
/** Every registered action, optionally filtered by target collection. */
|
|
34
|
+
export function listTriggerActions(target) {
|
|
35
|
+
const all = [...actionRegistry.values()];
|
|
36
|
+
if (target === undefined)
|
|
37
|
+
return all;
|
|
38
|
+
return all.filter((definition) => definition.targets === undefined || definition.targets.includes(target));
|
|
39
|
+
}
|
|
40
|
+
/** Clears the action registry — tests only. @internal */
|
|
41
|
+
export function clearTriggerActions() {
|
|
42
|
+
actionRegistry.clear();
|
|
43
|
+
}
|
|
44
|
+
function isTriggerEvent(value) {
|
|
45
|
+
return typeof value === "string" && TRIGGER_EVENTS.includes(value);
|
|
46
|
+
}
|
|
47
|
+
function metaNumber(meta, key) {
|
|
48
|
+
const value = meta?.[key];
|
|
49
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
50
|
+
}
|
|
51
|
+
/** Resolve the proximity radius for a marker trigger from meta. @internal */
|
|
52
|
+
export function triggerRadiusOf(meta, fallback = DEFAULT_TRIGGER_RADIUS) {
|
|
53
|
+
const explicit = metaNumber(meta, TRIGGER_RADIUS_KEY) ?? metaNumber(meta, "radius");
|
|
54
|
+
if (explicit === undefined)
|
|
55
|
+
return fallback;
|
|
56
|
+
return Math.max(0, explicit);
|
|
57
|
+
}
|
|
58
|
+
function specsFromMeta(meta) {
|
|
59
|
+
if (meta === undefined)
|
|
60
|
+
return [];
|
|
61
|
+
const list = meta[TRIGGER_LIST_KEY];
|
|
62
|
+
if (Array.isArray(list)) {
|
|
63
|
+
if (list.length === 0) {
|
|
64
|
+
// Empty multi-list is the inspector's "cleared" sentinel — fall through to flat on/action.
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const out = [];
|
|
68
|
+
for (const entry of list) {
|
|
69
|
+
if (typeof entry !== "object" || entry === null)
|
|
70
|
+
continue;
|
|
71
|
+
const row = entry;
|
|
72
|
+
if (!isTriggerEvent(row[TRIGGER_ON_KEY]))
|
|
73
|
+
continue;
|
|
74
|
+
const action = row[TRIGGER_ACTION_KEY];
|
|
75
|
+
if (typeof action !== "string" || action.length === 0)
|
|
76
|
+
continue;
|
|
77
|
+
out.push({ on: row[TRIGGER_ON_KEY], action, paramsMeta: row });
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (!isTriggerEvent(meta[TRIGGER_ON_KEY]))
|
|
83
|
+
return [];
|
|
84
|
+
const action = meta[TRIGGER_ACTION_KEY];
|
|
85
|
+
if (typeof action !== "string" || action.length === 0)
|
|
86
|
+
return [];
|
|
87
|
+
return [{ on: meta[TRIGGER_ON_KEY], action, paramsMeta: meta }];
|
|
88
|
+
}
|
|
89
|
+
function resolveParams(actionId, paramsMeta) {
|
|
90
|
+
const definition = actionRegistry.get(actionId);
|
|
91
|
+
if (definition === undefined)
|
|
92
|
+
return {};
|
|
93
|
+
return parseParams(definition.schema, paramsMeta);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Read every valid `on`/`action` binding off a raw meta bag. Unknown events/actions are dropped;
|
|
97
|
+
* params are schema-parsed when the action is registered, else empty.
|
|
98
|
+
* @internal
|
|
99
|
+
*/
|
|
100
|
+
export function readTriggerSpecs(meta) {
|
|
101
|
+
return specsFromMeta(meta).map((spec) => ({
|
|
102
|
+
on: spec.on,
|
|
103
|
+
action: spec.action,
|
|
104
|
+
params: resolveParams(spec.action, spec.paramsMeta),
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Collect every authored trigger on a document's markers and volumes. Pure — no runtime state.
|
|
109
|
+
* Action params use the live {@link registerTriggerAction} registry when present.
|
|
110
|
+
*
|
|
111
|
+
* @capability authored-triggers schema'd on/action vocabulary on volumes and markers with runtime dispatch
|
|
112
|
+
*/
|
|
113
|
+
export function collectAuthoredTriggers(document) {
|
|
114
|
+
const out = [];
|
|
115
|
+
for (const marker of document.markers) {
|
|
116
|
+
const radius = triggerRadiusOf(marker.meta);
|
|
117
|
+
for (const spec of readTriggerSpecs(marker.meta)) {
|
|
118
|
+
out.push({
|
|
119
|
+
sourceId: marker.id,
|
|
120
|
+
sourceKind: "marker",
|
|
121
|
+
objectKind: marker.kind,
|
|
122
|
+
on: spec.on,
|
|
123
|
+
action: spec.action,
|
|
124
|
+
params: spec.params,
|
|
125
|
+
radius,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
for (const volume of document.volumes) {
|
|
130
|
+
for (const spec of readTriggerSpecs(volume.meta)) {
|
|
131
|
+
out.push({
|
|
132
|
+
sourceId: volume.id,
|
|
133
|
+
sourceKind: "volume",
|
|
134
|
+
objectKind: volume.kind,
|
|
135
|
+
on: spec.on,
|
|
136
|
+
action: spec.action,
|
|
137
|
+
params: spec.params,
|
|
138
|
+
radius: 0,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* True when `point` is inside an editor volume (sphere / cylinder / box). Cylinder height defaults
|
|
146
|
+
* to diameter when omitted; sphere ignores y for the common ground-plane case only when the volume
|
|
147
|
+
* radius covers the full vertical span — here y is tested for sphere and box too.
|
|
148
|
+
*/
|
|
149
|
+
export function pointInVolume(volume, point) {
|
|
150
|
+
const dx = point.x - volume.center.x;
|
|
151
|
+
const dy = point.y - volume.center.y;
|
|
152
|
+
const dz = point.z - volume.center.z;
|
|
153
|
+
if (volume.shape === "box") {
|
|
154
|
+
const hx = volume.halfExtents?.x ?? 5;
|
|
155
|
+
const hy = volume.halfExtents?.y ?? 5;
|
|
156
|
+
const hz = volume.halfExtents?.z ?? 5;
|
|
157
|
+
return Math.abs(dx) <= hx && Math.abs(dy) <= hy && Math.abs(dz) <= hz;
|
|
158
|
+
}
|
|
159
|
+
const radius = volume.radius ?? 5;
|
|
160
|
+
if (volume.shape === "cylinder") {
|
|
161
|
+
const height = volume.height ?? radius * 2;
|
|
162
|
+
if (Math.hypot(dx, dz) > radius)
|
|
163
|
+
return false;
|
|
164
|
+
return Math.abs(dy) <= height / 2;
|
|
165
|
+
}
|
|
166
|
+
return Math.hypot(dx, dy, dz) <= radius;
|
|
167
|
+
}
|
|
168
|
+
/** True when `point` is within `radius` of a marker's position (sphere for enter/exit/interact). @internal */
|
|
169
|
+
export function pointNearMarker(marker, point, radius) {
|
|
170
|
+
const dx = point.x - marker.position.x;
|
|
171
|
+
const dy = point.y - marker.position.y;
|
|
172
|
+
const dz = point.z - marker.position.z;
|
|
173
|
+
return Math.hypot(dx, dy, dz) <= radius;
|
|
174
|
+
}
|
|
175
|
+
function membershipKey(sourceId, actorId) {
|
|
176
|
+
return `${sourceId}\0${actorId}`;
|
|
177
|
+
}
|
|
178
|
+
function actorPoint(actor) {
|
|
179
|
+
const p = actor.position;
|
|
180
|
+
if (Array.isArray(p))
|
|
181
|
+
return { x: p[0], y: p[1], z: p[2] };
|
|
182
|
+
return p;
|
|
183
|
+
}
|
|
184
|
+
function insideSource(document, trigger, point) {
|
|
185
|
+
if (trigger.sourceKind === "volume") {
|
|
186
|
+
const volume = document.volumes.find((entry) => entry.id === trigger.sourceId);
|
|
187
|
+
return volume !== undefined && pointInVolume(volume, point);
|
|
188
|
+
}
|
|
189
|
+
const marker = document.markers.find((entry) => entry.id === trigger.sourceId);
|
|
190
|
+
return marker !== undefined && pointNearMarker(marker, point, trigger.radius);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Build a runtime that watches a document's authored triggers against moving actors and dispatches
|
|
194
|
+
* to per-action handlers (and optional catch-all). Pure membership math; the game supplies actors
|
|
195
|
+
* each tick from its own player/entity poses.
|
|
196
|
+
*
|
|
197
|
+
* @capability authored-triggers schema'd on/action vocabulary on volumes and markers with runtime dispatch
|
|
198
|
+
*/
|
|
199
|
+
export function createAuthoredTriggerRuntime(options) {
|
|
200
|
+
const document = options.document;
|
|
201
|
+
const triggers = options.triggers ?? collectAuthoredTriggers(document);
|
|
202
|
+
let members = new Set();
|
|
203
|
+
const sourceIds = new Map();
|
|
204
|
+
for (const trigger of triggers) {
|
|
205
|
+
const list = sourceIds.get(trigger.sourceId) ?? [];
|
|
206
|
+
list.push(trigger);
|
|
207
|
+
sourceIds.set(trigger.sourceId, list);
|
|
208
|
+
}
|
|
209
|
+
function emit(events) {
|
|
210
|
+
for (const event of events) {
|
|
211
|
+
options.handlers?.[event.action]?.(event);
|
|
212
|
+
options.onDispatch?.(event);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
triggers: () => triggers,
|
|
217
|
+
reset() {
|
|
218
|
+
members = new Set();
|
|
219
|
+
},
|
|
220
|
+
step(input) {
|
|
221
|
+
const next = new Set();
|
|
222
|
+
const insideNow = new Map();
|
|
223
|
+
for (const actor of input.actors) {
|
|
224
|
+
const point = actorPoint(actor);
|
|
225
|
+
for (const [sourceId, sourceTriggers] of sourceIds) {
|
|
226
|
+
const probe = sourceTriggers[0];
|
|
227
|
+
if (!insideSource(document, probe, point))
|
|
228
|
+
continue;
|
|
229
|
+
const key = membershipKey(sourceId, actor.id);
|
|
230
|
+
next.add(key);
|
|
231
|
+
let set = insideNow.get(sourceId);
|
|
232
|
+
if (set === undefined) {
|
|
233
|
+
set = new Set();
|
|
234
|
+
insideNow.set(sourceId, set);
|
|
235
|
+
}
|
|
236
|
+
set.add(actor.id);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const events = [];
|
|
240
|
+
for (const [sourceId, actorsInside] of insideNow) {
|
|
241
|
+
const sourceTriggers = sourceIds.get(sourceId) ?? [];
|
|
242
|
+
for (const actorId of actorsInside) {
|
|
243
|
+
const key = membershipKey(sourceId, actorId);
|
|
244
|
+
const wasInside = members.has(key);
|
|
245
|
+
if (!wasInside) {
|
|
246
|
+
for (const trigger of sourceTriggers) {
|
|
247
|
+
if (trigger.on !== "enter")
|
|
248
|
+
continue;
|
|
249
|
+
events.push({
|
|
250
|
+
on: "enter",
|
|
251
|
+
action: trigger.action,
|
|
252
|
+
sourceId: trigger.sourceId,
|
|
253
|
+
sourceKind: trigger.sourceKind,
|
|
254
|
+
objectKind: trigger.objectKind,
|
|
255
|
+
actorId,
|
|
256
|
+
params: trigger.params,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
for (const key of members) {
|
|
263
|
+
if (next.has(key))
|
|
264
|
+
continue;
|
|
265
|
+
const sep = key.indexOf("\0");
|
|
266
|
+
const sourceId = key.slice(0, sep);
|
|
267
|
+
const actorId = key.slice(sep + 1);
|
|
268
|
+
for (const trigger of sourceIds.get(sourceId) ?? []) {
|
|
269
|
+
if (trigger.on !== "exit")
|
|
270
|
+
continue;
|
|
271
|
+
events.push({
|
|
272
|
+
on: "exit",
|
|
273
|
+
action: trigger.action,
|
|
274
|
+
sourceId: trigger.sourceId,
|
|
275
|
+
sourceKind: trigger.sourceKind,
|
|
276
|
+
objectKind: trigger.objectKind,
|
|
277
|
+
actorId,
|
|
278
|
+
params: trigger.params,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const interactActors = new Set(input.interact ?? []);
|
|
283
|
+
if (interactActors.size > 0) {
|
|
284
|
+
for (const actor of input.actors) {
|
|
285
|
+
if (!interactActors.has(actor.id))
|
|
286
|
+
continue;
|
|
287
|
+
const point = actorPoint(actor);
|
|
288
|
+
for (const sourceTriggers of sourceIds.values()) {
|
|
289
|
+
const probe = sourceTriggers[0];
|
|
290
|
+
if (!insideSource(document, probe, point))
|
|
291
|
+
continue;
|
|
292
|
+
for (const trigger of sourceTriggers) {
|
|
293
|
+
if (trigger.on !== "interact")
|
|
294
|
+
continue;
|
|
295
|
+
events.push({
|
|
296
|
+
on: "interact",
|
|
297
|
+
action: trigger.action,
|
|
298
|
+
sourceId: trigger.sourceId,
|
|
299
|
+
sourceKind: trigger.sourceKind,
|
|
300
|
+
objectKind: trigger.objectKind,
|
|
301
|
+
actorId: actor.id,
|
|
302
|
+
params: trigger.params,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
members = next;
|
|
309
|
+
emit(events);
|
|
310
|
+
return events;
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Build a meta patch that sets a single flat trigger (`on` + `action` + optional param fields) and
|
|
316
|
+
* clears a multi-trigger list if present. Used by the editor inspector.
|
|
317
|
+
* @internal
|
|
318
|
+
*/
|
|
319
|
+
export function triggerMetaPatch(on, action, params = {}) {
|
|
320
|
+
if (on === "" || action.length === 0) {
|
|
321
|
+
return { [TRIGGER_ON_KEY]: undefined, [TRIGGER_ACTION_KEY]: undefined, [TRIGGER_LIST_KEY]: undefined };
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
[TRIGGER_ON_KEY]: on,
|
|
325
|
+
[TRIGGER_ACTION_KEY]: action,
|
|
326
|
+
[TRIGGER_LIST_KEY]: undefined,
|
|
327
|
+
...params,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
/** Read the single flat trigger (`on`/`action`) from meta for the inspector, ignoring non-empty multi-lists. @internal */
|
|
331
|
+
export function readFlatTrigger(meta) {
|
|
332
|
+
if (meta === undefined)
|
|
333
|
+
return { on: "", action: "" };
|
|
334
|
+
const list = meta[TRIGGER_LIST_KEY];
|
|
335
|
+
if (Array.isArray(list) && list.length > 0)
|
|
336
|
+
return { on: "", action: "" };
|
|
337
|
+
const on = isTriggerEvent(meta[TRIGGER_ON_KEY]) ? meta[TRIGGER_ON_KEY] : "";
|
|
338
|
+
const action = typeof meta[TRIGGER_ACTION_KEY] === "string" ? meta[TRIGGER_ACTION_KEY] : "";
|
|
339
|
+
return { on, action };
|
|
340
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type PathFollowState, type PathProgress, type Waypoint } from "../nav/pathFollow.js";
|
|
2
|
+
import type { GameContext } from "../runtime/gameContext.js";
|
|
3
|
+
/** Whether a behavior instance advances and writes pose (`active`), is temporarily suspended retaining
|
|
4
|
+
* state (`paused`), or is held off until re-enabled (`disabled`). */
|
|
5
|
+
export type BehaviorStatus = "active" | "paused" | "disabled";
|
|
6
|
+
/**
|
|
7
|
+
* Catch-up policy applied when a paused instance resumes. `freeze` (default, deterministic) discards
|
|
8
|
+
* the time spent paused; `advance` silently fast-forwards the instance by the paused duration without
|
|
9
|
+
* emitting intermediate pose writes. Only patrol honors `advance`; wander treats it as `freeze`.
|
|
10
|
+
*/
|
|
11
|
+
export type BehaviorResumePolicy = "freeze" | "advance";
|
|
12
|
+
/** Serializable snapshot of one behavior instance — round-trips exactly through
|
|
13
|
+
* {@link BehaviorControl.serialize}/{@link BehaviorControl.restore}. */
|
|
14
|
+
export type BehaviorSnapshot = {
|
|
15
|
+
readonly kind: "patrol";
|
|
16
|
+
readonly state: PathFollowState;
|
|
17
|
+
} | {
|
|
18
|
+
readonly kind: "wander";
|
|
19
|
+
readonly origin: Waypoint;
|
|
20
|
+
readonly target: Waypoint | null;
|
|
21
|
+
};
|
|
22
|
+
/** Inspection readout for editor/debug tooling, from {@link BehaviorControl.inspect}/{@link BehaviorControl.list}. */
|
|
23
|
+
export interface BehaviorInspection {
|
|
24
|
+
id: string;
|
|
25
|
+
kind: "patrol" | "wander";
|
|
26
|
+
status: BehaviorStatus;
|
|
27
|
+
reason: string | null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Per-entity control surface for the behavior runtime — pause/resume/disable/enable an instance,
|
|
31
|
+
* seek it to semantic progress, serialize/restore its state, and inspect it, all keyed by stable
|
|
32
|
+
* entity id without a full-world scan. Obtain it with {@link behaviorControl}.
|
|
33
|
+
*/
|
|
34
|
+
export interface BehaviorControl {
|
|
35
|
+
/** Current status of the instance, or `null` if the entity has no live behavior. */
|
|
36
|
+
status(id: string): BehaviorStatus | null;
|
|
37
|
+
/** Human-readable reason attached to the last pause/disable, or `null`. */
|
|
38
|
+
reason(id: string): string | null;
|
|
39
|
+
/** Suspend advancement and pose writes, retaining state. No-op (`false`) if not active. */
|
|
40
|
+
pause(id: string, reason?: string): boolean;
|
|
41
|
+
/** Resume a paused instance, applying the catch-up `policy` (default `freeze`). */
|
|
42
|
+
resume(id: string, policy?: BehaviorResumePolicy): boolean;
|
|
43
|
+
/** Hold the instance off (no advance, no pose) until {@link enable}. Retains state. */
|
|
44
|
+
disable(id: string, reason?: string): boolean;
|
|
45
|
+
/** Re-activate a disabled instance from its retained state (no catch-up). */
|
|
46
|
+
enable(id: string): boolean;
|
|
47
|
+
/** Jump a patrol instance to semantic {@link PathProgress}. Returns `false` for non-patrol instances. */
|
|
48
|
+
seek(id: string, progress: PathProgress): boolean;
|
|
49
|
+
/** Capture the instance's exact serializable state, or `null` if absent. */
|
|
50
|
+
serialize(id: string): BehaviorSnapshot | null;
|
|
51
|
+
/** Restore an instance from a {@link BehaviorSnapshot} of the matching kind. */
|
|
52
|
+
restore(id: string, snapshot: BehaviorSnapshot): boolean;
|
|
53
|
+
/** Inspect one instance, or `null` if absent. */
|
|
54
|
+
inspect(id: string): BehaviorInspection | null;
|
|
55
|
+
/** Inspect every live instance (bounded by spawned behavior entities). */
|
|
56
|
+
list(): BehaviorInspection[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Advance every spawned entity carrying a `patrol` or `wander` {@link BehaviorDescriptor} one tick — the
|
|
60
|
+
* engine reads the descriptor, keeps the per-entity nav state itself, and poses the entity, so ambient
|
|
61
|
+
* traffic and idle NPC routes are register-once (attach the behavior at spawn) instead of a per-game
|
|
62
|
+
* per-frame `advancePathFollow` + `setPose` loop. Instances that are paused or disabled through
|
|
63
|
+
* {@link behaviorControl} retain their state and are skipped. The shell/host call this each frame; a game never does.
|
|
64
|
+
*
|
|
65
|
+
* @capability behavior-tick auto-advance patrol/wander behaviors on spawned entities, no per-game route loop
|
|
66
|
+
*/
|
|
67
|
+
export declare function advanceBehaviors(ctx: GameContext, dt: number): void;
|
|
68
|
+
/**
|
|
69
|
+
* Obtain the per-context {@link BehaviorControl} surface for suspending, resuming, seeking, serializing,
|
|
70
|
+
* and inspecting behavior instances by entity id — the lifecycle contract games use to hand pose
|
|
71
|
+
* ownership to possession/streaming/staggering code instead of bypassing the behavior runtime.
|
|
72
|
+
*
|
|
73
|
+
* @capability behavior-control pause/disable/resume/seek/inspect behavior instances per entity
|
|
74
|
+
*/
|
|
75
|
+
export declare function behaviorControl(ctx: GameContext): BehaviorControl;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { seededRng } from "../random/rng.js";
|
|
2
|
+
import { advancePathFollow, createPathFollow, pathFollowSeek, } from "../nav/pathFollow.js";
|
|
3
|
+
import { perContext } from "../runtime/perContext.js";
|
|
4
|
+
const DEFAULT_WANDER_SPEED = 1.5;
|
|
5
|
+
const WANDER_ARRIVAL = 0.6;
|
|
6
|
+
function patrolOf(entity) {
|
|
7
|
+
return entity.behaviors.find((b) => b.kind === "patrol") ?? null;
|
|
8
|
+
}
|
|
9
|
+
function wanderOf(entity) {
|
|
10
|
+
return entity.behaviors.find((b) => b.kind === "wander") ?? null;
|
|
11
|
+
}
|
|
12
|
+
const runtimeOf = perContext((ctx) => {
|
|
13
|
+
const nav = new Map();
|
|
14
|
+
const refresh = () => {
|
|
15
|
+
const live = new Set();
|
|
16
|
+
for (const entity of ctx.scene.entity.list()) {
|
|
17
|
+
live.add(entity.id);
|
|
18
|
+
if (nav.has(entity.id))
|
|
19
|
+
continue;
|
|
20
|
+
const patrol = patrolOf(entity);
|
|
21
|
+
if (patrol !== null) {
|
|
22
|
+
const config = { waypoints: patrol.waypoints, speed: patrol.speed, loop: patrol.loop };
|
|
23
|
+
nav.set(entity.id, {
|
|
24
|
+
kind: "patrol",
|
|
25
|
+
config,
|
|
26
|
+
state: patrol.startProgress !== undefined ? pathFollowSeek(config, patrol.startProgress) : createPathFollow(config),
|
|
27
|
+
groundClamp: patrol.groundClamp ?? false,
|
|
28
|
+
status: "active",
|
|
29
|
+
reason: null,
|
|
30
|
+
pausedElapsed: 0,
|
|
31
|
+
});
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const wander = wanderOf(entity);
|
|
35
|
+
if (wander !== null) {
|
|
36
|
+
nav.set(entity.id, {
|
|
37
|
+
kind: "wander",
|
|
38
|
+
radius: wander.radius,
|
|
39
|
+
origin: entity.position,
|
|
40
|
+
target: null,
|
|
41
|
+
roll: seededRng(`wander:${entity.id}`),
|
|
42
|
+
status: "active",
|
|
43
|
+
reason: null,
|
|
44
|
+
pausedElapsed: 0,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const id of nav.keys())
|
|
49
|
+
if (!live.has(id))
|
|
50
|
+
nav.delete(id);
|
|
51
|
+
};
|
|
52
|
+
ctx.scene.entity.subscribeMembership(refresh);
|
|
53
|
+
refresh();
|
|
54
|
+
return { nav };
|
|
55
|
+
});
|
|
56
|
+
function stepWander(ctx, id, nav, dt) {
|
|
57
|
+
const entity = ctx.scene.entity.get(id);
|
|
58
|
+
if (entity === null)
|
|
59
|
+
return;
|
|
60
|
+
const [px, , pz] = entity.position;
|
|
61
|
+
if (nav.target === null || Math.hypot(px - nav.target[0], pz - nav.target[2]) < WANDER_ARRIVAL) {
|
|
62
|
+
const angle = nav.roll() * Math.PI * 2;
|
|
63
|
+
const distance = Math.sqrt(nav.roll()) * nav.radius;
|
|
64
|
+
const tx = nav.origin[0] + Math.cos(angle) * distance;
|
|
65
|
+
const tz = nav.origin[2] + Math.sin(angle) * distance;
|
|
66
|
+
nav.target = [tx, ctx.world.groundHeightAt(tx, tz), tz];
|
|
67
|
+
}
|
|
68
|
+
const speed = entity.movement.walkSpeed ?? DEFAULT_WANDER_SPEED;
|
|
69
|
+
const dx = nav.target[0] - px;
|
|
70
|
+
const dz = nav.target[2] - pz;
|
|
71
|
+
const dist = Math.hypot(dx, dz);
|
|
72
|
+
if (dist < 1e-6)
|
|
73
|
+
return;
|
|
74
|
+
const step = Math.min(dist, speed * dt);
|
|
75
|
+
const nx = px + (dx / dist) * step;
|
|
76
|
+
const nz = pz + (dz / dist) * step;
|
|
77
|
+
ctx.scene.entity.setPose(id, {
|
|
78
|
+
position: [nx, ctx.world.groundHeightAt(nx, nz), nz],
|
|
79
|
+
rotationY: Math.atan2(dx, dz),
|
|
80
|
+
dt,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function posePatrol(ctx, id, nav, dt) {
|
|
84
|
+
const [x, y, z] = nav.state.position;
|
|
85
|
+
ctx.scene.entity.setPose(id, {
|
|
86
|
+
position: nav.groundClamp ? [x, ctx.world.groundHeightAt(x, z), z] : [x, y, z],
|
|
87
|
+
rotationY: nav.state.heading,
|
|
88
|
+
dt,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Advance every spawned entity carrying a `patrol` or `wander` {@link BehaviorDescriptor} one tick — the
|
|
93
|
+
* engine reads the descriptor, keeps the per-entity nav state itself, and poses the entity, so ambient
|
|
94
|
+
* traffic and idle NPC routes are register-once (attach the behavior at spawn) instead of a per-game
|
|
95
|
+
* per-frame `advancePathFollow` + `setPose` loop. Instances that are paused or disabled through
|
|
96
|
+
* {@link behaviorControl} retain their state and are skipped. The shell/host call this each frame; a game never does.
|
|
97
|
+
*
|
|
98
|
+
* @capability behavior-tick auto-advance patrol/wander behaviors on spawned entities, no per-game route loop
|
|
99
|
+
*/
|
|
100
|
+
export function advanceBehaviors(ctx, dt) {
|
|
101
|
+
if (dt <= 0)
|
|
102
|
+
return;
|
|
103
|
+
const { nav } = runtimeOf(ctx);
|
|
104
|
+
if (nav.size === 0)
|
|
105
|
+
return;
|
|
106
|
+
for (const [id, entry] of nav) {
|
|
107
|
+
if (entry.status !== "active") {
|
|
108
|
+
if (entry.status === "paused")
|
|
109
|
+
entry.pausedElapsed += dt;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (entry.kind === "patrol") {
|
|
113
|
+
entry.state = advancePathFollow(entry.config, entry.state, dt);
|
|
114
|
+
posePatrol(ctx, id, entry, dt);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
stepWander(ctx, id, entry, dt);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Obtain the per-context {@link BehaviorControl} surface for suspending, resuming, seeking, serializing,
|
|
123
|
+
* and inspecting behavior instances by entity id — the lifecycle contract games use to hand pose
|
|
124
|
+
* ownership to possession/streaming/staggering code instead of bypassing the behavior runtime.
|
|
125
|
+
*
|
|
126
|
+
* @capability behavior-control pause/disable/resume/seek/inspect behavior instances per entity
|
|
127
|
+
*/
|
|
128
|
+
export function behaviorControl(ctx) {
|
|
129
|
+
const { nav } = runtimeOf(ctx);
|
|
130
|
+
const setStatus = (id, status, reason) => {
|
|
131
|
+
const entry = nav.get(id);
|
|
132
|
+
if (entry === undefined)
|
|
133
|
+
return false;
|
|
134
|
+
entry.status = status;
|
|
135
|
+
entry.reason = reason;
|
|
136
|
+
return true;
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
status: (id) => nav.get(id)?.status ?? null,
|
|
140
|
+
reason: (id) => nav.get(id)?.reason ?? null,
|
|
141
|
+
pause: (id, reason) => {
|
|
142
|
+
const entry = nav.get(id);
|
|
143
|
+
if (entry === undefined || entry.status !== "active")
|
|
144
|
+
return false;
|
|
145
|
+
entry.status = "paused";
|
|
146
|
+
entry.reason = reason ?? null;
|
|
147
|
+
entry.pausedElapsed = 0;
|
|
148
|
+
return true;
|
|
149
|
+
},
|
|
150
|
+
resume: (id, policy = "freeze") => {
|
|
151
|
+
const entry = nav.get(id);
|
|
152
|
+
if (entry === undefined || entry.status !== "paused")
|
|
153
|
+
return false;
|
|
154
|
+
if (policy === "advance" && entry.kind === "patrol" && entry.pausedElapsed > 0) {
|
|
155
|
+
entry.state = advancePathFollow(entry.config, entry.state, entry.pausedElapsed);
|
|
156
|
+
// Emit a single final pose at the caught-up position (no intermediate writes).
|
|
157
|
+
posePatrol(ctx, id, entry, entry.pausedElapsed);
|
|
158
|
+
}
|
|
159
|
+
entry.status = "active";
|
|
160
|
+
entry.reason = null;
|
|
161
|
+
entry.pausedElapsed = 0;
|
|
162
|
+
return true;
|
|
163
|
+
},
|
|
164
|
+
disable: (id, reason) => setStatus(id, "disabled", reason ?? null),
|
|
165
|
+
enable: (id) => {
|
|
166
|
+
const entry = nav.get(id);
|
|
167
|
+
if (entry === undefined || entry.status !== "disabled")
|
|
168
|
+
return false;
|
|
169
|
+
entry.status = "active";
|
|
170
|
+
entry.reason = null;
|
|
171
|
+
entry.pausedElapsed = 0;
|
|
172
|
+
return true;
|
|
173
|
+
},
|
|
174
|
+
seek: (id, progress) => {
|
|
175
|
+
const entry = nav.get(id);
|
|
176
|
+
if (entry === undefined || entry.kind !== "patrol")
|
|
177
|
+
return false;
|
|
178
|
+
entry.state = pathFollowSeek(entry.config, progress);
|
|
179
|
+
return true;
|
|
180
|
+
},
|
|
181
|
+
serialize: (id) => {
|
|
182
|
+
const entry = nav.get(id);
|
|
183
|
+
if (entry === undefined)
|
|
184
|
+
return null;
|
|
185
|
+
if (entry.kind === "patrol")
|
|
186
|
+
return { kind: "patrol", state: { ...entry.state } };
|
|
187
|
+
return { kind: "wander", origin: [...entry.origin], target: entry.target === null ? null : [...entry.target] };
|
|
188
|
+
},
|
|
189
|
+
restore: (id, snapshot) => {
|
|
190
|
+
const entry = nav.get(id);
|
|
191
|
+
if (entry === undefined || entry.kind !== snapshot.kind)
|
|
192
|
+
return false;
|
|
193
|
+
if (entry.kind === "patrol" && snapshot.kind === "patrol") {
|
|
194
|
+
entry.state = { ...snapshot.state };
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
if (entry.kind === "wander" && snapshot.kind === "wander") {
|
|
198
|
+
entry.origin = [...snapshot.origin];
|
|
199
|
+
entry.target = snapshot.target === null ? null : [...snapshot.target];
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
203
|
+
},
|
|
204
|
+
inspect: (id) => {
|
|
205
|
+
const entry = nav.get(id);
|
|
206
|
+
if (entry === undefined)
|
|
207
|
+
return null;
|
|
208
|
+
return { id, kind: entry.kind, status: entry.status, reason: entry.reason };
|
|
209
|
+
},
|
|
210
|
+
list: () => {
|
|
211
|
+
const out = [];
|
|
212
|
+
for (const [id, entry] of nav)
|
|
213
|
+
out.push({ id, kind: entry.kind, status: entry.status, reason: entry.reason });
|
|
214
|
+
return out;
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ProximityPrompt } from "../interaction/proximityPrompt.js";
|
|
2
|
-
import type { Waypoint } from "../nav/pathFollow.js";
|
|
2
|
+
import type { PathProgress, Waypoint } from "../nav/pathFollow.js";
|
|
3
3
|
export interface WanderBehavior {
|
|
4
4
|
kind: "wander";
|
|
5
5
|
radius: number;
|
|
@@ -9,6 +9,16 @@ export interface PatrolBehavior {
|
|
|
9
9
|
waypoints: readonly Waypoint[];
|
|
10
10
|
speed: number;
|
|
11
11
|
loop: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Optional initial progress the follower is seeded at instead of waypoint zero — lets a fleet of
|
|
14
|
+
* route followers start at distributed phases. Round-trips through the behavior lifecycle seek/serialize.
|
|
15
|
+
*/
|
|
16
|
+
startProgress?: PathProgress;
|
|
17
|
+
/**
|
|
18
|
+
* Sample world ground height for the pose Y each tick, so a route authored in the XZ plane rides
|
|
19
|
+
* uneven terrain. Default false (waypoint Y is used verbatim).
|
|
20
|
+
*/
|
|
21
|
+
groundClamp?: boolean;
|
|
12
22
|
}
|
|
13
23
|
export interface PromptableBehavior {
|
|
14
24
|
kind: "promptable";
|
|
@@ -21,10 +31,12 @@ export type BehaviorDescriptor = WanderBehavior | PatrolBehavior | PromptableBeh
|
|
|
21
31
|
export declare function wander({ radius }: {
|
|
22
32
|
radius: number;
|
|
23
33
|
}): WanderBehavior;
|
|
24
|
-
export declare function patrol({ waypoints, speed, loop, }: {
|
|
34
|
+
export declare function patrol({ waypoints, speed, loop, startProgress, groundClamp, }: {
|
|
25
35
|
waypoints: readonly Waypoint[];
|
|
26
36
|
speed: number;
|
|
27
37
|
loop?: boolean;
|
|
38
|
+
startProgress?: PathProgress;
|
|
39
|
+
groundClamp?: boolean;
|
|
28
40
|
}): PatrolBehavior;
|
|
29
41
|
export declare function promptable(prompt: ProximityPrompt): PromptableBehavior;
|
|
30
42
|
export declare function talkable(dialogueId: string): PromptableBehavior;
|
package/dist/scene/behaviors.js
CHANGED
|
@@ -2,8 +2,13 @@ import { command, keybind, proximityPrompt, } from "../interaction/proximityProm
|
|
|
2
2
|
export function wander({ radius }) {
|
|
3
3
|
return { kind: "wander", radius };
|
|
4
4
|
}
|
|
5
|
-
export function patrol({ waypoints, speed, loop = true, }) {
|
|
6
|
-
|
|
5
|
+
export function patrol({ waypoints, speed, loop = true, startProgress, groundClamp, }) {
|
|
6
|
+
const behavior = { kind: "patrol", waypoints, speed, loop };
|
|
7
|
+
if (startProgress !== undefined)
|
|
8
|
+
behavior.startProgress = startProgress;
|
|
9
|
+
if (groundClamp !== undefined)
|
|
10
|
+
behavior.groundClamp = groundClamp;
|
|
11
|
+
return behavior;
|
|
7
12
|
}
|
|
8
13
|
export function promptable(prompt) {
|
|
9
14
|
return { kind: "promptable", prompt };
|