vault backup: 2024-10-12 17:19:45

This commit is contained in:
2024-10-12 17:19:46 +08:00
parent ff94ddca61
commit 244c0c52f6
960 changed files with 31348 additions and 10 deletions

View File

@@ -0,0 +1,46 @@
# ArrayParm
- **功能描述:** 指定一个函数为使用Array<*>的函数,数组元素类型为通配符的泛型。
- **使用位置:** UFUNCTION
- **引擎模块:** Blueprint
- **元数据类型:** strings="abc"
- **关联项:** [ArrayTypeDependentParams](../ArrayTypeDependentParams/ArrayTypeDependentParams.md)
- **常用程度:** ★★★
指定一个函数为使用Array<*>的函数,数组元素类型为通配符的泛型。
在内部逻辑上的处理区别是有ArrayParm的会采用UK2Node_CallArrayFunction来生成节点而不是UK2Node_CallFunction。
ArrayParam可以指定多个用逗号分隔开。
在源码里只在UKismetArrayLibrary里使用但如果自己也想顶一个数组的操作则也可以加上ArrayParam。
因为数组元素类型为通配符的泛型因此在C++中实现的时候要配合CustomThunk来自己写一些蓝图逻辑胶水代码才好正确处理不同的数组类型。这部分可以参照源码里UKismetArrayLibrary的样例模仿。
## 测试代码:
```cpp
UCLASS(Blueprintable, BlueprintType)
class INSIDER_API UMyFunction_Param :public UBlueprintFunctionLibrary
{
public:
GENERATED_BODY()
public:
//Array
UFUNCTION(BlueprintPure, CustomThunk, meta = (ArrayParm = "TargetArray"))
static int32 MyArray_Count(const TArray<int32>& TargetArray);
static int32 GenericMyArray_Count(const void* TargetArray, const FArrayProperty* ArrayProp);
DECLARE_FUNCTION(execMyArray_Count);
UFUNCTION(BlueprintPure, CustomThunk, meta = (ArrayParm = "ArrayA,ArrayB", ArrayTypeDependentParams = "ArrayB"))
static int32 MyArray_CompareSize(const TArray<int32>& ArrayA, const TArray<int32>& ArrayB);
static int32 GenericMyArray_CompareSize(void* ArrayA, const FArrayProperty* ArrayAProp, void* ArrayB, const FArrayProperty* ArrayBProp);
DECLARE_FUNCTION(execMyArray_CompareSize);
};
```
## 蓝图效果:
![Untitled](Untitled.png)
可以看到在没有连接具体数组类型的时候Array是灰色的通配符类型。而连接上不同的数组类型Array参数引脚就会自动变成相应的类型这些逻辑是在UK2Node_CallArrayFunction中实现的有兴趣的去自行翻阅。

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@@ -0,0 +1,69 @@
# ArrayTypeDependentParams
- **功能描述:** 当ArryParam指定的函数拥有两个或以上Array参数的时候指定哪些数组参数的类型也应该相应的被更新改变。
- **使用位置:** UFUNCTION
- **元数据类型:** string="abc"
- **关联项:** [ArrayParm](../ArrayParm/ArrayParm.md)
当ArryParam指定的函数拥有两个或以上Array参数的时候指定哪些数组参数的类型也应该相应的被更新改变。
指明一个参数的类型用于确定ArrayParam的值类型
```cpp
UCLASS(Blueprintable, BlueprintType)
class INSIDER_API UMyFunction_Param :public UBlueprintFunctionLibrary
{
public:
GENERATED_BODY()
public:
//Array
UFUNCTION(BlueprintPure, CustomThunk, meta = (ArrayParm = "ArrayA,ArrayB", ArrayTypeDependentParams = "ArrayB"))
static int32 MyArray_CompareSize(const TArray<int32>& ArrayA, const TArray<int32>& ArrayB);
static int32 GenericMyArray_CompareSize(void* ArrayA, const FArrayProperty* ArrayAProp, void* ArrayB, const FArrayProperty* ArrayBProp);
DECLARE_FUNCTION(execMyArray_CompareSize);
};
```
如果没有ArrayTypeDependentParams在连接ArrayA后ArrayB的类型依然没有确定即使连接上了也是如此这应该是引擎的实现所限制。编译会造成编译错误。
![Untitled](Untitled.png)
因此ArrayTypeDependentParams可以指定另外的数组参数其类型会由别的第一个数组实际参数所决定即typeof(ArrayB)=typeof(ArrayA)。在示例代码里所示加上ArrayB作为ArrayTypeDependentParams 之后MyArrayB无论是先连接到ArrayA还是ArrayB都可以触发二者改变为一致的数组类型。这是因为ArrayA作为第一个参数天生在引擎内已经实现了第一个参数的动态类型实时变化。因此我们只要再加上ArrayB就好了。
## 原理:
引擎内已经实现了第一个参数的动态类型实时变化:
```cpp
void UK2Node_CallArrayFunction::AllocateDefaultPins()
{
Super::AllocateDefaultPins();
UEdGraphPin* TargetArrayPin = GetTargetArrayPin();
if (ensureMsgf(TargetArrayPin, TEXT("%s"), *GetFullName()))
{
TargetArrayPin->PinType.ContainerType = EPinContainerType::Array;
TargetArrayPin->PinType.bIsReference = true;
TargetArrayPin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard;
TargetArrayPin->PinType.PinSubCategory = NAME_None;
TargetArrayPin->PinType.PinSubCategoryObject = nullptr;
}
TArray< FArrayPropertyPinCombo > ArrayPins;
GetArrayPins(ArrayPins);
for(auto Iter = ArrayPins.CreateConstIterator(); Iter; ++Iter)
{
if(Iter->ArrayPropPin)
{
Iter->ArrayPropPin->bHidden = true;
Iter->ArrayPropPin->bNotConnectable = true;
Iter->ArrayPropPin->bDefaultValueIsReadOnly = true;
}
}
PropagateArrayTypeInfo(TargetArrayPin);
}
```
关于ArrayDependentParam的作用机制可以参照UK2Node_CallArrayFunction里的NotifyPinConnectionListChanged和PropagateArrayTypeInfo这两个函数的实现可以看到其他的数组参数Pin类型被动态的修改为SourcePin的类型。

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -0,0 +1,134 @@
# AutoCreateRefTerm
- **功能描述:** 指定函数的多个输入引用参数在没有连接的时候自动为其创建默认值
- **使用位置:** UFUNCTION
- **引擎模块:** Blueprint
- **元数据类型:** strings="abc"
- **常用程度:** ★★★★★
指定函数的多个输入引用参数在没有连接的时候自动为其创建默认值。
要注意“输入”+“引用”,这两个前提项。
当有些情况你想把函数的参数采用引用来传递,但是又不想每次都得必须连接一个变量,想在不连接的时候提供一个内联编辑的默认值,因此蓝图系统就提供了这么一个便利功能。
## 测试代码:
```cpp
UFUNCTION(BlueprintCallable, meta = (AutoCreateRefTerm = "Location,Value"))
static bool MyFunc_HasAutoCreateRefTerm(const FVector& Location, const int32& Value) { return false; }
UFUNCTION(BlueprintCallable)
static bool MyFunc_NoAutoCreateRefTerm(const FVector& Location, const int32& Value) { return false; }
UFUNCTION(BlueprintCallable)
static bool MyFunc_NoRef(FVector Location, int32 Value) { return false; }
```
## 蓝图效果:
可以见到MyFunc_NoAutoCreateRefTerm的函数会产生编译的报错因为是引用参数但是却没有连接导致引用缺少实参。
![Untitled](Untitled.png)
## 原理代码:
```cpp
void UEdGraphSchema_K2::GetAutoEmitTermParameters(const UFunction* Function, TArray<FString>& AutoEmitParameterNames)
{
AutoEmitParameterNames.Reset();
const FString& MetaData = Function->GetMetaData(FBlueprintMetadata::MD_AutoCreateRefTerm);
if (!MetaData.IsEmpty())
{
MetaData.ParseIntoArray(AutoEmitParameterNames, TEXT(","), true);
for (int32 NameIndex = 0; NameIndex < AutoEmitParameterNames.Num();)
{
FString& ParameterName = AutoEmitParameterNames[NameIndex];
ParameterName.TrimStartAndEndInline();
if (ParameterName.IsEmpty())
{
AutoEmitParameterNames.RemoveAtSwap(NameIndex);
}
else
{
++NameIndex;
}
}
}
// Allow any params that are blueprint defined to be autocreated:
if (!FBlueprintEditorUtils::IsNativeSignature(Function))
{
for ( TFieldIterator<FProperty> ParamIter(Function, EFieldIterationFlags::Default);
ParamIter && (ParamIter->PropertyFlags & CPF_Parm);
++ParamIter)
{
FProperty* Param = *ParamIter;
if(Param->HasAnyPropertyFlags(CPF_ReferenceParm))
{
AutoEmitParameterNames.Add(Param->GetName());
}
}
}
}
还有在
void UK2Node_CallFunction::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
if ( Function )
{
TArray<FString> AutoCreateRefTermPinNames;
CompilerContext.GetSchema()->GetAutoEmitTermParameters(Function, AutoCreateRefTermPinNames);
const bool bHasAutoCreateRefTerms = AutoCreateRefTermPinNames.Num() != 0;
for (UEdGraphPin* Pin : Pins)
{
const bool bIsRefInputParam = Pin && Pin->PinType.bIsReference && (Pin->Direction == EGPD_Input) && !CompilerContext.GetSchema()->IsMetaPin(*Pin);
if (!bIsRefInputParam)
{
continue;
}
const bool bHasConnections = Pin->LinkedTo.Num() > 0;
const bool bCreateDefaultValRefTerm = bHasAutoCreateRefTerms &&
!bHasConnections && AutoCreateRefTermPinNames.Contains(Pin->PinName.ToString());
if (bCreateDefaultValRefTerm)
{
const bool bHasDefaultValue = !Pin->DefaultValue.IsEmpty() || Pin->DefaultObject || !Pin->DefaultTextValue.IsEmpty();
// copy defaults as default values can be reset when the pin is connected
const FString DefaultValue = Pin->DefaultValue;
UObject* DefaultObject = Pin->DefaultObject;
const FText DefaultTextValue = Pin->DefaultTextValue;
bool bMatchesDefaults = Pin->DoesDefaultValueMatchAutogenerated();
UEdGraphPin* ValuePin = InnerHandleAutoCreateRef(this, Pin, CompilerContext, SourceGraph, bHasDefaultValue);
if ( ValuePin )
{
if (bMatchesDefaults)
{
// Use the latest code to set default value
Schema->SetPinAutogeneratedDefaultValueBasedOnType(ValuePin);
}
else
{
ValuePin->DefaultValue = DefaultValue;
ValuePin->DefaultObject = DefaultObject;
ValuePin->DefaultTextValue = DefaultTextValue;
}
}
}
// since EX_Self does not produce an addressable (referenceable) FProperty, we need to shim
// in a "auto-ref" term in its place (this emulates how UHT generates a local value for
// native functions; hence the IsNative() check)
else if (bHasConnections && Pin->LinkedTo[0]->PinType.PinSubCategory == UEdGraphSchema_K2::PSC_Self && Pin->PinType.bIsConst && !Function->IsNative())
{
InnerHandleAutoCreateRef(this, Pin, CompilerContext, SourceGraph, /*bForceAssignment =*/true);
}
}
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

View File

@@ -0,0 +1,122 @@
# CustomStructureParam
- **功能描述:** 被CustomStructureParam标记的函数参数会变成Wildcard的通配符参数其引脚的类型会等于连接的变量类型。
- **使用位置:** UFUNCTION
- **引擎模块:** Blueprint
- **元数据类型:** strings="abc"
- **常用程度:** ★★★★★
被CustomStructureParam标记的多个函数参数会变成Wildcard的通配符参数其引脚的类型会等于连接的变量类型。
CustomStructureParam总是和CustomThunk一起配合使用这样才能在自己的函数体内来处理泛型的参数类型。
```cpp
UFUNCTION(BlueprintCallable, CustomThunk, meta = (DisplayName = "PrintStructFields", CustomStructureParam = "inputStruct"))
static FString PrintStructFields(const int32& inputStruct) { return TEXT(""); }
DECLARE_FUNCTION(execPrintStructFields);
static FString Generic_PrintStructFields(const UScriptStruct* ScriptStruct, const void* StructData);
DEFINE_FUNCTION(UMyFunction_Custom::execPrintStructFields)
{
FString result;
Stack.MostRecentPropertyAddress = nullptr;
Stack.StepCompiledIn<FStructProperty>(nullptr);
void* StructData = Stack.MostRecentPropertyAddress;
FStructProperty* StructProperty = CastField<FStructProperty>(Stack.MostRecentProperty);
UScriptStruct* ScriptStruct = StructProperty->Struct;
P_FINISH;
P_NATIVE_BEGIN;
result = Generic_PrintStructFields(ScriptStruct, StructData);
P_NATIVE_END;
*(FString*)RESULT_PARAM = result;
}
FString UMyFunction_Custom::Generic_PrintStructFields(const UScriptStruct* ScriptStruct, const void* StructData)
{
FString str;
for (TFieldIterator<FProperty> i(ScriptStruct); i; ++i)
{
FString propertyValueString;
const void* propertyValuePtr = i->ContainerPtrToValuePtr<const void*>(StructData);
i->ExportTextItem_Direct(propertyValueString, propertyValuePtr, nullptr, (UObject*)ScriptStruct, PPF_None);
str += FString::Printf(TEXT("%s:%s\n"), *i->GetFName().ToString(), *propertyValueString);
}
return str;
}
```
## 蓝图中的效果:
![Untitled](Untitled.png)
可以看到定义了一个接受通用结构参数的节点然后打印出内部所有的属性。其中CustomStructureParam 指定函数的参数是自定义的类型。
源码中的典型例子是
```cpp
UFUNCTION(BlueprintCallable, CustomThunk, Category = "DataTable", meta=(CustomStructureParam = "OutRow", BlueprintInternalUseOnly="true"))
static ENGINE_API bool GetDataTableRowFromName(UDataTable* Table, FName RowName, FTableRowBase& OutRow);
```
## 原理:
首先拥有CustomStructureParam的参数会被识别为Wildcard属性。然后通过FCustomStructureParamHelper来控制Pin->PinType = LinkedTo->PinType;从而改变Pin的实际类型。
```cpp
bool UEdGraphSchema_K2::IsWildcardProperty(const FProperty* Property)
{
UFunction* Function = Property->GetOwner<UFunction>();
return Function && ( UK2Node_CallArrayFunction::IsWildcardProperty(Function, Property)
|| UK2Node_CallFunction::IsStructureWildcardProperty(Function, Property->GetFName())
|| UK2Node_CallFunction::IsWildcardProperty(Function, Property)
|| FEdGraphUtilities::IsArrayDependentParam(Function, Property->GetFName()) );
}
static void FCustomStructureParamHelper::HandleSinglePin(UEdGraphPin* Pin)
{
if (Pin)
{
if (Pin->LinkedTo.Num() > 0)
{
UEdGraphPin* LinkedTo = Pin->LinkedTo[0];
check(LinkedTo);
if (UK2Node* Node = Cast<UK2Node>(Pin->GetOwningNode()))
{
ensure(
!LinkedTo->PinType.IsContainer() ||
Node->DoesWildcardPinAcceptContainer(Pin)
);
}
else
{
ensure( !LinkedTo->PinType.IsContainer() );
}
Pin->PinType = LinkedTo->PinType;
}
else
{
// constness and refness are controlled by our declaration
// but everything else needs to be reset to default wildcard:
const bool bWasRef = Pin->PinType.bIsReference;
const bool bWasConst = Pin->PinType.bIsConst;
Pin->PinType = FEdGraphPinType();
Pin->PinType.bIsReference = bWasRef;
Pin->PinType.bIsConst = bWasConst;
Pin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard;
Pin->PinType.PinSubCategory = NAME_None;
Pin->PinType.PinSubCategoryObject = nullptr;
}
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -0,0 +1,144 @@
# DeterminesOutputType
- **功能描述:** 指定一个参数的类型作为函数动态调整输出参数类型的参考类型
- **使用位置:** UFUNCTION
- **引擎模块:** Blueprint
- **元数据类型:** string="abc"
- **限制类型:** Class或Object指针类型或容器类型
- **关联项:** [DynamicOutputParam](../DynamicOutputParam.md)
- **常用程度:** ★★★
指定一个参数的类型作为函数输出参数的类型。
假定这么一个函数原型:
```cpp
UFUNCTION(BlueprintCallable, meta = (DeterminesOutputType = "A",DynamicOutputParam="P1,P2"))
TypeR MyFunc(TypeA A,Type1 P1,Type2 P2,Type3 P3);
```
DeterminesOutputType的值指定了一个函数参数名称即A。其TypeA的类型必须是Class或Object一般是TSubClassOf<XXX> 或者XXX* 当然也可以是TArray<XXX*>还可以是指向参数结构里的某个属性。如Args_ActorClassType。TSoftObjectPtr<XXX>也是可以的指向一个子类Asset对象然后输出的基类Asset*就可以相应改变。
所谓输出参数包括返回值和函数的输出参数因此上述函数原型里的TypeR,P1,P2都是输出参数。为了让输出参数的类型也相应变化TypeR、Type1和Type2的类型也得是Class或Object类型且A参数在蓝图节点上实际选择的类型必须是输出参数类型的子类这样才能自动转换过去。
如果没有P1和P2只把返回值当作TypeR则可以不指定DynamicOutputParam也可以自动默认把返回值当作动态的输出参数。否则则需要手动书写DynamicOutputParam来指定哪些函数参数来支持动态类型。
## 测试代码:
```cpp
UCLASS(Blueprintable, BlueprintType)
class INSIDER_API AMyAnimalActor :public AActor
{
public:
GENERATED_BODY()
};
UCLASS(Blueprintable, BlueprintType)
class INSIDER_API AMyCatActor :public AMyAnimalActor
{
public:
GENERATED_BODY()
};
UCLASS(Blueprintable, BlueprintType)
class INSIDER_API AMyDogActor :public AMyAnimalActor
{
public:
GENERATED_BODY()
};
USTRUCT(BlueprintType)
struct FMyOutputTypeArgs
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
int32 MyInt = 1;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
TSubclassOf<AMyAnimalActor> ActorClassType;
};
UCLASS(Blueprintable, BlueprintType)
class INSIDER_API UMyFunctionLibrary_OutputTypeTest :public UBlueprintFunctionLibrary
{
public:
GENERATED_BODY()
public:
//class
UFUNCTION(BlueprintCallable, meta = (DeterminesOutputType = "ActorClassType"))
static TArray<AActor*> MyGetAnimals(TSubclassOf<AMyAnimalActor> ActorClassType);
//have to add DynamicOutputParam
UFUNCTION(BlueprintCallable, meta = (DeterminesOutputType = "ActorClassType", DynamicOutputParam = "OutActors"))
static void MyGetAnimalsOut(TSubclassOf<AMyAnimalActor> ActorClassType, TArray<AActor*>& OutActors);
//have to add DynamicOutputParam
UFUNCTION(BlueprintCallable, meta = (DeterminesOutputType = "ActorClassType", DynamicOutputParam = "FirstOutActor,OutActors"))
static void MyGetAnimalsOut2(TSubclassOf<AMyAnimalActor> ActorClassType, AActor*& FirstOutActor, TArray<AActor*>& OutActors);
//object
UFUNCTION(BlueprintCallable, meta = (DeterminesOutputType = "ExampleActor"))
static TArray<AActor*> MyGetAnimalsWithActor(AMyAnimalActor* ExampleActor);
UFUNCTION(BlueprintCallable, meta = (DeterminesOutputType = "ExampleActorArray"))
static TArray<AActor*> MyGetAnimalsWithActorArray(TArray<AMyAnimalActor*> ExampleActorArray);
//struct property
UFUNCTION(BlueprintCallable, meta = (DeterminesOutputType = "Args_ActorClassType"))
static TArray<AActor*> MyGetAnimalsWithStructProperty(const FMyOutputTypeArgs& Args);
};
```
## 蓝图中效果:
用返回值当作输出参数的例子注意到返回值类型实际变成了TArray<AMyCatActor*>
![pic_a](pic_a.png)
也可以加上DynamicOutputParam来指定输出参数作为动态类型参数
![pic_b](pic_b.png)
DynamicOutputParam可以指定多个参数
![pic_c](pic_c.png)
DeterminesOutputType 的参数类型也可以是Object或者Object的容器
![pic_d](pic_d.png)
DeterminesOutputType 的参数甚至可以是结构里的某个属性但是只有SplitStruct的时候才生效因为这个时候结构的属性变量才变成函数的Pin才可以进行DeterminesOutputType的名称比对。这个时候要书写成“A_B”而不是“A.B”。
![pic_e](pic_e.png)
## 原理:
DeterminesOutputType的作用机制是根据这个名称去函数蓝图节点上查找Pin这个Pin得是Class或Object类型的容器也行因为必须是这二者才支持指针类型的转换。这个Pin在蓝图节点上是会由各种TypePicker来实际指定值比如ClassPicker或ObjectPicker。之后根据TypePicker选择的值就可以相应的调整DynamicOutputParam指定的参数的类型或返回参数真正发挥类型改变的是
Pin->PinType.PinSubCategoryObject = PickedClass;这一句。
```cpp
void FDynamicOutputHelper::ConformOutputType() const
{
if (IsTypePickerPin(MutatingPin))
{
UClass* PickedClass = GetPinClass(MutatingPin);
UK2Node_CallFunction* FuncNode = GetFunctionNode();
// See if there is any dynamic output pins
TArray<UEdGraphPin*> DynamicPins;
GetDynamicOutPins(FuncNode, DynamicPins);
// Set the pins class
for (UEdGraphPin* Pin : DynamicPins)
{
if (ensure(Pin != nullptr))
{
Pin->PinType.PinSubCategoryObject = PickedClass;//设定每个动态参数的子类型
}
}
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@@ -0,0 +1,9 @@
# DynamicOutputParam
- **功能描述:** 配合DeterminesOutputType指定多个支持动态类型的输出参数。
- **使用位置:** UFUNCTION
- **元数据类型:** strings="abc"
- **限制类型:** Class或Object指针类型或容器类型
- **关联项:** [DeterminesOutputType](DeterminesOutputType/DeterminesOutputType.md)
常常和DeterminesOutputType一起配合。动态参数的数量可以为多个。

View File

@@ -0,0 +1,41 @@
# HideSpawnParms
- **功能描述:** 在UGamelayTask子类生成的蓝图异步节点上隐藏UGamelayTask子类继承链中某些属性。
- **使用位置:** UFUNCTION
- **元数据类型:** strings="abc"
- **关联项:** [ExposedAsyncProxy](../../ExposedAsyncProxy/ExposedAsyncProxy.md)
在UGamelayTask子类生成的蓝图异步节点上隐藏UGamelayTask子类继承链中某些属性。
HideSpawnParms 只在UK2Node_LatentGameplayTaskCall中判断因此只作用于UGameplayTask的子类。在源码中找到的唯一用法是 HideSpawnParms = "Instigator”但是其UGamelayTask子类继承链中并无该属性因此其实是不发挥作用的。
```cpp
UFUNCTION(BlueprintCallable, Meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "true", HideSpawnParms = "Instigator"), Category = "Ability|Tasks")
static UAbilityTask_StartAbilityState* StartAbilityState(UGameplayAbility* OwningAbility, FName StateName, bool bEndCurrentState = true);
```
保留和去掉HideSpawnParms 的蓝图的节点都为:
![Untitled](Untitled.png)
## 源码里发生的位置:
```cpp
void UK2Node_LatentGameplayTaskCall::CreatePinsForClass(UClass* InClass)
{
// Tasks can hide spawn parameters by doing meta = (HideSpawnParms="PropertyA,PropertyB")
// (For example, hide Instigator in situations where instigator is not relevant to your task)
TArray<FString> IgnorePropertyList;
{
UFunction* ProxyFunction = ProxyFactoryClass->FindFunctionByName(ProxyFactoryFunctionName);
const FString& IgnorePropertyListStr = ProxyFunction->GetMetaData(FName(TEXT("HideSpawnParms")));
if (!IgnorePropertyListStr.IsEmpty())
{
IgnorePropertyListStr.ParseIntoArray(IgnorePropertyList, TEXT(","), true);
}
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -0,0 +1,8 @@
# MapKeyParam
- **功能描述:** 指定一个函数参数为Map的Key其根据MapParam指定的实际Map参数的Key类型而相应改变。
- **使用位置:** UFUNCTION
- **元数据类型:** string="abc"
- **限制类型:** TMap
- **关联项:** [MapParam](MapParam.md)
- **常用程度:** ★★★

View File

@@ -0,0 +1,92 @@
# MapParam
- **功能描述:** 指定一个函数为使用TMap<TKey,TValue>的函数,元素类型为通配符的泛型。
- **使用位置:** UFUNCTION
- **引擎模块:** Blueprint
- **元数据类型:** string="abc"
- **限制类型:** TMap
- **关联项:** [MapKeyParam](MapKeyParam.md), [MapValueParam](MapValueParam.md)
- **常用程度:** ★★★
指定一个函数为使用TMap<TKey,TValue>的函数,元素类型为通配符的泛型。
只能支持一个MapParam源码中的实现是只根据一个名字来FindPin。
在源码中例子都是在UBlueprintMapLibrary中使用。
## 测试代码1
```cpp
UFUNCTION(BlueprintPure, CustomThunk, meta = (MapParam = "TargetMap"))
static int32 MyMap_Count(const TMap<int32, int32>& TargetMap);
static int32 GenericMyMap_Count(const void* TargetMap, const FMapProperty* MapProperty);
DECLARE_FUNCTION(execMyMap_Count);
```
## 蓝图中效果1
![Untitled](Untitled.png)
因为只支持一个MapParam因此如果你书写这种代码 。
## 测试代码2
```cpp
UFUNCTION(BlueprintPure, CustomThunk, meta = (MapParam = "MapA,MapB"))
static int32 MyMap_CompareSize(const TMap<int32, int32>& MapA, const TMap<int32, int32>& MapB);
static int32 GenericMyMap_CompareSize(void* MapA, const FMapProperty* MapAProp, void* MapB, const FMapProperty* MapBProp);
DECLARE_FUNCTION(execMyMap_CompareSize);
```
会导致MapParam搜索不到Pin从而失去通配符的功能。
![Untitled](Untitled%201.png)
而如果要实现类似Add的功能达到Key和Value的Pin类型也可以动态的根据Map的类型而自动的改变。则需要加上MapKeyParam 和MapValueParam 分别的指定另外的函数参数以便能找到正确的Pin从而实现动态的根据Map类型而更改KeyValue Pin类型。MapKeyParam 和MapValueParam 指定的参数也可以为数组等容器可以参照UBlueprintMapLibrary中的Keys和Values参数。
```cpp
UFUNCTION(BlueprintCallable, CustomThunk, meta = (MapParam = "TargetMap",MapKeyParam = "Key", MapValueParam = "Value"))
static bool MyMap_FindOrAdd(const TMap<int32, int32>& TargetMap, const int32& Key, const int32& Value);
static bool GenericMyMap_FindOrAdd(const void* TargetMap, const FMapProperty* MapProperty, const void* KeyPtr, const void* ValuePtr);
DECLARE_FUNCTION(execMyMap_FindOrAdd);
```
## 蓝图中的效果2
![Untitled](Untitled%202.png)
## 原理代码:
```cpp
void UK2Node_CallFunction::ConformContainerPins()
{
//在这其中检测容器Pin
const FString& MapPinMetaData = TargetFunction->GetMetaData(FBlueprintMetadata::MD_MapParam);
const FString& MapKeyPinMetaData = TargetFunction->GetMetaData(FBlueprintMetadata::MD_MapKeyParam);
const FString& MapValuePinMetaData = TargetFunction->GetMetaData(FBlueprintMetadata::MD_MapValueParam);
if(!MapPinMetaData.IsEmpty() || !MapKeyPinMetaData.IsEmpty() || !MapValuePinMetaData.IsEmpty() )
{
// if the map pin has a connection infer from that, otherwise use the information on the key param and value param:
bool bReadyToPropagateKeyType = false;
FEdGraphTerminalType KeyTypeToPropagate;
bool bReadyToPropagateValueType = false;
FEdGraphTerminalType ValueTypeToPropagate;
UEdGraphPin* MapPin = MapPinMetaData.IsEmpty() ? nullptr : FindPin(MapPinMetaData);
UEdGraphPin* MapKeyPin = MapKeyPinMetaData.IsEmpty() ? nullptr : FindPin(MapKeyPinMetaData);
UEdGraphPin* MapValuePin = MapValuePinMetaData.IsEmpty() ? nullptr : FindPin(MapValuePinMetaData);
TryReadTypeToPropagate(MapPin, bReadyToPropagateKeyType, KeyTypeToPropagate);//读取MapPin的Key连接类型
TryReadValueTypeToPropagate(MapPin, bReadyToPropagateValueType, ValueTypeToPropagate);//读取MapPin上连接的Map Value类型
TryReadTypeToPropagate(MapKeyPin, bReadyToPropagateKeyType, KeyTypeToPropagate);//读取KeyPin上的连接类型
TryReadTypeToPropagate(MapValuePin, bReadyToPropagateValueType, ValueTypeToPropagate);//读取ValuePin上的连接类型
TryPropagateType(MapPin, KeyTypeToPropagate, bReadyToPropagateKeyType);//改变MapPin的Key当前类型
TryPropagateType(MapKeyPin, KeyTypeToPropagate, bReadyToPropagateKeyType);//改变KeyPin的当前类型
TryPropagateValueType(MapPin, ValueTypeToPropagate, bReadyToPropagateValueType);//改变MapPin的Value当前类型
TryPropagateType(MapValuePin, ValueTypeToPropagate, bReadyToPropagateValueType);//改变ValuePin的当前类型
}
}
```

View File

@@ -0,0 +1,8 @@
# MapValueParam
- **功能描述:** 指定一个函数参数为Map的Value其根据MapParam指定的实际Map参数的Value类型而相应改变。
- **使用位置:** UFUNCTION
- **元数据类型:** string="abc"
- **限制类型:** TMap
- **关联项:** [MapParam](../MapParam/MapParam.md)
- **常用程度:** ★★★

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB