diff --git a/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/1920x1080/chest.png b/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/1920x1080/chest.png new file mode 100644 index 00000000..7797de1c Binary files /dev/null and b/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/1920x1080/chest.png differ diff --git a/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/1920x1080/chest_F_icon.png b/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/1920x1080/chest_F_icon.png new file mode 100644 index 00000000..2c79d588 Binary files /dev/null and b/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/1920x1080/chest_F_icon.png differ diff --git a/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/1920x1080/flower_F_icon.png b/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/1920x1080/flower_F_icon.png new file mode 100644 index 00000000..67eca806 Binary files /dev/null and b/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/1920x1080/flower_F_icon.png differ diff --git a/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/AutoOpenChestAssets.cs b/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/AutoOpenChestAssets.cs new file mode 100644 index 00000000..5fd596e6 --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/AutoOpenChestAssets.cs @@ -0,0 +1,60 @@ +using BetterGenshinImpact.Core.Recognition; +using BetterGenshinImpact.GameTask.Model; +using OpenCvSharp; + +namespace BetterGenshinImpact.GameTask.AutoFishing.Assets; + +public class AutoOpenChestAssets : BaseAssets +{ + public RecognitionObject ChestIconRo; + public RecognitionObject ChestFIconRo; + public RecognitionObject FlowerFIconRo; + + +#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑添加 "required" 修饰符或声明为可为 null。 + private AutoOpenChestAssets() : base() + { + Initialization(this.systemInfo); + } + + protected AutoOpenChestAssets(ISystemInfo systemInfo) : base(systemInfo) + { + Initialization(systemInfo); + } +#pragma warning restore CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑添加 "required" 修饰符或声明为可为 null。 + + private void Initialization(ISystemInfo systemInfo) + { + var assetScale = systemInfo.AssetScale; + ChestIconRo = new RecognitionObject + { + Name = "ChestIcon", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage("AutoOpenChest", "chest.png", systemInfo), + RegionOfInterest = new Rect((int)(330* assetScale), + (int)(130*assetScale), + (int)(1250*assetScale), + (int)(840 * assetScale)), + DrawOnWindow = false + }.InitTemplate(); + + ChestFIconRo = new RecognitionObject + { + Name = "ChestFIcon", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage("AutoOpenChest", "chest_F_icon.png", systemInfo), + RegionOfInterest = new Rect((int)(1150 * assetScale),(int)(450 * assetScale),(int)(100 * assetScale),(int)(300 * assetScale)), + DrawOnWindow = false + }.InitTemplate(); + + + FlowerFIconRo = new RecognitionObject + { + Name = "FlowerFIcon", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage("AutoOpenChest", "flower_F_icon.png", systemInfo), + RegionOfInterest = new Rect((int)(1150 * assetScale), (int)(450 * assetScale), (int)(100 * assetScale), (int)(300 * assetScale)), + DrawOnWindow = false + }.InitTemplate(); + } +} diff --git a/BetterGenshinImpact/GameTask/AutoOpenChest/AutoOpenChestTask.cs b/BetterGenshinImpact/GameTask/AutoOpenChest/AutoOpenChestTask.cs new file mode 100644 index 00000000..73074c0b --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoOpenChest/AutoOpenChestTask.cs @@ -0,0 +1,106 @@ +using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; +using BetterGenshinImpact.GameTask; +using BetterGenshinImpact.GameTask.AutoFishing.Assets; +using BetterGenshinImpact.GameTask.Common.BgiVision; +using BetterGenshinImpact.GameTask.Model.Area; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using static BetterGenshinImpact.GameTask.Common.TaskControl; +using static TorchSharp.torch.distributions.constraints; +namespace GameTask.AutoOpenChest; + +/// +/// 识别宝箱图标,走向宝箱并开启。 +/// +public class AutoOpenChestTask : ISoloTask +{ + public string Name => "识别并开启宝箱"; + + private AutoOpenChestAssets assets = AutoOpenChestAssets.Instance; + + public async Task Start(CancellationToken ct) + { + var ra = CaptureToRectArea(); + + if (ra.Find(assets.ChestFIconRo).IsExist()) + { + CancellationTokenSource _ct = new(); + ct.Register(_ct.Cancel); + bool isFlower = false; // 是否是地脉花 + // 限制寻找宝箱的时间 + var timeLimit = 60; + var timeoutTask = Task.Delay(TimeSpan.FromSeconds(timeLimit), _ct.Token) + .ContinueWith(_ => _ct.Cancel(), TaskContinuationOptions.OnlyOnRanToCompletion); + try + { + while (!_ct.IsCancellationRequested) + { + ra = CaptureToRectArea(); + Region chestIcon = ra.Find(assets.ChestIconRo); + int limit = chestIcon.Width; + if (!chestIcon.IsExist()) + { + Logger.LogInformation("未找到宝箱图标"); + return; + } + + if (ra.Find(assets.ChestFIconRo).IsExist() || ra.Find(assets.FlowerFIconRo).IsExist()) + { + // 找到宝箱/ 地脉花 + isFlower = ra.Find(assets.FlowerFIconRo).IsExist(); + Simulation.SendInput.SimulateAction(GIActions.PickUpOrInteract, KeyType.KeyPress); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); + break; + } + + if (Math.Abs(chestIcon.Width / 2 - chestIcon.X) < limit) + { + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); + } + + if (chestIcon.Y > 600) + { + // 若宝箱图标在下方就表示宝箱在后面。 + Simulation.SendInput.SimulateAction(GIActions.MoveBackward); + await Delay(30, _ct.Token); + Simulation.SendInput.Mouse.MiddleButtonClick(); + } + else + { + var gap = (ra.Width / 2) - chestIcon.X; + int rate = 2; + Simulation.SendInput.Mouse.MoveMouseBy(gap / rate, 0); + } + + await Delay(500, _ct.Token); + } + } + finally + { + // 如果循环提前退出,取消计时任务 + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); + _ct.Cancel(); + await timeoutTask; // 等待超时任务结束(忽略可能的异常) + } + + // TODO : 是否考虑兼容地脉花 以及地脉花的获取策略 + + if (isFlower) { + // 地脉花策略 + flowerHandle(); + } + } + } + + private async void flowerHandle() + { + Simulation.SendInput.SimulateAction(GIActions.OpenPaimonMenu); + } + + +}