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

2022-01-22 00:00:00 client-server synchronization udp java

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

I am making a client server MMO style game. So far I have the framework set up so that the server and clients interact with each other in order to provide state updates. The server maintains the game state and periodically calculates the next state and then it every once in a while (every n milliseconds) it sends out the new state to all the clients. This new state is able to be viewed and reacted to on the client side by the user. These actions are then sent back to the server to be processed and sent out for the next update.

明显的问题是这些更新在服务器和客户端之间传输需要时间.如果客户端采取行动攻击敌人,则在更新返回服务器时,服务器很可能已经将游戏状态推进到足够远,以至于敌人不再在同一地点,并且超出范围.

The obvious problem is that it takes time for these updates to travel between server and clients. If a client acts to attack an enemy, by the time that update has gotten back to the server, it's very possible the server has progressed the game state far enough that the enemy is no longer in the same spot, and out of range.

为了解决这个问题,我一直在努力想出一个好的解决方案.我看过以下内容,它对一些人有所帮助,但并不完全:多人游戏同步.我已经得出结论,除了传输游戏的当前状态之外,我还可以传输其他信息,例如方向(或 AI 移动的目标位置)和速度.由此,我有一部分需要在客户端通过将游戏状态推进到未来 n 毫秒来猜测"实际状态(如服务器所见).

In order to combat this problem, I have been trying to come up with a good solution. I have looked at the follow, and it has helped some, but not completely: Mutli Player Game synchronization. I already came to the conclusion that instead of just transmitting the current state of the game, I can transmit other information such as direction (or target position for AI movement) and speed. From this, I have part of what is needed to 'guess', on the client side, what the actual state is (as the server sees it) by progressing the game state n milliseconds into the future.

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

The problem is determining the amount of time to progress the state, because it will depend on the lag time between server and client, which could vary considerably. Also, should I progress the game state to what it would currently be when the client views it (i.e. only account for the time it took the update to get to the client) or should I progress it far enough so that when its response is sent back to the server, it will be the correct state by then (account for both to and from journey).

有什么建议吗?

重申:

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

1) What is the best way to calculate the amount of time between send and receive?

2) 我应该将客户端状态推进到足以计算整个往返行程的程度,还是仅计算从服务器获取数据到客户端所需的时间?

2) Should I progress the client side state far enough to count for the entire round trip, or just the time it takes to get the data from the server to the client?

到目前为止我的想法

由于我已经有很多数据包在客户端和服务器之间来回传输,因此我不想在必要时增加该流量.目前,客户端向服务器发送状态更新数据包(UDP)约 150 毫秒(仅在发生变化时),然后由服务器接收和处理.目前,服务器对这些数据包没有响应.

Since I already have many packets going back and forth between the clients and server, I do not want to add to that traffic if I have to. Currently, the clients send status update packets (UDP) to the server ~150 milliseconds (only if something has changed), and then these are receive and processed by the server. Currently, the server sends no response to these packets.

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

To start off, I will have the clients attempt to estimate their lag time. I will default it to something like 50 to 100 milliseconds. I am proposing that about every 2 seconds (per client) the server will immediately respond to one of these packets, sending back the packet index in a special timing update packet. If the client receives the timing packet, it will use the index to calculate how long ago this packet was sent, and then use the time between packets as the new lag time.

这应该让客户端在他们的延迟上保持合理的最新状态,而不会出现过多的网络流量.

This should keep the clients reasonably up to date on their lag, with out too much excess network traffic.

听起来可以接受,还是有更好的方法?这仍然没有回答问题二.

Sound acceptable, or is there a better way? This still doesn't answer question two.

推荐答案

2) 我应该将客户端状态推进到足以计算整个往返行程的程度,还是仅计算从服务器获取数据到客户端所需的时间?

2) Should I progress the client side state far enough to count for the entire round trip, or just the time it takes to get the data from the server to the client?

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

Let's assume that the server sends the state at time T0, the client sees it in time T1, the player reacts in time T2, and the server obtains their answer in time T3, and processes it instantly. Here, the round trip delay is T1-T0 + T3-T2. In an ideal world, T0=T1 and T2=T3, and the only delay between the observing time and the processing of the player's action is the player's reaction time, i.e., T2-T1. In the real world it's T3-T0. So in order to simulate the ideal world you need to subtract the whole round trip delay:

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

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

This means that a player on a slower network sees more advanced state the a player on a fast network. However, this is no advantage for them, since it takes longer till their reaction gets processed. Of course, it could get funny in case of two players sitting next to each other and using different speed networks. But this is quite improbable scenario, isn't it?

整个过程有问题:您在未来进行推断,这可能会导致荒谬的情况.其中一些,比如潜入墙壁很容易被阻止,但那些取决于玩家互动的则不能.1

There's a problem with the whole procedure: You're extrapolating in the future and this may lead to nonsensical situations. Some of them, like diving into walls can be easily prevented, but those depending on player's interaction can not.1

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

Maybe you could turn your idea upside down: Instead of forecasting, try to evaluate player's action at the time T3 - (T1-T0 + T3-T2). If you determine that a character would be hit this way, reduce its hit points accordingly. This may be easier and more realistic then the original idea, or it may be worse, or not applicable at all. Just an idea.

1 想象一下两个玩家互相竞争.根据推断,它们在右侧相互通过.事实上,他们中的一个改变了他们的方向,最后他们在左侧相互通过.

1 Imagine two players running against each other. According to the extrapolating they pass each other on the right side. In fact, one of them changes their direction, and at the end they passes each other on the left side.

相关文章