基于帧同步的游戏框架说明

基于帧同步的游戏框架说明

一,关于帧同步和状态同步的比较

 

帧同步

状态同步

安全性

比较差,计算都在客户端,服务器只做转发;有服务器校验的方案,比较繁琐

计算都在服务器 可以将重要的判定都由服务器决定

网络流量

比较小,每一帧只同步玩家的操作指令

如果单位数量多,需要同步的数据量会比较大

技能实现

比较容易,只用客户端实现即可,开发周期短

需要服务器和客户端实现相同的运算逻辑,如果是不同的语言相当于要开发两次;另外前后端机制的配合也比较复杂

录像回放

记录每一帧的指令即可,数据量小

不太容易做录像

一些限制

1,随机种子要一致,不能使用浮点数,导致在游戏逻辑层使用外部库要注意,包括物理引擎之类的都禁止使用;

2,代码要求比较高,如果出现异常就会出现玩家之间数据不一致,导致战斗结果无效。

3,断线重连比较复杂,通常需要客户端重头跑帧指令。

没有要求

二,实际项目《战争怒吼》帧同步方案分析

 

1,整体架构:

 

基于帧同步的游戏框架说明_第1张图片

 

2,游戏类型是一款在moba游戏上加入rts元素的实时对战游戏,支持1v1,2v2的模式。

 

3,关于lockstep

 

简单的说就是游戏时间划分成一个一个的turn,每个trun玩家发送指令给服务器,服务器收集每个玩家的指令,在这一帧末尾广播给所有玩家;客户端收到指令后,执行相应的指令;

因为么个客户端的开始状态一致,那么经过相同的指令计算后,状态也应该是一致的;这就是帧同步的核心原理。

原始的lockstep要求每一个turn会等待所有玩家的指令,如果有一个玩家卡顿了,其他玩家也会受到影响;我们针对这种情况作了改进,如果超过一定时间就认为这个客户端这一帧没有做操作,

从而不会影响其他玩家。

 

4,模块说明

loginserver:  登录服务器,负责接入第三方账户系统登录

logicserver:大厅服务器,负责养成逻辑,可以横向扩展多个;基于skynet

gamecenter: 中心服务器,负责全局性的功能,如玩家状态管理,帮会,匹配等;基于skynet,可以按功能扩展

battleserver:战斗服务器,负责战斗过程,基于c++;核心逻辑是基于房间的概念,每场战斗就是一个房间,房间内的玩家进行帧同步处理

checkserver:验证服务器,负责验算战斗过程,用于当客户端战斗结果不一致的时候,服务器校验

replaycenter:验证中心服务器,负责管理验证服务器,负载均衡

 

5,一场战斗的生命周期

gamecenter匹配好一场战斗之后,根据负载均衡选择一个battleserver,将玩家信息发送给battleserver;

battleserver根据玩家信息创建一个房间room和玩家对象,返回给gamecenter战斗服地址;

gamecenter通过logicserver返回地址给客户端;

客户端连接战斗服,并且加载对应的战斗地图,加载过程会广播给其他玩家;

当一个房间中所有玩家都加载完成,战斗服务器广播战斗开始;

战斗中每秒15帧,每一帧会收集所有玩家的操作指令,在帧末尾广播出去;

帧指令需要缓存,因为需要做断线重连;

为了高效的管理这个缓存,这里设计了一个专门为此服务的内存池,每次分配一个固定块的内存,用链表记录起来;每次分配就从块内存中分配,不够再向系统申请;

当战斗结束的时候,直接将链表中所有的块内存全部释放。

当客户端判断战斗结束,会给服务器发送战斗结束协议;战斗服务器将战斗结果发送给gamecenter,即可结束这一场战斗。

 

6,关于作弊检查

客户端每一帧会将关键状态序列化计算md5发送给战斗服务器,战斗服务器每一帧会收集到每个客户端的md5;如果md5不一致即可知道有客户端状态不一致;

如果是2v2,我们可以用其中三个md5的一致来判断一个不一致的人客户端出问题了,这种情况会丢弃有问题的客户端的战斗结果。

如果是1v1,我们不能通过md5的方式知道正确的客户端。此时会用到checkserver,这个服务器上跑了客户端的战斗逻辑,得益于将战斗逻辑独立成一个lib,

我们在ubuntu系统上安装mono运行环境可以在服务器上跑战斗过程,就是将帧指令发送给checkserver验算战斗结果。缺点就是内存占用比较大,一场战斗内存在15M左右;

因此我们先通过第一种方式来检查,实在不行才启用第二种方式。

 

7,关于客户端

客户端需要将逻辑和表现分开,逻辑层每一帧会根据收到的服务器指令来更新逻辑状态;由服务器帧来驱动逻辑运算,要考虑由于网络波动造成的帧信号时快时慢,

逻辑循环要针对这种情况做快进或者等待;表现层考虑手感优先需要对玩家操作的单位快速做出响应,表现都是不用等待服务器状态的。比如移动,

客户端本地是可以自由操作自己控制的单位。表现层需要对玩家移动过程进行差值计算等,因为逻辑帧通常低于表现帧。另外表现层玩家坐标要考虑跟逻辑层的差异,

允许一定的误差,误差过大要考虑如果缩小;目前的处理就是当玩家停止移动的时候,跟服务器这一帧的状态同步一次,差异比较小的时候,玩家不会有明显的感觉。

 

参考资料:

https://gameinstitute.qq.com/course/detail/10036

http://bindog.github.io/blog/2015/03/10/synchronization-in-multiplayer-networked-game-lockstep/

 

 

 

 

你可能感兴趣的:(技术)