From 2ad86bac1d9ea1a9436cb623d4a4b8f50f25b8a9 Mon Sep 17 00:00:00 2001 From: jyelon Date: Sat, 28 Mar 2026 23:47:05 -0400 Subject: [PATCH] Implemented new functions FindOneWithExternalID, etc. --- .../Source/UEWingman/Private/WingUtils.cpp | 17 +- .../Source/UEWingman/Public/WingUtils.h | 145 +++++++++++++----- 2 files changed, 123 insertions(+), 39 deletions(-) diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp index 96d57962..60b1cb79 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp @@ -65,10 +65,15 @@ FString WingUtils::ExternalizeID(FName Name) return WingTokenizer::ExternalizeID(Name.ToString()); } +FName WingUtils::CheckInternalizeID(const FString &ExternalID) +{ + return FName(WingTokenizer::CheckInternalizeID(ExternalID)); +} + FString WingUtils::CheckProposedName(const FString &ExternalID) { FString InternalID = WingTokenizer::CheckInternalizeID(ExternalID); - if (!InternalID.IsEmpty() && WingTokenizer::WouldExternalizeReadably(InternalID)) + if (!InternalID.IsEmpty() && !WingTokenizer::WouldExternalizeReadably(InternalID)) { UWingServer::Printf(TEXT("ERROR: id %s would not be a readable id, may not create item with this name"), *ExternalID); @@ -351,6 +356,11 @@ bool WingUtils::CheckExactlyOneNamed(int Count, const TCHAR *Kind, const FString return true; } +bool WingUtils::CheckExactlyOneNamed(int Count, const TCHAR *Kind, FName Name) +{ + return CheckExactlyOneNamed(Count, Kind, ExternalizeID(Name)); +} + bool WingUtils::CheckExactlyNoneNamed(int Count, const TCHAR *Kind, const FString &Name) { if (Count > 0) @@ -361,6 +371,11 @@ bool WingUtils::CheckExactlyNoneNamed(int Count, const TCHAR *Kind, const FStrin return true; } +bool WingUtils::CheckExactlyNoneNamed(int Count, const TCHAR *Kind, FName Name) +{ + return CheckExactlyNoneNamed(Count, Kind, ExternalizeID(Name)); +} + bool WingUtils::CheckCanRename(UEdGraphNode* Node, const FString &Name) { if (!Node->bCanRenameNode) diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h index 462c6876..2b0265cb 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h @@ -5,42 +5,122 @@ #include "EdGraph/EdGraph.h" #include "EdGraph/EdGraphPin.h" #include "Materials/MaterialInstanceConstant.h" +#include "Materials/MaterialExpression.h" #include "MaterialTypes.h" +#include "Components/ActorComponent.h" +#include "Engine/SCS_Node.h" +#include "Engine/MemberReference.h" +#include "Engine/Blueprint.h" +#include "K2Node_EditablePinBase.h" +#include "Components/Widget.h" +#include "WingActorComponent.h" -class UBlueprint; -class UEdGraphNode; -class UEdGraphPin; -class UMaterial; -class UMaterialInstance; -class UMaterialFunction; -class UMaterialExpression; struct FEdGraphSchemaAction; class UAnimationStateMachineGraph; class UAnimStateNode; class UAnimStateTransitionNode; -class UActorComponent; -class UWorld; -class UStaticMesh; -class USkeletalMesh; -class UAnimSequence; -class UBlendSpace; -class UTexture; class UScriptStruct; class UEnum; -class USCS_Node; -class UWidget; -struct FMemberReference; -struct FBPVariableDescription; -struct FUserPinInfo; struct FBPInterfaceDescription; -struct FWingActorComponent; -class UWingComponentReference; + +#include "Engine/World.h" +#include "Materials/Material.h" +#include "Engine/StaticMesh.h" +#include "Engine/SkeletalMesh.h" +#include "Animation/AnimSequence.h" +#include "Animation/BlendSpace.h" +#include "Engine/Texture.h" +#include "Materials/MaterialFunction.h" // Stateless utility functions used by MCP handlers and the MCP server. // This is effectively a namespace — all methods are static. class WingUtils { public: + // Given an array and a reference to an element of the array, return + // a pointer to the element, or if the element is already a pointer, the element. + template static const T* EltAsPtr(const TArray &A, const T &Elt) { return &Elt; } + template static T* EltAsPtr(TArray &A, T &Elt) { return &Elt; } + template static T* EltAsPtr(const TArray &A, T* &Elt) { return Elt; } + template static T* EltAsPtr(TArray &A, T* &Elt) { return Elt; } + template static const T* EltAsPtr(const TArray &A, const T* &Elt) { return Elt; } + template static const T* EltAsPtr(TArray &A, const T* &Elt) { return Elt; } + + //////////////////////////////////////////////////////// + // + // GetFName + // + // For objects whose FormatName uses ExternalizeID, + // GetFName returns the raw internal FName. + // + //////////////////////////////////////////////////////// + + static FName GetFName(const UActorComponent *C) { return C->GetFName(); } + static FName GetFName(const UEdGraph *Graph) { return Graph->GetFName(); } + static FName GetFName(const TObjectPtr &Graph) { return Graph->GetFName(); } + static FName GetFName(const UEdGraphNode* Node) { return Node->GetFName(); } + static FName GetFName(const UEdGraphPin *Pin) { return Pin->GetFName(); } + static FName GetFName(const FMemberReference &Ref) { return Ref.GetMemberName(); } + static FName GetFName(const FBPVariableDescription &Var) { return Var.VarName; } + static FName GetFName(const UMaterialExpression *Expression) { return Expression->GetFName(); } + static FName GetFName(const FProperty *Prop) { return Prop->GetFName(); } + static FName GetFName(const FUserPinInfo &Pin) { return Pin.PinName; } + static FName GetFName(const UWingComponentReference *Ref) { return Ref->VariableName; } + static FName GetFName(const UWidget *Widget) { return Widget->GetFName(); } + + template + static auto FindOneWithInternalID(FName InternalID, ArrayType &Array, const TCHAR *Kind) + { + 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; + return Result; + } + + template + static auto FindOneWithExternalID(const FString &ExternalID, ArrayType &Array, const TCHAR *Kind) + { + decltype(EltAsPtr(Array, Array[0])) Result = nullptr; + FName InternalID = CheckInternalizeID(ExternalID); + if (!InternalID.IsNone()) Result = FindOneWithInternalID(InternalID, Array, Kind); + return Result; + } + + template + static bool FindNoneWithInternalID(FName InternalID, ArrayType &Array, const TCHAR *Kind) + { + for (auto &Elt : Array) if (GetFName(Elt) == InternalID) + return CheckExactlyNoneNamed(1, Kind, InternalID); + return true; + } + + template + static bool FindNoneWithExternalID(const FString &ExternalID, ArrayType &Array, const TCHAR *Kind) + { + FName InternalID = CheckInternalizeID(ExternalID); + if (InternalID.IsNone()) return false; + return FindNoneWithInternalID(InternalID, Array, Kind); + } + + //////////////////////////////////////////////////////// + // + // GetPathName + // + // For objects whose FormatName returns a path name, + // GetPathName returns the raw path. + // + //////////////////////////////////////////////////////// + + static FString GetPathName(const UWorld *World) { return World->GetPathName(); } + static FString GetPathName(const UMaterial *Material) { return Material->GetPathName(); } + static FString GetPathName(const UMaterialInstance *MI) { return MI->GetPathName(); } + static FString GetPathName(const UMaterialFunction *MF) { return MF->GetPathName(); } + static FString GetPathName(const UStaticMesh *Mesh) { return Mesh->GetPathName(); } + static FString GetPathName(const USkeletalMesh *Mesh) { return Mesh->GetPathName(); } + static FString GetPathName(const UAnimSequence *Anim) { return Anim->GetPathName(); } + static FString GetPathName(const UTexture *Texture) { return Texture->GetPathName(); } + //////////////////////////////////////////////////////// // // Name Formatting @@ -78,7 +158,6 @@ public: static FString FormatName(const FProperty *Prop); static FString FormatName(const FUserPinInfo &Pin); static FString FormatName(const FBPInterfaceDescription &IFace); - static FString FormatName(const FWingActorComponent &Comp); static FString FormatName(const UWingComponentReference *Ref); static FString FormatName(const UWidget *Widget); @@ -97,21 +176,6 @@ public: //////////////////////////////////////////////////////// - template - static TArray FindAllNamed(const FString &Name, const TArray &Array) - { - TArray Result; - for (T* Elt : Array) if (Identifies(Name, Elt)) Result.Add(Elt); - return Result; - } - - template>> - static TArray FindAllNamed(const FString &Name, TArray &Array) - { - TArray Result; - for (T& Elt : Array) if (Identifies(Name, Elt)) Result.Add(&Elt); - return Result; - } template static T* FindExactlyOneNamed(const FString &Name, const TArray &Array, const TCHAR *Kind) @@ -144,9 +208,11 @@ public: } //////////////////////////////////////////////////////// - static FString ExternalizeID(const FString& Name); + static FString ExternalizeID(const FString& InternalID); static FString ExternalizeID(FName Name); + static FName CheckInternalizeID(const FString &ExternalID); + //////////////////////////////////////////////////////// // In Unreal, Menu items tend to be an unpredictable // mix of CamelCase without spaces, and with spaces. @@ -218,7 +284,10 @@ public: // ----- 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 CheckCanRename(UEdGraphNode* Node, const FString &Name); };