ue-mcp 1.2.3 → 1.3.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 (255) hide show
  1. package/README.md +4 -3
  2. package/dist/action-class.js +56 -3
  3. package/dist/action-class.js.map +1 -1
  4. package/dist/bridge-timeouts.d.ts +64 -0
  5. package/dist/bridge-timeouts.js +118 -0
  6. package/dist/bridge-timeouts.js.map +1 -0
  7. package/dist/bridge.js +10 -2
  8. package/dist/bridge.js.map +1 -1
  9. package/dist/editor-control.d.ts +72 -5
  10. package/dist/editor-control.js +164 -140
  11. package/dist/editor-control.js.map +1 -1
  12. package/dist/editor-target.d.ts +55 -1
  13. package/dist/editor-target.js +107 -10
  14. package/dist/editor-target.js.map +1 -1
  15. package/dist/engine-observer.d.ts +59 -5
  16. package/dist/engine-observer.js +249 -29
  17. package/dist/engine-observer.js.map +1 -1
  18. package/dist/engine-root.d.ts +91 -0
  19. package/dist/engine-root.js +448 -0
  20. package/dist/engine-root.js.map +1 -0
  21. package/dist/epic-enrich.js +16 -1
  22. package/dist/epic-enrich.js.map +1 -1
  23. package/dist/feedback-cli.js +4 -0
  24. package/dist/feedback-cli.js.map +1 -1
  25. package/dist/feedback-deferred.d.ts +9 -0
  26. package/dist/feedback-deferred.js +2 -0
  27. package/dist/feedback-deferred.js.map +1 -1
  28. package/dist/feedback-fallback.d.ts +99 -0
  29. package/dist/feedback-fallback.js +173 -0
  30. package/dist/feedback-fallback.js.map +1 -0
  31. package/dist/flow/write-methods.js +20 -0
  32. package/dist/flow/write-methods.js.map +1 -1
  33. package/dist/index.js +41 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/lean-context.js +8 -3
  36. package/dist/lean-context.js.map +1 -1
  37. package/dist/locking.js +11 -2
  38. package/dist/locking.js.map +1 -1
  39. package/dist/plugin/loader.d.ts +4 -0
  40. package/dist/plugin/loader.js +22 -8
  41. package/dist/plugin/loader.js.map +1 -1
  42. package/dist/plugin/manifest.d.ts +72 -52
  43. package/dist/plugin/manifest.js +118 -21
  44. package/dist/plugin/manifest.js.map +1 -1
  45. package/dist/plugin-cli.js +16 -3
  46. package/dist/plugin-cli.js.map +1 -1
  47. package/dist/project.d.ts +11 -0
  48. package/dist/project.js +23 -2
  49. package/dist/project.js.map +1 -1
  50. package/dist/python-gate.d.ts +95 -0
  51. package/dist/python-gate.js +175 -0
  52. package/dist/python-gate.js.map +1 -0
  53. package/dist/tool-counts.json +16 -16
  54. package/dist/tools/animation.js +288 -24
  55. package/dist/tools/animation.js.map +1 -1
  56. package/dist/tools/asset.js +79 -14
  57. package/dist/tools/asset.js.map +1 -1
  58. package/dist/tools/audio.js +59 -5
  59. package/dist/tools/audio.js.map +1 -1
  60. package/dist/tools/blueprint.js +29 -12
  61. package/dist/tools/blueprint.js.map +1 -1
  62. package/dist/tools/chooser.js +4 -1
  63. package/dist/tools/chooser.js.map +1 -1
  64. package/dist/tools/editor.js +81 -43
  65. package/dist/tools/editor.js.map +1 -1
  66. package/dist/tools/feedback.js +214 -48
  67. package/dist/tools/feedback.js.map +1 -1
  68. package/dist/tools/foliage.js +27 -1
  69. package/dist/tools/foliage.js.map +1 -1
  70. package/dist/tools/gameplay.js +38 -11
  71. package/dist/tools/gameplay.js.map +1 -1
  72. package/dist/tools/gas.js +17 -5
  73. package/dist/tools/gas.js.map +1 -1
  74. package/dist/tools/landscape.js +22 -7
  75. package/dist/tools/landscape.js.map +1 -1
  76. package/dist/tools/level.js +322 -51
  77. package/dist/tools/level.js.map +1 -1
  78. package/dist/tools/material.js +10 -4
  79. package/dist/tools/material.js.map +1 -1
  80. package/dist/tools/niagara.js +3 -2
  81. package/dist/tools/niagara.js.map +1 -1
  82. package/dist/tools/pcg.js +6 -5
  83. package/dist/tools/pcg.js.map +1 -1
  84. package/dist/tools/plugins.js +2 -0
  85. package/dist/tools/plugins.js.map +1 -1
  86. package/dist/tools/project.js +47 -20
  87. package/dist/tools/project.js.map +1 -1
  88. package/dist/types.d.ts +24 -0
  89. package/dist/types.js +46 -3
  90. package/dist/types.js.map +1 -1
  91. package/dist/ue-mcp.default.yml +493 -125
  92. package/package.json +2 -2
  93. package/plugin/ue_mcp_bridge/NATIVE_RUNTIME_VISIBILITY.md +53 -0
  94. package/plugin/ue_mcp_bridge/NATIVE_STATIC_MESH_USAGE_PROGRESS.md +115 -0
  95. package/plugin/ue_mcp_bridge/README_MassHandlers.md +97 -0
  96. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.cpp +14 -0
  97. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.cpp +21 -4
  98. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.h +9 -0
  99. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerJsonProperty.h +395 -69
  100. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.cpp +79 -3
  101. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.h +25 -0
  102. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +3 -3
  103. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRigSequencer.cpp +3061 -0
  104. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRetargeterAuthoring.cpp +961 -0
  105. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRigAuthoring.cpp +900 -0
  106. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Pose.cpp +769 -0
  107. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Sequence.cpp +44 -3
  108. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_SkeletalLive.cpp +217 -11
  109. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_StateMachine.cpp +551 -24
  110. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Validation.cpp +735 -0
  111. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.cpp +352 -73
  112. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.h +8 -0
  113. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkProperties.cpp +1 -1
  114. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.cpp +503 -0
  115. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.h +21 -0
  116. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkUpsert.cpp +2 -2
  117. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Enum.cpp +2 -2
  118. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.cpp +902 -0
  119. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.h +33 -0
  120. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Import.cpp +478 -134
  121. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Mesh.cpp +5 -5
  122. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.cpp +933 -0
  123. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.h +35 -0
  124. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Redirectors.cpp +478 -0
  125. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_RenderTarget.cpp +1 -1
  126. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Sockets.cpp +4 -4
  127. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +2 -2
  128. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Subobject.cpp +319 -0
  129. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_SoundCue.cpp +3 -3
  130. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.cpp +482 -35
  131. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.h +10 -0
  132. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.cpp +502 -0
  133. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.h +43 -0
  134. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Functions.cpp +89 -7
  135. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Graph.cpp +17 -51
  136. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +107 -0
  137. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Properties.cpp +10 -10
  138. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Search.cpp +648 -0
  139. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.cpp +5 -1
  140. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.cpp +252 -1
  141. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.h +10 -2
  142. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.cpp +252 -41
  143. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.h +4 -0
  144. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +250 -27
  145. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIE.cpp +303 -125
  146. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIERuntime.cpp +73 -50
  147. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_RuntimeVisibility.cpp +757 -0
  148. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.cpp +11 -2
  149. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +3 -0
  150. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers_Batch.cpp +419 -0
  151. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.cpp +39 -161
  152. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.h +66 -1
  153. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BTAuthoring.cpp +1323 -0
  154. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BehaviorTree.cpp +1211 -0
  155. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +2 -0
  156. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +60 -0
  157. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Runtime.cpp +363 -12
  158. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/HandlerEditorState.h +84 -0
  159. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +1288 -36
  160. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.h +3 -0
  161. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +41 -16
  162. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.cpp +959 -213
  163. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.h +66 -0
  164. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_BatchWrite.cpp +1571 -0
  165. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Convert.cpp +316 -0
  166. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Inspection.cpp +280 -0
  167. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection.cpp +666 -0
  168. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection_Internal.h +63 -0
  169. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Lights.cpp +43 -12
  170. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_MultiLevel.cpp +13 -47
  171. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_PostProcess.cpp +527 -0
  172. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Query.cpp +1169 -0
  173. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Refresh.cpp +723 -0
  174. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Save.cpp +325 -0
  175. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Spatial.cpp +360 -0
  176. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Trace.cpp +178 -58
  177. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Transient.cpp +337 -0
  178. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Volumes.cpp +25 -12
  179. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartition.cpp +10 -9
  180. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartitionSettings.cpp +686 -0
  181. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.cpp +467 -0
  182. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.h +22 -0
  183. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.cpp +452 -175
  184. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.h +5 -0
  185. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Build.cpp +597 -0
  186. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.cpp +17 -15
  187. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PCGHandlers.cpp +38 -168
  188. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +39 -30
  189. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +392 -78
  190. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +2 -0
  191. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers_Internal.h +83 -0
  192. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.cpp +200 -0
  193. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.h +15 -0
  194. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +19 -12
  195. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.cpp +31 -1
  196. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.cpp +307 -69
  197. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.h +84 -0
  198. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Extraction.cpp +8 -41
  199. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Properties.cpp +33 -52
  200. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/ActorSelectorTests.cpp +344 -0
  201. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationControlRigTimelineTests.cpp +60 -0
  202. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationPoseTests.cpp +115 -0
  203. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetBulkReadTests.cpp +177 -0
  204. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetDeleteGuardTests.cpp +276 -0
  205. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPathResolutionTests.cpp +243 -0
  206. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPropertyPersistTests.cpp +213 -0
  207. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetSubobjectTests.cpp +235 -0
  208. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AutomationRunnerTests.cpp +72 -0
  209. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeAuthoringTests.cpp +526 -0
  210. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeNodeTests.cpp +334 -0
  211. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BlueprintHandlerSurfaceTests.cpp +362 -0
  212. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BridgeProtocolTests.cpp +14 -0
  213. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/CollisionQueryTests.cpp +288 -0
  214. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/DataTableRowWriteTests.cpp +453 -0
  215. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/EditorFunctionCallTests.cpp +223 -0
  216. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/FoliageBatchTests.cpp +147 -0
  217. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GameThreadGateTests.cpp +82 -0
  218. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GasLiveAttributeTests.cpp +183 -0
  219. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LandscapeSampleTests.cpp +119 -0
  220. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelBatchWriteTests.cpp +176 -0
  221. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelComponentTreeInstanceCountTests.cpp +189 -0
  222. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelConvertBrushesTests.cpp +100 -0
  223. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelInstanceProjectionTests.cpp +265 -0
  224. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelPostProcessOverrideTests.cpp +258 -0
  225. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelQueryComponentsTests.cpp +195 -0
  226. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelRefreshTests.cpp +142 -0
  227. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelSaveReportTests.cpp +125 -0
  228. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelScriptHandlersTests.cpp +42 -0
  229. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelStaticMeshUsageTests.cpp +412 -0
  230. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTraceWorldScopeTests.cpp +133 -0
  231. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTransientActorTests.cpp +205 -0
  232. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelWorldPartitionSettingsTests.cpp +168 -0
  233. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTestTypes.h +51 -0
  234. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTests.cpp +379 -0
  235. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MaterialBuildTests.cpp +238 -0
  236. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshBooleanTests.cpp +170 -0
  237. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshGeometryTests.cpp +116 -0
  238. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageSaveExtensionTests.cpp +161 -0
  239. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageWriteGuardTests.cpp +253 -0
  240. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/RuntimeVisibilityTests.cpp +143 -0
  241. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerHandlerTests.cpp +660 -0
  242. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerScrubTests.cpp +50 -0
  243. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SkeletonDiffTests.cpp +685 -0
  244. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/WidgetBlueprintResolveTests.cpp +145 -0
  245. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/UE_MCP_Bridge.cpp +80 -0
  246. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerFunctionCall.h +509 -0
  247. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerQuery.h +407 -0
  248. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerUtils.h +1008 -77
  249. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/UE_MCP_Bridge.Build.cs +87 -0
  250. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/MCPEngineStatus.cpp +152 -14
  251. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/Tests/MCPEngineStatusTests.cpp +65 -0
  252. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Public/MCPEngineStatus.h +32 -1
  253. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/UE_MCP_BridgeStatus.Build.cs +2 -0
  254. package/skills/ue-mcp-animation/SKILL.md +154 -0
  255. package/skills/ue-mcp-blueprint/SKILL.md +71 -0
@@ -0,0 +1,176 @@
1
+ // Coverage for the level batch writes that is safe to run anywhere.
2
+ //
3
+ // run_automation_tests dispatches every EditorContext/EngineFilter test in the
4
+ // process against whatever project the bridge is attached to, so nothing here
5
+ // may mutate a level. Everything below stays on the paths that are specified
6
+ // to write nothing: argument rejection, selector refusal, and the dry run.
7
+ // The committing paths are exercised by the smoke suite against the dedicated
8
+ // test project instead.
9
+
10
+ #if WITH_DEV_AUTOMATION_TESTS
11
+
12
+ #include "HandlerRegistry.h"
13
+ #include "Handlers/LevelHandlers.h"
14
+ #include "Misc/AutomationTest.h"
15
+
16
+ namespace
17
+ {
18
+ TSharedPtr<FJsonObject> MCPBatchTestRun(
19
+ FMCPHandlerRegistry& Registry,
20
+ const TCHAR* Method,
21
+ const TSharedPtr<FJsonObject>& Request)
22
+ {
23
+ const TSharedPtr<FJsonValue> Response = Registry.ExecuteHandler(Method, Request);
24
+ if (!Response.IsValid() || Response->Type != EJson::Object)
25
+ {
26
+ return nullptr;
27
+ }
28
+ return Response->AsObject();
29
+ }
30
+ }
31
+
32
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
33
+ FLevelBatchWriteRegistrationTest,
34
+ "UE.MCP.Level.BatchWrite.Registration",
35
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
36
+
37
+ bool FLevelBatchWriteRegistrationTest::RunTest(const FString& Parameters)
38
+ {
39
+ FMCPHandlerRegistry Registry;
40
+ FLevelHandlers::RegisterHandlers(Registry);
41
+
42
+ for (const TCHAR* Method : {
43
+ TEXT("batch_set_actor_properties"),
44
+ TEXT("bulk_set_component_property"),
45
+ TEXT("remove_components_by_class"),
46
+ TEXT("spawn_actors_batch") })
47
+ {
48
+ TestTrue(FString::Printf(TEXT("%s is registered"), Method), Registry.HasHandler(Method));
49
+ TestTrue(
50
+ FString::Printf(TEXT("%s carries its own timeout"), Method),
51
+ Registry.GetHandlerTimeout(Method) > 0.0f);
52
+ }
53
+ return true;
54
+ }
55
+
56
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
57
+ FLevelBatchWriteRefusalTest,
58
+ "UE.MCP.Level.BatchWrite.RefusesAnUnboundedRequest",
59
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
60
+
61
+ bool FLevelBatchWriteRefusalTest::RunTest(const FString& Parameters)
62
+ {
63
+ FMCPHandlerRegistry Registry;
64
+ FLevelHandlers::RegisterHandlers(Registry);
65
+
66
+ // batch_set_properties with no selector would mean "every actor in the
67
+ // level", which is never what someone means by a property batch.
68
+ {
69
+ TSharedPtr<FJsonObject> Properties = MakeShared<FJsonObject>();
70
+ Properties->SetBoolField(TEXT("bHidden"), true);
71
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
72
+ Request->SetObjectField(TEXT("properties"), Properties);
73
+ const TSharedPtr<FJsonObject> Response =
74
+ MCPBatchTestRun(Registry, TEXT("batch_set_actor_properties"), Request);
75
+ if (Response.IsValid())
76
+ {
77
+ TestFalse(TEXT("no selector fails"), Response->GetBoolField(TEXT("success")));
78
+ TestTrue(TEXT("and lists the selectors it accepts"),
79
+ Response->GetStringField(TEXT("error")).Contains(TEXT("labelPrefix")));
80
+ }
81
+ }
82
+
83
+ // And properties are required: a selector on its own does nothing.
84
+ {
85
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
86
+ Request->SetStringField(TEXT("tag"), TEXT("SomeTag"));
87
+ const TSharedPtr<FJsonObject> Response =
88
+ MCPBatchTestRun(Registry, TEXT("batch_set_actor_properties"), Request);
89
+ if (Response.IsValid())
90
+ {
91
+ TestFalse(TEXT("no properties fails"), Response->GetBoolField(TEXT("success")));
92
+ TestTrue(TEXT("and names the parameter"),
93
+ Response->GetStringField(TEXT("error")).Contains(TEXT("properties")));
94
+ }
95
+ }
96
+
97
+ // spawn_actors_batch needs exactly one source. Two would make the spawn
98
+ // count ambiguous, which is the sort of ambiguity that spawns 380 actors.
99
+ {
100
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
101
+ Request->SetStringField(TEXT("actorClass"), TEXT("StaticMeshActor"));
102
+ Request->SetArrayField(TEXT("instances"), { MakeShared<FJsonValueObject>(MakeShared<FJsonObject>()) });
103
+ Request->SetObjectField(TEXT("fromComponents"), MakeShared<FJsonObject>());
104
+ const TSharedPtr<FJsonObject> Response =
105
+ MCPBatchTestRun(Registry, TEXT("spawn_actors_batch"), Request);
106
+ if (Response.IsValid())
107
+ {
108
+ TestFalse(TEXT("two spawn sources fail"), Response->GetBoolField(TEXT("success")));
109
+ }
110
+ }
111
+ {
112
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
113
+ Request->SetStringField(TEXT("actorClass"), TEXT("StaticMeshActor"));
114
+ const TSharedPtr<FJsonObject> Response =
115
+ MCPBatchTestRun(Registry, TEXT("spawn_actors_batch"), Request);
116
+ if (Response.IsValid())
117
+ {
118
+ TestFalse(TEXT("no spawn source fails"), Response->GetBoolField(TEXT("success")));
119
+ }
120
+ }
121
+
122
+ // An unresolvable component class is named rather than matching nothing.
123
+ {
124
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
125
+ Request->SetStringField(TEXT("componentClass"), TEXT("NotARealComponentClass"));
126
+ const TSharedPtr<FJsonObject> Response =
127
+ MCPBatchTestRun(Registry, TEXT("remove_components_by_class"), Request);
128
+ if (Response.IsValid())
129
+ {
130
+ TestFalse(TEXT("an unresolvable component class fails"), Response->GetBoolField(TEXT("success")));
131
+ TestEqual(TEXT("and says why"),
132
+ Response->GetStringField(TEXT("reason")), FString(TEXT("class_not_found")));
133
+ }
134
+ }
135
+
136
+ return true;
137
+ }
138
+
139
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
140
+ FLevelBatchWriteDryRunDefaultTest,
141
+ "UE.MCP.Level.BatchWrite.RemoveComponentsPreviewsByDefault",
142
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
143
+
144
+ bool FLevelBatchWriteDryRunDefaultTest::RunTest(const FString& Parameters)
145
+ {
146
+ FMCPHandlerRegistry Registry;
147
+ FLevelHandlers::RegisterHandlers(Registry);
148
+
149
+ // remove_components_by_class deletes components whose auto-generated names
150
+ // a caller cannot enumerate, so it previews unless told otherwise. This
151
+ // runs against whatever map is open with no actor selector at all, which
152
+ // is the widest request the action accepts, and it must still write
153
+ // nothing.
154
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
155
+ Request->SetStringField(TEXT("componentClass"), TEXT("SplineMeshComponent"));
156
+
157
+ const TSharedPtr<FJsonObject> Response =
158
+ MCPBatchTestRun(Registry, TEXT("remove_components_by_class"), Request);
159
+ if (!Response.IsValid() || !Response->GetBoolField(TEXT("success")))
160
+ {
161
+ // No editor world available in this context, and this test may not
162
+ // open a map to make one.
163
+ return true;
164
+ }
165
+
166
+ TestTrue(TEXT("dryRun defaults to true"), Response->GetBoolField(TEXT("dryRun")));
167
+ TestFalse(TEXT("a preview saves nothing"), Response->GetBoolField(TEXT("saved")));
168
+ TestTrue(TEXT("a preview reports what it would have removed"),
169
+ Response->HasField(TEXT("wouldRemoveComponents")));
170
+ TestFalse(TEXT("and does not claim to have removed anything"),
171
+ Response->HasField(TEXT("removedComponents")));
172
+
173
+ return true;
174
+ }
175
+
176
+ #endif // WITH_DEV_AUTOMATION_TESTS
@@ -0,0 +1,189 @@
1
+ // Coverage for per-ISM instance counts in get_component_tree (#986).
2
+ //
3
+ // The tree reported an instanced mesh component's class, its mesh and its
4
+ // materials, and not how many instances it held. That is the one number that
5
+ // decides whether to touch it: a component with three instances and one with
6
+ // three hundred thousand were the same row. Getting it meant dumping every
7
+ // instance transform through get_instance_transforms just to count them.
8
+ //
9
+ // The round trip runs on a transient verification actor, which cannot be saved
10
+ // into the map and is destroyed at the end.
11
+
12
+ #if WITH_DEV_AUTOMATION_TESTS
13
+
14
+ #include "HandlerRegistry.h"
15
+ #include "Handlers/LevelHandlers.h"
16
+ #include "Misc/AutomationTest.h"
17
+
18
+ namespace
19
+ {
20
+ TSharedPtr<FJsonObject> MCPInstanceCountTestRun(
21
+ FMCPHandlerRegistry& Registry,
22
+ const TCHAR* Method,
23
+ const TSharedPtr<FJsonObject>& Request)
24
+ {
25
+ const TSharedPtr<FJsonValue> Response = Registry.ExecuteHandler(Method, Request);
26
+ if (!Response.IsValid() || Response->Type != EJson::Object)
27
+ {
28
+ return nullptr;
29
+ }
30
+ return Response->AsObject();
31
+ }
32
+
33
+ /** One transform entry for add_hismc_instances. */
34
+ TSharedPtr<FJsonValue> MCPInstanceCountTestTransform(double X)
35
+ {
36
+ TSharedPtr<FJsonObject> Location = MakeShared<FJsonObject>();
37
+ Location->SetNumberField(TEXT("x"), X);
38
+ Location->SetNumberField(TEXT("y"), 0.0);
39
+ Location->SetNumberField(TEXT("z"), 0.0);
40
+ TSharedPtr<FJsonObject> Entry = MakeShared<FJsonObject>();
41
+ Entry->SetObjectField(TEXT("location"), Location);
42
+ return MakeShared<FJsonValueObject>(Entry);
43
+ }
44
+
45
+ /** The component row for a named component in a get_component_tree response. */
46
+ TSharedPtr<FJsonObject> MCPInstanceCountTestFindComponent(
47
+ const TSharedPtr<FJsonObject>& Response,
48
+ const FString& NameContains)
49
+ {
50
+ if (!Response.IsValid()) return nullptr;
51
+ const TArray<TSharedPtr<FJsonValue>>* Rows = nullptr;
52
+ if (!Response->TryGetArrayField(TEXT("components"), Rows) || !Rows) return nullptr;
53
+ for (const TSharedPtr<FJsonValue>& Value : *Rows)
54
+ {
55
+ const TSharedPtr<FJsonObject> Row = Value.IsValid() ? Value->AsObject() : nullptr;
56
+ if (!Row.IsValid()) continue;
57
+ if (Row->GetStringField(TEXT("name")).Contains(NameContains, ESearchCase::IgnoreCase)) return Row;
58
+ }
59
+ return nullptr;
60
+ }
61
+ }
62
+
63
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
64
+ FLevelComponentTreeInstanceCountTest,
65
+ "UE.MCP.Level.ComponentTree.ReportsInstanceCounts",
66
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
67
+
68
+ bool FLevelComponentTreeInstanceCountTest::RunTest(const FString& Parameters)
69
+ {
70
+ FMCPHandlerRegistry Registry;
71
+ FLevelHandlers::RegisterHandlers(Registry);
72
+ TestTrue(TEXT("get_component_tree is registered"), Registry.HasHandler(TEXT("get_component_tree")));
73
+
74
+ TSharedPtr<FJsonObject> SpawnRequest = MakeShared<FJsonObject>();
75
+ SpawnRequest->SetStringField(TEXT("actorClass"), TEXT("StaticMeshActor"));
76
+ SpawnRequest->SetStringField(TEXT("label"), TEXT("UEMCP_InstanceCountTest"));
77
+ const TSharedPtr<FJsonObject> SpawnResponse =
78
+ MCPInstanceCountTestRun(Registry, TEXT("spawn_transient_actor"), SpawnRequest);
79
+ if (!SpawnResponse.IsValid() || !SpawnResponse->GetBoolField(TEXT("success")))
80
+ {
81
+ // No editor world in this context, and this test may not open a map.
82
+ return true;
83
+ }
84
+ const TSharedPtr<FJsonObject> SpawnedActor = SpawnResponse->GetObjectField(TEXT("actor"));
85
+ const FString ActorPath = SpawnedActor.IsValid() ? SpawnedActor->GetStringField(TEXT("actorPath")) : FString();
86
+ const FString ActorLabel = TEXT("UEMCP_InstanceCountTest");
87
+ const FString ComponentName = TEXT("UEMCP_TestHISM");
88
+
89
+ bool bAddedComponent = false;
90
+ {
91
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
92
+ Request->SetStringField(TEXT("actorLabel"), ActorLabel);
93
+ Request->SetStringField(TEXT("componentClass"), TEXT("HierarchicalInstancedStaticMeshComponent"));
94
+ Request->SetStringField(TEXT("componentName"), ComponentName);
95
+ const TSharedPtr<FJsonObject> Response =
96
+ MCPInstanceCountTestRun(Registry, TEXT("add_component_to_actor"), Request);
97
+ bAddedComponent = Response.IsValid() && Response->GetBoolField(TEXT("success"));
98
+ }
99
+
100
+ if (bAddedComponent)
101
+ {
102
+ // An empty instanced component still has to report a count. Zero is an
103
+ // answer; a missing field is not, because a caller cannot tell it apart
104
+ // from a field that was trimmed.
105
+ {
106
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
107
+ Request->SetStringField(TEXT("actorLabel"), ActorLabel);
108
+ const TSharedPtr<FJsonObject> Response =
109
+ MCPInstanceCountTestRun(Registry, TEXT("get_component_tree"), Request);
110
+ const TSharedPtr<FJsonObject> Row = MCPInstanceCountTestFindComponent(Response, ComponentName);
111
+ TestNotNull(TEXT("the tree lists the instanced component"), Row.Get());
112
+ if (Row.IsValid())
113
+ {
114
+ double Count = -1.0;
115
+ TestTrue(TEXT("an empty ISM still reports instanceCount"),
116
+ Row->TryGetNumberField(TEXT("instanceCount"), Count));
117
+ TestEqual(TEXT("which is zero"), static_cast<int32>(Count), 0);
118
+ const TSharedPtr<FJsonObject>* Instanced = nullptr;
119
+ if (Row->TryGetObjectField(TEXT("instanced"), Instanced) && Instanced)
120
+ {
121
+ TestTrue(TEXT("and a HISM is reported as hierarchical"),
122
+ (*Instanced)->GetBoolField(TEXT("hierarchical")));
123
+ }
124
+ }
125
+ }
126
+
127
+ // Add instances, then read the count back through the tree rather than
128
+ // through the writer's own report.
129
+ {
130
+ TArray<TSharedPtr<FJsonValue>> Transforms;
131
+ Transforms.Add(MCPInstanceCountTestTransform(0.0));
132
+ Transforms.Add(MCPInstanceCountTestTransform(100.0));
133
+ Transforms.Add(MCPInstanceCountTestTransform(200.0));
134
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
135
+ Request->SetStringField(TEXT("actorLabel"), ActorLabel);
136
+ Request->SetStringField(TEXT("componentName"), ComponentName);
137
+ Request->SetArrayField(TEXT("transforms"), Transforms);
138
+ const TSharedPtr<FJsonObject> AddResponse =
139
+ MCPInstanceCountTestRun(Registry, TEXT("add_hismc_instances"), Request);
140
+ if (AddResponse.IsValid() && AddResponse->GetBoolField(TEXT("success")))
141
+ {
142
+ TSharedPtr<FJsonObject> TreeRequest = MakeShared<FJsonObject>();
143
+ TreeRequest->SetStringField(TEXT("actorLabel"), ActorLabel);
144
+ const TSharedPtr<FJsonObject> TreeResponse =
145
+ MCPInstanceCountTestRun(Registry, TEXT("get_component_tree"), TreeRequest);
146
+ const TSharedPtr<FJsonObject> Row =
147
+ MCPInstanceCountTestFindComponent(TreeResponse, ComponentName);
148
+ if (Row.IsValid())
149
+ {
150
+ double Count = -1.0;
151
+ Row->TryGetNumberField(TEXT("instanceCount"), Count);
152
+ TestEqual(TEXT("the tree reports the instances that were added"),
153
+ static_cast<int32>(Count), 3);
154
+ }
155
+ }
156
+ }
157
+ }
158
+
159
+ // A component that holds no instances at all must NOT grow the field, so a
160
+ // caller can use its presence to mean "this is an instanced component".
161
+ {
162
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
163
+ Request->SetStringField(TEXT("actorLabel"), ActorLabel);
164
+ const TSharedPtr<FJsonObject> Response =
165
+ MCPInstanceCountTestRun(Registry, TEXT("get_component_tree"), Request);
166
+ const TSharedPtr<FJsonObject> Root =
167
+ MCPInstanceCountTestFindComponent(Response, TEXT("StaticMeshComponent"));
168
+ if (Root.IsValid())
169
+ {
170
+ double Count = -1.0;
171
+ TestFalse(TEXT("a plain StaticMeshComponent has no instanceCount"),
172
+ Root->TryGetNumberField(TEXT("instanceCount"), Count));
173
+ }
174
+ }
175
+
176
+ if (!ActorPath.IsEmpty())
177
+ {
178
+ TSharedPtr<FJsonObject> DestroyRequest = MakeShared<FJsonObject>();
179
+ DestroyRequest->SetStringField(TEXT("actorPath"), ActorPath);
180
+ const TSharedPtr<FJsonObject> DestroyResponse =
181
+ MCPInstanceCountTestRun(Registry, TEXT("destroy_transient_actor"), DestroyRequest);
182
+ TestTrue(TEXT("the verification actor is destroyed"),
183
+ DestroyResponse.IsValid() && DestroyResponse->GetBoolField(TEXT("success")));
184
+ }
185
+
186
+ return true;
187
+ }
188
+
189
+ #endif // WITH_DEV_AUTOMATION_TESTS
@@ -0,0 +1,100 @@
1
+ // Coverage for level(convert_brushes_to_static_mesh) (#911).
2
+ //
3
+ // The committing path destroys actors and writes new mesh packages, so nothing
4
+ // here goes near it. What is asserted is the set of refusals, because those
5
+ // are the whole feature: ConvertActors itself is one engine call.
6
+
7
+ #if WITH_DEV_AUTOMATION_TESTS
8
+
9
+ #include "HandlerRegistry.h"
10
+ #include "Handlers/LevelHandlers.h"
11
+ #include "Misc/AutomationTest.h"
12
+
13
+ namespace
14
+ {
15
+ TSharedPtr<FJsonObject> MCPConvertTestRun(FMCPHandlerRegistry& Registry, const TSharedPtr<FJsonObject>& Request)
16
+ {
17
+ const TSharedPtr<FJsonValue> Response =
18
+ Registry.ExecuteHandler(TEXT("convert_brushes_to_static_mesh"), Request);
19
+ if (!Response.IsValid() || Response->Type != EJson::Object)
20
+ {
21
+ return nullptr;
22
+ }
23
+ return Response->AsObject();
24
+ }
25
+ }
26
+
27
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
28
+ FLevelConvertBrushesGuardrailTest,
29
+ "UE.MCP.Level.ConvertBrushes.Guardrails",
30
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
31
+
32
+ bool FLevelConvertBrushesGuardrailTest::RunTest(const FString& Parameters)
33
+ {
34
+ FMCPHandlerRegistry Registry;
35
+ FLevelHandlers::RegisterHandlers(Registry);
36
+
37
+ TestTrue(TEXT("convert_brushes_to_static_mesh is registered"),
38
+ Registry.HasHandler(TEXT("convert_brushes_to_static_mesh")));
39
+ TestTrue(TEXT("it carries its own timeout, because generating meshes is slow"),
40
+ Registry.GetHandlerTimeout(TEXT("convert_brushes_to_static_mesh")) > 0.0f);
41
+
42
+ // No selector would mean "every brush in the level", and this destroys what
43
+ // it converts.
44
+ {
45
+ const TSharedPtr<FJsonObject> Response = MCPConvertTestRun(Registry, MakeShared<FJsonObject>());
46
+ if (Response.IsValid())
47
+ {
48
+ TestFalse(TEXT("an unbounded conversion fails"), Response->GetBoolField(TEXT("success")));
49
+ TestTrue(TEXT("and says it will not run against a whole level"),
50
+ Response->GetStringField(TEXT("error")).Contains(TEXT("implicitly")));
51
+ }
52
+ }
53
+
54
+ // The generated meshes must not land in engine content.
55
+ {
56
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
57
+ Request->SetStringField(TEXT("folderPath"), TEXT("Blockout"));
58
+ Request->SetStringField(TEXT("destinationPath"), TEXT("/Engine/Meshes"));
59
+ const TSharedPtr<FJsonObject> Response = MCPConvertTestRun(Registry, Request);
60
+ if (Response.IsValid())
61
+ {
62
+ TestFalse(TEXT("an engine destination fails"), Response->GetBoolField(TEXT("success")));
63
+ TestTrue(TEXT("and says why"),
64
+ Response->GetStringField(TEXT("error")).Contains(TEXT("writable")));
65
+ }
66
+ }
67
+
68
+ // A class filter that is not a brush class is a caller error, not an empty
69
+ // result set.
70
+ {
71
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
72
+ Request->SetStringField(TEXT("folderPath"), TEXT("Blockout"));
73
+ Request->SetStringField(TEXT("classFilter"), TEXT("StaticMeshActor"));
74
+ const TSharedPtr<FJsonObject> Response = MCPConvertTestRun(Registry, Request);
75
+ if (Response.IsValid())
76
+ {
77
+ TestFalse(TEXT("a non-brush class filter fails"), Response->GetBoolField(TEXT("success")));
78
+ }
79
+ }
80
+
81
+ // And the default is a preview, on a selector that is valid but matches
82
+ // nothing in an arbitrary project.
83
+ {
84
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
85
+ Request->SetStringField(TEXT("folderPath"), TEXT("UEMCPNoSuchFolderForTests"));
86
+ const TSharedPtr<FJsonObject> Response = MCPConvertTestRun(Registry, Request);
87
+ if (Response.IsValid() && Response->GetBoolField(TEXT("success")))
88
+ {
89
+ TestTrue(TEXT("dryRun defaults to true"), Response->GetBoolField(TEXT("dryRun")));
90
+ TestEqual(TEXT("an empty folder is eligible for nothing"),
91
+ static_cast<int32>(Response->GetNumberField(TEXT("eligible"))), 0);
92
+ TestTrue(TEXT("and explains what the exclusions are"),
93
+ Response->HasField(TEXT("zeroMatchNote")));
94
+ }
95
+ }
96
+
97
+ return true;
98
+ }
99
+
100
+ #endif // WITH_DEV_AUTOMATION_TESTS