幀同步遊戲開發小結
阿新 • • 發佈:2020-03-04
*本文發表於程式設計師劉宇的個人部落格,轉載請註明來源,https://www.cnblogs.com/xiaohutu/p/12402399.html*
這幾年做了一些網路同步專案,總結一下幀同步的一些東西。
## 1. 幀同步基本特點
1. 所有的邏輯行為運算都在客戶端進行,客戶端保證彼此之間執行結果的一致性。
2. 客戶端將自己的所有操作發給伺服器,伺服器轉發。
3. 伺服器維持一定的邏輯幀率向客戶端發包,每次都帶上一間隔的所有客戶端發來的操作,如果沒有就發空幀,附帶上客戶端需要執行此包的幀數。
4. 客戶端收到幀資料執行這一邏輯幀的行為,否則等待。
![](https://img2020.cnblogs.com/blog/1579144/202003/1579144-20200304155530843-1907365625.png)
## 2. 同步性的保證
- 確保需要同步部分邏輯執行次序的一致性,特別關注各種容器的底層結構以及執行過程中對容器的增刪改。
- 確保AI、物理引擎等執行結果的一致性,避免因為使用部分遊戲引擎的更新特性,導致一些AI計算的時間次序問題。
- 確保數學運算在不同cpu上的的一致性,使用定點數或者浮點數擷取等方法計算邏輯。
- 確保隨機結果基於次數的一致性,使用次數一致性的隨機演算法,如梅森旋轉演算法。
- 確保客戶端資料來源的一致性,儲存的靜態資料以及讀取過程需要特別關注。
## 3. 邏輯畫面分離
- 抽離開影象執行邏輯和關鍵幀執行邏輯的迴圈結構。
- 邏輯部分可以無畫面執行,正確的輸出結果。
- 資料關鍵幀(即執行AI的關鍵幀)可以調整,和影象幀的比例也可以調整,影象幀做好動畫、位移、旋轉等行為的平滑。
- 在一些遊戲中需要實現快速的邏輯與影象脫鉤,即迅速載入畫面,迅速解除安裝畫面,是否需要畫面由需求決定。
## 4. 樂觀鎖
- 傳統情況,每個客戶端必須回報給伺服器收到幀數,伺服器再次傳送確認包才執行幀資料,否則所有人等待。
- 現在情況,基於現在手遊的流行程度和若網路環境,手遊一般都採取樂觀鎖模式。即收到伺服器推幀後,客戶端立即執行,不等待其他人。這樣卡頓的人自己卡,不影響其他人的遊戲體驗。同時卡頓的人在收到資料後,自行加速補幀,追趕上正確的遊戲速度。
## 5. 斷線的處理
- 斷線重連:伺服器儲存好所有的開戰資料和所有的幀資料,用來做斷線重連(見7)。
- 軟重連:製作一定的遊戲策略,在遊戲畫面卡住的情況下,儘量通過從伺服器拉取增量幀資料來恢復現場。
## 6. 弱網路處理和優化
- 應對網路抖動,快取適當的幀在本地,作為抖動視窗,本地適當延後執行,這樣可以應對網路延遲較高的情況。當然快取的越多,客戶端操作操作的延遲就越高,越少則遇到未收到幀的時候有可能會卡頓。
- 如果對操作實時性要求比較高,可以製作回滾機制(Rollback)(見9),客戶端在預測的基礎上,對玩家的操作進行實時的響應,不等待伺服器資料,實時的進行行為。收到伺服器的推送後將自己的預測與伺服器下發的資料進行行為的一致性驗證,不一致則立刻回滾,執行伺服器的資料。
- 應對TCP的擁塞機制,使用RUDP一類的帶保障機制的UDP協議,避免協議擁塞導致的卡頓。
- 應對UDP丟包,首先是客戶端回包帶標籤來補發點機制,其次也可以每次都發冗餘包,比如上5個關鍵幀的所有資料。
- 協議包不一定採取Protobuf等通用結構,可以採用自定義二進位制來減流量,提高弱網路發包的成功率。
## 7. 追趕和重連的補幀
在卡頓情況和短線重連發生之後,都要在短時間內執行大量的幀資料來追趕上其他人的遊戲進度,這個週期下客戶端有一些特點,分情況看一下:
- 斷線重連時,因為其他人的當前幀數遠超過自己,此時自己的玩家輸入操作是基於很舊的資料執行,如果立即同步過去,其他人的客戶端會存在非法和不合理的情況,所以一般這個時候會遮蔽或者丟棄掉。大多數網遊都是使用Loading畫面遮蔽掉這個過程,因為玩家自知是斷線,可以理解。
- 較短時間的補幀,伺服器是可以設計為接受操作的。對於自己來說,這個操作實際時延是當前展示的邏輯幀到收到伺服器下一個最新邏輯幀的時間。因為存在延遲,對於所有客戶端來說,這個操作也有可能在執行時被標記為非法,比如攻擊一個小兵的操作,實際上過一兩幀執行的時候,小兵已經死亡。客戶端對於幀資料的處理必須要處理好異常情況,多個客戶端使用同樣的異常處理則結果仍然是同步的。
![](https://img2020.cnblogs.com/blog/1579144/202003/1579144-20200304162453794-1829563403.png)
## 8. 戰鬥錄影
這一塊對於幀同步來說天生是有優勢的,採用和斷線重連一樣的機制,按正常速度播放就可以在客戶端重播整個戰鬥過程。一個戰報資料包括:
- 開始資料(單位屬性,ID,戰場資訊等)
- 過程資料(總幀數,有操作的幀資料)
## 9. 回滾(Rollback)和高階錄影
先說說回滾的實現:
1. 首先遊戲的邏輯、資料、表現拆解的特別完美,可以實現資料變化後畫面儘量不違和的變化。
2. 將所有資料可以按照幀儲存,可以採用Attribute來採集指定變數,也自己寫好介面實現(這一步會比較複雜,但是可行),這一步我們稱之為快照(Snapshot)。
3. 在遊戲執行時,儲存一定量的幀本地資料,比如100幀。
4. 在遊戲邏輯進行預測,與伺服器資料不一致失敗後,進行資料的回滾,同時通知表現層回滾,執行相應的表現層邏輯。
這個時候,我們可以得到錄影的拖動功能:
1. 錄影播放的時候實時儲存所有快照。
2. 製作進度條,可以反覆拖動。拖動後在資料層執行上面同樣的第4步操作,回退畫面。
## 10. 防作弊
- 首先做完整的戰鬥離線校驗是沒有問題的,類似戰鬥錄影的過程,可以採用跑客戶端同一套程式碼的方式來進行。這對於伺服器來說是一個性能問題,取決於遊戲型別和資料大小。
- 根據錄影資料驗證合法性的基礎上,還要加入技能CD等確認客戶端輸入合法性的校驗。
- 對於多個客戶端上報不同結果的情況,需要根據不同情況具體分析,如果是多人對戰專案,傾向於採信結果相同多的一方。無論如何都要進行離線校驗。
- 同時也可以進行實時線上校驗,採用和客戶端一套程式碼執行在伺服器的形式,來模擬一個客戶端驗證各種資料的結果。
- 對於開圖等客戶端外掛,需要額外手段防護,無法通過幀同步機制來防止。
- 對於加速外掛,天生可以防止,不存在問題。
## 11. 同步性的除錯
一個成熟的專案,中期一定要經歷大量的除錯來能保證幀同步一致性,這裡有一些我用過的技術手段和方法。
1. 首先戰鬥校驗服,客戶端的釋出全自動化,通過遊戲更新機制裡的程式版本號和資源版本號來保證客戶端資源的一致性。
2. 戰鬥校驗服也自動釋出一個客戶端的純邏輯執行版本,用來離線在客戶端除錯戰鬥純邏輯過程。
3. 在戰鬥過程中加入日誌用來檢視除錯,在戰鬥校驗服、客戶端除錯模式、客戶端執行模式下均生成同格式的日誌,用來進行比對。
4. 不一致的戰鬥資料通過戰鬥校驗服、客戶端除錯模式、客戶端執行模式的日誌進行檢視比對。
5. 有了以上機制後,製作全自動校驗驗證的程式,採集一定的戰鬥用例,每次發版本或者長期多機器、多平臺自動化24H執行,避免修改導致的一致性問題。
## 12. 總結
- 總體來說,幀同步對於伺服器壓力很小,承載較高、流量也小。
- 對於客戶端來說,實現簡單,除錯難度較高,作為一個實現實時戰鬥的放來,價效比較高。
- 幀同步比較適用於弱聯網情況下的強同步遊戲,有足夠多的方式應對弱聯網環境。
- 幀同步製作需要中途加入的遊戲比較簡單。
- 幀同步實現錄影、校驗等難度不高。
寫到這裡差不多把個人的一些經驗與大家分享完畢,有問題歡迎與我聯絡,謝謝大家的