using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Threading; using System.Threading.Tasks; using JXHelper.Config; using JXHelper.Platform; namespace JXHelper.Core; /// /// Động cơ tuần tra bãi luyện theo chuỗi tọa độ Waypoints (INV-BG-INPUT-NO-HIJACK). /// Vừa di chuyển theo lộ trình vừa hỗ trợ quét quái trên đường. /// public class PatrolEngine : IDisposable { private CancellationTokenSource? _cts; private Task? _loopTask; public bool IsPaused { get; set; } public event Action? OnLog; public void Start(IntPtr hWnd, BotConfig config) { Stop(); if (!config.PatrolEnabled) return; var waypoints = ParseWaypoints(config.WaypointsData); if (waypoints.Count == 0) return; _cts = new CancellationTokenSource(); var ct = _cts.Token; _loopTask = Task.Run(() => PatrolLoopAsync(hWnd, config, waypoints, ct), ct); } public void Stop() { _cts?.Cancel(); _cts?.Dispose(); _cts = null; _loopTask = null; } private async Task PatrolLoopAsync(IntPtr hWnd, BotConfig config, List waypoints, CancellationToken ct) { int currentIndex = 0; while (!ct.IsCancellationRequested && NativeMethods.IsWindow(hWnd)) { try { if (IsPaused || waypoints.Count == 0) { await Task.Delay(500, ct); continue; } var pt = waypoints[currentIndex]; OnLog?.Invoke($"[TUẦN TRA] Di chuyển đến Waypoint {currentIndex + 1}/{waypoints.Count}: ({pt.X}, {pt.Y})"); // Click chuột trái vào tọa độ mặt đất trong game để di chuyển await BackgroundInput.SendLeftClickAsync(hWnd, pt.X, pt.Y); // Chờ nhân vật di chuyển int intervalMs = Math.Max(2000, config.PatrolIntervalSeconds * 1000); await Task.Delay(intervalMs, ct); currentIndex = (currentIndex + 1) % waypoints.Count; } catch (OperationCanceledException) { break; } catch (Exception ex) { OnLog?.Invoke($"[LỖI TUẦN TRA] {ex.Message}"); await Task.Delay(2000, ct); } } } public static List ParseWaypoints(string? data) { var list = new List(); if (string.IsNullOrWhiteSpace(data)) return list; var parts = data.Split(';', StringSplitOptions.RemoveEmptyEntries); foreach (var p in parts) { var coords = p.Split(',', StringSplitOptions.RemoveEmptyEntries); if (coords.Length == 2 && int.TryParse(coords[0].Trim(), out int x) && int.TryParse(coords[1].Trim(), out int y)) { list.Add(new Point(x, y)); } } return list; } public static string FormatWaypoints(IEnumerable points) { return string.Join(";", points.Select(p => $"{p.X},{p.Y}")); } public void Dispose() { Stop(); } }