Exemplo n.º 1
0
        private static Sc2Replay ParseReplay(IMpqArchive archive)
        {
            if (archive == null) throw new ArgumentNullException("archive");

            var result = new Sc2Replay();
            ParseUserDataHeader(archive, result);

            dynamic details = archive.ReadSerializedData("replay.details", false);

            result.MapName = Encoding.UTF8.GetString(details[1]);

            // parse the date, subtract the time zone to get UTC time
            var timeZoneOffset = new TimeSpan((long)details[6]);
            var date = DateTime.FromFileTime((long)details[5]);
            var adjustedDate = date.Subtract(timeZoneOffset);
            result.DatePlayed = DateTime.SpecifyKind(adjustedDate, DateTimeKind.Utc);

            result.Players = ParsePlayers(details);
            ParseMapInformation(details, result);

            // hack: we don't actually parse the replay gateway since I 
            //  haven't been able to find it in the replay file yet.
            //  for now, we just assume that it's the same as the gateway
            //  of the map file resource.
            result.Gateway = result.MapGateway; 

            result.Attributes = ParseAttributes(archive);
            ApplyAttributes(result);
            return result;
        }
        private static void ApplyAttributes(Sc2Replay replay)
        {
            foreach (var attribute in replay.Attributes)
            {
                var stringValue = attribute.StringValue;

                Sc2ReplayPlayer player = null;

                // player indices are 1-based, and 0 means that the attribute doesn't relate to a player
                if (attribute.PlayerIndex > 0 && attribute.PlayerIndex <= replay.Players.Length)
                    player = replay.Players[attribute.PlayerIndex - 1];

                switch (attribute.Type)
                {
                    case Sc2ReplayAttributeType.PlayerType:
                        if (stringValue.Equals("comp", StringComparison.OrdinalIgnoreCase))
                            player.Type = Sc2ReplayPlayerType.Computer;
                        else if (stringValue.Equals("humn", StringComparison.OrdinalIgnoreCase))
                            player.Type = Sc2ReplayPlayerType.Human;
                        break;

                    case Sc2ReplayAttributeType.TeamSize:
                        replay.TeamSize = stringValue.Trim('\0');
                        break;

                    case Sc2ReplayAttributeType.PlayerTeam_1v1:
                    case Sc2ReplayAttributeType.PlayerTeam_2v2:
                    case Sc2ReplayAttributeType.PlayerTeam_3v3:
                    case Sc2ReplayAttributeType.PlayerTeam_4v4:
                    case Sc2ReplayAttributeType.PlayerTeam_FFA:
                        var team = stringValue.Trim('\0', 'T');
                        player.Team = Convert.ToInt32(team);
                        break;
                    
                    case Sc2ReplayAttributeType.PlayerRace:
                        player.SelectedRace = RaceParser.Parse(stringValue);
                        break;

                    case Sc2ReplayAttributeType.GameType:
                        if (stringValue.Equals("priv", StringComparison.OrdinalIgnoreCase))
                            replay.GameType = Sc2GameType.Custom;
                        else if (stringValue.Trim('\0').Equals("amm", StringComparison.OrdinalIgnoreCase))
                            replay.GameType = Sc2GameType.Matchmaking;
                        break;


                }
            }
        }
Exemplo n.º 3
0
        private static void ParseMapInformation(dynamic details, Sc2Replay result)
        {
            var resources = (object[]) details[10];
            var mapData = (byte[]) resources.Last();

            if (mapData[0] != 's' ||
                mapData[1] != '2' ||
                mapData[2] != 'm' ||
                mapData[3] != 'a' ||
                mapData[4] != 0 ||
                mapData[5] != 0)
                throw new Sc2ReplayParsingException("Replay file format invalid (Error parsing map gateway and hash)");

            result.MapGateway = Encoding.UTF8.GetString(mapData, 6, 2);
            var mapHashBytes = new byte[32];
            Array.Copy(mapData, 8, mapHashBytes, 0, 32);
            result.MapHash = string.Join("", mapHashBytes.Select(b => b.ToString("X2"))).ToLowerInvariant();
        }
Exemplo n.º 4
0
        private static void ParseUserDataHeader(IMpqArchive replay, Sc2Replay result)
        {
            dynamic data = Starcraft2SerializedData.Deserialize(replay.UserDataHeader.UserData, true);

            var starcraft2 = (string)data[0];
            if (!starcraft2.StartsWith("StarCraft II replay"))
                // todo: this is kind of a hack, for some reason there are extra funky characters after "replay". Why?
                throw new InvalidOperationException(
                    String.Format(
                        "This does not appear to be a SC2 replay file. (Unexpected user header string: '{0}')",
                        starcraft2));

            var buildAndVersion = (IDictionary<long, object>)data[1];
            result.Version = new[] { (long)buildAndVersion[0], (long)buildAndVersion[1], (long)buildAndVersion[2], (long)buildAndVersion[3] };
            result.Build = new[] { (long)buildAndVersion[4], (long)buildAndVersion[5] };

            ValidateBuild(result.Build);

            var lengthInTicks = (long)data[3];
            result.Length = TimeSpan.FromSeconds(lengthInTicks / 16d);
        }