From aad3d8b2efc34c68e4816d3c9a2c13d85b61761d Mon Sep 17 00:00:00 2001 From: TheSnoozer Date: Tue, 25 Sep 2018 07:38:28 -0400 Subject: [PATCH] https://github.com/ORelio/Minecraft-Console-Client/issues/525: general 1.13 support (v393 protocol). Note that terrainandmovements might cause some issues --- .gitignore | 1 + MinecraftClient/Program.cs | 4 +- MinecraftClient/Protocol/ChatParser.cs | 14 +- .../Protocol/Handlers/Protocol18.cs | 259 ++++++++++++++++-- MinecraftClient/Protocol/ProtocolHandler.cs | 4 +- MinecraftClient/Settings.cs | 2 +- 6 files changed, 251 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 163e9ada..5b09ccb6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /MinecraftClientGUI.suo /MinecraftClient.userprefs /.vs/ +SessionCache.ini diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index 2950ad7a..28e76d95 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -23,7 +23,7 @@ namespace MinecraftClient public const string Version = MCHighestVersion; public const string MCLowestVersion = "1.4.6"; - public const string MCHighestVersion = "1.12.2"; + public const string MCHighestVersion = "1.13"; public static readonly string BuildInfo = null; private static Thread offlinePrompt = null; @@ -289,7 +289,7 @@ namespace MinecraftClient /// /// Disconnect the current client from the server and restart it /// - /// Optional delay, in seconds, before restarting + /// Optional delay, in seconds, before restarting public static void Restart(int delaySeconds = 0) { new Thread(new ThreadStart(delegate diff --git a/MinecraftClient/Protocol/ChatParser.cs b/MinecraftClient/Protocol/ChatParser.cs index 60d78f66..7fa68cbd 100644 --- a/MinecraftClient/Protocol/ChatParser.cs +++ b/MinecraftClient/Protocol/ChatParser.cs @@ -96,10 +96,20 @@ namespace MinecraftClient.Protocol try { string assets_index = DownloadString(Settings.TranslationsFile_Website_Index); - string[] tmp = assets_index.Split(new string[] { "minecraft/lang/" + Settings.Language + ".lang" }, StringSplitOptions.None); + string[] tmp = assets_index.Split(new string[] { "minecraft/lang/" + Settings.Language.ToLower() + ".json" }, StringSplitOptions.None); tmp = tmp[1].Split(new string[] { "hash\": \"" }, StringSplitOptions.None); string hash = tmp[1].Split('"')[0]; //Translations file identifier on Mojang's servers - System.IO.File.WriteAllText(Language_File, DownloadString(Settings.TranslationsFile_Website_Download + '/' + hash.Substring(0, 2) + '/' + hash)); + string translation_file_location = Settings.TranslationsFile_Website_Download + '/' + hash.Substring(0, 2) + '/' + hash; + if (Settings.DebugMessages) + ConsoleIO.WriteLineFormatted("§8Performing request to " + translation_file_location); + + StringBuilder stringBuilder = new StringBuilder(); + foreach (KeyValuePair entry in Json.ParseJson(DownloadString(translation_file_location)).Properties) + { + stringBuilder.Append(entry.Key + "=" + entry.Value.StringValue + Environment.NewLine); + } + + System.IO.File.WriteAllText(Language_File, stringBuilder.ToString()); ConsoleIO.WriteLineFormatted("§8Done. File saved as '" + Language_File + '\''); } catch diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 329bca53..ab6260ff 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -25,9 +25,18 @@ namespace MinecraftClient.Protocol.Handlers private const int MC17w13aVersion = 318; private const int MC112pre5Version = 332; private const int MC17w31aVersion = 336; + private const int MC17w45aVersion = 343; + private const int MC17w46aVersion = 345; + private const int MC17w47aVersion = 346; + private const int MC18w01aVersion = 352; + private const int MC18w06aVersion = 357; + private const int MC113pre4Version = 386; + private const int MC113pre7Version = 389; + private const int MC113Version = 393; private int compression_treshold = 0; private bool autocomplete_received = false; + private int autocomplete_transaction_id = 0; private readonly List autocomplete_result = new List(); private bool login_phase = true; private bool encrypted = false; @@ -254,7 +263,7 @@ namespace MinecraftClient.Protocol.Handlers default: return PacketIncomingType.UnknownPacket; } } - else + else if (protocol < MC17w45aVersion) { switch (packetID) { @@ -277,6 +286,98 @@ namespace MinecraftClient.Protocol.Handlers default: return PacketIncomingType.UnknownPacket; } } + else if (protocol < MC17w46aVersion) + { + switch (packetID) + { + case 0x1F: return PacketIncomingType.KeepAlive; + case 0x23: return PacketIncomingType.JoinGame; + case 0x0E: return PacketIncomingType.ChatMessage; + case 0x35: return PacketIncomingType.Respawn; + case 0x2F: return PacketIncomingType.PlayerPositionAndLook; + case 0x21: return PacketIncomingType.ChunkData; + case 0x0F: return PacketIncomingType.MultiBlockChange; + case 0x0B: return PacketIncomingType.BlockChange; + //MapChunkBulk removed in 1.9 + case 0x1D: return PacketIncomingType.UnloadChunk; + case 0x2E: return PacketIncomingType.PlayerListUpdate; + //TabCompleteResult accidentely removed + case 0x18: return PacketIncomingType.PluginMessage; + case 0x1A: return PacketIncomingType.KickPacket; + //NetworkCompressionTreshold removed in 1.9 + case 0x34: return PacketIncomingType.ResourcePackSend; + default: return PacketIncomingType.UnknownPacket; + } + } + else if (protocol < MC18w01aVersion) + { + switch (packetID) + { + case 0x20: return PacketIncomingType.KeepAlive; + case 0x24: return PacketIncomingType.JoinGame; + case 0x0E: return PacketIncomingType.ChatMessage; + case 0x36: return PacketIncomingType.Respawn; + case 0x30: return PacketIncomingType.PlayerPositionAndLook; + case 0x21: return PacketIncomingType.ChunkData; + case 0x0F: return PacketIncomingType.MultiBlockChange; + case 0x0B: return PacketIncomingType.BlockChange; + //MapChunkBulk removed in 1.9 + case 0x1E: return PacketIncomingType.UnloadChunk; + case 0x2F: return PacketIncomingType.PlayerListUpdate; + case 0x10: return PacketIncomingType.TabCompleteResult; + case 0x19: return PacketIncomingType.PluginMessage; + case 0x1B: return PacketIncomingType.KickPacket; + //NetworkCompressionTreshold removed in 1.9 + case 0x35: return PacketIncomingType.ResourcePackSend; + default: return PacketIncomingType.UnknownPacket; + } + } + else if (protocol < MC113pre7Version) + { + switch (packetID) + { + case 0x20: return PacketIncomingType.KeepAlive; + case 0x24: return PacketIncomingType.JoinGame; + case 0x0E: return PacketIncomingType.ChatMessage; + case 0x37: return PacketIncomingType.Respawn; + case 0x31: return PacketIncomingType.PlayerPositionAndLook; + case 0x21: return PacketIncomingType.ChunkData; + case 0x0F: return PacketIncomingType.MultiBlockChange; + case 0x0B: return PacketIncomingType.BlockChange; + //MapChunkBulk removed in 1.9 + case 0x1E: return PacketIncomingType.UnloadChunk; + case 0x2F: return PacketIncomingType.PlayerListUpdate; + case 0x10: return PacketIncomingType.TabCompleteResult; + case 0x19: return PacketIncomingType.PluginMessage; + case 0x1B: return PacketIncomingType.KickPacket; + //NetworkCompressionTreshold removed in 1.9 + case 0x36: return PacketIncomingType.ResourcePackSend; + default: return PacketIncomingType.UnknownPacket; + } + } + else + { + switch (packetID) + { + case 0x21: return PacketIncomingType.KeepAlive; + case 0x25: return PacketIncomingType.JoinGame; + case 0x0E: return PacketIncomingType.ChatMessage; + case 0x38: return PacketIncomingType.Respawn; + case 0x32: return PacketIncomingType.PlayerPositionAndLook; + case 0x22: return PacketIncomingType.ChunkData; + case 0x0F: return PacketIncomingType.MultiBlockChange; + case 0x0B: return PacketIncomingType.BlockChange; + //MapChunkBulk removed in 1.9 + case 0x1F: return PacketIncomingType.UnloadChunk; + case 0x30: return PacketIncomingType.PlayerListUpdate; + case 0x10: return PacketIncomingType.TabCompleteResult; + case 0x19: return PacketIncomingType.PluginMessage; + case 0x1B: return PacketIncomingType.KickPacket; + //NetworkCompressionTreshold removed in 1.9 + case 0x37: return PacketIncomingType.ResourcePackSend; + default: return PacketIncomingType.UnknownPacket; + } + } } /// @@ -368,7 +469,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.TeleportConfirm: return 0x00; } } - else + else if (protocol < MC17w45aVersion) { switch (packet) { @@ -384,6 +485,70 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.TeleportConfirm: return 0x00; } } + else if (protocol < MC17w46aVersion) + { + switch (packet) + { + case PacketOutgoingType.KeepAlive: return 0x0A; + case PacketOutgoingType.ResourcePackStatus: return 0x17; + case PacketOutgoingType.ChatMessage: return 0x01; + case PacketOutgoingType.ClientStatus: return 0x02; + case PacketOutgoingType.ClientSettings: return 0x03; + case PacketOutgoingType.PluginMessage: return 0x08; + case PacketOutgoingType.TabComplete: throw new InvalidOperationException("TabComplete was accidentely removed in protocol " + protocol + ". Please use a more recent version."); + case PacketOutgoingType.PlayerPosition: return 0x0C; + case PacketOutgoingType.PlayerPositionAndLook: return 0x0D; + case PacketOutgoingType.TeleportConfirm: return 0x00; + } + } + else if (protocol < MC113pre4Version) + { + switch (packet) + { + case PacketOutgoingType.KeepAlive: return 0x0B; + case PacketOutgoingType.ResourcePackStatus: return 0x18; + case PacketOutgoingType.ChatMessage: return 0x01; + case PacketOutgoingType.ClientStatus: return 0x02; + case PacketOutgoingType.ClientSettings: return 0x03; + case PacketOutgoingType.PluginMessage: return 0x09; + case PacketOutgoingType.TabComplete: return 0x04; + case PacketOutgoingType.PlayerPosition: return 0x0D; + case PacketOutgoingType.PlayerPositionAndLook: return 0x0E; + case PacketOutgoingType.TeleportConfirm: return 0x00; + } + } + else if (protocol < MC113pre7Version) + { + switch (packet) + { + case PacketOutgoingType.KeepAlive: return 0x0C; + case PacketOutgoingType.ResourcePackStatus: return 0x1B; + case PacketOutgoingType.ChatMessage: return 0x01; + case PacketOutgoingType.ClientStatus: return 0x02; + case PacketOutgoingType.ClientSettings: return 0x03; + case PacketOutgoingType.PluginMessage: return 0x09; + case PacketOutgoingType.TabComplete: return 0x04; + case PacketOutgoingType.PlayerPosition: return 0x0E; + case PacketOutgoingType.PlayerPositionAndLook: return 0x0F; + case PacketOutgoingType.TeleportConfirm: return 0x00; + } + } + else + { + switch (packet) + { + case PacketOutgoingType.KeepAlive: return 0x0E; + case PacketOutgoingType.ResourcePackStatus: return 0x1D; + case PacketOutgoingType.ChatMessage: return 0x02; + case PacketOutgoingType.ClientStatus: return 0x03; + case PacketOutgoingType.ClientSettings: return 0x04; + case PacketOutgoingType.PluginMessage: return 0x0A; + case PacketOutgoingType.TabComplete: return 0x05; + case PacketOutgoingType.PlayerPosition: return 0x10; + case PacketOutgoingType.PlayerPositionAndLook: return 0x11; + case PacketOutgoingType.TeleportConfirm: return 0x00; + } + } throw new System.ComponentModel.InvalidEnumArgumentException("Unknown PacketOutgoingType (protocol=" + protocol + ")", (int)packet, typeof(PacketOutgoingType)); } @@ -652,11 +817,31 @@ namespace MinecraftClient.Protocol.Handlers } break; case PacketIncomingType.TabCompleteResult: + if (protocolversion >= MC17w46aVersion) + { + autocomplete_transaction_id = readNextVarInt(packetData); + } + + if (protocolversion >= MC17w47aVersion) + { + // Start of the text to replace - currently unused + readNextVarInt(packetData); + } + + if (protocolversion >= MC18w06aVersion) + { + // Length of the text to replace - currently unused + readNextVarInt(packetData); + } + int autocomplete_count = readNextVarInt(packetData); autocomplete_result.Clear(); for (int i = 0; i < autocomplete_count; i++) autocomplete_result.Add(readNextString(packetData)); autocomplete_received = true; + + // In protocolversion >= MC18w06aVersion there is additional data if the match is a tooltip + // Don't worry about skipping remaining data since there is no useful for us (yet) break; case PacketIncomingType.PluginMessage: String channel = readNextString(packetData); @@ -1313,7 +1498,7 @@ namespace MinecraftClient.Protocol.Handlers /// /// Get byte array representing a double /// - /// Array to process + /// Double to process /// Array ready to send private byte[] getDouble(double number) { @@ -1341,9 +1526,9 @@ namespace MinecraftClient.Protocol.Handlers /// /// Get a byte array from the given string for sending over the network, with length information prepended. /// - /// String to process + /// String to process /// Array ready to send - private byte[] getString(string text) + private static byte[] getString(string text) { byte[] bytes = Encoding.UTF8.GetBytes(text); @@ -1456,17 +1641,14 @@ namespace MinecraftClient.Protocol.Handlers public bool Login() { byte[] protocol_version = getVarInt(protocolversion); - byte[] server_adress_val = Encoding.UTF8.GetBytes(handler.GetServerHost() + (forgeInfo != null ? "\0FML\0" : "")); - byte[] server_adress_len = getVarInt(server_adress_val.Length); + string server_address = handler.GetServerHost() + (forgeInfo != null ? "\0FML\0" : ""); byte[] server_port = BitConverter.GetBytes((ushort)handler.GetServerPort()); Array.Reverse(server_port); byte[] next_state = getVarInt(2); - byte[] handshake_packet = concatBytes(protocol_version, server_adress_len, server_adress_val, server_port, next_state); + byte[] handshake_packet = concatBytes(protocol_version, getString(server_address), server_port, next_state); SendPacket(0x00, handshake_packet); - byte[] username_val = Encoding.UTF8.GetBytes(handler.GetUsername()); - byte[] username_len = getVarInt(username_val.Length); - byte[] login_packet = concatBytes(username_len, username_val); + byte[] login_packet = getString(handler.GetUsername()); SendPacket(0x00, login_packet); @@ -1621,9 +1803,7 @@ namespace MinecraftClient.Protocol.Handlers return true; try { - byte[] message_val = Encoding.UTF8.GetBytes(message); - byte[] message_len = getVarInt(message_val.Length); - byte[] message_packet = concatBytes(message_len, message_val); + byte[] message_packet = getString(message); SendPacket(PacketOutgoingType.ChatMessage, message_packet); return true; } @@ -1634,7 +1814,6 @@ namespace MinecraftClient.Protocol.Handlers /// /// Send a respawn packet to the server /// - /// Message /// True if properly sent public bool SendRespawnPacket() { @@ -1655,8 +1834,16 @@ namespace MinecraftClient.Protocol.Handlers { if (String.IsNullOrEmpty(brandInfo)) return false; - - return SendPluginChannelPacket("MC|Brand", getString(brandInfo)); + // Plugin channels were significantly changed between Minecraft 1.12 and 1.13 + // https://wiki.vg/index.php?title=Pre-release_protocol&oldid=14132#Plugin_Channels + if (protocolversion >= MC113Version) + { + return SendPluginChannelPacket("minecraft:brand", getString(brandInfo)); + } + else + { + return SendPluginChannelPacket("MC|Brand", getString(brandInfo)); + } } /// @@ -1789,15 +1976,35 @@ namespace MinecraftClient.Protocol.Handlers if (String.IsNullOrEmpty(BehindCursor)) return new string[] { }; - byte[] tocomplete_val = Encoding.UTF8.GetBytes(BehindCursor); - byte[] tocomplete_len = getVarInt(tocomplete_val.Length); + byte[] transaction_id = getVarInt(autocomplete_transaction_id); byte[] assume_command = new byte[] { 0x00 }; byte[] has_position = new byte[] { 0x00 }; - byte[] tabcomplete_packet = protocolversion >= MC18Version - ? protocolversion >= MC19Version - ? concatBytes(tocomplete_len, tocomplete_val, assume_command, has_position) - : concatBytes(tocomplete_len, tocomplete_val, has_position) - : concatBytes(tocomplete_len, tocomplete_val); + + byte[] tabcomplete_packet = new byte[] { }; + + if (protocolversion >= MC18Version) + { + if (protocolversion >= MC17w46aVersion) + { + tabcomplete_packet = concatBytes(tabcomplete_packet, transaction_id); + tabcomplete_packet = concatBytes(tabcomplete_packet, getString(BehindCursor)); + } + else + { + tabcomplete_packet = concatBytes(tabcomplete_packet, getString(BehindCursor)); + + if (protocolversion >= MC19Version) + { + tabcomplete_packet = concatBytes(tabcomplete_packet, assume_command); + } + + tabcomplete_packet = concatBytes(tabcomplete_packet, has_position); + } + } + else + { + tabcomplete_packet = concatBytes(getString(BehindCursor)); + } autocomplete_received = false; autocomplete_result.Clear(); @@ -1823,11 +2030,9 @@ namespace MinecraftClient.Protocol.Handlers byte[] packet_id = getVarInt(0); byte[] protocol_version = getVarInt(-1); - byte[] server_adress_val = Encoding.UTF8.GetBytes(host); - byte[] server_adress_len = getVarInt(server_adress_val.Length); byte[] server_port = BitConverter.GetBytes((ushort)port); Array.Reverse(server_port); byte[] next_state = getVarInt(1); - byte[] packet = concatBytes(packet_id, protocol_version, server_adress_len, server_adress_val, server_port, next_state); + byte[] packet = concatBytes(packet_id, protocol_version, getString(host), server_port, next_state); byte[] tosend = concatBytes(getVarInt(packet.Length), packet); tcp.Client.Send(tosend, SocketFlags.None); diff --git a/MinecraftClient/Protocol/ProtocolHandler.cs b/MinecraftClient/Protocol/ProtocolHandler.cs index b6857376..207027d9 100644 --- a/MinecraftClient/Protocol/ProtocolHandler.cs +++ b/MinecraftClient/Protocol/ProtocolHandler.cs @@ -106,7 +106,7 @@ namespace MinecraftClient.Protocol int[] supportedVersions_Protocol16 = { 51, 60, 61, 72, 73, 74, 78 }; if (Array.IndexOf(supportedVersions_Protocol16, ProtocolVersion) > -1) return new Protocol16Handler(Client, ProtocolVersion, Handler); - int[] supportedVersions_Protocol18 = { 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340 }; + int[] supportedVersions_Protocol18 = { 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393 }; if (Array.IndexOf(supportedVersions_Protocol18, ProtocolVersion) > -1) return new Protocol18Handler(Client, ProtocolVersion, Handler, forgeInfo); throw new NotSupportedException("The protocol version no." + ProtocolVersion + " is not supported."); @@ -189,6 +189,8 @@ namespace MinecraftClient.Protocol return 338; case "1.12.2": return 340; + case "1.13": + return 393; default: return 0; } diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index f066f436..31715970 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -73,7 +73,7 @@ namespace MinecraftClient //Other Settings public static string TranslationsFile_FromMCDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\.minecraft\assets\objects\ed\eda1518b15c711cf6e75d99003bd87753f67fac4"; //MC 1.10 en_GB.lang - public static string TranslationsFile_Website_Index = "https://s3.amazonaws.com/Minecraft.Download/indexes/1.10.json"; + public static string TranslationsFile_Website_Index = "https://s3.amazonaws.com/Minecraft.Download/indexes/1.13.json"; public static string TranslationsFile_Website_Download = "http://resources.download.minecraft.net"; public static TimeSpan splitMessageDelay = TimeSpan.FromSeconds(2); public static List Bots_Owners = new List();