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
|
@@ -22,6 +22,9 @@ private:
|
|
|
22
22
|
static TSharedPtr<FJsonValue> DeleteAsset(const TSharedPtr<FJsonObject>& Params);
|
|
23
23
|
static TSharedPtr<FJsonValue> DeleteAssetBatch(const TSharedPtr<FJsonObject>& Params);
|
|
24
24
|
static TSharedPtr<FJsonValue> BulkRename(const TSharedPtr<FJsonObject>& Params);
|
|
25
|
+
// Bounded redirector clean-up after a move (#908). Lives in
|
|
26
|
+
// AssetHandlers_Redirectors.cpp.
|
|
27
|
+
static TSharedPtr<FJsonValue> FixupRedirectors(const TSharedPtr<FJsonObject>& Params);
|
|
25
28
|
static TSharedPtr<FJsonValue> CreateDataAsset(const TSharedPtr<FJsonObject>& Params);
|
|
26
29
|
// Bounded batch create-or-update of UDataAsset instances. Lives in
|
|
27
30
|
// AssetHandlers_BulkUpsert.cpp.
|
|
@@ -32,6 +35,9 @@ private:
|
|
|
32
35
|
// #726: create an asset of any concrete UObject class via its registered
|
|
33
36
|
// factory (or NewObject fallback), not just UDataAsset subclasses.
|
|
34
37
|
static TSharedPtr<FJsonValue> CreateAssetByClass(const TSharedPtr<FJsonObject>& Params);
|
|
38
|
+
// A named subobject inside an existing asset's package (#975). Lives in
|
|
39
|
+
// AssetHandlers_Subobject.cpp.
|
|
40
|
+
static TSharedPtr<FJsonValue> CreateSubobject(const TSharedPtr<FJsonObject>& Params);
|
|
35
41
|
static TSharedPtr<FJsonValue> SaveAsset(const TSharedPtr<FJsonObject>& Params);
|
|
36
42
|
// #429: bulk save of every dirty package - one-shot end-of-workflow flush.
|
|
37
43
|
static TSharedPtr<FJsonValue> SaveAllDirty(const TSharedPtr<FJsonObject>& Params);
|
|
@@ -97,6 +103,8 @@ private:
|
|
|
97
103
|
static TSharedPtr<FJsonValue> SetStringTableEntry(const TSharedPtr<FJsonObject>& Params);
|
|
98
104
|
static TSharedPtr<FJsonValue> RemoveStringTableEntry(const TSharedPtr<FJsonObject>& Params);
|
|
99
105
|
static TSharedPtr<FJsonValue> ImportStringTable(const TSharedPtr<FJsonObject>& Params);
|
|
106
|
+
// CSV import with key-set validation and an explicit save result (#978).
|
|
107
|
+
static TSharedPtr<FJsonValue> ImportStringTableCsv(const TSharedPtr<FJsonObject>& Params);
|
|
100
108
|
|
|
101
109
|
// Export
|
|
102
110
|
static TSharedPtr<FJsonValue> ExportAsset(const TSharedPtr<FJsonObject>& Params);
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkProperties.cpp
CHANGED
|
@@ -205,7 +205,7 @@ TSharedPtr<FJsonValue> FAssetHandlers::BulkSetAssetProperties(const TSharedPtr<F
|
|
|
205
205
|
continue;
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
UObject* LoadedAsset =
|
|
208
|
+
UObject* LoadedAsset = MCPLoadAssetObject(AssetPath);
|
|
209
209
|
if (!LoadedAsset)
|
|
210
210
|
{
|
|
211
211
|
RejectItem(BulkStatusNotFound, FString::Printf(TEXT("Preflight failed: could not load asset '%s'"), *AssetPath));
|
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
// asset(bulk_read_properties) - read the same properties off many assets in
|
|
2
|
+
// one call (#909).
|
|
3
|
+
//
|
|
4
|
+
// The reporter needed voice-management and concurrency settings across 582
|
|
5
|
+
// SoundWave, SoundCue and MetaSoundSource assets. audio(list) does not report
|
|
6
|
+
// those fields, and asset(read_properties) answers one asset per call, so the
|
|
7
|
+
// question became a Python loop. This is the same shape as
|
|
8
|
+
// level(query_components), one level up: the directory and class filters, the
|
|
9
|
+
// property reads, the predicates and the aggregates all run in the editor, and
|
|
10
|
+
// only the answer crosses the wire.
|
|
11
|
+
//
|
|
12
|
+
// This file exists as its own translation unit with its own registration so
|
|
13
|
+
// the change lands without touching AssetHandlers.cpp.
|
|
14
|
+
//
|
|
15
|
+
// It never writes. Loading an asset to read it does not dirty its package, and
|
|
16
|
+
// the response says so rather than asking to be believed.
|
|
17
|
+
|
|
18
|
+
#include "AssetHandlers_BulkRead.h"
|
|
19
|
+
|
|
20
|
+
#include "AssetRegistry/AssetRegistryModule.h"
|
|
21
|
+
#include "AssetRegistry/IAssetRegistry.h"
|
|
22
|
+
#include "Engine/Blueprint.h"
|
|
23
|
+
#include "HandlerEditorState.h"
|
|
24
|
+
#include "HandlerQuery.h"
|
|
25
|
+
#include "HandlerRegistry.h"
|
|
26
|
+
#include "HandlerUtils.h"
|
|
27
|
+
#include "Misc/FileHelper.h"
|
|
28
|
+
#include "Misc/Paths.h"
|
|
29
|
+
#include "Serialization/JsonSerializer.h"
|
|
30
|
+
#include "Serialization/JsonWriter.h"
|
|
31
|
+
#include "UObject/Package.h"
|
|
32
|
+
|
|
33
|
+
namespace
|
|
34
|
+
{
|
|
35
|
+
// Every one of these is here because the action it replaces was unbounded.
|
|
36
|
+
constexpr int32 MCPBulkReadDefaultRowLimit = 200;
|
|
37
|
+
constexpr int32 MCPBulkReadMaxRowLimit = 2000;
|
|
38
|
+
constexpr int32 MCPBulkReadDefaultMaxAssets = 2000;
|
|
39
|
+
constexpr int32 MCPBulkReadHardMaxAssets = 20000;
|
|
40
|
+
constexpr int32 MCPBulkReadMaxProperties = 32;
|
|
41
|
+
constexpr int32 MCPBulkReadMaxPredicates = 24;
|
|
42
|
+
constexpr int32 MCPBulkReadMaxGroups = 200;
|
|
43
|
+
constexpr int32 MCPBulkReadMaxCountByPaths = 8;
|
|
44
|
+
constexpr int32 MCPBulkReadMaxCountByValues = 64;
|
|
45
|
+
constexpr int32 MCPBulkReadDefaultGroupSamples = 5;
|
|
46
|
+
constexpr int32 MCPBulkReadMaxGroupSamples = 25;
|
|
47
|
+
constexpr int32 MCPBulkReadMaxExplicitPaths = 5000;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A Blueprint asset's properties live on its generated class default
|
|
51
|
+
* object, not on the UBlueprint wrapper, so reading `bCanEverTick` off the
|
|
52
|
+
* wrapper would always report absent.
|
|
53
|
+
*/
|
|
54
|
+
UObject* MCPBulkReadTarget(UObject* Asset)
|
|
55
|
+
{
|
|
56
|
+
if (UBlueprint* Blueprint = Cast<UBlueprint>(Asset))
|
|
57
|
+
{
|
|
58
|
+
if (UClass* GeneratedClass = Blueprint->GeneratedClass)
|
|
59
|
+
{
|
|
60
|
+
if (UObject* CDO = GeneratedClass->GetDefaultObject())
|
|
61
|
+
{
|
|
62
|
+
return CDO;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return Asset;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Render one row set as pretty JSON for the outputPath variant. */
|
|
70
|
+
FString MCPBulkReadSerializeRows(const TArray<TSharedPtr<FJsonValue>>& Rows)
|
|
71
|
+
{
|
|
72
|
+
TSharedPtr<FJsonObject> Document = MakeShared<FJsonObject>();
|
|
73
|
+
Document->SetNumberField(TEXT("count"), Rows.Num());
|
|
74
|
+
Document->SetArrayField(TEXT("rows"), Rows);
|
|
75
|
+
FString Output;
|
|
76
|
+
const TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&Output);
|
|
77
|
+
FJsonSerializer::Serialize(Document.ToSharedRef(), Writer);
|
|
78
|
+
return Output;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
void FAssetBulkReadHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
|
|
83
|
+
{
|
|
84
|
+
// Loading hundreds of assets to read them takes longer than the default
|
|
85
|
+
// handler timeout allows, and a timeout here would look like a hang.
|
|
86
|
+
Registry.RegisterHandlerWithTimeout(
|
|
87
|
+
TEXT("bulk_read_asset_properties"), &BulkReadAssetProperties, 300.0f);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
TSharedPtr<FJsonValue> FAssetBulkReadHandlers::BulkReadAssetProperties(const TSharedPtr<FJsonObject>& Params)
|
|
91
|
+
{
|
|
92
|
+
MCP_CHECK_GAME_THREAD();
|
|
93
|
+
|
|
94
|
+
// ── Properties to read ──────────────────────────────────────────────────
|
|
95
|
+
TArray<FString> PropertyPaths;
|
|
96
|
+
{
|
|
97
|
+
const TArray<TSharedPtr<FJsonValue>>* PropertyValues = nullptr;
|
|
98
|
+
if (Params->TryGetArrayField(TEXT("propertyNames"), PropertyValues) && PropertyValues)
|
|
99
|
+
{
|
|
100
|
+
PropertyPaths = JsonArrayToStringList(PropertyValues);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (PropertyPaths.IsEmpty())
|
|
104
|
+
{
|
|
105
|
+
return MCPError(TEXT("Missing required 'propertyNames' array (dotted paths into nested structs are supported, e.g. 'CullDistance.Max')"));
|
|
106
|
+
}
|
|
107
|
+
if (PropertyPaths.Num() > MCPBulkReadMaxProperties)
|
|
108
|
+
{
|
|
109
|
+
return MCPError(FString::Printf(
|
|
110
|
+
TEXT("'propertyNames' exceeds the maximum of %d entries"), MCPBulkReadMaxProperties));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ── Selection ───────────────────────────────────────────────────────────
|
|
114
|
+
TArray<FString> ExplicitPaths;
|
|
115
|
+
{
|
|
116
|
+
const TArray<TSharedPtr<FJsonValue>>* PathValues = nullptr;
|
|
117
|
+
if (Params->TryGetArrayField(TEXT("assetPaths"), PathValues) && PathValues)
|
|
118
|
+
{
|
|
119
|
+
ExplicitPaths = JsonArrayToStringList(PathValues);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const FString Directory = OptionalString(Params, TEXT("directory"));
|
|
123
|
+
if (ExplicitPaths.IsEmpty() && Directory.IsEmpty())
|
|
124
|
+
{
|
|
125
|
+
return MCPError(TEXT("Pass either 'assetPaths' (explicit list) or 'directory' (with optional 'classNames')"));
|
|
126
|
+
}
|
|
127
|
+
if (ExplicitPaths.Num() > MCPBulkReadMaxExplicitPaths)
|
|
128
|
+
{
|
|
129
|
+
return MCPError(FString::Printf(
|
|
130
|
+
TEXT("'assetPaths' exceeds the maximum of %d entries"), MCPBulkReadMaxExplicitPaths));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const bool bRecursive = OptionalBool(Params, TEXT("recursive"), true);
|
|
134
|
+
const bool bMatchSubclasses = OptionalBool(Params, TEXT("matchSubclasses"), true);
|
|
135
|
+
const int32 MaxAssets = FMath::Clamp(
|
|
136
|
+
OptionalInt(Params, TEXT("maxAssets"), MCPBulkReadDefaultMaxAssets), 1, MCPBulkReadHardMaxAssets);
|
|
137
|
+
|
|
138
|
+
TArray<UClass*> ClassFilters;
|
|
139
|
+
{
|
|
140
|
+
const TArray<TSharedPtr<FJsonValue>>* ClassValues = nullptr;
|
|
141
|
+
if (Params->TryGetArrayField(TEXT("classNames"), ClassValues) && ClassValues)
|
|
142
|
+
{
|
|
143
|
+
for (const FString& Spec : JsonArrayToStringList(ClassValues))
|
|
144
|
+
{
|
|
145
|
+
UClass* Resolved = MCPResolveClass(Spec, true);
|
|
146
|
+
if (!Resolved)
|
|
147
|
+
{
|
|
148
|
+
return MCPClassNotFoundError(Spec, TEXT("classNames"));
|
|
149
|
+
}
|
|
150
|
+
ClassFilters.Add(Resolved);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ── Predicates and aggregates ───────────────────────────────────────────
|
|
156
|
+
TArray<MCPQuery::FPredicate> Predicates;
|
|
157
|
+
{
|
|
158
|
+
const TArray<TSharedPtr<FJsonValue>>* WhereValues = nullptr;
|
|
159
|
+
Params->TryGetArrayField(TEXT("where"), WhereValues);
|
|
160
|
+
FString ParseError;
|
|
161
|
+
if (!MCPQuery::ParsePredicates(WhereValues, MCPBulkReadMaxPredicates, Predicates, ParseError))
|
|
162
|
+
{
|
|
163
|
+
return MCPError(ParseError);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const FString WhereMode = OptionalString(Params, TEXT("whereMode"), TEXT("all")).ToLower();
|
|
167
|
+
if (WhereMode != TEXT("all") && WhereMode != TEXT("any"))
|
|
168
|
+
{
|
|
169
|
+
return MCPError(TEXT("'whereMode' must be either 'all' or 'any'"));
|
|
170
|
+
}
|
|
171
|
+
const bool bSuspectOnly = OptionalBool(Params, TEXT("suspectOnly"), false);
|
|
172
|
+
if (bSuspectOnly)
|
|
173
|
+
{
|
|
174
|
+
if (WhereMode == TEXT("any") && Predicates.Num() > 0)
|
|
175
|
+
{
|
|
176
|
+
return MCPError(TEXT("'suspectOnly' cannot be combined with whereMode 'any'; add {field:'suspect', op:'isTrue'} to 'where' instead"));
|
|
177
|
+
}
|
|
178
|
+
MCPQuery::FPredicate Suspect;
|
|
179
|
+
Suspect.Field = TEXT("suspect");
|
|
180
|
+
Suspect.Op = TEXT("isTrue");
|
|
181
|
+
Predicates.Add(MoveTemp(Suspect));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const FString GroupBy = OptionalString(Params, TEXT("groupBy"));
|
|
185
|
+
const int32 GroupSamples = FMath::Clamp(
|
|
186
|
+
OptionalInt(Params, TEXT("sampleLimit"), MCPBulkReadDefaultGroupSamples), 0, MCPBulkReadMaxGroupSamples);
|
|
187
|
+
TArray<FString> CountByPaths;
|
|
188
|
+
{
|
|
189
|
+
const TArray<TSharedPtr<FJsonValue>>* CountByValues = nullptr;
|
|
190
|
+
if (Params->TryGetArrayField(TEXT("countBy"), CountByValues) && CountByValues)
|
|
191
|
+
{
|
|
192
|
+
CountByPaths = JsonArrayToStringList(CountByValues);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (CountByPaths.Num() > MCPBulkReadMaxCountByPaths)
|
|
196
|
+
{
|
|
197
|
+
return MCPError(FString::Printf(
|
|
198
|
+
TEXT("'countBy' exceeds the maximum of %d paths"), MCPBulkReadMaxCountByPaths));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const bool bCountOnly = OptionalBool(Params, TEXT("countOnly"), false);
|
|
202
|
+
const int32 Limit = FMath::Clamp(
|
|
203
|
+
OptionalInt(Params, TEXT("limit"), MCPBulkReadDefaultRowLimit), 0, MCPBulkReadMaxRowLimit);
|
|
204
|
+
const int32 StartIndex = FMath::Max(0, OptionalInt(Params, TEXT("startIndex"), 0));
|
|
205
|
+
const FString OutputPath = OptionalString(Params, TEXT("outputPath"));
|
|
206
|
+
|
|
207
|
+
// ── Gather candidate asset paths ────────────────────────────────────────
|
|
208
|
+
TArray<FString> CandidatePaths;
|
|
209
|
+
bool bScanTruncated = false;
|
|
210
|
+
if (!ExplicitPaths.IsEmpty())
|
|
211
|
+
{
|
|
212
|
+
CandidatePaths = MoveTemp(ExplicitPaths);
|
|
213
|
+
}
|
|
214
|
+
else
|
|
215
|
+
{
|
|
216
|
+
FAssetRegistryModule& AssetRegistryModule =
|
|
217
|
+
FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
|
218
|
+
IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
|
|
219
|
+
|
|
220
|
+
FARFilter Filter;
|
|
221
|
+
Filter.bRecursivePaths = bRecursive;
|
|
222
|
+
Filter.PackagePaths.Add(FName(*Directory));
|
|
223
|
+
for (const UClass* Class : ClassFilters)
|
|
224
|
+
{
|
|
225
|
+
Filter.ClassPaths.Add(Class->GetClassPathName());
|
|
226
|
+
}
|
|
227
|
+
Filter.bRecursiveClasses = bMatchSubclasses;
|
|
228
|
+
|
|
229
|
+
TArray<FAssetData> Found;
|
|
230
|
+
AssetRegistry.GetAssets(Filter, Found);
|
|
231
|
+
for (const FAssetData& Data : Found)
|
|
232
|
+
{
|
|
233
|
+
if (Data.AssetClassPath.GetAssetName() == FName(TEXT("ObjectRedirector")))
|
|
234
|
+
{
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
CandidatePaths.Add(Data.GetObjectPathString());
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
CandidatePaths.Sort();
|
|
241
|
+
if (CandidatePaths.Num() > MaxAssets)
|
|
242
|
+
{
|
|
243
|
+
bScanTruncated = true;
|
|
244
|
+
CandidatePaths.SetNum(MaxAssets);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
TArray<FString> DirtyBefore;
|
|
248
|
+
MCPEditorState::CollectDirtyEditorPackageNames(DirtyBefore);
|
|
249
|
+
|
|
250
|
+
// ── Read ────────────────────────────────────────────────────────────────
|
|
251
|
+
int32 Loaded = 0;
|
|
252
|
+
int32 Matched = 0;
|
|
253
|
+
TArray<FString> UnloadableAssets;
|
|
254
|
+
TArray<FString> ClassFilteredOut;
|
|
255
|
+
TArray<TSharedPtr<FJsonValue>> Rows;
|
|
256
|
+
TMap<FString, int32> GroupCounts;
|
|
257
|
+
TMap<FString, TArray<FString>> GroupSamplesByKey;
|
|
258
|
+
TArray<FString> GroupOrder;
|
|
259
|
+
TMap<FString, TMap<FString, int32>> CountByHistograms;
|
|
260
|
+
bool bGroupsTruncated = false;
|
|
261
|
+
|
|
262
|
+
for (const FString& AssetPath : CandidatePaths)
|
|
263
|
+
{
|
|
264
|
+
UObject* Asset = LoadObject<UObject>(nullptr, *AssetPath);
|
|
265
|
+
if (!Asset)
|
|
266
|
+
{
|
|
267
|
+
if (UnloadableAssets.Num() < 50)
|
|
268
|
+
{
|
|
269
|
+
UnloadableAssets.Add(AssetPath);
|
|
270
|
+
}
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
++Loaded;
|
|
274
|
+
|
|
275
|
+
// An explicit assetPaths list bypasses the registry filter, so the
|
|
276
|
+
// class filter has to be applied here too or classNames would silently
|
|
277
|
+
// mean nothing for that shape of request.
|
|
278
|
+
if (ClassFilters.Num() > 0)
|
|
279
|
+
{
|
|
280
|
+
bool bClassMatches = false;
|
|
281
|
+
for (UClass* Class : ClassFilters)
|
|
282
|
+
{
|
|
283
|
+
if (bMatchSubclasses ? Asset->IsA(Class) : (Asset->GetClass() == Class))
|
|
284
|
+
{
|
|
285
|
+
bClassMatches = true;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (!bClassMatches)
|
|
290
|
+
{
|
|
291
|
+
if (ClassFilteredOut.Num() < 50)
|
|
292
|
+
{
|
|
293
|
+
ClassFilteredOut.Add(AssetPath);
|
|
294
|
+
}
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
UObject* Target = MCPBulkReadTarget(Asset);
|
|
300
|
+
|
|
301
|
+
TSharedPtr<FJsonObject> Props = MakeShared<FJsonObject>();
|
|
302
|
+
TArray<FString> MissingProperties;
|
|
303
|
+
bool bAnyNull = false;
|
|
304
|
+
for (const FString& PropertyPath : PropertyPaths)
|
|
305
|
+
{
|
|
306
|
+
FString ResolvedType;
|
|
307
|
+
const TSharedPtr<FJsonValue> Value = MCPQuery::ReadDottedProperty(Target, PropertyPath, ResolvedType);
|
|
308
|
+
if (!Value.IsValid())
|
|
309
|
+
{
|
|
310
|
+
// Absent is not null. "This class has no such property" and
|
|
311
|
+
// "this property is unset" are different findings, and
|
|
312
|
+
// collapsing them is what makes an audit unactionable.
|
|
313
|
+
MissingProperties.Add(PropertyPath);
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
if (Value->Type == EJson::Null)
|
|
317
|
+
{
|
|
318
|
+
bAnyNull = true;
|
|
319
|
+
}
|
|
320
|
+
Props->SetField(PropertyPath, Value);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
TSharedPtr<FJsonObject> Row = MakeShared<FJsonObject>();
|
|
324
|
+
Row->SetStringField(TEXT("assetPath"), Asset->GetPathName());
|
|
325
|
+
Row->SetStringField(TEXT("assetName"), Asset->GetName());
|
|
326
|
+
Row->SetStringField(TEXT("className"), Asset->GetClass()->GetName());
|
|
327
|
+
Row->SetStringField(TEXT("packagePath"), Asset->GetOutermost()->GetName());
|
|
328
|
+
if (Target != Asset)
|
|
329
|
+
{
|
|
330
|
+
Row->SetStringField(TEXT("readFrom"), Target->GetPathName());
|
|
331
|
+
}
|
|
332
|
+
Row->SetObjectField(TEXT("props"), Props);
|
|
333
|
+
Row->SetArrayField(TEXT("missingProperties"), MCPStringListToJson(MissingProperties));
|
|
334
|
+
Row->SetBoolField(TEXT("suspect"), MissingProperties.Num() > 0 || bAnyNull);
|
|
335
|
+
|
|
336
|
+
if (!MCPQuery::EvaluateAll(Predicates, Row, WhereMode == TEXT("all")))
|
|
337
|
+
{
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
++Matched;
|
|
341
|
+
|
|
342
|
+
if (!GroupBy.IsEmpty())
|
|
343
|
+
{
|
|
344
|
+
const FString Key = MCPQuery::ValueKey(MCPQuery::ResolvePath(Row, GroupBy));
|
|
345
|
+
if (int32* Existing = GroupCounts.Find(Key))
|
|
346
|
+
{
|
|
347
|
+
++(*Existing);
|
|
348
|
+
}
|
|
349
|
+
else if (GroupCounts.Num() < MCPBulkReadMaxGroups)
|
|
350
|
+
{
|
|
351
|
+
GroupCounts.Add(Key, 1);
|
|
352
|
+
GroupOrder.Add(Key);
|
|
353
|
+
}
|
|
354
|
+
else
|
|
355
|
+
{
|
|
356
|
+
bGroupsTruncated = true;
|
|
357
|
+
}
|
|
358
|
+
if (GroupCounts.Contains(Key))
|
|
359
|
+
{
|
|
360
|
+
TArray<FString>& Samples = GroupSamplesByKey.FindOrAdd(Key);
|
|
361
|
+
if (Samples.Num() < GroupSamples)
|
|
362
|
+
{
|
|
363
|
+
Samples.Add(Asset->GetName());
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
for (const FString& CountPath : CountByPaths)
|
|
369
|
+
{
|
|
370
|
+
TMap<FString, int32>& Histogram = CountByHistograms.FindOrAdd(CountPath);
|
|
371
|
+
const FString Key = MCPQuery::ValueKey(MCPQuery::ResolvePath(Row, CountPath));
|
|
372
|
+
if (int32* Existing = Histogram.Find(Key))
|
|
373
|
+
{
|
|
374
|
+
++(*Existing);
|
|
375
|
+
}
|
|
376
|
+
else if (Histogram.Num() < MCPBulkReadMaxCountByValues)
|
|
377
|
+
{
|
|
378
|
+
Histogram.Add(Key, 1);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (!bCountOnly)
|
|
383
|
+
{
|
|
384
|
+
Rows.Add(MakeShared<FJsonValueObject>(Row));
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// ── Response ────────────────────────────────────────────────────────────
|
|
389
|
+
auto Result = MCPSuccess();
|
|
390
|
+
Result->SetNumberField(TEXT("candidates"), CandidatePaths.Num());
|
|
391
|
+
Result->SetNumberField(TEXT("loaded"), Loaded);
|
|
392
|
+
Result->SetNumberField(TEXT("matched"), Matched);
|
|
393
|
+
Result->SetBoolField(TEXT("countOnly"), bCountOnly);
|
|
394
|
+
Result->SetBoolField(TEXT("scanTruncated"), bScanTruncated);
|
|
395
|
+
if (bScanTruncated)
|
|
396
|
+
{
|
|
397
|
+
Result->SetStringField(TEXT("scanNote"), FString::Printf(
|
|
398
|
+
TEXT("More than maxAssets (%d) candidates matched the selection; narrow 'directory' or 'classNames'."),
|
|
399
|
+
MaxAssets));
|
|
400
|
+
}
|
|
401
|
+
Result->SetArrayField(TEXT("unloadableAssets"), MCPStringListToJson(UnloadableAssets));
|
|
402
|
+
if (ClassFilteredOut.Num() > 0)
|
|
403
|
+
{
|
|
404
|
+
Result->SetArrayField(TEXT("classFilteredOut"), MCPStringListToJson(ClassFilteredOut));
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (!bCountOnly)
|
|
408
|
+
{
|
|
409
|
+
if (!OutputPath.IsEmpty())
|
|
410
|
+
{
|
|
411
|
+
// File output is the escape valve for a result set too large to be
|
|
412
|
+
// worth paging through. The rows still exist; they just do not go
|
|
413
|
+
// through the model's context to get to disk.
|
|
414
|
+
const FString Absolute = FPaths::ConvertRelativePathToFull(OutputPath);
|
|
415
|
+
if (!FFileHelper::SaveStringToFile(MCPBulkReadSerializeRows(Rows), *Absolute))
|
|
416
|
+
{
|
|
417
|
+
return MCPError(FString::Printf(TEXT("Failed to write 'outputPath': %s"), *Absolute));
|
|
418
|
+
}
|
|
419
|
+
Result->SetStringField(TEXT("outputPath"), Absolute);
|
|
420
|
+
Result->SetNumberField(TEXT("written"), Rows.Num());
|
|
421
|
+
}
|
|
422
|
+
else
|
|
423
|
+
{
|
|
424
|
+
const int32 First = FMath::Min(StartIndex, Rows.Num());
|
|
425
|
+
const int32 Last = FMath::Min(First + Limit, Rows.Num());
|
|
426
|
+
TArray<TSharedPtr<FJsonValue>> Page;
|
|
427
|
+
for (int32 Index = First; Index < Last; ++Index)
|
|
428
|
+
{
|
|
429
|
+
Page.Add(Rows[Index]);
|
|
430
|
+
}
|
|
431
|
+
Result->SetArrayField(TEXT("rows"), Page);
|
|
432
|
+
Result->SetNumberField(TEXT("returned"), Page.Num());
|
|
433
|
+
Result->SetNumberField(TEXT("startIndex"), StartIndex);
|
|
434
|
+
Result->SetNumberField(TEXT("limit"), Limit);
|
|
435
|
+
const int32 NextStartIndex = StartIndex + Page.Num();
|
|
436
|
+
Result->SetBoolField(TEXT("hasMore"), NextStartIndex < Rows.Num());
|
|
437
|
+
if (NextStartIndex < Rows.Num())
|
|
438
|
+
{
|
|
439
|
+
Result->SetNumberField(TEXT("nextStartIndex"), NextStartIndex);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (!GroupBy.IsEmpty())
|
|
445
|
+
{
|
|
446
|
+
GroupOrder.Sort([&GroupCounts](const FString& A, const FString& B)
|
|
447
|
+
{
|
|
448
|
+
const int32 CountA = GroupCounts.FindChecked(A);
|
|
449
|
+
const int32 CountB = GroupCounts.FindChecked(B);
|
|
450
|
+
return CountA != CountB ? CountA > CountB : A < B;
|
|
451
|
+
});
|
|
452
|
+
TArray<TSharedPtr<FJsonValue>> GroupArray;
|
|
453
|
+
for (const FString& Key : GroupOrder)
|
|
454
|
+
{
|
|
455
|
+
TSharedPtr<FJsonObject> GroupObject = MakeShared<FJsonObject>();
|
|
456
|
+
GroupObject->SetStringField(TEXT("key"), Key);
|
|
457
|
+
GroupObject->SetNumberField(TEXT("count"), GroupCounts.FindChecked(Key));
|
|
458
|
+
if (const TArray<FString>* Samples = GroupSamplesByKey.Find(Key))
|
|
459
|
+
{
|
|
460
|
+
GroupObject->SetArrayField(TEXT("samples"), MCPStringListToJson(*Samples));
|
|
461
|
+
}
|
|
462
|
+
GroupArray.Add(MakeShared<FJsonValueObject>(GroupObject));
|
|
463
|
+
}
|
|
464
|
+
Result->SetStringField(TEXT("groupBy"), GroupBy);
|
|
465
|
+
Result->SetArrayField(TEXT("groups"), GroupArray);
|
|
466
|
+
Result->SetBoolField(TEXT("groupsTruncated"), bGroupsTruncated);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (CountByPaths.Num() > 0)
|
|
470
|
+
{
|
|
471
|
+
TSharedPtr<FJsonObject> CountsObject = MakeShared<FJsonObject>();
|
|
472
|
+
for (const FString& CountPath : CountByPaths)
|
|
473
|
+
{
|
|
474
|
+
TSharedPtr<FJsonObject> Histogram = MakeShared<FJsonObject>();
|
|
475
|
+
if (const TMap<FString, int32>* Values = CountByHistograms.Find(CountPath))
|
|
476
|
+
{
|
|
477
|
+
for (const TPair<FString, int32>& Pair : *Values)
|
|
478
|
+
{
|
|
479
|
+
Histogram->SetNumberField(Pair.Key, Pair.Value);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
CountsObject->SetObjectField(CountPath, Histogram);
|
|
483
|
+
}
|
|
484
|
+
Result->SetObjectField(TEXT("counts"), CountsObject);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// The read guarantee, asserted rather than assumed. Loading an asset to
|
|
488
|
+
// read it does not dirty its package; if something did, the caller sees
|
|
489
|
+
// which package rather than an unexplained unsaved-changes marker.
|
|
490
|
+
TArray<FString> DirtyAfter;
|
|
491
|
+
MCPEditorState::CollectDirtyEditorPackageNames(DirtyAfter);
|
|
492
|
+
for (const FString& Already : DirtyBefore)
|
|
493
|
+
{
|
|
494
|
+
DirtyAfter.Remove(Already);
|
|
495
|
+
}
|
|
496
|
+
Result->SetBoolField(TEXT("dirtiedPackages"), DirtyAfter.Num() > 0);
|
|
497
|
+
if (DirtyAfter.Num() > 0)
|
|
498
|
+
{
|
|
499
|
+
Result->SetArrayField(TEXT("dirtyPackages"), MCPStringListToJson(DirtyAfter));
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return MCPResult(Result);
|
|
503
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "CoreMinimal.h"
|
|
4
|
+
#include "Dom/JsonObject.h"
|
|
5
|
+
#include "Dom/JsonValue.h"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* asset(bulk_read_properties) (#909).
|
|
9
|
+
*
|
|
10
|
+
* Its own class rather than another FAssetHandlers member, with its own
|
|
11
|
+
* registration entry in BridgeServer.cpp, so this lands without touching
|
|
12
|
+
* AssetHandlers.cpp at all.
|
|
13
|
+
*/
|
|
14
|
+
class FAssetBulkReadHandlers
|
|
15
|
+
{
|
|
16
|
+
public:
|
|
17
|
+
static void RegisterHandlers(class FMCPHandlerRegistry& Registry);
|
|
18
|
+
|
|
19
|
+
private:
|
|
20
|
+
static TSharedPtr<FJsonValue> BulkReadAssetProperties(const TSharedPtr<FJsonObject>& Params);
|
|
21
|
+
};
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkUpsert.cpp
CHANGED
|
@@ -351,7 +351,7 @@ TSharedPtr<FJsonValue> FAssetHandlers::BulkRestoreDataAssets(const TSharedPtr<FJ
|
|
|
351
351
|
continue;
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
-
UObject* Asset =
|
|
354
|
+
UObject* Asset = MCPLoadAssetObject(AssetPath);
|
|
355
355
|
if (!Asset)
|
|
356
356
|
{
|
|
357
357
|
Errors.Add(MakeShared<FJsonValueString>(FString::Printf(TEXT("Unable to load '%s' for rollback"), *AssetPath)));
|
|
@@ -510,7 +510,7 @@ TSharedPtr<FJsonValue> FAssetHandlers::BulkUpsertDataAssets(const TSharedPtr<FJs
|
|
|
510
510
|
*Prepared.DataClass->GetPathName()));
|
|
511
511
|
}
|
|
512
512
|
|
|
513
|
-
Prepared.ExistingAsset =
|
|
513
|
+
Prepared.ExistingAsset = MCPLoadAssetObject(Prepared.AssetPath);
|
|
514
514
|
if (Prepared.ExistingAsset)
|
|
515
515
|
{
|
|
516
516
|
if (OnConflict == TEXT("error"))
|
|
@@ -136,7 +136,7 @@ TSharedPtr<FJsonValue> FAssetHandlers::ListEnumValues(const TSharedPtr<FJsonObje
|
|
|
136
136
|
FString AssetPath;
|
|
137
137
|
if (auto Err = RequireStringAlt(Params, TEXT("assetPath"), TEXT("path"), AssetPath)) return Err;
|
|
138
138
|
|
|
139
|
-
UEnum* Enum =
|
|
139
|
+
UEnum* Enum = LoadAssetByPath<UEnum>(AssetPath);
|
|
140
140
|
if (!Enum) return MCPError(FString::Printf(TEXT("Enum not found: %s"), *AssetPath));
|
|
141
141
|
|
|
142
142
|
TSharedPtr<FJsonObject> Res = MCPSuccess();
|
|
@@ -162,7 +162,7 @@ TSharedPtr<FJsonValue> FAssetHandlers::EditUserDefinedEnum(const TSharedPtr<FJso
|
|
|
162
162
|
FString Op;
|
|
163
163
|
if (auto Err = RequireString(Params, TEXT("op"), Op)) return Err;
|
|
164
164
|
|
|
165
|
-
UUserDefinedEnum* Enum =
|
|
165
|
+
UUserDefinedEnum* Enum = LoadAssetByPath<UUserDefinedEnum>(AssetPath);
|
|
166
166
|
if (!Enum) return MCPError(FString::Printf(TEXT("UserDefinedEnum not found (native UEnums cannot be edited): %s"), *AssetPath));
|
|
167
167
|
|
|
168
168
|
TSharedPtr<FJsonObject> Res = MCPSuccess();
|