From 3ce91188c7bb16e3882315f832f69f936b18dec7 Mon Sep 17 00:00:00 2001 From: ORelio Date: Sat, 20 Jun 2015 22:58:18 +0200 Subject: [PATCH] Add support for C# scripts in scripting bot - Now scripts can also be written in C# - C# scripts can access ChatBot API - Add more methods in ChatBot API - Add an example of C# script file - Coding style fixes: method names ucfirst --- MinecraftClient/ChatBot.cs | 118 +++++++++--- MinecraftClient/ChatBots/Alerts.cs | 2 +- MinecraftClient/ChatBots/AutoRelog.cs | 2 +- MinecraftClient/ChatBots/AutoRespond.cs | 8 +- MinecraftClient/ChatBots/ChatLog.cs | 8 +- MinecraftClient/ChatBots/HangmanGame.cs | 6 +- MinecraftClient/ChatBots/PlayerListLogger.cs | 2 +- MinecraftClient/ChatBots/RemoteControl.cs | 8 +- MinecraftClient/ChatBots/Script.cs | 173 ++++++++++++++---- MinecraftClient/ChatBots/TestBot.cs | 6 +- MinecraftClient/Commands/Connect.cs | 4 +- MinecraftClient/Commands/List.cs | 2 +- MinecraftClient/Commands/Reco.cs | 2 +- MinecraftClient/Commands/Set.cs | 2 +- MinecraftClient/McTcpClient.cs | 25 +-- MinecraftClient/Program.cs | 16 +- .../Protocol/Handlers/Protocol16.cs | 2 +- .../Protocol/Handlers/Protocol17.cs | 8 +- .../Protocol/Handlers/Protocol18.cs | 8 +- .../Protocol/IMinecraftComHandler.cs | 12 +- MinecraftClient/Settings.cs | 27 ++- MinecraftClient/config/sample-script.cs | 15 ++ 22 files changed, 321 insertions(+), 135 deletions(-) create mode 100644 MinecraftClient/config/sample-script.cs diff --git a/MinecraftClient/ChatBot.cs b/MinecraftClient/ChatBot.cs index 579430cc..59fff3cd 100644 --- a/MinecraftClient/ChatBot.cs +++ b/MinecraftClient/ChatBot.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; +using System.Threading; namespace MinecraftClient { @@ -33,8 +34,11 @@ namespace MinecraftClient public enum DisconnectReason { InGameKick, LoginRejected, ConnectionLost }; //Will be automatically set on bot loading, don't worry about this - public void SetHandler(McTcpClient handler) { this.handler = handler; } - private McTcpClient handler; + public void SetHandler(McTcpClient handler) { this._handler = handler; } + public void SetMaster(ChatBot master) { this.master = master; } + private McTcpClient Handler { get { return master != null ? master.Handler : _handler; } } + private McTcpClient _handler = null; + private ChatBot master = null; /* ================================================== */ /* Main methods to override for creating your bot */ @@ -80,10 +84,12 @@ namespace MinecraftClient /// Text to send to the server /// True if the text was sent with no error - protected bool SendText(string text) + protected bool SendText(object text) { LogToConsole("Sending '" + text + "'"); - return handler.SendText(text); + bool result = Handler.SendText(text is string ? (string)text : text.ToString()); + Thread.Sleep(1000); + return result; } /// @@ -92,10 +98,10 @@ namespace MinecraftClient /// The command to process /// TRUE if the command was indeed an internal MCC command - protected bool performInternalCommand(string command) + protected bool PerformInternalCommand(string command) { string temp = ""; - return handler.performInternalCommand(command, ref temp); + return Handler.PerformInternalCommand(command, ref temp); } /// @@ -105,16 +111,16 @@ namespace MinecraftClient /// May contain a confirmation or error message after processing the command, or "" otherwise. /// TRUE if the command was indeed an internal MCC command - protected bool performInternalCommand(string command, ref string response_msg) + protected bool PerformInternalCommand(string command, ref string response_msg) { - return handler.performInternalCommand(command, ref response_msg); + return Handler.PerformInternalCommand(command, ref response_msg); } /// /// Remove color codes ("§c") from a text message received from the server /// - protected static string getVerbatim(string text) + protected static string GetVerbatim(string text) { if ( String.IsNullOrEmpty(text) ) return String.Empty; @@ -135,7 +141,7 @@ namespace MinecraftClient /// Verify that a string contains only a-z A-Z 0-9 and _ characters. /// - protected static bool isValidName(string username) + protected static bool IsValidName(string username) { if ( String.IsNullOrEmpty(username) ) return false; @@ -158,9 +164,9 @@ namespace MinecraftClient /// 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) + protected static bool IsPrivateMessage(string text, ref string message, ref string sender) { - text = getVerbatim(text); + text = GetVerbatim(text); if (text == "") { return false; } string[] tmp = text.Split(' '); @@ -177,7 +183,7 @@ namespace MinecraftClient } else message = text.Substring(tmp[0].Length + 10); //MC 1.5 sender = tmp[0]; - return isValidName(sender); + return IsValidName(sender); } //Detect Essentials (Bukkit) /m messages @@ -189,7 +195,7 @@ namespace MinecraftClient 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); + return IsValidName(sender); } //Detect Essentials (Bukkit) /me messages with some custom rank @@ -201,7 +207,7 @@ namespace MinecraftClient message = text.Substring(tmp[0].Length + 1 + tmp[1].Length + 4 + tmp[2].Length + 1); sender = tmp[0].Substring(1); if (sender[0] == '~') { sender = sender.Substring(1); } - return isValidName(sender); + return IsValidName(sender); } //Detect HeroChat PMsend @@ -210,7 +216,7 @@ namespace MinecraftClient { sender = text.Substring(5).Split(':')[0]; message = text.Substring(text.IndexOf(':') + 2); - return isValidName(sender); + return IsValidName(sender); } else return false; @@ -226,10 +232,10 @@ namespace MinecraftClient /// 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) + protected static bool IsChatMessage(string text, ref string message, ref string sender) { - text = getVerbatim(text); + text = GetVerbatim(text); string[] tmp = text.Split(' '); if (text.Length > 0) { @@ -251,7 +257,7 @@ namespace MinecraftClient tmp2 = sender.Split(' '); sender = tmp2[tmp2.Length - 1]; if (sender[0] == '~') { sender = sender.Substring(1); } - return isValidName(sender); + return IsValidName(sender); } catch (IndexOutOfRangeException) { return false; } } @@ -264,7 +270,7 @@ namespace MinecraftClient int name_start = text.Substring(0, name_end).LastIndexOf(']') + 2; sender = text.Substring(name_start, name_end - name_start); message = text.Substring(name_end + 2); - return isValidName(sender); + return IsValidName(sender); } } return false; @@ -277,14 +283,14 @@ namespace MinecraftClient /// Will contain the sender's username, if it's a teleport request /// Returns true if the text is a teleport request - protected static bool isTeleportRequest(string text, ref string sender) + protected static bool IsTeleportRequest(string text, ref string sender) { - text = getVerbatim(text); + text = GetVerbatim(text); sender = text.Split(' ')[0]; if (text.EndsWith("has requested to teleport to you.") || text.EndsWith("has requested that you teleport to them.")) { - return isValidName(sender); + return IsValidName(sender); } else return false; } @@ -294,10 +300,10 @@ namespace MinecraftClient /// /// Log text to write - public static void LogToConsole(string text) + public static void LogToConsole(object text) { ConsoleIO.WriteLineFormatted("§8[BOT] " + text); - string logfile = Settings.expandVars(Settings.chatbotLogFile); + string logfile = Settings.ExpandVars(Settings.chatbotLogFile); if (!String.IsNullOrEmpty(logfile)) { @@ -309,7 +315,7 @@ namespace MinecraftClient catch { return; /* Invalid file name or access denied */ } } - File.AppendAllLines(logfile, new string[] { getTimestamp() + ' ' + text }); + File.AppendAllLines(logfile, new string[] { GetTimestamp() + ' ' + text }); } } @@ -340,7 +346,7 @@ namespace MinecraftClient protected void UnloadBot() { - handler.BotUnLoad(this); + Handler.BotUnLoad(this); } /// @@ -362,14 +368,14 @@ namespace MinecraftClient protected void RunScript(string filename, string playername = "") { - handler.BotLoad(new ChatBots.Script(filename, playername)); + Handler.BotLoad(new ChatBots.Script(filename, playername)); } /// /// Get a Y-M-D h:m:s timestamp representing the current system date and time /// - protected static string getTimestamp() + protected static string GetTimestamp() { DateTime time = DateTime.Now; return String.Format("{0}-{1}-{2} {3}:{4}:{5}", @@ -404,5 +410,59 @@ namespace MinecraftClient return new string[0]; } } + + /// + /// Set a custom %variable% which will be available through expandVars() + /// + /// Name of the variable + /// Value of the variable + /// True if the parameters were valid + + protected static bool SetVar(string varName, object varData) + { + return Settings.SetVar(varName, varData.ToString()); + } + + /// + /// Get a custom %variable% or null if the variable does not exist + /// + /// Variable name + /// The value or null if the variable does not exists + + protected static string GetVar(string varName) + { + return Settings.GetVar(varName); + } + + /// + /// Get a custom %variable% as an Integer or null if the variable does not exist + /// + /// Variable name + /// The value or null if the variable does not exists + + protected static int GetVarAsInt(string varName) + { + return Settings.str2int(Settings.GetVar(varName)); + } + + /// + /// Load login/password using an account alias + /// + /// True if the account was found and loaded + + protected static bool SetAccount(string accountAlias) + { + return Settings.SetAccount(accountAlias); + } + + /// + /// Load server information in ServerIP and ServerPort variables from a "serverip:port" couple or server alias + /// + /// True if the server IP was valid and loaded, false otherwise + + protected static bool SetServerIP(string server) + { + return Settings.SetServerIP(server); + } } } diff --git a/MinecraftClient/ChatBots/Alerts.cs b/MinecraftClient/ChatBots/Alerts.cs index cd21bae4..9ad12b2b 100644 --- a/MinecraftClient/ChatBots/Alerts.cs +++ b/MinecraftClient/ChatBots/Alerts.cs @@ -30,7 +30,7 @@ namespace MinecraftClient.ChatBots public override void GetText(string text) { //Remove color codes and convert to lowercase - text = getVerbatim(text).ToLower(); + text = GetVerbatim(text).ToLower(); //Proceed only if no exclusions are found in text if (!excludelist.Any(exclusion => text.Contains(exclusion))) diff --git a/MinecraftClient/ChatBots/AutoRelog.cs b/MinecraftClient/ChatBots/AutoRelog.cs index 19d831f5..d98e30d5 100644 --- a/MinecraftClient/ChatBots/AutoRelog.cs +++ b/MinecraftClient/ChatBots/AutoRelog.cs @@ -47,7 +47,7 @@ namespace MinecraftClient.ChatBots public override bool OnDisconnect(DisconnectReason reason, string message) { - message = getVerbatim(message); + message = GetVerbatim(message); string comp = message.ToLower(); foreach (string msg in dictionary) { diff --git a/MinecraftClient/ChatBots/AutoRespond.cs b/MinecraftClient/ChatBots/AutoRespond.cs index 52a14944..567b38b0 100644 --- a/MinecraftClient/ChatBots/AutoRespond.cs +++ b/MinecraftClient/ChatBots/AutoRespond.cs @@ -182,14 +182,14 @@ namespace MinecraftClient.ChatBots public override void GetText(string text) { //Remove colour codes - text = getVerbatim(text).ToLower(); + text = GetVerbatim(text).ToLower(); //Check if this is a valid message string sender = "", message = ""; - bool chatMessage = isChatMessage(text, ref message, ref sender); + bool chatMessage = IsChatMessage(text, ref message, ref sender); bool privateMessage = false; if (!chatMessage) - privateMessage = isPrivateMessage(text, ref message, ref sender); + privateMessage = IsPrivateMessage(text, ref message, ref sender); //Process only chat messages sent by another user if ((chatMessage || privateMessage) && sender != Settings.Username) @@ -201,7 +201,7 @@ namespace MinecraftClient.ChatBots { string response = null; LogToConsole(header + toPerform); - performInternalCommand(toPerform, ref response); + PerformInternalCommand(toPerform, ref response); if (!String.IsNullOrEmpty(response)) LogToConsole(header + response); } diff --git a/MinecraftClient/ChatBots/ChatLog.cs b/MinecraftClient/ChatBots/ChatLog.cs index 7d4acc07..54468253 100644 --- a/MinecraftClient/ChatBots/ChatLog.cs +++ b/MinecraftClient/ChatBots/ChatLog.cs @@ -69,15 +69,15 @@ namespace MinecraftClient.ChatBots public override void GetText(string text) { - text = getVerbatim(text); + text = GetVerbatim(text); string sender = ""; string message = ""; - if (saveChat && isChatMessage(text, ref message, ref sender)) + if (saveChat && IsChatMessage(text, ref message, ref sender)) { save("Chat " + sender + ": " + message); } - else if (savePrivate && isPrivateMessage(text, ref message, ref sender)) + else if (savePrivate && IsPrivateMessage(text, ref message, ref sender)) { save("Private " + sender + ": " + message); } @@ -90,7 +90,7 @@ namespace MinecraftClient.ChatBots private void save(string tosave) { if (dateandtime) - tosave = getTimestamp() + ' ' + tosave; + tosave = GetTimestamp() + ' ' + tosave; string directory = Path.GetDirectoryName(logfile); if (!String.IsNullOrEmpty(directory) && !Directory.Exists(directory)) diff --git a/MinecraftClient/ChatBots/HangmanGame.cs b/MinecraftClient/ChatBots/HangmanGame.cs index 9b11cc2c..0ea3c2ea 100644 --- a/MinecraftClient/ChatBots/HangmanGame.cs +++ b/MinecraftClient/ChatBots/HangmanGame.cs @@ -52,9 +52,9 @@ namespace MinecraftClient.ChatBots { string message = ""; string username = ""; - text = getVerbatim(text); + text = GetVerbatim(text); - if (isPrivateMessage(text, ref message, ref username)) + if (IsPrivateMessage(text, ref message, ref username)) { if (Settings.Bots_Owners.Contains(username.ToLower())) { @@ -73,7 +73,7 @@ namespace MinecraftClient.ChatBots } else { - if (running && isChatMessage(text, ref message, ref username)) + if (running && IsChatMessage(text, ref message, ref username)) { if (message.Length == 1) { diff --git a/MinecraftClient/ChatBots/PlayerListLogger.cs b/MinecraftClient/ChatBots/PlayerListLogger.cs index 9124b664..1d1c5cb9 100644 --- a/MinecraftClient/ChatBots/PlayerListLogger.cs +++ b/MinecraftClient/ChatBots/PlayerListLogger.cs @@ -46,7 +46,7 @@ namespace MinecraftClient.ChatBots 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"); + System.IO.File.AppendAllText(file, TimeStamp + "\n" + GetVerbatim(text) + "\n\n"); } } } diff --git a/MinecraftClient/ChatBots/RemoteControl.cs b/MinecraftClient/ChatBots/RemoteControl.cs index dfdf5d2a..300beb02 100644 --- a/MinecraftClient/ChatBots/RemoteControl.cs +++ b/MinecraftClient/ChatBots/RemoteControl.cs @@ -13,19 +13,19 @@ namespace MinecraftClient.ChatBots { public override void GetText(string text) { - text = getVerbatim(text); + text = GetVerbatim(text); string command = "", sender = ""; - if (isPrivateMessage(text, ref command, ref sender) && Settings.Bots_Owners.Contains(sender.ToLower().Trim())) + if (IsPrivateMessage(text, ref command, ref sender) && Settings.Bots_Owners.Contains(sender.ToLower().Trim())) { string response = ""; - performInternalCommand(command, ref response); + PerformInternalCommand(command, ref response); if (response.Length > 0) { SendPrivateMessage(sender, response); } } else if (Settings.RemoteCtrl_AutoTpaccept - && isTeleportRequest(text, ref sender) + && IsTeleportRequest(text, ref sender) && (Settings.RemoteCtrl_AutoTpaccept_Everyone || Settings.Bots_Owners.Contains(sender.ToLower().Trim()))) { SendText("/tpaccept"); diff --git a/MinecraftClient/ChatBots/Script.cs b/MinecraftClient/ChatBots/Script.cs index cb96ffa8..44ae5891 100644 --- a/MinecraftClient/ChatBots/Script.cs +++ b/MinecraftClient/ChatBots/Script.cs @@ -2,6 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; +using Microsoft.CSharp; +using System.CodeDom.Compiler; namespace MinecraftClient.ChatBots { @@ -14,9 +17,11 @@ namespace MinecraftClient.ChatBots 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; + private bool csharp; + private Thread thread; + private ManualResetEvent tpause; public Script(string filename) { @@ -38,10 +43,13 @@ namespace MinecraftClient.ChatBots { filename, filename + ".txt", + filename + ".cs", "scripts" + dir_slash + filename, "scripts" + dir_slash + filename + ".txt", + "scripts" + dir_slash + filename + ".cs", "config" + dir_slash + filename, "config" + dir_slash + filename + ".txt", + "config" + dir_slash + filename + ".cs", }; foreach (string possible_file in files) @@ -62,63 +70,152 @@ namespace MinecraftClient.ChatBots if (lookForScript(ref file)) { lines = System.IO.File.ReadAllLines(file); - if (owner != null) { SendPrivateMessage(owner, "Script '" + file + "' loaded."); } + csharp = file.EndsWith(".cs"); + thread = null; + + 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 (csharp) //C# compiled script { - if (nextline < lines.Length) //Is there an instruction left to interpret? + //Initialize thread on first update + if (thread == null) { - 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) + tpause = new ManualResetEvent(false); + thread = new Thread(() => { - if (instruction_line[0] != '#' && instruction_line[0] != '/' && instruction_line[1] != '/') - { - instruction_line = Settings.expandVars(instruction_line); - string instruction_name = instruction_line.Split(' ')[0]; - switch (instruction_name.ToLower()) - { - case "wait": - int ticks = 10; - try - { - ticks = Convert.ToInt32(instruction_line.Substring(5, instruction_line.Length - 5)); - } - catch { } - sleepticks = ticks; - break; - default: - if (!performInternalCommand(instruction_line)) - { - sleepticks = 0; Update(); //Unknown command : process next line immediately - } - else if (instruction_name.ToLower() != "log") { LogToConsole(instruction_line); } - break; - } - } - else { sleepticks = 0; Update(); } //Comment: process next line immediately - } + if (!RunCSharpScript(String.Join("\n", lines), file, tpause) && owner != null) + SendPrivateMessage(owner, "Script '" + file + "' failed to run."); + }); + thread.Start(); } + + //Let the thread run for a short span of time + if (thread != null) + { + tpause.Set(); + tpause.Reset(); + if (thread.Join(100)) + UnloadBot(); + } + } + else //Classic MCC script interpreter + { + if (sleepticks > 0) { sleepticks--; } else { - //No more instructions to interpret - UnloadBot(); + 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 + + if (instruction_line.Length > 1) + { + if (instruction_line[0] != '#' && instruction_line[0] != '/' && instruction_line[1] != '/') + { + instruction_line = Settings.ExpandVars(instruction_line); + string instruction_name = instruction_line.Split(' ')[0]; + switch (instruction_name.ToLower()) + { + case "wait": + int ticks = 10; + try + { + ticks = Convert.ToInt32(instruction_line.Substring(5, instruction_line.Length - 5)); + } + catch { } + sleepticks = ticks; + break; + default: + if (!PerformInternalCommand(instruction_line)) + { + Update(); //Unknown command : process next line immediately + } + else if (instruction_name.ToLower() != "log") { LogToConsole(instruction_line); } + break; + } + } + else { Update(); } //Comment: process next line immediately + } + } + else + { + //No more instructions to interpret + UnloadBot(); + } } } } + + private bool RunCSharpScript(string script, string filename = "C# Script", ManualResetEvent tpause = null) + { + //Script compatibility check for handling future versions differently + if (!script.ToLower().StartsWith("//mccscript 1.0")) + { + ConsoleIO.WriteLineFormatted("§8Script file '" + filename + "' does not start with a valid //MCCScript comment."); + return false; + } + + //Create a simple ChatBot class from the given script, allowing access to ChatBot API + string code = String.Join("\n", new string[] + { + "using System;", + "using System.IO;", + "using System.Threading;", + "using MinecraftClient;", + "namespace ScriptLoader {", + "public class Script : ChatBot {", + "public void Run(ChatBot master, ManualResetEvent tpause) {", + "SetMaster(master);", + tpause != null + ? script.Replace(";\n", ";\ntpause.WaitOne();\n") + : script, + "}}}", + }); + + //Compile the C# class in memory using all the currently loaded assemblies + CSharpCodeProvider compiler = new CSharpCodeProvider(); + CompilerParameters parameters = new CompilerParameters(); + parameters.ReferencedAssemblies + .AddRange(AppDomain.CurrentDomain + .GetAssemblies() + .Where(a => !a.IsDynamic) + .Select(a => a.Location).ToArray()); + parameters.CompilerOptions = "/t:library"; + parameters.GenerateInMemory = true; + CompilerResults result + = compiler.CompileAssemblyFromSource(parameters, code); + + //Process compile warnings and errors + if (result.Errors.Count > 0) + { + ConsoleIO.WriteLineFormatted("§8Error loading '" + filename + "':\n" + result.Errors[0].ErrorText); + return false; + } + + //Run the compiled script with exception handling + object compiledScript = result.CompiledAssembly.CreateInstance("ScriptLoader.Script"); + try { compiledScript.GetType().GetMethod("Run").Invoke(compiledScript, new object[] { this, tpause }); } + catch (Exception e) + { + ConsoleIO.WriteLineFormatted("§8Runtime error for '" + filename + "':\n" + e); + return false; + } + + return true; + } } } diff --git a/MinecraftClient/ChatBots/TestBot.cs b/MinecraftClient/ChatBots/TestBot.cs index ffd921f8..ce6ef8f7 100644 --- a/MinecraftClient/ChatBots/TestBot.cs +++ b/MinecraftClient/ChatBots/TestBot.cs @@ -15,13 +15,13 @@ namespace MinecraftClient.ChatBots { string message = ""; string username = ""; - text = getVerbatim(text); + text = GetVerbatim(text); - if (isPrivateMessage(text, ref message, ref username)) + if (IsPrivateMessage(text, ref message, ref username)) { ConsoleIO.WriteLine("Bot: " + username + " told me : " + message); } - else if (isChatMessage(text, ref message, ref username)) + else if (IsChatMessage(text, ref message, ref username)) { ConsoleIO.WriteLine("Bot: " + username + " said : " + message); } diff --git a/MinecraftClient/Commands/Connect.cs b/MinecraftClient/Commands/Connect.cs index 3d57dbd3..4e92ecc9 100644 --- a/MinecraftClient/Commands/Connect.cs +++ b/MinecraftClient/Commands/Connect.cs @@ -17,13 +17,13 @@ namespace MinecraftClient.Commands string[] args = getArgs(command); if (args.Length > 1) { - if (!Settings.setAccount(args[1])) + if (!Settings.SetAccount(args[1])) { return "Unknown account '" + args[1] + "'."; } } - if (Settings.setServerIP(args[0])) + if (Settings.SetServerIP(args[0])) { Program.Restart(); return ""; diff --git a/MinecraftClient/Commands/List.cs b/MinecraftClient/Commands/List.cs index 116085d0..da9368e0 100644 --- a/MinecraftClient/Commands/List.cs +++ b/MinecraftClient/Commands/List.cs @@ -12,7 +12,7 @@ namespace MinecraftClient.Commands public override string Run(McTcpClient handler, string command) { - return "PlayerList: " + String.Join(", ", handler.getOnlinePlayers()); + return "PlayerList: " + String.Join(", ", handler.GetOnlinePlayers()); } } } diff --git a/MinecraftClient/Commands/Reco.cs b/MinecraftClient/Commands/Reco.cs index 520f4fea..49e18e76 100644 --- a/MinecraftClient/Commands/Reco.cs +++ b/MinecraftClient/Commands/Reco.cs @@ -15,7 +15,7 @@ namespace MinecraftClient.Commands string[] args = getArgs(command); if (args.Length > 0) { - if (!Settings.setAccount(args[0])) + if (!Settings.SetAccount(args[0])) { return "Unknown account '" + args[0] + "'."; } diff --git a/MinecraftClient/Commands/Set.cs b/MinecraftClient/Commands/Set.cs index 9316077a..5fc2adab 100644 --- a/MinecraftClient/Commands/Set.cs +++ b/MinecraftClient/Commands/Set.cs @@ -17,7 +17,7 @@ namespace MinecraftClient.Commands string[] temp = getArg(command).Split('='); if (temp.Length > 1) { - if (Settings.setVar(temp[0], getArg(command).Substring(temp[0].Length + 1))) + if (Settings.SetVar(temp[0], getArg(command).Substring(temp[0].Length + 1))) { return ""; //Success } diff --git a/MinecraftClient/McTcpClient.cs b/MinecraftClient/McTcpClient.cs index 46b40c59..769c2d02 100644 --- a/MinecraftClient/McTcpClient.cs +++ b/MinecraftClient/McTcpClient.cs @@ -34,11 +34,11 @@ namespace MinecraftClient 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; } + 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; @@ -101,10 +101,10 @@ namespace MinecraftClient 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.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.ScriptScheduler_Enabled) { BotLoad(new ChatBots.ScriptScheduler(Settings.ExpandVars(Settings.ScriptScheduler_TasksFile))); } if (Settings.RemoteCtrl_Enabled) { BotLoad(new ChatBots.RemoteControl()); } if (Settings.AutoRespond_Enabled) { BotLoad(new ChatBots.AutoRespond(Settings.AutoRespond_Matches)); } } @@ -209,7 +209,7 @@ namespace MinecraftClient { string response_msg = ""; string command = Settings.internalCmdChar == ' ' ? text : text.Substring(1); - if (!performInternalCommand(Settings.expandVars(command), ref response_msg) && Settings.internalCmdChar == '/') + if (!PerformInternalCommand(Settings.ExpandVars(command), ref response_msg) && Settings.internalCmdChar == '/') { SendText(text); } @@ -234,7 +234,7 @@ namespace MinecraftClient /// May contain a confirmation or error message after processing the command, or "" otherwise. /// TRUE if the command was indeed an internal MCC command - public bool performInternalCommand(string command, ref string response_msg) + public bool PerformInternalCommand(string command, ref string response_msg) { /* Load commands from the 'Commands' namespace */ @@ -314,7 +314,8 @@ namespace MinecraftClient Thread.Sleep(1000); - if (client != null) { client.Close(); } + if (client != null) + client.Close(); } /// @@ -476,7 +477,7 @@ namespace MinecraftClient /// /// Online player names - public string[] getOnlinePlayers() + public string[] GetOnlinePlayers() { lock (onlinePlayers) { diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index 6fc954de..2beabf47 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -63,7 +63,7 @@ namespace MinecraftClient Settings.Password = args[1]; if (args.Length >= 3) { - Settings.setServerIP(args[2]); + Settings.SetServerIP(args[2]); //Single command? if (args.Length >= 4) @@ -77,7 +77,7 @@ namespace MinecraftClient if (Settings.ConsoleTitle != "") { Settings.Username = "New Window"; - Console.Title = Settings.expandVars(Settings.ConsoleTitle); + Console.Title = Settings.ExpandVars(Settings.ConsoleTitle); } //Asking the user to type in missing data such as Username and Password @@ -130,7 +130,7 @@ namespace MinecraftClient if (result == ProtocolHandler.LoginResult.Success) { if (Settings.ConsoleTitle != "") - Console.Title = Settings.expandVars(Settings.ConsoleTitle); + Console.Title = Settings.ExpandVars(Settings.ConsoleTitle); if (Settings.playerHeadAsIcon) ConsoleIcon.setPlayerIconAsync(Settings.Username); @@ -140,7 +140,7 @@ namespace MinecraftClient if (Settings.ServerIP == "") { Console.Write("Server IP : "); - Settings.setServerIP(Console.ReadLine()); + Settings.SetServerIP(Console.ReadLine()); } //Get server version @@ -186,7 +186,7 @@ namespace MinecraftClient //Update console title if (Settings.ConsoleTitle != "") - Console.Title = Settings.expandVars(Settings.ConsoleTitle); + Console.Title = Settings.ExpandVars(Settings.ConsoleTitle); } catch (NotSupportedException) { HandleFailure("Cannot connect to the server : This version is not supported !", true); } } @@ -306,15 +306,15 @@ namespace MinecraftClient if (command.StartsWith("reco")) { - message = new Commands.Reco().Run(null, Settings.expandVars(command)); + message = new Commands.Reco().Run(null, Settings.ExpandVars(command)); } else if (command.StartsWith("connect")) { - message = new Commands.Connect().Run(null, Settings.expandVars(command)); + message = new Commands.Connect().Run(null, Settings.ExpandVars(command)); } else if (command.StartsWith("exit") || command.StartsWith("quit")) { - message = new Commands.Exit().Run(null, Settings.expandVars(command)); + message = new Commands.Exit().Run(null, Settings.ExpandVars(command)); } else if (command.StartsWith("help")) { diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index 38686d17..4acf4447 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -505,7 +505,7 @@ namespace MinecraftClient.Protocol.Handlers public bool Login() { - if (Handshake(handler.getUserUUID(), handler.getUsername(), handler.getSessionID(), handler.getServerHost(), handler.getServerPort())) + if (Handshake(handler.GetUserUUID(), handler.GetUsername(), handler.GetSessionID(), handler.GetServerHost(), handler.GetServerPort())) { Send(new byte[] { 0xCD, 0 }); try diff --git a/MinecraftClient/Protocol/Handlers/Protocol17.cs b/MinecraftClient/Protocol/Handlers/Protocol17.cs index b7c08e37..7d74e80b 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol17.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol17.cs @@ -349,16 +349,16 @@ namespace MinecraftClient.Protocol.Handlers { byte[] packet_id = getVarInt(0); byte[] protocol_version = getVarInt(protocolversion); - byte[] server_adress_val = Encoding.UTF8.GetBytes(handler.getServerHost()); + byte[] server_adress_val = Encoding.UTF8.GetBytes(handler.GetServerHost()); byte[] server_adress_len = getVarInt(server_adress_val.Length); - byte[] server_port = BitConverter.GetBytes((ushort)handler.getServerPort()); Array.Reverse(server_port); + byte[] server_port = BitConverter.GetBytes((ushort)handler.GetServerPort()); Array.Reverse(server_port); byte[] next_state = getVarInt(2); byte[] handshake_packet = concatBytes(packet_id, protocol_version, server_adress_len, server_adress_val, server_port, next_state); byte[] handshake_packet_tosend = concatBytes(getVarInt(handshake_packet.Length), handshake_packet); Send(handshake_packet_tosend); - byte[] username_val = Encoding.UTF8.GetBytes(handler.getUsername()); + byte[] username_val = Encoding.UTF8.GetBytes(handler.GetUsername()); byte[] username_len = getVarInt(username_val.Length); byte[] login_packet = concatBytes(packet_id, username_len, username_val); byte[] login_packet_tosend = concatBytes(getVarInt(login_packet.Length), login_packet); @@ -377,7 +377,7 @@ namespace MinecraftClient.Protocol.Handlers string serverID = readNextString(); byte[] Serverkey = readNextByteArray(); byte[] token = readNextByteArray(); - return StartEncryption(handler.getUserUUID(), handler.getSessionID(), token, serverID, Serverkey); + return StartEncryption(handler.GetUserUUID(), handler.GetSessionID(), token, serverID, Serverkey); } else if (pid == 0x02) //Login successful { diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 67fb96ca..509bfb92 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -449,15 +449,15 @@ namespace MinecraftClient.Protocol.Handlers public bool Login() { byte[] protocol_version = getVarInt(protocolversion); - byte[] server_adress_val = Encoding.UTF8.GetBytes(handler.getServerHost()); + byte[] server_adress_val = Encoding.UTF8.GetBytes(handler.GetServerHost()); byte[] server_adress_len = getVarInt(server_adress_val.Length); - byte[] server_port = BitConverter.GetBytes((ushort)handler.getServerPort()); Array.Reverse(server_port); + byte[] server_port = BitConverter.GetBytes((ushort)handler.GetServerPort()); Array.Reverse(server_port); byte[] next_state = getVarInt(2); byte[] handshake_packet = concatBytes(protocol_version, server_adress_len, server_adress_val, server_port, next_state); SendPacket(0x00, handshake_packet); - byte[] username_val = Encoding.UTF8.GetBytes(handler.getUsername()); + byte[] username_val = Encoding.UTF8.GetBytes(handler.GetUsername()); byte[] username_len = getVarInt(username_val.Length); byte[] login_packet = concatBytes(username_len, username_val); @@ -478,7 +478,7 @@ namespace MinecraftClient.Protocol.Handlers string serverID = readNextString(ref packetData); byte[] Serverkey = readNextByteArray(ref packetData); byte[] token = readNextByteArray(ref packetData); - return StartEncryption(handler.getUserUUID(), handler.getSessionID(), token, serverID, Serverkey); + return StartEncryption(handler.GetUserUUID(), handler.GetSessionID(), token, serverID, Serverkey); } else if (packetID == 0x02) //Login successful { diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs index f74d22a4..79f8659e 100644 --- a/MinecraftClient/Protocol/IMinecraftComHandler.cs +++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs @@ -16,12 +16,12 @@ namespace MinecraftClient.Protocol /* The MinecraftCom Hanler must * provide these getters */ - int getServerPort(); - string getServerHost(); - string getUsername(); - string getUserUUID(); - string getSessionID(); - string[] getOnlinePlayers(); + int GetServerPort(); + string GetServerHost(); + string GetUsername(); + string GetUserUUID(); + string GetSessionID(); + string[] GetOnlinePlayers(); /// /// This method is called when the protocol handler receives a chat message diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index b7daa524..735de5cd 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -149,7 +149,7 @@ namespace MinecraftClient { case "login": Login = argValue; break; case "password": Password = argValue; break; - case "serverip": setServerIP(argValue); break; + case "serverip": SetServerIP(argValue); break; case "singlecommand": SingleCommand = argValue; break; case "language": Language = argValue; break; case "consoletitle": ConsoleTitle = argValue; break; @@ -204,7 +204,7 @@ namespace MinecraftClient if (server_data.Length == 2 && server_data[0] != "localhost" && !server_data[0].Contains('.') - && setServerIP(server_data[1])) + && SetServerIP(server_data[1])) Servers[server_data[0]] = new KeyValuePair(ServerIP, ServerPort); } @@ -313,7 +313,7 @@ namespace MinecraftClient break; case ParseMode.AppVars: - setVar(argName, argValue); + SetVar(argName, argValue); break; case ParseMode.AutoRespond: @@ -433,7 +433,7 @@ namespace MinecraftClient /// /// True if the account was found and loaded - public static bool setAccount(string accountAlias) + public static bool SetAccount(string accountAlias) { accountAlias = accountAlias.ToLower(); if (Accounts.ContainsKey(accountAlias)) @@ -450,7 +450,7 @@ namespace MinecraftClient /// /// True if the server IP was valid and loaded, false otherwise - public static bool setServerIP(string server) + public static bool SetServerIP(string server) { server = server.ToLower(); string[] sip = server.Split(':'); @@ -489,7 +489,7 @@ namespace MinecraftClient /// Value of the variable /// True if the parameters were valid - public static bool setVar(string varName, string varData) + public static bool SetVar(string varName, string varData) { varName = new string(varName.TakeWhile(char.IsLetterOrDigit).ToArray()).ToLower(); if (varName.Length > 0) @@ -500,13 +500,26 @@ namespace MinecraftClient else return false; } + /// + /// Get a custom %variable% or null if the variable does not exist + /// + /// Variable name + /// The value or null if the variable does not exists + + public static string GetVar(string varName) + { + if (AppVars.ContainsKey(varName)) + return AppVars[varName]; + return null; + } + /// /// Replace %variables% with their value /// /// String to parse /// Modifier string - public static string expandVars(string str) + public static string ExpandVars(string str) { StringBuilder result = new StringBuilder(); for (int i = 0; i < str.Length; i++) diff --git a/MinecraftClient/config/sample-script.cs b/MinecraftClient/config/sample-script.cs new file mode 100644 index 00000000..6240c46a --- /dev/null +++ b/MinecraftClient/config/sample-script.cs @@ -0,0 +1,15 @@ +//MCCScript 1.0 + +/* This is a sample script for Minecraft Console Client + * The code provided in this file will be compiled at runtime and executed + * Allowed instructions: Any C# code AND all methods provided by the bot API */ + +for (int i = 0; i < 5; i++) +{ + int count = GetVarAsInt("test"); + count++; + SetVar("test", count); + SendText("Hello World no. " + count); + PerformInternalCommand("log Sleeping for 5 seconds..."); + Thread.Sleep(5000); +} \ No newline at end of file