mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-04-01 10:39:50 +08:00
198 lines
7.8 KiB
C#
198 lines
7.8 KiB
C#
using BetterGenshinImpact.Core.Recognition.OCR;
|
|
using BetterGenshinImpact.Core.Simulator;
|
|
using BetterGenshinImpact.GameTask.AutoArtifactSalvage;
|
|
using BetterGenshinImpact.GameTask.GetGridIcons;
|
|
using BetterGenshinImpact.GameTask.Model.Area;
|
|
using BetterGenshinImpact.GameTask.Model.GameUI;
|
|
using BetterGenshinImpact.View.Drawable;
|
|
using BetterGenshinImpact.Helpers;
|
|
using Fischless.WindowsInput;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.ML.OnnxRuntime;
|
|
using OpenCvSharp;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace BetterGenshinImpact.GameTask.Common.Job
|
|
{
|
|
internal class CountInventoryItem : ISoloTask<object>
|
|
{
|
|
public string Name => "背包数物品";
|
|
|
|
private readonly ILogger logger = App.GetLogger<CountInventoryItem>();
|
|
private readonly InputSimulator input = Simulation.SendInput;
|
|
private CancellationToken ct;
|
|
private readonly GridScreenName gridScreenName;
|
|
private readonly string? itemName;
|
|
private readonly IEnumerable<string>? itemNames;
|
|
|
|
public CountInventoryItem(GridScreenName gridScreenName, string? itemName = null, IEnumerable<string>? itemNames = null)
|
|
{
|
|
this.gridScreenName = gridScreenName;
|
|
if (itemName != null && itemNames != null)
|
|
{
|
|
throw new ArgumentException($"参数{nameof(itemName)}和{nameof(itemNames)}不能同时使用");
|
|
}
|
|
if (itemName == null && itemNames == null)
|
|
{
|
|
throw new ArgumentException($"参数{nameof(itemName)}和{nameof(itemNames)}不能同时为空");
|
|
}
|
|
if (itemNames != null && !itemNames.Any())
|
|
{
|
|
throw new ArgumentException($"参数{nameof(itemNames)}不能为空序列");
|
|
}
|
|
this.itemName = itemName;
|
|
this.itemNames = itemNames;
|
|
}
|
|
|
|
public async Task<object> Start(CancellationToken ct)
|
|
{
|
|
this.ct = ct;
|
|
|
|
if (this.itemName != null)
|
|
{
|
|
logger.LogInformation("打开背包并在{grid}寻找{name}……", this.gridScreenName, this.itemName!);
|
|
}
|
|
else
|
|
{
|
|
logger.LogInformation("打开背包并在{grid}寻找{first}等{count}类物品……", this.gridScreenName, this.itemNames!.First(), this.itemNames!.Count());
|
|
}
|
|
await new ReturnMainUiTask().Start(ct);
|
|
await AutoArtifactSalvageTask.OpenInventory(this.gridScreenName, input, logger, this.ct);
|
|
|
|
using InferenceSession session = GridIconsAccuracyTestTask.LoadModel(out Dictionary<string, float[]> prototypes);
|
|
|
|
object result;
|
|
if (this.itemName != null)
|
|
{
|
|
result = await FindOne(session, prototypes);
|
|
}
|
|
else
|
|
{
|
|
result = await FindMulti(session, prototypes);
|
|
}
|
|
|
|
await new ReturnMainUiTask().Start(ct);
|
|
|
|
return result;
|
|
}
|
|
|
|
private async Task<int> FindOne(InferenceSession session, Dictionary<string, float[]> prototypes)
|
|
{
|
|
GridScreen gridScreen = new GridScreen(GridParams.Templates[this.gridScreenName], logger, ct);
|
|
gridScreen.OnAfterTurnToNewPage += GridScreen.DrawItemsAfterTurnToNewPage;
|
|
gridScreen.OnBeforeScroll += () => VisionContext.Instance().DrawContent.ClearAll();
|
|
int? count = null;
|
|
try
|
|
{
|
|
await foreach ((ImageRegion pageRegion, Rect itemRect) in gridScreen)
|
|
{
|
|
using ImageRegion itemRegion = pageRegion.DeriveCrop(itemRect);
|
|
using Mat icon = itemRegion.SrcMat.GetGridIcon();
|
|
var result = GridIconsAccuracyTestTask.Infer(icon, session, prototypes);
|
|
if (result.Item1 == null)
|
|
{
|
|
continue;
|
|
}
|
|
string predName = result.Item1;
|
|
if (predName == this.itemName!)
|
|
{
|
|
string ocrText = itemRegion.SrcMat.GetGridItemIconText(OcrFactory.Paddle);
|
|
string numStr = StringUtils.ConvertFullWidthNumToHalfWidth(ocrText);
|
|
if (int.TryParse(numStr, out int num))
|
|
{
|
|
count = num;
|
|
}
|
|
else
|
|
{
|
|
logger.LogWarning("无法识别数量:{text}", numStr);
|
|
count = -2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
VisionContext.Instance().DrawContent.ClearAll();
|
|
}
|
|
if (count == null)
|
|
{
|
|
count = -1;
|
|
logger.LogInformation("没有找到{name}", this.itemName!);
|
|
}
|
|
return count.Value;
|
|
}
|
|
|
|
private async Task<Dictionary<string, int>> FindMulti(InferenceSession session, Dictionary<string, float[]> prototypes)
|
|
{
|
|
Dictionary<string, int> itemsCountDic = new Dictionary<string, int>();
|
|
List<string> notFoundItemNames = this.itemNames!.ToList();
|
|
|
|
GridScreen gridScreen = new GridScreen(GridParams.Templates[this.gridScreenName], logger, ct);
|
|
gridScreen.OnAfterTurnToNewPage += GridScreen.DrawItemsAfterTurnToNewPage;
|
|
gridScreen.OnBeforeScroll += () => VisionContext.Instance().DrawContent.ClearAll();
|
|
try
|
|
{
|
|
await foreach ((ImageRegion pageRegion, Rect itemRect) in gridScreen)
|
|
{
|
|
using ImageRegion itemRegion = pageRegion.DeriveCrop(itemRect);
|
|
using Mat icon = itemRegion.SrcMat.GetGridIcon();
|
|
var result = GridIconsAccuracyTestTask.Infer(icon, session, prototypes);
|
|
if (result.Item1 == null)
|
|
{
|
|
continue;
|
|
}
|
|
string predName = result.Item1;
|
|
if (this.itemNames!.Contains(predName) && !itemsCountDic!.ContainsKey(predName))
|
|
{
|
|
int count;
|
|
string ocrText = itemRegion.SrcMat.GetGridItemIconText(OcrFactory.Paddle);
|
|
string numStr = StringUtils.ConvertFullWidthNumToHalfWidth(ocrText);
|
|
if (int.TryParse(numStr, out int num))
|
|
{
|
|
count = num;
|
|
}
|
|
else
|
|
{
|
|
logger.LogWarning("无法识别数量:{text}", numStr);
|
|
count = -2;
|
|
}
|
|
|
|
if (!itemsCountDic!.TryAdd(predName, count))
|
|
{
|
|
logger.LogWarning("重复的名称:{name}", predName);
|
|
}
|
|
|
|
notFoundItemNames.RemoveAll(n => n == predName);
|
|
|
|
if (notFoundItemNames.Count <= 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
VisionContext.Instance().DrawContent.ClearAll();
|
|
}
|
|
|
|
if (notFoundItemNames.Count > 0)
|
|
{
|
|
logger.LogInformation("没有找到{name}", String.Join(", ", notFoundItemNames));
|
|
}
|
|
return itemsCountDic;
|
|
}
|
|
|
|
async Task ISoloTask.Start(CancellationToken ct)
|
|
{
|
|
await Start(ct);
|
|
}
|
|
}
|
|
}
|