好的多人在线游戏/大型多人在线游戏客户端<>服务器是否在移动计算中使用延迟?

3
这里有几个问题。
假设我有客户端A,它将向服务器发送以下消息:“START MOVEMENT FORWARD”。
由于延迟的存在,服务器不会立即接收到此消息。
问题1:ping(或更好的说法是往返时间)是客户端发送消息到服务器并接收到响应所需的时间。如果可以忽略服务器注意到已收到消息并开始发送响应所需的时间(这应该非常短),这是否意味着以下内容?
  1. 客户端发送消息到服务器所需时间 = 往返时间 / 2
  2. 服务器发送消息到客户端所需时间 = 往返时间 / 2
因此,当客户端A发送该消息时,服务器将在客户端发送消息后约经过往返时间/2毫秒才能接收到该消息。这引出了下一个问题。
问题2:客户端是否应该先发送数据包,然后等待往返时间/ 2毫秒后再实际执行该命令(在本例中为向前移动)以补偿延迟?
现在,服务器将向所有附近的玩家发送以下消息:“CLIENT A IS NOW MOVING FORWARD”。然后这些客户端将确保客户端a的角色开始移动,这使我想到了下一个问题。
问题3:接收到其他客户端移动消息的客户端是否应考虑该消息是往返时间/ 2毫秒之前由服务器发送的?因此,用于运动计算时间戳的当前时间应减少往返时间/ 2?
在我看来,所有这些方法都可以确保客户端之间的同步性得到改善,因为延迟已经被考虑在内。这是正确的做法吗?大多数其他良好的多人游戏是否都这样做?您有任何评论、建议、替代方案或相关的随意呼喊吗?提前致谢。
4个回答

10

我认为在大多数MMO游戏中,除了出现严重的延迟之外,客户端主要是通过与服务器的交互来移动。服务器利用客户端发送到服务器的消息来重新生成移动。例如,如果服务器出现延迟,客户端将停止接收来自服务器的反馈,并返回服务器确定您所处位置位置。这就是为什么在出现严重延迟时会反弹回几个帧。这样,服务器还可以控制您的速度,以便您不会使用加速作弊。如果您的客户端以超过服务器确定的速度移动,那么您只需跳回额外的帧。

其他客户端将不允许您在一定时间内没有收到服务器响应的情况下移动。这就是您会经历“冻结延迟”的时间。

当涉及到其他玩家的位置时,确实存在延迟,如果您采取两台计算机,在像魔兽世界这样的游戏中连接并同时移动两个角色,您会看到在两台计算机上,非本地角色将在您真正开始移动他之后开始移动。

客户端通常具有某种形式的延迟补偿。因此,如果另一个玩家朝着某个方向移动然后停止,您的客户端仍将模拟该玩家的移动,直到您收到来自服务器的消息表明他改变了方向或停止移动。这就是为什么当延迟很高时,其他玩家可以来回跳动。这也是为什么在您遇到网络延迟时,玩家似乎可以轻松地滑动/奔跑/走开,然后在您的客户端接收到服务器位置时返回其真实位置的原因。

当然,这也会因引擎而异,但这是一种相当普遍的方法。

编辑:忘记添加服务器也非常常见的延迟补偿。如果在MMO中击中范围内的某个人,该人可能并不在服务器的视野范围内。因此,服务器会考虑双方客户端的延迟,并尝试匹配您是否真正在彼此的范围内。


请注意,我并不是在问许多游戏使用什么样的移动系统或算法,这已经在另一个帖子中讨论过了。这里的主要问题是是否应该考虑延迟对于移动计算(无论是客户端还是服务器端)的影响,并且如果我所做的假设是正确的。无论如何,感谢您的尝试帮助,点赞支持。 - Tom
对于误解我感到抱歉。 我的建议是,您至少应该在服务器端使用延迟补偿,以使高延迟的人也能公平竞争。然而,如何实现这一点,我可能无法回答。祝你好运,希望你最终能找到你要寻找的东西。 - Jonas B

4

这是一个旧问题,但我最近已经编写了类似的代码,所以也许这会帮助到某些人。

是的,延迟在计算中总是有用的。 但它比RTT略微复杂。 回程时间始终在变化...你的网络代码可以保持平均值,但与该平均值的方差很大。

本地客户端、远程客户端和服务器都使用算法预测当前位置。以下数据接近典型:

  • 时间:t
  • 位置:位置(x,y,z)和方向(x,y,z,w)
  • 移动:线性运动矢量给出方向,长度为速度(x,y,z),和旋转运动矢量给出轴,长度为旋转速度(x,y,z)

您需要算法,从[T,P,M]集合推导出simtime。我不会在这里提供那些。

当客户端在[T,P,M]上注册船只驾驶变化时,该变化直到T+deltaT才能到达服务器。但是,如果deltaT在典型网络延迟的公差范围内,则服务器可以说:“是的,它发生在T,我接受了。”否则,它可能想要纠正客户端,说“不,这超出了公差范围,它发生在我的时间T'”,此时客户端将不得不从服务器的纠正后的变化[T,P,M]开始重新播放(这意味着您需要保留它们的队列或列表)。

下一个客户端将在T+deltaT+differentdeltaT时获得它。它不可能改变已经模拟过的内容,因此,如果它没有延迟其模拟,它将跳过远程船只,您将看到一个抖动帧。这就是为什么远程驱动的船只应该将其模拟延迟一段时间,这段时间始终大于2 * typicaldeltaT。它应该是一个恒定的延迟,或者一个逐渐变化的延迟,在严重滞后的情况下,你仍会看到抖动帧

您可以使用额外的平滑代码来平滑所有抖动,但除非您的代码完美无缺,否则不要这样做,因为它只会使问题难以找到。

您必须拥有良好的同步时间参考。很多代码都处理得相当粗糙(例如RakNet并没有很好地处理它)。以下是一个好提示:在短期内,您可以假定每个人的时钟都以相同的速度运行,您只需要弄清楚偏移量是多少,因此保持最大和最小偏移量的窗口,并随着学习而关闭;从长远来看,您需要补偿那些时钟运行快或慢的客户端,因此如果确定必须这样做,则允许窗口打开。您必须使用本地时间源,它单调递增且不依赖于处理器速度(现在是可变的)。

不要延迟本地模拟当本地“avatar”移动。这看起来太不响应了。您可以稍微延迟一下(最多50毫秒)以帮助改善同步,但将延迟全部延伸到RTT会使您的游戏看起来令人沮丧地不响应。设置一个本地延迟选项并进行测试,因为小的一致延迟是可以接受的并且可以提高同步性能。但是这不是必要的,而且可能会导致很多问题,所以我建议在最后才编写此代码。(如果您正在尝试制作FPS格斗游戏,则需要执行此操作以及其他所有可用的帮助)。
至于防作弊与模拟平滑度:首先,当官方位置发生更改时,客户端不应只从上次已知位置进行外推。它应该注册一个调整向量并缓慢移动从旧路径到新路径以获得平滑度(但是如上所述,最后编写此代码,否则它将掩盖其他错误)。其次,服务器应容忍广泛的延迟...即使在同一以太网上的机器上,数据包延迟通常也会运行5ms至100ms左右...这是相当大的范围。当然,您需要切断它并说“如果您在时间T移动但我在T + some_large_number收到数据包,那么我认为您正在调整过去并向我撒谎。”some_large_number不应比平均RTT大得多,以保持人们的诚实。
模拟永远不会被紧密同步。它们应该在互联网上保持在400ms左右,但在延迟时肯定会偏离...到30秒或更长时间,并且您需要容忍这些事情,因为它们并不罕见。鉴于互联网受铜中光速的限制,您可以始终期望单向延迟通常至少在100ms最小值以上,通常为500ms或更长时间。
因此,我强烈建议您不要尝试在互联网上制作格斗FPS游戏(一些大公司尝试了但总是会遇到问题)。如果您使用投射物,则可以使用技巧(通过在一个模拟中快速运行它们,在另一个模拟中运行它们缓慢),使得即使时间不准确,看起来也是正确的。此外,FPS游戏使用命中检测基于攻击者的模拟...当攻击者知道他已经准确地瞄准却错过了时,感觉更加错误,而不是防守者知道他已经离开了位置,但仍然被击中。您必须选择其中之一,从心理学的角度来看,就是这样做的。格斗需要一种同步水平,这实际上是不可能的,大多数游戏公司不会涉足MMORPG FPS格斗游戏,而是使用自动瞄准(尝试玩玩《Mortal Online》,您会明白我的意思)。
祝你好运。

1

对于Q1:我认为那看起来是正确的。

Q2:我过去处理这个问题的方式是:如果你想让事情感觉灵敏,就立即在客户端模拟上执行动作,然后服务器在游戏时间向前模拟当人物启动动作时。也就是说,客户端知道它在游戏模拟时间的哪个毫秒开始,因此服务器也可以在那个时间开始(注意:这总是从服务器当前的tick向后倒退,所以你必须将状态保存回去)。

Q3:客户端只需要知道他们正在模拟X时间,并且服务器说事件集{A,B,C}发生在时间{X,Y,Z}。然后客户端和服务器可以使用相同的信息向前模拟并保持同步(除非发生同时冲突)。在这些情况下,你让服务器重新同步事物,所以通常会有一个相当紧密的误差范围和大多数平稳的体验。

如果你的目标是改善延迟感知,你也可以尝试信任客户端。


那么服务器必须始终知道客户端的往返时间?此外,您将如何存储每个时刻每艘船的X、Y和角度?当船在旋转时,又该如何计算这些内容呢? - Tom
延迟并不重要,因为客户端和服务器都在共享的时间框架中向前模拟。因此,如果客户端说“在时间5我跳了起来”,服务器可以在时间5正确地模拟该事件。Q2:对于存储数据:只需有多个副本。与您的网格信息或游戏数据相比,您的动态信息非常小。Q3:确定性和冲突解决。向前模拟时间。如果玩家A和B互动,则解决并纠正客户端。如果没有冲突:服务器和客户端会自动同步。 - aaron

0

在解决这些问题时,有几种网络模型;

在网络游戏中,你需要同步两个东西,一个是时间,另一个是空间。

  1. 一种名为锁步的网络游戏模型;

你应该看一下《帝国时代2》游戏工作室写的文章,其中详细介绍了锁步模型。

在该模型中,客户端和服务器逐帧运行游戏逻辑,例如,即时战略游戏将100毫秒作为一帧。服务器和客户端将同步帧ID,以实现时间同步。

客户端在第50帧时发送前进命令,但不会立即执行该命令,而是告诉服务器在第51帧运行移动命令;当第51帧到来时,服务器和客户端将同时运行命令,因此客户端和服务器的逻辑将相同。

在这种模型中,在第50帧时,客户端和服务器可能会运行在第49帧发布的命令,因此客户端输入反馈始终存在100毫秒或更多的延迟。

客户端和服务器之间的滞后不仅包含网络RTT,还包括逻辑帧延迟,即100毫秒。

在这个模型中,为了同步空间,你需要让客户端代码和服务器代码具有确定性,这样它们只能同步命令和帧ID,不需要同步实体状态。

在这个模型中,输入反馈很大,所以你需要播放动画或声音来帮助玩家忽略延迟。

  1. 其他模型使用状态同步

在这个模型中,我们还需要同步时间,这样客户端就可以猜测服务器的当前时间。

当玩家输入时,客户端立即移动,然后发送移动命令或客户端目标位置到服务器,并附带当前服务器时间戳,该时间戳由客户端估算。

当服务器接收到客户端命令时,它知道命令在服务器时间上是何时发出的,然后尝试使用外推法运行命令。

所有其他客户端将接收到该命令及其服务器时间,并尝试外推该命令。

这些技术包括客户端预测、服务器延迟补偿和服务器实体插值。

在这个模型中,客户端输入反馈很短,但对于一些冲动命令,比如使用技能,我们仍然需要使用锁步方法,配合动画、声音和粒子效果来弥补输入反馈时间。

在网络游戏中,至少有两种命令。第一种是像移动这样的命令,它会持续一段时间,就像一个稳定的流,具有连续性属性。
另一种是使用带有冷却时间的技能,命令效果会在瞬间生效,我们应该对它们进行不同的处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接