从游戏服务端角度分析移动同步(状态同步)

参考文章:

https://www.lfzxb.top/ow-gdc-gameplay-architecture-and-netcode/

https://zhuanlan.zhihu.com/p/544473862

  对于游戏服务端来说,针对状态同步主要需要考虑的是三大模块,即校验、模拟、计算。客户端输入的任何信息都需要进行校验,避免多人游戏作弊情况的发生。客户端在进行游戏的同时,服务端也同样进行游戏模拟,只不过对于服务端来说只有数据,且数据是离散的,而客户端不仅有数据,同时还有渲染表现。计算即对模拟的过程进行计算,比如已知速度时间求速度等。

TIPS:下述示例网络层协议基于TCP,正常情况下应当使用UDP亦或KCP。下述移动同步思想主要来源于《守望先锋》网络同步方案以及Source Engine(起源引擎)网络同步方案。仅供参考。

对于以下设计主要目的是为了克服网络延迟、以及玩家作弊的问题。

针对这些问题,服务端和客户端分别会有不同的策略来处理,服务端会采用数据压缩、延迟补偿等技术,而这些技术对于客户端是不可见的。而客户端一般会采用执行预测值和平滑插值来提升游戏体验。

技术术语

  • RTT,网络通讯在客户端和服务端之间传递需要花费一定的时间。一个数据包从客户端发送到服务端再返回客户端的时间为一个RTT。(这也就是说客户端的时间总是比服务端稍晚一些。此外,客户端的输入信息包在传输时也会发成延迟,所以服务端一直都在处理延时过的用户指令。还有,每一个客户端都有不同情况的网络延迟,这取决于客户端帧率、服务端帧率、以及相应的其它后台事务逻辑,这些都不是恒定的)
  • Tick,对于服务端来说,只有数据,即从一个点到下一个点是瞬时的,即表现为数据离散。一个点到下一个点所经历的时间为一个Tick。如果默认情况下一个Tick为15ms,那么每秒就会发生66.666…次Tick。(实际上就是帧率,如果我们服务端的帧率为66.666…,那么意味着一秒执行66.666…次,也就是每次执行15ms,即一次Update为一个Tick。在每一个Tick中,服务器都要处理用户传递来的命令、做一步物理模拟、检测游戏规则、更新所有对象的状态。

客户端策略

  由于服务端和客户端的时间差异,将会引起逻辑上的问题,并且随着网络延迟的增高问题变得更加严重。如果所有的操作客户端都是等待服务端响应之后在处理,那么在快节奏的动作游戏中,甚至几毫秒的延迟,玩家都会有延迟感,并且对于命中判断这种问题,会造成难以击中其他玩家、难以和移动物体互动的情况。下面客户端通过两个方法来解决这个问题。一是客户端输入预测,一是平滑差值处理。

客户端输入预测

  客户端在UI交互之后立即发送操作给服务端,此时,客户端不应该等待服务端的反馈,而应该立即移动,这个过程我们叫做客户端输入预测,那么客户端本地具体如果预测(我们约定本地玩家为p1)的目标点呢?我们假定客户端的输出流是稳定的(即客户端进行逻辑帧控制,按照一定的频率进行输出),那么客户端的始终总是会超前于服务器的,从客户端到服务端的时间,我们预计它大概超前半个RTT加上一个缓存帧的时长(缓存帧即多久进行一次输出处理)。也就是说,服务端收到客户端的状态改变移动同步请求时,客户端已经移动至如下位置(假定为二维平面,客户端当玩家操作UI时就立即进行响应移动

predictionPosX += (rotationX * speed * (halfRTT + intervalTime));
predictionPosY += (rotationY * speed * (halfRTT + intervalTime));

  而服务端也会根据半个RTT加上从缓冲区取出玩家状态的时间来在当前Tick模拟角色状态。

actualPosX += (rotationX * speed * (halfRTT + bufReadTime));
actualPosY += (rotationY * speed * (halfRTT + bufReadTime));

这也就是为何客户端永远领先于服务端。正因为客户端是一股脑的尽快接受玩家输入并渲染响应,尽可能地贴近现在时刻提高玩家体验。而如果还需要等待服务器回包才能响应的话,那看起来就太慢了,会让游戏变得卡顿。服务端模拟完角色状态之后,响应对该角色感兴趣的角色(包括它状态改变的角色本身)正确的位置信息。那么也就意味着,客户端根据玩家输入的预测(历史轨迹)需要使用一个队列进行存储,最终服务端的回包不是和当前角色所在状态比较,而是跟角色的历史状态比较。判断是否合法。如果与服务端模拟结果相同,那么客户端会开开心心地继续处理下一个输入。如果结果不一致,那么就是一个”预测错误“。这时简单的处理就是直接使用服务都安下发的结果直接覆盖当前客户端的结果,但是这个结果可能已经非常”旧“(相对于当前时刻的输入来讲)了,因为服务单的会包可能都是在几百毫秒之前的了。复杂的做法是使用例外一个队列记录玩家的历史输入(注意,这里是记录输入,而不是输入后的预测),当预测失败时,我们将从服务端没有进行校验的历史操作到当前操作的所有历史输入一次性打包发送给服务端(即从最后一次被服务器确认的运动状态到现在的全部输入都发送给服务端),服务端一次性模拟完所有的操作(相当于重播一遍直至追上当前时刻,也被称为缓存重放机制),返回一个最新状态给客户端,也就意味着服务端直接追上客户端,与客户端状态保持一致。这时服务端再次响应所有对该角色感兴趣的角色(包括当前状态角色)正确的状态信息,客户端为了玩家体验,会进行平滑插值处理。

平滑插值

  这里不做过多简述,可查阅网上资料。

服务端策略

数据压缩

  这里主要是对数据进行优化压缩,比如服务端AOI算法,具体可参考链接:https://blog.csdn.net/qq135595696/article/details/128377140

服务端滞后补偿

  让我们来假设玩家在客户端时间10.5s时对某一个目标发出射击。开火的消息被打包成用户指令,并且发送给服务器。当这个数据包在网络传输,服务器还在持续模拟游戏世界的运行,相关目标可能会移动到一个完全不懂的位置上。 当10.6s时,玩家指令包到达服务器,但是此时服务器已经检测不到这个命中,尽管玩家确实瞄中了目标。这种错误,需要使用服务器端的滞后补偿来修正。

  滞后补偿系统记录前1s内所有玩家的位置。如果一个玩家指令被执行,服务器将会用下面的公式来估算指令的生成时间:

指令执行时刻(客户端生成指令的时刻) = 当前服务器时刻 - 数据包传输延迟 - 客户端画面插值延时

  然后,服务器将所有其他玩家(只有玩家)移回到指令执行时刻的位置。这样玩家的指令在执行的时候就可以正确瞄准了。在用户指令被处理完成后,玩家恢复到当前时刻的位置。

TIPS:由于实例插值被包含在计算公式中,如果没有开启实例插值,那么将引起意料之外的结果。

  上图是监听服务器的屏幕截图,有200ms的网络延迟。红色的有效射击区表示的是目标在客户端上100ms + 平滑插值延 前的位置。从有效射击区显示的时间点开始,用户指令向服务器传送,目标也持续向左边移动。用户指令到达服务器,服务器根据估算出的指令生成时间重置目标的位置(蓝色有效射击区)。服务器运算出设计的弹道轨迹,并且检测出命中。

  【额外说明】关于上图显示框体到底显示的是哪个时刻的简单计算:

  服务器和客户端的有效射击区并不是完全匹配的,这是因为时间精度上差异造成。对于高速移动的物体,就算是几毫秒的差异,也会造成数英寸的错误。多人游戏中,命中检测并不是完美的像素检测,他受到Tick频率精度和运动速度的影响。

  网络中延迟和滞后补偿将会带来一个矛盾,这两个看似会使得游戏世界的运行与真实情况的偏离。举例来说,你可能在进入掩体之后,仍旧被一个已经看不到人击中。这个是因为,服务器已经把你的游戏角色的有效射击区及时移动到掩体后,但是在攻击者的客户端上,你的角色仍旧是暴露在掩体外的。这个不一致的问题,在缓慢的数据包传播速度之下并不能被解决。但是事实是,你并不能意识到这个问题,因为光速(数据包的传输速度)太快了,所以所有人都可以见到一个相同的、正确的世界。

从游戏服务端角度分析移动同步(状态同步)相关推荐

  1. Python 主流棋牌游戏 服务端 框架分析 原创笔记

    经测试此产品运营稳定 包含数十款房卡子游戏.俱乐部(五级权限).比赛场 客户端采用Lua脚本开发 .后端Python 看过一些棋牌产品 很多产品基于此套棋牌框架开发而来 算市面上一个主流框架 但却没有 ...

  2. 百万在线:大型游戏服务端开发

    进入手游时代,服务端技术也在向前演进.现代游戏服务端既要承载数以万计的在线玩家,又要适应快速变化的市场需求,因此,如何设计合适的架构就成了重中之重.服务端技术并不简单,作为服务端新人,全面掌握服务端技 ...

  3. 基于skynet设计游戏服务端框架

    skynet并不是一个开箱即用的服务端框架,游戏后端在开展业务时,需要根据自身业务特点,合理设计相应的服务端框架.在这里我根据自身的设计目标,写下各方面的选择与取舍.对于小型企业来说,一些商业化的软件 ...

  4. java游戏服务端实现

     java游戏服务端实现 一个多人在线的棋牌类网络游戏的项目临近尾声,我参与了该项目的整个设计流程,并且完成了90%的核心代码.关于这个项目,有很多地方值得聊一聊.本系列不打算把这个项目将得多么详 ...

  5. 【服务端】多线程游戏服务端

    多线程游戏服务端 一.系统介绍 二.系统架构 2.1 Sunnet进程的运行 2.1.1 SocketThread线程的运行 2.1.2 WorkerThreads线程的运行 2.1.3 TimerT ...

  6. HTML+JS+websocket 实现联机“游戏王”对战(十)- 搭建游戏服务端

    目录: 游戏王联机卡牌对战 1 - 前言 游戏王联机卡牌对战 2 - 联机模式 游戏王联机卡牌对战 3 - 界面布局 游戏王联机卡牌对战 4 - 卡组系统 游戏王联机卡牌对战 5 - 卡片选中系统 游 ...

  7. Node 小游戏服务端2

    小游戏服务端开发之客户端传参 接上节,因为服务端语言用的是Node.js 以及基于NODE 的Koa框架,大的框架逻辑部分已编写完成.但在测试过程中有跨域以及参数接收问题: 知识点:Node koa ...

  8. 新一代游戏服务端框架,该是什么样的?

    说起游戏服务端引擎,大家会想起Skynet.KbEngine.Photon.Pomelo等等.在探索服务端技术时候,我们不仅仅要了解当代服务端引擎,更要有些前沿眼光,去预测未来的游戏服务端是什么样的. ...

  9. 如何快速开发游戏服务端框架?

    快速开发游戏服务端框架的方法如下: 分析游戏需求:首先要明确游戏的功能和玩法,并确定服务端的职责. 选择适当的开发工具:可以选择一些专门用于游戏服务端开发的工具,比如 Unity.Unreal Eng ...

最新文章

  1. Android Studio 新建drawable-hdpi、drawable-mdpi等
  2. RSA选用小公钥指数(e=3)真的不安全吗?
  3. 专访 | 神策数据CEO桑文锋:谁说大数据不需要「小而美」
  4. mac你没有权限打开应用程序_如何管理Mac的隐私权限控制
  5. LoadRunner11支持的浏览器小结-Loadrunner11打不开IE浏览器的问题
  6. vue-cli搭建和“Cannot find module npm-cli.js” 、“operation not permitted” 、 deprecated coffee-script等错误
  7. R40gpio输出无高低电平变化【原创】
  8. Ubuntu20.04搭建ftp服务(亲测通过)
  9. 隐藏画质代码_和平精英120帧率代码是什么?隐藏的120帧率代码更改方法技巧
  10. Linux下安装并启动MongoDB
  11. VMware 设置共享文件夹
  12. Exchange反垃圾防病毒网关——SecurityGateway基本部署
  13. DSTE经营分析会(战略落地的核心抓手)
  14. Spring Boot - Mybatis 缓存
  15. 调整report_timing输出格式
  16. Unity UGUI 检测按钮的按下与抬起
  17. 中国00后互联网学习行为报告.pdf
  18. excel打印预览在哪里_易打标条码标签设计打印软件下载_易打标条码标签设计打印软件绿色版下载...
  19. html怎么设置一个表格的宽度一样吗,html表格单元格大小 怎样在html中设置所有表格大小一样...
  20. 《云计算技术与应用》最新章节测试答案

热门文章

  1. 8. 面向对象 -- 继承
  2. 数字去重(5种方法)
  3. 科学道德与学术诚信 计算机,关于开展2020级研究生科学道德和学术诚信教育工作的通知...
  4. 前端优化-改善滑动流畅度的几类方法
  5. 【HTML】HTML网页设计-----可爱多肉网页设计
  6. java runnable main_【BUG】”main” prio=5 tid=1 RUNNABLE
  7. Pro10丨枢轴点反转策略
  8. 十大监控工具,值得一试
  9. 数据结构:递归(迷宫回溯、八皇后)
  10. 运行报Invalid property 'specParamList[0][specName]' of bean class [com.model.Produ... 报错的解决办法