ue-mcp 1.2.4 → 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 (243) 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/lean-context.js +8 -3
  34. package/dist/lean-context.js.map +1 -1
  35. package/dist/locking.js +11 -2
  36. package/dist/locking.js.map +1 -1
  37. package/dist/project.d.ts +11 -0
  38. package/dist/project.js +23 -2
  39. package/dist/project.js.map +1 -1
  40. package/dist/python-gate.d.ts +95 -0
  41. package/dist/python-gate.js +175 -0
  42. package/dist/python-gate.js.map +1 -0
  43. package/dist/tool-counts.json +16 -16
  44. package/dist/tools/animation.js +288 -24
  45. package/dist/tools/animation.js.map +1 -1
  46. package/dist/tools/asset.js +79 -14
  47. package/dist/tools/asset.js.map +1 -1
  48. package/dist/tools/audio.js +59 -5
  49. package/dist/tools/audio.js.map +1 -1
  50. package/dist/tools/blueprint.js +29 -12
  51. package/dist/tools/blueprint.js.map +1 -1
  52. package/dist/tools/chooser.js +4 -1
  53. package/dist/tools/chooser.js.map +1 -1
  54. package/dist/tools/editor.js +81 -43
  55. package/dist/tools/editor.js.map +1 -1
  56. package/dist/tools/feedback.js +214 -48
  57. package/dist/tools/feedback.js.map +1 -1
  58. package/dist/tools/foliage.js +27 -1
  59. package/dist/tools/foliage.js.map +1 -1
  60. package/dist/tools/gameplay.js +38 -11
  61. package/dist/tools/gameplay.js.map +1 -1
  62. package/dist/tools/gas.js +17 -5
  63. package/dist/tools/gas.js.map +1 -1
  64. package/dist/tools/landscape.js +22 -7
  65. package/dist/tools/landscape.js.map +1 -1
  66. package/dist/tools/level.js +322 -51
  67. package/dist/tools/level.js.map +1 -1
  68. package/dist/tools/material.js +10 -4
  69. package/dist/tools/material.js.map +1 -1
  70. package/dist/tools/niagara.js +3 -2
  71. package/dist/tools/niagara.js.map +1 -1
  72. package/dist/tools/pcg.js +6 -5
  73. package/dist/tools/pcg.js.map +1 -1
  74. package/dist/tools/project.js +47 -20
  75. package/dist/tools/project.js.map +1 -1
  76. package/dist/types.d.ts +21 -0
  77. package/dist/types.js +46 -3
  78. package/dist/types.js.map +1 -1
  79. package/dist/ue-mcp.default.yml +493 -125
  80. package/package.json +2 -2
  81. package/plugin/ue_mcp_bridge/NATIVE_RUNTIME_VISIBILITY.md +53 -0
  82. package/plugin/ue_mcp_bridge/NATIVE_STATIC_MESH_USAGE_PROGRESS.md +115 -0
  83. package/plugin/ue_mcp_bridge/README_MassHandlers.md +97 -0
  84. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.cpp +14 -0
  85. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.cpp +21 -4
  86. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.h +9 -0
  87. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerJsonProperty.h +395 -69
  88. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.cpp +79 -3
  89. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.h +25 -0
  90. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +3 -3
  91. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRigSequencer.cpp +3061 -0
  92. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRetargeterAuthoring.cpp +961 -0
  93. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRigAuthoring.cpp +900 -0
  94. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Pose.cpp +769 -0
  95. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Sequence.cpp +44 -3
  96. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_SkeletalLive.cpp +217 -11
  97. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_StateMachine.cpp +551 -24
  98. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Validation.cpp +735 -0
  99. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.cpp +352 -73
  100. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.h +8 -0
  101. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkProperties.cpp +1 -1
  102. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.cpp +503 -0
  103. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.h +21 -0
  104. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkUpsert.cpp +2 -2
  105. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Enum.cpp +2 -2
  106. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.cpp +902 -0
  107. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.h +33 -0
  108. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Import.cpp +478 -134
  109. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Mesh.cpp +5 -5
  110. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.cpp +933 -0
  111. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.h +35 -0
  112. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Redirectors.cpp +478 -0
  113. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_RenderTarget.cpp +1 -1
  114. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Sockets.cpp +4 -4
  115. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +2 -2
  116. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Subobject.cpp +319 -0
  117. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_SoundCue.cpp +3 -3
  118. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.cpp +482 -35
  119. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.h +10 -0
  120. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.cpp +502 -0
  121. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.h +43 -0
  122. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Functions.cpp +89 -7
  123. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Graph.cpp +17 -51
  124. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +107 -0
  125. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Properties.cpp +10 -10
  126. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Search.cpp +648 -0
  127. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.cpp +5 -1
  128. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.cpp +252 -1
  129. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.h +10 -2
  130. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.cpp +252 -41
  131. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.h +4 -0
  132. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +250 -27
  133. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIE.cpp +303 -125
  134. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIERuntime.cpp +73 -50
  135. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_RuntimeVisibility.cpp +757 -0
  136. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.cpp +11 -2
  137. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +3 -0
  138. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers_Batch.cpp +419 -0
  139. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.cpp +39 -161
  140. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.h +66 -1
  141. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BTAuthoring.cpp +1323 -0
  142. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BehaviorTree.cpp +1211 -0
  143. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +2 -0
  144. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +60 -0
  145. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Runtime.cpp +363 -12
  146. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/HandlerEditorState.h +84 -0
  147. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +1288 -36
  148. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.h +3 -0
  149. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +41 -16
  150. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.cpp +959 -213
  151. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.h +66 -0
  152. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_BatchWrite.cpp +1571 -0
  153. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Convert.cpp +316 -0
  154. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Inspection.cpp +280 -0
  155. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection.cpp +666 -0
  156. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection_Internal.h +63 -0
  157. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Lights.cpp +43 -12
  158. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_MultiLevel.cpp +13 -47
  159. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_PostProcess.cpp +527 -0
  160. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Query.cpp +1169 -0
  161. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Refresh.cpp +723 -0
  162. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Save.cpp +325 -0
  163. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Spatial.cpp +360 -0
  164. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Trace.cpp +178 -58
  165. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Transient.cpp +337 -0
  166. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Volumes.cpp +25 -12
  167. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartition.cpp +10 -9
  168. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartitionSettings.cpp +686 -0
  169. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.cpp +467 -0
  170. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.h +22 -0
  171. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.cpp +452 -175
  172. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.h +5 -0
  173. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Build.cpp +597 -0
  174. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.cpp +17 -15
  175. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PCGHandlers.cpp +38 -168
  176. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +39 -30
  177. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +392 -78
  178. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +2 -0
  179. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers_Internal.h +83 -0
  180. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.cpp +200 -0
  181. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.h +15 -0
  182. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +19 -12
  183. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.cpp +31 -1
  184. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.cpp +307 -69
  185. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.h +84 -0
  186. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Extraction.cpp +8 -41
  187. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Properties.cpp +33 -52
  188. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/ActorSelectorTests.cpp +344 -0
  189. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationControlRigTimelineTests.cpp +60 -0
  190. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationPoseTests.cpp +115 -0
  191. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetBulkReadTests.cpp +177 -0
  192. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetDeleteGuardTests.cpp +276 -0
  193. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPathResolutionTests.cpp +243 -0
  194. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPropertyPersistTests.cpp +213 -0
  195. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetSubobjectTests.cpp +235 -0
  196. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AutomationRunnerTests.cpp +72 -0
  197. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeAuthoringTests.cpp +526 -0
  198. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeNodeTests.cpp +334 -0
  199. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BlueprintHandlerSurfaceTests.cpp +362 -0
  200. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BridgeProtocolTests.cpp +14 -0
  201. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/CollisionQueryTests.cpp +288 -0
  202. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/DataTableRowWriteTests.cpp +453 -0
  203. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/EditorFunctionCallTests.cpp +223 -0
  204. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/FoliageBatchTests.cpp +147 -0
  205. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GameThreadGateTests.cpp +82 -0
  206. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GasLiveAttributeTests.cpp +183 -0
  207. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LandscapeSampleTests.cpp +119 -0
  208. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelBatchWriteTests.cpp +176 -0
  209. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelComponentTreeInstanceCountTests.cpp +189 -0
  210. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelConvertBrushesTests.cpp +100 -0
  211. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelInstanceProjectionTests.cpp +265 -0
  212. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelPostProcessOverrideTests.cpp +258 -0
  213. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelQueryComponentsTests.cpp +195 -0
  214. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelRefreshTests.cpp +142 -0
  215. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelSaveReportTests.cpp +125 -0
  216. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelScriptHandlersTests.cpp +42 -0
  217. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelStaticMeshUsageTests.cpp +412 -0
  218. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTraceWorldScopeTests.cpp +133 -0
  219. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTransientActorTests.cpp +205 -0
  220. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelWorldPartitionSettingsTests.cpp +168 -0
  221. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTestTypes.h +51 -0
  222. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTests.cpp +379 -0
  223. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MaterialBuildTests.cpp +238 -0
  224. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshBooleanTests.cpp +170 -0
  225. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshGeometryTests.cpp +116 -0
  226. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageSaveExtensionTests.cpp +161 -0
  227. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageWriteGuardTests.cpp +253 -0
  228. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/RuntimeVisibilityTests.cpp +143 -0
  229. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerHandlerTests.cpp +660 -0
  230. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerScrubTests.cpp +50 -0
  231. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SkeletonDiffTests.cpp +685 -0
  232. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/WidgetBlueprintResolveTests.cpp +145 -0
  233. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/UE_MCP_Bridge.cpp +80 -0
  234. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerFunctionCall.h +509 -0
  235. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerQuery.h +407 -0
  236. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerUtils.h +1008 -77
  237. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/UE_MCP_Bridge.Build.cs +87 -0
  238. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/MCPEngineStatus.cpp +152 -14
  239. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/Tests/MCPEngineStatusTests.cpp +65 -0
  240. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Public/MCPEngineStatus.h +32 -1
  241. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/UE_MCP_BridgeStatus.Build.cs +2 -0
  242. package/skills/ue-mcp-animation/SKILL.md +154 -0
  243. package/skills/ue-mcp-blueprint/SKILL.md +71 -0
@@ -0,0 +1,334 @@
1
+ #if WITH_DEV_AUTOMATION_TESTS
2
+
3
+ #include "Handlers/GameplayHandlers.h"
4
+ #include "HandlerRegistry.h"
5
+ #include "Misc/AutomationTest.h"
6
+
7
+ #include "Dom/JsonObject.h"
8
+ #include "Dom/JsonValue.h"
9
+ #include "UObject/Package.h"
10
+ #include "UObject/UObjectGlobals.h"
11
+
12
+ #include "BehaviorTree/BlackboardData.h"
13
+ #include "BehaviorTree/Blackboard/BlackboardKeyType.h"
14
+ #include "BehaviorTree/BTNode.h"
15
+
16
+ namespace
17
+ {
18
+ // The BT node classes under test are resolved by path rather than included
19
+ // by header, so a build without one of them skips the case instead of
20
+ // failing to link.
21
+ UClass* MCPBTTestFindClass(const TCHAR* ClassPath)
22
+ {
23
+ return FindObject<UClass>(nullptr, ClassPath);
24
+ }
25
+
26
+ UBTNode* MCPBTTestMakeNode(const TCHAR* ClassPath)
27
+ {
28
+ UClass* Class = MCPBTTestFindClass(ClassPath);
29
+ if (!Class) return nullptr;
30
+ return NewObject<UBTNode>(GetTransientPackage(), Class);
31
+ }
32
+
33
+ FString MCPBTTestGetString(const TSharedPtr<FJsonObject>& Object, const TCHAR* Field)
34
+ {
35
+ FString Value;
36
+ if (Object.IsValid()) Object->TryGetStringField(Field, Value);
37
+ return Value;
38
+ }
39
+ }
40
+
41
+ // #887: get_behavior_tree_info walked UBlackboardData::Keys as if it were an
42
+ // array of UObject pointers. It is an array of FBlackboardEntry structs, so the
43
+ // walk read each entry's FName as a pointer and dereferenced it, and every
44
+ // blackboard with at least one key took the editor down with an access
45
+ // violation. This test builds that exact shape in memory.
46
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
47
+ FMCPBehaviorTreeBlackboardKeysTest,
48
+ "UE.MCP.Gameplay.BehaviorTree.BlackboardKeys",
49
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
50
+
51
+ bool FMCPBehaviorTreeBlackboardKeysTest::RunTest(const FString& Parameters)
52
+ {
53
+ UBlackboardData* Blackboard = NewObject<UBlackboardData>(GetTransientPackage());
54
+ TestNotNull(TEXT("blackboard was created"), Blackboard);
55
+ if (!Blackboard) return false;
56
+
57
+ UClass* ObjectKeyClass = MCPBTTestFindClass(TEXT("/Script/AIModule.BlackboardKeyType_Object"));
58
+
59
+ FBlackboardEntry Typed;
60
+ Typed.EntryName = TEXT("TargetActor");
61
+ if (ObjectKeyClass)
62
+ {
63
+ Typed.KeyType = NewObject<UBlackboardKeyType>(Blackboard, ObjectKeyClass);
64
+ }
65
+ Blackboard->Keys.Add(Typed);
66
+
67
+ // A key whose type was never picked is a real authoring state, and the
68
+ // reader has to describe it rather than dereference it.
69
+ FBlackboardEntry Untyped;
70
+ Untyped.EntryName = TEXT("PatrolIndex");
71
+ Blackboard->Keys.Add(Untyped);
72
+
73
+ const TArray<TSharedPtr<FJsonValue>> Keys = FGameplayHandlers::DescribeBlackboardKeys(Blackboard);
74
+ TestEqual(TEXT("both keys are described"), Keys.Num(), 2);
75
+ if (Keys.Num() != 2) return false;
76
+
77
+ const TSharedPtr<FJsonObject> First = Keys[0]->AsObject();
78
+ const TSharedPtr<FJsonObject> Second = Keys[1]->AsObject();
79
+ TestEqual(TEXT("first key name"), MCPBTTestGetString(First, TEXT("name")), FString(TEXT("TargetActor")));
80
+ TestEqual(TEXT("second key name"), MCPBTTestGetString(Second, TEXT("name")), FString(TEXT("PatrolIndex")));
81
+ TestEqual(TEXT("untyped key reports an empty type instead of crashing"),
82
+ MCPBTTestGetString(Second, TEXT("type")), FString());
83
+ if (ObjectKeyClass)
84
+ {
85
+ TestEqual(TEXT("typed key reports its short type name"),
86
+ MCPBTTestGetString(First, TEXT("type")), FString(TEXT("Object")));
87
+ }
88
+
89
+ // A null blackboard is an empty answer, never a dereference.
90
+ TestEqual(TEXT("null blackboard yields no keys"),
91
+ FGameplayHandlers::DescribeBlackboardKeys(nullptr).Num(), 0);
92
+ return true;
93
+ }
94
+
95
+ // #888: BTDecorator_Blackboard keeps its whole configuration in protected C++
96
+ // fields, so the graph read used to report class and name only. Every field a
97
+ // "the tree runs but the wrong branch fires" investigation needs comes back now.
98
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
99
+ FMCPBehaviorTreeDecoratorConfigTest,
100
+ "UE.MCP.Gameplay.BehaviorTree.DecoratorConfig",
101
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
102
+
103
+ bool FMCPBehaviorTreeDecoratorConfigTest::RunTest(const FString& Parameters)
104
+ {
105
+ UBTNode* Decorator = MCPBTTestMakeNode(TEXT("/Script/AIModule.BTDecorator_Blackboard"));
106
+ if (!Decorator)
107
+ {
108
+ AddInfo(TEXT("BTDecorator_Blackboard is not present in this build; skipping."));
109
+ return true;
110
+ }
111
+
112
+ // The nested write is the #919 path: a dotted address into a protected
113
+ // struct field on an owned node subobject.
114
+ FString Error;
115
+ TestTrue(TEXT("selected blackboard key is writable through a dotted path"),
116
+ FGameplayHandlers::WriteBTNodeProperty(Decorator, TEXT("BlackboardKey.SelectedKeyName"),
117
+ MakeShared<FJsonValueString>(TEXT("TargetActor")), Error));
118
+ TestEqual(TEXT("no error writing the selected key"), Error, FString());
119
+
120
+ #if WITH_EDITORONLY_DATA
121
+ // The comparison operation is authored data, so the engine declares it
122
+ // editor-only. It is the field that says whether the branch tests for
123
+ // "is set" or "is not set".
124
+ TestTrue(TEXT("basic operation is writable by enumerator name"),
125
+ FGameplayHandlers::WriteBTNodeProperty(Decorator, TEXT("BasicOperation"),
126
+ MakeShared<FJsonValueString>(TEXT("NotSet")), Error));
127
+ #endif
128
+ TestTrue(TEXT("flow abort mode is writable by enumerator name"),
129
+ FGameplayHandlers::WriteBTNodeProperty(Decorator, TEXT("FlowAbortMode"),
130
+ MakeShared<FJsonValueString>(TEXT("LowerPriority")), Error));
131
+ TestTrue(TEXT("notify observer is writable by enumerator name"),
132
+ FGameplayHandlers::WriteBTNodeProperty(Decorator, TEXT("NotifyObserver"),
133
+ MakeShared<FJsonValueString>(TEXT("ResultChange")), Error));
134
+
135
+ const TSharedPtr<FJsonObject> Described = FGameplayHandlers::DescribeBTNode(
136
+ Decorator, TEXT("Root.Children[0].Decorators[0]"), TEXT("Root.Children[0]"),
137
+ /*bIncludeProperties*/ false, /*bIncludeInherited*/ false, TSet<FString>());
138
+
139
+ TestEqual(TEXT("kind"), MCPBTTestGetString(Described, TEXT("kind")), FString(TEXT("decorator")));
140
+ TestEqual(TEXT("path"), MCPBTTestGetString(Described, TEXT("path")), FString(TEXT("Root.Children[0].Decorators[0]")));
141
+ TestEqual(TEXT("parentPath"), MCPBTTestGetString(Described, TEXT("parentPath")), FString(TEXT("Root.Children[0]")));
142
+ TestEqual(TEXT("class"), MCPBTTestGetString(Described, TEXT("class")), FString(TEXT("BTDecorator_Blackboard")));
143
+ TestTrue(TEXT("inverseCondition is reported"), Described->HasField(TEXT("inverseCondition")));
144
+ TestEqual(TEXT("flowAbortMode"), MCPBTTestGetString(Described, TEXT("flowAbortMode")), FString(TEXT("LowerPriority")));
145
+ TestEqual(TEXT("notifyObserver"), MCPBTTestGetString(Described, TEXT("notifyObserver")), FString(TEXT("ResultChange")));
146
+ #if WITH_EDITORONLY_DATA
147
+ TestEqual(TEXT("basicOperation"), MCPBTTestGetString(Described, TEXT("basicOperation")), FString(TEXT("NotSet")));
148
+ #endif
149
+
150
+ const TSharedPtr<FJsonObject>* BlackboardKey = nullptr;
151
+ TestTrue(TEXT("blackboardKey is reported"), Described->TryGetObjectField(TEXT("blackboardKey"), BlackboardKey));
152
+ if (BlackboardKey && (*BlackboardKey).IsValid())
153
+ {
154
+ TestEqual(TEXT("selectedKeyName"),
155
+ MCPBTTestGetString(*BlackboardKey, TEXT("selectedKeyName")), FString(TEXT("TargetActor")));
156
+ }
157
+
158
+ // A null node is answered, not dereferenced.
159
+ const TSharedPtr<FJsonObject> Empty = FGameplayHandlers::DescribeBTNode(
160
+ nullptr, TEXT("Root"), FString(), false, false, TSet<FString>());
161
+ TestTrue(TEXT("a null node yields an empty object"), Empty.IsValid() && Empty->Values.Num() == 0);
162
+ return true;
163
+ }
164
+
165
+ // #940: on UE 5.8 BTTask_MoveTo::FilterClass is a FValueOrBBKey_Class, so the
166
+ // class lives in DefaultValue and get_editor_property reads the field as empty.
167
+ // #889 is the same struct shape one field over: AcceptableRadius is a
168
+ // FValueOrBBKey_Float, so the number a caller sends has to reach DefaultValue
169
+ // rather than bounce off the struct's export-text importer.
170
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
171
+ FMCPBehaviorTreeMoveToFilterClassTest,
172
+ "UE.MCP.Gameplay.BehaviorTree.MoveToFilterClass",
173
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
174
+
175
+ bool FMCPBehaviorTreeMoveToFilterClassTest::RunTest(const FString& Parameters)
176
+ {
177
+ UBTNode* MoveTo = MCPBTTestMakeNode(TEXT("/Script/AIModule.BTTask_MoveTo"));
178
+ if (!MoveTo)
179
+ {
180
+ AddInfo(TEXT("BTTask_MoveTo is not present in this build; skipping."));
181
+ return true;
182
+ }
183
+
184
+ FString Error;
185
+
186
+ // A JSON number aimed at the struct lands on its DefaultValue.
187
+ TestTrue(TEXT("AcceptableRadius accepts a bare JSON number"),
188
+ FGameplayHandlers::WriteBTNodeProperty(MoveTo, TEXT("AcceptableRadius"),
189
+ MakeShared<FJsonValueNumber>(60.0), Error));
190
+ TestEqual(TEXT("no error writing AcceptableRadius"), Error, FString());
191
+
192
+ TSharedPtr<FJsonValue> Radius = FGameplayHandlers::ReadBTNodeProperty(MoveTo, TEXT("AcceptableRadius"), Error);
193
+ TestTrue(TEXT("AcceptableRadius reads back as an object"), Radius.IsValid() && Radius->Type == EJson::Object);
194
+ if (Radius.IsValid() && Radius->Type == EJson::Object)
195
+ {
196
+ double Stored = 0.0;
197
+ Radius->AsObject()->TryGetNumberField(TEXT("defaultValue"), Stored);
198
+ TestEqual(TEXT("AcceptableRadius DefaultValue"), Stored, 60.0);
199
+ }
200
+
201
+ // #919: the filtered property read names what it wants and gets that, with
202
+ // the FValueOrBBKey_* struct already unpacked.
203
+ TSet<FString> Filter;
204
+ Filter.Add(TEXT("acceptableradius"));
205
+ const TSharedPtr<FJsonObject> Filtered = FGameplayHandlers::DescribeBTNode(
206
+ MoveTo, TEXT("Root.Children[0]"), TEXT("Root"),
207
+ /*bIncludeProperties*/ true, /*bIncludeInherited*/ false, Filter);
208
+ const TSharedPtr<FJsonObject>* Properties = nullptr;
209
+ TestTrue(TEXT("a filtered read reports properties"), Filtered->TryGetObjectField(TEXT("properties"), Properties));
210
+ if (Properties && (*Properties).IsValid())
211
+ {
212
+ TestEqual(TEXT("only the named property is reported"), (*Properties)->Values.Num(), 1);
213
+ TestTrue(TEXT("the named property is the one asked for"), (*Properties)->HasField(TEXT("AcceptableRadius")));
214
+ }
215
+
216
+ // FilterClass is the same shape holding a class.
217
+ UClass* FilterClass = MCPBTTestFindClass(TEXT("/Script/NavigationSystem.RecastFilter_UseDefaultArea"));
218
+ if (!FilterClass)
219
+ {
220
+ AddInfo(TEXT("RecastFilter_UseDefaultArea is not present in this build; skipping the class half."));
221
+ return true;
222
+ }
223
+ const FString FilterClassPath = FilterClass->GetPathName();
224
+
225
+ TestTrue(TEXT("FilterClass accepts a class path"),
226
+ FGameplayHandlers::WriteBTNodeProperty(MoveTo, TEXT("FilterClass"),
227
+ MakeShared<FJsonValueString>(FilterClassPath), Error));
228
+ TestEqual(TEXT("no error writing FilterClass"), Error, FString());
229
+
230
+ TSharedPtr<FJsonValue> FilterValue = FGameplayHandlers::ReadBTNodeProperty(MoveTo, TEXT("FilterClass"), Error);
231
+ TestTrue(TEXT("FilterClass reads back as an object"), FilterValue.IsValid() && FilterValue->Type == EJson::Object);
232
+ if (FilterValue.IsValid() && FilterValue->Type == EJson::Object)
233
+ {
234
+ TestEqual(TEXT("FilterClass DefaultValue is the class that was written"),
235
+ MCPBTTestGetString(FilterValue->AsObject(), TEXT("defaultValue")), FilterClassPath);
236
+ bool bBound = true;
237
+ FilterValue->AsObject()->TryGetBoolField(TEXT("isBound"), bBound);
238
+ TestFalse(TEXT("a literal class is not a blackboard binding"), bBound);
239
+ }
240
+
241
+ // An object value writes the struct's own fields, which is how the field
242
+ // is bound to a blackboard key instead of pinned to a literal.
243
+ TSharedPtr<FJsonObject> Binding = MakeShared<FJsonObject>();
244
+ Binding->SetStringField(TEXT("Key"), TEXT("NavFilter"));
245
+ TestTrue(TEXT("FilterClass accepts a blackboard key binding"),
246
+ FGameplayHandlers::WriteBTNodeProperty(MoveTo, TEXT("FilterClass"),
247
+ MakeShared<FJsonValueObject>(Binding), Error));
248
+
249
+ FilterValue = FGameplayHandlers::ReadBTNodeProperty(MoveTo, TEXT("FilterClass"), Error);
250
+ if (FilterValue.IsValid() && FilterValue->Type == EJson::Object)
251
+ {
252
+ TestEqual(TEXT("bound key name"),
253
+ MCPBTTestGetString(FilterValue->AsObject(), TEXT("key")), FString(TEXT("NavFilter")));
254
+ bool bBound = false;
255
+ FilterValue->AsObject()->TryGetBoolField(TEXT("isBound"), bBound);
256
+ TestTrue(TEXT("a key name reads as bound"), bBound);
257
+ }
258
+
259
+ // Null clears the class without touching the binding.
260
+ TestTrue(TEXT("FilterClass accepts null to clear the class"),
261
+ FGameplayHandlers::WriteBTNodeProperty(MoveTo, TEXT("FilterClass"),
262
+ MakeShared<FJsonValueNull>(), Error));
263
+ FilterValue = FGameplayHandlers::ReadBTNodeProperty(MoveTo, TEXT("FilterClass"), Error);
264
+ if (FilterValue.IsValid() && FilterValue->Type == EJson::Object)
265
+ {
266
+ TestEqual(TEXT("cleared DefaultValue"),
267
+ MCPBTTestGetString(FilterValue->AsObject(), TEXT("defaultValueName")), FString());
268
+ }
269
+
270
+ // A property the node does not declare is a structured error, never a
271
+ // silent no-op and never a dereference.
272
+ TestFalse(TEXT("an unknown property is rejected"),
273
+ FGameplayHandlers::WriteBTNodeProperty(MoveTo, TEXT("NotAProperty"),
274
+ MakeShared<FJsonValueNumber>(1.0), Error));
275
+ TestTrue(TEXT("the rejection names the property"), Error.Contains(TEXT("NotAProperty")));
276
+
277
+ // A null node is answered, not dereferenced.
278
+ TestFalse(TEXT("a null node is rejected"),
279
+ FGameplayHandlers::WriteBTNodeProperty(nullptr, TEXT("AcceptableRadius"),
280
+ MakeShared<FJsonValueNumber>(1.0), Error));
281
+ return true;
282
+ }
283
+
284
+ // The BT actions have to be reachable by the names the TypeScript schema
285
+ // advertises, and each has to answer a call with no parameters with a
286
+ // structured error rather than a crash.
287
+ IMPLEMENT_SIMPLE_AUTOMATION_TEST(
288
+ FMCPBehaviorTreeRegistrationTest,
289
+ "UE.MCP.Gameplay.BehaviorTree.RegistrationAndPreflight",
290
+ EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
291
+
292
+ bool FMCPBehaviorTreeRegistrationTest::RunTest(const FString& Parameters)
293
+ {
294
+ FMCPHandlerRegistry Registry;
295
+ FGameplayHandlers::RegisterHandlers(Registry);
296
+
297
+ const TCHAR* Methods[] = {
298
+ TEXT("get_behavior_tree_info"),
299
+ TEXT("read_behavior_tree_graph"),
300
+ TEXT("read_bt_node_properties"),
301
+ TEXT("list_bt_tasks"),
302
+ TEXT("set_bt_node_property"),
303
+ TEXT("set_bt_task_property"),
304
+ };
305
+ for (const TCHAR* Method : Methods)
306
+ {
307
+ TestTrue(FString::Printf(TEXT("%s is registered"), Method), Registry.HasHandler(Method));
308
+ }
309
+
310
+ // Every action that needs an asset path says so, and list_bt_tasks answers
311
+ // without one because a directory sweep is its whole point.
312
+ const TCHAR* NeedAssetPath[] = {
313
+ TEXT("get_behavior_tree_info"),
314
+ TEXT("read_behavior_tree_graph"),
315
+ TEXT("read_bt_node_properties"),
316
+ TEXT("set_bt_node_property"),
317
+ TEXT("set_bt_task_property"),
318
+ };
319
+ for (const TCHAR* Method : NeedAssetPath)
320
+ {
321
+ const TSharedPtr<FJsonValue> Response = Registry.ExecuteHandler(Method, MakeShared<FJsonObject>());
322
+ TestTrue(FString::Printf(TEXT("%s returns an object"), Method),
323
+ Response.IsValid() && Response->Type == EJson::Object);
324
+ if (!Response.IsValid() || Response->Type != EJson::Object) continue;
325
+
326
+ const TSharedPtr<FJsonObject> Object = Response->AsObject();
327
+ TestFalse(FString::Printf(TEXT("%s rejects an empty call"), Method), Object->GetBoolField(TEXT("success")));
328
+ TestTrue(FString::Printf(TEXT("%s names assetPath"), Method),
329
+ Object->GetStringField(TEXT("error")).Contains(TEXT("assetPath")));
330
+ }
331
+ return true;
332
+ }
333
+
334
+ #endif