using BetterGenshinImpact.Core.Recognition.OCR;
using BetterGenshinImpact.Core.Simulator;
using BetterGenshinImpact.GameTask.AutoArtifactSalvage;
using BetterGenshinImpact.GameTask.Common.Job;
using BetterGenshinImpact.GameTask.Model.Area;
using BetterGenshinImpact.GameTask.Model.GameUI;
using BetterGenshinImpact.Helpers.Extensions;
using Fischless.WindowsInput;
using Microsoft.Extensions.Logging;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using static BetterGenshinImpact.GameTask.Common.TaskControl;
namespace BetterGenshinImpact.GameTask.GetGridIcons;
///
/// 获取Grid界面的物品图标
///
public class GetGridIconsTask : ISoloTask
{
private readonly ILogger logger = App.GetLogger();
private readonly InputSimulator input = Simulation.SendInput;
private CancellationToken ct;
public string Name => "获取Grid界面物品图标独立任务";
private readonly int? maxNumToGet;
private readonly GridScreenName gridScreenName;
private readonly bool starAsSuffix;
public GetGridIconsTask(GridScreenName gridScreenName, bool starAsSuffix, int? maxNumToGet = null)
{
this.gridScreenName = gridScreenName;
this.starAsSuffix = starAsSuffix;
this.maxNumToGet = maxNumToGet;
}
public async Task Start(CancellationToken ct)
{
this.ct = ct;
switch (this.gridScreenName)
{
case GridScreenName.Weapons:
case GridScreenName.Artifacts:
case GridScreenName.CharacterDevelopmentItems:
case GridScreenName.Food:
case GridScreenName.Materials:
case GridScreenName.Gadget:
case GridScreenName.Quest:
case GridScreenName.PreciousItems:
case GridScreenName.Furnishings:
await new ReturnMainUiTask().Start(ct);
await AutoArtifactSalvageTask.OpenBag(this.gridScreenName, this.input, this.logger, this.ct);
break;
default:
logger.LogInformation("{name}暂不支持自动打开,请提前手动打开界面", gridScreenName.GetDescription());
break;
}
using var ra0 = CaptureToRectArea();
GridScreenParams gridParams = GridScreenParams.Templates[this.gridScreenName];
Rect gridRoi = gridParams.GetRect(ra0);
int count = this.maxNumToGet ?? int.MaxValue;
string directory = Path.Combine(AppContext.BaseDirectory, "log/gridIcons", DateTime.Now.ToString("yyyyMMddHHmmss"));
Directory.CreateDirectory(directory);
GridScreen gridScreen = new GridScreen(gridRoi, gridParams, this.logger, this.ct);
HashSet fileNames = new HashSet();
await foreach (ImageRegion itemRegion in gridScreen)
{
itemRegion.Click();
await Delay(300, ct);
using var ra1 = CaptureToRectArea();
using ImageRegion nameRegion = ra1.DeriveCrop(new Rect((int)(ra1.Width * 0.682), (int)(ra1.Width * 0.0625), (int)(ra1.Width * 0.256), (int)(ra1.Width * 0.03125)));
var ocrResult = OcrFactory.Paddle.OcrResult(nameRegion.SrcMat);
string itemName = ocrResult.Text;
string itemStar = "";
if (this.starAsSuffix)
{
using ImageRegion starRegion = ra1.DeriveCrop(new Rect((int)(ra1.Width * 0.682), (int)(ra1.Width * 0.1823), (int)(ra1.Width * 0.105), (int)(ra1.Width * 0.02345)));
itemStar = String.Join(string.Empty, Enumerable.Repeat("★", GetStars(starRegion.SrcMat)));
}
string fileName = itemName + itemStar;
if (fileNames.Add(fileName))
{
string filePath = Path.Combine(directory, $"{fileName}.png");
Thread saveThread = new Thread(() =>
{
try
{
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
itemRegion.SrcMat.ToBitmap().Save(fs, System.Drawing.Imaging.ImageFormat.Png);
}
logger.LogInformation("图片保存成功:{Text}", fileName);
}
catch (Exception e)
{
logger.LogError(e, "图片保存失败:{Text}", fileName);
}
});
saveThread.IsBackground = true; // 设置为后台线程
saveThread.Start();
}
else
{
logger.LogInformation("重复的物品:{Text}", fileName);
}
count--;
if (count <= 0)
{
logger.LogInformation("检查次数已耗尽");
break;
}
}
}
///
/// OCR检测★字符很不稳定,因此用cv
/// 非常简陋的色彩检测,请传入聚焦的图像,勿带入可能的干扰
///
///
///
public static int GetStars(Mat mat)
{
Scalar yellowLower = new Scalar(50 - 5, 204 - 5, 255 - 5);
Scalar yellowUpper = new Scalar(50 + 5, 204 + 5, 255 + 0);
using Mat mask = mat.InRange(yellowLower, yellowUpper);
var contours = mask.FindContoursAsArray(RetrievalModes.External, ContourApproximationModes.ApproxSimple);
return contours?.Length ?? 0;
}
}