diff --git a/MinecraftClient/ChatBots/Alerts.cs b/MinecraftClient/ChatBots/Alerts.cs index 9ad12b2b..b79df8b3 100644 --- a/MinecraftClient/ChatBots/Alerts.cs +++ b/MinecraftClient/ChatBots/Alerts.cs @@ -41,7 +41,7 @@ namespace MinecraftClient.ChatBots if (Settings.Alerts_Beep_Enabled) Console.Beep(); //Text found ! - if (ConsoleIO.basicIO) //Using a GUI? Pass text as is. + if (ConsoleIO.BasicIO) //Using a GUI? Pass text as is. ConsoleIO.WriteLine(text.Replace(alert, "§c" + alert + "§r")); else //Using Console Prompt : Print text with alert highlighted diff --git a/MinecraftClient/ConsoleIO.cs b/MinecraftClient/ConsoleIO.cs index 4d945c31..225416a9 100644 --- a/MinecraftClient/ConsoleIO.cs +++ b/MinecraftClient/ConsoleIO.cs @@ -10,10 +10,11 @@ namespace MinecraftClient /// /// Allows simultaneous console input and output without breaking user input /// (Without having this annoying behaviour : User inp[Some Console output]ut) + /// Provide some fancy features such as formatted output, text pasting and tab-completion. + /// By ORelio - (c) 2012-2018 - Available under the CDDL-1.0 license /// public static class ConsoleIO { - public static bool basicIO = false; private static IAutoComplete autocomplete_engine; private static LinkedList autocomplete_words = new LinkedList(); private static LinkedList previous = new LinkedList(); @@ -38,6 +39,32 @@ namespace MinecraftClient } } + /// + /// Set an auto-completion engine for TAB autocompletion. + /// + /// Engine implementing the IAutoComplete interface + public static void SetAutoCompleteEngine(IAutoComplete engine) + { + autocomplete_engine = engine; + } + + /// + /// Determines whether to use interactive IO or basic IO. + /// Set to true to disable interactive command prompt and use the default Console.Read|Write() methods. + /// Color codes are printed as is when BasicIO is enabled. + /// + public static bool BasicIO = false; + + /// + /// Determine whether WriteLineFormatted() should prepend lines with timestamps by default. + /// + public static bool EnableTimestamps = false; + + /// + /// Specify a generic log line prefix for WriteLogLine() + /// + public static string LogPrefix = "§8[Log] "; + /// /// Read a password from the standard input /// @@ -88,7 +115,11 @@ namespace MinecraftClient /// public static string ReadLine() { - if (basicIO) { return Console.ReadLine(); } + if (BasicIO) + { + return Console.ReadLine(); + } + ConsoleKeyInfo k = new ConsoleKeyInfo(); lock (io_lock) @@ -199,7 +230,7 @@ namespace MinecraftClient } /// - /// Debug routine + /// Debug routine: print all keys pressed in the console /// public static void DebugReadInput() { @@ -216,7 +247,7 @@ namespace MinecraftClient /// public static void Write(string text) { - if (!basicIO) + if (!BasicIO) { lock (io_lock) { @@ -276,29 +307,48 @@ namespace MinecraftClient } /// - /// Write a Minecraft-Formatted string to the standard output, using §c color codes + /// Write a Minecraft-Like formatted string to the standard output, using §c color codes + /// See minecraft.gamepedia.com/Classic_server_protocol#Color_Codes for more info /// /// String to write /// If false, space are printed instead of newlines - public static void WriteLineFormatted(string str, bool acceptnewlines = true) + /// + /// If false, no timestamp is prepended. + /// If true, "hh-mm-ss" timestamp will be prepended. + /// If unspecified, value is retrieved from EnableTimestamps. + /// + public static void WriteLineFormatted(string str, bool acceptnewlines = true, bool? displayTimestamp = null) { - if (basicIO) { Console.WriteLine(str); return; } if (!String.IsNullOrEmpty(str)) { - if (Settings.chatTimeStamps) + if (!acceptnewlines) + { + str = str.Replace('\n', ' '); + } + if (displayTimestamp == null) + { + displayTimestamp = EnableTimestamps; + } + if (displayTimestamp.Value) { int hour = DateTime.Now.Hour, minute = DateTime.Now.Minute, second = DateTime.Now.Second; ConsoleIO.Write(String.Format("{0}:{1}:{2} ", hour.ToString("00"), minute.ToString("00"), second.ToString("00"))); } - if (!acceptnewlines) { str = str.Replace('\n', ' '); } - if (ConsoleIO.basicIO) { ConsoleIO.WriteLine(str); return; } - string[] subs = str.Split(new char[] { '§' }); - if (subs[0].Length > 0) { ConsoleIO.Write(subs[0]); } - for (int i = 1; i < subs.Length; i++) + if (BasicIO) { - if (subs[i].Length > 0) + Console.WriteLine(str); + return; + } + string[] parts = str.Split(new char[] { '§' }); + if (parts[0].Length > 0) + { + ConsoleIO.Write(parts[0]); + } + for (int i = 1; i < parts.Length; i++) + { + if (parts[i].Length > 0) { - switch (subs[i][0]) + switch (parts[i][0]) { case '0': Console.ForegroundColor = ConsoleColor.Gray; break; //Should be Black but Black is non-readable on a black background case '1': Console.ForegroundColor = ConsoleColor.DarkBlue; break; @@ -319,32 +369,46 @@ namespace MinecraftClient case 'r': Console.ForegroundColor = ConsoleColor.Gray; break; } - if (subs[i].Length > 1) + if (parts[i].Length > 1) { - ConsoleIO.Write(subs[i].Substring(1, subs[i].Length - 1)); + ConsoleIO.Write(parts[i].Substring(1, parts[i].Length - 1)); } } } Console.ForegroundColor = ConsoleColor.Gray; - ConsoleIO.Write('\n'); } + ConsoleIO.Write('\n'); } /// - /// Write a Minecraft Console Client Log line + /// Write a prefixed log line. Prefix is set in LogPrefix. /// /// Text of the log line public static void WriteLogLine(string text) { - WriteLineFormatted("§8[MCC] " + text); + WriteLineFormatted(LogPrefix + text); } #region Subfunctions + + /// + /// Clear all text inside the input prompt + /// private static void ClearLineAndBuffer() { - while (buffer2.Length > 0) { GoRight(); } - while (buffer.Length > 0) { RemoveOneChar(); } + while (buffer2.Length > 0) + { + GoRight(); + } + while (buffer.Length > 0) + { + RemoveOneChar(); + } } + + /// + /// Remove one character on the left of the cursor in input prompt + /// private static void RemoveOneChar() { if (buffer.Length > 0) @@ -369,10 +433,17 @@ namespace MinecraftClient if (buffer2.Length > 0) { Console.Write(buffer2 + " \b"); - for (int i = 0; i < buffer2.Length; i++) { GoBack(); } + for (int i = 0; i < buffer2.Length; i++) + { + GoBack(); + } } } } + + /// + /// Move the cursor one character to the left inside the console, regardless of input prompt state + /// private static void GoBack() { try @@ -387,6 +458,10 @@ namespace MinecraftClient } catch (ArgumentOutOfRangeException) { /* Console was resized!? */ } } + + /// + /// Move the cursor one character to the left in input prompt, adjusting buffers accordingly + /// private static void GoLeft() { if (buffer.Length > 0) @@ -396,6 +471,10 @@ namespace MinecraftClient Console.Write('\b'); } } + + /// + /// Move the cursor one character to the right in input prompt, adjusting buffers accordingly + /// private static void GoRight() { if (buffer2.Length > 0) @@ -405,16 +484,30 @@ namespace MinecraftClient buffer2 = buffer2.Substring(1); } } + + /// + /// Insert a new character in the input prompt + /// + /// New character private static void AddChar(char c) { Console.Write(c); buffer += c; Console.Write(buffer2); - for (int i = 0; i < buffer2.Length; i++) { GoBack(); } + for (int i = 0; i < buffer2.Length; i++) + { + GoBack(); + } } + #endregion #region Clipboard management + + /// + /// Read a string from the Windows clipboard + /// + /// String from the Windows clipboard private static string ReadClipboard() { string clipdata = ""; @@ -433,17 +526,7 @@ namespace MinecraftClient staThread.Join(); return clipdata; } - #endregion - #region AutoComplete API - /// - /// Set an auto-completion engine for TAB autocompletion - /// - /// Engine implementing the IAutoComplete interface - public static void SetAutoCompleteEngine(IAutoComplete engine) - { - autocomplete_engine = engine; - } #endregion } @@ -453,6 +536,11 @@ namespace MinecraftClient /// public interface IAutoComplete { + /// + /// Provide a list of auto-complete strings based on the provided input behing the cursor + /// + /// Text behind the cursor, e.g. "my input comm" + /// List of auto-complete words, e.g. ["command", "comment"] IEnumerable AutoComplete(string BehindCursor); } } diff --git a/MinecraftClient/McTcpClient.cs b/MinecraftClient/McTcpClient.cs index 192b645b..ea43fb49 100644 --- a/MinecraftClient/McTcpClient.cs +++ b/MinecraftClient/McTcpClient.cs @@ -202,7 +202,7 @@ namespace MinecraftClient while (client.Client.Connected) { text = ConsoleIO.ReadLine(); - if (ConsoleIO.basicIO && text.Length > 0 && text[0] == (char)0x00) + if (ConsoleIO.BasicIO && text.Length > 0 && text[0] == (char)0x00) { //Process a request from the GUI string[] command = text.Substring(1).Split((char)0x00); diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index f59ea8e0..2950ad7a 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -49,10 +49,11 @@ namespace MinecraftClient ConsoleIO.DebugReadInput(); } - //Basic Input/Output ? + //Setup ConsoleIO + ConsoleIO.LogPrefix = "§8[MCC] "; if (args.Length >= 1 && args[args.Length - 1] == "BasicIO") { - ConsoleIO.basicIO = true; + ConsoleIO.BasicIO = true; args = args.Where(o => !Object.ReferenceEquals(o, args[args.Length - 1])).ToArray(); } @@ -116,7 +117,7 @@ namespace MinecraftClient if (Settings.Login == "") { - Console.Write(ConsoleIO.basicIO ? "Please type the username or email of your choice.\n" : "Login : "); + Console.Write(ConsoleIO.BasicIO ? "Please type the username or email of your choice.\n" : "Login : "); Settings.Login = Console.ReadLine(); } if (Settings.Password == "" && (Settings.SessionCaching == CacheType.None || !SessionCache.Contains(Settings.Login.ToLower()))) @@ -133,10 +134,10 @@ namespace MinecraftClient /// private static void RequestPassword() { - Console.Write(ConsoleIO.basicIO ? "Please type the password for " + Settings.Login + ".\n" : "Password : "); - Settings.Password = ConsoleIO.basicIO ? Console.ReadLine() : ConsoleIO.ReadPassword(); + Console.Write(ConsoleIO.BasicIO ? "Please type the password for " + Settings.Login + ".\n" : "Password : "); + Settings.Password = ConsoleIO.BasicIO ? Console.ReadLine() : ConsoleIO.ReadPassword(); if (Settings.Password == "") { Settings.Password = "-"; } - if (!ConsoleIO.basicIO) + if (!ConsoleIO.BasicIO) { //Hide password length Console.CursorTop--; Console.Write("Password : <******>"); @@ -262,7 +263,6 @@ namespace MinecraftClient } else { - Console.ForegroundColor = ConsoleColor.Gray; string failureMessage = "Minecraft Login failed : "; switch (result) { @@ -366,7 +366,10 @@ namespace MinecraftClient ConsoleIO.WriteLineFormatted("Or press Enter to exit Minecraft Console Client."); while (command.Length > 0) { - if (!ConsoleIO.basicIO) { ConsoleIO.Write('>'); } + if (!ConsoleIO.BasicIO) + { + ConsoleIO.Write('>'); + } command = Console.ReadLine().Trim(); if (command.Length > 0) { diff --git a/MinecraftClient/Protocol/ChatParser.cs b/MinecraftClient/Protocol/ChatParser.cs index 9d0e7d12..60d78f66 100644 --- a/MinecraftClient/Protocol/ChatParser.cs +++ b/MinecraftClient/Protocol/ChatParser.cs @@ -92,8 +92,7 @@ namespace MinecraftClient.Protocol //File not found? Try downloading language file from Mojang's servers? if (!System.IO.File.Exists(Language_File)) { - Console.ForegroundColor = ConsoleColor.DarkGray; - ConsoleIO.WriteLine("Downloading '" + Settings.Language + ".lang' from Mojang servers..."); + ConsoleIO.WriteLineFormatted("§8Downloading '" + Settings.Language + ".lang' from Mojang servers..."); try { string assets_index = DownloadString(Settings.TranslationsFile_Website_Index); @@ -101,13 +100,12 @@ namespace MinecraftClient.Protocol 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)); - ConsoleIO.WriteLine("Done. File saved as '" + Language_File + '\''); + ConsoleIO.WriteLineFormatted("§8Done. File saved as '" + Language_File + '\''); } catch { - ConsoleIO.WriteLine("Failed to download the file."); + ConsoleIO.WriteLineFormatted("§8Failed to download the file."); } - Console.ForegroundColor = ConsoleColor.Gray; } //Download Failed? Defaulting to en_GB.lang if the game is installed diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index fcd2087f..f066f436 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -79,7 +79,6 @@ namespace MinecraftClient public static List Bots_Owners = new List(); public static TimeSpan botMessageDelay = TimeSpan.FromSeconds(2); public static string Language = "en_GB"; - public static bool chatTimeStamps = false; public static bool interactiveMode = true; public static char internalCmdChar = '/'; public static bool playerHeadAsIcon = false; @@ -214,7 +213,7 @@ namespace MinecraftClient case "singlecommand": SingleCommand = argValue; break; case "language": Language = argValue; break; case "consoletitle": ConsoleTitle = argValue; break; - case "timestamps": chatTimeStamps = str2bool(argValue); break; + case "timestamps": ConsoleIO.EnableTimestamps = str2bool(argValue); break; case "exitonfailure": interactiveMode = !str2bool(argValue); break; case "playerheadicon": playerHeadAsIcon = str2bool(argValue); break; case "chatbotlogfile": chatbotLogFile = argValue; break;