帧同步与状态同步
本文写的是自己学习帧同步和状态同步的一个记录。
早期网络游戏是P2P模式,常见于局域网。P2P的实现原理是对于相同的软件系统,同样的操作会得到同样的结果。P2P当中每台机器都在设定的时间T的末尾对收集到的各个玩家操作进行计算。循环该过程直到最后。这样可以保证每个玩家得到相同的结果。这种模式下每一帧所有的机器都会进行同步,所以叫帧同步。
经典的帧同步会在时间段T的末尾进行排查,看看是否接受到了所有玩家的操作,包括空操作,如果没有就会等待。你还没来,我就等等你,颇有种侠义精神,也符合当时局域网环境都是好哥们一起开黑的情景。当然讲义气的代价就是所有人都有等待最慢的那个,一个人卡大家都卡。后来为了解决这个问题出现了PacketServer,是一个专门用来收发操作包的服务器,大家都通把操作发给服务器,然后在末尾得到服务器发送的经过确认的操作合集进行计算。在这种情况下,卡的人就只会影响自己,好哥们先行一步。(服务器卡了当然全完蛋,这种灾害哪种同步模型都没办法解决)
在基本的帧同步方式中,服务器只是不加判断地接收并转发客户端操作,让各客户端自己进行计算,这就会导致外挂很多。为了解决外挂问题,除了运行反作弊服务器对客户端上传的操作进行判断,还可以把计算提到服务器,让服务器计算出各种对局状态并且向客户端发送状态列表,这就有了状态同步。客户端只进行渲染和操作上传。当网络足够好,带宽足够大,甚至连渲染都可以放到服务器,客户端只需要接受渲染好多帧,当做能控制的播放器,这就是云游戏。
帧同步的断线重连是个大问题。因为只需要转发操作,服务器只能拿到各个客户端从T0时刻开始的各操作,而不知道各个时期大家的状态。现在一台机器从T1时刻开始断线,到T2时刻重新连上,这时候从它原有的状态到现在的状态只能靠它自己拼命的去算,一直算到和大家一样的T3状态,从T2连上到T3算完之间可能要过好久,更可怕的是大退之后啥也没保留,要从T0开始计算,当然如果客户端不保留操作也要就算是大退也要从T0开始。连上后很长时间不能动,这显然是很不好的体验。
放着这个问题不谈,假设大家的网络都比较稳定,但是在互联网上大家隔的很远,就有了延时问题。为了解决延时问题,有了预测技术。预测技术让客户端来预测丢包中间发生了什么,比如位置间突然出现两个大的跨度可以加速,达到一种比较好的体验。
帧同步只要记录好操作和随机数种子帧同步可以很容易回放出战斗过程。状态同步也能接受到操作,这里应该可以照做。一般来讲,帧同步能做到的状态同步都可以。反过来不行。
帧同步需要得到每个玩家的操作来计算,状态同步可以用一些算法来压缩同步的内容。比方说,随着玩家数量的增加,帧同步每个人需要接受的指令都在增加,而服务器需要发送的玩家和命令都在增加,对玩家的压力是线性增长,对服务器是多项式增长。而状态同步可以只同步必要的对局状态量以及各玩家理论视野内的其他对象状态给他,压力是线性增长。也就是说对于大型游戏只能用状态同步。