文章

【Unity/Lock Step】帧同步理论:Part 1开篇Opening

【Unity/Lock Step】帧同步理论:Part 1开篇Opening

概述

  • 帧同步理论系列文章目标为——介绍如何实现一个普适帧同步框架,能够用于任何适合帧同步(特指确定性Lock Step网络同步模型,具体参照引用的《网络游戏同步技术概述》一文)的游戏类型。
    • 所谓普适,即能够完整实现基本的游戏同步,预测回滚。并对帧同步的缺点编写解决方案,特别是射击游戏领域的特有优化(例如偷窥者优势)
  • 本文目标为帧同步实战的开篇,重点在于介绍帧同步同步模型实现的必要技术点/重点概念以及前人经验/技术选型


哪些游戏适合帧同步方案

  • 人数相对较少的网络游戏
  • 游戏中需要战斗回放功能
  • 游戏中需要加速功能
  • 需要服务器同步逻辑校验防止作弊


网络传输协议选型

现代游戏通常只使用UDP,RUDP,KCP,不使用TCP

  • 冗余UDP和RUDP的选择,通常选择冗余UDP

知乎某答主:这两种方式,区别是巨大的。可靠传输的UDP,在帧同步中,个人认为是不合适的,因为他为了保证包的顺序和处理丢包重传等,在网络不佳的情况下,delay很大,将导致收发包处理都会变成类似tcp的效果,只是比TCP会好一些。必须要用冗余信息的UDP的方式,才能获得好的效果。并且实现并不复杂,只要和服务器商议好确认帧和如何重传即可,自己实现,有很大的优化空间。


帧同步网络模型重点概念

与状态同步区别

  • 其他同步方案快照同步(Snapshot Synchronization、Snapshot Interpolation),认为其等同于状态同步(State Synchronization)
  • 状态同步的C端下行接受S端的所有状态的子集的同步(这可以限制C端所能收到的对象信息的量),C端上行包括输入以及可能的状态集,C端有权限能够创建和同步仅在本地的状态。而帧同步上下行均只有输入。

运行结果一致性原则

  • 此为帧同步的原则,在实现上,C端只同步输入到S端,S端同步输入到其余所有C端,运算都在C端进行。为了保证运算结果在各端,各逻辑帧完全一致,就需要以下几点
    • 浮点运算一致,由于各平台的浮点数标准可能不同,浮点数经过多次运算后会产生蝴蝶效应误差。解决方案有两点。#题外,Unity的JobSystem可能已经实现了各平台运算结果相同,如果是,JobSystem便可以使用
      1. 定点数,使用现成定点数库。定点数确定小数点的位置,将整数以及小数分别用二进制存储。
      2. 整数替代浮点数,将十进制浮点数左移为整数。此方法需要注意整数溢出问题。
    • 保证执行顺序,C端在每个逻辑帧执行后,世界状态彼此必须完全相同,有以下逻辑执行限制
      1. 尽量不要在逻辑执行流程中使用多线程,因为很难与网络线程同步,且多线程调度也存在开销,需要花精力找到平衡点。
      2. 确定性的执行顺序限制,字典,Unity协程均存在不确定性执行顺序
      3. 可能存在的导航,物理等更新顺序
    • 随机数在各端一致,需要使用确定性的随机数方案,在各端同步随机数种子

预测&回滚

帧同步网络模型对网络要求较高,因此搭配预测和回滚来达到流畅游戏。预测输入如果和S端同步输入不一致,将发生回滚。

  • 预测,简单预测通常为保持上一帧输入或者清空输入,复杂的先不谈
  • 回滚,需要保存状态的复制和还原,需要保存之前帧的输入。
    • 保存状态有以下四种实现方法
      1. 手动,项目前期方便
      2. 反射,有性能问题
      3. 代码生成,推荐
      4. memorycopy,只适用内存紧凑型游戏
    • 回滚恢复状态
      • memory写入,只适用于内存紧凑型游戏
      • 命令模式,适用于大部分游戏,因为游戏内存通常是复杂的
    • 回滚View层绑定,发生回滚时,生成的mesh,entity,特效等销毁等


日志Dump

  • 对于回滚后的日志混乱问题,可以分成多个日志并分别记录。正常日志记录直接将世界状态和输入,执行的行为dump到日志就行
  • 对于服务器多实例日志,可以加上实例id来区别


引用

#推荐


#一般

  • 帧同步联机战斗要点和思考https://zhuanlan.zhihu.com/p/38468615
    • 对帧同步的难点和重点进行了解释,并且包含了答主对于ACT游戏帧同步预测,回滚,如何流畅战斗,以及优化的思考。有一些实现的代码和思路

#题外

本文由作者按照 CC BY 4.0 进行授权

热门标签