diff --git a/BetterGenshinImpact.Test/Dataset/AvatarClassifyGen.cs b/BetterGenshinImpact.Test/Dataset/AvatarClassifyGen.cs index e3c15960..4e8798cf 100644 --- a/BetterGenshinImpact.Test/Dataset/AvatarClassifyGen.cs +++ b/BetterGenshinImpact.Test/Dataset/AvatarClassifyGen.cs @@ -19,17 +19,17 @@ public class AvatarClassifyGen // 读取基础图像 // List sideImageFiles = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "*.png", SearchOption.TopDirectoryOnly).ToList(); // 只用一个图像 - List sideImageFiles = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Chasca.png", SearchOption.TopDirectoryOnly).ToList(); - List sideImageFiles2 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Olorun.png", SearchOption.TopDirectoryOnly).ToList(); + List sideImageFiles = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_HutaoCostumeWinter.png", SearchOption.TopDirectoryOnly).ToList(); + List sideImageFiles2 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Iansan.png", SearchOption.TopDirectoryOnly).ToList(); sideImageFiles.AddRange(sideImageFiles2); - // List sideImageFiles3 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_NilouCostumeFairy.png", SearchOption.TopDirectoryOnly).ToList(); - // sideImageFiles.AddRange(sideImageFiles3); - // List sideImageFiles4 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Kachina.png", SearchOption.TopDirectoryOnly).ToList(); - // sideImageFiles.AddRange(sideImageFiles4); - // List sideImageFiles5 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Mualani.png", SearchOption.TopDirectoryOnly).ToList(); - // sideImageFiles.AddRange(sideImageFiles5); - // List sideImageFiles6 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Kinich.png", SearchOption.TopDirectoryOnly).ToList(); - // sideImageFiles.AddRange(sideImageFiles6); + List sideImageFiles3 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Citlali.png", SearchOption.TopDirectoryOnly).ToList(); + sideImageFiles.AddRange(sideImageFiles3); + List sideImageFiles4 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Lanyan.png", SearchOption.TopDirectoryOnly).ToList(); + sideImageFiles.AddRange(sideImageFiles4); + List sideImageFiles5 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_XianglingCostumeWinter.png", SearchOption.TopDirectoryOnly).ToList(); + sideImageFiles.AddRange(sideImageFiles5); + List sideImageFiles6 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Mavuika.png", SearchOption.TopDirectoryOnly).ToList(); + sideImageFiles.AddRange(sideImageFiles6); // 生成训练集 GenTo(sideImageFiles, Path.Combine(BaseDir, @"dateset\train"), 200); diff --git a/BetterGenshinImpact.Test/Dataset/AvatarClassifyTransparentGen.cs b/BetterGenshinImpact.Test/Dataset/AvatarClassifyTransparentGen.cs index 2e9ad387..5f2def11 100644 --- a/BetterGenshinImpact.Test/Dataset/AvatarClassifyTransparentGen.cs +++ b/BetterGenshinImpact.Test/Dataset/AvatarClassifyTransparentGen.cs @@ -27,9 +27,17 @@ public class AvatarClassifyTransparentGen // 读取基础图像 // List sideImageFiles = Directory.GetFiles(Path.Combine(BaseDir, SideSrcTransportDir), "*.png", SearchOption.TopDirectoryOnly).ToList(); // 只用一个图像 - List sideImageFiles = Directory.GetFiles(Path.Combine(BaseDir, SideSrcTransportDir), "UI_AvatarIcon_Side_Chasca.png", SearchOption.TopDirectoryOnly).ToList(); - List sideImageFiles2 = Directory.GetFiles(Path.Combine(BaseDir, SideSrcTransportDir), "UI_AvatarIcon_Side_Olorun.png", SearchOption.TopDirectoryOnly).ToList(); + List sideImageFiles = Directory.GetFiles(Path.Combine(BaseDir, SideSrcTransportDir), "UI_AvatarIcon_Side_HutaoCostumeWinter.png", SearchOption.TopDirectoryOnly).ToList(); + List sideImageFiles2 = Directory.GetFiles(Path.Combine(BaseDir, SideSrcTransportDir), "UI_AvatarIcon_Side_Iansan.png", SearchOption.TopDirectoryOnly).ToList(); sideImageFiles.AddRange(sideImageFiles2); + List sideImageFiles3 = Directory.GetFiles(Path.Combine(BaseDir, SideSrcTransportDir), "UI_AvatarIcon_Side_Citlali.png", SearchOption.TopDirectoryOnly).ToList(); + sideImageFiles.AddRange(sideImageFiles3); + List sideImageFiles4 = Directory.GetFiles(Path.Combine(BaseDir, SideSrcTransportDir), "UI_AvatarIcon_Side_Lanyan.png", SearchOption.TopDirectoryOnly).ToList(); + sideImageFiles.AddRange(sideImageFiles4); + List sideImageFiles5 = Directory.GetFiles(Path.Combine(BaseDir, SideSrcTransportDir), "UI_AvatarIcon_Side_XianglingCostumeWinter.png", SearchOption.TopDirectoryOnly).ToList(); + sideImageFiles.AddRange(sideImageFiles5); + List sideImageFiles6 = Directory.GetFiles(Path.Combine(BaseDir, SideSrcTransportDir), "UI_AvatarIcon_Side_Mavuika.png", SearchOption.TopDirectoryOnly).ToList(); + sideImageFiles.AddRange(sideImageFiles6); // 生成训练集 GenTo(sideImageFiles, Path.Combine(BaseDir, @"dateset\train"), 200); // 生成测试集 diff --git a/BetterGenshinImpact/Assets/Model/Common/avatar_side_classify_sim.onnx b/BetterGenshinImpact/Assets/Model/Common/avatar_side_classify_sim.onnx index 07eb0189..301c9ee5 100644 Binary files a/BetterGenshinImpact/Assets/Model/Common/avatar_side_classify_sim.onnx and b/BetterGenshinImpact/Assets/Model/Common/avatar_side_classify_sim.onnx differ diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 18bcb6d3..fd54e030 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -10,7 +10,7 @@ true Assets\Images\logo.ico BetterGI - 0.38.1 + 0.39.1 x64 embedded @@ -128,6 +128,9 @@ Always + + Always + Always diff --git a/BetterGenshinImpact/Core/Simulator/Simulation.cs b/BetterGenshinImpact/Core/Simulator/Simulation.cs index 9939ef9f..5f56046d 100644 --- a/BetterGenshinImpact/Core/Simulator/Simulation.cs +++ b/BetterGenshinImpact/Core/Simulator/Simulation.cs @@ -1,5 +1,8 @@ using Fischless.WindowsInput; using System; +using BetterGenshinImpact.GameTask.Common; +using Microsoft.Extensions.Logging; +using Vanara.PInvoke; namespace BetterGenshinImpact.Core.Simulator; @@ -13,4 +16,26 @@ public class Simulation { return new PostMessageSimulator(hWnd); } -} + + public static void ReleaseAllKey() + { + foreach (User32.VK key in Enum.GetValues(typeof(User32.VK))) + { + // 检查键是否被按下 + if (IsKeyDown(key)) // 强制转换 VK 枚举为 int + { + TaskControl.Logger.LogDebug($"解除{key}的按下状态."); + SendInput.Keyboard.KeyUp(key); + } + } + } + + private static bool IsKeyDown(User32.VK key) + { + // 获取按键状态 + var state = User32.GetAsyncKeyState((int)key); + + // 检查高位是否为 1(表示按键被按下) + return (state & 0x8000) != 0; + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs index 647c7b26..75065796 100644 --- a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs +++ b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs @@ -98,7 +98,6 @@ public class AutoDomainTask : ISoloTask } } } - await Delay(2000, ct); @@ -118,13 +117,13 @@ public class AutoDomainTask : ISoloTask var combatScenes = new CombatScenes().InitializeTeam(CaptureToRectArea()); // 前置进入秘境 - EnterDomain(); + await EnterDomain(); for (var i = 0; i < _taskParam.DomainRoundNum; i++) { // 0. 关闭秘境提示 Logger.LogDebug("0. 关闭秘境提示"); - CloseDomainTip(); + await CloseDomainTip(); // 队伍没初始化成功则重试 RetryTeamInit(combatScenes); @@ -221,15 +220,37 @@ public class AutoDomainTask : ISoloTask await Delay(1000, _ct); await Bv.WaitForMainUi(_ct); await Delay(1000, _ct); - var walkKey = User32.VK.VK_W; - if (MapLazyAssets.Instance.DomainBackwardList.Contains(_taskParam.DomainName)) + + if ("芬德尼尔之顶".Equals(_taskParam.DomainName)) { - walkKey = User32.VK.VK_S; + Simulation.SendInput.Keyboard.KeyDown(VK.VK_S); + Thread.Sleep(3000); + Simulation.SendInput.Keyboard.KeyUp(VK.VK_S); + } + else if ("无妄引咎密宫".Equals(_taskParam.DomainName)) + { + Simulation.SendInput.Keyboard.KeyDown(VK.VK_W); + Thread.Sleep(500); + Simulation.SendInput.Keyboard.KeyUp(VK.VK_W); + Thread.Sleep(100); + Simulation.SendInput.Keyboard.KeyDown(VK.VK_A); + Thread.Sleep(1600); + Simulation.SendInput.Keyboard.KeyUp(VK.VK_A); + } + else if ("苍白的遗荣".Equals(_taskParam.DomainName)) + { + Simulation.SendInput.Keyboard.KeyDown(VK.VK_W); + Thread.Sleep(1000); + Simulation.SendInput.Keyboard.KeyUp(VK.VK_W); + } + else + { + Simulation.SendInput.Keyboard.KeyDown(VK.VK_W); + Thread.Sleep(3000); + Simulation.SendInput.Keyboard.KeyUp(VK.VK_W); } - Simulation.SendInput.Keyboard.KeyDown(walkKey); - Thread.Sleep(3500); - Simulation.SendInput.Keyboard.KeyUp(walkKey); + await Delay(3000, _ct); // 站稳 } else { @@ -256,7 +277,7 @@ public class AutoDomainTask : ISoloTask return true; } - private void EnterDomain() + private async Task EnterDomain() { var fightAssets = AutoFightContext.Instance.FightAssets; @@ -267,7 +288,7 @@ public class AutoDomainTask : ISoloTask Simulation.SendInput.Keyboard.KeyPress(VK.VK_F); Logger.LogInformation("自动秘境:{Text}", "进入秘境"); // 秘境开门动画 5s - Sleep(5000, _ct); + await Delay(5000, _ct); } int retryTimes = 0, clickCount = 0; @@ -281,14 +302,14 @@ public class AutoDomainTask : ISoloTask clickCount++; } - Sleep(1500, _ct); + await Delay(1500, _ct); } // 载入动画 - Sleep(3000, _ct); + await Delay(3000, _ct); } - private void CloseDomainTip() + private async Task CloseDomainTip() { // 2min的载入时间总够了吧 var retryTimes = 0; @@ -298,16 +319,16 @@ public class AutoDomainTask : ISoloTask using var cactRectArea = CaptureToRectArea().Find(AutoFightContext.Instance.FightAssets.ClickAnyCloseTipRa); if (!cactRectArea.IsEmpty()) { - Sleep(1000, _ct); + await Delay(1000, _ct); cactRectArea.Click(); break; } // todo 添加小地图角标位置检测 防止有人手点了 - Sleep(1000, _ct); + await Delay(1000, _ct); } - Sleep(1500, _ct); + await Delay(1500, _ct); } private List FindCombatScriptAndSwitchAvatar(CombatScenes combatScenes) diff --git a/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json b/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json index efef1435..972f1f41 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json +++ b/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json @@ -1620,7 +1620,8 @@ "卡齐纳", "卡齐那", "卡其那", - "冲天钻钻" + "冲天钻钻", + "岩莉莉" ], "burstCD": 18, "id": "10000100", @@ -1634,7 +1635,8 @@ "基尼奇", "Kinich", "基哥", - "基尼齐" + "基尼齐", + "蜘蛛侠" ], "burstCD": 18, "id": "10000101", @@ -1684,7 +1686,8 @@ "恰斯卡", "Chasca", "武卡", - "调停人" + "调停人", + "鸟人" ], "burstCD": 15, "id": "10000104", @@ -1696,9 +1699,10 @@ { "alias": [ "欧洛伦", - "Olorun", + "Ororon", "庇笛", "孙子", + "大孙子", "蝙蝠侠" ], "burstCD": 15, @@ -1707,5 +1711,55 @@ "nameEn": "Olorun", "skillCD": 15, "weapon": "12" + }, + { + "alias": [ + "玛薇卡", + "Mavuika", + "火神", + "马薇卡", + "玛维卡", + "马维卡" + ], + "burstCD": 18, + "id": "10000106", + "name": "玛薇卡", + "nameEn": "Mavuika", + "skillCD": 15, + "weapon": "11" + }, + { + "alias": [ + "茜特菈莉", + "Citlali", + "西特菈莉", + "西特拉莉", + "茜特拉莉", + "西特拉利", + "黑曜石奶奶", + "黑曜石", + "奶奶", + "老伴" + ], + "burstCD": 15, + "id": "10000107", + "name": "茜特菈莉", + "nameEn": "Citlali", + "skillCD": 16, + "weapon": "10" + }, + { + "alias": [ + "蓝砚", + "蓝燕", + "兰砚", + "兰燕" + ], + "burstCD": 15, + "id": "10000108", + "name": "蓝砚", + "nameEn": "Lanyan", + "skillCD": 16, + "weapon": "10" } ] \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoGeniusInvokation/Assets/tcg_character_card.json b/BetterGenshinImpact/GameTask/AutoGeniusInvokation/Assets/tcg_character_card.json index f3ca531d..ec93435d 100644 --- a/BetterGenshinImpact/GameTask/AutoGeniusInvokation/Assets/tcg_character_card.json +++ b/BetterGenshinImpact/GameTask/AutoGeniusInvokation/Assets/tcg_character_card.json @@ -1787,6 +1787,75 @@ } ] }, + { + "id": 1214, + "nameEn": "mualani", + "type": "character", + "name": "玛拉妮", + "hp": 10, + "energy": 2, + "element": "水元素", + "weapon": "法器", + "skills": [ + { + "nameEn": "cooling_treatment", + "name": "降温处理", + "skillTag": [ + "普通攻击" + ], + "cost": [ + { + "id": 1102, + "nameEn": "hydro", + "type": "水元素", + "count": 1 + }, + { + "id": 1109, + "nameEn": "unaligned_element", + "type": "无色元素", + "count": 2 + } + ] + }, + { + "nameEn": "surfshark_wavebreaker", + "name": "踏鲨破浪", + "skillTag": [ + "元素战技" + ], + "cost": [ + { + "id": 1102, + "nameEn": "hydro", + "type": "水元素", + "count": 2 + } + ] + }, + { + "nameEn": "boomsharkalaka", + "name": "爆瀑飞弹", + "skillTag": [ + "元素爆发" + ], + "cost": [ + { + "id": 1102, + "nameEn": "hydro", + "type": "水元素", + "count": 3 + }, + { + "id": 1110, + "nameEn": "energy", + "type": "充能", + "count": 2 + } + ] + } + ] + }, { "id": 1301, "nameEn": "diluc", @@ -3482,6 +3551,75 @@ } ] }, + { + "id": 1412, + "nameEn": "clorinde", + "type": "character", + "name": "克洛琳德", + "hp": 10, + "energy": 2, + "element": "雷元素", + "weapon": "单手剑", + "skills": [ + { + "nameEn": "oath_of_hunting_shadows", + "name": "逐影之誓", + "skillTag": [ + "普通攻击" + ], + "cost": [ + { + "id": 1104, + "nameEn": "electro", + "type": "雷元素", + "count": 1 + }, + { + "id": 1109, + "nameEn": "unaligned_element", + "type": "无色元素", + "count": 2 + } + ] + }, + { + "nameEn": "hunters_vigil", + "name": "狩夜之巡", + "skillTag": [ + "元素战技" + ], + "cost": [ + { + "id": 1104, + "nameEn": "electro", + "type": "雷元素", + "count": 2 + } + ] + }, + { + "nameEn": "last_lightfall", + "name": "残光将终", + "skillTag": [ + "元素爆发" + ], + "cost": [ + { + "id": 1104, + "nameEn": "electro", + "type": "雷元素", + "count": 3 + }, + { + "id": 1110, + "nameEn": "energy", + "type": "充能", + "count": 2 + } + ] + } + ] + }, { "id": 1501, "nameEn": "sucrose", @@ -7220,6 +7358,75 @@ } ] }, + { + "id": 2603, + "nameEn": "golden_wolflord", + "type": "character", + "name": "黄金王兽", + "hp": 10, + "energy": 2, + "element": "岩元素", + "weapon": "其他武器", + "skills": [ + { + "nameEn": "wolflords_strike", + "name": "王狼直击", + "skillTag": [ + "普通攻击" + ], + "cost": [ + { + "id": 1106, + "nameEn": "geo", + "type": "岩元素", + "count": 1 + }, + { + "id": 1109, + "nameEn": "unaligned_element", + "type": "无色元素", + "count": 2 + } + ] + }, + { + "nameEn": "howling_riftcall", + "name": "兽境轰召", + "skillTag": [ + "元素战技" + ], + "cost": [ + { + "id": 1106, + "nameEn": "geo", + "type": "岩元素", + "count": 3 + } + ] + }, + { + "nameEn": "golden_cankerbind", + "name": "黄金侵绞", + "skillTag": [ + "元素爆发" + ], + "cost": [ + { + "id": 1106, + "nameEn": "geo", + "type": "岩元素", + "count": 3 + }, + { + "id": 1110, + "nameEn": "energy", + "type": "充能", + "count": 2 + } + ] + } + ] + }, { "id": 2701, "nameEn": "jadeplume_terrorshroom", @@ -7450,74 +7657,5 @@ "cost": [] } ] - }, - { - "id": 4608, - "nameEn": "golden_wolflord", - "type": "character", - "name": "黄金王兽", - "hp": 40, - "energy": 2, - "element": "岩元素", - "weapon": "其他武器", - "skills": [ - { - "nameEn": "wolflords_strike", - "name": "王狼直击", - "skillTag": [ - "普通攻击" - ], - "cost": [ - { - "id": 1106, - "nameEn": "geo", - "type": "岩元素", - "count": 1 - }, - { - "id": 1109, - "nameEn": "unaligned_element", - "type": "无色元素", - "count": 2 - } - ] - }, - { - "nameEn": "howling_riftcall", - "name": "兽境轰召", - "skillTag": [ - "元素战技" - ], - "cost": [ - { - "id": 1106, - "nameEn": "geo", - "type": "岩元素", - "count": 3 - } - ] - }, - { - "nameEn": "golden_cankerbind", - "name": "黄金侵绞", - "skillTag": [ - "元素爆发" - ], - "cost": [ - { - "id": 1106, - "nameEn": "geo", - "type": "岩元素", - "count": 3 - }, - { - "id": 1110, - "nameEn": "energy", - "type": "充能", - "count": 2 - } - ] - } - ] } ] \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/album_music_complate.png b/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/album_music_complate.png new file mode 100644 index 00000000..8133cabe Binary files /dev/null and b/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/album_music_complate.png differ diff --git a/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/btn_list.png b/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/btn_list.png new file mode 100644 index 00000000..4d61b9c8 Binary files /dev/null and b/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/btn_list.png differ diff --git a/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/btn_pause.png b/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/btn_pause.png new file mode 100644 index 00000000..faf82997 Binary files /dev/null and b/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/btn_pause.png differ diff --git a/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/ui_left_top_album_icon.png b/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/ui_left_top_album_icon.png new file mode 100644 index 00000000..cd36fbbb Binary files /dev/null and b/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/1920x1080/ui_left_top_album_icon.png differ diff --git a/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/AutoMusicAssets.cs b/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/AutoMusicAssets.cs new file mode 100644 index 00000000..b78b03a6 --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoMusicGame/Assets/AutoMusicAssets.cs @@ -0,0 +1,46 @@ +using BetterGenshinImpact.Core.Recognition; +using BetterGenshinImpact.GameTask.Model; +using BetterGenshinImpact.Helpers.Extensions; +using OpenCvSharp; + +namespace BetterGenshinImpact.GameTask.AutoMusicGame.Assets; + +public class AutoMusicAssets : BaseAssets +{ + public RecognitionObject UiLeftTopAlbumIcon; + public RecognitionObject BtnPause; + public RecognitionObject AlbumMusicComplate; + public RecognitionObject BtnList; + + private AutoMusicAssets() + { + UiLeftTopAlbumIcon = new RecognitionObject + { + Name = "UiLeftTopAlbumIcon", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage(@"AutoMusicGame", "ui_left_top_album_icon.png"), + RegionOfInterest = new Rect(0, 0, (int)(150 * AssetScale), (int)(120 * AssetScale)), + }.InitTemplate(); + BtnPause = new RecognitionObject + { + Name = "BtnPause", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage(@"AutoMusicGame", "btn_pause.png"), + RegionOfInterest = CaptureRect.CutRightTop(0.2, 0.2), + }.InitTemplate(); + AlbumMusicComplate = new RecognitionObject + { + Name = "AlbumMusicComplate", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage(@"AutoMusicGame", "album_music_complate.png"), + RegionOfInterest = new Rect( (int)(900 * AssetScale),(int)(320 * AssetScale), (int)(100 * AssetScale), (int)(80 * AssetScale)), + }.InitTemplate(); + BtnList = new RecognitionObject + { + Name = "BtnList", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage(@"AutoMusicGame", "btn_list.png"), + RegionOfInterest = CaptureRect.CutRightBottom(0.4, 0.2), + }.InitTemplate(); + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoMusicGame/AutoAlbumTask.cs b/BetterGenshinImpact/GameTask/AutoMusicGame/AutoAlbumTask.cs new file mode 100644 index 00000000..d025dde7 --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoMusicGame/AutoAlbumTask.cs @@ -0,0 +1,102 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using BetterGenshinImpact.GameTask.AutoMusicGame.Assets; +using BetterGenshinImpact.GameTask.Common.BgiVision; +using BetterGenshinImpact.GameTask.Model.Area; +using Microsoft.Extensions.Logging; +using static BetterGenshinImpact.GameTask.Common.TaskControl; + +namespace BetterGenshinImpact.GameTask.AutoMusicGame; + +/// +/// 自动音乐专辑 +/// +public class AutoAlbumTask(AutoMusicGameParam taskParam) : ISoloTask +{ + public string Name => "自动音游专辑"; + + private AutoMusicGameTask _autoMusicGameTask = new AutoMusicGameTask(taskParam); + + public async Task Start(CancellationToken ct) + { + try + { + AutoMusicGameTask.Init(); + Logger.LogInformation("开始自动演奏整个专辑未完成的音乐"); + await StartOneAlbum(ct); + } + catch (Exception e) + { + Logger.LogError("自动音乐专辑任务异常:{Msg}", e.Message); + } + } + + public async Task StartOneAlbum(CancellationToken ct) + { + using var iconRa = CaptureToRectArea().Find(AutoMusicAssets.Instance.UiLeftTopAlbumIcon); + if (!iconRa.IsExist()) + { + throw new Exception("当前未处于专辑界面,请在专辑界面运行本任务"); + } + + // 12个音乐 + for (int i = 0; i < 13; i++) + { + + + using var doneRa = CaptureToRectArea().Find(AutoMusicAssets.Instance.AlbumMusicComplate); + if (doneRa.IsExist()) + { + Logger.LogInformation("当前乐曲{Num}所有奖励已领取,切换下一首", i + 1); + GameCaptureRegion.GameRegion1080PPosClick(310, 220); + await Delay(800, ct); + continue; + } + + Logger.LogInformation("当前乐曲{Num}存在未领取奖励,前往演奏", i + 1); + Bv.ClickWhiteConfirmButton(CaptureToRectArea()); + await Delay(800, ct); + // 点击传说 + GameCaptureRegion.GameRegion1080PPosClick(1400, 600); + await Delay(200, ct); + // 演奏 + Bv.ClickWhiteConfirmButton(CaptureToRectArea()); + await Delay(500, ct); + + CancellationTokenSource cts = new(); + ct.Register(cts.Cancel); + + // 演奏结束检查任务 + var checkTask = Task.Run(async () => + { + while (!cts.Token.IsCancellationRequested) + { + await Delay(5000, ct); // n秒检查一次 + using var listRa = CaptureToRectArea().Find(AutoMusicAssets.Instance.BtnList); + if (listRa.IsExist()) + { + listRa.Click(); + return; + } + } + }, cts.Token); + + // 演奏任务 + var musicTask = _autoMusicGameTask.StartWithOutInit(cts.Token); + + // 等待任意一个任务完成 + await Task.WhenAny(checkTask, musicTask); + await cts.CancelAsync(); + Logger.LogInformation("当前乐曲{Num}演奏结束", i + 1); + await Delay(2000, ct); + + await Bv.WaitUntilFound(AutoMusicAssets.Instance.UiLeftTopAlbumIcon, ct); + Logger.LogInformation("切换下一首"); + GameCaptureRegion.GameRegion1080PPosClick(310, 220); + await Delay(800, ct); + } + + Logger.LogInformation("当前专辑所有乐曲演奏结束"); + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoMusicGame/AutoMusicGameTask.cs b/BetterGenshinImpact/GameTask/AutoMusicGame/AutoMusicGameTask.cs index 60d6ed4d..f0ed06d1 100644 --- a/BetterGenshinImpact/GameTask/AutoMusicGame/AutoMusicGameTask.cs +++ b/BetterGenshinImpact/GameTask/AutoMusicGame/AutoMusicGameTask.cs @@ -15,47 +15,73 @@ public class AutoMusicGameTask(AutoMusicGameParam taskParam) : ISoloTask { public string Name => "自动音游"; + + // private readonly ConcurrentDictionary _keyX = new() + // { + // [User32.VK.VK_A] = 417, + // [User32.VK.VK_S] = 632, + // [User32.VK.VK_D] = 846, + // [User32.VK.VK_J] = 1065, + // [User32.VK.VK_K] = 1282, + // [User32.VK.VK_L] = 1500 + // }; + // + // private readonly int _keyY = 916; + + private readonly ConcurrentDictionary _keyX = new() { [User32.VK.VK_A] = 417, - [User32.VK.VK_S] = 632, - [User32.VK.VK_D] = 846, - [User32.VK.VK_J] = 1065, - [User32.VK.VK_K] = 1282, - [User32.VK.VK_L] = 1500 + [User32.VK.VK_S] = 628, + [User32.VK.VK_D] = 844, + [User32.VK.VK_J] = 1061, + [User32.VK.VK_K] = 1277, + [User32.VK.VK_L] = 1493 }; - private readonly int _keyY = 916; + private readonly int _keyY = 921; private readonly IntPtr _hWnd = TaskContext.Instance().GameHandle; - public Task Start(CancellationToken ct) + public async Task Start(CancellationToken ct) { Init(); - - var assetScale = TaskContext.Instance().SystemInfo.AssetScale; - var taskFactory = new TaskFactory(); - var taskList = new List(); - - // 计算按键位置 - var gameCaptureRegion = CaptureToRectArea(); - - foreach (var keyValuePair in _keyX) - { - var (x, y) = gameCaptureRegion.ConvertPositionToGameCaptureRegion((int)(keyValuePair.Value * assetScale), (int)(_keyY * assetScale)); - // 添加任务 - taskList.Add(taskFactory.StartNew(() => DoWhitePressWin32(ct, keyValuePair.Key, new Point(x, y)))); - } - - Task.WaitAll([.. taskList]); - return Task.CompletedTask; + await StartWithOutInit(ct); } - private void DoWhitePressWin32(CancellationToken ct, User32.VK key, Point point) + public async Task StartWithOutInit(CancellationToken ct) + { + try + { + Logger.LogInformation("开始自动演奏"); + var assetScale = TaskContext.Instance().SystemInfo.AssetScale; + // var taskFactory = new TaskFactory(); + var taskList = new List(); + + // 计算按键位置 + var gameCaptureRegion = CaptureToRectArea(); + + foreach (var keyValuePair in _keyX) + { + var (x, y) = gameCaptureRegion.ConvertPositionToGameCaptureRegion((int)(keyValuePair.Value * assetScale), (int)(_keyY * assetScale)); + // 添加任务 + taskList.Add(Task.Run(async () => await DoWhitePressWin32(ct, keyValuePair.Key, new Point(x, y)), ct)); + } + + await Task.WhenAll(taskList); + } + finally + { + Simulation.ReleaseAllKey(); + Logger.LogInformation("结束自动演奏"); + } + } + + private async Task DoWhitePressWin32(CancellationToken ct, User32.VK key, Point point) { while (!ct.IsCancellationRequested) { - Thread.Sleep(10); + await Task.Delay(5, ct); // Stopwatch sw = new(); // sw.Start(); var hdc = User32.GetDC(_hWnd); @@ -67,7 +93,7 @@ public class AutoMusicGameTask(AutoMusicGameParam taskParam) : ISoloTask KeyDown(key); while (!ct.IsCancellationRequested) { - Thread.Sleep(10); + await Task.Delay(5, ct); hdc = User32.GetDC(_hWnd); c = Gdi32.GetPixel(hdc, point.X, point.Y); Gdi32.DeleteDC(hdc); @@ -76,6 +102,7 @@ public class AutoMusicGameTask(AutoMusicGameParam taskParam) : ISoloTask break; } } + KeyUp(key); } @@ -84,6 +111,121 @@ public class AutoMusicGameTask(AutoMusicGameParam taskParam) : ISoloTask } } + // private async Task DoWhitePressWin32Default(CancellationToken ct, User32.VK key, Point point) + // { + // while (!ct.IsCancellationRequested) + // { + // await Task.Delay(10, ct); + // var c = GetPixel(point.X, point.Y); + // + // if (c.G < 220) + // { + // KeyDown(key); + // while (!ct.IsCancellationRequested) + // { + // Thread.Sleep(10); + // c = GetPixel(point.X, point.Y); + // if (c.G >= 230 && c.G != 255) + // { + // if (point.X == 417) + // { + // Debug.WriteLine("打断颜色:" + c.R + "," + c.G + "," + c.B); + // } + // + // break; + // } + // } + // + // KeyUp(key); + // } + // } + // } + + // private async Task DoWhitePressWin32Default(CancellationToken ct, User32.VK key, Point point) + // { + // while (!ct.IsCancellationRequested) + // { + // await Task.Delay(5, ct); + // var color = GetPixel(point.X, point.Y); + // int r = color.R, g = color.G, b = color.B; + // + // if (r >= 140 && r <= 255 && g >= 100 && g <= 170 && b >= 230 && b <= 255) + // { + // // 按下按键 + // KeyDown(key); + // + // int z1 = 0; + // while (z1 < 3) + // { + // await Task.Delay(5, ct); + // color = GetPixel(point.X, point.Y); + // int r1 = color.R, g1 = color.G, b1 = color.B; + // var color2 = GetPixel(point.X + 2, point.Y + 2); + // int r11 = color2.R, g11 = color2.G, b11 = color2.B; + // + // if ((r1 >= 140 && r1 <= 255 && g1 >= 100 && g1 <= 170) || (r11 >= 140 && r11 <= 255 && g11 >= 100 && g11 <= 170)) + // { + // continue; + // } + // + // z1++; + // } + // + // Console.WriteLine($"{key} purple1 {r} {g} {b}"); + // + // int z2 = 0; + // while (z2 < 10) + // { + // await Task.Delay(5, ct); + // color = GetPixel(point.X, point.Y); + // int r1 = color.R, g1 = color.G, b1 = color.B; + // var color2 = GetPixel(point.X + 2, point.Y + 2); + // int r11 = color2.R, g11 = color2.G, b11 = color2.B; + // + // if (g1 >= 100 && g1 <= 170 || g11 >= 100 && g11 <= 170) + // { + // continue; + // } + // + // z2++; + // } + // + // Console.WriteLine($"{key} purple - 紫键结束 {r} {g} {b}"); + // KeyUp(key); + // } + // + // if (r >= 230 && r <= 255 && g >= 170 && g <= 210 && b >= 50 && b <= 120) + // { + // KeyDown(key); + // + // var color2 = GetPixel(point.X, point.Y); + // int r2 = color2.R, g2 = color2.G, b2 = color2.B; + // + // + // while (g2 >= 170 && g2 <= 210 && b2 >= 50 && b2 <= 120) + // { + // + // await Task.Delay(5, ct); + // color2 = GetPixel(point.X, point.Y); + // r2 = color2.R; + // g2 = color2.G; + // b2 = color2.B; + // } + // + // KeyUp(key); + // } + // } + // } + + private COLORREF GetPixel(int x, int y) + { + var hdc = User32.GetDC(_hWnd); + var c = Gdi32.GetPixel(hdc, x, y); + Gdi32.DeleteDC(hdc); + return c; + } + + private void KeyUp(User32.VK key) { Simulation.SendInput.Keyboard.KeyUp(key); @@ -94,17 +236,21 @@ public class AutoMusicGameTask(AutoMusicGameParam taskParam) : ISoloTask Simulation.SendInput.Keyboard.KeyDown(key); } - private void Init() + public static void Init() { LogScreenResolution(); } - private void LogScreenResolution() + public static void LogScreenResolution() { var gameScreenSize = SystemControl.GetGameScreenRect(TaskContext.Instance().GameHandle); if (gameScreenSize.Width * 9 != gameScreenSize.Height * 16) { - Logger.LogWarning("游戏窗口分辨率不是 16:9 !当前分辨率为 {Width}x{Height} , 非 16:9 分辨率的游戏可能无法正常使用自动活动音游功能 !", gameScreenSize.Width, gameScreenSize.Height); + Logger.LogError("游戏窗口分辨率不是 16:9 !当前分辨率为 {Width}x{Height} , 非 16:9 分辨率的游戏无法正常使用自动活动音游功能 !", gameScreenSize.Width, gameScreenSize.Height); + throw new Exception("游戏窗口分辨率不是 16:9"); } + + Logger.LogInformation("{Name}:回到游戏主界面时记得关闭自动音游任务!", "千音雅集"); + Logger.LogWarning("{Name}:默认的样式“轻漾涟漪”是{No}的!需要手动完成几首曲目获得{Money}千音币后兑换并使用胡桃样式“{Hutao}”!", "千音雅集", "不可用", 600, "疏影引蝶映梅红"); } -} +} \ No newline at end of file diff --git a/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml b/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml index 056568c6..ba03236c 100644 --- a/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml +++ b/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml @@ -1176,7 +1176,7 @@ --> - + @@ -1188,7 +1188,7 @@ + + + + + + + + + + + + + + + 进入专辑界面使用,自动演奏未完成乐曲 - + + 点击查看使用教程 + + + + + +