关于异步通信与同步通信的问题

关于异步通信与同步通信的问题,第1张

卡牌类游戏如果仅仅是单人游戏,那便也没什么技术含量了。从拉用户的角度,如果没有实时多人游戏玩法便也失去了游戏一大块吸引力。

通过这些年对卡牌类游戏的积淀,帧同步是这类游戏最常用的多人游戏同步方案。如果是回合类型游戏,那么状态同步便大概率是首选项了,但它的实现复杂度在这类游戏中却又不及帧同步技术了。所以这一章,就记录我所开发的几个项目所设计的帧同步方案与细节。

我们将项目中所有的浮点数类型全都统一成了定点数,这样就确保我们的逻辑运算不会因平台的不同而导致计算结果的差异。之所以不同平台对浮点数的运算有差异,则是因为各厂商底层硬件对浮点数的运算不一致导致。虽然大家计算结果都差不多,但是到了小数点最后几位总会有所不同。如果采用double进行计算,虽然double精度更高,但依旧免不了会在最后几位出现不一致的情况,只是这时已经是小数点后二三十位的事情了。

正是基于这个原因,我们最开始先使用double作为浮点数据类型,后又使用定点数进行替换。因为我的定点数实现的有效精度只能到小数点后5位,所以即便底层硬件会对浮点数运算产生误差,却依旧会被定点数强制统一而不必担心更小精度运算不一致所导致的问题。

定点数方案在网上可以找到一大堆,而且也对定点数方案的利弊进行过多方分析,此处不作赘述,只是网上多用10000作为定点数的放大倍数,这是我的定点数实现与网上所不同的地方。

在我实现的定点数中,采取了一个特殊的放大倍数,即 2^16 。这样一个放大倍数,最大的好处就是定点数之间的大多数运算,都可以采用位运算的形式进行放大缩小,于性能上更合适一些。此外,2的16次方作为放大倍数,可以使小数的有效位保持到小数点后5位,从计算精度的角度考虑,这样一个范围也是满足我们项目开发需求的。至于不同项目的放大倍数,可以根据需要可以调整为其他的2的n此幂均可。

采用2的整数次幂,会在定点数的乘、除、开方、比较大小运算中提高计算性能,远比乘除10000效率来得高。特别说明的是,这里我们的开方直接调用了C#数学库中的开方 *** 作,不同的是在开方前我们就需要对待开方的数左移16位,这样开方得到的结果才是满足定点数放大倍数的值。

基于以上几点,我们才会使用long作为定点数内部的数据存储类型,而定点数所表示数字的范围,与int类型一致。如果使用定点数存储了一个大于int最大值的数,那么很可能就会在后续的计算中因移位而产生计算错误。

当实现了自己的定点数方案之后,就需要根据它的精度去生成 三角函数查询表 。这里我仅生成了sin查询表,而计算其他三角函数时根据sin值就可求得具体值。

在实现定点数的过程中,还有很多值得参考的内容:

采用帧同步方案后,网络方案就是一个需要关注的议题。

帧同步方案下,客户端和服务器之间无论每帧都同步信息,还是有数据变动时再同步信息,都需要频繁地使用网络进行数据交互。传统TCP方案下,TCP本身发送机制有延时,所以就需要使用KCP来实现高实时性,但是代价(按照官方说法)就是额外消耗10%-20%的带宽。

但是需要说明的是,在丢包率上升的情况下,KCP因其底层数据包的组织与发送形式,会导致流量变大,这种情形下反而不如使用TCP的综合效率。这是选用KCP方案的一个缺陷。

我的项目中,最终设计了两套网络结构,KCP与TCP。这里就需要客户端采集与服务器的网络状态数据(ping值)。当丢包率与延迟不严重时(可根据项目实际情况设定阈值),网络采用KCP;一旦网络状态超过阈值,则将底层网络方案切换为TCP。这种方案的设计目的,主要就是为了解决丢包率上升时KCP流量过大的问题,但是具体情况需要根据项目类型与具体需求而定。

战斗逻辑处,我们已经讲过定帧的概念了,但是那里的定帧主要针对的是逻辑的定帧执行。

帧同步也需要定帧的概念。只有当所有客户端与服务器帧率统一时,大家的行为才能被约束一致。因此,我们就需要将帧同步的定帧与逻辑的定帧加以区分,下面我就用“逻辑帧”指代逻辑的帧,而使用”服务帧“指代帧同步的帧。

最简易的方案,就是设计之初就令逻辑帧与服务帧的帧率统一。这样做的好处,就是免去了两个帧速率不一所导致的匹配问题,服务器每驱动一帧,逻辑帧就运行一帧,实现起来简单方便。

但是,服务帧的设计一般是要从通讯性能出发的,天生帧率会比较低,而逻辑帧因项目需求不同而不稳定,大概率是比较高的帧率。所以,服务帧与逻辑帧的帧率不匹配是常态,这就需要用到一些转接件来实现我们的需求了。

还记得 第一章 我曾提到的接口 ILogicMgr 吗,它的派生类的作用之一,就是提供一个“帧率差速器”,以使得游戏逻辑能够在服务帧与逻辑帧不同的帧率下平稳运行。帧率差速器以帧率最快的一方的速率为基础速率进行心跳,每次心跳时返回本次心跳结果。帧率差速器的心跳结果分为三种:

因为我们的项目是锁帧方案,服务帧先行,所以差速器心跳流程图如下:

差速器是锁帧模式下的一个重点,因为它的存在,才能够让逻辑帧与服务帧按照顺序执行。也因为差速器内部有时间管理,所以才能够实现服务帧的锁帧功能。这部分内容依靠的就是服务器同步的 当前最大帧号 数据,以最大帧号作为限制。如果网络出现波动,那么客户端逻辑就会卡在最大帧号对应的时间点,直到收到了服务器最新的最大帧号数据。

追帧 也是在此处完成,即如果客户端发现落后服务器帧数比较多,就需要在此处设计算法加速逻辑的运行,使得一次心跳执行更多的逻辑帧。但是需要注意不要一次把所有逻辑帧都跑完,这样会造成客户端显示效果上的撕裂感。

上文在讲 帧率差速器 时,已说明了服务帧与逻辑帧的概念,而且我们也明确了差速器是需要用在接口 ILogicMgr 的派生类中的,所以逻辑部分自然也是集成在这里的。

当差速器每次心跳结果是逻辑帧时,就是我们调用逻辑的心跳的时机。以此便完成了帧同步方案下逻辑的集成。也因为逻辑的心跳是在 ILogicMgr 中被驱动的,所以无论追帧或是心跳时间控制,都可以在此处根据需求进行开发。

我在项目中采用的帧同步方案已在上文进行了较为详细的说明。

需要指出的是,在服务帧概念下,我们的方案是以 服务器领先客户端 实现锁帧效果的。这种实现方案最为简单也最为有效。当我们面对的项目是一个对实时性要求不高的项目时,这种锁帧方案可以简单有效地实现我们的需求,也不会对玩家造成太多的感受上的负面影响。

如果项目实时性要求高怎么办?

类似ACT或MOBA类游戏,玩家需要能够及时获得技能释放的反馈,否则延迟的技能释放会撕裂快节奏的游戏体验。这种情况下就需要我们设计全新的思路。而在此之前,我们需要明确快照的概念。

快照,即当前数据的拷贝。我们之所以需要快照,是因为我们后续会需要在某个时间点保存所有的数据,然后在另一个时间点通过保存的数据还原战场的数据。

基于战斗框架,快照我们其实只需要逻辑的数据快照即可,这样即便逻辑通过快照进行了数据回滚,也可以将数据同步给显示层进行还原。ECS架构本身因为对数据与逻辑进行了完整的分离,所以快照与数据回滚的实现方案可以参考 第二章 内容,此处不作赘述。

下文我们将介绍一个可以改进的帧同步策略,就需要用到数据快照与回滚。

还有一种帧同步策略,即在服务帧概念下,客户端时间领先于服务器时间。这种情况下,客户端所有的逻辑可以看做是一种预演,而服务器下发的则是过去某帧的信息。

假设客户端是第 n+2 帧,服务器下发的是第 n 帧。

以上就是客户端优先的帧同步策略,但是这里也需要考虑几个实现的问题:

以上就是我对帧同步相关的记录与思考, 下一篇 便聚焦开发工具进行说明。

首先要知道游戏类型是什么,然后知道承载人数是多少,以及开发周期多少。需要根据这些来决定游戏架构和技术选型。

对于gameplay来说,本身就是个大循环,一定频率进行tick,接收来客户端或者其他服务器的rpc,处理逻辑,然后数据落地以及发送数据给客户端或者其他服务器,一般gameplay来说在同一个进程里都是同步的方式去编写,同步的实现大多数是单线程的,或者使用coroutine来实现actor这种模式。大部分游戏交互都是比较多,所以不论service和service之间的交互还是玩家和玩家之间的交互,如果考虑多线程的同步的问题,会非常复杂以及很容易做错,所以一个service内同一个时刻都是在一个线程中执行的。

针对mmo或者一些竞技类游戏往往有场景管理的概念,就是游戏AOI,比如一个玩家移动,需要告诉周围所有的玩家,复杂度在nn,如果减少这个n,就有了AOI算法,比如九宫格,十字链表等,如果刚开服的时候很多人挤到一个主城中,就算采用九宫格和十字链表等AOI等算法,往往同屏内玩家数量还是很大,客户端渲染的单位数量比服务器少一个数量级的,所以场景管理这里还可以有个分线的做法,玩家多的时候,不同线不可见,玩家少的时候进行合并。

如果做帧同步一些关键点为表现要和逻辑分离,随机算法和随机种子的一致性,数学库浮点换定点,三角函数采用泰勒展开或者查表法,需要保序的容器,timer不能基于钟表时间而需要帧timer,以及防作弊(一般都是投票法,或者服务器跑个验证端)

现在很多游戏在线更新bug甚至不停服更新慢慢变成一种强需求了,实现这种方式主要使用脚本热更新,热重启+逻辑内存以及ab服切换来实现。

震惊!某 游戏 奖金上亿赛事观战竟卡成PPT,周六无法开启 游戏 ,玩家们竟这样说

适应了!

不得不以一个UC式的开头来吐槽笔者上周末的遭遇,笔者与久未相见的朋友兴冲冲地准备开个两人黑,但朋友受不了反复出现的老问题,扭头玩起了更老的 游戏 DNF。

作为一名经验丰富且久经考验的dota2战士,我熟知各类紧急抢救 *** 作,随意试玩机器人模式可以解决这个老问题,可我朋友只是个周末玩家而已。

为什么我的眼里常含泪水,只因为我对这服务器恨得深沉,当我死了,我一定要带走这垃圾服务器。爱从来不需要理由,就像诗人艾青对祖国深沉的爱一样与生俱来。但恨却比爱显得更加感情激烈,可以有没来由的爱,却从来没有无来由的恨。

我真的无奈于这服务器,无法直面这惨淡的周末时光。

一 CALL ME DAD

为什么服务器是爸爸,对,说的就是你,Dota2的服务器。

The Server is the Man!

其实,早在上世界九十年代,国外的 游戏 爱好者便开始搭建服务器提供收费 游戏 服务,是最早的 游戏 开发商,运行商和获利者。

但对早年的国内大部分 游戏 玩家而言,服务器或者说另类的主机是一个较为虚幻的概念,大部分的 游戏 只能称之为联网 游戏 ,或者干脆就是简单的联机 游戏 ,真正让大家对于服务器拥有概念的是大型网络 游戏 ”(MMOG)的浮出水面,使得 游戏 直接联入互联网,激发了大家强烈的互动情绪。

诸多即时战略 游戏 的出现更是加深了这一认知。

我想要和别人一起玩,

这成为玩家心中的呼声。

正是在这股思潮的鼓动之下,使得多人在线 游戏 成为了大家心中的宠儿,自然包括我们的dota。在2005年,601版发布不久, IceFrog成为dota主要的地图程序员,负责包括 游戏 的执行和平衡的测试在内的任何工作。

在2003年《魔兽争霸III:冰封王座》之后,暴雪公司正式宣布了《魔兽世界》的开发计划,之前就已经秘密开发了数年之久。魔兽世界于2004年年中在北美公开测试,2004年11月开始在美国发行,中国大陆亦已于2005年6月正式收费运营。

服务器这一概念才开始深入人心,普通玩家才开始走进服务器。

服务器正是为了解决大型多人在线 游戏 产生的诸多问题而生,而延迟,或者说网络同步正是它要解决的问题之一。

在虚拟世界中,保证 游戏 的一致性是一个基本前提。通俗的说就是虚拟世界中的事实,当多人玩家一起玩 游戏 时,看上去他们确实像是在共享同一个虚拟世界,在同一个世界中游玩。比如在一个FPS 游戏 中,大家的延迟都很高,A、B两个玩家同时发现了对方,并向对方射击,如果没有很好的同步机制,那么A的屏幕上显示B还没有开q就被击杀,而B的屏幕上显示A还没有开q就被击杀,这就出现了不一致的问提。

OK,这让我们回到开头,让我们来了解为什么dota2的服务器是玩家们的爸爸,而在dota1中我们却很少遇到卡顿情况,反而碰到的大多是挂比们。

原因是两者采取的处理延迟的方式不一样而已,他们采用了不同的 游戏 同步模式。一个是帧同步,另一个是状态同步。当然实际应用下来很复杂,这里只是简单介绍而已。

其实在早期的DOTA或者说WAR3中,严格意义上是没有服务器这一概念的,类似的只有主机这一说法,但主机并不满足服务器这一严格定义。在这里感谢来源于网上的与相关资料,只做引用,以向大众简单介绍为主。

什么是帧同步

一般War3/星际等采用,基于指令驱动各个客户端自计算逻辑。服务端只管分发指令,每个客户端根据完整的规则运算整个战场。

简单来说,就是所有的事自己管,所有的数据都有自己的数据完成,网络传输的仅仅是指令而已,既是玩家的 *** 作指令,由自己的电脑完成计算并呈现出来,具体下来。其实你只是在看一场由自己计算机演算好的视频而已。

这样对网的要求仅仅只是稳定而已,它并不需要巨大的流量,你的电脑将会自己计算完成一切,自然作弊也很简单,数据处理几乎由你自己完成,哪里不能作弊开挂呢

那什么是状态同步

大部分MMORPG的主要实现方式,具体下来,服务器负责计算大部分的 游戏 过程,并且转送这些计算的结果,客户端仅仅负责发送玩家的 *** 作,以及表现收到的 游戏 结果。服务器是一个运行 游戏 的专用主机,用于裁定世界模拟, 游戏 规则,玩家输入处理。客户端是一个连接到 游戏 服务器的计算机。客户端和服务器之间,通过相互以高频率发送小数据包来交互。客户端从服务器接收到世界的当前状态,并且根据这些状态更新,生成输出视频、音频内容,进而呈现在玩家面前。

简单来说,对于我们的电脑而言,上面的dota2客户端虽然也承担 游戏 逻辑的模拟,只处理些不太重要的逻辑计算。因此更像是素材收集库,大号的电视机,显示器。我们只知道我们自己的事,其他的东西全在服务器身上。

1 网络完善状态好,不仅要稳定还要快速

因为服务器和客户端需要进行所有的数据交互和同步,导致网络流量大。所以涉及到的网络问题一旦发生波动,不管是哪一方,影响都特别巨大。

2 服务器压力大,卡顿时直接闪现

前文中已经提到,服务器负责处理大部分的 游戏 逻辑计算,因此,大部分的 游戏 处理过程都是由服务器完成,再将数据传送回客户端呈现,因此服务器出了一点问题,直接导致我们的体验很差,直接GG。

3 地狱火问题,单位数量越多越卡

这只是一个小问题,笔者早年曾经遇到过,单位越多同步的数据量越大,当单位越多时,往往会越卡,本来尚能接受的 游戏 流畅程度瞬间下滑。早年服务器脆弱时,几乎很清楚可以看见这个问题,几个地狱火一砸,卡顿明显,现在基本已经消失。

正是如此导致网络延迟处理起来特别的麻烦,即使是专业人员也得花时间来排除,然而这并不能成为理由。

二 完美和V社的糊涂账

完美的支持者说,明明先登国外协调服务器,红字完美可不背锅,再说了,国际服有时不也登不上嘛,国际间网络影响啦。

V社的支持者说,国服可比外服崩的常见多了,再说了,每周六的必卡,不定期卡顿,这个锅也能放到V社身上

争吵无益于解决任何问题。

结果一团乱麻,受伤的只有想玩 游戏 的我们。

作为拥有这个星球最高 游戏 奖金赛事的dota2,实在不应该如此没有牌面,很显然的一点,当年这款用户成熟度极高,赛事层出不穷的顶级 游戏 产品,始终没有迎来如同当年一样灿烂的未来。

很难想象,这是一款几乎与英雄联盟同时推出的 游戏 ,作为继任者的dota2,最正版毫无争议的完成品,但是在用户的数量上,从一开始DOTA与《英雄联盟》在用户上的并驾齐驱,到了后来《英雄联盟》完完全全的甩开了“继承者”的DOTA2。

从 游戏 人数上来说,dota2并没有完成它转化老玩家和吸引新玩家的 历史 使命,在这两项大考上都交出了不及格的答卷,建立于辉煌之上却最终只能偏距一隅。笔者很幸运也是2012就能接触玩到dota2,但一直一来体验真的糟糕,多少次满怀期待却因为服务器最终无奈GG,最终在13年ti3结束才最终得以享受流畅的 游戏 ,真的是一把辛酸泪。

V社和完美可以称得上是天生的合作者,各怀心思,却又不谋而合。

完美试图通过对dota2的支持完成自身电竞版图的构成,在电竞这一未来大势面前发出自己的声音,真正的盈利对完美来说并不重要,从财报来看,坚挺的老端游和全新的手游,甚至不断发展的影视事业这些才是完美的经济增长点。

其次,对于V社手中的steam,完美同样抱有期待,作为最想代理的产品,代理steam可不再是赔钱赚吆喝那么简单了。

但完美到底愿意花多少心思在dota2上,我们不得而知,毕竟,办事和努力办事就在努力两字上了。

但从V社角度来看,没有比完美更好的背锅侠和小弟了,steam通过曲线救国的方式走进了玩家心中。

完美代理了DOTA2,但是所有用户是通过Steam下载,只是一开始使用一下完美的账号,后面完全是通过Steam账号,所有的用户数据基本都在V社手里,发生了什么也只能求靠远在大洋彼岸的V社工程师。当初V社选择制作dota2也是想到了借助其广大的用户基数推广steam平台,在中国它成功了,而且是相当的成功,普通玩家通过这个平台了解到了更多的 游戏 。

双方的目的都达到了,那么到底谁该为土豆服务器买单呢

steam素来以服务器质量过硬而享誉盛名,可为什么在dota2的服务器上偏偏和育碧一样呢完美在业内同样拥有声誉,技术实力同样不容小觑,开发的 游戏 也是一个赛一个的精致,可为啥连相当成熟的服务器技术方案都解决和实施不好呢

完美真的甘愿顶着骂名,而V社也继续选择合作,甚至在CSGO之后将steam中国也交给了他们,显然对完美信任有加。

三 无奈的玩家

玩家有多喜爱这个 游戏 ,就有多讨厌这个不时抽风的服务器。

这个顽疾几乎是伴随着dota2而生,几乎是每一个玩家的切身之痛,它就好像是一个dota2上无可奈何的瘤子,吸着玩家们宝贵的时间,吸着玩家们最珍贵的耐心,消磨着玩家们不断积攒下来的最真挚对dota2的热爱。

年年高涨的奖金证明了玩家们的爱,笔者从有余力开始就没有断过支持,因为玩饰品真的上瘾,没够。即使是笔者的不少云玩家朋友也依然贡献了不少,年年不曾缺席的他们依然会看着直播,不忙的时候来把dota。可有时这糟糕的观战也让人感到难受。

观战问题真的延续有很长一阵时间了,眼看本土TI将至,中国地区的预选赛也即将开打,那什么来宽慰一直在支持的玩家们呢

答应我,起码观战不要PPT,好吗

这真的是一个简单的要求。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/13156436.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-06-13
下一篇 2023-06-13

发表评论

登录后才能评论

评论列表(0条)

保存