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;
// 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<FName> 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"));
}
};

View File

@@ -32,8 +32,9 @@ public:
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
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:"));
}
};

View File

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

View File

@@ -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<UWingComponentReference*> Components3 = UWingComponentReference::GetAll(BP);

View File

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

View File

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

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()
{
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode;
TWeakObjectPtr<UK2Node_EditablePinBase> 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()

View File

@@ -21,15 +21,17 @@ static const FName Flag_ExposeToCinematics(TEXT("ExposeToCinematics"));
static TSet<FName> Flags_None = { };
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)
{
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<UK2Node_FunctionEntry>(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<FUserPinInfo>& 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<UK2Node_FunctionEntry>(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;
}
Category = Cat::EditablePinBase;
PinBase = InPinBase;
PinBase = Node;
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;
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;
}
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<EWingVariableCategory>()->GetNameStringByValue(int(Category)));
return false;
}
return true;
}
bool WingVariables::CheckSanity(Cat Category)
{
const TSet<FName> &Relevant = GetRelevantFlagSet(Category);
TSet<FName> 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<FName> &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<UK2Node_EditablePinBase> EntryNode;
TWeakObjectPtr<UK2Node_EditablePinBase> 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<UK2Node_EditablePinBase> EntryNode;
TWeakObjectPtr<UK2Node_EditablePinBase> 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;
}
}

View File

@@ -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<Var> 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);
void PrintAll(FStringBuilderBase &Out, bool Always, const TCHAR *Header);
// Print all the variables via UWingServer.
void PrintAll(int32 Indent = 0);
// Clear everything
void Clear();
// Make sure that this variable list makes sense for the given context.
bool CheckSanity(Cat Category);
// 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);
};