In the last blog post, you get a byte array of compressed data by decompressing and merging the compressed chunks. From now on, this data will be processed.
The data in this section mainly includes two types of information: one is the information before the game , such as game map, game player, team, race, advanced options, etc., which have been identified before entering the game, and the other is the information of the game. This includes players in the process of the operation of the game, chat in the game. The information before the game begins to take up the first part of the uncompressed data, followed by a large part of the information that keeps the game in progress.
This article describes how to parse the information before the game starts.
The structure of the information before the game begins:
Note: In the following parts of the structure of the explanation, gray font callout information does not parse it, no longer detailed, to understand that you can refer to the W3g_format.txt document.
I. Overall structure
1, 4 bytes: unknown.
2, Variable bytes: Host player record (Detailed view "second, player record").
3, variable byte: Game name, string, end with 0x00.
4, 1 bytes: Empty byte, 0x00.
5, Variable bytes: Specially encoded data (including game settings, maps, creator), End with 0x00 (Detailed View "Three, specially encoded data").
6, 4 bytes: number of players.
7, 4 bytes: Game type.
8, 4 bytes: unknown.
9, Variable bytes: Join the game player list (Detailed view: "Four, join the game player list" and "second, player record").
10, variable byte: Slot list (Detailed view: "Five, slot list").
Second, the player record
1, 1 bytes: Player type, 0x00 host, 0x16 join the game player ("Four, join the game player list").
2, 1 bytes: Player ID.
3, variable byte: player name, End with 0x00.
4, 1 bytes: Additional data size, 0x01 or 0x08.
5, 1, or 8 bytes: Append data.
Third, specially encoded data
This is a special code of data, this part needs to decode to continue parsing, decoding the way directly to see the following code, here no longer introduced.
After decoding:
1, 4 bytes: Game settings, this section contains some advanced options, the following figure, but this part of the few people to change, so here no longer to parse.
2, 5 bytes: unknown.
3, 4 bytes: map check.
4, variable byte: Map path, string, end with 0x00.
5, Variable bytes: Creator, string, ending with 0x00.
Four, join the game player list
If more than one player joins the game, each player corresponds to one of the following structures. Since it is a player who joins the game, each player's corresponding data is 0x16. The player list ends when traversing to the first byte is not 0x16. Note that the list of players who joined the game does not contain computer players, and computer players are in the "Five, slot list".
1, Variable bytes: Player record (Detailed view "second, player record").
2, 4 bytes: 0x00000000.
V. List of slot
A slot is a player's position in the interface before the game starts. The following figure, that is, 4 slot.
1, 1 bytes: fixed 0x19.
2, 2 bytes: The number of bytes in the following data.
3, 1 bytes: slot quantity.
4, variable byte: Slot the list of records, which contains multiple slot records, the number is the value of the above byte (Detailed view of "six, slot record").
5, 4 bytes: Random seed.
6, 1 bytes: Whether the team, race can choose.
7, 1 bytes: Number of positions in the map.
Vi. Record of slot
Each slot occupies 9 bytes:
1, 1 bytes: the corresponding Player ID, the computer player is 0x00.
2, 1 bytes: Map download percentage (usually 100).
3, 1 bytes: slot state, 0x00 empty, 0x01 closed, 0x02 in use.
4, 1 bytes: Whether it is computer players, 0x00 not computer players, 0x01 computer players.
5, 1 bytes: The team, 0~11, respectively, indicates that the team 1 to the troop 12,12 represents the referee or the viewer.
6, 1 bytes: color, 0 Red 1 Blue 2 green 3 Purple 4 yellow 5 Orange 6 Green 7 Powder 8 Gray 9 Blue 10 dark green 11 brown 12 Referee or viewer
7, 1 bytes: Race, 0x01/0x41, 0x02/0x42 orc, 0x04/0x44 night Elves, 0x08/0x48 Undead, 0x20/0x60 random.
8, 1 bytes: computer difficulty, 0x00 simple, 0x01 medium difficulty, 0x02 maddening.
9, 1 bytes: Barrier (that is, the percentage of blood), one of the 0x32,0x3c,0x46,0x50,0x5a,0x64, representing 50% to 100% respectively.
Java parsing:
Create a Uncompresseddata class that you can use to understand the compressed data.
Uncompresseddata.java
Package com.xxg.w3gparser;
Import java.io.UnsupportedEncodingException;
Import java.util.ArrayList;
Import java.util.List;
public class Uncompresseddata {/** * uncompressed byte array/private byte[] uncompresseddatabytes;
/** * parsed byte position */private int offset;
/** * Player List * * Private list<player> playerlist = new arraylist<player> ();
/** * Game name/private String gamename;
/** * Map path/private String map;
/** * Game Creator name */private String creatername; Public Uncompresseddata (byte[] uncompresseddatabytes) throws Unsupportedencodingexception, w3gexception {This.uncomp
Resseddatabytes = uncompresseddatabytes;
Skip the first 4 unknown bytes offset = 4;
Parse the first player Analysisplayerrecode ();
Game Name (UTF-8 encoded) int begin = Offset;
while (Uncompresseddatabytes[offset]!= 0) {offset++;
} gamename = new String (uncompresseddatabytes, Begin, Offset-begin, "UTF-8");
offset++;
Skips over an empty byte offset++; Parse a specially encoded byte string containing the game settings, theFigure and creator Analysisencodedbytes ();
Skip Playercount, gametype, LanguageID offset = 12;
Resolves the player list while (uncompresseddatabytes[offset] = = 0x16) {analysisplayerrecode ();
Skipped 4 Unknown bytes 0x00000000 offset = 4;
//Gamestartrecord-recordid, number of data bytes following offset = 3;
Parse each slot byte slotcount = Uncompresseddatabytes[offset];
offset++;
for (int i = 0; i < Slotcount i++) {analysisslotrecode (i);
}//Randomseed, Randomseed, startspotcount offset + + 6; /** * Parsing Playerrecode * @throws unsupportedencodingexception * * private void Analysisplayerrecode () throws Uns
upportedencodingexception {Player player = new player ();
Playerlist.add (player);
is the host (0 as host) byte ishostbyte = Uncompresseddatabytes[offset];
Boolean ishost = Ishostbyte = = 0;
Player.sethost (Ishost);
offset++;
Player ID byte playerID = uncompresseddatabytes[offset];
Player.setplayerid (playerID);
offset++; PlayersName (UTF-8 encoded) int begin = Offset;
while (Uncompresseddatabytes[offset]!= 0) {offset++;
string playername = new String (uncompresseddatabytes, Begin, Offset-begin, "UTF-8");
Player.setplayername (PlayerName);
offset++;
Additional data size int additionaldatasize = Uncompresseddatabytes[offset];
offset++;
Plus additional data size offset + = additionaldatasize; /** * Parse a specially encoded byte string * @throws unsupportedencodingexception * * private void Analysisencodedbytes () throws Unsupp
ortedencodingexception {int begin = offset;
while (Uncompresseddatabytes[offset]!= 0) {offset++;
}//encoded data and the length of the decoded data int encodelength = offset-begin-1;
int decodelength = encodelength-(encodeLength-1)/8-1;
Encoded data and decoded data byte[] Encodedata = new Byte[encodelength];
byte[] Decodedata = new Byte[decodelength];
Copies the encoded byte string part into a separate byte array, which is convenient for parsing system.arraycopy (uncompresseddatabytes, Begin, Encodedata, 0, encodelength); Decoding (decoding code from Http://w3g.deepnode. de/files/w3g_format.txt document 4.3, translated from C language code to 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[enc
Odepos]-1);
else {decodedata[decodepos++] = Encodedata[encodepos];
}} encodepos++;
//Skip the game settings directly, this part no longer resolves the int decodeoffset = 13;
int decodebegin = Decodeoffset;
Map path while (Decodedata[decodeoffset]!= 0) {decodeoffset++;
The map = new String (Decodedata, Decodebegin, Decodeoffset-decodebegin, "UTF-8");
decodeoffset++;
Host (game creator) player name decodebegin = Decodeoffset;
while (Decodedata[decodeoffset]!= 0) {decodeoffset++;
} creatername = new String (Decodedata, Decodebegin, Decodeoffset-decodebegin, "UTF-8");
decodeoffset++;
offset++; /** * resolves each slot/private void AnalysisslOtrecode (int slotnumber) {//player ID byte playerID = uncompresseddatabytes[offset];
offset++;
Skip map Download percent offset++;
The state 0-empty 1-closed 2 used byte slotstatus = Uncompresseddatabytes[offset];
offset++;
is the computer byte Computerplayflag = Uncompresseddatabytes[offset];
Boolean Iscomputer = Computerplayflag = = 1;
offset++;
Troop byte team = Uncompresseddatabytes[offset];
offset++;
Color byte color = Uncompresseddatabytes[offset];
offset++;
Race byte race = Uncompresseddatabytes[offset];
offset++;
Computer difficulty byte aistrength = Uncompresseddatabytes[offset];
offset++;
Barrier (percentage of blood) byte handicap = Uncompresseddatabytes[offset];
offset++;
Set player list 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); /** * Get Player Object * through Player ID * @param playerid player ID * @return corresponding Player object/private player Getplaybyid (b
Yte playerID) {Player p = null;
for (player player:playerlist) {if (playerID = = Player.getplayerid ()) {p = player;
Break
} return p;
Public list<player> getplayerlist () {return playerlist;
Public String Getgamename () {return gamename;
Public String Getmap () {return map;
Public String Getcreatername () {return creatername; }
}
The Player class represents information for each player, including computer players. Where SlotNumber represents the player's slot position, starting with 0, will be used to parse the chat information later.
Player.java
Package com.xxg.w3gparser;
public class Player {/** * is a host/private Boolean ishost;
/** * Player ID */private byte playerID;
/** * Player's slot position * * private int slotnumber;
/** * Player Name */private String playername;
/** * is the computer * * Private Boolean iscomputer;
/** * 0~11: Team 1~12 * 12: Referee or Viewer/private byte Teamnumber;
/** * Player color, 0 Red 1 Blue 2 green 3 Purple 4 yellow 5 Orange 6 Green 7 Powder 8 Gray 9 Blue 10 dark black 11 brown 12 Referee or viewer * * private byte color;
/** * Race: 0x01/0x41, 0x02/0x42 orc, 0x04/0x44 night elf, 0x08/0x48 Undead, 0x20/0x60 random * * Private byte race;
/** * Computer level: 0 simple, 1 medium difficulty, 2 maddening * * Private byte aistrength;
/** * Obstacle, also on the percentage of blood, take the value of 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;
The public void setslotnumber (int slotnumber) {this.slotnumber = SlotNumber; }
}
In Replay.java, add uncompresseddata parsing.
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 {//Convert file to byte array for easy processing byte[] Fileby
TES = Filetobytearray (w3gfile);
Parse Header Header = new header (filebytes);
traversal resolves each compressed block of data, decompressing, merging long compresseddatablockcount = Header.getcompresseddatablockcount (); byte[] uncompresseddatabytes = new Byte[0];
Data decompression in all compressed data blocks merged into this array int offset = 68; for (int i = 0; i < Compresseddatablockcount i++) {compresseddatablock Compresseddatablock = new Compresseddatabloc
K (filebytes, offset);
Array merge 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;
To understand the compressed byte array uncompresseddata = new Uncompresseddata (uncompresseddatabytes); /** * Convert file to byte array * @param w3gfile file * @return byte array * @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 ();
The public header, GetHeader () {return header;
Public Uncompresseddata Getuncompresseddata () {return uncompresseddata; }
}
Modify the main method to test the above code.
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/desktop/131230_[ud]962030958_vs_[orc]"
FLYGOGOGO_ANCIENTISLES_RN.W3G "));
Header Header = Replay.getheader ();
System.out.println ("version: 1." + header.getversionnumber () + "." + Header.getbuildnumber ());
Long Duration = Header.getduration ();
System.out.println ("Time Length:" + convertmillisecondtostring (duration));
Uncompresseddata uncompresseddata = Replay.getuncompresseddata ();
System.out.println ("Game Name:" + uncompresseddata.getgamename ());
System.out.println ("Game Creator:" + Uncompresseddata.getcreatername ());
System.out.println ("Game map:" + uncompresseddata.getmap ()); list<player> list = Uncompresseddata.getplayerlist ();
for (player player:list) {System.out.println ("---player" + player.getplayerid () + "---");
System.out.println ("Player name:" + player.getplayername ());
if (Player.ishost ()) {System.out.println ("Host: Host");
else {System.out.println ("host: No");
} if (Player.getteamnumber ()!=) {System.out.println ("Player team:" + (Player.getteamnumber () + 1));
Switch (Player.getrace ()) {case 0x01:case 0x41:system.out.println ("Player race: Terran");
Break
Case 0x02:case 0x42:system.out.println ("Player race: Orc clan");
Break
Case 0x04:case 0x44:system.out.println ("Player Race: Night Elf");
Break
Case 0x08:case 0x48:system.out.println ("Player race: Undead");
Break Case 0x20:case 0x60:system.out.println ("playerRace: Random ");
Break
Switch (Player.getcolor ()) {case 0:system.out.println ("Player color: Red");
Break
Case 1:SYSTEM.OUT.PRINTLN ("Player color: Blue");
Break
Case 2:SYSTEM.OUT.PRINTLN ("Player color: green");
Break
Case 3:SYSTEM.OUT.PRINTLN ("Player color: Violet");
Break
Case 4:SYSTEM.OUT.PRINTLN ("Player color: yellow");
Break
Case 5:SYSTEM.OUT.PRINTLN ("Player color: orange");
Break
Case 6:SYSTEM.OUT.PRINTLN ("Player color: green");
Break
Case 7:SYSTEM.OUT.PRINTLN ("Player color: Powder");
Break
Case 8:SYSTEM.OUT.PRINTLN ("Player color: Gray");
Break
Case 9:SYSTEM.OUT.PRINTLN ("Player Color: Light blue");
Break
Case 10:SYSTEM.OUT.PRINTLN ("Player color: Dark green");
Break
Case 11:SYSTEM.OUT.PRINTLN ("Player color: Brown");
Break } System.out.println ("Barrier (blood volume):" + player.getHandicap () + "%");
if (Player.iscomputer ()) {System.out.println ("Whether computer player: computer player");
Switch (Player.getaistrength ()) {case 0:SYSTEM.OUT.PRINTLN ("Computer difficulty: simple");
Break
Case 1:SYSTEM.OUT.PRINTLN ("Computer Difficulty: Medium difficulty");
Break
Case 2:SYSTEM.OUT.PRINTLN ("Computer Difficulty: maddening");
Break
} else {System.out.println ("Whether computer player: no");
} else {System.out.println ("player team: Referee or viewer"); }} private static String convertmillisecondtostring (long millisecond) {Long second =
(millisecond/1000)% 60;
Long Minite = (millisecond/1000)/60;
if (second <) {return minite + ": 0" + second;
else {return minite + ":" + second; }
}
}
Program output:
Version: 1.26.6059
Duration: 15:39
Game Name: Local LAN Games (96
Game created by: 962030958
Game map: maps\e-wclmap\ (2) ancientisles.w3x
---player 1---
Player Name: 962030958
Host: Host
slotnumber:0
Player team: 1
Player Race: Undead
Player color: Yellow
Barrier (blood volume): 100%
Whether the computer player: no
---player 2---
Player Name: Flygogogo
Host: No
Slotnumber:1
Player team: 2
Player Race: Orc
Player color: Blue
Barrier (blood volume): 100%
Whether the computer player: no
Reference Document: Http://w3g.deepnode.de/files/w3g_format.txt
Author: Fork Brother reproduced Please specify the source: http://blog.csdn.net/xiao__gui/article/details/18218003