DOTA 2 的觀戰、錄像系統的工作原理是什麼?為什麼這麼強大?
每一個玩家每一場比賽都被記錄到伺服器端,而每一場錄像都記錄了整個地圖每個角落發生的事情,包括每個選手的第一視角操作,而一場一個小時的比賽錄像才70兆大小,而更令人驚訝的是可以實時觀戰,雖然有兩分鐘延遲……很好奇這樣的觀戰,錄像系統是怎麼做出來的,他是記錄每一個選手的操作(這貌似是唯一變數),然後把這一行行命令施加給我電腦上的Dota2系統中地圖上的英雄模型,然後重現的比賽嗎?不然我想不出來如何如此高效實現這項功能。
補充一點,每一局結束後就可以立即下載錄像,證明在比賽過程中就完成了上傳,但是玩的時候上傳寬頻佔用並不高,這是不是側面證明我上面的猜想呢?本題已加入圓桌 ? 電競風雲 · 決戰肉山,更多「刀塔(DOTA 2)」相關的話題歡迎關注討論
不知道為啥這個答案突然又被收錄進圓桌了。還是再次重申一邊這個這個答案是很久以前DOTA還沒換引擎的時候寫的,很多東西到現在發生了變化,比如新引擎基礎下使用的新版多伺服器連接機制等等,本答案僅供參考並且我懶得更新(
不知道為啥這個答案最近又有人開始關注了,在這裡說明一下。由於這篇答案是在很早之前寫的,加上中間有一次更換遊戲引擎的巨型更新,雖然遊戲大的架構仍然沒變但是可能會有一些改動,所以本答案僅供參考,以實際情況為準。
首先有一點需要說明:DOTA2是valve的作品,由起源引擎製作。
起源引擎是什麼引擎呢?大體上來說下列遊戲都是起源引擎做的:求生之路系列,傳送門系列,cs系列,半條命系列,另外還有軍團要塞2。錄像功能是這個引擎自有的功能,然後在DOTA2上閥門廠的工程師又進行了額外的加工。這個引擎上的遊戲基本都是fps有木有!!!不過這很好地解釋了為什麼可以記錄滑鼠位置。像cs這種遊戲錄像只記錄單位位置不記錄鏡頭方向的話根本就是失去了錄像的意義突然想到這裡可能沒說明白,鏡頭移動的原理是這樣的:先隱藏滑鼠,然後在每一幀(tick)內計算滑鼠位置與中心的距離和方向,然後將這個數據加以修正之後作為鏡頭移動的依據。然後將滑鼠重置到中心位置,並進行開火的相關判定
在DOTA2中,取消了滑鼠強制移動到中心的步驟,鏡頭移動的方式也做了修改,你對地圖上下達的指令相當於你用第一人稱向地圖上開了一槍,然後依據你開槍的類型(移動攻擊之類的),依照特定的邏輯讓遊戲單位響應。所以說為了得知你要向單位下達什麼指令,獲取滑鼠的狀態是必須的,既然已經得到了數據,沒有理由不把它記錄到錄像文件里。觀戰跟錄像是完全不同的機制。
解釋觀戰之前先說明一下,遊戲有三種伺服器:遊戲協調伺服器,負責匹配及賬號數據處理,在米國由閥門廠控制;遊戲伺服器,負責具體執行遊戲,位於世界各地;觀戰伺服器,負責抓取本地區的遊戲進行轉播,傳遞其他觀戰伺服器的數據,也同時負責了DOTA TV聊天的工作。當你開始匹配,「我要找對手」的信息被發送到協調伺服器。匹配成功後由協調伺服器負責尋找空閑的遊戲伺服器,並向玩家方發送伺服器的IP,此時遊戲伺服器開始載入地圖,玩家端彈出比賽以就緒的提示。遊戲伺服器載入完成之後,遊戲伺服器會立即開始錄像的記錄工作,同時會有一個(或多個)特殊的的客戶端立即連入遊戲,這個客戶端就是觀戰伺服器,觀戰伺服器本身作為客戶端接受遊戲伺服器的數據,同時作為伺服器向其負責的地區發送遊戲伺服器的數據,這裡存在一個故意設置的延遲,防止無關玩家獲得實時數據。緊接著玩家與其他必要人員連入遊戲伺服器,遊戲正式開始。遊戲結束後,觀戰伺服器繼續廣播數據(存在延遲)遊戲伺服器開始錄像的處理工作。錄像生產成功後將會傳遞到錄像數據中心,並登記到協調伺服器。登記成功後遊戲協調伺服器就會向玩家開放錄像的下載。錄像文件並不是基於操作的推演,而僅僅是將操作展示給你看
換句話說就是錄像裡面滑鼠的移動跟點擊什麼的與單位動作之間沒什麼關係單位的移動情況與其他相關情況是單獨記錄到錄像文件里的。雖然彈道是錄像展示時實時生成的,但是什麼時間點對誰造成了什麼傷害卻是錄像單獨記錄的。這也避免了版本不同導致的錄像出錯問題。(雖然實際上還有點區別,大體上是這樣的)錄像的處理過程存在必要的壓縮。比如說有一個單位靜止不動,那麼只有它開始靜止不動的時間點及靜止的時間會被記錄,而不是在每一幀內都記錄相同的數據目測中間文字太長沒人看,上圖我猜測如果輸入不變輸出不變就比較簡單,大致上只記錄用戶操作和AI決定作為輸入然後用遊戲重放應該就可以,對於那些可能會有隨機效果的,要多記錄一個隨機選擇的結果。
只記錄操作,需要遊戲本身是確定性的不確定性有多重來源,例如網路延遲,隨機數生成,浮點數運算
這應該算是業內獨一無二的客戶端直播系統,和錄像系統還是有區別,不簡單是每個單位的動作,還有玩家,解說視角語音等,比賽數據從伺服器到達解說哪裡,再結合解說的視角語音返回伺服器,校對時間後,再打包成流媒體發布;在具體到cdn,防止ddos等,都是設計時需要考慮到的
ps1.應該是出於帶寬考慮,dota2直播裡面有些操作是不記錄的,比如選手的改建以及鍵盤操作,滑鼠選中死靈書這樣的非英雄單位也是沒有記錄;2
一般沒有解說的只需要下載30m左右,題主所說的70m可能是解壓後的普通錄像吧;帶語音的一般要100m左右,有可能有不同語言的很多解說,會比較大3.dota2有時會被ddos,伺服器崩潰無法直播,人多的時候會卡,也是cdn優化不到位補充一下,之所以會有2分鐘延遲,那不是延遲,是為了防止土豪開兩台電腦,一台打天梯,一台觀戰,從而達到開圖的目的而已。做成實時的很簡單,無非是把伺服器傳給玩家的數據給觀眾傳一份罷了。
首先原理很簡單 就是記錄輸入(這裡輸入可以是經過處理的有效輸入 也可以是簡單的輸入設備的raw data)相同的輸入應該輸出相同的結果 (不過實現上需要注意浮點數運算無法克服的不一致性 需要精確同步的邏輯數據應該採用定點數 例如位置 生命等 其他數據 比如動畫插值可以用浮點數 因為不需要精確同步)數據量取決於實際輸入的規模不過這種做法有個缺點 就是必須從頭開始模擬 不支持隨機跳轉 基本也不可逆 所以魔獸3錄像不支持隨機跳轉 錯過了只能從頭再放一邊 不過星級2支持 但是很快就能注意到 星際2也並不支持完全的隨機跳轉 只是跳轉到一個比較接近的時間點 然後模擬至所要求的時間點 其實實現就是每隔一段時間完整採樣一次的所有需要同步的數據並記錄 然後錄像就能支持從這個點開始模擬 數據量取決於需要同步的數據規模和採樣周期以上兩者的數據量不會很大dota2 幾十兆的數據量已經非常大了 主要是解說的音頻數據 和其它非遊戲數據(比如有沒有彈幕功能...抱歉暴露了我其實並沒怎麼玩dota2 也沒用過錄像功能...)
1. 是的,只要記錄一些指令就可以了。比如 t 時刻 A 單位從 m 點移動到了 n 點,釋放了 x 技能。2. 伺服器本來就有這些記錄,所以不需要上傳。一場遊戲中,客戶端和服務端交互的信息也是這些指令而已。
gdc文章里有分享 10幾年前在國外就很普及的技術了 只不過越來越完善 核心思想十幾年前就定下來了想了解的話推薦你看下 遊戲編程精粹2 1.16章節 遊戲輸入的記錄與重放
這....記錄一系列後台數據而已啊....
用的是Google的protocal buffers和自家的SourceTV(HLTV DOTATV)。
先來說說錄像吧。
我們在dota2中下載的錄像都會存儲在 dota 2 betagamedota
eplays文件夾中,有興趣的可以先去打開來看看。一般來說,這個錄像的大小在幾百K到幾M之間,某些大型錦標賽的錄像文件可以達到數百M的大小,這是因為除了遊戲本身之外,這些錄像還同時記錄了多個解說頻道的音頻等信息。
錄像是如何記錄一場遊戲呢?這個過程說白了就是一個序列化與反序列化的過程。錄像的保存過程是將所有的操作進行序列化來寫入file buffer的過程,而錄像的播放就是讀取文件、反序列化、引擎執行的過程。
V社是如何完成這個過程的呢?
他使用的是一個開源的,由Google開發的"Protocal Buffers"來完成這個過程。
https://github.com/google/protobuf
當然了,V社是用這個庫,不僅是完成了錄像和觀戰,而是完成了dota2中幾乎所有有關於網路傳輸還有存儲的所有工作,比如說我們點擊尋找比賽啦、邀請另一個玩家進入隊伍啦,等等等等。
你可以在這個解包後的文件夾中來找到所有的定義:
https://github.com/SteamDatabase/GameTracking-Dota2/tree/master/Protobufs
至於這個流程是怎麼在伺服器之間傳輸的, @棋山 的說法是沒有問題的,你在這個文件夾中可以看到的,會有很多由gc來分別的文件,這個GC,代表的就是遊戲協調伺服器。通過查看gcsdk_gcmessages.proto這個文件中V社規範而合理的命名,再加上合理的想像,可以大概想見這個GC伺服器的實現,但是因為僅僅是想像而已,就不展開去講了。
而要想知道DEM文件中到底包含了哪些內容,你可以在 http://media.steampowered.com/apps/dota2/dev/demoinfo2.zip這個地址來下載V社開源的,用來dump .dem文件的源代碼。(不過貌似因為度假社對於這些代碼缺乏維護,已經不能用來解析目前的錄像文件了),通過閱讀代碼也可以知道dem的文件結構,比如說,錄像文件都是由一個一個的packet組成的,而packet的內容,我們可以讀讀DempDemoPacket的源代碼:
void CDemoFileDump::DumpDemoPacket( const std::string buf )
{
size_t index = 0;
while( index &< buf.size() )
{
int Cmd = ReadVarInt32( buf, index );
uint32 Size = ReadVarInt32( buf, index );
if( index + Size &> buf.size() )
{
const std::string strName = GetNetMsgName( Cmd );
fatal_errorf( "buf.ReadBytes() failed. Cmd:%d "%s"
", Cmd, strName.c_str() );
}
switch( Cmd )
{
#define HANDLE_NetMsg( _x ) case net_ ## _x: PrintNetMessage&< CNETMsg_ ## _x, net_ ## _x &>( *this, buf[ index ], Size ); break
#define HANDLE_SvcMsg( _x ) case svc_ ## _x: PrintNetMessage&< CSVCMsg_ ## _x, svc_ ## _x &>( *this, buf[ index ], Size ); break
default:
printf( "WARNING. DumpUserMessage(): Unknown netmessage %d.
", Cmd );
break;
HANDLE_NetMsg( NOP ); // 0
HANDLE_NetMsg( Disconnect ); // 1
HANDLE_NetMsg( File ); // 2
HANDLE_NetMsg( SplitScreenUser ); // 3
HANDLE_NetMsg( Tick ); // 4
HANDLE_NetMsg( StringCmd ); // 5
HANDLE_NetMsg( SetConVar ); // 6
HANDLE_NetMsg( SignonState ); // 7
HANDLE_SvcMsg( ServerInfo ); // 8
HANDLE_SvcMsg( SendTable ); // 9
HANDLE_SvcMsg( ClassInfo ); // 10
HANDLE_SvcMsg( SetPause ); // 11
HANDLE_SvcMsg( CreateStringTable ); // 12
HANDLE_SvcMsg( UpdateStringTable ); // 13
HANDLE_SvcMsg( VoiceInit ); // 14
HANDLE_SvcMsg( VoiceData ); // 15
HANDLE_SvcMsg( Print ); // 16
HANDLE_SvcMsg( Sounds ); // 17
HANDLE_SvcMsg( SetView ); // 18
HANDLE_SvcMsg( FixAngle ); // 19
HANDLE_SvcMsg( CrosshairAngle ); // 20
HANDLE_SvcMsg( BSPDecal ); // 21
HANDLE_SvcMsg( SplitScreen ); // 22
HANDLE_SvcMsg( UserMessage ); // 23
//$ HANDLE_SvcMsg( EntityMessage ); // 24
HANDLE_SvcMsg( GameEvent ); // 25
HANDLE_SvcMsg( PacketEntities ); // 26
HANDLE_SvcMsg( TempEntities ); // 27
HANDLE_SvcMsg( Prefetch ); // 28
HANDLE_SvcMsg( Menu ); // 29
HANDLE_SvcMsg( GameEventList ); // 30
HANDLE_SvcMsg( GetCvarValue ); // 31
#undef HANDLE_SvcMsg
#undef HANDLE_NetMsg
}
index += Size;
}
}
據說只是傳一些文本文件記錄指令…然後引擎通過解析文件達到錄像或觀戰的目的…
有的時候會發現錄像里買物品的時候會有一些小問題
簡單的來說,記錄的只是參數,而其他東西遊戲裡面都有!只有幾十KB的網速,只要延遲低也能玩dota2也是這個道理!
Command pattern.
你玩的一些遊戲其實都是數據變換...你看起來華麗的特效只是在數據變換下的動畫效果而已。動畫效果什麼的是本地文件自帶的。所以像war3里一個錄像文件就記錄著數據的變化而已。錄像文件根據時間長短 就1兩M的樣子
星際不就能錄像了而且錄像更小.原理基本一樣的這問題也問,.唉
1.是的,就算你APM高達500,1個小時也就30000個動作,10個人也就300000個動作,每個動作只需要描述時間地點人物就行了.實際上打doto,大多數時候只需要50的APM.
2.比賽是在伺服器上進行的,打完的那一刻伺服器上面就有完整的錄像了.而本地的數據反而不是完整的,所以需要下載.本地是沒有迷霧中的數據的,這從根本上杜絕了開圖外掛的出現.就和象棋似的 炮二平五 馬二進三
推薦閱讀:
※如何看待6月14日晚阿怡重開直播且人氣突破200W(鬥魚)?
※《星際爭霸II》職業比賽的觀賞性和《星際爭霸》相比如何?
※黃翔(longdd)的Dota2真實水平如何?
※如何評價 Dota 2 的觀戰系統?
※為什麼有時腦子會出現dota的影像?