網路遊戲(聯機遊戲)中的「延遲補償」機制是怎麼回事?能舉個例子(比如CS)來說明它是怎麼工作的么?


終於碰到個本專業的問題了。

@王旭 同學的答案很詳細,然而是錯的。

在網路遊戲中,由於延遲或者網路狀況的抖動,可能會將客戶端效果產生一定的扭曲,影響玩家體驗以及進一步的操作。要降低因為延遲帶來的體驗問題,有兩種策略,一種為客戶端預測,一種為延遲補償。 @王旭

這句是對的。

而上述答案中之後的描述,實際上較詳細的描述了「客戶端預測」(Client Side Prediction)的整個過程,特別是結合魔獸世界的部分應該基本是正確的。然而其中看似「補償」相關的描述,實際上準確的來說僅僅是插值運算(interpolation),是整個「客戶端預測」演算法中的一部分。

而實際上,「延遲補償」(Lag Compensation)是個伺服器端的行為

原提問者提到CS,實際上也是有代表性的,因為第一個提出並實現Lag Compensation的正是half-life。其最初也是最知名的描述參見valve的Yahn W. Bernier所寫的文章:《Latency Compensating Methods in Client/Server In-game Protocol Design and Optimization》(https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization#Game_Design_Implications_of_Lag_Compensation )。

其中關於Lag Compensation,我直接抄過來好了:

Lag compensation is a method of normalizing server-side the state of the world for each player as that player"s user commands are executed. You can think of lag compensation as taking a step back in time, on the server, and looking at the state of the world at the exact instant that the user performed some action. The algorithm works as follows:

  1. Before executing a player"s current user command, the server:
    1. Computes a fairly accurate latency for the player
    2. Searches the server history (for the current player) for the world update that was sent to the player and received by the player just before the player would have issued the movement command
    3. From that update (and the one following it based on the exact target time being used), for each player in the update, move the other players backwards in time to exactly where they were when the current player"s user command was created. This moving backwards must account for both connection latency and the interpolation amount the client was using that frame.
  2. Allow the user command to execute (including any weapon firing commands, etc., that will run ray casts against all of the other players in their "old" positions).

  3. Move all of the moved/time-warped players back to their correct/current positions

簡單歸納一下,就是在伺服器端考慮了客戶端的網路延遲,將伺服器狀態回滾到延遲前,再進行運算。所以這個策略有時候也被稱作「rewind replay」。Lag Compensation除了用於改善因延遲帶來的用戶體驗(要理解其怎樣改善了這方面的用戶體驗,請參見最後推薦的文章),實際上更重要的是為了防止由於「客戶端預測」而可能導致的作弊行為。在網遊設計中有一個鐵律:「The Server Is The Man」(Unreal的老大說的)。

以上為針對提問相關的回答。再多說一些不太相關的。實際上針對FPS(CS、Quake)和MMO(魔獸)等不同類型的網路遊戲,其網路設計差異還是挺大的,涉及到比如發包頻率、發包量、伺服器處理能力、玩法相關(是否要精確的射線檢查)等各方面的考慮。國內遊戲研發主要以MMO為主,在這方面大家鑽研較多,所以參考魔獸、包括研究著名的魔獸服務端開源實現「大芒果」的肯定不在少數。魔獸在客戶端預測方面真是十分厲害的。原理方面,@王旭 同學講的基本都對了。然而追究到細節,我作為一枚MMO客戶端程序員表示至今還有很多不明白是如何實現的。而「大芒果」中,是沒有Lag Compensation的,對於加速作弊等幾乎沒有處理。作為一個號稱只用於研究的開源項目沒有考慮這些完全可以理解,而我相信真實的魔獸伺服器肯定不會實現的那麼簡單。

最後,還推薦一篇文章:《What every programmer needs to know about game networking》(http://gafferongames.com/networking-for-game-programmers/what-every-programmer-needs-to-know-about-game-networking/),從標題也能看出,這篇是描述網遊中網路模型這塊的集大成者了,還包含了主要的歷史演進過程,有興趣的可以深究一下。PS:@王旭 同學文末給出的參考鏈接里其中之一就是這篇的中文翻譯版本,但我大致看了一下,翻譯的不算準確,且沒有標明原文地址。所以還是在這裡給出了原文鏈接。


update:

看到樓下 @王劍飛 的答案,果然是自己答錯了,是服務端的行為,自己臆斷了,抱歉。自己確實是全程搞客戶端的,對服務端不是特別熟悉。

沒有刪除答案,因為覺得裡面的客戶端預測還是沒問題的,所以請忽略我對延遲補償的答案,謝謝。

========================================================================

嘗試答一下,稍微和已知領域有一些交集,有錯誤的地方還望指正。

「延遲補償」機制應該說的是網路遊戲中的一種服務端和客戶端的移動同步策略。

在網路遊戲中,由於延遲或者網路狀況的抖動,可能會將客戶端效果產生一定的扭曲,影響玩家體驗以及進一步的操作。要降低因為延遲帶來的體驗問題,有兩種策略,一種為客戶端預測,一種為延遲補償。

先說說客戶端預測。簡單的說,就是在用戶進行操作的時候,一方面客戶端向服務端發包說明用戶操作,另一方面客戶端自己進行一定的預先行動,等到服務端確認後,根據服務端返回的結果,進行狀態修正。

延遲補償,指的是當延遲發生後,需要把客戶端當前目標的位置儘快的和服務端位置進行同步。為了追求比較平滑的變化,而不是生硬的將目標從A點轉移到B點,採取的一些坐標和動畫播放差值策略。一般的延遲補償,分兩種情況:如果延遲不是很大,則略微加快人物的移動和動畫播放速度,讓人物儘快的「跑」到目標點;如果延遲非常大,幾秒級的,則放棄插幀,直接瞬間移動。

這裡使用魔獸世界的移動同步進行舉例說明:

客戶端發三種包:

1. 開始操作包,指的是用戶開始移動的信號,告訴服務端,目標何時從何地朝哪裡開始移動,方向多少;

2. 心跳包,在操作開始後,如果操作狀態不變,每一個心跳時間(300ms左右),告訴服務端,我仍舊保持上一個操作狀態;

3. 停止包,告訴服務端,上一個操作狀態停止,以及目標停留的位置。

操作上,一般是按下「向前」,發操作包,持續按住,每一個心跳時間發一個心跳包,當改變方向或者鬆開向前,發停止包,再發另一個方向的操作包。

服務端向其他用戶進行同步的時候,策略是直接廣播出去,但是,晚一個心跳包的時間。內部的更新策略是:

1. 收到操作包,等待一個心跳的時間,目標狀態轉為移動,並且發包給其他客戶端命其移動;

2. 收到心跳包,更新一個心跳的位移,發包給其他客戶端,同步目標坐標,這時其他客戶端的人物也在移動,所以同步的代價比較小,客戶端看起來很流暢。

3. 收到停止包,根據佔據心跳時間的比例,算出坐標,發給其他客戶端同步。

然後我們開始看延遲了會怎樣:

1. 當前操作人物在走的時候,由於持續的心跳包發不出去,其他客戶端上,角色就會停在上一個心跳包的位置,並且等待下一個心跳包的到來,保持動畫播放。這也就是魔獸世界中其他人突然卡的時候,在原地跑的原因。自己當前人物也會在走了兩步後,坐標停在原地,但是仍舊會播放移動動畫。 此時服務端沒收到新的心跳包,只將操作人物的坐標,向前更新一個心跳包,避免了因為延遲,服務端靠時間乘以速度矢量來計算位移,導致的有可能「跳崖」之類的意外事件。客戶端本地先進行一個心跳的移動,這個算是客戶端預測的一種實現。

2. 當延遲結束後,客戶端將延遲的包收回後,根據最後的狀態來同步場景中的角色。當發現同步距離差大於一個心跳包後,判定為延遲過大,進行延遲補償。如果距離比較短,使用一個比較短的時間,進行位移和動畫插幀同步,讓目標從「走」過去變成「跑過去」;如果距離較長,可以確定發生了巨大延遲,那麼就無所謂了,做少量的位移插幀,動畫插幀融合可做可不做,類似「瞬移」過去。

對於CS的話,因為是區域網遊戲,低延遲下,應該是沒有客戶端預測的,延遲補償應該和魔獸世界中的類似。

嗯,就是這麼多了,好像還說了一些答非所問的東西,抱歉。

參考:

http://blog.csdn.net/rellikt/article/details/5878447

http://blog.csdn.net/xpwang168/article/details/7660472


其實客戶端也是有延時補償演算法的。

林偉,之前提出過影子跟隨演算法,算是一種客戶端的延時補償演算法,可以在較高的延時下,保證遊戲動作看起來依然流暢。(可以在08年的第7期的《程序員·遊戲創造》上找到,網上有下載,請自行搜索)

而魔獸世界,關於服務端的延時補償,雖然沒有代碼,但是我們可以從其他方面觀察到。舉個栗子,Quartz等施法條插件,都有檢測施法延時的功能。

比如,在搓坐騎的時候,施法條的右邊,會顯示一條綠色的部分,在施法條還沒有走完,而只是走到綠色的部分的時候,這個時候,開始移動,會發現,並沒有打斷搓坐騎的施法,而是馬上騎上馬,開始移動了。據說奧山裡面還可以一鍵上馬哦= =

再比如,PVP的時候,打斷施法,使用Quartz插件後,會發現對方的施法條,是會多出來一節的。比如一個法術,需要1s的施法時間,延時是100ms,在quartz的施法條中顯示,可能是1s+2*100ms。

即是說,在1.2s的時間內,都是有可能打斷對方的施法的。

所以,可以看出,服務端在處理各種操作的時候,都需要考慮的客戶端的延時,對於各種操作的結果的影響。對於各種不同的操作,處理的方式,也會不一樣(這個就是麻煩的地方了,很多體力活)

說得不對的地方,請輕拍。


參考該系列文章http://www.gabrielgambetta.com/client-server-game-architecture.html

詳細介紹了因為網路延遲帶來的問題以及解決方案,最後還給出了一個在線的demo,寫的非常好。


推薦閱讀:

《守望先鋒》是否出現玩家流失的情況,為什麼?
蝸牛的《九陰真經》算得上是國產武俠的良心之作嗎?
如何評價DOTA6.86版本的改動?
如何評價中國遊戲團隊眾籌遊戲《地球 OL》?
從遊戲從業者的角度來說,魔獸世界作為 MMORPG 有何獨到之處?

TAG:遊戲 | 網路遊戲 | 遊戲開發 |