diff --git a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs index 389e8c1c..f3efb1a4 100644 --- a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs +++ b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs @@ -1102,7 +1102,7 @@ public class AutoDomainTask : ISoloTask { // 自动刷干树脂 // 识别树脂状况 - var resinStatus = ResinStatus.RecogniseFromRegion(ra3); + var resinStatus = ResinStatus.RecogniseFromRegion(ra3, TaskContext.Instance().SystemInfo, OcrFactory.Paddle); resinStatus.Print(Logger); if (resinStatus is { CondensedResinCount: <= 0, OriginalResinCount: < 20 }) diff --git a/BetterGenshinImpact/GameTask/AutoDomain/Model/ResinStatus.cs b/BetterGenshinImpact/GameTask/AutoDomain/Model/ResinStatus.cs index 2b292f94..baf15ca7 100644 --- a/BetterGenshinImpact/GameTask/AutoDomain/Model/ResinStatus.cs +++ b/BetterGenshinImpact/GameTask/AutoDomain/Model/ResinStatus.cs @@ -1,10 +1,11 @@ -using System; +using BetterGenshinImpact.Core.Recognition; using BetterGenshinImpact.Core.Recognition.OCR; -using BetterGenshinImpact.GameTask.AutoFight.Assets; +using BetterGenshinImpact.GameTask.Model; using BetterGenshinImpact.GameTask.Model.Area; using BetterGenshinImpact.Helpers; using Microsoft.Extensions.Logging; using OpenCvSharp; +using System; namespace BetterGenshinImpact.GameTask.AutoDomain.Model; @@ -18,35 +19,43 @@ public class ResinStatus /// /// 脆弱树脂(60) /// - public int FragileResinCount { get; set; } = 0; + public int FragileResinCount { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } /// - /// 浓缩树脂(40) + /// 浓缩树脂(60) /// public int CondensedResinCount { get; set; } = 0; /// /// 须臾树脂(60壶内购买) /// - public int TransientResinCount { get; set; } = 0; + public int TransientResinCount { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - public static ResinStatus RecogniseFromRegion(ImageRegion region) + public static ResinStatus RecogniseFromRegion(ImageRegion region, ISystemInfo systemInfo, IOcrService ocrService) { var status = new ResinStatus(); - // 1. 原粹树脂 起点 w-(256+100) ~ w-256 - var captureArea = TaskContext.Instance().SystemInfo.ScaleMax1080PCaptureRect; - var assetScale = TaskContext.Instance().SystemInfo.AssetScale; - var originalResinTopIconRa = AutoFightAssets.Instance.OriginalResinTopIconRa; - var originalResinRes = region.Find(originalResinTopIconRa); + // 1. 原粹树脂 + var assetScale = systemInfo.AssetScale; + var originalResinTopIconRa = new RecognitionObject + { + Name = "OriginalResinTopIcon", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "original_resin_top_icon.png", systemInfo), + DrawOnWindow = false + }.InitTemplate(); + using ImageRegion crop1 = region.DeriveCrop(new Rect((int)(1300 * assetScale), (int)(25 * assetScale), (int)(160 * assetScale), (int)(50 * assetScale))); // 数字位数的不同导致了水平方向上宽泛的区域 + //Cv2.ImShow("test", crop1.SrcMat); + //Cv2.WaitKey(); + var originalResinRes = crop1.Find(originalResinTopIconRa); if (originalResinRes.IsEmpty()) { throw new Exception("未找到原粹树脂图标"); } - var originalResinCountRect = new Rect(originalResinRes.Right + 30, (int)(37 * assetScale), - captureArea.Width - (originalResinRes.Right + 30) - (int)(190 * assetScale), (int)(21 * assetScale)); - string cnt1 = OcrFactory.Paddle.OcrWithoutDetector(region.DeriveCrop(originalResinCountRect).SrcMat); + var originalResinCountRect = new Rect(crop1.X + originalResinRes.Right + (int)(25 * assetScale), (int)(37 * assetScale), (int)(110 * assetScale)/* 考虑最长的“200/200” */, (int)(24 * assetScale)); + using ImageRegion originalResinCountRegion = region.DeriveCrop(originalResinCountRect); + string cnt1 = ocrService.OcrWithoutDetector(originalResinCountRegion.SrcMat); var match = System.Text.RegularExpressions.Regex.Match(cnt1, @"(\d+)\s*[/17]\s*(2|20|200)"); if (match.Success) { @@ -55,12 +64,22 @@ public class ResinStatus } // 2. 浓缩树脂 - var condensedResinRes = region.Find(AutoFightAssets.Instance.CondensedResinTopIconRa); + int startX = crop1.X + originalResinRes.Left - (int)(180 * assetScale); // 从原粹树脂图标位置起算 + var condensedResinTopIconRa = new RecognitionObject + { + Name = "CondensedResinTopIcon", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "condensed_resin_top_icon.png", systemInfo), + DrawOnWindow = false + }.InitTemplate(); + using ImageRegion crop2 = region.DeriveCrop(new Rect(startX, (int)(25 * assetScale), (int)(90 * assetScale), (int)(50 * assetScale))); + var condensedResinRes = crop2.Find(condensedResinTopIconRa); if (condensedResinRes.IsExist()) { // 找出 icon 的位置 + 25 ~ icon 的位置+45 就是浓缩树脂的数字,数字宽20 - var condensedResinCountRect = new Rect(condensedResinRes.Right + (int)(25 * assetScale), condensedResinRes.Y, (int)(20 * assetScale), condensedResinRes.Height); - string cnt40 = OcrFactory.Paddle.OcrWithoutDetector(region.DeriveCrop(condensedResinCountRect).SrcMat); + var condensedResinCountRect = new Rect(crop2.X + condensedResinRes.Right + (int)(20 * assetScale), (int)(37 * assetScale), (int)(70 * assetScale), (int)(24 * assetScale)); + using ImageRegion countRegion = region.DeriveCrop(condensedResinCountRect); + string cnt40 = ocrService.OcrWithoutDetector(countRegion.SrcMat); status.CondensedResinCount = StringUtils.TryExtractPositiveInt(cnt40, 0); } diff --git a/BetterGenshinImpact/GameTask/AutoFight/Assets/1920x1080/use_condensed_resin.png b/BetterGenshinImpact/GameTask/AutoFight/Assets/1920x1080/use_condensed_resin.png deleted file mode 100644 index 3df04cbd..00000000 Binary files a/BetterGenshinImpact/GameTask/AutoFight/Assets/1920x1080/use_condensed_resin.png and /dev/null differ diff --git a/BetterGenshinImpact/GameTask/AutoFight/Assets/AutoFightAssets.cs b/BetterGenshinImpact/GameTask/AutoFight/Assets/AutoFightAssets.cs index bbd30103..6fd55764 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Assets/AutoFightAssets.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/Assets/AutoFightAssets.cs @@ -1,4 +1,4 @@ -using BetterGenshinImpact.Core.Recognition; +using BetterGenshinImpact.Core.Recognition; using BetterGenshinImpact.GameTask.Model; using OpenCvSharp; using System.Collections.Generic; @@ -23,15 +23,9 @@ public class AutoFightAssets : BaseAssets public RecognitionObject ArtifactAreaRa; public RecognitionObject ExitRa; public RecognitionObject ClickAnyCloseTipRa; - public RecognitionObject UseCondensedResinRa; - // 树脂状态 - public RecognitionObject CondensedResinCountRa; - public RecognitionObject FragileResinCountRa; // 自动秘境 // public RecognitionObject LockIconRa; // 锁定辅助图标 - public RecognitionObject CondensedResinTopIconRa; - public RecognitionObject OriginalResinTopIconRa; public Dictionary AvatarCostumeMap; @@ -44,7 +38,7 @@ public class AutoFightAssets : BaseAssets // 小道具位置 public Rect GadgetRect; - + public RecognitionObject AbnormalIconRa; private AutoFightAssets() @@ -59,7 +53,7 @@ public class AutoFightAssets : BaseAssets (int)(41 * AssetScale), (int)(18 * AssetScale)); QRect = new Rect(CaptureRect.Width - (int)(157 * AssetScale), CaptureRect.Height - (int)(165 * AssetScale), (int)(110 * AssetScale), (int)(110 * AssetScale)); - ZCooldownRect = new Rect(CaptureRect.Width - (int)(130 * AssetScale), (int)(814 * AssetScale), + ZCooldownRect = new Rect(CaptureRect.Width - (int)(130 * AssetScale), (int)(814 * AssetScale), (int)(60 * AssetScale), (int)(24 * AssetScale)); // 小道具位置 1920-133,800,60,50 GadgetRect = new Rect(CaptureRect.Width - (int)(133 * AssetScale), (int)(800 * AssetScale), @@ -205,7 +199,7 @@ public class AutoFightAssets : BaseAssets Name = "ArtifactArea", RecognitionType = RecognitionTypes.TemplateMatch, TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "artifact_flower_logo.png"), - RegionOfInterest = new Rect(CaptureRect.Width / 2,0,CaptureRect.Width / 2, CaptureRect.Height), + RegionOfInterest = new Rect(CaptureRect.Width / 2, 0, CaptureRect.Width / 2, CaptureRect.Height), DrawOnWindow = false }.InitTemplate(); @@ -219,15 +213,6 @@ public class AutoFightAssets : BaseAssets DrawOnWindow = false }.InitTemplate(); - UseCondensedResinRa = new RecognitionObject - { - Name = "UseCondensedResin", - RecognitionType = RecognitionTypes.TemplateMatch, - TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "use_condensed_resin.png"), - RegionOfInterest = new Rect(0, CaptureRect.Height / 2, CaptureRect.Width / 2, CaptureRect.Height / 2), - DrawOnWindow = false - }.InitTemplate(); - ExitRa = new RecognitionObject { Name = "Exit", @@ -237,23 +222,6 @@ public class AutoFightAssets : BaseAssets DrawOnWindow = false }.InitTemplate(); - CondensedResinCountRa = new RecognitionObject - { - Name = "CondensedResinCount", - RecognitionType = RecognitionTypes.TemplateMatch, - TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "condensed_resin_count.png"), - RegionOfInterest = new Rect(CaptureRect.Width / 2, CaptureRect.Height / 3 * 2, CaptureRect.Width / 2, CaptureRect.Height / 3), - DrawOnWindow = false - }.InitTemplate(); - FragileResinCountRa = new RecognitionObject - { - Name = "FragileResinCount", - RecognitionType = RecognitionTypes.TemplateMatch, - TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "fragile_resin_count.png"), - RegionOfInterest = new Rect(CaptureRect.Width / 2, CaptureRect.Height / 3 * 2, CaptureRect.Width / 2, CaptureRect.Height / 3), - DrawOnWindow = false - }.InitTemplate(); - // 自动秘境 // LockIconRa = new RecognitionObject // { @@ -263,30 +231,14 @@ public class AutoFightAssets : BaseAssets // RegionOfInterest = new Rect(CaptureRect.Width - (int)(215 * AssetScale), 0, (int)(215 * AssetScale), (int)(80 * AssetScale)), // DrawOnWindow = false // }.InitTemplate(); - CondensedResinTopIconRa = new RecognitionObject - { - Name = "CondensedResinTopIcon", - RecognitionType = RecognitionTypes.TemplateMatch, - TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "condensed_resin_top_icon.png"), - RegionOfInterest = new Rect((int)(1270 * AssetScale), (int)(25 * AssetScale), (int)(520 * AssetScale), (int)(45 * AssetScale)), - DrawOnWindow = false - }.InitTemplate(); - OriginalResinTopIconRa = new RecognitionObject - { - Name = "OriginalResinTopIcon", - RecognitionType = RecognitionTypes.TemplateMatch, - TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "original_resin_top_icon.png"), - RegionOfInterest = new Rect(CaptureRect.Width - (int)(450 * AssetScale), (int)(25 * AssetScale), (int)(265 * AssetScale), (int)(45 * AssetScale)), - DrawOnWindow = false - }.InitTemplate(); + AbnormalIconRa = new RecognitionObject { Name = "AbnormalIcon", RecognitionType = RecognitionTypes.TemplateMatch, TemplateImageMat = GameTaskManager.LoadAssetImage("AutoFight", "abnormal_icon.png"), - RegionOfInterest = new Rect(0,(int)(CaptureRect.Height*0.08), (int)(CaptureRect.Width*0.04), (int)(CaptureRect.Height*0.07)), + RegionOfInterest = new Rect(0, (int)(CaptureRect.Height * 0.08), (int)(CaptureRect.Width * 0.04), (int)(CaptureRect.Height * 0.07)), DrawOnWindow = false }.InitTemplate(); - } } diff --git a/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/AutoOpenChestAssets.cs b/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/AutoOpenChestAssets.cs index 5fd596e6..fce1f847 100644 --- a/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/AutoOpenChestAssets.cs +++ b/BetterGenshinImpact/GameTask/AutoOpenChest/Assets/AutoOpenChestAssets.cs @@ -1,8 +1,8 @@ -using BetterGenshinImpact.Core.Recognition; +using BetterGenshinImpact.Core.Recognition; using BetterGenshinImpact.GameTask.Model; using OpenCvSharp; -namespace BetterGenshinImpact.GameTask.AutoFishing.Assets; +namespace BetterGenshinImpact.GameTask.AutoOpenChest.Assets; public class AutoOpenChestAssets : BaseAssets { @@ -14,7 +14,7 @@ public class AutoOpenChestAssets : BaseAssets #pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑添加 "required" 修饰符或声明为可为 null。 private AutoOpenChestAssets() : base() { - Initialization(this.systemInfo); + Initialization(systemInfo); } protected AutoOpenChestAssets(ISystemInfo systemInfo) : base(systemInfo) diff --git a/BetterGenshinImpact/GameTask/AutoOpenChest/AutoOpenChestTask.cs b/BetterGenshinImpact/GameTask/AutoOpenChest/AutoOpenChestTask.cs index 73074c0b..089b5cd5 100644 --- a/BetterGenshinImpact/GameTask/AutoOpenChest/AutoOpenChestTask.cs +++ b/BetterGenshinImpact/GameTask/AutoOpenChest/AutoOpenChestTask.cs @@ -1,8 +1,6 @@ -using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator; using BetterGenshinImpact.Core.Simulator.Extensions; -using BetterGenshinImpact.GameTask; -using BetterGenshinImpact.GameTask.AutoFishing.Assets; -using BetterGenshinImpact.GameTask.Common.BgiVision; +using BetterGenshinImpact.GameTask.AutoOpenChest.Assets; using BetterGenshinImpact.GameTask.Model.Area; using Microsoft.Extensions.Logging; using System; @@ -11,8 +9,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using static BetterGenshinImpact.GameTask.Common.TaskControl; -using static TorchSharp.torch.distributions.constraints; -namespace GameTask.AutoOpenChest; +namespace BetterGenshinImpact.GameTask.AutoOpenChest; /// /// 识别宝箱图标,走向宝箱并开启。 @@ -72,7 +69,7 @@ public class AutoOpenChestTask : ISoloTask } else { - var gap = (ra.Width / 2) - chestIcon.X; + var gap = ra.Width / 2 - chestIcon.X; int rate = 2; Simulation.SendInput.Mouse.MoveMouseBy(gap / rate, 0); } diff --git a/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs b/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs index 76472706..9d747489 100644 --- a/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs +++ b/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs @@ -1,5 +1,6 @@ using BetterGenshinImpact.Core.BgiVision; using BetterGenshinImpact.Core.Recognition; +using BetterGenshinImpact.Core.Recognition.OCR; using BetterGenshinImpact.Core.Simulator; using BetterGenshinImpact.Core.Simulator.Extensions; using BetterGenshinImpact.GameTask.AutoArtifactSalvage; @@ -398,7 +399,7 @@ public class AutoStygianOnslaughtTask : ISoloTask { // 自动刷干树脂 // 识别树脂状况 - var resinStatus = ResinStatus.RecogniseFromRegion(ra3); + var resinStatus = ResinStatus.RecogniseFromRegion(ra3, TaskContext.Instance().SystemInfo, OcrFactory.Paddle); resinStatus.Print(_logger); if (resinStatus is { CondensedResinCount: <= 0, OriginalResinCount: < 20 }) diff --git a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoDomainTests/ResinStatusTests.cs b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoDomainTests/ResinStatusTests.cs new file mode 100644 index 00000000..ed2ecd8c --- /dev/null +++ b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoDomainTests/ResinStatusTests.cs @@ -0,0 +1,44 @@ +using BetterGenshinImpact.GameTask.AutoDomain.Model; +using BetterGenshinImpact.GameTask.Model.Area; +using BetterGenshinImpact.GameTask.Model.Area.Converter; +using BetterGenshinImpact.UnitTest.CoreTests.RecognitionTests.OCRTests; +using OpenCvSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoDomainTests +{ + [Collection("Init Collection")] + public class ResinStatusTests + { + private readonly PaddleFixture paddle; + + public ResinStatusTests(PaddleFixture paddle) + { + this.paddle = paddle; + } + + [Theory] + [InlineData(@"AutoDomain\SelectRevitalization.png", 21, 0, 2, 1)] + /// + /// 测试识别四种树脂数量,数量应正确 + /// + public void RecogniseFromRegion_ResinStatusShouldBeRight(string screenshot1080p, int originalResinCount, int fragileResinCount, int condensedResinCount, int transientResinCount) + { + // + Mat mat = new Mat(@$"..\..\..\Assets\{screenshot1080p}"); + var imageRegion = new ImageRegion(mat, 0, 0, converter: new ScaleConverter(1d)); + FakeSystemInfo systemInfo = new FakeSystemInfo(new Vanara.PInvoke.RECT(0, 0, mat.Width, mat.Height), 1); + + // + var result = ResinStatus.RecogniseFromRegion(imageRegion, systemInfo, this.paddle.Get()); // todo:System.Exception : 未找到原粹树脂图标 + + // + Assert.Equal(originalResinCount, result.OriginalResinCount); + Assert.Equal(condensedResinCount, result.CondensedResinCount); + } + } +} diff --git a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/FakeSystemInfo.cs b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/FakeSystemInfo.cs similarity index 90% rename from Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/FakeSystemInfo.cs rename to Test/BetterGenshinImpact.UnitTest/GameTaskTests/FakeSystemInfo.cs index 1a05badc..209c2e33 100644 --- a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/FakeSystemInfo.cs +++ b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/FakeSystemInfo.cs @@ -1,4 +1,4 @@ -using BetterGenshinImpact.GameTask.Model; +using BetterGenshinImpact.GameTask.Model; using BetterGenshinImpact.GameTask.Model.Area; using OpenCvSharp; using System; @@ -9,7 +9,7 @@ using System.Text; using System.Threading.Tasks; using Vanara.PInvoke; -namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests +namespace BetterGenshinImpact.UnitTest.GameTaskTests { internal class FakeSystemInfo : ISystemInfo { @@ -29,7 +29,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests public RECT GameScreenSize { get; } - public double AssetScale { get; } + public double AssetScale { get; } = 1; public double ZoomOutMax1080PRatio { get; } diff --git a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/GetGridIconsTests/GridIconsAccuracyTestTaskTests.cs b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/GetGridIconsTests/GridIconsAccuracyTestTaskTests.cs index ece8e548..7297d158 100644 --- a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/GetGridIconsTests/GridIconsAccuracyTestTaskTests.cs +++ b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/GetGridIconsTests/GridIconsAccuracyTestTaskTests.cs @@ -27,8 +27,8 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.GetGridIconsTests yield return new object[] { @"GetGridIcons\FoodGrid.png", 8, true, new[] { ("苹果", 0), ("日落果", 0), ("星蕈", 0), ("泡泡桔", 0), ("烛伞蘑菇", 0), ("宝石闪闪", 4), ("咚咚", 4), ("枫达", 2), ("雾凇秋分", 4), ("蒙德土豆饼", 3), /*("爪爪土豆饼", 3), ("北地苹果焖肉", 3), ("四方和平", 3), ("盛世太平", 3), ("三彩团子", 3), ("夏祭游鱼", 3)*/} }; // todo 爪爪土豆饼被吃掉了没进训练集。。。 - yield return new object[] { @"GetGridIcons\FoodGrid_Attack.png", 8, false, new[] { ("果果软糖", 3), ("方块戏法", 3), ("「缥雨一滴」", 3), ("繁弦急管", 3), ("繁弦急管", 3), ("「簇火赞歌」", 3), ("轻策家常菜", 3), ("冒险家蛋堡", 3), ("冒险家蛋堡", 3), ("测绘员蛋堡", 3), ("串串三味", 3), ("连心面", 3), ("摩拉急速来", 3), ("双果清露", 3), ("双果清露", 3), ("双果清露", 3), ("四喜圆满", 3), ("祝圣交响乐", 3), ("满足沙拉", 2), ("满足沙拉", 2), ("至高的智慧(生活)", 2), ("摇·滚·鸡!", 2), ("岩港三鲜", 2), ("鲜鱼燉萝卜", 2), ("炸萝卜丸子", 2), ("炸萝卜丸子", 2), ("杏仁豆腐", 2), ("杏仁豆腐", 2), ("「美梦」", 2), ("凉拌薄荷", 2), ("炸肉排三明治", 2), ("唯一的真相", 2) } }; - yield return new object[] { @"GetGridIcons\MaterialGrid_TreesAndBaits.png", 8, false, new[] { ("松木", 1), ("却砂木", 1), ("竹节", 1), ("垂香木", 1), ("杉木", 1), ("梦见木", 1), ("枫木", 1), ("孔雀木", 1), ("御伽木", 1), ("辉木", 1), ("业果木", 1), ("证悟木", 1), ("枫木", 1), ("黑铜号角", 1), ("悬铃木", 1), ("白梣木", 1), ("香柏木", 1), ("白栗栎木", 1), ("灰灰楼林木", 1), ("燃爆木", 1), ("布匹", 0), ("红色染料", 0), ("黄色染料", 0), ("蓝色染料", 0), ("果酿饵", 2), ("赤糜饵", 2), ("蠕虫假饵", 2), ("飞蝇假饵", 2), ("甘露饵", 2), ("酸桔饵", 2), ("维护机关频闪诱饵", 2), ("澄晶果粒饵", 2) } }; + yield return new object[] { @"GetGridIcons\FoodGrid_Attack.png", 8, false, new[] { ("果果软糖", 3), ("方块戏法", 3), ("「缥雨一滴」", 3), ("繁弦急管", 3), ("繁弦急管", 3), ("「簇火赞歌」", 3), ("轻策家常菜", 3), ("冒险家蛋堡", 3), ("冒险家蛋堡", 3), ("测绘员蛋堡", 3), ("串串三味", 3), ("连心面", 3), ("摩拉急速来", 3), ("双果清露", 3), ("双果清露", 3), ("双果清露", 3), ("四喜圆满", 3), ("祝圣交响乐", 3), ("满足沙拉", 2), ("满足沙拉", 2), ("至高的智慧(生活)", 2), ("摇·滚·鸡!", 2), ("岩港三鲜", 2), ("鲜鱼炖萝卜", 2), ("炸萝卜丸子", 2), ("炸萝卜丸子", 2), ("杏仁豆腐", 2), ("杏仁豆腐", 2), ("「美梦」", 2), ("凉拌薄荷", 2), ("炸肉排三明治", 2), ("唯一的真相", 2) } }; + yield return new object[] { @"GetGridIcons\MaterialGrid_TreesAndBaits.png", 8, false, new[] { ("松木", 1), ("却砂木", 1), ("竹节", 1), ("垂香木", 1), ("杉木", 1), ("梦见木", 1), ("枫木", 1), ("孔雀木", 1), ("御伽木", 1), ("辉木", 1), ("业果木", 1), ("证悟木", 1), ("刺葵木", 1), ("柽木", 1), ("悬铃木", 1), ("白梣木", 1), ("香柏木", 1), ("白栗栎木", 1), ("灰灰楼林木", 1), ("燃爆木", 1), ("布匹", 0), ("红色染料", 0), ("黄色染料", 0), ("蓝色染料", 0), ("果酿饵", 2), ("赤糜饵", 2), ("蠕虫假饵", 2), ("飞蝇假饵", 2), ("甘露饵", 2), ("酸桔饵", 2), ("维护机关频闪诱饵", 2), ("澄晶果粒饵", 2) } }; // string.Join(", ",result.Select(s=>$"(\"{s.Item1}\", {s.Item2})")) }