虚幻引擎:528K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2#2L8Y4u0W2j5h3I4W2L8X3N6A6L8X3g2Q4x3X3g2U0L8$3#2Q4x3V1k6*7K9q4)9J5k6p5y4z5
虚幻引擎源码:a36K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6q4M7r3W2U0c8$3q4E0k6i4x3`. 在epic中关联github,并打开网址加入EpicGames
实例游戏:SCUM.exe(也可自己编译模板工程)


(因不同版本GetName算法存在细微差异,演示版本为4.23)
FName 是UE4提供个一种轻型系统使用字符串。其内部并不直接存储字符串,而是将字符串通过CityHash解算后存储在一个全局的NamePool之中。相同字符串的FName在NamePool数据表中也只存储一次。打包后FName 不区分大小写,它们为不可变,无法被操作。
FNames 的存储系统和静态特性决定了通过键进行 FNames 的查找和访问速度较快。其内部存储着字符串在NamePool中的索引值,他的容量非常小,当游戏逻辑在用来传递参数,比较等操作时,只传递或比较索引,而不需要对字符串本身的内容做操作,就可以显著的提升游戏性能。
在源码NameTypes.h文件中可以看到FName类

UnrealNames.cpp
static bool bNamePoolInitialized; 标志位表示FNamePool是否初始化,如果没有初始化则new一个对象,并把bNamePoolInitialized赋值为true,否则直接返回NamePoolData
UnrealNames.cpp 中包含了#include "UObject/UnrealNames.h"



引擎会在初始化的时候注册一些字符串,我们选择“FloatProperty”作为特征去ida中定位
一个正常的UE工程,分为Engine文件和自己的文件,Engine存储的是引擎源码,在自己文件中寻址到本体exe并拖入IDA中

“FloatProperty”附近也存在其他初始化用到的字符串


找到该函数的引用,发现初始化流程与源码一致,成功定位到NamePoolData

去NamePoolData+0x10的地方验证一下

FameEntryId:内部只有一个uint32变量占4个字节,让FName变的更轻量。该变量就是存储字符串在NamePool中的Block的下标和地址Offset偏移量。(可以理解为寻找字符串位置的钥匙,哈希的key)
WITH_CASE_PRESERVING_NAME:在下面代码讲解的部分时,会以[编辑器]or[打包后]两种状态讲解,UE提供了WITH_CASE_PRESERVING_NAME宏可对编辑器UHT开启FName大小支持,编辑器默认状态下是已开启,发布版关闭。
这也是前面验证时为何要+0x10的原因
NameEntry是真正存储字符串的结构体,内部包含了字符串的数组,字符串的长度,是否是宽字节。后续会被New出堆内存分配该Entry。
unreal Engine的三种字符串类:
FString
类似于STL中的String
FText
比FString多了语言本地化功能
FName
哈希索引可与FString,FText相互转换
UnrealNames.cpp中的实现方法FName转FString FString FName::ToString() const
GetPlainNameString是 FName 类中用于处理名称字符串的函数,主要作用是将内部存储的名称转换为不带路径的纯字符串。
和主线无关,所以重心放到GetDisplayNameEntry,其GetDisplayIndex是获取存储名称在内部哈希表中的索引
Resolve函数
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!