Files
integration/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/Blueprint_AddInterface.h

115 lines
3.6 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.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 name or 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(FStringBuilderBase& Result) override
{
MCPAssets<UBlueprint> Assets;
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
UBlueprint* BP = Assets.Object();
// Resolve the interface class
UClass* InterfaceClass = FindInterfaceClass(InterfaceName, Result);
if (!InterfaceClass) return;
// Check for duplicates
for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces)
{
if (IfaceDesc.Interface == InterfaceClass)
{
MCPErrorCallback(Result).SetError(FString::Printf(
TEXT("Interface '%s' is already implemented by this Blueprint."),
*MCPUtils::FormatName(InterfaceClass)));
return;
}
}
FTopLevelAssetPath InterfacePath = InterfaceClass->GetClassPathName();
MCPUtils::PreEdit({BP});
bool bAdded = FBlueprintEditorUtils::ImplementNewInterface(BP, InterfacePath);
if (!bAdded)
{
MCPErrorCallback(Result).SetError(FString::Printf(
TEXT("ImplementNewInterface failed for '%s'."),
*MCPUtils::FormatName(InterfaceClass)));
return;
}
// Collect stub function graph names from the newly added interface entry
MCPUtils::PostEdit({BP});
Result.Appendf(TEXT("Added interface %s\n"), *MCPUtils::FormatName(InterfaceClass));
Result.Appendf(TEXT("Function stubs:\n"));
for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces)
{
if (IfaceDesc.Interface != InterfaceClass) continue;
for (const UEdGraph* Graph : IfaceDesc.Graphs)
{
if (Graph)
Result.Appendf(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, FStringBuilderBase& Result)
{
// Strategy 1: Search loaded UInterface classes by name
for (TObjectIterator<UClass> 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<UBlueprint> IfaceAssets;
if (!IfaceAssets.Exact(Name).AllContent().Errors(Result).ETwo().Load()) return nullptr;
if (!IfaceAssets.Objects().IsEmpty())
{
UClass* GenClass = IfaceAssets.Object()->GeneratedClass;
if (GenClass && GenClass->IsChildOf(UInterface::StaticClass()))
return GenClass;
}
MCPErrorCallback(Result).SetError(FString::Printf(
TEXT("Interface '%s' not found. Provide a Blueprint Interface asset name (e.g. 'BPI_MyInterface') or a native UInterface class name."),
*Name));
return nullptr;
}
};