Beispiel #1
0
        // 4.1 [PlayerRecord]
        internal void Load(BinaryReader reader)
        {
            #region doc
            //offset | size/type | Description
            //-------+-----------+-----------------------------------------------------------
            //0x0000 |  1 byte   | RecordID:
            //       |           |  0x00 for game host
            //       |           |  0x16 for additional players (see 4.9)
            //0x0001 |  1 byte   | PlayerID
            //0x0002 |  n bytes  | PlayerName (null terminated string)
            //   n+2 |  1 byte   | size of additional data:
            //       |           |  0x01 = custom
            //       |           |  0x08 = ladder
            #endregion
            //RecordId
            reader.ReadByte();
            playerId = reader.ReadByte();
            name     = ParserUtility.ReadString(reader);
            gameType = (GameType)reader.ReadByte();

            if (gameType == GameType.Custom)
            {
                reader.ReadByte();
            }
            else
            {
                //time
                reader.ReadInt32();
                Race = (Race)reader.ReadUInt32();
            }
        }
Beispiel #2
0
        internal void Train(string ability, int time)
        {
            string heroName = ParserUtility.GetHeroByAbility(ability);

            foreach (Hero hero in heroes)
            {
                if (hero.Name == heroName)
                {
                    hero.Train(ability, time);
                }
            }
        }
Beispiel #3
0
        private void OrderItem(Player player, uint itemId, int time)
        {
            if (itemId < 0x41000000 || itemId > 0x7a000000)
            {
                return;
            }
            string stringId = ParserUtility.StringFromUInt(itemId);

            switch (ParserUtility.ItemTypeFromId(stringId))
            {
            case ItemType.None:
                if ((itemId >> 16) == 0x00000233)
                {
                    player.Units.Order(new OrderItem("ubsp", time));
                }
                break;

            case ItemType.Hero:
                player.Heroes.Order(stringId, time);
                break;

            case ItemType.HeroAbility:
                player.Heroes.Train(stringId, time);
                break;

            case ItemType.Building:
                player.Buildings.Order(new OrderItem(stringId, time));
                break;

            case ItemType.Item:
                player.Items.Order(new OrderItem(stringId, time));
                if (stringId == "tret")
                {
                    player.Heroes.PossibleRetrained(time);
                }
                break;

            case ItemType.Unit:
                player.Units.Order(new OrderItem(stringId, time));
                break;

            case ItemType.Upgrade:
                player.Upgrades.Order(new OrderItem(stringId, time));;
                break;

            case ItemType.Research:
                player.Researches.Order(new OrderItem(stringId, time));;
                break;
            }
        }
Beispiel #4
0
        private void LoadPlayers(BinaryReader reader)
        {
            #region 4.0 [Decompressed data]

            #region doc

            // # |   Size   | Name
            //---+----------+--------------------------
            // 1 |   4 byte | Unknown (0x00000110 - another record id?)
            // 2 | variable | PlayerRecord (see 4.1)
            // 3 | variable | GameName (null terminated string) (see 4.2)
            // 4 |   1 byte | Nullbyte
            // 5 | variable | Encoded String (null terminated) (see 4.3)
            //   |          |  - GameSettings (see 4.4)
            //   |          |  - Map&CreatorName (see 4.5)
            // 6 |   4 byte | PlayerCount (see 4.6)
            // 7 |   4 byte | GameType (see 4.7)
            // 8 |   4 byte | LanguageID (see 4.8)
            // 9 | variable | PlayerList (see 4.9)
            //10 | variable | GameStartRecord (see 4.11)

            #endregion
            //Unknown
            reader.ReadInt32();

            host = new Player();
            host.Load(reader);
            players.Add(host);
            type = host.GameType;

            name = ParserUtility.ReadString(reader);
            //nullbyte
            reader.ReadByte();

            byte[] decoded = ParserUtility.GetDecodedBytes(reader);

            settings = new GameSettings(decoded);
            map      = new MapInfo(ParserUtility.GetUInt(decoded, 9), ParserUtility.GetString(decoded, 13));
            #endregion

            //playerCount, gameType, langId
            reader.ReadBytes(12);

            #region Player List
            while (reader.PeekChar() == 0x16)
            {
                #region doc
                //offset | size/type | Description
                //-------+-----------+-----------------------------------------------------------
                //0x0000 | 4/11 byte | PlayerRecord (see 4.1)
                //0x000? |    4 byte | unknown
                //       |           |  (always 0x00000000 for patch version >= 1.07
                //       |           |   always 0x00000001 for patch version <= 1.06)
                #endregion

                Player p = new Player();
                p.Load(reader);
                players.Add(p);
                reader.ReadBytes(4);
            }
            #endregion

            #region 4.10 [GameStartRecord]
            #region doc
            //offset | size/type | Description
            //-------+-----------+-----------------------------------------------------------
            //0x0000 |  1 byte   | RecordID - always 0x19
            //0x0001 |  1 word   | number of data bytes following
            //0x0003 |  1 byte   | nr of SlotRecords following (== nr of slots on startscreen)
            //0x0004 |  n bytes  | nr * SlotRecord (see 4.11)
            //   n+4 |  1 dword  | RandomSeed (see 4.12)
            //   n+8 |  1 byte   | SelectMode
            //       |           |   0x00 - team & race selectable (for standard custom games)
            //       |           |   0x01 - team not selectable
            //       |           |          (map setting: fixed alliances in WorldEditor)
            //       |           |   0x03 - team & race not selectable
            //       |           |          (map setting: fixed player properties in WorldEditor)
            //       |           |   0x04 - race fixed to random
            //       |           |          (extended map options: random races selected)
            //       |           |   0xcc - Automated Match Making (ladder)
            //   n+9 |  1 byte   | StartSpotCount (nr. of start positions in map)
            #endregion

            //RecordId, number of data bytes following
            reader.ReadBytes(3);
            byte nSlots = reader.ReadByte();
            for (byte i = 0; i < nSlots; i++)
            {
                #region 4.11 [SlotRecord]

                #region doc
                //offset | size/type | Description
                //-------+-----------+-----------------------------------------------------------
                //0x0000 |  1 byte   | player id (0x00 for computer players)
                //0x0001 |  1 byte   | map download percent: 0x64 in custom, 0xff in ladder
                //0x0002 |  1 byte   | slotstatus:
                //       |           |   0x00 empty slot
                //       |           |   0x01 closed slot
                //       |           |   0x02 used slot
                //0x0003 |  1 byte   | computer player flag:
                //       |           |   0x00 for human player
                //       |           |   0x01 for computer player
                //0x0004 |  1 byte   | team number:0 - 11
                //       |           | (team 12 == observer or referee)
                //0x0005 |  1 byte   | color (0-11):
                //       |           |   value+1 matches player colors in world editor:
                //       |           |   (red, blue, cyan, purple, yellow, orange, green,
                //       |           |    pink, gray, light blue, dark green, brown)
                //       |           |   color 12 == observer or referee
                //0x0006 |  1 byte   | player race flags (as selected on map screen):
                //       |           |   0x01=human
                //       |           |   0x02=orc
                //       |           |   0x04=nightelf
                //       |           |   0x08=undead
                //       |           |   0x20=random
                //       |           |   0x40=race selectable/fixed (see notes below)
                //0x0007 |  1 byte   | computer AI strength: (only present in v1.03 or higher)
                //       |           |   0x00 for easy
                //       |           |   0x01 for normal
                //       |           |   0x02 for insane
                //       |           | for non-AI players this seems to be always 0x01
                //0x0008 |  1 byte   | player handicap in percent (as displayed on startscreen)
                //       |           | valid values: 0x32, 0x3C, 0x46, 0x50, 0x5A, 0x64
                //       |           | (field only present in v1.07 or higher)
                #endregion

                #region
                byte playerId = reader.ReadByte();
                reader.ReadByte();
                byte        slotStatus   = reader.ReadByte();
                byte        computerFlag = reader.ReadByte();
                byte        teamNo       = reader.ReadByte();
                PlayerColor color        = (PlayerColor)reader.ReadByte();
                Race        race         = (Race)reader.ReadByte();
                if ((uint)race > 0x40)
                {
                    race -= 0x40;
                }
                AIStrength strength = (AIStrength)reader.ReadByte();
                int        handicap = reader.ReadByte();
                #endregion

                #region
                if (slotStatus == 0x02)
                {
                    Player player = GetPlayerById(playerId);
                    if (player == null && computerFlag == 0x01)
                    {
                        player      = new Player();
                        player.Race = race;
                        player.Id   = i;
                        if (strength == AIStrength.Easy)
                        {
                            player.Name = "电脑(简单的)";
                        }
                        else if (strength == AIStrength.Normal)
                        {
                            player.Name = "电脑(中等的)";
                        }
                        else
                        {
                            player.Name = "电脑(令人发狂的)";
                        }
                        players.Add(player);
                    }
                    else if (player == null)
                    {
                        continue;
                    }
                    player.SlotNo     = i;
                    player.Color      = color;
                    player.Handicap   = handicap;
                    player.Id         = playerId;
                    player.IsComputer = computerFlag == 0x01;
                    player.IsObserver = teamNo == 12;
                    player.Race       = race;
                    player.TeamNo     = teamNo + 1;
                }
                #endregion
                #endregion
            }


            if (buildNo == 0 && nSlots == 0)
            {
                #region 6.1 Notes on official Blizzard Replays
                #region doc
                //o Since the lack of all slot records, one has to generate these data:
                //iterate slotNumber from 1 to number of PlayerRecords (see 4.1)
                //  player id    = slotNumber
                //  slotstatus   = 0x02                   (used)
                //  computerflag = 0x00                   (human player)
                //  team number  = (slotNumber -1) mod 2  (team membership alternates in
                //                                                          PlayerRecord)
                //  color        = unknown                (player gets random colors)
                //  race         = as in PlayerRecord
                //  computerAI   = 0x01                   (non computer player)
                //  handicap     = 0x64                   (100%)
                #endregion
                foreach (Player player in players)
                {
                    player.SlotNo   = player.Id;
                    player.TeamNo   = (player.SlotNo - 1) % 2;
                    player.Handicap = 100;
                }
                #endregion
            }

            foreach (Player player in players)
            {
                Team team = GetTeamByNo(player.TeamNo);
                team.Add(player);
            }
            //random seed, select mode, startspotcount
            reader.ReadBytes(6);
            #endregion
        }
Beispiel #5
0
        private MemoryStream LoadHeader(Stream stream)
        {
            MemoryStream blocksData = new MemoryStream();

            using (BinaryReader reader = new BinaryReader(stream))
            {
                #region 2.0 [Header]

                #region doc

                //offset | size/type | Description
                //-------+-----------+-----------------------------------------------------------
                //0x0000 | 28 chars  | zero terminated string "Warcraft III recorded game\0x1A\0"
                //0x001c |  1 dword  | fileoffset of first compressed data block (header size)
                //       |           |  0x40 for WarCraft III with patch <= v1.06
                //       |           |  0x44 for WarCraft III patch >= 1.07 and TFT replays
                //0x0020 |  1 dword  | overall size of compressed file
                //0x0024 |  1 dword  | replay header version:
                //       |           |  0x00 for WarCraft III with patch <= 1.06
                //       |           |  0x01 for WarCraft III patch >= 1.07 and TFT replays
                //0x0028 |  1 dword  | overall size of decompressed data (excluding header)
                //0x002c |  1 dword  | number of compressed data blocks in file
                //0x0030 |  n bytes  | SubHeader (see section 2.1 and 2.2)

                #endregion

                ValidateHeaderString(reader.ReadBytes(28));

                int headerSize = reader.ReadInt32();
                //overall size of compressed file
                reader.ReadInt32();
                int versionFlag = reader.ReadInt32();
                //overall size of decompressed data (excluding header)
                reader.ReadInt32();
                int nBlocks = reader.ReadInt32();

                #endregion

                #region SubHeader

                if (versionFlag == 0)
                {
                    throw new W3gParserException("本软件不支持1.06及更低版本录像.");
                }
                else if (versionFlag == 1)
                {
                    #region 2.2 [SubHeader] for header version 1

                    #region doc

                    //offset | size/type | Description
                    //-------+-----------+-----------------------------------------------------------
                    //0x0000 |  1 dword  | version identifier string reading:
                    //       |           |  'WAR3' for WarCraft III Classic
                    //       |           |  'W3XP' for WarCraft III Expansion Set 'The Frozen Throne'
                    //0x0004 |  1 dword  | version number (corresponds to patch 1.xx so far)
                    //0x0008 |  1  word  | build number (see section 2.3)
                    //0x000A |  1  word  | flags
                    //       |           |   0x0000 for single player games
                    //       |           |   0x8000 for multiplayer games (LAN or Battle.net)
                    //0x000C |  1 dword  | replay length in msec
                    //0x0010 |  1 dword  | CRC32 checksum for the header
                    //       |           | (the checksum is calculated for the complete header
                    //       |           |  including this field which is set to zero)

                    #endregion

                    string war3string = ParserUtility.StringFromUInt(reader.ReadUInt32());
                    if (war3string != "W3XP")
                    {
                        throw new W3gParserException("本软件只支持冰封王座录像,不支持混乱之治录像.");
                    }

                    version = reader.ReadInt32();
                    buildNo = reader.ReadInt32();
                    //flags
                    reader.ReadInt16();
                    length = reader.ReadInt32();
                    //CRC32 checksum for the header
                    reader.ReadInt32();

                    #endregion
                }

                #endregion

                reader.BaseStream.Seek(headerSize, SeekOrigin.Begin);
                for (int i = 0; i < nBlocks; i++)
                {
                    #region [Data block header]

                    #region doc

                    //offset | size/type | Description
                    //-------+-----------+-----------------------------------------------------------
                    //0x0000 |  1  word  | size n of compressed data block (excluding header)
                    //0x0002 |  1  word  | size of decompressed data block (currently 8k)
                    //0x0004 |  1 dword  | unknown (probably checksum)
                    //0x0008 |  n bytes  | compressed data (decompress using zlib)

                    #endregion

                    ushort compressedSize   = reader.ReadUInt16();
                    ushort decompressedSize = reader.ReadUInt16();
                    //unknown (probably checksum)
                    reader.ReadInt32();

                    byte[] decompressed = new byte[decompressedSize];
                    byte[] compressed   = reader.ReadBytes(compressedSize);
                    using (InflaterInputStream zipStream = new InflaterInputStream(new MemoryStream(compressed)))
                    {
                        zipStream.Read(decompressed, 0, decompressedSize);
                    }
                    blocksData.Write(decompressed, 0, decompressedSize);

                    #endregion
                }
            }
            blocksData.Seek(0, SeekOrigin.Begin);
            return(blocksData);
        }
Beispiel #6
0
        private void LoadActions(BinaryReader reader)
        {
            int  time     = 0;
            bool isPaused = false;

            while (reader.BaseStream.Length - reader.BaseStream.Position > 0)
            {
                byte blockId = reader.ReadByte();
                switch (blockId)
                {
                case 0x1A:
                case 0x1B:
                case 0x1C:
                    reader.BaseStream.Seek(reader.BaseStream.Position + 4, SeekOrigin.Begin);
                    break;

                case 0x22:
                    reader.BaseStream.Seek(reader.BaseStream.Position + 5, SeekOrigin.Begin);
                    break;

                case 0x23:
                    reader.BaseStream.Seek(reader.BaseStream.Position + 10, SeekOrigin.Begin);
                    break;

                case 0x2F:
                    reader.BaseStream.Seek(reader.BaseStream.Position + 8, SeekOrigin.Begin);
                    break;

                //leave game
                case 0x17:
                    reader.ReadInt32();
                    byte   playerId = reader.ReadByte();
                    Player p        = GetPlayerById(playerId);
                    p.Time = time;
                    reader.ReadInt64();
                    break;

                //chat
                case 0x20:
                    byte fromId = reader.ReadByte();
                    reader.ReadBytes(2);
                    byte   chatType = reader.ReadByte();
                    TalkTo to       = TalkTo.All;
                    if (chatType != 0x10)
                    {
                        to = (TalkTo)reader.ReadInt32();
                    }
                    string message = ParserUtility.ReadString(reader);
                    if (chatType != 0x10)
                    {
                        ChatInfo chat = new ChatInfo(time, GetPlayerById(fromId), to, GetPlayerById((byte)(to - 3)), message);
                        chats.Add(chat);
                    }
                    break;

                //time slot
                case 0x1E:
                case 0x1F:
                    short rest          = reader.ReadInt16();
                    short increasedTime = reader.ReadInt16();
                    if (!isPaused)
                    {
                        time += increasedTime;
                    }
                    rest -= 2;
                    LoadTimeSlot(reader, rest, time, ref isPaused);
                    break;

                case 0:
                    return;

                default:
                    throw new W3gParserException("未知的数据块ID.");
                }
            }
        }