diff --git a/BetterGenshinImpact/GameTask/AutoFight/AutoFightConfig.cs b/BetterGenshinImpact/GameTask/AutoFight/AutoFightConfig.cs
index 127425f3..815e7fb4 100644
--- a/BetterGenshinImpact/GameTask/AutoFight/AutoFightConfig.cs
+++ b/BetterGenshinImpact/GameTask/AutoFight/AutoFightConfig.cs
@@ -60,6 +60,12 @@ public partial class AutoFightConfig : ObservableObject
[ObservableProperty]
private bool _fastCheckEnabled = false;
+ ///
+ /// 旋转寻找敌人位置
+ ///
+ [ObservableProperty]
+ private bool _rotateFindEnemyEnabled = false;
+
///
/// 快速检查战斗结束的参数,可填入数字和人名,多种用分号分隔,例如:15,白术;钟离;,如果是数字(小于等于0则不会根据时间去检查),则指定检查间隔,如果是人名,则该角色执行一轮操作后进行检查。同时每轮结束后检查不变。
///
diff --git a/BetterGenshinImpact/GameTask/AutoFight/AutoFightParam.cs b/BetterGenshinImpact/GameTask/AutoFight/AutoFightParam.cs
index 5a5fb090..6ee6ad0e 100644
--- a/BetterGenshinImpact/GameTask/AutoFight/AutoFightParam.cs
+++ b/BetterGenshinImpact/GameTask/AutoFight/AutoFightParam.cs
@@ -18,6 +18,7 @@ public class AutoFightParam : BaseTaskParam
public string FastCheckParams = "";
public string CheckEndDelay = "";
public string BeforeDetectDelay = "";
+ public bool RotateFindEnemyEnabled = false;
}
public AutoFightParam(string path, AutoFightConfig autoFightConfig)
@@ -34,12 +35,17 @@ public class AutoFightParam : BaseTaskParam
FinishDetectConfig.FastCheckParams = autoFightConfig.FinishDetectConfig.FastCheckParams;
FinishDetectConfig.CheckEndDelay = autoFightConfig.FinishDetectConfig.CheckEndDelay;
FinishDetectConfig.BeforeDetectDelay = autoFightConfig.FinishDetectConfig.BeforeDetectDelay;
+ FinishDetectConfig.RotateFindEnemyEnabled = autoFightConfig.FinishDetectConfig.RotateFindEnemyEnabled;
+
+
KazuhaPartyName = autoFightConfig.KazuhaPartyName;
OnlyPickEliteDropsMode = autoFightConfig.OnlyPickEliteDropsMode;
BattleThresholdForLoot = autoFightConfig.BattleThresholdForLoot ?? BattleThresholdForLoot;
//下面参数固定,只取自动战斗里面的
FinishDetectConfig.BattleEndProgressBarColor = TaskContext.Instance().Config.AutoFightConfig.FinishDetectConfig.BattleEndProgressBarColor;
FinishDetectConfig.BattleEndProgressBarColorTolerance = TaskContext.Instance().Config.AutoFightConfig.FinishDetectConfig.BattleEndProgressBarColorTolerance;
+
+
}
public FightFinishDetectConfig FinishDetectConfig { get; set; } = new();
@@ -57,5 +63,4 @@ public class AutoFightParam : BaseTaskParam
public string KazuhaPartyName;
public string OnlyPickEliteDropsMode="";
-
}
\ No newline at end of file
diff --git a/BetterGenshinImpact/GameTask/AutoFight/AutoFightSeek.cs b/BetterGenshinImpact/GameTask/AutoFight/AutoFightSeek.cs
new file mode 100644
index 00000000..b7401e92
--- /dev/null
+++ b/BetterGenshinImpact/GameTask/AutoFight/AutoFightSeek.cs
@@ -0,0 +1,365 @@
+using BetterGenshinImpact.Core.Simulator;
+using BetterGenshinImpact.Core.Simulator.Extensions;
+using Microsoft.Extensions.Logging;
+using System.Threading;
+using System.Threading.Tasks;
+using static BetterGenshinImpact.GameTask.Common.TaskControl;
+using OpenCvSharp;
+using BetterGenshinImpact.Core.Recognition.OpenCv;
+
+namespace BetterGenshinImpact.GameTask.AutoFight
+{
+ public static class MoveForwardTask
+ {
+
+ public static async Task ExecuteAsync(Scalar scalarLower, Scalar scalarHigher, ILogger logger, CancellationToken ct)
+ {
+ await MoveForwardAsync(scalarLower, scalarHigher, logger, ct);
+ }
+
+ public static Task MoveForwardAsync(Scalar scalarLower, Scalar scalarHigher, ILogger logger, CancellationToken ct)
+ {
+ var image2 = CaptureToRectArea();
+ Mat mask2 = OpenCvCommonHelper.Threshold(
+ image2.DeriveCrop(0, 0, image2.Width * 1570 / 1920, image2.Height * 970 / 1080).SrcMat,
+ scalarLower,
+ scalarHigher
+ );
+
+ Mat labels2 = new Mat();
+ Mat stats2 = new Mat();
+ Mat centroids2 = new Mat();
+
+ int numLabels2 = Cv2.ConnectedComponentsWithStats(mask2, labels2, stats2, centroids2, connectivity: PixelConnectivity.Connectivity4, ltype: MatType.CV_32S);
+
+ logger.LogInformation($"检测数量J: {numLabels2 - 1}");
+
+ if (numLabels2 > 1)
+ {
+ // 获取第一个连通对象的统计信息(标签1)
+ Mat firstRow = stats2.Row(1); // 获取第1行(标签1)的数据
+ int[] stats;
+ bool success = firstRow.GetArray(out stats); // 使用 out 参数来接收数组数据
+
+ if (success)
+ {
+ int x = stats[0];
+ int y = stats[1];
+ // int width = stats[2];
+ int height = stats[3];
+
+ Point firstPixel = new Point(x, y);
+ logger.LogInformation($"找到的连通对象的第一个像素坐标: ({firstPixel.X}, {firstPixel.Y}),连通对象的高度: {height}");
+
+ if (firstPixel.X < 500 || firstPixel.X > 1200 || firstPixel.Y < 300 || firstPixel.Y > 920)
+ {
+ // 非中心区域的处理逻辑
+ if (firstPixel.X < 500 && firstPixel.Y < 300)
+ {
+ // 左上区域
+ if (height <= 6)
+ {
+ logger.LogInformation("敌人在左上,向前加向左移动");
+ Task.Run(() =>
+ {
+ Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown);
+ Simulation.SendInput.SimulateAction(GIActions.MoveLeft, KeyType.KeyDown);
+ Task.Delay(1000, ct).Wait();
+ Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp);
+ Simulation.SendInput.SimulateAction(GIActions.MoveLeft, KeyType.KeyUp);
+ }, ct);
+ }
+ }
+ else if (firstPixel.X > 1200 && firstPixel.Y < 300)
+ {
+ // 右上区域
+ if (height <= 6)
+ {
+ logger.LogInformation("敌人在右上,向前加向右移动");
+ Task.Run(() =>
+ {
+ Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown);
+ Simulation.SendInput.SimulateAction(GIActions.MoveRight, KeyType.KeyDown);
+ Task.Delay(1000, ct).Wait();
+ Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp);
+ Simulation.SendInput.SimulateAction(GIActions.MoveRight, KeyType.KeyUp);
+ }, ct);
+ }
+ }
+ else if (firstPixel.X < 500 && firstPixel.Y > 920)
+ {
+ // 左下区域
+ if (height <= 6)
+ {
+ logger.LogInformation("敌人在左下,向后加向左移动");
+ Task.Run(() =>
+ {
+ Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyDown);
+ Simulation.SendInput.SimulateAction(GIActions.MoveLeft, KeyType.KeyDown);
+ Task.Delay(1000, ct).Wait();
+ Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyUp);
+ Simulation.SendInput.SimulateAction(GIActions.MoveLeft, KeyType.KeyUp);
+ }, ct);
+ }
+ }
+ else if (firstPixel.X > 1200 && firstPixel.Y > 920)
+ {
+ // 右下区域
+ if (height <= 6)
+ {
+ logger.LogInformation("敌人在右下,向后加向右移动");
+ Task.Run(() =>
+ {
+ Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyDown);
+ Simulation.SendInput.SimulateAction(GIActions.MoveRight, KeyType.KeyDown);
+ Task.Delay(1000, ct).Wait();
+ Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyUp);
+ Simulation.SendInput.SimulateAction(GIActions.MoveRight, KeyType.KeyUp);
+ }, ct);
+ }
+ }
+ else if (firstPixel.Y < 300)
+ {
+ // 上方区域
+ if (height <= 6)
+ {
+ logger.LogInformation("敌人在上方,向前移动");
+ Task.Run(() =>
+ {
+ Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown);
+ Task.Delay(1000, ct).Wait();
+ Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp);
+ }, ct);
+ }
+ }
+ else if (firstPixel.Y > 920)
+ {
+ // 下方区域
+ if (height <= 6)
+ {
+ logger.LogInformation("敌人在下方,向后移动");
+ Task.Run(() =>
+ {
+ Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyDown);
+ Task.Delay(1000, ct).Wait();
+ Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyUp);
+ }, ct);
+ }
+ }
+ else
+ {
+ // 非上述区域且非中心区域,判断左右
+ if (firstPixel.X < 920 && height > 6)
+ {
+ logger.LogInformation("敌人在左侧,不移动");
+ }
+ else if (firstPixel.X > 920 && height > 6)
+ {
+ logger.LogInformation("敌人在右侧,不移动");
+ }
+ }
+ }
+ else // 中心区域
+ {
+ if (height > 6)
+ {
+ logger.LogInformation("敌人在中心且高度大于6,不移动");
+ }
+ else if (firstPixel.Y < 300)
+ {
+ logger.LogInformation("敌人在上方,向前移动");
+ Task.Run(() =>
+ {
+ Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown);
+ Task.Delay(1000, ct).Wait();
+ Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp);
+ }, ct);
+ }
+ else if (firstPixel.Y > 920)
+ {
+ logger.LogInformation("敌人在下方,向后移动");
+ Task.Run(() =>
+ {
+ Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyDown);
+ Task.Delay(1000, ct).Wait();
+ Simulation.SendInput.SimulateAction(GIActions.MoveBackward, KeyType.KeyUp);
+ }, ct);
+ }
+ else
+ {
+ logger.LogInformation("敌人在中心,不移动");
+ }
+ }
+ }
+ else
+ {
+ logger.LogError("无法获取统计信息数组");
+ }
+ }
+
+ mask2.Dispose();
+ labels2.Dispose();
+ return Task.FromResult(null);
+ }
+ }
+
+ public class AutoFightSeek
+ {
+ public static async Task SeekAndFightAsync(ILogger logger, int detectDelayTime, CancellationToken ct)
+ {
+ Scalar bloodLower = new Scalar(255, 90, 90);
+ int retryCount = 0;
+
+ while (retryCount < 10)
+ {
+ var image = CaptureToRectArea();
+ Mat mask = OpenCvCommonHelper.Threshold(image.DeriveCrop(0, 0, 1500, 900).SrcMat, bloodLower);
+ Mat labels = new Mat();
+ Mat stats = new Mat();
+ Mat centroids = new Mat();
+
+ int numLabels = Cv2.ConnectedComponentsWithStats(mask, labels, stats, centroids,
+ connectivity: PixelConnectivity.Connectivity4, ltype: MatType.CV_32S);
+ logger.LogInformation($"检测数量首次: {numLabels - 1}");
+
+ if (numLabels > 1)
+ {
+ logger.LogInformation("首次检测画面内疑似有怪物,继续战斗...");
+ // 获取第一个连通对象的统计信息(标签1)
+ Mat firstRow = stats.Row(1); // 获取第1行(标签1)的数据
+ int[] statsArray;
+ bool success = firstRow.GetArray(out statsArray); // 使用 out 参数来接收数组数据
+ int height = statsArray[3];
+ logger.LogInformation($"敌人血量高度:{height}");
+
+ // //如果不用旋转判断敌人,直接跳过开队伍检测,加快战斗速度
+ // return height > 2;//大于2预防误判
+
+ if (success)
+ {
+
+
+ if (height < 7 && height > 2)
+ {
+ logger.LogInformation("敌人血量高度小于7且大于2,向前移动");
+ Task.Run(() =>
+ {
+ MoveForwardTask.MoveForwardAsync(bloodLower, bloodLower, logger, ct);
+ Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown);
+ Task.Delay(1000, ct).Wait();
+ Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp);
+ }, ct);
+ }
+
+ mask.Dispose();
+ labels.Dispose();
+ stats.Dispose();
+ centroids.Dispose();
+ return height > 2;
+ }
+ }
+ //如果不用旋转判断敌人,直接跳过开队伍检测,加快战斗速度
+ // else
+ // {
+ // logger.LogInformation("首次检测画面内没有怪物...");
+ // return true;
+ // }
+
+
+ mask.Dispose();
+ labels.Dispose();
+ stats.Dispose();
+ centroids.Dispose();
+
+ logger.LogInformation("画面内没有怪物,旋转寻找...");
+ if (retryCount <= 1)
+ {
+ Simulation.SendInput.Mouse.MoveMouseBy(image.Width / 2, -image.Height / 3);
+ }
+ else
+ {
+ Simulation.SendInput.Mouse.MoveMouseBy(image.Width / 2, 0);
+ }
+
+ await Task.Delay(300,ct);
+
+ image = CaptureToRectArea();
+ mask = OpenCvCommonHelper.Threshold(image.DeriveCrop(0, 0, 1500, 900).SrcMat, bloodLower);
+ labels = new Mat();
+ stats = new Mat();
+ centroids = new Mat();
+
+ numLabels = Cv2.ConnectedComponentsWithStats(mask, labels, stats, centroids,
+ connectivity: PixelConnectivity.Connectivity4, ltype: MatType.CV_32S);
+ logger.LogInformation($"检测数量第 {retryCount + 1} 次: {numLabels - 1}");
+
+ if (numLabels > 1)
+ {
+ Mat firstRow2 = stats.Row(1); // 获取第1行(标签1)的数据
+ int[] statsArray2;
+ bool success2 = firstRow2.GetArray(out statsArray2); // 使用 out 参数来接收数组数据
+ int height2 = statsArray2[3];
+
+ if (success2)
+ {
+
+ logger.LogInformation($"敌人血量高度:{height2}");
+ if (height2 < 7 && height2 > 2)
+ {
+ logger.LogInformation("画面内有找到怪物,继续战斗...");
+ Task.Run(() => { MoveForwardTask.MoveForwardAsync(bloodLower, bloodLower, logger, ct); }, ct);
+ }
+ mask.Dispose();
+ labels.Dispose();
+ stats.Dispose();
+ centroids.Dispose();
+ return height2 > 2;
+ }
+
+ }
+
+ if (retryCount == 0)
+ {
+ Simulation.SendInput.SimulateAction(GIActions.OpenPartySetupScreen);
+ await Delay(detectDelayTime, ct);
+ var ra3 = CaptureToRectArea();
+ 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))
+ {
+ logger.LogInformation("识别到战斗结束");
+ Simulation.SendInput.SimulateAction(GIActions.OpenPartySetupScreen);
+ return true;
+ }
+ }
+
+ logger.LogInformation("画面内没有怪物,尝试重新检测...");
+ retryCount++;
+ }
+
+ return false;
+ }
+
+ private static bool IsYellow(int r, int g, int b)
+ {
+ //Logger.LogInformation($"IsYellow({r},{g},{b})");
+ // 黄色范围:R高,G高,B低
+ return (r >= 200 && r <= 255) &&
+ (g >= 200 && g <= 255) &&
+ (b >= 0 && b <= 100);
+ }
+
+ private static bool IsWhite(int r, int g, int b)
+ {
+ //Logger.LogInformation($"IsWhite({r},{g},{b})");
+ // 白色范围:R高,G高,B低
+ return (r >= 240 && r <= 255) &&
+ (g >= 240 && g <= 255) &&
+ (b >= 240 && b <= 255);
+ }
+ }
+
+}
diff --git a/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs b/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs
index e5426383..ad03c911 100644
--- a/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs
+++ b/BetterGenshinImpact/GameTask/AutoFight/AutoFightTask.cs
@@ -18,10 +18,8 @@ using BetterGenshinImpact.GameTask.Common.Job;
using OpenCvSharp;
using BetterGenshinImpact.Helpers;
using Vanara;
-using Vanara.PInvoke;
using Microsoft.Extensions.DependencyInjection;
-
namespace BetterGenshinImpact.GameTask.AutoFight;
public class AutoFightTask : ISoloTask
@@ -49,6 +47,7 @@ public class AutoFightTask : ISoloTask
public double CheckTime = 5;
public List CheckNames = new();
public bool FastCheckEnabled;
+ public bool RotateFindEnemyEnabled = false;
public TaskFightFinishDetectConfig(AutoFightParam.FightFinishDetectConfig finishDetectConfig)
{
@@ -61,6 +60,7 @@ public class AutoFightTask : ISoloTask
ParseSingleOrCommaSeparated(finishDetectConfig.BattleEndProgressBarColorTolerance, (6, 6, 6));
DetectDelayTime =
(int)((double.TryParse(finishDetectConfig.BeforeDetectDelay, out var result) ? result : 0.45) * 1000);
+ RotateFindEnemyEnabled = finishDetectConfig.RotateFindEnemyEnabled;
}
public (int, int, int) BattleEndProgressBarColor { get; }
@@ -369,8 +369,7 @@ public class AutoFightTask : ISoloTask
timeOutFlag = true;
break;
}
-
- // 通用化战斗策略
+
command.Execute(combatScenes);
//统计战斗人次
if (i == combatCommands.Count - 1 || command.Name != combatCommands[i + 1].Name)
@@ -401,13 +400,9 @@ public class AutoFightTask : ISoloTask
}
else
{
- Logger.LogInformation($"延时检查为{delayTime}毫秒");
+ // Logger.LogInformation($"延时检查为{delayTime}毫秒");
}
-
- /*if (i CheckFightFinish(int delayTime = 1500, int detectDelayTime = 450)
+ public async Task CheckFightFinish(int delayTime = 1500, int detectDelayTime = 450)
{
- // YOLO 判断血条和怪物位置
- // if (HasFightFlagByYolo(CaptureToRectArea()))
- // {
- // _lastFightFlagTime = DateTime.Now;
- // return false;
- // }
- //
-
- //Random random = new Random();
- //double randomFraction = random.NextDouble(); // 生成 0 到 1 之间的随机小数
- //此处随机数,防止固定招式下,使按L正好处于招式下,导致无法准确判断战斗结束
- // double randomNumber = 1 + (randomFraction * (3 - 1));
-
- // 几秒内没有检测到血条和怪物位置,则开始旋转视角重新检测
- //if ((DateTime.Now - _lastFightFlagTime).TotalSeconds > randomNumber)
- //{
- // 旋转完毕后都没有检测到血条和怪物位置,则按L键确认战斗结束
- /**
- Simulation.SendInput.Mouse.MiddleButtonClick();
- await Delay(300, _ct);
- for (var i = 0; i < 8; i++)
+ if (_finishDetectConfig.RotateFindEnemyEnabled)
{
- Simulation.SendInput.Mouse.MoveMouseBy((int)(500 * _dpi), 0);
- await Delay(800, _ct); // 等待视角稳定
- if (HasFightFlagByYolo(CaptureToRectArea()))
+ bool? result = null;
+ try
{
- _lastFightFlagTime = DateTime.Now;
- return false;
+ result = await AutoFightSeek.SeekAndFightAsync(Logger, detectDelayTime, _ct);
}
+ catch (Exception ex)
+ {
+ Logger.LogError(ex, "SeekAndFightAsync 方法发生异常");
+ result = false;
+ }
+
+ if (result == true)
+ {
+ return true;
+ }
+
+ return false;
}
- **/
- //Simulation.SendInput.SimulateAction(GIActions.Drop);//在换队前取消爬墙状态
- await Delay(delayTime, _ct);
+
+ if (!_finishDetectConfig.RotateFindEnemyEnabled)await Delay(delayTime, _ct);
+
Logger.LogInformation("打开编队界面检查战斗是否结束,延时{detectDelayTime}毫秒检查", detectDelayTime);
// 最终方案确认战斗结束
Simulation.SendInput.SimulateAction(GIActions.OpenPartySetupScreen);
await Delay(detectDelayTime, _ct);
+
var ra = CaptureToRectArea();
+ //判断整个界面是否有红色色块,如果有,则战继续,否则战斗结束
+ // 只提取橙色
+
var b3 = ra.SrcMat.At(50, 790); //进度条颜色
var whiteTile = ra.SrcMat.At(50, 768); //白块
Simulation.SendInput.SimulateAction(GIActions.Drop);
@@ -600,14 +589,14 @@ public class AutoFightTask : ISoloTask
Logger.LogInformation($"未识别到战斗结束yellow{b3.Item0},{b3.Item1},{b3.Item2}");
Logger.LogInformation($"未识别到战斗结束white{whiteTile.Item0},{whiteTile.Item1},{whiteTile.Item2}");
- /**
- if (!Bv.IsInMainUi(ra))
+
+ Task.Run(() =>
{
- // 如果不在主界面,说明异常,直接结束战斗继续下一步(地图追踪下一步会进入异常处理)
- Logger.LogInformation("当前不在主界面,直接结束战斗!");
- return true;
- }**/
-
+ Scalar bloodLower = new Scalar(255, 90, 90);
+ MoveForwardTask.MoveForwardAsync(bloodLower, bloodLower, Logger, _ct);
+ } ,_ct);
+
+
_lastFightFlagTime = DateTime.Now;
return false;
}
diff --git a/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml b/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml
index 92fd4862..76b9ac57 100644
--- a/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml
+++ b/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml
@@ -569,7 +569,34 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml b/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml
index f395f6d5..54177c5b 100644
--- a/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml
+++ b/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml
@@ -947,8 +947,36 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+