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
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
#include "Framework/Docking/TabManager.h"
|
|
29
29
|
#include "Widgets/Docking/SDockTab.h"
|
|
30
30
|
#include "ISettingsModule.h"
|
|
31
|
+
#include "Interfaces/IMainFrameModule.h"
|
|
31
32
|
#include "Modules/ModuleManager.h"
|
|
32
33
|
#include "Misc/ConfigCacheIni.h"
|
|
33
34
|
#include "Misc/ConfigContext.h"
|
|
@@ -41,6 +42,7 @@
|
|
|
41
42
|
#include "RenderingThread.h"
|
|
42
43
|
#include "Misc/AutomationTest.h"
|
|
43
44
|
#include "HAL/PlatformProcess.h"
|
|
45
|
+
#include "HAL/PlatformTime.h"
|
|
44
46
|
#include "Slate/SceneViewport.h"
|
|
45
47
|
#include "HAL/PlatformMemory.h"
|
|
46
48
|
#include "Misc/App.h"
|
|
@@ -246,6 +248,7 @@ void FEditorHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
|
|
|
246
248
|
// order in BridgeServer.cpp, which is not a contract.
|
|
247
249
|
Registry.RegisterHandler(TEXT("save_dirty"), &SaveDirty);
|
|
248
250
|
Registry.RegisterHandler(TEXT("list_dirty_packages"), &ListDirtyPackages);
|
|
251
|
+
Registry.RegisterHandler(TEXT("get_world_state"), &GetWorldState);
|
|
249
252
|
Registry.RegisterHandler(TEXT("request_editor_shutdown"), &RequestEditorShutdown);
|
|
250
253
|
Registry.RegisterHandler(TEXT("list_pie_instances"), &ListPIEInstances);
|
|
251
254
|
Registry.RegisterHandler(TEXT("invoke_object_function"), &InvokeObjectFunction);
|
|
@@ -254,6 +257,8 @@ void FEditorHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
|
|
|
254
257
|
Registry.RegisterHandler(TEXT("read_bone_transforms"), &ReadBoneTransforms);
|
|
255
258
|
Registry.RegisterHandler(TEXT("teleport_runtime_actor"), &TeleportRuntimeActor);
|
|
256
259
|
Registry.RegisterHandler(TEXT("set_movement_mode"), &SetMovementMode);
|
|
260
|
+
Registry.RegisterHandler(TEXT("set_runtime_visibility"), &SetRuntimeVisibility);
|
|
261
|
+
Registry.RegisterHandler(TEXT("restore_runtime_visibility"), &RestoreRuntimeVisibility);
|
|
257
262
|
// #802: resolve a live instance path, and write to a live instance.
|
|
258
263
|
Registry.RegisterHandler(TEXT("find_object"), &FindLiveObjects);
|
|
259
264
|
Registry.RegisterHandler(TEXT("set_object_property"), &SetObjectProperty);
|
|
@@ -1163,7 +1168,11 @@ TSharedPtr<FJsonValue> FEditorHandlers::HitTestViewportPixel(const TSharedPtr<FJ
|
|
|
1163
1168
|
{
|
|
1164
1169
|
FString Label;
|
|
1165
1170
|
if (!V->TryGetString(Label)) continue;
|
|
1166
|
-
|
|
1171
|
+
// #983: an ignore list is the plural case, so a label naming
|
|
1172
|
+
// several actors ignores all of them.
|
|
1173
|
+
TArray<AActor*> Matches;
|
|
1174
|
+
MCPCollectActorsByToken(World, Label, EMCPActorMatch::LabelNameOrPath, Matches);
|
|
1175
|
+
for (AActor* A : Matches) Query.AddIgnoredActor(A);
|
|
1167
1176
|
}
|
|
1168
1177
|
}
|
|
1169
1178
|
|
|
@@ -1190,6 +1199,7 @@ TSharedPtr<FJsonValue> FEditorHandlers::HitTestViewportPixel(const TSharedPtr<FJ
|
|
|
1190
1199
|
AActor* HitActor = Hit.GetActor();
|
|
1191
1200
|
UPrimitiveComponent* HitComp = Hit.GetComponent();
|
|
1192
1201
|
if (HitActor) Result->SetStringField(TEXT("actorLabel"), HitActor->GetActorLabel());
|
|
1202
|
+
if (HitActor) Result->SetStringField(TEXT("actorPath"), HitActor->GetPathName());
|
|
1193
1203
|
if (HitActor) Result->SetStringField(TEXT("actorClass"), HitActor->GetClass()->GetName());
|
|
1194
1204
|
if (HitComp)
|
|
1195
1205
|
{
|
|
@@ -1433,8 +1443,18 @@ TSharedPtr<FJsonValue> FEditorHandlers::GetBuildStatus(const TSharedPtr<FJsonObj
|
|
|
1433
1443
|
}
|
|
1434
1444
|
TSharedPtr<FJsonValue> FEditorHandlers::CaptureScreenshot(const TSharedPtr<FJsonObject>& Params)
|
|
1435
1445
|
{
|
|
1436
|
-
|
|
1437
|
-
|
|
1446
|
+
// #966: capture_scene_png names this parameter `outputPath` and this action
|
|
1447
|
+
// named it `filename`, for the same thing, so passing one to the other
|
|
1448
|
+
// failed on a call that was otherwise correct. Both are accepted by both.
|
|
1449
|
+
FString Filename = OptionalString(Params, TEXT("filename"));
|
|
1450
|
+
if (Filename.IsEmpty())
|
|
1451
|
+
{
|
|
1452
|
+
Filename = OptionalString(Params, TEXT("outputPath"));
|
|
1453
|
+
}
|
|
1454
|
+
if (Filename.IsEmpty())
|
|
1455
|
+
{
|
|
1456
|
+
return MCPError(TEXT("Missing 'filename' (also accepted as 'outputPath'): where to write the image"));
|
|
1457
|
+
}
|
|
1438
1458
|
|
|
1439
1459
|
// Ensure the filename has a proper extension
|
|
1440
1460
|
if (!Filename.EndsWith(TEXT(".png")) && !Filename.EndsWith(TEXT(".jpg")) && !Filename.EndsWith(TEXT(".bmp")))
|
|
@@ -1899,6 +1919,71 @@ TSharedPtr<FJsonValue> FEditorHandlers::ListDirtyPackages(const TSharedPtr<FJson
|
|
|
1899
1919
|
return MCPResult(Result);
|
|
1900
1920
|
}
|
|
1901
1921
|
|
|
1922
|
+
// #920 / #921: one read that answers "which world is open, and what is unsaved"
|
|
1923
|
+
// together. level(get_current) and list_dirty_packages are two calls, so the
|
|
1924
|
+
// editor can change between them and neither answer proves which world the
|
|
1925
|
+
// other described. Both reports were filed independently by the same team,
|
|
1926
|
+
// which is a fair signal that two calls is genuinely not good enough for a QA
|
|
1927
|
+
// gate. This runs in one game-thread dispatch, so the pair is consistent.
|
|
1928
|
+
TSharedPtr<FJsonValue> FEditorHandlers::GetWorldState(const TSharedPtr<FJsonObject>& Params)
|
|
1929
|
+
{
|
|
1930
|
+
if (!GEditor)
|
|
1931
|
+
{
|
|
1932
|
+
return MCPError(TEXT("Editor not available"));
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
UWorld* EditorWorld = GEditor->GetEditorWorldContext().World();
|
|
1936
|
+
if (!EditorWorld)
|
|
1937
|
+
{
|
|
1938
|
+
// Fail closed. An empty answer here would read as "nothing is open and
|
|
1939
|
+
// nothing is dirty", which is the reassuring shape of a wrong answer.
|
|
1940
|
+
return MCPError(TEXT("No editor world is currently resolvable, so world state cannot be reported"));
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
auto Result = MCPSuccess();
|
|
1944
|
+
|
|
1945
|
+
UPackage* WorldPackage = EditorWorld->GetOutermost();
|
|
1946
|
+
Result->SetStringField(TEXT("editorWorldName"), EditorWorld->GetName());
|
|
1947
|
+
Result->SetStringField(TEXT("editorWorldPackage"), WorldPackage ? WorldPackage->GetName() : FString());
|
|
1948
|
+
Result->SetBoolField(TEXT("worldPackageDirty"), WorldPackage != nullptr && WorldPackage->IsDirty());
|
|
1949
|
+
|
|
1950
|
+
if (ULevel* Persistent = EditorWorld->PersistentLevel)
|
|
1951
|
+
{
|
|
1952
|
+
if (UPackage* LevelPackage = Persistent->GetOutermost())
|
|
1953
|
+
{
|
|
1954
|
+
Result->SetStringField(TEXT("persistentLevelPackage"), LevelPackage->GetName());
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
// PIE and SIE are distinct states and a caller acting on the wrong one gets
|
|
1959
|
+
// a confidently wrong result, so report both rather than one "inPIE" flag.
|
|
1960
|
+
const bool bSimulating = GEditor->bIsSimulatingInEditor;
|
|
1961
|
+
const bool bPlayWorld = GEditor->PlayWorld != nullptr;
|
|
1962
|
+
Result->SetBoolField(TEXT("playInEditor"), bPlayWorld && !bSimulating);
|
|
1963
|
+
Result->SetBoolField(TEXT("simulateInEditor"), bSimulating);
|
|
1964
|
+
Result->SetStringField(TEXT("mode"), bSimulating ? TEXT("simulate") : (bPlayWorld ? TEXT("play") : TEXT("editor")));
|
|
1965
|
+
|
|
1966
|
+
const FDirtyEditorPackages Dirty = CollectDirtyEditorPackages();
|
|
1967
|
+
TArray<FString> All;
|
|
1968
|
+
All.Reserve(Dirty.Content.Num() + Dirty.Maps.Num());
|
|
1969
|
+
All.Append(Dirty.Content);
|
|
1970
|
+
All.Append(Dirty.Maps);
|
|
1971
|
+
All.Sort();
|
|
1972
|
+
|
|
1973
|
+
TArray<TSharedPtr<FJsonValue>> DirtyJson;
|
|
1974
|
+
DirtyJson.Reserve(All.Num());
|
|
1975
|
+
for (const FString& PackageName : All)
|
|
1976
|
+
{
|
|
1977
|
+
DirtyJson.Add(MakeShared<FJsonValueString>(PackageName));
|
|
1978
|
+
}
|
|
1979
|
+
Result->SetArrayField(TEXT("dirtyPackages"), DirtyJson);
|
|
1980
|
+
Result->SetNumberField(TEXT("dirtyPackageCount"), All.Num());
|
|
1981
|
+
Result->SetNumberField(TEXT("dirtyContentCount"), Dirty.Content.Num());
|
|
1982
|
+
Result->SetNumberField(TEXT("dirtyMapCount"), Dirty.Maps.Num());
|
|
1983
|
+
|
|
1984
|
+
return MCPResult(Result);
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1902
1987
|
TSharedPtr<FJsonValue> FEditorHandlers::RequestEditorShutdown(const TSharedPtr<FJsonObject>& Params)
|
|
1903
1988
|
{
|
|
1904
1989
|
if (!GEditor)
|
|
@@ -1956,7 +2041,8 @@ TSharedPtr<FJsonValue> FEditorHandlers::RequestEditorShutdown(const TSharedPtr<F
|
|
|
1956
2041
|
{
|
|
1957
2042
|
return true;
|
|
1958
2043
|
}
|
|
1959
|
-
|
|
2044
|
+
IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>(TEXT("MainFrame"));
|
|
2045
|
+
MainFrameModule.RequestCloseEditor();
|
|
1960
2046
|
return false;
|
|
1961
2047
|
}),
|
|
1962
2048
|
1.0f);
|
|
@@ -1969,15 +2055,14 @@ TSharedPtr<FJsonValue> FEditorHandlers::RequestEditorShutdown(const TSharedPtr<F
|
|
|
1969
2055
|
TSharedPtr<FJsonValue> FEditorHandlers::FocusViewportOnActor(const TSharedPtr<FJsonObject>& Params)
|
|
1970
2056
|
{
|
|
1971
2057
|
FString ActorLabel;
|
|
1972
|
-
if (auto Err =
|
|
2058
|
+
if (auto Err = RequireStringAlt(Params, TEXT("actorLabel"), TEXT("actorPath"), ActorLabel)) return Err;
|
|
1973
2059
|
|
|
1974
2060
|
REQUIRE_EDITOR_WORLD(World);
|
|
1975
2061
|
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
}
|
|
2062
|
+
TSharedPtr<FJsonValue> ActorErr;
|
|
2063
|
+
AActor* TargetActor = MCPResolveActor(World, Params, ActorErr);
|
|
2064
|
+
if (!TargetActor) return ActorErr;
|
|
2065
|
+
ActorLabel = TargetActor->GetActorLabel();
|
|
1981
2066
|
|
|
1982
2067
|
// Get the viewport client
|
|
1983
2068
|
FLevelEditorViewportClient* ViewportClient = GCurrentLevelEditingViewportClient;
|
|
@@ -2020,6 +2105,7 @@ TSharedPtr<FJsonValue> FEditorHandlers::FocusViewportOnActor(const TSharedPtr<FJ
|
|
|
2020
2105
|
auto Result = MCPSuccess();
|
|
2021
2106
|
Result->SetObjectField(TEXT("viewLocation"), LocObj);
|
|
2022
2107
|
Result->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
2108
|
+
Result->SetStringField(TEXT("actorPath"), TargetActor->GetPathName());
|
|
2023
2109
|
return MCPResult(Result);
|
|
2024
2110
|
}
|
|
2025
2111
|
TSharedPtr<FJsonValue> FEditorHandlers::CreateNewLevel(const TSharedPtr<FJsonObject>& Params)
|
|
@@ -2450,8 +2536,18 @@ TSharedPtr<FJsonValue> FEditorHandlers::CaptureScenePng(const TSharedPtr<FJsonOb
|
|
|
2450
2536
|
UWorld* World = ResolveWorldFromParams(Params, *WorldScope);
|
|
2451
2537
|
if (!World) return MCPError(FString::Printf(TEXT("World not available for scope '%s'"), *WorldScope));
|
|
2452
2538
|
|
|
2453
|
-
|
|
2454
|
-
|
|
2539
|
+
// #966: capture_screenshot names this parameter `filename` and this action
|
|
2540
|
+
// named it `outputPath`, for the same thing, so passing one to the other
|
|
2541
|
+
// failed on a call that was otherwise correct. Both are accepted by both.
|
|
2542
|
+
FString OutputPath = OptionalString(Params, TEXT("outputPath"));
|
|
2543
|
+
if (OutputPath.IsEmpty())
|
|
2544
|
+
{
|
|
2545
|
+
OutputPath = OptionalString(Params, TEXT("filename"));
|
|
2546
|
+
}
|
|
2547
|
+
if (OutputPath.IsEmpty())
|
|
2548
|
+
{
|
|
2549
|
+
return MCPError(TEXT("Missing 'outputPath' (also accepted as 'filename'): where to write the PNG"));
|
|
2550
|
+
}
|
|
2455
2551
|
|
|
2456
2552
|
// Resolution
|
|
2457
2553
|
int32 Width = OptionalInt(Params, TEXT("width"), 1280);
|
|
@@ -2467,10 +2563,18 @@ TSharedPtr<FJsonValue> FEditorHandlers::CaptureScenePng(const TSharedPtr<FJsonOb
|
|
|
2467
2563
|
// #599: focusActorLabel frames the capture on a specific actor by computing
|
|
2468
2564
|
// a camera position from the actor's bounds and looking at its center.
|
|
2469
2565
|
const FString FocusLabel = OptionalString(Params, TEXT("focusActorLabel"));
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2566
|
+
const FString FocusPath = OptionalString(Params, TEXT("focusActorPath"));
|
|
2567
|
+
if (!FocusLabel.IsEmpty() || !FocusPath.IsEmpty())
|
|
2568
|
+
{
|
|
2569
|
+
// #983: framing on the wrong copy of a duplicated label is a capture
|
|
2570
|
+
// that quietly shows somewhere else entirely.
|
|
2571
|
+
FMCPActorSelector FocusSel;
|
|
2572
|
+
FocusSel.LabelKey = TEXT("focusActorLabel");
|
|
2573
|
+
FocusSel.PathKey = TEXT("focusActorPath");
|
|
2574
|
+
FocusSel.Match = EMCPActorMatch::LabelNameOrPath;
|
|
2575
|
+
TSharedPtr<FJsonValue> FocusErr;
|
|
2576
|
+
AActor* Focus = MCPResolveActor(World, Params, FocusErr, FocusSel);
|
|
2577
|
+
if (!Focus) return FocusErr;
|
|
2474
2578
|
FVector Origin, Extent;
|
|
2475
2579
|
Focus->GetActorBounds(false, Origin, Extent);
|
|
2476
2580
|
const double Radius = FMath::Max(Extent.Size(), 50.0);
|
|
@@ -2483,27 +2587,69 @@ TSharedPtr<FJsonValue> FEditorHandlers::CaptureScenePng(const TSharedPtr<FJsonOb
|
|
|
2483
2587
|
Rotation = (Origin - Location).Rotation();
|
|
2484
2588
|
}
|
|
2485
2589
|
|
|
2486
|
-
//
|
|
2590
|
+
// #966: the capture actor used to be spawned once and LEFT IN THE LEVEL.
|
|
2591
|
+
// It is a level actor, so it was saved into the map and committed to source
|
|
2592
|
+
// control as though somebody had authored it, and list_dirty_packages
|
|
2593
|
+
// reported nothing while it sat there, so the usual "did I change
|
|
2594
|
+
// anything" check missed it entirely. A capture must leave the level
|
|
2595
|
+
// exactly as it found it.
|
|
2596
|
+
//
|
|
2597
|
+
// Two halves. First, sweep any debris earlier builds left behind, so a
|
|
2598
|
+
// project that already has one is cleaned by the next capture rather than
|
|
2599
|
+
// by hand.
|
|
2487
2600
|
static const FString CaptureLabel = TEXT("__ClaudeSceneCapture");
|
|
2488
|
-
|
|
2489
|
-
for (TActorIterator<ASceneCapture2D> It(World); It; ++It)
|
|
2601
|
+
int32 RemovedStrayCaptures = 0;
|
|
2490
2602
|
{
|
|
2491
|
-
|
|
2603
|
+
TArray<ASceneCapture2D*> Strays;
|
|
2604
|
+
for (TActorIterator<ASceneCapture2D> It(World); It; ++It)
|
|
2492
2605
|
{
|
|
2493
|
-
|
|
2494
|
-
|
|
2606
|
+
if (It->GetActorLabel() == CaptureLabel)
|
|
2607
|
+
{
|
|
2608
|
+
Strays.Add(*It);
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
for (ASceneCapture2D* Stray : Strays)
|
|
2612
|
+
{
|
|
2613
|
+
// These ones ARE in the map, so their removal is a real edit and
|
|
2614
|
+
// goes through Modify(): the level has to become dirty, or the
|
|
2615
|
+
// debris comes straight back on the next load.
|
|
2616
|
+
if (IsValid(Stray) && World->DestroyActor(Stray))
|
|
2617
|
+
{
|
|
2618
|
+
++RemovedStrayCaptures;
|
|
2619
|
+
}
|
|
2495
2620
|
}
|
|
2496
2621
|
}
|
|
2497
|
-
|
|
2622
|
+
|
|
2623
|
+
// Second, this capture's own actor: transient, outside the scene outliner,
|
|
2624
|
+
// in no actor package of its own, and destroyed on every exit from here.
|
|
2625
|
+
// The transient flag alone is not enough, because the debris that prompted
|
|
2626
|
+
// this was visible in the outliner and in the map's actor list either way.
|
|
2627
|
+
FActorSpawnParameters SpawnParams;
|
|
2628
|
+
SpawnParams.ObjectFlags |= RF_Transient;
|
|
2629
|
+
#if WITH_EDITOR
|
|
2630
|
+
SpawnParams.bTemporaryEditorActor = true;
|
|
2631
|
+
SpawnParams.bHideFromSceneOutliner = true;
|
|
2632
|
+
SpawnParams.bCreateActorPackage = false;
|
|
2633
|
+
#endif
|
|
2634
|
+
ASceneCapture2D* CaptureActor = World->SpawnActor<ASceneCapture2D>(ASceneCapture2D::StaticClass(), Location, Rotation, SpawnParams);
|
|
2635
|
+
if (!CaptureActor) return MCPError(TEXT("Failed to spawn SceneCapture2D actor"));
|
|
2636
|
+
CaptureActor->SetActorHiddenInGame(true);
|
|
2637
|
+
|
|
2638
|
+
ON_SCOPE_EXIT
|
|
2498
2639
|
{
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2640
|
+
if (IsValid(CaptureActor))
|
|
2641
|
+
{
|
|
2642
|
+
// Drop the render target first: the component holds the only
|
|
2643
|
+
// reference keeping it alive past this call.
|
|
2644
|
+
if (USceneCaptureComponent2D* Dying = CaptureActor->GetCaptureComponent2D())
|
|
2645
|
+
{
|
|
2646
|
+
Dying->TextureTarget = nullptr;
|
|
2647
|
+
}
|
|
2648
|
+
// bShouldModifyLevel=false: this actor was never part of the map,
|
|
2649
|
+
// so removing it is not an edit and must not dirty the package.
|
|
2650
|
+
World->DestroyActor(CaptureActor, /*bNetForce*/ false, /*bShouldModifyLevel*/ false);
|
|
2651
|
+
}
|
|
2652
|
+
};
|
|
2507
2653
|
|
|
2508
2654
|
USceneCaptureComponent2D* Comp = CaptureActor->GetCaptureComponent2D();
|
|
2509
2655
|
if (!Comp) return MCPError(TEXT("SceneCapture2D has no capture component"));
|
|
@@ -2557,7 +2703,13 @@ TSharedPtr<FJsonValue> FEditorHandlers::CaptureScenePng(const TSharedPtr<FJsonOb
|
|
|
2557
2703
|
Result->SetNumberField(TEXT("width"), Width);
|
|
2558
2704
|
Result->SetNumberField(TEXT("height"), Height);
|
|
2559
2705
|
Result->SetNumberField(TEXT("sizeBytes"), (double)Size);
|
|
2560
|
-
|
|
2706
|
+
// The capture actor is gone by the time this reaches the caller, so say so
|
|
2707
|
+
// rather than naming an actor they could go and look for.
|
|
2708
|
+
Result->SetBoolField(TEXT("captureActorRemoved"), true);
|
|
2709
|
+
if (RemovedStrayCaptures > 0)
|
|
2710
|
+
{
|
|
2711
|
+
Result->SetNumberField(TEXT("strayCaptureActorsRemoved"), RemovedStrayCaptures);
|
|
2712
|
+
}
|
|
2561
2713
|
return MCPResult(Result);
|
|
2562
2714
|
}
|
|
2563
2715
|
|
|
@@ -2625,12 +2777,27 @@ TSharedPtr<FJsonValue> FEditorHandlers::ListFunctionLibraries(const TSharedPtr<F
|
|
|
2625
2777
|
// Headlessly run registered Automation tests whose name matches a filter and
|
|
2626
2778
|
// report pass/fail + errors. Uses FAutomationTestFramework's synchronous
|
|
2627
2779
|
// StartTestByName/StopTest, which fully runs non-latent tests. Latent tests
|
|
2628
|
-
// (that enqueue cross-frame commands)
|
|
2629
|
-
//
|
|
2780
|
+
// (that enqueue cross-frame commands) get a bounded drain, and one that has not
|
|
2781
|
+
// finished when the budget runs out is abandoned and reported, never stopped
|
|
2782
|
+
// mid-queue.
|
|
2783
|
+
//
|
|
2784
|
+
// #993: StopTest asserts on LatentCommands.IsEmpty() inside InternalStopTest,
|
|
2785
|
+
// and this handler used to call it unconditionally after a drain loop that gave
|
|
2786
|
+
// up after a fixed iteration count. A CQTest test that starts multi-client PIE
|
|
2787
|
+
// still had commands queued at that point, so the assert fired and took the
|
|
2788
|
+
// editor down: the caller saw a WebSocket close 1006, not a test result. A
|
|
2789
|
+
// handler must never take the editor down.
|
|
2630
2790
|
TSharedPtr<FJsonValue> FEditorHandlers::RunAutomationTests(const TSharedPtr<FJsonObject>& Params)
|
|
2631
2791
|
{
|
|
2632
2792
|
const FString NameFilter = OptionalString(Params, TEXT("filter"));
|
|
2633
2793
|
const int32 MaxTests = OptionalInt(Params, TEXT("maxTests"), 50);
|
|
2794
|
+
// How long one test's latent queue may take. The handler occupies the game
|
|
2795
|
+
// thread for its whole run, so this is deliberately small by default: a
|
|
2796
|
+
// latent command that needs real frames (PIE, anything waiting on a world
|
|
2797
|
+
// tick) cannot make progress from in here however long it is given, and
|
|
2798
|
+
// waiting longer only holds the editor still for longer.
|
|
2799
|
+
const double LatentBudgetSeconds = FMath::Clamp(
|
|
2800
|
+
OptionalNumber(Params, TEXT("latentTimeoutSeconds"), 5.0), 0.0, 120.0);
|
|
2634
2801
|
|
|
2635
2802
|
// #765: this handler runs tests SYNCHRONOUSLY via StartTestByName inside a
|
|
2636
2803
|
// single tick, so it never depended on the interactive-frame-rate gate that
|
|
@@ -2663,7 +2830,7 @@ TSharedPtr<FJsonValue> FEditorHandlers::RunAutomationTests(const TSharedPtr<FJso
|
|
|
2663
2830
|
Framework.GetValidTestNames(AllTests);
|
|
2664
2831
|
|
|
2665
2832
|
TArray<TSharedPtr<FJsonValue>> Results;
|
|
2666
|
-
int32 Ran = 0, Passed = 0, Failed = 0;
|
|
2833
|
+
int32 Ran = 0, Passed = 0, Failed = 0, Abandoned = 0;
|
|
2667
2834
|
for (const FAutomationTestInfo& Info : AllTests)
|
|
2668
2835
|
{
|
|
2669
2836
|
const FString TestName = Info.GetTestName();
|
|
@@ -2677,21 +2844,57 @@ TSharedPtr<FJsonValue> FEditorHandlers::RunAutomationTests(const TSharedPtr<FJso
|
|
|
2677
2844
|
|
|
2678
2845
|
Framework.StartTestByName(TestName, /*RoleIndex*/ 0);
|
|
2679
2846
|
|
|
2680
|
-
//
|
|
2681
|
-
|
|
2682
|
-
|
|
2847
|
+
// Drain the latent queue, bounded by wall clock rather than by a fixed
|
|
2848
|
+
// iteration count. The old bound was 1000 iterations of a zero-length
|
|
2849
|
+
// sleep, which elapses in no time at all and gave a command that polls
|
|
2850
|
+
// for a condition no real chance to reach one. Network commands are
|
|
2851
|
+
// pumped alongside, because the framework's own per-frame path does and
|
|
2852
|
+
// a latent queue behind an undelivered network command never empties.
|
|
2853
|
+
const double DrainStartedAt = FPlatformTime::Seconds();
|
|
2854
|
+
while (!Framework.ExecuteLatentCommands()
|
|
2855
|
+
&& (FPlatformTime::Seconds() - DrainStartedAt) < LatentBudgetSeconds)
|
|
2683
2856
|
{
|
|
2684
|
-
|
|
2857
|
+
Framework.ExecuteNetworkCommands();
|
|
2858
|
+
FPlatformProcess::Sleep(0.001f);
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
// #993: StopTest asserts that the latent queue is empty. Anything still
|
|
2862
|
+
// queued here needs frames this handler cannot give it, because the
|
|
2863
|
+
// handler owns the game thread for its whole run and the engine loop
|
|
2864
|
+
// only advances once it returns. Clear the queue and record the test as
|
|
2865
|
+
// abandoned; calling StopTest with commands outstanding is what took
|
|
2866
|
+
// the editor down.
|
|
2867
|
+
const bool bAbandoned = !Framework.IsLatentCommandQueueEmpty();
|
|
2868
|
+
if (bAbandoned)
|
|
2869
|
+
{
|
|
2870
|
+
Framework.DequeueAllCommands();
|
|
2685
2871
|
}
|
|
2686
2872
|
|
|
2687
2873
|
FAutomationTestExecutionInfo ExecInfo;
|
|
2688
|
-
const bool
|
|
2874
|
+
const bool bStopReportedPass = Framework.StopTest(ExecInfo);
|
|
2875
|
+
const bool bPassed = bStopReportedPass && !bAbandoned;
|
|
2689
2876
|
++Ran;
|
|
2690
|
-
if (
|
|
2877
|
+
if (bAbandoned) ++Abandoned;
|
|
2878
|
+
else if (bPassed) ++Passed;
|
|
2879
|
+
else ++Failed;
|
|
2880
|
+
|
|
2881
|
+
// An abandoned test may have left PIE running, and leaving it up would
|
|
2882
|
+
// silently change what every later call in this session sees.
|
|
2883
|
+
if (bAbandoned && GEditor && (GEditor->PlayWorld != nullptr || GEditor->bIsSimulatingInEditor))
|
|
2884
|
+
{
|
|
2885
|
+
GEditor->RequestEndPlayMap();
|
|
2886
|
+
}
|
|
2691
2887
|
|
|
2692
2888
|
TSharedPtr<FJsonObject> R = MakeShared<FJsonObject>();
|
|
2693
2889
|
R->SetStringField(TEXT("test"), DisplayName.IsEmpty() ? TestName : DisplayName);
|
|
2694
2890
|
R->SetBoolField(TEXT("passed"), bPassed);
|
|
2891
|
+
R->SetBoolField(TEXT("abandoned"), bAbandoned);
|
|
2892
|
+
if (bAbandoned)
|
|
2893
|
+
{
|
|
2894
|
+
R->SetStringField(TEXT("abandonedReason"), FString::Printf(
|
|
2895
|
+
TEXT("Latent commands were still queued after %.1fs. They need engine frames, which cannot happen while this handler holds the game thread, so the test was abandoned rather than stopped mid-queue (stopping mid-queue asserts and terminates the editor). Run this one from the editor's Automation window, or with -ExecCmds=\"Automation RunTests %s\" at launch."),
|
|
2896
|
+
LatentBudgetSeconds, *TestName));
|
|
2897
|
+
}
|
|
2695
2898
|
R->SetNumberField(TEXT("errors"), ExecInfo.GetErrorTotal());
|
|
2696
2899
|
R->SetNumberField(TEXT("warnings"), ExecInfo.GetWarningTotal());
|
|
2697
2900
|
if (ExecInfo.GetErrorTotal() > 0)
|
|
@@ -2715,6 +2918,14 @@ TSharedPtr<FJsonValue> FEditorHandlers::RunAutomationTests(const TSharedPtr<FJso
|
|
|
2715
2918
|
Result->SetNumberField(TEXT("ran"), Ran);
|
|
2716
2919
|
Result->SetNumberField(TEXT("passed"), Passed);
|
|
2717
2920
|
Result->SetNumberField(TEXT("failed"), Failed);
|
|
2921
|
+
Result->SetNumberField(TEXT("abandoned"), Abandoned);
|
|
2922
|
+
Result->SetNumberField(TEXT("latentTimeoutSeconds"), LatentBudgetSeconds);
|
|
2923
|
+
if (Abandoned > 0)
|
|
2924
|
+
{
|
|
2925
|
+
Result->SetStringField(TEXT("warning"), FString::Printf(
|
|
2926
|
+
TEXT("%d test(s) were abandoned with latent commands still queued. They need engine frames, and this handler holds the game thread for its whole run, so it cannot supply any. Raising latentTimeoutSeconds helps a test that only polls; a test that starts PIE needs the editor's Automation window or -ExecCmds=\"Automation RunTests <name>\" at launch. Nothing was stopped mid-queue, which is what used to terminate the editor (#993)."),
|
|
2927
|
+
Abandoned));
|
|
2928
|
+
}
|
|
2718
2929
|
Result->SetArrayField(TEXT("results"), Results);
|
|
2719
2930
|
return MCPResult(Result);
|
|
2720
2931
|
}
|
|
@@ -144,6 +144,7 @@ private:
|
|
|
144
144
|
static TSharedPtr<FJsonValue> SaveDirty(const TSharedPtr<FJsonObject>& Params);
|
|
145
145
|
// #340: enumerate currently-dirty content/map packages
|
|
146
146
|
static TSharedPtr<FJsonValue> ListDirtyPackages(const TSharedPtr<FJsonObject>& Params);
|
|
147
|
+
static TSharedPtr<FJsonValue> GetWorldState(const TSharedPtr<FJsonObject>& Params);
|
|
147
148
|
// Gracefully close the editor after dirty-package and PIE safety checks.
|
|
148
149
|
static TSharedPtr<FJsonValue> RequestEditorShutdown(const TSharedPtr<FJsonObject>& Params);
|
|
149
150
|
// PIE runtime inspection/control (#739/#756/#757/#761/#764/#770/#777/#778).
|
|
@@ -154,6 +155,9 @@ private:
|
|
|
154
155
|
static TSharedPtr<FJsonValue> ReadBoneTransforms(const TSharedPtr<FJsonObject>& Params);
|
|
155
156
|
static TSharedPtr<FJsonValue> TeleportRuntimeActor(const TSharedPtr<FJsonObject>& Params);
|
|
156
157
|
static TSharedPtr<FJsonValue> SetMovementMode(const TSharedPtr<FJsonObject>& Params);
|
|
158
|
+
// Bounded, reversible visibility changes on live PIE actors/components.
|
|
159
|
+
static TSharedPtr<FJsonValue> SetRuntimeVisibility(const TSharedPtr<FJsonObject>& Params);
|
|
160
|
+
static TSharedPtr<FJsonValue> RestoreRuntimeVisibility(const TSharedPtr<FJsonObject>& Params);
|
|
157
161
|
// #802: locate live UObject instances, and write to one.
|
|
158
162
|
static TSharedPtr<FJsonValue> FindLiveObjects(const TSharedPtr<FJsonObject>& Params);
|
|
159
163
|
static TSharedPtr<FJsonValue> SetObjectProperty(const TSharedPtr<FJsonObject>& Params);
|