From 61ce935c63f15debe9cd7d4110b4e6878d737812 Mon Sep 17 00:00:00 2001 From: ORelio Date: Fri, 26 Aug 2016 12:19:25 +0200 Subject: [PATCH] Add support for Minecraft Settings - Add Minecraft vanilla settings from Settings screen - These settings are sent to server when joining - Allows to customize skin layers shown to other players - Most other settings are ignored by servers - Update language file from 1.9 to 1.10 version - Minor aesthetic changes in INI file comments Suggestion by TNT-UP in issue #161 and Splodger1 in MC Forum. --- MinecraftClient/McTcpClient.cs | 9 + .../Protocol/Handlers/Protocol16.cs | 5 + .../Protocol/Handlers/Protocol18.cs | 36 ++++ MinecraftClient/Protocol/IMinecraftCom.cs | 20 ++- MinecraftClient/Settings.cs | 160 ++++++++++++++---- 5 files changed, 192 insertions(+), 38 deletions(-) diff --git a/MinecraftClient/McTcpClient.cs b/MinecraftClient/McTcpClient.cs index 3951e1c7..ec56755f 100644 --- a/MinecraftClient/McTcpClient.cs +++ b/MinecraftClient/McTcpClient.cs @@ -370,6 +370,15 @@ namespace MinecraftClient { if (!String.IsNullOrWhiteSpace(Settings.BrandInfo)) handler.SendBrandInfo(Settings.BrandInfo.Trim()); + if (Settings.MCSettings_Enabled) + handler.SendClientSettings( + Settings.MCSettings_Locale, + Settings.MCSettings_RenderDistance, + Settings.MCSettings_Difficulty, + Settings.MCSettings_ChatMode, + Settings.MCSettings_ChatColors, + Settings.MCSettings_Skin_All, + Settings.MCSettings_MainHand); foreach (ChatBot bot in bots) bot.AfterGameJoined(); } diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index 77e21dfc..a31b7c38 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -626,6 +626,11 @@ namespace MinecraftClient.Protocol.Handlers return false; //Only supported since MC 1.7 } + public bool SendClientSettings(string language, byte viewDistance, byte difficulty, byte chatMode, bool chatColors, byte skinParts, byte mainHand) + { + return false; //Currently not implemented + } + public bool SendLocationUpdate(Location location, bool onGround) { return false; //Currently not implemented diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 6ce70dc0..24459d8e 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -1469,6 +1469,42 @@ namespace MinecraftClient.Protocol.Handlers return SendPluginChannelPacket("MC|Brand", getString(brandInfo)); } + /// + /// Inform the server of the client's Minecraft settings + /// + /// Client language eg en_US + /// View distance, in chunks + /// Game difficulty (client-side...) + /// Chat mode (allows muting yourself) + /// Show chat colors + /// Show skin layers + /// 1.9+ main hand + /// True if client settings were successfully sent + public bool SendClientSettings(string language, byte viewDistance, byte difficulty, byte chatMode, bool chatColors, byte skinParts, byte mainHand) + { + try + { + List fields = new List(); + fields.AddRange(getString(language)); + fields.Add(viewDistance); + fields.AddRange(protocolversion >= MC19Version + ? getVarInt(chatMode) + : new byte[] { chatMode }); + fields.Add(chatColors ? (byte)1 : (byte)0); + if (protocolversion < MC18Version) + { + fields.Add(difficulty); + fields.Add((byte)(skinParts & 0x1)); //show cape + } + else fields.Add(skinParts); + if (protocolversion >= MC19Version) + fields.AddRange(getVarInt(mainHand)); + SendPacket(protocolversion >= MC19Version ? 0x04 : 0x15, fields); + } + catch (SocketException) { } + return false; + } + /// /// Send a location update to the server /// diff --git a/MinecraftClient/Protocol/IMinecraftCom.cs b/MinecraftClient/Protocol/IMinecraftCom.cs index 927258fd..1c305eae 100644 --- a/MinecraftClient/Protocol/IMinecraftCom.cs +++ b/MinecraftClient/Protocol/IMinecraftCom.cs @@ -20,14 +20,12 @@ namespace MinecraftClient.Protocol /// Start the login procedure once connected to the server /// /// True if login was successful - bool Login(); /// /// Disconnect from the server /// /// Reason - void Disconnect(); /// @@ -35,14 +33,12 @@ namespace MinecraftClient.Protocol /// /// Text to send /// True if successfully sent - bool SendChatMessage(string message); /// /// Allow to respawn after death /// /// True if packet successfully sent - bool SendRespawnPacket(); /// @@ -50,15 +46,26 @@ namespace MinecraftClient.Protocol /// /// Client string describing the client /// True if brand info was successfully sent - bool SendBrandInfo(string brandInfo); + /// + /// Inform the server of the client's Minecraft settings + /// + /// Client language eg en_US + /// View distance, in chunks + /// Game difficulty (client-side...) + /// Chat mode (allows muting yourself) + /// Show chat colors + /// Show skin layers + /// 1.9+ main hand + /// True if client settings were successfully sent + bool SendClientSettings(string language, byte viewDistance, byte difficulty, byte chatMode, bool chatColors, byte skinParts, byte mainHand); + /// /// Send a location update telling that we moved to that location /// /// The new location /// True if packet was successfully sent - bool SendLocationUpdate(Location location, bool onGround); /// @@ -68,7 +75,6 @@ namespace MinecraftClient.Protocol /// Channel to send packet on /// packet Data /// True if message was successfully sent - bool SendPluginChannelPacket(string channel, byte[] data); } } diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index 3f0b1ea1..1e7b4a7b 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -39,9 +39,40 @@ namespace MinecraftClient public static string ProxyUsername = ""; public static string ProxyPassword = ""; + //Minecraft Settings + public static bool MCSettings_Enabled = true; + public static string MCSettings_Locale = "en_US"; + public static byte MCSettings_Difficulty = 0; + public static byte MCSettings_RenderDistance = 8; + public static byte MCSettings_ChatMode = 0; + public static bool MCSettings_ChatColors = true; + public static byte MCSettings_MainHand = 0; + public static bool MCSettings_Skin_Hat = true; + public static bool MCSettings_Skin_Cape = true; + public static bool MCSettings_Skin_Jacket = false; + public static bool MCSettings_Skin_Sleeve_Left = false; + public static bool MCSettings_Skin_Sleeve_Right = false; + public static bool MCSettings_Skin_Pants_Left = false; + public static bool MCSettings_Skin_Pants_Right = false; + public static byte MCSettings_Skin_All + { + get + { + return (byte) ( + ((MCSettings_Skin_Cape ? 1 : 0) << 0) + | ((MCSettings_Skin_Jacket ? 1 : 0) << 1) + | ((MCSettings_Skin_Sleeve_Left ? 1 : 0) << 2) + | ((MCSettings_Skin_Sleeve_Right ? 1 : 0) << 3) + | ((MCSettings_Skin_Pants_Left ? 1 : 0) << 4) + | ((MCSettings_Skin_Pants_Right ? 1 : 0) << 5) + | ((MCSettings_Skin_Hat ? 1 : 0) << 6) + ); + } + } + //Other Settings - public static string TranslationsFile_FromMCDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\.minecraft\assets\objects\3d\3d7f778ea0a3baaf826ae75a094d77c46410902f"; //MC 1.9 en_GB.lang - public static string TranslationsFile_Website_Index = "https://s3.amazonaws.com/Minecraft.Download/indexes/1.9.json"; + 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_Download = "http://resources.download.minecraft.net"; public static TimeSpan splitMessageDelay = TimeSpan.FromSeconds(2); public static List Bots_Owners = new List(); @@ -119,7 +150,7 @@ namespace MinecraftClient private static readonly Dictionary> Accounts = new Dictionary>(); private static readonly Dictionary> Servers = new Dictionary>(); - private enum ParseMode { Default, Main, AppVars, Proxy, AntiAFK, Hangman, Alerts, ChatLog, AutoRelog, ScriptScheduler, RemoteControl, ChatFormat, AutoRespond }; + private enum ParseMode { Default, Main, AppVars, Proxy, MCSettings, AntiAFK, Hangman, Alerts, ChatLog, AutoRelog, ScriptScheduler, RemoteControl, ChatFormat, AutoRespond }; /// /// Load settings from the give INI file @@ -153,6 +184,7 @@ namespace MinecraftClient case "chatlog": pMode = ParseMode.ChatLog; break; case "hangman": pMode = ParseMode.Hangman; break; case "main": pMode = ParseMode.Main; break; + case "mcsettings": pMode = ParseMode.MCSettings; break; case "scriptscheduler": pMode = ParseMode.ScriptScheduler; break; case "remotecontrol": pMode = ParseMode.RemoteControl; break; case "proxy": pMode = ParseMode.Proxy; break; @@ -395,6 +427,56 @@ namespace MinecraftClient case "matchesfile": AutoRespond_Matches = argValue; break; } break; + + case ParseMode.MCSettings: + switch (argName.ToLower()) + { + case "enabled": MCSettings_Enabled = str2bool(argValue); break; + case "locale": MCSettings_Locale = argValue; break; + case "difficulty": + switch (argValue.ToLower()) + { + case "peaceful": MCSettings_Difficulty = 0; break; + case "easy": MCSettings_Difficulty = 1; break; + case "normal": MCSettings_Difficulty = 2; break; + case "difficult": MCSettings_Difficulty = 3; break; + } + break; + case "renderdistance": + MCSettings_RenderDistance = (byte)str2int(argValue); + switch (argValue.ToLower()) + { + case "tiny": MCSettings_RenderDistance = 2; break; + case "short": MCSettings_RenderDistance = 4; break; + case "medium": MCSettings_RenderDistance = 8; break; + case "far": MCSettings_RenderDistance = 16; break; + } + break; + case "chatmode": + switch (argValue.ToLower()) + { + case "enabled": MCSettings_ChatMode = 0; break; + case "commands": MCSettings_ChatMode = 1; break; + case "disabled": MCSettings_ChatMode = 2; break; + } + break; + case "chatcolors": MCSettings_ChatColors = str2bool(argValue); break; + case "skin_cape": MCSettings_Skin_Cape = str2bool(argValue); break; + case "skin_jacket": MCSettings_Skin_Jacket = str2bool(argValue); break; + case "skin_sleeve_left": MCSettings_Skin_Sleeve_Left = str2bool(argValue); break; + case "skin_sleeve_right": MCSettings_Skin_Sleeve_Right = str2bool(argValue); break; + case "skin_pants_left": MCSettings_Skin_Pants_Left = str2bool(argValue); break; + case "skin_pants_right": MCSettings_Skin_Pants_Right = str2bool(argValue); break; + case "skin_hat": MCSettings_Skin_Hat = str2bool(argValue); break; + case "main_hand": + switch (argValue.ToLower()) + { + case "left": MCSettings_MainHand = 0; break; + case "right": MCSettings_MainHand = 1; break; + } + break; + } + break; } } } @@ -412,35 +494,35 @@ namespace MinecraftClient public static void WriteDefaultSettings(string settingsfile) { - System.IO.File.WriteAllText(settingsfile, "#Minecraft Console Client v" + Program.Version + "\r\n" - + "#Startup Config File\r\n" + System.IO.File.WriteAllText(settingsfile, "# Minecraft Console Client v" + Program.Version + "\r\n" + + "# Startup Config File\r\n" + "\r\n" + "[Main]\r\n" + "\r\n" - + "#General settings\r\n" - + "#leave blank to prompt user on startup\r\n" - + "#Use \"-\" as password for offline mode\r\n" + + "# General settings\r\n" + + "# Leave blank to prompt user on startup\r\n" + + "# Use \"-\" as password for offline mode\r\n" + "\r\n" + "login=\r\n" + "password=\r\n" + "serverip=\r\n" + "\r\n" - + "#Advanced settings\r\n" + + "# Advanced settings\r\n" + "\r\n" + "language=en_GB\r\n" + "consoletitle=%username%@%serverip% - Minecraft Console Client\r\n" - + "internalcmdchar=slash #use 'none', 'slash' or 'backslash'\r\n" - + "splitmessagedelay=2 #seconds between each part of a long message\r\n" - + "botowners=Player1,Player2,Player3 #use name list or myfile.txt with one name per line\r\n" - + "botmessagedelay=2 #seconds to delay between message a bot makes to avoid accidental spam\r\n" - + "mcversion=auto #use 'auto' or '1.X.X' values\r\n" - + "brandinfo=mcc #use 'mcc','vanilla', or 'none'\r\n" - + "chatbotlogfile= #leave empty for no logfile\r\n" - + "privatemsgscmdname=tell #used by RemoteControl bot\r\n" - + "showsystemmessages=true #system messages for server ops\r\n" - + "showxpbarmessages=true #messages displayed above xp bar\r\n" - + "terrainandmovements=false #uses more ram, cpu, bandwidth\r\n" - + "sessioncache=memory #use 'none', 'memory' or 'disk'\r\n" + + "internalcmdchar=slash # Use 'none', 'slash' or 'backslash'\r\n" + + "splitmessagedelay=2 # Seconds between each part of a long message\r\n" + + "botowners=Player1,Player2,Player3 # Use name list or myfile.txt with one name per line\r\n" + + "botmessagedelay=2 # Seconds to delay between message a bot makes to avoid accidental spam\r\n" + + "mcversion=auto # Use 'auto' or '1.X.X' values\r\n" + + "brandinfo=mcc # Use 'mcc','vanilla', or 'none'\r\n" + + "chatbotlogfile= # Leave empty for no logfile\r\n" + + "privatemsgscmdname=tell # Used by RemoteControl bot\r\n" + + "showsystemmessages=true # System messages for server ops\r\n" + + "showxpbarmessages=true # Messages displayed above xp bar\r\n" + + "terrainandmovements=false # Uses more ram, cpu, bandwidth\r\n" + + "sessioncache=memory # Use 'none', 'memory' or 'disk' (disk is experimental)\r\n" + "accountlist=accounts.txt\r\n" + "serverlist=servers.txt\r\n" + "playerheadicon=true\r\n" @@ -450,24 +532,40 @@ namespace MinecraftClient + "timestamps=false\r\n" + "\r\n" + "[AppVars]\r\n" - + "#yourvar=yourvalue\r\n" - + "#can be used in some other fields as %yourvar%\r\n" - + "#%username% and %serverip% are reserved variables.\r\n" + + "# yourvar=yourvalue\r\n" + + "# can be used in some other fields as %yourvar%\r\n" + + "# %username% and %serverip% are reserved variables.\r\n" + "\r\n" + "[Proxy]\r\n" - + "enabled=false #use 'false', 'true', or 'login' for login only\r\n" - + "type=HTTP #Supported types: HTTP, SOCKS4, SOCKS4a, SOCKS5\r\n" + + "enabled=false # Use 'false', 'true', or 'login' for login only\r\n" + + "type=HTTP # Supported types: HTTP, SOCKS4, SOCKS4a, SOCKS5\r\n" + "server=0.0.0.0:0000\r\n" + "username=\r\n" + "password=\r\n" + "\r\n" + "[ChatFormat]\r\n" - + "builtins=true #support for handling vanilla and common message formats\r\n" - + "#public=^<([a-zA-Z0-9_]+)> (.+)$ #uncomment and adapt if necessary\r\n" - + "#private=^([a-zA-Z0-9_]+) whispers to you: (.+)$ #vanilla example\r\n" - + "#tprequest=^([a-zA-Z0-9_]+) has requested (?:to|that you) teleport to (?:you|them)\\.$\r\n" + + "builtins=true # Support for common message formats\r\n" + + "# public=^<([a-zA-Z0-9_]+)> (.+)$ # Uncomment and adapt if necessary\r\n" + + "# private=^([a-zA-Z0-9_]+) whispers to you: (.+)$ # Vanilla private message example\r\n" + + "# tprequest=^([a-zA-Z0-9_]+) has requested (?:to|that you) teleport to (?:you|them)\\.$\r\n" + "\r\n" - + "#Bot Settings\r\n" + + "[MCSettings]\r\n" + + "enabled=true # If disabled, client settings are not sent to the server\r\n" + + "locale=en_US # Use any language implemented in Minecraft\r\n" + + "renderdistance=medium # tiny, short, medium, far, or chunk amount [0 - 255]\r\n" + + "difficulty=normal # MC 1.7- difficulty. peaceful, easy, normal, difficult\r\n" + + "chatmode=enabled # enabled, commands, disabled. Allows to mute yourself...\r\n" + + "chatcolors=true # Allows disabling chat colors server-side\r\n" + + "main_hand=left # MC 1.9+ main hand. left or right\r\n" + + "skin_cape=true\r\n" + + "skin_hat=true\r\n" + + "skin_jacket=false\r\n" + + "skin_sleeve_left=false\r\n" + + "skin_sleeve_right=false\r\n" + + "skin_pants_left=false\r\n" + + "skin_pants_right=false" + + "\r\n" + + "# Bot Settings\r\n" + "\r\n" + "[Alerts]\r\n" + "enabled=false\r\n"