同步客户端 - 服务器游戏状态

时间:2011-04-17 01:40:26

标签: java synchronization udp client-server

我正在制作一个客户端服务器MMO风格的游戏。到目前为止,我已经设置了框架,以便服务器和客户端相互交互以提供状态更新。服务器维护游戏状态并定期计算下一个状态,然后每隔一段时间(每n毫秒)将其发送给所有客户端。用户可以在客户端查看和响应该新状态。然后将这些操作发送回服务器进行处理并发送出去进行下一次更新。

显而易见的问题是,这些更新需要时间在服务器和客户端之间传输。如果客户端行动攻击敌人,那么当更新回到服务器时,服务器很可能已经使游戏状态进展得足够远,以至于敌人不再在同一地点,并且超出范围。 / p>

为了解决这个问题,我一直试图想出一个好的解决方案。我看了下面的内容,它帮助了一些,但并非完全:Mutli Player Game synchronization。我已经得出结论,我不仅可以传输游戏的当前状态,而且可以传输其他信息,例如方向(或AI运动的目标位置)和速度。从这一点来看,我通过在未来n毫秒内推进游戏状态,在客户端获得“猜测”所需的部分内容,即实际状态(服务器看到的)。

问题在于确定进展状态的时间量,因为它取决于服务器和客户端之间的滞后时间,这可能会有很大差异。此外,我应该将游戏状态推进到客户端查看它时当前的状态(即只考虑更新到达客户端所花费的时间),还是应该将其推进得足够远以便在发送响应时回到服务器,那时它将是正确的状态(来往于旅程的帐户)。

有什么建议吗?

重申:

1)计算发送和接收之间的时间量的最佳方法是什么?

2)我是否应该将客户端状态推进到足以计入整个往返时间,或者只是将数据从服务器提供给客户端所需的时间?

编辑:到目前为止我提出了什么

由于我已经有许多数据包在客户端和服务器之间来回传递,我不想在必要时添加到该流量。目前,客户端向服务器发送状态更新数据包(UDP)〜150毫秒(仅在某些内容发生变化时),然后由服务器接收和处理这些数据包。目前,服务器不会对这些数据包发送任何响应。

首先,我会让客户尝试估算他们的延迟时间。我将它默认为50至100毫秒。我建议大约每2秒(每个客户端)服务器将立即响应其中一个数据包,在特殊的定时更新数据包中发回数据包索引。如果客户端收到定时数据包,它将使用索引来计算此数据包发送的时间,然后使用数据包之间的时间作为新的延迟时间。

这应该让客户合理地保持最新的延迟,同时避免过多的网络流量。

声音可以接受,还是有更好的方法?这仍然没有回答问题二。

3 个答案:

答案 0 :(得分:4)

首先,就像一个FYI一样,如果你担心延迟不到1秒,你就会开始摆脱MMO的现实滞后现象。所有大型MMO处理这个的方式是基本上同时有两个不同的“游戏” - 有一个基础游戏引擎处理所有的数学,字符状态,应用数值变化,然后有图形客户端。

第一个“游戏”,数学和计算,在概念上更接近传统的控制台游戏(如旧的MUD)。考虑来回传递的消息,具有非常高的ACID隔离度。这些消息更多地关注准确性,但您应该假设这些消息可能需要1-2秒(或更长时间)来处理和更新。这是“规则律师”,确保正确计算生命值等等。

第二个“游戏”是图形客户端。这个客户真正专注于保持事情发生的错觉比第一个游戏快得多,但同时也将同步事件与图形外观同步。这个图形客户端通常只是扁平化而不是关键。该客户端负责30 fps +图形。这就是为什么很多这些图形客户端都会使用诸如在用户按下按钮时启动攻击动画这样的技巧,但在第一个游戏解决攻击之前不会实际解析动画。

我知道这与你的问题的字面解释有点不同,但是一旦你到外面,两台机器在网络上相互坐在一起100ms是非常乐观的......

答案 1 :(得分:2)

  

2)我是否应该将客户端状态推进到足以计入整个往返时间,或者只是将数据从服务器提供给客户端所需的时间?

假设服务器在时间T0发送状态,客户端在时间T1看到它,玩家在时间T2做出反应,服务器在时间T3获得他们的答案,并立即处理它。 这里,往返延迟是T1-T0 + T3-T2。在理想世界中,T0 = T1且T2 = T3, 并且观察时间和玩家行动处理之间的唯一延迟是玩家的反应时间,即T2-T1。 在现实世界中,它是T3-T0。 因此,为了模拟理想世界,您需要减去整个往返延迟:

T2-T1 = T3-T0 + (T1-T0 + T3-T2)

这意味着较慢网络上的玩家在快速网络上看到更高级的状态。 然而,这对他们来说没有任何好处,因为它需要更长的时间直到他们的反应得到处理。 当然,如果两个玩家坐在一起并使用不同的速度网络,它可能会变得有趣。 但这是不太可能的情况,不是吗?

整个程序有问题: 你将来推断,这可能导致荒谬的情况。 其中一些,比如潜入墙壁可以很容易地防止,但那些取决于玩家的互动不能。 1

也许你可以把你的想法颠倒过来: 而不是预测,尝试在时间T3 - (T1-T0 + T3-T2)评估玩家的行动。如果您确定以这种方式击中角色,请相应地降低其生命值。 这可能比最初的想法更容易和更现实,或者可能更糟或根本不适用。只是一个想法。


1 想象一下,两名球员互相对抗。 根据推断,它们在右侧相互传递。 实际上,其中一个改变了方向,最后它们在左侧相互通过。

答案 2 :(得分:2)

解决此类问题的一种方法是在客户端服务器上运行游戏模拟。

因此,不是仅仅在服务器上模拟世界,而是在客户端上进行。只需将客户端所做的事情(例如“玩家击中怪物”)发送到服务器即可。服务器运行相同的模拟并检查事件。

如果它们不匹配(玩家作弊,滞后),它会向客户端发送否决权,并且该操作在服务器上未记录为成功。这意味着所有其他客户端都没有注意到它(服务器不会将操作转发给其他客户端)。

这应该是处理滞后的一种非常有效的方法,特别是如果你有很多PvM战斗(而不是PvP):由于怪物是一个模拟,如果两者之间有很长的滞后并不重要。客户端和服务器。

那说:大多数网络都是如此之快,以至于延迟应该在几毫秒的范围内。这意味着你“只是”必须让服务器足够快,以便它可以响应,比方说,< 100ms,玩家将不会注意到。