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
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// Coverage for level(query_components) that is safe to run anywhere.
|
|
2
|
+
//
|
|
3
|
+
// run_automation_tests dispatches every EditorContext/EngineFilter test in the
|
|
4
|
+
// process against whatever project the bridge is attached to, so nothing here
|
|
5
|
+
// may write. query_components never writes by design, which makes most of it
|
|
6
|
+
// testable directly: the assertions below run the real handler against the
|
|
7
|
+
// open editor world and check the contract (registration, argument rejection,
|
|
8
|
+
// bounded output, the read guarantee, clean enum names) rather than any
|
|
9
|
+
// particular level's contents.
|
|
10
|
+
|
|
11
|
+
#if WITH_DEV_AUTOMATION_TESTS
|
|
12
|
+
|
|
13
|
+
#include "HandlerRegistry.h"
|
|
14
|
+
#include "Handlers/LevelHandlers.h"
|
|
15
|
+
#include "Misc/AutomationTest.h"
|
|
16
|
+
|
|
17
|
+
namespace
|
|
18
|
+
{
|
|
19
|
+
TSharedPtr<FJsonObject> MCPQueryTestRun(FMCPHandlerRegistry& Registry, const TSharedPtr<FJsonObject>& Request)
|
|
20
|
+
{
|
|
21
|
+
const TSharedPtr<FJsonValue> Response = Registry.ExecuteHandler(TEXT("query_components"), Request);
|
|
22
|
+
if (!Response.IsValid() || Response->Type != EJson::Object)
|
|
23
|
+
{
|
|
24
|
+
return nullptr;
|
|
25
|
+
}
|
|
26
|
+
return Response->AsObject();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
TSharedPtr<FJsonObject> MCPQueryTestPredicate(const FString& Field, const FString& Op)
|
|
30
|
+
{
|
|
31
|
+
TSharedPtr<FJsonObject> Predicate = MakeShared<FJsonObject>();
|
|
32
|
+
Predicate->SetStringField(TEXT("field"), Field);
|
|
33
|
+
Predicate->SetStringField(TEXT("op"), Op);
|
|
34
|
+
return Predicate;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
39
|
+
FLevelQueryComponentsContractTest,
|
|
40
|
+
"UE.MCP.Level.QueryComponents.Contract",
|
|
41
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
42
|
+
|
|
43
|
+
bool FLevelQueryComponentsContractTest::RunTest(const FString& Parameters)
|
|
44
|
+
{
|
|
45
|
+
FMCPHandlerRegistry Registry;
|
|
46
|
+
FLevelHandlers::RegisterHandlers(Registry);
|
|
47
|
+
|
|
48
|
+
TestTrue(TEXT("query_components is registered"), Registry.HasHandler(TEXT("query_components")));
|
|
49
|
+
TestTrue(
|
|
50
|
+
TEXT("query_components carries its own timeout, because a whole-map scan outlives the default"),
|
|
51
|
+
Registry.GetHandlerTimeout(TEXT("query_components")) > 0.0f);
|
|
52
|
+
|
|
53
|
+
// An unknown field group is an error rather than a silently empty
|
|
54
|
+
// projection. A projection that quietly produces nothing is how a caller
|
|
55
|
+
// ends up trusting a confident zero.
|
|
56
|
+
{
|
|
57
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
58
|
+
Request->SetArrayField(TEXT("fields"), { MakeShared<FJsonValueString>(TEXT("nonsense")) });
|
|
59
|
+
const TSharedPtr<FJsonObject> Response = MCPQueryTestRun(Registry, Request);
|
|
60
|
+
TestTrue(TEXT("unknown field group returns an object"), Response.IsValid());
|
|
61
|
+
if (Response.IsValid())
|
|
62
|
+
{
|
|
63
|
+
TestFalse(TEXT("unknown field group fails"), Response->GetBoolField(TEXT("success")));
|
|
64
|
+
TestTrue(
|
|
65
|
+
TEXT("unknown field group names the offending entry"),
|
|
66
|
+
Response->GetStringField(TEXT("error")).Contains(TEXT("nonsense")));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// An unknown operator is likewise rejected, and the message lists the
|
|
71
|
+
// operators that do exist.
|
|
72
|
+
{
|
|
73
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
74
|
+
Request->SetArrayField(TEXT("where"), {
|
|
75
|
+
MakeShared<FJsonValueObject>(MCPQueryTestPredicate(TEXT("shadow.castShadow"), TEXT("approximately"))) });
|
|
76
|
+
const TSharedPtr<FJsonObject> Response = MCPQueryTestRun(Registry, Request);
|
|
77
|
+
TestTrue(TEXT("unknown operator returns an object"), Response.IsValid());
|
|
78
|
+
if (Response.IsValid())
|
|
79
|
+
{
|
|
80
|
+
TestFalse(TEXT("unknown operator fails"), Response->GetBoolField(TEXT("success")));
|
|
81
|
+
TestTrue(
|
|
82
|
+
TEXT("unknown operator lists the valid ones"),
|
|
83
|
+
Response->GetStringField(TEXT("error")).Contains(TEXT("isTrue")));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// A predicate missing its field is rejected by index, so a caller with
|
|
88
|
+
// twenty predicates knows which one.
|
|
89
|
+
{
|
|
90
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
91
|
+
Request->SetArrayField(TEXT("where"), { MakeShared<FJsonValueObject>(MakeShared<FJsonObject>()) });
|
|
92
|
+
const TSharedPtr<FJsonObject> Response = MCPQueryTestRun(Registry, Request);
|
|
93
|
+
if (Response.IsValid())
|
|
94
|
+
{
|
|
95
|
+
TestFalse(TEXT("predicate without a field fails"), Response->GetBoolField(TEXT("success")));
|
|
96
|
+
TestTrue(
|
|
97
|
+
TEXT("predicate rejection names the index"),
|
|
98
|
+
Response->GetStringField(TEXT("error")).Contains(TEXT("where[0]")));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// suspectOnly is an AND, so combining it with whereMode 'any' would change
|
|
103
|
+
// what the other predicates mean. That is refused rather than guessed at.
|
|
104
|
+
{
|
|
105
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
106
|
+
Request->SetBoolField(TEXT("suspectOnly"), true);
|
|
107
|
+
Request->SetStringField(TEXT("whereMode"), TEXT("any"));
|
|
108
|
+
Request->SetArrayField(TEXT("where"), {
|
|
109
|
+
MakeShared<FJsonValueObject>(MCPQueryTestPredicate(TEXT("shadow.castShadow"), TEXT("isTrue"))) });
|
|
110
|
+
const TSharedPtr<FJsonObject> Response = MCPQueryTestRun(Registry, Request);
|
|
111
|
+
if (Response.IsValid())
|
|
112
|
+
{
|
|
113
|
+
TestFalse(TEXT("suspectOnly with whereMode any fails"), Response->GetBoolField(TEXT("success")));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// A levelPath that is not a map is refused before anything is opened.
|
|
118
|
+
{
|
|
119
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
120
|
+
Request->SetStringField(TEXT("levelPath"), TEXT("/Game/UEMCPDefinitelyNotAMap"));
|
|
121
|
+
const TSharedPtr<FJsonObject> Response = MCPQueryTestRun(Registry, Request);
|
|
122
|
+
if (Response.IsValid())
|
|
123
|
+
{
|
|
124
|
+
TestFalse(TEXT("a missing level package fails"), Response->GetBoolField(TEXT("success")));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
132
|
+
FLevelQueryComponentsBoundsTest,
|
|
133
|
+
"UE.MCP.Level.QueryComponents.BoundedAndReadOnly",
|
|
134
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
135
|
+
|
|
136
|
+
bool FLevelQueryComponentsBoundsTest::RunTest(const FString& Parameters)
|
|
137
|
+
{
|
|
138
|
+
FMCPHandlerRegistry Registry;
|
|
139
|
+
FLevelHandlers::RegisterHandlers(Registry);
|
|
140
|
+
|
|
141
|
+
// An unfiltered query against whatever map is open. This is the shape that
|
|
142
|
+
// used to return over a megabyte, so the assertions are about the caps.
|
|
143
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
144
|
+
Request->SetNumberField(TEXT("limit"), 5);
|
|
145
|
+
Request->SetArrayField(TEXT("fields"), {
|
|
146
|
+
MakeShared<FJsonValueString>(TEXT("shadow")),
|
|
147
|
+
MakeShared<FJsonValueString>(TEXT("navigation")) });
|
|
148
|
+
|
|
149
|
+
const TSharedPtr<FJsonObject> Response = MCPQueryTestRun(Registry, Request);
|
|
150
|
+
if (!Response.IsValid() || !Response->GetBoolField(TEXT("success")))
|
|
151
|
+
{
|
|
152
|
+
// No editor world (a cook or commandlet context) is not a failure of
|
|
153
|
+
// this handler, and this test is not allowed to open a map to create
|
|
154
|
+
// one. Everything above already ran without a world.
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const TArray<TSharedPtr<FJsonValue>>& Rows = Response->GetArrayField(TEXT("rows"));
|
|
159
|
+
TestTrue(TEXT("the row array honours 'limit'"), Rows.Num() <= 5);
|
|
160
|
+
TestTrue(
|
|
161
|
+
TEXT("'matched' is reported independently of how many rows came back"),
|
|
162
|
+
Response->GetNumberField(TEXT("matched")) >= Rows.Num());
|
|
163
|
+
|
|
164
|
+
// The #912 guarantee: a map-wide read leaves nothing dirty.
|
|
165
|
+
TestFalse(TEXT("a query dirties no packages"), Response->GetBoolField(TEXT("dirtiedPackages")));
|
|
166
|
+
|
|
167
|
+
// The #943 trap: a clean enum name, never EComponentMobility.MOVABLE.
|
|
168
|
+
for (const TSharedPtr<FJsonValue>& RowValue : Rows)
|
|
169
|
+
{
|
|
170
|
+
if (!RowValue.IsValid() || RowValue->Type != EJson::Object) continue;
|
|
171
|
+
const TSharedPtr<FJsonObject> Row = RowValue->AsObject();
|
|
172
|
+
if (!Row->HasTypedField<EJson::Object>(TEXT("navigation"))) continue;
|
|
173
|
+
const FString Mobility = Row->GetObjectField(TEXT("navigation"))->GetStringField(TEXT("mobility"));
|
|
174
|
+
TestFalse(
|
|
175
|
+
FString::Printf(TEXT("mobility '%s' carries no enum type prefix"), *Mobility),
|
|
176
|
+
Mobility.Contains(TEXT("EComponentMobility")));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// countOnly answers the aggregate question without paying for rows.
|
|
180
|
+
{
|
|
181
|
+
TSharedPtr<FJsonObject> CountRequest = MakeShared<FJsonObject>();
|
|
182
|
+
CountRequest->SetBoolField(TEXT("countOnly"), true);
|
|
183
|
+
CountRequest->SetStringField(TEXT("groupBy"), TEXT("actorClass"));
|
|
184
|
+
const TSharedPtr<FJsonObject> CountResponse = MCPQueryTestRun(Registry, CountRequest);
|
|
185
|
+
if (CountResponse.IsValid() && CountResponse->GetBoolField(TEXT("success")))
|
|
186
|
+
{
|
|
187
|
+
TestFalse(TEXT("countOnly returns no rows array"), CountResponse->HasField(TEXT("rows")));
|
|
188
|
+
TestTrue(TEXT("countOnly still groups"), CountResponse->HasField(TEXT("groups")));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
#endif // WITH_DEV_AUTOMATION_TESTS
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Coverage for the level refresh and inspect actions (#944, #915, #914).
|
|
2
|
+
//
|
|
3
|
+
// run_automation_tests dispatches every EditorContext/EngineFilter test in the
|
|
4
|
+
// process against whatever project the bridge is attached to. Two of these
|
|
5
|
+
// three actions rebuild engine state, so the assertions stay on the paths
|
|
6
|
+
// specified to change nothing: the refusals that keep them from running
|
|
7
|
+
// unbounded, and the dry run.
|
|
8
|
+
|
|
9
|
+
#if WITH_DEV_AUTOMATION_TESTS
|
|
10
|
+
|
|
11
|
+
#include "HandlerRegistry.h"
|
|
12
|
+
#include "Handlers/LevelHandlers.h"
|
|
13
|
+
#include "Misc/AutomationTest.h"
|
|
14
|
+
|
|
15
|
+
namespace
|
|
16
|
+
{
|
|
17
|
+
TSharedPtr<FJsonObject> MCPRefreshTestRun(
|
|
18
|
+
FMCPHandlerRegistry& Registry,
|
|
19
|
+
const TCHAR* Method,
|
|
20
|
+
const TSharedPtr<FJsonObject>& Request)
|
|
21
|
+
{
|
|
22
|
+
const TSharedPtr<FJsonValue> Response = Registry.ExecuteHandler(Method, Request);
|
|
23
|
+
if (!Response.IsValid() || Response->Type != EJson::Object)
|
|
24
|
+
{
|
|
25
|
+
return nullptr;
|
|
26
|
+
}
|
|
27
|
+
return Response->AsObject();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
32
|
+
FLevelRefreshRefusesUnboundedTest,
|
|
33
|
+
"UE.MCP.Level.Refresh.RefusesAnUnboundedRequest",
|
|
34
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
35
|
+
|
|
36
|
+
bool FLevelRefreshRefusesUnboundedTest::RunTest(const FString& Parameters)
|
|
37
|
+
{
|
|
38
|
+
FMCPHandlerRegistry Registry;
|
|
39
|
+
FLevelHandlers::RegisterHandlers(Registry);
|
|
40
|
+
|
|
41
|
+
for (const TCHAR* Method : {
|
|
42
|
+
TEXT("rerun_construction_scripts"),
|
|
43
|
+
TEXT("recreate_physics_state"),
|
|
44
|
+
TEXT("test_component_overlap") })
|
|
45
|
+
{
|
|
46
|
+
TestTrue(FString::Printf(TEXT("%s is registered"), Method), Registry.HasHandler(Method));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Rerunning every construction script in a map destroys and rebuilds every
|
|
50
|
+
// generated component in it, so an empty request is refused rather than
|
|
51
|
+
// treated as "all".
|
|
52
|
+
{
|
|
53
|
+
const TSharedPtr<FJsonObject> Response =
|
|
54
|
+
MCPRefreshTestRun(Registry, TEXT("rerun_construction_scripts"), MakeShared<FJsonObject>());
|
|
55
|
+
if (Response.IsValid())
|
|
56
|
+
{
|
|
57
|
+
TestFalse(TEXT("an unbounded rerun fails"), Response->GetBoolField(TEXT("success")));
|
|
58
|
+
TestTrue(TEXT("and says which selectors it wants"),
|
|
59
|
+
Response->GetStringField(TEXT("error")).Contains(TEXT("actorLabels")));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Same for the physics rebuild, which is long and disruptive and whose bug
|
|
64
|
+
// is always localised to the meshes that changed.
|
|
65
|
+
{
|
|
66
|
+
const TSharedPtr<FJsonObject> Response =
|
|
67
|
+
MCPRefreshTestRun(Registry, TEXT("recreate_physics_state"), MakeShared<FJsonObject>());
|
|
68
|
+
if (Response.IsValid())
|
|
69
|
+
{
|
|
70
|
+
TestFalse(TEXT("an unbounded physics rebuild fails"), Response->GetBoolField(TEXT("success")));
|
|
71
|
+
TestTrue(TEXT("and says so explicitly"),
|
|
72
|
+
Response->GetStringField(TEXT("error")).Contains(TEXT("whole world")));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// An unknown overlap method is named rather than silently treated as OBB.
|
|
77
|
+
{
|
|
78
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
79
|
+
Request->SetStringField(TEXT("actorLabelA"), TEXT("A"));
|
|
80
|
+
Request->SetStringField(TEXT("actorLabelB"), TEXT("B"));
|
|
81
|
+
Request->SetStringField(TEXT("method"), TEXT("Sphere"));
|
|
82
|
+
const TSharedPtr<FJsonObject> Response =
|
|
83
|
+
MCPRefreshTestRun(Registry, TEXT("test_component_overlap"), Request);
|
|
84
|
+
if (Response.IsValid())
|
|
85
|
+
{
|
|
86
|
+
TestFalse(TEXT("an unknown method fails"), Response->GetBoolField(TEXT("success")));
|
|
87
|
+
TestTrue(TEXT("and lists the ones that exist"),
|
|
88
|
+
Response->GetStringField(TEXT("error")).Contains(TEXT("AABB")));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Both labels are required, and a missing one is named.
|
|
93
|
+
{
|
|
94
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
95
|
+
Request->SetStringField(TEXT("actorLabelA"), TEXT("A"));
|
|
96
|
+
const TSharedPtr<FJsonObject> Response =
|
|
97
|
+
MCPRefreshTestRun(Registry, TEXT("test_component_overlap"), Request);
|
|
98
|
+
if (Response.IsValid())
|
|
99
|
+
{
|
|
100
|
+
TestFalse(TEXT("a one-sided overlap test fails"), Response->GetBoolField(TEXT("success")));
|
|
101
|
+
TestTrue(TEXT("and names the missing parameter"),
|
|
102
|
+
Response->GetStringField(TEXT("error")).Contains(TEXT("actorLabelB")));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
110
|
+
FLevelRecreatePhysicsPreviewTest,
|
|
111
|
+
"UE.MCP.Level.Refresh.PhysicsRebuildPreviewsByDefault",
|
|
112
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
113
|
+
|
|
114
|
+
bool FLevelRecreatePhysicsPreviewTest::RunTest(const FString& Parameters)
|
|
115
|
+
{
|
|
116
|
+
FMCPHandlerRegistry Registry;
|
|
117
|
+
FLevelHandlers::RegisterHandlers(Registry);
|
|
118
|
+
|
|
119
|
+
// A bounded request with no dryRun given. The preflight is the default,
|
|
120
|
+
// which is what #915 asked for: see what would be rebuilt, and what its
|
|
121
|
+
// collision state is now, before rebuilding it.
|
|
122
|
+
TSharedPtr<FJsonObject> Request = MakeShared<FJsonObject>();
|
|
123
|
+
Request->SetStringField(TEXT("componentClass"), TEXT("StaticMeshComponent"));
|
|
124
|
+
|
|
125
|
+
const TSharedPtr<FJsonObject> Response =
|
|
126
|
+
MCPRefreshTestRun(Registry, TEXT("recreate_physics_state"), Request);
|
|
127
|
+
if (!Response.IsValid() || !Response->GetBoolField(TEXT("success")))
|
|
128
|
+
{
|
|
129
|
+
// No editor world in this context, and this test may not open a map.
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
TestTrue(TEXT("dryRun defaults to true"), Response->GetBoolField(TEXT("dryRun")));
|
|
134
|
+
TestTrue(TEXT("a preview reports what it would rebuild"), Response->HasField(TEXT("wouldRecreate")));
|
|
135
|
+
TestFalse(TEXT("and does not claim to have rebuilt anything"), Response->HasField(TEXT("recreated")));
|
|
136
|
+
TestTrue(TEXT("a preview still returns the current collision summary"),
|
|
137
|
+
Response->HasField(TEXT("collisionSummary")));
|
|
138
|
+
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#endif // WITH_DEV_AUTOMATION_TESTS
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Coverage for level(save) reporting the truth about the packages it touched
|
|
2
|
+
// (#964).
|
|
3
|
+
//
|
|
4
|
+
// The failure this guards is a FALSE failure: the old action answered
|
|
5
|
+
// {"success": false, "error": "Failed to save current level"} on a map that
|
|
6
|
+
// editor(save_dirty) then wrote seconds later. An agent that believes a save
|
|
7
|
+
// did not happen redoes work that was already on disk, so a save reporting
|
|
8
|
+
// failure when nothing failed is more expensive than one that reports nothing.
|
|
9
|
+
//
|
|
10
|
+
// The test deliberately writes nothing. It runs only when the level and its
|
|
11
|
+
// external packages are already clean, and then asserts that a save with
|
|
12
|
+
// nothing to do is reported as the success it is, names the package it
|
|
13
|
+
// considered, and carries no error. A test that saved the map to check saving
|
|
14
|
+
// would leave exactly the kind of unasked-for commit this repo works to avoid.
|
|
15
|
+
|
|
16
|
+
#if WITH_DEV_AUTOMATION_TESTS
|
|
17
|
+
|
|
18
|
+
#include "Editor.h"
|
|
19
|
+
#include "Engine/Level.h"
|
|
20
|
+
#include "Engine/World.h"
|
|
21
|
+
#include "HandlerRegistry.h"
|
|
22
|
+
#include "Handlers/LevelHandlers.h"
|
|
23
|
+
#include "Misc/AutomationTest.h"
|
|
24
|
+
#include "UObject/Package.h"
|
|
25
|
+
|
|
26
|
+
namespace
|
|
27
|
+
{
|
|
28
|
+
TSharedPtr<FJsonObject> MCPLevelSaveTestRun(
|
|
29
|
+
FMCPHandlerRegistry& Registry,
|
|
30
|
+
const TSharedPtr<FJsonObject>& Request)
|
|
31
|
+
{
|
|
32
|
+
const TSharedPtr<FJsonValue> Response = Registry.ExecuteHandler(TEXT("save_level"), Request);
|
|
33
|
+
if (!Response.IsValid() || Response->Type != EJson::Object)
|
|
34
|
+
{
|
|
35
|
+
return nullptr;
|
|
36
|
+
}
|
|
37
|
+
return Response->AsObject();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** True when saving would write nothing at all, so the test is safe to run. */
|
|
41
|
+
bool MCPLevelSaveTestNothingIsDirty(UWorld* World)
|
|
42
|
+
{
|
|
43
|
+
if (!World) return false;
|
|
44
|
+
ULevel* Level = World->GetCurrentLevel();
|
|
45
|
+
if (!Level) Level = World->PersistentLevel;
|
|
46
|
+
if (!Level) return false;
|
|
47
|
+
UPackage* Package = Level->GetOutermost();
|
|
48
|
+
if (!Package || Package->IsDirty()) return false;
|
|
49
|
+
if (Level->IsUsingExternalObjects())
|
|
50
|
+
{
|
|
51
|
+
for (UPackage* External : Level->GetLoadedExternalObjectPackages())
|
|
52
|
+
{
|
|
53
|
+
if (External && External->IsDirty()) return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
61
|
+
FLevelSaveReportsWhatHappenedTest,
|
|
62
|
+
"UE.MCP.Level.Save.ReportsWhatHappenedToEachPackage",
|
|
63
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
64
|
+
|
|
65
|
+
bool FLevelSaveReportsWhatHappenedTest::RunTest(const FString& Parameters)
|
|
66
|
+
{
|
|
67
|
+
FMCPHandlerRegistry Registry;
|
|
68
|
+
FLevelHandlers::RegisterHandlers(Registry);
|
|
69
|
+
TestTrue(TEXT("save_level is registered"), Registry.HasHandler(TEXT("save_level")));
|
|
70
|
+
|
|
71
|
+
UWorld* World = GEditor ? GEditor->GetEditorWorldContext().World() : nullptr;
|
|
72
|
+
if (!World) return true;
|
|
73
|
+
if (GEditor->PlayWorld != nullptr || GEditor->bIsSimulatingInEditor) return true;
|
|
74
|
+
if (!MCPLevelSaveTestNothingIsDirty(World))
|
|
75
|
+
{
|
|
76
|
+
// Something is unsaved. Running the action here would write it, and
|
|
77
|
+
// this test is not permitted to commit anybody's work for them.
|
|
78
|
+
AddInfo(TEXT("Skipped: the open level has unsaved changes, and this test never writes."));
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const TSharedPtr<FJsonObject> Response = MCPLevelSaveTestRun(Registry, MakeShared<FJsonObject>());
|
|
83
|
+
if (!Response.IsValid()) return true;
|
|
84
|
+
|
|
85
|
+
// The regression: nothing failed, so nothing may be reported as a failure.
|
|
86
|
+
TestTrue(TEXT("a save with nothing to do succeeds"), Response->GetBoolField(TEXT("success")));
|
|
87
|
+
FString Error;
|
|
88
|
+
TestFalse(TEXT("and carries no error"), Response->TryGetStringField(TEXT("error"), Error));
|
|
89
|
+
TestEqual(TEXT("and reports that nothing failed"),
|
|
90
|
+
static_cast<int32>(Response->GetNumberField(TEXT("failedCount"))), 0);
|
|
91
|
+
TestEqual(TEXT("and that nothing needed writing"),
|
|
92
|
+
static_cast<int32>(Response->GetNumberField(TEXT("savedCount"))), 0);
|
|
93
|
+
|
|
94
|
+
// The diagnostic half: the response names what it considered, so a caller
|
|
95
|
+
// can tell "already saved" from "saved nothing because it looked nowhere".
|
|
96
|
+
FString LevelPackage;
|
|
97
|
+
TestTrue(TEXT("the response names the level package"),
|
|
98
|
+
Response->TryGetStringField(TEXT("levelPackage"), LevelPackage));
|
|
99
|
+
TestTrue(TEXT("which is not empty"), !LevelPackage.IsEmpty());
|
|
100
|
+
FString Message;
|
|
101
|
+
TestTrue(TEXT("and says in words that nothing needed writing"),
|
|
102
|
+
Response->TryGetStringField(TEXT("message"), Message));
|
|
103
|
+
|
|
104
|
+
// A clean package appears as skipped with its reason, never as a failure.
|
|
105
|
+
const TArray<TSharedPtr<FJsonValue>>* SkippedRows = nullptr;
|
|
106
|
+
if (Response->TryGetArrayField(TEXT("skipped"), SkippedRows) && SkippedRows)
|
|
107
|
+
{
|
|
108
|
+
TestTrue(TEXT("the clean level package is listed as skipped"), SkippedRows->Num() >= 1);
|
|
109
|
+
if (SkippedRows->Num() > 0)
|
|
110
|
+
{
|
|
111
|
+
const TSharedPtr<FJsonObject> Row = (*SkippedRows)[0]->AsObject();
|
|
112
|
+
if (Row.IsValid())
|
|
113
|
+
{
|
|
114
|
+
TestFalse(TEXT("a skipped package is not marked saved"), Row->GetBoolField(TEXT("saved")));
|
|
115
|
+
TestFalse(TEXT("and was not dirty"), Row->GetBoolField(TEXT("wasDirty")));
|
|
116
|
+
FString RowError;
|
|
117
|
+
TestFalse(TEXT("and is not an error"), Row->TryGetStringField(TEXT("error"), RowError));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#endif // WITH_DEV_AUTOMATION_TESTS
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#if WITH_DEV_AUTOMATION_TESTS
|
|
2
|
+
|
|
3
|
+
#include "Handlers/LevelHandlers.h"
|
|
4
|
+
#include "EdGraph/EdGraph.h"
|
|
5
|
+
#include "EdGraph/EdGraphNode.h"
|
|
6
|
+
#include "Engine/Blueprint.h"
|
|
7
|
+
#include "EdGraphSchema_K2.h"
|
|
8
|
+
#include "Kismet2/BlueprintEditorUtils.h"
|
|
9
|
+
#include "Misc/AutomationTest.h"
|
|
10
|
+
|
|
11
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
12
|
+
FLevelScriptClearGraphNodesTest,
|
|
13
|
+
"UE.MCP.Level.ClearLevelScript.GraphNodes",
|
|
14
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
15
|
+
|
|
16
|
+
bool FLevelScriptClearGraphNodesTest::RunTest(const FString& Parameters)
|
|
17
|
+
{
|
|
18
|
+
UBlueprint* Blueprint = NewObject<UBlueprint>(GetTransientPackage());
|
|
19
|
+
UEdGraph* Graph = NewObject<UEdGraph>(Blueprint, TEXT("EventGraph"));
|
|
20
|
+
Blueprint->UbergraphPages.Add(Graph);
|
|
21
|
+
Graph->AddNode(NewObject<UEdGraphNode>(Graph, TEXT("FirstNode")));
|
|
22
|
+
Graph->AddNode(NewObject<UEdGraphNode>(Graph, TEXT("SecondNode")));
|
|
23
|
+
FEdGraphPinType VariableType;
|
|
24
|
+
VariableType.PinCategory = UEdGraphSchema_K2::PC_Boolean;
|
|
25
|
+
FBlueprintEditorUtils::AddMemberVariable(Blueprint, TEXT("LegacyReference"), VariableType);
|
|
26
|
+
|
|
27
|
+
TArray<TSharedPtr<FJsonValue>> Graphs;
|
|
28
|
+
TestEqual(TEXT("dry run reports both nodes"),
|
|
29
|
+
FLevelHandlers::ClearBlueprintGraphNodes(Blueprint, true, Graphs), 2);
|
|
30
|
+
TestEqual(TEXT("dry run keeps both nodes"), Graph->Nodes.Num(), 2);
|
|
31
|
+
TestEqual(TEXT("dry run reports the graph"), Graphs.Num(), 1);
|
|
32
|
+
|
|
33
|
+
Graphs.Reset();
|
|
34
|
+
TestEqual(TEXT("apply removes both nodes"),
|
|
35
|
+
FLevelHandlers::ClearBlueprintGraphNodes(Blueprint, false, Graphs), 2);
|
|
36
|
+
TestEqual(TEXT("apply leaves the graph empty"), Graph->Nodes.Num(), 0);
|
|
37
|
+
FBlueprintEditorUtils::RemoveMemberVariable(Blueprint, TEXT("LegacyReference"));
|
|
38
|
+
TestEqual(TEXT("member variable can be removed"), Blueprint->NewVariables.Num(), 0);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#endif
|