Ported a few MCP handlers to the new registration system
This commit is contained in:
@@ -1,55 +1,36 @@
|
|||||||
|
#include "BlueprintMCPHandlers_DiffBlueprints.h"
|
||||||
#include "BlueprintMCPServer.h"
|
#include "BlueprintMCPServer.h"
|
||||||
#include "Engine/Blueprint.h"
|
#include "Engine/Blueprint.h"
|
||||||
#include "EdGraph/EdGraph.h"
|
#include "EdGraph/EdGraph.h"
|
||||||
#include "EdGraph/EdGraphNode.h"
|
#include "EdGraph/EdGraphNode.h"
|
||||||
#include "EdGraph/EdGraphPin.h"
|
#include "EdGraph/EdGraphPin.h"
|
||||||
#include "K2Node_BreakStruct.h"
|
|
||||||
#include "K2Node_MakeStruct.h"
|
|
||||||
#include "K2Node_CallFunction.h"
|
|
||||||
#include "K2Node_VariableGet.h"
|
|
||||||
#include "K2Node_VariableSet.h"
|
|
||||||
#include "Kismet2/BlueprintEditorUtils.h"
|
|
||||||
#include "Serialization/JsonReader.h"
|
|
||||||
#include "Serialization/JsonWriter.h"
|
|
||||||
#include "Serialization/JsonSerializer.h"
|
|
||||||
|
|
||||||
// ============================================================
|
void UMCPHandler_DiffBlueprints::Handle(const FJsonObject* Json, FJsonObject* Result)
|
||||||
// HandleDiffBlueprints — structural diff between two Blueprints
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
void FBlueprintMCPServer::HandleDiffBlueprints(const FJsonObject* Json, FJsonObject* Result)
|
|
||||||
{
|
{
|
||||||
FString BlueprintA = Json->GetStringField(TEXT("blueprintA"));
|
MCPHelper* Helper = MCPHelper::Get();
|
||||||
FString BlueprintB = Json->GetStringField(TEXT("blueprintB"));
|
|
||||||
FString GraphFilter = Json->GetStringField(TEXT("graph"));
|
|
||||||
|
|
||||||
if (BlueprintA.IsEmpty() || BlueprintB.IsEmpty())
|
|
||||||
{
|
|
||||||
return MakeErrorJson(Result, TEXT("Missing required fields: blueprintA, blueprintB"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load both blueprints
|
// Load both blueprints
|
||||||
FString LoadErrorA, LoadErrorB;
|
FString LoadErrorA, LoadErrorB;
|
||||||
UBlueprint* BPA = LoadBlueprintByName(BlueprintA, LoadErrorA);
|
UBlueprint* BPA = Helper->LoadBlueprintByName(BlueprintA, LoadErrorA);
|
||||||
if (!BPA) { MakeErrorJson(Result, FString::Printf(TEXT("blueprintA: %s"), *LoadErrorA)); return; }
|
if (!BPA) { Helper->MakeErrorJson(Result, FString::Printf(TEXT("blueprintA: %s"), *LoadErrorA)); return; }
|
||||||
|
|
||||||
UBlueprint* BPB = LoadBlueprintByName(BlueprintB, LoadErrorB);
|
UBlueprint* BPB = Helper->LoadBlueprintByName(BlueprintB, LoadErrorB);
|
||||||
if (!BPB) { MakeErrorJson(Result, FString::Printf(TEXT("blueprintB: %s"), *LoadErrorB)); return; }
|
if (!BPB) { Helper->MakeErrorJson(Result, FString::Printf(TEXT("blueprintB: %s"), *LoadErrorB)); return; }
|
||||||
|
|
||||||
// Helper to gather graphs from a Blueprint
|
// Helper to gather graphs from a Blueprint
|
||||||
auto GatherGraphs = [&GraphFilter](UBlueprint* BP) -> TArray<UEdGraph*>
|
auto GatherGraphs = [this](UBlueprint* BP) -> TArray<UEdGraph*>
|
||||||
{
|
{
|
||||||
TArray<UEdGraph*> Graphs;
|
TArray<UEdGraph*> Graphs;
|
||||||
for (UEdGraph* G : BP->UbergraphPages)
|
for (UEdGraph* G : BP->UbergraphPages)
|
||||||
{
|
{
|
||||||
if (!G) continue;
|
if (!G) continue;
|
||||||
if (!GraphFilter.IsEmpty() && G->GetName() != GraphFilter) continue;
|
if (!Graph.IsEmpty() && (G->GetName() != Graph)) continue;
|
||||||
Graphs.Add(G);
|
Graphs.Add(G);
|
||||||
}
|
}
|
||||||
for (UEdGraph* G : BP->FunctionGraphs)
|
for (UEdGraph* G : BP->FunctionGraphs)
|
||||||
{
|
{
|
||||||
if (!G) continue;
|
if (!G) continue;
|
||||||
if (!GraphFilter.IsEmpty() && G->GetName() != GraphFilter) continue;
|
if (!Graph.IsEmpty() && (G->GetName() != Graph)) continue;
|
||||||
Graphs.Add(G);
|
Graphs.Add(G);
|
||||||
}
|
}
|
||||||
return Graphs;
|
return Graphs;
|
||||||
@@ -167,7 +148,7 @@ void FBlueprintMCPServer::HandleDiffBlueprints(const FJsonObject* Json, FJsonObj
|
|||||||
if (!N) continue;
|
if (!N) continue;
|
||||||
for (UEdGraphPin* Pin : N->Pins)
|
for (UEdGraphPin* Pin : N->Pins)
|
||||||
{
|
{
|
||||||
if (!Pin || Pin->Direction != EGPD_Output) continue;
|
if (!Pin || (Pin->Direction != EGPD_Output)) continue;
|
||||||
for (UEdGraphPin* Linked : Pin->LinkedTo)
|
for (UEdGraphPin* Linked : Pin->LinkedTo)
|
||||||
{
|
{
|
||||||
if (!Linked || !Linked->GetOwningNode()) continue;
|
if (!Linked || !Linked->GetOwningNode()) continue;
|
||||||
@@ -180,7 +161,7 @@ void FBlueprintMCPServer::HandleDiffBlueprints(const FJsonObject* Json, FJsonObj
|
|||||||
if (!N) continue;
|
if (!N) continue;
|
||||||
for (UEdGraphPin* Pin : N->Pins)
|
for (UEdGraphPin* Pin : N->Pins)
|
||||||
{
|
{
|
||||||
if (!Pin || Pin->Direction != EGPD_Output) continue;
|
if (!Pin || (Pin->Direction != EGPD_Output)) continue;
|
||||||
for (UEdGraphPin* Linked : Pin->LinkedTo)
|
for (UEdGraphPin* Linked : Pin->LinkedTo)
|
||||||
{
|
{
|
||||||
if (!Linked || !Linked->GetOwningNode()) continue;
|
if (!Linked || !Linked->GetOwningNode()) continue;
|
||||||
@@ -205,7 +186,7 @@ void FBlueprintMCPServer::HandleDiffBlueprints(const FJsonObject* Json, FJsonObj
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bIdentical = OnlyInA.Num() == 0 && OnlyInB.Num() == 0 && ConnsOnlyInA.Num() == 0 && ConnsOnlyInB.Num() == 0;
|
bool bIdentical = (OnlyInA.Num() == 0) && (OnlyInB.Num() == 0) && (ConnsOnlyInA.Num() == 0) && (ConnsOnlyInB.Num() == 0);
|
||||||
GD->SetStringField(TEXT("status"), bIdentical ? TEXT("identical") : TEXT("different"));
|
GD->SetStringField(TEXT("status"), bIdentical ? TEXT("identical") : TEXT("different"));
|
||||||
GD->SetNumberField(TEXT("nodeCountA"), GA->Nodes.Num());
|
GD->SetNumberField(TEXT("nodeCountA"), GA->Nodes.Num());
|
||||||
GD->SetNumberField(TEXT("nodeCountB"), GB->Nodes.Num());
|
GD->SetNumberField(TEXT("nodeCountB"), GB->Nodes.Num());
|
||||||
|
|||||||
@@ -1,30 +1,23 @@
|
|||||||
|
#include "BlueprintMCPHandlers_Interfaces.h"
|
||||||
#include "BlueprintMCPServer.h"
|
#include "BlueprintMCPServer.h"
|
||||||
#include "Engine/Blueprint.h"
|
#include "Engine/Blueprint.h"
|
||||||
#include "EdGraph/EdGraph.h"
|
#include "EdGraph/EdGraph.h"
|
||||||
#include "Kismet2/BlueprintEditorUtils.h"
|
#include "Kismet2/BlueprintEditorUtils.h"
|
||||||
#include "Kismet2/KismetEditorUtilities.h"
|
|
||||||
#include "Serialization/JsonReader.h"
|
|
||||||
#include "Serialization/JsonWriter.h"
|
|
||||||
#include "Serialization/JsonSerializer.h"
|
|
||||||
#include "UObject/UObjectIterator.h"
|
#include "UObject/UObjectIterator.h"
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// HandleListInterfaces — list implemented interfaces on a Blueprint
|
// ListInterfaces
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
void FBlueprintMCPServer::HandleListInterfaces(const FJsonObject* Json, FJsonObject* Result)
|
void UMCPHandler_ListInterfaces::Handle(const FJsonObject* Json, FJsonObject* Result)
|
||||||
{
|
{
|
||||||
FString BlueprintName = Json->GetStringField(TEXT("blueprint"));
|
MCPHelper* Helper = MCPHelper::Get();
|
||||||
if (BlueprintName.IsEmpty())
|
|
||||||
{
|
|
||||||
return MakeErrorJson(Result, TEXT("Missing required field: blueprint"));
|
|
||||||
}
|
|
||||||
|
|
||||||
FString LoadError;
|
FString LoadError;
|
||||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
UBlueprint* BP = Helper->LoadBlueprintByName(Blueprint, LoadError);
|
||||||
if (!BP)
|
if (!BP)
|
||||||
{
|
{
|
||||||
return MakeErrorJson(Result, LoadError);
|
return Helper->MakeErrorJson(Result, LoadError);
|
||||||
}
|
}
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> InterfacesArr;
|
TArray<TSharedPtr<FJsonValue>> InterfacesArr;
|
||||||
@@ -39,7 +32,6 @@ void FBlueprintMCPServer::HandleListInterfaces(const FJsonObject* Json, FJsonObj
|
|||||||
IfaceObj->SetStringField(TEXT("name"), IfaceDesc.Interface->GetName());
|
IfaceObj->SetStringField(TEXT("name"), IfaceDesc.Interface->GetName());
|
||||||
IfaceObj->SetStringField(TEXT("classPath"), IfaceDesc.Interface->GetPathName());
|
IfaceObj->SetStringField(TEXT("classPath"), IfaceDesc.Interface->GetPathName());
|
||||||
|
|
||||||
// Collect function graph names from the interface
|
|
||||||
TArray<TSharedPtr<FJsonValue>> FuncArr;
|
TArray<TSharedPtr<FJsonValue>> FuncArr;
|
||||||
for (const UEdGraph* Graph : IfaceDesc.Graphs)
|
for (const UEdGraph* Graph : IfaceDesc.Graphs)
|
||||||
{
|
{
|
||||||
@@ -53,30 +45,24 @@ void FBlueprintMCPServer::HandleListInterfaces(const FJsonObject* Json, FJsonObj
|
|||||||
InterfacesArr.Add(MakeShared<FJsonValueObject>(IfaceObj));
|
InterfacesArr.Add(MakeShared<FJsonValueObject>(IfaceObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetStringField(TEXT("blueprint"), BlueprintName);
|
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
||||||
Result->SetNumberField(TEXT("count"), InterfacesArr.Num());
|
Result->SetNumberField(TEXT("count"), InterfacesArr.Num());
|
||||||
Result->SetArrayField(TEXT("interfaces"), InterfacesArr);
|
Result->SetArrayField(TEXT("interfaces"), InterfacesArr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// HandleAddInterface — add a Blueprint Interface implementation
|
// AddInterface
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
void FBlueprintMCPServer::HandleAddInterface(const FJsonObject* Json, FJsonObject* Result)
|
void UMCPHandler_AddInterface::Handle(const FJsonObject* Json, FJsonObject* Result)
|
||||||
{
|
{
|
||||||
FString BlueprintName = Json->GetStringField(TEXT("blueprint"));
|
MCPHelper* Helper = MCPHelper::Get();
|
||||||
FString InterfaceName = Json->GetStringField(TEXT("interfaceName"));
|
|
||||||
|
|
||||||
if (BlueprintName.IsEmpty() || InterfaceName.IsEmpty())
|
|
||||||
{
|
|
||||||
return MakeErrorJson(Result, TEXT("Missing required fields: blueprint, interfaceName"));
|
|
||||||
}
|
|
||||||
|
|
||||||
FString LoadError;
|
FString LoadError;
|
||||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
UBlueprint* BP = Helper->LoadBlueprintByName(Blueprint, LoadError);
|
||||||
if (!BP)
|
if (!BP)
|
||||||
{
|
{
|
||||||
return MakeErrorJson(Result, LoadError);
|
return Helper->MakeErrorJson(Result, LoadError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the interface class
|
// Resolve the interface class
|
||||||
@@ -114,7 +100,7 @@ void FBlueprintMCPServer::HandleAddInterface(const FJsonObject* Json, FJsonObjec
|
|||||||
if (!InterfaceClass)
|
if (!InterfaceClass)
|
||||||
{
|
{
|
||||||
FString IfaceLoadError;
|
FString IfaceLoadError;
|
||||||
UBlueprint* IfaceBP = LoadBlueprintByName(InterfaceName, IfaceLoadError);
|
UBlueprint* IfaceBP = Helper->LoadBlueprintByName(InterfaceName, IfaceLoadError);
|
||||||
if (IfaceBP && IfaceBP->GeneratedClass && IfaceBP->GeneratedClass->IsChildOf(UInterface::StaticClass()))
|
if (IfaceBP && IfaceBP->GeneratedClass && IfaceBP->GeneratedClass->IsChildOf(UInterface::StaticClass()))
|
||||||
{
|
{
|
||||||
InterfaceClass = IfaceBP->GeneratedClass;
|
InterfaceClass = IfaceBP->GeneratedClass;
|
||||||
@@ -123,7 +109,7 @@ void FBlueprintMCPServer::HandleAddInterface(const FJsonObject* Json, FJsonObjec
|
|||||||
|
|
||||||
if (!InterfaceClass)
|
if (!InterfaceClass)
|
||||||
{
|
{
|
||||||
return MakeErrorJson(Result, FString::Printf(
|
return Helper->MakeErrorJson(Result, FString::Printf(
|
||||||
TEXT("Interface '%s' not found. Provide a Blueprint Interface asset name (e.g. 'BPI_MyInterface') or a native UInterface class name."),
|
TEXT("Interface '%s' not found. Provide a Blueprint Interface asset name (e.g. 'BPI_MyInterface') or a native UInterface class name."),
|
||||||
*InterfaceName));
|
*InterfaceName));
|
||||||
}
|
}
|
||||||
@@ -133,24 +119,23 @@ void FBlueprintMCPServer::HandleAddInterface(const FJsonObject* Json, FJsonObjec
|
|||||||
{
|
{
|
||||||
if (IfaceDesc.Interface == InterfaceClass)
|
if (IfaceDesc.Interface == InterfaceClass)
|
||||||
{
|
{
|
||||||
return MakeErrorJson(Result, FString::Printf(
|
return Helper->MakeErrorJson(Result, FString::Printf(
|
||||||
TEXT("Interface '%s' is already implemented by Blueprint '%s'"),
|
TEXT("Interface '%s' is already implemented by Blueprint '%s'"),
|
||||||
*InterfaceName, *BlueprintName));
|
*InterfaceName, *Blueprint));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get interface class path for the non-deprecated overload
|
|
||||||
FTopLevelAssetPath InterfacePath = InterfaceClass->GetClassPathName();
|
FTopLevelAssetPath InterfacePath = InterfaceClass->GetClassPathName();
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Adding interface '%s' to Blueprint '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Adding interface '%s' to Blueprint '%s'"),
|
||||||
*InterfaceClass->GetName(), *BlueprintName);
|
*InterfaceClass->GetName(), *Blueprint);
|
||||||
|
|
||||||
bool bAdded = FBlueprintEditorUtils::ImplementNewInterface(BP, InterfacePath);
|
bool bAdded = FBlueprintEditorUtils::ImplementNewInterface(BP, InterfacePath);
|
||||||
if (!bAdded)
|
if (!bAdded)
|
||||||
{
|
{
|
||||||
return MakeErrorJson(Result, FString::Printf(
|
return Helper->MakeErrorJson(Result, FString::Printf(
|
||||||
TEXT("FBlueprintEditorUtils::ImplementNewInterface failed for interface '%s' on Blueprint '%s'"),
|
TEXT("FBlueprintEditorUtils::ImplementNewInterface failed for interface '%s' on Blueprint '%s'"),
|
||||||
*InterfaceName, *BlueprintName));
|
*InterfaceName, *Blueprint));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect stub function graph names from the newly added interface entry
|
// Collect stub function graph names from the newly added interface entry
|
||||||
@@ -171,13 +156,13 @@ void FBlueprintMCPServer::HandleAddInterface(const FJsonObject* Json, FJsonObjec
|
|||||||
}
|
}
|
||||||
|
|
||||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||||
bool bSaved = SaveBlueprintPackage(BP);
|
if (Save) Helper->SaveBlueprintPackage(BP);
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added interface '%s' to '%s' (%d function stubs, saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added interface '%s' to '%s' (%d function stubs)"),
|
||||||
*InterfaceClass->GetName(), *BlueprintName, AddedFunctions.Num(), bSaved ? TEXT("true") : TEXT("false"));
|
*InterfaceClass->GetName(), *Blueprint, AddedFunctions.Num());
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
Result->SetBoolField(TEXT("success"), true);
|
||||||
Result->SetStringField(TEXT("blueprint"), BlueprintName);
|
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
||||||
Result->SetStringField(TEXT("interfaceName"), InterfaceClass->GetName());
|
Result->SetStringField(TEXT("interfaceName"), InterfaceClass->GetName());
|
||||||
Result->SetStringField(TEXT("interfacePath"), InterfaceClass->GetPathName());
|
Result->SetStringField(TEXT("interfacePath"), InterfaceClass->GetPathName());
|
||||||
|
|
||||||
@@ -187,34 +172,21 @@ void FBlueprintMCPServer::HandleAddInterface(const FJsonObject* Json, FJsonObjec
|
|||||||
FuncArr.Add(MakeShared<FJsonValueString>(FuncName));
|
FuncArr.Add(MakeShared<FJsonValueString>(FuncName));
|
||||||
}
|
}
|
||||||
Result->SetArrayField(TEXT("functionGraphsAdded"), FuncArr);
|
Result->SetArrayField(TEXT("functionGraphsAdded"), FuncArr);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// HandleRemoveInterface — remove a Blueprint Interface implementation
|
// RemoveInterface
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
void FBlueprintMCPServer::HandleRemoveInterface(const FJsonObject* Json, FJsonObject* Result)
|
void UMCPHandler_RemoveInterface::Handle(const FJsonObject* Json, FJsonObject* Result)
|
||||||
{
|
{
|
||||||
FString BlueprintName = Json->GetStringField(TEXT("blueprint"));
|
MCPHelper* Helper = MCPHelper::Get();
|
||||||
FString InterfaceName = Json->GetStringField(TEXT("interfaceName"));
|
|
||||||
|
|
||||||
if (BlueprintName.IsEmpty() || InterfaceName.IsEmpty())
|
|
||||||
{
|
|
||||||
return MakeErrorJson(Result, TEXT("Missing required fields: blueprint, interfaceName"));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bPreserveFunctions = false;
|
|
||||||
if (Json->HasField(TEXT("preserveFunctions")))
|
|
||||||
{
|
|
||||||
bPreserveFunctions = Json->GetBoolField(TEXT("preserveFunctions"));
|
|
||||||
}
|
|
||||||
|
|
||||||
FString LoadError;
|
FString LoadError;
|
||||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
UBlueprint* BP = Helper->LoadBlueprintByName(Blueprint, LoadError);
|
||||||
if (!BP)
|
if (!BP)
|
||||||
{
|
{
|
||||||
return MakeErrorJson(Result, LoadError);
|
return Helper->MakeErrorJson(Result, LoadError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the interface in ImplementedInterfaces by name (case-insensitive)
|
// Find the interface in ImplementedInterfaces by name (case-insensitive)
|
||||||
@@ -257,9 +229,9 @@ void FBlueprintMCPServer::HandleRemoveInterface(const FJsonObject* Json, FJsonOb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MakeErrorJson(Result, FString::Printf(
|
Helper->MakeErrorJson(Result, FString::Printf(
|
||||||
TEXT("Interface '%s' is not implemented by Blueprint '%s'"),
|
TEXT("Interface '%s' is not implemented by Blueprint '%s'"),
|
||||||
*InterfaceName, *BlueprintName));
|
*InterfaceName, *Blueprint));
|
||||||
Result->SetArrayField(TEXT("implementedInterfaces"), IfaceList);
|
Result->SetArrayField(TEXT("implementedInterfaces"), IfaceList);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -267,19 +239,18 @@ void FBlueprintMCPServer::HandleRemoveInterface(const FJsonObject* Json, FJsonOb
|
|||||||
FTopLevelAssetPath InterfacePath = FoundInterface->GetClassPathName();
|
FTopLevelAssetPath InterfacePath = FoundInterface->GetClassPathName();
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removing interface '%s' from Blueprint '%s' (preserveFunctions: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removing interface '%s' from Blueprint '%s' (preserveFunctions: %s)"),
|
||||||
*FoundInterface->GetName(), *BlueprintName, bPreserveFunctions ? TEXT("true") : TEXT("false"));
|
*FoundInterface->GetName(), *Blueprint, PreserveFunctions ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
FBlueprintEditorUtils::RemoveInterface(BP, InterfacePath, bPreserveFunctions);
|
FBlueprintEditorUtils::RemoveInterface(BP, InterfacePath, PreserveFunctions);
|
||||||
|
|
||||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||||
bool bSaved = SaveBlueprintPackage(BP);
|
if (Save) Helper->SaveBlueprintPackage(BP);
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removed interface '%s' from '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removed interface '%s' from '%s'"),
|
||||||
*FoundInterface->GetName(), *BlueprintName, bSaved ? TEXT("true") : TEXT("false"));
|
*FoundInterface->GetName(), *Blueprint);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
Result->SetBoolField(TEXT("success"), true);
|
||||||
Result->SetStringField(TEXT("blueprint"), BlueprintName);
|
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
||||||
Result->SetStringField(TEXT("interfaceName"), FoundInterface->GetName());
|
Result->SetStringField(TEXT("interfaceName"), FoundInterface->GetName());
|
||||||
Result->SetBoolField(TEXT("preservedFunctions"), bPreserveFunctions);
|
Result->SetBoolField(TEXT("preservedFunctions"), PreserveFunctions);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2667,6 +2667,7 @@ void UMCPHandler_SpawnNode::Handle(const FJsonObject* Json, FJsonObject* Result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||||
|
if (Save) Helper->SaveBlueprintPackage(BP);
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Spawned node '%s' (class %s) via action '%s' in graph '%s' of '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Spawned node '%s' (class %s) via action '%s' in graph '%s' of '%s'"),
|
||||||
*NewNode->NodeGuid.ToString(),
|
*NewNode->NodeGuid.ToString(),
|
||||||
|
|||||||
@@ -684,11 +684,11 @@ bool FBlueprintMCPServer::Start(int32 InPort, bool bEditorMode)
|
|||||||
|
|
||||||
// Interface tools
|
// Interface tools
|
||||||
Router->BindRoute(FHttpPath(TEXT("/api/add-interface")), EHttpServerRequestVerbs::VERB_POST,
|
Router->BindRoute(FHttpPath(TEXT("/api/add-interface")), EHttpServerRequestVerbs::VERB_POST,
|
||||||
QueuedHandler(TEXT("addInterface")));
|
QueuedHandler(TEXT("add_interface")));
|
||||||
Router->BindRoute(FHttpPath(TEXT("/api/remove-interface")), EHttpServerRequestVerbs::VERB_POST,
|
Router->BindRoute(FHttpPath(TEXT("/api/remove-interface")), EHttpServerRequestVerbs::VERB_POST,
|
||||||
QueuedHandler(TEXT("removeInterface")));
|
QueuedHandler(TEXT("remove_interface")));
|
||||||
Router->BindRoute(FHttpPath(TEXT("/api/list-interfaces")), EHttpServerRequestVerbs::VERB_POST,
|
Router->BindRoute(FHttpPath(TEXT("/api/list-interfaces")), EHttpServerRequestVerbs::VERB_POST,
|
||||||
QueuedHandler(TEXT("listInterfaces")));
|
QueuedHandler(TEXT("list_interfaces")));
|
||||||
|
|
||||||
// Event Dispatcher tools
|
// Event Dispatcher tools
|
||||||
Router->BindRoute(FHttpPath(TEXT("/api/add-event-dispatcher")), EHttpServerRequestVerbs::VERB_POST,
|
Router->BindRoute(FHttpPath(TEXT("/api/add-event-dispatcher")), EHttpServerRequestVerbs::VERB_POST,
|
||||||
@@ -720,7 +720,7 @@ bool FBlueprintMCPServer::Start(int32 InPort, bool bEditorMode)
|
|||||||
Router->BindRoute(FHttpPath(TEXT("/api/analyze-rebuild-impact")), EHttpServerRequestVerbs::VERB_POST,
|
Router->BindRoute(FHttpPath(TEXT("/api/analyze-rebuild-impact")), EHttpServerRequestVerbs::VERB_POST,
|
||||||
QueuedHandler(TEXT("analyzeRebuildImpact")));
|
QueuedHandler(TEXT("analyzeRebuildImpact")));
|
||||||
Router->BindRoute(FHttpPath(TEXT("/api/diff-blueprints")), EHttpServerRequestVerbs::VERB_POST,
|
Router->BindRoute(FHttpPath(TEXT("/api/diff-blueprints")), EHttpServerRequestVerbs::VERB_POST,
|
||||||
QueuedHandler(TEXT("diffBlueprints")));
|
QueuedHandler(TEXT("diff_blueprints")));
|
||||||
|
|
||||||
// Material read-only tools (Phase 1)
|
// Material read-only tools (Phase 1)
|
||||||
Router->BindRoute(FHttpPath(TEXT("/api/materials")), EHttpServerRequestVerbs::VERB_GET,
|
Router->BindRoute(FHttpPath(TEXT("/api/materials")), EHttpServerRequestVerbs::VERB_GET,
|
||||||
@@ -997,8 +997,8 @@ void FBlueprintMCPServer::RegisterHandlers()
|
|||||||
TEXT("addVariable"),
|
TEXT("addVariable"),
|
||||||
TEXT("removeVariable"),
|
TEXT("removeVariable"),
|
||||||
TEXT("setVariableMetadata"),
|
TEXT("setVariableMetadata"),
|
||||||
TEXT("addInterface"),
|
TEXT("add_interface"),
|
||||||
TEXT("removeInterface"),
|
TEXT("remove_interface"),
|
||||||
TEXT("addEventDispatcher"),
|
TEXT("addEventDispatcher"),
|
||||||
TEXT("addFunctionParameter"),
|
TEXT("addFunctionParameter"),
|
||||||
TEXT("addComponent"),
|
TEXT("addComponent"),
|
||||||
@@ -1079,9 +1079,7 @@ void FBlueprintMCPServer::RegisterHandlers()
|
|||||||
H(TEXT("addVariable"), &FBlueprintMCPServer::HandleAddVariable);
|
H(TEXT("addVariable"), &FBlueprintMCPServer::HandleAddVariable);
|
||||||
H(TEXT("removeVariable"), &FBlueprintMCPServer::HandleRemoveVariable);
|
H(TEXT("removeVariable"), &FBlueprintMCPServer::HandleRemoveVariable);
|
||||||
H(TEXT("setVariableMetadata"), &FBlueprintMCPServer::HandleSetVariableMetadata);
|
H(TEXT("setVariableMetadata"), &FBlueprintMCPServer::HandleSetVariableMetadata);
|
||||||
H(TEXT("addInterface"), &FBlueprintMCPServer::HandleAddInterface);
|
// add_interface, remove_interface, list_interfaces now handled by new-style registry
|
||||||
H(TEXT("removeInterface"), &FBlueprintMCPServer::HandleRemoveInterface);
|
|
||||||
H(TEXT("listInterfaces"), &FBlueprintMCPServer::HandleListInterfaces);
|
|
||||||
H(TEXT("addEventDispatcher"), &FBlueprintMCPServer::HandleAddEventDispatcher);
|
H(TEXT("addEventDispatcher"), &FBlueprintMCPServer::HandleAddEventDispatcher);
|
||||||
H(TEXT("listEventDispatchers"), &FBlueprintMCPServer::HandleListEventDispatchers);
|
H(TEXT("listEventDispatchers"), &FBlueprintMCPServer::HandleListEventDispatchers);
|
||||||
H(TEXT("addFunctionParameter"), &FBlueprintMCPServer::HandleAddFunctionParameter);
|
H(TEXT("addFunctionParameter"), &FBlueprintMCPServer::HandleAddFunctionParameter);
|
||||||
@@ -1093,7 +1091,7 @@ void FBlueprintMCPServer::RegisterHandlers()
|
|||||||
H(TEXT("restoreGraph"), &FBlueprintMCPServer::HandleRestoreGraph);
|
H(TEXT("restoreGraph"), &FBlueprintMCPServer::HandleRestoreGraph);
|
||||||
H(TEXT("findDisconnectedPins"), &FBlueprintMCPServer::HandleFindDisconnectedPins);
|
H(TEXT("findDisconnectedPins"), &FBlueprintMCPServer::HandleFindDisconnectedPins);
|
||||||
H(TEXT("analyzeRebuildImpact"), &FBlueprintMCPServer::HandleAnalyzeRebuildImpact);
|
H(TEXT("analyzeRebuildImpact"), &FBlueprintMCPServer::HandleAnalyzeRebuildImpact);
|
||||||
H(TEXT("diffBlueprints"), &FBlueprintMCPServer::HandleDiffBlueprints);
|
// diff_blueprints is now handled by UMCPHandler_DiffBlueprints (new-style registry)
|
||||||
H(TEXT("createStruct"), &FBlueprintMCPServer::HandleCreateStruct);
|
H(TEXT("createStruct"), &FBlueprintMCPServer::HandleCreateStruct);
|
||||||
H(TEXT("createEnum"), &FBlueprintMCPServer::HandleCreateEnum);
|
H(TEXT("createEnum"), &FBlueprintMCPServer::HandleCreateEnum);
|
||||||
H(TEXT("addStructProperty"), &FBlueprintMCPServer::HandleAddStructProperty);
|
H(TEXT("addStructProperty"), &FBlueprintMCPServer::HandleAddStructProperty);
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "MCPHandler.h"
|
||||||
|
#include "BlueprintMCPHandlers_DiffBlueprints.generated.h"
|
||||||
|
|
||||||
|
UCLASS(meta=(ToolName="diff_blueprints"))
|
||||||
|
class UMCPHandler_DiffBlueprints : public UMCPHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="First blueprint name or package path"))
|
||||||
|
FString BlueprintA;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Second blueprint name or package path"))
|
||||||
|
FString BlueprintB;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Optional, Description="Filter to a specific graph name"))
|
||||||
|
FString Graph;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Structural diff between two different Blueprints. Compares nodes, "
|
||||||
|
"connections, and variables across graphs. Use for comparing variants, "
|
||||||
|
"finding divergence after copy-paste, or auditing consistency.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override;
|
||||||
|
};
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "MCPHandler.h"
|
||||||
|
#include "BlueprintMCPHandlers_Interfaces.generated.h"
|
||||||
|
|
||||||
|
UCLASS(meta=(ToolName="list_interfaces"))
|
||||||
|
class UMCPHandler_ListInterfaces : public UMCPHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
||||||
|
FString Blueprint;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("List all Blueprint Interfaces implemented by a Blueprint, "
|
||||||
|
"including their function graphs.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
UCLASS(meta=(ToolName="add_interface"))
|
||||||
|
class UMCPHandler_AddInterface : public UMCPHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
||||||
|
FString Blueprint;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Interface name (e.g. 'BPI_MyInterface') or native UInterface class name"))
|
||||||
|
FString InterfaceName;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Optional, Description="Save the blueprint after adding the interface"))
|
||||||
|
bool Save = false;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Add a Blueprint Interface implementation to a Blueprint. "
|
||||||
|
"Creates stub function graphs for each interface function.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
UCLASS(meta=(ToolName="remove_interface"))
|
||||||
|
class UMCPHandler_RemoveInterface : public UMCPHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
||||||
|
FString Blueprint;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Interface name to remove"))
|
||||||
|
FString InterfaceName;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Optional, Description="If true, keep the function graphs as regular functions"))
|
||||||
|
bool PreserveFunctions = false;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Optional, Description="Save the blueprint after removing the interface"))
|
||||||
|
bool Save = false;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Remove a Blueprint Interface implementation from a Blueprint. "
|
||||||
|
"Optionally preserve the function graphs as regular functions.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override;
|
||||||
|
};
|
||||||
@@ -25,6 +25,9 @@ public:
|
|||||||
UPROPERTY(meta=(Optional, Description="Y position in the graph"))
|
UPROPERTY(meta=(Optional, Description="Y position in the graph"))
|
||||||
int32 PosY = 0;
|
int32 PosY = 0;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Optional, Description="Save the blueprint after spawning the node"))
|
||||||
|
bool Save = false;
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
virtual FString GetDescription() const override
|
||||||
{
|
{
|
||||||
return TEXT("Create a node in a Blueprint graph using the editor's action database. "
|
return TEXT("Create a node in a Blueprint graph using the editor's action database. "
|
||||||
|
|||||||
@@ -193,10 +193,6 @@ private:
|
|||||||
void HandleRemoveVariable(const FJsonObject* Json, FJsonObject* Result);
|
void HandleRemoveVariable(const FJsonObject* Json, FJsonObject* Result);
|
||||||
void HandleSetVariableMetadata(const FJsonObject* Json, FJsonObject* Result);
|
void HandleSetVariableMetadata(const FJsonObject* Json, FJsonObject* Result);
|
||||||
|
|
||||||
// ----- Interfaces -----
|
|
||||||
void HandleAddInterface(const FJsonObject* Json, FJsonObject* Result);
|
|
||||||
void HandleRemoveInterface(const FJsonObject* Json, FJsonObject* Result);
|
|
||||||
void HandleListInterfaces(const FJsonObject* Json, FJsonObject* Result);
|
|
||||||
|
|
||||||
// ----- Event Dispatchers -----
|
// ----- Event Dispatchers -----
|
||||||
void HandleAddEventDispatcher(const FJsonObject* Json, FJsonObject* Result);
|
void HandleAddEventDispatcher(const FJsonObject* Json, FJsonObject* Result);
|
||||||
@@ -226,8 +222,6 @@ private:
|
|||||||
void HandleFindDisconnectedPins(const FJsonObject* Json, FJsonObject* Result);
|
void HandleFindDisconnectedPins(const FJsonObject* Json, FJsonObject* Result);
|
||||||
void HandleAnalyzeRebuildImpact(const FJsonObject* Json, FJsonObject* Result);
|
void HandleAnalyzeRebuildImpact(const FJsonObject* Json, FJsonObject* Result);
|
||||||
|
|
||||||
// ----- Cross-Blueprint comparison (read-only) -----
|
|
||||||
void HandleDiffBlueprints(const FJsonObject* Json, FJsonObject* Result);
|
|
||||||
|
|
||||||
// ----- Material read-only handlers (Phase 1) -----
|
// ----- Material read-only handlers (Phase 1) -----
|
||||||
void HandleListMaterials(const FJsonObject* Json, FJsonObject* Result);
|
void HandleListMaterials(const FJsonObject* Json, FJsonObject* Result);
|
||||||
|
|||||||
Reference in New Issue
Block a user