UE引擎研究笔记

  • 对UE的反射名(可选 or 全部)进行HASH,且不影响游戏原始的运行效果。

  • 对结构体进行随机化。


需要了解的东西


实现思路

① 源码级

    (宏实现)编译期处理所有gen.cpp字符串

    资源预处理

    处理代码中对反射名的引用

② bin层

    直接对bin数据的字符串处理

混淆反射的思路:

1、只有正式&编译打包时,才会hash;避免直接对gen.cpp哈希后,影响编辑器。

2、资源预处理。这个东西可以理解为数据初始化的存档,里边记录着对象反射的序列化数据,用于加载时反序列化初始到对应对象中;因此如果只单纯对gen.cpp进行hash,那么游戏初始化对象时,遇到带有资源的属性直接报错。

  • 目前只修改UE4下边gen.cpp中非对象类型的反射名,游戏能跑通,打包编译也正常,下一步研究一下资源预处理。

记录

开发&调试环境相关

确保安装UE引擎是勾选输入调试用符号,不然没法对UE引擎部分进行调试。

vs中四种编译模式:DebugGameDebugGame EditorDevelopmentDevelopment EditorShipping

  • Editor:对UE4Editor.exe进行调试,这个模式下也是可以调试游戏的,只需要在编辑器中点击启动。

  • 不带Editor:直接对游戏进行调试。

其中DebugDevelopmentShipping的区别简单说就是编译优化程度不同(低→高)。


当以Editor模式调试时,项目工程目录下的Binaries会生成一个dll文件,该文件实际上为游戏本体,用于加载到编辑器中。(Editor选项的编译产物为DLL,反之为EXE)。

使用VS调试时,发现被编译的gen.hgen.cpp的来源会根据选择的调试目标进行重定向。例如当前选择的调试目标为DebugGame Editor,并且断点打在UE4中,但是拉起调试后,断点却断在了UE4Editor中;以调试目标为DebugGame时,也会发生相同的情况。(断点在UE4Editor,却断在UE4中)

验证编译产物的反射名。

Editor编译时:

不带Editor编译:

知识相关

术词

COD:Class Default Object”,即“类默认对象”。在UE中,每一个类(UClass)都有其对应的CDO。复制或者实例化一个类型对象的时候,CDO不会被重新创建,尽管后续该实例可能会有一些数据被修改,但它们的CDO其实还是一直不变的,相同类型的所有实例都是共享的同一个CDO,所以CDO很适合用于做一些所有对象共享的操作与数据存储。

由 UClass::GetDefaultObject() 获取到的为类的 CDO 对象。它由引擎自动创建,编程时需要注意避免在 CDO 中处理非必要的逻辑 。CDO 对象的主要作用就是用于为类提供默认值。例如我们在编辑器中编辑的蓝图类的属性就是保存在该蓝图类的 CDO 中,且在构造此蓝图类的实例时会以其 CDO 作为默认的模板对象来初始化蓝图类实例的属性。此外 CDO 对象是具有稳定的网络路径的,可由网络同步其引用( 参考此链接),这使得我们在同步一个 UObject 对象的属性时,仅需同步和 CDO 中不同的属性即可。同样的道理在序列化时也只需保存和 CDO 中不同的差异属性即可。

资源

https://www.cnblogs.com/sin998/p/15501520.html

资源路径,右键资源,点击复制引用。

会得到一串字符串:Blueprint’/Game/FirstPersonCPP/Blueprints/FirstPersonCharacter.FirstPersonCharacter’

  • 红色部分

资源的类型,平时加载资源的时候也可以不要,加载函数内部会截掉这部分只留单引号里面的路径,所以其实前面这个StaticMesh或Blueprint可以不写,在编辑器Content Browser里右键点资源拷路径是有这部分的,我猜引擎留着这部分可能是为了用户清楚他的类型是什么,更方便识别一些,这个只是给人看的,程序不看这个。

  • 绿色部分

资源的分区。大部分资源的路径都是以/Game开头,这个其实表示这个资源是在游戏的Content目录下面,也可以是/Engine就表示引擎下面的,比如下图,或者对应插件目录。

  • 蓝色部分

实际资源路径,表示资源在哪个文件夹下面。

  • 黄色部分

资源的包(Package)名,也就是这个资源所在的真实物理资源文件(uasset/umap)的名字,包其实就是UE4将对象按照自己的规则序列化到磁盘上的文件,在Content Browser里看到的每一个文件都是一个包。

  • 紫色部分

资源的对象名,因为物理的资源文件里面可能有多个对象,这个名字可以唯一标识包的内部每个对象的唯一名字。比如蓝图资源里有多个UObject,一个关卡文件里有多个Actor,一个UI蓝图里有多个控件。如果不写,UE4的某些接口会默认以包名补充到后面,也就是说默认使用和包名相同的对象名,但有的接口又可能不做处理,所以还是建议写。如果用的不是默认对象,而是资源对象的类,就要在后面加一个_C,如果是CDO对象,就要在前面加Default__。

  • 冒号部分

子对象名,有些资源路径后面会带冒号:接一个文件名,这种其实是对象的子对象名,有的资源对象内部有子对象,比如C++类里的子类,这个不常用,知道即可。


若对象名带有“_C”表示这是一个蓝图产生类(GeneratedClass),没加的代表是蓝图类。


ParentClass是蓝图要编辑的对象的父类

蓝图GeneratedClass就好像修改器存档的关系,如果我们把UE4运行起来的世界看做是一个没有实时存档功能的上古游戏,那么,我们需要游戏存档(GeneratedClass)我们才能游玩,而我们要修改存档只能使用特定的修改器(特定类型的Blueprint)。而游戏运行起来后完全不需要修改器,只需要游戏存档。每次当我们点击蓝图的Compile编译按钮时,相当于我们使用修改器编辑存档后点击保存,只有点击保存了我们的修改才有效。


资源是一种 “既可以被序列化成文件(.uasset、.umap) 保存在硬盘” , 又可以 “从硬盘加载然后反序列化到内存中(UObject)” 的对象 ,主要用来存贮游戏资源(比如:蓝图,贴图,骨骼,声音,特效等).从硬盘加载资产文件以后,在内存中就可以把它当作UObject对象使用了;比如:UBlueprint、UTexture2D、USkeletalMesh、 USoundWave 等


勾选

点击

会在对应资源下生成utxt文件。

该文件以json格式保存资源的存储内容(简化过),可以大概进行浏览。


Cook
什么是Cook(烘焙)?

Cook简单而言就是对“没用”资产的提出过程,比如在日常开发过程中,我们需要调试,以及有些功能只有在编辑器下才可用,资产中也会携带与正式发布版无关的功能或者相关内容,Cook的过程就是对这一类我们不需要的东西做剔除,然后只保留游戏相关的部分,这个过程就是的Cook。

理解了Cook的概念再对上面做参数介绍的时候有关Cook的部分这里做一下说明:

  • Unknown:相当于自动Cook,如果有对此资源的引用就Cook,如果没有就不Cook

  • Never Cook:永不Cook,如果存在对它的引用会报错

  • Development Cook:在Development打包条件下有引用就会Cook

  • Development Always Cook:在Development打包条件下永远会Cook

  • Always Cook:在Development或者Ship打包条件下永远会Cook

总结:只要有对资产的引用,就应该做Cook操作。

Cook前后资产对比:

图片引擎中的资产大小

Cook之后的大小

从对比可知,Cook前后资产大小的变化,一般会减小,因为去掉了编辑器相关的部分。

反射相关

反射中间文件(gen.h、gen.cpp),由UHT生成,存放下列两个位置

路径 作用
X:/ProjectSource/Intermediate/Build/Win64/UE4 实际生成到EXE中
X:/ProjectSource/Intermediate/Build/Win64/UE4Editor 在UE4Editor面板中显示

如果想重新生成反射文件有两种方法:

1、vs点击重新生成解决方案。

2、删除反射文件,编译 or 运行编辑器时会自动生成。

3、打包时,好像会判断时间戳,太久的话会重新生成


同步修改gen.cpp和cpp中的内容

会出现一个情况,进入游戏后枪不见了!

这是因为uasset资源绑定的反射名(gen.cpp)没有修改。进入编辑器中右键对象-浏览至资产

点击在文件夹视图中显示

此时定位到对应文件,直接二进制编辑器大概,搜索原反射名

可看到资源中保存的数据名未改变,要改变有两种方式:

1、重新在编辑器中设置。

2、修改二进制bin,但是需要注意字符串长度与原反射名一致。


代码层探究CreateDefaultSubobject与反射的作用,以UE4Editor为例。

序号 .cpp gen.cpp 结果
1 FP_GunFP_Gun FP_GunFP_Gun111 编译后重新打开调试器,可看到面板的反射名变了,且加载的资源、数据项、数据依旧正常。
2 FP_GunFP_Gun111 FP_GunFP_Gun 编译后重新打开调试器,面板可搜索到FP_Gun,但是不可编辑,也缺少了很多项数据,编辑器中运行时崩溃。
3 FP_GunFP_Gun111 FP_GunFP_Gun111 编译后重新打开调试器,可看到面板的反射名变了,且数据项都正常,只是缺少数据;与1情况相同,只是数据都清空。
4 FP_GunFP_Gun111 FP_GunFP_Gun11 与3相同

所以为什么 2 的结果会崩溃,我有点迷茫。。。。。。崩溃点:

明明他妈的构造都创建出对象了,到这里就空了。

这个暂时不用管。


对象相关

其他

带【*】为重点

https://blog.csdn.net/ZFSR05255134/article/details/116763773

https://www.cnblogs.com/wellbye/p/5808894.html?utm_source=itdadao&utm_medium=referral

https://blog.csdn.net/qq_29523119/article/details/119420238

https://zhuanlan.zhihu.com/p/61042237

https://zhuanlan.zhihu.com/p/529711999

【*】 https://papalqi.cn/