From 9720fa9f8de43394472d9619c0656d45a9f1c2be Mon Sep 17 00:00:00 2001 From: jyelon Date: Mon, 30 Mar 2026 23:45:53 -0400 Subject: [PATCH] Progress on variable modification --- Content/Testing/BP_Test.uasset | 4 +- .../Handlers/BlueprintVariable_Create.h | 17 +- .../Handlers/BlueprintVariable_Dump.h | 5 +- .../Handlers/BlueprintVariable_Modify.h | 16 +- .../UEWingman/Handlers/Blueprint_Dump.h | 9 +- .../UEWingman/Handlers/GraphVariables_Dump.h | 25 +- .../Handlers/GraphVariables_Modify.h | 30 ++- .../UEWingman/Handlers/Test_ParseVariables.h | 36 --- .../UEWingman/Private/WingGraphExport.cpp | 24 +- .../UEWingman/Private/WingVariables.cpp | 244 +++++++++++------- .../Source/UEWingman/Public/WingVariables.h | 76 ++++-- 11 files changed, 248 insertions(+), 238 deletions(-) delete mode 100644 Plugins/UEWingman/Source/UEWingman/Handlers/Test_ParseVariables.h diff --git a/Content/Testing/BP_Test.uasset b/Content/Testing/BP_Test.uasset index 9262c558..f778c109 100644 --- a/Content/Testing/BP_Test.uasset +++ b/Content/Testing/BP_Test.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70b5ccb833a544d0c583defa35ed7e58d568e7a02f7fe5e37c9bc958b6f3eb56 -size 44409 +oid sha256:906f25718c06e1253e323913ff875c9f6f0f59b637b3a9def20ab6cdd8456060 +size 45363 diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Create.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Create.h index 6d0ccf84..feefa18b 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Create.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Create.h @@ -41,18 +41,17 @@ public: if (!BP) return; // Parse the variable declarations. - WingVariables Parsed; - if (!WingVariables::ParseString(Variables, Parsed)) return; - if (Parsed.IsEmpty()) { UWingServer::Print(TEXT("ERROR: No variables specified.\n")); return; } - if (!Parsed.CheckSanity(WingVariables::Cat::Blueprint)) return; + WingVariables Vars; + if (!Vars.ParseString(Variables)) return; + if (Vars.IsEmpty()) { UWingServer::Print(TEXT("ERROR: No variables specified.\n")); return; } // Check for name collisions against existing variables, components, and the like. TSet Names; FBlueprintEditorUtils::GetClassVariableList(BP, Names); - if (!WingUtils::FindNoDuplicateNames(Names, Parsed.GetVariables(), TEXT("variable or component"))) return; + if (!WingUtils::FindNoDuplicateNames(Names, Vars.GetVariables(), TEXT("variable or component"))) return; // Create the variables. - for (const WingVariables::Var& V : Parsed.GetVariables()) + for (const WingVariables::Var& V : Vars.GetVariables()) { if (!FBlueprintEditorUtils::AddMemberVariable(BP, V.Name, V.Type)) { @@ -63,10 +62,10 @@ public: } // Update everything. - if (!Parsed.AssociateBlueprintNewVariables(BP)) return; - Parsed.UpdateVariableFlags(); + if (!Vars.AssociateBlueprintVariables(BP)) return; + Vars.UpdateVariableFlags(); FKismetEditorUtilities::CompileBlueprint(BP); - if (!Parsed.UpdateVariableDefaults()) return; + if (!Vars.UpdateVariableDefaults()) return; UWingServer::Printf(TEXT("Success.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Dump.h index f80ef6b6..8b440b7d 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Dump.h @@ -32,8 +32,9 @@ public: UBlueprint* BP = F.Walk(Blueprint).Cast(); if (!BP) return; - WingVariables Vars = WingVariables::ParseBlueprintVariables(BP); + WingVariables Vars; + Vars.LoadBlueprintVariables(BP); if (Vars.IsEmpty()) { UWingServer::Print(TEXT("No variables.\n")); return; } - Vars.PrintAll(); + Vars.PrintAll(UWingServer::GetPrintBuffer(), true, TEXT("Blueprint Variables:")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Modify.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Modify.h index d959c15f..9c1b02ee 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Modify.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Modify.h @@ -39,19 +39,19 @@ public: if (!BP) return; // Parse the variable declarations. - WingVariables Parsed; - if (!WingVariables::ParseString(Variables, Parsed)) return; - if (Parsed.IsEmpty()) { UWingServer::Print(TEXT("ERROR: No variables specified.\n")); return; } - if (!Parsed.CheckSanity(WingVariables::Cat::Blueprint)) return; + WingVariables Vars; + if (!Vars.ParseString(Variables)) return; + if (Vars.IsEmpty()) { UWingServer::Print(TEXT("ERROR: No variables specified.\n")); return; } + if (!Vars.CheckSanity(WingVariables::Cat::BlueprintVariables)) return; // Associate with existing blueprint variables. - if (!Parsed.AssociateBlueprintNewVariables(BP)) return; + if (!Vars.AssociateBlueprintVariables(BP)) return; // Update types and flags, compile, then update defaults. - Parsed.UpdateVariableTypes(); - Parsed.UpdateVariableFlags(); + Vars.UpdateVariableTypes(); + Vars.UpdateVariableFlags(); FKismetEditorUtilities::CompileBlueprint(BP); - if (!Parsed.UpdateVariableDefaults()) return; + if (!Vars.UpdateVariableDefaults()) return; UWingServer::Printf(TEXT("Success.\n")); } diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h index fa20292d..bd358704 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h @@ -84,12 +84,9 @@ public: } // Variables (new format) - WingVariables BlueprintVars = WingVariables::ParseBlueprintVariables(BP); - if (!BlueprintVars.IsEmpty()) - { - UWingServer::Print(TEXT("\nVariables (new format):\n")); - BlueprintVars.PrintAll(2); - } + WingVariables BlueprintVars; + BlueprintVars.LoadBlueprintVariables(BP); + BlueprintVars.PrintAll(UWingServer::GetPrintBuffer(), true, TEXT("Blueprint Variables 2:")); // Components TArray Components3 = UWingComponentReference::GetAll(BP); diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Dump.h index 191b6a84..f80ad03f 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Dump.h @@ -33,27 +33,8 @@ public: UEdGraph* G = F.Walk(Graph).Cast(); if (!G) return; - FStringBuilderBase &Output = UWingServer::GetPrintBuffer(); - TWeakObjectPtr EntryNode; - TWeakObjectPtr ResultNode; - FBlueprintEditorUtils::GetEntryAndResultNodes(G, EntryNode, ResultNode); - WingVariables Arguments = WingVariables::ParseEditablePinBase(EntryNode.Get()); - WingVariables ReturnValues = WingVariables::ParseEditablePinBase(EntryNode.Get()); - WingVariables Locals = WingVariables::ParseFunctionLocalVariables(EntryNode.Get()); - if (!Arguments.GetVariables().IsEmpty()) - { - Output.Appendf(TEXT("Arguments:\n")); - Arguments.PrintAll(Output, 4); - } - if (!ReturnValues.GetVariables().IsEmpty()) - { - Output.Appendf(TEXT("ReturnValues:\n")); - ReturnValues.PrintAll(Output, 4); - } - if (!Locals.GetVariables().IsEmpty()) - { - Output.Appendf(TEXT("LocalVariables:\n")); - Locals.PrintAll(Output, 4); - } + WingGraphVariables Vars; + Vars.LoadGraph(G); + Vars.PrintAll(UWingServer::GetPrintBuffer(), true); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Modify.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Modify.h index 918aef2c..c8f2c864 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Modify.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Modify.h @@ -18,15 +18,21 @@ class UWing_GraphVariables_Modify : public UObject, public IWingHandler GENERATED_BODY() public: - UPROPERTY(meta=(Description="Path to a function graph (e.g. '/Game/MyBP,graph:MyFunction')")) + UPROPERTY(meta=(Description="Path to a graph")) FString Graph; - UPROPERTY(meta=(Description="Variable declarations, one per line. Format: type name = default")) - FString Variables; + UPROPERTY(meta=(Optional, Description="Argument declarations, one per line.")) + FString Arguments; + + UPROPERTY(meta=(Optional, Description="Return Value declarations, one per line.")) + FString ReturnValues; + + UPROPERTY(meta=(Optional, Description="Local Variable declarations, one per line.")) + FString LocalVariables; virtual FString GetDescription() const override { - return TEXT("Modify existing local variables of a function graph."); + return TEXT("Modify existing arguments, return values, and local variables of a graph."); } virtual void Handle() override @@ -35,15 +41,13 @@ public: UEdGraph* G = F.Walk(Graph).Cast(); if (!G) return; - WingVariables Parsed; - if (!WingVariables::ParseString(Variables, Parsed)) return; - if (Parsed.IsEmpty()) { UWingServer::Print(TEXT("ERROR: No variables specified.\n")); return; } - if (!Parsed.CheckSanity(WingVariables::Cat::FunctionLocal)) return; - - if (!Parsed.AssociateFunctionLocalVariables(G)) return; - Parsed.UpdateVariableTypes(); - Parsed.UpdateVariableFlags(); - Parsed.UpdateVariableDefaults(); + WingGraphVariables Vars; + if (!Vars.ParseStrings(Arguments, ReturnValues, LocalVariables)) return; + if (!Vars.CheckSanity(G)) return; + if (!Vars.AssociateGraph(G)) return; + Vars.UpdateVariableTypes(); + Vars.UpdateVariableFlags(); + Vars.UpdateVariableDefaults(); UWingServer::Printf(TEXT("Success.\n")); } diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Test_ParseVariables.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Test_ParseVariables.h deleted file mode 100644 index 31c82bee..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Test_ParseVariables.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingHandler.h" -#include "WingServer.h" -#include "WingVariables.h" -#include "Test_ParseVariables.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_Test_ParseVariables : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Variable declarations, one per line. Format: type name (flags) = default")) - FString Variables; - - virtual FString GetDescription() const override - { - return TEXT("Test: parse variable declarations and print them back out."); - } - - virtual void Handle() override - { - WingVariables Parsed; - if (!WingVariables::ParseString(Variables, Parsed)) return; - - UWingServer::Print(TEXT("Parsed variables:\n")); - Parsed.PrintAll(1); - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp index 9ac80a27..c327a4d1 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp @@ -289,27 +289,9 @@ void WingGraphExport::EmitMaterialProperties(UEdGraphNode* Node, FStringBuilderB void WingGraphExport::EmitLocalVariables() { - TWeakObjectPtr EntryNode; - TWeakObjectPtr ResultNode; - FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, EntryNode, ResultNode); - WingVariables Arguments = WingVariables::ParseEditablePinBase(EntryNode.Get()); - WingVariables ReturnValues = WingVariables::ParseEditablePinBase(EntryNode.Get()); - WingVariables Locals = WingVariables::ParseFunctionLocalVariables(EntryNode.Get()); - if (!Arguments.GetVariables().IsEmpty()) - { - Output.Appendf(TEXT("Arguments:\n")); - Arguments.PrintAll(Output, 4); - } - if (!ReturnValues.GetVariables().IsEmpty()) - { - Output.Appendf(TEXT("ReturnValues:\n")); - ReturnValues.PrintAll(Output, 4); - } - if (!Locals.GetVariables().IsEmpty()) - { - Output.Appendf(TEXT("LocalVariables:\n")); - Locals.PrintAll(Output, 4); - } + WingGraphVariables Vars; + Vars.LoadGraph(Graph); + Vars.PrintAll(Output, false); } void WingGraphExport::EmitGraph() diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp index 11248552..5d054189 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp @@ -21,15 +21,17 @@ static const FName Flag_ExposeToCinematics(TEXT("ExposeToCinematics")); static TSet Flags_None = { }; static TSet Flags_BlueprintVariables = { Flag_InstanceEditable, Flag_BlueprintReadOnly, Flag_ExposeOnSpawn, Flag_Private, Flag_ExposeToCinematics }; -static TSet Flags_FunctionLocalVariables = { }; const TSet &WingVariables::GetRelevantFlagSet(WingVariables::Cat C) { switch (C) { - case Cat::Blueprint: return Flags_BlueprintVariables; - case Cat::FunctionLocal: return Flags_FunctionLocalVariables; - default: return Flags_None; + case Cat::BlueprintVariables: return Flags_BlueprintVariables; + case Cat::LocalVariables: return Flags_None; + case Cat::FunctionArguments: return Flags_None; + case Cat::FunctionReturnValues: return Flags_None; + case Cat::MacroEntry: return Flags_None; + case Cat::MacroExit: return Flags_None; } } @@ -38,19 +40,36 @@ void WingVariables::Var::AddFlagIfRelevant(FName Flag, WingVariables::Cat C) if (GetRelevantFlagSet(C).Contains(Flag)) Flags.Add(Flag); } -WingVariables WingVariables::ParseBlueprintVariables(UBlueprint *BP) +void WingVariables::Clear() { - WingVariables Result; - Result.Category = Cat::Blueprint; - Result.Blueprint = BP; + Variables.Empty(); + Blueprint = nullptr; + FuncEntry = nullptr; + PinBase = nullptr; +} + +void WingVariables::ClearAssociation() +{ + for (Var V : Variables) + { + V.BPVar = nullptr; + V.Pin = nullptr; + } + Blueprint = nullptr; + FuncEntry = nullptr; + PinBase = nullptr; +} + +void WingVariables::LoadBlueprintVariables(UBlueprint *BP) +{ + Clear(); for (FBPVariableDescription& Desc : BP->NewVariables) { // Skip event dispatchers. if (Desc.VarType.PinCategory == UEdGraphSchema_K2::PC_MCDelegate) continue; // Parse the bulk of the flags. - Var V = ParseVariableDescription(Desc, Cat::Blueprint); - V.BPVar = &Desc; + Var V = ParseVariableDescription(Desc, Cat::BlueprintVariables); // Read default value from CDO if available. if (BP->GeneratedClass) @@ -58,63 +77,51 @@ WingVariables WingVariables::ParseBlueprintVariables(UBlueprint *BP) UObject* CDO = BP->GeneratedClass->GetDefaultObject(); FProperty* Prop = BP->GeneratedClass->FindPropertyByName(Desc.VarName); if (CDO && Prop) + { V.DefaultValue = FWingProperty(Prop, CDO).GetText(); + V.DefaultSpecified = true; + } } - Result.Variables.Add(MoveTemp(V)); + Variables.Add(MoveTemp(V)); } - return Result; } -WingVariables WingVariables::ParseFunctionLocalVariables(UK2Node_EditablePinBase *Node) +void WingVariables::LoadLocalVariables(UK2Node_EditablePinBase *Node) { - WingVariables Result; + Clear(); if (UK2Node_FunctionEntry *Func = Cast(Node)) { - Result.Category = Cat::FunctionLocal; - Result.PinBase = Node; for (FBPVariableDescription& Desc : Func->LocalVariables) { - Var V = ParseVariableDescription(Desc, Cat::FunctionLocal); + Var V = ParseVariableDescription(Desc, Cat::LocalVariables); V.DefaultValue = Desc.DefaultValue; - V.BPVar = &Desc; - Result.Variables.Add(MoveTemp(V)); + V.DefaultSpecified = true; + Variables.Add(MoveTemp(V)); } } - else - { - Result.Category = Cat::Empty; - } - return Result; } -WingVariables WingVariables::ParseEditablePinBase(UK2Node_EditablePinBase* Node) +void WingVariables::LoadEditablePinBase(UK2Node_EditablePinBase* Node) { - WingVariables Result; + Clear(); if (Node != nullptr) { - Result.Category = Cat::EditablePinBase; - Result.PinBase = Node; for (const TSharedPtr& PinInfo : Node->UserDefinedPins) { Var V; V.Name = PinInfo->PinName; V.Type = PinInfo->PinType; V.DefaultValue = PinInfo->PinDefaultValue; - V.Pin = PinInfo; - Result.Variables.Add(MoveTemp(V)); + V.DefaultSpecified = true; + Variables.Add(MoveTemp(V)); } } - else - { - Result.Category = Cat::Empty; - } - return Result; } -bool WingVariables::AssociateBlueprintNewVariables(UBlueprint *BP) +bool WingVariables::AssociateBlueprintVariables(UBlueprint *BP) { - Category = Cat::Blueprint; + ClearAssociation(); Blueprint = BP; for (Var &V : Variables) { @@ -122,15 +129,15 @@ bool WingVariables::AssociateBlueprintNewVariables(UBlueprint *BP) if (Desc == nullptr) return false; V.BPVar = Desc; } - Blueprint = BP; return true; } -bool WingVariables::AssociateFunctionLocalVariables(UK2Node_EditablePinBase *Node) +bool WingVariables::AssociateLocalVariables(UK2Node_EditablePinBase *Node) { - Category = Cat::FunctionLocal; + ClearAssociation(); if (UK2Node_FunctionEntry *Func = Cast(Node)) { + FuncEntry = Func; for (Var &V : Variables) { FBPVariableDescription *Desc = WingUtils::FindOneWithInternalID(V.Name, Func->LocalVariables, TEXT("local variable")); @@ -141,77 +148,75 @@ bool WingVariables::AssociateFunctionLocalVariables(UK2Node_EditablePinBase *Nod } else { + if (Variables.IsEmpty()) { return true; } UWingServer::Printf(TEXT("Graph can't have local variables, not a function graph: %s\n"), *WingUtils::FormatName(Node->GetGraph())); return false; } } -bool WingVariables::AssociateEditablePinBase(UK2Node_EditablePinBase *InPinBase) +bool WingVariables::AssociateEditablePinBase(UK2Node_EditablePinBase *Node) { - if (!InPinBase || !InPinBase->IsEditable()) + ClearAssociation(); + if (Node != nullptr) { - UWingServer::Print(TEXT("ERROR: Node does not have editable pins.\n")); - return false; + PinBase = Node; + for (Var &V : Variables) + { + TSharedPtr *Found = WingUtils::FindOneWithInternalID(V.Name, Node->UserDefinedPins, TEXT("pin")); + if (!Found) return false; + V.Pin = *Found; + } } - Category = Cat::EditablePinBase; - PinBase = InPinBase; - for (Var &V : Variables) + else { - TSharedPtr *Found = WingUtils::FindOneWithInternalID(V.Name, InPinBase->UserDefinedPins, TEXT("pin")); - if (!Found) return false; - V.Pin = *Found; + if (Variables.IsEmpty()) return true; + UWingServer::Printf(TEXT("Cannot modify variables, graph node does not exist yet")); + return false; } return true; } void WingVariables::UpdateVariableTypes() { - switch (Category) - { - case Cat::Blueprint: UpdateBlueprintVariableTypes(); break; - case Cat::FunctionLocal: UpdateLocalVariableTypes(); break; - case Cat::EditablePinBase: UpdateEditablePinBaseTypes(); break; - default: return; - } + if (Blueprint) return UpdateBlueprintVariableTypes(); + if (FuncEntry) return UpdateLocalVariableTypes(); + if (PinBase) return UpdateEditablePinBaseTypes(); } void WingVariables::UpdateVariableFlags() { - switch (Category) - { - case Cat::Blueprint: UpdateBlueprintVariableFlags(); break; - case Cat::FunctionLocal: UpdateLocalVariableFlags(); break; - case Cat::EditablePinBase: UpdateEditablePinBaseFlags(); break; - default: return; - } + if (Blueprint) return UpdateBlueprintVariableFlags(); + if (FuncEntry) return UpdateLocalVariableFlags(); + if (PinBase) return UpdateEditablePinBaseFlags(); } bool WingVariables::UpdateVariableDefaults() { - switch (Category) - { - case Cat::Blueprint: return UpdateBlueprintVariableDefaults(); break; - case Cat::FunctionLocal: return UpdateLocalVariableDefaults(); break; - case Cat::EditablePinBase: return UpdateEditablePinBaseDefaults(); break; - default: return true; - } + if (Blueprint) return UpdateBlueprintVariableDefaults(); + if (FuncEntry) return UpdateLocalVariableDefaults(); + if (PinBase) return UpdateEditablePinBaseDefaults(); + return true; } +bool WingVariables::CheckEmpty(Cat Category) +{ + if (!Variables.IsEmpty()) + { + UWingServer::Printf(TEXT("This kind of graph is not allowed to have %s"), + *StaticEnum()->GetNameStringByValue(int(Category))); + return false; + } + return true; +} bool WingVariables::CheckSanity(Cat Category) { const TSet &Relevant = GetRelevantFlagSet(Category); - TSet NamesUsed; for (const Var &Variable : Variables) { FString VarName = WingUtils::ExternalizeID(Variable.Name); FString TypeText = UWingTypes::TypeToText(Variable.Type); - if (NamesUsed.Contains(Variable.Name)) - { - UWingServer::Printf(TEXT("Variable name appears twice: %s\n"), *VarName); - return false; - } if (TypeText.IsEmpty()) { UWingServer::Printf(TEXT("Type of variable %s is not valid for unknown reasons\n"), *VarName); @@ -235,7 +240,6 @@ bool WingVariables::CheckSanity(Cat Category) return true; } - bool WingVariables::ParseVariableFlags(WingTokenizer &Tok, TSet &Out) { Tok.Advance(); // Step over open-paren @@ -346,11 +350,16 @@ WingVariables::Var WingVariables::ParseVariableDescription(const FBPVariableDesc return Result; } -void WingVariables::PrintAll(FStringBuilderBase &Out, int32 Indent) +void WingVariables::PrintAll(FStringBuilderBase &Out, bool Always, const TCHAR *Header) { - FString Prefix; - for (int32 i = 0; i < Indent; i++) Prefix += TEXT(" "); - + if (Header != nullptr) + { + if (Always || (!Variables.IsEmpty())) + { + Out.Append(Header); + Out.AppendChar('\n'); + } + } for (const Var& V : Variables) { FString TypeStr = UWingTypes::TypeToText(V.Type); @@ -370,7 +379,7 @@ void WingVariables::PrintAll(FStringBuilderBase &Out, int32 Indent) } // Print: type name (flags) = defaultvalue - Out.Appendf(TEXT("%s%s %s"), *Prefix, *TypeStr, *NameStr); + Out.Appendf(TEXT(" %s %s"), *TypeStr, *NameStr); if (!FlagsStr.IsEmpty()) Out.Appendf(TEXT(" (%s)"), *FlagsStr); if (!V.DefaultValue.IsEmpty()) @@ -379,11 +388,6 @@ void WingVariables::PrintAll(FStringBuilderBase &Out, int32 Indent) } } -void WingVariables::PrintAll(int32 Indent) -{ - PrintAll(UWingServer::GetPrintBuffer(), Indent); -} - void WingVariables::UpdateBlueprintVariableTypes() { for (const Var &Input : Variables) @@ -505,17 +509,17 @@ bool WingVariables::UpdateEditablePinBaseDefaults() return true; } -void WingGraphVariables::ParseGraph(const UEdGraph *Graph) +void WingGraphVariables::LoadGraph(const UEdGraph *Graph) { TWeakObjectPtr EntryNode; TWeakObjectPtr ResultNode; FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, EntryNode, ResultNode); - Arguments = WingVariables::ParseEditablePinBase(EntryNode.Get()); - ReturnValues = WingVariables::ParseEditablePinBase(ResultNode.Get()); - LocalVariables = WingVariables::ParseLocalVariables(EntryNode.Get()); + Arguments.LoadEditablePinBase(EntryNode.Get()); + ReturnValues.LoadEditablePinBase(ResultNode.Get()); + LocalVariables.LoadLocalVariables(EntryNode.Get()); } -bool WingGraphVariables::ParseAll(const FString &A, const FString &R, const FString &L) +bool WingGraphVariables::ParseStrings(const FString &A, const FString &R, const FString &L) { if (!Arguments.ParseString(A)) return false; if (!ReturnValues.ParseString(R)) return false; @@ -523,7 +527,7 @@ bool WingGraphVariables::ParseAll(const FString &A, const FString &R, const FStr return true; } -bool WingGraphVariables::AssociateAll(const UEdGraph *Graph) +bool WingGraphVariables::AssociateGraph(const UEdGraph *Graph) { TWeakObjectPtr EntryNode; TWeakObjectPtr ResultNode; @@ -534,3 +538,55 @@ bool WingGraphVariables::AssociateAll(const UEdGraph *Graph) if (!LocalVariables.AssociateLocalVariables(EntryNode.Get())) OK = false; return OK; } + +void WingGraphVariables::PrintAll(FStringBuilderBase &Out, bool Always) +{ + Arguments.PrintAll(Out, Always, TEXT("Arguments:")); + ReturnValues.PrintAll(Out, Always, TEXT("ReturnValues:")); + LocalVariables.PrintAll(Out, Always, TEXT("LocalVariables:")); +} + +void WingGraphVariables::UpdateVariableTypes() +{ + Arguments.UpdateVariableTypes(); + ReturnValues.UpdateVariableTypes(); + LocalVariables.UpdateVariableTypes(); +} + +void WingGraphVariables::UpdateVariableFlags() +{ + Arguments.UpdateVariableFlags(); + ReturnValues.UpdateVariableFlags(); + LocalVariables.UpdateVariableFlags(); +} + +bool WingGraphVariables::UpdateVariableDefaults() +{ + return Arguments.UpdateVariableDefaults() && + ReturnValues.UpdateVariableDefaults() && + LocalVariables.UpdateVariableDefaults(); +} + +bool WingGraphVariables::CheckSanity(const UEdGraph *Graph) +{ + EGraphType Type = Graph->GetSchema()->GetGraphType(Graph); + if (Type == EGraphType::GT_Function) + { + return Arguments.CheckSanity(Cat::FunctionArguments) && + ReturnValues.CheckSanity(Cat::FunctionReturnValues) && + LocalVariables.CheckSanity(Cat::LocalVariables); + } + else if (Type == EGraphType::GT_Macro) + { + return Arguments.CheckSanity(Cat::MacroEntry) && + ReturnValues.CheckSanity(Cat::MacroExit) && + LocalVariables.CheckEmpty(Cat::LocalVariables); + } + else + { + UWingServer::Printf( + TEXT("Graphs of this type may not have arguments, return values, or local variables.")); + return false; + } +} + diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h b/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h index fa1cb9d2..3ab1cc03 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h @@ -3,20 +3,26 @@ #include "CoreMinimal.h" #include "EdGraph/EdGraphPin.h" #include "Engine/Blueprint.h" -#include "K2Node_EditablePinBase.h" struct WingTokenizer; +class UK2Node_EditablePinBase; +class UK2Node_FunctionEntry; + +UENUM() +enum class EWingVariableCategory : uint8 +{ + BlueprintVariables, + LocalVariables, + FunctionArguments, + FunctionReturnValues, + MacroEntry, + MacroExit +}; class WingVariables { public: - enum class Cat - { - Empty, - Blueprint, - LocalVariable, - EditablePinBase, - }; + using Cat = EWingVariableCategory; struct Var { @@ -48,15 +54,15 @@ public: }; private: - // The category of these variables. - Cat Category; - // A list of all the variables. TArray Variables; // A pointer to a blueprint. UBlueprint *Blueprint = nullptr; + // A pointer to a Function entry node. + UK2Node_FunctionEntry *FuncEntry = nullptr; + // A pointer to an editable pin base. UK2Node_EditablePinBase* PinBase = nullptr; @@ -71,26 +77,35 @@ public: bool IsEmpty() const { return Variables.IsEmpty(); } // Print all the variables to a string builder. - void PrintAll(FStringBuilderBase &Out, int32 Indent = 0); - - // Print all the variables via UWingServer. - void PrintAll(int32 Indent = 0); + void PrintAll(FStringBuilderBase &Out, bool Always, const TCHAR *Header); - // Make sure that this variable list makes sense for the given context. - bool CheckSanity(Cat Category); + // Clear everything + void Clear(); + + // Clear any association. + void ClearAssociation(); + + // Check the sanity. + bool CheckSanity(Cat C); + + // Check that the variables are empty. + bool CheckEmpty(Cat C); // Parse variables from a string. One variable per line. // Format: type name (flag1, flag2) = defaultvalue // Returns false on parse error. bool ParseString(const FString &Input); - // Parse variables from a given source. - static WingVariables ParseBlueprintVariables(UBlueprint *BP); - static WingVariables ParseLocalVariables(UK2Node_EditablePinBase* Node); - static WingVariables ParseEditablePinBase(UK2Node_EditablePinBase* Node); + // Make a best effort to load all available existing state. + // This does not associate the variables. If you want to manipulate + // the variables, you'll have to associate them. + void LoadBlueprintVariables(UBlueprint *BP); + void LoadLocalVariables(UK2Node_EditablePinBase* Node); + void LoadEditablePinBase(UK2Node_EditablePinBase* Node); - // Associate every variable in the list with an existing blueprint variable. - bool AssociateBlueprintNewVariables(UBlueprint *BP); + // Associate every variable in the list with an existing + // variable in a blueprint or graph. + bool AssociateBlueprintVariables(UBlueprint *BP); bool AssociateLocalVariables(UK2Node_EditablePinBase* Node); bool AssociateEditablePinBase(UK2Node_EditablePinBase* Node); @@ -123,8 +138,19 @@ struct WingGraphVariables WingGraphVariables() {} - void ParseGraph(const UEdGraph *Graph); - bool ParseStrings(const FString &A, const FString &R, const FString &L); + using Cat = WingVariables::Cat; + + void LoadGraph(const UEdGraph *Graph); bool AssociateGraph(const UEdGraph *Graph); + bool ParseStrings(const FString &A, const FString &R, const FString &L); + void PrintAll(FStringBuilderBase &Out, bool Always); + void UpdateVariableTypes(); + void UpdateVariableFlags(); + bool UpdateVariableDefaults(); + bool CheckSanity(const UEdGraph *Graph); + +private: + static Cat GraphEntryCategory(const UEdGraph *Graph); + static Cat GraphExitCategory(const UEdGraph *Graph); };