4.5 KiB
Raw Blame History

Variadic

  • 功能描述: 标识一个函数可以接受任意类型的多个参数包括input/output)

  • 元数据类型: bool

  • 引擎模块: Blueprint, UHT

  • 作用机制: 在Meta中加入Variadic

  • 常用程度: ★★★

标识一个函数可以接受任意类型的多个参数包括input/output)

在源码中搜索应用然后配合UK2Node_ExecutePythonScript

UFUNCTION(BlueprintCallable, CustomThunk, Category = "Python|Execution", meta=(Variadic, BlueprintInternalUseOnly="true"))
    static bool ExecutePythonScript(UPARAM(meta=(MultiLine=True)) const FString& PythonScript, const TArray<FString>& PythonInputs, const TArray<FString>& PythonOutputs);
	DECLARE_FUNCTION(execExecutePythonScript);

蓝图的效果:

Untitled

示例代码:

UCLASS(Blueprintable, BlueprintType)
class INSIDER_API UMyFunction_Variadic : public UBlueprintFunctionLibrary
{
public:
	GENERATED_BODY()
public:
	/*
			[PrintVariadicFields	Function->Struct->Field->Object	/Script/Insider.MyFunction_Variadic:PrintVariadicFields]
			(BlueprintInternalUseOnly = true, BlueprintType = true, CustomThunk = true, ModuleRelativePath = Function/Variadic/MyFunction_Variadic.h, Variadic = )
	*/
	UFUNCTION(BlueprintCallable, CustomThunk, BlueprintInternalUseOnly, meta = (Variadic))
	static FString PrintVariadicFields(const TArray<FString>& Inputs, const TArray<FString>& Outputs);
	DECLARE_FUNCTION(execPrintVariadicFields);
};

FString UMyFunction_Variadic::PrintVariadicFields(const TArray<FString>& Inputs, const TArray<FString>& Outputs)
{
	check(0);
	return TEXT("");
}

DEFINE_FUNCTION(UMyFunction_Variadic::execPrintVariadicFields)
{
	FString str;

	P_GET_TARRAY_REF(FString, Inputs);
	P_GET_TARRAY_REF(FString, Outputs);

	for (const FString& PythonInput : Inputs)
	{
		Stack.MostRecentPropertyAddress = nullptr;
		Stack.MostRecentProperty = nullptr;
		Stack.StepCompiledIn<FProperty>(nullptr);
		check(Stack.MostRecentProperty && Stack.MostRecentPropertyAddress);

		FProperty* p = CastField<FProperty>(Stack.MostRecentProperty);

		FString propertyValueString;
		const void* propertyValuePtr = p->ContainerPtrToValuePtr<const void*>(Stack.MostRecentPropertyContainer);

		p->ExportTextItem_Direct(propertyValueString, propertyValuePtr, nullptr, nullptr, PPF_None);

		str += FString::Printf(TEXT("%s:%s\n"), *p->GetFName().ToString(), *propertyValueString);

	}
	P_FINISH;

	*(FString*)RESULT_PARAM = str;
}

示例效果:

Untitled

打印:

CallFunc_MakeVector_ReturnValue:(X=1.000000,Y=2.000000,Z=3.000000) CallFunc_MakeLiteralDouble_ReturnValue:456.000000

原理:

普通的CustomThunk函数还有一些限制参数名字和个数是在UFuntion里写死的不能支持动态的个数。

目前,想使用Variadic功能需要自定义蓝图节点用C++来为K2Node_CallFunction添加引脚。

想必是想要开发来同时实现K2Node以及对应的CustomThunk+Variadic方法,来保证使用上的安全性。

BlueprintInternalUseOnly也要加上否则会自动生成普通的蓝图函数达不到variadic的效果。

以下是不加BlueprintInternalUseOnly自动生成的版本:

Untitled

实际应该是:然后再手动添加参数。

Untitled

ildcard的区别是ildcard的参数是任意类型的但个数是固定好的

Untitled

官方添加的和Python交互的功能 Added a Blueprint node for calling Python with args

官方的提交:

https://github.com/EpicGames/UnrealEngine/commit/61d0f65e1cded45ed94f0422eb931f446888e972

注释:

Implemented variadic function support for Blueprints

`Variadic functions are required to be a CustomThunk marked with the "Variadic" meta-data. They can then be used from a custom Blueprint node to accept arbitrary arguments at the end of their parameter list (any extra pins added to the node that aren't part of the main function definition will become the variadic payload).

Variadic arguments aren't type checked, so you need other function input to tell you how many to expect, and for a nativizied function, also what type of arguments you're dealing with.

#jira UE-84932 #rb Dan.OConnor

[CL 10421401 by Jamie Dale in Dev-Editor branch]`