unreal-engine-mcp-server 0.4.7 → 0.5.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 (438) hide show
  1. package/.env.example +26 -0
  2. package/.env.production +38 -7
  3. package/.eslintrc.json +0 -54
  4. package/.eslintrc.override.json +8 -0
  5. package/.github/ISSUE_TEMPLATE/bug_report.yml +94 -0
  6. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  7. package/.github/ISSUE_TEMPLATE/feature_request.yml +56 -0
  8. package/.github/copilot-instructions.md +478 -45
  9. package/.github/dependabot.yml +19 -0
  10. package/.github/labeler.yml +24 -0
  11. package/.github/labels.yml +70 -0
  12. package/.github/pull_request_template.md +42 -0
  13. package/.github/release-drafter.yml +148 -0
  14. package/.github/workflows/auto-merge.yml +38 -0
  15. package/.github/workflows/ci.yml +38 -0
  16. package/.github/workflows/dependency-review.yml +17 -0
  17. package/.github/workflows/gemini-issue-triage.yml +172 -0
  18. package/.github/workflows/greetings.yml +23 -0
  19. package/.github/workflows/labeler.yml +16 -0
  20. package/.github/workflows/links.yml +80 -0
  21. package/.github/workflows/pr-size-labeler.yml +137 -0
  22. package/.github/workflows/publish-mcp.yml +12 -7
  23. package/.github/workflows/release-drafter.yml +23 -0
  24. package/.github/workflows/release.yml +112 -0
  25. package/.github/workflows/semantic-pull-request.yml +35 -0
  26. package/.github/workflows/smoke-test.yml +36 -0
  27. package/.github/workflows/stale.yml +28 -0
  28. package/CHANGELOG.md +267 -31
  29. package/CONTRIBUTING.md +140 -0
  30. package/README.md +166 -71
  31. package/claude_desktop_config_example.json +7 -6
  32. package/dist/automation/bridge.d.ts +50 -0
  33. package/dist/automation/bridge.js +452 -0
  34. package/dist/automation/connection-manager.d.ts +23 -0
  35. package/dist/automation/connection-manager.js +107 -0
  36. package/dist/automation/handshake.d.ts +11 -0
  37. package/dist/automation/handshake.js +89 -0
  38. package/dist/automation/index.d.ts +3 -0
  39. package/dist/automation/index.js +3 -0
  40. package/dist/automation/message-handler.d.ts +12 -0
  41. package/dist/automation/message-handler.js +149 -0
  42. package/dist/automation/request-tracker.d.ts +25 -0
  43. package/dist/automation/request-tracker.js +98 -0
  44. package/dist/automation/types.d.ts +130 -0
  45. package/dist/automation/types.js +2 -0
  46. package/dist/cli.js +32 -5
  47. package/dist/config.d.ts +27 -0
  48. package/dist/config.js +60 -0
  49. package/dist/constants.d.ts +12 -0
  50. package/dist/constants.js +12 -0
  51. package/dist/graphql/resolvers.d.ts +268 -0
  52. package/dist/graphql/resolvers.js +743 -0
  53. package/dist/graphql/schema.d.ts +5 -0
  54. package/dist/graphql/schema.js +437 -0
  55. package/dist/graphql/server.d.ts +26 -0
  56. package/dist/graphql/server.js +115 -0
  57. package/dist/graphql/types.d.ts +7 -0
  58. package/dist/graphql/types.js +2 -0
  59. package/dist/handlers/resource-handlers.d.ts +20 -0
  60. package/dist/handlers/resource-handlers.js +180 -0
  61. package/dist/index.d.ts +31 -18
  62. package/dist/index.js +119 -619
  63. package/dist/prompts/index.js +4 -4
  64. package/dist/resources/actors.d.ts +17 -12
  65. package/dist/resources/actors.js +56 -76
  66. package/dist/resources/assets.d.ts +6 -14
  67. package/dist/resources/assets.js +115 -147
  68. package/dist/resources/levels.d.ts +13 -13
  69. package/dist/resources/levels.js +25 -34
  70. package/dist/server/resource-registry.d.ts +20 -0
  71. package/dist/server/resource-registry.js +37 -0
  72. package/dist/server/tool-registry.d.ts +23 -0
  73. package/dist/server/tool-registry.js +322 -0
  74. package/dist/server-setup.d.ts +21 -0
  75. package/dist/server-setup.js +111 -0
  76. package/dist/services/health-monitor.d.ts +34 -0
  77. package/dist/services/health-monitor.js +105 -0
  78. package/dist/services/metrics-server.d.ts +11 -0
  79. package/dist/services/metrics-server.js +105 -0
  80. package/dist/tools/actors.d.ts +147 -9
  81. package/dist/tools/actors.js +350 -311
  82. package/dist/tools/animation.d.ts +135 -4
  83. package/dist/tools/animation.js +510 -411
  84. package/dist/tools/assets.d.ts +117 -19
  85. package/dist/tools/assets.js +259 -284
  86. package/dist/tools/audio.d.ts +102 -42
  87. package/dist/tools/audio.js +272 -685
  88. package/dist/tools/base-tool.d.ts +17 -0
  89. package/dist/tools/base-tool.js +46 -0
  90. package/dist/tools/behavior-tree.d.ts +94 -0
  91. package/dist/tools/behavior-tree.js +39 -0
  92. package/dist/tools/blueprint/helpers.d.ts +29 -0
  93. package/dist/tools/blueprint/helpers.js +182 -0
  94. package/dist/tools/blueprint.d.ts +228 -118
  95. package/dist/tools/blueprint.js +685 -832
  96. package/dist/tools/consolidated-tool-definitions.d.ts +5462 -1781
  97. package/dist/tools/consolidated-tool-definitions.js +829 -496
  98. package/dist/tools/consolidated-tool-handlers.d.ts +2 -1
  99. package/dist/tools/consolidated-tool-handlers.js +211 -1026
  100. package/dist/tools/debug.d.ts +143 -85
  101. package/dist/tools/debug.js +234 -180
  102. package/dist/tools/dynamic-handler-registry.d.ts +11 -0
  103. package/dist/tools/dynamic-handler-registry.js +101 -0
  104. package/dist/tools/editor.d.ts +139 -18
  105. package/dist/tools/editor.js +239 -244
  106. package/dist/tools/engine.d.ts +10 -4
  107. package/dist/tools/engine.js +13 -5
  108. package/dist/tools/environment.d.ts +36 -0
  109. package/dist/tools/environment.js +267 -0
  110. package/dist/tools/foliage.d.ts +105 -14
  111. package/dist/tools/foliage.js +219 -331
  112. package/dist/tools/handlers/actor-handlers.d.ts +3 -0
  113. package/dist/tools/handlers/actor-handlers.js +232 -0
  114. package/dist/tools/handlers/animation-handlers.d.ts +3 -0
  115. package/dist/tools/handlers/animation-handlers.js +185 -0
  116. package/dist/tools/handlers/argument-helper.d.ts +16 -0
  117. package/dist/tools/handlers/argument-helper.js +80 -0
  118. package/dist/tools/handlers/asset-handlers.d.ts +3 -0
  119. package/dist/tools/handlers/asset-handlers.js +496 -0
  120. package/dist/tools/handlers/audio-handlers.d.ts +3 -0
  121. package/dist/tools/handlers/audio-handlers.js +166 -0
  122. package/dist/tools/handlers/blueprint-handlers.d.ts +4 -0
  123. package/dist/tools/handlers/blueprint-handlers.js +358 -0
  124. package/dist/tools/handlers/common-handlers.d.ts +14 -0
  125. package/dist/tools/handlers/common-handlers.js +56 -0
  126. package/dist/tools/handlers/editor-handlers.d.ts +3 -0
  127. package/dist/tools/handlers/editor-handlers.js +119 -0
  128. package/dist/tools/handlers/effect-handlers.d.ts +3 -0
  129. package/dist/tools/handlers/effect-handlers.js +171 -0
  130. package/dist/tools/handlers/environment-handlers.d.ts +3 -0
  131. package/dist/tools/handlers/environment-handlers.js +170 -0
  132. package/dist/tools/handlers/graph-handlers.d.ts +3 -0
  133. package/dist/tools/handlers/graph-handlers.js +90 -0
  134. package/dist/tools/handlers/input-handlers.d.ts +3 -0
  135. package/dist/tools/handlers/input-handlers.js +21 -0
  136. package/dist/tools/handlers/inspect-handlers.d.ts +3 -0
  137. package/dist/tools/handlers/inspect-handlers.js +383 -0
  138. package/dist/tools/handlers/level-handlers.d.ts +3 -0
  139. package/dist/tools/handlers/level-handlers.js +237 -0
  140. package/dist/tools/handlers/lighting-handlers.d.ts +3 -0
  141. package/dist/tools/handlers/lighting-handlers.js +144 -0
  142. package/dist/tools/handlers/performance-handlers.d.ts +3 -0
  143. package/dist/tools/handlers/performance-handlers.js +130 -0
  144. package/dist/tools/handlers/pipeline-handlers.d.ts +3 -0
  145. package/dist/tools/handlers/pipeline-handlers.js +110 -0
  146. package/dist/tools/handlers/sequence-handlers.d.ts +3 -0
  147. package/dist/tools/handlers/sequence-handlers.js +376 -0
  148. package/dist/tools/handlers/system-handlers.d.ts +4 -0
  149. package/dist/tools/handlers/system-handlers.js +506 -0
  150. package/dist/tools/input.d.ts +19 -0
  151. package/dist/tools/input.js +89 -0
  152. package/dist/tools/introspection.d.ts +103 -40
  153. package/dist/tools/introspection.js +425 -568
  154. package/dist/tools/landscape.d.ts +97 -36
  155. package/dist/tools/landscape.js +280 -409
  156. package/dist/tools/level.d.ts +130 -10
  157. package/dist/tools/level.js +639 -675
  158. package/dist/tools/lighting.d.ts +77 -38
  159. package/dist/tools/lighting.js +441 -943
  160. package/dist/tools/logs.d.ts +3 -3
  161. package/dist/tools/logs.js +5 -57
  162. package/dist/tools/materials.d.ts +91 -24
  163. package/dist/tools/materials.js +190 -118
  164. package/dist/tools/niagara.d.ts +149 -39
  165. package/dist/tools/niagara.js +232 -182
  166. package/dist/tools/performance.d.ts +27 -12
  167. package/dist/tools/performance.js +204 -122
  168. package/dist/tools/physics.d.ts +32 -77
  169. package/dist/tools/physics.js +171 -582
  170. package/dist/tools/property-dictionary.d.ts +13 -0
  171. package/dist/tools/property-dictionary.js +82 -0
  172. package/dist/tools/sequence.d.ts +73 -48
  173. package/dist/tools/sequence.js +196 -748
  174. package/dist/tools/tool-definition-utils.d.ts +59 -0
  175. package/dist/tools/tool-definition-utils.js +35 -0
  176. package/dist/tools/ui.d.ts +66 -34
  177. package/dist/tools/ui.js +134 -214
  178. package/dist/types/env.d.ts +0 -3
  179. package/dist/types/env.js +0 -7
  180. package/dist/types/tool-interfaces.d.ts +898 -0
  181. package/dist/types/tool-interfaces.js +2 -0
  182. package/dist/types/tool-types.d.ts +183 -19
  183. package/dist/types/tool-types.js +0 -4
  184. package/dist/unreal-bridge.d.ts +24 -131
  185. package/dist/unreal-bridge.js +364 -1506
  186. package/dist/utils/command-validator.d.ts +9 -0
  187. package/dist/utils/command-validator.js +67 -0
  188. package/dist/utils/elicitation.d.ts +1 -1
  189. package/dist/utils/elicitation.js +12 -15
  190. package/dist/utils/error-handler.d.ts +2 -51
  191. package/dist/utils/error-handler.js +11 -87
  192. package/dist/utils/ini-reader.d.ts +3 -0
  193. package/dist/utils/ini-reader.js +69 -0
  194. package/dist/utils/logger.js +9 -6
  195. package/dist/utils/normalize.d.ts +3 -0
  196. package/dist/utils/normalize.js +56 -0
  197. package/dist/utils/response-factory.d.ts +7 -0
  198. package/dist/utils/response-factory.js +33 -0
  199. package/dist/utils/response-validator.d.ts +3 -24
  200. package/dist/utils/response-validator.js +130 -81
  201. package/dist/utils/result-helpers.d.ts +4 -5
  202. package/dist/utils/result-helpers.js +15 -16
  203. package/dist/utils/safe-json.js +5 -11
  204. package/dist/utils/unreal-command-queue.d.ts +24 -0
  205. package/dist/utils/unreal-command-queue.js +120 -0
  206. package/dist/utils/validation.d.ts +0 -40
  207. package/dist/utils/validation.js +1 -78
  208. package/dist/wasm/index.d.ts +70 -0
  209. package/dist/wasm/index.js +535 -0
  210. package/docs/GraphQL-API.md +888 -0
  211. package/docs/Migration-Guide-v0.5.0.md +692 -0
  212. package/docs/Roadmap.md +53 -0
  213. package/docs/WebAssembly-Integration.md +628 -0
  214. package/docs/editor-plugin-extension.md +370 -0
  215. package/docs/handler-mapping.md +242 -0
  216. package/docs/native-automation-progress.md +128 -0
  217. package/docs/testing-guide.md +423 -0
  218. package/mcp-config-example.json +6 -6
  219. package/package.json +60 -27
  220. package/plugins/McpAutomationBridge/Config/FilterPlugin.ini +8 -0
  221. package/plugins/McpAutomationBridge/McpAutomationBridge.uplugin +64 -0
  222. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/McpAutomationBridge.Build.cs +189 -0
  223. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.cpp +22 -0
  224. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.h +30 -0
  225. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeHelpers.h +1983 -0
  226. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeModule.cpp +72 -0
  227. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSettings.cpp +46 -0
  228. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +581 -0
  229. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +2394 -0
  230. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetQueryHandlers.cpp +300 -0
  231. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetWorkflowHandlers.cpp +2807 -0
  232. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AudioHandlers.cpp +1087 -0
  233. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BehaviorTreeHandlers.cpp +488 -0
  234. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.cpp +643 -0
  235. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.h +31 -0
  236. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +1184 -0
  237. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +5652 -0
  238. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers_List.cpp +152 -0
  239. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ControlHandlers.cpp +2614 -0
  240. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_DebugHandlers.cpp +42 -0
  241. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EditorFunctionHandlers.cpp +1237 -0
  242. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +1701 -0
  243. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +2145 -0
  244. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_FoliageHandlers.cpp +954 -0
  245. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InputHandlers.cpp +209 -0
  246. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InsightsHandlers.cpp +41 -0
  247. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LandscapeHandlers.cpp +1164 -0
  248. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LevelHandlers.cpp +762 -0
  249. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +634 -0
  250. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LogHandlers.cpp +136 -0
  251. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_MaterialGraphHandlers.cpp +494 -0
  252. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraGraphHandlers.cpp +278 -0
  253. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraHandlers.cpp +625 -0
  254. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PerformanceHandlers.cpp +401 -0
  255. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PipelineHandlers.cpp +67 -0
  256. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +735 -0
  257. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PropertyHandlers.cpp +2634 -0
  258. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_RenderHandlers.cpp +189 -0
  259. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.cpp +917 -0
  260. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.h +39 -0
  261. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +2670 -0
  262. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequencerHandlers.cpp +519 -0
  263. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_TestHandlers.cpp +38 -0
  264. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_UiHandlers.cpp +668 -0
  265. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_WorldPartitionHandlers.cpp +346 -0
  266. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.cpp +1330 -0
  267. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.h +149 -0
  268. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +783 -0
  269. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSettings.h +115 -0
  270. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSubsystem.h +796 -0
  271. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpConnectionManager.h +117 -0
  272. package/scripts/check-unreal-connection.mjs +19 -0
  273. package/scripts/clean-tmp.js +23 -0
  274. package/scripts/patch-wasm.js +26 -0
  275. package/scripts/run-all-tests.mjs +131 -0
  276. package/scripts/smoke-test.ts +94 -0
  277. package/scripts/sync-mcp-plugin.js +143 -0
  278. package/scripts/test-no-plugin-alternates.mjs +113 -0
  279. package/scripts/validate-server.js +46 -0
  280. package/scripts/verify-automation-bridge.js +200 -0
  281. package/server.json +57 -21
  282. package/src/automation/bridge.ts +558 -0
  283. package/src/automation/connection-manager.ts +130 -0
  284. package/src/automation/handshake.ts +99 -0
  285. package/src/automation/index.ts +2 -0
  286. package/src/automation/message-handler.ts +167 -0
  287. package/src/automation/request-tracker.ts +123 -0
  288. package/src/automation/types.ts +107 -0
  289. package/src/cli.ts +33 -6
  290. package/src/config.ts +73 -0
  291. package/src/constants.ts +12 -0
  292. package/src/graphql/resolvers.ts +1010 -0
  293. package/src/graphql/schema.ts +452 -0
  294. package/src/graphql/server.ts +154 -0
  295. package/src/graphql/types.ts +7 -0
  296. package/src/handlers/resource-handlers.ts +186 -0
  297. package/src/index.ts +152 -663
  298. package/src/prompts/index.ts +4 -4
  299. package/src/resources/actors.ts +58 -76
  300. package/src/resources/assets.ts +147 -134
  301. package/src/resources/levels.ts +28 -33
  302. package/src/server/resource-registry.ts +47 -0
  303. package/src/server/tool-registry.ts +354 -0
  304. package/src/server-setup.ts +148 -0
  305. package/src/services/health-monitor.ts +132 -0
  306. package/src/services/metrics-server.ts +142 -0
  307. package/src/tools/actors.ts +417 -322
  308. package/src/tools/animation.ts +671 -461
  309. package/src/tools/assets.ts +353 -289
  310. package/src/tools/audio.ts +323 -766
  311. package/src/tools/base-tool.ts +52 -0
  312. package/src/tools/behavior-tree.ts +45 -0
  313. package/src/tools/blueprint/helpers.ts +189 -0
  314. package/src/tools/blueprint.ts +787 -965
  315. package/src/tools/consolidated-tool-definitions.ts +993 -515
  316. package/src/tools/consolidated-tool-handlers.ts +272 -1139
  317. package/src/tools/debug.ts +292 -187
  318. package/src/tools/dynamic-handler-registry.ts +151 -0
  319. package/src/tools/editor.ts +309 -246
  320. package/src/tools/engine.ts +14 -3
  321. package/src/tools/environment.ts +287 -0
  322. package/src/tools/foliage.ts +314 -379
  323. package/src/tools/handlers/actor-handlers.ts +271 -0
  324. package/src/tools/handlers/animation-handlers.ts +237 -0
  325. package/src/tools/handlers/argument-helper.ts +142 -0
  326. package/src/tools/handlers/asset-handlers.ts +532 -0
  327. package/src/tools/handlers/audio-handlers.ts +194 -0
  328. package/src/tools/handlers/blueprint-handlers.ts +380 -0
  329. package/src/tools/handlers/common-handlers.ts +87 -0
  330. package/src/tools/handlers/editor-handlers.ts +123 -0
  331. package/src/tools/handlers/effect-handlers.ts +220 -0
  332. package/src/tools/handlers/environment-handlers.ts +183 -0
  333. package/src/tools/handlers/graph-handlers.ts +116 -0
  334. package/src/tools/handlers/input-handlers.ts +28 -0
  335. package/src/tools/handlers/inspect-handlers.ts +450 -0
  336. package/src/tools/handlers/level-handlers.ts +252 -0
  337. package/src/tools/handlers/lighting-handlers.ts +147 -0
  338. package/src/tools/handlers/performance-handlers.ts +132 -0
  339. package/src/tools/handlers/pipeline-handlers.ts +127 -0
  340. package/src/tools/handlers/sequence-handlers.ts +415 -0
  341. package/src/tools/handlers/system-handlers.ts +564 -0
  342. package/src/tools/input.ts +101 -0
  343. package/src/tools/introspection.ts +493 -584
  344. package/src/tools/landscape.ts +394 -489
  345. package/src/tools/level.ts +752 -694
  346. package/src/tools/lighting.ts +583 -984
  347. package/src/tools/logs.ts +9 -57
  348. package/src/tools/materials.ts +231 -121
  349. package/src/tools/niagara.ts +293 -168
  350. package/src/tools/performance.ts +320 -168
  351. package/src/tools/physics.ts +268 -613
  352. package/src/tools/property-dictionary.ts +98 -0
  353. package/src/tools/sequence.ts +255 -815
  354. package/src/tools/tool-definition-utils.ts +35 -0
  355. package/src/tools/ui.ts +207 -283
  356. package/src/types/env.ts +0 -10
  357. package/src/types/tool-interfaces.ts +250 -0
  358. package/src/types/tool-types.ts +243 -21
  359. package/src/unreal-bridge.ts +460 -1550
  360. package/src/utils/command-validator.ts +75 -0
  361. package/src/utils/elicitation.ts +10 -7
  362. package/src/utils/error-handler.ts +14 -90
  363. package/src/utils/ini-reader.ts +86 -0
  364. package/src/utils/logger.ts +8 -3
  365. package/src/utils/normalize.ts +60 -0
  366. package/src/utils/response-factory.ts +39 -0
  367. package/src/utils/response-validator.ts +176 -56
  368. package/src/utils/result-helpers.ts +21 -19
  369. package/src/utils/safe-json.ts +14 -11
  370. package/src/utils/unreal-command-queue.ts +152 -0
  371. package/src/utils/validation.ts +4 -1
  372. package/src/wasm/index.ts +838 -0
  373. package/test-server.mjs +100 -0
  374. package/tests/run-unreal-tool-tests.mjs +242 -14
  375. package/tests/test-animation.mjs +44 -0
  376. package/tests/test-asset-advanced.mjs +82 -0
  377. package/tests/test-asset-errors.mjs +35 -0
  378. package/tests/test-audio.mjs +219 -0
  379. package/tests/test-automation-timeouts.mjs +98 -0
  380. package/tests/test-behavior-tree.mjs +261 -0
  381. package/tests/test-blueprint-events.mjs +35 -0
  382. package/tests/test-blueprint-graph.mjs +79 -0
  383. package/tests/test-blueprint.mjs +577 -0
  384. package/tests/test-client-mode.mjs +86 -0
  385. package/tests/test-console-command.mjs +56 -0
  386. package/tests/test-control-actor.mjs +425 -0
  387. package/tests/test-control-editor.mjs +80 -0
  388. package/tests/test-extra-tools.mjs +38 -0
  389. package/tests/test-graphql.mjs +322 -0
  390. package/tests/test-inspect.mjs +72 -0
  391. package/tests/test-landscape.mjs +60 -0
  392. package/tests/test-manage-asset.mjs +438 -0
  393. package/tests/test-manage-level.mjs +70 -0
  394. package/tests/test-materials.mjs +356 -0
  395. package/tests/test-niagara.mjs +185 -0
  396. package/tests/test-no-inline-python.mjs +122 -0
  397. package/tests/test-plugin-handshake.mjs +82 -0
  398. package/tests/test-render.mjs +33 -0
  399. package/tests/test-runner.mjs +933 -0
  400. package/tests/test-search-assets.mjs +66 -0
  401. package/tests/test-sequence.mjs +68 -0
  402. package/tests/test-system.mjs +57 -0
  403. package/tests/test-wasm.mjs +193 -0
  404. package/tests/test-world-partition.mjs +215 -0
  405. package/tsconfig.json +3 -3
  406. package/wasm/Cargo.lock +363 -0
  407. package/wasm/Cargo.toml +42 -0
  408. package/wasm/LICENSE +21 -0
  409. package/wasm/README.md +253 -0
  410. package/wasm/src/dependency_resolver.rs +377 -0
  411. package/wasm/src/lib.rs +153 -0
  412. package/wasm/src/property_parser.rs +271 -0
  413. package/wasm/src/transform_math.rs +396 -0
  414. package/wasm/tests/integration.rs +109 -0
  415. package/.github/workflows/smithery-build.yml +0 -29
  416. package/dist/tools/build_environment_advanced.d.ts +0 -65
  417. package/dist/tools/build_environment_advanced.js +0 -633
  418. package/dist/tools/rc.d.ts +0 -110
  419. package/dist/tools/rc.js +0 -437
  420. package/dist/tools/visual.d.ts +0 -40
  421. package/dist/tools/visual.js +0 -282
  422. package/dist/utils/http.d.ts +0 -6
  423. package/dist/utils/http.js +0 -151
  424. package/dist/utils/python-output.d.ts +0 -18
  425. package/dist/utils/python-output.js +0 -290
  426. package/dist/utils/python.d.ts +0 -2
  427. package/dist/utils/python.js +0 -4
  428. package/dist/utils/stdio-redirect.d.ts +0 -2
  429. package/dist/utils/stdio-redirect.js +0 -20
  430. package/docs/unreal-tool-test-cases.md +0 -574
  431. package/smithery.yaml +0 -29
  432. package/src/tools/build_environment_advanced.ts +0 -732
  433. package/src/tools/rc.ts +0 -515
  434. package/src/tools/visual.ts +0 -281
  435. package/src/utils/http.ts +0 -187
  436. package/src/utils/python-output.ts +0 -351
  437. package/src/utils/python.ts +0 -3
  438. package/src/utils/stdio-redirect.ts +0 -18
@@ -1,16 +1,13 @@
1
- import { bestEffortInterpretedText, coerceBoolean, coerceNumber, coerceString, interpretStandardResult } from '../utils/result-helpers.js';
1
+ import { coerceBoolean, coerceNumber, coerceString } from '../utils/result-helpers.js';
2
2
  export class FoliageTools {
3
3
  bridge;
4
- constructor(bridge) {
4
+ automationBridge;
5
+ constructor(bridge, automationBridge) {
5
6
  this.bridge = bridge;
7
+ this.automationBridge = automationBridge;
6
8
  }
7
- // NOTE: We intentionally avoid issuing Unreal console commands here because
8
- // they have proven unreliable and generate engine warnings (failed FindConsoleObject).
9
- // Instead, we validate inputs and return structured results. Actual foliage
10
- // authoring should be implemented via Python APIs in future iterations.
11
- // Add foliage type via Python (creates FoliageType asset properly)
9
+ setAutomationBridge(automationBridge) { this.automationBridge = automationBridge; }
12
10
  async addFoliageType(params) {
13
- // Basic validation to prevent bad inputs like 'undefined' and empty strings
14
11
  const errors = [];
15
12
  const name = String(params?.name ?? '').trim();
16
13
  const meshPath = String(params?.meshPath ?? '').trim();
@@ -35,194 +32,58 @@ export class FoliageTools {
35
32
  if (errors.length > 0) {
36
33
  return { success: false, error: errors.join('; ') };
37
34
  }
38
- const py = `
39
- import unreal, json
40
-
41
- name = ${JSON.stringify(name)}
42
- mesh_path = ${JSON.stringify(meshPath)}
43
- fallback_mesh = '/Engine/EngineMeshes/Sphere'
44
- package_path = '/Game/Foliage/Types'
45
-
46
- res = {'success': False, 'created': False, 'asset_path': '', 'used_mesh': '', 'exists_after': False, 'method': '', 'note': ''}
47
-
48
- try:
49
- # Ensure package directory
50
- try:
51
- if not unreal.EditorAssetLibrary.does_directory_exist(package_path):
52
- unreal.EditorAssetLibrary.make_directory(package_path)
53
- except Exception as e:
54
- res['note'] += f"; make_directory failed: {e}"
55
-
56
- # Load mesh or fallback
57
- mesh = None
58
- try:
59
- if unreal.EditorAssetLibrary.does_asset_exist(mesh_path):
60
- mesh = unreal.EditorAssetLibrary.load_asset(mesh_path)
61
- except Exception as e:
62
- res['note'] += f"; could not check/load mesh_path: {e}"
63
-
64
- if not mesh:
65
- mesh = unreal.EditorAssetLibrary.load_asset(fallback_mesh)
66
- res['note'] += '; fallback_mesh_used'
67
- if mesh:
68
- res['used_mesh'] = str(mesh.get_path_name())
69
-
70
- # Create FoliageType asset using proper UE5 API
71
- asset = None
72
- try:
73
- asset_path = f"{package_path}/{name}"
74
-
75
- # Check if asset already exists
76
- if unreal.EditorAssetLibrary.does_asset_exist(asset_path):
77
- asset = unreal.EditorAssetLibrary.load_asset(asset_path)
78
- res['note'] += '; loaded_existing'
79
- else:
80
- # Create FoliageType_InstancedStaticMesh using proper API
81
- try:
82
- asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
83
-
84
- # Try to create factory and set mesh property
85
- factory = None
86
- try:
87
- factory = unreal.FoliageType_InstancedStaticMeshFactory()
88
- # Try different property names for different UE versions
89
- try:
90
- factory.set_editor_property('mesh', mesh)
91
- except:
92
- try:
93
- factory.set_editor_property('static_mesh', mesh)
94
- except:
95
- try:
96
- factory.set_editor_property('source_mesh', mesh)
97
- except:
98
- pass # Factory will use default or no mesh
99
- except:
100
- res['note'] += '; factory_creation_failed'
101
- factory = None
102
-
103
- # Create the asset with or without factory
104
- if factory:
105
- asset = asset_tools.create_asset(
106
- asset_name=name,
107
- package_path=package_path,
108
- asset_class=unreal.FoliageType_InstancedStaticMesh,
109
- factory=factory
110
- )
111
- else:
112
- # Try without factory
113
- asset = asset_tools.create_asset(
114
- asset_name=name,
115
- package_path=package_path,
116
- asset_class=unreal.FoliageType_InstancedStaticMesh,
117
- factory=None
118
- )
119
-
120
- if asset:
121
- # Configure foliage properties
122
- asset.set_editor_property('mesh', mesh)
123
- if ${params.density !== undefined ? params.density : 1.0} >= 0:
124
- asset.set_editor_property('density', ${params.density !== undefined ? params.density : 1.0})
125
- if ${params.randomYaw === false ? 'False' : 'True'}:
126
- asset.set_editor_property('random_yaw', True)
127
- if ${params.alignToNormal === false ? 'False' : 'True'}:
128
- asset.set_editor_property('align_to_normal', True)
129
-
130
- # Set scale range
131
- min_scale = ${params.minScale || 0.8}
132
- max_scale = ${params.maxScale || 1.2}
133
- asset.set_editor_property('scale_x', (min_scale, max_scale))
134
- asset.set_editor_property('scale_y', (min_scale, max_scale))
135
- asset.set_editor_property('scale_z', (min_scale, max_scale))
136
-
137
- res['note'] += '; created_with_factory'
138
- else:
139
- res['note'] += '; factory_creation_failed'
140
- except AttributeError:
141
- # Fallback if factory doesn't exist - use base FoliageType
142
- try:
143
- asset = asset_tools.create_asset(
144
- asset_name=name,
145
- package_path=package_path,
146
- asset_class=unreal.FoliageType,
147
- factory=None
148
- )
149
- if asset:
150
- res['note'] += '; created_base_foliage_type'
151
- except Exception as e2:
152
- res['note'] += f"; base_creation_failed: {e2}"
153
- except Exception as e:
154
- res['note'] += f"; factory_creation_failed: {e}"
155
- asset = None
156
- except Exception as e:
157
- res['note'] += f"; create_asset failed: {e}"
158
- asset = None
159
-
160
- if asset and mesh:
161
- try:
162
- # Set the mesh property (different property names in different UE versions)
163
- try:
164
- asset.set_editor_property('mesh', mesh)
165
- except:
166
- try:
167
- asset.set_editor_property('static_mesh', mesh)
168
- except:
169
- pass
170
-
171
- # Save the asset
172
- unreal.EditorAssetLibrary.save_asset(asset.get_path_name())
173
- res['asset_path'] = str(asset.get_path_name())
174
- res['created'] = True
175
- res['method'] = 'FoliageType_InstancedStaticMesh'
176
- except Exception as e:
177
- res['note'] += f"; set/save asset failed: {e}"
178
- elif not asset:
179
- res['note'] += "; asset creation returned None"
180
- elif not mesh:
181
- res['note'] += "; mesh object is None, cannot assign to foliage type"
182
-
183
- # Verify existence
184
- res['exists_after'] = unreal.EditorAssetLibrary.does_asset_exist(res['asset_path']) if res['asset_path'] else False
185
- res['success'] = res['exists_after'] or res['created']
186
-
187
- except Exception as e:
188
- res['success'] = False
189
- res['note'] += f"; fatal: {e}"
190
-
191
- print('RESULT:' + json.dumps(res))
192
- `.trim();
193
- const pyResp = await this.bridge.executePython(py);
194
- const interpreted = interpretStandardResult(pyResp, {
195
- successMessage: `Foliage type '${name}' processed`,
196
- failureMessage: 'Add foliage type failed'
197
- });
198
- if (!interpreted.success) {
35
+ if (!this.automationBridge) {
36
+ throw new Error('Automation Bridge not available. Foliage operations require plugin support.');
37
+ }
38
+ try {
39
+ const base = meshPath.includes('.') ? meshPath : `${meshPath}.${meshPath.split('/').filter(Boolean).pop()}`;
40
+ const response = await this.automationBridge.sendAutomationRequest('add_foliage_type', {
41
+ name,
42
+ meshPath: base,
43
+ density: params.density ?? 100,
44
+ radius: params.radius ?? 0,
45
+ minScale: params.minScale ?? 1.0,
46
+ maxScale: params.maxScale ?? 1.0,
47
+ alignToNormal: params.alignToNormal ?? true,
48
+ randomYaw: params.randomYaw ?? true,
49
+ groundSlope: params.groundSlope ?? 45
50
+ }, {
51
+ timeoutMs: 60000
52
+ });
53
+ if (response.success === false) {
54
+ return {
55
+ success: false,
56
+ error: response.error || response.message || 'Add foliage type failed',
57
+ note: coerceString(response.result?.note)
58
+ };
59
+ }
60
+ const payload = response.result;
61
+ const created = coerceBoolean(payload.created, false) ?? false;
62
+ const exists = coerceBoolean(payload.exists_after, false) ?? created;
63
+ const method = coerceString(payload.method) ?? 'Unknown';
64
+ const assetPath = coerceString(payload.asset_path);
65
+ const usedMesh = coerceString(payload.used_mesh);
66
+ const note = coerceString(payload.note);
67
+ return {
68
+ success: true,
69
+ created,
70
+ exists,
71
+ method,
72
+ assetPath,
73
+ usedMesh,
74
+ note,
75
+ message: exists
76
+ ? `Foliage type '${name}' ready (${method})`
77
+ : `Created foliage '${name}' but verification did not find it yet`
78
+ };
79
+ }
80
+ catch (error) {
199
81
  return {
200
82
  success: false,
201
- error: coerceString(interpreted.payload.note) ?? interpreted.error ?? 'Add foliage type failed',
202
- note: coerceString(interpreted.payload.note) ?? bestEffortInterpretedText(interpreted)
83
+ error: `Failed to add foliage type: ${error instanceof Error ? error.message : String(error)}`
203
84
  };
204
85
  }
205
- const payload = interpreted.payload;
206
- const created = coerceBoolean(payload.created, false) ?? false;
207
- const exists = coerceBoolean(payload.exists_after, false) ?? created;
208
- const method = coerceString(payload.method) ?? 'Unknown';
209
- const assetPath = coerceString(payload.asset_path);
210
- const usedMesh = coerceString(payload.used_mesh);
211
- const note = coerceString(payload.note);
212
- return {
213
- success: true,
214
- created,
215
- exists,
216
- method,
217
- assetPath,
218
- usedMesh,
219
- note,
220
- message: exists
221
- ? `Foliage type '${name}' ready (${method})`
222
- : `Created foliage '${name}' but verification did not find it yet`
223
- };
224
86
  }
225
- // Paint foliage by placing HISM instances (editor-only)
226
87
  async paintFoliage(params) {
227
88
  const errors = [];
228
89
  const foliageType = String(params?.foliageType ?? '').trim();
@@ -246,131 +107,90 @@ print('RESULT:' + json.dumps(res))
246
107
  if (errors.length > 0) {
247
108
  return { success: false, error: errors.join('; ') };
248
109
  }
249
- const brush = Number.isFinite(params.brushSize) ? params.brushSize : 300;
250
- const py = `
251
- import unreal, json, random, math
252
-
253
- res = {'success': False, 'added': 0, 'actor': '', 'component': '', 'used_mesh': '', 'note': ''}
254
- foliage_type_name = ${JSON.stringify(foliageType)}
255
- px, py, pz = ${pos[0]}, ${pos[1]}, ${pos[2]}
256
- radius = float(${brush}) / 2.0
257
-
258
- try:
259
- actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
260
- if not actor_subsystem:
261
- raise RuntimeError('EditorActorSubsystem unavailable. Enable Editor Scripting Utilities plugin.')
262
-
263
- all_actors = actor_subsystem.get_all_level_actors()
264
-
265
- # Find or create a container actor using modern EditorActorSubsystem
266
- label = f"FoliageContainer_{foliage_type_name}"
267
- container = None
268
- for a in all_actors:
269
- try:
270
- if a and a.get_actor_label() == label:
271
- container = a
272
- break
273
- except Exception:
274
- pass
275
-
276
- if not container:
277
- container = actor_subsystem.spawn_actor_from_class(
278
- unreal.StaticMeshActor,
279
- unreal.Vector(px, py, pz)
280
- )
281
- if not container:
282
- raise RuntimeError('Failed to spawn foliage container actor via EditorActorSubsystem')
283
- try:
284
- container.set_actor_label(label)
285
- except Exception:
286
- pass
287
-
288
- # Resolve mesh from FoliageType asset
289
- mesh = None
290
- fol_asset_path = f"/Game/Foliage/Types/{foliage_type_name}.{foliage_type_name}"
291
- if unreal.EditorAssetLibrary.does_asset_exist(fol_asset_path):
292
- try:
293
- ft_asset = unreal.EditorAssetLibrary.load_asset(fol_asset_path)
294
- mesh = ft_asset.get_editor_property('mesh')
295
- except Exception:
296
- mesh = None
297
-
298
- if not mesh:
299
- mesh = unreal.EditorAssetLibrary.load_asset('/Engine/EngineMeshes/Sphere')
300
- res['note'] += '; used_fallback_mesh'
301
-
302
- if mesh:
303
- res['used_mesh'] = str(mesh.get_path_name())
304
-
305
- # Since HISM components and add_component don't work in this version,
306
- # spawn individual StaticMeshActors for each instance
307
- target_count = max(5, int(radius / 20.0))
308
- added = 0
309
- for i in range(target_count):
310
- ang = random.random() * math.tau
311
- r = random.random() * radius
312
- x, y, z = px + math.cos(ang) * r, py + math.sin(ang) * r, pz
313
- try:
314
- # Spawn static mesh actor at position using modern subsystem
315
- inst_actor = actor_subsystem.spawn_actor_from_class(
316
- unreal.StaticMeshActor,
317
- unreal.Vector(x, y, z),
318
- unreal.Rotator(0, random.random()*360.0, 0)
319
- )
320
- if inst_actor and mesh:
321
- # Set mesh on the actor's component
322
- try:
323
- mesh_comp = inst_actor.static_mesh_component
324
- if mesh_comp:
325
- mesh_comp.set_static_mesh(mesh)
326
- inst_actor.set_actor_label(f"{foliage_type_name}_instance_{i}")
327
- # Group under the container for organization
328
- inst_actor.attach_to_actor(container, "", unreal.AttachmentRule.KEEP_WORLD, unreal.AttachmentRule.KEEP_WORLD, unreal.AttachmentRule.KEEP_WORLD, False)
329
- added += 1
330
- except Exception as e:
331
- res['note'] += f"; instance_{i} setup failed: {e}"
332
- except Exception as e:
333
- res['note'] += f"; spawn instance_{i} failed: {e}"
334
-
335
- res['added'] = added
336
- res['actor'] = container.get_actor_label()
337
- res['component'] = 'StaticMeshActors' # Using actors instead of components
338
- res['success'] = True
339
- except Exception as e:
340
- res['success'] = False
341
- res['note'] += f"; fatal: {e}"
342
-
343
- print('RESULT:' + json.dumps(res))
344
- `.trim();
345
- const pyResp = await this.bridge.executePython(py);
346
- const interpreted = interpretStandardResult(pyResp, {
347
- successMessage: `Painted foliage for '${foliageType}'`,
348
- failureMessage: 'Paint foliage failed'
349
- });
350
- if (!interpreted.success) {
110
+ if (!this.automationBridge) {
111
+ throw new Error('Automation Bridge not available. Foliage operations require plugin support.');
112
+ }
113
+ try {
114
+ const typePath = foliageType.includes('/') ? foliageType : `/Game/Foliage/${foliageType}.${foliageType}`;
115
+ const response = await this.automationBridge.sendAutomationRequest('paint_foliage', {
116
+ foliageTypePath: typePath,
117
+ locations: [{ x: pos[0], y: pos[1], z: pos[2] }],
118
+ brushSize: Number.isFinite(params.brushSize) ? params.brushSize : 300,
119
+ paintDensity: params.paintDensity,
120
+ eraseMode: params.eraseMode
121
+ }, {
122
+ timeoutMs: 60000
123
+ });
124
+ if (response.success === false) {
125
+ return {
126
+ success: false,
127
+ error: response.error || response.message || 'Paint foliage failed',
128
+ note: coerceString(response.result?.note)
129
+ };
130
+ }
131
+ const payload = response.result;
132
+ const added = coerceNumber(payload.instancesPlaced) ?? coerceNumber(payload?.count) ?? 0;
133
+ const note = coerceString(payload.note);
134
+ return {
135
+ success: true,
136
+ added,
137
+ note,
138
+ message: `Painted ${added} instances for '${foliageType}' around (${pos[0]}, ${pos[1]}, ${pos[2]})`
139
+ };
140
+ }
141
+ catch (error) {
351
142
  return {
352
143
  success: false,
353
- error: coerceString(interpreted.payload.note) ?? interpreted.error ?? 'Paint foliage failed',
354
- note: coerceString(interpreted.payload.note) ?? bestEffortInterpretedText(interpreted)
144
+ error: `Failed to paint foliage: ${error instanceof Error ? error.message : String(error)}`
355
145
  };
356
146
  }
357
- const payload = interpreted.payload;
358
- const added = coerceNumber(payload.added) ?? 0;
359
- const actor = coerceString(payload.actor);
360
- const component = coerceString(payload.component);
361
- const usedMesh = coerceString(payload.used_mesh);
362
- const note = coerceString(payload.note);
363
- return {
364
- success: true,
365
- added,
366
- actor,
367
- component,
368
- usedMesh,
369
- note,
370
- message: `Painted ${added} instances for '${foliageType}' around (${pos[0]}, ${pos[1]}, ${pos[2]})`
371
- };
372
147
  }
373
- // Create instanced mesh
148
+ async getFoliageInstances(params) {
149
+ if (!this.automationBridge) {
150
+ throw new Error('Automation Bridge not available. Foliage operations require plugin support.');
151
+ }
152
+ try {
153
+ const typePath = params.foliageType ? (params.foliageType.includes('/') ? params.foliageType : `/Game/Foliage/${params.foliageType}.${params.foliageType}`) : undefined;
154
+ const response = await this.automationBridge.sendAutomationRequest('get_foliage_instances', {
155
+ foliageTypePath: typePath
156
+ }, { timeoutMs: 60000 });
157
+ if (response.success === false) {
158
+ return { success: false, error: response.error || response.message || 'Get foliage instances failed' };
159
+ }
160
+ const payload = response.result;
161
+ return {
162
+ success: true,
163
+ count: coerceNumber(payload.count) ?? 0,
164
+ instances: payload.instances ?? []
165
+ };
166
+ }
167
+ catch (error) {
168
+ return { success: false, error: `Failed to get foliage instances: ${error instanceof Error ? error.message : String(error)}` };
169
+ }
170
+ }
171
+ async removeFoliage(params) {
172
+ if (!this.automationBridge) {
173
+ throw new Error('Automation Bridge not available. Foliage operations require plugin support.');
174
+ }
175
+ try {
176
+ const typePath = params.foliageType ? (params.foliageType.includes('/') ? params.foliageType : `/Game/Foliage/${params.foliageType}.${params.foliageType}`) : undefined;
177
+ const response = await this.automationBridge.sendAutomationRequest('remove_foliage', {
178
+ foliageTypePath: typePath,
179
+ removeAll: !!params.removeAll
180
+ }, { timeoutMs: 60000 });
181
+ if (response.success === false) {
182
+ return { success: false, error: response.error || response.message || 'Remove foliage failed' };
183
+ }
184
+ const payload = response.result;
185
+ return {
186
+ success: true,
187
+ instancesRemoved: coerceNumber(payload.instancesRemoved) ?? 0
188
+ };
189
+ }
190
+ catch (error) {
191
+ return { success: false, error: `Failed to remove foliage: ${error instanceof Error ? error.message : String(error)}` };
192
+ }
193
+ }
374
194
  async createInstancedMesh(params) {
375
195
  const commands = [];
376
196
  commands.push(`CreateInstancedStaticMesh ${params.name} ${params.meshPath}`);
@@ -388,7 +208,6 @@ print('RESULT:' + json.dumps(res))
388
208
  await this.bridge.executeConsoleCommands(commands);
389
209
  return { success: true, message: `Instanced mesh ${params.name} created with ${params.instances.length} instances` };
390
210
  }
391
- // Set foliage LOD
392
211
  async setFoliageLOD(params) {
393
212
  const commands = [];
394
213
  if (params.lodDistances) {
@@ -400,24 +219,99 @@ print('RESULT:' + json.dumps(res))
400
219
  await this.bridge.executeConsoleCommands(commands);
401
220
  return { success: true, message: 'Foliage LOD settings updated' };
402
221
  }
403
- // Create procedural foliage
222
+ async addFoliage(params) {
223
+ if (params.locations && params.locations.length > 0) {
224
+ if (!this.automationBridge) {
225
+ throw new Error('Automation Bridge not available.');
226
+ }
227
+ const response = await this.automationBridge.sendAutomationRequest('paint_foliage', {
228
+ foliageTypePath: params.foliageType.includes('/') ? params.foliageType : `/Game/Foliage/${params.foliageType}.${params.foliageType}`,
229
+ locations: params.locations,
230
+ brushSize: 0,
231
+ paintDensity: 1,
232
+ eraseMode: false
233
+ });
234
+ if (!response.success) {
235
+ return { success: false, error: response.error || 'Failed to add foliage instances' };
236
+ }
237
+ return { success: true, message: `Added ${params.locations.length} foliage instances` };
238
+ }
239
+ return { success: true, message: 'No locations provided for addFoliage' };
240
+ }
404
241
  async createProceduralFoliage(params) {
405
- const commands = [];
406
- commands.push(`CreateProceduralFoliageVolume ${params.volumeName} ${params.position.join(' ')} ${params.size.join(' ')}`);
407
- for (const type of params.foliageTypes) {
408
- commands.push(`AddProceduralFoliageType ${params.volumeName} ${type}`);
242
+ if (!this.automationBridge) {
243
+ throw new Error('Automation Bridge not available.');
244
+ }
245
+ const volName = params.volumeName || params.name || 'ProceduralFoliageVolume';
246
+ const loc = params.bounds?.location ? [params.bounds.location.x, params.bounds.location.y, params.bounds.location.z] : (params.position || [0, 0, 0]);
247
+ const size = params.bounds?.size ? [params.bounds.size.x, params.bounds.size.y, params.bounds.size.z] : (params.size || [1000, 1000, 100]);
248
+ const foliageTypes = Array.isArray(params.foliageTypes)
249
+ ? params.foliageTypes.map(t => {
250
+ if (typeof t === 'string')
251
+ return { meshPath: t, density: 0.5 };
252
+ return t;
253
+ })
254
+ : [];
255
+ const payload = {
256
+ name: volName,
257
+ bounds: {
258
+ location: { x: loc[0], y: loc[1], z: loc[2] },
259
+ size: { x: size[0], y: size[1], z: size[2] }
260
+ },
261
+ foliageTypes,
262
+ seed: params.seed ?? 42,
263
+ tileSize: params.tileSize ?? 1000
264
+ };
265
+ const response = await this.automationBridge.sendAutomationRequest('create_procedural_foliage', payload);
266
+ if (!response.success) {
267
+ return {
268
+ success: false,
269
+ error: response.error || 'Failed to create procedural foliage'
270
+ };
409
271
  }
410
- if (params.seed !== undefined) {
411
- commands.push(`SetProceduralSeed ${params.volumeName} ${params.seed}`);
272
+ const result = response.result;
273
+ return {
274
+ success: true,
275
+ message: `Procedural foliage volume ${volName} created`,
276
+ details: response,
277
+ volumeActor: result?.volume_actor,
278
+ spawnerPath: result?.spawner_path,
279
+ foliageTypesCount: result?.foliage_types_count
280
+ };
281
+ }
282
+ async addFoliageInstances(params) {
283
+ if (!this.automationBridge) {
284
+ throw new Error('Automation Bridge not available. Foliage instance placement requires plugin support.');
285
+ }
286
+ try {
287
+ const typePath = params.foliageType.includes('/') ? params.foliageType : `/Game/Foliage/${params.foliageType}.${params.foliageType}`;
288
+ const response = await this.automationBridge.sendAutomationRequest('add_foliage_instances', {
289
+ foliageType: typePath,
290
+ transforms: params.transforms
291
+ }, {
292
+ timeoutMs: 120000
293
+ });
294
+ if (response.success === false) {
295
+ return {
296
+ success: false,
297
+ error: response.error || response.message || 'Failed to add foliage instances',
298
+ message: response.message || 'Failed to add foliage instances'
299
+ };
300
+ }
301
+ const result = response.result;
302
+ return {
303
+ success: true,
304
+ message: response.message || `Added ${result?.instances_count || params.transforms.length} foliage instances`,
305
+ instancesCount: result?.instances_count
306
+ };
412
307
  }
413
- if (params.tileSize !== undefined) {
414
- commands.push(`SetProceduralTileSize ${params.volumeName} ${params.tileSize}`);
308
+ catch (error) {
309
+ return {
310
+ success: false,
311
+ error: `Failed to add foliage instances: ${error instanceof Error ? error.message : String(error)}`
312
+ };
415
313
  }
416
- commands.push(`GenerateProceduralFoliage ${params.volumeName}`);
417
- await this.bridge.executeConsoleCommands(commands);
418
- return { success: true, message: `Procedural foliage volume ${params.volumeName} created` };
419
314
  }
420
- // Set foliage collision
421
315
  async setFoliageCollision(params) {
422
316
  const commands = [];
423
317
  if (params.collisionEnabled !== undefined) {
@@ -432,7 +326,6 @@ print('RESULT:' + json.dumps(res))
432
326
  await this.bridge.executeConsoleCommands(commands);
433
327
  return { success: true, message: 'Foliage collision settings updated' };
434
328
  }
435
- // Create grass system
436
329
  async createGrassSystem(params) {
437
330
  const commands = [];
438
331
  commands.push(`CreateGrassSystem ${params.name}`);
@@ -450,12 +343,10 @@ print('RESULT:' + json.dumps(res))
450
343
  await this.bridge.executeConsoleCommands(commands);
451
344
  return { success: true, message: `Grass system ${params.name} created` };
452
345
  }
453
- // Remove foliage instances
454
346
  async removeFoliageInstances(params) {
455
347
  const command = `RemoveFoliageInRadius ${params.foliageType} ${params.position.join(' ')} ${params.radius}`;
456
348
  return this.bridge.executeConsoleCommand(command);
457
349
  }
458
- // Select foliage instances
459
350
  async selectFoliageInstances(params) {
460
351
  let command;
461
352
  if (params.selectAll) {
@@ -469,7 +360,6 @@ print('RESULT:' + json.dumps(res))
469
360
  }
470
361
  return this.bridge.executeConsoleCommand(command);
471
362
  }
472
- // Update foliage instances
473
363
  async updateFoliageInstances(params) {
474
364
  const commands = [];
475
365
  if (params.updateTransforms) {
@@ -482,7 +372,6 @@ print('RESULT:' + json.dumps(res))
482
372
  await this.bridge.executeConsoleCommands(commands);
483
373
  return { success: true, message: 'Foliage instances updated' };
484
374
  }
485
- // Create foliage spawner
486
375
  async createFoliageSpawner(params) {
487
376
  const commands = [];
488
377
  commands.push(`CreateFoliageSpawner ${params.name} ${params.spawnArea}`);
@@ -494,7 +383,6 @@ print('RESULT:' + json.dumps(res))
494
383
  await this.bridge.executeConsoleCommands(commands);
495
384
  return { success: true, message: `Foliage spawner ${params.name} created` };
496
385
  }
497
- // Optimize foliage
498
386
  async optimizeFoliage(params) {
499
387
  const commands = [];
500
388
  if (params.mergeInstances) {
@@ -0,0 +1,3 @@
1
+ import { ITools } from '../../types/tool-interfaces.js';
2
+ export declare function handleActorTools(action: string, args: any, tools: ITools): Promise<any>;
3
+ //# sourceMappingURL=actor-handlers.d.ts.map