https://gafferongames.com/post/what_every_programmer_needs_to_know_about_game_networking/
Have you ever wondered how multiplayer games work?
From the outside it seems magical: two or more players sharing a consistent experience(一致的体验) across the network like they actually exist together in the same virtual world.
But as programmers we know the truth of what is actually going on underneath is quite different from what you see.
It turns out it’s all an illusion . A massive sleight-of-hand (一个大戏法).
What you perceive as a shared reality is only an approximation unique to your own point of view and place in time. (你所感受到的真实感,只是在你这个客户端的“独特的”近似表达)
Peer-to-Peer Lockstep
In the beginning games were networked peer-to-peer, with each each computer exchanging information with each other in a fully connected mesh topology(网络拓扑). You can still see this model alive today in RTS games, and interestingly for some reason, perhaps because it was the first way - it’s still how most people think that game networking works.一开始,游戏网络是p2p方式,每个游戏端都是相互链接的网络拓扑结构。你仍然可以在当今的RTS游戏中看到这种模式。有趣的是,也许这是第一种网络方式,现在很多人认为游戏网络就是这样工作的。
The basic idea is to abstract the game into a series of turns and a set of command messages when processed at the beginning of each turn direct the evolution of the game state. For example: move unit, attack unit, construct building. All that is needed to network this is to run exactly the same set of commands and turns on each player’s machine starting from a common initial state.
基本思路是:将游戏抽象成一系列的回合,并且在每回合开始的时候处理一组指令消息,这组指令消息会在每个客户端推进游戏状态。
比如移动单位、攻击单位、建造建筑。要实现网络联机,只需从一个共同的初始状态开始,在每个玩家的机器上运行完全相同的命令和回合。
Of course this is an overly simplistic explanation and glosses over many subtle points, but it gets across the basic idea of how networking for RTS games work. You can read more about this networking model here: 1500 Archers on a 28.8: Network Programming in Age of Empires and Beyond.
当然,这是一种过于简单的解释,并掩盖了许多微妙之处,但它却传达了RTS游戏网络运作的基本理念。
It seems so simple and elegant, but unfortunately there are several limitations.
它看起来简单优雅,但不幸的是有一些限制。
First, it’s exceptionally difficult to ensure that a game is completely deterministic; that each turn plays out identically on each machine. For example, one unit could take slightly a different path on two machines, arriving sooner to a battle and saving the day on one machine, while arriving later on the other and erm. not saving the day. Like a butterfly flapping it’s wings and causing a hurricane on the other side of the world, one tiny difference results in complete desynchronization over time.
首先,我们很难确保游戏是完全确定的;每个回合在每台机器上的表现都是一样的。例如,同一个单位在两台机器上可能会选择略微不同的路径,一台机器上可能会更早到达战场并挽救局面,而在另一台机器上则可能晚到并且无法挽救局面。就像一只蝴蝶扇动翅膀可能在世界另一端引起飓风一样,一个微小的差异最终会导致随着时间的推移完全失去同步。"
The next limitation is that in order to ensure that the game plays out identically on all machines it is necessary to wait until all player’s commands for that turn are received before simulating that turn. This means that each player in the game has latency equal to the most lagged player. RTS games typically hide this by providing audio feedback immediately and/or playing cosmetic animation, but ultimately any truly game affecting action may occur only after this delay has passed.
下一个限制是,为了确保游戏在所有机器上以完全相同的方式运行,需要等待所有玩家该回合的指令都被接收到后,才能模拟该回合的进程。这意味着游戏中每位玩家的延迟将等于延迟最大的那位玩家。即时战略游戏(RTS)通常通过立即提供音效反馈和/或播放装饰性的动画来掩盖这一问题,但最终,任何真正影响游戏的行动只能在这一延迟过去之后才能生效。
The final limitation occurs because of the way the game synchronizes by sending just the command messages which change the state. In order for this to work it is necessary for all players to start from the same initial state. Typically this means that each player must join up in a lobby before commencing play, although it is technically possible to support late join, this is not common due to the difficulty of capturing and transmitting a completely deterministic starting point in the middle of a live game.
最后一个限制源于游戏通过仅发送改变状态的指令消息来实现同步的方式。为了让这种方法奏效,所有玩家必须从相同的初始状态开始。通常情况下,这意味着每位玩家在游戏开始之前必须先进入同一个大厅。尽管从技术上讲支持玩家在游戏中途加入是可能的,但由于在实时游戏中捕获并传输一个完全确定性的起始点非常困难,这种功能并不常见。
Despite these limitations this model naturally suits RTS games and it still lives on today in games like “Command and Conquer”, “Age of Empires” and “Starcraft”. The reason being that in RTS games the game state consists of many thousands of units and is simply too large to exchange between players. These games have no choice but to exchange the commands which drive the evolution of the game state.
But for other genres, the state of the art has moved on. So that’s it for the deterministic peer-to-peer lockstep networking model. Now lets look at the evolution of action games starting with Doom, Quake and Unreal.
尽管存在这些限制,这种模式仍然非常适合即时战略(RTS)游戏,并且在《命令与征服》《帝国时代》和《星际争霸》等游戏中依然得以延续。原因在于,在RTS游戏中,游戏状态由成千上万个单位组成,数据量过于庞大,无法在玩家之间直接交换。这些游戏别无选择,只能交换驱动游戏状态演变的指令。
但对于其他游戏类型,技术的前沿已经不断发展。因此,关于确定性的点对点锁步网络模型的讨论到此为止。接下来,让我们看看动作游戏的演变,从《毁灭战士》《雷神之锤》和《虚幻》开始。
Client/Server
In the era of action games, the limitations of peer-to-peer lockstep became apparent in Doom, which despite playing well over the LAN played terribly over the internet for typical users:
Although it is possible to connect two DOOM machines together across the Internet using a modem link, the resulting game will be slow, ranging from the unplayable (e.g. a 14.4Kbps PPP connection) to the marginally playable (e.g. a 28.8Kbps modem running a Compressed SLIP driver). Since these sorts of connections are of only marginal utility, this document will focus only on direct net connections.
在动作游戏的时代,peer-to-peer lockstep 模型的局限性在《毁灭战士》中变得显而易见。尽管它在局域网(LAN)环境下运行良好,但对于普通用户而言,通过互联网的游戏体验却非常糟糕:
尽管可以通过调制解调器连接两台运行《毁灭战士》的机器以实现跨互联网的对战,但游戏的运行速度会非常慢,从完全无法游玩(例如使用14.4Kbps的PPP连接)到勉强可玩(例如使用运行压缩SLIP驱动的28.8Kbps调制解调器)不等。由于此类连接的实用性非常有限,本文件将仅专注于直接网络连接。
The problem of course was that Doom was designed for networking over LAN only, and used the peer-to-peer lockstep model described previously for RTS games. Each turn player inputs (key presses etc.) were exchanged with other peers, and before any player could simulate a frame all other player’s key presses needed to be received.
问题在于,《毁灭战士》仅设计用于局域网(LAN)环境下的联网,并采用了之前描述的适用于RTS游戏的点对点锁步模型。每回合,玩家的输入(例如按键等)会与其他玩家进行交换,而在任何玩家能够模拟一个帧之前,都必须接收到所有其他玩家的按键输入。
In other words, before you could turn, move or shoot you had to wait for the inputs from the most lagged modem player. Just imagine the wailing and gnashing of teeth that this would have resulted in for the sort of folks with internet connections that were “of only marginal utility”. :)
换句话说,在你能够转身、移动或射击之前,必须等待来自延迟最大的调制解调器玩家的输入。试想一下,这对那些使用“勉强实用”的互联网连接的玩家来说,会带来多少哀嚎和咬牙切齿的场面吧。:)
In order to move beyond the LAN and the well connected elite at university networks and large companies, it was necessary to change the model. And in 1996, that’s exactly what John Carmack and his team did when he released Quake using client/server instead of peer-to-peer.
在1996年,约翰·卡马克(John Carmack)和他的团队正是这么做的。他们在发布《雷神之锤》(Quake)时,采用了客户端/服务器(client/server)模型,取代了点对点(peer-to-peer)模型。
Now instead of each player running the same game code and communicating directly with each other, each player was now a “client” and they all communicated with just one computer called the “server”. There was no longer any need for the game to be deterministic across all machines, because the game really only existed on the server. Each client effectively acted as a dumb terminal showing an approximation of the game as it played out on the server.
现在,每位玩家不再运行相同的游戏代码并直接相互通信,而是变成了“客户端”,他们都只与一台被称为“服务器”的计算机通信。游戏不再需要在所有机器上保持确定性,因为游戏实际上只存在于服务器上。每个客户端实际上相当于一个dumb terminal ,展示出服务器上游戏运行时的近似画面。
In a pure client/server model you run no game code locally, instead sending your inputs such as key presses, mouse movement, clicks to the server. In response the server updates the state of your character in the world and replies with a packet containing the state of your character and other players near you. All the client has to do is interpolate between these updates to provide the illusion of smooth movement and BAM you have a networked game.
在c/s模型中,您本地不运行任何游戏代码,而是将按键、鼠标移动、点击等输入发送到服务器。服务器根据这些输入更新您在游戏世界中的角色状态,并回复一个数据包,其中包含您角色的状态以及您附近其他玩家的状态。客户端所需做的只是在这些更新之间进行插值,以提供平滑运动的假象,这样,一个联网游戏就诞生了。
This was a great step forward. The quality of the game experience now depended on the connection between the client and the server instead of the most lagged peer in the game. It also became possible for players to come and go in the middle of the game, and the number of players increased as client/server reduced the bandwidth required on average per-player.
这是一次巨大的进步。游戏体验的质量现在取决于客户端与服务器之间的连接,而不是游戏中延迟最大的玩家。此外,玩家可以在游戏进行中随时加入或退出,且由于客户端/服务器模型平均每位玩家所需的带宽减少,玩家数量也得以增加。
But there were still problems with the pure client/server model:
While I can remember and justify all of my decisions about networking from DOOM through Quake, the bottom line is that I was working with the wrong basic assumptions for doing a good internet game. My original design was targeted at < 200ms connection latencies. People that have a digital connection to the internet through a good provider get a pretty good game experience. Unfortunately, 99% of the world gets on with a slip or ppp connection over a modem, often through a crappy overcrowded ISP. This gives 300+ ms latencies, minimum. Client. User's modem. ISP's modem. Server. ISP's modem. User's modem. Client. God, that sucks.Ok, I made a bad call. I have a T1 to my house, so I just wasn't familliar with PPP life. I'm addressing it now.
John Carmack:
虽然我记得并能解释我在《毁灭战士》(DOOM)到《雷神之锤》(Quake)之间关于联网的所有设计决策,但归根结底,我在设计优秀的互联网游戏时基于了一些错误的基本假设。我的初始设计是针对延迟小于200毫秒的连接优化的。那些通过优质供应商以数字连接方式接入互联网的用户能获得相当不错的游戏体验。然而,不幸的是,世界上99%的人是通过调制解调器使用SLIP或PPP连接接入互联网的,通常还得通过一个劣质且过于拥挤的ISP。这种情况下的延迟至少是300毫秒以上。流程是:客户端、用户的调制解调器、ISP的调制解调器、服务器、ISP的调制解调器、用户的调制解调器、客户端。天哪,这太糟糕了。
好吧,我做了一个糟糕的决定。我家里有一条T1线路,所以我根本不了解PPP用户的生活。现在,我正在解决这个问题。
The problem was of course latency.
What happened next would change the industry forever. 接下来的事情将永远改变整个行业。
Client-Side Prediction
In the original Quake you felt the latency between your computer and the server. Press forward and you’d wait however long it took for packets to travel to the server and back to you before you’d actually start moving. Press fire and you wait for that same delay before shooting. If you’ve played any modern FPS like Call of Duty: Modern Warfare, you know this is no longer what happens. So how exactly do modern FPS games remove the latency on your own actions in multiplayer?
在原版《雷神之锤》(Quake)中,你能明显感受到你电脑与服务器之间的延迟。按下“前进”键后,你需要等待数据包往返服务器所需的时间,然后角色才会真正开始移动。按下“开火”键后,你同样需要经历同样的延迟,才能真正射击。
如果你玩过任何现代FPS游戏,比如《使命召唤:现代战争》,你会知道这种延迟已经不再存在。那么,现代FPS游戏是如何在多人模式中消除自己动作的延迟的呢?
When writing about his plans for the soon to be released QuakeWorld, John Carmack said:
I am now allowing the client to guess at the results of the users movement until the authoritative response from the server comes through. This is a biiiig architectural change. The client now needs to know about solidity of objects, friction, gravity, etc. I am sad to see the elegant client-as-terminal setup go away, but I am practical above idealistic.
到他对即将发布的 QuakeWorld 的计划时,约翰·卡马克(John Carmack)写道:
So now in order to remove the latency, the client runs more code than it previously did. It is no longer a dumb terminal sending inputs to the server and interpolating between state sent back. Instead it is able to predict the movement of your character locally and immediately in response to your input, running a subset of the game code for your player character on the client machine.我现在允许客户端在等待服务器的权威响应到来之前,猜测用户动作的结果。这是一个非常大的架构变更。客户端现在需要了解物体的固体特性、摩擦力、重力等。我很遗憾看到优雅的“客户端作为终端”的设置被舍弃,但相比于理想主义,我更倾向于务实主义。
因此,为了消除延迟,客户端现在需要运行比以前更多的代码。它不再是一个仅向服务器发送输入并在接收到的状态之间插值的dumb terminal。相反,它能够在本地预测你的角色移动,并即时响应你的输入,在客户端机器上为玩家角色运行游戏代码的一个子集。
Now as soon as you press forward, there is no wait for a round trip between client and server - your character start moving forward right away.
现在,当你按下“前进”键时,不再需要等待客户端和服务器之间的往返延迟——你的角色会立即开始向前移动。
The difficulty of this approach is not in the prediction, for the prediction works just as normal game code does - evolving the state of the game character forward in time according to the player’s input. The difficulty is in applying the correction back from the server to resolve cases when the client and server disagree about where the player character should be and what it is doing.
这种方法的难点不在于预测,因为预测的工作方式与普通的游戏代码类似——根据玩家的输入,推进游戏角色的状态随时间向前演变。真正的难点在于如何应用服务器返回的修正数据,以解决客户端和服务器在玩家角色的位置以及其行为上的分歧。
Now at this point you might wonder. Hey, if you are running code on the client - why not just make the client authoritative over their player character? The client could run the simulation code for their own character and simply tell the server where they are each time they send a packet. The problem with this is that if each player were able to simply tell the server “here is my current position” it would be trivially easy to hack the client such that a cheater could instantly dodge the RPG about to hit them, or teleport instantly behind you to shoot you in the back.
到了这里,你可能会想:“嘿,如果客户端已经在运行代码,为什么不让客户端对自己的角色具有权威性呢?” 客户端可以运行自己的角色模拟代码,并在每次发送数据包时简单地告诉服务器它当前的位置。
问题在于,如果每个玩家都能够简单地告诉服务器“这是我的当前位置”,那么修改客户端进行作弊将变得非常容易。比如,作弊者可以瞬间躲开即将命中的火箭弹,或者瞬间传送到你身后射击你。
So in FPS games it is absolutely necessary that the server is the authoritative over the state of each player character, in-spite of the fact that each player is locally predicting the motion of their own character to hide latency. As Tim Sweeney writes in The Unreal Networking Architecture: “The Server Is The Man”.
因此,在FPS游戏中,服务器对每个玩家角色的状态必须具有绝对的权威性,即使每个玩家都在本地预测自己角色的运动以隐藏延迟。正如蒂姆·斯威尼(Tim Sweeney)在《虚幻网络架构》中所写的那样:“服务器才是老大”(“The Server Is The Man”)。
Here is where it gets interesting. If the client and the server disagree, the client must accept the update for the position from the server, but due to latency between the client and server this correction is necessarily in the past. For example, if it takes 100ms from client to server and 100ms back, then any server correction for the player character position will appear to be 200ms in the past, relative to the time up to which the client has predicted their own movement.
这就是事情变得有趣的地方。如果客户端和服务器的状态不同步,客户端必须接受服务器发送的角色位置更新。然而,由于客户端和服务器之间存在延迟,这种修正必然是针对过去的状态。例如,如果从客户端到服务器需要100毫秒,再从服务器返回需要100毫秒,那么任何服务器对玩家角色位置的修正,相对于客户端已经预测的时间线来看,都显得滞后了200毫秒。
If the client were to simply apply this server correction update verbatim, it would yank the client back in time, completely undoing any client-side prediction. How then to solve this while still allowing the client to predict ahead?
如果客户端只是简单地照搬服务器的修正更新,直接应用到当前状态,这将把客户端的角色状态强制拉回到过去,完全推翻任何客户端预测。那么,如何在允许客户端继续预测的同时解决这个问题呢?
The solution is to keep a circular buffer of past character state and input for the local player on the client, then when the client receives a correction from the server,
it first discards any buffered state older than the corrected state from the server,
and replays the state starting from the corrected state back to the present “predicted” time on the client using player inputs stored in the circular buffer.
In effect the client invisibly “rewinds and replays” the last n frames of local player character movement while holding the rest of the world fixed.
解决方法是客户端为本地玩家角色的状态和输入维护一个循环缓冲区(circular buffer)。当客户端从服务器接收到修正数据时,它会采取以下步骤:
-
1.丢弃旧状态:客户端首先丢弃循环缓冲区中比服务器修正状态更旧的所有记录。
-
2.回放重演:从服务器提供的修正状态开始,客户端使用循环缓冲区中存储的玩家输入,重新计算角色的状态,逐帧回放直到恢复到当前的“预测”时间。
通过这种方式,客户端实际上是无形中“回放并重演”了最近 n 帧的玩家角色运动,而同时保持游戏世界的其余部分固定不变。
这一过程解决了修正延迟的问题,同时保留了客户端预测的平滑体验,从而让玩家几乎察觉不到延迟所带来的影响。
This way the player appears to control their own character without any latency, and provided that the client and server character simulation code is reasonable, giving roughly exactly the same result for the same inputs on the client and server, it is rarely corrected. It is as Tim Sweeney describes:
... the best of both worlds: In all cases, the server remains completely authoritative. Nearly all the time, the client movement simulation exactly mirrors the client movement carried out by the server, so the client's position is seldom corrected. Only in the rare case, such as a player getting hit by a rocket, or bumping into an enemy, will the client's location need to be corrected.
通过这种方式,玩家看起来能够即时控制自己的角色而没有任何延迟。而只要客户端和服务器的角色模拟代码设计合理,对于相同的输入能在客户端和服务器上产生几乎完全一致的结果,就很少需要进行修正。正如蒂姆·斯威尼(Tim Sweeney)所描述的那样:
这是一种两全其美的设计:在所有情况下,服务器始终保持完全的权威性。几乎所有时候,客户端的运动模拟与服务器执行的客户端运动完全一致,因此客户端的位置很少需要修正。只有在少数情况下,例如玩家被火箭击中或撞到敌人时,客户端的位置才需要进行修正。
“客户端预测+服务器权威模式”是一个精心设计的平衡:客户端提供即时反馈以实现流畅的用户体验,而服务器确保了游戏的公平性和同步性。
In other words, only when the player’s character is affected by something external to the local player’s input, which cannot possibly be predicted on the client, will the player’s position need to be corrected. That and of course, if the player is attempting to cheat :)
换句话说,只有当玩家的角色受到本地玩家输入之外的外部因素影响时,而这些影响无法在客户端进行预测,才需要对玩家的位置进行修正。当然,还有一种情况是,玩家试图作弊时也会触发修正标签:Needs,Networking,游戏,server,player,client,玩家,客户端 From: https://www.cnblogs.com/sun-shadow/p/18673818