diff --git a/.mcp.json b/.mcp.json index 45d7e5fa..9e7c12b9 100644 --- a/.mcp.json +++ b/.mcp.json @@ -1,6 +1,6 @@ { "mcpServers": { - "blueprint-mcp": { + "ue-wingman": { "command": "python3", "args": ["tools/mcp-bridge.py"] } diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/AnimBlueprint_ListSyncGroups.h b/Plugins/UEWingman/Deprecated/AnimBlueprint_ListSyncGroups.h similarity index 100% rename from Plugins/UEWingman/Source/UEWingman/HalfBaked/AnimBlueprint_ListSyncGroups.h rename to Plugins/UEWingman/Deprecated/AnimBlueprint_ListSyncGroups.h diff --git a/Plugins/UEWingman/Deprecated/UMCPHandler_AddMaterialExpression.h b/Plugins/UEWingman/Deprecated/UMCPHandler_AddMaterialExpression.h index b0d8e847..4534c051 100644 --- a/Plugins/UEWingman/Deprecated/UMCPHandler_AddMaterialExpression.h +++ b/Plugins/UEWingman/Deprecated/UMCPHandler_AddMaterialExpression.h @@ -17,7 +17,7 @@ // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- -UCLASS(meta=(Group="Unclassified")) +UCLASS() class UMCPHandler_AddMaterialExpression : public UObject, public IMCPHandler { GENERATED_BODY() diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/AnimBlueprint_ListSlotNames.h b/Plugins/UEWingman/Source/UEWingman/HalfBaked/AnimBlueprint_ListSlotNames.h deleted file mode 100644 index 7c2d5851..00000000 --- a/Plugins/UEWingman/Source/UEWingman/HalfBaked/AnimBlueprint_ListSlotNames.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "Animation/AnimBlueprint.h" -#include "AnimGraphNode_Base.h" -#include "AnimBlueprint_ListSlotNames.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_AnimBlueprint_ListSlotNames : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Animation Blueprint package path")) - FString Blueprint; - - virtual FString GetDescription() const override - { - return TEXT("List all animation slot names used in an Animation Blueprint."); - } - - virtual void Handle() override - { - WingFetcher F; - UAnimBlueprint* AnimBP = F.Asset(Blueprint).Cast(); - if (!AnimBP) return; - - // Walk all anim nodes to collect slot names - TSet SlotNames; - for (UAnimGraphNode_Base* AnimNode : WingUtils::AllNodes(AnimBP)) - { - for (TFieldIterator PropIt(AnimNode->GetClass()); PropIt; ++PropIt) - { - if (PropIt->GetName().Contains(TEXT("SlotName")) || PropIt->GetName().Contains(TEXT("Slot"))) - { - FName SlotValue = PropIt->GetPropertyValue_InContainer(AnimNode); - if (!SlotValue.IsNone()) - { - SlotNames.Add(SlotValue.ToString()); - } - } - } - } - - for (const FString& Slot : SlotNames) - { - UWingServer::Printf(TEXT("%s\n"), *Slot); - } - - if (SlotNames.Num() == 0) - { - UWingServer::Print(TEXT("No animation slot names found.\n")); - } - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_Dump.h b/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_Dump.h deleted file mode 100644 index d328bc7d..00000000 --- a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_Dump.h +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingTypes.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "Engine/Blueprint.h" -#include "Animation/AnimBlueprint.h" -#include "Animation/Skeleton.h" -#include "Engine/SimpleConstructionScript.h" -#include "Engine/SCS_Node.h" -#include "Blueprint_Dump.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_Blueprint_Dump : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Blueprint path")) - FString Blueprint; - - virtual FString GetDescription() const override - { - return TEXT("Dump a Blueprint's structure: variables, interfaces, components, " - "and graph names. Does not include graph contents (use Graph_Dump for that)."); - } - - virtual void Handle() override - { - WingFetcher F; - 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)); - - // Animation Blueprint - if (UAnimBlueprint* AnimBP = Cast(BP)) - { - if (AnimBP->TargetSkeleton) - UWingServer::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.Interface)); - } - - // Variables - if (!BP->NewVariables.IsEmpty()) - { - UWingServer::Print(TEXT("\nVariables:\n")); - for (const FBPVariableDescription& V : BP->NewVariables) - { - UWingServer::Printf(TEXT(" %s %s"), - *UWingTypes::TypeToText(V.VarType), - *WingUtils::FormatName(V)); - if (!V.DefaultValue.IsEmpty()) - UWingServer::Printf(TEXT(" = %s"), *V.DefaultValue); - if (!V.Category.IsEmpty() && V.Category.ToString() != TEXT("Default")) - UWingServer::Printf(TEXT(" [%s]"), *V.Category.ToString()); - UWingServer::Print(TEXT("\n")); - } - } - - // Components - if (USimpleConstructionScript* SCS = BP->SimpleConstructionScript) - { - const TArray& AllNodes = SCS->GetAllNodes(); - if (!AllNodes.IsEmpty()) - { - UWingServer::Print(TEXT("\nComponents:\n")); - for (USCS_Node* Node : AllNodes) - { - if (!Node || !Node->ComponentTemplate) continue; - UWingServer::Printf(TEXT(" %s (%s)"), - *WingUtils::FormatName(Node->ComponentTemplate), - *WingUtils::FormatName(Node->ComponentClass)); - if (Node->ParentComponentOrVariableName != NAME_None) - UWingServer::Printf(TEXT(" parent=%s"), *Node->ParentComponentOrVariableName.ToString()); - UWingServer::Print(TEXT("\n")); - } - } - } - - // Graph names (without contents) - TArray Graphs = WingUtils::AllGraphs(BP); - if (!Graphs.IsEmpty()) - { - UWingServer::Print(TEXT("\nGraphs:\n")); - for (UEdGraph* Graph : Graphs) - UWingServer::Printf(TEXT(" %s\n"), *WingUtils::FormatName(Graph)); - } - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_ListComponents.h b/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_ListComponents.h deleted file mode 100644 index 9158e0de..00000000 --- a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_ListComponents.h +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "Engine/Blueprint.h" -#include "Engine/SimpleConstructionScript.h" -#include "Engine/SCS_Node.h" -#include "Blueprint_ListComponents.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_Blueprint_ListComponents : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Path to a blueprint, e.g. /Game/Tangibles/TAN_Tree")) - FString Blueprint; - - virtual FString GetDescription() const override - { - return TEXT("List all components in a Blueprint's SimpleConstructionScript, " - "showing hierarchy and component classes."); - } - - virtual void Handle() override - { - WingFetcher F; - F.Walk(Blueprint); - if (!F.Ok()) return; - - UBlueprint* BP = F.Cast(); - if (!BP) return; - - USimpleConstructionScript* SCS = BP->SimpleConstructionScript; - if (!SCS) - { - UWingServer::Print(TEXT("ERROR: Not an Actor Blueprint (no SimpleConstructionScript)\n")); - return; - } - - const TArray& RootNodes = SCS->GetRootNodes(); - const TArray& AllNodes = SCS->GetAllNodes(); - - if (AllNodes.Num() == 0) - { - UWingServer::Print(TEXT("No components.\n")); - return; - } - - UWingServer::Print(TEXT("WARNING: This only lists components added in this blueprint's SCS. " - "It does not include inherited components from C++ parent classes " - "(available via the CDO's OwnedComponents) or from parent blueprint SCS nodes.\n")); - - // Emit components as a tree, starting from root nodes - for (USCS_Node* Root : RootNodes) - { - if (!Root) continue; - EmitNode(Root, 0, Root == RootNodes[0]); - } - } - -private: - void EmitNode(USCS_Node* Node, int32 Depth, bool bIsSceneRoot) - { - // Indent to show hierarchy - for (int32 i = 0; i < Depth; i++) - UWingServer::Print(TEXT(" ")); - - FString ClassName = Node->ComponentClass - ? WingUtils::FormatName(Node->ComponentClass) - : TEXT("None"); - - UWingServer::Printf(TEXT("%s %s"), - *ClassName, - *WingUtils::FormatName(Node->ComponentTemplate)); - - if (bIsSceneRoot && Depth == 0) - UWingServer::Print(TEXT(" [SceneRoot]")); - - UWingServer::Print(TEXT("\n")); - - for (USCS_Node* Child : Node->GetChildNodes()) - { - if (!Child) continue; - EmitNode(Child, Depth + 1, false); - } - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_ListEventDispatchers.h b/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_ListEventDispatchers.h deleted file mode 100644 index 3df9f5be..00000000 --- a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_ListEventDispatchers.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingTypes.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "Engine/Blueprint.h" -#include "EdGraph/EdGraph.h" -#include "EdGraph/EdGraphPin.h" -#include "K2Node_FunctionEntry.h" -#include "K2Node_EditablePinBase.h" -#include "Kismet2/BlueprintEditorUtils.h" -#include "Blueprint_ListEventDispatchers.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_Blueprint_ListEventDispatchers : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Path to a blueprint, e.g. /Game/Foo/MyBlueprint")) - FString Blueprint; - - virtual FString GetDescription() const override - { - return TEXT("List all event dispatchers on a Blueprint, including their parameter signatures."); - } - - virtual void Handle() override - { - WingFetcher F; - UBlueprint* BP = F.Walk(Blueprint).Cast(); - if (!BP) return; - - TSet DelegateNameSet; - FBlueprintEditorUtils::GetDelegateNameList(BP, DelegateNameSet); - - for (const FName& DelegateName : DelegateNameSet) - { - UWingServer::Printf(TEXT("%s("), *DelegateName.ToString()); - - UEdGraph* SigGraph = FBlueprintEditorUtils::GetDelegateSignatureGraphByName(BP, DelegateName); - if (SigGraph) - { - bool bFirst = true; - for (UK2Node_FunctionEntry* FE : WingUtils::AllNodes(SigGraph)) - { - for (const TSharedPtr& PinInfo : FE->UserDefinedPins) - { - if (!PinInfo.IsValid()) continue; - if (!bFirst) UWingServer::Print(TEXT(", ")); - bFirst = false; - UWingServer::Printf(TEXT("%s %s"), - *UWingTypes::TypeToText(PinInfo->PinType), - *PinInfo->PinName.ToString()); - } - break; // only need the first entry node - } - } - - UWingServer::Print(TEXT(")\n")); - } - - if (DelegateNameSet.Num() == 0) - { - UWingServer::Print(TEXT("No event dispatchers found.\n")); - } - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_ListInterfaces.h b/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_ListInterfaces.h deleted file mode 100644 index 1d2c00c3..00000000 --- a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_ListInterfaces.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "Engine/Blueprint.h" -#include "Blueprint_ListInterfaces.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_Blueprint_ListInterfaces : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Path to a blueprint, e.g. /Game/Foo/MyBlueprint")) - FString Blueprint; - - virtual FString GetDescription() const override - { - return TEXT("List all Blueprint Interfaces implemented by a Blueprint, " - "including their function graphs."); - } - - virtual void Handle() override - { - WingFetcher F; - F.Walk(Blueprint); - if (!F.Ok()) return; - UBlueprint* BP = F.Cast(); - if (!BP) return; - - bool bAny = false; - for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces) - { - if (!IfaceDesc.Interface) continue; - bAny = true; - - UWingServer::Printf(TEXT("Interface: %s\n"), *WingUtils::FormatName(IfaceDesc.Interface)); - for (const UEdGraph* Graph : IfaceDesc.Graphs) - { - if (!Graph) continue; - UWingServer::Printf(TEXT(" %s\n"), *WingUtils::FormatName(Graph)); - } - } - - if (!bAny) - { - UWingServer::Print(TEXT("No interfaces implemented.\n")); - } - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h new file mode 100644 index 00000000..d281612d --- /dev/null +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h @@ -0,0 +1,258 @@ +#pragma once + +#include "CoreMinimal.h" +#include "WingServer.h" +#include "WingTypes.h" +#include "WingHandler.h" +#include "WingFetcher.h" +#include "WingUtils.h" +#include "Engine/Blueprint.h" +#include "Animation/AnimBlueprint.h" +#include "Animation/Skeleton.h" +#include "Engine/SimpleConstructionScript.h" +#include "Engine/SCS_Node.h" +#include "Components/SceneComponent.h" +#include "GameFramework/Actor.h" +#include "WingFunctionArgs.h" +#include "Kismet2/BlueprintEditorUtils.h" +#include "AnimationGraph.h" +#include "AnimationGraphSchema.h" +#include "AnimationStateMachineSchema.h" +#include "Blueprint_Dump.generated.h" + + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +UCLASS() +class UWing_Blueprint_Dump : public UObject, public IWingHandler +{ + GENERATED_BODY() + +public: + UPROPERTY(meta=(Description="Blueprint path")) + FString Blueprint; + + virtual FString GetDescription() const override + { + return TEXT("Dump a Blueprint's structure: variables, interfaces, components, " + "and graph names. Does not include graph contents (use Graph_Dump for that)."); + } + + virtual void Handle() override + { + WingFetcher F; + 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)); + + // Animation Blueprint + if (UAnimBlueprint* AnimBP = Cast(BP)) + { + if (AnimBP->TargetSkeleton) + UWingServer::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.Interface)); + } + + // Variables + if (!BP->NewVariables.IsEmpty()) + { + UWingServer::Print(TEXT("\nVariables:\n")); + for (const FBPVariableDescription& V : BP->NewVariables) + { + UWingServer::Printf(TEXT(" %s %s"), + *UWingTypes::TypeToText(V.VarType), + *WingUtils::FormatName(V)); + if (!V.DefaultValue.IsEmpty()) + UWingServer::Printf(TEXT(" = %s"), *V.DefaultValue); + if (!V.Category.IsEmpty() && V.Category.ToString() != TEXT("Default")) + UWingServer::Printf(TEXT(" [%s]"), *V.Category.ToString()); + UWingServer::Print(TEXT("\n")); + } + } + + // Components + bool bHasAny = false; + if (UClass* GenClass = BP->GeneratedClass) + { + // Native components first. + if (AActor* CDO = Cast(GenClass->GetDefaultObject())) + { + TArray NativeComponents; + CDO->GetComponents(NativeComponents); + for (UActorComponent* Comp : NativeComponents) + { + if (!bHasAny) { UWingServer::Print(TEXT("\nComponents:\n")); bHasAny = true; } + PrintComponent(Comp, TEXT("native")); + } + } + + // Blueprint SCS components (this blueprint and parents) + TArray Hierarchy; + UBlueprint::GetBlueprintHierarchyFromClass(GenClass, Hierarchy); + for (int32 i = Hierarchy.Num() - 1; i >= 0; --i) + { + UBlueprint* WalkBP = Hierarchy[i]; + if (!WalkBP->SimpleConstructionScript) continue; + const TCHAR* Annotation = (WalkBP == BP) ? nullptr : TEXT("inherited"); + for (USCS_Node* Node : WalkBP->SimpleConstructionScript->GetAllNodes()) + { + if (!bHasAny) { UWingServer::Print(TEXT("\nComponents:\n")); bHasAny = true; } + PrintComponent(Node, Annotation); + } + } + } + + // Event Dispatchers + if (!BP->DelegateSignatureGraphs.IsEmpty()) + { + UWingServer::Print(TEXT("\nEvent Dispatchers:\n")); + for (UEdGraph* Graph : BP->DelegateSignatureGraphs) + PrintEventDispatcher(Graph); + } + + // Graphs + TSet Printed; + + UWingServer::Print(TEXT("\nGraphs:\n")); + for (UEdGraph* Graph : BP->UbergraphPages) + { + UWingServer::Printf(TEXT(" EventGraph %s\n"), *WingUtils::FormatName(Graph)); + Printed.Add(Graph); + } + for (UEdGraph* Graph : BP->FunctionGraphs) + { + if (Graph->IsA()) continue; + PrintGraph(Graph, TEXT("Function")); + Printed.Add(Graph); + } + for (UEdGraph* Graph : BP->MacroGraphs) + { + PrintGraph(Graph, TEXT("Macro")); + Printed.Add(Graph); + } + for (const FBPInterfaceDescription& I : BP->ImplementedInterfaces) + for (UEdGraph* Graph : I.Graphs) + { + PrintGraph(Graph, TEXT("Interface"), I.Interface); + Printed.Add(Graph); + } + + // Delegate signature graphs are not real graphs, but mark them as printed. + for (UEdGraph* Graph : BP->DelegateSignatureGraphs) + Printed.Add(Graph); + + // Animation graphs and state machines. + TArray AllGraphs = WingUtils::AllGraphs(BP); + + FString AnimGraphNames; + for (UEdGraph* Graph : AllGraphs) + { + if (Printed.Contains(Graph)) continue; + if (!Graph->Schema || !Graph->Schema->IsChildOf(UAnimationGraphSchema::StaticClass())) continue; + if (!AnimGraphNames.IsEmpty()) AnimGraphNames += TEXT(", "); + AnimGraphNames += WingUtils::FormatName(Graph); + Printed.Add(Graph); + } + if (!AnimGraphNames.IsEmpty()) + UWingServer::Printf(TEXT("\nAnimation Graphs: %s\n"), *AnimGraphNames); + + FString StateMachineNames; + for (UEdGraph* Graph : AllGraphs) + { + if (Printed.Contains(Graph)) continue; + if (!Graph->Schema || !Graph->Schema->IsChildOf(UAnimationStateMachineSchema::StaticClass())) continue; + if (!StateMachineNames.IsEmpty()) StateMachineNames += TEXT(", "); + StateMachineNames += WingUtils::FormatName(Graph); + Printed.Add(Graph); + } + if (!StateMachineNames.IsEmpty()) + UWingServer::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"), + *WingUtils::FormatName(Graph), + *WingUtils::FormatName(Graph->GetSchema()->GetClass())); + } + } + +private: + void PrintEventDispatcher(UEdGraph* Graph) + { + TWeakObjectPtr EntryNode; + TWeakObjectPtr ResultNode; + FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, EntryNode, ResultNode); + + FString Args; + if (EntryNode.IsValid() && WingFunctionArgs::HasArgs(EntryNode.Get())) + Args = WingFunctionArgs::GetArgs(EntryNode.Get()); + + UWingServer::Printf(TEXT(" %s(%s)\n"), *WingUtils::FormatName(Graph), *Args); + } + + void PrintComponent(USCS_Node* Node, const TCHAR* Annotation = nullptr) + { + FString ClassName = Node->ComponentClass + ? WingUtils::FormatName(Node->ComponentClass) + : TEXT("None"); + UWingServer::Printf(TEXT(" %s %s"), + *ClassName, + *WingUtils::FormatName(Node)); + if (Node->ParentComponentOrVariableName != NAME_None) + UWingServer::Printf(TEXT(" [parent: %s]"), *Node->ParentComponentOrVariableName.ToString()); + if (Annotation) + UWingServer::Printf(TEXT(" [%s]"), Annotation); + UWingServer::Print(TEXT("\n")); + } + + void PrintComponent(UActorComponent* Comp, const TCHAR* Annotation = nullptr) + { + UWingServer::Printf(TEXT(" %s %s"), + *WingUtils::FormatName(Comp->GetClass()), + *Comp->GetName()); + if (USceneComponent* Scene = Cast(Comp)) + if (USceneComponent* Parent = Scene->GetAttachParent()) + UWingServer::Printf(TEXT(" [parent: %s]"), *Parent->GetName()); + if (Annotation) + UWingServer::Printf(TEXT(" [%s]"), Annotation); + UWingServer::Print(TEXT("\n")); + } + + void PrintGraph(UEdGraph* Graph, const TCHAR* Type, UClass* Interface = nullptr) + { + TWeakObjectPtr EntryNode; + TWeakObjectPtr ResultNode; + FBlueprintEditorUtils::GetEntryAndResultNodes(Graph, EntryNode, ResultNode); + + FString InputArgs; + FString OutputArgs; + if (EntryNode.IsValid() && WingFunctionArgs::HasArgs(EntryNode.Get())) + InputArgs = WingFunctionArgs::GetArgs(EntryNode.Get()); + if (ResultNode.IsValid() && WingFunctionArgs::HasArgs(ResultNode.Get())) + OutputArgs = WingFunctionArgs::GetArgs(ResultNode.Get()); + + UWingServer::Printf(TEXT(" %s %s"), Type, *WingUtils::FormatName(Graph)); + if (!InputArgs.IsEmpty()) + UWingServer::Printf(TEXT("(%s)"), *InputArgs); + if (!OutputArgs.IsEmpty()) + UWingServer::Printf(TEXT(" -> (%s)"), *OutputArgs); + if (Interface) + UWingServer::Printf(TEXT(" [%s]"), *WingUtils::FormatName(Interface)); + UWingServer::Print(TEXT("\n")); + } + +}; diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp index 0a3d93fc..ae7119e2 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp @@ -7,6 +7,7 @@ #include "Engine/MemberReference.h" #include "Engine/World.h" #include "Components/ActorComponent.h" +#include "Engine/SCS_Node.h" #include "EdGraph/EdGraph.h" #include "EdGraph/EdGraphNode.h" #include "EdGraph/EdGraphPin.h" @@ -85,6 +86,11 @@ FString WingUtils::FormatName(const UActorComponent *C) return C->GetName(); } +FString WingUtils::FormatName(const USCS_Node *Node) +{ + return Node->GetVariableName().ToString(); +} + FString WingUtils::FormatName(const UEdGraph *Graph) { FString Name = Graph->GetName(); diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h index 0d186830..ba86c145 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h @@ -27,6 +27,7 @@ class UBlendSpace; class UTexture; class UScriptStruct; class UEnum; +class USCS_Node; struct FMemberReference; struct FBPVariableDescription; // Stateless utility functions used by MCP handlers and the MCP server. @@ -50,6 +51,7 @@ public: 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);