switched to new way
This commit is contained in:
parent
f22d182c8f
commit
4a65c8e17b
96 changed files with 4991 additions and 10025 deletions
260
src/Poe2Trade.Inventory/InventoryManager.cs
Normal file
260
src/Poe2Trade.Inventory/InventoryManager.cs
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
using Poe2Trade.Core;
|
||||
using Poe2Trade.Game;
|
||||
using Poe2Trade.GameLog;
|
||||
using Poe2Trade.Screen;
|
||||
using Serilog;
|
||||
|
||||
namespace Poe2Trade.Inventory;
|
||||
|
||||
public class InventoryManager
|
||||
{
|
||||
private static readonly string SalvageTemplate = Path.Combine("assets", "salvage.png");
|
||||
|
||||
public InventoryTracker Tracker { get; } = new();
|
||||
|
||||
private bool _atOwnHideout = true;
|
||||
private string _sellerAccount = "";
|
||||
private readonly GameController _game;
|
||||
private readonly ScreenReader _screen;
|
||||
private readonly ClientLogWatcher _logWatcher;
|
||||
private readonly AppConfig _config;
|
||||
|
||||
public bool IsAtOwnHideout => _atOwnHideout;
|
||||
public string SellerAccount => _sellerAccount;
|
||||
|
||||
public InventoryManager(GameController game, ScreenReader screen, ClientLogWatcher logWatcher, AppConfig config)
|
||||
{
|
||||
_game = game;
|
||||
_screen = screen;
|
||||
_logWatcher = logWatcher;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public void SetLocation(bool atHome, string? seller = null)
|
||||
{
|
||||
_atOwnHideout = atHome;
|
||||
_sellerAccount = seller ?? "";
|
||||
}
|
||||
|
||||
public async Task ScanInventory(PostAction defaultAction = PostAction.Stash)
|
||||
{
|
||||
Log.Information("Scanning inventory...");
|
||||
await _game.FocusGame();
|
||||
await Helpers.Sleep(300);
|
||||
await _game.OpenInventory();
|
||||
|
||||
var result = await _screen.Grid.Scan("inventory");
|
||||
|
||||
var cells = new bool[5, 12];
|
||||
foreach (var cell in result.Occupied)
|
||||
{
|
||||
if (cell.Row < 5 && cell.Col < 12)
|
||||
cells[cell.Row, cell.Col] = true;
|
||||
}
|
||||
Tracker.InitFromScan(cells, result.Items, defaultAction);
|
||||
|
||||
await _game.PressEscape();
|
||||
await Helpers.Sleep(300);
|
||||
}
|
||||
|
||||
public async Task ClearToStash()
|
||||
{
|
||||
Log.Information("Checking inventory for leftover items...");
|
||||
await ScanInventory(PostAction.Stash);
|
||||
|
||||
if (Tracker.GetItems().Count == 0)
|
||||
{
|
||||
Log.Information("Inventory empty, nothing to clear");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Information("Found {Count} leftover items, depositing to stash", Tracker.GetItems().Count);
|
||||
await DepositItemsToStash(Tracker.GetItems());
|
||||
Tracker.Clear();
|
||||
Log.Information("Inventory cleared to stash");
|
||||
}
|
||||
|
||||
public async Task<bool> EnsureAtOwnHideout()
|
||||
{
|
||||
if (_atOwnHideout)
|
||||
{
|
||||
Log.Information("Already at own hideout");
|
||||
return true;
|
||||
}
|
||||
|
||||
await _game.FocusGame();
|
||||
await Helpers.Sleep(300);
|
||||
|
||||
var arrived = await WaitForAreaTransition(_config.TravelTimeoutMs, () => _game.GoToHideout());
|
||||
if (!arrived)
|
||||
{
|
||||
Log.Error("Timed out going to own hideout");
|
||||
return false;
|
||||
}
|
||||
|
||||
await Helpers.Sleep(1500);
|
||||
_atOwnHideout = true;
|
||||
_sellerAccount = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task DepositItemsToStash(List<PlacedItem> items)
|
||||
{
|
||||
if (items.Count == 0) return;
|
||||
|
||||
var stashPos = await FindAndClickNameplate("Stash");
|
||||
if (stashPos == null)
|
||||
{
|
||||
Log.Error("Could not find Stash nameplate");
|
||||
return;
|
||||
}
|
||||
await Helpers.Sleep(1000);
|
||||
|
||||
var inventoryLayout = GridLayouts.Inventory;
|
||||
Log.Information("Depositing {Count} items to stash", items.Count);
|
||||
|
||||
await _game.HoldCtrl();
|
||||
foreach (var item in items)
|
||||
{
|
||||
var center = _screen.Grid.GetCellCenter(inventoryLayout, item.Row, item.Col);
|
||||
await _game.LeftClickAt(center.X, center.Y);
|
||||
await Helpers.Sleep(150);
|
||||
}
|
||||
await _game.ReleaseCtrl();
|
||||
await Helpers.Sleep(500);
|
||||
|
||||
await _game.PressEscape();
|
||||
await Helpers.Sleep(500);
|
||||
Log.Information("Items deposited to stash");
|
||||
}
|
||||
|
||||
public async Task<bool> SalvageItems(List<PlacedItem> items)
|
||||
{
|
||||
if (items.Count == 0) return true;
|
||||
|
||||
var nameplate = await FindAndClickNameplate("SALVAGE BENCH");
|
||||
if (nameplate == null)
|
||||
{
|
||||
Log.Error("Could not find Salvage nameplate");
|
||||
return false;
|
||||
}
|
||||
await Helpers.Sleep(1000);
|
||||
|
||||
var salvageBtn = await _screen.TemplateMatch(SalvageTemplate);
|
||||
if (salvageBtn != null)
|
||||
{
|
||||
await _game.LeftClickAt(salvageBtn.X, salvageBtn.Y);
|
||||
await Helpers.Sleep(500);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning("Could not find salvage button via template match");
|
||||
}
|
||||
|
||||
var inventoryLayout = GridLayouts.Inventory;
|
||||
Log.Information("Salvaging {Count} inventory items", items.Count);
|
||||
|
||||
await _game.HoldCtrl();
|
||||
foreach (var item in items)
|
||||
{
|
||||
var center = _screen.Grid.GetCellCenter(inventoryLayout, item.Row, item.Col);
|
||||
await _game.LeftClickAt(center.X, center.Y);
|
||||
await Helpers.Sleep(150);
|
||||
}
|
||||
await _game.ReleaseCtrl();
|
||||
await Helpers.Sleep(500);
|
||||
|
||||
await _game.PressEscape();
|
||||
await Helpers.Sleep(500);
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task ProcessInventory()
|
||||
{
|
||||
try
|
||||
{
|
||||
var home = await EnsureAtOwnHideout();
|
||||
if (!home)
|
||||
{
|
||||
Log.Error("Cannot process inventory: failed to reach hideout");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Tracker.HasItemsWithAction(PostAction.Salvage))
|
||||
{
|
||||
var salvageItems = Tracker.GetItemsByAction(PostAction.Salvage);
|
||||
if (await SalvageItems(salvageItems))
|
||||
Tracker.RemoveItemsByAction(PostAction.Salvage);
|
||||
else
|
||||
Log.Warning("Salvage failed, depositing all to stash");
|
||||
}
|
||||
|
||||
await ScanInventory(PostAction.Stash);
|
||||
|
||||
var allItems = Tracker.GetItems();
|
||||
if (allItems.Count > 0)
|
||||
await DepositItemsToStash(allItems);
|
||||
|
||||
Tracker.Clear();
|
||||
Log.Information("Inventory processing complete");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Inventory processing failed");
|
||||
try { await _game.PressEscape(); await Helpers.Sleep(300); } catch { }
|
||||
Tracker.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(int X, int Y)?> FindAndClickNameplate(string name, int maxRetries = 3, int retryDelayMs = 1000)
|
||||
{
|
||||
for (var attempt = 1; attempt <= maxRetries; attempt++)
|
||||
{
|
||||
Log.Information("Searching for nameplate '{Name}' (attempt {Attempt}/{Max})", name, attempt, maxRetries);
|
||||
var pos = await _screen.FindTextOnScreen(name, fuzzy: true);
|
||||
if (pos.HasValue)
|
||||
{
|
||||
Log.Information("Clicking nameplate '{Name}' at ({X},{Y})", name, pos.Value.X, pos.Value.Y);
|
||||
await _game.LeftClickAt(pos.Value.X, pos.Value.Y);
|
||||
return pos;
|
||||
}
|
||||
if (attempt < maxRetries)
|
||||
await Helpers.Sleep(retryDelayMs);
|
||||
}
|
||||
|
||||
Log.Warning("Nameplate '{Name}' not found after {Max} retries", name, maxRetries);
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<bool> WaitForAreaTransition(int timeoutMs, Func<Task>? triggerAction = null)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
using var cts = new CancellationTokenSource(timeoutMs);
|
||||
cts.Token.Register(() => tcs.TrySetResult(false));
|
||||
|
||||
void Handler(string _) => tcs.TrySetResult(true);
|
||||
|
||||
_logWatcher.AreaEntered += Handler;
|
||||
try
|
||||
{
|
||||
if (triggerAction != null)
|
||||
{
|
||||
try { await triggerAction(); }
|
||||
catch
|
||||
{
|
||||
tcs.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
return await tcs.Task;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_logWatcher.AreaEntered -= Handler;
|
||||
}
|
||||
}
|
||||
|
||||
public (bool[,] Grid, List<PlacedItem> Items, int Free) GetInventoryState()
|
||||
{
|
||||
return (Tracker.GetGrid(), Tracker.GetItems(), Tracker.FreeCells);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue