vault backup: 2024-10-12 17:19:45
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# DataflowFlesh
|
||||
|
||||
- **功能描述:** ScriptStruct /Script/DataflowNodes.FloatOverrideDataflowNode
|
||||
- **使用位置:** USTRUCT
|
||||
- **引擎模块:** Struct
|
||||
- **元数据类型:** bool
|
||||
- **常用程度:** 0
|
||||
|
||||
没有在源码里找到应用的例子
|
@@ -0,0 +1,100 @@
|
||||
# HasNativeBreak
|
||||
|
||||
- **功能描述:** 为该结构指定一个C++内的UFunction函数作为Break节点的实现
|
||||
- **使用位置:** USTRUCT
|
||||
- **引擎模块:** Struct
|
||||
- **元数据类型:** string="abc"
|
||||
- **关联项:** [HasNativeMake](../HasNativeMake.md)
|
||||
- **常用程度:** ★★★★★
|
||||
|
||||
为该结构指定一个C++内的UFunction函数作为Break节点的实现
|
||||
|
||||
指定一个static *UFunction函数的完整路径值,一般是”/*Script/*Module.Class.Function”*
|
||||
|
||||
这个函数一般是BlueprintThreadSafe,因为这种纯Make和Break函数一般不带副作用,因此可以随便的多线程调用。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
//(BlueprintType = true, HasNativeBreak = /Script/Insider.MyHasNativeStructHelperLibrary.BreakMyHasNativeStruct, HasNativeMake = /Script/Insider.MyHasNativeStructHelperLibrary.MakeMyHasNativeStruct, ModuleRelativePath = Struct/MyStruct_NativeMakeBreak.h)
|
||||
USTRUCT(BlueprintType, meta = (HasNativeBreak = "/Script/Insider.MyHasNativeStructHelperLibrary.BreakMyHasNativeStruct", HasNativeMake = "/Script/Insider.MyHasNativeStructHelperLibrary.MakeMyHasNativeStruct"))
|
||||
struct INSIDER_API FMyStruct_HasNative
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
float MyReadWrite;
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
float MyReadOnly;
|
||||
UPROPERTY(EditAnywhere)
|
||||
float MyNotBlueprint;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct INSIDER_API FMyStruct_HasDefaultMakeBreak
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
float MyReadWrite;
|
||||
UPROPERTY(BlueprintReadOnly, EditAnywhere)
|
||||
float MyReadOnly;
|
||||
UPROPERTY(EditAnywhere)
|
||||
float MyNotBlueprint;
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UMyHasNativeStructHelperLibrary : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UFUNCTION(BlueprintPure, meta = (BlueprintThreadSafe))
|
||||
static void BreakMyHasNativeStruct(const FMyStruct_HasNative& myStruct, float& outValue)
|
||||
{
|
||||
outValue = myStruct.MyReadWrite + myStruct.MyReadOnly + myStruct.MyNotBlueprint;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure, meta = (BlueprintThreadSafe))
|
||||
static FMyStruct_HasNative MakeMyHasNativeStruct(float value)
|
||||
{
|
||||
FMyStruct_HasNative result;
|
||||
result.MyReadWrite = value;
|
||||
result.MyReadOnly = value;
|
||||
result.MyNotBlueprint = value;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## 蓝图节点:
|
||||
|
||||

|
||||
|
||||
## 原理是:
|
||||
|
||||
通过Meta里配置的值去找UFunction函数,因此我们配置的时候需要提供的是能找到UFunction的完整路径值。这个函数的签名会自动的被反射提取信息到UK2Node_CallFunction节点上,从而构造出不同样式的Make和Break蓝图节点。
|
||||
|
||||
```cpp
|
||||
E:\P4V\Engine\Source\Editor\BlueprintGraph\Private\EdGraphSchema_K2.cpp
|
||||
|
||||
const FString& MetaData = StructType->GetMetaData(FBlueprintMetadata::MD_NativeMakeFunction);
|
||||
const UFunction* Function = FindObject<UFunction>(nullptr, *MetaData, true);
|
||||
|
||||
UK2Node_CallFunction* CallFunctionNode;
|
||||
|
||||
if (Params.bTransient || Params.CompilerContext)
|
||||
{
|
||||
CallFunctionNode = (Params.bTransient ? NewObject<UK2Node_CallFunction>(Graph) : Params.CompilerContext->SpawnIntermediateNode<UK2Node_CallFunction>(GraphNode, Params.SourceGraph));
|
||||
CallFunctionNode->SetFromFunction(Function);
|
||||
CallFunctionNode->AllocateDefaultPins();
|
||||
}
|
||||
else
|
||||
{
|
||||
FGraphNodeCreator<UK2Node_CallFunction> MakeStructCreator(*Graph);
|
||||
CallFunctionNode = MakeStructCreator.CreateNode(false);
|
||||
CallFunctionNode->SetFromFunction(Function);
|
||||
MakeStructCreator.Finalize();
|
||||
}
|
||||
|
||||
SplitPinNode = CallFunctionNode;
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
@@ -0,0 +1,7 @@
|
||||
# HasNativeMake
|
||||
|
||||
- **功能描述:** 为该结构指定一个C++内的UFunction函数作为Mreak节点的实现
|
||||
- **使用位置:** USTRUCT
|
||||
- **元数据类型:** string="abc"
|
||||
- **关联项:** [HasNativeBreak](HasNativeBreak/HasNativeBreak.md)
|
||||
- **常用程度:** ★★★★★
|
@@ -0,0 +1,69 @@
|
||||
# IgnoreForMemberInitializationTest
|
||||
|
||||
- **功能描述:** 使得该属性忽略结构的未初始验证。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Struct
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** C++结构下的属性
|
||||
- **常用程度:** ★★
|
||||
|
||||
使得该属性忽略结构的未初始验证。
|
||||
|
||||
- 所谓未初始化,指的是C++结构里的变量没有在构造函数里初始化,也没有直接写上初始值
|
||||
- 结构未初始验证指的是引擎提供的验证工具,可采用控制台命令“CoreUObject.AttemptToFindUninitializedScriptStructMembers”调用。然后会输出引擎内所有未初始化的变量信息。
|
||||
- UE里的USTRUCT只是一个纯C++结构,不像用UCLASS定义的类都是一个UObject,后者的UPROPERTY属性会自动的都初始化为0,而结构里的UPROPERTY并不会自动的初始化,因此就需要我们手动的初始化。
|
||||
- 从实践来说,如果开发者清楚知道某变量未初始化不会影响逻辑,那即使未初始化也并没有关系。但现实是往往大家绝大多数情况下只是单纯的犯懒或者遗忘给属性初始化。因此还是建议大家尽量给结构里的所有属性都初始化值。但一些特殊情况下,某些属性确实不适合初始化,比如源码例子里一些FGuid变量,只在真正用到的时候才手动赋值,在这之前初始化什么值其实都意义不大。在这种情况下,就可以用IgnoreForMemberInitializationTest来使该属性忽略这个验证,避免输出报错信息。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
USTRUCT(BlueprintType)
|
||||
struct INSIDER_API FMyStruct_InitTest
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
int32 MyProperty;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite,meta=(IgnoreForMemberInitializationTest))
|
||||
int32 MyProperty_IgnoreTest;
|
||||
};
|
||||
```
|
||||
|
||||
## 测试结果:
|
||||
|
||||
可见MyProperty因为没有IgnoreForMemberInitializationTest就报错了。
|
||||
|
||||
```cpp
|
||||
在控制台调用CoreUObject.AttemptToFindUninitializedScriptStructMembers后:
|
||||
|
||||
LogClass: Error: IntProperty FMyStruct_InitTest::MyProperty is not initialized properly. Module:Insider File:Property/Struct/MyProperty_Struct.h
|
||||
```
|
||||
|
||||
## 原理:
|
||||
|
||||
这个命令行调用AttemptToFindUninitializedScriptStructMembers,继而继续调用FindUninitializedScriptStructMembers来查找出UScriptStruct中的未初始化变量。具体的找出方式可以在该函数中细看。
|
||||
|
||||
```cpp
|
||||
|
||||
static void FindUninitializedScriptStructMembers(UScriptStruct* ScriptStruct, EScriptStructTestCtorSyntax ConstructorSyntax, TSet<const FProperty*>& OutUninitializedProperties)
|
||||
{
|
||||
|
||||
for (const FProperty* Property : TFieldRange<FProperty>(ScriptStruct, EFieldIteratorFlags::ExcludeSuper))
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
static const FName NAME_IgnoreForMemberInitializationTest(TEXT("IgnoreForMemberInitializationTest"));
|
||||
if (Property->HasMetaData(NAME_IgnoreForMemberInitializationTest))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
|
||||
}
|
||||
|
||||
//由这个调用
|
||||
FStructUtils::AttemptToFindUninitializedScriptStructMembers();
|
||||
|
||||
// 命令行调用
|
||||
CoreUObject.AttemptToFindUninitializedScriptStructMembers
|
||||
```
|
@@ -0,0 +1,71 @@
|
||||
# MakeStructureDefaultValue
|
||||
|
||||
- **功能描述:** 存储BP中自定义结构里的属性的默认值。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Struct
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** BP里的用户自定义Struct
|
||||
- **常用程度:** ★
|
||||
|
||||
存储BP中自定义结构里的属性的默认值。
|
||||
|
||||
- 在C++中我们写的USTRUCT的结构里的属性默认值并不需要存储在元数据中,因为在创建该结构实例的时候,就自然会调用该结构的构造函数,从而正确初始化值。
|
||||
- 而在蓝图中的用户自定义结构,并没有构造函数之类的机制。因此我们需要一个专门的Tab来填写属性的默认值。这些默认值就会存储在属性的元数据中。
|
||||
-
|
||||
|
||||
## 测试代码:
|
||||
|
||||
在蓝图中定义一个结构BP_StructDefaultTest,并填上默认值。
|
||||
|
||||

|
||||
|
||||
## 测试结果:
|
||||
|
||||
用测试命令行打印出其相关的信息,可以见到MyInt和MyString的真正属性名以及MakeStructureDefaultValue 的值。
|
||||
|
||||
```cpp
|
||||
[struct BP_StructDefaultTest UserDefinedStruct->ScriptStruct->Struct->Field->Object /Game/Struct/BP_StructDefaultTest.BP_StructDefaultTest]
|
||||
(BlueprintType = true, Tooltip = )
|
||||
ObjectFlags: RF_Public | RF_Standalone | RF_Transactional | RF_WasLoaded | RF_LoadCompleted
|
||||
Outer: Package /Game/Struct/BP_StructDefaultTest
|
||||
StructFlags: STRUCT_NoFlags
|
||||
Size: 24
|
||||
{
|
||||
(DisplayName = MyInt, Tooltip = , MakeStructureDefaultValue = 789)
|
||||
0-[4] int32 MyInt_3_CC664A574A072369083883B38EA2F129;
|
||||
PropertyFlags: CPF_Edit | CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash
|
||||
ObjectFlags: RF_Public | RF_LoadCompleted
|
||||
Outer: UserDefinedStruct /Game/Struct/BP_StructDefaultTest.BP_StructDefaultTest
|
||||
Path: IntProperty /Game/Struct/BP_StructDefaultTest.BP_StructDefaultTest:MyInt_3_CC664A574A072369083883B38EA2F129
|
||||
(DisplayName = MyString, Tooltip = , MakeStructureDefaultValue = Hello)
|
||||
8-[16] FString MyString_6_D8FAF5D6454C781C2D5175ACF266C394;
|
||||
PropertyFlags: CPF_Edit | CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_HasGetValueTypeHash
|
||||
ObjectFlags: RF_Public | RF_LoadCompleted
|
||||
Outer: UserDefinedStruct /Game/Struct/BP_StructDefaultTest.BP_StructDefaultTest
|
||||
Path: StrProperty /Game/Struct/BP_StructDefaultTest.BP_StructDefaultTest:MyString_6_D8FAF5D6454C781C2D5175ACF266C394
|
||||
};
|
||||
```
|
||||
|
||||
## 原理:
|
||||
|
||||
在BP中结构创建变量保存的时候,如果发现默认值不为空,则设置到MakeStructureDefaultValue中去。之后再MakeStruct的时候就可以用上了。
|
||||
|
||||
```cpp
|
||||
void UK2Node_MakeStruct::FMakeStructPinManager::CustomizePinData(UEdGraphPin* Pin, FName SourcePropertyName, int32 ArrayIndex, FProperty* Property) const
|
||||
{
|
||||
const FString& MetadataDefaultValue = Property->GetMetaData(TEXT("MakeStructureDefaultValue"));
|
||||
if (!MetadataDefaultValue.IsEmpty())
|
||||
{
|
||||
Schema->SetPinAutogeneratedDefaultValue(Pin, MetadataDefaultValue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUserDefinedStructureCompilerInner::CreateVariables(UUserDefinedStruct* Struct, const class UEdGraphSchema_K2* Schema, FCompilerResultsLog& MessageLog)
|
||||
{
|
||||
if (!VarDesc.DefaultValue.IsEmpty())
|
||||
{
|
||||
VarProperty->SetMetaData(TEXT("MakeStructureDefaultValue"), *VarDesc.DefaultValue);
|
||||
}
|
||||
}
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 187 KiB |
Reference in New Issue
Block a user