(翻译 ) Source Multiplayer Networking Source引擎的多人网路系统

https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking

 

Multiplayer games based on the Source Source use a Client-Server networking architecture. Usually a server is a dedicated host that runs the game and is authoritative about world simulation, game rules, and player input processing. A client is a player's computer connected to a game server. The client and server communicate with each other by sending small data packets at a high frequency (usually 20 to 30 packets per second). A client receives the current world state from the server and generates video and audio output based on these updates. The client also samples data from input devices (keyboard, mouse, microphone, etc.) and sends these input samples back to the server for further processing. Clients only communicate with the game server and not between each other (like in a peer-to-peer application). In contrast with a single player game, a multiplayer game has to deal with a variety of new problems caused by packet-based communication.

Network bandwidth is limited, so the server can't send a new update packet to all clients for every single world change. Instead, the server takes snapshots of the current world state at a constant rate and broadcasts these snapshots to the clients. Network packets take a certain amount of time to travel between the client and the server (i.e. half the ping time). This means that the client time is always a little bit behind the server time. Furthermore, client input packets are also delayed on their way back, so the server is processing temporally delayed user commands. In addition, each client has a different network delay which varies over time due to other background traffic and the client's framerate. These time differences between server and client causes logical problems, becoming worse with increasing network latencies. In fast-paced action games, even a delay of a few milliseconds can cause a laggy gameplay feeling and make it hard to hit other players or interact with moving objects. Besides bandwidth limitations and network latencies, information can get lost due to network packet loss.

基于 Source 引擎的多人游戏使用客户端-服务器的网络架构。通常,服务器是一个运行游戏的专用主机,对世界模拟、游戏规则以及玩家输入处理具有权威性。客户端是连接到游戏服务器的玩家计算机。客户端与服务器通过高频率(通常每秒 20 到 30 个数据包)发送小型数据包进行通信。客户端从服务器接收当前的世界状态,并基于这些更新生成视频和音频输出。客户端还会从输入设备(键盘、鼠标、麦克风等)采样数据,并将这些输入样本发送回服务器进行进一步处理。

客户端只与游戏服务器通信,而不会像点对点应用那样彼此通信。相比单人游戏,多人游戏必须应对由于基于数据包的通信所引发的各种新问题。

网络带宽是有限的,因此服务器无法为每一个世界变化向所有客户端发送新的更新数据包。取而代之的是,服务器以固定速率对当前世界状态进行快照,并将这些快照广播给所有客户端。网络数据包在客户端与服务器之间传输需要一定时间(即一半的 ping 时间)。这意味着客户端时间总是略微滞后于服务器时间。此外,客户端的输入数据包在返回途中也会有延迟,因此服务器处理的是有时间延迟的用户指令。每个客户端的网络延迟也不同,并且会因后台流量和客户端帧率的变化而波动。这些服务器与客户端之间的时间差会造成逻辑问题,并且在网络延迟增加的情况下问题会加剧。

在快节奏的动作游戏中,即便只有几毫秒的延迟也会让游戏感觉卡顿,导致玩家难以命中其他玩家或与移动物体互动。除了带宽限制和网络延迟外,信息还可能因为网络数据包丢失而丢失。

 To cope with the issues introduced by network communication, the Source engine server employs techniques such as data compression and lag compensation which are invisible to the client. The client then performs prediction and interpolation to further improve the experience.

Note:If you follow a player in "First-Person" as a spectator in a game or SourceTV, you don't exactly see what the player sees. Spectators see the game world without lag compensation.

为了应对网络通信带来的问题,Source 引擎的服务器采用了诸如数据压缩和延迟补偿等技术,这些对于客户端来说是不可见的。客户端随后会执行预测和插值操作,以进一步改善体验。

**注意:**如果你在游戏中或在 SourceTV 中以“第一人称”视角观战某位玩家,你看到的并不完全是该玩家所看到的内容。观众看到的游戏世界并没有经过延迟补偿。

Basic networking

The server simulates the game in discrete time steps called ticks. By default, the timestep is 15ms, so 66.666... ticks per second are simulated, but mods can specify their own tickrate. During each tick, the server processes incoming user commands, runs a physical simulation step, checks the game rules, and updates all object states. After simulating a tick, the server decides if any client needs a world update and takes a snapshot of the current world state if necessary. A higher tickrate increases the simulation precision, but also requires more CPU power and available bandwidth on both server and client. The server admin may override the default tickrate with the -tickrate command line parameter, though tickrate changes done this way are not recommended because the mod may not work as designed if its tickrate is changed.

服务器以离散时间步(称为“tick”)来模拟游戏。默认情况下,每个 tick 为 15 毫秒,因此每秒模拟约 66.666... 个 tick,但模组可以指定自己的 tickrate(tick 速率)。在每个 tick 中,服务器会处理收到的用户指令,运行一次物理模拟,检查游戏规则,并更新所有对象的状态。在模拟完一个 tick 后,服务器会决定是否需要向客户端发送世界更新,并在需要时对当前的世界状态进行快照。较高的 tickrate 会提高模拟精度,但也会增加服务器和客户端的 CPU 占用和带宽需求

服务器管理员可以通过命令行参数 -tickrate 来覆盖默认 tickrate,不过不推荐这种方式更改 tickrate,因为某些模组在不同 tickrate 下可能无法正常运行。

Note.pngNote:The -tickrate command line parameter is not available newer version of CS:S, DoD:S, TF2, L4D and L4D2, and was disabled in code likely because changing tickrate may cause causes server timing issues for certain games.
The tickrate is set to 66 in CSS, DoD S and TF2. 60 in CS 1.6 and HL1, and 30 in L4D, L4D2 and TFC.

注意:
-tickrate 命令行参数在新版的 CS:S、DoD:S、TF2、L4D 和 L4D2 中已不可用,并可能在代码层面被禁用,因为更改 tickrate 可能会引发某些游戏的服务器时序问题
这些游戏的默认 tickrate 为:

  • CS:S、DoD:S 和 TF2:66

  • CS 1.6 和 HL1:60

  • L4D、L4D2 和 TFC:30


Some older version of those games can have it's tickrate changed, however. Users can also install this server plugins ↓ to restore the disabled -tickrate command line parameter.

Clients usually have only a limited amount of available bandwidth. In the worst case, players with a modem connection can't receive more than 5 to 7 KB/sec. If the server tried to send them updates with a higher data rate, packet loss would be unavoidable. Therefore, the client has to tell the server its incoming bandwidth capacity by setting the console variable rate (in bytes/second). This is the most important network variable for clients and it has to be set correctly for an optimal gameplay experience. The client can request a certain snapshot rate by changing cl_updaterate (default 20), but the server will never send more updates than simulated ticks or exceed the requested client rate limit. Server admins can limit data rate values requested by clients with sv_minrate and sv_maxrate (both in bytes/second). Also the snapshot rate can be restricted with sv_minupdaterate and sv_maxupdaterate (both in snapshots/second).

客户端通常只有有限的可用带宽。在最坏情况下,使用调制解调器连接的玩家最多也只能接收 5 到 7 KB/秒。如果服务器试图以更高的数据率向其发送更新,将不可避免地导致数据包丢失。因此,客户端需要通过设置控制台变量 rate(单位为字节/秒)来告知服务器它的接收带宽上限。这是客户端最重要的网络变量,必须正确设置才能获得最佳游戏体验

客户端可以通过更改 cl_updaterate(默认值为 20)来请求特定的快照更新频率,但服务器不会发送超过 Tick 率或超出客户端请求限制的更新包服务器管理员可以通过 sv_minratesv_maxrate(单位同样为字节/秒)来限制客户端所请求的数据率范围;也可以通过 sv_minupdateratesv_maxupdaterate(单位为快照/秒)来限制快照发送速率。

The client creates user commands from sampling input devices with the same tick rate that the server is running with. A user command is basically a snapshot of the current keyboard and mouse state. But instead of sending a new packet to the server for each user command, the client sends command packets at a certain rate of packets per second (usually 30). This means two or more user commands are transmitted within the same packet. Clients can increase the command rate with cl_cmdrate. This will increase responsiveness but requires more outgoing bandwidth, too.

客户端会以与服务器相同的 Tick 率对输入设备(键盘、鼠标等)进行采样,从而创建用户指令(User Commands)。用户指令本质上是当前输入状态的快照但客户端并不会为每条用户指令都发送一个单独的数据包,而是以一定的频率(通常是每秒 30 个数据包)打包发送多个用户指令。也就是说,每个数据包中可能包含两条或更多的用户指令客户端可以通过设置 cl_cmdrate 来增加指令发送频率,这会提升操作响应性,但同时也会增加上行带宽需求

Game data is compressed using delta compression to reduce network load. That means the server doesn't send a full world snapshot each time, but rather only changes (a delta snapshot) that happened since the last acknowledged update. With each packet sent between the client and server, acknowledge numbers are attached to keep track of their data flow. Usually full (non-delta) snapshots are only sent when a game starts or a client suffers from heavy packet loss for a couple of seconds. Clients can request a full snapshot manually with the cl_fullupdate command.

为了减轻网络负担,游戏数据使用了差异压缩(Delta Compression)。也就是说,服务器并不会每次都发送完整的世界快照,而是只发送自上一次客户端确认以来发生的变化(即差异快照)。每个客户端与服务器之间交换的数据包都会附带确认号,以便双方跟踪数据流。通常,只有在游戏开始或客户端出现严重的数据包丢失时,服务器才会发送完整快照。客户端也可以通过命令 cl_fullupdate 手动请求一次完整快照。

Responsiveness, or the time between user input and its visible feedback in the game world, are determined by lots of factors, including the server/client CPU load, simulation tickrate, data rate and snapshot update settings, but mostly by the network packet traveling time. The time between the client sending a user command, the server responding to it, and the client receiving the server's response is called the latency or ping (or round trip time). Low latency is a significant advantage when playing a multiplayer online game. Techniques like prediction and lag compensation try to minimize that advantage and allow a fair game for players with slower connections. Tweaking networking setting can help to gain a better experience if the necessary bandwidth and CPU power is available. We recommend keeping the default settings, since improper changes may cause more negative side effects than actual benefits.

响应速度,也就是从用户输入到游戏中产生可见反馈之间所经历的时间,由许多因素共同决定,包括服务器和客户端的 CPU 负载、Tick 率、数据速率以及快照更新设置,但最主要的因素是网络数据包的传输时间。客户端发送用户指令 → 服务器响应 → 客户端收到服务器响应的这段时间,称为 延迟(latency)或 ping(即往返时间)

在多人在线游戏中,低延迟是一个显著优势。而像**预测(prediction)和延迟补偿(lag compensation)**这样的技术,正是为了尽量减少这种优势带来的不公平,使连接速度较慢的玩家也能享有公平的游戏体验。

如果带宽和 CPU 性能足够,通过调节网络设置可以获得更好的体验。但我们建议使用默认设置,因为不当的更改可能会带来比收益更大的负面效果。

 

Servers for these games that support altering Tickrate  支持修改 Tickrate 的游戏服务器

 

Note.pngNote:Most singleplayer games such as Half-Life 2 Half-Life 2 can have it's tickrate changed.
Clarify: what about Counter-Strike Counter-Strike?, Half-Life Half-Life seems to use 60 or something according to "+graph", it is unknown if this can be altered.
Clarify: How about other Source 2 Source 2.

The tickrate can be altered by using the -tickrate parameter for these games:

Source

By default, without using server plugins ↓, some servers tickrate cannot be altered for these games due to various reasons such as GoldSrc GoldSrc lacking the -tickrate command line parameter, or intentionally disabled in-code by Valve due to "server ops are abusing it" and/or "using -tickrate may cause server timing-related issues":

GoldSrc

60 Tickrate

30 Tickrate

Source

66 Tickrate

30 Tickrate

Source 2

64 Tickrate, with Sub-tick

  • Counter-Strike 2 Counter-Strike 2
    • Note.pngNote:Originally can be changed during Limited Test but later was hardcoded to 64-tick.
 Confirm:Does the -tickrate command (or similar) exists or works with GoldSrc games?
Note.pngNote:In previous versions on some of those games, it can be changed. Alternatively user can also use server plugins ↓.
Note.pngNote:The lowest or highest values depends on the game. Minimum tickrate is 11.

Using server plugins to restore -tickrate for games that have it disabled

Users can install this server plugins to make the -tickrate command works again on games that have it disabled. Note that loading plugins would require -insecure (disabling VAC) for it to work.
All Source games / L4D & L4D2

 

Entity interpolation

Main article: Interpolation

By default, the client receives about 20 snapshot per second. If the objects (entities) in the world were only rendered at the positions received by the server, moving objects and animation would look choppy and jittery. Dropped packets would also cause noticeable glitches. The trick to solve this problem is to go back in time for rendering, so positions and animations can be continuously interpolated between two recently received snapshots. With 20 snapshots per second, a new update arrives about every 50 milliseconds. If the client render time is shifted back by 50 milliseconds, entities can be always interpolated between the last received snapshot and the snapshot before that.

Source defaults to an interpolation period ('lerp') of 100-milliseconds (cl_interp 0.1); this way, even if one snapshot is lost, there are always two valid snapshots to interpolate between. Take a look at the following figure showing the arrival times of incoming world snapshots:

实体插值(Entity Interpolation)

主条目: [插值(Interpolation)]

默认情况下,客户端每秒接收约 20 个世界快照。如果游戏中的物体(实体)仅按照服务器传来的坐标进行渲染,移动物体和动画将会看起来非常卡顿和跳动。此外,如果某个快照丢失,还会导致明显的画面错乱。

解决这个问题的方法是:渲染时“回到过去”,也就是说,将客户端的渲染时间向后偏移,这样就可以在最近接收到的两个快照之间,平滑插值出一个连续的渲染效果

在每秒 20 个快照的情况下,每个更新大约间隔 50 毫秒。如果客户端将渲染时间延后 50 毫秒,那么它就可以始终在“上一个快照”和“上上个快照”之间做插值,从而让移动和动画看起来平滑。

Source 引擎默认使用 100 毫秒的插值周期(lerp),也就是 cl_interp 0.1
这样做的好处是,即使一个快照丢失,仍然有两个有效的快照可以用来插值

下图展示了世界快照到达客户端的时间分布(原文中的图表会进一步说明插值机制):

客户端收到的最后一个快照是在 tick 344,即 10.30 秒。客户端时间会根据这个快照以及客户端的帧率持续递增。如果渲染一个新的视频帧,渲染时间就是当前客户端时间 10.32 减去视图插值延迟 0.1 秒。在本例中,就是 10.22 秒,此时所有实体及其动画都会根据快照 340 和 342 之间的正确插值比例进行插值计算。

由于我们有 100 毫秒的插值延迟,即使因为丢包而错过了快照 342,插值仍然可以正常工作。在这种情况下,会使用快照 340 和 344 进行插值。如果连续丢失多个快照,插值将无法正常工作,因为历史缓冲区中的快照数量不足。此时,渲染器会启用外推(cl_extrapolate 1),并尝试基于目前已知的历史信息对实体进行简单的线性外推。外推仅在最多 0.25 秒的丢包期间进行(由 cl_extrapolate_amount 控制),因为超出这个时间后预测误差会变得过大。

实体插值默认会引入 100 毫秒的固定视角“延迟”(由 cl_interp 0.1 设置),即使你是在本地服务器上游玩(即服务器和客户端在同一台机器上)。但这并不意味着你在射击其他玩家时必须提前瞄准,因为服务器端的延迟补偿机制了解客户端的实体插值,并会纠正这个误差。

p:More recent Source games have the cl_interp_ratio cvar. With this you can easily and safely decrease the interpolation period by setting cl_interp to 0, then increasing the value of cl_updaterate (the useful limit of which depends on server tickrate). You can check your final lerp with net_graph 1.

Note.pngNote:If you turn on sv_showhitboxes (not available in Source 2009) you will see player hitboxes drawn in server time, meaning they are ahead of the rendered player model by the lerp period. This is perfectly normal!

更近版本的 Source 游戏增加了 cl_interp_ratio 控制变量(cvar)。通过这个设置,你可以轻松且安全地减少插值周期,方法是将 cl_interp 设置为 0,然后提高 cl_updaterate 的值(其有效限制取决于服务器的 tickrate)。你可以通过 net_graph 1 来查看最终的插值(lerp)值。

注意:
如果你启用 sv_showhitboxes(在 Source 2009 中不可用),你将看到玩家的 hitbox(碰撞盒)是以服务器时间绘制的,也就是说它们会比渲染的玩家模型提前显示,提前的时间就是插值周期。这是完全正常的!

Input prediction

Main article: Prediction

Lets assume a player has a network latency of 150 milliseconds and starts to move forward. The information that the +FORWARD key is pressed is stored in a user command and send to the server. There the user command is processed by the movement code and the player's character is moved forward in the game world. This world state change is transmitted to all clients with the next snapshot update. So the player would see his own change of movement with a 150 milliseconds delay after he started walking. This delay applies to all players actions like movement, shooting weapons, etc. and becomes worse with higher latencies.

A delay between player input and corresponding visual feedback creates a strange, unnatural feeling and makes it hard to move or aim precisely. Client-side input prediction (cl_predict 1) is a way to remove this delay and let the player's actions feel more instant. Instead of waiting for the server to update your own position, the local client just predicts the results of its own user commands. Therefore, the client runs exactly the same code and rules the server will use to process the user commands. After the prediction is finished, the local player will move instantly to the new location while the server still sees him at the old place.

After 150 milliseconds, the client will receive the server snapshot that contains the changes based on the user command he predicted earlier. Then the client compares the server position with his predicted position. If they are different, a prediction error has occurred. This indicates that the client didn't have the correct information about other entities and the environment when it processed the user command. Then the client has to correct its own position, since the server has final authority over client-side prediction. If cl_showerror 1 is turned on, clients can see when prediction errors happen. Prediction error correction can be quite noticeable and may cause the client's view to jump erratically. By gradually correcting this error over a short amount of time (cl_smoothtime), errors can be smoothly corrected. Prediction error smoothing can be turned off with cl_smooth 0.

Prediction is only possible for the local player and entities affected only by him, since prediction works by using the client's keypresses to make a "best guess" of where the player will end up. Predicting other players would require literally predicting the future with no data, since there's no way to instantaneously get keypresses from them.

输入预测

主条目: [预测(Prediction)]

假设一个玩家的网络延迟是 150 毫秒,并且他开始向前移动。按下 +FORWARD 键的信息会被存储在一个用户命令中,并发送到服务器。在服务器端,用户命令会被移动代码处理,玩家的角色会在游戏世界中向前移动。这个世界状态的变化会通过下一个快照更新传送给所有客户端。因此,玩家会在开始行走后 150 毫秒 延迟看到自己移动的变化。这个延迟适用于所有玩家的操作,如移动、开火等,且随着延迟的增加,延迟问题会变得更严重。

玩家输入和相应视觉反馈之间的延迟会产生一种奇怪、不自然的感觉,使得玩家难以精确地移动或瞄准。客户端输入预测(cl_predict 1)是一种消除这种延迟的方法,让玩家的操作感觉更加即时。客户端不再等待服务器更新自己的位置,而是直接预测自己用户命令的结果。因此,客户端运行的代码和规则与服务器用来处理用户命令的代码完全相同。

预测完成后,玩家会立即移动到新位置,而服务器仍然看到他在原地。

150 毫秒后,客户端会收到服务器的快照,其中包含基于玩家先前预测的用户命令所产生的变化。此时,客户端将比较服务器位置和自己预测的位置。如果它们不同,说明发生了预测错误。这表示客户端在处理用户命令时,无法获取关于其他实体和环境的正确信息。此时,客户端需要修正自己的位置,因为服务器对于客户端预测有最终的控制权。如果启用了 cl_showerror 1,客户端就能看到何时发生预测错误。预测错误修正可能会比较明显,并导致客户端视角出现不稳定的跳动。通过在短时间内逐渐修正这个错误(由 cl_smoothtime 控制),可以平滑地修正预测错误。如果不需要平滑修正,可以通过设置 cl_smooth 0 来关闭。

预测仅适用于本地玩家和仅受他影响的实体,因为预测是通过使用客户端的按键输入来“最佳猜测”玩家将最终到达的位置来实现的。预测其他玩家的行为则不可能,因为没有办法即时获得他们的按键输入,预测他们的行为实际上相当于预测未来。

Lag compensation

All source code for lag compensation and view interpolation is available in the Source SDK. See Lag compensation for implementation details.

Let's say a player shoots at a target at client time 10.5. The firing information is packed into a user command and sent to the server. While the packet is on its way through the network, the server continues to simulate the world, and the target might have moved to a different position. The user command arrives at server time 10.6 and the server wouldn't detect the hit, even though the player has aimed exactly at the target. This error is corrected by the server-side lag compensation.

The lag compensation system keeps a history of all recent player positions for one second. If a user command is executed, the server estimates at what time the command was created as follows:

Command Execution Time = Current Server Time - Packet Latency - Client View Interpolation

Then the server moves all other players - only players - back to where they were at the command execution time. The user command is executed and the hit is detected correctly. After the user command has been processed, the players revert to their original positions.

Note.pngNote:Since entity interpolation is included in the equation, failing to have it on can cause undesired results.

On a listen server you can enable sv_showimpacts 1 to see the different server and client hitboxes:

延迟补偿

所有关于延迟补偿和视图插值的源代码都可以在 Source SDK 中找到。有关实现细节,请参见《延迟补偿》。

假设玩家在客户端时间 10.5 秒时向目标开火。开火的信息被打包到一个用户命令中并发送到服务器。当数据包在网络上传输时,服务器继续模拟世界,目标可能已经移动到不同的位置。用户命令在服务器时间 10.6 秒到达,服务器没有检测到命中,尽管玩家的瞄准正好对准了目标。这个错误会通过服务器端的延迟补偿来纠正。

延迟补偿系统会保留最近一秒钟内所有玩家的位置历史记录。如果执行了一个用户命令,服务器会估算该命令是在何时创建的,公式如下:

Command Execution Time = Current Server Time - Packet Latency - Client View Interpolation

然后,服务器将所有其他玩家的位置——仅限玩家——移动回命令执行时间时的位置。用户命令被执行,命中被正确检测到。在用户命令处理完成后,玩家会恢复到他们的原始位置。

注意:
由于实体插值包含在这个计算中,如果没有启用它,可能会导致不希望出现的结果。

在本地服务器上,你可以启用 sv_showimpacts 1 来查看不同的服务器和客户端的 hitbox(碰撞盒)。

This screenshot was taken on a listen server with 200 milliseconds of lag (using net_fakelag), right after the server confirmed the hit. The red hitbox shows the target position on the client where it was 100ms + interp period ago. Since then, the target continued to move to the left while the user command was travelling to the server. After the user command arrived, the server restored the target position (blue hitbox) based on the estimated command execution time. The server traces the shot and confirms the hit (the client sees blood effects).

这张截图是在一个有200毫秒延迟的监听服务器上拍摄的(使用了net_fakelag),在服务器确认击中的时候。红色的击中框显示的是客户端上目标的位置,这个位置是在100毫秒加上插值延迟之前的。当时,目标继续向左移动,而用户的命令正在向服务器传输。当用户命令到达服务器时,服务器根据估计的命令执行时间恢复了目标的位置(蓝色击中框)。服务器跟踪射击并确认击中(客户端看到血液效果)。

Client and server hitboxes don't exactly match because of small precision errors in time measurement. Even a small difference of a few milliseconds can cause an error of several inches for fast-moving objects. Multiplayer hit detection is not pixel perfect and has known precision limitations based on the tickrate and the speed of moving objects.

The question arises, why is hit detection so complicated on the server? Doing the back tracking of player positions and dealing with precision errors while hit detection could be done client-side way easier and with pixel precision. The client would just tell the server with a "hit" message what player has been hit and where. We can't allow that simply because a game server can't trust the clients on such important decisions. Even if the client is "clean" and protected by VAC Valve Anti-Cheat, the packets could be still modified on a 3rd machine while routed to the game server. These "cheat proxies" could inject "hit" messages into the network packet without being detected by VAC (a "man-in-the-middle" attack).

Network latencies and lag compensation can create paradoxes that seem illogical compared to the real world. For example, you can be hit by an attacker you can't even see anymore because you already took cover. What happened is that the server moved your player hitboxes back in time, where you were still exposed to your attacker. This inconsistency problem can't be solved in general because of the relatively slow packet speeds. In the real world, you don't notice this problem because light (the packets) travels so fast and you and everybody around you sees the same world as it is right now.

由于时间测量上的小精度误差,客户端和服务器的击中框并不完全匹配。即使是几毫秒的微小差异,也可能导致快速移动物体的几英寸误差。多人游戏的击中检测并不是像素级精确的,并且存在已知的精度限制,这些限制与服务器的tickrate和物体的移动速度有关。

问题来了,为什么击中检测在服务器端如此复杂?在客户端做玩家位置的回溯并处理精度误差的击中检测可以更简单,也能达到像素级的精度。客户端只需要通过一个“击中”消息告诉服务器哪个玩家被击中了,击中的位置在哪。但是我们不能允许这样做,因为游戏服务器不能信任客户端在这么重要的决策上。即使客户端是“干净”的,并且受到Valve反作弊保护,数据包仍然可能在传输到游戏服务器的过程中被第三方机器修改。这些“作弊代理”可以在网络数据包中注入“击中”消息,而不会被VAC检测到(这就是“中间人攻击”)。

网络延迟和延迟补偿可能会产生看起来与现实世界不符的悖论。例如,你可能会被一个你已经看不见的攻击者击中,因为你已经躲进了掩体。发生的情况是,服务器将你的玩家击中框回溯到过去的时间点,那时你仍然暴露在攻击者面前。这个不一致问题通常无法解决,因为数据包传输速度相对较慢。在现实世界中,你不会注意到这个问题,因为光速(即数据包传输速度)非常快,你和你周围的每个人都能看到同一个实时的世界。

 

Net graph

The Source engine offers a couple of tools to check your client connection speed and quality. The most popular one is the net graph, which can be enabled with net_graph 2 (or +graph). Incoming packets are represented by small lines moving from right to left. The height of each line reflects size of a packet. If a gap appears between lines, a packet was lost or arrived out of order. The lines are color-coded depending on what kind of data they contain.

Under the net graph, the first line shows your current rendered frames per second, your average latency, and the current value of cl_updaterate. The second line shows the size in bytes of the last incoming packet (snapshots), the average incoming bandwidth, and received packets per second. The third line shows the same data just for outgoing packets (user commands).

网络图

Source 引擎提供了几个工具来检查客户端的连接速度和质量。最常用的工具是网络图(net graph),可以通过输入 net_graph 2(或 +graph)在控制台中启用。传入的网络数据包通过从右到左的小线条表示。每条线的高度表示数据包的大小。如果线条之间出现间隙,说明数据包丢失或顺序错乱。线条根据数据类型的不同而有不同的颜色。

在网络图的下方,第一行显示当前的渲染帧率(FPS)、平均延迟以及当前的 cl_updaterate 值。第二行显示最后一个传入数据包的大小(快照)、平均传入带宽和接收的数据包每秒数。第三行显示的是出站数据包(用户命令)的相同数据。

 

Optimizations

The default networking settings are designed for playing on dedicated server on the Internet. The settings are balanced to work well for most client/server hardware and network configurations. For Internet games the only console variable that should be adjusted on the client is "rate", which defines your available bytes/second bandwidth of your network connection. Good values for "rate" is 4500 for modems, 6000 for ISDN, 10000 DSL and above.

In an high-performance network environment, where the server and all clients have the necessary hardware resources available, it's possible to tweak bandwidth and tickrate settings to gain more gameplay precision. Increasing the server tickrate generally improves movement and shooting precision but comes with a higher CPU cost. A Source server running with tickrate 100 generates about 1.5x more CPU load than a default tickrate 66. That can cause serious calculation lags, especially when lots of people are shooting at the same time. It's not suggested to run a game server with a higher tickrate than 66 to reserve necessary CPU resources for critical situations.

优化

默认的网络设置是为了在互联网上的专用服务器上进行游戏而设计的。这些设置在客户端/服务器硬件和网络配置上经过平衡,适用于大多数情况。在互联网游戏中,客户端唯一需要调整的控制台变量是“rate”,它定义了网络连接的可用字节/秒带宽。对于不同的网络连接,建议的“rate”值如下:调制解调器为4500,ISDN为6000,DSL及以上为10000。

在高性能的网络环境中,如果服务器和所有客户端都有足够的硬件资源,可以通过调整带宽和tickrate设置来提高游戏精度。提高服务器的tickrate通常能改善移动和射击的精度,但会带来更高的CPU成本。一个运行tickrate为100的Source服务器比默认的tickrate 66消耗大约1.5倍的CPU资源。这可能会导致严重的计算延迟,特别是在很多人同时开火时。为了为关键时刻保留必要的CPU资源,不建议运行高于66的tickrate游戏服务器。

Note:It is not possible to change tickrate on CSS, DoD S TF2, L4D and L4D2 because changing tickrate causes server timing issues. The tickrate is set to 66 in CSS, DoD S and TF2, 60 in HL, CS 1.6 and most GoldSrc games, and 30 in L4D, L4D2 and TFC.
Changing tickrate is however, possible with older version of those games.

注意:

在CSS、DoD S、TF2、L4D和L4D2中无法更改tickrate,因为更改tickrate会导致服务器时间问题。在CSS、DoD S和TF2中,tickrate设置为66;在HL、CS 1.6和大多数GoldSrc游戏中,tickrate设置为60;在L4D、L4D2和TFC中,tickrate设置为30。

不过,在这些游戏的旧版本中,仍然可以更改tickrate。

If the game server is running with a higher tickrate, clients can increase their snapshot update rate (cl_updaterate) and user command rate (cl_cmdrate), if the necessary bandwidth (rate) is available. The snapshot update rate is limited by the server tickrate, a server can't send more then one update per tick. So for a tickrate 66 server, the highest client value for cl_updaterate would be 66. If you increase the snapshot rate and encounter packet loss or choke, you have to turn it down again. With an increased cl_updaterate you can also lower the view interpolation delay (cl_interp). The default interpolation delay is 0.1 seconds, which derives from the default cl_updaterate 20. View interpolation delay gives a moving player a small advantage over a stationary player since the moving player can see his target a split second earlier. This effect is unavoidable, but it can be reduced by decreasing the view interpolation delay. If both players are moving, the view lag delay is affecting both players and nobody has an advantage.

如果游戏服务器使用更高的tickrate,客户端可以提高它们的快照更新率(cl_updaterate)和用户命令率(cl_cmdrate),前提是有足够的带宽(rate)。快照更新率受到服务器tickrate的限制,服务器每个tick只能发送一次更新。因此,对于一个tickrate为66的服务器,客户端的cl_updaterate的最高值为66。如果你增加快照更新率并遇到数据包丢失或延迟,你需要将其调低。通过增加cl_updaterate,你还可以减少视图插值延迟(cl_interp)。默认的插值延迟是0.1秒,这源自默认的cl_updaterate 20。视图插值延迟使得移动的玩家相对于静止的玩家稍微占有一点优势,因为移动的玩家可以比静止玩家稍早一点看到目标。这个效果是不可避免的,但可以通过减少视图插值延迟来减小。如果两个玩家都在移动,视图延迟影响两者,任何人都没有优势。

This is the relation between snapshot rate and view interpolation delay is the following:

interpolation period = max( cl_interp, cl_interp_ratio / cl_updaterate )

"Max(x,y)" means "whichever of these is higher". You can set cl_interp to 0 and still have a safe amount of interp. You can then increase cl_updaterate to decrease your interp period further, but don't exceed tickrate (66) or flood your connection with more data than it can handle.

Tips

Don't change console settings unless you are 100% sure what you are doing
Most "high-performance" setting cause exactly the opposite effect, if the server or network can't handle the load.
Don't turn off view interpolation and/or lag compensation
It will not improve movement or shooting precision.
Optimized setting for one client may not work for other clients
Do not just use settings from other clients without verifing them for your system.

快照更新率和视图插值延迟之间的关系如下:

interpolation period = max( cl_interp, cl_interp_ratio / cl_updaterate )

“Max(x,y)”表示“较大的那个”。你可以将cl_interp设置为0,仍然保持安全的插值。然后你可以增加cl_updaterate,进一步减少插值周期,但不要超过tickrate(66),也不要向连接发送超过它能处理的数据量。

 

公式 interpolation period = max(cl_interp, cl_interp_ratio / cl_updaterate) 是用来计算 插值周期(interpolation period) 的,这个周期决定了客户端在渲染时需要回溯多少时间来平滑和预测目标的位置。它通过两个主要的因素来计算:cl_interpcl_interp_ratio / cl_updaterate

让我们详细解释这两个部分以及它们如何影响插值周期。

1. cl_interp

cl_interp 是客户端插值的时间延迟,通常由 100毫秒(0.1秒)设置为默认值。它表示客户端在渲染时会根据上一个接收到的快照和当前快照之间的差值来进行插值,通常用来平滑玩家的位置和动画。

  • 例如,如果 cl_interp = 0.1,那么客户端会回溯 0.1秒来根据快照做插值,以确保画面流畅,而不是直接显示到达的最新位置。

2. cl_interp_ratiocl_updaterate

  • cl_interp_ratio 控制了客户端希望接收多少个快照之间的插值时间。默认情况下,cl_interp_ratio 的值是 2,这意味着客户端期望渲染出比服务器发送的快照更多的信息。

  • cl_updaterate 控制了客户端每秒请求多少个快照(即服务器更新的频率)。例如,如果 cl_updaterate = 66,则客户端每秒请求 66 个快照。

当你计算 cl_interp_ratio / cl_updaterate 时,实际上是在计算每个快照之间的时间差。这个值决定了客户端在插值时应该回溯多少时间来平滑渲染。例如:

  • 如果 cl_interp_ratio = 2cl_updaterate = 66,那么 cl_interp_ratio / cl_updaterate = 2 / 66 = 0.0303 秒(大约 30毫秒)

这个时间差表示客户端需要回溯多少时间来根据服务器发送的快照做插值。

3. 为什么用 max 函数?

interpolation period 的公式使用了 max 函数来确保插值周期(回溯时间)始终取两个计算值中的最大值。即使你通过调整 cl_interp_ratiocl_updaterate 来缩短插值周期,cl_interp 的默认值仍然会对插值周期产生影响。

 

 

提示:

  • 除非你百分百确定自己在做什么,否则不要更改控制台设置。

  • 如果服务器或网络无法处理负载,大多数“高性能”设置会产生相反的效果。

  • 不要关闭视图插值和/或延迟补偿。 这不会改善移动或射击精度。

  • 为一个客户端优化的设置可能不适用于其他客户端。 不要在没有验证你系统的情况下,直接使用其他客户端的设置。

 

posted @ 2025-04-07 21:40  sun_dust_shadow  阅读(5)  评论(0)    收藏  举报