From 46ea58423b2de6da19b0a236f086629de29b1549 Mon Sep 17 00:00:00 2001 From: jyelon Date: Mon, 16 Mar 2026 04:56:25 -0400 Subject: [PATCH] Urgh --- Content/Testing/BP_VarTest2.uasset | 4 +- .../Source/BlueprintMCP/BlueprintMCP.Build.cs | 3 +- .../Handlers/GraphNode_ShowMenu.h | 104 ++++++++++++++++++ .../BlueprintMCP/Private/BPVarEditor.cpp | 12 +- 4 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/GraphNode_ShowMenu.h diff --git a/Content/Testing/BP_VarTest2.uasset b/Content/Testing/BP_VarTest2.uasset index 09917adf..69c94f48 100644 --- a/Content/Testing/BP_VarTest2.uasset +++ b/Content/Testing/BP_VarTest2.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:769d8a49cd6d6bce7daba5a3cabd0bf9bc39469c6534dfbda1ac1baecf3df261 -size 25017 +oid sha256:a426feb7372347c28c835a840f6b890468baa0a272ab022a7efefbb2ecc0d529 +size 49393 diff --git a/Plugins/BlueprintMCP/Source/BlueprintMCP/BlueprintMCP.Build.cs b/Plugins/BlueprintMCP/Source/BlueprintMCP/BlueprintMCP.Build.cs index f8a62504..1712e577 100644 --- a/Plugins/BlueprintMCP/Source/BlueprintMCP/BlueprintMCP.Build.cs +++ b/Plugins/BlueprintMCP/Source/BlueprintMCP/BlueprintMCP.Build.cs @@ -31,7 +31,8 @@ public class BlueprintMCP : ModuleRules "AnimGraphRuntime", "RHI", "Slate", - "SlateCore" + "SlateCore", + "ToolMenus" }); } } diff --git a/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/GraphNode_ShowMenu.h b/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/GraphNode_ShowMenu.h new file mode 100644 index 00000000..709a4a12 --- /dev/null +++ b/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/GraphNode_ShowMenu.h @@ -0,0 +1,104 @@ +#pragma once + +#include "CoreMinimal.h" +#include "MCPHandler.h" +#include "MCPFetcher.h" +#include "MCPUtils.h" +#include "MCPServer.h" +#include "EdGraph/EdGraphNode.h" +#include "EdGraph/EdGraphSchema.h" +#include "ToolMenus.h" +#include "GraphNode_ShowMenu.generated.h" + + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +UCLASS() +class UMCP_GraphNode_ShowMenu : public UObject, public IMCPHandler +{ + GENERATED_BODY() + +public: + UPROPERTY(meta=(Description="Target node")) + FString Node; + + virtual FString GetDescription() const override + { + return TEXT("Show context menu actions available for a node and its pins."); + } + + virtual void Handle() override + { + MCPFetcher F; + UEdGraphNode* FoundNode = F.Walk(Node).Cast(); + if (!FoundNode) return; + + UEdGraph* Graph = FoundNode->GetGraph(); + if (!Graph) return; + + const UEdGraphSchema* Schema = Graph->GetSchema(); + if (!Schema) return; + + // Print actions for the node itself (no pin). + PrintActions(FoundNode, Graph, Schema, nullptr); + + // Print actions for each pin. + for (UEdGraphPin* Pin : FoundNode->Pins) + { + PrintActions(FoundNode, Graph, Schema, Pin); + } + } + +private: + + void PrintMenu(UToolMenu* Menu, const TCHAR* Header) + { + bool bAnyEntries = false; + for (const FToolMenuSection& Section : Menu->Sections) + { + for (const FToolMenuEntry& Entry : Section.Blocks) + { + FText Label = Entry.Label.Get(); + if (Label.IsEmpty()) + continue; + + // Check if this is a command-based entry or a direct action. + TSharedPtr OutCommandList; + bool bIsCommand = (Entry.GetActionForCommand(FToolMenuContext(), OutCommandList) != nullptr) + || OutCommandList.IsValid(); + + if (!bAnyEntries) + UMCPServer::Printf(TEXT(" %s:\n"), Header); + if (bIsCommand) + UMCPServer::Printf(TEXT(" %s (command)\n"), *Label.ToString()); + else + UMCPServer::Printf(TEXT(" %s\n"), *Label.ToString()); + bAnyEntries = true; + } + } + } + + void PrintActions(UEdGraphNode* FoundNode, UEdGraph* Graph, const UEdGraphSchema* Schema, const UEdGraphPin* Pin) + { + UGraphNodeContextMenuContext* Context = NewObject(); + Context->Init(Graph, FoundNode, Pin, false); + + // Print header. + if (Pin) + UMCPServer::Printf(TEXT("\nPin: %s\n"), *MCPUtils::FormatName(Pin)); + else + UMCPServer::Printf(TEXT("Node: %s\n"), *MCPUtils::FormatName(FoundNode)); + + // Gather and print node-level actions. + UToolMenu* NodeMenu = NewObject(); + FoundNode->GetNodeContextMenuActions(NodeMenu, Context); + PrintMenu(NodeMenu, TEXT("Node Actions")); + + // Gather and print schema-level actions. + UToolMenu* SchemaMenu = NewObject(); + Schema->GetContextMenuActions(SchemaMenu, Context); + PrintMenu(SchemaMenu, TEXT("Schema Actions")); + } +}; diff --git a/Plugins/BlueprintMCP/Source/BlueprintMCP/Private/BPVarEditor.cpp b/Plugins/BlueprintMCP/Source/BlueprintMCP/Private/BPVarEditor.cpp index 50edf71f..76ef8ac6 100644 --- a/Plugins/BlueprintMCP/Source/BlueprintMCP/Private/BPVarEditor.cpp +++ b/Plugins/BlueprintMCP/Source/BlueprintMCP/Private/BPVarEditor.cpp @@ -43,8 +43,18 @@ void FBPVarEditor::Dump() bool FBPVarEditor::ApplyJson(const FJsonObject* Json) { - LoadFlags(); bool bHasDefault = Json->HasField(TEXT("DefaultValue")); + bool bHasType = Json->HasField(TEXT("VarType")); + if (bHasDefault && bHasType) + { + UMCPServer::Print(TEXT( + "ERROR: Cannot set VarType and DefaultValue in the same call.\n" + "Change the type first, then recompile the blueprint,\n" + "then set the default.\n")); + return false; + } + + LoadFlags(); TArray Props = MergedProperties(); if (!MCPJson::PopulateFromJson(Props, Json, true))