stash calibration

This commit is contained in:
Boki 2026-02-18 20:01:05 -05:00
parent 3ae65d0e64
commit 3062993f7c
3 changed files with 21 additions and 12 deletions

View file

@ -16,7 +16,8 @@ public class StashCalibrator
private static readonly Region SubTabRegion = new(23, 165, 840, 50); private static readonly Region SubTabRegion = new(23, 165, 840, 50);
// Horizontal gap (px) between OCR words to split into separate tab names // Horizontal gap (px) between OCR words to split into separate tab names
private const int TabGapThreshold = 25; private const int TabGapThreshold = 25;
private const int PostClickDelay = 600; private const int PostTabClickMin = 120;
private const int PostTabClickMax = 250;
public StashCalibrator(IScreenReader screen, IGameController game) public StashCalibrator(IScreenReader screen, IGameController game)
{ {
@ -27,21 +28,24 @@ public class StashCalibrator
/// <summary> /// <summary>
/// Calibrates an already-open stash/shop panel. /// Calibrates an already-open stash/shop panel.
/// OCRs tab bar, clicks each tab, detects folders and grid size. /// OCRs tab bar, clicks each tab, detects folders and grid size.
/// When firstFolderOnly is true (shop), only the first folder is inspected.
/// </summary> /// </summary>
public async Task<StashCalibration> CalibrateOpenPanel() public async Task<StashCalibration> CalibrateOpenPanel(bool firstFolderOnly = false)
{ {
var tabs = await OcrTabBar(TabBarRegion); var tabs = await OcrTabBar(TabBarRegion);
Log.Information("StashCalibrator: found {Count} tabs: {Names}", Log.Information("StashCalibrator: found {Count} tabs: {Names}",
tabs.Count, string.Join(", ", tabs.Select(t => t.Name))); tabs.Count, string.Join(", ", tabs.Select(t => t.Name)));
for (var i = 0; i < tabs.Count; i++) var limit = firstFolderOnly ? Math.Min(1, tabs.Count) : tabs.Count;
for (var i = 0; i < limit; i++)
{ {
var tab = tabs[i]; var tab = tabs[i];
tab.Index = i; tab.Index = i;
// Click this tab // Click this tab
await _game.LeftClickAt(tab.ClickX, tab.ClickY); await _game.LeftClickAt(tab.ClickX, tab.ClickY);
await Helpers.Sleep(PostClickDelay); await Helpers.RandomDelay(PostTabClickMin, PostTabClickMax);
// Check for sub-tabs (folder detection) // Check for sub-tabs (folder detection)
var subTabs = await OcrTabBar(SubTabRegion); var subTabs = await OcrTabBar(SubTabRegion);
@ -58,7 +62,7 @@ public class StashCalibrator
// Click sub-tab to detect its grid size // Click sub-tab to detect its grid size
await _game.LeftClickAt(sub.ClickX, sub.ClickY); await _game.LeftClickAt(sub.ClickX, sub.ClickY);
await Helpers.Sleep(PostClickDelay); await Helpers.RandomDelay(PostTabClickMin, PostTabClickMax);
sub.GridCols = await DetectGridSize(isFolder: true); sub.GridCols = await DetectGridSize(isFolder: true);
} }
@ -73,6 +77,10 @@ public class StashCalibrator
} }
} }
// For firstFolderOnly, trim to only the inspected tabs
if (firstFolderOnly && tabs.Count > limit)
tabs = tabs.GetRange(0, limit);
return new StashCalibration return new StashCalibration
{ {
Tabs = tabs, Tabs = tabs,

View file

@ -66,6 +66,7 @@ public partial class App : Application
var window = new MainWindow { DataContext = mainVm }; var window = new MainWindow { DataContext = mainVm };
window.SetConfigStore(store); window.SetConfigStore(store);
desktop.MainWindow = window; desktop.MainWindow = window;
desktop.ShutdownMode = Avalonia.Controls.ShutdownMode.OnMainWindowClose;
var overlay = new OverlayWindow(bot); var overlay = new OverlayWindow(bot);
overlay.Show(); overlay.Show();

View file

@ -212,7 +212,7 @@ public partial class DebugViewModel : ObservableObject
// Focus game and open stash // Focus game and open stash
await _bot.Game.FocusGame(); await _bot.Game.FocusGame();
await Helpers.Sleep(Delays.PostFocus); await Helpers.RandomDelay(150, 300);
var stashPos = await _bot.Inventory.FindAndClickNameplate("STASH"); var stashPos = await _bot.Inventory.FindAndClickNameplate("STASH");
if (!stashPos.HasValue) if (!stashPos.HasValue)
@ -220,30 +220,30 @@ public partial class DebugViewModel : ObservableObject
DebugResult = "STASH nameplate not found. Stand near your stash."; DebugResult = "STASH nameplate not found. Stand near your stash.";
return; return;
} }
await Helpers.Sleep(Delays.PostStashOpen); await Helpers.RandomDelay(300, 500);
// Calibrate stash // Calibrate stash
var stashCal = await calibrator.CalibrateOpenPanel(); var stashCal = await calibrator.CalibrateOpenPanel();
// Close stash, try shop // Close stash, try shop
await _bot.Game.PressEscape(); await _bot.Game.PressEscape();
await Helpers.Sleep(Delays.PostEscape); await Helpers.RandomDelay(200, 400);
StashCalibration? shopCal = null; StashCalibration? shopCal = null;
var angePos = await _bot.Inventory.FindAndClickNameplate("ANGE"); var angePos = await _bot.Inventory.FindAndClickNameplate("ANGE");
if (angePos.HasValue) if (angePos.HasValue)
{ {
await Helpers.Sleep(Delays.PostStashOpen); await Helpers.RandomDelay(300, 500);
// ANGE opens a dialog — click "Manage Shop" to open shop tabs // ANGE opens a dialog — click "Manage Shop" to open shop tabs
var managePos = await _bot.Screen.FindTextOnScreen("Manage Shop", fuzzy: true); var managePos = await _bot.Screen.FindTextOnScreen("Manage Shop", fuzzy: true);
if (managePos.HasValue) if (managePos.HasValue)
{ {
await _bot.Game.LeftClickAt(managePos.Value.X, managePos.Value.Y); await _bot.Game.LeftClickAt(managePos.Value.X, managePos.Value.Y);
await Helpers.Sleep(Delays.PostStashOpen); await Helpers.RandomDelay(300, 500);
} }
shopCal = await calibrator.CalibrateOpenPanel(); shopCal = await calibrator.CalibrateOpenPanel(firstFolderOnly: true);
await _bot.Game.PressEscape(); await _bot.Game.PressEscape();
await Helpers.Sleep(Delays.PostEscape); await Helpers.RandomDelay(200, 400);
} }
// Save // Save