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
@@ -54,6 +54,10 @@ private:
54
54
  static TSharedPtr<FJsonValue> DeleteVariable(const TSharedPtr<FJsonObject>& Params);
55
55
  static TSharedPtr<FJsonValue> AddFunctionParameter(const TSharedPtr<FJsonObject>& Params);
56
56
  static TSharedPtr<FJsonValue> SetVariableDefault(const TSharedPtr<FJsonObject>& Params);
57
+ // #902: read the RESOLVED default off the generated class CDO, so a
58
+ // write-compile-readback loop can verify itself. Reports whether that value
59
+ // has reached the package as well as what it is (#931).
60
+ static TSharedPtr<FJsonValue> GetVariableDefault(const TSharedPtr<FJsonObject>& Params);
57
61
 
58
62
  // v0.7.8 - agent-ergonomics additions (stubs)
59
63
  static TSharedPtr<FJsonValue> ReadBlueprintGraphSummary(const TSharedPtr<FJsonObject>& Params);
@@ -83,6 +87,7 @@ private:
83
87
  static TSharedPtr<FJsonValue> ReparentBlueprint(const TSharedPtr<FJsonObject>& Params);
84
88
  // #580 flush orphaned InheritableComponentHandler override records
85
89
  static TSharedPtr<FJsonValue> FlushInheritableComponentHandler(const TSharedPtr<FJsonObject>& Params);
90
+ static TSharedPtr<FJsonValue> FlushComponentTemplates(const TSharedPtr<FJsonObject>& Params);
86
91
 
87
92
  // issues #182/#183: C++ class CDO property access
88
93
  static TSharedPtr<FJsonValue> SetCdoProperty(const TSharedPtr<FJsonObject>& Params);
@@ -97,6 +102,11 @@ private:
97
102
  static TSharedPtr<FJsonValue> ConnectPinsBatch(const TSharedPtr<FJsonObject>& Params);
98
103
  static TSharedPtr<FJsonValue> SetNodePosition(const TSharedPtr<FJsonObject>& Params);
99
104
  static TSharedPtr<FJsonValue> AutoLayoutGraph(const TSharedPtr<FJsonObject>& Params);
105
+ // #945: project-wide search for authored function call sites, narrowed by
106
+ // the Asset Registry before any package is loaded. Defined in
107
+ // BlueprintHandlers_Search.cpp.
108
+ static TSharedPtr<FJsonValue> SearchCallSites(const TSharedPtr<FJsonObject>& Params);
109
+
100
110
  // #419: SetCapsuleSize on CapsuleComponent BP templates (UFUNCTION setter
101
111
  // path; raw property writes leave the visualizer stale)
102
112
  static TSharedPtr<FJsonValue> SetCapsuleSize(const TSharedPtr<FJsonObject>& Params);
@@ -0,0 +1,502 @@
1
+ // Effective collision reads (#925). See BlueprintHandlers_Collision.h for why
2
+ // the existing property dumps cannot answer the question these two do.
3
+ //
4
+ // The whole file reads. Nothing here writes a package, spawns anything, or
5
+ // touches the open level.
6
+
7
+ #include "BlueprintHandlers_Collision.h"
8
+
9
+ #include "BlueprintHandlers_Internal.h"
10
+ #include "HandlerRegistry.h"
11
+ #include "HandlerUtils.h"
12
+
13
+ #include "Components/PrimitiveComponent.h"
14
+ #include "Engine/Blueprint.h"
15
+ #include "Engine/CollisionProfile.h"
16
+ #include "Engine/EngineTypes.h"
17
+ #include "GameFramework/Actor.h"
18
+
19
+ #include "Dom/JsonObject.h"
20
+ #include "Dom/JsonValue.h"
21
+
22
+ namespace
23
+ {
24
+ // The container has one byte per serialisable channel and ECC_GameTraceChannel50
25
+ // is the last of them, so the response table is exactly this wide. ECC_MAX is
26
+ // larger because it counts the deprecated non-serialised entry past the end.
27
+ constexpr int32 CollisionChannelCount = 64;
28
+
29
+ /** "Block" rather than "ECR_Block". The enum's DisplayName metadata says the
30
+ * same thing, but only in an editor build with metadata loaded, and a result
31
+ * field that silently degrades to an ordinal is worse than a switch. */
32
+ const TCHAR* CollisionResponseName(ECollisionResponse Response)
33
+ {
34
+ switch (Response)
35
+ {
36
+ case ECR_Ignore: return TEXT("Ignore");
37
+ case ECR_Overlap: return TEXT("Overlap");
38
+ case ECR_Block: return TEXT("Block");
39
+ default: return TEXT("Unknown");
40
+ }
41
+ }
42
+
43
+ /** The spelling the Collision details panel uses, for the same reason. */
44
+ const TCHAR* CollisionEnabledName(ECollisionEnabled::Type Enabled)
45
+ {
46
+ switch (Enabled)
47
+ {
48
+ case ECollisionEnabled::NoCollision: return TEXT("NoCollision");
49
+ case ECollisionEnabled::QueryOnly: return TEXT("QueryOnly");
50
+ case ECollisionEnabled::PhysicsOnly: return TEXT("PhysicsOnly");
51
+ case ECollisionEnabled::QueryAndPhysics: return TEXT("QueryAndPhysics");
52
+ case ECollisionEnabled::ProbeOnly: return TEXT("ProbeOnly");
53
+ case ECollisionEnabled::QueryAndProbe: return TEXT("QueryAndProbe");
54
+ default: return TEXT("Unknown");
55
+ }
56
+ }
57
+
58
+ /** The C++ enumerator for a container index: ECC_Camera for 4. Stable across
59
+ * projects, unlike the display name, so a caller can key on it. */
60
+ FString CollisionChannelEnumName(int32 Index)
61
+ {
62
+ if (Index >= 0 && Index < 8)
63
+ {
64
+ static const TCHAR* const Fixed[8] = {
65
+ TEXT("ECC_WorldStatic"), TEXT("ECC_WorldDynamic"), TEXT("ECC_Pawn"),
66
+ TEXT("ECC_Visibility"), TEXT("ECC_Camera"), TEXT("ECC_PhysicsBody"),
67
+ TEXT("ECC_Vehicle"), TEXT("ECC_Destructible")
68
+ };
69
+ return Fixed[Index];
70
+ }
71
+ if (Index >= 8 && Index < 14)
72
+ {
73
+ return FString::Printf(TEXT("ECC_EngineTraceChannel%d"), Index - 7);
74
+ }
75
+ if (Index >= 14 && Index < CollisionChannelCount)
76
+ {
77
+ return FString::Printf(TEXT("ECC_GameTraceChannel%d"), Index - 13);
78
+ }
79
+ return FString::Printf(TEXT("ECC_Unknown%d"), Index);
80
+ }
81
+
82
+ /** The name a channel carries when the project has not renamed it. Comparing
83
+ * the configured name against this is what tells a project's own channel
84
+ * ("Weapon") apart from an unused slot ("GameTraceChannel7"). */
85
+ FString CollisionChannelDefaultName(int32 Index)
86
+ {
87
+ FString EnumName = CollisionChannelEnumName(Index);
88
+ EnumName.RemoveFromStart(TEXT("ECC_"));
89
+ return EnumName;
90
+ }
91
+
92
+ /** One channel, described once so the component read and the profile read
93
+ * cannot disagree about what a channel is called. */
94
+ struct FMCPCollisionChannelInfo
95
+ {
96
+ int32 Index = 0;
97
+ ECollisionChannel Channel = ECC_WorldStatic;
98
+ FString EnumName;
99
+ FString DisplayName;
100
+ bool bCustomNamed = false;
101
+ bool bTraceChannel = false;
102
+ bool bObjectChannel = false;
103
+ };
104
+
105
+ /** Build the channel table from the project's own collision settings, so a
106
+ * custom trace or object channel appears under the name the project gave it
107
+ * rather than as GameTraceChannel<n>. */
108
+ TArray<FMCPCollisionChannelInfo> BuildCollisionChannelTable()
109
+ {
110
+ TArray<FMCPCollisionChannelInfo> Table;
111
+
112
+ UCollisionProfile* Profile = UCollisionProfile::Get();
113
+ Table.Reserve(CollisionChannelCount);
114
+ for (int32 Index = 0; Index < CollisionChannelCount; ++Index)
115
+ {
116
+ FMCPCollisionChannelInfo Info;
117
+ Info.Index = Index;
118
+ Info.Channel = static_cast<ECollisionChannel>(Index);
119
+ Info.EnumName = CollisionChannelEnumName(Index);
120
+
121
+ const FString DefaultName = CollisionChannelDefaultName(Index);
122
+ Info.DisplayName = DefaultName;
123
+ if (Profile)
124
+ {
125
+ const FName Configured = Profile->ReturnChannelNameFromContainerIndex(Index);
126
+ if (!Configured.IsNone())
127
+ {
128
+ Info.DisplayName = Configured.ToString();
129
+ }
130
+ Info.bTraceChannel = Profile->ConvertToTraceType(Info.Channel) != TraceTypeQuery_MAX;
131
+ Info.bObjectChannel = Profile->ConvertToObjectType(Info.Channel) != ObjectTypeQuery_MAX;
132
+ }
133
+ Info.bCustomNamed = !Info.DisplayName.Equals(DefaultName, ESearchCase::CaseSensitive);
134
+ Table.Add(Info);
135
+ }
136
+ return Table;
137
+ }
138
+
139
+ /** Which channels a response list carries by default.
140
+ *
141
+ * All 64 would bury the answer in fifty unused GameTraceChannel slots, so the
142
+ * default is the eight engine channels every project has plus every channel
143
+ * the project actually configured. includeAllChannels=true asks for the rest. */
144
+ bool ShouldReportChannel(const FMCPCollisionChannelInfo& Info, bool bIncludeAll)
145
+ {
146
+ if (bIncludeAll) return true;
147
+ if (Info.Index < 8) return true;
148
+ return Info.bCustomNamed;
149
+ }
150
+
151
+ /** Match a caller's `channel` argument against the table. Accepts the
152
+ * configured display name ("Weapon"), the C++ enumerator ("ECC_Camera"), the
153
+ * bare enumerator ("Camera") and the container index as a string. Returns
154
+ * INDEX_NONE on a miss. */
155
+ int32 FindCollisionChannel(const TArray<FMCPCollisionChannelInfo>& Table, const FString& Spec)
156
+ {
157
+ if (Spec.IsEmpty()) return INDEX_NONE;
158
+
159
+ if (Spec.IsNumeric())
160
+ {
161
+ const int32 AsIndex = FCString::Atoi(*Spec);
162
+ return (AsIndex >= 0 && AsIndex < Table.Num()) ? AsIndex : INDEX_NONE;
163
+ }
164
+
165
+ for (const FMCPCollisionChannelInfo& Info : Table)
166
+ {
167
+ if (Info.DisplayName.Equals(Spec, ESearchCase::IgnoreCase)) return Info.Index;
168
+ if (Info.EnumName.Equals(Spec, ESearchCase::IgnoreCase)) return Info.Index;
169
+ }
170
+ return INDEX_NONE;
171
+ }
172
+
173
+ /** The names a failed channel lookup should suggest: everything a caller could
174
+ * legitimately have meant, without the unused slots. */
175
+ FString DescribeKnownChannels(const TArray<FMCPCollisionChannelInfo>& Table)
176
+ {
177
+ TArray<FString> Names;
178
+ for (const FMCPCollisionChannelInfo& Info : Table)
179
+ {
180
+ if (ShouldReportChannel(Info, /*bIncludeAll=*/false))
181
+ {
182
+ Names.Add(Info.DisplayName);
183
+ }
184
+ }
185
+ return FString::Join(Names, TEXT(", "));
186
+ }
187
+
188
+ void WriteChannelIdentity(const TSharedPtr<FJsonObject>& Out, const FMCPCollisionChannelInfo& Info)
189
+ {
190
+ Out->SetStringField(TEXT("channel"), Info.DisplayName);
191
+ Out->SetStringField(TEXT("enumName"), Info.EnumName);
192
+ Out->SetNumberField(TEXT("channelIndex"), Info.Index);
193
+ Out->SetBoolField(TEXT("isTraceChannel"), Info.bTraceChannel);
194
+ Out->SetBoolField(TEXT("isObjectChannel"), Info.bObjectChannel);
195
+ Out->SetBoolField(TEXT("isCustomNamed"), Info.bCustomNamed);
196
+ }
197
+
198
+ /** Look a profile up by name, tolerating a renamed profile through the
199
+ * engine's own redirect table. */
200
+ bool LookUpProfileTemplate(const FString& ProfileName, FCollisionResponseTemplate& OutTemplate, FString& OutResolvedName)
201
+ {
202
+ OutResolvedName = ProfileName;
203
+ UCollisionProfile* Profile = UCollisionProfile::Get();
204
+ if (!Profile) return false;
205
+
206
+ FName Name(*ProfileName);
207
+ if (const FName* Redirect = Profile->LookForProfileRedirect(Name))
208
+ {
209
+ Name = *Redirect;
210
+ OutResolvedName = Name.ToString();
211
+ }
212
+ return Profile->GetProfileTemplate(Name, OutTemplate);
213
+ }
214
+
215
+ /** Every profile the project has, for a lookup that missed. */
216
+ TArray<FString> ListProfileNames()
217
+ {
218
+ TArray<FString> Names;
219
+ UCollisionProfile* Profile = UCollisionProfile::Get();
220
+ if (!Profile) return Names;
221
+ for (int32 Index = 0; Index < Profile->GetNumOfProfiles(); ++Index)
222
+ {
223
+ if (const FCollisionResponseTemplate* Template = Profile->GetProfileByIndex(Index))
224
+ {
225
+ Names.AddUnique(Template->Name.ToString());
226
+ }
227
+ }
228
+ return Names;
229
+ }
230
+
231
+ /** Collect every component on an Actor CDO, which is where a native C++
232
+ * constructor's CreateDefaultSubobject lands. This is the case #925 was
233
+ * reported from: verifying that a rebuilt constructor's
234
+ * SetCollisionResponseToChannel actually reached the CDO. */
235
+ UActorComponent* FindComponentOnActorCDO(
236
+ AActor* CDO,
237
+ const FString& ComponentName,
238
+ TArray<FString>& OutAvailable)
239
+ {
240
+ if (!CDO) return nullptr;
241
+
242
+ UActorComponent* Found = nullptr;
243
+ for (UActorComponent* Component : CDO->GetComponents())
244
+ {
245
+ if (!Component) continue;
246
+ const FString Name = Component->GetName();
247
+ OutAvailable.AddUnique(Name);
248
+ if (!Found && Name.Equals(ComponentName, ESearchCase::IgnoreCase))
249
+ {
250
+ Found = Component;
251
+ }
252
+ }
253
+ return Found;
254
+ }
255
+ }
256
+
257
+ void FCollisionQueryHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
258
+ {
259
+ Registry.RegisterHandler(TEXT("get_component_collision"), &GetComponentCollision);
260
+ Registry.RegisterHandler(TEXT("resolve_collision_profile"), &ResolveCollisionProfile);
261
+ }
262
+
263
+ TSharedPtr<FJsonValue> FCollisionQueryHandlers::GetComponentCollision(const TSharedPtr<FJsonObject>& Params)
264
+ {
265
+ FString AssetPath;
266
+ if (auto Err = RequireStringAlt(Params, TEXT("assetPath"), TEXT("path"), AssetPath)) return Err;
267
+
268
+ FString ComponentName;
269
+ if (auto Err = RequireString(Params, TEXT("componentName"), ComponentName)) return Err;
270
+
271
+ const FString RequestedChannel = OptionalString(Params, TEXT("channel"));
272
+ const bool bIncludeAll = OptionalBool(Params, TEXT("includeAllChannels"), false);
273
+
274
+ // Two ways in, because the two things a caller wants to verify live in
275
+ // different places: a Blueprint's component template, and a native class's
276
+ // CDO component. A Blueprint path resolves as an asset; anything else is
277
+ // tried as a class.
278
+ UActorComponent* Component = nullptr;
279
+ TArray<FString> Available;
280
+ bool bInherited = false;
281
+ FString Source;
282
+ FString OwnerPath;
283
+
284
+ if (UBlueprint* Blueprint = Cast<UBlueprint>(MCPLoadAssetObject(AssetPath)))
285
+ {
286
+ Component = ResolveComponentTemplate(
287
+ Blueprint, ComponentName, /*bForWrite=*/false, bInherited, Available);
288
+ Source = TEXT("blueprint");
289
+ OwnerPath = Blueprint->GetPathName();
290
+ }
291
+ else
292
+ {
293
+ UClass* Class = MCPResolveClass(AssetPath);
294
+ if (!Class)
295
+ {
296
+ return MCPClassNotFoundError(AssetPath, TEXT("assetPath"));
297
+ }
298
+ if (!Class->IsChildOf(AActor::StaticClass()))
299
+ {
300
+ return MCPClassUnusableError(AssetPath, Class, TEXT("wrong_base"),
301
+ TEXT("it is not an Actor class, so it has no component to read collision from."));
302
+ }
303
+ AActor* CDO = Cast<AActor>(Class->GetDefaultObject());
304
+ Component = FindComponentOnActorCDO(CDO, ComponentName, Available);
305
+ Source = TEXT("class");
306
+ OwnerPath = Class->GetPathName();
307
+ }
308
+
309
+ if (!Component)
310
+ {
311
+ Available.Sort([](const FString& A, const FString& B) { return A < B; });
312
+ return MCPError(FString::Printf(
313
+ TEXT("Component '%s' not found on '%s'. Available: [%s]"),
314
+ *ComponentName, *AssetPath, *FString::Join(Available, TEXT(", "))));
315
+ }
316
+
317
+ UPrimitiveComponent* Primitive = Cast<UPrimitiveComponent>(Component);
318
+ if (!Primitive)
319
+ {
320
+ // A SceneComponent or a bare ActorComponent has no BodyInstance at all,
321
+ // and saying "not a PrimitiveComponent" is the difference between an
322
+ // answerable question and an empty response.
323
+ return MCPError(FString::Printf(
324
+ TEXT("Component '%s' on '%s' is a %s, which carries no collision. Only PrimitiveComponent ")
325
+ TEXT("subclasses (capsules, boxes, spheres, meshes) have a collision profile and per-channel responses."),
326
+ *ComponentName, *AssetPath, *Component->GetClass()->GetName()));
327
+ }
328
+
329
+ const TArray<FMCPCollisionChannelInfo> Table = BuildCollisionChannelTable();
330
+
331
+ int32 SingleChannel = INDEX_NONE;
332
+ if (!RequestedChannel.IsEmpty())
333
+ {
334
+ SingleChannel = FindCollisionChannel(Table, RequestedChannel);
335
+ if (SingleChannel == INDEX_NONE)
336
+ {
337
+ return MCPError(FString::Printf(
338
+ TEXT("Unknown collision channel '%s'. Pass a configured channel name, a C++ enumerator ")
339
+ TEXT("(ECC_Camera), or a container index. Known channels: %s"),
340
+ *RequestedChannel, *DescribeKnownChannels(Table)));
341
+ }
342
+ }
343
+
344
+ const FName ProfileName = Primitive->GetCollisionProfileName();
345
+ FCollisionResponseTemplate ProfileTemplate;
346
+ FString ResolvedProfileName;
347
+ const bool bProfileResolved =
348
+ LookUpProfileTemplate(ProfileName.ToString(), ProfileTemplate, ResolvedProfileName);
349
+
350
+ auto Result = MCPSuccess();
351
+ Result->SetStringField(TEXT("assetPath"), AssetPath);
352
+ Result->SetStringField(TEXT("resolvedPath"), OwnerPath);
353
+ Result->SetStringField(TEXT("source"), Source);
354
+ Result->SetStringField(TEXT("componentName"), Component->GetName());
355
+ Result->SetStringField(TEXT("componentClass"), Component->GetClass()->GetName());
356
+ Result->SetBoolField(TEXT("inherited"), bInherited);
357
+
358
+ Result->SetStringField(TEXT("collisionEnabled"), CollisionEnabledName(Primitive->GetCollisionEnabled()));
359
+ Result->SetBoolField(TEXT("collisionEnabledForQueries"), Primitive->IsQueryCollisionEnabled());
360
+ Result->SetBoolField(TEXT("collisionEnabledForPhysics"), Primitive->IsPhysicsCollisionEnabled());
361
+
362
+ const ECollisionChannel ObjectType = Primitive->GetCollisionObjectType();
363
+ const int32 ObjectTypeIndex = static_cast<int32>(ObjectType);
364
+ Result->SetStringField(TEXT("objectType"),
365
+ Table.IsValidIndex(ObjectTypeIndex) ? Table[ObjectTypeIndex].DisplayName : CollisionChannelEnumName(ObjectTypeIndex));
366
+ Result->SetStringField(TEXT("objectTypeEnumName"), CollisionChannelEnumName(ObjectTypeIndex));
367
+ Result->SetNumberField(TEXT("objectTypeIndex"), ObjectTypeIndex);
368
+
369
+ Result->SetStringField(TEXT("profileName"), ProfileName.ToString());
370
+ Result->SetBoolField(TEXT("profileResolved"), bProfileResolved);
371
+ if (bProfileResolved && !ResolvedProfileName.Equals(ProfileName.ToString(), ESearchCase::CaseSensitive))
372
+ {
373
+ Result->SetStringField(TEXT("profileRedirectedTo"), ResolvedProfileName);
374
+ }
375
+
376
+ // The effective response per channel. GetCollisionResponseToChannel is the
377
+ // evaluated answer: the profile's response with the component's own
378
+ // overrides already folded in. The profile's own response rides alongside
379
+ // so a caller can see WHERE the answer came from, which is what the
380
+ // ResponseArray text dump could never show for an inherited response.
381
+ TArray<TSharedPtr<FJsonValue>> Responses;
382
+ for (const FMCPCollisionChannelInfo& Info : Table)
383
+ {
384
+ if (SingleChannel != INDEX_NONE && Info.Index != SingleChannel) continue;
385
+ if (SingleChannel == INDEX_NONE && !ShouldReportChannel(Info, bIncludeAll)) continue;
386
+
387
+ const ECollisionResponse Effective = Primitive->GetCollisionResponseToChannel(Info.Channel);
388
+
389
+ TSharedPtr<FJsonObject> Entry = MakeShared<FJsonObject>();
390
+ WriteChannelIdentity(Entry, Info);
391
+ Entry->SetStringField(TEXT("response"), CollisionResponseName(Effective));
392
+ if (bProfileResolved)
393
+ {
394
+ const ECollisionResponse FromProfile = ProfileTemplate.ResponseToChannels.GetResponse(Info.Channel);
395
+ Entry->SetStringField(TEXT("profileResponse"), CollisionResponseName(FromProfile));
396
+ Entry->SetBoolField(TEXT("overridesProfile"), Effective != FromProfile);
397
+ }
398
+ Responses.Add(MakeShared<FJsonValueObject>(Entry));
399
+ }
400
+
401
+ if (SingleChannel != INDEX_NONE && Responses.Num() > 0)
402
+ {
403
+ // One channel asked for, one answer at the top level as well as in the
404
+ // list, so the caller does not have to index into an array of one.
405
+ Result->SetObjectField(TEXT("channel"), Responses[0]->AsObject());
406
+ }
407
+ Result->SetArrayField(TEXT("responses"), Responses);
408
+ Result->SetNumberField(TEXT("responseCount"), Responses.Num());
409
+ Result->SetBoolField(TEXT("includeAllChannels"), bIncludeAll);
410
+ return MCPResult(Result);
411
+ }
412
+
413
+ TSharedPtr<FJsonValue> FCollisionQueryHandlers::ResolveCollisionProfile(const TSharedPtr<FJsonObject>& Params)
414
+ {
415
+ FString ProfileName;
416
+ if (auto Err = RequireString(Params, TEXT("profileName"), ProfileName)) return Err;
417
+
418
+ const FString RequestedChannel = OptionalString(Params, TEXT("channel"));
419
+ const bool bIncludeAll = OptionalBool(Params, TEXT("includeAllChannels"), false);
420
+
421
+ if (!UCollisionProfile::Get())
422
+ {
423
+ return MCPError(TEXT("Collision settings are not available in this process."));
424
+ }
425
+
426
+ FCollisionResponseTemplate Template;
427
+ FString ResolvedProfileName;
428
+ if (!LookUpProfileTemplate(ProfileName, Template, ResolvedProfileName))
429
+ {
430
+ TArray<FString> Known = ListProfileNames();
431
+ Known.Sort([](const FString& A, const FString& B) { return A < B; });
432
+
433
+ TSharedPtr<FJsonObject> Obj = MakeShared<FJsonObject>();
434
+ Obj->SetBoolField(TEXT("success"), false);
435
+ Obj->SetStringField(TEXT("error"), FString::Printf(
436
+ TEXT("No collision profile named '%s'. The project defines: %s"),
437
+ *ProfileName, *FString::Join(Known, TEXT(", "))));
438
+ Obj->SetStringField(TEXT("profileName"), ProfileName);
439
+ Obj->SetStringField(TEXT("reason"), TEXT("profile_not_found"));
440
+ TArray<TSharedPtr<FJsonValue>> KnownJson;
441
+ for (const FString& Name : Known) KnownJson.Add(MakeShared<FJsonValueString>(Name));
442
+ Obj->SetArrayField(TEXT("knownProfiles"), KnownJson);
443
+ return MakeShared<FJsonValueObject>(Obj);
444
+ }
445
+
446
+ const TArray<FMCPCollisionChannelInfo> Table = BuildCollisionChannelTable();
447
+
448
+ int32 SingleChannel = INDEX_NONE;
449
+ if (!RequestedChannel.IsEmpty())
450
+ {
451
+ SingleChannel = FindCollisionChannel(Table, RequestedChannel);
452
+ if (SingleChannel == INDEX_NONE)
453
+ {
454
+ return MCPError(FString::Printf(
455
+ TEXT("Unknown collision channel '%s'. Pass a configured channel name, a C++ enumerator ")
456
+ TEXT("(ECC_Camera), or a container index. Known channels: %s"),
457
+ *RequestedChannel, *DescribeKnownChannels(Table)));
458
+ }
459
+ }
460
+
461
+ auto Result = MCPSuccess();
462
+ Result->SetStringField(TEXT("profileName"), Template.Name.ToString());
463
+ Result->SetStringField(TEXT("requestedProfileName"), ProfileName);
464
+ if (!ResolvedProfileName.Equals(ProfileName, ESearchCase::CaseSensitive))
465
+ {
466
+ Result->SetStringField(TEXT("profileRedirectedTo"), ResolvedProfileName);
467
+ }
468
+ Result->SetStringField(TEXT("collisionEnabled"), CollisionEnabledName(Template.CollisionEnabled));
469
+
470
+ const int32 ObjectTypeIndex = static_cast<int32>(Template.ObjectType.GetValue());
471
+ Result->SetStringField(TEXT("objectType"),
472
+ Table.IsValidIndex(ObjectTypeIndex) ? Table[ObjectTypeIndex].DisplayName : CollisionChannelEnumName(ObjectTypeIndex));
473
+ Result->SetStringField(TEXT("objectTypeEnumName"), CollisionChannelEnumName(ObjectTypeIndex));
474
+ Result->SetStringField(TEXT("objectTypeName"), Template.ObjectTypeName.ToString());
475
+ Result->SetNumberField(TEXT("objectTypeIndex"), ObjectTypeIndex);
476
+ Result->SetBoolField(TEXT("canModify"), Template.bCanModify);
477
+ #if WITH_EDITORONLY_DATA
478
+ Result->SetStringField(TEXT("helpMessage"), Template.HelpMessage);
479
+ #endif
480
+
481
+ TArray<TSharedPtr<FJsonValue>> Responses;
482
+ for (const FMCPCollisionChannelInfo& Info : Table)
483
+ {
484
+ if (SingleChannel != INDEX_NONE && Info.Index != SingleChannel) continue;
485
+ if (SingleChannel == INDEX_NONE && !ShouldReportChannel(Info, bIncludeAll)) continue;
486
+
487
+ TSharedPtr<FJsonObject> Entry = MakeShared<FJsonObject>();
488
+ WriteChannelIdentity(Entry, Info);
489
+ Entry->SetStringField(TEXT("response"),
490
+ CollisionResponseName(Template.ResponseToChannels.GetResponse(Info.Channel)));
491
+ Responses.Add(MakeShared<FJsonValueObject>(Entry));
492
+ }
493
+
494
+ if (SingleChannel != INDEX_NONE && Responses.Num() > 0)
495
+ {
496
+ Result->SetObjectField(TEXT("channel"), Responses[0]->AsObject());
497
+ }
498
+ Result->SetArrayField(TEXT("responses"), Responses);
499
+ Result->SetNumberField(TEXT("responseCount"), Responses.Num());
500
+ Result->SetBoolField(TEXT("includeAllChannels"), bIncludeAll);
501
+ return MCPResult(Result);
502
+ }
@@ -0,0 +1,43 @@
1
+ #pragma once
2
+
3
+ #include "CoreMinimal.h"
4
+ #include "Dom/JsonValue.h"
5
+ #include "Dom/JsonObject.h"
6
+
7
+ /**
8
+ * Effective collision reads (#925).
9
+ *
10
+ * What already existed reports the collision a component STORES, not the
11
+ * collision it HAS. blueprint(read_component_properties) exports BodyInstance
12
+ * as text, and that text carries CollisionProfileName plus the ResponseArray of
13
+ * overrides that DIFFER from the profile. A response inherited from the profile
14
+ * (the Pawn profile blocking Camera, say) appears nowhere in it, so "does this
15
+ * capsule block ECC_Camera" could not be answered from the dump.
16
+ * editor(get_object_properties) has the same limit: it exports property text,
17
+ * it does not evaluate the profile.
18
+ *
19
+ * That gap has teeth. A live-coded constructor change to
20
+ * SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore) LOOKED applied, because
21
+ * the Live Coding compile succeeded, and the CDO still answered ECR_BLOCK until
22
+ * a proper on-disk build and an editor restart. The text dump was byte for byte
23
+ * identical before and after. Only the effective response, which is what
24
+ * UPrimitiveComponent::GetCollisionResponseToChannel returns, showed it.
25
+ *
26
+ * A separate class rather than another FBlueprintHandlers partition, because
27
+ * these register themselves and the two actions land in two different wire
28
+ * categories (`blueprint` and `project`) while sharing one channel table. The
29
+ * actions still read as blueprint(get_component_collision) and
30
+ * project(resolve_collision_profile) to a caller.
31
+ */
32
+ class FCollisionQueryHandlers
33
+ {
34
+ public:
35
+ static void RegisterHandlers(class FMCPHandlerRegistry& Registry);
36
+
37
+ private:
38
+ /** Resolved collision state of one component template or CDO component. */
39
+ static TSharedPtr<FJsonValue> GetComponentCollision(const TSharedPtr<FJsonObject>& Params);
40
+
41
+ /** Per-channel responses of one named collision profile. */
42
+ static TSharedPtr<FJsonValue> ResolveCollisionProfile(const TSharedPtr<FJsonObject>& Params);
43
+ };