This commit is contained in:
Boki 2026-02-16 13:18:04 -05:00
parent 2d6a6bd3a1
commit d80e723b94
28 changed files with 1801 additions and 352 deletions

View file

@ -40,6 +40,7 @@ public partial class App : Application
services.AddSingleton<IInventoryManager, InventoryManager>();
// Bot
services.AddSingleton<FramePipelineService>();
services.AddSingleton<LinkManager>();
services.AddSingleton<TradeExecutor>();
services.AddSingleton<TradeQueue>();

View file

@ -1,25 +1,76 @@
using Timer = System.Timers.Timer;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using Poe2Trade.Bot;
using Poe2Trade.Core;
using Poe2Trade.Screen;
namespace Poe2Trade.Ui.ViewModels;
public partial class MappingViewModel : ObservableObject
public partial class MappingViewModel : ObservableObject, IDisposable
{
private readonly BotOrchestrator _bot;
private readonly Timer _statsTimer;
[ObservableProperty] private MapType _selectedMapType;
[ObservableProperty] private bool _isFrameSaverEnabled;
[ObservableProperty] private int _framesSaved;
[ObservableProperty] private bool _isDetectionEnabled;
[ObservableProperty] private int _enemiesDetected;
[ObservableProperty] private float _inferenceMs;
[ObservableProperty] private bool _hasModel;
public static MapType[] MapTypes { get; } = [MapType.TrialOfChaos, MapType.Temple, MapType.Endgame];
private static readonly string ModelPath = Path.GetFullPath("tools/python-detect/models/enemy-v1.pt");
public MappingViewModel(BotOrchestrator bot)
{
_bot = bot;
_selectedMapType = bot.Config.MapType;
_hasModel = File.Exists(ModelPath);
_bot.EnemyDetector.DetectionUpdated += OnDetectionUpdated;
_statsTimer = new Timer(1000);
_statsTimer.Elapsed += (_, _) => Dispatcher.UIThread.Post(RefreshStats);
_statsTimer.Start();
}
partial void OnSelectedMapTypeChanged(MapType value)
{
_bot.Store.UpdateSettings(s => s.MapType = value);
}
partial void OnIsFrameSaverEnabledChanged(bool value)
{
_bot.FrameSaver.Enabled = value;
}
partial void OnIsDetectionEnabledChanged(bool value)
{
_bot.EnemyDetector.Enabled = value;
}
private void OnDetectionUpdated(DetectionSnapshot snapshot)
{
Dispatcher.UIThread.Post(() =>
{
EnemiesDetected = snapshot.Enemies.Count;
InferenceMs = snapshot.InferenceMs;
});
}
private void RefreshStats()
{
FramesSaved = _bot.FrameSaver.SavedCount;
HasModel = File.Exists(ModelPath);
}
public void Dispose()
{
_statsTimer.Stop();
_statsTimer.Dispose();
_bot.EnemyDetector.DetectionUpdated -= OnDetectionUpdated;
}
}

View file

@ -213,20 +213,66 @@
<!-- ========== MAPPING TAB ========== -->
<TabItem Header="Mapping">
<Border DataContext="{Binding MappingVm}" Background="#161b22"
BorderBrush="#30363d" BorderThickness="1" CornerRadius="8"
Padding="10" Margin="0,6,0,0">
<StackPanel Spacing="8" x:DataType="vm:MappingViewModel">
<TextBlock Text="MAP TYPE" FontSize="11" FontWeight="SemiBold"
Foreground="#8b949e" />
<ComboBox ItemsSource="{x:Static vm:MappingViewModel.MapTypes}"
SelectedItem="{Binding SelectedMapType}" Width="200" />
<TextBlock Text="REQUIRED ITEMS" FontSize="11" FontWeight="SemiBold"
Foreground="#8b949e" Margin="0,8,0,0" />
<TextBlock Text="{Binding SelectedMapType, Converter={StaticResource MapRequirementsText}}"
FontSize="13" Foreground="#e6edf3" />
<ScrollViewer DataContext="{Binding MappingVm}" Margin="0,6,0,0">
<StackPanel Spacing="8" Margin="0" x:DataType="vm:MappingViewModel">
<!-- Map Type -->
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
CornerRadius="8" Padding="10">
<StackPanel Spacing="8">
<TextBlock Text="MAP TYPE" FontSize="11" FontWeight="SemiBold"
Foreground="#8b949e" />
<ComboBox ItemsSource="{x:Static vm:MappingViewModel.MapTypes}"
SelectedItem="{Binding SelectedMapType}" Width="200" />
<TextBlock Text="REQUIRED ITEMS" FontSize="11" FontWeight="SemiBold"
Foreground="#8b949e" Margin="0,8,0,0" />
<TextBlock Text="{Binding SelectedMapType, Converter={StaticResource MapRequirementsText}}"
FontSize="13" Foreground="#e6edf3" />
</StackPanel>
</Border>
<!-- Training Data -->
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
CornerRadius="8" Padding="10">
<StackPanel Spacing="8">
<TextBlock Text="TRAINING DATA" FontSize="11" FontWeight="SemiBold"
Foreground="#8b949e" />
<ToggleSwitch IsChecked="{Binding IsFrameSaverEnabled}"
OnContent="Save Frames" OffContent="Save Frames" />
<TextBlock FontSize="12" Foreground="#8b949e">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} frames saved to training-data/raw/">
<Binding Path="FramesSaved" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</Border>
<!-- Enemy Detection -->
<Border Background="#161b22" BorderBrush="#30363d" BorderThickness="1"
CornerRadius="8" Padding="10">
<StackPanel Spacing="8">
<TextBlock Text="ENEMY DETECTION" FontSize="11" FontWeight="SemiBold"
Foreground="#8b949e" />
<ToggleSwitch IsChecked="{Binding IsDetectionEnabled}"
IsEnabled="{Binding HasModel}"
OnContent="Detection On" OffContent="Detection Off" />
<StackPanel Orientation="Horizontal" Spacing="16"
IsVisible="{Binding HasModel}">
<TextBlock Text="{Binding EnemiesDetected, StringFormat='{}{0} enemies'}"
FontSize="12" Foreground="#e6edf3" />
<TextBlock Text="{Binding InferenceMs, StringFormat='{}{0:F1}ms inference'}"
FontSize="12" Foreground="#8b949e" />
</StackPanel>
<TextBlock Text="No model found. Train one first."
FontSize="12" Foreground="#484f58"
IsVisible="{Binding !HasModel}" />
</StackPanel>
</Border>
</StackPanel>
</Border>
</ScrollViewer>
</TabItem>
<!-- ========== DEBUG TAB ========== -->