Example #1
0
        //Precondition: datablock cannot be null
        //Parses Gamename, playerNames and the team indices of the player.
        private void ParseGameHeaderBlock(DataBlock dataBlock, ReplayData replayData, out int endIndex)
        {
            //Skip 4 (According to specification, first 4 bytes is unknown)
            int currIndex = 4;

            byte[] gameHeaderData = dataBlock.DecompressedDataBlockBytes;

            byte recordId = gameHeaderData[currIndex];
            currIndex++;
            byte playerId = gameHeaderData[currIndex];
            currIndex++;

            string playerName = ByteUtility.GetNullTerminatedString(gameHeaderData, currIndex, out currIndex);

            replayData.AddPlayerInfo(new PlayerInfo(playerName,playerId,recordId));
            
            //Custom data byte. We can safely ignore this.
            Debug.Assert(gameHeaderData[currIndex] == 0x01);
            currIndex++;
            //Null byte. Ignore this as well
            Debug.Assert(gameHeaderData[currIndex] == 0x00);
            currIndex++;

            replayData.GameName = ByteUtility.GetNullTerminatedString(gameHeaderData, currIndex, out currIndex);

            //Null byte.
            Debug.Assert(gameHeaderData[currIndex] == 0x00);
            currIndex++;
            
            //Refers to Section 4.4, 4.5 (Game Settings, Map&Creator Name)
            //We don't actually need this information, but it's kept just in case we need it in the future
            string encodedString = ByteUtility.GetReplayEncodedString(gameHeaderData, currIndex, out currIndex);

            //According to spec, this is player count but in reality, it's mapslotcount
            uint mapSlotCount = ByteUtility.ReadDoubleWord(gameHeaderData, currIndex);
            currIndex += 4;

            //Game Type byte. Safely skip (Section 4.7)
            currIndex++;

            //Private Flag. Safely Skip (Section 4.7)
            currIndex++;

            //Unknown Word. Safely Skip (Section 4.7)
            currIndex += 2;

            //Language ID. Safely Skip (Section 4.8)
            currIndex += 4;

            //Loop until we find all players
            while (gameHeaderData[currIndex] == 0x16)
            {
                recordId = gameHeaderData[currIndex];
                currIndex++;
                playerId = gameHeaderData[currIndex];
                currIndex++;

                playerName = ByteUtility.GetNullTerminatedString(gameHeaderData, currIndex, out currIndex);
                replayData.AddPlayerInfo(new PlayerInfo(playerName, playerId, recordId));

                //Custom data byte. We can safely ignore this.
                Debug.Assert(gameHeaderData[currIndex] == 0x01);
                currIndex++;

                //Skip 4 unknown bytes (Section 4.9)
                currIndex += 4;

                //Skip null byte
                while (gameHeaderData[currIndex] == 0x00)
                {
                    currIndex++;
                }
            }
            
            //Skip Record Id (Section 4.10, always 0x19)
            currIndex++;

            //Number of data bytes following
            ushort dataByteCount = ByteUtility.ReadWord(gameHeaderData, currIndex);
            currIndex += 2;

            //number of available slots (For fate, always 12)
            int slotCount = gameHeaderData[currIndex];
            currIndex++;

            //int slotRecordIndex = 0;
            for (int i = 0; i < slotCount; i++ )
            {
                playerId = gameHeaderData[currIndex];
                currIndex++;
                if (playerId == 0x00) //Computer player. Skip to next one
                {
                    currIndex += 8;
                    continue;
                }

                //Skip map download percent
                currIndex++;

                byte slotStatus = gameHeaderData[currIndex];
                if (slotStatus == 0x00) //Empty slot. Skip to next one.
                {
                    currIndex += 7;
                    continue;
                }
                currIndex++;

                //Skip computer player flag
                currIndex++;

                byte teamNumber = gameHeaderData[currIndex];
                PlayerInfo player = replayData.GetPlayerInfoByPlayerReplayId(playerId);
                if (player == null)
                    throw new InvalidDataException("Player Id not found! ID: " + playerId);
                player.Team = teamNumber;
                replayData.PlayerCount++;
                currIndex++;

                //Skip rest of bytes (color, raceflags, AI strength, handicap)
                currIndex += 4;
            }
            
            //Skip randomseed (Section 4.12)
            currIndex += 4;

            //Skip selectMode
            byte selectMode = gameHeaderData[currIndex];
            //For fate, Team & Race is not selectable.
            
            currIndex++;

            //Skip StartSpotCount
            currIndex++;

            endIndex = currIndex;
        }