using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Globalization; namespace MinecraftClient { /// /// Welcome to the Bot API file ! /// The virtual class "ChatBot" contains anything you need for creating chat bots /// Inherit from this class while adding your bot class to the namespace "Bots", below. /// Once your bot is created, read the explanations below to start using it in the MinecraftClient app. /// /// Pieces of code to add in other parts of the program for your bot. Line numbers are approximative. /// Program.cs:166 | if (Settings.YourBot_Enabled){ handler.BotLoad(new Bots.YourBot()); } /// Settings.cs:73 | public static bool YourBot_Enabled = false; /// Settings.cs:74 | private enum ParseMode { /* [...] */, YourBot }; /// Settings.cs:106| case "yourbot": pMode = ParseMode.YourBot; break; /// Settings.cs:197| case ParseMode.YourBot: switch (argName.ToLower()) { case "enabled": YourBot_Enabled = str2bool(argValue); break; } break; /// Settings.cs:267| + "[YourBot]\r\n" + "enabled=false\r\n" /// Here your are. Now you will have a setting in MinecraftClient.ini for enabling your brand new bot. /// Delete MinecraftClient.ini to re-generate it or add the lines [YourBot] and enabled=true to the existing one. /// /// /// The virtual class containing anything you need for creating chat bots. /// public abstract class ChatBot { public enum DisconnectReason { InGameKick, LoginRejected, ConnectionLost }; #region MinecraftCom Handler for this bot //Will be automatically set on bot loading, don't worry about this public void SetHandler(MinecraftCom handler) { this.handler = handler; } private MinecraftCom handler; #endregion /// /// Anything you want to initialize your bot, will be called on load by MinecraftCom /// public virtual void Initialize() { } /// /// Will be called every ~100ms (10fps) if loaded in MinecraftCom /// public virtual void Update() { } /// /// Any text sent by the server will be sent here by MinecraftCom /// /// Text from the server public virtual void GetText(string text) { } /// /// Is called when the client has been disconnected fom the server /// /// Disconnect Reason /// Kick message, if any /// Return TRUE if the client is about to restart public virtual bool OnDisconnect(DisconnectReason reason, string message) { return false; } #region ToolBox /// /// Send text to the server. Can be anything such as chat messages or commands /// /// Text to send to the server protected void SendText(string text) { Console.ForegroundColor = ConsoleColor.DarkGray; ConsoleIO.WriteLine("BOT:" + text); handler.SendChatMessage(text); Console.ForegroundColor = ConsoleColor.Gray; } /// /// Remove color codes ("§c") from a text message received from the server /// protected static string getVerbatim(string text) { if ( String.IsNullOrEmpty(text) ) return String.Empty; int idx = 0; var data = new char[text.Length]; for ( int i = 0; i < text.Length; i++ ) if ( text[i] != '§' ) data[idx++] = text[i]; else i++; return new string(data, 0, idx); } /// /// Verify that a string contains only a-z A-Z 0-9 and _ characters. /// protected static bool isValidName(string username) { if ( String.IsNullOrEmpty(username) ) return false; foreach ( char c in username ) if ( !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') ) return false; return true; } /// /// Returns true is the text passed is a private message sent to the bot /// /// text to test /// if it's a private message, this will contain the message /// if it's a private message, this will contain the player name that sends the message /// Returns true if the text is a private message protected static bool isPrivateMessage(string text, ref string message, ref string sender) { if (text == "") { return false; } string[] tmp = text.Split(' '); try { //Detect vanilla /tell messages //Someone whispers to you: message if (tmp.Length > 2 && tmp[1] == "whispers") { message = text.Substring(tmp[0].Length + 18); sender = tmp[0]; return isValidName(sender); } //Detect Essentials (Bukkit) /m messages //[Someone -> me] message else if (text[0] == '[' && tmp.Length > 3 && tmp[1] == "->" && (tmp[2] == "me]" || tmp[2] == "moi]")) //'me' is replaced by 'moi' in french servers { message = text.Substring(tmp[0].Length + 4 + tmp[2].Length + 1); sender = tmp[0].Substring(1); if (sender[0] == '~') { sender = sender.Substring(1); } return isValidName(sender); } else return false; } catch (IndexOutOfRangeException) { return false; } } /// /// Returns true is the text passed is a public message written by a player on the chat /// /// text to test /// if it's message, this will contain the message /// if it's message, this will contain the player name that sends the message /// Returns true if the text is a chat message protected static bool isChatMessage(string text, ref string message, ref string sender) { //Detect chat messages // message //<*Faction Someone> message //<*Faction Someone>: message //<*Faction ~Nicknamed>: message if (text == "") { return false; } if (text[0] == '<') { try { text = text.Substring(1); string[] tmp = text.Split('>'); sender = tmp[0]; message = text.Substring(sender.Length + 2); if (message.Length > 1 && message[0] == ' ') { message = message.Substring(1); } tmp = sender.Split(' '); sender = tmp[tmp.Length - 1]; if (sender[0] == '~') { sender = sender.Substring(1); } return isValidName(sender); } catch (IndexOutOfRangeException) { return false; } } else return false; } /// /// Writes some text in the console. Nothing will be sent to the server. /// /// Log text to write public static void LogToConsole(string text) { Console.ForegroundColor = ConsoleColor.DarkGray; ConsoleIO.WriteLine("[BOT] " + text); Console.ForegroundColor = ConsoleColor.Gray; } /// /// Disconnect from the server and restart the program /// It will unload & reload all the bots and then reconnect to the server /// protected void ReconnectToTheServer() { ReconnectToTheServer(3); } /// /// Disconnect from the server and restart the program /// It will unload & reload all the bots and then reconnect to the server /// /// If connection fails, the client will make X extra attempts protected void ReconnectToTheServer(int ExtraAttempts) { McTcpClient.AttemptsLeft = ExtraAttempts; Program.Restart(); } /// /// Disconnect from the server and exit the program /// protected void DisconnectAndExit() { Program.Exit(); } /// /// Unload the chatbot, and release associated memory. /// protected void UnloadBot() { handler.BotUnLoad(this); } /// /// Send a private message to a player /// /// Player name /// Message protected void SendPrivateMessage(string player, string message) { SendText("/tell " + player + ' ' + message); } /// /// Run a script from a file using a Scripting bot /// /// File name /// Player name to send error messages, if applicable protected void RunScript(string filename, string playername = "") { handler.BotLoad(new Bots.Script(filename, playername)); } #endregion } namespace Bots { /// /// Example of message receiving. /// public class TestBot : ChatBot { public override void GetText(string text) { string message = ""; string username = ""; text = getVerbatim(text); if (isPrivateMessage(text, ref message, ref username)) { ConsoleIO.WriteLine("Bot: " + username + " told me : " + message); } else if (isChatMessage(text, ref message, ref username)) { ConsoleIO.WriteLine("Bot: " + username + " said : " + message); } } } /// /// This bot sends a command every 60 seconds in order to stay non-afk. /// public class AntiAFK : ChatBot { private int count; private int timeping; /// /// This bot sends a /ping command every X seconds in order to stay non-afk. /// /// Time amount between each ping (10 = 1s, 600 = 1 minute, etc.) public AntiAFK(int pingparam) { count = 0; timeping = pingparam; if (timeping < 10) { timeping = 10; } //To avoid flooding } public override void Update() { count++; if (count == timeping) { SendText(Settings.AntiAFK_Command); count = 0; } } } /// /// This bot sends a /list command every X seconds and save the result. /// public class PlayerListLogger : ChatBot { private int count; private int timeping; private string file; /// /// This bot sends a /list command every X seconds and save the result. /// /// Time amount between each list ping (10 = 1s, 600 = 1 minute, etc.) public PlayerListLogger(int pingparam, string filetosavein) { count = 0; file = filetosavein; timeping = pingparam; if (timeping < 10) { timeping = 10; } //To avoid flooding } public override void Update() { count++; if (count == timeping) { SendText("/list"); count = 0; } } public override void GetText(string text) { if (text.Contains("Joueurs en ligne") || text.Contains("Connected:") || text.Contains("online:")) { LogToConsole("Saving Player List"); DateTime now = DateTime.Now; string TimeStamp = "[" + now.Year + '/' + now.Month + '/' + now.Day + ' ' + now.Hour + ':' + now.Minute + ']'; System.IO.File.AppendAllText(file, TimeStamp + "\n" + getVerbatim(text) + "\n\n"); } } } /// /// "Le jeu du Pendu" (Hangman game) /// public class Pendu : ChatBot { private int vie = 0; private int vie_param = 10; private int compteur = 0; private int compteur_param = 3000; //5 minutes private bool running = false; private bool[] discovered; private string word = ""; private string letters = ""; private bool English; /// /// "Le jeu du Pendu" (Hangman Game) /// /// if true, the game will be in english. If false, the game will be in french. public Pendu(bool english) { English = english; } public override void Update() { if (running) { if (compteur > 0) { compteur--; } else { SendText(English ? "You took too long to try a letter." : "Temps imparti écoulé !"); SendText(English ? "Game canceled." : "Partie annulée."); running = false; } } } public override void GetText(string text) { string message = ""; string username = ""; text = getVerbatim(text); if (isPrivateMessage(text, ref message, ref username)) { if (Settings.Bots_Owners.Contains(username.ToLower())) { switch (message) { case "start": start(); break; case "stop": running = false; break; default: break; } } } else { if (running && isChatMessage(text, ref message, ref username)) { if (message.Length == 1) { char letter = message.ToUpper()[0]; if (letter >= 'A' && letter <= 'Z') { if (letters.Contains(letter)) { SendText(English ? ("Letter " + letter + " has already been tried.") : ("Le " + letter + " a déjà été proposé.")); } else { letters += letter; compteur = compteur_param; if (word.Contains(letter)) { for (int i = 0; i < word.Length; i++) { if (word[i] == letter) { discovered[i] = true; } } SendText(English ? ("Yes, the word contains a " + letter + '!') : ("Le " + letter + " figurait bien dans le mot :)")); } else { vie--; if (vie == 0) { SendText(English ? "Game Over! :]" : "Perdu ! Partie terminée :]"); SendText(English ? ("The word was: " + word) : ("Le mot était : " + word)); running = false; } else SendText(English ? ("The " + letter + "? No.") : ("Le " + letter + " ? Non.")); } if (running) { SendText(English ? ("Mysterious word: " + word_cached + " (lives : " + vie + ")") : ("Mot mystère : " + word_cached + " (vie : " + vie + ")")); } if (winner) { SendText(English ? ("Congrats, " + username + '!') : ("Félicitations, " + username + " !")); running = false; } } } } } } } private void start() { vie = vie_param; running = true; letters = ""; word = chooseword(); compteur = compteur_param; discovered = new bool[word.Length]; SendText(English ? "Hangman v1.0 - By ORelio" : "Pendu v1.0 - Par ORelio"); SendText(English ? ("Mysterious word: " + word_cached + " (lives : " + vie + ")") : ("Mot mystère : " + word_cached + " (vie : " + vie + ")")); SendText(English ? ("Try some letters ... :)") : ("Proposez une lettre ... :)")); } private string chooseword() { if (System.IO.File.Exists(English ? Settings.Hangman_FileWords_EN : Settings.Hangman_FileWords_FR)) { string[] dico = System.IO.File.ReadAllLines(English ? Settings.Hangman_FileWords_EN : Settings.Hangman_FileWords_FR); return dico[new Random().Next(dico.Length)]; } else { LogToConsole(English ? "File not found: " + Settings.Hangman_FileWords_EN : "Fichier introuvable : " + Settings.Hangman_FileWords_FR); return English ? "WORDSAREMISSING" : "DICOMANQUANT"; } } private string word_cached { get { string printed = ""; for (int i = 0; i < word.Length; i++) { if (discovered[i]) { printed += word[i]; } else printed += '_'; } return printed; } } private bool winner { get { for (int i = 0; i < discovered.Length; i++) { if (!discovered[i]) { return false; } } return true; } } } /// /// This bot make the console beep on some specified words. Useful to detect when someone is talking to you, for example. /// public class Alerts : ChatBot { private string[] dictionary = new string[0]; private string[] excludelist = new string[0]; public override void Initialize() { if (System.IO.File.Exists(Settings.Alerts_MatchesFile)) { dictionary = System.IO.File.ReadAllLines(Settings.Alerts_MatchesFile); for (int i = 0; i < dictionary.Length; i++) { dictionary[i] = dictionary[i].ToLower(); } } else LogToConsole("File not found: " + Settings.Alerts_MatchesFile); if (System.IO.File.Exists(Settings.Alerts_ExcludesFile)) { excludelist = System.IO.File.ReadAllLines(Settings.Alerts_ExcludesFile); for (int i = 0; i < excludelist.Length; i++) { excludelist[i] = excludelist[i].ToLower(); } } else LogToConsole("File not found : " + Settings.Alerts_ExcludesFile); } public override void GetText(string text) { text = getVerbatim(text); string comp = text.ToLower(); foreach (string alert in dictionary) { if (comp.Contains(alert)) { bool ok = true; foreach (string exclusion in excludelist) { if (comp.Contains(exclusion)) { ok = false; break; } } if (ok) { if (Settings.Alerts_Beep_Enabled) { Console.Beep(); } //Text found ! if (ConsoleIO.basicIO) { ConsoleIO.WriteLine(comp.Replace(alert, "§c" + alert + "§r")); } else { #region Displaying the text with the interesting part highlighted Console.BackgroundColor = ConsoleColor.DarkGray; Console.ForegroundColor = ConsoleColor.White; //Will be used for text displaying string[] temp = comp.Split(alert.Split(','), StringSplitOptions.RemoveEmptyEntries); int p = 0; //Special case : alert in the beginning of the text string test = ""; for (int i = 0; i < alert.Length; i++) { test += comp[i]; } if (test == alert) { Console.BackgroundColor = ConsoleColor.Yellow; Console.ForegroundColor = ConsoleColor.Red; for (int i = 0; i < alert.Length; i++) { ConsoleIO.Write(text[p]); p++; } } //Displaying the rest of the text for (int i = 0; i < temp.Length; i++) { Console.BackgroundColor = ConsoleColor.DarkGray; Console.ForegroundColor = ConsoleColor.White; for (int j = 0; j < temp[i].Length; j++) { ConsoleIO.Write(text[p]); p++; } Console.BackgroundColor = ConsoleColor.Yellow; Console.ForegroundColor = ConsoleColor.Red; try { for (int j = 0; j < alert.Length; j++) { ConsoleIO.Write(text[p]); p++; } } catch (IndexOutOfRangeException) { } } Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Gray; ConsoleIO.Write('\n'); #endregion } } } } } } /// /// This bot saves the received messages in a text file. /// public class ChatLog : ChatBot { public enum MessageFilter { AllText, AllMessages, OnlyChat, OnlyWhispers }; private bool dateandtime; private bool saveOther = true; private bool saveChat = true; private bool savePrivate = true; private string logfile; /// /// This bot saves the messages received in the specified file, with some filters and date/time tagging. /// /// The file to save the log in /// The kind of messages to save /// Add a date and time before each message public ChatLog(string file, MessageFilter filter, bool AddDateAndTime) { dateandtime = AddDateAndTime; logfile = file; switch (filter) { case MessageFilter.AllText: saveOther = true; savePrivate = true; saveChat = true; break; case MessageFilter.AllMessages: saveOther = false; savePrivate = true; saveChat = true; break; case MessageFilter.OnlyChat: saveOther = false; savePrivate = false; saveChat = true; break; case MessageFilter.OnlyWhispers: saveOther = false; savePrivate = true; saveChat = false; break; } } public static MessageFilter str2filter(string filtername) { switch (filtername.ToLower()) { case "all": return MessageFilter.AllText; case "messages": return MessageFilter.AllMessages; case "chat": return MessageFilter.OnlyChat; case "private": return MessageFilter.OnlyWhispers; default: return MessageFilter.AllText; } } public override void GetText(string text) { text = getVerbatim(text); string sender = ""; string message = ""; if (saveChat && isChatMessage(text, ref message, ref sender)) { save("Chat " + sender + ": " + message); } else if (savePrivate && isPrivateMessage(text, ref message, ref sender)) { save("Private " + sender + ": " + message); } else if (saveOther) { save("Other: " + text); } } private void save(string tosave) { if (dateandtime) { int day = DateTime.Now.Day, month = DateTime.Now.Month; int hour = DateTime.Now.Hour, minute = DateTime.Now.Minute, second = DateTime.Now.Second; string D = day < 10 ? "0" + day : "" + day; string M = month < 10 ? "0" + month : "" + day; string Y = "" + DateTime.Now.Year; string h = hour < 10 ? "0" + hour : "" + hour; string m = minute < 10 ? "0" + minute : "" + minute; string s = second < 10 ? "0" + second : "" + second; tosave = "" + D + '-' + M + '-' + Y + ' ' + h + ':' + m + ':' + s + ' ' + tosave; } System.IO.FileStream stream = new System.IO.FileStream(logfile, System.IO.FileMode.OpenOrCreate); System.IO.StreamWriter writer = new System.IO.StreamWriter(stream); stream.Seek(0, System.IO.SeekOrigin.End); writer.WriteLine(tosave); writer.Dispose(); stream.Close(); } } /// /// This bot automatically re-join the server if kick message contains predefined string (Server is restarting ...) /// public class AutoRelog : ChatBot { private string[] dictionary = new string[0]; private int attempts; private int delay; /// /// This bot automatically re-join the server if kick message contains predefined string /// /// Delay before re-joining the server (in seconds) /// Number of retries if connection fails (-1 = infinite) public AutoRelog(int DelayBeforeRelog, int retries) { attempts = retries; if (attempts == -1) { attempts = int.MaxValue; } McTcpClient.AttemptsLeft = attempts; delay = DelayBeforeRelog; if (delay < 1) { delay = 1; } } public override void Initialize() { McTcpClient.AttemptsLeft = attempts; if (System.IO.File.Exists(Settings.AutoRelog_KickMessagesFile)) { dictionary = System.IO.File.ReadAllLines(Settings.AutoRelog_KickMessagesFile); for (int i = 0; i < dictionary.Length; i++) { dictionary[i] = dictionary[i].ToLower(); } } else LogToConsole("File not found: " + Settings.AutoRelog_KickMessagesFile); } public override bool OnDisconnect(DisconnectReason reason, string message) { message = getVerbatim(message); string comp = message.ToLower(); foreach (string msg in dictionary) { if (comp.Contains(msg)) { LogToConsole("Waiting " + delay + " seconds before reconnecting..."); System.Threading.Thread.Sleep(delay * 1000); McTcpClient.AttemptsLeft = attempts; ReconnectToTheServer(); return true; } } return false; } } /// /// Runs a list of commands /// public class Script : ChatBot { private string file; private string[] lines = new string[0]; private int sleepticks = 10; private int sleepticks_interval = 10; private int nextline = 0; private string owner; public Script(string filename) { file = filename; } public Script(string filename, string ownername) :this(filename) { if (ownername != "") owner = ownername; } public static bool lookForScript(ref string filename) { //Automatically look in subfolders and try to add ".txt" file extension string[] files = new string[] { filename, filename + ".txt", "scripts\\" + filename, "scripts\\" + filename + ".txt", "config\\" + filename, "config\\" + filename + ".txt", }; foreach (string possible_file in files) { if (System.IO.File.Exists(possible_file)) { filename = possible_file; return true; } } return false; } public override void Initialize() { //Load the given file from the startup parameters if (lookForScript(ref file)) { lines = System.IO.File.ReadAllLines(file); if (owner != null) { SendPrivateMessage(owner, "Script '" + file + "' loaded."); } } else { LogToConsole("File not found: '" + file + "'"); if (owner != null) SendPrivateMessage(owner, "File not found: '" + file + "'"); UnloadBot(); //No need to keep the bot active } } public override void Update() { if (sleepticks > 0) { sleepticks--; } else { if (nextline < lines.Length) //Is there an instruction left to interpret? { string instruction_line = lines[nextline].Trim(); // Removes all whitespaces at start and end of current line nextline++; //Move the cursor so that the next time the following line will be interpreted sleepticks = sleepticks_interval; //Used to delay next command sending and prevent from beign kicked for spamming if (instruction_line.Length > 1) { if (instruction_line[0] != '#' && instruction_line[0] != '/' && instruction_line[1] != '/') { string instruction_name = instruction_line.Split(' ')[0]; switch (instruction_name.ToLower()) { case "send": SendText(instruction_line.Substring(5, instruction_line.Length - 5)); break; case "wait": int ticks = 10; try { ticks = Convert.ToInt32(instruction_line.Substring(5, instruction_line.Length - 5)); } catch { } sleepticks = ticks; break; case "disconnect": DisconnectAndExit(); break; case "exit": //Exit bot & stay connected to the server UnloadBot(); break; case "connect": if (instruction_line.Length >= 9) { Settings.ServerIP = instruction_line.Substring(8); ReconnectToTheServer(); } break; default: sleepticks = 0; Update(); //Unknown command : process next line immediately break; } } else { sleepticks = 0; Update(); } //Comment: process next line immediately } } else { //No more instructions to interpret UnloadBot(); } } } } /// /// Trigger scripts on specific events /// public class ScriptScheduler : ChatBot { private class TaskDesc { public string script_file = null; public bool triggerOnFirstLogin = false; public bool triggerOnLogin = false; public bool triggerOnTime = false; public List triggerOnTime_Times = new List(); public bool alreadyTriggered = false; } private static bool firstlogin_done = false; private string tasksfile; private bool serverlogin_done; private List tasks = new List(); private int verifytasks_timeleft = 10; private int verifytasks_delay = 10; public ScriptScheduler(string tasksfile) { this.tasksfile = tasksfile; serverlogin_done = false; } public override void Initialize() { //Load the given file from the startup parameters if (System.IO.File.Exists(tasksfile)) { TaskDesc current_task = null; String[] lines = System.IO.File.ReadAllLines(tasksfile); foreach (string lineRAW in lines) { string line = lineRAW.Split('#')[0].Trim(); if (line.Length > 0) { if (line[0] == '[' && line[line.Length - 1] == ']') { switch (line.Substring(1, line.Length - 2).ToLower()) { case "task": checkAddTask(current_task); current_task = new TaskDesc(); //Create a blank task break; } } else if (current_task != null) { string argName = line.Split('=')[0]; if (line.Length > (argName.Length + 1)) { string argValue = line.Substring(argName.Length + 1); switch (argName.ToLower()) { case "triggeronfirstlogin": current_task.triggerOnFirstLogin = Settings.str2bool(argValue); break; case "triggeronlogin": current_task.triggerOnLogin = Settings.str2bool(argValue); break; case "triggerontime": current_task.triggerOnTime = Settings.str2bool(argValue); break; case "timevalue": try { current_task.triggerOnTime_Times.Add(DateTime.ParseExact(argValue, "HH:mm", CultureInfo.InvariantCulture)); } catch { } break; case "script": current_task.script_file = argValue; break; } } } } } checkAddTask(current_task); } else { LogToConsole("File not found: '" + tasksfile + "'"); UnloadBot(); //No need to keep the bot active } } private void checkAddTask(TaskDesc current_task) { if (current_task != null) { //Check if we built a valid task before adding it if (current_task.script_file != null && Script.lookForScript(ref current_task.script_file) //Check if file exists && (current_task.triggerOnLogin || (current_task.triggerOnTime && current_task.triggerOnTime_Times.Count > 0))) //Look for a valid trigger { tasks.Add(current_task); } } } public override void Update() { if (verifytasks_timeleft <= 0) { verifytasks_timeleft = verifytasks_delay; if (serverlogin_done) { foreach (TaskDesc task in tasks) { if (task.triggerOnTime) { foreach (DateTime time in task.triggerOnTime_Times) { if (time.Hour == DateTime.Now.Hour && time.Minute == DateTime.Now.Minute) { if (!task.alreadyTriggered) { task.alreadyTriggered = true; RunScript(task.script_file); } } } } else task.alreadyTriggered = false; } } else { foreach (TaskDesc task in tasks) { if (task.triggerOnLogin || (firstlogin_done == false && task.triggerOnFirstLogin)) RunScript(task.script_file); } firstlogin_done = true; serverlogin_done = true; } } else verifytasks_timeleft--; } } /// /// Allow to perform operations using whispers to the bot /// public class RemoteControl : ChatBot { public override void GetText(string text) { text = getVerbatim(text); string command = "", sender = ""; if (isPrivateMessage(text, ref command, ref sender) && Settings.Bots_Owners.Contains(sender.ToLower())) { string cmd_name = command.Split(' ')[0]; switch (cmd_name.ToLower()) { case "exit": DisconnectAndExit(); break; case "reco": ReconnectToTheServer(); break; case "script": if (command.Length >= 8) RunScript(command.Substring(7), sender); break; case "send": if (command.Length >= 6) SendText(command.Substring(5)); break; case "connect": if (command.Length >= 9) { Settings.ServerIP = command.Substring(8); ReconnectToTheServer(); } break; case "help": if (command.Length >= 6) { string help_cmd_name = command.Substring(5).ToLower(); switch (help_cmd_name) { case "exit": SendPrivateMessage(sender, "exit: disconnect from the server."); break; case "reco": SendPrivateMessage(sender, "reco: restart and reconnct to the server."); break; case "script": SendPrivateMessage(sender, "script : run a script file."); break; case "send": SendPrivateMessage(sender, "send : send a chat message or command."); break; case "connect": SendPrivateMessage(sender, "connect : connect to the specified server."); break; case "help": SendPrivateMessage(sender, "help : show brief help about a command."); break; default: SendPrivateMessage(sender, "help: unknown command '" + help_cmd_name + "'."); break; } } else SendPrivateMessage(sender, "help . Available commands: exit, reco, script, send, connect."); break; default: SendPrivateMessage(sender, "Unknown command '" + cmd_name + "'. Use 'help' for help."); break; } } } } } }