From 0ce969077841f3b7a89df98755576372f8fe5c2e Mon Sep 17 00:00:00 2001 From: BruceChen Date: Sat, 14 Jan 2023 00:53:36 +0800 Subject: [PATCH] 1.19.3 Chat command signing support & Update chat paser --- MinecraftClient/McClient.cs | 6 +- .../Protocol/Handlers/Protocol16.cs | 2 +- .../Protocol/Handlers/Protocol18.cs | 192 ++++++++++-------- .../Protocol/Message/ChatMessage.cs | 27 +-- .../Protocol/Message/ChatParser.cs | 37 +++- .../Protocol/Message/LastSeenMessageList.cs | 3 +- 6 files changed, 164 insertions(+), 103 deletions(-) diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index 9d49ae59..d001f872 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -64,6 +64,7 @@ namespace MinecraftClient private double motionY; public enum MovementType { Sneak, Walk, Sprint } private int sequenceId; // User for player block synchronization (Aka. digging, placing blocks, etc..) + private bool CanSendMessage = false; private readonly string host; private readonly int port; @@ -286,6 +287,9 @@ namespace MinecraftClient /// private void TrySendMessageToServer() { + if (!CanSendMessage) + return; + while (chatQueue.Count > 0 && nextMessageSendTime < DateTime.Now) { string text = chatQueue.Dequeue(); @@ -2411,7 +2415,7 @@ namespace MinecraftClient if (protocolversion >= Protocol18Handler.MC_1_19_3_Version && playerKeyPair != null) handler.SendPlayerSession(playerKeyPair); - + CanSendMessage = true; if (inventoryHandlingRequested) { diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index aba5c555..6ac8d7be 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -119,7 +119,7 @@ namespace MinecraftClient.Protocol.Handlers case 0x02: ReadData(1); ReadNextString(); ReadNextString(); ReadData(4); break; case 0x03: string message = ReadNextString(); - handler.OnTextReceived(new ChatMessage(message, protocolversion >= 72, 0, Guid.Empty)); break; + handler.OnTextReceived(new ChatMessage(message, null, protocolversion >= 72, -1, Guid.Empty)); break; case 0x04: ReadData(16); break; case 0x05: ReadData(6); ReadNextItemSlot(); break; case 0x06: ReadData(12); break; diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 5a6f0f5f..c47b2d27 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -377,6 +377,8 @@ namespace MinecraftClient.Protocol.Handlers for (int i = 0; i < worldCount; i++) dataTypes.ReadNextString(packetData); // Dimension Names (World Names) - 1.16 and above var registryCodec = dataTypes.ReadNextNbt(packetData); // Registry Codec (Dimension Codec) - 1.16 and above + if (protocolVersion >= MC_1_19_Version) + ChatParser.ReadChatType(registryCodec); if (handler.GetTerrainEnabled()) World.StoreDimensionList(registryCodec); } @@ -455,9 +457,6 @@ namespace MinecraftClient.Protocol.Handlers } } - if (protocolVersion >= MC_1_19_3_Version) - SendPlayerSession(handler.GetPlayerKeyPair()); - break; case PacketTypesIn.DeclareCommands: if (protocolVersion >= MC_1_19_Version) @@ -486,7 +485,7 @@ namespace MinecraftClient.Protocol.Handlers else senderUUID = Guid.Empty; - handler.OnTextReceived(new(message, true, messageType, senderUUID)); + handler.OnTextReceived(new(message, null, true, messageType, senderUUID)); } else if (protocolVersion == MC_1_19_Version) // 1.19 { @@ -608,25 +607,31 @@ namespace MinecraftClient.Protocol.Handlers { // 1.19.3+ // Header section + // net.minecraft.network.packet.s2c.play.ChatMessageS2CPacket#write Guid senderUUID = dataTypes.ReadNextUUID(packetData); int index = dataTypes.ReadNextVarInt(packetData); // Signature is fixed size of 256 bytes byte[]? messageSignature = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextByteArray(packetData, 256) : null; // Body + // net.minecraft.network.message.MessageBody.Serialized#write string message = dataTypes.ReadNextString(packetData); long timestamp = dataTypes.ReadNextLong(packetData); long salt = dataTypes.ReadNextLong(packetData); // Previous Messages + // net.minecraft.network.message.LastSeenMessageList.Indexed#write + // net.minecraft.network.message.MessageSignatureData.Indexed#write int totalPreviousMessages = dataTypes.ReadNextVarInt(packetData); - List> previousMessageSignatures = new(); - + Tuple[] previousMessageSignatures = new Tuple[totalPreviousMessages]; for (int i = 0; i < totalPreviousMessages; i++) { - int messageId = dataTypes.ReadNextVarInt(packetData); - if (messageId == 0) // from botcraft implementation. Only read if id is 0. Byte array is fixed size of 256 bytes - previousMessageSignatures.Add(new Tuple(messageId, dataTypes.ReadNextByteArray(packetData, 256))); + // net.minecraft.network.message.MessageSignatureData.Indexed#fromBuf + int messageId = dataTypes.ReadNextVarInt(packetData) - 1; + if (messageId == -1) + previousMessageSignatures[i] = new Tuple(messageId, dataTypes.ReadNextByteArray(packetData, 256)); + else + previousMessageSignatures[i] = new Tuple(messageId, null); } // Other @@ -638,14 +643,16 @@ namespace MinecraftClient.Protocol.Handlers dataTypes.ReadNextULongArray(packetData); // Network Target + // net.minecraft.network.message.MessageType.Serialized#write int chatTypeId = dataTypes.ReadNextVarInt(packetData); string chatName = dataTypes.ReadNextString(packetData); string? targetName = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; - Dictionary chatInfo = Json.ParseJson(chatName).Properties; + ChatParser.MessageType messageTypeEnum = ChatParser.ChatId2Type!.GetValueOrDefault(chatTypeId, ChatParser.MessageType.CHAT); + + Dictionary chatInfo = Json.ParseJson(targetName ?? chatName).Properties; string senderDisplayName = (chatInfo.ContainsKey("insertion") ? chatInfo["insertion"] : chatInfo["text"]).StringValue; string? senderTeamName = null; - ChatParser.MessageType messageTypeEnum = ChatParser.ChatId2Type!.GetValueOrDefault(chatTypeId, ChatParser.MessageType.CHAT); if (targetName != null && (messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_INCOMING || messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_OUTGOING)) senderTeamName = Json.ParseJson(targetName).Properties["with"].DataArray[0].Properties["text"].StringValue; @@ -663,13 +670,68 @@ namespace MinecraftClient.Protocol.Handlers } } - // TODO: Verify the message - ChatMessage chat = new(message, false, chatTypeId, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, messageSignature, false); + // Todo: verify message + bool verifyResult; + if (!isOnlineMode) + verifyResult = false; + else if (senderUUID == handler.GetUserUuid()) + verifyResult = true; + else + { + PlayerInfo? player = handler.GetPlayerInfo(senderUUID); + if (player == null || !player.IsMessageChainLegal()) + verifyResult = false; + else + { + verifyResult = false; + //bool lastVerifyResult = player.IsMessageChainLegal(); + //verifyResult = player.VerifyMessage(message, timestamp, salt, ref headerSignature, ref precedingSignature, lastSeenMessages); + //if (lastVerifyResult && !verifyResult) + // log.Warn(string.Format(Translations.chat_message_chain_broken, senderDisplayName)); + } + } + + ChatMessage chat = new(message, false, chatTypeId, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, messageSignature, verifyResult); if (isOnlineMode && !chat.LacksSender() && messageSignature != null) Acknowledge(chat); handler.OnTextReceived(chat); } break; + case PacketTypesIn.SystemChat: + string systemMessage = dataTypes.ReadNextString(packetData); + if (protocolVersion >= MC_1_19_3_Version) + { + bool isOverlay = dataTypes.ReadNextBool(packetData); + if (isOverlay) + { + if (!Config.Main.Advanced.ShowXPBarMessages) + break; + } + else + { + if (!Config.Main.Advanced.ShowSystemMessages) + break; + } + handler.OnTextReceived(new(systemMessage, null, true, -1, Guid.Empty, true)); + } + else + { + int msgType = dataTypes.ReadNextVarInt(packetData); + if ((msgType == 1 && !Config.Main.Advanced.ShowSystemMessages)) + break; + handler.OnTextReceived(new(systemMessage, null, true, msgType, Guid.Empty, true)); + } + break; + case PacketTypesIn.ProfilelessChatMessage: + string message_ = dataTypes.ReadNextString(packetData); + int messageType_ = dataTypes.ReadNextVarInt(packetData); + string messageName = dataTypes.ReadNextString(packetData); + string? targetName_ = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; + ChatMessage profilelessChat = new(message_, messageName, true, messageType_, Guid.Empty, true); + profilelessChat.isSenderJson = true; + profilelessChat.teamName = targetName_; + handler.OnTextReceived(profilelessChat); + break; case PacketTypesIn.CombatEvent: // 1.8 - 1.16.5 if (protocolVersion >= MC_1_8_Version && protocolVersion <= MC_1_16_5_Version) @@ -1214,14 +1276,6 @@ namespace MinecraftClient.Protocol.Handlers break; case PacketTypesIn.ChatSuggestions: break; - case PacketTypesIn.ProfilelessChatMessage: - string message_ = dataTypes.ReadNextString(packetData); - int messageType_ = dataTypes.ReadNextVarInt(packetData); - string messageName = dataTypes.ReadNextString(packetData); - string? targetName_ = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null; - - // Not clear for what this is used for as the time of writing - break; case PacketTypesIn.MapChunkBulk: if (protocolVersion < MC_1_9_Version && handler.GetTerrainEnabled()) { @@ -1296,14 +1350,13 @@ namespace MinecraftClient.Protocol.Handlers case PacketTypesIn.PlayerInfo: if (protocolVersion >= MC_1_19_3_Version) { - // int actions = dataTypes.ReadNextVarInt(packetData); - ulong actionBitset = dataTypes.ReadNextByte(packetData); + byte actionBitset = dataTypes.ReadNextByte(packetData); int numberOfActions = dataTypes.ReadNextVarInt(packetData); for (int i = 0; i < numberOfActions; i++) { Guid playerUuid = dataTypes.ReadNextUUID(packetData); - if ((actionBitset & (1ul << 0)) > 0) // Actions bit 0: add player + if ((actionBitset & (1 << 0)) > 0) // Actions bit 0: add player { string name = dataTypes.ReadNextString(packetData); int numberOfProperties = dataTypes.ReadNextVarInt(packetData); @@ -1318,7 +1371,7 @@ namespace MinecraftClient.Protocol.Handlers } PlayerInfo player = handler.GetPlayerInfo(playerUuid)!; - if ((actionBitset & (1ul << 1)) > 0) // Actions bit 1: initialize chat + if ((actionBitset & (1 << 1)) > 0) // Actions bit 1: initialize chat { bool hasSignatureData = dataTypes.ReadNextBool(packetData); if (hasSignatureData) @@ -1334,20 +1387,20 @@ namespace MinecraftClient.Protocol.Handlers player.ClearPublicKey(); } } - if ((actionBitset & (1ul << 2)) > 0) // Actions bit 2: update gamemode + if ((actionBitset & 1 << 2) > 0) // Actions bit 2: update gamemode { handler.OnGamemodeUpdate(playerUuid, dataTypes.ReadNextVarInt(packetData)); } - if ((actionBitset & (1ul << 3)) > 0) // Actions bit 3: update listed + if ((actionBitset & (1 << 3)) > 0) // Actions bit 3: update listed { player.Listed = dataTypes.ReadNextBool(packetData); } - if ((actionBitset & (1ul << 4)) > 0) // Actions bit 4: update latency + if ((actionBitset & (1 << 4)) > 0) // Actions bit 4: update latency { int latency = dataTypes.ReadNextVarInt(packetData); handler.OnLatencyUpdate(playerUuid, latency); //Update latency; } - if ((actionBitset & (1ul << 5)) > 0) // Actions bit 5: update display name + if ((actionBitset & (1 << 5)) > 0) // Actions bit 5: update display name { if (dataTypes.ReadNextBool(packetData)) player.DisplayName = dataTypes.ReadNextString(packetData); @@ -1811,13 +1864,6 @@ namespace MinecraftClient.Protocol.Handlers long TimeOfday = dataTypes.ReadNextLong(packetData); handler.OnTimeUpdate(WorldAge, TimeOfday); break; - case PacketTypesIn.SystemChat: - string systemMessage = dataTypes.ReadNextString(packetData); - int msgType = dataTypes.ReadNextVarInt(packetData); - if ((msgType == 1 && !Config.Main.Advanced.ShowSystemMessages)) - break; - handler.OnTextReceived(new(systemMessage, true, msgType, Guid.Empty, true)); - break; case PacketTypesIn.EntityTeleport: if (handler.GetEntityHandlingEnabled()) { @@ -2498,9 +2544,12 @@ namespace MinecraftClient.Protocol.Handlers try { - LastSeenMessageList.Acknowledgment? acknowledgment = - (protocolVersion >= MC_1_19_2_Version) ? ConsumeAcknowledgment() : null; + LastSeenMessageList.Acknowledgment? acknowledgment_1_19_2 = + (protocolVersion == MC_1_19_2_Version) ? ConsumeAcknowledgment() : null; + (LastSeenMessageList.AcknowledgedMessage[] acknowledgment_1_19_3, byte[] bitset_1_19_3, int messageCount_1_19_3) = + (protocolVersion >= MC_1_19_3_Version) ? lastSeenMessagesCollector.Collect_1_19_3() : new(Array.Empty(), Array.Empty(), 0); + List fields = new(); // Command: String @@ -2529,34 +2578,37 @@ namespace MinecraftClient.Protocol.Handlers foreach ((string argName, string message) in needSigned) { fields.AddRange(dataTypes.GetString(argName)); // Argument name: String - byte[] sign = (protocolVersion >= MC_1_19_2_Version) ? - playerKeyPair!.PrivateKey.SignMessage(message, uuid, timeNow, ref salt, acknowledgment!.lastSeen) : - playerKeyPair!.PrivateKey.SignMessage(message, uuid, timeNow, ref salt); - fields.AddRange(DataTypes.GetVarInt(sign.Length)); // Signature length: VarInt - fields.AddRange(sign); // Signature: Byte Array + + byte[] sign; + if (protocolVersion == MC_1_19_Version) + sign = playerKeyPair!.PrivateKey.SignMessage(message, uuid, timeNow, ref salt); + else if (protocolVersion == MC_1_19_2_Version) + sign = playerKeyPair!.PrivateKey.SignMessage(message, uuid, timeNow, ref salt, acknowledgment_1_19_2!.lastSeen); + else // protocolVersion >= MC_1_19_3_Version + sign = playerKeyPair!.PrivateKey.SignMessage(message, uuid, chatUuid, messageIndex++, timeNow, ref salt, acknowledgment_1_19_3); + + if (protocolVersion <= MC_1_19_2_Version) + fields.AddRange(DataTypes.GetVarInt(sign.Length)); // Signature length: VarInt + + fields.AddRange(sign); // Signature: Byte Array } } - if (protocolVersion < MC_1_19_3_Version) - { - // Signed Preview: Boolean (1.19.2) - fields.AddRange(dataTypes.GetBool(false)); - } - else - { - fields.AddRange(dataTypes.GetVarInt(messageCount)); // Message count (1.19.3) - } + if (protocolVersion <= MC_1_19_2_Version) + fields.AddRange(dataTypes.GetBool(false)); // Signed Preview: Boolean if (protocolVersion == MC_1_19_2_Version) { // Message Acknowledgment (1.19.2) - fields.AddRange(dataTypes.GetAcknowledgment(acknowledgment!, isOnlineMode && Config.Signature.LoginWithSecureProfile)); + fields.AddRange(dataTypes.GetAcknowledgment(acknowledgment_1_19_2!, isOnlineMode && Config.Signature.LoginWithSecureProfile)); } else if (protocolVersion >= MC_1_19_3_Version) { - // 1.19.3 - // Acknowledged: BitSet (no idea what is this) - fields.AddRange(new byte[3] { 0, 0, 0 }); + // message count + fields.AddRange(DataTypes.GetVarInt(messageCount_1_19_3)); + + // Acknowledged: BitSet + fields.AddRange(bitset_1_19_3); } SendPacket(PacketTypesOut.ChatCommand, fields); @@ -2575,7 +2627,7 @@ namespace MinecraftClient.Protocol.Handlers /// True if properly sent public bool SendChatMessage(string message, PlayerKeyPair? playerKeyPair) { - if (String.IsNullOrEmpty(message)) + if (string.IsNullOrEmpty(message)) return true; // Process Chat Command - 1.19 and above @@ -2622,8 +2674,8 @@ namespace MinecraftClient.Protocol.Handlers sign = playerKeyPair.PrivateKey.SignMessage(message, playerUuid, timeNow, ref salt); else if (protocolVersion == MC_1_19_2_Version) // 1.19.2 sign = playerKeyPair.PrivateKey.SignMessage(message, playerUuid, timeNow, ref salt, acknowledgment_1_19_2!.lastSeen); - else // 1.19.3+ - sign = playerKeyPair.PrivateKey.SignMessage(message, playerUuid, handler.GetPlayerInfo(playerUuid)!.ChatUuid, messageIndex++, timeNow, ref salt, acknowledgment_1_19_3); + else // protocolVersion >= MC_1_19_3_Version + sign = playerKeyPair.PrivateKey.SignMessage(message, playerUuid, chatUuid, messageIndex++, timeNow, ref salt, acknowledgment_1_19_3); if (protocolVersion >= MC_1_19_3_Version) fields.AddRange(dataTypes.GetBool(true)); @@ -3317,28 +3369,6 @@ namespace MinecraftClient.Protocol.Handlers packet.AddRange(playerKeyPair.PublicKey.SignatureV2); SendPacket(PacketTypesOut.PlayerSession, packet); - - return true; - } - catch (SocketException) { return false; } - catch (System.IO.IOException) { return false; } - catch (ObjectDisposedException) { return false; } - } - else { return false; } - } - - public bool SendMessageAcknowledgment(int messageCount) - { - if (protocolVersion >= MC_1_19_3_Version) - { - try - { - List packet = new(); - - packet.AddRange(dataTypes.GetVarInt(messageCount)); - - SendPacket(PacketTypesOut.MessageAcknowledgment, packet); - return true; } catch (SocketException) { return false; } diff --git a/MinecraftClient/Protocol/Message/ChatMessage.cs b/MinecraftClient/Protocol/Message/ChatMessage.cs index 23a34be4..c2b74fc6 100644 --- a/MinecraftClient/Protocol/Message/ChatMessage.cs +++ b/MinecraftClient/Protocol/Message/ChatMessage.cs @@ -5,31 +5,31 @@ namespace MinecraftClient.Protocol.Message public class ChatMessage { // in 1.19 and above, isSignedChat = true - public readonly bool isSignedChat; + public bool isSignedChat; - public readonly string content; + public string content; - public readonly bool isJson; + public bool isJson, isSenderJson; // 0: chat (chat box), 1: system message (chat box), 2: game info (above hotbar), 3: say command, // 4: msg command, 5: team msg command, 6: emote command, 7: tellraw command - public readonly int chatTypeId; + public int chatTypeId; - public readonly Guid senderUUID; + public Guid senderUUID; - public readonly bool isSystemChat; + public bool isSystemChat; - public readonly string? unsignedContent; + public string? unsignedContent; - public readonly string? displayName; + public string? displayName; - public readonly string? teamName; + public string? teamName; - public readonly DateTime? timestamp; + public DateTime? timestamp; - public readonly byte[]? signature; + public byte[]? signature; - public readonly bool? isSignatureLegal; + public bool? isSignatureLegal; public ChatMessage(string content, bool isJson, int chatType, Guid senderUUID, string? unsignedContent, string displayName, string? teamName, long timestamp, byte[] signature, bool isSignatureLegal) { @@ -47,11 +47,12 @@ namespace MinecraftClient.Protocol.Message this.isSignatureLegal = isSignatureLegal; } - public ChatMessage(string content, bool isJson, int chatType, Guid senderUUID, bool isSystemChat = false) + public ChatMessage(string content, string? displayName, bool isJson, int chatType, Guid senderUUID, bool isSystemChat = false) { isSignedChat = isSystemChat; this.isSystemChat = isSystemChat; this.content = content; + this.displayName = displayName; this.isJson = isJson; chatTypeId = chatType; this.senderUUID = senderUUID; diff --git a/MinecraftClient/Protocol/Message/ChatParser.cs b/MinecraftClient/Protocol/Message/ChatParser.cs index c0eef1bc..06c316d1 100644 --- a/MinecraftClient/Protocol/Message/ChatParser.cs +++ b/MinecraftClient/Protocol/Message/ChatParser.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; @@ -28,6 +29,30 @@ namespace MinecraftClient.Protocol public static Dictionary? ChatId2Type; + public static void ReadChatType(Dictionary registryCodec) + { + Dictionary chatTypeDictionary = ChatId2Type ?? new(); + var chatTypeListNbt = (object[])(((Dictionary)registryCodec["minecraft:chat_type"])["value"]); + foreach (var (chatName, chatId) in from Dictionary chatTypeNbt in chatTypeListNbt + let chatName = (string)chatTypeNbt["name"] + let chatId = (int)chatTypeNbt["id"] + select (chatName, chatId)) + { + chatTypeDictionary[chatId] = chatName switch + { + "minecraft:chat" => MessageType.CHAT, + "minecraft:emote_command" => MessageType.EMOTE_COMMAND, + "minecraft:msg_command_incoming" => MessageType.MSG_COMMAND_INCOMING, + "minecraft:msg_command_outgoing" => MessageType.MSG_COMMAND_OUTGOING, + "minecraft:say_command" => MessageType.SAY_COMMAND, + "minecraft:team_msg_command_incoming" => MessageType.TEAM_MSG_COMMAND_INCOMING, + "minecraft:team_msg_command_outgoing" => MessageType.TEAM_MSG_COMMAND_OUTGOING, + _ => MessageType.CHAT, + }; + } + ChatId2Type = chatTypeDictionary; + } + /// /// The main function to convert text from MC 1.6+ JSON to MC 1.5.2 formatted text /// @@ -47,7 +72,7 @@ namespace MinecraftClient.Protocol /// Returns the translated text public static string ParseSignedChat(ChatMessage message, List? links = null) { - string sender = message.displayName!; + string sender = message.isSenderJson ? ParseText(message.displayName!) : message.displayName!; string content; if (Config.Signature.ShowModifiedChat && message.unsignedContent != null) { @@ -66,7 +91,7 @@ namespace MinecraftClient.Protocol List usingData = new(); MessageType chatType; - if (message.isSystemChat) + if (message.chatTypeId == -1) chatType = MessageType.RAW_MSG; else if (!ChatId2Type!.TryGetValue(message.chatTypeId, out chatType)) chatType = MessageType.CHAT; @@ -119,7 +144,7 @@ namespace MinecraftClient.Protocol if (message.isSystemChat) { if (Config.Signature.MarkSystemMessage) - color = "§z §r "; // Custom color code §z : Background Gray + color = "§z▍§r"; // Custom color code §z : Background Gray } else { @@ -128,18 +153,18 @@ namespace MinecraftClient.Protocol if (Config.Signature.ShowModifiedChat && message.unsignedContent != null) { if (Config.Signature.MarkModifiedMsg) - color = "§x §r "; // Custom color code §x : Background Yellow + color = "§x▍§r"; // Custom color code §x : Background Yellow } else { if (Config.Signature.MarkLegallySignedMsg) - color = "§y §r "; // Custom color code §y : Background Green + color = "§y▍§r"; // Custom color code §y : Background Green } } else { if (Config.Signature.MarkIllegallySignedMsg) - color = "§w §r "; // Custom color code §w : Background Red + color = "§w▍§r"; // Custom color code §w : Background Red } } return color + text; diff --git a/MinecraftClient/Protocol/Message/LastSeenMessageList.cs b/MinecraftClient/Protocol/Message/LastSeenMessageList.cs index 528e3cee..a068c6af 100644 --- a/MinecraftClient/Protocol/Message/LastSeenMessageList.cs +++ b/MinecraftClient/Protocol/Message/LastSeenMessageList.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Security.Permissions; using static MinecraftClient.Protocol.Message.LastSeenMessageList; @@ -120,7 +121,7 @@ namespace MinecraftClient.Protocol.Message { // net.minecraft.network.message.LastSeenMessagesCollector#add(net.minecraft.network.message.MessageSignatureData, boolean) // net.minecraft.network.message.LastSeenMessagesCollector#add(net.minecraft.network.message.AcknowledgedMessage) - if (entry == lastEntry) + if (lastEntry != null && entry.signature.SequenceEqual(lastEntry.signature)) return false; lastEntry = entry;