lecodes-sdk 0.19.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/README.md +114 -0
- package/dist/global.d.ts +503 -0
- package/dist/host.d.ts +61 -0
- package/dist/inject.js +4730 -0
- package/dist/types/animate/animate.d.ts +20 -0
- package/dist/types/animate/bezier.d.ts +2 -0
- package/dist/types/animate/easings.d.ts +21 -0
- package/dist/types/canvas/Canvas.d.ts +168 -0
- package/dist/types/core/Aspect.d.ts +171 -0
- package/dist/types/core/InspectorUI.d.ts +88 -0
- package/dist/types/core/StateMachine.d.ts +81 -0
- package/dist/types/core/color.d.ts +13 -0
- package/dist/types/core/compWrite.d.ts +11 -0
- package/dist/types/core/events.d.ts +11 -0
- package/dist/types/core/fields.d.ts +58 -0
- package/dist/types/core/registry.d.ts +7 -0
- package/dist/types/core/signals.d.ts +29 -0
- package/dist/types/core/time.d.ts +31 -0
- package/dist/types/g2/Camera2D.d.ts +19 -0
- package/dist/types/g2/CharacterController2D.d.ts +134 -0
- package/dist/types/g2/Node2D.d.ts +91 -0
- package/dist/types/g2/OneWay2D.d.ts +24 -0
- package/dist/types/g2/Physics2D.d.ts +147 -0
- package/dist/types/g2/Scene2D.d.ts +72 -0
- package/dist/types/g2/Shape2D.d.ts +58 -0
- package/dist/types/g2/Sprite.d.ts +51 -0
- package/dist/types/g2/SpriteAnimation.d.ts +50 -0
- package/dist/types/g2/SpriteSheet.d.ts +69 -0
- package/dist/types/g2/Texture2D.d.ts +16 -0
- package/dist/types/g2/Tilemap.d.ts +20 -0
- package/dist/types/g2/Tileset.d.ts +32 -0
- package/dist/types/g2/Trigger2D.d.ts +20 -0
- package/dist/types/g2/autotile.d.ts +133 -0
- package/dist/types/g2/cells.d.ts +14 -0
- package/dist/types/g2/defineScene2d.d.ts +141 -0
- package/dist/types/g2/groups2d.d.ts +16 -0
- package/dist/types/g2/loop.d.ts +4 -0
- package/dist/types/g2/scenarios2d.d.ts +30 -0
- package/dist/types/g2/touch.d.ts +2 -0
- package/dist/types/gl/Camera.d.ts +79 -0
- package/dist/types/gl/CameraPlace.d.ts +26 -0
- package/dist/types/gl/CharacterController.d.ts +98 -0
- package/dist/types/gl/Gearbox.d.ts +86 -0
- package/dist/types/gl/Geometry.d.ts +39 -0
- package/dist/types/gl/IK.d.ts +53 -0
- package/dist/types/gl/InstancedMesh.d.ts +46 -0
- package/dist/types/gl/Light.d.ts +73 -0
- package/dist/types/gl/Lightmap.d.ts +85 -0
- package/dist/types/gl/Locomotion.d.ts +279 -0
- package/dist/types/gl/Material.d.ts +100 -0
- package/dist/types/gl/Mesh.d.ts +33 -0
- package/dist/types/gl/Model.d.ts +53 -0
- package/dist/types/gl/NavAgent.d.ts +99 -0
- package/dist/types/gl/NavMesh.d.ts +169 -0
- package/dist/types/gl/Node.d.ts +99 -0
- package/dist/types/gl/Noise.d.ts +20 -0
- package/dist/types/gl/Particles.d.ts +277 -0
- package/dist/types/gl/Physics.d.ts +91 -0
- package/dist/types/gl/Plane.d.ts +19 -0
- package/dist/types/gl/Ragdoll.d.ts +86 -0
- package/dist/types/gl/Ray.d.ts +8 -0
- package/dist/types/gl/Scene.d.ts +221 -0
- package/dist/types/gl/Shape.d.ts +122 -0
- package/dist/types/gl/Terrain.d.ts +280 -0
- package/dist/types/gl/Texture.d.ts +27 -0
- package/dist/types/gl/Trigger.d.ts +10 -0
- package/dist/types/gl/Vehicle.d.ts +191 -0
- package/dist/types/gl/Wheel.d.ts +95 -0
- package/dist/types/gl/animation/AnimationClip.d.ts +60 -0
- package/dist/types/gl/animation/Animator.d.ts +219 -0
- package/dist/types/gl/animation/Layer.d.ts +31 -0
- package/dist/types/gl/animation/Loop.d.ts +17 -0
- package/dist/types/gl/animation/Playback.d.ts +36 -0
- package/dist/types/gl/animation/core.d.ts +367 -0
- package/dist/types/gl/controls.d.ts +19 -0
- package/dist/types/gl/physicsEvents.d.ts +1 -0
- package/dist/types/gl/scenarios.d.ts +98 -0
- package/dist/types/gl/state.d.ts +5 -0
- package/dist/types/gl/terrainMesh.d.ts +46 -0
- package/dist/types/gl/touch.d.ts +2 -0
- package/dist/types/inject.d.ts +123 -0
- package/dist/types/math/Mathf.d.ts +39 -0
- package/dist/types/math/mat4.d.ts +66 -0
- package/dist/types/math/quat.d.ts +53 -0
- package/dist/types/math/vec.d.ts +129 -0
- package/dist/types/net/codec.d.ts +25 -0
- package/dist/types/net/core.d.ts +106 -0
- package/dist/types/net/index.d.ts +80 -0
- package/dist/types/net/replication.d.ts +101 -0
- package/dist/types/plugins/camera.d.ts +25 -0
- package/dist/types/plugins/geolocation.d.ts +39 -0
- package/dist/types/plugins/oauth.d.ts +25 -0
- package/dist/types/plugins/permission.d.ts +1 -0
- package/dist/types/plugins/push.d.ts +46 -0
- package/dist/types/plugins/qr.d.ts +21 -0
- package/dist/types/plugins/service.d.ts +33 -0
- package/dist/types/runtime/app.d.ts +67 -0
- package/dist/types/runtime/appEvents.d.ts +7 -0
- package/dist/types/runtime/channel.d.ts +1 -0
- package/dist/types/runtime/clipboard.d.ts +7 -0
- package/dist/types/runtime/datetime.d.ts +80 -0
- package/dist/types/runtime/device.d.ts +126 -0
- package/dist/types/runtime/fetch.d.ts +31 -0
- package/dist/types/runtime/files.d.ts +33 -0
- package/dist/types/runtime/input.d.ts +121 -0
- package/dist/types/runtime/media.d.ts +46 -0
- package/dist/types/runtime/misc.d.ts +11 -0
- package/dist/types/runtime/net.d.ts +15 -0
- package/dist/types/runtime/rpc.d.ts +44 -0
- package/dist/types/runtime/service.d.ts +1 -0
- package/dist/types/runtime/share.d.ts +2 -0
- package/dist/types/runtime/storage.d.ts +5 -0
- package/dist/types/runtime/touch.d.ts +56 -0
- package/dist/types/scene/defineScene.d.ts +296 -0
- package/dist/types/scene/editorPlugins.d.ts +82 -0
- package/dist/types/scene/gizmos.d.ts +56 -0
- package/dist/types/scene/grammar.d.ts +56 -0
- package/dist/types/scene/level.d.ts +98 -0
- package/dist/types/scene/material.d.ts +76 -0
- package/dist/types/server/auth/appConfig.d.ts +16 -0
- package/dist/types/server/auth/global.d.ts +56 -0
- package/dist/types/server/auth/models.d.ts +164 -0
- package/dist/types/server/auth/types.d.ts +56 -0
- package/dist/types/server/channel.d.ts +28 -0
- package/dist/types/server/context.d.ts +27 -0
- package/dist/types/server/db/defineDb.d.ts +36 -0
- package/dist/types/server/db/fields.d.ts +146 -0
- package/dist/types/server/db/index.d.ts +6 -0
- package/dist/types/server/db/marci/query.d.ts +326 -0
- package/dist/types/server/db/types.d.ts +163 -0
- package/dist/types/server/errors.d.ts +8 -0
- package/dist/types/server/inject.d.ts +5 -0
- package/dist/types/ui/NativeView.d.ts +38 -0
- package/dist/types/ui/UI.d.ts +27 -0
- package/dist/types/ui/UIBottomSheet.d.ts +71 -0
- package/dist/types/ui/UIButton.d.ts +30 -0
- package/dist/types/ui/UIContainer.d.ts +33 -0
- package/dist/types/ui/UIImage.d.ts +35 -0
- package/dist/types/ui/UIInput.d.ts +110 -0
- package/dist/types/ui/UIModal.d.ts +70 -0
- package/dist/types/ui/UINode.d.ts +363 -0
- package/dist/types/ui/UIPager.d.ts +123 -0
- package/dist/types/ui/UIPopover.d.ts +39 -0
- package/dist/types/ui/UIScreen.d.ts +57 -0
- package/dist/types/ui/UIScrollable.d.ts +40 -0
- package/dist/types/ui/UISpacer.d.ts +9 -0
- package/dist/types/ui/UITabs.d.ts +96 -0
- package/dist/types/ui/UIText.d.ts +19 -0
- package/dist/types/ui/UIVideo.d.ts +28 -0
- package/dist/types/ui/UIVirtualizedList.d.ts +97 -0
- package/dist/types/ui/UIWidget.d.ts +65 -0
- package/dist/types/ui/fonts.d.ts +9 -0
- package/dist/types/ui/presentable.d.ts +68 -0
- package/dist/types/ui/router.d.ts +40 -0
- package/dist/types/ui/theme.d.ts +26 -0
- package/dist/types.json +1 -0
- package/package.json +46 -0
- package/prompts/2d.md +395 -0
- package/prompts/3d-scene-files.md +113 -0
- package/prompts/3d-scene.md +119 -0
- package/prompts/3d.md +303 -0
- package/prompts/README.md +142 -0
- package/prompts/ar.md +109 -0
- package/prompts/canvas.md +27 -0
- package/prompts/compose.ts +46 -0
- package/prompts/concept.md +49 -0
- package/prompts/core-design.md +75 -0
- package/prompts/core.md +264 -0
- package/prompts/design.md +218 -0
- package/prompts/dist/2d-game.md +1530 -0
- package/prompts/dist/3d-app.md +1672 -0
- package/prompts/dist/ar-app.md +1548 -0
- package/prompts/dist/concept.md +49 -0
- package/prompts/dist/design.md +498 -0
- package/prompts/dist/ui-app.md +1134 -0
- package/prompts/index.md +37 -0
- package/prompts/intake-prompt.md +33 -0
- package/prompts/namer-prompt.md +12 -0
- package/prompts/router-prompt.md +50 -0
- package/prompts/select.ts +111 -0
- package/prompts/ui-design.md +203 -0
- package/prompts/ui.md +803 -0
- package/src/animate/animate.ts +238 -0
- package/src/animate/bezier.ts +138 -0
- package/src/animate/easings.ts +126 -0
- package/src/bridges.d.ts +1345 -0
- package/src/canvas/Canvas.ts +305 -0
- package/src/compile/__tests__/assetIconMacro.test.ts +219 -0
- package/src/compile/__tests__/assetMacro.test.ts +74 -0
- package/src/compile/__tests__/assetName.test.ts +55 -0
- package/src/compile/__tests__/compile.test.ts +287 -0
- package/src/compile/__tests__/detectEntry.test.ts +132 -0
- package/src/compile/__tests__/fontMacro.test.ts +199 -0
- package/src/compile/aspectMacro.ts +86 -0
- package/src/compile/assetIconMacro.ts +384 -0
- package/src/compile/assetMacro.ts +146 -0
- package/src/compile/assetName.ts +50 -0
- package/src/compile/bundler.ts +287 -0
- package/src/compile/compileProject.ts +127 -0
- package/src/compile/detectEntry.ts +128 -0
- package/src/compile/fontMacro.ts +459 -0
- package/src/compile/fontRegistry.ts +78 -0
- package/src/compile/header.ts +67 -0
- package/src/compile/index.ts +100 -0
- package/src/compile/libraryImports.ts +52 -0
- package/src/compile/liteMaterial.ts +247 -0
- package/src/compile/sceneEditor.ts +88 -0
- package/src/compile/serverSplit.ts +233 -0
- package/src/compile/serverTypes.ts +227 -0
- package/src/compile/sfnt.ts +98 -0
- package/src/compile/shaderSchema.ts +202 -0
- package/src/compile/shaderTargets.ts +77 -0
- package/src/compile/sourcemap.ts +25 -0
- package/src/core/Aspect.ts +568 -0
- package/src/core/InspectorUI.ts +212 -0
- package/src/core/StateMachine.ts +308 -0
- package/src/core/__tests__/stateMachine.test.ts +132 -0
- package/src/core/color.ts +66 -0
- package/src/core/compWrite.ts +42 -0
- package/src/core/events.ts +38 -0
- package/src/core/fields.ts +120 -0
- package/src/core/registry.ts +23 -0
- package/src/core/signals.ts +277 -0
- package/src/core/time.ts +84 -0
- package/src/g2/Camera2D.ts +40 -0
- package/src/g2/CharacterController2D.ts +276 -0
- package/src/g2/Node2D.ts +267 -0
- package/src/g2/OneWay2D.ts +66 -0
- package/src/g2/Physics2D.ts +346 -0
- package/src/g2/Scene2D.ts +209 -0
- package/src/g2/Shape2D.ts +259 -0
- package/src/g2/Sprite.ts +89 -0
- package/src/g2/SpriteAnimation.ts +171 -0
- package/src/g2/SpriteSheet.ts +166 -0
- package/src/g2/Texture2D.ts +47 -0
- package/src/g2/Tilemap.ts +41 -0
- package/src/g2/Tileset.ts +71 -0
- package/src/g2/Trigger2D.ts +77 -0
- package/src/g2/autotile.ts +433 -0
- package/src/g2/cells.ts +91 -0
- package/src/g2/defineScene2d.ts +381 -0
- package/src/g2/groups2d.ts +106 -0
- package/src/g2/loop.ts +50 -0
- package/src/g2/scenarios2d.ts +69 -0
- package/src/g2/touch.ts +83 -0
- package/src/gl/Camera.ts +160 -0
- package/src/gl/CameraPlace.ts +52 -0
- package/src/gl/CharacterController.ts +238 -0
- package/src/gl/Gearbox.ts +212 -0
- package/src/gl/Geometry.ts +279 -0
- package/src/gl/IK.ts +193 -0
- package/src/gl/InstancedMesh.ts +132 -0
- package/src/gl/Light.ts +135 -0
- package/src/gl/Lightmap.ts +402 -0
- package/src/gl/Locomotion.ts +498 -0
- package/src/gl/Material.ts +279 -0
- package/src/gl/Mesh.ts +83 -0
- package/src/gl/Model.ts +124 -0
- package/src/gl/NavAgent.ts +337 -0
- package/src/gl/NavMesh.ts +397 -0
- package/src/gl/Node.ts +350 -0
- package/src/gl/Noise.ts +30 -0
- package/src/gl/Particles.ts +676 -0
- package/src/gl/Physics.ts +222 -0
- package/src/gl/Plane.ts +53 -0
- package/src/gl/Ragdoll.ts +270 -0
- package/src/gl/Ray.ts +16 -0
- package/src/gl/Scene.ts +505 -0
- package/src/gl/Shape.ts +409 -0
- package/src/gl/Terrain.ts +1092 -0
- package/src/gl/Texture.ts +63 -0
- package/src/gl/Trigger.ts +45 -0
- package/src/gl/Vehicle.ts +473 -0
- package/src/gl/Wheel.ts +240 -0
- package/src/gl/animation/AnimationClip.ts +204 -0
- package/src/gl/animation/Animator.ts +329 -0
- package/src/gl/animation/Layer.ts +39 -0
- package/src/gl/animation/Loop.ts +31 -0
- package/src/gl/animation/Playback.ts +52 -0
- package/src/gl/animation/core.ts +670 -0
- package/src/gl/controls.ts +95 -0
- package/src/gl/physicsEvents.ts +20 -0
- package/src/gl/scenarios.ts +291 -0
- package/src/gl/state.ts +6 -0
- package/src/gl/terrainMesh.ts +219 -0
- package/src/gl/touch.ts +68 -0
- package/src/host.d.ts +61 -0
- package/src/inject.ts +203 -0
- package/src/math/Mathf.ts +118 -0
- package/src/math/mat4.ts +278 -0
- package/src/math/quat.ts +232 -0
- package/src/math/vec.ts +255 -0
- package/src/net/codec.ts +119 -0
- package/src/net/core.ts +384 -0
- package/src/net/index.ts +181 -0
- package/src/net/replication.ts +622 -0
- package/src/plugins/camera.ts +81 -0
- package/src/plugins/geolocation.ts +123 -0
- package/src/plugins/oauth.ts +61 -0
- package/src/plugins/permission.ts +7 -0
- package/src/plugins/push.ts +132 -0
- package/src/plugins/qr.ts +73 -0
- package/src/plugins/service.ts +47 -0
- package/src/runtime/app.ts +101 -0
- package/src/runtime/appEvents.ts +54 -0
- package/src/runtime/channel.ts +61 -0
- package/src/runtime/clipboard.ts +20 -0
- package/src/runtime/datetime.ts +329 -0
- package/src/runtime/device.ts +293 -0
- package/src/runtime/fetch.ts +77 -0
- package/src/runtime/files.ts +108 -0
- package/src/runtime/input.ts +175 -0
- package/src/runtime/media.ts +111 -0
- package/src/runtime/misc.ts +16 -0
- package/src/runtime/net.ts +36 -0
- package/src/runtime/rpc.ts +218 -0
- package/src/runtime/service.ts +83 -0
- package/src/runtime/share.ts +9 -0
- package/src/runtime/storage.ts +13 -0
- package/src/runtime/touch.ts +76 -0
- package/src/scene/defineScene.ts +1396 -0
- package/src/scene/editorPlugins.ts +110 -0
- package/src/scene/gizmos.ts +148 -0
- package/src/scene/grammar.ts +120 -0
- package/src/scene/level.ts +296 -0
- package/src/scene/material.ts +188 -0
- package/src/server/auth/appConfig.ts +12 -0
- package/src/server/auth/global.ts +80 -0
- package/src/server/auth/host.ts +318 -0
- package/src/server/auth/models.ts +83 -0
- package/src/server/auth/types.ts +50 -0
- package/src/server/channel.ts +56 -0
- package/src/server/context.ts +36 -0
- package/src/server/db/defineDb.ts +237 -0
- package/src/server/db/fields.ts +132 -0
- package/src/server/db/httpTransport.ts +93 -0
- package/src/server/db/index.ts +7 -0
- package/src/server/db/marci/query.ts +412 -0
- package/src/server/db/types.ts +202 -0
- package/src/server/errors.ts +12 -0
- package/src/server/host.ts +74 -0
- package/src/server/inject.ts +13 -0
- package/src/server/runtime.ts +133 -0
- package/src/server/validate.ts +87 -0
- package/src/ui/NativeView.ts +142 -0
- package/src/ui/UI.ts +39 -0
- package/src/ui/UIBottomSheet.ts +139 -0
- package/src/ui/UIButton.ts +101 -0
- package/src/ui/UIContainer.ts +60 -0
- package/src/ui/UIImage.ts +83 -0
- package/src/ui/UIInput.ts +185 -0
- package/src/ui/UIModal.ts +139 -0
- package/src/ui/UINode.ts +830 -0
- package/src/ui/UIPager.ts +362 -0
- package/src/ui/UIPopover.ts +100 -0
- package/src/ui/UIScreen.ts +123 -0
- package/src/ui/UIScrollable.ts +87 -0
- package/src/ui/UISpacer.ts +14 -0
- package/src/ui/UITabs.ts +236 -0
- package/src/ui/UIText.ts +51 -0
- package/src/ui/UIVideo.ts +88 -0
- package/src/ui/UIVirtualizedList.ts +241 -0
- package/src/ui/UIWidget.ts +127 -0
- package/src/ui/fonts.ts +13 -0
- package/src/ui/presentable.ts +117 -0
- package/src/ui/router.ts +132 -0
- package/src/ui/theme.ts +84 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
// A navmesh agent, as an aspect on a 3D Node (docs/navmesh-plan.md §5). The GAME decides where it
|
|
2
|
+
// goes and when; DetourCrowd (creator-nav, one update per fixed step for the whole crowd) does the
|
|
3
|
+
// corridor, steering, path replanning and local avoidance; this aspect applies its slot to the node:
|
|
4
|
+
//
|
|
5
|
+
// const op = new Node().aspect(NavAgent, { radius: 0.4, speed: 3.2 })
|
|
6
|
+
// scene.add(op)
|
|
7
|
+
// op.agent.goTo(player.position) // false = nothing to walk on there
|
|
8
|
+
// op.agent.on('arrive', () => engage())
|
|
9
|
+
// if (op.agent.state === 'blocked') op.agent.goTo(nav.randomPoint(op.position, 8)!)
|
|
10
|
+
//
|
|
11
|
+
// Two ways to move the node (`drive`):
|
|
12
|
+
// • 'position' (default) — the crowd owns the transform: every host including headless, no
|
|
13
|
+
// physics. The node is placed on the navmesh surface (heights are quantized to the bake's
|
|
14
|
+
// cell height, 10 cm by default).
|
|
15
|
+
// • 'controller' — the node has a CharacterController: the crowd's velocity becomes its `move`
|
|
16
|
+
// command each fixed step, the capsule collides with everything, and the crowd slot is warped
|
|
17
|
+
// back to the body when they diverge (a push-back off the mesh is corrected by Detour itself).
|
|
18
|
+
// Facing turns toward the velocity at `turnSpeed` (0 = leave the rotation alone).
|
|
19
|
+
//
|
|
20
|
+
// Without a loaded NavMesh the aspect is inert — `goTo` returns false, nothing throws — so a
|
|
21
|
+
// project stays runnable on a host without navigation.
|
|
22
|
+
|
|
23
|
+
import { Aspect } from "../core/Aspect"
|
|
24
|
+
import type { FieldMeta } from "../core/fields"
|
|
25
|
+
import { Vec3, cx, cy, cz, type Vec3Like } from "../math/vec"
|
|
26
|
+
import { CharacterController } from "./CharacterController"
|
|
27
|
+
import { NavCrowd, NavMesh, NAV_AGENT, NAV_READ } from "./NavMesh"
|
|
28
|
+
import type { Node } from "./Node"
|
|
29
|
+
|
|
30
|
+
export type NavAgentState = "idle" | "moving" | "arrived" | "blocked" | "offmesh"
|
|
31
|
+
export type NavAgentAvoidance = "off" | "low" | "medium" | "high"
|
|
32
|
+
export type NavAgentDrive = "position" | "controller"
|
|
33
|
+
|
|
34
|
+
export type NavAgentEvents = {
|
|
35
|
+
/** Reached the target (within `stopDistance`). */
|
|
36
|
+
arrive: () => void
|
|
37
|
+
/** The target cannot be reached — the agent stopped at the closest point (or nowhere near). */
|
|
38
|
+
blocked: () => void
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const AVOIDANCE: Record<NavAgentAvoidance, number> = { off: -1, low: 0, medium: 1, high: 3 }
|
|
42
|
+
const DEG2RAD = Math.PI / 180
|
|
43
|
+
const JOIN_RETRY_STEPS = 30
|
|
44
|
+
|
|
45
|
+
export class NavAgent extends Aspect<"agent", Node, NavAgentEvents> {
|
|
46
|
+
static readonly aspect = "agent"
|
|
47
|
+
/** The crowd advances first, then every agent applies its slot. */
|
|
48
|
+
static after = [ NavCrowd ]
|
|
49
|
+
|
|
50
|
+
static fields: FieldMeta<NavAgent> = {
|
|
51
|
+
radius: { min: 0.05, max: 5, step: 0.05 },
|
|
52
|
+
height: { min: 0.1, max: 10, step: 0.1 },
|
|
53
|
+
speed: { min: 0, max: 50, step: 0.1 },
|
|
54
|
+
acceleration: { min: 0.1, max: 200, step: 0.5 },
|
|
55
|
+
turnSpeed: { min: 0, max: 3600, step: 10 },
|
|
56
|
+
separation: { min: 0, max: 10, step: 0.1 },
|
|
57
|
+
stopDistance: { min: 0, max: 10, step: 0.05 },
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private _radius = 0.4
|
|
61
|
+
private _height = 1.8
|
|
62
|
+
private _speed = 3
|
|
63
|
+
private _acceleration = 8
|
|
64
|
+
private _avoidance: NavAgentAvoidance = "medium"
|
|
65
|
+
private _separation = 2
|
|
66
|
+
private _include: string[] | undefined
|
|
67
|
+
private _exclude: string[] | undefined
|
|
68
|
+
/** deg/s the node turns toward its velocity; 0 = never touch the rotation. */
|
|
69
|
+
turnSpeed = 540
|
|
70
|
+
/** How the node follows its slot. */
|
|
71
|
+
drive: NavAgentDrive = "position"
|
|
72
|
+
/** Reached = within this many metres (along the corridor) of the target. */
|
|
73
|
+
stopDistance = 0.3
|
|
74
|
+
|
|
75
|
+
/** Agent radius (metres). Defaults to the navmesh's. */
|
|
76
|
+
get radius(): number { return this._radius }
|
|
77
|
+
set radius(v: number) { this._radius = v; this._dirty = true }
|
|
78
|
+
get height(): number { return this._height }
|
|
79
|
+
set height(v: number) { this._height = v; this._dirty = true }
|
|
80
|
+
/** Top speed (m/s). */
|
|
81
|
+
get speed(): number { return this._speed }
|
|
82
|
+
set speed(v: number) { this._speed = v; this._dirty = true }
|
|
83
|
+
get acceleration(): number { return this._acceleration }
|
|
84
|
+
set acceleration(v: number) { this._acceleration = v; this._dirty = true }
|
|
85
|
+
/** Local (agent-vs-agent) avoidance quality. */
|
|
86
|
+
get avoidance(): NavAgentAvoidance { return this._avoidance }
|
|
87
|
+
set avoidance(v: NavAgentAvoidance) { this._avoidance = v; this._dirty = true }
|
|
88
|
+
/** Separation force weight (0 = none). */
|
|
89
|
+
get separation(): number { return this._separation }
|
|
90
|
+
set separation(v: number) { this._separation = v; this._dirty = true }
|
|
91
|
+
/** Area names this agent may walk (default: all). */
|
|
92
|
+
get include(): string[] | undefined { return this._include }
|
|
93
|
+
set include(v: string[] | undefined) { this._include = v; this._dirty = true }
|
|
94
|
+
/** Area names this agent never enters. */
|
|
95
|
+
get exclude(): string[] | undefined { return this._exclude }
|
|
96
|
+
set exclude(v: string[] | undefined) { this._exclude = v; this._dirty = true }
|
|
97
|
+
|
|
98
|
+
state: NavAgentState = "idle"
|
|
99
|
+
/** The current velocity after avoidance (m/s). */
|
|
100
|
+
readonly velocity = new Vec3(0, 0, 0)
|
|
101
|
+
/** The velocity the corridor asked for, before avoidance. */
|
|
102
|
+
readonly desiredVelocity = new Vec3(0, 0, 0)
|
|
103
|
+
/** Metres left along the corridor (-1 = no target). */
|
|
104
|
+
remainingDistance = -1
|
|
105
|
+
/** Where the agent is going, or null. */
|
|
106
|
+
get target(): Vec3 | null { return this._target }
|
|
107
|
+
get hasPath(): boolean { return this._target !== null }
|
|
108
|
+
|
|
109
|
+
private _crowd: NavCrowd | null = null
|
|
110
|
+
private _slot = -1
|
|
111
|
+
private _target: Vec3 | null = null
|
|
112
|
+
/** velocity-driven (`move`) rather than target-driven */
|
|
113
|
+
private _steering = false
|
|
114
|
+
private _dirty = false
|
|
115
|
+
private _faceX = 0
|
|
116
|
+
private _faceZ = -1
|
|
117
|
+
private _retryAt = 0
|
|
118
|
+
private _lastSeen = -1
|
|
119
|
+
private _still = 0
|
|
120
|
+
private _near = 0
|
|
121
|
+
private _slow = 0
|
|
122
|
+
|
|
123
|
+
onAttach(): void {
|
|
124
|
+
this.state = "idle"
|
|
125
|
+
this._join()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
onReconfigure(): void { this._dirty = true }
|
|
129
|
+
|
|
130
|
+
onDetach(): void {
|
|
131
|
+
this._leave()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Walk to a point. False = no walkable polygon near it (or no navmesh) — the current target stays. */
|
|
135
|
+
goTo(target: Vec3Like): boolean {
|
|
136
|
+
if (this._slot < 0 && !this._join()) return false
|
|
137
|
+
const ok = _creatorNav.crowdSetTarget(this._crowd!._id, this._slot, cx(target), cy(target), cz(target))
|
|
138
|
+
if (!ok) return false
|
|
139
|
+
this._target = new Vec3(cx(target), cy(target), cz(target))
|
|
140
|
+
this._steering = false
|
|
141
|
+
this.state = "moving"
|
|
142
|
+
this._still = 0
|
|
143
|
+
this._near = 0
|
|
144
|
+
this._slow = 0
|
|
145
|
+
return true
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Drop the target and decelerate to a stop. */
|
|
149
|
+
stop(): void {
|
|
150
|
+
if (this._slot >= 0) _creatorNav.crowdResetTarget(this._crowd!._id, this._slot)
|
|
151
|
+
this._target = null
|
|
152
|
+
this._steering = false
|
|
153
|
+
this.remainingDistance = -1
|
|
154
|
+
this.state = "idle"
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Steer by velocity instead of a target — a player on WASD, a scripted push: the crowd keeps
|
|
159
|
+
* the node on the mesh and avoids the other agents, no path and no arrival. Call it every fixed
|
|
160
|
+
* step (the last velocity holds until the next call); `move(0, 0)` stops. Cancels `goTo`.
|
|
161
|
+
* False = no navmesh / off the mesh.
|
|
162
|
+
*/
|
|
163
|
+
move(vx: number, vz: number): boolean {
|
|
164
|
+
if (this._slot < 0 && !this._join()) return false
|
|
165
|
+
this._target = null
|
|
166
|
+
this.remainingDistance = -1
|
|
167
|
+
if (vx === 0 && vz === 0) {
|
|
168
|
+
if (this._steering) { _creatorNav.crowdResetTarget(this._crowd!._id, this._slot); this._steering = false }
|
|
169
|
+
this.state = "idle"
|
|
170
|
+
return true
|
|
171
|
+
}
|
|
172
|
+
_creatorNav.crowdSetVelocity(this._crowd!._id, this._slot, vx, 0, vz)
|
|
173
|
+
this._steering = true
|
|
174
|
+
this.state = "moving"
|
|
175
|
+
return true
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Teleport (a spawn, a respawn). The target, if any, is kept. */
|
|
179
|
+
warp(p: Vec3Like): void {
|
|
180
|
+
this.node.position = [ cx(p), cy(p), cz(p) ]
|
|
181
|
+
if (this._slot >= 0 && !_creatorNav.crowdWarp(this._crowd!._id, this._slot, cx(p), cy(p), cz(p))) {
|
|
182
|
+
// off the mesh now — leave the crowd and re-join when it is back on
|
|
183
|
+
this._leave()
|
|
184
|
+
this._retryAt = 0
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private params(): Float32Array {
|
|
189
|
+
const p = new Float32Array(NAV_AGENT.COUNT)
|
|
190
|
+
const mesh = this._crowd?._mesh
|
|
191
|
+
p[NAV_AGENT.RADIUS] = this._radius
|
|
192
|
+
p[NAV_AGENT.HEIGHT] = this._height
|
|
193
|
+
p[NAV_AGENT.MAX_SPEED] = this._speed
|
|
194
|
+
p[NAV_AGENT.MAX_ACCELERATION] = this._acceleration
|
|
195
|
+
p[NAV_AGENT.COLLISION_QUERY_RANGE] = 0
|
|
196
|
+
p[NAV_AGENT.PATH_OPTIMIZATION_RANGE] = 0
|
|
197
|
+
p[NAV_AGENT.SEPARATION_WEIGHT] = this._separation
|
|
198
|
+
p[NAV_AGENT.AVOIDANCE] = AVOIDANCE[this._avoidance] ?? 1
|
|
199
|
+
p[NAV_AGENT.INCLUDE_FLAGS] = mesh ? mesh.flags(this._include) : 0xffff
|
|
200
|
+
p[NAV_AGENT.EXCLUDE_FLAGS] = mesh && this._exclude ? mesh.flags(this._exclude) : 0
|
|
201
|
+
p[NAV_AGENT.ANTICIPATE_TURNS] = 1
|
|
202
|
+
p[NAV_AGENT.OPTIMIZE_VIS] = 1
|
|
203
|
+
p[NAV_AGENT.OPTIMIZE_TOPO] = 1
|
|
204
|
+
return p
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** @internal Register with the active navmesh's crowd. False = no navmesh / off the mesh. */
|
|
208
|
+
_join(): boolean {
|
|
209
|
+
const mesh = NavMesh.active
|
|
210
|
+
if (!mesh || typeof _creatorNav === "undefined") return false
|
|
211
|
+
const crowd = mesh._crowd()
|
|
212
|
+
if (!crowd._ensureCapacity()) return false
|
|
213
|
+
if (mesh._maxRadius < this._radius) mesh._maxRadius = this._radius
|
|
214
|
+
const p = this.node.worldPosition
|
|
215
|
+
const slot = _creatorNav.crowdAdd(crowd._id, p.x, p.y, p.z, this.params())
|
|
216
|
+
if (slot < 0) { this._retryAt = crowd._step + JOIN_RETRY_STEPS; return false }
|
|
217
|
+
this._crowd = crowd
|
|
218
|
+
this._slot = slot
|
|
219
|
+
this._dirty = false
|
|
220
|
+
this._lastSeen = -1
|
|
221
|
+
crowd._agents.add(this)
|
|
222
|
+
if (this._target && !_creatorNav.crowdSetTarget(crowd._id, slot, this._target.x, this._target.y, this._target.z)) this._target = null
|
|
223
|
+
return true
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** @internal The crowd was re-created (capacity grew): take a fresh slot, keep the target. */
|
|
227
|
+
_rejoin(): void {
|
|
228
|
+
const crowd = this._crowd
|
|
229
|
+
if (!crowd) return
|
|
230
|
+
const p = this.node.worldPosition
|
|
231
|
+
const slot = _creatorNav.crowdAdd(crowd._id, p.x, p.y, p.z, this.params())
|
|
232
|
+
this._slot = slot
|
|
233
|
+
if (slot >= 0 && this._target) _creatorNav.crowdSetTarget(crowd._id, slot, this._target.x, this._target.y, this._target.z)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** @internal Leave the crowd (detach, navmesh disposal). */
|
|
237
|
+
_leave(): void {
|
|
238
|
+
if (this._crowd && this._slot >= 0 && typeof _creatorNav !== "undefined" && this._crowd._id) {
|
|
239
|
+
_creatorNav.crowdRemove(this._crowd._id, this._slot)
|
|
240
|
+
}
|
|
241
|
+
this._crowd?._agents.delete(this)
|
|
242
|
+
this._crowd = null
|
|
243
|
+
this._slot = -1
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
updateFixed(dt: number): void {
|
|
247
|
+
if (this._slot < 0) {
|
|
248
|
+
// no crowd yet (the navmesh loaded after the attach, or the spawn was off the mesh): retry
|
|
249
|
+
if (NavMesh.active && (this._crowd === null ? true : this._crowd._step >= this._retryAt)) {
|
|
250
|
+
if (!this._join()) this._retryAt = (NavMesh.active._crowd()._step) + JOIN_RETRY_STEPS
|
|
251
|
+
}
|
|
252
|
+
return
|
|
253
|
+
}
|
|
254
|
+
const crowd = this._crowd!
|
|
255
|
+
if (crowd._mesh !== NavMesh.active) { this._leave(); return }
|
|
256
|
+
if (this._dirty) { this._dirty = false; _creatorNav.crowdSetParams(crowd._id, this._slot, this.params()) }
|
|
257
|
+
if (crowd._step === this._lastSeen) return // the crowd has not advanced since (a frame with no step)
|
|
258
|
+
this._lastSeen = crowd._step
|
|
259
|
+
const b = crowd._buf
|
|
260
|
+
const o = this._slot * NAV_READ.STRIDE
|
|
261
|
+
const st = b[o + NAV_READ.STATE]!
|
|
262
|
+
if (st === 0) { this._leave(); return }
|
|
263
|
+
const px = b[o + NAV_READ.POS_X]!, py = b[o + NAV_READ.POS_Y]!, pz = b[o + NAV_READ.POS_Z]!
|
|
264
|
+
const vx = b[o + NAV_READ.VEL_X]!, vy = b[o + NAV_READ.VEL_Y]!, vz = b[o + NAV_READ.VEL_Z]!
|
|
265
|
+
this.velocity.x = vx; this.velocity.y = vy; this.velocity.z = vz
|
|
266
|
+
this.desiredVelocity.x = b[o + NAV_READ.DVEL_X]!; this.desiredVelocity.y = b[o + NAV_READ.DVEL_Y]!; this.desiredVelocity.z = b[o + NAV_READ.DVEL_Z]!
|
|
267
|
+
const remaining = b[o + NAV_READ.REMAINING]!
|
|
268
|
+
this.remainingDistance = remaining
|
|
269
|
+
|
|
270
|
+
// the node
|
|
271
|
+
const node = this.node
|
|
272
|
+
if (this.drive === "controller") {
|
|
273
|
+
const cc = node.get(CharacterController)
|
|
274
|
+
if (cc) {
|
|
275
|
+
cc.move(vx, vz)
|
|
276
|
+
// the body is the truth: re-sync the slot when the capsule ended up elsewhere
|
|
277
|
+
const wp = node.worldPosition
|
|
278
|
+
const dx = wp.x - px, dz = wp.z - pz
|
|
279
|
+
if (dx * dx + dz * dz > this._radius * this._radius * 0.25) _creatorNav.crowdWarp(crowd._id, this._slot, wp.x, wp.y, wp.z)
|
|
280
|
+
} else {
|
|
281
|
+
node.position = [ px, py, pz ]
|
|
282
|
+
}
|
|
283
|
+
} else {
|
|
284
|
+
node.position = [ px, py, pz ]
|
|
285
|
+
}
|
|
286
|
+
if (this.turnSpeed > 0) this.face(vx, vz, dt)
|
|
287
|
+
|
|
288
|
+
// the state machine — arrival / blocked are decided here, in JS. A crowd never lets everyone
|
|
289
|
+
// reach the same point: the first agent stops ON it and avoidance holds the rest jostling in a
|
|
290
|
+
// ring around it — so a second spent within a few radii of the goal counts as arrived, and
|
|
291
|
+
// standing still anywhere else for 3 s (a jam, a door that closed) counts as blocked.
|
|
292
|
+
if (this._target) {
|
|
293
|
+
const ts = b[o + NAV_READ.TARGET_STATE]!
|
|
294
|
+
const partial = b[o + NAV_READ.PARTIAL]! > 0.5
|
|
295
|
+
const speed = Math.hypot(vx, vz)
|
|
296
|
+
if (ts === 1) {
|
|
297
|
+
this.finish("blocked")
|
|
298
|
+
} else if (ts === 2 && remaining >= 0 && remaining <= this.stopDistance) {
|
|
299
|
+
this.finish(partial ? "blocked" : "arrived")
|
|
300
|
+
} else {
|
|
301
|
+
// near = a few radii out (the first ring); slow-near = creeping in the outer rings of a big crowd
|
|
302
|
+
const r = this._radius
|
|
303
|
+
const valid = ts === 2 && remaining >= 0
|
|
304
|
+
this._near = valid && remaining <= this.stopDistance + r * 8 ? this._near + 1 : 0
|
|
305
|
+
this._slow = valid && remaining <= this.stopDistance + r * 16 && speed < 0.7 ? this._slow + 1 : 0
|
|
306
|
+
this._still = speed < 0.15 ? this._still + 1 : 0
|
|
307
|
+
if (this._near >= 60 || this._slow >= 120) this.finish(partial ? "blocked" : "arrived")
|
|
308
|
+
else if (this._still >= 180) this.finish("blocked")
|
|
309
|
+
else this.state = st === 3 ? "offmesh" : "moving"
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
private finish(state: "arrived" | "blocked"): void {
|
|
315
|
+
_creatorNav.crowdResetTarget(this._crowd!._id, this._slot)
|
|
316
|
+
this._target = null
|
|
317
|
+
this.state = state
|
|
318
|
+
this.remainingDistance = 0
|
|
319
|
+
this.emit(state === "arrived" ? "arrive" : "blocked")
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private face(vx: number, vz: number, dt: number): void {
|
|
323
|
+
const speed = Math.hypot(vx, vz)
|
|
324
|
+
if (speed < 0.05) return
|
|
325
|
+
const a0 = Math.atan2(this._faceX, this._faceZ)
|
|
326
|
+
const a1 = Math.atan2(vx / speed, vz / speed)
|
|
327
|
+
let delta = a1 - a0
|
|
328
|
+
while (delta > Math.PI) delta -= 2 * Math.PI
|
|
329
|
+
while (delta < -Math.PI) delta += 2 * Math.PI
|
|
330
|
+
const max = this.turnSpeed * DEG2RAD * dt
|
|
331
|
+
const a = a0 + Math.max(-max, Math.min(max, delta))
|
|
332
|
+
this._faceX = Math.sin(a)
|
|
333
|
+
this._faceZ = Math.cos(a)
|
|
334
|
+
const p = this.node.position
|
|
335
|
+
this.node.lookAt([ cx(p) + this._faceX, cy(p), cz(p) + this._faceZ ], "-z")
|
|
336
|
+
}
|
|
337
|
+
}
|