This commit is contained in:
Boki 2026-02-21 23:35:32 -05:00
parent 152c74fa15
commit 5e1b5c2a48
10 changed files with 211 additions and 150 deletions

View file

@ -20,6 +20,10 @@ public abstract class GameExecutor
protected readonly IInventoryManager _inventory;
protected readonly SavedSettings _config;
protected volatile bool _stopped;
protected CancellationTokenSource _stopCts = new();
/// <summary>Cancellation token that fires when Stop() is called.</summary>
protected CancellationToken StopToken => _stopCts.Token;
protected GameExecutor(IGameController game, IScreenReader screen,
IInventoryManager inventory, SavedSettings config)
@ -33,8 +37,20 @@ public abstract class GameExecutor
public virtual void Stop()
{
_stopped = true;
_stopCts.Cancel();
}
/// <summary>Reset stopped state for a new run.</summary>
protected void ResetStop()
{
_stopped = false;
_stopCts.Dispose();
_stopCts = new CancellationTokenSource();
}
/// <summary>Cancellable sleep that throws OperationCanceledException when stopped.</summary>
protected Task Sleep(int ms) => Helpers.Sleep(ms, _stopCts.Token);
// ------ Loot pickup ------
// Tiers to skip (noise, low-value, or hidden by filter)
@ -53,11 +69,11 @@ public abstract class GameExecutor
// Move mouse out of the way so it doesn't cover labels
_game.MoveMouseInstant(0, 1440);
await Helpers.Sleep(100);
await Sleep(100);
// Hold Alt, capture, detect
await _game.KeyDown(InputSender.VK.MENU);
await Helpers.Sleep(250);
await Sleep(250);
using var capture = _screen.CaptureRawBitmap();
var labels = _screen.DetectLootLabels(capture, capture);
@ -81,14 +97,14 @@ public abstract class GameExecutor
label.Tier, label.AvgR, label.AvgG, label.AvgB, label.CenterX, label.CenterY);
await _game.LeftClickAt(label.CenterX, label.CenterY);
totalPicked++;
await Helpers.Sleep(200);
await Sleep(200);
}
// Quick check: capture small region around each clicked label to see if
// new labels appeared underneath. If none changed, we're done.
await Helpers.Sleep(300);
await Sleep(300);
_game.MoveMouseInstant(0, 1440);
await Helpers.Sleep(100);
await Sleep(100);
using var recheck = _screen.CaptureRawBitmap();
var newLabels = _screen.DetectLootLabels(recheck, recheck);
@ -103,7 +119,7 @@ public abstract class GameExecutor
}
Log.Information("Quick recheck: {Count} new labels appeared, continuing", newPickups.Count);
await Helpers.Sleep(300);
await Sleep(300);
}
Log.Information("Loot pickup complete ({Count} items)", totalPicked);
@ -118,9 +134,9 @@ public abstract class GameExecutor
Log.Information("Recovering: escaping and going to hideout");
await _game.FocusGame();
await _game.PressEscape();
await Helpers.Sleep(Delays.PostEscape);
await Sleep(Delays.PostEscape);
await _game.PressEscape();
await Helpers.Sleep(Delays.PostEscape);
await Sleep(Delays.PostEscape);
var arrived = await _inventory.WaitForAreaTransition(
_config.TravelTimeoutMs, () => _game.GoToHideout());
@ -160,7 +176,7 @@ public abstract class GameExecutor
var match = await _screen.TemplateMatch(templatePath);
if (match == null)
{
await Helpers.Sleep(500);
await Sleep(500);
continue;
}
@ -182,7 +198,7 @@ public abstract class GameExecutor
// Stop, settle, re-match for accurate position
await _game.KeyUp(vk2);
await _game.KeyUp(vk1);
await Helpers.Sleep(300);
await Sleep(300);
var fresh = await _screen.TemplateMatch(templatePath);
if (fresh != null)
@ -194,7 +210,7 @@ public abstract class GameExecutor
return match;
}
await Helpers.Sleep(200);
await Sleep(200);
}
Log.Error("WalkAndMatch timed out after {Ms}ms (spotted={Spotted})", timeoutMs, spotted);
return null;