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,633 +0,0 @@
1
- import { interpretStandardResult, coerceBoolean, coerceNumber, coerceString, coerceStringArray } from '../utils/result-helpers.js';
2
- /**
3
- * Advanced Build Environment Tools
4
- * Implements procedural terrain and foliage using documented Unreal Engine Python APIs
5
- */
6
- export class BuildEnvironmentAdvanced {
7
- bridge;
8
- constructor(bridge) {
9
- this.bridge = bridge;
10
- }
11
- /**
12
- * Create procedural terrain using ProceduralMeshComponent
13
- * This works around the landscape API limitations
14
- */
15
- async createProceduralTerrain(params) {
16
- const pythonScript = `
17
- import unreal
18
- import json
19
- import math
20
-
21
- name = ${JSON.stringify(params.name)}
22
- location = unreal.Vector(${params.location?.[0] || 0}, ${params.location?.[1] || 0}, ${params.location?.[2] || 0})
23
- size_x = ${params.sizeX || 2000}
24
- size_y = ${params.sizeY || 2000}
25
- subdivisions = ${params.subdivisions || 50}
26
- height_function = ${JSON.stringify(params.heightFunction || 'math.sin(x/100) * 50 + math.cos(y/100) * 30')}
27
-
28
- result = {}
29
-
30
- try:
31
- # Get editor subsystem
32
- subsys = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
33
-
34
- # Create ProceduralMeshActor
35
- proc_actor = None
36
- proc_mesh_comp = None
37
-
38
- # Try ProceduralMeshActor first
39
- try:
40
- proc_actor = subsys.spawn_actor_from_class(
41
- unreal.ProceduralMeshActor,
42
- location,
43
- unreal.Rotator(0, 0, 0)
44
- )
45
- proc_actor.set_actor_label(f"{name}_ProceduralTerrain")
46
- proc_mesh_comp = proc_actor.get_component_by_class(unreal.ProceduralMeshComponent)
47
- except:
48
- # Fallback: Create empty actor and add ProceduralMeshComponent
49
- # If spawning ProceduralMeshActor failed, surface a clear error about the plugin requirement
50
- raise Exception("Failed to spawn ProceduralMeshActor. Ensure the 'Procedural Mesh Component' plugin is enabled and available.")
51
-
52
- if proc_mesh_comp:
53
- # Generate terrain mesh
54
- vertices = []
55
- triangles = []
56
- normals = []
57
- uvs = []
58
- vertex_colors = []
59
-
60
- step_x = size_x / subdivisions
61
- step_y = size_y / subdivisions
62
-
63
- # Create vertices with height variation
64
- for y in range(subdivisions + 1):
65
- for x in range(subdivisions + 1):
66
- # Position
67
- vert_x = x * step_x - size_x / 2
68
- vert_y = y * step_y - size_y / 2
69
-
70
- # Calculate height using the provided function
71
- try:
72
- vert_z = eval(height_function, {"x": vert_x, "y": vert_y, "math": math})
73
- except:
74
- vert_z = 0 # Fallback to flat if function fails
75
-
76
- vertices.append(unreal.Vector(vert_x, vert_y, vert_z))
77
- normals.append(unreal.Vector(0, 0, 1)) # Will be recalculated
78
- uvs.append(unreal.Vector2D(x / subdivisions, y / subdivisions))
79
-
80
- # Color based on height
81
- height_normalized = min(1.0, max(0.0, (vert_z + 100) / 200))
82
- vertex_colors.append(unreal.LinearColor(height_normalized, 1 - height_normalized, 0.2, 1))
83
-
84
- # Create triangles
85
- for y in range(subdivisions):
86
- for x in range(subdivisions):
87
- idx = y * (subdivisions + 1) + x
88
-
89
- # First triangle
90
- triangles.extend([idx, idx + subdivisions + 1, idx + 1])
91
- # Second triangle
92
- triangles.extend([idx + 1, idx + subdivisions + 1, idx + subdivisions + 2])
93
-
94
- # Create mesh section
95
- proc_mesh_comp.create_mesh_section_linear_color(
96
- 0, # Section index
97
- vertices,
98
- triangles,
99
- normals,
100
- uvs,
101
- vertex_colors,
102
- [], # Tangents
103
- True # Create collision
104
- )
105
-
106
- # Apply material if specified
107
- if ${JSON.stringify(params.material || '')}:
108
- material = unreal.EditorAssetLibrary.load_asset(${JSON.stringify(params.material || '/Engine/MapTemplates/Materials/BasicGrid01')})
109
- if material:
110
- proc_mesh_comp.set_material(0, material)
111
-
112
- # Enable collision
113
- proc_mesh_comp.set_collision_enabled(unreal.CollisionEnabled.QUERY_AND_PHYSICS)
114
-
115
- result = {
116
- "success": True,
117
- "message": f"Created procedural terrain '{name}'",
118
- "actor_name": proc_actor.get_actor_label(),
119
- "vertices": len(vertices),
120
- "triangles": len(triangles) // 3,
121
- "size": [size_x, size_y],
122
- "subdivisions": subdivisions
123
- }
124
- else:
125
- result = {"success": False, "error": "Could not create ProceduralMeshComponent"}
126
-
127
- except Exception as e:
128
- result = {"success": False, "error": str(e)}
129
-
130
- print(f"RESULT:{json.dumps(result)}")
131
- `.trim();
132
- const response = await this.bridge.executePython(pythonScript);
133
- const interpreted = interpretStandardResult(response, {
134
- successMessage: `Created procedural terrain '${params.name}'`,
135
- failureMessage: `Failed to create procedural terrain '${params.name}'`
136
- });
137
- if (!interpreted.success) {
138
- const failure = {
139
- success: false,
140
- error: interpreted.error ?? interpreted.message,
141
- message: interpreted.message
142
- };
143
- if (interpreted.warnings) {
144
- failure.warnings = interpreted.warnings;
145
- }
146
- if (interpreted.details) {
147
- failure.details = interpreted.details;
148
- }
149
- if (interpreted.payload && Object.keys(interpreted.payload).length > 0) {
150
- failure.payload = interpreted.payload;
151
- }
152
- return failure;
153
- }
154
- const payload = { ...interpreted.payload };
155
- const actorName = coerceString(payload.actor_name) ?? coerceString(payload.actorName);
156
- const vertices = coerceNumber(payload.vertices);
157
- const triangles = coerceNumber(payload.triangles);
158
- const subdivisions = coerceNumber(payload.subdivisions);
159
- const sizeArray = Array.isArray(payload.size)
160
- ? payload.size.map(entry => {
161
- if (typeof entry === 'number' && Number.isFinite(entry)) {
162
- return entry;
163
- }
164
- if (typeof entry === 'string') {
165
- const parsed = Number(entry);
166
- return Number.isFinite(parsed) ? parsed : undefined;
167
- }
168
- return undefined;
169
- }).filter((entry) => typeof entry === 'number')
170
- : undefined;
171
- payload.success = true;
172
- payload.message = interpreted.message;
173
- if (actorName) {
174
- payload.actor_name = actorName;
175
- payload.actorName = actorName;
176
- }
177
- if (typeof vertices === 'number') {
178
- payload.vertices = vertices;
179
- }
180
- if (typeof triangles === 'number') {
181
- payload.triangles = triangles;
182
- }
183
- if (typeof subdivisions === 'number') {
184
- payload.subdivisions = subdivisions;
185
- }
186
- if (sizeArray && sizeArray.length === 2) {
187
- payload.size = sizeArray;
188
- }
189
- if (interpreted.warnings) {
190
- payload.warnings = interpreted.warnings;
191
- }
192
- if (interpreted.details) {
193
- payload.details = interpreted.details;
194
- }
195
- return payload;
196
- }
197
- /**
198
- * Create procedural foliage using ProceduralFoliageSpawner
199
- * Uses the documented Unreal Engine API
200
- */
201
- async createProceduralFoliage(params) {
202
- const pythonScript = `
203
- import unreal
204
- import json
205
-
206
- name = ${JSON.stringify(params.name)}
207
- bounds_location = unreal.Vector(${params.bounds.location[0]}, ${params.bounds.location[1]}, ${params.bounds.location[2]})
208
- bounds_size = unreal.Vector(${params.bounds.size[0]}, ${params.bounds.size[1]}, ${params.bounds.size[2]})
209
- seed = ${params.seed || 12345}
210
-
211
- result = {}
212
-
213
- try:
214
- subsys = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
215
- asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
216
-
217
- # Validate Procedural Foliage plugin/classes are available
218
- if not hasattr(unreal, 'ProceduralFoliageVolume') or not hasattr(unreal, 'ProceduralFoliageSpawner'):
219
- raise Exception("Procedural Foliage plugin not available. Please enable the 'Procedural Foliage' plugin and try again.")
220
-
221
- # Create ProceduralFoliageVolume
222
- volume_actor = subsys.spawn_actor_from_class(
223
- unreal.ProceduralFoliageVolume,
224
- bounds_location,
225
- unreal.Rotator(0, 0, 0)
226
- )
227
- volume_actor.set_actor_label(f"{name}_ProceduralFoliageVolume")
228
- volume_actor.set_actor_scale3d(unreal.Vector(bounds_size.x/100.0, bounds_size.y/100.0, bounds_size.z/100.0)) # Scale is in meters
229
-
230
- # Get the procedural component
231
- proc_comp = volume_actor.procedural_component
232
- if not proc_comp:
233
- proc_comp = volume_actor.get_component_by_class(unreal.ProceduralFoliageComponent)
234
-
235
- if proc_comp:
236
- # Create ProceduralFoliageSpawner asset
237
- spawner_path = f"/Game/Foliage/Spawners/{name}_Spawner"
238
- package_path = "/Game/Foliage/Spawners"
239
-
240
- # Ensure directory exists
241
- if not unreal.EditorAssetLibrary.does_directory_exist(package_path):
242
- unreal.EditorAssetLibrary.make_directory(package_path)
243
-
244
- # Create spawner
245
- spawner = None
246
- if unreal.EditorAssetLibrary.does_asset_exist(spawner_path):
247
- spawner = unreal.EditorAssetLibrary.load_asset(spawner_path)
248
- else:
249
- # Create new spawner
250
- factory = unreal.ProceduralFoliageSpawnerFactory()
251
- spawner = asset_tools.create_asset(
252
- asset_name=f"{name}_Spawner",
253
- package_path=package_path,
254
- asset_class=unreal.ProceduralFoliageSpawner,
255
- factory=factory
256
- )
257
-
258
- if spawner:
259
- # Configure spawner (use set_editor_property for read-only attributes)
260
- spawner.set_editor_property('random_seed', seed)
261
- spawner.set_editor_property('tile_size', max(bounds_size.x, bounds_size.y))
262
-
263
- # Create foliage types
264
- foliage_types = []
265
- ft_input = json.loads(r'''${JSON.stringify(params.foliageTypes)}''')
266
- for ft_params in ft_input:
267
- # Load mesh
268
- mesh = unreal.EditorAssetLibrary.load_asset(ft_params['meshPath'])
269
- if mesh:
270
- # Create FoliageTypeObject
271
- ft_obj = unreal.FoliageTypeObject()
272
-
273
- # Try to create or load FoliageType_InstancedStaticMesh
274
- ft_asset_name = f"FT_{name}_{len(foliage_types)}"
275
- ft_asset_path = f"/Game/Foliage/Types/{ft_asset_name}"
276
-
277
- ft_asset = None
278
- if unreal.EditorAssetLibrary.does_asset_exist(ft_asset_path):
279
- ft_asset = unreal.EditorAssetLibrary.load_asset(ft_asset_path)
280
- else:
281
- # Create simple foliage type
282
- ft_asset = unreal.FoliageType_InstancedStaticMesh()
283
-
284
- if ft_asset:
285
- # Configure foliage type (use set_editor_property)
286
- ft_asset.set_editor_property('mesh', mesh)
287
- ft_asset.set_editor_property('density', ft_params.get('density', 1.0))
288
- ft_asset.set_editor_property('random_yaw', ft_params.get('randomYaw', True))
289
- ft_asset.set_editor_property('align_to_normal', ft_params.get('alignToNormal', True))
290
-
291
- min_scale = ft_params.get('minScale', 0.8)
292
- max_scale = ft_params.get('maxScale', 1.2)
293
- ft_asset.set_editor_property('scale_x', unreal.FloatInterval(min_scale, max_scale))
294
- ft_asset.set_editor_property('scale_y', unreal.FloatInterval(min_scale, max_scale))
295
- ft_asset.set_editor_property('scale_z', unreal.FloatInterval(min_scale, max_scale))
296
-
297
- ft_obj.set_editor_property('foliage_type_object', ft_asset)
298
- foliage_types.append(ft_obj)
299
-
300
- # Set foliage types on spawner
301
- spawner.set_editor_property('foliage_types', foliage_types)
302
-
303
- # Assign spawner to component
304
- proc_comp.set_editor_property('foliage_spawner', spawner)
305
-
306
- # Save spawner asset
307
- unreal.EditorAssetLibrary.save_asset(spawner.get_path_name())
308
-
309
- # Resimulate
310
- try:
311
- unreal.ProceduralFoliageEditorLibrary.resimulate_procedural_foliage_volumes([volume_actor])
312
- result['resimulated'] = True
313
- except:
314
- # Manual simulation
315
- spawner.simulate(num_steps=-1)
316
- result['resimulated'] = False
317
- result['note'] = 'Used manual simulation'
318
-
319
- result['success'] = True
320
- result['message'] = f"Created procedural foliage volume '{name}'"
321
- result['volume_actor'] = volume_actor.get_actor_label()
322
- result['spawner_path'] = spawner.get_path_name()
323
- result['foliage_types_count'] = len(foliage_types)
324
- else:
325
- result['success'] = False
326
- result['error'] = 'Could not create ProceduralFoliageSpawner'
327
- else:
328
- result['success'] = False
329
- result['error'] = 'Could not get ProceduralFoliageComponent'
330
-
331
- except Exception as e:
332
- result['success'] = False
333
- result['error'] = str(e)
334
-
335
- print(f"RESULT:{json.dumps(result)}")
336
- `.trim();
337
- const response = await this.bridge.executePython(pythonScript);
338
- const interpreted = interpretStandardResult(response, {
339
- successMessage: `Created procedural foliage volume '${params.name}'`,
340
- failureMessage: `Failed to create procedural foliage volume '${params.name}'`
341
- });
342
- if (!interpreted.success) {
343
- const failure = {
344
- success: false,
345
- error: interpreted.error ?? interpreted.message,
346
- message: interpreted.message
347
- };
348
- if (interpreted.warnings) {
349
- failure.warnings = interpreted.warnings;
350
- }
351
- if (interpreted.details) {
352
- failure.details = interpreted.details;
353
- }
354
- if (interpreted.payload && Object.keys(interpreted.payload).length > 0) {
355
- failure.payload = interpreted.payload;
356
- }
357
- return failure;
358
- }
359
- const payload = { ...interpreted.payload };
360
- const volumeActor = coerceString(payload.volume_actor) ?? coerceString(payload.volumeActor);
361
- const spawnerPath = coerceString(payload.spawner_path) ?? coerceString(payload.spawnerPath);
362
- const foliageCount = coerceNumber(payload.foliage_types_count) ?? coerceNumber(payload.foliageTypesCount);
363
- const resimulated = coerceBoolean(payload.resimulated);
364
- const note = coerceString(payload.note);
365
- const messages = coerceStringArray(payload.messages);
366
- payload.success = true;
367
- payload.message = interpreted.message;
368
- if (volumeActor) {
369
- payload.volume_actor = volumeActor;
370
- payload.volumeActor = volumeActor;
371
- }
372
- if (spawnerPath) {
373
- payload.spawner_path = spawnerPath;
374
- payload.spawnerPath = spawnerPath;
375
- }
376
- if (typeof foliageCount === 'number') {
377
- payload.foliage_types_count = foliageCount;
378
- payload.foliageTypesCount = foliageCount;
379
- }
380
- if (typeof resimulated === 'boolean') {
381
- payload.resimulated = resimulated;
382
- }
383
- if (note) {
384
- payload.note = note;
385
- }
386
- if (messages && messages.length > 0) {
387
- payload.messages = messages;
388
- }
389
- if (interpreted.warnings) {
390
- payload.warnings = interpreted.warnings;
391
- }
392
- if (interpreted.details) {
393
- payload.details = interpreted.details;
394
- }
395
- return payload;
396
- }
397
- /**
398
- * Add foliage instances using InstancedFoliageActor
399
- * Direct instance placement approach
400
- */
401
- async addFoliageInstances(params) {
402
- const pythonScript = `
403
- import unreal
404
- import json
405
-
406
- foliage_type_path = ${JSON.stringify(params.foliageType)}
407
- transforms_data = ${JSON.stringify(params.transforms)}
408
-
409
- result = {}
410
-
411
- try:
412
- # Get world context
413
- editor_subsystem = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem)
414
- world = editor_subsystem.get_editor_world()
415
-
416
- # Load foliage type or mesh
417
- foliage_asset = unreal.EditorAssetLibrary.load_asset(foliage_type_path)
418
-
419
- if foliage_asset:
420
- # Prepare transforms
421
- transforms = []
422
- for t_data in transforms_data:
423
- location = unreal.Vector(t_data['location'][0], t_data['location'][1], t_data['location'][2])
424
- rotation = unreal.Rotator(
425
- t_data.get('rotation', [0, 0, 0])[0],
426
- t_data.get('rotation', [0, 0, 0])[1],
427
- t_data.get('rotation', [0, 0, 0])[2]
428
- )
429
- scale = unreal.Vector(
430
- t_data.get('scale', [1, 1, 1])[0],
431
- t_data.get('scale', [1, 1, 1])[1],
432
- t_data.get('scale', [1, 1, 1])[2]
433
- )
434
-
435
- transform = unreal.Transform(location, rotation, scale)
436
- transforms.append(transform)
437
-
438
- # Add instances using InstancedFoliageActor
439
- unreal.InstancedFoliageActor.add_instances(
440
- world,
441
- foliage_asset,
442
- transforms
443
- )
444
-
445
- result['success'] = True
446
- result['message'] = f"Added {len(transforms)} foliage instances"
447
- result['instances_count'] = len(transforms)
448
- else:
449
- result['success'] = False
450
- result['error'] = f"Could not load foliage asset: {foliage_type_path}"
451
-
452
- except Exception as e:
453
- result['success'] = False
454
- result['error'] = str(e)
455
-
456
- print(f"RESULT:{json.dumps(result)}")
457
- `.trim();
458
- const response = await this.bridge.executePython(pythonScript);
459
- const interpreted = interpretStandardResult(response, {
460
- successMessage: 'Foliage instances added',
461
- failureMessage: 'Failed to add foliage instances'
462
- });
463
- if (!interpreted.success) {
464
- const failure = {
465
- success: false,
466
- error: interpreted.error ?? interpreted.message,
467
- message: interpreted.message
468
- };
469
- if (interpreted.warnings) {
470
- failure.warnings = interpreted.warnings;
471
- }
472
- if (interpreted.details) {
473
- failure.details = interpreted.details;
474
- }
475
- if (interpreted.payload && Object.keys(interpreted.payload).length > 0) {
476
- failure.payload = interpreted.payload;
477
- }
478
- return failure;
479
- }
480
- const payload = { ...interpreted.payload };
481
- const count = coerceNumber(payload.instances_count) ?? coerceNumber(payload.instancesCount);
482
- const message = coerceString(payload.message) ?? interpreted.message;
483
- payload.success = true;
484
- payload.message = message;
485
- if (typeof count === 'number') {
486
- payload.instances_count = count;
487
- payload.instancesCount = count;
488
- }
489
- if (interpreted.warnings) {
490
- payload.warnings = interpreted.warnings;
491
- }
492
- if (interpreted.details) {
493
- payload.details = interpreted.details;
494
- }
495
- return payload;
496
- }
497
- /**
498
- * Create landscape grass type for automatic foliage on landscape
499
- */
500
- async createLandscapeGrassType(params) {
501
- const pythonScript = `
502
- import unreal
503
- import json
504
-
505
- name = ${JSON.stringify(params.name)}
506
- mesh_path = ${JSON.stringify(params.meshPath)}
507
- density = ${params.density || 1.0}
508
- min_scale = ${params.minScale || 0.8}
509
- max_scale = ${params.maxScale || 1.2}
510
-
511
- result = {}
512
-
513
- try:
514
- asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
515
-
516
- # Create directory
517
- package_path = "/Game/Landscape/GrassTypes"
518
- if not unreal.EditorAssetLibrary.does_directory_exist(package_path):
519
- unreal.EditorAssetLibrary.make_directory(package_path)
520
-
521
- # Create LandscapeGrassType
522
- grass_type_path = f"{package_path}/{name}"
523
-
524
- if not unreal.EditorAssetLibrary.does_asset_exist(grass_type_path):
525
- # Create using factory
526
- factory = unreal.LandscapeGrassTypeFactory()
527
- grass_type = asset_tools.create_asset(
528
- asset_name=name,
529
- package_path=package_path,
530
- asset_class=unreal.LandscapeGrassType,
531
- factory=factory
532
- )
533
-
534
- if grass_type:
535
- # Load mesh
536
- mesh = unreal.EditorAssetLibrary.load_asset(mesh_path)
537
- if mesh:
538
- # Configure grass type (use set_editor_property)
539
- grass_variety = unreal.GrassVariety()
540
- grass_variety.set_editor_property('grass_mesh', mesh)
541
- # GrassDensity is PerPlatformFloat in UE5+; set via struct instance
542
- pp_density = unreal.PerPlatformFloat()
543
- pp_density.set_editor_property('Default', float(density * 100.0))
544
- grass_variety.set_editor_property('grass_density', pp_density)
545
- grass_variety.set_editor_property('use_grid', True)
546
- grass_variety.set_editor_property('placement_jitter', 1.0)
547
- # Set cull distances as PerPlatformInt and LOD as int (engine uses mixed types here)
548
- pp_start = unreal.PerPlatformInt()
549
- pp_start.set_editor_property('Default', 10000)
550
- grass_variety.set_editor_property('start_cull_distance', pp_start)
551
- pp_end = unreal.PerPlatformInt()
552
- pp_end.set_editor_property('Default', 20000)
553
- grass_variety.set_editor_property('end_cull_distance', pp_end)
554
- grass_variety.set_editor_property('min_lod', -1)
555
- grass_variety.set_editor_property('scaling', unreal.GrassScaling.UNIFORM)
556
- grass_variety.set_editor_property('scale_x', unreal.FloatInterval(min_scale, max_scale))
557
- grass_variety.set_editor_property('scale_y', unreal.FloatInterval(min_scale, max_scale))
558
- grass_variety.set_editor_property('scale_z', unreal.FloatInterval(min_scale, max_scale))
559
- grass_variety.set_editor_property('random_rotation', True)
560
- grass_variety.set_editor_property('align_to_surface', True)
561
-
562
- grass_type.set_editor_property('grass_varieties', [grass_variety])
563
-
564
- # Save asset
565
- unreal.EditorAssetLibrary.save_asset(grass_type.get_path_name())
566
-
567
- result['success'] = True
568
- result['message'] = f"Created landscape grass type '{name}'"
569
- result['asset_path'] = grass_type.get_path_name()
570
- else:
571
- result['success'] = False
572
- result['error'] = f"Could not load mesh: {mesh_path}"
573
- else:
574
- result['success'] = False
575
- result['error'] = "Could not create LandscapeGrassType"
576
- else:
577
- result['success'] = False
578
- result['error'] = f"Grass type already exists: {grass_type_path}"
579
-
580
- except Exception as e:
581
- result['success'] = False
582
- result['error'] = str(e)
583
-
584
- print(f"RESULT:{json.dumps(result)}")
585
- `.trim();
586
- const response = await this.bridge.executePython(pythonScript);
587
- const interpreted = interpretStandardResult(response, {
588
- successMessage: `Created landscape grass type '${params.name}'`,
589
- failureMessage: `Failed to create landscape grass type '${params.name}'`
590
- });
591
- if (!interpreted.success) {
592
- const failure = {
593
- success: false,
594
- error: interpreted.error ?? interpreted.message,
595
- message: interpreted.message
596
- };
597
- if (interpreted.warnings) {
598
- failure.warnings = interpreted.warnings;
599
- }
600
- if (interpreted.details) {
601
- failure.details = interpreted.details;
602
- }
603
- if (interpreted.payload && Object.keys(interpreted.payload).length > 0) {
604
- failure.payload = interpreted.payload;
605
- }
606
- return failure;
607
- }
608
- const payload = { ...interpreted.payload };
609
- const assetPath = coerceString(payload.asset_path) ?? coerceString(payload.assetPath);
610
- const note = coerceString(payload.note);
611
- const messages = coerceStringArray(payload.messages);
612
- payload.success = true;
613
- payload.message = interpreted.message;
614
- if (assetPath) {
615
- payload.asset_path = assetPath;
616
- payload.assetPath = assetPath;
617
- }
618
- if (note) {
619
- payload.note = note;
620
- }
621
- if (messages && messages.length > 0) {
622
- payload.messages = messages;
623
- }
624
- if (interpreted.warnings) {
625
- payload.warnings = interpreted.warnings;
626
- }
627
- if (interpreted.details) {
628
- payload.details = interpreted.details;
629
- }
630
- return payload;
631
- }
632
- }
633
- //# sourceMappingURL=build_environment_advanced.js.map