boss ready

This commit is contained in:
Boki 2026-02-21 15:44:22 -05:00
parent 89c3a0a077
commit 64a6ab694b
21 changed files with 857 additions and 249 deletions

View file

@ -71,6 +71,7 @@ public sealed class D2dOverlay
using var ctx = new D2dRenderContext(hwnd, Width, Height);
_layers.Add(new D2dEnemyBoxLayer(ctx));
_layers.Add(new D2dLootLabelLayer(ctx));
_layers.Add(new D2dHudInfoLayer());
_layers.Add(new D2dDebugTextLayer());
@ -182,6 +183,9 @@ public sealed class D2dOverlay
{
var detection = _bot.EnemyDetector.Latest;
var bossDetection = _bot.BossDetector.Latest;
var showLoot = _bot.LootDebugDetector.Enabled;
return new OverlayState(
Enemies: detection.Enemies,
Bosses: bossDetection.Bosses,
@ -192,6 +196,8 @@ public sealed class D2dOverlay
NavPosition: _bot.Navigation.WorldPosition,
IsExploring: _bot.Navigation.IsExploring,
ShowHudDebug: _bot.Store.Settings.ShowHudDebug,
ShowLootDebug: showLoot,
LootLabels: _bot.LootDebugDetector.Latest,
Fps: fps,
Timing: timing);
}

View file

@ -13,6 +13,8 @@ public record OverlayState(
MapPosition NavPosition,
bool IsExploring,
bool ShowHudDebug,
bool ShowLootDebug,
IReadOnlyList<LootLabel> LootLabels,
double Fps,
RenderTiming? Timing);

View file

@ -0,0 +1,61 @@
using System.Drawing;
using Vortice.Direct2D1;
using Vortice.DirectWrite;
using Vortice.Mathematics;
namespace Poe2Trade.Ui.Overlay.Layers;
internal sealed class D2dLootLabelLayer : ID2dOverlayLayer, IDisposable
{
private readonly D2dRenderContext _ctx;
private readonly Dictionary<string, IDWriteTextLayout> _labelCache = new();
private ID2D1SolidColorBrush? _fillBrush;
public D2dLootLabelLayer(D2dRenderContext ctx)
{
_ctx = ctx;
_fillBrush = ctx.RenderTarget.CreateSolidColorBrush(new Color4(0f, 1f, 0f, 0.15f));
}
public void Draw(D2dRenderContext ctx, OverlayState state)
{
if (!state.ShowLootDebug || state.LootLabels.Count == 0) return;
var rt = ctx.RenderTarget;
foreach (var label in state.LootLabels)
{
float x = label.CenterX - label.Width / 2f;
float y = label.CenterY - label.Height / 2f;
float w = label.Width;
float h = label.Height;
var rect = new RectangleF(x, y, w, h);
rt.FillRectangle(rect, _fillBrush!);
rt.DrawRectangle(rect, ctx.Green, 3f);
// Label: "tier (R,G,B)"
var key = $"{label.Tier} ({label.AvgR},{label.AvgG},{label.AvgB})";
if (!_labelCache.TryGetValue(key, out var layout))
{
layout = _ctx.CreateTextLayout(key, _ctx.LabelFormat);
_labelCache[key] = layout;
}
var m = layout.Metrics;
var labelX = x;
var labelY = 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, ctx.Green);
}
}
public void Dispose()
{
foreach (var l in _labelCache.Values) l?.Dispose();
}
}

View file

@ -20,6 +20,12 @@ public partial class DebugViewModel : ObservableObject
[ObservableProperty] private string _selectedGridLayout = "inventory";
[ObservableProperty] private decimal? _clickX;
[ObservableProperty] private decimal? _clickY;
[ObservableProperty] private bool _showLootDebug;
partial void OnShowLootDebugChanged(bool value)
{
_bot.LootDebugDetector.Enabled = value;
}
public string[] GridLayoutNames { get; } =
[

View file

@ -24,6 +24,7 @@ public partial class MappingViewModel : ObservableObject, IDisposable
[ObservableProperty] private string _invitationTabPath = "";
[ObservableProperty] private string _lootTabPath = "";
[ObservableProperty] private decimal? _invitationCount = 15;
[ObservableProperty] private decimal? _runCount = 15;
public static MapType[] MapTypes { get; } = [MapType.TrialOfChaos, MapType.Temple, MapType.Endgame, MapType.Kulemak];
public ObservableCollection<string> StashTabPaths { get; } = [];
@ -45,6 +46,7 @@ public partial class MappingViewModel : ObservableObject, IDisposable
_invitationTabPath = bot.Config.Kulemak.InvitationTabPath;
_lootTabPath = bot.Config.Kulemak.LootTabPath;
_invitationCount = bot.Config.Kulemak.InvitationCount;
_runCount = bot.Config.Kulemak.RunCount;
LoadStashTabPaths();
_bot.EnemyDetector.DetectionUpdated += OnDetectionUpdated;
@ -80,6 +82,11 @@ public partial class MappingViewModel : ObservableObject, IDisposable
_bot.Store.UpdateSettings(s => s.Kulemak.InvitationCount = (int)(value ?? 15));
}
partial void OnRunCountChanged(decimal? value)
{
_bot.Store.UpdateSettings(s => s.Kulemak.RunCount = (int)(value ?? 15));
}
private void LoadStashTabPaths()
{
StashTabPaths.Clear();

View file

@ -255,10 +255,10 @@
SelectedItem="{Binding LootTabPath}" />
</DockPanel>
<DockPanel>
<TextBlock Text="Invitations per batch" FontSize="11" Foreground="#8b949e"
<TextBlock Text="Runs" FontSize="11" Foreground="#8b949e"
Width="140" VerticalAlignment="Center" />
<NumericUpDown Value="{Binding InvitationCount}"
Minimum="1" Maximum="60" Increment="1" Width="100" />
<NumericUpDown Value="{Binding RunCount}"
Minimum="1" Maximum="999" Increment="1" Width="100" />
</DockPanel>
</StackPanel>
</Border>
@ -334,6 +334,17 @@
</StackPanel>
</Border>
<!-- Debug overlays -->
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
CornerRadius="8" Padding="8">
<StackPanel Spacing="6">
<TextBlock Text="DEBUG OVERLAYS" FontSize="11" FontWeight="SemiBold"
Foreground="#8b949e" />
<ToggleSwitch IsChecked="{Binding ShowLootDebug}"
Content="Loot Labels" Foreground="#e6edf3" />
</StackPanel>
</Border>
<!-- Row 2: Find text -->
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
CornerRadius="8" Padding="8">