lecodes-cli 0.19.0 → 0.20.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.
Files changed (270) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +1069 -396
  3. package/package.json +14 -13
  4. package/runtime/scene-harness.json +1 -1
  5. package/runtime/sdk-types.json +1 -1
  6. package/runtime/web/assets/Roboto-Variable-DHm9jpd-.woff2 +0 -0
  7. package/runtime/web/assets/__vite-browser-external-BIHI7g3E.js +1 -0
  8. package/runtime/web/assets/basis-C64VHDVD.js +1 -0
  9. package/runtime/web/assets/basis_transcoder-VXdx5NbI.wasm +0 -0
  10. package/runtime/web/assets/createViewerLite-BvHobVhp.js +852 -0
  11. package/runtime/web/assets/draco-BiISTFcR.js +118 -0
  12. package/runtime/web/assets/draco_decoder-DsQ12WqX.wasm +0 -0
  13. package/runtime/web/assets/index-CfNCCBjN.js +2 -0
  14. package/runtime/web/assets/mapViewImpl-B2JcES8l.js +810 -0
  15. package/runtime/web/assets/maplibre-gl-worker-CJfwIrte.js +8 -0
  16. package/runtime/web/assets/neutral_ibl128-D-lzdkLN.ktx +0 -0
  17. package/runtime/web/assets/worker-Caf-yYEI.js +2 -0
  18. package/runtime/web/embed.html +32 -0
  19. package/runtime/web/embed.js +171 -0
  20. package/src/api.ts +302 -0
  21. package/src/browserAuth.ts +87 -0
  22. package/src/cmgenTool.ts +104 -0
  23. package/src/commands/app.ts +896 -0
  24. package/src/commands/appAndroid.ts +603 -0
  25. package/src/commands/appDesktop.ts +339 -0
  26. package/src/commands/appDesktopMac.ts +470 -0
  27. package/src/commands/appIcon.ts +187 -0
  28. package/src/commands/appShared.ts +542 -0
  29. package/src/commands/appTemplates.ts +907 -0
  30. package/src/commands/appTemplatesAndroid.ts +599 -0
  31. package/src/commands/appTemplatesGradlew.ts +9 -0
  32. package/src/commands/assets.ts +28 -0
  33. package/src/commands/clone.ts +60 -0
  34. package/src/commands/compile.ts +253 -0
  35. package/src/commands/create.ts +59 -0
  36. package/src/commands/design.ts +863 -0
  37. package/src/commands/designTemplates.ts +11 -0
  38. package/src/commands/desktop.ts +127 -0
  39. package/src/commands/dev.ts +236 -0
  40. package/src/commands/diff.ts +59 -0
  41. package/src/commands/init.ts +191 -0
  42. package/src/commands/install.ts +198 -0
  43. package/src/commands/lightmap.ts +290 -0
  44. package/src/commands/link.ts +147 -0
  45. package/src/commands/login.ts +24 -0
  46. package/src/commands/navmesh.ts +225 -0
  47. package/src/commands/pn.ts +305 -0
  48. package/src/commands/projectTemplates.ts +130 -0
  49. package/src/commands/pull.ts +109 -0
  50. package/src/commands/push.ts +173 -0
  51. package/src/commands/render.ts +416 -0
  52. package/src/commands/scene.ts +148 -0
  53. package/src/commands/shaders.ts +157 -0
  54. package/src/commands/status.ts +29 -0
  55. package/src/commands/test.ts +371 -0
  56. package/src/commands/thumbs.ts +178 -0
  57. package/src/commands/types.ts +87 -0
  58. package/src/commands/update.ts +190 -0
  59. package/src/compile/assetIcons.ts +214 -0
  60. package/src/compile/collect.ts +46 -0
  61. package/src/compile/collectLocal.ts +37 -0
  62. package/src/compile/designCompile.ts +104 -0
  63. package/src/compile/fonts.ts +156 -0
  64. package/src/compile/headlessBundle.ts +129 -0
  65. package/src/compile/nativeStack.ts +21 -0
  66. package/src/compile/projectCompile.ts +109 -0
  67. package/src/compile/sceneCompile.ts +113 -0
  68. package/src/compile/screenEntry.ts +127 -0
  69. package/src/compile/shaders.ts +245 -0
  70. package/src/config.ts +42 -0
  71. package/src/designMeta.ts +35 -0
  72. package/src/desktopRenderer.ts +545 -0
  73. package/src/desktopScript.ts +276 -0
  74. package/src/dev/clientTemplates.ts +160 -0
  75. package/src/dev/devServer.ts +333 -0
  76. package/src/dev/webRunner.ts +22 -0
  77. package/src/dev/wsServer.ts +144 -0
  78. package/src/distRoot.ts +20 -0
  79. package/src/ignore.ts +163 -0
  80. package/src/index.ts +494 -0
  81. package/src/lecodes-3d-editor.d.ts +41 -0
  82. package/src/lecodes-assets.d.ts +7 -0
  83. package/src/lecodes-design.d.ts +191 -0
  84. package/src/lecodes-renderer.d.ts +131 -0
  85. package/src/localFiles.ts +144 -0
  86. package/src/manifest.ts +46 -0
  87. package/src/matcTool.ts +137 -0
  88. package/src/peers.ts +40 -0
  89. package/src/project.ts +61 -0
  90. package/src/projectEnv.ts +94 -0
  91. package/src/qrcode-terminal.d.ts +9 -0
  92. package/src/releases.ts +125 -0
  93. package/src/serverDiff.ts +78 -0
  94. package/src/textDiff.ts +103 -0
  95. package/src/types.ts +0 -0
  96. package/src/util.ts +146 -0
  97. package/runtime/sdk/animate/animate.ts +0 -238
  98. package/runtime/sdk/animate/bezier.ts +0 -138
  99. package/runtime/sdk/animate/easings.ts +0 -126
  100. package/runtime/sdk/canvas/Canvas.ts +0 -305
  101. package/runtime/sdk/compile/aspectMacro.ts +0 -86
  102. package/runtime/sdk/compile/assetIconMacro.ts +0 -384
  103. package/runtime/sdk/compile/assetMacro.ts +0 -146
  104. package/runtime/sdk/compile/assetName.ts +0 -50
  105. package/runtime/sdk/compile/bundler.ts +0 -287
  106. package/runtime/sdk/compile/compileProject.ts +0 -129
  107. package/runtime/sdk/compile/detectEntry.ts +0 -128
  108. package/runtime/sdk/compile/fontMacro.ts +0 -459
  109. package/runtime/sdk/compile/fontRegistry.ts +0 -78
  110. package/runtime/sdk/compile/header.ts +0 -67
  111. package/runtime/sdk/compile/index.ts +0 -100
  112. package/runtime/sdk/compile/libraryImports.ts +0 -52
  113. package/runtime/sdk/compile/liteMaterial.ts +0 -247
  114. package/runtime/sdk/compile/sceneEditor.ts +0 -88
  115. package/runtime/sdk/compile/serverSplit.ts +0 -233
  116. package/runtime/sdk/compile/serverTypes.ts +0 -227
  117. package/runtime/sdk/compile/sfnt.ts +0 -98
  118. package/runtime/sdk/compile/shaderSchema.ts +0 -202
  119. package/runtime/sdk/compile/shaderTargets.ts +0 -81
  120. package/runtime/sdk/compile/sourcemap.ts +0 -25
  121. package/runtime/sdk/core/Aspect.ts +0 -568
  122. package/runtime/sdk/core/InspectorUI.ts +0 -212
  123. package/runtime/sdk/core/StateMachine.ts +0 -308
  124. package/runtime/sdk/core/color.ts +0 -66
  125. package/runtime/sdk/core/compWrite.ts +0 -42
  126. package/runtime/sdk/core/events.ts +0 -38
  127. package/runtime/sdk/core/fields.ts +0 -120
  128. package/runtime/sdk/core/registry.ts +0 -23
  129. package/runtime/sdk/core/signals.ts +0 -277
  130. package/runtime/sdk/core/time.ts +0 -84
  131. package/runtime/sdk/g2/Camera2D.ts +0 -40
  132. package/runtime/sdk/g2/CharacterController2D.ts +0 -276
  133. package/runtime/sdk/g2/Node2D.ts +0 -267
  134. package/runtime/sdk/g2/OneWay2D.ts +0 -66
  135. package/runtime/sdk/g2/Physics2D.ts +0 -346
  136. package/runtime/sdk/g2/Scene2D.ts +0 -209
  137. package/runtime/sdk/g2/Shape2D.ts +0 -259
  138. package/runtime/sdk/g2/Sprite.ts +0 -89
  139. package/runtime/sdk/g2/SpriteAnimation.ts +0 -171
  140. package/runtime/sdk/g2/SpriteSheet.ts +0 -166
  141. package/runtime/sdk/g2/Texture2D.ts +0 -47
  142. package/runtime/sdk/g2/Tilemap.ts +0 -41
  143. package/runtime/sdk/g2/Tileset.ts +0 -71
  144. package/runtime/sdk/g2/Trigger2D.ts +0 -77
  145. package/runtime/sdk/g2/autotile.ts +0 -433
  146. package/runtime/sdk/g2/cells.ts +0 -91
  147. package/runtime/sdk/g2/defineScene2d.ts +0 -381
  148. package/runtime/sdk/g2/groups2d.ts +0 -106
  149. package/runtime/sdk/g2/loop.ts +0 -50
  150. package/runtime/sdk/g2/scenarios2d.ts +0 -69
  151. package/runtime/sdk/g2/touch.ts +0 -83
  152. package/runtime/sdk/gl/Camera.ts +0 -160
  153. package/runtime/sdk/gl/CameraPlace.ts +0 -52
  154. package/runtime/sdk/gl/CharacterController.ts +0 -238
  155. package/runtime/sdk/gl/Gearbox.ts +0 -212
  156. package/runtime/sdk/gl/Geometry.ts +0 -279
  157. package/runtime/sdk/gl/IK.ts +0 -193
  158. package/runtime/sdk/gl/InstancedMesh.ts +0 -132
  159. package/runtime/sdk/gl/Light.ts +0 -107
  160. package/runtime/sdk/gl/Lightmap.ts +0 -256
  161. package/runtime/sdk/gl/Material.ts +0 -260
  162. package/runtime/sdk/gl/Mesh.ts +0 -83
  163. package/runtime/sdk/gl/Model.ts +0 -124
  164. package/runtime/sdk/gl/NavAgent.ts +0 -337
  165. package/runtime/sdk/gl/NavMesh.ts +0 -397
  166. package/runtime/sdk/gl/Node.ts +0 -350
  167. package/runtime/sdk/gl/Noise.ts +0 -30
  168. package/runtime/sdk/gl/Particles.ts +0 -676
  169. package/runtime/sdk/gl/Physics.ts +0 -222
  170. package/runtime/sdk/gl/Plane.ts +0 -53
  171. package/runtime/sdk/gl/Ragdoll.ts +0 -270
  172. package/runtime/sdk/gl/Ray.ts +0 -16
  173. package/runtime/sdk/gl/Scene.ts +0 -486
  174. package/runtime/sdk/gl/Shape.ts +0 -409
  175. package/runtime/sdk/gl/Terrain.ts +0 -1092
  176. package/runtime/sdk/gl/Texture.ts +0 -63
  177. package/runtime/sdk/gl/Trigger.ts +0 -45
  178. package/runtime/sdk/gl/Vehicle.ts +0 -473
  179. package/runtime/sdk/gl/Wheel.ts +0 -240
  180. package/runtime/sdk/gl/animation/AnimationClip.ts +0 -204
  181. package/runtime/sdk/gl/animation/Animator.ts +0 -120
  182. package/runtime/sdk/gl/animation/Layer.ts +0 -31
  183. package/runtime/sdk/gl/animation/Loop.ts +0 -30
  184. package/runtime/sdk/gl/animation/Playback.ts +0 -44
  185. package/runtime/sdk/gl/animation/core.ts +0 -336
  186. package/runtime/sdk/gl/controls.ts +0 -95
  187. package/runtime/sdk/gl/physicsEvents.ts +0 -20
  188. package/runtime/sdk/gl/scenarios.ts +0 -291
  189. package/runtime/sdk/gl/state.ts +0 -6
  190. package/runtime/sdk/gl/terrainMesh.ts +0 -219
  191. package/runtime/sdk/gl/touch.ts +0 -68
  192. package/runtime/sdk/inject.ts +0 -197
  193. package/runtime/sdk/math/Mathf.ts +0 -118
  194. package/runtime/sdk/math/mat4.ts +0 -278
  195. package/runtime/sdk/math/quat.ts +0 -232
  196. package/runtime/sdk/math/vec.ts +0 -255
  197. package/runtime/sdk/net/codec.ts +0 -119
  198. package/runtime/sdk/net/core.ts +0 -384
  199. package/runtime/sdk/net/index.ts +0 -181
  200. package/runtime/sdk/net/replication.ts +0 -622
  201. package/runtime/sdk/plugins/camera.ts +0 -81
  202. package/runtime/sdk/plugins/geolocation.ts +0 -123
  203. package/runtime/sdk/plugins/oauth.ts +0 -61
  204. package/runtime/sdk/plugins/permission.ts +0 -7
  205. package/runtime/sdk/plugins/push.ts +0 -132
  206. package/runtime/sdk/plugins/qr.ts +0 -73
  207. package/runtime/sdk/plugins/service.ts +0 -47
  208. package/runtime/sdk/runtime/app.ts +0 -101
  209. package/runtime/sdk/runtime/appEvents.ts +0 -54
  210. package/runtime/sdk/runtime/channel.ts +0 -61
  211. package/runtime/sdk/runtime/clipboard.ts +0 -20
  212. package/runtime/sdk/runtime/datetime.ts +0 -329
  213. package/runtime/sdk/runtime/device.ts +0 -293
  214. package/runtime/sdk/runtime/fetch.ts +0 -77
  215. package/runtime/sdk/runtime/files.ts +0 -23
  216. package/runtime/sdk/runtime/input.ts +0 -175
  217. package/runtime/sdk/runtime/media.ts +0 -111
  218. package/runtime/sdk/runtime/misc.ts +0 -16
  219. package/runtime/sdk/runtime/net.ts +0 -36
  220. package/runtime/sdk/runtime/rpc.ts +0 -218
  221. package/runtime/sdk/runtime/service.ts +0 -83
  222. package/runtime/sdk/runtime/share.ts +0 -9
  223. package/runtime/sdk/runtime/storage.ts +0 -13
  224. package/runtime/sdk/runtime/touch.ts +0 -76
  225. package/runtime/sdk/scene/defineScene.ts +0 -1353
  226. package/runtime/sdk/scene/editorPlugins.ts +0 -110
  227. package/runtime/sdk/scene/gizmos.ts +0 -148
  228. package/runtime/sdk/scene/grammar.ts +0 -120
  229. package/runtime/sdk/scene/material.ts +0 -188
  230. package/runtime/sdk/server/auth/appConfig.ts +0 -12
  231. package/runtime/sdk/server/auth/global.ts +0 -80
  232. package/runtime/sdk/server/auth/host.ts +0 -318
  233. package/runtime/sdk/server/auth/models.ts +0 -83
  234. package/runtime/sdk/server/auth/types.ts +0 -50
  235. package/runtime/sdk/server/channel.ts +0 -56
  236. package/runtime/sdk/server/context.ts +0 -36
  237. package/runtime/sdk/server/db/defineDb.ts +0 -237
  238. package/runtime/sdk/server/db/fields.ts +0 -132
  239. package/runtime/sdk/server/db/httpTransport.ts +0 -93
  240. package/runtime/sdk/server/db/index.ts +0 -7
  241. package/runtime/sdk/server/db/marci/query.ts +0 -412
  242. package/runtime/sdk/server/db/types.ts +0 -202
  243. package/runtime/sdk/server/errors.ts +0 -12
  244. package/runtime/sdk/server/host.ts +0 -74
  245. package/runtime/sdk/server/inject.ts +0 -13
  246. package/runtime/sdk/server/runtime.ts +0 -133
  247. package/runtime/sdk/server/validate.ts +0 -87
  248. package/runtime/sdk/ui/NativeView.ts +0 -142
  249. package/runtime/sdk/ui/UI.ts +0 -39
  250. package/runtime/sdk/ui/UIBottomSheet.ts +0 -139
  251. package/runtime/sdk/ui/UIButton.ts +0 -101
  252. package/runtime/sdk/ui/UIContainer.ts +0 -60
  253. package/runtime/sdk/ui/UIImage.ts +0 -83
  254. package/runtime/sdk/ui/UIInput.ts +0 -185
  255. package/runtime/sdk/ui/UIModal.ts +0 -139
  256. package/runtime/sdk/ui/UINode.ts +0 -830
  257. package/runtime/sdk/ui/UIPager.ts +0 -362
  258. package/runtime/sdk/ui/UIPopover.ts +0 -100
  259. package/runtime/sdk/ui/UIScreen.ts +0 -123
  260. package/runtime/sdk/ui/UIScrollable.ts +0 -87
  261. package/runtime/sdk/ui/UISpacer.ts +0 -14
  262. package/runtime/sdk/ui/UITabs.ts +0 -236
  263. package/runtime/sdk/ui/UIText.ts +0 -51
  264. package/runtime/sdk/ui/UIVideo.ts +0 -88
  265. package/runtime/sdk/ui/UIVirtualizedList.ts +0 -241
  266. package/runtime/sdk/ui/UIWidget.ts +0 -127
  267. package/runtime/sdk/ui/fonts.ts +0 -13
  268. package/runtime/sdk/ui/presentable.ts +0 -117
  269. package/runtime/sdk/ui/router.ts +0 -132
  270. package/runtime/sdk/ui/theme.ts +0 -84
@@ -1,337 +0,0 @@
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
- }