1. 抽离部分内部类,格式化代码

2. ValueTuple 已过时,元组建议使用 ()
3. 暂停变量不建议放在 TaskContext.Instance().Config.Suspend 中,会被持久化到配置内
4. 修改一些方法和变量的存放位置
This commit is contained in:
辉鸭蛋 2024-12-21 14:35:42 +08:00
parent 36e49bcbc7
commit e497f6ec79
10 changed files with 183 additions and 225 deletions

View File

@ -68,11 +68,6 @@ public partial class AllConfig : ObservableObject
/// </summary>
[ObservableProperty]
private string _inferenceDevice = "CPU";
/// <summary>
/// 暂停
/// </summary>
[ObservableProperty]
private bool _suspend = false;
[ObservableProperty]
private List<ValueTuple<string,int, string, string>> _NextScheduledTask = [];

View File

@ -728,7 +728,7 @@ namespace BetterGenshinImpact.GameTask.AutoFishing
{
NewRetry.Do(() =>
{
SystemControl.TrySuspend();
TaskControl.TrySuspend();
if (IsEnabled && !SystemControl.IsGenshinImpactActiveByProcess())
{
_logger.LogWarning("当前获取焦点的窗口不是原神,暂停");

View File

@ -107,7 +107,7 @@ public class GeniusInvokationControl
{
return;
}
SystemControl.TrySuspend();
TaskControl.TrySuspend();
if (!SystemControl.IsGenshinImpactActiveByProcess())
{
_logger.LogWarning("当前获取焦点的窗口不是原神,暂停");

View File

@ -24,6 +24,8 @@ using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BetterGenshinImpact.GameTask.AutoPathing.Suspend;
using BetterGenshinImpact.GameTask.Common;
using Vanara.PInvoke;
using static BetterGenshinImpact.GameTask.Common.TaskControl;
using static BetterGenshinImpact.GameTask.SystemControl;
@ -34,19 +36,20 @@ namespace BetterGenshinImpact.GameTask.AutoPathing;
public class PathExecutor
{
private readonly CameraRotateTask _rotateTask;
private readonly TrapEscaper _trapEscaper;
private readonly TrapEscaper _trapEscaper;
private readonly BlessingOfTheWelkinMoonTask _blessingOfTheWelkinMoonTask = new();
private AutoSkipTrigger? _autoSkipTrigger;
private PathingPartyConfig? _partyConfig;
private CancellationToken ct;
private PathExecutorSuspend pathExecutorSuspend;
public PathExecutor(CancellationToken ct) {
_trapEscaper= new(ct);
public PathExecutor(CancellationToken ct)
{
_trapEscaper = new(ct);
_rotateTask = new(ct);
this.ct = ct;
pathExecutorSuspend=new PathExecutorSuspend(this);
pathExecutorSuspend = new PathExecutorSuspend(this);
}
public PathingPartyConfig PartyConfig
@ -70,108 +73,56 @@ public class PathExecutor
private int _inTrap = 0;
//记录当前相关点位数组
private ValueTuple<int, List<WaypointForTrack>> curWaypoints;
public (int, List<WaypointForTrack>) CurWaypoints { get; set; }
//记录当前点位
private ValueTuple<int, WaypointForTrack> curWaypoint;
public (int, WaypointForTrack) CurWaypoint { get; set; }
//记录恢复点位数组
private ValueTuple<int, List<WaypointForTrack>> recordWaypoints;
private (int, List<WaypointForTrack>) RecordWaypoints { get; set; }
//记录恢复点位
private ValueTuple<int, WaypointForTrack> recordWaypoint;
private (int, WaypointForTrack) RecordWaypoint { get; set; }
//跳过除走路径以外的操作
private bool skipOtherOperations=false;
private bool _skipOtherOperations = false;
//暂停逻辑相关实现,这里主要用来记录,用来恢复相应操作
public class PathExecutorSuspend : ISuspendable
//当到达恢复点位
public void TryCloseSkipOtherOperations()
{
private bool _isSuspended;
//记录当前相关点位数组
private ValueTuple<int, List<WaypointForTrack>> waypoints;
//记录当前点位
private ValueTuple<int, WaypointForTrack> waypoint;
private PathExecutor pathExecutor;
public PathExecutorSuspend(PathExecutor pathExecutor)
Logger.LogWarning("判断是否跳过路径追踪:" + (CurWaypoint.Item1 < RecordWaypoint.Item1));
if (RecordWaypoints == CurWaypoints && CurWaypoint.Item1 < RecordWaypoint.Item1)
{
this.pathExecutor = pathExecutor;
return;
}
public bool IsSuspended
if (_skipOtherOperations)
{
get
{
return _isSuspended;
}
}
public void Suspend()
{
waypoints = pathExecutor.curWaypoints;
waypoint = pathExecutor.curWaypoint;
_isSuspended = true;
}
//路径过远时,检查路径追踪点位经过暂停(当前点位和后一个点位算经过暂停),并重置状态
public bool checkAndResetSuspendPoint()
{
if (_isSuspended)
{
return false;
}
if (pathExecutor.curWaypoints == waypoints && (pathExecutor.curWaypoint == waypoint || (pathExecutor.curWaypoint.Item1-1) == waypoint.Item1))
{
return true;
}
reset();
return false;
}
public void Resume()
{
_isSuspended = false;
}
public void reset()
{
waypoints = default;
waypoint = default;
}
}
//当到达恢复点位
public void TryCloseSkipOtherOperations()
{
Logger.LogWarning("判断是否跳过路径追踪:" + (curWaypoint.Item1 < recordWaypoint.Item1));
if (recordWaypoints == curWaypoints && curWaypoint.Item1 < recordWaypoint.Item1)
{
return;
}
if (skipOtherOperations) {
Logger.LogWarning("已到达上次点位,路径追踪功能恢复");
}
skipOtherOperations = false;
_skipOtherOperations = false;
}
//记录点位,方便后面恢复
public void StartSkipOtherOperations() {
public void StartSkipOtherOperations()
{
Logger.LogWarning("记录恢复点位,路径追踪将到达上次点位之前将跳过走路之外的操作");
skipOtherOperations = true;
recordWaypoints = curWaypoints;
recordWaypoint = curWaypoint;
_skipOtherOperations = true;
RecordWaypoints = CurWaypoints;
RecordWaypoint = CurWaypoint;
}
public async Task Pathing(PathingTask task)
{
// SuspendableDictionary;
var sdkey = "PathExecutor";
var sd= SystemControl.SuspendableDictionary;
if (sd.ContainsKey(sdkey)) {
sd.Remove(sdkey);
}
SystemControl.SuspendableDictionary.TryAdd(sdkey, pathExecutorSuspend);
const string sdKey = "PathExecutor";
var sd = RunnerContext.Instance.SuspendableDictionary;
sd.Remove(sdKey);
RunnerContext.Instance.SuspendableDictionary.TryAdd(sdKey, pathExecutorSuspend);
if (!task.Positions.Any())
{
@ -202,8 +153,8 @@ public class PathExecutor
foreach (var waypoints in waypointsList)
{
curWaypoints = (waypointsList.FindIndex(wps=>wps==waypoints), waypoints);
CurWaypoints = (waypointsList.FindIndex(wps => wps == waypoints), waypoints);
for (var i = 0; i < RetryTimes; i++)
{
@ -212,8 +163,7 @@ public class PathExecutor
await ResolveAnomalies(); // 异常场景处理
foreach (var waypoint in waypoints)
{
curWaypoint = (waypoints.FindIndex(wps => wps == waypoint), waypoint);
CurWaypoint = (waypoints.FindIndex(wps => wps == waypoint), waypoint);
TryCloseSkipOtherOperations();
await RecoverWhenLowHp(waypoint); // 低血量恢复
if (waypoint.Type == WaypointType.Teleport.Code)
@ -237,8 +187,9 @@ public class PathExecutor
{
await MoveCloseTo(waypoint);
}
//skipOtherOperations如果重试则跳过相关操作
if (!string.IsNullOrEmpty(waypoint.Action) && !skipOtherOperations)
if (!string.IsNullOrEmpty(waypoint.Action) && !_skipOtherOperations)
{
// 执行 action
await AfterMoveToTarget(waypoint);
@ -265,7 +216,7 @@ public class PathExecutor
StartSkipOtherOperations();
Logger.LogWarning(retryException.Message);
}
finally
{
// 不管咋样,松开所有按键
@ -289,7 +240,7 @@ public class PathExecutor
// 血量肯定不满,直接去七天神像回血
await TpStatueOfTheSeven();
}
var pRaList = ra.FindMulti(AutoFightAssets.Instance.PRa); // 判断是否联机
if (pRaList.Count > 0)
{
@ -494,12 +445,11 @@ public class PathExecutor
/// <summary>
/// 尝试队伍回血,如果单人回血,由于记录检查时是哪位残血,则当作行走位处理。
/// </summary>
private async Task<bool> TryPartyHealing() {
foreach (var avatar in _combatScenes?.Avatars ?? [])
private async Task<bool> TryPartyHealing()
{
foreach (var avatar in _combatScenes?.Avatars ?? [])
{
if (avatar.Name == "白术" )
if (avatar.Name == "白术")
{
if (avatar.TrySwitch())
{
@ -512,10 +462,11 @@ public class PathExecutor
await Delay(4000, ct);
return true;
}
break;
}
else if (avatar.Name == "希格雯") {
else if (avatar.Name == "希格雯")
{
if (avatar.TrySwitch())
{
Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_E);
@ -523,9 +474,10 @@ public class PathExecutor
await SwitchAvatar(PartyConfig.MainAvatarIndex);
return true;
}
break;
}else if (avatar.Name == "珊瑚宫心海")
}
else if (avatar.Name == "珊瑚宫心海")
{
if (avatar.TrySwitch())
{
@ -538,13 +490,13 @@ public class PathExecutor
await Delay(5000, ct);
return true;
}
}
}
return false;
}
private async Task RecoverWhenLowHp(WaypointForTrack waypoint)
{
if (PartyConfig.OnlyInTeleportRecover && waypoint.Type != WaypointType.Teleport.Code)
@ -555,9 +507,9 @@ public class PathExecutor
using var region = CaptureToRectArea();
if (Bv.CurrentAvatarIsLowHp(region) && !(await TryPartyHealing() && Bv.CurrentAvatarIsLowHp(region)))
{
Logger.LogInformation("当前角色血量过低,去须弥七天神像恢复");
await TpStatueOfTheSeven();
throw new RetryException("回血完成后重试路线");
Logger.LogInformation("当前角色血量过低,去须弥七天神像恢复");
await TpStatueOfTheSeven();
throw new RetryException("回血完成后重试路线");
}
else if (Bv.ClickIfInReviveModal(region))
{
@ -632,17 +584,16 @@ public class PathExecutor
if (distance > 500)
{
if (pathExecutorSuspend.checkAndResetSuspendPoint())
if (pathExecutorSuspend.CheckAndResetSuspendPoint())
{
throw new RetryNoCountException("可能暂停导致路径过远,重试一次此路线!");
}
else {
else
{
Logger.LogWarning("距离过远,跳过路径点");
}
break;
}
@ -745,7 +696,7 @@ public class PathExecutor
_elementalSkillLastUseTime = DateTime.UtcNow;
}
}
// 自动疾跑
if (distance > 20)
{

View File

@ -0,0 +1,8 @@
namespace BetterGenshinImpact.GameTask.AutoPathing.Suspend;
public interface ISuspendable
{
void Suspend(); // 暂停操作
void Resume(); // 恢复操作
bool IsSuspended { get; } // 是否处于暂停状态
}

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using BetterGenshinImpact.GameTask.AutoPathing.Model;
namespace BetterGenshinImpact.GameTask.AutoPathing.Suspend;
//暂停逻辑相关实现,这里主要用来记录,用来恢复相应操作
public class PathExecutorSuspend(PathExecutor pathExecutor) : ISuspendable
{
private bool _isSuspended;
//记录当前相关点位数组
private (int, List<WaypointForTrack>) _waypoints;
//记录当前点位
private (int, WaypointForTrack) _waypoint;
public bool IsSuspended => _isSuspended;
public void Suspend()
{
_waypoints = pathExecutor.CurWaypoints;
_waypoint = pathExecutor.CurWaypoint;
_isSuspended = true;
}
//路径过远时,检查路径追踪点位经过暂停(当前点位和后一个点位算经过暂停),并重置状态
public bool CheckAndResetSuspendPoint()
{
if (_isSuspended)
{
return false;
}
if (pathExecutor.CurWaypoints == _waypoints && (pathExecutor.CurWaypoint == _waypoint || (pathExecutor.CurWaypoint.Item1 - 1) == _waypoint.Item1))
{
return true;
}
Reset();
return false;
}
public void Resume()
{
_isSuspended = false;
}
public void Reset()
{
_waypoints = default;
_waypoint = default;
}
}

View File

@ -3,9 +3,11 @@ using BetterGenshinImpact.GameTask.Model.Area;
using Fischless.GameCapture;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
using BetterGenshinImpact.GameTask.AutoPathing.Suspend;
namespace BetterGenshinImpact.GameTask.Common;
@ -15,9 +17,12 @@ public class TaskControl
public static readonly SemaphoreSlim TaskSemaphore = new(1, 1);
public static void CheckAndSleep(int millisecondsTimeout)
{
SystemControl.TrySuspend();
TrySuspend();
if (!SystemControl.IsGenshinImpactActiveByProcess())
{
Logger.LogInformation("当前获取焦点的窗口不是原神,停止执行");
@ -31,7 +36,7 @@ public class TaskControl
{
NewRetry.Do(() =>
{
SystemControl.TrySuspend();
TrySuspend();
if (!SystemControl.IsGenshinImpactActiveByProcess())
{
Logger.LogInformation("当前获取焦点的窗口不是原神,暂停");
@ -41,70 +46,35 @@ public class TaskControl
}, TimeSpan.FromSeconds(1), 100);
Thread.Sleep(millisecondsTimeout);
}
public static void TrySuspend()
{
bool first = true;
while (RunnerContext.Instance.IsSuspend)
{
if (first)
{
Logger.LogWarning("快捷键触发暂停,等待解除");
foreach (var item in RunnerContext.Instance.SuspendableDictionary)
{
item.Value.Suspend();
}
// public static void Sleep(int millisecondsTimeout, CancellationTokenSource? cts)
// {
// if (cts is { IsCancellationRequested: true })
// {
// throw new NormalEndException("取消自动任务");
// }
//
// if (millisecondsTimeout <= 0)
// {
// return;
// }
//
// NewRetry.Do(() =>
// {
// if (cts is { IsCancellationRequested: true })
// {
// throw new NormalEndException("取消自动任务");
// }
//
// if (!SystemControl.IsGenshinImpactActiveByProcess())
// {
// Logger.LogInformation("当前获取焦点的窗口不是原神,暂停");
// throw new RetryException("当前获取焦点的窗口不是原神");
// }
// }, TimeSpan.FromSeconds(1), 100);
// Thread.Sleep(millisecondsTimeout);
// if (cts is { IsCancellationRequested: true })
// {
// throw new NormalEndException("取消自动任务");
// }
// }
first = false;
}
// public static async Task Delay(int millisecondsTimeout, CancellationTokenSource cts)
// {
// if (cts is { IsCancellationRequested: true })
// {
// throw new NormalEndException("取消自动任务");
// }
//
// if (millisecondsTimeout <= 0)
// {
// return;
// }
//
// NewRetry.Do(() =>
// {
// if (cts is { IsCancellationRequested: true })
// {
// throw new NormalEndException("取消自动任务");
// }
//
// if (!SystemControl.IsGenshinImpactActiveByProcess())
// {
// Logger.LogInformation("当前获取焦点的窗口不是原神,暂停");
// throw new RetryException("当前获取焦点的窗口不是原神");
// }
// }, TimeSpan.FromSeconds(1), 100);
// await Task.Delay(millisecondsTimeout, cts.Token);
// if (cts is { IsCancellationRequested: true })
// {
// throw new NormalEndException("取消自动任务");
// }
// }
Thread.Sleep(1000);
}
if (RunnerContext.Instance.IsSuspend)
{
Logger.LogWarning("暂停已经解除");
foreach (var item in RunnerContext.Instance.SuspendableDictionary)
{
item.Value.Resume();
}
}
}
public static void Sleep(int millisecondsTimeout, CancellationToken ct)
{
@ -124,7 +94,7 @@ public class TaskControl
{
throw new NormalEndException("取消自动任务");
}
SystemControl.TrySuspend();
TrySuspend();
if (!SystemControl.IsGenshinImpactActiveByProcess())
{
Logger.LogInformation("当前获取焦点的窗口不是原神,暂停");
@ -157,7 +127,7 @@ public class TaskControl
{
throw new NormalEndException("取消自动任务");
}
SystemControl.TrySuspend();
TrySuspend();
if (!SystemControl.IsGenshinImpactActiveByProcess())
{
Logger.LogInformation("当前获取焦点的窗口不是原神,暂停");

View File

@ -1,9 +1,12 @@
using BetterGenshinImpact.GameTask.AutoFight.Model;
using System.Collections.Generic;
using BetterGenshinImpact.GameTask.AutoFight.Model;
using BetterGenshinImpact.Model;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;
using BetterGenshinImpact.GameTask.AutoPathing.Suspend;
using BetterGenshinImpact.GameTask.Common.Job;
using OpenCvSharp;
using Wpf.Ui.Controls;
using static BetterGenshinImpact.GameTask.Common.TaskControl;
@ -18,6 +21,16 @@ public class RunnerContext : Singleton<RunnerContext>
/// 是否是连续执行配置组的场景
/// </summary>
public bool IsContinuousRunGroup { get; set; }
/// <summary>
/// 暂停逻辑
/// </summary>
public bool IsSuspend { get; set; }
/// <summary>
/// 暂停实现
/// </summary>
public Dictionary<string, ISuspendable> SuspendableDictionary = new();
/// <summary>
/// 当前使用队伍名称
@ -68,6 +81,8 @@ public class RunnerContext : Singleton<RunnerContext>
}
_combatScenes = null;
IsSuspend = false;
SuspendableDictionary.Clear();
}
/// <summary>
@ -78,5 +93,7 @@ public class RunnerContext : Singleton<RunnerContext>
IsContinuousRunGroup = false;
PartyName = null;
_combatScenes = null;
IsSuspend = false;
SuspendableDictionary.Clear();
}
}

View File

@ -5,6 +5,7 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using BetterGenshinImpact.GameTask.AutoFishing;
using BetterGenshinImpact.GameTask.AutoPathing.Suspend;
using Microsoft.Extensions.Logging;
using Vanara.PInvoke;
@ -12,50 +13,11 @@ namespace BetterGenshinImpact.GameTask;
public class SystemControl
{
public static nint FindGenshinImpactHandle()
{
return FindHandleByProcessName("YuanShen", "GenshinImpact", "Genshin Impact Cloud Game");
}
//实现暂停逻辑
public interface ISuspendable
{
void Suspend(); // 暂停操作
void Resume(); // 恢复操作
bool IsSuspended { get; } // 是否处于暂停状态
}
public static bool Suspend()
{
return TaskContext.Instance().Config.Suspend;
}
public static Dictionary<String, ISuspendable> SuspendableDictionary = new();
public static void TrySuspend()
{
bool isSuspend= SystemControl.Suspend();
bool first = true;
while (SystemControl.Suspend())
{
if (first) {
App.GetLogger<SystemControl>().LogWarning("快捷键触发暂停,等待解除");
foreach (var item in SuspendableDictionary)
{
item.Value.Suspend();
}
first = false;
}
Thread.Sleep(1000);
}
if (isSuspend) {
App.GetLogger<SystemControl>().LogWarning("暂停已经解除");
foreach (var item in SuspendableDictionary)
{
item.Value.Resume();
}
}
}
public static async Task<nint> StartFromLocalAsync(string path)
{
// 直接exe启动
@ -79,6 +41,7 @@ public class SystemControl
await Task.Delay(5577);
}
return FindGenshinImpactHandle();
}
@ -295,4 +258,4 @@ public class SystemControl
// // TODO点完之后有个15s的倒计时好像不处理也没什么问题直接睡个20s吧
// Thread.Sleep(20000);
// }
}
}

View File

@ -215,7 +215,7 @@ public partial class HotKeyPageViewModel : ObservableObject, IViewModel
nameof(Config.HotKeyConfig.SuspendHotkey),
Config.HotKeyConfig.SuspendHotkey,
Config.HotKeyConfig.SuspendHotkeyType,
(_, _) => { TaskContext.Instance().Config.Suspend = !TaskContext.Instance().Config.Suspend; }
(_, _) => { RunnerContext.Instance.IsSuspend = !RunnerContext.Instance.IsSuspend; }
));
var takeScreenshotHotKeySettingModel = new HotKeySettingModel(
"游戏截图",