ue-mcp 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/action-class.js +56 -3
- package/dist/action-class.js.map +1 -1
- package/dist/bridge-timeouts.d.ts +64 -0
- package/dist/bridge-timeouts.js +118 -0
- package/dist/bridge-timeouts.js.map +1 -0
- package/dist/bridge.js +10 -2
- package/dist/bridge.js.map +1 -1
- package/dist/editor-control.d.ts +72 -5
- package/dist/editor-control.js +164 -140
- package/dist/editor-control.js.map +1 -1
- package/dist/editor-target.d.ts +55 -1
- package/dist/editor-target.js +107 -10
- package/dist/editor-target.js.map +1 -1
- package/dist/engine-observer.d.ts +59 -5
- package/dist/engine-observer.js +249 -29
- package/dist/engine-observer.js.map +1 -1
- package/dist/engine-root.d.ts +91 -0
- package/dist/engine-root.js +448 -0
- package/dist/engine-root.js.map +1 -0
- package/dist/epic-enrich.js +16 -1
- package/dist/epic-enrich.js.map +1 -1
- package/dist/feedback-cli.js +4 -0
- package/dist/feedback-cli.js.map +1 -1
- package/dist/feedback-deferred.d.ts +9 -0
- package/dist/feedback-deferred.js +2 -0
- package/dist/feedback-deferred.js.map +1 -1
- package/dist/feedback-fallback.d.ts +99 -0
- package/dist/feedback-fallback.js +173 -0
- package/dist/feedback-fallback.js.map +1 -0
- package/dist/flow/write-methods.js +20 -0
- package/dist/flow/write-methods.js.map +1 -1
- package/dist/index.js +41 -2
- package/dist/index.js.map +1 -1
- package/dist/lean-context.js +8 -3
- package/dist/lean-context.js.map +1 -1
- package/dist/locking.js +11 -2
- package/dist/locking.js.map +1 -1
- package/dist/plugin/loader.d.ts +4 -0
- package/dist/plugin/loader.js +22 -8
- package/dist/plugin/loader.js.map +1 -1
- package/dist/plugin/manifest.d.ts +72 -52
- package/dist/plugin/manifest.js +118 -21
- package/dist/plugin/manifest.js.map +1 -1
- package/dist/plugin-cli.js +16 -3
- package/dist/plugin-cli.js.map +1 -1
- package/dist/project.d.ts +11 -0
- package/dist/project.js +23 -2
- package/dist/project.js.map +1 -1
- package/dist/python-gate.d.ts +95 -0
- package/dist/python-gate.js +175 -0
- package/dist/python-gate.js.map +1 -0
- package/dist/tool-counts.json +16 -16
- package/dist/tools/animation.js +288 -24
- package/dist/tools/animation.js.map +1 -1
- package/dist/tools/asset.js +79 -14
- package/dist/tools/asset.js.map +1 -1
- package/dist/tools/audio.js +59 -5
- package/dist/tools/audio.js.map +1 -1
- package/dist/tools/blueprint.js +29 -12
- package/dist/tools/blueprint.js.map +1 -1
- package/dist/tools/chooser.js +4 -1
- package/dist/tools/chooser.js.map +1 -1
- package/dist/tools/editor.js +81 -43
- package/dist/tools/editor.js.map +1 -1
- package/dist/tools/feedback.js +214 -48
- package/dist/tools/feedback.js.map +1 -1
- package/dist/tools/foliage.js +27 -1
- package/dist/tools/foliage.js.map +1 -1
- package/dist/tools/gameplay.js +38 -11
- package/dist/tools/gameplay.js.map +1 -1
- package/dist/tools/gas.js +17 -5
- package/dist/tools/gas.js.map +1 -1
- package/dist/tools/landscape.js +22 -7
- package/dist/tools/landscape.js.map +1 -1
- package/dist/tools/level.js +322 -51
- package/dist/tools/level.js.map +1 -1
- package/dist/tools/material.js +10 -4
- package/dist/tools/material.js.map +1 -1
- package/dist/tools/niagara.js +3 -2
- package/dist/tools/niagara.js.map +1 -1
- package/dist/tools/pcg.js +6 -5
- package/dist/tools/pcg.js.map +1 -1
- package/dist/tools/plugins.js +2 -0
- package/dist/tools/plugins.js.map +1 -1
- package/dist/tools/project.js +47 -20
- package/dist/tools/project.js.map +1 -1
- package/dist/types.d.ts +24 -0
- package/dist/types.js +46 -3
- package/dist/types.js.map +1 -1
- package/dist/ue-mcp.default.yml +493 -125
- package/package.json +2 -2
- package/plugin/ue_mcp_bridge/NATIVE_RUNTIME_VISIBILITY.md +53 -0
- package/plugin/ue_mcp_bridge/NATIVE_STATIC_MESH_USAGE_PROGRESS.md +115 -0
- package/plugin/ue_mcp_bridge/README_MassHandlers.md +97 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.cpp +14 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.cpp +21 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.h +9 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerJsonProperty.h +395 -69
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.cpp +79 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.h +25 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +3 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRigSequencer.cpp +3061 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRetargeterAuthoring.cpp +961 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRigAuthoring.cpp +900 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Pose.cpp +769 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Sequence.cpp +44 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_SkeletalLive.cpp +217 -11
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_StateMachine.cpp +551 -24
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Validation.cpp +735 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.cpp +352 -73
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.h +8 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkProperties.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.cpp +503 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkRead.h +21 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_BulkUpsert.cpp +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Enum.cpp +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.cpp +902 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Geometry.h +33 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Import.cpp +478 -134
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Mesh.cpp +5 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.cpp +933 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_MeshBoolean.h +35 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Redirectors.cpp +478 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_RenderTarget.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Sockets.cpp +4 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Subobject.cpp +319 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_SoundCue.cpp +3 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.cpp +482 -35
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.h +10 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.cpp +502 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Collision.h +43 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Functions.cpp +89 -7
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Graph.cpp +17 -51
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +107 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Properties.cpp +10 -10
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Search.cpp +648 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.cpp +5 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.cpp +252 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DiffHandlers.h +10 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.cpp +252 -41
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.h +4 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +250 -27
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIE.cpp +303 -125
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIERuntime.cpp +73 -50
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_RuntimeVisibility.cpp +757 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.cpp +11 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +3 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers_Batch.cpp +419 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.cpp +39 -161
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.h +66 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BTAuthoring.cpp +1323 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BehaviorTree.cpp +1211 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +2 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +60 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Runtime.cpp +363 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/HandlerEditorState.h +84 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +1288 -36
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.h +3 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +41 -16
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.cpp +959 -213
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.h +66 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_BatchWrite.cpp +1571 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Convert.cpp +316 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Inspection.cpp +280 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection.cpp +666 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection_Internal.h +63 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Lights.cpp +43 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_MultiLevel.cpp +13 -47
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_PostProcess.cpp +527 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Query.cpp +1169 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Refresh.cpp +723 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Save.cpp +325 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Spatial.cpp +360 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Trace.cpp +178 -58
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Transient.cpp +337 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Volumes.cpp +25 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartition.cpp +10 -9
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartitionSettings.cpp +686 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.cpp +467 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MassHandlers.h +22 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.cpp +452 -175
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.h +5 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Build.cpp +597 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.cpp +17 -15
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PCGHandlers.cpp +38 -168
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +39 -30
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +392 -78
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +2 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers_Internal.h +83 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.cpp +200 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.h +15 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +19 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.cpp +31 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.cpp +307 -69
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.h +84 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Extraction.cpp +8 -41
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Properties.cpp +33 -52
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/ActorSelectorTests.cpp +344 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationControlRigTimelineTests.cpp +60 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AnimationPoseTests.cpp +115 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetBulkReadTests.cpp +177 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetDeleteGuardTests.cpp +276 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPathResolutionTests.cpp +243 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetPropertyPersistTests.cpp +213 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AssetSubobjectTests.cpp +235 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/AutomationRunnerTests.cpp +72 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeAuthoringTests.cpp +526 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BehaviorTreeNodeTests.cpp +334 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BlueprintHandlerSurfaceTests.cpp +362 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/BridgeProtocolTests.cpp +14 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/CollisionQueryTests.cpp +288 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/DataTableRowWriteTests.cpp +453 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/EditorFunctionCallTests.cpp +223 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/FoliageBatchTests.cpp +147 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GameThreadGateTests.cpp +82 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/GasLiveAttributeTests.cpp +183 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LandscapeSampleTests.cpp +119 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelBatchWriteTests.cpp +176 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelComponentTreeInstanceCountTests.cpp +189 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelConvertBrushesTests.cpp +100 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelInstanceProjectionTests.cpp +265 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelPostProcessOverrideTests.cpp +258 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelQueryComponentsTests.cpp +195 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelRefreshTests.cpp +142 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelSaveReportTests.cpp +125 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelScriptHandlersTests.cpp +42 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelStaticMeshUsageTests.cpp +412 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTraceWorldScopeTests.cpp +133 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelTransientActorTests.cpp +205 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/LevelWorldPartitionSettingsTests.cpp +168 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTestTypes.h +51 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MCPInstancedStructPathTests.cpp +379 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MaterialBuildTests.cpp +238 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshBooleanTests.cpp +170 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/MeshGeometryTests.cpp +116 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageSaveExtensionTests.cpp +161 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/PackageWriteGuardTests.cpp +253 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/RuntimeVisibilityTests.cpp +143 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerHandlerTests.cpp +660 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SequencerScrubTests.cpp +50 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/SkeletonDiffTests.cpp +685 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/WidgetBlueprintResolveTests.cpp +145 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/UE_MCP_Bridge.cpp +80 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerFunctionCall.h +509 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerQuery.h +407 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerUtils.h +1008 -77
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/UE_MCP_Bridge.Build.cs +87 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/MCPEngineStatus.cpp +152 -14
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/Tests/MCPEngineStatusTests.cpp +65 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Public/MCPEngineStatus.h +32 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/UE_MCP_BridgeStatus.Build.cs +2 -0
- package/skills/ue-mcp-animation/SKILL.md +154 -0
- package/skills/ue-mcp-blueprint/SKILL.md +71 -0
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
#include "HandlerRegistry.h"
|
|
4
4
|
#include "HandlerUtils.h"
|
|
5
5
|
#include "HandlerJsonProperty.h"
|
|
6
|
+
#include "JsonSerializer.h"
|
|
6
7
|
#include "Kismet2/BlueprintEditorUtils.h"
|
|
7
8
|
#include "Kismet2/KismetEditorUtilities.h"
|
|
8
9
|
#include "BlueprintEditorLibrary.h"
|
|
9
10
|
#include "Engine/Blueprint.h"
|
|
11
|
+
#include "Engine/BlueprintGeneratedClass.h"
|
|
12
|
+
// #942: World -> level script Blueprint resolution.
|
|
13
|
+
#include "Engine/World.h"
|
|
14
|
+
#include "Engine/Level.h"
|
|
15
|
+
#include "Engine/LevelScriptBlueprint.h"
|
|
10
16
|
#include "EdGraph/EdGraphPin.h"
|
|
11
17
|
#include "EdGraphSchema_K2.h"
|
|
12
18
|
#include "K2Node.h"
|
|
@@ -17,6 +23,7 @@
|
|
|
17
23
|
#include "Editor.h"
|
|
18
24
|
#include "Editor/EditorEngine.h"
|
|
19
25
|
#include "UObject/UObjectGlobals.h"
|
|
26
|
+
#include "UObject/UObjectHash.h"
|
|
20
27
|
#include "UObject/UnrealType.h"
|
|
21
28
|
#include "UObject/Package.h"
|
|
22
29
|
#include "Misc/PackageName.h"
|
|
@@ -25,6 +32,7 @@
|
|
|
25
32
|
#include "UObject/TopLevelAssetPath.h"
|
|
26
33
|
#include "AssetToolsModule.h"
|
|
27
34
|
#include "IAssetTools.h"
|
|
35
|
+
#include "PackageTools.h"
|
|
28
36
|
#include "Factories/BlueprintFactory.h"
|
|
29
37
|
#include "EdGraph/EdGraph.h"
|
|
30
38
|
#include "K2Node_CallFunction.h"
|
|
@@ -35,6 +43,7 @@
|
|
|
35
43
|
#include "K2Node_EditablePinBase.h"
|
|
36
44
|
#include "K2Node_IfThenElse.h"
|
|
37
45
|
#include "K2Node_MacroInstance.h"
|
|
46
|
+
#include "K2Node_AddComponent.h"
|
|
38
47
|
#include "K2Node_VariableGet.h"
|
|
39
48
|
#include "K2Node_DynamicCast.h"
|
|
40
49
|
#include "K2Node_VariableSet.h"
|
|
@@ -69,6 +78,10 @@
|
|
|
69
78
|
void FBlueprintHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
|
|
70
79
|
{
|
|
71
80
|
constexpr float ReadBlueprintGraphTimeoutSeconds = 180.0f;
|
|
81
|
+
// #945: a first sweep on a cold project pays for every package load the
|
|
82
|
+
// registry could not rule out, which the default request timeout does not
|
|
83
|
+
// come close to covering.
|
|
84
|
+
constexpr float SearchCallSitesTimeoutSeconds = 600.0f;
|
|
72
85
|
|
|
73
86
|
Registry.RegisterHandler(TEXT("create_blueprint"), &CreateBlueprint);
|
|
74
87
|
Registry.RegisterHandler(TEXT("read_blueprint"), &ReadBlueprint);
|
|
@@ -107,6 +120,7 @@ void FBlueprintHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
|
|
|
107
120
|
Registry.RegisterHandler(TEXT("delete_variable"), &DeleteVariable);
|
|
108
121
|
Registry.RegisterHandler(TEXT("add_function_parameter"), &AddFunctionParameter);
|
|
109
122
|
Registry.RegisterHandler(TEXT("set_variable_default"), &SetVariableDefault);
|
|
123
|
+
Registry.RegisterHandler(TEXT("get_blueprint_variable_default"), &GetVariableDefault);
|
|
110
124
|
|
|
111
125
|
// v0.7.8 stubs
|
|
112
126
|
Registry.RegisterHandler(TEXT("read_blueprint_graph_summary"), &ReadBlueprintGraphSummary);
|
|
@@ -125,6 +139,7 @@ void FBlueprintHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
|
|
|
125
139
|
Registry.RegisterHandler(TEXT("reparent_component"), &ReparentComponent);
|
|
126
140
|
Registry.RegisterHandler(TEXT("reparent_blueprint"), &ReparentBlueprint);
|
|
127
141
|
Registry.RegisterHandler(TEXT("flush_inheritable_component_handler"), &FlushInheritableComponentHandler);
|
|
142
|
+
Registry.RegisterHandler(TEXT("flush_blueprint_component_templates"), &FlushComponentTemplates);
|
|
128
143
|
Registry.RegisterHandler(TEXT("set_actor_tick_settings"), &SetActorTickSettings);
|
|
129
144
|
|
|
130
145
|
// v0.7.12 - issue #128 - single-property read (inherited-aware)
|
|
@@ -147,6 +162,9 @@ void FBlueprintHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
|
|
|
147
162
|
Registry.RegisterHandler(TEXT("connect_pins_batch"), &ConnectPinsBatch);
|
|
148
163
|
Registry.RegisterHandler(TEXT("set_node_position"), &SetNodePosition);
|
|
149
164
|
Registry.RegisterHandler(TEXT("auto_layout_graph"), &AutoLayoutGraph);
|
|
165
|
+
|
|
166
|
+
// #945: project-wide call-site audit (BlueprintHandlers_Search.cpp).
|
|
167
|
+
Registry.RegisterHandlerWithTimeout(TEXT("search_blueprint_call_sites"), &SearchCallSites, SearchCallSitesTimeoutSeconds);
|
|
150
168
|
}
|
|
151
169
|
|
|
152
170
|
// ---------------------------------------------------------------------------
|
|
@@ -166,7 +184,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ReadBlueprintGraphSummary(const TShar
|
|
|
166
184
|
const bool bFiltering = !TitleFilter.IsEmpty() || !ClassFilter.IsEmpty();
|
|
167
185
|
|
|
168
186
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
169
|
-
if (!Blueprint) return
|
|
187
|
+
if (!Blueprint) return BlueprintNotFoundError(AssetPath);
|
|
170
188
|
|
|
171
189
|
UEdGraph* Graph = FindGraph(Blueprint, GraphName);
|
|
172
190
|
if (!Graph) return MCPError(FString::Printf(TEXT("Graph not found: %s"), *GraphName));
|
|
@@ -214,6 +232,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ReadBlueprintGraphSummary(const TShar
|
|
|
214
232
|
|
|
215
233
|
TSharedPtr<FJsonObject> Result = MCPSuccess();
|
|
216
234
|
Result->SetStringField(TEXT("path"), AssetPath);
|
|
235
|
+
AnnotateResolvedBlueprint(Result, Blueprint);
|
|
217
236
|
Result->SetStringField(TEXT("graphName"), GraphName);
|
|
218
237
|
// #298: identify graph type so callers can tell ubergraph / construction
|
|
219
238
|
// script / function / macro apart without having to grep node titles.
|
|
@@ -254,7 +273,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::GetBlueprintExecutionFlow(const TShar
|
|
|
254
273
|
FString EntryPoint = OptionalString(Params, TEXT("entryPoint"), TEXT(""));
|
|
255
274
|
|
|
256
275
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
257
|
-
if (!Blueprint) return
|
|
276
|
+
if (!Blueprint) return BlueprintNotFoundError(AssetPath);
|
|
258
277
|
|
|
259
278
|
UEdGraph* Graph = FindGraph(Blueprint, GraphName);
|
|
260
279
|
if (!Graph) return MCPError(FString::Printf(TEXT("Graph not found: %s"), *GraphName));
|
|
@@ -336,6 +355,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::GetBlueprintExecutionFlow(const TShar
|
|
|
336
355
|
|
|
337
356
|
TSharedPtr<FJsonObject> Result = MCPSuccess();
|
|
338
357
|
Result->SetStringField(TEXT("path"), AssetPath);
|
|
358
|
+
AnnotateResolvedBlueprint(Result, Blueprint);
|
|
339
359
|
Result->SetStringField(TEXT("graphName"), GraphName);
|
|
340
360
|
Result->SetStringField(TEXT("entryPoint"), Entry->GetNodeTitle(ENodeTitleType::ListView).ToString());
|
|
341
361
|
Result->SetStringField(TEXT("entryId"), Entry->NodeGuid.ToString(EGuidFormats::Short));
|
|
@@ -351,7 +371,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::GetBlueprintDependencies(const TShare
|
|
|
351
371
|
const bool bReverse = OptionalBool(Params, TEXT("reverse"), false);
|
|
352
372
|
|
|
353
373
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
354
|
-
if (!Blueprint) return
|
|
374
|
+
if (!Blueprint) return BlueprintNotFoundError(AssetPath);
|
|
355
375
|
|
|
356
376
|
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
|
357
377
|
IAssetRegistry& Registry = AssetRegistryModule.Get();
|
|
@@ -433,9 +453,52 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::GetBlueprintDependencies(const TShare
|
|
|
433
453
|
return MCPResult(Result);
|
|
434
454
|
}
|
|
435
455
|
|
|
456
|
+
namespace
|
|
457
|
+
{
|
|
458
|
+
// #942: resolve a World/umap path to the level script Blueprint that lives
|
|
459
|
+
// inside it. The level script is a subobject of the persistent level, never
|
|
460
|
+
// an asset of its own, so loading a UBlueprint from "/Game/Maps/SomeLevel"
|
|
461
|
+
// can never find it however the path is spelled.
|
|
462
|
+
//
|
|
463
|
+
// bDontCreate is deliberate. A map that has never had a Level Blueprint
|
|
464
|
+
// opened has no level script object, and a READ must not author one as a
|
|
465
|
+
// side effect: it would dirty the map package and write a new subobject
|
|
466
|
+
// into somebody's level for asking a question about it.
|
|
467
|
+
ULevelScriptBlueprint* ResolveLevelScriptBlueprint(const FString& AssetPath)
|
|
468
|
+
{
|
|
469
|
+
UWorld* World = LoadAssetByPath<UWorld>(AssetPath);
|
|
470
|
+
if (!World || !World->PersistentLevel) return nullptr;
|
|
471
|
+
return World->PersistentLevel->GetLevelScriptBlueprint(/*bDontCreate=*/true);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
436
475
|
UBlueprint* FBlueprintHandlers::LoadBlueprint(const FString& AssetPath)
|
|
437
476
|
{
|
|
438
|
-
|
|
477
|
+
if (UBlueprint* Direct = LoadAssetByPath<UBlueprint>(AssetPath))
|
|
478
|
+
{
|
|
479
|
+
return Direct;
|
|
480
|
+
}
|
|
481
|
+
// #942: one resolution point, so every action that reaches a Blueprint
|
|
482
|
+
// through this function accepts a umap path on exactly the same terms.
|
|
483
|
+
return ResolveLevelScriptBlueprint(AssetPath);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
TSharedPtr<FJsonValue> BlueprintNotFoundError(const FString& AssetPath)
|
|
487
|
+
{
|
|
488
|
+
if (UWorld* World = LoadAssetByPath<UWorld>(AssetPath))
|
|
489
|
+
{
|
|
490
|
+
return MCPError(FString::Printf(
|
|
491
|
+
TEXT("'%s' is a World, and its level script Blueprint does not exist yet, so there is nothing to read. Open the map's Level Blueprint in the editor once (that creates it), then retry this call with the same path. When it exists it resolves to %s:PersistentLevel.%s"),
|
|
492
|
+
*AssetPath, *World->GetPathName(), *World->GetName()));
|
|
493
|
+
}
|
|
494
|
+
return MCPError(FString::Printf(TEXT("Blueprint not found: %s"), *AssetPath));
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
void AnnotateResolvedBlueprint(const TSharedPtr<FJsonObject>& Result, UBlueprint* Blueprint)
|
|
498
|
+
{
|
|
499
|
+
if (!Result.IsValid() || !Blueprint) return;
|
|
500
|
+
Result->SetStringField(TEXT("blueprintPath"), Blueprint->GetPathName());
|
|
501
|
+
Result->SetBoolField(TEXT("isLevelScript"), Blueprint->IsA<ULevelScriptBlueprint>());
|
|
439
502
|
}
|
|
440
503
|
|
|
441
504
|
// ---------------------------------------------------------------------------
|
|
@@ -451,9 +514,9 @@ namespace
|
|
|
451
514
|
const FString Name = Graph->GetName();
|
|
452
515
|
const int32 DuplicateIndex = SeenCounts.FindOrAdd(Name)++;
|
|
453
516
|
const int32 DuplicateCount = NameCounts.FindRef(Name);
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
517
|
+
// #945: one selector rule, shared with search_call_sites so the two
|
|
518
|
+
// cannot disagree about how to address the same graph.
|
|
519
|
+
const FString Selector = MakeGraphSelector(Name, DuplicateIndex, DuplicateCount);
|
|
457
520
|
|
|
458
521
|
TSharedPtr<FJsonObject> GraphObj = MakeShared<FJsonObject>();
|
|
459
522
|
GraphObj->SetStringField(TEXT("name"), Name);
|
|
@@ -465,17 +528,6 @@ namespace
|
|
|
465
528
|
GraphObj->SetNumberField(TEXT("duplicateCount"), DuplicateCount);
|
|
466
529
|
return GraphObj;
|
|
467
530
|
}
|
|
468
|
-
|
|
469
|
-
void CountGraphNames(const TArray<UEdGraph*>& Graphs, TMap<FString, int32>& OutNameCounts)
|
|
470
|
-
{
|
|
471
|
-
for (UEdGraph* Graph : Graphs)
|
|
472
|
-
{
|
|
473
|
-
if (Graph)
|
|
474
|
-
{
|
|
475
|
-
++OutNameCounts.FindOrAdd(Graph->GetName());
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
531
|
}
|
|
480
532
|
|
|
481
533
|
TSharedPtr<FJsonValue> FBlueprintHandlers::ListGraphs(const TSharedPtr<FJsonObject>& Params)
|
|
@@ -486,7 +538,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ListGraphs(const TSharedPtr<FJsonObje
|
|
|
486
538
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
487
539
|
if (!Blueprint)
|
|
488
540
|
{
|
|
489
|
-
return
|
|
541
|
+
return BlueprintNotFoundError(AssetPath);
|
|
490
542
|
}
|
|
491
543
|
|
|
492
544
|
TArray<UEdGraph*> AllGraphs;
|
|
@@ -505,6 +557,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ListGraphs(const TSharedPtr<FJsonObje
|
|
|
505
557
|
|
|
506
558
|
auto Result = MCPSuccess();
|
|
507
559
|
Result->SetStringField(TEXT("path"), AssetPath);
|
|
560
|
+
AnnotateResolvedBlueprint(Result, Blueprint);
|
|
508
561
|
Result->SetArrayField(TEXT("graphs"), GraphsArray);
|
|
509
562
|
|
|
510
563
|
return MCPResult(Result);
|
|
@@ -527,7 +580,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ResolveGraph(const TSharedPtr<FJsonOb
|
|
|
527
580
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
528
581
|
if (!Blueprint)
|
|
529
582
|
{
|
|
530
|
-
return
|
|
583
|
+
return BlueprintNotFoundError(AssetPath);
|
|
531
584
|
}
|
|
532
585
|
|
|
533
586
|
TArray<UEdGraph*> AllGraphs;
|
|
@@ -588,6 +641,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ResolveGraph(const TSharedPtr<FJsonOb
|
|
|
588
641
|
|
|
589
642
|
TSharedPtr<FJsonObject> Result = MCPSuccess();
|
|
590
643
|
Result->SetStringField(TEXT("path"), AssetPath);
|
|
644
|
+
AnnotateResolvedBlueprint(Result, Blueprint);
|
|
591
645
|
Result->SetStringField(TEXT("requestedGraphName"), RequestedName);
|
|
592
646
|
Result->SetNumberField(TEXT("matchCount"), MatchArray.Num());
|
|
593
647
|
Result->SetBoolField(TEXT("ambiguous"), MatchArray.Num() > 1);
|
|
@@ -1122,7 +1176,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ReadBlueprint(const TSharedPtr<FJsonO
|
|
|
1122
1176
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
1123
1177
|
if (!Blueprint)
|
|
1124
1178
|
{
|
|
1125
|
-
return
|
|
1179
|
+
return BlueprintNotFoundError(AssetPath);
|
|
1126
1180
|
}
|
|
1127
1181
|
|
|
1128
1182
|
// #353/#370: per-component property dump on demand. Off by default so the
|
|
@@ -1153,6 +1207,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ReadBlueprint(const TSharedPtr<FJsonO
|
|
|
1153
1207
|
|
|
1154
1208
|
auto Result = MCPSuccess();
|
|
1155
1209
|
Result->SetStringField(TEXT("path"), AssetPath);
|
|
1210
|
+
AnnotateResolvedBlueprint(Result, Blueprint);
|
|
1156
1211
|
Result->SetStringField(TEXT("className"), Blueprint->GetName());
|
|
1157
1212
|
if (Blueprint->ParentClass)
|
|
1158
1213
|
{
|
|
@@ -1331,7 +1386,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::AddVariable(const TSharedPtr<FJsonObj
|
|
|
1331
1386
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
1332
1387
|
if (!Blueprint)
|
|
1333
1388
|
{
|
|
1334
|
-
return
|
|
1389
|
+
return BlueprintNotFoundError(AssetPath);
|
|
1335
1390
|
}
|
|
1336
1391
|
|
|
1337
1392
|
// Idempotency: if the variable already exists on the blueprint, short-circuit.
|
|
@@ -1399,7 +1454,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::AddComponent(const TSharedPtr<FJsonOb
|
|
|
1399
1454
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
1400
1455
|
if (!Blueprint)
|
|
1401
1456
|
{
|
|
1402
|
-
return
|
|
1457
|
+
return BlueprintNotFoundError(AssetPath);
|
|
1403
1458
|
}
|
|
1404
1459
|
|
|
1405
1460
|
// Idempotency: existing SCS component with same name short-circuits.
|
|
@@ -1562,7 +1617,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::CompileBlueprint(const TSharedPtr<FJs
|
|
|
1562
1617
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
1563
1618
|
if (!Blueprint)
|
|
1564
1619
|
{
|
|
1565
|
-
return
|
|
1620
|
+
return BlueprintNotFoundError(AssetPath);
|
|
1566
1621
|
}
|
|
1567
1622
|
|
|
1568
1623
|
// #703: capture the compiler log and report real status instead of always
|
|
@@ -1943,15 +1998,217 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ListNodeTypes(const TSharedPtr<FJsonO
|
|
|
1943
1998
|
return MCPResult(Result);
|
|
1944
1999
|
}
|
|
1945
2000
|
|
|
2001
|
+
// ---------------------------------------------------------------------------
|
|
2002
|
+
// #902 / #931: resolved variable defaults, and whether they are on disk.
|
|
2003
|
+
//
|
|
2004
|
+
// list_variables could confirm a variable existed but nothing returned the
|
|
2005
|
+
// value the generated class actually resolved to, so a write-compile-readback
|
|
2006
|
+
// loop was impossible natively and callers dropped to Python for
|
|
2007
|
+
// get_default_object(bp.generated_class()).get_editor_property(name).
|
|
2008
|
+
//
|
|
2009
|
+
// The value lives on the CDO, not on FBPVariableDescription::DefaultValue. The
|
|
2010
|
+
// engine documents that string as an "optional new default value", and it is
|
|
2011
|
+
// empty for most variables, so reading it answers a different question than
|
|
2012
|
+
// the one being asked. Anything that reads it instead reports an empty default
|
|
2013
|
+
// for a variable that plainly has one.
|
|
2014
|
+
//
|
|
2015
|
+
// Persistence is reported separately, and that separation is the point (#931).
|
|
2016
|
+
// A write that sets a CDO property and marks the package dirty without saving
|
|
2017
|
+
// it reads back correctly for the rest of the session and is gone on the next
|
|
2018
|
+
// editor start. UPackage::IsDirty is the engine's own record of exactly that
|
|
2019
|
+
// state, so `persisted` is false while the package holds unsaved changes: the
|
|
2020
|
+
// readback distinguishes "this value is on disk" from "this value is in this
|
|
2021
|
+
// process", instead of echoing the write back at the caller either way.
|
|
2022
|
+
// ---------------------------------------------------------------------------
|
|
2023
|
+
namespace
|
|
2024
|
+
{
|
|
2025
|
+
struct FResolvedVariableDefault
|
|
2026
|
+
{
|
|
2027
|
+
FProperty* Property = nullptr;
|
|
2028
|
+
const void* ValueAddress = nullptr;
|
|
2029
|
+
FString ValueText;
|
|
2030
|
+
TSharedPtr<FJsonValue> Value;
|
|
2031
|
+
FString DeclaringClass;
|
|
2032
|
+
FString DeclaringClassPath;
|
|
2033
|
+
bool bInherited = false;
|
|
2034
|
+
};
|
|
2035
|
+
|
|
2036
|
+
// Resolve one variable's compiled default off the Blueprint's generated
|
|
2037
|
+
// class CDO. Returns false with a caller-facing reason on any miss.
|
|
2038
|
+
bool ResolveVariableDefault(
|
|
2039
|
+
UBlueprint* Blueprint,
|
|
2040
|
+
const FString& VarName,
|
|
2041
|
+
FResolvedVariableDefault& Out,
|
|
2042
|
+
FString& OutError)
|
|
2043
|
+
{
|
|
2044
|
+
if (!Blueprint)
|
|
2045
|
+
{
|
|
2046
|
+
OutError = TEXT("No Blueprint to resolve a variable default from");
|
|
2047
|
+
return false;
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
UClass* GeneratedClass = Blueprint->GeneratedClass.Get();
|
|
2051
|
+
if (!GeneratedClass)
|
|
2052
|
+
{
|
|
2053
|
+
OutError = FString::Printf(
|
|
2054
|
+
TEXT("Blueprint '%s' has no generated class, so it has no resolved defaults yet. Compile it first (blueprint compile)."),
|
|
2055
|
+
*Blueprint->GetName());
|
|
2056
|
+
return false;
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
UObject* CDO = GeneratedClass->GetDefaultObject();
|
|
2060
|
+
if (!CDO)
|
|
2061
|
+
{
|
|
2062
|
+
OutError = FString::Printf(
|
|
2063
|
+
TEXT("Generated class '%s' has no class default object"), *GeneratedClass->GetName());
|
|
2064
|
+
return false;
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2067
|
+
FProperty* Prop = GeneratedClass->FindPropertyByName(FName(*VarName));
|
|
2068
|
+
if (!Prop)
|
|
2069
|
+
{
|
|
2070
|
+
// Name the variables that DO resolve, so a caller that has just
|
|
2071
|
+
// added one can see whether the compile carried it through.
|
|
2072
|
+
TArray<FString> Available;
|
|
2073
|
+
for (TFieldIterator<FProperty> It(GeneratedClass); It && Available.Num() < 60; ++It)
|
|
2074
|
+
{
|
|
2075
|
+
if (*It) Available.Add((*It)->GetName());
|
|
2076
|
+
}
|
|
2077
|
+
OutError = FString::Printf(
|
|
2078
|
+
TEXT("Variable '%s' has no property on generated class '%s'. If it was just added, compile the Blueprint. Resolved properties: [%s]"),
|
|
2079
|
+
*VarName, *GeneratedClass->GetName(), *FString::Join(Available, TEXT(", ")));
|
|
2080
|
+
return false;
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
Out.Property = Prop;
|
|
2084
|
+
Out.ValueAddress = Prop->ContainerPtrToValuePtr<void>(CDO);
|
|
2085
|
+
Prop->ExportText_Direct(Out.ValueText, Out.ValueAddress, Out.ValueAddress, CDO, PPF_None);
|
|
2086
|
+
Out.Value = FMCPJsonSerializer::SerializeValue(Out.ValueAddress, Prop);
|
|
2087
|
+
|
|
2088
|
+
if (UClass* Owner = Prop->GetOwnerClass())
|
|
2089
|
+
{
|
|
2090
|
+
Out.DeclaringClass = Owner->GetName();
|
|
2091
|
+
Out.DeclaringClassPath = Owner->GetPathName();
|
|
2092
|
+
Out.bInherited = Owner != GeneratedClass;
|
|
2093
|
+
}
|
|
2094
|
+
return true;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
// Write the resolved value onto a JSON object. Shared so list_variables and
|
|
2098
|
+
// get_variable_default cannot report the same value under different names.
|
|
2099
|
+
void WriteResolvedVariableDefault(const TSharedPtr<FJsonObject>& Obj, const FResolvedVariableDefault& Resolved)
|
|
2100
|
+
{
|
|
2101
|
+
if (!Obj.IsValid() || !Resolved.Property) return;
|
|
2102
|
+
Obj->SetField(TEXT("value"), Resolved.Value.IsValid() ? Resolved.Value : MakeShared<FJsonValueNull>());
|
|
2103
|
+
Obj->SetStringField(TEXT("valueText"), Resolved.ValueText);
|
|
2104
|
+
Obj->SetStringField(TEXT("cppType"), Resolved.Property->GetCPPType());
|
|
2105
|
+
if (!Resolved.DeclaringClass.IsEmpty())
|
|
2106
|
+
{
|
|
2107
|
+
Obj->SetStringField(TEXT("declaringClass"), Resolved.DeclaringClass);
|
|
2108
|
+
Obj->SetStringField(TEXT("declaringClassPath"), Resolved.DeclaringClassPath);
|
|
2109
|
+
}
|
|
2110
|
+
Obj->SetBoolField(TEXT("inherited"), Resolved.bInherited);
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
// #931: state whether what was just read is on disk. The package's own
|
|
2114
|
+
// dirty flag is the answer: it is set by every write that reaches the
|
|
2115
|
+
// object and cleared by a successful save, so a value that reads back
|
|
2116
|
+
// correctly out of a dirty package has not been persisted and will be gone
|
|
2117
|
+
// after a restart.
|
|
2118
|
+
void WriteDefaultPersistence(const TSharedPtr<FJsonObject>& Obj, UBlueprint* Blueprint)
|
|
2119
|
+
{
|
|
2120
|
+
if (!Obj.IsValid() || !Blueprint) return;
|
|
2121
|
+
UPackage* Package = Blueprint->GetOutermost();
|
|
2122
|
+
const bool bDirty = Package && Package->IsDirty();
|
|
2123
|
+
if (Package)
|
|
2124
|
+
{
|
|
2125
|
+
Obj->SetStringField(TEXT("packageName"), Package->GetName());
|
|
2126
|
+
}
|
|
2127
|
+
Obj->SetBoolField(TEXT("packageDirty"), bDirty);
|
|
2128
|
+
Obj->SetBoolField(TEXT("persisted"), !bDirty);
|
|
2129
|
+
if (bDirty)
|
|
2130
|
+
{
|
|
2131
|
+
Obj->SetStringField(TEXT("persistenceNote"),
|
|
2132
|
+
TEXT("This value is live in the editor but its package has unsaved changes, so it is not on disk and will revert on the next editor start. Save the Blueprint (blueprint compile_all with save, or asset save) and read again to confirm it persisted."));
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
TSharedPtr<FJsonValue> FBlueprintHandlers::GetVariableDefault(const TSharedPtr<FJsonObject>& Params)
|
|
2138
|
+
{
|
|
2139
|
+
FString AssetPath;
|
|
2140
|
+
if (auto Err = RequireStringAlt(Params, TEXT("path"), TEXT("assetPath"), AssetPath)) return Err;
|
|
2141
|
+
|
|
2142
|
+
FString VarName;
|
|
2143
|
+
if (auto Err = RequireString(Params, TEXT("name"), VarName)) return Err;
|
|
2144
|
+
|
|
2145
|
+
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
2146
|
+
if (!Blueprint)
|
|
2147
|
+
{
|
|
2148
|
+
return BlueprintNotFoundError(AssetPath);
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
FResolvedVariableDefault Resolved;
|
|
2152
|
+
FString ResolveError;
|
|
2153
|
+
if (!ResolveVariableDefault(Blueprint, VarName, Resolved, ResolveError))
|
|
2154
|
+
{
|
|
2155
|
+
return MCPError(ResolveError);
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
auto Result = MCPSuccess();
|
|
2159
|
+
Result->SetStringField(TEXT("path"), AssetPath);
|
|
2160
|
+
AnnotateResolvedBlueprint(Result, Blueprint);
|
|
2161
|
+
Result->SetStringField(TEXT("name"), VarName);
|
|
2162
|
+
WriteResolvedVariableDefault(Result, Resolved);
|
|
2163
|
+
WriteDefaultPersistence(Result, Blueprint);
|
|
2164
|
+
|
|
2165
|
+
// The authored string, when there is one, is reported alongside rather than
|
|
2166
|
+
// instead of the resolved value. It is advisory: the engine treats it as an
|
|
2167
|
+
// optional override, so an empty one is normal and says nothing. A non-empty
|
|
2168
|
+
// one that disagrees with the CDO means the next recompile can move the
|
|
2169
|
+
// value, which is worth seeing in a verification loop.
|
|
2170
|
+
for (const FBPVariableDescription& Var : Blueprint->NewVariables)
|
|
2171
|
+
{
|
|
2172
|
+
if (Var.VarName.ToString() != VarName) continue;
|
|
2173
|
+
Result->SetBoolField(TEXT("declaredOnThisBlueprint"), true);
|
|
2174
|
+
if (Var.DefaultValue.IsEmpty()) break;
|
|
2175
|
+
|
|
2176
|
+
Result->SetStringField(TEXT("authoredDefault"), Var.DefaultValue);
|
|
2177
|
+
FDefaultConstructedPropertyElement Authored(Resolved.Property);
|
|
2178
|
+
// No owning object on purpose: this is a read, and an owner is what
|
|
2179
|
+
// lets the importer construct instanced subobjects under the real
|
|
2180
|
+
// asset. A question about a value must not touch it.
|
|
2181
|
+
const bool bParsed = FBlueprintEditorUtils::PropertyValueFromString_Direct(
|
|
2182
|
+
Resolved.Property,
|
|
2183
|
+
Var.DefaultValue,
|
|
2184
|
+
static_cast<uint8*>(Authored.GetObjAddress()),
|
|
2185
|
+
/*OwningObject=*/nullptr);
|
|
2186
|
+
if (bParsed)
|
|
2187
|
+
{
|
|
2188
|
+
Result->SetBoolField(TEXT("matchesAuthoredDefault"),
|
|
2189
|
+
Resolved.Property->Identical(Resolved.ValueAddress, Authored.GetObjAddress(), PPF_None));
|
|
2190
|
+
}
|
|
2191
|
+
break;
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
return MCPResult(Result);
|
|
2195
|
+
}
|
|
2196
|
+
|
|
1946
2197
|
TSharedPtr<FJsonValue> FBlueprintHandlers::ListBlueprintVariables(const TSharedPtr<FJsonObject>& Params)
|
|
1947
2198
|
{
|
|
1948
2199
|
FString AssetPath;
|
|
1949
2200
|
if (auto Err = RequireStringAlt(Params, TEXT("path"), TEXT("assetPath"), AssetPath)) return Err;
|
|
1950
2201
|
|
|
2202
|
+
// #902: resolved values are opt-in. They cost a CDO property read and a
|
|
2203
|
+
// JSON serialization per variable, and every existing caller of this action
|
|
2204
|
+
// wants the declaration list, so the default payload is unchanged and a
|
|
2205
|
+
// verification loop asks for the values it needs.
|
|
2206
|
+
const bool bIncludeValues = OptionalBool(Params, TEXT("includeValues"), false);
|
|
2207
|
+
|
|
1951
2208
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
1952
2209
|
if (!Blueprint)
|
|
1953
2210
|
{
|
|
1954
|
-
return
|
|
2211
|
+
return BlueprintNotFoundError(AssetPath);
|
|
1955
2212
|
}
|
|
1956
2213
|
|
|
1957
2214
|
TArray<TSharedPtr<FJsonValue>> Variables;
|
|
@@ -2014,13 +2271,37 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ListBlueprintVariables(const TSharedP
|
|
|
2014
2271
|
(Var.HasMetaData(FBlueprintMetadata::MD_ExposeOnSpawn) &&
|
|
2015
2272
|
Var.GetMetaData(FBlueprintMetadata::MD_ExposeOnSpawn).ToBool()));
|
|
2016
2273
|
|
|
2274
|
+
if (bIncludeValues)
|
|
2275
|
+
{
|
|
2276
|
+
FResolvedVariableDefault Resolved;
|
|
2277
|
+
FString ResolveError;
|
|
2278
|
+
if (ResolveVariableDefault(Blueprint, Var.VarName.ToString(), Resolved, ResolveError))
|
|
2279
|
+
{
|
|
2280
|
+
WriteResolvedVariableDefault(VarObj, Resolved);
|
|
2281
|
+
}
|
|
2282
|
+
else
|
|
2283
|
+
{
|
|
2284
|
+
// A variable that has no compiled property is a real state
|
|
2285
|
+
// (added but not compiled yet), so say so per variable rather
|
|
2286
|
+
// than failing the whole listing.
|
|
2287
|
+
VarObj->SetStringField(TEXT("valueError"), ResolveError);
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2017
2291
|
Variables.Add(MakeShared<FJsonValueObject>(VarObj));
|
|
2018
2292
|
}
|
|
2019
2293
|
|
|
2020
2294
|
auto Result = MCPSuccess();
|
|
2021
2295
|
Result->SetStringField(TEXT("path"), AssetPath);
|
|
2296
|
+
AnnotateResolvedBlueprint(Result, Blueprint);
|
|
2022
2297
|
Result->SetArrayField(TEXT("variables"), Variables);
|
|
2023
2298
|
Result->SetNumberField(TEXT("count"), Variables.Num());
|
|
2299
|
+
if (bIncludeValues)
|
|
2300
|
+
{
|
|
2301
|
+
// Persistence is a property of the package, not of any one variable, so
|
|
2302
|
+
// it is stated once for the whole listing.
|
|
2303
|
+
WriteDefaultPersistence(Result, Blueprint);
|
|
2304
|
+
}
|
|
2024
2305
|
return MCPResult(Result);
|
|
2025
2306
|
}
|
|
2026
2307
|
TSharedPtr<FJsonValue> FBlueprintHandlers::RemoveComponent(const TSharedPtr<FJsonObject>& Params)
|
|
@@ -2034,7 +2315,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::RemoveComponent(const TSharedPtr<FJso
|
|
|
2034
2315
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
2035
2316
|
if (!Blueprint)
|
|
2036
2317
|
{
|
|
2037
|
-
return
|
|
2318
|
+
return BlueprintNotFoundError(AssetPath);
|
|
2038
2319
|
}
|
|
2039
2320
|
|
|
2040
2321
|
USimpleConstructionScript* SCS = Blueprint->SimpleConstructionScript;
|
|
@@ -2129,7 +2410,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::DeleteVariable(const TSharedPtr<FJson
|
|
|
2129
2410
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
2130
2411
|
if (!Blueprint)
|
|
2131
2412
|
{
|
|
2132
|
-
return
|
|
2413
|
+
return BlueprintNotFoundError(AssetPath);
|
|
2133
2414
|
}
|
|
2134
2415
|
|
|
2135
2416
|
bool bFound = false;
|
|
@@ -2210,7 +2491,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::AddLocalVariable(const TSharedPtr<FJs
|
|
|
2210
2491
|
FString TypeStr = OptionalString(Params, TEXT("varType"), TEXT("bool"));
|
|
2211
2492
|
|
|
2212
2493
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
2213
|
-
if (!Blueprint) return
|
|
2494
|
+
if (!Blueprint) return BlueprintNotFoundError(AssetPath);
|
|
2214
2495
|
|
|
2215
2496
|
// Find the function graph and its FunctionEntry node.
|
|
2216
2497
|
UEdGraph* FuncGraph = nullptr;
|
|
@@ -2276,7 +2557,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ListLocalVariables(const TSharedPtr<F
|
|
|
2276
2557
|
if (auto Err = RequireString(Params, TEXT("functionName"), FunctionName)) return Err;
|
|
2277
2558
|
|
|
2278
2559
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
2279
|
-
if (!Blueprint) return
|
|
2560
|
+
if (!Blueprint) return BlueprintNotFoundError(AssetPath);
|
|
2280
2561
|
|
|
2281
2562
|
UEdGraph* FuncGraph = nullptr;
|
|
2282
2563
|
for (UEdGraph* G : Blueprint->FunctionGraphs)
|
|
@@ -2317,7 +2598,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ValidateBlueprint(const TSharedPtr<FJ
|
|
|
2317
2598
|
if (auto Err = RequireStringAlt(Params, TEXT("path"), TEXT("assetPath"), AssetPath)) return Err;
|
|
2318
2599
|
|
|
2319
2600
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
2320
|
-
if (!Blueprint) return
|
|
2601
|
+
if (!Blueprint) return BlueprintNotFoundError(AssetPath);
|
|
2321
2602
|
|
|
2322
2603
|
// Run compile without saving; collect diagnostics from the compiler result log.
|
|
2323
2604
|
FCompilerResultsLog Log;
|
|
@@ -2353,6 +2634,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ReparentComponent(const TSharedPtr<FJ
|
|
|
2353
2634
|
|
|
2354
2635
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
2355
2636
|
if (!Blueprint) return MCPError(TEXT("Blueprint not found"));
|
|
2637
|
+
if (auto Blocked = MCPAssetWriteBlockedError(Blueprint, AssetPath, TEXT("reparent this component"))) return Blocked;
|
|
2356
2638
|
USimpleConstructionScript* SCS = Blueprint->SimpleConstructionScript;
|
|
2357
2639
|
if (!SCS) return MCPError(TEXT("Blueprint has no SCS"));
|
|
2358
2640
|
|
|
@@ -2370,12 +2652,15 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ReparentComponent(const TSharedPtr<FJ
|
|
|
2370
2652
|
Parent->AddChildNode(Child);
|
|
2371
2653
|
|
|
2372
2654
|
FKismetEditorUtilities::CompileBlueprint(Blueprint);
|
|
2373
|
-
|
|
2655
|
+
|
|
2656
|
+
FString SaveReason;
|
|
2657
|
+
const bool bSaved = SaveAssetPackageChecked(Blueprint, SaveReason);
|
|
2374
2658
|
|
|
2375
2659
|
auto Result = MCPSuccess();
|
|
2376
2660
|
MCPSetUpdated(Result);
|
|
2377
2661
|
Result->SetStringField(TEXT("componentName"), ComponentName);
|
|
2378
2662
|
Result->SetStringField(TEXT("newParent"), NewParent);
|
|
2663
|
+
MCPNoteSaveOutcome(Result, AssetPath, bSaved, SaveReason);
|
|
2379
2664
|
return MCPResult(Result);
|
|
2380
2665
|
}
|
|
2381
2666
|
|
|
@@ -2390,7 +2675,16 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ReparentBlueprint(const TSharedPtr<FJ
|
|
|
2390
2675
|
if (auto Err = RequireString(Params, TEXT("parentClass"), ParentClassName)) return Err;
|
|
2391
2676
|
|
|
2392
2677
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
2393
|
-
if (!Blueprint) return
|
|
2678
|
+
if (!Blueprint) return BlueprintNotFoundError(AssetPath);
|
|
2679
|
+
|
|
2680
|
+
// #932: reparenting reparents, recompiles AND saves, and the save is not
|
|
2681
|
+
// optional. A .uasset that was never checked out of source control is
|
|
2682
|
+
// read-only on disk, and asking the engine to write it turned the failed
|
|
2683
|
+
// save into a FATAL error that took the whole editor process down. The
|
|
2684
|
+
// asset itself was fine and the call replayed cleanly after a checkout, so
|
|
2685
|
+
// the only thing missing was this question, asked before the Blueprint is
|
|
2686
|
+
// touched rather than after it has already been reparented and recompiled.
|
|
2687
|
+
if (auto Blocked = MCPAssetWriteBlockedError(Blueprint, AssetPath, TEXT("reparent this Blueprint"))) return Blocked;
|
|
2394
2688
|
|
|
2395
2689
|
// Resolve parent class: full path > short name > engine-module implicit.
|
|
2396
2690
|
UClass* NewParent = nullptr;
|
|
@@ -2436,7 +2730,8 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ReparentBlueprint(const TSharedPtr<FJ
|
|
|
2436
2730
|
UBlueprintEditorLibrary::ReparentBlueprint(Blueprint, NewParent);
|
|
2437
2731
|
FKismetEditorUtilities::CompileBlueprint(Blueprint);
|
|
2438
2732
|
|
|
2439
|
-
|
|
2733
|
+
FString SaveReason;
|
|
2734
|
+
const bool bSaved = SaveAssetPackageChecked(Blueprint, SaveReason);
|
|
2440
2735
|
|
|
2441
2736
|
auto Result = MCPSuccess();
|
|
2442
2737
|
MCPSetUpdated(Result);
|
|
@@ -2446,6 +2741,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::ReparentBlueprint(const TSharedPtr<FJ
|
|
|
2446
2741
|
{
|
|
2447
2742
|
Result->SetStringField(TEXT("previousParent"), OldParent->GetPathName());
|
|
2448
2743
|
}
|
|
2744
|
+
MCPNoteSaveOutcome(Result, AssetPath, bSaved, SaveReason);
|
|
2449
2745
|
return MCPResult(Result);
|
|
2450
2746
|
}
|
|
2451
2747
|
|
|
@@ -2459,7 +2755,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::FlushInheritableComponentHandler(cons
|
|
|
2459
2755
|
if (auto Err = RequireStringAlt(Params, TEXT("path"), TEXT("assetPath"), AssetPath)) return Err;
|
|
2460
2756
|
|
|
2461
2757
|
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
2462
|
-
if (!Blueprint) return
|
|
2758
|
+
if (!Blueprint) return BlueprintNotFoundError(AssetPath);
|
|
2463
2759
|
|
|
2464
2760
|
UInheritableComponentHandler* ICH = Blueprint->GetInheritableComponentHandler(/*bCreateIfNecessary=*/false);
|
|
2465
2761
|
if (!ICH)
|
|
@@ -2505,7 +2801,7 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::FlushInheritableComponentHandler(cons
|
|
|
2505
2801
|
return MCPResult(Result);
|
|
2506
2802
|
}
|
|
2507
2803
|
|
|
2508
|
-
TSharedPtr<FJsonValue> FBlueprintHandlers::
|
|
2804
|
+
TSharedPtr<FJsonValue> FBlueprintHandlers::FlushComponentTemplates(const TSharedPtr<FJsonObject>& Params)
|
|
2509
2805
|
{
|
|
2510
2806
|
FString AssetPath;
|
|
2511
2807
|
if (auto Err = RequireStringAlt(Params, TEXT("path"), TEXT("assetPath"), AssetPath)) return Err;
|
|
@@ -2516,6 +2812,157 @@ TSharedPtr<FJsonValue> FBlueprintHandlers::RunConstructionScript(const TSharedPt
|
|
|
2516
2812
|
return MCPError(FString::Printf(TEXT("Blueprint not found: %s"), *AssetPath));
|
|
2517
2813
|
}
|
|
2518
2814
|
|
|
2815
|
+
TArray<UK2Node_AddComponent*> ComponentNodes;
|
|
2816
|
+
FBlueprintEditorUtils::GetAllNodesOfClass(Blueprint, ComponentNodes);
|
|
2817
|
+
|
|
2818
|
+
TArray<UActorComponent*> ReferencedTemplates;
|
|
2819
|
+
bool bNeedsUpdate = false;
|
|
2820
|
+
for (UK2Node_AddComponent* ComponentNode : ComponentNodes)
|
|
2821
|
+
{
|
|
2822
|
+
UActorComponent* Template = ComponentNode ? ComponentNode->GetTemplateFromNode() : nullptr;
|
|
2823
|
+
if (!Template)
|
|
2824
|
+
{
|
|
2825
|
+
continue;
|
|
2826
|
+
}
|
|
2827
|
+
if (ReferencedTemplates.Contains(Template))
|
|
2828
|
+
{
|
|
2829
|
+
bNeedsUpdate = true;
|
|
2830
|
+
continue;
|
|
2831
|
+
}
|
|
2832
|
+
ReferencedTemplates.Add(Template);
|
|
2833
|
+
bNeedsUpdate |= !Template->HasAllFlags(RF_ArchetypeObject | RF_Transactional);
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
const int32 RecordsBefore = Blueprint->ComponentTemplates.Num();
|
|
2837
|
+
if (RecordsBefore != ReferencedTemplates.Num())
|
|
2838
|
+
{
|
|
2839
|
+
bNeedsUpdate = true;
|
|
2840
|
+
}
|
|
2841
|
+
else
|
|
2842
|
+
{
|
|
2843
|
+
for (int32 Index = 0; Index < RecordsBefore; ++Index)
|
|
2844
|
+
{
|
|
2845
|
+
if (Blueprint->ComponentTemplates[Index].Get() != ReferencedTemplates[Index])
|
|
2846
|
+
{
|
|
2847
|
+
bNeedsUpdate = true;
|
|
2848
|
+
break;
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2853
|
+
TArray<TSharedPtr<FJsonValue>> RemovedTemplates;
|
|
2854
|
+
TArray<UActorComponent*> OrphanTemplates;
|
|
2855
|
+
for (UActorComponent* Template : Blueprint->ComponentTemplates)
|
|
2856
|
+
{
|
|
2857
|
+
if (Template && !ReferencedTemplates.Contains(Template))
|
|
2858
|
+
{
|
|
2859
|
+
OrphanTemplates.AddUnique(Template);
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
if (Blueprint->GeneratedClass)
|
|
2863
|
+
{
|
|
2864
|
+
TArray<UObject*> OwnedObjects;
|
|
2865
|
+
GetObjectsWithOuter(Blueprint->GeneratedClass, OwnedObjects, EGetObjectsFlags::None);
|
|
2866
|
+
for (UObject* OwnedObject : OwnedObjects)
|
|
2867
|
+
{
|
|
2868
|
+
UActorComponent* Template = Cast<UActorComponent>(OwnedObject);
|
|
2869
|
+
if (Template
|
|
2870
|
+
&& Template->GetName().StartsWith(UK2Node_AddComponent::ComponentTemplateNamePrefix)
|
|
2871
|
+
&& !ReferencedTemplates.Contains(Template))
|
|
2872
|
+
{
|
|
2873
|
+
OrphanTemplates.AddUnique(Template);
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
bNeedsUpdate |= !OrphanTemplates.IsEmpty();
|
|
2878
|
+
|
|
2879
|
+
for (UActorComponent* Template : OrphanTemplates)
|
|
2880
|
+
{
|
|
2881
|
+
TSharedPtr<FJsonObject> Identity = MakeShared<FJsonObject>();
|
|
2882
|
+
Identity->SetStringField(TEXT("name"), Template->GetName());
|
|
2883
|
+
Identity->SetStringField(TEXT("objectPath"), Template->GetPathName());
|
|
2884
|
+
Identity->SetStringField(TEXT("classPath"), Template->GetClass()->GetPathName());
|
|
2885
|
+
RemovedTemplates.Add(MakeShared<FJsonValueObject>(Identity));
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
if (bNeedsUpdate)
|
|
2889
|
+
{
|
|
2890
|
+
Blueprint->Modify();
|
|
2891
|
+
FBlueprintEditorUtils::UpdateComponentTemplates(Blueprint);
|
|
2892
|
+
if (UBlueprintGeneratedClass* GeneratedClass = Cast<UBlueprintGeneratedClass>(Blueprint->GeneratedClass))
|
|
2893
|
+
{
|
|
2894
|
+
for (UActorComponent* Template : OrphanTemplates)
|
|
2895
|
+
{
|
|
2896
|
+
GeneratedClass->ComponentTemplates.Remove(Template);
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
for (UActorComponent* Template : OrphanTemplates)
|
|
2900
|
+
{
|
|
2901
|
+
Template->Modify();
|
|
2902
|
+
Template->ClearFlags(RF_Public | RF_Standalone);
|
|
2903
|
+
if (!Template->Rename(nullptr, GetTransientPackage(),
|
|
2904
|
+
REN_DoNotDirty | REN_DontCreateRedirectors | REN_AllowPackageLinkerMismatch | REN_NonTransactional))
|
|
2905
|
+
{
|
|
2906
|
+
return MCPError(FString::Printf(TEXT("Failed to retire orphan component template: %s"), *Template->GetPathName()));
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2909
|
+
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Blueprint);
|
|
2910
|
+
FKismetEditorUtilities::CompileBlueprint(Blueprint);
|
|
2911
|
+
const int32 RecordsAfter = Blueprint->ComponentTemplates.Num();
|
|
2912
|
+
if (!SaveAssetPackage(Blueprint))
|
|
2913
|
+
{
|
|
2914
|
+
return MCPError(FString::Printf(TEXT("Failed to save Blueprint after flushing component templates: %s"), *AssetPath));
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
if (!OrphanTemplates.IsEmpty())
|
|
2918
|
+
{
|
|
2919
|
+
FText ReloadError;
|
|
2920
|
+
TArray<UPackage*> PackagesToReload{Blueprint->GetOutermost()};
|
|
2921
|
+
if (!UPackageTools::ReloadPackages(
|
|
2922
|
+
PackagesToReload, ReloadError, EReloadPackagesInteractionMode::AssumePositive))
|
|
2923
|
+
{
|
|
2924
|
+
return MCPError(FString::Printf(TEXT("Failed to reload Blueprint after retiring orphan templates: %s"), *ReloadError.ToString()));
|
|
2925
|
+
}
|
|
2926
|
+
Blueprint = LoadBlueprint(AssetPath);
|
|
2927
|
+
if (!Blueprint || !SaveAssetPackage(Blueprint))
|
|
2928
|
+
{
|
|
2929
|
+
return MCPError(FString::Printf(TEXT("Failed final Blueprint save after retiring orphan templates: %s"), *AssetPath));
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2933
|
+
auto Result = MCPSuccess();
|
|
2934
|
+
MCPSetUpdated(Result);
|
|
2935
|
+
Result->SetStringField(TEXT("path"), AssetPath);
|
|
2936
|
+
Result->SetNumberField(TEXT("recordsBefore"), RecordsBefore);
|
|
2937
|
+
Result->SetNumberField(TEXT("recordsAfter"), RecordsAfter);
|
|
2938
|
+
Result->SetNumberField(TEXT("recordsRemoved"), RemovedTemplates.Num());
|
|
2939
|
+
Result->SetArrayField(TEXT("removedTemplates"), RemovedTemplates);
|
|
2940
|
+
Result->SetBoolField(TEXT("reloadedAfterCleanup"), !OrphanTemplates.IsEmpty());
|
|
2941
|
+
return MCPResult(Result);
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2944
|
+
auto Result = MCPSuccess();
|
|
2945
|
+
MCPSetExisted(Result);
|
|
2946
|
+
Result->SetStringField(TEXT("path"), AssetPath);
|
|
2947
|
+
Result->SetNumberField(TEXT("recordsBefore"), RecordsBefore);
|
|
2948
|
+
Result->SetNumberField(TEXT("recordsAfter"), Blueprint->ComponentTemplates.Num());
|
|
2949
|
+
Result->SetNumberField(TEXT("recordsRemoved"), RemovedTemplates.Num());
|
|
2950
|
+
Result->SetArrayField(TEXT("removedTemplates"), RemovedTemplates);
|
|
2951
|
+
Result->SetBoolField(TEXT("reloadedAfterCleanup"), false);
|
|
2952
|
+
return MCPResult(Result);
|
|
2953
|
+
}
|
|
2954
|
+
|
|
2955
|
+
TSharedPtr<FJsonValue> FBlueprintHandlers::RunConstructionScript(const TSharedPtr<FJsonObject>& Params)
|
|
2956
|
+
{
|
|
2957
|
+
FString AssetPath;
|
|
2958
|
+
if (auto Err = RequireStringAlt(Params, TEXT("path"), TEXT("assetPath"), AssetPath)) return Err;
|
|
2959
|
+
|
|
2960
|
+
UBlueprint* Blueprint = LoadBlueprint(AssetPath);
|
|
2961
|
+
if (!Blueprint)
|
|
2962
|
+
{
|
|
2963
|
+
return BlueprintNotFoundError(AssetPath);
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2519
2966
|
UClass* SpawnClass = Blueprint->GeneratedClass;
|
|
2520
2967
|
if (!SpawnClass)
|
|
2521
2968
|
{
|