延迟补偿(Lag Compensation)
「我明明瞄准了打中了,为什么没伤害?」——延迟让你屏幕上看到的敌人位置,和服务器上敌人的真实位置不一样。延迟补偿就是解决「以谁的画面为准」的机制。它没有完美解,只有取舍:要么牺牲射手的公平,要么牺牲被打者的公平。本篇讲三种命中判定模型、服务器回溯的实现、以及那个消不掉的「拐角枪」难题。
一句话结论
服务器保存所有玩家的历史位置,收到射击时回溯到「射手开枪那一刻」的世界快照做命中判定——用 RTT/2 + 插值延迟反推回溯时刻。
场景问题
打个比方:这像看直播打电话。你看的球赛画面比现场慢几秒(网络延迟 + 插值缓冲),你打电话说「他刚进球了!」——现场其实早过了那一刻。射击游戏里,你屏幕上的敌人是服务器几十毫秒前的位置(经过传输延迟 + 客户端插值平滑)。你对着这个「过去的敌人」开枪,等子弹信息到服务器,敌人早跑了。如果服务器按「现在」判定,你必然打空。延迟补偿让服务器倒带回你开枪那一刻的画面来判定。
实现方案
1. 三种命中判定模型
| 模型 | 谁判定 | 公平性 | 作弊风险 |
|---|---|---|---|
| 客户端判定上报 | 客户端算命中,告诉服务器「我打中了 X」 | 射手爽 | 极高:可伪造任意命中(aimbot 天堂) |
| 服务器即时判定 | 服务器按当前位置判定 | 都不爽:射手要打提前量 | 低,但手感差 |
| 服务器回溯(rewind) | 服务器倒带到射手开枪那刻判定 | 射手公平(所见即所得) | 低:服务器仍权威,只是换了判定时刻 |
主流竞技 FPS(含 UE 项目)用服务器回溯:既保留服务器权威(防作弊),又让射手「打哪儿中哪儿」。
2. 服务器回溯的实现要点
- 历史环形缓冲:服务器为每个玩家保存最近一段时间(约 0.5~1 秒量级)的碰撞位置历史。时长要覆盖最大可接受 RTT,越长内存越大(每玩家 × 每帧一份碰撞快照)。
- 回溯时刻反推:
回溯时间 ≈ 收到射击的时刻 − (RTT/2 + 客户端插值延迟)。RTT/2 是包从客户端到服务器的单程,插值延迟是客户端为平滑 SimulatedProxy 而故意滞后的缓冲(通常 100~200ms)。两者都要减掉,才对齐到射手屏幕上看到的那一刻。 - 服务器端时间戳校验:客户端上报的时间戳/帧号必须校验合理范围(不能回溯太远、不能是未来),防伪造时间戳「回溯到敌人静止的历史」作弊。
- UE 落地方式:UE 没有开箱即用的通用 lag compensation 组件,通常自实现(自己维护历史缓冲 + 回溯射线检测),或参考 Lyra / 第三方插件的做法。这点面试常问,别答成「UE 自带」。
3. 取舍的本质:拐角枪消不掉
延迟补偿把不公平从射手转嫁给了被打者。经典症状「拐角后被打死(shot around the corner)」:
- 你(被打者)已经跑过拐角,在自己屏幕上安全了。
- 但射手屏幕上(滞后几十毫秒)你还没转过去,他开枪。
- 服务器回溯到射手那一刻——那时你确实还在枪口下——判定命中。
- 你在「已经安全」的位置上莫名其妙死了。
这个矛盾无法消除,只能选择牺牲谁:
- 偏向射手(回溯)→ 被打者体验「拐角枪」。
- 偏向被打者(即时判定/限制回溯时长)→ 射手要打提前量,高延迟玩家几乎打不中。
调参手段:限制最大回溯时长(高 ping 玩家不给全额补偿)、对不同武器用不同策略。但本质取舍还在。
4. 按品类的倾向
| 品类 | 倾向 | 原因 |
|---|---|---|
| 竞技 FPS(CS 类、Valorant 类) | 强回溯,射手优先 | 射击手感是核心,「所见即所得」不可妥协 |
| MOBA | 服务器权威即时判定为主 | 技能多为范围/锁定,精确瞬时命中少,公平>手感 |
| 格斗 | 常用回滚网络码(rollback,另一套) | 帧级精确,宁可回滚重演也要两端一致 |
格斗的 rollback netcode 和这里的服务器回溯是不同东西:rollback 是 P2P 各端预测对手输入、错了回滚重演整局面;服务器回溯是 C/S 下服务器倒带做单次命中判定。确定性网络模型的另一极是帧同步,见 帧同步(Lockstep)。
5. 一句话记住这几个「都在倒带」的概念
四个概念都涉及「回到过去」,但倒带谁的什么、为了什么完全不同——这是面试最容易被追问穿的地方:
| 倒带什么 | 为了什么 | 类比 | |
|---|---|---|---|
| 服务器回溯(本篇) | 服务器把别人的碰撞体倒回你开枪那一刻 | 判定这一枪中没中 | 回看录像判越位 |
| CMC 回滚重放(移动预测) | 客户端把自己的位置倒回权威点,再重走未确认的操作 | 让自己的动作既即时又对齐权威 | 从某笔账起把后面几笔重记 |
| 物理 resimulation(网络物理) | 把一堆刚体倒回某个物理步重新模拟 | 让多体物理结果收敛 | 整叠骨牌重摆再推 |
| 格斗 rollback netcode | 各端把整个局面倒回,用真实输入重演 | P2P 下两端逐帧完全一致 | 两人各自把这几帧重下一遍 |
一句话区分:服务器回溯只倒带「判定用的历史位置」,不重演任何逻辑;另外三个都要重新跑一遍模拟。所以服务器回溯便宜(查历史 + 一次射线检测),后三个贵(按步重算)。
为什么这么做
服务器回溯 = 权威 + 手感的最优折中:客户端判定不可信(作弊),服务器即时判定手感差(要打提前量)。回溯让服务器保留权威(自己倒带、自己判定、自己结算),同时对齐射手视角,让「瞄准即命中」——这是竞技射击的刚需。
减 RTT/2 + 插值延迟:必须精确对齐到「射手屏幕上那一刻」,否则回溯到错误时刻还是判不准。这两个延迟都真实存在于「服务器真相」到「客户端画面」的链路上。
为什么别的选择不行
- 信客户端命中上报:aimbot、伤害伪造全放行,竞技游戏根本没法玩,见 反作弊。
- 服务器只按当前位置判定:高延迟玩家永远打空(敌人早移动了),手感崩,且惩罚网络差的玩家。
- 回溯时长无限:内存爆炸,且给「回溯到敌人静止的远古历史」的作弊留口子。
- 想彻底消除拐角枪:数学上不可能——只要有延迟,射手和被打者的「当前画面」就不一致,公平必然向一方倾斜。承认取舍、按品类选边才是正解。
沉淀结论
三种命中模型:客户端判定(不安全)/服务器即时(手感差)/服务器回溯(主流)。回溯 = 服务器存历史环形缓冲(~1 秒),收到射击按 RTT/2 + 插值延迟 反推回溯时刻,倒带目标碰撞体做射线检测,命中权威结算。UE 需自实现(非自带)。本质取舍:回溯把不公平从射手转给被打者(拐角枪消不掉),按品类选边。
记忆口诀
三模型:客户端判定(不安全) / 服务器即时(手感差) / 服务器回溯(主流)
回溯:历史环形缓冲~1秒 / RTT/2+插值延迟反推时刻 / 倒带碰撞体射线检测 / 权威结算
校验:时间戳合理范围 / 防回溯远古 / 防未来时间戳
UE:无自带组件 / 自实现 or 参考 Lyra
取舍:不公平从射手转给被打者 / 拐角枪消不掉 / 按品类选边
品类:FPS 强回溯 / MOBA 即时权威 / 格斗 rollback
内容来源
综合整理。主要参考:Valve《Source Multiplayer Networking / Lag Compensation》经典文档、Epic UE 网络文档、竞技 FPS 网络码公开分享、Lyra 示例工程。数字为业界数量级估算。
相关专题:移动预测与回滚(本篇的姊妹机制)见 移动预测与回滚;命中的 Server RPC 上报见 RPC;时间戳/命中校验的防作弊见 服务器权威与反作弊;确定性帧同步对比见 帧同步 Lockstep。
自测:合上资料能说清楚吗?
三种命中判定模型的取舍?主流选哪个?
参考答案
① 客户端判定上报:射手爽但作弊风险极高(伪造命中),不可用于竞技;② 服务器即时判定:按当前位置判,防作弊但高延迟玩家要打提前量、手感差;③ 服务器回溯:服务器倒带到射手开枪那刻判定,既保权威(防作弊)又让射手所见即所得。竞技 FPS 主流用回溯。
服务器回溯怎么确定「回溯到哪一刻」?
参考答案
回溯时刻 ≈ 收到射击的时刻 − (RTT/2 + 客户端插值延迟)。RTT/2 是包单程传输时间,插值延迟是客户端为平滑显示别人(SimulatedProxy)而故意滞后的缓冲(约 100~200ms)。两者都减掉才对齐到射手屏幕上看到目标的那一刻。服务器把目标碰撞体倒带到该时刻再做射线检测。
为什么「拐角枪」消不掉?
参考答案
只要有网络延迟,射手屏幕(滞后几十毫秒)和被打者屏幕就显示不同的位置。你已跑过拐角在自己屏幕安全,但射手屏幕上你还没转过去、他开枪;服务器回溯到射手那刻你确实在枪口下,判定命中。这是延迟补偿把不公平从射手转给了被打者——数学上无法两全,只能按品类选择牺牲谁。
UE 自带延迟补偿吗?
参考答案
不自带通用的 lag compensation 组件。移动有 CMC 的预测回滚,但命中回溯通常要自实现(自己维护每玩家历史位置环形缓冲 + 收到射击时回溯射线检测),或参考 Lyra、第三方插件的做法。面试别答成「UE 自带」。