add auto cook #266

This commit is contained in:
辉鸭蛋 2024-05-23 00:27:13 +08:00
parent a801bb2c4f
commit a84c94c5ce
13 changed files with 240 additions and 95 deletions

View File

@ -50,5 +50,11 @@
Height="23"
Click="GenAvatarData"
Content="生成侧面头像数据集" />
<Button Canvas.Left="10"
Canvas.Top="190"
Width="100"
Height="23"
Click="AutoCookTestCase"
Content="自动烹饪图像测试" />
</Canvas>
</Window>

View File

@ -60,4 +60,9 @@ public partial class MainWindow : Window
{
AvatarClassifyGen.GenAll();
}
private void AutoCookTestCase(object sender, RoutedEventArgs e)
{
AutoCookTest.Test();
}
}

View File

@ -0,0 +1,17 @@
using OpenCvSharp;
namespace BetterGenshinImpact.Test.Simple;
internal class AutoCookTest
{
public static void Test()
{
var img = new Mat(@"E:\HuiTask\更好的原神\自动烹饪\2.png");
Cv2.CvtColor(img, img, ColorConversionCodes.BGR2RGB);
var img2 = new Mat();
// Cv2.InRange(img, new Scalar(255, 192, 64), new Scalar(255, 192, 64), img2);
Cv2.InRange(img, new Scalar(255, 255, 192), new Scalar(255, 255, 192), img2);
Cv2.ImShow("img", img2);
}
}

View File

@ -468,6 +468,12 @@
<None Update="GameTask\Common\Element\Assets\1920x1080\submit_icon_exclamation.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\Common\Element\Assets\1920x1080\ui_left_top_cook_icon.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\Common\Element\Assets\1920x1080\ui_lt_cook_icon.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="GameTask\Common\Element\Assets\1920x1080\yellow_track_point_28x.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

View File

@ -13,6 +13,7 @@ using Fischless.GameCapture;
using System;
using System.ComponentModel;
using System.Text.Json.Serialization;
using BetterGenshinImpact.GameTask.AutoCook;
namespace BetterGenshinImpact.Core.Config;
@ -90,10 +91,15 @@ public partial class AllConfig : ObservableObject
public AutoFishingConfig AutoFishingConfig { get; set; } = new();
/// <summary>
/// 自动钓鱼配置
/// 快速传送配置
/// </summary>
public QuickTeleportConfig QuickTeleportConfig { get; set; } = new();
/// <summary>
/// 自动烹饪配置
/// </summary>
public AutoCookConfig AutoCookConfig { get; set; } = new();
/// <summary>
/// 自动打牌配置
/// </summary>
@ -145,6 +151,7 @@ public partial class AllConfig : ObservableObject
AutoSkipConfig.PropertyChanged += OnAnyPropertyChanged;
AutoFishingConfig.PropertyChanged += OnAnyPropertyChanged;
QuickTeleportConfig.PropertyChanged += OnAnyPropertyChanged;
AutoCookConfig.PropertyChanged += OnAnyPropertyChanged;
MacroConfig.PropertyChanged += OnAnyPropertyChanged;
HotKeyConfig.PropertyChanged += OnAnyPropertyChanged;
AutoWoodConfig.PropertyChanged += OnAnyPropertyChanged;

View File

@ -0,0 +1,54 @@
using BetterGenshinImpact.Core.Recognition.OpenCv;
using BetterGenshinImpact.GameTask.Common.Element.Assets;
using Microsoft.Extensions.Logging;
using OpenCvSharp;
using System.Linq;
namespace BetterGenshinImpact.GameTask.AutoCook;
public class AutoCookTrigger : ITaskTrigger
{
private readonly ILogger<AutoCookTrigger> _logger = App.GetLogger<AutoCookTrigger>();
public string Name => "自动烹饪";
public bool IsEnabled { get; set; }
public int Priority => 50;
public bool IsExclusive { get; set; }
public void Init()
{
IsEnabled = TaskContext.Instance().Config.AutoCookConfig.Enabled;
IsExclusive = false;
}
public void OnCapture(CaptureContent content)
{
// 判断是否处于烹饪界面
IsExclusive = false;
content.CaptureRectArea.Find(ElementAssets.Instance.UiLeftTopCookIcon, foundRectArea =>
{
IsExclusive = true;
var captureRect = TaskContext.Instance().SystemInfo.ScaleMax1080PCaptureRect;
using var region = content.CaptureRectArea.DeriveCrop(0, captureRect.Height / 2, captureRect.Width, captureRect.Height / 2);
var perfectBarRects = ContoursHelper.FindSpecifyColorRects(region.SrcMat, new Scalar(255, 192, 64), 0, 8);
if (perfectBarRects.Count >= 2)
{
// 点击烹饪按钮
var btnList = ContoursHelper.FindSpecifyColorRects(region.SrcMat, new Scalar(255, 255, 192), 12, 12);
if (btnList.Count >= 1)
{
if (btnList.Count > 1)
{
_logger.LogWarning("自动烹饪:{Text}", "识别到多个结束烹饪按钮");
btnList = [.. btnList.OrderByDescending(r => r.Width)];
}
var btn = btnList[0];
var x = btn.X + btn.Width / 2;
var y = btn.Y + btn.Height / 2;
region.ClickTo(x, y);
_logger.LogInformation("自动烹饪:{Text}", "点击结束按钮");
}
}
});
}
}

View File

@ -0,0 +1,17 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System;
namespace BetterGenshinImpact.GameTask.AutoCook;
/// <summary>
///自动烹饪配置
/// </summary>
[Serializable]
public partial class AutoCookConfig : ObservableObject
{
/// <summary>
/// 触发器是否启用
/// </summary>
[ObservableProperty]
private bool _enabled = false;
}

View File

@ -1,9 +1,5 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterGenshinImpact.GameTask.AutoPick
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -16,6 +16,8 @@ public class ElementAssets : BaseAssets<ElementAssets>
public RecognitionObject PaimonMenuRo;
public RecognitionObject BlueTrackPoint;
public RecognitionObject UiLeftTopCookIcon;
private ElementAssets()
{
// 按钮
@ -83,5 +85,15 @@ public class ElementAssets : BaseAssets<ElementAssets>
Threshold = 0.6,
DrawOnWindow = true
}.InitTemplate();
// 左上角UI元素
UiLeftTopCookIcon = new RecognitionObject
{
Name = "UiLeftTopCookIcon",
RecognitionType = RecognitionTypes.TemplateMatch,
TemplateImageMat = GameTaskManager.LoadAssetImage(@"Common\Element", "ui_left_top_cook_icon.png"),
RegionOfInterest = new Rect(0, 0, (int)(150 * AssetScale), (int)(120 * AssetScale)),
DrawOnWindow = false
}.InitTemplate();
}
}

View File

@ -20,110 +20,111 @@ using BetterGenshinImpact.GameTask.QuickSereniteaPot.Assets;
using BetterGenshinImpact.GameTask.QuickTeleport.Assets;
using BetterGenshinImpact.View.Drawable;
namespace BetterGenshinImpact.GameTask
namespace BetterGenshinImpact.GameTask;
internal class GameTaskManager
{
internal class GameTaskManager
public static Dictionary<string, ITaskTrigger>? TriggerDictionary { get; set; }
/// <summary>
/// 一定要在任务上下文初始化完毕后使用
/// </summary>
/// <returns></returns>
public static List<ITaskTrigger> LoadTriggers()
{
public static Dictionary<string, ITaskTrigger>? TriggerDictionary { get; set; }
/// <summary>
/// 一定要在任务上下文初始化完毕后使用
/// </summary>
/// <returns></returns>
public static List<ITaskTrigger> LoadTriggers()
ReloadAssets();
TriggerDictionary = new Dictionary<string, ITaskTrigger>()
{
ReloadAssets();
TriggerDictionary = new Dictionary<string, ITaskTrigger>()
{ "RecognitionTest", new TestTrigger() },
{ "GameLoading", new GameLoadingTrigger() },
{ "AutoPick", new AutoPick.AutoPickTrigger() },
{ "QuickTeleport", new QuickTeleport.QuickTeleportTrigger() },
{ "AutoSkip", new AutoSkip.AutoSkipTrigger() },
{ "AutoFishing", new AutoFishing.AutoFishingTrigger() },
{ "AutoCook", new AutoCook.AutoCookTrigger() }
};
var loadedTriggers = TriggerDictionary.Values.ToList();
loadedTriggers.ForEach(i => i.Init());
loadedTriggers = loadedTriggers.OrderByDescending(i => i.Priority).ToList();
return loadedTriggers;
}
public static void RefreshTriggerConfigs()
{
if (TriggerDictionary is { Count: > 0 })
{
TriggerDictionary["AutoPick"].IsEnabled = TaskContext.Instance().Config.AutoPickConfig.Enabled;
// 用于刷新AutoPick的黑白名单
TriggerDictionary["AutoPick"].Init();
TriggerDictionary["AutoSkip"].IsEnabled = TaskContext.Instance().Config.AutoSkipConfig.Enabled;
TriggerDictionary["AutoFishing"].IsEnabled = TaskContext.Instance().Config.AutoFishingConfig.Enabled;
// 钓鱼有很多变量要初始化直接重新newZA
if (TriggerDictionary["AutoFishing"].IsEnabled == false)
{
{ "RecognitionTest", new TestTrigger() },
{ "GameLoading", new GameLoadingTrigger() },
{ "AutoPick", new AutoPick.AutoPickTrigger() },
{ "QuickTeleport", new QuickTeleport.QuickTeleportTrigger() },
{ "AutoSkip", new AutoSkip.AutoSkipTrigger() },
{ "AutoFishing", new AutoFishing.AutoFishingTrigger() }
};
TriggerDictionary["AutoFishing"].Init();
}
TriggerDictionary["QuickTeleport"].IsEnabled = TaskContext.Instance().Config.QuickTeleportConfig.Enabled;
TriggerDictionary["GameLoading"].Init();
TriggerDictionary["AutoCook"].Init();
// 清理画布
WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<object>(new object(), "RemoveAllButton", new object(), ""));
VisionContext.Instance().DrawContent.ClearAll();
}
ReloadAssets();
}
var loadedTriggers = TriggerDictionary.Values.ToList();
public static void ReloadAssets()
{
AutoPickAssets.DestroyInstance();
AutoSkipAssets.DestroyInstance();
AutoFishingAssets.DestroyInstance();
QuickTeleportAssets.DestroyInstance();
AutoWoodAssets.DestroyInstance();
AutoGeniusInvokationAssets.DestroyInstance();
AutoFightAssets.DestroyInstance();
ElementAssets.DestroyInstance();
QuickSereniteaPotAssets.DestroyInstance();
GameLoadingAssets.DestroyInstance();
}
loadedTriggers.ForEach(i => i.Init());
loadedTriggers = loadedTriggers.OrderByDescending(i => i.Priority).ToList();
return loadedTriggers;
/// <summary>
/// 获取素材图片并缩放
/// todo 支持多语言
/// </summary>
/// <param name="featName">任务名称</param>
/// <param name="assertName">素材文件名</param>
/// <param name="flags"></param>
/// <returns></returns>
/// <exception cref="FileNotFoundException"></exception>
public static Mat LoadAssetImage(string featName, string assertName, ImreadModes flags = ImreadModes.Color)
{
var info = TaskContext.Instance().SystemInfo;
var assetsFolder = Global.Absolute($@"GameTask\{featName}\Assets\{info.GameScreenSize.Width}x{info.GameScreenSize.Height}");
if (!Directory.Exists(assetsFolder))
{
assetsFolder = Global.Absolute($@"GameTask\{featName}\Assets\1920x1080");
}
public static void RefreshTriggerConfigs()
if (!Directory.Exists(assetsFolder))
{
if (TriggerDictionary is { Count: > 0 })
{
TriggerDictionary["AutoPick"].IsEnabled = TaskContext.Instance().Config.AutoPickConfig.Enabled;
// 用于刷新AutoPick的黑白名单
TriggerDictionary["AutoPick"].Init();
TriggerDictionary["AutoSkip"].IsEnabled = TaskContext.Instance().Config.AutoSkipConfig.Enabled;
TriggerDictionary["AutoFishing"].IsEnabled = TaskContext.Instance().Config.AutoFishingConfig.Enabled;
// 钓鱼有很多变量要初始化直接重新newZA
if (TriggerDictionary["AutoFishing"].IsEnabled == false)
{
TriggerDictionary["AutoFishing"].Init();
}
TriggerDictionary["QuickTeleport"].IsEnabled = TaskContext.Instance().Config.QuickTeleportConfig.Enabled;
TriggerDictionary["GameLoading"].Init();
// 清理画布
WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<object>(new object(), "RemoveAllButton", new object(), ""));
VisionContext.Instance().DrawContent.ClearAll();
}
ReloadAssets();
throw new FileNotFoundException($"未找到{featName}的素材文件夹");
}
public static void ReloadAssets()
var filePath = Path.Combine(assetsFolder, assertName);
if (!File.Exists(filePath))
{
AutoPickAssets.DestroyInstance();
AutoSkipAssets.DestroyInstance();
AutoFishingAssets.DestroyInstance();
QuickTeleportAssets.DestroyInstance();
AutoWoodAssets.DestroyInstance();
AutoGeniusInvokationAssets.DestroyInstance();
AutoFightAssets.DestroyInstance();
ElementAssets.DestroyInstance();
QuickSereniteaPotAssets.DestroyInstance();
GameLoadingAssets.DestroyInstance();
throw new FileNotFoundException($"未找到{featName}中的{assertName}文件");
}
/// <summary>
/// 获取素材图片并缩放
/// todo 支持多语言
/// </summary>
/// <param name="featName">任务名称</param>
/// <param name="assertName">素材文件名</param>
/// <param name="flags"></param>
/// <returns></returns>
/// <exception cref="FileNotFoundException"></exception>
public static Mat LoadAssetImage(string featName, string assertName, ImreadModes flags = ImreadModes.Color)
var mat = Mat.FromStream(File.OpenRead(filePath), flags);
if (info.GameScreenSize.Width != 1920)
{
var info = TaskContext.Instance().SystemInfo;
var assetsFolder = Global.Absolute($@"GameTask\{featName}\Assets\{info.GameScreenSize.Width}x{info.GameScreenSize.Height}");
if (!Directory.Exists(assetsFolder))
{
assetsFolder = Global.Absolute($@"GameTask\{featName}\Assets\1920x1080");
}
if (!Directory.Exists(assetsFolder))
{
throw new FileNotFoundException($"未找到{featName}的素材文件夹");
}
var filePath = Path.Combine(assetsFolder, assertName);
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"未找到{featName}中的{assertName}文件");
}
var mat = Mat.FromStream(File.OpenRead(filePath), flags);
if (info.GameScreenSize.Width != 1920)
{
mat = ResizeHelper.Resize(mat, info.AssetScale);
}
return mat;
mat = ResizeHelper.Resize(mat, info.AssetScale);
}
return mat;
}
}

View File

@ -750,7 +750,7 @@
<ui:TextBlock Grid.Row="0"
Grid.Column="0"
FontTypography="Body"
Text="活动音游"
Text="活动音游(限时)"
TextWrapping="Wrap" />
<ui:TextBlock Grid.Row="1"
Grid.Column="0"

View File

@ -597,6 +597,30 @@
</StackPanel>
</ui:CardExpander>
<!-- 自动烹饪 -->
<ui:CardControl Margin="0,0,0,12" Icon="{ui:SymbolIcon Fireplace24}">
<ui:CardControl.Header>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TextBlock Grid.Row="0"
Grid.Column="0"
FontTypography="Body"
Text="自动烹饪"
TextWrapping="Wrap" />
<ui:TextBlock Grid.Row="1"
Grid.Column="0"
Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}"
TextWrapping="Wrap">
手动烹饪时,自动在完美状态下结束烹饪(不用的时候请关闭)
</ui:TextBlock>
</Grid>
</ui:CardControl.Header>
<ui:ToggleSwitch Margin="0,0,36,0" IsChecked="{Binding Config.AutoCookConfig.Enabled, Mode=TwoWay}" />
</ui:CardControl>
<!-- 一键战斗 -->
<!--<ui:CardExpander Margin="0,0,0,12" ContentPadding="0" Icon="{ui:SymbolIcon ArrowSync24}">
<ui:CardExpander.Header>