Post

DOOM3网络架构

DOOM3网络架构

前情提要:本篇为翻译,原文地址如下:

The DOOM III Network Architect

The DOOM III Network Architect \ DOOM3网络架构

Abstract \ 摘要

一个能提供玩家快节奏的强交互游戏环境的电脑游戏必须要提供一致的响应及时的体验。然而,在电脑游戏的运行基于网络连接的情况下,这是困难的,因为网络环境充斥着强制因素,比如带宽,信息到达目的地的延迟。所有的网络架构都需要实现一致性,响应性,带宽和延迟要求之间的权衡。根据游戏类型和网络环境指定平衡策略。这篇论文展示DOOM3的网络结构。

Introduction \ 介绍

fps游戏中,玩家在实时的虚拟环境中移动,以第一人称的视角观察环境。玩家通过控制虚拟玩家的眼睛进行观察。在第一人称射击游戏中,最重要的任务是保持生存并使用各种武器消灭虚拟对手。第一人称射击游戏高度互动,通常速度很快,注重速度和准确性。一个好的第一人称射击游戏旨在让玩家沉浸在行动中。

多人游戏需要共享显示。玩家在一个虚拟环境中共享体验,不同的视角下,玩家能看到发生在虚拟世界中的同样的变化和时间。每个玩家都有自己的计算机,这些计算机通过本地网络或互联网相互连接。网络用于共享信息,使所有玩家都能体验到相同的虚拟环境。

一个能提供玩家快节奏的强交互游戏环境的电脑游戏必须要提供一致的响应及时的体验。玩家能够及时接受到做出的动作的反应是非常重要的。不同玩家观察到相同的事件接受到的信息是相同的也是非常重要的。然而,网络的限制导致提供一致的高响应的环境非常困难。首先的限制是带宽,因为我们有大量的数据需要传输。然后是处于不同网络的计算机之间数据的发送和接受存在延迟,这也就是我们常说的网络延迟。尽管这些年网络的发展,带宽大大提高,但是延迟并没有太大的发展。根据资料,现在的网络延迟正常在50-100ms之间。即使使用快速玻璃光纤连接,如果世界不同地区的人们想要互相玩耍,也不可避免地会产生相对较大的延迟。

在多人游戏中,总会有人觉得有必要通过独创性来克服技能不足的问题,比如利用网络架构中的 bug 或漏洞,或者实施各种作弊。在设计网络架构时,重要的是要考虑系统可能容易受到的作弊。另一个重要问题是安全。个人可能会试图卸载服务器或以其他方式破坏游戏。也许更糟糕的是,个人可能会试图将游戏作为工具来攻击网络或互联网上的计算机。一个强大的网络架构可以抵御攻击和滥用。最后但同样重要的是,可移植性可能在网络架构的设计中发挥作用。一些网络模型比其他模型更适合跨平台多人游戏。

第一人称射击游戏中的游戏状态通常被建模为游戏对象或实体的列表。玩家、敌人、子弹、门等都是游戏中的实体。与其区别对待所有这些特殊目的元素,不如将它们绑定在一个系统中,提供共同的结构和通信方法。类层次结构和功能组件通常用于对不同实体进行建模。第一人称射击游戏中的网络化完全是关于同步相同游戏实体的多个副本的状态,以便所有玩家在虚拟环境中经历相同的变化和事件。一些网络模型要求所有玩家管理和维护他们自己的所有游戏实体副本,其中使用相同的规则和方法来同步推进这些实体的状态。其他网络模型不断通过网络传达实体状态的变化。

PreWork \ 提前工作

本文翻译于2025年,此时绝大部分的游戏的网络结构采用CS架构,S端甚至是分布式架构。P2P、Package Server架构已经过时,所以不予翻译。感兴趣的读者可以自行浏览原文。

Client-Server

在CS模型中,服务端负责进行游戏逻辑的决策,客户端处于玩家处,负责渲染。客户端向服务端发送按键信号或者视角视角信号,并接受一系列实体进行渲染。这样的网络模型不会受到去同步网络游戏的影响,因为服务器是权威的,而去同步网络游戏之间存在分歧。玩家可以在任何时候加入退出游戏,因为客户端不需要对状态进行持久化。服务端发送快照 / snapshot(用于更新游戏状态和渲染的一系列游戏实体列表)为了减少带宽压力,发送的快照从客户端接收到的最后一个快照进行压缩。然而,更新事件的发生并不常见,发生频率通常在10hz到20hz。为了表现平滑的变化中的高交互的环境,客户端会在最后收到的两个快照中进行插值或推断。

如果没有特殊的措施,CS模型也将面对上述说的p2p模型的问题,随着玩家的网络延迟增加,会影响整个系统的响应能力和可玩性。客户端向服务端提供输入,服务端处理输入。客户端只会从服务端接受快照,并使用快照中的内容进行渲染。换句话说,使用cs网络模型,从对输入进行采样到客户端屏幕上看到结果,至少需要一个完整的ping时间。为了解决这个问题,客户端会对玩家的移动进行预测。产生的输入不仅会发送个服务端,同时也会在客户端中进行预测。然而,客户端中对于环境变量的显示仍然是基于服务端的快照的插值或推断的结果。换句话说,玩家在 (预测的) 现在中移动,而玩家在屏幕上看到的是过去。

CS网络模型同样可以被视为异步的网络架构。客户端和服务端之间的上流和下流通信是不同的。还有,客户端中的玩家移动是实时渲染的,但是游戏的状态是过期的,环境的建模也是过期的基于过去收到的快照的。Quake 系列游戏中使用的网络模型非常有效,此后已被广泛应用于许多游戏中。这种网络架构比p2p网络模型更适合在互联网上进行快节奏的第一人称射击游戏,但仍然存在一些问题。

CS网络模型允许玩家中途加入游戏,游戏将不会继续当服务端关闭。一种情况是使用保证长时间运行的主机运行服务端,然而,如果专用服务器不可用,可能需要实施服务器迁移,以便即使运行服务器的玩家决定离开游戏,游戏也能继续进行。(也就是互联网中的容灾问题)

在客户端预测中,玩家在当下移动,而玩家在屏幕上看到的是过去的画面。这样也导致了玩家在某个时机进行射击时实际上是对过去的对象进行射击。然而,击中判定是发生在未来的服务端中。换句话说,玩家必须预测未来某个时间任何目标的位置,并且必须引导这些目标,以便在未来击中它们。即使玩家只需要提前 100 毫秒预测,这也可能很棘手,需要一些练习。

一些游戏,比如Half-Life,尝试减轻这些问题通过实现“延迟补偿”。这个想法是让玩家向过去位置可视化的对手射击,当服务器进行命中检测时,它会及时回溯以验证目标过去是否被击中。为此,服务器必须跟踪所有可能对手的过去位置历史记录。这种技术不仅增加了相当大的复杂性,还带来了几个不必要的副作用。拥有快速 (低延迟) 连接的玩家将经常遇到不一致的情况。例如,玩家可能在安全地绕过拐角后被击中。其他玩家的连接质量越差,这种情况就会越频繁地发生。换句话说,玩家不再能够控制自己游戏体验的质量。

延迟补偿还是存在缺点的,因为它可能导致一些时间的发生,而这些时间并不是基于共同的现实的。举个例子,有两个玩家,一个低ping时,一个高ping时;玩家围绕一颗树进行移动,因此树会挡住低ping玩家的预测开火线。高 ping 的玩家在本地实时移动,同时从相对遥远的过去位置观察对手。这个玩家对树的观察就不会被遮挡。在延迟补偿下,高ping玩家可以在此时击中低ping玩家,因为服务器确实能够检测到过去位置的对手,同时保持玩家当前的位置。显然,在这个例子中,Ping 较低的玩家可能会被击中,而从该玩家的角度来看,这应该是不可能的。在这个特定的实例中,问题可以通过下面的方法得到轻微的缓解:不仅使用对手的过去位置进行命中检测,还使用对手的当前视线来缓解问题。只有在过去的时机击中才会被记录,并且要需要有即刻的清晰的视线。尽管额外的视线测试能够减少玩家在某些情况发现不一致的可能性,但并不意味着他同样解决了其他情况下的不一致的问题。

尽管延迟补偿比其他的替代方案更好,但是它仅仅定位了问题的一部分。射击的位置检查会被回滚一段时间,但是玩家与周围环境的交互仍是基于实时的移动状态和过时的环境状态。

在(运行在服务端中的)QuakeIII的代码和仿真预测代码(运行在客户端)是单独的区分的模块。尽管是单独的模块,但是每个模块都必须清楚另一个模块的实现,以保持游戏表示的合理同步。模块间的高耦合是不合理的因为会导致代码的可扩展变得非常困难。所以会发布两个版本,一个是多人游戏版本下的客户端和单机版本下的客户端。

为了平滑的展示变化的环境,客户端会在最后收到的两个快照中进行插值或推测。除非考虑到物理学和游戏规则,否则这种推断可能会产生不切实际的结果。比如,对于弹道轨迹的预测,如果没有考虑物理规则,可能会预测导致子弹表现违反物理规律(穿墙等)。适当的外推会在客户端引入额外的复杂性和更多需要与服务器上运行的代码同步的代码。

在复杂的游戏引擎中,插值可以非常困难的,因为实体的状态是复杂的;并且完善的插值通常是昂贵的或者弱定义的。比如,可用于动画系统的骨骼动画系统被用来产生人物动画,并且可以进行任意的骨骼修改以达到特定效果。首先,需要将完整的骨架发送到网络以进行适当的插值。此外,还需要在四元数之间进行昂贵的球面线性插值,才能在最后两个快照的骨架之间进行插值。

在 Quake III 竞技场中,客户端的快照仅包含客户端潜在可见集 (PVS)[34] 中那些实体的状态。此外,快照中的实体状态只能相对于前一个快照中的实体状态进行增量压缩。因此,持续离开和进入 PVS 的实体状态不能进行增量压缩。每当实体进入 PVS 时,它的状态必须在下一个快照中完整发送。在一个包含许多需要在网络上同步的实体的环境中,这可能会导致大量带宽消耗。

Quake III Arena 中的大多数网络流量都是通过发送不可靠的消息产生的。如果它们被丢弃,通常没有必要重新发送相同的快照,因为它们包含的信息很快就会过时。然而,可靠的消息也可以在 Quake III Arena 中用于特定的、通常不频繁的更新。在 Quake III Arena 中发送可靠消息的唯一方法是使用服务器命令。这些服务器命令是基于字符串的,效率低下。然而,通过可靠的消息同步游戏状态的一小部分可能非常方便。像 Quake III Arena 中那样使用基于字符串的服务器命令会带来相当大的开销。

为了将实体状态写入快照,Quake III Arena 使用具有固定数据字段的固定实体状态结构。其优点是所有实体都具有相同的结构,并且可以使用单个优化例程进行增量压缩。另一方面,不同类型的实体可能维护着相当不同的状态变量,开发人员经常最终会在不同实体上出于不同目的重复使用实体状态结构字段。在一个包含许多不同实体且维护着完全不同状态变量的游戏中,对所有实体使用固定的实体状态结构很快就变得不切实际。

这里提出的 Doom III 网络架构与 Quake III Arena 的网络模型类似,但试图解决其中的几个问题。

Network Architecture

DooM III 的网络架构是基于客户端-服务端架构。服务端产生游戏状态的快照,并将其发送给客户端。客户端使用的快照中包含着所有游戏实体的压缩状态。每个客户端实例产生输入,发送玩家意图给服务端。

除了玩家的输入,第一人称玩家射击游戏的一切都是固定的。即使是随机数生成器也是伪随机的,根据初始值(seed)产生的相同的随机数序列。此外,Doom III 游戏状态始终以固定的帧率 60 帧每秒更新,与计算机速度无关。同样的游戏引擎对于相同的玩家输入会产生相同的结果。使用这种决定论来复制客户端的信息是有意义的。为了呈现一个平稳变化的环境,Quake III Arena 客户端在最后两个快照之间进行插值或外推,并使用客户端对玩家移动的预测来提高感知响应能力。这里介绍的系统使用对客户端 PVS 中所有实体的预测来提高响应能力,并呈现一个平稳变化的环境。这包括对玩家移动的预测,因为玩家控制的化身也是客户端 PVS 中的实体。

服务端不会等待用户的输入去处理游戏。如果没有新输入及时到达以处理下一个游戏帧,服务器将重复旧玩家输入。客户端尝试确保服务端经常收到新的输入以推进服务端的游戏状态。相同的,客户端时间是领先于服务端时间的。客户端运行的时间刚好足够长,以便玩家的输入可以立即在客户端进行处理,并可以通过网络发送到服务器,在服务器需要处理输入以推进游戏之前到达。图 4 显示了一个时间线,其中包含服务器时间、客户端时间和到达客户端的快照时间。

网络中的ping值是会波动的。因此,客户端不会仅仅跑在服务器前面足够远,以至于根据当前或平均延迟,输入能够及时到达服务器。客户端会稍微提前一些运行,这样即使发送到服务器的网络消息延迟有一些波动,输入也能及时到达。客户端能够通过使用预测来提前实体的状态,从而领先于服务器。服务器以 10 到 20 赫兹的速率向客户端发送快照。虽然没有新的快照到达,但客户端会按帧预测实体的状态。收到快照后,客户端会用快照中的实体状态覆盖其实体状态。客户端收到的快照来自过去至少一个完整的 ping 时间,相对于客户端的当前时间。因此,客户端在处理快照时会暂时回溯时间。然后,客户端必须快速重新预测从这个状态到当前客户端时间的时间,从那里客户端可以继续按帧进行预测。图 5 显示了客户端的预测。

This post is licensed under CC BY 4.0 by the author.