unity網絡同步幀同步與狀態同步

幀同步

所謂幀同步(lockstep),其實是同步操作,確保兩個客戶端邏輯一致,然後服務器接收每個客戶端操作(cmd),
然後再下發下去,相同的邏輯,相同的操作,相同的觸發事件(Event)便會播放(DoAction)相同的結果。

 

優點

第一,它的開發效率比較高。如果你開發思路的整體框架是驗證可行的,如果你把它的缺點解決了,那麼你的開發思路完全就跟寫單機一樣,你只需要遵從這樣的思路,儘量保證性能,程序該怎麼寫就怎麼寫。

比如我們以前要在狀態同步下面做一個複雜的技能,有很多段位的技能,可能要開發好幾天,纔能有一個稍微過得去的結果,而在幀同步下面,英雄做多段位技能很可能半天就搞定了。

第二,它能實現更強的打擊感,打擊感強除了我們說的各種反饋、特效、音效外,還有它的準確性。利用幀同步,遊戲裏面看到這些揮舞的動作,就能做到在比較準確的時刻產生反饋,以及動作本身的密度也可以做到很高的頻率,這在狀態同步下是比較難做的。

第三,它的流量消耗是穩定的。大家應該看過《星級爭霸》的錄像,它只有幾百K的大小,這裏面只有驅動遊戲的輸入序列。幀同步只會隨着玩家數量的增多,流量纔會增長,如果玩家數量固定的話,不管你的遊戲有多複雜,你的角色有多少,流量消耗基本上都是穩定的。

四,這點延伸開來還有一個好處,就是可以更方便地實現觀戰,錄像的存儲、回放,以及基於錄像文件的後續處理。

缺點

第一,最致命的缺點是網絡要求比較高,幀同步是鎖幀的,如果有網絡的抖動,一段時間調用次數不穩定,網絡命令的延遲就會擠壓,引起卡頓。

第二,它的反外掛能力很弱,幀同步的邏輯都在客戶端裏面,你可以比較容易的修改它。但爲什麼《王者榮耀》敢用幀同步,一方面是因爲當時立項的時候開發週期很短,半年時間要做上線,要有幾十個英雄,存在時間的壓力,另一方面,MOBA類遊戲不像數值成長類的遊戲,它的玩法是基於單局的,單局的作弊修改,頂多影響這一局的勝負,不會存檔,不會出現刷多少錢刷多少好的裝備的問題,而且作弊之後我們也很容易監測到,並給予應有的懲罰,所以我們認爲這不是致命的缺點。

第三,它的斷線重回時間很長,相信臺下也有很多王者玩家,也曾碰到過閃退以後重回加載非常長的情況,甚至加載完以後遊戲也快結束了,這是幀同步比較致命的問題。

第四,它的邏輯性能優化有很大的壓力。大家應該沒有見到哪一款大型遊戲是用幀同步來做的,因爲這些遊戲的每一個邏輯對象都是需要在客戶端進行運算的。如果你做一個主城,主城裏面有上千人,上千人雖然玩家看不到它,但遊戲仍然需要對他們進行有效的邏輯運算,所以幀同步無法做非常多的對象都需要更新的遊戲場景。

 

如何保證同步

  • 同樣的邏輯幀數(10-30),渲染幀可以更高(30以上)
  • 同樣的隨機數
  • 同樣的數據,角色武器裝備等數據
  • 接管物理的update,不使用Mono的update,自己驅動各系統update代碼,並確保代碼的調用運行順序要一致
  • 功能邏輯複合多人玩法,區分音效特效震動的播放,對是否自己的判斷
  • 幀同步會動畫突然變化 不過幀同步的都無法避免吧 做一些過度和假動畫無邏輯(例如轉身和走)前端照常播放動畫 不會但不會自己切換動畫處於一個循環,只有接收到服務器的cmd進行下一個操作而轉變動畫纔會跳到下一個動畫
  • 公式儘量簡化(隨機float 轉int),並且截取一定的精度範圍(目前是小數點後3位)
     

重連

做法:接受從0開始所有幀重新快速播放到當前幀,如果幀列表count大於規定速度則按照最大速度播放,否則按照剩餘的count播放相應次數的幀。

追幀

什麼是追幀:當前玩家播放到幀比服務器的幀落後時,服務器下發多個幀,玩家便要開始快進到服務器當前幀
爲什麼要追幀:如果網絡波動,服務器會有最晚的接受幀時間,
做法:超過則下次發送多個幀,然後快進播放(多次DoAction),快進期間,不播放特效音效等不影響運行結果的邏輯

 

協議

1.roomInfo ①randseed ②role ③...
2.event ①int frame ②event type ③byte[] param
3.cmd ①int frame ②int[] cmd

 

事件

主要事件有

1.房間信息(角色數量和角色信息)
2.角色死亡/重生
3.生成怪物/Boss
4.玩家信息改變(換裝,位移)
5.遊戲時間結束

 

如何驗證同步

1.把一些關鍵的運行(例如cmd,位置,動畫,攻擊,發射子彈等)在一幀的最後,整理爲一個string然後轉hashcode,上傳(①int 幀 ②int hashcode)至服務器,服務器對比hashcode,如果hashcode不一樣,則發生了不一樣的邏輯,然後服務器去請求這一幀的詳細日誌(string DebugDetail),獲取回來有何不一樣。

2.做驗證服校驗哪裏不一樣,既是把讓服務器把cmd、相關玩家數據和隨機種子存下來,然後再播放一次本局然後一次性上傳日誌,比較差異。

 

不同步debug記錄

1.物理結果
問題:當剛體同時進入到了2個碰撞體,有可能會在不同客戶端計算出不同的結果,無法控制。
解決:不使用物理力kinimatic

2.浮點數不一樣
裁剪小數點,儘量用整數

3.不能使用unity的mono、time、 random、 Invoke,因爲時機和結果每個客戶端不確定。

 

驗證

把同步信息存下來,服務器自己跑一次,看detail debug是否一樣

 

防攻擊

1.特別是搞棋牌的項目,還有小公司沒法通過法律手段來防止別人攻擊。特別有用處。因爲高防實在太貴,用不起。設計思路如下:
2. 需要有很多ip,客戶端能夠隨時切換連接,這樣別人攻擊一個可以切換其他的進程去連接。
3. 需要保證狀態不丟失,消息不丟失不重發,顯然tcp做不到。
4. 使用udp。因爲udp是無連接的
5. 需要保證消息可靠,所以kcp是非常合理的選擇
6. 可以設計一個路由進程來轉發,udp消息通過路由再轉發給realm gate等等
7. 路由進程可以起非常多個,客戶端在連接realm或者gate之前先請求路由進程,告訴路由進程自己需要真正連接的地址,路由進程記錄下來。然後客戶端用kcp連接,路由進程把發過來的udp消息轉發給真正的地址,比如gate。所以服務端對外的是路由進程,gate realm變成了內網地址。
8. 客戶端連接會每隔2秒ping一次,ping超過10s沒有回消息則重新請求一個路由來連接。這樣別人攻擊一臺路由我們就可以不停的關閉被攻擊的路由進程,或者開啓新的路由都可以。
9.因爲udp無連接狀態,kcp會保證不丟消息會重發,所以即使換了路由進程,仍然能夠保證消息一致性

 

狀態同步

將其他玩家的狀態行爲同步的方式,一幫情況下AI邏輯,技能邏輯,戰鬥計算都由服務器運算,只是將運算的結果同步給客戶端,客戶端只需要接受服務器傳過來的狀態變化,然後更新自己本地的動作狀態、Buff狀態,位置等就可以了,但是爲了給玩家好的體驗,減少同步的數據量,客戶端也會做很多的本地運算,減少服務器同步的頻率以及數據量。

優點

第一,它的安全性非常高,外掛基本上沒有什麼能力從中收益。

第二,狀態同步對於網絡的帶寬和抖動包有更強的適應能力,即便出現了200、300的輸入延遲再恢復正常,玩家其實也感受不到不太舒服的地方。

第三,在開發遊戲過程中,它的斷線重連比較快,如果我的遊戲崩潰了,客戶端重啓之後只需要服務器把所有重要對象的狀態再同步一次過來,重新再創建出來就可以了。

第四,邏輯性能優化有優勢,它的客戶端性能優化優勢也比較明顯,比如優化時可以做裁剪,玩家看不到的角色可以不用創建,不用對它進行運算,節省消耗。

缺點

第一,它的開發效率低,相對幀同步而言要差一些,很多時候你需要保證服務器與客戶端的每一個角色對象的狀態之間保持一致,但事實上你很難做到一致。

比如客戶端和服務器端更新的頻率,對優化的一些裁剪,網絡的抖動等等,你要讓每一個狀態在客戶端同步是比較難的,而你要想調試這些東西,來優化它帶來的漏洞、不一致的現象,花費的週期也會比較長,想要達到優化好的水平也比較難。

第二,打擊感差,它比較難做出動作類遊戲打擊感和精確性。比如說你要做一個射擊類角色,他的子彈每秒鐘要產生幾十顆,基於狀態同步來做是比較難的,因爲系統在很短時間內,會產生很多數據,要通過創建、銷燬、位置運算來同步。

第三,它的流量會隨着遊戲的複雜度,而逐漸增長,比如角色的多少。希望在3G、4G的網絡條件下也能夠玩PvP,所以我們希望它對付費流量的消耗能控制在比較合理的水平,不希望打一局遊戲就消耗幾十兆的數據流量。

 

參考鏈接:

MMORPG服務器架構 https://blog.csdn.net/a6627651/article/details/47044589

tx王者 https://blog.csdn.net/anypkv/article/details/78480877

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章