
游戏后端深入剖析 - 《光环:抵达》

设计上的半可靠性: 光环:突击的可扩展网络建立在故意不可靠的复制基础上,借鉴了部落模型,因为放弃交付保证使得优先级引擎能够实现无需达到带宽上限的 16 人对战。
三种协议,一种系统: 状态数据(最终一致性)、事件(零保证,丰富上下文)和控制数据(用于提高预测精度的小型高频输入),每种数据都有一份不同的可靠性合同,精确匹配该数据实际需要的内容。
延迟在哪里?: 每个主机裁决的机制都有延迟。工程工作在于选择将其放在哪里,Bungie 的序列图方法使得在编写任何代码之前就可以将这种权衡显性化。
作为网络工具的机制: Bungie 在《突击》中获得的五大带宽胜利中,有四个是游戏设计的变化,而不是网络代码的变化, 将可感知的不一致性转移到玩家根本不会注意到的地方或窗口。
测量后再切割: 一个定制的带宽分析器集成到《光环》的电影重播系统中,使得从《光环 3》到《突击》的带宽减少超过 80%,其教训是,您无法在没有首先构建数据驱动工具的情况下安全地进行优化。
Bungie 现任技术主管 David Aldridge 在 2011 年的 GDC 上发表了游戏开发网络领域被引用次数最多的演讲之一。该场演讲以“是我先开枪打中你的”为题,揭开了《光环:致远星》16 人竞技多人游戏背后完整网络架构的神秘面纱。
这场演讲涵盖了该游戏架构和设计理念的主要方面,从基础的复制协议和优先级引擎,到在真实网络条件下设计、测量和优化单个游戏机制的实际过程。
间接地,这突出了任何游戏工作室(无论大小)都可以添加到其多人游戏中以帮助改善其在线架构的最佳实践。
[编者注] 鉴于 David 演讲的范围非常广泛,为了便于阅读,我们专门在这篇文章中为每个主要见解添加了“核心要点”。
继承自 Tribes 的架构
《光环:致远星》的网络并非凭空诞生。Aldridge 和他的团队将他们的整个架构基础追溯到 1998 年的一篇 GDC 论文:Mark Frohnmayer 和 Tim Gift 撰写的“Tribes 引擎网络模型”。为了更深入地了解这篇基础论文及其对现代开发者的启示,Edgegap 针对 Tribes 网络模型进行了专门的深度剖析。
Bungie 当时要解决的核心问题是大家所熟知的:
对于在一场对局中的 N 个玩家,要传输的游戏状态数据量接近 N 的平方级别。
在 16 人游戏中,幼稚的“发送所有内容”方法算下来大约需要每秒 20 兆比特的带宽。
换句话说,“完全不可行”。
Tribes 模型为他们提供了答案。该系统建立在半可靠协议之上,而不是建立在每个数据包都必须按顺序到达的可靠传输之上。
“半可靠”这个词听起来像是一种妥协。但它实际上是一个刻意为之的架构选择。
正如 Aldridge 所解释的,“不可靠性使激进的优先级划分成为可能”,这正是使整个系统具备可扩展性的原因。当你不需要保证每个更新的送达时,你就可以让你的流控制层来决定当前什么最重要,并相应地填充每个数据包。没有因连接拥堵而产生的延迟债。也没有因等待重传丢失的数据包而导致系统范围的停顿。
核心要点: 半可靠协议不是捷径,它们是可扩展多人游戏网络的基础。如果你的游戏拥有大量的对象和玩家,保证送达最终会在带宽上击垮你。这就是为什么一个具备高度优化数据同步能力的网络代码是关键。此外,数据意味着出口流量成本,应将其降至最低以确保更低的整体云成本。
三项协议,各司其职
在半可靠的基础之上,Bungie 运行着三种不同的复制协议,每种协议都针对不同类型的数据进行了微调。
状态数据提供一个保证:最新值最终一定会送达。它不保证任何中间值。如果一个玩家的位置每秒更新 30 次,但其中只有 10 次更新成功传输,客户端就会重建正确的当前位置并跳过中间的所有内容。这涵盖了绝大多数游戏属性,包括位置、生命值、计时器以及对局中每个网络实体上的数百个对象属性。
事件则相反:零送达保证。它们可以被完全丢弃。这是可以接受的,因为事件描述的是某事发生的原因,例如为什么生命值条下降了,或者为什么疣猪号掉了一个轮子。如果你当时不在场亲眼目睹这一变化,你只需关心当前的状态。事件的价值在于上下文的润色。状态数据才承载着事实真相。
控制数据是玩家控制器输入的子采样流,尽可能频繁地从客户端发送到主机,并反射回所有客户端。它非常小,每个玩家大约 20 比特,经过精心的人工打包。其唯一目的是预测精度。如果玩家推动摇杆开始向左侧移,由此产生的位置变化在几帧内是不可见的。控制数据会立即传输该意图,让每个其他客户端在位置变化显示在状态数据中之前,就开始预测该移动。
核心要点: 并非所有的游戏数据都应该一视同仁。将持久状态、上下文事件和输入预测分流到具有不同可靠性保证的独特协议中,正是让你能够高效地为每种数据类型服务,而不是为了应对全盘最坏的情况而过度设计。
优先级:引擎盖下的引擎
三种协议为你提供了正确的数据类型。优先级划分则决定了在每个数据包中实际发送什么。
游戏世界中的每个对象都会收到一个持续更新的优先级评分,该评分是针对每个客户端进行评估的。系统会权衡距离、屏幕呈现度、潜在威胁以及最近的交互历史。有些权重符合直觉,有些则不然。
Aldridge 的团队发现,玩家会执着地注视着自己扔出的飞在空中的手榴弹,“即使在扔出后手榴弹对他们来说已经完全无关紧要了”,因此玩家拥有的手榴弹需要比单纯的威胁逻辑所建议的更高的优先级。一具尸体在几秒钟内会获得接近最大值的相关性,因为玩家会在击杀后注视着布娃娃物理效果下倒下的尸体。而在远处角落里滚动的未引爆手榴弹大约每秒只更新三次。
当流控制决定发送数据包时,复制层会按优先级顺序对其进行填充。高优先级对象进入,低优先级对象等待。如果带宽受限,游戏会优雅降级,较不重要的对象更新较慢,而不是停顿整个模拟。其结果是一个没有硬性对象上限的系统,在 16 人对局中支持超过 2,000 个同步实体。
这种针对每个对象、每个客户端的能见度是历经千辛万苦才获得的。Edgegap 的分析为游戏开发者提供了一个具有可比性的服务器和网络性能洞察层,而无需数年的定制工具投入,从而呈现了在实时多人游戏上做出明智且可付诸行动的开发决策所需的数据。
核心要点: 优先级划分是将半可靠协议转化为可扩展系统的关键。要做好这一点,需要针对真实的玩家行为来微调权重,而不仅仅是逻辑上的接近。要做好这一点,还需要拥有能够看到你的网络在实践中究竟在做什么的工具。
绘制延迟图:作为设计工具的时序图
在为任何机制编写网络代码之前,Aldridge 的团队绘制了一个双机时序图:一侧是客户端,另一侧是主机,每个消息箭头的倾斜度都代表传输过程中的单向网络延迟。
这种倾斜正是全部意义所在。它使得每个潜在的重叠、每个易受攻击的窗口期,以及两台机器可能对游戏状态产生分歧的每个时刻,在任何代码存在之前都清晰可见。
扔手榴弹是最清晰的例证。在单台机器上,流程很简单:按下触发键,起手动画,释放帧,手榴弹发射。问题在于如何在不产生穿帮的情况下引入第二台机器。
方案一:在开始动画前向主机请求许可。画出这个流程会立即暴露出问题。在客户端收到对其按键操作的任何反馈之前,存在一个完整的往返时间间隔。“玩家极度讨厌这种设计,”正如 Aldridge 所说。完全不可接受。
方案二:在本地扔出,同时告知主机。这种方法没有可见的延迟窗口,听起来不错,但这意味着实际上没有进行主机判定。这就是在悄悄累积延迟债,以后肯定会显现为不同步。
实际的答案是第三条路:在按键时预测动画,但在释放帧时暂停生成手榴弹。玩家的手臂立即移动。手榴弹在释放帧处消失。一个创建请求发送给主机。主机的确认大约在一个往返时间后到达。
在那个窗口期,玩家被放大的手臂动画填满了屏幕的三分之一。在扔手榴弹时,玩家看的不是自己的手,而是通过十字准星进行瞄准。他们注意不到长达 150 毫秒的时间差。据 Aldridge 称,休闲玩家甚至注意不到长达 200 毫秒的时间差。这解释了为什么 Bungie 在三部《光环》作品中都采用了这种投掷手榴弹的设计。
核心要点: 双机时序图是网络设计中最实用的工具之一。在编写任何代码之前,用明确的延迟箭头勾勒出机制,将暴露延迟窗口和延迟债,而这些在其他任何方式下几乎都是无法发现的。
[编者注:并不是每个人都拥有 Bungie 在开发像《光环》这样的 AAA 游戏时所拥有的资源。优化是关键,但预先规划是一种奢侈。这就是为什么确保在制作过程中留出时间来优化你的游戏服务器、网络和整体后端,对于性能和成本效益至关重要。]
延迟在哪里?
David 和他的团队使用的时序图方法直接引出了演讲中最重要的规则:永远要问你把延迟藏在了哪里。
“如果存在主机判定,你就必然会在某个地方产生延迟。如果你在任何地方都没有延迟,那么你实际上就没有主机判定——你已经欠下了延迟债。”
延迟无法被消除,只能被转移。设计工作就是选择把它放在哪里,放在玩家不会注意到的地方,或者它对感知的影响小到可以发布。
每个工作室都可以利用的一个重要手段,就是简单地通过服务器部署来降低基础延迟。Edgegap 的编排平台通过将游戏服务器部署到离你实际玩家群体最近的地方,将平均延迟降低了 58%。这并没有消除“延迟在哪里”的问题,但它大幅收窄了你开展工作的边缘空间。
换句话说,200 毫秒的往返时间与 40 毫秒的往返时间需要非常不同的设计权衡。较小的游戏工作室受益尤甚,因为这样就不需要把那么多的网络开发精力放在隐藏那些本来就不应该存在的延迟上。
核心要点: 延迟不仅是一个需要修复的 Bug,它更是一个需要明智支出的预算。通过智能服务器部署缩短基础往返时间,有助于在你的网络工程师开始接触该问题之前就缩小该预算问题。
当最好的网卡修正是游戏设计修正时
在《致远星》中,Bungie 的五个主要网络“优化胜利”中有四个来自于改变游戏机制,而不是网络代码。
这是这场演讲中最违反直觉、也可能是最持久的教训。
装甲锁定的例子让这一点变得具体:
机制:按下按钮,播放一个三帧的开场动画,获得无敌状态和无限质量。
在发布版本之前经历了两个失败的迭代。
两者都存在一个窗口期,即在开场动画期间,手榴弹可以在主机上爆炸并造成伤害,导致已经在自己屏幕上看到蓝色护盾的玩家承受了他们确信自己对其免疫的伤害。
在每次测试版发布后,论坛上都有成千上万的相关帖子。
最终版本引入了一项针对性的修改。
正如 Aldridge 所描述的:“我们介入并拿走了设计师精心调整的帧延迟数值,为了网络而对其进行了强行改动。我们实际上改变了游戏的玩法。”主机提早激活护盾,将开场延迟缩短了测得的主机与激活客户端之间的往返时间。当客户端看到护盾出现时,它与他们的预期相符。不一致性被转移到了最在乎的玩家(即使用装甲锁定的玩家)之外,转移到了主机和其他玩家身上,他们几乎察觉不到别人的护盾是否早开启了几帧。
刺杀机制也经历了类似的历程。发布的版本使用了一个大约四分之三秒的纯视觉插值混合来吸收进入时的位置差异。在调试模式下,该混合是可见的,动画师们立即指出了这一点。但在游戏中,它是不可见的。在每次刺杀开始时,摄像机会拉出到第三人称视角,并在该窗口期内以每秒大约 25 英尺的速度移动。玩家的空间参照变化如此之快,以至于 20 英尺的混合完全被忽视了。他们的大脑自动补全了连贯性。
布娃娃物理效果解决方案将这一原则发挥到了极致:完全停止对布娃娃物理效果进行网络传输。仅在所有同行之间同步初始死亡状态。在此之后,让物理效果在本地分化。两个设计考量得以解决:
首先,布娃娃阻挡子弹的问题(通过允许完全穿透且无副作用来解决);以及
光环社区由来已久的在倒下对手的尸体上蹲起嘲讽的传统,这要求布娃娃物理效果处于大致正确的位置。
两者都是可以解决的,没有人注意到这些改变,结果是释放了大约 10% 到 12% 的带宽。
核心要点: 你的网络工程师和你的游戏设计师需要从一开始就协同工作。一些最有效的延迟解决方案根本不在网络层中。它们存在于机制本身的设计中,存在于能够无形中吸收不一致性的感知窗口和玩家注意力模式中。
先构建工具,再进行优化
Aldridge 引用了一条优化法则:“程序优化的第一条法则:不要做。第二条法则,仅适用于专家:现在还不要做。”
Bungie 知道他们需要优化,因此他们在触碰任何网络代码之前,先构建了安全进行优化的工具。
带宽剖析器追踪了整个模拟过程中的使用情况和优先级结果。
而真正的能力来自于将剖析器数据拼接到《光环》现有的影片系统中。
影片是确定性的游戏记录,自《光环3》以来就是一项面向用户的功能。Aldridge 的团队在每个游戏帧后注入一个调试二进制大对象,其中包含在该刻采样到的所有网络状态、发送和接收的每个数据包以及每个优先级划分决策。正如他所说,“这在光环历史上尚属首次”,他们可以在事后分析网络性能,倒带到任何时刻,过滤到特定的客户端,并准确地检查什么在何时传输给了谁。总开发时间:核心工具大约花了六个星期。
该工具集直接实现了从《光环3》到《致远星》超过 80% 的带宽减少。
它所呈现的一个例子是:在地面上滚动的闲置手榴弹在优先级层上消耗了不成比例的带宽份额。其根本原因是《光环3》末期的一个 Bug 修复,该修复大幅提高了装备对象的优先级,以解决关于延迟的投诉。由于设计上的意外,手榴弹和装备共享了相同的父类。每个地图上掉落的每个手榴弹都继承了该提升,并在任何时候都被视为高优先级。一个单行的修正(即:仅将提升应用到活跃的装备上)释放了大约 20% 的带宽。
对于没有六个星期来构建定制剖析基础设施的工作室,Edgegap 的分析工具可以呈现实时和历史性能数据的容器层和游戏服务器层,帮助团队捕获 Bungie 定制剖析器旨在发现的那些系统性模式、带宽异常、对象级优先级问题、服务器帧时间峰值等。
核心要点: 网络熵是悄无声息地累积的,你无法修复你看不到的东西。在优化之前投资于深度的检查工具不是可选的,因为正是这项工作才使得优化成为可能。
将感知延迟转化为一门科学
在模拟网络条件下进行游戏测试为 Bungie 提供了一个受控环境,但“对局质量”的衡量问题却更难。正如 Aldridge 所指出的,玩家“可以告诉我们他们是否玩得开心,这几乎与他们是否获胜完美相关。”这还不够细致,无法指导工程决策。
解决方案:在游戏测试中提供一个专用的控制器按钮,将带有时间戳的调试事件直接注入到影片中。每次玩家感觉到延迟时,他们就会按下它。工程师们跳转到那一帧,检查完整的网络状态,并进行调查。当团队可以运行在他们的带宽目标上并且看到游戏测试者零按键时,他们知道他们成功了。
产生了一个有用的副作用:玩家不仅在遇到实际网络问题时按下该按钮,而且每当游戏机制让他们感到困惑或失去方向时也会按下它。
在几乎满血的状态下被一颗手榴弹一击必杀感觉就像是延迟。没有清楚解释死因的死亡镜头感觉就像是延迟。工程团队会调取这些影片片段,带着数据直接去找设计师。网络工具变成了游戏设计的反馈闭环。
核心要点: 感知延迟是一个产品信号,而不仅仅是一个网络指标。为游戏测试者构建一种能够精确标记它的方法(当与可重现的游戏状态挂钩时),可以将模糊的抱怨转化为对工程师和设计师来说都可付诸行动的数据。
智能主机选择与主机迁移的成本
主机迁移,即当当前主机的连接退化时在会话中途切换到更好的主机的行为,在起作用时是非常强大的。
然而,Aldridge 承认这可以成为一个专门的独立演讲,因为它是一项重大的工程任务,考虑采用它的工作室不应低估其范围。
《六日伊拉克》的首席网络工程师,来自 Highwire Game 的 Michał Buras,在他的演讲中剖析了主机迁移复杂性在对等网络 (P2P) 和基于中继的多人游戏中带来的挑战级别,这在致力于该途径之前是一个有用的参考。
专用服务器完全规避了这一问题。由于专用服务器充当主机,因此没有可供迁移的主机,会话连续性从而在基础设施层面进行管理。
核心要点: 由谁来托管会话与你如何设计会话同样重要。P2P 或基于中继的网络架构中的主机迁移具有一定的工程成本,而专用服务器基础设施可以完全避免这一成本。
数据及其对带宽成本的意义
《致远星》的最终基准:16 人游戏以 250 kbps 的带宽稳定运行且无延迟穿帮,而设计目标是 384 kbps。相比《光环3》,总带宽减少了 80% 以上。
节省的每一千字节都有双重意义:
首先是对玩家而言,因为较低的带宽要求意味着你的更多玩家群体可以在更广泛的连接类型下顺畅运行游戏。
其次是对你的基础设施账单而言,因为出口流量成本直接与你的服务器传输了多少数据成正比。
因此,优化复制、嘀嗒率 (tickrate) 和优先级逻辑,也就是在优化你的云支出。对于寻找具体起步点的 Unreal Engine 开发者,Edgegap 发布了一份 Unreal Engine 服务器剖析和优化清单,Unity 的等效清单也正在开发中。
核心要点: 带宽优化不仅是一个网络质量问题,也是一个直接影响游戏本身盈利能力的商业成本问题。因此,对复制效率的每一次改进都会直接减少出口流量支出,使其成为少数几个在玩家体验和基础设施预算两方面都能获得回报的工程投资之一。
—
本文基于并引用了 David Aldridge 在 GDC 2011 上的原始演讲,该演讲发表在 GDC YouTube 频道上。原始内容中的所有权利均归其各自所有者所有。
书写者
Edgegap团队









