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.
- package/README.md +4 -3
- package/dist/action-class.js +56 -3
- package/dist/action-class.js.map +1 -1
- package/dist/bridge-timeouts.d.ts +64 -0
- package/dist/bridge-timeouts.js +118 -0
- package/dist/bridge-timeouts.js.map +1 -0
- package/dist/bridge.js +10 -2
- package/dist/bridge.js.map +1 -1
- package/dist/editor-control.d.ts +72 -5
- package/dist/editor-control.js +164 -140
- package/dist/editor-control.js.map +1 -1
- package/dist/editor-target.d.ts +55 -1
- package/dist/editor-target.js +107 -10
- package/dist/editor-target.js.map +1 -1
- package/dist/engine-observer.d.ts +59 -5
- package/dist/engine-observer.js +249 -29
- package/dist/engine-observer.js.map +1 -1
- package/dist/engine-root.d.ts +91 -0
- package/dist/engine-root.js +448 -0
- package/dist/engine-root.js.map +1 -0
- package/dist/epic-enrich.js +16 -1
- package/dist/epic-enrich.js.map +1 -1
- package/dist/feedback-cli.js +4 -0
- package/dist/feedback-cli.js.map +1 -1
- package/dist/feedback-deferred.d.ts +9 -0
- package/dist/feedback-deferred.js +2 -0
- package/dist/feedback-deferred.js.map +1 -1
- package/dist/feedback-fallback.d.ts +99 -0
- package/dist/feedback-fallback.js +173 -0
- package/dist/feedback-fallback.js.map +1 -0
- package/dist/flow/write-methods.js +20 -0
- package/dist/flow/write-methods.js.map +1 -1
- package/dist/index.js +41 -2
- package/dist/index.js.map +1 -1
- package/dist/lean-context.js +8 -3
- package/dist/lean-context.js.map +1 -1
- package/dist/locking.js +11 -2
- package/dist/locking.js.map +1 -1
- package/dist/plugin/loader.d.ts +4 -0
- package/dist/plugin/loader.js +22 -8
- package/dist/plugin/loader.js.map +1 -1
- package/dist/plugin/manifest.d.ts +72 -52
- package/dist/plugin/manifest.js +118 -21
- package/dist/plugin/manifest.js.map +1 -1
- package/dist/plugin-cli.js +16 -3
- package/dist/plugin-cli.js.map +1 -1
- package/dist/project.d.ts +11 -0
- package/dist/project.js +23 -2
- package/dist/project.js.map +1 -1
- package/dist/python-gate.d.ts +95 -0
- package/dist/python-gate.js +175 -0
- package/dist/python-gate.js.map +1 -0
- package/dist/tool-counts.json +16 -16
- package/dist/tools/animation.js +288 -24
- package/dist/tools/animation.js.map +1 -1
- package/dist/tools/asset.js +79 -14
- package/dist/tools/asset.js.map +1 -1
- package/dist/tools/audio.js +59 -5
- package/dist/tools/audio.js.map +1 -1
- package/dist/tools/blueprint.js +29 -12
- package/dist/tools/blueprint.js.map +1 -1
- package/dist/tools/chooser.js +4 -1
- package/dist/tools/chooser.js.map +1 -1
- package/dist/tools/editor.js +81 -43
- package/dist/tools/editor.js.map +1 -1
- package/dist/tools/feedback.js +214 -48
- package/dist/tools/feedback.js.map +1 -1
- package/dist/tools/foliage.js +27 -1
- package/dist/tools/foliage.js.map +1 -1
- package/dist/tools/gameplay.js +38 -11
- package/dist/tools/gameplay.js.map +1 -1
- package/dist/tools/gas.js +17 -5
- package/dist/tools/gas.js.map +1 -1
- package/dist/tools/landscape.js +22 -7
- package/dist/tools/landscape.js.map +1 -1
- package/dist/tools/level.js +322 -51
- package/dist/tools/level.js.map +1 -1
- package/dist/tools/material.js +10 -4
- package/dist/tools/material.js.map +1 -1
- package/dist/tools/niagara.js +3 -2
- package/dist/tools/niagara.js.map +1 -1
- package/dist/tools/pcg.js +6 -5
- package/dist/tools/pcg.js.map +1 -1
- package/dist/tools/plugins.js +2 -0
- package/dist/tools/plugins.js.map +1 -1
- package/dist/tools/project.js +47 -20
- package/dist/tools/project.js.map +1 -1
- package/dist/types.d.ts +24 -0
- package/dist/types.js +46 -3
- package/dist/types.js.map +1 -1
- package/dist/ue-mcp.default.yml +493 -125
- package/package.json +2 -2
- package/plugin/ue_mcp_bridge/NATIVE_RUNTIME_VISIBILITY.md +53 -0
- package/plugin/ue_mcp_bridge/NATIVE_STATIC_MESH_USAGE_PROGRESS.md +115 -0
- package/plugin/ue_mcp_bridge/README_MassHandlers.md +97 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.cpp +14 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.cpp +21 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.h +9 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerJsonProperty.h +395 -69
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.cpp +79 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.h +25 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +3 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRigSequencer.cpp +3061 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRetargeterAuthoring.cpp +961 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRigAuthoring.cpp +900 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Pose.cpp +769 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Sequence.cpp +44 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_SkeletalLive.cpp +217 -11
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_StateMachine.cpp +551 -24
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Validation.cpp +735 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.cpp +352 -73
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.h +8 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkProperties.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.cpp +503 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.h +21 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkUpsert.cpp +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Enum.cpp +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.cpp +902 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.h +33 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Import.cpp +478 -134
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Mesh.cpp +5 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.cpp +933 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.h +35 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Redirectors.cpp +478 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_RenderTarget.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Sockets.cpp +4 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Subobject.cpp +319 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_SoundCue.cpp +3 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.cpp +482 -35
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.h +10 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.cpp +502 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.h +43 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Functions.cpp +89 -7
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Graph.cpp +17 -51
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +107 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Properties.cpp +10 -10
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Search.cpp +648 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.cpp +5 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.cpp +252 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.h +10 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.cpp +252 -41
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.h +4 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +250 -27
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIE.cpp +303 -125
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIERuntime.cpp +73 -50
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_RuntimeVisibility.cpp +757 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.cpp +11 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +3 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers_Batch.cpp +419 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.cpp +39 -161
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.h +66 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BTAuthoring.cpp +1323 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BehaviorTree.cpp +1211 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +2 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +60 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Runtime.cpp +363 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/HandlerEditorState.h +84 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +1288 -36
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.h +3 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +41 -16
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.cpp +959 -213
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.h +66 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_BatchWrite.cpp +1571 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Convert.cpp +316 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Inspection.cpp +280 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection.cpp +666 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection_Internal.h +63 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Lights.cpp +43 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_MultiLevel.cpp +13 -47
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_PostProcess.cpp +527 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Query.cpp +1169 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Refresh.cpp +723 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Save.cpp +325 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Spatial.cpp +360 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Trace.cpp +178 -58
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Transient.cpp +337 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Volumes.cpp +25 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartition.cpp +10 -9
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartitionSettings.cpp +686 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.cpp +467 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.h +22 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.cpp +452 -175
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.h +5 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Build.cpp +597 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.cpp +17 -15
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PCGHandlers.cpp +38 -168
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +39 -30
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +392 -78
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +2 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers_Internal.h +83 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.cpp +200 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.h +15 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +19 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.cpp +31 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.cpp +307 -69
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.h +84 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Extraction.cpp +8 -41
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Properties.cpp +33 -52
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/ActorSelectorTests.cpp +344 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationControlRigTimelineTests.cpp +60 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationPoseTests.cpp +115 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetBulkReadTests.cpp +177 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetDeleteGuardTests.cpp +276 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPathResolutionTests.cpp +243 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPropertyPersistTests.cpp +213 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetSubobjectTests.cpp +235 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AutomationRunnerTests.cpp +72 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeAuthoringTests.cpp +526 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeNodeTests.cpp +334 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BlueprintHandlerSurfaceTests.cpp +362 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BridgeProtocolTests.cpp +14 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/CollisionQueryTests.cpp +288 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/DataTableRowWriteTests.cpp +453 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/EditorFunctionCallTests.cpp +223 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/FoliageBatchTests.cpp +147 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GameThreadGateTests.cpp +82 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GasLiveAttributeTests.cpp +183 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LandscapeSampleTests.cpp +119 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelBatchWriteTests.cpp +176 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelComponentTreeInstanceCountTests.cpp +189 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelConvertBrushesTests.cpp +100 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelInstanceProjectionTests.cpp +265 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelPostProcessOverrideTests.cpp +258 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelQueryComponentsTests.cpp +195 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelRefreshTests.cpp +142 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelSaveReportTests.cpp +125 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelScriptHandlersTests.cpp +42 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelStaticMeshUsageTests.cpp +412 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTraceWorldScopeTests.cpp +133 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTransientActorTests.cpp +205 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelWorldPartitionSettingsTests.cpp +168 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTestTypes.h +51 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTests.cpp +379 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MaterialBuildTests.cpp +238 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshBooleanTests.cpp +170 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshGeometryTests.cpp +116 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageSaveExtensionTests.cpp +161 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageWriteGuardTests.cpp +253 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/RuntimeVisibilityTests.cpp +143 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerHandlerTests.cpp +660 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerScrubTests.cpp +50 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SkeletonDiffTests.cpp +685 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/WidgetBlueprintResolveTests.cpp +145 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/UE_MCP_Bridge.cpp +80 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerFunctionCall.h +509 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerQuery.h +407 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerUtils.h +1008 -77
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/UE_MCP_Bridge.Build.cs +87 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/MCPEngineStatus.cpp +152 -14
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/Tests/MCPEngineStatusTests.cpp +65 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Public/MCPEngineStatus.h +32 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/UE_MCP_BridgeStatus.Build.cs +2 -0
- package/skills/ue-mcp-animation/SKILL.md +154 -0
- package/skills/ue-mcp-blueprint/SKILL.md +71 -0
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeAuthoringTests.cpp
ADDED
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
#if WITH_DEV_AUTOMATION_TESTS
|
|
2
|
+
|
|
3
|
+
// The engine contracts that BehaviorTree graph authoring rests on (#889, #947).
|
|
4
|
+
//
|
|
5
|
+
// add_bt_node, move_bt_node and remove_bt_node need a real asset path, so these
|
|
6
|
+
// tests do not call the handlers. They build the same BehaviorTree + graph pair
|
|
7
|
+
// in memory and drive the same engine calls in the same order, which is what
|
|
8
|
+
// actually needs pinning: every one of these behaviours is undocumented, and a
|
|
9
|
+
// silent change to any of them would leave the handlers compiling and producing
|
|
10
|
+
// trees that do not run.
|
|
11
|
+
//
|
|
12
|
+
// The contract that matters most is the ordering one. Child execution order is
|
|
13
|
+
// not stored anywhere: BTGraphHelpers::CreateChildren sorts each output pin's
|
|
14
|
+
// links by node X position on every compile, so a composite's child order IS
|
|
15
|
+
// the graph layout. Reordering a Selector's branches is therefore a position
|
|
16
|
+
// rewrite, and if that ever stops being true, reordering silently becomes a
|
|
17
|
+
// no-op rather than failing. FMCPBTAuthoringChildOrderTest is what would catch
|
|
18
|
+
// it.
|
|
19
|
+
|
|
20
|
+
#include "Handlers/GameplayHandlers.h"
|
|
21
|
+
#include "Misc/AutomationTest.h"
|
|
22
|
+
|
|
23
|
+
#include "Dom/JsonObject.h"
|
|
24
|
+
#include "Dom/JsonValue.h"
|
|
25
|
+
#include "UObject/Package.h"
|
|
26
|
+
#include "UObject/UObjectGlobals.h"
|
|
27
|
+
|
|
28
|
+
#include "EdGraph/EdGraph.h"
|
|
29
|
+
#include "EdGraph/EdGraphNode.h"
|
|
30
|
+
#include "EdGraph/EdGraphPin.h"
|
|
31
|
+
#include "EdGraph/EdGraphSchema.h"
|
|
32
|
+
#include "Kismet2/BlueprintEditorUtils.h"
|
|
33
|
+
|
|
34
|
+
#include "BehaviorTree/BehaviorTree.h"
|
|
35
|
+
#include "BehaviorTree/BehaviorTreeTypes.h"
|
|
36
|
+
#include "BehaviorTree/BlackboardData.h"
|
|
37
|
+
#include "BehaviorTree/Blackboard/BlackboardKeyType.h"
|
|
38
|
+
#include "BehaviorTree/BTCompositeNode.h"
|
|
39
|
+
#include "BehaviorTree/BTDecorator.h"
|
|
40
|
+
#include "BehaviorTree/BTNode.h"
|
|
41
|
+
#include "BehaviorTree/BTTaskNode.h"
|
|
42
|
+
|
|
43
|
+
#include "AIGraphTypes.h"
|
|
44
|
+
#include "BehaviorTreeGraph.h"
|
|
45
|
+
#include "BehaviorTreeGraphNode.h"
|
|
46
|
+
#include "BehaviorTreeGraphNode_Composite.h"
|
|
47
|
+
#include "BehaviorTreeGraphNode_Decorator.h"
|
|
48
|
+
#include "BehaviorTreeGraphNode_Root.h"
|
|
49
|
+
#include "BehaviorTreeGraphNode_Task.h"
|
|
50
|
+
#include "EdGraphSchema_BehaviorTree.h"
|
|
51
|
+
|
|
52
|
+
namespace
|
|
53
|
+
{
|
|
54
|
+
// Node classes are resolved by path rather than pulled in by header, so a
|
|
55
|
+
// build missing one of them skips the case instead of failing to link.
|
|
56
|
+
UClass* MCPBTAuthTestClass(const TCHAR* ClassPath)
|
|
57
|
+
{
|
|
58
|
+
return FindObject<UClass>(nullptr, ClassPath);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// A BehaviorTree with a freshly seeded editor graph, built exactly the way
|
|
62
|
+
// the authoring handlers seed one for a tree that has never been opened in
|
|
63
|
+
// the BehaviorTree editor.
|
|
64
|
+
struct FMCPBTAuthTestTree
|
|
65
|
+
{
|
|
66
|
+
UBehaviorTree* Tree = nullptr;
|
|
67
|
+
UBehaviorTreeGraph* Graph = nullptr;
|
|
68
|
+
UBehaviorTreeGraphNode_Root* Root = nullptr;
|
|
69
|
+
|
|
70
|
+
bool IsValid() const { return Tree && Graph && Root; }
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
FMCPBTAuthTestTree MCPBTAuthTestMakeTree()
|
|
74
|
+
{
|
|
75
|
+
FMCPBTAuthTestTree Out;
|
|
76
|
+
Out.Tree = NewObject<UBehaviorTree>(GetTransientPackage());
|
|
77
|
+
if (!Out.Tree) return Out;
|
|
78
|
+
|
|
79
|
+
Out.Tree->BTGraph = FBlueprintEditorUtils::CreateNewGraph(
|
|
80
|
+
Out.Tree,
|
|
81
|
+
FName(TEXT("Behavior Tree")),
|
|
82
|
+
UBehaviorTreeGraph::StaticClass(),
|
|
83
|
+
UEdGraphSchema_BehaviorTree::StaticClass());
|
|
84
|
+
|
|
85
|
+
Out.Graph = Cast<UBehaviorTreeGraph>(Out.Tree->BTGraph);
|
|
86
|
+
if (!Out.Graph) return Out;
|
|
87
|
+
|
|
88
|
+
if (const UEdGraphSchema* Schema = Out.Graph->GetSchema())
|
|
89
|
+
{
|
|
90
|
+
Schema->CreateDefaultNodesForGraph(*Out.Graph);
|
|
91
|
+
}
|
|
92
|
+
Out.Graph->OnCreated();
|
|
93
|
+
|
|
94
|
+
for (UEdGraphNode* Node : Out.Graph->Nodes)
|
|
95
|
+
{
|
|
96
|
+
if (UBehaviorTreeGraphNode_Root* Root = Cast<UBehaviorTreeGraphNode_Root>(Node))
|
|
97
|
+
{
|
|
98
|
+
Out.Root = Root;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return Out;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Place a graph node carrying RuntimeClass, the way add_bt_node does:
|
|
106
|
+
// ClassData first, then Finalize, which runs PostPlacedNewNode and spawns
|
|
107
|
+
// the UBTNode instance under the asset.
|
|
108
|
+
UBehaviorTreeGraphNode* MCPBTAuthTestPlace(
|
|
109
|
+
UBehaviorTreeGraph* Graph, UClass* GraphNodeClass, UClass* RuntimeClass, int32 PosX, int32 PosY)
|
|
110
|
+
{
|
|
111
|
+
if (!Graph || !GraphNodeClass || !RuntimeClass) return nullptr;
|
|
112
|
+
|
|
113
|
+
UBehaviorTreeGraphNode* Created = nullptr;
|
|
114
|
+
{
|
|
115
|
+
FGraphNodeCreator<UBehaviorTreeGraphNode> Creator(*Graph);
|
|
116
|
+
Created = Creator.CreateNode(/*bSelectNewNode*/ false, GraphNodeClass);
|
|
117
|
+
if (Created)
|
|
118
|
+
{
|
|
119
|
+
Created->ClassData = FGraphNodeClassData(RuntimeClass, FString());
|
|
120
|
+
}
|
|
121
|
+
Creator.Finalize();
|
|
122
|
+
}
|
|
123
|
+
if (Created)
|
|
124
|
+
{
|
|
125
|
+
Created->NodePosX = PosX;
|
|
126
|
+
Created->NodePosY = PosY;
|
|
127
|
+
}
|
|
128
|
+
return Created;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
bool MCPBTAuthTestLink(UBehaviorTreeGraph* Graph, UBehaviorTreeGraphNode* Parent, UBehaviorTreeGraphNode* Child)
|
|
132
|
+
{
|
|
133
|
+
if (!Graph || !Parent || !Child) return false;
|
|
134
|
+
const UEdGraphSchema* Schema = Graph->GetSchema();
|
|
135
|
+
UEdGraphPin* Out = Parent->GetOutputPin(0);
|
|
136
|
+
UEdGraphPin* In = Child->GetInputPin(0);
|
|
137
|
+
if (!Schema || !Out || !In) return false;
|
|
138
|
+
return Schema->TryCreateConnection(Out, In);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// The whole authoring path in one pass: seed a graph, place a composite under
|
|
143
|
+
// the root, place two tasks under the composite, compile, then prove the
|
|
144
|
+
// compiled runtime tree is the one that was drawn.
|
|
145
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
146
|
+
FMCPBTAuthoringCompileTest,
|
|
147
|
+
"UE.MCP.Gameplay.BehaviorTree.AuthoringCompile",
|
|
148
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
149
|
+
|
|
150
|
+
bool FMCPBTAuthoringCompileTest::RunTest(const FString& Parameters)
|
|
151
|
+
{
|
|
152
|
+
UClass* SelectorClass = MCPBTAuthTestClass(TEXT("/Script/AIModule.BTComposite_Selector"));
|
|
153
|
+
UClass* WaitClass = MCPBTAuthTestClass(TEXT("/Script/AIModule.BTTask_Wait"));
|
|
154
|
+
if (!SelectorClass || !WaitClass)
|
|
155
|
+
{
|
|
156
|
+
AddInfo(TEXT("BTComposite_Selector or BTTask_Wait is not present in this build; skipping."));
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
FMCPBTAuthTestTree Fixture = MCPBTAuthTestMakeTree();
|
|
161
|
+
TestTrue(TEXT("a BehaviorTree graph can be seeded with its root node"), Fixture.IsValid());
|
|
162
|
+
if (!Fixture.IsValid()) return false;
|
|
163
|
+
|
|
164
|
+
// The seeded graph compiles to an empty tree, which is the state a caller
|
|
165
|
+
// starts from after gameplay(create_behavior_tree).
|
|
166
|
+
Fixture.Graph->UpdateAsset();
|
|
167
|
+
TestNull(TEXT("a graph with only a root compiles to no runtime root"), Fixture.Tree->RootNode.Get());
|
|
168
|
+
|
|
169
|
+
UBehaviorTreeGraphNode* Selector = MCPBTAuthTestPlace(
|
|
170
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Composite::StaticClass(), SelectorClass, 0, 200);
|
|
171
|
+
TestNotNull(TEXT("the composite graph node was placed"), Selector);
|
|
172
|
+
if (!Selector) return false;
|
|
173
|
+
|
|
174
|
+
// PostPlacedNewNode is what turns ClassData into a runtime node instance
|
|
175
|
+
// owned by the asset. Without it every later step operates on nothing.
|
|
176
|
+
TestNotNull(TEXT("placing the node spawned its runtime instance"), Selector->NodeInstance.Get());
|
|
177
|
+
TestTrue(TEXT("the instance is owned by the BehaviorTree asset"),
|
|
178
|
+
Selector->NodeInstance && Selector->NodeInstance->GetOuter() == Fixture.Tree);
|
|
179
|
+
|
|
180
|
+
TestTrue(TEXT("the schema links the composite under the root"),
|
|
181
|
+
MCPBTAuthTestLink(Fixture.Graph, Fixture.Root, Selector));
|
|
182
|
+
|
|
183
|
+
UBehaviorTreeGraphNode* Left = MCPBTAuthTestPlace(
|
|
184
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Task::StaticClass(), WaitClass, -300, 400);
|
|
185
|
+
UBehaviorTreeGraphNode* Right = MCPBTAuthTestPlace(
|
|
186
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Task::StaticClass(), WaitClass, 300, 400);
|
|
187
|
+
TestTrue(TEXT("both task nodes were placed"), Left != nullptr && Right != nullptr);
|
|
188
|
+
if (!Left || !Right) return false;
|
|
189
|
+
|
|
190
|
+
TestTrue(TEXT("the first task links under the composite"), MCPBTAuthTestLink(Fixture.Graph, Selector, Left));
|
|
191
|
+
TestTrue(TEXT("the second task links under the composite"), MCPBTAuthTestLink(Fixture.Graph, Selector, Right));
|
|
192
|
+
|
|
193
|
+
// A task cannot sit directly under the root: the root's output pin is
|
|
194
|
+
// declared SingleComposite. The schema is what enforces this, which is why
|
|
195
|
+
// add_bt_node routes every link through it rather than writing pins.
|
|
196
|
+
UBehaviorTreeGraphNode* Stray = MCPBTAuthTestPlace(
|
|
197
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Task::StaticClass(), WaitClass, 900, 400);
|
|
198
|
+
if (Stray)
|
|
199
|
+
{
|
|
200
|
+
TestFalse(TEXT("the schema refuses a task directly under the root"),
|
|
201
|
+
MCPBTAuthTestLink(Fixture.Graph, Fixture.Root, Stray));
|
|
202
|
+
Stray->DestroyNode();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
Fixture.Graph->UpdateAsset();
|
|
206
|
+
|
|
207
|
+
UBTCompositeNode* RuntimeRoot = Fixture.Tree->RootNode.Get();
|
|
208
|
+
TestNotNull(TEXT("the graph compiled into a runtime root"), RuntimeRoot);
|
|
209
|
+
if (!RuntimeRoot) return false;
|
|
210
|
+
TestTrue(TEXT("the runtime root is the composite that was placed"),
|
|
211
|
+
static_cast<UObject*>(RuntimeRoot) == Selector->NodeInstance.Get());
|
|
212
|
+
TestEqual(TEXT("both tasks compiled in as children"), RuntimeRoot->Children.Num(), 2);
|
|
213
|
+
|
|
214
|
+
// A compiled node carries a real execution index. This is the step that
|
|
215
|
+
// reflection alone can never reach: a UBTNode spawned by script keeps
|
|
216
|
+
// MAX_uint16 here and the tree refuses to run.
|
|
217
|
+
TestTrue(TEXT("the runtime root has a real execution index"),
|
|
218
|
+
RuntimeRoot->GetExecutionIndex() != MAX_uint16);
|
|
219
|
+
|
|
220
|
+
// The addresses the read surface reports, derived from the compiled tree.
|
|
221
|
+
TMap<UBTNode*, FString> Addresses;
|
|
222
|
+
FGameplayHandlers::MapBTNodeAddresses(Fixture.Tree, Addresses);
|
|
223
|
+
const FString* RootAddress = Addresses.Find(RuntimeRoot);
|
|
224
|
+
TestTrue(TEXT("the compiled root has an address"), RootAddress != nullptr);
|
|
225
|
+
if (RootAddress) TestEqual(TEXT("the compiled root addresses as Root"), *RootAddress, FString(TEXT("Root")));
|
|
226
|
+
|
|
227
|
+
if (RuntimeRoot->Children.Num() == 2)
|
|
228
|
+
{
|
|
229
|
+
const FString* FirstChild = Addresses.Find(Cast<UBTNode>(RuntimeRoot->Children[0].ChildTask.Get()));
|
|
230
|
+
TestTrue(TEXT("the first child has an address"), FirstChild != nullptr);
|
|
231
|
+
if (FirstChild)
|
|
232
|
+
{
|
|
233
|
+
TestEqual(TEXT("the first child addresses as Root.Children[0]"),
|
|
234
|
+
*FirstChild, FString(TEXT("Root.Children[0]")));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Child execution order is the graph's X layout, re-derived on every compile.
|
|
241
|
+
// This is the contract move_bt_node's reorder depends on, and the one that
|
|
242
|
+
// would break silently.
|
|
243
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
244
|
+
FMCPBTAuthoringChildOrderTest,
|
|
245
|
+
"UE.MCP.Gameplay.BehaviorTree.AuthoringChildOrder",
|
|
246
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
247
|
+
|
|
248
|
+
bool FMCPBTAuthoringChildOrderTest::RunTest(const FString& Parameters)
|
|
249
|
+
{
|
|
250
|
+
UClass* SequenceClass = MCPBTAuthTestClass(TEXT("/Script/AIModule.BTComposite_Sequence"));
|
|
251
|
+
UClass* WaitClass = MCPBTAuthTestClass(TEXT("/Script/AIModule.BTTask_Wait"));
|
|
252
|
+
if (!SequenceClass || !WaitClass)
|
|
253
|
+
{
|
|
254
|
+
AddInfo(TEXT("BTComposite_Sequence or BTTask_Wait is not present in this build; skipping."));
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
FMCPBTAuthTestTree Fixture = MCPBTAuthTestMakeTree();
|
|
259
|
+
if (!Fixture.IsValid())
|
|
260
|
+
{
|
|
261
|
+
AddError(TEXT("could not seed a BehaviorTree graph"));
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
UBehaviorTreeGraphNode* Sequence = MCPBTAuthTestPlace(
|
|
266
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Composite::StaticClass(), SequenceClass, 0, 200);
|
|
267
|
+
UBehaviorTreeGraphNode* First = MCPBTAuthTestPlace(
|
|
268
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Task::StaticClass(), WaitClass, -300, 400);
|
|
269
|
+
UBehaviorTreeGraphNode* Second = MCPBTAuthTestPlace(
|
|
270
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Task::StaticClass(), WaitClass, 300, 400);
|
|
271
|
+
if (!Sequence || !First || !Second)
|
|
272
|
+
{
|
|
273
|
+
AddError(TEXT("could not place the nodes under test"));
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
MCPBTAuthTestLink(Fixture.Graph, Fixture.Root, Sequence);
|
|
278
|
+
MCPBTAuthTestLink(Fixture.Graph, Sequence, First);
|
|
279
|
+
MCPBTAuthTestLink(Fixture.Graph, Sequence, Second);
|
|
280
|
+
Fixture.Graph->UpdateAsset();
|
|
281
|
+
|
|
282
|
+
UBTCompositeNode* RuntimeRoot = Fixture.Tree->RootNode.Get();
|
|
283
|
+
if (!RuntimeRoot || RuntimeRoot->Children.Num() != 2)
|
|
284
|
+
{
|
|
285
|
+
AddError(TEXT("the sequence did not compile with two children"));
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
TestTrue(TEXT("the leftmost node compiles as child 0"),
|
|
290
|
+
static_cast<UObject*>(RuntimeRoot->Children[0].ChildTask.Get()) == First->NodeInstance.Get());
|
|
291
|
+
TestTrue(TEXT("the rightmost node compiles as child 1"),
|
|
292
|
+
static_cast<UObject*>(RuntimeRoot->Children[1].ChildTask.Get()) == Second->NodeInstance.Get());
|
|
293
|
+
|
|
294
|
+
// Swap the positions and nothing else. If ordering were held in the link
|
|
295
|
+
// array, or anywhere but the layout, this recompile would not move.
|
|
296
|
+
const int32 FirstX = First->NodePosX;
|
|
297
|
+
First->NodePosX = Second->NodePosX;
|
|
298
|
+
Second->NodePosX = FirstX;
|
|
299
|
+
Fixture.Graph->UpdateAsset();
|
|
300
|
+
|
|
301
|
+
RuntimeRoot = Fixture.Tree->RootNode.Get();
|
|
302
|
+
if (!RuntimeRoot || RuntimeRoot->Children.Num() != 2)
|
|
303
|
+
{
|
|
304
|
+
AddError(TEXT("the sequence lost its children on recompile"));
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
TestTrue(TEXT("swapping X positions swaps the execution order"),
|
|
309
|
+
static_cast<UObject*>(RuntimeRoot->Children[0].ChildTask.Get()) == Second->NodeInstance.Get());
|
|
310
|
+
TestTrue(TEXT("and the former first child now runs second"),
|
|
311
|
+
static_cast<UObject*>(RuntimeRoot->Children[1].ChildTask.Get()) == First->NodeInstance.Get());
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Reparenting: breaking a child's input link and relinking it under a different
|
|
316
|
+
// composite moves the whole branch, which is move_bt_node's reconnect path.
|
|
317
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
318
|
+
FMCPBTAuthoringReparentTest,
|
|
319
|
+
"UE.MCP.Gameplay.BehaviorTree.AuthoringReparent",
|
|
320
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
321
|
+
|
|
322
|
+
bool FMCPBTAuthoringReparentTest::RunTest(const FString& Parameters)
|
|
323
|
+
{
|
|
324
|
+
UClass* SelectorClass = MCPBTAuthTestClass(TEXT("/Script/AIModule.BTComposite_Selector"));
|
|
325
|
+
UClass* SequenceClass = MCPBTAuthTestClass(TEXT("/Script/AIModule.BTComposite_Sequence"));
|
|
326
|
+
UClass* WaitClass = MCPBTAuthTestClass(TEXT("/Script/AIModule.BTTask_Wait"));
|
|
327
|
+
if (!SelectorClass || !SequenceClass || !WaitClass)
|
|
328
|
+
{
|
|
329
|
+
AddInfo(TEXT("the composite or task classes under test are absent from this build; skipping."));
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
FMCPBTAuthTestTree Fixture = MCPBTAuthTestMakeTree();
|
|
334
|
+
if (!Fixture.IsValid())
|
|
335
|
+
{
|
|
336
|
+
AddError(TEXT("could not seed a BehaviorTree graph"));
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
UBehaviorTreeGraphNode* Selector = MCPBTAuthTestPlace(
|
|
341
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Composite::StaticClass(), SelectorClass, 0, 200);
|
|
342
|
+
UBehaviorTreeGraphNode* Sequence = MCPBTAuthTestPlace(
|
|
343
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Composite::StaticClass(), SequenceClass, -300, 400);
|
|
344
|
+
UBehaviorTreeGraphNode* Task = MCPBTAuthTestPlace(
|
|
345
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Task::StaticClass(), WaitClass, 300, 400);
|
|
346
|
+
if (!Selector || !Sequence || !Task)
|
|
347
|
+
{
|
|
348
|
+
AddError(TEXT("could not place the nodes under test"));
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
MCPBTAuthTestLink(Fixture.Graph, Fixture.Root, Selector);
|
|
353
|
+
MCPBTAuthTestLink(Fixture.Graph, Selector, Sequence);
|
|
354
|
+
MCPBTAuthTestLink(Fixture.Graph, Selector, Task);
|
|
355
|
+
Fixture.Graph->UpdateAsset();
|
|
356
|
+
|
|
357
|
+
UBTCompositeNode* RuntimeRoot = Fixture.Tree->RootNode.Get();
|
|
358
|
+
TestEqual(TEXT("the selector starts with two children"), RuntimeRoot ? RuntimeRoot->Children.Num() : 0, 2);
|
|
359
|
+
|
|
360
|
+
// Move the task under the sequence. The old link has to go first: the
|
|
361
|
+
// child's input pin holds a single connection, and the compiled child list
|
|
362
|
+
// is only correct once it has.
|
|
363
|
+
if (UEdGraphPin* TaskIn = Task->GetInputPin(0))
|
|
364
|
+
{
|
|
365
|
+
TaskIn->BreakAllPinLinks(true);
|
|
366
|
+
}
|
|
367
|
+
Task->NodePosX = -300;
|
|
368
|
+
Task->NodePosY = 600;
|
|
369
|
+
TestTrue(TEXT("the task relinks under the sequence"), MCPBTAuthTestLink(Fixture.Graph, Sequence, Task));
|
|
370
|
+
Fixture.Graph->UpdateAsset();
|
|
371
|
+
|
|
372
|
+
RuntimeRoot = Fixture.Tree->RootNode.Get();
|
|
373
|
+
if (!RuntimeRoot)
|
|
374
|
+
{
|
|
375
|
+
AddError(TEXT("the tree lost its root on recompile"));
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
TestEqual(TEXT("the selector is down to one child"), RuntimeRoot->Children.Num(), 1);
|
|
379
|
+
if (RuntimeRoot->Children.Num() != 1) return false;
|
|
380
|
+
|
|
381
|
+
UBTCompositeNode* RuntimeSequence = RuntimeRoot->Children[0].ChildComposite.Get();
|
|
382
|
+
TestTrue(TEXT("that child is the sequence"),
|
|
383
|
+
static_cast<UObject*>(RuntimeSequence) == Sequence->NodeInstance.Get());
|
|
384
|
+
if (!RuntimeSequence) return false;
|
|
385
|
+
TestEqual(TEXT("the sequence picked up the task"), RuntimeSequence->Children.Num(), 1);
|
|
386
|
+
if (RuntimeSequence->Children.Num() == 1)
|
|
387
|
+
{
|
|
388
|
+
TestTrue(TEXT("and it is the task that was moved"),
|
|
389
|
+
static_cast<UObject*>(RuntimeSequence->Children[0].ChildTask.Get()) == Task->NodeInstance.Get());
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Addresses follow the move, which is what lets a caller hand a guid to the
|
|
393
|
+
// authoring calls and the same node's address to the read calls.
|
|
394
|
+
TMap<UBTNode*, FString> Addresses;
|
|
395
|
+
FGameplayHandlers::MapBTNodeAddresses(Fixture.Tree, Addresses);
|
|
396
|
+
if (const FString* TaskAddress = Addresses.Find(Cast<UBTNode>(Task->NodeInstance.Get())))
|
|
397
|
+
{
|
|
398
|
+
TestEqual(TEXT("the moved task readdresses under the sequence"),
|
|
399
|
+
*TaskAddress, FString(TEXT("Root.Children[0].Children[0]")));
|
|
400
|
+
}
|
|
401
|
+
else
|
|
402
|
+
{
|
|
403
|
+
AddError(TEXT("the moved task has no address in the compiled tree"));
|
|
404
|
+
}
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Decorators are subnodes, not children. AddSubNode is what puts one on a node,
|
|
409
|
+
// and the compiler reads it off the owner's Decorators array into the parent
|
|
410
|
+
// composite's child entry. Linking a decorator as a child instead would compile
|
|
411
|
+
// to nothing at all.
|
|
412
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
413
|
+
FMCPBTAuthoringSubNodeTest,
|
|
414
|
+
"UE.MCP.Gameplay.BehaviorTree.AuthoringSubNode",
|
|
415
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
416
|
+
|
|
417
|
+
bool FMCPBTAuthoringSubNodeTest::RunTest(const FString& Parameters)
|
|
418
|
+
{
|
|
419
|
+
UClass* SelectorClass = MCPBTAuthTestClass(TEXT("/Script/AIModule.BTComposite_Selector"));
|
|
420
|
+
UClass* WaitClass = MCPBTAuthTestClass(TEXT("/Script/AIModule.BTTask_Wait"));
|
|
421
|
+
UClass* DecoratorClass = MCPBTAuthTestClass(TEXT("/Script/AIModule.BTDecorator_Blackboard"));
|
|
422
|
+
UClass* BoolKeyClass = MCPBTAuthTestClass(TEXT("/Script/AIModule.BlackboardKeyType_Bool"));
|
|
423
|
+
if (!SelectorClass || !WaitClass || !DecoratorClass)
|
|
424
|
+
{
|
|
425
|
+
AddInfo(TEXT("the composite, task or decorator classes under test are absent from this build; skipping."));
|
|
426
|
+
return true;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
FMCPBTAuthTestTree Fixture = MCPBTAuthTestMakeTree();
|
|
430
|
+
if (!Fixture.IsValid())
|
|
431
|
+
{
|
|
432
|
+
AddError(TEXT("could not seed a BehaviorTree graph"));
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// A blackboard with one key, so the decorator's FBlackboardKeySelector has
|
|
437
|
+
// something real to resolve against when InitializeFromAsset runs.
|
|
438
|
+
UBlackboardData* Blackboard = NewObject<UBlackboardData>(Fixture.Tree);
|
|
439
|
+
FBlackboardEntry Entry;
|
|
440
|
+
Entry.EntryName = TEXT("IsAlive");
|
|
441
|
+
if (BoolKeyClass)
|
|
442
|
+
{
|
|
443
|
+
Entry.KeyType = NewObject<UBlackboardKeyType>(Blackboard, BoolKeyClass);
|
|
444
|
+
}
|
|
445
|
+
Blackboard->Keys.Add(Entry);
|
|
446
|
+
Fixture.Tree->BlackboardAsset = Blackboard;
|
|
447
|
+
|
|
448
|
+
UBehaviorTreeGraphNode* Selector = MCPBTAuthTestPlace(
|
|
449
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Composite::StaticClass(), SelectorClass, 0, 200);
|
|
450
|
+
UBehaviorTreeGraphNode* Task = MCPBTAuthTestPlace(
|
|
451
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Task::StaticClass(), WaitClass, 0, 400);
|
|
452
|
+
if (!Selector || !Task)
|
|
453
|
+
{
|
|
454
|
+
AddError(TEXT("could not place the nodes under test"));
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
MCPBTAuthTestLink(Fixture.Graph, Fixture.Root, Selector);
|
|
459
|
+
MCPBTAuthTestLink(Fixture.Graph, Selector, Task);
|
|
460
|
+
|
|
461
|
+
// The subnode is constructed against the graph and handed to AddSubNode,
|
|
462
|
+
// which does the guid, the instance spawn and the parent bookkeeping.
|
|
463
|
+
UBehaviorTreeGraphNode* SubNode = NewObject<UBehaviorTreeGraphNode>(
|
|
464
|
+
Fixture.Graph, UBehaviorTreeGraphNode_Decorator::StaticClass());
|
|
465
|
+
SubNode->ClassData = FGraphNodeClassData(DecoratorClass, FString());
|
|
466
|
+
Task->AddSubNode(SubNode, Fixture.Graph);
|
|
467
|
+
|
|
468
|
+
TestEqual(TEXT("the decorator landed in the task's Decorators list"), Task->Decorators.Num(), 1);
|
|
469
|
+
TestEqual(TEXT("and not in its Services list"), Task->Services.Num(), 0);
|
|
470
|
+
TestNotNull(TEXT("AddSubNode spawned the decorator instance"), SubNode->NodeInstance.Get());
|
|
471
|
+
|
|
472
|
+
UBTNode* DecoratorInstance = Cast<UBTNode>(SubNode->NodeInstance);
|
|
473
|
+
if (DecoratorInstance)
|
|
474
|
+
{
|
|
475
|
+
FString WriteError;
|
|
476
|
+
TestTrue(TEXT("the decorator's blackboard key is writable before the compile"),
|
|
477
|
+
FGameplayHandlers::WriteBTNodeProperty(DecoratorInstance, TEXT("BlackboardKey.SelectedKeyName"),
|
|
478
|
+
MakeShared<FJsonValueString>(TEXT("IsAlive")), WriteError));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
Fixture.Graph->UpdateAsset();
|
|
482
|
+
|
|
483
|
+
UBTCompositeNode* RuntimeRoot = Fixture.Tree->RootNode.Get();
|
|
484
|
+
if (!RuntimeRoot || RuntimeRoot->Children.Num() != 1)
|
|
485
|
+
{
|
|
486
|
+
AddError(TEXT("the selector did not compile with its one child"));
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// The decorator is stored on the PARENT composite's child entry, not on the
|
|
491
|
+
// task. That asymmetry between the graph and the runtime tree is why the
|
|
492
|
+
// read surface addresses it as Root.Children[0].Decorators[0].
|
|
493
|
+
TestEqual(TEXT("the decorator compiled onto the child entry"),
|
|
494
|
+
RuntimeRoot->Children[0].Decorators.Num(), 1);
|
|
495
|
+
|
|
496
|
+
TMap<UBTNode*, FString> Addresses;
|
|
497
|
+
FGameplayHandlers::MapBTNodeAddresses(Fixture.Tree, Addresses);
|
|
498
|
+
if (DecoratorInstance)
|
|
499
|
+
{
|
|
500
|
+
if (const FString* Address = Addresses.Find(DecoratorInstance))
|
|
501
|
+
{
|
|
502
|
+
TestEqual(TEXT("the decorator addresses under its child entry"),
|
|
503
|
+
*Address, FString(TEXT("Root.Children[0].Decorators[0]")));
|
|
504
|
+
}
|
|
505
|
+
else
|
|
506
|
+
{
|
|
507
|
+
AddError(TEXT("the compiled decorator has no address"));
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// UpdateAsset re-runs InitializeFromAsset on every node, which is what
|
|
511
|
+
// turns the key name into a resolved key id. A selector that never
|
|
512
|
+
// resolves leaves the decorator permanently false at runtime.
|
|
513
|
+
if (BoolKeyClass)
|
|
514
|
+
{
|
|
515
|
+
FString ReadError;
|
|
516
|
+
const TSharedPtr<FJsonValue> Read = FGameplayHandlers::ReadBTNodeProperty(
|
|
517
|
+
DecoratorInstance, TEXT("BlackboardKey.SelectedKeyName"), ReadError);
|
|
518
|
+
FString ReadName;
|
|
519
|
+
if (Read.IsValid()) Read->TryGetString(ReadName);
|
|
520
|
+
TestEqual(TEXT("the key name survives the compile"), ReadName, FString(TEXT("IsAlive")));
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
#endif // WITH_DEV_AUTOMATION_TESTS
|