當前位置: 華文星空 > 知識

網遊伺服器邏輯和傳輸如何分層/解耦?

2022-01-19知識

題主的描述很詳細,基本看懂了。

很多時候,問出正確的問題,很容易得到正確的答案;而如果疑問的角度不好,就會陷入矛盾,無法得到有效的結果。

這個問題就屬於後者——實際上,題主是找錯了解耦的角度。

PickUp 訊息來說。題主的設計問題在於 耦合不足 ,具體來說是PickUp包沒有做完該做的事,無效資訊過多、有效資訊不足,給網絡同步帶來疑難。

1、PickUp訊息包應該包含哪些內容?

客戶端和伺服器的同步是網絡遊戲的核心問題之一。無論現代硬件如何前進演化,仍然有一些基本原則,比如:

  1. 需要同步的數據,應當盡可能小。
  2. 不要去反復更新沒有變化的數據。
  3. 不要同步與此次操作無關的數據。

所以在比較標準的設計中,「拾取道具 PickUp」這件事,應有C2S和S2C兩個網絡包:

C2S ,客戶端到伺服器的請求。應當包含:

  1. 道具在場景中的ID。(或者道具位置,只要是能夠標識出掉落道具的參數)。

訊息完畢。

只有這一個參數?

仔細想想,確實如此。在真正的網遊中,客戶端只要告訴伺服器「我要撿哪個道具」就夠了,至於那個道具是否存在?距離多遠?是什麽東西?能不能撿?都是由伺服器說了算,不需要也不能夠由客戶端來決定。

甚至客戶端具體是哪個玩家,即PlayerID也是由網絡層決定的,客戶端無權定義自己的身份。

S2C ,伺服器對PickUp事件的響應。應當包含:

  1. 拾取成功或失敗,失敗原因用錯誤碼表示即可。
  2. 如果拾取失敗,無需任何其它數據。訊息完畢。
  3. 如果拾取成功,則訊息中僅包含 有變化 的道具資訊。比如第幾個背包格子添加什麽道具,或者某個道具的疊加數量+1。總之僅包含變化的道具資訊。訊息完畢。

這些數據足夠滿足絕大多數典型的網絡遊戲,不需要其它任何數據,也不應該添加其它數據。

為什麽呢?

2、問題:由此操作引發的其它數據變化,如何處理?

顯然,如果遊戲比較復雜,比如WOW那種的,拾取新道具的操作可能引發其它一系列變化,包括不限於:

  1. 角色負重變化,某些內容變化。
  2. 任務列表變化。
  3. 技能變化。
  4. 狀態(buff)變化。

……等等很多。

但是註意,就算變化再多,這些變化一般也不加入到PickUp訊息中。

以任務變化來說,當拾取新的任務道具時,新增道具觸發了任務系統的重新整理。假如任務有變化,自然會觸發任務系統的同步機制,任務系統自然會推播「 有改變的任務 」到客戶端。

同理,角色數據、技能系統也都像這樣有自己的同步機制,都會在發生改變時,發送「最小改變數據」同步給客戶端。

各個模組各司其職。無論如何,它們與「拾取道具」這件事沒有直接關系,不歸拾取道具的邏輯負責。

3、題主的設計有哪些不妥?

單說從問題描述中看到的一些不妥之處。

1、Net.SendItemUpdate、Net.SendPlayerUpdate等函數,疑似發送了全部數據。

前面提過,全量更新違背了資訊最小化原則。不僅讓網絡包變大,更糟糕的是:當玩家同時發送多個請求時,多個響應的全量包之間的數據是重復的甚至不一致的,數據正確性與處理順序密切相關,容易引起數據同步的BUG。

2、一個PickUp請求,產生了三個獨立的響應。

一個請求產生多個響應,本身沒問題。但是具體到題主的程式碼中,與前文描述的情況不一樣。

主要是請求包和響應包應當包含哪些數據、不應當包含哪些數據需要想清楚。

4、關於網絡同步能否解耦的問

網絡同步有些情況下能解耦,有些情況下應該強耦合,慢慢來談。

首先,網絡同步有三種基本方式:

1、狀態同步

伺服器和客戶端持續高頻率同步「所有狀態」,經典的例子是早年的Quake網絡版。

不要以為同步「所有狀態」會很慢。其實,利用diff演算法,自動辨識差異化資訊並同步,能得到極為優異的網絡效能。

簡單、高速、有效,是寫得好的狀態同步演算法最大的特點。

2、訊框同步

訊框同步是網絡上討論很多的概念。它的核心就是「僅同步使用者操作,不發送任何狀態數據」。

訊框同步的前提是「操作相同,結果一定相同」。訊框同步在原理上不難理解,但實際開發起來有很多疑難。主要是對邏輯程式碼的編寫提出了很高要求,任何一點點邏輯瑕疵都會導致客戶端伺服器數據不一致。所以真正完全采用訊框同步的遊戲並不是那麽多。

但是從效能和效率上來講,訊框同步確實是王者級別的存在,適合很多高頻高速操作的移動端網絡遊戲。

3、★ 事件同步

雖然前兩種同步方式經常聽說,但實際上,介於前兩者之間、或者說結合了前兩者的同步方式才是大部份網絡遊戲的真實方案。

真正網遊專案中,特別是MMO中,很難有一種同步方式打天下的情況。要完美解決所有問題,還是只能定義各種各樣不同的邏輯包,具體問題具體分析。

像題主的「拾取道具PickUp」這個包,客戶端到伺服器的是一個操作(操作:拾取周圍某個道具),伺服器返回的是一些狀態(成功或失敗,背包狀態、角色狀態)。

有時是操作、有時是狀態,無法統一命名,我稱之為事件同步。或者說是一種很自由的同步方式,完全取決於每一個包的處理怎麽寫。

搞清楚了幾種同步方式的區別,你會發現:訊框同步和狀態同步,都能做到與具體邏輯程式碼無關,也就是真正意義上的「解耦」。

在訊框同步和狀態同步框架下,只要邏輯程式碼寫對了,所有的狀態自然就由底層同步了。網絡的事情完全不用操心。

而更普遍的「事件同步」方式下,同步機制本身就與遊戲邏輯密切相關,開發者不得不精心設計每一個訊息包,把每一個包都寫對了,才能做到無漏洞、數據一致。

沒想清楚這一點的情況下,強行在每一個操作中同步所有數據,模仿「狀態同步」的做法,自然就會踩到坑裏~~

網絡線上遊戲的機遇

近幾年獨立遊戲蓬勃發展,但 線上功能完善的創新遊戲 發展水平並不高。

這既是市場的短板,也是歷史的機遇,希望有誌氣的小夥伴們考慮這一條充滿挑戰的道路~~~