⚠ 2026-07-25 勘误:拿一个确定被引擎消费的真名字
TIER3_DESCRIPTION回头对账,发现下面第 2 条结论 (「引擎硬编的 tag = 0 个」)的搜索方法失效了 —— 引擎从不用预计算 hash 立即数,它对代码里的宽字符串字面量 运行时算 rghash。修正后的口径、实测数字与打包器的连带修复都在 第 9 节。 第 1、3 条(任意 tag 值可用 / 警告是 GUTS 专属)复核后仍然成立。
起因很俗:一个老整合 mod 的加载日志刷满
Found property name with a hashcode (…) that has no match in tags.dat。 问题是——这到底是 mod 用了"非法 tag",还是别的什么?顺着这条警告,把 TL2 的 tag 系统从Torchlight2.exe挖到底。方法:IDA(idalib MCP)反编译
Torchlight2.exe(32 位,imagebase0x400000)与EditorGuts.dll(imagebase0x10000000)+ 对MEDIA/TAGS.DAT基线(3631 个 tag 名)做 rghash 对账 + 扫两个真实整合 mod 的全部 DAT property key。所有sub_XXXXXXXX是绝对地址。一句话结论:引擎按名字哈希(rghash)匹配 tag,运行时根本不查
TAGS.DAT。所以 mod 里想写什么 tag 都行;TAGS.DAT只是 GUTS 的下拉列表 + hash→名字的显示反查表,不是校验门。那条刷屏的警告也不是游戏发的——是 GUTS 编辑器发的, 而且属性数据一个字节都没丢。
0. 结论先行
- 引擎支持任意 tag(rghash 匹配,零校验)。
TAGS.DAT= GUTS 下拉列表 + hash→name 显示反查表,不是校验集。GUTS 里选不到某 tag,只因它不在这张表里;绕过 GUTS 直接写 DAT / 直接打包,任何 tag 都认。 引擎硬编的 tag = 0 个。(→ 2026-07-25 已收窄,见 第 9 节) 68 个候选 tag 的 hash 立即数搜遍整个 exe 代码段,0 命中;rghash 的 56 个调用者全是 DAT 字段键解析器。tag 100% 数据驱动——boss/hero 之类的特殊行为走UNITTYPES/MONSTERCLASS/ 显式 DAT 标志(如ISBOSS),不是 tag。no match in tags.dat警告是 GUTS 专属,数据不丢。 游戏本体Torchlight2.exe里根本没有这条字符串。真正的风险不是"警告"本身,而是用 GUTS 打开再保存会把不认识的 key 名洗成 hash 数字,还可能顺手丢掉你编辑过的别的字段。
下面是每条的 exe 证据。
1. 引擎怎么认一个 tag:rghash + 纯哈希比较
rghash = sub_4C9FE0(0x4C9FE0)。djb2 的一个变体,逐 wchar 滚动:
h = len(s)
for wchar c in s:
h = (h >> 27) ^ (h << 5) ^ c # 逐指令确认:shr ecx,0x1B shl esi,5 xor ecx,esi xor ecx,edx
它和 EditorGuts.dll 里的 sub_100CA9A0 是同一个算法——这点很关键,因为 GUTS 编译 DAT 时用它算 key/name 的 hash,游戏运行时也用它算,两边必须一致才对得上。
tag 匹配 = 一次纯 hash 比较。sub_4CA070 反出来就一行:
return rghash(a2) == this[2]; // this[2] 是这个 tag 对象加载时存下的 hash
没有注册表查询,没有成员校验。任何字符串,只要它的 rghash 等于存下的那个值,就匹配。 结构键(key)也一样:sub_4CA7D0 里硬编了 BASEOBJECT / PROPERTIES / NAME / ID,每个都是先 rghash 再比。
这就够定性了:比较的那一端是加载数据时算出来的 hash,从来不是"这个 tag 在不在合法集合里"。合法集合这个概念在运行时不存在。
2. TAGS.DAT 是什么:一张 hash→名字的反查表
那 TAGS.DAT 到底干嘛用的?sub_65BBF0 是它的运行时解析器(debug 串 "Loading tag file:" / "Tags parsed. Total count:"),逻辑很直白:
读 COUNT
循环读 TAG0..TAGn 的名字字符串:
hash = rghash(name)
entry = sub_4FF760(&hash) # 在 map 里取/建这个 hash 的项
entry+4 = name # 把名字挂上去
结果是一张 hash → name 的表,给 UI/tooltip 反查显示名用的。不是校验门:未登记的 tag 照样按 hash 匹配,只是缺一个好看的显示名。
顺带把 Q4(tag hash 到底是不是 rghash)钉死:对 3631 个 baseline tag 名逐个算 rghash,3568 个(98%)命中 TAGS.DAT 里那 3692 个整数。剩下 2% 的不命中是解码损坏 / 本地化碎片——TAGS.DAT 的字符串池里还混着非 tag 的本地化 UI 串(像 ', EINGANG' 这种)。也就是说:TAGS.DAT 里那些整数,就是名字的 rghash。 这张表两个方向都能查(名字↔hash),GUTS 的下拉列表也从它来。
补一个容易踩的锚点:游戏里的 tag 注册不走一条显式加载
TAGS.DAT字符串的路径。exe 里"MEDIA/TAGS.DAT"宽串(@0x2182044)只被sub_65B310(一个 DAT→文本反编译工具)引用;"TAGS"宽串(@0x21821f4)只被sub_789B00(控制台命令分发器)引用,是个 debug 命令。都不是游戏性 tag 系统。
3. 引擎硬编了几个 tag?—— 0 个
“零校验"还留了个尾巴:万一引擎特殊处理某个 tag(比如看到 HERO 就触发特殊 AI)呢?两个独立角度收敛到同一个答案。
角度一:56 个 rghash 调用者,逐个看。 把 sub_4C9FE0 的全部 56 个调用点反编译、提传入的字符串常量,分类下来全是各类 DAT/LAYOUT 的字段键解析器 + TAGS.DAT 加载器,没有任何"魔法 tag”:
- 结构/布局键:
NAME/ID/PROPERTIES/BASEOBJECT/DESCRIPTOR/LOGICGROUP/PIECE/GUID/MESH… - 各内容类型的字段键:SKILL(
SKILL_TYPE/ACTIVATION_TYPE/TARGET_ALIGNMENT…)、AFFIX/EFFECT(TARGET/IGNORE_UNITTYPE/DURATION…)、QUEST(TASK/REWARD…)、以及 EMOTE/FEATURE/THEME/KEYBIND 等。 - tag 注册表加载:
sub_65BBF0(COUNT/TAG<i>)。
结论:rghash 是个通用的"DAT 字段键按哈希匹配"函数,不是给某个具体 tag 开小灶的地方。
角度二:直接搜 hash 立即数。 引擎若要特殊处理某 tag,只能用预计算好的 hash 立即数去比(运行时不会临时哈希一个字符串常量)。于是:对 68 个候选 tag 算 rghash——28 个常见的游戏性猜测(HERO / BOSS / CHAMPION / PET / SUMMONED / MALE / FEMALE / ELITE / MINION …)+ 40 个真实 baseline 单词 tag——把它们的 little-endian u32 在全 exe find_bytes 搜一遍:代码段 0 命中。唯一那个"命中"是 PET@0x253b69d,但它无 xref、地址还不是 4 字节对齐 = 纯巧合的数据字节,不是 tag-hash 引用。
→ tag 100% 数据驱动。 一个自定义 tag 有没有意义,完全取决于你有没有同时写好引用它的数据规则(affix/loot/spawn DAT)。只有载体、没人检查 = 惰性死数据(无害,也没用)。想"白嫖"引擎现成的特殊行为?没有捷径——那些行为走 UNITTYPES / 类 / 显式标志,不认任何 tag 字符串。
4. 那条刷屏警告的真相:GUTS 专属,数据不丢
回到起因的那条日志。先做个决定性的事实核对:Found property name with a hashcode (…) that has no match in tags.dat: 这条字符串,在 Torchlight2.exe 里搜不到(ASCII、宽字节都 0 命中)。它只活在 EditorGuts.dll 里——宽串 @0x11E93868「Found property name with a hashcode (」+ 窄串 @0x11E938BF「) that has no match in tags.dat: 」。发出者是 sub_10289D20。
sub_10289D20 逐属性读流(每条属性 = key_hash(4) + type(4) + value),顺序是这样的:
sub_10287DD0(key_hash, value, …, type) # ① 无条件先调用 —— 属性+值原样存下,永不丢
在 tags.dat 的 hash→name 树里查 key_hash: # ② 之后才查
命中 → 用真名(sub_10288C10(node+5))
未命中 → 打这条警告,并 sub_10296760 把 hash 格式化成字符串,拿它当"名字"用
三点定论:
- 这是 GUTS 编辑器的诊断信息。 游戏引擎从不发、也不 care——和第 1 节"引擎按 hash 零校验匹配任意 tag"完全自洽。
- 属性值不丢。 存值那步(
sub_10287DD0)在查表之前就无条件跑了。GUTS 只是没有友好名可显示,退化成拿 hashcode 当名字。 - 真风险 = 过 GUTS 往返。 一旦在 GUTS 里重存,这些"只剩 hash 名"的属性会以 hash 数字写回(dev 的原话:GUTS 用 hash 数字替换不认的 key、还在此基础上重算 hash),而且 GUTS 可能顺带丢弃你编辑过的其它字段。绕开 GUTS——文本编辑 + 直接打包(mikuro packer)——这一整类问题根本不发生。
5. 实测:两个整合 mod 的 property key 排查
理论说完,拿真东西验。方法:把一个 mod 里出现的每一个 property key 拿去和 TAGS.DAT 的 3692 个登记 hash 对账,把"没登记"的自动分三桶——GUTS 数字损坏 / 编辑距离 1 的 typo / 真·自定义。
5.1 老 IMBA 整合(48,869 DAT)= typo 叠 GUTS 损坏
扫出来的"自定义 key",一细看全是原版键漏了词尾 D 的坏版:
| 坏 key | rghash | 文件数 | 判定 |
|---|---|---|---|
DEXTERITY_REQUIRE |
1970490181 | 2720 | typo of DEXTERITY_REQUIRED |
STRENGTH_REQUIRE |
2034231625 | 2517 | typo of STRENGTH_REQUIRED |
MAGIC_REQUIRE |
4272869367 | 2272 | typo of MAGIC_REQUIRED |
DEFENSE_REQUIRE |
1284104295 | 1638 | typo of DEFENSE_REQUIRED |
SHOULDERS_OVERRIDE |
786463860 | 29 | 真自定义 / TL2 无护肩槽 → 惰性 |
前四个是原版的装备需求键 *_REQUIRED(引擎运行时按字符串算 hash 读:exe 宽串 STRENGTH_REQUIRED@0x2174364 / DEXTERITY_REQUIRED@0x2174304)去掉词尾 D 的坏版。引擎只读带 D 的,所以这些缺 D 的键 = 死数据,它们写的属性需求根本不被强制执行。
全仓一算更触目:*_REQUIRE(坏)3439 文件、*_REQUIRED(原版)9412 文件、两者并存仅 304 文件。也就是说约 3135 个物品只有缺 D 的坏键、没有原版键 —— 这些物品的属性需求被引擎静默忽略。
在这之上还叠了一层 GUTS 损坏:53 个 key 被写成了纯十进制 hash 数字(某次在 GUTS 里重存,文本 key 名被换成了它的 hash)。其中 5 个还能反查回原名(就是上面那几个 *_REQUIRE + SHOULDERS_OVERRIDE),另外 48 个名字已经永久丢失——不可逆,只能从别处副本找回或保留数字(还能跑,只是失去可读名)。
5.2 challenger-continent(72,740 DAT,走 mikuro packer、不过 GUTS)= 干净
同样的扫描,对照组结果:
*_REQUIRE(坏)0 文件;*_REQUIRED(原版)14,615 文件;两者并存 0;需求失效 0。- GUTS 数字损坏 0 个。
- 扫描器的原始 flag 经人工复核,逐条落到"良性 / WIP":
TIER4_DESCRIPTION(3):★误报,非 typo。TAGS.DAT只登记TIER1/2/3_DESCRIPTION,TIER4是有意的第 4 层扩展(纯显示,引擎按 1-3 读,无害)。MOD_ID/VERSION/AUTHOR/WEBSITE/MOD_FILE_NAME(各 10):MOD.DAT的清单头字段(10 个子库各一份),本就不属于游戏数据键,不在TAGS.DAT是对的。chest_OVERRIDE(3)/belt_OVERRIDE(6)/shoulders_OVERRIDE(6),小写、在实验内容/下:真隐患但当前无害。rghash 大小写敏感 → 小写版引擎读不到(原版是CHEST_OVERRIDE大写;BELT/SHOULDERS压根没有原版槽位)。属 WIP。SHOULDERS_OVERRIDE(76,大写):有意的自定义护肩槽键;TL2 无原版护肩槽,除非本 mod 另加槽位,否则惰性。INCLUDE_DEAD(1):一次性自定义键,需确认意图。
对照很说明问题:同一个引擎、同一张 TAGS.DAT、两个 mod。过 GUTS 打包的那个,满身 typo + 53 处 hash 数字疤;走 mikuro packer 直接打包、不过 GUTS 的那个,两样都是 0。“绕开 GUTS = 零损坏” —— 在 7 万多个文件上被实证。
6. 配套工具
scan_mod_problems.py:对着一个 mod 的 MEDIA 树 +TAGS.DAT,列出所有未登记的 property key,自动分桶(GUTS 数字损坏 / 编辑距离 1 typo / 真自定义)。上面两份报告就是它出的。注意"自定义/typo"这桶仍需人工复核——TIER4_DESCRIPTION那个误报就是例子。- mikuro packer 的 DAT 反编译:把编译后的 BINDAT /
.DAT还原成可读文本,好看清一个 shipped 或 GUTS 存过的 DAT 里实际装着哪些 key —— 那 53 个 hash 数字键就是这么抓出来的。
7. 给 modder 的三条实操
- 想用 GUTS 里选不到的 tag? 直接写 DAT / 直接打包就行,引擎认。但要让 tag “做事”,你得自己写引用它的数据规则(affix/loot/spawn DAT);引擎不给任何 tag 白送行为。想补个显示名,把 tag 加进
TAGS.DAT即可(仅影响 UI 显示)。 - 别拿 GUTS 往返编辑第三方老 mod。 它会把不认识的 key 洗成 hash 数字、还可能丢字段。要改就走文本 + 直接打包。
- 看到满屏
no match in tags.dat? 先分清是谁在打——如果是 GUTS,数据没丢,只是显示名退化;真要担心的是别把这些"只剩 hash 名"的属性再过一次 GUTS。
8. 诚实边界
- Q1 / Q3 / Q4 已用 exe 反编译实证:rghash
sub_4C9FE0、匹配sub_4CA070、注册表sub_65BBF0、3568=98% 的 hash 对账、68 个 hash 立即数 0 命中。 - 注意区分两个不同问题:"哪些 tag 能用" = 全部(本文已答);"哪些 tag 触发引擎特殊行为" 需另搜预计算 hash 立即数——本轮只对 68 个候选搜过(0 命中),不是对全 hash 空间的证明。
- Q2(item/unit 的 tag 是存的还是派生的)本轮未收口:DAT 里几乎没有显式
<>TAG:键,初步疑为派生,留待后续。 - rghash 是 32 位,理论上存在碰撞;baseline 那 3631 个名里混着 PAK 字符串池的非 tag 本地化串(就是对账里那 2% 不命中的来源)。
9. 勘误(2026-07-25):TIER3_DESCRIPTION 把结论修窄了
上面第 2 条(「引擎硬编的 tag = 0 个」)是靠"搜 hash 立即数 0 命中"得出的。隔了一天,拿一个确定被引擎消费的
真名字回头对账 —— TIER3_DESCRIPTION,技能 tooltip 里第三层加成那行字 —— 那条推理链当场断了。
9.1 它到底怎么被消费:三段链路
① DAT key → 技能定义字段。 技能 DAT 顶层 [SKILL] 里就是一条普通属性:
<TRANSLATE>TIER1_DESCRIPTION:5 pillars of flame are created
<TRANSLATE>TIER2_DESCRIPTION:6 pillars of flame are created
<TRANSLATE>TIER3_DESCRIPTION:7 pillars of flame are created
引擎侧硬编了这三个名字的宽字符串字面量,在技能定义加载器 sub_6DC320 里逐个取值:
| key | 字面量 | 取值点 | 存入定义对象 |
|---|---|---|---|
TIER1_DESCRIPTION |
@0x218B4AC |
0x6DD905 |
+0x270 |
TIER2_DESCRIPTION |
@0x218B488 |
0x6DD95C |
+0x28C |
TIER3_DESCRIPTION |
@0x218B464 |
0x6DD9B3 |
+0x2A8 |
取值走通用属性包 getter:sub_677F00 → sub_677E80,而 sub_677E80 的第一行就是
v3 = sub_4C9FE0(key) —— 对代码里的字面量现算 rghash,再在按 hash 排序的二叉树里二分查值。
② tooltip 渲染 sub_6D4020。 同一个函数按名字取 UI 控件:TIER1_SEC/TIER2_SEC/TIER3_SEC(三段容器)、
TIER1DESCRIPTION/TIER2DESCRIPTION/TIER3DESCRIPTION(文本)、TIERDIVIDER(分隔线)。每段:字段为空就隐藏,
非空就填字并 setAlpha(已投点数 < 阈值 ? 0.5 : 1.0)(sub_70ECF0 → CEGUI::Window::setAlpha)。
阈值 5 / 10 / 15 是 exe 立即数,三段全空时兜底显示 "No Tier upgrades available."。
③ 技能树格子 sub_79F4F0 另绑一组 TIERTEXT1/2/3(和 MINUS/PLUS/PROGRESSBAR/INVESTED/CONTAINER 同批)。
exe 里 TIER 开头的宽字面量总共 13 个,已全部枚举,没有任何 TIER4。
9.2 于是第 2 条错在哪
错的是搜法,不是数据。 引擎特殊处理一个名字不需要预计算 hash 立即数 —— 它把名字当宽串字面量放在代码里, 每次调用现算。所以"全 exe 搜 hash 立即数 → 0 命中"这个实验,无论引擎硬编多少名字,结果都必然是 0,它证明不了任何事。
换个能看见的量法:把 exe 的全部 UTF-16LE 字面量抽出来和 TAGS.DAT 名字池求交 ——
| 条数 | |
|---|---|
TAGS.DAT 池里 identifier 形态的名字 |
2929 |
| └ 以宽字面量硬编在 exe 里 | 1167(39%) |
| └ exe 内 0 命中(纯数据空间) | 1762(61%) |
| exe 内 identifier 形态宽字面量 | 4050 |
└ 不在 TAGS.DAT 池里 |
2883 |
顺带两处也得改口:
sub_4CA070不是"tag 匹配器",它是节点.keyHash == rghash(字面量)的 key 比较器,全 exe 只有 1 个调用点 (sub_506550比TIMELINEOBJECTEVENT)。第 1 节把它当作 tag 匹配的核心证据,是误标。- “56 个 rghash 调用者"口径太窄:硬编名字在属性 getter 的调用点(光
sub_677F00一家 xref 就 ≥100), 不在 rghash 的直接调用点。
还有一条方法论教训:IDA 的字符串列表不可靠 —— TIER3_DESCRIPTION 根本没被它收录,用 find_regex 查是 0 命中。
所以第 4 节"exe 里没有那条 GUTS 警告串"这个断言,本轮换成对原始字节做 UTF-16LE/ASCII 全量抽取重新验了一遍:
no match in tags.dat / Found property name with a hashcode 仍是 0,而 TAGS.DAT / Loading tag file / Tags parsed 有 ——
结论不变。
9.3 修正后的口径:名字有两个命名空间
原文把 TAGS.DAT 里的名字统称"tag”,这才是根子上的混淆。实际是两套东西:
- 引擎读的 key(
TIER3_DESCRIPTION、SKILL_ICON、CHEST_OVERRIDE…):名字硬编在 exe 里, 大小写敏感、逐字符。写错的 key 照样被存进属性包(rghash 不校验),但没有任何代码去查它 → 惰性数据,静默失效。第 5.2 节里chest_OVERRIDE(小写)那条隐患的机理正是这个。 - 数据之间互相匹配的值(unit / 关卡的 tag、spawnclass 名…):随便起名,只要"载体"和"检查者"两边一致。
进不进
TAGS.DAT只影响 GUTS 能不能从下拉列表选到、以及 hash 反查显示名。
「任意 tag 都能用」只对第 2 类成立 —— 这一类本轮也复核过:131 个 A1-* 关卡任务 tag 在 exe 内 0 命中;
引擎自己的属性表(sub_4A29A0,CWidgetUnitImageDescriptor 的 schema)注册 TAG 属性时,说明文字写着
“The tag to check in the unit data of the target.” —— 拿数据里的 tag 去比数据。掉落侧同理
(sub_5FE2C0 循环读 TAG 块的 NAME/CHANCE/MINCOUNT/MAXCOUNT)。
而"想靠起个特殊 tag 名白嫖引擎行为"这条实操结论不变,只是理由要改:不是"引擎不硬编任何名字", 而是引擎硬编的是它自己那套 key,那套 key 的行为你改不了、也没有多余的钩子。
顺带把第 5.2 节 TIER4_DESCRIPTION 那条从推测升级成实证:引擎不读(exe 无该字面量)+ UI 没有
TIER4_SEC/TIER4DESCRIPTION/TIERTEXT4 控件 → 100% 惰性、无害、不显示。要做第 4 层,只能把文案并进
TIER3_DESCRIPTION。另外那个 5/10/15 阈值只驱动 tooltip 里该段文字的灰显/高亮,数据侧改不了;
技能实际数值随投点走 [LEVEL] 数据 —— 如果你把 tier 加成做在别的档位,tooltip 的灰/亮就会和实际加成对不上。
9.4 连带修复:打包器的 UNK_<hex> 回写洞
这次对账顺手戳破了自家工具链的一个真 bug。BINDAT 只存名字的 rghash,所以反编译要靠一张内嵌反查词表
(1678 条,取自出货数据),查不到的 hash 会输出占位名 UNK_<8位十六进制>。问题在编译回去的时候:
编译器老老实实对 UNK_1A2B3C4D 这串文本算 rghash —— 于是得到一个完全不同的 hash。
它不报错、不警告,数据就这么静默失联了。
这不是理论风险。拿 80,505 个真实 DAT(挑战者大陆全仓)扫了一遍 key 与 section 名:
- 新 key 只有 20 个(全是 mod 自造的清单字段 /
*_OVERRIDE实验 /TIER4_DESCRIPTION); - 新 section 有 104 个,压倒性是
LEVEL17…LEVEL100。
因为词表是从原版出货数据提的,数字家族就卡在原版用到的位置:LEVEL1..16、CHILD1..5、
ENCHANTCOST1..4、VALUE1..5、TIER1..3_DESCRIPTION。而 mod 早就越界了。所以一个 [LEVEL20] 被解出来是
UNK_…,打包回去就变成引擎永远查不到的 key —— 整段数据无声消失。
修法(已落地,Rust 与 WASM 两个打包器共用同一份 bindat.rs):
UNK_<HEX8>成为正式转义:编译时识别它并把原始 hash 原样写回,反编译 → 编译现在逐字节相同。 刻意写严(长度精确 + 大写十六进制),形状不对的一律当普通名字哈希。- 打包时给警告:凡是走这条转义的文件,打包过程会列出文件与占位名 ——
数据没丢,但可读的名字丢了,提醒你在知道真名时换回去,并且永远别手改
UNK_里的数字(那会改掉 hash)。 - WASM 侧额外导出
dat_raw_hash_names(data),让浏览器版工具能弹同一条提示。
至于"把 exe 里那 4050 条 identifier 全灌进词表"——想过,不做:合并后确实 0 碰撞,但真正的缺口是 mod 现造的名字, 那是任何词表都覆盖不了的;把转义修对才是根治。
附录:关键地址
Torchlight2.exe(imagebase 0x400000)
| 功能 | 地址 |
|---|---|
| rghash(名字/键哈希) | sub_4C9FE0 |
sub_4CA070 |
|
| 属性包取值(rghash + hash 二叉树查找) | sub_677F00 → sub_677E80 |
技能定义加载器(读 TIER1/2/3_DESCRIPTION) |
sub_6DC320 |
技能 tooltip(TIER<n>_SEC/TIER<n>DESCRIPTION/TIERDIVIDER,阈值 5/10/15) |
sub_6D4020 |
技能树格子(TIERTEXT1/2/3) |
sub_79F4F0 |
| 控件 alpha(灰显/高亮) | sub_70ECF0 → CEGUI::Window::setAlpha |
结构键解析(BASEOBJECT/PROPERTIES/NAME/ID) |
sub_4CA7D0 |
TAGS.DAT 加载器(hash→name 反查表) / map 取建 |
sub_65BBF0 / sub_4FF760 |
| 原版需求键宽串 | STRENGTH_REQUIRED@0x2174364 / DEXTERITY_REQUIRED@0x2174304 |
"MEDIA/TAGS.DAT" 宽串(仅 DAT 反编译工具引用) / "TAGS" 控制台命令 |
@0x2182044·sub_65B310 / @0x21821f4·sub_789B00 |
EditorGuts.dll(imagebase 0x10000000)
| 功能 | 地址 |
|---|---|
| rghash 孪生 | sub_100CA9A0 |
| 属性流读取 / 发那条 no-match 警告 | sub_10289D20 |
| 查表前无条件存属性+值 | sub_10287DD0 |
| hash→字符串(退化显示名) / 名字取值 | sub_10296760 / sub_10288C10 |
| 警告格式串 | 宽 @0x11E93868 / 窄 @0x11E938BF |
配套资源:原版游戏分析/TAGS_RE/(TAGS_ENGINE_SET.md 主结论、IMBA_custom_keys.txt 与 challenger_key_problems.txt 两份排查报告、_LEDGER.json 逆向账本、tags_dat_baseline.txt 3631 名基线)。