auto pathing: fix not releasing the mouse and keyboard when stopping tasks

更新日志和黑名单

移除 `PathExecutor.cs` 中的无用引用,重构 `Pathing` 方法,添加 `InitializePathing` 和 `ConvertWaypoints` 方法,提取传送点处理逻辑到 `HandleTeleportWaypoint` 方法。修改 `TpTask.cs` 中的日志格式为浮点数格式。将 `TaskRunner.cs` 中的 `FireAndForgetAsync` 方法重命名为 `RunThreadAsync`,并在 `ScriptService.cs` 中相应替换调用。为 `DpiHelper.cs` 中的 `ScaleY` 属性添加注释。更新 `pick_black_lists.json`,添加新的黑名单项 `"摆放巧像"`。在 `MapPathingViewModel.cs` 中添加 `_mapViewer` 字段,并在 `OnOpenMapViewer` 方法中使用。
This commit is contained in:
辉鸭蛋 2024-09-09 21:57:48 +08:00
parent 1a2b63fff7
commit a06f0fcdb2
7 changed files with 64 additions and 40 deletions

View File

@ -2,7 +2,6 @@
using BetterGenshinImpact.GameTask.AutoPathing.Model;
using BetterGenshinImpact.GameTask.AutoPathing.Model.Enum;
using BetterGenshinImpact.GameTask.AutoTrackPath;
using BetterGenshinImpact.GameTask.Common;
using BetterGenshinImpact.GameTask.Common.BgiVision;
using BetterGenshinImpact.GameTask.Common.Map;
using BetterGenshinImpact.GameTask.Model.Area;
@ -16,7 +15,6 @@ using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BetterGenshinImpact.Helpers;
using Vanara.PInvoke;
using static BetterGenshinImpact.GameTask.Common.TaskControl;
@ -28,22 +26,59 @@ public class PathExecutor(CancellationTokenSource cts)
public async Task Pathing(PathingTask task)
{
_dpi = DpiHelper.ScaleY;
if (task.Positions.Count == 0)
_dpi = TaskContext.Instance().DpiScale;
if (!task.Positions.Any())
{
Logger.LogWarning("没有路径点,寻路结束");
return;
}
task.Positions.First().Type = WaypointType.Teleport.Code;
InitializePathing(task);
// 初始化查看地图
var waypoints = ConvertWaypoints(task.Positions);
await Delay(100, cts);
Navigation.WarmUp(); // 提前加载地图特征点
try
{
foreach (var waypoint in waypoints)
{
if (waypoint.Type == WaypointType.Teleport.Code)
{
await HandleTeleportWaypoint(waypoint);
}
else
{
// Path不用走得很近Target需要接近但都需要先移动到对应位置
await MoveTo(waypoint);
if (waypoint.Type == WaypointType.Target.Code || !string.IsNullOrEmpty(waypoint.Action))
{
await MoveCloseTo(waypoint);
}
}
}
}
finally
{
// 不管咋样,松开所有按键
Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W);
Simulation.SendInput.Mouse.RightButtonUp();
}
}
private void InitializePathing(PathingTask task)
{
task.Positions.First().Type = WaypointType.Teleport.Code;
WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<object>(this,
"UpdateCurrentPathing", new object(), task));
}
// 大地图传送的时候使用游戏坐标追踪的时候应该使用2048地图图像坐标这里临时做转换后续改进
private List<Waypoint> ConvertWaypoints(List<Waypoint> positions)
{
var waypoints = new List<Waypoint>();
foreach (var waypoint in task.Positions)
foreach (var waypoint in positions)
{
if (waypoint.Type == WaypointType.Teleport.Code)
{
@ -59,30 +94,14 @@ public class PathExecutor(CancellationTokenSource cts)
(waypointCopy.X, waypointCopy.Y) = MapCoordinate.GameToMain2048(waypoint.X, waypoint.Y);
waypoints.Add(waypointCopy);
}
return waypoints;
}
await Delay(100, cts);
Navigation.WarmUp(); // 提前加载地图特征点
foreach (var waypoint in waypoints)
{
if (waypoint.Type == WaypointType.Teleport.Code)
{
// Logger.LogInformation("正在传送到{x},{y}", waypoint.X, waypoint.Y);
var (tpX, tpY) = await new TpTask(cts).Tp(waypoint.X, waypoint.Y);
var (tprX, tprY) = MapCoordinate.GameToMain2048(tpX, tpY);
EntireMap.Instance.SetPrevPosition((float)tprX, (float)tprY); // 通过上一个位置直接进行局部特征匹配
continue;
}
// Path不用走得很近Target需要接近但都需要先移动到对应位置
await MoveTo(waypoint);
if (waypoint.Type == WaypointType.Target.Code || !string.IsNullOrEmpty(waypoint.Action))
{
await MoveCloseTo(waypoint);
}
}
private async Task HandleTeleportWaypoint(Waypoint waypoint)
{
var (tpX, tpY) = await new TpTask(cts).Tp(waypoint.X, waypoint.Y);
var (tprX, tprY) = MapCoordinate.GameToMain2048(tpX, tpY);
EntireMap.Instance.SetPrevPosition((float)tprX, (float)tprY); // 通过上一个位置直接进行局部特征匹配
}
private async Task MoveTo(Waypoint waypoint)
@ -90,7 +109,7 @@ public class PathExecutor(CancellationTokenSource cts)
var screen = CaptureToRectArea();
var position = Navigation.GetPosition(screen);
var targetOrientation = Navigation.GetTargetOrientation(waypoint, position);
Logger.LogInformation("粗略接近途经点,位置({x2},{y2})", waypoint.X, waypoint.Y);
Logger.LogInformation("粗略接近途经点,位置({x2},{y2})", $"{waypoint.X:F1}", $"{waypoint.Y:F1}");
await WaitUntilRotatedTo(targetOrientation, 5);
var startTime = DateTime.UtcNow;
var lastPositionRecord = DateTime.UtcNow;
@ -195,7 +214,7 @@ public class PathExecutor(CancellationTokenSource cts)
var screen = CaptureToRectArea();
var position = Navigation.GetPosition(screen);
var targetOrientation = Navigation.GetTargetOrientation(waypoint, position);
Logger.LogInformation("精确接近目标点,位置({x2},{y2})", waypoint.X, waypoint.Y);
Logger.LogInformation("精确接近目标点,位置({x2},{y2})", $"{waypoint.X:F1}", $"{waypoint.Y:F1}");
if (waypoint.MoveMode == MoveModeEnum.Fly.Code && waypoint.Action == ActionEnum.StopFlying.Code)
{
//下落攻击接近目的地
@ -239,8 +258,6 @@ public class PathExecutor(CancellationTokenSource cts)
{
Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W);
}
// 不管咋样抬起w键
Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W);
}
private int RotateTo(int targetOrientation, ImageRegion imageRegion, double controlRatio = 1)

View File

@ -37,7 +37,7 @@ public class TpTask(CancellationTokenSource cts)
{
// 获取最近的传送点位置
var (x, y) = GetRecentlyTpPoint(tpX, tpY);
Logger.LogInformation("({TpX},{TpY}) 最近的传送点位置 ({X},{Y})", tpX, tpY, x, y);
Logger.LogInformation("({TpX},{TpY}) 最近的传送点位置 ({X},{Y})", $"{tpX:F1}", $"{tpY:F1}", $"{x:F1}", $"{y:F1}");
// M 打开地图识别当前位置,中心点为当前位置
using var ra1 = CaptureToRectArea();

View File

@ -94,7 +94,7 @@ public class TaskRunner
Task.Run(() => RunAsync(action));
}
public async Task FireAndForgetAsync(Func<Task> action)
public async Task RunThreadAsync(Func<Task> action)
{
await Task.Run(() => RunAsync(action));
}

View File

@ -8,6 +8,9 @@ namespace BetterGenshinImpact.Helpers;
public class DpiHelper
{
/// <summary>
/// 只能主线程调用
/// </summary>
public static float ScaleY => GetScaleY();
private static float GetScaleY()

View File

@ -44,7 +44,7 @@ public partial class ScriptService(HomePageViewModel homePageViewModel) : IScrip
// 循环执行所有脚本
var timerOperation = hasTimer ? DispatcherTimerOperationEnum.UseCacheImageWithTriggerEmpty : DispatcherTimerOperationEnum.UseSelfCaptureImage;
await new TaskRunner(timerOperation)
.RunAsync(async () =>
.RunThreadAsync(async () =>
{
foreach (var project in projects)
{
@ -145,7 +145,7 @@ public partial class ScriptService(HomePageViewModel homePageViewModel) : IScrip
var timerOperation = hasTimer ? DispatcherTimerOperationEnum.UseCacheImageWithTriggerEmpty : DispatcherTimerOperationEnum.UseSelfCaptureImage;
await new TaskRunner(timerOperation)
.FireAndForgetAsync(async () =>
.RunThreadAsync(async () =>
{
foreach (var project in list)
{

View File

@ -2,6 +2,7 @@
"石之轮",
"幻想真境剧诗",
"开始演奏",
"摆放巧像",
"摹刻巧像",
"摹刻码像",
"募刻巧像",

View File

@ -28,6 +28,8 @@ public partial class MapPathingViewModel : ObservableObject, INavigationAware, I
[ObservableProperty]
private ObservableCollection<PathingTask> _pathItems = [];
private MapViewer? _mapViewer;
private void InitScriptListViewData()
{
_pathItems.Clear();
@ -106,6 +108,7 @@ public partial class MapPathingViewModel : ObservableObject, INavigationAware, I
[RelayCommand]
public void OnOpenMapViewer()
{
new MapViewer().Show();
_mapViewer ??= new MapViewer();
_mapViewer.Show();
}
}