Пример #1
0
        /// <summary> Erases the entire chat log of a file. </summary>
        /// <param name="fileName"> The file name.  </param>
        public static void ClearChatLog(string fileName)
        {
            var replay = new Replay();

            // File in the version numbers for later use.
            MpqHeader.ParseHeader(replay, fileName);

            using (var archive = new CArchive(fileName))
            {
                var files = archive.FindFiles("replay.*");
                {
                    const string CurFile  = "replay.message.events";
                    var          fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    var arr = ClearChatLog(buffer);
                    archive.ImportFile("replay.message.events", arr);
                }

                archive.Close();
            }
        }
Пример #2
0
        /// <summary> Adds a single chat message to a replay. </summary>
        /// <param name="fileName"> The file name.  </param>
        /// <param name="message"> The message.  </param>
        /// <param name="target"> The target. </param>
        /// <param name="playerId"> The player id.  </param>
        /// <param name="numSeconds"> The number of in-game seconds to insert the message at.  </param>
        public static void AddChatMessageToReplay(
            string fileName, string message, ChatMessageTarget target, int playerId, int numSeconds)
        {
            var replay = new Replay();

            // File in the version numbers for later use.
            MpqHeader.ParseHeader(replay, fileName);

            using (var archive = new CArchive(fileName))
            {
                var files = archive.FindFiles("replay.*");
                {
                    const string CurFile  = "replay.message.events";
                    var          fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    var arr = GenerateChatMessage(buffer, message, target, playerId, numSeconds);
                    archive.ImportFile("replay.message.events", arr);
                }

                archive.Close();
            }
        }
        /// <summary> Adds a single chat message to a replay. </summary>
        /// <param name="fileName"> The file name.  </param>
        /// <param name="message"> The message.  </param>
        /// <param name="target"> The target. </param>
        /// <param name="playerId"> The player id.  </param>
        /// <param name="numSeconds"> The number of in-game seconds to insert the message at.  </param>
        public static void AddChatMessageToReplay(
            string fileName, string message, ChatMessageTarget target, int playerId, int numSeconds)
        {
            var replay = new Replay();

            // File in the version numbers for later use.
            MpqHeader.ParseHeader(replay, fileName);

            using (var archive = new CArchive(fileName))
            {
                var files = archive.FindFiles("replay.*");
                {
                    const string CurFile = "replay.message.events";
                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    var arr = GenerateChatMessage(buffer, message, target, playerId, numSeconds);
                    archive.ImportFile("replay.message.events", arr);
                }

                archive.Close();
            }
        }
        /// <summary> Adds a single chat message to a replay. </summary>
        /// <param name="fileName"> The file name.  </param>
        /// <param name="messages"> The messages to add.  </param>
        public static void AddChatMessageToReplay(string fileName, IEnumerable<ChatMessage> messages)
        {
            var replay = new Replay();

            // File in the version numbers for later use.
            MpqHeader.ParseHeader(replay, fileName);

            using (var archive = new CArchive(fileName))
            {
                var files = archive.FindFiles("replay.*");
                {
                    const string CurFile = "replay.message.events";
                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    foreach (var message in messages)
                    {
                        buffer = GenerateChatMessage(
                            buffer,
                            message.Message,
                            message.MessageTarget,
                            message.PlayerId,
                            (int)message.Timestamp.TotalSeconds);
                    }

                    archive.ImportFile("replay.message.events", buffer);
                }

                archive.Close();
            }
        }
Пример #5
0
        private static byte[] GetMpqArchiveFileBytes(CArchive archive, string archivedFileName)
        {
            var buffer = new byte[archive.FindFiles(archivedFileName).Single().Size];

            archive.ExportFile(archivedFileName, buffer);
            return(buffer);
        }
Пример #6
0
        /// <summary> Adds a single chat message to a replay. </summary>
        /// <param name="fileName"> The file name.  </param>
        /// <param name="messages"> The messages to add.  </param>
        public static void AddChatMessageToReplay(string fileName, IEnumerable <ChatMessage> messages)
        {
            var replay = new Replay();

            // File in the version numbers for later use.
            MpqHeader.ParseHeader(replay, fileName);

            using (var archive = new CArchive(fileName))
            {
                var files = archive.FindFiles("replay.*");
                {
                    const string CurFile  = "replay.message.events";
                    var          fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    foreach (var message in messages)
                    {
                        buffer = GenerateChatMessage(
                            buffer,
                            message.Message,
                            message.MessageTarget,
                            message.PlayerId,
                            (int)message.Timestamp.TotalSeconds);
                    }

                    archive.ImportFile("replay.message.events", buffer);
                }

                archive.Close();
            }
        }
Пример #7
0
        public static void InitializeDBC(string path)
        {
            if (_initializedDBC)
            {
                return;
            }

            string root = path ?? GetWoWInstallPath();

            foreach (var language in Languages)
            {
                var dir = root + "\\Data\\" + language;
                if (!Directory.Exists(dir))
                {
                    continue;
                }

                var file = dir + "\\locale-" + language + ".mpq";
                if (!File.Exists(file))
                {
                    continue;
                }

                _locale = new CArchive(file);
                Console.WriteLine("Using locale: " + file);
                break;
            }

            _initializedDBC = true;
        }
        static void Main(string[] args)
        {
            var heroesAccountsFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), @"Heroes of the Storm\Accounts");
            var randomReplayFileName = Directory.GetFiles(heroesAccountsFolder, "*.StormReplay", SearchOption.AllDirectories).OrderBy(i => Guid.NewGuid()).First();

            // Use temp directory for MpqLib directory permissions requirements
            var tmpPath = Path.GetTempFileName();
            File.Copy(randomReplayFileName, tmpPath, true);

            try
            {
                // Create our Replay object: this object will be filled as you parse the different files in the .StormReplay archive
                var replay = new Replay();
                MpqHeader.ParseHeader(replay, tmpPath);
                using (var archive = new CArchive(tmpPath))
                {
                    ReplayInitData.Parse(replay, GetMpqArchiveFileBytes(archive, ReplayInitData.FileName));
                    ReplayDetails.Parse(replay, GetMpqArchiveFileBytes(archive, ReplayDetails.FileName));
                    ReplayTrackerEvents.Parse(replay, GetMpqArchiveFileBytes(archive, ReplayTrackerEvents.FileName));
                    ReplayAttributeEvents.Parse(replay, GetMpqArchiveFileBytes(archive, ReplayAttributeEvents.FileName));
                    if (replay.ReplayBuild >= 32455)
                        ReplayGameEvents.Parse(replay, GetMpqArchiveFileBytes(archive, ReplayGameEvents.FileName));
                    ReplayServerBattlelobby.Parse(replay, GetMpqArchiveFileBytes(archive, ReplayServerBattlelobby.FileName));
                    ReplayMessageEvents.Parse(replay, GetMpqArchiveFileBytes(archive, ReplayMessageEvents.FileName));
                    Unit.ParseUnitData(replay);
                }

                // Our Replay object now has all currently available information
                var playerDictionary = new Dictionary<int, Player>();
                Console.WriteLine("Replay Build: " + replay.ReplayBuild);
                Console.WriteLine("Map: " + replay.Map);
                foreach (var player in replay.Players.OrderByDescending(i => i.IsWinner))
                {
                    playerDictionary[player.PlayerId] = player;
                    Console.WriteLine("Player: " + player.Name + ", Win: " + player.IsWinner + ", Hero: " + player.Character + ", Lvl: " + player.CharacterLevel + (replay.ReplayBuild >= 32524 ? ", Talents: " + string.Join(",", player.Talents.OrderBy(i => i)) : ""));
                }


                foreach (var message in replay.ChatMessages)
                     if (playerDictionary.ContainsKey(message.PlayerId))
                        Console.WriteLine(playerDictionary[message.PlayerId].Name + ": " + message.Message);
                    
                Console.WriteLine("Press Any Key to Close");
                Console.Read();
            }
            finally
            {
                if (File.Exists(tmpPath))
                    File.Delete(tmpPath);
            }
        }
Пример #9
0
        static void Main(string[] args)
        {
            var heroesAccountsFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), @"Heroes of the Storm\Accounts");
            var randomReplayFileName = Directory.GetFiles(heroesAccountsFolder, "*.StormReplay", SearchOption.AllDirectories).OrderBy(i => Guid.NewGuid()).First();

            // Use temp directory for MpqLib directory permissions requirements
            var tmpPath = Path.GetTempFileName();

            File.Copy(randomReplayFileName, tmpPath, true);

            try
            {
                // Create our Replay object: this object will be filled as you parse the different files in the .StormReplay archive
                var replay = new Replay();
                MpqHeader.ParseHeader(replay, tmpPath);
                using (var archive = new CArchive(tmpPath))
                {
                    ReplayInitData.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.initData"));
                    ReplayDetails.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.details"));
                    ReplayTrackerEvents.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.tracker.events"));
                    ReplayAttributeEvents.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.attributes.events"));
                    if (replay.ReplayBuild >= 32455)
                    {
                        ReplayGameEvents.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.game.events"));
                    }
                    ReplayServerBattlelobby.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.server.battlelobby"));
                    Unit.ParseUnitData(replay);
                }

                // Our Replay object now has all currently available information
                Console.WriteLine("Replay Build: " + replay.ReplayBuild);
                Console.WriteLine("Map: " + replay.Map);
                foreach (var player in replay.Players.OrderByDescending(i => i.IsWinner))
                {
                    Console.WriteLine("Player: " + player.Name + ", Win: " + player.IsWinner + ", Hero: " + player.Character + ", Lvl: " + player.CharacterLevel + (replay.ReplayBuild >= 32524 ? ", Talents: " + string.Join(",", player.Talents.OrderBy(i => i)) : ""));
                }

                Console.WriteLine("Press Any Key to Close");
                Console.Read();
            }
            finally
            {
                if (File.Exists(tmpPath))
                {
                    File.Delete(tmpPath);
                }
            }
        }
Пример #10
0
        public static void Initialize(string path = null)
        {
            if (_initialized)
                return;
            _initialized = true;
            string root = path ?? GetWoWInstallPath();
            var files = Directory.GetFiles(root + "\\Data\\", "*.MPQ", SearchOption.TopDirectoryOnly).OrderByDescending(s => s);
            foreach (var file in files)
            {
                if (IgnoredMPQs.Contains(Path.GetFileName(file)))
                    continue;
                var archive = new CArchive(file);
                Console.WriteLine("Opened " + file + " with " + archive.FileCount + " files...");
                _archives.Add(Path.GetFileNameWithoutExtension(file), archive);
            }

            InitializeDBC(root);
        }
Пример #11
0
        public static void Initialize(string path = null)
        {
            if (_initialized)
            {
                return;
            }
            _initialized = true;
            string root  = path ?? GetWoWInstallPath();
            var    files = Directory.GetFiles(root + "\\Data\\", "*.MPQ", SearchOption.TopDirectoryOnly).OrderByDescending(s => s);

            foreach (var file in files)
            {
                if (IgnoredMPQs.Contains(Path.GetFileName(file)))
                {
                    continue;
                }
                var archive = new CArchive(file);
                Console.WriteLine("Opened " + file + " with " + archive.FileCount + " files...");
                _archives.Add(Path.GetFileNameWithoutExtension(file), archive);
            }

            InitializeDBC(root);
        }
Пример #12
0
        static void Main(string[] args)
        {
            var path = args[0];
           
            // Use temp directory for MpqLib directory permissions requirements
            var tmpPath = Path.GetTempFileName();
            File.Copy(path, tmpPath, true);

            try
            {
                // Create our Replay object: this object will be filled as you parse the different files in the .StormReplay archive
                var replay = new Replay();
                MpqHeader.ParseHeader(replay, tmpPath);
                using (var archive = new CArchive(tmpPath))
                {
                    ReplayInitData.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.initData"));
                    ReplayDetails.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.details"));
                    ReplayTrackerEvents.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.tracker.events"));
                    ReplayAttributeEvents.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.attributes.events"));
                    if (replay.ReplayBuild >= 32455)
                        ReplayGameEvents.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.game.events"));
                    ReplayServerBattlelobby.Parse(replay, GetMpqArchiveFileBytes(archive, "replay.server.battlelobby"));
                    Unit.ParseUnitData(replay);
                }

                // Our Replay object now has all currently available information
                Console.WriteLine(JsonConvert.SerializeObject(replay, Formatting.None, new JsonSerializerSettings { 
                    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
                    NullValueHandling = NullValueHandling.Ignore
                }));
            }
            finally
            {
                if (File.Exists(tmpPath))
                    File.Delete(tmpPath);
            }
        }
Пример #13
0
        public static void InitializeDBC(string path)
        {
            if (_initializedDBC)
                return;

            string root = path ?? GetWoWInstallPath();

            foreach (var language in Languages)
            {
                var dir = root + "\\Data\\" + language;
                if (!Directory.Exists(dir))
                    continue;

                var file = dir + "\\locale-" + language + ".mpq";
                if (!File.Exists(file))
                    continue;

                _locale = new CArchive(file);
                Console.WriteLine("Using locale: " + file);
                break;
            }

            _initializedDBC = true;
        }
Пример #14
0
 private static byte[] GetMpqArchiveFileBytes(CArchive archive, string archivedFileName)
 {
     var buffer = new byte[archive.FindFiles(archivedFileName).Single().Size];
     archive.ExportFile(archivedFileName, buffer);
     return buffer;
 }
Пример #15
0
        /// <summary> Parses a .SC2Replay file and returns relevant replay information.  </summary>
        /// <param name="fileName"> Full path to a .SC2Replay file.  </param>
        /// <param name="noEvents"> True if you don't want to parse events (uses about 5~10 MB on a pro replay, half on an amateur replay) </param>
        /// <returns> Returns the fully parsed Replay object. </returns>
        public static Replay Parse(string fileName, bool noEvents = false)
        {
            if (File.Exists(fileName) == false)
            {
                throw new FileNotFoundException("The specified file does not exist.", fileName);
            }

            var replay = new Replay();

            // File in the version numbers for later use.
            MpqHeader.ParseHeader(replay, fileName);

            CArchive archive;

            try
            {
                archive = new CArchive(fileName);
            }
            catch (IOException)
            {
                // Usually thrown if the archive name contains korean. Copy it to a local file and open.
                var tmpPath = Path.GetTempFileName();

                File.Copy(fileName, tmpPath, true);

                archive = new CArchive(tmpPath);
            }

            try
            {
                var files = archive.FindFiles("replay.*");
                {
                    const string CurFile = "replay.initData";

                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    ReplayInitData.Parse(replay, buffer);
                }

                {
                    // Local scope allows the byte[] to be GC sooner, and prevents misreferences
                    const string CurFile = "replay.details";

                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    ReplayDetails.Parse(replay, buffer);
                }

                {
                    const string CurFile = "replay.attributes.events";
                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    ReplayAttributeEvents.Parse(replay, buffer);
                }

                {
                    const string CurFile = "replay.message.events";
                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);
                    try
                    {
                        replay.ChatMessages = ReplayMessageEvents.Parse(buffer);
                    }
                    catch // Chat may have been removed without maintaining the structure
                          // Example:  LiquidHayPro vs MFTarga.SC2Replay from TLPro pack #36
                          // You can see a date on the file in MPQ editor, and viewing the
                          // replay in SC2 results in no chat at all.
                    {
                        replay.ChatMessages = new List<ChatMessage>();
                    }
                }

                try
                {
                    if (!noEvents)
                    {
                        const string CurFile = "replay.game.events";

                        var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                        var buffer = new byte[fileSize];

                        archive.ExportFile(CurFile, buffer);

                        replay.PlayerEvents = ReplayGameEvents.Parse(replay, buffer);
                    }
                }
                catch (Exception)
                {
                    // Likely to happen with any non-standard (i.e. format isn't melee nvn, locked alliances) replay.
                }
            }
            finally
            {
                archive.Dispose();
            }

            replay.Timestamp = File.GetCreationTime(fileName);

            return replay;
        }
Пример #16
0
        /// <summary> Parses a .SC2Replay file and returns relevant replay information.  </summary>
        /// <param name="fileName"> Full path to a .SC2Replay file.  </param>
        /// <returns> Returns the fully parsed Replay object. </returns>
        public static Replay Parse(string fileName)
        {
            if (File.Exists(fileName) == false)
            {
                throw new FileNotFoundException("The specified file does not exist.", fileName);
            }

            var replay = new Replay();

            // File in the version numbers for later use.
            MpqHeader.ParseHeader(replay, fileName);

            CArchive archive;

            try
            {
                archive = new CArchive(fileName);
            }
            catch (IOException)
            {
                // Usually thrown if the archive name contains korean. Copy it to a local file and open.
                var tmpPath = Path.GetTempFileName();

                File.Copy(fileName, tmpPath, true);

                archive = new CArchive(tmpPath);
            }

            try
            {
                var files = archive.FindFiles("replay.*");
                {
                    const string CurFile = "replay.initData";

                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    ReplayInitData.Parse(replay, buffer);
                }

                {
                    // Local scope allows the byte[] to be GC sooner, and prevents misreferences
                    const string CurFile = "replay.details";

                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    ReplayDetails.Parse(replay, buffer);
                }

                {
                    const string CurFile = "replay.attributes.events";
                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    ReplayAttributeEvents.Parse(replay, buffer);
                }

                {
                    const string CurFile = "replay.message.events";
                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    replay.ChatMessages = ReplayMessageEvents.Parse(buffer);
                }

                try
                {
                    const string CurFile = "replay.game.events";

                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    replay.PlayerEvents = ReplayGameEvents.Parse(replay, buffer);
                }
                catch (Exception)
                {
                    // In the current state, the parsing commonly fails.
                    // Incase of failing, we should probably just ignore the results of the parse
                    // And return.
                }
            }
            finally
            {
                archive.Dispose();
            }

            replay.Timestamp = File.GetCreationTime(fileName);

            return replay;
        }
        /// <summary> Erases the entire chat log of a file. </summary>
        /// <param name="fileName"> The file name.  </param>
        public static void ClearChatLog(string fileName)
        {
            var replay = new Replay();

            // File in the version numbers for later use.
            MpqHeader.ParseHeader(replay, fileName);

            using (var archive = new CArchive(fileName))
            {
                var files = archive.FindFiles("replay.*");
                {
                    const string CurFile = "replay.message.events";
                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    var arr = ClearChatLog(buffer);
                    archive.ImportFile("replay.message.events", arr);
                }

                archive.Close();
            }
        }
Пример #18
0
        /// <summary> Parses a .SC2Replay file and returns relevant replay information.  </summary>
        /// <param name="fileName"> Full path to a .SC2Replay file.  </param>
        /// <param name="noEvents"> True if you don't want to parse events (uses about 5~10 MB on a pro replay, half on an amateur replay) </param>
        /// <returns> Returns the fully parsed Replay object. </returns>
        public static Replay Parse(string fileName, bool noEvents = false)
        {
            if (File.Exists(fileName) == false)
            {
                throw new FileNotFoundException("The specified file does not exist.", fileName);
            }

            var replay = new Replay();

            // File in the version numbers for later use.
            MpqHeader.ParseHeader(replay, fileName);

            CArchive archive;

            try
            {
                archive = new CArchive(fileName);
            }
            catch (IOException)
            {
                // Usually thrown if the archive name contains korean. Copy it to a local file and open.
                var tmpPath = Path.GetTempFileName();

                File.Copy(fileName, tmpPath, true);

                archive = new CArchive(tmpPath);
            }

            try
            {
                var files = archive.FindFiles("replay.*");
                {
                    const string CurFile = "replay.initData";

                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    ReplayInitData.Parse(replay, buffer);
                }

                {
                    // Local scope allows the byte[] to be GC sooner, and prevents misreferences
                    const string CurFile = "replay.details";

                    var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    ReplayDetails.Parse(replay, buffer);
                }

                {
                    const string CurFile  = "replay.attributes.events";
                    var          fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);

                    ReplayAttributeEvents.Parse(replay, buffer);
                }

                {
                    const string CurFile  = "replay.message.events";
                    var          fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                    var buffer = new byte[fileSize];

                    archive.ExportFile(CurFile, buffer);
                    try
                    {
                        replay.ChatMessages = ReplayMessageEvents.Parse(buffer);
                    }
                    catch // Chat may have been removed without maintaining the structure
                          // Example:  LiquidHayPro vs MFTarga.SC2Replay from TLPro pack #36
                          // You can see a date on the file in MPQ editor, and viewing the
                          // replay in SC2 results in no chat at all.
                    {
                        replay.ChatMessages = new List <ChatMessage>();
                    }
                }

                try
                {
                    if (!noEvents)
                    {
                        const string CurFile = "replay.game.events";

                        var fileSize = (from f in files where f.FileName.Equals(CurFile) select f).Single().Size;

                        var buffer = new byte[fileSize];

                        archive.ExportFile(CurFile, buffer);

                        replay.PlayerEvents = ReplayGameEvents.Parse(replay, buffer);
                    }
                }
                catch (Exception)
                {
                    // Likely to happen with any non-standard (i.e. format isn't melee nvn, locked alliances) replay.
                }
            }
            finally
            {
                archive.Dispose();
            }

            replay.Timestamp = File.GetCreationTime(fileName);

            return(replay);
        }