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
|
@@ -63,6 +63,250 @@
|
|
|
63
63
|
#include "Materials/MaterialInterface.h"
|
|
64
64
|
#include "EngineUtils.h"
|
|
65
65
|
#include "Widgets/SViewport.h"
|
|
66
|
+
#include "UObject/SoftObjectPath.h"
|
|
67
|
+
|
|
68
|
+
// ── WidgetBlueprint resolution (#972) ────────────────────────────────────────
|
|
69
|
+
// See the contract and the mechanism note on MCPWidget in WidgetHandlers.h.
|
|
70
|
+
// Everything here is defined exactly once, in this translation unit, and
|
|
71
|
+
// declared in the shared header, because the module is a unity build and a
|
|
72
|
+
// second file-local copy would be a redefinition on some grouping.
|
|
73
|
+
namespace MCPWidget
|
|
74
|
+
{
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* "WidgetBlueprint'/Game/UI/WBP_Foo.WBP_Foo'", "/Game/UI/WBP_Foo",
|
|
78
|
+
* "/Game/UI/WBP_Foo.WBP_Foo" and "/Game/UI/WBP_Foo.WBP_Foo_C" all normalise to
|
|
79
|
+
* "/Game/UI/WBP_Foo.WBP_Foo". A path with no object part gets one inferred from
|
|
80
|
+
* the package name, which is the convention every asset in the content browser
|
|
81
|
+
* follows.
|
|
82
|
+
*/
|
|
83
|
+
static FString NormalizeWidgetBlueprintObjectPath(const FString& InAssetPath)
|
|
84
|
+
{
|
|
85
|
+
FString Path = InAssetPath;
|
|
86
|
+
Path.TrimStartAndEndInline();
|
|
87
|
+
if (Path.IsEmpty()) return Path;
|
|
88
|
+
|
|
89
|
+
// "Class'/Game/...'" and "Class /Game/..." export forms.
|
|
90
|
+
int32 QuoteIndex = INDEX_NONE;
|
|
91
|
+
if (Path.FindChar(TCHAR('\''), QuoteIndex))
|
|
92
|
+
{
|
|
93
|
+
Path = Path.RightChop(QuoteIndex + 1);
|
|
94
|
+
Path.RemoveFromEnd(TEXT("'"));
|
|
95
|
+
}
|
|
96
|
+
else
|
|
97
|
+
{
|
|
98
|
+
int32 SpaceIndex = INDEX_NONE;
|
|
99
|
+
if (Path.FindChar(TCHAR(' '), SpaceIndex))
|
|
100
|
+
{
|
|
101
|
+
Path = Path.RightChop(SpaceIndex + 1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
Path.TrimStartAndEndInline();
|
|
105
|
+
|
|
106
|
+
// Subobject part ("Package.Asset:Inner") is not ours to resolve.
|
|
107
|
+
int32 ColonIndex = INDEX_NONE;
|
|
108
|
+
if (Path.FindChar(TCHAR(':'), ColonIndex))
|
|
109
|
+
{
|
|
110
|
+
Path = Path.Left(ColonIndex);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const int32 LastSlash = Path.Find(TEXT("/"), ESearchCase::CaseSensitive, ESearchDir::FromEnd);
|
|
114
|
+
const int32 LastDot = Path.Find(TEXT("."), ESearchCase::CaseSensitive, ESearchDir::FromEnd);
|
|
115
|
+
if (LastDot <= LastSlash)
|
|
116
|
+
{
|
|
117
|
+
// No object part. Infer it from the package name.
|
|
118
|
+
const FString AssetName = FPackageName::GetLongPackageAssetName(Path);
|
|
119
|
+
if (AssetName.IsEmpty()) return FString();
|
|
120
|
+
return Path + TEXT(".") + AssetName;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// "/Game/UI/WBP_Foo.WBP_Foo_C" names the generated class. Keep the trailing
|
|
124
|
+
// _C off the object path; the class is resolved from the blueprint anyway.
|
|
125
|
+
FString ObjectName = Path.RightChop(LastDot + 1);
|
|
126
|
+
if (ObjectName.EndsWith(TEXT("_C"), ESearchCase::CaseSensitive))
|
|
127
|
+
{
|
|
128
|
+
ObjectName.LeftChopInline(2);
|
|
129
|
+
Path = Path.Left(LastDot + 1) + ObjectName;
|
|
130
|
+
}
|
|
131
|
+
return Path;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Accept a candidate only if it is a WidgetBlueprint the editor still consults.
|
|
136
|
+
*
|
|
137
|
+
* RF_NewerVersionExists is the flag a package reload leaves on the object it
|
|
138
|
+
* replaced. Handing one of those back is exactly the failure #972 describes
|
|
139
|
+
* after asset(force_reload): every write lands on a corpse, the real asset
|
|
140
|
+
* never changes, and nothing reports an error. IsValid covers null and garbage.
|
|
141
|
+
*/
|
|
142
|
+
static UWidgetBlueprint* AsLiveWidgetBlueprint(UObject* Candidate, FString& OutFoundClass)
|
|
143
|
+
{
|
|
144
|
+
if (!IsValid(Candidate)) return nullptr;
|
|
145
|
+
if (Candidate->HasAnyFlags(RF_NewerVersionExists)) return nullptr;
|
|
146
|
+
|
|
147
|
+
if (UWidgetBlueprint* AsBlueprint = Cast<UWidgetBlueprint>(Candidate))
|
|
148
|
+
{
|
|
149
|
+
return AsBlueprint;
|
|
150
|
+
}
|
|
151
|
+
// A caller who passed the generated class path gets the blueprint behind it.
|
|
152
|
+
if (UClass* AsClass = Cast<UClass>(Candidate))
|
|
153
|
+
{
|
|
154
|
+
if (UWidgetBlueprint* Generated = Cast<UWidgetBlueprint>(AsClass->ClassGeneratedBy))
|
|
155
|
+
{
|
|
156
|
+
return Generated;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
OutFoundClass = Candidate->GetClass()->GetName();
|
|
160
|
+
return nullptr;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** True when the AssetRegistry or the filesystem says the asset is really there. */
|
|
164
|
+
static bool WidgetBlueprintAssetExists(const FString& ObjectPath, const FString& PackageName)
|
|
165
|
+
{
|
|
166
|
+
if (!PackageName.IsEmpty() && FPackageName::DoesPackageExist(PackageName))
|
|
167
|
+
{
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
// An asset created this session and not yet saved has no file, so the
|
|
171
|
+
// registry is the only witness. Never load anything to answer this.
|
|
172
|
+
if (FAssetRegistryModule* ARM =
|
|
173
|
+
FModuleManager::GetModulePtr<FAssetRegistryModule>(TEXT("AssetRegistry")))
|
|
174
|
+
{
|
|
175
|
+
const FAssetData Data = ARM->Get().GetAssetByObjectPath(FSoftObjectPath(ObjectPath));
|
|
176
|
+
if (Data.IsValid()) return true;
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
FWidgetBlueprintResolve ResolveWidgetBlueprint(const FString& AssetPath)
|
|
182
|
+
{
|
|
183
|
+
FWidgetBlueprintResolve Out;
|
|
184
|
+
Out.ObjectPath = NormalizeWidgetBlueprintObjectPath(AssetPath);
|
|
185
|
+
if (Out.ObjectPath.IsEmpty())
|
|
186
|
+
{
|
|
187
|
+
Out.Failure = EWidgetBlueprintResolveFailure::NotFound;
|
|
188
|
+
return Out;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const FString PackageName = FPackageName::ObjectPathToPackageName(Out.ObjectPath);
|
|
192
|
+
Out.bAssetExists = WidgetBlueprintAssetExists(Out.ObjectPath, PackageName);
|
|
193
|
+
|
|
194
|
+
// Step 1. The object hash, first and cheapest. An asset already in memory
|
|
195
|
+
// answers here without the AssetRegistry round trip UEditorAssetLibrary
|
|
196
|
+
// makes, which is the step that was intermittently returning null.
|
|
197
|
+
if (UWidgetBlueprint* Live =
|
|
198
|
+
AsLiveWidgetBlueprint(FindObject<UObject>(nullptr, *Out.ObjectPath), Out.FoundClass))
|
|
199
|
+
{
|
|
200
|
+
Out.Blueprint = Live;
|
|
201
|
+
return Out;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Step 2. The historical path. Kept because it understands more path
|
|
205
|
+
// spellings than the object hash does and it is what every other handler
|
|
206
|
+
// in this plugin uses.
|
|
207
|
+
if (UWidgetBlueprint* Live =
|
|
208
|
+
AsLiveWidgetBlueprint(UEditorAssetLibrary::LoadAsset(AssetPath), Out.FoundClass))
|
|
209
|
+
{
|
|
210
|
+
Out.Blueprint = Live;
|
|
211
|
+
return Out;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Step 3. Load the object directly, bypassing the registry entirely. Only
|
|
215
|
+
// worth attempting when something really is there: StaticLoadObject on a
|
|
216
|
+
// path with no package behind it can force a blocking package search.
|
|
217
|
+
if (Out.bAssetExists)
|
|
218
|
+
{
|
|
219
|
+
if (UWidgetBlueprint* Live =
|
|
220
|
+
AsLiveWidgetBlueprint(LoadObject<UObject>(nullptr, *Out.ObjectPath), Out.FoundClass))
|
|
221
|
+
{
|
|
222
|
+
Out.Blueprint = Live;
|
|
223
|
+
return Out;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Step 4. "Failed to find object 'Object /Game/x/WBP_Foo.WBP_Foo'" in
|
|
227
|
+
// the log means the package resolved but the object lookup inside it
|
|
228
|
+
// did not. Load the package explicitly and look again.
|
|
229
|
+
if (!PackageName.IsEmpty())
|
|
230
|
+
{
|
|
231
|
+
if (UPackage* Package = LoadPackage(nullptr, *PackageName, LOAD_None))
|
|
232
|
+
{
|
|
233
|
+
Package->FullyLoad();
|
|
234
|
+
const FString ObjectName = FPackageName::ObjectPathToObjectName(Out.ObjectPath);
|
|
235
|
+
if (UWidgetBlueprint* Live =
|
|
236
|
+
AsLiveWidgetBlueprint(FindObject<UObject>(Package, *ObjectName), Out.FoundClass))
|
|
237
|
+
{
|
|
238
|
+
Out.Blueprint = Live;
|
|
239
|
+
return Out;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (!Out.FoundClass.IsEmpty())
|
|
246
|
+
{
|
|
247
|
+
Out.Failure = EWidgetBlueprintResolveFailure::WrongType;
|
|
248
|
+
}
|
|
249
|
+
else if (Out.bAssetExists)
|
|
250
|
+
{
|
|
251
|
+
Out.Failure = EWidgetBlueprintResolveFailure::Unresolvable;
|
|
252
|
+
}
|
|
253
|
+
else
|
|
254
|
+
{
|
|
255
|
+
Out.Failure = EWidgetBlueprintResolveFailure::NotFound;
|
|
256
|
+
}
|
|
257
|
+
return Out;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
TSharedPtr<FJsonValue> WidgetBlueprintResolveError(
|
|
261
|
+
const FString& AssetPath,
|
|
262
|
+
const FWidgetBlueprintResolve& Resolved)
|
|
263
|
+
{
|
|
264
|
+
switch (Resolved.Failure)
|
|
265
|
+
{
|
|
266
|
+
case EWidgetBlueprintResolveFailure::WrongType:
|
|
267
|
+
return MCPError(FString::Printf(
|
|
268
|
+
TEXT("'%s' is a %s, not a WidgetBlueprint."),
|
|
269
|
+
*AssetPath, *Resolved.FoundClass));
|
|
270
|
+
|
|
271
|
+
case EWidgetBlueprintResolveFailure::Unresolvable:
|
|
272
|
+
// The distinction the caller needs: the asset is there, so retrying or
|
|
273
|
+
// reloading the bridge is the move. Renaming or re-creating it is not.
|
|
274
|
+
return MCPError(FString::Printf(
|
|
275
|
+
TEXT("'%s' exists but could not be resolved to a live WidgetBlueprint on this call. ")
|
|
276
|
+
TEXT("The object handle went stale (a package reload or a GC pass replaced it), the asset is not missing. ")
|
|
277
|
+
TEXT("Retry the call; if it keeps failing, editor(action=\"reload_bridge\") clears it."),
|
|
278
|
+
*AssetPath));
|
|
279
|
+
|
|
280
|
+
case EWidgetBlueprintResolveFailure::NotFound:
|
|
281
|
+
default:
|
|
282
|
+
return MCPError(FString::Printf(
|
|
283
|
+
TEXT("No asset exists at '%s'. Nothing of that name is in the AssetRegistry and no package of that name is on disk. ")
|
|
284
|
+
TEXT("Check the path with widget(action=\"list\") or asset(action=\"search\")."),
|
|
285
|
+
*AssetPath));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
UWidgetBlueprint* ResolveWidgetBlueprintOrError(
|
|
290
|
+
const FString& AssetPath,
|
|
291
|
+
TSharedPtr<FJsonValue>& OutError)
|
|
292
|
+
{
|
|
293
|
+
const FWidgetBlueprintResolve Resolved = ResolveWidgetBlueprint(AssetPath);
|
|
294
|
+
if (!Resolved.Blueprint)
|
|
295
|
+
{
|
|
296
|
+
OutError = WidgetBlueprintResolveError(AssetPath, Resolved);
|
|
297
|
+
}
|
|
298
|
+
return Resolved.Blueprint;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
TSharedPtr<FJsonValue> MissingWidgetTreeError(const FString& AssetPath)
|
|
302
|
+
{
|
|
303
|
+
return MCPError(FString::Printf(
|
|
304
|
+
TEXT("WidgetBlueprint '%s' resolved but has no WidgetTree. The asset is loaded and broken, not missing; ")
|
|
305
|
+
TEXT("open it in the editor or re-create it."),
|
|
306
|
+
*AssetPath));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
}
|
|
66
310
|
|
|
67
311
|
void FWidgetHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
|
|
68
312
|
{
|
|
@@ -200,12 +444,9 @@ TSharedPtr<FJsonValue> FWidgetHandlers::ReadWidgetTree(const TSharedPtr<FJsonObj
|
|
|
200
444
|
FString AssetPath;
|
|
201
445
|
if (auto Err = RequireStringAlt(Params, TEXT("assetPath"), TEXT("path"), AssetPath)) return Err;
|
|
202
446
|
|
|
203
|
-
|
|
204
|
-
UWidgetBlueprint* WidgetBP =
|
|
205
|
-
if (!WidgetBP)
|
|
206
|
-
{
|
|
207
|
-
return MCPError(FString::Printf(TEXT("Failed to load WidgetBlueprint at '%s'"), *AssetPath));
|
|
208
|
-
}
|
|
447
|
+
TSharedPtr<FJsonValue> ResolveError;
|
|
448
|
+
UWidgetBlueprint* WidgetBP = MCPWidget::ResolveWidgetBlueprintOrError(AssetPath, ResolveError);
|
|
449
|
+
if (!WidgetBP) return ResolveError;
|
|
209
450
|
|
|
210
451
|
auto Result = MCPSuccess();
|
|
211
452
|
|
|
@@ -332,11 +573,18 @@ TSharedPtr<FJsonValue> FWidgetHandlers::RunEditorUtilityWidget(const TSharedPtr<
|
|
|
332
573
|
FString AssetPath;
|
|
333
574
|
if (auto Err = RequireStringAlt(Params, TEXT("assetPath"), TEXT("path"), AssetPath)) return Err;
|
|
334
575
|
|
|
335
|
-
|
|
336
|
-
|
|
576
|
+
// UEditorUtilityWidgetBlueprint derives from UWidgetBlueprint, so it goes
|
|
577
|
+
// through the same revalidating resolver and gets the same stale-handle
|
|
578
|
+
// recovery every other widget action gets (#972).
|
|
579
|
+
TSharedPtr<FJsonValue> ResolveError;
|
|
580
|
+
UWidgetBlueprint* ResolvedBP = MCPWidget::ResolveWidgetBlueprintOrError(AssetPath, ResolveError);
|
|
581
|
+
if (!ResolvedBP) return ResolveError;
|
|
582
|
+
UEditorUtilityWidgetBlueprint* EUWidget = Cast<UEditorUtilityWidgetBlueprint>(ResolvedBP);
|
|
337
583
|
if (!EUWidget)
|
|
338
584
|
{
|
|
339
|
-
return MCPError(FString::Printf(
|
|
585
|
+
return MCPError(FString::Printf(
|
|
586
|
+
TEXT("'%s' is a %s, not an EditorUtilityWidgetBlueprint."),
|
|
587
|
+
*AssetPath, *ResolvedBP->GetClass()->GetName()));
|
|
340
588
|
}
|
|
341
589
|
|
|
342
590
|
UEditorUtilitySubsystem* Subsystem = GEditor->GetEditorSubsystem<UEditorUtilitySubsystem>();
|
|
@@ -604,17 +852,11 @@ TSharedPtr<FJsonValue> FWidgetHandlers::AddWidget(const TSharedPtr<FJsonObject>&
|
|
|
604
852
|
FString ParentWidgetName = OptionalString(Params, TEXT("parentWidgetName"));
|
|
605
853
|
|
|
606
854
|
// ── Load the WidgetBlueprint ──
|
|
607
|
-
|
|
608
|
-
UWidgetBlueprint* WidgetBP =
|
|
609
|
-
if (!WidgetBP)
|
|
610
|
-
{
|
|
611
|
-
return MCPError(FString::Printf(TEXT("Failed to load WidgetBlueprint at '%s'"), *AssetPath));
|
|
612
|
-
}
|
|
855
|
+
TSharedPtr<FJsonValue> ResolveError;
|
|
856
|
+
UWidgetBlueprint* WidgetBP = MCPWidget::ResolveWidgetBlueprintOrError(AssetPath, ResolveError);
|
|
857
|
+
if (!WidgetBP) return ResolveError;
|
|
613
858
|
|
|
614
|
-
if (!WidgetBP->WidgetTree)
|
|
615
|
-
{
|
|
616
|
-
return MCPError(TEXT("WidgetTree is null"));
|
|
617
|
-
}
|
|
859
|
+
if (!WidgetBP->WidgetTree) return MCPWidget::MissingWidgetTreeError(AssetPath);
|
|
618
860
|
|
|
619
861
|
// ── Resolve the UClass ──
|
|
620
862
|
UClass* WClass = ResolveWidgetClass(WidgetClassName);
|
|
@@ -784,17 +1026,11 @@ TSharedPtr<FJsonValue> FWidgetHandlers::RemoveWidget(const TSharedPtr<FJsonObjec
|
|
|
784
1026
|
FString WidgetName;
|
|
785
1027
|
if (auto Err = RequireString(Params, TEXT("widgetName"), WidgetName)) return Err;
|
|
786
1028
|
|
|
787
|
-
|
|
788
|
-
UWidgetBlueprint* WidgetBP =
|
|
789
|
-
if (!WidgetBP)
|
|
790
|
-
{
|
|
791
|
-
return MCPError(FString::Printf(TEXT("Failed to load WidgetBlueprint at '%s'"), *AssetPath));
|
|
792
|
-
}
|
|
1029
|
+
TSharedPtr<FJsonValue> ResolveError;
|
|
1030
|
+
UWidgetBlueprint* WidgetBP = MCPWidget::ResolveWidgetBlueprintOrError(AssetPath, ResolveError);
|
|
1031
|
+
if (!WidgetBP) return ResolveError;
|
|
793
1032
|
|
|
794
|
-
if (!WidgetBP->WidgetTree)
|
|
795
|
-
{
|
|
796
|
-
return MCPError(TEXT("WidgetTree is null"));
|
|
797
|
-
}
|
|
1033
|
+
if (!WidgetBP->WidgetTree) return MCPWidget::MissingWidgetTreeError(AssetPath);
|
|
798
1034
|
|
|
799
1035
|
// Find the widget
|
|
800
1036
|
UWidget* FoundWidget = nullptr;
|
|
@@ -880,12 +1116,10 @@ TSharedPtr<FJsonValue> FWidgetHandlers::MoveWidget(const TSharedPtr<FJsonObject>
|
|
|
880
1116
|
FString NewParentName;
|
|
881
1117
|
if (auto Err = RequireStringAlt(Params, TEXT("newParentWidgetName"), TEXT("parentWidgetName"), NewParentName)) return Err;
|
|
882
1118
|
|
|
883
|
-
|
|
884
|
-
UWidgetBlueprint* WidgetBP =
|
|
885
|
-
if (!WidgetBP
|
|
886
|
-
|
|
887
|
-
return MCPError(FString::Printf(TEXT("Failed to load WidgetBlueprint at '%s'"), *AssetPath));
|
|
888
|
-
}
|
|
1119
|
+
TSharedPtr<FJsonValue> ResolveError;
|
|
1120
|
+
UWidgetBlueprint* WidgetBP = MCPWidget::ResolveWidgetBlueprintOrError(AssetPath, ResolveError);
|
|
1121
|
+
if (!WidgetBP) return ResolveError;
|
|
1122
|
+
if (!WidgetBP->WidgetTree) return MCPWidget::MissingWidgetTreeError(AssetPath);
|
|
889
1123
|
|
|
890
1124
|
// Find the widget to move
|
|
891
1125
|
UWidget* WidgetToMove = nullptr;
|
|
@@ -1002,12 +1236,10 @@ TSharedPtr<FJsonValue> FWidgetHandlers::SetRoot(const TSharedPtr<FJsonObject>& P
|
|
|
1002
1236
|
FString WidgetName;
|
|
1003
1237
|
if (auto Err = RequireString(Params, TEXT("widgetName"), WidgetName)) return Err;
|
|
1004
1238
|
|
|
1005
|
-
|
|
1006
|
-
UWidgetBlueprint* WidgetBP =
|
|
1007
|
-
if (!WidgetBP
|
|
1008
|
-
|
|
1009
|
-
return MCPError(FString::Printf(TEXT("Failed to load WidgetBlueprint at '%s'"), *AssetPath));
|
|
1010
|
-
}
|
|
1239
|
+
TSharedPtr<FJsonValue> ResolveError;
|
|
1240
|
+
UWidgetBlueprint* WidgetBP = MCPWidget::ResolveWidgetBlueprintOrError(AssetPath, ResolveError);
|
|
1241
|
+
if (!WidgetBP) return ResolveError;
|
|
1242
|
+
if (!WidgetBP->WidgetTree) return MCPWidget::MissingWidgetTreeError(AssetPath);
|
|
1011
1243
|
|
|
1012
1244
|
UWidget* NewRoot = nullptr;
|
|
1013
1245
|
WidgetBP->WidgetTree->ForEachWidget([&](UWidget* W)
|
|
@@ -1068,12 +1300,10 @@ TSharedPtr<FJsonValue> FWidgetHandlers::WrapRoot(const TSharedPtr<FJsonObject>&
|
|
|
1068
1300
|
FString WrapperClassName;
|
|
1069
1301
|
if (auto Err = RequireStringAlt(Params, TEXT("wrapperClass"), TEXT("widgetClass"), WrapperClassName)) return Err;
|
|
1070
1302
|
|
|
1071
|
-
|
|
1072
|
-
UWidgetBlueprint* WidgetBP =
|
|
1073
|
-
if (!WidgetBP
|
|
1074
|
-
|
|
1075
|
-
return MCPError(FString::Printf(TEXT("Failed to load WidgetBlueprint at '%s'"), *AssetPath));
|
|
1076
|
-
}
|
|
1303
|
+
TSharedPtr<FJsonValue> ResolveError;
|
|
1304
|
+
UWidgetBlueprint* WidgetBP = MCPWidget::ResolveWidgetBlueprintOrError(AssetPath, ResolveError);
|
|
1305
|
+
if (!WidgetBP) return ResolveError;
|
|
1306
|
+
if (!WidgetBP->WidgetTree) return MCPWidget::MissingWidgetTreeError(AssetPath);
|
|
1077
1307
|
|
|
1078
1308
|
UWidget* OldRoot = WidgetBP->WidgetTree->RootWidget;
|
|
1079
1309
|
if (!OldRoot)
|
|
@@ -1200,6 +1430,14 @@ TSharedPtr<FJsonValue> FWidgetHandlers::ListWidgetClasses(const TSharedPtr<FJson
|
|
|
1200
1430
|
// ─────────────────────────────────────────────────────────────
|
|
1201
1431
|
namespace WidgetRuntime_Internal
|
|
1202
1432
|
{
|
|
1433
|
+
// These names are deliberately widget-specific. This namespace is opened with
|
|
1434
|
+
// a block-scope using-directive at several call sites, which injects its names
|
|
1435
|
+
// into the global namespace at exactly the point where a unity-blob neighbour's
|
|
1436
|
+
// anonymous-namespace definitions live. GasHandlers_Runtime.cpp defines a
|
|
1437
|
+
// ResolveRuntimeWorld and EditorHandlers_PIERuntime.cpp a VectorJson; those
|
|
1438
|
+
// pairs resolved as overloads only by arity and by the absence of an implicit
|
|
1439
|
+
// FVector/FVector2D conversion. audit:unity cannot see this class of collision,
|
|
1440
|
+
// because it walks anonymous-namespace bodies only.
|
|
1203
1441
|
struct FDerivedClipState
|
|
1204
1442
|
{
|
|
1205
1443
|
bool bHasRect = false;
|
|
@@ -1239,7 +1477,7 @@ namespace WidgetRuntime_Internal
|
|
|
1239
1477
|
static TMap<FString, uint64> PreviousLayoutCaptureFrames;
|
|
1240
1478
|
static uint64 LayoutCaptureSequence = 0;
|
|
1241
1479
|
|
|
1242
|
-
static UWorld*
|
|
1480
|
+
static UWorld* ResolveWidgetRuntimeWorld()
|
|
1243
1481
|
{
|
|
1244
1482
|
if (!GEditor) return nullptr;
|
|
1245
1483
|
FWorldContext* PIE = GEditor->GetPIEWorldContext();
|
|
@@ -1274,7 +1512,7 @@ namespace WidgetRuntime_Internal
|
|
|
1274
1512
|
return TEXT("Unknown");
|
|
1275
1513
|
}
|
|
1276
1514
|
|
|
1277
|
-
static TSharedPtr<FJsonObject>
|
|
1515
|
+
static TSharedPtr<FJsonObject> WidgetVector2DJson(const FVector2D& Value)
|
|
1278
1516
|
{
|
|
1279
1517
|
TSharedPtr<FJsonObject> Obj = MakeShared<FJsonObject>();
|
|
1280
1518
|
Obj->SetNumberField(TEXT("x"), Value.X);
|
|
@@ -1348,13 +1586,13 @@ namespace WidgetRuntime_Internal
|
|
|
1348
1586
|
const FVector2D Alignment = CanvasSlot->GetAlignment();
|
|
1349
1587
|
TSharedPtr<FJsonObject> Canvas = MakeShared<FJsonObject>();
|
|
1350
1588
|
TSharedPtr<FJsonObject> AnchorsObj = MakeShared<FJsonObject>();
|
|
1351
|
-
AnchorsObj->SetObjectField(TEXT("minimum"),
|
|
1352
|
-
AnchorsObj->SetObjectField(TEXT("maximum"),
|
|
1589
|
+
AnchorsObj->SetObjectField(TEXT("minimum"), WidgetVector2DJson(Anchors.Minimum));
|
|
1590
|
+
AnchorsObj->SetObjectField(TEXT("maximum"), WidgetVector2DJson(Anchors.Maximum));
|
|
1353
1591
|
AnchorsObj->SetBoolField(TEXT("stretchedHorizontally"), !FMath::IsNearlyEqual(Anchors.Minimum.X, Anchors.Maximum.X));
|
|
1354
1592
|
AnchorsObj->SetBoolField(TEXT("stretchedVertically"), !FMath::IsNearlyEqual(Anchors.Minimum.Y, Anchors.Maximum.Y));
|
|
1355
1593
|
Canvas->SetObjectField(TEXT("anchors"), AnchorsObj);
|
|
1356
1594
|
Canvas->SetObjectField(TEXT("offsets"), MarginJson(Offsets));
|
|
1357
|
-
Canvas->SetObjectField(TEXT("alignment"),
|
|
1595
|
+
Canvas->SetObjectField(TEXT("alignment"), WidgetVector2DJson(Alignment));
|
|
1358
1596
|
Canvas->SetBoolField(TEXT("autoSize"), CanvasSlot->GetAutoSize());
|
|
1359
1597
|
Canvas->SetNumberField(TEXT("zOrder"), CanvasSlot->GetZOrder());
|
|
1360
1598
|
SlotObj->SetObjectField(TEXT("canvas"), Canvas);
|
|
@@ -1577,21 +1815,21 @@ namespace WidgetRuntime_Internal
|
|
|
1577
1815
|
|
|
1578
1816
|
TSharedPtr<FJsonObject> GeometryObj = MakeShared<FJsonObject>();
|
|
1579
1817
|
GeometryObj->SetBoolField(TEXT("hasCachedSlateWidget"), bHasCachedSlateWidget);
|
|
1580
|
-
GeometryObj->SetObjectField(TEXT("desiredSize"),
|
|
1581
|
-
GeometryObj->SetObjectField(TEXT("localSize"),
|
|
1582
|
-
GeometryObj->SetObjectField(TEXT("absoluteSize"),
|
|
1583
|
-
GeometryObj->SetObjectField(TEXT("absolutePosition"),
|
|
1818
|
+
GeometryObj->SetObjectField(TEXT("desiredSize"), WidgetVector2DJson(DesiredSize));
|
|
1819
|
+
GeometryObj->SetObjectField(TEXT("localSize"), WidgetVector2DJson(LocalSize));
|
|
1820
|
+
GeometryObj->SetObjectField(TEXT("absoluteSize"), WidgetVector2DJson(AbsoluteSize));
|
|
1821
|
+
GeometryObj->SetObjectField(TEXT("absolutePosition"), WidgetVector2DJson(AbsolutePosition));
|
|
1584
1822
|
GeometryObj->SetObjectField(TEXT("layoutBoundingRect"), RectJson(LayoutRect));
|
|
1585
1823
|
GeometryObj->SetObjectField(TEXT("renderBoundingRect"), RectJson(RenderRect));
|
|
1586
1824
|
GeometryObj->SetNumberField(TEXT("accumulatedLayoutScale"), Geometry.GetAccumulatedLayoutTransform().GetScale());
|
|
1587
1825
|
Obj->SetObjectField(TEXT("geometry"), GeometryObj);
|
|
1588
1826
|
|
|
1589
1827
|
TSharedPtr<FJsonObject> TransformObj = MakeShared<FJsonObject>();
|
|
1590
|
-
TransformObj->SetObjectField(TEXT("translation"),
|
|
1591
|
-
TransformObj->SetObjectField(TEXT("scale"),
|
|
1592
|
-
TransformObj->SetObjectField(TEXT("shear"),
|
|
1828
|
+
TransformObj->SetObjectField(TEXT("translation"), WidgetVector2DJson(RenderTransform.Translation));
|
|
1829
|
+
TransformObj->SetObjectField(TEXT("scale"), WidgetVector2DJson(RenderTransform.Scale));
|
|
1830
|
+
TransformObj->SetObjectField(TEXT("shear"), WidgetVector2DJson(RenderTransform.Shear));
|
|
1593
1831
|
TransformObj->SetNumberField(TEXT("angleDegrees"), RenderTransform.Angle);
|
|
1594
|
-
TransformObj->SetObjectField(TEXT("pivot"),
|
|
1832
|
+
TransformObj->SetObjectField(TEXT("pivot"), WidgetVector2DJson(Widget->GetRenderTransformPivot()));
|
|
1595
1833
|
Obj->SetObjectField(TEXT("renderTransform"), TransformObj);
|
|
1596
1834
|
|
|
1597
1835
|
TSharedPtr<FJsonObject> ClipObj = MakeShared<FJsonObject>();
|
|
@@ -1742,10 +1980,10 @@ namespace WidgetRuntime_Internal
|
|
|
1742
1980
|
bSlotChanged;
|
|
1743
1981
|
DeltaObj->SetBoolField(TEXT("hasPreviousCapture"), true);
|
|
1744
1982
|
DeltaObj->SetBoolField(TEXT("changed"), bChanged);
|
|
1745
|
-
DeltaObj->SetObjectField(TEXT("absolutePositionDelta"),
|
|
1746
|
-
DeltaObj->SetObjectField(TEXT("localSizeDelta"),
|
|
1747
|
-
DeltaObj->SetObjectField(TEXT("absoluteSizeDelta"),
|
|
1748
|
-
DeltaObj->SetObjectField(TEXT("desiredSizeDelta"),
|
|
1983
|
+
DeltaObj->SetObjectField(TEXT("absolutePositionDelta"), WidgetVector2DJson(PositionDelta));
|
|
1984
|
+
DeltaObj->SetObjectField(TEXT("localSizeDelta"), WidgetVector2DJson(LocalSizeDelta));
|
|
1985
|
+
DeltaObj->SetObjectField(TEXT("absoluteSizeDelta"), WidgetVector2DJson(AbsoluteSizeDelta));
|
|
1986
|
+
DeltaObj->SetObjectField(TEXT("desiredSizeDelta"), WidgetVector2DJson(DesiredSizeDelta));
|
|
1749
1987
|
DeltaObj->SetBoolField(TEXT("slotPropertiesChanged"), bSlotChanged);
|
|
1750
1988
|
if (bChanged)
|
|
1751
1989
|
{
|
|
@@ -1846,7 +2084,7 @@ TSharedPtr<FJsonValue> FWidgetHandlers::ListRuntimeWidgets(const TSharedPtr<FJso
|
|
|
1846
2084
|
{
|
|
1847
2085
|
using namespace WidgetRuntime_Internal;
|
|
1848
2086
|
|
|
1849
|
-
UWorld* World =
|
|
2087
|
+
UWorld* World = ResolveWidgetRuntimeWorld();
|
|
1850
2088
|
if (!World)
|
|
1851
2089
|
{
|
|
1852
2090
|
return MCPError(TEXT("No PIE world available. Is Play-In-Editor running?"));
|
|
@@ -1898,7 +2136,7 @@ TSharedPtr<FJsonValue> FWidgetHandlers::GetRuntimeWidget(const TSharedPtr<FJsonO
|
|
|
1898
2136
|
{
|
|
1899
2137
|
using namespace WidgetRuntime_Internal;
|
|
1900
2138
|
|
|
1901
|
-
UWorld* World =
|
|
2139
|
+
UWorld* World = ResolveWidgetRuntimeWorld();
|
|
1902
2140
|
if (!World)
|
|
1903
2141
|
{
|
|
1904
2142
|
return MCPError(TEXT("No PIE world available. Is Play-In-Editor running?"));
|
|
@@ -2094,7 +2332,7 @@ TSharedPtr<FJsonValue> FWidgetHandlers::GetRuntimeWidget(const TSharedPtr<FJsonO
|
|
|
2094
2332
|
TSharedPtr<FJsonValue> FWidgetHandlers::AddWidgetToViewport(const TSharedPtr<FJsonObject>& Params)
|
|
2095
2333
|
{
|
|
2096
2334
|
using namespace WidgetRuntime_Internal;
|
|
2097
|
-
UWorld* World =
|
|
2335
|
+
UWorld* World = ResolveWidgetRuntimeWorld();
|
|
2098
2336
|
if (!World)
|
|
2099
2337
|
{
|
|
2100
2338
|
return MCPError(TEXT("No PIE world available. Start Play-In-Editor first (editor pie_control action=play)."));
|
|
@@ -2151,7 +2389,7 @@ TSharedPtr<FJsonValue> FWidgetHandlers::AddWidgetToViewport(const TSharedPtr<FJs
|
|
|
2151
2389
|
TSharedPtr<FJsonValue> FWidgetHandlers::InvokeRuntimeWidgetFunction(const TSharedPtr<FJsonObject>& Params)
|
|
2152
2390
|
{
|
|
2153
2391
|
using namespace WidgetRuntime_Internal;
|
|
2154
|
-
UWorld* World =
|
|
2392
|
+
UWorld* World = ResolveWidgetRuntimeWorld();
|
|
2155
2393
|
if (!World)
|
|
2156
2394
|
{
|
|
2157
2395
|
return MCPError(TEXT("No PIE world available. Is Play-In-Editor running?"));
|
|
@@ -2242,7 +2480,7 @@ TSharedPtr<FJsonValue> FWidgetHandlers::GetRuntimeDelegates(const TSharedPtr<FJs
|
|
|
2242
2480
|
{
|
|
2243
2481
|
using namespace WidgetRuntime_Internal;
|
|
2244
2482
|
|
|
2245
|
-
UWorld* World =
|
|
2483
|
+
UWorld* World = ResolveWidgetRuntimeWorld();
|
|
2246
2484
|
if (!World)
|
|
2247
2485
|
{
|
|
2248
2486
|
return MCPError(TEXT("No PIE world available. Is Play-In-Editor running?"));
|
|
@@ -4,6 +4,90 @@
|
|
|
4
4
|
#include "Dom/JsonValue.h"
|
|
5
5
|
#include "Dom/JsonObject.h"
|
|
6
6
|
|
|
7
|
+
class UWidgetBlueprint;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Shared WidgetBlueprint resolution for every widget action (#972).
|
|
11
|
+
*
|
|
12
|
+
* Symptom: building a WidgetBlueprint incrementally failed every second or
|
|
13
|
+
* third add_widget with "Failed to load WidgetBlueprint", on an asset that was
|
|
14
|
+
* on disk, was in the AssetRegistry, and that asset(search) could see. Then it
|
|
15
|
+
* wedged permanently, and asset(force_reload) made it worse while
|
|
16
|
+
* editor(reload_bridge) cleared it instantly.
|
|
17
|
+
*
|
|
18
|
+
* Mechanism, confirmed by reading every widget translation unit: the handlers
|
|
19
|
+
* hold NO pointer between calls. Each one re-resolved from the path through
|
|
20
|
+
* UEditorAssetLibrary::LoadAsset, which is not a plain load. It converts the
|
|
21
|
+
* path, looks the asset up in the AssetRegistry, and loads the FAssetData it
|
|
22
|
+
* got back. That round trip is what intermittently answers null: the registry
|
|
23
|
+
* entry a call resolved through can be mid-rescan, and after a package reload
|
|
24
|
+
* it names an object that has been consigned to oblivion (RF_NewerVersionExists)
|
|
25
|
+
* while a new one holds the name. So the stale handle is real, it just lives in
|
|
26
|
+
* the engine's asset plumbing rather than in a static in this plugin, and
|
|
27
|
+
* "resolve fresh per call" was already true and not enough on its own.
|
|
28
|
+
*
|
|
29
|
+
* The resolver below therefore does three things the old one-liner did not:
|
|
30
|
+
*
|
|
31
|
+
* 1. Asks the object hash FIRST (FindObject on the object path). An asset
|
|
32
|
+
* already in memory answers without touching the registry round trip at
|
|
33
|
+
* all, which is the step that removes the intermittency.
|
|
34
|
+
* 2. Revalidates whatever it gets. IsValid plus an RF_NewerVersionExists
|
|
35
|
+
* check, so a reload's corpse is never handed to a caller who would then
|
|
36
|
+
* mutate an object the editor no longer consults.
|
|
37
|
+
* 3. Falls through progressively (EditorAssetLibrary, direct LoadObject,
|
|
38
|
+
* explicit LoadPackage then look inside it) instead of giving up on the
|
|
39
|
+
* first null.
|
|
40
|
+
*
|
|
41
|
+
* It also separates "there is no such asset" from "the asset is there and the
|
|
42
|
+
* handle went stale", because the caller's next move differs: fix the path, or
|
|
43
|
+
* retry / reload the bridge.
|
|
44
|
+
*/
|
|
45
|
+
namespace MCPWidget
|
|
46
|
+
{
|
|
47
|
+
|
|
48
|
+
enum class EWidgetBlueprintResolveFailure : uint8
|
|
49
|
+
{
|
|
50
|
+
/** Resolved. */
|
|
51
|
+
None,
|
|
52
|
+
/** Nothing in the AssetRegistry and no package of that name on disk. */
|
|
53
|
+
NotFound,
|
|
54
|
+
/** The path names something real that is not a WidgetBlueprint. */
|
|
55
|
+
WrongType,
|
|
56
|
+
/** The asset exists but no live object could be reached this call. */
|
|
57
|
+
Unresolvable,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
struct FWidgetBlueprintResolve
|
|
61
|
+
{
|
|
62
|
+
UWidgetBlueprint* Blueprint = nullptr;
|
|
63
|
+
EWidgetBlueprintResolveFailure Failure = EWidgetBlueprintResolveFailure::None;
|
|
64
|
+
/** The normalised object path that was searched for. */
|
|
65
|
+
FString ObjectPath;
|
|
66
|
+
/** Class of the object that was found, when Failure is WrongType. */
|
|
67
|
+
FString FoundClass;
|
|
68
|
+
/** True when the registry or the filesystem says the asset is really there. */
|
|
69
|
+
bool bAssetExists = false;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/** Resolve fresh, revalidate, and say why when it fails. Never caches. */
|
|
73
|
+
FWidgetBlueprintResolve ResolveWidgetBlueprint(const FString& AssetPath);
|
|
74
|
+
|
|
75
|
+
/** Error JSON for a failed resolve, worded per failure kind. */
|
|
76
|
+
TSharedPtr<FJsonValue> WidgetBlueprintResolveError(
|
|
77
|
+
const FString& AssetPath,
|
|
78
|
+
const FWidgetBlueprintResolve& Resolved);
|
|
79
|
+
|
|
80
|
+
/** The `if (!WidgetBP) return Err;` shape every handler wants. */
|
|
81
|
+
UWidgetBlueprint* ResolveWidgetBlueprintOrError(
|
|
82
|
+
const FString& AssetPath,
|
|
83
|
+
TSharedPtr<FJsonValue>& OutError);
|
|
84
|
+
|
|
85
|
+
/** A resolved blueprint whose WidgetTree is missing is a broken asset, not a
|
|
86
|
+
* failed load. Separate message so the two stop looking identical. */
|
|
87
|
+
TSharedPtr<FJsonValue> MissingWidgetTreeError(const FString& AssetPath);
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
7
91
|
class FWidgetHandlers
|
|
8
92
|
{
|
|
9
93
|
public:
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Extraction.cpp
CHANGED
|
@@ -18,49 +18,16 @@
|
|
|
18
18
|
|
|
19
19
|
namespace
|
|
20
20
|
{
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const int32 LastSlashIndex = ObjectPath.Find(TEXT("/"), ESearchCase::CaseSensitive, ESearchDir::FromEnd);
|
|
29
|
-
const int32 DotIndex = ObjectPath.Find(TEXT("."), ESearchCase::CaseSensitive, ESearchDir::FromEnd);
|
|
30
|
-
if (DotIndex <= LastSlashIndex)
|
|
31
|
-
{
|
|
32
|
-
const FString AssetName = FPackageName::GetLongPackageAssetName(ObjectPath);
|
|
33
|
-
if (!AssetName.IsEmpty())
|
|
34
|
-
{
|
|
35
|
-
ObjectPath += TEXT(".") + AssetName;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return ObjectPath;
|
|
39
|
-
}
|
|
40
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Extraction's loader. Delegates to the one shared resolver (#972) rather than
|
|
23
|
+
* carrying a second path-normalising, second-chance-loading copy of it: the
|
|
24
|
+
* module is a unity build, and two file-local copies of the same helper both
|
|
25
|
+
* collide and drift. A null return is still the normal "destination does not
|
|
26
|
+
* exist yet, create it" outcome here.
|
|
27
|
+
*/
|
|
41
28
|
UWidgetBlueprint* LoadWidgetBlueprintForExtraction(const FString& AssetPath)
|
|
42
29
|
{
|
|
43
|
-
|
|
44
|
-
// A missing destination is the normal create path. StaticLoadObject on a
|
|
45
|
-
// non-existent package can force a blocking package search, so only use the
|
|
46
|
-
// fallback for explicit object/generated-class paths supplied by callers.
|
|
47
|
-
if (!LoadedAsset && AssetPath.Contains(TEXT(".")))
|
|
48
|
-
{
|
|
49
|
-
const FString ObjectPath = MakeExtractionWidgetBlueprintObjectPath(AssetPath);
|
|
50
|
-
LoadedAsset = StaticLoadObject(UObject::StaticClass(), nullptr, *ObjectPath);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(LoadedAsset))
|
|
54
|
-
{
|
|
55
|
-
return WidgetBlueprint;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (UClass* LoadedClass = Cast<UClass>(LoadedAsset))
|
|
59
|
-
{
|
|
60
|
-
return Cast<UWidgetBlueprint>(LoadedClass->ClassGeneratedBy);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return nullptr;
|
|
30
|
+
return MCPWidget::ResolveWidgetBlueprint(AssetPath).Blueprint;
|
|
64
31
|
}
|
|
65
32
|
|
|
66
33
|
struct FExtractedWidgetPlanEntry
|