network simulation loop
title: "Network Simulation Loop" tags: "fusion"
概述
Fusion以一致的時間步長來運行基於離散刷新的模擬,而不管使用的網路模式如何。處理此問題的整個過程稱為「已連網模擬迴圈」。所有邏輯都寫在NetworkBehaviour
的子類別中,這意味著常規Unity遊戲物件是這個模擬迴圈的中心部分。
除了向前移動世界狀態的快照外,Fusion還可以根據本機玩家輸入或任何基於物理的物件,來預測未來的狀態(打開客戶端的物理預測是可選的)。
可以基於當前已知資料及自訂程式碼,為任何物件編寫客戶端預測邏輯(例如外推彈道軌跡)。
本檔案更詳細地解釋了與Fusion模擬迴圈工作原理相關的最重要概念。
刷新
已連網機器之間存在自然發生的時間差異,Fusion使用稱為 刷新 的離散抽象時間單位來處理模擬,而不是直接按時間驅動。刷新與任何特定客戶端和主機上傳遞的實際真實世界時間解耦。使用刷新而不是硬體時鐘,允許網路階段中的所有客戶端共享「時間」概念的共同參考框架。刷新不會漂移,也不受精確度問題的影響,這對於在多台已連網機器上準確推斷未來和過去的事件至關重要。
每個刷新之間的時間步長由NetworkProjectConfig
中的Simulation > Tick Rate
定義。刷新頻率以赫茲(Hz)為單位定義;因此60的時間步長等於1/60秒的差量。這意味著系統將使用1/60秒的時間步長來推進遊戲狀態,而不管前一個和當前刷新之間實際經過了多少時間。在程式碼中,可以透過NetworkRunner.DeltaTime
屬性存取時間步長。
重要提示: 用於模擬迴圈的刷新率與渲染率(每秒幀數)不同!
每個刷新都有一個相應的狀態快照,其明確地陳述了當時世界的「真相」。為了在下一個刷新生成新的快照,Fusion將在每個NetworkBehaviour
上叫用FixedUpdateNetwork()
來更新他們負責的遊戲物件的整體狀態的部分。Fusion指的是對給定的GameObject
擁有State Authority
。
對於任何給定的物件,只有一台機器具有State Authority
。
- 在客戶端/伺服器設定中,這 始終 是伺服器。
- 在客戶端授權設定中,每個客戶端都擁有自己的物件,每個客戶端通常對其建立的物件保持授權。
輸入處理
Fusion使用輸入來驅動客戶端預測。客戶端根據其本機(過時)資訊和本機玩家的輸入預測下一個伺服器狀態。當收到實際狀態時,客戶端將使用這個新的基準真相作為基礎來重新模擬新的未來狀態。
為了使預測成為可能,輸入處理被分為兩步。
- 輸入輪詢:Fusion透過特定物件的輸入授權從客戶端的本機硬體收集輸入。
- 輸入消耗:輸入由本機模擬應用,並與伺服器共享,以包含在權威模擬中。
有關輸入定義、輪詢和消耗的更多資訊,請閱讀手冊中的網路輸入頁面。
預測
預測涉及客戶端根據其 當前 本機資訊 預測 未來 伺服器狀態。由於已連網設備之間的繼承延遲,基於從伺服器接收到的真實遊戲狀態快照的本機資訊總是過時的。客戶端使用預測來嘗試使本機遊戲狀態與伺服器遊戲狀態保持同步。這對於減輕網路延遲對玩家體驗的影響是必要的。網路延遲始終等於從伺服器到客戶端再返回的往返時間。它可以用離散的刷新來推理。
想像一個具有以下特徵的場景:
- 當前伺服器刷新:100
- 刷新率:1/60秒
- 客戶端1的延遲等於4個刷新(伺服器到客戶端2個刷新+客戶端到伺服器2個刷新)
- 客戶端2的延遲等於6個刷新(伺服器到客戶端3個刷新+客戶端到伺服器3個刷新)
雖然客户端知道它們各自的延遲,但伺服器會通知客户端需要預測多少刷新數才能跟上。預測使客户端能及時發送他們的輸入,以便伺服器在給定的時間點要求它。客户端具有輸入授權的物件將使用本機輸入(例如玩家角色)進行預測,從而產生即時回應的錯覺;它被稱為輸入授權,因為雖然它不能顯式控制物件的狀態,但它可以控制驅動狀態的輸入。
例如,當客户端1移動他們的玩家角色時,它會根據從伺服器收到的最後一個經過驗證的刷新來預測未來的狀態。基於這些預測,客户端1告訴伺服器它計畫在伺服器的2個刷新的未來做什麼(即刷新102)。這為輸入在線上傳輸並被伺服器及時接收留下了足夠的時間,以便在刷新102的驗證狀態的模擬期間將其消耗。只要沒有任何東西干擾客戶端1的玩家移動,客户端1上的 已預測 刷新102和伺服器上的 已驗證 刷新102將處於相同的狀態。
為了確保客戶端1先預測足夠的刷新在未來補償延遲,伺服器告訴它總是比伺服器狀態提前至少2個刷新。另一方面,由於延遲較高,客戶端2需要預測未來的3個刷新才能跟上。
從圖中可以看出,由於客戶端1和客戶端2對伺服器的相對延遲,它們 不 處於完全相同的狀態。客戶端意識到他們的「真相」是錯誤的,因為其他客戶端的資訊還沒有到達他們。這就是複製與核對發揮作用的地方。
複製
Fusion在緊湊型記憶體緩衝區中管理和模擬狀態行程。當Fusion從伺服器接收到狀態快照時,它會將快照解包到記憶體緩衝區中。由於緩衝區中保存的當前狀態是基於預測狀態的,因此用快照中的狀態替換它,意味著客戶端被有效地及時貼齊到與從伺服器接收到的快照相關的刷新。然後,Fusion在接收到的狀態和客戶端的本機預測狀態之間的每個刷新運行一次模擬迴圈;這會使狀態恢復到接收快照之前的狀態,除非有更準確的預測狀態。
核對
當客戶端收到一個新的快照,其中包含最新的(因此更準確的)世界狀態時,客戶端會將其本機狀態與它自己的狀態進行核對。核對是透過複製客戶端收到的最後一個伺服器快照,並將本機遊戲狀態從與伺服器快照關聯的刷新重新模擬到當前刷新來完成的。
最終的結果是,伺服器始終處於穩定的核對狀態,當發生意外事件時,客戶端將逐步進行自我調整。此過程在Fusion中稱為 重新模擬,因為它基於新的驗證狀態重新模擬舊輸入的效果,以使客戶端的狀態與伺服器相核對。
如果客戶端1和2在伺服器上發生碰撞,這一點尤為重要。它們的位置將由伺服器解決,因為它專門決定任何給定刷新的任何物件的結束狀態;這就是為什麼伺服器被稱為具有狀態授權的原因。
示例
伺服器向客戶端發送源源不斷的舊資料。當客戶端1接收到 已驗證 刷新100時,它會將刷新100的 已驗證 狀態複製到其記憶體緩衝區中,從而覆蓋其先前 已預測 的刷新100。
- 如果沒有發生任何意外,那麼本機 已預測 的刷新100將已經是正確的狀態,這意味著客戶端1和伺服器完全同步,除了客戶端1比伺服器領先2個刷新。
- 如果已驗證的刷新與客戶端1的預測不匹配,則 已驗證 刷新100將被用作校正狀態。
在任一情況下,客戶端將按順序從100、101和102重新應用其輸入,以到達新的刷新103。
隨時間從客戶端1的角度來看,當它收到校正的刷新101,對102和103應用其輸入並達到校正狀態時,它將處於刷新104。
客戶端2在其模擬迴圈期間經歷完全相同的過程。唯一的區別是接收伺服器 已驗證 刷新1的刷新的輕微延遲,這是由於其較高的延遲,它透過進一步預測來補償。
FixedUpdateNetwork()
為了將當前刷新狀態推進到下一個刷新狀態,Fusion對場景中的所有NetworkBehaviour
元件調用FixedUpdateNetwork()
。由於在複製和預測過程中都調用了FixedUpdateNetwork
,因此本機狀態應該只從網路狀態中 衍生;從FixedUpdateNetwork
向本機狀態 應用 漸進差量更新,很可能會導致應用太多更改。
快照內插補點
通常,每個客戶端只對單個或少數幾個GameObjects
擁有輸入授權;剩餘的GameObjects
透過快照更新將其狀態回饋給客戶端。與預測狀態不同,快照始終位於伺服器之後,因為從伺服器發送到客戶端接收和複製之間存在一些延遲。
Fusion將這些「遠端」控制的GameObjects
稱為 代理。
如果快照按原樣應用於代理的當前(視覺效果)狀態,則它將以模擬的刷新率而不是客戶端的渲染率,進行動畫和更新。出於幾個原因,應避免這種情況:
- 節約頻寬。通常希望以比渲染低得多的頻率運行模擬。例如,30Hz的網路模擬頻率和120Hz的渲染頻率。
- 網路封包的到達率不一致。將遊戲的渲染頻率與具有較大隨機方面的事件連結起來,會導致抖動移動。
為了將網路封包頻率與渲染的重新整理率解耦,同時提供流暢的狀態轉換,Fusion在兩個快照之間內插補點「渲染狀態」。內插補點的目的是即時的流暢,而不是刷新;理想情況下,內插補點基於兩個最新可用的快照。但是,快照可能不會以恆定的速率到達。所以,除非有一個小的餘量(緩衝區)阻止這種情況發生,否則恆定速率內插補點有可能趕上不恆定的網路快照。
Fusions的眾多優勢之一是內插補點算法,該算法根據當前網路條件調整所需的偏移和緩衝。這為客戶端提供了盡可能小的延遲,同時仍然提供流暢的視覺效果。
Fusions的核心元件,如NetworkTransform
,使用內插補點來轉換其視覺效果元件,但即使對於您的自訂網路屬性,您也可以存取和使用Fusions內建的內插補點器。關於內插補點器的更多資訊,可以在此處找到。