diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp index dd7bab2e..91a2a443 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp @@ -38,6 +38,13 @@ WingGraphExport::WingGraphExport(UEdGraphNode* InNode, bool Locals, bool Details // //////////////////////////////////////////////////////// +bool WingGraphExport::IsLinked(UEdGraphPin* Pin) +{ + if (Pin == nullptr) return false; + if (Pin->LinkedTo.IsEmpty()) return false; + return true; +} + UEdGraphPin* WingGraphExport::GetLinkedTo(UEdGraphPin* Pin) { if (Pin == nullptr) return nullptr; @@ -64,13 +71,16 @@ bool WingGraphExport::IsDefaultToSelf(UEdGraphPin* Pin) return Pin->PinName.ToString() == DefaultToSelfPinName; } -TArray WingGraphExport::FilterPins(UEdGraphNode* Node, EEdGraphPinDirection Direction, FName Category) +TArray WingGraphExport::GetPins( + UEdGraphNode* Node, EEdGraphPinDirection Direction, PinKind Kind) { TArray Result; for (UEdGraphPin* Pin : Node->Pins) { - if (Direction != EGPD_MAX && Pin->Direction != Direction) continue; - if (!Category.IsNone() && Pin->PinType.PinCategory != Category) continue; + if (Pin->bHidden) continue; + if (Pin->Direction != Direction) continue; + if ((Kind == PK_VALUE) && (Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Exec)) continue; + if ((Kind == PK_EXEC) && (Pin->PinType.PinCategory != UEdGraphSchema_K2::PC_Exec)) continue; Result.Add(Pin); } return Result; @@ -78,78 +88,23 @@ TArray WingGraphExport::FilterPins(UEdGraphNode* Node, EEdGraphPin bool WingGraphExport::HasExecPin(UEdGraphNode* Node, EEdGraphPinDirection Direction) { - return FilterPins(Node, Direction, UEdGraphSchema_K2::PC_Exec).Num() > 0; -} - -UEdGraphPin* WingGraphExport::FindFirstPin(UEdGraphNode* Node, EEdGraphPinDirection Direction) -{ - for (UEdGraphPin* Pin : Node->Pins) - { - if (Pin->Direction == Direction) return Pin; - } - return nullptr; + return GetPins(Node, Direction, PK_EXEC).Num() > 0; } //////////////////////////////////////////////////////// // -// Traverse and Emit the Nodes. +// Traversal // //////////////////////////////////////////////////////// -FString WingGraphExport::FormatPinSource(UEdGraphPin* Pin) -{ - // If connected, show source node.pin - UEdGraphPin* LinkedTo = GetLinkedTo(Pin); - if (LinkedTo != nullptr) - { - UEdGraphNode* LinkedToNode = LinkedTo->GetOwningNode(); - FString PinLabel = WingUtils::FormatName(LinkedTo); - return FString::Printf(TEXT("%s.%s"), *WingUtils::FormatName(LinkedToNode), *PinLabel); - } - - // String pins: always show in quotes (even if empty). - FName Category = Pin->PinType.PinCategory; - if (Category == UEdGraphSchema_K2::PC_String || - Category == UEdGraphSchema_K2::PC_Name || - Category == UEdGraphSchema_K2::PC_Text) - { - return FString::Printf(TEXT("\"%s\""), *Pin->DefaultValue); - } - - // If has a non-empty default, show it. - if (!Pin->DefaultValue.IsEmpty()) - { - return Pin->DefaultValue; - } - - if (Pin->DefaultObject) - { - return Pin->DefaultObject->GetName(); - } - - if (!Pin->DefaultTextValue.IsEmpty()) - { - return FString::Printf(TEXT("\"%s\""), *Pin->DefaultTextValue.ToString()); - } - - if (IsDefaultToSelf(Pin)) - { - return TEXT(""); - } - else - { - return TEXT(""); - } -} - void WingGraphExport::Traverse(UEdGraphNode* Node) { if (Visited.Contains(Node)) return; Visited.Add(Node); // First, traverse input nodes - for (UEdGraphPin* Pin : FilterPins(Node, EGPD_Input)) + for (UEdGraphPin* Pin : GetPins(Node, EGPD_Input, PK_BOTH)) for (UEdGraphPin* LinkedPin : Pin->LinkedTo) Traverse(LinkedPin->GetOwningNode()); @@ -159,7 +114,7 @@ void WingGraphExport::Traverse(UEdGraphNode* Node) // Then, traverse exec output nodes only. // Data outputs are not followed — data nodes get pulled in // through their consumers' input traversal. - for (UEdGraphPin* Pin : FilterPins(Node, EGPD_Output, UEdGraphSchema_K2::PC_Exec)) + for (UEdGraphPin* Pin : GetPins(Node, EGPD_Output, PK_EXEC)) for (UEdGraphPin* LinkedPin : Pin->LinkedTo) Traverse(LinkedPin->GetOwningNode()); } @@ -195,6 +150,62 @@ void WingGraphExport::SortNodes() } } +//////////////////////////////////////////////////////// +// +// Text Output +// +//////////////////////////////////////////////////////// + +void WingGraphExport::EmitLinks(UEdGraphPin* Pin) +{ + bool comma = false; + for (const UEdGraphPin *Other : Pin->LinkedTo) + { + if (comma) Output.Append(TEXT(", ")); + comma = true; + Output.Appendf(TEXT("node:%s,pin:%s"), + *WingUtils::FormatName(Other->GetOwningNode()), *WingUtils::FormatName(Other)); + } +} + +void WingGraphExport::EmitInputPinValue(UEdGraphPin* Pin) +{ + // If connected, show source node and pin + if (IsLinked(Pin)) return EmitLinks(Pin); + + // String pins: always show in quotes (even if empty). + FName Category = Pin->PinType.PinCategory; + if (Category == UEdGraphSchema_K2::PC_String || + Category == UEdGraphSchema_K2::PC_Name || + Category == UEdGraphSchema_K2::PC_Text) + { + Output.Appendf(TEXT("\"%s\""), *Pin->DefaultValue); + return; + } + + // If has a non-empty default, show it. + if (!Pin->DefaultValue.IsEmpty()) + { + Output.Append(Pin->DefaultValue); + return; + } + + if (Pin->DefaultObject) + { + Output.Append(Pin->DefaultObject->GetName()); + return; + } + + if (!Pin->DefaultTextValue.IsEmpty()) + { + Output.Appendf(TEXT("\"%s\""), *Pin->DefaultTextValue.ToString()); + return; + } + + Output.Appendf(TEXT("")); +} + + void WingGraphExport::EmitNode(UEdGraphNode* Node) { if (Node->IsA()) return; @@ -218,45 +229,65 @@ void WingGraphExport::EmitNode(UEdGraphNode* Node) SuppressedDetails = true; } + // Emit the input exec pin(s). Do not show what they're connected to. + TArray ExecIns = GetPins(Node, EGPD_Input, PK_EXEC); + for (UEdGraphPin* Pin : ExecIns) + { + if (IsLinked(Pin)) + { + Output.Appendf(TEXT(" exec-in %s from "), *WingUtils::FormatName(Pin)); + EmitLinks(Pin); + Output.AppendChar('\n'); + } + else + { + Output.Appendf(TEXT(" exec-in %s (unconnected)\n"), *WingUtils::FormatName(Pin)); + } + } + // Emit input data pins. - for (UEdGraphPin* Pin : FilterPins(Node, EGPD_Input)) + for (UEdGraphPin* Pin : GetPins(Node, EGPD_Input, PK_VALUE)) { if (Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Exec) continue; - if (Pin->bHidden) continue; - Output.Appendf(TEXT(" input %s %s = %s\n"), + Output.Appendf(TEXT(" input-pin %s %s = "), *UWingTypes::TypeToText(Pin->PinType), - *WingUtils::FormatName(Pin), - *FormatPinSource(Pin)); + *WingUtils::FormatName(Pin)); + EmitInputPinValue(Pin); + Output.AppendChar('\n'); } - // Emit output data pins as a return line. - FString ReturnPins; - for (UEdGraphPin* Pin : FilterPins(Node, EGPD_Output)) + // Emit output data pins as a single 'output-pins' line. + TArray OutputPins = GetPins(Node, EGPD_Output, PK_VALUE); + if (!OutputPins.IsEmpty()) { - if (Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Exec) continue; - if (Pin->bHidden) continue; - if (!ReturnPins.IsEmpty()) ReturnPins += TEXT(", "); - ReturnPins += WingUtils::FormatName(Pin); - } - if (!ReturnPins.IsEmpty()) - { - Output.Appendf(TEXT(" output-pins %s\n"), *ReturnPins); + Output.Append(TEXT(" output-pins ")); + bool comma = false; + for (UEdGraphPin *Pin : OutputPins) + { + if (comma) Output.Append(TEXT(", ")); + comma = true; + Output.Append(UWingTypes::TypeToText(Pin->PinType)); + Output.AppendChar(' '); + Output.Append(WingUtils::FormatName(Pin)); + } + Output.AppendChar('\n'); } - // Emit output exec pins as goto statements. - TArray ExecOuts = FilterPins(Node, EGPD_Output, UEdGraphSchema_K2::PC_Exec); + // Emit output exec pins. + TArray ExecOuts = GetPins(Node, EGPD_Output, PK_EXEC); for (UEdGraphPin* Pin : ExecOuts) { - UEdGraphPin* LinkedTo = GetLinkedTo(Pin); - if (!LinkedTo) continue; - - FString Target = WingUtils::FormatName(LinkedTo->GetOwningNode()); - - if (ExecOuts.Num() == 1) - Output.Appendf(TEXT(" goto %s\n"), *Target); + if (IsLinked(Pin)) + { + Output.Appendf(TEXT(" exec-out %s to "), *WingUtils::FormatName(Pin)); + EmitLinks(Pin); + Output.AppendChar('\n'); + } else - Output.Appendf(TEXT(" goto-if %s %s\n"), *WingUtils::FormatName(Pin), *Target); + { + Output.Appendf(TEXT(" exec-out %s (unconnected)\n"), *WingUtils::FormatName(Pin)); + } } Output.Append(TEXT("\n")); diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingGraphExport.h b/Plugins/UEWingman/Source/UEWingman/Public/WingGraphExport.h index 76d48c78..66dfa995 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingGraphExport.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingGraphExport.h @@ -22,6 +22,17 @@ private: // //////////////////////////////////////////////////////// + enum PinKind + { + PK_EXEC, + PK_VALUE, + PK_BOTH + }; + + // Return true if this pin is connected. + // + static bool IsLinked(UEdGraphPin *Pin); + // Get the pin that this pin is linked to. // static UEdGraphPin* GetLinkedTo(UEdGraphPin *Pin); @@ -32,27 +43,24 @@ private: static bool IsDefaultToSelf(UEdGraphPin* Pin); // Get a subset of the pins in the node, filtered - // by direction, category, or both. + // by direction, Kind, or both. // - static TArray FilterPins(UEdGraphNode* Node, - EEdGraphPinDirection Direction = EGPD_MAX, FName Category = FName()); - + static TArray GetPins( + UEdGraphNode* Node, EEdGraphPinDirection Direction, PinKind Kind); + // Return true if the node has an exec pin that points // in the specified direction. // static bool HasExecPin(UEdGraphNode* Node, EEdGraphPinDirection Direction); - // Find the first pin that points in the specified direction. - // - static UEdGraphPin* FindFirstPin(UEdGraphNode* Node, EEdGraphPinDirection Direction); - //////////////////////////////////////////////////////// // // Traverse and Emit the Nodes. // //////////////////////////////////////////////////////// - FString FormatPinSource(UEdGraphPin* Pin); + void EmitLinks(UEdGraphPin* Pin); + void EmitInputPinValue(UEdGraphPin* Pin); void Traverse(UEdGraphNode* Node); void SortNodes(); void EmitNode(UEdGraphNode* Node);