unreal-engine-mcp-server 0.4.7 → 0.5.1

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 (454) 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-config.yml +51 -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 +27 -0
  19. package/.github/workflows/labeler.yml +17 -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 +13 -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 +338 -31
  29. package/CONTRIBUTING.md +140 -0
  30. package/GEMINI.md +115 -0
  31. package/Public/Plugin_setup_guide.mp4 +0 -0
  32. package/README.md +189 -128
  33. package/claude_desktop_config_example.json +7 -6
  34. package/dist/automation/bridge.d.ts +50 -0
  35. package/dist/automation/bridge.js +452 -0
  36. package/dist/automation/connection-manager.d.ts +23 -0
  37. package/dist/automation/connection-manager.js +107 -0
  38. package/dist/automation/handshake.d.ts +11 -0
  39. package/dist/automation/handshake.js +89 -0
  40. package/dist/automation/index.d.ts +3 -0
  41. package/dist/automation/index.js +3 -0
  42. package/dist/automation/message-handler.d.ts +12 -0
  43. package/dist/automation/message-handler.js +149 -0
  44. package/dist/automation/request-tracker.d.ts +25 -0
  45. package/dist/automation/request-tracker.js +98 -0
  46. package/dist/automation/types.d.ts +130 -0
  47. package/dist/automation/types.js +2 -0
  48. package/dist/cli.js +32 -5
  49. package/dist/config.d.ts +26 -0
  50. package/dist/config.js +59 -0
  51. package/dist/constants.d.ts +16 -0
  52. package/dist/constants.js +16 -0
  53. package/dist/graphql/loaders.d.ts +64 -0
  54. package/dist/graphql/loaders.js +117 -0
  55. package/dist/graphql/resolvers.d.ts +268 -0
  56. package/dist/graphql/resolvers.js +746 -0
  57. package/dist/graphql/schema.d.ts +5 -0
  58. package/dist/graphql/schema.js +437 -0
  59. package/dist/graphql/server.d.ts +26 -0
  60. package/dist/graphql/server.js +117 -0
  61. package/dist/graphql/types.d.ts +9 -0
  62. package/dist/graphql/types.js +2 -0
  63. package/dist/handlers/resource-handlers.d.ts +20 -0
  64. package/dist/handlers/resource-handlers.js +180 -0
  65. package/dist/index.d.ts +33 -18
  66. package/dist/index.js +130 -619
  67. package/dist/resources/actors.d.ts +17 -12
  68. package/dist/resources/actors.js +56 -76
  69. package/dist/resources/assets.d.ts +6 -14
  70. package/dist/resources/assets.js +115 -147
  71. package/dist/resources/levels.d.ts +13 -13
  72. package/dist/resources/levels.js +25 -34
  73. package/dist/server/resource-registry.d.ts +20 -0
  74. package/dist/server/resource-registry.js +37 -0
  75. package/dist/server/tool-registry.d.ts +23 -0
  76. package/dist/server/tool-registry.js +322 -0
  77. package/dist/server-setup.d.ts +20 -0
  78. package/dist/server-setup.js +71 -0
  79. package/dist/services/health-monitor.d.ts +34 -0
  80. package/dist/services/health-monitor.js +105 -0
  81. package/dist/services/metrics-server.d.ts +11 -0
  82. package/dist/services/metrics-server.js +105 -0
  83. package/dist/tools/actors.d.ts +163 -9
  84. package/dist/tools/actors.js +356 -311
  85. package/dist/tools/animation.d.ts +135 -4
  86. package/dist/tools/animation.js +510 -411
  87. package/dist/tools/assets.d.ts +75 -29
  88. package/dist/tools/assets.js +265 -284
  89. package/dist/tools/audio.d.ts +102 -42
  90. package/dist/tools/audio.js +272 -685
  91. package/dist/tools/base-tool.d.ts +17 -0
  92. package/dist/tools/base-tool.js +46 -0
  93. package/dist/tools/behavior-tree.d.ts +94 -0
  94. package/dist/tools/behavior-tree.js +39 -0
  95. package/dist/tools/blueprint.d.ts +208 -126
  96. package/dist/tools/blueprint.js +685 -832
  97. package/dist/tools/consolidated-tool-definitions.d.ts +5462 -1781
  98. package/dist/tools/consolidated-tool-definitions.js +829 -496
  99. package/dist/tools/consolidated-tool-handlers.d.ts +2 -1
  100. package/dist/tools/consolidated-tool-handlers.js +198 -1027
  101. package/dist/tools/debug.d.ts +143 -85
  102. package/dist/tools/debug.js +234 -180
  103. package/dist/tools/dynamic-handler-registry.d.ts +13 -0
  104. package/dist/tools/dynamic-handler-registry.js +23 -0
  105. package/dist/tools/editor.d.ts +30 -83
  106. package/dist/tools/editor.js +247 -244
  107. package/dist/tools/engine.d.ts +10 -4
  108. package/dist/tools/engine.js +13 -5
  109. package/dist/tools/environment.d.ts +30 -0
  110. package/dist/tools/environment.js +267 -0
  111. package/dist/tools/foliage.d.ts +65 -99
  112. package/dist/tools/foliage.js +221 -331
  113. package/dist/tools/handlers/actor-handlers.d.ts +3 -0
  114. package/dist/tools/handlers/actor-handlers.js +227 -0
  115. package/dist/tools/handlers/animation-handlers.d.ts +3 -0
  116. package/dist/tools/handlers/animation-handlers.js +185 -0
  117. package/dist/tools/handlers/argument-helper.d.ts +16 -0
  118. package/dist/tools/handlers/argument-helper.js +80 -0
  119. package/dist/tools/handlers/asset-handlers.d.ts +3 -0
  120. package/dist/tools/handlers/asset-handlers.js +496 -0
  121. package/dist/tools/handlers/audio-handlers.d.ts +3 -0
  122. package/dist/tools/handlers/audio-handlers.js +166 -0
  123. package/dist/tools/handlers/blueprint-handlers.d.ts +4 -0
  124. package/dist/tools/handlers/blueprint-handlers.js +358 -0
  125. package/dist/tools/handlers/common-handlers.d.ts +14 -0
  126. package/dist/tools/handlers/common-handlers.js +56 -0
  127. package/dist/tools/handlers/editor-handlers.d.ts +3 -0
  128. package/dist/tools/handlers/editor-handlers.js +119 -0
  129. package/dist/tools/handlers/effect-handlers.d.ts +3 -0
  130. package/dist/tools/handlers/effect-handlers.js +171 -0
  131. package/dist/tools/handlers/environment-handlers.d.ts +3 -0
  132. package/dist/tools/handlers/environment-handlers.js +170 -0
  133. package/dist/tools/handlers/graph-handlers.d.ts +3 -0
  134. package/dist/tools/handlers/graph-handlers.js +90 -0
  135. package/dist/tools/handlers/input-handlers.d.ts +3 -0
  136. package/dist/tools/handlers/input-handlers.js +21 -0
  137. package/dist/tools/handlers/inspect-handlers.d.ts +3 -0
  138. package/dist/tools/handlers/inspect-handlers.js +383 -0
  139. package/dist/tools/handlers/level-handlers.d.ts +3 -0
  140. package/dist/tools/handlers/level-handlers.js +237 -0
  141. package/dist/tools/handlers/lighting-handlers.d.ts +3 -0
  142. package/dist/tools/handlers/lighting-handlers.js +144 -0
  143. package/dist/tools/handlers/performance-handlers.d.ts +3 -0
  144. package/dist/tools/handlers/performance-handlers.js +130 -0
  145. package/dist/tools/handlers/pipeline-handlers.d.ts +3 -0
  146. package/dist/tools/handlers/pipeline-handlers.js +110 -0
  147. package/dist/tools/handlers/sequence-handlers.d.ts +3 -0
  148. package/dist/tools/handlers/sequence-handlers.js +376 -0
  149. package/dist/tools/handlers/system-handlers.d.ts +4 -0
  150. package/dist/tools/handlers/system-handlers.js +506 -0
  151. package/dist/tools/input.d.ts +19 -0
  152. package/dist/tools/input.js +89 -0
  153. package/dist/tools/introspection.d.ts +103 -40
  154. package/dist/tools/introspection.js +425 -568
  155. package/dist/tools/landscape.d.ts +54 -93
  156. package/dist/tools/landscape.js +284 -409
  157. package/dist/tools/level.d.ts +66 -27
  158. package/dist/tools/level.js +647 -675
  159. package/dist/tools/lighting.d.ts +77 -38
  160. package/dist/tools/lighting.js +445 -943
  161. package/dist/tools/logs.d.ts +3 -3
  162. package/dist/tools/logs.js +5 -57
  163. package/dist/tools/materials.d.ts +91 -24
  164. package/dist/tools/materials.js +194 -118
  165. package/dist/tools/niagara.d.ts +149 -39
  166. package/dist/tools/niagara.js +267 -182
  167. package/dist/tools/performance.d.ts +27 -13
  168. package/dist/tools/performance.js +203 -122
  169. package/dist/tools/physics.d.ts +32 -77
  170. package/dist/tools/physics.js +175 -582
  171. package/dist/tools/property-dictionary.d.ts +13 -0
  172. package/dist/tools/property-dictionary.js +82 -0
  173. package/dist/tools/sequence.d.ts +85 -60
  174. package/dist/tools/sequence.js +208 -747
  175. package/dist/tools/tool-definition-utils.d.ts +59 -0
  176. package/dist/tools/tool-definition-utils.js +35 -0
  177. package/dist/tools/ui.d.ts +64 -34
  178. package/dist/tools/ui.js +134 -214
  179. package/dist/types/automation-responses.d.ts +115 -0
  180. package/dist/types/automation-responses.js +2 -0
  181. package/dist/types/env.d.ts +0 -3
  182. package/dist/types/env.js +0 -7
  183. package/dist/types/responses.d.ts +249 -0
  184. package/dist/types/responses.js +2 -0
  185. package/dist/types/tool-interfaces.d.ts +898 -0
  186. package/dist/types/tool-interfaces.js +2 -0
  187. package/dist/types/tool-types.d.ts +183 -19
  188. package/dist/types/tool-types.js +0 -4
  189. package/dist/unreal-bridge.d.ts +24 -131
  190. package/dist/unreal-bridge.js +364 -1506
  191. package/dist/utils/command-validator.d.ts +9 -0
  192. package/dist/utils/command-validator.js +68 -0
  193. package/dist/utils/elicitation.d.ts +1 -1
  194. package/dist/utils/elicitation.js +12 -15
  195. package/dist/utils/error-handler.d.ts +2 -51
  196. package/dist/utils/error-handler.js +11 -87
  197. package/dist/utils/ini-reader.d.ts +3 -0
  198. package/dist/utils/ini-reader.js +69 -0
  199. package/dist/utils/logger.js +9 -6
  200. package/dist/utils/normalize.d.ts +3 -0
  201. package/dist/utils/normalize.js +56 -0
  202. package/dist/utils/path-security.d.ts +2 -0
  203. package/dist/utils/path-security.js +24 -0
  204. package/dist/utils/response-factory.d.ts +7 -0
  205. package/dist/utils/response-factory.js +27 -0
  206. package/dist/utils/response-validator.d.ts +3 -24
  207. package/dist/utils/response-validator.js +130 -81
  208. package/dist/utils/result-helpers.d.ts +4 -5
  209. package/dist/utils/result-helpers.js +15 -16
  210. package/dist/utils/safe-json.js +5 -11
  211. package/dist/utils/unreal-command-queue.d.ts +24 -0
  212. package/dist/utils/unreal-command-queue.js +120 -0
  213. package/dist/utils/validation.d.ts +0 -40
  214. package/dist/utils/validation.js +1 -78
  215. package/dist/wasm/index.d.ts +70 -0
  216. package/dist/wasm/index.js +535 -0
  217. package/docs/GraphQL-API.md +888 -0
  218. package/docs/Migration-Guide-v0.5.0.md +684 -0
  219. package/docs/Roadmap.md +53 -0
  220. package/docs/WebAssembly-Integration.md +628 -0
  221. package/docs/editor-plugin-extension.md +370 -0
  222. package/docs/handler-mapping.md +242 -0
  223. package/docs/native-automation-progress.md +128 -0
  224. package/docs/testing-guide.md +423 -0
  225. package/mcp-config-example.json +6 -6
  226. package/package.json +67 -28
  227. package/plugins/McpAutomationBridge/Config/FilterPlugin.ini +8 -0
  228. package/plugins/McpAutomationBridge/McpAutomationBridge.uplugin +64 -0
  229. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/McpAutomationBridge.Build.cs +189 -0
  230. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.cpp +22 -0
  231. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.h +30 -0
  232. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeHelpers.h +1983 -0
  233. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeModule.cpp +72 -0
  234. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSettings.cpp +46 -0
  235. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +581 -0
  236. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +2394 -0
  237. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetQueryHandlers.cpp +300 -0
  238. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetWorkflowHandlers.cpp +2807 -0
  239. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AudioHandlers.cpp +1087 -0
  240. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BehaviorTreeHandlers.cpp +488 -0
  241. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.cpp +643 -0
  242. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.h +31 -0
  243. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +1184 -0
  244. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +5652 -0
  245. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers_List.cpp +152 -0
  246. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ControlHandlers.cpp +2614 -0
  247. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_DebugHandlers.cpp +42 -0
  248. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EditorFunctionHandlers.cpp +1237 -0
  249. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +1701 -0
  250. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +2145 -0
  251. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_FoliageHandlers.cpp +954 -0
  252. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InputHandlers.cpp +209 -0
  253. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InsightsHandlers.cpp +41 -0
  254. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LandscapeHandlers.cpp +1164 -0
  255. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LevelHandlers.cpp +762 -0
  256. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +634 -0
  257. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LogHandlers.cpp +136 -0
  258. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_MaterialGraphHandlers.cpp +494 -0
  259. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraGraphHandlers.cpp +278 -0
  260. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraHandlers.cpp +625 -0
  261. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PerformanceHandlers.cpp +401 -0
  262. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PipelineHandlers.cpp +67 -0
  263. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +735 -0
  264. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PropertyHandlers.cpp +2634 -0
  265. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_RenderHandlers.cpp +189 -0
  266. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.cpp +917 -0
  267. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.h +39 -0
  268. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +2670 -0
  269. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequencerHandlers.cpp +519 -0
  270. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_TestHandlers.cpp +38 -0
  271. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_UiHandlers.cpp +668 -0
  272. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_WorldPartitionHandlers.cpp +346 -0
  273. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.cpp +1330 -0
  274. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.h +149 -0
  275. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +783 -0
  276. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSettings.h +115 -0
  277. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSubsystem.h +796 -0
  278. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpConnectionManager.h +117 -0
  279. package/scripts/check-unreal-connection.mjs +19 -0
  280. package/scripts/clean-tmp.js +23 -0
  281. package/scripts/patch-wasm.js +26 -0
  282. package/scripts/run-all-tests.mjs +136 -0
  283. package/scripts/smoke-test.ts +94 -0
  284. package/scripts/sync-mcp-plugin.js +143 -0
  285. package/scripts/test-no-plugin-alternates.mjs +113 -0
  286. package/scripts/validate-server.js +46 -0
  287. package/scripts/verify-automation-bridge.js +200 -0
  288. package/server.json +58 -21
  289. package/src/automation/bridge.ts +558 -0
  290. package/src/automation/connection-manager.ts +130 -0
  291. package/src/automation/handshake.ts +99 -0
  292. package/src/automation/index.ts +2 -0
  293. package/src/automation/message-handler.ts +167 -0
  294. package/src/automation/request-tracker.ts +123 -0
  295. package/src/automation/types.ts +107 -0
  296. package/src/cli.ts +33 -6
  297. package/src/config.ts +73 -0
  298. package/src/constants.ts +19 -0
  299. package/src/graphql/loaders.ts +244 -0
  300. package/src/graphql/resolvers.ts +1008 -0
  301. package/src/graphql/schema.ts +452 -0
  302. package/src/graphql/server.ts +156 -0
  303. package/src/graphql/types.ts +10 -0
  304. package/src/handlers/resource-handlers.ts +186 -0
  305. package/src/index.ts +166 -664
  306. package/src/resources/actors.ts +58 -76
  307. package/src/resources/assets.ts +148 -134
  308. package/src/resources/levels.ts +28 -33
  309. package/src/server/resource-registry.ts +47 -0
  310. package/src/server/tool-registry.ts +354 -0
  311. package/src/server-setup.ts +114 -0
  312. package/src/services/health-monitor.ts +132 -0
  313. package/src/services/metrics-server.ts +142 -0
  314. package/src/tools/actors.ts +426 -323
  315. package/src/tools/animation.ts +672 -461
  316. package/src/tools/assets.ts +364 -289
  317. package/src/tools/audio.ts +323 -766
  318. package/src/tools/base-tool.ts +52 -0
  319. package/src/tools/behavior-tree.ts +45 -0
  320. package/src/tools/blueprint.ts +792 -970
  321. package/src/tools/consolidated-tool-definitions.ts +993 -515
  322. package/src/tools/consolidated-tool-handlers.ts +258 -1146
  323. package/src/tools/debug.ts +292 -187
  324. package/src/tools/dynamic-handler-registry.ts +33 -0
  325. package/src/tools/editor.ts +329 -253
  326. package/src/tools/engine.ts +14 -3
  327. package/src/tools/environment.ts +281 -0
  328. package/src/tools/foliage.ts +330 -392
  329. package/src/tools/handlers/actor-handlers.ts +265 -0
  330. package/src/tools/handlers/animation-handlers.ts +237 -0
  331. package/src/tools/handlers/argument-helper.ts +142 -0
  332. package/src/tools/handlers/asset-handlers.ts +532 -0
  333. package/src/tools/handlers/audio-handlers.ts +194 -0
  334. package/src/tools/handlers/blueprint-handlers.ts +380 -0
  335. package/src/tools/handlers/common-handlers.ts +87 -0
  336. package/src/tools/handlers/editor-handlers.ts +123 -0
  337. package/src/tools/handlers/effect-handlers.ts +220 -0
  338. package/src/tools/handlers/environment-handlers.ts +183 -0
  339. package/src/tools/handlers/graph-handlers.ts +116 -0
  340. package/src/tools/handlers/input-handlers.ts +28 -0
  341. package/src/tools/handlers/inspect-handlers.ts +450 -0
  342. package/src/tools/handlers/level-handlers.ts +252 -0
  343. package/src/tools/handlers/lighting-handlers.ts +147 -0
  344. package/src/tools/handlers/performance-handlers.ts +132 -0
  345. package/src/tools/handlers/pipeline-handlers.ts +127 -0
  346. package/src/tools/handlers/sequence-handlers.ts +415 -0
  347. package/src/tools/handlers/system-handlers.ts +564 -0
  348. package/src/tools/input.ts +101 -0
  349. package/src/tools/introspection.ts +493 -584
  350. package/src/tools/landscape.ts +418 -507
  351. package/src/tools/level.ts +786 -708
  352. package/src/tools/lighting.ts +588 -984
  353. package/src/tools/logs.ts +9 -57
  354. package/src/tools/materials.ts +237 -121
  355. package/src/tools/niagara.ts +335 -168
  356. package/src/tools/performance.ts +320 -169
  357. package/src/tools/physics.ts +274 -613
  358. package/src/tools/property-dictionary.ts +98 -0
  359. package/src/tools/sequence.ts +276 -820
  360. package/src/tools/tool-definition-utils.ts +35 -0
  361. package/src/tools/ui.ts +205 -283
  362. package/src/types/automation-responses.ts +119 -0
  363. package/src/types/env.ts +0 -10
  364. package/src/types/responses.ts +355 -0
  365. package/src/types/tool-interfaces.ts +250 -0
  366. package/src/types/tool-types.ts +243 -21
  367. package/src/unreal-bridge.ts +460 -1550
  368. package/src/utils/command-validator.ts +76 -0
  369. package/src/utils/elicitation.ts +10 -7
  370. package/src/utils/error-handler.ts +14 -90
  371. package/src/utils/ini-reader.ts +86 -0
  372. package/src/utils/logger.ts +8 -3
  373. package/src/utils/normalize.test.ts +162 -0
  374. package/src/utils/normalize.ts +60 -0
  375. package/src/utils/path-security.ts +43 -0
  376. package/src/utils/response-factory.ts +44 -0
  377. package/src/utils/response-validator.ts +176 -56
  378. package/src/utils/result-helpers.ts +21 -19
  379. package/src/utils/safe-json.test.ts +90 -0
  380. package/src/utils/safe-json.ts +14 -11
  381. package/src/utils/unreal-command-queue.ts +152 -0
  382. package/src/utils/validation.test.ts +184 -0
  383. package/src/utils/validation.ts +4 -1
  384. package/src/wasm/index.ts +838 -0
  385. package/test-server.mjs +100 -0
  386. package/tests/run-unreal-tool-tests.mjs +242 -14
  387. package/tests/test-animation.mjs +369 -0
  388. package/tests/test-asset-advanced.mjs +82 -0
  389. package/tests/test-asset-errors.mjs +35 -0
  390. package/tests/test-asset-graph.mjs +311 -0
  391. package/tests/test-audio.mjs +417 -0
  392. package/tests/test-automation-timeouts.mjs +98 -0
  393. package/tests/test-behavior-tree.mjs +444 -0
  394. package/tests/test-blueprint-graph.mjs +410 -0
  395. package/tests/test-blueprint.mjs +577 -0
  396. package/tests/test-client-mode.mjs +86 -0
  397. package/tests/test-console-command.mjs +56 -0
  398. package/tests/test-control-actor.mjs +425 -0
  399. package/tests/test-control-editor.mjs +112 -0
  400. package/tests/test-graphql.mjs +372 -0
  401. package/tests/test-input.mjs +349 -0
  402. package/tests/test-inspect.mjs +302 -0
  403. package/tests/test-landscape.mjs +316 -0
  404. package/tests/test-lighting.mjs +428 -0
  405. package/tests/test-manage-asset.mjs +438 -0
  406. package/tests/test-manage-level.mjs +89 -0
  407. package/tests/test-materials.mjs +356 -0
  408. package/tests/test-niagara.mjs +185 -0
  409. package/tests/test-no-inline-python.mjs +122 -0
  410. package/tests/test-performance.mjs +539 -0
  411. package/tests/test-plugin-handshake.mjs +82 -0
  412. package/tests/test-runner.mjs +933 -0
  413. package/tests/test-sequence.mjs +104 -0
  414. package/tests/test-system.mjs +96 -0
  415. package/tests/test-wasm.mjs +283 -0
  416. package/tests/test-world-partition.mjs +215 -0
  417. package/tsconfig.json +3 -3
  418. package/vitest.config.ts +35 -0
  419. package/wasm/Cargo.lock +363 -0
  420. package/wasm/Cargo.toml +42 -0
  421. package/wasm/LICENSE +21 -0
  422. package/wasm/README.md +253 -0
  423. package/wasm/src/dependency_resolver.rs +377 -0
  424. package/wasm/src/lib.rs +153 -0
  425. package/wasm/src/property_parser.rs +271 -0
  426. package/wasm/src/transform_math.rs +396 -0
  427. package/wasm/tests/integration.rs +109 -0
  428. package/.github/workflows/smithery-build.yml +0 -29
  429. package/dist/prompts/index.d.ts +0 -21
  430. package/dist/prompts/index.js +0 -217
  431. package/dist/tools/build_environment_advanced.d.ts +0 -65
  432. package/dist/tools/build_environment_advanced.js +0 -633
  433. package/dist/tools/rc.d.ts +0 -110
  434. package/dist/tools/rc.js +0 -437
  435. package/dist/tools/visual.d.ts +0 -40
  436. package/dist/tools/visual.js +0 -282
  437. package/dist/utils/http.d.ts +0 -6
  438. package/dist/utils/http.js +0 -151
  439. package/dist/utils/python-output.d.ts +0 -18
  440. package/dist/utils/python-output.js +0 -290
  441. package/dist/utils/python.d.ts +0 -2
  442. package/dist/utils/python.js +0 -4
  443. package/dist/utils/stdio-redirect.d.ts +0 -2
  444. package/dist/utils/stdio-redirect.js +0 -20
  445. package/docs/unreal-tool-test-cases.md +0 -574
  446. package/smithery.yaml +0 -29
  447. package/src/prompts/index.ts +0 -249
  448. package/src/tools/build_environment_advanced.ts +0 -732
  449. package/src/tools/rc.ts +0 -515
  450. package/src/tools/visual.ts +0 -281
  451. package/src/utils/http.ts +0 -187
  452. package/src/utils/python-output.ts +0 -351
  453. package/src/utils/python.ts +0 -3
  454. package/src/utils/stdio-redirect.ts +0 -18
@@ -1,17 +1,39 @@
1
1
  // Performance tools for Unreal Engine
2
2
  import { UnrealBridge } from '../unreal-bridge.js';
3
- import { coerceBoolean, coerceNumber, interpretStandardResult } from '../utils/result-helpers.js';
3
+ import { AutomationBridge } from '../automation/index.js';
4
+ import { Logger } from '../utils/logger.js';
4
5
 
5
6
  export class PerformanceTools {
6
- constructor(private bridge: UnrealBridge) {}
7
+ private log = new Logger('PerformanceTools');
8
+ private automationBridge?: AutomationBridge;
9
+
10
+ constructor(private bridge: UnrealBridge, automationBridge?: AutomationBridge) {
11
+ this.automationBridge = automationBridge;
12
+ }
13
+
14
+ setAutomationBridge(automationBridge?: AutomationBridge) {
15
+ this.automationBridge = automationBridge;
16
+ }
7
17
 
8
18
  // Start profiling
9
19
  async startProfiling(params: {
10
20
  type: 'CPU' | 'GPU' | 'Memory' | 'RenderThread' | 'GameThread' | 'All';
11
21
  duration?: number;
12
22
  }) {
13
- const commands: string[] = [];
14
-
23
+ if (this.automationBridge) {
24
+ try {
25
+ const response = await this.automationBridge.sendAutomationRequest('start_profiling', {
26
+ type: params.type,
27
+ duration: params.duration
28
+ });
29
+ if (response.success) return { success: true, message: `${params.type} profiling started (bridge)` };
30
+ } catch (_e) {
31
+ // Fallback
32
+ }
33
+ }
34
+
35
+ const commands: string[] = [];
36
+
15
37
  switch (params.type) {
16
38
  case 'CPU':
17
39
  commands.push('stat startfile');
@@ -34,25 +56,34 @@ export class PerformanceTools {
34
56
  commands.push('stat memory');
35
57
  break;
36
58
  }
37
-
59
+
38
60
  if (params.duration) {
39
61
  commands.push(`stat stopfile ${params.duration}`);
40
62
  }
41
-
63
+
42
64
  await this.bridge.executeConsoleCommands(commands);
43
-
65
+
44
66
  return { success: true, message: `${params.type} profiling started` };
45
67
  }
46
68
 
47
69
  // Stop profiling
48
70
  async stopProfiling() {
71
+ if (this.automationBridge) {
72
+ try {
73
+ const response = await this.automationBridge.sendAutomationRequest('stop_profiling', {});
74
+ if (response.success) return { success: true, message: 'Profiling stopped (bridge)' };
75
+ } catch (_e) {
76
+ // Fallback
77
+ }
78
+ }
79
+
49
80
  const commands = [
50
81
  'stat stopfile',
51
82
  'stat none'
52
83
  ];
53
-
84
+
54
85
  await this.bridge.executeConsoleCommands(commands);
55
-
86
+
56
87
  return { success: true, message: 'Profiling stopped' };
57
88
  }
58
89
 
@@ -62,27 +93,43 @@ export class PerformanceTools {
62
93
  verbose?: boolean;
63
94
  }) {
64
95
  const startTime = Date.now();
65
- console.log('[PerformanceTools] Starting showFPS with params:', params);
66
-
96
+ this.log.debug('Starting showFPS with params:', params);
97
+
98
+ if (this.automationBridge) {
99
+ try {
100
+ const response = await this.automationBridge.sendAutomationRequest('show_fps', {
101
+ enabled: params.enabled,
102
+ verbose: params.verbose
103
+ });
104
+ if (response.success) return {
105
+ success: true,
106
+ message: params.enabled ? 'FPS display enabled (bridge)' : 'FPS display disabled (bridge)',
107
+ fpsVisible: params.enabled
108
+ };
109
+ } catch (_e) {
110
+ // Fallback
111
+ }
112
+ }
113
+
67
114
  try {
68
115
  // Use stat fps as requested - shows FPS counter
69
116
  // For more detailed timing info, use 'stat unit' instead
70
- const command = params.enabled
117
+ const command = params.enabled
71
118
  ? (params.verbose ? 'stat unit' : 'stat fps')
72
119
  : 'stat none';
73
-
74
- console.log(`[PerformanceTools] Executing command: ${command}`);
120
+
121
+ this.log.debug(`Executing command: ${command}`);
75
122
  await this.bridge.executeConsoleCommand(command);
76
- console.log(`[PerformanceTools] Command completed in ${Date.now() - startTime}ms`);
77
- return {
78
- success: true,
123
+ this.log.debug(`Command completed in ${Date.now() - startTime}ms`);
124
+ return {
125
+ success: true,
79
126
  message: params.enabled ? 'FPS display enabled' : 'FPS display disabled',
80
127
  fpsVisible: params.enabled,
81
128
  command: command
82
129
  };
83
130
  } catch (error) {
84
- return {
85
- success: false,
131
+ return {
132
+ success: false,
86
133
  error: `Failed to ${params.enabled ? 'enable' : 'disable'} FPS display: ${error}`,
87
134
  fpsVisible: false
88
135
  };
@@ -94,10 +141,22 @@ export class PerformanceTools {
94
141
  category: 'Unit' | 'FPS' | 'Memory' | 'Game' | 'Slate' | 'Engine' | 'RHI' | 'Streaming' | 'SceneRendering' | 'Physics' | 'Navigation' | 'Particles' | 'Audio';
95
142
  enabled: boolean;
96
143
  }) {
97
- const command = params.enabled
144
+ if (this.automationBridge) {
145
+ try {
146
+ const response = await this.automationBridge.sendAutomationRequest('show_stats', {
147
+ category: params.category,
148
+ enabled: params.enabled
149
+ });
150
+ if (response.success) return { success: true, message: `Stat '${params.category}' configured (bridge)` };
151
+ } catch (_e) {
152
+ // Fallback
153
+ }
154
+ }
155
+
156
+ const command = params.enabled
98
157
  ? `stat ${params.category.toLowerCase()}`
99
158
  : 'stat none';
100
-
159
+
101
160
  return this.bridge.executeConsoleCommand(command);
102
161
  }
103
162
 
@@ -106,6 +165,18 @@ export class PerformanceTools {
106
165
  category: 'ViewDistance' | 'AntiAliasing' | 'PostProcessing' | 'PostProcess' | 'Shadows' | 'GlobalIllumination' | 'Reflections' | 'Textures' | 'Effects' | 'Foliage' | 'Shading';
107
166
  level: 0 | 1 | 2 | 3 | 4; // 0=Low, 1=Medium, 2=High, 3=Epic, 4=Cinematic
108
167
  }) {
168
+ if (this.automationBridge) {
169
+ try {
170
+ const response = await this.automationBridge.sendAutomationRequest('set_scalability', {
171
+ category: params.category,
172
+ level: params.level
173
+ });
174
+ if (response.success) return { success: true, message: `${params.category} quality set to level ${params.level} (bridge)` };
175
+ } catch (_e) {
176
+ // Fallback
177
+ }
178
+ }
179
+
109
180
  // Map incoming category to the base name expected by "sg.<Base>Quality"
110
181
  // Note: Several CVars use singular form (Shadow/Texture/Reflection)
111
182
  const categoryBaseMap: Record<string, string> = {
@@ -130,115 +201,60 @@ export class PerformanceTools {
130
201
  }
131
202
 
132
203
  const base = categoryBaseMap[params.category] || params.category;
133
-
204
+
134
205
  // Use direct console command to set with highest priority (SetByConsole)
135
206
  // This avoids conflicts with the scalability system
136
207
  const setCommand = `sg.${base}Quality ${requestedLevel}`;
137
-
208
+
138
209
  // Apply the console command directly
139
210
  await this.bridge.executeConsoleCommand(setCommand);
140
-
141
- // Skip GameUserSettings entirely to avoid any scalability triggers
142
- // Console command already applied with correct priority
143
- /* eslint-disable no-useless-escape */
144
- const py = `
145
- import unreal, json
146
- result = {'success': True, 'category': '${base}', 'requested': ${requestedLevel}, 'actual': ${requestedLevel}, 'method': 'ConsoleOnly'}
147
-
148
- # Simply verify the console variable was set correctly
149
- try:
150
- # Try to read the console variable directly to verify it was set
151
- # This doesn't trigger any scalability system
152
- import sys
153
- from io import StringIO
154
-
155
- # Capture console output
156
- old_stdout = sys.stdout
157
- sys.stdout = StringIO()
158
-
159
- # Execute console command to query the value
160
- try:
161
- unreal.SystemLibrary.execute_console_command(None, 'sg.${base}Quality', None)
162
- except:
163
- pass
164
-
165
- # Get the output
166
- console_output = sys.stdout.getvalue()
167
- sys.stdout = old_stdout
168
-
169
- # Parse the output to get the actual value
170
- if 'sg.${base}Quality' in console_output:
171
- # Extract the value from output like 'sg.ShadowQuality = "3"'
172
- import re
173
- match = re.search(r'sg\.${base}Quality\\s*=\\s*"(\\d+)"', console_output)
174
- if match:
175
- result['actual'] = int(match.group(1))
176
- result['verified'] = True
177
-
178
- result['method'] = 'ConsoleOnly'
179
- except Exception as e:
180
- # Even on error, the console command was applied
181
- result['method'] = 'ConsoleOnly'
182
- result['note'] = str(e)
183
-
184
- print('RESULT:' + json.dumps(result))
185
- `.trim();
186
- /* eslint-enable no-useless-escape */
187
-
188
- // Always try to apply through Python for consistency
189
- try {
190
- const pyResp = await this.bridge.executePython(py);
191
- const interpreted = interpretStandardResult(pyResp, {
192
- successMessage: `${params.category} quality set to level ${requestedLevel}`,
193
- failureMessage: `Failed to set ${params.category} quality`
194
- });
195
-
196
- if (interpreted.success) {
197
- const actual = coerceNumber(interpreted.payload.actual) ?? requestedLevel;
198
- const verified = coerceBoolean(interpreted.payload.success, true) === true && actual === requestedLevel;
199
- return {
200
- success: true,
201
- message: interpreted.message,
202
- verified,
203
- readback: actual,
204
- method: (interpreted.payload.method as string) || 'ConsoleOnly'
205
- };
206
- }
207
- } catch {
208
- // Ignore Python errors and fall through
209
- }
210
211
 
211
- // If Python fails, the console command was still applied
212
- return {
213
- success: true,
212
+ return {
213
+ success: true,
214
214
  message: `${params.category} quality set to level ${requestedLevel}`,
215
- method: 'CVarOnly'
215
+ method: 'Console'
216
216
  };
217
217
  }
218
218
 
219
219
  // Set resolution scale
220
220
  async setResolutionScale(params: {
221
- scale: number; // 0.5 to 2.0
221
+ scale: number; // Accepts both percentage (10-200) and multiplier (0.1-2.0)
222
222
  }) {
223
223
  // Validate input
224
224
  if (params.scale === undefined || params.scale === null || isNaN(params.scale)) {
225
225
  return { success: false, error: 'Invalid scale parameter' };
226
226
  }
227
-
228
- // Clamp scale between 10% (0.1) and 200% (2.0) - Unreal Engine limits
229
- // Note: r.ScreenPercentage takes values from 10 to 200, not 0.5 to 2.0
230
- const clampedScale = Math.max(0.1, Math.min(2.0, params.scale));
231
- const percentage = Math.round(clampedScale * 100);
232
-
233
- // Ensure percentage is within Unreal's valid range
227
+
228
+ // Intelligently detect if scale is a percentage (10-200) or multiplier (0.1-2.0)
229
+ // If scale >= 10, assume it's already a percentage value
230
+ let percentage: number;
231
+ if (params.scale >= 10) {
232
+ // User passed percentage directly (e.g., 100 for 100%)
233
+ percentage = Math.round(params.scale);
234
+ } else {
235
+ // User passed multiplier (e.g., 1.0 for 100%)
236
+ percentage = Math.round(params.scale * 100);
237
+ }
238
+
239
+ // Clamp to Unreal's valid range (10-200%)
234
240
  const finalPercentage = Math.max(10, Math.min(200, percentage));
235
-
241
+
242
+ if (this.automationBridge) {
243
+ try {
244
+ const response = await this.automationBridge.sendAutomationRequest('set_resolution_scale', { scale: finalPercentage });
245
+
246
+ if (response.success) return { success: true, message: `Resolution scale set to ${finalPercentage}% (bridge)`, actualScale: finalPercentage / 100 };
247
+ } catch (_e) {
248
+ // Fallback
249
+ }
250
+ }
251
+
236
252
  const command = `r.ScreenPercentage ${finalPercentage}`;
237
-
253
+
238
254
  try {
239
255
  await this.bridge.executeConsoleCommand(command);
240
- return {
241
- success: true,
256
+ return {
257
+ success: true,
242
258
  message: `Resolution scale set to ${finalPercentage}%`,
243
259
  actualScale: finalPercentage / 100
244
260
  };
@@ -251,6 +267,14 @@ print('RESULT:' + json.dumps(result))
251
267
  async setVSync(params: {
252
268
  enabled: boolean;
253
269
  }) {
270
+ if (this.automationBridge) {
271
+ try {
272
+ const response = await this.automationBridge.sendAutomationRequest('set_vsync', { enabled: params.enabled });
273
+ if (response.success) return { success: true, message: 'VSync configured (bridge)' };
274
+ } catch (_e) {
275
+ // Fallback
276
+ }
277
+ }
254
278
  const command = `r.VSync ${params.enabled ? 1 : 0}`;
255
279
  return this.bridge.executeConsoleCommand(command);
256
280
  }
@@ -259,6 +283,14 @@ print('RESULT:' + json.dumps(result))
259
283
  async setFrameRateLimit(params: {
260
284
  maxFPS: number; // 0 for unlimited
261
285
  }) {
286
+ if (this.automationBridge) {
287
+ try {
288
+ const response = await this.automationBridge.sendAutomationRequest('set_frame_rate_limit', { maxFPS: params.maxFPS });
289
+ if (response.success) return { success: true, message: 'Max FPS set (bridge)' };
290
+ } catch (_e) {
291
+ // Fallback
292
+ }
293
+ }
262
294
  const command = `t.MaxFPS ${params.maxFPS}`;
263
295
  return this.bridge.executeConsoleCommand(command);
264
296
  }
@@ -267,6 +299,13 @@ print('RESULT:' + json.dumps(result))
267
299
  async enableGPUTiming(params: {
268
300
  enabled: boolean;
269
301
  }) {
302
+ // Note: C++ handler doesn't seem to have explicit 'enable_gpu_timing' in the list I saw earlier?
303
+ // Checking McpAutomationBridge_PerformanceHandlers.cpp content provided:
304
+ // It has: generate_memory_report, start/stop_profiling, show_fps, show_stats, set_scalability, set_resolution_scale, set_vsync, set_frame_rate_limit, configure_nanite, configure_lod.
305
+ // IT DOES NOT HAVE enable_gpu_timing.
306
+ // So we stick to console command for this one, or add it to C++ later.
307
+ // I will NOT add bridge call here to avoid failure since I know it's missing.
308
+
270
309
  const command = `r.GPUStatsEnabled ${params.enabled ? 1 : 0}`;
271
310
  return this.bridge.executeConsoleCommand(command);
272
311
  }
@@ -276,20 +315,41 @@ print('RESULT:' + json.dumps(result))
276
315
  detailed?: boolean;
277
316
  outputPath?: string;
278
317
  }) {
279
- const commands: string[] = [];
280
-
318
+ // If output path is specified, use Automation Bridge for file writing
319
+ if (this.automationBridge) {
320
+ try {
321
+ const response = await this.automationBridge.sendAutomationRequest('generate_memory_report', {
322
+ detailed: params.detailed ?? false,
323
+ outputPath: params.outputPath
324
+ });
325
+
326
+ // Even if no output path, bridge can run the report
327
+ if (response.success) {
328
+ return { success: true, message: response.message || 'Memory report generated' };
329
+ }
330
+ } catch (error) {
331
+ // Fallback only if no output path (since console can't save to file reliably)
332
+ if (params.outputPath) {
333
+ return { success: false, error: `Failed to generate memory report: ${error instanceof Error ? error.message : String(error)}` };
334
+ }
335
+ }
336
+ }
337
+
338
+ const commands: string[] = [];
339
+
281
340
  if (params.detailed) {
282
341
  commands.push('memreport -full');
283
342
  } else {
284
343
  commands.push('memreport');
285
344
  }
286
-
345
+
346
+ // Writing reports to disk via console is not supported
287
347
  if (params.outputPath) {
288
- commands.push(`obj savepackage ${params.outputPath}`);
348
+ throw new Error('Saving memreport to a file requires Automation Bridge support');
289
349
  }
290
-
350
+
291
351
  await this.bridge.executeConsoleCommands(commands);
292
-
352
+
293
353
  return { success: true, message: 'Memory report generated' };
294
354
  }
295
355
 
@@ -299,20 +359,34 @@ print('RESULT:' + json.dumps(result))
299
359
  poolSize?: number; // MB
300
360
  boostPlayerLocation?: boolean;
301
361
  }) {
302
- const commands: string[] = [];
303
-
362
+ if (this.automationBridge) {
363
+ try {
364
+ const response = await this.automationBridge.sendAutomationRequest('configure_texture_streaming', {
365
+ enabled: params.enabled,
366
+ poolSize: params.poolSize,
367
+ boostPlayerLocation: params.boostPlayerLocation
368
+ });
369
+
370
+ if (response.success) return { success: true, message: response.message || 'Texture streaming configured (bridge)' };
371
+ } catch (_error) {
372
+ // Fallback
373
+ }
374
+ }
375
+
376
+ if (params.boostPlayerLocation && !this.automationBridge) {
377
+ throw new Error('Boosting player location for streaming requires Automation Bridge support');
378
+ }
379
+
380
+ const commands: string[] = [];
381
+
304
382
  commands.push(`r.TextureStreaming ${params.enabled ? 1 : 0}`);
305
-
383
+
306
384
  if (params.poolSize !== undefined) {
307
385
  commands.push(`r.Streaming.PoolSize ${params.poolSize}`);
308
386
  }
309
-
310
- if (params.boostPlayerLocation !== undefined) {
311
- commands.push(`r.Streaming.UseFixedPoolSize ${params.boostPlayerLocation ? 1 : 0}`);
312
- }
313
-
387
+
314
388
  await this.bridge.executeConsoleCommands(commands);
315
-
389
+
316
390
  return { success: true, message: 'Texture streaming configured' };
317
391
  }
318
392
 
@@ -322,25 +396,46 @@ print('RESULT:' + json.dumps(result))
322
396
  lodBias?: number; // skeletal LOD bias (int)
323
397
  distanceScale?: number; // distance scale (float) applied to both static and skeletal
324
398
  }) {
325
- const commands: string[] = [];
326
-
399
+ if (this.automationBridge) {
400
+ try {
401
+ const response = await this.automationBridge.sendAutomationRequest('configure_lod', {
402
+ forceLOD: params.forceLOD,
403
+ lodBias: params.lodBias
404
+ // Note: C++ handler doesn't seem to have explicit 'distanceScale'.
405
+ // We will stick to console for proper implementation of distanceScale
406
+ });
407
+
408
+ // If we have distanceScale, we still need to apply it via console as C++ seems to miss it
409
+ if (params.distanceScale !== undefined) {
410
+ await this.bridge.executeConsoleCommand(`r.StaticMeshLODDistanceScale ${params.distanceScale}`);
411
+ await this.bridge.executeConsoleCommand(`r.SkeletalMeshLODDistanceScale ${params.distanceScale}`);
412
+ }
413
+
414
+ if (response.success) return { success: true, message: 'LOD settings configured' };
415
+ } catch (_e) {
416
+ // Fallback
417
+ }
418
+ }
419
+
420
+ const commands: string[] = [];
421
+
327
422
  if (params.forceLOD !== undefined) {
328
423
  commands.push(`r.ForceLOD ${params.forceLOD}`);
329
424
  }
330
-
425
+
331
426
  if (params.lodBias !== undefined) {
332
427
  // Skeletal mesh LOD bias is an integer bias value
333
428
  commands.push(`r.SkeletalMeshLODBias ${params.lodBias}`);
334
429
  }
335
-
430
+
336
431
  if (params.distanceScale !== undefined) {
337
432
  // Apply distance scale to both static and skeletal meshes
338
433
  commands.push(`r.StaticMeshLODDistanceScale ${params.distanceScale}`);
339
434
  commands.push(`r.SkeletalMeshLODDistanceScale ${params.distanceScale}`);
340
435
  }
341
-
436
+
342
437
  await this.bridge.executeConsoleCommands(commands);
343
-
438
+
344
439
  return { success: true, message: 'LOD settings configured' };
345
440
  }
346
441
 
@@ -352,6 +447,8 @@ print('RESULT:' + json.dumps(result))
352
447
  maxFPS?: number; // default 60
353
448
  hzb?: boolean; // default true
354
449
  }) {
450
+ // This is a composite helper, stick to console or individual bridge calls.
451
+ // Console is efficient enough for batch cvar setting.
355
452
  const p = {
356
453
  distanceScale: params?.distanceScale ?? 1.0,
357
454
  skeletalBias: params?.skeletalBias ?? 0,
@@ -377,23 +474,53 @@ print('RESULT:' + json.dumps(result))
377
474
  // Draw call optimization
378
475
  async optimizeDrawCalls(params: {
379
476
  enableInstancing?: boolean;
380
- enableBatching?: boolean; // no-op (deprecated internal toggle)
477
+
381
478
  mergeActors?: boolean;
479
+ actors?: string[];
382
480
  }) {
383
- const commands: string[] = [];
384
-
481
+ // If merging actors, bridge is required and actors must be provided
482
+ if (params.mergeActors) {
483
+ if (this.automationBridge) {
484
+ try {
485
+ const actors = Array.isArray(params.actors)
486
+ ? params.actors.filter((name): name is string => typeof name === 'string' && name.length > 0)
487
+ : undefined;
488
+
489
+ if (!actors || actors.length < 2) {
490
+ return {
491
+ success: false,
492
+ error: 'Merge actors requires an "actors" array with at least 2 valid actor names.'
493
+ };
494
+ }
495
+
496
+ const payload: any = {
497
+ enableInstancing: params.enableInstancing,
498
+ mergeActors: params.mergeActors,
499
+ actors: actors
500
+ };
501
+
502
+ const response = await this.automationBridge.sendAutomationRequest('merge_actors', payload);
503
+
504
+ return response.success
505
+ ? { success: true, message: response.message || 'Actors merged for optimization' }
506
+ : { success: false, error: response.message || response.error || 'Failed to merge actors' };
507
+ } catch (error) {
508
+ return { success: false, error: `Failed to merge actors: ${error instanceof Error ? error.message : String(error)}` };
509
+ }
510
+ }
511
+ throw new Error('Actor merging requires Automation Bridge support');
512
+ }
513
+
514
+ const commands: string[] = [];
515
+
385
516
  if (params.enableInstancing !== undefined) {
386
517
  commands.push(`r.MeshDrawCommands.DynamicInstancing ${params.enableInstancing ? 1 : 0}`);
387
518
  }
388
-
519
+
389
520
  // Avoid using r.RHICmdBypass; it's a low-level debug toggle and not suitable for general batching control
390
-
391
- if (params.mergeActors) {
392
- commands.push('MergeActors');
393
- }
394
-
521
+
395
522
  await this.bridge.executeConsoleCommands(commands);
396
-
523
+
397
524
  return { success: true, message: 'Draw call optimization configured' };
398
525
  }
399
526
 
@@ -403,18 +530,18 @@ print('RESULT:' + json.dumps(result))
403
530
  method?: 'Hardware' | 'Software' | 'Hierarchical';
404
531
  freezeRendering?: boolean;
405
532
  }) {
406
- const commands: string[] = [];
407
-
533
+ const commands: string[] = [];
534
+
408
535
  // Enable/disable HZB occlusion (boolean)
409
536
  commands.push(`r.HZBOcclusion ${params.enabled ? 1 : 0}`);
410
-
537
+
411
538
  // Optional freeze rendering toggle
412
539
  if (params.freezeRendering !== undefined) {
413
540
  commands.push(`FreezeRendering ${params.freezeRendering ? 1 : 0}`);
414
541
  }
415
-
542
+
416
543
  await this.bridge.executeConsoleCommands(commands);
417
-
544
+
418
545
  return { success: true, message: 'Occlusion culling configured' };
419
546
  }
420
547
 
@@ -424,22 +551,22 @@ print('RESULT:' + json.dumps(result))
424
551
  cacheShaders?: boolean;
425
552
  reducePermutations?: boolean;
426
553
  }) {
427
- const commands: string[] = [];
428
-
554
+ const commands: string[] = [];
555
+
429
556
  if (params.compileOnDemand !== undefined) {
430
557
  commands.push(`r.ShaderDevelopmentMode ${params.compileOnDemand ? 1 : 0}`);
431
558
  }
432
-
559
+
433
560
  if (params.cacheShaders !== undefined) {
434
561
  commands.push(`r.ShaderPipelineCache.Enabled ${params.cacheShaders ? 1 : 0}`);
435
562
  }
436
-
563
+
437
564
  if (params.reducePermutations) {
438
565
  commands.push('RecompileShaders changed');
439
566
  }
440
-
567
+
441
568
  await this.bridge.executeConsoleCommands(commands);
442
-
569
+
443
570
  return { success: true, message: 'Shader optimization configured' };
444
571
  }
445
572
 
@@ -449,20 +576,44 @@ print('RESULT:' + json.dumps(result))
449
576
  maxPixelsPerEdge?: number;
450
577
  streamingPoolSize?: number;
451
578
  }) {
452
- const commands: string[] = [];
453
-
579
+ if (this.automationBridge) {
580
+ try {
581
+ const response = await this.automationBridge.sendAutomationRequest('configure_nanite', {
582
+ enabled: params.enabled,
583
+ maxPixelsPerEdge: params.maxPixelsPerEdge,
584
+ streamingPoolSize: params.streamingPoolSize
585
+ });
586
+ // C++ handler snippet only showed `r.Nanite`.
587
+ // Checking snippet: `if (CVar) CVar->Set(bEnabled ? 1 : 0);`
588
+ // It missed maxPixelsPerEdge and streamingPoolSize in the snippet I read.
589
+ // Let's rely on fallback or partial console commands for the extras.
590
+ if (params.maxPixelsPerEdge !== undefined) {
591
+ await this.bridge.executeConsoleCommand(`r.Nanite.MaxPixelsPerEdge ${params.maxPixelsPerEdge}`);
592
+ }
593
+ if (params.streamingPoolSize !== undefined) {
594
+ await this.bridge.executeConsoleCommand(`r.Nanite.StreamingPoolSize ${params.streamingPoolSize}`);
595
+ }
596
+
597
+ if (response.success) return { success: true, message: 'Nanite configured' };
598
+ } catch (_e) {
599
+ // Fallback
600
+ }
601
+ }
602
+
603
+ const commands: string[] = [];
604
+
454
605
  commands.push(`r.Nanite ${params.enabled ? 1 : 0}`);
455
-
606
+
456
607
  if (params.maxPixelsPerEdge !== undefined) {
457
608
  commands.push(`r.Nanite.MaxPixelsPerEdge ${params.maxPixelsPerEdge}`);
458
609
  }
459
-
610
+
460
611
  if (params.streamingPoolSize !== undefined) {
461
612
  commands.push(`r.Nanite.StreamingPoolSize ${params.streamingPoolSize}`);
462
613
  }
463
-
614
+
464
615
  await this.bridge.executeConsoleCommands(commands);
465
-
616
+
466
617
  return { success: true, message: 'Nanite configured' };
467
618
  }
468
619
 
@@ -472,20 +623,20 @@ print('RESULT:' + json.dumps(result))
472
623
  streamingDistance?: number;
473
624
  cellSize?: number;
474
625
  }) {
475
- const commands: string[] = [];
476
-
626
+ const commands: string[] = [];
627
+
477
628
  commands.push(`wp.Runtime.EnableStreaming ${params.enabled ? 1 : 0}`);
478
-
629
+
479
630
  if (params.streamingDistance !== undefined) {
480
631
  commands.push(`wp.Runtime.StreamingDistance ${params.streamingDistance}`);
481
632
  }
482
-
633
+
483
634
  if (params.cellSize !== undefined) {
484
635
  commands.push(`wp.Runtime.CellSize ${params.cellSize}`);
485
636
  }
486
-
637
+
487
638
  await this.bridge.executeConsoleCommands(commands);
488
-
639
+
489
640
  return { success: true, message: 'World Partition configured' };
490
641
  }
491
642
 
@@ -495,16 +646,16 @@ print('RESULT:' + json.dumps(result))
495
646
  outputPath?: string;
496
647
  }) {
497
648
  const duration = params.duration || 60;
498
-
499
- // Start recording and GPU profiling
500
- await this.bridge.executeConsoleCommands(['stat startfile', 'profilegpu']);
501
-
649
+
650
+ // Start recording and GPU profiling
651
+ await this.bridge.executeConsoleCommands(['stat startfile', 'profilegpu']);
652
+
502
653
  // Wait for the requested duration
503
654
  await new Promise(resolve => setTimeout(resolve, duration * 1000));
504
-
655
+
505
656
  // Stop recording and clear stats
506
657
  await this.bridge.executeConsoleCommands(['stat stopfile', 'stat none']);
507
-
658
+
508
659
  return { success: true, message: `Benchmark completed for ${duration} seconds` };
509
660
  }
510
661
  }