mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-03-15 07:43:20 +08:00
185 lines
5.6 KiB
C#
185 lines
5.6 KiB
C#
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);
|
||
}
|
||
|
||
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("取消自动任务");
|
||
}
|
||
|
||
_delayManager.Sleep(millisecondsTimeout, ct);
|
||
}
|
||
|
||
public static async Task Delay(int millisecondsTimeout, CancellationToken ct)
|
||
{
|
||
if (ct is { IsCancellationRequested: true })
|
||
{
|
||
throw new NormalEndException("取消自动任务");
|
||
}
|
||
|
||
await _delayManager.DelayAsync(millisecondsTimeout, ct);
|
||
}
|
||
|
||
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;
|
||
}
|
||
} |