started adding navigation
This commit is contained in:
parent
32781b1462
commit
468e0a7246
20 changed files with 844 additions and 31 deletions
156
src/Poe2Trade.Navigation/NavigationExecutor.cs
Normal file
156
src/Poe2Trade.Navigation/NavigationExecutor.cs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
using Poe2Trade.Core;
|
||||
using Poe2Trade.Game;
|
||||
using Serilog;
|
||||
|
||||
namespace Poe2Trade.Navigation;
|
||||
|
||||
public class NavigationExecutor : IDisposable
|
||||
{
|
||||
private readonly IGameController _game;
|
||||
private readonly MinimapConfig _config;
|
||||
private readonly MinimapCapture _capture;
|
||||
private readonly PositionTracker _tracker;
|
||||
private readonly WorldMap _worldMap;
|
||||
private NavigationState _state = NavigationState.Idle;
|
||||
private bool _stopped;
|
||||
private static readonly Random Rng = new();
|
||||
|
||||
public event Action<NavigationState>? StateChanged;
|
||||
public NavigationState State => _state;
|
||||
|
||||
public NavigationExecutor(IGameController game, MinimapConfig? config = null)
|
||||
{
|
||||
_game = game;
|
||||
_config = config ?? new MinimapConfig();
|
||||
_capture = new MinimapCapture(_config);
|
||||
_tracker = new PositionTracker(_config);
|
||||
_worldMap = new WorldMap(_config);
|
||||
}
|
||||
|
||||
private void SetState(NavigationState s)
|
||||
{
|
||||
_state = s;
|
||||
StateChanged?.Invoke(s);
|
||||
}
|
||||
|
||||
public Task Stop()
|
||||
{
|
||||
_stopped = true;
|
||||
SetState(NavigationState.Idle);
|
||||
Log.Information("Navigation executor stopped");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_tracker.Reset();
|
||||
_worldMap.Reset();
|
||||
_stopped = false;
|
||||
SetState(NavigationState.Idle);
|
||||
}
|
||||
|
||||
public async Task RunExploreLoop()
|
||||
{
|
||||
_stopped = false;
|
||||
Log.Information("Starting explore loop");
|
||||
|
||||
// Open minimap overlay (Tab)
|
||||
await _game.ToggleMinimap();
|
||||
await Helpers.Sleep(300);
|
||||
|
||||
while (!_stopped)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 1. Capture frame
|
||||
SetState(NavigationState.Capturing);
|
||||
using var frame = _capture.CaptureFrame();
|
||||
if (frame == null)
|
||||
{
|
||||
Log.Warning("Failed to capture minimap frame");
|
||||
await Helpers.Sleep(200);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. Track position via phase correlation
|
||||
SetState(NavigationState.Processing);
|
||||
var pos = _tracker.UpdatePosition(frame.GrayMat);
|
||||
|
||||
// 3. Stitch into world map
|
||||
_worldMap.StitchFrame(frame.ClassifiedMat, pos);
|
||||
|
||||
// 4. Check if stuck
|
||||
if (_tracker.IsStuck)
|
||||
{
|
||||
SetState(NavigationState.Stuck);
|
||||
Log.Information("Stuck detected, clicking random direction");
|
||||
await ClickRandomDirection();
|
||||
await Helpers.Sleep(_config.MovementWaitMs);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 5. Find best exploration direction
|
||||
SetState(NavigationState.Planning);
|
||||
var direction = _worldMap.FindNearestUnexplored(pos);
|
||||
|
||||
if (direction == null)
|
||||
{
|
||||
Log.Information("Map fully explored");
|
||||
SetState(NavigationState.Completed);
|
||||
break;
|
||||
}
|
||||
|
||||
// 6. Click to move in that direction
|
||||
SetState(NavigationState.Moving);
|
||||
await ClickToMove(direction.Value.dirX, direction.Value.dirY);
|
||||
|
||||
// 7. Wait for character to walk
|
||||
await Helpers.Sleep(_config.MovementWaitMs);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error in explore loop");
|
||||
SetState(NavigationState.Failed);
|
||||
await Helpers.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (_state != NavigationState.Completed)
|
||||
SetState(NavigationState.Idle);
|
||||
|
||||
Log.Information("Explore loop ended");
|
||||
}
|
||||
|
||||
private async Task ClickToMove(double dirX, double dirY)
|
||||
{
|
||||
// Player is at minimap center on screen; click offset from center
|
||||
var len = Math.Sqrt(dirX * dirX + dirY * dirY);
|
||||
if (len < 0.001) return;
|
||||
|
||||
var nx = dirX / len;
|
||||
var ny = dirY / len;
|
||||
|
||||
var clickX = _config.MinimapCenterX + (int)(nx * _config.ClickRadius);
|
||||
var clickY = _config.MinimapCenterY + (int)(ny * _config.ClickRadius);
|
||||
|
||||
Log.Debug("Click to move: ({X}, {Y}) dir=({Dx:F2}, {Dy:F2})", clickX, clickY, nx, ny);
|
||||
await _game.LeftClickAt(clickX, clickY);
|
||||
}
|
||||
|
||||
private async Task ClickRandomDirection()
|
||||
{
|
||||
var angle = Rng.NextDouble() * 2 * Math.PI;
|
||||
await ClickToMove(Math.Cos(angle), Math.Sin(angle));
|
||||
}
|
||||
|
||||
public MapPosition Position => _tracker.Position;
|
||||
public byte[] GetMapSnapshot() => _worldMap.GetMapSnapshot();
|
||||
public byte[] GetViewportSnapshot(int viewSize = 400) => _worldMap.GetViewportSnapshot(_tracker.Position, viewSize);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_capture.Dispose();
|
||||
_tracker.Dispose();
|
||||
_worldMap.Dispose();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue