Files
better-genshin-impact/BetterGenshinImpact/GameTask/Common/TaskControl.cs
mfkvfhpdx 4760752e70 在调度器里面的任务之前,增加月卡处理,解决4点如果未进入任务会卡住的问题。增加了日志分析小怪详细。解决日志分析兜底结束日期不生效的问题。 (#1433)
* 修改调度器任务和部分独立任务失去焦点时,强制切换回游戏窗口,如果用常规的方式无法激活窗口,则第10次会尝试最小化所有窗口后激活游戏。

* 去除未引入的类引用

* 修正战斗结束后,大概率打开队伍界面的问题

* 修复有些电脑上因未知原因,战斗0秒打断

* 把失焦激活放入了设置-通用设置-其他设置中,默认关闭。暂停恢复时,重置移动的起始时间,防止因暂停而导致超时放弃任务。

* 在调度器里面的任务之前,增加月卡处理,解决4点如果未进入任务会卡住的问题。增加了日志分析小怪详细。解决日志分析兜底结束日期不生效的问题。

* 在设置=》其他设置中 增加调度器任务传送过程中自动领取探索奖励功能配置。

* 调整自动派遣后恢复原任务的逻辑

* 自动领取派遣奖励时,跳过异常,防止整个配置组任务被打断。

* 把打开大地图方法从TpTask中抽出为公共方法,自动领取派遣代码调整到了调度器中。

* 去除了未使用的引用

* 暂停恢复逻辑增加恢复中条件和非空判断

* 增加了临时暂停自动拾取的逻辑(RunnerContext.AutoPickTriggerStopCount 为0时不限制,大于0时停止,多次暂停会累加该值,每次恢复-1),支持嵌套情况的暂停,在自动派遣(和结束后5秒)或暂停调度器任务时,同时暂停自动拾取功能。

* 调整暂停拾取方法

* 调整个日志输出

* 路径追踪复苏时,暂停拾取
2025-04-26 21:47:57 +08:00

226 lines
6.5 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);
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())
{
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("取消自动任务");
}
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 CaptureImageRes 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 CaptureImageRes? 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;
}
}