Files
integration/Plugins/BlueprintMCP/Source/BlueprintMCP/Private/Handlers/UMCPHandler_DisconnectBlueprintPins.h
2026-03-08 22:17:14 -04:00

145 lines
4.1 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "Engine/World.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_DisconnectBlueprintPins.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
USTRUCT()
struct FDisconnectPinEntry
{
GENERATED_BODY()
UPROPERTY()
FString Node;
UPROPERTY()
FString PinName;
UPROPERTY(meta=(Optional))
FString TargetNode;
UPROPERTY(meta=(Optional))
FString TargetPinName;
};
UCLASS()
class UMCPHandler_DisconnectBlueprintPins : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Blueprint name or package path"))
FString Blueprint;
UPROPERTY(meta=(Description="Array of {node, pinName, targetNode?, targetPinName?} objects. If target is omitted, all connections on the pin are broken."))
FMCPJsonArray Disconnections;
virtual FString GetDescription() const override
{
return TEXT("Disconnect pins in a Blueprint graph. "
"Can disconnect a specific link or all links on a pin.");
}
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
{
MCPAssets<UBlueprint> Assets;
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
UBlueprint* BP = Assets.Object();
TArray<TSharedPtr<FJsonValue>> Results;
int32 SuccessCount = 0;
int32 TotalDisconnected = 0;
for (const TSharedPtr<FJsonValue>& DiscVal : Disconnections.Array)
{
TSharedRef<FJsonObject> EntryResult = MakeShared<FJsonObject>();
Results.Add(MakeShared<FJsonValueObject>(EntryResult));
FDisconnectPinEntry Entry;
if (!MCPUtils::PopulateFromJson(FDisconnectPinEntry::StaticStruct(), &Entry, DiscVal, &*EntryResult)) continue;
UEdGraphNode* Node = MCPUtils::FindNodeByGuid(BP, Entry.Node);
if (!Node)
{
EntryResult->SetStringField(TEXT("error"), FString::Printf(TEXT("Node '%s' not found"), *Entry.Node));
continue;
}
UEdGraphPin* Pin = Node->FindPin(FName(*Entry.PinName));
if (!Pin)
{
EntryResult->SetStringField(TEXT("error"), FString::Printf(TEXT("Pin '%s' not found on node '%s'"), *Entry.PinName, *Entry.Node));
continue;
}
int32 DisconnectedCount = 0;
if (!Entry.TargetNode.IsEmpty() && !Entry.TargetPinName.IsEmpty())
{
UEdGraphNode* TargetNode = MCPUtils::FindNodeByGuid(BP, Entry.TargetNode);
if (!TargetNode)
{
EntryResult->SetStringField(TEXT("error"), FString::Printf(TEXT("Target node '%s' not found"), *Entry.TargetNode));
continue;
}
UEdGraphPin* TargetPin = TargetNode->FindPin(FName(*Entry.TargetPinName));
if (!TargetPin)
{
EntryResult->SetStringField(TEXT("error"), FString::Printf(TEXT("Target pin '%s' not found on node '%s'"), *Entry.TargetPinName, *Entry.TargetNode));
continue;
}
if (!Pin->LinkedTo.Contains(TargetPin))
{
EntryResult->SetStringField(TEXT("error"), TEXT("The specified pins are not connected to each other"));
continue;
}
Pin->BreakLinkTo(TargetPin);
DisconnectedCount = 1;
}
else
{
DisconnectedCount = Pin->LinkedTo.Num();
if (DisconnectedCount > 0)
{
Pin->BreakAllPinLinks(true);
}
}
EntryResult->SetNumberField(TEXT("disconnectedCount"), DisconnectedCount);
SuccessCount++;
TotalDisconnected += DisconnectedCount;
}
if (TotalDisconnected > 0)
{
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
}
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: DisconnectPin — %d/%d succeeded, %d links broken in '%s'"),
SuccessCount, Disconnections.Array.Num(), TotalDisconnected, *Blueprint);
Result->SetNumberField(TEXT("successCount"), SuccessCount);
Result->SetNumberField(TEXT("totalCount"), Disconnections.Array.Num());
Result->SetNumberField(TEXT("totalDisconnected"), TotalDisconnected);
Result->SetArrayField(TEXT("results"), Results);
}
};