帧同步

  1. 帧同步
    1. 帧锁定同步
    2. 乐观帧锁定
      1. 回放-采用操作2
      2. 逻辑帧同步
  2. 可靠UDP
    1. 对抗丢包
  3. 小断线重连
  4. 大断线重连
  5. New

参考内容 帧锁定同步算法

帧同步

向服务器发送操作时可以选择使用位图的方式发送。如使用int32_t类型 来表示最多32个按键的状态。

帧锁定同步

帧锁定同步会使用逻辑帧的概念来收集玩家操作,然后向服务发送。等待所有玩家的帧到达后, 才进行同步, 所以称为Lock.

乐观帧锁定

乐观帧锁定在玩家按下操作键后就会立即向服务器发送本次操作。

服务器本身含有游戏循环,每个逻辑帧会将本逻辑帧内收集到的操作发送给客户端。发送的时候会带上逻辑帧的标号。

客户端收到服务器发送的操作后,目前看到了两种执行方式。

  1. 使用回调等方式,直接将数据包中的操作作用到玩家上。此时不能追帧?, 而且回放也做不了
  2. 将所有操作收集起来,根据逻辑帧信息进行作用。此时如果逻辑帧落后则进行追帧操作。

回放-采用操作2

服务器每次下发时是以逻辑帧为单位,客户端取数据包时同样以逻辑帧为单位。

回放时,服务器一次性下发所有保存的 带服务器逻辑帧编号 的数据包。
客户端取数据包执行时,只会取服务器逻辑帧编号小于等于当前本地逻辑帧编号的数据包。

逻辑帧同步

所有客户端和服务器同步逻辑帧的编号,使用PING包计算本地和服务器之间的延迟T。

当服务器下发逻辑帧开始命令后,使用本地的时间减去 0.5T 即为真正的开始时间。

可靠UDP

对抗丢包

冗余N帧

小断线重连

只有当收到下一帧的数据包时才消耗本帧的数据包

如果直接消耗本帧的数据包,发生断网时如果本帧含有多个数据包。恢复时还需要额外的带上其他标记,不利于请求以后的数据包。如果收到下一帧时才消耗,恢复时只需要请求接下来的数据包即可。

大断线重连

New

0延时和瞬间处理的情况下, 服务器每秒30轮循环(30帧). 客户端产生输入后立刻(帧结束?)发送同步包, 服务器每次收到后将包放入队列, 服务器每轮循环开始时从队列中取出上一帧的所有输入, (进行计算, 服务器保存一份本帧结束时的状态), 将上一帧的输入发送到客户端(同一帧内的输入是否要严格区分相差多少ms?). 客户端收到输入后立刻(帧结束?)应用数据包.

断线重连, 请求增量输入还是服务器当前状态? 请求增量输入需要知晓从哪一帧开始断线, 请求丢失部分. 请求服务器缓存的一份状态则不需要, 直接进行全量替换.

客户端是否需要帧循环? 需要的话是否需要帧编号和服务器进行同步? 服务器肯定是有帧循环和帧编号.

存在延时: 客户端的输入不能立刻到达服务器, 服务器的输出不能立刻到达客户端. 服务器是否需要等待客户端一帧的输入?
需要就会导致本帧被卡主, 高延迟玩家的体验要好一点, 客户端的输入是否需要等到上一帧结果出现后再发送? 需要的话同步性会加强, 不需要时低延迟的会抢跑一些输入.
不需要时, 各跑各的岂不是很方便? 客户端的输入可以随时到来, 来了之后放入下一帧队列即可. 不过这样会导致高延迟的体验较差, 因为低延迟的会更先看到画面, 更早的做出操作.

服务器当前状态: 状态同步的缺点就是由于状态计算导致延时变高一点, 这里状态计算肯定是异步的, 不会和服务器帧循环绑定, 这样会导致帧同步变成状态同步.

更换UDP还需要考虑可靠性的问题, 使用KCP? 还是定制下通过冗余帧之类的减少同步?

一文深入浅出网络游戏的状态同步,一文深入浅出网络游戏的帧同步.