public static void Parse(Replay replay, byte[] buffer) { int headerSize = 4; if (replay.ReplayBuild >= 17326) // 1.2.0 { headerSize = 5; } var numAttributes = BitConverter.ToInt32(buffer, headerSize); var attributes = new ReplayAttribute[numAttributes]; int initialOffset = 4 + headerSize; for (int i = 0; i < numAttributes; i++) { attributes[i] = ReplayAttribute.Parse(buffer, initialOffset + (i * 13)); } var rae = new ReplayAttributeEvents { Attributes = attributes }; rae.ApplyAttributes(replay); }
public static void Parse(Replay replay, byte[] buffer) { int headerSize = 4; if (replay.ReplayBuild >= 17326) // 1.2.0 { headerSize = 5; } var numAttributes = BitConverter.ToInt32(buffer, headerSize); var attributes = new ReplayAttribute[numAttributes]; int initialOffset = 4 + headerSize; for (int i = 0; i < numAttributes; i++) { attributes[i] = ReplayAttribute.Parse(buffer, initialOffset + (i*13)); } var rae = new ReplayAttributeEvents { Attributes = attributes }; rae.ApplyAttributes(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); }