Progress on variable modification

This commit is contained in:
2026-03-30 23:45:53 -04:00
parent e982fec1a4
commit 9720fa9f8d
11 changed files with 248 additions and 238 deletions

Binary file not shown.

View File

@@ -41,18 +41,17 @@ public:
if (!BP) return; if (!BP) return;
// Parse the variable declarations. // Parse the variable declarations.
WingVariables Parsed; WingVariables Vars;
if (!WingVariables::ParseString(Variables, Parsed)) return; if (!Vars.ParseString(Variables)) return;
if (Parsed.IsEmpty()) { UWingServer::Print(TEXT("ERROR: No variables specified.\n")); return; } if (Vars.IsEmpty()) { UWingServer::Print(TEXT("ERROR: No variables specified.\n")); return; }
if (!Parsed.CheckSanity(WingVariables::Cat::Blueprint)) return;
// Check for name collisions against existing variables, components, and the like. // Check for name collisions against existing variables, components, and the like.
TSet<FName> Names; TSet<FName> Names;
FBlueprintEditorUtils::GetClassVariableList(BP, 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. // 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)) if (!FBlueprintEditorUtils::AddMemberVariable(BP, V.Name, V.Type))
{ {
@@ -63,10 +62,10 @@ public:
} }
// Update everything. // Update everything.
if (!Parsed.AssociateBlueprintNewVariables(BP)) return; if (!Vars.AssociateBlueprintVariables(BP)) return;
Parsed.UpdateVariableFlags(); Vars.UpdateVariableFlags();
FKismetEditorUtilities::CompileBlueprint(BP); FKismetEditorUtilities::CompileBlueprint(BP);
if (!Parsed.UpdateVariableDefaults()) return; if (!Vars.UpdateVariableDefaults()) return;
UWingServer::Printf(TEXT("Success.\n")); UWingServer::Printf(TEXT("Success.\n"));
} }
}; };

View File

@@ -32,8 +32,9 @@ public:
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>(); UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return; if (!BP) return;
WingVariables Vars = WingVariables::ParseBlueprintVariables(BP); WingVariables Vars;
Vars.LoadBlueprintVariables(BP);
if (Vars.IsEmpty()) { UWingServer::Print(TEXT("No variables.\n")); return; } if (Vars.IsEmpty()) { UWingServer::Print(TEXT("No variables.\n")); return; }
Vars.PrintAll(); Vars.PrintAll(UWingServer::GetPrintBuffer(), true, TEXT("Blueprint Variables:"));
} }
}; };

View File

@@ -39,19 +39,19 @@ public:
if (!BP) return; if (!BP) return;
// Parse the variable declarations. // Parse the variable declarations.
WingVariables Parsed; WingVariables Vars;
if (!WingVariables::ParseString(Variables, Parsed)) return; if (!Vars.ParseString(Variables)) return;
if (Parsed.IsEmpty()) { UWingServer::Print(TEXT("ERROR: No variables specified.\n")); return; } if (Vars.IsEmpty()) { UWingServer::Print(TEXT("ERROR: No variables specified.\n")); return; }
if (!Parsed.CheckSanity(WingVariables::Cat::Blueprint)) return; if (!Vars.CheckSanity(WingVariables::Cat::BlueprintVariables)) return;
// Associate with existing blueprint variables. // Associate with existing blueprint variables.
if (!Parsed.AssociateBlueprintNewVariables(BP)) return; if (!Vars.AssociateBlueprintVariables(BP)) return;
// Update types and flags, compile, then update defaults. // Update types and flags, compile, then update defaults.
Parsed.UpdateVariableTypes(); Vars.UpdateVariableTypes();
Parsed.UpdateVariableFlags(); Vars.UpdateVariableFlags();
FKismetEditorUtilities::CompileBlueprint(BP); FKismetEditorUtilities::CompileBlueprint(BP);
if (!Parsed.UpdateVariableDefaults()) return; if (!Vars.UpdateVariableDefaults()) return;
UWingServer::Printf(TEXT("Success.\n")); UWingServer::Printf(TEXT("Success.\n"));
} }

View File

@@ -84,12 +84,9 @@ public:
} }
// Variables (new format) // Variables (new format)
WingVariables BlueprintVars = WingVariables::ParseBlueprintVariables(BP); WingVariables BlueprintVars;
if (!BlueprintVars.IsEmpty()) BlueprintVars.LoadBlueprintVariables(BP);
{ BlueprintVars.PrintAll(UWingServer::GetPrintBuffer(), true, TEXT("Blueprint Variables 2:"));
UWingServer::Print(TEXT("\nVariables (new format):\n"));
BlueprintVars.PrintAll(2);
}
// Components // Components
TArray<UWingComponentReference*> Components3 = UWingComponentReference::GetAll(BP); TArray<UWingComponentReference*> Components3 = UWingComponentReference::GetAll(BP);

View File

@@ -33,27 +33,8 @@ public:
UEdGraph* G = F.Walk(Graph).Cast<UEdGraph>(); UEdGraph* G = F.Walk(Graph).Cast<UEdGraph>();
if (!G) return; if (!G) return;
FStringBuilderBase &Output = UWingServer::GetPrintBuffer(); WingGraphVariables Vars;
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode; Vars.LoadGraph(G);
TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode; Vars.PrintAll(UWingServer::GetPrintBuffer(), true);
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);
}
} }
}; };

View File

@@ -18,15 +18,21 @@ class UWing_GraphVariables_Modify : public UObject, public IWingHandler
GENERATED_BODY() GENERATED_BODY()
public: public:
UPROPERTY(meta=(Description="Path to a function graph (e.g. '/Game/MyBP,graph:MyFunction')")) UPROPERTY(meta=(Description="Path to a graph"))
FString Graph; FString Graph;
UPROPERTY(meta=(Description="Variable declarations, one per line. Format: type name = default")) UPROPERTY(meta=(Optional, Description="Argument declarations, one per line."))
FString Variables; 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 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 virtual void Handle() override
@@ -35,15 +41,13 @@ public:
UEdGraph* G = F.Walk(Graph).Cast<UEdGraph>(); UEdGraph* G = F.Walk(Graph).Cast<UEdGraph>();
if (!G) return; if (!G) return;
WingVariables Parsed; WingGraphVariables Vars;
if (!WingVariables::ParseString(Variables, Parsed)) return; if (!Vars.ParseStrings(Arguments, ReturnValues, LocalVariables)) return;
if (Parsed.IsEmpty()) { UWingServer::Print(TEXT("ERROR: No variables specified.\n")); return; } if (!Vars.CheckSanity(G)) return;
if (!Parsed.CheckSanity(WingVariables::Cat::FunctionLocal)) return; if (!Vars.AssociateGraph(G)) return;
Vars.UpdateVariableTypes();
if (!Parsed.AssociateFunctionLocalVariables(G)) return; Vars.UpdateVariableFlags();
Parsed.UpdateVariableTypes(); Vars.UpdateVariableDefaults();
Parsed.UpdateVariableFlags();
Parsed.UpdateVariableDefaults();
UWingServer::Printf(TEXT("Success.\n")); UWingServer::Printf(TEXT("Success.\n"));
} }

View File

@@ -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);
}
};

View File

@@ -289,27 +289,9 @@ void WingGraphExport::EmitMaterialProperties(UEdGraphNode* Node, FStringBuilderB
void WingGraphExport::EmitLocalVariables() void WingGraphExport::EmitLocalVariables()
{ {
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode; WingGraphVariables Vars;
TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode; Vars.LoadGraph(Graph);
FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, EntryNode, ResultNode); Vars.PrintAll(Output, false);
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);
}
} }
void WingGraphExport::EmitGraph() void WingGraphExport::EmitGraph()

View File

@@ -21,15 +21,17 @@ static const FName Flag_ExposeToCinematics(TEXT("ExposeToCinematics"));
static TSet<FName> Flags_None = { }; static TSet<FName> Flags_None = { };
static TSet<FName> Flags_BlueprintVariables = { Flag_InstanceEditable, Flag_BlueprintReadOnly, Flag_ExposeOnSpawn, Flag_Private, Flag_ExposeToCinematics }; static TSet<FName> Flags_BlueprintVariables = { Flag_InstanceEditable, Flag_BlueprintReadOnly, Flag_ExposeOnSpawn, Flag_Private, Flag_ExposeToCinematics };
static TSet<FName> Flags_FunctionLocalVariables = { };
const TSet<FName> &WingVariables::GetRelevantFlagSet(WingVariables::Cat C) const TSet<FName> &WingVariables::GetRelevantFlagSet(WingVariables::Cat C)
{ {
switch (C) switch (C)
{ {
case Cat::Blueprint: return Flags_BlueprintVariables; case Cat::BlueprintVariables: return Flags_BlueprintVariables;
case Cat::FunctionLocal: return Flags_FunctionLocalVariables; case Cat::LocalVariables: return Flags_None;
default: 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); if (GetRelevantFlagSet(C).Contains(Flag)) Flags.Add(Flag);
} }
WingVariables WingVariables::ParseBlueprintVariables(UBlueprint *BP) void WingVariables::Clear()
{ {
WingVariables Result; Variables.Empty();
Result.Category = Cat::Blueprint; Blueprint = nullptr;
Result.Blueprint = BP; 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) for (FBPVariableDescription& Desc : BP->NewVariables)
{ {
// Skip event dispatchers. // Skip event dispatchers.
if (Desc.VarType.PinCategory == UEdGraphSchema_K2::PC_MCDelegate) continue; if (Desc.VarType.PinCategory == UEdGraphSchema_K2::PC_MCDelegate) continue;
// Parse the bulk of the flags. // Parse the bulk of the flags.
Var V = ParseVariableDescription(Desc, Cat::Blueprint); Var V = ParseVariableDescription(Desc, Cat::BlueprintVariables);
V.BPVar = &Desc;
// Read default value from CDO if available. // Read default value from CDO if available.
if (BP->GeneratedClass) if (BP->GeneratedClass)
@@ -58,63 +77,51 @@ WingVariables WingVariables::ParseBlueprintVariables(UBlueprint *BP)
UObject* CDO = BP->GeneratedClass->GetDefaultObject(); UObject* CDO = BP->GeneratedClass->GetDefaultObject();
FProperty* Prop = BP->GeneratedClass->FindPropertyByName(Desc.VarName); FProperty* Prop = BP->GeneratedClass->FindPropertyByName(Desc.VarName);
if (CDO && Prop) if (CDO && Prop)
{
V.DefaultValue = FWingProperty(Prop, CDO).GetText(); 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<UK2Node_FunctionEntry>(Node)) if (UK2Node_FunctionEntry *Func = Cast<UK2Node_FunctionEntry>(Node))
{ {
Result.Category = Cat::FunctionLocal;
Result.PinBase = Node;
for (FBPVariableDescription& Desc : Func->LocalVariables) for (FBPVariableDescription& Desc : Func->LocalVariables)
{ {
Var V = ParseVariableDescription(Desc, Cat::FunctionLocal); Var V = ParseVariableDescription(Desc, Cat::LocalVariables);
V.DefaultValue = Desc.DefaultValue; V.DefaultValue = Desc.DefaultValue;
V.BPVar = &Desc; V.DefaultSpecified = true;
Result.Variables.Add(MoveTemp(V)); 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) if (Node != nullptr)
{ {
Result.Category = Cat::EditablePinBase;
Result.PinBase = Node;
for (const TSharedPtr<FUserPinInfo>& PinInfo : Node->UserDefinedPins) for (const TSharedPtr<FUserPinInfo>& PinInfo : Node->UserDefinedPins)
{ {
Var V; Var V;
V.Name = PinInfo->PinName; V.Name = PinInfo->PinName;
V.Type = PinInfo->PinType; V.Type = PinInfo->PinType;
V.DefaultValue = PinInfo->PinDefaultValue; V.DefaultValue = PinInfo->PinDefaultValue;
V.Pin = PinInfo; V.DefaultSpecified = true;
Result.Variables.Add(MoveTemp(V)); 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; Blueprint = BP;
for (Var &V : Variables) for (Var &V : Variables)
{ {
@@ -122,15 +129,15 @@ bool WingVariables::AssociateBlueprintNewVariables(UBlueprint *BP)
if (Desc == nullptr) return false; if (Desc == nullptr) return false;
V.BPVar = Desc; V.BPVar = Desc;
} }
Blueprint = BP;
return true; return true;
} }
bool WingVariables::AssociateFunctionLocalVariables(UK2Node_EditablePinBase *Node) bool WingVariables::AssociateLocalVariables(UK2Node_EditablePinBase *Node)
{ {
Category = Cat::FunctionLocal; ClearAssociation();
if (UK2Node_FunctionEntry *Func = Cast<UK2Node_FunctionEntry>(Node)) if (UK2Node_FunctionEntry *Func = Cast<UK2Node_FunctionEntry>(Node))
{ {
FuncEntry = Func;
for (Var &V : Variables) for (Var &V : Variables)
{ {
FBPVariableDescription *Desc = WingUtils::FindOneWithInternalID(V.Name, Func->LocalVariables, TEXT("local variable")); FBPVariableDescription *Desc = WingUtils::FindOneWithInternalID(V.Name, Func->LocalVariables, TEXT("local variable"));
@@ -141,77 +148,75 @@ bool WingVariables::AssociateFunctionLocalVariables(UK2Node_EditablePinBase *Nod
} }
else else
{ {
if (Variables.IsEmpty()) { return true; }
UWingServer::Printf(TEXT("Graph can't have local variables, not a function graph: %s\n"), UWingServer::Printf(TEXT("Graph can't have local variables, not a function graph: %s\n"),
*WingUtils::FormatName(Node->GetGraph())); *WingUtils::FormatName(Node->GetGraph()));
return false; 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")); PinBase = Node;
return false;
}
Category = Cat::EditablePinBase;
PinBase = InPinBase;
for (Var &V : Variables) for (Var &V : Variables)
{ {
TSharedPtr<FUserPinInfo> *Found = WingUtils::FindOneWithInternalID(V.Name, InPinBase->UserDefinedPins, TEXT("pin")); TSharedPtr<FUserPinInfo> *Found = WingUtils::FindOneWithInternalID(V.Name, Node->UserDefinedPins, TEXT("pin"));
if (!Found) return false; if (!Found) return false;
V.Pin = *Found; V.Pin = *Found;
} }
}
else
{
if (Variables.IsEmpty()) return true;
UWingServer::Printf(TEXT("Cannot modify variables, graph node does not exist yet"));
return false;
}
return true; return true;
} }
void WingVariables::UpdateVariableTypes() void WingVariables::UpdateVariableTypes()
{ {
switch (Category) if (Blueprint) return UpdateBlueprintVariableTypes();
{ if (FuncEntry) return UpdateLocalVariableTypes();
case Cat::Blueprint: UpdateBlueprintVariableTypes(); break; if (PinBase) return UpdateEditablePinBaseTypes();
case Cat::FunctionLocal: UpdateLocalVariableTypes(); break;
case Cat::EditablePinBase: UpdateEditablePinBaseTypes(); break;
default: return;
}
} }
void WingVariables::UpdateVariableFlags() void WingVariables::UpdateVariableFlags()
{ {
switch (Category) if (Blueprint) return UpdateBlueprintVariableFlags();
{ if (FuncEntry) return UpdateLocalVariableFlags();
case Cat::Blueprint: UpdateBlueprintVariableFlags(); break; if (PinBase) return UpdateEditablePinBaseFlags();
case Cat::FunctionLocal: UpdateLocalVariableFlags(); break;
case Cat::EditablePinBase: UpdateEditablePinBaseFlags(); break;
default: return;
}
} }
bool WingVariables::UpdateVariableDefaults() bool WingVariables::UpdateVariableDefaults()
{ {
switch (Category) if (Blueprint) return UpdateBlueprintVariableDefaults();
{ if (FuncEntry) return UpdateLocalVariableDefaults();
case Cat::Blueprint: return UpdateBlueprintVariableDefaults(); break; if (PinBase) return UpdateEditablePinBaseDefaults();
case Cat::FunctionLocal: return UpdateLocalVariableDefaults(); break; return true;
case Cat::EditablePinBase: return UpdateEditablePinBaseDefaults(); break;
default: return true;
}
} }
bool WingVariables::CheckEmpty(Cat Category)
{
if (!Variables.IsEmpty())
{
UWingServer::Printf(TEXT("This kind of graph is not allowed to have %s"),
*StaticEnum<EWingVariableCategory>()->GetNameStringByValue(int(Category)));
return false;
}
return true;
}
bool WingVariables::CheckSanity(Cat Category) bool WingVariables::CheckSanity(Cat Category)
{ {
const TSet<FName> &Relevant = GetRelevantFlagSet(Category); const TSet<FName> &Relevant = GetRelevantFlagSet(Category);
TSet<FName> NamesUsed;
for (const Var &Variable : Variables) for (const Var &Variable : Variables)
{ {
FString VarName = WingUtils::ExternalizeID(Variable.Name); FString VarName = WingUtils::ExternalizeID(Variable.Name);
FString TypeText = UWingTypes::TypeToText(Variable.Type); 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()) if (TypeText.IsEmpty())
{ {
UWingServer::Printf(TEXT("Type of variable %s is not valid for unknown reasons\n"), *VarName); 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; return true;
} }
bool WingVariables::ParseVariableFlags(WingTokenizer &Tok, TSet<FName> &Out) bool WingVariables::ParseVariableFlags(WingTokenizer &Tok, TSet<FName> &Out)
{ {
Tok.Advance(); // Step over open-paren Tok.Advance(); // Step over open-paren
@@ -346,11 +350,16 @@ WingVariables::Var WingVariables::ParseVariableDescription(const FBPVariableDesc
return Result; return Result;
} }
void WingVariables::PrintAll(FStringBuilderBase &Out, int32 Indent) void WingVariables::PrintAll(FStringBuilderBase &Out, bool Always, const TCHAR *Header)
{ {
FString Prefix; if (Header != nullptr)
for (int32 i = 0; i < Indent; i++) Prefix += TEXT(" "); {
if (Always || (!Variables.IsEmpty()))
{
Out.Append(Header);
Out.AppendChar('\n');
}
}
for (const Var& V : Variables) for (const Var& V : Variables)
{ {
FString TypeStr = UWingTypes::TypeToText(V.Type); FString TypeStr = UWingTypes::TypeToText(V.Type);
@@ -370,7 +379,7 @@ void WingVariables::PrintAll(FStringBuilderBase &Out, int32 Indent)
} }
// Print: type name (flags) = defaultvalue // Print: type name (flags) = defaultvalue
Out.Appendf(TEXT("%s%s %s"), *Prefix, *TypeStr, *NameStr); Out.Appendf(TEXT(" %s %s"), *TypeStr, *NameStr);
if (!FlagsStr.IsEmpty()) if (!FlagsStr.IsEmpty())
Out.Appendf(TEXT(" (%s)"), *FlagsStr); Out.Appendf(TEXT(" (%s)"), *FlagsStr);
if (!V.DefaultValue.IsEmpty()) 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() void WingVariables::UpdateBlueprintVariableTypes()
{ {
for (const Var &Input : Variables) for (const Var &Input : Variables)
@@ -505,17 +509,17 @@ bool WingVariables::UpdateEditablePinBaseDefaults()
return true; return true;
} }
void WingGraphVariables::ParseGraph(const UEdGraph *Graph) void WingGraphVariables::LoadGraph(const UEdGraph *Graph)
{ {
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode; TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode;
TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode; TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode;
FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, EntryNode, ResultNode); FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, EntryNode, ResultNode);
Arguments = WingVariables::ParseEditablePinBase(EntryNode.Get()); Arguments.LoadEditablePinBase(EntryNode.Get());
ReturnValues = WingVariables::ParseEditablePinBase(ResultNode.Get()); ReturnValues.LoadEditablePinBase(ResultNode.Get());
LocalVariables = WingVariables::ParseLocalVariables(EntryNode.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 (!Arguments.ParseString(A)) return false;
if (!ReturnValues.ParseString(R)) 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; return true;
} }
bool WingGraphVariables::AssociateAll(const UEdGraph *Graph) bool WingGraphVariables::AssociateGraph(const UEdGraph *Graph)
{ {
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode; TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode;
TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode; TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode;
@@ -534,3 +538,55 @@ bool WingGraphVariables::AssociateAll(const UEdGraph *Graph)
if (!LocalVariables.AssociateLocalVariables(EntryNode.Get())) OK = false; if (!LocalVariables.AssociateLocalVariables(EntryNode.Get())) OK = false;
return OK; 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;
}
}

View File

@@ -3,20 +3,26 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "EdGraph/EdGraphPin.h" #include "EdGraph/EdGraphPin.h"
#include "Engine/Blueprint.h" #include "Engine/Blueprint.h"
#include "K2Node_EditablePinBase.h"
struct WingTokenizer; struct WingTokenizer;
class UK2Node_EditablePinBase;
class UK2Node_FunctionEntry;
UENUM()
enum class EWingVariableCategory : uint8
{
BlueprintVariables,
LocalVariables,
FunctionArguments,
FunctionReturnValues,
MacroEntry,
MacroExit
};
class WingVariables class WingVariables
{ {
public: public:
enum class Cat using Cat = EWingVariableCategory;
{
Empty,
Blueprint,
LocalVariable,
EditablePinBase,
};
struct Var struct Var
{ {
@@ -48,15 +54,15 @@ public:
}; };
private: private:
// The category of these variables.
Cat Category;
// A list of all the variables. // A list of all the variables.
TArray<Var> Variables; TArray<Var> Variables;
// A pointer to a blueprint. // A pointer to a blueprint.
UBlueprint *Blueprint = nullptr; UBlueprint *Blueprint = nullptr;
// A pointer to a Function entry node.
UK2Node_FunctionEntry *FuncEntry = nullptr;
// A pointer to an editable pin base. // A pointer to an editable pin base.
UK2Node_EditablePinBase* PinBase = nullptr; UK2Node_EditablePinBase* PinBase = nullptr;
@@ -71,26 +77,35 @@ public:
bool IsEmpty() const { return Variables.IsEmpty(); } bool IsEmpty() const { return Variables.IsEmpty(); }
// Print all the variables to a string builder. // Print all the variables to a string builder.
void PrintAll(FStringBuilderBase &Out, int32 Indent = 0); void PrintAll(FStringBuilderBase &Out, bool Always, const TCHAR *Header);
// Print all the variables via UWingServer. // Clear everything
void PrintAll(int32 Indent = 0); void Clear();
// Make sure that this variable list makes sense for the given context. // Clear any association.
bool CheckSanity(Cat Category); 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. // Parse variables from a string. One variable per line.
// Format: type name (flag1, flag2) = defaultvalue // Format: type name (flag1, flag2) = defaultvalue
// Returns false on parse error. // Returns false on parse error.
bool ParseString(const FString &Input); bool ParseString(const FString &Input);
// Parse variables from a given source. // Make a best effort to load all available existing state.
static WingVariables ParseBlueprintVariables(UBlueprint *BP); // This does not associate the variables. If you want to manipulate
static WingVariables ParseLocalVariables(UK2Node_EditablePinBase* Node); // the variables, you'll have to associate them.
static WingVariables ParseEditablePinBase(UK2Node_EditablePinBase* Node); 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. // Associate every variable in the list with an existing
bool AssociateBlueprintNewVariables(UBlueprint *BP); // variable in a blueprint or graph.
bool AssociateBlueprintVariables(UBlueprint *BP);
bool AssociateLocalVariables(UK2Node_EditablePinBase* Node); bool AssociateLocalVariables(UK2Node_EditablePinBase* Node);
bool AssociateEditablePinBase(UK2Node_EditablePinBase* Node); bool AssociateEditablePinBase(UK2Node_EditablePinBase* Node);
@@ -123,8 +138,19 @@ struct WingGraphVariables
WingGraphVariables() {} WingGraphVariables() {}
void ParseGraph(const UEdGraph *Graph); using Cat = WingVariables::Cat;
bool ParseStrings(const FString &A, const FString &R, const FString &L);
void LoadGraph(const UEdGraph *Graph);
bool AssociateGraph(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);
}; };