mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-11-07 17:36:07 +00:00
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
This commit is contained in:
parent
3224c59eab
commit
3ce91188c7
22 changed files with 321 additions and 135 deletions
|
|
@ -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)))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue