private static void ParseReplayArchive(Replay replay, MpqArchive archive, bool ignoreErrors, bool detailedBattleLobbyParsing = false)
        {
            archive.AddListfileFilenames();

            // Replay Details
            ReplayDetails.Parse(replay, GetMpqFile(archive, ReplayDetails.FileName), ignoreErrors);

            if (!ignoreErrors)
            {
                if (replay.Players.Length != 10 || replay.Players.Count(i => i.IsWinner) != 5)
                {
                    // Filter out 'Try Me' games, any games without 10 players, and incomplete games
                    return;
                }
                else if (replay.Timestamp == DateTime.MinValue)
                {
                    // Uncommon issue when parsing replay.details
                    return;
                }
                else if (replay.Timestamp < new DateTime(2014, 10, 6, 0, 0, 0, DateTimeKind.Utc))
                {
                    // Technical Alpha replays
                    return;
                }
            }

            // Replay Init Data
            ReplayInitData.Parse(replay, GetMpqFile(archive, ReplayInitData.FileName));

            ReplayAttributeEvents.Parse(replay, GetMpqFile(archive, ReplayAttributeEvents.FileName));

            replay.TrackerEvents = ReplayTrackerEvents.Parse(GetMpqFile(archive, ReplayTrackerEvents.FileName));

            try
            {
                replay.GameEvents = ReplayGameEvents.Parse(GetMpqFile(archive, ReplayGameEvents.FileName), replay.ClientListByUserID, replay.ReplayBuild, replay.ReplayVersionMajor);
                replay.IsGameEventsParsedSuccessfully = true;
            }
            catch
            {
                replay.GameEvents = new List <GameEvent>();
            }

            {
                // Gather talent selections
                var talentGameEventsDictionary = replay.GameEvents
                                                 .Where(i => i.eventType == GameEventType.CHeroTalentSelectedEvent)
                                                 .GroupBy(i => i.player)
                                                 .ToDictionary(
                    i => i.Key,
                    i => i.Select(j => new Talent {
                    TalentID = (int)j.data.unsignedInt.Value, TimeSpanSelected = j.TimeSpan
                }).OrderBy(j => j.TimeSpanSelected).ToArray());

                foreach (var player in talentGameEventsDictionary.Keys)
                {
                    player.Talents = talentGameEventsDictionary[player];
                }
            }

            // Replay Server Battlelobby
            if (!ignoreErrors && archive.Any(i => i.Filename == ReplayServerBattlelobby.FileName))
            {
                if (detailedBattleLobbyParsing)
                {
                    ReplayServerBattlelobby.Parse(replay, GetMpqFile(archive, ReplayServerBattlelobby.FileName));
                }
                else
                {
                    ReplayServerBattlelobby.GetBattleTags(replay, GetMpqFile(archive, ReplayServerBattlelobby.FileName));
                }
            }

            // Parse Unit Data using Tracker events
            Unit.ParseUnitData(replay);

            // Parse Statistics
            if (replay.ReplayBuild >= 40431)
            {
                try
                {
                    Statistics.Parse(replay);
                    replay.IsStatisticsParsedSuccessfully = true;
                }
                catch
                {
                    replay.IsGameEventsParsedSuccessfully = false;
                }
            }

            // Replay Message Events
            // ReplayMessageEvents.Parse(replay, GetMpqFile(archive, ReplayMessageEvents.FileName));

            // Replay Resumable Events
            // So far it doesn't look like this file has anything we would be interested in
            // ReplayResumableEvents.Parse(replay, GetMpqFile(archive, "replay.resumable.events"));
        }