ue-mcp 1.2.4 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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/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/project.js +47 -20
- package/dist/tools/project.js.map +1 -1
- package/dist/types.d.ts +21 -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
|
@@ -8,8 +8,67 @@ public class UE_MCP_Bridge : ModuleRules
|
|
|
8
8
|
// new .cpp until this file changes.
|
|
9
9
|
// Private/Handlers/AssetHandlers_BulkUpsert.cpp: UBT caches the module's
|
|
10
10
|
// file list and will not pick up a new .cpp until this file changes.
|
|
11
|
+
// Private/Handlers/LevelHandlers_Inspection.cpp and its focused test: same reason.
|
|
11
12
|
// Private/BridgeStateFiles.cpp, Private/BridgeParamEcho.cpp and
|
|
12
13
|
// Private/Tests/BridgeProtocolTests.cpp: same reason.
|
|
14
|
+
// Private/Tests/SequencerHandlerTests.cpp: same reason.
|
|
15
|
+
// Private/Handlers/LevelHandlers_InstanceProjection.cpp and
|
|
16
|
+
// Private/Tests/LevelInstanceProjectionTests.cpp: same reason.
|
|
17
|
+
// Private/Tests/PackageSaveExtensionTests.cpp: same reason.
|
|
18
|
+
// Private/Handlers/AnimationHandlers_ControlRigSequencer.cpp,
|
|
19
|
+
// Private/Handlers/AnimationHandlers_Validation.cpp,
|
|
20
|
+
// Private/Handlers/AnimationHandlers_IKRigAuthoring.cpp and
|
|
21
|
+
// Private/Handlers/AnimationHandlers_IKRetargeterAuthoring.cpp plus
|
|
22
|
+
// Private/Tests/AnimationControlRigTimelineTests.cpp: same reason.
|
|
23
|
+
// Private/Tests/DataTableRowWriteTests.cpp: same reason.
|
|
24
|
+
// Private/Handlers/EditorHandlers_RuntimeVisibility.cpp and
|
|
25
|
+
// Private/Tests/RuntimeVisibilityTests.cpp: same reason.
|
|
26
|
+
// Private/Handlers/MaterialHandlers_Build.cpp and
|
|
27
|
+
// Private/Tests/MaterialBuildTests.cpp: same reason.
|
|
28
|
+
// Private/Handlers/AssetHandlers_Geometry.cpp,
|
|
29
|
+
// Private/Handlers/AnimationHandlers_Pose.cpp,
|
|
30
|
+
// Private/Tests/MeshGeometryTests.cpp and
|
|
31
|
+
// Private/Tests/AnimationPoseTests.cpp: same reason.
|
|
32
|
+
// Private/Tests/WidgetBlueprintResolveTests.cpp and
|
|
33
|
+
// Private/Tests/GasLiveAttributeTests.cpp: same reason.
|
|
34
|
+
// Private/Tests/BlueprintHandlerSurfaceTests.cpp: same reason.
|
|
35
|
+
// Private/Handlers/BlueprintHandlers_Search.cpp: same reason.
|
|
36
|
+
// Private/Handlers/LevelHandlers_Query.cpp,
|
|
37
|
+
// Private/Handlers/LevelHandlers_BatchWrite.cpp,
|
|
38
|
+
// Private/Handlers/LevelHandlers_Convert.cpp,
|
|
39
|
+
// Private/Handlers/LevelHandlers_Refresh.cpp,
|
|
40
|
+
// Private/Handlers/LevelHandlers_Transient.cpp,
|
|
41
|
+
// Private/Handlers/AssetHandlers_BulkRead.cpp,
|
|
42
|
+
// Private/Handlers/FoliageHandlers_Batch.cpp,
|
|
43
|
+
// Private/Tests/LevelQueryComponentsTests.cpp,
|
|
44
|
+
// Private/Tests/LevelBatchWriteTests.cpp,
|
|
45
|
+
// Private/Tests/LevelRefreshTests.cpp,
|
|
46
|
+
// Private/Tests/LevelConvertBrushesTests.cpp,
|
|
47
|
+
// Private/Tests/LevelTransientActorTests.cpp,
|
|
48
|
+
// Private/Tests/AssetBulkReadTests.cpp and
|
|
49
|
+
// Private/Tests/FoliageBatchTests.cpp: same reason.
|
|
50
|
+
// Private/Tests/EditorFunctionCallTests.cpp (#885/#969): same reason.
|
|
51
|
+
// Private/Tests/SequencerScrubTests.cpp (#881): same reason.
|
|
52
|
+
// Private/Tests/AssetPathResolutionTests.cpp and
|
|
53
|
+
// Private/Tests/AssetPropertyPersistTests.cpp: same reason.
|
|
54
|
+
// Private/Handlers/AssetHandlers_Subobject.cpp,
|
|
55
|
+
// Private/Handlers/AssetHandlers_Redirectors.cpp and
|
|
56
|
+
// Private/Tests/AssetSubobjectTests.cpp: same reason.
|
|
57
|
+
// Private/Tests/AssetDeleteGuardTests.cpp (#976): same reason.
|
|
58
|
+
// Private/Tests/PackageWriteGuardTests.cpp (#932): same reason.
|
|
59
|
+
// Private/Handlers/BlueprintHandlers_Collision.cpp and
|
|
60
|
+
// Private/Tests/CollisionQueryTests.cpp (#925): same reason.
|
|
61
|
+
// Private/Handlers/AssetHandlers_MeshBoolean.cpp and
|
|
62
|
+
// Private/Tests/MeshBooleanTests.cpp (#916): same reason.
|
|
63
|
+
// Private/Tests/LevelTraceWorldScopeTests.cpp (#933): same reason.
|
|
64
|
+
// Private/Tests/LandscapeSampleTests.cpp (#939): same reason.
|
|
65
|
+
// Private/Handlers/LevelHandlers_PostProcess.cpp and
|
|
66
|
+
// Private/Tests/LevelPostProcessOverrideTests.cpp (#950): same reason.
|
|
67
|
+
// Private/Handlers/LevelHandlers_Save.cpp and
|
|
68
|
+
// Private/Tests/LevelSaveReportTests.cpp (#964): same reason.
|
|
69
|
+
// Private/Tests/LevelComponentTreeInstanceCountTests.cpp (#986): same reason.
|
|
70
|
+
// Private/Handlers/LevelHandlers_WorldPartitionSettings.cpp and
|
|
71
|
+
// Private/Tests/LevelWorldPartitionSettingsTests.cpp (#985): same reason.
|
|
13
72
|
public UE_MCP_Bridge(ReadOnlyTargetRules Target) : base(Target)
|
|
14
73
|
{
|
|
15
74
|
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
|
@@ -30,9 +89,25 @@ public class UE_MCP_Bridge : ModuleRules
|
|
|
30
89
|
new string[]
|
|
31
90
|
{
|
|
32
91
|
"AIModule",
|
|
92
|
+
// #889: authoring a BehaviorTree means driving UBehaviorTreeGraph
|
|
93
|
+
// and its node classes, then calling UpdateAsset to compile the
|
|
94
|
+
// graph into the runnable UBTCompositeNode tree. That orchestration
|
|
95
|
+
// lives only in BehaviorTreeEditor (with FGraphNodeClassData and
|
|
96
|
+
// UAIGraphNode::AddSubNode coming from AIGraph beneath it) and is
|
|
97
|
+
// not exposed to script, so no reflected runtime API can stand in
|
|
98
|
+
// for it. Both are editor modules, which this plugin already is:
|
|
99
|
+
// its .uplugin declares Type "Editor" and UnrealEd, UMGEditor and
|
|
100
|
+
// MaterialEditor are already linked the same way.
|
|
101
|
+
"AIGraph",
|
|
102
|
+
"BehaviorTreeEditor",
|
|
33
103
|
"MessageLog",
|
|
104
|
+
"AnimationCore",
|
|
34
105
|
"AnimGraph",
|
|
35
106
|
"AnimationEditor",
|
|
107
|
+
// UAnimPoseExtensions / FAnimPoseEvaluationOptions (AnimPose.h),
|
|
108
|
+
// the engine's own pose evaluator, used by animation(sample_pose)
|
|
109
|
+
// and animation(measure_natural_speed).
|
|
110
|
+
"AnimationBlueprintLibrary",
|
|
36
111
|
"AnimationModifiers",
|
|
37
112
|
"AssetRegistry",
|
|
38
113
|
"AssetTools",
|
|
@@ -51,6 +126,7 @@ public class UE_MCP_Bridge : ModuleRules
|
|
|
51
126
|
"ContentBrowser",
|
|
52
127
|
"ControlRig",
|
|
53
128
|
"ControlRigDeveloper",
|
|
129
|
+
"ControlRigEditor",
|
|
54
130
|
"RigVMDeveloper",
|
|
55
131
|
"DataValidation",
|
|
56
132
|
"EditorScriptingUtilities",
|
|
@@ -74,6 +150,7 @@ public class UE_MCP_Bridge : ModuleRules
|
|
|
74
150
|
"LevelEditor",
|
|
75
151
|
"LevelSequence",
|
|
76
152
|
"LevelSequenceEditor",
|
|
153
|
+
"MainFrame",
|
|
77
154
|
"MaterialEditor",
|
|
78
155
|
"MovieScene",
|
|
79
156
|
"MovieSceneTracks",
|
|
@@ -90,6 +167,7 @@ public class UE_MCP_Bridge : ModuleRules
|
|
|
90
167
|
"PythonScriptPlugin",
|
|
91
168
|
"Sequencer",
|
|
92
169
|
"Settings",
|
|
170
|
+
"SkeletalMeshEditor",
|
|
93
171
|
"Slate",
|
|
94
172
|
"SlateCore",
|
|
95
173
|
"StateTreeModule",
|
|
@@ -139,4 +217,13 @@ public class UE_MCP_Bridge : ModuleRules
|
|
|
139
217
|
}
|
|
140
218
|
}
|
|
141
219
|
|
|
220
|
+
// Rescan trigger: level-script handler automation coverage added.
|
|
142
221
|
// Rescan trigger: round 2 added handler translation units.
|
|
222
|
+
// Rescan trigger: Private/Tests/GameThreadGateTests.cpp (#968).
|
|
223
|
+
// Rescan trigger: Private/Tests/AutomationRunnerTests.cpp (#993).
|
|
224
|
+
// Rescan trigger: Mass and skeletal-mesh handler translation units.
|
|
225
|
+
// Rescan trigger: FInstancedStruct scalar, wrapper-array and nested path tests added.
|
|
226
|
+
// Round 3: Private/Handlers/GameplayHandlers_BehaviorTree.cpp and
|
|
227
|
+
// Private/Tests/BehaviorTreeNodeTests.cpp.
|
|
228
|
+
// Round 4: Private/Handlers/GameplayHandlers_BTAuthoring.cpp and
|
|
229
|
+
// Private/Tests/BehaviorTreeAuthoringTests.cpp.
|
|
@@ -128,10 +128,25 @@ void FMCPEngineStatus::Install()
|
|
|
128
128
|
|
|
129
129
|
RebindFeedbackContextIfNeeded();
|
|
130
130
|
|
|
131
|
+
// #990: nothing polls a commandlet's engine state, and 32 of them writing
|
|
132
|
+
// one document four times a second was a build-breaking error storm. Do not
|
|
133
|
+
// even start the thread there.
|
|
134
|
+
if (!ShouldPublishStatus())
|
|
135
|
+
{
|
|
136
|
+
UE_LOG(LogMCPBridgeStatus, Log,
|
|
137
|
+
TEXT("[UE-MCP] Engine status snapshot installed without a writer thread: this process is a commandlet, and nothing polls a commandlet's engine state."));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Per-process status files from editors that crashed. Swept once, here, by
|
|
142
|
+
// the next process that can prove them stale, so a machine that crashes
|
|
143
|
+
// repeatedly does not accumulate a directory of them.
|
|
144
|
+
RemoveStaleInstanceStatusFiles();
|
|
145
|
+
|
|
131
146
|
bStopWriter = false;
|
|
132
147
|
WriterThread = FRunnableThread::Create(this, TEXT("MCPEngineStatusWriter"), 0, TPri_BelowNormal);
|
|
133
148
|
|
|
134
|
-
UE_LOG(LogMCPBridgeStatus, Log, TEXT("[UE-MCP] Engine status snapshot installed -> %s"), *
|
|
149
|
+
UE_LOG(LogMCPBridgeStatus, Log, TEXT("[UE-MCP] Engine status snapshot installed -> %s"), *InstanceStatusFilePath());
|
|
135
150
|
}
|
|
136
151
|
|
|
137
152
|
void FMCPEngineStatus::Shutdown()
|
|
@@ -188,9 +203,36 @@ void FMCPEngineStatus::Shutdown()
|
|
|
188
203
|
ModalProvider = nullptr;
|
|
189
204
|
CompileProvider = nullptr;
|
|
190
205
|
|
|
191
|
-
// Leave no stale file behind: a status
|
|
192
|
-
//
|
|
193
|
-
|
|
206
|
+
// Leave no stale file behind: a status from a dead editor claiming a 40%
|
|
207
|
+
// slow task is worse than no file at all. This process's own file always
|
|
208
|
+
// goes; the shared one only if this process is the last thing that wrote
|
|
209
|
+
// it, so an editor shutting down does not blind a client watching another
|
|
210
|
+
// editor of the same project (#990).
|
|
211
|
+
IFileManager::Get().Delete(*InstanceStatusFilePath(), false, false, true);
|
|
212
|
+
if (SharedStatusBelongsToThisProcess())
|
|
213
|
+
{
|
|
214
|
+
IFileManager::Get().Delete(*StatusFilePath(), false, false, true);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
bool FMCPEngineStatus::SharedStatusBelongsToThisProcess()
|
|
219
|
+
{
|
|
220
|
+
FString Raw;
|
|
221
|
+
if (!FFileHelper::LoadFileToString(Raw, *StatusFilePath()))
|
|
222
|
+
{
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
TSharedPtr<FJsonObject> Parsed;
|
|
226
|
+
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Raw);
|
|
227
|
+
if (!FJsonSerializer::Deserialize(Reader, Parsed) || !Parsed.IsValid())
|
|
228
|
+
{
|
|
229
|
+
// Unreadable, so nothing can be shown to own it. Leaving it costs one
|
|
230
|
+
// stale file; removing it could take a live editor's snapshot away.
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
double Pid = 0.0;
|
|
234
|
+
return Parsed->TryGetNumberField(TEXT("pid"), Pid)
|
|
235
|
+
&& (uint32)Pid == FPlatformProcess::GetCurrentProcessId();
|
|
194
236
|
}
|
|
195
237
|
|
|
196
238
|
void FMCPEngineStatus::RebindFeedbackContextIfNeeded()
|
|
@@ -370,6 +412,10 @@ TSharedPtr<FJsonObject> FMCPEngineStatus::Snapshot() const
|
|
|
370
412
|
FScopeLock Lock(&Mutex);
|
|
371
413
|
|
|
372
414
|
Out->SetStringField(TEXT("phase"), Phase);
|
|
415
|
+
// #990: which process this describes. One project directory can hold the
|
|
416
|
+
// status of several, and a document that does not name its subject cannot
|
|
417
|
+
// be told apart from one that does.
|
|
418
|
+
Out->SetNumberField(TEXT("pid"), (double)FPlatformProcess::GetCurrentProcessId());
|
|
373
419
|
Out->SetNumberField(TEXT("uptimeSeconds"), Now - InstallSeconds);
|
|
374
420
|
Out->SetNumberField(TEXT("modulesLoaded"), ModulesLoaded);
|
|
375
421
|
|
|
@@ -450,13 +496,105 @@ TSharedPtr<FJsonObject> FMCPEngineStatus::Snapshot() const
|
|
|
450
496
|
return Out;
|
|
451
497
|
}
|
|
452
498
|
|
|
499
|
+
FString FMCPEngineStatus::StatusDir()
|
|
500
|
+
{
|
|
501
|
+
return FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("UE_MCP_Bridge"));
|
|
502
|
+
}
|
|
503
|
+
|
|
453
504
|
FString FMCPEngineStatus::StatusFilePath()
|
|
454
505
|
{
|
|
455
|
-
return FPaths::Combine(
|
|
506
|
+
return FPaths::Combine(StatusDir(), TEXT("status.json"));
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
FString FMCPEngineStatus::InstanceStatusFilePath()
|
|
510
|
+
{
|
|
511
|
+
return FPaths::Combine(StatusDir(),
|
|
512
|
+
FString::Printf(TEXT("status.%u.json"), FPlatformProcess::GetCurrentProcessId()));
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
bool FMCPEngineStatus::ShouldPublishStatus()
|
|
516
|
+
{
|
|
517
|
+
// #990: a commandlet publishes nothing. A distributed HLOD build runs 32
|
|
518
|
+
// WorldPartitionBuilderCommandlet slots, each its own UnrealEditor-Cmd.exe
|
|
519
|
+
// with this plugin loaded, and all 32 wrote the same status.json from their
|
|
520
|
+
// own writer threads four times a second. One run produced 3,743
|
|
521
|
+
// Error-severity log lines, up to 147 in a single slot, and every slot then
|
|
522
|
+
// finished with "Failure - 112 error(s)" even where the HLOD work had
|
|
523
|
+
// succeeded, which breaks exit-status and error-count success detection for
|
|
524
|
+
// CI. One commandlet died in a retry storm. Nothing polls a commandlet's
|
|
525
|
+
// engine state in the first place: this exists so an agent can see what an
|
|
526
|
+
// INTERACTIVE editor is doing while its game thread is blocked.
|
|
527
|
+
//
|
|
528
|
+
// Asked per flush rather than once at Install, because the commandlet flag
|
|
529
|
+
// is set during engine startup and Install runs at PostConfigInit.
|
|
530
|
+
return !IsRunningCommandlet();
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
bool FMCPEngineStatus::PublishAtomically(const FString& FinalPath, const FString& Contents)
|
|
534
|
+
{
|
|
535
|
+
// Write then move: a reader polling at the same rate would otherwise catch
|
|
536
|
+
// a half-written file and report "no snapshot" at the exact moment the
|
|
537
|
+
// snapshot matters.
|
|
538
|
+
//
|
|
539
|
+
// #990: the temp file carries this process's pid, the way
|
|
540
|
+
// FMCPBridgeStateFiles::PublishJson has always done it. Without that every
|
|
541
|
+
// process in the project directory wrote and renamed one shared
|
|
542
|
+
// `status.json.tmp`, so concurrent writers deleted each other's temp file
|
|
543
|
+
// out from under the rename and each failure was logged at Error severity.
|
|
544
|
+
const FString TempPath = FString::Printf(TEXT("%s.%u.tmp"), *FinalPath, FPlatformProcess::GetCurrentProcessId());
|
|
545
|
+
if (!FFileHelper::SaveStringToFile(Contents, *TempPath))
|
|
546
|
+
{
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
if (!IFileManager::Get().Move(*FinalPath, *TempPath, /*Replace*/ true, /*EvenIfReadOnly*/ true))
|
|
550
|
+
{
|
|
551
|
+
IFileManager::Get().Delete(*TempPath, /*RequireExists*/ false, /*EvenReadOnly*/ false, /*Quiet*/ true);
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
void FMCPEngineStatus::RemoveStaleInstanceStatusFiles()
|
|
558
|
+
{
|
|
559
|
+
const FString Dir = StatusDir();
|
|
560
|
+
TArray<FString> FileNames;
|
|
561
|
+
IFileManager::Get().FindFiles(FileNames, *FPaths::Combine(Dir, TEXT("status.*.json")), /*Files*/ true, /*Directories*/ false);
|
|
562
|
+
|
|
563
|
+
const uint32 OwnPid = FPlatformProcess::GetCurrentProcessId();
|
|
564
|
+
for (const FString& FileName : FileNames)
|
|
565
|
+
{
|
|
566
|
+
// "status.<pid>.json" - the middle token is the pid, and anything that
|
|
567
|
+
// is not a number is not a file this writes.
|
|
568
|
+
FString Middle = FileName;
|
|
569
|
+
Middle.RemoveFromStart(TEXT("status."));
|
|
570
|
+
Middle.RemoveFromEnd(TEXT(".json"));
|
|
571
|
+
if (Middle.IsEmpty() || !Middle.IsNumeric())
|
|
572
|
+
{
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const uint32 Pid = (uint32)FCString::Strtoui64(*Middle, nullptr, 10);
|
|
577
|
+
if (Pid == 0 || Pid == OwnPid || FPlatformProcess::IsApplicationRunning(Pid))
|
|
578
|
+
{
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const FString FilePath = FPaths::Combine(Dir, FileName);
|
|
583
|
+
if (IFileManager::Get().Delete(*FilePath, /*RequireExists*/ false, /*EvenReadOnly*/ false, /*Quiet*/ true))
|
|
584
|
+
{
|
|
585
|
+
UE_LOG(LogMCPBridgeStatus, Log,
|
|
586
|
+
TEXT("[UE-MCP] Removed the stale engine status file for pid %u: that process is gone."), Pid);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
456
589
|
}
|
|
457
590
|
|
|
458
591
|
void FMCPEngineStatus::FlushToDisk()
|
|
459
592
|
{
|
|
593
|
+
if (!ShouldPublishStatus())
|
|
594
|
+
{
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
|
|
460
598
|
TSharedPtr<FJsonObject> Json = Snapshot();
|
|
461
599
|
Json->SetStringField(TEXT("writtenAt"), FDateTime::UtcNow().ToIso8601());
|
|
462
600
|
|
|
@@ -464,15 +602,15 @@ void FMCPEngineStatus::FlushToDisk()
|
|
|
464
602
|
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&Serialised);
|
|
465
603
|
FJsonSerializer::Serialize(Json.ToSharedRef(), Writer);
|
|
466
604
|
|
|
467
|
-
//
|
|
468
|
-
//
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
605
|
+
// The per-process file first: it is the one nobody else can overwrite, and
|
|
606
|
+
// it is what a reader that understands several editors of one project uses.
|
|
607
|
+
PublishAtomically(InstanceStatusFilePath(), Serialised);
|
|
608
|
+
|
|
609
|
+
// And the shared path, so a client older than this change still finds a
|
|
610
|
+
// snapshot where it has always looked. Two editors of one project take
|
|
611
|
+
// turns here; the per-process files above are where each one's own truth
|
|
612
|
+
// stays intact.
|
|
613
|
+
PublishAtomically(StatusFilePath(), Serialised);
|
|
476
614
|
}
|
|
477
615
|
|
|
478
616
|
uint32 FMCPEngineStatus::Run()
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/Tests/MCPEngineStatusTests.cpp
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#if WITH_DEV_AUTOMATION_TESTS
|
|
2
|
+
|
|
3
|
+
#include "MCPEngineStatus.h"
|
|
4
|
+
#include "CoreGlobals.h"
|
|
5
|
+
#include "Dom/JsonObject.h"
|
|
6
|
+
#include "HAL/PlatformProcess.h"
|
|
7
|
+
#include "Misc/AutomationTest.h"
|
|
8
|
+
#include "Misc/Paths.h"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* What the status writer puts on disk, and what it refuses to put there.
|
|
12
|
+
*
|
|
13
|
+
* #990: every process that loads this plugin ran a writer thread that wrote
|
|
14
|
+
* `status.json` through one shared `status.json.tmp`. A distributed HLOD build
|
|
15
|
+
* runs 32 WorldPartitionBuilderCommandlet slots against one project directory,
|
|
16
|
+
* so 32 processes deleted and renamed the same temp file four times a second.
|
|
17
|
+
* One run produced 3,743 Error-severity log lines, and every slot ended with
|
|
18
|
+
* "Failure - 112 error(s)" even where the HLOD work succeeded, which breaks
|
|
19
|
+
* error-count success detection for CI.
|
|
20
|
+
*
|
|
21
|
+
* Nothing here binds a port or writes into the live state directory: these are
|
|
22
|
+
* assertions about paths and about the commandlet decision, both of which are
|
|
23
|
+
* pure.
|
|
24
|
+
*/
|
|
25
|
+
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
|
26
|
+
FMCPEngineStatusPathsTest,
|
|
27
|
+
"UE.MCP.BridgeStatus.StatusPaths",
|
|
28
|
+
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
|
|
29
|
+
|
|
30
|
+
bool FMCPEngineStatusPathsTest::RunTest(const FString& Parameters)
|
|
31
|
+
{
|
|
32
|
+
const FString Shared = FMCPEngineStatus::StatusFilePath();
|
|
33
|
+
const FString Own = FMCPEngineStatus::InstanceStatusFilePath();
|
|
34
|
+
|
|
35
|
+
TestEqual(TEXT("the shared path keeps its historical name"),
|
|
36
|
+
FPaths::GetCleanFilename(Shared), FString(TEXT("status.json")));
|
|
37
|
+
|
|
38
|
+
// The per-process name is what makes two editors of one project describable
|
|
39
|
+
// at the same time, and what a reader falls back across.
|
|
40
|
+
TestEqual(TEXT("the per-process path is named for this pid"),
|
|
41
|
+
FPaths::GetCleanFilename(Own),
|
|
42
|
+
FString::Printf(TEXT("status.%u.json"), FPlatformProcess::GetCurrentProcessId()));
|
|
43
|
+
TestNotEqual(TEXT("the two are different files"), Own, Shared);
|
|
44
|
+
TestEqual(TEXT("and live in the same directory"), FPaths::GetPath(Own), FPaths::GetPath(Shared));
|
|
45
|
+
TestEqual(TEXT("which is the bridge state directory"),
|
|
46
|
+
FPaths::GetPath(Own), FMCPEngineStatus::StatusDir());
|
|
47
|
+
|
|
48
|
+
// The publish decision. An editor publishes; a commandlet does not, because
|
|
49
|
+
// nothing polls a commandlet's engine state and dozens of them share one
|
|
50
|
+
// project directory.
|
|
51
|
+
TestTrue(TEXT("publishing follows the commandlet flag, and only that"),
|
|
52
|
+
FMCPEngineStatus::ShouldPublishStatus() == !IsRunningCommandlet());
|
|
53
|
+
|
|
54
|
+
// The snapshot has to name its subject: a document that does not say which
|
|
55
|
+
// process it describes cannot be told apart from one that does.
|
|
56
|
+
const TSharedPtr<FJsonObject> Snapshot = FMCPEngineStatus::Get().Snapshot();
|
|
57
|
+
TestTrue(TEXT("a snapshot exists"), Snapshot.IsValid());
|
|
58
|
+
double Pid = 0.0;
|
|
59
|
+
TestTrue(TEXT("the snapshot names its process"), Snapshot.IsValid() && Snapshot->TryGetNumberField(TEXT("pid"), Pid));
|
|
60
|
+
TestEqual(TEXT("and it is this one"), (int32)Pid, (int32)FPlatformProcess::GetCurrentProcessId());
|
|
61
|
+
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#endif
|
|
@@ -86,6 +86,30 @@ public:
|
|
|
86
86
|
virtual uint32 Run() override;
|
|
87
87
|
virtual void Stop() override;
|
|
88
88
|
|
|
89
|
+
/** <Project>/Saved/UE_MCP_Bridge. */
|
|
90
|
+
static FString StatusDir();
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The shared `status.json`, still written so a client older than #990 finds
|
|
94
|
+
* a snapshot where it has always looked.
|
|
95
|
+
*/
|
|
96
|
+
static FString StatusFilePath();
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* `status.<pid>.json`, this process's own. One project directory can hold
|
|
100
|
+
* the status of several processes, and a single shared document describes
|
|
101
|
+
* only whichever of them wrote last (#990).
|
|
102
|
+
*/
|
|
103
|
+
static FString InstanceStatusFilePath();
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* False in a commandlet. Nothing polls a commandlet's engine state, and a
|
|
107
|
+
* distributed build runs dozens of them against one project directory,
|
|
108
|
+
* where they used to fight over one file and turn a successful build into
|
|
109
|
+
* thousands of Error lines (#990).
|
|
110
|
+
*/
|
|
111
|
+
static bool ShouldPublishStatus();
|
|
112
|
+
|
|
89
113
|
private:
|
|
90
114
|
struct FSlowTaskEntry
|
|
91
115
|
{
|
|
@@ -96,7 +120,14 @@ private:
|
|
|
96
120
|
/** Serialise under the lock, then write atomically (temp file + move). */
|
|
97
121
|
void FlushToDisk();
|
|
98
122
|
|
|
99
|
-
|
|
123
|
+
/** Temp file plus rename, with the temp file named for this process. */
|
|
124
|
+
static bool PublishAtomically(const FString& FinalPath, const FString& Contents);
|
|
125
|
+
|
|
126
|
+
/** Drop `status.<pid>.json` files left by processes that are gone. */
|
|
127
|
+
static void RemoveStaleInstanceStatusFiles();
|
|
128
|
+
|
|
129
|
+
/** Does the shared status.json currently name this process? */
|
|
130
|
+
static bool SharedStatusBelongsToThisProcess();
|
|
100
131
|
|
|
101
132
|
mutable FCriticalSection Mutex;
|
|
102
133
|
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ue-mcp-animation
|
|
3
|
+
description: Use when creating, modifying, retargeting, rigging, constraining, or validating skeletal animation through UE-MCP. Covers native UE 5.8 IK Rig and Retargeter authoring, the Control Rig begin/read/apply/bake loop, generic contact locks, per-rig anatomical and mirrored-axis discovery, quaternion keying, deterministic bone analysis, and exact fixed-frame Unreal capture.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UE-MCP native animation workflow
|
|
7
|
+
|
|
8
|
+
Create quality animation from measured pose constraints, not guessed control
|
|
9
|
+
angles. Control names, local axes, palm axes, handedness, and scale are
|
|
10
|
+
properties of the selected rig. Discover them again for every unfamiliar rig;
|
|
11
|
+
never paste values from another rig or negate a left-side Euler pose to make a
|
|
12
|
+
right-side pose.
|
|
13
|
+
|
|
14
|
+
## Required loop
|
|
15
|
+
|
|
16
|
+
1. Call `project(action="get_status")`; verify the intended project and editor.
|
|
17
|
+
2. Establish the character's authoring baseline before editing clips. Search
|
|
18
|
+
for a Control Rig already bound to the target mesh/skeleton and inspect it
|
|
19
|
+
with `read_control_rig_hierarchy` and `read_control_rig_graph`. It must have
|
|
20
|
+
the controls, Forward Solve, and Backward Solve required for the intended
|
|
21
|
+
edits. If the project or character has no suitable rig, create one first
|
|
22
|
+
with the bundled Epic 5.8 controlrig actions (`epic_create`,
|
|
23
|
+
`epic_import_bones_from_asset`, `epic_add_control`, deliberate Forward Solve
|
|
24
|
+
nodes/links, and `epic_add_backward_solve_graph`), then save the exact rig
|
|
25
|
+
with `asset(epic_save_assets)`. `epic_create` alone creates no imported
|
|
26
|
+
bones, authored controls, or solver wiring. Run an unchanged
|
|
27
|
+
source-to-controls-to-bones round trip on the exact production mesh. Do not
|
|
28
|
+
begin production work on an unverified or merely name-compatible rig.
|
|
29
|
+
3. Resolve the source AnimSequence, mesh, skeleton, verified Control Rig, and
|
|
30
|
+
frame rate.
|
|
31
|
+
When IK/retarget assets are part of the job, use `read_ik_rig` and
|
|
32
|
+
`read_ik_retargeter` first. On UE 5.8 use `configure_ik_rig` for validated
|
|
33
|
+
roots, ancestry-valid chains, concrete goals, solver connections and
|
|
34
|
+
effectors; use `configure_ik_retargeter` for the default op stack, source and
|
|
35
|
+
target rig assignment to every op, auto/manual mappings, preview meshes, and
|
|
36
|
+
a named retarget pose. Read both assets back after saving. A chain's goal
|
|
37
|
+
string is not proof that a goal or solver exists.
|
|
38
|
+
4. Create a versioned session with `begin_control_rig_edit`. Use a unique
|
|
39
|
+
LevelSequence path and `bindingTag`, an end-exclusive frame range, and
|
|
40
|
+
`onConflict="error"`. Use `rigMode="asset"` for a project rig or `"fk"` only
|
|
41
|
+
when generated FK controls are intentional. The source must be non-additive
|
|
42
|
+
and mesh-compatible; flatten an additive clip against its intended base
|
|
43
|
+
first. `layered` controls the session layer, not an additive source base.
|
|
44
|
+
A finite non-zero source `RateScale` is compensated in Sequencer so the raw
|
|
45
|
+
timeline maps once without modifying the source asset; zero is rejected.
|
|
46
|
+
5. Call `read_control_rig_edit` at rest, transitions, extrema, and end in both
|
|
47
|
+
`local` and `global` space. Here `global` is rig/global (normally mesh
|
|
48
|
+
component) space, not actor world space.
|
|
49
|
+
6. Inspect every control's `controlType`, `animatable`, and enum metadata. Write
|
|
50
|
+
scalars with the matching `set_bool`, `set_float`, or `set_int`; enum values
|
|
51
|
+
must come from `enumOptions`. Never write `animatable=false` controls.
|
|
52
|
+
7. Define anatomical component-space targets, then solve proximal to distal:
|
|
53
|
+
shoulder/upper arm, elbow pole and bend, forearm direction, wrist, palm
|
|
54
|
+
normal, then secondary motion. For a wave, the forearm must rise, the wrist
|
|
55
|
+
must sit above the elbow/near the shoulder region, and the probed palm normal
|
|
56
|
+
must face the intended viewer before wrist oscillation is added.
|
|
57
|
+
8. When an axis is uncertain, make an immutable probe session. Apply a small
|
|
58
|
+
positive and negative rotation to one local axis at one fixed frame, bake,
|
|
59
|
+
and inspect the resulting component-space shoulder/forearm/hand landmarks
|
|
60
|
+
with `analyze_animation`. Probe the right side separately; mirrored parents
|
|
61
|
+
or negative scale can reverse anatomical meanings. Preserve the full scale
|
|
62
|
+
read from the control.
|
|
63
|
+
9. Apply absolute `set_keys` transforms with finite normalized quaternions,
|
|
64
|
+
complete translation/rotationQuaternion/scale payloads, and strictly
|
|
65
|
+
increasing frames. Preserve translation and scale unless intentionally
|
|
66
|
+
editing them. If the source bake has dense keys, key every affected frame;
|
|
67
|
+
sparse keys will not replace the intervening source motion. Apply related
|
|
68
|
+
controls and scalar switches in one transaction.
|
|
69
|
+
For a fixed contact, use `contact_lock` in the same operation batch. Supply a
|
|
70
|
+
keyable translatable driver, optional driven bone/socket, inclusive frame
|
|
71
|
+
range, component-space target, optional pole/stabilizer controls, and
|
|
72
|
+
position/rotation tolerances. The session must contain one source animation
|
|
73
|
+
section. The bridge samples it per frame, writes dense smooth-edged keys, and
|
|
74
|
+
transactionally reads back the driver and stabilizers. A driven bone/socket
|
|
75
|
+
returns `verification=bake_and_analyze_required`; bake, analyze every
|
|
76
|
+
constrained frame, and reject the output if its residual misses the motion's
|
|
77
|
+
acceptance tolerance. FK contacts whose translation is ignored by skeleton
|
|
78
|
+
retargeting use a local rotation-chain solve and report
|
|
79
|
+
`solver=fk_rotation_chain`; that path requires a driven bone and does not
|
|
80
|
+
accept stabilizers. Position-only locks leave the driven control orientation
|
|
81
|
+
unkeyed. The bridge does not guess the driver, pole, foot roll, friction,
|
|
82
|
+
joint limits, or pelvis compensation.
|
|
83
|
+
10. Read back the edited frames in local and global space. Reject elbow flips,
|
|
84
|
+
discontinuities, wrong forearm direction, wrong palm normal, or unexpected
|
|
85
|
+
changes outside the edited chain before baking.
|
|
86
|
+
11. Bake to a new versioned AnimSequence with `bake_control_rig_edit`,
|
|
87
|
+
`reduceKeys=false`, and `onConflict="error"`. Never overwrite source,
|
|
88
|
+
another iteration's session, or prior approved output assets.
|
|
89
|
+
|
|
90
|
+
## Validation and visual review
|
|
91
|
+
|
|
92
|
+
Run `analyze_animation` on source and output using the same mesh, explicit
|
|
93
|
+
frames, and bones. Include root, pelvis, the complete edited chain, feet,
|
|
94
|
+
opposite side, and any controls/bones expected to remain unchanged. Write its
|
|
95
|
+
native `manifest.json` and `samples.ndjson` beneath
|
|
96
|
+
`Saved/Codex/AnimationQA`.
|
|
97
|
+
|
|
98
|
+
Check numeric integrity, invalid transforms, selected-bone bounds, root
|
|
99
|
+
displacement/speed, and loop seam metrics. Derive gesture-specific checks from
|
|
100
|
+
component transforms: shoulder-relative wrist height, elbow-to-wrist vector,
|
|
101
|
+
elbow angle/plane stability, probed palm-normal alignment, speed/acceleration,
|
|
102
|
+
direction changes, and drift in untouched bones. Numeric samples are the source
|
|
103
|
+
of truth; screenshots are the human visual gate.
|
|
104
|
+
|
|
105
|
+
Use the analyzer's `rateScale`, `effectiveDurationSeconds`, and per-notify
|
|
106
|
+
`rawTriggerTimeSeconds` / `effectiveTriggerTimeSeconds` fields when validating
|
|
107
|
+
gameplay release timing. Effective times use the asset-rate magnitude and are
|
|
108
|
+
null when the asset rate is zero.
|
|
109
|
+
|
|
110
|
+
For an exact native frame capture, without Computer Use or Python:
|
|
111
|
+
|
|
112
|
+
1. `editor(action="open_asset", assetPath=<baked_anim>)`.
|
|
113
|
+
2. `editor(action="find_object")` for `className="AnimSingleNodeInstance"`,
|
|
114
|
+
`nameContains="AnimPreviewInstance"`, `world="any"`; select the match under
|
|
115
|
+
the current `AnimationEditorPreviewActor`.
|
|
116
|
+
3. In one `editor(action="invoke_object_functions")` call, invoke `SetPlaying` with
|
|
117
|
+
`bIsPlaying=false`, then `SetPosition` with
|
|
118
|
+
`InPosition=frame*rateDenominator/rateNumerator` and
|
|
119
|
+
`bFireNotifies=false` on that object path.
|
|
120
|
+
4. Open the asset again to focus its window and call
|
|
121
|
+
`editor(action="capture_screenshot", target="window")`.
|
|
122
|
+
5. Capture start, entry, both extrema, exit, and end with a consistent view.
|
|
123
|
+
|
|
124
|
+
Keep versioned V&V fixtures for a from-scratch gesture, full-body IK authoring,
|
|
125
|
+
a retarget between known skeletons, a copied animation modified through IK plus
|
|
126
|
+
its pole target, a bone/socket contact with an unrelated simultaneous edit, and
|
|
127
|
+
edge cases covering mirrored/negative scale, dense keys, additive-source
|
|
128
|
+
rejection/flattening, layered sessions, scalar enums, root motion, loops, and
|
|
129
|
+
short clips.
|
|
130
|
+
|
|
131
|
+
The loop generalizes beyond humanoid arms. Re-discover the rig mapping, then
|
|
132
|
+
express legs as hip/knee-pole/foot/contact constraints; spine and head as
|
|
133
|
+
arc/twist/aim constraints; tails, tentacles, and ropes as length-preserving
|
|
134
|
+
chain curves with delayed phase; and props or mechanisms as pivot, attachment,
|
|
135
|
+
contact, and clearance constraints. Only control/bone names, axes/signs,
|
|
136
|
+
mirrored scale, limits, and motion constraints are rig-specific.
|
|
137
|
+
|
|
138
|
+
## Compatibility and endpoint rule
|
|
139
|
+
|
|
140
|
+
The four Control Rig session actions, `configure_ik_rig`,
|
|
141
|
+
`configure_ik_retargeter`, and `contact_lock` are UE 5.8 only and return
|
|
142
|
+
`unsupported_engine_version` on older engines; do not invent a reflected or
|
|
143
|
+
raw-bone fallback. Legacy IK create/read behavior is unchanged.
|
|
144
|
+
`analyze_animation` is cross-version through the native APIs in the compiled
|
|
145
|
+
engine. See the public
|
|
146
|
+
[Native Control Rig Animation](https://ue-mcp.com/docs/control-rig-animation/)
|
|
147
|
+
guide for full call shapes and fixture guidance.
|
|
148
|
+
|
|
149
|
+
Edit ranges are `[startFrame, endFrameExclusive)`. The bridge keeps an internal
|
|
150
|
+
support frame for Unreal's exact-duration export sample without making the
|
|
151
|
+
exclusive end authorable. Validate the last visible frame and exact-duration
|
|
152
|
+
sample separately. A non-looping endpoint must hold the intended final pose
|
|
153
|
+
without an adjacent-frame teleport or rotation jump; a looping endpoint must
|
|
154
|
+
pass the requested seam check. A large endpoint discontinuity fails the bake.
|