diff --git a/BetterGenshinImpact/Core/Config/AllConfig.cs b/BetterGenshinImpact/Core/Config/AllConfig.cs index 76f60fab..cf813bb2 100644 --- a/BetterGenshinImpact/Core/Config/AllConfig.cs +++ b/BetterGenshinImpact/Core/Config/AllConfig.cs @@ -68,11 +68,6 @@ public partial class AllConfig : ObservableObject /// [ObservableProperty] private string _inferenceDevice = "CPU"; - /// - /// 暂停 - /// - [ObservableProperty] - private bool _suspend = false; [ObservableProperty] private List> _NextScheduledTask = []; diff --git a/BetterGenshinImpact/GameTask/AutoFishing/AutoFishingTrigger.cs b/BetterGenshinImpact/GameTask/AutoFishing/AutoFishingTrigger.cs index 7e023a1b..f982155e 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/AutoFishingTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/AutoFishingTrigger.cs @@ -728,7 +728,7 @@ namespace BetterGenshinImpact.GameTask.AutoFishing { NewRetry.Do(() => { - SystemControl.TrySuspend(); + TaskControl.TrySuspend(); if (IsEnabled && !SystemControl.IsGenshinImpactActiveByProcess()) { _logger.LogWarning("当前获取焦点的窗口不是原神,暂停"); diff --git a/BetterGenshinImpact/GameTask/AutoGeniusInvokation/GeniusInvokationControl.cs b/BetterGenshinImpact/GameTask/AutoGeniusInvokation/GeniusInvokationControl.cs index f039aabc..83935cec 100644 --- a/BetterGenshinImpact/GameTask/AutoGeniusInvokation/GeniusInvokationControl.cs +++ b/BetterGenshinImpact/GameTask/AutoGeniusInvokation/GeniusInvokationControl.cs @@ -107,7 +107,7 @@ public class GeniusInvokationControl { return; } - SystemControl.TrySuspend(); + TaskControl.TrySuspend(); if (!SystemControl.IsGenshinImpactActiveByProcess()) { _logger.LogWarning("当前获取焦点的窗口不是原神,暂停"); diff --git a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs index 418327ce..d6bfb6f5 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs @@ -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> curWaypoints; + public (int, List) CurWaypoints { get; set; } + //记录当前点位 - private ValueTuple curWaypoint; + public (int, WaypointForTrack) CurWaypoint { get; set; } //记录恢复点位数组 - private ValueTuple> recordWaypoints; + private (int, List) RecordWaypoints { get; set; } + //记录恢复点位 - private ValueTuple 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> waypoints; - //记录当前点位 - private ValueTuple 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 /// /// 尝试队伍回血,如果单人回血,由于记录检查时是哪位残血,则当作行走位处理。 /// - private async Task TryPartyHealing() { - - - foreach (var avatar in _combatScenes?.Avatars ?? []) + private async Task 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) { diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Suspend/ISuspendable.cs b/BetterGenshinImpact/GameTask/AutoPathing/Suspend/ISuspendable.cs new file mode 100644 index 00000000..9b6ba961 --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoPathing/Suspend/ISuspendable.cs @@ -0,0 +1,8 @@ +namespace BetterGenshinImpact.GameTask.AutoPathing.Suspend; + +public interface ISuspendable +{ + void Suspend(); // 暂停操作 + void Resume(); // 恢复操作 + bool IsSuspended { get; } // 是否处于暂停状态 +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Suspend/PathExecutorSuspend.cs b/BetterGenshinImpact/GameTask/AutoPathing/Suspend/PathExecutorSuspend.cs new file mode 100644 index 00000000..6a2ae719 --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoPathing/Suspend/PathExecutorSuspend.cs @@ -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) _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; + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/Common/TaskControl.cs b/BetterGenshinImpact/GameTask/Common/TaskControl.cs index dbc036e9..5fedb870 100644 --- a/BetterGenshinImpact/GameTask/Common/TaskControl.cs +++ b/BetterGenshinImpact/GameTask/Common/TaskControl.cs @@ -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("当前获取焦点的窗口不是原神,暂停"); diff --git a/BetterGenshinImpact/GameTask/RunnerContext.cs b/BetterGenshinImpact/GameTask/RunnerContext.cs index 2d069941..3b34daf3 100644 --- a/BetterGenshinImpact/GameTask/RunnerContext.cs +++ b/BetterGenshinImpact/GameTask/RunnerContext.cs @@ -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 /// 是否是连续执行配置组的场景 /// public bool IsContinuousRunGroup { get; set; } + + /// + /// 暂停逻辑 + /// + public bool IsSuspend { get; set; } + + /// + /// 暂停实现 + /// + public Dictionary SuspendableDictionary = new(); /// /// 当前使用队伍名称 @@ -68,6 +81,8 @@ public class RunnerContext : Singleton } _combatScenes = null; + IsSuspend = false; + SuspendableDictionary.Clear(); } /// @@ -78,5 +93,7 @@ public class RunnerContext : Singleton IsContinuousRunGroup = false; PartyName = null; _combatScenes = null; + IsSuspend = false; + SuspendableDictionary.Clear(); } } \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/SystemControl.cs b/BetterGenshinImpact/GameTask/SystemControl.cs index ee21a438..125752e3 100644 --- a/BetterGenshinImpact/GameTask/SystemControl.cs +++ b/BetterGenshinImpact/GameTask/SystemControl.cs @@ -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 SuspendableDictionary = new(); - public static void TrySuspend() - { - bool isSuspend= SystemControl.Suspend(); - bool first = true; - while (SystemControl.Suspend()) - { - if (first) { - App.GetLogger().LogWarning("快捷键触发暂停,等待解除"); - foreach (var item in SuspendableDictionary) - { - item.Value.Suspend(); - } - first = false; - } - - Thread.Sleep(1000); - } - if (isSuspend) { - App.GetLogger().LogWarning("暂停已经解除"); - foreach (var item in SuspendableDictionary) - { - item.Value.Resume(); - } - } - } public static async Task 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); // } -} +} \ No newline at end of file diff --git a/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs index aa49d7f3..bfb6dc36 100644 --- a/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs @@ -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( "游戏截图",