From ecf0114f626ac2ee6ae8ffbf2cceb69b7e0b1b09 Mon Sep 17 00:00:00 2001 From: ORelio Date: Mon, 28 May 2018 22:01:51 +0200 Subject: [PATCH] ConsoleIO: Sync with SharpTools Had 2 versions of the ConsoleIO class, one here inc MCC (the original), and another one in SharpTools, more generic, for use in other projects. Both had diverged, this commit imports changes from the other repository. This should not have any particular effect on MCC, besides adding more documentation and settings in the source code of the class. If any issue arises, as always, please report it :) --- MinecraftClient/ChatBots/Alerts.cs | 2 +- MinecraftClient/ConsoleIO.cs | 156 +++++++++++++++++++------ MinecraftClient/McTcpClient.cs | 2 +- MinecraftClient/Program.cs | 19 +-- MinecraftClient/Protocol/ChatParser.cs | 8 +- MinecraftClient/Settings.cs | 3 +- 6 files changed, 139 insertions(+), 51 deletions(-) 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;