mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-05-09 00:34:14 +08:00
通过点位配置,支持在未识别点位情况下,从大地图中心点来识别坐标。 (#1526)
* 修改调度器任务和部分独立任务失去焦点时,强制切换回游戏窗口,如果用常规的方式无法激活窗口,则第10次会尝试最小化所有窗口后激活游戏。 * 去除未引入的类引用 * 修正战斗结束后,大概率打开队伍界面的问题 * 修复有些电脑上因未知原因,战斗0秒打断 * 把失焦激活放入了设置-通用设置-其他设置中,默认关闭。暂停恢复时,重置移动的起始时间,防止因暂停而导致超时放弃任务。 * 在调度器里面的任务之前,增加月卡处理,解决4点如果未进入任务会卡住的问题。增加了日志分析小怪详细。解决日志分析兜底结束日期不生效的问题。 * 在设置=》其他设置中 增加调度器任务传送过程中自动领取探索奖励功能配置。 * 调整自动派遣后恢复原任务的逻辑 * 自动领取派遣奖励时,跳过异常,防止整个配置组任务被打断。 * 把打开大地图方法从TpTask中抽出为公共方法,自动领取派遣代码调整到了调度器中。 * 去除了未使用的引用 * 暂停恢复逻辑增加恢复中条件和非空判断 * 增加了临时暂停自动拾取的逻辑(RunnerContext.AutoPickTriggerStopCount 为0时不限制,大于0时停止,多次暂停会累加该值,每次恢复-1),支持嵌套情况的暂停,在自动派遣(和结束后5秒)或暂停调度器任务时,同时暂停自动拾取功能。 * 调整暂停拾取方法 * 调整个日志输出 * 路径追踪复苏时,暂停拾取 * 增加根据点位配置,支持能在点位未识别情况下,使用大地图中心点的方式来定位,从而支持像铜锁小岛处这种小地图无法识别的点位。调整了对未识别点位的默认逻辑,未配置点位配置情况下,未识别点位,会取上一个识别的点位,从而支持在某些地方断续小地图能识别情况下的脚本。
This commit is contained in:
@@ -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<string> 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();
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="WaypointType"/>
|
||||
|
||||
@@ -20,6 +20,8 @@ public class WaypointForTrack : Waypoint
|
||||
public double MatY { get; set; }
|
||||
|
||||
public string MapName { get; set; }
|
||||
//异常识别
|
||||
public Misidentification Misidentification { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 存在 combat_script 的 action 的话,这个值会存在
|
||||
|
||||
@@ -492,7 +492,12 @@ public class PathExecutor
|
||||
private List<List<WaypointForTrack>> ConvertWaypointsForTrack(List<Waypoint> 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<List<WaypointForTrack>>();
|
||||
@@ -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<Point2f> GetPosition(ImageRegion imageRegion, string mapName)
|
||||
|
||||
/// <summary>
|
||||
/// 根据时间在两个点之间插值。
|
||||
/// </summary>
|
||||
/// <param name="startPoint">起点坐标</param>
|
||||
/// <param name="endPoint">终点坐标</param>
|
||||
/// <param name="startTime">起始时间</param>
|
||||
/// <param name="midTime">中间时间</param>
|
||||
/// <param name="endTime">结束时间</param>
|
||||
/// <returns>中间点坐标</returns>
|
||||
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<Point2f> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user