public static byte[] ReadSpecialBlob(BitReader bitReader, int numBitsForLength)
        {
            var stringLength = bitReader.Read(numBitsForLength);

            bitReader.AlignToByte();
            bitReader.ReadBytes(2);
            return(bitReader.ReadBytes((int)stringLength));
        }
Пример #2
0
        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(25);
                bitReader.Read(7);
                bool noCollection = bitReader.ReadBoolean();

                // repeat of the collection section above
                if (replay.ReplayBuild >= 51609 && !noCollection)
                {
                    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);

                        bitReader.ReadBoolean();
                    }
                    // else if not equal, then data isn't available, most likely an observer
                }
                else if (!noCollection)
                {
                    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);
                }

                bitReader.ReadBoolean(); // m_hasSilencePenalty

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

                if (replay.ReplayBuild >= 66977)
                {
                    bitReader.ReadBoolean();                                                                      // m_isBlizzardStaff
                }
                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
        }
Пример #3
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++)
                {
                    var nameLength = reader.ReadByte();
                    var str        = reader.ReadString(nameLength);

                    playerList[j] = str;

                    if (reader.ReadBoolean())
                    {
                        var strLength = reader.ReadByte();
                        reader.AlignToByte();

                        // Clan Tag
                        reader.ReadString(strLength);
                    }

                    if (reader.ReadBoolean())
                    {
                        reader.ReadByte().ToString(); // Highest league
                    }
                    if (reader.ReadBoolean())
                    {
                        reader.ReadInt32().ToString(); // Swarm level
                    }
                    reader.ReadInt32();                // Random seed (So far, always 0 in Heroes)

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

                    reader.AlignToByte();
                    reader.ReadBytes(11); // Bunch of garbage \0
                }

                // 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 maxPlayers = reader.Read(5);
                if (maxPlayers != 10) // Max Players
                {
                    replay.GameMode = GameMode.TryMe;
                }

                // About 1000 bytes from here is a list of characters, character skins, character mounts, artifact selections, and other data
            }
        }