/// <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> Inserts the given chat message into the file buffer. </summary> /// <param name="buffer"> The file buffer. </param> /// <param name="message"> The message to insert. </param> /// <param name="target"> The target. </param> /// <param name="playerId"> The player id. </param> /// <param name="seconds"> The number of in-game seconds to insert the message. </param> /// <returns> The final buffer with the inserted message. </returns> /// <exception cref="NotSupportedException"> Thrown if the message is longer than 64 character. </exception> private static byte[] GenerateChatMessage( byte[] buffer, string message, ChatMessageTarget target, int playerId, int seconds) { if (message.Length >= 256) { throw new NotSupportedException("This call does not support strings longer than 256 characters."); } int targetValue = seconds * 16; var completeFile = new List <byte>(); bool hasBeenWritten = false; bool adjustTimestamps = false; using (var stream = new MemoryStream(buffer)) { using (var reader = new BinaryReader(stream)) { int totalTime = 0; int shiftValue = 0; while (reader.BaseStream.Position < reader.BaseStream.Length) { // While not EOF int timestamp = ParseTimestamp(reader); totalTime += timestamp; if (hasBeenWritten == false && totalTime > targetValue) { var orgValue = totalTime - timestamp; shiftValue = targetValue - orgValue; var shiftTimestamp = CreateTimestamp(shiftValue); #region Writing the chat message var bytes = new List <byte>(); bytes.AddRange(shiftTimestamp); bytes.Add((byte)playerId); // playerid // &8 for +64, &16 for +128 var messageOut = Encoding.UTF8.GetBytes(message); int length = messageOut.Length; if (length < 64) { var opcode = (byte)target; bytes.Add(opcode); // opcode bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 128) { var opcode = (byte)((byte)target | 8); bytes.Add(opcode); length -= 64; bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 192) { var opcode = (byte)((byte)target | 16); bytes.Add(opcode); length -= 128; bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 256) { var opcode = (byte)((byte)target | 24); bytes.Add(opcode); length -= 192; bytes.Add((byte)length); bytes.AddRange(messageOut); } completeFile.AddRange(bytes); #endregion hasBeenWritten = true; adjustTimestamps = true; } completeFile.AddRange( adjustTimestamps ? CreateTimestamp(timestamp - shiftValue) : CreateTimestamp(timestamp)); completeFile.Add(reader.ReadByte()); // PlayerID var opCode = reader.ReadByte(); completeFile.Add(opCode); if (opCode == 0x80) { completeFile.AddRange(reader.ReadBytes(4)); } else if (opCode == 0x83) { completeFile.AddRange(reader.ReadBytes(8)); } else if ((opCode & 0x80) == 0) { var length = reader.ReadByte(); completeFile.Add(length); if ((opCode & 8) == 8) { length += 64; } if ((opCode & 16) == 16) { length += 128; } completeFile.AddRange(reader.ReadBytes(length)); } } // If we reach the end and the message still hasn't been entered... if (hasBeenWritten == false) { var shiftTimestamp = CreateTimestamp(targetValue - totalTime); var bytes = new List <byte>(); bytes.AddRange(shiftTimestamp); bytes.Add((byte)playerId); // playerid // &8 for +64, &16 for +128 var messageOut = Encoding.UTF8.GetBytes(message); int length = messageOut.Length; if (length < 64) { var opcode = (byte)target; bytes.Add(opcode); // opcode bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 128) { var opcode = (byte)((byte)target | 8); bytes.Add(opcode); length -= 64; bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 192) { var opcode = (byte)((byte)target | 16); bytes.Add(opcode); length -= 128; bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 256) { var opcode = (byte)((byte)target | 24); bytes.Add(opcode); length -= 192; bytes.Add((byte)length); bytes.AddRange(messageOut); } completeFile.AddRange(bytes); } } } return(completeFile.ToArray()); }
/// <summary> Inserts the given chat message into the file buffer. </summary> /// <param name="buffer"> The file buffer. </param> /// <param name="message"> The message to insert. </param> /// <param name="target"> The target. </param> /// <param name="playerId"> The player id. </param> /// <param name="seconds"> The number of in-game seconds to insert the message. </param> /// <returns> The final buffer with the inserted message. </returns> /// <exception cref="NotSupportedException"> Thrown if the message is longer than 64 character. </exception> private static byte[] GenerateChatMessage( byte[] buffer, string message, ChatMessageTarget target, int playerId, int seconds) { if (message.Length >= 256) { throw new NotSupportedException("This call does not support strings longer than 256 characters."); } int targetValue = seconds * 16; var completeFile = new List<byte>(); bool hasBeenWritten = false; bool adjustTimestamps = false; using (var stream = new MemoryStream(buffer)) { using (var reader = new BinaryReader(stream)) { int totalTime = 0; int shiftValue = 0; while (reader.BaseStream.Position < reader.BaseStream.Length) { // While not EOF int timestamp = ParseTimestamp(reader); totalTime += timestamp; if (hasBeenWritten == false && totalTime > targetValue) { var orgValue = totalTime - timestamp; shiftValue = targetValue - orgValue; var shiftTimestamp = CreateTimestamp(shiftValue); #region Writing the chat message var bytes = new List<byte>(); bytes.AddRange(shiftTimestamp); bytes.Add((byte)playerId); // playerid // &8 for +64, &16 for +128 var messageOut = Encoding.UTF8.GetBytes(message); int length = messageOut.Length; if (length < 64) { var opcode = (byte)target; bytes.Add(opcode); // opcode bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 128) { var opcode = (byte)((byte)target | 8); bytes.Add(opcode); length -= 64; bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 192) { var opcode = (byte)((byte)target | 16); bytes.Add(opcode); length -= 128; bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 256) { var opcode = (byte)((byte)target | 24); bytes.Add(opcode); length -= 192; bytes.Add((byte)length); bytes.AddRange(messageOut); } completeFile.AddRange(bytes); #endregion hasBeenWritten = true; adjustTimestamps = true; } completeFile.AddRange( adjustTimestamps ? CreateTimestamp(timestamp - shiftValue) : CreateTimestamp(timestamp)); completeFile.Add(reader.ReadByte()); // PlayerID var opCode = reader.ReadByte(); completeFile.Add(opCode); if (opCode == 0x80) { completeFile.AddRange(reader.ReadBytes(4)); } else if (opCode == 0x83) { completeFile.AddRange(reader.ReadBytes(8)); } else if ((opCode & 0x80) == 0) { var length = reader.ReadByte(); completeFile.Add(length); if ((opCode & 8) == 8) { length += 64; } if ((opCode & 16) == 16) { length += 128; } completeFile.AddRange(reader.ReadBytes(length)); } } // If we reach the end and the message still hasn't been entered... if (hasBeenWritten == false) { var shiftTimestamp = CreateTimestamp(targetValue - totalTime); var bytes = new List<byte>(); bytes.AddRange(shiftTimestamp); bytes.Add((byte)playerId); // playerid // &8 for +64, &16 for +128 var messageOut = Encoding.UTF8.GetBytes(message); int length = messageOut.Length; if (length < 64) { var opcode = (byte)target; bytes.Add(opcode); // opcode bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 128) { var opcode = (byte)((byte)target | 8); bytes.Add(opcode); length -= 64; bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 192) { var opcode = (byte)((byte)target | 16); bytes.Add(opcode); length -= 128; bytes.Add((byte)length); bytes.AddRange(messageOut); } else if (length < 256) { var opcode = (byte)((byte)target | 24); bytes.Add(opcode); length -= 192; bytes.Add((byte)length); bytes.AddRange(messageOut); } completeFile.AddRange(bytes); } } } return completeFile.ToArray(); }