Files
integration/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h
2026-03-19 12:01:38 -04:00

229 lines
7.9 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "Dom/JsonObject.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphPin.h"
#include "Materials/MaterialInstanceConstant.h"
#include "MaterialTypes.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;
struct FMemberReference;
struct FBPVariableDescription;
struct FUserPinInfo;
// Stateless utility functions used by MCP handlers and the MCP server.
// This is effectively a namespace — all methods are static.
class WingUtils
{
public:
////////////////////////////////////////////////////////
//
// Name Formatting
//
// The goal here is to centralize the code that outputs
// names, and have everybody use it, so that names are
// used consistently. The secondary goal is to choose
// names that are as uniquely-identifying as is practical.
// It's not always 100% possible to get perfectly unique
// names, though, so our code needs to check for ambiguity.
//
////////////////////////////////////////////////////////
static FString FormatName(const UWorld *World);
static FString FormatName(const UBlueprint *BP);
static FString FormatName(const UActorComponent *C);
static FString FormatName(const USCS_Node *Node);
static FString FormatName(const UEdGraph *Graph);
static FString FormatName(const UEdGraphNode* Node);
static FString FormatName(const UEdGraphPin *Pin);
static FString FormatName(const FMemberReference &Ref);
static FString FormatName(const FBPVariableDescription &Var);
static FString FormatName(const UStruct *Struct);
static FString FormatName(const UClass *Class);
static FString FormatName(const UMaterial *Material);
static FString FormatName(const UMaterialInstance *MaterialInstance);
static FString FormatName(const UMaterialFunction *MaterialFunction);
static FString FormatName(const UMaterialExpression *Expression);
static FString FormatName(const UStaticMesh *Mesh);
static FString FormatName(const USkeletalMesh *Mesh);
static FString FormatName(const UAnimSequence *Anim);
static FString FormatName(const UBlendSpace *BlendSpace);
static FString FormatName(const UTexture *Texture);
static FString FormatName(const UScriptStruct *Struct);
static FString FormatName(const UEnum *Enum);
static FString FormatName(const FProperty *Prop);
static FString FormatName(const FUserPinInfo &Pin);
////////////////////////////////////////////////////////
//
// Identifies
//
// Return true if the name identifies the object. The
// FormatName functions, above, always return names that
// identify the object. However, there may be other
// names that also identify the object. Identifying names
// aren't 100% guaranteed to be unique, but very likely.
//
////////////////////////////////////////////////////////
template<typename T>
static bool Identifies(const FString &Name, T&& Obj)
{
return FormatName(std::forward<T>(Obj)).Equals(Name, ESearchCase::IgnoreCase);
}
template<typename T>
static TArray<T*> FindAllNamed(const FString &Name, const TArray<T*> &Array)
{
TArray<T*> Result;
for (T* Elt : Array) if (Identifies(Name, Elt)) Result.Add(Elt);
return Result;
}
template<typename T>
static TArray<T*> FindAllNamed(const FString &Name, TArray<T> &Array)
{
TArray<T*> Result;
for (T& Elt : Array) if (Identifies(Name, Elt)) Result.Add(&Elt);
return Result;
}
template<typename T>
static T* FindExactlyOneNamed(const FString &Name, const TArray<T*> &Array)
{
int Count = 0;
T* Result = nullptr;
for (T* Elt : Array) if (Identifies(Name, Elt)) { Count++; Result = Elt; }
if (!CheckExactlyOneNamed(Count, T::StaticClass(), Name)) return nullptr;
return Result;
}
template<typename T>
static T* FindExactlyOneNamed(const FString &Name, TArray<T> &Array)
{
int Count = 0;
T* Result = nullptr;
for (T& Elt : Array) if (Identifies(Name, Elt)) { Count++; Result = &Elt; }
if (!CheckExactlyOneNamed(Count, T::StaticStruct()->GetName(), Name)) return nullptr;
return Result;
}
template<typename T>
static bool FindExactlyNoneNamed(const FString &Name, const TArray<T*> &Array)
{
for (T* Elt: Array) if (Identifies(Name, Elt))
{
return CheckExactlyNoneNamed(1, T::StaticClass(), Name);
}
return true;
}
template<typename T>
static bool FindExactlyNoneNamed(const FString &Name, const TArray<T> &Array)
{
for (const T& Elt: Array) if (Identifies(Name, Elt))
{
return CheckExactlyNoneNamed(1, T::StaticStruct()->GetName(), Name);
}
return true;
}
////////////////////////////////////////////////////////
static void SanitizeNameInPlace(FString& Name);
static FString SanitizeName(const FString& Name);
static FString SanitizeName(FName Name);
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);
template<typename T>
static FString EnumToString(TEnumAsByte<T> Value)
{ return EnumToString(StaticEnum<T>(), (int64)Value); }
template<typename T>
static FString EnumToString(T Value)
{ return EnumToString(StaticEnum<T>(), (int64)Value); }
template<typename T>
static bool StringToEnum(const FString& Str, T& OutValue)
{ int64 V; if (!StringToEnum(StaticEnum<T>(), Str, V)) return false; OutValue = (T)V; return true; }
// ----- Blueprint helpers -----
static TArray<UEdGraph*> AllGraphs(UBlueprint* BP);
static TArray<UEdGraphNode*> AllNodes(UBlueprint* BP);
template<class T> static TArray<T*> AllNodes(UBlueprint* BP)
{
TArray<T*> Result;
for (UEdGraph* Graph : AllGraphs(BP))
for (UEdGraphNode* Node : Graph->Nodes)
if (T* Typed = Cast<T>(Node))
Result.Add(Typed);
return Result;
}
template<class T> static TArray<T*> AllNodes(UEdGraph* Graph)
{
TArray<T*> Result;
for (UEdGraphNode* Node : Graph->Nodes)
if (T* Typed = Cast<T>(Node))
Result.Add(Typed);
return Result;
}
// ----- Material helpers -----
static void EnsureMaterialGraph(UMaterial* Material);
// If the material editor has a transient preview copy of this material,
// return that copy (which is what the editor is actually working on).
// Otherwise return the original.
static UMaterial* ReplaceMaterialWithTransientCopy(UMaterial* Material);
// ----- Anim blueprint helpers -----
static UAnimationStateMachineGraph* FindStateMachineGraph(UBlueprint* BP, const FString& GraphName);
static UAnimStateNode* FindStateByName(UAnimationStateMachineGraph* SMGraph, const FString& StateName);
static UAnimStateTransitionNode* FindTransition(UAnimationStateMachineGraph* SMGraph, const FString& FromStateName, const FString& ToStateName);
// ----- Graph actions (node spawning) -----
static FString ActionFullName(const TSharedPtr<FEdGraphSchemaAction>& Action);
static TArray<TSharedPtr<FEdGraphSchemaAction>> SearchGraphActions(UEdGraph* Graph, const FString& Query, int32 MaxResults = 0, bool ExactMatch = false);
// ----- Text formatting -----
static FString WrapText(const FString& Text, int32 ColLimit, const FString& Prefix);
// ----- Handler discovery -----
static TArray<UClass*> CollectHandlerClasses();
static FString GetHandlerName(UClass* HandlerClass);
static FString GetHandlerGroup(UClass* HandlerClass);
static void PrintHandlerHelp(UClass* HandlerClass);
// ----- Common Error Reporting -----
static bool CheckExactlyOneNamed(int Count, const FString &Kind, const FString &Name);
static bool CheckExactlyOneNamed(int Count, UClass *Class, const FString &Name);
static bool CheckExactlyNoneNamed(int Count, const FString &Kind, const FString &Name);
static bool CheckExactlyNoneNamed(int Count, UClass *Class, const FString &Name);
};