文档定位与维护规范: 本文是
tl2-mikuro-runtime项目的核心技术账本与拦截规范。在代码库中增补、废弃或修改任何 Hook 时,必须同步更新本文对应条目及末尾的「更新记录」。
- 开源代码仓库:heiybb/tl2-mikuro-runtime
- 虚拟地址基准:文中所注
sub_XXXXXX与十六进制绝对地址0xXXXXXX均以零售版Torchlight2.exev1.25.9.5 的静态逆向工程数据库(IDA Pro 默认基址0x400000)为参考坐标,非运行期绝对内存地址。由于原版程序启用了 ASLR(地址空间布局随机化),运行期全部基于 AOB(Array of Bytes)字节特征码进行动态内存扫描与重定位。- 实证性与结论边界:本文所有机制结论均严格提取自源码及其实机断言验证过的「实证」范畴;对于源码中明确标明「未证实」或「待验」的边界,均予以客观保留,坚决不进行主观外推。
0. 架构定位:Runtime 的运行机制与功能矩阵
tl2-mikuro-runtime 在物理交付层面表现为一个 d3d9.dll 动态链接库代理(底层集成 MinHook 框架与 ImGui 渲染管线)。部署至游戏根目录后,宿主进程 Torchlight2.exe 在初始化 Direct3D 9 运行时将优先将其加载。
运行时首先链接底层的真实 Direct3D 9 实现(优先检索并加载同目录下更名的 d3d9_dxvk.dll,若不存在则回退至 Windows 系统目录的 d3d9.dll),随后创建独立的初始化工作线程,利用 AOB 字节特征码在已加载的游戏进程镜像中动态检索数十个目标引擎函数,有序实施入口 Detour 拦截或函数体内联补丁(Inline Patch / Code Cave)。
其承载的功能覆盖十大技术领域,面向不同受众提供清晰的工程支持:
| 功能大类 | 纯原版游戏受众 | 挑战者大陆(MOD)受众 | 索引章节 |
|---|---|---|---|
| 原版缺陷托底(崩溃预防、内存溢出修复、技能冷却生效修复) | 直接获得系统级稳定性提升 | 直接获得系统级稳定性提升 | §3.2 |
| 原版机制修正(矫正原版底层逻辑矛盾,默认开启,可配置关闭) | 获得数值与机制一致性保障 | 获得数值与机制一致性保障 | §3.3 |
| MOD 兼容托底(原版数据保持逐位等价,特定 MOD 环境激活兼容逻辑) | 机制完全透明(无侵入) | 提供关键兼容性支撑 | §3.4 |
| 启动性能优化(重构热点路径瓶颈算法,消除无用拷贝开销) | 显著缩短启动耗时 | 启动耗时大幅缩减(数据量越大收益越显著) | §3.5 |
| 掉落生命周期过滤(规则化拦截不合规道具落地生成) | 按需配置生效 | 按需配置生效 | §3.6 |
| 死槽 131 自定义效果体系(属性上限突破、扩展词缀机制、宠物嘲讽) | 机制完全透明(原版数据未引用) | 构成扩展玩法与装备构筑的核心底座 | §3.7 |
| 卷轴与附魔渠道扩展(乱铸、强化、词缀迁移、附魔剥离、神明祝福、涤除) | 机制完全透明(基于专属菜单名物理隔离) | 构成扩展玩法与高级打造的核心底座 | §3.8 |
| 视觉渲染 / HUD 强化(镶嵌发光、传奇光晕、护盾实时吸收计量面板) | 按需配置生效 | 按需配置生效 | §3.9 |
| 操控模式扩展(WASD 平滑键盘移动) | 按需配置生效 | 按需配置生效 | §3.10 |
| 底层诊断探针(地形栅格导出、网格可视化投影、VFS 耗时剖析,默认禁用) | 仅在系统排障与逆向分析时挂载 | 仅在系统排障与逆向分析时挂载 | §3.11 |
实机验证构建版本:
- 官方零售版(Retail)v1.25.9.5;
- Steam 数字版 v1.25.5.6。 除个别注明「Steam 版待验」的项目外,所有内置 AOB 特征码均通过了双版本的唯一命中性交叉核验。
1. 安全总则:动态拦截的八大工程规范
为确保「系统托底」的确定性,Runtime 遵循以下最高工程准则:宁可个别扩展特性静默失效,也绝不引入比未加载时更差的系统状态或额外不稳定因素。
- 全面采用 AOB 动态签名定位,严禁硬编码 RVA:
- 早期通过静态 RVA 定位的方案在跨版本(如 Steam 数字版)执行时导致代码偏移错位(例如曾引发宠物嘲讽必崩问题),自 2026-07-23 起已全量切换为字节特征码动态扫描。
- 签名规范要求:受重定位表(Relocation Table)影响的动态修正字节(SEH 结构化异常处理器入口、
mov reg, offset寻址、IAT 导入调用)一律强制通配;E8/E9相对寻址指令(rel32)的操作数一律强制通配(该操作数虽不受 ASLR 影响,但跨版本重编译时位移必定发生改变)。 - 交付前由工程审计脚本
tools/aob_check.py直接解析多版本 PE 结构,校验特征签名的全局唯一性及重定位掩码覆盖率,完全脱离对外部逆向工具环境的单点依赖。
- 特征未命中则静默自禁用,贯彻原子性启停:
- 任一功能模块所依赖的关键特征码若未实现唯一命中,该模块必须整体拒绝挂载,并在运行日志中明确记录为「未启用 / 已搁置 / 不支持的游戏版本」。具备多重拦截点的复合模块(如 DoT 护盾结算、外观槽多人同步、技能冷却修复等)必须执行严格的原子性启停逻辑——要么全量部署,要么整体撤销,绝不允许残留半套拦截逻辑。
- 只读内存探测路径全面包裹 SEH 异常防护(
__try/__except):- 针对游戏内部未初始化指针或野指针的探测性解引用,一律通过结构化异常处理进行边界防护。偶发异常仅抛弃当前单帧计算,坚决杜绝进程崩溃。
- 由于 MSVC 编译器限制
__try块内不可存在依赖栈展开(Stack Unwinding)的 C++ 局部对象(编译器告警 C2712),所有直接访问游戏堆栈的底层叶子函数均被严格解耦为纯 POD(Plain Old Data)接口。
- 共享引擎全局常量遵循瞬态修改模式(Scoped Ephemeral Patching):
- 当需要修改引擎全局常量时,必须严格执行「读取并暂存原值 → 写入目标值 → 触发原版逻辑 → 立即恢复原值」的作用域局部修改模式,严禁长期常驻修改。
- 原因在于核心数值上限常量具有跨系统共享特征(例如闪避率上限与格挡率上限在引擎内部复用同一个
75.0浮点常量),全局常驻修改势必污染其他无关调用链。鉴于游戏核心战斗与 UI 渲染均运行于引擎主线程且原版算法无递归嵌套,该执行窗口在时间切片上完全免疫多线程并发冲突。
- 跨 CRT 堆对象生命周期严格委托游戏引擎原生接口管理:
- 原版游戏基于 VC90 编译构建并动态链接
MSVCP90.dll,而 Runtime 代理 DLL 基于现代 C++ 工具链编译,两者底层的堆分配器与 STL 容器内存布局物理隔离。 - 涉及跨模块交互的
std::wstring构造、赋值与析构必须显式从MSVCP90.dll导出表按符号修饰名动态导出并调用;新增CEffect对象必须调用引擎内存池分配接口(allocHolder);注销 Effect 对象必须调用引擎原生的expireEffects(将 duration 持续时间写入-900.0哨兵标记)。
- 原版游戏基于 VC90 编译构建并动态链接
- 多级分层运行期开关配置体系:
- 支持
mikuro_runtime.conf配置文件、游戏根目录标记文件与环境变量三种控制手段。 - 在工程实践中,文件系统标记文件具备最高可靠性:由于环境变量在经过启动器或 Steam 客户端多级进程派生调用时极易发生继承丢失(2026-07-25 实机测试踩坑坐实),底层关键模块的开关均以标记文件为首选硬件级断开机制。
- 支持
DLL_PROCESS_DETACH规避侵入式 Hook 卸载:- 在进程正常退出时,Windows 处于 Loader Lock 状态。此时强行挂起工作线程或撤销 MinHook 挂钩容易触发死锁或内存访问违例。代理 DLL 的生命周期与宿主进程完全绑定,统一由操作系统在进程销毁时完成资源回收。
- 前置核心总闸防护机制(Master Gatekeeper):
- 掉落物统一落地放置函数
sub_5EAA80与CItem的 RTTI 类型描述符构成本框架最核心的两条基础特征码。在InitThread执行期,若此二者未成功命中,初始化流程将立即终止返回,后续所有核心 Hook 一律放弃挂载。 - 仅有时序上排在总闸之前的先行模块不受其制约:包括两项启动性能补丁、VFS 探针、WASD 基础地址解析、外观槽多人同步以及冷却词条修复(上述模块均自备独立的特征码与自检校验器)。
- 掉落物统一落地放置函数
2. 装载时序机制(hooks.cpp InitThread)
模块装载顺序具有严格的因果依赖关系,必须依照以下时序流水线依序执行:
optfindfile::Install():挂载 VFS 文件检索哈希索引。该操作必须抢在 AOB 特征码全量扫描前完成:DllMain注入触发时,宿主游戏的数据加载线程往往已在数毫秒内拉起,若等待二十余条签名检索完毕则将错过热点加载窗口。由于该性能补丁与 VFS 探针均需拦截sub_68F630邻近区域,而 MinHook 不允许重复挂载同一入口,因此补丁模块享有绝对优先权。optunitscan::Install():挂载unittype全量扫描无用拷贝优化补丁。vfsprobe::Install():挂载 VFS 加载耗时探针(默认处于未装载状态)。ResolveEngine():启动全局 AOB 签名扫描,检索核心系统地址:道具落地函数、命名属性访问器、GUID 到实体定义映射器、本地化翻译表实例、资源管理器以及四大 RTTI 描述符。lf::LoadConfig():解析配置文件mikuro_runtime.conf(该配置必须在回放 WASD 状态前完成读取)。wasd::Init():仅动态解析 WASD 所需的两组内存指针并暂存,不挂载任何 Hook。MH_Initialize():初始化 MinHook 核心引擎;若初始化失败则整个 Runtime 立即终止。cosmeticmp::Install():挂载外观槽多人同步模块(自备独立 AOB 特征码与自校验逻辑,不依赖前置总闸)。skillcdfix::Install():挂载技能冷却词条生效修复模块(同样自备特征码与自校验逻辑)。- 依据配置项判定若
wasd == 1,则调用wasd::SetActive(true)执行延迟懒装载。 - 核心总闸安全判定:检查
pPlace或CItemRTTI 指针;若解析为空则打出警告日志并终止后续拦截安装。 - 挂载道具落地 Detour;注册掉落决议器探针(编译期宏默认关闭);注册走格探针(受标记文件门控);执行护盾 HUD 布局签名静态核验(零 Hook)。
- 挂载跨关卡不持久化地面掉落逻辑(拦截两组关卡序列化函数);挂载存盘/读档崩溃保护补丁。
- 挂载主动技能施放 Detour(百分比冷却缩减与宠物嘲讽令);挂载宝石镶嵌部位限制(两处拦截点);挂载宝石发光与传奇装备光晕渲染模块。
- 挂载诅咒/强化卷轴应用逻辑;挂载附魔迁移与剥离控制器(一次性注入 21 处底层原语地址)。
- 挂载
EFFECTSLIST数据加载器 Detour(必须先执行ResolveEffectArrays()扫描未被修改的原始函数体,再挂载 Hook,防止入口补丁指令破坏特征匹配)。 - 挂载属性重算防崩溃内联补丁;挂载暴击状态门控;挂载暴击吸血逻辑;挂载 Tooltip 描述信息子类型分流器。
- 挂载四大数值上限突破(减伤、暴击伤害、闪避率、格挡率)以及角色属性面板减伤数值同步补丁(面板同步复用减伤全局常量地址,因而严格排在减伤挂载之后)。
- 挂载 DoT 伤害护盾吸收结算补丁(要求三项底层符号全数命中,缺一不可)。
ResolveTaunt():预热检索嘲讽所需的四条辅助特征码(规避首次施法时在关键帧热点路径上全镜像扫码引发卡顿)。overlay::InstallD3D9Hooks():构建虚拟 Dummy D3D 设备以提取设备虚表(vtable),随后对虚表槽位挂载EndScene与Reset拦截点;走格可视化探针在此阶段一并挂载SetTransform。
3. 内存拦截与补丁实现总账
表格字段规范:
- 拦截方式:
detour表示基于 MinHook 的函数入口跳转拦截;内联表示在函数体内写入跳转中继(Code Cave / 补丁桩);改向表示仅重定向单个call rel32的相对跳转偏移;vtable表示劫持虚表函数指针;子类化表示通过SetWindowLongPtr劫持窗口消息处理过程。 - 未命中回退:记录特征签名不匹配或底层依赖缺失时的系统降级策略。
3.1 核心基础设施(注入与覆盖层渲染)
| 目标标识 | 拦截方式 | 源文件 / 入口点 | 功能职责 | 配置开关 | 未命中回退 |
|---|---|---|---|---|---|
Direct3DCreate9 / Direct3DCreate9Ex | 导出转发 | hooks.cppWrap_*、d3d9.def | 注入引导入口。优先动态加载游戏同级目录下的 d3d9_dxvk.dll(DXVK 运行库),若不存在则加载系统原生的 d3d9.dll;对其余 D3DPERF_* 接口执行无损透传转发。 | — | 底层 Direct3D 驱动加载失败时返回空指针。 |
IDirect3DDevice9::EndScene(虚表槽位 42) | vtable | overlay.cppHookEndScene | 仅在「当前渲染目标 == 主后备缓冲区(BackBuffer)」的调用切片内驱动 ImGui 绘制管线。每帧驱动:WASD 移动更新、走格探针更新、附魔面板关闭后 NPC 对话关闭兜底、宝石发光与传奇光晕绘制、走格网格透视投影、护盾 HUD 仪表、诅咒结果结算面板及主配置菜单。当捕获到底层设备重置(指针变更)时自动重新绑定 ImGui 后端。 | Home 键切换主面板显隐 | 无法构建 Dummy 设备时覆盖层禁用,其余 Hook 保持正常运行。 |
IDirect3DDevice9::Reset(虚表槽位 16) | vtable | overlay.cppHookReset | 在图形设备执行 Reset 之前强制释放 ImGui 占用的 D3DPOOL_DEFAULT 资源,在设备重置成功后重新构建显存资源(杜绝重置后引用野指针引发崩溃,大幅提升 DXVK 环境下的重置成功率)。重置时一并清空诅咒结算记录与宝石发光渲染缓存。 | — | 同上。 |
| 游戏窗口消息过程 | 子类化 | overlay.cppHookWndProc | 处理 Home 快捷键;面板展开时将消息分发给 ImGui。光标位于 ImGui 面板区域时强制吞掉全部鼠标输入(包含 WM_LBUTTONUP,若仅拦截按下事件会导致游戏角色被地面寻路逻辑唤醒移动),获取文本焦点时吞掉键盘输入;面板处于关闭状态时仅分发 WM_MOUSEMOVE 且不拦截消息(维持护盾条悬停提示所需的光标坐标更新)。严格规避干预系统光标状态(启用 NoMouseCursorChange),防止与引擎原生的 SetCursor 产生竞态闪烁。 | — | — |
IDirect3DDevice9::SetTransform(虚表槽位 44) | vtable | gridprobe.cppDetour_SetTransform | 拦截并捕获引擎的 VIEW 与 PROJECTION 变换矩阵,供 F10 快捷键在场景地表投影绘制可视化走格网格。仅在显式启用走格探针时动态挂载;探针未激活时函数体仅保留单次布尔判断。 | 详见 §3.11 | 探针未挂载时不实施拦截。 |
3.2 原版缺陷托底(稳定性与正确性修复)
此类补丁旨在修复原版可执行文件的程序实现缺陷,完全不干预原版预期的游戏机制设计;在不加载任何 MOD 的纯原版环境下依然能够显著提升系统稳定性。
| 目标标识 | 拦截方式 | 源文件 / 入口点 | 缺陷根因与修复实现方案 | 配置开关(默认) | 未命中回退 |
|---|---|---|---|---|---|
存档编码器 sub_680DC0(关卡过渡 / 存盘序列化) | detour (Naked 桩函数) | hook_savefix.cppDetour_Scramble | 缺陷机理:原版底层在序列化期间连续执行两次 malloc(bodyLen),且未对返回指针做任何空指针校验。在大容量背包或大仓库 MOD 环境下,存档数据显著膨胀,32 位进程地址空间极易触发内存耗尽(OOM)。解引用空指针直接引发进程崩溃,表现为「过图切关卡时瞬间闪退」。修复实现:入口桩函数预先利用 VirtualAlloc 分配独立临时缓冲区并安全完成数据加扰,将内部状态位标记为 flag = 1,随后无条件跳转回原函数;原函数检测到 flag == 1 时在执行 malloc 之前即刻提前返回,既避免了原版内存二次分配崩溃,又安全利用原函数析构了以值传递的 std::wstring 临时变量。数据峰值内存消耗由 $2 \times \text{body}$ 骤降至 $1 \times \text{body}$。 | saveFix(默认开启,关闭即完全等价于原版行为,供故障比对) | 签名未命中则跳过修复,记录警告日志 [W]。 |
存档解码器 sub_681210(读档反序列化) | detour (Naked 桩全量替换) | hook_savefix.cppDetour_Descramble | 缺陷机理:解码端同样存在双 malloc 缺陷,在 OOM 状态下直接调用 memset(NULL) 引发硬崩溃,表现为「选择角色载入或打开储物箱时闪退」。由于原函数在执行 malloc 之后才判断状态位,入口桩无法直接借用其退出路径,必须实施全量替代。修复实现:流式解密过程中同步计算 djb2 校验和,严格确认校验和无误后方才提交明文数据并主动析构 std::wstring 返回 1;遭遇 OOM、校验和失配、异常存档版本或文件 IO 错误时一律拒绝提交,跳转至原函数降级执行(完全复刻原版异常行为)。该算法与 tl2-save-toolkit 工具链在字节级一致,经 1,200 个合成存档与 21 个生产真实存档校验实现零误差。 | 同上 | 同上。 |
CEffect 属性缩放求值循环 sub_7A6530( fmul 指令前 27 字节) | 内联 Code Cave | hooks.cppInstallEffScaleGuard | 缺陷机理(2026-07-29 经 5 份实机 Crash Dump 与动态探针证实):在 recomputeStats 遍历 Effect 链表执行属性重算期间,同帧失效过期的 Buff 或词缀注销操作会提前释放当前正在被求值的 CEffect 对象内存。外层循环携带已析构的悬垂 this 指针执行 fmul dword ptr [eax] 指令解引用空指针崩溃。该竞态概率与词缀销毁频次正相关,在多被动技能或高频触发词缀的构筑中呈极高发病率。修复实现:补丁必须打在循环体求值流程内部(此时对象在入口时尚未析构),注入内联桩校验 [esi+104h] 是否已置零;若检测为已释放的悬垂状态,则将乘数修正为 0.0f(严禁修正为 1.0,st0 寄存器中存有基础属性值,乘 1.0 会误将已销毁的词缀按 100% 权重结算)。正常健康数据下绝不满足触发条件,不干涉底层内存分配生命周期。 | 无开关 (致命崩溃修复,必须强制常驻) | 签名未命中则拒绝安装,记录警告日志 [W]。 |
CUnit::executeInstantEffectCase 216 与 Case 217 尾部 | 内联 30 字节补丁桩 ×2 | skill_cd_fix.cppCdApplyAll | 缺陷机理:Case 216(MODIFY SKILL COOLDOWN REMAINING)与 Case 217(SET SKILL COOLDOWN REMAINING)原版在处理技能冷却变更时,仅调用 findSkillByName 获取同名技能链表的首个实例 list[0]。但在技能连招或连续施法过程中,原技能实例若仍在活动队列中,引擎会自动克隆生成新的 CSkill 实例(克隆体常驻不会被立即销毁)。若当前正在冷却的是克隆体,原版修改的却是早已冷却完毕的基准实例,直接导致玩家观察到「冷却缩减词条完全失效」;该异常随世界刷新或重启进程恢复,但在地图切换或洗点时持续存在。修复实现:重写两处 Case 出口,压入 4 项参数调用 CdApplyAll,根据定义指针(CSkill+0x10)递归遍历活动表与基准表内的全部同技能实例:MODIFY 执行累加运算,SET 执行直接赋值,负数及 NaN 异常值自动归零纠正;仅当实例原先未在活动表中且冷却时间由 $\le 0$ 跃迁为 $> 0$ 时方才调用 pushActiveSkill(防止重复入表导致每帧双倍衰减);顺带根治了 SET 0(强制移除当前冷却)以往遗漏克隆体的问题。装载期安全自校验:两处补丁点必须各自唯一命中,且解析出的 3 组内部引擎函数地址完全一致, findSkillByName / setCooldownRemaining / pushActiveSkill 函数体经逐字节签名比对完全吻合,任一校验失败则整体放弃注入。 | 标记文件 mikuro_no_skill_cd_fix.txt或环境变量 MIKURO_SKILL_CD_FIX=0 可手动关闭 | 命中数 $\ne 1$ 或自校验不通过则不修改任何字节。 |
技能冷却词条修复说明:该模块最初于 2026-09-05 通过独立补丁器
tools/tl2_cdfix_patch.py生成二进制补丁 Exe 供玩家测试通过,随后移植为当前动态拦截模块,底层逻辑逐字节完全等价。截至本文档首版,该模块的最终挂载接线在工作区处于就绪状态。
3.3 原版机制修正(战斗与数值逻辑矫正)
此类补丁旨在矫正原版底层逻辑的固有设计缺陷,属于机制行为层面的修正。默认处于启用状态,可通过 mikuro_runtime.conf 独立关闭。
| 目标标识 | 拦截方式 | 源文件 / 入口点 | 缺陷根因与修复实现方案 | 配置开关(默认) | 未命中回退 |
|---|---|---|---|---|---|
护盾吸收结算 sub_51FEB0( CUnit::consumeAbsorbBuffers)+ 回血/DoT 轮询 sub_53C2F0( CUnit::tickHealthRegenAndDoT);网络权威查询 sub_511AC0( CUnit::isLocallyAuthoritative,只读调用) | detour ×2 | hooks.cppDetour_DotAbsorbDetour_DotTick | 缺陷机理(汇编指令级实证):原版吸收函数的第四参数并非控制「是否吸收伤害」,而是控制「是否真实扣除护盾容量池」(bCommit 标志)。在 DoT 结算路径(computeNetHealthDeltaPerSec)中,该参数被硬编码恒传为 0。这一设计引发了两个相反方向的严重缺陷:① 同属性护盾绝对无敌:若护盾吸收类型与 DoT 属性匹配,吸收函数只减免伤害却从不扣除护盾池(如工程师力场自带 DAMAGE_TYPE:ALL,在持续 30 秒内对任何属性 DoT 处于事实上的无限吸收无敌状态);② 异属性护盾完全穿透:若护盾属性不匹配,DoT 伤害将直接穿透护盾攻击本体生命值(例如法师余烬护盾属于 PHYSICAL 物理通道,而燃烧 DoT 走 FIRE 通道,吸收率为 0;DAT 数据未定义 DAMAGE_TYPE 时引擎默认按 PHYSICAL 物理结算,导致绝大多数 MOD 自制护盾面对元素 DoT 全额穿透)。玩家社群反馈的「DoT 穿盾」本质上即为此缺陷。修复实现:在 Detour_DotTick 中捕获并记录当前帧时间步长 $\Delta t$;在 Detour_DotAbsorb 中仅接管满足 self == 正在轮询的单位 && bCommit == 0 && dt > 0 条件的 7 次通道轮询:以伤害速率 $\times \Delta t$ 得到当前帧真实伤害 $\rightarrow$ 在对应属性通道内真实扣减护盾池 $\rightarrow$ 未被完全吸收的余量在通道 0(物理)执行物理护盾兜底吸收(精准复刻直接物理伤害路径的「物理护盾通吃」判定)$\rightarrow$ 将吸收结果除以 $\Delta t$ 还原为引擎内部的速率语义;通道 6 为轮询终点,结算完毕后立即关闭当前帧判定窗口。联机状态下护盾池扣除严格遵循 isLocallyAuthoritative 判定,非权威客户端仅抵扣本地伤害而不变动权威护盾池。已知系统影响边界:若游戏设置中开启了 COMBAT LOG,每帧每个通道均会输出一行结算日志;怪物自身的通用护盾(通常为 ALL 类型)亦会被 DoT 伤害正常击破;至于直接写入生命值而不经由吸收管道的生命流失效果(Effect 185, HP MOD OVER TIME),不在本拦截覆盖范围内。 | dotShield(默认开启,关闭则原样放行原版逻辑) | 三项底层符号若缺失任一,则整套拦截逻辑完全放弃安装。 |
3.4 MOD 兼容托底(数据透明性与多人互通)
此类补丁在原版数据环境下保持逐位等价,仅在特定 MOD 加载并激活非原生数据结构时提供底层行为兼容。
| 目标标识 | 拦截方式 | 源文件 / 入口点 | 缺陷根因与修复实现方案 | 配置开关(默认) | 未命中回退 |
|---|---|---|---|---|---|
CUnit::sendInventoryToPeer( 0x535940)+ 三处 call 指令重定向:P0: CInventoryContainer::collectItems+0x5E(唯一一处 call isEquipable);P1: broadcastItemPlacement(选择消息类型分支); P2: 同函数计算 msg+60 衣柜标志处 | detour ×1 + 改向 ×3 | cosmetic_mp.cppDet_SendInvPred_NetCollectPred_MsgSelectPred_WardrobeFlag | 缺陷机理:外观装备槽 MOD(如 cosmetic_slots)通常将 6 个身体护甲槽位的数据属性配置为 EQUIPABLE:false 以作为纯外观位。然而,游戏引擎底层将 EQUIPABLE 标志作为判定「是否属于有效真实装备位」的唯一基准,同时联动控制属性生效、套装计数、属性需求校验以及网络数据包序列化广播。这导致外观槽内的物品在发送端直接被网络同步逻辑剔除,其他联机客户端无法接收外观装备数据,表现为联机时角色模型呈裸体状态。修复实现:仅在发送端放宽上述三处条件分支判定,接收端代码完全保持原样(接收端底层原生支持将道具存入 EQUIPABLE:false 的槽位,且仅在 isEquipable 为真时附加词缀属性,这与外观槽的设计语义完全一致)。放宽判据严格收敛为「目标槽位的硬编码装备位是否落在护甲六槽(索引 3 至 8)」,坚决规避使用宽泛的 != 0 判定(否则将误将索引 13 的 POINTER 光标拖拽悬空槽纳入广播,导致原版行为受损)。P0 拦截点受到严格的 TLS 线程局部存储作用域控制(仅在 sendInventoryToPeer 调用栈上下文内放宽条件,规避污染 collectItems(equippedOnly=1) 在引擎内部的其余二十余处本地调用)。装载期安全自校验:三处修改点必须为 call 指令且跳转目标与动态扫描到的属性访问器绝对一致;两处锚点距离必须严格等于 0x164。 | 标记文件 mikuro_no_cosmetic_mp.txt或环境变量 MIKURO_COSMETIC_MP=0 可手动关闭 | 七项特征签名缺失任一,或自校验未通过,则不写入任何补丁字节;Hook 挂载失败则整体撤销。 |
3.5 启动性能优化补丁(算法与内存流重构)
此类补丁始终保持开启,不提供运行时开关。其核心原则为「严格复刻原函数的全部逻辑分支与对外语义,仅对耗时瓶颈算法进行重构或剥离汇编级死代码」。基准数据取自加载 9 款主流 MOD 的 VFS 探针实机采样。
| 目标标识 | 拦截方式 | 源文件 / 入口点 | 优化机理与算法实现 | 实测吞吐收益 | 失败回退策略 |
|---|---|---|---|---|---|
PackageMgr::findFile目录内条目线性遍历 sub_68F630 | detour | opt_findfile.cppDetour_FindFile | 优化机理:原版在检索 VFS 虚拟文件系统时,对目标目录内的每一个项循环执行 std::operator== 字符串比较,平均单次查找需全量遍历 1,275 个条目,耗时占整个函数执行时间的 95%。算法实现:重构循环体检索策略:仅当目录条目数超过 256 时,自适应构建基于 (hash, original_index) 的排序二分检索索引,检索命中后再精确复核文件名与标志位,严格维持「返回首个匹配项」的原版语义;当桶内条目数发生变动时自适应重构索引。针对目录缺失的冷路径依然回退调用原函数。辅助函数地址均直接从 findFile 函数体内的内部 call 相对偏移反解(规避独立签名因绝对重定位地址差异在 Steam 数字版上失效的问题)。 | 检索耗时: 1,173 ms → 88 ms | 签名或内部 call 寻址失败则拒绝启用;Hook 冲突(MH_ERROR_ALREADY_CREATED)或索引分配异常时置入中毒标志,自动回退至原版线性查找。 |
unittype 体系全量扫描 sub_65DC90 | detour | opt_unitscan.cppDetour_UnitScan | 优化机理:原版在中序遍历两层红黑树时,对遍历到的每一个节点均盲目执行一次 std::wstring 拷贝构造与析构。汇编级审查证实该临时变量自始至终未被后续指令读取,属于完全的死代码;由于单位类型字符串长度普遍 $\ge 8$ 字符,超出了 VC9 STL 的 SSO(小字符串优化)7 字节容量上限,每次拷贝均在堆上触发一次昂贵的内存分配与释放。算法实现:逐指令级复刻原函数遍历逻辑,精准剔除两处无用拷贝构造与析构指令。该优化不仅作用于启动期,亦加速运行期的 Tooltip 动态构建与掉落生成。 | 扫描耗时: 726 ms → 49 ms; 数据加载总耗时: 3,874 ms → 3,296 ms | 同上。 |
DAT 属性名哈希计算 sub_4C9FE0 | — | opt_dathash.cpp(代码保留,未接入) | 实现位级等价的快速哈希算法,通过了 25/25 项静态自检与 16,384 次影子比对验证。 实测结论:吞吐收益为 0(1,349 ms → 1,349 ms)。原因在于原方案高估了 MSVCP90 中 length() 与 operator[] 的调用开销,哈希计算在整体属性读取耗时中占比不足 4%,属于非瓶颈路径。源码保留作为算法参考。 | 收益为 0 | — |
影子验证机制的移除说明:两项优化补丁在早期版本中均集成了运行期影子验证(在过渡窗口内同时执行新旧路径并比对返回指针)。在历经数百次启动测试保持零失配后,为消除冗余开销已于 2026-08-17 彻底移除影子分支,单次启动进一步节省约 38 ms。其维护代价在于:运行期不再提供自动容错交叉比对,后续针对新版游戏执行适配时,必须严格依照 AOB 审计流程核对特征命中、内部 Call 偏移及结构体位移。
3.6 掉落生命周期过滤(道具生成与序列化控制)
该模块为 Runtime 最早落地的核心系统(2026-06-25 首版实现),用于在游戏底层拦截垃圾道具的实例化与持久化。
| 目标标识 | 拦截方式 | 源文件 / 入口点 | 功能实现与过滤管线 | 配置开关(默认) | 未命中回退 |
|---|---|---|---|---|---|
掉落物统一落地入口 sub_5EAA80( CLevel 放置实体,全场景掉落汇聚点) | detour | hooks.cppDetour_Place | 实现机理:在道具实体被加入关卡前读取活跃 CItem 内存指针(偏移 +0x110 道具等级、+0x1AC 单位类型 ID、+0x1A0 GUID 标识符)。判定符合过滤规则时直接阻断调用原函数,使道具永不落入场景。实体合法性三级过滤门: ① RTTI 类型安全校验:确保指针满足 is-a CItem;② 单位类型预置表校验:检查是否命中硬编码内置道具表(140 条)或排除非道具表(158 条); ③ 动态类型回退:对于 MOD 动态注册的未知类型,动态查询引擎内部的 unittype 注册表二叉树,严格确认满足「引擎层级继承自 ITEM」且排除 CBreakable(可破坏物)与 CTriggerUnit(环境触发器),防止等级过滤误删宝箱或机关导致场景缺损。名称与本地化解析:根据 GUID 调用 sub_65FDE0 获取持久化定义节点,调用 sub_677F00 提取 DISPLAYNAME(落地点生成的临时定义节点数据不完整,NAME 字段在落地后方被填入);中文名称直接从内存中的 CStringTranslate 键值树读取,真实反映 MOD 加载覆盖优先级。规则判定优先级:道具名称白名单 > 道具名称黑名单 > 单位类型白名单 > 单位类型黑名单 > 稀有度阈值 > 需求等级下限; QUEST* 任务道具对除 blockQuest 之外的所有过滤规则享有绝对豁免权。 | enabled(默认开启)logOnly(默认开启:仅记录日志不实际拦截,供观察验证)具体黑白名单与等级见 §4.1 | 核心总闸:若该函数特征未命中,整个 Runtime 后续所有核心 Hook 均放弃挂载。 |
关卡存盘逐实体序列化 sub_5FF570与其孪生函数 sub_5FF630(仅被关卡状态持久化 sub_5C51A0 内部调用) | detour ×2 | hook_b.cppDetour_Ser0Detour_Ser1 | 实现机理(架构代号 Hook B):在关卡切换触发地图数据序列化时,针对地面真实掉落物(满足 is-a CItem 且严格排除 CTriggerUnit 与 CBreakable)直接跳过其存盘序列化流程。当玩家重新返回该关卡时,地面残留掉落已被自然清除。该逻辑仅跳过存盘编码,不释放活跃对象,内存开销为零。边界防护:早期误在角色存档函数 sub_435E10 挂载的实现会导致玩家装备丢失,已彻底纠正;2026-07-12 补全了触发器与可破坏物排除逻辑,杜绝了此前因任务门开启状态未被持久化导致回图时任务门重新锁死的缺陷。 | clearOnTransition(默认关闭) | 签名未中或三项 RTTI 描述符缺失任一,则强制禁用该模块(杜绝误锁任务门)。 |
掉落决议探针 sub_6FCA10(只读调用点探针) | — | hooks.cppDetour_LootResolve | 作为掉落生成链路验证探针开发,用于统计各 TREASURE_MONSTERLOOT_* 掉落表的命中频次,验证按名称检索道具原型的可行性。 | 编译期宏控制:MIKURO_LOOT_HOOK_ENABLED=0(2026-07-25 起整条技术路线搁置,转为优先分析原版数据配置) | — |
3.7 死槽 131 自定义效果体系(属性多路复用与突破)
原版引擎 EFFECTSLIST.DAT 中的第 131 项 FUTURISTICNESS 在原版所有基础数据和词缀中均未被引用。Runtime 将该未分配槽位作为多路复用信道:利用 VALUE3(结构体偏移 CEffect+0xE4)作为 SUBTYPE 子功能选择器,在单一 Effect 类型下派生扩展出数十种自定义战斗与机制效果。
数值提取路径统一标准化为:遍历角色装备栏本体及其镶嵌灵石的内部效果管理器(CItem+0x1B4),累加所有满足 type == 131 && VALUE3 == 目标子类型 的 VALUE(偏移 +0xD4)数值。统计范围严格限定于主装备槽及所有挂载有 EQUIPABLE 标志的子容器,排除行囊与共享储物箱,基于 CItem 指针执行去重计算,并维护 500 ms 的瞬态缓存。
SUBTYPE 子功能号段分配表(新增或调整效果必须首先在此分配):
| 子类型号 | 功能语义 | 挂载载体 | 消费与生效模块 |
|---|---|---|---|
| 1 | 暴击吸血百分比(%) | 装备本体 / 灵石 | Detour_ModHP + Detour_RollCrit |
| 2 | 宠物嘲讽光环半径(米) | 宠物项圈 | Detour_SkillAct → PetTauntFor |
| 3 | 技能百分比冷却缩减(乘法叠乘) | 灵石 | Detour_SkillAct;镶嵌孔位规则限制 |
| 4 | 伤害减免上限突破(+) | 灵石 | Detour_DmgCap / Detour_DmgCapPanel |
| 5 | 暴击伤害倍率上限突破(+) | 灵石 | Detour_CritCap |
| 6 | 闪避几率上限突破(+) | 灵石 | Detour_DodgeCap |
| 7 | 格挡几率上限突破(+) | 灵石 | Detour_BlockCap;镶嵌孔位规则限制 |
| 8 | 保留空闲 | — | — |
| 9 | 消耗品标记:卷轴「鬼工·乱铸」 | 消耗品 | curse.cpp |
| 10 | 消耗品标记:卷轴「天工·强化」(VALUE5 > 0 标识启迪模式) | 消耗品 | curse.cpp |
| 11 | 装备词缀账本:诅咒记录(VALUE4 已用次数 / VALUE5 上限) | 装备本体 | curse.cpp |
| 12 | 装备词缀账本:强化记录 | 装备本体 | curse.cpp |
| 13 | 保留空缺(原计划开发「归真」以撤销诅咒,已作废:确立诅咒不可逆设计原则) | — | — |
| 14 | 消耗品标记:卷轴「天工·返璞」(移除强化)—— 仅占位,尚未实现底层逻辑,仅含 Tooltip 文本预置 | 消耗品 | — |
历史机制沿革说明:在 2026-07-16 架构重构前,冷却缩减原由
SOCKS(Type 133)承载,目前已全量收拢至 131/3;源码中遗留的GemSocksValue等函数命名属于历史兼容符号,实际判定语义均以当前代码为准。
死槽 131 拦截与消费实现清单:
| 目标标识 | 拦截方式 | 源文件 / 入口点 | 功能实现与运行逻辑 | 配置开关 | 未命中回退 |
|---|---|---|---|---|---|
主动技能激活 sub_6C39E0( CSkillActivation::Activate) | detour | hooks.cppDetour_SkillAct | ① 动态冷却缩减:原版将本次计算所得的冷却时间写入结构体 this+0xF0。Detour 拦截后,提取角色所穿戴灵石的乘法因子 $\prod(1 - v/100)$ 进行乘积缩减,硬编码保底时间下限为 0.1 秒(杜绝除零或无限连发),不设游戏性数值硬顶;技能就绪状态检测与 UI 技能栏转圈冷却动画均直接读取该字段,表现高度自洽。仅当施法者 RTTI 为 CCharacter 时生效。② 宠物嘲讽指令:若技能名称包含「御兽」或标识符 MIKURO_AZURE_CHAOFENG,则检索施法者(支持宠物自主施法或继承旧档机制)周围 10 米范围内存活且具备有效 AI 的敌方目标,调用 setTarget(mon, pet) 并通过 CAIManager::setFlag(5, 4.0s) 施加 NEVER CHANGE TARGET 强制仇恨锁定;宠物必须佩戴 131/2 装备方被视作合法嘲讽主体;自动排除玩家及友方召唤单位。底层复用 setTarget(sub_524AF0)、setFlag(sub_701590)、getPosition(sub_61DCE0)及全局单例获取接口 sub_41CE60。原有的 T 键物理快捷键因绕过技能消耗与冷却已于 2026-08-08 彻底移除。 | 数据侧驱动(取决于装备是否存在对应效果) | 特征未命中则技能冷却与嘲讽效果维持原版行为。 |
暴击判定入口 sub_52AC60( rollCritical) | detour | hooks.cppDetour_RollCrit | 记录「本次命中是否触发暴击」与「当前攻击发起者指针」两组全局上下文变量,为后续吸血计算提供原子化门控。原函数负责弹出 Critical 战斗跳字、分发联机网络数据包及播放暴击光效,在 applyDamage 实际扣血前被调用。 | — | 特征未命中则暴击吸血降级为无门控的常规普攻吸血。 |
实体生命值变更 sub_53BC80( modifyHealth) | detour | hooks.cppDetour_ModHP | 优先放行原版扣血逻辑;若检测到满足 delta < 0 && a5 == 刚判定暴击的攻击者 && 攻击者装备包含 131/1,则计算 $\lvert delta \rvert \times \text{pct}%$,重新调用原函数对攻击者实施生命恢复(内置递归重入防护锁),并当场消费复位暴击标志(防止同攻击者后续的多段非暴击 DoT Tick 误触发吸血)。 | — | 特征未命中则吸血机制整体禁用。 |
减伤上限计算 sub_522AE0 | detour + 瞬态改常量 | hooks.cppDetour_DmgCap | 原版针对玩家单位将 PERCENT DAMAGE TAKEN 减伤词条的累加值硬封顶于 $-75.0%$(浮点常量 flt_2170218,比较分支与写入赋值共用该地址)。若受击玩家装备挂载有 131/4 效果,则瞬时将常量值覆写为 $-\min(75 + futu, 95)$ $\rightarrow$ 调用原版求值函数 $\rightarrow$ 立即恢复原始常量。硬编码 95% 上限以防免伤无敌;怪物单位继续走原版基准路径。 | 数据侧驱动 | 特征未命中或常量寻址异常(提取值非负)则禁用上限突破。 |
属性面板减伤数值获取 sub_51AD60 | detour + 瞬态改常量 + 瞬态改立即数 | hooks.cppDetour_DmgCapPanel | 独立拦截动因:原版角色面板所显示的减伤比例经由独立的 Getter 函数计算,当检测到数值 $v < -75.0$ 时,直接执行 return 75(该 75 在机器码中体现为硬编码立即数 mov edi, -75)。为促使属性面板如实展示 $\min(\text{真实减伤}, cap)$,必须在调用切片内对浮点常量 flt_2170218 与汇编立即数实施双重瞬态修改:若仅改浮点阈值,当实际减伤超过上限时面板依然卡死在 75;若仅改立即数,处于 75 至新上限之间的过渡区间会被错误放大拔高。已知显示特性:面板仅支持整型渲染,当上限为 77.5% 时向下取整显示为 77%。 | 数据侧驱动 | 减伤常量未解析则跳过;特征或立即数寻址失败仅禁用面板显示同步,不影响实际战斗承伤计算。 |
暴击伤害倍率获取 sub_521020 | detour + 瞬态改常量 | hooks.cppDetour_CritCap | 原版将暴击伤害倍率硬截断于 $[0, 500]$ 区间(浮点常量 flt_2141E00)。攻击方玩家若装备 131/5 效果,则将上限动态调整为 $500 + futu$,且不设硬性天花板(标准灵石每颗提供 +20%)。由于暴击倍率与闪避率的 Getter 函数序言机器码高度同构,旧版特征码因直接绑定绝对内存地址导致在 ASLR 下从未成功装载(2026-07-22 修复):现采用统一特征码 ScanAll 扫描,根据入栈操作数所指向的宽字符串字面量 CRIT_BONUS 与 DODGE_CHANCE 实现精准分流。 | 数据侧驱动 | 入口未命中或常量非正数则禁用扩展。 |
闪避几率计算 sub_520F10 | detour + 瞬态改常量 | hooks.cppDetour_DodgeCap | 原版玩家闪避率被限制为 $\min(dodge, 75)$(浮点常量 flt_2170884,此常量在引擎内部被三处逻辑跨系统共享,因此必须严格采用局部瞬态修改)。若装备 131/6 效果,上限提升至 $\min(75 + futu, 95)$(每颗标准灵石提供 +2.5%)。闪避判定在引擎底层仅对近战武器攻击生效。 | 数据侧驱动 | 同上。 |
格挡几率计算 sub_524090( getBlockChance) | detour + 瞬态改常量 | hooks.cppDetour_BlockCap | 复用上述 flt_2170884 共享常量;装备 131/7 效果时,上限提升至 $\min(75 + futu, \mathbf{85})$。格挡上限之所以严于闪避,是因为格挡在近战攻击与通用伤害管线中均会触发投骰,对技能、投射物、范围伤害(AOE)、持续伤害(DoT)及反弹伤害均具有全额格挡效果。汇编调用约定特殊性:该函数返回整型(三个返回出口均跳转至 jmp __ftol2_sse),且无栈参数直接以 retn 0 退出——若误按其他浮点 Getter 编写 retn 4 桩函数将导致堆栈指针破坏与返回值错乱。 | 数据侧驱动 | 同上。 |
宝石镶嵌合法性校验虚方法 sub_7CBCC0(高亮显示与落孔共用) | detour | hooks.cppDetour_CanSocket | 原函数在校验时仅检查 SOCKETABLE、空插孔及固定大类,底层完全不解析词缀数据中的 NOT_UNITTYPES 规则(实机断言证实),导致在数据层对宝石限制镶嵌部位无效。疾速灵石(131/3)限制为:武器(8)、头盔(12)、护手(23)与盾牌(21),每件装备限镶 $\le 2$ 颗(双手武器 10 判定为可镶 4 颗);格挡灵石(131/7)限制为相同四类,不设颗数上限(85% 绝对上限构成天然天花板)。判定对象依据宝石自身的 EffectMgr 是否挂载对应 SUBTYPE,免去硬编码 GUID 清单。部位判定调用 sub_511FA0 IsUnittype。 | 数据侧驱动 | 特征未命中则限位失效(回退为全部位自由镶嵌)。 |
拖拽落孔放置动作 sub_7CCC50(虚表槽位 13) | detour | hooks.cppDetour_SocketDrop | 必须在此虚函数入口点直接截断并执行 return 0:原版内部实现为先执行插入逻辑,紧接着无条件从源物品中销毁移除源宝石;若在更底层的子流程进行拦截,会导致「宝石插入被阻断,但源宝石依然被强制扣除销毁」的吞宝石致命缺陷(实机测试曾两次踩坑坐实)。 | 数据侧驱动 | 特征未命中则落孔拦截失效,仅保留高亮提示。 |
EFFECTSLIST 数据加载器 sub_401000 | detour | hooks.cppDetour_EffLoad | 原加载器负责将 EffectsList.dat 结构反序列化为 SoA(结构体数组)全局内存表(每个字段一张数组、共 239 项、每项容纳 0x1C 字节的 std::wstring)。Detour 在原版加载完毕后,直接调用游戏 CRT 的 wstring 接口,在内存中动态修改 FUTURISTICNESS 对应的 NAME、GOODDES、GOODDESOT、BADDES、BADDESOT 及 DISPLAYPRECISION 字段为自定义说明文案——彻底脱离了对全局 EFFECTSLIST.DAT 物理文件的覆盖式分发依赖(杜绝了多 MOD 冲突覆盖)。7 组内部数组基址通过解析加载器函数体内的 lea ecx, [edi+ARR]、mov [esi*4+ARR] 及 fstp [esi*4+ARR] 指令操作数动态提取,取代早期硬编码 RVA。安装若滞后于数据加载,则在挂载瞬间强制触发一次覆写。 | — | 特征未命中则效果描述文本维持未汉化原状(回退依赖外部物理文件补丁)。 |
词缀 Tooltip 文本生成 sub_7A70B0( CEffect::buildTooltipDescription) | detour | hooks.cppDetour_BuildTip | 引擎对每种 Effect 类型在全局描述表中仅分配一条模板,而 131 承载了多套子效果。原函数构造好基础描述后,若检测到 type == 131,根据 VALUE3 调用 SetGameWStr 覆写输出内容:1 至 7 号子类型各自映射为独立的动态数值描述;9、10、14 号卷轴覆盖为其专属说明(消耗品道具在引擎中确实会强行渲染其内部携带的 Effect 描述行,2026-08-16 实机截图确认,若不实施拦截会荒谬地展示出「暴击时吸取 0% 伤害为生命」的死词缀);11 与 12 号账本读取 VALUE4/VALUE5 格式化为「已用/上限」进度;其余非法子类统一输出「Mikuro 自定义效果 #n」兜底。 | — | 特征未命中则回退至引擎全局模板文本。 |
3.8 卷轴与附魔渠道扩展(自定义打造管道)
该系统在数据侧依托 tl2-mikuro-runtime-mod(定义新增打造 NPC、自制 .LAYOUT 交互界面与卷轴物品),在引擎侧由本模块提供拦截支持。原生逆向工程报告沉淀于该仓库的 docs/ 目录。
| 目标标识 | 拦截方式 | 源文件 / 入口点 | 功能实现与运行逻辑 | 配置开关 | 未命中回退 |
|---|---|---|---|---|---|
动态效果施加入口 sub_583080( CEquipment::ApplyDynamicEffect,右键卷轴点选目标装备触发;装备鉴定、祛魔、附魔均由此虚方法分发) | detour | curse.cppDetour_ApplyDynEffect | 判定施加的 Effect 是否为 131/9 或 131/10;若非本系统效果则无损放行原版逻辑。 乱铸机制(子类型 9):遍历目标装备的三个 Effect 链表,跳过 Type 131 及 238(引擎内置的「作弊装备」标记),将普通词缀的 VALUE、VALUE1、VALUE2 按 $[0.7, 1.3]$ 浮点随机数执行缩放,基础攻击、防御与伤害加成同步浮动 $\pm 30%$;已锻造次数记录在装备自身的账本 Effect(子类型 11)中随存档持久化,默认上限 3 次(支持数据驱动,优先采纳账本的 VALUE5);达到上限时返回 0 $\rightarrow$ 原版判定为施加失败 $\rightarrow$ 不扣除消耗品卷轴,弹出橙色失败警告提示。若装备尚未建立账本,有意调用一次原函数利用其 default 分支将卷轴内部的 Effect 深度拷贝至装备上,随后就地将其属性重写转化为正规账本。强化机制(子类型 10):若 VALUE5 > 0 判定为「启迪」模式(激活隐藏潜能,默认策略取大值),若为 0 则作为常规强化处理,附加带有 MIKURO_ 前缀的新增词缀(命中原版同名词缀时遵循同名顶替规则)。不可撤销设计决策:底层确立「诅咒不可逆」原则(重 Roll 算法基于全局随机源且不持久化种子,二次重 Roll 必将生成另一组词缀;禁止引入「附加负面词缀」作为惩罚——Tooltip 合并机制仅比对 Type 而忽略名称,会导致负面词缀与原有词缀异常合并为单行)。操作完成后调用 CEffectMgr::invalidateTooltipCache(sub_7ADD60)刷新视图。锻造结果面板采用 ImGui 自主渲染(呈现锻造前后属性对比,数值增涨显示为绿色,数值衰减显示为红色,12 秒平滑淡出),完全抛弃原生 Tooltip 渲染(原生 Tooltip 显示值经由等级曲线换算,与写入内存的真实数值存在系统性偏差)。 | 编译期宏控制:CURSE_MUTATE_ENABLED=1(置 0 则仅输出调试内存 dump,不执行数据变更) | 特征未命中则模块整体禁用;invalidateTip 未命中会导致 Tooltip 延迟至下一次交互事件方才更新。 |
存档记录反序列化 0x591CB0( CEquipment::loadFromSaveRecord) | detour | curse.cppDetour_LoadFromSaveRecord | 原版存档在反序列化期间不保证 Effect 链表的原始顺序,读档后装备账本往往被置于链表末尾(导致 Tooltip 中「已诅咒 N/次」的标注行从基础属性下方下坠至描述最底端)。Detour 在原版恢复完 Effect 之后,强制执行重排序逻辑将账本 Effect 重新置顶。该函数序言包含 and esp, -64 栈 64 字节对齐指令,MinHook 能够原生兼容处理。 | — | 特征未命中则诅咒机制正常运行,仅读档后 Tooltip 提示行排版下移。 |
打造状态机判定 0x7429A0( CEquipmentModifierController::updateCanCombine) | detour | enchant_transfer.cppDetour_UpdateCanCombine | 原版合成师交互界面由该控制器统一调度,菜单、槽位与容器完全依托数据驱动。Runtime 的 4 套自制 .LAYOUT 界面复用此控制器,Detour 优先比对当前菜单的标识符后执行精准分流:MIKURO_ENCHANT_TRANSFER(双槽词缀迁移)、MIKURO_ENCHANT_STRIP(单槽词缀移除)、MIKURO_BLESS(神明祝福)、MIKURO_UNBLESS(神明涤除);若不属于上述标识符则无条件回退调用原版逻辑——确保原版合成师、附魔师与宝石拆解功能不受丝毫干扰。原版依据配方匹配控制按钮高亮,本系统根据专属业务规则分发 402/403 交互事件。 | — | 8 处核心依赖地址若缺失任一,则模块整体安全禁用。 |
打造执行管线 0x741D70( doCombine) | detour | enchant_transfer.cppDetour_DoCombine | 词缀迁移:严格限定仅迁移原版附魔师所附加的词缀属性(判据为 CEffect+0x28 & 0x400,即附魔师执行 markNewEffectsAsEnchanted 所打上的标志位;掉落随机词缀、DAT 基础属性及宝石镶嵌效果天然被排除)。迁移过程必须同步贯通两条底层通道:① Effect 逻辑层:调用引擎堆拷贝构造并在目标装备上调用 linkEffect,将 +0xD4、+0xD8、+0xDC 与 +0xE0 四组浮点数值原样写回目标(针对区间型词缀,若仅执行浅拷贝会导致引擎重新随机投骰,实测同一来源经三次拷贝数值分别漂移为 5.087、5.231 与 4.788);② 附加伤害投影层:附魔烘焙后原始 Effect 已被注销,仅在桶 B( CEquipment+0x3FC)中残留物理投影,必须通过 addBakedDamageOfType 完成数据注入。同步刷新 STAT_ENCHANTCOUNT(偏移 +0x3B4,控制 Tooltip 中「附魔: N」文本行,归零时该行自动隐藏)。若接收装备放回背包时空间不足,立即终止事务且不销毁源装备(坚决杜绝吞装备);事务提交成功后将源装备移出容器,触发析构并将内存安全归还至引擎内存池。单件装备支持迁移上限为 5 条,支持 UI 勾选。词缀剥离:将目标 Effect 的持续时间置为 -900.0 哨兵标记,随后调用 expireEffects(精准复刻原版清除烘焙伤害词缀的标准手段);仅遍历检索 0 至 2 号链表,3 号条件触发链表无法清除(与原版祛魔逻辑一致)。神明祝福:调用 addRandomAffixes 抽取词缀,以 NPC 自身的 UNITTYPE(MIKURO_BLESSER)作为词缀池检索索引,打上专属的 0x400000 标记位(区别于附魔师的 0x400),词缀上限为 3 条。神明涤除:仅定向清洗携带 0x400000 标志的祝福词缀。金币扣除:统一调用 CUnit::addGold 传入负数金额实现明码标价;若底层未解析到 addGold 接口,两大面板一律拒绝执行交易,坚决杜绝免费漏洞。 | 编译期宏控制:TRANSFER_ENABLED=1TRANSFER_DESTROY_SOURCE=1TRANSFER_SEND_NPC_AWAY=0(迁移大师定义为常驻城镇 NPC) | 同上;非致命辅助地址缺失仅触发功能降级并在模块日志中告警。 |
单选复选按钮状态变更 0x7247F0( CWidgetToggleButton::setToggled) | detour | enchant_transfer.cppDetour_SetToggled | 当玩家在界面上勾选或取消迁移词缀条目时,必须实时重新计算并刷新「当前选定迁移数量」。此函数为引擎全局 Hook(游戏内所有 Toggle Button 事件均由此派发),Detour 入口首要操作即校验按钮所属指针,若非本系统控件则以极低开销瞬间返回。状态读取直接解引用结构体 +0x144,规避多余函数调用。 | — | 挂载失败则勾选功能依然可用,但状态统计行数字无法实现实时刷新。 |
Tooltip 主显示区文本生成 0x7B0720( CEffectMgr 内部实现) | detour | enchant_transfer.cppDetour_MainTipText | 原版 Tooltip 主区过滤条件为 !(flags & 0x400),附魔专区过滤条件为 flags & 0x400。由于「MIKURO 的祝福」未标记 0x400,默认会落入主显示区并与常规基础词缀混杂在一起。Detour 拦截后提取带有 0x400000 标记的祝福词缀,在排版中单独剥离为专属的墨绿色文本块。底层调用 AppendGameWStr 直接在引擎已构建好的 std::wstring 尾部进行格式化追加。 | — | 特征未命中则祝福词缀渲染为普通白字,功能生效不受影响。 |
NPC 对话强制终结 0x7062F0( CGame::endNPCConversation,参数 force=1) | 只读调用点 (每帧轮询) | enchant_transfer.cppTickEndConversation | 当自制打造菜单关闭后,由于引擎内部「已打开菜单链表中若存在任一未关闭菜单(sub_7A0CA0 为真)则阻止对话退出」的判定持续为真(诱因尚未完全确定,已排除的假设记录于相关文档),导致游戏摄像机镜头永久卡死在近景拉近特写视角。本模块在检测到自制面板已全量关闭但 NPC 对话状态依然挂起时,直接绕过前置闸门调用此底层接口完成摄像机视角的安全复位。全局单例地址从 CGame::update 内部提取。 | 编译期宏控制:XFER_CONV_PROBE=0 | 依赖缺失会导致关闭自定义面板后摄像机镜头偶发残留于特写视角。 |
3.9 视觉渲染与 HUD 交互强化
| 目标标识 | 拦截方式 | 源文件 / 入口点 | 功能实现与视觉管线 | 配置开关(默认) | 未命中回退 |
|---|---|---|---|---|---|
装备 Tooltip 插孔遍历渲染 sub_588180(格式化拼接 SOCKET{n} 控件名称,检索对应 Widget 填入宝石图标及名称;鼠标悬停 Rollover 与装备对比 Compare 均经由此接口) | detour | socket_glow.cppDetour_SockRow | 在数据结构中动态登记「当前插孔的 SOCKETICON Widget 实例指针 $\leftrightarrow$ 目标特效光晕配置」;在 EndScene 渲染周期内,利用 ImGui 背景绘图列表(Background DrawList)在图标屏幕投影矩形区域叠加特效。v1 规则:若宝石显示名(CItem+0x208)包含「青莲」,则在图标边缘渲染青色法阵结界与动态雷弧特效。控件检索复用 sub_70C420;控件屏幕可见性与绝对像素坐标通过 CEGUIBase.dll 导出接口 isVisible 与 getUnclippedPixelRect 解析(实机内存断言证实:CEGUI 的 Rect 内存成员布局严格为 {top, bottom, left, right},早期静态推导出的 {left, top, right, bottom} 存在严重偏差)。该渲染属于纯叠加图层,完全不修改游戏原生 UI 的内部状态。签名批注:零售版 1.25.9.5 实测唯一命中,Steam 版尚待核验。 | socketGlow(默认开启) | 特征码或 CEGUI 导出接口缺失则模块安全禁用。 |
装备 Tooltip 整体渲染封装 sub_588600 | detour | socket_glow.cppDetour_TipFill | 在引擎完成整个 Tooltip 绘制后,解析对应物品的稀有度属性(前缀包含 LEGENDARY,检索策略为预编译静态表优先、动态注册表回退)$\rightarrow$ 捕获并登记 Tooltip 根 Widget 的外边框屏幕矩形,在边框边缘叠加绘制金色动态火舌、符文流转与火星飞溅动效。 | 同上 | 特征未命中则金边火焰效果禁用。 |
| 护盾实时计量仪表盘 (零 Hook 纯只读实现) | 只读轮询 | shield_hud.cpp | 每帧主动轮询玩家及其全部随从单位(解引用玩家结构体 +0x72C 宠物数组指针与 +0x738 数组计数;宠物与召唤物均通过 addPet 统一纳入该数组),读取其实体上挂载的 SHIELD BUFFER(Effect 122)的剩余吸收量(结构体偏移 +0xD4;由于引擎底层不持久化护盾初始上限,数值计算完毕后仅保留当前瞬时值,仪表盘通过自适应算法记录峰值以呈现「当前/上限」百分比),并在屏幕上渲染平滑护盾条。技术路线选型动因:坚持采用每帧只读轮询而非拦截吸收函数——吸收函数仅在单位遭受攻击时方才被动触发,当护盾自然持续时间结束过期、或遭受 SHIELD BREAK 机制瞬间驱散时,拦截方案会导致 HUD 残留陈旧数值。装载期对 5 组关键布局特征码执行严格静态校验(包括护盾值偏移、效果类型判定、EffectMgr 偏移、EffectList 结构布局及随从数组偏移),任一签名未命中则整块禁用——与其呈现失真的脏数据,坚决杜绝渲染不准确的 HUD。内置 8 组高清图标(编译为 RCDATA 资源嵌入 DLL)。 | shieldHud(默认开启);快捷键 F8 随时向日志输出全场景所有带盾实体的微秒级详细分析 Dump | 5 项布局签名未全数命中则整体拒绝挂载。 |
| 游戏原生 UI 风格化封装 (零 Hook 纯资源实现) | ImGui 渲染 | ui_frame.cpp | 从原版游戏纹理图集 MEDIA/UI/HUD/*.DDS 中精准切分出九宫格金边纹理与金色分割线并打包为 DLL 资源。驱动 ImGui 控件完全复刻《火炬之光 2》原生的沉浸式羊皮纸金边风格;通过 Windows WIC 引擎动态解码 RCDATA 资源并实例化为 D3D9 显存纹理(护盾 HUD 亦复用此图元管线)。 | — | — |
3.10 操控模式扩展(WASD 键盘平滑移动)
| 目标标识 | 拦截方式 | 源文件 / 入口点 | 功能实现与运动管线 | 配置开关(默认) | 未命中回退 |
|---|---|---|---|---|---|
user32!GetCursorPos | detour (懒安装) | wasd.cppHookGetCursorPos | 仅在内部标志位有效的作用域切片内(即引擎调用该接口计算角色移动目标航点的切片),返回根据 WASD 键盘输入合成的虚拟屏幕光标坐标;其余常规渲染与交互周期内完全透传原生系统调用。从而保证光标视觉图标、法术技能瞄准射线等继续获取物理真实光标坐标,玩家的真实物理鼠标在键盘移动全程中保持绝对静止。 | wasd(默认关闭);游戏内配置面板勾选为唯一激活入口 | 挂载失败则回退至通过 SetCursorPos 直接操纵真实系统光标的旧方案。 |
光标到世界地表坐标转换 sub_4258D0(角色寻路移动与法术瞄准共用底层原语) | detour (懒安装) | wasd.cppHookGroundPt | 当满足 this == 游戏单例 && WASD 激活 && 调用栈不处于技能执行函数 sub_545070 内部 条件时,开启合成点注入标志并模拟持续按下鼠标左键。游戏引擎无缝沿用原生的「持续按住左键向目标地面点移动」逻辑,全量复用底层寻路网格、动态碰撞体排斥、地形坡度贴地及角色运动骨骼动画管线,完全不直接覆写角色的世界坐标,具备天然的多人联机网络安全性。合成目标点设定为以屏幕中心为基准沿按键方向偏移 radius 像素(默认 100 像素,支持快捷键 [ 与 ] 动态微调)。开发早期曾尝试直接调用寻路接口或 SetDestination,实机验证均告失败(原生接口仅计算折线路径而不驱动物理运动状态机)。生命周期管理:Hook 采取延迟懒装载策略,直至玩家在面板首次显式勾选时方才挂载;挂载后常驻不卸载(未激活时仅开销单次布尔分支透传,相比频繁挂载/卸载开销更低且杜绝了卸载失败风险)。 | 同上; 快捷键 F6 切换启闭(仅在当前运行会话中已于面板显式开启过时响应,防止全局误触); 快捷键 F7 标定模式(已整体停用,进入等同于暂停) | Init 两项特征未命中则面板隐藏该功能项;技能执行函数特征未命中则仅依赖单例指针分流(在按住 WASD 施放地面法术时可能发生目标点抖动)。 |
3.11 底层诊断探针(默认处于未装载状态)
| 目标标识 | 拦截方式 | 源文件 / 入口点 | 功能实现与分析能力 | 配置开关 | 维护状态 |
|---|---|---|---|---|---|
可行走性判定 sub_5DB690( CLevel::isWalkable,每帧移动更新密集调用) | detour | gridprobe.cppDetour_WalkQ | 仅捕获并缓存 this 指针,以零性能损耗获取当前活跃的 CLevel 关卡对象实例。功能特性: ① 快捷键 F9:将游戏运行时内存中多层动态合成完毕后的整关网格数据导出为 .mpp 兼容二进制文件(生成 mikuro_griddump_NN_walk.mpp 与 _flag.mpp,结构包含 24 字节文件头与 $W \times H$ 矩阵字节,与原版发布格式逐字节二进制同构,可直接被离线仿真分析工具 tl2-zone-merge-sim 读取加载),并同步在日志中记录玩家坐标、当前单元格标志及 $13 \times 13$ 的 ASCII 字符邻域视图;② 快捷键 F10:切换场景贴地网格透视可视化(将玩家周围 $\pm 24$ 栅格投影逆变换至屏幕坐标,直观甄别「不可通行空气墙 vs 地形美术表现」);摄像机矩阵依托 IDirect3DDevice9::SetTransform(槽位 44)捕获,多组渲染候选流基于「玩家投影点最贴近屏幕中心」算法自动标定。安装前执行严格的序言字节偏移校验( +92 与 +688 偏移必须与逆向定案吻合),检测到多重命中则拒绝挂载。 | 标记文件 mikuro_grid_probe.txt或环境变量 MIKURO_GRID_PROBE=1;编译期宏控制: MIKURO_GRID_PROBE_ENABLED=1 | 在编可用;2026-08-08 走格分析收尾后曾关闭,08-12 收到空气墙异常反馈后重新激活。 |
VFS 虚拟文件系统关键调用:loadAll(sub_64A590)、mount(sub_691360)、setStatus(sub_67C2C0)与 fread | detour ×3~4 | probe_vfs.cpp | 度量游戏资源反序列化各阶段的微秒级耗时(包含 loadAll 状态转换、资源包挂载与磁盘流读取;启动性能补丁模块自身维护独立计时,避免对相同入口重复挂钩)。逆向归因结论:MOD 挂载时的二次方排重耗时($O(n^2)$)已通过在打包阶段拆分 SPAWNCLASSES 子目录彻底规避(加载耗时由 1,817 ms 降至 563 ms,无需侵入式补丁);Spawnclasses 交叉链接产生的 1,349 ms 耗时分散于 913 万个瞬态 std::wstring 构造中,因无单一瓶颈点已决定放弃打补丁。 | 标记文件 mikuro_vfs_probe.txt或环境变量 MIKURO_VFS_PROBE=1;编译期宏控制: MIKURO_VFS_PROBE_ENABLED=1 | 在编可用,2026-08-18 起重构为纯按需启用机制。 |
图形与逻辑耗时剖析器:OgreMain.dll、CEGUIBase.dll、Plugin_OctreeSceneManager.dll 导出函数(含 renderOneFrame、_updateAllRenderTargets、renderGUI 等)+ D3D9 接口 + 游戏逻辑驱动 CGame::tick(sub_444130)、属性重算 sub_7AFE00、效果注销 sub_7AF2A0 等 | detour (导出表挂接 + AOB 特征扫描) | profiler.cpp | 全链路帧耗时剖析器。快捷键 F7 唤起仪表盘,按 Ogre 场景渲染阶段与 Direct3D 9 指令提交两个维度剖析单帧 CPU 时间分配;基于硬件 rdtsc 指令度量。额外记录「每帧 Effect 缩放求值迭代次数」(读取 §3.2 内联补丁维护的原子计数器)。 | 内部代码调用 prof::Install() 已被显式注释屏蔽 | 当前停用。源码归档记录:2026-07-25 性能分析收官(证实原版引擎各渲染与计算层级均慢于现代工业标准,但无单点绝对热点,D3D9 指令提交仅占总帧时的 2%~3%,主要瓶颈在 Ogre 图形树与玩法逻辑 CPU 线程);07-29 曾短暂启用以排查「升级被动技能瞬间掉帧」问题,随后复原。重新启用仅需解除两处调用注释。 |
| 掉落决议调用点探针 | — | hooks.cpp | 详见 §3.6。 | 编译期宏控制:MIKURO_LOOT_HOOK_ENABLED=0 | 技术路线搁置。 |
3.12 基础引擎原语与解析符号表(只读引用,未实施 Hook)
下表整理了 Runtime 各模块频繁调用、但其自身代码段未被注入任何拦截桩的原生引擎接口与数据结构基址,供后续架构维护检索:
| 引擎底层原语 | 解析来源与方式 | 核心系统用途与消费场景 |
|---|---|---|
命名属性读取 sub_677F00、GUID 到单位定义节点映射器 sub_65FDE0、Units 静态数据库全局单例(从 sub_65FDE0 内部指令 mov ecx, [X] 反解提取) | hooks.cppResolveEngine | 掉落物名称解析与属性提取。 |
CStringTranslate 本地化翻译单例(从 Getter sub_6580E0 内部指令 mov eax, [X] 提取);结构体偏移 +0x38 加载标志位、+0x8 BST 二叉树根节点;节点键位于 +0x10,翻译值指针位于 +0x2C | 同上 | 提取单位类型的中文本地化名称(仅在中文构建版本生效)。 |
资源管理器全局单例(从 Getter sub_6488C0 提取);unittype 注册表指针 *(resmgr+0x6C),偏移 +0x18 加载守卫位、+0x8 BST 根节点;层级继承判定表位于 +0x1C、+0x20 与 +0x24 | 同上 | MOD 动态 unittype 逆向反查、is-a ITEM 类型判定、配置面板下拉列表构建以及扩展稀有度自适应发现(阈值 6 票)。 |
RTTI 类型描述符 TypeDescriptor ×4:CItem、CCharacter、CBreakable、CTriggerUnit(名称字符串偏移 -0x8);手写 is-a 遍历管线走 COL $\rightarrow$ CHD $\rightarrow$ 基类数组 | 同上 | 支撑整个框架所有「判定目标是否为玩家 / 道具 / 可破坏物 / 机关触发器」的 RTTI 类型安全判定。 |
MSVCP90.dll 导出接口:wstring(wchar_t const*)、operator= 与 ~wstring | hooks.cppResolveWString、hook_savefix.cpp、opt_findfile.cpp | 支撑所有涉及修改或析构引擎内部 std::wstring 对象的安全操作。严重警告:必须严格绑定 MSVCP90.dll,绝不可链接 MSVCP100.dll(早期描述符修改整体失效即因引用错动态库版本)。 |
Tooltip 单行渲染原语 0x7A91D0( CEffect::getTooltipLine,调用参数 useStored=1) | hooks.cppEffectTooltipLine | 在自制 UI 面板中渲染与游戏原生 Tooltip 逐像素一致的属性文本描述;useStored=1 保证只读零副作用,若误传 0 会覆写结构体 +0xD4 与 +0xD8 原始数值。 |
层级判定原语 sub_511FA0(CUnit::IsUnittype)、标志位查询 CUnit::hasUnitType(早期逆向工程数据库误命名为 CCharacter_hasEffectTypeFlag,现已修正) | hooks.cpp 特征扫描 $\rightarrow$ 镶嵌门控 / enchant_transfer::Install | 宝石镶嵌合法性校验;附魔迁移装备大类校验(258 Equippable、8 Weapon、13 Armor;戒指标记链同时挂载 39 TRINKET 与 13 ARMOR)。 |
宠物嘲讽底层支持原语:setTarget(sub_524AF0)、CAIManager::setFlag(sub_701590)、getPosition(sub_61DCE0)与游戏全局单例 Getter sub_41CE60 | hooks.cppResolveTaunt;导出辅助接口 MikuroGetPlayerPos 与 MikuroGetLocalPlayer | 驱动宠物嘲讽逻辑;为走格探针与护盾 HUD 提供本地玩家绝对锚点定位(单例偏移 +0x2C + CCharacter RTTI 校验)。 |
附魔迁移系统底层原语:allocHolder(需要长达 127 字节的复杂特征码以实现唯一命中,本质为 MSVC 静态局部变量初始化样板代码)、CEffect 拷贝构造函数、itemLinkEffect、recomputeStats、invalidateTooltipCache、removeFromContainer / addToContainer、menuFindWidget(在 CUIMenu 内部查找,与 Tooltip 控件检索 sub_70C420 物理隔离)、widgetSetText、CWidget::setVisible / setToggled、addBakedDamageOfType、expireEffects、addGold、addRandomAffixes、endNPCConversation 及游戏全局单例 | hooks.cpp 特征扫描 $\rightarrow$ enchant_transfer::Install | 详见 §3.8 附魔与打造系统的完整实现链路。 |
CEGUI 基础动态库导出接口:?isVisible@Window@CEGUI@@QBE_N_N@Z、?getUnclippedPixelRect@Window@CEGUI@@QBE?AVRect@2@XZ | socket_glow.cpp | 检索原生 UI 控件的屏幕可见性及其在视口内的绝对像素裁剪矩形。 |
权威状态判定 sub_511AC0( CUnit::isLocallyAuthoritative) | hooks.cpp | 多人联机状态下判定本地实体是否具备网络权威性,驱动 DoT 护盾扣池与吸收决策。 |
4. 运行期配置、系统标志与调试速查
4.1 配置文件规范:mikuro_runtime.conf
文件位于游戏执行目录,由 Runtime 独占解析(游戏启动器仅负责调度 Direct3D 包装层及 dxvk.conf)。格式遵循 key = value,支持 # 与 ; 行注释。游戏内置面板点击「存为默认」时将原子化写回(先写入临时文件 .tmp 再完成覆盖替换)。列表型配置项支持多行重复指定。
| 配置键名 | 默认值 | 关联功能职责 |
|---|---|---|
saveFix | 1 | 控制 §3.2 存盘/读档 OOM 崩溃修复逻辑(Detour 保持常驻挂载,该配置为函数体内的快速放行开关)。 |
dotShield | 1 | 控制 §3.3 DoT 伤害护盾吸收与扣减机制修正。 |
clearOnTransition | 0 | 控制 §3.6 跨关卡切图时不持久化地面掉落物。 |
wasd | 0 | 控制 §3.10 WASD 平滑键盘移动模式(启动阶段读取并回放状态;运行期以模块内部状态机为准,保存配置时回写)。 |
socketGlow | 1 | 控制 §3.9 宝石镶嵌发光及传奇装备边框流火光晕。 |
shieldHud | 1 | 控制 §3.9 实时护盾吸收计量仪表盘。 |
enabled / logOnly | 1 / 1 | 掉落物生命周期过滤总开关 / 仅记录审计日志而不执行物理拦截。 |
blockNormal / blockMagicblockUnique / blockLegendaryblockQuest | 0 | 基于道具稀有度过滤(原版绿色与蓝色道具在底层统一标识为 MAGIC,无法剥离;blockQuest 为屏蔽任务道具的底层唯一开关,UI 界面默认不暴露)。 |
blockTier(支持重复定义) | 空 | 匹配并过滤 MOD 扩展稀有度前缀(例如 EPIC、RUNE 等);旧版配置项 blockEpic / blockRune 保持向前兼容映射。 |
useLevelFloor / levelFloor | 0 / 0 | 丢弃需求等级低于指定绝对下限的道具实体。 |
blockUnittype / blockName(支持重复定义) | 空 | 单位类型黑名单匹配 / 道具名称关键词黑名单(子串不区分大小写模糊匹配)。 |
allowUnittype(支持重复定义,整表覆写机制:首次定义将清空内置出厂名单)allowName | SOCKETABLEAMULET / 空 | 道具保留白名单。配置 allowUnittype = 空值可显式清空出厂预置白名单。 |
4.2 文件系统标记文件与环境变量(定位基准为当前进程工作目录)
| 启闭状态 | 标记文件名 | 环境变量键值 | 关联目标模块 |
|---|---|---|---|
| 强制关闭 | mikuro_no_skill_cd_fix.txt | MIKURO_SKILL_CD_FIX=0 | 技能冷却词条生效修复模块。 |
| 强制关闭 | mikuro_no_cosmetic_mp.txt | MIKURO_COSMETIC_MP=0 | 外观槽多人同步兼容模块。 |
| 强制开启 | mikuro_grid_probe.txt | MIKURO_GRID_PROBE=1 | 地形可行走网格诊断探针。 |
| 强制开启 | mikuro_vfs_probe.txt | MIKURO_VFS_PROBE=1 | VFS 虚拟文件系统耗时分析探针。 |
| 强制开启 | mikuro_loot_probe.txt | MIKURO_LOOT_PROBE=1 | 掉落生成决议探针(编译期宏默认关闭,此开关处于休眠状态)。 |
4.3 编译期预处理宏定义
| 预处理宏标识 | 当前预置值 | 宏定义所在文件与生效范围 |
|---|---|---|
LF_EN | 由构建命令行 /p:Lang=en 注入 | 全局开关:UI 文案英文输出,不加载系统级中文字体,不执行单位类型的中文本地化映射。 |
CURSE_MUTATE_ENABLED | 1 | curse.cpp:置 0 时仅执行内存结构分析 Dump,不执行词缀数值随机变异。 |
ENH_INSIGHT_POLICY | 0(取较大值) | curse.cpp:当启迪效果作用于已存在账本的装备时,上限数值的合并仲裁策略(0 取大值 / 1 累加 / 2 直接覆盖)。 |
TRANSFER_ENABLEDTRANSFER_DESTROY_SOURCETRANSFER_SEND_NPC_AWAYXFER_CONV_PROBE | 1 1 0 0 | enchant_transfer.cpp:控制词缀迁移总开关、事务完成后是否销毁源装备、NPC 交互后是否离开当前城镇(固定配置为常驻 NPC)、对话状态机诊断转储。 |
MIKURO_LOOT_HOOK_ENABLED | 0 | hooks.cpp:掉落物生成决议底层探针开关。 |
MIKURO_GRID_PROBE_ENABLEDMIKURO_VFS_PROBE_ENABLED | 1 1 | 各自探针源码实现文件。 |
prof::Install() 代码调用 | 注释停用 | hooks.cpp 初始化尾部与 overlay.cpp 渲染管线。 |
4.4 运行期交互与调试快捷键
| 物理键位 | 核心操作职责 | 响应前置约束条件 |
|---|---|---|
Home | 呼出或隐藏 ImGui 运行时主配置控制台 | Direct3D 覆盖层成功初始化。 |
F6 | 快速切换 WASD 键盘平滑移动模式的启用与暂停 | 当前运行会话中已显式在配置面板勾选激活过 WASD 功能。 |
F7 | WASD 移动步进标定模式(已被停用,进入等同于逻辑暂停) | 同上;Profiler 诊断面板的 F7 快捷键随其整体停用。 |
F8 | 触发全场景所有带盾实体的护盾吸收状态 Dump 至日志文件 | 护盾 HUD 布局的 5 项特征签名完全匹配命中。 |
F9 / F10 | 导出整关网格 .mpp 镜像 / 切换场景地表贴地透视网格渲染 | 走格探针已显式通过标记文件挂载启用。 |
[ / ] | 动态微调 WASD 合成目标点的步长半径(步长增减 20 像素) | 同 F6 约束条件。 |
4.5 运行期日志规范与格式定义
运行时日志输出至游戏同级目录的 tl2_mikuro_runtime.log(单次进程启动时清空重构)。日志行严格遵循定长格式: [+ 1.234][3f88][I][findfile] 日志正文内容
+ 1.234:相对于 Runtime 代理 DLL 执行DLL_PROCESS_ATTACH的浮点运行秒数;3f88:当前输出日志的操作线程 ID 低 16 位十六进制表示;I:日志严重性级别;E(Error):预期生效的核心拦截失败或遭遇未处理异常;W(Warn):非致命性降级,特征未中跳过可选模块;I(Info):系统初始化关键里程碑与显式未启用说明;D(Debug):单项详细内存状态转储与内部调用追踪。
findfile:在loot_filter.h严格注册的模块标签白名单。规范约束:即便某个功能模块被显式禁用,初始化流程中亦必须输出一行[I]明确注明未装载,彻底消除「模块因代码缺陷未安装」与「运行时版本过旧未包含该模块」的日志混淆。
5. 维护约定与版本演进准则
- 增补拦截点(Add Hook):
- 必须在 §3 对应分类表格中录入标准条目(目标 IDA 坐标、拦截方式、源文件与 Detour 符号、技术职责、开关规范及回退策略);
- 若引入新的死槽 131 效果,必须同步更新 §3.7 的 SUBTYPE 号段分配表;
- 若引入新的配置项、标记文件、快捷键或编译宏,必须同步更新 §4 相关速查表;
- 必须在 §7「更新记录」中按当前真实日期追加一条变更摘要。
- 废弃或停用拦截点(Deprecate Hook):
- 严禁直接从表格中物理删除条目;必须将其维护状态显式标记为「已停用」或「已搁置」,并注明历史废除日期与架构归因(如 profiler 与掉落探针的处理规范),同时在 §7 留痕。
- 特征码重构(Signature Refactor):
- 若仅重构 AOB 特征码而不改变拦截逻辑,§3 表格内容保持不动,但在 §7 记录一次特征演进(跨版本兼容性回退是极其关键的维护历史)。
- 实证性保障:
- 表内所有标称「实证」的论断均须在源码注释中能索引到对应的断言或 Dump 记录;若源码中注为「待验」,文档必须严谨标注为「待验」。
- 多端技术文档同步:
- 本文内容必须与源码仓库中的
loot_filter.h模块标签定义及用户文档README.zh-CN.md保持完全一致;改动其中任一文档时,需联动复核其余两处。
- 本文内容必须与源码仓库中的
6. 运行期状态快照(截至 2026-09-05 工程状态)
在默认配置且所有 AOB 特征码全量命中的基准环境下,Runtime 常驻活跃的 MinHook Detour 拦截点共计 32 项:
- 渲染覆盖层与设备管理:2 项;
- 掉落物落地拦截:1 项;
- 跨关卡切图存盘序列化过滤:2 项;
- 存盘/读档 OOM 崩溃修复:2 项;
- 主动技能激活(冷却缩减与嘲讽):1 项;
- 宝石镶嵌部位与落孔拦截:2 项;
- 宝石发光与传奇装备流火光晕:2 项;
- 乱铸与强化卷轴应用逻辑:2 项;
- 自定义打造与附魔通道状态机:4 项;
EFFECTSLIST运行时汉化覆盖:1 项;- 暴击状态捕获与暴击吸血:2 项;
- Tooltip 词缀子类型分流器:1 项;
- 四大数值上限突破与面板同步:5 项;
- DoT 伤害护盾吸收与轮询修正:2 项;
- VFS 与单位扫描性能优化补丁:2 项;
- 外观装备槽网络复制拦截:1 项。
除上述 Detour 之外,系统常驻挂载 6 处内联补丁 / 调用重定向:
CEffect属性缩放悬垂指针防护 Code Cave:1 处;- 技能冷却词条生效修复内联补丁桩:2 处;
- 外观槽网络同步条件分支
call重定向:3 处。
以及窗口消息过程子类化拦截 1 处。
按需与非活动模块:
- 按需懒装载模块:WASD 移动控制(2 项 Detour);
- 调试探针模块:走格分析探针(2 项 Detour)、VFS 耗时探针(3~4 项 Detour);
- 归档与停用模块:全链路性能剖析器(停用)、掉落生成决议探针(搁置)。
7. 历史演进与变更审计记录
记录按时间倒序排列;仅收录拦截点级别的增删、架构重构与关键缺陷修复,不收录纯文本或 UI 注释类提交。
| 变更日期 | 核心技术变更摘要 |
|---|---|
| 2026-09-05 | 本规范技术账本正式确立。新增 §3.2 技能冷却词条修复模块 skill_cd_fix(包含两处内联补丁桩与三项函数体全量自校验;此前以独立 Exe 补丁实测通过并移植),相关挂载在工作区处于就绪状态。 |
| 2026-09-04 | 新增 §3.4 外观槽多人同步兼容模块 cosmetic_mp(包含 1 项入口 Detour 与 3 处条件分支 call 改向,原版数据环境下保持逐位等价)。 |
| 2026-09-01 | 新增 §3.3 DoT 伤害护盾吸收结算修正机制(挂载 absorb 与 tick 两项 Detour,由配置项 dotShield 门控)。 |
| 2026-08-29 | 存盘/读档 OOM 崩溃保护调整为默认开启且脱离对启动器的依赖;WASD 模式迁移至游戏内置面板控制,底层 Hook 重构为延迟懒装载;配置面板新增「存为默认」持久化功能。 |
| 2026-08-23 | 打造系统扩展神明祝福与神明涤除两大菜单,接入 addRandomAffixes 与 addGold 接口;挂载 Tooltip 主区文本生成器 Detour(祝福词缀单独渲染为墨绿色);接入 endNPCConversation 解决镜头特写卡死;神明祝福调用链剥离冗余的 recomputeStats。 |
| 2026-08-22 | 新增 §3.8 词缀迁移与词缀剥离模块(挂载 updateCanCombine、doCombine 与 setToggled 三项 Detour,接入十余项原生引擎原语)。 |
| 2026-08-19 | ImGui 面板重构接入游戏原生九宫格金边纹理(ui_frame);修复装备账本锻造次数在 Tooltip 中延迟刷新的显示缺陷。 |
| 2026-08-18 | VFS 耗时分析探针重构为纯按需启用机制(默认状态零 Hook 注入);日志管线规范化为定长前缀、严重性分级与模块标签体系(全量重构 219 处调用点)。 |
| 2026-08-17 | 新增 §3.5 unittype 全量扫描无用拷贝剔除补丁(数据加载节省约 0.68 秒);修复 findFile 两项辅助特征在不同游戏版本上的重定位失效缺陷,改为从主函数体内动态解析相对偏移;性能优化模块彻底剥离运行期影子验证机制。 |
| 2026-08-16 | 调整死槽 131 号段划分规范,将消耗品卷轴与装备持久化账本物理拆分为独立子类型(9 与 10 号分配给卷轴,11 与 12 号分配给装备账本)。 |
| 2026-08-14 | 新增 §3.8 诅咒打造卷轴体系(挂载 ApplyDynamicEffect 与 loadFromSaveRecord)。 |
| 2026-08-12 | 新增 §3.5 VFS 虚拟文件系统目录检索哈希二分索引补丁(MOD 密集环境下加载节省约 1.09 秒)。 |
| 2026-08-08 | 新增 §3.11 地形可行走网格分析探针 gridprobe(集成 F9 数据导出与 F10 场景透视投影);彻底移除宠物嘲讽的 T 键物理快捷键,收拢技能施放为唯一权威入口;最近掉落列表中 UNITTYPE 字段恢复显示原始定义名称。 |
| 2026-07-30 | 全链路帧耗时剖析器 profiler 归档入库(源码标记其于 07-25 结案停用、07-29 短暂开启后复原,当前维持停用状态);传奇装备边框流火动效正式生效。 |
| 2026-07-24 | 掉落物生命周期过滤系统引入白名单机制(出厂预置 SOCKETABLE 与 AMULET)与分级过滤判定管线。 |
| 2026-07-23 | 架构重大演进:全面废除硬编码静态 RVA,全量迁移至 AOB 动态字节特征码扫描,彻底修复跨版本兼容性缺陷(宠物嘲讽在 Steam 版本由必崩转为稳定可用)。 |
| 2026-07-22 | 新增角色面板减伤上限数值同步 Detour;修复暴击伤害与闪避率上限 Hook 因特征码硬编码静态字符串地址在 ASLR 下从未成功装载的历史缺陷。 |
| 2026-07-21 | 新增 §3.9 装备 Tooltip 宝石插孔发光动效(青莲法阵系列)。 |
| 2026-07-20 | 新增 §3.10 WASD 平滑键盘移动操控系统。 |
| 2026-07-17 | 新增减伤、暴击伤害、闪避率与格挡率四大核心数值上限突破机制(承载于 131/4~7),格挡率绝对上限纠正为 85%;引入格挡灵石部位限制;宠物嘲讽正式支持通过技能施放事件触发。 |
| 2026-07-16 | 新增暴击吸血机制(死槽 131 的首个功能落地)、宠物嘲讽光环与 Effect 门控校验;确立死槽 131 + SUBTYPE 多路复用架构标准,冷却缩减由原 SOCKS(Type 133)收拢归入 131/3;实现 Tooltip 词缀按子类型分流渲染。 |
| 2026-07-12 | 跨关卡切图掉落过滤补全 CTriggerUnit 与 CBreakable 实体排除规则(彻底根治任务门开启状态丢失被误锁的缺陷)。 |
| 2026-07-11 | 掉落过滤系统支持 MOD 动态稀有度与单位类型的运行时自动发现(基于注册表 BST 检索)及任务道具全局豁免机制。 |
| 2026-07-04 | 新增 §3.2 存盘/读档 OOM 致命内存溢出崩溃修复补丁;开源代码仓库正式由 tl2-loot-filter 战略更名为 tl2-mikuro-runtime。 |
| 2026-06-25 | 项目首版正式发布:基于 d3d9.dll 动态库代理架构,实现道具落地拦截 Detour 与 ImGui 覆盖层管线(提供中英双语支持),集成 GitHub Actions 自动化发布流程。 |