#pragma once #include "CoreMinimal.h" #include "MCPHandler.h" #include "MCPAssets.h" #include "MCPFetcher.h" #include "MCPUtils.h" #include "MCPServer.h" #include "Engine/Blueprint.h" #include "Kismet2/BlueprintEditorUtils.h" #include "UObject/UObjectIterator.h" #include "Blueprint_AddInterface.generated.h" // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- UCLASS() class UMCP_Blueprint_AddInterface : public UObject, public IMCPHandler { GENERATED_BODY() public: UPROPERTY(meta=(Description="Blueprint package path")) FString Blueprint; UPROPERTY(meta=(Description="Interface name (e.g. 'BPI_MyInterface') or native UInterface class name")) FString InterfaceName; virtual FString GetDescription() const override { return TEXT("Add a Blueprint Interface implementation to a Blueprint. " "Creates stub function graphs for each interface function."); } virtual void Handle() override { MCPFetcher F; UBlueprint* BP = F.Asset(Blueprint).Cast(); if (!BP) return; // Resolve the interface class UClass* InterfaceClass = FindInterfaceClass(InterfaceName); if (!InterfaceClass) return; // Check for duplicates for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces) { if (IfaceDesc.Interface == InterfaceClass) { UMCPServer::Printf(TEXT("ERROR: Interface '%s' is already implemented by this Blueprint.\n"), *MCPUtils::FormatName(InterfaceClass)); return; } } FTopLevelAssetPath InterfacePath = InterfaceClass->GetClassPathName(); bool bAdded = FBlueprintEditorUtils::ImplementNewInterface(BP, InterfacePath); if (!bAdded) { UMCPServer::Printf(TEXT("ERROR: ImplementNewInterface failed for '%s'.\n"), *MCPUtils::FormatName(InterfaceClass)); return; } // Collect stub function graph names from the newly added interface entry UMCPServer::Printf(TEXT("Added interface %s\n"), *MCPUtils::FormatName(InterfaceClass)); UMCPServer::Printf(TEXT("Function stubs:\n")); for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces) { if (IfaceDesc.Interface != InterfaceClass) continue; for (const UEdGraph* Graph : IfaceDesc.Graphs) { if (Graph) UMCPServer::Printf(TEXT(" %s\n"), *MCPUtils::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. 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 (MCPUtils::Identifies(Name, *It)) return *It; } // Strategy 2: Try loading as a Blueprint Interface asset MCPAssets IfaceAssets; if (!IfaceAssets.Exact(Name).AllContent().ETwo().Load()) return nullptr; if (!IfaceAssets.Objects().IsEmpty()) { UClass* GenClass = IfaceAssets.Object()->GeneratedClass; if (GenClass && GenClass->IsChildOf(UInterface::StaticClass())) return GenClass; } UMCPServer::Printf(TEXT("ERROR: Interface '%s' not found. Provide a Blueprint Interface asset name (e.g. 'BPI_MyInterface') or a native UInterface class name.\n"), *Name); return nullptr; } };