Add support for C# script extensions

- Allow defining function for use into the script
- Allow defining a ChatBot for loading it into MCC
- Improve sample script and add more examples
- Todo add new documentation into the readme file
This commit is contained in:
ORelio 2015-06-21 18:45:43 +02:00
parent a6b3bf0481
commit e29b4ee545
6 changed files with 115 additions and 26 deletions

View file

@ -33,9 +33,10 @@ namespace MinecraftClient
{ {
public enum DisconnectReason { InGameKick, LoginRejected, ConnectionLost }; public enum DisconnectReason { InGameKick, LoginRejected, ConnectionLost };
//Will be automatically set on bot loading, don't worry about this //Handler will be automatically set on bot loading, don't worry about this
public void SetHandler(McTcpClient handler) { this._handler = handler; } public void SetHandler(McTcpClient handler) { this._handler = handler; }
public void SetMaster(ChatBot master) { this.master = master; } protected void SetMaster(ChatBot master) { this.master = master; }
protected void LoadBot(ChatBot bot) { Handler.BotUnLoad(bot); Handler.BotLoad(bot); }
private McTcpClient Handler { get { return master != null ? master.Handler : _handler; } } private McTcpClient Handler { get { return master != null ? master.Handler : _handler; } }
private McTcpClient _handler = null; private McTcpClient _handler = null;
private ChatBot master = null; private ChatBot master = null;

View file

@ -97,7 +97,7 @@ namespace MinecraftClient.ChatBots
tpause = new ManualResetEvent(false); tpause = new ManualResetEvent(false);
thread = new Thread(() => thread = new Thread(() =>
{ {
if (!RunCSharpScript(String.Join("\n", lines), file, tpause) && owner != null) if (!RunCSharpScript() && owner != null)
SendPrivateMessage(owner, "Script '" + file + "' failed to run."); SendPrivateMessage(owner, "Script '" + file + "' failed to run.");
}); });
thread.Start(); thread.Start();
@ -160,16 +160,37 @@ namespace MinecraftClient.ChatBots
} }
} }
private bool RunCSharpScript(string script, string filename = "C# Script", ManualResetEvent tpause = null) private bool RunCSharpScript()
{ {
//Script compatibility check for handling future versions differently //Script compatibility check for handling future versions differently
if (!script.ToLower().StartsWith("//mccscript 1.0")) if (lines.Length < 1 || lines[0] != "//MCCScript 1.0")
{ {
ConsoleIO.WriteLineFormatted("§8Script file '" + filename + "' does not start with a valid //MCCScript comment."); LogToConsole("Script file '" + file + "' does not start with a valid //MCCScript identifier.");
return false; return false;
} }
//Create a simple ChatBot class from the given script, allowing access to ChatBot API //Process different sections of the script file
bool scriptMain = true;
List<string> script = new List<string>();
List<string> extensions = new List<string>();
foreach (string line in lines)
{
if (line.StartsWith("//MCCScript"))
{
if (line.EndsWith("Extensions"))
scriptMain = false;
}
else if (scriptMain)
{
script.Add(line);
//Add breakpoints for step-by-step execution of the script
if (tpause != null && line.Trim().EndsWith(";"))
script.Add("tpause.WaitOne();");
}
else extensions.Add(line);
}
//Generate a ChatBot class, allowing access to the ChatBot API
string code = String.Join("\n", new string[] string code = String.Join("\n", new string[]
{ {
"using System;", "using System;",
@ -178,12 +199,12 @@ namespace MinecraftClient.ChatBots
"using MinecraftClient;", "using MinecraftClient;",
"namespace ScriptLoader {", "namespace ScriptLoader {",
"public class Script : ChatBot {", "public class Script : ChatBot {",
"public void Run(ChatBot master, ManualResetEvent tpause) {", "public void __run(ChatBot master, ManualResetEvent tpause) {",
"SetMaster(master);", "SetMaster(master);",
tpause != null String.Join("\n", script),
? script.Replace(";\n", ";\ntpause.WaitOne();\n") "}",
: script, String.Join("\n", extensions),
"}}}", "}}",
}); });
//Compile the C# class in memory using all the currently loaded assemblies //Compile the C# class in memory using all the currently loaded assemblies
@ -202,16 +223,16 @@ namespace MinecraftClient.ChatBots
//Process compile warnings and errors //Process compile warnings and errors
if (result.Errors.Count > 0) if (result.Errors.Count > 0)
{ {
ConsoleIO.WriteLineFormatted("§8Error loading '" + filename + "':\n" + result.Errors[0].ErrorText); LogToConsole("Error loading '" + file + "':\n" + result.Errors[0].ErrorText);
return false; return false;
} }
//Run the compiled script with exception handling //Run the compiled script with exception handling
object compiledScript = result.CompiledAssembly.CreateInstance("ScriptLoader.Script"); object compiledScript = result.CompiledAssembly.CreateInstance("ScriptLoader.Script");
try { compiledScript.GetType().GetMethod("Run").Invoke(compiledScript, new object[] { this, tpause }); } try { compiledScript.GetType().GetMethod("__run").Invoke(compiledScript, new object[] { this, tpause }); }
catch (Exception e) catch (Exception e)
{ {
ConsoleIO.WriteLineFormatted("§8Runtime error for '" + filename + "':\n" + e); LogToConsole("Runtime error for '" + file + "':\n" + e);
return false; return false;
} }

View file

@ -94,9 +94,9 @@ namespace MinecraftClient
public static string AutoRespond_Matches = "matches.ini"; public static string AutoRespond_Matches = "matches.ini";
//Custom app variables and Minecraft accounts //Custom app variables and Minecraft accounts
private static Dictionary<string, string> AppVars = new Dictionary<string, string>(); private static readonly Dictionary<string, string> AppVars = new Dictionary<string, string>();
private static Dictionary<string, KeyValuePair<string, string>> Accounts = new Dictionary<string, KeyValuePair<string, string>>(); private static readonly Dictionary<string, KeyValuePair<string, string>> Accounts = new Dictionary<string, KeyValuePair<string, string>>();
private static Dictionary<string, KeyValuePair<string, ushort>> Servers = new Dictionary<string, KeyValuePair<string, ushort>>(); private static readonly Dictionary<string, KeyValuePair<string, ushort>> Servers = new Dictionary<string, KeyValuePair<string, ushort>>();
private enum ParseMode { Default, Main, AppVars, Proxy, AntiAFK, Hangman, Alerts, ChatLog, AutoRelog, ScriptScheduler, RemoteControl, AutoRespond }; private enum ParseMode { Default, Main, AppVars, Proxy, AntiAFK, Hangman, Alerts, ChatLog, AutoRelog, ScriptScheduler, RemoteControl, AutoRespond };
@ -490,6 +490,8 @@ namespace MinecraftClient
/// <returns>True if the parameters were valid</returns> /// <returns>True if the parameters were valid</returns>
public static bool SetVar(string varName, string varData) public static bool SetVar(string varName, string varData)
{
lock (AppVars)
{ {
varName = new string(varName.TakeWhile(char.IsLetterOrDigit).ToArray()).ToLower(); varName = new string(varName.TakeWhile(char.IsLetterOrDigit).ToArray()).ToLower();
if (varName.Length > 0) if (varName.Length > 0)
@ -499,6 +501,7 @@ namespace MinecraftClient
} }
else return false; else return false;
} }
}
/// <summary> /// <summary>
/// Get a custom %variable% or null if the variable does not exist /// Get a custom %variable% or null if the variable does not exist

View file

@ -0,0 +1,30 @@
//MCCScript 1.0
/* This script demonstrates how to add fields and methods */
for (int i = 0; i < 5; i++)
{
int count = GetVarAsInt("test") + 1;
SetVar("test", count);
SendHelloWorld(count);
SleepBetweenSends();
}
//MCCScript Extensions
/* Here you can define methods for use into your script */
void SendHelloWorld(int count)
{
/* Warning: Do not make more than one server-related call into a method
* defined as a script extension eg SendText or switching servers,
* as execution flow is not managed in the Extensions section */
SendText("Hello World no. " + count);
}
void SleepBetweenSends()
{
LogToConsole("Sleeping for 5 seconds...");
Thread.Sleep(5000);
}

View file

@ -0,0 +1,35 @@
//MCCScript 1.0
/* This is a sample script that will load a ChatBot into Minecraft Console Client
* Simply execute the script once with /script or the script scheduler to load the bot */
LoadBot(new ExampleBot());
//MCCScript Extensions
/* The ChatBot class must be defined as an extension of the script in the Extensions section
* The class can override common methods from ChatBot.cs, take a look at MCC's source code */
public class ExampleBot : ChatBot
{
public override void Initialize()
{
LogToConsole("Sucessfully Initialized!");
}
public override void GetText(string text)
{
string message = "";
string username = "";
text = GetVerbatim(text);
if (IsChatMessage(text, ref message, ref username))
{
LogToConsole("Public message from " + username + ": " + message);
}
else if (IsPrivateMessage(text, ref message, ref username))
{
LogToConsole("Private message from " + username + ": " + message);
}
}
}

View file

@ -6,10 +6,9 @@
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{ {
int count = GetVarAsInt("test"); int count = GetVarAsInt("test") + 1;
count++;
SetVar("test", count); SetVar("test", count);
SendText("Hello World no. " + count); SendText("Hello World no. " + count);
PerformInternalCommand("log Sleeping for 5 seconds..."); LogToConsole("Sleeping for 5 seconds...");
Thread.Sleep(5000); Thread.Sleep(5000);
} }