UE4C++泛型蓝图节点

UE4C++泛型蓝图节点

注:这篇文章是博主边学边写的便于自己学习,很多东西可能解释得不是很详细。此处采用的是UE4.26

要求:掌握基本的c++知识 + 基本的UE元组符的使用,例如:UFUNCTION等等

全局搜索CustomThunk关键字,我们可发现泛型蓝图节点的实现规律,包含:

  • UFUNCTION的函数声明;
  • 自定义Thunk函数体DECLARE_FUNCTION(execFunctionName);
  • 真正执行泛型逻辑的Generic_FunctionName()泛型函数。

注释:自己在看完文档之后,参考代码可在UKismetArrayLibrary蓝图函数库中找!!!!!!

例如:

UFUNCTION(BlueprintCallable, 
CustomThunk, //在UFUNCTION()内添加CustomThunk关键字,使UHT在生成.generate.h文件时跳过该函数的execMap_Clear函数的生成,而采用自定义的函数体
meta=(DisplayName = "Clear", //显示在蓝图中的名字
CompactNodeTitle = "CLEAR",
MapParam = "TargetMap" ), 
Category = "Utilities|Map")
	static void Map_Clear(const TMap<int32, int32>& TargetMap);
	DECLARE_FUNCTION(execMap_Clear)
	{
    
    
		Stack.MostRecentProperty = nullptr;
		Stack.StepCompiledIn<FMapProperty>(NULL);
		void* MapAddr = Stack.MostRecentPropertyAddress;
		FMapProperty* MapProperty = CastField<FMapProperty>(Stack.MostRecentProperty);
		if (!MapProperty)
		{
    
    
			Stack.bArrayContextFailed = true;
			return;
		}
		
		P_FINISH;
		P_NATIVE_BEGIN;
		GenericMap_Clear(MapAddr, MapProperty);
		P_NATIVE_END
	}
static void GenericMap_Clear(
const void* TargetMap, 
const FMapProperty* MapProperty);
void UBlueprintMapLibrary::GenericMap_Clear(
	const void* TargetMap,
 	const FMapProperty* MapProperty)
{
    
    
	if(TargetMap)
	{
    
    
		FScriptMapHelper MapHelper(MapProperty, TargetMap);
		MapHelper.EmptyValues();
	}
}

这就是一个蓝图数组的Clear函数的实现具体内容,除了有些特殊的宏让我们难以读懂,但当我们多看此系列之后,不难发现其中的规律是固定的。接下来就详细讲解这方面内容。

CustomStructureParam标明一个占位符时,源代码中常用const int32& VariableName表示一个输入类型泛型参数,int32& VariableName表示一个输出类型的泛型参数,而此int32的类型只是代表一个占位符,可以任意变换形式。
stomStructureParam标明多个占位符时,变量以逗号隔开如:CustomStructureParam = “Value1,Value2,Value”。

标识泛型函数通配符(wildcard)参数的说明符主要分为四种,SingleVariable wildcard类型的"CustomStructureParam"、“Array"ArrayParm”、“MapParam”、"SetParam"以及各种辅助说明符,四种说明符存在部分差异。

下面是SingleVariable wildcard类型的说明:
将此代码拷贝到自己创建的BlueprintFunctionLibrary中,运行,在蓝图中则可找到对应函数
在这里插入图片描述

//声明带有一个通配符的函数
//当然将int32替换成其他类型,也可以编译成功,此处为了与源代码保持一致。
UFUNCTION(
	BlueprintCallable, 
	CustomThunk,
	meta = (CustomStructureParam = "Value"),
	Category = "Utilities|Variadic")
	static void TestFunction1(const int32& Value);

DECLARE_FUNCTION(execTestFunction1) {
    
    }

// 标记为“CustomStructureParam”的变量将是一个占位符,
//此处将int32替换成UProperty类型依旧编译成功
UFUNCTION(
	BlueprintCallable, 
	CustomThunk,
	meta = (CustomStructureParam = "Value"), 
	Category = "Utilities|Variadic")
	static void TestFunction2(UProperty* Value);
DECLARE_FUNCTION(execTestFunction2) {
    
    }

// 用多个通配符参数声明一个函数。
UFUNCTION(
	BlueprintCallable,
	CustomThunk,
	meta = (CustomStructureParam = "Value1,Value2,Value"),
	Category = "Utilities|Variadic")
	static void TestFunction3(const int32& Value1, const int32& Value2, int32& Value);

DECLARE_FUNCTION(execTestFunction3) {
    
    }

// 错误的通配符声明方式
UFUNCTION(
	BlueprintCallable,
	CustomThunk, 
	meta = (CustomStructureParam = "Value1|Value2"), //此处错误
	Category = "Utilities|Variadic")
	static void TestFunction4(const int32& Value1, const int32& Value2);

DECLARE_FUNCTION(execTestFunction4) {
    
    }

// 错误的类型声明方式
UFUNCTION(
	BlueprintCallable,
	CustomThunk,
	meta = (CustomStructureParam = "Value"),
	Category = "Utilities|Variadic")
	static void TestFunction5(const TArray<int32>& Value);
DECLARE_FUNCTION(execTestFunction5) {
    
    }

在这里插入图片描述
在这里插入图片描述
Array泛型参数示例

	//标明单个Array数组通配符
	UFUNCTION(
		BlueprintCallable, 
		CustomThunk, 
		meta = (ArrayParm = "Array"),
		Category = "Utilities|Variadic")
		static void TestArray1(const TArray<int32>& Array);
	DECLARE_FUNCTION(execTestArray1) {
    
    }

	// 用一个通配符数组参数和一个类型相关参数声明一个函数。.
	UFUNCTION(
		BlueprintCallable,
		CustomThunk, 
		meta = (ArrayParm = "Array",
		 ArrayTypeDependentParams = "Item"), 
		Category = "Utilities|Variadic")
		static void TestArray2(const TArray<int32>& Array, const int32& Item);
	DECLARE_FUNCTION(execTestArray2) {
    
    }

	//用多个通配符数组参数声明一个函数。
	UFUNCTION(BlueprintCallable,
		CustomThunk, 
		meta = (ArrayParm = "Array1,Array2,Array3",
 ArrayTypeDependentParams = "Array1,Array2,Array3"), 
		Category = "Utilities|Variadic")
		static void TestArray3(
		const TArray<int32>& Array1,
		 const TArray<int32>& Array2, TArray<int32>& Array3);
	DECLARE_FUNCTION(execTestArray3) {
    
    }

	//用多个通配符数组参数声明函数
	UFUNCTION(BlueprintCallable,
		CustomThunk,
		meta = (ArrayParm = "Array1,Array2,Array3", 
		ArrayTypeDependentParams = "Array1,Array3"),
		Category = "Utilities|Variadic")
		static void TestArray4(
			const TArray<int32>& Array1,
			const TArray<int32>& Array2,
			TArray<int32>& Array3);
	DECLARE_FUNCTION(execTestArray4) {
    
    }

	//用多个通配符数组参数声明函数
	UFUNCTION(BlueprintCallable,
		CustomThunk, 
		meta = (ArrayParm = "Array1|Array2|Array3"), //错误的声明方式
		Category = "Utilities|Variadic")
		static void TestArray5(
			const TArray<int32>& Array1,
			const TArray<int32>& Array2,
			TArray<int32>& Array3);
	DECLARE_FUNCTION(execTestArray5) {
    
    }

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

与单个通配符一直,源代码中常用const TArray& ArrayName表示一个输入类型的泛型Array参数,TArray& ArrayName表示一个输出类型的泛型Array参数。
ArrayParm说明符标识多个泛型参数变量时,变量之间需以英文逗号”,”分隔,不得包含其他字符。
被ArrayTypeDependentParams说明符标识的多个泛型Array参数的类型相互依赖,在蓝图图表中被调用时只有确定其中之一,余下泛型Array参数随之变化,如上图描述的TestArray3与TestArray4,同样只链接了一个点,但是因为ArrayTypeDependentParams所声明的不同导致出现俩种不同的结果,ArrayTypeDependentParams将其声明的数组全部关联了,只要有一个有类型,其他相关联的都有类型,甚至用它将数组类型与单个类型都能关联上,如TestArray2。

Map泛型函数示例:
public:
// 输入单个Map类型数组通配符
UFUNCTION(
BlueprintCallable,
CustomThunk,
meta = (MapParam = “TargetMap”),
Category = “Utilities|Variadic”)
static void TestMap1(const TMap<int32, int32>& TargetMap);
DECLARE_FUNCTION(execTestMap1) {}

// 用一个通配符映射参数和类型相关参数声明一个函数。
UFUNCTION(
	BlueprintCallable,
	CustomThunk,
	meta = (MapParam = "TargetMap",
		MapKeyParam = "Key", //MapKeyParam ,声明Map Key值的关联
		MapValueParam = "Value",//MapValueParam ,声明Map Value值的关联
		AutoCreateRefTerm = "Key, Value"), 
	Category = "Utilities|Variadic")
	static void TestMap2(
		const TMap<int32, int32>& TargetMap, 
		const int32& Key,
		const int32& Value);
DECLARE_FUNCTION(execTestMap2) {
    
    }

//用多个通配符映射参数声明一个函数。
UFUNCTION(BlueprintCallable,
	CustomThunk, 
	meta = (MapParam = "TargetMap,SourceMap,ReturnMap"),
	Category = "Utilities|Variadic")
	static void TestMap3(
		const TMap<int32, int32>& TargetMap, 
		const TMap<int32, int32>& SourceMap, 
		TMap<int32, int32>& ReturnMap);
DECLARE_FUNCTION(execTestMap3) {
    
    }

//用多个通配符映射参数声明一个函数。
UFUNCTION(
	BlueprintCallable,
	CustomThunk,
	meta = (MapParam = "TargetMap|SourceMap|ReturnMap"),
	Category = "Utilities|Variadic")
	static void TestMap4(
		const TMap<int32, int32>& TargetMap, 
		const TMap<int32, int32>& SourceMap,
		TMap<int32, int32>& ReturnMap);
DECLARE_FUNCTION(execTestMap4) {
    
    }

在这里插入图片描述
在这里插入图片描述
对比之前的俩个通配符,此Map通配符出现的结果,似乎这结果不是我们预期之内的,它在单个Map统配符时候,出现的结果是正确的,但是采用MapParam = "TargetMap|SourceMap|ReturnMap"与MapParam = "TargetMap,SourceMap,ReturnMap"标明,出现的结果都是错误的,此处要么是引擎不允许这样的使用方式,要么是引擎现存的Bug。

		//单个Set通配符
		UFUNCTION(
			BlueprintCallable, 
			CustomThunk,
			meta = (SetParam = "TargetSet"),
			Category = "Utilities|Variadic")
			static void TestSet1(const TSet<int32>& TargetSet);
		DECLARE_FUNCTION(execTestSet1) {
    
    }

		//单个Set通配符,与单个通配符的错误关联
		UFUNCTION(BlueprintCallable,
			CustomThunk,
			meta = (SetParam = "TargetSet,NewItem"),
			Category = "Utilities|Variadic")
			static void TestSet2(const TSet<int32>& TargetSet, const int32& NewItem);
		DECLARE_FUNCTION(execTestSet2) {
    
    }

		//单个Set通配符,与单个通配符的关联
		UFUNCTION(BlueprintCallable,
			CustomThunk,
			meta = (SetParam = "TargetSet|NewItem"),
			Category = "Utilities|Variadic")
			static void TestSet3(
				const TSet<int32>& TargetSet, 
				const int32& NewItem);
		DECLARE_FUNCTION(execTestSet3) {
    
    }

		//单个Set与Array的关联
		UFUNCTION(
			BlueprintCallable,
			CustomThunk,
			meta = (SetParam = "TargetSet|NewItems"), 
			Category = "Utilities|Variadic")
			static void TestSet4(
				const TSet<int32>& TargetSet, 
				const TArray<int32>& NewItems);
		DECLARE_FUNCTION(execTestSet4) {
    
    }

		//多个Set
		UFUNCTION(
			BlueprintCallable, 
			CustomThunk,
			meta = (SetParam = "Set1|Set2,Set3"),
			Category = "Utilities|Variadic")
			static void TestSet5(
				const TSet<int32>& Set1,
				const TSet<int32>& Set2,
				TSet<int32>& Set3);
		DECLARE_FUNCTION(execTestSet5) {
    
    }

		//多个Set的关联
		UFUNCTION(
			BlueprintCallable, 
			CustomThunk,
			meta = (SetParam = "Set1|Set2|Set3"), 
			Category = "Utilities|Variadic")
			static void TestSet6(
				const TSet<int32>& Set1,
				const TSet<int32>& Set2, 
				TSet<int32>& Set3);
		DECLARE_FUNCTION(execTestSet6) {
    
    }

在这里插入图片描述
在这里插入图片描述
声明泛型Set参数时, SetParam说明符列表的泛型参数之间用”|”分隔符进行关联,其他的对比之前的通配符没有其他具体很大的区分,在此不过多赘述。

  • Thunk函数体的实现

Thunk函数体主要作用:获取蓝图虚拟机VM中的值并传递给C++。

在编译时,UHT会在该类的generated.h文件中为其自动生成一个形如DECLARE_FUNCTION(execFunctionName) {}的函数体,也就是我们所说的Thunk函数体,而我们在家了CustomThunk说明符之后,UHT不再为我们生成对应的反射,由于Thunk函数是Runtime时获取蓝图VM传递过来的参数值,因而Thunk函数的代码是在Runtime时运行的,那我们改如何获取正确的获取蓝图节点中传来的数据呢,当然参照源码与它生成的函数是最正确的方式。

我们在自己的创建的蓝图函数库中添加:

UFUNCTION(BlueprintCallable, Category = "MyProject")
	static void  TestFunction(
		bool BoolVar
		, uint8 ByteVar
		, int32 IntegerVar
		, float FloatVar
		, FName NameVar
		, FString StringVar
		, const FText& TextVar
		, FVector VectorVar
		, FTransform TransformVar
		, UObject* ObjectVar
		, TSubclassOf<UObject> ClassVar
		, bool& RetBoolVar
		, uint8& RetByteVar
		, int32& RetIntegerVar
		, float& RetFloatVar
		, FName& RetNameVar
		, FString& RetStringVar
		, FText& RetTextVar
		, FVector& RetVectorVar
		, FTransform& RetTransformVar
		, UObject*& RetObjectVar
		, TSubclassOf<UObject>& RetClassVar
	){
    
    };

在这里插入图片描述
打开.generated.h文件,然后打开所在文件夹
在这里插入图片描述
找到与.generated.h同名的.gen.cpp文件
在这里插入图片描述
双击打开之后就找到了对应生成的Thunk函数体在这里插入图片描述

DEFINE_FUNCTION(UGenericNodeLibrary::execTestFunction)
	{
    
    
		P_GET_UBOOL(Z_Param_BoolVar);
		P_GET_PROPERTY(FByteProperty,Z_Param_ByteVar);
		P_GET_PROPERTY(FIntProperty,Z_Param_IntegerVar);
		P_GET_PROPERTY(FFloatProperty,Z_Param_FloatVar);
		P_GET_PROPERTY(FNameProperty,Z_Param_NameVar);
		P_GET_PROPERTY(FStrProperty,Z_Param_StringVar);
		P_GET_PROPERTY_REF(FTextProperty,Z_Param_Out_TextVar);
		P_GET_STRUCT(FVector,Z_Param_VectorVar);
		P_GET_STRUCT(FTransform,Z_Param_TransformVar);
		P_GET_OBJECT(UObject,Z_Param_ObjectVar);
		P_GET_OBJECT(UClass,Z_Param_ClassVar);
		P_GET_UBOOL_REF(Z_Param_Out_RetBoolVar);
		P_GET_PROPERTY_REF(FByteProperty,Z_Param_Out_RetByteVar);
		P_GET_PROPERTY_REF(FIntProperty,Z_Param_Out_RetIntegerVar);
		P_GET_PROPERTY_REF(FFloatProperty,Z_Param_Out_RetFloatVar);
		P_GET_PROPERTY_REF(FNameProperty,Z_Param_Out_RetNameVar);
		P_GET_PROPERTY_REF(FStrProperty,Z_Param_Out_RetStringVar);
		P_GET_PROPERTY_REF(FTextProperty,Z_Param_Out_RetTextVar);
		P_GET_STRUCT_REF(FVector,Z_Param_Out_RetVectorVar);
		P_GET_STRUCT_REF(FTransform,Z_Param_Out_RetTransformVar);
		P_GET_OBJECT_REF(UObject,Z_Param_Out_RetObjectVar);
		P_GET_OBJECT_REF_NO_PTR(TSubclassOf<UObject> ,Z_Param_Out_RetClassVar);
		P_FINISH;
		P_NATIVE_BEGIN;
		UGenericNodeLibrary::TestFunction(Z_Param_BoolVar,Z_Param_ByteVar,Z_Param_IntegerVar,Z_Param_FloatVar,Z_Param_NameVar,Z_Param_StringVar,Z_Param_Out_TextVar,Z_Param_VectorVar,Z_Param_TransformVar,Z_Param_ObjectVar,Z_Param_ClassVar,Z_Param_Out_RetBoolVar,Z_Param_Out_RetByteVar,Z_Param_Out_RetIntegerVar,Z_Param_Out_RetFloatVar,Z_Param_Out_RetNameVar,Z_Param_Out_RetStringVar,Z_Param_Out_RetTextVar,Z_Param_Out_RetVectorVar,Z_Param_Out_RetTransformVar,Z_Param_Out_RetObjectVar,Z_Param_Out_RetClassVar);
		P_NATIVE_END;
	}

P_FINISH代表参数获取完成,因此前方为获取参数,P_NATIVE_BEGIN为激活函数开始,P_NATIVE_BEGIN为激活函数结束。
获取泛型Single Variable

Stack.StepCompiledIn<UStructProperty>(NULL);
void* SrcPropertyAddr = Stack.MostRecentPropertyAddress;
UProperty* SrcProperty = Cast<UProperty>(Stack.MostRecentProperty);

获取泛型Array Variable

  Stack.StepCompiledIn<UArrayProperty>(NULL);
  void* SrcArrayAddr = Stack.MostRecentPropertyAddress;
  UArrayProperty* SrcArrayProperty = Cast<UArrayProperty>(Stack.MostRecentProperty);

获取泛型Map Variable

  Stack.MostRecentProperty = nullptr;
  Stack.StepCompiledIn<UMapProperty>(NULL);
  void* SrcMapAddr = Stack.MostRecentPropertyAddress;
  UMapProperty* SrcMapProperty = Cast<UMapProperty>(Stack.MostRecentProperty);

获取泛型Set Variable

  Stack.MostRecentProperty = nullptr;
  Stack.StepCompiledIn<USetProperty>(NULL);
  void* SetAddr = Stack.MostRecentPropertyAddress;
  USetProperty* SetProperty = Cast<USetProperty>(Stack.MostRecentProperty);

被标记为泛型的参数,需要手动获取参数的类型和地址。
如果需要让某个跟随着其他引脚一起改变数据类型的引脚在类型改变之后,在节点上可以填入初始值而不需要再接入其他引脚的话,则在meta中添加AutoCreateRefTerm标识参数,不同参数之间用","隔开。
执行StepCompiledIn让MostRecentPropertyAddress指向下一个参数的地址。
Stack.MostRecentPropertyAddress和Stack.MostRecentProperty这两个变量,就是当前参数值的内存地址和反射信息。
“thunk”函数是一个包装,它完成的核心任务就是处理蓝图虚拟机的Stack,然后调用我们使用C++实现的函数。

综合以上得
要自定义一个泛型函数,需要UFUNCTION添加CustomThunk,并声明泛型变量,DECLARE_FUNCTION中获取对应泛型数据,并调用自身真正的函数。

	UFUNCTION(BlueprintCallable,
		CustomThunk,
		 Category = "Utilities|Variables",
		meta = (CustomStructureParam = "Value",
			AutoCreateRefTerm = "Value", 
			DisplayName = "GET/SET (Property)", 
			CompactNodeTitle = "GET/SET"))
		static void AccessPropertyByName(
			UObject * Object,
			FName PropertyName, 
			const int32 & Value,
			bool bSetter = true);

	DECLARE_FUNCTION(execAccessPropertyByName)
	{
    
    
		P_GET_OBJECT(UObject, OwnerObject);
		P_GET_PROPERTY(UNameProperty, PropertyName);

		Stack.StepCompiledIn<UStructProperty>(NULL);
		void* SrcPropertyAddr = Stack.MostRecentPropertyAddress;
		UProperty* SrcProperty = Cast<UProperty>(Stack.MostRecentProperty);

		P_GET_UBOOL(bSetter);
		P_FINISH;

		P_NATIVE_BEGIN;
		Generic_AccessPropertyByName(
			OwnerObject, 
			PropertyName,
			SrcPropertyAddr,
			SrcProperty,
			bSetter);
		P_NATIVE_END;
	}

	static void Generic_AccessPropertyByName(
		UObject* OwnerObject,
		FName PropertyName, 
		void* SrcPropertyAddr, 
		UProperty* SrcProperty, 
		bool bSetter = true)
		{
    
    
			if (OwnerObject != NULL)
			{
    
    
				UProperty* FoundProp = FindField<UProperty>(OwnerObject->GetClass(), PropertyName);
		
				if ((FoundProp != NULL) && (FoundProp->SameType(SrcProperty)))
				{
    
    
					void* Dest = FoundProp->ContainerPtrToValuePtr<void>(OwnerObject);
					if (bSetter == true)
					{
    
    
						FoundProp->CopySingleValue(Dest, SrcPropertyAddr);
					}
					else
					{
    
    
						FoundProp->CopySingleValue(SrcPropertyAddr, Dest);
					}
					return;
				}
			}
			UE_LOG(LogTemp, Warning, TEXT("UGenericNodeLibrary::Generic_AccessPropertyByName: Failed to find %s variable from %s object"), *(FString("Generic_AccessPropertyByName!")));
		};

在这里插入图片描述

  • 源码
  • .h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Kismet/KismetSystemLibrary.h"
#include "GenericNodeLibrary.generated.h"

/**
 *
 */
UCLASS()
class GAME_SANDBOX_API UGenericNodeLibrary : public UBlueprintFunctionLibrary
{
    
    
	GENERATED_BODY()

	//CustomStructureParam = "Variable"标识变量Variable为wildcard类型参数,
	//“const int32& Variable” 并非表示Variable变量类型为const int32,
	//该参数在此处相当于一个占位符,const + & 指示该参数为输入参数;
	//当然将int32替换成其他类型,也可以编译成功,此处为了与源代码保持一致。
	//其中CustomThunk的作用是指示UHT不需要为蓝图函数生成exec方法,使用自定义的execFunction,如上所示的
	//UnrealHeaderTool(虚幻头文件工具)的代码生成器将不会为此函数生成execFoo转换程序; 可由用户来提供。
	UFUNCTION(BlueprintCallable,
		CustomThunk, 
		meta = (CustomStructureParam = "Variable", AutoCreateRefTerm = "Variable"), Category = "GenericNodeLibrary")
		void FunctionName(const int32 & Variable);
	DECLARE_FUNCTION(execFunctionName)
	{
    
    
	}

	UFUNCTION(BlueprintCallable,
		CustomThunk, Category = "Utilities|Variables",
		meta = (CustomStructureParam = "Value",
			AutoCreateRefTerm = "Value", 
			DisplayName = "GET/SET (Property)", 
			CompactNodeTitle = "GET/SET"))
		static void AccessPropertyByName(
			UObject * Object,
			FName PropertyName, 
			const int32 & Value,
			bool bSetter = true);

	DECLARE_FUNCTION(execAccessPropertyByName)
	{
    
    
		P_GET_OBJECT(UObject, OwnerObject);
		P_GET_PROPERTY(UNameProperty, PropertyName);

		Stack.StepCompiledIn<UStructProperty>(NULL);
		void* SrcPropertyAddr = Stack.MostRecentPropertyAddress;
		/// Reference: Plugins\Experimental\StructBox\Source\StructBox\Classes\StructBoxLibrary.h -> execSetStructInBox
		UProperty* SrcProperty = Cast<UProperty>(Stack.MostRecentProperty);

		P_GET_UBOOL(bSetter);
		P_FINISH;

		P_NATIVE_BEGIN;
		Generic_AccessPropertyByName(
			OwnerObject, 
			PropertyName,
			SrcPropertyAddr,
			SrcProperty,
			bSetter);
		P_NATIVE_END;
	}

	static void Generic_AccessPropertyByName(
		UObject* OwnerObject,
		FName PropertyName, 
		void* SrcPropertyAddr, 
		UProperty* SrcProperty, 
		bool bSetter = true);

	//声明带有一个通配符的函数
	//当然将int32替换成其他类型,也可以编译成功,此处为了与源代码保持一致。
	UFUNCTION(
		BlueprintCallable, 
		CustomThunk,
		meta = (CustomStructureParam = "Value"),
		Category = "Utilities|Variadic")
		static void TestFunction1(const int32& Value);

	DECLARE_FUNCTION(execTestFunction1) {
    
    }

	// 标记为“CustomStructureParam”的变量将是一个占位符,
	//此处将int32替换成UProperty类型依旧编译成功
	UFUNCTION(
		BlueprintCallable, 
		CustomThunk,
		meta = (CustomStructureParam = "Value"), 
		Category = "Utilities|Variadic")
		static void TestFunction2(UProperty* Value);
	DECLARE_FUNCTION(execTestFunction2) {
    
    }

	// 用多个通配符参数声明一个函数。
	UFUNCTION(
		BlueprintCallable,
		CustomThunk,
		meta = (CustomStructureParam = "Value1,Value2,Value"),
		Category = "Utilities|Variadic")
		static void TestFunction3(const int32& Value1, const int32& Value2, int32& Value);
	
	DECLARE_FUNCTION(execTestFunction3) {
    
    }

	// 错误的通配符声明方式
	UFUNCTION(
		BlueprintCallable,
		CustomThunk, 
		meta = (CustomStructureParam = "Value1|Value2"), //此处错误
		Category = "Utilities|Variadic")
		static void TestFunction4(const int32& Value1, const int32& Value2);

	DECLARE_FUNCTION(execTestFunction4) {
    
    }

	// 错误的类型声明方式
	UFUNCTION(
		BlueprintCallable,
		CustomThunk,
		meta = (CustomStructureParam = "Value"),
		Category = "Utilities|Variadic")
		static void TestFunction5(const TArray<int32>& Value);
	DECLARE_FUNCTION(execTestFunction5) {
    
    }

public: // Wildcard TArray

	//标明单个Array数组通配符
	UFUNCTION(
		BlueprintCallable, 
		CustomThunk, 
		meta = (ArrayParm = "Array"),
		Category = "Utilities|Variadic")
		static void TestArray1(const TArray<int32>& Array);
	DECLARE_FUNCTION(execTestArray1) {
    
    }

	// 用一个通配符数组参数和一个类型相关参数声明一个函数。.
	UFUNCTION(
		BlueprintCallable,
		CustomThunk, 
		meta = (ArrayParm = "Array", ArrayTypeDependentParams = "Item"), 
		Category = "Utilities|Variadic")
		static void TestArray2(const TArray<int32>& Array, const int32& Item);
	DECLARE_FUNCTION(execTestArray2) {
    
    }

	//用多个通配符数组参数声明一个函数。
	UFUNCTION(BlueprintCallable,
		CustomThunk, 
		meta = (ArrayParm = "Array1,Array2,Array3",
 ArrayTypeDependentParams = "Array1,Array2,Array3"), 
		Category = "Utilities|Variadic")
		static void TestArray3(const TArray<int32>& Array1, const TArray<int32>& Array2, TArray<int32>& Array3);
	DECLARE_FUNCTION(execTestArray3) {
    
    }

	//用多个通配符数组参数声明函数
	UFUNCTION(BlueprintCallable,
		CustomThunk,
		meta = (ArrayParm = "Array1,Array2,Array3", ArrayTypeDependentParams = "Array1,Array3"),
		Category = "Utilities|Variadic")
		static void TestArray4(
			const TArray<int32>& Array1,
			const TArray<int32>& Array2,
			TArray<int32>& Array3);
	DECLARE_FUNCTION(execTestArray4) {
    
    }

	//用多个通配符数组参数声明函数
	UFUNCTION(BlueprintCallable,
		CustomThunk, 
		meta = (ArrayParm = "Array1|Array2|Array3"), //错误的声明方式
		Category = "Utilities|Variadic")
		static void TestArray5(
			const TArray<int32>& Array1,
			const TArray<int32>& Array2,
			TArray<int32>& Array3);
	DECLARE_FUNCTION(execTestArray5) {
    
    }

public:
	// 输入单个Map类型数组通配符
	UFUNCTION(
		BlueprintCallable, 
		CustomThunk, 
		meta = (MapParam = "TargetMap"),
		Category = "Utilities|Variadic")
		static void TestMap1(const TMap<int32, int32>& TargetMap);
	DECLARE_FUNCTION(execTestMap1) {
    
    }

	// 用一个通配符映射参数和类型相关参数声明一个函数。
	UFUNCTION(
		BlueprintCallable,
		CustomThunk,
		meta = (MapParam = "TargetMap",
			MapKeyParam = "Key", 
			MapValueParam = "Value",
			AutoCreateRefTerm = "Key, Value"), 
		Category = "Utilities|Variadic")
		static void TestMap2(
			const TMap<int32, int32>& TargetMap, 
			const int32& Key,
			const int32& Value);
	DECLARE_FUNCTION(execTestMap2) {
    
    }

	//用多个通配符映射参数声明一个函数。
	UFUNCTION(BlueprintCallable,
		CustomThunk, 
		meta = (MapParam = "TargetMap,SourceMap,ReturnMap"),
		Category = "Utilities|Variadic")
		static void TestMap3(
			const TMap<int32, int32>& TargetMap, 
			const TMap<int32, int32>& SourceMap, 
			TMap<int32, int32>& ReturnMap);
	DECLARE_FUNCTION(execTestMap3) {
    
    }

	//用多个通配符映射参数声明一个函数。
	UFUNCTION(
		BlueprintCallable,
		CustomThunk,
		meta = (MapParam = "TargetMap|SourceMap|ReturnMap"),
		Category = "Utilities|Variadic")
		static void TestMap4(
			const TMap<int32, int32>& TargetMap, 
			const TMap<int32, int32>& SourceMap,
			TMap<int32, int32>& ReturnMap);
	DECLARE_FUNCTION(execTestMap4) {
    
    }

public:// wildcard Set

		//单个Set通配符
		UFUNCTION(
			BlueprintCallable, 
			CustomThunk,
			meta = (SetParam = "TargetSet"),
			Category = "Utilities|Variadic")
			static void TestSet1(const TSet<int32>& TargetSet);
		DECLARE_FUNCTION(execTestSet1) {
    
    }

		//单个Set通配符,与单个通配符的错误关联
		UFUNCTION(BlueprintCallable,
			CustomThunk,
			meta = (SetParam = "TargetSet,NewItem"),
			Category = "Utilities|Variadic")
			static void TestSet2(const TSet<int32>& TargetSet, const int32& NewItem);
		DECLARE_FUNCTION(execTestSet2) {
    
    }

		//单个Set通配符,与单个通配符的关联
		UFUNCTION(BlueprintCallable,
			CustomThunk,
			meta = (SetParam = "TargetSet|NewItem"),
			Category = "Utilities|Variadic")
			static void TestSet3(
				const TSet<int32>& TargetSet, 
				const int32& NewItem);
		DECLARE_FUNCTION(execTestSet3) {
    
    }

		//单个Set与Array的关联
		UFUNCTION(
			BlueprintCallable,
			CustomThunk,
			meta = (SetParam = "TargetSet|NewItems"), 
			Category = "Utilities|Variadic")
			static void TestSet4(
				const TSet<int32>& TargetSet, 
				const TArray<int32>& NewItems);
		DECLARE_FUNCTION(execTestSet4) {
    
    }

		//多个Set
		UFUNCTION(
			BlueprintCallable, 
			CustomThunk,
			meta = (SetParam = "Set1|Set2,Set3"),
			Category = "Utilities|Variadic")
			static void TestSet5(
				const TSet<int32>& Set1,
				const TSet<int32>& Set2,
				TSet<int32>& Set3);
		DECLARE_FUNCTION(execTestSet5) {
    
    }

		//多个Set的关联
		UFUNCTION(
			BlueprintCallable, 
			CustomThunk,
			meta = (SetParam = "Set1|Set2|Set3"), 
			Category = "Utilities|Variadic")
			static void TestSet6(
				const TSet<int32>& Set1,
				const TSet<int32>& Set2, 
				TSet<int32>& Set3);
		DECLARE_FUNCTION(execTestSet6) {
    
    }
public:
	UFUNCTION(BlueprintCallable, Category = "MyProject")
		static void  TestFunction(
			bool BoolVar
			, uint8 ByteVar
			, int32 IntegerVar
			, float FloatVar
			, FName NameVar
			, FString StringVar
			, const FText& TextVar
			, FVector VectorVar
			, FTransform TransformVar
			, UObject* ObjectVar
			, TSubclassOf<UObject> ClassVar
			, bool& RetBoolVar
			, uint8& RetByteVar
			, int32& RetIntegerVar
			, float& RetFloatVar
			, FName& RetNameVar
			, FString& RetStringVar
			, FText& RetTextVar
			, FVector& RetVectorVar
			, FTransform& RetTransformVar
			, UObject*& RetObjectVar
			, TSubclassOf<UObject>& RetClassVar
		){
    
    };
};

.cpp

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


#include "GenericNodeLibrary.h"
#include "Engine.h"
void UGenericNodeLibrary::Generic_AccessPropertyByName(UObject* OwnerObject, FName PropertyName, void* SrcPropertyAddr, UProperty* SrcProperty, bool bSetter /*= true*/)
{
    
    
	if (OwnerObject != NULL)
	{
    
    
		UProperty* FoundProp = FindField<UProperty>(OwnerObject->GetClass(), PropertyName);

		if ((FoundProp != NULL) && (FoundProp->SameType(SrcProperty)))
		{
    
    
			void* Dest = FoundProp->ContainerPtrToValuePtr<void>(OwnerObject);
			if (bSetter == true)
			{
    
    
				FoundProp->CopySingleValue(Dest, SrcPropertyAddr);
			}
			else
			{
    
    
				FoundProp->CopySingleValue(SrcPropertyAddr, Dest);
			}
			return;
		}
	}
	UE_LOG(LogTemp, Warning, TEXT("UGenericNodeLibrary::Generic_AccessPropertyByName: Failed to find %s variable from %s object"), *(FString("Generic_AccessPropertyByName!")));
}

猜你喜欢

转载自blog.csdn.net/weixin_56946623/article/details/123982505
今日推荐