unreal-engine-mcp-server 0.4.6 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. package/.env.example +26 -0
  2. package/.env.production +38 -7
  3. package/.eslintrc.json +0 -54
  4. package/.eslintrc.override.json +8 -0
  5. package/.github/ISSUE_TEMPLATE/bug_report.yml +94 -0
  6. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  7. package/.github/ISSUE_TEMPLATE/feature_request.yml +56 -0
  8. package/.github/copilot-instructions.md +478 -45
  9. package/.github/dependabot.yml +19 -0
  10. package/.github/labeler.yml +24 -0
  11. package/.github/labels.yml +70 -0
  12. package/.github/pull_request_template.md +42 -0
  13. package/.github/release-drafter.yml +148 -0
  14. package/.github/workflows/auto-merge.yml +38 -0
  15. package/.github/workflows/ci.yml +38 -0
  16. package/.github/workflows/dependency-review.yml +17 -0
  17. package/.github/workflows/gemini-issue-triage.yml +172 -0
  18. package/.github/workflows/greetings.yml +23 -0
  19. package/.github/workflows/labeler.yml +16 -0
  20. package/.github/workflows/links.yml +80 -0
  21. package/.github/workflows/pr-size-labeler.yml +137 -0
  22. package/.github/workflows/publish-mcp.yml +12 -7
  23. package/.github/workflows/release-drafter.yml +23 -0
  24. package/.github/workflows/release.yml +112 -0
  25. package/.github/workflows/semantic-pull-request.yml +35 -0
  26. package/.github/workflows/smoke-test.yml +36 -0
  27. package/.github/workflows/stale.yml +28 -0
  28. package/CHANGELOG.md +269 -22
  29. package/CONTRIBUTING.md +140 -0
  30. package/README.md +166 -72
  31. package/claude_desktop_config_example.json +7 -6
  32. package/dist/automation/bridge.d.ts +50 -0
  33. package/dist/automation/bridge.js +452 -0
  34. package/dist/automation/connection-manager.d.ts +23 -0
  35. package/dist/automation/connection-manager.js +107 -0
  36. package/dist/automation/handshake.d.ts +11 -0
  37. package/dist/automation/handshake.js +89 -0
  38. package/dist/automation/index.d.ts +3 -0
  39. package/dist/automation/index.js +3 -0
  40. package/dist/automation/message-handler.d.ts +12 -0
  41. package/dist/automation/message-handler.js +149 -0
  42. package/dist/automation/request-tracker.d.ts +25 -0
  43. package/dist/automation/request-tracker.js +98 -0
  44. package/dist/automation/types.d.ts +130 -0
  45. package/dist/automation/types.js +2 -0
  46. package/dist/cli.js +32 -5
  47. package/dist/config.d.ts +27 -0
  48. package/dist/config.js +60 -0
  49. package/dist/constants.d.ts +12 -0
  50. package/dist/constants.js +12 -0
  51. package/dist/graphql/resolvers.d.ts +268 -0
  52. package/dist/graphql/resolvers.js +743 -0
  53. package/dist/graphql/schema.d.ts +5 -0
  54. package/dist/graphql/schema.js +437 -0
  55. package/dist/graphql/server.d.ts +26 -0
  56. package/dist/graphql/server.js +115 -0
  57. package/dist/graphql/types.d.ts +7 -0
  58. package/dist/graphql/types.js +2 -0
  59. package/dist/handlers/resource-handlers.d.ts +20 -0
  60. package/dist/handlers/resource-handlers.js +180 -0
  61. package/dist/index.d.ts +31 -18
  62. package/dist/index.js +119 -604
  63. package/dist/prompts/index.js +4 -4
  64. package/dist/resources/actors.d.ts +17 -12
  65. package/dist/resources/actors.js +56 -76
  66. package/dist/resources/assets.d.ts +6 -14
  67. package/dist/resources/assets.js +115 -147
  68. package/dist/resources/levels.d.ts +13 -13
  69. package/dist/resources/levels.js +25 -34
  70. package/dist/server/resource-registry.d.ts +20 -0
  71. package/dist/server/resource-registry.js +37 -0
  72. package/dist/server/tool-registry.d.ts +23 -0
  73. package/dist/server/tool-registry.js +322 -0
  74. package/dist/server-setup.d.ts +21 -0
  75. package/dist/server-setup.js +111 -0
  76. package/dist/services/health-monitor.d.ts +34 -0
  77. package/dist/services/health-monitor.js +105 -0
  78. package/dist/services/metrics-server.d.ts +11 -0
  79. package/dist/services/metrics-server.js +105 -0
  80. package/dist/tools/actors.d.ts +147 -9
  81. package/dist/tools/actors.js +350 -311
  82. package/dist/tools/animation.d.ts +135 -4
  83. package/dist/tools/animation.js +510 -411
  84. package/dist/tools/assets.d.ts +117 -19
  85. package/dist/tools/assets.js +259 -284
  86. package/dist/tools/audio.d.ts +102 -42
  87. package/dist/tools/audio.js +272 -685
  88. package/dist/tools/base-tool.d.ts +17 -0
  89. package/dist/tools/base-tool.js +46 -0
  90. package/dist/tools/behavior-tree.d.ts +94 -0
  91. package/dist/tools/behavior-tree.js +39 -0
  92. package/dist/tools/blueprint/helpers.d.ts +29 -0
  93. package/dist/tools/blueprint/helpers.js +182 -0
  94. package/dist/tools/blueprint.d.ts +228 -118
  95. package/dist/tools/blueprint.js +685 -832
  96. package/dist/tools/consolidated-tool-definitions.d.ts +5475 -1627
  97. package/dist/tools/consolidated-tool-definitions.js +829 -482
  98. package/dist/tools/consolidated-tool-handlers.d.ts +2 -1
  99. package/dist/tools/consolidated-tool-handlers.js +211 -1009
  100. package/dist/tools/debug.d.ts +143 -85
  101. package/dist/tools/debug.js +234 -180
  102. package/dist/tools/dynamic-handler-registry.d.ts +11 -0
  103. package/dist/tools/dynamic-handler-registry.js +101 -0
  104. package/dist/tools/editor.d.ts +139 -18
  105. package/dist/tools/editor.js +239 -244
  106. package/dist/tools/engine.d.ts +10 -4
  107. package/dist/tools/engine.js +13 -5
  108. package/dist/tools/environment.d.ts +36 -0
  109. package/dist/tools/environment.js +267 -0
  110. package/dist/tools/foliage.d.ts +105 -14
  111. package/dist/tools/foliage.js +219 -331
  112. package/dist/tools/handlers/actor-handlers.d.ts +3 -0
  113. package/dist/tools/handlers/actor-handlers.js +232 -0
  114. package/dist/tools/handlers/animation-handlers.d.ts +3 -0
  115. package/dist/tools/handlers/animation-handlers.js +185 -0
  116. package/dist/tools/handlers/argument-helper.d.ts +16 -0
  117. package/dist/tools/handlers/argument-helper.js +80 -0
  118. package/dist/tools/handlers/asset-handlers.d.ts +3 -0
  119. package/dist/tools/handlers/asset-handlers.js +496 -0
  120. package/dist/tools/handlers/audio-handlers.d.ts +3 -0
  121. package/dist/tools/handlers/audio-handlers.js +166 -0
  122. package/dist/tools/handlers/blueprint-handlers.d.ts +4 -0
  123. package/dist/tools/handlers/blueprint-handlers.js +358 -0
  124. package/dist/tools/handlers/common-handlers.d.ts +14 -0
  125. package/dist/tools/handlers/common-handlers.js +56 -0
  126. package/dist/tools/handlers/editor-handlers.d.ts +3 -0
  127. package/dist/tools/handlers/editor-handlers.js +119 -0
  128. package/dist/tools/handlers/effect-handlers.d.ts +3 -0
  129. package/dist/tools/handlers/effect-handlers.js +171 -0
  130. package/dist/tools/handlers/environment-handlers.d.ts +3 -0
  131. package/dist/tools/handlers/environment-handlers.js +170 -0
  132. package/dist/tools/handlers/graph-handlers.d.ts +3 -0
  133. package/dist/tools/handlers/graph-handlers.js +90 -0
  134. package/dist/tools/handlers/input-handlers.d.ts +3 -0
  135. package/dist/tools/handlers/input-handlers.js +21 -0
  136. package/dist/tools/handlers/inspect-handlers.d.ts +3 -0
  137. package/dist/tools/handlers/inspect-handlers.js +383 -0
  138. package/dist/tools/handlers/level-handlers.d.ts +3 -0
  139. package/dist/tools/handlers/level-handlers.js +237 -0
  140. package/dist/tools/handlers/lighting-handlers.d.ts +3 -0
  141. package/dist/tools/handlers/lighting-handlers.js +144 -0
  142. package/dist/tools/handlers/performance-handlers.d.ts +3 -0
  143. package/dist/tools/handlers/performance-handlers.js +130 -0
  144. package/dist/tools/handlers/pipeline-handlers.d.ts +3 -0
  145. package/dist/tools/handlers/pipeline-handlers.js +110 -0
  146. package/dist/tools/handlers/sequence-handlers.d.ts +3 -0
  147. package/dist/tools/handlers/sequence-handlers.js +376 -0
  148. package/dist/tools/handlers/system-handlers.d.ts +4 -0
  149. package/dist/tools/handlers/system-handlers.js +506 -0
  150. package/dist/tools/input.d.ts +19 -0
  151. package/dist/tools/input.js +89 -0
  152. package/dist/tools/introspection.d.ts +103 -40
  153. package/dist/tools/introspection.js +425 -568
  154. package/dist/tools/landscape.d.ts +97 -36
  155. package/dist/tools/landscape.js +280 -409
  156. package/dist/tools/level.d.ts +130 -10
  157. package/dist/tools/level.js +639 -675
  158. package/dist/tools/lighting.d.ts +77 -38
  159. package/dist/tools/lighting.js +441 -943
  160. package/dist/tools/logs.d.ts +45 -0
  161. package/dist/tools/logs.js +210 -0
  162. package/dist/tools/materials.d.ts +91 -24
  163. package/dist/tools/materials.js +190 -118
  164. package/dist/tools/niagara.d.ts +149 -39
  165. package/dist/tools/niagara.js +232 -182
  166. package/dist/tools/performance.d.ts +27 -12
  167. package/dist/tools/performance.js +204 -122
  168. package/dist/tools/physics.d.ts +32 -77
  169. package/dist/tools/physics.js +171 -582
  170. package/dist/tools/property-dictionary.d.ts +13 -0
  171. package/dist/tools/property-dictionary.js +82 -0
  172. package/dist/tools/sequence.d.ts +73 -48
  173. package/dist/tools/sequence.js +196 -748
  174. package/dist/tools/tool-definition-utils.d.ts +59 -0
  175. package/dist/tools/tool-definition-utils.js +35 -0
  176. package/dist/tools/ui.d.ts +66 -34
  177. package/dist/tools/ui.js +134 -214
  178. package/dist/types/env.d.ts +0 -3
  179. package/dist/types/env.js +0 -7
  180. package/dist/types/tool-interfaces.d.ts +898 -0
  181. package/dist/types/tool-interfaces.js +2 -0
  182. package/dist/types/tool-types.d.ts +195 -11
  183. package/dist/types/tool-types.js +0 -4
  184. package/dist/unreal-bridge.d.ts +24 -131
  185. package/dist/unreal-bridge.js +364 -1506
  186. package/dist/utils/command-validator.d.ts +9 -0
  187. package/dist/utils/command-validator.js +67 -0
  188. package/dist/utils/elicitation.d.ts +1 -1
  189. package/dist/utils/elicitation.js +12 -15
  190. package/dist/utils/error-handler.d.ts +2 -51
  191. package/dist/utils/error-handler.js +11 -87
  192. package/dist/utils/ini-reader.d.ts +3 -0
  193. package/dist/utils/ini-reader.js +69 -0
  194. package/dist/utils/logger.js +9 -6
  195. package/dist/utils/normalize.d.ts +3 -0
  196. package/dist/utils/normalize.js +56 -0
  197. package/dist/utils/response-factory.d.ts +7 -0
  198. package/dist/utils/response-factory.js +33 -0
  199. package/dist/utils/response-validator.d.ts +3 -24
  200. package/dist/utils/response-validator.js +130 -81
  201. package/dist/utils/result-helpers.d.ts +4 -5
  202. package/dist/utils/result-helpers.js +15 -16
  203. package/dist/utils/safe-json.js +5 -11
  204. package/dist/utils/unreal-command-queue.d.ts +24 -0
  205. package/dist/utils/unreal-command-queue.js +120 -0
  206. package/dist/utils/validation.d.ts +0 -40
  207. package/dist/utils/validation.js +1 -78
  208. package/dist/wasm/index.d.ts +70 -0
  209. package/dist/wasm/index.js +535 -0
  210. package/docs/GraphQL-API.md +888 -0
  211. package/docs/Migration-Guide-v0.5.0.md +692 -0
  212. package/docs/Roadmap.md +53 -0
  213. package/docs/WebAssembly-Integration.md +628 -0
  214. package/docs/editor-plugin-extension.md +370 -0
  215. package/docs/handler-mapping.md +242 -0
  216. package/docs/native-automation-progress.md +128 -0
  217. package/docs/testing-guide.md +423 -0
  218. package/mcp-config-example.json +6 -6
  219. package/package.json +60 -27
  220. package/plugins/McpAutomationBridge/Config/FilterPlugin.ini +8 -0
  221. package/plugins/McpAutomationBridge/McpAutomationBridge.uplugin +64 -0
  222. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/McpAutomationBridge.Build.cs +189 -0
  223. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.cpp +22 -0
  224. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeGlobals.h +30 -0
  225. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeHelpers.h +1983 -0
  226. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeModule.cpp +72 -0
  227. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSettings.cpp +46 -0
  228. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +581 -0
  229. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +2394 -0
  230. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetQueryHandlers.cpp +300 -0
  231. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AssetWorkflowHandlers.cpp +2807 -0
  232. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AudioHandlers.cpp +1087 -0
  233. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BehaviorTreeHandlers.cpp +488 -0
  234. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.cpp +643 -0
  235. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintCreationHandlers.h +31 -0
  236. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +1184 -0
  237. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +5652 -0
  238. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers_List.cpp +152 -0
  239. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ControlHandlers.cpp +2614 -0
  240. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_DebugHandlers.cpp +42 -0
  241. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EditorFunctionHandlers.cpp +1237 -0
  242. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +1701 -0
  243. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +2145 -0
  244. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_FoliageHandlers.cpp +954 -0
  245. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InputHandlers.cpp +209 -0
  246. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_InsightsHandlers.cpp +41 -0
  247. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LandscapeHandlers.cpp +1164 -0
  248. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LevelHandlers.cpp +762 -0
  249. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +634 -0
  250. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LogHandlers.cpp +136 -0
  251. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_MaterialGraphHandlers.cpp +494 -0
  252. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraGraphHandlers.cpp +278 -0
  253. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_NiagaraHandlers.cpp +625 -0
  254. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PerformanceHandlers.cpp +401 -0
  255. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PipelineHandlers.cpp +67 -0
  256. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +735 -0
  257. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_PropertyHandlers.cpp +2634 -0
  258. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_RenderHandlers.cpp +189 -0
  259. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.cpp +917 -0
  260. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SCSHandlers.h +39 -0
  261. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +2670 -0
  262. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequencerHandlers.cpp +519 -0
  263. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_TestHandlers.cpp +38 -0
  264. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_UiHandlers.cpp +668 -0
  265. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_WorldPartitionHandlers.cpp +346 -0
  266. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.cpp +1330 -0
  267. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpBridgeWebSocket.h +149 -0
  268. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +783 -0
  269. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSettings.h +115 -0
  270. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpAutomationBridgeSubsystem.h +796 -0
  271. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Public/McpConnectionManager.h +117 -0
  272. package/scripts/check-unreal-connection.mjs +19 -0
  273. package/scripts/clean-tmp.js +23 -0
  274. package/scripts/patch-wasm.js +26 -0
  275. package/scripts/run-all-tests.mjs +131 -0
  276. package/scripts/smoke-test.ts +94 -0
  277. package/scripts/sync-mcp-plugin.js +143 -0
  278. package/scripts/test-no-plugin-alternates.mjs +113 -0
  279. package/scripts/validate-server.js +46 -0
  280. package/scripts/verify-automation-bridge.js +200 -0
  281. package/server.json +57 -21
  282. package/src/automation/bridge.ts +558 -0
  283. package/src/automation/connection-manager.ts +130 -0
  284. package/src/automation/handshake.ts +99 -0
  285. package/src/automation/index.ts +2 -0
  286. package/src/automation/message-handler.ts +167 -0
  287. package/src/automation/request-tracker.ts +123 -0
  288. package/src/automation/types.ts +107 -0
  289. package/src/cli.ts +33 -6
  290. package/src/config.ts +73 -0
  291. package/src/constants.ts +12 -0
  292. package/src/graphql/resolvers.ts +1010 -0
  293. package/src/graphql/schema.ts +452 -0
  294. package/src/graphql/server.ts +154 -0
  295. package/src/graphql/types.ts +7 -0
  296. package/src/handlers/resource-handlers.ts +186 -0
  297. package/src/index.ts +152 -649
  298. package/src/prompts/index.ts +4 -4
  299. package/src/resources/actors.ts +58 -76
  300. package/src/resources/assets.ts +147 -134
  301. package/src/resources/levels.ts +28 -33
  302. package/src/server/resource-registry.ts +47 -0
  303. package/src/server/tool-registry.ts +354 -0
  304. package/src/server-setup.ts +148 -0
  305. package/src/services/health-monitor.ts +132 -0
  306. package/src/services/metrics-server.ts +142 -0
  307. package/src/tools/actors.ts +417 -322
  308. package/src/tools/animation.ts +671 -461
  309. package/src/tools/assets.ts +353 -289
  310. package/src/tools/audio.ts +323 -766
  311. package/src/tools/base-tool.ts +52 -0
  312. package/src/tools/behavior-tree.ts +45 -0
  313. package/src/tools/blueprint/helpers.ts +189 -0
  314. package/src/tools/blueprint.ts +787 -965
  315. package/src/tools/consolidated-tool-definitions.ts +993 -500
  316. package/src/tools/consolidated-tool-handlers.ts +272 -1122
  317. package/src/tools/debug.ts +292 -187
  318. package/src/tools/dynamic-handler-registry.ts +151 -0
  319. package/src/tools/editor.ts +309 -246
  320. package/src/tools/engine.ts +14 -3
  321. package/src/tools/environment.ts +287 -0
  322. package/src/tools/foliage.ts +314 -379
  323. package/src/tools/handlers/actor-handlers.ts +271 -0
  324. package/src/tools/handlers/animation-handlers.ts +237 -0
  325. package/src/tools/handlers/argument-helper.ts +142 -0
  326. package/src/tools/handlers/asset-handlers.ts +532 -0
  327. package/src/tools/handlers/audio-handlers.ts +194 -0
  328. package/src/tools/handlers/blueprint-handlers.ts +380 -0
  329. package/src/tools/handlers/common-handlers.ts +87 -0
  330. package/src/tools/handlers/editor-handlers.ts +123 -0
  331. package/src/tools/handlers/effect-handlers.ts +220 -0
  332. package/src/tools/handlers/environment-handlers.ts +183 -0
  333. package/src/tools/handlers/graph-handlers.ts +116 -0
  334. package/src/tools/handlers/input-handlers.ts +28 -0
  335. package/src/tools/handlers/inspect-handlers.ts +450 -0
  336. package/src/tools/handlers/level-handlers.ts +252 -0
  337. package/src/tools/handlers/lighting-handlers.ts +147 -0
  338. package/src/tools/handlers/performance-handlers.ts +132 -0
  339. package/src/tools/handlers/pipeline-handlers.ts +127 -0
  340. package/src/tools/handlers/sequence-handlers.ts +415 -0
  341. package/src/tools/handlers/system-handlers.ts +564 -0
  342. package/src/tools/input.ts +101 -0
  343. package/src/tools/introspection.ts +493 -584
  344. package/src/tools/landscape.ts +394 -489
  345. package/src/tools/level.ts +752 -694
  346. package/src/tools/lighting.ts +583 -984
  347. package/src/tools/logs.ts +219 -0
  348. package/src/tools/materials.ts +231 -121
  349. package/src/tools/niagara.ts +293 -168
  350. package/src/tools/performance.ts +320 -168
  351. package/src/tools/physics.ts +268 -613
  352. package/src/tools/property-dictionary.ts +98 -0
  353. package/src/tools/sequence.ts +255 -815
  354. package/src/tools/tool-definition-utils.ts +35 -0
  355. package/src/tools/ui.ts +207 -283
  356. package/src/types/env.ts +0 -10
  357. package/src/types/tool-interfaces.ts +250 -0
  358. package/src/types/tool-types.ts +250 -13
  359. package/src/unreal-bridge.ts +460 -1550
  360. package/src/utils/command-validator.ts +75 -0
  361. package/src/utils/elicitation.ts +10 -7
  362. package/src/utils/error-handler.ts +14 -90
  363. package/src/utils/ini-reader.ts +86 -0
  364. package/src/utils/logger.ts +8 -3
  365. package/src/utils/normalize.ts +60 -0
  366. package/src/utils/response-factory.ts +39 -0
  367. package/src/utils/response-validator.ts +176 -56
  368. package/src/utils/result-helpers.ts +21 -19
  369. package/src/utils/safe-json.ts +14 -11
  370. package/src/utils/unreal-command-queue.ts +152 -0
  371. package/src/utils/validation.ts +4 -1
  372. package/src/wasm/index.ts +838 -0
  373. package/test-server.mjs +100 -0
  374. package/tests/run-unreal-tool-tests.mjs +242 -14
  375. package/tests/test-animation.mjs +44 -0
  376. package/tests/test-asset-advanced.mjs +82 -0
  377. package/tests/test-asset-errors.mjs +35 -0
  378. package/tests/test-audio.mjs +219 -0
  379. package/tests/test-automation-timeouts.mjs +98 -0
  380. package/tests/test-behavior-tree.mjs +261 -0
  381. package/tests/test-blueprint-events.mjs +35 -0
  382. package/tests/test-blueprint-graph.mjs +79 -0
  383. package/tests/test-blueprint.mjs +577 -0
  384. package/tests/test-client-mode.mjs +86 -0
  385. package/tests/test-console-command.mjs +56 -0
  386. package/tests/test-control-actor.mjs +425 -0
  387. package/tests/test-control-editor.mjs +80 -0
  388. package/tests/test-extra-tools.mjs +38 -0
  389. package/tests/test-graphql.mjs +322 -0
  390. package/tests/test-inspect.mjs +72 -0
  391. package/tests/test-landscape.mjs +60 -0
  392. package/tests/test-manage-asset.mjs +438 -0
  393. package/tests/test-manage-level.mjs +70 -0
  394. package/tests/test-materials.mjs +356 -0
  395. package/tests/test-niagara.mjs +185 -0
  396. package/tests/test-no-inline-python.mjs +122 -0
  397. package/tests/test-plugin-handshake.mjs +82 -0
  398. package/tests/test-render.mjs +33 -0
  399. package/tests/test-runner.mjs +933 -0
  400. package/tests/test-search-assets.mjs +66 -0
  401. package/tests/test-sequence.mjs +68 -0
  402. package/tests/test-system.mjs +57 -0
  403. package/tests/test-wasm.mjs +193 -0
  404. package/tests/test-world-partition.mjs +215 -0
  405. package/tsconfig.json +3 -3
  406. package/wasm/Cargo.lock +363 -0
  407. package/wasm/Cargo.toml +42 -0
  408. package/wasm/LICENSE +21 -0
  409. package/wasm/README.md +253 -0
  410. package/wasm/src/dependency_resolver.rs +377 -0
  411. package/wasm/src/lib.rs +153 -0
  412. package/wasm/src/property_parser.rs +271 -0
  413. package/wasm/src/transform_math.rs +396 -0
  414. package/wasm/tests/integration.rs +109 -0
  415. package/.github/workflows/smithery-build.yml +0 -29
  416. package/dist/tools/build_environment_advanced.d.ts +0 -65
  417. package/dist/tools/build_environment_advanced.js +0 -633
  418. package/dist/tools/rc.d.ts +0 -110
  419. package/dist/tools/rc.js +0 -437
  420. package/dist/tools/visual.d.ts +0 -40
  421. package/dist/tools/visual.js +0 -282
  422. package/dist/utils/http.d.ts +0 -6
  423. package/dist/utils/http.js +0 -151
  424. package/dist/utils/python-output.d.ts +0 -18
  425. package/dist/utils/python-output.js +0 -290
  426. package/dist/utils/python.d.ts +0 -2
  427. package/dist/utils/python.js +0 -4
  428. package/dist/utils/stdio-redirect.d.ts +0 -2
  429. package/dist/utils/stdio-redirect.js +0 -20
  430. package/docs/unreal-tool-test-cases.md +0 -572
  431. package/smithery.yaml +0 -29
  432. package/src/tools/build_environment_advanced.ts +0 -732
  433. package/src/tools/rc.ts +0 -515
  434. package/src/tools/visual.ts +0 -281
  435. package/src/utils/http.ts +0 -187
  436. package/src/utils/python-output.ts +0 -351
  437. package/src/utils/python.ts +0 -3
  438. package/src/utils/stdio-redirect.ts +0 -18
@@ -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,
@@ -379,21 +476,52 @@ print('RESULT:' + json.dumps(result))
379
476
  enableInstancing?: boolean;
380
477
  enableBatching?: boolean; // no-op (deprecated internal toggle)
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
+ enableBatching: params.enableBatching,
499
+ mergeActors: params.mergeActors,
500
+ actors: actors
501
+ };
502
+
503
+ const response = await this.automationBridge.sendAutomationRequest('merge_actors', payload);
504
+
505
+ return response.success
506
+ ? { success: true, message: response.message || 'Actors merged for optimization' }
507
+ : { success: false, error: response.message || response.error || 'Failed to merge actors' };
508
+ } catch (error) {
509
+ return { success: false, error: `Failed to merge actors: ${error instanceof Error ? error.message : String(error)}` };
510
+ }
511
+ }
512
+ throw new Error('Actor merging requires Automation Bridge support');
513
+ }
514
+
515
+ const commands: string[] = [];
516
+
385
517
  if (params.enableInstancing !== undefined) {
386
518
  commands.push(`r.MeshDrawCommands.DynamicInstancing ${params.enableInstancing ? 1 : 0}`);
387
519
  }
388
-
520
+
389
521
  // 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
-
522
+
395
523
  await this.bridge.executeConsoleCommands(commands);
396
-
524
+
397
525
  return { success: true, message: 'Draw call optimization configured' };
398
526
  }
399
527
 
@@ -403,18 +531,18 @@ print('RESULT:' + json.dumps(result))
403
531
  method?: 'Hardware' | 'Software' | 'Hierarchical';
404
532
  freezeRendering?: boolean;
405
533
  }) {
406
- const commands: string[] = [];
407
-
534
+ const commands: string[] = [];
535
+
408
536
  // Enable/disable HZB occlusion (boolean)
409
537
  commands.push(`r.HZBOcclusion ${params.enabled ? 1 : 0}`);
410
-
538
+
411
539
  // Optional freeze rendering toggle
412
540
  if (params.freezeRendering !== undefined) {
413
541
  commands.push(`FreezeRendering ${params.freezeRendering ? 1 : 0}`);
414
542
  }
415
-
543
+
416
544
  await this.bridge.executeConsoleCommands(commands);
417
-
545
+
418
546
  return { success: true, message: 'Occlusion culling configured' };
419
547
  }
420
548
 
@@ -424,22 +552,22 @@ print('RESULT:' + json.dumps(result))
424
552
  cacheShaders?: boolean;
425
553
  reducePermutations?: boolean;
426
554
  }) {
427
- const commands: string[] = [];
428
-
555
+ const commands: string[] = [];
556
+
429
557
  if (params.compileOnDemand !== undefined) {
430
558
  commands.push(`r.ShaderDevelopmentMode ${params.compileOnDemand ? 1 : 0}`);
431
559
  }
432
-
560
+
433
561
  if (params.cacheShaders !== undefined) {
434
562
  commands.push(`r.ShaderPipelineCache.Enabled ${params.cacheShaders ? 1 : 0}`);
435
563
  }
436
-
564
+
437
565
  if (params.reducePermutations) {
438
566
  commands.push('RecompileShaders changed');
439
567
  }
440
-
568
+
441
569
  await this.bridge.executeConsoleCommands(commands);
442
-
570
+
443
571
  return { success: true, message: 'Shader optimization configured' };
444
572
  }
445
573
 
@@ -449,20 +577,44 @@ print('RESULT:' + json.dumps(result))
449
577
  maxPixelsPerEdge?: number;
450
578
  streamingPoolSize?: number;
451
579
  }) {
452
- const commands: string[] = [];
453
-
580
+ if (this.automationBridge) {
581
+ try {
582
+ const response = await this.automationBridge.sendAutomationRequest('configure_nanite', {
583
+ enabled: params.enabled,
584
+ maxPixelsPerEdge: params.maxPixelsPerEdge,
585
+ streamingPoolSize: params.streamingPoolSize
586
+ });
587
+ // C++ handler snippet only showed `r.Nanite`.
588
+ // Checking snippet: `if (CVar) CVar->Set(bEnabled ? 1 : 0);`
589
+ // It missed maxPixelsPerEdge and streamingPoolSize in the snippet I read.
590
+ // Let's rely on fallback or partial console commands for the extras.
591
+ if (params.maxPixelsPerEdge !== undefined) {
592
+ await this.bridge.executeConsoleCommand(`r.Nanite.MaxPixelsPerEdge ${params.maxPixelsPerEdge}`);
593
+ }
594
+ if (params.streamingPoolSize !== undefined) {
595
+ await this.bridge.executeConsoleCommand(`r.Nanite.StreamingPoolSize ${params.streamingPoolSize}`);
596
+ }
597
+
598
+ if (response.success) return { success: true, message: 'Nanite configured' };
599
+ } catch (_e) {
600
+ // Fallback
601
+ }
602
+ }
603
+
604
+ const commands: string[] = [];
605
+
454
606
  commands.push(`r.Nanite ${params.enabled ? 1 : 0}`);
455
-
607
+
456
608
  if (params.maxPixelsPerEdge !== undefined) {
457
609
  commands.push(`r.Nanite.MaxPixelsPerEdge ${params.maxPixelsPerEdge}`);
458
610
  }
459
-
611
+
460
612
  if (params.streamingPoolSize !== undefined) {
461
613
  commands.push(`r.Nanite.StreamingPoolSize ${params.streamingPoolSize}`);
462
614
  }
463
-
615
+
464
616
  await this.bridge.executeConsoleCommands(commands);
465
-
617
+
466
618
  return { success: true, message: 'Nanite configured' };
467
619
  }
468
620
 
@@ -472,20 +624,20 @@ print('RESULT:' + json.dumps(result))
472
624
  streamingDistance?: number;
473
625
  cellSize?: number;
474
626
  }) {
475
- const commands: string[] = [];
476
-
627
+ const commands: string[] = [];
628
+
477
629
  commands.push(`wp.Runtime.EnableStreaming ${params.enabled ? 1 : 0}`);
478
-
630
+
479
631
  if (params.streamingDistance !== undefined) {
480
632
  commands.push(`wp.Runtime.StreamingDistance ${params.streamingDistance}`);
481
633
  }
482
-
634
+
483
635
  if (params.cellSize !== undefined) {
484
636
  commands.push(`wp.Runtime.CellSize ${params.cellSize}`);
485
637
  }
486
-
638
+
487
639
  await this.bridge.executeConsoleCommands(commands);
488
-
640
+
489
641
  return { success: true, message: 'World Partition configured' };
490
642
  }
491
643
 
@@ -495,16 +647,16 @@ print('RESULT:' + json.dumps(result))
495
647
  outputPath?: string;
496
648
  }) {
497
649
  const duration = params.duration || 60;
498
-
499
- // Start recording and GPU profiling
500
- await this.bridge.executeConsoleCommands(['stat startfile', 'profilegpu']);
501
-
650
+
651
+ // Start recording and GPU profiling
652
+ await this.bridge.executeConsoleCommands(['stat startfile', 'profilegpu']);
653
+
502
654
  // Wait for the requested duration
503
655
  await new Promise(resolve => setTimeout(resolve, duration * 1000));
504
-
656
+
505
657
  // Stop recording and clear stats
506
658
  await this.bridge.executeConsoleCommands(['stat stopfile', 'stat none']);
507
-
659
+
508
660
  return { success: true, message: `Benchmark completed for ${duration} seconds` };
509
661
  }
510
662
  }