• Welcome to Valhalla Legends Archive.
 

Reading a Warcraft III Replay???

Started by Miraglade, July 10, 2004, 04:15 AM

Previous topic - Next topic

Miraglade

How would you go about gathing information from a warcraft replay file?
--Players, Map, Races, etc.

I have looked at this site http://photoduhavre.free.fr/notes.htm , but im not sure how to get to that stage :/

Any information about how to go about this would be helpful (a rough outline would be nice)
*Any code would need to be in Java of course
*If you can tell already im pretty much a noob with Java (pretty much all programming)
--So ignor my noobness or any misspellings :)

Tuberload

I found some more current information on the replay file format here.

This does sound interesting so I might try and take on this project. If I do I will post my results when I get them.
Quote"Pray not for lighter burdens, but for stronger backs." -- Teddy Roosevelt
"Your forefathers have given you freedom, so good luck, see you around, hope you make it" -- Unknown

Tuberload

Here is what I have so far. It reads the first part of the header and displays it. Tomorrow I will make it parse the sub header and data blocks. From there all you have to do is figure out the compression, and how to play the replay. HTH.

WC3RHeader.java:
package tuberload.wc3.replay;
import java.io.BufferedInputStream;
import java.io.IOException;
import tuberload.util.Array;
import tuberload.util.ByteBuffer;
/**
*   Constructs the Warcraft III Replay header information.
*/
public class WC3RHeader
{
   // Replay header information
   private char[] file_desc = new char[26];
   private int unknown_1;            // always 0x1A00 so fatr
   private int head_size;
   private int file_size;
   private int replay_ver;
   private int decomp_size;
   private int data_blocks;         // number of data blockes
   // Subheader information
   private WC3RSubHeader sub_head;
   
   /**
    *   Initialize the header.
    */
   public WC3RHeader (BufferedInputStream bos) throws IOException
   {
      // create byte buffer
      ByteBuffer bb = new ByteBuffer();
      byte[] data = new byte[bos.available()];
      bos.read (data, 0, bos.available());
      bb.insertByte (data);
      // get file description
      data = new byte[26];
      data = bb.getBytes (0, 26);
      for (int i = 0; i < 26; i++)
         file_desc[i] = (char)data[i];
      // unknown 1
      unknown_1 = bb.getWord (0x1a);
      // header size/subheader location
      head_size = bb.getDword (0x1c);
      // file size
      file_size = bb.getDword (0x20);
      // replay version
      replay_ver = bb.getDword (0x24);
      // decompressed file size
      decomp_size = bb.getDword (0x28);
      // the number of compressed data blocks
      data_blocks = bb.getDword (0x2c);
      // get the subheader information
      if (replay_ver == 0x00)
      {
         // load sub header
      }
      else if (replay_ver == 0x01)
      {
         // load sub header 1
      }
      else
         System.out.println ("Unknown replay version!");
      
   }
   /**
    *   Get the number of compressed data blocks.
    */
   public int getDataBlocksCount()
   {
      return data_blocks;
   }
   /**
    *   Get the file size after decompression.
    */
   public int getDecompressedSize()
   {
      return decomp_size;
   }
   /**
    *   Get the file size.
    */
   public int getFileSize()
   {
      return file_size;
   }
   /**
    *   Get the replay version.
    */
   public int getReplayVersion()
   {
      return replay_ver;
   }
   /**
    *   Get the header size.
    */
   public int getHeaderSize()
   {
      return head_size;
   }
   /**
    *   Get the file description.
    */
   public char[] getFileDescription()
   {
      return file_desc;
   }
   
}


WC3RSubHeader.java
package tuberload.wc3.replay;
import java.io.BufferedInputStream;
import java.io.IOException;

public abstract class WC3RSubHeader
{
   protected int unknown_1;      // uknown_1 and patch_ver switch in header1
   protected int patch_ver;
   protected int build_num;
   protected int players_flag;      // single/multiplayer
   protected int replay_len;      // milliseconds
   protected int checksum;
}


WC3RSubHeader1.java
package tuberload.wc3.replay;

public class WC3RSubHeader1 extends WC3RSubHeader
{
   protected int ver_ident;      // Classic/Expansion
}


WC3RMain.java
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import tuberload.wc3.replay.WC3RHeader;
import tuberload.wc3.replay.WC3RSubHeader;

public class WC3Main
{
   public static void main (String[] args)
   {
      try
      {
         BufferedInputStream bos = new BufferedInputStream (
            new FileInputStream ("Jeremy1.w3g"));
         WC3RHeader header = new WC3RHeader (bos);
         
         System.out.println ("File Description: "
            + String.valueOf (header.getFileDescription()));
         System.out.println ("Header Size: " + header.getHeaderSize());
         System.out.println ("File Size: " + header.getFileSize());
         System.out.println ("Decompressed Size: "
            + header.getDecompressedSize());
         System.out.println ("Replay Version: " + header.getReplayVersion());
         System.out.println ("Number of Compressed Data Blocks: "
            + header.getDataBlocksCount());
      }
      catch (IOException exc) { System.out.println (exc.getStackTrace()); }
   }
}
Quote"Pray not for lighter burdens, but for stronger backs." -- Teddy Roosevelt
"Your forefathers have given you freedom, so good luck, see you around, hope you make it" -- Unknown

UserLoser.

It would be quite an interesting project to write a program to view replays.

Tuberload

If anyone has a replay from version 1.06 or below it would be very helpful for testing purposes, otherwise I will just reinstall WC3 tonight and make my own.

TIA
Quote"Pray not for lighter burdens, but for stronger backs." -- Teddy Roosevelt
"Your forefathers have given you freedom, so good luck, see you around, hope you make it" -- Unknown

UserLoser.

#5
Quote from: Tuberload on July 11, 2004, 02:18 PM
If anyone has a replay from version 1.06 or below it would be very helpful for testing purposes, otherwise I will just reinstall WC3 tonight and make my own.

TIA


Why 1.06?  I have plenty of 1.16 if you'd like some.

Edit: Nevermind, I see on that document it mentions about 1.06 and below, is different than 1.07 and up.

Tuberload

Quote from: UserLoser. on July 11, 2004, 04:00 PMWhy 1.06?  I have plenty of 1.16 if you'd like some.

The replay file format changes after 1.07 and I wanted to make it backwards compatible. I have 1.16 installed right now so I have no way of making an old replay.
Quote"Pray not for lighter burdens, but for stronger backs." -- Teddy Roosevelt
"Your forefathers have given you freedom, so good luck, see you around, hope you make it" -- Unknown

Tuberload

#7
Code update: it now fully reads the header information and displays it. It is setup to handle old replay files, but I have been unable to test it so far so it might not work correctly.

WC3RHeader.java:
package tuberload.wc3.replay;
import java.io.BufferedInputStream;
import java.io.IOException;
import tuberload.util.Array;
import tuberload.util.ByteBuffer;
/**
*   Constructs the Warcraft III Replay header information.
*/
public class WC3RHeader
{
   // Replay header information
   private char[] file_desc = new char[26];
   private int unknown_1;            // always 0x1A00 so far
   private int head_size;
   private int file_size;
   private int replay_ver;
   private int decomp_size;
   private int data_blocks;         // number of data blocks
   // Subheader information
   private WC3RSubHeader sub_head;      // created based on replay version
   
   /**
    *   Initialize the header.
    */
   public WC3RHeader (BufferedInputStream bos) throws IOException
   {
      // create byte buffer
      ByteBuffer bb = new ByteBuffer();
      byte[] data = new byte[bos.available()];
      bos.read (data, 0, bos.available());
      bb.insertByte (data);
      // get file description
      data = new byte[26];
      data = bb.getBytes (0, 26);
      for (int i = 0; i < 26; i++)
         file_desc[i] = (char)data[i];
      // unknown 1
      unknown_1 = bb.getWord (0x1a);
      // header size/subheader location
      head_size = bb.getDword (0x1c);
      // file size
      file_size = bb.getDword (0x20);
      // replay version
      replay_ver = bb.getDword (0x24);
      // decompressed file size
      decomp_size = bb.getDword (0x28);
      // the number of compressed data blocks
      data_blocks = bb.getDword (0x2c);
      // get the subheader information
      if (replay_ver == 0x00)
      {
         sub_head = new WC3RSubHeader (bb);
      }
      else if (replay_ver == 0x01)
      {
         sub_head = new WC3RSubHeader1 (bb);
      }
      else
         System.out.println ("Unknown replay version!");
      
   }
   /**
    *   Get the subheader information.
    */
   public WC3RSubHeader getSubHeader()
   {
      return sub_head;
   }
   /**
    *   Get the number of compressed data blocks.
    */
   public int getDataBlocksCount()
   {
      return data_blocks;
   }
   /**
    *   Get the file size after decompression.
    */
   public int getDecompressedSize()
   {
      return decomp_size;
   }
   /**
    *   Get the file size.
    */
   public int getFileSize()
   {
      return file_size;
   }
   /**
    *   Get the replay version.
    */
   public int getReplayVersion()
   {
      return replay_ver;
   }
   /**
    *   Get the header size.
    */
   public int getHeaderSize()
   {
      return head_size;
   }
   /**
    *   Get the file description.
    */
   public char[] getFileDescription()
   {
      return file_desc;
   }
}


WC3RSubHeader.java
package tuberload.wc3.replay;
import tuberload.util.ByteBuffer;

public class WC3RSubHeader
{
   protected int unknown_1;      // uknown_1 and patch_ver switch in sub header1
   protected int patch_ver;
   protected int build_num;
   protected int players_flag;      // single/multiplayer
   protected int replay_len;      // milliseconds
   protected int checksum;
   /**
    *   Initialize the subheader.
    */
   public WC3RSubHeader (ByteBuffer bb)
   {
      unknown_1 = bb.getWord (0x30);
      patch_ver = bb.getWord (0x32);
      build_num = bb.getWord (0x34);
      players_flag = bb.getWord (0x36);
      replay_len = bb.getDword (0x38);
      checksum = bb.getDword (0x3c);
   }
   /**   
    *   Get the replay length.
    */
   public int getReplayLength()
   {
      return replay_len;
   }
   /**
    *   Get the replay checksum.
    */
   public int getChecksum()
   {
      return checksum;
   }
   /**
    *   Get the patch version.
    */
   public int getGamePatchVersion()
   {
      return patch_ver;
   }
   /**
    *   Get the build number.
    */
   public int getGameBuildNumber()
   {
      return build_num;
   }
   /**
    *   Get the number of players flag.
    */
   public boolean isMultiplayer()
   {
      boolean multi = false;
      if (players_flag == 0x8000)
         multi = true;
      return multi;
   }
   /**
    *   Get the game type.
    */
   public boolean isExpansion()
   {
      return false;
   }
}


WC3RSubHeader1.java
package tuberload.wc3.replay;
import tuberload.util.ByteBuffer;

public class WC3RSubHeader1 extends WC3RSubHeader
{
   protected int ver_ident;      // Classic/Expansion
   /**
    *   Initialize the subheader v1
    */
   public WC3RSubHeader1 (ByteBuffer bb)
   {
      super (bb);
      ver_ident = bb.getDword (0x30);
      patch_ver = bb.getDword (0x34);
      build_num = bb.getWord (0x38);
      players_flag = bb.getWord (0x3a);
      replay_len = bb.getDword (0x3c);
      checksum = bb.getDword (0x40);
   }
   /**
    *   Get the game type.
    */
   public boolean isExpansion()
   {
      boolean expansion = false;
      if (ver_ident != 0x57415233)
         expansion = true;
      return expansion;
   }
}


WC3Main.java
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import tuberload.wc3.replay.WC3RHeader;
import tuberload.wc3.replay.WC3RSubHeader;

public class WC3Main
{
   public static void main (String[] args)
   {
      try
      {
         BufferedInputStream bos = new BufferedInputStream (
            new FileInputStream ("Jeremy1.w3g"));
         WC3RHeader header = new WC3RHeader (bos);
         WC3RSubHeader sub_head = header.getSubHeader();
         
         System.out.println ("File Description: "
            + String.valueOf (header.getFileDescription()));
         System.out.println ("Header Size: " + header.getHeaderSize());
         System.out.println ("File Size: " + header.getFileSize());
         System.out.println ("Decompressed Size: "
            + header.getDecompressedSize());
         System.out.println ("Replay Version: " + header.getReplayVersion());
         System.out.println ("Number of Compressed Data Blocks: "
            + header.getDataBlocksCount());
         System.out.println ("Game Patch Version: "
            + sub_head.getGamePatchVersion());
         System.out.println ("Game Build: " + sub_head.getGameBuildNumber());
         System.out.println ("Replay Length: " + sub_head.getReplayLength());
         System.out.println ("Expansion Game:: " + sub_head.isExpansion());
         System.out.println ("Multiplayer: " + sub_head.isMultiplayer());
         System.out.println ("Checksum: " + sub_head.getChecksum());
      }
      catch (IOException exc) { System.out.println (exc.getStackTrace()); }
   }
}


I believe the replay data is compressed using zlib, so I will work on decompressing and displaying the data blocks next.
Quote"Pray not for lighter burdens, but for stronger backs." -- Teddy Roosevelt
"Your forefathers have given you freedom, so good luck, see you around, hope you make it" -- Unknown

dxoigmn

What is the reasoning behind creating your own ByteBuffer?

Tuberload

Quote from: dxoigmn on July 11, 2004, 04:38 PM
What is the reasoning behind creating your own ByteBuffer?

I have been working on my own library for quite some time now. No real reasoning behind it other than learning. Basically I do it for shits and giggles and an occasional brain cell addition. ;)
Quote"Pray not for lighter burdens, but for stronger backs." -- Teddy Roosevelt
"Your forefathers have given you freedom, so good luck, see you around, hope you make it" -- Unknown

dxoigmn

#10
Quote from: Tuberload on July 11, 2004, 04:40 PM
Quote from: dxoigmn on July 11, 2004, 04:38 PM
What is the reasoning behind creating your own ByteBuffer?

I have been working on my own library for quite some time now. No real reasoning behind it other than learning. Basically I do it for shits and giggles and an occasional brain cell addition. ;)

Heh.  I was going to say the ByteBuffer in java.nio is pretty robust; but whatever floats your boat ;)

muert0

#11
If you know where to get the 1.06 patch from or if 1.00 will work I'll reinstall and run a game for you.

NVM I think I found the patch on the blizzard FTP I'm gonna uninstall and reinstall now.
To lazy for slackware.

Tuberload

Quote from: muert0 on July 11, 2004, 05:30 PM
If you know where to get the 1.06 patch from or if 1.00 will work I'll reinstall and run a game for you.

NVM I think I found the patch on the blizzard FTP I'm gonna uninstall and reinstall now.

1.00 will work, and thanks.
Quote"Pray not for lighter burdens, but for stronger backs." -- Teddy Roosevelt
"Your forefathers have given you freedom, so good luck, see you around, hope you make it" -- Unknown

Tuberload

Thanks to meurt0 I was able to test it on versions previous to 1.07 and it works fine.
Quote"Pray not for lighter burdens, but for stronger backs." -- Teddy Roosevelt
"Your forefathers have given you freedom, so good luck, see you around, hope you make it" -- Unknown

Tuberload

#14
On a side note to anyone who may be interested, while that documentation is a very good start I have been running a crossed errors and inconsistency in the data so you may have to figure a few things out.

I will be writing my own documentation for the file format as I figure it out. I figure it is a good enough place to start learning such a thing.
Quote"Pray not for lighter burdens, but for stronger backs." -- Teddy Roosevelt
"Your forefathers have given you freedom, so good luck, see you around, hope you make it" -- Unknown