using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Diagnostics; using System.Threading; namespace MinecraftClientGUI { /// /// This class acts as a wrapper for MinecraftClient.exe /// Allows the rest of the program to consider this class as the Minecraft client itself. /// class MinecraftClient { public static string ExePath = "MinecraftClient.exe"; public bool Disconnected { get { return disconnected; } } private LinkedList OutputBuffer = new LinkedList(); private LinkedList tabAutoCompleteBuffer = new LinkedList(); private bool disconnected = false; private Process Client; private Thread Reader; /// /// Start a client using command-line arguments /// /// Arguments to pass public MinecraftClient(string[] args) { initClient("\"" + String.Join("\" \"", args) + "\" BasicIO"); } /// /// Start the client using username, password and server IP /// /// Username or email /// Password for the given username /// Server IP to join public MinecraftClient(string username, string password, string serverip) { initClient('"' + username + "\" \"" + password + "\" \"" + serverip + "\" BasicIO"); } /// /// Inner function for launching the external console application /// /// Arguments to pass private void initClient(string arguments) { if (File.Exists(ExePath)) { Client = new Process(); Client.StartInfo.FileName = ExePath; Client.StartInfo.Arguments = arguments; Client.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; Client.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ANSICodePage); Client.StartInfo.UseShellExecute = false; Client.StartInfo.RedirectStandardOutput = true; Client.StartInfo.RedirectStandardInput = true; Client.StartInfo.CreateNoWindow = true; Client.Start(); Reader = new Thread(new ThreadStart(t_reader)); Reader.Start(); } else throw new FileNotFoundException("Cannot find Minecraft Client Executable!", ExePath); } /// /// Thread for reading output and app messages from the console /// private void t_reader() { while (true) { try { string line = ""; while (line.Trim() == "") { line = Client.StandardOutput.ReadLine() + Client.MainWindowTitle; if (line == "Server was successfuly joined.") { disconnected = false; } if (line == "You have left the server.") { disconnected = true; } if (line[0] == (char)0x00) { //App message from the console string[] command = line.Substring(1).Split((char)0x00); switch (command[0].ToLower()) { case "autocomplete": if (command.Length > 1) { tabAutoCompleteBuffer.AddLast(command[1]); } else tabAutoCompleteBuffer.AddLast(""); break; } } else OutputBuffer.AddLast(line); } } catch (NullReferenceException) { break; } } } /// /// Get the first queuing output line to print /// /// public string ReadLine() { while (OutputBuffer.Count < 1) { } string line = OutputBuffer.First.Value; OutputBuffer.RemoveFirst(); return line; } /// /// Complete a playername or a command, usually by pressing the TAB key /// /// Text to complete /// Returns an autocompletion for the provided text public string tabAutoComplete(string text_behindcursor) { tabAutoCompleteBuffer.Clear(); if (text_behindcursor != null && text_behindcursor.Trim().Length > 0) { text_behindcursor = text_behindcursor.Trim(); SendText((char)0x00 + "autocomplete" + (char)0x00 + text_behindcursor); int maxwait = 30; while (tabAutoCompleteBuffer.Count < 1 && maxwait > 0) { Thread.Sleep(100); maxwait--; } if (tabAutoCompleteBuffer.Count > 0) { string text_completed = tabAutoCompleteBuffer.First.Value; tabAutoCompleteBuffer.RemoveFirst(); return text_completed; } else return text_behindcursor; } else return ""; } /// /// Send a message or a command to the server /// /// Text to send public void SendText(string text) { if (text != null) { text = text.Replace("\t", ""); text = text.Replace("\r", ""); text = text.Replace("\n", ""); text = text.Trim(); if (text.Length > 0) { Client.StandardInput.WriteLine(text); } } } /// /// Properly disconnect from the server and dispose the client /// public void Close() { Client.StandardInput.WriteLine("/quit"); if (Reader.IsAlive) { Reader.Abort(); } if (!Client.WaitForExit(3000)) { try { Client.Kill(); } catch { } } } } }