原文:https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
輸入預測
假設玩家的網絡延遲為150毫秒,並開始向前移動。該按鍵命令發送到服務器。用戶命令被處理,並且玩家的角色在游戲世界中向前移動。這個狀態更改將通過下一次快照更新傳輸到所有客戶端。所以玩家在開始走路之后,會在150毫秒的延遲時間后看到自己的動作變化。這種延遲存在於所有玩家的行動,如運動,射擊武器等,並且隨着更高的延遲而變得更糟。玩家輸入和相應的視覺反饋之間的延遲會產生奇怪的,不自然的感覺,並且使得難以精確地移動或瞄准。
客戶端輸入預測(cl_predict 1
)是一種消除這種延遲的方法,讓玩家的動作感覺更加即時。而不是等待服務器更新自己的位置,本地客戶端只是預測自己的用戶命令的結果。因此,客戶端運行與服務器完全相同的代碼和規則,便於服務器驗證用戶命令。預測完成后,本地玩家將立即移動到新位置,而服務器仍然在舊位置看到他。
150毫秒后,客戶端將根據他之前預測的用戶命令接收包含更改的服務器快照。然后,客戶端將服務器位置與他的預測位置進行比較。如果它們不同,則發生預測錯誤。這表示客戶端在處理用戶命令時沒有獲得其他實體和環境的正確信息。然后,客戶端必須糾正自己的位置,因為服務器具有決定客戶端預測是否准確的最終權限。如果cl_showerror 1
打開,客戶可以看到預測錯誤發生。預測誤差校正可能非常顯著,可能導致客戶端的視圖不規律地跳動。通過在短時間內逐漸糾正這個錯誤(cl_smoothtime
),可以順利地糾正錯誤。cl_smooth 0
只有當他們受到影響的本地玩家和實體才能進行預測,因為可以通過使用客戶的按鍵來做出玩家最終的“最好的猜測”。無法預測其他的玩家。
滯后補償
- 源代碼SDK中提供了用於滯后補償和視圖插值的所有源代碼。查看實施細節的滯后補償。
假設玩家在客戶端10.5射擊目標。發射信息被打包成用戶命令並發送到服務器。當數據包正在通過網絡時,服務器繼續模擬世界,目標可能已經移動到不同的位置。用戶命令到達服務器時間10.6,並且服務器將會檢測到未命中,即使玩家完全瞄准目標。該錯誤需要服務器端滯后補償進行糾正。
滯后補償制度保存了所有近期一秒鍾內玩家的歷史位置。如果執行了用戶命令,則服務器估計創建命令的時間如下:
命令執行時間 = 當前服務器時間 - 數據包延遲 - 客戶端視圖插值
然后,服務器將所有相關玩家 - 移動到他們在命令執行時間的地方。執行用戶命令並正確檢測命中。用戶命令處理完畢后,玩家將恢復到最新的位置。

該屏幕截圖是net_fakelag
在服務器確認命中之后,在具有200毫秒延遲(使用)的監聽服務器上拍攝的。紅色的hitbox在客戶端顯示100ms + interp之前的目標位置。此后,當用戶命令發往服務器時,目標繼續向左移動。用戶命令到達后,服務器根據估計的命令執行時間恢復目標位置(藍色命中框)。服務器確認命中(客戶端看到血液效應)。
思考:
由於時間測量中的精確度誤差小,客戶端和服務器的命中框不完全匹配。即使是幾毫秒的小差也可能導致快速移動物體幾英寸的誤差。多人攻擊檢測不是像素完美的,並且基於運動對象的滴答率和速度已知精度限制。
問題出在了,為什么命中檢測在服務器上這么復雜?在點擊檢測時,對玩家位置執行后跟蹤和精度處理錯誤,可以通過客戶端方式更輕松,並更精確。客戶端只是告訴服務器一個“命中”消息什么玩家被擊中和哪里。但是我們不能容忍,因為游戲服務器不能信任客戶端這樣重要的決定。即使客戶端“干凈”並受到Valve Anti-Cheat的保護,也可以在第三台機器上修改數據包,同時路由到游戲服務器。這些“欺騙代理”可能會在VAC(“中間人”攻擊)中察覺到“打”消息到網絡包中。
網絡延遲和滯后補償可能產生與現實世界似乎不合邏輯的矛盾。例如,你可以被一個甚至不能再看到的攻擊者擊中,因為你已經被蓋了。發生了什么事情是,服務器將您的播放器命中的時間推遲回來,您仍然暴露在您的攻擊者身上。由於數據包速度相對較慢,這種不一致性問題一般無法解決。在現實世界中,你不會注意到這個問題,因為光(包)行進得如此之快,你和你周圍的人都看到與現在相同的世界。
附:一種計算客戶端服務器間網絡延遲的方法
客戶端想服務器發送一個請求,同時客戶端記錄下當前時間:sendTime
這個請求服務器收到以后不做任何處理,直接返回給客戶端。客戶端收到以后再次記錄當前時間:receiveTime
網絡延時就是: (receiveTimer - sendTime)/ 2
服務器方的計算方法同理。
服務器端的工作簡介:針對客戶端的命令,驗證當前位置是否合法,目標位置是否可達並修正(碰撞檢測),玩家操作延時補償,