7.2 确定性与网络同步


7.2 确定性与网络同步

本节摘要:确定性指同一初始状态、同一输入 tick 序列、同一引擎版本,得到同一状态序列。固定 dt、整数 tick、约束排序稳定、慎用多线程归约和未定义浮点,是前提。联机常见锁步或状态同步加回滚。物理若绑渲染帧率,分叉是必然。先让单机回放咬死,再谈网络。

先说结论

阅读完本节,你应当能够:

  1. 列出破坏确定性的常见来源
  2. 设计以 tick 为键的输入缓冲
  3. 比较锁步与快照插值,说明回滚对物理的要求
  4. 用哈希校验发现哪一 tick 开始分叉

一、先能回放

把每 tick 的输入(键盘、射线命中随机种子、破碎随机)写入日志,重放时不读设备,只读日志。画面可以 144Hz 插值,逻辑必须 tick。校验:每 N tick 对动态体位置哈希,与录制时比。不等就从该 tick 单步找第一处差异。

破坏源:

  • 变 dt
  • 接触列表顺序随内存地址或哈希桶遍历而变
  • 多线程岛完成顺序影响本不该耦合的写(分岛 bug)或日志
  • rand() 未进输入日志
  • 未初始化内存
  • SIMD 归约顺序、快速数学、不同 CPU 的浮点
  • 指针当排序键

接触排序按 (min(idA,idB), max(idA,idB), featureId)。宽相哈希遍历后必须排序再交给窄相。这点不做,回放必炸。

联机模型 物理要求 带宽 适合
锁步 全确定,所有端跑同一 tick 低,只发输入 RTS、格斗
状态同步 主机权威,客户端预测展示 高,发快照 射击、开放世界
预测回滚 本地预测,权威纠正时倒带重演 格斗、平台

锁步不能丢 tick,一端慢全员等。回滚要求 step 纯函数式:能保存/恢复完整热状态。所以 1.3 的 SoA 便于 memcpy 快照。对象图指针满天飞时回滚是噩梦。

二、浮点现实

跨平台锁步极难:x87 vs SSE、FMA、GPU 物理几乎不可能一致。同编译器同架构同设置才有希望。跨平台常用:定点数、或主机权威不要求客户端物理一致。游戏产品多数选权威服务器,客户端物理只做表现,重要碰撞以服务器为准。格斗游戏愿意为锁步约束平台。

💡 关键直觉:网络同步首先是时间模型问题,其次才是压缩。没有固定 tick,再好的插值也在同步两套不同的物理定律。

客户端预测:本地立刻 step,服务器晚到的结果不同则回滚到服务器 tick 重演中间输入。重演次数受 RTT 限制。物理太贵就不要每帧全解回滚,改回滚简化代理(只角色胶囊)。载具全物理回滚要仔细预算。

三、随机、休眠与层

破碎随机、粒子喷射必须用随 tick 推进的确定性 RNG,种子进关卡或房间。休眠阈值造成的分叉:一端睡一端没睡,之后接触全变。锁步里休眠必须是确定性规则,浮点末位差异会被阈值放大。有人锁步关闭休眠,或用定点数速度。权威模式可休眠,因为客户端不需要一致。

⚠️ 常见坑:用系统高精度计时器当电机相位。相位必须是 tick * dt。墙钟不同步,门开关时机分叉。

哈希粒度:不要只哈希“有没有分叉”,要分岛哈希,定位哪座岛先坏。调试绘制在回放中可用,但不要把绘制纳入哈希。

物理与动画:KCC 若读动画曲线,曲线必须按逻辑时间采样。按显示时间采样,回放镜头一变轨迹就变。

测试:录 10 秒堆箱子,重放哈希全中。改接触排序再录,应能故意分叉,证明校验器工作。联机再测丢包:回滚后视觉可抖,逻辑应回到权威。

不要在物理里读文件、读时钟、遍历 std::unordered_map 当顺序源。容器遍历顺序是隐藏输入。

跨版本:哈希算法和约束顺序是协议的一部分。引擎一改 PGS 次数,旧回放失效。版本号进录像头。

四、分叉定位流程与输入压缩

分叉定位:权威与客户端每 N tick 对全场景哈希,不等则对岛哈希,定位岛后对该岛刚体位置逐个比,找到第一对差异物体,再看该 tick 接触列表是否同序同特征。通常是排序或随机。把接触列表也记进调试录像(可开关),体积大但能救命。

输入压缩:布尔键位打包位域,模拟摇杆量化。量化是确定性的一部分,两端同样量化。不要一端 float 一端压缩。射线命中若用于物理(钩索),命中刚体 id 必须进输入,不要两端各自射线,浮点相机一点差就会钩到不同物体。

回滚预算:物理 step 若 2 毫秒,回滚 10 tick 就是 20 毫秒,帧预算可能爆。对策:限制回滚深度、简化预测(只角色)、降低物理频率。测量再定。不要假设回滚免费。

关闭物理里的哈希表遍历当顺序源。候选对进数组后 sort。写一条静态分析或运行断言:step 内不得调用非确定性时钟。有人把性能计数器的时间戳写进休眠逻辑,分叉就来了。计数器只读出,不进分支。

跨版本录像失效要提示,不要静默错乱重放。版本号含:PGS 次数默认值、dt、约束排序规则编号。改默认迭代次数就是改协议。

实践问答

哈希多久比一次?

每 N tick,N 按带宽和定位精度折中。太稀定位慢,太密费。分岛哈希在全场景不等时再做。

钩索为什么要把命中 id 进输入?

两端各自射线会因相机浮点差钩到不同物体。权威命中进输入,客户端不自作主张。

回滚 10 tick 会不会卡?

step 若 2 毫秒就是 20 毫秒。测再定。简化预测、降物理频率、限深度。不要假设免费。

unordered_map 遍历为什么危险?

顺序是隐藏输入。候选进数组后 sort。step 内当顺序源的容器必须有稳定序。

改默认 PGS 次数为什么要升版本号?

那是协议。旧回放会分叉。版本号含 dt、迭代默认、排序规则。静默错乱重放比拒绝更糟。

参数扫描笔记:确定性

扫描 1:系统时钟当电机相位

门开关分叉。相位用 tick 乘 dt。

扫描 2:一端 float 摇杆一端量化

输入不一致。两端同样量化。

扫描 3:休眠阈值放大浮点差

锁步可关休眠或定点数。权威模式可休眠。

扫描 4:回放把绘制纳入哈希

开关绘制就分叉。绘制不含哈希。

扫描 5:KCC 按显示时间采动画

镜头一变轨迹变。逻辑时间采样。

扫描 6:step 读文件

隐藏输入。禁。

扫描 7:哈希只报是否分叉不分岛

定位慢。分岛再逐体。

扫描 8:旧录像无版本头

静默错乱。拒绝并提示。

扫描 9:预测回滚拷对象图指针

噩梦。热列 memcpy。又回到 1.3。

工程备忘录

备忘 1

「02-确定性与网络同步」的单元测试尽量不依赖图形窗口。能在无头模式跑的断言,才会每次提交都跑。只靠进游戏看一看,等于没有测试。把金字塔睡眠、速度交换、自由落体距离这类金标准写成断言。 本条对应「02-确定性与网络同步」第 1 号备忘,和相邻条目不要合并成一句空话,分开验收。

备忘 2

文档里的公式符号必须和代码注释同一张表。尤其是法向从谁指向谁、相对速度谁减谁、lambda 是力还是冲量。「02-确定性与网络同步」相关代码若混用两套符号,吸引接触和飞天会轮流出现,现场非常像随机 bug。 本条对应「02-确定性与网络同步」第 2 号备忘,和相邻条目不要合并成一句空话,分开验收。

备忘 3

性能上先问能不能少做。「02-确定性与网络同步」再快,也快不过把睡着的岛整岛跳过、把碎片到期删掉、把静态体移出动态表。减工作量优于把同样工作向量化。向量化平方算法只是错得更稳更快。 本条对应「02-确定性与网络同步」第 3 号备忘,和相邻条目不要合并成一句空话,分开验收。

备忘 4

可视化是「02-确定性与网络同步」的一部分而不是插件。接触生成时就把点、法向、深度留下来给绘制。事后从形状重新推断,会和求解器看到的数据不一致,你会修一个并不存在的偏差。 本条对应「02-确定性与网络同步」第 4 号备忘,和相邻条目不要合并成一句空话,分开验收。

备忘 5

固定时间步是「02-确定性与网络同步」所有数值实验的尺子。尺子在抖,你无法比较积分器,无法调 beta,无法谈确定性。谁把渲染帧时间直接喂进物理,谁就在用弹性的尺子量钢梁。 本条对应「02-确定性与网络同步」第 5 号备忘,和相邻条目不要合并成一句空话,分开验收。

备忘 6

「02-确定性与网络同步」里出现 NaN 要在源头断言:未归一化法向、零长度边当轴、除以过小的有效质量、四元数没归一。把 NaN 传到求解器再查,整场速度都会脏,回溯成本高一个数量级。 本条对应「02-确定性与网络同步」第 6 号备忘,和相邻条目不要合并成一句空话,分开验收。

备忘 7

和美术、策划交接「02-确定性与网络同步」参数时,用测试盒而不是形容词。说清楚二十厘米台阶能上、八十厘米不能,比说手感更跟手有用。测试盒还能在引擎升级后当合同跑一遍。 本条对应「02-确定性与网络同步」第 7 号备忘,和相邻条目不要合并成一句空话,分开验收。

备忘 8

「02-确定性与网络同步」若跨模块耦合,先单向再双向。布料先撞静地,流体先撞静箱,关节先吊静锚。双向一步到位时,你分不清是 A 推 B 写错还是 B 还力写错。控制变量不是学术,是省生命。 本条对应「02-确定性与网络同步」第 8 号备忘,和相邻条目不要合并成一句空话,分开验收。

备忘 9

睡眠和唤醒属于「02-确定性与网络同步」正确性,不只是性能。该醒不醒会穿模,不该醒全醒会卡顿。爆炸查询、关节边、运动学平台都是唤醒图的边。漏一条边,现场像鬼。 本条对应「02-确定性与网络同步」第 9 号备忘,和相邻条目不要合并成一句空话,分开验收。

备忘 10

「02-确定性与网络同步」的默认值要进协议版本。改默认迭代次数、默认 dt、默认皮肤半径,旧回放会分叉。版本头拒绝错版本,比静默错乱重放更负责任。 本条对应「02-确定性与网络同步」第 10 号备忘,和相邻条目不要合并成一句空话,分开验收。

本节速览

  • 确定性 = 固定 tick + 稳定排序 + 输入日志 + 无隐藏状态
  • 先单机回放哈希,再联机
  • 跨平台浮点锁步几乎不现实;多数游戏权威服务器。
  • 回滚需要可 memcpy 的热状态
  • RNG、休眠、动画采样都是输入
  • 墙钟不准进物理;相位用 tick。
  • 哈希分岛,版本号进录像。

下一节决定这条自研路径何时该换成现成引擎,以及现成引擎各自擅长什么。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U