帧同步方案介绍
在联网的客户端(可能有主机)之间的一种步进和同步机制,目的是为了让所有客户端只需同步操作,就能运行出同样的结果。
网络层
- P2P帧同步模式
客户端之间建立直接的UDP连接,每个客户端收到所有其它客户端的第N帧输入数据时,才执行第N帧。当长时间未收到某个客户端的输入时会等待同步,未果该客户端会掉线。
- Host-Peer帧同步模式1
Host一定要等到所有客户端第N帧消息到达,才会向所有Peer同步第N帧。当长时间未收到某个客户端的输入时会等待同步,未果该客户端会掉线。
- Host-Peer帧同步模式2(乐观帧同步)
所有客户端直接向Host发玩家的当前输入数据,Host按固定的时间间隔发每一帧的所有玩家的输入数据给所有客户端,客户端收到时再执行这一帧。
逻辑架构层
按一定的帧率执行,并保证在每一帧相同的输入下产生相同的输出,以确保同步性和确定性
相关重难点方案介绍
不同步问题
- 自动化测试
通过自动化测试,来查可能的同步问题,每夜测试会通过长时间、多案例覆盖,并利用多机环境进行测试
- 同步日志
核心层执行过程可以打印非常详细的日志到内存里,如果是完全同步的两个客户端,日志应该是完全一样的,如果有不同步问题可通过此日志的差异进行定位
- 录像
可以在自动化测试时同时保存录像,如果测试失败可以通过回放来定位问题
反外挂
- 客户端自验证
各客户端在每一逻辑帧计算关键数据的校验和(如单位血量、法力值、位置等),通过比较各个客户端在某一帧的校验和是否一致,来判断是否有客户端使用外挂,这种方法不能检查单局少于3个人的情况
- 服务器验证
核心层放到服务器做验证,在线抽查或离线检查,通过实时或通过播放单局录像,计算和判断每帧的校验和是否和各客户端一致
- 客户端分布式验证
可以利用空闲的客户端离线验证历史游戏是否有人作弊,可以根据CPU负载仅核心层高倍数或低倍速回放进行验证
- 修改挂
前面提到三种验证方式可以有效的检测修改挂,只要动到关键数据,帧校验和肯定会不一样,除非只是在在地修改,这样结果没有任何意义
- 感知挂
帧同步客户端在线都有所有数据,这一块是传统帧同步方案较难处理的问题,如果游戏对感知挂特别敏感,需要权衡利弊,考虑好对这个方案和传统C/S方案之间的选择,或在这个方案之上的针对特定游戏的改进方案
- 操作挂
模拟玩家操作,这个在帧同步下和MMORPG一样,只能通过行为特征去防,而一般模拟操作用来刷PVE环境会更容易
- 私服/免服
如果官方平台社区运营的好,平台乐趣是单机无法复制的,所以从这个意义上来讲,免服本地玩意义不大,而私服可能要通过法律途径打击
录像
要保证录像回放和录制时一致性,需要回放时的EXE、DLL、脚本、数据等核心层用到的文件的版本和录像时是一致的,所以录像要按版本保存,并同时保存相关文件版本
录像回放时,可以选择回放倍速,倍速在核心层就是在每秒钟执行更多的逻辑帧,如一倍每秒16帧,两倍速就是32帧,表现层要加快动画的播放速度,按回放倍率高速动画的播放速度,按实现能达到的帧率正常执行即可,和核心层帧率无关
录像系统除了给玩家之间分享游戏过程外,还可以用于报错系统,对于外网一些难重现问题可以有录像辅助回放
因为录像保存了相应版本的可执行文件,要考虑可执行文件对资源的兼容问题,这样回放时,不会因为有新版本的资源无法解读而出现播放错误,有两个方法解决:
1、可执行文件对末来版本资源的向后兼容
2、资源的加载可经过虚拟文件系统重定向,播放录像时只加载相应版本的资源
断线重连
帧同步架构的断线重连需要客户端从第一帧开始运行到当前帧,需要一定的处理时间,有这样一些方法加快速度:
-
用高速快播的方式,让核心层快速快进到当前帧,因为核心层平时就跑到16帧每秒,还不是全速,假如能跑到16倍速,加载时间就是游戏当前时间的1/16,比如进行了16分钟就是1分钟
-
为加快核心层快进速度,可以将密集计算的函数记录执行信息放到本地文件缓存,比如寻路,在重连快播的时候直接从记录中取函数结果,不需要执行这些耗时函数
-
表现层在核心层快播的时候,可以将自己要处理的表现命令进行缓存并整理,在最后核心层快播结束时,再处理整理后的表现命令,减少表现层占用的CPU,使核心层能以更快的速度运行,对诸如创建A、销毁A,可以进行裁剪,减少执行负载
和传统C/S方案的对比
传统C/S模式
以服务器的状态为准,客户端对某些需要即时表现的内容预先处理,同时发给服务器,如果服务器验证有较大偏差再纠正客户端。客户端和服务器之间传递的多是状态数据,客户端之间无法保证在某一时刻或某一帧是一致的,因为每个客户端都可能随时发起本地的预处理。
帧同步模式
每个客户端按照严格的帧的概念来同步执行,客户端之间只需要同步操作,单局游戏的各个客户端在每个逻辑帧运算结束时,各个客户端能达到一致的运算结果。