unreal-engine-mcp-server 0.4.6 → 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 +269 -22
  29. package/CONTRIBUTING.md +140 -0
  30. package/README.md +166 -72
  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 -604
  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 +5475 -1627
  97. package/dist/tools/consolidated-tool-definitions.js +829 -482
  98. package/dist/tools/consolidated-tool-handlers.d.ts +2 -1
  99. package/dist/tools/consolidated-tool-handlers.js +211 -1009
  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 +45 -0
  161. package/dist/tools/logs.js +210 -0
  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 +195 -11
  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 -649
  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 -500
  316. package/src/tools/consolidated-tool-handlers.ts +272 -1122
  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 +219 -0
  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 +250 -13
  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 -572
  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
@@ -0,0 +1,625 @@
1
+ #include "McpAutomationBridgeGlobals.h"
2
+ #include "McpAutomationBridgeHelpers.h"
3
+ #include "McpAutomationBridgeSubsystem.h"
4
+
5
+ #if WITH_EDITOR
6
+ #include "AssetRegistry/AssetRegistryModule.h"
7
+ #include "AssetToolsModule.h"
8
+ #include "Async/Async.h"
9
+ #include "EditorAssetLibrary.h"
10
+ #include "Engine/World.h"
11
+ #include "Modules/ModuleManager.h"
12
+ #include "NiagaraActor.h"
13
+ #include "NiagaraComponent.h"
14
+ #include "NiagaraEmitter.h"
15
+ #include "NiagaraEmitterFactoryNew.h"
16
+ #include "NiagaraParameterCollection.h"
17
+ #include "NiagaraScriptFactoryNew.h"
18
+ #include "NiagaraSystem.h"
19
+ #include "NiagaraSystemFactoryNew.h"
20
+ #if __has_include("Subsystems/EditorActorSubsystem.h")
21
+ #include "Subsystems/EditorActorSubsystem.h"
22
+ #elif __has_include("EditorActorSubsystem.h")
23
+ #include "EditorActorSubsystem.h"
24
+ #endif
25
+ #endif
26
+
27
+ #if WITH_EDITOR
28
+ #include "AssetRegistry/AssetRegistryModule.h"
29
+ #include "AssetToolsModule.h"
30
+ #include "Async/Async.h"
31
+ #include "EditorAssetLibrary.h"
32
+ #include "Engine/World.h"
33
+ #include "Modules/ModuleManager.h"
34
+ #include "NiagaraActor.h"
35
+ #include "NiagaraComponent.h"
36
+ #include "NiagaraEmitter.h"
37
+ #include "NiagaraEmitterFactoryNew.h"
38
+ #include "NiagaraParameterCollection.h"
39
+ #include "NiagaraScriptFactoryNew.h"
40
+ #include "NiagaraSystem.h"
41
+ #include "NiagaraSystemFactoryNew.h"
42
+ #if __has_include("Subsystems/EditorActorSubsystem.h")
43
+ #include "Subsystems/EditorActorSubsystem.h"
44
+ #elif __has_include("EditorActorSubsystem.h")
45
+ #include "EditorActorSubsystem.h"
46
+ #endif
47
+ #endif
48
+
49
+ bool UMcpAutomationBridgeSubsystem::HandleCreateNiagaraSystem(
50
+ const FString &RequestId, const FString &Action,
51
+ const TSharedPtr<FJsonObject> &Payload,
52
+ TSharedPtr<FMcpBridgeWebSocket> RequestingSocket) {
53
+ const FString Lower = Action.ToLower();
54
+ if (!Lower.Equals(TEXT("create_niagara_system"), ESearchCase::IgnoreCase)) {
55
+ return false;
56
+ }
57
+
58
+ #if WITH_EDITOR
59
+ if (!Payload.IsValid()) {
60
+ SendAutomationError(RequestingSocket, RequestId,
61
+ TEXT("create_niagara_system payload missing"),
62
+ TEXT("INVALID_PAYLOAD"));
63
+ return true;
64
+ }
65
+
66
+ FString SystemName;
67
+ if (!Payload->TryGetStringField(TEXT("name"), SystemName) ||
68
+ SystemName.IsEmpty()) {
69
+ SendAutomationError(RequestingSocket, RequestId, TEXT("name required"),
70
+ TEXT("INVALID_ARGUMENT"));
71
+ return true;
72
+ }
73
+
74
+ FString SavePath;
75
+ if (!Payload->TryGetStringField(TEXT("savePath"), SavePath) ||
76
+ SavePath.IsEmpty()) {
77
+ SendAutomationError(RequestingSocket, RequestId, TEXT("savePath required"),
78
+ TEXT("INVALID_ARGUMENT"));
79
+ return true;
80
+ }
81
+
82
+ // Check for Niagara plugin availability via module system
83
+ // Previous check for asset existence failed even when Niagara was enabled
84
+ // because it was looking for engine content which requires "Show Engine
85
+ // Content" in Content Browser
86
+ if (!FModuleManager::Get().IsModuleLoaded(TEXT("Niagara"))) {
87
+ SendAutomationError(RequestingSocket, RequestId,
88
+ TEXT("Niagara plugin module is not loaded. Please "
89
+ "enable and restart the editor."),
90
+ TEXT("DEPENDENCY_MISSING"));
91
+ return true;
92
+ }
93
+
94
+ UNiagaraSystemFactoryNew *Factory = NewObject<UNiagaraSystemFactoryNew>();
95
+ if (!Factory) {
96
+ SendAutomationError(RequestingSocket, RequestId,
97
+ TEXT("Failed to create Niagara system factory"),
98
+ TEXT("FACTORY_FAILED"));
99
+ return true;
100
+ }
101
+
102
+ FString PackagePath = SavePath;
103
+ FString AssetName = SystemName;
104
+ FAssetToolsModule &AssetToolsModule =
105
+ FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
106
+ UObject *NewAsset = AssetToolsModule.Get().CreateAsset(
107
+ AssetName, PackagePath, UNiagaraSystem::StaticClass(), Factory);
108
+ UNiagaraSystem *NiagaraSystem = Cast<UNiagaraSystem>(NewAsset);
109
+
110
+ if (!NiagaraSystem) {
111
+ SendAutomationError(RequestingSocket, RequestId,
112
+ TEXT("Failed to create Niagara system asset"),
113
+ TEXT("ASSET_CREATION_FAILED"));
114
+ return true;
115
+ }
116
+
117
+ UEditorAssetLibrary::SaveAsset(NiagaraSystem->GetPathName());
118
+
119
+ TSharedPtr<FJsonObject> Resp = MakeShared<FJsonObject>();
120
+ Resp->SetBoolField(TEXT("success"), true);
121
+ Resp->SetStringField(TEXT("systemPath"), NiagaraSystem->GetPathName());
122
+ Resp->SetStringField(TEXT("systemName"), SystemName);
123
+
124
+ SendAutomationResponse(RequestingSocket, RequestId, true,
125
+ TEXT("Niagara system created successfully"), Resp,
126
+ FString());
127
+ return true;
128
+ #else
129
+ SendAutomationResponse(RequestingSocket, RequestId, false,
130
+ TEXT("create_niagara_system requires editor build"),
131
+ nullptr, TEXT("NOT_IMPLEMENTED"));
132
+ return true;
133
+ #endif
134
+ }
135
+
136
+ bool UMcpAutomationBridgeSubsystem::HandleCreateNiagaraEmitter(
137
+ const FString &RequestId, const FString &Action,
138
+ const TSharedPtr<FJsonObject> &Payload,
139
+ TSharedPtr<FMcpBridgeWebSocket> RequestingSocket) {
140
+ const FString Lower = Action.ToLower();
141
+ if (!Lower.Equals(TEXT("create_niagara_emitter"), ESearchCase::IgnoreCase)) {
142
+ return false;
143
+ }
144
+
145
+ #if WITH_EDITOR
146
+ if (!Payload.IsValid()) {
147
+ SendAutomationError(RequestingSocket, RequestId,
148
+ TEXT("create_niagara_emitter payload missing"),
149
+ TEXT("INVALID_PAYLOAD"));
150
+ return true;
151
+ }
152
+
153
+ FString EmitterName;
154
+ if (!Payload->TryGetStringField(TEXT("name"), EmitterName) ||
155
+ EmitterName.IsEmpty()) {
156
+ SendAutomationError(RequestingSocket, RequestId, TEXT("name required"),
157
+ TEXT("INVALID_ARGUMENT"));
158
+ return true;
159
+ }
160
+
161
+ FString SavePath;
162
+ if (!Payload->TryGetStringField(TEXT("savePath"), SavePath) ||
163
+ SavePath.IsEmpty()) {
164
+ SendAutomationError(RequestingSocket, RequestId, TEXT("savePath required"),
165
+ TEXT("INVALID_ARGUMENT"));
166
+ return true;
167
+ }
168
+
169
+ // Check for Niagara plugin availability via module system
170
+ if (!FModuleManager::Get().IsModuleLoaded(TEXT("Niagara"))) {
171
+ SendAutomationError(RequestingSocket, RequestId,
172
+ TEXT("Niagara plugin module is not loaded. Please "
173
+ "enable and restart the editor."),
174
+ TEXT("DEPENDENCY_MISSING"));
175
+ return true;
176
+ }
177
+
178
+ UNiagaraEmitterFactoryNew *Factory = NewObject<UNiagaraEmitterFactoryNew>();
179
+ if (!Factory) {
180
+ SendAutomationError(RequestingSocket, RequestId,
181
+ TEXT("Failed to create Niagara emitter factory"),
182
+ TEXT("FACTORY_FAILED"));
183
+ return true;
184
+ }
185
+
186
+ FString PackagePath = SavePath;
187
+ FString AssetName = EmitterName;
188
+ FAssetToolsModule &AssetToolsModule =
189
+ FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
190
+ UObject *NewAsset = AssetToolsModule.Get().CreateAsset(
191
+ AssetName, PackagePath, UNiagaraEmitter::StaticClass(), Factory);
192
+ UNiagaraEmitter *NiagaraEmitter = Cast<UNiagaraEmitter>(NewAsset);
193
+
194
+ if (!NiagaraEmitter) {
195
+ SendAutomationError(RequestingSocket, RequestId,
196
+ TEXT("Failed to create Niagara emitter asset"),
197
+ TEXT("ASSET_CREATION_FAILED"));
198
+ return true;
199
+ }
200
+
201
+ UEditorAssetLibrary::SaveAsset(NiagaraEmitter->GetPathName());
202
+
203
+ TSharedPtr<FJsonObject> Resp = MakeShared<FJsonObject>();
204
+ Resp->SetBoolField(TEXT("success"), true);
205
+ Resp->SetStringField(TEXT("emitterPath"), NiagaraEmitter->GetPathName());
206
+ Resp->SetStringField(TEXT("emitterName"), EmitterName);
207
+
208
+ SendAutomationResponse(RequestingSocket, RequestId, true,
209
+ TEXT("Niagara emitter created successfully"), Resp,
210
+ FString());
211
+ return true;
212
+ #else
213
+ SendAutomationResponse(RequestingSocket, RequestId, false,
214
+ TEXT("create_niagara_emitter requires editor build"),
215
+ nullptr, TEXT("NOT_IMPLEMENTED"));
216
+ return true;
217
+ #endif
218
+ }
219
+
220
+ bool UMcpAutomationBridgeSubsystem::HandleSpawnNiagaraActor(
221
+ const FString &RequestId, const FString &Action,
222
+ const TSharedPtr<FJsonObject> &Payload,
223
+ TSharedPtr<FMcpBridgeWebSocket> RequestingSocket) {
224
+ const FString Lower = Action.ToLower();
225
+ if (!Lower.Equals(TEXT("spawn_niagara_actor"), ESearchCase::IgnoreCase)) {
226
+ return false;
227
+ }
228
+
229
+ #if WITH_EDITOR
230
+ if (!Payload.IsValid()) {
231
+ SendAutomationError(RequestingSocket, RequestId,
232
+ TEXT("spawn_niagara_actor payload missing"),
233
+ TEXT("INVALID_PAYLOAD"));
234
+ return true;
235
+ }
236
+
237
+ FString SystemPath;
238
+ if (!Payload->TryGetStringField(TEXT("systemPath"), SystemPath) ||
239
+ SystemPath.IsEmpty()) {
240
+ SendAutomationError(RequestingSocket, RequestId,
241
+ TEXT("systemPath required"), TEXT("INVALID_ARGUMENT"));
242
+ return true;
243
+ }
244
+
245
+ double X = 0.0, Y = 0.0, Z = 0.0;
246
+ const TSharedPtr<FJsonObject> *LocationObj = nullptr;
247
+ if (Payload->TryGetObjectField(TEXT("location"), LocationObj) &&
248
+ LocationObj) {
249
+ (*LocationObj)->TryGetNumberField(TEXT("x"), X);
250
+ (*LocationObj)->TryGetNumberField(TEXT("y"), Y);
251
+ (*LocationObj)->TryGetNumberField(TEXT("z"), Z);
252
+ }
253
+
254
+ FString ActorName;
255
+ Payload->TryGetStringField(TEXT("name"), ActorName);
256
+
257
+ if (!GEditor || !GEditor->GetEditorWorldContext().World()) {
258
+ SendAutomationError(RequestingSocket, RequestId,
259
+ TEXT("Editor world not available"),
260
+ TEXT("EDITOR_NOT_AVAILABLE"));
261
+ return true;
262
+ }
263
+
264
+ UWorld *World = GEditor->GetEditorWorldContext().World();
265
+
266
+ if (!UEditorAssetLibrary::DoesAssetExist(SystemPath)) {
267
+ SendAutomationResponse(
268
+ RequestingSocket, RequestId, false,
269
+ FString::Printf(TEXT("Niagara system asset not found: %s"),
270
+ *SystemPath),
271
+ nullptr, TEXT("ASSET_NOT_FOUND"));
272
+ return true;
273
+ }
274
+
275
+ UNiagaraSystem *NiagaraSystem =
276
+ LoadObject<UNiagaraSystem>(nullptr, *SystemPath);
277
+ if (!NiagaraSystem) {
278
+ SendAutomationError(RequestingSocket, RequestId,
279
+ TEXT("Failed to load Niagara system"),
280
+ TEXT("LOAD_FAILED"));
281
+ return true;
282
+ }
283
+
284
+ FVector Location(X, Y, Z);
285
+ ANiagaraActor *NiagaraActor = World->SpawnActor<ANiagaraActor>(
286
+ ANiagaraActor::StaticClass(), Location, FRotator::ZeroRotator);
287
+
288
+ if (!NiagaraActor) {
289
+ SendAutomationError(RequestingSocket, RequestId,
290
+ TEXT("Failed to spawn Niagara actor"),
291
+ TEXT("SPAWN_FAILED"));
292
+ return true;
293
+ }
294
+
295
+ if (NiagaraActor->GetNiagaraComponent()) {
296
+ NiagaraActor->GetNiagaraComponent()->SetAsset(NiagaraSystem);
297
+ }
298
+
299
+ if (!ActorName.IsEmpty()) {
300
+ NiagaraActor->SetActorLabel(ActorName);
301
+ } else {
302
+ NiagaraActor->SetActorLabel(
303
+ FString::Printf(TEXT("NiagaraActor_%s"),
304
+ *FGuid::NewGuid().ToString(EGuidFormats::Short)));
305
+ }
306
+
307
+ TSharedPtr<FJsonObject> Resp = MakeShared<FJsonObject>();
308
+ Resp->SetBoolField(TEXT("success"), true);
309
+ Resp->SetStringField(TEXT("actorPath"), NiagaraActor->GetPathName());
310
+ Resp->SetStringField(TEXT("actorName"), NiagaraActor->GetActorLabel());
311
+ Resp->SetStringField(TEXT("systemPath"), SystemPath);
312
+
313
+ SendAutomationResponse(RequestingSocket, RequestId, true,
314
+ TEXT("Niagara actor spawned successfully"), Resp,
315
+ FString());
316
+ return true;
317
+ #else
318
+ SendAutomationResponse(RequestingSocket, RequestId, false,
319
+ TEXT("spawn_niagara_actor requires editor build"),
320
+ nullptr, TEXT("NOT_IMPLEMENTED"));
321
+ return true;
322
+ #endif
323
+ }
324
+
325
+ bool UMcpAutomationBridgeSubsystem::HandleModifyNiagaraParameter(
326
+ const FString &RequestId, const FString &Action,
327
+ const TSharedPtr<FJsonObject> &Payload,
328
+ TSharedPtr<FMcpBridgeWebSocket> RequestingSocket) {
329
+ const FString Lower = Action.ToLower();
330
+ if (!Lower.Equals(TEXT("modify_niagara_parameter"),
331
+ ESearchCase::IgnoreCase)) {
332
+ return false;
333
+ }
334
+
335
+ #if WITH_EDITOR
336
+ if (!Payload.IsValid()) {
337
+ SendAutomationError(RequestingSocket, RequestId,
338
+ TEXT("modify_niagara_parameter payload missing"),
339
+ TEXT("INVALID_PAYLOAD"));
340
+ return true;
341
+ }
342
+
343
+ FString ActorName;
344
+ if (!Payload->TryGetStringField(TEXT("actorName"), ActorName) ||
345
+ ActorName.IsEmpty()) {
346
+ SendAutomationError(RequestingSocket, RequestId, TEXT("actorName required"),
347
+ TEXT("INVALID_ARGUMENT"));
348
+ return true;
349
+ }
350
+
351
+ FString ParameterName;
352
+ if (!Payload->TryGetStringField(TEXT("parameterName"), ParameterName) ||
353
+ ParameterName.IsEmpty()) {
354
+ SendAutomationError(RequestingSocket, RequestId,
355
+ TEXT("parameterName required"),
356
+ TEXT("INVALID_ARGUMENT"));
357
+ return true;
358
+ }
359
+
360
+ FString ParameterType;
361
+ if (!Payload->TryGetStringField(TEXT("parameterType"), ParameterType)) {
362
+ Payload->TryGetStringField(TEXT("type"), ParameterType);
363
+ }
364
+ if (ParameterType.IsEmpty())
365
+ ParameterType = TEXT("Float");
366
+
367
+ if (!GEditor || !GEditor->GetEditorWorldContext().World()) {
368
+ SendAutomationError(RequestingSocket, RequestId,
369
+ TEXT("Editor world not available"),
370
+ TEXT("EDITOR_NOT_AVAILABLE"));
371
+ return true;
372
+ }
373
+
374
+ UEditorActorSubsystem *ActorSS =
375
+ GEditor->GetEditorSubsystem<UEditorActorSubsystem>();
376
+ if (!ActorSS) {
377
+ SendAutomationError(RequestingSocket, RequestId,
378
+ TEXT("EditorActorSubsystem not available"),
379
+ TEXT("EDITOR_ACTOR_SUBSYSTEM_MISSING"));
380
+ return true;
381
+ }
382
+
383
+ TArray<AActor *> AllActors = ActorSS->GetAllLevelActors();
384
+ ANiagaraActor *NiagaraActor = nullptr;
385
+
386
+ for (AActor *Actor : AllActors) {
387
+ if (Actor &&
388
+ Actor->GetActorLabel().Equals(ActorName, ESearchCase::IgnoreCase)) {
389
+ NiagaraActor = Cast<ANiagaraActor>(Actor);
390
+ if (NiagaraActor)
391
+ break;
392
+ }
393
+ }
394
+
395
+ if (!NiagaraActor || !NiagaraActor->GetNiagaraComponent()) {
396
+ SendAutomationError(RequestingSocket, RequestId,
397
+ TEXT("Niagara actor not found"),
398
+ TEXT("ACTOR_NOT_FOUND"));
399
+ return true;
400
+ }
401
+
402
+ UNiagaraComponent *NiagaraComp = NiagaraActor->GetNiagaraComponent();
403
+ bool bSuccess = false;
404
+
405
+ if (ParameterType.Equals(TEXT("Float"), ESearchCase::IgnoreCase)) {
406
+ double Value = 0.0;
407
+ if (Payload->TryGetNumberField(TEXT("value"), Value)) {
408
+ NiagaraComp->SetFloatParameter(FName(*ParameterName),
409
+ static_cast<float>(Value));
410
+ bSuccess = true;
411
+ }
412
+ } else if (ParameterType.Equals(TEXT("Vector"), ESearchCase::IgnoreCase)) {
413
+ const TSharedPtr<FJsonObject> *VectorObj = nullptr;
414
+ const TArray<TSharedPtr<FJsonValue>> *VectorArr = nullptr;
415
+
416
+ if (Payload->TryGetObjectField(TEXT("value"), VectorObj) && VectorObj) {
417
+ double VX = 0.0, VY = 0.0, VZ = 0.0;
418
+ (*VectorObj)->TryGetNumberField(TEXT("x"), VX);
419
+ (*VectorObj)->TryGetNumberField(TEXT("y"), VY);
420
+ (*VectorObj)->TryGetNumberField(TEXT("z"), VZ);
421
+ NiagaraComp->SetVectorParameter(FName(*ParameterName),
422
+ FVector(VX, VY, VZ));
423
+ bSuccess = true;
424
+ } else if (Payload->TryGetArrayField(TEXT("value"), VectorArr) &&
425
+ VectorArr && VectorArr->Num() >= 3) {
426
+ double VX = (*VectorArr)[0]->AsNumber();
427
+ double VY = (*VectorArr)[1]->AsNumber();
428
+ double VZ = (*VectorArr)[2]->AsNumber();
429
+ NiagaraComp->SetVectorParameter(FName(*ParameterName),
430
+ FVector(VX, VY, VZ));
431
+ bSuccess = true;
432
+ }
433
+ } else if (ParameterType.Equals(TEXT("Color"), ESearchCase::IgnoreCase)) {
434
+ const TSharedPtr<FJsonObject> *ColorObj = nullptr;
435
+ const TArray<TSharedPtr<FJsonValue>> *ColorArr = nullptr;
436
+
437
+ if (Payload->TryGetObjectField(TEXT("value"), ColorObj) && ColorObj) {
438
+ double R = 0.0, G = 0.0, B = 0.0, A = 1.0;
439
+ (*ColorObj)->TryGetNumberField(TEXT("r"), R);
440
+ (*ColorObj)->TryGetNumberField(TEXT("g"), G);
441
+ (*ColorObj)->TryGetNumberField(TEXT("b"), B);
442
+ (*ColorObj)->TryGetNumberField(TEXT("a"), A);
443
+ NiagaraComp->SetColorParameter(FName(*ParameterName),
444
+ FLinearColor(R, G, B, A));
445
+ bSuccess = true;
446
+ } else if (Payload->TryGetArrayField(TEXT("value"), ColorArr) && ColorArr &&
447
+ ColorArr->Num() >= 3) {
448
+ double R = (*ColorArr)[0]->AsNumber();
449
+ double G = (*ColorArr)[1]->AsNumber();
450
+ double B = (*ColorArr)[2]->AsNumber();
451
+ double A = (ColorArr->Num() > 3) ? (*ColorArr)[3]->AsNumber() : 1.0;
452
+ NiagaraComp->SetColorParameter(FName(*ParameterName),
453
+ FLinearColor(R, G, B, A));
454
+ bSuccess = true;
455
+ }
456
+ } else if (ParameterType.Equals(TEXT("Bool"), ESearchCase::IgnoreCase)) {
457
+ bool Value = false;
458
+ if (Payload->TryGetBoolField(TEXT("value"), Value)) {
459
+ NiagaraComp->SetBoolParameter(FName(*ParameterName), Value);
460
+ bSuccess = true;
461
+ }
462
+ }
463
+
464
+ TSharedPtr<FJsonObject> Resp = MakeShared<FJsonObject>();
465
+ Resp->SetBoolField(TEXT("success"), bSuccess);
466
+ Resp->SetStringField(TEXT("actorName"), ActorName);
467
+ Resp->SetStringField(TEXT("parameterName"), ParameterName);
468
+ Resp->SetStringField(TEXT("parameterType"), ParameterType);
469
+
470
+ SendAutomationResponse(
471
+ RequestingSocket, RequestId, bSuccess,
472
+ bSuccess ? TEXT("Niagara parameter modified successfully")
473
+ : TEXT("Failed to modify parameter"),
474
+ Resp, bSuccess ? FString() : TEXT("PARAMETER_SET_FAILED"));
475
+ return true;
476
+ #else
477
+ SendAutomationResponse(RequestingSocket, RequestId, false,
478
+ TEXT("modify_niagara_parameter requires editor build"),
479
+ nullptr, TEXT("NOT_IMPLEMENTED"));
480
+ return true;
481
+ #endif
482
+ }
483
+
484
+ bool UMcpAutomationBridgeSubsystem::HandleCreateNiagaraRibbon(
485
+ const FString &RequestId, const FString &Action,
486
+ const TSharedPtr<FJsonObject> &Payload,
487
+ TSharedPtr<FMcpBridgeWebSocket> RequestingSocket) {
488
+ const FString Lower = Action.ToLower();
489
+ if (!Lower.Equals(TEXT("create_niagara_ribbon"), ESearchCase::IgnoreCase)) {
490
+ return false;
491
+ }
492
+
493
+ #if WITH_EDITOR
494
+ if (!Payload.IsValid()) {
495
+ SendAutomationError(RequestingSocket, RequestId,
496
+ TEXT("create_niagara_ribbon payload missing"),
497
+ TEXT("INVALID_PAYLOAD"));
498
+ return true;
499
+ }
500
+
501
+ FString SystemPath;
502
+ if (!Payload->TryGetStringField(TEXT("systemPath"), SystemPath) ||
503
+ SystemPath.IsEmpty()) {
504
+ SendAutomationError(RequestingSocket, RequestId,
505
+ TEXT("systemPath required"), TEXT("INVALID_ARGUMENT"));
506
+ return true;
507
+ }
508
+
509
+ FString Name;
510
+ Payload->TryGetStringField(TEXT("name"), Name);
511
+
512
+ if (!GEditor || !GEditor->GetEditorWorldContext().World()) {
513
+ SendAutomationError(RequestingSocket, RequestId,
514
+ TEXT("Editor world not available"),
515
+ TEXT("EDITOR_NOT_AVAILABLE"));
516
+ return true;
517
+ }
518
+
519
+ UWorld *World = GEditor->GetEditorWorldContext().World();
520
+
521
+ if (!UEditorAssetLibrary::DoesAssetExist(SystemPath)) {
522
+ SendAutomationResponse(
523
+ RequestingSocket, RequestId, false,
524
+ FString::Printf(TEXT("Niagara system asset not found: %s"),
525
+ *SystemPath),
526
+ nullptr, TEXT("ASSET_NOT_FOUND"));
527
+ return true;
528
+ }
529
+
530
+ UNiagaraSystem *NiagaraSystem =
531
+ LoadObject<UNiagaraSystem>(nullptr, *SystemPath);
532
+ if (!NiagaraSystem) {
533
+ SendAutomationError(RequestingSocket, RequestId,
534
+ TEXT("Failed to load Niagara system"),
535
+ TEXT("LOAD_FAILED"));
536
+ return true;
537
+ }
538
+
539
+ FVector Start(0, 0, 0);
540
+ const TSharedPtr<FJsonObject> *StartObj = nullptr;
541
+ if (Payload->TryGetObjectField(TEXT("start"), StartObj) && StartObj) {
542
+ double X = 0, Y = 0, Z = 0;
543
+ (*StartObj)->TryGetNumberField(TEXT("x"), X);
544
+ (*StartObj)->TryGetNumberField(TEXT("y"), Y);
545
+ (*StartObj)->TryGetNumberField(TEXT("z"), Z);
546
+ Start = FVector(X, Y, Z);
547
+ }
548
+
549
+ ANiagaraActor *NiagaraActor = World->SpawnActor<ANiagaraActor>(
550
+ ANiagaraActor::StaticClass(), Start, FRotator::ZeroRotator);
551
+
552
+ if (!NiagaraActor) {
553
+ SendAutomationError(RequestingSocket, RequestId,
554
+ TEXT("Failed to spawn Niagara actor"),
555
+ TEXT("SPAWN_FAILED"));
556
+ return true;
557
+ }
558
+
559
+ NiagaraActor->SetActorLabel(Name.IsEmpty() ? TEXT("NiagaraRibbon") : Name);
560
+
561
+ UNiagaraComponent *NiagaraComp = NiagaraActor->GetNiagaraComponent();
562
+ if (NiagaraComp) {
563
+ NiagaraComp->SetAsset(NiagaraSystem);
564
+
565
+ // Set Parameters
566
+ NiagaraComp->SetVectorParameter(FName("User.RibbonStart"), Start);
567
+
568
+ const TSharedPtr<FJsonObject> *EndObj = nullptr;
569
+ if (Payload->TryGetObjectField(TEXT("end"), EndObj) && EndObj) {
570
+ double X = 0, Y = 0, Z = 0;
571
+ (*EndObj)->TryGetNumberField(TEXT("x"), X);
572
+ (*EndObj)->TryGetNumberField(TEXT("y"), Y);
573
+ (*EndObj)->TryGetNumberField(TEXT("z"), Z);
574
+ // Often needed to ensure the beam has an endpoint
575
+ NiagaraComp->SetVectorParameter(FName("User.RibbonEnd"),
576
+ FVector(X, Y, Z));
577
+ NiagaraComp->SetVectorParameter(FName("User.BeamEnd"), FVector(X, Y, Z));
578
+ }
579
+
580
+ double Width = 10.0;
581
+ if (Payload->TryGetNumberField(TEXT("width"), Width)) {
582
+ NiagaraComp->SetFloatParameter(FName("User.RibbonWidth"), (float)Width);
583
+ NiagaraComp->SetFloatParameter(FName("User.BeamWidth"), (float)Width);
584
+ }
585
+
586
+ const TSharedPtr<FJsonObject> *ColorObj = nullptr;
587
+ FLinearColor ColorVal(1, 1, 1, 1);
588
+ if (Payload->TryGetObjectField(TEXT("color"), ColorObj) && ColorObj) {
589
+ double R = 1, G = 1, B = 1, A = 1;
590
+ (*ColorObj)->TryGetNumberField(TEXT("r"), R);
591
+ (*ColorObj)->TryGetNumberField(TEXT("g"), G);
592
+ (*ColorObj)->TryGetNumberField(TEXT("b"), B);
593
+ (*ColorObj)->TryGetNumberField(TEXT("a"), A);
594
+ ColorVal = FLinearColor(R, G, B, A);
595
+ } else {
596
+ const TArray<TSharedPtr<FJsonValue>> *ColorArr = nullptr;
597
+ if (Payload->TryGetArrayField(TEXT("color"), ColorArr) && ColorArr &&
598
+ ColorArr->Num() >= 3) {
599
+ double R = (*ColorArr)[0]->AsNumber();
600
+ double G = (*ColorArr)[1]->AsNumber();
601
+ double B = (*ColorArr)[2]->AsNumber();
602
+ double A = (ColorArr->Num() > 3) ? (*ColorArr)[3]->AsNumber() : 1.0;
603
+ ColorVal = FLinearColor(R, G, B, A);
604
+ }
605
+ }
606
+ NiagaraComp->SetColorParameter(FName("User.RibbonColor"), ColorVal);
607
+ NiagaraComp->SetColorParameter(FName("User.Color"), ColorVal);
608
+ }
609
+
610
+ TSharedPtr<FJsonObject> Resp = MakeShared<FJsonObject>();
611
+ Resp->SetBoolField(TEXT("success"), true);
612
+ Resp->SetStringField(TEXT("actorPath"), NiagaraActor->GetPathName());
613
+ Resp->SetStringField(TEXT("actorName"), NiagaraActor->GetActorLabel());
614
+
615
+ SendAutomationResponse(RequestingSocket, RequestId, true,
616
+ TEXT("Niagara ribbon created successfully"), Resp,
617
+ FString());
618
+ return true;
619
+ #else
620
+ SendAutomationResponse(RequestingSocket, RequestId, false,
621
+ TEXT("create_niagara_ribbon requires editor build"),
622
+ nullptr, TEXT("NOT_IMPLEMENTED"));
623
+ return true;
624
+ #endif
625
+ }