ue-mcp 1.3.0 → 1.3.1-beta.2
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 +5 -3
- package/dist/action-class.js +141 -3
- package/dist/action-class.js.map +1 -1
- package/dist/action-schema.d.ts +157 -0
- package/dist/action-schema.js +731 -0
- package/dist/action-schema.js.map +1 -0
- package/dist/bridge-timeouts.js +23 -0
- package/dist/bridge-timeouts.js.map +1 -1
- package/dist/bridge.js +28 -11
- package/dist/bridge.js.map +1 -1
- package/dist/call-pipeline.d.ts +126 -0
- package/dist/call-pipeline.js +144 -0
- package/dist/call-pipeline.js.map +1 -0
- package/dist/content-index.d.ts +41 -0
- package/dist/content-index.js +149 -0
- package/dist/content-index.js.map +1 -0
- package/dist/cpp-correctness.d.ts +165 -0
- package/dist/cpp-correctness.js +562 -0
- package/dist/cpp-correctness.js.map +1 -0
- package/dist/dialog-cli.d.ts +15 -0
- package/dist/dialog-cli.js +146 -0
- package/dist/dialog-cli.js.map +1 -0
- package/dist/editor-control.d.ts +268 -18
- package/dist/editor-control.js +789 -54
- package/dist/editor-control.js.map +1 -1
- package/dist/editor-target.d.ts +31 -0
- package/dist/editor-target.js +34 -0
- package/dist/editor-target.js.map +1 -1
- package/dist/engine-analysis.d.ts +286 -0
- package/dist/engine-analysis.js +874 -0
- package/dist/engine-analysis.js.map +1 -0
- package/dist/engine-index.d.ts +159 -0
- package/dist/engine-index.js +496 -0
- package/dist/engine-index.js.map +1 -0
- package/dist/epic-enrich.js +2 -2
- package/dist/epic-enrich.js.map +1 -1
- package/dist/field-select.d.ts +57 -0
- package/dist/field-select.js +204 -0
- package/dist/field-select.js.map +1 -0
- package/dist/flow/bridge-task.d.ts +5 -0
- package/dist/flow/bridge-task.js +11 -1
- package/dist/flow/bridge-task.js.map +1 -1
- package/dist/flow/flow-tool.js +207 -34
- package/dist/flow/flow-tool.js.map +1 -1
- package/dist/flow/guarded-bridge.js +23 -7
- package/dist/flow/guarded-bridge.js.map +1 -1
- package/dist/flow/handler-outcome.d.ts +97 -0
- package/dist/flow/handler-outcome.js +127 -0
- package/dist/flow/handler-outcome.js.map +1 -0
- package/dist/flow/journal-actions.d.ts +24 -0
- package/dist/flow/journal-actions.js +364 -0
- package/dist/flow/journal-actions.js.map +1 -0
- package/dist/flow/registry.js +18 -2
- package/dist/flow/registry.js.map +1 -1
- package/dist/flow/schema.d.ts +30 -30
- package/dist/flow/skill-actions.d.ts +14 -0
- package/dist/flow/skill-actions.js +269 -0
- package/dist/flow/skill-actions.js.map +1 -0
- package/dist/flow/task-factory.d.ts +9 -3
- package/dist/flow/task-factory.js +55 -11
- package/dist/flow/task-factory.js.map +1 -1
- package/dist/index.js +169 -13
- package/dist/index.js.map +1 -1
- package/dist/init.js +14 -0
- package/dist/init.js.map +1 -1
- package/dist/install-check.d.ts +101 -0
- package/dist/install-check.js +366 -0
- package/dist/install-check.js.map +1 -0
- package/dist/journal.d.ts +212 -0
- package/dist/journal.js +406 -0
- package/dist/journal.js.map +1 -0
- package/dist/lean-context.js +22 -5
- package/dist/lean-context.js.map +1 -1
- package/dist/offline.d.ts +162 -0
- package/dist/offline.js +303 -0
- package/dist/offline.js.map +1 -0
- package/dist/pagination.d.ts +99 -0
- package/dist/pagination.js +175 -0
- package/dist/pagination.js.map +1 -0
- package/dist/path-params.d.ts +61 -0
- package/dist/path-params.js +120 -0
- package/dist/path-params.js.map +1 -0
- package/dist/plugin/injection.js +2 -2
- package/dist/plugin/injection.js.map +1 -1
- package/dist/plugin/manifest.d.ts +15 -15
- package/dist/plugin/provision.js +2 -2
- package/dist/plugin/provision.js.map +1 -1
- package/dist/project.d.ts +35 -0
- package/dist/project.js +72 -8
- package/dist/project.js.map +1 -1
- package/dist/session-env.js +12 -0
- package/dist/session-env.js.map +1 -1
- package/dist/session-surface.js +2 -19
- package/dist/session-surface.js.map +1 -1
- package/dist/session.d.ts +29 -0
- package/dist/session.js +54 -1
- package/dist/session.js.map +1 -1
- package/dist/skill-packs.d.ts +141 -0
- package/dist/skill-packs.js +478 -0
- package/dist/skill-packs.js.map +1 -0
- package/dist/skills.d.ts +14 -11
- package/dist/skills.js +38 -65
- package/dist/skills.js.map +1 -1
- package/dist/tool-counts.json +20 -20
- package/dist/tools/animation.js +81 -17
- package/dist/tools/animation.js.map +1 -1
- package/dist/tools/asset.js +237 -39
- package/dist/tools/asset.js.map +1 -1
- package/dist/tools/audio.js +43 -8
- package/dist/tools/audio.js.map +1 -1
- package/dist/tools/blueprint.js +76 -10
- package/dist/tools/blueprint.js.map +1 -1
- package/dist/tools/demo.js +3 -3
- package/dist/tools/demo.js.map +1 -1
- package/dist/tools/editor.js +159 -42
- package/dist/tools/editor.js.map +1 -1
- package/dist/tools/fab.js +7 -7
- package/dist/tools/fab.js.map +1 -1
- package/dist/tools/feedback.js +14 -4
- package/dist/tools/feedback.js.map +1 -1
- package/dist/tools/foliage.js +50 -4
- package/dist/tools/foliage.js.map +1 -1
- package/dist/tools/gameplay.js +137 -51
- package/dist/tools/gameplay.js.map +1 -1
- package/dist/tools/gas.js +74 -9
- package/dist/tools/gas.js.map +1 -1
- package/dist/tools/landscape.js +158 -10
- package/dist/tools/landscape.js.map +1 -1
- package/dist/tools/level.js +37 -18
- package/dist/tools/level.js.map +1 -1
- package/dist/tools/material.js +43 -8
- package/dist/tools/material.js.map +1 -1
- package/dist/tools/networking.js +10 -10
- package/dist/tools/networking.js.map +1 -1
- package/dist/tools/niagara.js +44 -8
- package/dist/tools/niagara.js.map +1 -1
- package/dist/tools/pcg.js +25 -8
- package/dist/tools/pcg.js.map +1 -1
- package/dist/tools/plugins.js +1 -1
- package/dist/tools/plugins.js.map +1 -1
- package/dist/tools/project.d.ts +17 -1
- package/dist/tools/project.js +571 -17
- package/dist/tools/project.js.map +1 -1
- package/dist/tools/reflection.js +15 -5
- package/dist/tools/reflection.js.map +1 -1
- package/dist/tools/statetree.js +44 -3
- package/dist/tools/statetree.js.map +1 -1
- package/dist/tools/widget.js +70 -4
- package/dist/tools/widget.js.map +1 -1
- package/dist/types.d.ts +75 -10
- package/dist/types.js +95 -20
- package/dist/types.js.map +1 -1
- package/dist/ue-mcp.default.yml +1571 -201
- package/dist/user-state.d.ts +42 -0
- package/dist/user-state.js +366 -38
- package/dist/user-state.js.map +1 -1
- package/dist/version-check.js +46 -5
- package/dist/version-check.js.map +1 -1
- package/package.json +4 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.cpp +130 -24
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.h +44 -8
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/EngineStatusHooks.cpp +22 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.cpp +135 -66
- 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 +117 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerPoseSearchSchema.h +92 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerStateTreeSchema.h +224 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.cpp +467 -13
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.h +36 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +4 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRigSequencer.cpp +132 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Depth.cpp +1432 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRetargeterAuthoring.cpp +41 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_IKRigAuthoring.cpp +45 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_MotionMatching.cpp +186 -15
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Sequence.cpp +319 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_SkeletalLive.cpp +45 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Skeleton.cpp +2866 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_StateMachine.cpp +547 -10
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_Validation.cpp +28 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.cpp +551 -57
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.h +40 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_GeometryScript.cpp +2697 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Hygiene.cpp +1700 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Import.cpp +494 -57
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Mesh.cpp +121 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Redirectors.cpp +11 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Sockets.cpp +55 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Subobject.cpp +12 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_UV.cpp +2972 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers.cpp +55 -22
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers.h +32 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_Depth.cpp +1559 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_MetaSound.cpp +562 -67
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_MetaSoundRead.cpp +1415 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_Mixing.cpp +210 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers_SoundCue.cpp +61 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.cpp +506 -25
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.h +43 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Depth.cpp +2579 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Functions.cpp +162 -13
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Graph.cpp +694 -25
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +96 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Properties.cpp +124 -11
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Search.cpp +73 -24
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_UserTypes.cpp +1344 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ChooserHandlers.cpp +136 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ChooserHandlers_Nested.cpp +14 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.cpp +120 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DialogHandlers.cpp +588 -133
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DialogHandlers.h +65 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.cpp +679 -26
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.h +50 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +70 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIE.cpp +261 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_PIERuntime.cpp +270 -23
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Profiling.cpp +1665 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_RuntimeVisibility.cpp +41 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_ViewportControl.cpp +1229 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EpicHandlers.cpp +22 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FabHandlers.cpp +103 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.cpp +120 -12
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +14 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers_Batch.cpp +87 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers_Depth.cpp +1482 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.cpp +954 -168
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.h +63 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BTAuthoring.cpp +12 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_BTRuntime.cpp +1556 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_EQS.cpp +760 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_Input.cpp +1297 -4
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_Mass.cpp +1303 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_Perception.cpp +1493 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +164 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +77 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Abilities.cpp +1392 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Runtime.cpp +882 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers_Snapshot.cpp +1002 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +113 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.h +31 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +3778 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.cpp +790 -44
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_BatchWrite.cpp +44 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Convert.cpp +6 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_InstanceProjection.cpp +37 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Lights.cpp +64 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_MultiLevel.cpp +13 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_PostProcess.cpp +156 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Query.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Refresh.cpp +18 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Save.cpp +9 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Transient.cpp +79 -11
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_Volumes.cpp +174 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartition.cpp +77 -14
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers_WorldPartitionSettings.cpp +79 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.cpp +591 -32
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.h +16 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Advanced.cpp +168 -8
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Build.cpp +30 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Function.cpp +106 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Graph.cpp +156 -23
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_RVT.cpp +1510 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NetworkingHandlers.cpp +232 -13
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.cpp +471 -45
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.h +23 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers_Advanced.cpp +1936 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers_Compile.cpp +300 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PCGHandlers.cpp +520 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +369 -13
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ProjectHandlers.cpp +44 -5
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ProjectHandlers.h +13 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ProjectHandlers_Plugins.cpp +482 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ReflectionHandlers.cpp +346 -31
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ReflectionHandlers.h +5 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ReflectionHandlers_Schema.cpp +842 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +270 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SkeletalMeshHandlers.cpp +65 -3
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.cpp +912 -23
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers.h +22 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/StateTreeHandlers_Depth.cpp +1782 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.cpp +579 -185
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.h +37 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Animation.cpp +2691 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_CommonUI.cpp +612 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Extraction.cpp +14 -11
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Properties.cpp +253 -7
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_RuntimeState.cpp +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Tests/DataTableRowWriteTests.cpp +352 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/UE_MCP_Bridge.cpp +48 -25
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerPagination.h +404 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/HandlerUtils.h +593 -18
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/JsonSerializer.cpp +19 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/UE_MCP_Bridge.Build.cs +31 -0
- package/plugin/ue_mcp_bridge/UE_MCP_Bridge.uplugin +2 -2
- package/skills/ue-mcp-animation/ue-mcp.yml +14 -0
- package/skills/ue-mcp-blueprint/ue-mcp.yml +8 -0
- package/skills/ue-mcp-epic-routing/ue-mcp.yml +6 -0
- package/skills/ue-mcp-native-cpp/ue-mcp.yml +7 -0
- package/skills/ue-mcp-niagara/ue-mcp.yml +9 -0
- package/skills/ue-mcp-workflow/SKILL.md +3 -2
- package/skills/ue-mcp-workflow/ue-mcp.yml +3 -0
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_CommonUI.cpp
ADDED
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
// CommonUI support, and the BindWidget contract it depends on. A translation-unit
|
|
2
|
+
// partition of FWidgetHandlers; registration stays in WidgetHandlers.cpp.
|
|
3
|
+
//
|
|
4
|
+
// ── Why so little is here ────────────────────────────────────────────────────
|
|
5
|
+
//
|
|
6
|
+
// An audit came first, because most of CommonUI turned out to be reachable
|
|
7
|
+
// already and a handler that duplicates a property write is a liability. What
|
|
8
|
+
// was checked, and where the existing route is:
|
|
9
|
+
//
|
|
10
|
+
// Adding a CommonUI widget widget(add_widget). ResolveWidgetClass
|
|
11
|
+
// (WidgetHandlers.cpp) resolves a full path and,
|
|
12
|
+
// as of this ticket, an unambiguous short name
|
|
13
|
+
// over every loaded UWidget subclass.
|
|
14
|
+
// Discovering the class names widget(list_classes), which this ticket turned
|
|
15
|
+
// from a hardcoded 21-entry UMG array into a real
|
|
16
|
+
// enumeration grouped by module.
|
|
17
|
+
// Runtime push / pop UCommonActivatableWidgetContainerBase::
|
|
18
|
+
// BP_AddWidget and RemoveWidget are
|
|
19
|
+
// BlueprintCallable (CommonActivatableWidgetContainer.h:156,
|
|
20
|
+
// :72), so editor(invoke_object_function) calls them.
|
|
21
|
+
// Tab registration UCommonTabListWidgetBase::RegisterTab /
|
|
22
|
+
// RemoveTab / SelectTabByID are BlueprintCallable
|
|
23
|
+
// (CommonTabListWidgetBase.h:107, :111, :123).
|
|
24
|
+
// Every style, border, text, Plain UPROPERTYs: UCommonButtonBase::Style
|
|
25
|
+
// lazy-image and load-guard (CommonButtonBase.h:826), UCommonBorder::Style
|
|
26
|
+
// setting (CommonBorder.h:46), UCommonTextBlock::Style
|
|
27
|
+
// (CommonTextBlock.h:207),
|
|
28
|
+
// UCommonBoundActionBar::ActionButtonClass
|
|
29
|
+
// (CommonBoundActionBar.h:68). widget(set_property)
|
|
30
|
+
// and widget(set_style) already write all of them.
|
|
31
|
+
// Style asset creation blueprint(create) resolves any parent class, and
|
|
32
|
+
// UCommonButtonStyle / UCommonTextStyle are plain
|
|
33
|
+
// UObject subclasses.
|
|
34
|
+
// Input action data UCommonInputSettings is config=Game, so
|
|
35
|
+
// project(set_config) writes it.
|
|
36
|
+
//
|
|
37
|
+
// That left exactly two things no existing action can answer:
|
|
38
|
+
//
|
|
39
|
+
// 1. BindWidget metadata. A native UUserWidget subclass states its contract in
|
|
40
|
+
// UPROPERTY meta, and metadata is not a property value. reflection(reflect_class)
|
|
41
|
+
// reports a fixed allowlist of meta keys (ReflectionHandlers.cpp:350-357:
|
|
42
|
+
// Category, DisplayName, EditCondition, Clamp*, UI*, Units) and BindWidget is
|
|
43
|
+
// not among them. So a caller subclassing CommonButtonBase had no way to learn
|
|
44
|
+
// which child widgets it must name, and found out from a compile error.
|
|
45
|
+
// This generalises well past CommonUI: it is the contract of ANY native
|
|
46
|
+
// UserWidget parent.
|
|
47
|
+
// 2. The CommonUI wiring rules. They are relationships between a project
|
|
48
|
+
// setting, an engine class override and a widget tree, evaluated together.
|
|
49
|
+
// Each half is readable; nothing joins them, and every one of them fails
|
|
50
|
+
// silently at runtime rather than at compile time.
|
|
51
|
+
//
|
|
52
|
+
// ── Why nothing here links CommonUI ──────────────────────────────────────────
|
|
53
|
+
//
|
|
54
|
+
// CommonUI ships disabled. A Build.cs dependency on it would fail to link the
|
|
55
|
+
// whole bridge in every project that has it off, which is most of them, so every
|
|
56
|
+
// CommonUI class below is reached by path at runtime through FindObject and every
|
|
57
|
+
// property by name through FindFProperty. When the plugin is off the actions say
|
|
58
|
+
// so, and say how to turn it on, rather than failing to load.
|
|
59
|
+
|
|
60
|
+
#include "WidgetHandlers.h"
|
|
61
|
+
#include "HandlerRegistry.h"
|
|
62
|
+
#include "HandlerUtils.h"
|
|
63
|
+
|
|
64
|
+
#include "WidgetBlueprint.h"
|
|
65
|
+
#include "Blueprint/UserWidget.h"
|
|
66
|
+
#include "Blueprint/WidgetTree.h"
|
|
67
|
+
#include "Animation/WidgetAnimation.h"
|
|
68
|
+
#include "Components/Widget.h"
|
|
69
|
+
#include "Components/PanelWidget.h"
|
|
70
|
+
|
|
71
|
+
#include "Interfaces/IPluginManager.h"
|
|
72
|
+
|
|
73
|
+
#include "Engine/Engine.h"
|
|
74
|
+
#include "Engine/Blueprint.h"
|
|
75
|
+
#include "UObject/Class.h"
|
|
76
|
+
#include "UObject/UnrealType.h"
|
|
77
|
+
#include "UObject/SoftObjectPtr.h"
|
|
78
|
+
#include "Dom/JsonObject.h"
|
|
79
|
+
#include "Dom/JsonValue.h"
|
|
80
|
+
|
|
81
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
82
|
+
// File-local helpers.
|
|
83
|
+
//
|
|
84
|
+
// The module is a unity build, so two .cpp files in one blob share their
|
|
85
|
+
// anonymous namespace and a duplicated helper is a redefinition (C2084). Every
|
|
86
|
+
// name below is prefixed WCui_ inside a named namespace and exists nowhere else
|
|
87
|
+
// in the tree; nothing was copied out of WidgetHandlers.cpp or
|
|
88
|
+
// WidgetHandlers_Animation.cpp, both of which are neighbours in this module.
|
|
89
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
90
|
+
namespace MCPWidgetCommonUI
|
|
91
|
+
{
|
|
92
|
+
|
|
93
|
+
/** The four BindWidget meta keys, and what each one means. */
|
|
94
|
+
struct FWCui_BindKind
|
|
95
|
+
{
|
|
96
|
+
const TCHAR* MetaKey;
|
|
97
|
+
bool bOptional;
|
|
98
|
+
bool bAnimation;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
static const FWCui_BindKind WCui_BindKinds[] = {
|
|
102
|
+
{ TEXT("BindWidget"), false, false },
|
|
103
|
+
{ TEXT("BindWidgetOptional"), true, false },
|
|
104
|
+
{ TEXT("BindWidgetAnim"), false, true },
|
|
105
|
+
{ TEXT("BindWidgetAnimOptional"), true, true },
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Is this property part of a UserWidget's bind contract, and how strict is it?
|
|
110
|
+
*
|
|
111
|
+
* `meta=(BindWidget, OptionalWidget=true)` is the older spelling of
|
|
112
|
+
* BindWidgetOptional and the engine still honours it, so both are read here.
|
|
113
|
+
* Missing that would report a property as required when the compiler does not.
|
|
114
|
+
*/
|
|
115
|
+
static bool WCui_ReadBindKind(const FProperty* Prop, bool& bOutOptional, bool& bOutAnimation)
|
|
116
|
+
{
|
|
117
|
+
// WITH_METADATA, not WITH_EDITOR: metadata is what this reads and that macro
|
|
118
|
+
// is what gates the API. Both are on in an editor build; only one of them
|
|
119
|
+
// says why this code needs the guard.
|
|
120
|
+
#if WITH_METADATA
|
|
121
|
+
for (const FWCui_BindKind& Kind : WCui_BindKinds)
|
|
122
|
+
{
|
|
123
|
+
if (!Prop->HasMetaData(Kind.MetaKey)) continue;
|
|
124
|
+
bOutAnimation = Kind.bAnimation;
|
|
125
|
+
bOutOptional = Kind.bOptional
|
|
126
|
+
|| Prop->GetBoolMetaData(TEXT("OptionalWidget"))
|
|
127
|
+
|| Prop->HasMetaData(TEXT("BindWidgetOptional"))
|
|
128
|
+
|| Prop->HasMetaData(TEXT("BindWidgetAnimOptional"));
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
#endif // WITH_METADATA
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Resolve a class spec: short name, /Script path, or a Widget Blueprint path. */
|
|
136
|
+
static UClass* WCui_ResolveWidgetClassSpec(const FString& Spec)
|
|
137
|
+
{
|
|
138
|
+
if (Spec.IsEmpty()) return nullptr;
|
|
139
|
+
|
|
140
|
+
if (UClass* Direct = MCPResolveClass(Spec, /*bAllowLoad*/ true))
|
|
141
|
+
{
|
|
142
|
+
if (Direct->IsChildOf(UWidget::StaticClass())) return Direct;
|
|
143
|
+
}
|
|
144
|
+
// A Widget Blueprint path names the asset; its contract lives on the class.
|
|
145
|
+
if (UObject* Asset = LoadObject<UObject>(nullptr, *Spec))
|
|
146
|
+
{
|
|
147
|
+
if (UBlueprint* BP = Cast<UBlueprint>(Asset))
|
|
148
|
+
{
|
|
149
|
+
if (BP->GeneratedClass && BP->GeneratedClass->IsChildOf(UWidget::StaticClass()))
|
|
150
|
+
{
|
|
151
|
+
return BP->GeneratedClass;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return nullptr;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** A CommonUI class by name, or null when the plugin is not loaded. */
|
|
159
|
+
static UClass* WCui_CommonClass(const TCHAR* Module, const TCHAR* ClassName)
|
|
160
|
+
{
|
|
161
|
+
const FString Path = FString::Printf(TEXT("/Script/%s.%s"), Module, ClassName);
|
|
162
|
+
return FindObject<UClass>(nullptr, *Path);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
static bool WCui_PluginLoaded()
|
|
166
|
+
{
|
|
167
|
+
return IPluginManager::Get().FindEnabledPlugin(TEXT("CommonUI")).IsValid();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Every widget in the tree, parents before children. */
|
|
171
|
+
static void WCui_CollectWidgets(UWidgetTree* Tree, TArray<UWidget*>& Out)
|
|
172
|
+
{
|
|
173
|
+
if (!Tree) return;
|
|
174
|
+
Tree->ForEachWidget([&Out](UWidget* W) { if (W) Out.Add(W); });
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** The class a TSubclassOf property currently points at, or null. */
|
|
178
|
+
static UClass* WCui_ReadClassProperty(UObject* Object, const TCHAR* PropertyName)
|
|
179
|
+
{
|
|
180
|
+
FClassProperty* Prop = FindFProperty<FClassProperty>(Object->GetClass(), PropertyName);
|
|
181
|
+
if (!Prop) return nullptr;
|
|
182
|
+
return Cast<UClass>(Prop->GetObjectPropertyValue_InContainer(Object));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** True when the named TSubclassOf property exists on the object AND is unset. */
|
|
186
|
+
static bool WCui_ClassPropertyIsUnset(UObject* Object, const TCHAR* PropertyName)
|
|
187
|
+
{
|
|
188
|
+
FClassProperty* Prop = FindFProperty<FClassProperty>(Object->GetClass(), PropertyName);
|
|
189
|
+
if (!Prop) return false; // Property absent: a different engine version, not a fault.
|
|
190
|
+
return WCui_ReadClassProperty(Object, PropertyName) == nullptr;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** One entry in the audit's problems array, in one shape for every rule. */
|
|
194
|
+
static TSharedPtr<FJsonValue> WCui_Problem(
|
|
195
|
+
const TCHAR* Rule, const FString& Where, const FString& What, const FString& Fix)
|
|
196
|
+
{
|
|
197
|
+
TSharedPtr<FJsonObject> Obj = MakeShared<FJsonObject>();
|
|
198
|
+
Obj->SetStringField(TEXT("rule"), Rule);
|
|
199
|
+
Obj->SetStringField(TEXT("where"), Where);
|
|
200
|
+
Obj->SetStringField(TEXT("problem"), What);
|
|
201
|
+
Obj->SetStringField(TEXT("fix"), Fix);
|
|
202
|
+
return MakeShared<FJsonValueObject>(Obj);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
static TSharedPtr<FJsonValue> WCui_Note(const TCHAR* Rule, const FString& Why)
|
|
206
|
+
{
|
|
207
|
+
TSharedPtr<FJsonObject> Obj = MakeShared<FJsonObject>();
|
|
208
|
+
Obj->SetStringField(TEXT("rule"), Rule);
|
|
209
|
+
Obj->SetStringField(TEXT("reason"), Why);
|
|
210
|
+
return MakeShared<FJsonValueObject>(Obj);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
} // namespace MCPWidgetCommonUI
|
|
214
|
+
|
|
215
|
+
using namespace MCPWidgetCommonUI;
|
|
216
|
+
|
|
217
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
218
|
+
// get_bind_widget_contract
|
|
219
|
+
//
|
|
220
|
+
// What a native UserWidget parent requires of the Widget Blueprint below it.
|
|
221
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
222
|
+
|
|
223
|
+
TSharedPtr<FJsonValue> FWidgetHandlers::GetBindWidgetContract(const TSharedPtr<FJsonObject>& Params)
|
|
224
|
+
{
|
|
225
|
+
const FString ClassName = OptionalString(Params, TEXT("className"));
|
|
226
|
+
const FString AssetPath = OptionalString(Params, TEXT("assetPath"));
|
|
227
|
+
|
|
228
|
+
if (ClassName.IsEmpty() && AssetPath.IsEmpty())
|
|
229
|
+
{
|
|
230
|
+
return MCPError(TEXT(
|
|
231
|
+
"Pass className to read a parent class's contract (a short name like CommonButtonBase, a full "
|
|
232
|
+
"path like /Script/CommonUI.CommonButtonBase, or a Widget Blueprint path), or assetPath to read "
|
|
233
|
+
"a Widget Blueprint's contract AND check its own tree against it. Neither was given."));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ── Resolve the class whose contract this is.
|
|
237
|
+
UWidgetBlueprint* WidgetBP = nullptr;
|
|
238
|
+
UClass* ContractClass = nullptr;
|
|
239
|
+
|
|
240
|
+
if (!AssetPath.IsEmpty())
|
|
241
|
+
{
|
|
242
|
+
TSharedPtr<FJsonValue> ResolveError;
|
|
243
|
+
WidgetBP = MCPWidget::ResolveWidgetBlueprintOrError(AssetPath, ResolveError);
|
|
244
|
+
if (!WidgetBP) return ResolveError;
|
|
245
|
+
// The contract is what the PARENT demands. Reading the generated class
|
|
246
|
+
// would also pick up the Blueprint's own widget variables, which are the
|
|
247
|
+
// answer rather than the question.
|
|
248
|
+
ContractClass = WidgetBP->ParentClass;
|
|
249
|
+
if (!ContractClass)
|
|
250
|
+
{
|
|
251
|
+
return MCPError(FString::Printf(
|
|
252
|
+
TEXT("Widget Blueprint '%s' has no parent class, which means the asset is broken."), *AssetPath));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (!ClassName.IsEmpty())
|
|
257
|
+
{
|
|
258
|
+
UClass* Named = WCui_ResolveWidgetClassSpec(ClassName);
|
|
259
|
+
if (!Named)
|
|
260
|
+
{
|
|
261
|
+
return MCPError(FString::Printf(
|
|
262
|
+
TEXT("'%s' does not name a loaded UWidget subclass. Short names of loaded classes resolve, as "
|
|
263
|
+
"does a full path (/Script/CommonUI.CommonButtonBase) or a Widget Blueprint path. List "
|
|
264
|
+
"what this editor has with widget(list_classes). A class from a plugin that is off does "
|
|
265
|
+
"not exist until project(enable_plugin) and an editor restart."), *ClassName));
|
|
266
|
+
}
|
|
267
|
+
ContractClass = Named;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ── Gather the contract, walking up so an inherited requirement is reported
|
|
271
|
+
// with the class that actually declares it.
|
|
272
|
+
TArray<TSharedPtr<FJsonValue>> Requirements;
|
|
273
|
+
int32 RequiredCount = 0;
|
|
274
|
+
int32 OptionalCount = 0;
|
|
275
|
+
|
|
276
|
+
for (TFieldIterator<FProperty> It(ContractClass); It; ++It)
|
|
277
|
+
{
|
|
278
|
+
FProperty* Prop = *It;
|
|
279
|
+
bool bOptional = false;
|
|
280
|
+
bool bAnimation = false;
|
|
281
|
+
if (!WCui_ReadBindKind(Prop, bOptional, bAnimation)) continue;
|
|
282
|
+
|
|
283
|
+
FString ExpectedType;
|
|
284
|
+
if (FObjectPropertyBase* ObjProp = CastField<FObjectPropertyBase>(Prop))
|
|
285
|
+
{
|
|
286
|
+
ExpectedType = ObjProp->PropertyClass ? ObjProp->PropertyClass->GetName() : FString();
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
TSharedPtr<FJsonObject> Entry = MakeShared<FJsonObject>();
|
|
290
|
+
Entry->SetStringField(TEXT("widgetName"), Prop->GetName());
|
|
291
|
+
Entry->SetStringField(TEXT("expectedClass"), ExpectedType);
|
|
292
|
+
Entry->SetStringField(TEXT("declaredBy"),
|
|
293
|
+
Prop->GetOwnerClass() ? Prop->GetOwnerClass()->GetName() : FString());
|
|
294
|
+
Entry->SetBoolField(TEXT("optional"), bOptional);
|
|
295
|
+
Entry->SetStringField(TEXT("kind"), bAnimation ? TEXT("animation") : TEXT("widget"));
|
|
296
|
+
Entry->SetStringField(TEXT("satisfyWith"), bAnimation
|
|
297
|
+
? TEXT("widget(create_animation) with animationName set to widgetName")
|
|
298
|
+
: TEXT("widget(add_widget) with widgetName set to widgetName and widgetClass to expectedClass"));
|
|
299
|
+
|
|
300
|
+
if (bOptional) ++OptionalCount; else ++RequiredCount;
|
|
301
|
+
Requirements.Add(MakeShared<FJsonValueObject>(Entry));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
auto Result = MCPSuccess();
|
|
305
|
+
Result->SetStringField(TEXT("className"), ContractClass->GetName());
|
|
306
|
+
Result->SetStringField(TEXT("classPath"), ContractClass->GetPathName());
|
|
307
|
+
Result->SetArrayField(TEXT("requirements"), Requirements);
|
|
308
|
+
Result->SetNumberField(TEXT("requiredCount"), RequiredCount);
|
|
309
|
+
Result->SetNumberField(TEXT("optionalCount"), OptionalCount);
|
|
310
|
+
|
|
311
|
+
// ── When a Blueprint was named, say which requirements it already meets.
|
|
312
|
+
// A contract with no way to check it against an asset is only half an answer.
|
|
313
|
+
if (WidgetBP)
|
|
314
|
+
{
|
|
315
|
+
TArray<UWidget*> Tree;
|
|
316
|
+
WCui_CollectWidgets(WidgetBP->WidgetTree, Tree);
|
|
317
|
+
|
|
318
|
+
TArray<FString> AnimationNames;
|
|
319
|
+
for (UWidgetAnimation* Anim : WidgetBP->Animations)
|
|
320
|
+
{
|
|
321
|
+
if (Anim) AnimationNames.Add(Anim->GetName());
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
TArray<TSharedPtr<FJsonValue>> Missing;
|
|
325
|
+
TArray<TSharedPtr<FJsonValue>> WrongType;
|
|
326
|
+
int32 Satisfied = 0;
|
|
327
|
+
|
|
328
|
+
for (const TSharedPtr<FJsonValue>& Entry : Requirements)
|
|
329
|
+
{
|
|
330
|
+
const TSharedPtr<FJsonObject>* Obj = nullptr;
|
|
331
|
+
if (!Entry->TryGetObject(Obj) || !Obj) continue;
|
|
332
|
+
FString Name, Expected;
|
|
333
|
+
bool bOptional = false;
|
|
334
|
+
bool bAnimation = false;
|
|
335
|
+
(*Obj)->TryGetStringField(TEXT("widgetName"), Name);
|
|
336
|
+
(*Obj)->TryGetStringField(TEXT("expectedClass"), Expected);
|
|
337
|
+
(*Obj)->TryGetBoolField(TEXT("optional"), bOptional);
|
|
338
|
+
FString Kind;
|
|
339
|
+
(*Obj)->TryGetStringField(TEXT("kind"), Kind);
|
|
340
|
+
bAnimation = Kind == TEXT("animation");
|
|
341
|
+
|
|
342
|
+
if (bAnimation)
|
|
343
|
+
{
|
|
344
|
+
if (AnimationNames.Contains(Name)) { ++Satisfied; continue; }
|
|
345
|
+
if (!bOptional) Missing.Add(MakeShared<FJsonValueObject>(*Obj));
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
UWidget* Found = nullptr;
|
|
350
|
+
for (UWidget* W : Tree)
|
|
351
|
+
{
|
|
352
|
+
if (W->GetName() == Name) { Found = W; break; }
|
|
353
|
+
}
|
|
354
|
+
if (!Found)
|
|
355
|
+
{
|
|
356
|
+
if (!bOptional) Missing.Add(MakeShared<FJsonValueObject>(*Obj));
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// A widget of the right name but the wrong class fails the compile
|
|
361
|
+
// exactly as loudly as a missing one, and is far harder to spot.
|
|
362
|
+
UClass* ExpectedClass = Expected.IsEmpty() ? nullptr : MCPResolveClass(Expected, false);
|
|
363
|
+
if (ExpectedClass && !Found->GetClass()->IsChildOf(ExpectedClass))
|
|
364
|
+
{
|
|
365
|
+
TSharedPtr<FJsonObject> Bad = MakeShared<FJsonObject>();
|
|
366
|
+
Bad->SetStringField(TEXT("widgetName"), Name);
|
|
367
|
+
Bad->SetStringField(TEXT("expectedClass"), Expected);
|
|
368
|
+
Bad->SetStringField(TEXT("actualClass"), Found->GetClass()->GetName());
|
|
369
|
+
Bad->SetBoolField(TEXT("optional"), bOptional);
|
|
370
|
+
WrongType.Add(MakeShared<FJsonValueObject>(Bad));
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
++Satisfied;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
TSharedPtr<FJsonObject> Check = MakeShared<FJsonObject>();
|
|
377
|
+
Check->SetStringField(TEXT("assetPath"), AssetPath);
|
|
378
|
+
Check->SetStringField(TEXT("parentClass"), ContractClass->GetName());
|
|
379
|
+
Check->SetNumberField(TEXT("satisfied"), Satisfied);
|
|
380
|
+
Check->SetArrayField(TEXT("missing"), Missing);
|
|
381
|
+
Check->SetArrayField(TEXT("wrongType"), WrongType);
|
|
382
|
+
Check->SetBoolField(TEXT("compiles"), Missing.Num() == 0 && WrongType.Num() == 0);
|
|
383
|
+
Result->SetObjectField(TEXT("check"), Check);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
Result->SetStringField(TEXT("note"), TEXT(
|
|
387
|
+
"A required entry with no widget of that exact name and a compatible class fails the Widget "
|
|
388
|
+
"Blueprint compile. The name is the property name, matched exactly and case-sensitively."));
|
|
389
|
+
|
|
390
|
+
return MCPResult(Result);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
394
|
+
// audit_commonui
|
|
395
|
+
//
|
|
396
|
+
// The wiring rules that fail silently at runtime instead of loudly at compile.
|
|
397
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
398
|
+
|
|
399
|
+
TSharedPtr<FJsonValue> FWidgetHandlers::AuditCommonUI(const TSharedPtr<FJsonObject>& Params)
|
|
400
|
+
{
|
|
401
|
+
const FString AssetPath = OptionalString(Params, TEXT("assetPath"));
|
|
402
|
+
|
|
403
|
+
TArray<TSharedPtr<FJsonValue>> Problems;
|
|
404
|
+
TArray<TSharedPtr<FJsonValue>> NotChecked;
|
|
405
|
+
TArray<FString> Checked;
|
|
406
|
+
|
|
407
|
+
// ── Rule 1: the plugin itself.
|
|
408
|
+
const bool bPluginLoaded = WCui_PluginLoaded();
|
|
409
|
+
Checked.Add(TEXT("plugin_enabled"));
|
|
410
|
+
if (!bPluginLoaded)
|
|
411
|
+
{
|
|
412
|
+
Problems.Add(WCui_Problem(
|
|
413
|
+
TEXT("plugin_enabled"), TEXT("project"),
|
|
414
|
+
TEXT("The CommonUI plugin is not enabled in this editor, so no CommonUI class exists and no "
|
|
415
|
+
"CommonUI widget can be added or configured."),
|
|
416
|
+
TEXT("project(enable_plugin, pluginName=\"CommonUI\") then editor(restart_editor). Everything "
|
|
417
|
+
"below is unknowable until then.")));
|
|
418
|
+
|
|
419
|
+
auto Early = MCPSuccess();
|
|
420
|
+
Early->SetBoolField(TEXT("pluginEnabled"), false);
|
|
421
|
+
Early->SetArrayField(TEXT("problems"), Problems);
|
|
422
|
+
Early->SetNumberField(TEXT("problemCount"), Problems.Num());
|
|
423
|
+
Early->SetArrayField(TEXT("checked"), MCPStringListToJson(Checked));
|
|
424
|
+
Early->SetArrayField(TEXT("notChecked"), NotChecked);
|
|
425
|
+
return MCPResult(Early);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ── Rule 2: the game viewport client.
|
|
429
|
+
// CommonUI routes input to the UI before the game through its own viewport
|
|
430
|
+
// client. With the engine default in place, gamepad navigation and the Back
|
|
431
|
+
// action do nothing, and nothing anywhere reports why.
|
|
432
|
+
Checked.Add(TEXT("game_viewport_client"));
|
|
433
|
+
UClass* CommonViewport = WCui_CommonClass(TEXT("CommonUI"), TEXT("CommonGameViewportClient"));
|
|
434
|
+
if (!CommonViewport)
|
|
435
|
+
{
|
|
436
|
+
NotChecked.Add(WCui_Note(TEXT("game_viewport_client"),
|
|
437
|
+
TEXT("UCommonGameViewportClient is not loaded even though the plugin is enabled.")));
|
|
438
|
+
}
|
|
439
|
+
else if (GEngine)
|
|
440
|
+
{
|
|
441
|
+
UClass* Current = GEngine->GameViewportClientClass;
|
|
442
|
+
if (!Current || !Current->IsChildOf(CommonViewport))
|
|
443
|
+
{
|
|
444
|
+
Problems.Add(WCui_Problem(
|
|
445
|
+
TEXT("game_viewport_client"), TEXT("project"),
|
|
446
|
+
FString::Printf(
|
|
447
|
+
TEXT("GameViewportClientClass is %s, which is not a CommonGameViewportClient. CommonUI "
|
|
448
|
+
"input routing, the Back action and gamepad navigation are inactive."),
|
|
449
|
+
Current ? *Current->GetName() : TEXT("unset")),
|
|
450
|
+
TEXT("project(set_config, configName=\"Engine\", section=\"/Script/Engine.Engine\", "
|
|
451
|
+
"key=\"GameViewportClientClassName\", "
|
|
452
|
+
"value=\"/Script/CommonUI.CommonGameViewportClient\") then restart the editor.")));
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
else
|
|
456
|
+
{
|
|
457
|
+
NotChecked.Add(WCui_Note(TEXT("game_viewport_client"), TEXT("GEngine is not available.")));
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// ── Rule 3: the input action data.
|
|
461
|
+
// Without it, every CommonUI input action resolves to nothing, so bound
|
|
462
|
+
// action bars come up empty and Back is unhandled.
|
|
463
|
+
Checked.Add(TEXT("input_action_data"));
|
|
464
|
+
UClass* InputSettingsClass = WCui_CommonClass(TEXT("CommonInput"), TEXT("CommonInputSettings"));
|
|
465
|
+
if (!InputSettingsClass)
|
|
466
|
+
{
|
|
467
|
+
NotChecked.Add(WCui_Note(TEXT("input_action_data"),
|
|
468
|
+
TEXT("UCommonInputSettings is not loaded, so the project's CommonUI input data cannot be read.")));
|
|
469
|
+
}
|
|
470
|
+
else
|
|
471
|
+
{
|
|
472
|
+
UObject* SettingsCDO = InputSettingsClass->GetDefaultObject();
|
|
473
|
+
FSoftObjectProperty* InputData =
|
|
474
|
+
FindFProperty<FSoftObjectProperty>(InputSettingsClass, TEXT("InputData"));
|
|
475
|
+
if (!SettingsCDO || !InputData)
|
|
476
|
+
{
|
|
477
|
+
NotChecked.Add(WCui_Note(TEXT("input_action_data"),
|
|
478
|
+
TEXT("UCommonInputSettings has no InputData property in this engine version.")));
|
|
479
|
+
}
|
|
480
|
+
else
|
|
481
|
+
{
|
|
482
|
+
const FSoftObjectPtr* Value = InputData->ContainerPtrToValuePtr<FSoftObjectPtr>(SettingsCDO);
|
|
483
|
+
if (!Value || Value->IsNull())
|
|
484
|
+
{
|
|
485
|
+
Problems.Add(WCui_Problem(
|
|
486
|
+
TEXT("input_action_data"), TEXT("project"),
|
|
487
|
+
TEXT("CommonInputSettings.InputData is unset, so no CommonUI input action resolves. "
|
|
488
|
+
"Bound action bars render empty and the Back action is never handled."),
|
|
489
|
+
TEXT("Create a UCommonUIInputData subclass with blueprint(create), then "
|
|
490
|
+
"project(set_config, configName=\"Game\", "
|
|
491
|
+
"section=\"/Script/CommonInput.CommonInputSettings\", key=\"InputData\", "
|
|
492
|
+
"value=\"<the class path>\").")));
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// ── Per-asset rules. Everything above is about the project; these are about
|
|
498
|
+
// one widget tree, and they only run when a caller names one.
|
|
499
|
+
if (AssetPath.IsEmpty())
|
|
500
|
+
{
|
|
501
|
+
NotChecked.Add(WCui_Note(TEXT("widget_tree"),
|
|
502
|
+
TEXT("No assetPath was given, so the per-widget rules (activatable focus target, bound action "
|
|
503
|
+
"bar button class, unstyled CommonUI widgets) did not run. Pass assetPath to include them.")));
|
|
504
|
+
}
|
|
505
|
+
else
|
|
506
|
+
{
|
|
507
|
+
TSharedPtr<FJsonValue> ResolveError;
|
|
508
|
+
UWidgetBlueprint* WidgetBP = MCPWidget::ResolveWidgetBlueprintOrError(AssetPath, ResolveError);
|
|
509
|
+
if (!WidgetBP) return ResolveError;
|
|
510
|
+
if (!WidgetBP->WidgetTree) return MCPWidget::MissingWidgetTreeError(AssetPath);
|
|
511
|
+
|
|
512
|
+
// Rule 4: an activatable widget with nothing to focus. On gamepad,
|
|
513
|
+
// activating it leaves focus wherever it was, which reads as the UI
|
|
514
|
+
// being dead rather than as a missing setting.
|
|
515
|
+
Checked.Add(TEXT("activatable_focus_target"));
|
|
516
|
+
UClass* ActivatableClass = WCui_CommonClass(TEXT("CommonUI"), TEXT("CommonActivatableWidget"));
|
|
517
|
+
if (ActivatableClass && WidgetBP->ParentClass && WidgetBP->ParentClass->IsChildOf(ActivatableClass))
|
|
518
|
+
{
|
|
519
|
+
UClass* GeneratedClass = WidgetBP->GeneratedClass;
|
|
520
|
+
UObject* CDO = GeneratedClass ? GeneratedClass->GetDefaultObject() : nullptr;
|
|
521
|
+
FStructProperty* FocusProp = CDO
|
|
522
|
+
? FindFProperty<FStructProperty>(CDO->GetClass(), TEXT("DesiredFocusWidget"))
|
|
523
|
+
: nullptr;
|
|
524
|
+
if (!CDO || !FocusProp)
|
|
525
|
+
{
|
|
526
|
+
NotChecked.Add(WCui_Note(TEXT("activatable_focus_target"),
|
|
527
|
+
TEXT("DesiredFocusWidget is not a property of UUserWidget in this engine version.")));
|
|
528
|
+
}
|
|
529
|
+
else
|
|
530
|
+
{
|
|
531
|
+
const void* FocusValue = FocusProp->ContainerPtrToValuePtr<void>(CDO);
|
|
532
|
+
FNameProperty* NameProp =
|
|
533
|
+
FindFProperty<FNameProperty>(FocusProp->Struct, TEXT("WidgetName"));
|
|
534
|
+
const FName FocusName = NameProp
|
|
535
|
+
? NameProp->GetPropertyValue_InContainer(FocusValue)
|
|
536
|
+
: NAME_None;
|
|
537
|
+
if (FocusName.IsNone())
|
|
538
|
+
{
|
|
539
|
+
Problems.Add(WCui_Problem(
|
|
540
|
+
TEXT("activatable_focus_target"), AssetPath,
|
|
541
|
+
TEXT("This is a CommonActivatableWidget with no DesiredFocusWidget, so activating it "
|
|
542
|
+
"on a gamepad hands focus to nothing and the screen appears unresponsive."),
|
|
543
|
+
TEXT("asset(set_property, assetPath=<this asset>, "
|
|
544
|
+
"propertyName=\"DesiredFocusWidget.WidgetName\", value=<a focusable widget "
|
|
545
|
+
"name from widget(read_tree)>).")));
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Rules 5 and 6 walk the tree once.
|
|
551
|
+
Checked.Add(TEXT("bound_action_bar_button_class"));
|
|
552
|
+
Checked.Add(TEXT("commonui_widget_style"));
|
|
553
|
+
UClass* ActionBarClass = WCui_CommonClass(TEXT("CommonUI"), TEXT("CommonBoundActionBar"));
|
|
554
|
+
|
|
555
|
+
// Every CommonUI widget whose look comes entirely from a Style class:
|
|
556
|
+
// unset, they render as nothing at all, which looks like a layout bug.
|
|
557
|
+
struct FStyled { const TCHAR* ClassName; const TCHAR* PropertyName; };
|
|
558
|
+
static const FStyled StyledClasses[] = {
|
|
559
|
+
{ TEXT("CommonButtonBase"), TEXT("Style") },
|
|
560
|
+
{ TEXT("CommonBorder"), TEXT("Style") },
|
|
561
|
+
{ TEXT("CommonTextBlock"), TEXT("Style") },
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
TArray<UWidget*> Tree;
|
|
565
|
+
WCui_CollectWidgets(WidgetBP->WidgetTree, Tree);
|
|
566
|
+
for (UWidget* Widget : Tree)
|
|
567
|
+
{
|
|
568
|
+
if (ActionBarClass && Widget->IsA(ActionBarClass)
|
|
569
|
+
&& WCui_ClassPropertyIsUnset(Widget, TEXT("ActionButtonClass")))
|
|
570
|
+
{
|
|
571
|
+
Problems.Add(WCui_Problem(
|
|
572
|
+
TEXT("bound_action_bar_button_class"), FString::Printf(TEXT("%s.%s"), *AssetPath, *Widget->GetName()),
|
|
573
|
+
TEXT("CommonBoundActionBar has no ActionButtonClass, so it has nothing to build its "
|
|
574
|
+
"entries from and renders empty however many actions are bound."),
|
|
575
|
+
FString::Printf(TEXT("widget(set_property, assetPath=%s, widgetName=%s, "
|
|
576
|
+
"propertyName=\"ActionButtonClass\", value=<a CommonButtonBase subclass that "
|
|
577
|
+
"implements CommonBoundActionButtonInterface>)."), *AssetPath, *Widget->GetName())));
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
for (const FStyled& Styled : StyledClasses)
|
|
581
|
+
{
|
|
582
|
+
UClass* StyledClass = WCui_CommonClass(TEXT("CommonUI"), Styled.ClassName);
|
|
583
|
+
if (!StyledClass || !Widget->IsA(StyledClass)) continue;
|
|
584
|
+
if (!WCui_ClassPropertyIsUnset(Widget, Styled.PropertyName)) continue;
|
|
585
|
+
Problems.Add(WCui_Problem(
|
|
586
|
+
TEXT("commonui_widget_style"), FString::Printf(TEXT("%s.%s"), *AssetPath, *Widget->GetName()),
|
|
587
|
+
FString::Printf(
|
|
588
|
+
TEXT("%s '%s' has no %s set. A CommonUI widget draws entirely from its style class, "
|
|
589
|
+
"so with none it renders as nothing and reads as a layout fault."),
|
|
590
|
+
Styled.ClassName, *Widget->GetName(), Styled.PropertyName),
|
|
591
|
+
FString::Printf(TEXT("widget(set_property, assetPath=%s, widgetName=%s, "
|
|
592
|
+
"propertyName=\"%s\", value=<a style asset path>). Create one with "
|
|
593
|
+
"blueprint(create) on the matching Common*Style parent class."),
|
|
594
|
+
*AssetPath, *Widget->GetName(), Styled.PropertyName)));
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
auto Result = MCPSuccess();
|
|
600
|
+
Result->SetBoolField(TEXT("pluginEnabled"), true);
|
|
601
|
+
if (!AssetPath.IsEmpty()) Result->SetStringField(TEXT("assetPath"), AssetPath);
|
|
602
|
+
Result->SetArrayField(TEXT("problems"), Problems);
|
|
603
|
+
Result->SetNumberField(TEXT("problemCount"), Problems.Num());
|
|
604
|
+
Result->SetArrayField(TEXT("checked"), MCPStringListToJson(Checked));
|
|
605
|
+
Result->SetArrayField(TEXT("notChecked"), NotChecked);
|
|
606
|
+
Result->SetStringField(TEXT("note"), TEXT(
|
|
607
|
+
"Every rule here fails silently at runtime rather than at compile time, which is why they are "
|
|
608
|
+
"worth a report. Authored values only: this reads the asset and the project settings, not a "
|
|
609
|
+
"running game."));
|
|
610
|
+
|
|
611
|
+
return MCPResult(Result);
|
|
612
|
+
}
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers_Extraction.cpp
CHANGED
|
@@ -510,22 +510,24 @@ TSharedPtr<FJsonValue> FWidgetHandlers::ExtractWidgetSubtree(const TSharedPtr<FJ
|
|
|
510
510
|
++CopiedBindings;
|
|
511
511
|
}
|
|
512
512
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
//
|
|
516
|
-
|
|
517
|
-
|
|
513
|
+
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Destination);
|
|
514
|
+
|
|
515
|
+
// WidgetVariableNameToGuidMap keeps external references stable when a widget
|
|
516
|
+
// variable is later renamed, and the compiler reports a failure for any
|
|
517
|
+
// widget variable it generates without an entry (#728). The entries are
|
|
518
|
+
// written off the widgets the destination tree actually owns rather than off
|
|
519
|
+
// the plan, because the importer renames a widget whose name was already
|
|
520
|
+
// taken while the plan still holds the name that was asked for.
|
|
521
|
+
const MCPWidgetGuidMap::FSyncReport GuidSync = MCPWidgetGuidMap::CompileChecked(Destination);
|
|
522
|
+
if (!GuidSync.bCompiled)
|
|
518
523
|
{
|
|
519
|
-
|
|
520
|
-
if (!Destination->WidgetVariableNameToGuidMap.Contains(WidgetName))
|
|
524
|
+
if (bCreatedDestination)
|
|
521
525
|
{
|
|
522
|
-
|
|
526
|
+
UEditorAssetLibrary::DeleteAsset(DestinationAssetPath);
|
|
523
527
|
}
|
|
528
|
+
return MCPWidgetGuidMap::BlockedError(DestinationAssetPath, GuidSync);
|
|
524
529
|
}
|
|
525
|
-
#endif
|
|
526
530
|
|
|
527
|
-
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Destination);
|
|
528
|
-
FKismetEditorUtilities::CompileBlueprint(Destination);
|
|
529
531
|
if (Destination->Status == BS_Error)
|
|
530
532
|
{
|
|
531
533
|
if (bCreatedDestination)
|
|
@@ -561,5 +563,6 @@ TSharedPtr<FJsonValue> FWidgetHandlers::ExtractWidgetSubtree(const TSharedPtr<FJ
|
|
|
561
563
|
Result->SetBoolField(TEXT("sourcePackageDirtyBefore"), bSourceDirtyBefore);
|
|
562
564
|
Result->SetBoolField(TEXT("sourcePackageDirtyAfter"), Source->GetOutermost()->IsDirty());
|
|
563
565
|
Result->SetBoolField(TEXT("sourceUnchanged"), bSourceDirtyBefore == Source->GetOutermost()->IsDirty());
|
|
566
|
+
MCPSetWidgetGuidOutcome(Result, GuidSync, Destination->GetPathName());
|
|
564
567
|
return MCPResult(Result);
|
|
565
568
|
}
|