// used for builds <= 47479 and 47903
        private static void ExtendedBattleTagParsingOld(Replay replay, BitReader bitReader)
        {
            bool changed47479 = false;

            if (replay.ReplayBuild == 47479 && DetectBattleTagChangeBuild47479(replay, bitReader))
            {
                changed47479 = true;
            }

            for (int i = 0; i < replay.ClientListByUserID.Length; i++)
            {
                if (replay.ClientListByUserID[i] == null)
                {
                    break;
                }

                string TId;
                string TId_2;

                // this first one is weird, nothing to indicate the length of the string
                if (i == 0)
                {
                    var offset = bitReader.ReadByte();
                    bitReader.ReadString(2); // T:
                    TId = bitReader.ReadString(12 + offset);

                    if (replay.ReplayBuild <= 47479 && !changed47479)
                    {
                        bitReader.ReadBytes(6);
                        ReadByte0x00(bitReader);
                        ReadByte0x00(bitReader);
                        ReadByte0x00(bitReader);
                        bitReader.Read(6);

                        // get T: again
                        TId_2 = Encoding.UTF8.GetString(ReadSpecialBlob(bitReader, 8));

                        if (TId != TId_2)
                        {
                            throw new Exception("TID dup not equal");
                        }
                    }
                }
                else
                {
                    ReadByte0x00(bitReader);
                    ReadByte0x00(bitReader);
                    ReadByte0x00(bitReader);
                    bitReader.Read(6);

                    // get XXXXXXXX#YYY
                    TId = Encoding.UTF8.GetString(ReadSpecialBlob(bitReader, 8));

                    if (replay.ReplayBuild <= 47479 && !changed47479)
                    {
                        bitReader.ReadBytes(6);
                        ReadByte0x00(bitReader);
                        ReadByte0x00(bitReader);
                        ReadByte0x00(bitReader);
                        bitReader.Read(6);

                        // get T: again
                        TId_2 = Encoding.UTF8.GetString(ReadSpecialBlob(bitReader, 8));

                        if (TId != TId_2)
                        {
                            throw new Exception("TID dup not equal");
                        }
                    }
                }
                replay.ClientListByUserID[i].BattleNetTId = TId;

                // next 31 bytes
                bitReader.ReadBytes(4); // same for all players
                bitReader.ReadByte();
                bitReader.ReadBytes(8); // same for all players
                bitReader.ReadBytes(4);

                bitReader.ReadBytes(14); // same for all players

                if (replay.ReplayBuild >= 47903 || changed47479)
                {
                    bitReader.ReadBytes(40);
                }
                else if (replay.ReplayBuild >= 47219 || replay.ReplayBuild == 47024)
                {
                    bitReader.ReadBytes(39);
                }
                else if (replay.ReplayBuild >= 45889)
                {
                    bitReader.ReadBytes(38);
                }
                else if (replay.ReplayBuild >= 45228)
                {
                    bitReader.ReadBytes(37);
                }
                else if (replay.ReplayBuild >= 44468)
                {
                    bitReader.ReadBytes(36);
                }
                else
                {
                    bitReader.ReadBytes(35);
                }

                if (replay.ReplayBuild >= 47903 || changed47479)
                {
                    bitReader.Read(1);
                }
                else if (replay.ReplayBuild >= 47219 || replay.ReplayBuild == 47024)
                {
                    bitReader.Read(6);
                }
                else if (replay.ReplayBuild >= 46690 || replay.ReplayBuild == 46416)
                {
                    bitReader.Read(5);
                }
                else if (replay.ReplayBuild >= 45889)
                {
                    bitReader.Read(2);
                }
                else if (replay.ReplayBuild >= 45228)
                {
                    bitReader.Read(3);
                }
                else
                {
                    bitReader.Read(5);
                }

                if (bitReader.ReadBoolean())
                {
                    // use this to determine who is in a party
                    // those in the same party will have the same exact 8 bytes of data
                    // the party leader is the first one (in the order of the client list)
                    replay.ClientListByUserID[i].PartyValue = bitReader.ReadInt32() + bitReader.ReadInt32();
                }

                bitReader.Read(1);
                var battleTag = Encoding.UTF8.GetString(bitReader.ReadBlobPrecededWithLength(7)).Split('#'); // battleTag <name>#xxxxx

                if (battleTag.Length != 2 || battleTag[0] != replay.ClientListByUserID[i].Name)
                {
                    throw new Exception("Couldn't find BattleTag");
                }

                replay.ClientListByUserID[i].BattleTag = int.Parse(battleTag[1]);

                // these similar bytes don't occur for last player
                bitReader.ReadBytes(27);
            }

            // some more bytes after (at least 700)
            // theres some HeroICONs and other repetitive stuff
        }
        private static void GetBattleTags(Replay replay, BitReader reader)
        {
            // Search for the BattleTag for each player
            var battleTagDigits = new List <char>();

            for (var playerNum = 0; playerNum < replay.Players.Length; playerNum++)
            {
                var player = replay.Players[playerNum];
                if (player == null)
                {
                    continue;
                }

                // Find each player's name, and then their associated BattleTag
                battleTagDigits.Clear();
                var playerNameBytes = Encoding.UTF8.GetBytes(player.Name);
                while (!reader.EndOfStream)
                {
                    var isFound = true;
                    for (var i = 0; i < playerNameBytes.Length + 1; i++)
                    {
                        if ((i == playerNameBytes.Length && reader.ReadByte() != 35 /* '#' Character */) || (i < playerNameBytes.Length && reader.ReadByte() != playerNameBytes[i]))
                        {
                            isFound = false;
                            break;
                        }
                    }

                    if (isFound)
                    {
                        break;
                    }
                }

                // Get the digits from the BattleTag
                while (!reader.EndOfStream)
                {
                    var currentCharacter = (char)reader.ReadByte();

                    if (playerNum == 9 && (currentCharacter == 'z' || currentCharacter == 'Ø'))
                    {
                        // If player is in slot 9, there's a chance that an extra digit could be appended to the BattleTag
                        battleTagDigits.RemoveAt(battleTagDigits.Count - 1);
                        break;
                    }
                    else if (char.IsDigit(currentCharacter))
                    {
                        battleTagDigits.Add(currentCharacter);
                    }
                    else
                    {
                        break;
                    }
                }

                if (reader.EndOfStream)
                {
                    break;
                }
                else if (battleTagDigits.Count == 0)
                {
                    continue;
                }

                player.BattleTag = int.Parse(string.Join("", battleTagDigits));
            }
        }
        /// <summary> Parses the replay.server.battlelobby file in a replay file. </summary>
        /// <param name="replay"> The replay file to apply the parsed data to. </param>
        /// <param name="buffer"> The buffer containing the replay.server.battlelobby file. </param>
        public static void Parse(Replay replay, byte[] buffer)
        {
            using (var stream = new MemoryStream(buffer))
            {
                var bitReader = new BitReader(stream);

                // 52124 and 52381 are non-tested ptr builds
                if (replay.ReplayBuild < 38793 ||
                    replay.ReplayBuild == 52124 || replay.ReplayBuild == 52381 ||
                    replay.GameMode == GameMode.Unknown)
                {
                    GetBattleTags(replay, bitReader);
                    return;
                }

                int s2mArrayLength = bitReader.ReadByte();
                int stringLength   = bitReader.ReadByte();

                bitReader.ReadString(stringLength);

                for (var i = 1; i < s2mArrayLength; i++)
                {
                    bitReader.Read(16);
                    bitReader.ReadString(stringLength);
                }

                if (bitReader.ReadByte() != s2mArrayLength)
                {
                    throw new Exception("s2ArrayLength not equal");
                }

                for (var i = 0; i < s2mArrayLength; i++)
                {
                    bitReader.ReadString(4); // s2m
                    bitReader.ReadBytes(2);  // 0x00 0x00
                    bitReader.ReadString(2); // Realm
                    bitReader.ReadBytes(32);
                }

                if (replay.ReplayBuild < 55929)
                {
                    // seems to be in all replays
                    bitReader.ReadInt16();
                    bitReader.stream.Position = bitReader.stream.Position + 684;

                    // seems to be in all replays
                    bitReader.ReadInt16();
                    bitReader.stream.Position = bitReader.stream.Position + 1944;

                    if (bitReader.ReadString(8) != "HumnComp")
                    {
                        throw new Exception("Not HumnComp");
                    }
                }

                bitReader.stream.Position = bitReader.stream.Position = bitReader.stream.Position + 19859;

                //// next section is language libraries?
                //// ---------------------------------------
                //for (int i = 0; ; i++) // no idea how to determine the count
                //{
                //    if (bitReader.ReadString(4).Substring(0, 2) != "s2") // s2mv; not sure if its going to be 'mv' all the time
                //    {
                //        bitReader.stream.Position = bitReader.stream.Position - 4;
                //        break;
                //    }

                //    bitReader.ReadBytes(2); // 0x00 0x00
                //    bitReader.ReadString(2); // Realm
                //    bitReader.ReadBytes(32);
                //}

                //bitReader.Read(32);
                //bitReader.Read(8);

                //bitReader.ReadByte();
                //for (int i = 0; ; i++) // no idea how to determine the count
                //{
                //    if (bitReader.ReadString(4).Substring(0, 2) != "s2") // s2ml
                //    {
                //        bitReader.stream.Position = bitReader.stream.Position - 4;
                //        break;
                //    }

                //    bitReader.ReadBytes(2); // 0x00 0x00
                //    bitReader.ReadString(2); // Realm
                //    bitReader.ReadBytes(32);
                //}

                //for (int k = 0; k < 11; k++)
                //{
                //    // ruRU, zhCN, plPL, esMX, frFR, esES
                //    // ptBR, itIT, enUs, deDe, koKR
                //    bitReader.ReadString(4);

                //    bitReader.ReadByte();
                //    for (int i = 0; ; i++)
                //    {
                //        if (bitReader.ReadString(4).Substring(0, 2) != "s2") // s2ml
                //        {
                //            bitReader.stream.Position = bitReader.stream.Position - 4;
                //            break;
                //        }
                //        bitReader.ReadString(4); // s2ml
                //        bitReader.ReadBytes(2); // 0x00 0x00
                //        bitReader.ReadString(2); // Realm
                //        bitReader.ReadBytes(32);
                //    }
                //}

                // new section, can't find a pattern
                // has blizzmaps#1, Hero, s2mv
                // --------------------
                //bitReader.ReadBytes(8); // all 0x00

                for (;;)
                {
                    // we're just going to skip all the way down to the s2mh
                    if (bitReader.ReadString(4) == "s2mh")
                    {
                        bitReader.stream.Position = bitReader.stream.Position - 4;
                        break;
                    }
                    else
                    {
                        bitReader.stream.Position = bitReader.stream.Position - 3;
                    }
                }

                for (var i = 0; i < s2mArrayLength; i++)
                {
                    bitReader.ReadString(4); // s2mh
                    bitReader.ReadBytes(2);  // 0x00 0x00
                    bitReader.ReadString(2); // Realm
                    bitReader.ReadBytes(32);
                }

                // Player collections - starting with HOTS 2.0 (live build 52860)
                // --------------------------------------------------------------
                List <string> playerCollection = new List <string>();

                int collectionSize = 0;

                if (replay.ReplayBuild >= 48027)
                {
                    collectionSize = bitReader.ReadInt16();
                }
                else
                {
                    collectionSize = bitReader.ReadInt32();
                }

                if (collectionSize > 5000)
                {
                    throw new Exception("collectionSize is an unusually large number");
                }

                for (int i = 0; i < collectionSize; i++)
                {
                    if (replay.ReplayBuild >= 55929)
                    {
                        bitReader.ReadBytes(8);
                    }
                    else
                    {
                        playerCollection.Add(bitReader.ReadString(bitReader.ReadByte()));
                    }
                }

                // use to determine if the collection item is usable by the player (owns/free to play/internet cafe)
                if (bitReader.ReadInt32() != collectionSize)
                {
                    throw new Exception("skinArrayLength not equal");
                }

                for (int i = 0; i < collectionSize; i++)
                {
                    for (int j = 0; j < 16; j++) // 16 is total player slots
                    {
                        bitReader.ReadByte();

                        var num = bitReader.Read(8);

                        if (replay.ReplayBuild < 55929)
                        {
                            if (replay.ClientListByUserID[j] != null)
                            {
                                if (num > 0)
                                {
                                    replay.ClientListByUserID[j].PlayerCollectionDictionary.Add(playerCollection[i], true);
                                }
                                else if (num == 0)
                                {
                                    replay.ClientListByUserID[j].PlayerCollectionDictionary.Add(playerCollection[i], false);
                                }
                                else
                                {
                                    throw new NotImplementedException();
                                }
                            }
                        }
                    }
                }

                // Player info
                // ------------------------
                if (replay.ReplayBuild <= 43259 || replay.ReplayBuild == 47801)
                {
                    // Builds that are not yet supported for detailed parsing
                    // build 47801 is a ptr build that had new data in the battletag section, the data was changed in 47944 (patch for 47801)
                    GetBattleTags(replay, bitReader);
                    return;
                }

                bitReader.ReadInt32(); // m_randomSeed
                bitReader.ReadBytes(32);

                bitReader.ReadInt32(); // 0x19

                if (replay.ReplayBuild <= 47479 || replay.ReplayBuild == 47903)
                {
                    ExtendedBattleTagParsingOld(replay, bitReader);
                    return;
                }

                for (int player = 0; player < replay.ClientListByUserID.Length; player++)
                {
                    if (replay.ClientListByUserID[player] == null)
                    {
                        break;
                    }

                    string TId;

                    if (player == 0)
                    {
                        var offset = bitReader.ReadByte();
                        bitReader.ReadString(2); // T:
                        TId = bitReader.ReadString(12 + offset);
                    }
                    else
                    {
                        ReadByte0x00(bitReader);
                        ReadByte0x00(bitReader);
                        ReadByte0x00(bitReader);
                        bitReader.Read(6);

                        // get XXXXXXXX#YYY
                        TId = Encoding.UTF8.GetString(ReadSpecialBlob(bitReader, 8));
                    }

                    replay.ClientListByUserID[player].BattleNetTId = TId;

                    // next 18 bytes
                    bitReader.ReadBytes(4); // same for all players
                    bitReader.ReadBytes(26);

                    // repeat of the collection section above
                    if (replay.ReplayBuild >= 51609)
                    {
                        int size = (int)bitReader.Read(12); // 3 bytes max 4095
                        if (size != collectionSize)
                        {
                            throw new Exception("size and collectionSize not equal");
                        }

                        int bytesSize = collectionSize / 8;
                        int bitsSize  = (collectionSize % 8) + 2; // two additional unknown bits

                        bitReader.ReadBytes(bytesSize);
                        bitReader.Read(bitsSize);
                    }
                    else
                    {
                        if (replay.ReplayBuild >= 48027)
                        {
                            bitReader.ReadInt16();
                        }
                        else
                        {
                            bitReader.ReadInt32();
                        }

                        // each byte has a max value of 0x7F (127)
                        bitReader.stream.Position = bitReader.stream.Position = bitReader.stream.Position + (collectionSize * 2);
                        bitReader.Read(1);
                    }

                    if (bitReader.ReadBoolean())
                    {
                        // use this to determine who is in a party
                        // those in the same party will have the same exact 8 bytes of data
                        // the party leader is the first one (in the order of the client list)
                        replay.ClientListByUserID[player].PartyValue = bitReader.ReadInt32() + bitReader.ReadInt32();
                    }

                    bitReader.Read(1);
                    var battleTag = Encoding.UTF8.GetString(bitReader.ReadBlobPrecededWithLength(7)).Split('#'); // battleTag <name>#xxxxx

                    if (battleTag.Length != 2 || battleTag[0] != replay.ClientListByUserID[player].Name)
                    {
                        throw new Exception("Couldn't find BattleTag");
                    }

                    replay.ClientListByUserID[player].BattleTag = int.Parse(battleTag[1]);

                    if (replay.ReplayBuild >= 52860 || (replay.ReplayVersionMajor == 2 && replay.ReplayBuild >= 51978))
                    {
                        replay.ClientListByUserID[player].AccountLevel = bitReader.ReadInt32(); // player's account level, not available in custom games
                    }
                    bitReader.ReadBytes(27);                                                    // these similar bytes don't occur for last player
                }

                // some more data after this
            }
        }
        internal static void DetailedParse(BitReader bitReader, Replay replay, int s2mArrayLength)
        {
            bitReader.AlignToByte();
            for (; ;)
            {
                // we're just going to skip all the way down to the s2mh
                if (bitReader.ReadString(4) == "s2mh")
                {
                    bitReader.stream.Position = bitReader.stream.Position - 4;
                    break;
                }
                else
                {
                    bitReader.stream.Position = bitReader.stream.Position - 3;
                }
            }

            for (var i = 0; i < s2mArrayLength; i++)
            {
                bitReader.ReadString(4); // s2mh
                bitReader.ReadBytes(2);  // 0x00 0x00
                bitReader.ReadString(2); // Realm
                bitReader.ReadBytes(32);
            }

            // Player collections - starting with HOTS 2.0 (live build 52860)
            // strings gone starting with build (ptr) 55929
            // --------------------------------------------------------------
            List <string> playerCollection = new List <string>();

            int collectionSize = 0;

            if (replay.ReplayBuild >= 48027)
            {
                collectionSize = bitReader.ReadInt16();
            }
            else
            {
                collectionSize = bitReader.ReadInt32();
            }

            if (collectionSize > 8000)
            {
                throw new DetailedParsedException("collectionSize is an unusually large number");
            }

            for (int i = 0; i < collectionSize; i++)
            {
                if (replay.ReplayBuild >= 55929)
                {
                    bitReader.ReadBytes(8); // most likey an identifier for the item; first six bytes are 0x00
                }
                else
                {
                    playerCollection.Add(bitReader.ReadString(bitReader.ReadByte()));
                }
            }

            // use to determine if the collection item is usable by the player (owns/free to play/internet cafe)
            if (bitReader.ReadInt32() != collectionSize)
            {
                throw new DetailedParsedException("skinArrayLength not equal");
            }

            for (int i = 0; i < collectionSize; i++)
            {
                for (int j = 0; j < 16; j++) // 16 is total player slots
                {
                    bitReader.ReadByte();

                    var num = bitReader.Read(8);

                    if (replay.ReplayBuild < 55929)
                    {
                        if (replay.ClientListByUserID[j] != null)
                        {
                            if (num > 0)
                            {
                                replay.ClientListByUserID[j].PlayerCollectionDictionary.Add(playerCollection[i], true);
                            }
                            else if (num == 0)
                            {
                                replay.ClientListByUserID[j].PlayerCollectionDictionary.Add(playerCollection[i], false);
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }
                        }
                    }
                }
            }

            // Player info
            // ------------------------
            if (replay.ReplayBuild <= 43259 || replay.ReplayBuild == 47801)
            {
                // Builds that are not yet supported for detailed parsing
                // build 47801 is a ptr build that had new data in the battletag section, the data was changed in 47944 (patch for 47801)
                GetBattleTags(replay, bitReader);
                return;
            }

            // m_randomSeed, set it if it hasn't been set
            if (replay.RandomValue == 0)
            {
                replay.RandomValue = (uint)bitReader.ReadInt32();
            }
            else
            {
                bitReader.ReadInt32();
            }

            bitReader.ReadBytes(32);
            bitReader.ReadInt32(); // 0x19

            if (replay.ReplayBuild <= 47479 || replay.ReplayBuild == 47903)
            {
                ExtendedBattleTagParsingOld(replay, bitReader);
                return;
            }

            for (int player = 0; player < replay.ClientListByUserID.Length; player++)
            {
                if (replay.ClientListByUserID[player] == null)
                {
                    break;
                }

                if (player == 0)
                {
                    var offset = bitReader.ReadByte();
                    bitReader.ReadString(2);                                                            // T:
                    replay.ClientListByUserID[player].BattleNetTId = bitReader.ReadString(12 + offset); // TId
                }
                else
                {
                    ReadByte0x00(bitReader);
                    ReadByte0x00(bitReader);
                    ReadByte0x00(bitReader);
                    bitReader.Read(6);

                    // get XXXXXXXX#YYY
                    replay.ClientListByUserID[player].BattleNetTId = Encoding.UTF8.GetString(ReadSpecialBlob(bitReader, 8)); // TId
                }

                // next 30 bytes
                bitReader.ReadBytes(4); // same for all players
                bitReader.ReadBytes(26);

                // repeat of the collection section above
                if (replay.ReplayBuild >= 51609)
                {
                    int size = (int)bitReader.Read(12); // 3 bytes
                    if (size == collectionSize)
                    {
                        int bytesSize = collectionSize / 8;
                        int bitsSize  = (collectionSize % 8);

                        bitReader.ReadBytes(bytesSize);
                        bitReader.Read(bitsSize);
                    }
                    // else if not equal, then data isn't available, most likely an observer
                }
                else
                {
                    if (replay.ReplayBuild >= 48027)
                    {
                        bitReader.ReadInt16();
                    }
                    else
                    {
                        bitReader.ReadInt32();
                    }

                    // each byte has a max value of 0x7F (127)
                    bitReader.stream.Position = bitReader.stream.Position + (collectionSize * 2);
                }

                if (replay.ReplayBuild >= 51609)
                {
                    bitReader.ReadBoolean();
                }

                bitReader.ReadBoolean(); // m_hasSilencePenalty

                if (replay.ReplayBuild >= 61718)
                {
                    bitReader.ReadBoolean();
                    bitReader.ReadBoolean(); // m_hasVoiceSilencePenalty
                }

                if (bitReader.ReadBoolean())                                                                      // is player in party
                {
                    replay.ClientListByUserID[player].PartyValue = bitReader.ReadInt32() + bitReader.ReadInt32(); // players in same party will have the same exact 8 bytes of data
                }
                bitReader.ReadBoolean();

                var battleTag = Encoding.UTF8.GetString(bitReader.ReadBlobPrecededWithLength(7)).Split('#'); // battleTag <name>#xxxxx

                if (battleTag.Length != 2 || battleTag[0] != replay.ClientListByUserID[player].Name)
                {
                    throw new DetailedParsedException("Couldn't find BattleTag");
                }

                replay.ClientListByUserID[player].BattleTag = int.Parse(battleTag[1]);

                if (replay.ReplayBuild >= 52860 || (replay.ReplayVersionMajor == 2 && replay.ReplayBuild >= 51978))
                {
                    replay.ClientListByUserID[player].AccountLevel = bitReader.ReadInt32(); // player's account level, not available in custom games
                }
                bitReader.ReadBytes(27);                                                    // these similar bytes don't occur for last player
            }

            // some more data after this
            // there is also a CSTM string down here, if it exists, the game is a custom game
        }
Пример #5
0
        /// <summary> Parses the replay.initdata file in a replay file. </summary>
        /// <param name="replay"> The replay file to apply the parsed data to. </param>
        /// <param name="buffer"> The buffer containing the replay.initdata file. </param>
        public static void Parse(Replay replay, byte[] buffer)
        {
            using (var stream = new MemoryStream(buffer))
            {
                var reader = new BitReader(stream);

                var i = reader.ReadByte();

                var playerList = new string[i];
                for (int j = 0; j < i; j++)
                {
                    playerList[j] = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(8));

                    if (reader.ReadBoolean())
                    {
                        var clanTag = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(8));
                        // Console.WriteLine(clanTag);
                    }

                    if (reader.ReadBoolean())
                    {
                        // Clan Logo
                        reader.ReadBlobPrecededWithLength(40);
                    }

                    if (reader.ReadBoolean())
                    {
                        var highestLeague = reader.Read(8);
                        // Console.WriteLine(highestLeague);
                    }

                    if (reader.ReadBoolean())
                    {
                        var combinedRaceLevels = reader.ReadInt32();
                        // Console.WriteLine(combinedRaceLevels);
                    }

                    reader.ReadInt32(); // Random seed (So far, always 0 in Heroes)

                    if (reader.ReadBoolean())
                    {
                        reader.Read(8); // Race Preference
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.Read(8);   // Team Preference
                    }
                    reader.ReadBoolean(); //test map
                    reader.ReadBoolean(); //test auto
                    reader.ReadBoolean(); //examine
                    reader.ReadBoolean(); //custom interface

                    var unknown1 = reader.ReadInt32();

                    reader.Read(2);       //observer

                    var unknown2 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));
                    var unknown3 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));
                    var unknown4 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));
                    var unknown5 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));
                    var unknown6 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));
                    var unknown7 = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));

                    // Console.WriteLine(unknown1 + unknown2 + unknown3 + unknown4 + unknown5 + unknown6 + unknown7);
                }

                // Marked as 'Random Value', so I will use as seed
                replay.RandomValue = (uint)reader.ReadInt32();

                reader.ReadBlobPrecededWithLength(10);  // Dflt

                reader.ReadBoolean();                   // Lock Teams
                reader.ReadBoolean();                   // Teams Together
                reader.ReadBoolean();                   // Advanced Shared Control
                reader.ReadBoolean();                   // Random Races
                reader.ReadBoolean();                   // BattleNet
                reader.ReadBoolean();                   // AMM
                reader.ReadBoolean();                   // Competitive
                reader.ReadBoolean();                   // No Victory Or Defeat
                reader.ReadBoolean();                   // Unknown 0
                reader.ReadBoolean();                   // Unknown 1
                reader.ReadBoolean();                   // Unknown 2
                reader.Read(2);                         // Fog
                reader.Read(2);                         // Observers
                reader.Read(2);                         // User Difficulty
                reader.ReadInt32(); reader.ReadInt32(); // 64 bit int: Client Debug Flags

                reader.Read(3);                         // Game Speed

                // Not sure what this 'Game Type' is
                reader.Read(3);

                var maxUsers = reader.Read(5);
                if (maxUsers != 10) // Max Players
                {
                    replay.GameMode = GameMode.TryMe;
                }

                reader.Read(5); // Max Observers
                reader.Read(5); // Max Players
                reader.Read(4); // + 1 = Max Teams
                reader.Read(6); // Max Colors
                reader.Read(8); // + 1 = Max Races
                reader.Read(8); // Max Controls

                replay.MapSize = new Point {
                    X = (int)reader.Read(8), Y = (int)reader.Read(8)
                };
                if (replay.MapSize.Y == 1)
                {
                    replay.MapSize.Y = replay.MapSize.X;
                }
                else if (replay.MapSize.X == 0)
                {
                    replay.MapSize.X = replay.MapSize.Y;
                }

                // About 1000 bytes from here is a list of characters, character skins, character mounts, artifact selections, and other data
            }
        }
Пример #6
0
        /// <summary> Parses the replay.initdata file in a replay file. </summary>
        /// <param name="replay"> The replay file to apply the parsed data to. </param>
        /// <param name="buffer"> The buffer containing the replay.initdata file. </param>
        public static void Parse(Replay replay, byte[] buffer)
        {
            using (var stream = new MemoryStream(buffer))
            {
                var reader = new BitReader(stream);

                var playerListLength = reader.Read(5);
                for (var i = 0; i < playerListLength; i++)
                {
                    var playerName = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(8)); // Player name

                    // Populate the client list
                    if (playerName != "")
                    {
                        if (i < replay.Players.Length && replay.Players[i].Name == playerName)
                        {
                            // 99.9% of matches have 10 players and 10 clients
                            replay.ClientList[i] = replay.Players[i];
                        }
                        else
                        {
                            // Some Custom games with Observers may have the client list in a different order than player list
                            // Hopefully in these rare cases, nobody will be sharing the same name :)
                            replay.ClientList[i] = replay.Players.SingleOrDefault(j => j.Name == playerName);
                        }

                        if (replay.ClientList[i] == null)
                        {
                            replay.ClientList[i] = new Player {
                                Name = playerName
                            }
                        }
                        ;
                    }

                    if (reader.ReadBoolean())
                    {
                        reader.ReadBlobPrecededWithLength(8); // clanTag
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.ReadBlobPrecededWithLength(40); // Clan Logo
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.Read(8); // highestLeague
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.ReadInt32(); // combinedRaceLevels
                    }
                    reader.ReadInt32();     // Random seed (So far, always 0 in Heroes)

                    if (reader.ReadBoolean())
                    {
                        reader.Read(8); // Race Preference
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.Read(8);                                            // Team Preference
                    }
                    reader.ReadBoolean();                                          //test map
                    reader.ReadBoolean();                                          //test auto
                    reader.ReadBoolean();                                          //examine
                    reader.ReadBoolean();                                          //custom interface

                    reader.ReadInt32();                                            // m_testType

                    reader.Read(2);                                                //observer

                    Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_hero - Currently Empty String
                    Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_skin - Currently Empty String
                    Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_mount - Currently Empty String
                    Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7)); // m_toonHandle - Currently Empty String
                }

                // Marked as 'Random Value', so I will use as seed
                replay.RandomValue = (uint)reader.ReadInt32();

                reader.ReadBlobPrecededWithLength(10);  // m_gameCacheName - "Dflt"

                reader.ReadBoolean();                   // Lock Teams
                reader.ReadBoolean();                   // Teams Together
                reader.ReadBoolean();                   // Advanced Shared Control
                reader.ReadBoolean();                   // Random Races
                reader.ReadBoolean();                   // BattleNet
                reader.ReadBoolean();                   // AMM
                reader.ReadBoolean();                   // Competitive
                reader.ReadBoolean();                   // m_practice
                reader.ReadBoolean();                   // m_cooperative
                reader.ReadBoolean();                   // m_noVictoryOrDefeat
                reader.ReadBoolean();                   // m_heroDuplicatesAllowed
                reader.Read(2);                         // Fog
                reader.Read(2);                         // Observers
                reader.Read(2);                         // User Difficulty
                reader.ReadInt32(); reader.ReadInt32(); // 64 bit int: Client Debug Flags

                reader.Read(3);                         // Game Speed

                // Not sure what this 'Game Type' is
                reader.Read(3);

                var maxUsers = reader.Read(5);
                if (maxUsers != 10) // Max Players
                {
                    replay.GameMode = GameMode.TryMe;
                }

                reader.Read(5); // Max Observers
                reader.Read(5); // Max Players
                reader.Read(4); // + 1 = Max Teams
                reader.Read(6); // Max Colors
                reader.Read(8); // + 1 = Max Races
                reader.Read(8); // Max Controls

                replay.MapSize = new Point {
                    X = (int)reader.Read(8), Y = (int)reader.Read(8)
                };
                if (replay.MapSize.Y == 1)
                {
                    replay.MapSize.Y = replay.MapSize.X;
                }
                else if (replay.MapSize.X == 0)
                {
                    replay.MapSize.X = replay.MapSize.Y;
                }

                // I haven't tested the following code on replays before build 39595 (End of 2015)
                if (replay.ReplayBuild < 39595)
                {
                    return;
                }

                reader.Read(32);                       // m_mapFileSyncChecksum
                reader.ReadBlobPrecededWithLength(11); // m_mapFileName
                reader.ReadBlobPrecededWithLength(8);  // m_mapAuthorName
                reader.Read(32);                       // m_modFileSyncChecksum

                // m_slotDescriptions
                var slotDescriptionLength = reader.Read(5);
                for (var i = 0; i < slotDescriptionLength; i++)
                {
                    reader.ReadBitArray(reader.Read(6)); // m_allowedColors
                    reader.ReadBitArray(reader.Read(8)); // m_allowedRaces
                    reader.ReadBitArray(reader.Read(6)); // m_allowedDifficulty
                    reader.ReadBitArray(reader.Read(8)); // m_allowedControls
                    reader.ReadBitArray(reader.Read(2)); // m_allowedObserveTypes
                    reader.ReadBitArray(reader.Read(7)); // m_allowedAIBuilds
                }

                reader.Read(6); // m_defaultDifficulty
                reader.Read(7); // m_defaultAIBuild

                // m_cacheHandles
                var cacheHandlesLength = reader.Read(6);
                for (var i = 0; i < cacheHandlesLength; i++)
                {
                    reader.ReadBytes(40);
                }

                reader.ReadBoolean(); // m_hasExtensionMod
                reader.ReadBoolean(); // m_isBlizzardMap
                reader.ReadBoolean(); // m_isPremadeFFA
                reader.ReadBoolean(); // m_isCoopMode

                #region m_lobbyState

                reader.Read(3); // m_phase
                reader.Read(5); // m_maxUsers
                reader.Read(5); // m_maxObservers

                // m_slots
                var slotsLength = reader.Read(5);
                for (var i = 0; i < slotsLength; i++)
                {
                    int?clientListIndex = null;

                    reader.Read(8); // m_control
                    if (reader.ReadBoolean())
                    {
                        clientListIndex = (int)reader.Read(4); // m_userId
                    }
                    reader.Read(4);                            // m_teamId
                    if (reader.ReadBoolean())
                    {
                        reader.Read(5); // m_colorPref
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.Read(8); // m_racePref
                    }
                    reader.Read(6);     // m_difficulty
                    reader.Read(7);     // m_aiBuild
                    reader.Read(7);     // m_handicap

                    // m_observe
                    var observerStatus = reader.Read(2);
                    if (observerStatus == 2 && clientListIndex.HasValue)
                    {
                        replay.ClientList[clientListIndex.Value].PlayerType = PlayerType.Spectator;
                    }

                    reader.Read(32);                                                                      // m_logoIndex

                    reader.ReadBlobPrecededWithLength(9);                                                 // m_hero

                    var skinAndSkinTint = Encoding.ASCII.GetString(reader.ReadBlobPrecededWithLength(9)); // m_skin
                    if (skinAndSkinTint == "")
                    {
                        skinAndSkinTint = null;
                    }
                    if (clientListIndex.HasValue && replay.ClientList[clientListIndex.Value] != null)
                    {
                        replay.ClientList[clientListIndex.Value].SkinAndSkinTint = skinAndSkinTint;
                    }

                    var mountAndMountTint = Encoding.ASCII.GetString(reader.ReadBlobPrecededWithLength(9)); // m_mount
                    if (mountAndMountTint == "")
                    {
                        mountAndMountTint = null;
                    }
                    if (clientListIndex.HasValue && replay.ClientList[clientListIndex.Value] != null)
                    {
                        replay.ClientList[clientListIndex.Value].MountAndMountTint = mountAndMountTint;
                    }

                    // m_artifacts
                    var artifactsLength = reader.Read(4);
                    for (var j = 0; j < artifactsLength; j++)
                    {
                        reader.ReadBlobPrecededWithLength(9);
                    }

                    if (reader.ReadBoolean())
                    {
                        reader.Read(8); // m_workingSetSlotId
                    }
                    // m_rewards
                    var rewardsLength = reader.Read(17);
                    for (var j = 0; j < rewardsLength; j++)
                    {
                        reader.Read(32);
                    }

                    reader.ReadBlobPrecededWithLength(7); // m_toonHandle

                    // m_licenses
                    var licensesLength = reader.Read(9);
                    for (var j = 0; j < licensesLength; j++)
                    {
                        reader.Read(32);
                    }

                    if (reader.ReadBoolean())
                    {
                        reader.Read(4);                                                                                       // m_tandemLeaderUserId
                    }
                    reader.ReadBlobPrecededWithLength(9);                                                                     // m_commander - Empty string

                    reader.Read(32);                                                                                          // m_commanderLevel - So far, always 0

                    if (reader.ReadBoolean() && clientListIndex.HasValue && replay.ClientList[clientListIndex.Value] != null) // m_hasSilencePenalty
                    {
                        replay.ClientList[clientListIndex.Value].IsSilenced = true;
                    }
                }

                if (reader.Read(32) != replay.RandomValue) // m_randomSeed
                {
                    throw new Exception("Replay Random Seed Values in Replay Init Data did not match");
                }

                if (reader.ReadBoolean())
                {
                    reader.Read(4);   // m_hostUserId
                }
                reader.ReadBoolean(); // m_isSinglePlayer

                reader.Read(8);       // m_pickedMapTag - So far, always 0

                reader.Read(32);      // m_gameDuration - So far, always 0

                reader.Read(6);       // m_defaultDifficulty

                reader.Read(7);       // m_defaultAIBuild

                #endregion
            }
        }
    }
Пример #7
0
        /// <summary> Parses the replay.initdata file in a replay file. </summary>
        /// <param name="replay"> The replay file to apply the parsed data to. </param>
        /// <param name="buffer"> The buffer containing the replay.initdata file. </param>
        public static void Parse(Replay replay, byte[] buffer)
        {
            using (var stream = new MemoryStream(buffer))
            {
                var reader = new BitReader(stream);

                var playerListLength = reader.Read(5);
                for (var i = 0; i < playerListLength; i++)
                {
                    var playerName = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(8)); // Player name

                    // Populate the name for each client in the client list by UserID
                    if (playerName != "")
                    {
                        replay.ClientListByUserID[i] = new Player {
                            Name = playerName
                        }
                    }
                    ;

                    if (reader.ReadBoolean())
                    {
                        reader.ReadBlobPrecededWithLength(8); // clanTag
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.ReadBlobPrecededWithLength(40); // Clan Logo
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.Read(8); // highestLeague
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.ReadInt32(); // combinedRaceLevels
                    }
                    reader.ReadInt32();     // Random seed (So far, always 0 in Heroes)

                    if (reader.ReadBoolean())
                    {
                        reader.Read(8); // Race Preference
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.Read(8);                                            // Team Preference
                    }
                    reader.ReadBoolean();                                          //test map
                    reader.ReadBoolean();                                          //test auto
                    reader.ReadBoolean();                                          //examine
                    reader.ReadBoolean();                                          //custom interface

                    reader.ReadInt32();                                            // m_testType

                    reader.Read(2);                                                //observer

                    Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_hero - Currently Empty String
                    Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_skin - Currently Empty String
                    Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_mount - Currently Empty String
                    if (replay.ReplayVersionMajor >= 2)
                    {
                        Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9));                 // m_banner - Currently Empty String
                        Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9));                 // m_spray - Currently Empty String
                    }
                    Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(7));                     // m_toonHandle - Currently Empty String
                }

                // Marked as 'Random Value', so I will use as seed
                replay.RandomValue = (uint)reader.ReadInt32();

                reader.ReadBlobPrecededWithLength(10);  // m_gameCacheName - "Dflt"

                reader.ReadBoolean();                   // Lock Teams
                reader.ReadBoolean();                   // Teams Together
                reader.ReadBoolean();                   // Advanced Shared Control
                reader.ReadBoolean();                   // Random Races
                reader.ReadBoolean();                   // BattleNet
                reader.ReadBoolean();                   // AMM
                reader.ReadBoolean();                   // Competitive
                reader.ReadBoolean();                   // m_practice
                reader.ReadBoolean();                   // m_cooperative
                reader.ReadBoolean();                   // m_noVictoryOrDefeat
                reader.ReadBoolean();                   // m_heroDuplicatesAllowed
                reader.Read(2);                         // Fog
                reader.Read(2);                         // Observers
                reader.Read(2);                         // User Difficulty
                reader.ReadInt32(); reader.ReadInt32(); // 64 bit int: Client Debug Flags

                // m_ammId
                if (replay.ReplayBuild >= 43905 && reader.ReadBoolean())
                {
                    switch (reader.ReadInt32())
                    {
                    case 50021:     // Versus AI (Cooperative)
                    case 50041:     // Practice
                        break;

                    case 50001:
                        replay.GameMode = GameMode.QuickMatch;
                        break;

                    case 50031:
                        replay.GameMode = GameMode.Brawl;
                        break;

                    case 50051:
                        replay.GameMode = GameMode.UnrankedDraft;
                        break;

                    case 50061:
                        replay.GameMode = GameMode.HeroLeague;
                        break;

                    case 50071:
                        replay.GameMode = GameMode.TeamLeague;
                        break;

                    default:
                        replay.GameMode = GameMode.Unknown;
                        break;
                    }
                }

                reader.Read(3); // Game Speed

                // Not sure what this 'Game Type' is
                reader.Read(3);

                var maxUsers = reader.Read(5);
                if (maxUsers != 10 && replay.GameMode != GameMode.Brawl) // Max Players
                {
                    replay.GameMode = GameMode.TryMe;
                }

                reader.Read(5); // Max Observers
                reader.Read(5); // Max Players
                reader.Read(4); // + 1 = Max Teams
                reader.Read(6); // Max Colors
                reader.Read(8); // + 1 = Max Races

                // Max Controls
                if (replay.ReplayBuild < 59279)
                {
                    reader.Read(8);
                }
                else
                {
                    reader.Read(4);
                }

                replay.MapSize = new Point {
                    X = (int)reader.Read(8), Y = (int)reader.Read(8)
                };
                if (replay.MapSize.Y == 1)
                {
                    replay.MapSize.Y = replay.MapSize.X;
                }
                else if (replay.MapSize.X == 0)
                {
                    replay.MapSize.X = replay.MapSize.Y;
                }

                // I haven't tested the following code on replays before build 39595 (End of 2015)
                if (replay.ReplayBuild < 39595)
                {
                    return;
                }

                reader.Read(32);                       // m_mapFileSyncChecksum
                reader.ReadBlobPrecededWithLength(11); // m_mapFileName
                reader.ReadBlobPrecededWithLength(8);  // m_mapAuthorName
                reader.Read(32);                       // m_modFileSyncChecksum

                // m_slotDescriptions
                var slotDescriptionLength = reader.Read(5);
                for (var i = 0; i < slotDescriptionLength; i++)
                {
                    reader.ReadBitArray(reader.Read(6)); // m_allowedColors
                    reader.ReadBitArray(reader.Read(8)); // m_allowedRaces
                    reader.ReadBitArray(reader.Read(6)); // m_allowedDifficulty

                    // m_allowedControls
                    if (replay.ReplayBuild < 59279)
                    {
                        reader.ReadBitArray(reader.Read(8));
                    }
                    else
                    {
                        reader.ReadBitArray(reader.Read(4));
                    }

                    reader.ReadBitArray(reader.Read(2)); // m_allowedObserveTypes
                    reader.ReadBitArray(reader.Read(7)); // m_allowedAIBuilds
                }

                reader.Read(6); // m_defaultDifficulty
                reader.Read(7); // m_defaultAIBuild

                // m_cacheHandles
                var cacheHandlesLength = reader.Read(6);
                for (var i = 0; i < cacheHandlesLength; i++)
                {
                    reader.ReadBytes(40);
                }

                reader.ReadBoolean(); // m_hasExtensionMod
                reader.ReadBoolean(); // m_isBlizzardMap
                reader.ReadBoolean(); // m_isPremadeFFA
                reader.ReadBoolean(); // m_isCoopMode

                #region m_lobbyState

                reader.Read(3); // m_phase
                reader.Read(5); // m_maxUsers
                reader.Read(5); // m_maxObservers

                // m_slots
                var slotsLength = reader.Read(5);
                for (var i = 0; i < slotsLength; i++)
                {
                    int?userID = null;

                    reader.Read(8); // m_control
                    if (reader.ReadBoolean())
                    {
                        userID = (int)reader.Read(4); // m_userId
                    }
                    reader.Read(4);                   // m_teamId
                    if (reader.ReadBoolean())
                    {
                        reader.Read(5); // m_colorPref
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.Read(8); // m_racePref
                    }
                    reader.Read(6);     // m_difficulty
                    reader.Read(7);     // m_aiBuild
                    reader.Read(7);     // m_handicap

                    // m_observe
                    var observerStatus = reader.Read(2);

                    reader.Read(32);                                                                      // m_logoIndex

                    reader.ReadBlobPrecededWithLength(9);                                                 // m_hero

                    var skinAndSkinTint = Encoding.ASCII.GetString(reader.ReadBlobPrecededWithLength(9)); // m_skin
                    if (skinAndSkinTint == "")
                    {
                        skinAndSkinTint = null;
                    }

                    var mountAndMountTint = Encoding.ASCII.GetString(reader.ReadBlobPrecededWithLength(9)); // m_mount
                    if (mountAndMountTint == "")
                    {
                        mountAndMountTint = null;
                    }

                    // m_artifacts
                    if (replay.ReplayBuild < 65579 || replay.ReplayBuild == 65617 || replay.ReplayBuild == 65654)
                    {
                        var artifactsLength = reader.Read(4);
                        for (var j = 0; j < artifactsLength; j++)
                        {
                            reader.ReadBlobPrecededWithLength(9);
                        }
                    }

                    int?workingSetSlotID = null;
                    if (reader.ReadBoolean())
                    {
                        workingSetSlotID = (int)reader.Read(8);  // m_workingSetSlotId
                    }
                    if (userID.HasValue && workingSetSlotID.HasValue)
                    {
                        if (replay.ClientListByWorkingSetSlotID[workingSetSlotID.Value] != null)
                        {
                            replay.ClientListByUserID[userID.Value] = replay.ClientListByWorkingSetSlotID[workingSetSlotID.Value];
                        }

                        if (observerStatus == 2)
                        {
                            replay.ClientListByUserID[userID.Value].PlayerType = PlayerType.Spectator;
                        }

                        replay.ClientListByUserID[userID.Value].SkinAndSkinTint   = skinAndSkinTint;
                        replay.ClientListByUserID[userID.Value].MountAndMountTint = mountAndMountTint;
                    }

                    // m_rewards
                    var rewardsLength = reader.Read(17);
                    for (var j = 0; j < rewardsLength; j++)
                    {
                        reader.Read(32);
                    }

                    reader.ReadBlobPrecededWithLength(7); // m_toonHandle

                    // m_licenses
                    if (replay.ReplayBuild < 49582 || replay.ReplayBuild == 49838)
                    {
                        var licensesLength = reader.Read(9);
                        for (var j = 0; j < licensesLength; j++)
                        {
                            reader.Read(32);
                        }
                    }

                    if (reader.ReadBoolean())
                    {
                        reader.Read(4); // m_tandemLeaderUserId
                    }
                    if (replay.ReplayBuild <= 41504)
                    {
                        reader.ReadBlobPrecededWithLength(9); // m_commander - Empty string

                        reader.Read(32);                      // m_commanderLevel - So far, always 0
                    }

                    if (reader.ReadBoolean() && userID.HasValue)                     // m_hasSilencePenalty
                    {
                        replay.ClientListByUserID[userID.Value].IsSilenced = true;
                    }

                    if (replay.ReplayBuild >= 61718 && reader.ReadBoolean() && userID.HasValue) // m_hasVoiceSilencePenalty
                    {
                        replay.ClientListByUserID[userID.Value].IsVoiceSilence = true;
                    }

                    if (replay.ReplayBuild >= 66977 && reader.ReadBoolean() && userID.HasValue)                    // m_isBlizzardStaff
                    {
                        replay.ClientListByUserID[userID.Value].IsBlizzardStaff = true;
                    }

                    if (replay.ReplayVersionMajor >= 2)
                    {
                        Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9));                         // m_banner
                        Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9));                         // m_spray
                        Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9));                         // m_announcerPack
                        Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9));                         // m_voiceLine

                        // m_heroMasteryTiers
                        if (replay.ReplayBuild >= 52561)
                        {
                            var heroMasteryTiersLength = reader.Read(10);
                            for (var j = 0; j < heroMasteryTiersLength; j++)
                            {
                                reader.Read(32);                                // m_hero
                                reader.Read(8);                                 // m_tier
                            }
                        }
                    }
                }

                if (reader.Read(32) != replay.RandomValue) // m_randomSeed
                {
                    throw new Exception("Replay Random Seed Values in Replay Init Data did not match");
                }

                if (reader.ReadBoolean())
                {
                    reader.Read(4);   // m_hostUserId
                }
                reader.ReadBoolean(); // m_isSinglePlayer

                reader.Read(8);       // m_pickedMapTag - So far, always 0

                reader.Read(32);      // m_gameDuration - So far, always 0

                reader.Read(6);       // m_defaultDifficulty

                reader.Read(7);       // m_defaultAIBuild

                #endregion
            }
        }
    }