为了让多个玩家在不同的机器上一起玩游戏,需要一个机制保证所有机器保持同步使得玩家看得见游戏状态的精确和流畅的表现,并允许玩家输入影响共享的游戏状态。
这个游戏状态代表游戏回话的当前状态(或者在MMO中,游戏世界的当前状态),包括所有玩家,NPCs,或者其他单位的位置和移动;子弹和炮弹;以及像积分,资产和资源的状态值。像移动,碰撞,命中检查和生成投射物这样的游戏事件会影响游戏状态,可以是来自玩家的输入,也可以来自游戏引擎的AI逻辑处理。影响它的状态和事件必须在所有机器之间以某种方式同步;否则,一个玩家在他们自己的机器上看见的对象对另一个玩家来说并不是他们所在的位置,导致混乱或者不公平游戏。
在可能以不同速度运行的不同机器上执行所有这些同步,同时处理比如延迟,丢包和有限带宽的物理限制,所有这些都属于这个通用术语“NetCode”。
为什么网络代码很难:延迟
网络中的延迟是信号从源端到目的地所需要花的时间。在处理Netcode时,我们永远不能假设一个信号能瞬间从A到B,事实上Netcode的存在就是为了处理这个事实。
当两台机器之间存在延迟,在一台机器上产生的任何事件需要些时间才能到达其它机器。如果延迟足够长,在其它机器上的游戏状态可能都已经移除了,结果就是该事件应用在不同机器上稍有不同的游戏状态,导致不同的结果。
举一个简单的例子,想象一款简单(且存在缺陷)的FPS游戏,在这款游戏中,玩家向另一名正在瞄准的玩家射击;射击事件会发送给其他玩家,并且花费一些时间才到达。由于网络延迟,等事件达到时,其它玩家的游戏状态可能已经更新到他们不再和十字线对齐的位置,结果就是在主动射击的玩家命中,在其它机器上没命中,如果延迟无法明确原因,在两台机器上的游戏状态将再也无法同步。
网络连接的基础延迟主要有以下三个原因:
- 无法打破的物理速度限制:光速
没有速度可以超过光速的信号,无论我们科技有多强。思考一下,在悉尼的玩家连接在纽约的服务器,超过地球1.6万公里(或1万英里)的距离。一个以光速传播的信号需要53毫秒才能到达这个距离。
现实中,数据传递的实际距离大得多,因为数据必须通过Internet连接到本地交换机,然后传输到位于悉尼的国家互联网骨干,潜入海底光纤电缆,它从澳大利亚蜿蜒而出,沿着海底到达斐济,然后到达夏威夷,它于美国接壤,沿着华盛顿州的海岸线,然后是一条通往芝加哥的路上光纤,然后是另一条从芝加哥通往纽约的光纤,也就是信号到达服务器的地方。而且光信号在光纤的传播速度比在空气或者真空中的要慢,可能最多会慢30%。由于额外的距离和较慢的传输速度,这个53毫秒的延迟数字很可能更接近于80ms。
2. 包路由延迟
在这段传输过程中的多个点,数据包必须被一些网络设备读取,这些设备决定了接下来要往哪条线发送数据。这个要求数据的部分被读取进设备的处理器,在沿着正确的线路被路由到距离预期目的地更近一步的网络节点之前,它的目的地地址被提取出来并与路由表相匹配。
很不幸的是,以上的操作都需要时间,每次这样做的时候,一个小延迟就会加到数据的总传输时长,考虑到必须路由数据到目的地的大量网络节点所造成的延迟,80ms的信号传输延迟很可能变成100ms。
3. 往返、确认和重新传输
根据所使用的网络协议,以及数据包丢失的可能性,沿着这条线可能需要多次传输才能完成这个数据的传输。比如,TCP包需要从目的地机器的接收确认来保证数据被正确传输了;如果没收到确认,或者数据接收中断或者不完整,发送方会重试重新传输。
这个意味着使用TCP和其它需要确认的协议,最好可能最多只需要一个往返就能完成数据传输,最差(在数据丢失和重传尝试的情况下)多个往返。在悉尼到纽约的例子中,很明显,由于传播和路由延迟,现在的传输延时是100ms,一个往返时间翻了一番,达到200ms;每一次额外的重传尝试都是这个数字的倍数。
所以在最好的情况下,玩家信号的往返时间(Round-Trip-Time)有200ms。没法让它更快了,事实上,在发生网络堵塞,网络中断,包丢失和路由更新的事情时,以上这些都会引入暂时的额外延迟(也被称为滞后峰值),会明显变得更差。
幸运的是,对于本地网络多人游戏来说,延迟情况要好得多,使用相同有线本地网络的电脑的ping时间是1ms或更低,使用最新WiFi标准的无线网络的电脑的ping时间是4ms或更低。然而,即使一个游戏被设计成只在本地网络sub-1ms网络延迟,延迟必须由netcode正确占了,还有一个意想不到的真正的机会延迟飙升造成的网络或计算机的内部阴谋。即使是一个延迟峰值也足以让一款没有处理延迟的游戏失去同步。
在第2部分中,我们将讨论游戏客户端彼此连接的不同方式,无论是否有专门的游戏服务器