日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java解析魔兽争霸3录像W3G文件(一):Header

發(fā)布時間:2024/8/1 java 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java解析魔兽争霸3录像W3G文件(一):Header 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

魔獸爭霸3是一款非常著名的即時戰(zhàn)略游戲。相信很多人都聽過sky、moon、grubby這些名字,還有塔魔infi、中國的鬼王ted、剛猛的fly、飄逸的th000等選手。遺憾的是WCG2013是魔獸爭霸3的最后一屆,我自己也去現(xiàn)場觀看了魔獸的總決賽。此外,還有DOTA、真三、澄海3C等著名的地圖。

魔獸爭霸的錄像大家都知道,是用來回放的,文件后綴名是.w3g,保存在魔獸爭霸下的REPLAY目錄下。現(xiàn)在很多軟件可以分析魔獸爭霸錄像,直接可以查看錄像的玩家、地圖,以及玩家的APM等信息。

最近在YY對戰(zhàn)平臺打魔獸,經(jīng)常能遇到Java程序員,說明Java程序員中有很多魔獸爭霸3的玩家,這里將Java解析魔獸爭霸3錄像的方法貢獻給同是WAR3玩家的小伙伴們。

魔獸爭霸3錄像文件由一個頭部(Header)多個壓縮數(shù)據(jù)塊(compressed data blocks)組成。本文主要內(nèi)容是解析Header部分,壓縮數(shù)據(jù)塊部分的解析會在后續(xù)的博文中詳細介紹。

Header結(jié)構(gòu):

Header部分包含了錄像的最基本的信息,大小是固定的前68個字節(jié),此后的全部是壓縮數(shù)據(jù)塊。對于1.06版本及之前的錄像,Header部分大小是64字節(jié),由于版本太古老這里就不考慮了。下面的代碼中也不再支持老版本的錄像。

Header中每個部分的意義:

1~28字節(jié)(28個字符):固定的字符串"Warcraft III recorded game\0x1A\0"。
29~32字節(jié)(4個字節(jié)):Header部分的總字節(jié)數(shù),對于1.07版本及之后,是68(0x44),對于1.06版本及之前是64(0x40)。
33~36字節(jié)(4個字節(jié)):壓縮數(shù)據(jù)塊的壓縮數(shù)據(jù)總字節(jié)數(shù),即解壓前。
37~40字節(jié)(4個字節(jié)):錄像版本標識(0表示1.06版本及之前版本,1表示1.07版本及之后版本)。
41~44字節(jié)(4個字節(jié)):壓縮數(shù)據(jù)塊解壓縮后的總字節(jié)數(shù)。
45~48字節(jié)(4個字節(jié)):壓縮數(shù)據(jù)塊的個數(shù)。
49~52字節(jié)(4個字節(jié)):一個字符串標識,"WAR3"表示非冰封王座,"W3XP"表示冰封王座。
53~56字節(jié)(4個字節(jié)):版本號(例如24即是1.24版本)。
57~58字節(jié)(2個字節(jié)):構(gòu)建號(build number)。
59~60字節(jié)(2個字節(jié)):0x0000表示單人游戲,0x8000(十進制32768)表示多人游戲。
61~64字節(jié)(4個字節(jié)):錄像時長(毫秒數(shù)),需要注意的是,這個時長不包括游戲中暫停的時長。
65~68字節(jié)(4個字節(jié)):Header部分CRC32校驗碼(包含這四個字節(jié)但是要都設(shè)為0)。

可以使用EditPlus的Hex Viewer方式打開w3g文件查看Header部分。



在這里可以發(fā)現(xiàn)一個問題,除了第一個字符串"Warcraft III recorded game\0x1A\0"以外,其他每個部分的字節(jié)順序都是倒過來的。例如Header部分總字節(jié)數(shù)是0x44000000,"W3XP"字符串順序是"PX3W"。這是因為這里使用的是小字節(jié)序(Little-Endian),也就是字節(jié)順序和正常的順序完全相反,所以在讀取的時候應(yīng)該將其倒過來讀。



Java解析Header:

知道了Header部分的結(jié)構(gòu),下面就可以用Java語言來解析Header了。

首先定義一個Replay類,表示一場錄像,構(gòu)造函數(shù)傳入錄像文件File。為了方便,將文件轉(zhuǎn)換成字節(jié)數(shù)組,再將字節(jié)數(shù)組傳給Header類進行處理。

Replay.java

package com.xxg.w3gparser;import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException;public class Replay {private Header header;public Replay(File w3gFile) throws IOException, W3GException {byte[] fileBytes = fileToByteArray(w3gFile);header = new Header(fileBytes);}/*** 將文件轉(zhuǎn)換成字節(jié)數(shù)組* @param w3gFile 文件* @return 字節(jié)數(shù)組* @throws IOException*/private byte[] fileToByteArray(File w3gFile) throws IOException {FileInputStream fileInputStream = new FileInputStream(w3gFile);ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int n;try {while((n = fileInputStream.read(buffer)) != -1) {byteArrayOutputStream.write(buffer, 0, n);}} finally {fileInputStream.close();}return byteArrayOutputStream.toByteArray();}public Header getHeader() {return header;}}
在Header類中,按小字節(jié)序讀取所有的Header信息。Header的最后四個字節(jié)是CRC32循環(huán)冗余檢驗碼,Java中可以使用java.util.zip.CRC32類來計算,下面的代碼中校驗了計算結(jié)果和Header中是否一致。有關(guān)CRC32的介紹可以查看相關(guān)資料,這里不再介紹。

Header.java

package com.xxg.w3gparser;import java.util.zip.CRC32;public class Header {public static final String BEGIN_TITLE = "Warcraft III recorded game\u001A\0";private long headerSize;private long compressedDataSize;private long headerVersion;private long uncompressedDataSize;private long compressedDataBlockCount;private String versionIdentifier;private long versionNumber;private int buildNumber;private int flag;private long duration;public Header(byte[] fileBytes) throws W3GException {// 讀取開頭的字符串"Warcraft III recorded game\u001A\0"String beginTitle = new String(fileBytes, 0, 28);System.out.println("1-28字節(jié):" + beginTitle);if (!BEGIN_TITLE.equals(beginTitle)) {throw new W3GException("錄像格式不正確。");}// header部分總大小(版本小于或等于V1.06是0x40(64),版本大于或等于V1.07是0x44(68))headerSize = LittleEndianTool.getUnsignedInt32(fileBytes, 28);System.out.println("29-32字節(jié):" + headerSize);if (headerSize != 0x44) {throw new W3GException("不支持V1.06及以下版本的錄像。");}// 壓縮文件大小compressedDataSize = LittleEndianTool.getUnsignedInt32(fileBytes, 32);System.out.println("33-36字節(jié):" + compressedDataSize);// header版本(版本小于或等于V1.06是0,版本大于或等于V1.07是1)headerVersion = LittleEndianTool.getUnsignedInt32(fileBytes, 36);System.out.println("37-40字節(jié):" + headerVersion);if (headerVersion != 1) {throw new W3GException("不支持V1.06及以下版本的錄像。");}// 解壓縮數(shù)據(jù)大小uncompressedDataSize = LittleEndianTool.getUnsignedInt32(fileBytes, 40);System.out.println("41-44字節(jié):" + uncompressedDataSize);// 壓縮數(shù)據(jù)塊數(shù)量compressedDataBlockCount = LittleEndianTool.getUnsignedInt32(fileBytes, 44);System.out.println("45-48字節(jié):" + compressedDataBlockCount);// WAR3:非冰封王座錄像,W3XP冰封王座錄像versionIdentifier = LittleEndianTool.getString(fileBytes, 48, 4);System.out.println("49-52字節(jié):" + versionIdentifier);// 版本號(例如1.24版本對應(yīng)的值是24)versionNumber = LittleEndianTool.getUnsignedInt32(fileBytes, 52);System.out.println("53-56字節(jié):" + versionNumber);// Build號buildNumber = LittleEndianTool.getUnsignedInt16(fileBytes, 56);System.out.println("57-58字節(jié):" + buildNumber);// 單人游戲(0x0000) 多人游戲(0x8000,對應(yīng)十進制32768)flag = LittleEndianTool.getUnsignedInt16(fileBytes, 58);System.out.println("59-60字節(jié):" + flag);// 錄像時長(毫秒)duration = LittleEndianTool.getUnsignedInt32(fileBytes, 60);System.out.println("61-64字節(jié):" + duration);// CRC32校驗碼long crc32 = LittleEndianTool.getUnsignedInt32(fileBytes, 64);System.out.println("65-68字節(jié):" + crc32);// 這里來校驗CRC32,將最后四位也就是CRC32所在的四個字節(jié)設(shè)為0后計算CRC32的值CRC32 crc32Tool = new CRC32();crc32Tool.update(fileBytes, 0, 64);crc32Tool.update(0);crc32Tool.update(0);crc32Tool.update(0);crc32Tool.update(0);System.out.println("計算CRC32:" + crc32Tool.getValue());// 判斷Header中后四位讀取的CRC32的值和計算得到的值比較,看是否一致if (crc32 != crc32Tool.getValue()) {throw new W3GException("Header部分CRC32校驗不通過。");}}public long getHeaderSize() {return headerSize;}public long getCompressedDataSize() {return compressedDataSize;}public long getHeaderVersion() {return headerVersion;}public long getUncompressedDataSize() {return uncompressedDataSize;}public long getCompressedDataBlockCount() {return compressedDataBlockCount;}public String getVersionIdentifier() {return versionIdentifier;}public long getVersionNumber() {return versionNumber;}public int getBuildNumber() {return buildNumber;}public int getFlag() {return flag;}public long getDuration() {return duration;}}
Header中用到了LittleEndianTool是用來按小字節(jié)序讀取數(shù)據(jù)的工具類。

LittleEndianTool.java

package com.xxg.w3gparser;/*** Little-Endian(小字節(jié)序)工具類* @author 叉叉哥(806223819@qq.com)*/ public class LittleEndianTool {/*** 以Little-Endian(小字節(jié)序)方式讀取字節(jié)數(shù)組中的一個16位(2個字節(jié))無符號整數(shù)* @param bytes 字節(jié)數(shù)組* @param offset 開始字節(jié)的位置索引* @return 16位(2個字節(jié))無符號整數(shù)*/public static int getUnsignedInt16(byte[] bytes, int offset) {int b0 = bytes[offset] & 0xFF;int b1 = bytes[offset + 1] & 0xFF;return b0 + (b1 << 8);}/*** 以Little-Endian(小字節(jié)序)方式讀取字節(jié)數(shù)組中的一個32位(4個字節(jié))無符號整數(shù)* @param bytes 字節(jié)數(shù)組* @param offset 開始字節(jié)的位置索引* @return 32位(4個字節(jié))無符號整數(shù)*/public static long getUnsignedInt32(byte[] bytes, int offset) {long b0 = bytes[offset] & 0xFFl;long b1 = bytes[offset + 1] & 0xFFl;long b2 = bytes[offset + 2] & 0xFFl;long b3 = bytes[offset + 3] & 0xFFl;return b0 + (b1 << 8) + (b2 << 16) + (b3 << 24);}/*** 以Little-Endian(小字節(jié)序)方式讀取字節(jié)數(shù)組中的字符串* @param bytes 字節(jié)數(shù)組* @param offset 開始字節(jié)的位置索引* @param length 需要讀取的長度* @return 讀取的字符串*/public static String getString(byte[] bytes, int offset, int length) {byte[] temp = new byte[length];for(int i = 0; i < length; i++) {temp[i] = bytes[offset + length - i - 1];}return new String(temp);}}
這里需要注意的是,Java中int類型4個字節(jié)大小,但是由于是有符號的整數(shù),補碼的最高位是符號位,所以對于Header中的4個字節(jié)的無符號整數(shù),必須要用long類型才足夠。2個字節(jié)的無符號整數(shù)需要使用Java中的int而不能是short。

另外,Header中用到了W3GException異常。

W3GException.java

package com.xxg.w3gparser;public class W3GException extends Exception {public W3GException(String message) {super(message);}}
最后用main方法調(diào)用這些代碼來測試。

Test.java

package com.xxg.w3gparser;import java.io.File; import java.io.IOException;public class Test {public static void main(String[] args) throws IOException, W3GException {Replay replay = new Replay(new File("E:/魔獸爭霸3冰封王座/REPLAY/100729_[NE]EHOME.ReMinD_VS_[ORC]WemadeFOX_Lyn_EchoIsles_RN.w3g"));Header header = replay.getHeader();System.out.println("WAR3錄像基本信息為:");System.out.println("版本:1." + header.getVersionNumber() + "." + header.getBuildNumber());long duration = header.getDuration();long second = (duration / 1000) % 60;long minite = (duration / 1000) / 60;if (second < 10) {System.out.println("時長:" + minite + ":0" + second);} else {System.out.println("時長:" + minite + ":" + second);}}}
輸出結(jié)果:

1-28字節(jié):Warcraft III recorded game ?
29-32字節(jié):68
33-36字節(jié):125736
37-40字節(jié):1
41-44字節(jié):311296
45-48字節(jié):38
49-52字節(jié):W3XP
53-56字節(jié):24
57-58字節(jié):6059
59-60字節(jié):32768
61-64字節(jié):783600
65-68字節(jié):1414752232
計算CRC32:1414752232
WAR3錄像基本信息為:
版本:1.24.6059
時長:13:03


參考文檔:http://w3g.deepnode.de/files/w3g_format.txt


作者:叉叉哥 ? 轉(zhuǎn)載請注明出處:http://blog.csdn.net/xiao__gui/article/details/17882303



總結(jié)

以上是生活随笔為你收集整理的Java解析魔兽争霸3录像W3G文件(一):Header的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 精品美女久久久久 | 暖暖日本视频 | 同性色老头性xxxx老头 | 国产精品久久久久久久无码 | 国产精品无码久久久久久电影 | 午夜色播 | 久久久久亚洲AV成人网人人小说 | 四虎av在线 | www.sesehu.com| 精品国产一区二区三区四区阿崩 | 国产一区在线观看视频 | 欧美激情电影一区二区 | 熟睡侵犯の奶水授乳在线 | 欧美污视频在线观看 | 综合久久99 | 免费a视频在线观看 | 国精产品乱码一区一区三区四区 | 国产精品va无码一区二区 | 亚洲精品高清在线观看 | 欧美精品极品 | 日韩一级大片 | 国产一区二区三区电影在线观看 | 人物动物互动39集免费观看 | 永久毛片 | 永久免费精品视频 | 国产高清色 | 久久国产麻豆 | 日本一本不卡 | 日本网站免费观看 | 欧美另类视频在线观看 | 狠狠成人| 国产男女无遮挡猛进猛出 | 小明看国产| 成人a√ | 欧美污视频在线观看 | 亚洲小说区图片区都市 | 欧美一级片免费观看 | 亚洲精品三| 国产高清视频在线观看 | 黄色三级视屏 | 中文字幕一区二区三区免费视频 | 亚洲综合色av | 成人无码精品1区2区3区免费看 | 成人欧美一区二区三区小说 | 影音先锋二区 | 成人午夜激情影院 | 乱岳| 中文精品一区二区三区 | 老熟妇仑乱一区二区av | 欧美黄色片免费看 | 毛片在线免费观看视频 | 国产精品夜夜躁视频 | 他揉捏她两乳不停呻吟动态图 | 亚洲区一区二区三区 | 新呦u视频一区二区 | 狠狠爱网站| 国产伦精品一区二区三区在线 | 日韩两性视频 | 成人在线观看免费爱爱 | 色欲一区二区三区精品a片 在线观看黄网站 | 亚洲国产精品一区二区尤物区 | xxxxxx日本 | 关秀媚三级 | 免费成人在线电影 | 亚洲国产系列 | 亚洲综合福利 | 日本三级一区 | 正在播放木下凛凛88av | 超碰在线最新地址 | 免费人成自慰网站 | 亚洲精品理论 | 日日夜夜添 | 超碰97在线资源站 | 五月天看片 | 美女被啪羞羞粉色视频 | 99久久精品免费看 | 美女视频免费在线观看 | 国产日韩第一页 | 日韩欧美一区二区区 | 女的被男的操 | 中字幕一区二区三区乱码 | 久色电影 | 成人av资源站 | 内射国产内射夫妻免费频道 | 一区二区三区在线播放视频 | 2020自拍偷拍| 99在线精品视频免费观看20 | www日本色 | 日韩免费观看一区二区 | 最新视频 - 8mav| 少妇高潮喷水在线观看 | 97人妻精品一区二区三区免 | 免费在线精品视频 | 在线a网| 雪白的扔子视频大全在线观看 | 日韩黄色一级视频 | 含羞草一区二区 | 亚洲欧美日韩精品色xxx | 亚洲男人网站 |