技术标签: 帧同步
谈到网络游戏,不可避免要谈到现有两种比较常见的网游同步技术:帧同步和状态同步
说到这两个名词,大家夸夸奇谈,都能讲上些许自己的见解,我反正啥也不懂
这篇文章就打算着重学习一下这两种技术的基础和原理
网络同步的目标就是时刻保证多台机器的游戏表现完全一致。
网络同步 = 实时的多端数据同步+实时的多端表现
同步战斗逻辑是包括技能逻辑、普攻、属性、伤害、移动、AI、检测、碰撞等等的一系列内容,这常常也被视为游戏开发过程中最难的部分。
网络同步按大类来分有两种做法:状态同步和帧同步。需要强调的是这两个概念并不是简单的对立概念,其中的差异包括:"数据格式与内容"、“逻辑的计算位置”和“是否有权威服务器”等。
LockStep的翻译是锁步同步,是齐步行军的意思
服务器对客户端指令进行收集和转发
针对传统严格帧锁定算法中网速慢会卡到网速快的问题,实践中线上动作游戏通常用“定时不等待”的乐观方式再每次Interval时钟发生时固定将操作广播给所有用户,不依赖具体每个玩家是否有操作更新:
状态同步顾名思义就是同步各个客户端的状态,保证每一次操作后的状态是一致的
通过开发服务端程序,把用户的操作作为输入实时上传到服务端,服务端通过计算返回结果给各个客户端,这样的过程就是状态同步。
虚幻引擎的网络同步模型
如今的状态同步:增量同步、RPC(远程过程调用)两种同步手段。
目前状态同步多用于CS架构,客户端通过RPC向服务器发送指令信息,服务器通过属性同步(增量状态同步)向客户端发送各个对象的状态信息。我们可以才有预测回滚、延迟补偿、插值等优化方式
区别表格
属性 | 帧同步(LockStep) | 状态同步 |
---|---|---|
确定性 | 严格确定 | 允许小误差,定时纠正误差数据 |
表现与响应速度 | 传统严格帧锁定要等其他客户端消息全部到达,响应比较慢;乐观帧锁定可以做到本地立刻响应,但是需要回滚的时候,体验就没那么好了 | 一般会做预测,可以做到立刻响应。不做预测的话,响应时间是一个往返时间(RTT) |
带宽与流量 | 带宽随人数增加而增加,不适合MMO | 需要发送各种状态数据,带宽占用比较高。可以通过压缩、裁剪、增量等方式优化。人数较少时候不如帧同步剩流量 |
网络延迟适应性 | 要求较低的延迟。如果延迟较高,所有玩家体验都不好。即使采用乐观帧锁定优化,高延迟下也容易产生卡顿 | 适应性较高,方便做各种插值优化。当然高延迟下,也容易产生位置突变 |
开发难度 | 初期开发减法,框架容易实现,但是后期解决bug和完善系统很困难。比如浮点数、随机数、执行顺序导致计算结果不一致,问题很难排查 | 框架比较复杂,客户端服务端一套代码,每个功能都需要客户端服务端联调。问题定位比较容易。也会出现时序问题 |
玩家数量 | 适合少量的玩家,比如ACT、MOBA | 可多可少 |
跨平台 | 不适合跨平台,会有浮点数问题,可以用定点数来将误差控制在一个可接受范围,同时可以定时纠正结果 | 适合。有权威服务器 |
反外挂 | P2P架构不适合反外挂,如果引入战斗服务器来校验各个客户端结果,可以解决常见外挂,但是透视和全图视野防不了 | 与服务器加入校验机制,可以起到比较好的反外挂效果。但是一样防不了透视外挂 |
中途加入和断线重连 | 比较复杂。可以在断线的时候,通过快捷播放服务器同步的帧数据来快速跟上游戏 | 容易。由于实时记录了各个对象的状态信息,所以重连的时候,直接创建这些对象,并同步信息即可 |
性能(客户端) | 客户端要跑完整逻辑,还要执行渲染逻辑,开销比较大 | 可以灵活优化,客户端跑较少逻辑 |
回放(离线) | 本身收集了所有玩家的输入信息进行逻辑推进,天然支持回放,且回放文件比较小 | 可以支持回放,但是逻辑比较复杂,需要不断记录状态信息,同时回放时候需要读取合适的时间。回放文件大 |
回放(实时) | 比较复杂,客户端需要本地对全场状态进行序列化,才能回到目标时间。播完回放后还需要加速追上实时游戏状态 | 相对容易,可以方便的记录快照信息,并按照录制内容随时播放 |
帧同步和状态同步游戏
老话题,选择 TCP还是 UDP,答案是大部分时候,TCP打开 NODELAY即可,现在网络情况好了很多,没必要引入新的复杂度。即便是“帧锁定算法”上线的多人实时格斗游戏,也有在用 TCP跑着的。
当然,等到你的游戏发布出去了,开始挣钱了,你想改进你的游戏效果,特别是高峰期的卡顿比例(需要收集客户端统计),那么你可以使用 UDP来改进,《街霸4》和《英雄联盟》都是使用 UDP的,比如你可以使用 libenet(英雄联盟用的)。不过 libenet所采用的传输技术,是上世纪的标准 ARQ做法了,《街霸4》所采用的传输技术远远高过 libenet,如果你想采用更为现代的传输技术,赢得更低延迟的话,可以使用“快速传输协议-KCP”,被再若干上线项目和开源项目使用的协议,效果远远 PK libenet。
在使用 KCP时,你可以用在你 TCP的基础上,再登陆时服务端返回 UDP端口和密钥,客户端通过 TCP收到以后,向服务端的 UDP端口每隔一秒重复发送包含握手信息,直到服务端返回成功或者失败。服务端通过 UDP传上来的密钥得知该客户端 sockaddr对应的 TCP连接,这样就建立 TCP连接到 UDP连接的映射关系。为了保持连接和 NAT出口映射,客户端一般需要每 60秒就发送一个 UDP心跳,服务端收到后回复客户端,再在这个 UDP连接的基础上增加调用 KCP的逻辑,实现快速可靠传输,这样一套 TCP/UDP两用的传输系统就建立了。
中国的网络情况比较特殊,会存在有些网络 UDP连接不上的情况,因此都是先连接 TCP,然后试图 UDP,UDP不通的情况下,退回 TCP也能正常游戏,一旦 TCP断开,则认为 UDP也断开了。
不果归根结底,还是先上 TCP,再根据自己游戏的特点和是否出现传输问题,选择 UDP。
下面对状态同步相关的一些优化技术进行学习。
首先问个问题:网络同步优化到底在优化什么?
我们进行网络同步优化,主要是想将网络延迟进行优化。
表现优化主要是想弱化玩家对延迟的感受
5.1.1 插值优化
在状态同步中,由于客户端每次收到的是其他角色的位置信息,为了避免位置突变,客户端会采用插值技术,让表现更平滑,而不是跳帧。
具体应用的时候,可以用使逻辑帧和渲染帧分离
5.1.2 客户端预测+回滚
关于预测,就是本地先执行。
把玩家本地预执行的指令都记录好时间戳并存放到一个Move_Buffer列表里(类似滑动窗口)。在添加了时间戳条件下,收到了一条过时的服务器位置数据。
延迟对抗主要是想弱化玩家对延迟的感受
5.2.1 延迟补偿(Lag Compensation)
延迟补偿就是弥补客户端到服务器同步延迟的一项技术,核心就是 服务器在指定时刻对玩家角色进行位置回滚与计算处理。
实现方式:服务端会定时记录所有玩家位置。假设客户端到服务端的延迟为Xms,当服务端收到客户端操作后,服务端使用记录的Xms前所有玩家位置来计算是否命中,从而抵消延迟带来的问题
延迟补偿缺陷:使用延迟补偿要考虑游戏类型。不适合ACT网游
5.2.2 命令缓冲区
把远端数据缓存在一个buffer里面,然后按照固定频率从buffer里面取,可以解决客户端卡顿已经网络抖动问题。
不过缓冲区和延迟是有冲突的,缓冲区越大,证明我们缓存远端数据越多,延迟越大!
守望先锋的InputBuffer
5.2.3 假表现
真实开发环境下,我们可以根据游戏的具体情况,加一些前摇动画来掩盖延迟。比如在无敌状态前播一个前摇动画等。
丢包对抗主要也是弱化玩家对延迟的感受
5.3.1 使用TCP
TCP不会丢包,对于延迟不敏感的游戏,优先采用TCP
5.3.2 冗余UDP数据包
一次性发送多个帧的数据来对抗丢包。
对于数据量比较小的游戏,可以采用冗余UDP的方案,即后续的UDP包会冗余一定量前面已发送的UDP包。
带宽优化的目的是减小客户端及服务器的同步压力。
5.4.1 同步对象裁剪
剔除不需要同步的对象。比如一个玩家离我很远,远到他的任何行为都不会影响到我,那我们就可以把他剔除,不进行同步给我,我不关心他的任何数据。
常见的裁剪方式有很多:SOI(Spheres Of Influence)、静态区域(把场景划分成多个区域,不在一个区域不同步)、视椎裁剪、八叉树裁剪、AOI(Area Of Interest)
着重讲一下AOI(Area Of Interest):根据玩家位置,维护一个动态的视野列表,视野外的对象会被完全忽略。实现方式有很多,常见的是基于格子的空间划分算法。虚幻引擎的大世界同步框架ReplicationGraph核心思想也是这个
5.4.2 分区、分房间
对于大型MMO来说,这是常见手段。将不同玩家分散到不同场景(不同服务器),这样可以减小服务器压力,降低延迟。但是也带来了跨服数据同步的问题
5.4.3 数据压缩和裁剪
坐标和旋转是我们场景的同步内容,但很多数据是不需要同步的。比如旋转的话,如果只需要一个Y轴旋转,我们可以传个float,而不是vector。比如我们可以压缩浮点数的精度。
然后对于状态同步,可以采用增量发送的方式来减少数据量
5.4.4 减少遍历和更细粒度的优化
对同步对象做优先级划分,发送频率调整等。
5.5.1 提升帧率
不同游戏的性能瓶颈不同,需要具体分析,包括:内存问题(GC、频繁申请与释放)、IO(资源加载、频繁读写文件,网络包发送频率过大,频繁读取数据库)、逻辑问题(大量遍历循环、无意义的Tick、过多的锁、高频率Log)、AI(寻路耗时)、物理问题(复杂模拟、碰撞检测)、语言特性等,客户端还有各种复杂的渲染问题(Draw Call太多,半透明,动态阴影),不断地优化,才能把帧率提高和稳定
5.5.2 保持帧率稳定和匹配
保持服务器帧率稳定
5.5.3 分摊计算压力
对于MMO这种服务器压力比较大的游戏,可以把一些复杂计算转交给客户端进行计算(甚至计算后返还给服务端),比如物理、寻路、AI等。
文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99
文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效
文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是
文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件
文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件
文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码
文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware
文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停
文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待
文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析
文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code
文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象