From da1db2e9a75c52db5afe0895777ed963031eb778 Mon Sep 17 00:00:00 2001
From: kis1yi <35934681+kis1yi@users.noreply.github.com>
Date: Wed, 3 Jun 2026 14:35:01 +0200
Subject: [PATCH 1/6] Reduced network polling and unblocked bot stop
---
Botbases/RSBot.Training/TrainingBase.cs | 2 +-
Library/RSBot.Core/Bot.cs | 16 +++--
Library/RSBot.Core/Components/SkillManager.cs | 10 ++-
Library/RSBot.Core/Network/Socket/Client.cs | 3 +-
Library/RSBot.Core/Network/Socket/NetBase.cs | 72 ++++++++++++++-----
Library/RSBot.Core/Network/Socket/Server.cs | 2 +
6 files changed, 76 insertions(+), 29 deletions(-)
diff --git a/Botbases/RSBot.Training/TrainingBase.cs b/Botbases/RSBot.Training/TrainingBase.cs
index 748da902..0028374c 100644
--- a/Botbases/RSBot.Training/TrainingBase.cs
+++ b/Botbases/RSBot.Training/TrainingBase.cs
@@ -80,7 +80,7 @@ public void Stop()
lock (Container.Lock)
{
if (Game.Player.InAction)
- SkillManager.CancelAction();
+ SkillManager.CancelAction(0);
Bundles.Stop();
}
diff --git a/Library/RSBot.Core/Bot.cs b/Library/RSBot.Core/Bot.cs
index df4703c2..b7a3b2e2 100644
--- a/Library/RSBot.Core/Bot.cs
+++ b/Library/RSBot.Core/Bot.cs
@@ -66,7 +66,10 @@ public void Start()
while (!TokenSource.IsCancellationRequested)
{
if (!Game.Ready)
+ {
+ await Task.Delay(100);
continue;
+ }
Botbase.Tick();
await Task.Delay(100);
@@ -82,25 +85,26 @@ public void Start()
///
public void Stop()
{
- ScriptManager.Stop();
- ShoppingManager.Stop();
- PickupManager.Stop();
-
if (Botbase == null)
return;
if (!Running)
return;
- if (!TokenSource.IsCancellationRequested)
+ Running = false;
+
+ if (TokenSource != null && !TokenSource.IsCancellationRequested)
TokenSource.Cancel();
EventManager.FireEvent("OnStopBot");
Log.Notify($"Stopping bot {Botbase.Name}");
Game.SelectedEntity = null;
+
+ ScriptManager.Stop();
+ ShoppingManager.Stop();
+ PickupManager.Stop();
Botbase.Stop();
- Running = false;
Log.Notify($"Stopped bot {Botbase.Name}");
Log.Status("Bot stopped");
diff --git a/Library/RSBot.Core/Components/SkillManager.cs b/Library/RSBot.Core/Components/SkillManager.cs
index 5f0f335b..643240c9 100644
--- a/Library/RSBot.Core/Components/SkillManager.cs
+++ b/Library/RSBot.Core/Components/SkillManager.cs
@@ -631,11 +631,17 @@ public static void CancelBuff(uint skillId)
/// Cancels the action.
///
///
- public static bool CancelAction()
+ public static bool CancelAction(int timeout = 500)
{
var packet = new Packet(0x7074);
packet.WriteByte(0x02); //Cancel
+ if (timeout <= 0)
+ {
+ PacketManager.SendPacket(packet, PacketDestination.Server);
+ return true;
+ }
+
var callback = new AwaitCallback(
response =>
{
@@ -647,7 +653,7 @@ public static bool CancelAction()
);
PacketManager.SendPacket(packet, PacketDestination.Server, callback);
- callback.AwaitResponse();
+ callback.AwaitResponse(timeout);
return callback.IsCompleted;
}
diff --git a/Library/RSBot.Core/Network/Socket/Client.cs b/Library/RSBot.Core/Network/Socket/Client.cs
index 60125290..b1e0be56 100644
--- a/Library/RSBot.Core/Network/Socket/Client.cs
+++ b/Library/RSBot.Core/Network/Socket/Client.cs
@@ -97,12 +97,12 @@ private void OnClientConnect(IAsyncResult ar)
if (IsClosing)
return;
- EnablePacketDispatcher = true;
_socket = _listener.EndAccept(ar);
_protocol = new SecurityProtocol();
_protocol.GenerateSecurity(true, true, true);
+ EnablePacketDispatcher = true;
_socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
OnConnected();
@@ -136,6 +136,7 @@ private void OnBeginReceiveCallback(IAsyncResult ar)
}
_protocol.Recv(_buffer, 0, receivedSize);
+ SignalPacketDispatcher();
}
catch (SocketException se)
{
diff --git a/Library/RSBot.Core/Network/Socket/NetBase.cs b/Library/RSBot.Core/Network/Socket/NetBase.cs
index f308a4ce..f625360a 100644
--- a/Library/RSBot.Core/Network/Socket/NetBase.cs
+++ b/Library/RSBot.Core/Network/Socket/NetBase.cs
@@ -31,13 +31,25 @@ public class NetBase(bool isClient = false)
///
private bool _isClient { get; set; } = isClient;
+ private readonly AutoResetEvent _packetSignal = new(false);
+ private volatile bool _enablePacketDispatcher;
+ private volatile bool _isClosing;
+
///
/// Gets or sets a value indicating whether this instance is closing.
///
///
/// true if this instance is closing; otherwise, false.
///
- public bool IsClosing { get; set; }
+ public bool IsClosing
+ {
+ get => _isClosing;
+ set
+ {
+ _isClosing = value;
+ _packetSignal.Set();
+ }
+ }
///
/// Gets or sets a value indicating whether [enable packet processor].
@@ -45,7 +57,15 @@ public class NetBase(bool isClient = false)
///
/// true if [enable packet processor]; otherwise, false.
///
- public bool EnablePacketDispatcher { get; set; }
+ public bool EnablePacketDispatcher
+ {
+ get => _enablePacketDispatcher;
+ set
+ {
+ _enablePacketDispatcher = value;
+ _packetSignal.Set();
+ }
+ }
///
/// Gets or sets the security protocol.
@@ -126,19 +146,17 @@ private void ProcessPacketsThreaded()
{
try
{
- while (!EnablePacketDispatcher && !IsClosing)
- Thread.Sleep(1);
-
- while (EnablePacketDispatcher && !IsClosing)
+ while (!IsClosing)
{
- ProcessQueuedPackets();
- Thread.Sleep(1);
- }
-
- if (IsClosing)
- return;
+ if (!EnablePacketDispatcher)
+ {
+ _packetSignal.WaitOne(100);
+ continue;
+ }
- ProcessPacketsThreaded();
+ if (!ProcessQueuedPackets())
+ _packetSignal.WaitOne(15);
+ }
}
catch { }
}
@@ -146,18 +164,22 @@ private void ProcessPacketsThreaded()
///
/// Processes the packets.
///
- private void ProcessQueuedPackets()
+ private bool ProcessQueuedPackets()
{
try
{
if (IsClosing || !EnablePacketDispatcher)
- return;
+ return false;
+
+ var packets = _protocol?.TransferIncoming();
+ var processed = false;
- var packets = _protocol.TransferIncoming();
if (packets != null)
{
foreach (var packet in packets)
{
+ processed = true;
+
if (packet.Opcode == 0x5000 || packet.Opcode == 0x9000)
continue;
@@ -174,17 +196,23 @@ private void ProcessQueuedPackets()
var buffers = _protocol?.TransferOutgoing();
if (buffers == null)
- return;
+ return processed;
foreach (var buffer in buffers)
{
if (_socket == null || IsClosing || !EnablePacketDispatcher || !_socket.Connected)
- return;
+ return processed;
_socket.Send(buffer);
+ processed = true;
}
+
+ return processed;
+ }
+ catch
+ {
+ return false;
}
- catch { }
}
///
@@ -196,5 +224,11 @@ public void Send(Packet packet)
OnPacketSent(packet);
_protocol?.Send(packet);
+ _packetSignal.Set();
+ }
+
+ protected void SignalPacketDispatcher()
+ {
+ _packetSignal.Set();
}
}
diff --git a/Library/RSBot.Core/Network/Socket/Server.cs b/Library/RSBot.Core/Network/Socket/Server.cs
index c39a91e6..ffdd92e3 100644
--- a/Library/RSBot.Core/Network/Socket/Server.cs
+++ b/Library/RSBot.Core/Network/Socket/Server.cs
@@ -133,6 +133,7 @@ private void OnBeginReceiveCallback(IAsyncResult ar)
_receivedPostInitialHandshakePacket = true;
_protocol.Recv(_buffer, 0, receivedSize);
+ SignalPacketDispatcher();
}
catch (SocketException se)
{
@@ -166,6 +167,7 @@ public void Send(Packet packet)
{
OnPacketSent(packet);
_protocol.Send(packet);
+ SignalPacketDispatcher();
}
///
From d1b64816cfdb6c182e5762c74c610f12e6621811 Mon Sep 17 00:00:00 2001
From: kis1yi <35934681+kis1yi@users.noreply.github.com>
Date: Wed, 3 Jun 2026 15:09:17 +0200
Subject: [PATCH 2/6] Harden bot stop and network worker lifecycle
---
Botbases/RSBot.Training/TrainingBase.cs | 2 +-
Library/RSBot.Core/Bot.cs | 82 ++++++++++++-------
Library/RSBot.Core/Components/SkillManager.cs | 6 --
Library/RSBot.Core/Network/Socket/Client.cs | 6 +-
Library/RSBot.Core/Network/Socket/NetBase.cs | 31 +++++--
Library/RSBot.Core/Network/Socket/Server.cs | 11 +--
6 files changed, 79 insertions(+), 59 deletions(-)
diff --git a/Botbases/RSBot.Training/TrainingBase.cs b/Botbases/RSBot.Training/TrainingBase.cs
index 0028374c..89cbd1c9 100644
--- a/Botbases/RSBot.Training/TrainingBase.cs
+++ b/Botbases/RSBot.Training/TrainingBase.cs
@@ -80,7 +80,7 @@ public void Stop()
lock (Container.Lock)
{
if (Game.Player.InAction)
- SkillManager.CancelAction(0);
+ SkillManager.CancelAction(50);
Bundles.Stop();
}
diff --git a/Library/RSBot.Core/Bot.cs b/Library/RSBot.Core/Bot.cs
index b7a3b2e2..c7dcfdc7 100644
--- a/Library/RSBot.Core/Bot.cs
+++ b/Library/RSBot.Core/Bot.cs
@@ -1,5 +1,6 @@
using System.Threading;
using System.Threading.Tasks;
+using System;
using RSBot.Core.Components;
using RSBot.Core.Event;
using RSBot.Core.Plugins;
@@ -8,6 +9,9 @@ namespace RSBot.Core;
public class Bot
{
+ private readonly object _lock = new();
+ private Task _workerTask;
+
///
/// Gets or sets a value indicating whether this is running.
///
@@ -50,34 +54,47 @@ public void SetBotbaseView(IBotbaseView botBaseView)
///
public void Start()
{
- if (Running || Botbase == null)
- return;
-
- TokenSource = new CancellationTokenSource();
-
- Task.Factory.StartNew(
- async e =>
- {
- Running = true;
+ CancellationTokenSource tokenSource;
+
+ lock (_lock)
+ {
+ if (Running || Botbase == null || (_workerTask != null && !_workerTask.IsCompleted))
+ return;
+
+ tokenSource = new CancellationTokenSource();
+ TokenSource = tokenSource;
+ Running = true;
+ _workerTask = Task.Run(() => RunAsync(tokenSource), tokenSource.Token);
+ }
+ }
- EventManager.FireEvent("OnStartBot");
- Botbase.Start();
+ private async Task RunAsync(CancellationTokenSource tokenSource)
+ {
+ var token = tokenSource.Token;
- while (!TokenSource.IsCancellationRequested)
- {
- if (!Game.Ready)
- {
- await Task.Delay(100);
- continue;
- }
+ try
+ {
+ EventManager.FireEvent("OnStartBot");
+ Botbase.Start();
+ while (!token.IsCancellationRequested)
+ {
+ if (Game.Ready)
Botbase.Tick();
- await Task.Delay(100);
- }
- },
- TokenSource.Token,
- TaskCreationOptions.LongRunning
- );
+
+ await Task.Delay(100, token);
+ }
+ }
+ catch (OperationCanceledException) when (token.IsCancellationRequested) { }
+ catch (Exception ex)
+ {
+ Log.Fatal(ex);
+ }
+ finally
+ {
+ if (ReferenceEquals(TokenSource, tokenSource))
+ Running = false;
+ }
}
///
@@ -85,16 +102,19 @@ public void Start()
///
public void Stop()
{
- if (Botbase == null)
- return;
+ CancellationTokenSource tokenSource;
- if (!Running)
- return;
+ lock (_lock)
+ {
+ if (Botbase == null || !Running)
+ return;
- Running = false;
+ Running = false;
+ tokenSource = TokenSource;
+ }
- if (TokenSource != null && !TokenSource.IsCancellationRequested)
- TokenSource.Cancel();
+ if (tokenSource != null && !tokenSource.IsCancellationRequested)
+ tokenSource.Cancel();
EventManager.FireEvent("OnStopBot");
Log.Notify($"Stopping bot {Botbase.Name}");
diff --git a/Library/RSBot.Core/Components/SkillManager.cs b/Library/RSBot.Core/Components/SkillManager.cs
index 643240c9..2314374c 100644
--- a/Library/RSBot.Core/Components/SkillManager.cs
+++ b/Library/RSBot.Core/Components/SkillManager.cs
@@ -636,12 +636,6 @@ public static bool CancelAction(int timeout = 500)
var packet = new Packet(0x7074);
packet.WriteByte(0x02); //Cancel
- if (timeout <= 0)
- {
- PacketManager.SendPacket(packet, PacketDestination.Server);
- return true;
- }
-
var callback = new AwaitCallback(
response =>
{
diff --git a/Library/RSBot.Core/Network/Socket/Client.cs b/Library/RSBot.Core/Network/Socket/Client.cs
index b1e0be56..5f337e5b 100644
--- a/Library/RSBot.Core/Network/Socket/Client.cs
+++ b/Library/RSBot.Core/Network/Socket/Client.cs
@@ -58,10 +58,7 @@ public void Shutdown()
{
try
{
- EnablePacketDispatcher = false;
- IsClosing = true;
-
- _dispatcherThread?.Join();
+ StopNetWorker();
//Close Socket
if (_socket != null)
@@ -81,7 +78,6 @@ public void Shutdown()
}
_protocol = null;
- _dispatcherThread = null;
}
catch { }
}
diff --git a/Library/RSBot.Core/Network/Socket/NetBase.cs b/Library/RSBot.Core/Network/Socket/NetBase.cs
index f625360a..db3ae740 100644
--- a/Library/RSBot.Core/Network/Socket/NetBase.cs
+++ b/Library/RSBot.Core/Network/Socket/NetBase.cs
@@ -128,15 +128,30 @@ public virtual void OnPacketSent(Packet packet)
protected void StartNetWorker()
{
- if (_dispatcherThread == null)
+ if (_dispatcherThread != null && _dispatcherThread.IsAlive)
+ return;
+
+ _dispatcherThread = new Thread(ProcessPacketsThreaded)
{
- _dispatcherThread = new Thread(ProcessPacketsThreaded)
- {
- Name = "Network.PacketProcessor",
- IsBackground = true,
- };
- _dispatcherThread.Start();
- }
+ Name = "Network.PacketProcessor",
+ IsBackground = true,
+ };
+ _dispatcherThread.Start();
+ }
+
+ protected void StopNetWorker(int joinTimeout = 1000)
+ {
+ EnablePacketDispatcher = false;
+ IsClosing = true;
+
+ var dispatcherThread = _dispatcherThread;
+ var stopped = dispatcherThread == null || !dispatcherThread.IsAlive || dispatcherThread == Thread.CurrentThread;
+
+ if (dispatcherThread != null && dispatcherThread.IsAlive && dispatcherThread != Thread.CurrentThread)
+ stopped = dispatcherThread.Join(joinTimeout);
+
+ if (stopped)
+ _dispatcherThread = null;
}
///
diff --git a/Library/RSBot.Core/Network/Socket/Server.cs b/Library/RSBot.Core/Network/Socket/Server.cs
index ffdd92e3..765b5cef 100644
--- a/Library/RSBot.Core/Network/Socket/Server.cs
+++ b/Library/RSBot.Core/Network/Socket/Server.cs
@@ -175,15 +175,11 @@ public void Send(Packet packet)
///
public void Disconnect()
{
- EnablePacketDispatcher = false;
- IsClosing = true;
+ StopNetWorker();
try
{
- if (_socket == null)
- return;
-
- if (_socket.Connected)
+ if (_socket != null && _socket.Connected)
{
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
@@ -194,8 +190,7 @@ public void Disconnect()
{
_socket = null;
OnDisconnected();
+ IsClosing = false;
}
-
- IsClosing = false;
}
}
From c4285b948fba7b95393cabdb45c5fa02a2176aeb Mon Sep 17 00:00:00 2001
From: kis1yi <35934681+kis1yi@users.noreply.github.com>
Date: Wed, 3 Jun 2026 15:26:25 +0200
Subject: [PATCH 3/6] Avoid blocking action cancel on bot stop
---
Botbases/RSBot.Training/TrainingBase.cs | 2 +-
Library/RSBot.Core/Components/SkillManager.cs | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/Botbases/RSBot.Training/TrainingBase.cs b/Botbases/RSBot.Training/TrainingBase.cs
index 89cbd1c9..dc33a72d 100644
--- a/Botbases/RSBot.Training/TrainingBase.cs
+++ b/Botbases/RSBot.Training/TrainingBase.cs
@@ -80,7 +80,7 @@ public void Stop()
lock (Container.Lock)
{
if (Game.Player.InAction)
- SkillManager.CancelAction(50);
+ SkillManager.CancelActionNoWait();
Bundles.Stop();
}
diff --git a/Library/RSBot.Core/Components/SkillManager.cs b/Library/RSBot.Core/Components/SkillManager.cs
index 2314374c..8da7c40e 100644
--- a/Library/RSBot.Core/Components/SkillManager.cs
+++ b/Library/RSBot.Core/Components/SkillManager.cs
@@ -651,4 +651,12 @@ public static bool CancelAction(int timeout = 500)
return callback.IsCompleted;
}
+
+ public static void CancelActionNoWait()
+ {
+ var packet = new Packet(0x7074);
+ packet.WriteByte(0x02); //Cancel
+
+ PacketManager.SendPacket(packet, PacketDestination.Server);
+ }
}
From 09ee8811354c8395244a2f49db3e5ae36f6d8e86 Mon Sep 17 00:00:00 2001
From: kis1yi <35934681+kis1yi@users.noreply.github.com>
Date: Wed, 3 Jun 2026 16:43:40 +0200
Subject: [PATCH 4/6] Handle recurring cancel-action responses on bot stop
---
Botbases/RSBot.Training/TrainingBase.cs | 3 ---
Library/RSBot.Core/Bot.cs | 20 ++++++++++++++
Library/RSBot.Core/Components/SkillManager.cs | 26 +++++++++++++------
3 files changed, 38 insertions(+), 11 deletions(-)
diff --git a/Botbases/RSBot.Training/TrainingBase.cs b/Botbases/RSBot.Training/TrainingBase.cs
index dc33a72d..91b6f20f 100644
--- a/Botbases/RSBot.Training/TrainingBase.cs
+++ b/Botbases/RSBot.Training/TrainingBase.cs
@@ -79,9 +79,6 @@ public void Stop()
{
lock (Container.Lock)
{
- if (Game.Player.InAction)
- SkillManager.CancelActionNoWait();
-
Bundles.Stop();
}
}
diff --git a/Library/RSBot.Core/Bot.cs b/Library/RSBot.Core/Bot.cs
index c7dcfdc7..93ff0175 100644
--- a/Library/RSBot.Core/Bot.cs
+++ b/Library/RSBot.Core/Bot.cs
@@ -119,6 +119,8 @@ public void Stop()
EventManager.FireEvent("OnStopBot");
Log.Notify($"Stopping bot {Botbase.Name}");
+ CancelActionOnStop();
+
Game.SelectedEntity = null;
ScriptManager.Stop();
@@ -129,4 +131,22 @@ public void Stop()
Log.Notify($"Stopped bot {Botbase.Name}");
Log.Status("Bot stopped");
}
+
+ private void CancelActionOnStop()
+ {
+ SkillManager.CancelAction(0);
+
+ _ = Task.Run(async () =>
+ {
+ for (var i = 1; i < 5; i++)
+ {
+ await Task.Delay(100);
+
+ if (Running || !Game.Player.InAction)
+ return;
+
+ SkillManager.CancelAction(0);
+ }
+ });
+ }
}
diff --git a/Library/RSBot.Core/Components/SkillManager.cs b/Library/RSBot.Core/Components/SkillManager.cs
index 8da7c40e..145b732b 100644
--- a/Library/RSBot.Core/Components/SkillManager.cs
+++ b/Library/RSBot.Core/Components/SkillManager.cs
@@ -633,30 +633,40 @@ public static void CancelBuff(uint skillId)
///
public static bool CancelAction(int timeout = 500)
{
- var packet = new Packet(0x7074);
- packet.WriteByte(0x02); //Cancel
+ if (timeout <= 0)
+ {
+ PacketManager.SendPacket(CreateCancelActionPacket(), PacketDestination.Server);
+ return true;
+ }
var callback = new AwaitCallback(
response =>
{
- return response.ReadByte() == 0x02 && response.ReadByte() == 0x00
- ? AwaitCallbackResult.Success
- : AwaitCallbackResult.ConditionFailed;
+ var state = response.ReadByte();
+ var recurring = response.ReadByte();
+
+ if (state == 0x02 && recurring == 0x00)
+ return AwaitCallbackResult.Success;
+
+ if (state == 0x02)
+ return AwaitCallbackResult.Fail;
+
+ return AwaitCallbackResult.ConditionFailed;
},
0xB074
);
- PacketManager.SendPacket(packet, PacketDestination.Server, callback);
+ PacketManager.SendPacket(CreateCancelActionPacket(), PacketDestination.Server, callback);
callback.AwaitResponse(timeout);
return callback.IsCompleted;
}
- public static void CancelActionNoWait()
+ private static Packet CreateCancelActionPacket()
{
var packet = new Packet(0x7074);
packet.WriteByte(0x02); //Cancel
- PacketManager.SendPacket(packet, PacketDestination.Server);
+ return packet;
}
}
From 2ac7c06a199f04fcd4be8dd08637d510bebaf92e Mon Sep 17 00:00:00 2001
From: kis1yi <35934681+kis1yi@users.noreply.github.com>
Date: Wed, 3 Jun 2026 16:56:19 +0200
Subject: [PATCH 5/6] Protection against NullReferenceException
---
Library/RSBot.Core/Bot.cs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/Library/RSBot.Core/Bot.cs b/Library/RSBot.Core/Bot.cs
index 93ff0175..a12526a8 100644
--- a/Library/RSBot.Core/Bot.cs
+++ b/Library/RSBot.Core/Bot.cs
@@ -134,6 +134,10 @@ public void Stop()
private void CancelActionOnStop()
{
+ var player = Game.Player;
+ if (player == null)
+ return;
+
SkillManager.CancelAction(0);
_ = Task.Run(async () =>
@@ -142,7 +146,7 @@ private void CancelActionOnStop()
{
await Task.Delay(100);
- if (Running || !Game.Player.InAction)
+ if (Running || !Game.Ready || !ReferenceEquals(Game.Player, player) || !player.InAction)
return;
SkillManager.CancelAction(0);
From a80600a5bd0320e84a7f59a56c54ef09911f3223 Mon Sep 17 00:00:00 2001
From: kis1yi <35934681+kis1yi@users.noreply.github.com>
Date: Wed, 3 Jun 2026 17:31:35 +0200
Subject: [PATCH 6/6] Improved cancel action retries
---
Library/RSBot.Core/Bot.cs | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/Library/RSBot.Core/Bot.cs b/Library/RSBot.Core/Bot.cs
index a12526a8..30dd06e3 100644
--- a/Library/RSBot.Core/Bot.cs
+++ b/Library/RSBot.Core/Bot.cs
@@ -135,22 +135,28 @@ public void Stop()
private void CancelActionOnStop()
{
var player = Game.Player;
- if (player == null)
+ if (player == null || !player.InAction)
return;
- SkillManager.CancelAction(0);
+ _ = CancelActionOnStopAsync();
- _ = Task.Run(async () =>
+ async Task CancelActionOnStopAsync()
{
- for (var i = 1; i < 5; i++)
- {
- await Task.Delay(100);
+ const int attempts = 5;
+ const int retryDelay = 1000;
+ for (var i = 0; i < attempts; i++)
+ {
if (Running || !Game.Ready || !ReferenceEquals(Game.Player, player) || !player.InAction)
return;
SkillManager.CancelAction(0);
+
+ if (i == attempts - 1)
+ return;
+
+ await Task.Delay(retryDelay).ConfigureAwait(false);
}
- });
+ }
}
}