【问题标题】:Do good multiplayer/mmo client<>server games use latency within movement calculations?好的多人/mmo 客户端<>服务器游戏在移动计算中使用延迟吗?
【发布时间】:2010-11-29 18:11:33
【问题描述】:

这里有几个问题。

假设我有客户端 A 将向服务器发送以下消息:“START MOVEMENT FORWARD”。

服务器不会立即收到此消息,因为延迟会导致延迟。

问题 1:ping(或更好:round trip time)是客户端向服务器发送消息并收到响应所需的时间。如果您可以忽略服务器注意到它收到消息并开始发送响应所需的时间(这应该很短),这是否意味着以下?

  1. 客户端向服务器发送某些信息所需的时间 = 往返时间 / 2
  2. 服务器向客户端发送内容所需的时间 = 往返时间 / 2

因此,当客户端 A 发送该消息时,服务器应该会在客户端发送消息后的往返时间/2 毫秒内收到该消息。这就引出了下一个问题。

问题 2:客户端是否应该先发送包,然后在客户端实际执行该命令之前等待往返时间/2 毫秒(在这种情况下:向前移动)以补偿延迟/滞后?

现在,服务器将向附近的所有玩家发送以下消息:“客户端 A 正在向前移动”。然后,这些客户将确保客户 a 的角色开始移动,这将引导我进入下一个问题。

问题 3:接收到其他客户端移动的消息的客户端是否应该考虑到该消息是由服务器往返时间/2 毫秒前发送的?那么当前用于移动计算时间戳的时间应该减少往返时间/2?

在我看来,所有这些方法都会确保客户端之间的同步得到改善,因为延迟已被考虑在内。这是正确的做事方式吗?大多数其他优秀的多人游戏都这样做吗?您想给出任何 cmet、建议、替代方案或随机但相关的呼喊?提前致谢。

【问题讨论】:

    标签: synchronization latency multiplayer roundtrip


    【解决方案1】:

    有几种网络模型可以解决这些问题;

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

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

    你应该看看帝国时代2游戏工作室写的文章,里面描述了锁步模型的细节。

    在这个Model中,Client和Server逐帧运行游戏逻辑,例如RTS以100ms为一帧,Server和Client会同步frame Id,即同步时间。

    客户端在第 50 帧,发送命令 MoveForward,但不立即运行,客户端将告诉服务器在第 51 帧运行移动命令; 然后当第 51 帧到来时,服务器和客户端将同时运行命令。 所以客户端和服务器的逻辑是一样的。

    在这样的模型中,在第 50 帧,客户端和服务器可能会运行在第 49 帧发出的命令,因此客户端输入反馈总是有 100 毫秒或更长时间的延迟。

    客户端和服务器之间的延迟不仅包含网络RTT,还包含逻辑帧延迟,即100ms;

    在这个模型中,要同步空间,你需要让你的客户端代码和服务端代码是确定性的,所以它们只能同步command和frameId,不需要同步实体状态。

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

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

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

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

    当服务器接收到客户端命令时,它知道客户端何时在服务器时间内发出该命令,它会尝试推断运行该命令。

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

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

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

    在网络游戏中,至少有两种命令,第一种是运动,命令会运行一段时间,像源源不断的流,具有连续性的属性。

    其他喜欢使用冷时技能,命令效果会带冲动,我们应该区别对待。

    【讨论】:

      【解决方案2】:

      这是一个老问题,但我最近编写了类似的代码,所以也许这会对某人有所帮助。

      是的,延迟在计算中总是有用的。但它比 RTT 稍微复杂一些。往返时间总是在变化...您的网络代码可以保持平均值,但与该平均值的差异很大。

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

      • 时间:t
      • 放置:位置 (x,y,z) 和方向 (x,y,z,w)
      • Movement:以长度为速度 (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 的时间。它应该是一个持续的延迟,或者是逐渐变化的延迟,在严重滞后的时候你仍然会看到 jerk 帧

      你可以用额外的平滑代码来平滑所有的混蛋,但在你的代码完美无瑕之前不要这样做,因为它只会让人无法看到问题出在哪里。

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

      不,当本地“化身”移动时,不要延迟本地模拟。这似乎太没有反应了。您可以稍微延迟它(最多可能 50 毫秒)以帮助改善同步,但一直延迟到 RTT 会使您的游戏看起来令人沮丧地没有响应。设置本地延迟选项并使用它,因为可以接受小的一致延迟并改善同步。但这不是必需的,并且会导致很多问题,因此我建议最后执行该代码。 (如果您正在尝试制作 FPS 近战游戏,则需要执行此操作以及您可以获得的所有其他帮助)。

      至于作弊预防与模拟流畅性:首先,当官方位置发生变化时,客户不应仅从最后已知位置推断。它应该注册一个调整向量并缓慢地从旧路径移动到新路径以保持平滑(但就像我上面所说的那样,最后执行此代码,否则它将掩盖其他错误)。其次,服务器应该容忍广泛的延迟......即使在同一以太网上的机器上,数据包延迟通常运行 5ms 到 100ms 左右......这是一个相当大的范围。当然,你需要切断它并说“如果你说你在 T 时间搬家,但我在 T + some_large_number 收到了数据包,那么我认为你是在试图调整过去并对我撒谎。” some_large_number 不应该比平均 RTT 大很多,以保持人们诚实。

      模拟永远不会紧密同步。它们应该在 Internet 上保持在 400 毫秒左右,但在延迟时间肯定会超出这个范围……到 30 秒或更长时间,你需要容忍这种情况,因为它们并不罕见。鉴于互联网受到铜缆中光速的限制,您始终可以预期,对于远方客户端,单向延迟通常至少在 100 毫秒的范围内,通常为 500 毫秒或更长。

      因此我强烈建议你不要尝试通过互联网制作近战 FPS 游戏(一些大公司尝试但总会遇到麻烦)。如果您使用射弹(通过在一个模拟中快速运行它们而在另一个模拟中慢速运行),您可以做一些技巧,这样即使时间关闭,它也会继续显示。此外,FPS游戏使用的规则是命中检测是基于攻击者的模拟......当攻击者知道他已经死在目标上并没有击中时,感觉更加错误,然后当防守者知道他不在路上并被击中时感觉更加错误无论如何。你必须选择一个或另一个,从心理上来说就是这样。近战需要一定程度的同步,坦率地说这是不可能的,大多数游戏公司不会接触 MMORPG FPS 近战,而是使用自动瞄准(尝试玩 Mortal Online,你会明白我的意思)。

      祝你好运。

      【讨论】:

        【解决方案3】:

        对于 Q1:这对我来说是正确的。

        Q2:我过去这样做的方式是:如果你想让事情感觉反应灵敏,立即在客户端的模拟上开始执行动作,然后服务器在游戏时间向前模拟人发起动作.即客户端知道它在游戏模拟时间的几毫秒开始,所以服务器也可以在那个时间启动它(注意:这总是从服务器的当前时间倒退,所以你必须及时保存状态去做这个)。

        Q3:客户端只需要知道他们在时间 X 进行模拟,并且服务器说事件集 {A,B,C} 发生在时间 {X,Y,Z}。然后客户端和服务器可以使用相同的信息模拟转发,并且通常保持同步(同时发生冲突时除外)。在这些情况下,您需要让服务器重新同步事物,因此您通常会在非常小的误差范围内结束,并且体验非常流畅。

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

        【讨论】:

        • 所以服务器必须一直知道客户端的往返时间?另外,您将如何及时存储每艘船的 X、Y 和角度?而且,当船同时旋转时,你会如何计算这样的东西?
        • 延迟无关紧要,因为客户端和服务器都在共享的时间范围内进行模拟转发。因此,如果客户端说“在时间 5 我跳了”,服务器可以在时间 5 正确地模拟该事件。 Q2:用于存储数据:只有多个副本。与您的网格信息或游戏数据相比,您的动态信息很小。 Q3:决定论和冲突解决。 sim 及时向前。如果玩家 A 和 B 互动,解决并纠正客户。如果没有冲突:服务器和客户端自动同步。
        【解决方案4】:

        我认为在大多数 mmo 中,您的客户端主要在不与服务器交互的情况下移动,除非出现严重滞后。服务器在客户端发送给服务器的消息的帮助下再现运动。因此,例如,如果服务器滞后,客户端将停止接收来自服务器的反馈并恢复到服务器确定您所在的位置。这就是为什么你在糟糕的延迟期间跳回几帧的原因。这样,服务器也可以控制您的速度,这样您就不会进行快速黑客攻击。如果您的客户端以超过服务器确定的速度的特定速率移动,您只需跳回额外的帧。

        如果服务器在一定时间内没有响应,其他客户端根本不会让您移动。这是您会遇到“冻结延迟”的时间。

        当然也有服务端简单地获取客户端发送的位置并盲目信任的情况。这些游戏通常容易受到传送黑客的攻击。

        其他玩家的位置确实有延迟,如果你拿两台电脑,连接wow之类的游戏,同时移动两个角色就可以看到。您会看到,在您真正开始移动他之后,非本地角色将在两台计算机上开始移动。

        客户通常会获得某种延迟补偿。因此,如果另一个玩家在某个方向移动然后停止,您的客户端仍会模拟该玩家的移动,直到您从服务器收到他改变方向或停止移动的消息。这就是为什么其他玩家可以在 ping 高时来回跳跃。这也是为什么玩家在您遇到延迟时似乎只是滑行/逃跑/走开,然后在您的客户端从服务器接收到位置时返回到他们的真实位置。

        当然,这会因引擎而异,但这是一种相当通用的方法。

        编辑:忘记补充说,服务器也使用延迟补偿是很常见的。如果您在您的范围内的 mmo 中击中某人,则该人可能不在服务器视图的范围内。因此,服务器会为您的两个客户端获取延迟,并尝试匹配您是否真的在彼此的范围内。

        【讨论】:

        • 请注意,我不是在问许多游戏使用什么样的运动系统或算法,我已经讨论过这是另一个线程。这里的主要问题是移动计算是否应该考虑延迟(在客户端或服务器端完成),以及我所做的假设是否正确。无论如何都要为尝试提供帮助而点赞。
        • 抱歉造成误解。我的两分钱是您至少应该在服务器端使用延迟补偿,以使其对具有高延迟的人公平。然而,实现它的好方法不是我有资格回答的问题。祝你好运,我希望你最终能找到你想要的东西。
        猜你喜欢
        • 1970-01-01
        • 2014-07-14
        • 2015-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-08
        • 2019-10-09
        相关资源
        最近更新 更多