参考资料:
https://gafferongames.com/ Gaffer on games
https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking 起源引擎网络同步资料
http://fabiensanglard.net/quake3/network.php quake3网络部分代码分析
最近在尝试在Unet的Reliable UDP的基础上,配合Entitas做一个快节奏多人联机游戏,熟悉一下相关的技术。
现在国内的资料指出,网络同步可以分为两大类,分别是帧同步和CS架构的各种同步
帧同步
帧同步大部分情况下应用于RTS游戏,各个客户端基于p2p连接,没有服务器。
帧同步中,客户端与客户端之间互相发送一帧中的“用户输入”。当一个客户端收到其余客户端的所有输入之后,就会根据这些输入进行这一帧的模拟。因此游戏中的延迟跟网络状况最差的那个玩家有关。
这样一来,为了保证每个客户端的游戏进程完全相同,每个客户端中都要保存完整的游戏状态。这也是为什么魔兽3、星际2、风暴英雄等一众帧同步游戏的全图挂无法从根本上禁止的原因。(Dota2是基于状态同步的,所以干掉全图挂是完全没问题的)同时要保证不同的电脑上,同样的输入产生完全同样的输出。
在流量方面,帧同步需要每个客户端之间两两发送指令,因此网络流量随着玩家人数提升增长的非常快。这也是为什么rts游戏中的玩家人数上限较低。
CS架构同步
CS架构引入了一个权威服务器作为各个客户端连接的中心。服务器运行着最核心的逻辑,接收客户端的命令,同步各个客户端的表现。
Gaffer on games中讲了两种同步,分别是快照同步和状态同步。在国内的资料中,一般都统一认为是状态同步(只是同步的内容不同而已)。
快照(Snapshot)同步
快照同步是quake3和起源引擎采用的架构。特点是服务器进行游戏逻辑的模拟,客户端只负责呈现画面。(当引入客户端预测后,就是另一回事了)
快照同步中,有一个用于模拟游戏的服务器和若干客户端。
在客户端上,客户端每帧向服务器发送指令信息,如移动、开火等。服务器发回的则是当前游戏世界的所有实体的“快照”,即当前这一刻的状态。
这样的架构好处在于,每个客户端的延迟情况只和自己的网络情况有关,同时随着玩家人数上升,网络负载提升的只有服务器而已(以及多出来的那个玩家的实体)。
同时服务器也可以有选择的发送快照的内容,比如不发送战争迷雾中的单位的信息,可以很大程度上避免玩家的作弊。
另外因为客户端收到的是快照,如果直接根据快照去更新游戏的话,游戏会变得一卡一卡,除非快照的频率非常高。
为了解决这个问题,可以引入客户端的快照缓存。客户端收到快照后并不立即渲染,而是将其放入一个缓存。通过设定一个延时值,比如0.1秒,客户端的渲染会渲染当前客户端时间减去0.1秒,获取这个时间两侧的快照(一个快照早于这个时间,另一个晚于这个时间),去做内插值。(当因为丢包之类的原因找不到快照用于插值时会做外插值)。
快照同步有许多优化的点,比如状态压缩等,具体就不细讲了。
状态同步
状态同步类似于快照同步,但是客户端不再只负责画面呈现,而是也会进行游戏逻辑的模拟。只在收到服务器发来的游戏状态时对游戏进行纠正。
此时,因为客户端本地也有一定的模拟逻辑,服务器可以只发送一些重要物体的快照,而将不重要的物体的信息交给客户端自行去计算。