Metamod 的真正力量来自本文的主角 - SourceHook。当插件加载时,SourceHook 会开始用 SourceHook 表替换引擎的虚函数表。然后,SourceHook 可以用插件的代码替换单个方法,同时保持其余虚函数表条目与游戏原始版本一致。由于 SourceHook 会跟踪所有所做的更改,因此它可以通过防止插件相互撤销对方的钩子来让插件彼此协同工作。并且,由于它仅在插件需要监听时才介于引擎之间,因此运行速度 很快。
释义:
-
钩子: 在程序运行过程中拦截并修改函数执行流程的一种技术(对应原文中的 detour)
得益于 SourceHook,Metamod 不必再担心太多游戏兼容性问题:只要它能够加载游戏并了解一些游戏状态的基本信息,它就可以正常运行。即使引擎的接口发生巨大变化,Metamod 也可以继续运行下去(不过插件方面就另当别论了……)。这种基本特性使 Metamod 能够快速移植到 Source 2 引擎,并且是其在反恐精英 2 领域迅速扩展的重要助力。
由于 SourceHook 只针对单个方法工作,许多插件(例如 SourceMod!)实际上并不需要了解太多它所要钩取的对象;它们只需要告诉 SourceHook 需要钩取哪个方法以及被钩取的方法期望接收哪些参数即可。插件维护工作量开始减少,逆向工程工作可以更多地集中在新特性上,而不是确保引擎与游戏的兼容性。直到今天,你仍然可以在 HL2SDK 中找到大量标有“未知”的方法:这些方法没有 Valve 的文档说明,对逆向工程师来说是个谜,但由于 SourceHook 的存在,它们变得完全无关紧要。
3. 今日的 SourceHook
自 2005 年以来,SourceHook 经历了数次重大更新,兼容所有主流 C++ 调用约定,可以很好地兼容 GCC 和 MSVC 的一些怪癖。即使在今天,SourceHook 仍然是所有 Source 引擎开发的核心,从 Sourcemod 充满活力的插件场景到 CS2Fixes 和 Counter-Strike Sharp 等更新开发项目都离不开它。SourceHook 代码库简洁、优雅且令人印象深刻的稳定性,可以加速我们的开发并缩短迭代时间。
尽管 SourceHook 是一个与 Metamod 基本独立的项目,但它从未真正离开过 Source 社区。由于许多游戏放弃了基于接口的架构,许多模组制作者转而使用静态钩子和实时反汇编器来进行修改。虚拟钩取在很大程度上已经成为 Mod 制作界过时的工具。
尽管如此,我们仍然期待在进军 Source 2 引擎时看到 SourceHook 迷人的小宏指令。让我们一起祝 SourceHook 再创辉煌二十年,生日快乐!
参考: