Skip to content

Commit 7a41056

Browse files
authored
适配 5.7 秘境领取奖励 (#1725)
* Improve error message for update failure in ScriptRepoWindow * 临时提交 * 完成浓缩树脂、原粹树脂的使用兼容
1 parent 32f7445 commit 7a41056

File tree

7 files changed

+189
-60
lines changed

7 files changed

+189
-60
lines changed

BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs

Lines changed: 80 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
using BetterGenshinImpact.GameTask.AutoArtifactSalvage;
4040
using System.Collections.ObjectModel;
4141
using BetterGenshinImpact.Core.Script.Dependence;
42+
using BetterGenshinImpact.GameTask.AutoDomain.Model;
43+
using BetterGenshinImpact.GameTask.Common;
4244
using Compunet.YoloSharp;
4345
using Microsoft.Extensions.DependencyInjection;
4446

@@ -182,7 +184,7 @@ private async Task DoDomain()
182184

183185
// 5. 快速领取奖励并判断是否有下一轮
184186
Logger.LogInformation("自动秘境:{Text}", "5. 领取奖励");
185-
if (!GettingTreasure(_taskParam.DomainRoundNum == 9999, i == _taskParam.DomainRoundNum - 1))
187+
if (!await GettingTreasure(i == _taskParam.DomainRoundNum - 1))
186188
{
187189
if (i == _taskParam.DomainRoundNum - 1)
188190
{
@@ -997,7 +999,7 @@ private Task LockCameraToEastTask(CancellationTokenSource cts, Task moveAvatarTa
997999
Simulation.SendInput.Mouse.MoveMouseBy(moveAngle, 0);
9981000
}
9991001

1000-
Sleep(100);
1002+
Sleep(100, _ct);
10011003
}
10021004

10031005
Logger.LogInformation("锁定东方向视角线程结束");
@@ -1008,64 +1010,51 @@ private Task LockCameraToEastTask(CancellationTokenSource cts, Task moveAvatarTa
10081010
/// <summary>
10091011
/// 领取奖励
10101012
/// </summary>
1011-
/// <param name="recognizeResin">是否识别树脂</param>
10121013
/// <param name="isLastTurn">是否最后一轮</param>
1013-
private bool GettingTreasure(bool recognizeResin, bool isLastTurn)
1014+
private async Task<bool> GettingTreasure(bool isLastTurn)
10141015
{
10151016
// 等待窗口弹出
1016-
Sleep(1500, _ct);
1017+
await Delay(300, _ct);
10171018

1018-
// 优先使用浓缩树脂
1019-
var retryTimes = 0;
1020-
while (true)
1019+
// OCR 弹出框
1020+
bool chooseResinPrompt = await NewRetry.WaitForAction(() =>
10211021
{
1022-
retryTimes++;
1023-
if (retryTimes > 3)
1024-
{
1025-
Logger.LogInformation("没有浓缩树脂了");
1026-
break;
1027-
}
1022+
using var ra = CaptureToRectArea();
1023+
var regionList = ra.FindMulti(RecognitionObject.Ocr(ra.Width * 0.25, ra.Height * 0.2, ra.Width * 0.5, ra.Height * 0.6));
1024+
return regionList.Any(t => t.Text.Contains("石化古树"));
1025+
}, _ct, 10, 500);
1026+
Debug.WriteLine("识别到选择树脂页");
10281027

1029-
var useCondensedResinRa = CaptureToRectArea().Find(AutoFightAssets.Instance.UseCondensedResinRa);
1030-
if (!useCondensedResinRa.IsEmpty())
1031-
{
1032-
useCondensedResinRa.Click();
1033-
// 点两下 #224 #218
1034-
// 解决水龙王按下左键后没松开,然后后续点击按下就没反应了
1035-
Sleep(400, _ct);
1036-
useCondensedResinRa.Click();
1037-
break;
1038-
}
1028+
if (!chooseResinPrompt)
1029+
{
1030+
throw new NormalEndException("未检测到选取树脂界面,可能是背包物品已满。");
1031+
}
1032+
1033+
1034+
await Delay(800, _ct);
1035+
// 弹出框
1036+
using var ra2 = CaptureToRectArea();
1037+
// 识别树脂状况
1038+
var resinStatus = ResinStatus.RecogniseFromRegion(ra2);
1039+
resinStatus.Print(Logger);
10391040

1040-
Sleep(800, _ct);
1041+
if (resinStatus.CondensedResinCount > 0)
1042+
{
1043+
PressUseResin(ra2, "浓缩树脂");
1044+
resinStatus.CondensedResinCount -= 1;
1045+
}
1046+
else if (resinStatus.OriginalResinCount >= 20)
1047+
{
1048+
PressUseResin(ra2, "原粹树脂");
1049+
resinStatus.OriginalResinCount -= 20;
10411050
}
10421051

1052+
10431053
Sleep(1000, _ct);
10441054

1045-
var hasSkip = false;
1046-
var captureArea = TaskContext.Instance().SystemInfo.ScaleMax1080PCaptureRect;
1047-
var assetScale = TaskContext.Instance().SystemInfo.AssetScale;
10481055
for (var i = 0; i < 30; i++)
10491056
{
1050-
// 跳过领取动画
1051-
if (!hasSkip)
1052-
{
1053-
TaskContext.Instance().PostMessageSimulator.LeftButtonClick(); // 先随便点一个地方使得跳过出现
1054-
}
1055-
10561057
using var ra = CaptureToRectArea();
1057-
1058-
// OCR识别是否有跳过
1059-
var ocrList = ra.FindMulti(RecognitionObject.Ocr(captureArea.Width - 230 * assetScale, 0,
1060-
230 * assetScale - 5, 80 * assetScale));
1061-
var skipTextRa = ocrList.FirstOrDefault(t => Regex.IsMatch(t.Text, this.skipLocalizedString));
1062-
if (skipTextRa != null)
1063-
{
1064-
hasSkip = true;
1065-
skipTextRa.Click(); // 有则点击
1066-
}
1067-
1068-
10691058
// 优先点击继续
10701059
using var confirmRectArea = ra.Find(AutoFightAssets.Instance.ConfirmRa);
10711060
if (!confirmRectArea.IsEmpty())
@@ -1081,14 +1070,7 @@ private bool GettingTreasure(bool recognizeResin, bool isLastTurn)
10811070
}
10821071
}
10831072

1084-
if (!recognizeResin)
1085-
{
1086-
confirmRectArea.Click();
1087-
return true;
1088-
}
1089-
1090-
var (condensedResinCount, fragileResinCount) = GetRemainResinStatus();
1091-
if (condensedResinCount == 0 && fragileResinCount < 20)
1073+
if (resinStatus.CondensedResinCount <= 0 && resinStatus.OriginalResinCount < 20)
10921074
{
10931075
// 没有体力了退出
10941076
var exitRectArea = ra.Find(AutoFightAssets.Instance.ExitRa);
@@ -1112,6 +1094,50 @@ private bool GettingTreasure(bool recognizeResin, bool isLastTurn)
11121094
throw new NormalEndException("未检测到秘境结束,可能是背包物品已满。");
11131095
}
11141096

1097+
private void PressUseResin(ImageRegion ra, string resinName)
1098+
{
1099+
var regionList = ra.FindMulti(RecognitionObject.Ocr(ra.Width * 0.25, ra.Height * 0.2, ra.Width * 0.5, ra.Height * 0.6));
1100+
var resinKey = regionList.FirstOrDefault(t => t.Text.Contains(resinName));
1101+
if (resinKey != null)
1102+
{
1103+
// 找到树脂名称对应的按键,关键词为使用,是同一行的(高度相交)
1104+
var useList = regionList.Where(t => t.Text.Contains("使用")).ToList();
1105+
if (useList.Count != 0)
1106+
{
1107+
// 找到使用按键
1108+
var useKey = useList.FirstOrDefault(t => t.X > ra.Width / 2 && IsHeightOverlap(t, resinKey));
1109+
if (useKey != null)
1110+
{
1111+
// 点击使用
1112+
useKey.Click();
1113+
Logger.LogInformation("自动秘境:使用 {ResinName}", resinName);
1114+
}
1115+
else
1116+
{
1117+
Logger.LogWarning("自动秘境:未找到 {ResinName} 的使用按键", resinName);
1118+
}
1119+
}
1120+
else
1121+
{
1122+
Logger.LogWarning("自动秘境:未找到 {ResinName} 的使用按键", resinName);
1123+
}
1124+
}
1125+
}
1126+
1127+
/// <summary>
1128+
/// 判断两个区域在垂直方向上是否有重叠
1129+
/// </summary>
1130+
private bool IsHeightOverlap(Region region1, Region region2)
1131+
{
1132+
int region1Top = region1.Y;
1133+
int region1Bottom = region1.Y + region1.Height;
1134+
int region2Top = region2.Y;
1135+
int region2Bottom = region2.Y + region2.Height;
1136+
1137+
// 检查区域是否在垂直方向上重叠
1138+
return (region1Top <= region2Bottom && region1Bottom >= region2Top);
1139+
}
1140+
11151141
/// <summary>
11161142
/// 获取剩余树脂状态
11171143
/// </summary>
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System;
2+
using BetterGenshinImpact.Core.Recognition.OCR;
3+
using BetterGenshinImpact.GameTask.AutoFight.Assets;
4+
using BetterGenshinImpact.GameTask.Model.Area;
5+
using BetterGenshinImpact.Helpers;
6+
using Microsoft.Extensions.Logging;
7+
using OpenCvSharp;
8+
9+
namespace BetterGenshinImpact.GameTask.AutoDomain.Model;
10+
11+
public class ResinStatus
12+
{
13+
/// <summary>
14+
/// 原粹树脂(1自回体)
15+
/// </summary>
16+
public int OriginalResinCount { get; set; } = 0;
17+
18+
/// <summary>
19+
/// 脆弱树脂(60)
20+
/// </summary>
21+
public int FragileResinCount { get; set; } = 0;
22+
23+
/// <summary>
24+
/// 浓缩树脂(40)
25+
/// </summary>
26+
public int CondensedResinCount { get; set; } = 0;
27+
28+
/// <summary>
29+
/// 须臾树脂(60壶内购买)
30+
/// </summary>
31+
public int TransientResinCount { get; set; } = 0;
32+
33+
public static ResinStatus RecogniseFromRegion(ImageRegion region)
34+
{
35+
var status = new ResinStatus();
36+
37+
// 1. 原粹树脂 起点 w-(256+100) ~ w-256
38+
var captureArea = TaskContext.Instance().SystemInfo.ScaleMax1080PCaptureRect;
39+
var assetScale = TaskContext.Instance().SystemInfo.AssetScale;
40+
var originalResinTopIconRa = AutoFightAssets.Instance.OriginalResinTopIconRa;
41+
originalResinTopIconRa.RegionOfInterest = new Rect(captureArea.Width - (int)(356 * assetScale), (int)(37 * assetScale), (int)(100 * assetScale), (int)(21 * assetScale));
42+
var originalResinRes = region.Find(originalResinTopIconRa);
43+
if (originalResinRes.IsEmpty())
44+
{
45+
throw new Exception("未找到原粹树脂图标");
46+
}
47+
48+
// 找出 icon 的位置 + 30 ~ w-267 就是原粹树脂的数字
49+
var originalResinCountRect = new Rect(originalResinRes.X + 30, originalResinTopIconRa.RegionOfInterest.Y,
50+
captureArea.Width - (originalResinRes.X + 30) - (int)(267 * assetScale), originalResinTopIconRa.RegionOfInterest.Height);
51+
string cnt1 = OcrFactory.Paddle.OcrWithoutDetector(region.DeriveCrop(originalResinCountRect).SrcMat);
52+
status.OriginalResinCount = StringUtils.TryExtractPositiveInt(cnt1, 0);
53+
54+
// 2. 浓缩树脂
55+
var condensedResinRes = region.Find(AutoFightAssets.Instance.CondensedResinTopIconRa);
56+
if (condensedResinRes.IsExist())
57+
{
58+
// 找出 icon 的位置 + 25 ~ icon 的位置+45 就是浓缩树脂的数字,数字宽20
59+
var condensedResinCountRect = new Rect(condensedResinRes.Right + (int)(25 * assetScale), condensedResinRes.Y, (int)(20 * assetScale), condensedResinRes.Height);
60+
string cnt40 = OcrFactory.Paddle.OcrWithoutDetector(region.DeriveCrop(condensedResinCountRect).SrcMat);
61+
status.CondensedResinCount = StringUtils.TryExtractPositiveInt(cnt40, 0);
62+
}
63+
64+
return status;
65+
}
66+
67+
public void Print(ILogger logger)
68+
{
69+
// logger.LogInformation("原粹树脂:{Cnt1},浓缩树脂:{Cnt2},须臾树脂:{Cnt3},脆弱树脂:{Cnt4}",
70+
// OriginalResinCount, CondensedResinCount, FragileResinCount, TransientResinCount);
71+
logger.LogInformation("原粹树脂:{Cnt1},浓缩树脂:{Cnt2}",
72+
OriginalResinCount, CondensedResinCount);
73+
}
74+
}
1.04 KB
Loading
456 Bytes
Loading

BetterGenshinImpact/GameTask/AutoFight/Assets/AutoFightAssets.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@ public class AutoFightAssets : BaseAssets<AutoFightAssets>
2626

2727
// 树脂状态
2828
public RecognitionObject CondensedResinCountRa;
29-
3029
public RecognitionObject FragileResinCountRa;
30+
// 自动秘境
31+
// public RecognitionObject LockIconRa; // 锁定辅助图标
32+
public RecognitionObject CondensedResinTopIconRa;
33+
public RecognitionObject OriginalResinTopIconRa;
3134

3235
public Dictionary<string, string> AvatarCostumeMap;
3336

@@ -245,5 +248,31 @@ private AutoFightAssets()
245248
RegionOfInterest = new Rect(CaptureRect.Width / 2, CaptureRect.Height / 3 * 2, CaptureRect.Width / 2, CaptureRect.Height / 3),
246249
DrawOnWindow = false
247250
}.InitTemplate();
251+
252+
// 自动秘境
253+
// LockIconRa = new RecognitionObject
254+
// {
255+
// Name = "LockIcon",
256+
// RecognitionType = RecognitionTypes.TemplateMatch,
257+
// TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "lock_icon.png"),
258+
// RegionOfInterest = new Rect(CaptureRect.Width - (int)(215 * AssetScale), 0, (int)(215 * AssetScale), (int)(80 * AssetScale)),
259+
// DrawOnWindow = false
260+
// }.InitTemplate();
261+
CondensedResinTopIconRa = new RecognitionObject
262+
{
263+
Name = "CondensedResinTopIcon",
264+
RecognitionType = RecognitionTypes.TemplateMatch,
265+
TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "condensed_resin_top_icon.png"),
266+
RegionOfInterest = new Rect((int)(1270 * AssetScale), (int)(25 * AssetScale), (int)(520 * AssetScale), (int)(45 * AssetScale)),
267+
DrawOnWindow = false
268+
}.InitTemplate();
269+
OriginalResinTopIconRa = new RecognitionObject
270+
{
271+
Name = "OriginalResinTopIcon",
272+
RecognitionType = RecognitionTypes.TemplateMatch,
273+
TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "original_resin_top_icon.png"),
274+
RegionOfInterest = new Rect(0, (int)(37 * AssetScale), CaptureRect.Width, (int)(21 * AssetScale)),
275+
DrawOnWindow = false
276+
}.InitTemplate();
248277
}
249278
}

BetterGenshinImpact/Helpers/StringUtils.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,21 +88,21 @@ public static int TryParseInt(string text, int defaultValue)
8888
return int.TryParse(text, out int result) ? result : defaultValue;
8989
}
9090

91-
public static int TryExtractPositiveInt(string text)
91+
public static int TryExtractPositiveInt(string text, int defaultValue = -1)
9292
{
9393
if (string.IsNullOrEmpty(text))
9494
{
95-
return -1;
95+
return defaultValue;
9696
}
9797

9898
try
9999
{
100100
text = RegexHelper.ExcludeNumberRegex().Replace(text, "");
101-
return int.Parse(text);
101+
return TryParseInt(text, defaultValue);
102102
}
103103
catch
104104
{
105-
return -1;
105+
return defaultValue;
106106
}
107107
}
108108

BetterGenshinImpact/View/Windows/ScriptRepoWindow.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ private async Task UpdateRepo()
8181
}
8282
catch (Exception ex)
8383
{
84-
Toast.Error($"更新失败: {ex.Message}");
84+
Toast.Error($"更新失败,可尝试重置仓库后重新更新。失败原因:: {ex.Message}");
8585
}
8686
}
8787

0 commit comments

Comments
 (0)