diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index 402046e4..db950515 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -10,7 +10,7 @@ using MinecraftClient.Protocol.Handlers.Forge; namespace MinecraftClient { /// - /// Minecraft Console Client by ORelio (c) 2012-2014. + /// Minecraft Console Client by ORelio & Contributors (c) 2012-2016. /// Allows to connect to any Minecraft server, send and receive text, automated scripts. /// This source code is released under the CDDL 1.0 License. /// @@ -20,9 +20,9 @@ namespace MinecraftClient private static McTcpClient Client; public static string[] startupargs; - public const string Version = "1.8.2"; + public const string Version = "1.9.0 BETA"; public const string MCLowestVersion = "1.4.6"; - public const string MCHighestVersion = "1.8.8"; + public const string MCHighestVersion = "1.9.0"; private static Thread offlinePrompt = null; private static bool useMcVersionOnce = false; diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index 905ee97f..1a080aa9 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -34,6 +34,9 @@ namespace MinecraftClient.Protocol.Handlers this.c = Client; this.protocolversion = ProtocolVersion; this.handler = Handler; + + if (Settings.TerrainAndMovements) + ConsoleIO.WriteLineFormatted("§8Terrain & Movements currently not handled for that MC version."); } private Protocol16Handler(TcpClient Client) diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index bd8af932..af04a0df 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -13,12 +13,13 @@ using MinecraftClient.Mapping; namespace MinecraftClient.Protocol.Handlers { /// - /// Implementation for Minecraft 1.7.X and 1.8.X Protocols + /// Implementation for Minecraft 1.7.X, 1.8.X, 1.9.X Protocols /// class Protocol18Handler : IMinecraftCom { private const int MC18Version = 47; + private const int MC19Version = 107; private int compression_treshold = 0; private bool autocomplete_received = false; @@ -44,6 +45,9 @@ namespace MinecraftClient.Protocol.Handlers this.protocolversion = ProtocolVersion; this.handler = Handler; this.forgeInfo = ForgeInfo; + + if (Settings.TerrainAndMovements && protocolversion > MC18Version) + ConsoleIO.WriteLineFormatted("§8Terrain & Movements currently not handled for that MC version."); } private Protocol18Handler(TcpClient Client) @@ -125,6 +129,85 @@ namespace MinecraftClient.Protocol.Handlers packetID = readNextVarInt(packetData); //Packet ID } + /// + /// Abstract incoming packet numbering + /// + + private enum PacketIncomingType + { + KeepAlive, + JoinGame, + ChatMessage, + PlayerPositionAndLook, + ChunkData, + MultiBlockChange, + BlockChange, + MapChunkBulk, + UnloadChunk, + PlayerListUpdate, + TabCompleteResult, + PluginMessage, + KickPacket, + NetworkCompressionTreshold, + ResourcePackSend, + UnknownPacket + } + + /// + /// Get abstract numbering ov the specified packet ID + /// + /// Packet ID + /// Protocol version + /// Abstract numbering + + private PacketIncomingType getPacketIncomingType(int packetID, int protocol) + { + if (protocol < MC19Version) + { + switch (packetID) + { + case 0x00: return PacketIncomingType.KeepAlive; + case 0x01: return PacketIncomingType.JoinGame; + case 0x02: return PacketIncomingType.ChatMessage; + case 0x08: return PacketIncomingType.PlayerPositionAndLook; + case 0x21: return PacketIncomingType.ChunkData; + case 0x22: return PacketIncomingType.MultiBlockChange; + case 0x23: return PacketIncomingType.BlockChange; + case 0x26: return PacketIncomingType.MapChunkBulk; + //UnloadChunk does not exists prior to 1.9 + case 0x38: return PacketIncomingType.PlayerListUpdate; + case 0x3A: return PacketIncomingType.TabCompleteResult; + case 0x3F: return PacketIncomingType.PluginMessage; + case 0x40: return PacketIncomingType.KickPacket; + case 0x46: return PacketIncomingType.NetworkCompressionTreshold; + case 0x48: 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 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 0x32: return PacketIncomingType.ResourcePackSend; + default: return PacketIncomingType.UnknownPacket; + } + } + } + /// /// Handle the given packet /// @@ -148,15 +231,15 @@ namespace MinecraftClient.Protocol.Handlers } // Regular in-game packets - switch (packetID) + switch (getPacketIncomingType(packetID, protocolversion)) { - case 0x00: //Keep-Alive - SendPacket(0x00, packetData); + case PacketIncomingType.KeepAlive: + SendPacket(protocolversion >= MC19Version ? 0x0B : 0x00, packetData); break; - case 0x01: //Join game + case PacketIncomingType.JoinGame: handler.OnGameJoined(); break; - case 0x02: //Chat message + case PacketIncomingType.ChatMessage: string message = readNextString(packetData); try { @@ -169,7 +252,7 @@ namespace MinecraftClient.Protocol.Handlers catch (ArgumentOutOfRangeException) { /* No message type */ } handler.OnTextReceived(ChatParser.ParseText(message)); break; - case 0x08: //Player Position and Look + case PacketIncomingType.PlayerPositionAndLook: if (Settings.TerrainAndMovements) { double x = readNextDouble(packetData); @@ -184,20 +267,23 @@ namespace MinecraftClient.Protocol.Handlers location.Z = (locMask & 1 << 2) != 0 ? location.Z + z : z; handler.UpdateLocation(location); + + if (protocolversion >= MC19Version) + readNextVarInt(packetData); } break; - case 0x21: //Chunk Data + case PacketIncomingType.ChunkData: if (Settings.TerrainAndMovements) { int chunkX = readNextInt(packetData); int chunkZ = readNextInt(packetData); bool chunksContinuous = readNextBool(packetData); - ushort chunkMask = readNextUShort(packetData); + ushort chunkMask = protocolversion >= MC19Version ? (ushort)readNextVarInt(packetData) : readNextUShort(packetData); int dataSize = readNextVarInt(packetData); ProcessChunkColumnData(chunkX, chunkZ, chunkMask, false, chunksContinuous, packetData); } break; - case 0x22: //Multi Block Change + case PacketIncomingType.MultiBlockChange: if (Settings.TerrainAndMovements) { int chunkX = readNextInt(packetData); @@ -214,12 +300,12 @@ namespace MinecraftClient.Protocol.Handlers } } break; - case 0x23: //Block Change + case PacketIncomingType.BlockChange: if (Settings.TerrainAndMovements) handler.GetWorld().SetBlock(Location.FromLong(readNextULong(packetData)), new Block((ushort)readNextVarInt(packetData))); break; - case 0x26: //Map Chunk Bulk - if (Settings.TerrainAndMovements) + case PacketIncomingType.MapChunkBulk: + if (protocolversion < MC19Version && Settings.TerrainAndMovements) { bool hasSkyLight = readNextBool(packetData); int chunkCount = readNextVarInt(packetData); @@ -240,7 +326,15 @@ namespace MinecraftClient.Protocol.Handlers ProcessChunkColumnData(chunkXs[chunkColumnNo], chunkZs[chunkColumnNo], chunkMasks[chunkColumnNo], hasSkyLight, true, packetData); } break; - case 0x38: //Player List update + case PacketIncomingType.UnloadChunk: + if (protocolversion >= MC19Version && Settings.TerrainAndMovements) + { + int chunkX = readNextInt(packetData); + int chunkZ = readNextInt(packetData); + handler.GetWorld()[chunkX, chunkZ] = null; + } + break; + case PacketIncomingType.PlayerListUpdate: if (protocolversion >= MC18Version) { int action = readNextVarInt(packetData); @@ -274,7 +368,7 @@ namespace MinecraftClient.Protocol.Handlers else handler.OnPlayerLeave(FakeUUID); } break; - case 0x3A: //Tab-Complete Result + case PacketIncomingType.TabCompleteResult: int autocomplete_count = readNextVarInt(packetData); string tab_list = ""; for (int i = 0; i < autocomplete_count; i++) @@ -288,7 +382,7 @@ namespace MinecraftClient.Protocol.Handlers if (tab_list.Length > 0) ConsoleIO.WriteLineFormatted("§8" + tab_list, false); break; - case 0x3F: //Plugin message. + case PacketIncomingType.PluginMessage: String channel = readNextString(packetData); if (protocolversion < MC18Version) { @@ -308,6 +402,7 @@ namespace MinecraftClient.Protocol.Handlers // The remaining data in the array is the entire payload of the packet. handler.OnPluginChannelMessage(channel, packetData.ToArray()); + #region Forge Login if (forgeInfo != null && fmlHandshakeState != FMLHandshakeClientState.DONE) { if (channel == "FML|HS") @@ -432,20 +527,22 @@ namespace MinecraftClient.Protocol.Handlers } } } + #endregion + return false; - case 0x40: //Kick Packet + case PacketIncomingType.KickPacket: handler.OnConnectionLost(ChatBot.DisconnectReason.InGameKick, ChatParser.ParseText(readNextString(packetData))); return false; - case 0x46: //Network Compression Treshold Info - if (protocolversion >= MC18Version) + case PacketIncomingType.NetworkCompressionTreshold: + if (protocolversion >= MC18Version && protocolversion < MC19Version) compression_treshold = readNextVarInt(packetData); break; - case 0x48: //Resource Pack Send + case PacketIncomingType.ResourcePackSend: string url = readNextString(packetData); string hash = readNextString(packetData); //Send back "accepted" and "successfully loaded" responses for plugins making use of resource pack mandatory - SendPacket(0x19, concatBytes(getVarInt(hash.Length), Encoding.UTF8.GetBytes(hash), getVarInt(3))); - SendPacket(0x19, concatBytes(getVarInt(hash.Length), Encoding.UTF8.GetBytes(hash), getVarInt(0))); + SendPacket(protocolversion >= MC19Version ? 0x16 : 0x19, concatBytes(getVarInt(hash.Length), Encoding.UTF8.GetBytes(hash), getVarInt(3))); + SendPacket(protocolversion >= MC19Version ? 0x16 : 0x19, concatBytes(getVarInt(hash.Length), Encoding.UTF8.GetBytes(hash), getVarInt(0))); break; default: return false; //Ignored packet @@ -465,7 +562,7 @@ namespace MinecraftClient.Protocol.Handlers private void ProcessChunkColumnData(int chunkX, int chunkZ, ushort chunkMask, bool hasSkyLight, bool chunksContinuous, List cache) { - if (chunksContinuous && chunkMask == 0) + if (protocolversion >= MC19Version && chunksContinuous && chunkMask == 0) { //Unload the entire chunk column handler.GetWorld()[chunkX, chunkZ] = null; @@ -978,7 +1075,8 @@ namespace MinecraftClient.Protocol.Handlers ConsoleIO.WriteLineFormatted("§8Server is in offline mode."); login_phase = false; - if (forgeInfo != null) { + if (forgeInfo != null) + { // Do the forge handshake. if (!CompleteForgeHandshake()) { @@ -1099,7 +1197,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(0x01, message_packet); + SendPacket(protocolversion >= MC19Version ? 0x02 : 0x01, message_packet); return true; } catch (SocketException) { return false; } @@ -1116,7 +1214,7 @@ namespace MinecraftClient.Protocol.Handlers { try { - SendPacket(0x16, new byte[] { 0 }); + SendPacket(protocolversion >= MC19Version ? 0x03 : 0x16, new byte[] { 0 }); return true; } catch (SocketException) { return false; } @@ -1149,7 +1247,7 @@ namespace MinecraftClient.Protocol.Handlers { try { - SendPacket(0x04, concatBytes( + SendPacket(protocolversion >= MC19Version ? 0x0C : 0x04, concatBytes( getDouble(location.X), getDouble(location.Y), getDouble(location.Z), new byte[] { onGround ? (byte)1 : (byte)0 })); return true; @@ -1180,7 +1278,7 @@ namespace MinecraftClient.Protocol.Handlers } else { - SendPacket(0x17, concatBytes(getString(channel), data)); + SendPacket(protocolversion >= MC19Version ? 0x09 : 0x17, concatBytes(getString(channel), data)); } return true; @@ -1218,14 +1316,17 @@ namespace MinecraftClient.Protocol.Handlers byte[] tocomplete_val = Encoding.UTF8.GetBytes(BehindCursor); byte[] tocomplete_len = getVarInt(tocomplete_val.Length); + byte[] assume_command = new byte[] { 0x00 }; byte[] has_position = new byte[] { 0x00 }; byte[] tabcomplete_packet = protocolversion >= MC18Version - ? concatBytes(tocomplete_len, tocomplete_val, has_position) + ? protocolversion >= MC19Version + ? concatBytes(tocomplete_len, tocomplete_val, assume_command, has_position) + : concatBytes(tocomplete_len, tocomplete_val, has_position) : concatBytes(tocomplete_len, tocomplete_val); autocomplete_received = false; autocomplete_result = BehindCursor; - SendPacket(0x14, tabcomplete_packet); + SendPacket(protocolversion >= MC19Version ? 0x01 : 0x14, 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--; }