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,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变量。
![Untitled](Untitled.png)
源码里可以找到:
```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()))
```

View File

@@ -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;
}
```

View File

@@ -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;
};
```
## 测试蓝图:
![Untitled](Untitled.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -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
```

View File

@@ -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总是会把所有的属性都序列化出来。
![Untitled](Untitled.png)
## 原理:
作用的机理是一个外部结构是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

View File

@@ -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;
}
}
}
}
}
```

View File

@@ -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;
}
```

View File

@@ -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);
}
}
}
}
}
}
```

View File

@@ -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};";
}
```

View File

@@ -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
```
蓝图里的效果:依然可以当作变量。
![Untitled](Untitled.png)
![Untitled](Untitled%201.png)
加上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