From 135d1b60bb057b446a789a6bbff0c9fade172afa Mon Sep 17 00:00:00 2001 From: kaedelcb <57870068+kaedelcb@users.noreply.github.com> Date: Sun, 10 Aug 2025 13:36:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=9B=BE=E4=BD=8D=E4=BC=98?= =?UTF-8?q?=E5=85=88=E5=8A=9F=E8=83=BD=E5=92=8C=E6=97=8B=E8=BD=AC=E5=AF=BB?= =?UTF-8?q?=E6=95=8C=E4=BC=98=E5=8C=96=20(#2039)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoFight/AutoFightConfig.cs | 12 ++ .../GameTask/AutoFight/AutoFightParam.cs | 10 +- .../GameTask/AutoFight/AutoFightSeek.cs | 158 ++++++++++++--- .../GameTask/AutoFight/AutoFightTask.cs | 36 +++- .../View/Pages/TaskSettingsPage.xaml | 181 +++++++++++++++++- .../Pages/View/ScriptGroupConfigView.xaml | 177 ++++++++++++++++- 6 files changed, 534 insertions(+), 40 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoFight/AutoFightConfig.cs b/BetterGenshinImpact/GameTask/AutoFight/AutoFightConfig.cs index 815e7fb4..557c7fa0 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/AutoFightConfig.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/AutoFightConfig.cs @@ -113,6 +113,18 @@ public partial class AutoFightConfig : ObservableObject [ObservableProperty] private bool _kazuhaPickupEnabled = true; + [ObservableProperty] + private string _guardianAvatar = " "; + + [ObservableProperty] + private bool _guardianCombatSkip = false; + + [ObservableProperty] + private bool _skipModel = false; + + [ObservableProperty] + private bool _guardianAvatarHold = false; + /// /// 战斗结束后,如果不存在万叶,则切换至存在万叶的队伍(基于开启万叶拾取情况下) /// diff --git a/BetterGenshinImpact/GameTask/AutoFight/AutoFightParam.cs b/BetterGenshinImpact/GameTask/AutoFight/AutoFightParam.cs index 6ee6ad0e..5559001e 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/AutoFightParam.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/AutoFightParam.cs @@ -45,7 +45,10 @@ public class AutoFightParam : BaseTaskParam FinishDetectConfig.BattleEndProgressBarColor = TaskContext.Instance().Config.AutoFightConfig.FinishDetectConfig.BattleEndProgressBarColor; FinishDetectConfig.BattleEndProgressBarColorTolerance = TaskContext.Instance().Config.AutoFightConfig.FinishDetectConfig.BattleEndProgressBarColorTolerance; - + GuardianAvatar = autoFightConfig.GuardianAvatar; + GuardianCombatSkip = autoFightConfig.GuardianCombatSkip; + SkipModel = autoFightConfig.SkipModel; + GuardianAvatarHold = autoFightConfig.GuardianAvatarHold; } public FightFinishDetectConfig FinishDetectConfig { get; set; } = new(); @@ -62,5 +65,8 @@ public class AutoFightParam : BaseTaskParam public string ActionSchedulerByCd = ""; public string KazuhaPartyName; public string OnlyPickEliteDropsMode=""; - + public string GuardianAvatar { get; set; } = " "; + public bool GuardianCombatSkip { get; set; } = false; + public bool SkipModel = false; + public bool GuardianAvatarHold = false; } \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoFight/AutoFightSeek.cs b/BetterGenshinImpact/GameTask/AutoFight/AutoFightSeek.cs index 497b9cbf..3482b4d5 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/AutoFightSeek.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/AutoFightSeek.cs @@ -6,6 +6,8 @@ using System.Threading.Tasks; using static BetterGenshinImpact.GameTask.Common.TaskControl; using OpenCvSharp; using BetterGenshinImpact.Core.Recognition.OpenCv; +using BetterGenshinImpact.GameTask.AutoFight.Model; +using BetterGenshinImpact.GameTask.AutoFight.Script; namespace BetterGenshinImpact.GameTask.AutoFight { @@ -207,14 +209,16 @@ namespace BetterGenshinImpact.GameTask.AutoFight } } - public class AutoFightSeek + public class AutoFightSeek { - public static async Task SeekAndFightAsync(ILogger logger, int detectDelayTime,int delayTime, CancellationToken ct) + public static int RotationCount = 0; + + public static async Task SeekAndFightAsync(ILogger logger, int detectDelayTime,int delayTime,CancellationToken ct) { Scalar bloodLower = new Scalar(255, 90, 90); int retryCount = 0; - while (retryCount < 10) + while (retryCount < 27) { var image = CaptureToRectArea(); Mat mask = OpenCvCommonHelper.Threshold(image.DeriveCrop(0, 0, 1500, 900).SrcMat, bloodLower); @@ -229,10 +233,10 @@ namespace BetterGenshinImpact.GameTask.AutoFight if (numLabels > 1) { logger.LogInformation("检测画面内疑似有敌人,继续战斗..."); - // 获取第一个连通对象的统计信息(标签1) - Mat firstRow = stats.Row(1); // 获取第1行(标签1)的数据 + + Mat firstRow = stats.Row(1); int[] statsArray; - bool success = firstRow.GetArray(out statsArray); // 使用 out 参数来接收数组数据 + bool success = firstRow.GetArray(out statsArray); int height = statsArray[3]; logger.LogInformation("敌人血量高度:{height}", height); @@ -241,9 +245,6 @@ namespace BetterGenshinImpact.GameTask.AutoFight stats.Dispose(); centroids.Dispose(); - // //如果不用旋转判断敌人,直接跳过开队伍检测,加快战斗速度 - // return height > 2;//大于2预防误判 - if (success && height > 2) { if (height < 7) @@ -261,12 +262,7 @@ namespace BetterGenshinImpact.GameTask.AutoFight } if (height < 3) return null; } - //如果不用旋转判断敌人,直接跳过开队伍检测,加快战斗速度 - // else - // { - // logger.LogInformation("首次检测画面内没有怪物..."); - // return true; - // } + if (retryCount == 0) { await Delay(delayTime,ct); @@ -277,7 +273,7 @@ namespace BetterGenshinImpact.GameTask.AutoFight var b33 = ra3.SrcMat.At(50, 790); // 进度条颜色 var whiteTile3 = ra3.SrcMat.At(50, 768); // 白块 Simulation.SendInput.SimulateAction(GIActions.Drop); - + if (IsWhite(whiteTile3.Item2, whiteTile3.Item1, whiteTile3.Item0) && IsYellow(b33.Item2, b33.Item1, b33.Item0)) { @@ -286,18 +282,30 @@ namespace BetterGenshinImpact.GameTask.AutoFight return true; } } - - // logger.LogInformation("画面内没有怪物,旋转寻找..."); - if (retryCount <= 1) + + if (RotationCount == 3 && retryCount == 0) { - Simulation.SendInput.Mouse.MoveMouseBy(image.Width / 2, -image.Height / 3); + Simulation.SendInput.Mouse.MiddleButtonClick(); + await Task.Delay(500, ct); + } + + if (retryCount <= 2) + { + var offsets = new (int x, int y)[] { + (image.Width / 6, -image.Height / 5), + (image.Width / 6, 0), + (image.Width / 6, image.Height / 6) + }; + + var offsetIndex = RotationCount < 3 ? 0 : (RotationCount == 3) ? 1 : 2; + Simulation.SendInput.Mouse.MoveMouseBy(offsets[offsetIndex].x, offsets[offsetIndex].y); } else { - Simulation.SendInput.Mouse.MoveMouseBy(image.Width / 2, 0); + Simulation.SendInput.Mouse.MoveMouseBy(image.Width / 6, 0); } - await Task.Delay(250,ct); + await Task.Delay(50,ct); image = CaptureToRectArea(); mask = OpenCvCommonHelper.Threshold(image.DeriveCrop(0, 0, 1500, 900).SrcMat, bloodLower); @@ -307,7 +315,6 @@ namespace BetterGenshinImpact.GameTask.AutoFight numLabels = Cv2.ConnectedComponentsWithStats(mask, labels, stats, centroids, connectivity: PixelConnectivity.Connectivity4, ltype: MatType.CV_32S); - // if (retryCount % 2 == 0) logger.LogInformation("检测敌人第 {retryCount} 次: {numLabels}", retryCount + 1, numLabels - 1); if (numLabels > 1) { @@ -336,8 +343,7 @@ namespace BetterGenshinImpact.GameTask.AutoFight if (height2 < 3) return null; } - - // logger.LogInformation("画面内没有怪物,尝试重新检测..."); + retryCount++; } logger.LogInformation("寻找敌人:{Text}", "无"); @@ -363,4 +369,106 @@ namespace BetterGenshinImpact.GameTask.AutoFight } } + public class AutoFightSkill + { + public static async Task EnsureGuardianSkill(Avatar guardianAvatar, CombatCommand command,string lastFightName, + string guardianAvatarName,bool guardianAvatarHold,int retryCount,CancellationToken ct) + { + int attempt = 0; + + if (guardianAvatar.IsSkillReady()) + { + while (attempt < retryCount) + { + if (guardianAvatar.TrySwitch(15,false)) + { + Simulation.ReleaseAllKey(); + + await Task.Delay(100, ct); + + guardianAvatar.ManualSkillCd = -1; + var cd1 = guardianAvatar.AfterUseSkill(); + if (cd1 > 0 ) + { + Logger.LogInformation("优先第 {text} 盾奶位 {GuardianAvatar} 战技Cd检测:{cd} 秒", guardianAvatarName, guardianAvatar.Name, cd1); + guardianAvatar.ManualSkillCd = -1; + return; + } + + guardianAvatar.UseSkill(guardianAvatarHold); + Simulation.ReleaseAllKey(); + await Task.Delay(200, ct); + + var cd2 = guardianAvatar.AfterUseSkill(); + if ( cd2 > 0 && guardianAvatar.TrySwitch(4,false)) + { + Logger.LogInformation("优先第 {text} 盾奶位 {GuardianAvatar} 释放战技成功,cd:{cd2} 秒", guardianAvatarName, guardianAvatar.Name, cd2); + guardianAvatar.ManualSkillCd = -1; + return; + } + + //新方法法:色块识别,带角色切换确认,不管OCR结果。避免OCR技能CD错误 + // if (await AvatarSkillAsync(Logger, guardianAvatar,false, 5, ct)) + // { + // guardianAvatar.ManualSkillCd = -1; + // return; + // } + + Logger.LogInformation("优先第 {text} 盾奶位 {GuardianAvatar} 释放战技:失败重试 {attempt} 次", guardianAvatarName, guardianAvatar.Name , attempt+1); + guardianAvatar.ManualSkillCd = 0; + } + attempt++; + } + } + } + + //新方法,备用,非OCR识别,判断色块进行,速度更快 + //检测技能图标中释放含有白色色块,检测前进行角色切换的确认,skills:false为E技能,true为Q技能(未开发) + public static async Task AvatarSkillAsync(ILogger logger, Avatar guardianAvatar, bool skills , int retryCount, CancellationToken ct) + { + if (guardianAvatar.TrySwitch()) + { + Scalar bloodLower = new Scalar(255, 255, 255); + int attempt = 0; + + while (attempt < retryCount) + { + var image2 = CaptureToRectArea(); + + var skillAra = skills + ? new Rect(image2.Width * 1700 / 1920, image2.Height * 996 / 1080, + image2.Width * 12 / 1920, image2.Height * 7 / 1080) //E技能区域 + + : new Rect(image2.Width * 1819 / 1920, image2.Height * 977 / 1080, + image2.Width * 13 / 1920, image2.Height * 6 / 1080); //Q技能区域 + + var mask2 = OpenCvCommonHelper.Threshold( + image2.DeriveCrop(skillAra).SrcMat, + bloodLower, + bloodLower + ); + + var labels2 = new Mat(); + var stats2 = new Mat(); + var centroids2 = new Mat(); + + int numLabels2 = Cv2.ConnectedComponentsWithStats(mask2, labels2, stats2, centroids2, + connectivity: PixelConnectivity.Connectivity4, ltype: MatType.CV_32S); + + logger.LogInformation("盾奶位 {guardianAvatar.Name} 战技状态:{text}", guardianAvatar.Name , numLabels2 > 1 ? "已释放" : "未释放"); + + if (numLabels2 > 1) + { + return true; + } + + attempt++; + await Task.Delay(100, ct); + } + } + guardianAvatar.AfterUseSkill(); + return false; + } + } + } diff --git a/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs b/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs index d24006ce..bbb0581f 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs @@ -13,6 +13,7 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using BetterGenshinImpact.Core.Config; using static BetterGenshinImpact.GameTask.Common.TaskControl; using BetterGenshinImpact.GameTask.Common.Job; using OpenCvSharp; @@ -38,6 +39,7 @@ public class AutoFightTask : ISoloTask private readonly double _dpi = TaskContext.Instance().DpiScale; + public static OtherConfig Config { get; set; } = TaskContext.Instance().Config.OtherConfig; private class TaskFightFinishDetectConfig { @@ -203,13 +205,12 @@ public class AutoFightTask : ISoloTask { return combatScenes; } - + if (attempt < maxRetries) { Thread.Sleep(retryDelayMs); // 可选:延迟再试 } } - throw new Exception("识别队伍角色失败(已重试 5 次)"); } // 方法1:判断是否是单个数字 @@ -276,6 +277,11 @@ public class AutoFightTask : ISoloTask //所有角色是否都可被跳过 var allCanBeSkipped = commandAvatarNames.All(a => canBeSkippedAvatarNames.Contains(a)); + //盾奶优先功能角色预处理 + var guardianAvatar = string.IsNullOrWhiteSpace(_taskParam.GuardianAvatar) ? null : combatScenes.SelectAvatar(int.Parse(_taskParam.GuardianAvatar)); + + AutoFightSeek.RotationCount= 0; // 重置旋转次数 + // 战斗操作 var fightTask = Task.Run(async () => { @@ -304,18 +310,25 @@ public class AutoFightTask : ISoloTask var skipFightName = ""; #endregion - + for (var i = 0; i < combatCommands.Count; i++) { var command = combatCommands[i]; - + var lastCommand = i == 0 ? command : combatCommands[i - 1]; + + #region 盾奶位技能优先功能 + + var skipModel = _taskParam.SkipModel? (guardianAvatar != null) : (guardianAvatar != null && lastFightName != command.Name); + if (skipModel) await AutoFightSkill.EnsureGuardianSkill(guardianAvatar,lastCommand,lastFightName,_taskParam.GuardianAvatar,_taskParam.GuardianAvatarHold,5,ct); var avatar = combatScenes.SelectAvatar(command.Name); - if (avatar is null) + + #endregion + + if (avatar is null || (avatar.Name == guardianAvatar?.Name && _taskParam.GuardianCombatSkip)) { continue; } - #region 每个命令的跳过战斗判定 // 判断是否满足跳过条件: @@ -362,9 +375,9 @@ public class AutoFightTask : ISoloTask #endregion - if (timeoutStopwatch.Elapsed > fightTimeout) + if (timeoutStopwatch.Elapsed > fightTimeout || AutoFightSeek.RotationCount >= 6) { - Logger.LogInformation("战斗超时结束"); + Logger.LogInformation(AutoFightSeek.RotationCount >= 6 ? "旋转次数达到上限,战斗结束" : "战斗超时结束"); fightEndFlag = true; timeOutFlag = true; break; @@ -544,14 +557,17 @@ public class AutoFightTask : ISoloTask bool? result = null; try { - result = await AutoFightSeek.SeekAndFightAsync(Logger, detectDelayTime,delayTime, _ct); + result = await AutoFightSeek.SeekAndFightAsync(Logger, detectDelayTime, delayTime, _ct); } catch (Exception ex) { Logger.LogError(ex, "SeekAndFightAsync 方法发生异常"); result = false; } - + + AutoFightSeek.RotationCount = (result == null) ? + AutoFightSeek.RotationCount + 1 : 0; + if (result != null) { return result.Value; diff --git a/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml b/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml index cbb1ad05..a0fdf3b0 100644 --- a/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml +++ b/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml @@ -10,6 +10,7 @@ xmlns:pages="clr-namespace:BetterGenshinImpact.ViewModel.Pages" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf" + xmlns:sys="clr-namespace:System;assembly=mscorlib" Title="TaskSettingsPage" d:DataContext="{d:DesignInstance Type=pages:TaskSettingsPageViewModel}" d:DesignHeight="1300" @@ -590,7 +591,7 @@ Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" - Text="(建议配合开启“更快检测结束战斗”使用) 在打开队伍界面检测战斗结束前,会先检测画面中如果存在敌人,再判断是否需要移动靠近敌人,并跳过检测战斗结束,如果画面内没有敌人,则进行旋转寻找敌人。" + Text="(建议设1秒左右“更快检测结束战斗”配合使用) 在打开队伍界面检测战斗结束前,会先检测画面中如果存在敌人,再判断是否需要移动靠近敌人,并跳过检测战斗结束,如果画面内没有敌人,则进行旋转寻找敌人。" TextWrapping="Wrap" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml b/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml index 54177c5b..be3c980e 100644 --- a/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml +++ b/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml @@ -839,6 +839,7 @@ + @@ -968,7 +969,7 @@ HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}" - Text="(建议配合开启“更快检测结束战斗”使用) 在打开队伍界面检测战斗结束前,会先检测画面中如果存在敌人,再判断是否需要移动靠近敌人,并跳过检测战斗结束,如果画面内没有敌人,则进行旋转寻找敌人。" + Text="(建议设1秒左右“更快检测结束战斗”配合使用) 在打开队伍界面检测战斗结束前,会先检测画面中如果存在敌人,再判断是否需要移动靠近敌人,并跳过检测战斗结束,如果画面内没有敌人,则进行旋转寻找敌人。" TextWrapping="Wrap" /> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +