/// <summary> Parses the Replay.Messages.Events file. </summary> /// <param name="buffer"> Buffer containing the contents of the replay.messages.events file. </param> /// <returns> A list of chat messages parsed from the buffer. </returns> public static void Parse(Replay replay, byte[] buffer) { using (var stream = new MemoryStream(buffer)) { using (var reader = new BinaryReader(stream)) { int totalTime = 0; while (reader.BaseStream.Position < reader.BaseStream.Length) { // While not EOF var message = new ChatMessage(); var time = ParseTimestamp(reader); // sometimes we only have a header for the message if (reader.BaseStream.Position >= reader.BaseStream.Length) break; message.PlayerId = reader.ReadByte(); // I believe this 'PlayerId' is an index for this client list, which can include observers // var player = replay.ClientList[message.PlayerId]; totalTime += time; var opCode = reader.ReadByte(); if (opCode == 0x80) reader.ReadBytes(4); else if (opCode == 0x83) reader.ReadBytes(8); else if (opCode == 2 && message.PlayerId <= 10) { if (message.PlayerId == 80) continue; message.MessageTarget = (ChatMessageTarget)(opCode & 7); var length = reader.ReadByte(); if ((opCode & 8) == 8) length += 64; if ((opCode & 16) == 16) length += 128; message.Message = Encoding.UTF8.GetString(reader.ReadBytes(length)); } else { } if (message.Message != null) { message.Timestamp = new TimeSpan(0, 0, (int)Math.Round(totalTime / 16.0)); replay.ChatMessages.Add(message); } } } } }
/// <summary> Parses the Replay.Messages.Events file. </summary> /// <param name="buffer"> Buffer containing the contents of the replay.messages.events file. </param> /// <returns> A list of chat messages parsed from the buffer. </returns> public static void Parse(Replay replay, byte[] buffer) { var messages = new List<ChatMessage>(); using (var stream = new MemoryStream(buffer)) { using (var reader = new BinaryReader(stream)) { int totalTime = 0; while (reader.BaseStream.Position < reader.BaseStream.Length) { // While not EOF var message = new ChatMessage(); var time = ParseTimestamp(reader); message.PlayerId = reader.ReadByte(); totalTime += time; var opCode = reader.ReadByte(); if (opCode == 0x80) reader.ReadBytes(4); else if (opCode == 0x83) reader.ReadBytes(8); else if (opCode == 2 && message.PlayerId <= 10) { if (message.PlayerId == 80) continue; message.MessageTarget = (ChatMessageTarget)(opCode & 7); var length = reader.ReadByte(); if ((opCode & 8) == 8) length += 64; if ((opCode & 16) == 16) length += 128; message.Message = Encoding.UTF8.GetString(reader.ReadBytes(length)); } else { } if (message.Message != null) { message.Timestamp = new TimeSpan(0, 0, (int)Math.Round(totalTime / 16.0)); messages.Add(message); } } } } replay.ChatMessages = messages; }
/// <summary> Parses the Replay.Messages.Events file. </summary> /// <param name="buffer"> Buffer containing the contents of the replay.messages.events file. </param> /// <returns> A list of messages parsed from the buffer. </returns> public static void Parse(Replay replay, byte[] buffer) { if (buffer.Length <= 1) { // Chat has been removed from this replay return; } var ticksElapsed = 0; using (var stream = new MemoryStream(buffer)) { var bitReader = new Streams.BitReader(stream); while (!bitReader.EndOfStream) { var message = new Message(); ticksElapsed += (int)bitReader.Read(6 + (bitReader.Read(2) << 3)); message.Timestamp = new TimeSpan(0, 0, (int)Math.Round(ticksElapsed / 16.0)); var playerIndex = (int)bitReader.Read(5); if (playerIndex != 16) { message.MessageSender = replay.ClientListByUserID[playerIndex]; message.PlayerIndex = playerIndex; } message.MessageEventType = (MessageEventType)bitReader.Read(4); switch (message.MessageEventType) { case MessageEventType.SChatMessage: { ChatMessage chatMessage = new ChatMessage(); chatMessage.MessageTarget = (MessageTarget)bitReader.Read(3); // m_recipient (the target) chatMessage.Message = Encoding.UTF8.GetString(bitReader.ReadBlobPrecededWithLength(11)); // m_string message.ChatMessage = chatMessage; replay.Messages.Add(message); break; } case MessageEventType.SPingMessage: { PingMessage pingMessage = new PingMessage(); pingMessage.MessageTarget = (MessageTarget)bitReader.Read(3); // m_recipient (the target) pingMessage.XCoordinate = bitReader.ReadInt32() - (-2147483648); // m_point x pingMessage.YCoordinate = bitReader.ReadInt32() - (-2147483648); // m_point y message.PingMessage = pingMessage; replay.Messages.Add(message); break; } case MessageEventType.SLoadingProgressMessage: { // can be used to keep track of how fast/slow players are loading // also includes players who are reloading the game var progress = bitReader.ReadInt32() - (-2147483648); // m_progress break; } case MessageEventType.SServerPingMessage: { break; } case MessageEventType.SReconnectNotifyMessage: { bitReader.Read(2); // m_status; is either a 1 or a 2 break; } case MessageEventType.SPlayerAnnounceMessage: { PlayerAnnounceMessage announceMessage = new PlayerAnnounceMessage(); announceMessage.AnnouncementType = (AnnouncementType)bitReader.Read(2); switch (announceMessage.AnnouncementType) { case AnnouncementType.None: { break; } case AnnouncementType.Ability: { AbilityAnnouncment ability = new AbilityAnnouncment(); ability.AbilityLink = bitReader.ReadInt16(); // m_abilLink ability.AbilityIndex = (int)bitReader.Read(5); // m_abilCmdIndex ability.ButtonLink = bitReader.ReadInt16(); // m_buttonLink announceMessage.AbilityAnnouncement = ability; break; } case AnnouncementType.Behavior: // no idea what triggers this { bitReader.ReadInt16(); // m_behaviorLink bitReader.ReadInt16(); // m_buttonLink break; } case AnnouncementType.Vitals: { VitalAnnouncment vital = new VitalAnnouncment(); vital.VitalType = (VitalType)(bitReader.ReadInt16() - (-32768)); announceMessage.VitalAnnouncement = vital; break; } default: throw new NotImplementedException(); } if (replay.ReplayBuild > 45635) { // m_announceLink bitReader.ReadInt16(); } bitReader.ReadInt32(); // m_otherUnitTag bitReader.ReadInt32(); // m_unitTag message.PlayerAnnounceMessage = announceMessage; replay.Messages.Add(message); break; } default: throw new NotImplementedException(); } bitReader.AlignToByte(); } } }