Files
IC.Rebuild/diagnostics/2026-10-11-network-manager.md
T

5.7 KiB
Raw Permalink Blame History

0.1.13:统一收发观察与独立日志订阅

日期:2026 年 10 月 11 日。用户将本轮工作切到收发包管理器。交付 M1 的只读管理器与日志接入;M4 主动发送、编码器、排队和请求响应事务仍未实现。

已接入的能力

  • Runtime/NetworkManager.cs 管理原有两个 Zone Hook,复用 SharedModuleResource。第一个模块订阅启动 Hook,最后一个模块订阅释放 Hook;关闭 36 只释放记录器自己的订阅,其他模块可以独立持有管理器。
  • Core/NativePacketCapture.cs 继续负责原有原生长度契约和有界复制,本轮未修改签名、ABI、载荷边界、读取时点、版本限制和原函数参数。
  • Core/NetworkPipeline.cs 提供 Received、BeforeSend、AfterSend 三种只读观察。每个订阅可独立限定 Opcode,并通过 IDisposable 取消;一个订阅抛异常不会阻断后续订阅或改变原函数调用次数与返回值。
  • Core/PacketRecorder.cs 将消息写入现有 PacketBuffer。36 保留收包和发送入口两类记录,不额外把发送后事件写成第二条上行记录;暂停、方向过滤和 Opcode 过滤仅作用于记录器。
  • 网络面板显示订阅数、收包/发送入口/发送返回的观察计数、订阅异常及最近原生发送返回码。日志暂停时观察仍继续,因此暂停不再等于停止网络内存复制;关闭 36 且无其他消费者时才释放 Hook。

接口契约

模块在自己的生命周期入口调用,例如:

network.Observe(scope, NetworkPhase.Received, observation =>
{
    var message = observation.Message;
    // message.Payload is ReadOnlySpan<byte>; only copy/process owned data here.
}, opcode: 338);

订阅的建立和释放与现有模块启停一样在框架生命周期代码中执行,不能从原生回调中释放 Hook。回调在原生调用线程同步执行,同一消息同一阶段按注册顺序回调,多个原生线程之间不承诺全局顺序。回调不得操作线程绑定游戏/UI 服务、等待 Framework、主动发送或阻塞;耗时任务由消费者基于自持有数据安排。

上行流程:在发送入口复制一次 → BeforeSend → 原函数恰好一次 → AfterSend。后者包含同一个 NetworkMessage 和原生 byte 返回码;发送前捕获的订阅集合用于两个阶段,发送中途新增的订阅从下次调用开始。原函数抛出时不重试、不伪造 AfterSend。原生返回码未解释为服务端确认。

下行流程:原函数先执行一次,返回非零后才读取 holder → Received;返回零时不读消息。原生读取失败仍保留既有元数据降级或错误计数。捕获和订阅异常处理不包裹原函数,避免异常路径重复调用。

每条 NetworkMessage 自持有不可变载荷副本,外部只有只读 Span,不能取得原生指针或底层可写数组;发送前后共享相同观察 ID 和消息实例。消费者可保留消息,不依赖原生发送对象或接收 holder 的生命周期。无对应观察订阅时跳过复制;有 Opcode 限定时在读头后筛选。

取消后不再进入该订阅的后续分发;已经通过活动检查、开始执行的回调可能结束在取消之后,取消不会强行中止它。释放过程中不持有订阅锁调用消费者;一个回调取消其他尚未执行的订阅时,后者会跳过。插件先释放所有模块作用域再关闭分发器。

记录兼容与来源

PacketRecord 新增可选 Context,包含观察 ID、NativeZone 来源、RawIpcPayload 阶段、观察阶段与可用的原生返回码。日志时间使用捕获快照的时间,仍保留独立的缓冲区记录序号。旧 JSONL 缺少 Context 时为 null,界面明确显示阶段未知,不把旧数据伪标为转换后状态。

NativeZone 表示采集入口,不保证实际发送者是游戏本体:其他插件经同一原生入口发送的数据也可能出现。当前管理器不主动发送,也未加入来源归因。RawIpcPayload 是排除 IPC 头的原始游戏载荷,不代表状态 ID 等字段已经转换。编号 8 继续使用自己的转换后 SetStatus 入口。

普通日志仍记录 BeforeSend,因此上行记录里的原生返回码为空;发送后的原始返回码通过 AfterSend 订阅和面板提供。下行记录可以附带接收返回码。观察 ID 只在本次插件实例内关联,不是服务器请求 ID,也不能跨重载用于业务匹配。

验证

Release 构建通过,0 警告、0 错误;77 项离线测试通过。新增七组检查针对调用顺序/次数、复制寿命、原生返回码、捕获与订阅异常、接收失败时不读取、日志过滤与独立订阅、取消/重复订阅/卸载、共享 Hook 持有者和新记录字段往返。

复用原 capture-018.jsonl:891 条(534 上行、357 下行)经新分发器与记录器回放后,载荷字节、方向、Opcode、版本、目标、完整性和读取问题逐条一致;发送后观察 534 次,订阅错误与读取错误均为 0。回放使用托管原函数代理返回 1,不代表真实原生发送已实测,更没有重发这些样本。报告见 2026-10-11-capture-018-manager.json。

原文件解析仍为全部具名、679 条有限字段解析、0 条已支持格式拒绝、8 组 Ping 配对。原文件及 Opcode 缓存未修改。回放按新观察时间生成临时内存记录;原文件的时间和序号只读保留,Ping/RTT 分析仍用原文件。

现场只需一次聚焦检查:重新加载后开启 36,正常移动,确认管理器计数与日志增加;暂停记录时日志停止增加而管理器继续;解除暂停后恢复;关闭 36 后在当前没有其他消费者的情况下订阅数为 0。性能、切区及卸载仍需现场验收,不要求重新提供泛化抓包。