MMO即時戰鬥:地圖角色同步管理和防作弊實現

皮皮豬頭發表於2014-11-23


一、前言

      無論是端遊、頁遊、手遊如果是採用了MMO即時戰鬥遊戲模式,基本都會遇到同屏多角色實時移動、釋放技能、戰鬥等場景,於是自然也需要實現如何管理同屏內各種角色的資訊同步:例如角色的位置、以及角色身上的裝備、時裝、buffer等狀態的實時切換。同步在網路遊戲中是非常重要的,它保證了每個玩家在螢幕上看到的東西大體是一樣的,解決同步問題的最簡單的方法就是把每個玩家的動作都向其他玩家廣播一遍,這裡其實就存在一些問題:1向哪些玩家廣播,廣播哪些訊息;2如果網路延遲怎麼辦。角色的定義一般包括人物、怪物、寵物、NPC等,由於這各種角色在地圖上基本處於隨時不規則移動並且各種屬性資訊也處於不斷變化中(例如:變身、穿脫裝備,甚至使用隱身藥水),所以需要實現地圖的區塊上各種角色的列表管理、切換地圖、進出區塊管理,實時同步角色的位置資訊,以及附近角色的屬性資訊變化到遊戲內相應的玩家身上,而且這些資訊的同步需要實時,否則基本就失去了即時戰鬥的意義。一般會採用長連線的方式,方便實時推送互動資訊。同時由於MMO網路遊戲環境的複雜性,管理好角色資訊的同時還需要保證遊戲的公平性,防止作弊、外掛,例如:判定人物的移動速度異常或者瞬間移動,糾正人物釋放技能的時間間隔等,相信只要在公網運營過的遊戲都多少會遇到防作弊的問題。本文主要結合參與開發並在外網運營了幾年的一款MMORPG遊戲做討論和分析,遊戲規模國內最高同時30w線上,同區最高上w人,相信會有一定的實戰參考意義,當然也有討論和改進的空間,這也是寫這篇文章的主要目的。

二、 地圖以及角色管理

      無論是3D還是2D遊戲:既然是即時地圖戰鬥,那就自然有空間的概念,於是就產生了地圖,一般遊戲內玩家最經常發生的互動也是在地圖上面發生的。mmorpg的地圖一般會有固定的一些屬性:例如:地圖的寬度、高度、最大角色數、地圖上面怪物的AI、以及常用的九宮格劃分割槽塊大小等等屬性。地圖寬高度用於控制地圖的大小,最大角色數用於控制地圖的最大承載容量,防止過載,影響玩家體驗。例如:圖1對地圖的部分關鍵屬性進行定義

 



2.1地圖區塊劃分

      通常的遊戲玩法:地圖上面的玩家在地圖裡面只需要看到視野內周圍發生的事情,並不需要關心不同地圖,甚至相同地圖離自己很遠的地方此刻正在發生的實時場景,即使要關心,一般也是通過聊天公告等資訊同步,並不需要收看現場直播)。於是,對地圖採用分而治之的方法,把每張地圖進行區塊切分,定義好區塊的大小,例如圖1採用正方形的劃分方法,規定每個區塊的邊長為6,一般區塊的大小不會經常進行隨意變動(除非在一些特殊的副本地圖裡面,該值如果進行了變化則需要進行特殊處理)這就是地圖區塊的概念。於是每個線上玩家在地圖上面都會被定位到屬於自己的區塊,而當玩家在地圖上面移動,則會在不同的區塊之間進行來回的切換。同時,玩家在地圖裡面必然需要實時看到周圍地圖發生的場景,一般採用九宮格的方式,如圖23.:也就是說會實時同步包括玩家所在區塊在內的周邊9個區塊的角色資訊給予相應的玩家,理論上玩家只能看到9宮內發生的事情。


2.2地圖管理

      劃分好了地圖區塊之後,地圖的管理至少還要包括:a阻擋的資訊:包括靜態阻擋和動態阻擋:角色移動的同時需要考慮地圖區塊裡面的阻擋資訊(例如:來自角色阻擋、來自地圖固定建築的阻擋等)b角色管理:需要管理地圖上面角色實時資訊,並且維護各個區塊的最新角色實時列表資訊:用於九宮格內玩家資訊的同步。對於進入地圖固定區塊的玩家需要實時同步自己的資訊給予附近的玩家,告訴他們有角色進入視野了,相反也要同步區塊周圍的角色資訊給該玩家,同時,對於離開地圖區塊的玩家,需要同步資訊告訴附近的玩家離開視野的訊息,保證下一幀該角色不會再出現在該區塊上。而處在同個9宮格內的玩家,也需要互相同步屬性資訊,保證看到的是最新的角色屬性變化位置資訊等;並且地圖上面的NPC、怪物等角色自動重新整理也需要地圖邏輯來處理,例如怪物死亡之後,需要處理怪物退出遊戲世界,一般還要讓怪物經過一段時間自動復活,重新加入地圖,另外還有地圖上面怪物的AI,會在另外一篇文章單獨討論。

      具體角色在地圖上面管理程式碼的實現:針對所有角色我們首先採用定時重新整理的機制,在所有的角色身上繫結定時器,例如:GamePlayer,GameMonster,GameNpc定時觸發重新整理機制:根據玩家實時所在的地圖比較前後所在的區塊是否一致,如果不一致,自然就需要處理附近玩家有角色進出視野的資訊。例如:角色A定時觸發了重新整理機制,發現已經從地圖亞特蘭蒂斯區塊99進入到了亞特蘭蒂斯98區塊,這時,自然就要重新計算玩家的九宮格區塊變化,通知相關有區塊資訊變化上面的地圖角色位置資訊:並且需要實時維護一份每個區塊每張地圖上面的角色列表,這樣做的目的:作為地圖管理者,有必要知道當前我的地圖上到底都有誰,常用於玩家附近的聊天,玩家同地圖的聊天,並且根據玩法一般還有地圖刷怪通知該地圖所有玩家的資訊等需求。另外,單獨針對玩家的位置資訊管理,則還跟遊戲的特定玩法有關係,例如可以飛地圖的遊戲,則當玩家實時切換地圖之後,則會直接觸發進出區塊視野的資訊,而並不需要等到定時器觸發來更新角色位置資訊,還有玩家重新登入或者退出遊戲,自然而然也要實時處理相應的位置同步資訊;還有玩家換裝、使用技能、上下坐騎等都即時發訊息通知九宮格內的玩家同步屬性資訊

三、 人物的移動

      對於mmorpg,玩家的移動幾乎無時不在,並且相對於怪物的移動,寵物的移動等,玩家的移動更加核心,更加複雜不可控。特別是在大規模團戰中,玩家會經常移動,於是需要管理好地圖上玩家的移動,如果管理不好,則會出現大規模的外掛等,嚴重影響遊戲的公平性,對於整個遊戲也幾乎是毀滅性的打擊

3.1人物移動實現方法

      通常對於遊戲內玩家的移動有幾種處理方法:1客戶端只通知伺服器要移動的位置,但並不需要經過後臺的驗證就直接開始移動了,通常伺服器需要對最終客戶端移動的位置進行校驗,如果沒有該步檢測,那外掛就可以為所欲為了2客戶端每一次移動都需要通過伺服器的驗證,然後再進行移動,該方法在網路延遲的情況下,會變得比較不流暢,給玩家帶來很不爽的感覺。方法1同樣存在問題:同步的誤差,特別是在網路延遲特別嚴重的時候:比如有一個玩家A向伺服器發了條指令,說我現在在P1點,要去P2點。指令發出的時間是T0,伺服器收到指令的時間是T1,然後向周圍的玩家廣播這條訊息,訊息的內容是玩家AP1P2”有一個在A附近的玩家B,收到伺服器的這則廣播的訊息的時間是T2,然後開始在客戶端上畫圖,AP1P2點。這個時候就存在一個不同步的問題,玩家A和玩家B的螢幕上顯示的畫面相差了T2-T1的時間,要解決該問題,參考了之前的一篇文章,大致的內容如下:“有個解決方案:預測拉扯,首先要定義一個值叫:預測誤差。然後需要在伺服器端每個玩家連線的類裡面加一項屬性,叫latency,然後在玩家登陸的時候,對客戶端的時間和伺服器的時間進行比較,得出來的差值儲存在latency裡面。還是上面的那個例子,伺服器廣播訊息的時候,就根據要廣播物件的latency,計算出一個客戶端的CurrentTime,然後在訊息頭裡麵包含這個CurrentTime,然後再進行廣播。並且同時在玩家A的客戶端本地建立一個佇列,儲存該條訊息,直到獲得伺服器驗證就從未被驗證的訊息佇列裡面將該訊息刪除,如果驗證失敗,則會被拉扯回P1點。然後當玩家B收到了伺服器發過來的訊息玩家AP1P2”這個時候就檢查訊息裡面伺服器發出的時間和本地時間做比較,如果大於定義的預測誤差,就算出在T2這個時間,玩家A的螢幕上走到的地點P3,然後把玩家B螢幕上的玩家A直接拉扯到P3,再繼續走下去,這樣就能保證同步。更進一步,為了保證客戶端執行起來更加smooth,我並不推薦直接把玩家拉扯過去,而是算出P3偏後的一點P4,然後用(P4-P1)/T(P4-P3)來算出一個很快的速度S,然後讓玩家A用速度S快速移動到P4,這樣的處理方法是比較合理的,這種解決方案的原形在國際上被稱為(Full plesiochronous),當然,該原形被我篡改了很多來適應網路遊戲的同步,所以而變成所謂的:預測拉扯”

 

 

 

 

      方法1實現:進行人物移動管理,需要定義以下相應的移動訊息:具體的訊息定義如下

(a)MSG_PLAYERMOVINGPOSTOSERVER //客戶端向伺服器端傳送移動中玩家位置改變

(b)MSG_PLAYERMOVINGPOSANDDIRTOSERVER, //移動中玩家位置和朝向改變

(c)MSG_PLAYERPOSTOSERVER,                //原地不動玩家的位置訊息

(d)MSG_PLAYERPOSANDDIRTOSERVER,        //原地不動玩家的位置和朝向訊息

 

      訊息ab負責向伺服器同步人物需要移動到的目標位置和朝向資訊,伺服器需要對該位置資訊進行阻擋、狀態判斷等合法性檢測通過後,則同步角色位置資訊到9宮格內的其它角色,相反如果失敗例如移動到阻擋裡面,則需要通知客戶端糾正位置。訊息cd則同時用於前後臺校驗玩家的位置資訊,例如角色一定時間內移動後最終停下來的位置。

 

四、 防作弊

      常用的前後端訊息加密,以及客戶端加殼的機制幾乎已經是通用的做法,所以這裡不做重複,而且再高明的加密或者加殼幾乎都有被破解的可能,但這些機制依然要堅持使用,至少可以提高作弊的成本,可以延長遊戲的壽命,下面再描述我們目前除了訊息加密和加殼之外採用的方法

限制客戶端傳送移動訊息的頻率:一般遊戲內玩家並不需要進行太過於頻繁的移動,就算需要頻繁的移動客戶端也可以對移動進行合併處理再上報移動位置資訊,所以對於頻繁的移動訊息完全可以當做非法請求不處理。目的用於防止外掛封包頻繁的傳送移動訊息,進行非法的快速移動(例如運營中發現玩家使用變速齒輪等外掛,用於搶掉落寶箱等場景,會有玩家進行瞬移到寶箱附近拿走物品,這時候守門的人就崩潰了,嚴重影響了遊戲的公平性)

移動距離檢測:記錄客戶端每次傳送移動訊息的伺服器時間間隔,根據人物的正常移動速度,算出合法的移動範圍(一般需要加上一定的誤差,由於網路的延遲等原因,不可能做到100%精確),如果發現不正常的移動速度,一般先採用和平的方法,讓該移動訊息失效。目的用於防止外掛封包傳送不符合人物移動速度的位移資訊

訊息時間校驗:使用外掛的玩家,例如變速齒輪等外掛,而且變速齒輪可以調整倍數,所以一般可以嘗試出遊戲的檢測頻率,因此必須採取手段防止玩家使用該外掛。分析出變速齒輪的原理,一般是通過修改API函式GETTICKCOUNTTIMEGETTIME,騙過了遊戲和程式的定時器導致遊戲和程式速度被改變。服務端傳送時間種子到客戶端.客戶端做個差值.舉個例子:服務端發來的種子是timeGetTime()=2000,客戶端本地取時間是timeGetTime()=1000那麼差值就是1000客戶端所有的協議中增加時間字clienttime=timeGetTime()+1000到服務端。服務端取當前時間對這個時間做個容錯校驗.容錯範圍需要你自己調節.一般最好設大點.不然容易誤判.

五、 運營中遇到的問題和優化空間

5.1伺服器效能瓶頸

      即時戰鬥類遊戲一般都會設計有跨服戰、國戰等這樣的玩法,會遇到某時段同屏角色數非常多的特殊場景,這時候大量的角色戰鬥中移動和釋放技能,上下坐騎、必然會造成訊息量暴增,伺服器壓力驟增。以線上運營的遊戲為例,解決辦法:

      首先,對峰值期間的訊息進行統計分析,對頻繁傳送並且流量大的訊息進行重點監測,例如:分析出來大量角色移動進入區塊,同步角色資訊包括人物身上的時裝,坐騎,寵物、裝備等,會有一個峰值。但遊戲中一般大規模團戰的地圖中,玩家一般最先關心的是敵人的動向位置資訊,反而對人物的坐騎,時裝,裝備等資訊可以延後,於是可以對某些特殊的場景例如國戰地圖,跨服戰地圖進行特殊的重新整理機制進行優化,當區塊內角色數到達一定數量後,同步資訊只同步人物位置,模型等資訊,減少訊息的流量

      其次,為了防止高峰時期伺服器處理訊息量過大,待處理訊息佇列以及傳送佇列擁擠,造成雪崩。對訊息進行分級別定義,定義訊息的時候進行訊息級別定義,目前分為低、中、高三種訊息型別,並且限制每種型別在等待處理的訊息佇列中的最大個數,每種訊息型別在佇列中大於特定的值,則直接丟棄,不處理。例如:伺服器ping訊息,人物跳躍等則可以定義為優先順序低的訊息,同理對於伺服器需要傳送出去的訊息包也進行分級

實現方法如下圖:



5.2刷錢刷經驗

      一般外網運營一段時間的遊戲很多都會遇到刷錢刷經驗的bug,也許一些沒有交易系統或者休閒類的遊戲不會遇到,不過反正我們遇到了,就算沒遇到做好預防措施也是必要的。解決方案是:請數值策劃定製好根據遊戲玩法角色對應一天最多能獲得多少經驗和金幣,由伺服器進行合法性檢測,如果超過了閥值則必須採取處理措施。我們模仿了現實社會,給遊戲設計了一張監獄地圖,監獄顧名思義就是給犯法的人準備的,遊戲裡面發現有作弊,或者刷錢刷經驗等的行為都會自動被傳送到該地圖,該地圖沒有傳送點,只能一直呆在裡面不能打怪升級也不能交易等諸多限制,進入該地圖的玩家只有等坐牢時間到期了或者通過客服申訴成功,才會被傳送出該地圖

相關文章