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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java解析魔兽争霸3录像_Java解析魔兽争霸3录像W3G文件(三):解析游戏开始前的信息...

發布時間:2024/8/1 java 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java解析魔兽争霸3录像_Java解析魔兽争霸3录像W3G文件(三):解析游戏开始前的信息... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上一篇博文中,通過對壓縮數據塊的解壓縮以及合并,得到了解壓縮的字節數組。從現在開始,就要處理這個數據。

這個部分的數據主要包括兩大類信息:一類是游戲開始前的信息,例如游戲地圖,游戲玩家,隊伍、種族情況,高級選項等等,這些信息都是在進入游戲之前已經確定的東西;另一類是游戲進行時的信息,這塊包括玩家游戲過程中的操作、游戲中的聊天等。其中,游戲開始前的信息占解壓縮后的數據的前一小部分,緊接著后面的一大部分保存著游戲進行時的信息。

本文介紹如何解析游戲開始前的信息。

游戲開始前的信息的結構:

注:在下面各部分結構解釋中,灰色字體標注的信息不對其進行解析,就不再詳細介紹,要想了解可以參考w3g_format.txt文檔。

一、總體結構

1、4 字節:未知。2、variable字節:主機玩家記錄(詳細查看【二、玩家記錄】)。

3、variable字節:游戲名稱,字符串,以0x00結束。

4、1字節:空字節,0x00。5、variable字節:特殊編碼的數據(包括游戲設置、地圖、創建者),以0x00結束(詳細查看【三、特殊編碼的數據】)。

6、4字節:玩家數量。

7、4字節:游戲類型。

8、4字節:未知。

9、variable字節:加入游戲的玩家列表(詳細查看:【四、加入游戲的玩家列表】以及【二、玩家記錄】)。

10、variable字節:Slot列表(詳細查看:【五、Slot列表】)。

二、玩家記錄

1、1字節:玩家類型,0x00主機,0x16加入游戲的玩家(【四、加入游戲的玩家列表】)。

2、1字節:玩家ID。

3、variable字節:玩家名稱,以0x00結束。

4、1字節:附加數據大小,0x01或0x08。

5、1或8字節:附加數據。

三、特殊編碼的數據

這是一段特殊編碼的數據,該部分需要解碼后才能繼續解析,解碼的方式直接看下面的代碼,這里不再介紹。

解碼后:

1、4字節:游戲設置,這部分包含一些高級選項,如下圖,不過這部分很少有人去改變,所以這里不再去解析了。

2、5字節:未知。

3、4字節:地圖校驗。

4、variable字節:地圖路徑,字符串,以0x00結束。

5、variable字節:創建者,字符串,以0x00結束。

四、加入游戲的玩家列表

如果有多個玩家加入游戲,每個玩家對應一個下面的結構。由于是加入游戲的玩家,所以每個玩家對應的數據都是0x16開頭。當遍歷到第一個字節不是0x16時玩家列表就結束了。注意,加入游戲的玩家列表中不包含電腦玩家,電腦玩家在【五、Slot列表】中。

1、variable字節:玩家記錄(詳細查看【二、玩家記錄】)。

2、4字節:0x00000000。

五、Slot列表

一個Slot是指游戲開始前的界面的一個玩家位置。如下圖,即是4個Slot。

1、1字節:固定0x19。

2、2字節:下面的數據的字節數。

3、1字節:Slot數量。

4、variable字節:Slot記錄的列表,其中包含多個Slot記錄,數量即上面一個字節的值(詳細查看【六、Slot記錄】)。

5、4字節:隨機種子。

6、1字節:隊伍、種族是否可選擇。

7、1字節:地圖中的位置數量。

六、Slot記錄

每個Slot占9個字節:

1、1字節:對應的玩家ID,電腦玩家是0x00。

2、1字節:地圖下載百分比(一般都是100)。

3、1字節:Slot狀態,0x00空的,0x01關閉著的,0x02使用中的。

4、1字節:是否是電腦玩家,0x00非電腦玩家,0x01電腦玩家。

5、1字節:隊伍,0~11分別表示隊伍1到隊伍12,12表示裁判或觀看者。

6、1字節:顏色,0紅1藍2青3紫4黃5橘黃6綠7粉8灰9淺藍10深綠11棕12裁判或觀看者

7、1字節:種族,0x01/0x41人族,0x02/0x42獸族,0x04/0x44暗夜精靈,0x08/0x48不死族,0x20/0x60隨機。

8、1字節:電腦難度,0x00簡單的,0x01中等難度的,0x02令人發狂的。

9、1字節:障礙(也就是血量百分比),0x32,0x3C,0x46,0x50,0x5A,0x64之一,分別表示50%到100%。

Java解析:

創建一個UncompressedData類,用于處理解壓縮后的數據。

UncompressedData.java

package com.xxg.w3gparser;

import java.io.UnsupportedEncodingException;

import java.util.ArrayList;

import java.util.List;

public class UncompressedData {

/**

* 解壓縮的字節數組

*/

private byte[] uncompressedDataBytes;

/**

* 解析的字節位置

*/

private int offset;

/**

* 玩家列表

*/

private List playerList = new ArrayList();

/**

* 游戲名稱

*/

private String gameName;

/**

* 地圖路徑

*/

private String map;

/**

* 游戲創建者名稱

*/

private String createrName;

public UncompressedData(byte[] uncompressedDataBytes) throws UnsupportedEncodingException, W3GException {

this.uncompressedDataBytes = uncompressedDataBytes;

// 跳過前4個未知字節

offset += 4;

// 解析第一個玩家

analysisPlayerRecode();

// 游戲名稱(UTF-8編碼)

int begin = offset;

while(uncompressedDataBytes[offset] != 0) {

offset++;

}

gameName = new String(uncompressedDataBytes, begin, offset - begin, "UTF-8");

offset++;

// 跳過一個空字節

offset++;

// 解析一段特殊編碼的字節串,其中包含游戲設置、地圖和創建者

analysisEncodedBytes();

// 跳過PlayerCount、GameType、LanguageID

offset += 12;

// 解析玩家列表

while(uncompressedDataBytes[offset] == 0x16) {

analysisPlayerRecode();

// 跳過4個未知的字節0x00000000

offset += 4;

}

// GameStartRecord - RecordID、number of data bytes following

offset += 3;

// 解析每個Slot

byte slotCount = uncompressedDataBytes[offset];

offset++;

for(int i = 0; i < slotCount; i++) {

analysisSlotRecode(i);

}

// RandomSeed、RandomSeed、StartSpotCount

offset += 6;

}

/**

* 解析PlayerRecode

* @throws UnsupportedEncodingException

*/

private void analysisPlayerRecode() throws UnsupportedEncodingException {

Player player = new Player();

playerList.add(player);

// 是否是主機(0為主機)

byte isHostByte = uncompressedDataBytes[offset];

boolean isHost = isHostByte == 0;

player.setHost(isHost);

offset++;

// 玩家ID

byte playerId = uncompressedDataBytes[offset];

player.setPlayerId(playerId);

offset++;

// 玩家名稱(UTF-8編碼)

int begin = offset;

while(uncompressedDataBytes[offset] != 0) {

offset++;

}

String playerName = new String(uncompressedDataBytes, begin, offset - begin, "UTF-8");

player.setPlayerName(playerName);

offset++;

// 附加數據大小

int additionalDataSize = uncompressedDataBytes[offset];

offset++;

// 加上附加數據大小

offset += additionalDataSize;

}

/**

* 解析特殊編碼的字節串

* @throws UnsupportedEncodingException

*/

private void analysisEncodedBytes() throws UnsupportedEncodingException {

int begin = offset;

while(uncompressedDataBytes[offset] != 0) {

offset++;

}

// 編碼的數據和解碼后的數據的長度

int encodeLength = offset - begin - 1;

int decodeLength = encodeLength - (encodeLength - 1) / 8 - 1;

// 編碼的數據和解碼后的數據

byte[] encodeData = new byte[encodeLength];

byte[] decodeData = new byte[decodeLength];

// 將編碼字節串部分拷貝成一個單獨的字節數組,便于解析

System.arraycopy(uncompressedDataBytes, begin, encodeData, 0, encodeLength);

// 解碼(解碼的代碼來自于http://w3g.deepnode.de/files/w3g_format.txt文檔4.3部分,由C語言代碼翻譯成Java)

byte mask = 0;

int decodePos = 0;

int encodePos = 0;

while (encodePos < encodeLength) {

if (encodePos % 8 == 0) {

mask = encodeData[encodePos];

} else {

if ((mask & (0x1 << (encodePos % 8))) == 0) {

decodeData[decodePos++] = (byte) (encodeData[encodePos] - 1);

} else {

decodeData[decodePos++] = encodeData[encodePos];

}

}

encodePos++;

}

// 直接跳過游戲設置,這部分不再解析了

int decodeOffset = 13;

int decodeBegin = decodeOffset;

// 地圖路徑

while(decodeData[decodeOffset] != 0) {

decodeOffset++;

}

map = new String(decodeData, decodeBegin, decodeOffset - decodeBegin, "UTF-8");

decodeOffset++;

// 主機(游戲創建者)玩家名稱

decodeBegin = decodeOffset;

while(decodeData[decodeOffset] != 0) {

decodeOffset++;

}

createrName = new String(decodeData, decodeBegin, decodeOffset - decodeBegin, "UTF-8");

decodeOffset++;

offset++;

}

/**

* 解析每個Slot

*/

private void analysisSlotRecode(int slotNumber) {

// 玩家ID

byte playerId = uncompressedDataBytes[offset];

offset++;

// 跳過地圖下載百分比

offset++;

// 狀態 0空的 1關閉的 2使用的

byte slotStatus = uncompressedDataBytes[offset];

offset++;

// 是否是電腦

byte computerPlayFlag = uncompressedDataBytes[offset];

boolean isComputer = computerPlayFlag == 1;

offset++;

// 隊伍

byte team = uncompressedDataBytes[offset];

offset++;

// 顏色

byte color = uncompressedDataBytes[offset];

offset++;

// 種族

byte race = uncompressedDataBytes[offset];

offset++;

// 電腦難度

byte aiStrength = uncompressedDataBytes[offset];

offset++;

// 障礙(血量百分比)

byte handicap = uncompressedDataBytes[offset];

offset++;

// 設置玩家列表

if(slotStatus == 2) {

Player player= null;

if(!isComputer) {

player = getPlayById(playerId);

} else {

player = new Player();

playerList.add(player);

}

player.setComputer(isComputer);

player.setAiStrength(aiStrength);

player.setColor(color);

player.setHandicap(handicap);

player.setRace(race);

player.setTeamNumber(team);

player.setSlotNumber(slotNumber);

}

}

/**

* 通過玩家ID獲取Player對象

* @param playerId 玩家ID

* @return 對應的Player對象

*/

private Player getPlayById(byte playerId) {

Player p = null;

for(Player player : playerList) {

if(playerId == player.getPlayerId()) {

p = player;

break;

}

}

return p;

}

public List getPlayerList() {

return playerList;

}

public String getGameName() {

return gameName;

}

public String getMap() {

return map;

}

public String getCreaterName() {

return createrName;

}

}

Player類表示每個玩家的信息,包括電腦玩家。其中slotNumber表示玩家的Slot位置,從0開始,后面將會用于解析聊天信息。

Player.java

package com.xxg.w3gparser;

public class Player {

/**

* 是否是主機

*/

private boolean isHost;

/**

* 玩家ID

*/

private byte playerId;

/**

* 玩家的Slot位置

*/

private int slotNumber;

/**

* 玩家名稱

*/

private String playerName;

/**

* 是否是電腦

*/

private boolean isComputer;

/**

* 0~11:隊伍1~12

* 12:裁判或觀看者

*/

private byte teamNumber;

/**

* 玩家顏色,0紅1藍2青3紫4黃5橘黃6綠7粉8灰9淺藍10深綠11棕12裁判或觀看者

*/

private byte color;

/**

* 種族:0x01/0x41人族,0x02/0x42獸族,0x04/0x44暗夜精靈,0x08/0x48不死族,0x20/0x60隨機

*/

private byte race;

/**

* 電腦級別:0簡單的,1中等難度的,2令人發狂的

*/

private byte aiStrength;

/**

* 障礙,也就血量百分比,取值有50,60,70,80,90,100

*/

private byte handicap;

public boolean isHost() {

return isHost;

}

public void setHost(boolean isHost) {

this.isHost = isHost;

}

public byte getPlayerId() {

return playerId;

}

public void setPlayerId(byte playerId) {

this.playerId = playerId;

}

public String getPlayerName() {

return playerName;

}

public void setPlayerName(String playerName) {

this.playerName = playerName;

}

public boolean isComputer() {

return isComputer;

}

public void setComputer(boolean isComputer) {

this.isComputer = isComputer;

}

public byte getTeamNumber() {

return teamNumber;

}

public void setTeamNumber(byte teamNumber) {

this.teamNumber = teamNumber;

}

public byte getColor() {

return color;

}

public void setColor(byte color) {

this.color = color;

}

public byte getRace() {

return race;

}

public void setRace(byte race) {

this.race = race;

}

public byte getAiStrength() {

return aiStrength;

}

public void setAiStrength(byte aiStrength) {

this.aiStrength = aiStrength;

}

public byte getHandicap() {

return handicap;

}

public void setHandicap(byte handicap) {

this.handicap = handicap;

}

public int getSlotNumber() {

return slotNumber;

}

public void setSlotNumber(int slotNumber) {

this.slotNumber = slotNumber;

}

}

在Replay.java中,加入UncompressedData解析。

Replay.java

package com.xxg.w3gparser;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.util.zip.DataFormatException;

public class Replay {

private Header header;

private UncompressedData uncompressedData;

public Replay(File w3gFile) throws IOException, W3GException, DataFormatException {

// 將文件轉為字節數組,方便處理

byte[] fileBytes = fileToByteArray(w3gFile);

// 解析Header

header = new Header(fileBytes);

// 遍歷解析每個壓縮數據塊,解壓縮,合并

long compressedDataBlockCount = header.getCompressedDataBlockCount();

byte[] uncompressedDataBytes = new byte[0]; // 所有壓縮數據塊中數據解壓合并到這個數組中

int offset = 68;

for(int i = 0; i < compressedDataBlockCount; i++) {

CompressedDataBlock compressedDataBlock = new CompressedDataBlock(fileBytes, offset);

// 數組合并

byte[] blockUncompressedData = compressedDataBlock.getUncompressedDataBytes();

byte[] temp = new byte[uncompressedDataBytes.length + blockUncompressedData.length];

System.arraycopy(uncompressedDataBytes, 0, temp, 0, uncompressedDataBytes.length);

System.arraycopy(blockUncompressedData, 0, temp, uncompressedDataBytes.length, blockUncompressedData.length);

uncompressedDataBytes = temp;

int blockCompressedDataSize = compressedDataBlock.getCompressedDataSize();

offset += 8 + blockCompressedDataSize;

}

// 處理解壓縮后的字節數組

uncompressedData = new UncompressedData(uncompressedDataBytes);

}

/**

* 將文件轉換成字節數組

* @param w3gFile 文件

* @return 字節數組

* @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;

}

public UncompressedData getUncompressedData() {

return uncompressedData;

}

}

修改main方法,測試以上代碼。

Test.java

package com.xxg.w3gparser;

import java.io.File;

import java.io.IOException;

import java.util.List;

import java.util.zip.DataFormatException;

public class Test {

public static void main(String[] args) throws IOException, W3GException, DataFormatException {

Replay replay = new Replay(new File("C:/Documents and Settings/Administrator/桌面/131230_[UD]962030958_VS_[ORC]flygogogo_AncientIsles_RN.w3g"));

Header header = replay.getHeader();

System.out.println("版本:1." + header.getVersionNumber() + "." + header.getBuildNumber());

long duration = header.getDuration();

System.out.println("時長:" + convertMillisecondToString(duration));

UncompressedData uncompressedData = replay.getUncompressedData();

System.out.println("游戲名稱:" + uncompressedData.getGameName());

System.out.println("游戲創建者:" + uncompressedData.getCreaterName());

System.out.println("游戲地圖:" + uncompressedData.getMap());

List list = uncompressedData.getPlayerList();

for(Player player : list) {

System.out.println("---玩家" + player.getPlayerId() + "---");

System.out.println("玩家名稱:" + player.getPlayerName());

if(player.isHost()) {

System.out.println("是否主機:主機");

} else {

System.out.println("是否主機:否");

}

if(player.getTeamNumber() != 12) {

System.out.println("玩家隊伍:" + (player.getTeamNumber() + 1));

switch(player.getRace()) {

case 0x01:

case 0x41:

System.out.println("玩家種族:人族");

break;

case 0x02:

case 0x42:

System.out.println("玩家種族:獸族");

break;

case 0x04:

case 0x44:

System.out.println("玩家種族:暗夜精靈");

break;

case 0x08:

case 0x48:

System.out.println("玩家種族:不死族");

break;

case 0x20:

case 0x60:

System.out.println("玩家種族:隨機");

break;

}

switch(player.getColor()) {

case 0:

System.out.println("玩家顏色:紅");

break;

case 1:

System.out.println("玩家顏色:藍");

break;

case 2:

System.out.println("玩家顏色:青");

break;

case 3:

System.out.println("玩家顏色:紫");

break;

case 4:

System.out.println("玩家顏色:黃");

break;

case 5:

System.out.println("玩家顏色:橘");

break;

case 6:

System.out.println("玩家顏色:綠");

break;

case 7:

System.out.println("玩家顏色:粉");

break;

case 8:

System.out.println("玩家顏色:灰");

break;

case 9:

System.out.println("玩家顏色:淺藍");

break;

case 10:

System.out.println("玩家顏色:深綠");

break;

case 11:

System.out.println("玩家顏色:棕");

break;

}

System.out.println("障礙(血量):" + player.getHandicap() + "%");

if(player.isComputer()) {

System.out.println("是否電腦玩家:電腦玩家");

switch (player.getAiStrength()) {

case 0:

System.out.println("電腦難度:簡單的");

break;

case 1:

System.out.println("電腦難度:中等難度的");

break;

case 2:

System.out.println("電腦難度:令人發狂的");

break;

}

} else {

System.out.println("是否電腦玩家:否");

}

} else {

System.out.println("玩家隊伍:裁判或觀看者");

}

}

}

private static String convertMillisecondToString(long millisecond) {

long second = (millisecond / 1000) % 60;

long minite = (millisecond / 1000) / 60;

if (second < 10) {

return minite + ":0" + second;

} else {

return minite + ":" + second;

}

}

}

程序輸出:

版本:1.26.6059

時長:15:39

游戲名稱:當地局域網內的游戲 (96

游戲創建者:962030958

游戲地圖:Maps\E-WCLMAP\(2)AncientIsles.w3x

---玩家1---

玩家名稱:962030958

是否主機:主機

SlotNumber:0

玩家隊伍:1

玩家種族:不死族

玩家顏色:黃

障礙(血量):100%

是否電腦玩家:否

---玩家2---

玩家名稱:flygogogo

是否主機:否

SlotNumber:1

玩家隊伍:2

玩家種族:獸族

玩家顏色:藍

障礙(血量):100%

是否電腦玩家:否

總結

以上是生活随笔為你收集整理的java解析魔兽争霸3录像_Java解析魔兽争霸3录像W3G文件(三):解析游戏开始前的信息...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 人体裸体bbbbb欣赏 | 波多野结衣在线网址 | 国产在线一 | 国产高清在线 | 台湾佬在线 | 国产精品精品国产 | 久久久88 | 九九九久久久精品 | 国产一区二区三区视频网站 | www.亚洲综合 | 日韩免费精品 | 天天爽夜夜爽一区二区三区 | 中文字幕无人区二 | 亚洲国产精品成人va在线观看 | 日韩欧美在线观看一区二区 | 亚洲精品污一区二区三区 | 婷婷狠狠 | 欧美日韩精品一二三区 | 一级裸体片 | 国产九色视频 | 国产视频一区二区三区在线观看 | jzzijzzij亚洲成熟少妇在线播放 狠狠躁日日躁夜夜躁2022麻豆 | 国产这里只有精品 | 成人精品久久久 | 色a视频 | 91gao| 国产精品人人妻人人爽人人牛 | 国产一区欧美日韩 | 成人激情五月天 | 波多野结衣av一区二区全免费观看 | 久久精品视频中文字幕 | 91精品播放 | 日韩国产中文字幕 | 亚洲av电影天堂男人的天堂 | 性久久久 | 涩色网站| 丰满少妇aaaaaa爰片毛片 | 欧美性一区二区三区 | 韩国黄色网 | av中文字幕一区二区三区 | av在线网页| 免费在线观看中文字幕 | 农村老女人av | 农村搞破鞋视频大全 | 国产综合久久久久久鬼色 | 黄色aa视频 | 欧美在线观看免费高清 | 天天躁日日躁狠狠躁 | 尤物毛片| 爱爱色图| 成人动漫h在线观看 | 日韩精品久久久久久久酒店 | 日日干夜夜操 | 欧美多人猛交狂配 | 久久日本精品字幕区二区 | 久久狠狠干 | 夜夜导航| 免费看污黄网站在线观看 | www.桃色av嫩草.com| 久久久久亚洲AV成人网人人小说 | 欧洲一区二区三区四区 | 国产福利影院 | 久久综合丁香 | 男女视频免费网站 | www.奇米| 99国产精品国产免费观看 | 久草视频在线播放 | 中文字幕第4页 | 成人一级大片 | 一区二区国产在线 | 欧美一性一交 | 日本美女动态 | 成人免费无码大片a毛片抽搐色欲 | 男男play呻吟动漫网站 | 男插女动态图 | 亚洲一区在线免费观看 | 精品久久久久久一区二区里番 | 韩国女主播裸体摇奶 | 亚州春色| 五月天社区 | mm1313亚洲国产精品无码试看 | 天天人人综合 | 亚洲精品久久久久久久久久久 | 青青草99 | 国产精品女主播 | 影音先锋日韩资源 | 欧美一区二区三区四区五区六区 | 天堂在线观看视频 | 美女色诱男人激情视频 | 自拍欧美日韩 | 欧美人与禽性xxxxx杂性 | 中文永久免费观看 | 亚洲 欧美 综合 | 免费大黄网站 | 久久免费播放视频 | 99热网站 | 色综合av | 成人性爱视频在线观看 | 澳门超碰 |