
原生任务钩子
《巫师3:重制版》的巫师脚本任务块事件,来自引擎自带的任务监听器。无需编辑任务文件。
查看大图[center][size=6][b]Native Quest Hook[/b][/size]
[size=4]用于《巫师3:狂猎》重制版的 WitcherScript 任务块事件[/size]
[i]无需修改任何任务文件,即可获知任务块的开始、结束和推进。[/i][/center]
[line]
[size=5][b]这是什么?[/b][/size]
Native Quest Hook 是一个[modder 工具 mod]。它自身不会产生任何可见效果:其他 mod 可以通过它来跟踪任务进度。
跟踪任务进度的 mod 一直都需要修改 [b].w2phase[/b] 文件来添加脚本或 fact 块。正是这些修改导致任务 mod 之间互相冲突。Native Quest Hook 则完全不需要这么做。你的 mod 通过 GUID 来指定它关心的任务块,当游戏运行这些块时,它就能收到相应的事件。
[code]public function OnBlockFinished(guid : string, output : name)
{
// “At the Mercy of Strangers”中的“Interaction dialog”已完成,并且玩家选择了“Help”
}[/code][b]如果你是玩家:[/b]只有当你在用的某个 mod 把它列为前置需求时(例如 [b][url=https://www.nexusmods.com/witcher3/mods/6568]Progress on the Path NG[/url][/b]),你才需要这个。装好之后就不用再管它了。
[line]
[size=5][b]特性[/b][/size]
[list]
[][b]不修改任何任务文件。[/b]它不包含任何 phase、任务或场景文件,所以不会与任务 mod 产生冲突,加载顺序也无关紧要。[/]
[][b]它只监听,不修改。[/b]引擎中仍然保留着 REDkit 任务调试器所使用的任务监听器。每当一个任务块被激活或停用时,每个任务线程都会调用它,但在正常游戏中没有任何东西在监听。Native Quest Hook 会挂上自己的监听器。它不会挂钩任务代码:它依托任务系统自身的 tick 运行。[/]
[][b]对引擎来说开销很低。[/b]引擎的回调只负责复制发生的事件。其余工作都要等到任务 tick 结束后才处理。[/]
[][b]经过过滤。[/b]只有 mod 所关注的块才会通过一个普通的强类型调用传递给脚本。单次加载过程中可能会触发约 10,000 个块事件,所以这一点很重要。[/]
[][b]还能拿到输出。[/b]当一个块结束时,它会告诉你触发了哪个输出(Help、Nope、Out……),而正是这个输出推动任务前进。[/]
[][b]能区分加载和真实进度。[/b]它能将真实进度与游戏在加载、快速旅行或切换世界后仅进行恢复的块区分开来。[/]
[][b]在其他游戏版本上也是安全的。[/b]它会识别当前的 Steam 版本,并对它用到的每个地址进行代码校验。在其他版本上,它会在 exe 中搜索自己需要的内容。如果任何内容都无法精确定位,它就会自动关闭并记录原因。它从不猜测。[/]
[][b]静默失败。[/b]如果玩家没有安装 .asi,使用它的 mod 仍然可以编译并运行。它们的监听器只是收不到任何事件。[/]
[/list][line]
[size=5][b]前置需求[/b][/size]
[list]
[][b]《巫师3:狂猎》[/b],次世代(4.x)更新版本。[/]
[]ThirteenAG 的 [url=https://github.com/ThirteenAG/Ultimate-ASI-Loader]Ultimate ASI Loader[/url]:其 [b]dinput8.dll[/b] 放在 [b]bin\x64_dx12[/b] 中。诸如 [url=https://www.nexusmods.com/witcher3/mods/6568]Progress on the Path NG[/url] 这样的 mod 已经包含了它,所以你可能已经有了。[/]
[/list][line]
[size=5][b]安装[/b][/size]
[list=1]
[]如果还没有安装 [url=https://github.com/ThirteenAG/Ultimate-ASI-Loader]Ultimate ASI Loader[/url],请先安装它。[/]
[]将下载的压缩包解压到你的《巫师3》文件夹中(即包含 [b]bin[/b]、[b]content[/b] 和 [b]mods[/b] 的那个文件夹)。[/]
[/list]这会把以下内容放置到位:
[list]
[][b]NativeQuestHook.asi[/b] 放入 [b]bin\x64_dx12[/b][/]
[][b]modNativeQuestHook[/b] 放入 [b]mods[/b][/]
[/list]它不需要任何设置,也不需要 Script Merger。它的日志位于 [b]bin\x64_dx12\NativeQuestHook.log[/b],上次会话的日志会保留为 [b]NativeQuestHook.prev.log[/b],这样即使发生崩溃,崩溃时的日志也能在下次启动后保留下来。
[b]卸载:[/b]删除上述两项即可。使用它的 mod 会继续运行;只是不再收到任务事件。
[line]
[size=5][b]面向 modder:在你的 mod 中使用它[/b][/size]
你的 mod 不需要自己的 .asi 或 C++ 代码:只需将 [b]modNativeQuestHook[/b] 安装在其旁边即可。
[b]1. 找到 GUID。[/b]每个任务块都有一个 GUID,它在各个补丁和 mod 之间保持不变。Brothers In Arms 保留了原版游戏 130,545 个 GUID 中的 130,541 个。
使用 [url=https://github.com/Faen668/W3ModWorkbench]W3 Mod Workbench[/url]([b]--to-json[/b])解码 phase,然后查找块的 [b]guid[/b]。或者开启 [b]LogEveryBlock[/b](见下方调试部分)并游玩该任务。
[b]2. 编写监听器。[/b]
[code]class CMyMod_Listener extends CNQH_Listener
{
public function Init() : CMyMod_Listener
{
watched.PushBack("4b435b43-30c2-40d8-9eae-08df8d1b7df9"); // Interaction dialog: Help or Nope
watched.PushBack("4f6a4f44-3e1a-40f4-bd24-ebb2b16f1232"); // Pause: the player left the area
return this;
}
public function OnBlockFinished(guid : string, output : name)
{
if (guid == "4b435b43-30c2-40d8-9eae-08df8d1b7df9" && output == 'Help')
{
// the player helped him
}
}
}[/code][b]3. 注册它。[/b]
[code]@wrapMethod
function NQH_RegisterListeners()
{
wrappedMethod();
NQH_Register('MyMod', (new CMyMod_Listener in theGame).Init());
}[/code][b]NQH_RegisterListeners[/b] 每次会话调用一次。你也可以随时自行调用 [b]NQH_Register[/b];使用相同 id 再次注册会替换你的监听器。
源代码中包含一个完整的示例 mod:[url=https://github.com/Faen668/NativeQuestHook/tree/main/examples/modNQHExample]examples/modNQHExample[/url]。
[size=4][b]事件[/b][/size]
[list]
[][b]OnBlockActivated(guid)[/b]:一个被关注的块开始了。[/]
[][b]OnBlockFinished(guid, output)[/b]:它结束了并触发了 [b]output[/b],正是这个输出推动任务前进。对于输出没有名称的块(例如暂停块),则为 [b]None[/b]。[/]
[][b]OnBlockActive(guid)[/b]:在你注册时它已经在运行,或者游戏在加载或切换世界后恢复了它。[/]
[][b]OnBlockStopped(guid)[/b]:它没有完成就停止了:加载、离开其所在世界,或任务推进越过了它。[/]
[/list][size=4][b]函数[/b][/size]
[list]
[][b]NQH_Register(id, listener)[/b]:注册一个监听器,或替换具有该 id 的监听器。[/]
[][b]NQH_Changed()[/b]:在修改已注册监听器的 [b]watched[/b] 列表后调用。[/]
[][b]NQH_IsBlockActive(guid)[/b]:某个被关注的块当前是否正在运行。[/]
[][b]NQH_IsNativeActive()[/b]:NativeQuestHook.asi 是否已安装并正常工作。[/]
[][b]NQH_ApiVersion()[/b]:脚本 API 的版本,目前为 1。[/]
[/list][size=4][b]须知[/b][/size]
[list]
[][b]OnBlockFinished 会在下一个块运行前一个 tick 触发。[/b]这使得它足够早,可以替代你原本要添加到任务中的脚本块。[/]
[][b]一个输出可能通向多个块,块也可以汇合和循环。[/b]应关注你关心其结束的那个块,而不是它之后的那一个。[/]
[][b]GUID 在整个游戏及其 DLC 中是唯一的。[/b]不过,一个共享的外部 phase 仍可能同时在多个地方运行,而且 mod 可以复制块并产生重复。[/]
[/list][size=4][b]调试[/b][/size]
要记录游戏运行的所有任务块(而不仅仅是关注的块),请创建 [b]bin\x64_dx12\NativeQuestHook.ini[/b],内容如下:
[code][Debug]
LogEveryBlock=1[/code]每行显示块的类、名称和 GUID,它所在的 phase,它触发的输出,以及该输出所通向的块的 GUID。游戏运行时即可读取日志。
[line]
[size=5][b]兼容性[/b][/size]
[list]
[][b]Brothers In Arms 及其他任务 mod:[/b]兼容。Native Quest Hook 不修改任何任务文件。[/]
[][b]Script Merger:[/b]不需要。它不替换任何原版脚本。[/]
[][b]其他 .asi mod:[/b]没问题。它与它们共用 Ultimate ASI Loader。[/]
[][b]游戏版本:[/b]为当前 Steam 版本构建(exe 时间戳 0x6ADFBD7A)。在其他版本上,它会搜索自己需要的内容,如果找不到则会安全地自动关闭。[/]
[/list][line]
[size=5][b]源代码[/b][/size]
Native Quest Hook 是开源的:[url=https://github.com/Faen668/NativeQuestHook][/url][url=github.com/Faen668/NativeQuestHook]Github[/url]
.asi 使用 CMake 和 Visual Studio 2022(x64)构建,脚本使用 REDkit 的 wcc_lite 编译。其背后的研究,从调用哪些函数到任务块和线程的内存布局,都总结在源代码的注释中。欢迎在那里提交 bug 报告和 pull request。
[line]
[size=5][b]致谢[/b][/size]
[list]
[][url=https://www.nexusmods.com/profile/MerseyRockoff?gameId=952]Mersey[/url],感谢他给了我灵感。[/]
[][url=https://github.com/ThirteenAG/Ultimate-ASI-Loader]ThirteenAG[/url],感谢 Ultimate ASI Loader,它负责加载 .asi。[/]
[]CD PROJEKT RED,感谢《巫师3》和 REDkit。[/]
[/list][line]
[size=5][b]许可[/b][/size]
代码以 [url=https://github.com/Faen668/NativeQuestHook/blob/main/LICENSE]MIT 许可证[/url]发布,© 2026 Faen90。只要保留版权和许可声明,即可自由使用、修改、包含在你自己的 mod 中并在此基础上构建。
欢迎你将它列为你 mod 的前置需求,或将其打包在你 mod 的下载中。如果你打包分发,请保持其更新,并随附 LICENSE 文件。
[size=2]使用 Witcher III Modding Tool 制作,该工具由 CD PROJEKT RED 开发并发布,用于《巫师3:狂猎》。© 2014 及 © CD PROJEKT RED。保留所有权利。在此查看 Witcher III Modding Tool:[url=http://redkit.cdprojektred.com/]http://redkit.cdprojektred.com/[/url]
《巫师3》和 REDkit 归 CD PROJEKT RED 所有。这是一个非官方 mod,未获得他们的认可。[/size]
正在加载版本记录…
正在加载评论…
评论在新手盒子客户端中发表,这里同步展示。