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,205 @@
1
+ // Coverage for the transient verification actors (#956) and the component
2
+ // material overrides (#946).
3
+ //
4
+ // spawn_transient_actor is safe to run for real: its whole contract is that it
5
+ // cannot persist anything, and asserting that contract is most of the point.
6
+ // It is still cleaned up here, because a test that leaves an actor behind
7
+ // while testing an action about not leaving actors behind would be absurd.
8
+
9
+ #if WITH_DEV_AUTOMATION_TESTS
10
+
11
+ #include "HandlerRegistry.h"
12
+ #include "Handlers/LevelHandlers.h"
13
+ #include "Misc/AutomationTest.h"
14
+
15
+ namespace
16
+ {
17
+ TSharedPtr<FJsonObject> MCPTransientTestRun(
18
+ FMCPHandlerRegistry& Registry,
19
+ const TCHAR* Method,
20
+ const TSharedPtr<FJsonObject>& Request)
21
+ {
22
+ const TSharedPtr<FJsonValue> Response = Registry.ExecuteHandler(Method, Request);
23
+ if (!Response.IsValid() || Response->Type != EJson::Object)
24
+ {
25
+ return nullptr;
26
+ }
27
+ return Response->AsObject();
28
+ }
29
+ }
30
+
31
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
32
+ FLevelTransientActorContractTest,
33
+ "UE.MCP.Level.TransientActor.CannotBeSavedIntoTheMap",
34
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
35
+
36
+ bool FLevelTransientActorContractTest::RunTest(const FString& Parameters)
37
+ {
38
+ FMCPHandlerRegistry Registry;
39
+ FLevelHandlers::RegisterHandlers(Registry);
40
+
41
+ for (const TCHAR* Method : {
42
+ TEXT("spawn_transient_actor"),
43
+ TEXT("destroy_transient_actor"),
44
+ TEXT("list_transient_actors"),
45
+ TEXT("set_component_materials") })
46
+ {
47
+ TestTrue(FString::Printf(TEXT("%s is registered"), Method), Registry.HasHandler(Method));
48
+ }
49
+
50
+ // An unresolvable class is named rather than producing a null actor.
51
+ {
52
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
53
+ Request->SetStringField(TEXT("actorClass"), TEXT("NotARealActorClassAtAll"));
54
+ const TSharedPtr<FJsonObject> Response =
55
+ MCPTransientTestRun(Registry, TEXT("spawn_transient_actor"), Request);
56
+ if (Response.IsValid())
57
+ {
58
+ TestFalse(TEXT("an unresolvable class fails"), Response->GetBoolField(TEXT("success")));
59
+ }
60
+ }
61
+
62
+ // An unknown initialize level is rejected by name, because silently
63
+ // falling back to 'none' would leave a caller reading an uninitialised
64
+ // component and believing it had asked for more.
65
+ {
66
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
67
+ Request->SetStringField(TEXT("actorClass"), TEXT("StaticMeshActor"));
68
+ Request->SetStringField(TEXT("initialize"), TEXT("everything"));
69
+ const TSharedPtr<FJsonObject> Response =
70
+ MCPTransientTestRun(Registry, TEXT("spawn_transient_actor"), Request);
71
+ if (Response.IsValid())
72
+ {
73
+ TestFalse(TEXT("an unknown initialize level fails"), Response->GetBoolField(TEXT("success")));
74
+ TestTrue(TEXT("and lists the ones that exist"),
75
+ Response->GetStringField(TEXT("error")).Contains(TEXT("beginPlay")));
76
+ }
77
+ }
78
+
79
+ // destroy with no target does nothing rather than guessing.
80
+ {
81
+ const TSharedPtr<FJsonObject> Response =
82
+ MCPTransientTestRun(Registry, TEXT("destroy_transient_actor"), MakeShared<FJsonObject>());
83
+ if (Response.IsValid())
84
+ {
85
+ TestFalse(TEXT("destroy with no target fails"), Response->GetBoolField(TEXT("success")));
86
+ }
87
+ }
88
+
89
+ // The real round trip, in whatever map is open.
90
+ TSharedPtr<FJsonObject> SpawnRequest = MakeShared<FJsonObject>();
91
+ SpawnRequest->SetStringField(TEXT("actorClass"), TEXT("StaticMeshActor"));
92
+ SpawnRequest->SetStringField(TEXT("label"), TEXT("UEMCP_TransientContractTest"));
93
+ const TSharedPtr<FJsonObject> SpawnResponse =
94
+ MCPTransientTestRun(Registry, TEXT("spawn_transient_actor"), SpawnRequest);
95
+ if (!SpawnResponse.IsValid() || !SpawnResponse->GetBoolField(TEXT("success")))
96
+ {
97
+ // No editor world in this context, and this test may not open a map.
98
+ return true;
99
+ }
100
+
101
+ const TSharedPtr<FJsonObject> Actor = SpawnResponse->GetObjectField(TEXT("actor"));
102
+ const FString ActorPath = Actor->GetStringField(TEXT("actorPath"));
103
+ TestTrue(TEXT("the spawned actor really is RF_Transient"), Actor->GetBoolField(TEXT("transient")));
104
+
105
+ // The #966-shaped guarantee: a verification spawn that dirties the map has
106
+ // failed at its one job, label included, since SetActorLabel dirties by
107
+ // default and this passes bMarkDirty=false.
108
+ TestFalse(TEXT("spawning a verification actor dirties nothing"),
109
+ SpawnResponse->GetBoolField(TEXT("dirtiedPackages")));
110
+
111
+ // It shows up in the listing, so nothing can be left behind unnoticed.
112
+ {
113
+ const TSharedPtr<FJsonObject> ListResponse =
114
+ MCPTransientTestRun(Registry, TEXT("list_transient_actors"), MakeShared<FJsonObject>());
115
+ if (ListResponse.IsValid() && ListResponse->GetBoolField(TEXT("success")))
116
+ {
117
+ TestTrue(TEXT("the listing sees it"),
118
+ static_cast<int32>(ListResponse->GetNumberField(TEXT("total"))) >= 1);
119
+ }
120
+ }
121
+
122
+ // And cleanup destroys exactly it.
123
+ TSharedPtr<FJsonObject> DestroyRequest = MakeShared<FJsonObject>();
124
+ DestroyRequest->SetStringField(TEXT("actorPath"), ActorPath);
125
+ const TSharedPtr<FJsonObject> DestroyResponse =
126
+ MCPTransientTestRun(Registry, TEXT("destroy_transient_actor"), DestroyRequest);
127
+ TestTrue(TEXT("destroy succeeds"), DestroyResponse.IsValid() && DestroyResponse->GetBoolField(TEXT("success")));
128
+ if (DestroyResponse.IsValid())
129
+ {
130
+ TestEqual(TEXT("destroy removed exactly one actor"),
131
+ static_cast<int32>(DestroyResponse->GetNumberField(TEXT("destroyed"))), 1);
132
+ }
133
+
134
+ return true;
135
+ }
136
+
137
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
138
+ FLevelSetComponentMaterialsContractTest,
139
+ "UE.MCP.Level.SetComponentMaterials.Contract",
140
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
141
+
142
+ bool FLevelSetComponentMaterialsContractTest::RunTest(const FString& Parameters)
143
+ {
144
+ FMCPHandlerRegistry Registry;
145
+ FLevelHandlers::RegisterHandlers(Registry);
146
+
147
+ // No selector would mean every actor in the level.
148
+ {
149
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
150
+ Request->SetStringField(TEXT("material"), TEXT("/Engine/EngineMaterials/DefaultMaterial.DefaultMaterial"));
151
+ const TSharedPtr<FJsonObject> Response =
152
+ MCPTransientTestRun(Registry, TEXT("set_component_materials"), Request);
153
+ if (Response.IsValid())
154
+ {
155
+ TestFalse(TEXT("no selector fails"), Response->GetBoolField(TEXT("success")));
156
+ }
157
+ }
158
+
159
+ // A selector but no instruction about what to write.
160
+ {
161
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
162
+ Request->SetStringField(TEXT("labelPrefix"), TEXT("Anything"));
163
+ const TSharedPtr<FJsonObject> Response =
164
+ MCPTransientTestRun(Registry, TEXT("set_component_materials"), Request);
165
+ if (Response.IsValid())
166
+ {
167
+ TestFalse(TEXT("no materials fails"), Response->GetBoolField(TEXT("success")));
168
+ TestTrue(TEXT("and lists the three modes"),
169
+ Response->GetStringField(TEXT("error")).Contains(TEXT("clearOverrides")));
170
+ }
171
+ }
172
+
173
+ // Two modes at once would fight over the same slots.
174
+ {
175
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
176
+ Request->SetStringField(TEXT("labelPrefix"), TEXT("Anything"));
177
+ Request->SetStringField(TEXT("material"), TEXT("/Engine/EngineMaterials/DefaultMaterial.DefaultMaterial"));
178
+ Request->SetBoolField(TEXT("clearOverrides"), true);
179
+ const TSharedPtr<FJsonObject> Response =
180
+ MCPTransientTestRun(Registry, TEXT("set_component_materials"), Request);
181
+ if (Response.IsValid())
182
+ {
183
+ TestFalse(TEXT("two modes fail"), Response->GetBoolField(TEXT("success")));
184
+ }
185
+ }
186
+
187
+ // A material path that does not resolve fails the whole call rather than
188
+ // half-applying across the matched actors.
189
+ {
190
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
191
+ Request->SetStringField(TEXT("labelPrefix"), TEXT("Anything"));
192
+ Request->SetStringField(TEXT("material"), TEXT("/Game/UEMCPNoSuchMaterialForTests"));
193
+ const TSharedPtr<FJsonObject> Response =
194
+ MCPTransientTestRun(Registry, TEXT("set_component_materials"), Request);
195
+ if (Response.IsValid())
196
+ {
197
+ TestFalse(TEXT("an unresolvable material fails before any write"),
198
+ Response->GetBoolField(TEXT("success")));
199
+ }
200
+ }
201
+
202
+ return true;
203
+ }
204
+
205
+ #endif // WITH_DEV_AUTOMATION_TESTS
@@ -0,0 +1,168 @@
1
+ // Coverage for the World Partition streaming surface (#985).
2
+ //
3
+ // These actions write the streaming configuration of whatever map is open, so
4
+ // the assertions stay on the paths specified to change nothing: the refusals
5
+ // that keep a bad request from half-applying, and the shape of the read. A test
6
+ // that retuned CellSize to prove CellSize can be retuned would leave somebody's
7
+ // map streaming differently.
8
+ //
9
+ // The read is asserted on whichever map the run happens to have open. On a
10
+ // non-partitioned map it must refuse by name rather than answering with an
11
+ // empty success, because "this map has no grids" and "this map is not World
12
+ // Partition" are different facts and only one of them is actionable.
13
+
14
+ #if WITH_DEV_AUTOMATION_TESTS
15
+
16
+ #include "Editor.h"
17
+ #include "Engine/World.h"
18
+ #include "HandlerRegistry.h"
19
+ #include "Handlers/LevelHandlers.h"
20
+ #include "Misc/AutomationTest.h"
21
+ #include "WorldPartition/WorldPartition.h"
22
+
23
+ namespace
24
+ {
25
+ TSharedPtr<FJsonObject> MCPWorldPartitionTestRun(
26
+ FMCPHandlerRegistry& Registry,
27
+ const TCHAR* Method,
28
+ const TSharedPtr<FJsonObject>& Request)
29
+ {
30
+ const TSharedPtr<FJsonValue> Response = Registry.ExecuteHandler(Method, Request);
31
+ if (!Response.IsValid() || Response->Type != EJson::Object)
32
+ {
33
+ return nullptr;
34
+ }
35
+ return Response->AsObject();
36
+ }
37
+ }
38
+
39
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
40
+ FLevelWorldPartitionSettingsSurfaceTest,
41
+ "UE.MCP.Level.WorldPartition.SettingsSurface",
42
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
43
+
44
+ bool FLevelWorldPartitionSettingsSurfaceTest::RunTest(const FString& Parameters)
45
+ {
46
+ FMCPHandlerRegistry Registry;
47
+ FLevelHandlers::RegisterHandlers(Registry);
48
+
49
+ for (const TCHAR* Method : {
50
+ TEXT("get_world_partition_settings"),
51
+ TEXT("set_world_partition_settings"),
52
+ TEXT("add_runtime_cell_transformer"),
53
+ TEXT("set_actor_hlod_layer") })
54
+ {
55
+ TestTrue(FString::Printf(TEXT("%s is registered"), Method), Registry.HasHandler(Method));
56
+ }
57
+
58
+ UWorld* World = GEditor ? GEditor->GetEditorWorldContext().World() : nullptr;
59
+ if (!World) return true;
60
+ const bool bPartitioned = World->GetWorldPartition() != nullptr;
61
+
62
+ // The read.
63
+ {
64
+ const TSharedPtr<FJsonObject> Response =
65
+ MCPWorldPartitionTestRun(Registry, TEXT("get_world_partition_settings"), MakeShared<FJsonObject>());
66
+ if (Response.IsValid())
67
+ {
68
+ if (bPartitioned)
69
+ {
70
+ TestTrue(TEXT("a World Partition map answers"), Response->GetBoolField(TEXT("success")));
71
+ const TArray<TSharedPtr<FJsonValue>>* Grids = nullptr;
72
+ TestTrue(TEXT("and reports its streaming grids"),
73
+ Response->TryGetArrayField(TEXT("grids"), Grids));
74
+ const TArray<TSharedPtr<FJsonValue>>* Transformers = nullptr;
75
+ TestTrue(TEXT("and its runtime cell transformer stack"),
76
+ Response->TryGetArrayField(TEXT("cellTransformers"), Transformers));
77
+ FString WorldPartitionPath;
78
+ TestTrue(TEXT("and names the world partition object"),
79
+ Response->TryGetStringField(TEXT("worldPartition"), WorldPartitionPath));
80
+ }
81
+ else
82
+ {
83
+ // The distinction that matters: not partitioned is a refusal
84
+ // with a reason, not an empty success a caller reads as "no
85
+ // grids configured".
86
+ TestFalse(TEXT("a non-partitioned map is refused"), Response->GetBoolField(TEXT("success")));
87
+ TestTrue(TEXT("and the refusal says why"),
88
+ Response->GetStringField(TEXT("error")).Contains(TEXT("World Partition")));
89
+ }
90
+ }
91
+ }
92
+
93
+ // A write with nothing in it is a request that means nothing.
94
+ {
95
+ const TSharedPtr<FJsonObject> Response =
96
+ MCPWorldPartitionTestRun(Registry, TEXT("set_world_partition_settings"), MakeShared<FJsonObject>());
97
+ if (Response.IsValid())
98
+ {
99
+ TestFalse(TEXT("an empty write is refused"), Response->GetBoolField(TEXT("success")));
100
+ }
101
+ }
102
+
103
+ // A path that does not resolve fails the whole call. Streaming settings are
104
+ // changed in batches and a half-applied batch is a configuration nobody
105
+ // asked for.
106
+ if (bPartitioned)
107
+ {
108
+ TSharedPtr<FJsonObject> Settings = MakeShared<FJsonObject>();
109
+ Settings->SetNumberField(TEXT("NotARealWorldPartitionProperty"), 1.0);
110
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
111
+ Request->SetObjectField(TEXT("settings"), Settings);
112
+ const TSharedPtr<FJsonObject> Response =
113
+ MCPWorldPartitionTestRun(Registry, TEXT("set_world_partition_settings"), Request);
114
+ if (Response.IsValid())
115
+ {
116
+ TestFalse(TEXT("an unresolvable path fails the call"), Response->GetBoolField(TEXT("success")));
117
+ TestTrue(TEXT("and says nothing was written"),
118
+ Response->GetStringField(TEXT("error")).Contains(TEXT("Nothing was written")));
119
+ }
120
+ }
121
+
122
+ // A class that is not a cell transformer is refused by name rather than
123
+ // added and left to fail at streaming-generation time.
124
+ {
125
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
126
+ Request->SetStringField(TEXT("transformerClass"), TEXT("StaticMeshActor"));
127
+ const TSharedPtr<FJsonObject> Response =
128
+ MCPWorldPartitionTestRun(Registry, TEXT("add_runtime_cell_transformer"), Request);
129
+ if (Response.IsValid())
130
+ {
131
+ TestFalse(TEXT("a non-transformer class is refused"), Response->GetBoolField(TEXT("success")));
132
+ }
133
+ }
134
+
135
+ // The HLOD batch refuses an unbounded run, like every other selector-driven
136
+ // write in this category.
137
+ {
138
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
139
+ Request->SetStringField(TEXT("hlodLayer"), FString());
140
+ const TSharedPtr<FJsonObject> Response =
141
+ MCPWorldPartitionTestRun(Registry, TEXT("set_actor_hlod_layer"), Request);
142
+ if (Response.IsValid())
143
+ {
144
+ TestFalse(TEXT("an unbounded HLOD assignment is refused"), Response->GetBoolField(TEXT("success")));
145
+ TestTrue(TEXT("and names the selectors it wants"),
146
+ Response->GetStringField(TEXT("error")).Contains(TEXT("actorLabels")));
147
+ }
148
+ }
149
+
150
+ // And a missing hlodLayer is refused rather than treated as "clear it",
151
+ // because clearing 295 actors' overrides by omission would be a disaster.
152
+ {
153
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
154
+ Request->SetStringField(TEXT("labelPrefix"), TEXT("UEMCP_NoSuchActorPrefix"));
155
+ const TSharedPtr<FJsonObject> Response =
156
+ MCPWorldPartitionTestRun(Registry, TEXT("set_actor_hlod_layer"), Request);
157
+ if (Response.IsValid())
158
+ {
159
+ TestFalse(TEXT("omitting hlodLayer is refused"), Response->GetBoolField(TEXT("success")));
160
+ TestTrue(TEXT("and says the parameter is required"),
161
+ Response->GetStringField(TEXT("error")).Contains(TEXT("hlodLayer")));
162
+ }
163
+ }
164
+
165
+ return true;
166
+ }
167
+
168
+ #endif // WITH_DEV_AUTOMATION_TESTS
@@ -0,0 +1,51 @@
1
+ #pragma once
2
+
3
+ #include "CoreMinimal.h"
4
+ #include "StructUtils/InstancedStruct.h"
5
+ #include "MCPInstancedStructPathTestTypes.generated.h"
6
+
7
+ /** Reflected payload used only by the FInstancedStruct property-path tests. */
8
+ USTRUCT()
9
+ struct FUEMCPInstancedStructPathElement
10
+ {
11
+ GENERATED_BODY()
12
+
13
+ UPROPERTY()
14
+ int32 Scalar = 0;
15
+
16
+ UPROPERTY()
17
+ FString Sibling;
18
+ };
19
+
20
+ /** Payload shape with both scalar and indexed nested leaves. */
21
+ USTRUCT()
22
+ struct FUEMCPInstancedStructPathPayload
23
+ {
24
+ GENERATED_BODY()
25
+
26
+ UPROPERTY()
27
+ int32 Scalar = 0;
28
+
29
+ UPROPERTY()
30
+ FString Sibling;
31
+
32
+ UPROPERTY()
33
+ TArray<FUEMCPInstancedStructPathElement> Elements;
34
+ };
35
+
36
+ /** In-memory UObject target resolved by both property handlers through its object path. */
37
+ UCLASS()
38
+ class UUEMCPInstancedStructPathTestObject : public UObject
39
+ {
40
+ GENERATED_BODY()
41
+
42
+ public:
43
+ UPROPERTY()
44
+ FInstancedStruct Payload;
45
+
46
+ UPROPERTY()
47
+ FInstancedStruct EmptyPayload;
48
+
49
+ UPROPERTY()
50
+ TArray<FInstancedStruct> OpStack;
51
+ };