From f848495243b167686d820be1939f1e7183df15e2 Mon Sep 17 00:00:00 2001
From: ReinforceZwei <39955851+ReinforceZwei@users.noreply.github.com>
Date: Wed, 12 May 2021 12:20:13 +0800
Subject: [PATCH] Implement schedule main thread task with return value (#1579)
* Implement schedule main thread task with return value
* Revert change of TestBot.cs
---
MinecraftClient/ChatBot.cs | 58 ++++++++++++--------------
MinecraftClient/McClient.cs | 21 ++++++----
MinecraftClient/MinecraftClient.csproj | 1 +
MinecraftClient/TaskWithResult.cs | 47 +++++++++++++++++++++
4 files changed, 88 insertions(+), 39 deletions(-)
create mode 100644 MinecraftClient/TaskWithResult.cs
diff --git a/MinecraftClient/ChatBot.cs b/MinecraftClient/ChatBot.cs
index e32c9458..aafc2942 100644
--- a/MinecraftClient/ChatBot.cs
+++ b/MinecraftClient/ChatBot.cs
@@ -72,7 +72,7 @@ namespace MinecraftClient
{
if (delayTasks[i].Tick())
{
- Handler.ScheduleTask(delayTasks[i].Task);
+ delayTasks[i].Task.DynamicInvoke();
tasksToRemove.Add(i);
}
}
@@ -1390,37 +1390,44 @@ namespace MinecraftClient
}
///
- /// Schedule a task to run on main thread
+ /// Schedule a task to run on main thread. Returned value cannot be retrieved
///
/// Task to run
/// Run the task after X ticks (1 tick delay = ~100ms). 0 for no delay
///
/// // Delay ~10 seconds
- /// ScheduleTask(delegate ()
+ /// ScheduleTaskDelayed(new Action(() =>
/// {
/// /** Your code here **/
/// Console.WriteLine("10 seconds has passed");
- /// }, 100);
+ /// }), 100);
///
- protected void ScheduleTask(Action task, int delayTicks = 0)
+ protected void ScheduleTaskDelayed(Delegate task, int delayTicks = 0)
{
- if (task != null)
+ if (delayTicks <= 0)
{
- if (delayTicks <= 0)
+ // Immediately schedule to run on next update
+ Handler.ScheduleTask(task);
+ }
+ else
+ {
+ lock (delayTasksLock)
{
- // Immediately schedule to run on next update
- Handler.ScheduleTask(task);
- }
- else
- {
- lock (delayTasksLock)
- {
- delayTasks.Add(new DelayedTask(task, delayTicks));
- }
+ delayTasks.Add(new DelayedTask(task, delayTicks));
}
}
}
+ ///
+ /// Schedule a task to run on main thread.
+ ///
+ /// Task to run
+ /// Any value returned from the task
+ protected object ScheduleTask(Delegate task)
+ {
+ return Handler.ScheduleTask(task);
+ }
+
///
/// Command runner definition.
/// Returned string will be the output of the command
@@ -1468,16 +1475,16 @@ namespace MinecraftClient
private class DelayedTask
{
- private Action task;
+ private Delegate task;
private int Counter;
- public Action Task { get { return task; } }
+ public Delegate Task { get { return task; } }
- public DelayedTask(Action task)
+ public DelayedTask(Delegate task)
: this(task, 0)
{ }
- public DelayedTask(Action task, int delayTicks)
+ public DelayedTask(Delegate task, int delayTicks)
{
this.task = task;
Counter = delayTicks;
@@ -1494,17 +1501,6 @@ namespace MinecraftClient
return true;
return false;
}
-
- ///
- /// Execute the task
- ///
- public void Execute()
- {
- if (task != null)
- {
- task();
- }
- }
}
}
}
diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs
index 4901b57e..f55b5c65 100644
--- a/MinecraftClient/McClient.cs
+++ b/MinecraftClient/McClient.cs
@@ -32,7 +32,7 @@ namespace MinecraftClient
private Queue chatQueue = new Queue();
private static DateTime nextMessageSendTime = DateTime.MinValue;
- private Action threadTasks;
+ private Queue threadTasks = new Queue();
private object threadTasksLock = new object();
private readonly List bots = new List();
@@ -312,7 +312,7 @@ namespace MinecraftClient
while (client.Client.Connected)
{
string text = ConsoleIO.ReadLine();
- ScheduleTask(delegate () { HandleCommandPromptText(text); });
+ ScheduleTask(new Action(() => { HandleCommandPromptText(text); }));
}
}
catch (IOException) { }
@@ -641,12 +641,14 @@ namespace MinecraftClient
SendRespawnPacket();
}
- if (threadTasks != null)
+
+ lock (threadTasksLock)
{
- lock (threadTasksLock)
+ while (threadTasks.Count > 0)
{
- threadTasks();
- threadTasks = null;
+ var taskToRun = threadTasks.Dequeue();
+ taskToRun.Execute();
+ taskToRun.Release();
}
}
}
@@ -697,12 +699,15 @@ namespace MinecraftClient
/// Schedule a task to run on the main thread
///
/// Task to run
- public void ScheduleTask(Action task)
+ public object ScheduleTask(Delegate task)
{
+ var taskAndResult = new TaskWithResult(task);
lock (threadTasksLock)
{
- threadTasks += task;
+ threadTasks.Enqueue(taskAndResult);
}
+ taskAndResult.Block();
+ return taskAndResult.Result;
}
#region Management: Load/Unload ChatBots and Enable/Disable settings
diff --git a/MinecraftClient/MinecraftClient.csproj b/MinecraftClient/MinecraftClient.csproj
index 117b619f..8850677f 100644
--- a/MinecraftClient/MinecraftClient.csproj
+++ b/MinecraftClient/MinecraftClient.csproj
@@ -222,6 +222,7 @@
+
diff --git a/MinecraftClient/TaskWithResult.cs b/MinecraftClient/TaskWithResult.cs
new file mode 100644
index 00000000..c68a5014
--- /dev/null
+++ b/MinecraftClient/TaskWithResult.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+
+namespace MinecraftClient
+{
+ public class TaskWithResult
+ {
+ private Delegate Task;
+ private AutoResetEvent ResultEvent = new AutoResetEvent(false);
+
+ public object Result;
+
+ public TaskWithResult(Delegate task)
+ {
+ Task = task;
+ }
+
+ ///
+ /// Execute the delegate and set the property to the returned value
+ ///
+ /// Value returned from delegate
+ public object Execute()
+ {
+ Result = Task.DynamicInvoke();
+ return Result;
+ }
+
+ ///
+ /// Block the program execution
+ ///
+ public void Block()
+ {
+ ResultEvent.WaitOne();
+ }
+
+ ///
+ /// Resume the program execution
+ ///
+ public void Release()
+ {
+ ResultEvent.Set();
+ }
+ }
+}