using System; using System.Drawing; using System.Threading; using System.Threading.Tasks; using BetterGenshinImpact.Core.Simulator; using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Exception; using BetterGenshinImpact.GameTask.Model.Area; using Fischless.GameCapture; using Microsoft.Extensions.Logging; using OpenCvSharp; using Vanara.PInvoke; namespace BetterGenshinImpact.GameTask.Common; public class TaskControl { public static ILogger Logger { get; } = App.GetLogger(); public static readonly SemaphoreSlim TaskSemaphore = new(1, 1); public static void CheckAndSleep(int millisecondsTimeout) { TrySuspend(); CheckAndActivateGameWindow(); Thread.Sleep(millisecondsTimeout); } public static void Sleep(int millisecondsTimeout) { NewRetry.Do(() => { TrySuspend(); CheckAndActivateGameWindow(); }, TimeSpan.FromSeconds(1), 100); Thread.Sleep(millisecondsTimeout); } private static bool IsKeyPressed(User32.VK key) { // 获取按键状态 var state = User32.GetAsyncKeyState((int)key); // 检查高位是否为 1(表示按键被按下) return (state & 0x8000) != 0; } public static void TrySuspend() { var first = true; //此处为了记录最开始的暂停状态 var isSuspend = RunnerContext.Instance.IsSuspend; while (RunnerContext.Instance.IsSuspend) { if (first) { RunnerContext.Instance.StopAutoPick(); //使快捷键本身释放 Thread.Sleep(300); foreach (User32.VK key in Enum.GetValues(typeof(User32.VK))) { // 检查键是否被按下 if (IsKeyPressed(key)) // 强制转换 VK 枚举为 int { Logger.LogWarning($"解除{key}的按下状态."); Simulation.SendInput.Keyboard.KeyUp(key); } } Logger.LogWarning("快捷键触发暂停,等待解除"); foreach (var item in RunnerContext.Instance.SuspendableDictionary) { item.Value.Suspend(); } first = false; } Thread.Sleep(1000); } //从暂停中解除 if (isSuspend) { Logger.LogWarning("暂停已经解除"); RunnerContext.Instance.ResumeAutoPick(); foreach (var item in RunnerContext.Instance.SuspendableDictionary) { item.Value.Resume(); } } } private static void CheckAndActivateGameWindow() { if (!TaskContext.Instance().Config.OtherConfig.RestoreFocusOnLostEnabled) { if (!SystemControl.IsGenshinImpactActiveByProcess()) { var name = SystemControl.GetActiveByProcess(); Logger.LogWarning($"当前获取焦点的窗口为: {name},不是原神,暂停"); throw new RetryException("当前获取焦点的窗口不是原神"); } } var count = 0; //未激活则尝试恢复窗口 while (!SystemControl.IsGenshinImpactActiveByProcess()) { if (count >= 10 && count % 10 == 0) { Logger.LogInformation("多次尝试未恢复,尝试最小化后激活窗口!"); SystemControl.MinimizeAndActivateWindow(TaskContext.Instance().GameHandle); } else { Logger.LogInformation("当前获取焦点的窗口不是原神,尝试恢复窗口"); SystemControl.FocusWindow(TaskContext.Instance().GameHandle); } count++; Thread.Sleep(1000); } } public static void Sleep(int millisecondsTimeout, CancellationToken ct) { if (ct.IsCancellationRequested) { throw new NormalEndException("取消自动任务"); } if (millisecondsTimeout <= 0) { return; } NewRetry.Do(() => { if (ct.IsCancellationRequested) { throw new NormalEndException("取消自动任务"); } TrySuspend(); CheckAndActivateGameWindow(); }, TimeSpan.FromSeconds(1), 100); Thread.Sleep(millisecondsTimeout); if (ct.IsCancellationRequested) { throw new NormalEndException("取消自动任务"); } } public static async Task Delay(int millisecondsTimeout, CancellationToken ct) { if (ct is { IsCancellationRequested: true }) { throw new NormalEndException("取消自动任务"); } if (millisecondsTimeout <= 0) { return; } NewRetry.Do(() => { if (ct is { IsCancellationRequested: true }) { throw new NormalEndException("取消自动任务"); } TrySuspend(); CheckAndActivateGameWindow(); }, TimeSpan.FromSeconds(1), 100); await Task.Delay(millisecondsTimeout, ct); if (ct is { IsCancellationRequested: true }) { throw new NormalEndException("取消自动任务"); } } public static Mat CaptureGameImage(IGameCapture? gameCapture) { var image = gameCapture?.Capture(); if (image == null) { Logger.LogWarning("截图失败!"); // 重试3次 for (var i = 0; i < 3; i++) { image = gameCapture?.Capture(); if (image != null) { return image; } Sleep(30); } throw new Exception("尝试多次后,截图失败!"); } else { return image; } } public static Mat? CaptureGameImageNoRetry(IGameCapture? gameCapture) { return gameCapture?.Capture(); } /// /// 自动判断当前运行上下文中截图方式,并选择合适的截图方式返回 /// /// public static ImageRegion CaptureToRectArea(bool forceNew = false) { var image = CaptureGameImage(TaskTriggerDispatcher.GlobalGameCapture); var content = new CaptureContent(image, 0, 0); return content.CaptureRectArea; } }