2026-03-08 22:17:14 -04:00
# pragma once
# include "CoreMinimal.h"
# include "MCPHandler.h"
2026-03-13 14:26:04 -04:00
# include "MCPAssets.h"
2026-03-14 00:02:00 -04:00
# include "MCPFetcher.h"
2026-03-08 22:17:14 -04:00
# include "MCPUtils.h"
2026-03-13 14:26:04 -04:00
# include "MCPServer.h"
2026-03-08 22:17:14 -04:00
# include "Engine/Blueprint.h"
# include "Kismet2/BlueprintEditorUtils.h"
# include "UObject/UObjectIterator.h"
2026-03-12 00:44:17 -04:00
# include "Blueprint_AddInterface.generated.h"
2026-03-08 22:17:14 -04:00
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
2026-03-12 00:44:17 -04:00
UCLASS ( )
class UMCP_Blueprint_AddInterface : public UObject , public IMCPHandler
2026-03-08 22:17:14 -04:00
{
GENERATED_BODY ( )
public :
2026-03-14 00:02:00 -04:00
UPROPERTY ( meta = ( Description = " Blueprint package path " ) )
2026-03-08 22:17:14 -04:00
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. " ) ;
}
2026-03-13 23:41:59 -04:00
virtual void Handle ( ) override
2026-03-08 22:17:14 -04:00
{
2026-03-14 00:02:00 -04:00
MCPFetcher F ;
UBlueprint * BP = F . Asset ( Blueprint ) . Cast < UBlueprint > ( ) ;
if ( ! BP ) return ;
2026-03-08 22:17:14 -04:00
// Resolve the interface class
2026-03-13 23:41:59 -04:00
UClass * InterfaceClass = FindInterfaceClass ( InterfaceName ) ;
2026-03-10 07:17:42 -04:00
if ( ! InterfaceClass ) return ;
2026-03-08 22:17:14 -04:00
// Check for duplicates
for ( const FBPInterfaceDescription & IfaceDesc : BP - > ImplementedInterfaces )
{
if ( IfaceDesc . Interface = = InterfaceClass )
{
2026-03-13 14:26:04 -04:00
UMCPServer : : Printf ( TEXT ( " ERROR: Interface '%s' is already implemented by this Blueprint. \n " ) ,
* MCPUtils : : FormatName ( InterfaceClass ) ) ;
2026-03-10 07:17:42 -04:00
return ;
2026-03-08 22:17:14 -04:00
}
}
FTopLevelAssetPath InterfacePath = InterfaceClass - > GetClassPathName ( ) ;
bool bAdded = FBlueprintEditorUtils : : ImplementNewInterface ( BP , InterfacePath ) ;
if ( ! bAdded )
{
2026-03-13 14:26:04 -04:00
UMCPServer : : Printf ( TEXT ( " ERROR: ImplementNewInterface failed for '%s'. \n " ) ,
* MCPUtils : : FormatName ( InterfaceClass ) ) ;
2026-03-10 07:17:42 -04:00
return ;
2026-03-08 22:17:14 -04:00
}
// Collect stub function graph names from the newly added interface entry
2026-03-13 23:41:59 -04:00
UMCPServer : : Printf ( TEXT ( " Added interface %s \n " ) , * MCPUtils : : FormatName ( InterfaceClass ) ) ;
UMCPServer : : Printf ( TEXT ( " Function stubs: \n " ) ) ;
2026-03-08 22:17:14 -04:00
for ( const FBPInterfaceDescription & IfaceDesc : BP - > ImplementedInterfaces )
{
2026-03-10 07:17:42 -04:00
if ( IfaceDesc . Interface ! = InterfaceClass ) continue ;
for ( const UEdGraph * Graph : IfaceDesc . Graphs )
2026-03-08 22:17:14 -04:00
{
2026-03-10 07:17:42 -04:00
if ( Graph )
2026-03-13 23:41:59 -04:00
UMCPServer : : Printf ( TEXT ( " %s \n " ) , * MCPUtils : : FormatName ( Graph ) ) ;
2026-03-08 22:17:14 -04:00
}
2026-03-10 07:17:42 -04:00
break ;
2026-03-08 22:17:14 -04:00
}
2026-03-10 07:17:42 -04:00
}
2026-03-08 22:17:14 -04:00
2026-03-10 07:17:42 -04:00
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.
2026-03-13 23:41:59 -04:00
static UClass * FindInterfaceClass ( const FString & Name )
2026-03-10 07:17:42 -04:00
{
// 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 ;
}
2026-03-08 22:17:14 -04:00
2026-03-10 07:17:42 -04:00
// Strategy 2: Try loading as a Blueprint Interface asset
MCPAssets < UBlueprint > IfaceAssets ;
2026-03-13 14:26:04 -04:00
if ( ! IfaceAssets . Exact ( Name ) . AllContent ( ) . ETwo ( ) . Load ( ) ) return nullptr ;
2026-03-10 07:17:42 -04:00
if ( ! IfaceAssets . Objects ( ) . IsEmpty ( ) )
2026-03-08 22:17:14 -04:00
{
2026-03-10 07:17:42 -04:00
UClass * GenClass = IfaceAssets . Object ( ) - > GeneratedClass ;
if ( GenClass & & GenClass - > IsChildOf ( UInterface : : StaticClass ( ) ) )
return GenClass ;
2026-03-08 22:17:14 -04:00
}
2026-03-10 07:17:42 -04:00
2026-03-13 14:26:04 -04:00
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 ) ;
2026-03-10 07:17:42 -04:00
return nullptr ;
2026-03-08 22:17:14 -04:00
}
} ;