From 550beda7c4749cd99a0494cef6a92c3241610dee Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sat, 10 Jun 2017 09:05:06 -0700 Subject: [PATCH 1/2] Update to 1.12 This adds support for Minecraft 1.12's protocol, and also abstracts out outgoing packet IDs. I include packet IDs for some 1.12 snapshots, even though snapshot versions aren't supported, because I already had written the code (though in a far more messy variant) for my MC-106551 test script; while they won't be used right now, they may be useful if snapshots are ever formally supported in the future. --- MinecraftClient/Program.cs | 4 +- .../Protocol/Handlers/Protocol18.cs | 179 ++++++++++++++++-- MinecraftClient/Protocol/ProtocolHandler.cs | 5 +- 3 files changed, 168 insertions(+), 20 deletions(-) diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index 38f511b9..0d5fab39 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -20,9 +20,9 @@ namespace MinecraftClient private static McTcpClient Client; public static string[] startupargs; - public const string Version = "1.11.0 DEV"; + public const string Version = "1.12.0 DEV"; public const string MCLowestVersion = "1.4.6"; - public const string MCHighestVersion = "1.11.2"; + public const string MCHighestVersion = "1.12.0"; private static Thread offlinePrompt = null; private static bool useMcVersionOnce = false; diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index c64251e9..7a5fae16 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -22,6 +22,8 @@ namespace MinecraftClient.Protocol.Handlers private const int MC191Version = 108; private const int MC110Version = 210; private const int MC111Version = 315; + private const int MC17w13aVersion = 318; + private const int MC112pre5Version = 332; private int compression_treshold = 0; private bool autocomplete_received = false; @@ -152,7 +154,7 @@ namespace MinecraftClient.Protocol.Handlers } /// - /// Get abstract numbering ov the specified packet ID + /// Get abstract numbering of the specified packet ID /// /// Packet ID /// Protocol version @@ -182,7 +184,7 @@ namespace MinecraftClient.Protocol.Handlers default: return PacketIncomingType.UnknownPacket; } } - else + else if (protocol < MC17w13aVersion) { switch (packetID) { @@ -205,6 +207,140 @@ namespace MinecraftClient.Protocol.Handlers default: return PacketIncomingType.UnknownPacket; } } + else if (protocolversion < MC112pre5Version) + { + switch (packetID) + { + case 0x20: return PacketIncomingType.KeepAlive; + case 0x24: return PacketIncomingType.JoinGame; + case 0x10: return PacketIncomingType.ChatMessage; + case 0x35: return PacketIncomingType.Respawn; + case 0x2F: return PacketIncomingType.PlayerPositionAndLook; + case 0x21: return PacketIncomingType.ChunkData; + case 0x11: return PacketIncomingType.MultiBlockChange; + case 0x0C: return PacketIncomingType.BlockChange; + //MapChunkBulk removed in 1.9 + case 0x1E: return PacketIncomingType.UnloadChunk; + case 0x2E: return PacketIncomingType.PlayerListUpdate; + case 0x0F: return PacketIncomingType.TabCompleteResult; + case 0x19: return PacketIncomingType.PluginMessage; + case 0x1B: return PacketIncomingType.KickPacket; + //NetworkCompressionTreshold removed in 1.9 + case 0x34: return PacketIncomingType.ResourcePackSend; + default: return PacketIncomingType.UnknownPacket; + } + } + else + { + switch (packetID) + { + case 0x1F: return PacketIncomingType.KeepAlive; + case 0x23: return PacketIncomingType.JoinGame; + case 0x0F: return PacketIncomingType.ChatMessage; + case 0x34: return PacketIncomingType.Respawn; + case 0x2E: return PacketIncomingType.PlayerPositionAndLook; + case 0x20: return PacketIncomingType.ChunkData; + case 0x10: return PacketIncomingType.MultiBlockChange; + case 0x0B: return PacketIncomingType.BlockChange; + //MapChunkBulk removed in 1.9 + case 0x1D: return PacketIncomingType.UnloadChunk; + case 0x2D: return PacketIncomingType.PlayerListUpdate; + case 0x0E: return PacketIncomingType.TabCompleteResult; + case 0x18: return PacketIncomingType.PluginMessage; + case 0x1A: return PacketIncomingType.KickPacket; + //NetworkCompressionTreshold removed in 1.9 + case 0x33: return PacketIncomingType.ResourcePackSend; + default: return PacketIncomingType.UnknownPacket; + } + } + } + + /// + /// Abstract outgoing packet numbering + /// + private enum PacketOutgoingType + { + KeepAlive, + ResourcePackStatus, + ChatMessage, + ClientStatus, + ClientSettings, + PluginMessage, + TabComplete, + PlayerPosition, + PlayerPositionAndLook + } + + /// + /// Get packet ID of the specified outgoing packet + /// + /// Abstract packet numbering + /// Protocol version + /// Packet ID + private int getPacketOutgoingID(PacketOutgoingType packet, int protocol) + { + if (protocol < MC19Version) + { + switch (packet) + { + case PacketOutgoingType.KeepAlive: return 0x00; + case PacketOutgoingType.ResourcePackStatus: return 0x19; + case PacketOutgoingType.ChatMessage: return 0x01; + case PacketOutgoingType.ClientStatus: return 0x16; + case PacketOutgoingType.ClientSettings: return 0x15; + case PacketOutgoingType.PluginMessage: return 0x17; + case PacketOutgoingType.TabComplete: return 0x14; + case PacketOutgoingType.PlayerPosition: return 0x04; + case PacketOutgoingType.PlayerPositionAndLook: return 0x06; + } + } + else if (protocol < MC17w13aVersion) + { + switch (packet) + { + case PacketOutgoingType.KeepAlive: return 0x0B; + case PacketOutgoingType.ResourcePackStatus: return 0x16; + case PacketOutgoingType.ChatMessage: return 0x02; + case PacketOutgoingType.ClientStatus: return 0x03; + case PacketOutgoingType.ClientSettings: return 0x04; + case PacketOutgoingType.PluginMessage: return 0x09; + case PacketOutgoingType.TabComplete: return 0x01; + case PacketOutgoingType.PlayerPosition: return 0x0C; + case PacketOutgoingType.PlayerPositionAndLook: return 0x0D; + } + } + else if (protocolversion < MC112pre5Version) + { + switch (packet) + { + case PacketOutgoingType.KeepAlive: return 0x0C; + case PacketOutgoingType.ResourcePackStatus: return 0x17; + case PacketOutgoingType.ChatMessage: return 0x03; + case PacketOutgoingType.ClientStatus: return 0x04; + case PacketOutgoingType.ClientSettings: return 0x05; + case PacketOutgoingType.PluginMessage: return 0x0A; + case PacketOutgoingType.TabComplete: return 0x02; + case PacketOutgoingType.PlayerPosition: return 0x0D; + case PacketOutgoingType.PlayerPositionAndLook: return 0x0E; + } + } + else + { + switch (packet) + { + case PacketOutgoingType.KeepAlive: return 0x0C; + case PacketOutgoingType.ResourcePackStatus: return 0x17; + case PacketOutgoingType.ChatMessage: return 0x03; + case PacketOutgoingType.ClientStatus: return 0x04; + case PacketOutgoingType.ClientSettings: return 0x05; + case PacketOutgoingType.PluginMessage: return 0x0A; + case PacketOutgoingType.TabComplete: return 0x02; + case PacketOutgoingType.PlayerPosition: return 0x0E; + case PacketOutgoingType.PlayerPositionAndLook: return 0x0F; + } + } + + throw new System.ComponentModel.InvalidEnumArgumentException("Unknown PacketOutgoingType (protocol=" + protocol + ")", (int)packet, typeof(PacketOutgoingType)); } /// @@ -231,7 +367,7 @@ namespace MinecraftClient.Protocol.Handlers switch (getPacketIncomingType(packetID, protocolversion)) { case PacketIncomingType.KeepAlive: - SendPacket(protocolversion >= MC19Version ? 0x0B : 0x00, packetData); + SendPacket(PacketOutgoingType.KeepAlive, packetData); break; case PacketIncomingType.JoinGame: handler.OnGameJoined(); @@ -639,9 +775,8 @@ namespace MinecraftClient.Protocol.Handlers byte[] responseHeader = new byte[0]; if (protocolversion < MC110Version) //MC 1.10 does not include resource pack hash in responses responseHeader = concatBytes(getVarInt(hash.Length), Encoding.UTF8.GetBytes(hash)); - int packResponsePid = protocolversion >= MC19Version ? 0x16 : 0x19; //ID changed in 1.9 - SendPacket(packResponsePid, concatBytes(responseHeader, getVarInt(3))); //Accepted pack - SendPacket(packResponsePid, concatBytes(responseHeader, getVarInt(0))); //Successfully loaded + SendPacket(PacketOutgoingType.ResourcePackStatus, concatBytes(responseHeader, getVarInt(3))); //Accepted pack + SendPacket(PacketOutgoingType.ResourcePackStatus, concatBytes(responseHeader, getVarInt(0))); //Successfully loaded break; default: return false; //Ignored packet @@ -1220,7 +1355,17 @@ namespace MinecraftClient.Protocol.Handlers } /// - /// Send a packet to the server, compression and encryption will be handled automatically + /// Send a packet to the server. Packet ID, compression, and encryption will be handled automatically. + /// + /// packet type + /// packet Data + private void SendPacket(PacketOutgoingType packet, IEnumerable packetData) + { + SendPacket(getPacketOutgoingID(packet, protocolversion), packetData); + } + + /// + /// Send a packet to the server. Compression and encryption will be handled automatically. /// /// packet ID /// packet Data @@ -1436,7 +1581,7 @@ namespace MinecraftClient.Protocol.Handlers byte[] message_val = Encoding.UTF8.GetBytes(message); byte[] message_len = getVarInt(message_val.Length); byte[] message_packet = concatBytes(message_len, message_val); - SendPacket(protocolversion >= MC19Version ? 0x02 : 0x01, message_packet); + SendPacket(PacketOutgoingType.ChatMessage, message_packet); return true; } catch (SocketException) { return false; } @@ -1452,7 +1597,7 @@ namespace MinecraftClient.Protocol.Handlers { try { - SendPacket(protocolversion >= MC19Version ? 0x03 : 0x16, new byte[] { 0 }); + SendPacket(PacketOutgoingType.ClientStatus, new byte[] { 0 }); return true; } catch (SocketException) { return false; } @@ -1501,7 +1646,7 @@ namespace MinecraftClient.Protocol.Handlers else fields.Add(skinParts); if (protocolversion >= MC19Version) fields.AddRange(getVarInt(mainHand)); - SendPacket(protocolversion >= MC19Version ? 0x04 : 0x15, fields); + SendPacket(PacketOutgoingType.ClientSettings, fields); } catch (SocketException) { } return false; @@ -1518,20 +1663,20 @@ namespace MinecraftClient.Protocol.Handlers { if (Settings.TerrainAndMovements) { - int packetId; + PacketOutgoingType packetType; if (yawpitch != null && yawpitch.Length == 8) { - packetId = protocolversion >= MC19Version ? 0x0D : 0x06; + packetType = PacketOutgoingType.PlayerPositionAndLook; } else { yawpitch = new byte[0]; - packetId = protocolversion >= MC19Version ? 0x0C : 0x04; + packetType = PacketOutgoingType.PlayerPosition; } try { - SendPacket(packetId, concatBytes( + SendPacket(packetType, concatBytes( getDouble(location.X), getDouble(location.Y), protocolversion < MC18Version @@ -1563,11 +1708,11 @@ namespace MinecraftClient.Protocol.Handlers byte[] length = BitConverter.GetBytes((short)data.Length); Array.Reverse(length); - SendPacket(0x17, concatBytes(getString(channel), length, data)); + SendPacket(PacketOutgoingType.PluginMessage, concatBytes(getString(channel), length, data)); } else { - SendPacket(protocolversion >= MC19Version ? 0x09 : 0x17, concatBytes(getString(channel), data)); + SendPacket(PacketOutgoingType.PluginMessage, concatBytes(getString(channel), data)); } return true; @@ -1614,7 +1759,7 @@ namespace MinecraftClient.Protocol.Handlers autocomplete_received = false; autocomplete_result.Clear(); autocomplete_result.Add(BehindCursor); - SendPacket(protocolversion >= MC19Version ? 0x01 : 0x14, tabcomplete_packet); + SendPacket(PacketOutgoingType.TabComplete, tabcomplete_packet); int wait_left = 50; //do not wait more than 5 seconds (50 * 100 ms) while (wait_left > 0 && !autocomplete_received) { System.Threading.Thread.Sleep(100); wait_left--; } diff --git a/MinecraftClient/Protocol/ProtocolHandler.cs b/MinecraftClient/Protocol/ProtocolHandler.cs index 73a3a603..0a7556fc 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 }; + int[] supportedVersions_Protocol18 = { 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335 }; 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."); @@ -182,6 +182,9 @@ namespace MinecraftClient.Protocol case "1.11.1": case "1.11.2": return 316; + case "1.12": + case "1.12.0": + return 335; default: return 0; } From a4cd442904b7c52e037dfe5433081a94ebd77bd5 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sat, 10 Jun 2017 09:28:10 -0700 Subject: [PATCH 2/2] Fix README markdown The README had markdown headers that were no longer valid (plus a few other cases of wierdly formatted markdown). I've fixed this. I also added a CI banner and link, so that the latest development build can be accessed directly. --- README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e3d4a3e6..aeef1a76 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,29 @@ Minecraft Console Client ======================== -Minecraft Console Client is a lightweight app allowing to connect to any minecraft server, +[![Appveyor build status](https://ci.appveyor.com/api/projects/status/github/ORelio/Minecraft-Console-Client?branch=Indev)](https://ci.appveyor.com/project/ORelio/minecraft-console-client) + +Minecraft Console Client is a lightweight app allowing to connect to any Minecraft server, send commands and receive text messages in a fast and easy way without having to open the main Minecraft game. It also provides various automation for administration and other purposes. -##How to use +## How to use Downloads, help and more info available on the [Minecraft Forum thread](http://www.minecraftforum.net/topic/1314800-/)'s first post.
Alternatively, you can take a look at the [README](https://github.com/ORelio/Minecraft-Console-Client/blob/master/MinecraftClient/config/README.txt) file from the latest stable binary release. -##How to contribute +## How to contribute -If you'd like to contribute to Minecraft Console Client, great! But please fork the *indev* branch to do so, as the *master* branch is the stable branch, corresponding to the last binary release, which does not contains the latest fixes and is available for forking into your own projects. Using *indev* branch, just submit a pull request :) +If you'd like to contribute to Minecraft Console Client, great! But please fork the *Indev* branch to do so, as the *master* branch is the stable branch, corresponding to the last binary release, which does not contains the latest fixes and is available for forking into your own projects. Using *Indev* branch, just submit a pull request :) -##License +## License -Unless specifically stated, the code is from me or contributors, and available under CDDL-1.0.
-Else, the license and original author are mentioned in source file headers.
+Unless specifically stated, the code is from me or contributors, and available under CDDL-1.0. +Else, the license and original author are mentioned in source file headers. The main terms of the CDDL-1.0 license are basically the following: - You may use the licensed code in whole or in part in any program you desire, regardless of the license of the program as a whole (or rather, as excluding the code you are borrowing). The program itself may be open or closed source, free or commercial. - However, in all cases, any modifications, improvements, or additions to the CDDL code (any code that is referenced in direct modifications to the CDDL code is considered an addition to the CDDL code, and so is bound by this requirement; e.g. a modification of a math function to use a fast lookup table makes that table itself an addition to the CDDL code, regardless of whether it's in a source code file of its own) must be made publicly and freely available in source, under the CDDL license itself. -- In any program (source or binary) that uses CDDL code, recognition must be given to the source (either project or author) of the CDDL code. As well, modifications to the CDDL code (which must be distributed as source) may not remove notices indicating the ancestry of the code.

-More info at http://qstuff.blogspot.fr/2007/04/why-cddl.html
+- In any program (source or binary) that uses CDDL code, recognition must be given to the source (either project or author) of the CDDL code. As well, modifications to the CDDL code (which must be distributed as source) may not remove notices indicating the ancestry of the code. + +More info at http://qstuff.blogspot.fr/2007/04/why-cddl.html Full license at http://opensource.org/licenses/CDDL-1.0