diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_AddComponent.h b/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_AddComponent.h index f28e666e..408b1402 100644 --- a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_AddComponent.h +++ b/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_AddComponent.h @@ -27,13 +27,13 @@ public: FString Blueprint; UPROPERTY(meta=(Description="Component class name (e.g. StaticMeshComponent, SceneComponent)")) - FString ComponentClass; + FString Class; UPROPERTY(meta=(Description="Component name for the new component")) FString Component; UPROPERTY(meta=(Optional, Description="Name of the parent component to attach to")) - FString ParentComponent; + FString Parent; virtual FString GetDescription() const override { @@ -61,22 +61,22 @@ public: return; // Resolve the component class by name - UClass* ComponentClassObj = UWingTypes::TextToOneObjectType(ComponentClass); + UClass* ComponentClassObj = UWingTypes::TextToOneObjectType(Class); if (!ComponentClassObj) return; if (!ComponentClassObj->IsChildOf(UActorComponent::StaticClass())) { - UWingServer::Printf(TEXT("ERROR: '%s' is not a subclass of UActorComponent\n"), *ComponentClass); + UWingServer::Printf(TEXT("ERROR: '%s' is not a subclass of UActorComponent\n"), *Class); return; } // If parent component specified, find its SCS node USCS_Node* ParentSCSNode = nullptr; - if (!ParentComponent.IsEmpty()) + if (!Parent.IsEmpty()) { for (USCS_Node* Node : Existing) { if (Node && Node->ComponentTemplate && - WingUtils::Identifies(ParentComponent, Node->ComponentTemplate)) + WingUtils::Identifies(Parent, Node->ComponentTemplate)) { ParentSCSNode = Node; break; @@ -86,7 +86,7 @@ public: if (!ParentSCSNode) { UWingServer::Printf(TEXT("ERROR: Parent component '%s' not found in Blueprint '%s'\n"), - *ParentComponent, *WingUtils::FormatName(BP)); + *Parent, *WingUtils::FormatName(BP)); return; } } diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_RefreshAllNodes.h b/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_RefreshAllNodes.h deleted file mode 100644 index 6175a214..00000000 --- a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_RefreshAllNodes.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingUtils.h" -#include "Engine/Blueprint.h" -#include "EdGraph/EdGraph.h" -#include "EdGraph/EdGraphNode.h" -#include "EdGraph/EdGraphPin.h" -#include "Kismet2/BlueprintEditorUtils.h" -#include "Blueprint_RefreshAllNodes.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_Blueprint_RefreshAllNodes : public UObject, public IWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Blueprint package path")) - FString Blueprint; - - virtual FString GetDescription() const override - { - return TEXT("Refresh all nodes in a Blueprint, removing orphaned pins. " - "Reports compiler warnings and errors."); - } - - virtual void Handle() override - { - // Load Blueprint - WingFetcher F; - UBlueprint* BP = F.Asset(Blueprint).Cast(); - if (!BP) return; - - int32 GraphCount = WingUtils::AllGraphs(BP).Num(); - int32 NodeCount = WingUtils::AllNodes(BP).Num(); - - // Refresh all nodes - FBlueprintEditorUtils::RefreshAllNodes(BP); - - // Remove orphaned pins from all nodes - int32 OrphanedPinsRemoved = 0; - for (UEdGraphNode* Node : WingUtils::AllNodes(BP)) - { - for (int32 i = Node->Pins.Num() - 1; i >= 0; --i) - { - UEdGraphPin* Pin = Node->Pins[i]; - if (Pin && Pin->bOrphanedPin) - { - Pin->BreakAllPinLinks(); - Node->Pins.RemoveAt(i); - OrphanedPinsRemoved++; - } - } - } - - // Summary - UWingServer::Printf(TEXT("Refreshed %s: %d graphs, %d nodes"), *WingUtils::FormatName(BP), GraphCount, NodeCount); - if (OrphanedPinsRemoved > 0) - { - UWingServer::Printf(TEXT(", %d orphaned pins removed"), OrphanedPinsRemoved); - } - UWingServer::Print(TEXT("\n")); - - // Collect compiler warnings and errors - if (BP->Status == BS_Error) - { - UWingServer::Print(TEXT("ERROR: Blueprint has compiler errors after refresh\n")); - } - - for (UEdGraphNode* Node : WingUtils::AllNodes(BP)) - { - if (!Node->bHasCompilerMessage) continue; - const TCHAR* Prefix = (Node->ErrorType == EMessageSeverity::Error) ? TEXT("ERROR") : TEXT("WARNING"); - UWingServer::Printf(TEXT("%s: [%s] %s: %s\n"), - Prefix, *WingUtils::FormatName(Node->GetGraph()), - *WingUtils::FormatName(Node), *Node->ErrorMsg); - } - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_AddInterface.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_AddInterface.h similarity index 60% rename from Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_AddInterface.h rename to Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_AddInterface.h index da2a2cdc..817ac579 100644 --- a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_AddInterface.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_AddInterface.h @@ -3,11 +3,11 @@ #include "CoreMinimal.h" #include "WingHandler.h" #include "WingFetcher.h" +#include "WingTypes.h" #include "WingUtils.h" #include "WingServer.h" #include "Engine/Blueprint.h" #include "Kismet2/BlueprintEditorUtils.h" -#include "UObject/UObjectIterator.h" #include "Blueprint_AddInterface.generated.h" @@ -25,12 +25,11 @@ public: FString Blueprint; UPROPERTY(meta=(Description="Native UInterface class name or Blueprint Interface package path")) - FString InterfaceName; + FString Interface; virtual FString GetDescription() const override { - return TEXT("Add a Blueprint Interface implementation to a Blueprint. " - "Creates stub function graphs for each interface function."); + return TEXT("Add an interface to a blueprint"); } virtual void Handle() override @@ -40,7 +39,7 @@ public: if (!BP) return; // Resolve the interface class - UClass* InterfaceClass = FindInterfaceClass(InterfaceName); + UClass* InterfaceClass = UWingTypes::TextToOneInterfaceType(Interface); if (!InterfaceClass) return; // Check for duplicates @@ -65,41 +64,14 @@ public: // Collect stub function graph names from the newly added interface entry UWingServer::Printf(TEXT("Added interface %s\n"), *WingUtils::FormatName(InterfaceClass)); - UWingServer::Printf(TEXT("Function stubs:\n")); for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces) { if (IfaceDesc.Interface != InterfaceClass) continue; for (const UEdGraph* Graph : IfaceDesc.Graphs) { - if (Graph) - UWingServer::Printf(TEXT(" %s\n"), *WingUtils::FormatName(Graph)); + UWingServer::Printf(TEXT("New Graph: %s\n"), *WingUtils::FormatName(Graph)); } break; } } - -private: - // Resolve an interface name to a UClass. Tries loaded UInterface classes - // first (for native interfaces), then falls back to loading a Blueprint - // Interface asset by package path. - static UClass* FindInterfaceClass(const FString& Name) - { - // Strategy 1: Search loaded UInterface classes by name - for (TObjectIterator It; It; ++It) - { - if (!It->IsChildOf(UInterface::StaticClass())) continue; - if (WingUtils::Identifies(Name, *It)) - return *It; - } - - // Strategy 2: Try loading as a Blueprint Interface asset by package path - WingFetcher F; - UBlueprint* IfaceBP = F.Asset(Name).Cast(); - if (IfaceBP && IfaceBP->GeneratedClass && IfaceBP->GeneratedClass->IsChildOf(UInterface::StaticClass())) - return IfaceBP->GeneratedClass; - - UWingServer::Printf(TEXT("ERROR: Interface '%s' not found. Provide a native UInterface class name or Blueprint Interface package path.\n"), - *Name); - return nullptr; - } }; diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_Compile.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Compile.h similarity index 58% rename from Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_Compile.h rename to Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Compile.h index 91b19d3a..6e5408d4 100644 --- a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_Compile.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Compile.h @@ -6,6 +6,7 @@ #include "WingFetcher.h" #include "WingUtils.h" #include "Engine/Blueprint.h" +#include "EdGraph/EdGraphNode.h" #include "Kismet2/KismetEditorUtilities.h" #include "Blueprint_Compile.generated.h" @@ -20,35 +21,38 @@ class UWing_Blueprint_Compile : public UObject, public IWingHandler GENERATED_BODY() public: - UPROPERTY(meta=(Optional, Description="Path of the blueprint.")) + UPROPERTY(meta=(Description="Blueprint to compile")) FString Blueprint; virtual FString GetDescription() const override { - return TEXT("Compile a blueprint. "); + return TEXT("Compile a blueprint. " + "Reports compiler warnings and errors."); } virtual void Handle() override { WingFetcher F; - UBlueprint *BP = F.Walk(Blueprint).Cast(); + UBlueprint* BP = F.Asset(Blueprint).Cast(); + if (!BP) return; + // Compile EBlueprintCompileOptions CompileOpts = - EBlueprintCompileOptions::SkipSave | - EBlueprintCompileOptions::SkipGarbageCollection | - EBlueprintCompileOptions::SkipFiBSearchMetaUpdate; - + EBlueprintCompileOptions::SkipSave | + EBlueprintCompileOptions::SkipGarbageCollection | + EBlueprintCompileOptions::SkipFiBSearchMetaUpdate; FKismetEditorUtilities::CompileBlueprint(BP, CompileOpts, nullptr); - // Collect compiler messages from nodes + // Report compiler messages for (UEdGraphNode* Node : WingUtils::AllNodes(BP)) { if (!Node->bHasCompilerMessage) continue; - UWingServer::Printf(TEXT("%s %s: %s\n"), - *WingUtils::FormatName(Node->GetGraph()), - *WingUtils::FormatName(Node), - *Node->ErrorMsg); + const TCHAR* Prefix = (Node->ErrorType == EMessageSeverity::Error) ? TEXT("ERROR") : TEXT("WARNING"); + UWingServer::Printf(TEXT("%s: [%s] %s: %s\n"), + Prefix, *WingUtils::FormatName(Node->GetGraph()), + *WingUtils::FormatName(Node), *Node->ErrorMsg); } + UWingServer::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 d281612d..72710bc8 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Dump.h @@ -61,8 +61,7 @@ public: // Interfaces for (const FBPInterfaceDescription& I : BP->ImplementedInterfaces) { - if (I.Interface) - UWingServer::Printf(TEXT("Interface: %s\n"), *WingUtils::FormatName(I.Interface)); + if (I.Interface) UWingServer::Printf(TEXT("Interface: %s\n"), *WingUtils::FormatName(I)); } // Variables diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_RemoveInterface.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_RemoveInterface.h similarity index 70% rename from Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_RemoveInterface.h rename to Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_RemoveInterface.h index 882a4658..de9547f1 100644 --- a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_RemoveInterface.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_RemoveInterface.h @@ -24,7 +24,7 @@ public: FString Blueprint; UPROPERTY(meta=(Description="Interface name to remove")) - FString InterfaceName; + FString Interface; UPROPERTY(meta=(Optional, Description="If true, keep the function graphs as regular functions")) bool PreserveFunctions = false; @@ -42,27 +42,10 @@ public: if (!BP) return; // Find the interface by name - UClass* FoundInterface = nullptr; - for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces) - { - if (!IfaceDesc.Interface) continue; - if (WingUtils::Identifies(InterfaceName, IfaceDesc.Interface)) - { - FoundInterface = IfaceDesc.Interface; - break; - } - } - - if (!FoundInterface) - { - UWingServer::Printf(TEXT("ERROR: Interface '%s' not found. Implemented interfaces:\n"), *InterfaceName); - for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces) - { - if (IfaceDesc.Interface) - UWingServer::Printf(TEXT(" %s\n"), *WingUtils::FormatName(IfaceDesc.Interface)); - } - return; - } + FBPInterfaceDescription *IFaceDesc = + WingUtils::FindExactlyOneNamed(Interface, BP->ImplementedInterfaces); + if (!IFaceDesc) return; + UClass* FoundInterface = IFaceDesc->Interface; FTopLevelAssetPath InterfacePath = FoundInterface->GetClassPathName(); FBlueprintEditorUtils::RemoveInterface(BP, InterfacePath, PreserveFunctions); diff --git a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_Reparent.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Reparent.h similarity index 84% rename from Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_Reparent.h rename to Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Reparent.h index 414c8c1d..09ddaa8f 100644 --- a/Plugins/UEWingman/Source/UEWingman/HalfBaked/Blueprint_Reparent.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Blueprint_Reparent.h @@ -40,8 +40,6 @@ public: UBlueprint* BP = F.Asset(Blueprint).Cast(); if (!BP) return; - FString OldParentName = BP->ParentClass ? WingUtils::FormatName(BP->ParentClass) : TEXT("None"); - // Find the new parent class by short type name UClass* NewParentClassObj = UWingTypes::TextToOneObjectType(Parent); if (!NewParentClassObj) return; @@ -51,7 +49,7 @@ public: FBlueprintEditorUtils::RefreshAllNodes(BP); FKismetEditorUtilities::CompileBlueprint(BP); - UWingServer::Printf(TEXT("Reparented %s: %s -> %s\n"), - *WingUtils::FormatName(BP), *OldParentName, *WingUtils::FormatName(NewParentClassObj)); + UWingServer::Printf(TEXT("Reparented %s -> %s\n"), + *WingUtils::FormatName(BP), *WingUtils::FormatName(NewParentClassObj)); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp index 1a40f87d..0e18b989 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingUtils.cpp @@ -210,6 +210,11 @@ FString WingUtils::FormatName(const FUserPinInfo &Pin) return SanitizeName(Pin.PinName); } +FString WingUtils::FormatName(const FBPInterfaceDescription &IFace) +{ + return FormatName(IFace.Interface); +} + // ============================================================ // Formatting other things // ============================================================ diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h index 8e0caa7f..5382cc6c 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h @@ -31,6 +31,8 @@ class USCS_Node; struct FMemberReference; struct FBPVariableDescription; struct FUserPinInfo; +struct FBPInterfaceDescription; + // Stateless utility functions used by MCP handlers and the MCP server. // This is effectively a namespace — all methods are static. class WingUtils @@ -73,6 +75,7 @@ public: static FString FormatName(const UEnum *Enum); static FString FormatName(const FProperty *Prop); static FString FormatName(const FUserPinInfo &Pin); + static FString FormatName(const FBPInterfaceDescription &IFace); //////////////////////////////////////////////////////// //