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); } /**