妖尾歷經(jīng)幾年開發(fā),終于在今年6月底順利上線,至今運(yùn)營兩個多月,筆者從2017年初參與開發(fā),主要負(fù)責(zé)妖尾戰(zhàn)斗系統(tǒng)開發(fā),一路解決了一些技術(shù)問題,踩了一些坑,感覺有不少點是值得記錄和分享的,希望能借幾篇文字,系統(tǒng)性總結(jié)MMORPG戰(zhàn)斗系統(tǒng)的開發(fā)經(jīng)驗。
本文主要介紹戰(zhàn)斗錄像系統(tǒng),戰(zhàn)斗錄像基本是所有MMORPG游戲的標(biāo)配系統(tǒng),它同時也能成為開發(fā)調(diào)試?yán)?,在整個開發(fā)階段扮演重要角色。
首先是調(diào)試?yán)?br>
一些項目組開發(fā)戰(zhàn)斗系統(tǒng)時,可能會優(yōu)先開發(fā)涉及表現(xiàn)的相關(guān)功能,迭代的新增戰(zhàn)斗表現(xiàn),修復(fù)Bug,直到整個戰(zhàn)斗表現(xiàn)看起來相當(dāng)完整了,到了后期再應(yīng)策劃要求,補(bǔ)充戰(zhàn)斗錄像系統(tǒng)。筆者項目是在開發(fā)中期加入戰(zhàn)斗錄像功能的,在經(jīng)歷完整個戰(zhàn)斗開發(fā)階段后,得出的經(jīng)驗是
盡可能在基礎(chǔ)框架搭建、前后臺開始聯(lián)調(diào)階段就同步開發(fā)戰(zhàn)斗錄像系統(tǒng),利用戰(zhàn)斗錄像來輔助系統(tǒng)開發(fā)、調(diào)試
。到了項目中后期,戰(zhàn)斗錄像會發(fā)揮更大的用處,此時戰(zhàn)斗系統(tǒng)已經(jīng)提交到SVN版本控制,項目組所有人都可以體驗到戰(zhàn)斗系統(tǒng),所有人都或多或少地扮演測試人員的角色,項目群會頻繁地反饋戰(zhàn)斗系統(tǒng)的表現(xiàn)問題,諸如報錯、卡死,單位詐尸等等,什么反饋都會有,總之發(fā)揮你的想象力。當(dāng)時開發(fā)會頻繁地奔波于各個項目組成員的電腦面前,溝通、查看日志,嘗試弄清問題,有了戰(zhàn)斗錄像后,我們會讓對方給錄像文件,在本地環(huán)境重放戰(zhàn)斗錄像,重現(xiàn)現(xiàn)場慢慢定位問題。
戰(zhàn)斗錄像能多大程度的輔助開發(fā)調(diào)試,取決于相關(guān)工具鏈有多完善,下面介紹妖尾項目對于工具鏈的打造。首先簡單看下戰(zhàn)斗錄像框架:
一般來說,網(wǎng)絡(luò)底層往上還會有一層業(yè)務(wù)網(wǎng)絡(luò)層,妖尾的業(yè)務(wù)網(wǎng)絡(luò)層分成兩個,一個負(fù)責(zé)普通業(yè)務(wù)邏輯,一個網(wǎng)絡(luò)層供戰(zhàn)斗專用。通過在戰(zhàn)斗網(wǎng)絡(luò)層接口插樁,戰(zhàn)斗錄像模塊就能收集一場戰(zhàn)斗的所有數(shù)據(jù)。戰(zhàn)斗結(jié)束后,自動將該場戰(zhàn)斗數(shù)據(jù)保存成本地錄像文件,當(dāng)然,我們還要提供手動保存錄像接口,以便戰(zhàn)斗中途卡死了也能保存錄像。雖然有了戰(zhàn)斗數(shù)據(jù),還要配備一套完整功能的GUI工具才能提高調(diào)試效率,因此筆者基于Unity開發(fā)了戰(zhàn)斗錄像播放器工具。
?
上圖是戰(zhàn)斗錄像播放器經(jīng)過幾次迭代后的截圖,除了實現(xiàn)最基本的播放錄像、查看數(shù)據(jù)功能,還有查看設(shè)備數(shù)據(jù),上傳/下載錄像、生成戰(zhàn)斗播報、差量構(gòu)建指定回合戰(zhàn)場包等功能。筆者覺得在
開發(fā)初期,先實現(xiàn)播放錄像、查看數(shù)據(jù)的功能就能滿足大部分調(diào)試需求了
,開發(fā)時間成本只有2-3天,但它會在之后1-2個月甚至更久的前期開發(fā)階段幫你縮短調(diào)試定位時間,節(jié)省更多時間早(bu)點(cun)下(zai)班(de),或幫策劃做更多需求,重要的是解放心態(tài),不再疲于溝通Bug,構(gòu)造現(xiàn)場,因為現(xiàn)場就在錄像里。
簡單描述這套調(diào)試工具的使用姿勢:
* 開發(fā)過程中遇到了戰(zhàn)斗Bug,如果在第一時間無法判斷Bug原因,先保存錄像,再逐步分析問題。
*
選擇報錯的戰(zhàn)斗錄像,通過時間戳/快速模式重跑戰(zhàn)斗,逐步縮小問題范圍:觀察戰(zhàn)斗錄像播到第幾個回合報錯,是資源加載、選招還是表演階段報錯,通過報錯前的日志,逐步定位是哪個類哪個接口的問題,再猜測并驗證某行代碼,直到問題解決。
* 如果不是卡死報錯,戰(zhàn)斗也能跑完,但策劃反饋某個技能/Buff表現(xiàn)與預(yù)期不同,就要查看關(guān)鍵表演包的數(shù)據(jù),看是后臺傳的有問題,還是前臺表現(xiàn)沒做對。
* 上面兩類問題的排查通常是無法一步到位的,排查過程會不斷追蹤代碼給可疑代碼打Log,會臨時修改某些變量,會臨時修改某段代碼邏輯,依靠不斷重跑戰(zhàn)斗來驗證。
*
解決Bug的過程也少不了跟后臺的溝通,在這之前,后臺重數(shù)據(jù)輕表現(xiàn),前臺重表現(xiàn)輕數(shù)據(jù),導(dǎo)致一種現(xiàn)象就是后臺找前臺問表現(xiàn),前臺找后臺問數(shù)據(jù),溝通成本比較高。有了這套工具,前臺開發(fā)對于這場戰(zhàn)斗包括服務(wù)器、角色I(xiàn)D、戰(zhàn)斗ID、戰(zhàn)場ID,協(xié)議數(shù)據(jù)等信息都了如指掌,快速分析出是前臺問題就直接修復(fù),是后臺問題就告訴對方去修復(fù)哪塊數(shù)據(jù)。
這里另外分享1個Bug調(diào)試修復(fù)的經(jīng)驗。個人認(rèn)為Bug修復(fù)總時間 = 問題溝通時間 + 問題定位時間 + 代碼修改時間 +
編譯驗證時間,像戰(zhàn)斗這類大型系統(tǒng),可能會經(jīng)歷多輪問題定位、代碼修改、編譯驗證才能修好1個Bug。Lua代碼做好Hot
reload開關(guān),最好做到修改某處代碼,重進(jìn)戰(zhàn)斗就能驗證最新代碼。每次重啟游戲至少花費(fèi)30+秒,1個Bug平均幾次重啟驗證就是幾分鐘時間,做好Hot
reload節(jié)省下的時間相當(dāng)可觀。
初期在項目組內(nèi)推行用錄像反饋戰(zhàn)斗Bug時,我們讓大家把保存下來的錄像文件單發(fā)給戰(zhàn)斗開發(fā)來調(diào)試,很快發(fā)現(xiàn)用戶體驗并不友好,不是所有人都是開發(fā),大家不清楚錄像保存到哪個目錄了,找到目錄,他們也弄不清楚要發(fā)哪個錄像給開發(fā)。在忍受了一段時間的靈魂三連問后,筆者又加上了錄像上傳/下載功能。
上面兩張圖是錄像上傳/下載流程及錄像下載頁面。我們將Bug反饋操作簡化成游戲內(nèi)一鍵反饋,點擊按鈕就能自動保存錄像文件,并將二進(jìn)制文件數(shù)據(jù)Base64編碼成字符串,利用魔方質(zhì)管組幫忙搭建的Web服務(wù),通過Http請求將數(shù)據(jù)上傳到Web服務(wù)器保存數(shù)據(jù)庫,開發(fā)通過Web頁面就可以搜索/下載base64字符串格式的錄像文件,最后錄像播放接口做適配,支持二進(jìn)制/base64字符串兩種格式數(shù)據(jù)的錄像播放,整個環(huán)節(jié)就打通了。
開發(fā)階段我們自行開發(fā)了戰(zhàn)斗錄像來輔助調(diào)試,確實也是到了戰(zhàn)斗系統(tǒng)基本穩(wěn)定后,策劃們才前后提了戰(zhàn)斗錄像的正式需求,先做了一版基于服務(wù)器保存的活動錄像,又做了一版基于客戶端保存的戰(zhàn)斗錄像大廳。
前后做這兩版錄像需求,雖然都是觀看錄像,但其實現(xiàn)大不相同,因此需要謹(jǐn)慎設(shè)計整個錄像模塊,讓兩套邏輯獨(dú)立并行,能共用底層功能,并盡量保持外部接口一致性。上圖是整個戰(zhàn)斗錄像的模塊劃分,可劃分為實現(xiàn)戰(zhàn)斗錄像基礎(chǔ)功能的核心模塊,及涉及界面UI的兩版業(yè)務(wù)功能模塊。BattleReplayManager是核心類,它對外接收錄像相關(guān)的控制請求,對內(nèi)調(diào)度其他核心模塊類,獲取/保存/構(gòu)造數(shù)據(jù),控制錄像播放流程,并通過給戰(zhàn)斗網(wǎng)絡(luò)層發(fā)送協(xié)議數(shù)據(jù)影響戰(zhàn)斗表現(xiàn)。
服務(wù)器錄像
基于服務(wù)器保存的活動錄像,所有數(shù)據(jù)都由服務(wù)器提供。前臺首先發(fā)送觀看錄像請求,接收錄像概要數(shù)據(jù)包,獲取戰(zhàn)斗波次/回合等信息用于顯示和跳回合。收到初始戰(zhàn)場包后進(jìn)入戰(zhàn)斗,在每回合表演完后請求下一回合表演數(shù)據(jù)。正常播放錄像時,收到的協(xié)議數(shù)據(jù)跟普通戰(zhàn)斗是一樣的,但如果在戰(zhàn)斗中途跳回合,除了新回合的表演包,還會收到新回合的戰(zhàn)場包,用于恢復(fù)新回合初的戰(zhàn)場單位狀態(tài)。這個過程跟戰(zhàn)斗斷線重連恢復(fù)戰(zhàn)場是同一套邏輯,因此把戰(zhàn)斗斷線重連的坑填完,實現(xiàn)服務(wù)器錄像基本沒有難點。
客戶端錄像
相對服務(wù)器錄像,實現(xiàn)基于客戶端保存的錄像功能要考慮比較多問題:
* 確定錄像數(shù)據(jù)結(jié)構(gòu),用什么數(shù)據(jù)結(jié)構(gòu)存儲一場戰(zhàn)斗的所有協(xié)議及相關(guān)信息較優(yōu)?
* 保證錄制數(shù)據(jù)完整性。網(wǎng)絡(luò)抖動、切出游戲再切回來等場景可能會導(dǎo)致少了某回合表演數(shù)據(jù)怎么辦?
* 如何實現(xiàn)跳回合。一場正常戰(zhàn)斗的協(xié)議包,除了初始戰(zhàn)場包,每個回合只有表演包,沒有戰(zhàn)場包,跳回合怎么恢復(fù)戰(zhàn)場狀態(tài)?
* 錄像上傳/下載的傳輸策略。協(xié)議收發(fā)有64kb限制,錄像文件大小超過了怎么辦?
* 保證用戶體驗。評估極限情況的錄像文件大小,保證流暢的錄像觀看體驗。
模塊開發(fā)初期就考慮這些問題,就可以避免基礎(chǔ)設(shè)計出錯,后期積重難返的尷尬情況。
1. 錄像文件結(jié)構(gòu)
首先是確定錄像文件格式,由于妖尾協(xié)議基于pb通信,錄像文件一開始就沒有打算自定義二進(jìn)制格式,而是直接基于pb定義數(shù)據(jù)結(jié)構(gòu),這樣有幾點好處:
* pb傳輸效率高,而且開發(fā)熟悉pb,不像自定義格式還有理解成本,開發(fā)效率也高。
*
協(xié)議與錄像文件采用同種格式,比較容易根據(jù)查看列表,上傳/下載錄像等業(yè)務(wù)去反推最優(yōu)的錄像文件數(shù)據(jù)結(jié)構(gòu)。讓每份錄像文件既可以有戰(zhàn)斗錄像數(shù)據(jù),也有關(guān)于錄像大廳的業(yè)務(wù)數(shù)據(jù),一次設(shè)計,解決兩個問題。
* pb支持?jǐn)?shù)據(jù)結(jié)構(gòu)嵌套,列表,能做出錄像頭、錄像數(shù)據(jù)塊設(shè)計,上傳/下載協(xié)議也容易切分錄像文件做分塊傳輸。
基于幾點考慮,錄像文件由BattleReplayFile錄像頭、BattleReplayFileBlock錄像數(shù)據(jù)塊兩部分組成。BattleReplayFile的blocks字段用于存放BattleReplayFileBlock列表,BattleReplayFile其他字段是概要信息。這樣查看錄像列表時,后臺只需要返回不帶blocks數(shù)據(jù)的BattleReplayFile列表即可。上傳/下載錄像時也可以先傳錄像頭、再批量分次傳錄像數(shù)據(jù)塊。
message?BattleReplayFile
{
????optional?string?name?=?1;???????????????????????//?錄像文件名
????repeated?BattleReplayFileBlock?blocks?=?2;??????//?協(xié)議文件塊
????optional?uint32?block_num?=?3;??????????????????//?協(xié)議文件總塊數(shù)
????repeated?string?ext_info_keys?=?4;??????????????//?錄像額外信息參數(shù)Key
????repeated?string?ext_info_values?=?5;????????????//?錄像額外信息參數(shù)Value
????...?//?id、時間、雙方成員、回合、波次等錄像概要信息
????...?//?簡介、點贊、收藏等錄像大廳業(yè)務(wù)信息
}
message?BattleReplayFileBlock
{
????optional?uint32?index?=?1;??????????????????//?協(xié)議塊序號
????optional?string?name?=?2;???????????????????//?協(xié)議類名
????optional?bytes?data?=?3;????????????????????//?協(xié)議數(shù)據(jù)
????...?//時間、回合等其他信息
}
2. 錄像文件校驗
網(wǎng)絡(luò)抖動、切出游戲再切回來等情況導(dǎo)致斷線重連,可能導(dǎo)致戰(zhàn)斗錄像數(shù)據(jù)損壞,因此保存本地前先做錄像文件校驗,判斷有沒有丟關(guān)鍵協(xié)議包,包括初始戰(zhàn)場包、入包表演包、各回合表演包及退出戰(zhàn)場包,保證協(xié)議包序,通過校驗才保存錄像文件,不通過就提示玩家錄像數(shù)據(jù)損壞無法保存。
3. 錄像回合跳轉(zhuǎn)
一場戰(zhàn)斗錄像單靠收到的協(xié)議包,可以正常順序播放整個戰(zhàn)斗,卻不能跳轉(zhuǎn)回合播放,因為中間跳過了幾回合的表演演算,戰(zhàn)斗邏輯層無法將戰(zhàn)場數(shù)據(jù)修正成跳轉(zhuǎn)回合的狀態(tài)。服務(wù)器錄像可以依靠后臺發(fā)跳轉(zhuǎn)回合戰(zhàn)場包做恢復(fù),客戶端錄像就要靠前臺自己處理,用錄像表演包演算出跳轉(zhuǎn)回合的戰(zhàn)場狀態(tài)。
第一直覺是在戰(zhàn)斗邏輯層處理跳出的表演包,只是跳過表演,直接做數(shù)據(jù)演算,但稍加思考會發(fā)現(xiàn)有很多問題:戰(zhàn)斗邏輯層里,數(shù)據(jù)與表現(xiàn)基本耦合在一起,畢竟這樣的編碼實現(xiàn)方式最直觀。想抽離表現(xiàn)只演算數(shù)據(jù),只能在原有代碼里加ifelse分支,重寫數(shù)據(jù)演算邏輯。幾十個表演類,新增這么多分支,編碼再加調(diào)試,必然失去對代碼的把控,也破壞了原有系統(tǒng)穩(wěn)定性。即使哼哧哼哧硬寫下來,也會發(fā)現(xiàn)只實現(xiàn)了向后跳轉(zhuǎn)回合,沒實現(xiàn)向前跳轉(zhuǎn)回合,因為戰(zhàn)斗邏輯層實現(xiàn)的是按回合往下演算的邏輯。
跳出這個誤區(qū),我們認(rèn)為戰(zhàn)斗錄像數(shù)據(jù)應(yīng)該要有每個回合的戰(zhàn)場包,跳轉(zhuǎn)時供戰(zhàn)斗邏輯層重置回合戰(zhàn)場,因此后臺修改了戰(zhàn)斗邏輯,每回合都會發(fā)當(dāng)回合戰(zhàn)場包,這些戰(zhàn)場包做了特殊標(biāo)記,只用于錄像存儲,不會影響戰(zhàn)斗邏輯,實現(xiàn)起來很快,但也清楚有明顯效率問題。
基本上,戰(zhàn)場包都會比表演包大,甚至大很多,如果某個回合技能不太復(fù)雜,那表演包數(shù)據(jù)其實非常小,為了實現(xiàn)跳回合,由后臺給每個回合加發(fā)戰(zhàn)場包,會非常影響戰(zhàn)斗的協(xié)議數(shù)據(jù)量,保存錄像文件變大,也會增加上傳/下載錄像時的負(fù)擔(dān)。這么實現(xiàn)不合理的點在于,每回合戰(zhàn)場包其實是冗余數(shù)據(jù),每回合狀態(tài)是可以通過初始戰(zhàn)場包加表演包推算出來的。為了優(yōu)化這個問題,前臺實現(xiàn)了一個戰(zhàn)場包構(gòu)建器,以初始戰(zhàn)場包、回合1~n-1表演包為輸入,輸出目標(biāo)回合n的戰(zhàn)場包。這樣在保存錄像時不需要保存回合戰(zhàn)場包,錄像跳轉(zhuǎn)回合時由構(gòu)造器動態(tài)生成戰(zhàn)場包即可。編寫調(diào)試戰(zhàn)場包構(gòu)建器時,要注意檢查前后臺的戰(zhàn)場包差異,我們會打印戰(zhàn)場包數(shù)據(jù),通過Beyond
Compare查看差異,不斷調(diào)整代碼,直到構(gòu)建的關(guān)鍵數(shù)據(jù)一致為止。戰(zhàn)場包構(gòu)建器調(diào)試好后,只要后續(xù)不新增表演類型,就可以保證構(gòu)建器可信可用,即使新增表演,代碼工作量也很少。
優(yōu)化完做下簡單測試,打了一場40回合的5v5
pvp戰(zhàn)斗保存錄像,比較兩種方案的保存錄像文件大?。簝?yōu)化后文件大小是優(yōu)化前的65%,減少了252KB,由于5v5pvp表演復(fù)雜,因此回合表演包數(shù)據(jù)本身也非常多,換做是一般的戰(zhàn)斗,數(shù)據(jù)優(yōu)化比率會更高。
4. 錄像上傳/下載策略
妖尾一次協(xié)議收發(fā)有64KB大小限制,看前面的數(shù)據(jù)可知,回合數(shù)比較多的戰(zhàn)斗錄像文件大小肯定會超過64KB,我們既不希望上傳/下載錄像單次傳輸?shù)臄?shù)據(jù)量超過64KB,又不希望單次傳輸數(shù)據(jù)量太少,導(dǎo)致協(xié)議發(fā)送次數(shù)過多,浪費(fèi)太多時間在RRT上,因此采用的錄像傳輸策略是,首次傳輸單獨(dú)發(fā)送錄像頭,后續(xù)傳輸錄像數(shù)據(jù)塊切塊傳輸,保證每次傳輸?shù)乃蠦attleReplayFileBlock的data總大小不超過50KB。采用這樣的策略,5回合以內(nèi)的小型戰(zhàn)斗基本都能分2次傳輸完畢,像上面的5v5
pvp大型戰(zhàn)斗則需要進(jìn)行11次傳輸。這就引出了下個問題思考,大型戰(zhàn)斗的錄像觀看會不會有體驗問題。
5.流式傳輸及錄像緩存
戰(zhàn)斗錄像大廳的設(shè)計初衷,是讓玩家可以自主分享/觀看他們覺得滿意的戰(zhàn)斗錄像,所以我們猜測玩家會比較多的上傳/下載/觀看大型pvp戰(zhàn)斗錄像,對于上傳而言并不會有什么問題,因為就是一次性操作,但對下載/觀看場景就要盡量進(jìn)行優(yōu)化,我們不希望玩家每次看錄像,都要有感知地等待一會,等上10次網(wǎng)絡(luò)回包,下載完錄像文件才能觀看錄像,也不希望玩家每次看錄像都得重復(fù)下載文件,對玩家的手機(jī)流量也很不友好。
針對這兩點問題,戰(zhàn)斗錄像參考網(wǎng)絡(luò)視頻的做法,加上了流式傳輸及錄像緩存的特性。
如上圖所示,流式傳輸?shù)哪康脑谟趦?yōu)化玩家觀看新錄像的體驗,不管一個完整的錄像有多大,需要多少次傳輸才能完成,只需要先獲得部分頭部數(shù)據(jù),就能觀看錄像。
前臺只需要頭2次回包,獲取錄像概況、初始回合戰(zhàn)場包和表演包,就足以表演第1回合的戰(zhàn)斗,進(jìn)入錄像戰(zhàn)斗后,靜默下載其余的錄像數(shù)據(jù),一般后續(xù)的錄像數(shù)據(jù)下載速度遠(yuǎn)遠(yuǎn)快于戰(zhàn)斗表演速度,這樣完全不影響整場戰(zhàn)斗的錄像觀看。假設(shè)網(wǎng)絡(luò)環(huán)境極端惡劣,表演完當(dāng)前回合戰(zhàn)斗后,后續(xù)錄像數(shù)據(jù)還沒返回,BattleReplayManager會每幀輪詢等待下個回合表演數(shù)據(jù),即使網(wǎng)絡(luò)斷掉了拿不到數(shù)據(jù),玩家仍然可以點擊按鈕退出戰(zhàn)斗錄像。
錄像緩存的目的則在于優(yōu)化玩家重復(fù)觀看錄像的體驗,減少流量消耗
。當(dāng)看過一次錄像,下載了完整的錄像數(shù)據(jù)后,前臺就會把錄像保存到本地緩存起來了,盡管錄像頭里存儲了部分戰(zhàn)斗錄像大廳的字段,比如點贊、收藏數(shù)等,這些字段數(shù)據(jù)會失效,但戰(zhàn)斗數(shù)據(jù)是不會變的。查看大廳的錄像列表時,后臺會返回只有錄像頭BattleReplayFile,沒有數(shù)據(jù)塊BattleReplayFileBlock的列表,玩家請求觀看時,判斷本地緩存有沒有該錄像緩存,有就不再走原來的下載流程,直接讀取緩存文件播放即可。
洋洋灑灑寫了一些關(guān)于戰(zhàn)斗錄像的總結(jié),也確實是因為錄像系統(tǒng)對戰(zhàn)斗開發(fā)調(diào)試有所幫助,作為一個功能系統(tǒng),也需要在早期考慮一些問題,做設(shè)計和優(yōu)化,希望本文能對MMORPG或其他類型游戲戰(zhàn)斗的設(shè)計開發(fā),提供一些借鑒經(jīng)驗。
附上我們的游戲官網(wǎng)[妖精的尾巴:魔導(dǎo)少年] <https://yw.qq.com/>,快來玩吧~
熱門工具 換一換
感谢您访问我们的网站,您可能还对以下资源感兴趣:
调教肉文小说-国产成本人片免费av-空姐av种子无码-在线观看免费午夜视频-综合久久精品激情-国产成人丝袜视频在线观看软件-大芭区三区四区无码-啊啊好爽啊啊插啊用力啊啊-wanch视频网-国产精品成人a免费观看