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
package/src/tools/ui.ts CHANGED
@@ -1,9 +1,18 @@
1
1
  // UI tools for Unreal Engine
2
2
  import { UnrealBridge } from '../unreal-bridge.js';
3
+ import { AutomationBridge } from '../automation/index.js';
3
4
  import { bestEffortInterpretedText, interpretStandardResult } from '../utils/result-helpers.js';
4
5
 
5
6
  export class UITools {
6
- constructor(private bridge: UnrealBridge) {}
7
+ private automationBridge?: AutomationBridge;
8
+
9
+ constructor(private bridge: UnrealBridge, automationBridge?: AutomationBridge) {
10
+ this.automationBridge = automationBridge;
11
+ }
12
+
13
+ setAutomationBridge(automationBridge?: AutomationBridge) {
14
+ this.automationBridge = automationBridge;
15
+ }
7
16
 
8
17
  // Create widget blueprint
9
18
  async createWidget(params: {
@@ -12,60 +21,73 @@ export class UITools {
12
21
  savePath?: string;
13
22
  }) {
14
23
  const path = params.savePath || '/Game/UI/Widgets';
15
- const py = `
16
- import unreal
17
- import json
18
- name = r"${params.name}"
19
- path = r"${path}"
20
- try:
21
- asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
22
- try:
23
- factory = unreal.WidgetBlueprintFactory()
24
- except Exception:
25
- factory = None
26
- if not factory:
27
- print('RESULT:' + json.dumps({'success': False, 'error': 'WidgetBlueprintFactory unavailable'}))
28
- else:
29
- # Try setting parent_class in a version-tolerant way
30
- try:
31
- factory.parent_class = unreal.UserWidget
32
- except Exception:
33
- try:
34
- factory.set_editor_property('parent_class', unreal.UserWidget)
35
- except Exception:
36
- pass
37
- asset = asset_tools.create_asset(asset_name=name, package_path=path, asset_class=unreal.WidgetBlueprint, factory=factory)
38
- if asset:
39
- unreal.EditorAssetLibrary.save_asset(f"{path}/{name}")
40
- print('RESULT:' + json.dumps({'success': True}))
41
- else:
42
- print('RESULT:' + json.dumps({'success': False, 'error': 'Failed to create WidgetBlueprint'}))
43
- except Exception as e:
44
- print('RESULT:' + json.dumps({'success': False, 'error': str(e)}))
45
- `.trim();
24
+
25
+ // Plugin-first: attempt to create the widget asset via the Automation Bridge.
26
+ if (this.automationBridge && typeof this.automationBridge.sendAutomationRequest === 'function') {
27
+ try {
28
+ const resp = await this.automationBridge.sendAutomationRequest('system_control', {
29
+ action: 'create_widget',
30
+ name: params.name,
31
+ widgetType: params.type,
32
+ savePath: path
33
+ });
34
+ if (resp && resp.success !== false) {
35
+ const result = resp.result ?? resp;
36
+ const resultObj = result && typeof result === 'object' ? (result as Record<string, unknown>) : undefined;
37
+ const widgetPath = typeof resultObj?.widgetPath === 'string' ? (resultObj.widgetPath as string) : `${path}/${params.name}`;
38
+ const message = resp.message || `Widget created at ${widgetPath}`;
39
+ return {
40
+ success: true,
41
+ message,
42
+ widgetPath,
43
+ exists: Boolean(resultObj?.exists),
44
+ ...(resultObj || {})
45
+ };
46
+ }
47
+ } catch (error) {
48
+ console.warn('UITools.createWidget automation bridge request failed, falling back to editor function:', error);
49
+ }
50
+ }
51
+
52
+ // Fallback: attempt to create the widget asset via the Automation
53
+ // Bridge plugin using the generic CREATE_ASSET function. If the plugin
54
+ // does not implement the action the bridge will fall back to executing
55
+ // the Python template (deprecated and gated by server opt-in).
46
56
  try {
47
- const resp = await this.bridge.executePython(py);
48
- const interpreted = interpretStandardResult(resp, {
49
- successMessage: 'Widget blueprint created',
50
- failureMessage: 'Failed to create WidgetBlueprint'
51
- });
57
+ const payload = {
58
+ asset_name: params.name,
59
+ package_path: path,
60
+ factory_class: 'WidgetBlueprintFactory',
61
+ asset_class: 'unreal.WidgetBlueprint'
62
+ } as Record<string, any>;
52
63
 
53
- if (interpreted.success) {
54
- return { success: true, message: interpreted.message };
64
+ const resp = await this.bridge.executeEditorFunction('CREATE_ASSET', payload as any);
65
+ const result = resp && typeof resp === 'object' ? (resp.result ?? resp) : resp;
66
+
67
+ // Interpret common success shapes returned by plugin or Python template
68
+ if (result && (result.success === true || result.created === true || Boolean(result.path))) {
69
+ return { success: true, message: result.message ?? `Widget created at ${result.path ?? `${path}/${params.name}`}` };
55
70
  }
56
71
 
57
- return {
58
- success: false,
59
- error: interpreted.error ?? 'Failed to create widget blueprint',
60
- details: bestEffortInterpretedText(interpreted)
61
- };
72
+ // If plugin/template returned a structured failure, surface it
73
+ if (result && result.success === false) {
74
+ return { success: false, error: result.error ?? result.message ?? 'Failed to create widget blueprint', details: result };
75
+ }
76
+
77
+ // Fallback: if no structured response, return generic failure
78
+ return { success: false, error: 'Failed to create widget blueprint' };
62
79
  } catch (e) {
63
80
  return { success: false, error: `Failed to create widget blueprint: ${e}` };
64
81
  }
65
82
  }
66
83
 
84
+ // Show widget (convenience wrapper)
85
+ async showWidget(widgetPath: string) {
86
+ return this.addWidgetToViewport({ widgetClass: widgetPath });
87
+ }
88
+
67
89
  // Add widget component
68
- async addWidgetComponent(params: {
90
+ async addWidgetComponent(_params: {
69
91
  widgetName: string;
70
92
  componentType: 'Button' | 'Text' | 'Image' | 'ProgressBar' | 'Slider' | 'CheckBox' | 'ComboBox' | 'TextBox' | 'ScrollBox' | 'Canvas' | 'VerticalBox' | 'HorizontalBox' | 'Grid' | 'Overlay';
71
93
  componentName: string;
@@ -76,162 +98,135 @@ except Exception as e:
76
98
  alignment?: [number, number];
77
99
  };
78
100
  }) {
79
- const commands: string[] = [];
80
-
81
- commands.push(`AddWidgetComponent ${params.widgetName} ${params.componentType} ${params.componentName}`);
82
-
83
- if (params.slot) {
84
- if (params.slot.position) {
85
- commands.push(`SetWidgetPosition ${params.widgetName}.${params.componentName} ${params.slot.position.join(' ')}`);
86
- }
87
- if (params.slot.size) {
88
- commands.push(`SetWidgetSize ${params.widgetName}.${params.componentName} ${params.slot.size.join(' ')}`);
89
- }
90
- if (params.slot.anchor) {
91
- commands.push(`SetWidgetAnchor ${params.widgetName}.${params.componentName} ${params.slot.anchor.join(' ')}`);
92
- }
93
- if (params.slot.alignment) {
94
- commands.push(`SetWidgetAlignment ${params.widgetName}.${params.componentName} ${params.slot.alignment.join(' ')}`);
95
- }
101
+ if (!this.automationBridge) {
102
+ throw new Error('Automation bridge required for widget component operations');
103
+ }
104
+
105
+ try {
106
+ // Map correctly to McpAutomationBridge_UiHandlers.cpp: add_widget_child
107
+ const response = await this.automationBridge.sendAutomationRequest('manage_ui', {
108
+ action: 'add_widget_child', // Use 'action' inside payload for subAction
109
+ widgetPath: _params.widgetName, // C++ expects 'widgetPath'
110
+ childClass: _params.componentType, // C++ expects 'childClass'
111
+ parentName: _params.slot ? 'Root' : undefined, // Rudimentary mapping
112
+ });
113
+
114
+ return response.success
115
+ ? { success: true, message: response.message || 'Widget component added', ...(response.result || {}) }
116
+ : { success: false, error: response.error || response.message || 'Failed to add widget component' };
117
+ } catch (error) {
118
+ return { success: false, error: `Failed to add widget component: ${error instanceof Error ? error.message : String(error)}` };
96
119
  }
97
-
98
- await this.bridge.executeConsoleCommands(commands);
99
-
100
- return { success: true, message: `Component ${params.componentName} added to widget` };
101
120
  }
102
121
 
103
- // Set text
104
- async setWidgetText(params: {
105
- widgetName: string;
106
- componentName: string;
107
- text: string;
108
- fontSize?: number;
109
- color?: [number, number, number, number];
110
- fontFamily?: string;
122
+ // Set text (requires C++ plugin)
123
+ async setWidgetText(_params: {
124
+ key: string; // The widget name to find
125
+ value: string; // The text to set
126
+ componentName?: string; // Legacy/Unused in new impl
111
127
  }) {
112
- const commands: string[] = [];
113
-
114
- commands.push(`SetWidgetText ${params.widgetName}.${params.componentName} "${params.text}"`);
115
-
116
- if (params.fontSize !== undefined) {
117
- commands.push(`SetWidgetFontSize ${params.widgetName}.${params.componentName} ${params.fontSize}`);
128
+ if (!this.automationBridge) {
129
+ throw new Error('Automation bridge required for setting widget text');
118
130
  }
119
-
120
- if (params.color) {
121
- commands.push(`SetWidgetTextColor ${params.widgetName}.${params.componentName} ${params.color.join(' ')}`);
122
- }
123
-
124
- if (params.fontFamily) {
125
- commands.push(`SetWidgetFont ${params.widgetName}.${params.componentName} ${params.fontFamily}`);
131
+
132
+ try {
133
+ // Changed to 'system_control' with subAction
134
+ const response = await this.automationBridge.sendAutomationRequest('system_control', {
135
+ subAction: 'set_widget_text',
136
+ key: _params.key,
137
+ value: _params.value
138
+ });
139
+
140
+ return response.success
141
+ ? { success: true, message: response.message || 'Widget text set', ...(response.result || {}) }
142
+ : { success: false, error: response.error || response.message || 'Failed to set widget text' };
143
+ } catch (error) {
144
+ return { success: false, error: `Failed to set widget text: ${error instanceof Error ? error.message : String(error)}` };
126
145
  }
127
-
128
- await this.bridge.executeConsoleCommands(commands);
129
-
130
- return { success: true, message: 'Widget text updated' };
131
146
  }
132
147
 
133
- // Set image
134
- async setWidgetImage(params: {
135
- widgetName: string;
136
- componentName: string;
137
- imagePath: string;
138
- tint?: [number, number, number, number];
139
- sizeToContent?: boolean;
148
+ // Set image (requires C++ plugin)
149
+ async setWidgetImage(_params: {
150
+ key: string;
151
+ texturePath: string;
152
+ componentName?: string; // Unused
140
153
  }) {
141
- const commands: string[] = [];
142
-
143
- commands.push(`SetWidgetImage ${params.widgetName}.${params.componentName} ${params.imagePath}`);
144
-
145
- if (params.tint) {
146
- commands.push(`SetWidgetImageTint ${params.widgetName}.${params.componentName} ${params.tint.join(' ')}`);
154
+ if (!this.automationBridge) {
155
+ throw new Error('Automation bridge required for setting widget images');
147
156
  }
148
-
149
- if (params.sizeToContent !== undefined) {
150
- commands.push(`SetWidgetSizeToContent ${params.widgetName}.${params.componentName} ${params.sizeToContent}`);
157
+
158
+ try {
159
+ const response = await this.automationBridge.sendAutomationRequest('system_control', {
160
+ subAction: 'set_widget_image',
161
+ key: _params.key,
162
+ texturePath: _params.texturePath
163
+ });
164
+
165
+ return response.success
166
+ ? { success: true, message: response.message || 'Widget image set', ...(response.result || {}) }
167
+ : { success: false, error: response.error || response.message || 'Failed to set widget image' };
168
+ } catch (error) {
169
+ return { success: false, error: `Failed to set widget image: ${error instanceof Error ? error.message : String(error)}` };
151
170
  }
152
-
153
- await this.bridge.executeConsoleCommands(commands);
154
-
155
- return { success: true, message: 'Widget image updated' };
156
171
  }
157
172
 
158
- // Create HUD
159
- async createHUD(params: {
173
+ // Create HUD (requires C++ plugin)
174
+ async createHUD(_params: {
160
175
  name: string;
161
- elements?: Array<{
162
- type: 'HealthBar' | 'AmmoCounter' | 'Score' | 'Timer' | 'Minimap' | 'Crosshair';
163
- position: [number, number];
164
- size?: [number, number];
165
- }>;
176
+ elements?: Array<any>;
166
177
  }) {
167
- const commands: string[] = [];
168
-
169
- commands.push(`CreateHUDClass ${params.name}`);
170
-
171
- if (params.elements) {
172
- for (const element of params.elements) {
173
- const size = element.size || [100, 50];
174
- commands.push(`AddHUDElement ${params.name} ${element.type} ${element.position.join(' ')} ${size.join(' ')}`);
175
- }
178
+ if (!this.automationBridge) {
179
+ throw new Error('Automation bridge required for creating HUDs');
180
+ }
181
+
182
+ // Default path assumption or require full path?
183
+ // C++ expects 'widgetPath'. If name is just "MyHUD", we might need to resolve it.
184
+ // For now, assume name is the path or user provides path.
185
+ const widgetPath = _params.name.startsWith('/Game') ? _params.name : `/Game/UI/${_params.name}`;
186
+
187
+ try {
188
+ const response = await this.automationBridge.sendAutomationRequest('system_control', {
189
+ subAction: 'create_hud',
190
+ widgetPath: widgetPath
191
+ });
192
+
193
+ return response.success
194
+ ? { success: true, message: response.message || 'HUD created', widgetName: (response.result as any)?.widgetName, ...(response.result || {}) }
195
+ : { success: false, error: response.error || response.message || 'Failed to create HUD' };
196
+ } catch (error) {
197
+ return { success: false, error: `Failed to create HUD: ${error instanceof Error ? error.message : String(error)}` };
176
198
  }
177
-
178
- await this.bridge.executeConsoleCommands(commands);
179
-
180
- return { success: true, message: `HUD ${params.name} created` };
181
199
  }
182
200
 
183
- // Show/Hide widget
184
201
  async setWidgetVisibility(params: {
185
- widgetName: string;
202
+ key: string;
186
203
  visible: boolean;
187
- playerIndex?: number;
188
204
  }) {
189
- const playerIndex = params.playerIndex ?? 0;
190
- const widgetName = params.widgetName?.trim();
191
- if (!widgetName) {
192
- return { success: false, error: 'widgetName is required' };
193
- }
194
-
195
- const verifyScript = `
196
- import unreal, json
197
- name = r"${widgetName}"
198
- candidates = []
199
- if name.startswith('/Game/'):
200
- candidates.append(name)
201
- else:
202
- candidates.append(f"/Game/UI/Widgets/{name}")
203
- candidates.append(f"/Game/{name}")
204
-
205
- found_path = ''
206
- for path in candidates:
207
- if unreal.EditorAssetLibrary.does_asset_exist(path):
208
- found_path = path
209
- break
210
-
211
- print('RESULT:' + json.dumps({'success': bool(found_path), 'path': found_path, 'candidates': candidates}))
212
- `.trim();
213
-
214
- const verify = await this.bridge.executePythonWithResult(verifyScript);
215
- if (!verify?.success) {
216
- return { success: false, error: `Widget asset not found for ${widgetName}` };
217
- }
218
-
219
- const command = params.visible
220
- ? `ShowWidget ${widgetName} ${playerIndex}`
221
- : `HideWidget ${widgetName} ${playerIndex}`;
222
-
223
- const raw = await this.bridge.executeConsoleCommand(command);
224
- const summary = this.bridge.summarizeConsoleCommand(command, raw);
205
+ if (!this.automationBridge) return { success: false, error: 'NO_BRIDGE' };
206
+ const response = await this.automationBridge.sendAutomationRequest('system_control', {
207
+ subAction: 'set_widget_visibility',
208
+ key: params.key,
209
+ visible: params.visible
210
+ });
211
+ return response.success
212
+ ? { success: true, message: response.message || 'Widget visibility set', ...(response.result || {}) }
213
+ : { success: false, error: response.error || response.message || 'Failed to set widget visibility' };
214
+ }
225
215
 
226
- return {
227
- success: true,
228
- message: params.visible ? `Widget ${widgetName} show command issued` : `Widget ${widgetName} hide command issued`,
229
- command: summary.command,
230
- output: summary.output || undefined,
231
- logLines: summary.logLines?.length ? summary.logLines : undefined
232
- };
216
+ async removeWidgetFromViewport(params: {
217
+ key?: string;
218
+ }) {
219
+ if (!this.automationBridge) return { success: false, error: 'NO_BRIDGE' };
220
+ const response = await this.automationBridge.sendAutomationRequest('system_control', {
221
+ subAction: 'remove_widget_from_viewport',
222
+ key: params.key
223
+ });
224
+ return response.success
225
+ ? { success: true, message: response.message || 'Widget removed from viewport', ...(response.result || {}) }
226
+ : { success: false, error: response.error || response.message || 'Failed to remove widget from viewport' };
233
227
  }
234
228
 
229
+
235
230
  // Add widget to viewport
236
231
  async addWidgetToViewport(params: {
237
232
  widgetClass: string;
@@ -240,93 +235,22 @@ print('RESULT:' + json.dumps({'success': bool(found_path), 'path': found_path, '
240
235
  }) {
241
236
  const zOrder = params.zOrder ?? 0;
242
237
  const playerIndex = params.playerIndex ?? 0;
243
-
244
- // Use Python API to create and add widget to viewport
245
- const py = `
246
- import unreal
247
- import json
248
- widget_path = r"${params.widgetClass}"
249
- z_order = ${zOrder}
250
- player_index = ${playerIndex}
251
- try:
252
- # Load the widget blueprint class
253
- if not unreal.EditorAssetLibrary.does_asset_exist(widget_path):
254
- print('RESULT:' + json.dumps({'success': False, 'error': f'Widget class not found: {widget_path}'}))
255
- else:
256
- widget_bp = unreal.EditorAssetLibrary.load_asset(widget_path)
257
- if not widget_bp:
258
- print('RESULT:' + json.dumps({'success': False, 'error': 'Failed to load widget blueprint'}))
259
- else:
260
- # Get the generated class from the widget blueprint
261
- widget_class = widget_bp.generated_class() if hasattr(widget_bp, 'generated_class') else widget_bp
262
-
263
- # Get the world and player controller via modern subsystems
264
- world = None
265
- try:
266
- world = unreal.EditorUtilityLibrary.get_editor_world()
267
- except Exception:
268
- pass
269
-
270
- if not world:
271
- editor_subsystem = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem)
272
- if editor_subsystem and hasattr(editor_subsystem, 'get_editor_world'):
273
- world = editor_subsystem.get_editor_world()
274
-
275
- if not world:
276
- print('RESULT:' + json.dumps({'success': False, 'error': 'No editor world available. Start a PIE session or enable Editor Scripting Utilities.'}))
277
- else:
278
- # Try to get player controller
279
- try:
280
- player_controller = unreal.GameplayStatics.get_player_controller(world, player_index)
281
- except Exception:
282
- player_controller = None
283
-
284
- if not player_controller:
285
- # If no player controller in PIE, try to get the first one or create a dummy
286
- print('RESULT:' + json.dumps({'success': False, 'error': 'No player controller available. Run in PIE mode first.'}))
287
- else:
288
- # Create the widget
289
- widget = unreal.WidgetBlueprintLibrary.create(world, widget_class, player_controller)
290
- if widget:
291
- # Add to viewport
292
- widget.add_to_viewport(z_order)
293
- print('RESULT:' + json.dumps({'success': True}))
294
- else:
295
- print('RESULT:' + json.dumps({'success': False, 'error': 'Failed to create widget instance'}))
296
- except Exception as e:
297
- print('RESULT:' + json.dumps({'success': False, 'error': str(e)}))
298
- `.trim();
299
-
238
+
300
239
  try {
301
- const resp = await this.bridge.executePython(py);
240
+ const resp = await this.bridge.executeEditorFunction('ADD_WIDGET_TO_VIEWPORT', { widget_path: params.widgetClass, z_order: zOrder, player_index: playerIndex } as any);
302
241
  const interpreted = interpretStandardResult(resp, {
303
242
  successMessage: `Widget added to viewport with z-order ${zOrder}`,
304
243
  failureMessage: 'Failed to add widget to viewport'
305
244
  });
306
-
307
245
  if (interpreted.success) {
308
246
  return { success: true, message: interpreted.message };
309
247
  }
310
-
311
- return {
312
- success: false,
313
- error: interpreted.error ?? 'Failed to add widget to viewport',
314
- details: bestEffortInterpretedText(interpreted)
315
- };
248
+ return { success: false, error: interpreted.error ?? 'Failed to add widget to viewport', details: bestEffortInterpretedText(interpreted) };
316
249
  } catch (e) {
317
250
  return { success: false, error: `Failed to add widget to viewport: ${e}` };
318
251
  }
319
252
  }
320
253
 
321
- // Remove widget from viewport
322
- async removeWidgetFromViewport(params: {
323
- widgetName: string;
324
- playerIndex?: number;
325
- }) {
326
- const playerIndex = params.playerIndex ?? 0;
327
- const command = `RemoveWidgetFromViewport ${params.widgetName} ${playerIndex}`;
328
- return this.bridge.executeConsoleCommand(command);
329
- }
330
254
 
331
255
  // Create menu
332
256
  async createMenu(params: {
@@ -338,19 +262,19 @@ except Exception as e:
338
262
  position?: [number, number];
339
263
  }>;
340
264
  }) {
341
- const commands: string[] = [];
342
-
265
+ const commands: string[] = [];
266
+
343
267
  commands.push(`CreateMenuWidget ${params.name} ${params.menuType}`);
344
-
268
+
345
269
  if (params.buttons) {
346
270
  for (const button of params.buttons) {
347
271
  const pos = button.position || [0, 0];
348
272
  commands.push(`AddMenuButton ${params.name} "${button.text}" ${button.action} ${pos.join(' ')}`);
349
273
  }
350
274
  }
351
-
275
+
352
276
  await this.bridge.executeConsoleCommands(commands);
353
-
277
+
354
278
  return { success: true, message: `Menu ${params.name} created` };
355
279
  }
356
280
 
@@ -368,23 +292,23 @@ except Exception as e:
368
292
  }>;
369
293
  }>;
370
294
  }) {
371
- const commands: string[] = [];
372
-
295
+ const commands: string[] = [];
296
+
373
297
  commands.push(`CreateWidgetAnimation ${params.widgetName} ${params.animationName} ${params.duration}`);
374
-
298
+
375
299
  if (params.tracks) {
376
300
  for (const track of params.tracks) {
377
301
  commands.push(`AddAnimationTrack ${params.widgetName}.${params.animationName} ${track.componentName} ${track.property}`);
378
-
302
+
379
303
  for (const keyframe of track.keyframes) {
380
304
  const value = Array.isArray(keyframe.value) ? keyframe.value.join(' ') : keyframe.value;
381
305
  commands.push(`AddAnimationKeyframe ${params.widgetName}.${params.animationName} ${track.componentName} ${keyframe.time} ${value}`);
382
306
  }
383
307
  }
384
308
  }
385
-
309
+
386
310
  await this.bridge.executeConsoleCommands(commands);
387
-
311
+
388
312
  return { success: true, message: `Animation ${params.animationName} created` };
389
313
  }
390
314
 
@@ -397,7 +321,7 @@ except Exception as e:
397
321
  }) {
398
322
  const playMode = params.playMode || 'Forward';
399
323
  const loops = params.loops ?? 1;
400
-
324
+
401
325
  const command = `PlayWidgetAnimation ${params.widgetName} ${params.animationName} ${playMode} ${loops}`;
402
326
  return this.bridge.executeConsoleCommand(command);
403
327
  }
@@ -414,30 +338,30 @@ except Exception as e:
414
338
  margin?: [number, number, number, number];
415
339
  };
416
340
  }) {
417
- const commands: string[] = [];
418
-
341
+ const commands: string[] = [];
342
+
419
343
  if (params.style.backgroundColor) {
420
344
  commands.push(`SetWidgetBackgroundColor ${params.widgetName}.${params.componentName} ${params.style.backgroundColor.join(' ')}`);
421
345
  }
422
-
346
+
423
347
  if (params.style.borderColor) {
424
348
  commands.push(`SetWidgetBorderColor ${params.widgetName}.${params.componentName} ${params.style.borderColor.join(' ')}`);
425
349
  }
426
-
350
+
427
351
  if (params.style.borderWidth !== undefined) {
428
352
  commands.push(`SetWidgetBorderWidth ${params.widgetName}.${params.componentName} ${params.style.borderWidth}`);
429
353
  }
430
-
354
+
431
355
  if (params.style.padding) {
432
356
  commands.push(`SetWidgetPadding ${params.widgetName}.${params.componentName} ${params.style.padding.join(' ')}`);
433
357
  }
434
-
358
+
435
359
  if (params.style.margin) {
436
360
  commands.push(`SetWidgetMargin ${params.widgetName}.${params.componentName} ${params.style.margin.join(' ')}`);
437
361
  }
438
-
362
+
439
363
  await this.bridge.executeConsoleCommands(commands);
440
-
364
+
441
365
  return { success: true, message: 'Widget style updated' };
442
366
  }
443
367
 
@@ -458,20 +382,20 @@ except Exception as e:
458
382
  showCursor?: boolean;
459
383
  lockCursor?: boolean;
460
384
  }) {
461
- const commands: string[] = [];
462
-
385
+ const commands: string[] = [];
386
+
463
387
  commands.push(`SetInputMode ${params.mode}`);
464
-
388
+
465
389
  if (params.showCursor !== undefined) {
466
390
  commands.push(`ShowMouseCursor ${params.showCursor}`);
467
391
  }
468
-
392
+
469
393
  if (params.lockCursor !== undefined) {
470
394
  commands.push(`SetMouseLockMode ${params.lockCursor}`);
471
395
  }
472
-
396
+
473
397
  await this.bridge.executeConsoleCommands(commands);
474
-
398
+
475
399
  return { success: true, message: `Input mode set to ${params.mode}` };
476
400
  }
477
401
 
@@ -495,21 +419,21 @@ except Exception as e:
495
419
  dropTargets?: string[];
496
420
  }) {
497
421
  const commands = [];
498
-
422
+
499
423
  commands.push(`EnableDragDrop ${params.widgetName}.${params.componentName}`);
500
-
424
+
501
425
  if (params.dragVisual) {
502
426
  commands.push(`SetDragVisual ${params.widgetName}.${params.componentName} ${params.dragVisual}`);
503
427
  }
504
-
428
+
505
429
  if (params.dropTargets) {
506
430
  for (const target of params.dropTargets) {
507
431
  commands.push(`AddDropTarget ${params.widgetName}.${params.componentName} ${target}`);
508
432
  }
509
433
  }
510
-
434
+
511
435
  await this.bridge.executeConsoleCommands(commands);
512
-
436
+
513
437
  return { success: true, message: 'Drag and drop configured' };
514
438
  }
515
439
 
@@ -523,7 +447,7 @@ except Exception as e:
523
447
  const duration = params.duration ?? 3.0;
524
448
  const type = params.type || 'Info';
525
449
  const position = params.position || 'TopRight';
526
-
450
+
527
451
  const command = `ShowNotification "${params.text}" ${duration} ${type} ${position}`;
528
452
  return this.bridge.executeConsoleCommand(command);
529
453
  }