Files
better-genshin-impact/BetterGenshinImpact/GameTask/Common/TaskControl.cs
2025-11-21 02:52:00 +00:00

207 lines
6.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<TaskControl>();
public static readonly SemaphoreSlim TaskSemaphore = new(1, 1);
private static readonly PausableDelayManager _delayManager = new();
public static void CheckAndSleep(int millisecondsTimeout)
{
_delayManager.Sleep(millisecondsTimeout);
}
/// <summary>
/// Checks and handles pause/suspend state and window focus without sleeping.
/// </summary>
public static void CheckPauseAndWindowFocus()
{
_delayManager.CheckPauseAndWindowFocus();
}
public static void Sleep(int millisecondsTimeout)
{
_delayManager.Sleep(millisecondsTimeout);
}
[Obsolete("Use CheckAndSleep or Sleep instead")]
private static bool IsKeyPressed(User32.VK key)
{
// 获取按键状态
var state = User32.GetAsyncKeyState((int)key);
// 检查高位是否为 1表示按键被按下
return (state & 0x8000) != 0;
}
[Obsolete("This method is now handled internally by PausableDelayManager")]
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();
}
}
}
[Obsolete("This method is now handled internally by PausableDelayManager")]
private static void CheckAndActivateGameWindow()
{
if (!TaskContext.Instance().Config.OtherConfig.RestoreFocusOnLostEnabled)
{
if (!SystemControl.IsGenshinImpactActiveByProcess())
{
Logger.LogInformation("当前获取焦点的窗口不是原神,暂停");
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("取消自动任务");
}
try
{
_delayManager.Sleep(millisecondsTimeout, ct);
}
catch (OperationCanceledException)
{
throw new NormalEndException("取消自动任务");
}
}
public static async Task Delay(int millisecondsTimeout, CancellationToken ct)
{
if (ct is { IsCancellationRequested: true })
{
throw new NormalEndException("取消自动任务");
}
try
{
await _delayManager.DelayAsync(millisecondsTimeout, ct);
}
catch (OperationCanceledException)
{
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();
}
/// <summary>
/// 自动判断当前运行上下文中截图方式,并选择合适的截图方式返回
/// </summary>
/// <returns></returns>
public static ImageRegion CaptureToRectArea(bool forceNew = false)
{
var image = CaptureGameImage(TaskTriggerDispatcher.GlobalGameCapture);
var content = new CaptureContent(image, 0, 0);
return content.CaptureRectArea;
}
}