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
@@ -399,6 +399,7 @@ TSharedPtr<FJsonValue> FNiagaraHandlers::SpawnNiagaraAtLocation(const TSharedPtr
399
399
  if (SpawnedComponent->GetOwner())
400
400
  {
401
401
  Result->SetStringField(TEXT("actorLabel"), SpawnedComponent->GetOwner()->GetActorLabel());
402
+ Result->SetStringField(TEXT("actorPath"), SpawnedComponent->GetOwner()->GetPathName());
402
403
  Result->SetStringField(TEXT("actorName"), SpawnedComponent->GetOwner()->GetName());
403
404
 
404
405
  // Rollback: delete_actor
@@ -476,6 +477,7 @@ TSharedPtr<FJsonValue> FNiagaraHandlers::SpawnNiagaraActor(const TSharedPtr<FJso
476
477
  MCPSetCreated(Result);
477
478
  Result->SetStringField(TEXT("systemPath"), SystemPath);
478
479
  Result->SetStringField(TEXT("actorLabel"), Actor->GetActorLabel());
480
+ Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
479
481
  Result->SetStringField(TEXT("actorName"), Actor->GetName());
480
482
  Result->SetBoolField(TEXT("activated"), bActivate);
481
483
 
@@ -491,15 +493,14 @@ TSharedPtr<FJsonValue> FNiagaraHandlers::SpawnNiagaraActor(const TSharedPtr<FJso
491
493
  TSharedPtr<FJsonValue> FNiagaraHandlers::ReactivateNiagara(const TSharedPtr<FJsonObject>& Params)
492
494
  {
493
495
  FString ActorLabel;
494
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
496
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
495
497
 
496
498
  REQUIRE_EDITOR_WORLD(World);
497
499
 
498
- AActor* Actor = FindActorByLabel(World, ActorLabel);
499
- if (!Actor)
500
- {
501
- return MCPError(FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
502
- }
500
+ TSharedPtr<FJsonValue> ActorErr;
501
+ AActor* Actor = MCPResolveActor(World, Params, ActorErr);
502
+ if (!Actor) return ActorErr;
503
+ ActorLabel = Actor->GetActorLabel();
503
504
  UNiagaraComponent* Comp = Actor->FindComponentByClass<UNiagaraComponent>();
504
505
  if (!Comp)
505
506
  {
@@ -513,13 +514,14 @@ TSharedPtr<FJsonValue> FNiagaraHandlers::ReactivateNiagara(const TSharedPtr<FJso
513
514
  auto Result = MCPSuccess();
514
515
  MCPSetUpdated(Result);
515
516
  Result->SetStringField(TEXT("actorLabel"), ActorLabel);
517
+ Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
516
518
  return MCPResult(Result);
517
519
  }
518
520
 
519
521
  TSharedPtr<FJsonValue> FNiagaraHandlers::SetNiagaraParameter(const TSharedPtr<FJsonObject>& Params)
520
522
  {
521
523
  FString ActorLabel;
522
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
524
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
523
525
 
524
526
  FString ParameterName;
525
527
  if (auto Err = RequireString(Params, TEXT("parameterName"), ParameterName)) return Err;
@@ -528,11 +530,10 @@ TSharedPtr<FJsonValue> FNiagaraHandlers::SetNiagaraParameter(const TSharedPtr<FJ
528
530
 
529
531
  REQUIRE_EDITOR_WORLD(World);
530
532
 
531
- AActor* FoundActor = FindActorByLabel(World, ActorLabel);
532
- if (!FoundActor)
533
- {
534
- return MCPError(FString::Printf(TEXT("Actor not found with label: %s"), *ActorLabel));
535
- }
533
+ TSharedPtr<FJsonValue> ActorErr;
534
+ AActor* FoundActor = MCPResolveActor(World, Params, ActorErr);
535
+ if (!FoundActor) return ActorErr;
536
+ ActorLabel = FoundActor->GetActorLabel();
536
537
 
537
538
  // Get Niagara component from the actor
538
539
  UNiagaraComponent* NiagaraComp = FoundActor->FindComponentByClass<UNiagaraComponent>();
@@ -589,6 +590,7 @@ TSharedPtr<FJsonValue> FNiagaraHandlers::SetNiagaraParameter(const TSharedPtr<FJ
589
590
 
590
591
  MCPSetUpdated(Result);
591
592
  Result->SetStringField(TEXT("actorLabel"), ActorLabel);
593
+ Result->SetStringField(TEXT("actorPath"), FoundActor->GetPathName());
592
594
  Result->SetStringField(TEXT("parameterName"), ParameterName);
593
595
  Result->SetStringField(TEXT("parameterType"), ParameterType);
594
596
  // No rollback: runtime niagara parameter overrides are ephemeral; replaying is safe.
@@ -1329,7 +1331,7 @@ namespace
1329
1331
  return Src ? Src->NodeGraph : nullptr;
1330
1332
  }
1331
1333
 
1332
- TSharedPtr<FJsonObject> PinToJson(const UEdGraphPin* Pin)
1334
+ TSharedPtr<FJsonObject> NiagaraPinToJson(const UEdGraphPin* Pin)
1333
1335
  {
1334
1336
  TSharedPtr<FJsonObject> O = MakeShared<FJsonObject>();
1335
1337
  O->SetStringField(TEXT("name"), Pin->PinName.ToString());
@@ -1518,8 +1520,8 @@ TSharedPtr<FJsonValue> FNiagaraHandlers::ListModuleInputs(const TSharedPtr<FJson
1518
1520
  for (UEdGraphPin* Pin : FC->Pins)
1519
1521
  {
1520
1522
  if (!Pin) continue;
1521
- if (Pin->Direction == EGPD_Input) SwitchPins.Add(MakeShared<FJsonValueObject>(PinToJson(Pin)));
1522
- if (Pin->Direction == EGPD_Output) Outputs.Add(MakeShared<FJsonValueObject>(PinToJson(Pin)));
1523
+ if (Pin->Direction == EGPD_Input) SwitchPins.Add(MakeShared<FJsonValueObject>(NiagaraPinToJson(Pin)));
1524
+ if (Pin->Direction == EGPD_Output) Outputs.Add(MakeShared<FJsonValueObject>(NiagaraPinToJson(Pin)));
1523
1525
  }
1524
1526
  ModObj->SetArrayField(TEXT("inputs"), Inputs);
1525
1527
  ModObj->SetNumberField(TEXT("inputCount"), Inputs.Num());
@@ -2,6 +2,7 @@
2
2
  #include "HandlerRegistry.h"
3
3
  #include "HandlerUtils.h"
4
4
  #include "HandlerAssetCreate.h"
5
+ #include "HandlerJsonProperty.h"
5
6
  #include "VolumeHelpers_Internal.h"
6
7
  #include "AssetRegistry/AssetRegistryModule.h"
7
8
  #include "AssetToolsModule.h"
@@ -54,148 +55,6 @@
54
55
 
55
56
  namespace
56
57
  {
57
- // #149: recursive JSON→FProperty setter used by set_pcg_node_settings.
58
- // Handles TArray, TSet, nested structs (JSON objects), UObject/Class refs
59
- // from string paths, and soft references. Falls back to ImportText for scalars.
60
- static bool SetJsonOnProperty(FProperty* Prop, void* ValueAddr, const TSharedPtr<FJsonValue>& Value, FString& OutError)
61
- {
62
- if (!Prop || !Value.IsValid() || !ValueAddr) { OutError = TEXT("null property/value/addr"); return false; }
63
-
64
- // TArray
65
- if (FArrayProperty* ArrProp = CastField<FArrayProperty>(Prop))
66
- {
67
- const TArray<TSharedPtr<FJsonValue>>* Items = nullptr;
68
- if (!Value->TryGetArray(Items) || !Items) { OutError = TEXT("expected JSON array"); return false; }
69
- FScriptArrayHelper H(ArrProp, ValueAddr);
70
- H.Resize(Items->Num());
71
- for (int32 i = 0; i < Items->Num(); ++i)
72
- {
73
- FString E;
74
- if (!SetJsonOnProperty(ArrProp->Inner, H.GetRawPtr(i), (*Items)[i], E))
75
- {
76
- OutError = FString::Printf(TEXT("[%d]: %s"), i, *E); return false;
77
- }
78
- }
79
- return true;
80
- }
81
-
82
- // TSet
83
- if (FSetProperty* SetProp = CastField<FSetProperty>(Prop))
84
- {
85
- const TArray<TSharedPtr<FJsonValue>>* Items = nullptr;
86
- if (!Value->TryGetArray(Items) || !Items) { OutError = TEXT("expected JSON array for TSet"); return false; }
87
- FScriptSetHelper H(SetProp, ValueAddr);
88
- H.EmptyElements();
89
- for (const TSharedPtr<FJsonValue>& V : *Items)
90
- {
91
- const int32 Idx = H.AddDefaultValue_Invalid_NeedsRehash();
92
- uint8* ElemAddr = H.GetElementPtr(Idx);
93
- FString E;
94
- if (!SetJsonOnProperty(SetProp->ElementProp, ElemAddr, V, E)) { OutError = E; return false; }
95
- }
96
- H.Rehash();
97
- return true;
98
- }
99
-
100
- // Struct: recurse on JSON object fields; otherwise fall through to ImportText
101
- if (FStructProperty* StructProp = CastField<FStructProperty>(Prop))
102
- {
103
- const TSharedPtr<FJsonObject>* SubObj = nullptr;
104
- if (Value->TryGetObject(SubObj) && SubObj && (*SubObj).IsValid())
105
- {
106
- for (const auto& Pair : (*SubObj)->Values)
107
- {
108
- FProperty* SubProp = StructProp->Struct->FindPropertyByName(FName(*Pair.Key));
109
- if (!SubProp) { OutError = FString::Printf(TEXT("struct field '%s' not found"), *Pair.Key); return false; }
110
- void* SubAddr = SubProp->ContainerPtrToValuePtr<void>(ValueAddr);
111
- FString E;
112
- if (!SetJsonOnProperty(SubProp, SubAddr, Pair.Value, E))
113
- {
114
- OutError = FString::Printf(TEXT("%s.%s: %s"), *StructProp->GetName(), *Pair.Key, *E); return false;
115
- }
116
- }
117
- return true;
118
- }
119
- }
120
-
121
- // Hard UObject ref - accept asset path
122
- if (FObjectProperty* ObjProp = CastField<FObjectProperty>(Prop))
123
- {
124
- FString Path;
125
- if (Value->TryGetString(Path) && !Path.IsEmpty())
126
- {
127
- UObject* Loaded = StaticLoadObject(ObjProp->PropertyClass, nullptr, *Path);
128
- if (!Loaded) { OutError = FString::Printf(TEXT("asset not found: %s"), *Path); return false; }
129
- ObjProp->SetObjectPropertyValue(ValueAddr, Loaded);
130
- return true;
131
- }
132
- }
133
-
134
- // Hard UClass ref - accept class path
135
- if (FClassProperty* ClassProp = CastField<FClassProperty>(Prop))
136
- {
137
- FString Path;
138
- if (Value->TryGetString(Path) && !Path.IsEmpty())
139
- {
140
- UClass* Loaded = LoadClass<UObject>(nullptr, *Path);
141
- if (!Loaded) { OutError = FString::Printf(TEXT("class not found: %s"), *Path); return false; }
142
- ClassProp->SetObjectPropertyValue(ValueAddr, Loaded);
143
- return true;
144
- }
145
- }
146
-
147
- // Soft object / soft class - accept path string
148
- if (FSoftObjectProperty* SoftObjProp = CastField<FSoftObjectProperty>(Prop))
149
- {
150
- FString Path;
151
- if (Value->TryGetString(Path))
152
- {
153
- FSoftObjectPath PathObj(Path);
154
- FSoftObjectPtr Ptr(PathObj);
155
- SoftObjProp->SetPropertyValue(ValueAddr, Ptr);
156
- return true;
157
- }
158
- }
159
-
160
- // Fallback: coerce JSON to string, run ImportText_Direct
161
- FString Str;
162
- if (Value->TryGetString(Str)) {}
163
- else if (Value->Type == EJson::Number) Str = FString::SanitizeFloat(Value->AsNumber());
164
- else if (Value->Type == EJson::Boolean) Str = Value->AsBool() ? TEXT("true") : TEXT("false");
165
- else Str = Value->AsString();
166
-
167
- const TCHAR* R = Prop->ImportText_Direct(*Str, ValueAddr, nullptr, PPF_None);
168
- if (R == nullptr) { OutError = FString::Printf(TEXT("ImportText failed for '%s'"), *Str); return false; }
169
- return true;
170
- }
171
-
172
- // #149: walk dotted property names into nested structs before assigning.
173
- // Enables "SplineMeshDescriptor.StaticMesh" style keys.
174
- static bool SetDottedPropertyFromJson(UObject* Owner, const FString& DottedName, const TSharedPtr<FJsonValue>& Value, FString& OutError)
175
- {
176
- TArray<FString> Parts;
177
- DottedName.ParseIntoArray(Parts, TEXT("."));
178
- if (Parts.Num() == 0) { OutError = TEXT("empty property name"); return false; }
179
-
180
- void* Container = Owner;
181
- UStruct* ContainerStruct = Owner->GetClass();
182
- FProperty* Prop = nullptr;
183
- for (int32 i = 0; i < Parts.Num(); ++i)
184
- {
185
- Prop = ContainerStruct->FindPropertyByName(FName(*Parts[i]));
186
- if (!Prop) { OutError = FString::Printf(TEXT("property '%s' not found at '%s'"), *Parts[i], *DottedName); return false; }
187
- if (i < Parts.Num() - 1)
188
- {
189
- FStructProperty* SP = CastField<FStructProperty>(Prop);
190
- if (!SP) { OutError = FString::Printf(TEXT("'%s' is not a struct - cannot descend"), *Parts[i]); return false; }
191
- Container = SP->ContainerPtrToValuePtr<void>(Container);
192
- ContainerStruct = SP->Struct;
193
- }
194
- }
195
- void* ValueAddr = Prop->ContainerPtrToValuePtr<void>(Container);
196
- return SetJsonOnProperty(Prop, ValueAddr, Value, OutError);
197
- }
198
-
199
58
  // #213: shared class lookup. Mirrors AddPCGNode's tolerant resolver - accepts
200
59
  // short name, "/Script/PCG.X" path, or "U"-prefixed short name.
201
60
  static UClass* FindPCGSettingsClass(const FString& ClassName)
@@ -212,7 +71,7 @@ namespace
212
71
  }
213
72
 
214
73
  // #213: locate a node by name within a graph, including Input/Output specials.
215
- static UPCGNode* FindNodeByName(UPCGGraph* Graph, const FString& Name)
74
+ static UPCGNode* FindPCGNodeByName(UPCGGraph* Graph, const FString& Name)
216
75
  {
217
76
  if (!Graph || Name.IsEmpty()) return nullptr;
218
77
  for (UPCGNode* Node : Graph->GetNodes())
@@ -226,7 +85,7 @@ namespace
226
85
 
227
86
  // #213: structured property serializer used by export_pcg_graph. Emits every
228
87
  // editable property recursively as JSON so the result round-trips through
229
- // SetDottedPropertyFromJson on import. Mirrors the lambda in
88
+ // MCPJsonProperty::SetDottedPropertyFromJson on import. Mirrors the lambda in
230
89
  // ReadPCGNodeSettings (#214/#215) but kept as a standalone function so both
231
90
  // callers can share it without rebuilding the closure each call.
232
91
  static TSharedPtr<FJsonValue> SerializePropForExport(FProperty* Prop, const void* Addr)
@@ -1014,7 +873,7 @@ TSharedPtr<FJsonValue> FPCGHandlers::SetPCGNodeSettings(const TSharedPtr<FJsonOb
1014
873
  for (const auto& Prop : PropertiesToSet)
1015
874
  {
1016
875
  FString SubErr;
1017
- if (SetDottedPropertyFromJson(Settings, Prop.Key, Prop.Value, SubErr))
876
+ if (MCPJsonProperty::SetDottedPropertyFromJson(Settings, Prop.Key, Prop.Value, SubErr))
1018
877
  {
1019
878
  SetResults->SetField(Prop.Key, Prop.Value);
1020
879
  }
@@ -1051,15 +910,14 @@ TSharedPtr<FJsonValue> FPCGHandlers::SetPCGNodeSettings(const TSharedPtr<FJsonOb
1051
910
  TSharedPtr<FJsonValue> FPCGHandlers::ExecutePCGGraph(const TSharedPtr<FJsonObject>& Params)
1052
911
  {
1053
912
  FString ActorLabel;
1054
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
913
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
1055
914
 
1056
915
  REQUIRE_EDITOR_WORLD(World);
1057
916
 
1058
- AActor* FoundActor = FindActorByLabel(World, ActorLabel);
1059
- if (!FoundActor)
1060
- {
1061
- return MCPError(FString::Printf(TEXT("Actor not found with label: %s"), *ActorLabel));
1062
- }
917
+ TSharedPtr<FJsonValue> ActorErr;
918
+ AActor* FoundActor = MCPResolveActor(World, Params, ActorErr);
919
+ if (!FoundActor) return ActorErr;
920
+ ActorLabel = FoundActor->GetActorLabel();
1063
921
 
1064
922
  // Get PCG component from the actor
1065
923
  UPCGComponent* PCGComp = FoundActor->FindComponentByClass<UPCGComponent>();
@@ -1080,6 +938,7 @@ TSharedPtr<FJsonValue> FPCGHandlers::ExecutePCGGraph(const TSharedPtr<FJsonObjec
1080
938
 
1081
939
  auto Result = MCPSuccess();
1082
940
  Result->SetStringField(TEXT("actorLabel"), ActorLabel);
941
+ Result->SetStringField(TEXT("actorPath"), FoundActor->GetPathName());
1083
942
  Result->SetStringField(TEXT("componentName"), PCGComp->GetName());
1084
943
  if (PCGComp->GetGraph())
1085
944
  {
@@ -1349,15 +1208,14 @@ TSharedPtr<FJsonValue> FPCGHandlers::ReadPCGNodeSettings(const TSharedPtr<FJsonO
1349
1208
  TSharedPtr<FJsonValue> FPCGHandlers::GetPCGComponentDetails(const TSharedPtr<FJsonObject>& Params)
1350
1209
  {
1351
1210
  FString ActorLabel;
1352
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
1211
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
1353
1212
 
1354
1213
  REQUIRE_EDITOR_WORLD(World);
1355
1214
 
1356
- AActor* FoundActor = FindActorByLabel(World, ActorLabel);
1357
- if (!FoundActor)
1358
- {
1359
- return MCPError(FString::Printf(TEXT("Actor not found with label: %s"), *ActorLabel));
1360
- }
1215
+ TSharedPtr<FJsonValue> ActorErr;
1216
+ AActor* FoundActor = MCPResolveActor(World, Params, ActorErr);
1217
+ if (!FoundActor) return ActorErr;
1218
+ ActorLabel = FoundActor->GetActorLabel();
1361
1219
 
1362
1220
  // Get all PCG components on the actor
1363
1221
  TArray<UPCGComponent*> PCGComps;
@@ -1370,6 +1228,7 @@ TSharedPtr<FJsonValue> FPCGHandlers::GetPCGComponentDetails(const TSharedPtr<FJs
1370
1228
 
1371
1229
  auto Result = MCPSuccess();
1372
1230
  Result->SetStringField(TEXT("actorLabel"), ActorLabel);
1231
+ Result->SetStringField(TEXT("actorPath"), FoundActor->GetPathName());
1373
1232
  Result->SetStringField(TEXT("actorClass"), FoundActor->GetClass()->GetName());
1374
1233
 
1375
1234
  TArray<TSharedPtr<FJsonValue>> ComponentsArray;
@@ -1525,7 +1384,10 @@ TSharedPtr<FJsonValue> FPCGHandlers::SetStaticMeshSpawnerMeshes(const TSharedPtr
1525
1384
  namespace
1526
1385
  {
1527
1386
  // Locate a UPCGComponent by actor label. Returns error JsonValue on failure.
1528
- TSharedPtr<FJsonValue> FindPCGComponentByLabel(const FString& ActorLabel, UPCGComponent*& OutComp, AActor*& OutActor)
1387
+ // #983: takes the parameter bag so it can read actorPath, and refuses a
1388
+ // label that names more than one actor rather than regenerating whichever
1389
+ // PCG volume the iterator reached first.
1390
+ TSharedPtr<FJsonValue> FindPCGComponentByLabel(const TSharedPtr<FJsonObject>& Params, UPCGComponent*& OutComp, AActor*& OutActor)
1529
1391
  {
1530
1392
  OutComp = nullptr;
1531
1393
  OutActor = nullptr;
@@ -1537,8 +1399,10 @@ namespace
1537
1399
  }
1538
1400
  if (!World) return MCPError(TEXT("Editor world not available"));
1539
1401
 
1540
- OutActor = FindActorByLabel(World, ActorLabel);
1541
- if (!OutActor) return MCPError(FString::Printf(TEXT("Actor not found with label: %s"), *ActorLabel));
1402
+ TSharedPtr<FJsonValue> ActorErr;
1403
+ OutActor = MCPResolveActor(World, Params, ActorErr);
1404
+ if (!OutActor) return ActorErr;
1405
+ const FString ActorLabel = OutActor->GetActorLabel();
1542
1406
  OutComp = OutActor->FindComponentByClass<UPCGComponent>();
1543
1407
  if (!OutComp) return MCPError(FString::Printf(TEXT("No PCGComponent on actor: %s"), *ActorLabel));
1544
1408
  return nullptr;
@@ -1553,10 +1417,11 @@ namespace
1553
1417
  TSharedPtr<FJsonValue> FPCGHandlers::ForceRegeneratePCG(const TSharedPtr<FJsonObject>& Params)
1554
1418
  {
1555
1419
  FString ActorLabel;
1556
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
1420
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
1557
1421
 
1558
1422
  UPCGComponent* PCGComp = nullptr; AActor* Actor = nullptr;
1559
- if (auto Err = FindPCGComponentByLabel(ActorLabel, PCGComp, Actor)) return Err;
1423
+ if (auto Err = FindPCGComponentByLabel(Params, PCGComp, Actor)) return Err;
1424
+ ActorLabel = Actor->GetActorLabel();
1560
1425
 
1561
1426
  UPCGGraph* OriginalGraph = PCGComp->GetGraph();
1562
1427
  if (!OriginalGraph)
@@ -1573,6 +1438,7 @@ TSharedPtr<FJsonValue> FPCGHandlers::ForceRegeneratePCG(const TSharedPtr<FJsonOb
1573
1438
 
1574
1439
  auto Result = MCPSuccess();
1575
1440
  Result->SetStringField(TEXT("actorLabel"), ActorLabel);
1441
+ Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
1576
1442
  Result->SetStringField(TEXT("componentName"), PCGComp->GetName());
1577
1443
  Result->SetStringField(TEXT("graphName"), OriginalGraph->GetName());
1578
1444
  Result->SetStringField(TEXT("graphPath"), OriginalGraph->GetPathName());
@@ -1583,16 +1449,18 @@ TSharedPtr<FJsonValue> FPCGHandlers::ForceRegeneratePCG(const TSharedPtr<FJsonOb
1583
1449
  TSharedPtr<FJsonValue> FPCGHandlers::CleanupPCG(const TSharedPtr<FJsonObject>& Params)
1584
1450
  {
1585
1451
  FString ActorLabel;
1586
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
1452
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
1587
1453
 
1588
1454
  UPCGComponent* PCGComp = nullptr; AActor* Actor = nullptr;
1589
- if (auto Err = FindPCGComponentByLabel(ActorLabel, PCGComp, Actor)) return Err;
1455
+ if (auto Err = FindPCGComponentByLabel(Params, PCGComp, Actor)) return Err;
1456
+ ActorLabel = Actor->GetActorLabel();
1590
1457
 
1591
1458
  const bool bRemoveComponents = OptionalBool(Params, TEXT("removeComponents"), true);
1592
1459
  PCGComp->Cleanup(bRemoveComponents);
1593
1460
 
1594
1461
  auto Result = MCPSuccess();
1595
1462
  Result->SetStringField(TEXT("actorLabel"), ActorLabel);
1463
+ Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
1596
1464
  Result->SetStringField(TEXT("componentName"), PCGComp->GetName());
1597
1465
  Result->SetBoolField(TEXT("removeComponents"), bRemoveComponents);
1598
1466
  Result->SetBoolField(TEXT("cleaned"), true);
@@ -1602,10 +1470,11 @@ TSharedPtr<FJsonValue> FPCGHandlers::CleanupPCG(const TSharedPtr<FJsonObject>& P
1602
1470
  TSharedPtr<FJsonValue> FPCGHandlers::ToggleGraphPCG(const TSharedPtr<FJsonObject>& Params)
1603
1471
  {
1604
1472
  FString ActorLabel;
1605
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
1473
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
1606
1474
 
1607
1475
  UPCGComponent* PCGComp = nullptr; AActor* Actor = nullptr;
1608
- if (auto Err = FindPCGComponentByLabel(ActorLabel, PCGComp, Actor)) return Err;
1476
+ if (auto Err = FindPCGComponentByLabel(Params, PCGComp, Actor)) return Err;
1477
+ ActorLabel = Actor->GetActorLabel();
1609
1478
 
1610
1479
  // If the caller supplies graphPath, load and use that; otherwise re-apply the current graph.
1611
1480
  FString GraphPath;
@@ -1626,6 +1495,7 @@ TSharedPtr<FJsonValue> FPCGHandlers::ToggleGraphPCG(const TSharedPtr<FJsonObject
1626
1495
 
1627
1496
  auto Result = MCPSuccess();
1628
1497
  Result->SetStringField(TEXT("actorLabel"), ActorLabel);
1498
+ Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
1629
1499
  Result->SetStringField(TEXT("componentName"), PCGComp->GetName());
1630
1500
  Result->SetStringField(TEXT("graphName"), TargetGraph->GetName());
1631
1501
  Result->SetStringField(TEXT("graphPath"), TargetGraph->GetPathName());
@@ -1758,7 +1628,7 @@ TSharedPtr<FJsonValue> FPCGHandlers::ImportGraph(const TSharedPtr<FJsonObject>&
1758
1628
  {
1759
1629
  const FString SettingName(*Pair.Key);
1760
1630
  FString SubErr;
1761
- if (SetDottedPropertyFromJson(DefaultSettings, SettingName, Pair.Value, SubErr))
1631
+ if (MCPJsonProperty::SetDottedPropertyFromJson(DefaultSettings, SettingName, Pair.Value, SubErr))
1762
1632
  {
1763
1633
  ++SettingsApplied;
1764
1634
  }
@@ -1788,7 +1658,7 @@ TSharedPtr<FJsonValue> FPCGHandlers::ImportGraph(const TSharedPtr<FJsonObject>&
1788
1658
  auto Resolve = [&](const FString& Name) -> UPCGNode*
1789
1659
  {
1790
1660
  if (UPCGNode** Found = ByLocalName.Find(Name); Found && *Found) return *Found;
1791
- return FindNodeByName(Graph, Name);
1661
+ return FindPCGNodeByName(Graph, Name);
1792
1662
  };
1793
1663
 
1794
1664
  auto FirstOutputPin = [](UPCGNode* N) -> FName
@@ -67,18 +67,17 @@ namespace
67
67
  TSharedPtr<FJsonValue> FPhysicsHandlers::SetCollisionProfile(const TSharedPtr<FJsonObject>& Params)
68
68
  {
69
69
  FString ActorLabel;
70
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
70
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
71
71
 
72
72
  FString ProfileName;
73
73
  if (auto Err = RequireString(Params, TEXT("profileName"), ProfileName)) return Err;
74
74
 
75
75
  REQUIRE_EDITOR_WORLD(World);
76
76
 
77
- AActor* Actor = FindActorByLabel(World, ActorLabel);
78
- if (!Actor)
79
- {
80
- return MCPError(FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
81
- }
77
+ TSharedPtr<FJsonValue> ActorErr;
78
+ AActor* Actor = MCPResolveActor(World, Params, ActorErr);
79
+ if (!Actor) return ActorErr;
80
+ ActorLabel = Actor->GetActorLabel();
82
81
 
83
82
  // Capture previous profile from first component (for rollback)
84
83
  TArray<UPrimitiveComponent*> PrimitiveComponents;
@@ -95,6 +94,7 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::SetCollisionProfile(const TSharedPtr<FJ
95
94
 
96
95
  auto Result = MCPSuccess();
97
96
  Result->SetStringField(TEXT("actorLabel"), ActorLabel);
97
+ Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
98
98
  Result->SetStringField(TEXT("profileName"), ProfileName);
99
99
 
100
100
  if (bAllAlreadyMatch)
@@ -135,7 +135,7 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::SetCollisionProfile(const TSharedPtr<FJ
135
135
  TSharedPtr<FJsonValue> FPhysicsHandlers::SetPhysicsEnabled(const TSharedPtr<FJsonObject>& Params)
136
136
  {
137
137
  FString ActorLabel;
138
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
138
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
139
139
 
140
140
  // #721: the published TS schema names this parameter "simulate" while the
141
141
  // handler historically read only "enabled", so a schema-conformant call
@@ -150,11 +150,10 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::SetPhysicsEnabled(const TSharedPtr<FJso
150
150
 
151
151
  REQUIRE_EDITOR_WORLD(World);
152
152
 
153
- AActor* Actor = FindActorByLabel(World, ActorLabel);
154
- if (!Actor)
155
- {
156
- return MCPError(FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
157
- }
153
+ TSharedPtr<FJsonValue> ActorErr;
154
+ AActor* Actor = MCPResolveActor(World, Params, ActorErr);
155
+ if (!Actor) return ActorErr;
156
+ ActorLabel = Actor->GetActorLabel();
158
157
 
159
158
  // Capture previous state for rollback / idempotency check
160
159
  TArray<UPrimitiveComponent*> PrimitiveComponents;
@@ -172,6 +171,7 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::SetPhysicsEnabled(const TSharedPtr<FJso
172
171
 
173
172
  auto Result = MCPSuccess();
174
173
  Result->SetStringField(TEXT("actorLabel"), ActorLabel);
174
+ Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
175
175
  Result->SetBoolField(TEXT("enabled"), bEnabled);
176
176
 
177
177
  if (bAllAlready)
@@ -212,7 +212,7 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::SetPhysicsEnabled(const TSharedPtr<FJso
212
212
  TSharedPtr<FJsonValue> FPhysicsHandlers::SetCollisionEnabled(const TSharedPtr<FJsonObject>& Params)
213
213
  {
214
214
  FString ActorLabel;
215
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
215
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
216
216
 
217
217
  FString CollisionType;
218
218
  if (auto Err = RequireString(Params, TEXT("collisionType"), CollisionType)) return Err;
@@ -242,11 +242,10 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::SetCollisionEnabled(const TSharedPtr<FJ
242
242
 
243
243
  REQUIRE_EDITOR_WORLD(World);
244
244
 
245
- AActor* Actor = FindActorByLabel(World, ActorLabel);
246
- if (!Actor)
247
- {
248
- return MCPError(FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
249
- }
245
+ TSharedPtr<FJsonValue> ActorErr;
246
+ AActor* Actor = MCPResolveActor(World, Params, ActorErr);
247
+ if (!Actor) return ActorErr;
248
+ ActorLabel = Actor->GetActorLabel();
250
249
 
251
250
  // Capture previous state
252
251
  TArray<UPrimitiveComponent*> PrimitiveComponents;
@@ -264,6 +263,7 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::SetCollisionEnabled(const TSharedPtr<FJ
264
263
 
265
264
  auto Result = MCPSuccess();
266
265
  Result->SetStringField(TEXT("actorLabel"), ActorLabel);
266
+ Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
267
267
  Result->SetStringField(TEXT("collisionType"), CollisionType);
268
268
 
269
269
  if (bAllAlready)
@@ -350,12 +350,15 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::SetCollision(const TSharedPtr<FJsonObje
350
350
  Targets.Add(Prim);
351
351
  TargetDesc = FString::Printf(TEXT("%s:%s"), *AssetPath, *ComponentName);
352
352
  }
353
- else if (Params->TryGetStringField(TEXT("actorLabel"), ActorLabel) && !ActorLabel.IsEmpty())
353
+ else if ((Params->TryGetStringField(TEXT("actorLabel"), ActorLabel) && !ActorLabel.IsEmpty())
354
+ || Params->HasField(TEXT("actorPath")))
354
355
  {
355
356
  UWorld* World = GetEditorWorld();
356
357
  if (!World) return MCPError(TEXT("No editor world available"));
357
- Actor = FindActorByLabel(World, ActorLabel);
358
- if (!Actor) return MCPError(FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
358
+ TSharedPtr<FJsonValue> ActorErr;
359
+ Actor = MCPResolveActor(World, Params, ActorErr);
360
+ if (!Actor) return ActorErr;
361
+ ActorLabel = Actor->GetActorLabel();
359
362
 
360
363
  TArray<UPrimitiveComponent*> AllPrims;
361
364
  Actor->GetComponents<UPrimitiveComponent>(AllPrims);
@@ -479,15 +482,14 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::SetCollision(const TSharedPtr<FJsonObje
479
482
  TSharedPtr<FJsonValue> FPhysicsHandlers::SetBodyProperties(const TSharedPtr<FJsonObject>& Params)
480
483
  {
481
484
  FString ActorLabel;
482
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
485
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
483
486
 
484
487
  REQUIRE_EDITOR_WORLD(World);
485
488
 
486
- AActor* Actor = FindActorByLabel(World, ActorLabel);
487
- if (!Actor)
488
- {
489
- return MCPError(FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
490
- }
489
+ TSharedPtr<FJsonValue> ActorErr;
490
+ AActor* Actor = MCPResolveActor(World, Params, ActorErr);
491
+ if (!Actor) return ActorErr;
492
+ ActorLabel = Actor->GetActorLabel();
491
493
 
492
494
  // Get all PrimitiveComponents
493
495
  int32 ComponentsModified = 0;
@@ -580,6 +582,7 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::SetBodyProperties(const TSharedPtr<FJso
580
582
 
581
583
  auto Result = MCPSuccess();
582
584
  Result->SetStringField(TEXT("actorLabel"), ActorLabel);
585
+ Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
583
586
  Result->SetArrayField(TEXT("propertiesSet"), PropsArray);
584
587
  Result->SetNumberField(TEXT("componentsModified"), ComponentsModified);
585
588
  Result->SetBoolField(TEXT("success"), ComponentsModified > 0);
@@ -610,14 +613,19 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::SetBodyProperties(const TSharedPtr<FJso
610
613
  TSharedPtr<FJsonValue> FPhysicsHandlers::AddImpulse(const TSharedPtr<FJsonObject>& Params)
611
614
  {
612
615
  FString ActorLabel;
613
- if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
616
+ if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
614
617
 
615
618
  const FString WorldScope = OptionalString(Params, TEXT("world"), TEXT("auto"));
616
619
  UWorld* World = ResolveWorldFromParams(Params, *WorldScope);
617
620
  if (!World) return MCPError(TEXT("World not available"));
618
621
 
619
- AActor* Actor = FindActorByLabelNameOrPath(World, ActorLabel);
620
- if (!Actor) return MCPError(FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
622
+ FMCPActorSelector ActorSel;
623
+ ActorSel.Match = EMCPActorMatch::LabelNameOrPath;
624
+ ActorSel.WorldLabel = World->IsGameWorld() ? TEXT("PIE") : TEXT("editor");
625
+ TSharedPtr<FJsonValue> ActorErr;
626
+ AActor* Actor = MCPResolveActor(World, Params, ActorErr, ActorSel);
627
+ if (!Actor) return ActorErr;
628
+ ActorLabel = Actor->GetActorLabel();
621
629
 
622
630
  // Resolve the primitive component: named, or the root.
623
631
  const FString ComponentName = OptionalString(Params, TEXT("componentName"));
@@ -669,6 +677,7 @@ TSharedPtr<FJsonValue> FPhysicsHandlers::AddImpulse(const TSharedPtr<FJsonObject
669
677
 
670
678
  auto Result = MCPSuccess();
671
679
  Result->SetStringField(TEXT("actorLabel"), Actor->GetActorLabel());
680
+ Result->SetStringField(TEXT("actorPath"), Actor->GetPathName());
672
681
  Result->SetStringField(TEXT("component"), Prim->GetName());
673
682
  Result->SetStringField(TEXT("mode"), Mode);
674
683
  Result->SetObjectField(TEXT("vector"), MCPVec3ToJsonObject(Vec));