mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-15 13:04:36 +00:00
Fixed Script Scheduler bug
This commit is contained in:
parent
5b13e740ef
commit
a5423211ad
6 changed files with 131 additions and 55 deletions
|
|
@ -25,6 +25,7 @@ namespace MinecraftClient.ChatBots
|
|||
private bool csharp;
|
||||
private Thread? thread;
|
||||
private readonly Dictionary<string, object>? localVars;
|
||||
private readonly string? scriptOwnerKey;
|
||||
|
||||
public Script(string filename)
|
||||
{
|
||||
|
|
@ -38,6 +39,13 @@ namespace MinecraftClient.ChatBots
|
|||
this.localVars = localVars;
|
||||
}
|
||||
|
||||
internal Script(string filename, string? ownername, Dictionary<string, object>? localVars, string? scriptOwnerKey)
|
||||
: this(filename, ownername, localVars)
|
||||
{
|
||||
this.scriptOwnerKey = scriptOwnerKey;
|
||||
SetScriptOwnerKey(scriptOwnerKey);
|
||||
}
|
||||
|
||||
private void ParseArguments(string argstr)
|
||||
{
|
||||
List<string> args = new();
|
||||
|
|
@ -166,7 +174,7 @@ namespace MinecraftClient.ChatBots
|
|||
{
|
||||
try
|
||||
{
|
||||
CSharpRunner.Run(this, lines, args, localVars, scriptName: file!);
|
||||
CSharpRunner.Run(this, lines, args, localVars, scriptName: file!, scriptOwnerKey: scriptOwnerKey);
|
||||
}
|
||||
catch (CSharpException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -183,64 +183,54 @@ namespace MinecraftClient.ChatBots
|
|||
private int verifytasks_timeleft = Settings.ClientTicksPerSecond;
|
||||
private readonly int verifytasks_delay = Settings.ClientTicksPerSecond;
|
||||
|
||||
public override void AfterGameJoined()
|
||||
{
|
||||
if (serverlogin_done)
|
||||
return;
|
||||
|
||||
serverlogin_done = true;
|
||||
verifytasks_timeleft = verifytasks_delay;
|
||||
RunLoginTasks();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (!serverlogin_done)
|
||||
return;
|
||||
|
||||
if (verifytasks_timeleft <= 0)
|
||||
{
|
||||
verifytasks_timeleft = verifytasks_delay;
|
||||
if (serverlogin_done)
|
||||
for (int taskIndex = 0; taskIndex < Config.TaskList.Length; taskIndex++)
|
||||
{
|
||||
foreach (TaskConfig task in Config.TaskList)
|
||||
TaskConfig task = Config.TaskList[taskIndex];
|
||||
if (task.Trigger_On_Times.Enable)
|
||||
{
|
||||
if (task.Trigger_On_Times.Enable)
|
||||
{
|
||||
bool matching_time_found = false;
|
||||
bool matching_time_found = false;
|
||||
|
||||
foreach (TimeSpan time in task.Trigger_On_Times.Times)
|
||||
foreach (TimeSpan time in task.Trigger_On_Times.Times)
|
||||
{
|
||||
if (time.Hours == DateTime.Now.Hour && time.Minutes == DateTime.Now.Minute)
|
||||
{
|
||||
if (time.Hours == DateTime.Now.Hour && time.Minutes == DateTime.Now.Minute)
|
||||
matching_time_found = true;
|
||||
if (!task.Trigger_On_Time_Already_Triggered)
|
||||
{
|
||||
matching_time_found = true;
|
||||
if (!task.Trigger_On_Time_Already_Triggered)
|
||||
{
|
||||
task.Trigger_On_Time_Already_Triggered = true;
|
||||
LogDebugToConsole(string.Format(Translations.bot_scriptScheduler_running_time, task.Action));
|
||||
CmdResult response = new();
|
||||
PerformInternalCommand(task.Action, ref response);
|
||||
if (response.status != CmdResult.Status.Done || !string.IsNullOrWhiteSpace(response.result))
|
||||
LogToConsole(response);
|
||||
}
|
||||
task.Trigger_On_Time_Already_Triggered = true;
|
||||
RunTaskAction(task, taskIndex, string.Format(Translations.bot_scriptScheduler_running_time, task.Action));
|
||||
}
|
||||
}
|
||||
|
||||
if (!matching_time_found)
|
||||
task.Trigger_On_Time_Already_Triggered = false;
|
||||
}
|
||||
|
||||
if (!matching_time_found)
|
||||
task.Trigger_On_Time_Already_Triggered = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (TaskConfig task in Config.TaskList)
|
||||
{
|
||||
if (task.Trigger_On_Login || (firstlogin_done == false && task.Trigger_On_First_Login))
|
||||
{
|
||||
LogDebugToConsole(string.Format(Translations.bot_scriptScheduler_running_login, task.Action));
|
||||
CmdResult response = new();
|
||||
PerformInternalCommand(task.Action, ref response);
|
||||
if (response.status != CmdResult.Status.Done || !string.IsNullOrWhiteSpace(response.result))
|
||||
LogToConsole(response);
|
||||
}
|
||||
}
|
||||
|
||||
firstlogin_done = true;
|
||||
serverlogin_done = true;
|
||||
}
|
||||
}
|
||||
else verifytasks_timeleft--;
|
||||
|
||||
foreach (TaskConfig task in Config.TaskList)
|
||||
for (int taskIndex = 0; taskIndex < Config.TaskList.Length; taskIndex++)
|
||||
{
|
||||
TaskConfig task = Config.TaskList[taskIndex];
|
||||
if (task.Trigger_On_Interval.Enable)
|
||||
{
|
||||
if (task.Trigger_On_Interval_Countdown == 0)
|
||||
|
|
@ -248,11 +238,7 @@ namespace MinecraftClient.ChatBots
|
|||
task.Trigger_On_Interval_Countdown = random.Next(
|
||||
Settings.DoubleToTick(task.Trigger_On_Interval.MinTime), Settings.DoubleToTick(task.Trigger_On_Interval.MaxTime)
|
||||
);
|
||||
LogDebugToConsole(string.Format(Translations.bot_scriptScheduler_running_inverval, task.Action));
|
||||
CmdResult response = new();
|
||||
PerformInternalCommand(task.Action, ref response);
|
||||
if (response.status != CmdResult.Status.Done || !string.IsNullOrWhiteSpace(response.result))
|
||||
LogToConsole(response);
|
||||
RunTaskAction(task, taskIndex, string.Format(Translations.bot_scriptScheduler_running_inverval, task.Action));
|
||||
}
|
||||
else task.Trigger_On_Interval_Countdown--;
|
||||
}
|
||||
|
|
@ -265,6 +251,58 @@ namespace MinecraftClient.ChatBots
|
|||
return false;
|
||||
}
|
||||
|
||||
private void RunLoginTasks()
|
||||
{
|
||||
bool isFirstLogin = !firstlogin_done;
|
||||
|
||||
for (int taskIndex = 0; taskIndex < Config.TaskList.Length; taskIndex++)
|
||||
{
|
||||
TaskConfig task = Config.TaskList[taskIndex];
|
||||
if (task.Trigger_On_Login || (isFirstLogin && task.Trigger_On_First_Login))
|
||||
RunTaskAction(task, taskIndex, string.Format(Translations.bot_scriptScheduler_running_login, task.Action));
|
||||
}
|
||||
|
||||
firstlogin_done = true;
|
||||
}
|
||||
|
||||
private void RunTaskAction(TaskConfig task, int taskIndex, string debugMessage)
|
||||
{
|
||||
LogDebugToConsole(debugMessage);
|
||||
|
||||
if (TryRunOwnedScript(task, taskIndex))
|
||||
return;
|
||||
|
||||
CmdResult response = new();
|
||||
PerformInternalCommand(task.Action, ref response);
|
||||
if (response.status != CmdResult.Status.Done || !string.IsNullOrWhiteSpace(response.result))
|
||||
LogToConsole(response);
|
||||
}
|
||||
|
||||
private bool TryRunOwnedScript(TaskConfig task, int taskIndex)
|
||||
{
|
||||
string action = task.Action.Trim();
|
||||
const string scriptCommand = "script";
|
||||
if (!action.StartsWith(scriptCommand, StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
|
||||
if (action.Length == scriptCommand.Length || !char.IsWhiteSpace(action[scriptCommand.Length]))
|
||||
return false;
|
||||
|
||||
string scriptArgs = action[scriptCommand.Length..].Trim();
|
||||
if (string.IsNullOrWhiteSpace(scriptArgs))
|
||||
return false;
|
||||
|
||||
string scriptOwnerKey = BuildScriptOwnerKey(task, taskIndex);
|
||||
Handler.UnloadBotsByScriptOwnerKey(scriptOwnerKey);
|
||||
Handler.BotLoad(new Script(scriptArgs, null, null, scriptOwnerKey));
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string BuildScriptOwnerKey(TaskConfig task, int taskIndex)
|
||||
{
|
||||
return $"{nameof(ScriptScheduler)}:{taskIndex}:{task.Task_Name}:{task.Action.Trim()}";
|
||||
}
|
||||
|
||||
private static string Task2String(TaskConfig task)
|
||||
{
|
||||
return string.Format(
|
||||
|
|
|
|||
|
|
@ -867,8 +867,11 @@ namespace MinecraftClient
|
|||
|
||||
DispatchBotEvent(bot => bot.OnDisconnect(ChatBot.DisconnectReason.UserLogout, ""));
|
||||
|
||||
foreach (ChatBot bot in bots.Where(bot => bot.ScriptOwnerKey is not null).ToList())
|
||||
BotUnLoad(bot);
|
||||
|
||||
botsOnHold.Clear();
|
||||
botsOnHold.AddRange(bots);
|
||||
botsOnHold.AddRange(bots.Where(bot => bot.ScriptOwnerKey is null));
|
||||
|
||||
if (handler is not null)
|
||||
{
|
||||
|
|
@ -1263,7 +1266,7 @@ namespace MinecraftClient
|
|||
bots.Add(b);
|
||||
if (init)
|
||||
DispatchBotEvent(bot => bot.Initialize(), [b]);
|
||||
if (handler is not null)
|
||||
if (CanSendMessage)
|
||||
DispatchBotEvent(bot => bot.AfterGameJoined(), [b]);
|
||||
}
|
||||
|
||||
|
|
@ -1291,6 +1294,21 @@ namespace MinecraftClient
|
|||
}
|
||||
}
|
||||
|
||||
internal void UnloadBotsByScriptOwnerKey(string scriptOwnerKey)
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
InvokeOnMainThread(() => UnloadBotsByScriptOwnerKey(scriptOwnerKey));
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (ChatBot bot in GetLoadedChatBots())
|
||||
{
|
||||
if (bot.ScriptOwnerKey == scriptOwnerKey)
|
||||
BotUnLoad(bot);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear bots
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace MinecraftClient.Scripting
|
|||
/// <param name="run">Set to false to compile and cache the script without launching it</param>
|
||||
/// <exception cref="CSharpException">Thrown if an error occured</exception>
|
||||
/// <returns>Result of the execution, returned by the script</returns>
|
||||
public static object? Run(ChatBot apiHandler, string[] lines, string[] args, Dictionary<string, object>? localVars, bool run = true, string scriptName = "Unknown Script")
|
||||
public static object? Run(ChatBot apiHandler, string[] lines, string[] args, Dictionary<string, object>? localVars, bool run = true, string scriptName = "Unknown Script", string? scriptOwnerKey = null)
|
||||
{
|
||||
//Script compatibility check for handling future versions differently
|
||||
if (lines.Length < 1 || lines[0] != "//MCCScript 1.0")
|
||||
|
|
@ -143,7 +143,7 @@ namespace MinecraftClient.Scripting
|
|||
{
|
||||
try
|
||||
{
|
||||
var compiled = runner.Execute(assembly!, args, localVars, apiHandler);
|
||||
var compiled = runner.Execute(assembly!, args, localVars, apiHandler, scriptOwnerKey);
|
||||
return compiled;
|
||||
}
|
||||
catch (Exception e) { throw new CSharpException(CSErrorType.RuntimeError, e); }
|
||||
|
|
@ -209,10 +209,11 @@ namespace MinecraftClient.Scripting
|
|||
/// <param name="apiHandler">ChatBot API Handler</param>
|
||||
/// <param name="tickHandler">ChatBot tick handler</param>
|
||||
/// <param name="localVars">Local variables passed along with the script</param>
|
||||
public CSharpAPI(ChatBot apiHandler, Dictionary<string, object>? localVars)
|
||||
public CSharpAPI(ChatBot apiHandler, Dictionary<string, object>? localVars, string? scriptOwnerKey = null)
|
||||
{
|
||||
SetMaster(apiHandler);
|
||||
this.localVars = localVars;
|
||||
SetScriptOwnerKey(scriptOwnerKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -39,9 +39,20 @@ namespace MinecraftClient.Scripting
|
|||
//Handler will be automatically set on bot loading, don't worry about this
|
||||
public void SetHandler(McClient handler) { _handler = handler; }
|
||||
protected void SetMaster(ChatBot master) { this.master = master; }
|
||||
protected void LoadBot(ChatBot bot) { Handler.BotUnLoad(bot); Handler.BotLoad(bot); }
|
||||
protected void LoadBot(ChatBot bot)
|
||||
{
|
||||
if (ScriptOwnerKey is not null)
|
||||
bot.SetScriptOwnerKey(ScriptOwnerKey);
|
||||
|
||||
if (Handler.GetLoadedChatBots().Any(loadedBot => ReferenceEquals(loadedBot, bot)))
|
||||
Handler.BotUnLoad(bot);
|
||||
|
||||
Handler.BotLoad(bot);
|
||||
}
|
||||
protected List<ChatBot> GetLoadedChatBots() { return Handler.GetLoadedChatBots(); }
|
||||
protected void UnLoadBot(ChatBot bot) { Handler.BotUnLoad(bot); }
|
||||
internal string? ScriptOwnerKey { get; private set; }
|
||||
internal void SetScriptOwnerKey(string? scriptOwnerKey) { ScriptOwnerKey = scriptOwnerKey; }
|
||||
private McClient? _handler = null;
|
||||
private ChatBot? master = null;
|
||||
private readonly List<string> registeredPluginChannels = new();
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ namespace MinecraftClient.Scripting.DynamicRun.Builder
|
|||
{
|
||||
internal class CompileRunner
|
||||
{
|
||||
public object? Execute(byte[] compiledAssembly, string[] args, Dictionary<string, object>? localVars, ChatBot apiHandler)
|
||||
public object? Execute(byte[] compiledAssembly, string[] args, Dictionary<string, object>? localVars, ChatBot apiHandler, string? scriptOwnerKey = null)
|
||||
{
|
||||
var assemblyLoadContextWeakRef = LoadAndExecute(compiledAssembly, args, localVars, apiHandler);
|
||||
var assemblyLoadContextWeakRef = LoadAndExecute(compiledAssembly, args, localVars, apiHandler, scriptOwnerKey);
|
||||
|
||||
for (var i = 0; i < 8 && assemblyLoadContextWeakRef.Item1.IsAlive; i++)
|
||||
{
|
||||
|
|
@ -28,18 +28,18 @@ namespace MinecraftClient.Scripting.DynamicRun.Builder
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static Tuple<WeakReference, object?> LoadAndExecute(byte[] compiledAssembly, string[] args, Dictionary<string, object>? localVars, ChatBot apiHandler)
|
||||
private static Tuple<WeakReference, object?> LoadAndExecute(byte[] compiledAssembly, string[] args, Dictionary<string, object>? localVars, ChatBot apiHandler, string? scriptOwnerKey)
|
||||
{
|
||||
using var asm = new MemoryStream(compiledAssembly);
|
||||
var assemblyLoadContext = new SimpleUnloadableAssemblyLoadContext();
|
||||
|
||||
var assembly = assemblyLoadContext.LoadFromStream(asm);
|
||||
var compiledScript = assembly.CreateInstance("ScriptLoader.Script")!;
|
||||
var execResult = compiledScript.GetType().GetMethod("__run")!.Invoke(compiledScript, new object[] { new CSharpAPI(apiHandler, localVars), args });
|
||||
var execResult = compiledScript.GetType().GetMethod("__run")!.Invoke(compiledScript, new object[] { new CSharpAPI(apiHandler, localVars, scriptOwnerKey), args });
|
||||
|
||||
assemblyLoadContext.Unload();
|
||||
|
||||
return new(new WeakReference(assemblyLoadContext), execResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue