C++中调用蓝图资产

 UEditorUtilitySubsystem* EditorUtilitySubsystem = GEditor->GetEditorSubsystem<UEditorUtilitySubsystem>();
 if (EditorUtilitySubsystem)
 {
 	FAssetData SuraToolsAsset(
 		TEXT("/SuraControlPanel/SURA-ToolSets511"), // SURA-ToolSets511.uasset
 		TEXT("/SuraControlPanel"),
 		TEXT("SURA-ToolSets511"),
 		UEditorUtilityWidgetBlueprint::StaticClass()->GetClassPathName()
 	); // asset路径在编辑器里通过Reference Viewer可以获得
 	auto WidgetBP = CastChecked<UEditorUtilityWidgetBlueprint>(SuraToolsAsset.GetAsset());
 	if (TabID == NAME_None)
 	{
 		EditorUtilitySubsystem->SpawnAndRegisterTabAndGetID(WidgetBP, TabID);
 	}
 	else
 	{
 		if (EditorUtilitySubsystem->DoesTabExist(TabID))
 		{
 			EditorUtilitySubsystem->CloseTabByID(TabID);
 		}
 		else
 		{
                        EditorUtilitySubsystem->SpawnRegisteredTabByID(TabID);
 		}
 	}
 }

FAssetData对象的创建

#480
 FAssetData ShadowCaptureActorAssetData(
 		TEXT("/SURAPlugin/ARShadow/ShadowGenerator/BluePrints/ShadowCapture"),
 		TEXT("/SURAPlugin/ARShadow/ShadowGenerator/BluePrints"),
 		TEXT("ShadowCapture"),
 		TEXT("Blueprint")
 ); // asset路径在编辑器里通过Reference Viewer可以获得
调用的是如下构造函数:
FAssetData(InPackageName, InPackagePath, InAssetName, InAssetClass)
UE5.1版的新API形式:
 // Run test on a single TestPlan asset
 FName PackageName = FName(FPaths::GetBaseFilename(Path, false));
 FName PackagePath = FName(FPaths::GetPath(Path));
 FName AssetName = FName(FPaths::GetBaseFilename(Path, true));
 FTopLevelAssetPath ClassName = UInterchangeImportTestPlan::StaticClass()->GetClassPathName();
 FInterchangeImportTestData& TP = TestPlans.AddDefaulted_GetRef();
 TP.AssetData = FAssetData(PackageName, PackagePath, AssetName, ClassName);

UObject类型获取其Asset Path

FTopLevelAssetPath ClassName =  UObject::StaticClass()->GetClassPathName();


//
// 注意这里UObject类型的AssetPath都是【/Script/Package.Class】的固定格式
// 之所以是这个固定格式,是因为其.generated.h里有DECLARE_CLASS宏调用,其注册的该UObject的PackagePath就是【/Script/Package】的格式
// 例如:/Script/Engine.Blueprint表示Engine模块的UBlueprint
// 
UClass* USuraControlPanelCommonBPLibrary::LoadCppClass( const FString& AssetPath )
{
	return ::StaticLoadClass(UObject::StaticClass(), nullptr, *AssetPath);
}

UObject Paths

Every Asset and Actor that the Unreal Editor has loaded in memory has a path that uniquely identifies it.
In general, these object paths follow the format:
 /path/PackageName.ObjectName:SubObjectName.SubObject
Programmers who work with the Engine in C++ may recognize this format as the same one accepted by functions like FindObject() and StaticFindObject().
For example, to deconstruct an Actor path shown in the request examples above:
/Game/ThirdPersonBP/Maps/The path to the Asset in the Content Browser.
ThirdPersonExampleMap.ThirdPersonExampleMap:The name of the package and the object it contains (for many Assets, these will be the same).
PersistentLevel.CubeMesh_5.StaticMeshComponent0The path through a hierarchy of sub-objects to the object you want to affect.
如上表所示,Path部分很好理解,在Content Browser里可以直接看到。而PackageName通常就是资产文件名,资产里包含若干Object,它们各有ObjectName,即资产文件其实是个Package

Interface在C++中的语法及使用

判断是否实现接口(参考):
若是C++里定义的接口,在蓝图里进行了实现,则在C++里通过该对象进行接口调用的方法如下:
 auto Owner = GetOwner<APawn>();
 if (Owner && Owner->GetClass()->ImplementsInterface(UAnjUpdatePoseInterface::StaticClass()))
 {
     IAnjUpdatePoseInterface::Execute_OnPoseUpdate(Owner, PoseData);
 }

UInterface and IInterface

///////// header file /////////
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "UObject/Interface.h"
#include "WhenCalled.generated.h"

class IWhenCalledInterface;
class UWhenCalledInterface;

UINTERFACE(BlueprintType, MinimalAPI)
class UWhenCalledManagerInterface: public UInterface
{
	GENERATED_UINTERFACE_BODY()
};

class SURAXR_API IWhenCalledManagerInterface
{
	GENERATED_IINTERFACE_BODY()
public:
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="SURAXR")
	int AddHandler(const TScriptInterface<IWhenCalledInterface>& Handler);

	virtual void BindDelegates() = 0;
};

UINTERFACE(BlueprintType, MinimalAPI)
class UWhenCalledInterface: public UInterface
{
	GENERATED_UINTERFACE_BODY()
};

class SURAXR_API IWhenCalledInterface
{
	GENERATED_IINTERFACE_BODY()
public:
	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
	int GetPriority() const;

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
	void DoAtBeginFrame();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
	void DoAtEndFrame();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
	void DoAtBeginFrameRT();

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
	void DoAtEndFrameRT();
};

UCLASS(Blueprintable, BlueprintType)
class SURAXR_API AWhenCalled : public AActor, public IWhenCalledManagerInterface
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AWhenCalled();

	// Begin IWhenCalledManagerInterface
	// Return: 0 on success; -1 on null Handler; 1 on Handler exists; 2 on Priority conflicts.
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="SURAXR")
	int AddHandler(const TScriptInterface<IWhenCalledInterface>& Handler);
	virtual int AddHandler_Implementation(const TScriptInterface<IWhenCalledInterface>& Handler) override;
	virtual void BindDelegates() override;
	// End IWhenCalledManagerInterface

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

private:
	// Begin IWhenCalledManagerInterface
	UPROPERTY()
	TMap<int, TScriptInterface<IWhenCalledInterface>> Manager;
	// End IWhenCalledManagerInterface
};


//////// implementation file //////
// Fill out your copyright notice in the Description page of Project Settings.


#include "WhenCalled.h"

UWhenCalledInterface::UWhenCalledInterface(class FObjectInitializer const &ObjectInitializer)
	:Super(ObjectInitializer)
{}

UWhenCalledManagerInterface::UWhenCalledManagerInterface(class FObjectInitializer const &ObjectInitializer)
	:Super(ObjectInitializer)
{}

// Sets default values
AWhenCalled::AWhenCalled()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

int AWhenCalled::AddHandler_Implementation( const TScriptInterface<IWhenCalledInterface>& Handler )
{
	UObject* Object = Handler.GetObject();
	IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object);
	if (Object || IHandler)
	{
		if (Manager.FindKey(Handler) != nullptr)
		{
			return 1; // Handler exists
		}

		TArray<int> Keys;
		Manager.GetKeys(Keys);
		for (int k: Keys)
		{
			int Prior = IHandler == nullptr? IWhenCalledInterface::Execute_GetPriority(Object) : IHandler->GetPriority();
			if (k == Prior)
			{
				return 2; // Priority conflicts.
			}
		}

		int Prior = IHandler == nullptr ? IWhenCalledInterface::Execute_GetPriority(Object) : IHandler->GetPriority();
		Manager.Add(Prior, Handler);
		Manager.KeyStableSort([](int A, int B)
		{
			return A < B;
		});
		return 0;
	}
	return -1;
}

void AWhenCalled::BindDelegates( )
{
	FCoreDelegates::OnBeginFrame.AddWeakLambda(this, [this]()
	{
		for (auto& iter : Manager)
		{
			UObject* Object = iter.Value.GetObject();
			if (Object)
			{
				IWhenCalledInterface::Execute_DoAtBeginFrame(Object);
				continue;
			}

			IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object);
			if (IHandler)
			{
				IHandler->DoAtBeginFrame();
				continue;
			}
		}
	});
	FCoreDelegates::OnEndFrame.AddWeakLambda(this, [this]()
	{
		for (auto& iter : Manager)
		{
			UObject* Object = iter.Value.GetObject();
			if (Object)
			{
				IWhenCalledInterface::Execute_DoAtEndFrame(Object);
				continue;
			}

			IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object);
			if (IHandler)
			{
				IHandler->DoAtEndFrame();
				continue;
			}
		}
	});
	/*FCoreDelegates::OnBeginFrameRT.AddWeakLambda(this, [this]()
	{
		for (auto& iter : Manager)
		{
			IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(iter.Value);
			if (IHandler)
			{
				IHandler->DoAtBeginFrameRT();
			}
		}
	});
	FCoreDelegates::OnEndFrameRT.AddWeakLambda(this, [this]()
	{
		for (auto& iter : Manager)
		{
			IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(iter.Value);
			if (IHandler)
			{
				IHandler->DoAtEndFrameRT();
			}
		}
	});*/
}

// Called when the game starts or when spawned
void AWhenCalled::BeginPlay()
{
	Super::BeginPlay();
	
	BindDelegates();
}

void AWhenCalled::EndPlay( const EEndPlayReason::Type EndPlayReason )
{
	Super::EndPlay(EndPlayReason);
}

// Called every frame
void AWhenCalled::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}