Add method to schedule main thread task (#1570)

* Add method to schedule main thread task
* ChatBot API: New delay task method
* Add sealed attribute to ChatBot internal method
This commit is contained in:
ReinforceZwei 2021-05-08 21:03:23 +08:00 committed by GitHub
parent b8ce4d16c4
commit a5a8075efb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 134 additions and 13 deletions

View file

@ -41,6 +41,8 @@ namespace MinecraftClient
private ChatBot master = null;
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 McClient Handler
{
get
@ -53,6 +55,39 @@ namespace MinecraftClient
}
}
/// <summary>
/// Will be called every ~100ms.
/// </summary>
/// <remarks>
/// <see cref="Update"/> method can be overridden by child class so need an extra update method
/// </remarks>
public sealed void UpdateInternal()
{
lock (delayTasksLock)
{
if (delayTasks.Count > 0)
{
List<int> tasksToRemove = new List<int>();
for (int i = 0; i < delayTasks.Count; i++)
{
if (delayTasks[i].Tick())
{
Handler.ScheduleTask(delayTasks[i].Task);
tasksToRemove.Add(i);
}
}
if (tasksToRemove.Count > 0)
{
tasksToRemove.Sort((a, b) => b.CompareTo(a)); // descending sort
foreach (int index in tasksToRemove)
{
delayTasks.RemoveAt(index);
}
}
}
}
}
/* ================================================== */
/* Main methods to override for creating your bot */
/* ================================================== */
@ -1354,6 +1389,38 @@ namespace MinecraftClient
return Handler.GetProtocolVersion();
}
/// <summary>
/// Schedule a task to run on main thread
/// </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
/// ScheduleTask(delegate ()
/// {
/// /** Your code here **/
/// Console.WriteLine("10 seconds has passed");
/// }, 100);
/// </example>
protected void ScheduleTask(Action task, int delayTicks = 0)
{
if (task != null)
{
if (delayTicks <= 0)
{
// Immediately schedule to run on next update
Handler.ScheduleTask(task);
}
else
{
lock (delayTasksLock)
{
delayTasks.Add(new DelayedTask(task, delayTicks));
}
}
}
}
/// <summary>
/// Command runner definition.
/// Returned string will be the output of the command
@ -1398,5 +1465,46 @@ namespace MinecraftClient
this.Runner = callback;
}
}
private class DelayedTask
{
private Action task;
private int Counter;
public Action Task { get { return task; } }
public DelayedTask(Action task)
: this(task, 0)
{ }
public DelayedTask(Action 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;
}
/// <summary>
/// Execute the task
/// </summary>
public void Execute()
{
if (task != null)
{
task();
}
}
}
}
}

View file

@ -28,11 +28,13 @@ namespace MinecraftClient
private readonly Dictionary<Guid, string> onlinePlayers = new Dictionary<Guid, string>();
private static bool commandsLoaded = false;
private Queue<string> commandQueue = new Queue<string>();
private Queue<string> chatQueue = new Queue<string>();
private static DateTime nextMessageSendTime = DateTime.MinValue;
private Action threadTasks;
private object threadTasksLock = new object();
private readonly List<ChatBot> bots = new List<ChatBot>();
private static readonly List<ChatBot> botsOnHold = new List<ChatBot>();
private static Dictionary<int, Container> inventories = new Dictionary<int, Container>();
@ -310,10 +312,7 @@ namespace MinecraftClient
while (client.Client.Connected)
{
string text = ConsoleIO.ReadLine();
lock (commandQueue)
{
commandQueue.Enqueue(text);
}
ScheduleTask(delegate () { HandleCommandPromptText(text); });
}
}
catch (IOException) { }
@ -579,6 +578,7 @@ namespace MinecraftClient
try
{
bot.Update();
bot.UpdateInternal();
}
catch (Exception e)
{
@ -590,14 +590,6 @@ namespace MinecraftClient
}
}
lock (commandQueue)
{
if (commandQueue.Count > 0)
{
HandleCommandPromptText(commandQueue.Dequeue());
}
}
lock (chatQueue)
{
if (chatQueue.Count > 0 && nextMessageSendTime < DateTime.Now)
@ -648,6 +640,15 @@ namespace MinecraftClient
if (respawnTicks == 0)
SendRespawnPacket();
}
if (threadTasks != null)
{
lock (threadTasksLock)
{
threadTasks();
threadTasks = null;
}
}
}
/// <summary>
@ -692,6 +693,18 @@ namespace MinecraftClient
else return false;
}
/// <summary>
/// Schedule a task to run on the main thread
/// </summary>
/// <param name="task">Task to run</param>
public void ScheduleTask(Action task)
{
lock (threadTasksLock)
{
threadTasks += task;
}
}
#region Management: Load/Unload ChatBots and Enable/Disable settings
/// <summary>