From e9fff6599aeb3cf8f20ac4c1757c8fd461d9678e Mon Sep 17 00:00:00 2001 From: jyelon Date: Sat, 4 Apr 2026 01:45:25 -0400 Subject: [PATCH] Enormouse overhaul --- .../UEWingman/Handlers/ActorComponent_Add.h | 16 +- .../Handlers/ActorComponent_Remove.h | 6 +- .../Handlers/ActorComponent_Reparent.h | 8 +- .../Source/UEWingman/Handlers/Asset_Backup.h | 6 +- .../UEWingman/Handlers/Asset_ContentBrowse.h | 4 +- .../Source/UEWingman/Handlers/Asset_Delete.h | 14 +- .../UEWingman/Handlers/Asset_FindReferences.h | 8 +- .../Source/UEWingman/Handlers/Asset_Rename.h | 8 +- .../Source/UEWingman/Handlers/Asset_Restore.h | 8 +- .../Source/UEWingman/Handlers/Asset_Search.h | 10 +- .../Handlers/BlueprintGraph_Create.h | 28 +- .../Handlers/BlueprintGraph_Delete.h | 8 +- .../Handlers/BlueprintInterface_Add.h | 12 +- .../Handlers/BlueprintInterface_Remove.h | 10 +- .../UEWingman/Handlers/Blueprint_Compile.h | 6 +- .../UEWingman/Handlers/Blueprint_Dump.h | 59 +- .../UEWingman/Handlers/Blueprint_Reparent.h | 8 +- .../UEWingman/Handlers/Create_Blueprint.h | 14 +- .../UEWingman/Handlers/Create_UsingFactory.h | 4 +- .../Source/UEWingman/Handlers/Details_Dump.h | 13 +- .../Source/UEWingman/Handlers/Details_Get.h | 8 +- .../Source/UEWingman/Handlers/Details_Set.h | 10 +- .../UEWingman/Handlers/Details_SetMany.h | 14 +- .../Handlers/Editor_ListOpenAssets.h | 6 +- .../UEWingman/Handlers/Editor_OpenAsset.h | 8 +- .../Handlers/EventDispatcher_Create.h | 20 +- .../Handlers/EventDispatcher_Delete.h | 8 +- .../UEWingman/Handlers/GraphNode_ChooseMenu.h | 8 +- .../UEWingman/Handlers/GraphNode_Create.h | 62 +- .../UEWingman/Handlers/GraphNode_Delete.h | 6 +- .../UEWingman/Handlers/GraphNode_Dump.h | 6 +- .../UEWingman/Handlers/GraphNode_GetComment.h | 8 +- .../UEWingman/Handlers/GraphNode_Rename.h | 6 +- .../Handlers/GraphNode_SearchTypes.h | 8 +- .../UEWingman/Handlers/GraphNode_SetComment.h | 4 +- .../Handlers/GraphNode_SetDefaults.h | 33 +- .../Handlers/GraphNode_SetPositions.h | 16 +- .../UEWingman/Handlers/GraphNode_ShowMenu.h | 8 +- .../UEWingman/Handlers/GraphPin_Connect.h | 15 +- .../UEWingman/Handlers/GraphPin_Disconnect.h | 17 +- .../Source/UEWingman/Handlers/Graph_Dump.h | 8 +- .../MaterialInstance_ClearParameter.h | 8 +- .../MaterialInstance_DumpParameters.h | 6 +- .../Handlers/MaterialInstance_SetParameter.h | 16 +- .../UEWingman/Handlers/Material_Compile.h | 8 +- .../Handlers/Material_DumpParameters.h | 4 +- .../Source/UEWingman/Handlers/ShowCommands.h | 4 +- .../UEWingman/Handlers/SysInfo_Factories.h | 2 +- .../UEWingman/Handlers/Test_Sanitizer.h | 2 +- .../UEWingman/Handlers/Test_Tokenizer.h | 2 +- .../UEWingman/Handlers/Test_TypeToText.h | 22 +- .../UEWingman/Handlers/Test_Unsanitize.h | 4 +- .../UEWingman/Handlers/TypeName_Search.h | 6 +- .../UEWingman/Handlers/Variables_Create.h | 18 +- .../UEWingman/Handlers/Variables_Dump.h | 8 +- .../UEWingman/Handlers/Variables_Modify.h | 18 +- .../UEWingman/Handlers/Variables_Remove.h | 16 +- .../Source/UEWingman/Handlers/Widget_Create.h | 22 +- .../Source/UEWingman/Handlers/Widget_Delete.h | 8 +- .../UEWingman/Handlers/Widget_Reparent.h | 12 +- .../UEWingman/Handlers/Widget_SearchTypes.h | 6 +- .../UEWingman/Private/WingActorComponent.cpp | 60 +- .../UEWingman/Private/WingFactories.cpp | 22 +- .../Source/UEWingman/Private/WingFetcher.cpp | 69 +- .../UEWingman/Private/WingGraphExport.cpp | 8 +- .../Source/UEWingman/Private/WingManual.cpp | 54 +- .../Private/WingMaterialParameter.cpp | 16 +- .../UEWingman/Private/WingPropHandle.cpp | 58 +- .../Source/UEWingman/Private/WingProperty.cpp | 707 ++++++++++-------- .../Source/UEWingman/Private/WingServer.cpp | 22 +- .../Source/UEWingman/Private/WingTypes.cpp | 104 +-- .../Source/UEWingman/Private/WingUtils.cpp | 42 +- .../UEWingman/Private/WingVariables.cpp | 255 +++---- .../Source/UEWingman/Private/WingWidgets.cpp | 10 +- .../UEWingman/Public/WingActorComponent.h | 19 +- .../Source/UEWingman/Public/WingFactories.h | 5 +- .../Source/UEWingman/Public/WingFetcher.h | 19 +- .../Source/UEWingman/Public/WingHandler.h | 46 ++ .../UEWingman/Public/WingMaterialParameter.h | 3 +- .../Source/UEWingman/Public/WingPropHandle.h | 15 +- .../Source/UEWingman/Public/WingProperty.h | 130 ++-- .../Source/UEWingman/Public/WingServer.h | 15 - .../Source/UEWingman/Public/WingTypes.h | 29 +- .../Source/UEWingman/Public/WingUtils.h | 53 +- .../Source/UEWingman/Public/WingVariables.h | 64 +- .../Source/UEWingman/Public/WingWidgets.h | 3 +- 86 files changed, 1324 insertions(+), 1225 deletions(-) diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Add.h b/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Add.h index 71c01de3..8ef263ee 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Add.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Add.h @@ -45,16 +45,16 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UBlueprint* BP = F.Asset(Blueprint).Cast(); if (!BP) return; // Check that the proposed name is valid - FName InternalID = WingUtils::CheckProposedName(Component); + FName InternalID = WingUtils::CheckProposedName(Component, WingOut::Stdout); if (InternalID.IsNone()) return; TSet Names; FBlueprintEditorUtils::GetClassVariableList(BP, Names); - if (!WingUtils::FindNoDuplicateName(Names, InternalID, TEXT("variable or component"))) return; + if (!WingUtils::FindNoDuplicateName(Names, InternalID, TEXT("variable or component"), WingOut::Stdout)) return; // Resolve the component class by name UWingTypes::Requirements Req; @@ -62,18 +62,18 @@ public: Req.Blueprintable = false; Req.AllowContainer = false; Req.IsChildOf = UActorComponent::StaticClass(); - UClass* ComponentClass = UWingTypes::TextToOneObjectType(Class, Req); + UClass* ComponentClass = UWingTypes::TextToOneObjectType(Class, Req, WingOut::Stdout); if (!ComponentClass) return; - if (!UWingComponentReference::CheckValidComponentClass(ComponentClass)) return; + if (!UWingComponentReference::CheckValidComponentClass(ComponentClass, WingOut::Stdout)) return; // Find the specified parent component TArray AllComponents = UWingComponentReference::GetAll(BP); - UWingComponentReference* ParentComp = WingUtils::FindOneWithExternalID(Parent, AllComponents, TEXT("Component")); + UWingComponentReference* ParentComp = WingUtils::FindOneWithExternalID(Parent, AllComponents, TEXT("Component"), WingOut::Stdout); if (!ParentComp) return; // Create the SCS node - if (!UWingComponentReference::AddComponent(BP, ComponentClass, ParentComp, InternalID)) return; + if (!UWingComponentReference::AddComponent(BP, ComponentClass, ParentComp, InternalID, WingOut::Stdout)) return; - UWingServer::Printf(TEXT("Component Added.\n")); + WingOut::Stdout.Printf(TEXT("Component Added.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Remove.h b/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Remove.h index e0d29cc7..7c349d54 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Remove.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Remove.h @@ -28,12 +28,12 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UWingComponentReference* CompRef = F.Walk(Component).Cast(); if (!CompRef) return; - if (!CompRef->DeleteComponent()) return; + if (!CompRef->DeleteComponent(WingOut::Stdout)) return; - UWingServer::Printf(TEXT("Removed component.\n")); + WingOut::Stdout.Printf(TEXT("Removed component.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Reparent.h b/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Reparent.h index a8198921..7a6b47ec 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Reparent.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/ActorComponent_Reparent.h @@ -35,18 +35,18 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UWingComponentReference* CompRef = F.Walk(Component).Cast(); if (!CompRef) return; // Find the new parent among all components (if specified) UBlueprint *BP = CompRef->BP; TArray AllComponents = UWingComponentReference::GetAll(BP); - UWingComponentReference* NewParent = WingUtils::FindOneWithExternalID(Parent, AllComponents, TEXT("Component")); + UWingComponentReference* NewParent = WingUtils::FindOneWithExternalID(Parent, AllComponents, TEXT("Component"), WingOut::Stdout); if (!NewParent) return; - if (!CompRef->ReparentComponent(NewParent)) return; + if (!CompRef->ReparentComponent(NewParent, WingOut::Stdout)) return; - UWingServer::Printf(TEXT("Reparented component.")); + WingOut::Stdout.Printf(TEXT("Reparented component.")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Backup.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Backup.h index 5a47422e..154747a6 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Backup.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Backup.h @@ -35,7 +35,7 @@ public: if (!IFileManager::Get().FileExists(*Filename)) { - UWingServer::Printf(TEXT("ERROR: Asset file not found: %s\n"), *Filename); + WingOut::Stdout.Printf(TEXT("ERROR: Asset file not found: %s\n"), *Filename); return; } @@ -43,10 +43,10 @@ public: uint32 CopyResult = IFileManager::Get().Copy(*BackupFilename, *Filename, true); if (CopyResult != COPY_OK) { - UWingServer::Printf(TEXT("ERROR: Failed to copy %s to %s\n"), *Filename, *BackupFilename); + WingOut::Stdout.Printf(TEXT("ERROR: Failed to copy %s to %s\n"), *Filename, *BackupFilename); return; } - UWingServer::Printf(TEXT("Backed up to %s\n"), *BackupFilename); + WingOut::Stdout.Printf(TEXT("Backed up to %s\n"), *BackupFilename); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_ContentBrowse.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_ContentBrowse.h index f084ea7d..9e2815e3 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_ContentBrowse.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_ContentBrowse.h @@ -93,11 +93,11 @@ public: } Results.Sort(); - for (const FString &Result : Results) UWingServer::Print(Result); + for (const FString &Result : Results) WingOut::Stdout.Print(Result); if (Results.IsEmpty()) { - UWingServer::Printf(TEXT("No contents found at '%s'.\n"), *Path); + WingOut::Stdout.Printf(TEXT("No contents found at '%s'.\n"), *Path); return; } } diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Delete.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Delete.h index 19e95e20..885043f5 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Delete.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Delete.h @@ -44,7 +44,7 @@ public: if (!IFileManager::Get().FileExists(*PackageFilename)) { - UWingServer::Printf(TEXT("ERROR: Asset file not found on disk: %s\n"), *PackageFilename); + WingOut::Stdout.Printf(TEXT("ERROR: Asset file not found on disk: %s\n"), *PackageFilename); return; } @@ -60,22 +60,22 @@ public: if (Referencers.Num() > 0 && !Force) { - UWingServer::Printf(TEXT("ERROR: Asset is still referenced by %d package(s):\n"), Referencers.Num()); + WingOut::Stdout.Printf(TEXT("ERROR: Asset is still referenced by %d package(s):\n"), Referencers.Num()); for (const FName& Ref : Referencers) { FString RefStr = Ref.ToString(); UPackage* RefPackage = FindPackage(nullptr, *RefStr); - UWingServer::Printf(TEXT(" %s%s\n"), *RefStr, + WingOut::Stdout.Printf(TEXT(" %s%s\n"), *RefStr, RefPackage ? TEXT(" (loaded)") : TEXT(" (on-disk only)")); } - UWingServer::Print(TEXT("Use force=true to skip the reference check.\n")); + WingOut::Stdout.Print(TEXT("Use force=true to skip the reference check.\n")); return; } // Force delete: unload the package from memory first if (Force && Referencers.Num() > 0) { - UWingServer::Printf(TEXT("WARNING: Force-deleting despite %d referencer(s).\n"), Referencers.Num()); + WingOut::Stdout.Printf(TEXT("WARNING: Force-deleting despite %d referencer(s).\n"), Referencers.Num()); } // Mark the package, and all the objects in it, as NOT @@ -109,7 +109,7 @@ public: if (!bDeleted) { - UWingServer::Printf(TEXT("ERROR: Failed to delete file from disk: %s\n"), *PackageFilename); + WingOut::Stdout.Printf(TEXT("ERROR: Failed to delete file from disk: %s\n"), *PackageFilename); return; } @@ -122,6 +122,6 @@ public: Registry.ScanPathsSynchronous({PackageDir}, true); } - UWingServer::Printf(TEXT("Deleted %s\n"), *Asset); + WingOut::Stdout.Printf(TEXT("Deleted %s\n"), *Asset); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_FindReferences.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_FindReferences.h index 580fa5e6..a2d90d6d 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_FindReferences.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_FindReferences.h @@ -35,7 +35,7 @@ public: FAssetData AssetData = Registry.GetAssetByObjectPath(FSoftObjectPath(Asset)); if (!AssetData.IsValid()) { - UWingServer::Printf(TEXT("ERROR: Asset not found: %s\n"), *Asset); + WingOut::Stdout.Printf(TEXT("ERROR: Asset not found: %s\n"), *Asset); return; } @@ -44,7 +44,7 @@ public: if (Referencers.Num() == 0) { - UWingServer::Print(TEXT("No referencers found.\n")); + WingOut::Stdout.Print(TEXT("No referencers found.\n")); return; } @@ -56,13 +56,13 @@ public: Registry.GetAssetsByPackageName(Ref, RefAssets); if (RefAssets.Num() > 0) { - UWingServer::Printf(TEXT("%s %s\n"), + WingOut::Stdout.Printf(TEXT("%s %s\n"), *WingUtils::FormatName(RefAssets[0].GetClass()), *RefStr); } else { - UWingServer::Printf(TEXT("Unknown %s\n"), *RefStr); + WingOut::Stdout.Printf(TEXT("Unknown %s\n"), *RefStr); } } } diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Rename.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Rename.h index 54a292c3..11dee8d6 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Rename.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Rename.h @@ -34,7 +34,7 @@ public: virtual void Handle() override { // Load the asset - WingFetcher F; + WingFetcher F(WingOut::Stdout); UObject* AssetObj = F.Asset(Asset).GetObj(); if (!AssetObj) return; @@ -48,7 +48,7 @@ public: NewAssetName = NewPath; if (NewPackagePath.IsEmpty()) { - UWingServer::Printf(TEXT("ERROR: Cannot determine directory from Asset '%s'\n"), *Asset); + WingOut::Stdout.Printf(TEXT("ERROR: Cannot determine directory from Asset '%s'\n"), *Asset); return; } } @@ -62,10 +62,10 @@ public: if (!AssetTools.RenameAssets(RenameData)) { - UWingServer::Print(TEXT("ERROR: Rename failed. The target path may be invalid or a conflicting asset may exist.\n")); + WingOut::Stdout.Print(TEXT("ERROR: Rename failed. The target path may be invalid or a conflicting asset may exist.\n")); return; } - UWingServer::Printf(TEXT("Renamed to %s/%s\n"), *NewPackagePath, *NewAssetName); + WingOut::Stdout.Printf(TEXT("Renamed to %s/%s\n"), *NewPackagePath, *NewAssetName); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Restore.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Restore.h index ec5b2aa0..b5d1ae85 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Restore.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Restore.h @@ -37,7 +37,7 @@ public: if (!IFileManager::Get().FileExists(*BackupFilename)) { - UWingServer::Printf(TEXT("ERROR: Backup file not found: %s\n"), *BackupFilename); + WingOut::Stdout.Printf(TEXT("ERROR: Backup file not found: %s\n"), *BackupFilename); return; } @@ -52,7 +52,7 @@ public: uint32 CopyResult = IFileManager::Get().Copy(*Filename, *BackupFilename, true); if (CopyResult != COPY_OK) { - UWingServer::Printf(TEXT("ERROR: Failed to copy backup over %s\n"), *Asset); + WingOut::Stdout.Printf(TEXT("ERROR: Failed to copy backup over %s\n"), *Asset); return; } @@ -64,12 +64,12 @@ public: UEditorLoadingAndSavingUtils::ReloadPackages({Package}, bReloaded, ErrorMessage, EReloadPackagesInteractionMode::AssumePositive); if (!bReloaded) { - UWingServer::Printf(TEXT("WARNING: Restored %s but reload failed: %s\n"), + WingOut::Stdout.Printf(TEXT("WARNING: Restored %s but reload failed: %s\n"), *Asset, *ErrorMessage.ToString()); return; } } - UWingServer::Printf(TEXT("Restored %s from backup\n"), *Asset); + WingOut::Stdout.Printf(TEXT("Restored %s from backup\n"), *Asset); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Search.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Search.h index 756c9751..e27425c4 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Search.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Asset_Search.h @@ -39,7 +39,7 @@ public: { if (Query.IsEmpty() && Type.IsEmpty()) { - UWingServer::Print(TEXT("ERROR: At least one of Query or Type must be specified\n")); + WingOut::Stdout.Print(TEXT("ERROR: At least one of Query or Type must be specified\n")); return; } @@ -55,7 +55,7 @@ public: Req.BlueprintType = false; Req.Blueprintable = false; Req.AllowContainer = false; - UClass* TypeClass = UWingTypes::TextToOneObjectType(Type, Req); + UClass* TypeClass = UWingTypes::TextToOneObjectType(Type, Req, WingOut::Stdout); if (!TypeClass) return; Filter.ClassPaths.Add(TypeClass->GetClassPathName()); } @@ -81,18 +81,18 @@ public: for (const FAssetData& Data : Results) { - UWingServer::Printf(TEXT("%s %s\n"), + WingOut::Stdout.Printf(TEXT("%s %s\n"), *WingUtils::FormatName(Data.GetClass()), *Data.PackageName.ToString()); } if (Results.Num() == 0) { - UWingServer::Print(TEXT("No assets found.\n")); + WingOut::Stdout.Print(TEXT("No assets found.\n")); } else if (Results.Num() >= Limit) { - UWingServer::Printf(TEXT("WARNING: You reached the limit of %d, to raise it, specify the Limit parameter.\n"), Limit); + WingOut::Stdout.Printf(TEXT("WARNING: You reached the limit of %d, to raise it, specify the Limit parameter.\n"), Limit); } } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Create.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Create.h index 4890acd0..fcb860de 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Create.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Create.h @@ -47,48 +47,48 @@ public: { if (GraphType != TEXT("function") && GraphType != TEXT("macro")) { - UWingServer::Printf(TEXT("ERROR: Invalid GraphType '%s'. Valid values: function, macro\n"), *GraphType); + WingOut::Stdout.Printf(TEXT("ERROR: Invalid GraphType '%s'. Valid values: function, macro\n"), *GraphType); return; } - WingFetcher F; + WingFetcher F(WingOut::Stdout); UBlueprint* BP = F.Walk(Blueprint).Cast(); if (!BP) return; // Check that this graph type is valid for this blueprint type if (BP->BlueprintType == BPTYPE_Interface) { - UWingServer::Print(TEXT("ERROR: Cannot add graphs to interface blueprints.\n")); + WingOut::Stdout.Print(TEXT("ERROR: Cannot add graphs to interface blueprints.\n")); return; } if (BP->BlueprintType == BPTYPE_MacroLibrary && GraphType == TEXT("function")) { - UWingServer::Print(TEXT("ERROR: Macro libraries cannot contain functions.\n")); + WingOut::Stdout.Print(TEXT("ERROR: Macro libraries cannot contain functions.\n")); return; } if (BP->BlueprintType == BPTYPE_FunctionLibrary && GraphType == TEXT("macro")) { - UWingServer::Print(TEXT("ERROR: Function libraries cannot contain macros.\n")); + WingOut::Stdout.Print(TEXT("ERROR: Function libraries cannot contain macros.\n")); return; } // Check graph name uniqueness and legality - FName InternalID = WingUtils::CheckProposedName(Graph); + FName InternalID = WingUtils::CheckProposedName(Graph, WingOut::Stdout); if (InternalID.IsNone()) return; - if (!WingUtils::FindNoneWithInternalID(InternalID, WingUtils::AllGraphs(BP), TEXT("Graph"))) + if (!WingUtils::FindNoneWithInternalID(InternalID, WingUtils::AllGraphs(BP), TEXT("Graph"), WingOut::Stdout)) return; // Parse and validate variables before making changes WingVariables Vars; - if (!Vars.InputVariables.ParseString(InputVariables)) return; - if (!Vars.OutputVariables.ParseString(OutputVariables)) return; + if (!Vars.InputVariables.ParseString(InputVariables, WingOut::Stdout)) return; + if (!Vars.OutputVariables.ParseString(OutputVariables, WingOut::Stdout)) return; // Create the Graph UEdGraph* NewGraph = FBlueprintEditorUtils::CreateNewGraph(BP, InternalID, UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass()); if (!NewGraph) { - UWingServer::Print(TEXT("ERROR: Failed to create graph\n")); + WingOut::Stdout.Print(TEXT("ERROR: Failed to create graph\n")); return; } @@ -103,10 +103,10 @@ public: } // Create the variables on the new graph - if (!Vars.SetBackingStore(NewGraph)) return; - if (!Vars.Check()) return; - if (!Vars.Create()) return; + if (!Vars.SetBackingStore(NewGraph, WingOut::Stdout)) return; + if (!Vars.Check(WingOut::Stdout)) return; + if (!Vars.Create(WingOut::Stdout)) return; - UWingServer::Printf(TEXT("Created %s graph: %s\n"), *GraphType, *WingUtils::FormatName(NewGraph)); + WingOut::Stdout.Printf(TEXT("Created %s graph: %s\n"), *GraphType, *WingUtils::FormatName(NewGraph)); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Delete.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Delete.h index 4dbf8619..544f899a 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Delete.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintGraph_Delete.h @@ -31,25 +31,25 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraph* FoundGraph = F.Walk(Graph).Cast(); if (!FoundGraph) return; UBlueprint* BP = FBlueprintEditorUtils::FindBlueprintForGraph(FoundGraph); if (!BP) { - UWingServer::Print(TEXT("ERROR: Could not find owning blueprint for this graph.\n")); + WingOut::Stdout.Print(TEXT("ERROR: Could not find owning blueprint for this graph.\n")); return; } if (!BP->FunctionGraphs.Contains(FoundGraph) && !BP->MacroGraphs.Contains(FoundGraph)) { - UWingServer::Printf(TEXT("ERROR: %s is not a function or macro graph.\n"), *WingUtils::FormatName(FoundGraph)); + WingOut::Stdout.Printf(TEXT("ERROR: %s is not a function or macro graph.\n"), *WingUtils::FormatName(FoundGraph)); return; } FBlueprintEditorUtils::RemoveGraph(BP, FoundGraph, EGraphRemoveFlags::Recompile); - UWingServer::Printf(TEXT("Deleted graph from %s\n"), *WingUtils::FormatName(BP)); + WingOut::Stdout.Printf(TEXT("Deleted graph from %s\n"), *WingUtils::FormatName(BP)); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintInterface_Add.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintInterface_Add.h index 6e8c0824..10aede51 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintInterface_Add.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintInterface_Add.h @@ -34,7 +34,7 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UBlueprint* BP = F.Asset(Blueprint).Cast(); if (!BP) return; @@ -43,7 +43,7 @@ public: Req.BlueprintType = false; Req.Blueprintable = false; Req.AllowContainer = false; - UClass* InterfaceClass = UWingTypes::TextToOneInterfaceType(Interface, Req); + UClass* InterfaceClass = UWingTypes::TextToOneInterfaceType(Interface, Req, WingOut::Stdout); if (!InterfaceClass) return; // Check for duplicates @@ -51,7 +51,7 @@ public: { if (IfaceDesc.Interface == InterfaceClass) { - UWingServer::Printf(TEXT("ERROR: Interface '%s' is already implemented by this Blueprint.\n"), + WingOut::Stdout.Printf(TEXT("ERROR: Interface '%s' is already implemented by this Blueprint.\n"), *WingUtils::FormatName(InterfaceClass)); return; } @@ -61,19 +61,19 @@ public: bool bAdded = FBlueprintEditorUtils::ImplementNewInterface(BP, InterfacePath); if (!bAdded) { - UWingServer::Printf(TEXT("ERROR: ImplementNewInterface failed for '%s'.\n"), + WingOut::Stdout.Printf(TEXT("ERROR: ImplementNewInterface failed for '%s'.\n"), *WingUtils::FormatName(InterfaceClass)); return; } // Collect stub function graph names from the newly added interface entry - UWingServer::Printf(TEXT("Added interface %s\n"), *WingUtils::FormatName(InterfaceClass)); + WingOut::Stdout.Printf(TEXT("Added interface %s\n"), *WingUtils::FormatName(InterfaceClass)); for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces) { if (IfaceDesc.Interface != InterfaceClass) continue; for (const UEdGraph* Graph : IfaceDesc.Graphs) { - UWingServer::Printf(TEXT("New Graph: %s\n"), *WingUtils::FormatName(Graph)); + WingOut::Stdout.Printf(TEXT("New Graph: %s\n"), *WingUtils::FormatName(Graph)); } break; } diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintInterface_Remove.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintInterface_Remove.h index 2bf4a432..de0b5756 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintInterface_Remove.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintInterface_Remove.h @@ -38,7 +38,7 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UBlueprint* BP = F.Asset(Blueprint).Cast(); if (!BP) return; @@ -47,7 +47,7 @@ public: Req.BlueprintType = false; Req.Blueprintable = false; Req.AllowContainer = false; - UClass* FoundInterface = UWingTypes::TextToOneInterfaceType(Interface, Req); + UClass* FoundInterface = UWingTypes::TextToOneInterfaceType(Interface, Req, WingOut::Stdout); if (!FoundInterface) return; // Verify this blueprint actually implements it @@ -58,7 +58,7 @@ public: } if (!Found) { - UWingServer::Printf(TEXT("ERROR: Blueprint %s does not implement interface %s\n"), + WingOut::Stdout.Printf(TEXT("ERROR: Blueprint %s does not implement interface %s\n"), *WingUtils::FormatName(BP), *WingUtils::FormatName(FoundInterface)); return; } @@ -66,8 +66,8 @@ public: FTopLevelAssetPath InterfacePath = FoundInterface->GetClassPathName(); FBlueprintEditorUtils::RemoveInterface(BP, InterfacePath, PreserveFunctions); - UWingServer::Printf(TEXT("Removed interface %s\n"), *WingUtils::FormatName(FoundInterface)); + WingOut::Stdout.Printf(TEXT("Removed interface %s\n"), *WingUtils::FormatName(FoundInterface)); if (PreserveFunctions) - UWingServer::Print(TEXT("Function graphs preserved as regular functions.\n")); + WingOut::Stdout.Print(TEXT("Function graphs preserved as regular functions.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Compile.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Compile.h index 01d7765b..466e2cff 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Compile.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Compile.h @@ -32,7 +32,7 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UBlueprint* BP = F.Asset(Blueprint).Cast(); if (!BP) return; @@ -48,11 +48,11 @@ public: { if (!Node->bHasCompilerMessage) continue; const TCHAR* Prefix = (Node->ErrorType == EMessageSeverity::Error) ? TEXT("ERROR") : TEXT("WARNING"); - UWingServer::Printf(TEXT("%s: [%s] %s: %s\n"), + WingOut::Stdout.Printf(TEXT("%s: [%s] %s: %s\n"), Prefix, *WingUtils::FormatName(Node->GetGraph()), *WingUtils::FormatName(Node), *Node->ErrorMsg); } - UWingServer::Printf(TEXT("Compilation Done.\n")); + WingOut::Stdout.Printf(TEXT("Compilation Done.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h index 723f8326..19c333fd 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h @@ -42,63 +42,63 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UBlueprint* BP = F.Walk(Blueprint).Cast(); if (!BP) return; // Header - UWingServer::Printf(TEXT("Blueprint: %s\n"), *WingUtils::FormatName(BP)); - UWingServer::Printf(TEXT("Parent: %s\n"), BP->ParentClass ? *WingUtils::FormatName(BP->ParentClass) : TEXT("None")); - UWingServer::Printf(TEXT("Type: %s\n"), *WingUtils::EnumToString(BP->BlueprintType)); + WingOut::Stdout.Printf(TEXT("Blueprint: %s\n"), *WingUtils::FormatName(BP)); + WingOut::Stdout.Printf(TEXT("Parent: %s\n"), BP->ParentClass ? *WingUtils::FormatName(BP->ParentClass) : TEXT("None")); + WingOut::Stdout.Printf(TEXT("Type: %s\n"), *WingUtils::EnumToString(BP->BlueprintType)); // Animation Blueprint if (UAnimBlueprint* AnimBP = Cast(BP)) { if (AnimBP->TargetSkeleton) - UWingServer::Printf(TEXT("TargetSkeleton: %s\n"), *AnimBP->TargetSkeleton->GetPathName()); + WingOut::Stdout.Printf(TEXT("TargetSkeleton: %s\n"), *AnimBP->TargetSkeleton->GetPathName()); } // Interfaces for (const FBPInterfaceDescription& I : BP->ImplementedInterfaces) { - if (I.Interface) UWingServer::Printf(TEXT("Interface: %s\n"), *WingUtils::FormatName(I)); + if (I.Interface) WingOut::Stdout.Printf(TEXT("Interface: %s\n"), *WingUtils::FormatName(I)); } // Variables WingVariables BlueprintVars; - BlueprintVars.SetBackingStore(BP); - BlueprintVars.Load(); - BlueprintVars.Print(UWingServer::GetPrintBuffer()); + BlueprintVars.SetBackingStore(BP, WingOut::Stdout); + BlueprintVars.Load(WingOut::Stdout); + BlueprintVars.Print(WingOut::StdoutBuffer); // Components TArray Components3 = UWingComponentReference::GetAll(BP); if (!Components3.IsEmpty()) { - UWingServer::Print(TEXT("\nComponents:\n")); + WingOut::Stdout.Print(TEXT("\nComponents:\n")); for (const UWingComponentReference* Ref : Components3) { - UWingServer::Printf(TEXT(" %s %s"), + WingOut::Stdout.Printf(TEXT(" %s %s"), *Ref->TypeName, *WingUtils::FormatName(Ref)); if (!Ref->ParentName.IsEmpty()) - UWingServer::Printf(TEXT(" [parent: %s]"), *Ref->ParentName); + WingOut::Stdout.Printf(TEXT(" [parent: %s]"), *Ref->ParentName); if (Ref->Inherited) - UWingServer::Print(TEXT(" [inherited]")); - UWingServer::Print(TEXT("\n")); + WingOut::Stdout.Print(TEXT(" [inherited]")); + WingOut::Stdout.Print(TEXT("\n")); } } // Widget Tree if (UWidgetBlueprint* WidgetBP = Cast(BP)) { - UWingServer::Print(TEXT("\nWidget Tree:\n")); + WingOut::Stdout.Print(TEXT("\nWidget Tree:\n")); WingWidgets::PrintWidgetTree(WidgetBP->WidgetTree->RootWidget, 1); } // Event Dispatchers if (!BP->DelegateSignatureGraphs.IsEmpty()) { - UWingServer::Print(TEXT("\nEvent Dispatchers:\n")); + WingOut::Stdout.Print(TEXT("\nEvent Dispatchers:\n")); for (UEdGraph* Graph : BP->DelegateSignatureGraphs) PrintEventDispatcher(Graph); } @@ -106,10 +106,10 @@ public: // Graphs TSet Printed; - UWingServer::Print(TEXT("\nGraphs:\n")); + WingOut::Stdout.Print(TEXT("\nGraphs:\n")); for (UEdGraph* Graph : BP->UbergraphPages) { - UWingServer::Printf(TEXT(" EventGraph %s\n"), *WingUtils::FormatName(Graph)); + WingOut::Stdout.Printf(TEXT(" EventGraph %s\n"), *WingUtils::FormatName(Graph)); Printed.Add(Graph); } for (UEdGraph* Graph : BP->FunctionGraphs) @@ -147,7 +147,7 @@ public: Printed.Add(Graph); } if (!AnimGraphNames.IsEmpty()) - UWingServer::Printf(TEXT("\nAnimation Graphs: %s\n"), *AnimGraphNames); + WingOut::Stdout.Printf(TEXT("\nAnimation Graphs: %s\n"), *AnimGraphNames); FString StateMachineNames; for (UEdGraph* Graph : AllGraphs) @@ -159,13 +159,13 @@ public: Printed.Add(Graph); } if (!StateMachineNames.IsEmpty()) - UWingServer::Printf(TEXT("\nAnimation State Machines: %s\n"), *StateMachineNames); + WingOut::Stdout.Printf(TEXT("\nAnimation State Machines: %s\n"), *StateMachineNames); // Catch any graphs we missed. for (UEdGraph* Graph : AllGraphs) { if (Printed.Contains(Graph)) continue; - UWingServer::Printf(TEXT("WARNING: unlisted graph: %s (%s)\n"), + WingOut::Stdout.Printf(TEXT("WARNING: unlisted graph: %s (%s)\n"), *WingUtils::FormatName(Graph), *WingUtils::FormatName(Graph->GetSchema()->GetClass())); } @@ -175,22 +175,21 @@ private: void PrintEventDispatcher(UEdGraph* Graph) { WingVariables Vars; - Vars.SetBackingStore(Graph); - Vars.Load(); + Vars.SetBackingStore(Graph, WingOut::Stdout); + Vars.Load(WingOut::Stdout); - FStringBuilderBase &Out = UWingServer::GetPrintBuffer(); - Out.Appendf(TEXT(" %s("), *WingUtils::FormatName(Graph)); - Vars.InputVariables.PrintCompact(Out); - Out.Append(TEXT(")\n")); + WingOut::Stdout.Printf(TEXT(" %s("), *WingUtils::FormatName(Graph)); + Vars.InputVariables.PrintCompact(WingOut::Stdout); + WingOut::Stdout.Printf(TEXT(")\n")); } void PrintGraph(UEdGraph* Graph, const TCHAR* Type, UClass* Interface = nullptr) { WingVariables Vars; - Vars.SetBackingStore(Graph); - Vars.Load(); + Vars.SetBackingStore(Graph, WingOut::Stdout); + Vars.Load(WingOut::Stdout); - FStringBuilderBase &Out = UWingServer::GetPrintBuffer(); + FStringBuilderBase &Out = WingOut::StdoutBuffer; Out.Appendf(TEXT(" %s %s"), Type, *WingUtils::FormatName(Graph)); Out.AppendChar('('); Vars.InputVariables.PrintCompact(Out); diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Reparent.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Reparent.h index 0415c5ed..32b6b5ca 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Reparent.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Reparent.h @@ -36,7 +36,7 @@ public: virtual void Handle() override { // Load Blueprint - WingFetcher F; + WingFetcher F(WingOut::Stdout); UBlueprint* BP = F.Asset(Blueprint).Cast(); if (!BP) return; @@ -45,13 +45,13 @@ public: Req.BlueprintType = false; Req.Blueprintable = true; Req.AllowContainer = false; - UClass* NewParentClassObj = UWingTypes::TextToOneObjectType(Parent, Req); + UClass* NewParentClassObj = UWingTypes::TextToOneObjectType(Parent, Req, WingOut::Stdout); if (!NewParentClassObj) return; // Validate reparent if (!WingUtils::CanReparentBlueprint(BP->GeneratedClass, NewParentClassObj)) { - UWingServer::Printf(TEXT("Error: Cannot reparent %s to %s — incompatible class hierarchy.\n"), + WingOut::Stdout.Printf(TEXT("Error: Cannot reparent %s to %s — incompatible class hierarchy.\n"), *WingUtils::FormatName(BP), *WingUtils::FormatName(NewParentClassObj)); return; } @@ -61,7 +61,7 @@ public: FBlueprintEditorUtils::RefreshAllNodes(BP); FKismetEditorUtilities::CompileBlueprint(BP); - UWingServer::Printf(TEXT("Reparented %s -> %s\n"), + WingOut::Stdout.Printf(TEXT("Reparented %s -> %s\n"), *WingUtils::FormatName(BP), *WingUtils::FormatName(NewParentClassObj)); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Create_Blueprint.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Create_Blueprint.h index 16224cc7..905faf94 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Create_Blueprint.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Create_Blueprint.h @@ -57,7 +57,7 @@ public: virtual void Handle() override { - if (!WingFactories::CheckNewAssetPath(Path)) return; + if (!WingFactories::CheckNewAssetPath(Path, WingOut::Stdout)) return; // Resolve parent class, if specified. UClass *ParentClassObj = nullptr; @@ -67,7 +67,7 @@ public: Req.BlueprintType = false; Req.Blueprintable = true; Req.AllowContainer = false; - ParentClassObj = UWingTypes::TextToOneObjectType(ParentClass, Req); + ParentClassObj = UWingTypes::TextToOneObjectType(ParentClass, Req, WingOut::Stdout); if (!ParentClassObj) return; } @@ -76,26 +76,26 @@ public: UFactory *Factory = NewObject(GetTransientPackage(), FactoryClass); if (Factory == nullptr) { - UWingServer::Printf(TEXT("ERROR: factory creation failed (bug)\n")); + WingOut::Stdout.Printf(TEXT("ERROR: factory creation failed (bug)\n")); return; } // Get the 'ParentClass' property. WingPropHandle Props; - TSharedPtr PCProp = Props.NamedProperty(Factory, TEXT("ParentClass"), true); + TSharedPtr PCProp = Props.NamedProperty(Factory, TEXT("ParentClass"), true, WingOut::Stdout); if (!PCProp) return; // Store the parent class. FPropertyAccess::Result SetResult = PCProp->SetValue(ParentClassObj); if (SetResult != FPropertyAccess::Result::Success) { - UWingServer::Printf(TEXT("ERROR: property does not allow value: %s\n"), *ParentClass); + WingOut::Stdout.Printf(TEXT("ERROR: property does not allow value: %s\n"), *ParentClass); return; } // Create the asset using the factory. - UObject *Blueprint = WingFactories::CreateAsset(Path, Factory); + UObject *Blueprint = WingFactories::CreateAsset(Path, Factory, WingOut::Stdout); if (Blueprint == nullptr) return; - UWingServer::Printf(TEXT("Created.\n")); + WingOut::Stdout.Printf(TEXT("Created.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Create_UsingFactory.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Create_UsingFactory.h index e9210173..816384a4 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Create_UsingFactory.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Create_UsingFactory.h @@ -49,7 +49,7 @@ public: { UClass* FactoryClass = Cast(ConfigurationObject); UFactory* Factory = NewObject(GetTransientPackage(), FactoryClass); - WingFactories::CreateAsset(Path, Factory); - UWingServer::Printf(TEXT("Created.\n")); + WingFactories::CreateAsset(Path, Factory, WingOut::Stdout); + WingOut::Stdout.Printf(TEXT("Created.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Dump.h index 1fdd6246..4b8428c7 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Dump.h @@ -18,9 +18,6 @@ public: UPROPERTY(EditAnywhere, meta=(Description="Target object")) FString Object; - UPROPERTY(meta=(Optional, Description="Substring filter for property names")) - FString Query; - virtual void Register() override { UWingServer::AddHandler(this, @@ -29,12 +26,11 @@ public: virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UObject* Target = F.Walk(Object).Cast(); if (!Target) return; - TArray Props = FWingProperty::GetDetailsImmutable(Target, CPF_Edit); - Props = FWingProperty::FindAllSubstring(Props, Query); + TArray Props = FWingProperty::GetDetails(Target, CPF_Edit, false); // Group by category, preserving within-category order. TSortedMap> Categories; @@ -45,14 +41,13 @@ public: Categories.FindOrAdd(Category).Add(P); } - FStringBuilderBase& Out = UWingServer::GetPrintBuffer(); for (const auto& Pair : Categories) { - Out.Appendf(TEXT("\n%s:\n"), *Pair.Key); + WingOut::Stdout.Printf(TEXT("\n%s:\n"), *Pair.Key); for (const FWingProperty& P : Pair.Value) { bool bEditable = !P->HasAnyPropertyFlags(CPF_EditConst); - Out.Appendf(TEXT(" %s %s %s = %s\n"), + WingOut::Stdout.Printf(TEXT(" %s %s %s = %s\n"), bEditable ? TEXT("editable") : TEXT("readonly"), *UWingTypes::TypeToText(P.Prop), *WingUtils::FormatName(P.Prop), diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Get.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Get.h index 1c9db12c..0a7f828b 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Get.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Get.h @@ -28,14 +28,14 @@ public: virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UObject* Obj = F.Walk(Object).Cast(); if (!Obj) return; - TArray Props = FWingProperty::GetDetailsImmutable(Obj, CPF_Edit); - FWingProperty* P = WingUtils::FindOneWithExternalID(Property, Props, TEXT("Property")); + TArray Props = FWingProperty::GetDetails(Obj, CPF_Edit, false); + FWingProperty* P = WingUtils::FindOneWithExternalID(Property, Props, TEXT("Property"), WingOut::Stdout); if (!P) return; - UWingServer::Print(P->GetText()); + WingOut::Stdout.Print(P->GetText()); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Set.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Set.h index 1ea00790..f74055d5 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Set.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Set.h @@ -31,15 +31,15 @@ public: virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UObject* Obj = F.Walk(Object).Cast(); if (!Obj) return; - TArray Props = FWingProperty::GetDetailsMutable(Obj, CPF_Edit); - FWingProperty* P = WingUtils::FindOneWithExternalID(Property, Props, TEXT("Property")); + TArray Props = FWingProperty::GetDetails(Obj, CPF_Edit, true); + FWingProperty* P = WingUtils::FindOneWithExternalID(Property, Props, TEXT("Property"), WingOut::Stdout); if (!P) return; - if (P->SetText(Value)) - UWingServer::Print(TEXT("OK\n")); + if (P->SetText(Value, WingOut::Stdout)) + WingOut::Stdout.Print(TEXT("OK\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_SetMany.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_SetMany.h index 774d60a8..bce27d0e 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_SetMany.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_SetMany.h @@ -28,22 +28,22 @@ public: virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UObject* Obj = F.Walk(Object).Cast(); if (!Obj) return; if (!Properties.Json || Properties.Json->Values.Num() == 0) { - UWingServer::Print(TEXT("Error: No properties specified\n")); + WingOut::Stdout.Print(TEXT("Error: No properties specified\n")); return; } - TArray Props = FWingProperty::GetDetailsMutable(Obj, CPF_Edit); + TArray Props = FWingProperty::GetDetails(Obj, CPF_Edit, true); // Validation pass — resolve all properties before modifying anything. for (const auto& Pair : Properties.Json->Values) { - FWingProperty* P = WingUtils::FindOneWithExternalID(Pair.Key, Props, TEXT("Property")); + FWingProperty* P = WingUtils::FindOneWithExternalID(Pair.Key, Props, TEXT("Property"), WingOut::Stdout); if (!P) return; } @@ -51,10 +51,10 @@ public: int SuccessCount = 0; for (const auto& Pair : Properties.Json->Values) { - FWingProperty* P = WingUtils::FindOneWithExternalID(Pair.Key, Props, TEXT("Property")); - if (P->SetJson(Pair.Value)) SuccessCount++; + FWingProperty* P = WingUtils::FindOneWithExternalID(Pair.Key, Props, TEXT("Property"), WingOut::Stdout); + if (P->SetJson(*Pair.Value, WingOut::Stdout)) SuccessCount++; } - UWingServer::Printf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num()); + WingOut::Stdout.Printf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num()); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Editor_ListOpenAssets.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Editor_ListOpenAssets.h index 33e5a5b3..30c103ec 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Editor_ListOpenAssets.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Editor_ListOpenAssets.h @@ -28,14 +28,14 @@ public: UAssetEditorSubsystem* Sub = GEditor->GetEditorSubsystem(); if (!Sub) { - UWingServer::Print(TEXT("Error: AssetEditorSubsystem not available\n")); + WingOut::Stdout.Print(TEXT("Error: AssetEditorSubsystem not available\n")); return; } TArray EditedAssets = Sub->GetAllEditedAssets(); if (EditedAssets.IsEmpty()) { - UWingServer::Print(TEXT("No asset editors are open.\n")); + WingOut::Stdout.Print(TEXT("No asset editors are open.\n")); return; } @@ -43,7 +43,7 @@ public: { bool bDirty = Asset->GetOutermost()->IsDirty(); - UWingServer::Printf(TEXT(" %s%s\n"), + WingOut::Stdout.Printf(TEXT(" %s%s\n"), bDirty ? TEXT("[unsaved] ") : TEXT(""), *Asset->GetPathName()); } diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Editor_OpenAsset.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Editor_OpenAsset.h index b560c66a..90f0e33a 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Editor_OpenAsset.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Editor_OpenAsset.h @@ -29,20 +29,20 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UObject* Obj = F.Walk(Asset).Cast(); if (!Obj) return; UAssetEditorSubsystem* Sub = GEditor->GetEditorSubsystem(); if (!Sub) { - UWingServer::Print(TEXT("Error: AssetEditorSubsystem not available\n")); + WingOut::Stdout.Print(TEXT("Error: AssetEditorSubsystem not available\n")); return; } if (Sub->OpenEditorForAsset(Obj)) - UWingServer::Printf(TEXT("Opened editor for %s\n"), *Obj->GetPathName()); + WingOut::Stdout.Printf(TEXT("Opened editor for %s\n"), *Obj->GetPathName()); else - UWingServer::Printf(TEXT("Error: Could not open editor for %s\n"), *Obj->GetPathName()); + WingOut::Stdout.Printf(TEXT("Error: Could not open editor for %s\n"), *Obj->GetPathName()); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Create.h b/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Create.h index f37e5774..bc3aba72 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Create.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Create.h @@ -37,27 +37,27 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UBlueprint* BP = F.Walk(Blueprint).Cast(); if (!BP) return; // Check for valid proposed name - FName InternalID = WingUtils::CheckProposedName(Dispatcher); + FName InternalID = WingUtils::CheckProposedName(Dispatcher, WingOut::Stdout); if (InternalID.IsNone()) return; TSet Names; FBlueprintEditorUtils::GetClassVariableList(BP, Names); - if (!WingUtils::FindNoDuplicateName(Names, InternalID, TEXT("variable or component"))) return; + if (!WingUtils::FindNoDuplicateName(Names, InternalID, TEXT("variable or component"), WingOut::Stdout)) return; // Parse the arguments. WingVariables Vars; - if (!Vars.InputVariables.ParseString(InputVariables)) return; + if (!Vars.InputVariables.ParseString(InputVariables, WingOut::Stdout)) return; // Add the delegate variable FEdGraphPinType DelegateType; DelegateType.PinCategory = UEdGraphSchema_K2::PC_MCDelegate; if (!FBlueprintEditorUtils::AddMemberVariable(BP, InternalID, DelegateType)) { - UWingServer::Printf(TEXT("ERROR: Failed to add event dispatcher '%s' to %s\n"), *Dispatcher, *WingUtils::FormatName(BP)); + WingOut::Stdout.Printf(TEXT("ERROR: Failed to add event dispatcher '%s' to %s\n"), *Dispatcher, *WingUtils::FormatName(BP)); return; } @@ -67,7 +67,7 @@ public: UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass()); if (!SigGraph) { - UWingServer::Printf(TEXT("ERROR: Failed to create signature graph for '%s'\n"), *Dispatcher); + WingOut::Stdout.Printf(TEXT("ERROR: Failed to create signature graph for '%s'\n"), *Dispatcher); return; } @@ -79,9 +79,9 @@ public: BP->DelegateSignatureGraphs.Add(SigGraph); // Store the function arguments - 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)); + if (!Vars.SetBackingStore(SigGraph, WingOut::Stdout)) return; + if (!Vars.Check(WingOut::Stdout)) return; + if (!Vars.Create(WingOut::Stdout)) return; + WingOut::Stdout.Printf(TEXT("Created event dispatcher %s in %s\n"), *Dispatcher, *WingUtils::FormatName(BP)); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Delete.h b/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Delete.h index 33c9b3db..63a7b766 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Delete.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/EventDispatcher_Delete.h @@ -33,13 +33,13 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UBlueprint* BP = F.Walk(Blueprint).Cast(); if (!BP) return; - FBPVariableDescription* Var = WingUtils::FindOneWithExternalID(Dispatcher, BP->NewVariables, TEXT("Dispatcher")); + FBPVariableDescription* Var = WingUtils::FindOneWithExternalID(Dispatcher, BP->NewVariables, TEXT("Dispatcher"), WingOut::Stdout); if (!Var) return; - TObjectPtr* SigGraph = WingUtils::FindOneWithExternalID(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph")); + TObjectPtr* SigGraph = WingUtils::FindOneWithExternalID(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph"), WingOut::Stdout); if (!SigGraph) return; UEdGraph* Graph = *SigGraph; @@ -51,6 +51,6 @@ public: // Remove the signature graph FBlueprintEditorUtils::RemoveGraph(BP, Graph, EGraphRemoveFlags::Recompile); - UWingServer::Printf(TEXT("Deleted event dispatcher %s from %s\n"), *Dispatcher, *WingUtils::FormatName(BP)); + WingOut::Stdout.Printf(TEXT("Deleted event dispatcher %s from %s\n"), *Dispatcher, *WingUtils::FormatName(BP)); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_ChooseMenu.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_ChooseMenu.h index 9d039ea4..67d11056 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_ChooseMenu.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_ChooseMenu.h @@ -35,7 +35,7 @@ public: private: virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraphNode* NodeObj = F.Walk(Node).Cast(); if (!NodeObj) return; @@ -49,15 +49,15 @@ private: if (WingToolMenu::Execute(Entry, Context)) { - UWingServer::Printf(TEXT("Executed: %s\n"), *LabelText); + WingOut::Stdout.Printf(TEXT("Executed: %s\n"), *LabelText); } else { - UWingServer::Printf(TEXT("ERROR: Action '%s' cannot execute (greyed out)\n"), *LabelText); + WingOut::Stdout.Printf(TEXT("ERROR: Action '%s' cannot execute (greyed out)\n"), *LabelText); } return; } - UWingServer::Printf(TEXT("ERROR: Menu item '%s' not found. Use GraphNode_ShowMenu to see available items.\n"), *Item); + WingOut::Stdout.Printf(TEXT("ERROR: Menu item '%s' not found. Use GraphNode_ShowMenu to see available items.\n"), *Item); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Create.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Create.h index f2e7876f..03e7415e 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Create.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Create.h @@ -30,6 +30,8 @@ struct FSpawnNodeEntry UPROPERTY() int32 PosY = 0; + + FWingGraphAction *Action; }; @@ -53,50 +55,40 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraph* TargetGraph = F.Walk(Graph).Cast(); if (!TargetGraph) return; int32 SuccessCount = 0; int32 TotalCount = Nodes.Array.Num(); FWingGraphActions GraphActions(TargetGraph); - - for (const TSharedPtr& NodeVal : Nodes.Array) + + // Parse the json array, turning it into an array of spawn node entries. + TArray Entries; + FSpawnNodeEntry Entry; + TArray Props = FWingProperty::GetAll(&Entry, CPF_None); + for (const TSharedPtr& Elt : Nodes.Array) { - FSpawnNodeEntry Entry; - if (!FWingProperty::PopulateFromJson(FSpawnNodeEntry::StaticStruct(), &Entry, NodeVal)) - continue; - - // Find the action by exact full name + if (!FWingProperty::PopulateFromJson(Props, *Elt, false, WingOut::Stdout)) return; TArray Results = GraphActions.Search(Entry.ActionName, 2, true); - if (Results.Num() == 0) - { - UWingServer::Printf(TEXT("ERROR: No action found matching '%s'. Use GraphNode_SearchTypes to find available actions.\n"), - *Entry.ActionName); - continue; - } - if (Results.Num() > 1) - { - UWingServer::Printf(TEXT("ERROR: More than one action matches '%s'.\n"), *Entry.ActionName); - continue; - } - - // Perform the action - UEdGraphNode* NewNode = Results[0]->Execute(FVector2D(Entry.PosX, Entry.PosY)); - if (!NewNode) - { - UWingServer::Printf(TEXT("ERROR: Execute returned null for '%s'.\n"), *Entry.ActionName); - continue; - } - - if (!NewNode->NodeGuid.IsValid()) - NewNode->CreateNewGuid(); - - UWingServer::Printf(TEXT("Spawned: %s (%s)\n"), - *WingUtils::FormatName(NewNode), *WingUtils::FormatName(NewNode->GetClass())); - SuccessCount++; + if (!WingUtils::CheckExactlyOneNamed(Results.Num(), TEXT("node type"), Entry.ActionName, WingOut::Stdout)) return; + Entry.Action = Results[0]; + Entries.Add(Entry); } - UWingServer::Printf(TEXT("Spawned %d/%d nodes.\n"), SuccessCount, TotalCount); + // Execute all. + for (const FSpawnNodeEntry &Entry : Entries) + { + UEdGraphNode* NewNode = Entry.Action->Execute(FVector2D(Entry.PosX, Entry.PosY)); + if (NewNode) + { + WingOut::Stdout.Printf(TEXT("Spawned: %s %s\n"), *Entry.ActionName, *WingUtils::FormatName(NewNode)); + } + else + { + WingOut::Stdout.Printf(TEXT("FAILED: %s\n"), *Entry.ActionName); + continue; + } + } } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Delete.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Delete.h index 6e4aa1b1..344d488a 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Delete.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Delete.h @@ -34,7 +34,7 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraphNode* FoundNode = F.Walk(Node).Cast(); if (!FoundNode) return; @@ -44,7 +44,7 @@ public: if (!FoundNode->CanUserDeleteNode()) { - UWingServer::Printf(TEXT("ERROR: Cannot delete node '%s' in graph '%s' — it is not deletable.\n"), + WingOut::Stdout.Printf(TEXT("ERROR: Cannot delete node '%s' in graph '%s' — it is not deletable.\n"), *NodeTitle, *GraphName); return; } @@ -63,6 +63,6 @@ public: Graph->RemoveNode(FoundNode); } - UWingServer::Printf(TEXT("Deleted node '%s' from graph '%s'.\n"), *NodeTitle, *GraphName); + WingOut::Stdout.Printf(TEXT("Deleted node '%s' from graph '%s'.\n"), *NodeTitle, *GraphName); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Dump.h index 4564ba72..8d1012c3 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Dump.h @@ -29,12 +29,12 @@ public: private: virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraphNode* NodeObj = F.Walk(Node).Cast(); if (!NodeObj) return; WingGraphExport Exporter(NodeObj); - UWingServer::Print(*Exporter.GetOutput()); - UWingServer::Print(Exporter.GetDetails()); + WingOut::Stdout.Print(*Exporter.GetOutput()); + WingOut::Stdout.Print(Exporter.GetDetails()); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_GetComment.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_GetComment.h index 78e20fa8..10218044 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_GetComment.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_GetComment.h @@ -29,12 +29,12 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraphNode* FoundNode = F.Walk(Node).Cast(); if (!FoundNode) return; - UWingServer::Printf(TEXT("Node: %s\n"), *WingUtils::FormatName(FoundNode)); - UWingServer::Printf(TEXT("Comment: %s\n"), *FoundNode->NodeComment); - UWingServer::Printf(TEXT("BubbleVisible: %s\n"), FoundNode->bCommentBubbleVisible ? TEXT("true") : TEXT("false")); + WingOut::Stdout.Printf(TEXT("Node: %s\n"), *WingUtils::FormatName(FoundNode)); + WingOut::Stdout.Printf(TEXT("Comment: %s\n"), *FoundNode->NodeComment); + WingOut::Stdout.Printf(TEXT("BubbleVisible: %s\n"), FoundNode->bCommentBubbleVisible ? TEXT("true") : TEXT("false")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Rename.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Rename.h index 0883ec91..981fb526 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Rename.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Rename.h @@ -33,13 +33,13 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraphNode* FoundNode = F.Walk(Node).Cast(); if (!FoundNode) return; - if (!WingUtils::CheckCanRename(FoundNode, Name)) return; + if (!WingUtils::CheckCanRename(FoundNode, Name, WingOut::Stdout)) return; FoundNode->OnRenameNode(Name); - UWingServer::Printf(TEXT("Renamed node to %s\n"), *Name); + WingOut::Stdout.Printf(TEXT("Renamed node to %s\n"), *Name); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SearchTypes.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SearchTypes.h index 984890db..57cf92a7 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SearchTypes.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SearchTypes.h @@ -39,7 +39,7 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraph* TargetGraph = F.Walk(Graph).Cast(); if (!TargetGraph) return; @@ -47,16 +47,16 @@ public: TArray Results = GraphActions.Search(Query, MaxResults, false); for (const FWingGraphAction* Action : Results) { - UWingServer::Printf(TEXT("%s\n"), *Action->Name); + WingOut::Stdout.Printf(TEXT("%s\n"), *Action->Name); } if (Results.Num() == 0) { - UWingServer::Print(TEXT("No matching node types found.\n")); + WingOut::Stdout.Print(TEXT("No matching node types found.\n")); } else if (Results.Num() >= MaxResults) { - UWingServer::Printf(TEXT("WARNING: Reached limit of %d results. You may specify MaxResults.\n"), MaxResults); + WingOut::Stdout.Printf(TEXT("WARNING: Reached limit of %d results. You may specify MaxResults.\n"), MaxResults); } } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetComment.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetComment.h index 1c3e41f7..2c30939b 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetComment.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetComment.h @@ -33,7 +33,7 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraphNode* FoundNode = F.Walk(Node).Cast(); if (!FoundNode) return; @@ -41,6 +41,6 @@ public: FoundNode->bCommentBubbleVisible = !Comment.IsEmpty(); FoundNode->bCommentBubblePinned = !Comment.IsEmpty(); - UWingServer::Printf(TEXT("Comment set on %s\n"), *WingUtils::FormatName(FoundNode)); + WingOut::Stdout.Printf(TEXT("Comment set on %s\n"), *WingUtils::FormatName(FoundNode)); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetDefaults.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetDefaults.h index 1ceab469..b9db5e5c 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetDefaults.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetDefaults.h @@ -55,7 +55,7 @@ public: void HandleK2Entry(const FSetNodeDefaultEntry& Entry, UEdGraph* GraphObj, const UEdGraphSchema_K2* K2Schema) { - WingFetcher F(GraphObj); + WingFetcher F(GraphObj, WingOut::Stdout); UEdGraphPin* Pin = F.Node(Entry.Node).Pin(Entry.Name).Cast(); if (!Pin) return; @@ -63,7 +63,7 @@ public: if (Pin->Direction != EGPD_Input) { - UWingServer::Printf(TEXT("error: %s is an output pin\n"), *WingUtils::FormatName(Pin)); + WingOut::Stdout.Printf(TEXT("error: %s is an output pin\n"), *WingUtils::FormatName(Pin)); return; } @@ -74,7 +74,7 @@ public: FString Error = K2Schema->IsPinDefaultValid(Pin, UseDefaultValue, UseDefaultObject, UseDefaultText); if (!Error.IsEmpty()) { - UWingServer::Printf(TEXT("error: %s: %s\n"), *WingUtils::FormatName(Pin), *Error); + WingOut::Stdout.Printf(TEXT("error: %s: %s\n"), *WingUtils::FormatName(Pin), *Error); return; } UWingServer::AddTouchedObject(Node); @@ -87,17 +87,17 @@ public: void HandleMaterialEntry(const FSetNodeDefaultEntry& Entry, UEdGraph* GraphObj) { - WingFetcher F(GraphObj); + WingFetcher F(GraphObj, WingOut::Stdout); UEdGraphNode* Node = F.Node(Entry.Node).Cast(); if (!Node) return; - TArray All = FWingProperty::GetDetailsMutable(Node, CPF_Edit); - FWingProperty *P = WingUtils::FindOneWithExternalID(Entry.Name, All, TEXT("Property")); + TArray All = FWingProperty::GetDetails(Node, CPF_Edit, true); + FWingProperty *P = WingUtils::FindOneWithExternalID(Entry.Name, All, TEXT("Property"), WingOut::Stdout); if (!P) return; UWingServer::AddTouchedObject(Node); - if (!P->SetText(Entry.Value)) + if (!P->SetText(Entry.Value, WingOut::Stdout)) return; } @@ -106,7 +106,7 @@ public: virtual void Handle() override { // Fetch the graph once. - WingFetcher GraphFetcher; + WingFetcher GraphFetcher(WingOut::Stdout); UEdGraph* GraphObj = GraphFetcher.Walk(Graph).Cast(); if (!GraphObj) return; @@ -116,22 +116,19 @@ public: if (!K2Schema && !MGSchema) { - UWingServer::Printf(TEXT("error: unsupported graph schema %s\n"), *Schema->GetClass()->GetName()); + WingOut::Stdout.Printf(TEXT("error: unsupported graph schema %s\n"), *Schema->GetClass()->GetName()); return; } + FSetNodeDefaultEntry Entry; + TArray Props = FWingProperty::GetAll(&Entry, CPF_None); for (const TSharedPtr& PinVal : Pins.Array) { - FSetNodeDefaultEntry Entry; - if (!FWingProperty::PopulateFromJson(FSetNodeDefaultEntry::StaticStruct(), &Entry, PinVal)) - continue; - - if (K2Schema) - HandleK2Entry(Entry, GraphObj, K2Schema); - else if (MGSchema) - HandleMaterialEntry(Entry, GraphObj); + if (!FWingProperty::PopulateFromJson(Props, *PinVal, false, WingOut::Stdout)) continue; + if (K2Schema) HandleK2Entry(Entry, GraphObj, K2Schema); + else if (MGSchema) HandleMaterialEntry(Entry, GraphObj); } - UWingServer::Printf(TEXT("Done.\n")); + WingOut::Stdout.Printf(TEXT("Done.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetPositions.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetPositions.h index 5f4edd9c..948afd5b 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetPositions.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetPositions.h @@ -4,6 +4,7 @@ #include "WingServer.h" #include "WingHandler.h" #include "WingFetcher.h" +#include "WingProperty.h" #include "WingUtils.h" #include "Engine/Blueprint.h" #include "EdGraph/EdGraphNode.h" @@ -49,26 +50,25 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraph* TargetGraph = F.Walk(Graph).Cast(); if (!TargetGraph) return; int32 SuccessCount = 0; - for (const TSharedPtr& NodeVal : Nodes.Array) + FMoveNodeEntry Entry; + TArray Props = FWingProperty::GetAll(&Entry, CPF_None); + for (const TSharedPtr& Elt : Nodes.Array) { - FMoveNodeEntry Entry; - if (!FWingProperty::PopulateFromJson(FMoveNodeEntry::StaticStruct(), &Entry, NodeVal)) continue; - - WingFetcher FN(TargetGraph); + if (!FWingProperty::PopulateFromJson(Props, *Elt, false, WingOut::Stdout)) continue; + WingFetcher FN(TargetGraph, WingOut::Stdout); UEdGraphNode* Node = FN.Node(Entry.Node).Cast(); if (!Node) continue; - Node->NodePosX = Entry.X; Node->NodePosY = Entry.Y; SuccessCount++; } - UWingServer::Printf(TEXT("Moved %d/%d nodes.\n"), SuccessCount, Nodes.Array.Num()); + WingOut::Stdout.Printf(TEXT("Moved %d/%d nodes.\n"), SuccessCount, Nodes.Array.Num()); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_ShowMenu.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_ShowMenu.h index cb46cbe7..4d093b9f 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_ShowMenu.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_ShowMenu.h @@ -31,13 +31,13 @@ public: private: virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraphNode* NodeObj = F.Walk(Node).Cast(); if (!NodeObj) return; if (Cast(NodeObj)) { - UWingServer::Printf(TEXT("Material graph nodes do not have usable context menus.")); + WingOut::Stdout.Printf(TEXT("Material graph nodes do not have usable context menus.")); return; } FToolMenuContext Context; @@ -45,8 +45,8 @@ private: for (FToolMenuEntry &Entry : Entries) { FString LabelText = Entry.Label.Get().ToString(); - UWingServer::Printf(TEXT("%s\n"), *LabelText); + WingOut::Stdout.Printf(TEXT("%s\n"), *LabelText); } - if (Entries.IsEmpty()) UWingServer::Printf(TEXT("No selectable menu entries right now.\n")); + if (Entries.IsEmpty()) WingOut::Stdout.Printf(TEXT("No selectable menu entries right now.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Connect.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Connect.h index e4294ab6..7a5ce4f8 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Connect.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Connect.h @@ -49,24 +49,25 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraph* G = F.Walk(Graph).Cast(); if (!G) return; int32 SuccessCount = 0; int32 TotalCount = Connections.Array.Num(); + FConnectPinsEntry Entry; + TArray EntryProps = FWingProperty::GetAll(&Entry, CPF_None); for (const TSharedPtr& ConnVal : Connections.Array) { - FConnectPinsEntry Entry; - if (!FWingProperty::PopulateFromJson(FConnectPinsEntry::StaticStruct(), &Entry, ConnVal)) + if (!FWingProperty::PopulateFromJson(EntryProps, *ConnVal, false, WingOut::Stdout)) continue; - WingFetcher FS(G); + WingFetcher FS(G, WingOut::Stdout); UEdGraphPin* SourcePin = FS.Walk(Entry.SourcePin).Cast(); if (!SourcePin) continue; - WingFetcher FT(G); + WingFetcher FT(G, WingOut::Stdout); UEdGraphPin* TargetPin = FT.Walk(Entry.TargetPin).Cast(); if (!TargetPin) continue; @@ -74,7 +75,7 @@ public: const FPinConnectionResponse Response = Schema->CanCreateConnection(SourcePin, TargetPin); if (Response.Response == CONNECT_RESPONSE_DISALLOW) { - UWingServer::Printf(TEXT("error: Cannot connect %s.%s to %s.%s: %s\n"), + WingOut::Stdout.Printf(TEXT("error: Cannot connect %s.%s to %s.%s: %s\n"), *WingUtils::FormatName(SourcePin->GetOwningNode()), *WingUtils::FormatName(SourcePin), *WingUtils::FormatName(TargetPin->GetOwningNode()), *WingUtils::FormatName(TargetPin), *Response.Message.ToString()); @@ -85,6 +86,6 @@ public: SuccessCount++; } - UWingServer::Printf(TEXT("Connected %d/%d pins.\n"), SuccessCount, TotalCount); + WingOut::Stdout.Printf(TEXT("Connected %d/%d pins.\n"), SuccessCount, TotalCount); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Disconnect.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Disconnect.h index 9193d264..d9becbfa 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Disconnect.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Disconnect.h @@ -49,19 +49,20 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraph* G = F.Walk(Graph).Cast(); if (!G) return; int32 SuccessCount = 0; int32 TotalDisconnected = 0; + FDisconnectPinEntry Entry; + TArray EntryProps = FWingProperty::GetAll(&Entry, CPF_None); for (const TSharedPtr& DiscVal : Disconnections.Array) { - FDisconnectPinEntry Entry; - if (!FWingProperty::PopulateFromJson(FDisconnectPinEntry::StaticStruct(), &Entry, DiscVal)) continue; + if (!FWingProperty::PopulateFromJson(EntryProps, *DiscVal, false, WingOut::Stdout)) continue; - WingFetcher FP(G); + WingFetcher FP(G, WingOut::Stdout); UEdGraphPin* Pin = FP.Walk(Entry.Pin).Cast(); if (!Pin) continue; @@ -69,13 +70,13 @@ public: if (!Entry.TargetPin.IsEmpty()) { - WingFetcher FT(G); + WingFetcher FT(G, WingOut::Stdout); UEdGraphPin* Target = FT.Walk(Entry.TargetPin).Cast(); if (!Target) continue; if (!Pin->LinkedTo.Contains(Target)) { - UWingServer::Printf(TEXT("Error: %s.%s is not connected to %s.%s\n"), + WingOut::Stdout.Printf(TEXT("Error: %s.%s is not connected to %s.%s\n"), *WingUtils::FormatName(Pin->GetOwningNode()), *WingUtils::FormatName(Pin), *WingUtils::FormatName(Target->GetOwningNode()), *WingUtils::FormatName(Target)); continue; @@ -93,14 +94,14 @@ public: } } - UWingServer::Printf(TEXT("Disconnected %d link(s) from %s.%s\n"), + WingOut::Stdout.Printf(TEXT("Disconnected %d link(s) from %s.%s\n"), DisconnectedCount, *WingUtils::FormatName(Pin->GetOwningNode()), *WingUtils::FormatName(Pin)); SuccessCount++; TotalDisconnected += DisconnectedCount; } - UWingServer::Printf(TEXT("Done: %d/%d succeeded, %d links broken.\n"), + WingOut::Stdout.Printf(TEXT("Done: %d/%d succeeded, %d links broken.\n"), SuccessCount, Disconnections.Array.Num(), TotalDisconnected); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Graph_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Graph_Dump.h index f5bbe524..30f93949 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Graph_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Graph_Dump.h @@ -36,19 +36,19 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UEdGraph *G = F.Walk(Graph).Cast(); if (!G) return; WingGraphExport Exporter(G); - UWingServer::Print(*Exporter.GetOutput()); + WingOut::Stdout.Print(*Exporter.GetOutput()); if (IncludeDetails) { - UWingServer::Print(Exporter.GetDetails()); + WingOut::Stdout.Print(Exporter.GetDetails()); } else { - UWingServer::Printf(TEXT("\nNote: use bDetails=true to see suppressed details.")); + WingOut::Stdout.Printf(TEXT("\nNote: use bDetails=true to see suppressed details.")); } } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_ClearParameter.h b/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_ClearParameter.h index bf218336..54be60cf 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_ClearParameter.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_ClearParameter.h @@ -40,13 +40,13 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UMaterialInstanceConstant* MI = F.Asset(MaterialInstance).Cast(); if (!MI) return; // Parse the association string. EMaterialParameterAssociation Association; - if (!WingMaterialParameter::ParseMaterialParameterAssociation(ParameterAssociation, Association)) + if (!WingMaterialParameter::ParseMaterialParameterAssociation(ParameterAssociation, Association, WingOut::Stdout)) return; FMaterialParameterInfo ParamID(*Parameter, Association, ParameterLayer); @@ -68,12 +68,12 @@ public: if (Removed == 0) { - UWingServer::Printf(TEXT("No override found for parameter '%s' (association=%s layer=%d) on %s"), + WingOut::Stdout.Printf(TEXT("No override found for parameter '%s' (association=%s layer=%d) on %s"), *Parameter, *ParameterAssociation, ParameterLayer, *WingUtils::FormatName(MI)); return; } - UWingServer::Printf(TEXT("Cleared override for '%s' on %s\n"), + WingOut::Stdout.Printf(TEXT("Cleared override for '%s' on %s\n"), *Parameter, *WingUtils::FormatName(MI)); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_DumpParameters.h b/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_DumpParameters.h index 3adb8190..0874c02d 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_DumpParameters.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_DumpParameters.h @@ -31,7 +31,7 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UMaterialInstanceConstant* MI = F.Asset(MaterialInstance).Cast(); if (!MI) return; @@ -42,7 +42,7 @@ public: for (auto& [Info, Meta] : AllParams) { if (!Meta.bOverride) continue; - if (!bHasOverrides) { UWingServer::Print(TEXT("\nOverridden Parameters:\n")); bHasOverrides = true; } + if (!bHasOverrides) { WingOut::Stdout.Print(TEXT("\nOverridden Parameters:\n")); bHasOverrides = true; } WingMaterialParameter::FormatMaterialParameter(Info, Meta); } @@ -51,7 +51,7 @@ public: for (auto& [Info, Meta] : AllParams) { if (Meta.bOverride) continue; - if (!bHasInherited) { UWingServer::Print(TEXT("\nInherited Parameters (not overridden):\n")); bHasInherited = true; } + if (!bHasInherited) { WingOut::Stdout.Print(TEXT("\nInherited Parameters (not overridden):\n")); bHasInherited = true; } WingMaterialParameter::FormatMaterialParameter(Info, Meta); } } diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_SetParameter.h b/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_SetParameter.h index 808548a7..9a715e7b 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_SetParameter.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/MaterialInstance_SetParameter.h @@ -44,13 +44,13 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UMaterialInstanceConstant* MI = F.Asset(MaterialInstance).Cast(); if (!MI) return; // Parse the association string. EMaterialParameterAssociation Association; - if (!WingMaterialParameter::ParseMaterialParameterAssociation(ParameterAssociation, Association)) + if (!WingMaterialParameter::ParseMaterialParameterAssociation(ParameterAssociation, Association, WingOut::Stdout)) return; // Build the parameter ID to look up. @@ -61,13 +61,13 @@ public: FMaterialParameterMetadata* Found = AllParams.Find(ParamID); if (!Found) { - UWingServer::Printf(TEXT("No parameter named '%s' with association=%s layer=%d"), + WingOut::Stdout.Printf(TEXT("No parameter named '%s' with association=%s layer=%d"), *Parameter, *ParameterAssociation, ParameterLayer); return; } if (Found->PrimitiveDataIndex != INDEX_NONE) { - UWingServer::Printf(TEXT("Parameter '%s' uses custom primitive data and cannot be set on a material instance"), *Parameter); + WingOut::Stdout.Printf(TEXT("Parameter '%s' uses custom primitive data and cannot be set on a material instance"), *Parameter); return; } @@ -80,7 +80,7 @@ public: float ScalarValue; if (!FDefaultValueHelper::ParseFloat(Value, ScalarValue)) { - UWingServer::Printf(TEXT("Failed to parse '%s' as a float"), *Value); + WingOut::Stdout.Printf(TEXT("Failed to parse '%s' as a float"), *Value); return; } MI->SetScalarParameterValueEditorOnly(ParamID, ScalarValue); @@ -91,17 +91,17 @@ public: FLinearColor Color; if (!Color.InitFromString(Value)) { - UWingServer::Printf(TEXT("Failed to parse '%s' as a color/vector (expected format: '(R=1,G=0,B=0,A=1)')"), *Value); + WingOut::Stdout.Printf(TEXT("Failed to parse '%s' as a color/vector (expected format: '(R=1,G=0,B=0,A=1)')"), *Value); return; } MI->SetVectorParameterValueEditorOnly(ParamID, Color); break; } default: - UWingServer::Printf(TEXT("Parameters of type %d (see EMaterialParameterType) are not implemented"), (int)Type); + WingOut::Stdout.Printf(TEXT("Parameters of type %d (see EMaterialParameterType) are not implemented"), (int)Type); return; } - UWingServer::Printf(TEXT("Set '%s' = %s on %s\n"), + WingOut::Stdout.Printf(TEXT("Set '%s' = %s on %s\n"), *Parameter, *Value, *WingUtils::FormatName(MI)); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Material_Compile.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Material_Compile.h index a027d910..bf7ff3e3 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Material_Compile.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Material_Compile.h @@ -30,7 +30,7 @@ public: virtual void Handle() override { // Load material - WingFetcher F; + WingFetcher F(WingOut::Stdout); UMaterial* MaterialObj = F.Asset(Material).Cast(); if (!MaterialObj) return; @@ -48,14 +48,14 @@ public: if (Errors.IsEmpty()) { - UWingServer::Printf(TEXT("%s compiled successfully.\n"), *WingUtils::FormatName(MaterialObj)); + WingOut::Stdout.Printf(TEXT("%s compiled successfully.\n"), *WingUtils::FormatName(MaterialObj)); } else { - UWingServer::Printf(TEXT("%s compiled with %d error(s):\n"), *WingUtils::FormatName(MaterialObj), Errors.Num()); + WingOut::Stdout.Printf(TEXT("%s compiled with %d error(s):\n"), *WingUtils::FormatName(MaterialObj), Errors.Num()); for (const FString& Err : Errors) { - UWingServer::Printf(TEXT(" %s\n"), *Err); + WingOut::Stdout.Printf(TEXT(" %s\n"), *Err); } } } diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Material_DumpParameters.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Material_DumpParameters.h index d679edcb..44ccc05f 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Material_DumpParameters.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Material_DumpParameters.h @@ -30,7 +30,7 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UMaterial* Mat = F.Asset(Material).Cast(); if (!Mat) return; @@ -40,6 +40,6 @@ public: { WingMaterialParameter::FormatMaterialParameter(Info, Meta); } - if (AllParams.IsEmpty()) UWingServer::Printf(TEXT("No material parameters.\n")); + if (AllParams.IsEmpty()) WingOut::Stdout.Printf(TEXT("No material parameters.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/ShowCommands.h b/Plugins/UEWingman/Source/UEWingman/Handlers/ShowCommands.h index 4530f175..418828fd 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/ShowCommands.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/ShowCommands.h @@ -46,7 +46,7 @@ public: if (Group != PrevGroup) { if (!PrevGroup.IsEmpty()) - UWingServer::Print(TEXT("\n")); + WingOut::Stdout.Print(TEXT("\n")); PrevGroup = Group; } } @@ -62,7 +62,7 @@ public: } if (Kind == EWingHandlerKind::Normal) { - UWingServer::Printf(TEXT( + WingOut::Stdout.Printf(TEXT( "\n" "You can also use ShowCommands with Kind=Create to see commands that create new assets.\n" "\n")); diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/SysInfo_Factories.h b/Plugins/UEWingman/Source/UEWingman/Handlers/SysInfo_Factories.h index 7304c012..c9caabe2 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/SysInfo_Factories.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/SysInfo_Factories.h @@ -51,7 +51,7 @@ public: Results.Sort(); for (const FString &Line : Results) { - UWingServer::Printf(TEXT("%s\n"), *Line); + WingOut::Stdout.Printf(TEXT("%s\n"), *Line); } } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Sanitizer.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Sanitizer.h index 9e92e381..db24a2bf 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Sanitizer.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Sanitizer.h @@ -27,6 +27,6 @@ public: } virtual void Handle() override { - UWingServer::Printf(TEXT("%s\n"), *WingTokenizer::ExternalizeID(FName(Input))); + WingOut::Stdout.Printf(TEXT("%s\n"), *WingTokenizer::ExternalizeID(FName(Input))); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Tokenizer.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Tokenizer.h index 864864ca..e49de826 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Tokenizer.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Tokenizer.h @@ -28,6 +28,6 @@ public: virtual void Handle() override { WingTokenizer T(Input); - T.PrintEverything(UWingServer::GetPrintBuffer()); + T.PrintEverything(WingOut::StdoutBuffer); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Test_TypeToText.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Test_TypeToText.h index 002bc216..5f638576 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Test_TypeToText.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Test_TypeToText.h @@ -33,22 +33,22 @@ public: Require.Blueprintable = false; Require.AllowContainer = true; - bool OK = UWingTypes::TextToType(Input, PinType, Require); + bool OK = UWingTypes::TextToType(Input, PinType, Require, WingOut::Stdout); - auto& Out = UWingServer::GetPrintBuffer(); - Out.Appendf(TEXT("ParseResult: %s\n"), OK ? TEXT("OK") : TEXT("FAILED")); - Out.Appendf(TEXT("PinCategory: %s\n"), *PinType.PinCategory.ToString()); - Out.Appendf(TEXT("PinSubCategory: %s\n"), *PinType.PinSubCategory.ToString()); - Out.Appendf(TEXT("PinSubCategoryObject: %s\n"), + auto& Out = WingOut::Stdout; + Out.Printf(TEXT("ParseResult: %s\n"), OK ? TEXT("OK") : TEXT("FAILED")); + Out.Printf(TEXT("PinCategory: %s\n"), *PinType.PinCategory.ToString()); + Out.Printf(TEXT("PinSubCategory: %s\n"), *PinType.PinSubCategory.ToString()); + Out.Printf(TEXT("PinSubCategoryObject: %s\n"), PinType.PinSubCategoryObject.IsValid() ? *PinType.PinSubCategoryObject->GetPathName() : TEXT("(none)")); - Out.Appendf(TEXT("ContainerType: %d\n"), (int32)PinType.ContainerType); + Out.Printf(TEXT("ContainerType: %d\n"), (int32)PinType.ContainerType); if (PinType.IsMap()) { - Out.Appendf(TEXT("ValueTerminalCategory: %s\n"), *PinType.PinValueType.TerminalCategory.ToString()); - Out.Appendf(TEXT("ValueTerminalSubCategory: %s\n"), *PinType.PinValueType.TerminalSubCategory.ToString()); - Out.Appendf(TEXT("ValueTerminalSubCategoryObject: %s\n"), + Out.Printf(TEXT("ValueTerminalCategory: %s\n"), *PinType.PinValueType.TerminalCategory.ToString()); + Out.Printf(TEXT("ValueTerminalSubCategory: %s\n"), *PinType.PinValueType.TerminalSubCategory.ToString()); + Out.Printf(TEXT("ValueTerminalSubCategoryObject: %s\n"), PinType.PinValueType.TerminalSubCategoryObject.IsValid() ? *PinType.PinValueType.TerminalSubCategoryObject->GetPathName() : TEXT("(none)")); @@ -57,7 +57,7 @@ public: if (OK) { FString RoundTrip = UWingTypes::TypeToText(PinType); - Out.Appendf(TEXT("TypeToText: %s\n"), RoundTrip.IsEmpty() ? TEXT("(empty)") : *RoundTrip); + Out.Printf(TEXT("TypeToText: %s\n"), RoundTrip.IsEmpty() ? TEXT("(empty)") : *RoundTrip); } } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Unsanitize.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Unsanitize.h index 04a607e8..15eff997 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Unsanitize.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Test_Unsanitize.h @@ -31,11 +31,11 @@ public: FName Result = WingTokenizer::TryInternalizeID(Input, Error); if (!Error.IsEmpty()) { - UWingServer::Printf(TEXT("Error: %s\n"), *Error); + WingOut::Stdout.Printf(TEXT("Error: %s\n"), *Error); } if (!Result.IsNone()) { - UWingServer::Printf(TEXT("Result: %s\n"), *Result.ToString()); + WingOut::Stdout.Printf(TEXT("Result: %s\n"), *Result.ToString()); } } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/TypeName_Search.h b/Plugins/UEWingman/Source/UEWingman/Handlers/TypeName_Search.h index 9a24e30b..5d9b4c22 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/TypeName_Search.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/TypeName_Search.h @@ -94,13 +94,13 @@ public: { const UWingTypes::Info& Info = *Matches[i]; if (IsProjectDefined(Info)) - UWingServer::Printf(TEXT("%s (%s, User-Defined)\n"), *Info.Short, *BroadCategory(Info)); + WingOut::Stdout.Printf(TEXT("%s (%s, User-Defined)\n"), *Info.Short, *BroadCategory(Info)); else - UWingServer::Printf(TEXT("%s (%s)\n"), *Info.Short, *BroadCategory(Info)); + WingOut::Stdout.Printf(TEXT("%s (%s)\n"), *Info.Short, *BroadCategory(Info)); } if (Count >= Limit) { - UWingServer::Printf(TEXT("Search limit reached, raise it with Limit=\n")); + WingOut::Stdout.Printf(TEXT("Search limit reached, raise it with Limit=\n")); } } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Create.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Create.h index 9837248b..b0d00dc2 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Create.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Create.h @@ -40,18 +40,18 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UObject* Obj = F.Walk(Object).Cast(); if (!Obj) return; 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; - if (!Vars.Check()) return; - if (!Vars.Create()) return; - UWingServer::Printf(TEXT("Success.\n")); + if (!Vars.SetBackingStore(Obj, WingOut::Stdout)) return; + if (!Vars.BlueprintVariables.ParseString(BlueprintVariables, WingOut::Stdout)) return; + if (!Vars.InputVariables.ParseString(InputVariables, WingOut::Stdout)) return; + if (!Vars.OutputVariables.ParseString(OutputVariables, WingOut::Stdout)) return; + if (!Vars.LocalVariables.ParseString(LocalVariables, WingOut::Stdout)) return; + if (!Vars.Check(WingOut::Stdout)) return; + if (!Vars.Create(WingOut::Stdout)) return; + WingOut::Stdout.Printf(TEXT("Success.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Dump.h index 486e45dd..9cbb6771 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Dump.h @@ -29,13 +29,13 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UObject* Obj = F.Walk(Object).Cast(); if (!Obj) return; WingVariables Vars; - if (!Vars.SetBackingStore(Obj)) return; - Vars.Load(); - Vars.Print(UWingServer::GetPrintBuffer()); + if (!Vars.SetBackingStore(Obj, WingOut::Stdout)) return; + Vars.Load(WingOut::Stdout); + Vars.Print(WingOut::StdoutBuffer); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Modify.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Modify.h index fcfeecc7..28256169 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Modify.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Modify.h @@ -41,18 +41,18 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UObject* Obj = F.Walk(Object).Cast(); if (!Obj) return; 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; - if (!Vars.Check()) return; - if (!Vars.Modify()) return; - UWingServer::Printf(TEXT("Success.\n")); + if (!Vars.SetBackingStore(Obj, WingOut::Stdout)) return; + if (!Vars.BlueprintVariables.ParseString(BlueprintVariables, WingOut::Stdout)) return; + if (!Vars.InputVariables.ParseString(InputVariables, WingOut::Stdout)) return; + if (!Vars.OutputVariables.ParseString(OutputVariables, WingOut::Stdout)) return; + if (!Vars.LocalVariables.ParseString(LocalVariables, WingOut::Stdout)) return; + if (!Vars.Check(WingOut::Stdout)) return; + if (!Vars.Modify(WingOut::Stdout)) return; + WingOut::Stdout.Printf(TEXT("Success.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Remove.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Remove.h index 49f643b9..a5249642 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Remove.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Variables_Remove.h @@ -40,17 +40,17 @@ public: } virtual void Handle() override { - WingFetcher F; + WingFetcher F(WingOut::Stdout); UObject* Obj = F.Walk(Object).Cast(); if (!Obj) return; 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; - if (!Vars.Remove()) return; - UWingServer::Printf(TEXT("Success.\n")); + if (!Vars.SetBackingStore(Obj, WingOut::Stdout)) return; + if (!Vars.BlueprintVariables.ParseNamesString(BlueprintVariables, WingOut::Stdout)) return; + if (!Vars.InputVariables.ParseNamesString(InputVariables, WingOut::Stdout)) return; + if (!Vars.OutputVariables.ParseNamesString(OutputVariables, WingOut::Stdout)) return; + if (!Vars.LocalVariables.ParseNamesString(LocalVariables, WingOut::Stdout)) return; + if (!Vars.Remove(WingOut::Stdout)) return; + WingOut::Stdout.Printf(TEXT("Success.\n")); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Create.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Create.h index 35ed8ec8..b1ee837c 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Create.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Create.h @@ -48,7 +48,7 @@ public: virtual void Handle() override { // Fetch the widget blueprint. - WingFetcher F; + WingFetcher F(WingOut::Stdout); UWidgetBlueprint* BP = F.Walk(Blueprint).Cast(); if (!BP) return; UWidgetTree* Tree = BP->WidgetTree; @@ -56,18 +56,18 @@ public: // Resolve the widget type. WingWidgets WidgetMenu; TArray TypeResults = WidgetMenu.Search(Type, 2, true); - if (!WingUtils::CheckExactlyOneNamed(TypeResults.Num(), TEXT("Widget type"), Type)) return; + if (!WingUtils::CheckExactlyOneNamed(TypeResults.Num(), TEXT("Widget type"), Type, WingOut::Stdout)) return; // Load the widget's class. UClass* WidgetClass = TypeResults[0].Class.LoadSynchronous(); if (!WidgetClass) { - UWingServer::Printf(TEXT("ERROR: Failed to load widget class for '%s'\n"), *Type); + WingOut::Stdout.Printf(TEXT("ERROR: Failed to load widget class for '%s'\n"), *Type); return; } // Validate the proposed name. - FName InternalID = WingUtils::CheckProposedName(Name); + FName InternalID = WingUtils::CheckProposedName(Name, WingOut::Stdout); if (InternalID.IsNone()) return; // Check that the name is unique among existing widgets. @@ -75,23 +75,23 @@ public: Tree->GetAllWidgets(AllWidgets); TSet Names; FBlueprintEditorUtils::GetClassVariableList(BP, Names); - if (!WingUtils::FindNoDuplicateNames(Names, AllWidgets, TEXT("widget or variable"))) return; - if (!WingUtils::FindNoDuplicateName(Names, InternalID, TEXT("widget or variable"))) return; + if (!WingUtils::FindNoDuplicateNames(Names, AllWidgets, TEXT("widget or variable"), WingOut::Stdout)) return; + if (!WingUtils::FindNoDuplicateName(Names, InternalID, TEXT("widget or variable"), WingOut::Stdout)) return; // If a parent is specified, find it and verify it's a panel. UPanelWidget* ParentPanel = nullptr; if (!Parent.IsEmpty()) { - UWidget* ParentWidget = WingUtils::FindOneWithExternalID(Parent, AllWidgets, TEXT("Widget")); + UWidget* ParentWidget = WingUtils::FindOneWithExternalID(Parent, AllWidgets, TEXT("Widget"), WingOut::Stdout); if (!ParentWidget) return; - if (!WingWidgets::CheckCanBeParent(ParentWidget)) return; + if (!WingWidgets::CheckCanBeParent(ParentWidget, WingOut::Stdout)) return; ParentPanel = Cast(ParentWidget); } else { if (Tree->RootWidget != nullptr) { - UWingServer::Printf(TEXT("ERROR: Widget tree already has a root widget. Specify a Parent.\n")); + WingOut::Stdout.Printf(TEXT("ERROR: Widget tree already has a root widget. Specify a Parent.\n")); return; } } @@ -105,7 +105,7 @@ public: if (!NewWidget) { - UWingServer::Printf(TEXT("ERROR: Failed to create widget\n")); + WingOut::Stdout.Printf(TEXT("ERROR: Failed to create widget\n")); return; } @@ -123,6 +123,6 @@ public: Tree->RootWidget = NewWidget; } - UWingServer::Printf(TEXT("Created widget '%s' of type '%s'\n"), *Name, *Type); + WingOut::Stdout.Printf(TEXT("Created widget '%s' of type '%s'\n"), *Name, *Type); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Delete.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Delete.h index 9af46ad2..8613929f 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Delete.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Delete.h @@ -34,7 +34,7 @@ public: virtual void Handle() override { // Walk to the widget. - WingFetcher F; + WingFetcher F(WingOut::Stdout); UWidget* TargetWidget = F.Walk(Widget).Cast(); if (!TargetWidget) return; @@ -42,7 +42,7 @@ public: UWidgetBlueprint* BP = TargetWidget->GetTypedOuter(); if (!BP) { - UWingServer::Printf(TEXT("ERROR: Could not find owning WidgetBlueprint\n")); + WingOut::Stdout.Printf(TEXT("ERROR: Could not find owning WidgetBlueprint\n")); return; } UWidgetTree* Tree = BP->WidgetTree; @@ -52,7 +52,7 @@ public: { if (Panel->GetChildrenCount() > 0) { - UWingServer::Printf(TEXT("ERROR: Widget '%s' has %d children. Remove them first.\n"), + WingOut::Stdout.Printf(TEXT("ERROR: Widget '%s' has %d children. Remove them first.\n"), *WingUtils::FormatName(TargetWidget), Panel->GetChildrenCount()); return; } @@ -80,6 +80,6 @@ public: // Rename to transient package to avoid name conflicts with future widgets. TargetWidget->Rename(nullptr, GetTransientPackage()); - UWingServer::Printf(TEXT("Deleted widget '%s'\n"), *WidgetName); + WingOut::Stdout.Printf(TEXT("Deleted widget '%s'\n"), *WidgetName); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Reparent.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Reparent.h index f7dbf523..f5302e30 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Reparent.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_Reparent.h @@ -36,7 +36,7 @@ public: virtual void Handle() override { // Walk to the widget. - WingFetcher F; + WingFetcher F(WingOut::Stdout); UWidget* TargetWidget = F.Walk(Widget).Cast(); if (!TargetWidget) return; @@ -44,7 +44,7 @@ public: UWidgetBlueprint* BP = TargetWidget->GetTypedOuter(); if (!BP) { - UWingServer::Printf(TEXT("ERROR: Could not find owning WidgetBlueprint\n")); + WingOut::Stdout.Printf(TEXT("ERROR: Could not find owning WidgetBlueprint\n")); return; } UWidgetTree* Tree = BP->WidgetTree; @@ -56,9 +56,9 @@ public: FString WidgetName = WingUtils::FormatName(TargetWidget); // Find the new parent and verify it's a panel with room. - UWidget* ParentWidget = WingUtils::FindOneWithExternalID(Parent, AllWidgets, TEXT("Widget")); + UWidget* ParentWidget = WingUtils::FindOneWithExternalID(Parent, AllWidgets, TEXT("Widget"), WingOut::Stdout); if (!ParentWidget) return; - if (!WingWidgets::CheckCanBeParent(ParentWidget)) return; + if (!WingWidgets::CheckCanBeParent(ParentWidget, WingOut::Stdout)) return; UPanelWidget* ParentPanel = Cast(ParentWidget); // Check for circular reparenting. @@ -66,7 +66,7 @@ public: { if (Ancestor == TargetWidget) { - UWingServer::Printf(TEXT("ERROR: Cannot reparent '%s' under itself\n"), *WidgetName); + WingOut::Stdout.Printf(TEXT("ERROR: Cannot reparent '%s' under itself\n"), *WidgetName); return; } } @@ -77,6 +77,6 @@ public: // Add to new parent. ParentPanel->AddChild(TargetWidget); - UWingServer::Printf(TEXT("Reparented '%s' under '%s'\n"), *WidgetName, *Parent); + WingOut::Stdout.Printf(TEXT("Reparented '%s' under '%s'\n"), *WidgetName, *Parent); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_SearchTypes.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_SearchTypes.h index 29c0213f..bd6229f8 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_SearchTypes.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Widget_SearchTypes.h @@ -35,16 +35,16 @@ public: TArray Results = Widgets.Search(Query, MaxResults, false); for (const WingWidgets::Type& Entry : Results) { - UWingServer::Printf(TEXT("%s\n"), *Entry.MenuName); + WingOut::Stdout.Printf(TEXT("%s\n"), *Entry.MenuName); } if (Results.Num() == 0) { - UWingServer::Print(TEXT("No matching widget types found.\n")); + WingOut::Stdout.Print(TEXT("No matching widget types found.\n")); } else if (Results.Num() >= MaxResults) { - UWingServer::Printf(TEXT("WARNING: Reached limit of %d results. You may specify MaxResults.\n"), MaxResults); + WingOut::Stdout.Printf(TEXT("WARNING: Reached limit of %d results. You may specify MaxResults.\n"), MaxResults); } } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingActorComponent.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingActorComponent.cpp index 67370aaf..f0b4a554 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingActorComponent.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingActorComponent.cpp @@ -40,77 +40,77 @@ UWingComponentReference::FoundComponent UWingComponentReference::FindComponent(U return Result; } -bool UWingComponentReference::CheckExists(UWingComponentReference::FoundComponent FC) +bool UWingComponentReference::CheckExists(UWingComponentReference::FoundComponent FC, WingOut Errors) { if ((FC.SCS == nullptr) && (FC.Native == nullptr)) { - UWingServer::Printf(TEXT("Cannot find component: %s\n"), *WingUtils::ExternalizeID(FC.Name)); + Errors.Printf(TEXT("Cannot find component: %s\n"), *WingUtils::ExternalizeID(FC.Name)); return false; } return true; } -bool UWingComponentReference::CheckValidParent(UWingComponentReference::FoundComponent FC) +bool UWingComponentReference::CheckValidParent(UWingComponentReference::FoundComponent FC, WingOut Errors) { if (FC.SCS && FC.Native) { - UWingServer::Printf(TEXT("Weirdness, two components named %s\n"), + Errors.Printf(TEXT("Weirdness, two components named %s\n"), *WingUtils::ExternalizeID(FC.Name)); return false; } if ((FC.SCS == nullptr) && (FC.Native == nullptr)) { - UWingServer::Printf(TEXT("No such parent component: %s\n"), + Errors.Printf(TEXT("No such parent component: %s\n"), *WingUtils::ExternalizeID(FC.Name)); return false; } if (FC.Native && (!Cast(FC.Native))) { - UWingServer::Printf(TEXT("Not a SceneComponent, so cannot be parent: %s\n"), + Errors.Printf(TEXT("Not a SceneComponent, so cannot be parent: %s\n"), *WingUtils::ExternalizeID(FC.Name)); return false; } return true; } -bool UWingComponentReference::CheckNoSuchComponent(FoundComponent FC) +bool UWingComponentReference::CheckNoSuchComponent(FoundComponent FC, WingOut Errors) { if (FC.SCS || FC.Native) { - UWingServer::Printf(TEXT("A component named %s already exists"), + Errors.Printf(TEXT("A component named %s already exists"), *WingUtils::ExternalizeID(FC.Name)); return false; } return true; } -bool UWingComponentReference::CheckNotNative(FoundComponent FC, const TCHAR *Action) +bool UWingComponentReference::CheckNotNative(FoundComponent FC, const TCHAR *Action, WingOut Errors) { if (FC.Native != nullptr) { - UWingServer::Printf(TEXT("Component %s is native, cannot %s native components"), + Errors.Printf(TEXT("Component %s is native, cannot %s native components"), *WingUtils::ExternalizeID(FC.Name), Action); return false; } return true; } -bool UWingComponentReference::CheckOwnedByBlueprint(FoundComponent FC, UBlueprint *BP) +bool UWingComponentReference::CheckOwnedByBlueprint(FoundComponent FC, UBlueprint *BP, WingOut Errors) { if ((FC.SCS == nullptr) || (FC.SCS->GetSCS() != BP->SimpleConstructionScript)) { - UWingServer::Printf(TEXT("Component %s belongs to blueprint %s, edit that blueprint instead"), + Errors.Printf(TEXT("Component %s belongs to blueprint %s, edit that blueprint instead"), *WingUtils::ExternalizeID(FC.Name), *WingUtils::FormatName(FC.SCS->GetSCS()->GetBlueprint())); return false; } return true; } -bool UWingComponentReference::CheckValidComponentClass(UClass *Class) +bool UWingComponentReference::CheckValidComponentClass(UClass *Class, WingOut Errors) { if (!Class->IsChildOf(UActorComponent::StaticClass())) { - UWingServer::Printf(TEXT("Class does not derive from ActorComponent: %s\n"), + Errors.Printf(TEXT("Class does not derive from ActorComponent: %s\n"), *WingUtils::FormatName(Class)); return false; } @@ -139,26 +139,26 @@ void UWingComponentReference::AddChildNode(UBlueprint *BP, USCS_Node *NewNode, F } } -bool UWingComponentReference::AddComponent(UBlueprint *BP, UClass *Class, UWingComponentReference *Parent, FName Name) +bool UWingComponentReference::AddComponent(UBlueprint *BP, UClass *Class, UWingComponentReference *Parent, FName Name, WingOut Errors) { TSet Names; FBlueprintEditorUtils::GetClassVariableList(BP, Names); if (Names.Contains(Name)) { - UWingServer::Printf(TEXT("There is already a variable or component named %s in %s.\n"), + Errors.Printf(TEXT("There is already a variable or component named %s in %s.\n"), *WingUtils::ExternalizeID(Name), *WingUtils::FormatName(Class)); return false; } FoundComponent ExistingComponent = FindComponent(BP, Name); - if (!CheckNoSuchComponent(ExistingComponent)) return false; + if (!CheckNoSuchComponent(ExistingComponent, Errors)) return false; FoundComponent ParentComponent = FindComponent(BP, Parent->VariableName); - if (!CheckValidParent(ParentComponent)) return false; - if (!CheckValidComponentClass(Class)) return false; + if (!CheckValidParent(ParentComponent, Errors)) return false; + if (!CheckValidComponentClass(Class, Errors)) return false; USCS_Node *NewNode = BP->SimpleConstructionScript->CreateNode(Class, Name); if (NewNode == nullptr) { - UWingServer::Printf(TEXT("Could not create new component %s of class %s, unknown reason.\n"), + Errors.Printf(TEXT("Could not create new component %s of class %s, unknown reason.\n"), *WingUtils::ExternalizeID(Name), *WingUtils::FormatName(Class)); return false; } @@ -167,18 +167,18 @@ bool UWingComponentReference::AddComponent(UBlueprint *BP, UClass *Class, UWingC return true; } -bool UWingComponentReference::ReparentComponent(UWingComponentReference *Parent) +bool UWingComponentReference::ReparentComponent(UWingComponentReference *Parent, WingOut Errors) { FoundComponent ParentComponent = FindComponent(BP, Parent->VariableName); - if (!CheckValidParent(ParentComponent)) return false; + if (!CheckValidParent(ParentComponent, Errors)) return false; FoundComponent ThisComponent = FindComponent(BP, VariableName); - if (!CheckExists(ThisComponent)) return false; - if (!CheckNotNative(ThisComponent, TEXT("reparent"))) return false; - if (!CheckOwnedByBlueprint(ThisComponent, BP)) return false; + if (!CheckExists(ThisComponent, Errors)) return false; + if (!CheckNotNative(ThisComponent, TEXT("reparent"), Errors)) return false; + if (!CheckOwnedByBlueprint(ThisComponent, BP, Errors)) return false; if (ParentComponent.SCS && ParentComponent.SCS->IsChildOf(ThisComponent.SCS)) { - UWingServer::Printf(TEXT("Cannot parent a component to itself or its own child.")); + Errors.Printf(TEXT("Cannot parent a component to itself or its own child.")); return false; } @@ -187,12 +187,12 @@ bool UWingComponentReference::ReparentComponent(UWingComponentReference *Parent) return true; } -bool UWingComponentReference::DeleteComponent() +bool UWingComponentReference::DeleteComponent(WingOut Errors) { FoundComponent ThisComponent = FindComponent(BP, VariableName); - if (!CheckExists(ThisComponent)) return false; - if (!CheckNotNative(ThisComponent, TEXT("delete"))) return false; - if (!CheckOwnedByBlueprint(ThisComponent, BP)) return false; + if (!CheckExists(ThisComponent, Errors)) return false; + if (!CheckNotNative(ThisComponent, TEXT("delete"), Errors)) return false; + if (!CheckOwnedByBlueprint(ThisComponent, BP, Errors)) return false; BP->SimpleConstructionScript->RemoveNodeAndPromoteChildren(ThisComponent.SCS); return true; } diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingFactories.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingFactories.cpp index 77966580..1cbf035f 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingFactories.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingFactories.cpp @@ -5,26 +5,26 @@ #include "AssetRegistry/AssetRegistryModule.h" #include "Kismet2/EnumEditorUtils.h" -bool WingFactories::CheckNewAssetPath(const FString& Path) +bool WingFactories::CheckNewAssetPath(const FString& Path, WingOut Errors) { if (UPackageTools::SanitizePackageName(Path) != Path) { - UWingServer::Printf(TEXT("ERROR: Package path '%s' is not a valid package name\n"), *Path); + Errors.Printf(TEXT("ERROR: Package path '%s' is not a valid package name\n"), *Path); return false; } if (!FPackageName::IsValidTextForLongPackageName(Path)) { - UWingServer::Printf(TEXT("ERROR: Package path '%s' is not a valid package name\n"), *Path); + Errors.Printf(TEXT("ERROR: Package path '%s' is not a valid package name\n"), *Path); return false; } if (!Path.StartsWith(TEXT("/Game"))) { - UWingServer::Printf(TEXT("ERROR: Package path '%s' must start with '/Game'\n"), *Path); + Errors.Printf(TEXT("ERROR: Package path '%s' must start with '/Game'\n"), *Path); return false; } if (FindObject(nullptr, *Path)) { - UWingServer::Printf(TEXT("ERROR: An asset already exists at '%s'\n"), *Path); + Errors.Printf(TEXT("ERROR: An asset already exists at '%s'\n"), *Path); return false; } return true; @@ -38,24 +38,24 @@ bool WingFactories::IsBlacklisted(UClass* FactoryClass) return false; } -UObject* WingFactories::CreateAsset(const FString& Path, UFactory* Factory) +UObject* WingFactories::CreateAsset(const FString& Path, UFactory* Factory, WingOut Errors) { // Check the blacklist. if (IsBlacklisted(Factory->GetClass())) { - UWingServer::Printf(TEXT("ERROR: Factory '%s' is blacklisted\n"), *Factory->GetClass()->GetName()); + Errors.Printf(TEXT("ERROR: Factory '%s' is blacklisted\n"), *Factory->GetClass()->GetName()); return nullptr; } // Validate the path, and that there's not already something there. - if (!CheckNewAssetPath(Path)) return nullptr; + if (!CheckNewAssetPath(Path, Errors)) return nullptr; FName Name = FName(FPackageName::GetShortName(Path)); // Create the package. UPackage *Package = CreatePackage(*Path); if (!Package) { - UWingServer::Printf(TEXT("ERROR: Failed to create package at '%s'\n"), *Path); + Errors.Printf(TEXT("ERROR: Failed to create package at '%s'\n"), *Path); return nullptr; } @@ -82,7 +82,7 @@ UObject* WingFactories::CreateAsset(const FString& Path, UFactory* Factory) } else { - UWingServer::Printf(TEXT("ERROR: Factory '%s' failed to create an object\n"), *Factory->GetClass()->GetName()); + Errors.Printf(TEXT("ERROR: Factory '%s' failed to create an object\n"), *Factory->GetClass()->GetName()); Package->ClearDirtyFlag(); Package->MarkAsGarbage(); return nullptr; @@ -109,7 +109,7 @@ UObject* UEnumFactoryWing::FactoryCreateNew(UClass* Class, UObject* InParent, FN { if (!FEnumEditorUtils::IsNameAvailebleForUserDefinedEnum(Name)) { - UWingServer::Printf(TEXT("ERROR: Enum name is already taken: %s\n"), *Name.ToString()); + WingOut::Stdout.Printf(TEXT("ERROR: Enum name is already taken: %s\n"), *Name.ToString()); return nullptr; } return FEnumEditorUtils::CreateUserDefinedEnum(InParent, Name, Flags); diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp index cdc8b4a5..ecd46964 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp @@ -59,11 +59,11 @@ WingFetcher& WingFetcher::SetError() void WingFetcher::PathFailed(const TCHAR* Expected) { if (ResultPin) - UWingServer::Printf(TEXT("ERROR: Path specifies a pin, but expected %s\n"), Expected); + Errors.Printf(TEXT("ERROR: Path specifies a pin, but expected %s\n"), Expected); else if (Obj) - UWingServer::Printf(TEXT("ERROR: Path specifies a %s, but expected %s\n"), *Obj->GetClass()->GetName(), Expected); + Errors.Printf(TEXT("ERROR: Path specifies a %s, but expected %s\n"), *Obj->GetClass()->GetName(), Expected); else - UWingServer::Printf(TEXT("ERROR: Path led to a null pointer\n")); + Errors.Printf(TEXT("ERROR: Path led to a null pointer\n")); UWingServer::SuggestManual(WingManual::Section::Paths); SetError(); } @@ -71,11 +71,11 @@ void WingFetcher::PathFailed(const TCHAR* Expected) WingFetcher& WingFetcher::TypeMismatch(const TCHAR* Walker, const TCHAR* Expected) { if (ResultPin) - UWingServer::Printf(TEXT("ERROR: Input to '%s' is a pin, but expected %s\n"), Walker, Expected); + Errors.Printf(TEXT("ERROR: Input to '%s' is a pin, but expected %s\n"), Walker, Expected); else if (Obj) - UWingServer::Printf(TEXT("ERROR: Input to '%s' is %s, but expected %s\n"), Walker, *Obj->GetClass()->GetName(), Expected); + Errors.Printf(TEXT("ERROR: Input to '%s' is %s, but expected %s\n"), Walker, *Obj->GetClass()->GetName(), Expected); else - UWingServer::Printf(TEXT("ERROR: Path led to a null pointer\n")); + Errors.Printf(TEXT("ERROR: Path led to a null pointer\n")); UWingServer::SuggestManual(WingManual::Section::Paths); SetError(); return *this; @@ -87,7 +87,7 @@ WingFetcher& WingFetcher::Walk(const FString& Path) if (Path.Contains(TEXT(" "))) { - UWingServer::Printf(TEXT("ERROR: Paths may not contain whitespace.")); + Errors.Printf(TEXT("ERROR: Paths may not contain whitespace.")); UWingServer::SuggestManual(WingManual::Section::Paths); UWingServer::SuggestManual(WingManual::Section::EscapeSequences); return SetError(); @@ -96,7 +96,7 @@ WingFetcher& WingFetcher::Walk(const FString& Path) Path.ParseIntoArray(Segments, TEXT(",")); if (Segments.Num() == 0) { - UWingServer::Print(TEXT("ERROR: Empty path\n")); + Errors.Print(TEXT("ERROR: Empty path\n")); UWingServer::SuggestManual(WingManual::Section::Paths); return SetError(); } @@ -117,7 +117,7 @@ WingFetcher& WingFetcher::Walk(const FString& Path) WalkFunc Func = GetWalker(Key); if (!Func) { - UWingServer::Printf(TEXT("ERROR: Unknown path step '%s'\n"), *Key); + Errors.Printf(TEXT("ERROR: Unknown path step '%s'\n"), *Key); UWingServer::SuggestManual(WingManual::Section::Paths); return SetError(); } @@ -134,7 +134,7 @@ WingFetcher& WingFetcher::Asset(const FString& PackagePath) if (!PackagePath.StartsWith(TEXT("/"))) { - UWingServer::Printf(TEXT("ERROR: Path must start with '/', got '%s'\n"), *PackagePath); + Errors.Printf(TEXT("ERROR: Path must start with '/', got '%s'\n"), *PackagePath); UWingServer::SuggestManual(WingManual::Section::Paths); return SetError(); } @@ -144,13 +144,13 @@ WingFetcher& WingFetcher::Asset(const FString& PackagePath) FString PackageName = FPackageName::ObjectPathToPackageName(PackagePath); if (!FPackageName::DoesPackageExist(PackageName)) { - UWingServer::Printf(TEXT("ERROR: Asset '%s' does not exist.\n"), *PackagePath); + Errors.Printf(TEXT("ERROR: Asset '%s' does not exist.\n"), *PackagePath); return SetError(); } SetObj(LoadObject(nullptr, *PackagePath)); if (!Obj) { - UWingServer::Printf(TEXT("ERROR: Could not load asset '%s'\n"), *PackagePath); + Errors.Printf(TEXT("ERROR: Could not load asset '%s'\n"), *PackagePath); return SetError(); } @@ -160,13 +160,13 @@ WingFetcher& WingFetcher::Asset(const FString& PackagePath) UAssetEditorSubsystem* Sub = GEditor->GetEditorSubsystem(); if (!Sub || !Sub->OpenEditorForAsset(Obj)) { - UWingServer::Printf(TEXT("ERROR: Could not open editor for '%s'\n"), *PackagePath); + Errors.Printf(TEXT("ERROR: Could not open editor for '%s'\n"), *PackagePath); return SetError(); } Editor = Sub->FindEditorForAsset(OriginalAsset, false); if (!Editor) { - UWingServer::Printf(TEXT("ERROR: Could not find editor instance for '%s'\n"), *PackagePath); + Errors.Printf(TEXT("ERROR: Could not find editor instance for '%s'\n"), *PackagePath); return SetError(); } @@ -184,7 +184,7 @@ bool WingFetcher::CheckAssetIsA(UClass* StaticClass) if (bError) return false; if (!OriginalAsset || !OriginalAsset->IsA(StaticClass)) { - UWingServer::Printf(TEXT("ERROR: Asset is %s, expected %s\n"), + Errors.Printf(TEXT("ERROR: Asset is %s, expected %s\n"), OriginalAsset ? *OriginalAsset->GetClass()->GetName() : TEXT("null"), *StaticClass->GetName()); SetError(); @@ -202,14 +202,14 @@ WingFetcher& WingFetcher::Graph(const FString& Value) { if (!Value.IsEmpty()) { - UWingServer::Printf(TEXT("ERROR: Materials have only one graph, with a blank name.\n\n")); + Errors.Printf(TEXT("ERROR: Materials have only one graph, with a blank name.\n\n")); UWingServer::SuggestManual(WingManual::Section::Paths); return SetError(); } WingUtils::EnsureMaterialGraph(Mat); if (!Mat->MaterialGraph) { - UWingServer::Printf(TEXT("ERROR: Material '%s' has no material graph\n"), *Mat->GetName()); + Errors.Printf(TEXT("ERROR: Material '%s' has no material graph\n"), *Mat->GetName()); return SetError(); } SetObj(Mat->MaterialGraph); @@ -224,13 +224,13 @@ WingFetcher& WingFetcher::Graph(const FString& Value) } TArray Graphs = WingUtils::AllGraphs(BP); - UEdGraph* Found = WingUtils::FindOneWithExternalID(Value, Graphs, TEXT("graph")); + UEdGraph* Found = WingUtils::FindOneWithExternalID(Value, Graphs, TEXT("graph"), Errors); if (!Found) { - UWingServer::Printf(TEXT("Graphs that exist in blueprint:\n")); + Errors.Printf(TEXT("Graphs that exist in blueprint:\n")); for (const UEdGraph *G : Graphs) { - UWingServer::Printf(TEXT(" %s\n"), *WingUtils::FormatName(G)); + Errors.Printf(TEXT(" %s\n"), *WingUtils::FormatName(G)); } return SetError(); } @@ -253,13 +253,13 @@ WingFetcher& WingFetcher::Node(const FString& Value) // Get the nodes from the graph. TArray AllNodes = WingUtils::AllNodes(Graph); - UEdGraphNode *Node = WingUtils::FindOneWithExternalID(Value, AllNodes, TEXT("node")); + UEdGraphNode *Node = WingUtils::FindOneWithExternalID(Value, AllNodes, TEXT("node"), Errors); if (Node == nullptr) { - UWingServer::Printf(TEXT("Nodes that exist in graph:\n")); + Errors.Printf(TEXT("Nodes that exist in graph:\n")); for (const UEdGraphNode *N : AllNodes) { - UWingServer::Printf(TEXT(" %s\n"), *WingUtils::FormatName(N)); + Errors.Printf(TEXT(" %s\n"), *WingUtils::FormatName(N)); } return SetError(); } @@ -277,13 +277,13 @@ WingFetcher& WingFetcher::Pin(const FString& Value) TypeMismatch(TEXT("pin"), TEXT("node")); return SetError(); } - UEdGraphPin *Found = WingUtils::FindOneWithExternalID(Value, N->Pins, TEXT("pin")); + UEdGraphPin *Found = WingUtils::FindOneWithExternalID(Value, N->Pins, TEXT("pin"), Errors); if (!Found) { - UWingServer::Printf(TEXT("Pins that exist in the node:\n")); + Errors.Printf(TEXT("Pins that exist in the node:\n")); for (const UEdGraphPin *P : N->Pins) { - UWingServer::Printf(TEXT(" %s\n"), *WingUtils::FormatName(P)); + Errors.Printf(TEXT(" %s\n"), *WingUtils::FormatName(P)); } return SetError(); } @@ -303,13 +303,13 @@ WingFetcher& WingFetcher::Component(const FString& Value) } TArray AllComponents = UWingComponentReference::GetAll(BP); - UWingComponentReference* Found = WingUtils::FindOneWithExternalID(Value, AllComponents, TEXT("component")); + UWingComponentReference* Found = WingUtils::FindOneWithExternalID(Value, AllComponents, TEXT("component"), Errors); if (!Found) { - UWingServer::Printf(TEXT("Components that exist in the blueprint:\n")); + Errors.Printf(TEXT("Components that exist in the blueprint:\n")); for (const UWingComponentReference* C : AllComponents) { - UWingServer::Printf(TEXT(" %s\n"), *WingUtils::FormatName(C)); + Errors.Printf(TEXT(" %s\n"), *WingUtils::FormatName(C)); } return SetError(); } @@ -331,13 +331,13 @@ WingFetcher& WingFetcher::Widget(const FString& Value) TArray AllWidgets; WidgetBP->WidgetTree->GetAllWidgets(AllWidgets); - UWidget* Found = WingUtils::FindOneWithExternalID(Value, AllWidgets, TEXT("widget")); + UWidget* Found = WingUtils::FindOneWithExternalID(Value, AllWidgets, TEXT("widget"), Errors); if (!Found) { - UWingServer::Printf(TEXT("Widgets that exist in the blueprint:\n")); + Errors.Printf(TEXT("Widgets that exist in the blueprint:\n")); for (const UWidget *W : AllWidgets) { - UWingServer::Printf(TEXT(" %s\n"), *WingUtils::FormatName(W)); + Errors.Printf(TEXT(" %s\n"), *WingUtils::FormatName(W)); } return SetError(); } @@ -358,18 +358,17 @@ WingFetcher& WingFetcher::LevelBlueprint(const FString& Value) if (!World->PersistentLevel) { - UWingServer::Print(TEXT("ERROR: World has no PersistentLevel\n")); + Errors.Print(TEXT("ERROR: World has no PersistentLevel\n")); return SetError(); } ULevelScriptBlueprint* LevelBP = World->PersistentLevel->GetLevelScriptBlueprint(true); if (!LevelBP) { - UWingServer::Print(TEXT("ERROR: World has no level blueprint\n")); + Errors.Print(TEXT("ERROR: World has no level blueprint\n")); return SetError(); } SetObj(LevelBP); return *this; } - diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp index 2a4a7f5f..0622acc3 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp @@ -254,7 +254,7 @@ void WingGraphExport::EmitNodeProperties(UEdGraphNode* Node, FStringBuilderBase& FString PrimaryCategory; if (UMaterialGraphNode* MatNode = Cast(Node)) { - WingPropHandle::Handles Handles = Props.GetDetails(Node, false); + WingPropHandle::Handles Handles = Props.GetDetails(Node, false, WingOut::Stdout); PrimaryCategory = MatNode->MaterialExpression->GetClass()->GetName(); for (const TSharedPtr& H : Handles) { @@ -265,7 +265,7 @@ void WingGraphExport::EmitNodeProperties(UEdGraphNode* Node, FStringBuilderBase& } else if (bPrimary) { - WingPropHandle::Handles Handles = Props.GetDetails(Node, false); + WingPropHandle::Handles Handles = Props.GetDetails(Node, false, WingOut::Stdout); for (const TSharedPtr& H : Handles) WingPropHandle::Print(*H, Out); } @@ -274,8 +274,8 @@ void WingGraphExport::EmitNodeProperties(UEdGraphNode* Node, FStringBuilderBase& void WingGraphExport::EmitLocalVariables() { WingVariables Vars; - Vars.SetBackingStore(Graph); - Vars.Load(); + Vars.SetBackingStore(Graph, WingOut::Stdout); + Vars.Load(WingOut::Stdout); Vars.Print(Output); } diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingManual.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingManual.cpp index bfdd7b70..e239ee92 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingManual.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingManual.cpp @@ -5,17 +5,17 @@ void WingManual::PrintHandlerPrototype(const FWingHandlerConfig& Handler) { - UWingServer::Print(Handler.Name); - UWingServer::Print(TEXT("(")); + WingOut::Stdout.Print(Handler.Name); + WingOut::Stdout.Print(TEXT("(")); bool bFirst = true; for (TFieldIterator PropIt(Handler.Class.Get(), EFieldIterationFlags::None); PropIt; ++PropIt) { - if (!bFirst) UWingServer::Print(TEXT(",")); + if (!bFirst) WingOut::Stdout.Print(TEXT(",")); bFirst = false; - if (PropIt->HasMetaData(TEXT("Optional"))) UWingServer::Print(TEXT("?")); - UWingServer::Print(PropIt->GetName()); + if (PropIt->HasMetaData(TEXT("Optional"))) WingOut::Stdout.Print(TEXT("?")); + WingOut::Stdout.Print(PropIt->GetName()); } - UWingServer::Print(TEXT(")\n")); + WingOut::Stdout.Print(TEXT(")\n")); } void WingManual::PrintHandlerArguments(const FWingHandlerConfig& Handler) @@ -31,30 +31,30 @@ void WingManual::PrintHandlerArguments(const FWingHandlerConfig& Handler) if (bOptional) { - UWingServer::Printf(TEXT(" %s (optional %s)"), *Name, *Type); + WingOut::Stdout.Printf(TEXT(" %s (optional %s)"), *Name, *Type); } else { - UWingServer::Printf(TEXT(" %s (%s)"), *Name, *Type); + WingOut::Stdout.Printf(TEXT(" %s (%s)"), *Name, *Type); } - if (!Desc.IsEmpty()) UWingServer::Printf(TEXT(" — %s"), *Desc); - UWingServer::Print(TEXT("\n")); + if (!Desc.IsEmpty()) WingOut::Stdout.Printf(TEXT(" — %s"), *Desc); + WingOut::Stdout.Print(TEXT("\n")); } } void WingManual::PrintHandlerDescription(const FWingHandlerConfig& Handler) { if (Handler.Documentation.IsEmpty()) return; - UWingServer::Print(WingUtils::WrapText(Handler.Documentation, 80, TEXT(" // "))); + WingOut::Stdout.Print(WingUtils::WrapText(Handler.Documentation, 80, TEXT(" // "))); } void WingManual::PrintHandlerHelp(const FWingHandlerConfig& Handler) { - UWingServer::Print(TEXT("\n")); + WingOut::Stdout.Print(TEXT("\n")); PrintHandlerPrototype(Handler); PrintHandlerArguments(Handler); PrintHandlerDescription(Handler); - UWingServer::Print(TEXT("\n")); + WingOut::Stdout.Print(TEXT("\n")); } void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* Handler, bool Abridged) @@ -65,7 +65,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H if (Abridged) { - UWingServer::Printf(TEXT("\n--- AUTOMATIC DOCUMENTATION ---\n")); + WingOut::Stdout.Printf(TEXT("\n--- AUTOMATIC DOCUMENTATION ---\n")); } if (Handler && (Sections.Contains(Section::HandlerHelp) || bPrintAll)) @@ -77,7 +77,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H { if (Abridged) { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n PATHS: Here are some example paths:" "\n /Game/Widgets/WB_Hotkeys,widget:Canvas·122" "\n /Game/Testing/BP_Test,graph:Rescale·Actor,node:K2Node_CallFunction_0,pin:Scale" @@ -87,7 +87,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H } else { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n PATHS:" "\n" "\n Most commands require you to specify a path. A path starts" @@ -123,7 +123,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H { if (Abridged) { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n TYPES: Here are some examples of valid types:" "\n Bool, String, Vector, Rotator, HitResult, Actor, Character," "\n PlayerController, EBlendMode, EMovementMode, BP_Manny, BP_Quinn," @@ -134,7 +134,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H } else { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n TYPES:" "\n" "\n To change variable types, or to express function prototypes, you will" @@ -157,7 +157,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H { if (Abridged) { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n VARIABLE DECLARATIONS: example variable declarations:" "\n Array Actors" "\n Float F (InstanceEditable)" @@ -166,7 +166,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H } else { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n VARIABLE DECLARATIONS:" "\n" "\n We have our own syntax for variable declarations: a type," @@ -192,7 +192,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H { if (Abridged) { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n USING HTML ESCAPE SEQUENCES:" "\n When we output FNames, we use HTML escape sequences for the" "\n following marks: \\\"'(),.:;<=>& We also escape control" @@ -218,7 +218,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H } else { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n USING HTML ESCAPE SEQUENCES:" "\n When we output FNames, we use HTML escape sequences for the" "\n following marks: \\\"'(),.:;<=>&, and for certain other characters." @@ -234,7 +234,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H if (Sections.Contains(Section::Whitespace) || bPrintAll) { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n ABOUT WHITESPACE:" "\n Do not put excess whitespace into paths, typenames, or" "\n function prototypes, only use whitespace where it is required" @@ -247,7 +247,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H { if (Abridged) { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n MATERIAL EDITING:" "\n We do not expose material expressions directly. Instead, use" "\n Property_Dump and Property_Set on the material graph nodes to" @@ -257,7 +257,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H } else { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n MATERIAL EDITING:" "\n" "\n We do not expose material expressions directly. Instead, you" @@ -272,7 +272,7 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H if (Sections.Contains(Section::ImportantCommands) || bPrintAll) { - UWingServer::Print(TEXT( + WingOut::Stdout.Print(TEXT( "\n COMMANDS YOU SHOULD KNOW ABOUT AND REMEMBER:" "\n UserManual: this explanation" "\n ShowCommands: a full list of all the commands" @@ -288,6 +288,6 @@ void WingManual::PrintManual(TSet
Sections, const FWingHandlerConfig* H if (Abridged) { - UWingServer::Printf(TEXT("\nUse command 'UserManual' to see the full manual.\n")); + WingOut::Stdout.Printf(TEXT("\nUse command 'UserManual' to see the full manual.\n")); } } diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingMaterialParameter.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingMaterialParameter.cpp index 977f229d..cc7cccd0 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingMaterialParameter.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingMaterialParameter.cpp @@ -15,7 +15,7 @@ TMap WingMaterialParameter:: return Result; } -bool WingMaterialParameter::ParseMaterialParameterAssociation(const FString& Str, EMaterialParameterAssociation& OutAssociation) +bool WingMaterialParameter::ParseMaterialParameterAssociation(const FString& Str, EMaterialParameterAssociation& OutAssociation, WingOut Errors) { if (Str.Equals(TEXT("Global"), ESearchCase::IgnoreCase)) OutAssociation = GlobalParameter; @@ -25,7 +25,7 @@ bool WingMaterialParameter::ParseMaterialParameterAssociation(const FString& Str OutAssociation = BlendParameter; else { - UWingServer::Printf(TEXT("ERROR: Invalid ParameterAssociation '%s' (expected 'Global', 'Layer', or 'Blend')\n"), *Str); + Errors.Printf(TEXT("ERROR: Invalid ParameterAssociation '%s' (expected 'Global', 'Layer', or 'Blend')\n"), *Str); return false; } return true; @@ -43,35 +43,35 @@ void WingMaterialParameter::FormatMaterialParameter(const FMaterialParameterInfo switch (Meta.Value.Type) { case EMaterialParameterType::Scalar: - UWingServer::Printf(TEXT(" %sScalar \"%s\" = %g\n"), *Prefix, *Info.Name.ToString(), Meta.Value.AsScalar()); + WingOut::Stdout.Printf(TEXT(" %sScalar \"%s\" = %g\n"), *Prefix, *Info.Name.ToString(), Meta.Value.AsScalar()); break; case EMaterialParameterType::Vector: { FLinearColor C = Meta.Value.AsLinearColor(); - UWingServer::Printf(TEXT(" %sVector \"%s\" = (R=%.3f, G=%.3f, B=%.3f, A=%.3f)\n"), + WingOut::Stdout.Printf(TEXT(" %sVector \"%s\" = (R=%.3f, G=%.3f, B=%.3f, A=%.3f)\n"), *Prefix, *Info.Name.ToString(), C.R, C.G, C.B, C.A); break; } case EMaterialParameterType::DoubleVector: { FVector4d V = Meta.Value.AsVector4d(); - UWingServer::Printf(TEXT(" %sDoubleVector \"%s\" = (%.3f, %.3f, %.3f, %.3f)\n"), + WingOut::Stdout.Printf(TEXT(" %sDoubleVector \"%s\" = (%.3f, %.3f, %.3f, %.3f)\n"), *Prefix, *Info.Name.ToString(), V.X, V.Y, V.Z, V.W); break; } case EMaterialParameterType::Texture: { UTexture* Tex = Cast(Meta.Value.AsTextureObject()); - UWingServer::Printf(TEXT(" %sTexture \"%s\" = %s\n"), + WingOut::Stdout.Printf(TEXT(" %sTexture \"%s\" = %s\n"), *Prefix, *Info.Name.ToString(), Tex ? *WingUtils::FormatName(Tex) : TEXT("None")); break; } case EMaterialParameterType::StaticSwitch: - UWingServer::Printf(TEXT(" %sStaticSwitch \"%s\" = %s\n"), + WingOut::Stdout.Printf(TEXT(" %sStaticSwitch \"%s\" = %s\n"), *Prefix, *Info.Name.ToString(), Meta.Value.AsStaticSwitch() ? TEXT("true") : TEXT("false")); break; default: - UWingServer::Printf(TEXT(" %sType%d \"%s\"\n"), *Prefix, (int)Meta.Value.Type, *Info.Name.ToString()); + WingOut::Stdout.Printf(TEXT(" %sType%d \"%s\"\n"), *Prefix, (int)Meta.Value.Type, *Info.Name.ToString()); break; } } diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp index 5f6c1f88..9bd6ccf0 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp @@ -186,19 +186,19 @@ TSharedPtr WingPropHandle::TryNamedProperty(const UStruct* Scri return TryNamedProperty(GetRootForStruct(ScriptStruct, Data), Name, RootFilter); } -TSharedPtr WingPropHandle::NamedProperty(UObject* Obj, FName Name, bool RootFilter) +TSharedPtr WingPropHandle::NamedProperty(UObject* Obj, FName Name, bool RootFilter, WingOut Errors) { TSharedPtr Result = TryNamedProperty(Obj, Name, RootFilter); if (!Result) - UWingServer::Printf(TEXT("ERROR: Property '%s' not found\n"), *Name.ToString()); + Errors.Printf(TEXT("ERROR: Property '%s' not found\n"), *Name.ToString()); return Result; } -TSharedPtr WingPropHandle::NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter) +TSharedPtr WingPropHandle::NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter, WingOut Errors) { TSharedPtr Result = TryNamedProperty(ScriptStruct, Data, Name, RootFilter); if (!Result) - UWingServer::Printf(TEXT("ERROR: Property '%s' not found\n"), *Name.ToString()); + Errors.Printf(TEXT("ERROR: Property '%s' not found\n"), *Name.ToString()); return Result; } @@ -208,7 +208,7 @@ TSharedPtr WingPropHandle::NamedProperty(const UStruct* ScriptS // ///////////////////////////////////////////////////////////////////////////// -WingPropHandle::Handles WingPropHandle::GetDetails(UObject* Obj, bool Mutable) +WingPropHandle::Handles WingPropHandle::GetDetails(UObject* Obj, bool Mutable, WingOut Errors) { bool RootFilter = false; @@ -219,7 +219,7 @@ WingPropHandle::Handles WingPropHandle::GetDetails(UObject* Obj, bool Mutable) { if (!BP->GeneratedClass) { - UWingServer::Printf(TEXT("ERROR: Blueprint '%s' has no GeneratedClass\n"), *Obj->GetName()); + Errors.Printf(TEXT("ERROR: Blueprint '%s' has no GeneratedClass\n"), *Obj->GetName()); return {}; } Obj = BP->GeneratedClass->GetDefaultObject(); @@ -235,7 +235,7 @@ WingPropHandle::Handles WingPropHandle::GetDetails(UObject* Obj, bool Mutable) Obj = Mutable ? Ref->GetMutableTemplate() : Ref->GetImmutableTemplate(); if (!Obj) { - UWingServer::Printf(TEXT("ERROR: Component '%s' has no template\n"), *Ref->VariableName.ToString()); + Errors.Printf(TEXT("ERROR: Component '%s' has no template\n"), *Ref->VariableName.ToString()); return {}; } } @@ -277,7 +277,7 @@ WingPropHandle::Handles WingPropHandle::GetDetails(UObject* Obj, bool Mutable) // ///////////////////////////////////////////////////////////////////////////// -bool WingPropHandle::OrganizeByName(const Handles &HList, TMap> &Result) +bool WingPropHandle::OrganizeByName(const Handles &HList, TMap> &Result, WingOut Errors) { Result.Empty(); TSet DuplicateNames; @@ -288,12 +288,12 @@ bool WingPropHandle::OrganizeByName(const Handles &HList, TMapMetaClass; - Class = UWingTypes::TextToOneObjectType(Text, Req); + Class = UWingTypes::TextToOneObjectType(Text, Req, Errors); if (!Class) return false; } if (Handle.SetValue(Class) != FPropertyAccess::Success) { - UWingServer::Printf(TEXT("ERROR: Failed to set class property '%s'\n"), + Errors.Printf(TEXT("ERROR: Failed to set class property '%s'\n"), *WingUtils::FormatName(Prop)); return false; } @@ -397,14 +397,14 @@ bool WingPropHandle::SetText(IPropertyHandle& Handle, const FString& Text) if (Enum != nullptr) { int64 EnumValue; - if (!WingUtils::StringToEnum(Enum, Value, EnumValue)) return false; + if (!WingUtils::StringToEnum(Enum, Value, EnumValue, Errors)) return false; Value = Enum->GetNameStringByValue(EnumValue); } FPropertyAccess::Result Result = Handle.SetValueFromFormattedString(Value); if (Result != FPropertyAccess::Success) { - UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s' (type: %s)\n"), + Errors.Printf(TEXT("ERROR: Failed to parse '%s' for property '%s' (type: %s)\n"), *Value, *WingUtils::FormatName(Prop), *Prop->GetCPPType()); return false; } @@ -417,14 +417,14 @@ bool WingPropHandle::SetText(IPropertyHandle& Handle, const FString& Text) // ///////////////////////////////////////////////////////////////////////////// -bool WingPropHandle::SetJson(IPropertyHandle& Handle, const TSharedPtr& JsonValue) +bool WingPropHandle::SetJson(IPropertyHandle& Handle, const TSharedPtr& JsonValue, WingOut Errors) { FPropertyAccess::Result Result; switch (JsonValue->Type) { case EJson::String: - return SetText(Handle, JsonValue->AsString()); + return SetText(Handle, JsonValue->AsString(), Errors); case EJson::Boolean: Result = Handle.SetValue(JsonValue->AsBool()); @@ -441,34 +441,34 @@ bool WingPropHandle::SetJson(IPropertyHandle& Handle, const TSharedPtr>& Props, const FJsonObject& Json, bool AllOptional) +bool WingPropHandle::PopulateFromJson(TArray>& Props, const FJsonObject& Json, bool AllOptional, WingOut Errors) { bool Ok = true; // Organize the properties by name. TMap> OrganizedProps; - if (!OrganizeByName(Props, OrganizedProps)) Ok = false; + if (!OrganizeByName(Props, OrganizedProps, Errors)) Ok = false; // Parse the keys in the json, make sure they're syntactically valid and // that they match the names of actual properties, and that there are no dups. TSet Specified; for (const auto& KV : Json.Values) { - FName Name = WingUtils::CheckInternalizeID(KV.Key); + FName Name = WingUtils::CheckInternalizeID(KV.Key, Errors); if (Name.IsNone()) { Ok = false; continue; } if (!OrganizedProps.Contains(Name)) { - UWingServer::Printf(TEXT("ERROR: Unknown parameter '%s'\n"), *KV.Key); + Errors.Printf(TEXT("ERROR: Unknown parameter '%s'\n"), *KV.Key); Ok = false; } - if (!WingUtils::FindNoDuplicateName(Specified, Name, TEXT("parameter"))) Ok = false; + if (!WingUtils::FindNoDuplicateName(Specified, Name, TEXT("parameter"), Errors)) Ok = false; } // Make sure that all required properties have been specified. @@ -480,7 +480,7 @@ bool WingPropHandle::PopulateFromJson(TArray>& Props FName Name = H->GetProperty()->GetFName(); if (!Specified.Contains(Name)) { - UWingServer::Printf(TEXT("Required parameter %s not specified\n"), + Errors.Printf(TEXT("Required parameter %s not specified\n"), *WingUtils::ExternalizeID(Name)); Ok = false; } @@ -494,8 +494,8 @@ bool WingPropHandle::PopulateFromJson(TArray>& Props // point, we're committed. for (const auto& KV : Json.Values) { - FName Name = WingUtils::CheckInternalizeID(KV.Key); - if (!SetJson(*OrganizedProps[Name], KV.Value)) Ok = false; + FName Name = WingUtils::CheckInternalizeID(KV.Key, Errors); + if (!SetJson(*OrganizedProps[Name], KV.Value, Errors)) Ok = false; } return Ok; } diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp index 97099572..9e2a3bf7 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp @@ -14,32 +14,313 @@ #include "Dom/JsonValue.h" -static bool IsPinTypeProperty(FProperty* Prop) +bool FWingProperty::SetObject(UObject *Obj, WingOut Errors) const { - FStructProperty* StructProp = CastField(Prop); - return StructProp && StructProp->Struct == FEdGraphPinType::StaticStruct(); + FObjectPropertyBase *OProp = CastField(Prop); + if (!OProp) + { + PrintExpectsReceived(TEXT("object"), Errors); + return false; + } + if (Obj) + { + if (!Obj->IsA(OProp->PropertyClass)) + { + Errors.Printf(TEXT("ERROR: Property '%s' expects %s, but received %s\n"), + *WingUtils::FormatName(Prop), *OProp->PropertyClass->GetName(), *Obj->GetClass()->GetName()); + return false; + } + if (FClassProperty *CProp = CastField(Prop)) + { + UClass *Class = CastChecked(Obj); + if (!Class->IsChildOf(CProp->MetaClass)) + { + Errors.Printf(TEXT("ERROR: Property '%s' expects a subclass of %s, but received %s\n"), + *WingUtils::FormatName(Prop), *CProp->MetaClass->GetName(), *Class->GetName()); + return false; + } + } + } + OProp->SetObjectPropertyValue_InContainer(Container, Obj); + return true; } -FWingProperty::FWingProperty(FProperty* InProp, void* InContainer) - : Prop(InProp), Container(InContainer) {} - -FWingProperty::FWingProperty(FProperty* InProp, UObject* InContainer) - : Prop(InProp), Container(static_cast(InContainer)) {} - -FString FWingProperty::GetCategory() +bool FWingProperty::SetDouble(double D, WingOut Errors) const { - FString Result = Prop->GetMetaData(TEXT("Category")); - if (Result.IsEmpty()) Result = "Unclassified"; - return Result; + FNumericProperty *NProp = CastField(Prop); + if (!NProp) + { + PrintExpectsReceived(TEXT("double"), Errors); + return false; + } + if (NProp->IsFloatingPoint()) + { + uint8 buffer[16]; + NProp->SetFloatingPointPropertyValue(buffer, D); + if (!FMath::IsFinite(NProp->GetFloatingPointPropertyValue(buffer))) + { + Errors.Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lf\n"), + *WingUtils::FormatName(Prop), *Prop->GetCPPType(), D); + return false; + } + Prop->SetValue_InContainer(Container, buffer); + return true; + } + else + { + uint8 buffer[16]; + if (FMath::Floor(D) != D) + { + PrintExpectsReceived(TEXT("double"), Errors); + return false; + } + if (FMath::Abs(D) > (double)((1LL)<<53)) + { + Errors.Printf(TEXT("ERROR: To store very large numbers in '%s', do not pass them as double. Use string or int.\n"), + *WingUtils::FormatName(Prop)); + return false; + } + int64 I = (int64)D; + NProp->SetIntPropertyValue(buffer, I); + if (NProp->GetSignedIntPropertyValue(buffer) != I) + { + Errors.Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"), + *WingUtils::FormatName(Prop), *Prop->GetCPPType(), I); + return false; + } + NProp->SetValue_InContainer(Container, buffer); + return true; + } +} + +bool FWingProperty::SetInt64(int64 I, WingOut Errors) const +{ + FNumericProperty *NProp = CastField(Prop); + if (!NProp) + { + PrintExpectsReceived(TEXT("int"), Errors); + return false; + } + if (NProp->IsFloatingPoint()) + { + uint8 buffer[16]; + double D = I; + NProp->SetFloatingPointPropertyValue(buffer, D); + int64 RT = (int64)NProp->GetFloatingPointPropertyValue(buffer); + if (RT != I) + { + Errors.Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"), + *WingUtils::FormatName(Prop), *Prop->GetCPPType(), I); + return false; + } + Prop->SetValue_InContainer(Container, buffer); + return true; + } + else + { + uint8 buffer[16]; + NProp->SetIntPropertyValue(buffer, I); + if (NProp->GetSignedIntPropertyValue(buffer) != I) + { + Errors.Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"), + *WingUtils::FormatName(Prop), *Prop->GetCPPType(), I); + return false; + } + NProp->SetValue_InContainer(Container, buffer); + return true; + } +} + +bool FWingProperty::SetBool(bool B, WingOut Errors) const +{ + if (FBoolProperty* BoolProp = CastField(Prop)) + { + Prop->SetValue_InContainer(Container, &B); + return true; + } + PrintExpectsReceived(TEXT("boolean"), Errors); + return false; +} + +bool FWingProperty::SetText(FString Value, WingOut Errors) const +{ + // Pin types get parsed by UWingTypes. + if (IsPinTypeProperty(Prop)) + { + FEdGraphPinType PinType; + UWingTypes::Requirements Req; + Req.BlueprintType = true; + Req.Blueprintable = false; + Req.AllowContainer = true; + if (!UWingTypes::TextToType(Value, PinType, Req, Errors)) return false; + Prop->SetValue_InContainer(Container, &PinType); + return true; + } + + // If it's an enum type, use our parsing routine which is smarter about + // prefixes than ImportText. We canonicalize the string, and then send + // it onward to ImportText. + UEnum *Enum = nullptr; + if (FByteProperty* ByteProp = CastField(Prop)) + Enum = ByteProp->Enum; + if (FEnumProperty* EnumProp = CastField(Prop)) + Enum = EnumProp->GetEnum(); + if (Enum != nullptr) + { + int64 EnumValue; + if (!WingUtils::StringToEnum(Enum, Value, EnumValue, Errors)) return false; + Value = Enum->GetNameStringByValue(EnumValue); + } + + // Now Use ImportText + const TCHAR* Result = Prop->ImportText_InContainer(*Value, Container, nullptr, PPF_None); + if ((!Result) || (*Result != 0)) + { + Errors.Printf(TEXT("ERROR: Failed to parse '%s' for property '%s' (type: %s)\n"), + *Value, *WingUtils::FormatName(Prop), *Prop->GetCPPType()); + return false; + } + if (!CheckImportTextResult(Value, Errors)) return false; + return true; +} + +bool FWingProperty::SetJson(const FJsonValue &JsonValue, WingOut Errors) const +{ + if (JsonValue.Type == EJson::String) + { + return SetText(JsonValue.AsString(), Errors); + } + + if (JsonValue.Type == EJson::Number) + { + return SetDouble(JsonValue.AsNumber(), Errors); + } + + if (JsonValue.Type == EJson::Boolean) + { + return SetBool(JsonValue.AsBool(), Errors); + } + + if (JsonValue.Type == EJson::Object) + { + FStructProperty* StructProp = CastField(Prop); + if (StructProp && (StructProp->Struct == FWingJsonObject::StaticStruct())) + { + FWingJsonObject Val; + Val.Json = JsonValue.AsObject(); + Prop->SetValue_InContainer(Container, &Val); + return true; + } + PrintExpectsReceived(TEXT("json object"), Errors); + return false; + } + + if (JsonValue.Type == EJson::Array) + { + FStructProperty* StructProp = CastField(Prop); + if (StructProp && (StructProp->Struct == FWingJsonArray::StaticStruct())) + { + FWingJsonArray Val; + Val.Array = JsonValue.AsArray(); + Prop->SetValue_InContainer(Container, &Val); + return true; + } + PrintExpectsReceived(TEXT("json array"), Errors); + return false; + } + + PrintExpectsReceived(TEXT("Unrecognized Json Data"), Errors); + return false; +} + +TOptional FWingProperty::GetObject(WingOut Errors) const +{ + FObjectPropertyBase *OProp = CastField(Prop); + if (!OProp) + { + PrintExpectsReceived(TEXT("object"), Errors); + return {}; + } + uint8 *VP = Prop->ContainerPtrToValuePtr(Container); + return OProp->GetObjectPropertyValue(VP); +} + +TOptional FWingProperty::GetDouble(WingOut Errors) const +{ + FNumericProperty *NProp = CastField(Prop); + if (!NProp) + { + PrintExpectsReceived(TEXT("double"), Errors); + return {}; + } + uint8 *VP = Prop->ContainerPtrToValuePtr(Container); + if (NProp->IsFloatingPoint()) + { + return NProp->GetFloatingPointPropertyValue(VP); + } + else + { + int64 I = NProp->GetSignedIntPropertyValue(VP); + double D = (double)I; + if ((int64)D != I) + { + Errors.Printf(TEXT("ERROR: Property '%s' value %lld cannot be represented losslessly as double\n"), + *WingUtils::FormatName(Prop), I); + return {}; + } + return D; + } +} + +TOptional FWingProperty::GetInt64(WingOut Errors) const +{ + FNumericProperty *NProp = CastField(Prop); + if (!NProp) + { + PrintExpectsReceived(TEXT("int"), Errors); + return {}; + } + uint8 *VP = Prop->ContainerPtrToValuePtr(Container); + if (NProp->IsFloatingPoint()) + { + double D = NProp->GetFloatingPointPropertyValue(VP); + if (FMath::Floor(D) != D) + { + Errors.Printf(TEXT("ERROR: Property '%s' value %lf is not an integer\n"), + *WingUtils::FormatName(Prop), D); + return {}; + } + if (FMath::Abs(D) > (double)((1LL)<<53)) + { + Errors.Printf(TEXT("ERROR: Property '%s' value %lf is too large to convert to int64 losslessly\n"), + *WingUtils::FormatName(Prop), D); + return {}; + } + return (int64)D; + } + else + { + return NProp->GetSignedIntPropertyValue(VP); + } +} + +TOptional FWingProperty::GetBool(WingOut Errors) const +{ + if (FBoolProperty* BoolProp = CastField(Prop)) + { + uint8 *VP = Prop->ContainerPtrToValuePtr(Container); + return BoolProp->GetPropertyValue(VP); + } + PrintExpectsReceived(TEXT("boolean"), Errors); + return {}; } FString FWingProperty::GetText() const { if (IsPinTypeProperty(Prop)) { - FEdGraphPinType PinType; - Prop->GetValue_InContainer(Container, &PinType); - return UWingTypes::TypeToText(PinType); + FEdGraphPinType *PinType = Prop->ContainerPtrToValuePtr(Container); + return UWingTypes::TypeToText(*PinType); } FString Result; Prop->ExportTextItem_InContainer(Result, Container, nullptr, nullptr, PPF_None); @@ -56,269 +337,35 @@ FString FWingProperty::GetTruncatedText(int32 MaxLen) const return Result; } -void FWingProperty::PrintExpectsReceived(const TCHAR *Type) + +FString FWingProperty::GetCategory() const { - UWingServer::Printf(TEXT("ERROR: '%s' received a %s, but expects %s\n"), - *WingUtils::FormatName(Prop), Type, *Prop->GetCPPType()); + FString Result = Prop->GetMetaData(TEXT("Category")); + if (Result.IsEmpty()) Result = "Unclassified"; + return Result; } - -bool FWingProperty::CheckImportTextResult(const FString &Value) +void FWingProperty::GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags, TArray &Props) { - uint8 *VP = Prop->ContainerPtrToValuePtr(Container); - if (FObjectPropertyBase *OProp = CastField(Prop)) - { - UObject *Obj = OProp->GetObjectPropertyValue(VP); - if (Obj == nullptr && Value.TrimStartAndEnd().Compare(TEXT("None"), ESearchCase::IgnoreCase) != 0) - { - UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s'\n"), - *Value, *WingUtils::FormatName(Prop)); - return false; - } - } - return true; -} - -bool FWingProperty::SetText(FString Value) -{ - // Pin types get parsed by UWingTypes. - if (IsPinTypeProperty(Prop)) - { - FEdGraphPinType PinType; - UWingTypes::Requirements Req; - Req.BlueprintType = true; - Req.Blueprintable = false; - Req.AllowContainer = true; - if (!UWingTypes::TextToType(Value, PinType, Req)) return false; - Prop->SetValue_InContainer(Container, &PinType); - return true; - } - - // If it's an enum type, use our parsing routine which is smarter about - // prefixes than ImportText. We canonicalize the string, and then send - // it onward to ImportText. - UEnum *Enum = nullptr; - if (FByteProperty* ByteProp = CastField(Prop)) - Enum = ByteProp->Enum; - if (FEnumProperty* EnumProp = CastField(Prop)) - Enum = EnumProp->GetEnum(); - if (Enum != nullptr) - { - int64 EnumValue; - if (!WingUtils::StringToEnum(Enum, Value, EnumValue)) return false; - Value = Enum->GetNameStringByValue(EnumValue); - } - - // Now Use ImportText - const TCHAR* Result = Prop->ImportText_InContainer(*Value, Container, nullptr, PPF_None); - if ((!Result) || (*Result != 0)) - { - UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s' (type: %s)\n"), - *Value, *WingUtils::FormatName(Prop), *Prop->GetCPPType()); - return false; - } - if (!CheckImportTextResult(Value)) return false; - return true; -} - -bool FWingProperty::SetDouble(double D) -{ - FNumericProperty *NProp = CastField(Prop); - if (!NProp) - { - PrintExpectsReceived(TEXT("double")); - return false; - } - if (NProp->IsFloatingPoint()) - { - uint8 buffer[16]; - NProp->SetFloatingPointPropertyValue(buffer, D); - if (!FMath::IsFinite(NProp->GetFloatingPointPropertyValue(buffer))) - { - UWingServer::Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lf\n"), - *WingUtils::FormatName(Prop), *Prop->GetCPPType(), D); - return false; - } - Prop->SetValue_InContainer(Container, buffer); - return true; - } - else - { - uint8 buffer[16]; - if (FMath::Floor(D) != D) - { - PrintExpectsReceived(TEXT("double")); - return false; - } - if (FMath::Abs(D) > (double)((1LL)<<53)) - { - UWingServer::Printf(TEXT("ERROR: To store very large numbers in '%s', do not pass them as double. Use string or int.\n"), - *WingUtils::FormatName(Prop)); - return false; - } - int64 I = (int64)D; - NProp->SetIntPropertyValue(buffer, I); - if (NProp->GetSignedIntPropertyValue(buffer) != I) - { - UWingServer::Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"), - *WingUtils::FormatName(Prop), *Prop->GetCPPType(), I); - return false; - } - NProp->SetValue_InContainer(Container, buffer); - return true; - } -} - -bool FWingProperty::SetInt64(int64 I) -{ - FNumericProperty *NProp = CastField(Prop); - if (!NProp) - { - PrintExpectsReceived(TEXT("int")); - return false; - } - if (NProp->IsFloatingPoint()) - { - uint8 buffer[16]; - double D = I; - NProp->SetFloatingPointPropertyValue(buffer, D); - int64 RT = (int64)NProp->GetFloatingPointPropertyValue(buffer); - if (RT != I) - { - UWingServer::Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"), - *WingUtils::FormatName(Prop), *Prop->GetCPPType(), I); - return false; - } - Prop->SetValue_InContainer(Container, buffer); - return true; - } - else - { - uint8 buffer[16]; - NProp->SetIntPropertyValue(buffer, I); - if (NProp->GetSignedIntPropertyValue(buffer) != I) - { - UWingServer::Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"), - *WingUtils::FormatName(Prop), *Prop->GetCPPType(), I); - return false; - } - NProp->SetValue_InContainer(Container, buffer); - return true; - } -} - -bool FWingProperty::SetBool(bool B) -{ - if (FBoolProperty* BoolProp = CastField(Prop)) - { - Prop->SetValue_InContainer(Container, &B); - return true; - } - PrintExpectsReceived(TEXT("boolean")); - return false; -} - - -bool FWingProperty::SetJson(const TSharedPtr &JsonValue) -{ - if (JsonValue->Type == EJson::String) - { - return SetText(JsonValue->AsString()); - } - - if (JsonValue->Type == EJson::Number) - { - return SetDouble(JsonValue->AsNumber()); - } - - if (JsonValue->Type == EJson::Boolean) - { - return SetBool(JsonValue->AsBool()); - } - - if (JsonValue->Type == EJson::Object) - { - void* ValuePtr = Prop->ContainerPtrToValuePtr(Container); - FStructProperty* StructProp = CastField(Prop); - if (StructProp && (StructProp->Struct == FWingJsonObject::StaticStruct())) - { - static_cast(ValuePtr)->Json = JsonValue->AsObject(); - return true; - } - PrintExpectsReceived(TEXT("json object")); - return false; - } - - if (JsonValue->Type == EJson::Array) - { - void* ValuePtr = Prop->ContainerPtrToValuePtr(Container); - FStructProperty* StructProp = CastField(Prop); - if (StructProp && (StructProp->Struct == FWingJsonArray::StaticStruct())) - { - static_cast(ValuePtr)->Array = JsonValue->AsArray(); - return true; - } - PrintExpectsReceived(TEXT("json array")); - return false; - } - - PrintExpectsReceived(TEXT("Unrecognized Json Data")); - return false; -} - -void FWingProperty::Collect(UStruct* StructType, void* Container, TArray &Props, EPropertyFlags Flags) -{ - TMap> Grouped; - - for (TFieldIterator It(StructType); It; ++It) + TArray Result; + for (TFieldIterator It(Obj.UStructPtr); It; ++It) { if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue; - FString SortCat = *It->GetMetaData(TEXT("Category")); - Grouped.FindOrAdd(SortCat).Add(FWingProperty(*It, Container)); - } - TArray Categories; - - Grouped.GetKeys(Categories); - Categories.Sort([](const FString& A, const FString& B) { - if (A.IsEmpty()) return false; - if (B.IsEmpty()) return true; - return A < B; - }); - - for (const FString& Category : Categories) - { - Props.Append(Grouped[Category]); + Result.Add(FWingProperty(*It, Obj.StructPtr)); } } -TArray FWingProperty::GetAll(UObject* Object, EPropertyFlags Flags) -{ - return GetAll(Object->GetClass(), Object, Flags); -} - -TArray FWingProperty::GetAll(UStruct* StructType, void* Container, EPropertyFlags Flags) +TArray FWingProperty::GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags) { TArray Result; - Collect(StructType, Container, Result, Flags); + GetAll(Obj, Flags, Result); return Result; } -TArray FWingProperty::GetNamed(UStruct* StructType, void* Container, const TArray &Names) -{ - TArray Result; - for (FName Name : Names) - { - FProperty *Prop = StructType->FindPropertyByName(Name); - if (Prop != nullptr) Result.Emplace(Prop, Container); - } - return Result; -} - - -TArray FWingProperty::GetNames(UStruct *StructType, EPropertyFlags Flags) +TArray FWingProperty::GetNames(UStruct *US, EPropertyFlags Flags) { TArray Result; - for (TFieldIterator It(StructType); It; ++It) + for (TFieldIterator It(US); It; ++It) { if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue; Result.Add(It->GetFName()); @@ -326,29 +373,23 @@ TArray FWingProperty::GetNames(UStruct *StructType, EPropertyFlags Flags) return Result; } -void FWingProperty::Remove(TArray& Props, const FString& Name) +void FWingProperty::Remove(TArray& Props, FName Name) { Props.RemoveAll([&](const FWingProperty& P) { return P.Prop->GetName() == Name; }); } -void FWingProperty::Move(TArray &Out, TArray &In, const FString &Name) +void FWingProperty::Move(TArray &Out, TArray &In, FName Name) { int Dst = 0; for (int i = 0; i < In.Num(); i++) { - if (In[i]->GetName() == Name) - { - Out.Add(In[i]); - } - else - { - In[Dst++] = In[i]; - } + if (In[i]->GetFName() == Name) Out.Add(In[i]); + else In[Dst++] = In[i]; } In.SetNum(Dst); } -TArray FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFlags Flags, bool Mutable) +TArray FWingProperty::GetDetails(UObject* Obj, EPropertyFlags Flags, bool Mutable) { if (!Obj) return {}; @@ -358,7 +399,7 @@ TArray FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFl { if (BP->GeneratedClass == nullptr) { - UWingServer::Printf(TEXT("ERROR: Blueprint '%s' has no GeneratedClass\n"), *Obj->GetName()); + WingOut::Stdout.Printf(TEXT("ERROR: Blueprint '%s' has no GeneratedClass\n"), *Obj->GetName()); return {}; } Obj = BP->GeneratedClass->GetDefaultObject(); @@ -370,13 +411,12 @@ TArray FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFl Obj = Mutable ? Ref->GetMutableTemplate() : Ref->GetImmutableTemplate(); if (!Obj) { - UWingServer::Printf(TEXT("ERROR: Component '%s' has no template\n"), *Ref->VariableName.ToString()); + WingOut::Stdout.Printf(TEXT("ERROR: Component '%s' has no template\n"), *Ref->VariableName.ToString()); return {}; } } - TArray Result; - Collect(Obj->GetClass(), Obj, Result, Flags); + TArray Result = GetAll(Obj, Flags); // If it's a Material Graph node, also collect properties from // the associated material expression. @@ -385,7 +425,7 @@ TArray FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFl { if (UMaterialExpression* Expr = MatNode->MaterialExpression) { - Collect(Expr->GetClass(), Expr, Result, Flags); + GetAll(Expr, Flags, Result); } } @@ -396,7 +436,7 @@ TArray FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFl FWingProperty::Remove(Result, TEXT("Slot")); if (UPanelSlot* Slot = Widget->Slot) { - Collect(Slot->GetClass(), Slot, Result, Flags); + GetAll(Slot, Flags, Result); } } @@ -404,50 +444,29 @@ TArray FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFl } -TArray FWingProperty::FindAllSubstring(const TArray& Props, const FString& Substring) -{ - if (Substring.IsEmpty()) return Props; - TArray Result; - for (const FWingProperty& P : Props) - { - if (WingUtils::FormatName(P.Prop).Contains(Substring, ESearchCase::IgnoreCase)) - Result.Add(P); - } - return Result; -} - -bool FWingProperty::PopulateFromJson(FWingProperty& P, const FJsonObject* Json, bool AllOptional) -{ - FString JsonKey = WingUtils::FormatName(P.Prop); - TSharedPtr Value = Json->TryGetField(JsonKey); - - if (Value == nullptr) - { - bool Optional = AllOptional || P.Prop->HasMetaData(TEXT("Optional")); - if (Optional) return true; - UWingServer::Printf(TEXT("ERROR: Missing required parameter '%s'\n"), *JsonKey); - return false; - } - - return P.SetJson(Value); -} - -bool FWingProperty::PopulateFromJson( - TArray& Props, const FJsonObject* Json, bool AllOptional) +bool FWingProperty::PopulateFromJson(TArray& Props, const FJsonValue& Json, bool AllOptional, WingOut Errors) { bool Ok = true; - // Build a set of known property names for the unknown-field check. - TSet KnownKeys; - for (const FWingProperty& P : Props) - KnownKeys.Add(WingUtils::FormatName(P.Prop)); - - // Check for unknown fields in the JSON - for (const auto& KV : Json->Values) + // Make sure they passed in a JSON object. + TSharedPtr Obj = Json.AsObject(); + if (Obj == nullptr) { - if (!KnownKeys.Contains(KV.Key)) + Errors.Printf(TEXT("property data should be stored in a json object\n")); + return false; + } + + // Build a set of known property names for the unknown-field check. + TSet KnownKeys; + for (const FWingProperty& P : Props) KnownKeys.Add(P->GetFName()); + + // Check for unknown fields in the JSON + for (const auto& KV : Obj->Values) + { + FName Name = WingUtils::CheckInternalizeID(KV.Key, Errors); + if (!KnownKeys.Contains(Name)) { - UWingServer::Printf(TEXT("ERROR: Unknown parameter '%s'\n"), *KV.Key); + Errors.Printf(TEXT("ERROR: Unknown parameter '%s'\n"), *KV.Key); Ok = false; } } @@ -455,23 +474,51 @@ bool FWingProperty::PopulateFromJson( // Populate each property from JSON for (FWingProperty& P : Props) { - if (!PopulateFromJson(P, Json, AllOptional)) Ok = false; + FString JsonKey = WingUtils::FormatName(P.Prop); + TSharedPtr Value = Obj->TryGetField(JsonKey); + if (!Value) + { + bool Optional = AllOptional || P.Prop->HasMetaData(TEXT("Optional")); + if (!Optional) + { + Errors.Printf(TEXT("ERROR: Missing required parameter '%s'\n"), *JsonKey); + Ok = false; + } + continue; + } + if (!P.SetJson(*Value, Errors)) Ok = false; } return Ok; } -bool FWingProperty::PopulateFromJson(UStruct* StructType, void* Container, const FJsonObject* Object) + +bool FWingProperty::IsPinTypeProperty(FProperty* Prop) { - TArray Props = FWingProperty::GetAll(StructType, Container, (EPropertyFlags)0); - return PopulateFromJson(Props, Object); + FStructProperty* StructProp = CastField(Prop); + return StructProp && StructProp->Struct == FEdGraphPinType::StaticStruct(); } -bool FWingProperty::PopulateFromJson(UStruct* StructType, void* Container, const TSharedPtr& Object) + + +void FWingProperty::PrintExpectsReceived(const TCHAR *Type, WingOut Errors) const { - if (!Object.IsValid() || (Object->Type != EJson::Object)) - { - UWingServer::Print(TEXT("ERROR: Expected a JSON object\n")); - return false; - } - return PopulateFromJson(StructType, Container, Object->AsObject().Get()); + Errors.Printf(TEXT("ERROR: '%s' received a %s, but expects %s\n"), + *WingUtils::FormatName(Prop), Type, *Prop->GetCPPType()); } + + +bool FWingProperty::CheckImportTextResult(const FString &Value, WingOut Errors) const +{ + if (FObjectPropertyBase *OProp = CastField(Prop)) + { + uint8 *VP = Prop->ContainerPtrToValuePtr(Container); + UObject *Obj = OProp->GetObjectPropertyValue(VP); + if (Obj == nullptr && Value.TrimStartAndEnd().Compare(TEXT("None"), ESearchCase::IgnoreCase) != 0) + { + Errors.Printf(TEXT("ERROR: Failed to parse '%s' for property '%s'\n"), + *Value, *WingUtils::FormatName(Prop)); + return false; + } + } + return true; +} \ No newline at end of file diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingServer.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingServer.cpp index 704a0aca..1b5eaf4a 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingServer.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingServer.cpp @@ -263,7 +263,7 @@ FString UWingServer::HandleRequest(const FString& Line) { LogCapture.CapturedErrors.Empty(); LogCapture.bEnabled = true; - HandlerOutput.Reset(); + WingOut::StdoutBuffer.Reset(); SuggestedManualSections.Empty(); LastHandler = nullptr; @@ -273,7 +273,7 @@ FString UWingServer::HandleRequest(const FString& Line) LogCapture.bEnabled = false; for (const FString& Msg : LogCapture.CapturedErrors) { - UWingServer::Printf(TEXT("UE_LOG: %s\n"), *Msg); + WingOut::Stdout.Printf(TEXT("UE_LOG: %s\n"), *Msg); } LogCapture.CapturedErrors.Empty(); if (!SuggestedManualSections.IsEmpty()) @@ -281,8 +281,8 @@ FString UWingServer::HandleRequest(const FString& Line) UWingServer::SuggestManual(WingManual::Section::HandlerHelp); WingManual::PrintManual(SuggestedManualSections, LastHandler, true); } - FString Result = HandlerOutput.ToString(); - HandlerOutput.Reset(); + FString Result = WingOut::StdoutBuffer.ToString(); + WingOut::StdoutBuffer.Reset(); for (int32 i = 0; i < Result.Len(); ++i) { if (Result[i] == TEXT('\0')) Result[i] = TEXT(' '); @@ -298,7 +298,7 @@ void UWingServer::TryCallHandler(const FString &Line) FJsonSerializer::Deserialize(Reader, Request); if (!Request.IsValid()) { - UWingServer::Printf(TEXT("Request is not valid JSON")); + WingOut::Stdout.Printf(TEXT("Request is not valid JSON")); return; } @@ -306,8 +306,8 @@ void UWingServer::TryCallHandler(const FString &Line) FString Command; if (!Request->TryGetStringField(TEXT("command"), Command)) { - UWingServer::Printf(TEXT("Request does not contain 'command' parameter")); - UWingServer::Printf(TEXT("We recommend sending command='UserManual'.")); + WingOut::Stdout.Printf(TEXT("Request does not contain 'command' parameter")); + WingOut::Stdout.Printf(TEXT("We recommend sending command='UserManual'.")); return; } Request->RemoveField(TEXT("command")); @@ -316,7 +316,7 @@ void UWingServer::TryCallHandler(const FString &Line) FWingHandlerConfig* Found = FindHandler(Command); if (!Found) { - UWingServer::Printf(TEXT("Unknown command: %s"), *Command); + WingOut::Stdout.Printf(TEXT("Unknown command: %s"), *Command); UWingServer::SuggestManual(WingManual::Section::ImportantCommands); return; } @@ -330,7 +330,7 @@ void UWingServer::TryCallHandler(const FString &Line) // Populate the handler object with the request parameters. WingPropHandle Props; WingPropHandle::Handles Handles = Props.AllProperties(HandlerObj.Get(), true); - if (!WingPropHandle::PopulateFromJson(Handles, *Request, false)) + if (!WingPropHandle::PopulateFromJson(Handles, *Request, false, WingOut::Stdout)) { UWingServer::SuggestManual(WingManual::Section::HandlerHelp); return; @@ -490,3 +490,7 @@ FWingHandlerConfig* UWingServer::FindHandler(const FString& Name) } return nullptr; } + +TStringBuilder<65536> WingOut::StdoutBuffer; +WingOut WingOut::Stdout(&WingOut::StdoutBuffer); +WingOut WingOut::None(nullptr); diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingTypes.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingTypes.cpp index fdd02428..4f569469 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingTypes.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingTypes.cpp @@ -433,124 +433,124 @@ static const FName NAME_TypeSoftClass(TEXT("SoftClass")); static const FName NAME_StartOfType("Start-of-Type"); -void UWingTypes::PrintParseError(WingTokenizer& Tok, const TCHAR* Message) +void UWingTypes::PrintParseError(WingTokenizer& Tok, const TCHAR* Message, WingOut Errors) { FString TypeText(Tok.GetRange(NAME_StartOfType, 1)); - UWingServer::Printf(TEXT("ERROR parsing type '%s' — %s\n"), *TypeText, Message); + Errors.Printf(TEXT("ERROR parsing type '%s' — %s\n"), *TypeText, Message); UWingServer::SuggestManual(WingManual::Section::Types); } -bool UWingTypes::ParseChar(WingTokenizer& Tok, TCHAR c) +bool UWingTypes::ParseChar(WingTokenizer& Tok, TCHAR c, WingOut Errors) { if (!Tok.TokenIs(c)) { - PrintParseError(Tok, *FString::Printf(TEXT("expected '%c'"), c)); + PrintParseError(Tok, *FString::Printf(TEXT("expected '%c'"), c), Errors); return false; } Tok.Advance(); return true; } -bool UWingTypes::ParsePlainIdentifier(WingTokenizer& Tok, FEdGraphPinType& OutType) +bool UWingTypes::ParsePlainIdentifier(WingTokenizer& Tok, FEdGraphPinType& OutType, WingOut Errors) { if (!Tok.TokenIs(Tok.Identifier)) { - PrintParseError(Tok, TEXT("expected identifier")); + PrintParseError(Tok, TEXT("expected identifier"), Errors); return false; } FString Name = Tok.NextName().ToString(); Tok.Advance(); - return ResolveShortName(Tok, Name, OutType); + return ResolveShortName(Tok, Name, OutType, Errors); } -bool UWingTypes::ParseWrapped(WingTokenizer& Tok, FName Wrapper, FEdGraphPinType& OutType) +bool UWingTypes::ParseWrapped(WingTokenizer& Tok, FName Wrapper, FEdGraphPinType& OutType, WingOut Errors) { Tok.Advance(); - if (!ParseChar(Tok, '<')) return false; - if (!ParsePlainIdentifier(Tok, OutType)) return false; + if (!ParseChar(Tok, '<', Errors)) return false; + if (!ParsePlainIdentifier(Tok, OutType, Errors)) return false; if (OutType.PinCategory != UEdGraphSchema_K2::PC_Object) { - PrintParseError(Tok, *FString::Printf(TEXT("'%s' is not an object type"), *OutType.PinSubCategoryObject->GetName())); + PrintParseError(Tok, *FString::Printf(TEXT("'%s' is not an object type"), *OutType.PinSubCategoryObject->GetName()), Errors); return false; } - if (!ParseChar(Tok, '>')) return false; + if (!ParseChar(Tok, '>', Errors)) return false; OutType.PinCategory = Wrapper; return true; } -bool UWingTypes::ParseMaybeWrapped(WingTokenizer& Tok, FEdGraphPinType& OutType) +bool UWingTypes::ParseMaybeWrapped(WingTokenizer& Tok, FEdGraphPinType& OutType, WingOut Errors) { if (Tok.TokenIs(NAME_TypeSoft, '<')) { - return ParseWrapped(Tok, UEdGraphSchema_K2::PC_SoftObject, OutType); + return ParseWrapped(Tok, UEdGraphSchema_K2::PC_SoftObject, OutType, Errors); } else if (Tok.TokenIs(NAME_TypeClass, '<')) { - return ParseWrapped(Tok, UEdGraphSchema_K2::PC_Class, OutType); + return ParseWrapped(Tok, UEdGraphSchema_K2::PC_Class, OutType, Errors); } else if (Tok.TokenIs(NAME_TypeSoftClass, '<')) { - return ParseWrapped(Tok, UEdGraphSchema_K2::PC_SoftClass, OutType); + return ParseWrapped(Tok, UEdGraphSchema_K2::PC_SoftClass, OutType, Errors); } - else return ParsePlainIdentifier(Tok, OutType); + else return ParsePlainIdentifier(Tok, OutType, Errors); } -bool UWingTypes::ParseArrayOrSet(WingTokenizer& Tok, FEdGraphPinType& OutType) +bool UWingTypes::ParseArrayOrSet(WingTokenizer& Tok, FEdGraphPinType& OutType, WingOut Errors) { Tok.Advance(); - if (!ParseChar(Tok, '<')) return false; - if (!ParseMaybeWrapped(Tok, OutType)) return false; - if (!ParseChar(Tok, '>')) return false; + if (!ParseChar(Tok, '<', Errors)) return false; + if (!ParseMaybeWrapped(Tok, OutType, Errors)) return false; + if (!ParseChar(Tok, '>', Errors)) return false; return true; } -bool UWingTypes::ParseMap(WingTokenizer& Tok, FEdGraphPinType& OutType) +bool UWingTypes::ParseMap(WingTokenizer& Tok, FEdGraphPinType& OutType, WingOut Errors) { Tok.Advance(); - if (!ParseChar(Tok, '<')) return false; - if (!ParsePlainIdentifier(Tok, OutType)) return false; - if (!ParseChar(Tok, ',')) return false; + if (!ParseChar(Tok, '<', Errors)) return false; + if (!ParsePlainIdentifier(Tok, OutType, Errors)) return false; + if (!ParseChar(Tok, ',', Errors)) return false; FEdGraphPinType ValueType; - if (!ParseMaybeWrapped(Tok, ValueType)) return false; + if (!ParseMaybeWrapped(Tok, ValueType, Errors)) return false; OutType.PinValueType.TerminalCategory = ValueType.PinCategory; OutType.PinValueType.TerminalSubCategory = ValueType.PinSubCategory; OutType.PinValueType.TerminalSubCategoryObject = ValueType.PinSubCategoryObject; - if (!ParseChar(Tok, '>')) return false; + if (!ParseChar(Tok, '>', Errors)) return false; return true; } -bool UWingTypes::ParseType(WingTokenizer& Tok, FEdGraphPinType& OutType) +bool UWingTypes::ParseType(WingTokenizer& Tok, FEdGraphPinType& OutType, WingOut Errors) { if (Tok.TokenIs(NAME_TypeArray, '<')) { OutType.ContainerType = EPinContainerType::Array; - if (!ParseArrayOrSet(Tok, OutType)) return false; + if (!ParseArrayOrSet(Tok, OutType, Errors)) return false; } else if (Tok.TokenIs(NAME_TypeSet, '<')) { OutType.ContainerType = EPinContainerType::Set; - if (!ParseArrayOrSet(Tok, OutType)) return false; + if (!ParseArrayOrSet(Tok, OutType, Errors)) return false; } else if (Tok.TokenIs(NAME_TypeMap, '<')) { OutType.ContainerType = EPinContainerType::Map; - if (!ParseMap(Tok, OutType)) return false; + if (!ParseMap(Tok, OutType, Errors)) return false; } else { - if (!ParseMaybeWrapped(Tok, OutType)) return false; + if (!ParseMaybeWrapped(Tok, OutType, Errors)) return false; } return true; } -bool UWingTypes::ResolveShortName(WingTokenizer& Tok, const FString &Name, FEdGraphPinType &OutType) +bool UWingTypes::ResolveShortName(WingTokenizer& Tok, const FString &Name, FEdGraphPinType &OutType, WingOut Errors) { Info* TypeInfo = ShortToInfo.Find(Name.ToLower()); if (!TypeInfo) { - PrintParseError(Tok, *FString::Printf(TEXT("unrecognized type '%s'"), *Name)); + PrintParseError(Tok, *FString::Printf(TEXT("unrecognized type '%s'"), *Name), Errors); return false; } @@ -566,7 +566,7 @@ bool UWingTypes::ResolveShortName(WingTokenizer& Tok, const FString &Name, FEdGr UObject* Obj = LoadObject(nullptr, *TypeInfo->PinSubCategoryObject); if (!Obj) { - PrintParseError(Tok, *FString::Printf(TEXT("failed to load type '%s' at path '%s'"), *Name, *TypeInfo->PinSubCategoryObject)); + PrintParseError(Tok, *FString::Printf(TEXT("failed to load type '%s' at path '%s'"), *Name, *TypeInfo->PinSubCategoryObject), Errors); return false; } @@ -605,7 +605,7 @@ bool UWingTypes::ResolveShortName(WingTokenizer& Tok, const FString &Name, FEdGr // --------------------------------------------------------------------------- -bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, const Requirements &Require, bool CheckEOF) +bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, const Requirements &Require, bool CheckEOF, WingOut Errors) { UWingTypes* Types = GEditor->GetEditorSubsystem(); check(Types); @@ -615,19 +615,19 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con !Require.Blueprintable.IsSet() || !Require.AllowContainer.IsSet()) { - UWingServer::Printf(TEXT("ERROR: TextToType called with underspecified Requirements list.\n")); + Errors.Printf(TEXT("ERROR: TextToType called with underspecified Requirements list.\n")); return false; } OutPinType = FEdGraphPinType(); - if (!Types->ParseType(Tok, OutPinType)) + if (!Types->ParseType(Tok, OutPinType, Errors)) { OutPinType = FEdGraphPinType(); return false; } if (CheckEOF && (Tok.NextType() != 0)) { - PrintParseError(Tok, TEXT("Extra tokens at end of Type name")); + PrintParseError(Tok, TEXT("Extra tokens at end of Type name"), Errors); OutPinType = FEdGraphPinType(); return false; } @@ -636,7 +636,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con if (OutPinType.IsContainer()) { FString Text(Tok.GetRange(NAME_StartOfType, 0)); - UWingServer::Printf(TEXT("ERROR: Type '%s' is a container, not allowed here\n"), *Text); + Errors.Printf(TEXT("ERROR: Type '%s' is a container, not allowed here\n"), *Text); UWingServer::SuggestManual(WingManual::Section::HandlerHelp); OutPinType = FEdGraphPinType(); return false; } @@ -646,7 +646,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con { if (OutPinType.PinCategory != Require.PinCategory) { - UWingServer::Printf(TEXT("ERROR: Need a type which is an %s, got a %s instead.\n"), + Errors.Printf(TEXT("ERROR: Need a type which is an %s, got a %s instead.\n"), *Require.PinCategory.ToString(), *OutPinType.PinCategory.ToString()); UWingServer::SuggestManual(WingManual::Section::HandlerHelp); OutPinType = FEdGraphPinType(); return false; @@ -657,7 +657,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con { if (!IsChildOf(OutPinType, Require.IsChildOf)) { - UWingServer::Printf(TEXT("ERROR: Type must derive from %s\n"), *WingUtils::FormatName(Require.IsChildOf)); + Errors.Printf(TEXT("ERROR: Type must derive from %s\n"), *WingUtils::FormatName(Require.IsChildOf)); UWingServer::SuggestManual(WingManual::Section::HandlerHelp); OutPinType = FEdGraphPinType(); return false; } @@ -668,7 +668,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con if (!IsBlueprintType(OutPinType)) { FString Text(Tok.GetRange(NAME_StartOfType, 0)); - UWingServer::Printf(TEXT("ERROR: Not a blueprint type: %s\n"), *Text); + Errors.Printf(TEXT("ERROR: Not a blueprint type: %s\n"), *Text); UWingServer::SuggestManual(WingManual::Section::HandlerHelp); OutPinType = FEdGraphPinType(); return false; } @@ -679,7 +679,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con if (!IsBlueprintable(OutPinType)) { FString Text(Tok.GetRange(NAME_StartOfType, 0)); - UWingServer::Printf(TEXT("ERROR: Not a blueprintable type: %s\n"), *Text); + Errors.Printf(TEXT("ERROR: Not a blueprintable type: %s\n"), *Text); UWingServer::SuggestManual(WingManual::Section::HandlerHelp); OutPinType = FEdGraphPinType(); return false; } @@ -688,36 +688,36 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con return true; } -bool UWingTypes::TextToType(const FString &Text, FEdGraphPinType& OutPinType, const Requirements &Require) +bool UWingTypes::TextToType(const FString &Text, FEdGraphPinType& OutPinType, const Requirements &Require, WingOut Errors) { WingTokenizer Tok(Text); - return TextToType(Tok, OutPinType, Require, true); + return TextToType(Tok, OutPinType, Require, true, Errors); } -UClass* UWingTypes::TextToOneObjectType(const FString& Text, const Requirements &Require) +UClass* UWingTypes::TextToOneObjectType(const FString& Text, const Requirements &Require, WingOut Errors) { FEdGraphPinType PinType; - if (!TextToType(Text, PinType, Require)) return nullptr; + if (!TextToType(Text, PinType, Require, Errors)) return nullptr; UClass* Class = Cast(PinType.PinSubCategoryObject.Get()); if ((!Class) || (PinType.PinCategory != UEdGraphSchema_K2::PC_Object) || (PinType.IsContainer())) { - UWingServer::Printf(TEXT("ERROR: '%s' is not an object class\n"), *Text); + Errors.Printf(TEXT("ERROR: '%s' is not an object class\n"), *Text); UWingServer::SuggestManual(WingManual::Section::Types); return nullptr; } return Class; } -UClass* UWingTypes::TextToOneInterfaceType(const FString& Text, const Requirements &Require) +UClass* UWingTypes::TextToOneInterfaceType(const FString& Text, const Requirements &Require, WingOut Errors) { FEdGraphPinType PinType; - if (!TextToType(Text, PinType, Require)) return nullptr; + if (!TextToType(Text, PinType, Require, Errors)) return nullptr; UClass* Class = Cast(PinType.PinSubCategoryObject.Get()); if ((!Class) || (PinType.PinCategory != UEdGraphSchema_K2::PC_Interface) || (PinType.IsContainer())) { - UWingServer::Printf(TEXT("ERROR: '%s' is not an interface class\n"), *Text); + Errors.Printf(TEXT("ERROR: '%s' is not an interface class\n"), *Text); UWingServer::SuggestManual(WingManual::Section::Types); return nullptr; } diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp index da36a9e4..2c7de536 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp @@ -61,24 +61,24 @@ FString WingUtils::ExternalizeID(FName Name) return WingTokenizer::ExternalizeID(Name); } -FName WingUtils::CheckInternalizeID(const FString &ExternalID) +FName WingUtils::CheckInternalizeID(const FString &ExternalID, WingOut Errors) { FString Error; FName InternalID = WingTokenizer::TryInternalizeID(ExternalID, Error); if (!Error.IsEmpty()) { - UWingServer::Printf(TEXT("%s\n"), *Error); + Errors.Printf(TEXT("%s\n"), *Error); UWingServer::SuggestManual(WingManual::Section::EscapeSequences); } return InternalID; } -FName WingUtils::CheckProposedName(const FString &ExternalID) +FName WingUtils::CheckProposedName(const FString &ExternalID, WingOut Errors) { - FName InternalID = CheckInternalizeID(ExternalID); + FName InternalID = CheckInternalizeID(ExternalID, Errors); if (!InternalID.IsNone() && !WingTokenizer::WouldExternalizeReadably(InternalID)) { - UWingServer::Printf(TEXT("ERROR: id %s would not be a readable id, may not create item with this name"), + Errors.Printf(TEXT("ERROR: id %s would not be a readable id, may not create item with this name"), *ExternalID); UWingServer::SuggestManual(WingManual::Section::EscapeSequences); return FName(); @@ -341,7 +341,7 @@ FString WingUtils::EnumToString(UEnum* Enum, int64 Value) return Enum->GetNameStringByValue(Value); } -bool WingUtils::StringToEnum(UEnum* Enum, const FString& Str, int64& OutValue) +bool WingUtils::StringToEnum(UEnum* Enum, const FString& Str, int64& OutValue, WingOut Errors) { int32 Index = Enum->GetIndexByNameString(Str); if (Index == INDEX_NONE) @@ -352,7 +352,7 @@ bool WingUtils::StringToEnum(UEnum* Enum, const FString& Str, int64& OutValue) } if (Index == INDEX_NONE) { - UWingServer::Printf(TEXT("ERROR: '%s' is not a valid value for %s\n"), *Str, *Enum->GetName()); + Errors.Printf(TEXT("ERROR: '%s' is not a valid value for %s\n"), *Str, *Enum->GetName()); OutValue = 0; return false; } @@ -365,53 +365,53 @@ bool WingUtils::StringToEnum(UEnum* Enum, const FString& Str, int64& OutValue) // Common Error Reporting // ============================================================ -bool WingUtils::CheckExactlyOneNamed(int Count, const TCHAR *Kind, const FString &Name) +bool WingUtils::CheckExactlyOneNamed(int Count, const TCHAR *Kind, const FString &Name, WingOut Errors) { if (Count == 0) { - UWingServer::Printf(TEXT("Could not find a %s named %s.\n"), Kind, *Name); + Errors.Printf(TEXT("Could not find a %s named %s.\n"), Kind, *Name); return false; } if (Count > 1) { - UWingServer::Printf(TEXT("More than one %s named %s\n"), Kind, *Name); + Errors.Printf(TEXT("More than one %s named %s\n"), Kind, *Name); return false; } return true; } -bool WingUtils::CheckExactlyOneNamed(int Count, const TCHAR *Kind, FName Name) +bool WingUtils::CheckExactlyOneNamed(int Count, const TCHAR *Kind, FName Name, WingOut Errors) { - return CheckExactlyOneNamed(Count, Kind, ExternalizeID(Name)); + return CheckExactlyOneNamed(Count, Kind, ExternalizeID(Name), Errors); } -bool WingUtils::CheckExactlyNoneNamed(int Count, const TCHAR *Kind, const FString &Name) +bool WingUtils::CheckExactlyNoneNamed(int Count, const TCHAR *Kind, const FString &Name, WingOut Errors) { if (Count > 0) { - UWingServer::Printf(TEXT("A %s named %s already exists."), Kind, *Name); + Errors.Printf(TEXT("A %s named %s already exists."), Kind, *Name); return false; } return true; } -bool WingUtils::CheckExactlyNoneNamed(int Count, const TCHAR *Kind, FName Name) +bool WingUtils::CheckExactlyNoneNamed(int Count, const TCHAR *Kind, FName Name, WingOut Errors) { - return CheckExactlyNoneNamed(Count, Kind, ExternalizeID(Name)); + return CheckExactlyNoneNamed(Count, Kind, ExternalizeID(Name), Errors); } -bool WingUtils::CheckCanRename(UEdGraphNode* Node, const FString &Name) +bool WingUtils::CheckCanRename(UEdGraphNode* Node, const FString &Name, WingOut Errors) { if (!Node->bCanRenameNode) { - UWingServer::Printf(TEXT("ERROR: Node %s does not support renaming.\n"), *FormatName(Node)); + Errors.Printf(TEXT("ERROR: Node %s does not support renaming.\n"), *FormatName(Node)); return false; } TSharedPtr Validator = FNameValidatorFactory::MakeValidator(Node); EValidatorResult Result = Validator->IsValid(Name, false); if (Result != EValidatorResult::Ok && Result != EValidatorResult::ExistingName) { - UWingServer::Printf(TEXT("ERROR: %s\n"), *INameValidatorInterface::GetErrorString(Name, Result)); + Errors.Printf(TEXT("ERROR: %s\n"), *INameValidatorInterface::GetErrorString(Name, Result)); return false; } return true; @@ -573,7 +573,7 @@ UAnimationStateMachineGraph* WingUtils::FindStateMachineGraph(UBlueprint* BP, co return nullptr; } -UAnimStateNode* WingUtils::FindStateByName(UAnimationStateMachineGraph* SMGraph, const FString& StateName) +UAnimStateNode* WingUtils::FindStateByName(UAnimationStateMachineGraph* SMGraph, const FString& StateName, WingOut Errors) { for (UEdGraphNode* Node : SMGraph->Nodes) { @@ -585,7 +585,7 @@ UAnimStateNode* WingUtils::FindStateByName(UAnimationStateMachineGraph* SMGraph, } } } - UWingServer::Printf(TEXT("ERROR: State '%s' not found in graph '%s'\n"), *StateName, *SMGraph->GetName()); + Errors.Printf(TEXT("ERROR: State '%s' not found in graph '%s'\n"), *StateName, *SMGraph->GetName()); return nullptr; } diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp index 6ca2fe94..edaff310 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp @@ -26,12 +26,12 @@ static TSet Flags_BlueprintVariables = { Flag_InstanceEditable, Flag_Blue -void WingVariableList::Print(FStringBuilderBase &Out) +void WingVariableList::Print(WingOut Out) { if (Variables.IsEmpty()) return; - Out.Append(ListName); - Out.AppendChar(':'); - Out.AppendChar('\n'); + Out.Print(ListName); + Out.PrintChar(':'); + Out.PrintChar('\n'); for (const Var& V : Variables) { FString TypeStr = UWingTypes::TypeToText(V.Type); @@ -51,23 +51,23 @@ void WingVariableList::Print(FStringBuilderBase &Out) } // Print: type name (flags) = defaultvalue - Out.Appendf(TEXT(" %s %s"), *TypeStr, *NameStr); + Out.Printf(TEXT(" %s %s"), *TypeStr, *NameStr); if (!FlagsStr.IsEmpty()) - Out.Appendf(TEXT(" (%s)"), *FlagsStr); + Out.Printf(TEXT(" (%s)"), *FlagsStr); if (!V.DefaultValue.IsEmpty()) - Out.Appendf(TEXT(" = %s"), *V.DefaultValue); - Out.Append(TEXT("\n")); + Out.Printf(TEXT(" = %s"), *V.DefaultValue); + Out.Print(TEXT("\n")); } } -void WingVariableList::PrintCompact(FStringBuilderBase &Out) +void WingVariableList::PrintCompact(WingOut Out) { bool First = true; for (const Var& V : Variables) { - if (!First) Out << TEXT(","); + if (!First) Out.PrintChar(','); First = false; - Out << UWingTypes::TypeToText(V.Type) << TEXT(" ") << WingUtils::ExternalizeID(V.Name); + Out.Printf(TEXT("%s %s"), *UWingTypes::TypeToText(V.Type), *WingUtils::ExternalizeID(V.Name)); } } @@ -80,11 +80,11 @@ void WingVariableList::ClearLinks() } } -bool WingVariableList::CheckSanity(const TSet &GoodFlags, bool Allow) +bool WingVariableList::CheckSanity(const TSet &GoodFlags, bool Allow, WingOut Errors) { if ((!Allow) && (!Variables.IsEmpty())) { - UWingServer::Printf(TEXT("In this context, %s must be empty."), ListName); + Errors.Printf(TEXT("In this context, %s must be empty."), ListName); return false; } for (const Var &Variable : Variables) @@ -93,20 +93,20 @@ bool WingVariableList::CheckSanity(const TSet &GoodFlags, bool Allow) FString TypeText = UWingTypes::TypeToText(Variable.Type); if (TypeText.IsEmpty()) { - UWingServer::Printf(TEXT("Type of variable %s is not valid for unknown reasons\n"), *VarName); + Errors.Printf(TEXT("Type of variable %s is not valid for unknown reasons\n"), *VarName); return false; } if (!UWingTypes::IsBlueprintType(Variable.Type)) { - UWingServer::Printf(TEXT("Type is not a valid BlueprintType: %s %s\n"), *TypeText, *VarName); + Errors.Printf(TEXT("Type is not a valid BlueprintType: %s %s\n"), *TypeText, *VarName); return false; } for (FName Flag : Variable.Flags) { if (!GoodFlags.Contains(Flag)) { - UWingServer::Printf(TEXT("Flag %s is not valid here. Valid flags are:"), *Flag.ToString()); - for (FName Rel : GoodFlags) UWingServer::Printf(TEXT(" %s\n"), *Rel.ToString()); + Errors.Printf(TEXT("Flag %s is not valid here. Valid flags are:"), *Flag.ToString()); + for (FName Rel : GoodFlags) Errors.Printf(TEXT(" %s\n"), *Rel.ToString()); return false; } } @@ -114,7 +114,7 @@ bool WingVariableList::CheckSanity(const TSet &GoodFlags, bool Allow) return true; } -bool WingVariableList::ParseString(const FString &Input) +bool WingVariableList::ParseString(const FString &Input, WingOut Errors) { Variables.Empty(); @@ -127,14 +127,14 @@ bool WingVariableList::ParseString(const FString &Input) if (Tok.NextType() == 0) continue; Var V; V.DefaultSpecified = false; - if (!ParseOneVariable(Tok, V)) return false; + if (!ParseOneVariable(Tok, V, Errors)) return false; Variables.Add(MoveTemp(V)); } return true; } -bool WingVariableList::ParseNamesString(const FString &Input) +bool WingVariableList::ParseNamesString(const FString &Input, WingOut Errors) { Variables.Empty(); WingTokenizer Tok(Input); @@ -151,27 +151,27 @@ bool WingVariableList::ParseNamesString(const FString &Input) if (!Tok.TokenIs(0)) { Tok.SaveCursor(NAME_None); - UWingServer::Printf(TEXT("Unexpected token %s in variable list"), + Errors.Printf(TEXT("Unexpected token %s in variable list"), *FString(Tok.GetRange(NAME_None, 1))); return false; } return true; } -bool WingVariableList::ParseOneVariable(WingTokenizer &Tok, Var &V) +bool WingVariableList::ParseOneVariable(WingTokenizer &Tok, Var &V, WingOut Errors) { // Parse type. UWingTypes::Requirements Req; Req.BlueprintType = true; Req.Blueprintable = false; Req.AllowContainer = true; - if (!UWingTypes::TextToType(Tok, V.Type, Req, false)) + if (!UWingTypes::TextToType(Tok, V.Type, Req, false, Errors)) return false; // Parse name. if (Tok.NextType() != Tok.Identifier) { - UWingServer::Print(TEXT("ERROR: Expected variable name after type\n")); + Errors.Print(TEXT("ERROR: Expected variable name after type\n")); return false; } V.Name = Tok.NextName(); @@ -180,7 +180,7 @@ bool WingVariableList::ParseOneVariable(WingTokenizer &Tok, Var &V) // Parse optional flags: (flag1, flag2, ...) if (Tok.TokenIs('(')) { - if (!ParseVariableFlags(Tok, V.Flags)) return false; + if (!ParseVariableFlags(Tok, V.Flags, Errors)) return false; } // Parse optional default value: = rest-of-line @@ -195,7 +195,7 @@ bool WingVariableList::ParseOneVariable(WingTokenizer &Tok, Var &V) if (Tok.NextType() != 0) { Tok.SaveCursor(NAME_None); - UWingServer::Printf(TEXT("ERROR: Unexpected token after variable declaration: '%s'\n"), + Errors.Printf(TEXT("ERROR: Unexpected token after variable declaration: '%s'\n"), *FString(Tok.GetRange(NAME_None, 1))); return false; } @@ -203,7 +203,7 @@ bool WingVariableList::ParseOneVariable(WingTokenizer &Tok, Var &V) return true; } -bool WingVariableList::ParseVariableFlags(WingTokenizer &Tok, TSet &Out) +bool WingVariableList::ParseVariableFlags(WingTokenizer &Tok, TSet &Out, WingOut Errors) { Tok.Advance(); // Step over open-paren while (Tok.TokenIs(Tok.Identifier)) @@ -216,7 +216,7 @@ bool WingVariableList::ParseVariableFlags(WingTokenizer &Tok, TSet &Out) if (!Tok.TokenIs(')')) { Tok.SaveCursor(NAME_None); - UWingServer::Printf(TEXT("ERROR: flag list contains invalid token '%s'\n"), + Errors.Printf(TEXT("ERROR: flag list contains invalid token '%s'\n"), *FString(Tok.GetRange(NAME_None, 1))); return false; } @@ -240,7 +240,7 @@ void WingVariables::ClearLinks() OutputVariables.ClearLinks(); } -void WingVariables::Print(FStringBuilderBase &Out) +void WingVariables::Print(WingOut Out) { BlueprintVariables.Print(Out); LocalVariables.Print(Out); @@ -248,13 +248,13 @@ void WingVariables::Print(FStringBuilderBase &Out) OutputVariables.Print(Out); } -void WingVariables::Load() +void WingVariables::Load(WingOut Errors) { Empty(); if (Blueprint != nullptr) return LoadBlueprint(); if (Graph != nullptr) return LoadGraph(); if (CustomEvent != nullptr) return LoadCustomEvent(); - ErrorNoBackingStore(); + ErrorNoBackingStore(Errors); } void WingVariables::LoadBlueprint() @@ -356,25 +356,25 @@ void WingVariables::LoadCustomEvent() LoadEditablePinBase(CustomEvent, InputVariables); } -bool WingVariables::Check() +bool WingVariables::Check(WingOut Errors) { - if (Blueprint) return CheckBlueprint(); - if (Graph) return CheckGraph(); - if (CustomEvent) return CheckCustomEvent(); - return ErrorNoBackingStore(); + if (Blueprint) return CheckBlueprint(Errors); + if (Graph) return CheckGraph(Errors); + if (CustomEvent) return CheckCustomEvent(Errors); + return ErrorNoBackingStore(Errors); } -bool WingVariables::CheckBlueprint() +bool WingVariables::CheckBlueprint(WingOut Errors) { bool OK = true; - if (!BlueprintVariables.CheckSanity(Flags_BlueprintVariables, true)) OK = false; - if (!LocalVariables.CheckSanity(Flags_None, false)) OK = false; - if (!InputVariables.CheckSanity(Flags_None, false)) OK = false; - if (!OutputVariables.CheckSanity(Flags_None, false)) OK = false; + if (!BlueprintVariables.CheckSanity(Flags_BlueprintVariables, true, Errors)) OK = false; + if (!LocalVariables.CheckSanity(Flags_None, false, Errors)) OK = false; + if (!InputVariables.CheckSanity(Flags_None, false, Errors)) OK = false; + if (!OutputVariables.CheckSanity(Flags_None, false, Errors)) OK = false; return OK; } -bool WingVariables::CheckGraph() +bool WingVariables::CheckGraph(WingOut Errors) { EGraphType T = Graph->GetSchema()->GetGraphType(Graph); bool AllowLocal = (T == EGraphType::GT_Function); @@ -382,56 +382,56 @@ bool WingVariables::CheckGraph() bool AllowOutput = (T == EGraphType::GT_Function) || (T == EGraphType::GT_Macro); if ((!AllowLocal) && (!AllowInput) && (!AllowOutput)) { - UWingServer::Printf(TEXT("This graph type has no variables.")); + Errors.Printf(TEXT("This graph type has no variables.")); return false; } bool OK = true; - if (!BlueprintVariables.CheckSanity(Flags_None, false)) OK = false; - if (!LocalVariables.CheckSanity(Flags_None, AllowLocal)) OK = false; - if (!InputVariables.CheckSanity(Flags_None, AllowInput)) OK = false; - if (!OutputVariables.CheckSanity(Flags_None, AllowOutput)) OK = false; + if (!BlueprintVariables.CheckSanity(Flags_None, false, Errors)) OK = false; + if (!LocalVariables.CheckSanity(Flags_None, AllowLocal, Errors)) OK = false; + if (!InputVariables.CheckSanity(Flags_None, AllowInput, Errors)) OK = false; + if (!OutputVariables.CheckSanity(Flags_None, AllowOutput, Errors)) OK = false; return OK; } -bool WingVariables::CheckCustomEvent() +bool WingVariables::CheckCustomEvent(WingOut Errors) { 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; + if (!BlueprintVariables.CheckSanity(Flags_None, false, Errors)) OK = false; + if (!LocalVariables.CheckSanity(Flags_None, false, Errors)) OK = false; + if (!InputVariables.CheckSanity(Flags_None, true, Errors)) OK = false; + if (!OutputVariables.CheckSanity(Flags_None, false, Errors)) OK = false; return OK; } -bool WingVariables::Modify() +bool WingVariables::Modify(WingOut Errors) { - if (Blueprint) return ModifyBlueprint(); - if (Graph) return ModifyGraph(); - if (CustomEvent) return ModifyCustomEvent(); - return ErrorNoBackingStore(); + if (Blueprint) return ModifyBlueprint(Errors); + if (Graph) return ModifyGraph(Errors); + if (CustomEvent) return ModifyCustomEvent(Errors); + return ErrorNoBackingStore(Errors); } -bool WingVariables::ModifyBlueprint() +bool WingVariables::ModifyBlueprint(WingOut Errors) { - if (!CheckBlueprint()) return false; - if (LinkBlueprintVariables()) return false; - for (Var &V : BlueprintVariables.Variables) + if (!CheckBlueprint(Errors)) return false; + if (LinkBlueprintVariables(Errors)) return false; + for (Var &V : BlueprintVariables.Variables) { V.BPVar->VarType = V.Type; ModifyBlueprintVariableFlags(V); } - if (!ModifyBlueprintDefaults()) return false; + if (!ModifyBlueprintDefaults(Errors)) return false; return true; } -bool WingVariables::LinkBlueprintVariables() +bool WingVariables::LinkBlueprintVariables(WingOut Errors) { ClearLinks(); for (Var &V : BlueprintVariables.Variables) { V.BPVar = WingUtils::FindOneWithInternalID( - V.Name, Blueprint->NewVariables, TEXT("non-inherited variable")); + V.Name, Blueprint->NewVariables, TEXT("non-inherited variable"), Errors); if (V.BPVar == nullptr) return false; } return true; @@ -468,7 +468,7 @@ void WingVariables::ModifyBlueprintVariableFlags(Var &Input) Out.RemoveMetaData(FBlueprintMetadata::MD_Private); } -bool WingVariables::ModifyBlueprintDefaults() +bool WingVariables::ModifyBlueprintDefaults(WingOut Errors) { bool AnySpecified = false; for (Var &Input : BlueprintVariables.Variables) @@ -479,7 +479,7 @@ bool WingVariables::ModifyBlueprintDefaults() UObject *CDO = WingUtils::GetGeneratedCDO(Blueprint); if (!CDO) { - UWingServer::Printf(TEXT("Blueprint didn't compile, cannot store default values")); + Errors.Printf(TEXT("Blueprint didn't compile, cannot store default values")); return false; } @@ -490,56 +490,56 @@ bool WingVariables::ModifyBlueprintDefaults() FProperty* Prop = CDO->GetClass()->FindPropertyByName(Input.Name); if (!Prop) { - UWingServer::Printf(TEXT("Variable exists in blueprint, but not the generated class, which is weird: %s."), + Errors.Printf(TEXT("Variable exists in blueprint, but not the generated class, which is weird: %s."), *WingTokenizer::ExternalizeID(Input.Name)); return false; } - if (!FWingProperty(Prop, CDO).SetText(Input.DefaultValue)) return false; + if (!FWingProperty(Prop, CDO).SetText(Input.DefaultValue, Errors)) return false; } } return true; } -bool WingVariables::ModifyGraph() +bool WingVariables::ModifyGraph(WingOut Errors) { - if (!CheckGraph()) return false; + if (!CheckGraph(Errors)) return false; ClearLinks(); UK2Node_EditablePinBase *InputNode, *OutputNode; UK2Node_FunctionEntry *LocalNode; - if (!GetGraphNodes(InputNode, OutputNode, LocalNode)) return false; + if (!GetGraphNodes(InputNode, OutputNode, LocalNode, Errors)) return false; for (Var &V : LocalVariables.Variables) { FBPVariableDescription *Desc = - WingUtils::FindOneWithInternalID(V.Name, LocalNode->LocalVariables, TEXT("local variable")); + WingUtils::FindOneWithInternalID(V.Name, LocalNode->LocalVariables, TEXT("local variable"), Errors); if (Desc == nullptr) return false; Desc->VarType = V.Type; if (V.DefaultSpecified) Desc->DefaultValue = V.DefaultValue; } - if (!ModifyEditablePinBase(InputVariables, InputNode)) return false; - if (!ModifyEditablePinBase(OutputVariables, OutputNode)) return false; + if (!ModifyEditablePinBase(InputVariables, InputNode, Errors)) return false; + if (!ModifyEditablePinBase(OutputVariables, OutputNode, Errors)) return false; if (InputNode) InputNode->ReconstructNode(); if (OutputNode) OutputNode->ReconstructNode(); return true; } -bool WingVariables::ModifyCustomEvent() +bool WingVariables::ModifyCustomEvent(WingOut Errors) { - if (!CheckCustomEvent()) return false; + if (!CheckCustomEvent(Errors)) return false; ClearLinks(); - if (!ModifyEditablePinBase(InputVariables, CustomEvent)) return false; + if (!ModifyEditablePinBase(InputVariables, CustomEvent, Errors)) return false; CustomEvent->ReconstructNode(); return true; } -bool WingVariables::ModifyEditablePinBase(WingVariableList &List, UK2Node_EditablePinBase *Node) +bool WingVariables::ModifyEditablePinBase(WingVariableList &List, UK2Node_EditablePinBase *Node, WingOut Errors) { for (Var &V : List.Variables) { TSharedPtr *Found = - WingUtils::FindOneWithInternalID(V.Name, Node->UserDefinedPins, List.ListName); + WingUtils::FindOneWithInternalID(V.Name, Node->UserDefinedPins, List.ListName, Errors); if (!Found) return false; (*Found)->PinType = V.Type; if (V.DefaultSpecified) (*Found)->PinDefaultValue = V.DefaultValue; @@ -550,7 +550,8 @@ bool WingVariables::ModifyEditablePinBase(WingVariableList &List, UK2Node_Editab bool WingVariables::GetGraphNodes( UK2Node_EditablePinBase *&InputNode, UK2Node_EditablePinBase *&OutputNode, - UK2Node_FunctionEntry *&LocalNode) + UK2Node_FunctionEntry *&LocalNode, + WingOut Errors) { // In theory, none of these errors should trigger, because // we call CheckSanity before calling this function. But @@ -563,22 +564,22 @@ bool WingVariables::GetGraphNodes( FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, Inputs, Outputs); if (!Inputs.IsValid()) { - UWingServer::Printf(TEXT("ERROR: no function entry node for graph.")); + Errors.Printf(TEXT("ERROR: no function entry node for graph.")); return false; - } + } if (!Outputs.IsValid() && (!OutputVariables.Variables.IsEmpty())) { Outputs = FBlueprintEditorUtils::FindOrCreateFunctionResultNode(Inputs.Get()); if (!Outputs.IsValid()) { - UWingServer::Printf(TEXT("ERROR: couldn't create result node for graph.")); + Errors.Printf(TEXT("ERROR: couldn't create result node for graph.")); return false; } } UK2Node_FunctionEntry *Locals = Cast(Inputs.Get()); if (!Locals && (!LocalVariables.Variables.IsEmpty())) { - UWingServer::Printf(TEXT("ERROR: function doesn't have a proper entry node for local variables")); + Errors.Printf(TEXT("ERROR: function doesn't have a proper entry node for local variables")); return false; } InputNode = Inputs.Get(); @@ -587,65 +588,65 @@ bool WingVariables::GetGraphNodes( return true; } -bool WingVariables::Create() +bool WingVariables::Create(WingOut Errors) { - if (Blueprint) return CreateBlueprint(); - if (Graph) return CreateGraph(); - if (CustomEvent) return CreateCustomEvent(); - return ErrorNoBackingStore(); + if (Blueprint) return CreateBlueprint(Errors); + if (Graph) return CreateGraph(Errors); + if (CustomEvent) return CreateCustomEvent(Errors); + return ErrorNoBackingStore(Errors); } -bool WingVariables::CreateBlueprint() +bool WingVariables::CreateBlueprint(WingOut Errors) { - if (!CheckBlueprint()) return false; + if (!CheckBlueprint(Errors)) return false; ClearLinks(); // Check for name collisions against existing variables, components, and the like. TSet Names; FBlueprintEditorUtils::GetClassVariableList(Blueprint, Names); - if (!WingUtils::FindNoDuplicateNames(Names, BlueprintVariables.Variables, TEXT("variable or component"))) return false; + if (!WingUtils::FindNoDuplicateNames(Names, BlueprintVariables.Variables, TEXT("variable or component"), Errors)) return false; // Create the variables. for (const WingVariables::Var& V : BlueprintVariables.Variables) { if (!FBlueprintEditorUtils::AddMemberVariable(Blueprint, V.Name, V.Type)) { - UWingServer::Printf(TEXT("ERROR: Failed to add variable '%s'\n"), + Errors.Printf(TEXT("ERROR: Failed to add variable '%s'\n"), *WingUtils::ExternalizeID(V.Name)); return false; } } - if (LinkBlueprintVariables()) return false; + if (LinkBlueprintVariables(Errors)) return false; for (Var &V : BlueprintVariables.Variables) ModifyBlueprintVariableFlags(V); - if (!ModifyBlueprintDefaults()) return false; + if (!ModifyBlueprintDefaults(Errors)) return false; return false; } -bool WingVariables::CreateGraph() +bool WingVariables::CreateGraph(WingOut Errors) { - if (!CheckGraph()) return false; + if (!CheckGraph(Errors)) return false; ClearLinks(); UK2Node_EditablePinBase *InputNode, *OutputNode; UK2Node_FunctionEntry *LocalNode; - if (!GetGraphNodes(InputNode, OutputNode, LocalNode)) return false; + if (!GetGraphNodes(InputNode, OutputNode, LocalNode, Errors)) return false; // Check for name collisions against existing local variables. const TCHAR *ctx = TEXT("local, function input, and function output variables"); TSet Names; if (InputNode && !WingUtils::FindNoDuplicateNames( - Names, InputNode->UserDefinedPins, ctx)) return false; + Names, InputNode->UserDefinedPins, ctx, Errors)) return false; if (OutputNode && !WingUtils::FindNoDuplicateNames( - Names, OutputNode->UserDefinedPins, ctx)) return false; + Names, OutputNode->UserDefinedPins, ctx, Errors)) return false; if (LocalNode && !WingUtils::FindNoDuplicateNames( - Names, LocalNode->LocalVariables, ctx)) return false; + Names, LocalNode->LocalVariables, ctx, Errors)) return false; if (!WingUtils::FindNoDuplicateNames( - Names, InputVariables.Variables, ctx)) return false; + Names, InputVariables.Variables, ctx, Errors)) return false; if (!WingUtils::FindNoDuplicateNames( - Names, OutputVariables.Variables, ctx)) return false; + Names, OutputVariables.Variables, ctx, Errors)) return false; if (!WingUtils::FindNoDuplicateNames( - Names, LocalVariables.Variables, ctx)) return false; + Names, LocalVariables.Variables, ctx, Errors)) return false; // Create input pins on the input node. for (const Var& V : InputVariables.Variables) @@ -661,7 +662,7 @@ bool WingVariables::CreateGraph() { if (!FBlueprintEditorUtils::AddLocalVariable(BP, Graph, V.Name, V.Type, V.DefaultValue)) { - UWingServer::Printf(TEXT("ERROR: Failed to create local variable '%s'\n"), + Errors.Printf(TEXT("ERROR: Failed to create local variable '%s'\n"), *WingUtils::ExternalizeID(V.Name)); return false; } @@ -672,17 +673,17 @@ bool WingVariables::CreateGraph() return true; } -bool WingVariables::CreateCustomEvent() +bool WingVariables::CreateCustomEvent(WingOut Errors) { - if (!CheckCustomEvent()) return false; + if (!CheckCustomEvent(Errors)) return false; ClearLinks(); // Check for name collisions against existing pins. TSet Names; if (!WingUtils::FindNoDuplicateNames( - Names, CustomEvent->UserDefinedPins, TEXT("event parameter"))) return false; + Names, CustomEvent->UserDefinedPins, TEXT("event parameter"), Errors)) return false; if (!WingUtils::FindNoDuplicateNames( - Names, InputVariables.Variables, TEXT("event parameter"))) return false; + Names, InputVariables.Variables, TEXT("event parameter"), Errors)) return false; for (const Var& V : InputVariables.Variables) AddUserPinInfo(V, EGPD_Output, CustomEvent); @@ -701,22 +702,22 @@ void WingVariables::AddUserPinInfo(const Var &V, EEdGraphPinDirection Dir, UK2No Node->UserDefinedPins.Add(Result); } -bool WingVariables::Remove() +bool WingVariables::Remove(WingOut Errors) { - if (Blueprint) return RemoveBlueprint(); - if (Graph) return RemoveGraph(); - if (CustomEvent) return RemoveCustomEvent(); - return ErrorNoBackingStore(); + if (Blueprint) return RemoveBlueprint(Errors); + if (Graph) return RemoveGraph(Errors); + if (CustomEvent) return RemoveCustomEvent(Errors); + return ErrorNoBackingStore(Errors); } -bool WingVariables::RemoveBlueprint() +bool WingVariables::RemoveBlueprint(WingOut Errors) { // Verify that all named variables exist. TArray Names; for (const Var& V : BlueprintVariables.Variables) { FBPVariableDescription* Found = - WingUtils::FindOneWithInternalID(V.Name, Blueprint->NewVariables, TEXT("non-inherited variable")); + WingUtils::FindOneWithInternalID(V.Name, Blueprint->NewVariables, TEXT("non-inherited variable"), Errors); if (!Found) return false; Names.Add(V.Name); } @@ -726,29 +727,29 @@ bool WingVariables::RemoveBlueprint() return true; } -bool WingVariables::RemoveGraph() +bool WingVariables::RemoveGraph(WingOut Errors) { UK2Node_EditablePinBase *InputNode, *OutputNode; UK2Node_FunctionEntry *LocalNode; - if (!GetGraphNodes(InputNode, OutputNode, LocalNode)) return false; + if (!GetGraphNodes(InputNode, OutputNode, LocalNode, Errors)) return false; // Verify that all named variables exist before removing anything. for (const Var& V : InputVariables.Variables) { TSharedPtr* Found = - WingUtils::FindOneWithInternalID(V.Name, InputNode->UserDefinedPins, TEXT("input variable")); + WingUtils::FindOneWithInternalID(V.Name, InputNode->UserDefinedPins, TEXT("input variable"), Errors); if (!Found) return false; } for (const Var& V : OutputVariables.Variables) { TSharedPtr* Found = - WingUtils::FindOneWithInternalID(V.Name, OutputNode->UserDefinedPins, TEXT("output variable")); + WingUtils::FindOneWithInternalID(V.Name, OutputNode->UserDefinedPins, TEXT("output variable"), Errors); if (!Found) return false; } for (const Var& V : LocalVariables.Variables) { FBPVariableDescription* Found = - WingUtils::FindOneWithInternalID(V.Name, LocalNode->LocalVariables, TEXT("local variable")); + WingUtils::FindOneWithInternalID(V.Name, LocalNode->LocalVariables, TEXT("local variable"), Errors); if (!Found) return false; } @@ -772,13 +773,13 @@ bool WingVariables::RemoveGraph() return true; } -bool WingVariables::RemoveCustomEvent() +bool WingVariables::RemoveCustomEvent(WingOut Errors) { // 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")); + WingUtils::FindOneWithInternalID(V.Name, CustomEvent->UserDefinedPins, TEXT("event parameter"), Errors); if (!Found) return false; } @@ -789,7 +790,7 @@ bool WingVariables::RemoveCustomEvent() return true; } -bool WingVariables::SetBackingStore(UObject *Obj) +bool WingVariables::SetBackingStore(UObject *Obj, WingOut Errors) { Blueprint = nullptr; Graph = nullptr; @@ -809,16 +810,16 @@ bool WingVariables::SetBackingStore(UObject *Obj) CustomEvent = E; return true; } - UWingServer::Printf(TEXT( + Errors.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() +bool WingVariables::ErrorNoBackingStore(WingOut Errors) { - UWingServer::Printf(TEXT( + Errors.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/Private/WingWidgets.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingWidgets.cpp index b590f227..fcbbe1e4 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingWidgets.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingWidgets.cpp @@ -90,17 +90,17 @@ TArray WingWidgets::Search(const FString& Query, int32 MaxRes return Results; } -bool WingWidgets::CheckCanBeParent(UWidget* Widget) +bool WingWidgets::CheckCanBeParent(UWidget* Widget, WingOut Errors) { UPanelWidget* Panel = Cast(Widget); if (!Panel) { - UWingServer::Printf(TEXT("ERROR: '%s' is not a panel widget and cannot have children\n"), *WingUtils::FormatName(Widget)); + Errors.Printf(TEXT("ERROR: '%s' is not a panel widget and cannot have children\n"), *WingUtils::FormatName(Widget)); return false; } if (!Panel->CanAddMoreChildren()) { - UWingServer::Printf(TEXT("ERROR: '%s' already has a child and cannot accept more\n"), *WingUtils::FormatName(Widget)); + Errors.Printf(TEXT("ERROR: '%s' already has a child and cannot accept more\n"), *WingUtils::FormatName(Widget)); return false; } return true; @@ -111,12 +111,12 @@ void WingWidgets::PrintWidgetTree(UWidget* Widget, int32 Depth) FString Indent = FString::ChrN(Depth * 2, TEXT(' ')); if (Widget == nullptr) { - UWingServer::Printf(TEXT("%s[null]\n"), *Indent); + WingOut::Stdout.Printf(TEXT("%s[null]\n"), *Indent); return; } FString TypeName = WingUtils::FormatName(Widget->GetClass()); FString WidgetName = WingUtils::FormatName(Widget); - UWingServer::Printf(TEXT("%s%s %s\n"), *Indent, *TypeName, *WidgetName); + WingOut::Stdout.Printf(TEXT("%s%s %s\n"), *Indent, *TypeName, *WidgetName); if (UPanelWidget* Panel = Cast(Widget)) { diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingActorComponent.h b/Plugins/UEWingman/Source/UEWingman/Public/WingActorComponent.h index 0b1f8b51..0ae81d70 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingActorComponent.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingActorComponent.h @@ -1,6 +1,7 @@ #pragma once #include "CoreMinimal.h" +#include "WingHandler.h" #include "WingActorComponent.generated.h" class UBlueprint; @@ -41,13 +42,13 @@ public: UActorComponent* GetImmutableTemplate() const; UActorComponent* GetMutableTemplate() const; - bool ReparentComponent(UWingComponentReference *Parent); - bool DeleteComponent(); - static bool AddComponent(UBlueprint *BP, UClass *Class, UWingComponentReference *Parent, FName Name); + bool ReparentComponent(UWingComponentReference *Parent, WingOut Errors); + bool DeleteComponent(WingOut Errors); + static bool AddComponent(UBlueprint *BP, UClass *Class, UWingComponentReference *Parent, FName Name, WingOut Errors); static TArray GetAll(UBlueprint* BP); - static bool CheckValidComponentClass(UClass *Class); + static bool CheckValidComponentClass(UClass *Class, WingOut Errors); private: struct FoundComponent { @@ -59,11 +60,11 @@ private: static UActorComponent *FindComponentInCDO(UClass *Class, FName Name); static USCS_Node* FindSCSNodeByName(UBlueprint *BP, FName VariableName); static FoundComponent FindComponent(UBlueprint *BP, FName Name); - static bool CheckValidParent(FoundComponent FC); - static bool CheckExists(FoundComponent FC); - static bool CheckNoSuchComponent(FoundComponent FC); - static bool CheckNotNative(FoundComponent FC, const TCHAR *Action); - static bool CheckOwnedByBlueprint(FoundComponent FC, UBlueprint *BP); + static bool CheckValidParent(FoundComponent FC, WingOut Errors); + static bool CheckExists(FoundComponent FC, WingOut Errors); + static bool CheckNoSuchComponent(FoundComponent FC, WingOut Errors); + static bool CheckNotNative(FoundComponent FC, const TCHAR *Action, WingOut Errors); + static bool CheckOwnedByBlueprint(FoundComponent FC, UBlueprint *BP, WingOut Errors); static void AddChildNode(UBlueprint *BP, USCS_Node *Node, FoundComponent Parent); static TMap CalculateParentNames(USimpleConstructionScript *Script); }; diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingFactories.h b/Plugins/UEWingman/Source/UEWingman/Public/WingFactories.h index 25a3dc8e..b0cef705 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingFactories.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingFactories.h @@ -3,6 +3,7 @@ #include "CoreMinimal.h" #include "Factories/Factory.h" #include "Factories/EnumFactory.h" +#include "WingHandler.h" #include "WingFactories.generated.h" @@ -13,7 +14,7 @@ public: // Create an asset on disk, using a factory instance. // Returns the main object. If there are problems, // prints error messages and returns nullptr. - static UObject *CreateAsset(const FString &Path, UFactory *Factory); + static UObject *CreateAsset(const FString &Path, UFactory *Factory, WingOut Errors); // Some factories are blacklisted, mainly because they // pop up dialog boxes. In those cases, we deal with it @@ -28,7 +29,7 @@ public: // Verifies that the asset path is a valid path, and also // that there's not something already there at that path. - static bool CheckNewAssetPath(const FString &Path); + static bool CheckNewAssetPath(const FString &Path, WingOut Errors); }; // The original UEnumFactory may pop a dialog. We made a better one. diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h b/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h index b98d906a..9ddc8b06 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h @@ -60,7 +60,7 @@ public: // output to WingServer::Printf. // bool Ok() const { return !bError; } - + // Try to fetch the current object as a UObject of // the specified type. If it isn't one, generates an // error and returns nullptr. @@ -75,19 +75,19 @@ public: // Get the current object as a UObject if it is one, // otherwise nullptr. Does not generate errors. - // + // UObject* GetObj() const { return Obj; } // Get the asset from where it all began: the first // step in the walk path. If the asset couldn't be // loaded, returns nullptr. Does not generate errors. - // + // UObject* GetAsset() const { return OriginalAsset; } // Get the asset from where it all began: the first // step in the walk path, as a specified type. Errors // if it cannot cast to the specified type. - // + // template T* CastAsset() { if (!CheckAssetIsA(T::StaticClass())) return nullptr; @@ -98,7 +98,7 @@ public: // opened. Get the editor. You must specify the type // that you expect the asset to be, and the type to cast // the editor to. Does not generate errors. - // + // template EditorType* CastEditor() { @@ -115,16 +115,16 @@ public: // Initialize empty. You need to call Asset, or walk // a path that starts with an asset. // - WingFetcher() {} + WingFetcher(WingOut InErrors) : Errors(InErrors) {} // Initialize with an object. From there, you can walk // to sub-objects. // - WingFetcher(UObject* O) : Obj(O) {} + WingFetcher(UObject* O, WingOut InErrors) : Obj(O), Errors(InErrors) {} private: - + // The Current Object. Only one of these can be non-null. UObject* Obj = nullptr; UEdGraphPin* ResultPin = nullptr; @@ -137,6 +137,9 @@ private: bool bError = false; bool bSkipNotify = false; + // Error reporting destination. + WingOut Errors; + // Internal methods. using WalkFunc = WingFetcher& (WingFetcher::*)(const FString&); void SetObj(UObject* InObj); diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingHandler.h b/Plugins/UEWingman/Source/UEWingman/Public/WingHandler.h index 2f9df4ac..4e75b01a 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingHandler.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingHandler.h @@ -8,6 +8,7 @@ // Marker struct for handler parameters that accept a JSON object. // PopulateFromJson stashes the actual JSON object into the Json field. +// USTRUCT() struct FWingJsonObject { @@ -17,6 +18,7 @@ struct FWingJsonObject // Marker struct for handler parameters that accept a JSON array. // PopulateFromJson stashes the actual JSON array into the Array field. +// USTRUCT() struct FWingJsonArray { @@ -56,4 +58,48 @@ public: // The configuration object. UObject *ConfigurationObject; + +public: }; + +// A 'WingOut' is our version of an output stream. It always +// contains a pointer to a string builder, or nullptr. +// +class WingOut +{ +public: + WingOut(FStringBuilderBase *O) : Buffer(O) {} + WingOut(FStringBuilderBase &O) : Buffer(&O) {} + static WingOut Stdout; + static WingOut None; + + void PrintChar(TCHAR Ch) { if (Buffer) Buffer->AppendChar(Ch); } + void Print(const TCHAR* Text) { if (Buffer) Buffer->Append(Text); } + void Print(const FString& Text) { if (Buffer) Buffer->Append(Text); } + template + void Printf(const FmtType& Fmt, ArgTypes&&... Args) + { if (Buffer) Buffer->Appendf(Fmt, Forward(Args)...); } + + static TStringBuilder<65536> StdoutBuffer; + +private: + FStringBuilderBase *Buffer; +}; + +// A FWingStructAndUStruct is a pointer to a struct and its associated ustruct. +// +struct FWingStructAndUStruct +{ + void *StructPtr; + UStruct *UStructPtr; + + // Copy constructor. + FWingStructAndUStruct(FWingStructAndUStruct &Src) : StructPtr(Src.StructPtr), UStructPtr(Src.UStructPtr) {} + + // Construct from a UObject. + FWingStructAndUStruct(UObject *Obj) : StructPtr(Obj), UStructPtr(Obj->GetClass()) {} + + // Construct from a UStruct pointer. + template>> + FWingStructAndUStruct(T *Struct) : StructPtr(Struct), UStructPtr(Struct->StaticStruct()) {} +}; \ No newline at end of file diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingMaterialParameter.h b/Plugins/UEWingman/Source/UEWingman/Public/WingMaterialParameter.h index 2366aed6..82e7287b 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingMaterialParameter.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingMaterialParameter.h @@ -2,12 +2,13 @@ #include "CoreMinimal.h" #include "Materials/Material.h" +#include "WingHandler.h" class WingMaterialParameter { public: static TMap GetMaterialParameters(UMaterialInterface* Material); - static bool ParseMaterialParameterAssociation(const FString& Str, EMaterialParameterAssociation& OutAssociation); + static bool ParseMaterialParameterAssociation(const FString& Str, EMaterialParameterAssociation& OutAssociation, WingOut Errors); static void FormatMaterialParameter(const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta); }; diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h b/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h index 8cb80e72..a343d45f 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h @@ -3,6 +3,7 @@ #include "CoreMinimal.h" #include "IPropertyRowGenerator.h" #include "PropertyHandle.h" +#include "WingHandler.h" class FJsonObject; class FJsonValue; @@ -44,35 +45,35 @@ public: TSharedPtr TryNamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter); // Like TryNamedProperty, but prints an error if the property is not found. - TSharedPtr NamedProperty(UObject* Obj, FName Name, bool RootFilter); - TSharedPtr NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter); + TSharedPtr NamedProperty(UObject* Obj, FName Name, bool RootFilter, WingOut Errors); + TSharedPtr NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter, WingOut Errors); // Get "details panel" properties for an object. Handles special // cases: blueprints (redirects to CDO), component references // (redirects to template), material graph nodes (includes // expression properties), widgets (includes slot properties). - Handles GetDetails(UObject* Obj, bool Mutable); + Handles GetDetails(UObject* Obj, bool Mutable, WingOut Errors); // Organize properties by name. If there's more than one property // of a given name, print an error and returns false, and returns a map // that contains one of the two duplicates. - static bool OrganizeByName(const Handles &H, TMap> &Result); + static bool OrganizeByName(const Handles &H, TMap> &Result, WingOut Errors); // Get/set text. Compared to the built in methods for getting and setting // text, these support more concise enum values, FEdGraphPinType, and // more concise Class properties. static FString GetText(IPropertyHandle& Handle); - static bool SetText(IPropertyHandle& Handle, const FString& Text); + static bool SetText(IPropertyHandle& Handle, const FString& Text, WingOut Errors); // Store a Json value into a property handle. The Json value must be // a string, number, or boolean. - static bool SetJson(IPropertyHandle& Handle, const TSharedPtr& JsonValue); + static bool SetJson(IPropertyHandle& Handle, const TSharedPtr& JsonValue, WingOut Errors); // Populate a whole bunch of properties from a Json object. If // AllOptional is true, the Json may supply a subset of the properties. // If not, the Json must supply all of them, excepting properties that // are explicitly marked Optional. - static bool PopulateFromJson(TArray>& Props, const FJsonObject& Json, bool AllOptional); + static bool PopulateFromJson(TArray>& Props, const FJsonObject& Json, bool AllOptional, WingOut Errors); // Print a single property in a standardized format: // editable|readonly Type Name = Value diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingProperty.h b/Plugins/UEWingman/Source/UEWingman/Public/WingProperty.h index 924ac22f..a9bd7cc7 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingProperty.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingProperty.h @@ -1,38 +1,88 @@ #pragma once #include "CoreMinimal.h" +#include "WingHandler.h" #include "WingUtils.h" + // A resolved property: the FProperty descriptor plus a pointer to -// the value's storage. operator-> forwards to the FProperty. +// the value's storage. +// struct FWingProperty { FProperty* Prop = nullptr; void* Container = nullptr; + // Construct a property reference. + // + FWingProperty(FProperty* InProp, void* InContainer) + : Prop(InProp), Container(InContainer) {} + + // Construct a null property reference. + // FWingProperty() = default; - FWingProperty(FProperty* InProp, void* InContainer); - FWingProperty(FProperty* InProp, UObject* InContainer); - bool SetDouble(double D); - bool SetInt64(int64 I); - bool SetBool(bool B); + // Operator -> forwards to the FProperty. + // + FProperty* operator->() const { return Prop; } + // Store a value. On failure, return false, and print an + // error. These will do automatic conversion of numeric + // types to other numeric types, as long as the value + // fits. They will also do text to any type, as long as + // the value parses as a value of the desired type. If + // you + // + bool SetObject(UObject *Obj, WingOut Errors) const; + bool SetDouble(double D, WingOut Errors) const; + bool SetInt64(int64 I, WingOut Errors) const; + bool SetBool(bool B, WingOut Errors) const; + bool SetText(FString Value, WingOut Errors) const; + bool SetJson(const FJsonValue &Value, WingOut Errors) const; + + // Fetch a value. If an error occurs such as a type + // mismatch, returns an empty optional and prints an + // error. These will do automatic conversion of numeric + // types to other numeric types, as long as the value + // fits. They will also do any type to text, which is + // why the GetText version needs no error reporting. + // + TOptional GetObject(WingOut Errors) const; + TOptional GetDouble(WingOut Errors) const; + TOptional GetInt64(WingOut Errors) const; + TOptional GetBool(WingOut Errors) const; FString GetText() const; - bool SetText(FString Value); - // Store data from a json object. - bool SetJson(const TSharedPtr &Value); - - // Get the Category metadata. - FString GetCategory(); - - // Get the text, replace newlines with whitespace, and - // truncate to the specified maximum length. + // Get the text, replace newlines with whitespace, and truncate to the specified maximum length. + // FString GetTruncatedText(int32 MaxLen) const; + // Get the Category metadata. + // + FString GetCategory() const; + + // Return true if the property is not the null property reference. + // explicit operator bool() const { return Prop != nullptr; } - FProperty* operator->() const { return Prop; } + + // Get the raw properties of the specified object or struct. + // + // This gets the properties that are literally present in the + // specified object or struct. No special interpretation is done. + // + static TArray GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags); + + // Get just the names of the properties of the specified struct/class. + // + static TArray GetNames(UStruct *US, EPropertyFlags Flags); + + // Remove any properties with the specified name. + // + static void Remove(TArray& Props, FName Name); + + // Move any properties with the specified name to the out array. + // + static void Move(TArray &Out, TArray &In, FName Name); // Return the "Details Panel" properties for the specified object. // @@ -46,49 +96,19 @@ struct FWingProperty // // When editing an inherited ActorComponent, you're actually editing // properties that *override* the original properties of the ActorComponent. - // The mutable version, 'GetDetailsMutable', tells this function to first - // create the overrides, and then edit those. - // - // For a more direct "just give me the properties of this object," - // use the GetAll function. + // The 'mutable' flag tells it whether to create overrides for these + // properties. // - static TArray GetDetailsMutable(UObject* Obj, EPropertyFlags Flags) - { return GetDetailsGeneral(Obj, Flags, true); } - static TArray GetDetailsImmutable(UObject *Obj, EPropertyFlags Flags) - { return GetDetailsGeneral(Obj, Flags, false); } - - // Get the raw properties of the specified object or struct. - // - // This gets the properties that are literally present in the - // specified object or struct. No special interpretation is done. - // - static TArray GetAll(UObject* Object, EPropertyFlags Flags); - static TArray GetAll(UStruct* StructType, void* Container, EPropertyFlags Flags); - - // Get the names of the properties in the specified class. - // - static TArray GetNames(UStruct *StructType, EPropertyFlags Flags); - - // Get the named properties. - // - static TArray GetNamed(UStruct* StructType, void* Container, const TArray &Names); - - // Functions to find items by name in an array of properties. - // - static TArray FindAllSubstring(const TArray& Props, const FString& Substring); - static void Remove(TArray& Props, const FString& Name); - static void Move(TArray &Out, TArray &In, const FString &Name); + static TArray GetDetails(UObject* Obj, EPropertyFlags Flags, bool Mutable); // Functions to populate properties from a JSON object. // - static bool PopulateFromJson(FWingProperty& Prop, const FJsonObject* Json, bool AllOptional = false); - static bool PopulateFromJson(TArray& Props, const FJsonObject* Json, bool AllOptional = false); - static bool PopulateFromJson(UStruct* StructType, void* Container, const FJsonObject* Object); - static bool PopulateFromJson(UStruct* StructType, void* Container, const TSharedPtr& Object); + static bool PopulateFromJson(TArray& Props, const FJsonValue& Json, + bool AllOptional, WingOut Errors); private: - static TArray GetDetailsGeneral(UObject* Obj, EPropertyFlags Flags, bool Mutable); - void PrintExpectsReceived(const TCHAR *Type); - static void Collect(UStruct* Struct, void* Container, TArray &Props, EPropertyFlags Flags); - bool CheckImportTextResult(const FString &Value); + static void GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags, TArray &Props); + static bool IsPinTypeProperty(FProperty *Prop); + void PrintExpectsReceived(const TCHAR *Type, WingOut Errors) const; + bool CheckImportTextResult(const FString &Value, WingOut Errors) const; }; diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingServer.h b/Plugins/UEWingman/Source/UEWingman/Public/WingServer.h index 1659d7df..58638cf3 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingServer.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingServer.h @@ -50,20 +50,6 @@ public: /** Track an object that has been modified by the current handler. */ static void AddTouchedObject(UObject* Obj) { GWingServer->Notifier.AddTouchedObject(Obj); } - /** Print text to the handler output buffer. */ - static void Print(const TCHAR* Text) { GWingServer->HandlerOutput.Append(Text); } - static void Print(const FString& Text) { GWingServer->HandlerOutput.Append(Text); } - - /** Print formatted text to the handler output buffer. */ - template - static void Printf(const FmtType& Fmt, ArgTypes&&... Args) - { - GWingServer->HandlerOutput.Appendf(Fmt, Forward(Args)...); - } - - /** Get the handler output buffer directly. */ - static FStringBuilderBase& GetPrintBuffer() { return GWingServer->HandlerOutput; } - /** Suggest that a manual section be printed after the handler finishes. */ static void SuggestManual(WingManual::Section Section) { GWingServer->SuggestedManualSections.Add(Section); } @@ -84,7 +70,6 @@ private: UPROPERTY() FWingNotifier Notifier; FWingHandlerConfig* LastHandler; - TStringBuilder<16384> HandlerOutput; TSet SuggestedManualSections; FLogCaptureOutputDevice LogCapture; // installed once at startup, enabled per-request TArray WingHandlerRegistry; // sorted by Name diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingTypes.h b/Plugins/UEWingman/Source/UEWingman/Public/WingTypes.h index 4b2db891..4144384d 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingTypes.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingTypes.h @@ -3,6 +3,7 @@ #include "CoreMinimal.h" #include "EditorSubsystem.h" #include "EdGraph/EdGraphPin.h" +#include "WingHandler.h" #include "WingTypes.generated.h" struct WingTokenizer; @@ -117,16 +118,16 @@ private: // Parser and ResolveShortName // --------------------------------------------------------------------------- - static void PrintParseError(WingTokenizer& Tok, const TCHAR* Message); - static bool ParseChar(WingTokenizer& Tok, TCHAR c); - bool ParsePlainIdentifier(WingTokenizer& Tok, FEdGraphPinType& OutType); - bool ParseWrapped(WingTokenizer& Tok, FName Wrapper, FEdGraphPinType& OutType); - bool ParseMaybeWrapped(WingTokenizer& Tok, FEdGraphPinType& OutType); - bool ParseArrayOrSet(WingTokenizer& Tok, FEdGraphPinType& OutType); - bool ParseMap(WingTokenizer& Tok, FEdGraphPinType& OutType); - bool ParseType(WingTokenizer& Tok, FEdGraphPinType& OutType); + static void PrintParseError(WingTokenizer& Tok, const TCHAR* Message, WingOut Errors); + static bool ParseChar(WingTokenizer& Tok, TCHAR c, WingOut Errors); + bool ParsePlainIdentifier(WingTokenizer& Tok, FEdGraphPinType& OutType, WingOut Errors); + bool ParseWrapped(WingTokenizer& Tok, FName Wrapper, FEdGraphPinType& OutType, WingOut Errors); + bool ParseMaybeWrapped(WingTokenizer& Tok, FEdGraphPinType& OutType, WingOut Errors); + bool ParseArrayOrSet(WingTokenizer& Tok, FEdGraphPinType& OutType, WingOut Errors); + bool ParseMap(WingTokenizer& Tok, FEdGraphPinType& OutType, WingOut Errors); + bool ParseType(WingTokenizer& Tok, FEdGraphPinType& OutType, WingOut Errors); - bool ResolveShortName(WingTokenizer& Tok, const FString &Name, FEdGraphPinType &OutType); + bool ResolveShortName(WingTokenizer& Tok, const FString &Name, FEdGraphPinType &OutType, WingOut Errors); public: // --------------------------------------------------------------------------- @@ -146,21 +147,21 @@ public: // Parse a type. If it doesn't parse, or if the type doesn't satisfy the // requirements, prints an error and returns false. If CheckEOF is true, // makes sure that the input is *just* a type and nothing else after it. - static bool TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, const Requirements &Require, bool CheckEOF); + static bool TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, const Requirements &Require, bool CheckEOF, WingOut Errors); // Parse a type. If it doesn't parse, or if the type doesn't satisfy the - // requirements, prints an error and returns false. - static bool TextToType(const FString& Text, FEdGraphPinType& OutPinType, const Requirements &Require); + // requirements, prints an error and returns false. + static bool TextToType(const FString& Text, FEdGraphPinType& OutPinType, const Requirements &Require, WingOut Errors); // Parse a type. If it doesn't parse, or if the type doesn't satisfy the // requirements, prints an error and returns false. Requires that the type // is an object type (even if that's not specified in the requirements struct). - static UClass* TextToOneObjectType(const FString& Text, const Requirements &Require); + static UClass* TextToOneObjectType(const FString& Text, const Requirements &Require, WingOut Errors); // Parse a type. If it doesn't parse, or if the type doesn't satisfy the // requirements, prints an error and returns false. Requires that the type // is an interface type (even if that's not specified in the requirements struct). - static UClass* TextToOneInterfaceType(const FString& Text, const Requirements &Require); + static UClass* TextToOneInterfaceType(const FString& Text, const Requirements &Require, WingOut Errors); private: // --------------------------------------------------------------------------- diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h index bf8b622d..431ecbdb 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h @@ -15,6 +15,7 @@ #include "Components/Widget.h" #include "WingActorComponent.h" #include "WingVariables.h" +#include "WingHandler.h" struct FEdGraphSchemaAction; class UAnimationStateMachineGraph; @@ -104,53 +105,53 @@ public: //////////////////////////////////////////////////////// template - static auto FindOneWithInternalID(FName InternalID, ArrayType &&Array, const TCHAR *Kind) + static auto FindOneWithInternalID(FName InternalID, ArrayType &&Array, const TCHAR *Kind, WingOut Errors) { decltype(EltAsPtr(Array, Array[0])) Result = nullptr; int Count = 0; for (auto &Elt : Array) if (GetFName(Elt) == InternalID) { Count++; Result = EltAsPtr(Array, Elt); } - if (!CheckExactlyOneNamed(Count, Kind, InternalID)) Result = nullptr; + if (!CheckExactlyOneNamed(Count, Kind, InternalID, Errors)) Result = nullptr; return Result; } template - static auto FindOneWithExternalID(const FString &ExternalID, ArrayType &&Array, const TCHAR *Kind) + static auto FindOneWithExternalID(const FString &ExternalID, ArrayType &&Array, const TCHAR *Kind, WingOut Errors) { decltype(EltAsPtr(Array, Array[0])) Result = nullptr; - FName InternalID = CheckInternalizeID(ExternalID); - if (!InternalID.IsNone()) Result = FindOneWithInternalID(InternalID, Array, Kind); + FName InternalID = CheckInternalizeID(ExternalID, Errors); + if (!InternalID.IsNone()) Result = FindOneWithInternalID(InternalID, Array, Kind, Errors); return Result; } template - static bool FindNoneWithInternalID(FName InternalID, ArrayType &&Array, const TCHAR *Kind) + static bool FindNoneWithInternalID(FName InternalID, ArrayType &&Array, const TCHAR *Kind, WingOut Errors) { - for (auto &Elt : Array) if (GetFName(Elt) == InternalID) - return CheckExactlyNoneNamed(1, Kind, InternalID); + for (auto &Elt : Array) if (GetFName(Elt) == InternalID) + return CheckExactlyNoneNamed(1, Kind, InternalID, Errors); return true; } template - static bool FindNoneWithExternalID(const FString &ExternalID, ArrayType &&Array, const TCHAR *Kind) + static bool FindNoneWithExternalID(const FString &ExternalID, ArrayType &&Array, const TCHAR *Kind, WingOut Errors) { - FName InternalID = CheckInternalizeID(ExternalID); + FName InternalID = CheckInternalizeID(ExternalID, Errors); if (InternalID.IsNone()) return false; - return FindNoneWithInternalID(InternalID, Array, Kind); + return FindNoneWithInternalID(InternalID, Array, Kind, Errors); } - static bool FindNoDuplicateName(TSet &Collection, FName InternalID, const TCHAR *Kind) + static bool FindNoDuplicateName(TSet &Collection, FName InternalID, const TCHAR *Kind, WingOut Errors) { if (Collection.Contains(InternalID)) - { CheckExactlyOneNamed(2, Kind, InternalID); return false; } + { CheckExactlyOneNamed(2, Kind, InternalID, Errors); return false; } Collection.Add(InternalID); return true; } template - static bool FindNoDuplicateNames(TSet &Collection, ArrayType &&Array, const TCHAR *Kind) + static bool FindNoDuplicateNames(TSet &Collection, ArrayType &&Array, const TCHAR *Kind, WingOut Errors) { for (auto &Elt : Array) - if (!FindNoDuplicateName(Collection, GetFName(Elt), Kind)) return false; + if (!FindNoDuplicateName(Collection, GetFName(Elt), Kind, Errors)) return false; return true; } @@ -200,7 +201,7 @@ public: // static FString ExternalizeID(const FString& InternalID); static FString ExternalizeID(FName Name); - static FName CheckInternalizeID(const FString &ExternalID); + static FName CheckInternalizeID(const FString &ExternalID, WingOut Errors); //////////////////////////////////////////////////////// // In Unreal, Menu items tend to be an unpredictable @@ -221,13 +222,13 @@ public: // empty string. //////////////////////////////////////////////////////// - static FName CheckProposedName(const FString &Name); + static FName CheckProposedName(const FString &Name, WingOut Errors); static FString FormatNodeTitle(const UEdGraphNode *Node); // ----- Enum helpers ----- static FString EnumToString(UEnum* Enum, int64 Value); - static bool StringToEnum(UEnum* Enum, const FString& Str, int64& OutValue); + static bool StringToEnum(UEnum* Enum, const FString& Str, int64& OutValue, WingOut Errors); template static FString EnumToString(TEnumAsByte Value) @@ -238,8 +239,8 @@ public: { return EnumToString(StaticEnum(), (int64)Value); } template - static bool StringToEnum(const FString& Str, T& OutValue) - { int64 V; if (!StringToEnum(StaticEnum(), Str, V)) return false; OutValue = (T)V; return true; } + static bool StringToEnum(const FString& Str, T& OutValue, WingOut Errors) + { int64 V; if (!StringToEnum(StaticEnum(), Str, V, Errors)) return false; OutValue = (T)V; return true; } // ----- Blueprint helpers ----- static TArray AllGraphs(UBlueprint* BP); @@ -258,7 +259,7 @@ public: // ----- Anim blueprint helpers ----- static UAnimationStateMachineGraph* FindStateMachineGraph(UBlueprint* BP, const FString& GraphName); - static UAnimStateNode* FindStateByName(UAnimationStateMachineGraph* SMGraph, const FString& StateName); + static UAnimStateNode* FindStateByName(UAnimationStateMachineGraph* SMGraph, const FString& StateName, WingOut Errors); static UAnimStateTransitionNode* FindTransition(UAnimationStateMachineGraph* SMGraph, const FString& FromStateName, const FString& ToStateName); // ----- Text formatting ----- @@ -273,11 +274,11 @@ public: static bool CanReparentBlueprint(UClass* CurrentGenerated, UClass* Proposed); // ----- Common Error Reporting ----- - static bool CheckExactlyOneNamed(int Count, const TCHAR *Kind, const FString &Name); - static bool CheckExactlyOneNamed(int Count, const TCHAR *Kind, FName Name); - static bool CheckExactlyNoneNamed(int Count, const TCHAR *Kind, const FString &Name); - static bool CheckExactlyNoneNamed(int Count, const TCHAR *Kind, FName Name); + static bool CheckExactlyOneNamed(int Count, const TCHAR *Kind, const FString &Name, WingOut Errors); + static bool CheckExactlyOneNamed(int Count, const TCHAR *Kind, FName Name, WingOut Errors); + static bool CheckExactlyNoneNamed(int Count, const TCHAR *Kind, const FString &Name, WingOut Errors); + static bool CheckExactlyNoneNamed(int Count, const TCHAR *Kind, FName Name, WingOut Errors); - static bool CheckCanRename(UEdGraphNode* Node, const FString &Name); + static bool CheckCanRename(UEdGraphNode* Node, const FString &Name, WingOut Errors); }; diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h b/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h index 05a8cbc9..b1987923 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingVariables.h @@ -3,6 +3,7 @@ #include "CoreMinimal.h" #include "EdGraph/EdGraphPin.h" #include "Engine/Blueprint.h" +#include "WingHandler.h" struct WingTokenizer; class UK2Node_CustomEvent; @@ -54,27 +55,27 @@ public: void Empty() { Variables.Empty(); } // Print the variables to a string builder. - void Print(FStringBuilderBase &Out); + void Print(WingOut Out); // Print compact: "type name,type name,..." - void PrintCompact(FStringBuilderBase &Out); + void PrintCompact(WingOut Out); // Clear the BPVar and Pin fields. void ClearLinks(); // Check the sanity of the vars in the array. If allow // is false, then no variables are allowed in the array. - bool CheckSanity(const TSet &GoodFlags, bool Allow); + bool CheckSanity(const TSet &GoodFlags, bool Allow, WingOut Errors); // Parse variables from a string. - bool ParseString(const FString &Input); + bool ParseString(const FString &Input, WingOut Errors); // Parse variable names only from a string. - bool ParseNamesString(const FString &Input); + bool ParseNamesString(const FString &Input, WingOut Errors); private: - bool ParseOneVariable(WingTokenizer &Tok, Var &V); - bool ParseVariableFlags(WingTokenizer &Tok, TSet &Out); + bool ParseOneVariable(WingTokenizer &Tok, Var &V, WingOut Errors); + bool ParseVariableFlags(WingTokenizer &Tok, TSet &Out, WingOut Errors); }; class WingVariables @@ -100,7 +101,7 @@ public: // Configure the backing store. On failure, // prints a message and returns false. - bool SetBackingStore(UObject *Obj); + bool SetBackingStore(UObject *Obj, WingOut Errors); // Clear the workspace. Doesn't affect the backing store. @@ -112,29 +113,29 @@ public: // Print the contents of the workspace. - void Print(FStringBuilderBase &Out); + void Print(WingOut Out); // Load: clear the workspace, then // copy everything from the backing store into the workspace. - void Load(); + void Load(WingOut Errors); // Check: make sure the contents of the workspace makes sense // given the type of backing store. - bool Check(); + bool Check(WingOut Errors); // Use the variables in the workspace to modify the backing store. - bool Modify(); + bool Modify(WingOut Errors); // Create every variable in the workspace in the backing store. - bool Create(); + bool Create(WingOut Errors); // Remove every variable mentioned in the workspace from the backing store. - bool Remove(); + bool Remove(WingOut Errors); private: void LoadBlueprint(); @@ -144,37 +145,38 @@ private: Var LoadLocalVariableDescription(FBPVariableDescription &Desc); void LoadEditablePinBase(UK2Node_EditablePinBase *Node, WingVariableList &List); - bool CheckBlueprint(); - bool CheckGraph(); + bool CheckBlueprint(WingOut Errors); + bool CheckGraph(WingOut Errors); - bool ModifyBlueprint(); - bool LinkBlueprintVariables(); + bool ModifyBlueprint(WingOut Errors); + bool LinkBlueprintVariables(WingOut Errors); void ModifyBlueprintVariableFlags(Var &Input); - bool ModifyBlueprintDefaults(); + bool ModifyBlueprintDefaults(WingOut Errors); - bool ModifyGraph(); + bool ModifyGraph(WingOut Errors); - bool CreateBlueprint(); + bool CreateBlueprint(WingOut Errors); - bool CreateGraph(); + bool CreateGraph(WingOut Errors); - bool RemoveBlueprint(); - bool RemoveGraph(); + bool RemoveBlueprint(WingOut Errors); + bool RemoveGraph(WingOut Errors); void LoadCustomEvent(); - bool CheckCustomEvent(); - bool ModifyCustomEvent(); - bool CreateCustomEvent(); - bool RemoveCustomEvent(); + bool CheckCustomEvent(WingOut Errors); + bool ModifyCustomEvent(WingOut Errors); + bool CreateCustomEvent(WingOut Errors); + bool RemoveCustomEvent(WingOut Errors); bool GetGraphNodes( UK2Node_EditablePinBase *&InputNode, UK2Node_EditablePinBase *&OutputNode, - UK2Node_FunctionEntry *&LocalNode); + UK2Node_FunctionEntry *&LocalNode, + WingOut Errors); - bool ModifyEditablePinBase(WingVariableList &List, UK2Node_EditablePinBase *Node); + bool ModifyEditablePinBase(WingVariableList &List, UK2Node_EditablePinBase *Node, WingOut Errors); void AddUserPinInfo(const Var &V, EEdGraphPinDirection Dir, UK2Node_EditablePinBase *Node); - bool ErrorNoBackingStore(); + bool ErrorNoBackingStore(WingOut Errors); }; diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingWidgets.h b/Plugins/UEWingman/Source/UEWingman/Public/WingWidgets.h index 4d64f667..4543cabc 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingWidgets.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingWidgets.h @@ -2,6 +2,7 @@ #include "CoreMinimal.h" #include "Components/Widget.h" +#include "WingHandler.h" class UWidgetTree; struct FAssetData; @@ -24,7 +25,7 @@ public: TArray Search(const FString& Query, int32 MaxResults, bool Exact); // Check if a widget can accept children. Prints error if not. - static bool CheckCanBeParent(UWidget* Widget); + static bool CheckCanBeParent(UWidget* Widget, WingOut Errors); // Print out a tree of widgets, just showing the names and types. static void PrintWidgetTree(UWidget* Widget, int32 Depth);