mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-04-02 10:45:22 +08:00
* 修改调度器任务和部分独立任务失去焦点时,强制切换回游戏窗口,如果用常规的方式无法激活窗口,则第10次会尝试最小化所有窗口后激活游戏。 * 去除未引入的类引用 * 修正战斗结束后,大概率打开队伍界面的问题 * 修复有些电脑上因未知原因,战斗0秒打断 * 把失焦激活放入了设置-通用设置-其他设置中,默认关闭。暂停恢复时,重置移动的起始时间,防止因暂停而导致超时放弃任务。 * 在调度器里面的任务之前,增加月卡处理,解决4点如果未进入任务会卡住的问题。增加了日志分析小怪详细。解决日志分析兜底结束日期不生效的问题。 * 在设置=》其他设置中 增加调度器任务传送过程中自动领取探索奖励功能配置。 * 调整自动派遣后恢复原任务的逻辑 * 自动领取派遣奖励时,跳过异常,防止整个配置组任务被打断。 * 把打开大地图方法从TpTask中抽出为公共方法,自动领取派遣代码调整到了调度器中。 * 去除了未使用的引用 * 暂停恢复逻辑增加恢复中条件和非空判断 * 增加了临时暂停自动拾取的逻辑(RunnerContext.AutoPickTriggerStopCount 为0时不限制,大于0时停止,多次暂停会累加该值,每次恢复-1),支持嵌套情况的暂停,在自动派遣(和结束后5秒)或暂停调度器任务时,同时暂停自动拾取功能。 * 调整暂停拾取方法 * 调整个日志输出 * 路径追踪复苏时,暂停拾取
226 lines
6.5 KiB
C#
226 lines
6.5 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);
|
||
|
||
|
||
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;
|
||
}
|
||
} |