mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
+ Rework task scheduling in chatbots + Switch back terrain processing to tasks
This commit is contained in:
parent
c1cfaf520d
commit
95d6318350
7 changed files with 517 additions and 461 deletions
|
|
@ -22,14 +22,13 @@ namespace MinecraftClient
|
|||
/// Run the specified C# script file
|
||||
/// </summary>
|
||||
/// <param name="apiHandler">ChatBot handler for accessing ChatBot API</param>
|
||||
/// <param name="tickHandler">Tick handler for waiting after some API calls</param>
|
||||
/// <param name="lines">Lines of the script file to run</param>
|
||||
/// <param name="args">Arguments to pass to the script</param>
|
||||
/// <param name="localVars">Local variables passed along with the script</param>
|
||||
/// <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, ManualResetEvent tickHandler, string[] lines, string[] args, Dictionary<string, object> localVars, bool run = true)
|
||||
public static object Run(ChatBot apiHandler, string[] lines, string[] args, Dictionary<string, object> localVars, bool run = true)
|
||||
{
|
||||
//Script compatibility check for handling future versions differently
|
||||
if (lines.Length < 1 || lines[0] != "//MCCScript 1.0")
|
||||
|
|
@ -140,7 +139,7 @@ namespace MinecraftClient
|
|||
.GetType()
|
||||
.GetMethod("__run")
|
||||
.Invoke(compiledScript,
|
||||
new object[] { new CSharpAPI(apiHandler, tickHandler, localVars), args });
|
||||
new object[] { new CSharpAPI(apiHandler, localVars), args });
|
||||
}
|
||||
catch (Exception e) { throw new CSharpException(CSErrorType.RuntimeError, e); }
|
||||
}
|
||||
|
|
@ -195,11 +194,6 @@ namespace MinecraftClient
|
|||
/// </summary>
|
||||
public class CSharpAPI : ChatBot
|
||||
{
|
||||
/// <summary>
|
||||
/// Thread blocking utility for stopping execution when making a ChatBot API call
|
||||
/// </summary>
|
||||
private ManualResetEvent tickHandler;
|
||||
|
||||
/// <summary>
|
||||
/// Holds local variables passed along with the script
|
||||
/// </summary>
|
||||
|
|
@ -211,10 +205,9 @@ namespace MinecraftClient
|
|||
/// <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, ManualResetEvent tickHandler, Dictionary<string , object> localVars)
|
||||
public CSharpAPI(ChatBot apiHandler, Dictionary<string , object> localVars)
|
||||
{
|
||||
SetMaster(apiHandler);
|
||||
this.tickHandler = tickHandler;
|
||||
this.localVars = localVars;
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +230,6 @@ namespace MinecraftClient
|
|||
public bool SendText(object text)
|
||||
{
|
||||
base.SendText(text is string ? (string)text : text.ToString());
|
||||
tickHandler.WaitOne();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -252,7 +244,6 @@ namespace MinecraftClient
|
|||
if (localVars == null)
|
||||
localVars = this.localVars;
|
||||
bool result = base.PerformInternalCommand(command, localVars);
|
||||
tickHandler.WaitOne();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +258,6 @@ namespace MinecraftClient
|
|||
if (extraAttempts == -999999)
|
||||
base.ReconnectToTheServer();
|
||||
else base.ReconnectToTheServer(extraAttempts);
|
||||
tickHandler.WaitOne();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -276,7 +266,6 @@ namespace MinecraftClient
|
|||
new public void DisconnectAndExit()
|
||||
{
|
||||
base.DisconnectAndExit();
|
||||
tickHandler.WaitOne();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -286,7 +275,6 @@ namespace MinecraftClient
|
|||
new public void LoadBot(ChatBot bot)
|
||||
{
|
||||
base.LoadBot(bot);
|
||||
tickHandler.WaitOne();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -406,7 +394,7 @@ namespace MinecraftClient
|
|||
ChatBots.Script.LookForScript(ref script);
|
||||
try { lines = File.ReadAllLines(script, Encoding.UTF8); }
|
||||
catch (Exception e) { throw new CSharpException(CSErrorType.FileReadError, e); }
|
||||
return CSharpRunner.Run(this, tickHandler, lines, args, localVars);
|
||||
return CSharpRunner.Run(this, lines, args, localVars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ namespace MinecraftClient
|
|||
private List<string> registeredPluginChannels = new List<String>();
|
||||
private List<string> registeredCommands = new List<string>();
|
||||
private object delayTasksLock = new object();
|
||||
private List<DelayedTask> delayTasks = new List<DelayedTask>();
|
||||
private List<TaskWithDelay> delayedTasks = new List<TaskWithDelay>();
|
||||
private McClient Handler
|
||||
{
|
||||
get
|
||||
|
|
@ -65,14 +65,14 @@ namespace MinecraftClient
|
|||
{
|
||||
lock (delayTasksLock)
|
||||
{
|
||||
if (delayTasks.Count > 0)
|
||||
if (delayedTasks.Count > 0)
|
||||
{
|
||||
List<int> tasksToRemove = new List<int>();
|
||||
for (int i = 0; i < delayTasks.Count; i++)
|
||||
for (int i = 0; i < delayedTasks.Count; i++)
|
||||
{
|
||||
if (delayTasks[i].Tick())
|
||||
if (delayedTasks[i].Tick())
|
||||
{
|
||||
delayTasks[i].Task.DynamicInvoke();
|
||||
delayedTasks[i].Task();
|
||||
tasksToRemove.Add(i);
|
||||
}
|
||||
}
|
||||
|
|
@ -81,7 +81,7 @@ namespace MinecraftClient
|
|||
tasksToRemove.Sort((a, b) => b.CompareTo(a)); // descending sort
|
||||
foreach (int index in tasksToRemove)
|
||||
{
|
||||
delayTasks.RemoveAt(index);
|
||||
delayedTasks.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1390,46 +1390,61 @@ namespace MinecraftClient
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedule a task to run on main thread. Returned value cannot be retrieved
|
||||
/// Invoke a task on the main thread, wait for completion and retrieve return value.
|
||||
/// </summary>
|
||||
/// <param name="task">Task to run with any type or return value</param>
|
||||
/// <returns>Any result returned from task, result type is inferred from the task</returns>
|
||||
/// <example>bool result = InvokeOnMainThread(methodThatReturnsAbool);</example>
|
||||
/// <example>bool result = InvokeOnMainThread(() => methodThatReturnsAbool(argument));</example>
|
||||
/// <example>int result = InvokeOnMainThread(() => { yourCode(); return 42; });</example>
|
||||
/// <typeparam name="T">Type of the return value</typeparam>
|
||||
protected T InvokeOnMainThread<T>(Func<T> task)
|
||||
{
|
||||
return Handler.InvokeOnMainThread(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoke a task on the main thread and wait for completion
|
||||
/// </summary>
|
||||
/// <param name="task">Task to run without return value</param>
|
||||
/// <example>InvokeOnMainThread(methodThatReturnsNothing);</example>
|
||||
/// <example>InvokeOnMainThread(() => methodThatReturnsNothing(argument));</example>
|
||||
/// <example>InvokeOnMainThread(() => { yourCode(); });</example>
|
||||
protected void InvokeOnMainThread(Action task)
|
||||
{
|
||||
Handler.InvokeOnMainThread(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedule a task to run on the main thread, and do not wait for completion
|
||||
/// </summary>
|
||||
/// <param name="task">Task to run</param>
|
||||
/// <param name="delayTicks">Run the task after X ticks (1 tick delay = ~100ms). 0 for no delay</param>
|
||||
/// <example>
|
||||
/// // Delay ~10 seconds
|
||||
/// ScheduleTaskDelayed(new Action(() =>
|
||||
/// {
|
||||
/// /** Your code here **/
|
||||
/// Console.WriteLine("10 seconds has passed");
|
||||
/// }), 100);
|
||||
/// <example>InvokeOnMainThread(methodThatReturnsNothing, 10);</example>
|
||||
/// <example>InvokeOnMainThread(() => methodThatReturnsNothing(argument), 10);</example>
|
||||
/// <example>InvokeOnMainThread(() => { yourCode(); }, 10);</example>
|
||||
/// </example>
|
||||
// TODO: Adapt to new IMinecraftComHandler API
|
||||
/*protected void ScheduleTaskDelayed(Delegate task, int delayTicks = 0)
|
||||
protected void ScheduleOnMainThread(Action task, int delayTicks = 0)
|
||||
{
|
||||
if (delayTicks <= 0)
|
||||
lock (delayTasksLock)
|
||||
{
|
||||
// Immediately schedule to run on next update
|
||||
Handler.InvokeOnMainThread(task);
|
||||
delayedTasks.Add(new TaskWithDelay(task, delayTicks));
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (delayTasksLock)
|
||||
{
|
||||
delayTasks.Add(new DelayedTask(task, delayTicks));
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedule a task to run on main thread.
|
||||
/// Schedule a task to run on the main thread, and do not wait for completion
|
||||
/// </summary>
|
||||
/// <param name="task">Task to run</param>
|
||||
/// <returns>Any value returned from the task</returns>
|
||||
// TODO: Adapt to new IMinecraftComHandler API
|
||||
/*
|
||||
protected object ScheduleTask(Delegate task)
|
||||
/// <param name="delay">Run the task after the specified delay</param>
|
||||
protected void ScheduleOnMainThread(Action task, TimeSpan delay)
|
||||
{
|
||||
return Handler.InvokeOnMainThread(task);
|
||||
}*/
|
||||
lock (delayTasksLock)
|
||||
{
|
||||
delayedTasks.Add(new TaskWithDelay(task, delay));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Command runner definition.
|
||||
|
|
@ -1475,35 +1490,5 @@ namespace MinecraftClient
|
|||
this.Runner = callback;
|
||||
}
|
||||
}
|
||||
|
||||
private class DelayedTask
|
||||
{
|
||||
private Delegate task;
|
||||
private int Counter;
|
||||
|
||||
public Delegate Task { get { return task; } }
|
||||
|
||||
public DelayedTask(Delegate task)
|
||||
: this(task, 0)
|
||||
{ }
|
||||
|
||||
public DelayedTask(Delegate task, int delayTicks)
|
||||
{
|
||||
this.task = task;
|
||||
Counter = delayTicks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tick the counter
|
||||
/// </summary>
|
||||
/// <returns>Return true if counted to zero</returns>
|
||||
public bool Tick()
|
||||
{
|
||||
Counter--;
|
||||
if (Counter <= 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ namespace MinecraftClient.ChatBots
|
|||
private string owner;
|
||||
private bool csharp;
|
||||
private Thread thread;
|
||||
private ManualResetEvent tpause;
|
||||
private Dictionary<string, object> localVars;
|
||||
|
||||
public Script(string filename)
|
||||
|
|
@ -157,12 +156,11 @@ namespace MinecraftClient.ChatBots
|
|||
//Initialize thread on first update
|
||||
if (thread == null)
|
||||
{
|
||||
tpause = new ManualResetEvent(false);
|
||||
thread = new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
CSharpRunner.Run(this, tpause, lines, args, localVars);
|
||||
CSharpRunner.Run(this, lines, args, localVars);
|
||||
}
|
||||
catch (CSharpException e)
|
||||
{
|
||||
|
|
@ -173,16 +171,14 @@ namespace MinecraftClient.ChatBots
|
|||
LogToConsole(e.InnerException);
|
||||
}
|
||||
});
|
||||
thread.Name = "MCC Script - " + file;
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
//Let the thread run for a short span of time
|
||||
if (thread != null)
|
||||
//Unload bot once the thread has finished running
|
||||
if (thread != null && !thread.IsAlive)
|
||||
{
|
||||
tpause.Set();
|
||||
tpause.Reset();
|
||||
if (!thread.IsAlive)
|
||||
UnloadBot();
|
||||
UnloadBot();
|
||||
}
|
||||
}
|
||||
else //Classic MCC script interpreter
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -222,6 +222,7 @@
|
|||
<Compile Include="Protocol\MicrosoftAuthentication.cs" />
|
||||
<Compile Include="Protocol\ProxiedWebRequest.cs" />
|
||||
<Compile Include="Protocol\ReplayHandler.cs" />
|
||||
<Compile Include="TaskWithDelay.cs" />
|
||||
<Compile Include="TaskWithResult.cs" />
|
||||
<Compile Include="Translations.cs" />
|
||||
<Compile Include="Inventory\VillagerInfo.cs" />
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
int compressedDataSize = dataTypes.ReadNextInt(packetData);
|
||||
byte[] compressed = dataTypes.ReadData(compressedDataSize, packetData);
|
||||
byte[] decompressed = ZlibUtils.Decompress(compressed);
|
||||
new Thread(() => {
|
||||
new Task(() => {
|
||||
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, addBitmap, currentDimension == 0, chunksContinuous, currentDimension, new Queue<byte>(decompressed));
|
||||
}).Start();
|
||||
}
|
||||
|
|
@ -449,7 +449,7 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
else dataTypes.ReadData(1024 * 4, packetData); // Biomes - 1.15 and above
|
||||
}
|
||||
int dataSize = dataTypes.ReadNextVarInt(packetData);
|
||||
new Thread(() => {
|
||||
new Task(() => {
|
||||
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, currentDimension, packetData);
|
||||
}).Start();
|
||||
}
|
||||
|
|
|
|||
45
MinecraftClient/TaskWithDelay.cs
Normal file
45
MinecraftClient/TaskWithDelay.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MinecraftClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds a task with delay
|
||||
/// </summary>
|
||||
class TaskWithDelay
|
||||
{
|
||||
private Action _task;
|
||||
private int tickCounter;
|
||||
private DateTime dateToLaunch;
|
||||
|
||||
public Action Task { get { return _task; } }
|
||||
|
||||
public TaskWithDelay(Action task, int delayTicks)
|
||||
{
|
||||
_task = task;
|
||||
tickCounter = delayTicks;
|
||||
dateToLaunch = DateTime.MaxValue;
|
||||
}
|
||||
|
||||
public TaskWithDelay(Action task, TimeSpan delay)
|
||||
{
|
||||
_task = task;
|
||||
tickCounter = int.MaxValue;
|
||||
dateToLaunch = DateTime.Now + delay;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tick the counter
|
||||
/// </summary>
|
||||
/// <returns>Return true if the task should run now</returns>
|
||||
public bool Tick()
|
||||
{
|
||||
tickCounter--;
|
||||
if (tickCounter <= 0 || dateToLaunch < DateTime.Now)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue