using BetterGenshinImpact.GameTask.AutoGeniusInvokation; using BetterGenshinImpact.GameTask.Model; using BetterGenshinImpact.Genshin.Settings; using BetterGenshinImpact.Helpers; using BetterGenshinImpact.View; using Fischless.GameCapture; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows; using BetterGenshinImpact.GameTask.AutoWood; using Vanara.PInvoke; namespace BetterGenshinImpact.GameTask { public class TaskTriggerDispatcher : IDisposable { private readonly ILogger _logger = App.GetLogger(); private readonly System.Timers.Timer _timer = new(); private List? _triggers; public IGameCapture? GameCapture { get; private set; } private static readonly object _locker = new(); private int _frameIndex = 0; private RECT _gameRect = RECT.Empty; private bool _prevGameActive; public TaskTriggerDispatcher() { _timer.Elapsed += Tick; //_timer.Tick += Tick; } public void Start(IntPtr hWnd, CaptureModes mode, int interval = 50) { // 初始化截图器 GameCapture = GameCaptureFactory.Create(mode); // 激活窗口 保证后面能够正常获取窗口信息 SystemControl.ActivateWindow(hWnd); // 初始化任务上下文(一定要在初始化触发器前完成) TaskContext.Instance().Init(hWnd); PrintSystemInfo(); // 初始化触发器(一定要在任务上下文初始化完毕后使用) _triggers = GameTaskManager.LoadTriggers(); // 启动截图 GameCapture.Start(hWnd); // 读取游戏注册表配置 ReadGameSettings(); // 启动定时器 _frameIndex = 0; _timer.Interval = interval; if (!_timer.Enabled) { _timer.Start(); } } private void ReadGameSettings() { try { SettingsContainer settings = new(); settings.FromReg(); var lang = settings.Language?.TextLang; if (lang != null && lang != TextLanguage.SimplifiedChinese) { _logger.LogWarning("当前游戏语言{Lang}不是简体中文,部分功能可能无法正常使用", lang); _logger.LogWarning("The game language is not Simplified Chinese, some functions may not work properly"); } } catch (Exception e) { MessageBox.Show("游戏注册表配置信息读取失败:" + e.Source + "\r\n--" + Environment.NewLine + e.StackTrace + "\r\n---" + Environment.NewLine + e.Message); } } private void PrintSystemInfo() { var systemInfo = TaskContext.Instance().SystemInfo; var width = systemInfo.GameScreenSize.Width; var height = systemInfo.GameScreenSize.Height; _logger.LogInformation("当前游戏分辨率{Width}x{Height},素材缩放比率{Scale}", width, height, systemInfo.AssetScale.ToString("F")); if (width * 9 != height * 16) { _logger.LogWarning("当前游戏分辨率不是16:9,部分功能可能无法正常使用"); } } public void Stop() { _timer.Stop(); GameCapture?.Stop(); _gameRect = RECT.Empty; _prevGameActive = false; } public void StartTimer() { if (!_timer.Enabled) { _timer.Start(); } } public void StopTimer() { if (_timer.Enabled) { _timer.Stop(); } } /// /// 启动独立任务 /// public void StartIndependentTask(IndependentTaskEnum taskType, BaseTaskParam param) { if (!_timer.Enabled) { throw new Exception("请先在启动页启动BetterGI,如果已经启动请重启"); } StopTimer(); var maskWindow = MaskWindow.Instance(); maskWindow.LogBox.IsHitTestVisible = false; maskWindow.Invoke(() => { maskWindow.Show(); }); if (taskType == IndependentTaskEnum.AutoGeniusInvokation) { AutoGeniusInvokationTask.Start((GeniusInvokationTaskParam)param); } else if (taskType == IndependentTaskEnum.AutoWood) { Task.Run(() => { new AutoWoodTask().Start((WoodTaskParam)param); }); } } public void Dispose() => Stop(); public void Tick(object? sender, EventArgs e) { var hasLock = false; try { Monitor.TryEnter(_locker, ref hasLock); if (!hasLock) { // 正在执行时跳过 return; } // 检查截图器是否初始化 if (GameCapture == null || !GameCapture.IsCapturing) { _logger.LogError("截图器未初始化!"); Stop(); return; } // 检查游戏是否在前台 var active = SystemControl.IsGenshinImpactActive(); var maskWindow = MaskWindow.Instance(); if (!active) { if (_prevGameActive) { Debug.WriteLine("游戏窗口不在前台, 不再进行截屏"); } var pName = SystemControl.GetActiveProcessName(); if (pName != "BetterGI" && pName != "YuanShen" && pName != "GenshinImpact" && pName != "Genshin Impact Cloud Game") { maskWindow.Invoke(() => { maskWindow.Hide(); }); } _prevGameActive = active; return; } else { if (!_prevGameActive) { maskWindow.Invoke(() => { if (!maskWindow.IsClosed) { maskWindow.Show(); } }); } _prevGameActive = active; // 移动游戏窗口的时候同步遮罩窗口的位置,此时不进行捕获 if (SyncMaskWindowPosition()) { return; } } // 帧序号自增 1分钟后归零(MaxFrameIndexSecond) _frameIndex = (_frameIndex + 1) % (int)(CaptureContent.MaxFrameIndexSecond * 1000d / _timer.Interval); if (_triggers == null || !_triggers.Exists(t => t.IsEnabled)) { Debug.WriteLine("没有可用的触发器, 不再进行截屏"); return; } var speedTimer = new SpeedTimer(); // 捕获游戏画面 var bitmap = GameCapture.Capture(); speedTimer.Record("截图"); if (bitmap == null) { _logger.LogWarning("截图失败!"); return; } // 循环执行所有触发器 有独占状态的触发器的时候只执行独占触发器 var content = new CaptureContent(bitmap, _frameIndex, _timer.Interval, this); var exclusiveTrigger = _triggers.FirstOrDefault(t => t is { IsEnabled: true, IsExclusive: true }); if (exclusiveTrigger != null) { exclusiveTrigger.OnCapture(content); } else { foreach (var trigger in _triggers.Where(trigger => trigger.IsEnabled)) { trigger.OnCapture(content); speedTimer.Record(trigger.Name); } } speedTimer.DebugPrint(); //if (_frameIndex / content.FrameRate % 2 == 0) //{ // GC.Collect(); //} content.Dispose(); } finally { if (hasLock) { Monitor.Exit(_locker); } } } /// /// / 移动游戏窗口的时候同步遮罩窗口的位置 /// /// private bool SyncMaskWindowPosition() { var hWnd = TaskContext.Instance().GameHandle; var currentRect = SystemControl.GetCaptureRect(hWnd); if (_gameRect == RECT.Empty) { _gameRect = new RECT(currentRect); } else if (_gameRect != currentRect) { // 后面大概可以取消掉这个判断,支持随意移动变化窗口 —— 不支持 需要考虑的问题太多了 if (_gameRect.Width != currentRect.Width || _gameRect.Height != currentRect.Height) { _logger.LogError("游戏窗口大小发生变化, 请重新启动捕获程序!"); } _gameRect = new RECT(currentRect); double scale = TaskContext.Instance().DpiScale; TaskContext.Instance().SystemInfo.CaptureAreaRect = currentRect; MaskWindow.Instance().RefreshPosition(currentRect, scale); return true; } return false; } } }