much better bot and ocr
This commit is contained in:
parent
bb8f50116a
commit
6257bcf122
25 changed files with 583 additions and 101 deletions
|
|
@ -8,6 +8,7 @@ using Poe2Trade.Game;
|
|||
using Poe2Trade.GameLog;
|
||||
using Poe2Trade.Inventory;
|
||||
using Poe2Trade.Screen;
|
||||
using Poe2Trade.Screen.Ocr;
|
||||
using Poe2Trade.Trade;
|
||||
using Poe2Trade.Ui.Overlay;
|
||||
using Poe2Trade.Ui.ViewModels;
|
||||
|
|
@ -33,6 +34,11 @@ public partial class App : Application
|
|||
services.AddSingleton(sp => sp.GetRequiredService<ConfigStore>().Settings);
|
||||
|
||||
// Services
|
||||
services.AddSingleton<IOcrEngine>(sp =>
|
||||
{
|
||||
var settings = sp.GetRequiredService<SavedSettings>();
|
||||
return OcrEngineFactory.Create(settings.OcrEngine);
|
||||
});
|
||||
services.AddSingleton<IGameController, GameController>();
|
||||
services.AddSingleton<IScreenReader, ScreenReader>();
|
||||
services.AddSingleton<IClientLogWatcher>(sp =>
|
||||
|
|
|
|||
|
|
@ -197,6 +197,8 @@ public sealed class D2dOverlay
|
|||
IsExploring: _bot.Navigation.IsExploring,
|
||||
ShowHudDebug: _bot.Store.Settings.ShowHudDebug,
|
||||
ShowLootDebug: showLoot,
|
||||
ShowYolo: _bot.ShowYoloOverlay,
|
||||
ShowFightPosition: _bot.ShowFightPositionOverlay,
|
||||
LootLabels: _bot.LootDebugDetector.Latest,
|
||||
FightPosition: _bot.BossRunExecutor.FightPosition,
|
||||
Fps: fps,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ public record OverlayState(
|
|||
bool IsExploring,
|
||||
bool ShowHudDebug,
|
||||
bool ShowLootDebug,
|
||||
bool ShowYolo,
|
||||
bool ShowFightPosition,
|
||||
IReadOnlyList<LootLabel> LootLabels,
|
||||
(double X, double Y)? FightPosition,
|
||||
double Fps,
|
||||
|
|
|
|||
|
|
@ -28,63 +28,68 @@ internal sealed class D2dEnemyBoxLayer : ID2dOverlayLayer, IDisposable
|
|||
|
||||
public void Draw(D2dRenderContext ctx, OverlayState state)
|
||||
{
|
||||
if (!state.ShowYolo && !state.ShowFightPosition) return;
|
||||
|
||||
var rt = ctx.RenderTarget;
|
||||
|
||||
foreach (var enemy in state.Enemies)
|
||||
if (state.ShowYolo)
|
||||
{
|
||||
var confirmed = enemy.HealthBarConfirmed;
|
||||
var boxBrush = confirmed ? ctx.Red : ctx.Yellow;
|
||||
var rect = new RectangleF(enemy.X, enemy.Y, enemy.Width, enemy.Height);
|
||||
rt.DrawRectangle(rect, boxBrush, 2f);
|
||||
|
||||
// Confidence label above the box
|
||||
var pctIndex = Math.Clamp((int)(enemy.Confidence * 100), 0, 100);
|
||||
var layout = confirmed ? _confirmedLabels[pctIndex] : _unconfirmedLabels[pctIndex];
|
||||
var textBrush = confirmed ? ctx.Red : ctx.Yellow;
|
||||
|
||||
var m = layout.Metrics;
|
||||
var labelX = enemy.X;
|
||||
var labelY = enemy.Y - m.Height - 2;
|
||||
|
||||
rt.FillRectangle(
|
||||
new RectangleF(labelX - 1, labelY - 1, m.Width + 2, m.Height + 2),
|
||||
ctx.LabelBgBrush);
|
||||
|
||||
rt.DrawTextLayout(new System.Numerics.Vector2(labelX, labelY), layout, textBrush);
|
||||
}
|
||||
|
||||
// Boss bounding boxes (cyan) — extrapolate position to compensate for inference delay
|
||||
var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
var ageMs = (float)Math.Clamp(now - state.BossTimestampMs, 0, 60);
|
||||
|
||||
foreach (var boss in state.Bosses)
|
||||
{
|
||||
float dx = boss.VxPerMs * ageMs;
|
||||
float dy = boss.VyPerMs * ageMs;
|
||||
var rect = new RectangleF(boss.X + dx, boss.Y + dy, boss.Width, boss.Height);
|
||||
rt.DrawRectangle(rect, ctx.Cyan, 3f);
|
||||
|
||||
var pct = Math.Clamp((int)(boss.Confidence * 100), 0, 100);
|
||||
var key = $"{boss.ClassName} {pct}%";
|
||||
if (!_bossLabels.TryGetValue(key, out var layout))
|
||||
foreach (var enemy in state.Enemies)
|
||||
{
|
||||
layout = _ctx.CreateTextLayout(key, _ctx.LabelFormat);
|
||||
_bossLabels[key] = layout;
|
||||
var confirmed = enemy.HealthBarConfirmed;
|
||||
var boxBrush = confirmed ? ctx.Red : ctx.Yellow;
|
||||
var rect = new RectangleF(enemy.X, enemy.Y, enemy.Width, enemy.Height);
|
||||
rt.DrawRectangle(rect, boxBrush, 2f);
|
||||
|
||||
// Confidence label above the box
|
||||
var pctIndex = Math.Clamp((int)(enemy.Confidence * 100), 0, 100);
|
||||
var layout = confirmed ? _confirmedLabels[pctIndex] : _unconfirmedLabels[pctIndex];
|
||||
var textBrush = confirmed ? ctx.Red : ctx.Yellow;
|
||||
|
||||
var m = layout.Metrics;
|
||||
var labelX = enemy.X;
|
||||
var labelY = enemy.Y - m.Height - 2;
|
||||
|
||||
rt.FillRectangle(
|
||||
new RectangleF(labelX - 1, labelY - 1, m.Width + 2, m.Height + 2),
|
||||
ctx.LabelBgBrush);
|
||||
|
||||
rt.DrawTextLayout(new System.Numerics.Vector2(labelX, labelY), layout, textBrush);
|
||||
}
|
||||
|
||||
var m = layout.Metrics;
|
||||
var labelX = boss.X + dx;
|
||||
var labelY = boss.Y + dy - m.Height - 2;
|
||||
// Boss bounding boxes (cyan) — extrapolate position to compensate for inference delay
|
||||
var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
var ageMs = (float)Math.Clamp(now - state.BossTimestampMs, 0, 60);
|
||||
|
||||
rt.FillRectangle(
|
||||
new RectangleF(labelX - 1, labelY - 1, m.Width + 2, m.Height + 2),
|
||||
ctx.LabelBgBrush);
|
||||
foreach (var boss in state.Bosses)
|
||||
{
|
||||
float dx = boss.VxPerMs * ageMs;
|
||||
float dy = boss.VyPerMs * ageMs;
|
||||
var rect = new RectangleF(boss.X + dx, boss.Y + dy, boss.Width, boss.Height);
|
||||
rt.DrawRectangle(rect, ctx.Cyan, 3f);
|
||||
|
||||
rt.DrawTextLayout(new System.Numerics.Vector2(labelX, labelY), layout, ctx.Cyan);
|
||||
var pct = Math.Clamp((int)(boss.Confidence * 100), 0, 100);
|
||||
var key = $"{boss.ClassName} {pct}%";
|
||||
if (!_bossLabels.TryGetValue(key, out var layout))
|
||||
{
|
||||
layout = _ctx.CreateTextLayout(key, _ctx.LabelFormat);
|
||||
_bossLabels[key] = layout;
|
||||
}
|
||||
|
||||
var m = layout.Metrics;
|
||||
var labelX = boss.X + dx;
|
||||
var labelY = boss.Y + dy - m.Height - 2;
|
||||
|
||||
rt.FillRectangle(
|
||||
new RectangleF(labelX - 1, labelY - 1, m.Width + 2, m.Height + 2),
|
||||
ctx.LabelBgBrush);
|
||||
|
||||
rt.DrawTextLayout(new System.Numerics.Vector2(labelX, labelY), layout, ctx.Cyan);
|
||||
}
|
||||
}
|
||||
|
||||
// Fight position — red circle on screen where the fight area is
|
||||
if (state.FightPosition is var (fx, fy))
|
||||
if (state.ShowFightPosition && state.FightPosition is var (fx, fy))
|
||||
{
|
||||
const double worldToScreen = 835.0 / 97.0; // inverse of screenToWorld
|
||||
const int screenCx = 1280, screenCy = 660; // player character screen position
|
||||
|
|
|
|||
|
|
@ -23,12 +23,24 @@ public partial class DebugViewModel : ObservableObject
|
|||
[ObservableProperty] private decimal? _clickX;
|
||||
[ObservableProperty] private decimal? _clickY;
|
||||
[ObservableProperty] private bool _showLootDebug;
|
||||
[ObservableProperty] private bool _showYolo = true;
|
||||
[ObservableProperty] private bool _showFightPosition = true;
|
||||
|
||||
partial void OnShowLootDebugChanged(bool value)
|
||||
{
|
||||
_bot.LootDebugDetector.Enabled = value;
|
||||
}
|
||||
|
||||
partial void OnShowYoloChanged(bool value)
|
||||
{
|
||||
_bot.ShowYoloOverlay = value;
|
||||
}
|
||||
|
||||
partial void OnShowFightPositionChanged(bool value)
|
||||
{
|
||||
_bot.ShowFightPositionOverlay = value;
|
||||
}
|
||||
|
||||
public string[] GridLayoutNames { get; } =
|
||||
[
|
||||
"inventory", "stash12", "stash12_folder", "stash24",
|
||||
|
|
|
|||
|
|
@ -20,11 +20,14 @@ public partial class SettingsViewModel : ObservableObject
|
|||
[ObservableProperty] private decimal? _betweenTradesDelayMs = 5000;
|
||||
[ObservableProperty] private bool _headless = true;
|
||||
[ObservableProperty] private bool _showHudDebug;
|
||||
[ObservableProperty] private string _ocrEngine = "WinOCR";
|
||||
[ObservableProperty] private bool _isSaved;
|
||||
[ObservableProperty] private string _calibrationStatus = "";
|
||||
[ObservableProperty] private string _stashCalibratedAt = "";
|
||||
[ObservableProperty] private string _shopCalibratedAt = "";
|
||||
|
||||
public static string[] OcrEngineOptions { get; } = ["WinOCR", "OneOCR", "EasyOCR"];
|
||||
|
||||
public ObservableCollection<StashTabViewModel> StashTabs { get; } = [];
|
||||
public ObservableCollection<StashTabViewModel> ShopTabs { get; } = [];
|
||||
|
||||
|
|
@ -46,6 +49,7 @@ public partial class SettingsViewModel : ObservableObject
|
|||
BetweenTradesDelayMs = s.BetweenTradesDelayMs;
|
||||
Headless = s.Headless;
|
||||
ShowHudDebug = s.ShowHudDebug;
|
||||
OcrEngine = s.OcrEngine;
|
||||
}
|
||||
|
||||
private void LoadTabs()
|
||||
|
|
@ -97,6 +101,7 @@ public partial class SettingsViewModel : ObservableObject
|
|||
s.BetweenTradesDelayMs = (int)(BetweenTradesDelayMs ?? 5000);
|
||||
s.Headless = Headless;
|
||||
s.ShowHudDebug = ShowHudDebug;
|
||||
s.OcrEngine = OcrEngine;
|
||||
});
|
||||
|
||||
IsSaved = true;
|
||||
|
|
@ -210,4 +215,5 @@ public partial class SettingsViewModel : ObservableObject
|
|||
partial void OnBetweenTradesDelayMsChanged(decimal? value) => IsSaved = false;
|
||||
partial void OnHeadlessChanged(bool value) => IsSaved = false;
|
||||
partial void OnShowHudDebugChanged(bool value) => IsSaved = false;
|
||||
partial void OnOcrEngineChanged(string value) => IsSaved = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -341,6 +341,10 @@
|
|||
<StackPanel Spacing="6">
|
||||
<TextBlock Text="DEBUG OVERLAYS" FontSize="11" FontWeight="SemiBold"
|
||||
Foreground="#8b949e" />
|
||||
<ToggleSwitch IsChecked="{Binding ShowYolo}"
|
||||
Content="YOLO Boxes" Foreground="#e6edf3" />
|
||||
<ToggleSwitch IsChecked="{Binding ShowFightPosition}"
|
||||
Content="Fight Position" Foreground="#e6edf3" />
|
||||
<ToggleSwitch IsChecked="{Binding ShowLootDebug}"
|
||||
Content="Loot Labels" Foreground="#e6edf3" />
|
||||
</StackPanel>
|
||||
|
|
@ -455,6 +459,12 @@
|
|||
<CheckBox IsChecked="{Binding ShowHudDebug}" Content="Show HUD debug overlay"
|
||||
Foreground="#e6edf3" />
|
||||
|
||||
<StackPanel Spacing="4" Margin="0,4,0,0">
|
||||
<TextBlock Text="OCR Engine (restart required)" FontSize="11" Foreground="#8b949e" />
|
||||
<ComboBox ItemsSource="{Binding OcrEngineOptions}"
|
||||
SelectedItem="{Binding OcrEngine}" MinWidth="200" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="8" Margin="0,2,0,0">
|
||||
<Button Content="Save Settings" Command="{Binding SaveSettingsCommand}" />
|
||||
<TextBlock Text="Saved!" Foreground="#3fb950" VerticalAlignment="Center"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue