diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Create.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Create.h index 9c4e4bad..2a55395c 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Create.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Create.h @@ -5,12 +5,9 @@ #include "WingHandler.h" #include "WingFetcher.h" #include "WingUtils.h" -#include "WingFunctionArgs.h" +#include "WingVariables.h" #include "Engine/Blueprint.h" #include "EdGraph/EdGraph.h" -#include "EdGraph/EdGraphNode.h" -#include "K2Node_EditablePinBase.h" -#include "K2Node_FunctionResult.h" #include "EdGraphSchema_K2.h" #include "Kismet2/BlueprintEditorUtils.h" #include "BlueprintGraph_Create.generated.h" @@ -35,11 +32,11 @@ public: UPROPERTY(meta=(Description="Type of graph: function or macro")) FString GraphType; - UPROPERTY(meta=(Description="Arguments expressed as: int x,float y")) - FString Arguments; + UPROPERTY(meta=(Optional, Description="Input variables, one per line")) + FString InputVariables; - UPROPERTY(meta=(Description="Return values expressed as: int x,float y")) - FString ReturnValues; + UPROPERTY(meta=(Optional, Description="Output variables, one per line")) + FString OutputVariables; virtual FString GetDescription() const override { @@ -81,9 +78,10 @@ public: if (!WingUtils::FindNoneWithInternalID(InternalID, WingUtils::AllGraphs(BP), TEXT("Graph"))) return; - // Validate argument and return value types before making changes - if (!Arguments.IsEmpty() && !WingFunctionArgs::CheckArgs(Arguments)) return; - if (!ReturnValues.IsEmpty() && !WingFunctionArgs::CheckArgs(ReturnValues)) return; + // Parse and validate variables before making changes + WingVariables Vars; + if (!Vars.InputVariables.ParseString(InputVariables)) return; + if (!Vars.OutputVariables.ParseString(OutputVariables)) return; // Create the Graph UEdGraph* NewGraph = FBlueprintEditorUtils::CreateNewGraph(BP, InternalID, @@ -104,18 +102,11 @@ public: FBlueprintEditorUtils::AddMacroGraph(BP, NewGraph, /*bIsUserCreated=*/true, /*SignatureFromClass=*/nullptr); } - // Try GetEntryAndResultNodes first (works for both functions and macros) - TWeakObjectPtr Entry; - TWeakObjectPtr Exit; - FBlueprintEditorUtils::GetEntryAndResultNodes(NewGraph, Entry, Exit); - if ((Entry == nullptr) || (Exit == nullptr)) - { - UWingServer::Printf(TEXT("Could not get graph entry and exit nodes.\n")); - return; - } - if (!WingFunctionArgs::SetArgs(Entry.Get(), Arguments)) return; - if (!WingFunctionArgs::SetArgs(Exit.Get(), ReturnValues)) return; - + // Create the variables on the new graph + if (!Vars.SetBackingStore(NewGraph)) return; + if (!Vars.Check()) return; + if (!Vars.Create()) return; + UWingServer::Printf(TEXT("Created %s graph: %s\n"), *GraphType, *WingUtils::FormatName(NewGraph)); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Create.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Create.h deleted file mode 100644 index 44d6f7b2..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Create.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "WingTypes.h" -#include "WingVariables.h" -#include "Engine/Blueprint.h" -#include "Kismet2/BlueprintEditorUtils.h" -#include "Kismet2/KismetEditorUtilities.h" -#include "BlueprintVariable_Create.generated.h" - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_BlueprintVariable_Create : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Blueprint path")) - FString Blueprint; - - UPROPERTY(meta=(Description="Variable declarations")) - FString Variables; - - virtual FString GetDescription() const override - { - return TEXT("Add new member variables to a Blueprint. " - "Format: 'type name (flags) = default', one per line."); - } - - virtual void Handle() override - { - WingFetcher F; - UBlueprint* BP = F.Walk(Blueprint).Cast(); - if (!BP) return; - - // Parse the variable declarations. - WingVariables Vars(BP); - if (!Vars.BlueprintVariables.ParseString(Variables)) return; - if (!Vars.Check()) return; - if (!Vars.Create()) return; - UWingServer::Printf(TEXT("Success.\n")); - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Delete.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Delete.h deleted file mode 100644 index d8a84d9e..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Delete.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "WingBlueprintVar.h" -#include "Engine/Blueprint.h" -#include "Kismet2/BlueprintEditorUtils.h" -#include "BlueprintVariable_Delete.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_BlueprintVariable_Delete : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Blueprint name or package path")) - FString Blueprint; - - UPROPERTY(meta=(Description="Name of the variable to delete")) - FString Variable; - - virtual FString GetDescription() const override - { - return TEXT("Remove a member variable from a Blueprint."); - } - - virtual void Handle() override - { - WingFetcher F; - UBlueprint* BP = F.Walk(Blueprint).Cast(); - if (!BP) return; - - FWingBlueprintVar Editor(BP, Variable); - if (Editor.NotFound()) return; - - FBlueprintEditorUtils::RemoveMemberVariable(BP, Editor.Desc->VarName); - - UWingServer::Printf(TEXT("Removed variable %s from %s\n"), - *Variable, *WingUtils::FormatName(BP)); - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Dump.h deleted file mode 100644 index 3fe59cd0..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Dump.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingVariables.h" -#include "BlueprintVariable_Dump.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_BlueprintVariable_Dump : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Blueprint name or package path")) - FString Blueprint; - - virtual FString GetDescription() const override - { - return TEXT("List all member variables of a Blueprint."); - } - - virtual void Handle() override - { - WingFetcher F; - UBlueprint* BP = F.Walk(Blueprint).Cast(); - if (!BP) return; - - WingVariables Vars(BP); - Vars.Load(); - Vars.Print(UWingServer::GetPrintBuffer()); - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Modify.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Modify.h deleted file mode 100644 index 873568f4..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Modify.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "WingVariables.h" -#include "Engine/Blueprint.h" -#include "Kismet2/KismetEditorUtilities.h" -#include "BlueprintVariable_Modify.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_BlueprintVariable_Modify : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Blueprint name or package path")) - FString Blueprint; - - UPROPERTY(meta=(Description="Variable declarations, one per line. Format: type name (flags) = default")) - FString Variables; - - virtual FString GetDescription() const override - { - return TEXT("Modify existing Blueprint variables. Format: 'type name (flags) = default', one per line."); - } - - virtual void Handle() override - { - WingFetcher F; - UBlueprint* BP = F.Walk(Blueprint).Cast(); - if (!BP) return; - - // Parse the variable declarations. - WingVariables Vars(BP); - if (!Vars.BlueprintVariables.ParseString(Variables)) return; - if (!Vars.Check()) return; - if (!Vars.Modify()) return; - UWingServer::Printf(TEXT("Success.\n")); - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Remove.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Remove.h deleted file mode 100644 index f3778b30..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Remove.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingVariables.h" -#include "BlueprintVariable_Remove.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_BlueprintVariable_Remove : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Blueprint path")) - FString Blueprint; - - UPROPERTY(meta=(Description="Variable names to remove, comma-separated")) - FString Variables; - - virtual FString GetDescription() const override - { - return TEXT("Remove member variables from a Blueprint."); - } - - virtual void Handle() override - { - WingFetcher F; - UBlueprint* BP = F.Walk(Blueprint).Cast(); - if (!BP) return; - - WingVariables Vars(BP); - if (!Vars.BlueprintVariables.ParseNamesString(Variables)) return; - if (!Vars.Remove()) 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 52781c0d..6c4a701f 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h @@ -10,7 +10,6 @@ #include "Animation/AnimBlueprint.h" #include "Animation/Skeleton.h" #include "WingActorComponent.h" -#include "WingFunctionArgs.h" #include "Kismet2/BlueprintEditorUtils.h" #include "AnimationGraph.h" #include "AnimationGraphSchema.h" @@ -66,25 +65,8 @@ public: } // Variables - if (!BP->NewVariables.IsEmpty()) - { - UWingServer::Print(TEXT("\nVariables:\n")); - for (const FBPVariableDescription& V : BP->NewVariables) - { - if (V.VarType.PinCategory == UEdGraphSchema_K2::PC_MCDelegate) continue; - UWingServer::Printf(TEXT(" %s %s"), - *UWingTypes::TypeToText(V.VarType), - *WingUtils::FormatName(V)); - if (!V.DefaultValue.IsEmpty()) - UWingServer::Printf(TEXT(" = %s"), *V.DefaultValue); - if (!V.Category.IsEmpty() && V.Category.ToString() != TEXT("Default")) - UWingServer::Printf(TEXT(" [%s]"), *V.Category.ToString()); - UWingServer::Print(TEXT("\n")); - } - } - - // Variables (new format) - WingVariables BlueprintVars(BP); + WingVariables BlueprintVars; + BlueprintVars.SetBackingStore(BP); BlueprintVars.Load(); BlueprintVars.Print(UWingServer::GetPrintBuffer()); @@ -192,38 +174,32 @@ public: private: void PrintEventDispatcher(UEdGraph* Graph) { - TWeakObjectPtr EntryNode; - TWeakObjectPtr ResultNode; - FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, EntryNode, ResultNode); + WingVariables Vars; + Vars.SetBackingStore(Graph); + Vars.Load(); - FString Args; - if (EntryNode.IsValid() && WingFunctionArgs::HasArgs(EntryNode.Get())) - Args = WingFunctionArgs::GetArgs(EntryNode.Get()); - - UWingServer::Printf(TEXT(" %s(%s)\n"), *WingUtils::FormatName(Graph), *Args); + FStringBuilderBase &Out = UWingServer::GetPrintBuffer(); + Out.Appendf(TEXT(" %s("), *WingUtils::FormatName(Graph)); + Vars.InputVariables.PrintCompact(Out); + Out.Append(TEXT(")\n")); } void PrintGraph(UEdGraph* Graph, const TCHAR* Type, UClass* Interface = nullptr) { - TWeakObjectPtr EntryNode; - TWeakObjectPtr ResultNode; - FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, EntryNode, ResultNode); + WingVariables Vars; + Vars.SetBackingStore(Graph); + Vars.Load(); - FString InputArgs; - FString OutputArgs; - if (EntryNode.IsValid() && WingFunctionArgs::HasArgs(EntryNode.Get())) - InputArgs = WingFunctionArgs::GetArgs(EntryNode.Get()); - if (ResultNode.IsValid() && WingFunctionArgs::HasArgs(ResultNode.Get())) - OutputArgs = WingFunctionArgs::GetArgs(ResultNode.Get()); - - UWingServer::Printf(TEXT(" %s %s"), Type, *WingUtils::FormatName(Graph)); - if (!InputArgs.IsEmpty()) - UWingServer::Printf(TEXT("(%s)"), *InputArgs); - if (!OutputArgs.IsEmpty()) - UWingServer::Printf(TEXT(" -> (%s)"), *OutputArgs); + FStringBuilderBase &Out = UWingServer::GetPrintBuffer(); + Out.Appendf(TEXT(" %s %s"), Type, *WingUtils::FormatName(Graph)); + Out.AppendChar('('); + Vars.InputVariables.PrintCompact(Out); + Out.Append(TEXT(") -> (")); + Vars.OutputVariables.PrintCompact(Out); + Out.AppendChar(')'); if (Interface) - UWingServer::Printf(TEXT(" [%s]"), *WingUtils::FormatName(Interface)); - UWingServer::Print(TEXT("\n")); + Out.Appendf(TEXT(" [%s]"), *WingUtils::FormatName(Interface)); + Out.AppendChar('\n'); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Create.h b/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Create.h index 367e42b9..192515a8 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Create.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Create.h @@ -4,7 +4,6 @@ #include "WingServer.h" #include "WingHandler.h" #include "WingFetcher.h" -#include "WingFunctionArgs.h" #include "WingUtils.h" #include "Engine/Blueprint.h" #include "EdGraphSchema_K2.h" @@ -28,8 +27,8 @@ public: UPROPERTY(meta=(Description="Name of the new event dispatcher")) FString Dispatcher; - UPROPERTY(meta=(Description="Arguments expressed as: int x,float y")) - FString Arguments; + UPROPERTY(meta=(Description="Input Variables, one per line, expressed as: type var = value")) + FString InputVariables; virtual FString GetDescription() const override { @@ -45,11 +44,13 @@ public: // Check for valid proposed name FName InternalID = WingUtils::CheckProposedName(Dispatcher); if (InternalID.IsNone()) return; - if (!WingUtils::FindNoneWithInternalID(InternalID, BP->NewVariables, TEXT("Variable"))) return; - if (!WingUtils::FindNoneWithInternalID(InternalID, WingUtils::AllGraphs(BP), TEXT("Graph"))) return; + TSet Names; + FBlueprintEditorUtils::GetClassVariableList(BP, Names); + if (!WingUtils::FindNoDuplicateName(Names, InternalID, TEXT("variable or component"))) return; - // Make sure the argument types are valid. - if (!WingFunctionArgs::CheckArgs(Arguments)) return; + // Parse the arguments. + WingVariables Vars; + if (!Vars.InputVariables.ParseString(InputVariables)) return; // Add the delegate variable FEdGraphPinType DelegateType; @@ -78,16 +79,9 @@ public: BP->DelegateSignatureGraphs.Add(SigGraph); // Store the function arguments - TWeakObjectPtr EntryNode; - TWeakObjectPtr ResultNode; - FBlueprintEditorUtils::GetEntryAndResultNodes(SigGraph, EntryNode, ResultNode); - if (!EntryNode.IsValid()) - { - UWingServer::Print(TEXT("ERROR: Entry node not found in delegate signature graph\n")); - return; - } - if (!WingFunctionArgs::SetArgs(EntryNode.Get(), Arguments)) return; - + if (!Vars.SetBackingStore(SigGraph)) return; + if (!Vars.Check()) return; + if (!Vars.Create()) return; UWingServer::Printf(TEXT("Created event dispatcher %s in %s\n"), *Dispatcher, *WingUtils::FormatName(BP)); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Dump.h deleted file mode 100644 index 45e1c8ee..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Dump.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "WingBlueprintVar.h" -#include "Engine/Blueprint.h" -#include "WingFunctionArgs.h" -#include "Kismet2/BlueprintEditorUtils.h" -#include "EventDispatcher_Dump.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_EventDispatcher_Dump : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Blueprint name or package path")) - FString Blueprint; - - UPROPERTY(meta=(Description="Name of the event dispatcher to inspect")) - FString Dispatcher; - - virtual FString GetDescription() const override - { - return TEXT("Show all editable properties of a Blueprint event dispatcher."); - } - - virtual void Handle() override - { - WingFetcher F; - UBlueprint* BP = F.Walk(Blueprint).Cast(); - if (!BP) return; - - FBPVariableDescription* Var = WingUtils::FindOneWithExternalID(Dispatcher, BP->NewVariables, TEXT("Dispatcher")); - if (!Var) return; - TObjectPtr* SigGraph = WingUtils::FindOneWithExternalID(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph")); - if (!SigGraph) return; - - TWeakObjectPtr EntryNode; - TWeakObjectPtr ResultNode; - FBlueprintEditorUtils::GetEntryAndResultNodes(*SigGraph, EntryNode, ResultNode); - if (!EntryNode.IsValid()) - { - UWingServer::Print(TEXT("ERROR: Entry node not found in delegate signature graph\n")); - return; - } - FString Args = WingFunctionArgs::GetArgs(EntryNode.Get()); - - UWingServer::Printf(TEXT("Event dispatcher %s in %s:\n"), *Dispatcher, *WingUtils::FormatName(BP)); - UWingServer::Printf(TEXT(" Arguments: %s\n"), *Args); - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Modify.h b/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Modify.h deleted file mode 100644 index 7e692fdc..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Modify.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "WingFunctionArgs.h" -#include "Engine/Blueprint.h" -#include "Kismet2/BlueprintEditorUtils.h" -#include "EventDispatcher_Modify.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_EventDispatcher_Modify : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Blueprint name or package path")) - FString Blueprint; - - UPROPERTY(meta=(Description="Name of the event dispatcher to modify")) - FString Dispatcher; - - UPROPERTY(meta=(Description="New arguments expressed as: int x,float y")) - FString Arguments; - - virtual FString GetDescription() const override - { - return TEXT("Modify the arguments of an existing Blueprint event dispatcher."); - } - - virtual void Handle() override - { - WingFetcher F; - UBlueprint* BP = F.Walk(Blueprint).Cast(); - if (!BP) return; - - FBPVariableDescription* Var = WingUtils::FindOneWithExternalID(Dispatcher, BP->NewVariables, TEXT("Dispatcher")); - if (!Var) return; - TObjectPtr* SigGraph = WingUtils::FindOneWithExternalID(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph")); - if (!SigGraph) return; - - // Make sure the argument types are valid. - if (!WingFunctionArgs::CheckArgs(Arguments)) return; - - TWeakObjectPtr EntryNode; - TWeakObjectPtr ResultNode; - FBlueprintEditorUtils::GetEntryAndResultNodes(*SigGraph, EntryNode, ResultNode); - if (!EntryNode.IsValid()) - { - UWingServer::Print(TEXT("ERROR: Entry node not found in delegate signature graph\n")); - return; - } - if (!WingFunctionArgs::SetArgs(EntryNode.Get(), Arguments)) return; - - UWingServer::Printf(TEXT("Modified event dispatcher %s in %s\n"), *Dispatcher, *WingUtils::FormatName(BP)); - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetArgs.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetArgs.h deleted file mode 100644 index 9ae26bf9..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetArgs.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingHandler.h" -#include "WingServer.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "WingFunctionArgs.h" -#include "GraphNode_SetArgs.generated.h" - -UCLASS() -class UWing_GraphNode_SetArgs : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Path to a graph node (FunctionEntry, FunctionResult, CustomEvent, or Tunnel)")) - FString Node; - - UPROPERTY(meta=(Description="Parameter list, such as 'int x,float y'")) - FString Args; - - UPROPERTY(meta=(Optional, Description="Also rename the node (which renames a Function or Custom Event)")) - FString Rename; - - virtual FString GetDescription() const override - { - return TEXT("Set the parameter list of a FunctionEntry, FunctionResult, CustomEvent, or Tunnel node."); - } - - virtual void Handle() override - { - WingFetcher F; - UEdGraphNode* NodeObj = F.Walk(Node).Cast(); - if (!NodeObj) return; - - if (!WingFunctionArgs::HasArgs(NodeObj)) - { - UWingServer::Printf(TEXT("ERROR: Node does not support editable args\n")); - UWingServer::SuggestManual(WingManual::Section::HandlerHelp); - return; - } - - if (!Rename.IsEmpty()) - { - if (!WingUtils::CheckCanRename(NodeObj, Rename)) return; - NodeObj->OnRenameNode(Rename); - } - - if (!WingFunctionArgs::SetArgs(NodeObj, Args)) return; - - UWingServer::Printf(TEXT("Args set to: %s\n"), *WingFunctionArgs::GetArgs(NodeObj)); - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Create.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Create.h similarity index 52% rename from Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Create.h rename to Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Create.h index 54d0a445..091d6868 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Create.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Create.h @@ -5,11 +5,7 @@ #include "WingServer.h" #include "WingFetcher.h" #include "WingVariables.h" -#include "Kismet2/BlueprintEditorUtils.h" -#include "Kismet2/KismetEditorUtilities.h" -#include "K2Node_EditablePinBase.h" -#include "K2Node_FunctionEntry.h" -#include "GraphVariables_Create.generated.h" +#include "Variables_Create.generated.h" // --------------------------------------------------------------------------- @@ -17,36 +13,40 @@ // --------------------------------------------------------------------------- UCLASS() -class UWing_GraphVariables_Create : public UObject, public IWingHandler +class UWing_Variables_Create : public UObject, public IWingHandler { GENERATED_BODY() public: - UPROPERTY(meta=(Description="Path to a function or macro graph (e.g. '/Game/MyBP,graph:MyFunction')")) - FString Graph; + UPROPERTY(meta=(Description="Path to a blueprint, graph, or custom event node")) + FString Object; - UPROPERTY(meta=(Optional, Description="Inputs to the graph")) + UPROPERTY(meta=(Optional, Description="Blueprint variables, one per line")) + FString BlueprintVariables; + + UPROPERTY(meta=(Optional, Description="Input variables, one per line")) FString InputVariables; - UPROPERTY(meta=(Optional, Description="Outputs to the graph")) + UPROPERTY(meta=(Optional, Description="Output variables, one per line")) FString OutputVariables; - UPROPERTY(meta=(Optional, Description="Locals to the graph")) + UPROPERTY(meta=(Optional, Description="Local variables, one per line")) FString LocalVariables; virtual FString GetDescription() const override { - return TEXT("Add new inputs, outputs, and local variables to a graph. " - "Format: 'type name (flags) = default', one per line"); + return TEXT("Add new variables. Format: 'type name (flags) = default', one per line."); } virtual void Handle() override { WingFetcher F; - UEdGraph* G = F.Walk(Graph).Cast(); - if (!G) return; + UObject* Obj = F.Walk(Object).Cast(); + if (!Obj) return; - WingVariables Vars(G); + WingVariables Vars; + if (!Vars.SetBackingStore(Obj)) return; + if (!Vars.BlueprintVariables.ParseString(BlueprintVariables)) return; if (!Vars.InputVariables.ParseString(InputVariables)) return; if (!Vars.OutputVariables.ParseString(OutputVariables)) return; if (!Vars.LocalVariables.ParseString(LocalVariables)) return; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Dump.h similarity index 55% rename from Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Dump.h rename to Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Dump.h index c3756b08..796199fd 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Dump.h @@ -5,8 +5,7 @@ #include "WingServer.h" #include "WingFetcher.h" #include "WingVariables.h" -#include "Kismet2/KismetEditorUtilities.h" -#include "GraphVariables_Dump.generated.h" +#include "Variables_Dump.generated.h" // --------------------------------------------------------------------------- @@ -14,26 +13,28 @@ // --------------------------------------------------------------------------- UCLASS() -class UWing_GraphVariables_Dump : public UObject, public IWingHandler +class UWing_Variables_Dump : public UObject, public IWingHandler { GENERATED_BODY() public: - UPROPERTY(meta=(Description="Path to a function graph (e.g. '/Game/MyBP,graph:MyFunction')")) - FString Graph; + UPROPERTY(meta=(Description="Path to a blueprint, graph, or custom event node")) + FString Object; virtual FString GetDescription() const override { - return TEXT("List all arguments, return values, and local variables of a function graph."); + return TEXT("List all variables of a blueprint, function graph," + "macro graph, event dispatcher graph, or custom event node"); } virtual void Handle() override { WingFetcher F; - UEdGraph* G = F.Walk(Graph).Cast(); - if (!G) return; + UObject* Obj = F.Walk(Object).Cast(); + if (!Obj) return; - WingVariables Vars(G); + WingVariables Vars; + if (!Vars.SetBackingStore(Obj)) return; Vars.Load(); Vars.Print(UWingServer::GetPrintBuffer()); } diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Modify.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Modify.h similarity index 51% rename from Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Modify.h rename to Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Modify.h index 6887f518..adc89fe7 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Modify.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Modify.h @@ -5,7 +5,7 @@ #include "WingServer.h" #include "WingFetcher.h" #include "WingVariables.h" -#include "GraphVariables_Modify.generated.h" +#include "Variables_Modify.generated.h" // --------------------------------------------------------------------------- @@ -13,35 +13,41 @@ // --------------------------------------------------------------------------- UCLASS() -class UWing_GraphVariables_Modify : public UObject, public IWingHandler +class UWing_Variables_Modify : public UObject, public IWingHandler { GENERATED_BODY() public: - UPROPERTY(meta=(Description="Path to a graph")) - FString Graph; + UPROPERTY(meta=(Description="Path to a blueprint, graph, or custom event node")) + FString Object; - UPROPERTY(meta=(Optional, Description="Inputs to the graph")) + UPROPERTY(meta=(Optional, Description="Blueprint variables, one per line")) + FString BlueprintVariables; + + UPROPERTY(meta=(Optional, Description="Input variables, one per line")) FString InputVariables; - UPROPERTY(meta=(Optional, Description="Outputs to the graph")) + UPROPERTY(meta=(Optional, Description="Output variables, one per line")) FString OutputVariables; - UPROPERTY(meta=(Optional, Description="Locals to the graph")) + UPROPERTY(meta=(Optional, Description="Local variables, one per line")) FString LocalVariables; virtual FString GetDescription() const override { - return TEXT("Modify existing arguments, return values, and local variables of a graph."); + return TEXT("Modify variables of a blueprint, function graph, " + "macro graph, event dispatcher graph, or custom event node. "); } virtual void Handle() override { WingFetcher F; - UEdGraph* G = F.Walk(Graph).Cast(); - if (!G) return; + UObject* Obj = F.Walk(Object).Cast(); + if (!Obj) return; - WingVariables Vars(G); + WingVariables Vars; + if (!Vars.SetBackingStore(Obj)) return; + if (!Vars.BlueprintVariables.ParseString(BlueprintVariables)) return; if (!Vars.InputVariables.ParseString(InputVariables)) return; if (!Vars.OutputVariables.ParseString(OutputVariables)) return; if (!Vars.LocalVariables.ParseString(LocalVariables)) return; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Remove.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Remove.h similarity index 65% rename from Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Remove.h rename to Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Remove.h index 10b01154..b36cfb5c 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphVariables_Remove.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Remove.h @@ -5,7 +5,7 @@ #include "WingHandler.h" #include "WingFetcher.h" #include "WingVariables.h" -#include "GraphVariables_Remove.generated.h" +#include "Variables_Remove.generated.h" // --------------------------------------------------------------------------- @@ -13,13 +13,16 @@ // --------------------------------------------------------------------------- UCLASS() -class UWing_GraphVariables_Remove : public UObject, public IWingHandler +class UWing_Variables_Remove : public UObject, public IWingHandler { GENERATED_BODY() public: - UPROPERTY(meta=(Description="Path to a function or macro graph")) - FString Graph; + UPROPERTY(meta=(Description="Path to a blueprint, graph, or custom event node")) + FString Object; + + UPROPERTY(meta=(Optional, Description="Blueprint variable names to remove, comma-separated")) + FString BlueprintVariables; UPROPERTY(meta=(Optional, Description="Input variable names to remove, comma-separated")) FString InputVariables; @@ -32,16 +35,18 @@ public: virtual FString GetDescription() const override { - return TEXT("Remove inputs, outputs, and local variables from a graph."); + return TEXT("Remove variables from a blueprint, graph, or custom event node."); } virtual void Handle() override { WingFetcher F; - UEdGraph* G = F.Walk(Graph).Cast(); - if (!G) return; + UObject* Obj = F.Walk(Object).Cast(); + if (!Obj) return; - WingVariables Vars(G); + WingVariables Vars; + if (!Vars.SetBackingStore(Obj)) return; + if (!Vars.BlueprintVariables.ParseNamesString(BlueprintVariables)) return; if (!Vars.InputVariables.ParseNamesString(InputVariables)) return; if (!Vars.OutputVariables.ParseNamesString(OutputVariables)) return; if (!Vars.LocalVariables.ParseNamesString(LocalVariables)) return; diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingBlueprintVar.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingBlueprintVar.cpp deleted file mode 100644 index a4889acb..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingBlueprintVar.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "WingBlueprintVar.h" -#include "WingServer.h" -#include "WingTypes.h" -#include "WingUtils.h" -#include "EdGraphSchema_K2.h" -#include "Kismet2/BlueprintEditorUtils.h" - -FWingBlueprintVar::FWingBlueprintVar(UBlueprint* BP, const FString& VarName) -{ - Desc = WingUtils::FindOneWithExternalID(VarName, BP->NewVariables, TEXT("Variable")); - if (!Desc) return; - if (Desc->VarType.PinCategory == UEdGraphSchema_K2::PC_MCDelegate) - { - UWingServer::Printf(TEXT("Cannot edit event dispatchers using BlueprintVariable functions.\n")); - Desc = nullptr; - return; - } - - // Try to find the default value property on the CDO. - if (BP->GeneratedClass) - { - UObject* CDO = BP->GeneratedClass->GetDefaultObject(); - FProperty* Prop = BP->GeneratedClass->FindPropertyByName(Desc->VarName); - if (CDO && Prop) - DefaultValueProp = FWingProperty(Prop, CDO); - } -} - -void FWingBlueprintVar::Dump() -{ - LoadFlags(); - LoadDefault(); - TArray Props = MergedProperties(); - for (FWingProperty& P : Props) - { - UWingServer::Printf(TEXT(" %s %s = %s\n"), - *UWingTypes::TypeToText(P.Prop), - *WingUtils::FormatName(P.Prop), - *P.GetText()); - } -} - -bool FWingBlueprintVar::ApplyJson(const FJsonObject* Json) -{ - bool bHasDefault = Json->HasField(TEXT("DefaultValue")); - bool bHasType = Json->HasField(TEXT("VarType")); - if (bHasDefault && bHasType) - { - UWingServer::Print(TEXT( - "ERROR: Cannot set VarType and DefaultValue in the same call.\n" - "Change the type first, then recompile the blueprint,\n" - "then set the default.\n")); - return false; - } - - LoadFlags(); - - TArray Props = MergedProperties(); - if (!FWingProperty::PopulateFromJson(Props, Json, true)) - return false; - - SaveFlags(); - if (bHasDefault) - return SaveDefault(); - return true; -} - -void FWingBlueprintVar::LoadFlags() -{ - InstanceEditable = !(Desc->PropertyFlags & CPF_DisableEditOnInstance); - BlueprintReadOnly = (Desc->PropertyFlags & CPF_BlueprintReadOnly) != 0; - ExposeToCinematics = (Desc->PropertyFlags & CPF_Interp) != 0; - ExposeOnSpawn = Desc->HasMetaData(FBlueprintMetadata::MD_ExposeOnSpawn); - Private = Desc->HasMetaData(FBlueprintMetadata::MD_Private); - - if (Desc->HasMetaData(TEXT("tooltip"))) - Description = Desc->GetMetaData(TEXT("tooltip")); - else - Description.Empty(); -} - -void FWingBlueprintVar::LoadDefault() -{ - if (DefaultValueProp) - DefaultValue = DefaultValueProp.GetText(); - else - DefaultValue.Empty(); -} - -void FWingBlueprintVar::SaveFlags() -{ - // CPF flags - if (InstanceEditable) - Desc->PropertyFlags &= ~CPF_DisableEditOnInstance; - else - Desc->PropertyFlags |= CPF_DisableEditOnInstance; - - if (BlueprintReadOnly) - Desc->PropertyFlags |= CPF_BlueprintReadOnly; - else - Desc->PropertyFlags &= ~CPF_BlueprintReadOnly; - - if (ExposeToCinematics) - Desc->PropertyFlags |= CPF_Interp; - else - Desc->PropertyFlags &= ~CPF_Interp; - - // Metadata flags - if (ExposeOnSpawn) - Desc->SetMetaData(FBlueprintMetadata::MD_ExposeOnSpawn, TEXT("true")); - else - Desc->RemoveMetaData(FBlueprintMetadata::MD_ExposeOnSpawn); - - if (Private) - Desc->SetMetaData(FBlueprintMetadata::MD_Private, TEXT("true")); - else - Desc->RemoveMetaData(FBlueprintMetadata::MD_Private); - - // Description/tooltip - if (!Description.IsEmpty()) - Desc->SetMetaData(TEXT("tooltip"), Description); - else - Desc->RemoveMetaData(TEXT("tooltip")); -} - -bool FWingBlueprintVar::SaveDefault() -{ - if (DefaultValueProp) - return DefaultValueProp.SetText(DefaultValue); - return true; -} - -TArray FWingBlueprintVar::MergedProperties() -{ - TArray Props = FWingProperty::GetAll( - FBPVariableDescription::StaticStruct(), Desc, CPF_Edit); - - FWingProperty::Remove(Props, TEXT("PropertyFlags")); - FWingProperty::Remove(Props, TEXT("MetaDataArray")); - FWingProperty::Remove(Props, TEXT("VarName")); - FWingProperty::Remove(Props, TEXT("VarGuid")); - FWingProperty::Remove(Props, TEXT("DefaultValue")); - - Props.Append(FWingProperty::GetAll( - FWingBlueprintVar::StaticStruct(), this, (EPropertyFlags)0)); - - // Remove DefaultValue if we don't have a CDO property to back it. - if (!DefaultValueProp) - FWingProperty::Remove(Props, TEXT("DefaultValue")); - - return Props; -} diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingFunctionArgs.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingFunctionArgs.cpp deleted file mode 100644 index 5044a949..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingFunctionArgs.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "WingFunctionArgs.h" -#include "K2Node_EditablePinBase.h" -#include "K2Node_FunctionResult.h" -#include "K2Node_Tunnel.h" -#include "WingTypes.h" -#include "WingUtils.h" -#include "WingServer.h" -#include "Kismet2/BlueprintEditorUtils.h" - -bool WingFunctionArgs::HasArgs(UEdGraphNode* Node) -{ - UK2Node_EditablePinBase* Editable = Cast(Node); - if (!Editable) return false; - return Editable->IsEditable(); -} - -FString WingFunctionArgs::GetArgs(UEdGraphNode* Node) -{ - UK2Node_EditablePinBase* Editable = Cast(Node); - if (!Editable) return FString(); - - TStringBuilder<256> SB; - for (const TSharedPtr& Pin : Editable->UserDefinedPins) - { - if (SB.Len() > 0) SB << TEXT(","); - SB << UWingTypes::TypeToText(Pin->PinType) << TEXT(" ") << WingUtils::FormatName(*Pin); - } - return FString(SB); -} - -EEdGraphPinDirection WingFunctionArgs::GetPinDirection(UK2Node_EditablePinBase* Node) -{ - // FunctionResult takes inputs; Tunnel depends on its flags; everything else outputs. - if (Node->IsA()) - return EGPD_Input; - if (UK2Node_Tunnel* Tunnel = Cast(Node)) - return Tunnel->bCanHaveInputs ? EGPD_Input : EGPD_Output; - return EGPD_Output; -} - -bool WingFunctionArgs::ParseArgs(const FString& Args, TArray& OutArgs) -{ - FString Trimmed = Args.TrimStartAndEnd(); - if (Trimmed.IsEmpty()) return true; - - TArray Parts; - Trimmed.ParseIntoArray(Parts, TEXT(",")); - - for (const FString& Part : Parts) - { - FString Token = Part.TrimStartAndEnd(); - if (Token.IsEmpty()) continue; - - // Split "type name" - FString TypeStr, NameStr; - if (!Token.Split(TEXT(" "), &TypeStr, &NameStr)) - { - UWingServer::Printf(TEXT("ERROR: Malformed parameter list near '%s'\n"), *Token); - return false; - } - - TypeStr.TrimStartAndEndInline(); - NameStr.TrimStartAndEndInline(); - - if (TypeStr.IsEmpty() || NameStr.IsEmpty()) - { - UWingServer::Printf(TEXT("ERROR: Malformed parameter list near '%s'\n"), *Token); - return false; - } - - FParsedArg Arg; - UWingTypes::Requirements Req; - Req.BlueprintType = true; - Req.Blueprintable = false; - Req.AllowContainer = true; - if (!UWingTypes::TextToType(TypeStr, Arg.PinType, Req)) return false; - Arg.PinName = FName(*NameStr); - OutArgs.Add(MoveTemp(Arg)); - } - return true; -} - -bool WingFunctionArgs::SetArgs(UEdGraphNode* Node, const FString& Args) -{ - UK2Node_EditablePinBase* Editable = Cast(Node); - if (!Editable || !Editable->IsEditable()) - { - UWingServer::Printf(TEXT("ERROR: Node does not contain an editable parameter list\n")); - return false; - } - - // Parse the args string. - TArray NewArgs; - if (!ParseArgs(Args, NewArgs)) - { - UWingServer::SuggestManual(WingManual::Section::ParameterLists); - UWingServer::SuggestManual(WingManual::Section::Types); - return false; - } - - EEdGraphPinDirection Direction = GetPinDirection(Editable); - - // Replace the UserDefinedPins array directly. - Editable->UserDefinedPins.Empty(); - for (const FParsedArg& Arg : NewArgs) - { - TSharedPtr PinInfo = MakeShareable(new FUserPinInfo()); - PinInfo->PinName = Arg.PinName; - PinInfo->PinType = Arg.PinType; - PinInfo->DesiredPinDirection = Direction; - Editable->UserDefinedPins.Add(PinInfo); - } - - // ReconstructNode rebuilds real pins from UserDefinedPins - // and rewires old connections by matching pin names. - Editable->ReconstructNode(); - return true; -} - -bool WingFunctionArgs::CheckArgs(const FString &Args) -{ - TArray NewArgs; - if (!ParseArgs(Args, NewArgs)) - { - UWingServer::Printf(TEXT("ERROR: Invalid parameter list: %s\n"), *Args); - UWingServer::SuggestManual(WingManual::Section::ParameterLists); - UWingServer::SuggestManual(WingManual::Section::Types); - return false; - } - return true; -} - diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp index 6b4cde7f..8a9fa4b5 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp @@ -10,7 +10,6 @@ #include "EdGraphNode_Comment.h" #include "K2Node_CallFunction.h" #include "K2Node_FunctionEntry.h" -#include "WingFunctionArgs.h" #include "WingVariables.h" #include "MaterialGraph/MaterialGraphNode.h" #include "Kismet2/BlueprintEditorUtils.h" @@ -205,10 +204,6 @@ void WingGraphExport::EmitNode(UEdGraphNode* Node) Output.Appendf(TEXT("\nnode %s: %s\n"), *WingUtils::FormatName(Node), *WingUtils::FormatNodeTitle(Node)); - // Emit function args (if applicable). - if (WingFunctionArgs::HasArgs(Node)) - Output.Appendf(TEXT(" args %s\n"), *WingFunctionArgs::GetArgs(Node)); - // Emit material expression properties (if applicable). EmitMaterialProperties(Node, Output, true); @@ -289,7 +284,8 @@ void WingGraphExport::EmitMaterialProperties(UEdGraphNode* Node, FStringBuilderB void WingGraphExport::EmitLocalVariables() { - WingVariables Vars(Graph); + WingVariables Vars; + Vars.SetBackingStore(Graph); Vars.Load(); Vars.Print(Output); } diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp index 7e25ca75..6ca2fe94 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp @@ -7,6 +7,7 @@ #include "EdGraphSchema_K2.h" #include "K2Node_FunctionEntry.h" #include "K2Node_FunctionResult.h" +#include "K2Node_CustomEvent.h" #include "K2Node_Tunnel.h" #include "K2Node_EditablePinBase.h" #include "Kismet2/BlueprintEditorUtils.h" @@ -58,7 +59,18 @@ void WingVariableList::Print(FStringBuilderBase &Out) Out.Append(TEXT("\n")); } } - + +void WingVariableList::PrintCompact(FStringBuilderBase &Out) +{ + bool First = true; + for (const Var& V : Variables) + { + if (!First) Out << TEXT(","); + First = false; + Out << UWingTypes::TypeToText(V.Type) << TEXT(" ") << WingUtils::ExternalizeID(V.Name); + } +} + void WingVariableList::ClearLinks() { for (Var &V : Variables) @@ -241,6 +253,8 @@ void WingVariables::Load() Empty(); if (Blueprint != nullptr) return LoadBlueprint(); if (Graph != nullptr) return LoadGraph(); + if (CustomEvent != nullptr) return LoadCustomEvent(); + ErrorNoBackingStore(); } void WingVariables::LoadBlueprint() @@ -337,12 +351,17 @@ void WingVariables::LoadEditablePinBase(UK2Node_EditablePinBase* Node, WingVaria } } +void WingVariables::LoadCustomEvent() +{ + LoadEditablePinBase(CustomEvent, InputVariables); +} + bool WingVariables::Check() { if (Blueprint) return CheckBlueprint(); if (Graph) return CheckGraph(); - check(false); - return false; + if (CustomEvent) return CheckCustomEvent(); + return ErrorNoBackingStore(); } bool WingVariables::CheckBlueprint() @@ -363,7 +382,7 @@ bool WingVariables::CheckGraph() bool AllowOutput = (T == EGraphType::GT_Function) || (T == EGraphType::GT_Macro); if ((!AllowLocal) && (!AllowInput) && (!AllowOutput)) { - UWingServer::Printf(TEXT("This graph has no editable variables.")); + UWingServer::Printf(TEXT("This graph type has no variables.")); return false; } @@ -375,12 +394,22 @@ bool WingVariables::CheckGraph() return OK; } +bool WingVariables::CheckCustomEvent() +{ + bool OK = true; + if (!BlueprintVariables.CheckSanity(Flags_None, false)) OK = false; + if (!LocalVariables.CheckSanity(Flags_None, false)) OK = false; + if (!InputVariables.CheckSanity(Flags_None, true)) OK = false; + if (!OutputVariables.CheckSanity(Flags_None, false)) OK = false; + return OK; +} + bool WingVariables::Modify() { if (Blueprint) return ModifyBlueprint(); if (Graph) return ModifyGraph(); - check(false); - return false; + if (CustomEvent) return ModifyCustomEvent(); + return ErrorNoBackingStore(); } bool WingVariables::ModifyBlueprint() @@ -488,28 +517,36 @@ bool WingVariables::ModifyGraph() Desc->VarType = V.Type; if (V.DefaultSpecified) Desc->DefaultValue = V.DefaultValue; } - for (Var &V : InputVariables.Variables) - { - TSharedPtr *Found = - WingUtils::FindOneWithInternalID(V.Name, InputNode->UserDefinedPins, TEXT("input variable")); - if (!Found) return false; - (*Found)->PinType = V.Type; - if (V.DefaultSpecified) (*Found)->PinDefaultValue = V.DefaultValue; - } - for (Var &V : OutputVariables.Variables) - { - TSharedPtr *Found = - WingUtils::FindOneWithInternalID(V.Name, OutputNode->UserDefinedPins, TEXT("output variable")); - if (!Found) return false; - (*Found)->PinType = V.Type; - if (V.DefaultSpecified) (*Found)->PinDefaultValue = V.DefaultValue; - } + if (!ModifyEditablePinBase(InputVariables, InputNode)) return false; + if (!ModifyEditablePinBase(OutputVariables, OutputNode)) return false; if (InputNode) InputNode->ReconstructNode(); if (OutputNode) OutputNode->ReconstructNode(); return true; } +bool WingVariables::ModifyCustomEvent() +{ + if (!CheckCustomEvent()) return false; + ClearLinks(); + if (!ModifyEditablePinBase(InputVariables, CustomEvent)) return false; + CustomEvent->ReconstructNode(); + return true; +} + +bool WingVariables::ModifyEditablePinBase(WingVariableList &List, UK2Node_EditablePinBase *Node) +{ + for (Var &V : List.Variables) + { + TSharedPtr *Found = + WingUtils::FindOneWithInternalID(V.Name, Node->UserDefinedPins, List.ListName); + if (!Found) return false; + (*Found)->PinType = V.Type; + if (V.DefaultSpecified) (*Found)->PinDefaultValue = V.DefaultValue; + } + return true; +} + bool WingVariables::GetGraphNodes( UK2Node_EditablePinBase *&InputNode, UK2Node_EditablePinBase *&OutputNode, @@ -554,8 +591,8 @@ bool WingVariables::Create() { if (Blueprint) return CreateBlueprint(); if (Graph) return CreateGraph(); - check(false); - return false; + if (CustomEvent) return CreateCustomEvent(); + return ErrorNoBackingStore(); } bool WingVariables::CreateBlueprint() @@ -635,6 +672,25 @@ bool WingVariables::CreateGraph() return true; } +bool WingVariables::CreateCustomEvent() +{ + if (!CheckCustomEvent()) return false; + ClearLinks(); + + // Check for name collisions against existing pins. + TSet Names; + if (!WingUtils::FindNoDuplicateNames( + Names, CustomEvent->UserDefinedPins, TEXT("event parameter"))) return false; + if (!WingUtils::FindNoDuplicateNames( + Names, InputVariables.Variables, TEXT("event parameter"))) return false; + + for (const Var& V : InputVariables.Variables) + AddUserPinInfo(V, EGPD_Output, CustomEvent); + + CustomEvent->ReconstructNode(); + return true; +} + void WingVariables::AddUserPinInfo(const Var &V, EEdGraphPinDirection Dir, UK2Node_EditablePinBase *Node) { TSharedPtr Result = MakeShareable( new FUserPinInfo() ); @@ -649,8 +705,8 @@ bool WingVariables::Remove() { if (Blueprint) return RemoveBlueprint(); if (Graph) return RemoveGraph(); - check(false); - return false; + if (CustomEvent) return RemoveCustomEvent(); + return ErrorNoBackingStore(); } bool WingVariables::RemoveBlueprint() @@ -715,3 +771,55 @@ bool WingVariables::RemoveGraph() if (OutputNode) OutputNode->ReconstructNode(); return true; } + +bool WingVariables::RemoveCustomEvent() +{ + // Verify that all named parameters exist before removing anything. + for (const Var& V : InputVariables.Variables) + { + TSharedPtr* Found = + WingUtils::FindOneWithInternalID(V.Name, CustomEvent->UserDefinedPins, TEXT("event parameter")); + if (!Found) return false; + } + + for (const Var& V : InputVariables.Variables) + CustomEvent->RemoveUserDefinedPinByName(V.Name); + + CustomEvent->ReconstructNode(); + return true; +} + +bool WingVariables::SetBackingStore(UObject *Obj) +{ + Blueprint = nullptr; + Graph = nullptr; + CustomEvent = nullptr; + if (UBlueprint *BP = Cast(Obj)) + { + Blueprint = BP; + return true; + } + if (UEdGraph *G = Cast(Obj)) + { + Graph = G; + return true; + } + if (UK2Node_CustomEvent *E = Cast(Obj)) + { + CustomEvent = E; + return true; + } + UWingServer::Printf(TEXT( + "ERROR: The variable editor can only edit blueprints, " + "graphs, and custom event nodes. Passed in: %s"), + *WingUtils::FormatName(Obj->GetClass())); + return false; +} + +bool WingVariables::ErrorNoBackingStore() +{ + UWingServer::Printf(TEXT( + "ERROR: The variable editor was not successfully " + "set up with an object to edit.")); + return false; +} diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingBlueprintVar.h b/Plugins/UEWingman/Source/UEWingman/Public/WingBlueprintVar.h deleted file mode 100644 index 244aac12..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingBlueprintVar.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingProperty.h" -#include "Engine/Blueprint.h" -#include "WingBlueprintVar.generated.h" - -// Editor-friendly view of a blueprint variable's properties. -// Wraps an FBPVariableDescription, exposing commonly-used flags -// and metadata as simple UPROPERTYs that the property system can -// populate from JSON. -USTRUCT() -struct FWingBlueprintVar -{ - GENERATED_BODY() - - FBPVariableDescription* Desc = nullptr; - FWingProperty DefaultValueProp; - - FWingBlueprintVar() = default; - FWingBlueprintVar(UBlueprint* BP, const FString& VarName); - - bool NotFound() const { return Desc == nullptr; } - - UPROPERTY(EditAnywhere, meta=(Optional, Description="Default value in Unreal text format")) - FString DefaultValue; - - UPROPERTY(EditAnywhere, meta=(Optional, Description="Variable description/tooltip")) - FString Description; - - UPROPERTY(EditAnywhere, meta=(Optional, Description="Allow editing on instances")) - bool InstanceEditable = false; - - UPROPERTY(EditAnywhere, meta=(Optional, Description="Read-only in blueprints")) - bool BlueprintReadOnly = false; - - UPROPERTY(EditAnywhere, meta=(Optional, Description="Expose as a pin when spawning")) - bool ExposeOnSpawn = false; - - UPROPERTY(EditAnywhere, meta=(Optional, Description="Private to this blueprint")) - bool Private = false; - - UPROPERTY(EditAnywhere, meta=(Optional, Description="Expose to cinematics/sequencer")) - bool ExposeToCinematics = false; - - // Load from Desc, populate from JSON, save back to Desc. - bool ApplyJson(const FJsonObject* Json); - - // Print all properties and their current values. - void Dump(); - -private: - void LoadFlags(); - void LoadDefault(); - void SaveFlags(); - bool SaveDefault(); - TArray MergedProperties(); -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingFunctionArgs.h b/Plugins/UEWingman/Source/UEWingman/Public/WingFunctionArgs.h deleted file mode 100644 index c1966560..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingFunctionArgs.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "EdGraph/EdGraphPin.h" - -class UEdGraphNode; -class UK2Node_EditablePinBase; - -struct WingFunctionArgs -{ - // Returns true if the node is an EditablePinBase subclass that - // actually supports user-defined pins (FunctionEntry, FunctionResult, - // CustomEvent, or Tunnel). - static bool HasArgs(UEdGraphNode* Node); - - // Returns the user-defined pins as a string like "int x,float y". - static FString GetArgs(UEdGraphNode* Node); - - // Sets the user-defined pins from a string like "int x,float y". - // Returns true on success. - static bool SetArgs(UEdGraphNode* Node, const FString& Args); - - // Returns true if the arguments are valid, if not prints error. - static bool CheckArgs(const FString &Args); - -private: - // A parsed argument: type + name. - struct FParsedArg - { - FEdGraphPinType PinType; - FName PinName; - }; - - // Parse "int x,float y" into an array of FParsedArg. - // Returns false and prints an error on failure. - static bool ParseArgs(const FString& Args, TArray& OutArgs); - - // Determine the pin direction for user-defined pins on this node. - static EEdGraphPinDirection GetPinDirection(UK2Node_EditablePinBase* Node); -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h b/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h index 90303f4e..05a8cbc9 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h @@ -5,6 +5,7 @@ #include "Engine/Blueprint.h" struct WingTokenizer; +class UK2Node_CustomEvent; class UK2Node_EditablePinBase; class UK2Node_FunctionEntry; struct FUserPinInfo; @@ -54,6 +55,9 @@ public: // Print the variables to a string builder. void Print(FStringBuilderBase &Out); + + // Print compact: "type name,type name,..." + void PrintCompact(FStringBuilderBase &Out); // Clear the BPVar and Pin fields. void ClearLinks(); @@ -77,11 +81,13 @@ class WingVariables { public: using Var = WingVariableList::Var; + WingVariables() {} // The backing store. Only one of these should be set. UBlueprint *Blueprint = nullptr; UEdGraph *Graph = nullptr; + UK2Node_CustomEvent *CustomEvent = nullptr; // The Workspace. At any given time, these may or may not contain // the same data as the backing store. @@ -91,10 +97,10 @@ public: WingVariableList InputVariables{TEXT("Input Variables")}; WingVariableList OutputVariables{TEXT("Output Variables")}; - // Constructors. Just initialize the pointers to the backing store. + // Configure the backing store. On failure, + // prints a message and returns false. - WingVariables(UBlueprint *BP) : Blueprint(BP) {} - WingVariables(UEdGraph *G) : Graph(G) {} + bool SetBackingStore(UObject *Obj); // Clear the workspace. Doesn't affect the backing store. @@ -155,11 +161,20 @@ private: bool RemoveBlueprint(); bool RemoveGraph(); + void LoadCustomEvent(); + bool CheckCustomEvent(); + bool ModifyCustomEvent(); + bool CreateCustomEvent(); + bool RemoveCustomEvent(); + bool GetGraphNodes( UK2Node_EditablePinBase *&InputNode, UK2Node_EditablePinBase *&OutputNode, UK2Node_FunctionEntry *&LocalNode); + bool ModifyEditablePinBase(WingVariableList &List, UK2Node_EditablePinBase *Node); void AddUserPinInfo(const Var &V, EEdGraphPinDirection Dir, UK2Node_EditablePinBase *Node); + + bool ErrorNoBackingStore(); }; diff --git a/Plugins/UEWingman/ue-wingman.py b/Plugins/UEWingman/ue-wingman.py index 31ab61fe..c6088dc0 100755 --- a/Plugins/UEWingman/ue-wingman.py +++ b/Plugins/UEWingman/ue-wingman.py @@ -2,7 +2,8 @@ """ Human-friendly MCP test client. -Usage: ue-wingman.py UserManual +Usage: ue-wingman.py [key=value ...] + ue-wingman.py (reads JSON with "command" from stdin) """ import sys @@ -17,27 +18,28 @@ TIMEOUT = 120 def main(): args = sys.argv[1:] if not args: - print("Usage: ue-wingman.py ShowCommands [key=value ...]") - sys.exit(1) - - no_args_commands = {"ShowCommands", "UserManual"} - if len(args) == 1 and args[0] not in no_args_commands: - # No extra arguments: read JSON object from stdin. - # Accumulate lines and try to parse after each one. + # No arguments: read a complete JSON object from stdin. + # The JSON must already contain a "command" key. decoder = json.JSONDecoder() raw = "" msg = None for line in sys.stdin: raw += line + stripped = raw.strip() try: - msg, _ = decoder.raw_decode(raw.lstrip()) + msg, _ = decoder.raw_decode(stripped) break - except json.JSONDecodeError: + except json.JSONDecodeError as e: + if e.pos < len(stripped): + print(f"Malformed JSON: {e.msg}") + sys.exit(1) continue if msg is None: print("Could not parse a complete JSON object from stdin") sys.exit(1) - msg["command"] = args[0] + if "command" not in msg: + print("JSON object must contain a \"command\" key") + sys.exit(1) else: msg = {"command": args[0]} for arg in args[1:]: