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,14 @@
# CustomConstructor
- **功能描述:** 阻止构造函数声明自动生成。
- **引擎模块:** UHT
- **元数据类型:** bool
- **作用机制:** 在ClassFlags中添加[CLASS_CustomConstructor](../../../Flags/EClassFlags/CLASS_CustomConstructor.md)
UHT不会生成 NO_API UMyClass_ModuleAPI(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());的默认构造函数。但是这个一般都是配合GENERATED_UCLASS_BODY使用的因为GENERATED_BODY会自动生成默认构造函数。一般在自己需要自定义这个函数的时候使用。但其实用GENERATED_BODY也行
当前已经弃用:
```cpp
CLASS_CustomConstructor UE_DEPRECATED(5.1, "CLASS_CustomConstructor should no longer be used. It is no longer being set by engine code.") = 0x00008000u,
```

View File

@@ -0,0 +1,56 @@
# CustomFieldNotify
- **功能描述:** 阻止UHT为该类生成FieldNotify的相关代码。
- **引擎模块:** UHT
- **元数据类型:** bool
- **作用机制:** 在ClassFlags中增加[HasCustomFieldNotify](../../../Flags/EClassFlags/HasCustomFieldNotify.md)
- **常用程度:** 0
阻止UHT为该类生成FieldNotify的相关代码。
在源码里只在UWidget上使用例如该类里面的bIsEnabled是FieldNotify正常来说UHT要为其生成代码。但如果该类想自己手动书写这些UHT代码则可以加上CustomFieldNotify来阻止UHT生成。UWidget的cpp里因为要用别的方式UE_FIELD_NOTIFICATION_IMPLEMENT_CLASS_DESCRIPTOR因此要拒绝UHT生成。
如果自己的类也要自己UE_FIELD_NOTIFICATION_IMPLEMENT_CLASS_DESCRIPTOR则可以用上CustomFieldNotify。
## 源码例子:
```cpp
//E:\P4V\Engine\Source\Runtime\UMG\Public\FieldNotification\FieldNotificationDeclaration.h
UCLASS(Abstract, BlueprintType, Blueprintable, CustomFieldNotify)
class UMG_API UWidget : public UVisual, public INotifyFieldValueChanged
{
GENERATED_UCLASS_BODY()
public:
UE_FIELD_NOTIFICATION_DECLARE_CLASS_DESCRIPTOR_BASE_BEGIN(UMG_API)
UE_FIELD_NOTIFICATION_DECLARE_FIELD(ToolTipText)
UE_FIELD_NOTIFICATION_DECLARE_FIELD(Visibility)
UE_FIELD_NOTIFICATION_DECLARE_FIELD(bIsEnabled)
UE_FIELD_NOTIFICATION_DECLARE_ENUM_FIELD_BEGIN(ToolTipText)
UE_FIELD_NOTIFICATION_DECLARE_ENUM_FIELD(Visibility)
UE_FIELD_NOTIFICATION_DECLARE_ENUM_FIELD(bIsEnabled)
UE_FIELD_NOTIFICATION_DECLARE_ENUM_FIELD_END()
UE_FIELD_NOTIFICATION_DECLARE_CLASS_DESCRIPTOR_BASE_END();
UPROPERTY(EditAnywhere, BlueprintReadWrite, FieldNotify, Getter="GetIsEnabled", Setter="SetIsEnabled", BlueprintGetter="GetIsEnabled", BlueprintSetter="SetIsEnabled", Category="Behavior")
uint8 bIsEnabled:1;
//cpp
UE_FIELD_NOTIFICATION_IMPLEMENT_CLASS_DESCRIPTOR_ThreeFields(UWidget, ToolTipText, Visibility, bIsEnabled);
```
## 原理:
在判断条件上可见HasCustomFieldNotify的判断。
```cpp
protected static bool NeedFieldNotifyCodeGen(UhtClass classObj)
{
return
!classObj.ClassExportFlags.HasAnyFlags(UhtClassExportFlags.HasCustomFieldNotify) &&
classObj.ClassExportFlags.HasAnyFlags(UhtClassExportFlags.HasFieldNotify);
}
```

View File

@@ -0,0 +1,8 @@
# CustomThunkTemplates
- **功能描述:** Specifies the struct that contains the CustomThunk implementations
- **引擎模块:** UHT
- **元数据类型:** bool
在源码里找不到引用的地方

View File

@@ -0,0 +1,34 @@
# Interface
- **功能描述:** 标识这个Class是个Interface。
- **引擎模块:** UHT
- **元数据类型:** bool
- **作用机制:** 在ClassFlags中添加[CLASS_Interface](../../../Flags/EClassFlags/CLASS_Interface.md)
- **常用程度:** 0
标识这个Class是个Interface。
只用在NoExportTypes.h中我们自己的UInterface不需要手动设置。
是UHT在为UInterface生成的时候设置在.generated.h里的。
## 源码例子:
```cpp
UCLASS(abstract, noexport, intrinsic, interface, Config = Engine)
class UInterface : public UObject
{}
```
## 原理:
```cpp
bool FKismetEditorUtilities::IsClassABlueprintInterface(const UClass* Class)
{
if (Class->HasAnyClassFlags(CLASS_Interface) && !Class->HasAnyClassFlags(CLASS_NewerVersionExists))
{
return true;
}
return false;
}
```

View File

@@ -0,0 +1,36 @@
# Intrinsic
- **功能描述:** 指定UHT完全不为此类生成代码需要自己手写。
- **引擎模块:** UHT
- **元数据类型:** bool
- **作用机制:** 在ClassFlags中增加[CLASS_Intrinsic](../../../Flags/EClassFlags/CLASS_Intrinsic.md)
- **常用程度:** 0
指定UHT完全不为此类生成代码需要自己手写。
只在C++直接设定一般新类不设定这个标记这个的都是UE4内部原生的那些类相当于已经在源码中手写了元数据代码。
noexport至少还会解析生成元数据只是缺少注册。因此instric类的所有元数据flags要自己手动标记。但是intrinsic完全不生成代码。其generated.h和.gen.cpp里面都是空的。noexporttyps.h里的目前采用intrinsic的类只有UCLASS(noexport, Intrinsic)class UModel{}这还是被cpp不编译的。
```cpp
//UCLASS(Intrinsic)
//class INSIDER_API UMyClass_Intrinsic :public UObject //syntax error: missing ';' before '<class-head>'
//{
// GENERATED_BODY()
//
//};
//.h
class INSIDER_API UMyClass_Intrinsic :public UObject
{
DECLARE_CLASS_INTRINSIC(UMyClass_Intrinsic, UObject, CLASS_MatchedSerializers, TEXT("/Script/Insider"))
};
//.cpp
IMPLEMENT_INTRINSIC_CLASS(UMyClass_Intrinsic, INSIDER_API, UObject, INSIDER_API, "/Script/Insider", {})
class COREUOBJECT_API UInterface : public UObject
{
DECLARE_CLASS_INTRINSIC(UInterface, UObject, CLASS_Interface | CLASS_Abstract, TEXT("/Script/CoreUObject"))
};
```

View File

@@ -0,0 +1,132 @@
# MinimalAPI
- **功能描述:** 不dll导出该类的函数只导出类型信息当作变量。
- **引擎模块:** DllExport
- **元数据类型:** bool
- **作用机制:** 在ClassFlags增加[CLASS_MinimalAPI](../../../../Flags/EClassFlags/CLASS_MinimalAPI.md)
- **常用程度:** ★★★
不dll导出该类的函数只导出类型信息当作变量。
- 其他引用的模块可以利用指针来做转换,但是不能调用上面的函数。但是蓝图里依然可以访问。
- 好处是可以缩短编译信息和加快链接速度因为没有了那么多dllexport函数。
- 注意MinimalAPI不能和MODULENAME_API一起使用因为MinimalAPI就是用来不导出的而MODULENAME_API就是用来导出的。但是MinimalAPI的效果并不等价于不写MODULENAME_API的效果因为MinimalAPI还会导出GetPrivateStaticClass用来允许NewObject。所以如果一个类完全不想让另一个模块知道则不需要写任何导出。而如果想让另一个模块知道类型但是完全不能调用函数则可以用MinimalAPI来防止。
- 游戏的模块推荐不导出。插件的模块外部的推荐导出内部的基类可以考虑MinimalAPI私有类则可以完全不导出。引擎里使用MinimalAPI还是非常多的生成的效果是这些类可以作为变量使用但不能继承和调用方法。
- 一般是配合BlueprintType使用这样就可以在蓝图中作为变量。
- 可以正常在蓝图中调用函数和属性。因为蓝图调用是只需要反射信息就可以的,因为是自己模块把函数和属性的指针注册到系统里。
## 示例代码:
```cpp
UCLASS()
class UMyClass_NotMinimalAPI :public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 MyProperty;
UFUNCTION(BlueprintCallable)
void MyFunc();
};
UCLASS(MinimalAPI)
class UMyClass_MinimalAPI :public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 MyProperty;
UFUNCTION(BlueprintCallable)
void MyFunc();
};
UCLASS(MinimalAPI, BlueprintType)
class UMyClass_MinimalAPI_BlueprintType :public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 MyProperty;
UFUNCTION(BlueprintCallable)
void MyFunc() {}
};
UCLASS(MinimalAPI)
class UMyClass_MinimalAPI_BlueprintFunctionLibary :public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
static void MyFuncInMinimalAPI();
UFUNCTION(BlueprintCallable)
static INSIDER_API void MyFuncInMinimalAPIWithAPI();
};
```
## 示例效果:
可以正常在蓝图中调用函数和属性。蓝图函数库中的方法也可以调用说明UHT对MinimalAPI还是依然生成反射的调用信息的蓝图调用是只需要反射信息就可以的因为是自己模块把函数和属性的指针注册到系统里因此并不需要dll导出。只不过在dll导出工具里查看dll导出的函数列表并没有该函数。
![Untitled](Untitled.png)
查看dll导出函数列表
```cpp
class UClass * __ptr64 __cdecl StaticClass<class UMyClass_MinimalAPI>(void)
class UClass * __ptr64 __cdecl StaticClass<class UMyClass_MinimalAPI_BlueprintFunctionLibary>(void)
class UClass * __ptr64 __cdecl StaticClass<class UMyClass_MinimalAPI_BlueprintType>(void)
class UClass * __ptr64 __cdecl StaticClass<class UMyClass_NotMinimalAPI>(void)
class UClass * __ptr64 __cdecl Z_Construct_UClass_UMyClass_MinimalAPI(void)
class UClass * __ptr64 __cdecl Z_Construct_UClass_UMyClass_MinimalAPI_BlueprintFunctionLibary(void)
class UClass * __ptr64 __cdecl Z_Construct_UClass_UMyClass_MinimalAPI_BlueprintFunctionLibary_NoRegister(void)
class UClass * __ptr64 __cdecl Z_Construct_UClass_UMyClass_MinimalAPI_BlueprintType(void)
class UClass * __ptr64 __cdecl Z_Construct_UClass_UMyClass_MinimalAPI_BlueprintType_NoRegister(void)
class UClass * __ptr64 __cdecl Z_Construct_UClass_UMyClass_MinimalAPI_NoRegister(void)
class UClass * __ptr64 __cdecl Z_Construct_UClass_UMyClass_NotMinimalAPI(void)
class UClass * __ptr64 __cdecl Z_Construct_UClass_UMyClass_NotMinimalAPI_NoRegister(void)
private: static class UClass * __ptr64 __cdecl UMyClass_MinimalAPI::GetPrivateStaticClass(void)
private: static class UClass * __ptr64 __cdecl UMyClass_MinimalAPI_BlueprintFunctionLibary::GetPrivateStaticClass(void)
private: static class UClass * __ptr64 __cdecl UMyClass_MinimalAPI_BlueprintType::GetPrivateStaticClass(void)
public: __cdecl UMyClass_MinimalAPI::UMyClass_MinimalAPI(class FObjectInitializer const & __ptr64) __ptr64
public: __cdecl UMyClass_MinimalAPI::UMyClass_MinimalAPI(class FVTableHelper & __ptr64) __ptr64
public: __cdecl UMyClass_MinimalAPI_BlueprintFunctionLibary::UMyClass_MinimalAPI_BlueprintFunctionLibary(class FObjectInitializer const & __ptr64) __ptr64
public: __cdecl UMyClass_MinimalAPI_BlueprintFunctionLibary::UMyClass_MinimalAPI_BlueprintFunctionLibary(class FVTableHelper & __ptr64) __ptr64
public: __cdecl UMyClass_MinimalAPI_BlueprintType::UMyClass_MinimalAPI_BlueprintType(class FObjectInitializer const & __ptr64) __ptr64
public: __cdecl UMyClass_MinimalAPI_BlueprintType::UMyClass_MinimalAPI_BlueprintType(class FVTableHelper & __ptr64) __ptr64
public: static void __cdecl UMyClass_MinimalAPI_BlueprintFunctionLibary::MyFuncInMinimalAPIWithAPI(void)
public: virtual __cdecl UMyClass_MinimalAPI::~UMyClass_MinimalAPI(void) __ptr64
public: virtual __cdecl UMyClass_MinimalAPI_BlueprintFunctionLibary::~UMyClass_MinimalAPI_BlueprintFunctionLibary(void) __ptr64
public: virtual __cdecl UMyClass_MinimalAPI_BlueprintType::~UMyClass_MinimalAPI_BlueprintType(void) __ptr64
public: void __cdecl UMyClass_MinimalAPI::`default constructor closure'(void) __ptr64
public: void __cdecl UMyClass_MinimalAPI_BlueprintFunctionLibary::`default constructor closure'(void) __ptr64
public: void __cdecl UMyClass_MinimalAPI_BlueprintType::`default constructor closure'(void) __ptr64
```
![Untitled](Untitled%201.png)
在跨模块调用的时候因为没有dll导出因此会触发链接错误。
```cpp
UMyClass_MinimalAPI* a = NewObject<UMyClass_MinimalAPI>();
//第一种错误
//error LNK2019: unresolved external symbol "public: void __cdecl UMyClass_MinimalAPI::MyFunc(void)" (?MyFunc@UMyClass_MinimalAPI@@QEAAXXZ) referenced in function "public: void __cdecl UMyClass_UseMinimalAPI::TestFunc(void)" (?TestFunc@UMyClass_UseMinimalAPI@@QEAAXXZ)
//a->MyFunc();
a->MyProperty++;
//第二种错误
//error LNK2019: unresolved external symbol "private: static class UClass * __cdecl UMyClass_NotMinimalAPI::GetPrivateStaticClass(void)" (?GetPrivateStaticClass@UMyClass_NotMinimalAPI@@CAPEAVUClass@@XZ)
//referenced in function "class UMyClass_NotMinimalAPI * __cdecl NewObject<class UMyClass_NotMinimalAPI>(class UObject *)" (??$NewObject@VUMyClass_NotMinimalAPI@@@@YAPEAVUMyClass_NotMinimalAPI@@PEAVUObject@@@Z)
auto* a = NewObject<UMyClass_NotMinimalAPI>();
//第三种错误
//error LNK2019: unresolved external symbol "public: static void __cdecl UMyClass_MinimalAPI_BlueprintFunctionLibary::MyFuncInMinimalAPI(void)" (?MyFuncInMinimalAPI@UMyClass_MinimalAPI_BlueprintFunctionLibary@@SAXXZ)
//referenced in function "public: void __cdecl UMyClass_UseMinimalAPI::TestFunc(void)" (?TestFunc@UMyClass_UseMinimalAPI@@QEAAXXZ)
UMyClass_MinimalAPI_BlueprintFunctionLibary::MyFuncInMinimalAPI();
UMyClass_MinimalAPI_BlueprintFunctionLibary::MyFuncInMinimalAPIWithAPI();
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -0,0 +1,32 @@
# NoExport
- **功能描述:** 指定UHT不要用来自动生成注册的代码而只是进行词法分析提取元数据。
- **引擎模块:** UHT
- **元数据类型:** bool
- **作用机制:** 在ClassFlags中增加EClassFlags: [CLASS_NoExport](../../../Flags/EClassFlags/CLASS_NoExport.md)
- **常用程度:** 0
指定UHT不要用来自动生成注册的代码而只是进行词法分析提取元数据。
引擎的NoExportTypes.h里大量都是这种类型专门提供给UHT来提取信息的。一般会用#if !CPP //noexport class来包裹来避免编译。同时在另一个地方会定义这个类。因为StaticRegisterNatives##TClass没有生成所以GetPrivateStaticClass不能调用成功所以不能NewObject。一般noexport和Intrinsic都是配合使用的。因为DECLARE_CLASS_INTRINSIC内部会声明static void StaticRegisterNatives##TClass() {} 来允许成功调用。
引擎里的结构倒是经常用noexport来阻止生成UHT注册。因为结构其实不需要调用GetPrivateStaticClass来创建元数据。只要有Z_Construct_UScriptStruct_XXX来生成构造相应的UScriptStruct对象就行。
## 测试代码:
```cpp
UCLASS(noexport)
class INSIDER_API UMyClass_NoExport :public UObject
{
GENERATED_BODY()
public:
};
```
## 测试结果:
```cpp
编译的时候生成错误:
error LNK2019: unresolved external symbol "private: static void __cdecl UMyClass_NoExport::StaticRegisterNativesUMyClass_NoExport(void)" (?StaticRegisterNativesUMyClass_NoExport@UMyClass_NoExport@@CAXXZ) referenced in function "private: static class UClass * __cdecl UMyClass_NoExport::GetPrivateStaticClass(void)" (?GetPrivateStaticClass@UMyClass_NoExport@@CAPEAVUClass@@XZ)
```

View File

@@ -0,0 +1,37 @@
# UCLASS()
- **功能描述:** 留空的默认行为是不能在蓝图中被继承,不能在蓝图中定义变量,但拥有反射的功能。
- **引擎模块:** UHT
- **元数据类型:** bool
- **作用机制:** 在ClassFlags中增加[CLASS_MatchedSerializers](../../../Flags/EClassFlags/CLASS_MatchedSerializers.md), [CLASS_Native](../../../Flags/EClassFlags/CLASS_Native.md), [CLASS_RequiredAPI](../../../Flags/EClassFlags/CLASS_RequiredAPI.md), [CLASS_TokenStreamAssembled](../../../Flags/EClassFlags/CLASS_TokenStreamAssembled.md), [CLASS_Intrinsic](../../../Flags/EClassFlags/CLASS_Intrinsic.md), [CLASS_Constructed](../../../Flags/EClassFlags/CLASS_Constructed.md)
- **关联项:** [不写UCLASS()](不写UCLASS().md)
- **常用程度:★★★★★**
不能在蓝图中被继承,不能在蓝图中定义变量。
但依然都可以通过蓝图ConstructObject创建出来。对于想要拥有反射功能但是并不想在蓝图中被使用会挺适合。
## 示例代码:
```cpp
/*
[MyClass_Default Class->Struct->Field->Object /Script/Insider.MyClass_Default] [IncludePath = Class/MyClass_Default.h, ModuleRelativePath = Class/MyClass_Default.h]
ObjectFlags: RF_Public | RF_Standalone | RF_Transient
Outer: Package /Script/Insider
ClassFlags: CLASS_MatchedSerializers | CLASS_Native | CLASS_RequiredAPI | CLASS_TokenStreamAssembled | CLASS_Intrinsic | CLASS_Constructed
Size: 48
{
public: void ExecuteUbergraph(int32 EntryPoint);
};
*/
UCLASS()
class INSIDER_API UMyClass_Default :public UObject
{
GENERATED_BODY()
public:
};
```
默认的拥有这些标志CLASS_MatchedSerializers | CLASS_Native | CLASS_RequiredAPI | CLASS_TokenStreamAssembled | CLASS_Intrinsic | CLASS_Constructed

View File

@@ -0,0 +1,21 @@
# 不写UCLASS()
- **功能描述:** 只是作为一个普通的C++对象,没有反射功能。
- **引擎模块:** UHT
- **元数据类型:** bool
- **关联项:** [UCLASS()](UCLASS().md)
- **常用程度:** ★
只是作为一个普通的C++对象,没有反射功能。
一般情况继承自UObject的最少也会有一个UCLASS()这样才有反射功能。但是注意如果调用UMyClass_NoUCLASS::StaticClass()会返回基类UObject的Class因为子类没有覆盖。因此也可以说本类是没有生成自己的UClass元数据对象。
```cpp
class INSIDER_API UMyClass_NoUCLASS :public UObject
{
};
```
UObject的Class默认的标记是CLASS_Abstract | CLASS_MatchedSerializers | CLASS_Native | CLASS_TokenStreamAssembled | CLASS_Intrinsic | CLASS_Constructed。因此不能被NewObject生成对象。在手动去掉CLASS_Abstract后可以正常new但是对象的名称依然是Object显然这是因为使用的就是Object的Class。