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
|
/// Run the specified C# script file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="apiHandler">ChatBot handler for accessing ChatBot API</param>
|
/// <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="lines">Lines of the script file to run</param>
|
||||||
/// <param name="args">Arguments to pass to the script</param>
|
/// <param name="args">Arguments to pass to the script</param>
|
||||||
/// <param name="localVars">Local variables passed along with 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>
|
/// <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>
|
/// <exception cref="CSharpException">Thrown if an error occured</exception>
|
||||||
/// <returns>Result of the execution, returned by the script</returns>
|
/// <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
|
//Script compatibility check for handling future versions differently
|
||||||
if (lines.Length < 1 || lines[0] != "//MCCScript 1.0")
|
if (lines.Length < 1 || lines[0] != "//MCCScript 1.0")
|
||||||
|
|
@ -140,7 +139,7 @@ namespace MinecraftClient
|
||||||
.GetType()
|
.GetType()
|
||||||
.GetMethod("__run")
|
.GetMethod("__run")
|
||||||
.Invoke(compiledScript,
|
.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); }
|
catch (Exception e) { throw new CSharpException(CSErrorType.RuntimeError, e); }
|
||||||
}
|
}
|
||||||
|
|
@ -195,11 +194,6 @@ namespace MinecraftClient
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CSharpAPI : ChatBot
|
public class CSharpAPI : ChatBot
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Thread blocking utility for stopping execution when making a ChatBot API call
|
|
||||||
/// </summary>
|
|
||||||
private ManualResetEvent tickHandler;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Holds local variables passed along with the script
|
/// Holds local variables passed along with the script
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -211,10 +205,9 @@ namespace MinecraftClient
|
||||||
/// <param name="apiHandler">ChatBot API Handler</param>
|
/// <param name="apiHandler">ChatBot API Handler</param>
|
||||||
/// <param name="tickHandler">ChatBot tick handler</param>
|
/// <param name="tickHandler">ChatBot tick handler</param>
|
||||||
/// <param name="localVars">Local variables passed along with the script</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);
|
SetMaster(apiHandler);
|
||||||
this.tickHandler = tickHandler;
|
|
||||||
this.localVars = localVars;
|
this.localVars = localVars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -237,7 +230,6 @@ namespace MinecraftClient
|
||||||
public bool SendText(object text)
|
public bool SendText(object text)
|
||||||
{
|
{
|
||||||
base.SendText(text is string ? (string)text : text.ToString());
|
base.SendText(text is string ? (string)text : text.ToString());
|
||||||
tickHandler.WaitOne();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,7 +244,6 @@ namespace MinecraftClient
|
||||||
if (localVars == null)
|
if (localVars == null)
|
||||||
localVars = this.localVars;
|
localVars = this.localVars;
|
||||||
bool result = base.PerformInternalCommand(command, localVars);
|
bool result = base.PerformInternalCommand(command, localVars);
|
||||||
tickHandler.WaitOne();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,7 +258,6 @@ namespace MinecraftClient
|
||||||
if (extraAttempts == -999999)
|
if (extraAttempts == -999999)
|
||||||
base.ReconnectToTheServer();
|
base.ReconnectToTheServer();
|
||||||
else base.ReconnectToTheServer(extraAttempts);
|
else base.ReconnectToTheServer(extraAttempts);
|
||||||
tickHandler.WaitOne();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -276,7 +266,6 @@ namespace MinecraftClient
|
||||||
new public void DisconnectAndExit()
|
new public void DisconnectAndExit()
|
||||||
{
|
{
|
||||||
base.DisconnectAndExit();
|
base.DisconnectAndExit();
|
||||||
tickHandler.WaitOne();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -286,7 +275,6 @@ namespace MinecraftClient
|
||||||
new public void LoadBot(ChatBot bot)
|
new public void LoadBot(ChatBot bot)
|
||||||
{
|
{
|
||||||
base.LoadBot(bot);
|
base.LoadBot(bot);
|
||||||
tickHandler.WaitOne();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -406,7 +394,7 @@ namespace MinecraftClient
|
||||||
ChatBots.Script.LookForScript(ref script);
|
ChatBots.Script.LookForScript(ref script);
|
||||||
try { lines = File.ReadAllLines(script, Encoding.UTF8); }
|
try { lines = File.ReadAllLines(script, Encoding.UTF8); }
|
||||||
catch (Exception e) { throw new CSharpException(CSErrorType.FileReadError, e); }
|
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> registeredPluginChannels = new List<String>();
|
||||||
private List<string> registeredCommands = new List<string>();
|
private List<string> registeredCommands = new List<string>();
|
||||||
private object delayTasksLock = new object();
|
private object delayTasksLock = new object();
|
||||||
private List<DelayedTask> delayTasks = new List<DelayedTask>();
|
private List<TaskWithDelay> delayedTasks = new List<TaskWithDelay>();
|
||||||
private McClient Handler
|
private McClient Handler
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -65,14 +65,14 @@ namespace MinecraftClient
|
||||||
{
|
{
|
||||||
lock (delayTasksLock)
|
lock (delayTasksLock)
|
||||||
{
|
{
|
||||||
if (delayTasks.Count > 0)
|
if (delayedTasks.Count > 0)
|
||||||
{
|
{
|
||||||
List<int> tasksToRemove = new List<int>();
|
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);
|
tasksToRemove.Add(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -81,7 +81,7 @@ namespace MinecraftClient
|
||||||
tasksToRemove.Sort((a, b) => b.CompareTo(a)); // descending sort
|
tasksToRemove.Sort((a, b) => b.CompareTo(a)); // descending sort
|
||||||
foreach (int index in tasksToRemove)
|
foreach (int index in tasksToRemove)
|
||||||
{
|
{
|
||||||
delayTasks.RemoveAt(index);
|
delayedTasks.RemoveAt(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1390,46 +1390,61 @@ namespace MinecraftClient
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <param name="task">Task to run</param>
|
/// <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>
|
/// <param name="delayTicks">Run the task after X ticks (1 tick delay = ~100ms). 0 for no delay</param>
|
||||||
/// <example>
|
/// <example>
|
||||||
/// // Delay ~10 seconds
|
/// <example>InvokeOnMainThread(methodThatReturnsNothing, 10);</example>
|
||||||
/// ScheduleTaskDelayed(new Action(() =>
|
/// <example>InvokeOnMainThread(() => methodThatReturnsNothing(argument), 10);</example>
|
||||||
/// {
|
/// <example>InvokeOnMainThread(() => { yourCode(); }, 10);</example>
|
||||||
/// /** Your code here **/
|
|
||||||
/// Console.WriteLine("10 seconds has passed");
|
|
||||||
/// }), 100);
|
|
||||||
/// </example>
|
/// </example>
|
||||||
// TODO: Adapt to new IMinecraftComHandler API
|
protected void ScheduleOnMainThread(Action task, int delayTicks = 0)
|
||||||
/*protected void ScheduleTaskDelayed(Delegate task, int delayTicks = 0)
|
|
||||||
{
|
|
||||||
if (delayTicks <= 0)
|
|
||||||
{
|
|
||||||
// Immediately schedule to run on next update
|
|
||||||
Handler.InvokeOnMainThread(task);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
lock (delayTasksLock)
|
lock (delayTasksLock)
|
||||||
{
|
{
|
||||||
delayTasks.Add(new DelayedTask(task, delayTicks));
|
delayedTasks.Add(new TaskWithDelay(task, delayTicks));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <param name="task">Task to run</param>
|
/// <param name="task">Task to run</param>
|
||||||
/// <returns>Any value returned from the task</returns>
|
/// <param name="delay">Run the task after the specified delay</param>
|
||||||
// TODO: Adapt to new IMinecraftComHandler API
|
protected void ScheduleOnMainThread(Action task, TimeSpan delay)
|
||||||
/*
|
|
||||||
protected object ScheduleTask(Delegate task)
|
|
||||||
{
|
{
|
||||||
return Handler.InvokeOnMainThread(task);
|
lock (delayTasksLock)
|
||||||
}*/
|
{
|
||||||
|
delayedTasks.Add(new TaskWithDelay(task, delay));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Command runner definition.
|
/// Command runner definition.
|
||||||
|
|
@ -1475,35 +1490,5 @@ namespace MinecraftClient
|
||||||
this.Runner = callback;
|
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 string owner;
|
||||||
private bool csharp;
|
private bool csharp;
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
private ManualResetEvent tpause;
|
|
||||||
private Dictionary<string, object> localVars;
|
private Dictionary<string, object> localVars;
|
||||||
|
|
||||||
public Script(string filename)
|
public Script(string filename)
|
||||||
|
|
@ -157,12 +156,11 @@ namespace MinecraftClient.ChatBots
|
||||||
//Initialize thread on first update
|
//Initialize thread on first update
|
||||||
if (thread == null)
|
if (thread == null)
|
||||||
{
|
{
|
||||||
tpause = new ManualResetEvent(false);
|
|
||||||
thread = new Thread(() =>
|
thread = new Thread(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CSharpRunner.Run(this, tpause, lines, args, localVars);
|
CSharpRunner.Run(this, lines, args, localVars);
|
||||||
}
|
}
|
||||||
catch (CSharpException e)
|
catch (CSharpException e)
|
||||||
{
|
{
|
||||||
|
|
@ -173,15 +171,13 @@ namespace MinecraftClient.ChatBots
|
||||||
LogToConsole(e.InnerException);
|
LogToConsole(e.InnerException);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
thread.Name = "MCC Script - " + file;
|
||||||
thread.Start();
|
thread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Let the thread run for a short span of time
|
//Unload bot once the thread has finished running
|
||||||
if (thread != null)
|
if (thread != null && !thread.IsAlive)
|
||||||
{
|
{
|
||||||
tpause.Set();
|
|
||||||
tpause.Reset();
|
|
||||||
if (!thread.IsAlive)
|
|
||||||
UnloadBot();
|
UnloadBot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -763,6 +763,8 @@ namespace MinecraftClient
|
||||||
/// Load a new bot
|
/// Load a new bot
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void BotLoad(ChatBot b, bool init = true)
|
public void BotLoad(ChatBot b, bool init = true)
|
||||||
|
{
|
||||||
|
InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
b.SetHandler(this);
|
b.SetHandler(this);
|
||||||
bots.Add(b);
|
bots.Add(b);
|
||||||
|
|
@ -771,12 +773,15 @@ namespace MinecraftClient
|
||||||
if (this.handler != null)
|
if (this.handler != null)
|
||||||
DispatchBotEvent(bot => bot.AfterGameJoined(), new ChatBot[] { b });
|
DispatchBotEvent(bot => bot.AfterGameJoined(), new ChatBot[] { b });
|
||||||
Settings.SingleCommand = "";
|
Settings.SingleCommand = "";
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unload a bot
|
/// Unload a bot
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void BotUnLoad(ChatBot b)
|
public void BotUnLoad(ChatBot b)
|
||||||
|
{
|
||||||
|
InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
bots.RemoveAll(item => object.ReferenceEquals(item, b));
|
bots.RemoveAll(item => object.ReferenceEquals(item, b));
|
||||||
|
|
||||||
|
|
@ -786,6 +791,7 @@ namespace MinecraftClient
|
||||||
{
|
{
|
||||||
UnregisterPluginChannel(entry.Key, b);
|
UnregisterPluginChannel(entry.Key, b);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -793,7 +799,7 @@ namespace MinecraftClient
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void BotClear()
|
public void BotClear()
|
||||||
{
|
{
|
||||||
bots.Clear();
|
InvokeOnMainThread(bots.Clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -812,6 +818,16 @@ namespace MinecraftClient
|
||||||
return inventoryHandlingEnabled;
|
return inventoryHandlingEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get entity handling status
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <remarks>Entity Handling cannot be enabled in runtime (or after joining server)</remarks>
|
||||||
|
public bool GetEntityHandlingEnabled()
|
||||||
|
{
|
||||||
|
return entityHandlingEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enable or disable Terrain and Movements.
|
/// Enable or disable Terrain and Movements.
|
||||||
/// Please note that Enabling will be deferred until next relog, respawn or world change.
|
/// Please note that Enabling will be deferred until next relog, respawn or world change.
|
||||||
|
|
@ -819,6 +835,8 @@ namespace MinecraftClient
|
||||||
/// <param name="enabled">Enabled</param>
|
/// <param name="enabled">Enabled</param>
|
||||||
/// <returns>TRUE if the setting was applied immediately, FALSE if delayed.</returns>
|
/// <returns>TRUE if the setting was applied immediately, FALSE if delayed.</returns>
|
||||||
public bool SetTerrainEnabled(bool enabled)
|
public bool SetTerrainEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
return InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
|
|
@ -836,6 +854,7 @@ namespace MinecraftClient
|
||||||
world.Clear();
|
world.Clear();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -845,6 +864,8 @@ namespace MinecraftClient
|
||||||
/// <param name="enabled">Enabled</param>
|
/// <param name="enabled">Enabled</param>
|
||||||
/// <returns>TRUE if the setting was applied immediately, FALSE if delayed.</returns>
|
/// <returns>TRUE if the setting was applied immediately, FALSE if delayed.</returns>
|
||||||
public bool SetInventoryEnabled(bool enabled)
|
public bool SetInventoryEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
return InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
|
|
@ -861,16 +882,7 @@ namespace MinecraftClient
|
||||||
inventories.Clear();
|
inventories.Clear();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
});
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get entity handling status
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <remarks>Entity Handling cannot be enabled in runtime (or after joining server)</remarks>
|
|
||||||
public bool GetEntityHandlingEnabled()
|
|
||||||
{
|
|
||||||
return entityHandlingEnabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -880,6 +892,8 @@ namespace MinecraftClient
|
||||||
/// <param name="enabled">Enabled</param>
|
/// <param name="enabled">Enabled</param>
|
||||||
/// <returns>TRUE if the setting was applied immediately, FALSE if delayed.</returns>
|
/// <returns>TRUE if the setting was applied immediately, FALSE if delayed.</returns>
|
||||||
public bool SetEntityHandlingEnabled(bool enabled)
|
public bool SetEntityHandlingEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
return InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
{
|
{
|
||||||
|
|
@ -898,6 +912,7 @@ namespace MinecraftClient
|
||||||
// Entity Handling cannot be enabled in runtime (or after joining server)
|
// Entity Handling cannot be enabled in runtime (or after joining server)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -909,7 +924,7 @@ namespace MinecraftClient
|
||||||
/// <param name="enabled"></param>
|
/// <param name="enabled"></param>
|
||||||
public void SetNetworkPacketCaptureEnabled(bool enabled)
|
public void SetNetworkPacketCaptureEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
networkPacketCaptureEnabled = enabled;
|
InvokeOnMainThread(() => { networkPacketCaptureEnabled = enabled; });
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
@ -958,10 +973,13 @@ namespace MinecraftClient
|
||||||
/// <param name="inventoryID">Window ID of the requested inventory</param>
|
/// <param name="inventoryID">Window ID of the requested inventory</param>
|
||||||
/// <returns> Item Dictionary indexed by Slot ID (Check wiki.vg for slot ID)</returns>
|
/// <returns> Item Dictionary indexed by Slot ID (Check wiki.vg for slot ID)</returns>
|
||||||
public Container GetInventory(int inventoryID)
|
public Container GetInventory(int inventoryID)
|
||||||
|
{
|
||||||
|
return InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (inventories.ContainsKey(inventoryID))
|
if (inventories.ContainsKey(inventoryID))
|
||||||
return inventories[inventoryID];
|
return inventories[inventoryID];
|
||||||
return null;
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1075,7 +1093,7 @@ namespace MinecraftClient
|
||||||
/// <returns>True if packet successfully sent</returns>
|
/// <returns>True if packet successfully sent</returns>
|
||||||
public bool SendRespawnPacket()
|
public bool SendRespawnPacket()
|
||||||
{
|
{
|
||||||
return handler.SendRespawnPacket();
|
return InvokeOnMainThread<bool>(handler.SendRespawnPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1084,6 +1102,8 @@ namespace MinecraftClient
|
||||||
/// <param name="channel">The channel to register.</param>
|
/// <param name="channel">The channel to register.</param>
|
||||||
/// <param name="bot">The bot to register the channel for.</param>
|
/// <param name="bot">The bot to register the channel for.</param>
|
||||||
public void RegisterPluginChannel(string channel, ChatBot bot)
|
public void RegisterPluginChannel(string channel, ChatBot bot)
|
||||||
|
{
|
||||||
|
InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (registeredBotPluginChannels.ContainsKey(channel))
|
if (registeredBotPluginChannels.ContainsKey(channel))
|
||||||
{
|
{
|
||||||
|
|
@ -1096,6 +1116,7 @@ namespace MinecraftClient
|
||||||
registeredBotPluginChannels[channel] = bots;
|
registeredBotPluginChannels[channel] = bots;
|
||||||
SendPluginChannelMessage("REGISTER", Encoding.UTF8.GetBytes(channel), true);
|
SendPluginChannelMessage("REGISTER", Encoding.UTF8.GetBytes(channel), true);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1104,6 +1125,8 @@ namespace MinecraftClient
|
||||||
/// <param name="channel">The channel to unregister.</param>
|
/// <param name="channel">The channel to unregister.</param>
|
||||||
/// <param name="bot">The bot to unregister the channel for.</param>
|
/// <param name="bot">The bot to unregister the channel for.</param>
|
||||||
public void UnregisterPluginChannel(string channel, ChatBot bot)
|
public void UnregisterPluginChannel(string channel, ChatBot bot)
|
||||||
|
{
|
||||||
|
InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (registeredBotPluginChannels.ContainsKey(channel))
|
if (registeredBotPluginChannels.ContainsKey(channel))
|
||||||
{
|
{
|
||||||
|
|
@ -1115,6 +1138,7 @@ namespace MinecraftClient
|
||||||
SendPluginChannelMessage("UNREGISTER", Encoding.UTF8.GetBytes(channel), true);
|
SendPluginChannelMessage("UNREGISTER", Encoding.UTF8.GetBytes(channel), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1126,6 +1150,8 @@ namespace MinecraftClient
|
||||||
/// <param name="sendEvenIfNotRegistered">Whether the packet should be sent even if the server or the client hasn't registered it yet.</param>
|
/// <param name="sendEvenIfNotRegistered">Whether the packet should be sent even if the server or the client hasn't registered it yet.</param>
|
||||||
/// <returns>Whether the packet was sent: true if it was sent, false if there was a connection error or it wasn't registered.</returns>
|
/// <returns>Whether the packet was sent: true if it was sent, false if there was a connection error or it wasn't registered.</returns>
|
||||||
public bool SendPluginChannelMessage(string channel, byte[] data, bool sendEvenIfNotRegistered = false)
|
public bool SendPluginChannelMessage(string channel, byte[] data, bool sendEvenIfNotRegistered = false)
|
||||||
|
{
|
||||||
|
return InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (!sendEvenIfNotRegistered)
|
if (!sendEvenIfNotRegistered)
|
||||||
{
|
{
|
||||||
|
|
@ -1139,6 +1165,7 @@ namespace MinecraftClient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return handler.SendPluginChannelPacket(channel, data);
|
return handler.SendPluginChannelPacket(channel, data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1147,7 +1174,7 @@ namespace MinecraftClient
|
||||||
/// <returns>TRUE if the item was successfully used</returns>
|
/// <returns>TRUE if the item was successfully used</returns>
|
||||||
public bool SendEntityAction(EntityActionType entityAction)
|
public bool SendEntityAction(EntityActionType entityAction)
|
||||||
{
|
{
|
||||||
return handler.SendEntityAction(playerEntityID, (int)entityAction);
|
return InvokeOnMainThread(() => handler.SendEntityAction(playerEntityID, (int)entityAction));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1156,7 +1183,7 @@ namespace MinecraftClient
|
||||||
/// <returns>TRUE if the item was successfully used</returns>
|
/// <returns>TRUE if the item was successfully used</returns>
|
||||||
public bool UseItemOnHand()
|
public bool UseItemOnHand()
|
||||||
{
|
{
|
||||||
return handler.SendUseItem(0);
|
return InvokeOnMainThread(() => handler.SendUseItem(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1164,6 +1191,8 @@ namespace MinecraftClient
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>TRUE if the slot was successfully clicked</returns>
|
/// <returns>TRUE if the slot was successfully clicked</returns>
|
||||||
public bool DoWindowAction(int windowId, int slotId, WindowActionType action)
|
public bool DoWindowAction(int windowId, int slotId, WindowActionType action)
|
||||||
|
{
|
||||||
|
return InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
Item item = null;
|
Item item = null;
|
||||||
if (inventories.ContainsKey(windowId) && inventories[windowId].Items.ContainsKey(slotId))
|
if (inventories.ContainsKey(windowId) && inventories[windowId].Items.ContainsKey(slotId))
|
||||||
|
|
@ -1446,6 +1475,7 @@ namespace MinecraftClient
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1459,7 +1489,7 @@ namespace MinecraftClient
|
||||||
/// <returns>TRUE if item given successfully</returns>
|
/// <returns>TRUE if item given successfully</returns>
|
||||||
public bool DoCreativeGive(int slot, ItemType itemType, int count, Dictionary<string, object> nbt = null)
|
public bool DoCreativeGive(int slot, ItemType itemType, int count, Dictionary<string, object> nbt = null)
|
||||||
{
|
{
|
||||||
return handler.SendCreativeInventoryAction(slot, itemType, count, nbt);
|
return InvokeOnMainThread(() => handler.SendCreativeInventoryAction(slot, itemType, count, nbt));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1469,7 +1499,7 @@ namespace MinecraftClient
|
||||||
/// <returns>TRUE if animation successfully done</returns>
|
/// <returns>TRUE if animation successfully done</returns>
|
||||||
public bool DoAnimation(int animation)
|
public bool DoAnimation(int animation)
|
||||||
{
|
{
|
||||||
return handler.SendAnimation(animation, playerEntityID);
|
return InvokeOnMainThread(() => handler.SendAnimation(animation, playerEntityID));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1479,6 +1509,8 @@ namespace MinecraftClient
|
||||||
/// <returns>TRUE if the window was successfully closed</returns>
|
/// <returns>TRUE if the window was successfully closed</returns>
|
||||||
/// <remarks>Sending close window for inventory 0 can cause server to update our inventory if there are any item in the crafting area</remarks>
|
/// <remarks>Sending close window for inventory 0 can cause server to update our inventory if there are any item in the crafting area</remarks>
|
||||||
public bool CloseInventory(int windowId)
|
public bool CloseInventory(int windowId)
|
||||||
|
{
|
||||||
|
return InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (inventories.ContainsKey(windowId))
|
if (inventories.ContainsKey(windowId))
|
||||||
{
|
{
|
||||||
|
|
@ -1487,6 +1519,7 @@ namespace MinecraftClient
|
||||||
return handler.SendCloseWindow(windowId);
|
return handler.SendCloseWindow(windowId);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1495,13 +1528,14 @@ namespace MinecraftClient
|
||||||
/// <returns>TRUE if the uccessfully clear</returns>
|
/// <returns>TRUE if the uccessfully clear</returns>
|
||||||
public bool ClearInventories()
|
public bool ClearInventories()
|
||||||
{
|
{
|
||||||
if (inventoryHandlingEnabled)
|
if (!inventoryHandlingEnabled)
|
||||||
|
return false;
|
||||||
|
return InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
inventories.Clear();
|
inventories.Clear();
|
||||||
inventories[0] = new Container(0, ContainerType.PlayerInventory, "Player Inventory");
|
inventories[0] = new Container(0, ContainerType.PlayerInventory, "Player Inventory");
|
||||||
return true;
|
return true;
|
||||||
}
|
});
|
||||||
else { return false; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1512,6 +1546,8 @@ namespace MinecraftClient
|
||||||
/// <param name="hand">Hand.MainHand or Hand.OffHand</param>
|
/// <param name="hand">Hand.MainHand or Hand.OffHand</param>
|
||||||
/// <returns>TRUE if interaction succeeded</returns>
|
/// <returns>TRUE if interaction succeeded</returns>
|
||||||
public bool InteractEntity(int EntityID, int type, Hand hand = Hand.MainHand)
|
public bool InteractEntity(int EntityID, int type, Hand hand = Hand.MainHand)
|
||||||
|
{
|
||||||
|
return InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
if (entities.ContainsKey(EntityID))
|
if (entities.ContainsKey(EntityID))
|
||||||
{
|
{
|
||||||
|
|
@ -1524,7 +1560,8 @@ namespace MinecraftClient
|
||||||
return handler.SendInteractEntity(EntityID, type);
|
return handler.SendInteractEntity(EntityID, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { return false; }
|
else return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1535,7 +1572,7 @@ namespace MinecraftClient
|
||||||
/// <returns>TRUE if successfully placed</returns>
|
/// <returns>TRUE if successfully placed</returns>
|
||||||
public bool PlaceBlock(Location location, Direction blockFace, Hand hand = Hand.MainHand)
|
public bool PlaceBlock(Location location, Direction blockFace, Hand hand = Hand.MainHand)
|
||||||
{
|
{
|
||||||
return handler.SendPlayerBlockPlacement((int)hand, location, blockFace);
|
return InvokeOnMainThread(() => handler.SendPlayerBlockPlacement((int)hand, location, blockFace));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1546,7 +1583,9 @@ namespace MinecraftClient
|
||||||
/// <param name="lookAtBlock">Also look at the block before digging</param>
|
/// <param name="lookAtBlock">Also look at the block before digging</param>
|
||||||
public bool DigBlock(Location location, bool swingArms = true, bool lookAtBlock = true)
|
public bool DigBlock(Location location, bool swingArms = true, bool lookAtBlock = true)
|
||||||
{
|
{
|
||||||
if (GetTerrainEnabled())
|
if (!GetTerrainEnabled())
|
||||||
|
return false;
|
||||||
|
return InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
// TODO select best face from current player location
|
// TODO select best face from current player location
|
||||||
Direction blockFace = Direction.Down;
|
Direction blockFace = Direction.Down;
|
||||||
|
|
@ -1560,8 +1599,7 @@ namespace MinecraftClient
|
||||||
return handler.SendPlayerDigging(0, location, blockFace)
|
return handler.SendPlayerDigging(0, location, blockFace)
|
||||||
&& (!swingArms || DoAnimation((int)Hand.MainHand))
|
&& (!swingArms || DoAnimation((int)Hand.MainHand))
|
||||||
&& handler.SendPlayerDigging(2, location, blockFace);
|
&& handler.SendPlayerDigging(2, location, blockFace);
|
||||||
}
|
});
|
||||||
else return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1572,9 +1610,12 @@ namespace MinecraftClient
|
||||||
public bool ChangeSlot(short slot)
|
public bool ChangeSlot(short slot)
|
||||||
{
|
{
|
||||||
if (slot >= 0 && slot <= 8)
|
if (slot >= 0 && slot <= 8)
|
||||||
|
{
|
||||||
|
return InvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
CurrentSlot = Convert.ToByte(slot);
|
CurrentSlot = Convert.ToByte(slot);
|
||||||
return handler.SendHeldItemChange(slot);
|
return handler.SendHeldItemChange(slot);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1590,7 +1631,7 @@ namespace MinecraftClient
|
||||||
public bool UpdateSign(Location location, string line1, string line2, string line3, string line4)
|
public bool UpdateSign(Location location, string line1, string line2, string line3, string line4)
|
||||||
{
|
{
|
||||||
// TODO Open sign editor first https://wiki.vg/Protocol#Open_Sign_Editor
|
// TODO Open sign editor first https://wiki.vg/Protocol#Open_Sign_Editor
|
||||||
return handler.SendUpdateSign(location, line1, line2, line3, line4);
|
return InvokeOnMainThread(() => handler.SendUpdateSign(location, line1, line2, line3, line4));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1599,7 +1640,7 @@ namespace MinecraftClient
|
||||||
/// <param name="selectedSlot">The slot of the trade, starts at 0.</param>
|
/// <param name="selectedSlot">The slot of the trade, starts at 0.</param>
|
||||||
public bool SelectTrade(int selectedSlot)
|
public bool SelectTrade(int selectedSlot)
|
||||||
{
|
{
|
||||||
return handler.SelectTrade(selectedSlot);
|
return InvokeOnMainThread(() => handler.SelectTrade(selectedSlot));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -1611,7 +1652,7 @@ namespace MinecraftClient
|
||||||
/// <param name="flags">command block flags</param>
|
/// <param name="flags">command block flags</param>
|
||||||
public bool UpdateCommandBlock(Location location, string command, CommandBlockMode mode, CommandBlockFlags flags)
|
public bool UpdateCommandBlock(Location location, string command, CommandBlockMode mode, CommandBlockFlags flags)
|
||||||
{
|
{
|
||||||
return handler.UpdateCommandBlock(location, command, mode, flags);
|
return InvokeOnMainThread(() => handler.UpdateCommandBlock(location, command, mode, flags));
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,7 @@
|
||||||
<Compile Include="Protocol\MicrosoftAuthentication.cs" />
|
<Compile Include="Protocol\MicrosoftAuthentication.cs" />
|
||||||
<Compile Include="Protocol\ProxiedWebRequest.cs" />
|
<Compile Include="Protocol\ProxiedWebRequest.cs" />
|
||||||
<Compile Include="Protocol\ReplayHandler.cs" />
|
<Compile Include="Protocol\ReplayHandler.cs" />
|
||||||
|
<Compile Include="TaskWithDelay.cs" />
|
||||||
<Compile Include="TaskWithResult.cs" />
|
<Compile Include="TaskWithResult.cs" />
|
||||||
<Compile Include="Translations.cs" />
|
<Compile Include="Translations.cs" />
|
||||||
<Compile Include="Inventory\VillagerInfo.cs" />
|
<Compile Include="Inventory\VillagerInfo.cs" />
|
||||||
|
|
|
||||||
|
|
@ -423,7 +423,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
int compressedDataSize = dataTypes.ReadNextInt(packetData);
|
int compressedDataSize = dataTypes.ReadNextInt(packetData);
|
||||||
byte[] compressed = dataTypes.ReadData(compressedDataSize, packetData);
|
byte[] compressed = dataTypes.ReadData(compressedDataSize, packetData);
|
||||||
byte[] decompressed = ZlibUtils.Decompress(compressed);
|
byte[] decompressed = ZlibUtils.Decompress(compressed);
|
||||||
new Thread(() => {
|
new Task(() => {
|
||||||
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, addBitmap, currentDimension == 0, chunksContinuous, currentDimension, new Queue<byte>(decompressed));
|
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, addBitmap, currentDimension == 0, chunksContinuous, currentDimension, new Queue<byte>(decompressed));
|
||||||
}).Start();
|
}).Start();
|
||||||
}
|
}
|
||||||
|
|
@ -449,7 +449,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
else dataTypes.ReadData(1024 * 4, packetData); // Biomes - 1.15 and above
|
else dataTypes.ReadData(1024 * 4, packetData); // Biomes - 1.15 and above
|
||||||
}
|
}
|
||||||
int dataSize = dataTypes.ReadNextVarInt(packetData);
|
int dataSize = dataTypes.ReadNextVarInt(packetData);
|
||||||
new Thread(() => {
|
new Task(() => {
|
||||||
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, currentDimension, packetData);
|
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, currentDimension, packetData);
|
||||||
}).Start();
|
}).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