State Transfer
簡介
Fusion支持許多網路架構,所有這些都依賴於狀態轉移。Fusion是以簡單的方式構建的,並自然地集成到Unity的工作流程中,同時提供先進的狀態轉移功能,如增量壓縮、客戶端預測和延遲補償,直接開箱即用。
狀態轉移入門
術語狀態轉移
指的是如何將遊戲狀態分配給所有客戶端。在一個狀態轉移架構中,遊戲狀態從伺服器傳輸到客戶端。該狀態包含了客戶端在本地複製遊戲狀態所需的一切。Fusion通過被稱為NetworkBehaviour
的專門的單體行為
的屬性公開遊戲狀態。所有聯網遊戲對象在某一特定時刻(tick)的[Networked]
屬性的完整集合被稱為快照。
Fusion所使用的兩種狀態傳輸模式是。
- 增量壓縮,即DC,它發送壓縮的完整世界快照;以及,
- 最終一致性(Eventual Consistency),即EC,它使用興趣管理過濾器來決定完整遊戲狀態的哪一部分將被包含在發送給每個客戶端的快照中。
在這兩種情況下,由於網路延遲,當客戶端收到核對後的狀態時已經過期。為了補償,Fusion將重新模擬本地[Networked]
屬性的狀態,從最近收到的狀態到以前更新的最後預測的時間(大約是快照時間加上RTT)。從這裡開始,Fusion可以進一步預測一個新的未來狀態,以匹配伺服器在下次收到客戶端輸入時的預期狀態。
在最終一致性模式下,收到的數據只代表總網路狀態的一個子集。這對應用程式來說是透明的,因為狀態總是由給定的NetworkObject
集合上的相同屬性暴露。
客戶端-與伺服器授權性
Fusion可以在兩種不同的授權模式下執行:
- 伺服器授權模式:一個嚴格的客戶/伺服器設置,有一個專門的無標頭Unity事件,其中一個客戶同時充當伺服器和客戶(主機)。
- 客戶端授權模式:每個客戶端對自己的對象有完全的權限。
在客戶端授權模式下,沒有重新模擬,所有的客戶端總是向前模擬,並且必須接受他們從其他客戶端收到的狀態快照作為當前的真相。
壓縮
狀態傳輸的明顯缺點是頻寬的使用。Fusion通過只發送網路遊戲狀態的變化,並為該數據選擇最小的比特級表示法,不遺餘力地減少包的大小;在最終一致性的情況下,它甚至被進一步減少,只包括與接收者有關的變化。
準確度
有效壓縮數據的一個關鍵方面是Accuracy
。在Fusion中,這可以在NetworkProjectConfig > Accuracy Defaults
中進行全局設置,或者使用[Accuracy]
屬性對每個單獨的變數進行設置。
準確度被Fusion用來將浮點數字轉換為整數。例如,Fusion將在0.00和1.00之間存儲一個具有兩位小數精度的浮點數,而不是在0和100之間存儲一個整數。盡管該值仍然需要相同數量的內存使用(4字節),但它可以更有效地被壓縮,從而節省了頻寬。應用程式可以通過為所有聯網的屬性選擇有意義的精度來減少其傳輸足跡。
增量壓縮
使用之前定義的精度,增量被壓縮,以減少需要傳輸的實際比特數;這時,由於其更密集的比特表示,被轉換為4字節整數的4字節浮點數可以被減少到只有幾個比特。
增量壓縮計算客戶已知收到的最後一個tick的總狀態和當前tick的總狀態之間的差異。例如,如果伺服器從客戶端確認它已經收到了Tick 95,而它自己目前處於Tick 100,那麼下一個增量將被計算為跨越5個tick。
在伺服器收到來自客戶端的確認之前,延遲會不斷增加;這通常會使幾個傳輸的數據包成為多餘的。雖然這看起來效率不高,但它賦予Fusion的巨大優勢是,它永遠不必擔心丟失的數據包。無論客戶機收到什麼樣的增量,它總是可以被應用到客戶機碰巧處於的任何狀態。如果一個較早的增量出現得晚了,它就會被簡單地丟掉,而不會對當前的狀態產生影響,也不需要延遲引起的恢復程序。
Fusion實際上是用一點頻寬來換取最壞情況下延遲的大幅減少。
興趣管理
當Fusion被設置為在最終一致性模式下執行時,可以通過利用API來控制向每個玩家發送什麼數據來進一步降低頻寬要求;這通常被稱為“興趣管理”。
這可以極大地減少跨線發送的數據量,而不影響個別玩家對世界的感知。這在有許多玩家的大型遊戲世界中尤其如此,為了使遊戲可玩,興趣管理往往是必不可少的。
有3種方法可以控制玩家對聯網遊戲對象的興趣列表:
- 興趣區(每個玩家有多個)
- 全局對象(針對所有玩家)
- 自定義興趣管理(每個玩家-對象成對)
興趣區
興趣區域,或稱AoI,定義了世界空間的球體,在數據傳輸中自動添加其中的NetworkObject
。這可以是玩家頭像周圍的一個球體,其半徑與玩家的視距或玩家需要更新的訊息的位置相匹配(例如,任務目標周圍的一個區域)。
為玩家指定AOI是對NetworkRunner
的一個簡單API呼叫。
C#
Runner.AddPlayerAreaOfInterest(PlayerRef player, Vector3 worldPosition, float radius);
Note: 在Shared Mode
中使用的半徑是固定的,在NetworkProjectConfig
中設置。
在ServerMode
和HostMode
中,它在伺服器/主機的FixedUpdateNetwork()
中每幀都被呼叫。如果從客戶端呼叫,玩家參考必須是本地玩家;這只有在Client Authority
模式下才有意義,在這種模式下,AOI責任由Photon Cloud處理。
為了讓伺服器知道哪些網路對象需要考慮納入AoI,特別是讓Photon Cloud知道對象在世界中的位置(鑒於它不了解Unity的場景圖),遊戲對象必須使用特定的預建的NetworkBehaviour
的變體:NetworkTransform
、NetworkTransform
或NetworkCharacterController
。
全局對象
除了AoI的空間表示之外,對象可以在NetworkObject
組件中被標記為global
。這將把它們包括在所有玩家的AOI中,不管他們的世界位置如何。
自定義興趣管理
個別玩家可能有他們一直感興趣的個別對象。要強制一個特定的NetworkObject
的數據總是被發送給玩家,請呼叫SetPlayerAlwaysInterested()
一次。
C#
Runner.SetPlayerAlwaysInterested(PlayerRef player, NetworkObject obj, bool always)
網路拓扑結構
Fusion支持幾種網路拓扑結構。
專屬伺服器
部署具有完全伺服器權限的Unity無標頭事件。這是一個典型的客戶/伺服器設置,它得益於有一個值得信賴的授權實體,對遊戲世界有充分的了解,包括物理對象和渲染基元(即使這些沒有被使用)。由於專用伺服器通常托管在公共靜態IP上,因此不需要UDP洞或網路中繼。
專用伺服器的主要缺點是為每個遊戲會話建立完整的Unity的事件消耗。
玩家托管
Player Hosted
的伺服器模式具有內置的打孔和中繼功能,包括由Photon Cloud提供的完整的主機遷移支持。如果UDP打洞失敗,Fusion無法在對象之間建立直接連接,玩家將不得不通過中繼連接;這是一種零星的情況,只發生在大約1/10的玩家身上。盡管在Player Hosted
模式下,中繼器引入了一個潛在的額外延遲源,但在遊戲中很少注意到它。
在Player Hosted
模式中,本地事件是一個伺服器,而不是一個客戶端。這種模式仍然允許使用本地玩家,並且會對其進行輪詢輸入,並按照預期在渲染時進行插值。總的來說,這個模式相當於一個專門的伺服器(也就是說,在遊戲代碼中沒有明顯的變化)。它擺脫了專用伺服器的成本,但犧牲了一個值得信賴的授權;換句話說,流氓主機可以作弊。
單人遊戲
Fusion允許網路代碼在本地執行而不需要改變。邏輯的執行與Player Hosted
模式一樣,但無需打開外部網路連接。這使應用程式不必在遊戲模式上做無休止的切換。
共享模式
客戶端對Photon Cloud的授權,使用最終一致性(EC)和興趣管理的數據驅動的伺服器管理的快照也可擴展到高玩家數量。共享模式使用Photon Cloud來執行專用伺服器的一些優勢,而沒有執行完整的Unity事件的大量消耗。
Optionally: Fusion的Photon伺服器插件可以完全訪問遊戲狀態,即使沒有Unity。這使得我們可以很容易地編寫一個自定義的Fusion伺服器插件,以便對遊戲狀態進行驗証,防止作弊和漏洞。
Back to top