add GoToAdventurersGuildTask

优化项目结构并新增任务和路径文件

主要更改:
- 在 `BetterGenshinImpact.csproj` 文件中,添加了对 `GameTask\Common\Element\Assets\Json\**` 目录的处理,并确保其内容始终复制到输出目录。
- 在 `RecognitionObject.cs` 文件中,新增了多个静态方法 `Ocr` 和一个静态实例 `OcrThis`。
- 在 `PathExecutor.cs` 文件中,优化了路径执行逻辑,新增 `GetPosition` 方法,并调整了超时判断。
- 在 `AutoPickAssets.cs` 文件中,添加了多个 `using` 语句,新增 `_logger` 和 `PickRo` 字段,并在构造函数中添加了自定义拾取按键的处理逻辑。
- 在 `AutoPickTrigger.cs` 文件中,移除了自定义拾取按键的初始化逻辑。
- 在 `OneKeyExpeditionTask.cs` 文件中,注释掉了 `Cv2.ImWrite` 方法的调用。
- 在 `TpTask.cs` 文件中,添加了点位很近时不切换的判断逻辑。
- 在 `BvSimpleOperation.cs` 文件中,新增了多个点击按钮的方法和 `FindF`、`FindFAndPress` 方法。
- 在 `BvStatus.cs` 文件中,新增了多个方法用于判断是否在对话界面并等待对话界面加载完成。
- 在 `GameTaskManager.cs` 文件中,添加了 `MapAssets.DestroyInstance` 方法的调用。
- 在 `HotKeyPageViewModel.cs` 文件中,注释掉了 `ElementalCollectHandler` 的测试代码,并添加了 `GoToAdventurersGuildTask` 的测试代码。
- 在 `TaskSettingsPageViewModel.cs` 文件中,更新了 `OnGoToAutoGeniusInvokationUrlAsync` 方法中的 URL。
- 添加了 `BetterGenshinImpact - Backup.csproj` 文件,配置了项目属性、资源文件和包引用。
- 添加了 `冒险家协会_枫丹.json`、`合成台_枫丹.json` 和 `合成台_璃月.json` 文件,定义了前往相应地点的路径和动作。
- 添加了 `ChooseTalkOptionTask.cs` 文件,实现了选择对话选项的任务。
- 添加了 `GoToAdventurersGuildTask.cs` 文件,实现了前往冒险家协会领取奖励的任务。
This commit is contained in:
辉鸭蛋 2024-11-10 22:49:55 +08:00
parent 648dfd3f41
commit 3c2739c5c5
18 changed files with 791 additions and 51 deletions

View File

@ -0,0 +1,148 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<LangVersion>12.0</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationIcon>Assets\Images\logo.ico</ApplicationIcon>
<AssemblyName>BetterGI</AssemblyName>
<AssemblyVersion>0.36.2</AssemblyVersion>
<Platforms>x64</Platforms>
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\Images\*.jpg" />
<None Remove="Assets\Images\*" />
<None Remove="Assets\Images\*.png" />
<None Remove="Assets\Images\*.ico" />
<None Remove="Assets\Fonts\*.ttf" />
<None Remove="Assets\Highlighting\*.xshd" />
<None Remove="Assets\Strings\*.html" />
<None Remove="Assets\Strings\*.md" />
<None Remove="Assets\Audios\*.mp3" />
</ItemGroup>
<ItemGroup>
<Resource Include="Assets\Images\*.jpg" />
<Resource Include="Assets\Images\Anniversary\*" />
<Resource Include="Assets\Images\*.png" />
<Resource Include="Assets\Images\*.ico" />
<Resource Include="Assets\Fonts\*.ttf" />
<Resource Include="Assets\Highlighting\*.xshd" />
<Resource Include="Assets\Strings\*.html" />
<Resource Include="Assets\Strings\*.md" />
<Resource Include="Assets\Audios\*.mp3" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AvalonEdit" Version="6.3.0.90" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Microsoft.ML.OnnxRuntime.DirectML" Version="1.18.1" />
<PackageReference Include="Microsoft.ML.OnnxRuntime.Managed" Version="1.18.1" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2592.51" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
<PackageReference Include="OpenCvSharp4.WpfExtensions" Version="4.8.0.20230708" />
<PackageReference Include="OpenCvSharp4.Extensions" Version="4.8.0.20230708" />
<PackageReference Include="OpenCvSharp4.Windows" Version="4.8.0.20230708" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.122" />
<PackageReference Include="Microsoft.ClearScript.V8" Version="7.4.5" />
<PackageReference Include="Microsoft.ClearScript.V8.Native.win-x64" Version="7.4.5" />
<PackageReference Include="MouseKeyHook" Version="5.7.1" />
<PackageReference Include="PresentMonFps" Version="2.0.5" />
<PackageReference Include="Sdcb.PaddleInference" Version="2.5.0.1" />
<PackageReference Include="Sdcb.PaddleInference.runtime.win64.openblas" Version="2.5.1" />
<PackageReference Include="Sdcb.PaddleOCR" Version="2.7.0" />
<PackageReference Include="Sdcb.PaddleOCR.Models.Online" Version="2.7.0.1" />
<PackageReference Include="Sdl.MultiSelectComboBox" Version="1.0.103" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.RichTextBoxEx.Wpf" Version="1.1.0.1" />
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
<PackageReference Include="Vanara.PInvoke.NtDll" Version="4.0.2" />
<PackageReference Include="Vanara.PInvoke.SHCore" Version="4.0.2" />
<PackageReference Include="Vanara.PInvoke.User32" Version="4.0.2" />
<PackageReference Include="WPF-UI" Version="3.0.5" />
<PackageReference Include="WPF-UI.Tray" Version="3.0.5" />
<PackageReference Include="WPF-UI.Violeta" Version="3.0.5.23" />
<PackageReference Include="YoloV8" Version="4.1.7" />
<PackageReference Include="gong-wpf-dragdrop" Version="3.2.1" />
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' == 'Debug'">
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Fischless.GameCapture\Fischless.GameCapture.csproj" />
<ProjectReference Include="..\Fischless.HotkeyCapture\Fischless.HotkeyCapture.csproj" />
<ProjectReference Include="..\Fischless.WindowsInput\Fischless.WindowsInput.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Assets\Map\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\Model\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="GameTask\AutoFight\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\AutoFight\Assets\combat_avatar.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\AutoFishing\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\AutoGeniusInvokation\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\AutoGeniusInvokation\Assets\tcg_character_card.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\AutoPick\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\AutoSkip\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\AutoSkip\Assets\hangout.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\AutoTrackPath\Assets\tp.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\Common\Element\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\AutoWood\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\GameLoading\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\QuickTeleport\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\QuickSereniteaPot\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="User\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="GameTask\Common\Element\Assets\新文件夹\" />
<Folder Include="GameTask\OneDragon\" />
<Folder Include="User\AutoPathing\" />
</ItemGroup>
</Project>

View File

@ -122,6 +122,9 @@
<None Update="GameTask\Common\Element\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\Common\Element\Assets\Json\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\AutoWood\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
@ -140,6 +143,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="GameTask\Common\Element\Assets\Json\" />
<Folder Include="GameTask\OneDragon\" />
<Folder Include="User\AutoPathing\" />
</ItemGroup>

View File

@ -144,5 +144,28 @@ public class RecognitionObject
/// </summary>
public List<string> RegexMatchText { get; set; } = [];
public static RecognitionObject Ocr(double x, double y, double w, double h)
{
return new RecognitionObject
{
RecognitionType = RecognitionTypes.Ocr,
RegionOfInterest = new Rect((int)Math.Round(x), (int)Math.Round(y), (int)Math.Round(w), (int)Math.Round(h))
};
}
public static RecognitionObject Ocr(Rect rect)
{
return new RecognitionObject
{
RecognitionType = RecognitionTypes.Ocr,
RegionOfInterest = rect
};
}
public static RecognitionObject OcrThis = new()
{
RecognitionType = RecognitionTypes.Ocr
};
#endregion OCR文字识别
}

View File

@ -2,12 +2,17 @@
using BetterGenshinImpact.Core.Simulator;
using BetterGenshinImpact.GameTask.AutoFight.Model;
using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Exception;
using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Model;
using BetterGenshinImpact.GameTask.AutoPathing.Handler;
using BetterGenshinImpact.GameTask.AutoPathing.Model;
using BetterGenshinImpact.GameTask.AutoPathing.Model.Enum;
using BetterGenshinImpact.GameTask.AutoSkip;
using BetterGenshinImpact.GameTask.AutoSkip.Assets;
using BetterGenshinImpact.GameTask.AutoTrackPath;
using BetterGenshinImpact.GameTask.Common.BgiVision;
using BetterGenshinImpact.GameTask.Common.Job;
using BetterGenshinImpact.GameTask.Common.Map;
using BetterGenshinImpact.GameTask.Model.Area;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using Microsoft.Extensions.Logging;
@ -18,11 +23,6 @@ using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Model;
using BetterGenshinImpact.GameTask.AutoSkip;
using BetterGenshinImpact.GameTask.AutoSkip.Assets;
using BetterGenshinImpact.GameTask.Common.Job;
using BetterGenshinImpact.GameTask.Model.Area;
using Vanara.PInvoke;
using static BetterGenshinImpact.GameTask.Common.TaskControl;
using ActionEnum = BetterGenshinImpact.GameTask.AutoPathing.Model.Enum.ActionEnum;
@ -99,7 +99,6 @@ public class PathExecutor(CancellationToken ct)
{
foreach (var waypoint in waypoints)
{
await ResolveAnomalies();
await RecoverWhenLowHp(); // 低血量恢复
if (waypoint.Type == WaypointType.Teleport.Code)
{
@ -132,7 +131,7 @@ public class PathExecutor(CancellationToken ct)
// 不管咋样,松开所有按键
Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W);
Simulation.SendInput.Mouse.RightButtonUp();
await ResolveAnomalies();
await ResolveAnomalies(); // 异常场景处理
}
}
}
@ -328,7 +327,7 @@ public class PathExecutor(CancellationToken ct)
await SwitchAvatar(PartyConfig.MainAvatarIndex);
var screen = CaptureToRectArea();
var position = Navigation.GetPosition(screen);
var position = await GetPosition(screen);
var targetOrientation = Navigation.GetTargetOrientation(waypoint, position);
Logger.LogInformation("粗略接近途经点,位置({x2},{y2})", $"{waypoint.GameX:F1}", $"{waypoint.GameY:F1}");
await _rotateTask.WaitUntilRotatedTo(targetOrientation, 5);
@ -352,7 +351,7 @@ public class PathExecutor(CancellationToken ct)
}
screen = CaptureToRectArea();
position = Navigation.GetPosition(screen);
position = await GetPosition(screen);
var distance = Navigation.GetDistance(waypoint, position);
Debug.WriteLine($"接近目标点中,距离为{distance}");
if (distance < 4)
@ -533,7 +532,7 @@ public class PathExecutor(CancellationToken ct)
private async Task MoveCloseTo(WaypointForTrack waypoint)
{
var screen = CaptureToRectArea();
var position = Navigation.GetPosition(screen);
var position = await GetPosition(screen);
var targetOrientation = Navigation.GetTargetOrientation(waypoint, position);
Logger.LogInformation("精确接近目标点,位置({x2},{y2})", $"{waypoint.GameX:F1}", $"{waypoint.GameY:F1}");
if (waypoint.MoveMode == MoveModeEnum.Fly.Code && waypoint.Action == ActionEnum.StopFlying.Code)
@ -549,14 +548,14 @@ public class PathExecutor(CancellationToken ct)
while (!ct.IsCancellationRequested)
{
stepsTaken++;
if (stepsTaken > 30)
if (stepsTaken > 25)
{
Logger.LogWarning("精确接近超时");
break;
}
screen = CaptureToRectArea();
position = Navigation.GetPosition(screen);
position = await GetPosition(screen);
if (Navigation.GetDistance(waypoint, position) < 2)
{
Logger.LogInformation("已到达路径点");
@ -626,12 +625,27 @@ public class PathExecutor(CancellationToken ct)
return null;
}
private async Task<Point2f> GetPosition(ImageRegion imageRegion)
{
var position = Navigation.GetPosition(imageRegion);
if (position == new Point2f())
{
if (!Bv.IsInBigMapUi(imageRegion))
{
await ResolveAnomalies();
}
}
return position;
}
/**
*
*
*/
public async Task ResolveAnomalies()
private async Task ResolveAnomalies()
{
// 处理月卡
await _blessingOfTheWelkinMoonTask.Start(ct);
@ -670,7 +684,7 @@ public class PathExecutor(CancellationToken ct)
else
{
noDisabledUiButtonTimes++;
if (noDisabledUiButtonTimes > 50)
if (noDisabledUiButtonTimes > 10)
{
Logger.LogInformation("自动剧情结束");
break;

View File

@ -1,16 +1,25 @@
using BetterGenshinImpact.Core.Recognition;
using System;
using BetterGenshinImpact.Core.Recognition;
using BetterGenshinImpact.GameTask.Model;
using BetterGenshinImpact.Helpers;
using OpenCvSharp;
using System.Drawing;
using Vanara.PInvoke;
using Microsoft.Extensions.Logging;
namespace BetterGenshinImpact.GameTask.AutoPick.Assets;
public class AutoPickAssets : BaseAssets<AutoPickAssets>
{
private readonly ILogger<AutoPickAssets> _logger = App.GetLogger<AutoPickAssets>();
public RecognitionObject FRo;
public RecognitionObject ChatIconRo;
public RecognitionObject SettingsIconRo;
public User32.VK PickVk = User32.VK.VK_F;
public RecognitionObject PickRo;
private AutoPickAssets()
{
FRo = new RecognitionObject
@ -41,6 +50,28 @@ public class AutoPickAssets : BaseAssets<AutoPickAssets>
DrawOnWindow = false,
DrawOnWindowPen = new Pen(Color.Chocolate, 2)
}.InitTemplate();
PickRo = FRo;
var keyName = TaskContext.Instance().Config.AutoPickConfig.PickKey;
if (!string.IsNullOrEmpty(keyName))
{
try
{
PickRo = LoadCustomPickKey(keyName);
PickVk = User32Helper.ToVk(keyName);
}
catch (Exception e)
{
_logger.LogDebug(e, "加载自定义拾取按键时发生异常");
_logger.LogError("加载自定义拾取按键失败继续使用默认的F键");
TaskContext.Instance().Config.AutoPickConfig.PickKey = "F";
return;
}
if (keyName != "F")
{
_logger.LogInformation("自定义拾取按键:{Key}", keyName);
}
}
}
public RecognitionObject LoadCustomPickKey(string key)

View File

@ -41,9 +41,6 @@ public partial class AutoPickTrigger : ITaskTrigger
/// </summary>
private List<string> _whiteList = [];
// 自定义拾取按键
private string _pickKeyName = "F";
private User32.VK _pickVk = User32.VK.VK_F;
private RecognitionObject _pickRo;
@ -53,7 +50,7 @@ public partial class AutoPickTrigger : ITaskTrigger
public AutoPickTrigger()
{
_autoPickAssets = AutoPickAssets.Instance;
_pickRo = _autoPickAssets.FRo;
_pickRo = _autoPickAssets.PickRo;
}
public AutoPickTrigger(AutoPickExternalConfig? config) : this()
@ -63,28 +60,6 @@ public partial class AutoPickTrigger : ITaskTrigger
public void Init()
{
var keyName = TaskContext.Instance().Config.AutoPickConfig.PickKey;
if (!string.IsNullOrEmpty(keyName))
{
try
{
_pickRo = _autoPickAssets.LoadCustomPickKey(keyName);
_pickVk = User32Helper.ToVk(keyName);
_pickKeyName = keyName;
}
catch (Exception e)
{
_logger.LogDebug(e, "加载自定义拾取按键时发生异常");
_logger.LogError("加载自定义拾取按键失败继续使用默认的F键");
TaskContext.Instance().Config.AutoPickConfig.PickKey = "F";
return;
}
if (_pickKeyName != "F")
{
_logger.LogInformation("自定义拾取按键:{Key}", _pickKeyName);
}
}
IsEnabled = TaskContext.Instance().Config.AutoPickConfig.Enabled;
try
{
@ -133,7 +108,7 @@ public partial class AutoPickTrigger : ITaskTrigger
content.CaptureRectArea.Find(_pickRo, foundRectArea =>
{
speedTimer.Record($"识别到 {_pickKeyName} 拾取键");
speedTimer.Record($"识别到拾取键");
if (_externalConfig is { ForceInteraction: true })
{
@ -227,7 +202,7 @@ public partial class AutoPickTrigger : ITaskTrigger
if (_whiteList.Contains(text))
{
LogPick(content, text);
Simulation.SendInput.Keyboard.KeyPress(_pickVk);
Simulation.SendInput.Keyboard.KeyPress(AutoPickAssets.Instance.PickVk);
return;
}
@ -247,7 +222,7 @@ public partial class AutoPickTrigger : ITaskTrigger
speedTimer.Record("黑名单判断");
LogPick(content, text);
Simulation.SendInput.Keyboard.KeyPress(_pickVk);
Simulation.SendInput.Keyboard.KeyPress(AutoPickAssets.Instance.PickVk);
}
});
speedTimer.DebugPrint();

View File

@ -4,9 +4,7 @@ using BetterGenshinImpact.GameTask.AutoSkip.Assets;
using BetterGenshinImpact.GameTask.Common;
using BetterGenshinImpact.View.Drawable;
using Microsoft.Extensions.Logging;
using OpenCvSharp;
using System;
using System.Xml.Linq;
using static BetterGenshinImpact.GameTask.Common.TaskControl;
using static Vanara.PInvoke.User32;
@ -24,7 +22,7 @@ public class OneKeyExpeditionTask
{
// 1.全部领取
var region = CaptureToRectArea(true);
Cv2.ImWrite($"log/ts.png", region.SrcMat);
// Cv2.ImWrite($"log/ts.png", region.SrcMat);
var ra = region.Find(assets.CollectRo);
if (!ra.IsEmpty())
{

View File

@ -380,6 +380,11 @@ public class TpTask(CancellationToken ct)
var bigMapCenterPoint = bigMapCenterPointNullable.Value;
Logger.LogDebug("识别当前大地图位置:{Pos}", bigMapCenterPoint);
minDistance = Math.Sqrt(Math.Pow(bigMapCenterPoint.X - x, 2) + Math.Pow(bigMapCenterPoint.Y - y, 2));
if (minDistance < 50)
{
// 点位很近的情况下不切换
return false;
}
}
var minCountry = "当前位置";

View File

@ -1,5 +1,12 @@
using BetterGenshinImpact.GameTask.Common.Element.Assets;
using System.Windows.Documents;
using BetterGenshinImpact.Core.Recognition;
using BetterGenshinImpact.Core.Simulator;
using BetterGenshinImpact.GameTask.AutoPick.Assets;
using BetterGenshinImpact.GameTask.AutoSkip.Assets;
using BetterGenshinImpact.GameTask.Common.Element.Assets;
using BetterGenshinImpact.GameTask.Model.Area;
using OpenCvSharp;
using Vanara.PInvoke;
namespace BetterGenshinImpact.GameTask.Common.BgiVision;
@ -24,6 +31,7 @@ public static partial class Bv
ra.Click();
return true;
}
return false;
}
@ -40,6 +48,7 @@ public static partial class Bv
ra.Click();
return true;
}
return false;
}
@ -56,6 +65,7 @@ public static partial class Bv
ra.Click();
return true;
}
return false;
}
@ -72,6 +82,7 @@ public static partial class Bv
ra.Click();
return true;
}
return false;
}
@ -88,6 +99,7 @@ public static partial class Bv
ra.Click();
return true;
}
return false;
}
@ -104,6 +116,7 @@ public static partial class Bv
ra.Click();
return true;
}
return false;
}
@ -126,4 +139,63 @@ public static partial class Bv
{
return ClickBlackCancelButton(captureRa) || ClickWhiteCancelButton(captureRa) || ClickOnlineNoButton(captureRa);
}
/// <summary>
/// 找到交互按钮
/// </summary>
/// <param name="captureRa"></param>
/// <param name="text"></param>
/// <returns></returns>
public static bool FindF(ImageRegion captureRa, params string[] text)
{
using var ra = captureRa.Find(AutoPickAssets.Instance.PickRo);
if (ra.IsExist())
{
if (text.Length == 0)
{
return true;
}
var scale = TaskContext.Instance().SystemInfo.AssetScale;
var config = TaskContext.Instance().Config.AutoPickConfig;
var textRect = new Rect(ra.X + (int)(config.ItemTextLeftOffset * scale), ra.Y,
(int)((config.ItemTextRightOffset - config.ItemTextLeftOffset) * scale), ra.Height);
var textRa = captureRa.DeriveCrop(textRect);
var list = textRa.FindMulti(RecognitionObject.OcrThis);
foreach (var item in list)
{
// 所有匹配成功才算成功
var success = true;
foreach (var t in text)
{
if (!item.Text.Contains(t))
{
success = false;
}
}
return success;
}
}
return false;
}
/// <summary>
/// 找到交互按钮并点击
/// </summary>
/// <param name="captureRa"></param>
/// <param name="text"></param>
/// <returns></returns>
public static bool FindFAndPress(ImageRegion captureRa, params string[] text)
{
if (FindF(captureRa, text))
{
Simulation.SendInput.Keyboard.KeyPress(AutoPickAssets.Instance.PickVk);
return true;
}
return false;
}
}

View File

@ -10,6 +10,7 @@ using BetterGenshinImpact.Core.Simulator;
using BetterGenshinImpact.GameTask.AutoFight;
using Vanara.PInvoke;
using System.Threading;
using BetterGenshinImpact.GameTask.AutoSkip.Assets;
using BetterGenshinImpact.GameTask.GameLoading.Assets;
namespace BetterGenshinImpact.GameTask.Common.BgiVision;
@ -185,6 +186,27 @@ public static partial class Bv
{
return captureRa.Find(GameLoadingAssets.Instance.WelkinMoonRo).IsExist();
}
/// <summary>
/// 是否在对话界面
/// </summary>
/// <param name="captureRa"></param>
/// <returns></returns>
public static bool IsInTalkUi(ImageRegion captureRa)
{
return captureRa.Find(AutoSkipAssets.Instance.DisabledUiButtonRo).IsExist();
}
/// <summary>
/// 等到对话界面加载完成
/// </summary>
/// <param name="ct"></param>
/// <param name="retryTimes"></param>
/// <returns></returns>
public static async Task<bool> WaitAndSkipForTalkUi(CancellationToken ct, int retryTimes = 5)
{
return await NewRetry.WaitForAction(() => IsInTalkUi(TaskControl.CaptureToRectArea()), ct, retryTimes, 500);
}
}
public enum MotionStatus

View File

@ -0,0 +1,28 @@
{
"info": {
"name": "冒险家协会_枫丹",
"type": "collect",
"author": "yemaxul",
"version": "2.0",
"description": "传送到枫丹冒险家协会",
"bgiVersion": "0.35.0"
},
"positions": [
{
"id": 1,
"x": 4508.97509765625,
"y": 3630.557373046875,
"type": "teleport",
"move_mode": "walk",
"action": ""
},
{
"id": 2,
"x": 4495.0,
"y": 3638.0,
"type": "path",
"move_mode": "walk",
"action": ""
}
]
}

View File

@ -0,0 +1,28 @@
{
"info": {
"name": "合成台_枫丹",
"type": "collect",
"author": "huiyadanli",
"version": "1.0",
"description": "枫丹合成台",
"bgiVersion": "0.35.0"
},
"positions": [
{
"id": 1,
"x": 4508.97509765625,
"y": 3630.557373046875,
"type": "teleport",
"move_mode": "walk",
"action": ""
},
{
"id": 3,
"x": 4480.33,
"y": 3628.3,
"type": "target",
"move_mode": "walk",
"action": ""
}
]
}

View File

@ -0,0 +1,36 @@
{
"info": {
"name": "合成台_璃月",
"type": "collect",
"author": "Yemaxul",
"version": "1.0",
"description": "璃月合成台,搭配树脂自动合成使用",
"bgiVersion": "0.35.0"
},
"positions": [
{
"id": 1,
"action": "",
"move_mode": "walk",
"type": "teleport",
"x": 266.86328125,
"y": -652.8173828125
},
{
"id": 2,
"x": 258.4609375,
"y": -658.4111328125,
"type": "path",
"move_mode": "walk",
"action": ""
},
{
"id": 3,
"x": 266.3046875,
"y": -653.61328125,
"type": "target",
"move_mode": "walk",
"action": ""
}
]
}

View File

@ -0,0 +1,218 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BetterGenshinImpact.Core.Recognition;
using BetterGenshinImpact.Core.Simulator;
using BetterGenshinImpact.GameTask.AutoSkip.Assets;
using BetterGenshinImpact.GameTask.AutoSkip;
using BetterGenshinImpact.GameTask.Common.BgiVision;
using BetterGenshinImpact.GameTask.Model.Area;
using OpenCvSharp;
using Vanara.PInvoke;
using static BetterGenshinImpact.GameTask.Common.TaskControl;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using BetterGenshinImpact.Core.Recognition.OpenCv;
namespace BetterGenshinImpact.GameTask.Common.Job;
public partial class ChooseTalkOptionTask
{
private readonly ILogger<ChooseTalkOptionTask> _logger = App.GetLogger<ChooseTalkOptionTask>();
public string Name => "持续对话并选择目标选项";
// private readonly AutoSkipConfig _config = TaskContext.Instance().Config.AutoSkipConfig;
/// <summary>
/// 单个界面单个选项选择
/// </summary>
/// <param name="option"></param>
/// <param name="ct"></param>
/// <param name="skipTimes">200ms一次点击几次空格</param>
/// <param name="isOrange"></param>
/// <returns></returns>
public async Task<TalkOptionRes> SingleSelectText(string option, CancellationToken ct, int skipTimes = 10, bool isOrange = false)
{
if (!await Bv.WaitAndSkipForTalkUi(ct, 10))
{
Logger.LogError("选项选择:{Text}", "当前界面不在对话选项界面");
return TalkOptionRes.NotFound;
}
await Task.Delay(200, ct);
for (var i = 0; i < skipTimes; i++) // 重试3次
{
var region = CaptureToRectArea();
var optionRegions = RecognizeOption(region, ct);
if (optionRegions == null)
{
TaskContext.Instance().PostMessageSimulator.KeyPressBackground(User32.VK.VK_SPACE);
await Delay(200, ct);
continue; // retry
}
foreach (var optionRa in optionRegions)
{
if (optionRa.Text.Contains(option))
{
if (isOrange)
{
if (!IsOrangeOption(region.DeriveCrop(optionRa.ToRect()).SrcMat))
{
return TalkOptionRes.FoundButNotOrange;
}
}
ClickOcrRegion(optionRa);
await Task.Delay(200, ct);
return TalkOptionRes.FoundAndClick;
}
}
}
return TalkOptionRes.NotFound;
}
public async Task SelectLastOptionOnce(CancellationToken ct)
{
var region = CaptureToRectArea();
if (Bv.IsInTalkUi(region))
{
var chatOptionResultList = region.FindMulti(AutoSkipAssets.Instance.OptionIconRo);
chatOptionResultList = [.. chatOptionResultList.OrderByDescending(r => r.Y)];
if (chatOptionResultList.Count > 0)
{
ClickOcrRegion(chatOptionResultList[0]);
await Task.Delay(200, ct);
}
}
}
public async Task SelectLastOptionUntilEnd(CancellationToken ct)
{
while (true)
{
var region = CaptureToRectArea();
if (Bv.IsInTalkUi(region))
{
var chatOptionResultList = region.FindMulti(AutoSkipAssets.Instance.OptionIconRo);
chatOptionResultList = [.. chatOptionResultList.OrderByDescending(r => r.Y)];
if (chatOptionResultList.Count > 0)
{
ClickOcrRegion(chatOptionResultList[0]);
}
else
{
TaskContext.Instance().PostMessageSimulator.KeyPressBackground(User32.VK.VK_SPACE);
}
}
else if (Bv.IsInMainUi(region))
{
break;
}
await Task.Delay(200, ct);
}
}
[GeneratedRegex(@"^[a-zA-Z0-9]+$")]
private static partial Regex EnOrNumRegex();
/// <summary>
/// 识别当前对话界面的所有选项
/// </summary>
/// <param name="region"></param>
/// <param name="ct"></param>
/// <returns></returns>
public List<Region>? RecognizeOption(ImageRegion region, CancellationToken ct)
{
var assetScale = TaskContext.Instance().SystemInfo.AssetScale;
// 气泡识别
var chatOptionResultList = region.FindMulti(AutoSkipAssets.Instance.OptionIconRo);
if (chatOptionResultList.Count > 0)
{
// 第一个元素就是最下面的
chatOptionResultList = [.. chatOptionResultList.OrderByDescending(r => r.Y)];
// 通过最下面的气泡框来文字识别
var lowest = chatOptionResultList[0];
var ocrRect = new Rect((int)(lowest.X + lowest.Width + 8 * assetScale), region.Height / 12,
(int)(535 * assetScale), (int)(lowest.Y + lowest.Height + 30 * assetScale - region.Height / 12d));
var ocrResList = region.FindMulti(RecognitionObject.Ocr(ocrRect));
// 删除为空的结果 和 纯英文的结果
var rs = new List<Region>();
// 按照y坐标排序
ocrResList = [.. ocrResList.OrderBy(r => r.Y)];
for (var i = 0; i < ocrResList.Count; i++)
{
var item = ocrResList[i];
if (string.IsNullOrEmpty(item.Text) || (item.Text.Length < 5 && EnOrNumRegex().IsMatch(item.Text)))
{
continue;
}
if (i != ocrResList.Count - 1)
{
if (ocrResList[i + 1].Y - ocrResList[i].Y > 150)
{
Debug.WriteLine($"存在Y轴偏差过大的结果忽略:{item.Text}");
continue;
}
}
rs.Add(item);
}
return ocrResList;
}
return null; // 没有找到气泡
}
private void ClickOcrRegion(Region region)
{
region.Click();
AutoSkipLog(region.Text);
}
private void AutoSkipLog(string text)
{
if (!string.IsNullOrEmpty(text))
{
_logger.LogInformation("对话选项:{Text}", text);
}
}
private bool IsOrangeOption(Mat textMat)
{
// 只提取橙色
using var bMat = OpenCvCommonHelper.Threshold(textMat, new Scalar(243, 195, 48), new Scalar(255, 205, 55));
var whiteCount = OpenCvCommonHelper.CountGrayMatColor(bMat, 255);
var rate = whiteCount * 1.0 / (bMat.Width * bMat.Height);
Debug.WriteLine($"识别到橙色文字区域占比:{rate}");
if (rate > 0.06)
{
return true;
}
return false;
}
}
public enum TalkOptionRes
{
// 未找到
NotFound,
// 找到但不是橙色
FoundButNotOrange,
// 找到并点击
FoundAndClick,
}

View File

@ -0,0 +1,134 @@
using BetterGenshinImpact.Core.Config;
using BetterGenshinImpact.GameTask.AutoPathing;
using BetterGenshinImpact.GameTask.AutoPathing.Model;
using BetterGenshinImpact.GameTask.AutoSkip.Assets;
using BetterGenshinImpact.GameTask.AutoSkip;
using BetterGenshinImpact.GameTask.Common.BgiVision;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
using static BetterGenshinImpact.GameTask.Common.TaskControl;
namespace BetterGenshinImpact.GameTask.Common.Job;
public class GoToAdventurersGuildTask
{
public string Name => "前往冒险家协会领取奖励";
private readonly int _retryTimes = 2;
private readonly ChooseTalkOptionTask _chooseTalkOptionTask = new();
public async Task Start(string country, CancellationToken ct)
{
Logger.LogInformation("→ {Name} 开始", Name);
for (int i = 0; i < _retryTimes; i++)
{
try
{
await DoOnce(country, ct);
break;
}
catch (Exception e)
{
Logger.LogError("前往冒险家协会领取奖励执行异常:" + e.Message);
if (i == _retryTimes - 1)
{
// 通知失败
throw;
}
else
{
await Delay(1000, ct);
Logger.LogInformation("重试前往冒险家协会领取奖励");
}
}
}
Logger.LogInformation("→ {Name} 结束", Name);
}
public async Task DoOnce(string country, CancellationToken ct)
{
// 1. 走到冒险家协会
await GoToAdventurersGuild(country, ct);
// 2. 交互
var ra = CaptureToRectArea();
if (!Bv.FindFAndPress(ra, "凯瑟琳"))
{
throw new Exception("未找与凯瑟琳对话交互按钮");
}
// 3. 等待对话界面
// 每日
var res = await _chooseTalkOptionTask.SingleSelectText("每日", ct, 10, true);
if (res == TalkOptionRes.FoundAndClick)
{
Logger.LogInformation("▶ {Text}", "领取『每日委托』奖励!");
await Delay(1000, ct);
await new ReturnMainUiTask().Start(ct);
// 结束后重新打开
await Delay(200, ct);
ra = CaptureToRectArea();
if (!Bv.FindFAndPress(ra, "凯瑟琳"))
{
throw new Exception("未找与凯瑟琳对话交互按钮");
}
}
else if (res == TalkOptionRes.FoundButNotOrange)
{
Logger.LogInformation("▶ {Text} 未完成或者已领取", "领取『每日委托』奖励");
}
else
{
Logger.LogWarning("▶ 未找到 {Text} 选项", "领取『每日委托』奖励");
}
// 探索
res = await _chooseTalkOptionTask.SingleSelectText("探索", ct, 10, true);
if (res == TalkOptionRes.FoundAndClick)
{
new OneKeyExpeditionTask().Run(AutoSkipAssets.Instance);
}
else if (res == TalkOptionRes.FoundButNotOrange)
{
Logger.LogInformation("▶ {Text} 未探索完成或已领取", "探索派遣");
}
else
{
Logger.LogWarning("▶ 未找到 {Text} 选项", "探索派遣");
}
// 如果最后还在对话界面,选择最后一个选项退出
if (Bv.IsInTalkUi(CaptureToRectArea()))
{
await _chooseTalkOptionTask.SelectLastOptionUntilEnd(ct);
Logger.LogInformation("退出当前对话");
}
}
/// <summary>
/// 前往冒险家协会
/// </summary>
/// <param name="country"></param>
/// <param name="ct"></param>
/// <returns></returns>
public async Task GoToAdventurersGuild(string country, CancellationToken ct)
{
var task = PathingTask.BuildFromFilePath(Global.Absolute(@$"GameTask\Common\Element\Assets\Json\冒险家协会_{country}.json"));
var pathingTask = new PathExecutor(ct)
{
PartyConfig = new PathingPartyConfig
{
Enabled = true,
AutoSkipEnabled = true
}
};
await pathingTask.Pathing(task);
await Delay(500, ct);
}
}

View File

@ -125,6 +125,7 @@ internal class GameTaskManager
ElementAssets.DestroyInstance();
QuickSereniteaPotAssets.DestroyInstance();
GameLoadingAssets.DestroyInstance();
MapAssets.DestroyInstance();
}
/// <summary>

View File

@ -550,11 +550,14 @@ public partial class HotKeyPageViewModel : ObservableObject, IViewModel
Config.HotKeyConfig.Test1HotkeyType,
(_, _) =>
{
var handler = new ElementalCollectHandler(ElementalType.Anemo);
handler.RunAsync(new CancellationToken());
// var handler = new ElementalCollectHandler(ElementalType.Anemo);
// handler.RunAsync(new CancellationToken());
// SwitchPartyTask switchPartyTask = new SwitchPartyTask();
// Task.Run(async () => { await switchPartyTask.Start("三保一", new CancellationToken()); });
GoToAdventurersGuildTask goToAdventurersGuildTask = new GoToAdventurersGuildTask();
Task.Run(async () => { await goToAdventurersGuildTask.Start("枫丹", new CancellationToken()); });
}
));
debugDirectory.Children.Add(new HotKeySettingModel(

View File

@ -196,7 +196,7 @@ public partial class TaskSettingsPageViewModel : ObservableObject, INavigationAw
[RelayCommand]
public async Task OnGoToAutoGeniusInvokationUrlAsync()
{
await Launcher.LaunchUriAsync(new Uri("https://bgi.huiyadan.com/doc.html#%E8%87%AA%E5%8A%A8%E4%B8%83%E5%9C%A3%E5%8F%AC%E5%94%A4"));
await Launcher.LaunchUriAsync(new Uri("https://bgi.huiyadan.com/feats/task/tcg.html"));
}
[RelayCommand]