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);
// Horizontal gap (px) between OCR words to split into separate tab names
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)
{
@ -27,21 +28,24 @@ public class StashCalibrator
/// <summary>
/// Calibrates an already-open stash/shop panel.
/// OCRs tab bar, clicks each tab, detects folders and grid size.
/// When firstFolderOnly is true (shop), only the first folder is inspected.
/// </summary>
public async Task<StashCalibration> CalibrateOpenPanel()
public async Task<StashCalibration> CalibrateOpenPanel(bool firstFolderOnly = false)
{
var tabs = await OcrTabBar(TabBarRegion);
Log.Information("StashCalibrator: found {Count} tabs: {Names}",
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];
tab.Index = i;
// Click this tab
await _game.LeftClickAt(tab.ClickX, tab.ClickY);
await Helpers.Sleep(PostClickDelay);
await Helpers.RandomDelay(PostTabClickMin, PostTabClickMax);
// Check for sub-tabs (folder detection)
var subTabs = await OcrTabBar(SubTabRegion);
@ -58,7 +62,7 @@ public class StashCalibrator
// Click sub-tab to detect its grid size
await _game.LeftClickAt(sub.ClickX, sub.ClickY);
await Helpers.Sleep(PostClickDelay);
await Helpers.RandomDelay(PostTabClickMin, PostTabClickMax);
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
{
Tabs = tabs,

View file

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

View file

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