/// <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(); } }
/// <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(); } }
private static byte[] GetMpqArchiveFileBytes(CArchive archive, string archivedFileName) { var buffer = new byte[archive.FindFiles(archivedFileName).Single().Size]; archive.ExportFile(archivedFileName, buffer); return(buffer); }
/// <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(); } }
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); } }
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); } } }
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); }
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); }
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); } }
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; }
private static byte[] GetMpqArchiveFileBytes(CArchive archive, string archivedFileName) { var buffer = new byte[archive.FindFiles(archivedFileName).Single().Size]; archive.ExportFile(archivedFileName, buffer); return buffer; }
/// <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; }
/// <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> 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); }