Working on editing MG
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -34,22 +34,22 @@ class UMCP_GraphPin_Connect : public UObject, public IMCPHandler
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
UPROPERTY(meta=(Description="Path to a graph, e.g. /Game/Foo,graph:EventGraph or /Game/Materials/M_Test"))
|
||||||
FString Blueprint;
|
FString Graph;
|
||||||
|
|
||||||
UPROPERTY(meta=(Description="Array of {sourcePin, targetPin} objects. Each pin is a path like node:MyNode,pin:Output"))
|
UPROPERTY(meta=(Description="Array of {sourcePin, targetPin} objects. Each pin is a path like node:MyNode,pin:Output"))
|
||||||
FMCPJsonArray Connections;
|
FMCPJsonArray Connections;
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
virtual FString GetDescription() const override
|
||||||
{
|
{
|
||||||
return TEXT("Connect pins between nodes in a Blueprint graph.");
|
return TEXT("Connect pins between nodes in a graph (Blueprint or Material).");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Handle(FStringBuilderBase& Result) override
|
virtual void Handle(FStringBuilderBase& Result) override
|
||||||
{
|
{
|
||||||
MCPFetcher F(Result);
|
MCPFetcher F(Result);
|
||||||
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
UEdGraph* G = F.Walk(Graph).ToGraph().Cast<UEdGraph>();
|
||||||
if (!BP) return;
|
if (!G) return;
|
||||||
|
|
||||||
F.PreEdit();
|
F.PreEdit();
|
||||||
|
|
||||||
@@ -62,15 +62,15 @@ public:
|
|||||||
if (!MCPUtils::PopulateFromJson(FConnectPinsEntry::StaticStruct(), &Entry, ConnVal, Result))
|
if (!MCPUtils::PopulateFromJson(FConnectPinsEntry::StaticStruct(), &Entry, ConnVal, Result))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
MCPFetcher FS(Result, BP);
|
MCPFetcher FS(Result, G);
|
||||||
UEdGraphPin* SourcePin = FS.Walk(Entry.SourcePin).Cast<UEdGraphPin>();
|
UEdGraphPin* SourcePin = FS.Walk(Entry.SourcePin).Cast<UEdGraphPin>();
|
||||||
if (!SourcePin) continue;
|
if (!SourcePin) continue;
|
||||||
|
|
||||||
MCPFetcher FT(Result, BP);
|
MCPFetcher FT(Result, G);
|
||||||
UEdGraphPin* TargetPin = FT.Walk(Entry.TargetPin).Cast<UEdGraphPin>();
|
UEdGraphPin* TargetPin = FT.Walk(Entry.TargetPin).Cast<UEdGraphPin>();
|
||||||
if (!TargetPin) continue;
|
if (!TargetPin) continue;
|
||||||
|
|
||||||
const UEdGraphSchema* Schema = SourcePin->GetOwningNode()->GetGraph()->GetSchema();
|
const UEdGraphSchema* Schema = G->GetSchema();
|
||||||
const FPinConnectionResponse Response = Schema->CanCreateConnection(SourcePin, TargetPin);
|
const FPinConnectionResponse Response = Schema->CanCreateConnection(SourcePin, TargetPin);
|
||||||
if (Response.Response == CONNECT_RESPONSE_DISALLOW)
|
if (Response.Response == CONNECT_RESPONSE_DISALLOW)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,23 +33,23 @@ class UMCP_GraphPin_Disconnect : public UObject, public IMCPHandler
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
UPROPERTY(meta=(Description="Path to a graph, e.g. /Game/Foo,graph:EventGraph or /Game/Materials/M_Test"))
|
||||||
FString Blueprint;
|
FString Graph;
|
||||||
|
|
||||||
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."))
|
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
|
||||||
{
|
{
|
||||||
return TEXT("Disconnect pins in a Blueprint graph. "
|
return TEXT("Disconnect pins in a graph (Blueprint or Material). "
|
||||||
"Can disconnect a specific link or all links on a pin.");
|
"Can disconnect a specific link or all links on a pin.");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Handle(FStringBuilderBase& Result) override
|
virtual void Handle(FStringBuilderBase& Result) override
|
||||||
{
|
{
|
||||||
MCPFetcher F(Result);
|
MCPFetcher F(Result);
|
||||||
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
UEdGraph* G = F.Walk(Graph).ToGraph().Cast<UEdGraph>();
|
||||||
if (!BP) return;
|
if (!G) return;
|
||||||
|
|
||||||
F.PreEdit();
|
F.PreEdit();
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
FDisconnectPinEntry Entry;
|
FDisconnectPinEntry Entry;
|
||||||
if (!MCPUtils::PopulateFromJson(FDisconnectPinEntry::StaticStruct(), &Entry, DiscVal, Result)) continue;
|
if (!MCPUtils::PopulateFromJson(FDisconnectPinEntry::StaticStruct(), &Entry, DiscVal, Result)) continue;
|
||||||
|
|
||||||
MCPFetcher FP(Result, BP);
|
MCPFetcher FP(Result, G);
|
||||||
UEdGraphPin* Pin = FP.Walk(Entry.Pin).Cast<UEdGraphPin>();
|
UEdGraphPin* Pin = FP.Walk(Entry.Pin).Cast<UEdGraphPin>();
|
||||||
if (!Pin) continue;
|
if (!Pin) continue;
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ public:
|
|||||||
|
|
||||||
if (!Entry.TargetPin.IsEmpty())
|
if (!Entry.TargetPin.IsEmpty())
|
||||||
{
|
{
|
||||||
MCPFetcher FT(Result, BP);
|
MCPFetcher FT(Result, G);
|
||||||
UEdGraphPin* Target = FT.Walk(Entry.TargetPin).Cast<UEdGraphPin>();
|
UEdGraphPin* Target = FT.Walk(Entry.TargetPin).Cast<UEdGraphPin>();
|
||||||
if (!Target) continue;
|
if (!Target) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -76,23 +76,28 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UEdGraphSchema_K2* Schema = Cast<UEdGraphSchema_K2>(Node->GetGraph()->GetSchema());
|
Pin->Modify();
|
||||||
check(Schema);
|
|
||||||
|
|
||||||
// Parse and validate the value before applying.
|
// K2 schemas support validation before setting; other schemas (e.g. material) don't.
|
||||||
|
const UEdGraphSchema_K2* K2Schema = Cast<UEdGraphSchema_K2>(Node->GetGraph()->GetSchema());
|
||||||
|
if (K2Schema)
|
||||||
|
{
|
||||||
FString UseDefaultValue;
|
FString UseDefaultValue;
|
||||||
TObjectPtr<UObject> UseDefaultObject = nullptr;
|
TObjectPtr<UObject> UseDefaultObject = nullptr;
|
||||||
FText UseDefaultText;
|
FText UseDefaultText;
|
||||||
Schema->GetPinDefaultValuesFromString(Pin->PinType, Node, Entry.Value, UseDefaultValue, UseDefaultObject, UseDefaultText, false);
|
K2Schema->GetPinDefaultValuesFromString(Pin->PinType, Node, Entry.Value, UseDefaultValue, UseDefaultObject, UseDefaultText, false);
|
||||||
FString Error = Schema->IsPinDefaultValid(Pin, UseDefaultValue, UseDefaultObject, UseDefaultText);
|
FString Error = K2Schema->IsPinDefaultValid(Pin, UseDefaultValue, UseDefaultObject, UseDefaultText);
|
||||||
if (!Error.IsEmpty())
|
if (!Error.IsEmpty())
|
||||||
{
|
{
|
||||||
Result.Appendf(TEXT("error: %s: %s\n"), *MCPUtils::FormatName(Pin), *Error);
|
Result.Appendf(TEXT("error: %s: %s\n"), *MCPUtils::FormatName(Pin), *Error);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
K2Schema->TrySetDefaultValue(*Pin, Entry.Value);
|
||||||
Pin->Modify();
|
}
|
||||||
Schema->TrySetDefaultValue(*Pin, Entry.Value);
|
else
|
||||||
|
{
|
||||||
|
Node->GetGraph()->GetSchema()->TrySetDefaultValue(*Pin, Entry.Value);
|
||||||
|
}
|
||||||
|
|
||||||
SuccessCount++;
|
SuccessCount++;
|
||||||
ModifiedNodes.Add(Node);
|
ModifiedNodes.Add(Node);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "K2Node_VariableGet.h"
|
#include "K2Node_VariableGet.h"
|
||||||
#include "K2Node_CallFunction.h"
|
#include "K2Node_CallFunction.h"
|
||||||
#include "K2Node_FunctionEntry.h"
|
#include "K2Node_FunctionEntry.h"
|
||||||
|
#include "MaterialGraph/MaterialGraphNode.h"
|
||||||
|
|
||||||
static FString WrapText(const FString& Text, int32 ColLimit, const FString& Prefix)
|
static FString WrapText(const FString& Text, int32 ColLimit, const FString& Prefix)
|
||||||
{
|
{
|
||||||
@@ -232,6 +233,9 @@ void FlxBlueprintExporter::EmitNode(UEdGraphNode* Node)
|
|||||||
|
|
||||||
Output.Appendf(TEXT("\nnode %s: %s\n"), *MCPUtils::FormatName(Node), *MCPUtils::FormatNodeTitle(Node));
|
Output.Appendf(TEXT("\nnode %s: %s\n"), *MCPUtils::FormatName(Node), *MCPUtils::FormatNodeTitle(Node));
|
||||||
|
|
||||||
|
// Emit material expression properties (if applicable).
|
||||||
|
EmitMaterialProperties(Node, Output, true);
|
||||||
|
|
||||||
// Emit input data pins.
|
// Emit input data pins.
|
||||||
for (UEdGraphPin* Pin : FilterPins(Node, EGPD_Input))
|
for (UEdGraphPin* Pin : FilterPins(Node, EGPD_Input))
|
||||||
{
|
{
|
||||||
@@ -274,6 +278,39 @@ void FlxBlueprintExporter::EmitNode(UEdGraphNode* Node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FlxBlueprintExporter::EmitMaterialProperty(UMaterialExpression* Expression, FProperty* Prop, FStringBuilderBase& Out)
|
||||||
|
{
|
||||||
|
FString ValueStr = MCPUtils::GetPropertyValueText(Expression, Prop);
|
||||||
|
ValueStr.ReplaceInline(TEXT("\r\n"), TEXT(" "));
|
||||||
|
ValueStr.ReplaceInline(TEXT("\n"), TEXT(" "));
|
||||||
|
if (ValueStr.Len() > 80)
|
||||||
|
ValueStr = ValueStr.Left(80) + TEXT("...");
|
||||||
|
|
||||||
|
bool bEditable = !Prop->HasAnyPropertyFlags(CPF_EditConst);
|
||||||
|
Out.Appendf(TEXT(" %s %s %s = %s\n"),
|
||||||
|
bEditable ? TEXT("editable") : TEXT("readonly"),
|
||||||
|
*MCPUtils::FormatPropertyType(Prop),
|
||||||
|
*MCPUtils::FormatName(Prop),
|
||||||
|
*ValueStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlxBlueprintExporter::EmitMaterialProperties(UEdGraphNode* Node, FStringBuilderBase& Out, bool bPrimary)
|
||||||
|
{
|
||||||
|
UMaterialGraphNode* MatNode = Cast<UMaterialGraphNode>(Node);
|
||||||
|
if (!MatNode || !MatNode->MaterialExpression) return;
|
||||||
|
|
||||||
|
UMaterialExpression* Expression = MatNode->MaterialExpression;
|
||||||
|
FString PrimaryCategory = Expression->GetClass()->GetName();
|
||||||
|
TArray<FProperty*> Props = MCPUtils::SearchProperties(Expression, FString(), CPF_Edit, false);
|
||||||
|
|
||||||
|
for (FProperty* Prop : Props)
|
||||||
|
{
|
||||||
|
FString Category = Prop->HasMetaData(TEXT("Category")) ? Prop->GetMetaData(TEXT("Category")) : FString();
|
||||||
|
if ((Category == PrimaryCategory) == bPrimary)
|
||||||
|
EmitMaterialProperty(Expression, Prop, Out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FlxBlueprintExporter::EmitLocalVariables()
|
void FlxBlueprintExporter::EmitLocalVariables()
|
||||||
{
|
{
|
||||||
for (UEdGraphNode* Node : Graph->Nodes)
|
for (UEdGraphNode* Node : Graph->Nodes)
|
||||||
@@ -312,6 +349,8 @@ void FlxBlueprintExporter::EmitDetails()
|
|||||||
if (Node->IsA<UK2Node_VariableGet>()) continue;
|
if (Node->IsA<UK2Node_VariableGet>()) continue;
|
||||||
Details.Appendf(TEXT("details %s\n"), *MCPUtils::FormatName(Node));
|
Details.Appendf(TEXT("details %s\n"), *MCPUtils::FormatName(Node));
|
||||||
Details.Appendf(TEXT(" pos %d, %d\n"), Node->NodePosX, Node->NodePosY);
|
Details.Appendf(TEXT(" pos %d, %d\n"), Node->NodePosX, Node->NodePosY);
|
||||||
|
|
||||||
|
EmitMaterialProperties(Node, Details, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +366,7 @@ void FlxBlueprintExporter::EmitComments()
|
|||||||
int32 CH = CommentNode->NodeHeight;
|
int32 CH = CommentNode->NodeHeight;
|
||||||
|
|
||||||
// Emit header.
|
// Emit header.
|
||||||
Output.Append(TEXT("\ncomment:\n"));
|
Output.Appendf(TEXT("\ncomment %s:\n"), *MCPUtils::FormatName(CommentNode));
|
||||||
|
|
||||||
// Emit wrapped, indented body.
|
// Emit wrapped, indented body.
|
||||||
Output.Append(WrapText(CommentNode->NodeComment, 70, TEXT(" - ")));
|
Output.Append(WrapText(CommentNode->NodeComment, 70, TEXT(" - ")));
|
||||||
|
|||||||
@@ -267,6 +267,42 @@ MCPFetcher& MCPFetcher::Template()
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MCPFetcher& MCPFetcher::ToBlueprint()
|
||||||
|
{
|
||||||
|
if (bError) return *this;
|
||||||
|
if (::Cast<UBlueprint>(Obj)) return *this;
|
||||||
|
|
||||||
|
if (UWorld* World = ::Cast<UWorld>(Obj))
|
||||||
|
{
|
||||||
|
if (!World->PersistentLevel)
|
||||||
|
return SetError(TEXT("ToBlueprint: World has no PersistentLevel"));
|
||||||
|
ULevelScriptBlueprint* LevelBP = World->PersistentLevel->GetLevelScriptBlueprint(true);
|
||||||
|
if (!LevelBP)
|
||||||
|
return SetError(TEXT("ToBlueprint: World has no level blueprint"));
|
||||||
|
SetObj(LevelBP);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TypeMismatch(TEXT("ToBlueprint"), TEXT("Blueprint or World"));
|
||||||
|
}
|
||||||
|
|
||||||
|
MCPFetcher& MCPFetcher::ToGraph()
|
||||||
|
{
|
||||||
|
if (bError) return *this;
|
||||||
|
if (::Cast<UEdGraph>(Obj)) return *this;
|
||||||
|
|
||||||
|
if (UMaterial* Mat = ::Cast<UMaterial>(Obj))
|
||||||
|
{
|
||||||
|
MCPUtils::EnsureMaterialGraph(Mat);
|
||||||
|
if (!Mat->MaterialGraph)
|
||||||
|
return SetError(FString::Printf(TEXT("ToGraph: Material '%s' has no material graph"), *Mat->GetName()));
|
||||||
|
SetObj(Mat->MaterialGraph);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TypeMismatch(TEXT("ToGraph"), TEXT("Graph or Material"));
|
||||||
|
}
|
||||||
|
|
||||||
MCPFetcher& MCPFetcher::MatExp(const FString& Value)
|
MCPFetcher& MCPFetcher::MatExp(const FString& Value)
|
||||||
{
|
{
|
||||||
if (bError) return *this;
|
if (bError) return *this;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#include "EdGraph/EdGraphNode.h"
|
#include "EdGraph/EdGraphNode.h"
|
||||||
#include "EdGraph/EdGraphPin.h"
|
#include "EdGraph/EdGraphPin.h"
|
||||||
|
|
||||||
|
class UMaterialExpression;
|
||||||
|
|
||||||
class FlxBlueprintExporter
|
class FlxBlueprintExporter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -60,6 +62,8 @@ private:
|
|||||||
void Traverse(UEdGraphNode* Node);
|
void Traverse(UEdGraphNode* Node);
|
||||||
void SortNodes();
|
void SortNodes();
|
||||||
void EmitNode(UEdGraphNode* Node);
|
void EmitNode(UEdGraphNode* Node);
|
||||||
|
void EmitMaterialProperty(UMaterialExpression* Expression, FProperty* Prop, FStringBuilderBase& Out);
|
||||||
|
void EmitMaterialProperties(UEdGraphNode* Node, FStringBuilderBase& Out, bool bPrimary);
|
||||||
void EmitLocalVariables();
|
void EmitLocalVariables();
|
||||||
void EmitGraph();
|
void EmitGraph();
|
||||||
void EmitDetails();
|
void EmitDetails();
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ public:
|
|||||||
// (e.g. Blueprint → CDO, everything else → as-is).
|
// (e.g. Blueprint → CDO, everything else → as-is).
|
||||||
MCPFetcher& Template();
|
MCPFetcher& Template();
|
||||||
|
|
||||||
|
// C++-only navigation: drill down to a specific type.
|
||||||
|
MCPFetcher& ToBlueprint();
|
||||||
|
MCPFetcher& ToGraph();
|
||||||
|
|
||||||
// Walker table entry.
|
// Walker table entry.
|
||||||
struct FWalker
|
struct FWalker
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user