前言
最近在做联网战斗同步这块的东西,读了不少文章、书籍,于是整理了一下。
之前也有在 团队内部技术分享 中分享过这块内容,但是有些东西受限于时间,只是大概的略过,重点放在了实现与遇到的难题解决上。
后来,在做优化调整的时候,又有不少新的收获,改进了之前的分享稿。
欢迎各位小伙伴来一起讨论,通过分享讨论来不断进步。
1. 简介
现状
网络游戏的同步方案,大概由以下三部分搭配组成
- 网络传输协议
- 网络同步模型
- 网络拓扑结构
网络传输协议(Network Transport Protocol)
-
分类
- UDP协议
- TCP协议
-
共同点
- 在 TCP/IP 协议族中[物理层,数据链路层,网络层,传输层,应用层],位于 传输层的协议,均依赖底层 网络层中的 IP协议。
-
区别
UDP TCP 传输可靠性 不可靠 可靠 传输速度 快 慢 带宽 包头小,省 包头大,费 连接速度 快 慢 - 此外,TCP还提供了 流量控制、拥塞控制等
-
其他
- 关于 KCP协议
- KCP协议是一个快速可靠协议,它以浪费10%-20%带宽的代价(相较于TCP协议),换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。纯算法实现,并不负责底层协议的收发。
- 更详细信息可跳转最下方 参考资料2
- 关于 KCP协议
网络同步模型(Network Model)
-
分类
- 状态同步(State Synchronization )
- 本质:上传包含 游戏外部变化原因集合(玩家操作等)及 中间状态的子集(客户端计算的部分);下发包含 游戏状态的集合。
- 帧同步(Lockstep)
- 本质:上传下发只包含游戏外部变化原因集合(玩家操作等)。
- 对于A客户端: [输入A] -> [过程A + 运算A] -> 输出A
- 对于B客户端: [输入B] -> [过程B + 运算B] -> 输出B
- 确保 [输入] 相同,再保证 [过程] 与 [运算] 一致,那么 [输出] 一定是一致的
- 逻辑帧,游戏在逻辑层面是离散的过程,即可认为是一个逻辑帧一个逻辑帧进行逻辑运算。
- 渲染帧,游戏在渲染层面是离散的过程,即可认为是一个渲染帧一个渲染帧进行画面呈现。
- 游戏逻辑帧 与 渲染帧 需要互相独立。
- 本质:上传下发只包含游戏外部变化原因集合(玩家操作等)。
- 状态同步(State Synchronization )
-
共同
- 两种同步方案都分为 上传 和 下发 过程。
- 上传 指客户端将信息传输给 服务器/客户端
- 下发 指客户端从 服务器/客户端 中获取信息
- 两种同步方案都分为 上传 和 下发 过程。
-
对比
帧同步 状态同步 流量 通常较低,取决于玩家数量 通常较高,取决于该客户端可观察到的网络实体数量 预表现 难,客户端本地计算,进行回滚等 较易,客户端进行预表现,服务器进行权威演算,客户端最终和服务器下发的状态进行调节或回滚 确定性 严格确定性 不严格确定性 弱网影响 大,较难做到预表现 小,较易做到预表现 断线重连 难,需要获取所有相关帧且快播追上进度 易,根据快照迅速恢复 实时回放 难,客户端需要消耗非常大性能去从头播放到对应序列,回放完后需要快播追赶 易,根据快照进行回放,回放完再根据快照恢复 逻辑性能优化 难,客户端需要运算所有逻辑,跟客户端性能强相关 易,大部分逻辑可在服务器进行,分担客户端运算压力 外挂影响 大,客户端拥有所有信息,透视类外挂影响严重 小,服务器可做视野剔除等处理 开发特征 平时开发高效,不需要前后端联调;但是开发时要保证各模块确定性,不同步BUG出现,难以排查 平时开发效率一般,需要前后端联调,无不同步BUG 第三方库影响 大,第三方库需要确保确定性 小,第三方库不需要确保确定