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" />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+