diff --git a/MinecraftClient/ChatBot.cs b/MinecraftClient/ChatBot.cs
index 8fc29e62..9ed626ae 100644
--- a/MinecraftClient/ChatBot.cs
+++ b/MinecraftClient/ChatBot.cs
@@ -8,7 +8,8 @@ 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 folder "Bots".
+ /// Inherit from this class while adding your bot class to the folder "ChatBots".
+ /// Override the methods you want for handling events: Initialize, Update, GetText.
/// 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.
diff --git a/MinecraftClient/Command.cs b/MinecraftClient/Command.cs
new file mode 100644
index 00000000..ea0d2902
--- /dev/null
+++ b/MinecraftClient/Command.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient
+{
+ ///
+ /// Represents an internal MCC command: Command name, source code and usage message
+ /// To add a new command, inherit from this class while adding the command class to the folder "Commands".
+ /// If inheriting from the 'Command' class and placed in the 'Commands' namespace, the command will be
+ /// automatically loaded and available in main chat prompt, scripts, remote control and command help.
+ ///
+
+ public abstract class Command
+ {
+ ///
+ /// The command name
+ ///
+
+ public abstract string CMDName { get; }
+
+ ///
+ /// Usage message, eg: 'name [args]: do something'
+ ///
+
+ public abstract string CMDDesc { get; }
+
+ ///
+ /// Perform the command
+ ///
+ /// The full command, eg: 'mycommand arg1 arg2'
+ /// A confirmation/error message, or "" if no message
+
+ public abstract string Run(McTcpClient handler, string command);
+
+ ///
+ /// Return a list of aliases for this command.
+ /// Override this method if you wish to put aliases to the command
+ ///
+
+ public virtual IEnumerable getCMDAliases() { return new string[0]; }
+
+ ///
+ /// Check if at least one argument has been passed to the command
+ ///
+
+ public static bool hasArg(string command)
+ {
+ int first_space = command.IndexOf(' ');
+ return (first_space > 0 && first_space < command.Length - 1);
+ }
+
+ ///
+ /// Extract the argument string from the command
+ ///
+ /// Argument or "" if no argument
+
+ public static string getArg(string command)
+ {
+ if (hasArg(command))
+ {
+ return command.Substring(command.IndexOf(' ') + 1);
+ }
+ else return "";
+ }
+
+ ///
+ /// Extract the arguments as a string array from the command
+ ///
+ /// Argument array or empty array if no arguments
+
+ public static string[] getArgs(string command)
+ {
+ return getArg(command).Split(' ');
+ }
+ }
+}
diff --git a/MinecraftClient/Commands/Connect.cs b/MinecraftClient/Commands/Connect.cs
new file mode 100644
index 00000000..d36890fd
--- /dev/null
+++ b/MinecraftClient/Commands/Connect.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Commands
+{
+ public class Connect : Command
+ {
+ public override string CMDName { get { return "connect"; } }
+ public override string CMDDesc { get { return "connect : connect to the specified server."; } }
+
+ public override string Run(McTcpClient handler, string command)
+ {
+ if (hasArg(command))
+ {
+ Settings.setServerIP(getArgs(command)[0]);
+ Program.Restart();
+ return "";
+ }
+ else return CMDDesc;
+ }
+ }
+}
diff --git a/MinecraftClient/Commands/Exit.cs b/MinecraftClient/Commands/Exit.cs
new file mode 100644
index 00000000..db26410d
--- /dev/null
+++ b/MinecraftClient/Commands/Exit.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Commands
+{
+ public class Exit : Command
+ {
+ public override string CMDName { get { return "exit"; } }
+ public override string CMDDesc { get { return "exit: disconnect from the server."; } }
+
+ public override string Run(McTcpClient handler, string command)
+ {
+ Program.Exit();
+ return "";
+ }
+
+ public override IEnumerable getCMDAliases()
+ {
+ return new string[] { "quit" };
+ }
+ }
+}
diff --git a/MinecraftClient/Commands/Reco.cs b/MinecraftClient/Commands/Reco.cs
new file mode 100644
index 00000000..a691ae66
--- /dev/null
+++ b/MinecraftClient/Commands/Reco.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Commands
+{
+ public class Reco : Command
+ {
+ public override string CMDName { get { return "reco"; } }
+ public override string CMDDesc { get { return "reco: restart and reconnect to the server."; } }
+
+ public override string Run(McTcpClient handler, string command)
+ {
+ Program.Restart();
+ return "";
+ }
+ }
+}
diff --git a/MinecraftClient/Commands/Respawn.cs b/MinecraftClient/Commands/Respawn.cs
new file mode 100644
index 00000000..ce894e52
--- /dev/null
+++ b/MinecraftClient/Commands/Respawn.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Commands
+{
+ public class Respawn : Command
+ {
+ public override string CMDName { get { return "respawn"; } }
+ public override string CMDDesc { get { return "respawn: respawn after death."; } }
+
+ public override string Run(McTcpClient handler, string command)
+ {
+ handler.SendRespawnPacket();
+ return "You have respawned.";
+ }
+ }
+}
diff --git a/MinecraftClient/Commands/Script.cs b/MinecraftClient/Commands/Script.cs
new file mode 100644
index 00000000..3273b60c
--- /dev/null
+++ b/MinecraftClient/Commands/Script.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Commands
+{
+ public class Script : Command
+ {
+ public override string CMDName { get { return "script"; } }
+ public override string CMDDesc { get { return "script : run a script file."; } }
+
+ public override string Run(McTcpClient handler, string command)
+ {
+ if (hasArg(command))
+ {
+ handler.BotLoad(new ChatBots.Script(getArg(command)));
+ return "";
+ }
+ else return CMDDesc;
+ }
+ }
+}
diff --git a/MinecraftClient/Commands/Send.cs b/MinecraftClient/Commands/Send.cs
new file mode 100644
index 00000000..f47e6450
--- /dev/null
+++ b/MinecraftClient/Commands/Send.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Commands
+{
+ public class Send : Command
+ {
+ public override string CMDName { get { return "send"; } }
+ public override string CMDDesc { get { return "send : send a chat message or command."; } }
+
+ public override string Run(McTcpClient handler, string command)
+ {
+ if (hasArg(command))
+ {
+ handler.SendChatMessage(getArg(command));
+ return "";
+ }
+ else return CMDDesc;
+ }
+ }
+}
diff --git a/MinecraftClient/Commands/Set.cs b/MinecraftClient/Commands/Set.cs
new file mode 100644
index 00000000..9316077a
--- /dev/null
+++ b/MinecraftClient/Commands/Set.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Commands
+{
+ public class Set : Command
+ {
+ public override string CMDName { get { return "set"; } }
+ public override string CMDDesc { get { return "set varname=value: set a custom %variable%."; } }
+
+ public override string Run(McTcpClient handler, string command)
+ {
+ if (hasArg(command))
+ {
+ string[] temp = getArg(command).Split('=');
+ if (temp.Length > 1)
+ {
+ if (Settings.setVar(temp[0], getArg(command).Substring(temp[0].Length + 1)))
+ {
+ return ""; //Success
+ }
+ else return "variable name must be A-Za-z0-9.";
+ }
+ else return CMDDesc;
+ }
+ else return CMDDesc;
+ }
+ }
+}
diff --git a/MinecraftClient/McTcpClient.cs b/MinecraftClient/McTcpClient.cs
index 743632ad..590e19af 100644
--- a/MinecraftClient/McTcpClient.cs
+++ b/MinecraftClient/McTcpClient.cs
@@ -17,6 +17,8 @@ namespace MinecraftClient
public class McTcpClient : IMinecraftComHandler
{
+ private static List cmd_names = new List();
+ private static Dictionary cmds = new Dictionary();
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 = ""; }
@@ -206,91 +208,59 @@ namespace MinecraftClient
public bool performInternalCommand(string command, ref string response_msg)
{
- response_msg = "";
- string[] command_args = command.Split(' ');
- string command_name = command_args[0].ToLower();
- switch (command_name)
+ /* Load commands from the 'Commands' namespace */
+
+ if (cmds.Count == 0)
{
- case "exit":
- case "quit":
- Program.Exit();
- break;
-
- case "reco":
- Program.Restart();
- break;
-
- case "respawn":
- handler.SendRespawnPacket();
- response_msg = "You have respawned.";
- break;
-
- case "send":
- if (command.Length > 5)
+ Type[] cmds_classes = Program.GetTypesInNamespace("MinecraftClient.Commands");
+ foreach (Type type in cmds_classes)
+ {
+ if (type.IsSubclassOf(typeof(Command)))
{
- string text = command.Substring(5);
- SendChatMessage(text);
- }
- else response_msg = "send : send a chat message or command.";
- break;
-
- case "set":
- if (command.Length > 3)
- {
- string[] temp = command.Substring(4).Split('=');
- if (temp.Length > 1)
+ try
{
- if (!Settings.setVar(temp[0], command.Substring(temp[0].Length + 5)))
- {
- response_msg = "variable name must be A-Za-z0-9.";
- }
+ Command cmd = (Command)Activator.CreateInstance(type);
+ cmds[cmd.CMDName.ToLower()] = cmd;
+ cmd_names.Add(cmd.CMDName.ToLower());
+ foreach (string alias in cmd.getCMDAliases())
+ cmds[alias.ToLower()] = cmd;
}
- else response_msg = "set varname=value: set a custom %variable%.";
- }
- else response_msg = "set varname=value: set a custom %variable%.";
- break;
-
- case "script":
- if (command.Length > 8)
- {
- BotLoad(new ChatBots.Script(command.Substring(8)));
- }
- else response_msg = "script : run a script file.";
- break;
-
- case "connect":
- if (command_args.Length > 1)
- {
- Settings.setServerIP(command_args[1]);
- Program.Restart();
- }
- else response_msg = "connect : connect to the specified server.";
- break;
-
- case "help":
- if (command.Length >= 6)
- {
- string help_cmd_name = command.Substring(5).ToLower();
- switch (help_cmd_name)
+ catch (Exception e)
{
- case "quit": response_msg = "quit: disconnect from the server."; break;
- case "exit": response_msg = "exit: disconnect from the server."; break;
- case "reco": response_msg = "reco: restart and reconnct to the server."; break;
- case "respawn": response_msg = "respawn: respawn after death."; break;
- case "send": response_msg = "send : send a chat message or command."; break;
- case "set": response_msg = "set varname=value: set a custom %variable%."; break;
- case "script": response_msg = "script : run a script file."; break;
- case "connect": response_msg = "connect : connect to the specified server."; break;
- case "help": response_msg = "help : show brief help about a command."; break;
- default: response_msg = "help: unknown command '" + help_cmd_name + "'."; break;
+ ConsoleIO.WriteLine(e.Message);
}
}
- else response_msg = "help . Available commands: exit, reco, script, send, connect.";
- break;
+ }
+ }
- default:
- response_msg = "Unknown command '" + command_name + "'. Use 'help' for help.";
- return false;
+ /* Process the provided command */
+
+ string command_name = command.Split(' ')[0].ToLower();
+ if (command_name == "help")
+ {
+ if (Command.hasArg(command))
+ {
+ string help_cmdname = Command.getArgs(command)[0].ToLower();
+ if (help_cmdname == "help")
+ {
+ response_msg = "help : show brief help about a command.";
+ }
+ else if (cmds.ContainsKey(help_cmdname))
+ {
+ response_msg = cmds[help_cmdname].CMDDesc;
+ }
+ else response_msg = "Unknown command '" + command_name + "'. Use 'help' for command list.";
+ }
+ else response_msg = "help . Available commands: " + String.Join(", ", cmd_names.ToArray());
+ }
+ else if (cmds.ContainsKey(command_name))
+ {
+ response_msg = cmds[command_name].Run(this, command);
+ }
+ else
+ {
+ response_msg = "Unknown command '" + command_name + "'. Use 'help' for help.";
+ return false;
}
return true;
}
@@ -404,5 +374,15 @@ namespace MinecraftClient
}
else return handler.SendChatMessage(text);
}
+
+ ///
+ /// Allow to respawn after death
+ ///
+ /// True if packet successfully sent
+
+ public bool SendRespawnPacket()
+ {
+ return handler.SendRespawnPacket();
+ }
}
}
diff --git a/MinecraftClient/MinecraftClient.csproj b/MinecraftClient/MinecraftClient.csproj
index 8add0d36..47f9a771 100644
--- a/MinecraftClient/MinecraftClient.csproj
+++ b/MinecraftClient/MinecraftClient.csproj
@@ -81,6 +81,14 @@
+
+
+
+
+
+
+
+
diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs
index 629520bf..a0265c1e 100644
--- a/MinecraftClient/Program.cs
+++ b/MinecraftClient/Program.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using MinecraftClient.Protocol;
+using System.Reflection;
namespace MinecraftClient
{
@@ -285,5 +286,18 @@ namespace MinecraftClient
if (Client != null) { Client.Disconnect(); ConsoleIO.Reset(); }
Environment.Exit(0);
}
+
+ ///
+ /// Enumerate types in namespace through reflection
+ ///
+ /// Namespace to process
+ /// Assembly to use. Default is Assembly.GetExecutingAssembly()
+ ///
+
+ public static Type[] GetTypesInNamespace(string nameSpace, Assembly assembly = null)
+ {
+ if (assembly == null) { assembly = Assembly.GetExecutingAssembly(); }
+ return assembly.GetTypes().Where(t => String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal)).ToArray();
+ }
}
}