本概述都是基于自己经历的项目见解,不一定是正确的。这是一个系列总结,以后会补充更多
帧同步的概述
-
帧同步,其实是基本帧更新的同步方式,但并不是要求每一帧都同步数据,而要求多端,他们执行在指定的帧号上,而且每一帧,多端运行结果都是一致的
-
一般而言,所谓的“帧”不是真实时间的帧(虽然也会受真实时间影响),而叫做作“网络帧”,由“服务器”决定能不能执行下一帧,并广播到多端上驱动更新“帧”。
这个是最简单的方式,实质上项目为了效果好,不会这么老实等待驱动事件
-
“网络帧”更新一般很慢,主要执行“逻辑”相关业务,与之相对有“表现”层,他的更新是独立的,可以有更高的帧数,以给用户更好的体现
大概流程如下流程图
为什么使用帧同步
- 对于细微表现有高要求的用户体验下,帧同步更新间隔更新短,且严格要求每一帧结果一致
- 帧同步实现的方式更简单,一般逻辑写完,就是能做完同步功能
帧恢复处理
- 为什么需要恢复: 网络的不稳定,或程序的不稳定都会引发程序的退出或卡住,为能继续这一局游戏,就需要帧恢复到当前运行的那一帧
- 一般帧恢复的做法,是从第指定帧重新运行到目标的帧上,这样可以保证目标帧的运行结果是一致。
- 帧执行时,会有一些外来的输入或随机数值的产生,为了恢复顺利,需要在这一帧里把这些数据收集起来
- 如果能把一帧的结果全部收集起来,再执行下一帧,那样我们能做到更快的帧恢复。
- 数据收集,一般我们可以考虑以下几点:
- 用户输入
- 随机数值
- 影响下一帧运行结果的数值
- 利用帧恢复的机制,实质可以很方便实现录像功能,及测试功能。
帧预测与回滚
- 为什么需要预测:受网络环境及其他客户端的运力影响,很难做准确的时间更新,同时为了用户的体验良好,允许在没有接受驱动更新时,可以多执行几帧。
- 预测分为:本地预测,服务端预测,及其他客户端预测
- 本地预测:用户操作,会致使本地AI变化,一般需要记录所有操作数据,并实时响应
- 服务端预测:一般是收到多帧用户操作后,判断帧的有效性,并广播给客户端恢复到有效帧上
- 其他客户端预测:在没有收到其他客户操作前,根据当帖操作预测对手的未来操作
- 预测都有关键行为帧,诸如角色受击,用户操作停止点,这些都是数据会有一些帧的关键结果,在有关键数据后,因为帧预测的导致的数据偏差都尝试恢复到该帧上。
以下举例预测情况
各端 | 帧1 | 帧2 | 帧3 | 帧4 |
---|---|---|---|---|
服务端 | 收到AB | 预测AB位移,只收到B | 预测AB位移, 只收到B, 攻击成功 | 收到AB,A为多帧数据,判断A 3帧后数据无效,回滚操作,相关帧替换为受击 |
客户端A | B摇杆位移 | 预测B位移,A摇杆位移 | 预测B位移,并攻击 | 摇杆,但滑回帧2位置表现受击 |
客户端B | B摇杆位移 | 预测A位移,B攻击 | A表现受击,B摇杆位移 | B摇杆位移 |
帧同步系统的构成
- 数据收集系统: 一般通过数据反射,收集关键数据,并通过protobuf, msgpack, json等封装数据
- 稳定的更新系统:诸如通过KCP协议驱动“网络帧”更新
帧同步的一致性
- 帧同步的一致性,一般是指对相同录像的帧结果是否一致,而所谓的结果一般是指收集的数据。
- 受平台及编程语言的问题,一致性在多端下有以下情况:
- 同一录像在同一端下多次运行结果一致性
- 同一录像在服务端与客户端的帧结果一致性
- 同一录像在不同客户端的帧结果一致性
- 发现不一致性后:
- 通过不一致的数据内容,反向追查大体有问题的过程
- 修改问题过程时,可能通过指定帧分流修改前后状态,跑同一录像验证
例如:
if( frame_id == 3001){
// 修改前代码
}else{
// 修改后代码
}
- 发现不同过程,也可以通过工具打印该帧的所有调用栈及相关过程变量
如果是脚本,可以利用脚本的反射机制实现