using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; using System.Threading; using System.IO; using System.Net; using MinecraftClient.Protocol; using MinecraftClient.Proxy; namespace MinecraftClient { /// /// The main client class, used to connect to a Minecraft server. /// public class McTcpClient : IMinecraftComHandler { private List bots = new List(); private static List scripts_on_hold = new List(); public void BotLoad(ChatBot b) { b.SetHandler(this); bots.Add(b); b.Initialize(); Settings.SingleCommand = ""; } public void BotUnLoad(ChatBot b) { bots.RemoveAll(item => object.ReferenceEquals(item, b)); } public void BotClear() { bots.Clear(); } public static int AttemptsLeft = 0; private string host; private int port; private string username; private string uuid; private string sessionid; public int getServerPort() { return port; } public string getServerHost() { return host; } public string getUsername() { return username; } public string getUserUUID() { return uuid; } public string getSessionID() { return sessionid; } TcpClient client; IMinecraftCom handler; /// /// Starts the main chat client /// /// The chosen username of a premium Minecraft Account /// The player's UUID for online-mode authentication /// A valid sessionID obtained after logging in /// The server IP /// The server port to use /// Minecraft protocol version to use public McTcpClient(string username, string uuid, string sessionID, int protocolversion, string server_ip, short port) { StartClient(username, uuid, sessionID, server_ip, port, protocolversion, false, ""); } /// /// Starts the main chat client in single command sending mode /// /// The chosen username of a premium Minecraft Account /// The player's UUID for online-mode authentication /// A valid sessionID obtained after logging in /// The server IP /// The server port to use /// Minecraft protocol version to use /// The text or command to send. public McTcpClient(string username, string uuid, string sessionID, string server_ip, short port, int protocolversion, string command) { StartClient(username, uuid, sessionID, server_ip, port, protocolversion, true, command); } /// /// Starts the main chat client, wich will login to the server using the MinecraftCom class. /// /// The chosen username of a premium Minecraft Account /// A valid sessionID obtained with MinecraftCom.GetLogin() /// The server IP /// The server port to use /// Minecraft protocol version to use /// The player's UUID for online-mode authentication /// If set to true, the client will send a single command and then disconnect from the server /// The text or command to send. Will only be sent if singlecommand is set to true. private void StartClient(string user, string uuid, string sessionID, string server_ip, short port, int protocolversion, bool singlecommand, string command) { this.sessionid = sessionID; this.uuid = uuid; this.username = user; this.host = server_ip; this.port = port; if (!singlecommand) { if (Settings.AntiAFK_Enabled) { BotLoad(new ChatBots.AntiAFK(Settings.AntiAFK_Delay)); } if (Settings.Hangman_Enabled) { BotLoad(new ChatBots.HangmanGame(Settings.Hangman_English)); } if (Settings.Alerts_Enabled) { BotLoad(new ChatBots.Alerts()); } if (Settings.ChatLog_Enabled) { BotLoad(new ChatBots.ChatLog(Settings.expandVars(Settings.ChatLog_File), Settings.ChatLog_Filter, Settings.ChatLog_DateTime)); } if (Settings.PlayerLog_Enabled) { BotLoad(new ChatBots.PlayerListLogger(Settings.PlayerLog_Delay, Settings.expandVars(Settings.PlayerLog_File))); } if (Settings.AutoRelog_Enabled) { BotLoad(new ChatBots.AutoRelog(Settings.AutoRelog_Delay, Settings.AutoRelog_Retries)); } if (Settings.ScriptScheduler_Enabled) { BotLoad(new ChatBots.ScriptScheduler(Settings.expandVars(Settings.ScriptScheduler_TasksFile))); } if (Settings.RemoteCtrl_Enabled) { BotLoad(new ChatBots.RemoteControl()); } } try { client = ProxyHandler.newTcpClient(host, port); client.ReceiveBufferSize = 1024 * 1024; handler = Protocol.ProtocolHandler.getProtocolHandler(client, protocolversion, this); Console.WriteLine("Version is supported.\nLogging in..."); if (handler.Login()) { if (singlecommand) { handler.SendChatMessage(command); ConsoleIO.WriteLineFormatted("§7Command §8" + command + "§7 sent."); Thread.Sleep(5000); handler.Disconnect(); Thread.Sleep(1000); } else { foreach (ChatBot bot in scripts_on_hold) { bots.Add(bot); } scripts_on_hold.Clear(); Console.WriteLine("Server was successfully joined.\nType '/quit' to leave the server."); StartTalk(); } } } catch (SocketException) { Console.WriteLine("Failed to connect to this IP."); if (AttemptsLeft > 0) { ChatBot.LogToConsole("Waiting 5 seconds (" + AttemptsLeft + " attempts left)..."); Thread.Sleep(5000); AttemptsLeft--; Program.Restart(); } else if (!singlecommand) { Console.ReadLine(); } } } /// /// Allows the user to send chat messages, commands, and to leave the server. /// private void StartTalk() { try { string text = ""; Thread.Sleep(500); handler.SendRespawnPacket(); while (client.Client.Connected) { text = ConsoleIO.ReadLine(); if (ConsoleIO.basicIO && text.Length > 0 && text[0] == (char)0x00) { //Process a request from the GUI string[] command = text.Substring(1).Split((char)0x00); switch (command[0].ToLower()) { case "autocomplete": if (command.Length > 1) { ConsoleIO.WriteLine((char)0x00 + "autocomplete" + (char)0x00 + handler.AutoComplete(command[1])); } else Console.WriteLine((char)0x00 + "autocomplete" + (char)0x00); break; } } else { text = text.Trim(); if (text.Length > 0) { if (text[0] == '/') { string command = text.Substring(1); if (isInternalCommand(command)) { performInternalCommand(command, true); } else SendChatMessage(text); } } } } } catch (IOException) { } } /// /// Check if the given command is a valid internal MCC command /// /// The command or command name /// TRUE if this is an internal command public bool isInternalCommand(string command) { string command_name = command.Split(' ')[0].ToLower(); switch (command_name) { case "exit": case "quit": case "reco": case "respawn": case "send": case "script": case "connect": return true; default: return false; } } /// /// Perform an internal MCC command (not a server command, use SendChatMessage() instead for that!) /// /// The command /// Set to true if command was sent by the user using the command prompt /// TRUE if the command was successfully recognized and performed public bool performInternalCommand(string command, bool interactive_mode = false) { string[] command_args = command.Split(' '); string command_name = command_args[0].ToLower(); switch (command_name) { case "exit": case "quit": Program.Exit(); break; case "reco": Program.Restart(); break; case "respawn": handler.SendRespawnPacket(); if (interactive_mode) ConsoleIO.WriteLine("You have respawned."); break; case "send": if (command.Length > 5) { string text = command.Substring(5); SendChatMessage(text); } break; case "script": if (command.Length > 8) BotLoad(new ChatBots.Script(command.Substring(8))); break; case "connect": if (command_args.Length > 1) { Settings.setServerIP(command_args[1]); Program.Restart(); } break; default: return false; } return true; } /// /// Disconnect the client from the server /// public void Disconnect() { foreach (ChatBot bot in bots) if (bot is ChatBots.Script) scripts_on_hold.Add((ChatBots.Script)bot); handler.Disconnect(); handler.Dispose(); Thread.Sleep(1000); if (client != null) { client.Close(); } } /// /// Received some text from the server /// /// Text received public void OnTextReceived(string text) { ConsoleIO.WriteLineFormatted(text, false); foreach (ChatBot bot in bots) bot.GetText(text); } /// /// When connection has been lost /// public void OnConnectionLost(ChatBot.DisconnectReason reason, string message) { bool will_restart = false; switch (reason) { case ChatBot.DisconnectReason.ConnectionLost: message = "Connection has been lost."; ConsoleIO.WriteLine(message); break; case ChatBot.DisconnectReason.InGameKick: ConsoleIO.WriteLine("Disconnected by Server :"); ConsoleIO.WriteLineFormatted(message); break; case ChatBot.DisconnectReason.LoginRejected: ConsoleIO.WriteLine("Login failed :"); ConsoleIO.WriteLineFormatted(message); break; } foreach (ChatBot bot in bots) will_restart |= bot.OnDisconnect(reason, message); if (!will_restart) { Program.ReadLineReconnect(); } } /// /// Called ~10 times per second by the protocol handler /// public void OnUpdate() { for (int i = 0; i < bots.Count; i++) { try { bots[i].Update(); } catch (Exception e) { ConsoleIO.WriteLineFormatted("§8Got error from " + bots[i].ToString() + ": " + e.ToString()); } } } /// /// Send a chat message or command to the server /// /// Text to send to the server /// True if the text was sent with no error public bool SendChatMessage(string text) { if (text.Length > 100) //Message is too long? { if (text[0] == '/') { //Send the first 100 chars of the command text = text.Substring(0, 100); return handler.SendChatMessage(text); } else { //Send the message splitted into several messages while (text.Length > 100) { handler.SendChatMessage(text.Substring(0, 100)); text = text.Substring(100, text.Length - 100); } return handler.SendChatMessage(text); } } else return handler.SendChatMessage(text); } } }