Refactoring more MCP handlers.
This commit is contained in:
Binary file not shown.
@@ -59,7 +59,8 @@ public:
|
|||||||
const TArray<USCS_Node*>& ExistingNodes = SCS->GetAllNodes();
|
const TArray<USCS_Node*>& ExistingNodes = SCS->GetAllNodes();
|
||||||
for (USCS_Node* Existing : ExistingNodes)
|
for (USCS_Node* Existing : ExistingNodes)
|
||||||
{
|
{
|
||||||
if (Existing && Existing->GetVariableName().ToString().Equals(Component, ESearchCase::IgnoreCase))
|
if (Existing && Existing->ComponentTemplate &&
|
||||||
|
MCPUtils::Identifies(Component, Existing->ComponentTemplate))
|
||||||
{
|
{
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
||||||
TEXT("A component named '%s' already exists in Blueprint '%s'"),
|
TEXT("A component named '%s' already exists in Blueprint '%s'"),
|
||||||
@@ -68,43 +69,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the component class by name
|
// Resolve the component class by name
|
||||||
// Try multiple name variants: exact name, with U prefix, without U prefix
|
|
||||||
UClass* ComponentClassObj = nullptr;
|
UClass* ComponentClassObj = nullptr;
|
||||||
|
|
||||||
TArray<FString> NamesToTry;
|
|
||||||
NamesToTry.Add(ComponentClass);
|
|
||||||
if (!ComponentClass.StartsWith(TEXT("U")))
|
|
||||||
{
|
|
||||||
NamesToTry.Add(FString::Printf(TEXT("U%s"), *ComponentClass));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Also try without U prefix
|
|
||||||
NamesToTry.Add(ComponentClass.Mid(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (TObjectIterator<UClass> It; It; ++It)
|
for (TObjectIterator<UClass> It; It; ++It)
|
||||||
{
|
{
|
||||||
if (!It->IsChildOf(UActorComponent::StaticClass()))
|
if (!It->IsChildOf(UActorComponent::StaticClass())) continue;
|
||||||
{
|
if (!MCPUtils::Identifies(ComponentClass, *It)) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
FString ClassName = It->GetName();
|
|
||||||
for (const FString& NameToTry : NamesToTry)
|
|
||||||
{
|
|
||||||
if (ClassName.Equals(NameToTry, ESearchCase::IgnoreCase))
|
|
||||||
{
|
|
||||||
ComponentClassObj = *It;
|
ComponentClassObj = *It;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ComponentClassObj)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ComponentClassObj)
|
if (!ComponentClassObj)
|
||||||
{
|
{
|
||||||
@@ -123,7 +95,8 @@ public:
|
|||||||
{
|
{
|
||||||
for (USCS_Node* Node : ExistingNodes)
|
for (USCS_Node* Node : ExistingNodes)
|
||||||
{
|
{
|
||||||
if (Node && Node->GetVariableName().ToString().Equals(ParentComponent, ESearchCase::IgnoreCase))
|
if (Node && Node->ComponentTemplate &&
|
||||||
|
MCPUtils::Identifies(ParentComponent, Node->ComponentTemplate))
|
||||||
{
|
{
|
||||||
ParentSCSNode = Node;
|
ParentSCSNode = Node;
|
||||||
break;
|
break;
|
||||||
@@ -139,7 +112,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Adding component '%s' (%s) to Blueprint '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Adding component '%s' (%s) to Blueprint '%s'"),
|
||||||
*Component, *ComponentClassObj->GetName(), *Blueprint);
|
*Component, *MCPUtils::FormatName(ComponentClassObj), *Blueprint);
|
||||||
|
|
||||||
// Create the SCS node
|
// Create the SCS node
|
||||||
USCS_Node* NewNode = SCS->CreateNode(ComponentClassObj, FName(*Component));
|
USCS_Node* NewNode = SCS->CreateNode(ComponentClassObj, FName(*Component));
|
||||||
@@ -147,7 +120,7 @@ public:
|
|||||||
{
|
{
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
||||||
TEXT("Failed to create SCS node for component '%s' with class '%s'"),
|
TEXT("Failed to create SCS node for component '%s' with class '%s'"),
|
||||||
*Component, *ComponentClassObj->GetName()));
|
*Component, *MCPUtils::FormatName(ComponentClassObj)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to the hierarchy
|
// Add to the hierarchy
|
||||||
@@ -164,15 +137,15 @@ public:
|
|||||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added component '%s' (%s) to '%s' (parent: %s, saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added component '%s' (%s) to '%s' (parent: %s, saved: %s)"),
|
||||||
*Component, *ComponentClassObj->GetName(), *Blueprint,
|
*Component, *MCPUtils::FormatName(ComponentClassObj), *Blueprint,
|
||||||
ParentSCSNode ? *ParentComponent : TEXT("(root)"),
|
ParentSCSNode ? *ParentComponent : TEXT("(root)"),
|
||||||
bSaved ? TEXT("true") : TEXT("false"));
|
bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetStringField(TEXT("component"), NewNode->GetVariableName().ToString());
|
Result->SetStringField(TEXT("component"), MCPUtils::FormatName(NewNode->ComponentTemplate));
|
||||||
Result->SetStringField(TEXT("componentClass"), ComponentClassObj->GetName());
|
Result->SetStringField(TEXT("componentClass"), MCPUtils::FormatName(ComponentClassObj));
|
||||||
if (ParentSCSNode)
|
if (ParentSCSNode)
|
||||||
{
|
{
|
||||||
Result->SetStringField(TEXT("parentComponent"), ParentSCSNode->GetVariableName().ToString());
|
Result->SetStringField(TEXT("parentComponent"), MCPUtils::FormatName(ParentSCSNode->ComponentTemplate));
|
||||||
}
|
}
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public:
|
|||||||
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(), *Blueprint);
|
*MCPUtils::FormatName(InterfaceClass), *Blueprint);
|
||||||
|
|
||||||
bool bAdded = FBlueprintEditorUtils::ImplementNewInterface(BP, InterfacePath);
|
bool bAdded = FBlueprintEditorUtils::ImplementNewInterface(BP, InterfacePath);
|
||||||
if (!bAdded)
|
if (!bAdded)
|
||||||
@@ -126,7 +126,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (Graph)
|
if (Graph)
|
||||||
{
|
{
|
||||||
AddedFunctions.Add(Graph->GetName());
|
AddedFunctions.Add(MCPUtils::FormatName(Graph));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -137,9 +137,9 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added interface '%s' to '%s' (%d function stubs)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added interface '%s' to '%s' (%d function stubs)"),
|
||||||
*InterfaceClass->GetName(), *Blueprint, AddedFunctions.Num());
|
*MCPUtils::FormatName(InterfaceClass), *Blueprint, AddedFunctions.Num());
|
||||||
|
|
||||||
Result->SetStringField(TEXT("interfaceName"), InterfaceClass->GetName());
|
Result->SetStringField(TEXT("interfaceName"), MCPUtils::FormatName(InterfaceClass));
|
||||||
Result->SetStringField(TEXT("interfacePath"), InterfaceClass->GetPathName());
|
Result->SetStringField(TEXT("interfacePath"), InterfaceClass->GetPathName());
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> FuncArr;
|
TArray<TSharedPtr<FJsonValue>> FuncArr;
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public:
|
|||||||
for (UK2Node_FunctionEntry* FE : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
for (UK2Node_FunctionEntry* FE : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
||||||
{
|
{
|
||||||
UEdGraph* FEGraph = FE->GetGraph();
|
UEdGraph* FEGraph = FE->GetGraph();
|
||||||
if (!FEGraph->GetName().Equals(FunctionName, ESearchCase::IgnoreCase)) continue;
|
if (!MCPUtils::Identifies(FunctionName, FEGraph)) continue;
|
||||||
// Skip delegate signature graphs (handled in Strategy 3)
|
// Skip delegate signature graphs (handled in Strategy 3)
|
||||||
if (BP->DelegateSignatureGraphs.Contains(FEGraph)) continue;
|
if (BP->DelegateSignatureGraphs.Contains(FEGraph)) continue;
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ public:
|
|||||||
for (UK2Node_FunctionEntry* FE : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
for (UK2Node_FunctionEntry* FE : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
||||||
{
|
{
|
||||||
UEdGraph* FEGraph = FE->GetGraph();
|
UEdGraph* FEGraph = FE->GetGraph();
|
||||||
if (!FEGraph->GetName().Equals(FunctionName, ESearchCase::IgnoreCase)) continue;
|
if (!MCPUtils::Identifies(FunctionName, FEGraph)) continue;
|
||||||
if (!BP->DelegateSignatureGraphs.Contains(FEGraph)) continue;
|
if (!BP->DelegateSignatureGraphs.Contains(FEGraph)) continue;
|
||||||
|
|
||||||
EntryNode = FE;
|
EntryNode = FE;
|
||||||
@@ -107,7 +107,7 @@ public:
|
|||||||
|
|
||||||
for (UEdGraph* Graph : BP->FunctionGraphs)
|
for (UEdGraph* Graph : BP->FunctionGraphs)
|
||||||
{
|
{
|
||||||
if (Graph) AvailFuncs.Add(MakeShared<FJsonValueString>(Graph->GetName()));
|
if (Graph) AvailFuncs.Add(MakeShared<FJsonValueString>(MCPUtils::FormatName(Graph)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom events
|
// Custom events
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ public:
|
|||||||
TSharedRef<FJsonObject> AffNode = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> AffNode = MakeShared<FJsonObject>();
|
||||||
AffNode->SetStringField(TEXT("nodeId"), VG->NodeGuid.ToString());
|
AffNode->SetStringField(TEXT("nodeId"), VG->NodeGuid.ToString());
|
||||||
AffNode->SetStringField(TEXT("nodeType"), TEXT("VariableGet"));
|
AffNode->SetStringField(TEXT("nodeType"), TEXT("VariableGet"));
|
||||||
AffNode->SetStringField(TEXT("graph"), VG->GetGraph()->GetName());
|
AffNode->SetStringField(TEXT("graph"), MCPUtils::FormatName(VG->GetGraph()));
|
||||||
TArray<TSharedPtr<FJsonValue>> AffPins;
|
TArray<TSharedPtr<FJsonValue>> AffPins;
|
||||||
for (UEdGraphPin* Pin : VG->Pins)
|
for (UEdGraphPin* Pin : VG->Pins)
|
||||||
{
|
{
|
||||||
@@ -122,7 +122,7 @@ public:
|
|||||||
{
|
{
|
||||||
AffPins.Add(MakeShared<FJsonValueString>(
|
AffPins.Add(MakeShared<FJsonValueString>(
|
||||||
FString::Printf(TEXT("%s (connected to %d pin(s))"),
|
FString::Printf(TEXT("%s (connected to %d pin(s))"),
|
||||||
*Pin->PinName.ToString(), Pin->LinkedTo.Num())));
|
*MCPUtils::FormatName(Pin), Pin->LinkedTo.Num())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AffNode->SetArrayField(TEXT("affectedPins"), AffPins);
|
AffNode->SetArrayField(TEXT("affectedPins"), AffPins);
|
||||||
@@ -134,7 +134,7 @@ public:
|
|||||||
TSharedRef<FJsonObject> AffNode = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> AffNode = MakeShared<FJsonObject>();
|
||||||
AffNode->SetStringField(TEXT("nodeId"), VS->NodeGuid.ToString());
|
AffNode->SetStringField(TEXT("nodeId"), VS->NodeGuid.ToString());
|
||||||
AffNode->SetStringField(TEXT("nodeType"), TEXT("VariableSet"));
|
AffNode->SetStringField(TEXT("nodeType"), TEXT("VariableSet"));
|
||||||
AffNode->SetStringField(TEXT("graph"), VS->GetGraph()->GetName());
|
AffNode->SetStringField(TEXT("graph"), MCPUtils::FormatName(VS->GetGraph()));
|
||||||
TArray<TSharedPtr<FJsonValue>> AffPins;
|
TArray<TSharedPtr<FJsonValue>> AffPins;
|
||||||
for (UEdGraphPin* Pin : VS->Pins)
|
for (UEdGraphPin* Pin : VS->Pins)
|
||||||
{
|
{
|
||||||
@@ -142,7 +142,7 @@ public:
|
|||||||
{
|
{
|
||||||
AffPins.Add(MakeShared<FJsonValueString>(
|
AffPins.Add(MakeShared<FJsonValueString>(
|
||||||
FString::Printf(TEXT("%s (connected to %d pin(s))"),
|
FString::Printf(TEXT("%s (connected to %d pin(s))"),
|
||||||
*Pin->PinName.ToString(), Pin->LinkedTo.Num())));
|
*MCPUtils::FormatName(Pin), Pin->LinkedTo.Num())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AffNode->SetArrayField(TEXT("affectedPins"), AffPins);
|
AffNode->SetArrayField(TEXT("affectedPins"), AffPins);
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public:
|
|||||||
// Strategy 1: Look for a K2Node_FunctionEntry in a function graph matching the name
|
// Strategy 1: Look for a K2Node_FunctionEntry in a function graph matching the name
|
||||||
for (UK2Node_FunctionEntry* FuncEntry : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
for (UK2Node_FunctionEntry* FuncEntry : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
||||||
{
|
{
|
||||||
if (FuncEntry->GetGraph()->GetName().Equals(FunctionName, ESearchCase::IgnoreCase))
|
if (MCPUtils::Identifies(FunctionName, FuncEntry->GetGraph()))
|
||||||
{
|
{
|
||||||
EntryNode = FuncEntry;
|
EntryNode = FuncEntry;
|
||||||
FoundNodeType = TEXT("FunctionEntry");
|
FoundNodeType = TEXT("FunctionEntry");
|
||||||
@@ -92,7 +92,7 @@ public:
|
|||||||
for (UK2Node_FunctionEntry* FE : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
for (UK2Node_FunctionEntry* FE : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
||||||
{
|
{
|
||||||
Available.Add(MakeShared<FJsonValueString>(
|
Available.Add(MakeShared<FJsonValueString>(
|
||||||
FString::Printf(TEXT("function:%s"), *FE->GetGraph()->GetName())));
|
FString::Printf(TEXT("function:%s"), *MCPUtils::FormatName(FE->GetGraph()))));
|
||||||
}
|
}
|
||||||
for (UK2Node_CustomEvent* CE : MCPUtils::AllNodes<UK2Node_CustomEvent>(BP))
|
for (UK2Node_CustomEvent* CE : MCPUtils::AllNodes<UK2Node_CustomEvent>(BP))
|
||||||
{
|
{
|
||||||
@@ -147,16 +147,16 @@ public:
|
|||||||
TArray<TSharedPtr<FJsonValue>> AffectedPins;
|
TArray<TSharedPtr<FJsonValue>> AffectedPins;
|
||||||
for (UEdGraphPin* Pin : EntryNode->Pins)
|
for (UEdGraphPin* Pin : EntryNode->Pins)
|
||||||
{
|
{
|
||||||
if (Pin && Pin->PinName.ToString().Equals(ParamName, ESearchCase::IgnoreCase) && Pin->LinkedTo.Num() > 0)
|
if (Pin && MCPUtils::Identifies(ParamName, Pin) && Pin->LinkedTo.Num() > 0)
|
||||||
{
|
{
|
||||||
for (UEdGraphPin* Linked : Pin->LinkedTo)
|
for (UEdGraphPin* Linked : Pin->LinkedTo)
|
||||||
{
|
{
|
||||||
if (Linked && Linked->GetOwningNode())
|
if (Linked && Linked->GetOwningNode())
|
||||||
{
|
{
|
||||||
TSharedRef<FJsonObject> AffPin = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> AffPin = MakeShared<FJsonObject>();
|
||||||
AffPin->SetStringField(TEXT("pinName"), Pin->PinName.ToString());
|
AffPin->SetStringField(TEXT("pinName"), MCPUtils::FormatName(Pin));
|
||||||
AffPin->SetStringField(TEXT("connectedToNode"), Linked->GetOwningNode()->NodeGuid.ToString());
|
AffPin->SetStringField(TEXT("connectedToNode"), Linked->GetOwningNode()->NodeGuid.ToString());
|
||||||
AffPin->SetStringField(TEXT("connectedToPin"), Linked->PinName.ToString());
|
AffPin->SetStringField(TEXT("connectedToPin"), MCPUtils::FormatName(Linked));
|
||||||
AffPin->SetStringField(TEXT("currentType"), Pin->PinType.PinCategory.ToString());
|
AffPin->SetStringField(TEXT("currentType"), Pin->PinType.PinCategory.ToString());
|
||||||
if (Pin->PinType.PinSubCategoryObject.IsValid())
|
if (Pin->PinType.PinSubCategoryObject.IsValid())
|
||||||
AffPin->SetStringField(TEXT("currentSubtype"), Pin->PinType.PinSubCategoryObject->GetName());
|
AffPin->SetStringField(TEXT("currentSubtype"), Pin->PinType.PinSubCategoryObject->GetName());
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ public:
|
|||||||
if (!BreakNode && !MakeNode)
|
if (!BreakNode && !MakeNode)
|
||||||
{
|
{
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Node '%s' is not a BreakStruct or MakeStruct node (class: %s)"),
|
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Node '%s' is not a BreakStruct or MakeStruct node (class: %s)"),
|
||||||
*Node, *FoundNode->GetClass()->GetName()));
|
*Node, *MCPUtils::FormatName(FoundNode->GetClass())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the new struct type
|
// Find the new struct type
|
||||||
@@ -267,7 +267,7 @@ public:
|
|||||||
TSharedPtr<FJsonObject> UpdatedNodeState = MCPUtils::SerializeNode(FoundNode);
|
TSharedPtr<FJsonObject> UpdatedNodeState = MCPUtils::SerializeNode(FoundNode);
|
||||||
|
|
||||||
Result->SetStringField(TEXT("newStructType"), NewStruct->GetName());
|
Result->SetStringField(TEXT("newStructType"), NewStruct->GetName());
|
||||||
Result->SetStringField(TEXT("nodeClass"), FoundNode->GetClass()->GetName());
|
Result->SetStringField(TEXT("nodeClass"), MCPUtils::FormatName(FoundNode->GetClass()));
|
||||||
Result->SetNumberField(TEXT("reconnected"), Reconnected);
|
Result->SetNumberField(TEXT("reconnected"), Reconnected);
|
||||||
Result->SetNumberField(TEXT("failed"), Failed);
|
Result->SetNumberField(TEXT("failed"), Failed);
|
||||||
Result->SetArrayField(TEXT("reconnectDetails"), ReconnectDetails);
|
Result->SetArrayField(TEXT("reconnectDetails"), ReconnectDetails);
|
||||||
|
|||||||
@@ -67,10 +67,10 @@ public:
|
|||||||
if (Node->bHasCompilerMessage)
|
if (Node->bHasCompilerMessage)
|
||||||
{
|
{
|
||||||
TSharedRef<FJsonObject> Msg = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> Msg = MakeShared<FJsonObject>();
|
||||||
Msg->SetStringField(TEXT("graph"), Node->GetGraph()->GetName());
|
Msg->SetStringField(TEXT("graph"), MCPUtils::FormatName(Node->GetGraph()));
|
||||||
Msg->SetStringField(TEXT("nodeId"), Node->NodeGuid.ToString());
|
Msg->SetStringField(TEXT("nodeId"), Node->NodeGuid.ToString());
|
||||||
Msg->SetStringField(TEXT("nodeTitle"), Node->GetNodeTitle(ENodeTitleType::FullTitle).ToString());
|
Msg->SetStringField(TEXT("nodeTitle"), MCPUtils::FormatName(Node));
|
||||||
Msg->SetStringField(TEXT("nodeClass"), Node->GetClass()->GetName());
|
Msg->SetStringField(TEXT("nodeClass"), MCPUtils::FormatName(Node->GetClass()));
|
||||||
Msg->SetStringField(TEXT("message"), Node->ErrorMsg);
|
Msg->SetStringField(TEXT("message"), Node->ErrorMsg);
|
||||||
|
|
||||||
if (Node->ErrorType == EMessageSeverity::Error)
|
if (Node->ErrorType == EMessageSeverity::Error)
|
||||||
|
|||||||
@@ -1,134 +0,0 @@
|
|||||||
#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_ConnectBlueprintPins.generated.h"
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
USTRUCT()
|
|
||||||
struct FConnectPinsEntry
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
FString SourceNode;
|
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
FString SourcePinName;
|
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
FString TargetNode;
|
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
FString TargetPinName;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
UCLASS()
|
|
||||||
class UMCPHandler_ConnectBlueprintPins : public UObject, public IMCPHandler
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
|
||||||
FString Blueprint;
|
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Array of {sourceNode, sourcePinName, targetNode, targetPinName} objects"))
|
|
||||||
FMCPJsonArray Connections;
|
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
|
||||||
{
|
|
||||||
return TEXT("Connect pins between nodes in a Blueprint graph.");
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
for (const TSharedPtr<FJsonValue>& ConnVal : Connections.Array)
|
|
||||||
{
|
|
||||||
TSharedRef<FJsonObject> EntryResult = MakeShared<FJsonObject>();
|
|
||||||
Results.Add(MakeShared<FJsonValueObject>(EntryResult));
|
|
||||||
|
|
||||||
FConnectPinsEntry Entry;
|
|
||||||
if (!MCPUtils::PopulateFromJson(FConnectPinsEntry::StaticStruct(), &Entry, ConnVal, &*EntryResult)) continue;
|
|
||||||
|
|
||||||
UEdGraph* SourceGraph = nullptr;
|
|
||||||
UEdGraphNode* SourceNode = MCPUtils::FindNodeByGuid(BP, Entry.SourceNode, &SourceGraph);
|
|
||||||
if (!SourceNode)
|
|
||||||
{
|
|
||||||
EntryResult->SetStringField(TEXT("error"), FString::Printf(TEXT("Source node '%s' not found"), *Entry.SourceNode));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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* SourcePin = SourceNode->FindPin(FName(*Entry.SourcePinName));
|
|
||||||
if (!SourcePin)
|
|
||||||
{
|
|
||||||
EntryResult->SetStringField(TEXT("error"), FString::Printf(TEXT("Source pin '%s' not found on node '%s'"), *Entry.SourcePinName, *Entry.SourceNode));
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
const UEdGraphSchema* Schema = SourceGraph->GetSchema();
|
|
||||||
if (!Schema)
|
|
||||||
{
|
|
||||||
EntryResult->SetStringField(TEXT("error"), TEXT("Graph schema not found"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bConnected = Schema->TryCreateConnection(SourcePin, TargetPin);
|
|
||||||
if (!bConnected)
|
|
||||||
{
|
|
||||||
EntryResult->SetStringField(TEXT("error"), FString::Printf(
|
|
||||||
TEXT("Cannot connect %s (%s) to %s (%s) — types are incompatible"),
|
|
||||||
*Entry.SourcePinName, *SourcePin->PinType.PinCategory.ToString(),
|
|
||||||
*Entry.TargetPinName, *TargetPin->PinType.PinCategory.ToString()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SuccessCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SuccessCount > 0)
|
|
||||||
{
|
|
||||||
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
|
|
||||||
}
|
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: ConnectPins — %d/%d succeeded in '%s'"),
|
|
||||||
SuccessCount, Connections.Array.Num(), *Blueprint);
|
|
||||||
Result->SetNumberField(TEXT("successCount"), SuccessCount);
|
|
||||||
Result->SetNumberField(TEXT("totalCount"), Connections.Array.Num());
|
|
||||||
Result->SetArrayField(TEXT("results"), Results);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "MCPHandler.h"
|
||||||
|
#include "MCPFetcher.h"
|
||||||
|
#include "MCPUtils.h"
|
||||||
|
#include "Engine/Blueprint.h"
|
||||||
|
#include "EdGraph/EdGraph.h"
|
||||||
|
#include "EdGraph/EdGraphNode.h"
|
||||||
|
#include "EdGraph/EdGraphPin.h"
|
||||||
|
#include "Kismet2/BlueprintEditorUtils.h"
|
||||||
|
#include "UMCPHandler_ConnectPins.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
USTRUCT()
|
||||||
|
struct FConnectPinsEntry
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
FString SourcePin;
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
FString TargetPin;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UMCPHandler_ConnectPins : public UObject, public IMCPHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
||||||
|
FString Blueprint;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Array of {sourcePin, targetPin} objects. Each pin is a path like node:MyNode,pin:Output"))
|
||||||
|
FMCPJsonArray Connections;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Connect pins between nodes in a Blueprint graph.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
|
{
|
||||||
|
|
||||||
|
MCPFetcher F(Result);
|
||||||
|
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||||
|
if (!BP) return;
|
||||||
|
|
||||||
|
TArray<TSharedPtr<FJsonValue>> Results;
|
||||||
|
int32 SuccessCount = 0;
|
||||||
|
|
||||||
|
for (const TSharedPtr<FJsonValue>& ConnVal : Connections.Array)
|
||||||
|
{
|
||||||
|
TSharedRef<FJsonObject> EntryResult = MakeShared<FJsonObject>();
|
||||||
|
Results.Add(MakeShared<FJsonValueObject>(EntryResult));
|
||||||
|
|
||||||
|
FConnectPinsEntry Entry;
|
||||||
|
if (!MCPUtils::PopulateFromJson(FConnectPinsEntry::StaticStruct(), &Entry, ConnVal, &*EntryResult)) continue;
|
||||||
|
|
||||||
|
MCPFetcher FS(EntryResult, BP);
|
||||||
|
UEdGraphPin* SourcePin = FS.Walk(Entry.SourcePin).Cast<UEdGraphPin>();
|
||||||
|
if (!SourcePin) continue;
|
||||||
|
|
||||||
|
MCPFetcher FT(EntryResult, BP);
|
||||||
|
UEdGraphPin* TargetPin = FT.Walk(Entry.TargetPin).Cast<UEdGraphPin>();
|
||||||
|
if (!TargetPin) continue;
|
||||||
|
|
||||||
|
const UEdGraphSchema* Schema = SourcePin->GetOwningNode()->GetGraph()->GetSchema();
|
||||||
|
const FPinConnectionResponse Response = Schema->CanCreateConnection(SourcePin, TargetPin);
|
||||||
|
if (Response.Response == CONNECT_RESPONSE_DISALLOW)
|
||||||
|
{
|
||||||
|
EntryResult->SetStringField(TEXT("error"), FString::Printf(
|
||||||
|
TEXT("Cannot connect %s.%s to %s.%s: %s"),
|
||||||
|
*MCPUtils::FormatName(SourcePin->GetOwningNode()), *MCPUtils::FormatName(SourcePin),
|
||||||
|
*MCPUtils::FormatName(TargetPin->GetOwningNode()), *MCPUtils::FormatName(TargetPin),
|
||||||
|
*Response.Message.ToString()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema->TryCreateConnection(SourcePin, TargetPin);
|
||||||
|
SuccessCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SuccessCount > 0)
|
||||||
|
{
|
||||||
|
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
|
||||||
|
}
|
||||||
|
|
||||||
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: ConnectPins — %d/%d succeeded in '%s'"),
|
||||||
|
SuccessCount, Connections.Array.Num(), *Blueprint);
|
||||||
|
Result->SetNumberField(TEXT("successCount"), SuccessCount);
|
||||||
|
Result->SetNumberField(TEXT("totalCount"), Connections.Array.Num());
|
||||||
|
Result->SetArrayField(TEXT("results"), Results);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -127,7 +127,7 @@ public:
|
|||||||
|
|
||||||
Result->SetStringField(TEXT("assetPath"), FullAssetPath);
|
Result->SetStringField(TEXT("assetPath"), FullAssetPath);
|
||||||
Result->SetStringField(TEXT("targetSkeleton"), SkeletonObj->GetName());
|
Result->SetStringField(TEXT("targetSkeleton"), SkeletonObj->GetName());
|
||||||
Result->SetStringField(TEXT("parentClass"), ParentClassObj->GetName());
|
Result->SetStringField(TEXT("parentClass"), MCPUtils::FormatName(ParentClassObj));
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
Result->SetArrayField(TEXT("graphs"), GraphNames);
|
Result->SetArrayField(TEXT("graphs"), GraphNames);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Creating Blueprint '%s' in '%s' with parent '%s' (type=%s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Creating Blueprint '%s' in '%s' with parent '%s' (type=%s)"),
|
||||||
*Blueprint, *PackagePath, *ParentClassObj->GetName(), *BlueprintType);
|
*Blueprint, *PackagePath, *MCPUtils::FormatName(ParentClassObj), *BlueprintType);
|
||||||
|
|
||||||
// Create the package
|
// Create the package
|
||||||
FString FullPackagePath = PackagePath / Blueprint;
|
FString FullPackagePath = PackagePath / Blueprint;
|
||||||
@@ -139,7 +139,7 @@ public:
|
|||||||
*Blueprint, GraphNames.Num(), bSaved ? TEXT("true") : TEXT("false"));
|
*Blueprint, GraphNames.Num(), bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetStringField(TEXT("assetPath"), FullAssetPath);
|
Result->SetStringField(TEXT("assetPath"), FullAssetPath);
|
||||||
Result->SetStringField(TEXT("parentClass"), ParentClassObj->GetName());
|
Result->SetStringField(TEXT("parentClass"), MCPUtils::FormatName(ParentClassObj));
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
Result->SetArrayField(TEXT("graphs"), GraphNames);
|
Result->SetArrayField(TEXT("graphs"), GraphNames);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public:
|
|||||||
|
|
||||||
for (UEdGraph* CandidateGraph : BP->FunctionGraphs)
|
for (UEdGraph* CandidateGraph : BP->FunctionGraphs)
|
||||||
{
|
{
|
||||||
if (CandidateGraph && CandidateGraph->GetName().Equals(Graph, ESearchCase::IgnoreCase))
|
if (CandidateGraph && MCPUtils::Identifies(Graph, CandidateGraph))
|
||||||
{
|
{
|
||||||
TargetGraph = CandidateGraph;
|
TargetGraph = CandidateGraph;
|
||||||
GraphType = TEXT("function");
|
GraphType = TEXT("function");
|
||||||
@@ -59,7 +59,7 @@ public:
|
|||||||
{
|
{
|
||||||
for (UEdGraph* CandidateGraph : BP->MacroGraphs)
|
for (UEdGraph* CandidateGraph : BP->MacroGraphs)
|
||||||
{
|
{
|
||||||
if (CandidateGraph && CandidateGraph->GetName().Equals(Graph, ESearchCase::IgnoreCase))
|
if (CandidateGraph && MCPUtils::Identifies(Graph, CandidateGraph))
|
||||||
{
|
{
|
||||||
TargetGraph = CandidateGraph;
|
TargetGraph = CandidateGraph;
|
||||||
GraphType = TEXT("macro");
|
GraphType = TEXT("macro");
|
||||||
@@ -73,7 +73,7 @@ public:
|
|||||||
{
|
{
|
||||||
for (UEdGraph* CandidateGraph : BP->UbergraphPages)
|
for (UEdGraph* CandidateGraph : BP->UbergraphPages)
|
||||||
{
|
{
|
||||||
if (CandidateGraph && CandidateGraph->GetName().Equals(Graph, ESearchCase::IgnoreCase))
|
if (CandidateGraph && MCPUtils::Identifies(Graph, CandidateGraph))
|
||||||
{
|
{
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
||||||
TEXT("Cannot delete UbergraphPage '%s'. EventGraph and other Ubergraph pages cannot be deleted."),
|
TEXT("Cannot delete UbergraphPage '%s'. EventGraph and other Ubergraph pages cannot be deleted."),
|
||||||
|
|||||||
@@ -131,8 +131,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Capture info before deletion
|
// Capture info before deletion
|
||||||
FString DeletedNodeTitle = TargetMatNode->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
|
FString DeletedNodeTitle = MCPUtils::FormatName(TargetMatNode);
|
||||||
FString DeletedExprClass = TargetMatNode->MaterialExpression->GetClass()->GetName();
|
FString DeletedExprClass = MCPUtils::FormatName(TargetMatNode->MaterialExpression->GetClass());
|
||||||
|
|
||||||
if (DryRun)
|
if (DryRun)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,52 +2,14 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "MCPHandler.h"
|
#include "MCPHandler.h"
|
||||||
#include "MCPAssetFinder.h"
|
#include "MCPFetcher.h"
|
||||||
#include "MCPServer.h"
|
|
||||||
#include "MCPUtils.h"
|
#include "MCPUtils.h"
|
||||||
#include "Engine/Blueprint.h"
|
|
||||||
#include "Materials/Material.h"
|
|
||||||
#include "Materials/MaterialInstanceConstant.h"
|
|
||||||
#include "Materials/MaterialFunction.h"
|
|
||||||
#include "Engine/World.h"
|
|
||||||
#include "Engine/LevelScriptBlueprint.h"
|
|
||||||
#include "EdGraph/EdGraph.h"
|
#include "EdGraph/EdGraph.h"
|
||||||
#include "EdGraph/EdGraphNode.h"
|
#include "EdGraph/EdGraphNode.h"
|
||||||
#include "EdGraph/EdGraphPin.h"
|
|
||||||
#include "EdGraphSchema_K2.h"
|
|
||||||
#include "K2Node.h"
|
|
||||||
#include "K2Node_CallFunction.h"
|
|
||||||
#include "K2Node_Event.h"
|
#include "K2Node_Event.h"
|
||||||
#include "K2Node_CustomEvent.h"
|
#include "K2Node_CustomEvent.h"
|
||||||
#include "K2Node_FunctionEntry.h"
|
#include "K2Node_FunctionEntry.h"
|
||||||
#include "K2Node_EditablePinBase.h"
|
|
||||||
#include "K2Node_VariableGet.h"
|
|
||||||
#include "K2Node_VariableSet.h"
|
|
||||||
#include "K2Node_BreakStruct.h"
|
|
||||||
#include "K2Node_MakeStruct.h"
|
|
||||||
#include "K2Node_DynamicCast.h"
|
|
||||||
#include "K2Node_CallParentFunction.h"
|
|
||||||
#include "K2Node_IfThenElse.h"
|
|
||||||
#include "K2Node_ExecutionSequence.h"
|
|
||||||
#include "K2Node_MacroInstance.h"
|
|
||||||
#include "K2Node_SpawnActorFromClass.h"
|
|
||||||
#include "K2Node_Select.h"
|
|
||||||
#include "K2Node_Knot.h"
|
|
||||||
#include "EdGraphNode_Comment.h"
|
|
||||||
#include "GameFramework/Actor.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/SavePackage.h"
|
|
||||||
#include "UObject/UObjectIterator.h"
|
|
||||||
#include "Misc/PackageName.h"
|
|
||||||
#include "AssetRegistry/AssetRegistryModule.h"
|
|
||||||
#include "AssetRegistry/IAssetRegistry.h"
|
|
||||||
#include "AssetToolsModule.h"
|
|
||||||
#include "IAssetTools.h"
|
|
||||||
#include "BlueprintNodeSpawner.h"
|
|
||||||
#include "UMCPHandler_DeleteNodeFromGraph.generated.h"
|
#include "UMCPHandler_DeleteNodeFromGraph.generated.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -61,10 +23,7 @@ class UMCPHandler_DeleteNodeFromGraph : public UObject, public IMCPHandler
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
UPROPERTY(meta=(Description="Path to the node, e.g. /Game/Foo,node:MyNode"))
|
||||||
FString Blueprint;
|
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Node GUID"))
|
|
||||||
FString Node;
|
FString Node;
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
virtual FString GetDescription() const override
|
||||||
@@ -76,24 +35,16 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
MCPAssets<UBlueprint> Assets;
|
MCPFetcher F(Result);
|
||||||
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
UEdGraphNode* FoundNode = F.Walk(Node).Cast<UEdGraphNode>();
|
||||||
UBlueprint* BP = Assets.Object();
|
if (!FoundNode) return;
|
||||||
|
|
||||||
UEdGraph* Graph = nullptr;
|
UEdGraph* Graph = FoundNode->GetGraph();
|
||||||
UEdGraphNode* FoundNode = MCPUtils::FindNodeByGuid(BP, Node, &Graph);
|
UBlueprint* BP = FBlueprintEditorUtils::FindBlueprintForNodeChecked(FoundNode);
|
||||||
if (!FoundNode)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Node '%s' not found"), *Node));
|
|
||||||
}
|
|
||||||
if (!Graph)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Graph not found for node '%s'"), *Node));
|
|
||||||
}
|
|
||||||
|
|
||||||
FString NodeClass = FoundNode->GetClass()->GetName();
|
FString NodeClass = MCPUtils::FormatName(FoundNode->GetClass());
|
||||||
FString NodeTitle = FoundNode->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
|
FString NodeTitle = MCPUtils::FormatName(FoundNode);
|
||||||
FString GraphName = Graph->GetName();
|
FString GraphName = MCPUtils::FormatName(Graph);
|
||||||
|
|
||||||
// Protect root/entry nodes — deleting these leaves the graph in an invalid
|
// Protect root/entry nodes — deleting these leaves the graph in an invalid
|
||||||
// state with no root node, causing compiler errors that can't be fixed
|
// state with no root node, causing compiler errors that can't be fixed
|
||||||
@@ -121,8 +72,8 @@ public:
|
|||||||
*NodeTitle, *GraphName));
|
*NodeTitle, *GraphName));
|
||||||
}
|
}
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Deleting node '%s' (%s) from graph '%s' in '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Deleting node '%s' (%s) from graph '%s'"),
|
||||||
*Node, *NodeTitle, *GraphName, *Blueprint);
|
*MCPUtils::FormatName(FoundNode), *NodeTitle, *GraphName);
|
||||||
|
|
||||||
FoundNode->BreakAllNodeLinks();
|
FoundNode->BreakAllNodeLinks();
|
||||||
Graph->RemoveNode(FoundNode);
|
Graph->RemoveNode(FoundNode);
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NodeDesc = Expr->GetClass()->GetName();
|
NodeDesc = MCPUtils::FormatName(Expr->GetClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the source node has input pins with connections, recurse
|
// If the source node has input pins with connections, recurse
|
||||||
@@ -170,7 +170,7 @@ public:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Non-material node (e.g., root, comment), just use title
|
// Non-material node (e.g., root, comment), just use title
|
||||||
NodeDesc = SourceNode->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
|
NodeDesc = MCPUtils::FormatName(SourceNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sources.Add(NodeDesc);
|
Sources.Add(NodeDesc);
|
||||||
@@ -201,7 +201,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (!Pin || Pin->Direction != EGPD_Input) continue;
|
if (!Pin || Pin->Direction != EGPD_Input) continue;
|
||||||
|
|
||||||
FString PinName = Pin->PinName.ToString();
|
FString PinName = MCPUtils::FormatName(Pin);
|
||||||
FString Description;
|
FString Description;
|
||||||
|
|
||||||
if (Pin->LinkedTo.Num() == 0)
|
if (Pin->LinkedTo.Num() == 0)
|
||||||
|
|||||||
@@ -117,13 +117,13 @@ public:
|
|||||||
for (UEdGraphNode* N : GA->Nodes)
|
for (UEdGraphNode* N : GA->Nodes)
|
||||||
{
|
{
|
||||||
if (!N) continue;
|
if (!N) continue;
|
||||||
FString Title = N->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
|
FString Title = MCPUtils::FormatName(N);
|
||||||
NodesA.FindOrAdd(Title).Add(N);
|
NodesA.FindOrAdd(Title).Add(N);
|
||||||
}
|
}
|
||||||
for (UEdGraphNode* N : GB->Nodes)
|
for (UEdGraphNode* N : GB->Nodes)
|
||||||
{
|
{
|
||||||
if (!N) continue;
|
if (!N) continue;
|
||||||
FString Title = N->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
|
FString Title = MCPUtils::FormatName(N);
|
||||||
NodesB.FindOrAdd(Title).Add(N);
|
NodesB.FindOrAdd(Title).Add(N);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ public:
|
|||||||
{
|
{
|
||||||
TSharedRef<FJsonObject> NObj = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> NObj = MakeShared<FJsonObject>();
|
||||||
NObj->SetStringField(TEXT("title"), Pair.Key);
|
NObj->SetStringField(TEXT("title"), Pair.Key);
|
||||||
NObj->SetStringField(TEXT("class"), Pair.Value[0]->GetClass()->GetName());
|
NObj->SetStringField(TEXT("class"), MCPUtils::FormatName(Pair.Value[0]->GetClass()));
|
||||||
NObj->SetNumberField(TEXT("extraCount"), CountA - CountB);
|
NObj->SetNumberField(TEXT("extraCount"), CountA - CountB);
|
||||||
OnlyInA.Add(MakeShared<FJsonValueObject>(NObj));
|
OnlyInA.Add(MakeShared<FJsonValueObject>(NObj));
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,7 @@ public:
|
|||||||
{
|
{
|
||||||
TSharedRef<FJsonObject> NObj = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> NObj = MakeShared<FJsonObject>();
|
||||||
NObj->SetStringField(TEXT("title"), Pair.Key);
|
NObj->SetStringField(TEXT("title"), Pair.Key);
|
||||||
NObj->SetStringField(TEXT("class"), Pair.Value[0]->GetClass()->GetName());
|
NObj->SetStringField(TEXT("class"), MCPUtils::FormatName(Pair.Value[0]->GetClass()));
|
||||||
NObj->SetNumberField(TEXT("extraCount"), CountB - CountA);
|
NObj->SetNumberField(TEXT("extraCount"), CountB - CountA);
|
||||||
OnlyInB.Add(MakeShared<FJsonValueObject>(NObj));
|
OnlyInB.Add(MakeShared<FJsonValueObject>(NObj));
|
||||||
}
|
}
|
||||||
@@ -170,9 +170,9 @@ public:
|
|||||||
// Connection diff: use connection key approach
|
// Connection diff: use connection key approach
|
||||||
auto MakeConnKey = [](UEdGraphPin* SrcPin, UEdGraphPin* TgtPin) -> FString
|
auto MakeConnKey = [](UEdGraphPin* SrcPin, UEdGraphPin* TgtPin) -> FString
|
||||||
{
|
{
|
||||||
FString SrcTitle = SrcPin->GetOwningNode()->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
|
FString SrcTitle = MCPUtils::FormatName(SrcPin->GetOwningNode());
|
||||||
FString TgtTitle = TgtPin->GetOwningNode()->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
|
FString TgtTitle = MCPUtils::FormatName(TgtPin->GetOwningNode());
|
||||||
return FString::Printf(TEXT("%s|%s|%s|%s"), *SrcTitle, *SrcPin->PinName.ToString(), *TgtTitle, *TgtPin->PinName.ToString());
|
return FString::Printf(TEXT("%s|%s|%s|%s"), *SrcTitle, *MCPUtils::FormatName(SrcPin), *TgtTitle, *MCPUtils::FormatName(TgtPin));
|
||||||
};
|
};
|
||||||
|
|
||||||
TSet<FString> ConnectionsA, ConnectionsB;
|
TSet<FString> ConnectionsA, ConnectionsB;
|
||||||
|
|||||||
@@ -2,15 +2,13 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "MCPHandler.h"
|
#include "MCPHandler.h"
|
||||||
#include "MCPAssetFinder.h"
|
#include "MCPFetcher.h"
|
||||||
#include "MCPUtils.h"
|
#include "MCPUtils.h"
|
||||||
#include "Engine/Blueprint.h"
|
#include "Engine/Blueprint.h"
|
||||||
#include "Engine/World.h"
|
|
||||||
#include "EdGraph/EdGraph.h"
|
|
||||||
#include "EdGraph/EdGraphNode.h"
|
#include "EdGraph/EdGraphNode.h"
|
||||||
#include "EdGraph/EdGraphPin.h"
|
#include "EdGraph/EdGraphPin.h"
|
||||||
#include "Kismet2/BlueprintEditorUtils.h"
|
#include "Kismet2/BlueprintEditorUtils.h"
|
||||||
#include "UMCPHandler_DisconnectBlueprintPins.generated.h"
|
#include "UMCPHandler_DisconnectPins.generated.h"
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -23,21 +21,15 @@ struct FDisconnectPinEntry
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
FString Node;
|
FString Pin;
|
||||||
|
|
||||||
UPROPERTY()
|
|
||||||
FString PinName;
|
|
||||||
|
|
||||||
UPROPERTY(meta=(Optional))
|
UPROPERTY(meta=(Optional))
|
||||||
FString TargetNode;
|
FString TargetPin;
|
||||||
|
|
||||||
UPROPERTY(meta=(Optional))
|
|
||||||
FString TargetPinName;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class UMCPHandler_DisconnectBlueprintPins : public UObject, public IMCPHandler
|
class UMCPHandler_DisconnectPins : public UObject, public IMCPHandler
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
@@ -45,7 +37,7 @@ public:
|
|||||||
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
||||||
FString Blueprint;
|
FString Blueprint;
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Array of {node, pinName, targetNode?, targetPinName?} objects. If target is omitted, all connections on the pin are broken."))
|
UPROPERTY(meta=(Description="Array of {pin, targetPin?} objects. Each pin is a path like node:MyNode,pin:Output. If targetPin is omitted, all connections on the pin are broken."))
|
||||||
FMCPJsonArray Disconnections;
|
FMCPJsonArray Disconnections;
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
virtual FString GetDescription() const override
|
||||||
@@ -57,9 +49,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
MCPAssets<UBlueprint> Assets;
|
MCPFetcher F(Result);
|
||||||
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||||
UBlueprint* BP = Assets.Object();
|
if (!BP) return;
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> Results;
|
TArray<TSharedPtr<FJsonValue>> Results;
|
||||||
int32 SuccessCount = 0;
|
int32 SuccessCount = 0;
|
||||||
@@ -73,45 +65,28 @@ public:
|
|||||||
FDisconnectPinEntry Entry;
|
FDisconnectPinEntry Entry;
|
||||||
if (!MCPUtils::PopulateFromJson(FDisconnectPinEntry::StaticStruct(), &Entry, DiscVal, &*EntryResult)) continue;
|
if (!MCPUtils::PopulateFromJson(FDisconnectPinEntry::StaticStruct(), &Entry, DiscVal, &*EntryResult)) continue;
|
||||||
|
|
||||||
UEdGraphNode* Node = MCPUtils::FindNodeByGuid(BP, Entry.Node);
|
MCPFetcher FP(EntryResult, BP);
|
||||||
if (!Node)
|
UEdGraphPin* Pin = FP.Walk(Entry.Pin).Cast<UEdGraphPin>();
|
||||||
{
|
if (!Pin) continue;
|
||||||
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;
|
int32 DisconnectedCount = 0;
|
||||||
|
|
||||||
if (!Entry.TargetNode.IsEmpty() && !Entry.TargetPinName.IsEmpty())
|
if (!Entry.TargetPin.IsEmpty())
|
||||||
{
|
{
|
||||||
UEdGraphNode* TargetNode = MCPUtils::FindNodeByGuid(BP, Entry.TargetNode);
|
MCPFetcher FT(EntryResult, BP);
|
||||||
if (!TargetNode)
|
UEdGraphPin* Target = FT.Walk(Entry.TargetPin).Cast<UEdGraphPin>();
|
||||||
|
if (!Target) continue;
|
||||||
|
|
||||||
|
if (!Pin->LinkedTo.Contains(Target))
|
||||||
{
|
{
|
||||||
EntryResult->SetStringField(TEXT("error"), FString::Printf(TEXT("Target node '%s' not found"), *Entry.TargetNode));
|
EntryResult->SetStringField(TEXT("error"), FString::Printf(
|
||||||
|
TEXT("%s.%s is not connected to %s.%s"),
|
||||||
|
*MCPUtils::FormatName(Pin->GetOwningNode()), *MCPUtils::FormatName(Pin),
|
||||||
|
*MCPUtils::FormatName(Target->GetOwningNode()), *MCPUtils::FormatName(Target)));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
UEdGraphPin* TargetPin = TargetNode->FindPin(FName(*Entry.TargetPinName));
|
Pin->BreakLinkTo(Target);
|
||||||
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;
|
DisconnectedCount = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2,24 +2,13 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "MCPHandler.h"
|
#include "MCPHandler.h"
|
||||||
#include "MCPAssetFinder.h"
|
#include "MCPFetcher.h"
|
||||||
#include "MCPUtils.h"
|
#include "MCPUtils.h"
|
||||||
#include "Engine/Blueprint.h"
|
#include "Engine/Blueprint.h"
|
||||||
#include "Engine/World.h"
|
#include "Animation/AnimBlueprint.h"
|
||||||
#include "Engine/Level.h"
|
#include "Animation/Skeleton.h"
|
||||||
#include "Engine/LevelScriptBlueprint.h"
|
#include "Engine/SimpleConstructionScript.h"
|
||||||
#include "EdGraph/EdGraph.h"
|
#include "Engine/SCS_Node.h"
|
||||||
#include "EdGraph/EdGraphNode.h"
|
|
||||||
#include "K2Node_CallFunction.h"
|
|
||||||
#include "K2Node_Event.h"
|
|
||||||
#include "K2Node_CustomEvent.h"
|
|
||||||
#include "K2Node_VariableGet.h"
|
|
||||||
#include "K2Node_VariableSet.h"
|
|
||||||
#include "K2Node_BreakStruct.h"
|
|
||||||
#include "K2Node_MakeStruct.h"
|
|
||||||
#include "K2Node_FunctionEntry.h"
|
|
||||||
#include "K2Node_EditablePinBase.h"
|
|
||||||
#include "AssetRegistry/IAssetRegistry.h"
|
|
||||||
#include "UMCPHandler_DumpBlueprint.generated.h"
|
#include "UMCPHandler_DumpBlueprint.generated.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -38,15 +27,77 @@ public:
|
|||||||
|
|
||||||
virtual FString GetDescription() const override
|
virtual FString GetDescription() const override
|
||||||
{
|
{
|
||||||
return TEXT("Load and serialize a Blueprint, returning its full structure including graphs, variables, and components.");
|
return TEXT("Dump a Blueprint's structure: variables, interfaces, components, "
|
||||||
|
"and graph names. Does not include graph contents (use DumpGraphs for that).");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
MCPAssets<UBlueprint> Assets;
|
MCPFetcher F(Result);
|
||||||
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||||
|
if (!BP) return;
|
||||||
|
|
||||||
TSharedRef<FJsonObject> Tmp = MCPUtils::SerializeBlueprint(Assets.Object());
|
Result->SetStringField(TEXT("name"), MCPUtils::FormatName(BP));
|
||||||
MCPUtils::CopyJsonFields(&*Tmp, Result);
|
Result->SetStringField(TEXT("parentClass"), BP->ParentClass ? MCPUtils::FormatName(BP->ParentClass) : TEXT("None"));
|
||||||
|
Result->SetStringField(TEXT("blueprintType"),
|
||||||
|
StaticEnum<EBlueprintType>()->GetNameStringByValue((int64)BP->BlueprintType));
|
||||||
|
|
||||||
|
// Animation Blueprint
|
||||||
|
if (UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP))
|
||||||
|
{
|
||||||
|
Result->SetBoolField(TEXT("isAnimBlueprint"), true);
|
||||||
|
if (AnimBP->TargetSkeleton)
|
||||||
|
{
|
||||||
|
Result->SetStringField(TEXT("targetSkeleton"), AnimBP->TargetSkeleton->GetName());
|
||||||
|
Result->SetStringField(TEXT("targetSkeletonPath"), AnimBP->TargetSkeleton->GetPathName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
TArray<TSharedPtr<FJsonValue>> Vars;
|
||||||
|
for (const FBPVariableDescription& V : BP->NewVariables)
|
||||||
|
{
|
||||||
|
TSharedRef<FJsonObject> VJ = MakeShared<FJsonObject>();
|
||||||
|
VJ->SetStringField(TEXT("name"), MCPUtils::FormatName(V));
|
||||||
|
VJ->SetStringField(TEXT("type"), V.VarType.PinCategory.ToString());
|
||||||
|
if (V.VarType.PinSubCategoryObject.IsValid())
|
||||||
|
VJ->SetStringField(TEXT("subtype"), V.VarType.PinSubCategoryObject->GetName());
|
||||||
|
VJ->SetBoolField(TEXT("isArray"), V.VarType.IsArray());
|
||||||
|
VJ->SetBoolField(TEXT("isSet"), V.VarType.IsSet());
|
||||||
|
VJ->SetBoolField(TEXT("isMap"), V.VarType.IsMap());
|
||||||
|
VJ->SetStringField(TEXT("category"), V.Category.ToString());
|
||||||
|
VJ->SetStringField(TEXT("defaultValue"), V.DefaultValue);
|
||||||
|
Vars.Add(MakeShared<FJsonValueObject>(VJ));
|
||||||
|
}
|
||||||
|
Result->SetArrayField(TEXT("variables"), Vars);
|
||||||
|
|
||||||
|
// Interfaces
|
||||||
|
TArray<TSharedPtr<FJsonValue>> Ifaces;
|
||||||
|
for (const FBPInterfaceDescription& I : BP->ImplementedInterfaces)
|
||||||
|
{
|
||||||
|
if (I.Interface)
|
||||||
|
Ifaces.Add(MakeShared<FJsonValueString>(MCPUtils::FormatName(I.Interface)));
|
||||||
|
}
|
||||||
|
Result->SetArrayField(TEXT("interfaces"), Ifaces);
|
||||||
|
|
||||||
|
// Components
|
||||||
|
if (USimpleConstructionScript* SCS = BP->SimpleConstructionScript)
|
||||||
|
{
|
||||||
|
TArray<TSharedPtr<FJsonValue>> Comps;
|
||||||
|
for (USCS_Node* Node : SCS->GetAllNodes())
|
||||||
|
{
|
||||||
|
if (!Node || !Node->ComponentTemplate) continue;
|
||||||
|
TSharedRef<FJsonObject> CJ = MakeShared<FJsonObject>();
|
||||||
|
CJ->SetStringField(TEXT("name"), MCPUtils::FormatName(Node->ComponentTemplate));
|
||||||
|
CJ->SetStringField(TEXT("class"), MCPUtils::FormatName(Node->ComponentClass));
|
||||||
|
if (Node->ParentComponentOrVariableName != NAME_None)
|
||||||
|
CJ->SetStringField(TEXT("parent"), Node->ParentComponentOrVariableName.ToString());
|
||||||
|
Comps.Add(MakeShared<FJsonValueObject>(CJ));
|
||||||
|
}
|
||||||
|
Result->SetArrayField(TEXT("components"), Comps);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Graph names (without contents)
|
||||||
|
Result->SetArrayField(TEXT("graphs"), MCPUtils::AllGraphNamesJson(BP));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
|
||||||
#include "MCPHandler.h"
|
|
||||||
#include "MCPAssetFinder.h"
|
|
||||||
#include "MCPUtils.h"
|
|
||||||
#include "Engine/Blueprint.h"
|
|
||||||
#include "Engine/World.h"
|
|
||||||
#include "Engine/Level.h"
|
|
||||||
#include "Engine/LevelScriptBlueprint.h"
|
|
||||||
#include "EdGraph/EdGraph.h"
|
|
||||||
#include "EdGraph/EdGraphNode.h"
|
|
||||||
#include "K2Node_CallFunction.h"
|
|
||||||
#include "K2Node_Event.h"
|
|
||||||
#include "K2Node_CustomEvent.h"
|
|
||||||
#include "K2Node_VariableGet.h"
|
|
||||||
#include "K2Node_VariableSet.h"
|
|
||||||
#include "K2Node_BreakStruct.h"
|
|
||||||
#include "K2Node_MakeStruct.h"
|
|
||||||
#include "K2Node_FunctionEntry.h"
|
|
||||||
#include "K2Node_EditablePinBase.h"
|
|
||||||
#include "AssetRegistry/IAssetRegistry.h"
|
|
||||||
#include "UMCPHandler_DumpBlueprintGraph.generated.h"
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
UCLASS()
|
|
||||||
class UMCPHandler_DumpBlueprintGraph : public UObject, public IMCPHandler
|
|
||||||
{
|
|
||||||
GENERATED_BODY()
|
|
||||||
|
|
||||||
public:
|
|
||||||
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
|
||||||
FString Blueprint;
|
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Graph name to dump"))
|
|
||||||
FString Graph;
|
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
|
||||||
{
|
|
||||||
return TEXT("Dump the detailed node/pin structure of a specific graph within a Blueprint.");
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
|
||||||
{
|
|
||||||
// URL-decode graph name to handle spaces encoded as '+' or '%20'
|
|
||||||
FString DecodedGraphName = MCPUtils::UrlDecode(Graph);
|
|
||||||
|
|
||||||
MCPAssets<UBlueprint> Assets;
|
|
||||||
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
|
||||||
UBlueprint* BP = Assets.Object();
|
|
||||||
|
|
||||||
TArray<UEdGraph*> AllGraphs = MCPUtils::AllGraphs(BP);
|
|
||||||
|
|
||||||
for (UEdGraph* GraphObj : AllGraphs)
|
|
||||||
{
|
|
||||||
if (GraphObj->GetName().Equals(DecodedGraphName, ESearchCase::IgnoreCase))
|
|
||||||
{
|
|
||||||
TSharedPtr<FJsonObject> GraphJson = MCPUtils::SerializeGraph(GraphObj);
|
|
||||||
if (GraphJson.IsValid())
|
|
||||||
{
|
|
||||||
MCPUtils::CopyJsonFields(GraphJson.Get(), Result);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not found — list available graphs
|
|
||||||
TArray<TSharedPtr<FJsonValue>> GraphNames;
|
|
||||||
for (UEdGraph* GraphObj : AllGraphs)
|
|
||||||
{
|
|
||||||
GraphNames.Add(MakeShared<FJsonValueString>(GraphObj->GetName()));
|
|
||||||
}
|
|
||||||
MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Graph '%s' not found"), *DecodedGraphName));
|
|
||||||
Result->SetArrayField(TEXT("availableGraphs"), GraphNames);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "MCPHandler.h"
|
||||||
|
#include "MCPFetcher.h"
|
||||||
|
#include "MCPUtils.h"
|
||||||
|
#include "BlueprintExporter.h"
|
||||||
|
#include "Engine/Blueprint.h"
|
||||||
|
#include "EdGraph/EdGraph.h"
|
||||||
|
#include "UMCPHandler_DumpGraphs.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UMCPHandler_DumpGraphs : public UObject, public IMCPHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Path to a blueprint or graph, e.g. /Game/Foo or /Game/Foo,graph:EventGraph"))
|
||||||
|
FString Path;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Dump blueprint graphs as readable text. "
|
||||||
|
"If given a blueprint, dumps all graphs. If given a specific graph, dumps only that one.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
|
||||||
|
{
|
||||||
|
MCPFetcher F(Result);
|
||||||
|
F.Walk(Path);
|
||||||
|
if (!F.Ok()) return;
|
||||||
|
|
||||||
|
if (UEdGraph* Graph = Cast<UEdGraph>(F.Obj))
|
||||||
|
{
|
||||||
|
EmitGraph(Graph, Result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UBlueprint* BP = Cast<UBlueprint>(F.Obj))
|
||||||
|
{
|
||||||
|
TArray<UEdGraph*> Graphs = MCPUtils::AllGraphs(BP);
|
||||||
|
for (UEdGraph* Graph : Graphs)
|
||||||
|
{
|
||||||
|
Result.Appendf(TEXT("\n======== %s ========\n"), *MCPUtils::FormatName(Graph));
|
||||||
|
EmitGraph(Graph, Result);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result.Appendf(TEXT("ERROR: Expected a blueprint or graph, got %s\n"),
|
||||||
|
*F.Obj->GetClass()->GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void EmitGraph(UEdGraph* Graph, FStringBuilderBase& Result)
|
||||||
|
{
|
||||||
|
FlxBlueprintExporter Exporter(Graph);
|
||||||
|
Result.Append(Exporter.GetOutput());
|
||||||
|
FString Details = Exporter.GetDetails();
|
||||||
|
if (!Details.IsEmpty())
|
||||||
|
{
|
||||||
|
Result.Append(TEXT("\n"));
|
||||||
|
Result.Append(Details);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -174,8 +174,8 @@ public:
|
|||||||
Entry->SetStringField(TEXT("newNodeId"), NewNode->NodeGuid.ToString());
|
Entry->SetStringField(TEXT("newNodeId"), NewNode->NodeGuid.ToString());
|
||||||
Entry->SetNumberField(TEXT("posX"), NewNode->NodePosX);
|
Entry->SetNumberField(TEXT("posX"), NewNode->NodePosX);
|
||||||
Entry->SetNumberField(TEXT("posY"), NewNode->NodePosY);
|
Entry->SetNumberField(TEXT("posY"), NewNode->NodePosY);
|
||||||
Entry->SetStringField(TEXT("nodeClass"), NewNode->GetClass()->GetName());
|
Entry->SetStringField(TEXT("nodeClass"), MCPUtils::FormatName(NewNode->GetClass()));
|
||||||
Entry->SetStringField(TEXT("nodeTitle"), NewNode->GetNodeTitle(ENodeTitleType::FullTitle).ToString());
|
Entry->SetStringField(TEXT("nodeTitle"), MCPUtils::FormatName(NewNode));
|
||||||
DuplicatedNodes.Add(MakeShared<FJsonValueObject>(Entry));
|
DuplicatedNodes.Add(MakeShared<FJsonValueObject>(Entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,52 +2,9 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "MCPHandler.h"
|
#include "MCPHandler.h"
|
||||||
#include "MCPAssetFinder.h"
|
#include "MCPFetcher.h"
|
||||||
#include "MCPServer.h"
|
|
||||||
#include "MCPUtils.h"
|
#include "MCPUtils.h"
|
||||||
#include "Engine/Blueprint.h"
|
|
||||||
#include "Materials/Material.h"
|
|
||||||
#include "Materials/MaterialInstanceConstant.h"
|
|
||||||
#include "Materials/MaterialFunction.h"
|
|
||||||
#include "Engine/World.h"
|
|
||||||
#include "Engine/LevelScriptBlueprint.h"
|
|
||||||
#include "EdGraph/EdGraph.h"
|
|
||||||
#include "EdGraph/EdGraphNode.h"
|
#include "EdGraph/EdGraphNode.h"
|
||||||
#include "EdGraph/EdGraphPin.h"
|
|
||||||
#include "EdGraphSchema_K2.h"
|
|
||||||
#include "K2Node.h"
|
|
||||||
#include "K2Node_CallFunction.h"
|
|
||||||
#include "K2Node_Event.h"
|
|
||||||
#include "K2Node_CustomEvent.h"
|
|
||||||
#include "K2Node_FunctionEntry.h"
|
|
||||||
#include "K2Node_EditablePinBase.h"
|
|
||||||
#include "K2Node_VariableGet.h"
|
|
||||||
#include "K2Node_VariableSet.h"
|
|
||||||
#include "K2Node_BreakStruct.h"
|
|
||||||
#include "K2Node_MakeStruct.h"
|
|
||||||
#include "K2Node_DynamicCast.h"
|
|
||||||
#include "K2Node_CallParentFunction.h"
|
|
||||||
#include "K2Node_IfThenElse.h"
|
|
||||||
#include "K2Node_ExecutionSequence.h"
|
|
||||||
#include "K2Node_MacroInstance.h"
|
|
||||||
#include "K2Node_SpawnActorFromClass.h"
|
|
||||||
#include "K2Node_Select.h"
|
|
||||||
#include "K2Node_Knot.h"
|
|
||||||
#include "EdGraphNode_Comment.h"
|
|
||||||
#include "GameFramework/Actor.h"
|
|
||||||
#include "Kismet2/BlueprintEditorUtils.h"
|
|
||||||
#include "Kismet2/KismetEditorUtilities.h"
|
|
||||||
#include "Serialization/JsonReader.h"
|
|
||||||
#include "Serialization/JsonWriter.h"
|
|
||||||
#include "Serialization/JsonSerializer.h"
|
|
||||||
#include "UObject/SavePackage.h"
|
|
||||||
#include "UObject/UObjectIterator.h"
|
|
||||||
#include "Misc/PackageName.h"
|
|
||||||
#include "AssetRegistry/AssetRegistryModule.h"
|
|
||||||
#include "AssetRegistry/IAssetRegistry.h"
|
|
||||||
#include "AssetToolsModule.h"
|
|
||||||
#include "IAssetTools.h"
|
|
||||||
#include "BlueprintNodeSpawner.h"
|
|
||||||
#include "UMCPHandler_GetNodeComment.generated.h"
|
#include "UMCPHandler_GetNodeComment.generated.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -61,10 +18,7 @@ class UMCPHandler_GetNodeComment : public UObject, public IMCPHandler
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
UPROPERTY(meta=(Description="Path to the node, e.g. /Game/Foo,node:MyNode"))
|
||||||
FString Blueprint;
|
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Node GUID"))
|
|
||||||
FString Node;
|
FString Node;
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
virtual FString GetDescription() const override
|
||||||
@@ -75,15 +29,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
MCPAssets<UBlueprint> Assets;
|
MCPFetcher F(Result);
|
||||||
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
UEdGraphNode* FoundNode = F.Walk(Node).Cast<UEdGraphNode>();
|
||||||
UBlueprint* BP = Assets.Object();
|
if (!FoundNode) return;
|
||||||
|
|
||||||
UEdGraphNode* FoundNode = MCPUtils::FindNodeByGuid(BP, Node);
|
|
||||||
if (!FoundNode)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Node '%s' not found"), *Node));
|
|
||||||
}
|
|
||||||
|
|
||||||
Result->SetStringField(TEXT("comment"), FoundNode->NodeComment);
|
Result->SetStringField(TEXT("comment"), FoundNode->NodeComment);
|
||||||
Result->SetBoolField(TEXT("commentBubbleVisible"), FoundNode->bCommentBubbleVisible);
|
Result->SetBoolField(TEXT("commentBubbleVisible"), FoundNode->bCommentBubbleVisible);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
UEdGraphPin* P = F.Walk(Pin).Cast<UEdGraphPin>();
|
UEdGraphPin* P = F.Walk(Pin).Cast<UEdGraphPin>();
|
||||||
if (!P) return;
|
if (!P) return;
|
||||||
|
|
||||||
Result->SetStringField(TEXT("pinName"), P->PinName.ToString());
|
Result->SetStringField(TEXT("pinName"), MCPUtils::FormatName(P));
|
||||||
Result->SetStringField(TEXT("direction"), P->Direction == EGPD_Input ? TEXT("Input") : TEXT("Output"));
|
Result->SetStringField(TEXT("direction"), P->Direction == EGPD_Input ? TEXT("Input") : TEXT("Output"));
|
||||||
Result->SetStringField(TEXT("type"), P->PinType.PinCategory.ToString());
|
Result->SetStringField(TEXT("type"), P->PinType.PinCategory.ToString());
|
||||||
|
|
||||||
@@ -79,8 +79,8 @@ public:
|
|||||||
if (!Linked || !Linked->GetOwningNode()) continue;
|
if (!Linked || !Linked->GetOwningNode()) continue;
|
||||||
TSharedRef<FJsonObject> CJ = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> CJ = MakeShared<FJsonObject>();
|
||||||
CJ->SetStringField(TEXT("nodeId"), Linked->GetOwningNode()->NodeGuid.ToString());
|
CJ->SetStringField(TEXT("nodeId"), Linked->GetOwningNode()->NodeGuid.ToString());
|
||||||
CJ->SetStringField(TEXT("pinName"), Linked->PinName.ToString());
|
CJ->SetStringField(TEXT("pinName"), MCPUtils::FormatName(Linked));
|
||||||
CJ->SetStringField(TEXT("nodeTitle"), Linked->GetOwningNode()->GetNodeTitle(ENodeTitleType::FullTitle).ToString());
|
CJ->SetStringField(TEXT("nodeTitle"), MCPUtils::FormatName(Linked->GetOwningNode()));
|
||||||
Conns.Add(MakeShared<FJsonValueObject>(CJ));
|
Conns.Add(MakeShared<FJsonValueObject>(CJ));
|
||||||
}
|
}
|
||||||
Result->SetArrayField(TEXT("connectedTo"), Conns);
|
Result->SetArrayField(TEXT("connectedTo"), Conns);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
|
|
||||||
if (Node->ComponentClass)
|
if (Node->ComponentClass)
|
||||||
{
|
{
|
||||||
CompObj->SetStringField(TEXT("componentClass"), Node->ComponentClass->GetName());
|
CompObj->SetStringField(TEXT("componentClass"), MCPUtils::FormatName(Node->ComponentClass));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
TSharedRef<FJsonObject> IfaceObj = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> IfaceObj = MakeShared<FJsonObject>();
|
||||||
IfaceObj->SetStringField(TEXT("name"), IfaceDesc.Interface->GetName());
|
IfaceObj->SetStringField(TEXT("name"), MCPUtils::FormatName(IfaceDesc.Interface));
|
||||||
IfaceObj->SetStringField(TEXT("classPath"), IfaceDesc.Interface->GetPathName());
|
IfaceObj->SetStringField(TEXT("classPath"), IfaceDesc.Interface->GetPathName());
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> FuncArr;
|
TArray<TSharedPtr<FJsonValue>> FuncArr;
|
||||||
@@ -55,7 +55,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (Graph)
|
if (Graph)
|
||||||
{
|
{
|
||||||
FuncArr.Add(MakeShared<FJsonValueString>(Graph->GetName()));
|
FuncArr.Add(MakeShared<FJsonValueString>(MCPUtils::FormatName(Graph)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IfaceObj->SetArrayField(TEXT("functions"), FuncArr);
|
IfaceObj->SetArrayField(TEXT("functions"), FuncArr);
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public:
|
|||||||
UClass* OwnerClass = Func->GetOwnerClass();
|
UClass* OwnerClass = Func->GetOwnerClass();
|
||||||
if (OwnerClass)
|
if (OwnerClass)
|
||||||
{
|
{
|
||||||
FuncObj->SetStringField(TEXT("definedIn"), OwnerClass->GetName());
|
FuncObj->SetStringField(TEXT("definedIn"), MCPUtils::FormatName(OwnerClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function flags
|
// Function flags
|
||||||
@@ -124,7 +124,7 @@ public:
|
|||||||
FuncList.Add(MakeShared<FJsonValueObject>(FuncObj));
|
FuncList.Add(MakeShared<FJsonValueObject>(FuncObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetStringField(TEXT("className"), FoundClass->GetName());
|
Result->SetStringField(TEXT("className"), MCPUtils::FormatName(FoundClass));
|
||||||
Result->SetNumberField(TEXT("count"), FuncList.Num());
|
Result->SetNumberField(TEXT("count"), FuncList.Num());
|
||||||
Result->SetArrayField(TEXT("functions"), FuncList);
|
Result->SetArrayField(TEXT("functions"), FuncList);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public:
|
|||||||
UClass* OwnerClass = Prop->GetOwnerClass();
|
UClass* OwnerClass = Prop->GetOwnerClass();
|
||||||
if (OwnerClass)
|
if (OwnerClass)
|
||||||
{
|
{
|
||||||
PropObj->SetStringField(TEXT("definedIn"), OwnerClass->GetName());
|
PropObj->SetStringField(TEXT("definedIn"), MCPUtils::FormatName(OwnerClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Property flags
|
// Property flags
|
||||||
@@ -99,7 +99,7 @@ public:
|
|||||||
PropList.Add(MakeShared<FJsonValueObject>(PropObj));
|
PropList.Add(MakeShared<FJsonValueObject>(PropObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetStringField(TEXT("className"), FoundClass->GetName());
|
Result->SetStringField(TEXT("className"), MCPUtils::FormatName(FoundClass));
|
||||||
Result->SetNumberField(TEXT("count"), PropList.Num());
|
Result->SetNumberField(TEXT("count"), PropList.Num());
|
||||||
Result->SetArrayField(TEXT("properties"), PropList);
|
Result->SetArrayField(TEXT("properties"), PropList);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,9 +128,9 @@ public:
|
|||||||
{
|
{
|
||||||
if (Node->bHasCompilerMessage)
|
if (Node->bHasCompilerMessage)
|
||||||
{
|
{
|
||||||
FString NodeTitle = Node->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
|
FString NodeTitle = MCPUtils::FormatName(Node);
|
||||||
FString NodeMsg = FString::Printf(TEXT("[%s] %s: %s"),
|
FString NodeMsg = FString::Printf(TEXT("[%s] %s: %s"),
|
||||||
*Node->GetGraph()->GetName(), *NodeTitle, *Node->ErrorMsg);
|
*MCPUtils::FormatName(Node->GetGraph()), *NodeTitle, *Node->ErrorMsg);
|
||||||
if (Node->ErrorType == EMessageSeverity::Error)
|
if (Node->ErrorType == EMessageSeverity::Error)
|
||||||
{
|
{
|
||||||
ErrorsArr.Add(MakeShared<FJsonValueString>(NodeMsg));
|
ErrorsArr.Add(MakeShared<FJsonValueString>(NodeMsg));
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (IfaceDesc.Interface)
|
if (IfaceDesc.Interface)
|
||||||
{
|
{
|
||||||
IfaceList.Add(MakeShared<FJsonValueString>(IfaceDesc.Interface->GetName()));
|
IfaceList.Add(MakeShared<FJsonValueString>(MCPUtils::FormatName(IfaceDesc.Interface)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ public:
|
|||||||
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(), *Blueprint, PreserveFunctions ? TEXT("true") : TEXT("false"));
|
*MCPUtils::FormatName(FoundInterface), *Blueprint, PreserveFunctions ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
FBlueprintEditorUtils::RemoveInterface(BP, InterfacePath, PreserveFunctions);
|
FBlueprintEditorUtils::RemoveInterface(BP, InterfacePath, PreserveFunctions);
|
||||||
|
|
||||||
@@ -102,8 +102,8 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removed interface '%s' from '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removed interface '%s' from '%s'"),
|
||||||
*FoundInterface->GetName(), *Blueprint);
|
*MCPUtils::FormatName(FoundInterface), *Blueprint);
|
||||||
|
|
||||||
Result->SetStringField(TEXT("interfaceName"), FoundInterface->GetName());
|
Result->SetStringField(TEXT("interfaceName"), MCPUtils::FormatName(FoundInterface));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public:
|
|||||||
// Strategy 1: Look for a K2Node_FunctionEntry in a function graph matching the name
|
// Strategy 1: Look for a K2Node_FunctionEntry in a function graph matching the name
|
||||||
for (UK2Node_FunctionEntry* FuncEntry : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
for (UK2Node_FunctionEntry* FuncEntry : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
||||||
{
|
{
|
||||||
if (FuncEntry->GetGraph()->GetName().Equals(FunctionName, ESearchCase::IgnoreCase))
|
if (MCPUtils::Identifies(FunctionName, FuncEntry->GetGraph()))
|
||||||
{
|
{
|
||||||
EntryNode = FuncEntry;
|
EntryNode = FuncEntry;
|
||||||
FoundNodeType = TEXT("FunctionEntry");
|
FoundNodeType = TEXT("FunctionEntry");
|
||||||
@@ -80,7 +80,7 @@ public:
|
|||||||
for (UK2Node_FunctionEntry* FE : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
for (UK2Node_FunctionEntry* FE : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
|
||||||
{
|
{
|
||||||
Available.Add(MakeShared<FJsonValueString>(
|
Available.Add(MakeShared<FJsonValueString>(
|
||||||
FString::Printf(TEXT("function:%s"), *FE->GetGraph()->GetName())));
|
FString::Printf(TEXT("function:%s"), *MCPUtils::FormatName(FE->GetGraph()))));
|
||||||
}
|
}
|
||||||
for (UK2Node_CustomEvent* CE : MCPUtils::AllNodes<UK2Node_CustomEvent>(BP))
|
for (UK2Node_CustomEvent* CE : MCPUtils::AllNodes<UK2Node_CustomEvent>(BP))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public:
|
|||||||
// Check if it's an UbergraphPage — disallow rename
|
// Check if it's an UbergraphPage — disallow rename
|
||||||
for (UEdGraph* CandidateGraph : BP->UbergraphPages)
|
for (UEdGraph* CandidateGraph : BP->UbergraphPages)
|
||||||
{
|
{
|
||||||
if (CandidateGraph && CandidateGraph->GetName().Equals(Graph, ESearchCase::IgnoreCase))
|
if (CandidateGraph && MCPUtils::Identifies(Graph, CandidateGraph))
|
||||||
{
|
{
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
||||||
TEXT("Cannot rename UbergraphPage '%s'. EventGraph and other Ubergraph pages cannot be renamed."),
|
TEXT("Cannot rename UbergraphPage '%s'. EventGraph and other Ubergraph pages cannot be renamed."),
|
||||||
@@ -62,7 +62,7 @@ public:
|
|||||||
|
|
||||||
for (UEdGraph* CandidateGraph : BP->FunctionGraphs)
|
for (UEdGraph* CandidateGraph : BP->FunctionGraphs)
|
||||||
{
|
{
|
||||||
if (CandidateGraph && CandidateGraph->GetName().Equals(Graph, ESearchCase::IgnoreCase))
|
if (CandidateGraph && MCPUtils::Identifies(Graph, CandidateGraph))
|
||||||
{
|
{
|
||||||
TargetGraph = CandidateGraph;
|
TargetGraph = CandidateGraph;
|
||||||
GraphType = TEXT("function");
|
GraphType = TEXT("function");
|
||||||
@@ -73,7 +73,7 @@ public:
|
|||||||
{
|
{
|
||||||
for (UEdGraph* CandidateGraph : BP->MacroGraphs)
|
for (UEdGraph* CandidateGraph : BP->MacroGraphs)
|
||||||
{
|
{
|
||||||
if (CandidateGraph && CandidateGraph->GetName().Equals(Graph, ESearchCase::IgnoreCase))
|
if (CandidateGraph && MCPUtils::Identifies(Graph, CandidateGraph))
|
||||||
{
|
{
|
||||||
TargetGraph = CandidateGraph;
|
TargetGraph = CandidateGraph;
|
||||||
GraphType = TEXT("macro");
|
GraphType = TEXT("macro");
|
||||||
@@ -108,7 +108,7 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Renamed graph '%s' to '%s', save %s"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Renamed graph '%s' to '%s', save %s"),
|
||||||
*Graph, *NewName, bSaved ? TEXT("true") : TEXT("false"));
|
*Graph, *NewName, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetStringField(TEXT("newName"), TargetGraph->GetName());
|
Result->SetStringField(TEXT("newName"), MCPUtils::FormatName(TargetGraph));
|
||||||
Result->SetStringField(TEXT("graphType"), GraphType);
|
Result->SetStringField(TEXT("graphType"), GraphType);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UBlueprint* BP = Assets.Object();
|
UBlueprint* BP = Assets.Object();
|
||||||
|
|
||||||
FString OldParentName = BP->ParentClass ? BP->ParentClass->GetName() : TEXT("None");
|
FString OldParentName = BP->ParentClass ? MCPUtils::FormatName(BP->ParentClass) : TEXT("None");
|
||||||
|
|
||||||
// Find the new parent class
|
// Find the new parent class
|
||||||
// Try C++ class first (e.g. "WebUIHUD" finds /Script/ModuleName.WebUIHUD)
|
// Try C++ class first (e.g. "WebUIHUD" finds /Script/ModuleName.WebUIHUD)
|
||||||
@@ -85,11 +85,11 @@ public:
|
|||||||
// Just warn, don't block — the user may intentionally reparent to a sibling
|
// Just warn, don't block — the user may intentionally reparent to a sibling
|
||||||
UE_LOG(LogTemp, Warning,
|
UE_LOG(LogTemp, Warning,
|
||||||
TEXT("BlueprintMCP: Reparenting '%s' from '%s' to '%s' — classes are not in a direct hierarchy"),
|
TEXT("BlueprintMCP: Reparenting '%s' from '%s' to '%s' — classes are not in a direct hierarchy"),
|
||||||
*Blueprint, *OldParentName, *NewParentClassObj->GetName());
|
*Blueprint, *OldParentName, *MCPUtils::FormatName(NewParentClassObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Reparenting '%s' from '%s' to '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Reparenting '%s' from '%s' to '%s'"),
|
||||||
*Blueprint, *OldParentName, *NewParentClassObj->GetName());
|
*Blueprint, *OldParentName, *MCPUtils::FormatName(NewParentClassObj));
|
||||||
|
|
||||||
// Perform reparent
|
// Perform reparent
|
||||||
BP->PreEditChange(nullptr);
|
BP->PreEditChange(nullptr);
|
||||||
@@ -105,7 +105,7 @@ public:
|
|||||||
// Save
|
// Save
|
||||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||||
|
|
||||||
FString NewParentActualName = NewParentClassObj->GetName();
|
FString NewParentActualName = MCPUtils::FormatName(NewParentClassObj);
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Reparent complete, save %s"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Reparent complete, save %s"),
|
||||||
bSaved ? TEXT("succeeded") : TEXT("failed"));
|
bSaved ? TEXT("succeeded") : TEXT("failed"));
|
||||||
|
|||||||
@@ -202,9 +202,9 @@ public:
|
|||||||
AtRisk->SetStringField(TEXT("type"), TEXT("connectionAtRisk"));
|
AtRisk->SetStringField(TEXT("type"), TEXT("connectionAtRisk"));
|
||||||
AtRisk->SetStringField(TEXT("functionName"), FuncName.ToString());
|
AtRisk->SetStringField(TEXT("functionName"), FuncName.ToString());
|
||||||
AtRisk->SetStringField(TEXT("nodeId"), CallNode->NodeGuid.ToString());
|
AtRisk->SetStringField(TEXT("nodeId"), CallNode->NodeGuid.ToString());
|
||||||
AtRisk->SetStringField(TEXT("pinName"), Pin->PinName.ToString());
|
AtRisk->SetStringField(TEXT("pinName"), MCPUtils::FormatName(Pin));
|
||||||
AtRisk->SetStringField(TEXT("connectedToNode"), Linked->GetOwningNode()->NodeGuid.ToString());
|
AtRisk->SetStringField(TEXT("connectedToNode"), Linked->GetOwningNode()->NodeGuid.ToString());
|
||||||
AtRisk->SetStringField(TEXT("connectedToPin"), Linked->PinName.ToString());
|
AtRisk->SetStringField(TEXT("connectedToPin"), MCPUtils::FormatName(Linked));
|
||||||
BrokenConnections.Add(MakeShared<FJsonValueObject>(AtRisk));
|
BrokenConnections.Add(MakeShared<FJsonValueObject>(AtRisk));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "MCPHandler.h"
|
||||||
|
#include "MCPAssetFinder.h"
|
||||||
|
#include "MCPUtils.h"
|
||||||
|
#include "UMCPHandler_SearchAssets.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UMCPHandler_SearchAssets : public UObject, public IMCPHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Optional, Description="Substring to match against asset package paths"))
|
||||||
|
FString Search;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Optional, Description="Asset class name to filter by, e.g. Blueprint, Material, StaticMesh"))
|
||||||
|
FString Type;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Optional, Description="Maximum number of results (default 50)"))
|
||||||
|
int32 Limit = 50;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Search for assets by name and/or type. At least one of Search or Type must be specified.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
|
||||||
|
{
|
||||||
|
if (Search.IsEmpty() && Type.IsEmpty())
|
||||||
|
{
|
||||||
|
Result.Append(TEXT("ERROR: At least one of Search or Type must be specified\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCPAssets<UObject> Assets;
|
||||||
|
|
||||||
|
// If a type is specified, find the UClass and filter by it
|
||||||
|
if (!Type.IsEmpty())
|
||||||
|
{
|
||||||
|
UClass* TypeClass = MCPUtils::FindClassByName(Type);
|
||||||
|
if (!TypeClass)
|
||||||
|
{
|
||||||
|
Result.Appendf(TEXT("ERROR: Unknown asset type '%s'\n"), *Type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Assets.NoScans().Scan(TypeClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Search.IsEmpty())
|
||||||
|
{
|
||||||
|
Assets.Substring(Search);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assets.AllContent().Limit(Limit).Errors(Result).Info();
|
||||||
|
|
||||||
|
const TArray<FAssetData>& AllData = Assets.AllData();
|
||||||
|
for (const FAssetData& Data : AllData)
|
||||||
|
{
|
||||||
|
Result.Appendf(TEXT("%s %s\n"),
|
||||||
|
*Data.AssetClassPath.GetAssetName().ToString(),
|
||||||
|
*Data.PackageName.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AllData.Num() >= Limit)
|
||||||
|
{
|
||||||
|
Result.Appendf(TEXT("WARNING: You reached the limit of %d, to raise it, specify the Limit parameter.\n"), Limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -125,7 +125,7 @@ public:
|
|||||||
R->SetStringField(TEXT("blueprintPath"), BPPath);
|
R->SetStringField(TEXT("blueprintPath"), BPPath);
|
||||||
R->SetStringField(TEXT("usage"), TEXT("functionParameter"));
|
R->SetStringField(TEXT("usage"), TEXT("functionParameter"));
|
||||||
R->SetStringField(TEXT("location"), FString::Printf(TEXT("%s.%s"),
|
R->SetStringField(TEXT("location"), FString::Printf(TEXT("%s.%s"),
|
||||||
*Node->GetGraph()->GetName(), *PinInfo->PinName.ToString()));
|
*MCPUtils::FormatName(Node->GetGraph()), *PinInfo->PinName.ToString()));
|
||||||
R->SetStringField(TEXT("nodeId"), Node->NodeGuid.ToString());
|
R->SetStringField(TEXT("nodeId"), Node->NodeGuid.ToString());
|
||||||
R->SetStringField(TEXT("currentType"), PinInfo->PinType.PinCategory.ToString());
|
R->SetStringField(TEXT("currentType"), PinInfo->PinType.PinCategory.ToString());
|
||||||
if (!ParamSubtype.IsEmpty())
|
if (!ParamSubtype.IsEmpty())
|
||||||
@@ -172,7 +172,7 @@ public:
|
|||||||
R->SetStringField(TEXT("blueprint"), BPName);
|
R->SetStringField(TEXT("blueprint"), BPName);
|
||||||
R->SetStringField(TEXT("blueprintPath"), BPPath);
|
R->SetStringField(TEXT("blueprintPath"), BPPath);
|
||||||
R->SetStringField(TEXT("usage"), TEXT("breakStruct"));
|
R->SetStringField(TEXT("usage"), TEXT("breakStruct"));
|
||||||
R->SetStringField(TEXT("location"), Node->GetGraph()->GetName());
|
R->SetStringField(TEXT("location"), MCPUtils::FormatName(Node->GetGraph()));
|
||||||
R->SetStringField(TEXT("nodeId"), Node->NodeGuid.ToString());
|
R->SetStringField(TEXT("nodeId"), Node->NodeGuid.ToString());
|
||||||
R->SetStringField(TEXT("structType"), BreakNode->StructType->GetName());
|
R->SetStringField(TEXT("structType"), BreakNode->StructType->GetName());
|
||||||
if (bIsLevel)
|
if (bIsLevel)
|
||||||
@@ -188,7 +188,7 @@ public:
|
|||||||
R->SetStringField(TEXT("blueprint"), BPName);
|
R->SetStringField(TEXT("blueprint"), BPName);
|
||||||
R->SetStringField(TEXT("blueprintPath"), BPPath);
|
R->SetStringField(TEXT("blueprintPath"), BPPath);
|
||||||
R->SetStringField(TEXT("usage"), TEXT("makeStruct"));
|
R->SetStringField(TEXT("usage"), TEXT("makeStruct"));
|
||||||
R->SetStringField(TEXT("location"), Node->GetGraph()->GetName());
|
R->SetStringField(TEXT("location"), MCPUtils::FormatName(Node->GetGraph()));
|
||||||
R->SetStringField(TEXT("nodeId"), Node->NodeGuid.ToString());
|
R->SetStringField(TEXT("nodeId"), Node->NodeGuid.ToString());
|
||||||
R->SetStringField(TEXT("structType"), MakeNode->StructType->GetName());
|
R->SetStringField(TEXT("structType"), MakeNode->StructType->GetName());
|
||||||
if (bIsLevel)
|
if (bIsLevel)
|
||||||
@@ -214,10 +214,10 @@ public:
|
|||||||
R->SetStringField(TEXT("blueprintPath"), BPPath);
|
R->SetStringField(TEXT("blueprintPath"), BPPath);
|
||||||
R->SetStringField(TEXT("usage"), TEXT("pinConnection"));
|
R->SetStringField(TEXT("usage"), TEXT("pinConnection"));
|
||||||
R->SetStringField(TEXT("location"), FString::Printf(TEXT("%s.%s"),
|
R->SetStringField(TEXT("location"), FString::Printf(TEXT("%s.%s"),
|
||||||
*Node->GetNodeTitle(ENodeTitleType::FullTitle).ToString(),
|
*MCPUtils::FormatName(Node),
|
||||||
*Pin->PinName.ToString()));
|
*MCPUtils::FormatName(Pin)));
|
||||||
R->SetStringField(TEXT("nodeId"), Node->NodeGuid.ToString());
|
R->SetStringField(TEXT("nodeId"), Node->NodeGuid.ToString());
|
||||||
R->SetStringField(TEXT("graph"), Node->GetGraph()->GetName());
|
R->SetStringField(TEXT("graph"), MCPUtils::FormatName(Node->GetGraph()));
|
||||||
R->SetStringField(TEXT("pinType"), Pin->PinType.PinCategory.ToString());
|
R->SetStringField(TEXT("pinType"), Pin->PinType.PinCategory.ToString());
|
||||||
if (!PinSubtype.IsEmpty())
|
if (!PinSubtype.IsEmpty())
|
||||||
R->SetStringField(TEXT("pinSubtype"), PinSubtype);
|
R->SetStringField(TEXT("pinSubtype"), PinSubtype);
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ public:
|
|||||||
if (ClassList.Num() >= Limit) continue; // Count but don't add beyond limit
|
if (ClassList.Num() >= Limit) continue; // Count but don't add beyond limit
|
||||||
|
|
||||||
TSharedRef<FJsonObject> ClassObj = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> ClassObj = MakeShared<FJsonObject>();
|
||||||
ClassObj->SetStringField(TEXT("name"), ClassName);
|
ClassObj->SetStringField(TEXT("name"), MCPUtils::FormatName(Class));
|
||||||
ClassObj->SetStringField(TEXT("fullPath"), Class->GetPathName());
|
ClassObj->SetStringField(TEXT("fullPath"), Class->GetPathName());
|
||||||
|
|
||||||
// Determine if it's a Blueprint-generated class
|
// Determine if it's a Blueprint-generated class
|
||||||
@@ -102,7 +102,7 @@ public:
|
|||||||
// Parent class
|
// Parent class
|
||||||
if (Class->GetSuperClass())
|
if (Class->GetSuperClass())
|
||||||
{
|
{
|
||||||
ClassObj->SetStringField(TEXT("parentClass"), Class->GetSuperClass()->GetName());
|
ClassObj->SetStringField(TEXT("parentClass"), MCPUtils::FormatName(Class->GetSuperClass()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module/package info
|
// Module/package info
|
||||||
|
|||||||
@@ -92,9 +92,9 @@ public:
|
|||||||
TSharedRef<FJsonObject> R = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> R = MakeShared<FJsonObject>();
|
||||||
R->SetStringField(TEXT("blueprint"), AssetName);
|
R->SetStringField(TEXT("blueprint"), AssetName);
|
||||||
R->SetStringField(TEXT("blueprintPath"), AssetPath);
|
R->SetStringField(TEXT("blueprintPath"), AssetPath);
|
||||||
R->SetStringField(TEXT("graph"), Node->GetGraph()->GetName());
|
R->SetStringField(TEXT("graph"), MCPUtils::FormatName(Node->GetGraph()));
|
||||||
R->SetStringField(TEXT("nodeTitle"), Title);
|
R->SetStringField(TEXT("nodeTitle"), MCPUtils::FormatName(Node));
|
||||||
R->SetStringField(TEXT("nodeClass"), Node->GetClass()->GetName());
|
R->SetStringField(TEXT("nodeClass"), MCPUtils::FormatName(Node->GetClass()));
|
||||||
if (!FuncName.IsEmpty()) R->SetStringField(TEXT("functionName"), FuncName);
|
if (!FuncName.IsEmpty()) R->SetStringField(TEXT("functionName"), FuncName);
|
||||||
if (!EventName.IsEmpty()) R->SetStringField(TEXT("eventName"), EventName);
|
if (!EventName.IsEmpty()) R->SetStringField(TEXT("eventName"), EventName);
|
||||||
if (!VarName.IsEmpty()) R->SetStringField(TEXT("variableName"), VarName);
|
if (!VarName.IsEmpty()) R->SetStringField(TEXT("variableName"), VarName);
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ public:
|
|||||||
{
|
{
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
||||||
TEXT("'%s' is not a subclass of '%s' (required by property '%s')"),
|
TEXT("'%s' is not a subclass of '%s' (required by property '%s')"),
|
||||||
*ResolvedClass->GetName(), *MetaClass->GetName(), *Property));
|
*MCPUtils::FormatName(ResolvedClass), *MCPUtils::FormatName(MetaClass), *Property));
|
||||||
}
|
}
|
||||||
ClassProp->SetPropertyValue_InContainer(CDO, ResolvedClass);
|
ClassProp->SetPropertyValue_InContainer(CDO, ResolvedClass);
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ public:
|
|||||||
FSoftObjectPtr SoftPtr(ResolvedClass);
|
FSoftObjectPtr SoftPtr(ResolvedClass);
|
||||||
SoftClassProp->SetPropertyValue_InContainer(CDO, SoftPtr);
|
SoftClassProp->SetPropertyValue_InContainer(CDO, SoftPtr);
|
||||||
}
|
}
|
||||||
ActualNewValue = ResolvedClass->GetName();
|
ActualNewValue = MCPUtils::FormatName(ResolvedClass);
|
||||||
bSuccess = true;
|
bSuccess = true;
|
||||||
}
|
}
|
||||||
// Handle object properties (TObjectPtr, UObject*)
|
// Handle object properties (TObjectPtr, UObject*)
|
||||||
|
|||||||
@@ -2,52 +2,10 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "MCPHandler.h"
|
#include "MCPHandler.h"
|
||||||
#include "MCPAssetFinder.h"
|
#include "MCPFetcher.h"
|
||||||
#include "MCPServer.h"
|
|
||||||
#include "MCPUtils.h"
|
#include "MCPUtils.h"
|
||||||
#include "Engine/Blueprint.h"
|
|
||||||
#include "Materials/Material.h"
|
|
||||||
#include "Materials/MaterialInstanceConstant.h"
|
|
||||||
#include "Materials/MaterialFunction.h"
|
|
||||||
#include "Engine/World.h"
|
|
||||||
#include "Engine/LevelScriptBlueprint.h"
|
|
||||||
#include "EdGraph/EdGraph.h"
|
|
||||||
#include "EdGraph/EdGraphNode.h"
|
#include "EdGraph/EdGraphNode.h"
|
||||||
#include "EdGraph/EdGraphPin.h"
|
|
||||||
#include "EdGraphSchema_K2.h"
|
|
||||||
#include "K2Node.h"
|
|
||||||
#include "K2Node_CallFunction.h"
|
|
||||||
#include "K2Node_Event.h"
|
|
||||||
#include "K2Node_CustomEvent.h"
|
|
||||||
#include "K2Node_FunctionEntry.h"
|
|
||||||
#include "K2Node_EditablePinBase.h"
|
|
||||||
#include "K2Node_VariableGet.h"
|
|
||||||
#include "K2Node_VariableSet.h"
|
|
||||||
#include "K2Node_BreakStruct.h"
|
|
||||||
#include "K2Node_MakeStruct.h"
|
|
||||||
#include "K2Node_DynamicCast.h"
|
|
||||||
#include "K2Node_CallParentFunction.h"
|
|
||||||
#include "K2Node_IfThenElse.h"
|
|
||||||
#include "K2Node_ExecutionSequence.h"
|
|
||||||
#include "K2Node_MacroInstance.h"
|
|
||||||
#include "K2Node_SpawnActorFromClass.h"
|
|
||||||
#include "K2Node_Select.h"
|
|
||||||
#include "K2Node_Knot.h"
|
|
||||||
#include "EdGraphNode_Comment.h"
|
|
||||||
#include "GameFramework/Actor.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/SavePackage.h"
|
|
||||||
#include "UObject/UObjectIterator.h"
|
|
||||||
#include "Misc/PackageName.h"
|
|
||||||
#include "AssetRegistry/AssetRegistryModule.h"
|
|
||||||
#include "AssetRegistry/IAssetRegistry.h"
|
|
||||||
#include "AssetToolsModule.h"
|
|
||||||
#include "IAssetTools.h"
|
|
||||||
#include "BlueprintNodeSpawner.h"
|
|
||||||
#include "UMCPHandler_SetNodeComment.generated.h"
|
#include "UMCPHandler_SetNodeComment.generated.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -61,10 +19,7 @@ class UMCPHandler_SetNodeComment : public UObject, public IMCPHandler
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
UPROPERTY(meta=(Description="Path to the node, e.g. /Game/Foo,node:MyNode"))
|
||||||
FString Blueprint;
|
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Node GUID"))
|
|
||||||
FString Node;
|
FString Node;
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Comment text to set"))
|
UPROPERTY(meta=(Description="Comment text to set"))
|
||||||
@@ -78,15 +33,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
MCPAssets<UBlueprint> Assets;
|
MCPFetcher F(Result);
|
||||||
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
UEdGraphNode* FoundNode = F.Walk(Node).Cast<UEdGraphNode>();
|
||||||
UBlueprint* BP = Assets.Object();
|
if (!FoundNode) return;
|
||||||
|
|
||||||
UEdGraphNode* FoundNode = MCPUtils::FindNodeByGuid(BP, Node);
|
|
||||||
if (!FoundNode)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Node '%s' not found"), *Node));
|
|
||||||
}
|
|
||||||
|
|
||||||
FString OldComment = FoundNode->NodeComment;
|
FString OldComment = FoundNode->NodeComment;
|
||||||
FoundNode->NodeComment = Comment;
|
FoundNode->NodeComment = Comment;
|
||||||
@@ -98,10 +47,11 @@ public:
|
|||||||
FoundNode->bCommentBubblePinned = true;
|
FoundNode->bCommentBubblePinned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UBlueprint* BP = FBlueprintEditorUtils::FindBlueprintForNodeChecked(FoundNode);
|
||||||
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
|
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Set comment on node '%s' in '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Set comment on node '%s'"),
|
||||||
*Node, *Blueprint);
|
*MCPUtils::FormatName(FoundNode));
|
||||||
|
|
||||||
Result->SetStringField(TEXT("oldComment"), OldComment);
|
Result->SetStringField(TEXT("oldComment"), OldComment);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,52 +2,11 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "MCPHandler.h"
|
#include "MCPHandler.h"
|
||||||
#include "MCPAssetFinder.h"
|
#include "MCPFetcher.h"
|
||||||
#include "MCPServer.h"
|
|
||||||
#include "MCPUtils.h"
|
#include "MCPUtils.h"
|
||||||
#include "Engine/Blueprint.h"
|
#include "Engine/Blueprint.h"
|
||||||
#include "Materials/Material.h"
|
|
||||||
#include "Materials/MaterialInstanceConstant.h"
|
|
||||||
#include "Materials/MaterialFunction.h"
|
|
||||||
#include "Engine/World.h"
|
|
||||||
#include "Engine/LevelScriptBlueprint.h"
|
|
||||||
#include "EdGraph/EdGraph.h"
|
|
||||||
#include "EdGraph/EdGraphNode.h"
|
#include "EdGraph/EdGraphNode.h"
|
||||||
#include "EdGraph/EdGraphPin.h"
|
|
||||||
#include "EdGraphSchema_K2.h"
|
|
||||||
#include "K2Node.h"
|
|
||||||
#include "K2Node_CallFunction.h"
|
|
||||||
#include "K2Node_Event.h"
|
|
||||||
#include "K2Node_CustomEvent.h"
|
|
||||||
#include "K2Node_FunctionEntry.h"
|
|
||||||
#include "K2Node_EditablePinBase.h"
|
|
||||||
#include "K2Node_VariableGet.h"
|
|
||||||
#include "K2Node_VariableSet.h"
|
|
||||||
#include "K2Node_BreakStruct.h"
|
|
||||||
#include "K2Node_MakeStruct.h"
|
|
||||||
#include "K2Node_DynamicCast.h"
|
|
||||||
#include "K2Node_CallParentFunction.h"
|
|
||||||
#include "K2Node_IfThenElse.h"
|
|
||||||
#include "K2Node_ExecutionSequence.h"
|
|
||||||
#include "K2Node_MacroInstance.h"
|
|
||||||
#include "K2Node_SpawnActorFromClass.h"
|
|
||||||
#include "K2Node_Select.h"
|
|
||||||
#include "K2Node_Knot.h"
|
|
||||||
#include "EdGraphNode_Comment.h"
|
|
||||||
#include "GameFramework/Actor.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/SavePackage.h"
|
|
||||||
#include "UObject/UObjectIterator.h"
|
|
||||||
#include "Misc/PackageName.h"
|
|
||||||
#include "AssetRegistry/AssetRegistryModule.h"
|
|
||||||
#include "AssetRegistry/IAssetRegistry.h"
|
|
||||||
#include "AssetToolsModule.h"
|
|
||||||
#include "IAssetTools.h"
|
|
||||||
#include "BlueprintNodeSpawner.h"
|
|
||||||
#include "UMCPHandler_SetNodePositions.generated.h"
|
#include "UMCPHandler_SetNodePositions.generated.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -91,9 +50,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
MCPAssets<UBlueprint> Assets;
|
MCPFetcher F(Result);
|
||||||
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||||
UBlueprint* BP = Assets.Object();
|
if (!BP) return;
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> Results;
|
TArray<TSharedPtr<FJsonValue>> Results;
|
||||||
int32 SuccessCount = 0;
|
int32 SuccessCount = 0;
|
||||||
@@ -106,12 +65,9 @@ public:
|
|||||||
FMoveNodeEntry Entry;
|
FMoveNodeEntry Entry;
|
||||||
if (!MCPUtils::PopulateFromJson(FMoveNodeEntry::StaticStruct(), &Entry, NodeVal, &*EntryResult)) continue;
|
if (!MCPUtils::PopulateFromJson(FMoveNodeEntry::StaticStruct(), &Entry, NodeVal, &*EntryResult)) continue;
|
||||||
|
|
||||||
UEdGraphNode* Node = MCPUtils::FindNodeByGuid(BP, Entry.Node);
|
MCPFetcher FN(EntryResult, BP);
|
||||||
if (!Node)
|
UEdGraphNode* Node = FN.Node(Entry.Node).Cast<UEdGraphNode>();
|
||||||
{
|
if (!Node) continue;
|
||||||
EntryResult->SetStringField(TEXT("error"), FString::Printf(TEXT("Node '%s' not found"), *Entry.Node));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 OldX = Node->NodePosX;
|
int32 OldX = Node->NodePosX;
|
||||||
int32 OldY = Node->NodePosY;
|
int32 OldY = Node->NodePosY;
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "MCPHandler.h"
|
#include "MCPHandler.h"
|
||||||
#include "MCPAssetFinder.h"
|
#include "MCPFetcher.h"
|
||||||
#include "MCPUtils.h"
|
#include "MCPUtils.h"
|
||||||
#include "Engine/Blueprint.h"
|
#include "Engine/Blueprint.h"
|
||||||
#include "Engine/World.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"
|
||||||
@@ -66,25 +65,12 @@ public:
|
|||||||
FSetPinDefaultEntry Entry;
|
FSetPinDefaultEntry Entry;
|
||||||
if (!MCPUtils::PopulateFromJson(FSetPinDefaultEntry::StaticStruct(), &Entry, PinVal, &*EntryResult)) continue;
|
if (!MCPUtils::PopulateFromJson(FSetPinDefaultEntry::StaticStruct(), &Entry, PinVal, &*EntryResult)) continue;
|
||||||
|
|
||||||
MCPAssets<UBlueprint> Assets;
|
MCPFetcher FE(EntryResult);
|
||||||
if (!Assets.Scan<UBlueprint>().Scan<UWorld>().Exact(Entry.Blueprint).Errors(&*EntryResult).ENone().ETwo().Load())
|
FE.Walk(Entry.Blueprint).Node(Entry.Node).Pin(Entry.PinName);
|
||||||
continue;
|
UEdGraphPin* Pin = FE.Cast<UEdGraphPin>();
|
||||||
UBlueprint* BP = Assets.Object();
|
if (!Pin) continue;
|
||||||
|
|
||||||
UEdGraph* Graph = nullptr;
|
UEdGraphNode* Node = Pin->GetOwningNode();
|
||||||
UEdGraphNode* Node = MCPUtils::FindNodeByGuid(BP, Entry.Node, &Graph);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Pin->Direction != EGPD_Input)
|
if (Pin->Direction != EGPD_Input)
|
||||||
{
|
{
|
||||||
@@ -92,7 +78,7 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UEdGraphSchema* Schema = Graph->GetSchema();
|
const UEdGraphSchema* Schema = Node->GetGraph()->GetSchema();
|
||||||
if (Schema)
|
if (Schema)
|
||||||
{
|
{
|
||||||
FString ValidationError = Schema->IsPinDefaultValid(Pin, Entry.Value, nullptr, FText::GetEmpty());
|
FString ValidationError = Schema->IsPinDefaultValid(Pin, Entry.Value, nullptr, FText::GetEmpty());
|
||||||
@@ -110,7 +96,7 @@ public:
|
|||||||
EntryResult->SetStringField(TEXT("oldValue"), OldValue);
|
EntryResult->SetStringField(TEXT("oldValue"), OldValue);
|
||||||
SuccessCount++;
|
SuccessCount++;
|
||||||
ModifiedNodes.Add(Node);
|
ModifiedNodes.Add(Node);
|
||||||
ModifiedBlueprints.Add(BP);
|
ModifiedBlueprints.Add(FBlueprintEditorUtils::FindBlueprintForNodeChecked(Node));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (UEdGraphNode* Node : ModifiedNodes)
|
for (UEdGraphNode* Node : ModifiedNodes)
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ public:
|
|||||||
TArray<TSharedPtr<FJsonValue>> GraphNames;
|
TArray<TSharedPtr<FJsonValue>> GraphNames;
|
||||||
for (UEdGraph* G : MCPUtils::AllGraphs(BP))
|
for (UEdGraph* G : MCPUtils::AllGraphs(BP))
|
||||||
{
|
{
|
||||||
GraphNames.Add(MakeShared<FJsonValueString>(G->GetName()));
|
GraphNames.Add(MakeShared<FJsonValueString>(MCPUtils::FormatName(G)));
|
||||||
}
|
}
|
||||||
MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Graph '%s' not found"), *DecodedGraphName));
|
MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Graph '%s' not found"), *DecodedGraphName));
|
||||||
Result->SetArrayField(TEXT("availableGraphs"), GraphNames);
|
Result->SetArrayField(TEXT("availableGraphs"), GraphNames);
|
||||||
@@ -165,7 +165,7 @@ public:
|
|||||||
|
|
||||||
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(),
|
||||||
*NewNode->GetClass()->GetName(),
|
*MCPUtils::FormatName(NewNode->GetClass()),
|
||||||
*Entry.ActionName,
|
*Entry.ActionName,
|
||||||
*DecodedGraphName,
|
*DecodedGraphName,
|
||||||
*Blueprint);
|
*Blueprint);
|
||||||
@@ -174,8 +174,8 @@ public:
|
|||||||
TSharedPtr<FJsonObject> NodeState = MCPUtils::SerializeNode(NewNode);
|
TSharedPtr<FJsonObject> NodeState = MCPUtils::SerializeNode(NewNode);
|
||||||
|
|
||||||
EntryResult->SetStringField(TEXT("nodeId"), NewNode->NodeGuid.ToString());
|
EntryResult->SetStringField(TEXT("nodeId"), NewNode->NodeGuid.ToString());
|
||||||
EntryResult->SetStringField(TEXT("nodeClass"), NewNode->GetClass()->GetName());
|
EntryResult->SetStringField(TEXT("nodeClass"), MCPUtils::FormatName(NewNode->GetClass()));
|
||||||
EntryResult->SetStringField(TEXT("nodeTitle"), NewNode->GetNodeTitle(ENodeTitleType::ListView).ToString());
|
EntryResult->SetStringField(TEXT("nodeTitle"), MCPUtils::FormatName(NewNode));
|
||||||
if (NodeState.IsValid())
|
if (NodeState.IsValid())
|
||||||
{
|
{
|
||||||
EntryResult->SetObjectField(TEXT("node"), NodeState);
|
EntryResult->SetObjectField(TEXT("node"), NodeState);
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public:
|
|||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: test-save — loaded '%s', GeneratedClass=%s"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: test-save — loaded '%s', GeneratedClass=%s"),
|
||||||
*BP->GetName(),
|
*BP->GetName(),
|
||||||
BP->GeneratedClass ? *BP->GeneratedClass->GetName() : TEXT("null"));
|
BP->GeneratedClass ? *MCPUtils::FormatName(BP->GeneratedClass) : TEXT("null"));
|
||||||
|
|
||||||
// Attempt save with NO modifications
|
// Attempt save with NO modifications
|
||||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
#include "Handlers/UMCPHandler_CheckPinConnectionCompatibility.h"
|
#include "Handlers/UMCPHandler_CheckPinConnectionCompatibility.h"
|
||||||
#include "Handlers/UMCPHandler_CompileBlueprint.h"
|
#include "Handlers/UMCPHandler_CompileBlueprint.h"
|
||||||
#include "Handlers/UMCPHandler_CompileMaterial.h"
|
#include "Handlers/UMCPHandler_CompileMaterial.h"
|
||||||
#include "Handlers/UMCPHandler_ConnectBlueprintPins.h"
|
#include "Handlers/UMCPHandler_ConnectPins.h"
|
||||||
#include "Handlers/UMCPHandler_ConnectMaterialExpressionPins.h"
|
#include "Handlers/UMCPHandler_ConnectMaterialExpressionPins.h"
|
||||||
#include "Handlers/UMCPHandler_CreateAnimBlueprintAsset.h"
|
#include "Handlers/UMCPHandler_CreateAnimBlueprintAsset.h"
|
||||||
#include "Handlers/UMCPHandler_CreateBlendSpaceAsset.h"
|
#include "Handlers/UMCPHandler_CreateBlendSpaceAsset.h"
|
||||||
@@ -31,10 +31,10 @@
|
|||||||
#include "Handlers/UMCPHandler_DeleteNodeFromGraph.h"
|
#include "Handlers/UMCPHandler_DeleteNodeFromGraph.h"
|
||||||
#include "Handlers/UMCPHandler_DescribeMaterialInEnglish.h"
|
#include "Handlers/UMCPHandler_DescribeMaterialInEnglish.h"
|
||||||
#include "Handlers/UMCPHandler_DiffTwoBlueprints.h"
|
#include "Handlers/UMCPHandler_DiffTwoBlueprints.h"
|
||||||
#include "Handlers/UMCPHandler_DisconnectBlueprintPins.h"
|
#include "Handlers/UMCPHandler_DisconnectPins.h"
|
||||||
#include "Handlers/UMCPHandler_DisconnectMaterialExpressionPin.h"
|
#include "Handlers/UMCPHandler_DisconnectMaterialExpressionPin.h"
|
||||||
#include "Handlers/UMCPHandler_DumpBlueprint.h"
|
#include "Handlers/UMCPHandler_DumpBlueprint.h"
|
||||||
#include "Handlers/UMCPHandler_DumpBlueprintGraph.h"
|
#include "Handlers/UMCPHandler_DumpGraphs.h"
|
||||||
#include "Handlers/UMCPHandler_DumpMaterial.h"
|
#include "Handlers/UMCPHandler_DumpMaterial.h"
|
||||||
#include "Handlers/UMCPHandler_DumpMaterialExpressionGraph.h"
|
#include "Handlers/UMCPHandler_DumpMaterialExpressionGraph.h"
|
||||||
#include "Handlers/UMCPHandler_DumpMaterialFunction.h"
|
#include "Handlers/UMCPHandler_DumpMaterialFunction.h"
|
||||||
@@ -67,6 +67,7 @@
|
|||||||
#include "Handlers/UMCPHandler_ReparentMaterialInstance.h"
|
#include "Handlers/UMCPHandler_ReparentMaterialInstance.h"
|
||||||
#include "Handlers/UMCPHandler_ReplaceFunctionCallsInBlueprint.h"
|
#include "Handlers/UMCPHandler_ReplaceFunctionCallsInBlueprint.h"
|
||||||
#include "Handlers/UMCPHandler_RestoreAsset.h"
|
#include "Handlers/UMCPHandler_RestoreAsset.h"
|
||||||
|
#include "Handlers/UMCPHandler_SearchAssets.h"
|
||||||
#include "Handlers/UMCPHandler_SearchSpawnableNodeTypes.h"
|
#include "Handlers/UMCPHandler_SearchSpawnableNodeTypes.h"
|
||||||
#include "Handlers/UMCPHandler_SearchTypeUsageInBlueprints.h"
|
#include "Handlers/UMCPHandler_SearchTypeUsageInBlueprints.h"
|
||||||
#include "Handlers/UMCPHandler_SearchUnrealClasses.h"
|
#include "Handlers/UMCPHandler_SearchUnrealClasses.h"
|
||||||
|
|||||||
@@ -127,29 +127,29 @@ void MCPUtils::AppendNumericSuffix(FString &Name, int32 N)
|
|||||||
Name += FString::Printf(TEXT("_%d"), N - 1);
|
Name += FString::Printf(TEXT("_%d"), N - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
FString MCPUtils::FormatName(UWorld *World)
|
FString MCPUtils::FormatName(const UWorld *World)
|
||||||
{
|
{
|
||||||
return World->GetPathName();
|
return World->GetPathName();
|
||||||
}
|
}
|
||||||
|
|
||||||
FString MCPUtils::FormatName(UBlueprint *BP)
|
FString MCPUtils::FormatName(const UBlueprint *BP)
|
||||||
{
|
{
|
||||||
return BP->GetPathName();
|
return BP->GetPathName();
|
||||||
}
|
}
|
||||||
|
|
||||||
FString MCPUtils::FormatName(UActorComponent *C)
|
FString MCPUtils::FormatName(const UActorComponent *C)
|
||||||
{
|
{
|
||||||
return C->GetName();
|
return C->GetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
FString MCPUtils::FormatName(UEdGraph *Graph)
|
FString MCPUtils::FormatName(const UEdGraph *Graph)
|
||||||
{
|
{
|
||||||
FString Name = Graph->GetName();
|
FString Name = Graph->GetName();
|
||||||
SanitizeNameInPlace(Name);
|
SanitizeNameInPlace(Name);
|
||||||
return Name;
|
return Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
FString MCPUtils::FormatName(UEdGraphNode* Node)
|
FString MCPUtils::FormatName(const UEdGraphNode* Node)
|
||||||
{
|
{
|
||||||
// Sanitized first line of the node title.
|
// Sanitized first line of the node title.
|
||||||
FString Title = Node->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
|
FString Title = Node->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
|
||||||
@@ -161,7 +161,7 @@ FString MCPUtils::FormatName(UEdGraphNode* Node)
|
|||||||
return Title;
|
return Title;
|
||||||
}
|
}
|
||||||
|
|
||||||
FString MCPUtils::FormatName(UEdGraphPin *Pin)
|
FString MCPUtils::FormatName(const UEdGraphPin *Pin)
|
||||||
{
|
{
|
||||||
FString Name = Pin->PinName.ToString();
|
FString Name = Pin->PinName.ToString();
|
||||||
SanitizeNameInPlace(Name);
|
SanitizeNameInPlace(Name);
|
||||||
@@ -198,34 +198,34 @@ bool MCPUtils::Identifies(const FString &Name, const UClass *Class)
|
|||||||
// Identifies
|
// Identifies
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
bool MCPUtils::Identifies(const FString &Name, UWorld *World)
|
bool MCPUtils::Identifies(const FString &Name, const UWorld *World)
|
||||||
{
|
{
|
||||||
return FormatName(World).Equals(Name, ESearchCase::IgnoreCase);
|
return FormatName(World).Equals(Name, ESearchCase::IgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MCPUtils::Identifies(const FString &Name, UBlueprint *BP)
|
bool MCPUtils::Identifies(const FString &Name, const UBlueprint *BP)
|
||||||
{
|
{
|
||||||
return FormatName(BP).Equals(Name, ESearchCase::IgnoreCase);
|
return FormatName(BP).Equals(Name, ESearchCase::IgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MCPUtils::Identifies(const FString &Name, UActorComponent *C)
|
bool MCPUtils::Identifies(const FString &Name, const UActorComponent *C)
|
||||||
{
|
{
|
||||||
return FormatName(C).Equals(Name, ESearchCase::IgnoreCase);
|
return FormatName(C).Equals(Name, ESearchCase::IgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MCPUtils::Identifies(const FString &Name, UEdGraph *Graph)
|
bool MCPUtils::Identifies(const FString &Name, const UEdGraph *Graph)
|
||||||
{
|
{
|
||||||
return FormatName(Graph).Equals(Name, ESearchCase::IgnoreCase);
|
return FormatName(Graph).Equals(Name, ESearchCase::IgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MCPUtils::Identifies(const FString &Name, UEdGraphNode* Node)
|
bool MCPUtils::Identifies(const FString &Name, const UEdGraphNode* Node)
|
||||||
{
|
{
|
||||||
if (Node->NodeGuid.ToString().Equals(Name, ESearchCase::IgnoreCase))
|
if (Node->NodeGuid.ToString().Equals(Name, ESearchCase::IgnoreCase))
|
||||||
return true;
|
return true;
|
||||||
return FormatName(Node).Equals(Name, ESearchCase::IgnoreCase);
|
return FormatName(Node).Equals(Name, ESearchCase::IgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MCPUtils::Identifies(const FString &Name, UEdGraphPin *Pin)
|
bool MCPUtils::Identifies(const FString &Name, const UEdGraphPin *Pin)
|
||||||
{
|
{
|
||||||
return FormatName(Pin).Equals(Name, ESearchCase::IgnoreCase);
|
return FormatName(Pin).Equals(Name, ESearchCase::IgnoreCase);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ struct MCPErrorCallback
|
|||||||
MCPErrorCallback(std::nullptr_t);
|
MCPErrorCallback(std::nullptr_t);
|
||||||
MCPErrorCallback(FString& OutError);
|
MCPErrorCallback(FString& OutError);
|
||||||
MCPErrorCallback(FJsonObject* Result);
|
MCPErrorCallback(FJsonObject* Result);
|
||||||
|
MCPErrorCallback(const TSharedRef<FJsonObject>& Result) : MCPErrorCallback(&*Result) {}
|
||||||
MCPErrorCallback(FStringBuilderBase& OutResult);
|
MCPErrorCallback(FStringBuilderBase& OutResult);
|
||||||
|
|
||||||
void SetError(const FString& Msg) const { Func(Msg); }
|
void SetError(const FString& Msg) const { Func(Msg); }
|
||||||
@@ -104,12 +105,12 @@ public:
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static FString FormatName(UWorld *World);
|
static FString FormatName(const UWorld *World);
|
||||||
static FString FormatName(UBlueprint *BP);
|
static FString FormatName(const UBlueprint *BP);
|
||||||
static FString FormatName(UActorComponent *C);
|
static FString FormatName(const UActorComponent *C);
|
||||||
static FString FormatName(UEdGraph *Graph);
|
static FString FormatName(const UEdGraph *Graph);
|
||||||
static FString FormatName(UEdGraphNode* Node);
|
static FString FormatName(const UEdGraphNode* Node);
|
||||||
static FString FormatName(UEdGraphPin *Pin);
|
static FString FormatName(const UEdGraphPin *Pin);
|
||||||
static FString FormatName(const FMemberReference &Ref);
|
static FString FormatName(const FMemberReference &Ref);
|
||||||
static FString FormatName(const FBPVariableDescription &Var);
|
static FString FormatName(const FBPVariableDescription &Var);
|
||||||
static FString FormatName(const UClass *Class);
|
static FString FormatName(const UClass *Class);
|
||||||
@@ -126,12 +127,12 @@ public:
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static bool Identifies(const FString &Name, UWorld *World);
|
static bool Identifies(const FString &Name, const UWorld *World);
|
||||||
static bool Identifies(const FString &Name, UBlueprint *BP);
|
static bool Identifies(const FString &Name, const UBlueprint *BP);
|
||||||
static bool Identifies(const FString &Name, UActorComponent *C);
|
static bool Identifies(const FString &Name, const UActorComponent *C);
|
||||||
static bool Identifies(const FString &Name, UEdGraph *Graph);
|
static bool Identifies(const FString &Name, const UEdGraph *Graph);
|
||||||
static bool Identifies(const FString &Name, UEdGraphNode* Node);
|
static bool Identifies(const FString &Name, const UEdGraphNode* Node);
|
||||||
static bool Identifies(const FString &Name, UEdGraphPin *Pin);
|
static bool Identifies(const FString &Name, const UEdGraphPin *Pin);
|
||||||
static bool Identifies(const FString &Name, const FMemberReference &Ref);
|
static bool Identifies(const FString &Name, const FMemberReference &Ref);
|
||||||
static bool Identifies(const FString &Name, const UClass *Class);
|
static bool Identifies(const FString &Name, const UClass *Class);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user