From 040cb5080bfa5d5fda037917ad934bda2ee2dff9 Mon Sep 17 00:00:00 2001 From: mfkvfhpdx Date: Sun, 11 May 2025 01:25:08 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=9A=E8=BF=87=E7=82=B9=E4=BD=8D=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=EF=BC=8C=E6=94=AF=E6=8C=81=E5=9C=A8=E6=9C=AA=E8=AF=86?= =?UTF-8?q?=E5=88=AB=E7=82=B9=E4=BD=8D=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C?= =?UTF-8?q?=E4=BB=8E=E5=A4=A7=E5=9C=B0=E5=9B=BE=E4=B8=AD=E5=BF=83=E7=82=B9?= =?UTF-8?q?=E6=9D=A5=E8=AF=86=E5=88=AB=E5=9D=90=E6=A0=87=E3=80=82=20(#1526?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修改调度器任务和部分独立任务失去焦点时,强制切换回游戏窗口,如果用常规的方式无法激活窗口,则第10次会尝试最小化所有窗口后激活游戏。 * 去除未引入的类引用 * 修正战斗结束后,大概率打开队伍界面的问题 * 修复有些电脑上因未知原因,战斗0秒打断 * 把失焦激活放入了设置-通用设置-其他设置中,默认关闭。暂停恢复时,重置移动的起始时间,防止因暂停而导致超时放弃任务。 * 在调度器里面的任务之前,增加月卡处理,解决4点如果未进入任务会卡住的问题。增加了日志分析小怪详细。解决日志分析兜底结束日期不生效的问题。 * 在设置=》其他设置中 增加调度器任务传送过程中自动领取探索奖励功能配置。 * 调整自动派遣后恢复原任务的逻辑 * 自动领取派遣奖励时,跳过异常,防止整个配置组任务被打断。 * 把打开大地图方法从TpTask中抽出为公共方法,自动领取派遣代码调整到了调度器中。 * 去除了未使用的引用 * 暂停恢复逻辑增加恢复中条件和非空判断 * 增加了临时暂停自动拾取的逻辑(RunnerContext.AutoPickTriggerStopCount 为0时不限制,大于0时停止,多次暂停会累加该值,每次恢复-1),支持嵌套情况的暂停,在自动派遣(和结束后5秒)或暂停调度器任务时,同时暂停自动拾取功能。 * 调整暂停拾取方法 * 调整个日志输出 * 路径追踪复苏时,暂停拾取 * 增加根据点位配置,支持能在点位未识别情况下,使用大地图中心点的方式来定位,从而支持像铜锁小岛处这种小地图无法识别的点位。调整了对未识别点位的默认逻辑,未配置点位配置情况下,未识别点位,会取上一个识别的点位,从而支持在某些地方断续小地图能识别情况下的脚本。 --- .../GameTask/AutoPathing/Model/Waypoint.cs | 30 ++++ .../AutoPathing/Model/WaypointForTrack.cs | 2 + .../GameTask/AutoPathing/PathExecutor.cs | 153 ++++++++++++++++-- 3 files changed, 173 insertions(+), 12 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Model/Waypoint.cs b/BetterGenshinImpact/GameTask/AutoPathing/Model/Waypoint.cs index 786b3402..4cc8285c 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Model/Waypoint.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Model/Waypoint.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Text.Json.Serialization; using BetterGenshinImpact.GameTask.AutoPathing.Model.Enum; namespace BetterGenshinImpact.GameTask.AutoPathing.Model; @@ -6,8 +9,35 @@ namespace BetterGenshinImpact.GameTask.AutoPathing.Model; [Serializable] public class Waypoint { + + + + + //异常识别处理 + public class Misidentification + { + + //何时处理 pathTooFar 路径过远 Unrecognized 未识别 + public List Type { get; set; }= ["unrecognized"]; + //处理方式 previousDetectedPoint 取上一个识别到的点位置 , mapRecognition 大地图识别 , ScheduledArrival 特定时间到达 + public string HandlingMode { get; set; } = "previousDetectedPoint"; + //自行预估的时间 + public int ArrivalTime { get; set; } = 0; + } + public class ExtParams + { + public Misidentification Misidentification { get; set; } = new(); + public string Description { get; set; } = ""; + //normal 小怪,elite 精英,legendary 传奇 + public string MonsterTag { get; set; } + } + + + public double X { get; set; } public double Y { get; set; } + + public ExtParams PointExtParams { get; set; }=new ExtParams(); /// /// diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Model/WaypointForTrack.cs b/BetterGenshinImpact/GameTask/AutoPathing/Model/WaypointForTrack.cs index 737accaa..5a76a6e2 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Model/WaypointForTrack.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Model/WaypointForTrack.cs @@ -20,6 +20,8 @@ public class WaypointForTrack : Waypoint public double MatY { get; set; } public string MapName { get; set; } + //异常识别 + public Misidentification Misidentification { get; set; } = new(); /// /// 存在 combat_script 的 action 的话,这个值会存在 diff --git a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs index 8dc37bd9..a7d83962 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs @@ -492,7 +492,12 @@ public class PathExecutor private List> ConvertWaypointsForTrack(List positions, PathingTask task) { // 把 X Y 转换为 MatX MatY - var allList = positions.Select(waypoint => new WaypointForTrack(waypoint, task.Info.MapName)).ToList(); + var allList = positions.Select(waypoint => + { + WaypointForTrack wft=new WaypointForTrack(waypoint, task.Info.MapName); + wft.Misidentification=waypoint.PointExtParams.Misidentification; + return wft; + }).ToList(); // 按照WaypointType.Teleport.Code切割数组 var result = new List>(); @@ -676,7 +681,7 @@ public class PathExecutor public async Task FaceTo(WaypointForTrack waypoint) { var screen = CaptureToRectArea(); - var position = await GetPosition(screen, waypoint.MapName); + var position = await GetPosition(screen, waypoint); var targetOrientation = Navigation.GetTargetOrientation(waypoint, position); Logger.LogInformation("朝向点,位置({x2},{y2})", $"{waypoint.GameX:F1}", $"{waypoint.GameY:F1}"); await _rotateTask.WaitUntilRotatedTo(targetOrientation, 2); @@ -691,7 +696,7 @@ public class PathExecutor await SwitchAvatar(PartyConfig.MainAvatarIndex); var screen = CaptureToRectArea(); - var position = await GetPosition(screen, waypoint.MapName); + var (position, additionalTimeInMs) = await GetPositionAndTime(screen, waypoint); var targetOrientation = Navigation.GetTargetOrientation(waypoint, position); Logger.LogInformation("粗略接近途经点,位置({x2},{y2})", $"{waypoint.GameX:F1}", $"{waypoint.GameY:F1}"); await _rotateTask.WaitUntilRotatedTo(targetOrientation, 5); @@ -722,7 +727,17 @@ public class PathExecutor EndJudgment(screen); - position = await GetPosition(screen, waypoint.MapName); + // position = await GetPosition(screen, waypoint); + (position, additionalTimeInMs) = await GetPositionAndTime(screen, waypoint); + if (additionalTimeInMs>0) + { + if (!Simulation.IsKeyDown(GIActions.MoveForward.ToActionKey().ToVK())) + { + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); + } + + additionalTimeInMs = additionalTimeInMs + 1000;//当做起步补偿 + } var distance = Navigation.GetDistance(waypoint, position); Debug.WriteLine($"接近目标点中,距离为{distance}"); if (distance < 4) @@ -739,7 +754,7 @@ public class PathExecutor } else { - Logger.LogWarning("距离过远,跳过路径点"); + Logger.LogWarning($"距离过远({position.X},{position.Y})->({waypoint.X},{waypoint.Y})={distance},跳过路径点"); } @@ -749,7 +764,7 @@ public class PathExecutor // 非攀爬状态下,检测是否卡死(脱困触发器) if (waypoint.MoveMode != MoveModeEnum.Climb.Code) { - if ((DateTime.UtcNow - lastPositionRecord).TotalMilliseconds > 1000) + if ((DateTime.UtcNow - lastPositionRecord).TotalMilliseconds > 1000 + additionalTimeInMs) { lastPositionRecord = DateTime.UtcNow; prevPositions.Add(position); @@ -943,7 +958,7 @@ public class PathExecutor EndJudgment(screen); - position = await GetPosition(screen, waypoint.MapName); + position = await GetPosition(screen, waypoint); if (Navigation.GetDistance(waypoint, position) < 2) { Logger.LogInformation("已到达路径点"); @@ -980,7 +995,7 @@ public class PathExecutor { Simulation.SendInput.Mouse.MiddleButtonClick(); var screen = CaptureToRectArea(); - var position = await GetPosition(screen, waypoint.MapName); + var position = await GetPosition(screen, waypoint); var targetOrientation = Navigation.GetTargetOrientation(waypoint, position); await _rotateTask.WaitUntilRotatedTo(targetOrientation, 10); var handler = ActionFactory.GetBeforeHandler(waypoint.Action); @@ -1039,11 +1054,74 @@ public class PathExecutor Logger.LogInformation("尝试切换角色{Name}失败!", avatar.Name); return null; } - - private async Task GetPosition(ImageRegion imageRegion, string mapName) + + /// + /// 根据时间在两个点之间插值。 + /// + /// 起点坐标 + /// 终点坐标 + /// 起始时间 + /// 中间时间 + /// 结束时间 + /// 中间点坐标 + public static Point2f InterpolatePointByTime( + Point2f startPoint, + Point2f endPoint, + DateTime startTime, + DateTime midTime, + DateTime endTime) { - var position = Navigation.GetPosition(imageRegion, mapName); + // 计算时间差 + double totalMillis = (endTime - startTime).TotalMilliseconds; + double midMillis = (midTime - startTime).TotalMilliseconds; + // 防止除以0 + if (totalMillis == 0) + return startPoint; + + // 计算比例 + float t = (float)(midMillis / totalMillis); + if (t>1.0f) + { + t = 1.0f; + } + // 插值计算 + float x = startPoint.X + (endPoint.X - startPoint.X) * t; + float y = startPoint.Y + (endPoint.Y - startPoint.Y) * t; + + return new Point2f(x, y); + } + + private Point2f prePosition; + private DateTime preTime; + //自动构造点位的最大时间 + private int maxAutoPositionTime=10000; + private async Task WaitForCloseMap(int maxAttempts, int delayMs) + { + await Delay(delayMs, ct); + for (var i = 0; i < maxAttempts; i++) + { + using var capture = CaptureToRectArea(); + if (Bv.IsInMainUi(capture)) + { + return; + } + + await Delay(delayMs, ct); + } + + } + + private async Task GetPosition(ImageRegion imageRegion, WaypointForTrack waypoint) + { + return (await GetPositionAndTime(imageRegion, waypoint)).point; + } + + private async Task<(Point2f point,int additionalTimeInMs)> GetPositionAndTime(ImageRegion imageRegion, WaypointForTrack waypoint) + { + + var position = Navigation.GetPosition(imageRegion, waypoint.MapName); + int time = 0; if (position == new Point2f()) { if (!Bv.IsInMainUi(imageRegion)) @@ -1053,7 +1131,58 @@ public class PathExecutor } } - return position; + var distance = Navigation.GetDistance(waypoint, position); + //何时处理 pathTooFar 路径过远 unrecognized 未识别 + if ((position is {X:0,Y:0} && waypoint.Misidentification.Type.Contains("unrecognized")) || (distance>500 && waypoint.Misidentification.Type.Contains("pathTooFar"))) + { + if (waypoint.Misidentification.HandlingMode == "previousDetectedPoint") + { + if (prePosition != default) + { + position = prePosition; + Logger.LogInformation(@$"未识别到具体路径,取上次点位"); + } + }else if (waypoint.Misidentification.HandlingMode == "mapRecognition"){ + //大地图识别坐标 + DateTime start = DateTime.Now; + TpTask tpTask = new TpTask(ct); + await tpTask.OpenBigMapUi(); + try + { + position =MapManager.GetMap(waypoint.MapName).ConvertGenshinMapCoordinatesToImageCoordinates(tpTask.GetPositionFromBigMap(waypoint.MapName)); + } + catch (Exception e) + { + Logger.LogInformation(@$"地图中心点识别失败!"); + } + + Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_ESCAPE); + //Bv.IsInMainUi(imageRegion); + await WaitForCloseMap(10,200); + DateTime end = DateTime.Now; + time=(int)(end - start).TotalMilliseconds; + Logger.LogInformation(@$"未识别到具体路径,打开地图计算中心点({position.X},{position.Y})"); + } + + /*if (prePosition!=default) + {*/ + //position = InterpolatePointByTime(prePosition,new Point2f((float)waypoint.GameX,(float)waypoint.GameY),preTime,DateTime.Now,preTime.AddMilliseconds(maxAutoPositionTime)); + //Logger.LogInformation(@$"未识别到具体路径,预测其路径为({position.X},{position.Y}),开始结束点位为:({prePosition.X},{prePosition.Y})({waypoint.GameX},{waypoint.GameY})"); + //Point2f GetBigMapCenterPoint(string mapName) + + // Logger.LogInformation(@$"未识别到具体路径,打开地图计算中心点({position.X},{position.Y})"); + //position =prePosition; + // } + + } + else + { + prePosition = position; + preTime = DateTime.Now; + } + + //Logger.LogInformation("识别到路径:"+position.X+","+position.Y); + return (position,time); } /**