优化 GreyMagic 函数调用调度,并统一 native 函数调用 API#91
Open
MnFeN wants to merge 6 commits into
Open
Conversation
二者 7.0 后选用的函数几乎没有区别,且前者的签名经常与一些卫月插件不兼容
线程池被提前占满,导致 WorkerProc 需要等待自动新建线程,所有调用需要等待 WorkerProc 创建而被阻塞
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
主要变更
新增
GreyMagicCallSchedulerMemory.CallInjected64依赖 GreyMagic 注入的入口函数。调用方会先准备目标函数地址、参数和返回值信息,然后开启一个FrameLock窗口,并 hook 入口函数调用指定的函数,直到等到了返回值后才释放入口函数,并将结果返回。因此,在直接调用
CallInjected64时,每次会占用一次FrameLock捕获机会,下一次调用需要再次等待游戏线程调用入口函数。目前使用的入口函数为 UI 线程上的函数,意味着每帧只能调用一次。对于短时间内连续发起的多个 native 调用,这会表现为延迟明显累积。PR 新增了
GreyMagicCallScheduler,用于在短时间内自动复用同一个FrameLock窗口。调度器会将需要执行的 native 调用加入队列,由后台 worker 获取一次FrameLock后,在 10 ms 窗口期内连续处理队列中的调用。调用方仍保持同步语义,只等待自己提交的调用完成并接收返回值或异常,不需要等待整个窗口释放。这样可以把多个紧邻发生的
CallInjected64调用合并到同一个FrameLock窗口内执行,减少重复等待 hook 入口触发的开销。对于文本指令、目标标记、场地标点等可能连续调用多个游戏内部函数的场景,可以显著降低累计延迟。对于连续执行多个开销很小的模组方法,优化非常显著,如
command指令中连续获取uiModule、raptureModule并调用ProcessChatBox,每 3 帧才能执行一次,而优化后几乎没有速度限制(每帧几十次):注:小队聊天等附带发包的指令,自己看到的文本如右图几乎瞬间显示;但发包会进入后台队列,即其他人视角下每 1/30 s 收到一条文本(与使用文本宏一致),相当于 60 fps 下的 2 帧 / 次。目前没有看到因调用函数提速而造成指令被客户端或服务器吞掉的现象(至少当前模块没有)。
新增
PostNamazu层的GreyMagic调用 API函数调用相关 API:
Call(...)/Call<T>(...)通过调度器自动复用 FrameLock。
DirectCall(...)/DirectCall<T>(...)直接调用,不经过调度器。
ExecuteInFrameLock(...)/ExecuteInFrameLock<T>(...)在调度器 FrameLock 窗口内执行自定义操作。
统一检查空函数指针、空参数、未初始化状态等错误。
统一规范化调用参数,防止 GreyMagic CachedCall 因参数类型不一致导致的报错,且支持
bool、enum等更多类型参数入栈。对游戏崩溃时
InjectionFinishedEvent was never fired增加更明确的错误提示。调整现有模块的 native 调用方式
将现有各模块 native 调用迁移到上述封装。
删除
AssemblyLock相关的使用:该锁会被 GreyMagic 的 CallInjected64 内部自动调用,用于保护其内部状态,因此原本的这个写法并没有额外锁住什么。移除
NormalCommand模组NormalCommand的回调现在重定向到Command,以兼容已有调用。目的是避免继续使用 7.0 后兼容性较差的旧签名,且两个模组目前使用的函数几乎没有区别。