vault backup: 2024-10-12 17:19:45
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
# BlueprintInternalUseOnly
|
||||
|
||||
- **功能描述:** 不可定义新BP变量,但可作为别的类的成员变量暴露和变量传递
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** Blueprint
|
||||
- **作用机制:** 在Meta中加入[BlueprintInternalUseOnly](../../../../Meta/Blueprint/BlueprintInternalUseOnly.md), [BlueprintType](../../../../Meta/Blueprint/BlueprintType.md)
|
||||
- **常用程度:** ★★
|
||||
|
||||
指明这个STRUCT会是个BlueprintType,但在蓝图编辑器中又不能声明新变量,但是可以作为别的类的成员变量暴露到蓝图中。
|
||||
|
||||
和不写BlueprintType的差别是什么?
|
||||
|
||||
不写BlueprintType则完全不能作为别的类的成员变量。BlueprintInternalUseOnly抑制了定义新变量的能力,但是可以作为变量传递。比如在C++中定义变量,然后在蓝图中传递。
|
||||
|
||||
如FTableRowBase本身并不能定义新变量,但是其子类(要加上BlueprintType)是可以定义新变量的,正常被使用。
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
//(BlueprintInternalUseOnly = true, BlueprintType = true, ModuleRelativePath = Struct/MyStruct_BlueprintInternalUseOnly.h)
|
||||
USTRUCT(BlueprintInternalUseOnly)
|
||||
struct INSIDER_API FMyStruct_BlueprintInternalUseOnly
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadWrite,EditAnywhere)
|
||||
float Score=0.f;
|
||||
};
|
||||
|
||||
USTRUCT()
|
||||
struct INSIDER_API FMyStruct_NoBlueprintInternalUseOnly
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
float Score=0.f;
|
||||
};
|
||||
|
||||
UCLASS(Blueprintable,BlueprintType)
|
||||
class INSIDER_API UMyClass_BlueprintInternalUseOnlyTest :public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UPROPERTY(BlueprintReadWrite,EditAnywhere)
|
||||
FMyStruct_BlueprintInternalUseOnly MyInternalStruct;
|
||||
|
||||
/*UPROPERTY(BlueprintReadWrite,EditAnywhere) //no supported by BP
|
||||
FMyStruct_NoBlueprintInternalUseOnly MyStruct;*/
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## 示例效果:
|
||||
|
||||
NewVar是UMyClass_BlueprintInternalUseOnlyTest 类型的,依然可以访问内部的MyInternalStruct变量。
|
||||
|
||||

|
||||
|
||||
源码里可以找到:
|
||||
|
||||
```cpp
|
||||
USTRUCT(BlueprintInternalUseOnly)
|
||||
struct FLatentActionInfo
|
||||
{}
|
||||
|
||||
USTRUCT(BlueprintInternalUseOnly)
|
||||
struct FTableRowBase
|
||||
{}
|
||||
```
|
||||
|
||||
## 原理:
|
||||
|
||||
```cpp
|
||||
bool UEdGraphSchema_K2::IsAllowableBlueprintVariableType(const UScriptStruct* InStruct, const bool bForInternalUse)
|
||||
{
|
||||
if (const UUserDefinedStruct* UDStruct = Cast<const UUserDefinedStruct>(InStruct))
|
||||
{
|
||||
if (EUserDefinedStructureStatus::UDSS_UpToDate != UDStruct->Status.GetValue())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// User-defined structs are always allowed as BP variable types.
|
||||
return true;
|
||||
}
|
||||
|
||||
// struct needs to be marked as BP type
|
||||
if (InStruct && InStruct->GetBoolMetaDataHierarchical(FBlueprintMetadata::MD_AllowableBlueprintVariableType))
|
||||
{
|
||||
// for internal use, all BP types are allowed
|
||||
if (bForInternalUse)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// for user-facing use case, only allow structs that don't have the internal-use-only tag
|
||||
// struct itself should not be tagged
|
||||
if (!InStruct->GetBoolMetaData(FBlueprintMetadata::MD_BlueprintInternalUseOnly))
|
||||
{
|
||||
// struct's base structs should not be tagged
|
||||
if (!InStruct->GetBoolMetaDataHierarchical(FBlueprintMetadata::MD_BlueprintInternalUseOnlyHierarchical))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//Node->IsIntermediateNode()如果为true,则是作为中间节点使用,true会导致bForInternalUse为true
|
||||
if (!UK2Node_MakeStruct::CanBeMade(Node->StructType, Node->IsIntermediateNode()))
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,67 @@
|
||||
# BlueprintInternalUseOnlyHierarchical
|
||||
|
||||
- **功能描述:** 在BlueprintInternalUseOnly的基础上,增加了子类也不能定义新BP变量的限制。
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** Blueprint
|
||||
- **作用机制:** 在Meta中加入[BlueprintInternalUseOnlyHierarchical](../../../Meta/Blueprint/BlueprintInternalUseOnlyHierarchical.md)
|
||||
- **常用程度:★**
|
||||
|
||||
在BlueprintInternalUseOnly的基础上,增加了子类也不能定义新BP变量的限制。
|
||||
|
||||
目前只找到一个用处,但是也依然没有子类。如果我们在C++中定义新的子类,则所有的子类都不能定义变量。注意和FTableRowBase的区别是,FTableRowBase的子类依然可以定义新变量,因为FTableRowBase的BlueprintInternalUseOnly标记只作用于自己。
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
USTRUCT(BlueprintInternalUseOnlyHierarchical)
|
||||
struct GAMEPLAYABILITIESEDITOR_API FGameplayAbilityAuditRow : public FTableRowBase
|
||||
{}
|
||||
|
||||
USTRUCT(BlueprintInternalUseOnly)
|
||||
struct FTableRowBase
|
||||
{}
|
||||
```
|
||||
|
||||
## 原理:
|
||||
|
||||
只在这个地方用到,GetBoolMetaDataHierarchical会检查结构的所有父类测试是否含有某个标记。所以只要有一个父类有一个这个标记,就不能定义新变量。
|
||||
|
||||
```cpp
|
||||
bool UEdGraphSchema_K2::IsAllowableBlueprintVariableType(const UScriptStruct* InStruct, const bool bForInternalUse)
|
||||
{
|
||||
if (const UUserDefinedStruct* UDStruct = Cast<const UUserDefinedStruct>(InStruct))
|
||||
{
|
||||
if (EUserDefinedStructureStatus::UDSS_UpToDate != UDStruct->Status.GetValue())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// User-defined structs are always allowed as BP variable types.
|
||||
return true;
|
||||
}
|
||||
|
||||
// struct needs to be marked as BP type
|
||||
if (InStruct && InStruct->GetBoolMetaDataHierarchical(FBlueprintMetadata::MD_AllowableBlueprintVariableType))
|
||||
{
|
||||
// for internal use, all BP types are allowed
|
||||
if (bForInternalUse)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// for user-facing use case, only allow structs that don't have the internal-use-only tag
|
||||
// struct itself should not be tagged
|
||||
if (!InStruct->GetBoolMetaData(FBlueprintMetadata::MD_BlueprintInternalUseOnly))
|
||||
{
|
||||
// struct's base structs should not be tagged
|
||||
if (!InStruct->GetBoolMetaDataHierarchical(FBlueprintMetadata::MD_BlueprintInternalUseOnlyHierarchical))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
```
|
@@ -0,0 +1,35 @@
|
||||
# BlueprintType
|
||||
|
||||
- **功能描述:** 允许这个结构在蓝图中声明变量
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** Blueprint
|
||||
- **作用机制:** 在Meta中加入[BlueprintType](../../../../Meta/Blueprint/BlueprintType.md)
|
||||
- **常用程度:★★★★★**
|
||||
|
||||
和UCLASS里的一样,可以允许这个结构在蓝图中声明变量
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
USTRUCT(BlueprintType)
|
||||
struct INSIDER_API FMyStruct_BlueprintType
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadWrite,EditAnywhere)
|
||||
float Score;
|
||||
};
|
||||
|
||||
USTRUCT()
|
||||
struct INSIDER_API FMyStruct_NoBlueprintType
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
float Score;
|
||||
};
|
||||
```
|
||||
|
||||
## 测试蓝图:
|
||||
|
||||

|
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,91 @@
|
||||
# immutable
|
||||
|
||||
- **功能描述:** Immutable is only legal in Object.h and is being phased out, do not use on new structs!
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** Serialization
|
||||
- **作用机制:** 在StructFlags中加入[STRUCT_Immutable](../../../Flags/EStructFlags/STRUCT_Immutable.md)
|
||||
|
||||
当前只在noexporttypes.h里找到一堆Struct
|
||||
|
||||
指定这个结构的字段已经定义完毕,以后不会再修改,因此可以UseBinarySerialization来序列化,不需要支持字段的增删。
|
||||
|
||||
```cpp
|
||||
//USTRUCT(BlueprintType,Immutable) //error : Immutable is being phased out in favor of SerializeNative, and is only legal on the mirror structs declared in UObject
|
||||
//struct INSIDER_API FMyStruct_Immutable
|
||||
//{
|
||||
// GENERATED_BODY()
|
||||
//
|
||||
// UPROPERTY(BlueprintReadWrite,EditAnywhere)
|
||||
// float Score;
|
||||
//
|
||||
//};
|
||||
|
||||
Struct[67] WithFlags:STRUCT_Immutable
|
||||
Struct: ScriptStruct /Script/CoreUObject.Guid
|
||||
Struct: ScriptStruct /Script/CoreUObject.DateTime
|
||||
Struct: ScriptStruct /Script/CoreUObject.Box
|
||||
Struct: ScriptStruct /Script/CoreUObject.Vector
|
||||
Struct: ScriptStruct /Script/CoreUObject.Box2D
|
||||
Struct: ScriptStruct /Script/CoreUObject.Vector2D
|
||||
Struct: ScriptStruct /Script/CoreUObject.Box2f
|
||||
Struct: ScriptStruct /Script/CoreUObject.Vector2f
|
||||
Struct: ScriptStruct /Script/CoreUObject.Box3d
|
||||
Struct: ScriptStruct /Script/CoreUObject.Vector3d
|
||||
Struct: ScriptStruct /Script/CoreUObject.Box3f
|
||||
Struct: ScriptStruct /Script/CoreUObject.Vector3f
|
||||
Struct: ScriptStruct /Script/CoreUObject.Color
|
||||
Struct: ScriptStruct /Script/CoreUObject.Int32Point
|
||||
Struct: ScriptStruct /Script/CoreUObject.Int32Vector
|
||||
Struct: ScriptStruct /Script/CoreUObject.Int32Vector2
|
||||
Struct: ScriptStruct /Script/CoreUObject.Int32Vector4
|
||||
Struct: ScriptStruct /Script/CoreUObject.Int64Point
|
||||
Struct: ScriptStruct /Script/CoreUObject.Int64Vector
|
||||
Struct: ScriptStruct /Script/CoreUObject.Int64Vector2
|
||||
Struct: ScriptStruct /Script/CoreUObject.Int64Vector4
|
||||
Struct: ScriptStruct /Script/CoreUObject.LinearColor
|
||||
Struct: ScriptStruct /Script/CoreUObject.Quat
|
||||
Struct: ScriptStruct /Script/CoreUObject.TwoVectors
|
||||
Struct: ScriptStruct /Script/CoreUObject.IntPoint
|
||||
Struct: ScriptStruct /Script/CoreUObject.IntVector
|
||||
Struct: ScriptStruct /Script/CoreUObject.IntVector2
|
||||
Struct: ScriptStruct /Script/CoreUObject.IntVector4
|
||||
Struct: ScriptStruct /Script/CoreUObject.Matrix
|
||||
Struct: ScriptStruct /Script/CoreUObject.Plane
|
||||
Struct: ScriptStruct /Script/CoreUObject.Matrix44d
|
||||
Struct: ScriptStruct /Script/CoreUObject.Plane4d
|
||||
Struct: ScriptStruct /Script/CoreUObject.Matrix44f
|
||||
Struct: ScriptStruct /Script/CoreUObject.Plane4f
|
||||
Struct: ScriptStruct /Script/CoreUObject.OrientedBox
|
||||
Struct: ScriptStruct /Script/CoreUObject.PackedNormal
|
||||
Struct: ScriptStruct /Script/CoreUObject.PackedRGB10A2N
|
||||
Struct: ScriptStruct /Script/CoreUObject.PackedRGBA16N
|
||||
Struct: ScriptStruct /Script/CoreUObject.Quat4d
|
||||
Struct: ScriptStruct /Script/CoreUObject.Quat4f
|
||||
Struct: ScriptStruct /Script/CoreUObject.Ray
|
||||
Struct: ScriptStruct /Script/CoreUObject.Ray3d
|
||||
Struct: ScriptStruct /Script/CoreUObject.Ray3f
|
||||
Struct: ScriptStruct /Script/CoreUObject.Rotator
|
||||
Struct: ScriptStruct /Script/CoreUObject.Rotator3d
|
||||
Struct: ScriptStruct /Script/CoreUObject.Rotator3f
|
||||
Struct: ScriptStruct /Script/CoreUObject.Sphere
|
||||
Struct: ScriptStruct /Script/CoreUObject.Sphere3d
|
||||
Struct: ScriptStruct /Script/CoreUObject.Sphere3f
|
||||
Struct: ScriptStruct /Script/CoreUObject.Timespan
|
||||
Struct: ScriptStruct /Script/CoreUObject.Transform3d
|
||||
Struct: ScriptStruct /Script/CoreUObject.Transform3f
|
||||
Struct: ScriptStruct /Script/CoreUObject.Uint32Point
|
||||
Struct: ScriptStruct /Script/CoreUObject.Uint32Vector
|
||||
Struct: ScriptStruct /Script/CoreUObject.Uint32Vector2
|
||||
Struct: ScriptStruct /Script/CoreUObject.Uint32Vector4
|
||||
Struct: ScriptStruct /Script/CoreUObject.Uint64Point
|
||||
Struct: ScriptStruct /Script/CoreUObject.Uint64Vector
|
||||
Struct: ScriptStruct /Script/CoreUObject.Uint64Vector2
|
||||
Struct: ScriptStruct /Script/CoreUObject.Uint64Vector4
|
||||
Struct: ScriptStruct /Script/CoreUObject.UintPoint
|
||||
Struct: ScriptStruct /Script/CoreUObject.UintVector
|
||||
Struct: ScriptStruct /Script/CoreUObject.UintVector2
|
||||
Struct: ScriptStruct /Script/CoreUObject.UintVector4
|
||||
Struct: ScriptStruct /Script/CoreUObject.Vector4
|
||||
Struct: ScriptStruct /Script/CoreUObject.Vector4d
|
||||
Struct: ScriptStruct /Script/CoreUObject.Vector4f
|
||||
```
|
@@ -0,0 +1,116 @@
|
||||
# Atomic
|
||||
|
||||
- **功能描述:** 指定该结构在序列化的时候总是一整个输出全部属性,而不是只输出改变的属性。
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** UHT
|
||||
- **作用机制:** 在StructFlags中加入[STRUCT_Atomic](../../../../Flags/EStructFlags/STRUCT_Atomic.md)
|
||||
- **常用程度:** ★
|
||||
|
||||
指定该结构在序列化的时候总是一整个输出全部属性,而不是只输出改变的属性。
|
||||
|
||||
所谓的原子化序列化指的是如果该结构的某个字段属性同默认值不同,但是其他字段相同,也要一次性的序列化整个结构,而不是拆开。注意这个只在普通的SerializeVersionedTaggedProperties下有效,因为是对比默认值。在Bin下无效。其实作用机理是当采用原子化序列化的时候,就不检查内部属性的默认值,从而无论什么情况都会序列化进整个属性。
|
||||
|
||||
UE的noexporttype.h中有大量的atomic的基础结构,如FVector,因为Immutable也会同时设置STRUCT_Atomic,但是没有发现单独设置Atomic的地方。
|
||||
|
||||
## 示例代码:
|
||||
|
||||
```cpp
|
||||
USTRUCT(BlueprintType)
|
||||
struct INSIDER_API FMyStruct_InnerItem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
int32 A = 1;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
int32 B = 2;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
int32 C = 3;
|
||||
|
||||
bool operator==(const FMyStruct_InnerItem& other)const
|
||||
{
|
||||
return A == other.A;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct INSIDER_API FMyStruct_NoAtomic
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
FMyStruct_InnerItem Item;
|
||||
};
|
||||
|
||||
USTRUCT(Atomic, BlueprintType)
|
||||
struct INSIDER_API FMyStruct_Atomic
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
FMyStruct_InnerItem Item;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct TStructOpsTypeTraits<FMyStruct_InnerItem> : public TStructOpsTypeTraitsBase2<FMyStruct_InnerItem>
|
||||
{
|
||||
enum
|
||||
{
|
||||
WithIdenticalViaEquality = true,
|
||||
};
|
||||
};
|
||||
|
||||
void USerializationLibrary::SaveStructToMemory(UScriptStruct* structClass, void* structObject, const void* structDefaults, TArray<uint8>& outSaveData, EInsiderSerializationFlags flags/*=EInsiderSerializationFlags::None*/)
|
||||
{
|
||||
FMemoryWriter MemoryWriter(outSaveData, false);
|
||||
MemoryWriter.SetWantBinaryPropertySerialization(EnumHasAnyFlags(flags, EInsiderSerializationFlags::UseBinary));
|
||||
if (!EnumHasAnyFlags(flags, EInsiderSerializationFlags::CheckDefaults))
|
||||
{
|
||||
structDefaults=nullptr;
|
||||
}
|
||||
structClass->SerializeItem(MemoryWriter, structObject, structDefaults);
|
||||
}
|
||||
|
||||
测试代码:
|
||||
FMyStruct_NoAtomic NoAtomicStruct;
|
||||
NoAtomicStruct.Item.A=3;
|
||||
|
||||
FMyStruct_Atomic AtomicStruct;
|
||||
AtomicStruct.Item.A=3;
|
||||
|
||||
TArray<uint8> NoAtomicMemoryChanged;
|
||||
USerializationLibrary::SaveStructToMemory(NoAtomicStruct,NoAtomicMemoryChanged,EInsiderSerializationFlags::CheckDefaults);
|
||||
|
||||
TArray<uint8> AtomicMemoryChanged;
|
||||
USerializationLibrary::SaveStructToMemory(AtomicStruct,AtomicMemoryChanged,EInsiderSerializationFlags::CheckDefaults);
|
||||
```
|
||||
|
||||
## 示例效果:
|
||||
|
||||
可见AtomicMemoryChanged的占用内存大小比AtomicMemoryChanged多,因为这两个结构的属性虽然都改变了,但是AtomicStruct总是会把所有的属性都序列化出来。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
作用的机理是,一个外部结构是Atomic的,其内部的属性如果发现有改变,这个时候内部属性得是另一个结构,因为如果只是Int属性,则不会对比内部属性默认值。如果是内部结构属性的话,因为其中一个ID字段不一样,就在对比的时候导致整个结构不等(但同时该内部结构又有其他属性是相同的,所以上面示例代码只改了A,且提供了==的比较函数)。默认的方式是依然会在内部结构的内部属性上继续对比默认值,但原子化后就截断了默认值为null,从而导致孙子属性没有默认值可对比,从而就把整个内部属性就都输出出来。因此Atomic是用在外部结构上的,用在FVector这种不太会继续拆开的结构其实没什么意义。
|
||||
|
||||
```cpp
|
||||
void UStruct::SerializeVersionedTaggedProperties(FStructuredArchive::FSlot Slot, uint8* Data, UStruct* DefaultsStruct, uint8* Defaults, const UObject* BreakRecursionIfFullyLoad) const
|
||||
{
|
||||
//……
|
||||
/** If true, it means that we want to serialize all properties of this struct if any properties differ from defaults */
|
||||
bool bUseAtomicSerialization = false;
|
||||
if (DefaultsScriptStruct)
|
||||
{
|
||||
bUseAtomicSerialization = DefaultsScriptStruct->ShouldSerializeAtomically(UnderlyingArchive);
|
||||
}
|
||||
|
||||
if (bUseAtomicSerialization)
|
||||
{
|
||||
DefaultValue = NULL;
|
||||
}
|
||||
}
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
@@ -0,0 +1,42 @@
|
||||
# HasDefaults
|
||||
|
||||
- **功能描述:** 指定该结构的字段拥有默认值。这样如果本结构作为函数参数或返回值时候,函数则可以为其提供默认值。
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** UHT
|
||||
- **限制类型:** 只在NoExportTypes.h供UHT使用
|
||||
- **作用机制:** 在FunctionFlags中加入[FUNC_HasDefaults](../../../Flags/EFunctionFlags/FUNC_HasDefaults.md)
|
||||
- **常用程度:** 0
|
||||
|
||||
指定该结构的字段拥有默认值。
|
||||
|
||||
不是指的是NoExportTypes.h的声明上是否写有默认值,而是指其真正的声明之处,其内部的属性都有初始值。这样如果本结构作为函数参数或返回值时候,函数则可以为其提供默认值。
|
||||
|
||||
NoExportTypes.h里的大部分结构都拥有该结构(88/135),没有的是像FPackedXXX的。
|
||||
|
||||
## 原理:
|
||||
|
||||
如果是一个class中的函数且参数用到了结构,如果该结构拥有HasDefaults,则会造成EFunctionFlags.HasDefaults
|
||||
|
||||
```cpp
|
||||
// The following code is only performed on functions in a class.
|
||||
if (Outer is UhtClass)
|
||||
{
|
||||
foreach (UhtType type in Children)
|
||||
{
|
||||
if (type is UhtProperty property)
|
||||
{
|
||||
if (property.PropertyFlags.HasExactFlags(EPropertyFlags.OutParm | EPropertyFlags.ReturnParm, EPropertyFlags.OutParm))
|
||||
{
|
||||
FunctionFlags |= EFunctionFlags.HasOutParms;
|
||||
}
|
||||
if (property is UhtStructProperty structProperty)
|
||||
{
|
||||
if (structProperty.ScriptStruct.HasDefaults)
|
||||
{
|
||||
FunctionFlags |= EFunctionFlags.HasDefaults;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@@ -0,0 +1,61 @@
|
||||
# HasNoOpConstructor
|
||||
|
||||
- **功能描述:** 指定该结构拥有ForceInit的构造函数,这样在作为BP function返回值的时候,可以调用来初始化
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** UHT
|
||||
- **限制类型:** 只在NoExportTypes.h供UHT使用
|
||||
- **常用程度:** 0
|
||||
|
||||
指定该结构拥有ForceInit的构造函数,这样在作为BP Function返回值或参数的时候,引擎就知道这个结构有这么一个构造函数可以调用来初始化。
|
||||
|
||||
作用的地方是UhtHeaderCodeGenerator中的AppendEventParameter,为了这样的代码,这是一个暴露到BP中的Event,要为它生成一些胶水代码。这里FLinearColor 就是HasNoOpConstructor。例如以下这个函数:
|
||||
|
||||
```cpp
|
||||
UFUNCTION(BlueprintNativeEvent, Category = "Modifier")
|
||||
FLinearColor GetVisualizationColor(FInputActionValue SampleValue, FInputActionValue FinalValue) const;
|
||||
```
|
||||
|
||||
生成的代码:
|
||||
|
||||
```cpp
|
||||
struct InputModifier_eventGetVisualizationColor_Parms
|
||||
{
|
||||
FInputActionValue SampleValue;
|
||||
FInputActionValue FinalValue;
|
||||
FLinearColor ReturnValue;
|
||||
|
||||
/** Constructor, initializes return property only **/
|
||||
InputModifier_eventGetVisualizationColor_Parms()
|
||||
: ReturnValue(ForceInit)//强制初始化
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static FName NAME_UInputModifier_GetVisualizationColor = FName(TEXT("GetVisualizationColor"));
|
||||
FLinearColor UInputModifier::GetVisualizationColor(FInputActionValue SampleValue, FInputActionValue FinalValue) const
|
||||
{
|
||||
InputModifier_eventGetVisualizationColor_Parms Parms;
|
||||
Parms.SampleValue=SampleValue;
|
||||
Parms.FinalValue=FinalValue;
|
||||
const_cast<UInputModifier*>(this)->ProcessEvent(FindFunctionChecked(NAME_UInputModifier_GetVisualizationColor),&Parms);
|
||||
return Parms.ReturnValue;
|
||||
}
|
||||
```
|
||||
|
||||
因此要求该结构拥有ForceInit的构造函数
|
||||
|
||||
```cpp
|
||||
FORCEINLINE explicit FLinearColor(EForceInit)
|
||||
: R(0), G(0), B(0), A(0)
|
||||
{}
|
||||
```
|
||||
|
||||
## 原理:
|
||||
|
||||
```cpp
|
||||
if (ScriptStruct.HasNoOpConstructor)
|
||||
{
|
||||
//If true, the an argument will need to be added to the constructor
|
||||
PropertyCaps |= UhtPropertyCaps.RequiresNullConstructorArg;
|
||||
}
|
||||
```
|
@@ -0,0 +1,120 @@
|
||||
# IsAlwaysAccessible
|
||||
|
||||
- **功能描述:** 指定UHT在生成文件的时候总是可以访问到改结构的声明,否则要在gen.cpp里生成镜像结构定义
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** UHT
|
||||
- **限制类型:** 只在NoExportTypes.h供UHT使用
|
||||
- **常用程度:** 0
|
||||
|
||||
指定该结构的声明是否在UHT为NoExportTypes.h生成的gen.cpp里总是可以访问到。
|
||||
|
||||
换句话说其实就是是否这些结构在GeneratedCppIncludes.h的声明里可以找到。如果不可以找到,那在后面生成Z_Construct_UScriptStruct_FMatrix44d_Statics这种类似的时候就得再自己定义一个镜像结构定义。如果可以找到,比如FGuid,则就不需要。
|
||||
|
||||
因此这只是一个手动的内部标记,帮助UHT程序识别哪些结构要再创建镜像结构定义。
|
||||
|
||||
在NoExportTypes.h查看各个结构的时候,会发现有些结构(85/135)会标上IsAlwaysAccessible,而有些没有。这是因为UHT在为NoExportTypes.h生成gen.cpp的时候,
|
||||
|
||||
```cpp
|
||||
\UnrealEngine\Engine\Source\Runtime\CoreUObject\Public\UObject\GeneratedCppIncludes.h
|
||||
#include "UObject/Object.h"
|
||||
#include "UObject/UObjectGlobals.h"
|
||||
#include "UObject/CoreNative.h"
|
||||
#include "UObject/Class.h"
|
||||
#include "UObject/MetaData.h"
|
||||
#include "UObject/UnrealType.h"
|
||||
#include "UObject/EnumProperty.h"
|
||||
#include "UObject/TextProperty.h"
|
||||
#include "UObject/FieldPathProperty.h"
|
||||
|
||||
#if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_2
|
||||
#include "CoreMinimal.h"
|
||||
#endif
|
||||
|
||||
\Hello\Intermediate\Build\Win64\HelloEditor\Inc\CoreUObject\UHT\NoExportTypes.gen.cpp:
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
/*===========================================================================
|
||||
Generated code exported from UnrealHeaderTool.
|
||||
DO NOT modify this manually! Edit the corresponding .h files instead!
|
||||
===========================================================================*/
|
||||
|
||||
//以下这两行
|
||||
#include "UObject/GeneratedCppIncludes.h"//A
|
||||
#include "UObject/NoExportTypes.h"//B
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
void EmptyLinkFunctionForGeneratedCodeNoExportTypes() {}
|
||||
```
|
||||
|
||||
在最开头的两个include里如果可以直接找到该struct的定义,则在gen.cpp中的A和B处需要结构定义的时候,就不需要再额外去找定义了。
|
||||
|
||||
```cpp
|
||||
const UECodeGen_Private::FStructParams Z_Construct_UScriptStruct_FMatrix44f_Statics::ReturnStructParams = {
|
||||
(UObject* (*)())Z_Construct_UPackage__Script_CoreUObject,
|
||||
nullptr,
|
||||
nullptr,
|
||||
"Matrix44f",
|
||||
Z_Construct_UScriptStruct_FMatrix44f_Statics::PropPointers,
|
||||
UE_ARRAY_COUNT(Z_Construct_UScriptStruct_FMatrix44f_Statics::PropPointers),
|
||||
sizeof(FMatrix44f),//这个A
|
||||
alignof(FMatrix44f),//这个B
|
||||
RF_Public|RF_Transient|RF_MarkAsNative,
|
||||
EStructFlags(0x00000038),
|
||||
METADATA_PARAMS(UE_ARRAY_COUNT(Z_Construct_UScriptStruct_FMatrix44f_Statics::Struct_MetaDataParams), Z_Construct_UScriptStruct_FMatrix44f_Statics::Struct_MetaDataParams)
|
||||
};
|
||||
```
|
||||
|
||||
如果找不到,比如FMatrix44f,是定义在Engine\Source\Runtime\Core\Public\Math\Matrix.h,则必须为它生成一个一模一样的定义(不include的作用是加快编译):
|
||||
|
||||
```cpp
|
||||
struct Z_Construct_UScriptStruct_FMatrix44f_Statics
|
||||
{
|
||||
struct FMatrix44f //内存布局一致的定义
|
||||
{
|
||||
FPlane4f XPlane;
|
||||
FPlane4f YPlane;
|
||||
FPlane4f ZPlane;
|
||||
FPlane4f WPlane;
|
||||
};
|
||||
|
||||
static_assert(sizeof(FMatrix44f) < MAX_uint16);
|
||||
static_assert(alignof(FMatrix44f) < MAX_uint8);
|
||||
```
|
||||
|
||||
当然如果子字段或者父类也找不到定义,则只需要把父定义先写在前面就可以了。因此cs里的FindNoExportStructsRecursive就是为了找到其相关的结构。没有标IsAlwaysAccessible则意味着要生成假的结构定义
|
||||
|
||||
```cpp
|
||||
private static void FindNoExportStructsRecursive(List<UhtScriptStruct> outScriptStructs, UhtStruct structObj)
|
||||
{
|
||||
for (UhtStruct? current = structObj; current != null; current = current.SuperStruct)
|
||||
{
|
||||
// Is isn't true for noexport structs
|
||||
if (current is UhtScriptStruct scriptStruct)
|
||||
{
|
||||
if (scriptStruct.ScriptStructFlags.HasAnyFlags(EStructFlags.Native))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// these are a special cases that already exists and if wrong if exported naively
|
||||
if (!scriptStruct.IsAlwaysAccessible)
|
||||
{
|
||||
outScriptStructs.Remove(scriptStruct);
|
||||
outScriptStructs.Add(scriptStruct);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (UhtType type in current.Children)
|
||||
{
|
||||
if (type is UhtProperty property)
|
||||
{
|
||||
foreach (UhtType referenceType in property.EnumerateReferencedTypes())
|
||||
{
|
||||
if (referenceType is UhtScriptStruct propertyScriptStruct)
|
||||
{
|
||||
FindNoExportStructsRecursive(outScriptStructs, propertyScriptStruct);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@@ -0,0 +1,32 @@
|
||||
# IsCoreType
|
||||
|
||||
- **功能描述:** 指定该结构是核心类,UHT在用它的时候不需要前向声明。
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** UHT
|
||||
- **限制类型:** 只在NoExportTypes.h供UHT使用
|
||||
- **常用程度:** 0
|
||||
|
||||
指定该结构是核心类,UHT在用它的时候不需要前向声明。
|
||||
|
||||
## 原理:
|
||||
|
||||
看UHT源码是把struct用在参数或属性等被引用的时候。
|
||||
|
||||
```cpp
|
||||
public override string? UhtStructProperty::GetForwardDeclarations()
|
||||
{
|
||||
if (ScriptStruct.IsCoreType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (TemplateWrapper != null)
|
||||
{
|
||||
StringBuilder builder = new();
|
||||
TemplateWrapper.AppendForwardDeclarations(builder);
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
return $"struct {ScriptStruct.SourceName};";
|
||||
}
|
||||
```
|
@@ -0,0 +1,158 @@
|
||||
# NoExport
|
||||
|
||||
- **功能描述:** 指定UHT不要用来自动生成注册的代码,而只是进行词法分析提取元数据。
|
||||
- **元数据类型:** bool
|
||||
- **引擎模块:** UHT
|
||||
- **常用程度:★**
|
||||
|
||||
指定UHT不要用来自动生成注册的代码,而只是进行词法分析提取元数据。
|
||||
|
||||
NoExportTypes.h里使用了很多该例子。定义的结构常常用!CPP宏包起来以不在C++中参与编译。因此一般是只给引擎内部使用的。
|
||||
|
||||
实际上我们想使用也可以,只要保持C++中内存布局一样,就可以自己多定义。使用场景:想自己定义一个UHT头喂给UHT分析,然后自己在别处定义实际的C++。一种典型用途是C++里的实际多个类继承于一个模板基类,如FVector2MaterialInput,这样可以每个特化子类定一个UHT类型别名。另一种目的是把UHT要分析的头文件都放在一个文件里,加速UHT分析生成,不用分析多个文件,反正只要UHT信息和内存布局对就行。
|
||||
|
||||
```cpp
|
||||
#if !CPP // begin noexport class
|
||||
USTRUCT(noexport, BlueprintType) //如果不写noexport,会报错:Expected a GENERATED_BODY() at the start of the struct、
|
||||
struct FFloatRK4SpringInterpolator
|
||||
{
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "FloatRK4SpringInterpolator")
|
||||
float StiffnessConstant;
|
||||
|
||||
/** 0 = Undamped, <1 = Underdamped, 1 = Critically damped, >1 = Over damped */
|
||||
UPROPERTY(EditAnywhere, Category = "FloatRK4SpringInterpolator")
|
||||
float DampeningRatio;
|
||||
|
||||
bool bIsInitialized;
|
||||
bool bIsInMotion;
|
||||
float TimeRemaining;
|
||||
FRK4SpringConstants SpringConstants;
|
||||
|
||||
float LastPosition;
|
||||
RK4Integrator::FRK4State<float> State;
|
||||
};
|
||||
#endif // end noexport class
|
||||
|
||||
//实际应用:
|
||||
template <typename T>
|
||||
struct FRK4SpringInterpolator
|
||||
{
|
||||
protected:
|
||||
float StiffnessConstant;
|
||||
float DampeningRatio;
|
||||
|
||||
bool bIsInitialized;
|
||||
bool bIsInMotion;
|
||||
float TimeRemaining;
|
||||
FRK4SpringConstants SpringConstants;
|
||||
|
||||
T LastPosition;
|
||||
RK4Integrator::FRK4State<T> State;
|
||||
}
|
||||
|
||||
struct FFloatRK4SpringInterpolator : FRK4SpringInterpolator<float>
|
||||
struct FVectorRK4SpringInterpolator : FRK4SpringInterpolator<FVector>
|
||||
```
|
||||
|
||||
不生成的代码包括:
|
||||
|
||||
```cpp
|
||||
USTRUCT(BlueprintType,noexport)
|
||||
struct INSIDER_API FMyStruct_NoExport
|
||||
{
|
||||
//抑制:GENERATED_BODY()解释生成的:
|
||||
//static class UScriptStruct* StaticStruct();
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
float Score;
|
||||
};
|
||||
|
||||
//抑制:
|
||||
//template<> INSIDER_API UScriptStruct* StaticStruct<struct FMyStruct_NoExport>();
|
||||
```
|
||||
|
||||
.h里不会生成,因此不会在别的模块里使用
|
||||
|
||||
```cpp
|
||||
template<> INSIDER_API UScriptStruct* StaticStruct<struct FMyStruct_NoExport>();
|
||||
```
|
||||
|
||||
但是依然会在Module.init.gen.cpp里生成Z_Construct_UScriptStruct_FMyStruct_NoExport的调用,因此还是会在蓝图里暴露出来。
|
||||
|
||||
```cpp
|
||||
#include "UObject/GeneratedCppIncludes.h"
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
void EmptyLinkFunctionForGeneratedCodeInsider_init() {}
|
||||
INSIDER_API UScriptStruct* Z_Construct_UScriptStruct_FMyStruct_NoExport();
|
||||
static FPackageRegistrationInfo Z_Registration_Info_UPackage__Script_Insider;
|
||||
FORCENOINLINE UPackage* Z_Construct_UPackage__Script_Insider()
|
||||
{
|
||||
if (!Z_Registration_Info_UPackage__Script_Insider.OuterSingleton)
|
||||
{
|
||||
static UObject* (*const SingletonFuncArray[])() = {
|
||||
(UObject* (*)())Z_Construct_UScriptStruct_FMyStruct_NoExport,//这里注入调用
|
||||
};
|
||||
static const UECodeGen_Private::FPackageParams PackageParams = {
|
||||
"/Script/Insider",
|
||||
SingletonFuncArray,
|
||||
UE_ARRAY_COUNT(SingletonFuncArray),
|
||||
PKG_CompiledIn | 0x00000000,
|
||||
0x02A7B98C,
|
||||
0xFA17C3C4,
|
||||
METADATA_PARAMS(0, nullptr)
|
||||
};
|
||||
UECodeGen_Private::ConstructUPackage(Z_Registration_Info_UPackage__Script_Insider.OuterSingleton, PackageParams);
|
||||
}
|
||||
return Z_Registration_Info_UPackage__Script_Insider.OuterSingleton;
|
||||
}
|
||||
static FRegisterCompiledInInfo Z_CompiledInDeferPackage_UPackage__Script_Insider(Z_Construct_UPackage__Script_Insider, TEXT("/Script/Insider"), Z_Registration_Info_UPackage__Script_Insider, CONSTRUCT_RELOAD_VERSION_INFO(FPackageReloadVersionInfo, 0x02A7B98C, 0xFA17C3C4));
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
```
|
||||
|
||||
蓝图里的效果:依然可以当作变量。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
加上noexport的区别是不能用StaticStruct和没了TCppStructOps,不能做一些优化。其他还是可以正常使用,就像FVector一样。
|
||||
|
||||
缺失的代码,也可以通过手动添加代码来获得。
|
||||
|
||||
```cpp
|
||||
USTRUCT(BlueprintType,noexport)
|
||||
struct INSIDER_API FMyStruct_NoExport
|
||||
{
|
||||
//GENERATED_BODY() //missing type specifier - int assumed,..generated.h里只是定一个StaticStruct()函数
|
||||
|
||||
static class UScriptStruct* StaticStruct(); //可以自己定义
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere)
|
||||
float Score;
|
||||
|
||||
};
|
||||
|
||||
template<> INSIDER_API UScriptStruct* StaticStruct<struct FMyStruct_NoExport>();//可以自己定义
|
||||
|
||||
//.cpp
|
||||
//链入函数声明,在其他的cpp里已经有实现,所以可以正常调用到
|
||||
INSIDER_API UScriptStruct* Z_Construct_UScriptStruct_FMyStruct_NoExport();
|
||||
UPackage* Z_Construct_UPackage__Script_Insider();
|
||||
|
||||
static FStructRegistrationInfo Z_Registration_Info_UScriptStruct_MyStruct_NoExport;
|
||||
|
||||
class UScriptStruct* FMyStruct_NoExport::StaticStruct()
|
||||
{
|
||||
if (!Z_Registration_Info_UScriptStruct_MyStruct_NoExport.OuterSingleton)
|
||||
{
|
||||
Z_Registration_Info_UScriptStruct_MyStruct_NoExport.OuterSingleton = GetStaticStruct(Z_Construct_UScriptStruct_FMyStruct_NoExport, Z_Construct_UPackage__Script_Insider(), TEXT("MyStruct_NoExport"));
|
||||
}
|
||||
return Z_Registration_Info_UScriptStruct_MyStruct_NoExport.OuterSingleton;
|
||||
}
|
||||
|
||||
template<> INSIDER_API UScriptStruct* StaticStruct<FMyStruct_NoExport>()
|
||||
{
|
||||
return FMyStruct_NoExport::StaticStruct();
|
||||
}
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Reference in New Issue
Block a user