UE4C++泛型蓝图节点

2023-10-27

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!")));
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UE4C++泛型蓝图节点 的相关文章

随机推荐

  • 金山文档手机app服务器异常,为什么我的手机看不了金山文档 看不了金山文档怎么办...

    1 手机wps上找到 我的office 点击上面的 登录wps 使用有关的账号登录 2 使用的QQ账号登录 登录成功 就可以使用wps的云文档功能了 可以将文档加入文档 只要在电脑上登录就可以同步查看了 3 在菜单当中找到 打开 在 导入到
  • 推荐三款最好用的压缩/解压软件

    写在前面 推荐三款特别好用的压缩 解压软件 Bandizip WinRAR 7 Zip 这三款软件也分别代表了三种常用的压缩格式 zip rar 7z 压缩格式 格式 优点 速度 zip 兼容性好 快 rar 私有格式 中 7z 压缩率高
  • 数据库架构在美团点评的演变实践

    前言 IT时代的缩影基本被CPU 操作系统 数据库这三大核心领域 支撑了半个世纪人类的商业科技文明 本文讲到美团点评数据库的演变 首先从数据库的简史讲起 把数据库划分成三个时代 分别就是关系型数据库时代 NoSQL时代 NewSQL时代 下
  • 【Kaggle】Stable Diffusion 竞赛(2023 年 5 月 11 日版本,准确率 0.59 + )

    一 第一部分讲解 mkdir p kaggle images from PIL import Image from pathlib import Path images list Path kaggle input stable diffu
  • android 轮播图_两步路户外助手谷歌卫星图终极解决方案

    不点蓝字 我们哪来故事 国庆节前 教大家一步步搞回了两步路 户外助手 的 谷歌卫星图 和 路网 错过的朋友可以看之前的文章 快速找回 两步路 户外助手 的谷歌卫星图 路网 但是文章发出后陆续收到一两个驴友反馈 路网是回来了 但是还是没有谷歌
  • linux ssh权限设置,linux 让ssh只允许指定的用户登录的权限设置

    方法一 只允许ssh指定用户登录权限的设置 SSH远程登录的权限直接影响服务器的安全 为ssh设置合理的用户权限是必须的 查看ssh版本的命令 ssh v 设置ssh只允许指定用户登录的方法 在 etc ssh sshd config文件中
  • 【mysql5.7开启 binlog】

    今天发现数据库连接不上了 一看服务器 家被人偷了 库还在只剩下一个表README 以下数据库已被删除 xxx xxx 我们有完整的备份 要恢复它 您必须向我们的比特币地址xxxx支付0 028比特币 BTC 如果您需要证明 请通过以下电子邮
  • grafana设置Alert阈值和邮件报警

    首先我们需要在机器上开启smtp 25服务 这里有一个坑 注意 云主机为了防止滥发邮件已经封掉了smtp的所有通信 所以云主机发邮件是有问题的 安装sendmail ubuntu用apt centos用yum 安装好后一般自动就跑起来了 n
  • 单例模式由浅入深(C# 版)

    单例模式由浅入深 C 版 有时候 我们希望某类只有一个实例 这样的好处是 1 可以实现数据共享 2 避免大量的创建销毁实例的操作 提高性能 为了实现单例模式 通常做法是 1 将构造函数私有化 避免外部直接new对象 2 对外提供一个方法来返
  • docker基础

    docker背景 以linux而言 linux操作系统会有一个主进程pid 1派生出其他进程来控制不同服务例如 pid 2 gt python pid 3 gt java pid4 gt php 三个服务可能会相互影响 使用者期望将这三个不
  • npm wepack-cli --save-dev nodejs -4048 operation not permitted

    其实就是权限不够 方法一在该目录管理员打开终端运行该命令即可 方法二 修改nodejs的权限找到nodejs的目录 之后右键属性 修改完成之后执行npm webpack cli save dev如果还是出现 4048的错误 重启电脑之后即可
  • mavenCentral()、jcenter()、google()仓库

    buildscript里是gradle脚本执行所需依赖 分别是对应的maven库和插件 buildscript repositories google jcenter maven url http maven aliyun com nexu
  • 2020-12-21

    转载一个SpringDataJpa JPA ORM框架的比较文章吧 供自己学习 三者区别 1 JPA是由sun定义的一个ORM规范 提供以下 2 SpringDataJpa是由Spring提供的一套简化JPA开发的框架 Criteria A
  • Hp服务器机箱风扇维修,HP服务器机箱改装(3)

    前几天一直学车 每天都要早上6点半爬起来去学车 所以改装进度有点慢 这两天休息 所以突击了一下 其实进度也不是很快 主要是下刀之前要多想 而且改的时候 要慢工出细活 所以进度不是很大 呵呵 放图 为了前面能装下那个360冷排 所以要把机箱正
  • 部署Swarm - Deploy Swarm

    参考文档 https docs docker com swarm install manual 使用的部署环境 参考文档中是要把Swarm部署到AWS的EC2上的 没有这样的条件 所以选择在本地建立多个虚机机来搭建 操作系统选择centos
  • Linux虚拟机配置yum源

    实验环境 centOS8 查看有没有yum源 ls etc yum repos d 如果有很多 repo文件 从本文第一步开始做 如果没有 则直接创建一个 repo文件 从本文第二步开始做 1 创建一个文件夹 把 etc yum repos
  • 上采样、下采样、过采样、欠采样是什么?

    之前面试时候遇到过这道题 这里整理一下 一般NLPer可能欠采样 过采样问的比较多 上 下采样CVer问的比较多 上采样和下采样在CNN中 可以理解为放大图片和缩小图片 所以池化其实可以理解为是下采样 数据不平衡时 可以使用欠采样和过采样进
  • 目标检测简介

    目录 一 简介 1 目标检测核心问题 2 目标检测任务 二 评估指标 1 IOU交并比 2 分类模型评估指标 1 准确率accuracy 2 召回率recall 3 精确率precision 4 F值 5 ROC和AUC 3 AP值 示例
  • cuda文件操作

    1 读取文件 const char usage Usage dwtHaar1D signal
  • UE4C++泛型蓝图节点

    UE4C 泛型蓝图节点 注 这篇文章是博主边学边写的便于自己学习 很多东西可能解释得不是很详细 此处采用的是UE4 26 要求 掌握基本的c 知识 基本的UE元组符的使用 例如 UFUNCTION等等 全局搜索CustomThunk关键字