网络同步技术理解

记一下自己对网络同步的理解。

网络同步主要有二种,帧同步和状态同步。

帧同步

帧锁定同步算法。具体不介绍。
大致意思是客户端和客户端每一帧发送“cmd”,客户端收到所有的输入后,根据这些cmd模拟一帧。因此网络延迟与网络状况最不好的玩家有关。

状态同步

主要参考https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
之前参与开发的一款FPS游戏就是基于这个架构。
假设是一个Client/Sever架构。对于一个游戏,理想的情况下,服务器每一帧把客户端的输入收集并计算结果发给客户端,客户端只负责表现结果(即像看一段实时视屏,没有运行逻辑)。

基本网络

正常情况下,服务端会有一个运行帧率。比如15ms,即每秒66.6帧。服务器每一帧处理用户的cmd,运行物理模拟,运行游戏逻辑,更新entity的状态。模拟结束后,服务器选择对客户端发送快照(snapshot,当前游戏的状态)。如果加大运行帧率会提高模拟的表现,但是对服务器的cpu负担和客户端的带宽就会有更高的要求。一般客户端的带宽是有限的,如果服务器发送的高频率数据,客户端会有数据包丢失。同样客户端发送的cmd也会根据自己的带宽设置(每秒发送多少个cmd)。
客户端每一帧向服务器发送指令(移动,开火等),服务器收到处理后返回游戏世界所有实体的快照,客户端收到这个快照(这个时间叫latency或者叫ping或者叫round trip time)。可以知道这个lantency越小,游戏的表现越好。
因为网络延迟是不可避免的,那么使得游戏的表现更好呢?
使用预测和延迟补偿技术就是为了提升游戏表现(减小高延迟玩家和低延迟玩家的不公平)。

差值

由于客户端收到的一个一个快照(正常是20个每秒),如果只是根据快照去更新的话,表现会非常卡,除非快照频率非常高(对服务器来说CPU和网络的压力会大大增加)。为了解决这个问题,客户端引入了快照缓存(snapshot history),根据网络状况和参数,计算一个延时值,比如当前时间的前0.1s(这个时间叫RenderTime),然后根据RenderTime计算在这个RenderTime二侧的SnapShot,根据时间进行差值然后渲染。这个时间一般是大于二个snapshot发送过来的时长,这样即使有一个snapshot由于网络原因丢失了,另外一个包还是可以进行差值。
网络同步技术理解
按照上图为例,当前的时间是10.32s,最新收到的快照是344,假设差值延迟是0.1s,那么rendering time为10.22,当前的渲染帧数据可以根据340和342差值得到。如果342快照丢失了,我们还可以根据340和344快照来进行差值。如果342和344都丢失了,那么差值就会工作不正常,需要使用额外的差值(extrapolation, 一种简单的做法是复制当前帧)

预测

假设我们的网络延迟(latency)为150ms,我们在客户端按w,想要移动角色,客户端A把向前移动的cmd发送给服务器,服务器收到命令后,把客户端A的状态设置为向前,并同步给其他客户端,其他客户端看到A开始移动了。
上面的流程,表现在客户端A为不流畅,操作迟钝。使用客户端预测可以去除这个延迟并使操作更加流畅。不等到服务器把A的位置更新,客户端预测执行命令的结果。这需要客户端和服务器需要对这个命令有共同的处理结果(即需要共用代码)。预测结束后A移动到了新位置,服务器上A的数据还是在旧位置。
过了150ms,客户端收到了服务器的snapshot,snapshot包含了A在服务器上执行命令得到的新位置。客户端比较自己预测的位置和snapshot的位置。如果二种一样,嗯万幸预测成功了。如果不一致,说明预测出错了(可能A在服务器上计算时,被其他玩家冻结住,或者打击退了),说明客户端A在预测执行的时候并没有正确的其他玩家和环境的信息。服务器有绝对权,所以客户端需要纠正自己错误的位置,一种是直接拉回到服务器的位置,二是使用平滑差值到服务器发过来的位置。
预测只对自己有效,因为你知道客户端的命令,但是不能预测其他玩家,你不能预测其他玩家的命令。

延迟补偿

假设我们在10.5对敌人B开了一枪,这个开枪的命令通过网络发送到服务器。在这个开枪命令发送到服务器之前,服务器还是在对世界进行模拟,当命令达到服务器时,B可能移动到一个不同的地方,如果命令在10.6到达,那么这个开枪不会被命中,即使在客户端A完全对准了玩家B。
网络同步技术理解
补偿系统是保存了所有玩家在过去1s的信息(可以是服务器发送snapshot的历史,它包含了说有的玩家信息)。
那么实际的击中模拟时间应该是
comandExecuteTime = ServerCurrentTime - Lantency - ClientViewInterpolation

服务器回到comandExecuteTime 这个时候的状态(只有玩家的位置和动作),计算开枪命中,计算结束后回到ServerCurrentTime的状态。
上图是一个例子。服务器有200ms的latency。左边红色是客户端100ms+差值时间之前的hit。当射击命令到达服务器,玩家B已经到了左边的位置,服务器回溯当前世界,玩家B现在是蓝色包围盒的位置,计算击中计算。红色和蓝色不完全一样是因为时间的精度差异(latency在实际的网络也不是一个固定的值200)。对于快速移动的物体,这个差异会更加明显。

未完待写

2019年7月7日

参考

http://t-machine.org/index.php/2008/03/13/entity-systems-are-the-future-of-mmos-part-4/
https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
https://www.cnblogs.com/yangrouchuan/p/7436389.html