1. 程式人生 > >Source引擎多人模式網絡同步模型

Source引擎多人模式網絡同步模型

但是 最重要的 緩沖 imp 調制 hit 位置 等待 translate

轉自:http://gad.qq.com/program/translateview/7168875

Source引擎的多人遊戲使用基於UDP通信的C/S架構。遊戲以服務器邏輯作為世界權威,客戶端和服務器通過UDP協議(20~30packet/s)通信。客戶端從服務器接收信息並基於當前世界狀態渲染畫面和輸出音頻。客戶端以固定頻率發送操作輸入到服務器。客戶端僅與遊戲服務器,而不是彼此之間通信。多人遊戲必須處理基於網絡消息同步所帶來的一系列問題。

網絡的帶寬是有限的,所以服務器不能為每一個世界的變化發送新的更新數據包發送到所有客戶端。相反,服務器以固定的頻率取當前世界狀態的快照並廣播這些快照到客戶端。網絡數據包需要一定的時間量的客戶端和服務器(RTT的一半)來往。這意味著客戶端時間相對服務器時間總是稍有滯後。此外,客戶端輸入數據包同步到服務器也有一定網絡傳輸時間,所以服務器處理客戶端輸入也存在延遲的。不同的客戶端因為網絡帶寬和通信線路不同也會存在不同的網絡延時。隨著服務器和客戶端之間的這些網絡延遲增大, 網絡延遲可能會導致邏輯問題。比如在快節奏的動作遊戲中,在幾毫秒的延遲甚至就會導致遊戲卡頓的感覺,玩家會覺得很難打到對方玩家或運動的物體。此外除了帶寬限制和網絡延遲還要考慮網絡傳輸中會有消息丟失的情況。

技術分享

為了解決網絡通信引入的一系列問題,Source引擎在服務器同步時采用了數據壓縮和延遲補償的邏輯,客戶端采用了預測運行和插值平滑處理等技術來獲得更好的遊戲體驗。

基本網絡模型

服務器以一個固定的時間間隔更新模擬遊戲世界。默認情況下,時間步長為15ms,以66.66次每秒的頻率更新模擬遊戲世界,但不同遊戲可以指定更新頻率。在每個更新周期內服務器處理傳入的用戶命令,運行物理模擬步,檢查遊戲規則,並更新所有的對象狀態。每一次模擬更新tick之後服務器會決定是否更新當前時間快照以及每個客戶端當前是否需更新。較高的tickrate增加了模擬精度,需要服務器和客戶端都有更多可用的CPU和帶寬資源。客戶通常只能提供有限的帶寬。在最壞的情況下,玩家的調制解調器連接不能獲得超過5-7KB /秒的流量。如果服務器的數據更新發送頻率超過了客戶端的帶寬處理限制,丟包是不可避免的。因此客戶端可以通過在控制臺設置接受帶寬限制,以告訴服務器其收到的帶寬容量。這是客戶最重要的網絡參數,想要獲得最佳的遊戲體驗的話必須正確的設置此參數。客戶端可以通過設置cl_updaterate(默認20)來改變獲得快照平的頻率,但服務器永遠不會發送比tickerate更多的更新或超過請求的客戶端帶寬限制。服務器管理員可以通過sv_minrate和sv_maxrate(byte/s)限制客戶端的上行請求頻率。當然快照更新同步頻率都受到sv_minupdaterate和sv_maxupdaterate(快照/秒)的限制。

客戶端使用與服務端tickrate一樣的頻率采樣操作輸入創建用戶命令。用戶命令基本上是當前的鍵盤和鼠標狀態的快照。客戶端不會把每個用戶命令都立即發送到服務器而是以每秒(通常是30)的速率發送命令包。這意味著兩個或更多個用戶的命令在同一包內傳輸。客戶可以增加與的cl_cmdrate命令速率。這可以提高響應速度,但需要更多的出口帶寬。

遊戲數據使用增量更新壓縮來減少網絡傳輸。服務器不會每次都發送一個完整的世界快照,而只會更新自上次確認更新(通過ACK確認)之後所發生的變化(增量快照)。客戶端和服務器之間發送的每個包都會帶有ACK序列號來跟蹤網絡數據流。當遊戲開始時或客戶端在發生非常嚴重的數據包丟失時, 客戶可以要求全額快照同步。

用戶操作的響應速度(操作到遊戲世界中的可視反饋之間的時間)是由很多因素決定的,包括服務器/客戶端的CPU負載,更新頻率,網絡速率和快照更新設置,但主要是由網絡包的傳輸時間確定。從客戶端發送命令到服務器響應, 再到客戶端接收此命令對應的服務器響應被稱為延遲或ping(或RTT)。低延遲在玩多人在線遊戲時有顯著的優勢。客戶端本地預測和服務器的延遲補償技術可以盡量為網絡較差的遊戲玩家提供相對公平的體驗。如果有良好的帶寬和CPU可用,可以通過調整網絡設置以獲得更好的體驗, 反之我們建議保持默認設置,因為不正確的更改可能導致負面影響大於實際效益。

Enitiy插值平滑

通常情況下客戶端接收每秒約20個快照更新。如果世界中的對象(實體)直接由服務器同步的位置呈現,物體移動和動畫會看起來很詭異。網絡通信的丟包也將導致明顯的毛刺。解決這個問題的關鍵是要延遲渲染,玩家位置和動畫可以在兩個最近收到快照之間的連續插值。以每秒20快照為例,一個新的快照更新到達時大約每50毫秒。如果客戶端渲染延遲50毫秒,客戶端收到一個快照,並在此之前的快照之間內插(Source默認為100毫秒的插補周期);這樣一來,即使一個快照丟失,總是可以在兩個有效快照之間進行平滑插值。如下圖顯示傳入世界快照的到達時間:

技術分享

在客戶端接收到的最後一個快照是在tick 344或10.30秒。客戶的時間將繼續在此快照的基礎上基於客戶端的幀率增加。下一個視圖幀渲染時間是當前客戶端的時間10.32減去0.1秒的畫面插值延遲10.20。在我們的例子下一個渲染幀的時間是10.22和所有實體及其動畫都可以基於快照340和342做正確的插值處理。

既然我們有一個100毫秒的延遲插值,如果快照342由於丟包缺失,插值可以使用快照340和344來進行平滑處理。如果連續多個快照丟失,插值處理可能表現不會很好,因為插值是基於緩沖區的歷史快照進行的。在這種情況下,渲染器會使用外推法(cl_extrapolate 1),並嘗試基於其已知的歷史,為實體做一個基於目前為止的一個簡單線性外推。外推只會快照更新包連續丟失(cl_extrapolate_amount)0.25秒才會觸發,因為該預測之後誤差將變得太大。實體內會插導致100毫秒默認(cl_interp 0.1)的恒定視圖“滯後”,就算你在listenserver(服務器和客戶端在同一臺機器上)上玩遊戲。這並不是說你必須提前預判動畫去瞄準射擊,因為服務器端的滯後補償知道客戶端實體插值並糾正這個誤差。

最近Source引擎的遊戲有cl_interp_ratioCVaR的。有了這個,你可以輕松,安全地通過設置cl_interp為0,那麽增加的cl_updaterate的值(這同時也會受限於服務器tickrate)來減少插補周期。你可以用net_graph 1檢查您的最終線性插值。

如果打開sv_showhitboxes,你會看到在服務器時間繪制的玩家包圍盒,這意味著他們在前進的線性插值時期所呈現的播放器模式。

輸入預測

讓我們假設一個玩家有150毫秒的網絡延遲,並開始前進。前進鍵被按下的信息被存儲在用戶命令,並發送至服務器。用戶命令是由移動代碼邏輯處理,玩家的角色將在遊戲世界中向前行走。這個世界狀態的變化傳送到所有客戶端的下一個快照的更新。因此玩家看到自己開始行動的響應會有150毫秒延遲,這種延遲對於高頻動作遊戲(體育,設計類遊戲)會有明顯的延遲感。玩家輸入和相應的視覺反饋之間的延遲會產生一種奇怪的,不自然的感覺,使得玩家很難移動或精確瞄準。客戶端的輸入預測(cl_predict 1)執行是一種消除這種延遲的方法,讓玩家的行動感到更即時。與其等待服務器來更新自己的位置,在本地客戶端只是預測自己的用戶命令的結果。因此,客戶端準確運行相同的代碼和規則服務器將使用來處理用戶命令。預測完成後,當地的玩家會移動到新位置,而服務器仍然可以看到他在老地方。150毫秒後,客戶會收到包含基於他早期預測用戶命令更改服務器的快照。客戶端會將預測位置同服務器的位置對比。如果它們是不同的,則發生了預測誤差。這表明,在客戶端沒有關於其他實體的正確信息和環境時,它處理用戶命令。然後,客戶端必須糾正自己的位置,因為服務器擁有客戶端預測最終決定權。如果cl_showerror 1開啟,客戶端可以看到,當預測誤差發生。預測誤差校正可以是相當明顯的,並且可能導致客戶端的視圖不規則跳動。通過在一定時間(cl_smoothtime)逐漸糾正這個錯誤,錯誤可以順利解決。預測誤差平滑處理可以通過設置cl_smooth 0來關閉。預測只對本地玩家以及那些只收它影響的實體有效,因為預測的工作原理是使用客戶端的操作來預測的。對於其他玩家沒法做有效預測, 因為沒有辦法立即從他們身上得到操作信息。

延遲補償

比方說,一個玩家在10.5s的時刻射擊了一個目標。射擊信息被打包到用戶命令,該命令通過網絡的方式發送至服務器。服務器持續模擬遊戲世界,目標可能已經移動到一個不同的位置。用戶命令到達服務器時間10.6時服務器就無法檢測到射擊命中,即使玩家已經在目標準確瞄準。這個錯誤需要由服務器側進行延遲補償校正。延遲補償系統使所有玩家最近位置的歷史一秒。如果在執行用戶的命令,服務器預計在命令創建什麽時間如下:

命令執行時間=當前服務器時間 - 數據包延遲 - 客戶端查看插值

然後服務器會將所有其他玩家回溯到命令執行時的位置,他們在命令執行時間。用戶指令被執行,並正確地檢測命中。用戶命令處理完成後,玩家將會恢復到原來的位置。由於實體插值包含在公式中,可能會導致意外的結果。服務器端可以啟用sv_showimpacts 1,顯示服務器和客戶端射擊包圍盒位置差異:

技術分享

該畫面在主機上設置延遲200毫秒(net_fakelag設置)時獲取的,射擊真實命中玩家。紅色命中包圍盒顯示了客戶端那裏是100毫秒+插補周期前的目標位置。此後,目標繼續向左移動,而用戶命令被行進到服務器。用戶命令到達後,服務器恢復基於所述估計的命令執行時間目標位置(藍色擊中盒)。服務器回溯演繹,並確認命中(客戶端看到流血效果)。

因為在時間測量精度的誤差客戶端和服務器命中包圍盒不完全匹配。對於快速移動的物體甚至幾毫秒的誤差也會導致幾英寸的誤差。多人遊戲擊中檢測不是基於像素的完美匹配,此外基於tickrate模擬的運動物體的速度也有精度的限制。

既然擊中檢測服務器上的邏輯如此復雜為什麽不把命中檢查放在客戶端呢?如果在客戶端進行命中檢查, 玩家位置和像素命中處理檢測都可以精準的進行。客戶端將只告訴服務器用“打”的消息一直打到什麽樣的玩家。因為遊戲服務器不能信任客戶端這種重要決定。因為即使客戶端是“幹凈”的,並通過了Valve反作弊保護,但是報文可以被截獲修改然後發送到遊戲服務器。這些“作弊代理”可以註入“打”的消息到網絡數據包而不被VAC被檢測。

網絡延遲和滯後補償可能會引起真實的世界不可能的邏輯。例如,您可能被你看不到的目標所擊中。服務器移到你的命中包圍盒時光倒流,你仍然暴露給了攻擊者。這種不一致問題不能通過一般化的防範解決,因為相對網絡包傳輸的速度。在現實世界中,因為光傳播如此之快,你,每個人都在你身邊看到同一個世界,所以你才你沒有註意到這個問題。

網絡視圖NET_Graph

Source引擎提供了一些工具來檢查您的客戶端連接速度和質量。使用net_graph 2可以啟用相關的視圖。下面的曲線圖中,第一行顯示每秒當前的渲染的幀,您的平均延遲時間,以及的cl_updaterate的當前值。第二行顯示在最後進來的數據包(快照),平均傳入帶寬和每秒接收的數據包的字節大小。第三行顯示剛剛傳出的數據包(用戶命令)相同的數據。

技術分享

默認的網絡設置是專門為通過互聯網連接的遊戲服務器設計的。可以適用大多數客戶機/服務器的硬件和網絡配置工作。對於網絡遊戲,應該在客戶端上進行調整,唯一的控制臺變量是“rate”,它定義客戶端可用的字節/網絡連接帶寬。

在一個良好的網絡環境中,服務器和所有客戶端都具有必要的硬件資源可用,可以調整帶寬和更新頻率設置,來獲得更多的遊戲精度。增加tickrate通常可以提高運動和射擊精度,但會消耗更多的服務器CPU資源。tickrate 100運行的服務器的負載大概是tickrate 66運行時的約1.5倍, 因此如果CPU性能不足可能會導致嚴重的計算滯後,尤其是在玩家數量比較多的時候。建議對具有更高tickrate超的遊戲服務器預留必要的CPU資源。

如果遊戲服務器使用較高tickrate運行時,客戶端可以在帶寬可用的情況下增加他們的快照更新率(的cl_updaterate)和用戶命令速率(的cl_cmdrate)。快照更新速率由服務器tickrate限制,一臺服務器無法發送每個時鐘周期的一個以上的更新。因此,對於一個tickrate66服務器,為的cl_updaterate最高的客戶價值,將是66。如果你增加快照率遇到,你必須再次打開它。與增加的cl_updaterate你也可以降低畫面插值延遲(cl_interp)。默認的插值延遲為0.1秒(默認的cl_updaterate為20) 視圖內插延遲會導致移動的玩家會比靜止不動的玩家更早發現對方。這種效果是不可避免的,但可以通過減小視圖內插值延遲來減小。如果雙方玩家正在移動,畫面滯後會延遲影響雙方玩家,雙方玩家都不能獲利。快照速率和視圖延遲插值之間的關系如下:

插補周期= MAX(cl_interp,cl_interp_ratio /cl_updaterate)

可以設置cl_interp為0,仍然有插值的安全量。也可以把cl_updaterate增加,進一步降低你的插補周期,但不會超過更新tickrate(66)或客戶端的網絡處理能力。

Tips

不要瞎改終端配置除非你完全確定你在幹嘛

如果客戶端和服務器沒有足夠CPU和網絡資源,絕大多數所所謂高性能優化都是起負面作用

不要關閉畫面插值和延遲補償

這樣並不能代理移動和設計精準度提升

優化設置可能不會對每個客戶端都有效

如果是你是在遊戲裏或者SourceTv裏第一視角觀看你看到的畫面和玩家可能不一樣

觀戰者的畫面沒有延遲補償

Source引擎多人模式網絡同步模型