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,147 @@
1
+ // Coverage for foliage(batch_set_settings_where) (#988).
2
+ //
3
+ // run_automation_tests dispatches every EditorContext/EngineFilter test in the
4
+ // process against whatever project the bridge is attached to, and this action
5
+ // writes to FoliageType assets, so the assertions stay on argument rejection
6
+ // and the dry run, both of which are specified to write nothing.
7
+
8
+ #if WITH_DEV_AUTOMATION_TESTS
9
+
10
+ #include "HandlerRegistry.h"
11
+ #include "Handlers/FoliageHandlers.h"
12
+ #include "Misc/AutomationTest.h"
13
+
14
+ namespace
15
+ {
16
+ TSharedPtr<FJsonObject> MCPFoliageBatchTestRun(
17
+ FMCPHandlerRegistry& Registry,
18
+ const TSharedPtr<FJsonObject>& Request)
19
+ {
20
+ const TSharedPtr<FJsonValue> Response =
21
+ Registry.ExecuteHandler(TEXT("batch_set_foliage_settings_where"), Request);
22
+ if (!Response.IsValid() || Response->Type != EJson::Object)
23
+ {
24
+ return nullptr;
25
+ }
26
+ return Response->AsObject();
27
+ }
28
+
29
+ TSharedPtr<FJsonObject> MCPFoliageBatchTestSettings()
30
+ {
31
+ TSharedPtr<FJsonObject> Settings = MakeShared<FJsonObject>();
32
+ Settings->SetBoolField(TEXT("bIncludeInHLOD"), false);
33
+ return Settings;
34
+ }
35
+ }
36
+
37
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
38
+ FFoliageBatchSettingsContractTest,
39
+ "UE.MCP.Foliage.BatchSetSettingsWhere.Contract",
40
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
41
+
42
+ bool FFoliageBatchSettingsContractTest::RunTest(const FString& Parameters)
43
+ {
44
+ FMCPHandlerRegistry Registry;
45
+ FFoliageHandlers::RegisterHandlers(Registry);
46
+
47
+ TestTrue(TEXT("batch_set_foliage_settings_where is registered"),
48
+ Registry.HasHandler(TEXT("batch_set_foliage_settings_where")));
49
+ TestTrue(TEXT("it carries its own timeout, because scanning and saving hundreds of assets is slow"),
50
+ Registry.GetHandlerTimeout(TEXT("batch_set_foliage_settings_where")) > 0.0f);
51
+
52
+ // No settings means there is nothing to write.
53
+ {
54
+ const TSharedPtr<FJsonObject> Response =
55
+ MCPFoliageBatchTestRun(Registry, MakeShared<FJsonObject>());
56
+ if (Response.IsValid())
57
+ {
58
+ TestFalse(TEXT("no settings fails"), Response->GetBoolField(TEXT("success")));
59
+ TestTrue(TEXT("and names the parameter"),
60
+ Response->GetStringField(TEXT("error")).Contains(TEXT("settings")));
61
+ }
62
+ }
63
+
64
+ // No predicate means "every foliage type in the project", which is not
65
+ // what anybody means by a conditional batch. The error points at the
66
+ // single-asset action for the case where one asset is what was wanted.
67
+ {
68
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
69
+ Request->SetObjectField(TEXT("settings"), MCPFoliageBatchTestSettings());
70
+ const TSharedPtr<FJsonObject> Response = MCPFoliageBatchTestRun(Registry, Request);
71
+ if (Response.IsValid())
72
+ {
73
+ TestFalse(TEXT("no predicate fails"), Response->GetBoolField(TEXT("success")));
74
+ TestTrue(TEXT("and offers set_settings for the single-asset case"),
75
+ Response->GetStringField(TEXT("error")).Contains(TEXT("set_settings")));
76
+ }
77
+ }
78
+
79
+ // A predicate but no candidate source.
80
+ {
81
+ TSharedPtr<FJsonObject> Predicate = MakeShared<FJsonObject>();
82
+ Predicate->SetStringField(TEXT("field"), TEXT("CullDistance.Max"));
83
+ Predicate->SetStringField(TEXT("op"), TEXT("gt"));
84
+ Predicate->SetNumberField(TEXT("value"), 0);
85
+
86
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
87
+ Request->SetObjectField(TEXT("settings"), MCPFoliageBatchTestSettings());
88
+ Request->SetArrayField(TEXT("where"), { MakeShared<FJsonValueObject>(Predicate) });
89
+ const TSharedPtr<FJsonObject> Response = MCPFoliageBatchTestRun(Registry, Request);
90
+ if (Response.IsValid())
91
+ {
92
+ TestFalse(TEXT("no candidate source fails"), Response->GetBoolField(TEXT("success")));
93
+ TestTrue(TEXT("and lists all three"),
94
+ Response->GetStringField(TEXT("error")).Contains(TEXT("fromLevel")));
95
+ }
96
+ }
97
+
98
+ return true;
99
+ }
100
+
101
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
102
+ FFoliageBatchSettingsPreviewTest,
103
+ "UE.MCP.Foliage.BatchSetSettingsWhere.PreviewsByDefault",
104
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
105
+
106
+ bool FFoliageBatchSettingsPreviewTest::RunTest(const FString& Parameters)
107
+ {
108
+ FMCPHandlerRegistry Registry;
109
+ FFoliageHandlers::RegisterHandlers(Registry);
110
+
111
+ // A complete, valid request against a directory that exists in every
112
+ // project. dryRun is not passed, so the default decides, and the default
113
+ // has to be the preview.
114
+ TSharedPtr<FJsonObject> Predicate = MakeShared<FJsonObject>();
115
+ Predicate->SetStringField(TEXT("field"), TEXT("CullDistance.Max"));
116
+ Predicate->SetStringField(TEXT("op"), TEXT("gt"));
117
+ Predicate->SetNumberField(TEXT("value"), 0);
118
+
119
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
120
+ Request->SetObjectField(TEXT("settings"), MCPFoliageBatchTestSettings());
121
+ Request->SetArrayField(TEXT("where"), { MakeShared<FJsonValueObject>(Predicate) });
122
+ Request->SetStringField(TEXT("directory"), TEXT("/Game"));
123
+
124
+ const TSharedPtr<FJsonObject> Response = MCPFoliageBatchTestRun(Registry, Request);
125
+ if (!Response.IsValid() || !Response->GetBoolField(TEXT("success")))
126
+ {
127
+ return true;
128
+ }
129
+
130
+ TestTrue(TEXT("dryRun defaults to true"), Response->GetBoolField(TEXT("dryRun")));
131
+ TestTrue(TEXT("a preview reports what it would update"), Response->HasField(TEXT("wouldUpdate")));
132
+ TestFalse(TEXT("and does not claim to have updated anything"), Response->HasField(TEXT("updated")));
133
+ TestFalse(TEXT("and saves nothing"), Response->HasField(TEXT("saved")));
134
+
135
+ // The zero-match note has to explain the interval trap, because
136
+ // CullDistance is an FInt32Interval and comparing it as a number is the
137
+ // mistake this action invites.
138
+ if (static_cast<int32>(Response->GetNumberField(TEXT("matched"))) == 0 &&
139
+ static_cast<int32>(Response->GetNumberField(TEXT("scanned"))) > 0)
140
+ {
141
+ TestTrue(TEXT("a zero match explains itself"), Response->HasField(TEXT("zeroMatchNote")));
142
+ }
143
+
144
+ return true;
145
+ }
146
+
147
+ #endif // WITH_DEV_AUTOMATION_TESTS
@@ -0,0 +1,82 @@
1
+ #if WITH_DEV_AUTOMATION_TESTS
2
+
3
+ #include "GameThreadExecutor.h"
4
+ #include "Dom/JsonObject.h"
5
+ #include "Dom/JsonValue.h"
6
+ #include "Misc/AutomationTest.h"
7
+
8
+ /**
9
+ * The readiness gate, and the one class of call it must never close in front of.
10
+ *
11
+ * #968: a modal raised during editor startup (the "Restore Packages" prompt
12
+ * after an unclean shutdown) blocks the game thread before the editor is ever
13
+ * marked ready. Every handler then answered "Editor is still initializing" -
14
+ * including respond_to_dialog and set_dialog_policy, the two calls that could
15
+ * have dismissed it. The gate was held shut by the very dialog those calls
16
+ * exist to clear, and the only escape was an OS kill, which discards whatever
17
+ * the user was being asked about. Meanwhile get_engine_state described the
18
+ * dialog down to its button labels, because it answers off the game thread.
19
+ *
20
+ * These run on the game thread, so ExecuteOnGameThread dispatches inline and
21
+ * the assertions are about the gate itself rather than about ticker timing.
22
+ */
23
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
24
+ FMCPGameThreadReadyGateTest,
25
+ "UE.MCP.Bridge.GameThread.ReadyGate",
26
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
27
+
28
+ bool FMCPGameThreadReadyGateTest::RunTest(const FString& Parameters)
29
+ {
30
+ FMCPGameThreadExecutor Executor;
31
+ TestFalse(TEXT("a fresh executor has not been told the editor is ready"), Executor.IsEditorReady());
32
+
33
+ bool bHandlerRan = false;
34
+ FMCPGameThreadExecutor::FHandlerFunction Handler =
35
+ [&bHandlerRan](const TSharedPtr<FJsonObject>&) -> TSharedPtr<FJsonValue>
36
+ {
37
+ bHandlerRan = true;
38
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
39
+ Result->SetBoolField(TEXT("success"), true);
40
+ return MakeShared<FJsonValueObject>(Result);
41
+ };
42
+
43
+ const TSharedPtr<FJsonObject> Params = MakeShared<FJsonObject>();
44
+
45
+ // An ordinary handler still waits. Refusing work that needs a built editor
46
+ // is the whole point of the gate and none of this weakens it.
47
+ TSharedPtr<FJsonValue> Gated = Executor.ExecuteOnGameThread(Handler, Params, 5.0f, /*bModalSafe*/ false);
48
+ TestTrue(TEXT("an ordinary handler is refused before the editor is ready"), Gated.IsValid() && Gated->Type == EJson::Object);
49
+ FString GatedError;
50
+ if (Gated.IsValid() && Gated->Type == EJson::Object)
51
+ {
52
+ Gated->AsObject()->TryGetStringField(TEXT("error"), GatedError);
53
+ }
54
+ TestTrue(TEXT("and told why"), GatedError.Contains(TEXT("still initializing")));
55
+ TestFalse(TEXT("and never reached the handler"), bHandlerRan);
56
+
57
+ // A modal-safe handler runs. It is the escape hatch from a blocked game
58
+ // thread, so nothing the block causes may stand in front of it.
59
+ bHandlerRan = false;
60
+ TSharedPtr<FJsonValue> Exempt = Executor.ExecuteOnGameThread(Handler, Params, 5.0f, /*bModalSafe*/ true);
61
+ TestTrue(TEXT("a modal-safe handler runs before the editor is ready"), bHandlerRan);
62
+ TestTrue(TEXT("and returns its own result, not the gate's error"),
63
+ Exempt.IsValid() && Exempt->Type == EJson::Object && Exempt->AsObject()->HasField(TEXT("success")));
64
+
65
+ FString ExemptError;
66
+ if (Exempt.IsValid() && Exempt->Type == EJson::Object)
67
+ {
68
+ Exempt->AsObject()->TryGetStringField(TEXT("error"), ExemptError);
69
+ }
70
+ TestTrue(TEXT("with no initializing error attached"), ExemptError.IsEmpty());
71
+
72
+ // Once the editor is ready both go through, so the exemption is about the
73
+ // window before readiness and changes nothing after it.
74
+ Executor.SetEditorReady();
75
+ bHandlerRan = false;
76
+ Executor.ExecuteOnGameThread(Handler, Params, 5.0f, /*bModalSafe*/ false);
77
+ TestTrue(TEXT("an ordinary handler runs once the editor is ready"), bHandlerRan);
78
+
79
+ return true;
80
+ }
81
+
82
+ #endif
@@ -0,0 +1,183 @@
1
+ #if WITH_DEV_AUTOMATION_TESTS
2
+
3
+ #include "Handlers/GasHandlers.h"
4
+ #include "HandlerRegistry.h"
5
+ #include "Misc/AutomationTest.h"
6
+ #include "AbilitySystemComponent.h"
7
+ #include "AbilitySystemTestAttributeSet.h"
8
+ #include "AttributeSet.h"
9
+ #include "Engine/Engine.h"
10
+ #include "Engine/World.h"
11
+ #include "GameFramework/Actor.h"
12
+ #include "Misc/ScopeExit.h"
13
+ #include "UObject/UnrealType.h"
14
+
15
+ /**
16
+ * #956: gas(get_live_attribute_value) / gas(set_live_attribute_value) must
17
+ * reach the attribute set instance REGISTERED on the actor's ASC, never a
18
+ * second one built alongside it.
19
+ *
20
+ * The case that makes this hard is the one these tests reproduce: an actor in
21
+ * a world that has not begun play never runs InitializeComponent, so its ASC
22
+ * has no registered sets at all even though the actor owns one. The only
23
+ * correct answer there is to register the actor's OWN instance. Constructing a
24
+ * fresh set instead compiles, runs, reports success, and writes to an object
25
+ * the gameplay code never reads, which is why the pointer-identity assertion
26
+ * below is the point of the whole file.
27
+ */
28
+
29
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
30
+ FGasAdoptOwnerAttributeSetsTest,
31
+ "UE.MCP.Gas.LiveAttributes.AdoptsTheActorsOwnSet",
32
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
33
+
34
+ bool FGasAdoptOwnerAttributeSetsTest::RunTest(const FString& Parameters)
35
+ {
36
+ // A private world, so nothing here touches whatever map the user has open.
37
+ UWorld* World = UWorld::CreateWorld(EWorldType::Editor, /*bInformEngineOfWorld=*/false);
38
+ if (!World)
39
+ {
40
+ AddError(TEXT("could not create a test world"));
41
+ return false;
42
+ }
43
+ ON_SCOPE_EXIT
44
+ {
45
+ World->DestroyWorld(false);
46
+ };
47
+
48
+ AActor* Actor = World->SpawnActor<AActor>();
49
+ if (!Actor)
50
+ {
51
+ AddError(TEXT("could not spawn the test actor"));
52
+ return false;
53
+ }
54
+
55
+ UAbilitySystemComponent* ASC = NewObject<UAbilitySystemComponent>(Actor);
56
+ ASC->RegisterComponent();
57
+
58
+ // The actor's own attribute set, outered to the actor exactly the way a
59
+ // CreateDefaultSubobject-created one is. This is the object the gameplay
60
+ // code would consult once the ASC knows about it.
61
+ // Constructed through the class pointer rather than the templated form:
62
+ // UAbilitySystemTestAttributeSet is MinimalAPI, so its class registration is
63
+ // exported and its constructor is not.
64
+ UAttributeSet* OwnSet = NewObject<UAttributeSet>(
65
+ Actor, UAbilitySystemTestAttributeSet::StaticClass());
66
+
67
+ // The whole premise: the world never began play, so nothing registered it.
68
+ TestNull(
69
+ TEXT("nothing is registered before adoption, even though the actor owns a set"),
70
+ ASC->GetAttributeSet(UAbilitySystemTestAttributeSet::StaticClass()));
71
+
72
+ TArray<FString> Adopted;
73
+ const int32 Count = MCPGas::AdoptOwnerAttributeSets(ASC, Actor, Adopted);
74
+ TestEqual(TEXT("one set was newly registered"), Count, 1);
75
+ TestEqual(TEXT("the registered set is named in the report"), Adopted.Num(), 1);
76
+
77
+ const UAttributeSet* Registered =
78
+ ASC->GetAttributeSet(UAbilitySystemTestAttributeSet::StaticClass());
79
+ TestNotNull(TEXT("the ASC now has a registered set"), Registered);
80
+
81
+ // THE assertion. A second, disconnected instance would satisfy every other
82
+ // check in this file and fail only this one.
83
+ TestTrue(
84
+ TEXT("the registered instance IS the actor's own object, not a copy"),
85
+ Registered == OwnSet);
86
+
87
+ // Idempotent: a second pass registers nothing and does not duplicate.
88
+ TArray<FString> Again;
89
+ TestEqual(TEXT("re-adopting registers nothing new"),
90
+ MCPGas::AdoptOwnerAttributeSets(ASC, Actor, Again), 0);
91
+ TestEqual(TEXT("the set appears exactly once"),
92
+ ASC->GetSpawnedAttributes().Num(), 1);
93
+
94
+ // A value written through the registered instance is the value the ASC's
95
+ // own accessor reads back, which is what "the gameplay code consults it"
96
+ // means in practice.
97
+ FStructProperty* ManaProp = MCPGas::FindAttributeDataProperty(
98
+ UAbilitySystemTestAttributeSet::StaticClass(), TEXT("Mana"));
99
+ TestNotNull(TEXT("Mana is found as an FGameplayAttributeData property"), ManaProp);
100
+ if (ManaProp)
101
+ {
102
+ const FGameplayAttribute Mana(ManaProp);
103
+ float NewValue = 42.0f;
104
+ Mana.SetNumericValueChecked(NewValue, const_cast<UAttributeSet*>(Registered));
105
+ // Read back through the ASC, which resolves the attribute's set on its
106
+ // own. It agreeing with the actor's object is the operational form of
107
+ // "the gameplay code consults this instance", and it is what a second,
108
+ // disconnected set would break.
109
+ TestEqual(TEXT("the ASC reads back what was written to the actor's own instance"),
110
+ ASC->GetNumericAttribute(Mana), Mana.GetNumericValue(OwnSet));
111
+ TestEqual(TEXT("the written value is what landed"),
112
+ Mana.GetNumericValue(OwnSet), 42.0f);
113
+ }
114
+
115
+ return true;
116
+ }
117
+
118
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
119
+ FGasAttributeDataPropertyLookupTest,
120
+ "UE.MCP.Gas.LiveAttributes.AttributePropertyLookup",
121
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
122
+
123
+ bool FGasAttributeDataPropertyLookupTest::RunTest(const FString& Parameters)
124
+ {
125
+ UClass* SetClass = UAbilitySystemTestAttributeSet::StaticClass();
126
+
127
+ TestNotNull(TEXT("bare property name resolves"),
128
+ MCPGas::FindAttributeDataProperty(SetClass, TEXT("Mana")));
129
+ TestNotNull(TEXT("Set.Property spelling resolves"),
130
+ MCPGas::FindAttributeDataProperty(SetClass, TEXT("AbilitySystemTestAttributeSet.Mana")));
131
+ TestNotNull(TEXT("Set:Property spelling resolves"),
132
+ MCPGas::FindAttributeDataProperty(SetClass, TEXT("AbilitySystemTestAttributeSet:Mana")));
133
+
134
+ // Plain float UPROPERTYs on an attribute set are not FGameplayAttributeData
135
+ // and are not what these actions address, so they must miss rather than
136
+ // resolve to something the caller cannot read a base value from.
137
+ TestNull(TEXT("a plain float property is not an attribute data property"),
138
+ MCPGas::FindAttributeDataProperty(SetClass, TEXT("Health")));
139
+ TestNull(TEXT("an unknown name misses"),
140
+ MCPGas::FindAttributeDataProperty(SetClass, TEXT("NoSuchAttribute")));
141
+ TestNull(TEXT("a null class misses rather than crashing"),
142
+ MCPGas::FindAttributeDataProperty(nullptr, TEXT("Mana")));
143
+
144
+ const FString Names = MCPGas::ListAttributeDataPropertyNames(SetClass);
145
+ TestTrue(TEXT("the miss message lists the real attribute names"), Names.Contains(TEXT("Mana")));
146
+ TestEqual(TEXT("a null class lists nothing"),
147
+ *MCPGas::ListAttributeDataPropertyNames(nullptr), TEXT("(none)"));
148
+
149
+ return true;
150
+ }
151
+
152
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
153
+ FGasLiveAttributeRegistrationTest,
154
+ "UE.MCP.Gas.LiveAttributes.RegistrationAndPreflight",
155
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
156
+
157
+ bool FGasLiveAttributeRegistrationTest::RunTest(const FString& Parameters)
158
+ {
159
+ FMCPHandlerRegistry Registry;
160
+ FGasHandlers::RegisterHandlers(Registry);
161
+
162
+ TestTrue(TEXT("get_live_attribute_value is registered"),
163
+ Registry.HasHandler(TEXT("get_live_attribute_value")));
164
+ TestTrue(TEXT("set_live_attribute_value is registered"),
165
+ Registry.HasHandler(TEXT("set_live_attribute_value")));
166
+
167
+ // Preflight runs before any world or actor lookup, so this is safe with no
168
+ // editor world and no PIE session.
169
+ const TSharedPtr<FJsonValue> Response =
170
+ Registry.ExecuteHandler(TEXT("get_live_attribute_value"), MakeShared<FJsonObject>());
171
+ TestTrue(TEXT("preflight returns an object"), Response.IsValid() && Response->Type == EJson::Object);
172
+ if (Response.IsValid() && Response->Type == EJson::Object)
173
+ {
174
+ const TSharedPtr<FJsonObject> Object = Response->AsObject();
175
+ TestFalse(TEXT("preflight is unsuccessful"), Object->GetBoolField(TEXT("success")));
176
+ TestTrue(TEXT("preflight names the first required field"),
177
+ Object->GetStringField(TEXT("error")).Contains(TEXT("attributeSet")));
178
+ }
179
+
180
+ return true;
181
+ }
182
+
183
+ #endif
@@ -0,0 +1,119 @@
1
+ // Coverage for landscape(sample) parameter parity (#939).
2
+ //
3
+ // The action documented "Params: x, y" and the handler required an object
4
+ // called `point`, so every documented call shape answered "Missing 'point'
5
+ // parameter" and there was no working call at all. These assertions pin the
6
+ // contract rather than the terrain: each accepted position shape gets PAST
7
+ // parameter validation, and a request with no position at all is refused with
8
+ // an error that names every shape that would have worked.
9
+ //
10
+ // The terrain half (heights, weights) needs a landscape in the level and is
11
+ // exercised by the live smoke run; what regressed here was the parameter
12
+ // handling, and that is checkable with no landscape at all.
13
+
14
+ #if WITH_DEV_AUTOMATION_TESTS
15
+
16
+ #include "HandlerRegistry.h"
17
+ #include "Handlers/LandscapeHandlers.h"
18
+ #include "Misc/AutomationTest.h"
19
+
20
+ namespace
21
+ {
22
+ TSharedPtr<FJsonObject> MCPLandscapeSampleTestRun(
23
+ FMCPHandlerRegistry& Registry,
24
+ const TSharedPtr<FJsonObject>& Request)
25
+ {
26
+ const TSharedPtr<FJsonValue> Response = Registry.ExecuteHandler(TEXT("sample_landscape"), Request);
27
+ if (!Response.IsValid() || Response->Type != EJson::Object)
28
+ {
29
+ return nullptr;
30
+ }
31
+ return Response->AsObject();
32
+ }
33
+
34
+ /** The error text a request is refused with, or empty when it succeeded. */
35
+ FString MCPLandscapeSampleTestError(const TSharedPtr<FJsonObject>& Response)
36
+ {
37
+ if (!Response.IsValid()) return FString();
38
+ if (Response->GetBoolField(TEXT("success"))) return FString();
39
+ return Response->GetStringField(TEXT("error"));
40
+ }
41
+ }
42
+
43
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
44
+ FLandscapeSampleAcceptsItsDocumentedArgumentsTest,
45
+ "UE.MCP.Landscape.Sample.AcceptsItsDocumentedArguments",
46
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
47
+
48
+ bool FLandscapeSampleAcceptsItsDocumentedArgumentsTest::RunTest(const FString& Parameters)
49
+ {
50
+ FMCPHandlerRegistry Registry;
51
+ FLandscapeHandlers::RegisterHandlers(Registry);
52
+ TestTrue(TEXT("sample_landscape is registered"), Registry.HasHandler(TEXT("sample_landscape")));
53
+
54
+ // No position at all is the one request that SHOULD be refused, and the
55
+ // refusal has to name every shape that works. The old message named only
56
+ // `point`, which is the shape the schema never advertised.
57
+ {
58
+ const TSharedPtr<FJsonObject> Response =
59
+ MCPLandscapeSampleTestRun(Registry, MakeShared<FJsonObject>());
60
+ if (Response.IsValid())
61
+ {
62
+ TestFalse(TEXT("a request with no position is refused"), Response->GetBoolField(TEXT("success")));
63
+ const FString Error = Response->GetStringField(TEXT("error"));
64
+ TestTrue(TEXT("and the refusal names the x/y shape"), Error.Contains(TEXT("x and y")));
65
+ TestTrue(TEXT("and the point shape"), Error.Contains(TEXT("point")));
66
+ TestTrue(TEXT("and the worldX/worldY shape"), Error.Contains(TEXT("worldX")));
67
+ }
68
+ }
69
+
70
+ // Every accepted shape must get past parameter validation. Whether a
71
+ // landscape exists in the level is a separate question, so the assertion is
72
+ // on the error NOT being the missing-position one.
73
+ auto TestShapeIsAccepted = [this, &Registry](const TCHAR* What, const TSharedPtr<FJsonObject>& Request)
74
+ {
75
+ const TSharedPtr<FJsonObject> Response = MCPLandscapeSampleTestRun(Registry, Request);
76
+ if (!Response.IsValid()) return;
77
+ const FString Error = MCPLandscapeSampleTestError(Response);
78
+ TestFalse(FString::Printf(TEXT("%s is not refused as a missing position"), What),
79
+ Error.Contains(TEXT("Missing sample position")));
80
+ TestFalse(FString::Printf(TEXT("%s is not refused for a missing 'point'"), What),
81
+ Error.Contains(TEXT("Missing 'point'")));
82
+ };
83
+
84
+ {
85
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
86
+ Request->SetNumberField(TEXT("x"), 1000.0);
87
+ Request->SetNumberField(TEXT("y"), 2000.0);
88
+ TestShapeIsAccepted(TEXT("x + y"), Request);
89
+ }
90
+ {
91
+ TSharedPtr<FJsonObject> Point = MakeShared<FJsonObject>();
92
+ Point->SetNumberField(TEXT("x"), 1000.0);
93
+ Point->SetNumberField(TEXT("y"), 2000.0);
94
+ Point->SetNumberField(TEXT("z"), 0.0);
95
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
96
+ Request->SetObjectField(TEXT("point"), Point);
97
+ TestShapeIsAccepted(TEXT("point {x, y, z}"), Request);
98
+ }
99
+ {
100
+ // The z is optional: the surface height is what the action answers, so
101
+ // requiring one as an input would be a riddle.
102
+ TSharedPtr<FJsonObject> Point = MakeShared<FJsonObject>();
103
+ Point->SetNumberField(TEXT("x"), 1000.0);
104
+ Point->SetNumberField(TEXT("y"), 2000.0);
105
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
106
+ Request->SetObjectField(TEXT("point"), Point);
107
+ TestShapeIsAccepted(TEXT("point {x, y}"), Request);
108
+ }
109
+ {
110
+ TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
111
+ Request->SetNumberField(TEXT("worldX"), 1000.0);
112
+ Request->SetNumberField(TEXT("worldY"), 2000.0);
113
+ TestShapeIsAccepted(TEXT("worldX + worldY"), Request);
114
+ }
115
+
116
+ return true;
117
+ }
118
+
119
+ #endif // WITH_DEV_AUTOMATION_TESTS