From 11dda84592d1c7c19deff658178f1965bb4c9842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Mon, 9 Dec 2024 00:57:17 +0800 Subject: [PATCH] pick drops --- .../Recognition/ONNX/BgiYoloV8Predictor.cs | 11 ++ .../ONNX/BgiYoloV8PredictorFactory.cs | 18 +++ .../GameTask/AutoFight/AutoFightTask.cs | 6 +- .../AutoPathing/Handler/MiningHandler.cs | 11 +- .../GameTask/Common/Job/ScanPickTask.cs | 110 ++++++++++++++++++ .../ViewModel/Pages/HotKeyPageViewModel.cs | 5 +- 6 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 BetterGenshinImpact/Core/Recognition/ONNX/BgiYoloV8PredictorFactory.cs create mode 100644 BetterGenshinImpact/GameTask/Common/Job/ScanPickTask.cs diff --git a/BetterGenshinImpact/Core/Recognition/ONNX/BgiYoloV8Predictor.cs b/BetterGenshinImpact/Core/Recognition/ONNX/BgiYoloV8Predictor.cs index f621abdb..2ce81e3a 100644 --- a/BetterGenshinImpact/Core/Recognition/ONNX/BgiYoloV8Predictor.cs +++ b/BetterGenshinImpact/Core/Recognition/ONNX/BgiYoloV8Predictor.cs @@ -8,6 +8,7 @@ using System.Diagnostics; using System.Drawing.Imaging; using System.IO; using System.Text.Json; +using BetterGenshinImpact.View.Drawable; namespace BetterGenshinImpact.Core.Recognition.ONNX; @@ -45,6 +46,16 @@ public class BgiYoloV8Predictor(string modelRelativePath) : IDisposable } } Debug.WriteLine("YOLOv8识别结果:" + JsonSerializer.Serialize(dict)); + + var list = new List(); + foreach (var box in result.Boxes) + { + var rect = new Rect(box.Bounds.X, box.Bounds.Y, box.Bounds.Width, box.Bounds.Height); + list.Add(region.ToRectDrawable(rect, modelRelativePath)); + } + + VisionContext.Instance().DrawContent.PutOrRemoveRectList(modelRelativePath, list); + return dict; } diff --git a/BetterGenshinImpact/Core/Recognition/ONNX/BgiYoloV8PredictorFactory.cs b/BetterGenshinImpact/Core/Recognition/ONNX/BgiYoloV8PredictorFactory.cs new file mode 100644 index 00000000..dbad7e95 --- /dev/null +++ b/BetterGenshinImpact/Core/Recognition/ONNX/BgiYoloV8PredictorFactory.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace BetterGenshinImpact.Core.Recognition.ONNX; + +public class BgiYoloV8PredictorFactory +{ + static Dictionary _predictors = new(); + + public static BgiYoloV8Predictor GetPredictor(string modelRelativePath) + { + if (!_predictors.ContainsKey(modelRelativePath)) + { + _predictors[modelRelativePath] = new BgiYoloV8Predictor(modelRelativePath); + } + + return _predictors[modelRelativePath]; + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs b/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs index c82bb894..bfb957e6 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using BetterGenshinImpact.GameTask.AutoFight.Assets; using static BetterGenshinImpact.GameTask.Common.TaskControl; using BetterGenshinImpact.Core.Recognition.OpenCv; +using BetterGenshinImpact.GameTask.Common.Job; using OpenCvSharp; using Vanara; @@ -40,7 +41,7 @@ public class AutoFightTask : ISoloTask if (_taskParam.FightFinishDetectEnabled) { - _predictor = new BgiYoloV8Predictor(@"Assets\Model\World\bgi_world.onnx"); + _predictor = BgiYoloV8PredictorFactory.GetPredictor(@"Assets\Model\World\bgi_world.onnx"); } } @@ -124,7 +125,10 @@ public class AutoFightTask : ISoloTask if (_taskParam is { FightFinishDetectEnabled: true, PickDropsAfterFightEnabled: true }) { + // + // 执行自动拾取掉落物的功能 + await new ScanPickTask().Start(ct); } } diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/MiningHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/MiningHandler.cs index e0121e67..db3695ea 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/MiningHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/MiningHandler.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using BetterGenshinImpact.GameTask.AutoFight.Model; using BetterGenshinImpact.GameTask.AutoFight.Script; using BetterGenshinImpact.GameTask.AutoPathing.Model; +using BetterGenshinImpact.GameTask.Common.Job; using Microsoft.Extensions.Logging; using static BetterGenshinImpact.GameTask.Common.TaskControl; @@ -22,6 +23,8 @@ public class MiningHandler : IActionHandler 坎蒂丝 e(hold) """); + private readonly ScanPickTask _scanPickTask = new(); + public async Task RunAsync(CancellationToken ct, WaypointForTrack? waypointForTrack = null) { var combatScenes = await RunnerContext.Instance.GetCombatScenes(ct); @@ -30,14 +33,14 @@ public class MiningHandler : IActionHandler Logger.LogError("队伍识别未初始化成功!"); return; } - + // 挖矿 Mining(combatScenes); - + await Delay(1000, ct); - + // 拾取 - + await _scanPickTask.Start(ct); } private void Mining(CombatScenes combatScenes) diff --git a/BetterGenshinImpact/GameTask/Common/Job/ScanPickTask.cs b/BetterGenshinImpact/GameTask/Common/Job/ScanPickTask.cs new file mode 100644 index 00000000..bb58d123 --- /dev/null +++ b/BetterGenshinImpact/GameTask/Common/Job/ScanPickTask.cs @@ -0,0 +1,110 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using BetterGenshinImpact.Core.Recognition.ONNX; +using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.GameTask.Model.Area; +using BetterGenshinImpact.View.Drawable; +using Microsoft.Extensions.Logging; +using OpenCvSharp; +using Vanara.PInvoke; +using static BetterGenshinImpact.GameTask.Common.TaskControl; + +namespace BetterGenshinImpact.GameTask.Common.Job; + +/// +/// 扫描拾取任务 +/// 请在安全地区使用 +/// +public class ScanPickTask +{ + private readonly BgiYoloV8Predictor _predictor = BgiYoloV8PredictorFactory.GetPredictor(@"Assets\Model\World\bgi_world.onnx"); + private readonly double _dpi = TaskContext.Instance().DpiScale; + private readonly RECT _realCaptureRect = TaskContext.Instance().SystemInfo.CaptureAreaRect; + + + public async Task Start(CancellationToken ct) + { + try + { + await DoOnce(ct); + } + catch (Exception e) + { + Logger.LogDebug(e, "拾取周边物品异常"); + Logger.LogError("拾取周边物品异常: {Msg}", e.Message); + } + finally + { + VisionContext.Instance().DrawContent.ClearAll(); + } + } + + public async Task DoOnce(CancellationToken ct) + { + await ResetCamera(ct); + + for (int n = 0; n < 5; n++) // 最多跑5次 + { + var hasDrops = false; + + // 旋转视角 + for (var i = 0; i < 20; i++) + { + var ra = CaptureToRectArea(); + var resultDic = _predictor.Detect(ra); + // 过滤出可拾取物品 + var pickItems = resultDic.Where(x => x.Key is "drops" or "ore") + .SelectMany(x => x.Value).ToList(); + + + if (pickItems.Count > 0) + { + hasDrops = true; + // 把鼠标位置和物品位置重合 + MoveCursorTo(pickItems.First(), ra); + await Delay(100, ct); + // 物体越小,距离越远 + await WalkForward(ct); + break; + } + + Simulation.SendInput.Mouse.MoveMouseBy((int)(300 * _dpi), 0); + await Delay(100, ct); + } + + if (!hasDrops) + { + break; + } + } + + } + + private static async Task WalkForward(CancellationToken ct) + { + Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W); + await Delay(1000, ct); + Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W); + } + + private void MoveCursorTo(Rect item, ImageRegion ra) + { + var centerX = (item.Left + item.Right) / 2; + var centerY = (item.Top + item.Bottom) / 2; + var dx = centerX - ra.Width / 2; + var dy = centerY - ra.Height / 2; + var r = _realCaptureRect.Width * 1.0 / ra.Width; // 缩放比例 + Simulation.SendInput.Mouse.MoveMouseBy((int)(dx * r * _dpi), (int)(dy * r * _dpi)); + } + + // 回正 并下移视角 + private async Task ResetCamera(CancellationToken ct) + { + // Simulation.SendInput.Keyboard.Mouse.MiddleButtonClick(); + // await Delay(500, ct); + Simulation.SendInput.Keyboard.Mouse.MoveMouseBy(0, (int)(500 * _dpi)); + await Delay(100, ct); + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs index 1febcf22..3eadcae1 100644 --- a/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs @@ -569,7 +569,10 @@ public partial class HotKeyPageViewModel : ObservableObject, IViewModel // Task.Run(async () => { await new ClaimBattlePassRewardsTask().Start(new CancellationToken()); }); // 领取邮件奖励 - Task.Run(async () => { await new ClaimMailRewardsTask().Start(new CancellationToken()); }); + // Task.Run(async () => { await new ClaimMailRewardsTask().Start(new CancellationToken()); }); + + // 拾取物品 + Task.Run(async () => { await new ScanPickTask().Start(new CancellationToken()); }); } )); debugDirectory.Children.Add(new HotKeySettingModel(