[譯]揭秘英雄聯盟的數據服務器

譯自:Riot Games Engineering

杰微刊劉曉鵬翻譯:揭秘英雄聯盟的數據服務器

Hey,大家好!我是 Bill “LtRandolph” Clark,一名英雄聯盟的游戲工程師。許多 Rioter 工程師關注大量的內容需要直接發送給玩家問題——這是兩個我最近最喜歡的例子之一,包括最新的冠軍Jhin及項目重構的支持。而我的團隊使得這個過程變得又快有簡單。

我們有一個簡單的目標:即允許參加游戲試玩項目的暴民,能夠創建兩倍于任何給定的LoL(英雄聯盟)補丁的內容。這說起來容易,但是執行起來卻是一個充滿挑戰的任務。

今天,我們討論實現這一目標我們所鋪設的基礎:Riot 游戲數據服務器(GDS)。雖然這是一篇技術文章,但是我會站在一個較高的層次來解釋這個問題。如果你是一個在做多系統間傳送數據工作的工程師,我希望這能讓你特別感興趣。

游戲數據:

首先,我們了解一些背景。在LoL的工作中,存在兩種類型的游戲數據:一種是 key-value 對,被稱為屬性數據(如 Black Cleaver HP 獎金是300),另一種是不透明的二進制數據(如,大文本、動畫和視頻)。在這篇文章中,我們只討論屬性數據,二進制數據處理是未來潛在的一篇博文。

在LoL的所有歷史中,屬性數據由一堆松散、混亂的文件組成,這些文件存儲在一個大的名為 DATA 的文件夾中。

早期,我們將數據存儲在.ini的文件中(對,就是 Windows 下 .ini的文件格式)。類似如下所示:


沒有漂亮的界面


當然,我創建這個例子是為了強調一些我們在編輯.ini文件時遇到的一些共同的問題。這離用戶友的界面相差甚遠。編輯原始文本時非常容易混亂——缺乏重要的內容,而其他字段又重復。設計者們每天不得不處理這種混亂,這里總共有 977 種法術,這些功能(當然忽略)位于“MissileEffect=AnnieBasicAttack_mis.troy”行中,在很早的LoL開發中,每個冠軍涉及一個令人愉快的場景:“Death=Cardmaster_Death.wav。”

下面是當前數據系統面臨的一些關鍵問題:

1、使用 Notepad++ 來編輯屬性數據

2、對已存在的字段沒有清晰的定義

3、缺乏類型安全

4、多人同時編輯同一個文件時會有合并沖突問題

5、繁瑣的并行版本(活躍(Live)版、公測版(PBE)及內部版本)

6、松散的文件鏈接;只有短名稱和隱藏的搜索路徑

游戲數據服務器

我們特意設計一個游戲數據服務器系統來定位這些問題。最基礎的是 RiotGameDataServer.exe——一段運行在每個開發者機器上的小程序。它以一個 Riot 拳頭形式顯示在工具欄,它所做的工作是連接屬性數據與計算機上的程序


準備著的GDS

GDS 為其他工具抽取出文件和數據的管理方式,所以這些工具只需要關注傳送過來數據的展示和編輯。我將其類比于操作系統窗口創建的抽象來思考,所以一個開發者只需要關注窗口該如何顯示即可。GDS 工具還包括許多內部開發工具,也有第三方工具,如 Maya 和 Photoshop。它們都通過基于 JSON 格式數據的 RPC API 與 GDS 進行通信。

關于一份整潔的 RPC API,我們可以很容易的通過使用一個名為Swagger的標準來生成一個文檔頁,它列出了所有的有效函數。這是 GDS 暴露的一小部分函數子集:

Swagger 文檔

GDS 屬性數據存在一個名叫 PROPERTIES 的文件夾中。該文件夾最終將包含所有英雄聯盟的屬性數據。當一個工具需要識別出在什么情況下 Black Cleaver 是 Pantheon 最喜歡的武器時,它就會給 localhost:1300(GDS 監聽的端口)發一個 HTTP 請求。當接收到一個“get?path=Items/BlackCleaver”請求時,GDS 就會去 PROPERTIES/Items/BlackCleaver.json文件中查找。響應結果類似如下所示:


稍微漂亮一點

當某個工具想要改變 Black Cleaver 造成的傷害值時,該工具需要發送另一條命令到localhost(或 127.0.0.1)的 1300 端口上,這次需要發送的指令是“et&path=PROPERTIES/Items/BlackCleaver.FlatHPMod&value=1000.”。GDS 工具將從源碼控制工具(Perforce)中獲取到指定的文件,并編輯對應的值,然后將成功或失敗的結果返回給頁面。因此,任何工具都可以很簡單的修改屬性數據文件,而不需要考慮數據的格式,文件操作或者其他復雜的因素。

這樣,我們就很容易創建工具,如RiotEditor,來解決問題 #1:使用 Notepad++ 來編輯屬性數據。


現在,我們總算有點結果了

屬性標記

對任何給定的類型,非常重要的一點是識別出其實際在的字段,這樣我們才能知道用戶可以編輯什么。為了完成這項工作,我們維護了一個環環相扣的宏與magic 模板集合,該集合允許我們在工程代碼里面直接標注類型。大概形式如下所示:


宏的修改

注意宏:PROPERTY_CLASS,PROPERTY_START,PROPERTY及 PROPERTY_END。它們負責兩項主要任務:

1、告知類定義了哪些出口,類的哪些字段應該是可編輯的。

2、告知屬性加載系統內存的偏移量,以便在運行時載入屬性值。

PROPERTY 宏可通過特定的簡單模板函數自動推斷類型。我們可以引用復雜類型,如BoundingVolume,只需要提供它們擁有的子屬性的標注。我們也可以跳過某些字段,如mRuntimeNumber,這意味著它們不會在 GDS 中暴露出來。

這是 GDS 中使用的 JSON 定義的結果:


Aww yiss

屬性標記解決了問題 #2 和 #3:分別是對已存在的字段沒有清晰的定義和沒有類型安全。

GDS 除了為其他工具抽取出文件和數據的管理方式外,還做了一件相當酷的事情,就是為 Riot 開發工程師提供一項技術,我們稱之為“層”。一層代表了一個可以關閉或打開的功能,我們可以為一個新的冠軍,一種新皮膚,一個游戲模型或一次大的重新平衡創建一個層。然后,當一個內容創建者在某一功能上工作時,他們可以告訴 GDS,例如,“激活”APItemRework層。

之后,GDS 會對APItemRework層包含的文件任何改變打上標簽。在磁盤上,這看起來像一個文件,我們稱之為RabadonsDeathcap.json,挨著該文件的另一個文件,名為RabadonsDeathcap.APItemRework.json。在第二個層文件中,GDS 簡單的標記每個被改變的字段為 delta。保存前后兩個值就是為了解決之后的合并沖突。這兩個文件并排看起來如下所示:


左側:基礎數據;右側:delta 層

由于我們捕獲了單個字段的改變,我們不再需要擔心多個 Rioters 同時修改同一個文件了,除非他們修改完全相同的字段。如果他們修改了同一個字段,我們也存儲了修改前后的值,所以可以識別出沖突。這樣做的好處是可以防止一個發包以后的bug:在創建 DJ Sona,團隊意外的將其狀態恢復到了上一個版本。

現在,我們解決了問題 #4:多人同時編輯同一個文件時的合并沖突問題。

分層,讓我們捕獲了某一特定功能的所有改變。為了真正發布這些功能,我們需要引入一個概念,叫做“游戲版本”。一個游戲版本定義了一個完整的打開層的集合。每個游戲版本保存了一個層名稱的簡單 JSON 列表。在任何給定的時間點,我們維護幾個主要的游戲版本:

1、Alpha:內部測試、準備發布到公測服務器上的功能集合。

2、Beta:當前公測服務器上的功能集合,如Jhin。要注意的是,Beta 版繼承了 Release 版的功能列表,所以它擁有最近更新的功能,類似于季前賽。

3、Release:當前正式服務器上的功能集合,如閃亮新補丁包 6.3。

還有一個很酷的特性是一個功能從一個版本遷移到另一版本只需要在我們層管理窗口執行一次拖拽操作即可,有了這個以后,我們不再需要在某個功能發生改變時,需將成百上千個文件從一個地方拖到另一個地方了。

這樣就很容易解決了問題 #5:全文件覆蓋的并發版本(活躍版、公測版及內部版本)

總結:

希望這篇文章能讓你體會到我們是如何使得LoL開發更有效率的。對于細心的讀者,你可能發現我們沒有深入討論問題 #6:松散的文件鏈接;只有短名稱和隱藏的搜索路徑。我留下這個問題沒解決是因為這個問題比預期的更麻煩——存在冗余、避免不必要的代碼重構、增加數據遷移、補丁大小等問題,因此,值得專門為此寫一篇完整的博客。

如果你對我們如何改變英雄聯盟中混亂的游戲數據的某方面感興趣,請務必在評論中告知我們。

更多精彩譯文

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容