技能模块的防外挂机制和同步机制优化
游戲在真實的環境中,有些特殊情況需要處理,本文介紹技能模塊是如何處理人為作弊和現實中的網絡導致的一些問題。
主要介紹三個功能:
1.防外掛
2.網絡延遲問題解決
3.網絡卡頓和抖動
4.流量優化
注意,本文默認介紹的是玩家的技能處理,也就是技能的控制端在玩家的客戶端。對于控制端在服務器的小怪,基本沒有以上問題。
每個游戲的技能系統的實現不同,處理方式也有可能不太一樣,本文所使用的技能系統參考之前寫的文章。
1.防外掛
由于技能是客戶端先行,因此技能模塊很多邏輯是放在客戶端的,有客戶端控制技能流程并且通知服務器執行相應的功能。由此可見,技能是由客戶端發起的,服務端必須對收到的既能執行命令進行驗證以保證技能確實是可用的,防止玩家通過外掛重復發送技能釋放消息無限次釋放技能。
每個游戲技能系統實現不同,可能對應的邏輯也不太一樣。基本原則是:
1.服務端保存技能釋放可用性的相關信息,比如技能CD、技能藍量等。
2.技能真正的釋放寫在服務端,客戶端只是提前播放技能的表現(動作、特效)。
3.服務端每次真正的釋放技能之前,對技能進行判斷是否可用。
4.對于收到的技能執行消息,根據實現系統的規則進行相應驗證。
下面,以我們的技能系統為例,介紹我們是如何實現防外掛的。
在我們系統中,包括三類同步消息:
?
- 技能根節點enter (root_enter): 表示一個大技能的進入
- 技能葉子節點enter(action_enter): 表示一個技能樹的執行節點的進入。
- 根節點exit(root_exit) :表示大技能結束
服務端會接受到客戶端發來的這三種技能消息,root_enter表示一個大技能的開始,action_enter表示一個技能執行節點的開始執行。root_exit和防外掛沒有關系。
由于技能的信息都是以root_enter來控制的,比如技能CD、技能耗藍和沉默/暈眩等導致的技能是否可用,因此,當服務端收到root_enter的時候,首先要判斷這個技能是否真的可以釋放,判斷后進入相關邏輯。
action_enter是技能真正的執行消息,技能模塊并沒有方法判斷一個執行節點(技能樹葉子節點)是否可用,因此,當收到action_enter的消息時,只能根據root節點的信息進行判斷。我們進行了兩種判斷:
?
- 判斷一:在root_enter和root_exit執行期間,表示正在執行這個大技能,收到action_enter后,判斷這個action是否屬于正在執行的大技能葉子節點,若不屬于,不能執行。
- 判斷二:我們還判斷了action_enter消息對應的執行節點的順序,保證執行節點是按照合法的順序執行的,而不能一直執行某一個特別牛逼的葉子節點。
- 此外,服務端執行action節點的時候,不能同時執行多個,每次只能執行一個action節點,并且需要持續相應的時間(action節點的后搖時間),上一個action節點執行結束后才能執行下一個節點。
基于以上機制,可以保證服務端收到的技能消息只有合法的消息才可以執行。
2.網絡延遲
在真實的網絡環境中,網絡延遲是難免的。造成的結果是,服務端一直晚于客戶端。為了解決著這個問題,一般采取的方式是基于網絡延遲時間讓服務端加快執行速度,去追趕客戶端。
以技能apply為例,當server端收到action_enter消息后,根據當前時間和客戶端開始時間可以計算出網絡延遲,將服務端的前搖時間減少兩個網絡延遲,當客戶端收到apply消息時,正好是客戶端的apply時間。
?
3.網絡波動和卡頓
對于手機游戲來說,網絡波動和賣QQ賬號平臺卡頓也是難免的,這種情況造成的結果就是,原本按一定的順序以一定的時間間隔到達服務器/客戶端的消息,可能同時到達了服務器/客戶端,或者時間間隔忽大忽小。
一般來說,當服務器由于網絡卡頓同時接收到多個技能開始執行的消息時,可以通過兩種方式進行處理。
1.接到技能執行消息后馬上執行,這樣導致的問題時可能在同一幀收到多條技能執行消息,并且在同一幀執行多個技能。這個策略的好處是處理方式比較簡單,而且能讓服務器盡快的跟客戶端同步。但是為了防止玩家使用外掛同時發送多個技能執行請求,這個策略是不可行的。
2.當接收到多條技能執行消息時,按序依次執行技能,每個技能的執行時間結束后,才執行下一條技能。這種策略的問題是,服務器的延遲與客戶端較大,如果玩家一直在不停的放技能,會導致服務器與客戶端的延遲越來越大。
客戶端和服務端采取不同的處理方式。
3.1 proxy服務端(主控端是玩家控制的客戶端)
服務器是技能真正執行的地方,因此需要保證技能正確的執行。因此,服務端基于第二種方式解決網絡卡頓,同時增加了一些邏輯,以保證服務端不會和客戶端延遲過大。
3.1.1 消息隊列
proxy服務端以隊列的形式保存下來收到的技能消息并依次執行。
我們系統中存在三種技能同步信息:
- root_enter:表示技能樹根結點進入執行,表示一個技能樹開始。
- action_enter :表示技能的執行節點進入執行,表示一個技能執行模塊開始執行,有一個執行模塊有后搖時間,根據后搖時間,他會自動結束。
- root_exit:表示技能樹結束。
當服務端收到技能同步消息后,就將消息存入隊列,技能執行模塊就根據隊列依次執行,其中,action_enter會執行一段時間,后搖時間點到達后結束。root_enter和root_exit對技能執行狀態進行控制。
3.1.2 防止服務端延遲過大
在某些情況下,服務端可能遲于戶端較長時間。比如網絡卡頓,導致客戶端多次釋放技能的消息同時到達服務端。為了解決這種問題,我們通過兩種機制,讓服務端追趕客戶端。
?
- 當接收到一個新的root_enter信息時,馬上清空掉隊列中的所有技能消息,執行隊列中對應的root_exit消息。然后執行新的root_enter信息。此策略表現是:當玩家執行一個新的技能,服務端之前還沒有執行的技能就不再執行了。
- 葉子節點的持續時間(后搖時間)根據網絡延遲進行一定的減少,給定一個系數比如0.8,一方面保證服務端不會快速的執行多個action節點,同時可以讓服務端盡快的追上客戶端。
3.2 proxy客戶端 (主控端是玩家控制的客戶端或者是服務器控制的怪物)
客戶端只是執行技能的表現,在網絡條件較差的情況下,我們只要保證游戲的正確性(不出錯誤,不影響服務器正確運行,網絡條件變好后游戲可以正確運行)即可,至于表現和用戶體驗,盡力就可以了。
在我們游戲中,客戶端的proxy端采用的是接到消息后馬上執行的策略。客戶端接到既能執行信息,那么就把之前正在執行的技能停止掉,然后執行新的就好了。
4.流量優化
流量的優化基本上沒有太多通用的技巧,最基本也是最重要的就是:不要同步沒有意義的消息。
這句話是廢話,但是也是流量優化的指導方向。聽起來很簡單,但是實現起來非常難,甚至想不同步冗余信息是不可能的。
為什么說這件事很難,甚至是不可能的呢?
一,只有梳理清楚了執行邏輯,才能確定哪些同步消息是必要的,哪些是冗余的。執行邏輯一定要清晰。
二,比如一條消息,某些情況是不用同步的,有的情況又要同步。那么發,還是不發。再細節一點,比如一個參數,有的情況不需要同步,有的情況需要同步。如果對每種情況進行特殊化編寫代碼,代碼可讀性可能較差,如果發送一個通用的同步消息,可能消息量比較大。那么,做到什么程度?大概做到游戲流量可以接受的成都就好了。
還有些tips可以減小流量信息,比如:
有些常見的string,甚至是所有的string,可以將其轉為一個int,客戶端服務端都知道這個int代表什么 即可。
有些float,可以通過乘以100轉為int傳到客戶端,客戶端再除以100即可。
等...
5.其他
本文基于底層的消息是保證消息順序、保證不掉包、保證消息不被篡改、保證消息沒有重發的。這件事,本身實現起來可能更加復雜。
總結
以上是生活随笔為你收集整理的技能模块的防外挂机制和同步机制优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 揭秘《英雄联盟》客户端更新运行自动化测试
- 下一篇: 《聚爆Implosion》性能精析:这是