Bootstrap

添加class值_UE4 UObject反射系列(三) Class相关

前言

  • 文章之后会修改.
    最近一些文章互相关联性较高, 可能随着某篇文章某些内容的深扒, 而导致一些内容更连贯, 并对所有相关内容进行修改
  • 源码版本4.22

大钊:《InsideUE4》UObject(六)类型系统代码生成重构-UE4CodeGen_Private

在前面的文章中,我们对一个空UObject类进行了一系列的分析, 那么如果不是空类呢?

这就是这篇文章的内容了,内容较多且繁杂, 如果前面掌握不太好,那就回去复习!

同时内容较多, 受限于篇幅, 可能会省略掉很多对比等实际操作.

请根据步骤一步一步跟做, 不保证教会, 但保证看懂。


属性篇 第一节

f7a0461989045dd7ab1e07476ac291b9.png

添加一个float的成员变量, 重新生成项目, 然后与空类(UGAObject01)generated.h和generated.cpp进行对比。

// 后文简称与头文件(generated.h)或者实现文件(generated.cpp)

没有发现任何显著变化, 可以认为无变化。


属性篇 第二节

21e261b0f90fe08385cf199e7dbbc724.png

添加U宏标记, 与空类对比, 进行同样的步骤。

与头文件对比, 无明显变化

与实现文件相比, Z_Construct_UClass_UGAObject05_Statics这个反射信息结构体发生很大的变化

74ff56652679ba1bee52093a7fd6598a.png
  • NewProp_TestFloatValue_MetaData

71eb11b9dfb1e038cea5c510392a66ef.png

名称直译, 新的属性_属性名称_元数据

这里是收集属性对应的元数据

  • NewProp_TestFloatValue

7c0ce36bf5b1af46f6f32c3364186f43.png

从数据上看, 可以轻易的出, 这是这个属性对应的反射信息

7cc33f1654539a29187b8567a0bbff96.png

跳一下结构体, 可以看到是FGenericPropertyParam这个结构体

2f0605675c958d4baf1a6997a6ba489a.png

属性值一一对应

这里只分析部分, 一些内容等用到的时候再分析.

NameUTF8 : 属性名称

PropertyFlags : 这个属性(EPropertyFlags)0x0010000000000000, 值实际是CPF_NativeAccessSpecifierPublic

Flags : 这个属性标记类属性的类别, 是个枚举, 这里是float

总共有下列这么多情况, 也就是说下面这些是所有可以加U宏的属性类型

6cd86d07624683cd8230c7fc8baa3e88.png
  • PropPointers

3396d82dd09b8763efff8b9cfece2072.png

88e644b2ede491de4d6efb0b2df862c4.png

可以看到是一个FPropertyParamsBase指针数组, 存储多个反射参数信息的指针

参考注释内容, FPropertyParamsBase只是规定了常见初始序列, 及前几个内容是这几个属性, 其他的多多少少, 会根据不同情况, 做一些拓展.

FPropertyParamsBaseWithOffset在FPropertyParamsBase的基础上多了属性偏移一个int32值

FGenericPropertyParams又在FPropertyParamsBaseWithOffset的基础上多了元数据信息

所以, 存储一个最基础信息的数据, 根据EPropertyGenFlags获得实际的类型, 就能生成对应的变量信息

上述内容就可以得到属性的反射信息, 那么怎么管理到Class上面呢?

ee803b57922782bf845dd6df66844fb4.png

如上, 传入Class反射参数一个属性反射信息数组和相应数量

至此, 这个float值, 反射信息就被记录并可以合理生成了.


属性篇 第三节

c162da05ac8aab74dafb431d3d1814be.png

我们进一步添加一些信息, BlueprintReadOnly, EditAnywhere, Catergory = "Test"

再和刚才的UGAObject05进行对比

0824280ae35c94753f25bc50767fffcf.png

元数据添加了一个Category

c9d76e4fcafef029d3d182a58f750cd0.png

PropertyFlags值发生了变化

bd032defffd032d35a15cc083742ad04.png

拆分可得, 多了CPF_BlueprintReadOnly | CPF_BlueprintVisible | CPF_Edit


属性篇 第四节

55d16693948b016aa2ca6bbcf0a20bba.png

再加上一个Replicated标记呢?

fd51db794b8c3f0172406eb02be08110.png

头文件会添加GetLifetimeReplicatedProps的override声明

// 这也是那个常见错误, 标记属性同步之后, 编译报错, GetLifetimeReplicatedProps函数没有定义的原因

PropertyFlags值发生了变化, 多了CPF_Net

29c11099e878bcde307fa7aba398625f.png

4ed419559d9b684cb10296264aa2e3b5.png

属性篇 第五节

acdd68d33d78b5eb09e77f342ecf4b40.png

修改同步方式为ReplicatedUsing, 与UGAObject07进行对比

dfed4a7646ee4b4149290705133059f0.png

可以看到此处RepNotifyFuncUTF8不在为空,为对应的函数名称

PropertyFlags值发生了变化, 多了CPF_RepNotify

fd340eead378c484f96988f5ba77ad91.png

那些UFunction相关的就之后再说了


属性篇 第六节

前文分析的都是单一float, 下文会开始分析一些数据类型

fe5a4b0cc96b6ec5cd8c63eefcdd4b89.png

6a9d838fa8f18425cd3055b51f5418cd.png

4367951221be236fcb8f45ccac32c0ea.png

与float类型, 只是换了一下类型

6fef3ee72fb8aa4bd7973276f59ed923.png

1143adbc8bff9163e1a48730e8ae7d48.png

84736ddfdc8365f0b54f999a1f84162f.png

760ff9ad5bfa3d9533a6cd61cfab14cf.png

810a1b8f2d975dbd8666005ea1a9e1b6.png

等等, 可以看出这些基本都是相同的.


属性篇 第七节

6e86cda438961618f7e5651b63a61804.png

d373aadd59170caf336e9d3f928c1a24.png

bool值的实现与float, int相比有些特殊, 感觉是因为内存对齐的问题导致的

求大佬指导


属性篇 第八节

bcda79496d3fd4e51fa689e35edad944.png

946c46476aeff8dd105616768a7bed1b.png

18d6508a88063db9c671564a6733892d.png

4d6624de68ea4526e4dee251465cb437.png

7d73d44f43457544d5c1a61628d0f3b3.png

d2290959a8472f8859844677bf4b479a.png

5ffb6aa430cc3c6b13be5cd61dd81d78.png

对比可以看到, FString,FName, FText实现和float, int类似


属性篇 第九节

8e5a010d71cc82bb4a94e0e3e27efe19.png

95daa9c182fc0b3933527224b59627f6.png

b4994a156632818accff311715278ea8.png

看一下AActor的呢, 发现多了一个指针, 联系前文, 是不是很熟悉?

是一个构造AActor对应UClass的一个函数, 详情见之后的COD

以及PropertyFlags值发生了变化, 多了CPF_UObjectWrapper

518f0249eac088e7bf51284f17f3910b.png

2de24c13f80989c750df959a2e71c43e.png

e9caa1f3be323bdc1a00bc9bb14cf5cf.png

3e3398473139bbe4b7cd9f19aee56438.png

667e8a52f6b618d89a9b5ac756a330ed.png

bb97f2991a780307ec200f2ff67389f6.png

可以看到, WeakObject和SoftObject的基本类似.


属性篇 第十节

e4e97a8df05194f18f683fb6d8a73392.png

2752781f5ceea0761117b051e0630f67.png

TSubclassOf<>相比AActor属性相关多了一个Z_Construct_UClass_UClass函数指针, 预计是这里依赖到了UClass, 所以要获得其构造函数, 提前调用

4d980c0c8f9daa6aac99fbcbb855ef80.png

17f5fa767494b9f9453052ce2890b4ee.png

TSoftClassPtr<>相比又不一样

统一比较一下

  • struct FObjectPropertyParams
    UClass* (*ClassFunc)();
  • struct FClassPropertyParams
    UClass* (*MetaClassFunc)();
    UClass* (*ClassFunc)();
  • struct FSoftClassPropertyParams
    UClass* (*MetaClassFunc)();

具体区别在哪里? 可能在之后会有分析吧.


属性篇 第十一节

75d5b0a01c4ac6a7a5fb41feb3a916d0.png

28bb0b5fb560e9b44377a0c16b2a0d7f.png

忽略调枚举本身的反射, 之后分析

枚举的处理就有些看不懂了, 相比前面属性的处理, 枚举这里有两个结构体信息

070d78cc2ef1a94c4438dc58795eab55.png

这是正常的反射信息, 函数指针是枚举对应对枚举UEnum的构建函数

70ca2e5b6f9ac83599335317b9c969a7.png

这个,,, 由于ArrayDim两者相同, 所以可以对应到一起, 但用处,,, 看不懂.


属性篇 第十二节

e20f77cb1720fe92e783a9c32234b1cd.png

131d9f86cddc16e2222bd0059b99a90e.png

忽略掉结构体本身的反射

相比来看, 也比较简单, 存了一个函数指针, 构建依赖的结构体(UScrUScriptStruct)


属性篇 第十三节

13ad16975ca40b937fdf2d81f11289f8.png

d8c9032b16c4ecfe6255e5a553441abb.png

e050f4d05e7093b0ddd92e465c1371ac.png

65909d1c4b04e1e5b8e57e4c1e8a3265.png

TArray这里的实现, 也是两个结构体, 一个是数组本身, 一个是数组对应的类型

数组对应类型结构体NewProp_TestValue_Inner数据很多都是空值, 只是为了收集数据类型.

b3aa137620b54baff402f2438b63a3fb.png

e85eca9865187dc6f7c0bdc0f33bdd5b.png

2facfc8c20ee7310265261724b4ff4d6.png

TSet同TArray

0c1c9db4db389b497f14927e72764d07.png

02cb7a67849af8409214c9a9e41795f9.png

3c02ae5b053a9642d4b1b2f8e4f301c5.png

3de714c769ff9520e90d28d64db72ed0.png

TMap则类似, 有三个结构体, 一个键的数据类型,一个值的数据类型

其他同上

不过可以看到Offset这个值, 键为0, 值为1, 有做一定的区别

具体原因, 不知, 后文遇到分析.


属性篇 第十四节

842e8c6e6d23d5f06433ceb1c265a1bb.png

7aed7cc085aba3c9b8abc0c53bdbd727.png

0bd731316b1498019b77bdcfdfcec245.png

PropertyFlags值发生了变化, 多了CPF_InstancedReference

并多了一个Z_Construct_UDelegateFunction_UGAObject26_TestGADelegate__DelegateSignature函数指针, 从代码上看及推断, 应该和前文类似, 是Delegate的依赖, 不太明白

e2145c2956d59bc63293f0b7b5797b90.png

15ede8b23a5e3683e26a1b4584591363.png

以及最后的动态多播代理

12bb11ec4214ce773c41caf281230c04.png

127fb62cc2db0767daac360bac8c31c2.png

基本同单播实现

同时, 这里PropertyFlags值添加一个BlueprintAssignable发生了变化, 多了CPF_BlueprintAssignable

f202839aa8d6e3a80b8ea3e8d0e91bb6.png

属性篇 第十五节

至此, 多数常见的数据类型的反射信息就分析过一篇了.

可能存在没有分析的内容(看不懂).

可能存在没有分析到的数据类型(赖或者不常用)

自己总结概况整理一下, 很多地方都是相同的.


属性篇 第十六节

最后的最后, 是最后一种情况, 如果有很多属性呢? 如果和C++普通的属性混在一起呢?

a8e0479168cfa3e961414a48c2371515.png

43f3e6a6e3cd73ae988780d27864aa0b.png

1985bc7235160e443eaa43f10835c887.png

d24f1c56408cf0e31fe5c144c6f44621.png

12e4f4ce6136bb98d8d1d31e32a3c9ab.png

是不是很熟悉呢? 只是重复定义并在数组里面加了一个值


至此, 反射系列关于参数相关的告一段落, 中间缺失的内容之后会视情况补上.

总共十六小节, 从GAObject04到GAObject28, 这么多个类, 希望一步一步跟做.

嗯, 虽然, 估计, 实际上, 应该不会有几个人跟着做(手动狗头)


结语

  • 这是本周应该更的, 由于昨天修复旧文章代理相关内容, 估计函数反射相关的到下周了
  • 本文中有些内容有缺失的地方, 可能会在之后找到对应资料, 或者有合适位置的时候再展开分析
  • 骗赞了, 骗评论了.
;