From 1e57bfcf181ad0d3f2937070dd1211bf2904d0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=90?= <121607261+jiegedabaobei@users.noreply.github.com> Date: Sun, 16 Nov 2025 00:54:36 +0800 Subject: [PATCH 01/73] =?UTF-8?q?=E6=97=B6=E7=9E=AC=E6=93=8D=E4=BD=9C=20(#?= =?UTF-8?q?2469)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/GameTask/Common/Job/SetTimeTask.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/BetterGenshinImpact/GameTask/Common/Job/SetTimeTask.cs b/BetterGenshinImpact/GameTask/Common/Job/SetTimeTask.cs index a8524d5b..861e5e55 100644 --- a/BetterGenshinImpact/GameTask/Common/Job/SetTimeTask.cs +++ b/BetterGenshinImpact/GameTask/Common/Job/SetTimeTask.cs @@ -84,9 +84,10 @@ public class SetTimeTask // 取消动画函数 private async Task CancelAnimation(CancellationToken ct) { - GameCaptureRegion.GameRegion1080PPosClick(200, 200); - await Delay(5, ct); - GameCaptureRegion.GameRegion1080PPosClick(200, 200); + GameCaptureRegion.GameRegion1080PPosMove(200, 200); + Simulation.SendInput.Mouse.LeftButtonDown(); + await Delay(10, ct); + Simulation.SendInput.Mouse.LeftButtonUp(); } double[] GetPosition(double r, double index) From 6f657aa1fe0b8ed3473d6db4a6663f491898ffdd Mon Sep 17 00:00:00 2001 From: ShadowLemoon <119576779+ShadowLemoon@users.noreply.github.com> Date: Sun, 16 Nov 2025 00:55:33 +0800 Subject: [PATCH 02/73] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=88=86=E8=A7=A3=E5=9C=A3=E9=81=97=E7=89=A9=E7=9A=84?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=B5=81=E7=A8=8B=20(#2467)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/Windows/ArtifactOcrDialog.xaml.cs | 33 ++++++++++++------- .../Pages/TaskSettingsPageViewModel.cs | 2 +- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/BetterGenshinImpact/View/Windows/ArtifactOcrDialog.xaml.cs b/BetterGenshinImpact/View/Windows/ArtifactOcrDialog.xaml.cs index ec985d59..b0f783e2 100644 --- a/BetterGenshinImpact/View/Windows/ArtifactOcrDialog.xaml.cs +++ b/BetterGenshinImpact/View/Windows/ArtifactOcrDialog.xaml.cs @@ -5,6 +5,7 @@ using BetterGenshinImpact.GameTask.Common; using BetterGenshinImpact.Helpers.Extensions; using BetterGenshinImpact.Helpers.Ui; using BetterGenshinImpact.ViewModel.Pages; +using Microsoft.Extensions.Logging; using OpenCvSharp; using System; using System.Globalization; @@ -23,6 +24,7 @@ public partial class ArtifactOcrDialog private readonly double heightRatio; private readonly string? javaScript; private readonly AutoArtifactSalvageTask autoArtifactSalvageTask; + public static ILogger Logger { get; } = App.GetLogger(); public ArtifactOcrDialog(double xRatio, double yRatio, double widthRatio, double heightRatio, string title, string? javaScript = null) { @@ -37,15 +39,17 @@ public partial class ArtifactOcrDialog SourceInitialized += (s, e) => WindowHelper.TryApplySystemBackdrop(this); MyTitleBar.Title = title; - - _ = CaptureAsync(); } - public async Task CaptureAsync() + public async Task CaptureAsync() { // 没启动时候,启动截图器 var homePageViewModel = App.GetService(); - if (!homePageViewModel!.TaskDispatcherEnabled) { await homePageViewModel.OnStartTriggerAsync(); } + if (!homePageViewModel!.TaskDispatcherEnabled) + { + _ = homePageViewModel.OnStartTriggerAsync(); + return false; + } using var ra = TaskControl.CaptureToRectArea(); using var card = ra.DeriveCrop(new OpenCvSharp.Rect((int)(ra.Width * xRatio), (int)(ra.Height * yRatio), (int)(ra.Width * widthRatio), (int)(ra.Height * heightRatio))); @@ -57,27 +61,35 @@ public partial class ArtifactOcrDialog try { - ArtifactStat artifact = this.autoArtifactSalvageTask.GetArtifactStat(card.SrcMat, OcrFactory.Paddle, out string allText); + // 将CPU密集的OCR操作放到后台线程执行 + var (artifact, allText) = await Task.Run(() => + { + ArtifactStat art = this.autoArtifactSalvageTask.GetArtifactStat(card.SrcMat, OcrFactory.Paddle, out string text); + return (art, text); + }); + // 回到UI线程更新界面 this.TxtRecognized.Text = allText; this.ModelStructure.Text = artifact.ToStructuredString(); if (this.javaScript != null) { - bool isMatch = Task.Run(() => AutoArtifactSalvageTask.IsMatchJavaScript(artifact, this.javaScript)).Result; + bool isMatch = await AutoArtifactSalvageTask.IsMatchJavaScript(artifact, this.javaScript); this.RegexResult.Text = isMatch ? "匹配" : "不匹配"; } } catch (Exception e) { - await HandleOcrExceptionAsync(e, card.SrcMat); + _ = Task.Run(() => HandleOcrExceptionAsync(e, card.SrcMat)); } + return true; } private static async Task HandleOcrExceptionAsync(Exception e, Mat srcMat) { - var result = ThemedMessageBox.Error( - $"{e.Message}\n\n是否保存该圣遗物截图?(至log/autoArtifactSalvageException/)", - "异常处理", + Logger.LogError(e, "自动分解圣遗物-OCR识别异常"); + var result = await ThemedMessageBox.ErrorAsync( + $"{e.Message}\n是否保存该圣遗物截图?(至log/autoArtifactSalvageException/)", + "识别失败", MessageBoxButton.YesNo, MessageBoxResult.No ); @@ -89,7 +101,6 @@ public partial class ArtifactOcrDialog string filePath = Path.Combine(directory, $"{DateTime.Now:yyyyMMddHHmmss}_GetArtifactStat.png"); Cv2.ImWrite(filePath, srcMat); } - await Task.CompletedTask; } private async void BtnOkClick(object sender, RoutedEventArgs e) diff --git a/BetterGenshinImpact/ViewModel/Pages/TaskSettingsPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/TaskSettingsPageViewModel.cs index ea85b0da..e23841bd 100644 --- a/BetterGenshinImpact/ViewModel/Pages/TaskSettingsPageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/TaskSettingsPageViewModel.cs @@ -555,7 +555,7 @@ public partial class TaskSettingsPageViewModel : ViewModel private async Task OnOpenArtifactSalvageTestOCRWindow() { ArtifactOcrDialog ocrDialog = new ArtifactOcrDialog(0.70, 0.112, 0.275, 0.50, "圣遗物分解", this.Config.AutoArtifactSalvageConfig.JavaScript); - ocrDialog.ShowDialog(); + if (await ocrDialog.CaptureAsync()) { ocrDialog.ShowDialog(); } } [RelayCommand] From 75835566d9885404444af775f70aa056a710a404 Mon Sep 17 00:00:00 2001 From: ShadowLemoon <119576779+ShadowLemoon@users.noreply.github.com> Date: Sun, 16 Nov 2025 00:55:51 +0800 Subject: [PATCH 03/73] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=BB=84=E8=AE=BE=E7=BD=AE=E6=97=A0=E6=B3=95=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E9=AB=98=E5=BA=A6=20(#2468)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewModel/Pages/ScriptControlViewModel.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/BetterGenshinImpact/ViewModel/Pages/ScriptControlViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/ScriptControlViewModel.cs index e798bb38..3b3500e5 100644 --- a/BetterGenshinImpact/ViewModel/Pages/ScriptControlViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/ScriptControlViewModel.cs @@ -315,6 +315,7 @@ public partial class ScriptControlViewModel : ViewModel Owner = Application.Current.MainWindow, WindowStartupLocation = WindowStartupLocation.CenterOwner, }; + uiMessageBox.SourceInitialized += (s, e) => WindowHelper.TryApplySystemBackdrop(uiMessageBox); void OnQuestionButtonOnClick(object sender, RoutedEventArgs args) { @@ -2011,8 +2012,11 @@ public partial class ScriptControlViewModel : ViewModel { Title = "配置组设置", Content = new ScriptGroupConfigView(new ScriptGroupConfigViewModel(TaskContext.Instance().Config, SelectedScriptGroup.Config)), - SizeToContent = SizeToContent.WidthAndHeight, - ResizeMode = ResizeMode.NoResize, + Width = 800, + Height = 600, + MinWidth = 800, + MaxWidth = 800, + MinHeight = 600, WindowStartupLocation = WindowStartupLocation.CenterOwner, ExtendsContentIntoTitleBar = true, WindowBackdropType = WindowBackdropType.Auto, From 461e446c35662ab10983a9b94e7e698d558e718d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sun, 16 Nov 2025 22:37:41 +0800 Subject: [PATCH 04/73] =?UTF-8?q?=E5=BB=B6=E9=95=BF=E7=A7=98=E5=A2=83?= =?UTF-8?q?=E8=BD=BD=E5=85=A5=E5=88=A4=E6=96=AD=E6=97=B6=E9=97=B4=20#2470?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs index ddf9bfd6..5b74fb7a 100644 --- a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs +++ b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs @@ -533,7 +533,7 @@ public class AutoDomainTask : ISoloTask var ocrListLeft = ra.Find(AutoFightAssets.Instance.AbnormalIconRa); return (ocrList.Any(t => t.Text.Contains(leyLineDisorderLocalizedString) || t.Text.Contains(clickanywheretocloseLocalizedString))) || ocrListLeft.IsExist(); - }, _ct, 20, 500); + }, _ct, 40, 500); if (!domainTipFound) { Logger.LogWarning("秘境提示未出现或未能点击。"); From fb0cccbf5fdefdae98810ff02de98c35581d1d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sun, 16 Nov 2025 23:29:30 +0800 Subject: [PATCH 05/73] =?UTF-8?q?=E6=94=AF=E6=8C=81=206.0=20=E6=8C=AA?= =?UTF-8?q?=E5=BE=B7=E5=8D=A1=E8=8E=B1=E8=87=AA=E5=8A=A8=E9=92=93=E9=B1=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 9c9d2d69..829cd68c 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -44,7 +44,7 @@ - + diff --git a/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs b/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs index 90162259..72f17d99 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs @@ -34,7 +34,7 @@ public class BigFishType public static readonly BigFishType MaulerShark = new ("mauler shark", BaitType.RefreshingLakkaBait, "凶凶鲨", 9); public static readonly BigFishType CrystalEye = new("crystal eye", BaitType.RefreshingLakkaBait, "明眼鱼", 9); - public static readonly BigFishType AxeheadFish = new ("axehead fish", BaitType.BerryBait, "巨斧鱼", 9); + public static readonly BigFishType AxeheadFish = new ("axehead", BaitType.BerryBait, "巨斧鱼", 9); public static IEnumerable Values { From 05247ea5a938f9bee03c4087500d766acffe48c5 Mon Sep 17 00:00:00 2001 From: huiyadanli <15783049+huiyadanli@users.noreply.github.com> Date: Sun, 16 Nov 2025 15:32:37 +0000 Subject: [PATCH 06/73] Update version to 0.53.2-alpha.1 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 829cd68c..141781dd 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -2,7 +2,7 @@ BetterGI - 0.53.1-alpha.4 + 0.53.2-alpha.1 false WinExe net8.0-windows10.0.22621.0 From 55bf112d807168d636f299ea6bb231a7922c9b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Tue, 18 Nov 2025 10:09:26 +0800 Subject: [PATCH 07/73] =?UTF-8?q?=E9=80=82=E9=85=8D=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=F0=9F=90=9F=E7=9A=84=E5=91=BD=E5=90=8D.=20Shorten=20name=20of?= =?UTF-8?q?=20SecretSourceScoutSweeper=20fish?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs b/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs index 72f17d99..2544c410 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs @@ -30,7 +30,7 @@ public class BigFishType public static readonly BigFishType Rapidfish = new("rapidfish", BaitType.SpinelgrainBait, "斗士急流鱼", 9); public static readonly BigFishType PhonyUnihornfish = new("phony unihornfish", BaitType.EmberglowBait, "燃素独角鱼", 10); public static readonly BigFishType MagmaRapidfish = new("magma rapidfish", BaitType.EmberglowBait, "炽岩斗士急流鱼", 9); - public static readonly BigFishType SecretSourceScoutSweeper = new ("secret source scout sweeper", BaitType.EmberglowBait, "秘源机关・巡戒使", 9); + public static readonly BigFishType SecretSourceScoutSweeper = new ("secret", BaitType.EmberglowBait, "秘源机关・巡戒使", 9); public static readonly BigFishType MaulerShark = new ("mauler shark", BaitType.RefreshingLakkaBait, "凶凶鲨", 9); public static readonly BigFishType CrystalEye = new("crystal eye", BaitType.RefreshingLakkaBait, "明眼鱼", 9); @@ -96,4 +96,4 @@ public class BigFishType { return e.NetIndex; } -} \ No newline at end of file +} From 51116d16d002a0401c72f049677a1642a106c1c5 Mon Sep 17 00:00:00 2001 From: DarkFlameMaster <1004452714@qq.com> Date: Tue, 18 Nov 2025 10:22:16 +0800 Subject: [PATCH 08/73] =?UTF-8?q?=E4=BC=98=E5=8C=96=20=E5=8F=AF=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E7=89=A9=E5=93=81=E7=9A=84=E8=AF=86=E5=88=AB=E6=96=B9?= =?UTF-8?q?=E6=B3=95=20(#2477)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/Recognition/OpenCv/ContoursHelper.cs | 50 ++++++++++++++++++- .../GameTask/AutoSkip/AutoSkipTrigger.cs | 3 +- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/BetterGenshinImpact/Core/Recognition/OpenCv/ContoursHelper.cs b/BetterGenshinImpact/Core/Recognition/OpenCv/ContoursHelper.cs index 4ba5c4ea..88490719 100644 --- a/BetterGenshinImpact/Core/Recognition/OpenCv/ContoursHelper.cs +++ b/BetterGenshinImpact/Core/Recognition/OpenCv/ContoursHelper.cs @@ -6,6 +6,40 @@ using System.Linq; namespace BetterGenshinImpact.Core.Recognition.OpenCv; +/// +/// 形态学操作参数类 +/// +public class MorphologyParam +{ + /// + /// 运算核大小 + /// + public Size KernelSize { get; set; } + + /// + /// 运算方法 + /// + public MorphTypes MorphType { get; set; } + + /// + /// 运算次数 + /// + public int Iterations { get; set; } + + /// + /// 形态学操作参数构造函数 + /// + /// 运算核大小 + /// 运算方法 + /// 运算次数 + public MorphologyParam(Size kernelSize, MorphTypes morphType, int iterations) + { + KernelSize = kernelSize; + MorphType = morphType; + Iterations = iterations; + } +} + public class ContoursHelper { /// @@ -16,14 +50,21 @@ public class ContoursHelper /// RGB色彩高位 /// 矩形最小宽度 /// 矩形最小高度 + /// 形态学操作参数(可选) /// - public static List FindSpecifyColorRects(Mat srcMat, Scalar low, Scalar high, int minWidth = -1, int minHeight = -1) + public static List FindSpecifyColorRects(Mat srcMat, Scalar low, Scalar high, int minWidth = -1, int minHeight = -1, MorphologyParam? morphologyParam = null) { try { using var src = srcMat.Clone(); Cv2.CvtColor(src, src, ColorConversionCodes.BGR2RGB); Cv2.InRange(src, low, high, src); + + if (morphologyParam != null) + { + using var kernel = Cv2.GetStructuringElement(MorphShapes.Rect, morphologyParam.KernelSize); + Cv2.MorphologyEx(src, src, morphologyParam.MorphType, kernel, iterations: morphologyParam.Iterations); + } Cv2.FindContours(src, out var contours, out _, RetrievalModes.External, ContourApproximationModes.ApproxSimple); @@ -56,4 +97,9 @@ public class ContoursHelper { return FindSpecifyColorRects(srcMat, color, color, minWidth, minHeight); } -} + + public static List FindSpecifyColorRects(Mat srcMat, Scalar color, int minWidth, int minHeight, MorphologyParam morphologyParam) + { + return FindSpecifyColorRects(srcMat, color, color, minWidth, minHeight, morphologyParam); + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs index cf7f9adb..1ce33caf 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs @@ -850,7 +850,8 @@ public partial class AutoSkipTrigger : ITaskTrigger { // var rects = MatchTemplateHelper.MatchOnePicForOnePic(content.CaptureRectArea.SrcMat.CvtColor(ColorConversionCodes.BGRA2BGR), // _autoSkipAssets.SubmitGoodsMat, TemplateMatchModes.SqDiffNormed, null, 0.9, 4); - var rects = ContoursHelper.FindSpecifyColorRects(content.CaptureRectArea.SrcMat, new Scalar(233, 229, 220), 100, 20); + var param = new MorphologyParam(new Size(5,5), MorphTypes.Close, 2); + var rects = ContoursHelper.FindSpecifyColorRects(content.CaptureRectArea.SrcMat, new Scalar(233, 229, 220), 100, 20, param); if (rects.Count == 0) { return false; From 81ac69bde070835d20cb103c389ff979b1bb90a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B7=E4=B8=AA=E5=90=8D=E5=AD=97=E5=A5=BD=E9=9A=BE?= =?UTF-8?q?=E7=9A=84=E5=96=B5?= <25520958+MisakaAldrich@users.noreply.github.com> Date: Tue, 18 Nov 2025 21:06:41 +0800 Subject: [PATCH 09/73] =?UTF-8?q?Update=20=E4=B8=87=E8=83=BD=E6=88=98?= =?UTF-8?q?=E6=96=97=E7=AD=96=E7=95=A5=EF=BC=88=E8=90=8C=E6=96=B0=E6=8E=A8?= =?UTF-8?q?=E8=8D=90=EF=BC=89.txt=20(#2480)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AutoFight/万能战斗策略(萌新推荐).txt | 71 +++++++++++++++---- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/BetterGenshinImpact/User/AutoFight/万能战斗策略(萌新推荐).txt b/BetterGenshinImpact/User/AutoFight/万能战斗策略(萌新推荐).txt index c913e5c2..b05c868b 100644 --- a/BetterGenshinImpact/User/AutoFight/万能战斗策略(萌新推荐).txt +++ b/BetterGenshinImpact/User/AutoFight/万能战斗策略(萌新推荐).txt @@ -1,8 +1,41 @@ // 作者:火山 -// 描述:万能战斗策略(新手推荐)。需要在,调度器→配置组→设置→战斗配置(开启)→自动检测战斗结束(开启)→更快检查结束战斗(开启)→旋转寻找敌人位置(开启)→检查战斗结束的延时(0.1)→按键触发后检查延时(0.35)→盾奶角色优先释放技能(开启,设置你的盾位)→战斗结束后使用万叶长E手机掉落物(开启) +// 描述:万能战斗策略(新手推荐)。内含详细使用说明,请务必打开本文档!!!(内含少部分满命、进阶操作,默认已注释不开启) +// 版本:v1.6 + +// 战斗配置设置流程 +// 该设置从调度器入口开始,按以下层级路径操作,核心为开启相关功能并配置关键参数。 +// 1. 进入战斗配置页面 +// 路径:调度器 → 配置组 → 设置 → 战斗配置操作:将 “战斗配置” 功能开启 + +// 2. 战斗结束检测相关设置 +// 所有子项均需开启,用于快速识别战斗状态,提升效率。 +// 自动检测战斗结束:开启 +// 更快检查结束战斗:开启,参数设置为 1 +// 检查战斗结束的延时:设置为 0.4 +// 按键触发后检查延时:设置为 0.4 + +// 3. 敌人定位与面向设置 +// 用于自动调整角色朝向,优化战斗操作。 +// 旋转寻找敌人位置:开启 +// Q 前检测:开启 +// 尝试面向敌人:可选开启(根据需求选择) + +// 4. 技能释放与角色优先级设置 +// 核心为盾奶角色技能优先释放,需准确配置角色位置。 +// 盾奶角色优先释放技能:开启 +// 关键设置:在队伍栏中,选择盾角色对应的序号(务必准确,不可选错)。 + +// 5. 掉落物拾取设置 +// 需根据队伍角色情况选择开启,核心注意万叶 / 琴的特殊设置。 +// 自动拾取掉落物:禁止开启(队伍中有万叶 / 琴时,一定要关闭!!!) +// 聚集材料动作设置:开启 +// 功能:自动选择万叶或琴(优先万叶),通过长 E 动作收集掉落物。 + +// 以下是战斗策略正文,注意合理搭配队伍 +// !!!请严格遵守BGI战斗配队逻辑!!!(以 盾【刚需】+主c【可以是后台输出角色】+副c【可以是后台输出角色】+万叶/琴【如需要捡掉落物的可以带,比如精英怪,小怪、副本可酌情不带换成,奶妈 or 后台输出角色】) // 盾(刚需) -茜特菈莉 attack,e,wait(0.2),keypress(q),wait(0.2),keypress(q),wait(0.2),keypress(q),attack(0.2) +茜特菈莉 e,attack(0.2),keypress(q),wait(0.2),keypress(q),attack(0.2),keypress(q),attack(0.2),keypress(e) 伊涅芙 e,attack(0.22),keypress(q),wait(0.1),keypress(q),attack(0.2),keypress(q),attack(0.2) 钟离 s(0.2), e(hold), wait(0.2), w(0.2),keypress(q),wait(0.2),keypress(q),attack(0.1) 莱依拉 e,wait(0.2), keypress(q),wait(0.2),keypress(q),attack(0.2),keypress(q),attack(0.2) @@ -11,18 +44,24 @@ 蓝砚 e,attack(0.15), click(middle),attack(0.15),click(middle),attack(0.15),click(middle),wait(0.2).dash(0.1),attack(0.2) // 后台、挂元素、副C、先手 -玛薇卡 attack(0.2),e +玛薇卡 attack(0.2),e,wait(0.2),keypress(q),attack(0.1) 迪希雅 e,attack(0.2),e 香菱 e,wait(0.3),keypress(q),attack(0.2),keypress(q),wait(0.2),keypress(q),attack(0.2) 仆人 attack,e -那维莱特 attack(0.23),e +那维莱特 attack(0.05),click(middle),e,wait(0.15),keydown(VK_LBUTTON),wait(0.27),keyup(VK_LBUTTON),wait(0.15),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),keydown(VK_LBUTTON),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-1100),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1200),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1300),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-1100),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1200),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1300),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-1100),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1200),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1300),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),click(middle),j,click(middle),wait(0.05),keyup(VK_LBUTTON) 纳西妲 e(hold),click(middle),keypress(q),wait(0.3),keypress(q),attack(0.3),keypress(q),attack(0.2) 艾梅莉埃 e,attack(0.2), keypress(q),attack(0.2),keypress(q),wait(0.2),keypress(q),attack(0.2) 丝柯克 attack(0.2),click(middle),keypress(q),wait(0.05),keypress(q),attack(0.05),click(middle),keydown(E),wait(0.22),attack(0.08),click(middle),keyup(E),keypress(q),wait(0.08),keypress(q) -芙宁娜 e,attack(0.2), keypress(q),attack(0.2),keypress(q),wait(0.2),keypress(q),attack(0.2) +芙宁娜 e,attack(0.2),keydown(W),attack(0.3),keypress(q),keyup(W),attack(0.3),keypress(q),attack(0.1),keydown(S),attack(0.33),keyup(S) +爱诺 e, wait(0.3), keypress(q), attack(0.22), keypress(q), attack(0.21) +菈乌玛 attack(0.1),keypress(q),wait(0.01),keydown(E),wait(0.4),attack(0.3),keyup(E),attack(0.15),keypress(q),keydown(E),wait(0.4),attack(0.3),keyup(E),attack(0.2),wait(0.1) + +// (有奈芙尔就去掉角色名之前的内容,→(//+一个空格 =// ) ←按照我注释的格式给上一行的菈乌玛长e策略注释掉,后面是短e策略,不消耗草露),菈乌玛 e,attack(0.2), keypress(q),attack(0.2),keypress(q),wait(0.2),keypress(q),attack(0.2) + 白术 e,attack(0.2) +珊瑚宫心海 e 芭芭拉 e,attack(0.2) -希格雯 e(hold),wait(0.2),keypress(q),wait(0.2),keypress(q) +希格雯 e(hold),wait(0.2),attack(0.21),keypress(q),wait(0.2),keypress(q) 爱可菲 e,attack(0.2), keypress(q),attack(0.2),keypress(q),wait(0.2),keypress(q),attack(0.2) 菲谢尔 e 欧洛伦 e,attack(0.3), keypress(q),wait(0.2),attack(0.3),keypress(q),wait(0.2),attack(0.3),keypress(q),wait(0.3) @@ -32,23 +71,31 @@ // 中置位 -夏沃蕾 attack(0.08),keypress(q),wait(0.2),keypress(q),wait(0.2),attack(0.2),keydown(e),wait(0.15), moveby(0,900),wait(0.15),keyup(e),attack(0.15) +夏沃蕾 attack(0.08),keypress(q),wait(0.2),keypress(q),wait(0.2),attack(0.21),keydown(e),wait(0.15), moveby(0,1300),wait(0.18),keyup(e),attack(0.15) 白术 attack(0.2), keypress(q),attack(0.2),keypress(q),wait(0.2),keypress(q),attack(0.2) -那维莱特 attack(0.08),keypress(q),wait(0.22),keypress(q),wait(0.2),keypress(q),e +// 奈芙尔 attack(0.08), keydown(VK_LBUTTON), keydown(E), wait(0.015), keyup(E), wait(0.015), wait(0.95), wait(0.015), keydown(VK_RBUTTON), wait(0.015), keyup(VK_RBUTTON), wait(0.015), keydown(S), wait(0.015), keyup(S), wait(0.25), keydown(W), wait(0.015), keyup(W), wait(0.85), keydown(VK_RBUTTON), wait(0.015), keyup(VK_RBUTTON), wait(0.015), keydown(S), wait(0.015), keyup(S), wait(0.25), keydown(W), wait(0.015), wait(0.015), keyup(W), wait(0.85), keydown(VK_RBUTTON), wait(0.015), keyup(VK_RBUTTON), wait(0.015), keydown(S), wait(0.015), keyup(S), wait(0.25), keydown(W), wait(0.015), keyup(W), wait(0.015), wait(0.015), wait(0.5), keyup(VK_LBUTTON),keypress(q),attack(0.2) //减抗 希诺宁 s(0.2),e,w(0.2),attack(0.35),wait(0.1),attack(0.35),keypress(x), wait(0.2), keypress(q), wait(0.3), keypress(q),keypress(x), wait(0.08), keypress(x),attack(0.2) 枫原万叶 attack(0.08),keypress(q),wait(0.3),keypress(q),wait(0.3),attack(0.2),keydown(E),wait(0.48),keyup(E),attack(0.3), wait(0.5),attack(0.1) 砂糖 e,attack(0.2),keypress(q),attack(0.2),keypress(q),e,attack(0.2) +琴 attack(0.21),keydown(e),wait(0.14), moveby(0,1300),wait(0.75),keyup(e),attack(0.12),keypress(q),attack(0.11),keypress(q),attack //爆发 -玛薇卡 e,click(middle),wait(0.12), keypress(q), wait(0.3), keypress(q), wait(0.3), charge(3.8), keydown(space), wait(0.1), keyup(space), attack(0.2),wait(0.2) +玛薇卡 attack(0.08),keydown(E),wait(0.4),attack(0.2),wait(0.01),keyup(E),click(middle),keydown(s),mousedown,wait(0.01),keypress(q), wait(0.2), keypress(q), keyup(s),mouseup,charge(3.8), keydown(space), wait(0.1), keyup(space), attack(0.2),wait(0.2) + //收尾,长轴 -那维莱特 charge(3),j,wait(0.3) +那维莱特 attack(0.05),keypress(q),wait(0.05),keypress(q),click(middle),e,wait(0.15),keydown(VK_LBUTTON),wait(0.27),keyup(VK_LBUTTON),wait(0.15),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),keydown(VK_LBUTTON),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-1100),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1200),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1300),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-1100),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1200),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1300),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-1100),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1200),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1300),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),click(middle),j,click(middle),keyup(VK_LBUTTON),wait(0.5),attack(0.2), click(middle),wait(0.2),keydown(VK_LBUTTON),wait(0.35),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),keydown(VK_LBUTTON),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-1100),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1200),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1300),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-1100),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1200),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1300),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-2100),wait(0.05),moveby(1800,-1100),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1200),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,1300),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),moveby(1800,0),wait(0.05),click(middle),j,click(middle),wait(0.05),keyup(VK_LBUTTON) +芭芭拉 e,attack(0.6),keypress(q),attack(2),charge(0.5),keypress(q),attack(0.2) 丝柯克 attack(0.05),keypress(e),wait(0.05),keypress(e),wait(0.2),attack(2.27),keypress(Q),dash,attack(2.27),keydown(S),keypress(Q),dash,keyup(S),attack(2.27),wait(0.11),charge(0.3),attack(1) 迪希雅 keypress(q),attack(0.1),dash(0.2),keypress(q),attack(0.3),keypress(q),attack(0.3),keypress(q),attack(0.3),keydown(S),attack(0.5),keyup(S),keydown(W),attack(0.5),keyup(W),keydown(S),attack(0.5),keyup(S),keydown(W),attack(0.5),keyup(W),keydown(S),attack(0.5),keyup(S),keydown(W),attack(0.5),keyup(W),keydown(S),attack(0.5),keyup(S) 娜维娅 keypress(q),attack(0.1),keypress(q),attack(0.1),keypress(q),attack(0.1),keypress(q),keydown(E),wait(0.8),keyup(E),attack(1.6),keydown(E),wait(0.8),keyup(E),attack(0.1),keydown(S),attack(0.33),keyup(S),keydown(W),attack(0.3),keyup(W),keydown(S),attack(0.3),keyup(S),keydown(W),attack(0.3),keyup(W),keydown(S),attack(0.3),keyup(S),keydown(W),attack(0.3),keyup(W),attack(0.2) -瓦雷莎 e, attack(1.25),wait(0.45), s(0.4), e, attack(1.25), wait(0.3),keypress(q), wait(0.45),s(0.4),e, attack(1.25),wait(0.45), s(0.4), e, attack(1.25), wait(0.3),keypress(q), attack(0.45) -仆人 charge(0.35),j,attack(3.2),j,attack(0.3),attack(0.52),keypress(q),attack(0.2) \ No newline at end of file +// (奈芙尔3zs)奈芙尔 attack(0.08), keydown(VK_LBUTTON), keydown(E), wait(0.015), keyup(E), wait(0.015), wait(0.95), wait(0.015), keydown(VK_RBUTTON), wait(0.015), keyup(VK_RBUTTON), wait(0.015), keydown(S), wait(0.015), keyup(S), wait(0.25), keydown(W), wait(0.015), keyup(W), wait(0.85), keydown(VK_RBUTTON), wait(0.015), keyup(VK_RBUTTON), wait(0.015), keydown(S), wait(0.015), keyup(S), wait(0.25), keydown(W), wait(0.015), wait(0.015), keyup(W), wait(0.85), keydown(VK_RBUTTON), wait(0.015), keyup(VK_RBUTTON), wait(0.015), keydown(S), wait(0.015), keyup(S), wait(0.25), keydown(W), wait(0.015), keyup(W), wait(0.015), wait(0.015), wait(0.5), keyup(VK_LBUTTON) +// (满命6刀)芙宁娜 attack(0.01),e,attack(0.1),dash(0.1),jump,wait(0.2),keypress(q),keydown(W),attack(0.3),keypress(q),keyup(W),attack(0.3),keypress(q),attack(0.1),keydown(S),attack(0.33),keyup(S),keydown(W),attack(0.3),keyup(W),keydown(S),attack(0.3),keyup(S),keydown(W),attack(0.3),keyup(W),keydown(S),attack(0.3),keyup(S),keydown(W),attack(0.3),keyup(W) +// (火神AZS)玛薇卡 q,attack(0.1),e,charge(0.6)4,dash(0.3),moveby(500,0),moveby(2300,0),attack(0.1),charge(0.7),dash(0.3),moveby(-500,0),moveby(-2300,-0),attack(0.1),charge(0.7),dash(0.3),moveby(500,0),moveby(2600,0),attack(0.1),charge(0.8),dash(0.3),moveby(-500,0),moveby(-2300,-0),attack(0.1),charge(0.8),dash(0.3),moveby(500,0),moveby(2300,0),attack(0.1),charge(0.8),dash(0.3),moveby(-500,0),moveby(-2300,-0) +// (火神ZZS)玛薇卡 attack(0.08), keypress(q),attack(0.03),keypress(q),keydown(E),wait(0.35),keyup(E),attack(0.03),wait(0.25), keydown(VK_LBUTTON),wait(0.155),keydown(VK_RBUTTON),wait(0.18),keyup(VK_LBUTTON),wait(0.02),keyup(VK_RBUTTON),wait(0.02),keydown(VK_LBUTTON),wait(0.16),keydown(VK_RBUTTON),wait(0.18),keyup(VK_LBUTTON),wait(0.02),keyup(VK_RBUTTON),wait(0.1),keydown(VK_LBUTTON),wait(0.05),keyup(VK_LBUTTON),wait(0.05),keydown(VK_LBUTTON),wait(0.05),keyup(VK_LBUTTON),wait(1.25), keydown(VK_LBUTTON),wait(0.155),keydown(VK_RBUTTON),wait(0.18),keyup(VK_LBUTTON),wait(0.02),keyup(VK_RBUTTON),wait(0.02),keydown(VK_LBUTTON),wait(0.16),keydown(VK_RBUTTON),wait(0.18),keyup(VK_LBUTTON),wait(0.02),keyup(VK_RBUTTON),wait(0.1),keydown(VK_LBUTTON),wait(0.05),keyup(VK_LBUTTON),wait(0.05),keydown(VK_LBUTTON),wait(0.05),keyup(VK_LBUTTON),wait(0.83) +// (回身 QE ZZS)玛薇卡 attack(0.03),keypress(q),keypress(q),keydown(E),wait(0.45),keyup(E),wait(0.2),keydown(VK_LBUTTON),wait(0.155),wait(0.359),keyup(VK_LBUTTON),wait(0.05),wait(0.05), keydown(VK_LBUTTON),wait(0.1),keyup(VK_LBUTTON),wait(0.05),keydown(VK_LBUTTON),wait(0.1),keyup(VK_LBUTTON),click(middle),wait(0.45), moveby(5500,0),wait(0.05),keydown(VK_LBUTTON),wait(0.125),keydown(VK_RBUTTON),wait(0.15),s(0.1),wait(0.1),keyup(VK_LBUTTON),wait(0.01),keyup(VK_RBUTTON),wait(0.08),keydown(VK_LBUTTON),wait(0.125),keydown(VK_RBUTTON),wait(0.1),s(0.1),wait(0.1),keyup(VK_LBUTTON),wait(0.01),keyup(VK_RBUTTON),wait(0.1),keydown(VK_LBUTTON),wait(0.05),keyup(VK_LBUTTON),wait(0.05),keydown(VK_LBUTTON),wait(0.05),keyup(VK_LBUTTON),wait(0.3) +瓦雷莎 e, attack(1.25),click(middle),wait(0.45), keydown(s), e, attack(1.25),keyup(s), wait(0.3),keypress(q), click(middle),wait(0.45) +仆人 charge(0.35), j, keydown(s),attack(1.17),attack(0.45),keyup(s),keydown(w),attack(0.38),attack(0.6),keyup(w),wait(0.2),keydown(s),attack(1.17),attack(0.45),keyup(s),keydown(w),attack(0.38),attack(0.6),keyup(w),wait(0.2) From dbf489fd0497b87f4b98ebcca81403f97116d200 Mon Sep 17 00:00:00 2001 From: kaedelcb <57870068+kaedelcb@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:29:13 +0800 Subject: [PATCH 10/73] =?UTF-8?q?=E9=80=82=E9=85=8D=E8=81=94=E6=9C=BA?= =?UTF-8?q?=E7=9B=B8=E5=85=B3UI=20(#2488)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoFight/Assets/1920x1080/p.png | Bin 607 -> 1854 bytes .../GameTask/Common/Job/SwitchPartyTask.cs | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/GameTask/AutoFight/Assets/1920x1080/p.png b/BetterGenshinImpact/GameTask/AutoFight/Assets/1920x1080/p.png index 9960ac6948bcca96ec5ff4012f484df0355932b8..6c749a0ed99fd74d242b002675d96a1c7f6783c3 100644 GIT binary patch literal 1854 zcmcIlTWl0n7#n5@LY+<>Xmok`};da;&{5pXnowm`}a9x8FBDX zEkWFMMh$n{-JwTisHa>&(WA(fO&J(X5RIF&27tZDCZi~>YJO_r)Q1$QDt@ZV9b!X9 zGfJqf119PmXbZ!EUMMNl=7-6~tc(d#$OdFKmDDUb>!IFHB*o(7Ue?InvBg{_%NOzsG5E!x6Q zekx(xhRiUTOvaTFT)G)&I7z}BJj3%eM$lHjW`iuPSsO|W0c1f_HEdPaNQV(b^|bA$ zu+oAHDWgoQS;a8nfH7HMFr15ZTq*%Wp<6>!sWRHKTl%n-qTU-4Tj72KF&)U#(&a50 z+Dj}XkG&>0cBz`8XRHSuMa2Us0Bq!^c$Rn5982>;7-x+aWYJsC`ec?ZKts3=6kvm; zfptZV^)Ce)3dupuvVjIsFyN=KD3_`#vfJm5@lw=B`*=mdRU`shib{YMfan#y9_T@e zFRu%q59l!MgwHu&C|gB`n4=saImU@@!L0yVar6BTGdf-I+SnAihLY}-r~ ze>os|J*%Tiaa19%$ISvn3(zOfURI3J(WslHkrWeS5>y05a#N%N<(O`!0Im}?1>%S? zv^YintEO2`>Sjn+aLfg#nlU@}qE)qU>iUb{MCq zQS_Fivp}0kAWV9TDv|;b2IT4=(~;dB_;lUlwJ%gOaLv8aN}es z#~H?HF@>Zs|IJta-F5A#1jjwjS(ckCekiwRq+x0kH{Y?>(?63R~{q^iSq1ni+mw%-( zIx!ALcdV(5-22VZq3G5-_d?;!rZ2`WoERNGIJ#nL`i-Z~jql$z^Gu{W{P8w!ac52C zPupL6?^MP29m<-y+>_USzfeEUlv|Ea$sa^i zQ%R4;PaKDnsh){9(e&c;&+Yafo@*HTC0%u(rjGIw5piU6_)^zYZ%;$+qxP$V55(&C xrreb$E9O=`c5UmYU&gDrCu$EJt9#-6Z^X=Dmp7U_8+86~!Irkb_?DhM{{U9_bguva literal 607 zcmV-l0-*hgP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0rW{kK~y+TeUVE@ zRACgy&q$yMYSUxsruHt}MdQ6B} zDF{)Fi)PRYb<$9>i)5Q9v4_pv`|o^TK9aG{Hm@1H^C!CVB!Js6AK z#msv|bC&f=t+6k_Xvv~LMHD@(tKvZiCD>A0|v(P%A zNxz(-l;z|(RyG%o08PCroIQl9VZwzr!s138RLU8IH2o9<^9L;n;7UZ5$u4y=aEmav z5j;9B522_FUJ3XT{MJCWM)l2gOTUm(od@22E~_^0hpGF*kTkD z&mu^En3r14SY0CgC29}Kk5^J+atj{98HiPL`kNI$+{9`MK8Cv=@lm`o>%G&dw zwB>-@dOk#3TIh5JAl51d7F((rBh){oKQsIr;KT7@>!Jkj2I1P)Ux4!%pgB^35}yqY z-c;oS!sT%W$^s{Fd%}as_(OdAxxM#056$13_c4U0Z{Yf)Dn4K~l$+TC$idXYDBf Date: Mon, 24 Nov 2025 11:03:39 +0800 Subject: [PATCH 11/73] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BE=A4=E5=8F=8B?= =?UTF-8?q?=E5=8F=91=E7=8E=B0=E7=9A=84bug=20(#2492)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/GameTask/Model/GameUI/GridCell.cs | 8 ++++---- BetterGenshinImpact/Helpers/ScriptObjectConverter.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/BetterGenshinImpact/GameTask/Model/GameUI/GridCell.cs b/BetterGenshinImpact/GameTask/Model/GameUI/GridCell.cs index 149e39b9..d32ff0df 100644 --- a/BetterGenshinImpact/GameTask/Model/GameUI/GridCell.cs +++ b/BetterGenshinImpact/GameTask/Model/GameUI/GridCell.cs @@ -111,7 +111,7 @@ namespace BetterGenshinImpact.GameTask.Model.GameUI count++; } } - avgColSpacing = count == 0 ? 0 : Math.Round(((double)sum) / count, MidpointRounding.AwayFromZero); + avgColSpacing = count == 0 ? 0 : ((double)sum) / count; } { int count = 0; @@ -130,11 +130,11 @@ namespace BetterGenshinImpact.GameTask.Model.GameUI count++; } } - avgRowSpace = count == 0 ? 0 : Math.Round(((double)sum) / count, MidpointRounding.AwayFromZero); + avgRowSpace = count == 0 ? 0 : ((double)sum) / count; } - int avgLeft = (int)Math.Round(cells.Average(c => c.Rect.X - (avgWidth + avgColSpacing) * c.ColNum), MidpointRounding.AwayFromZero); - int avgTop = (int)Math.Round(cells.Average(c => c.Rect.Y - (avgHeight + avgRowSpace) * c.RowNum), MidpointRounding.AwayFromZero); + double avgLeft = cells.Average(c => c.Rect.X - (avgWidth + avgColSpacing) * c.ColNum); + double avgTop = cells.Average(c => c.Rect.Y - (avgHeight + avgRowSpace) * c.RowNum); for (int i = 0; i < cells.Max(r => r.ColNum) + 1; i++) { diff --git a/BetterGenshinImpact/Helpers/ScriptObjectConverter.cs b/BetterGenshinImpact/Helpers/ScriptObjectConverter.cs index 1d0d3cfc..be352c23 100644 --- a/BetterGenshinImpact/Helpers/ScriptObjectConverter.cs +++ b/BetterGenshinImpact/Helpers/ScriptObjectConverter.cs @@ -57,8 +57,8 @@ public class ScriptObjectConverter /// /// 适用集合的重载 - /// 如果解析失败,默认返回一个空集合; - /// 如果集合元素解析失败,将跳过该元素 + /// 如果解析失败,返回null; + /// 如果集合元素解析失败,将跳过该元素,因此有可能返回空集合 /// 仅支持一层集合,不能再是集合 /// 避开反射,享受健康生活 /// @@ -66,7 +66,7 @@ public class ScriptObjectConverter /// /// /// - public static IEnumerable GetValue(ScriptObject source, string propertyName) + public static IEnumerable? GetValue(ScriptObject source, string propertyName) { if (source[propertyName] is not Undefined && source[propertyName] != null) { @@ -74,7 +74,7 @@ public class ScriptObjectConverter return TryMap(v8Value); } - return new T[0]; + return null; } /// From 89beeeccef66998b66004006e022c61ea95e8f57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Mon, 24 Nov 2025 22:58:36 +0800 Subject: [PATCH 12/73] 6.0 fish model 2 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 141781dd..44518673 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -44,7 +44,7 @@ - + From eb1a06f4b65861350451738d9b41cd22ac29bbb3 Mon Sep 17 00:00:00 2001 From: huiyadanli <15783049+huiyadanli@users.noreply.github.com> Date: Mon, 24 Nov 2025 15:01:29 +0000 Subject: [PATCH 13/73] Update version to 0.53.2-alpha.2 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 44518673..41381704 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -2,7 +2,7 @@ BetterGI - 0.53.2-alpha.1 + 0.53.2-alpha.2 false WinExe net8.0-windows10.0.22621.0 From b9707c43af8a51011c46101716dfe78306c86589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Tue, 25 Nov 2025 22:19:48 +0800 Subject: [PATCH 14/73] =?UTF-8?q?=E9=9D=9E4=E4=B8=AA=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8CImageDifferenceDetector.Fin?= =?UTF-8?q?dMostDifferentImage=20=E6=8A=9B=E5=87=BA=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OpenCv/ImageDifferenceDetector.cs | 112 ++++++++++-------- .../Model/PartyAvatarSideIndexHelper.cs | 9 +- 2 files changed, 68 insertions(+), 53 deletions(-) diff --git a/BetterGenshinImpact/Core/Recognition/OpenCv/ImageDifferenceDetector.cs b/BetterGenshinImpact/Core/Recognition/OpenCv/ImageDifferenceDetector.cs index e88a8a20..f436f7ef 100644 --- a/BetterGenshinImpact/Core/Recognition/OpenCv/ImageDifferenceDetector.cs +++ b/BetterGenshinImpact/Core/Recognition/OpenCv/ImageDifferenceDetector.cs @@ -14,71 +14,79 @@ public class ImageDifferenceDetector /// 差异最大的图片索引(0-3),如果没有图片获得3票则返回-1 public static int FindMostDifferentImage(Mat[] images) { - if (images is not { Length: 4 }) + try { - throw new ArgumentException("必须提供4张图片"); - } - - // 验证所有图片尺寸相同 - Size firstSize = images[0].Size(); - for (int i = 1; i < 4; i++) - { - if (images[i].Size() != firstSize) + if (images is not { Length: 4 }) { - throw new ArgumentException("所有图片必须具有相同的尺寸"); + throw new ArgumentException("必须提供4张图片"); } - } - // 存储每张图片获得的投票数 - int[] votes = new int[4]; - - // 每张图片投票给与它差异最大的图片 - for (int i = 0; i < 4; i++) - { - int maxDiffImageIndex = -1; - double maxDifference = 0; - - // 找出与图片i差异最大的图片 - for (int j = 0; j < 4; j++) + // 验证所有图片尺寸相同 + Size firstSize = images[0].Size(); + for (int i = 1; i < 4; i++) { - if (i != j) + if (images[i].Size() != firstSize) { - double difference = CalculateDifference(images[i], images[j]); - Debug.WriteLine($"{i} vs {j} 差异像素数量: {difference}"); - - if (difference > maxDifference) - { - maxDifference = difference; - maxDiffImageIndex = j; - } + throw new ArgumentException("所有图片必须具有相同的尺寸"); } } - // 图片i投票给差异最大的图片 - if (maxDiffImageIndex != -1) - { - votes[maxDiffImageIndex]++; - Debug.WriteLine($"图片 {i} 投票给图片 {maxDiffImageIndex} (差异值: {maxDifference:F2})"); - } - } + // 存储每张图片获得的投票数 + int[] votes = new int[4]; - // 输出投票结果 - Debug.WriteLine("\n投票结果:"); - for (int i = 0; i < 4; i++) - { - Debug.WriteLine($"图片 {i}: {votes[i]} 票"); - } - - // 检查是否有图片获得3票 - for (int i = 0; i < 4; i++) - { - if (votes[i] >= 3) + // 每张图片投票给与它差异最大的图片 + for (int i = 0; i < 4; i++) { - return i; + int maxDiffImageIndex = -1; + double maxDifference = 0; + + // 找出与图片i差异最大的图片 + for (int j = 0; j < 4; j++) + { + if (i != j) + { + double difference = CalculateDifference(images[i], images[j]); + Debug.WriteLine($"{i} vs {j} 差异像素数量: {difference}"); + + if (difference > maxDifference) + { + maxDifference = difference; + maxDiffImageIndex = j; + } + } + } + + // 图片i投票给差异最大的图片 + if (maxDiffImageIndex != -1) + { + votes[maxDiffImageIndex]++; + Debug.WriteLine($"图片 {i} 投票给图片 {maxDiffImageIndex} (差异值: {maxDifference:F2})"); + } } + + // 输出投票结果 + Debug.WriteLine("\n投票结果:"); + for (int i = 0; i < 4; i++) + { + Debug.WriteLine($"图片 {i}: {votes[i]} 票"); + } + + // 检查是否有图片获得3票 + for (int i = 0; i < 4; i++) + { + if (votes[i] >= 3) + { + return i; + } + } + + return -1; + } + catch (Exception ex) + { + Debug.WriteLine($"FindMostDifferentImage 出错: {ex.Message}"); + return -1; } - - return -1; } /// diff --git a/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs b/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs index a600698e..ddc4bae2 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs @@ -397,7 +397,14 @@ public class PartyAvatarSideIndexHelper else { // 使用更加靠谱的差值识别(-1是未识别) - return ImageDifferenceDetector.FindMostDifferentImage(mats); + if (mats.Length == 4) + { + return ImageDifferenceDetector.FindMostDifferentImage(mats); + } + else + { + return -1; + } } } finally From 16f4f5c311c8cbb772cefa694b9f3f459a007d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Tue, 25 Nov 2025 22:28:35 +0800 Subject: [PATCH 15/73] =?UTF-8?q?UseGadgetHandler=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=9C=80=E5=A4=A7CD=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AutoPathing/Handler/UseGadgetHandler.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/UseGadgetHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/UseGadgetHandler.cs index 8711dde0..ae6c9482 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/UseGadgetHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/UseGadgetHandler.cs @@ -35,6 +35,13 @@ public class UseGadgetHandler : IActionHandler } else { + double maxWaitSeconds = 100; + if (waypointForTrack != null + && !string.IsNullOrEmpty(waypointForTrack.ActionParams)) + { + double.TryParse(waypointForTrack.ActionParams, out maxWaitSeconds); // 最大等待时间,单位秒 + } + var screen = CaptureToRectArea(); var cd = GetCurrentCd(screen); if (cd > 100) @@ -46,7 +53,17 @@ public class UseGadgetHandler : IActionHandler { Logger.LogInformation("小道具正在CD中,等待CD结束 :{Cd}秒", cd); // 等待小道具CD结束 - var waitTime = (int)(cd * 1000) + 100; // 等待CD结束后再继续 + int waitTime; // 等待CD结束后再继续 + if (cd > maxWaitSeconds) + { + waitTime = (int)(maxWaitSeconds * 1000); + Logger.LogInformation("CD过长,使用最大CD:{Max}秒", maxWaitSeconds); + } + else + { + waitTime = (int)(cd * 1000) + 100; // 等待CD结束后再继续 + } + await Delay(waitTime, ct); Simulation.SendInput.SimulateAction(GIActions.QuickUseGadget); } @@ -55,6 +72,7 @@ public class UseGadgetHandler : IActionHandler Simulation.SendInput.SimulateAction(GIActions.QuickUseGadget); } } + Logger.LogInformation("使用小道具"); await Delay(300, ct); } From 56959d356fcb90b0ce5617a714db69dd3fcd2dae Mon Sep 17 00:00:00 2001 From: huiyadanli <15783049+huiyadanli@users.noreply.github.com> Date: Tue, 25 Nov 2025 14:31:29 +0000 Subject: [PATCH 16/73] Update version to 0.53.2-alpha.3 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 41381704..fe3ad69f 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -2,7 +2,7 @@ BetterGI - 0.53.2-alpha.2 + 0.53.2-alpha.3 false WinExe net8.0-windows10.0.22621.0 From ea4053485120e6dcbc52f9d43e62c3ca7943a9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Wed, 26 Nov 2025 00:17:43 +0800 Subject: [PATCH 17/73] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=87=BA=E6=88=98?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E6=A3=80=E6=B5=8B=E6=96=B9=E6=B3=952?= =?UTF-8?q?=EF=BC=9A=E8=BE=B9=E7=BC=98=E5=83=8F=E7=B4=A0=E7=99=BD=E8=89=B2?= =?UTF-8?q?=E6=AF=94=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Model/PartyAvatarSideIndexHelper.cs | 116 ++++++++++++++++-- .../Cv/ImageDifferenceDetectorTest.cs | 10 ++ 2 files changed, 118 insertions(+), 8 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs b/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs index ddc4bae2..2e30b6bf 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs @@ -35,10 +35,12 @@ public class PartyAvatarSideIndexHelper { autoFightAssets = AutoFightAssets.Instance; } + if (logger == null) { logger = TaskControl.Logger; } + var status = new MultiGameStatus(); // 判断当前联机人数 var pRaList = imageRegion.FindMulti(autoFightAssets.PRa); @@ -246,7 +248,7 @@ public class PartyAvatarSideIndexHelper public static List GetAvatarSideIconRectFromIndexRect(List indexRect, ISystemInfo systemInfo) { - return indexRect.Select(r=> GetAvatarSideIconRectFromIndexRect(r, systemInfo)).ToList(); + return indexRect.Select(r => GetAvatarSideIconRectFromIndexRect(r, systemInfo)).ToList(); } public static bool IsIntersecting(double y1, double h1, double y2, double h2) @@ -373,8 +375,7 @@ public class PartyAvatarSideIndexHelper Mat[] mats = new Mat[rectArray.Length]; try { - var whiteCount = 0; - var notWhiteRectNum = 0; + int whiteCount = 0, notWhiteRectNum = 0; var mat = imageRegion.CacheGreyMat; for (int i = 0; i < rectArray.Length; i++) { @@ -396,7 +397,14 @@ public class PartyAvatarSideIndexHelper } else { - // 使用更加靠谱的差值识别(-1是未识别) + // 方法2:边缘像素白色比例 + int m2 = FindActiveIndexRectByEdgeColor(mats); + if (m2 > 0) + { + return m2; + } + + // 方法3:使用更加靠谱的差值识别(-1是未识别),但是不支持非满队 if (mats.Length == 4) { return ImageDifferenceDetector.FindMostDifferentImage(mats); @@ -414,15 +422,13 @@ public class PartyAvatarSideIndexHelper mat?.Dispose(); } } - } public static bool IsWhiteRect(Mat indexMat) { - var count1 = OpenCvCommonHelper.CountGrayMatColor(indexMat, 251, 255); // 白 var count2 = OpenCvCommonHelper.CountGrayMatColor(indexMat, 50, 54); // 黑色文字 - if ((count1 + count2) * 1.0 / (indexMat.Width * indexMat.Height) > 0.4) + if ((count1 + count2) * 1.0 / (indexMat.Width * indexMat.Height) > 0.35) { // Debug.WriteLine($"白色矩形占比{(count1 + count2) * 1.0 / (indexMat.Width * indexMat.Height)}"); return true; @@ -450,7 +456,7 @@ public class PartyAvatarSideIndexHelper { return -1; } - + for (int i = 0; i < rectArray.Length; i++) { if (IsIntersecting(curr.Y, curr.Height, rectArray[i].Y, rectArray[i].Height)) @@ -461,4 +467,98 @@ public class PartyAvatarSideIndexHelper return -1; } + + /// + /// 通过边缘像素颜色识别出战角色编号 + /// + /// + /// + public static int FindActiveIndexRectByEdgeColor(Mat[] mats) + { + try + { + int whiteCount = 0, notWhiteRectNum = 0; + for (int i = 0; i < mats.Length; i++) + { + if (CalculateWhiteEdgePixelsRatio(mats[i]) > 0.5) + { + whiteCount++; + } + else + { + notWhiteRectNum = i + 1; + } + } + + if (whiteCount == mats.Length - 1) + { + return notWhiteRectNum; + } + else + { + return -1; + } + } + catch (Exception e) + { + Debug.WriteLine(e); + } + + return -1; + } + + /// + /// 计算灰度图最边缘一圈中纯白色(255)像素的占比 + /// + /// 返回纯白像素占比 (0.0 到 1.0) + public static double CalculateWhiteEdgePixelsRatio(Mat image) + { + int whiteCount = 0; + int height = image.Height; + int width = image.Width; + + // 如果图片太小,无法获取边缘 + if (height < 1 || width < 1) + { + return 0.0; + } + + // 计算总边缘像素数 + int totalCount = 2 * (width + height - 2); + + // 顶边和底边 + for (int x = 0; x < width; x++) + { + // 顶边 + if (image.At(0, x) >= 251) + { + whiteCount++; + } + + // 底边(避免只有一行时重复计数) + if (height > 1 && image.At(height - 1, x) >= 251) + { + whiteCount++; + } + } + + // 左边和右边(不包括四个角,因为已经在顶边和底边中计算过) + for (int y = 1; y < height - 1; y++) + { + // 左边 + if (image.At(y, 0) >= 251) + { + whiteCount++; + } + + // 右边(避免只有一列时重复计数) + if (width > 1 && image.At(y, width - 1) >= 251) + { + whiteCount++; + } + } + + // 计算并返回占比 + return totalCount > 0 ? (double)whiteCount / totalCount : 0.0; + } } \ No newline at end of file diff --git a/Test/BetterGenshinImpact.Test/Cv/ImageDifferenceDetectorTest.cs b/Test/BetterGenshinImpact.Test/Cv/ImageDifferenceDetectorTest.cs index f6ffab02..28124b0b 100644 --- a/Test/BetterGenshinImpact.Test/Cv/ImageDifferenceDetectorTest.cs +++ b/Test/BetterGenshinImpact.Test/Cv/ImageDifferenceDetectorTest.cs @@ -1,4 +1,5 @@ using BetterGenshinImpact.Core.Recognition.OpenCv; +using BetterGenshinImpact.GameTask.AutoFight.Model; using OpenCvSharp; namespace BetterGenshinImpact.Test.Cv; @@ -16,4 +17,13 @@ public class ImageDifferenceDetectorTest Console.WriteLine($"差异最大的图片索引是: {i}"); } + + public static void Test2() + { + Console.WriteLine($"1: {PartyAvatarSideIndexHelper.CalculateWhiteEdgePixelsRatio(Cv2.ImRead(@"E:\1.png", ImreadModes.Grayscale))}"); + Console.WriteLine($"2: {PartyAvatarSideIndexHelper.CalculateWhiteEdgePixelsRatio(Cv2.ImRead(@"E:\2.png", ImreadModes.Grayscale))}"); + Console.WriteLine($"3: {PartyAvatarSideIndexHelper.CalculateWhiteEdgePixelsRatio(Cv2.ImRead(@"E:\3.png", ImreadModes.Grayscale))}"); + Console.WriteLine($"4: {PartyAvatarSideIndexHelper.CalculateWhiteEdgePixelsRatio(Cv2.ImRead(@"E:\4.png", ImreadModes.Grayscale))}"); + + } } \ No newline at end of file From 971151eaa10dceb4f106150e30a31ad05150289a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Wed, 26 Nov 2025 21:24:16 +0800 Subject: [PATCH 18/73] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20using?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/Service/ScriptService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/Service/ScriptService.cs b/BetterGenshinImpact/Service/ScriptService.cs index 7ba75295..fd4dbd9b 100644 --- a/BetterGenshinImpact/Service/ScriptService.cs +++ b/BetterGenshinImpact/Service/ScriptService.cs @@ -583,7 +583,7 @@ public partial class ScriptService : IScriptService continue; } - var content = TaskControl.CaptureToRectArea(); + using var content = TaskControl.CaptureToRectArea(); if (Bv.IsInMainUi(content) || Bv.IsInAnyClosableUi(content) || Bv.IsInDomain(content)) { return; From 55ed41f878a2a796672bf68cd8b036009fc8390a Mon Sep 17 00:00:00 2001 From: Jamis Date: Fri, 28 Nov 2025 10:24:31 +0800 Subject: [PATCH 19/73] optimise log display in mask window (#2496) --- BetterGenshinImpact/View/MaskWindow.xaml.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BetterGenshinImpact/View/MaskWindow.xaml.cs b/BetterGenshinImpact/View/MaskWindow.xaml.cs index 6c1dc487..72d93ac3 100644 --- a/BetterGenshinImpact/View/MaskWindow.xaml.cs +++ b/BetterGenshinImpact/View/MaskWindow.xaml.cs @@ -205,6 +205,10 @@ public partial class MaskWindow : Window private void LogTextBoxTextChanged(object sender, TextChangedEventArgs e) { + if (LogTextBox.Document.Blocks.FirstBlock is Paragraph p && p.Inlines.Count > 100) + { + (p.Inlines as System.Collections.IList).RemoveAt(0); + } var textRange = new TextRange(LogTextBox.Document.ContentStart, LogTextBox.Document.ContentEnd); if (textRange.Text.Length > 10000) { From ba4ec6f7f6641de36e0c932a6355e5387ebcb3ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Fri, 28 Nov 2025 21:21:26 +0800 Subject: [PATCH 20/73] fix fish type --- BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs b/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs index 2544c410..6928fcc5 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs @@ -30,7 +30,7 @@ public class BigFishType public static readonly BigFishType Rapidfish = new("rapidfish", BaitType.SpinelgrainBait, "斗士急流鱼", 9); public static readonly BigFishType PhonyUnihornfish = new("phony unihornfish", BaitType.EmberglowBait, "燃素独角鱼", 10); public static readonly BigFishType MagmaRapidfish = new("magma rapidfish", BaitType.EmberglowBait, "炽岩斗士急流鱼", 9); - public static readonly BigFishType SecretSourceScoutSweeper = new ("secret", BaitType.EmberglowBait, "秘源机关・巡戒使", 9); + public static readonly BigFishType SecretSourceScoutSweeper = new ("secret source", BaitType.EmberglowBait, "秘源机关・巡戒使", 9); public static readonly BigFishType MaulerShark = new ("mauler shark", BaitType.RefreshingLakkaBait, "凶凶鲨", 9); public static readonly BigFishType CrystalEye = new("crystal eye", BaitType.RefreshingLakkaBait, "明眼鱼", 9); From 38e541137e47ecb0f6bf3f86171ff8c3d83224f7 Mon Sep 17 00:00:00 2001 From: huiyadanli <15783049+huiyadanli@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:23:40 +0000 Subject: [PATCH 21/73] Update version to 0.53.2-alpha.4 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index fe3ad69f..630f5771 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -2,7 +2,7 @@ BetterGI - 0.53.2-alpha.3 + 0.53.2-alpha.4 false WinExe net8.0-windows10.0.22621.0 From fdd270068d5d810a0a528cedf2e6e2d87a4a38a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sun, 30 Nov 2025 10:36:06 +0800 Subject: [PATCH 22/73] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=B1=BC=E7=B1=BB?= =?UTF-8?q?=E6=9E=9A=E4=B8=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs b/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs index 6928fcc5..59392e82 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs @@ -59,6 +59,7 @@ public class BigFishType yield return Rapidfish; yield return PhonyUnihornfish; yield return MagmaRapidfish; + yield return SecretSourceScoutSweeper; yield return MaulerShark; yield return CrystalEye; yield return AxeheadFish; From 18efc69d0dd27cded233ef48aee26a2f41d7bbda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BA=81=E5=8A=A8=E7=9A=84=E6=B0=A8=E6=B0=94?= <131591012+zaodonganqi@users.noreply.github.com> Date: Sun, 30 Nov 2025 19:35:46 +0800 Subject: [PATCH 23/73] =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=BC=B9=E7=AA=97UI?= =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=8C=E6=9B=B4=E6=96=B0=E6=88=AA=E5=8F=96?= =?UTF-8?q?=E7=89=A9=E5=93=81=E5=9B=BE=E6=A0=87=E5=AF=BC=E8=88=AA=E5=9C=B0?= =?UTF-8?q?=E5=9D=80=20(#2499)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/Model/SettingItem.cs | 10 +- .../Editable/ScriptGroupProjectEditor.xaml | 120 +++++++++--------- .../Pages/TaskSettingsPageViewModel.cs | 2 +- .../ScriptGroupProjectEditorViewModel.cs | 14 ++ 4 files changed, 82 insertions(+), 64 deletions(-) diff --git a/BetterGenshinImpact/Model/SettingItem.cs b/BetterGenshinImpact/Model/SettingItem.cs index 9350112e..685460ff 100644 --- a/BetterGenshinImpact/Model/SettingItem.cs +++ b/BetterGenshinImpact/Model/SettingItem.cs @@ -22,10 +22,11 @@ public class SettingItem { var list = new List(); - var label = new Label + var label = new TextBlock { - Content = Label, - Margin = new Thickness(0, 0, 0, 5) + Text = Label, + Margin = new Thickness(0, 0, 0, 5), + TextWrapping = TextWrapping.Wrap }; list.Add(label); @@ -40,7 +41,8 @@ public class SettingItem var textBox = new TextBox { Name = Name, - Margin = new Thickness(0, 0, 0, 10) + Margin = new Thickness(0, 0, 0, 10), + TextWrapping = TextWrapping.Wrap }; if (Default != null) { diff --git a/BetterGenshinImpact/View/Windows/Editable/ScriptGroupProjectEditor.xaml b/BetterGenshinImpact/View/Windows/Editable/ScriptGroupProjectEditor.xaml index abd8394e..c1ad45de 100644 --- a/BetterGenshinImpact/View/Windows/Editable/ScriptGroupProjectEditor.xaml +++ b/BetterGenshinImpact/View/Windows/Editable/ScriptGroupProjectEditor.xaml @@ -21,9 +21,10 @@ - + + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + diff --git a/BetterGenshinImpact/ViewModel/Pages/TaskSettingsPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/TaskSettingsPageViewModel.cs index e23841bd..4029d6de 100644 --- a/BetterGenshinImpact/ViewModel/Pages/TaskSettingsPageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/TaskSettingsPageViewModel.cs @@ -633,7 +633,7 @@ public partial class TaskSettingsPageViewModel : ViewModel [RelayCommand] private async Task OnGoToGetGridIconsUrlAsync() { - await Launcher.LaunchUriAsync(new Uri("https://bettergi.com/feats/task/getGridIcons.html")); + await Launcher.LaunchUriAsync(new Uri("https://bettergi.com/dev/getGridIcons.html")); } [RelayCommand] diff --git a/BetterGenshinImpact/ViewModel/Windows/Editable/ScriptGroupProjectEditorViewModel.cs b/BetterGenshinImpact/ViewModel/Windows/Editable/ScriptGroupProjectEditorViewModel.cs index c3c42124..5ee70e12 100644 --- a/BetterGenshinImpact/ViewModel/Windows/Editable/ScriptGroupProjectEditorViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Windows/Editable/ScriptGroupProjectEditorViewModel.cs @@ -125,6 +125,20 @@ public class ScriptGroupProjectEditorViewModel : ObservableObject public ScriptGroupProjectEditorViewModel(ScriptGroupProject project) { _project = project ?? throw new ArgumentNullException(nameof(project)); + + // 如果是JS脚本,每次打开配置窗口时强制重新加载项目信息,以读取最新的manifest.json + if (_project.Type == "Javascript") + { + try + { + _project.BuildScriptProjectRelation(); + } + catch + { + // 忽略加载失败,避免无法打开窗口,界面上会显示相关错误或为空 + } + } + _globalNotificationConfig = TaskContext.Instance().Config.NotificationConfig; // 监听全局配置变更 _project.PropertyChanged += (s, e) => From f8ec331a658b7e922e2f8fac0231c87f5f6d0372 Mon Sep 17 00:00:00 2001 From: ShadowLemoon <119576779+ShadowLemoon@users.noreply.github.com> Date: Sun, 30 Nov 2025 19:36:04 +0800 Subject: [PATCH 24/73] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=8E=A8?= =?UTF-8?q?=E7=90=86=E8=AE=BE=E5=A4=87=E7=9A=84=E6=9B=B4=E5=A4=9A=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E5=A4=A7=E5=B0=8F=20(#2502)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs index d432880f..0e2926f1 100644 --- a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs @@ -510,8 +510,11 @@ public partial class HomePageViewModel : ViewModel { Title = "硬件加速设置", Content = new HardwareAccelerationView(new HardwareAccelerationViewModel()), - SizeToContent = SizeToContent.WidthAndHeight, - ResizeMode = ResizeMode.NoResize, + Width = 800, + Height = 600, + MinWidth = 800, + MaxWidth = 800, + MinHeight = 600, Owner = Application.Current.MainWindow, WindowStartupLocation = WindowStartupLocation.CenterOwner, ExtendsContentIntoTitleBar = true, From a9f5541145a213d18e05664916511cdab0db5e4a Mon Sep 17 00:00:00 2001 From: ShadowLemoon <119576779+ShadowLemoon@users.noreply.github.com> Date: Sun, 30 Nov 2025 19:37:48 +0800 Subject: [PATCH 25/73] =?UTF-8?q?refactor:=20=E6=8F=90=E5=8F=96=E8=AF=86?= =?UTF-8?q?=E5=88=AB=E5=B9=B6=E7=82=B9=E5=87=BB=E6=8C=89=E9=92=AE=E7=9A=84?= =?UTF-8?q?=E9=80=9A=E7=94=A8=E6=96=B9=E6=B3=95=E5=B9=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=BB=B6=E8=BF=9F=20(#2503)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Common/BgiVision/BvSimpleOperation.cs | 110 +++++------------- 1 file changed, 30 insertions(+), 80 deletions(-) diff --git a/BetterGenshinImpact/GameTask/Common/BgiVision/BvSimpleOperation.cs b/BetterGenshinImpact/GameTask/Common/BgiVision/BvSimpleOperation.cs index 6f8ea7d2..6e19402f 100644 --- a/BetterGenshinImpact/GameTask/Common/BgiVision/BvSimpleOperation.cs +++ b/BetterGenshinImpact/GameTask/Common/BgiVision/BvSimpleOperation.cs @@ -6,6 +6,7 @@ using BetterGenshinImpact.GameTask.Model.Area; using Fischless.WindowsInput; using OpenCvSharp; using System.Text.RegularExpressions; +using System.Threading; namespace BetterGenshinImpact.GameTask.Common.BgiVision; @@ -17,53 +18,47 @@ namespace BetterGenshinImpact.GameTask.Common.BgiVision; /// public static partial class Bv { + /// + /// 通用方法:查找识别对象,如果存在则点击 + /// + /// 截图区域 + /// 识别对象 + /// 是否找到并点击 + public static bool FindAndClick(ImageRegion captureRa, RecognitionObject ro) + { + var ra = captureRa.Find(ro); + if (ra.IsExist()) + { + Thread.Sleep(500); + ra.Click(); + return true; + } + return false; + } + /// /// 点击减少按钮 /// /// /// public static bool ClickReduceButton(ImageRegion captureRa) - { - var ra = captureRa.Find(ElementAssets.Instance.Keyreduce); - if (ra.IsExist()) - { - ra.Click(); - return true; - } - return false; - } - + => FindAndClick(captureRa, ElementAssets.Instance.Keyreduce); + /// /// 点击增加按钮 + /// /// /// public static bool ClickAddButton(ImageRegion captureRa) - { - var ra = captureRa.Find(ElementAssets.Instance.Keyincrease); - if (ra.IsExist()) - { - ra.Click(); - return true; - } - return false; - } - + => FindAndClick(captureRa, ElementAssets.Instance.Keyincrease); + /// /// 点击白色确认按钮 /// /// /// public static bool ClickWhiteConfirmButton(ImageRegion captureRa) - { - var ra = captureRa.Find(ElementAssets.Instance.BtnWhiteConfirm); - if (ra.IsExist()) - { - ra.Click(); - return true; - } - - return false; - } + => FindAndClick(captureRa, ElementAssets.Instance.BtnWhiteConfirm); /// /// 点击白色取消按钮 @@ -71,16 +66,7 @@ public static partial class Bv /// /// public static bool ClickWhiteCancelButton(ImageRegion captureRa) - { - var ra = captureRa.Find(ElementAssets.Instance.BtnWhiteCancel); - if (ra.IsExist()) - { - ra.Click(); - return true; - } - - return false; - } + => FindAndClick(captureRa, ElementAssets.Instance.BtnWhiteCancel); /// /// 点击黑色确认按钮 @@ -88,16 +74,7 @@ public static partial class Bv /// /// public static bool ClickBlackConfirmButton(ImageRegion captureRa) - { - var ra = captureRa.Find(ElementAssets.Instance.BtnBlackConfirm); - if (ra.IsExist()) - { - ra.Click(); - return true; - } - - return false; - } + => FindAndClick(captureRa, ElementAssets.Instance.BtnBlackConfirm); /// /// 点击黑色取消按钮 @@ -105,16 +82,7 @@ public static partial class Bv /// /// public static bool ClickBlackCancelButton(ImageRegion captureRa) - { - var ra = captureRa.Find(ElementAssets.Instance.BtnBlackCancel); - if (ra.IsExist()) - { - ra.Click(); - return true; - } - - return false; - } + => FindAndClick(captureRa, ElementAssets.Instance.BtnBlackCancel); /// /// 点击联机确认按钮 @@ -122,16 +90,7 @@ public static partial class Bv /// /// public static bool ClickOnlineYesButton(ImageRegion captureRa) - { - var ra = captureRa.Find(ElementAssets.Instance.BtnOnlineYes); - if (ra.IsExist()) - { - ra.Click(); - return true; - } - - return false; - } + => FindAndClick(captureRa, ElementAssets.Instance.BtnOnlineYes); /// /// 点击联机取消按钮 @@ -139,16 +98,7 @@ public static partial class Bv /// /// public static bool ClickOnlineNoButton(ImageRegion captureRa) - { - var ra = captureRa.Find(ElementAssets.Instance.BtnOnlineNo); - if (ra.IsExist()) - { - ra.Click(); - return true; - } - - return false; - } + => FindAndClick(captureRa, ElementAssets.Instance.BtnOnlineNo); /// /// 点击确认按钮(优先点击白色背景的确认按钮) From c4df2324b5ca8ee5848a548dec7ea7a917acf3ac Mon Sep 17 00:00:00 2001 From: DarkFlameMaster <1004452714@qq.com> Date: Sun, 30 Nov 2025 21:47:18 +0800 Subject: [PATCH 26/73] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=89=A7=E6=83=85?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89=E5=85=B3=E9=94=AE?= =?UTF-8?q?=E8=AF=8D=20#2435=20(#2497)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoSkip/AutoSkipConfig.cs | 11 ++++- .../GameTask/AutoSkip/AutoSkipTrigger.cs | 23 +++++++++- .../View/Pages/TriggerSettingsPage.xaml | 43 ++++++++++++++++++- .../Pages/TriggerSettingsPageViewModel.cs | 2 +- 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs index e38f98af..0a74a8e8 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs @@ -62,6 +62,12 @@ public partial class AutoSkipConfig : ObservableObject /// [ObservableProperty] private string _clickChatOption = "优先选择第一个选项"; + + /// + /// 自定义优先选项文本,每行一个或用分号分隔 + /// + [ObservableProperty] + private string _customPriorityOptions = ""; /// /// 自动邀约启用 @@ -96,7 +102,10 @@ public partial class AutoSkipConfig : ObservableObject { return ClickChatOption == "随机选择选项"; } - + public bool IsClickCustomPriorityOption() + { + return ClickChatOption == "自定义优先选项"; + } public bool IsClickNoneChatOption() { return ClickChatOption == "不选择选项"; diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs index 1ce33caf..7086def8 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs @@ -544,7 +544,28 @@ public partial class AutoSkipTrigger : ITaskTrigger if (rs.Count > 0) { - // 用户自定义关键词 匹配 + // 自定义优先选项匹配 + if (_config.IsClickCustomPriorityOption() && !string.IsNullOrEmpty(_config.CustomPriorityOptions)) + { + var customOptions = _config.CustomPriorityOptions + .Split(new[] { '\r', '\n', ';', ';' }, StringSplitOptions.RemoveEmptyEntries) + .Select(s => s.Trim()) + .Where(s => !string.IsNullOrEmpty(s)) + .ToList(); + + foreach (var item in rs) + { + foreach (var customOption in customOptions) + { + if (item.Text.Contains(customOption)) + { + ClickOcrRegion(item); + return true; + } + } + } + } + // 内置关键词 匹配 foreach (var item in rs) { // 选择关键词 diff --git a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml index be096b89..840b615b 100644 --- a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml +++ b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml @@ -328,7 +328,7 @@ + + + + + + + + + + + + + + + + diff --git a/BetterGenshinImpact/ViewModel/Pages/TriggerSettingsPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/TriggerSettingsPageViewModel.cs index 623fec17..420dd360 100644 --- a/BetterGenshinImpact/ViewModel/Pages/TriggerSettingsPageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/TriggerSettingsPageViewModel.cs @@ -21,7 +21,7 @@ namespace BetterGenshinImpact.ViewModel.Pages; public partial class TriggerSettingsPageViewModel : ViewModel { - [ObservableProperty] private string[] _clickChatOptionNames = ["优先选择第一个选项", "随机选择选项", "优先选择最后一个选项", "不选择选项"]; + [ObservableProperty] private string[] _clickChatOptionNames = ["优先选择第一个选项", "随机选择选项","自定义优先选项", "优先选择最后一个选项", "不选择选项"]; [ObservableProperty] private string[] _selectChatOptionTypeNames = [SelectChatOptionTypes.UseMouse, SelectChatOptionTypes.UseInteractionKey]; From e62a76d238f0a98554859b6349eebbadb0a31238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BA=81=E5=8A=A8=E7=9A=84=E6=B0=A8=E6=B0=94?= <131591012+zaodonganqi@users.noreply.github.com> Date: Sun, 30 Nov 2025 21:47:46 +0800 Subject: [PATCH 27/73] =?UTF-8?q?B=E6=9C=8D=E7=99=BB=E5=BD=95=E7=9A=84?= =?UTF-8?q?=E7=AC=ACN=E6=AC=A1=E4=BC=98=E5=8C=96=20(#2504)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/GameTask/AutoWood/AutoWoodTask.cs | 2 +- .../GameTask/AutoWood/Utils/Login3rdParty.cs | 6 ++++-- BetterGenshinImpact/GameTask/GameLoading/GameLoading.cs | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoWood/AutoWoodTask.cs b/BetterGenshinImpact/GameTask/AutoWood/AutoWoodTask.cs index 2eaed037..b7e02724 100644 --- a/BetterGenshinImpact/GameTask/AutoWood/AutoWoodTask.cs +++ b/BetterGenshinImpact/GameTask/AutoWood/AutoWoodTask.cs @@ -1,4 +1,4 @@ -using BetterGenshinImpact.Core.Recognition.OCR; +using 曲线BetterGenshinImpact.Core.Recognition.OCR; using BetterGenshinImpact.Core.Simulator; using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Exception; using BetterGenshinImpact.GameTask.AutoWood.Assets; diff --git a/BetterGenshinImpact/GameTask/AutoWood/Utils/Login3rdParty.cs b/BetterGenshinImpact/GameTask/AutoWood/Utils/Login3rdParty.cs index 87d0a74f..1bce0703 100644 --- a/BetterGenshinImpact/GameTask/AutoWood/Utils/Login3rdParty.cs +++ b/BetterGenshinImpact/GameTask/AutoWood/Utils/Login3rdParty.cs @@ -8,6 +8,7 @@ using System.Threading; using BetterGenshinImpact.GameTask.Model.Area; using Vanara.PInvoke; using static BetterGenshinImpact.GameTask.Common.TaskControl; +using BetterGenshinImpact.GameTask; namespace BetterGenshinImpact.GameTask.AutoWood.Utils; @@ -107,9 +108,10 @@ internal sealed class Login3rdParty var (loginWindow, windowType) = GetBiliLoginWindow(process); if (loginWindow != IntPtr.Zero) { + var dpiScale = TaskContext.Instance().DpiScale; if (windowType.Contains("协议")) { - GameCaptureRegion.GameRegion1080PPosClick(1030, 615); + GameCaptureRegion.GameRegion1080PPosClick(960 + 70 * dpiScale, 540 + 75 * dpiScale); // 检查窗口是否还存在 var (remainingWindow, remainingType) = GetBiliLoginWindow(process); @@ -124,7 +126,7 @@ internal sealed class Login3rdParty if (windowType.Contains("登录")) { Thread.Sleep(2000); - GameCaptureRegion.GameRegion1080PPosClick(960, 630); + GameCaptureRegion.GameRegion1080PPosClick(960, 540 + 90 * dpiScale); Thread.Sleep(2000); // 检查窗口是否还存在 diff --git a/BetterGenshinImpact/GameTask/GameLoading/GameLoading.cs b/BetterGenshinImpact/GameTask/GameLoading/GameLoading.cs index 923c9133..fc368de9 100644 --- a/BetterGenshinImpact/GameTask/GameLoading/GameLoading.cs +++ b/BetterGenshinImpact/GameTask/GameLoading/GameLoading.cs @@ -316,15 +316,16 @@ public class GameLoadingTrigger : ITaskTrigger if (process != null && loginWindow != IntPtr.Zero) { + var dpiScale = TaskContext.Instance().DpiScale; if (windowType.Contains("协议")) { - GameCaptureRegion.GameRegion1080PPosClick(1030, 615); + GameCaptureRegion.GameRegion1080PPosClick(960 + 70 * dpiScale, 540 + 75 * dpiScale); } if (windowType.Contains("登录")) { Thread.Sleep(2000); - GameCaptureRegion.GameRegion1080PPosClick(960, 630); + GameCaptureRegion.GameRegion1080PPosClick(960, 540 + 90 * dpiScale); Thread.Sleep(2000); // 检查窗口是否还存在 From f19a16e1d3ef79a0eac4a1edf05d50f5406b4114 Mon Sep 17 00:00:00 2001 From: DarkFlameMaster <1004452714@qq.com> Date: Mon, 1 Dec 2025 00:40:04 +0800 Subject: [PATCH 28/73] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E7=9A=84=E6=94=AF=E6=8C=81=20(#2494)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/Script/EngineExtend.cs | 30 +++++++++++++++---- .../Core/Script/Project/ScriptProject.cs | 10 ++++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/BetterGenshinImpact/Core/Script/EngineExtend.cs b/BetterGenshinImpact/Core/Script/EngineExtend.cs index 5b5b4cc4..841686b8 100644 --- a/BetterGenshinImpact/Core/Script/EngineExtend.cs +++ b/BetterGenshinImpact/Core/Script/EngineExtend.cs @@ -1,13 +1,14 @@ -using BetterGenshinImpact.Core.Script.Dependence; +using System; +using System.Collections.Generic; +using BetterGenshinImpact.Core.Script.Dependence; using BetterGenshinImpact.Core.Script.Dependence.Model; using Microsoft.ClearScript; -using System.Reflection; using System.Threading; using System.Threading.Tasks; using OpenCvSharp; using BetterGenshinImpact.Core.Recognition; using BetterGenshinImpact.GameTask.Model.Area; -using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.Core.Script.Utils; using BetterGenshinImpact.GameTask.AutoDomain; using BetterGenshinImpact.GameTask.AutoFight; using BetterGenshinImpact.GameTask.AutoFight.Model; @@ -75,13 +76,30 @@ public class EngineExtend // 添加C#的类型 engine.AddHostType(typeof(Task)); - // 导入 CommonJS 模块 + // 导入 JavaScript 模块 // https://microsoft.github.io/ClearScript/2023/01/24/module-interop.html // https://github.com/microsoft/ClearScript/blob/master/ClearScriptTest/V8ModuleTest.cs engine.DocumentSettings.AccessFlags = DocumentAccessFlags.EnableFileLoading | DocumentAccessFlags.AllowCategoryMismatch; if (searchPaths != null) { - engine.DocumentSettings.SearchPath = string.Join(';', searchPaths); + var normalizedPaths = new List(); + foreach (var path in searchPaths) + { + try + { + var normalizedPath = ScriptUtils.NormalizePath(workDir, path); + normalizedPaths.Add(normalizedPath); + } + catch (Exception ex) + { + throw new Exception($"从 library 字段读取路径 '{path}' 失败: {ex.Message}", ex); + } + } + + if (normalizedPaths.Count > 0) + { + engine.DocumentSettings.SearchPath = string.Join(';', normalizedPaths); + } } } @@ -122,4 +140,4 @@ public class EngineExtend engine.AddHostObject("inputText", GlobalMethod.InputText); #pragma warning restore CS8974 // Converting method group to non-delegate type } -} +} \ No newline at end of file diff --git a/BetterGenshinImpact/Core/Script/Project/ScriptProject.cs b/BetterGenshinImpact/Core/Script/Project/ScriptProject.cs index d8320d89..7e0281a3 100644 --- a/BetterGenshinImpact/Core/Script/Project/ScriptProject.cs +++ b/BetterGenshinImpact/Core/Script/Project/ScriptProject.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using BetterGenshinImpact.Core.Script.Dependence; +using Microsoft.ClearScript.JavaScript; namespace BetterGenshinImpact.Core.Script.Project; @@ -89,7 +90,14 @@ public class ScriptProject } try { - await (Task)engine.Evaluate(code); + if (Manifest.Library.Length != 0) + { + await (Task)engine.Evaluate(new DocumentInfo { Category = ModuleCategory.Standard }, code); + } + else + { + await (Task)engine.Evaluate(code); + } } catch (Exception e) { From 7035bca98292bbf3aeeb296bb9eb5ec4f007d912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BA=81=E5=8A=A8=E7=9A=84=E6=B0=A8=E6=B0=94?= <131591012+zaodonganqi@users.noreply.github.com> Date: Mon, 1 Dec 2025 11:34:24 +0800 Subject: [PATCH 29/73] Fix namespace import for AutoWoodTask.cs (#2505) --- BetterGenshinImpact/GameTask/AutoWood/AutoWoodTask.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoWood/AutoWoodTask.cs b/BetterGenshinImpact/GameTask/AutoWood/AutoWoodTask.cs index b7e02724..e929448d 100644 --- a/BetterGenshinImpact/GameTask/AutoWood/AutoWoodTask.cs +++ b/BetterGenshinImpact/GameTask/AutoWood/AutoWoodTask.cs @@ -1,4 +1,4 @@ -using 曲线BetterGenshinImpact.Core.Recognition.OCR; +using BetterGenshinImpact.Core.Recognition.OCR; using BetterGenshinImpact.Core.Simulator; using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Exception; using BetterGenshinImpact.GameTask.AutoWood.Assets; @@ -549,4 +549,4 @@ public partial class AutoWoodTask : ISoloTask throw new RetryException("未检测进入游戏界面"); } } -} \ No newline at end of file +} From 63a936afee123150a9677f2a2700b6b9cb03a77f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=9D=E5=87=AF=E9=98=B3?= <10895490+haokaiyang@users.noreply.github.com> Date: Wed, 3 Dec 2025 17:49:43 +0800 Subject: [PATCH 30/73] auto tcg: update character card config to v6.2 (#2509) --- .../Assets/tcg_character_card.json | 227 +++++++++++++++++- 1 file changed, 225 insertions(+), 2 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoGeniusInvokation/Assets/tcg_character_card.json b/BetterGenshinImpact/GameTask/AutoGeniusInvokation/Assets/tcg_character_card.json index a1cff844..524034be 100644 --- a/BetterGenshinImpact/GameTask/AutoGeniusInvokation/Assets/tcg_character_card.json +++ b/BetterGenshinImpact/GameTask/AutoGeniusInvokation/Assets/tcg_character_card.json @@ -996,6 +996,83 @@ } ] }, + { + "id": 1115, + "nameEn": "escoffier", + "type": "character", + "name": "爱可菲", + "hp": 11, + "energy": 2, + "element": "冰元素", + "weapon": "长柄武器", + "skills": [ + { + "nameEn": "kitchen_skills", + "name": "后厨手艺", + "skillTag": [ + "普通攻击" + ], + "cost": [ + { + "id": 1101, + "nameEn": "cryo", + "type": "冰元素", + "count": 1 + }, + { + "id": 1109, + "nameEn": "unaligned_element", + "type": "无色元素", + "count": 2 + } + ] + }, + { + "nameEn": "lowtemperature_cooking", + "name": "低温烹饪", + "skillTag": [ + "元素战技" + ], + "cost": [ + { + "id": 1101, + "nameEn": "cryo", + "type": "冰元素", + "count": 3 + } + ] + }, + { + "nameEn": "scoring_cuts", + "name": "花刀技法", + "skillTag": [ + "元素爆发" + ], + "cost": [ + { + "id": 1101, + "nameEn": "cryo", + "type": "冰元素", + "count": 3 + }, + { + "id": 1110, + "nameEn": "energy", + "type": "充能", + "count": 2 + } + ] + }, + { + "nameEn": "constant_offthecuff_cookery", + "name": "时时刻刻的即兴料理", + "skillTag": [ + "被动技能" + ], + "cost": [] + } + ] + }, { "id": 1201, "nameEn": "barbara", @@ -1715,7 +1792,7 @@ "nameEn": "furina", "type": "character", "name": "芙宁娜", - "hp": 10, + "hp": 12, "energy": 2, "element": "水元素", "weapon": "单手剑", @@ -3001,6 +3078,75 @@ } ] }, + { + "id": 1316, + "nameEn": "gaming", + "type": "character", + "name": "嘉明", + "hp": 10, + "energy": 3, + "element": "火元素", + "weapon": "双手剑", + "skills": [ + { + "nameEn": "stellar_rend", + "name": "刃爪悬星", + "skillTag": [ + "普通攻击" + ], + "cost": [ + { + "id": 1103, + "nameEn": "pyro", + "type": "火元素", + "count": 1 + }, + { + "id": 1109, + "nameEn": "unaligned_element", + "type": "无色元素", + "count": 2 + } + ] + }, + { + "nameEn": "bestial_ascent", + "name": "瑞兽登高楼", + "skillTag": [ + "元素战技" + ], + "cost": [ + { + "id": 1103, + "nameEn": "pyro", + "type": "火元素", + "count": 3 + } + ] + }, + { + "nameEn": "suannis_gilded_dance", + "name": "璨焰金猊舞", + "skillTag": [ + "元素爆发" + ], + "cost": [ + { + "id": 1103, + "nameEn": "pyro", + "type": "火元素", + "count": 3 + }, + { + "id": 1110, + "nameEn": "energy", + "type": "充能", + "count": 3 + } + ] + } + ] + }, { "id": 1401, "nameEn": "fischl", @@ -3927,7 +4073,7 @@ "nameEn": "iansan", "type": "character", "name": "伊安珊", - "hp": 12, + "hp": 11, "energy": 2, "element": "雷元素", "weapon": "长柄武器", @@ -8690,6 +8836,83 @@ } ] }, + { + "id": 2604, + "nameEn": "black_serpent_knight_rockbreaker_ax", + "type": "character", + "name": "黑蛇骑士·摧岩之钺", + "hp": 12, + "energy": 2, + "element": "岩元素", + "weapon": "其他武器", + "skills": [ + { + "nameEn": "supreme_strike", + "name": "顶位迅斩", + "skillTag": [ + "普通攻击" + ], + "cost": [ + { + "id": 1106, + "nameEn": "geo", + "type": "岩元素", + "count": 1 + }, + { + "id": 1109, + "nameEn": "unaligned_element", + "type": "无色元素", + "count": 2 + } + ] + }, + { + "nameEn": "axe_and_aegis", + "name": "斧盾震击", + "skillTag": [ + "元素战技" + ], + "cost": [ + { + "id": 1106, + "nameEn": "geo", + "type": "岩元素", + "count": 3 + } + ] + }, + { + "nameEn": "stone_stance", + "name": "坚岩姿态", + "skillTag": [ + "元素爆发" + ], + "cost": [ + { + "id": 1106, + "nameEn": "geo", + "type": "岩元素", + "count": 3 + }, + { + "id": 1110, + "nameEn": "energy", + "type": "充能", + "count": 2 + } + ] + }, + { + "nameEn": "attacking_momentum", + "name": "攻阵气势", + "skillTag": [ + "被动技能" + ], + "cost": [] + } + ] + }, { "id": 2701, "nameEn": "jadeplume_terrorshroom", From 47f7ac19950f39e5b1d2730e28dfa1b921d1b0ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Wed, 3 Dec 2025 23:51:53 +0800 Subject: [PATCH 31/73] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=A7=92=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AutoFight/Assets/combat_avatar.json | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json b/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json index a59391f7..9eca21da 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json +++ b/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json @@ -52,7 +52,7 @@ "奇偶(男)", "MannequinBoy" ], - "id": "20000001", + "id": "10000117", "name": "奇偶(男)", "nameEn": "MannequinBoy", "weapon": "1" @@ -62,7 +62,7 @@ "奇偶(女)", "MannequinGirl" ], - "id": "20000002", + "id": "10000118", "name": "奇偶(女)", "nameEn": "MannequinGirl", "weapon": "1" @@ -1981,5 +1981,42 @@ "nameEn": "Nefer", "skillCD": 9, "weapon": "10" + }, + { + "alias": [ + "杜林", + "Durin" + ], + "burstCD": 18, + "id": "10000123", + "name": "杜林", + "nameEn": "Durin", + "skillCD": 12, + "weapon": "10" + }, + { + "alias": [ + "雅珂达", + "Jahoda" + ], + "burstCD": 18, + "id": "10000124", + "name": "雅珂达", + "nameEn": "Jahoda", + "skillCD": 15, + "weapon": "10" + }, + { + "alias": [ + "哥伦比娅", + "少女", + "Columbina" + ], + "burstCD": 15, + "id": "10000125", + "name": "哥伦比娅", + "nameEn": "Columbina", + "skillCD": 17, + "weapon": "10" } ] \ No newline at end of file From 90c6a7d93a9224b0eb8b760a599e6e0611a8dfc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sat, 6 Dec 2025 09:42:52 +0800 Subject: [PATCH 32/73] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=B0=91=E5=A5=B3?= =?UTF-8?q?=E5=90=8D=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoFight/Assets/combat_avatar.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json b/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json index 9eca21da..7403d397 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json +++ b/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json @@ -2009,8 +2009,10 @@ { "alias": [ "哥伦比娅", + "Columbina", "少女", - "Columbina" + "库塔尔", + "月神" ], "burstCD": 15, "id": "10000125", From be25f42e474f53116f66a209ba111e38c67fdca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sat, 6 Dec 2025 10:40:54 +0800 Subject: [PATCH 33/73] =?UTF-8?q?=20=20=E8=A1=A5=E5=85=85=E5=B0=91?= =?UTF-8?q?=E5=A5=B3=E7=9A=84=E5=88=AB=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoFight/Assets/combat_avatar.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json b/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json index 7403d397..5642e47c 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json +++ b/BetterGenshinImpact/GameTask/AutoFight/Assets/combat_avatar.json @@ -2012,7 +2012,8 @@ "Columbina", "少女", "库塔尔", - "月神" + "月神", + "月之少女" ], "burstCD": 15, "id": "10000125", From e3a67f309dfe9a1dc3f3f3da362455da55968e40 Mon Sep 17 00:00:00 2001 From: kaedelcb <57870068+kaedelcb@users.noreply.github.com> Date: Sat, 6 Dec 2025 10:41:54 +0800 Subject: [PATCH 34/73] =?UTF-8?q?F=E6=96=87=E5=AD=97=E8=8F=9C=E5=8D=95UI?= =?UTF-8?q?=E5=8C=BA=E5=9F=9F=E9=80=82=E9=85=8D=20(#2511)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/GameTask/Common/Job/ChooseTalkOptionTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/GameTask/Common/Job/ChooseTalkOptionTask.cs b/BetterGenshinImpact/GameTask/Common/Job/ChooseTalkOptionTask.cs index 624d9d95..8eddf31b 100644 --- a/BetterGenshinImpact/GameTask/Common/Job/ChooseTalkOptionTask.cs +++ b/BetterGenshinImpact/GameTask/Common/Job/ChooseTalkOptionTask.cs @@ -157,7 +157,7 @@ public partial class ChooseTalkOptionTask // 通过最下面的气泡框来文字识别 var lowest = chatOptionResultList[0]; - var ocrRect = new Rect((int)(lowest.X + lowest.Width + 8 * assetScale), region.Height / 12, + var ocrRect = new Rect((int)(lowest.X + lowest.Width + 8 * assetScale), region.Height / 8, (int)(535 * assetScale), (int)(lowest.Y + lowest.Height + 30 * assetScale - region.Height / 12d)); var ocrResList = region.FindMulti(RecognitionObject.Ocr(ocrRect)); From a9f3f563e1919d1f04331ed830b124c2443972ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sat, 6 Dec 2025 11:51:42 +0800 Subject: [PATCH 35/73] =?UTF-8?q?=E5=A2=9E=E5=BC=BA=20AutoSkipTrigger=20?= =?UTF-8?q?=E4=BB=A5=E6=94=AF=E6=8C=81=E6=97=A0=E6=B0=94=E6=B3=A1=E6=97=B6?= =?UTF-8?q?=E8=AF=86=E5=88=AB=20F=20=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoSkip/AutoSkipTrigger.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs index 7086def8..9ecda6ba 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs @@ -650,6 +650,16 @@ public partial class AutoSkipTrigger : ITaskTrigger return true; } + else + { + // 没有气泡的时候识别 F 选项 + using var pickRa = region.Find(AutoPickAssets.Instance.ChatPickRo); + if (pickRa.IsExist()) + { + _postMessageSimulator?.KeyPressBackground(AutoPickAssets.Instance.PickVk); + AutoSkipLog("无气泡图标,但存在交互键,直接按下交互键"); + } + } return false; } From 10dcf831e8ed0096cc1888404606022db92c9ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sat, 6 Dec 2025 13:57:18 +0800 Subject: [PATCH 36/73] =?UTF-8?q?=206.2=20=E6=AF=8F=E6=97=A5=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E7=A1=AE=E8=AE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoSkip/AutoSkipTrigger.cs | 10 ++++++++++ .../GameTask/Common/Job/GoToAdventurersGuildTask.cs | 11 ++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs index 9ecda6ba..7b56ea1b 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs @@ -591,6 +591,16 @@ public partial class AutoSkipTrigger : ITaskTrigger if (_config.AutoGetDailyRewardsEnabled && (item.Text.Contains("每日") || item.Text.Contains("委托"))) { ClickOcrRegion(item, "每日委托"); + TaskControl.Sleep(800); + + // 6.2 每日提示确认 + var ra1 = TaskControl.CaptureToRectArea(); + if (Bv.ClickBlackConfirmButton(ra1)) + { + _logger.LogInformation("存在提示并确认"); + } + ra1.Dispose(); + _prevGetDailyRewardsTime = DateTime.Now; // 记录领取时间 } else if (_config.AutoReExploreEnabled && (item.Text.Contains("探索") || item.Text.Contains("派遣"))) diff --git a/BetterGenshinImpact/GameTask/Common/Job/GoToAdventurersGuildTask.cs b/BetterGenshinImpact/GameTask/Common/Job/GoToAdventurersGuildTask.cs index 620e30a1..f8bec453 100644 --- a/BetterGenshinImpact/GameTask/Common/Job/GoToAdventurersGuildTask.cs +++ b/BetterGenshinImpact/GameTask/Common/Job/GoToAdventurersGuildTask.cs @@ -91,7 +91,16 @@ public class GoToAdventurersGuildTask if (res == TalkOptionRes.FoundAndClick) { Logger.LogInformation("▶ {Text}", "领取『每日委托』奖励!"); - await Delay(500, ct); + await Delay(800, ct); + + // 6.2 每日提示确认 + var ra1 = CaptureToRectArea(); + if (Bv.ClickBlackConfirmButton(ra1)) + { + Logger.LogInformation("存在提示并确认"); + } + ra1.Dispose(); + await _chooseTalkOptionTask.SelectLastOptionUntilEnd(ct, null, 3); // 点几下 await Bv.WaitUntilFound(ElementAssets.Instance.PaimonMenuRo, ct); await Delay(500, ct); From c26fde56441aef2f6e55b985035ab24b60c2e8df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sat, 6 Dec 2025 13:59:18 +0800 Subject: [PATCH 37/73] =?UTF-8?q?6.2=20=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 630f5771..1fd3d4a4 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -44,7 +44,7 @@ - + From 773b129bde41d793f25208976eb9d24eff0a6c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sat, 6 Dec 2025 18:30:44 +0800 Subject: [PATCH 38/73] =?UTF-8?q?=E5=8D=83=E6=98=9F=E5=A5=87=E9=81=87?= =?UTF-8?q?=E5=A4=A7=E5=8E=85F=E9=94=AE=E4=B8=8D=E8=A7=A6=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoPick/Assets/1920x1080/L.png | Bin 0 -> 308 bytes .../GameTask/AutoPick/Assets/AutoPickAssets.cs | 14 ++++++++++++++ .../GameTask/AutoPick/AutoPickTrigger.cs | 17 ++++++++++++----- 3 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 BetterGenshinImpact/GameTask/AutoPick/Assets/1920x1080/L.png diff --git a/BetterGenshinImpact/GameTask/AutoPick/Assets/1920x1080/L.png b/BetterGenshinImpact/GameTask/AutoPick/Assets/1920x1080/L.png new file mode 100644 index 0000000000000000000000000000000000000000..b1d05702257097f72c825314aff6587335713095 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^5a~60+7BevL9R^{>$3Kq)63)|7Gj4yIkU8r`iMv+DEVgBtc}%{S6C%Z8uK)ECV9_`|$*+7# z(;^K4S3#NMmM%8^k0ml^B}Ix^-JQtw?!k9fdAm2ixt~0<*aY+xgQu&X%Q~loCIDW` Bai9PI literal 0 HcmV?d00001 diff --git a/BetterGenshinImpact/GameTask/AutoPick/Assets/AutoPickAssets.cs b/BetterGenshinImpact/GameTask/AutoPick/Assets/AutoPickAssets.cs index 76258f90..be6ae35e 100644 --- a/BetterGenshinImpact/GameTask/AutoPick/Assets/AutoPickAssets.cs +++ b/BetterGenshinImpact/GameTask/AutoPick/Assets/AutoPickAssets.cs @@ -16,6 +16,8 @@ public class AutoPickAssets : BaseAssets public RecognitionObject FRo; public RecognitionObject ChatIconRo; public RecognitionObject SettingsIconRo; + public RecognitionObject LRo; + public User32.VK PickVk = User32.VK.VK_F; public RecognitionObject PickRo; @@ -51,6 +53,18 @@ public class AutoPickAssets : BaseAssets DrawOnWindow = false, DrawOnWindowPen = new Pen(Color.Chocolate, 2) }.InitTemplate(); + + LRo = new RecognitionObject + { + Name = "L", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage("AutoPick", "L.png"), + RegionOfInterest = new Rect(CaptureRect.Width-(int)(110 * AssetScale), + (int)(550 * AssetScale), + (int)(70 * AssetScale), + (int)(100 * AssetScale)), + }.InitTemplate(); + PickRo = FRo; var keyName = TaskContext.Instance().Config.AutoPickConfig.PickKey; diff --git a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs index 4e1c1e4a..f9e722f9 100644 --- a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs @@ -194,13 +194,20 @@ public partial class AutoPickTrigger : ITaskTrigger var scale = TaskContext.Instance().SystemInfo.AssetScale; var config = TaskContext.Instance().Config.AutoPickConfig; + + // 存在 L 键位是千星奇遇,无需拾取 + using var lKeyRa = content.CaptureRectArea.Find(_autoPickAssets.LRo); + if (lKeyRa.IsExist()) + { + return; + } // 识别到拾取键,开始识别物品图标 var isExcludeIcon = false; _autoPickAssets.ChatIconRo.RegionOfInterest = new Rect( foundRectArea.X + (int)(config.ItemIconLeftOffset * scale), foundRectArea.Y, (int)((config.ItemTextLeftOffset - config.ItemIconLeftOffset) * scale), foundRectArea.Height); - var chatIconRa = content.CaptureRectArea.Find(_autoPickAssets.ChatIconRo); + using var chatIconRa = content.CaptureRectArea.Find(_autoPickAssets.ChatIconRo); speedTimer.Record("识别聊天图标"); if (!chatIconRa.IsEmpty()) { @@ -210,7 +217,7 @@ public partial class AutoPickTrigger : ITaskTrigger else { _autoPickAssets.SettingsIconRo.RegionOfInterest = _autoPickAssets.ChatIconRo.RegionOfInterest; - var settingsIconRa = content.CaptureRectArea.Find(_autoPickAssets.SettingsIconRo); + using var settingsIconRa = content.CaptureRectArea.Find(_autoPickAssets.SettingsIconRo); speedTimer.Record("识别设置图标"); if (!settingsIconRa.IsEmpty()) { @@ -256,7 +263,7 @@ public partial class AutoPickTrigger : ITaskTrigger } // var textMat = new Mat(content.CaptureRectArea.SrcGreyMat, textRect); - var gradMat = new Mat(content.CaptureRectArea.CacheGreyMat, + using var gradMat = new Mat(content.CaptureRectArea.CacheGreyMat, new Rect(textRect.X, textRect.Y, textRect.Width, Math.Min(textRect.Height, 3))); var avgGrad = gradMat.Sobel(MatType.CV_32F, 1, 0).Mean().Val0; if (avgGrad < -3) @@ -273,13 +280,13 @@ public partial class AutoPickTrigger : ITaskTrigger } else { - var textMat = new Mat(content.CaptureRectArea.SrcMat, textRect); + using var textMat = new Mat(content.CaptureRectArea.SrcMat, textRect); var boundingRect = TextRectExtractor.GetTextBoundingRect(textMat); // 如果找到有效区域 if (boundingRect.X <20 && boundingRect.Width > 5 && boundingRect.Height > 5) { // 截取只包含文字的区域 - var textOnlyMat = new Mat(textMat, new Rect(0, 0, + using var textOnlyMat = new Mat(textMat, new Rect(0, 0, boundingRect.Right + 5 < textMat.Width ? boundingRect.Right + 5 : textMat.Width, textMat.Height)); text = OcrFactory.Paddle.OcrWithoutDetector(textOnlyMat); From 5b748d6774aa0a55a0c4e61b85b868932de554e2 Mon Sep 17 00:00:00 2001 From: huiyadanli <15783049+huiyadanli@users.noreply.github.com> Date: Sat, 6 Dec 2025 13:56:08 +0000 Subject: [PATCH 39/73] Update version to 0.53.3-alpha.1 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 1fd3d4a4..28eb406e 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -2,7 +2,7 @@ BetterGI - 0.53.2-alpha.4 + 0.53.3-alpha.1 false WinExe net8.0-windows10.0.22621.0 From 9eac84475779f54374212668f9d15ef30db307b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sun, 7 Dec 2025 02:11:04 +0800 Subject: [PATCH 40/73] =?UTF-8?q?=E4=BC=98=E5=8C=96OCR=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E7=9A=84CPU=E5=8D=A0=E7=94=A8=E5=92=8C=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/Core/Recognition/ONNX/BgiOnnxFactory.cs | 5 +++++ BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/BetterGenshinImpact/Core/Recognition/ONNX/BgiOnnxFactory.cs b/BetterGenshinImpact/Core/Recognition/ONNX/BgiOnnxFactory.cs index fb764405..e11b08d7 100644 --- a/BetterGenshinImpact/Core/Recognition/ONNX/BgiOnnxFactory.cs +++ b/BetterGenshinImpact/Core/Recognition/ONNX/BgiOnnxFactory.cs @@ -407,6 +407,11 @@ public class BgiOnnxFactory break; case ProviderType.Cpu: sessionOptions.AppendExecutionProvider_CPU(); + if (model.Name.Contains("PpOcr") || model.Name.Contains("Yap")) + { + sessionOptions.IntraOpNumThreads = 2; // 限制算子内部并行线程数 + sessionOptions.InterOpNumThreads = 1; // 限制算子间并行线程数(顺序执行) + } break; case ProviderType.Dnnl: sessionOptions.AppendExecutionProvider_Dnnl(); diff --git a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs index f9e722f9..221981d0 100644 --- a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs @@ -281,7 +281,8 @@ public partial class AutoPickTrigger : ITaskTrigger else { using var textMat = new Mat(content.CaptureRectArea.SrcMat, textRect); - var boundingRect = TextRectExtractor.GetTextBoundingRect(textMat); + // var boundingRect = TextRectExtractor.GetTextBoundingRect(textMat); + var boundingRect = new Rect(); // 默认不裁剪 // 如果找到有效区域 if (boundingRect.X <20 && boundingRect.Width > 5 && boundingRect.Height > 5) { From a0cea560d6d0bc23908b779df254a511e02ba0cb Mon Sep 17 00:00:00 2001 From: huiyadanli <15783049+huiyadanli@users.noreply.github.com> Date: Sat, 6 Dec 2025 18:15:18 +0000 Subject: [PATCH 41/73] Update version to 0.53.3-alpha.2 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 28eb406e..96db6797 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -2,7 +2,7 @@ BetterGI - 0.53.3-alpha.1 + 0.53.3-alpha.2 false WinExe net8.0-windows10.0.22621.0 From d282abfd4920f7b5218af3f5c52041291451a4d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sun, 7 Dec 2025 10:59:29 +0800 Subject: [PATCH 42/73] =?UTF-8?q?=E6=81=A2=E5=A4=8D=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E7=9A=84=E6=96=87=E5=AD=97=E5=8C=BA=E5=9F=9F=E6=8F=90?= =?UTF-8?q?=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/Recognition/OCR/Paddle/PaddleOcrService.cs | 4 +++- BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/BetterGenshinImpact/Core/Recognition/OCR/Paddle/PaddleOcrService.cs b/BetterGenshinImpact/Core/Recognition/OCR/Paddle/PaddleOcrService.cs index 9c70849c..fa8639c7 100644 --- a/BetterGenshinImpact/Core/Recognition/OCR/Paddle/PaddleOcrService.cs +++ b/BetterGenshinImpact/Core/Recognition/OCR/Paddle/PaddleOcrService.cs @@ -281,8 +281,10 @@ public class PaddleOcrService : IOcrService, IDisposable /// public string OcrWithoutDetector(Mat mat) { + var startTime = Stopwatch.GetTimestamp(); var str = _localRecModel.Run(mat).Text; - Debug.WriteLine($"PaddleOcrWithoutDetector 结果: {str}"); + var time = Stopwatch.GetElapsedTime(startTime); + Debug.WriteLine($"PaddleOcrWithoutDetector 耗时 {time.TotalMilliseconds}ms 结果: {str}"); return str; } diff --git a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs index 221981d0..003c4706 100644 --- a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs @@ -262,7 +262,6 @@ public partial class AutoPickTrigger : ITaskTrigger return; } - // var textMat = new Mat(content.CaptureRectArea.SrcGreyMat, textRect); using var gradMat = new Mat(content.CaptureRectArea.CacheGreyMat, new Rect(textRect.X, textRect.Y, textRect.Width, Math.Min(textRect.Height, 3))); var avgGrad = gradMat.Sobel(MatType.CV_32F, 1, 0).Mean().Val0; @@ -281,8 +280,8 @@ public partial class AutoPickTrigger : ITaskTrigger else { using var textMat = new Mat(content.CaptureRectArea.SrcMat, textRect); - // var boundingRect = TextRectExtractor.GetTextBoundingRect(textMat); - var boundingRect = new Rect(); // 默认不裁剪 + var boundingRect = TextRectExtractor.GetTextBoundingRect(textMat); + // var boundingRect = new Rect(); // 不使用自己写的文字区域提取 // 如果找到有效区域 if (boundingRect.X <20 && boundingRect.Width > 5 && boundingRect.Height > 5) { From 15d688797f57a074ba9d6017691a229d41ed0fac Mon Sep 17 00:00:00 2001 From: ShadowLemoon <119576779+ShadowLemoon@users.noreply.github.com> Date: Sun, 7 Dec 2025 23:37:52 +0800 Subject: [PATCH 43/73] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E5=8F=82=E6=95=B0=E7=9A=84=E6=96=87=E6=9C=AC=E6=A1=86?= =?UTF-8?q?=20(#2523)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/View/Pages/HomePage.xaml | 60 +++++++++----------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/BetterGenshinImpact/View/Pages/HomePage.xaml b/BetterGenshinImpact/View/Pages/HomePage.xaml index c5811f48..e1914ef5 100644 --- a/BetterGenshinImpact/View/Pages/HomePage.xaml +++ b/BetterGenshinImpact/View/Pages/HomePage.xaml @@ -399,47 +399,41 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + TextWrapping="Wrap" + AcceptsReturn="True" /> From 08f9312fb38652a35af6f052151a6078544f9b92 Mon Sep 17 00:00:00 2001 From: Bread Grocery Date: Sun, 7 Dec 2025 23:38:35 +0800 Subject: [PATCH 44/73] =?UTF-8?q?fix:=20=E6=B8=85=E9=99=A4=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=8A=A0=E8=BD=BD=E7=BC=93=E5=AD=98=E5=AF=BC=E8=87=B4?= =?UTF-8?q?library=E4=B8=AD=E7=9A=84=E6=96=87=E4=BB=B6=E5=8F=98=E5=8A=A8?= =?UTF-8?q?=E5=90=8E=E6=97=A0=E6=B3=95=E7=94=9F=E6=95=88=20(#2525)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/Core/Script/Project/ScriptProject.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BetterGenshinImpact/Core/Script/Project/ScriptProject.cs b/BetterGenshinImpact/Core/Script/Project/ScriptProject.cs index 7e0281a3..e9262e37 100644 --- a/BetterGenshinImpact/Core/Script/Project/ScriptProject.cs +++ b/BetterGenshinImpact/Core/Script/Project/ScriptProject.cs @@ -92,6 +92,8 @@ public class ScriptProject { if (Manifest.Library.Length != 0) { + // 清除Document缓存 + DocumentLoader.Default.DiscardCachedDocuments(); await (Task)engine.Evaluate(new DocumentInfo { Category = ModuleCategory.Standard }, code); } else From 275b2a5b903fedd846ddbc1408eed46210bb4e07 Mon Sep 17 00:00:00 2001 From: huiyadanli <15783049+huiyadanli@users.noreply.github.com> Date: Mon, 8 Dec 2025 14:16:52 +0000 Subject: [PATCH 45/73] Update version to 0.54.0 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 96db6797..9d27be21 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -2,7 +2,7 @@ BetterGI - 0.53.3-alpha.2 + 0.54.0 false WinExe net8.0-windows10.0.22621.0 From 72446fe51989bf500994262bc912560b4a0f6c78 Mon Sep 17 00:00:00 2001 From: Jamis Date: Thu, 11 Dec 2025 18:24:03 +0800 Subject: [PATCH 46/73] =?UTF-8?q?=E4=B8=BAjs=E9=85=8D=E7=BD=AE=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E5=A2=9E=E5=8A=A0=E5=88=86=E9=9A=94=E7=AC=A6=E5=92=8C?= =?UTF-8?q?=E5=A4=9A=E5=A4=8D=E9=80=89=E6=A1=86=20(#2535)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/Model/SettingItem.cs | 80 ++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 6 deletions(-) diff --git a/BetterGenshinImpact/Model/SettingItem.cs b/BetterGenshinImpact/Model/SettingItem.cs index 685460ff..fd79e80d 100644 --- a/BetterGenshinImpact/Model/SettingItem.cs +++ b/BetterGenshinImpact/Model/SettingItem.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text.Json; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; @@ -22,13 +24,16 @@ public class SettingItem { var list = new List(); - var label = new TextBlock + if (!String.IsNullOrEmpty(Label)) { - Text = Label, - Margin = new Thickness(0, 0, 0, 5), - TextWrapping = TextWrapping.Wrap - }; - list.Add(label); + var label = new TextBlock + { + Text = Label, + Margin = new Thickness(0, 0, 0, 5), + TextWrapping = TextWrapping.Wrap + }; + list.Add(label); + } var binding = new Binding { @@ -37,6 +42,13 @@ public class SettingItem }; switch (Type) { + case "separator": + list.Add(new Separator + { + Margin = new Thickness(0, 0, 0, 2) + }); + break; + case "input-text": var textBox = new TextBox { @@ -103,6 +115,62 @@ public class SettingItem list.Add(checkBox); break; + case "multi-checkbox": + { + var checkedValues = new List(); + if (context is IDictionary ctx) + { + if (!ctx.ContainsKey(Name)) + { + if (Default is JsonElement j) + { + ctx[Name] = j.Deserialize>(); + } + else + { + ctx[Name] = new List(); + } + } + else if (ctx[Name] is List listOfObjects) + { + ctx[Name] = listOfObjects.Select(i => (string)i).ToList(); + } + checkedValues = (List)ctx[Name]!; + } + var wrapPanel = new WrapPanel + { + Orientation = Orientation.Horizontal + }; + if (Options != null) + { + foreach (var option in Options) + { + var box = new CheckBox + { + Content = option, + IsChecked = checkedValues.Contains(option), + }; + RoutedEventHandler callback = (sender, e) => + { + bool isChecked = ((CheckBox)sender).IsChecked ?? false; + if (isChecked && !checkedValues.Contains(option)) + { + checkedValues.Add(option); + } + else if (!isChecked) + { + checkedValues.Remove(option); + } + }; + box.Checked += callback; + box.Unchecked += callback; + wrapPanel.Children.Add(box); + } + } + list.Add(wrapPanel); + break; + } + default: throw new Exception($"Unknown setting type: {Type}"); } From b2995e74020047e2663e21ffd73f17b6427be2f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Fri, 12 Dec 2025 01:16:28 +0800 Subject: [PATCH 47/73] =?UTF-8?q?=E8=A1=A5=E5=85=85=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AutoStygianOnslaughtTask.cs | 15 ++++++++++++--- .../ViewModel/Pages/HotKeyPageViewModel.cs | 6 +++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs b/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs index 653b0627..13c032b8 100644 --- a/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs +++ b/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs @@ -362,10 +362,19 @@ public class AutoStygianOnslaughtTask : ISoloTask /// private Task DomainEndDetectionTask(CancellationTokenSource cts) { - return new Task(async () => + return new Task(async void () => { - await Bv.WaitUntilFound(ElementAssets.Instance.BtnWhiteCancel, cts.Token, 150, 1000); - await cts.CancelAsync(); + try + { + await Bv.WaitUntilFound(ElementAssets.Instance.BtnWhiteCancel, cts.Token, 300, 1000); + _logger.LogInformation("检测到战斗结束,结束战斗操作线程"); + await cts.CancelAsync(); + } + catch (Exception e) + { + _logger.LogInformation("对局结束检测线程异常结束:{Msg}", e.Message); + _logger.LogDebug(e, "对局结束检测线程异常结束"); + } }, cts.Token); } diff --git a/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs index 7cf2ab22..a39f7fc2 100644 --- a/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/HotKeyPageViewModel.cs @@ -218,7 +218,11 @@ public partial class HotKeyPageViewModel : ObservableObject, IViewModel nameof(Config.HotKeyConfig.CancelTaskHotkey), Config.HotKeyConfig.CancelTaskHotkey, Config.HotKeyConfig.CancelTaskHotkeyType, - (_, _) => { CancellationContext.Instance.ManualCancel(); } + (_, _) => + { + _logger.LogInformation("检测到您配置的停止快捷键{Key}按下,停止当前执行任务", Config.HotKeyConfig.CancelTaskHotkey); + CancellationContext.Instance.ManualCancel(); + } )); systemDirectory.Children.Add(new HotKeySettingModel( "暂停当前脚本/独立任务", From 918aaf3b994099b7929b62c386221a0f20d7ad71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BA=81=E5=8A=A8=E7=9A=84=E6=B0=A8=E6=B0=94?= <131591012+zaodonganqi@users.noreply.github.com> Date: Sun, 14 Dec 2025 00:27:21 +0800 Subject: [PATCH 48/73] =?UTF-8?q?webview2=E6=94=B9=E7=94=A8=E8=99=9A?= =?UTF-8?q?=E6=8B=9F=E5=9F=9F=E5=90=8D=20(#2543)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/Script/ScriptRepoUpdater.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/BetterGenshinImpact/Core/Script/ScriptRepoUpdater.cs b/BetterGenshinImpact/Core/Script/ScriptRepoUpdater.cs index 2bfc9c09..573ad2d2 100644 --- a/BetterGenshinImpact/Core/Script/ScriptRepoUpdater.cs +++ b/BetterGenshinImpact/Core/Script/ScriptRepoUpdater.cs @@ -11,6 +11,7 @@ using BetterGenshinImpact.View.Controls.Webview; using BetterGenshinImpact.ViewModel.Pages; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; +using Microsoft.Web.WebView2.Core; using System; using System.Collections.Generic; using System.Diagnostics; @@ -1151,10 +1152,20 @@ public class ScriptRepoUpdater : Singleton _webWindow = null; }; + _webWindow.Panel!.DownloadFolderPath = MapPathingViewModel.PathJsonPath; - _webWindow.NavigateToFile(Global.Absolute(@"Assets\Web\ScriptRepo\index.html")); + // _webWindow.NavigateToFile(Global.Absolute(@"Assets\Web\ScriptRepo\index.html")); _webWindow.Panel!.OnWebViewInitializedAction = () => { + var assetsPath = Global.Absolute(@"Assets\Web\ScriptRepo"); + _webWindow.Panel!.WebView.CoreWebView2.SetVirtualHostNameToFolderMapping( + "bettergi.local", + assetsPath, + CoreWebView2HostResourceAccessKind.Allow + ); + + // _webWindow.Panel!.WebView.CoreWebView2.Navigate("https://bettergi.local/index.html"); + _webWindow.Panel!.WebView.CoreWebView2.AddHostObjectToScript("repoWebBridge", new RepoWebBridge()); // 允许内部外链使用默认浏览器打开 @@ -1170,6 +1181,8 @@ public class ScriptRepoUpdater : Singleton e.Handled = true; }; }; + + _webWindow.NavigateToUri(new Uri("https://bettergi.local/index.html")); _webWindow.Show(); } else From 8f432f6a43e8e9c0d8db56bad96081f3ccfb08aa Mon Sep 17 00:00:00 2001 From: ShadowLemoon <119576779+ShadowLemoon@users.noreply.github.com> Date: Sun, 14 Dec 2025 00:28:16 +0800 Subject: [PATCH 49/73] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E8=BF=9B?= =?UTF-8?q?=E5=85=A5=E5=B9=BD=E5=A2=83=E5=8D=B1=E6=88=98=E7=9A=84=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=20(#2537)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AutoStygianOnslaughtConfig.cs | 4 + .../AutoStygianOnslaughtTask.cs | 140 +++++++++++++++++- .../View/Pages/TaskSettingsPage.xaml | 28 ++++ 3 files changed, 170 insertions(+), 2 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtConfig.cs b/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtConfig.cs index c3f1f025..bd4e96c5 100644 --- a/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtConfig.cs +++ b/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtConfig.cs @@ -45,4 +45,8 @@ public partial class AutoStygianOnslaughtConfig : ObservableObject // 使用脆弱树脂刷取副本次数 [ObservableProperty] private int _fragileResinUseCount = 0; + + // 指定战斗队伍 + [ObservableProperty] + private string _fightTeamName = ""; } \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs b/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs index 13c032b8..9410a706 100644 --- a/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs +++ b/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs @@ -10,6 +10,7 @@ using BetterGenshinImpact.GameTask.AutoFight.Model; using BetterGenshinImpact.GameTask.AutoFight.Script; using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Exception; using BetterGenshinImpact.GameTask.AutoPick.Assets; +using BetterGenshinImpact.GameTask.AutoTrackPath; using BetterGenshinImpact.GameTask.Common; using BetterGenshinImpact.GameTask.Common.BgiVision; using BetterGenshinImpact.GameTask.Common.Element.Assets; @@ -94,6 +95,7 @@ public class AutoStygianOnslaughtTask : ISoloTask // 前置进入秘境 await TpToDomain(page); + await SelectDifficulty(page); await EnterDomain(page); await ChooseBoss(page); @@ -193,7 +195,7 @@ public class AutoStygianOnslaughtTask : ISoloTask } } - private async Task TpToDomain(BvPage page) + private async Task TpToDomain(BvPage page, bool isRetry = false) { await new ReturnMainUiTask().Start(_ct); await Delay(100, _ct); @@ -203,6 +205,7 @@ public class AutoStygianOnslaughtTask : ISoloTask { if (page.GetByText("幽境危战").WithRoi(r => r.CutRight(0.5)).IsExist()) { + await Delay(500, _ct); Simulation.SendInput.Keyboard.KeyPress(AutoPickAssets.Instance.PickVk); _logger.LogInformation($"{Name}:交互秘境"); return; @@ -216,6 +219,7 @@ public class AutoStygianOnslaughtTask : ISoloTask await page.GetByText("活动一览").WithRoi(r => r.CutLeftTop(0.3, 0.2)).WaitFor(); await Delay(500, _ct); + // 查找并点击幽境危战 - 前往挑战 if (page.GetByText("幽境危战").WithRoi(r => r.CutRight(0.5)).IsExist()) { await page.GetByText("前往挑战").WithRoi(r => r.CutRight(0.5)).Click(); @@ -226,11 +230,34 @@ public class AutoStygianOnslaughtTask : ISoloTask await Delay(1500, _ct); await page.GetByText("前往挑战").WithRoi(r => r.CutRight(0.5)).Click(); } + else + { + throw new Exception("未找到幽境危战选项"); + } _logger.LogInformation($"{Name}:点击前往挑战"); // 传送 await Delay(1000, _ct); + + try + { + await page.Locator(QuickTeleportAssets.Instance.TeleportButtonRo) + .WaitFor(); + } + catch + { + if (!isRetry) + { + // 未找到传送按钮,先返回主界面再重新进入 + _logger.LogWarning($"{Name}:未找到传送按钮,返回七天神像重新开始"); + await new TpTask(_ct).TpToStatueOfTheSeven(); + // 重新执行从打开活动界面开始的流程 + await TpToDomain(page, isRetry: true); + } + return; + } + await page.Locator(QuickTeleportAssets.Instance.TeleportButtonRo).Click(); _logger.LogInformation($"{Name}:点击传送"); await Delay(800, _ct); @@ -246,7 +273,6 @@ public class AutoStygianOnslaughtTask : ISoloTask private async Task EnterDomain(BvPage page) { - await Delay(4000, _ct); // 等待动画完成 await page.Locator(ElementAssets.Instance.BtnWhiteConfirm) .WithRoi(r => r.CutRight(0.5)) .ClickUntilDisappears(); @@ -285,6 +311,9 @@ public class AutoStygianOnslaughtTask : ISoloTask page.Click(203, 728); } + // 切换战斗队伍 + await SwitchTeam(page); + await Delay(120, _ct); // 幽境危战确认界面 @@ -577,6 +606,113 @@ public class AutoStygianOnslaughtTask : ISoloTask await new AutoArtifactSalvageTask(new AutoArtifactSalvageTaskParam(star, javaScript: null, artifactSetFilter: null, maxNumToCheck: null, recognitionFailurePolicy: null)).Start(_ct); } + private async Task SelectDifficulty(BvPage page) + { + await Delay(4000, _ct); // 等待动画完成 + + // 检查是否需要从至危挑战切换到困难 + if (page.GetByText("至危挑战").WithRoi(r => r.CutLeftTop(0.5, 0.2)).IsExist()) + { + _logger.LogInformation($"{Name}:找到至危挑战,尝试切换到困难模式"); + await Delay(500, _ct); + await page.GetByText("至危挑战").WithRoi(r => r.CutLeftTop(0.5, 0.2)).Click(); + await Delay(500, _ct); + } + + // 检查困难模式是否已选中 + var hardMode = page.GetByText("困难").WithRoi(r => r.CutRightTop(0.5, 0.2)).IsExist(); + + if (hardMode) + { + _logger.LogInformation($"{Name}:确认困难模式"); + } + else + { + _logger.LogWarning("未找到困难模式,尝试切换"); + await Delay(500, _ct); + page.Click(1096, 186); + await Delay(500, _ct); + page.Click(1093, 399); + } + } + + private async Task SwitchTeam(BvPage page) + { + var fightTeamName = _taskParam.FightTeamName; + if (string.IsNullOrEmpty(fightTeamName)) + { + _logger.LogInformation($"{Name}:不更换战斗队伍"); + return; + } + + _logger.LogInformation($"{Name}:配置战斗队伍为:{fightTeamName}"); + + // 查找预设队伍按钮并点击它打开面板 + var teamButton = page.GetByText("预设队伍").WithRoi(r => r.CutRightBottom(0.3, 0.1)).FindAll().FirstOrDefault(); + + if (teamButton == null) + { + // 如果按钮未找到,检查列表面板是否已打开 + var panelTitle = page.GetByText("预设队伍").WithRoi(r => r.CutLeftTop(0.15, 0.075)).FindAll().FirstOrDefault(); + if (panelTitle == null) + { + _logger.LogWarning("未找到预设队伍按钮,不执行切换操作"); + return; + } + // 列表面板已打开,跳过点击按钮步骤 + } + else + { + // 点击预设队伍按钮打开队伍选择面板 + teamButton.Click(); + await Delay(100, _ct); + } + + // 此时面板已打开,点击滚动条准备拖动 + page.Click(936, 150); + await Delay(100, _ct); + + // 滚轮预操作 - 按住左键准备拖动列表 + Simulation.SendInput.Mouse.LeftButtonDown(); + await Delay(100, _ct); + // 向上移动一点开始滚动 + GameCaptureRegion.GameRegion1080PPosMove(936, 140); + await Delay(100, _ct); + + int yOffset = 0; + const int maxRetries = 30; + + for (int retries = 0; retries < maxRetries; retries++) + { + // 查找队伍名称,OCR区域: 左侧竖列队伍列表 + var teamRegionList = page.GetByText(fightTeamName).WithRoi(r => r.CutLeft(0.18)).FindAll(); + var foundTeam = teamRegionList.FirstOrDefault(); + if (foundTeam != null) + { + Simulation.SendInput.Mouse.LeftButtonUp(); + await Delay(300, _ct); + foundTeam.Click(); + await Delay(500, _ct); + return; + } + + // 滚轮操作 - 在滚动条(936, y)位置拖动 + yOffset += 100; + if (130 + yOffset > 1080) + { + Simulation.SendInput.Mouse.LeftButtonUp(); + await Delay(100, _ct); + _logger.LogWarning("未找到预设战斗队伍名称,保持原有队伍"); + Simulation.SendInput.Keyboard.KeyPress(VK.VK_ESCAPE); + await Delay(500, _ct); + return; + } + + // 移动滚动条 + GameCaptureRegion.GameRegion1080PPosMove(936, 130 + yOffset); + await Delay(200, _ct); + } + } private async Task ExitDomain(BvPage page) { diff --git a/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml b/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml index 1ad11b47..0da4d7ea 100644 --- a/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml +++ b/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml @@ -1713,6 +1713,34 @@ + + + + + + + + + + + + + + From fb272c1756640c23da097c3799c2913125a7dc15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E5=B1=B1?= <939048569@qq.com> Date: Sun, 14 Dec 2025 00:29:07 +0800 Subject: [PATCH 50/73] =?UTF-8?q?Update=20MiningHandler=20=E2=80=94=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=8C=96=E7=9F=BF=E5=8A=A8=E4=BD=9C=20(#2544?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AutoPathing/Handler/MiningHandler.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoPathing/Handler/MiningHandler.cs b/BetterGenshinImpact/GameTask/AutoPathing/Handler/MiningHandler.cs index 276c4b1f..72a0857a 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/Handler/MiningHandler.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/Handler/MiningHandler.cs @@ -18,22 +18,23 @@ public class MiningHandler : IActionHandler { private readonly string[] _miningActions = [ - "诺艾尔 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", - "娜维娅 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", - "玛薇卡 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", + "爱诺 attack(0.8)", + "诺艾尔 attack(1.25)", + "玛薇卡 attack(0.20),j,wait(0.5),attack(0.6)", + "迪希雅 attack(0.22),j,wait(0.5),attack(0.22),j,wait(0.5),attack(0.45)", + "娜维娅 attack(1.25)", "辛焱 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", "重云 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", - "迪卢克 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", - "荒泷一斗 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", - "迪希雅 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", + "荒泷一斗 attack(0.1),charge(1.9),j,wait(0.5),attack(0.2)", "基尼奇 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", "菲米尼 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", "卡维 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", "优菈 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", "嘉明 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", - "多莉 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", + "多莉 attack(2.0)", "北斗 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", - "早柚 attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8),attack(0.28),jump,wait(0.8)", + "早柚 attack(0.23),j,wait(0.6),attack(0.23),j,wait(0.6),attack(0.23),j,wait(0.6),attack(0.23),j,wait(0.6)", + "迪卢克 charge(3.15),j", "坎蒂丝 e(hold,wait)", "雷泽 e(hold,wait)", "凝光 attack(4.0)", From 9c3a2d738d43139bec15c4bc276da09f29f9964a Mon Sep 17 00:00:00 2001 From: FishmanTheMurloc <162452111+FishmanTheMurloc@users.noreply.github.com> Date: Sun, 14 Dec 2025 00:29:26 +0800 Subject: [PATCH 51/73] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84Pen=E7=94=9F=E5=91=BD=E5=91=A8=E6=9C=9F=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=BB=98=E5=88=B6=E5=A4=B1=E8=B4=A5=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=9B=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=E9=B1=BC?= =?UTF-8?q?=E7=9A=84=E5=90=8D=E5=AD=97=E7=9A=84=E5=85=A5=E5=8F=82=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=20(#2545)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs | 4 +--- .../AutoFishingTests/BehavioursTests.ChooseBait.cs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs b/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs index dff8f0c8..1e3a5d68 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs @@ -859,10 +859,8 @@ namespace BetterGenshinImpact.GameTask.AutoFishing int hExtra = _cur.Height, vExtra = _cur.Height / 4; blackboard.fishBoxRect = new Rect(_cur.X - hExtra, _cur.Y - vExtra, (topMat.Width / 2 - _cur.X) * 2 + hExtra * 2, _cur.Height + vExtra * 2); - // VisionContext.Instance().DrawContent.PutRect("FishBox", _fishBoxRect.ToRectDrawable(new Pen(Color.LightPink, 2))); using var boxRa = imageRegion.Derive(blackboard.fishBoxRect); - using var pen = new System.Drawing.Pen(Color.LightPink, 2); - boxRa.DrawSelf("FishBox", pen); + boxRa.DrawSelf("FishBox", System.Drawing.Pens.LightPink); logger.LogInformation(" 识别到钓鱼框"); return BehaviourStatus.Succeeded; } diff --git a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs index 42c99678..ab2b7ac4 100644 --- a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs +++ b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs @@ -44,7 +44,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests [InlineData(@"20250225101300361_ChooseBait_Succeeded.png", new string[] { "medaka", "butterflyfish", "butterflyfish", "pufferfish" })] [InlineData(@"20250226161354285_ChooseBait_Succeeded.png", new string[] { "medaka" })] // 不稳定的测试用例,因未学习被照亮的场景 [InlineData(@"202503160917566615@900p.png", new string[] { "pufferfish" })] - [InlineData(@"202509141339218213_ChooseBait.png", new string[] { "axehead fish" })] + [InlineData(@"202509141339218213_ChooseBait.png", new string[] { "axehead" })] [InlineData(@"202509141339218213_ChooseBait.png", new string[] { "mauler shark", "crystal eye", "medaka", "medaka", "medaka" })] /// /// 测试各种选取鱼饵,结果为成功 From 4d5af17f983f7bd6c834c9553320516e71b1bbc4 Mon Sep 17 00:00:00 2001 From: Patrick-Ze <19711799+Patrick-Ze@users.noreply.github.com> Date: Sun, 14 Dec 2025 00:35:26 +0800 Subject: [PATCH 52/73] =?UTF-8?q?=E5=B0=86`=E4=B8=87=E8=83=BD=E6=88=98?= =?UTF-8?q?=E6=96=97=E7=AD=96=E7=95=A5=EF=BC=88=E8=90=8C=E6=96=B0=E6=8E=A8?= =?UTF-8?q?=E8=8D=90=EF=BC=89`=E7=A7=BB=E5=8A=A8=E8=87=B3=E5=A4=87?= =?UTF-8?q?=E7=94=A8=E7=AD=96=E7=95=A5=E6=96=87=E4=BB=B6=E5=A4=B9=20(#2534?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../User/AutoFight/{ => 群友分享}/万能战斗策略(萌新推荐).txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename BetterGenshinImpact/User/AutoFight/{ => 群友分享}/万能战斗策略(萌新推荐).txt (100%) diff --git a/BetterGenshinImpact/User/AutoFight/万能战斗策略(萌新推荐).txt b/BetterGenshinImpact/User/AutoFight/群友分享/万能战斗策略(萌新推荐).txt similarity index 100% rename from BetterGenshinImpact/User/AutoFight/万能战斗策略(萌新推荐).txt rename to BetterGenshinImpact/User/AutoFight/群友分享/万能战斗策略(萌新推荐).txt From 048e69e78b2bf57c6301eca8ec45ff2d96ce8b76 Mon Sep 17 00:00:00 2001 From: huiyadanli <15783049+huiyadanli@users.noreply.github.com> Date: Sat, 13 Dec 2025 16:40:01 +0000 Subject: [PATCH 53/73] Update version to 0.54.1-alpha.1 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 9d27be21..0de061d3 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -2,7 +2,7 @@ BetterGI - 0.54.0 + 0.54.1-alpha.1 false WinExe net8.0-windows10.0.22621.0 From 2c32dafd44fae1024229471774506a77b38474e3 Mon Sep 17 00:00:00 2001 From: Jamis Date: Sun, 14 Dec 2025 10:52:37 +0800 Subject: [PATCH 54/73] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=97=A7=E6=97=A5?= =?UTF-8?q?=E4=B9=8B=E6=B5=B7=E5=9C=B0=E5=9B=BE=20(#2546)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../GameTask/AutoTrackPath/TpTask.cs | 2 +- .../Common/Map/Maps/Base/DisplayMapTypes.cs | 3 + .../Common/Map/Maps/SeaOfBygoneErasMap.cs | 250 +++++++++++++++++- .../TeleportTransparentBackground.png | Bin 0 -> 1895 bytes .../ViewModel/Windows/MapViewerViewModel.cs | 4 + 5 files changed, 251 insertions(+), 8 deletions(-) create mode 100644 BetterGenshinImpact/GameTask/QuickTeleport/Assets/1920x1080/TeleportTransparentBackground.png diff --git a/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs b/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs index 748a7648..8e5ea498 100644 --- a/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs +++ b/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs @@ -894,7 +894,7 @@ public class TpTask if (matchRect == null) { Logger.LogWarning("切换区域失败:{Country}", areaName); - if (areaName == MapTypes.TheChasm.GetDescription() || areaName == MapTypes.Enkanomiya.GetDescription()) + if (areaName == MapTypes.TheChasm.GetDescription() || areaName == MapTypes.Enkanomiya.GetDescription() || areaName == MapTypes.SeaOfBygoneEras.GetDescription()) { throw new Exception($"切换独立地图区域[{areaName}]失败"); } diff --git a/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/DisplayMapTypes.cs b/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/DisplayMapTypes.cs index d8978d11..98b5cb3f 100644 --- a/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/DisplayMapTypes.cs +++ b/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/DisplayMapTypes.cs @@ -13,4 +13,7 @@ public enum DisplayMapTypes [Description("渊下宫")] Enkanomiya, + + [Description("旧日之海")] + SeaOfBygoneEras, } \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/Common/Map/Maps/SeaOfBygoneErasMap.cs b/BetterGenshinImpact/GameTask/Common/Map/Maps/SeaOfBygoneErasMap.cs index 7abd52d6..b1fceb8a 100644 --- a/BetterGenshinImpact/GameTask/Common/Map/Maps/SeaOfBygoneErasMap.cs +++ b/BetterGenshinImpact/GameTask/Common/Map/Maps/SeaOfBygoneErasMap.cs @@ -1,26 +1,47 @@ -using BetterGenshinImpact.GameTask.Common.Map.Maps.Base; +using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.GameTask.Common.Map.Maps.Base; using OpenCvSharp; +using Microsoft.Extensions.Logging; +using BetterGenshinImpact.Core.Recognition.OpenCv; +using System.Collections.Generic; +using System.Linq; +using System; +using Newtonsoft.Json.Linq; + namespace BetterGenshinImpact.GameTask.Common.Map.Maps; /// /// 旧日之海 -/// 从3x4改成了1x2 -/// 大地图都是半黑的,传送可能有问题 /// public class SeaOfBygoneErasMap : SceneBaseMap { #region 地图参数 - static readonly int GameMapRows = 1; // 游戏坐标下地图块的行数 - static readonly int GameMapCols = 2; // 游戏坐标下地图块的列数 - static readonly int GameMapUpRows = 0; // 游戏坐标下 左上角离地图原点的行数(注意原点在块的右下角) TODO 没找到 - static readonly int GameMapLeftCols = 0; // 游戏坐标下 左上角离地图原点的列数(注意原点在块的右下角) TODO 没找到 + static readonly int GameMapRows = 3; // 游戏坐标下地图块的行数 + static readonly int GameMapCols = 4; // 游戏坐标下地图块的列数 + static readonly int GameMapUpRows = 2; // 游戏坐标下 左上角离地图原点的行数(注意原点在块的右下角) + static readonly int GameMapLeftCols = 5; // 游戏坐标下 左上角离地图原点的列数(注意原点在块的右下角) #endregion 地图参数 static readonly int SeaOfBygoneErasMapImageBlockWidth = 1024; + private static Mat TeleportTemplate; + private static Mat TeleportTemplateMask; + private List MapTeleports; + + static SeaOfBygoneErasMap() + { + Mat img = GameTaskManager.LoadAssetImage("QuickTeleport", "TeleportTransparentBackground.png", ImreadModes.Unchanged); + + TeleportTemplate = new Mat(); + Cv2.CvtColor(img, TeleportTemplate, ColorConversionCodes.BGRA2GRAY); + + Mat[] channels = Cv2.Split(img); + TeleportTemplateMask = channels[3]; + } + public SeaOfBygoneErasMap() : base(type: MapTypes.SeaOfBygoneEras, mapSize: new Size(GameMapCols * SeaOfBygoneErasMapImageBlockWidth, GameMapRows * SeaOfBygoneErasMapImageBlockWidth), mapOriginInImageCoordinate: new Point2f((GameMapLeftCols + 1) * SeaOfBygoneErasMapImageBlockWidth, (GameMapUpRows + 1) * SeaOfBygoneErasMapImageBlockWidth), @@ -28,7 +49,222 @@ public class SeaOfBygoneErasMap : SceneBaseMap splitRow: 0, splitCol: 0) { + ExtractAndSaveFeature(Global.Absolute("Assets/Map/SeaOfBygoneEras/SeaOfBygoneEras_0_1024.png")); Layers = BaseMapLayer.LoadLayers(this); + + var mapTeleports = new List(); + var tpJson = System.IO.File.ReadAllText(Global.Absolute(@"GameTask\AutoTrackPath\Assets\tp.json")); + + JArray j = JArray.Parse(tpJson); + foreach (JObject i in j) + { + var sceneId = i["sceneId"]; + if (sceneId != null && (int)sceneId == 11) + { + foreach (var p in i["points"]!) + { + if ((string)p["type"]! != "Teleport") + { + continue; + } + var x = (float)p["position"]![2]!; + var y = (float)p["position"]![0]!; + var (x1, y1) = ConvertGenshinMapCoordinatesToImageCoordinates(x, y); + mapTeleports.Add(new Point(x1, y1)); + } + } + } + mapTeleports = mapTeleports.OrderBy(i => i.X).ThenBy(i => i.Y).ToList(); + MapTeleports = mapTeleports; + } + + public override Point2f GetBigMapPosition(Mat greyBigMapMat) + { + var rect = GetBigMapRectByTeleports(greyBigMapMat); + if (rect != default) + { + return rect.GetCenterPoint(); + } + + return base.GetBigMapPosition(greyBigMapMat); + } + + public override Rect GetBigMapRect(Mat greyBigMapMat) + { + var rect = GetBigMapRectByTeleports(greyBigMapMat); + if (rect != default) + { + return rect; + } + + return base.GetBigMapRect(greyBigMapMat); + } + + private Rect GetBigMapRectByTeleports(Mat greyBigMapMat) + { + // It's fine to miss some, but definitely no false positive results. + const double threshold = 0.99; + using Mat result = new Mat(); + Cv2.MatchTemplate(greyBigMapMat, TeleportTemplate, result, TemplateMatchModes.CCorrNormed, TeleportTemplateMask); + + var teleportPoints = new List(); + + // Step 1: Get all teleport positions from current screenshot + for (int i = 1; i < result.Rows - 1; ++i) + { + for (int j = 1; j < result.Cols - 1; ++j) + { + float val = result.At(i, j); + + if (val > threshold) + { + if (val >= result.At(i - 1, j - 1) && + val >= result.At(i - 1, j) && + val >= result.At(i - 1, j + 1) && + val >= result.At(i, j - 1) && + val >= result.At(i, j + 1) && + val >= result.At(i + 1, j - 1) && + val >= result.At(i + 1, j) && + val >= result.At(i + 1, j + 1)) + { + var newPoint = new Point(j, i); + bool tooClose = false; + foreach (var p in teleportPoints) + { + if (p.DistanceTo(newPoint) < 50) + { + tooClose = true; + break; + } + } + if (!tooClose) + { + teleportPoints.Add(newPoint); + } + } + } + } + } + + if (teleportPoints.Count < 2) + { + return default; + } + teleportPoints = teleportPoints.OrderBy(i => i.X).ThenBy(i => i.Y).ToList(); + /* + foreach (var p in teleportPoints) { + Logger.LogInformation("Teleport point: {a}", p); + } + Logger.LogInformation("Total telepoints: {c}", teleportPoints.Count); + */ + + Func GetAngleOfTwoPoints = (p0, p1) => + { + double deltaX = p0.X - p1.X; + int deltaY = p0.Y - p1.Y; + if (deltaY == 0) { return 90; } + var val = Math.Atan(deltaX / deltaY); + return val / Math.PI * 180; + }; + + // Step 2: find a diagonal determined by two of the teleports, let's call these two teleports reference points + Point rp0 = new Point(); + Point rp1 = new Point(); + double refAngle = 0.0; + { + double minAngleDiff = 180; + for (int i = 0; i < teleportPoints.Count; ++i) + { + for (int j = i + 1; j < teleportPoints.Count; ++j) + { + var p0 = teleportPoints[i]; + var p1 = teleportPoints[j]; + var angle = GetAngleOfTwoPoints(p0, p1); + if (Math.Abs(Math.Abs(angle) - 45) < minAngleDiff) + { + rp0 = p0; + rp1 = p1; + minAngleDiff = Math.Abs(Math.Abs(angle) - 45); + } + } + } + refAngle = GetAngleOfTwoPoints(rp0, rp1); + // Logger.LogInformation("Reference points {a} and {b}, Angle {c}", rp0, rp1, refAngle); + } + + { + /* + var debugMat = new Mat(); + Cv2.CvtColor(greyBigMapMat, debugMat, ColorConversionCodes.GRAY2BGR); + foreach (var p in teleportPoints) + { + Cv2.DrawMarker(debugMat, p, new Scalar(255, 0, 0), MarkerTypes.Cross, 20, 2); + } + Cv2.DrawMarker(debugMat, rp0, new Scalar(0, 255, 0), MarkerTypes.TriangleUp, 20, 2); + Cv2.DrawMarker(debugMat, rp1, new Scalar(0, 255, 0), MarkerTypes.TriangleUp, 20, 2); + Cv2.ImWrite(((DateTimeOffset)DateTime.UtcNow).ToUnixTimeMilliseconds().ToString() + ".png", debugMat); + */ + } + + // Step 3: For all diagonals determined by pairs of teleports on this map. + var minDeviation = double.MaxValue; + var transformParamScale = 0.0; + var transformParamDeltaX = 0.0; + var transformParamDeltaY = 0.0; + for (int i = 0; i < MapTeleports.Count; ++i) + { + for (int j = i + 1; j < MapTeleports.Count; ++j) + { + var mp0 = MapTeleports[i]; + var mp1 = MapTeleports[j]; + var angle = GetAngleOfTwoPoints(mp0, mp1); + if (Math.Abs(angle - refAngle) < 5) + { + // Step 4: Assuming this pair corresponds to the reference points + var mpDist = mp0.DistanceTo(mp1); + var rpDist = rp0.DistanceTo(rp1); + var scale = mpDist / rpDist; + var deltaX = mp0.X - rp0.X * scale; + var deltaY = mp0.Y - rp0.Y * scale; + + Func transformPoint = i => + { + return new Point(i.X * scale + deltaX, i.Y * scale + deltaY); + }; + + var transformedPoints = teleportPoints.Select(i => transformPoint(i)).ToList(); + // Step 5: Check how close the fit is + double totalDeviation = 0; + foreach (var p in transformedPoints) + { + var minDist = MapTeleports.Select(i => i.DistanceTo(p)).Min(); + totalDeviation += minDist; + } + if (totalDeviation < minDeviation) + { + minDeviation = totalDeviation; + transformParamScale = scale; + transformParamDeltaX = deltaX; + transformParamDeltaY = deltaY; + } + } + } + } + // Logger.LogInformation("Min deviation: {d}", minDeviation); + if (minDeviation < 200) + { + Func transformPoint = i => + { + return new Point(i.X * transformParamScale + transformParamDeltaX, i.Y * transformParamScale + transformParamDeltaY); + }; + var pTopLeft = transformPoint(new Point(0, 0)); + var pBottomRight = transformPoint(new Point(greyBigMapMat.Width, greyBigMapMat.Height)); + // Logger.LogInformation("Rect: {a}, {b}", pTopLeft, pBottomRight); + return new Rect(pTopLeft.X, pTopLeft.Y, pBottomRight.X - pTopLeft.X, pBottomRight.Y - pTopLeft.Y); + } + + + return default; } } \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/QuickTeleport/Assets/1920x1080/TeleportTransparentBackground.png b/BetterGenshinImpact/GameTask/QuickTeleport/Assets/1920x1080/TeleportTransparentBackground.png new file mode 100644 index 0000000000000000000000000000000000000000..b0bf883dfc2ae54f2a397e26587af74e03da6088 GIT binary patch literal 1895 zcmY*aX;@R&7QG2`7zJdiK!_nKjY$|DLzpCxl8}ZW5oGvOrVzuBL=qurp95n90UxQ4 zK@oyh5UHpX3D6G;P9W4EpaQQI5-K8Cra}?4>Gy7s()QeM-@VQ{Yp;Fw{d0w(!GZcP zD;NL(`eaf74a^o`Ahk8Y_g91OF<^r5Xn_QvNw#Yi+`tn^G%5g`L;=9rTmX0vQfJ=) zzzG}x%*6r#z5)Quxm6uuUf@A4Ba)m%r2-Bh)&?{n#()}#Am9T)tN@Ko3;;opPqr}) zvUf`Z1%Lt;puVMv2D54jzyPbavYG_)m!kx_t+tS;ZDXXWtefJ4=m0J>*TZ_RP5(vvH5X={cPUuk0yWm1Tc6B=`1dv#bLu$zH#xK6MSz3 zLe*${eY_{1mGoC9Hg9Vza6qi;1nY>wVYj`(QZE&Y4@qY+z|JavA4jiEs6+|`LYfi28W=nD*g*eEy)c8xSa9@YeW2ZQa z^Rg`6yV9S^n%!2{CU}Ec)x2unL^(7tvV)x{u(nfAZS&RlnE zqOh<_t|x7Eb^KNClfP&fmzGwXKIm|NvihPG|8U!v3kx>Sp1<%5Go_#@yK`B9TWbBw7%es4=TnrUij@sC*?{ywJ}@w_{+skD&cj1i!Rgj# zLu%>Gu6gW+(et)c_?_=^Vx(PpwQnukCB`GBvo6-l>#hq*pR>Zp-{&Ho4prMF#uv7< z4%P28_8qZ(7kS0u^$gPy$2Gr%WI2`Ms1*&+e!$Syr+aK{F9g~wo-WtnPAd(U-aHyj zEDNm^{k$Fz;2)zj$uyj|(xSMyxa~cohIKoA=WQ1X1&ec8-9vk9Iy+!xM2_x#v1}qB z;5ny)5euwt{^W^NF||%7VUIA>g?fLf&&W(o_bK_tzsq)=yK#fCa?B;@NxvD2PTW_n z>)fdn{5BDI-8Lpr`KF_-W@FAujB!IIyJAZeuU`0~Kr z{*rOZq1&s+wUU#hifB=h`}36EfmVZEMQQTYPCqf4+*xinGLt3uh=@28u+yuf9hTi= z-ycg9*|?P!OxNhvD8^^Jxw*qj!5qSsMEm5XOq6CXMSsQoR9}737Y*Ys>gW`-nZNrk zWB00Jcx)D-7EVhRJHR)-*2`w%msW#pUkNnkP;L?=iG!FvFMby0Mr@sj{W@zunGseQ zaNH_RJ;!gz#IJiMK^!Cs*iAAnt+O{`v+sS?b^3at7U%q}s}6OACI zIC9F4s9kZtTi4NGy_`<;yI0ry`!5?0AyC&pj*1D~M^5Ainn&^&NjI?QkjsYg4He@r`Z4 zIp+YDaE+v=l;>VhlPMVC-6eV97bx9#7+91dJOl9fLks=fEivd*L9yx&LM8?WG!bI6 F{}1d=`B(q| literal 0 HcmV?d00001 diff --git a/BetterGenshinImpact/ViewModel/Windows/MapViewerViewModel.cs b/BetterGenshinImpact/ViewModel/Windows/MapViewerViewModel.cs index 20605a68..a5bd8fe6 100644 --- a/BetterGenshinImpact/ViewModel/Windows/MapViewerViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Windows/MapViewerViewModel.cs @@ -98,6 +98,10 @@ public partial class MapViewerViewModel : ObservableObject { _mapImage = new Mat(Global.Absolute(@"Assets/Map/Enkanomiya/Enkanomiya_0_1024.png")); } + else if (mapName == MapTypes.SeaOfBygoneEras.ToString()) + { + _mapImage = new Mat(Global.Absolute(@"Assets/Map/SeaOfBygoneEras/SeaOfBygoneEras_0_1024.png")); + } else { throw new Exception("暂时不支持展示路径的地图类型:" + mapName); From 59cf8316b0090d42de28923fbda9bdaecfc425a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sun, 14 Dec 2025 11:00:09 +0800 Subject: [PATCH 55/73] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=83=8C=E6=99=AF=E5=9B=BE=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E8=BF=9E=E7=BB=AD=E6=9B=B4=E6=8D=A2=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?,=20fixed=20#2527?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs index 0e2926f1..5de056bf 100644 --- a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs @@ -588,6 +588,7 @@ public partial class HomePageViewModel : ViewModel bitmap.BeginInit(); bitmap.UriSource = new Uri(Path.GetFullPath(_customBannerImagePath)); bitmap.CacheOption = BitmapCacheOption.OnLoad; + bitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache; bitmap.EndInit(); BannerImageSource = bitmap; Toast.Success("背景图片更换成功!"); @@ -614,6 +615,7 @@ public partial class HomePageViewModel : ViewModel defaultBitmap.BeginInit(); defaultBitmap.UriSource = new Uri(DefaultBannerImagePath, UriKind.Absolute); defaultBitmap.CacheOption = BitmapCacheOption.OnLoad; + defaultBitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache; defaultBitmap.EndInit(); BannerImageSource = defaultBitmap; From c7c25b104f8d19a2969e5e2f431f6962cb8e6ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sun, 14 Dec 2025 12:15:12 +0800 Subject: [PATCH 56/73] =?UTF-8?q?=E4=BD=BF=E7=94=A8=20SetWinEventHook=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97=E9=81=AE=E7=BD=A9=E9=92=88?= =?UTF-8?q?=E5=AF=B9=E5=8E=9F=E7=A5=9E=E7=AA=97=E5=8F=A3=E7=9A=84=E8=B7=9F?= =?UTF-8?q?=E9=9A=8F=E5=BB=B6=E8=BF=9F=20#2540?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/TaskTriggerDispatcher.cs | 55 +++++++++++++++++-- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs b/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs index 75e2989b..ffc045e6 100644 --- a/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs +++ b/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs @@ -39,6 +39,15 @@ namespace BetterGenshinImpact.GameTask private static readonly object _triggerListLocker = new(); + private User32.HWINEVENTHOOK _winEventHookMoveSize; + private User32.HWINEVENTHOOK _winEventHookLocation; + private User32.WinEventProc _winEventProc; + private const uint EVENT_SYSTEM_MOVESIZESTART = 0x000A; + private const uint EVENT_SYSTEM_MOVESIZEEND = 0x000B; + private const uint EVENT_OBJECT_LOCATIONCHANGE = 0x800B; + private const uint WINEVENT_SKIPOWNTHREAD = 0x0001; + private const uint WINEVENT_SKIPOWNPROCESS = 0x0002; + public event EventHandler? UiTaskStopTickEvent; public event EventHandler? UiTaskStartTickEvent; @@ -132,6 +141,12 @@ namespace BetterGenshinImpact.GameTask } ); + // 使用 SetWinEventHook 监听窗口移动和大小变化事件 + _winEventProc = WinEventCallback; + var flags = (User32.WINEVENT)(WINEVENT_SKIPOWNPROCESS | WINEVENT_SKIPOWNTHREAD); + _winEventHookMoveSize = User32.SetWinEventHook(EVENT_SYSTEM_MOVESIZESTART, EVENT_SYSTEM_MOVESIZEEND, default, _winEventProc, 0, 0, flags); + _winEventHookLocation = User32.SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, default, _winEventProc, 0, 0, flags); + // 启动定时器 _frameIndex = 0; _timer.Interval = interval; @@ -147,6 +162,16 @@ namespace BetterGenshinImpact.GameTask GameCapture?.Stop(); _gameRect = RECT.Empty; _prevGameActive = false; + if (_winEventHookMoveSize != default) + { + User32.UnhookWinEvent(_winEventHookMoveSize); + _winEventHookMoveSize = default; + } + if (_winEventHookLocation != default) + { + User32.UnhookWinEvent(_winEventHookLocation); + _winEventHookLocation = default; + } } public void StartTimer() @@ -272,11 +297,11 @@ namespace BetterGenshinImpact.GameTask } _prevGameActive = active; - // 移动游戏窗口的时候同步遮罩窗口的位置,此时不进行捕获 - if (SyncMaskWindowPosition()) - { - return; - } + // // 移动游戏窗口的时候同步遮罩窗口的位置,此时不进行捕获 + // if (SyncMaskWindowPosition()) + // { + // return; + // } } if (_triggers == null || !_triggers.Exists(t => t.IsEnabled)) @@ -382,6 +407,24 @@ namespace BetterGenshinImpact.GameTask return rect.Width == 0 || rect.Height == 0; } + private void WinEventCallback(User32.HWINEVENTHOOK hWinEventHook, uint @event, HWND hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) + { + var target = TaskContext.Instance().GameHandle; + if (target == IntPtr.Zero) + { + return; + } + if (idObject != 0) + { + return; + } + var hwndPtr = hwnd.DangerousGetHandle(); + if (hwndPtr == target) + { + SyncMaskWindowPosition(); + } + } + public void TakeScreenshot() { try @@ -430,4 +473,4 @@ namespace BetterGenshinImpact.GameTask } } } -} \ No newline at end of file +} From f618f873264fe5dec0270dce3e39dc48a5adfb12 Mon Sep 17 00:00:00 2001 From: "std::bad_alloc" Date: Sun, 14 Dec 2025 13:31:19 +0800 Subject: [PATCH 57/73] =?UTF-8?q?=E4=B8=BA=E8=87=AA=E5=8A=A8=E5=89=A7?= =?UTF-8?q?=E6=83=85=E6=B7=BB=E5=8A=A0=E7=94=BB=E4=B8=AD=E7=94=BB=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=20(#2484)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 辉鸭蛋 --- .../GameTask/AutoSkip/AutoSkipConfig.cs | 8 +- .../GameTask/TaskTriggerDispatcher.cs | 20 ++ .../Service/PictureInPictureService.cs | 79 +++++++ .../View/Pages/TriggerSettingsPage.xaml | 27 ++- .../View/Windows/PictureInPictureWindow.xaml | 32 +++ .../Windows/PictureInPictureWindow.xaml.cs | 198 ++++++++++++++++++ 6 files changed, 362 insertions(+), 2 deletions(-) create mode 100644 BetterGenshinImpact/Service/PictureInPictureService.cs create mode 100644 BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml create mode 100644 BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml.cs diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs index 0a74a8e8..1eb40535 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs @@ -123,6 +123,12 @@ public partial class AutoSkipConfig : ObservableObject [ObservableProperty] private bool _submitGoodsEnabled = true; + /// + /// 游戏失焦时显示画中画 + /// + [ObservableProperty] + private bool _pictureInPictureEnabled = false; + /// /// 关闭弹出层 /// @@ -135,4 +141,4 @@ public partial class AutoSkipConfig : ObservableObject // /// // [ObservableProperty] // private string _selectChatOptionType = SelectChatOptionTypes.UseMouse; -} \ No newline at end of file +} diff --git a/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs b/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs index ffc045e6..ac1003ed 100644 --- a/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs +++ b/BetterGenshinImpact/GameTask/TaskTriggerDispatcher.cs @@ -14,6 +14,7 @@ using System.Linq; using System.Threading; using BetterGenshinImpact.GameTask.GameLoading; using Fischless.GameCapture.Graphics; +using BetterGenshinImpact.Service; using Vanara.PInvoke; namespace BetterGenshinImpact.GameTask @@ -162,6 +163,7 @@ namespace BetterGenshinImpact.GameTask GameCapture?.Stop(); _gameRect = RECT.Empty; _prevGameActive = false; + PictureInPictureService.Hide(resetManual: true); if (_winEventHookMoveSize != default) { User32.UnhookWinEvent(_winEventHookMoveSize); @@ -220,6 +222,7 @@ namespace BetterGenshinImpact.GameTask _logger.LogInformation("游戏已退出,BetterGI 自动停止截图器"); } + PictureInPictureService.Hide(resetManual: true); UiTaskStopTickEvent?.Invoke(sender, e); maskWindow.Invoke(maskWindow.Hide); return; @@ -227,6 +230,8 @@ namespace BetterGenshinImpact.GameTask // 检查游戏是否在前台 var hasBackgroundTriggerToRun = false; + var autoSkipConfig = TaskContext.Instance().Config.AutoSkipConfig; + var shouldShowPictureInPicture = autoSkipConfig.Enabled && autoSkipConfig.PictureInPictureEnabled && !PictureInPictureService.IsManuallyClosed; var active = SystemControl.IsGenshinImpactActive(); if (!active) { @@ -269,15 +274,21 @@ namespace BetterGenshinImpact.GameTask } } } + if (!hasBackgroundTriggerToRun && shouldShowPictureInPicture) + { + hasBackgroundTriggerToRun = true; + } if (!hasBackgroundTriggerToRun) { // 没有后台运行的触发器,这次不再进行截图 + PictureInPictureService.Hide(); return; } } else { + PictureInPictureService.Hide(resetManual: true); if (!TaskContext.Instance().Config.MaskWindowConfig.UseSubform) { // if (!_prevGameActive) @@ -324,6 +335,15 @@ namespace BetterGenshinImpact.GameTask return; } + if (shouldShowPictureInPicture && !active) + { + PictureInPictureService.Update(bitmap); + } + else + { + PictureInPictureService.Hide(); + } + // 循环执行所有触发器 有独占状态的触发器的时候只执行独占触发器 var content = new CaptureContent(bitmap, _frameIndex, _timer.Interval); diff --git a/BetterGenshinImpact/Service/PictureInPictureService.cs b/BetterGenshinImpact/Service/PictureInPictureService.cs new file mode 100644 index 00000000..74c9074b --- /dev/null +++ b/BetterGenshinImpact/Service/PictureInPictureService.cs @@ -0,0 +1,79 @@ +using BetterGenshinImpact.Helpers; +using BetterGenshinImpact.View.Windows; +using OpenCvSharp; +using System; + +namespace BetterGenshinImpact.Service; + +public static class PictureInPictureService +{ + private static PictureInPictureWindow? _window; + private static bool _manualClosed; + + public static bool IsManuallyClosed => _manualClosed; + + public static void Update(Mat frame) + { + if (_manualClosed) + { + return; + } + + var copy = frame.Clone(); + UIDispatcherHelper.BeginInvoke(() => + { + EnsureWindow(); + if (_window == null) + { + copy.Dispose(); + return; + } + + if (!_window.IsVisible) + { + _window.Show(); + } + + _window.SetFrame(copy); + }); + } + + public static void Hide(bool resetManual = false) + { + UIDispatcherHelper.BeginInvoke(() => + { + if (resetManual) + { + _manualClosed = false; + } + + if (_window != null && _window.IsVisible) + { + _window.Hide(); + } + }); + } + + public static void ResetManualClose() + { + _manualClosed = false; + } + + private static void EnsureWindow() + { + if (_window != null) + { + return; + } + + _window = new PictureInPictureWindow(); + _window.ClosedByUser += () => + { + _manualClosed = true; + }; + _window.Closed += (_, _) => + { + _window = null; + }; + } +} diff --git a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml index 840b615b..2a8023a5 100644 --- a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml +++ b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml @@ -260,6 +260,31 @@ Margin="0,0,36,0" IsChecked="{Binding Config.AutoSkipConfig.RunBackgroundEnabled, Mode=TwoWay}" /> + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml b/BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml new file mode 100644 index 00000000..788c500c --- /dev/null +++ b/BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml @@ -0,0 +1,32 @@ + + + + + diff --git a/BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml.cs b/BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml.cs new file mode 100644 index 00000000..d07ec814 --- /dev/null +++ b/BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml.cs @@ -0,0 +1,198 @@ +using BetterGenshinImpact.GameTask; +using BetterGenshinImpact.Helpers.DpiAwareness; +using BetterGenshinImpact.Helpers.Extensions; +using Mat = OpenCvSharp.Mat; +using System; +using System.Windows; +using System.Windows.Input; +using System.Windows.Media.Animation; +using BetterGenshinImpact.Helpers; +using System.Windows.Media; +using System.Windows.Interop; +using Vanara.PInvoke; +using Size = OpenCvSharp.Size; +using System.Windows.Media.Imaging; + +namespace BetterGenshinImpact.View.Windows; + +public partial class PictureInPictureWindow : Window +{ + private const double MinWidth = 220; + private const double MaxWidth = 1280; + private const double MarginSize = 16; + + private double _aspectRatio = 16d / 9d; + private bool _initializedPosition; + private bool _pointerDown; + private bool _dragging; + private Point _downPoint; + private Size _cacheSize; + + public event Action? ClosedByUser; + + public PictureInPictureWindow() + { + InitializeComponent(); + ShowActivated = false; + Opacity = 0; + Loaded += OnLoaded; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + var fade = new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(120)); + BeginAnimation(OpacityProperty, fade); + UpdateClip(); + } + + public void SetFrame(Mat frame) + { + if (!Dispatcher.CheckAccess()) + { + // 转移所有权:后台线程把 frame 交给 UI 线程处理并释放 + _ = Dispatcher.BeginInvoke(new Action(() => SetFrame(frame))); + return; + } + + try + { + var size = new Size(frame.Width, frame.Height); + if (_cacheSize != size || PreviewImage.Source is not WriteableBitmap wb) + { + var bitmap = frame.ToWriteableBitmap(); + PreviewImage.Source = bitmap; + _cacheSize = size; + UpdateSizeFromFrame(frame.Width, frame.Height); + UpdateClip(); + if (!_initializedPosition) + { + PositionNearGame(TaskContext.Instance().SystemInfo.CaptureAreaRect); + _initializedPosition = true; + } + } + else + { + frame.UpdateWriteableBitmap(wb); + } + } + finally + { + frame.Dispose(); + } + } + + private void UpdateSizeFromFrame(int width, int height) + { + if (width <= 0 || height <= 0) + { + return; + } + + _aspectRatio = width * 1d / height; + if (double.IsNaN(Width) || Width == 0) + { + var targetWidth = Math.Clamp(width / 4d, MinWidth, MaxWidth / 1.5); + Width = targetWidth; + Height = targetWidth / _aspectRatio; + } + } + + private void PositionNearGame(RECT captureRect) + { + var dpi = DpiHelper.ScaleY; + var targetLeft = captureRect.Left / dpi + captureRect.Width / dpi - Width - MarginSize; + var targetTop = captureRect.Top / dpi + MarginSize; + + Left = Math.Max(0, targetLeft); + Top = Math.Max(0, targetTop); + } + + private void OnMouseWheel(object sender, MouseWheelEventArgs e) + { + var ratio = e.Delta > 0 ? 1.08 : 0.92; + var nextWidth = Math.Clamp(Width * ratio, MinWidth, MaxWidth); + Width = nextWidth; + Height = nextWidth / _aspectRatio; + } + + private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + _pointerDown = true; + _dragging = false; + _downPoint = e.GetPosition(this); + } + + private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + if (!_dragging) + { + SystemControl.ActivateWindow(); + } + + _pointerDown = false; + _dragging = false; + } + + private void OnMouseRightButtonUp(object sender, MouseButtonEventArgs e) + { + ClosedByUser?.Invoke(); + Close(); + } + + private void OnMouseMove(object sender, MouseEventArgs e) + { + if (!_pointerDown || _dragging) + { + return; + } + + var current = e.GetPosition(this); + if (Math.Abs(current.X - _downPoint.X) > 4 || Math.Abs(current.Y - _downPoint.Y) > 4) + { + _dragging = true; + try + { + DragMove(); + } + catch + { + // ignored + } + } + } + + private void OnBorderSizeChanged(object sender, SizeChangedEventArgs e) + { + UpdateClip(); + } + + protected override void OnSourceInitialized(EventArgs e) + { + base.OnSourceInitialized(e); + var hwnd = new WindowInteropHelper(this).Handle; + var exStyle = User32.GetWindowLong(hwnd, User32.WindowLongFlags.GWL_EXSTYLE); + _ = User32.SetWindowLong(hwnd, User32.WindowLongFlags.GWL_EXSTYLE, exStyle | (int)User32.WindowStylesEx.WS_EX_TOOLWINDOW); + } + + private void UpdateClip() + { + if (PreviewImage == null || ContainerBorder == null) + { + return; + } + + var radius = ContainerBorder.CornerRadius.TopLeft; + if (ContainerBorder.ActualWidth <= 0 || ContainerBorder.ActualHeight <= 0) + { + return; + } + + PreviewImage.Clip = new RectangleGeometry(new Rect(0, 0, ContainerBorder.ActualWidth, ContainerBorder.ActualHeight), radius, radius); + } + + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + PreviewImage.Source = null; + } +} \ No newline at end of file From 47784ca01cbc1264b6a2faaa2ecf6178c2c551c2 Mon Sep 17 00:00:00 2001 From: erfang <34360545+erfang1998@users.noreply.github.com> Date: Sun, 14 Dec 2025 14:09:02 +0800 Subject: [PATCH 58/73] =?UTF-8?q?###=20=E5=8A=9F=E8=83=BD=E8=AF=B4?= =?UTF-8?q?=E6=98=8E=20(#2528)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 辉鸭蛋 --- .../GameTask/AutoSkip/AutoSkipConfig.cs | 6 +++++ .../GameTask/AutoSkip/AutoSkipTrigger.cs | 5 ++++ .../View/Pages/TriggerSettingsPage.xaml | 26 +++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs index 1eb40535..ce31dcf8 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs @@ -36,6 +36,12 @@ public partial class AutoSkipConfig : ObservableObject [ObservableProperty] private int _afterChooseOptionSleepDelay = 0; + /// + /// 点击对话框前的延迟(毫秒) + /// + [ObservableProperty] + private int _beforeClickConfirmDelay = 0; + /// /// 自动领取每日委托奖励 /// diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs index 7b56ea1b..ca790da6 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipTrigger.cs @@ -205,6 +205,11 @@ public partial class AutoSkipTrigger : ITaskTrigger _prevPlayingTime = DateTime.Now; if (TaskContext.Instance().Config.AutoSkipConfig.QuicklySkipConversationsEnabled) { + if (_config.BeforeClickConfirmDelay > 0) + { + // 在触发点击动作之前延迟时间 + Thread.Sleep(_config.BeforeClickConfirmDelay); + } if (IsUseInteractionKey) { _postMessageSimulator? .SimulateActionBackground(GIActions.PickUpOrInteract); // 注意这里不是交互键 NOTE By Ayu0K: 这里确实是交互键 diff --git a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml index 2a8023a5..6f89f566 100644 --- a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml +++ b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml @@ -429,6 +429,32 @@ Margin="0,0,24,0" Text="{Binding Config.AutoSkipConfig.AfterChooseOptionSleepDelay, Mode=TwoWay}" /> + + + + + + + + + + + + + From 3d526c2314823c539484bd06be735bc05c5add4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sun, 14 Dec 2025 15:39:34 +0800 Subject: [PATCH 59/73] =?UTF-8?q?=E4=B8=BA=E7=94=BB=E4=B8=AD=E7=94=BB?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E6=96=B0=E5=A2=9E=E4=BA=8660=E5=B8=A7?= =?UTF-8?q?=E7=9A=84=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoSkip/AutoSkipConfig.cs | 15 +++++++ .../Service/PictureInPictureService.cs | 10 ++++- .../View/Pages/TriggerSettingsPage.xaml | 15 +++++-- .../Windows/PictureInPictureWindow.xaml.cs | 42 ++++++++++++++++++- .../Pages/TriggerSettingsPageViewModel.cs | 10 ++++- 5 files changed, 85 insertions(+), 7 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs index ce31dcf8..e983c338 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoSkipConfig.cs @@ -134,6 +134,14 @@ public partial class AutoSkipConfig : ObservableObject /// [ObservableProperty] private bool _pictureInPictureEnabled = false; + + /// + /// 画中画的源图像类型 + /// TriggerDispatcher:来自于截图器50ms一次 + /// CaptureLoop:主动获取(60帧) + /// + [ObservableProperty] + private string _pictureInPictureSourceType = nameof(PictureSourceType.CaptureLoop); /// /// 关闭弹出层 @@ -148,3 +156,10 @@ public partial class AutoSkipConfig : ObservableObject // [ObservableProperty] // private string _selectChatOptionType = SelectChatOptionTypes.UseMouse; } + + +public enum PictureSourceType +{ + TriggerDispatcher, + CaptureLoop +} \ No newline at end of file diff --git a/BetterGenshinImpact/Service/PictureInPictureService.cs b/BetterGenshinImpact/Service/PictureInPictureService.cs index 74c9074b..761eb838 100644 --- a/BetterGenshinImpact/Service/PictureInPictureService.cs +++ b/BetterGenshinImpact/Service/PictureInPictureService.cs @@ -2,6 +2,8 @@ using BetterGenshinImpact.Helpers; using BetterGenshinImpact.View.Windows; using OpenCvSharp; using System; +using BetterGenshinImpact.GameTask; +using BetterGenshinImpact.GameTask.AutoSkip; namespace BetterGenshinImpact.Service; @@ -19,13 +21,17 @@ public static class PictureInPictureService return; } - var copy = frame.Clone(); + Mat? copy = null; + if (TaskContext.Instance().Config.AutoSkipConfig.PictureInPictureSourceType == nameof(PictureSourceType.TriggerDispatcher)) + { + copy = frame.Clone(); + } UIDispatcherHelper.BeginInvoke(() => { EnsureWindow(); if (_window == null) { - copy.Dispose(); + copy?.Dispose(); return; } diff --git a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml index 6f89f566..b55fd9d4 100644 --- a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml +++ b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml @@ -268,20 +268,29 @@ + + diff --git a/BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml.cs b/BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml.cs index d07ec814..33d775b1 100644 --- a/BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml.cs +++ b/BetterGenshinImpact/View/Windows/PictureInPictureWindow.xaml.cs @@ -3,6 +3,7 @@ using BetterGenshinImpact.Helpers.DpiAwareness; using BetterGenshinImpact.Helpers.Extensions; using Mat = OpenCvSharp.Mat; using System; +using System.Diagnostics; using System.Windows; using System.Windows.Input; using System.Windows.Media.Animation; @@ -12,6 +13,8 @@ using System.Windows.Interop; using Vanara.PInvoke; using Size = OpenCvSharp.Size; using System.Windows.Media.Imaging; +using BetterGenshinImpact.GameTask.AutoSkip; +using BetterGenshinImpact.Service; namespace BetterGenshinImpact.View.Windows; @@ -36,6 +39,7 @@ public partial class PictureInPictureWindow : Window ShowActivated = false; Opacity = 0; Loaded += OnLoaded; + CompositionTarget.Rendering += Loop; } private void OnLoaded(object sender, RoutedEventArgs e) @@ -45,8 +49,44 @@ public partial class PictureInPictureWindow : Window UpdateClip(); } - public void SetFrame(Mat frame) + private void Loop(object? sender, EventArgs e) { + if (PictureInPictureService.IsManuallyClosed || !IsVisible || TaskContext.Instance().Config.AutoSkipConfig.PictureInPictureSourceType != nameof(PictureSourceType.CaptureLoop)) + { + return; + } + + using var mat = TaskTriggerDispatcher.GlobalGameCapture?.Capture(); + if (mat != null) + { + if (_cacheSize != mat.Size() || PreviewImage.Source == null) + { + PreviewImage.Source = mat.ToWriteableBitmap(); + _cacheSize = mat.Size(); + if (!_initializedPosition) + { + PositionNearGame(TaskContext.Instance().SystemInfo.CaptureAreaRect); + _initializedPosition = true; + } + } + else + { + mat.UpdateWriteableBitmap((WriteableBitmap)PreviewImage.Source); + } + } + else + { + Debug.WriteLine("截图失败"); + } + } + + public void SetFrame(Mat? frame) + { + if (frame == null || TaskContext.Instance().Config.AutoSkipConfig.PictureInPictureSourceType != nameof(PictureSourceType.TriggerDispatcher)) + { + return; + } + if (!Dispatcher.CheckAccess()) { // 转移所有权:后台线程把 frame 交给 UI 线程处理并释放 diff --git a/BetterGenshinImpact/ViewModel/Pages/TriggerSettingsPageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/TriggerSettingsPageViewModel.cs index 420dd360..57cd9bba 100644 --- a/BetterGenshinImpact/ViewModel/Pages/TriggerSettingsPageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/TriggerSettingsPageViewModel.cs @@ -2,6 +2,7 @@ using BetterGenshinImpact.GameTask.AutoPick; using BetterGenshinImpact.GameTask.AutoSkip.Assets; using BetterGenshinImpact.GameTask.AutoSkip.Model; +using BetterGenshinImpact.GameTask.AutoSkip; using BetterGenshinImpact.Service.Interface; using BetterGenshinImpact.View.Pages; using BetterGenshinImpact.View.Windows; @@ -29,6 +30,13 @@ public partial class TriggerSettingsPageViewModel : ViewModel [ObservableProperty] private List _pickButtonNames; + [ObservableProperty] private Dictionary _pictureInPictureSourceTypeDict = + new() + { + { nameof(PictureSourceType.CaptureLoop), "60帧模式" }, + { nameof(PictureSourceType.TriggerDispatcher), "截图器供图" } + }; + public AllConfig Config { get; set; } private readonly INavigationService _navigationService; @@ -234,4 +242,4 @@ public partial class TriggerSettingsPageViewModel : ViewModel { _navigationService.Navigate(typeof(HotKeyPage)); } -} \ No newline at end of file +} From 573f7f13b88d16a513d49e038f566a7bd43f3ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sun, 14 Dec 2025 21:51:17 +0800 Subject: [PATCH 60/73] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=96=B0=E7=9A=84?= =?UTF-8?q?=E8=81=9A=E6=89=80=E4=B8=8D=E6=8B=BE=E5=8F=96=E7=9A=84=E5=9C=BA?= =?UTF-8?q?=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoPick/AutoPickTrigger.cs | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs index 003c4706..58f98a92 100644 --- a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs +++ b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs @@ -38,7 +38,7 @@ public partial class AutoPickTrigger : ITaskTrigger /// 拾取黑名单 /// private HashSet _blackList = []; - + /// /// 拾取黑名单(模糊匹配) /// @@ -78,7 +78,8 @@ public partial class AutoPickTrigger : ITaskTrigger { _blackList.UnionWith(userBlackList); } - _fuzzyBlackList = ReadTextList(@"User\pick_black_lists.txt"); + + _fuzzyBlackList = ReadTextList(@"User\pick_black_lists.txt"); } if (config.WhiteListEnabled) @@ -125,7 +126,7 @@ public partial class AutoPickTrigger : ITaskTrigger return []; } - + private List ReadTextList(string textFilePath) { try @@ -194,7 +195,7 @@ public partial class AutoPickTrigger : ITaskTrigger var scale = TaskContext.Instance().SystemInfo.AssetScale; var config = TaskContext.Instance().Config.AutoPickConfig; - + // 存在 L 键位是千星奇遇,无需拾取 using var lKeyRa = content.CaptureRectArea.Find(_autoPickAssets.LRo); if (lKeyRa.IsExist()) @@ -283,13 +284,13 @@ public partial class AutoPickTrigger : ITaskTrigger var boundingRect = TextRectExtractor.GetTextBoundingRect(textMat); // var boundingRect = new Rect(); // 不使用自己写的文字区域提取 // 如果找到有效区域 - if (boundingRect.X <20 && boundingRect.Width > 5 && boundingRect.Height > 5) + if (boundingRect.X < 20 && boundingRect.Width > 5 && boundingRect.Height > 5) { // 截取只包含文字的区域 using var textOnlyMat = new Mat(textMat, new Rect(0, 0, boundingRect.Right + 5 < textMat.Width ? boundingRect.Right + 5 : textMat.Width, textMat.Height)); text = OcrFactory.Paddle.OcrWithoutDetector(textOnlyMat); - + // if (RuntimeHelper.IsDebug) // { // // 如果不等于正确文字,则保存图片 @@ -351,7 +352,8 @@ public partial class AutoPickTrigger : ITaskTrigger { return; } - if (_fuzzyBlackList.Count>0) + + if (_fuzzyBlackList.Count > 0) { if (_fuzzyBlackList.Any(item => text.Contains(item))) { @@ -367,8 +369,6 @@ public partial class AutoPickTrigger : ITaskTrigger } speedTimer.DebugPrint(); - - } private bool DoNotPick(string text) @@ -385,12 +385,13 @@ public partial class AutoPickTrigger : ITaskTrigger { return true; } + // 挪德卡莱聚所中文名特殊处理,不拾取 if (text.Contains("聚所")) { return true; } - + if (text.Contains("霜月") && text.Contains("坊")) { return true; @@ -401,6 +402,11 @@ public partial class AutoPickTrigger : ITaskTrigger return true; } + if (text.Contains("西风成垒") || text.Contains("望崖营壁") || text.Contains("魔女的花园")) + { + return true; + } + return false; } @@ -475,21 +481,21 @@ public partial class AutoPickTrigger : ITaskTrigger // 0. 首先替换相似的括号字符并删除换行符、空格,使用Span进行原地替换以获得最佳性能 Span chars = stackalloc char[text.Length]; text.AsSpan().CopyTo(chars); - + int writeIndex = 0; bool hasChanges = false; - + for (int i = 0; i < chars.Length; i++) { char c = chars[i]; - + // 跳过换行符、回车符、空格、制表符等空白字符 if (char.IsWhiteSpace(c)) { hasChanges = true; continue; } - + // 替换括号字符 if (c == '【' || c == '[') { @@ -536,11 +542,11 @@ public partial class AutoPickTrigger : ITaskTrigger // 获取清理后的文字 var cleanedSpan = span.Slice(start, end - start + 1); - + // 3. 检查并补充引号配对 bool hasLeftQuote = false; bool hasRightQuote = false; - + // 快速扫描是否存在引号 for (int i = 0; i < cleanedSpan.Length; i++) { @@ -563,9 +569,7 @@ public partial class AutoPickTrigger : ITaskTrigger Debug.WriteLine("补充缺失的左引号"); return string.Concat("「", cleanedSpan); } - + return cleanedSpan.ToString(); } - - } \ No newline at end of file From a960ef40e90e2fc93b35ccc45fd6d64cdd23c517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sun, 14 Dec 2025 23:59:21 +0800 Subject: [PATCH 61/73] =?UTF-8?q?=E5=87=BA=E6=88=98=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E7=BC=96=E5=8F=B7=E8=AF=86=E5=88=AB=EF=BC=8C=E5=A4=84=E7=90=86?= =?UTF-8?q?=E8=83=8C=E6=99=AF=E5=85=A8=E7=99=BD=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoFight/Model/CombatScenes.cs | 2 +- .../Model/PartyAvatarSideIndexHelper.cs | 33 ++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs b/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs index f608ec70..3122438e 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs @@ -466,7 +466,7 @@ public class CombatScenes : IDisposable if (PartyAvatarSideIndexHelper.CountIndexRect(imageRegion) == Avatars.Length) { bool res = RefreshTeamAvatarIndexRectList(imageRegion); - _logger.LogWarning("多次识别出战角色失败,尝试刷新角色编号位置(处理草露问题),刷新结果:{Result}", res ? "成功" : "失败"); + _logger.LogWarning("多次识别出战角色失败,尝试刷新角色编号位置,刷新结果:{Result}", res ? "成功" : "失败"); imageRegion.SrcMat.SaveImage(Global.Absolute("log\\refresh_avatar_index_rect.png")); if (res) { diff --git a/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs b/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs index 2e30b6bf..122a56ac 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs @@ -403,7 +403,7 @@ public class PartyAvatarSideIndexHelper { return m2; } - + // 方法3:使用更加靠谱的差值识别(-1是未识别),但是不支持非满队 if (mats.Length == 4) { @@ -494,6 +494,29 @@ public class PartyAvatarSideIndexHelper { return notWhiteRectNum; } + else if (whiteCount == mats.Length) + { + // 如果四个都是白色,那就找内部有没有黑色 + int blackCount = 0, notBlackRectNum = -1; + for (int i = 0; i < mats.Length; i++) + { + var count = OpenCvCommonHelper.CountGrayMatColorC1(mats[i], 50, 50); // 黑字 + if (count > 0) + { + blackCount++; + } + else + { + notBlackRectNum = i + 1; + } + } + + if (notBlackRectNum >= 1) + { + TaskControl.Logger.LogDebug("当前所有编号边缘均为白色(背景过白),通过内部黑色像素识别出战编号为{Index},存在黑色数字的角色编号有{C1}个,总角色数量{C2}", notBlackRectNum, blackCount, mats.Length); + return notBlackRectNum; + } + } else { return -1; @@ -530,13 +553,13 @@ public class PartyAvatarSideIndexHelper for (int x = 0; x < width; x++) { // 顶边 - if (image.At(0, x) >= 251) + if (image.At(0, x) == 255) { whiteCount++; } // 底边(避免只有一行时重复计数) - if (height > 1 && image.At(height - 1, x) >= 251) + if (height > 1 && image.At(height - 1, x) == 255) { whiteCount++; } @@ -546,13 +569,13 @@ public class PartyAvatarSideIndexHelper for (int y = 1; y < height - 1; y++) { // 左边 - if (image.At(y, 0) >= 251) + if (image.At(y, 0) == 255) { whiteCount++; } // 右边(避免只有一列时重复计数) - if (width > 1 && image.At(y, width - 1) >= 251) + if (width > 1 && image.At(y, width - 1) == 255) { whiteCount++; } From 85829868a13855a16546de2a44b965fa1114a960 Mon Sep 17 00:00:00 2001 From: Jamis Date: Mon, 15 Dec 2025 01:31:52 +0800 Subject: [PATCH 62/73] improve welkin moon detection (#2549) --- .../GameTask/Common/Job/BlessingOfTheWelkinMoonTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/GameTask/Common/Job/BlessingOfTheWelkinMoonTask.cs b/BetterGenshinImpact/GameTask/Common/Job/BlessingOfTheWelkinMoonTask.cs index 88ce3beb..2aaadfc6 100644 --- a/BetterGenshinImpact/GameTask/Common/Job/BlessingOfTheWelkinMoonTask.cs +++ b/BetterGenshinImpact/GameTask/Common/Job/BlessingOfTheWelkinMoonTask.cs @@ -25,7 +25,7 @@ public class BlessingOfTheWelkinMoonTask if (t.Hour == 4 && t.Minute < 10) { using var ra = CaptureToRectArea(); - if (Bv.IsInBlessingOfTheWelkinMoon(ra)) + if (Bv.IsInBlessingOfTheWelkinMoon(ra) || ra.Find(ElementAssets.Instance.PrimogemRo).IsExist()) { Logger.LogInformation("检测到空月祝福界面,自动点击"); GameCaptureRegion.GameRegion1080PPosMove(100, 100); From a40643e828f766abe2d4413eda6caa07db319bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BA=81=E5=8A=A8=E7=9A=84=E6=B0=A8=E6=B0=94?= <131591012+zaodonganqi@users.noreply.github.com> Date: Mon, 15 Dec 2025 01:32:10 +0800 Subject: [PATCH 63/73] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=99=9A=E6=8B=9F?= =?UTF-8?q?=E5=9F=9F=E5=90=8D=E6=83=85=E5=86=B5=E4=B8=8BREADME=E5=86=85?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E8=8E=B7=E5=8F=96=E6=94=AF=E6=8C=81=20(#2552?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/Script/WebView/RepoWebBridge.cs | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/BetterGenshinImpact/Core/Script/WebView/RepoWebBridge.cs b/BetterGenshinImpact/Core/Script/WebView/RepoWebBridge.cs index c6573843..eac1a69f 100644 --- a/BetterGenshinImpact/Core/Script/WebView/RepoWebBridge.cs +++ b/BetterGenshinImpact/Core/Script/WebView/RepoWebBridge.cs @@ -8,6 +8,7 @@ using BetterGenshinImpact.View.Windows; using BetterGenshinImpact.ViewModel.Message; using CommunityToolkit.Mvvm.Messaging; using Newtonsoft.Json.Linq; +using System.Net; namespace BetterGenshinImpact.Core.Script.WebView; @@ -25,6 +26,11 @@ public sealed class RepoWebBridge ".vue", ".css", ".html", ".csv", ".xml", ".yaml", ".yml", ".ini", ".config" }; + + private static readonly HashSet AllowedImageExtensions = new(StringComparer.OrdinalIgnoreCase) + { + ".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".bmp", ".ico" + }; public async Task GetRepoJson() { @@ -75,25 +81,45 @@ public sealed class RepoWebBridge { try { + // URL 解码路径(处理中文文件名) + relPath = WebUtility.UrlDecode(relPath); + string filePath = Path.Combine(ScriptRepoUpdater.CenterRepoPath, "repo", relPath) .Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + + // 验证解析后的路径在允许的目录范围内 + string normalizedBasePath = Path.GetFullPath(Path.Combine(ScriptRepoUpdater.CenterRepoPath, "repo")); + string normalizedFilePath = Path.GetFullPath(filePath); + if (!normalizedFilePath.StartsWith(normalizedBasePath, StringComparison.OrdinalIgnoreCase)) + { + return "404"; + } if (!File.Exists(filePath)) { return "404"; } - string extension = Path.GetExtension(filePath); - return AllowedTextExtensions.Contains(extension) - ? await File.ReadAllTextAsync(filePath) - : "404"; + string extension = Path.GetExtension(filePath).ToLower(); + + if (AllowedTextExtensions.Contains(extension)) + { + return await File.ReadAllTextAsync(filePath); + } + else if (AllowedImageExtensions.Contains(extension)) + { + byte[] bytes = await File.ReadAllBytesAsync(filePath); + return Convert.ToBase64String(bytes); + } + + return "404"; } catch { return "404"; } } - + public async Task UpdateSubscribed(string path) { try From c1b7a3c1f721198fb38216134f51d752b624aa6b Mon Sep 17 00:00:00 2001 From: huiyadanli <15783049+huiyadanli@users.noreply.github.com> Date: Mon, 15 Dec 2025 02:31:23 +0000 Subject: [PATCH 64/73] Update version to 0.54.1-alpha.2 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 0de061d3..57f287d8 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -2,7 +2,7 @@ BetterGI - 0.54.1-alpha.1 + 0.54.1-alpha.2 false WinExe net8.0-windows10.0.22621.0 From 39be95f126c081ac8e0d992cf3d675b3e62cdd60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Thu, 18 Dec 2025 21:24:10 +0800 Subject: [PATCH 65/73] =?UTF-8?q?=E8=B5=B0=E4=B8=80=E6=AD=A5=E9=98=B2?= =?UTF-8?q?=E6=AD=A2=E5=9C=A8=E5=9C=B0=E8=84=89=E8=8A=B1=E4=B8=8A=20#2068?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AutoStygianOnslaught/AutoStygianOnslaughtTask.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs b/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs index 9410a706..848e6ef6 100644 --- a/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs +++ b/BetterGenshinImpact/GameTask/AutoStygianOnslaught/AutoStygianOnslaughtTask.cs @@ -143,7 +143,12 @@ public class AutoStygianOnslaughtTask : ISoloTask Bv.ClickWhiteCancelButton(ra); // 点击返回后是主角 await Bv.WaitUntilFound(ElementAssets.Instance.LeylineDisorderIconRo, _ct); - await Delay(6000, _ct); // 等待载入完成 + await Delay(2500, _ct); // 等待载入完成 + // 走一步防止在地脉花上 + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyDown); + await Delay(200, _ct); + Simulation.SendInput.SimulateAction(GIActions.MoveForward, KeyType.KeyUp); + await Delay(3400, _ct); // 等待载入完成 // 4. 寻找地脉花 _logger.LogInformation($"{Name}:{{Text}}", "3. 寻找地脉花"); From f66a96f0c095e52c93d495ed2432cf6486a32996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Thu, 18 Dec 2025 21:57:07 +0800 Subject: [PATCH 66/73] Update BetterGI.Assets.Map package version to 1.0.14 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 57f287d8..2290e0ba 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -43,7 +43,7 @@ - + From f1dd7bdd548b722dda48dac50372b8e611242fd9 Mon Sep 17 00:00:00 2001 From: Jamis Date: Thu, 18 Dec 2025 21:59:45 +0800 Subject: [PATCH 67/73] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=BF=9C=E5=8F=A4?= =?UTF-8?q?=E5=9C=A3=E5=B1=B1=E5=9C=B0=E5=9B=BE=E6=94=AF=E6=8C=81=20(#2569?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameTask/AutoTrackPath/Assets/tp.json | 387 ++++++++++++++++++ .../Map/Maps/AncientSacredMountainMap.cs | 13 +- 2 files changed, 395 insertions(+), 5 deletions(-) diff --git a/BetterGenshinImpact/GameTask/AutoTrackPath/Assets/tp.json b/BetterGenshinImpact/GameTask/AutoTrackPath/Assets/tp.json index 796d107d..a414b4cf 100644 --- a/BetterGenshinImpact/GameTask/AutoTrackPath/Assets/tp.json +++ b/BetterGenshinImpact/GameTask/AutoTrackPath/Assets/tp.json @@ -14477,5 +14477,392 @@ "areaId": 600 } ] + }, + { + "mapName": "AncientSacredMountain", + "sceneId": 101, + "description": "远古圣山", + "points": [ + { + "id": "11", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 5.254, + 770.154, + -544.8 + ], + "tranPosition": [ + 8.071999, + 770.3726, + -546.2424 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 800 + }, + { + "id": "12", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 301.3517, + 201.98, + -158.3329 + ], + "tranPosition": [ + 308.8704, + 201.54634, + -151.29555 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 800 + }, + { + "id": "13", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 100.683, + 210.202, + -143.976 + ], + "tranPosition": [ + 105.01541, + 210.202, + -152.21004 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 80005 + }, + { + "id": "14", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 305.55, + 138.782, + 108.762 + ], + "tranPosition": [ + 312.97974, + 141.13326, + 102.69159 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 80006 + }, + { + "id": "15", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 345.413, + 259.0234, + 264.3909 + ], + "tranPosition": [ + 346.47064, + 259.45032, + 270.15018 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 80006 + }, + { + "id": "16", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 512.608, + 106.953, + 7.501 + ], + "tranPosition": [ + 508.58472, + 107.43931, + 19.718029 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 800 + }, + { + "id": "17", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 640.53, + 89.07455, + -89.7999 + ], + "tranPosition": [ + 645.846, + 88.50239, + -85.27797 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 800 + }, + { + "id": "18", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 261.4832, + 57.82032, + -138.0443 + ], + "tranPosition": [ + 264.99072, + 57.53672, + -152.49945 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 80004 + }, + { + "id": "19", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 541.595, + 77.494, + -287.768 + ], + "tranPosition": [ + 534.5397, + 74.56176, + -293.87283 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 800 + }, + { + "id": "2", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 747.23, + 857.58, + 44.91 + ], + "tranPosition": [ + 752.04047, + 857.8871, + 40.86717 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 80001 + }, + { + "id": "20", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 474.239, + 115.454, + -497.752 + ], + "tranPosition": [ + 469.06088, + 115.62647, + -501.97424 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 800 + }, + { + "id": "21", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 251.6618, + 146.964, + -424.2064 + ], + "tranPosition": [ + 253.07848, + 147.8764, + -432.8027 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 800 + }, + { + "id": "22", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 427.1338, + -635.1426, + -434.3028 + ], + "tranPosition": [ + 450.01736, + -635.4016, + -424.52426 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 80009 + }, + { + "id": "3", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 365.439, + 751.873, + -185.486 + ], + "tranPosition": [ + 363.01917, + 751.1264, + -182.49893 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 800 + }, + { + "id": "4", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 207.5441, + 693.96, + 196.1411 + ], + "tranPosition": [ + 209.92026, + 694.134, + 202.46678 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 80002 + }, + { + "id": "5", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + -42.25665, + 822.063, + 193.6675 + ], + "tranPosition": [ + -42.84648, + 821.274, + 185.37282 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 800 + }, + { + "id": "6", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + 37.49844, + 737.135, + 383.0565 + ], + "tranPosition": [ + 35.7756, + 736.75525, + 387.55582 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 80002 + }, + { + "id": "7", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + -246.441, + 831.017, + -90.849 + ], + "tranPosition": [ + -248.21928, + 828.3109, + -80.89331 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 800 + }, + { + "id": "8", + "gadgetId": 70110002, + "gadgetType": "TransPointSecond", + "type": "Teleport", + "position": [ + -292.383, + 885.409, + -249.987 + ], + "tranPosition": [ + -290.66766, + 885.0531, + -245.20038 + ], + "country": "纳塔", + "name": "传送锚点", + "area": "远古圣山", + "areaId": 800 + } + ] } ] \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/Common/Map/Maps/AncientSacredMountainMap.cs b/BetterGenshinImpact/GameTask/Common/Map/Maps/AncientSacredMountainMap.cs index 8884aa8f..b02a96d3 100644 --- a/BetterGenshinImpact/GameTask/Common/Map/Maps/AncientSacredMountainMap.cs +++ b/BetterGenshinImpact/GameTask/Common/Map/Maps/AncientSacredMountainMap.cs @@ -1,4 +1,5 @@ -using BetterGenshinImpact.GameTask.Common.Map.Maps.Base; +using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.GameTask.Common.Map.Maps.Base; using OpenCvSharp; namespace BetterGenshinImpact.GameTask.Common.Map.Maps; @@ -11,10 +12,10 @@ public class AncientSacredMountainMap : SceneBaseMap { #region 地图参数 - static readonly int GameMapRows = 2; // 游戏坐标下地图块的行数 - static readonly int GameMapCols = 2; // 游戏坐标下地图块的列数 - static readonly int GameMapUpRows = 0; // 游戏坐标下 左上角离地图原点的行数(注意原点在块的右下角) - static readonly int GameMapLeftCols = 0; // 游戏坐标下 左上角离地图原点的列数(注意原点在块的右下角) + static readonly int GameMapRows = 4; // 游戏坐标下地图块的行数 + static readonly int GameMapCols = 4; // 游戏坐标下地图块的列数 + static readonly int GameMapUpRows = 1; // 游戏坐标下 左上角离地图原点的行数(注意原点在块的右下角) + static readonly int GameMapLeftCols = 1; // 游戏坐标下 左上角离地图原点的列数(注意原点在块的右下角) #endregion 地图参数 @@ -27,6 +28,8 @@ public class AncientSacredMountainMap : SceneBaseMap splitRow: 0, splitCol: 0) { + ExtractAndSaveFeature(Global.Absolute("Assets/Map/AncientSacredMountain/AncientSacredMountain_0_1024.png")); + ExtractAndSaveFeature(Global.Absolute("Assets/Map/AncientSacredMountain/AncientSacredMountain_-1_1024.webp")); Layers = BaseMapLayer.LoadLayers(this); } From f73a546acb87c9b89211bd96926809b38e11242b Mon Sep 17 00:00:00 2001 From: Jamis Date: Fri, 19 Dec 2025 11:04:53 +0800 Subject: [PATCH 68/73] Sea of Bygone Eras layered map (#2559) --- .../GameTask/Common/Map/Maps/Base/BaseMapLayer.cs | 2 +- .../GameTask/Common/Map/Maps/Base/SceneBaseMap.cs | 2 +- .../GameTask/Common/Map/Maps/SeaOfBygoneErasMap.cs | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/BaseMapLayer.cs b/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/BaseMapLayer.cs index f3ee32cf..1e199a83 100644 --- a/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/BaseMapLayer.cs +++ b/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/BaseMapLayer.cs @@ -117,7 +117,7 @@ public class BaseMapLayer(SceneBaseMap baseMap) return 0; } - return a.Floor > b.Floor ? 1 : -1; + return a.Floor < b.Floor ? 1 : -1; }); return layers; } diff --git a/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/SceneBaseMap.cs b/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/SceneBaseMap.cs index dd535ab8..6e796cbe 100644 --- a/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/SceneBaseMap.cs +++ b/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/SceneBaseMap.cs @@ -102,7 +102,7 @@ public abstract class SceneBaseMap : ISceneMap { try { - var result = SiftMatcher.KnnMatch(layer.TrainKeyPoints, layer.TrainDescriptors, greyMiniMapMat); + var result = SiftMatcher.KnnMatch(layer.TrainKeyPoints, layer.TrainDescriptors, greyMiniMapMat, null, DescriptorMatcherType.BruteForce); if (result != default) { return result; diff --git a/BetterGenshinImpact/GameTask/Common/Map/Maps/SeaOfBygoneErasMap.cs b/BetterGenshinImpact/GameTask/Common/Map/Maps/SeaOfBygoneErasMap.cs index b1fceb8a..32625fc8 100644 --- a/BetterGenshinImpact/GameTask/Common/Map/Maps/SeaOfBygoneErasMap.cs +++ b/BetterGenshinImpact/GameTask/Common/Map/Maps/SeaOfBygoneErasMap.cs @@ -50,6 +50,8 @@ public class SeaOfBygoneErasMap : SceneBaseMap splitCol: 0) { ExtractAndSaveFeature(Global.Absolute("Assets/Map/SeaOfBygoneEras/SeaOfBygoneEras_0_1024.png")); + ExtractAndSaveFeature(Global.Absolute("Assets/Map/SeaOfBygoneEras/SeaOfBygoneEras_-1_1024.webp")); + ExtractAndSaveFeature(Global.Absolute("Assets/Map/SeaOfBygoneEras/SeaOfBygoneEras_-2_1024.webp")); Layers = BaseMapLayer.LoadLayers(this); var mapTeleports = new List(); From cf7eab0939fffb183c4d70b63c75cd6292545fcb Mon Sep 17 00:00:00 2001 From: Jamis Date: Sat, 20 Dec 2025 00:27:06 +0800 Subject: [PATCH 69/73] update misc map data (#2570) --- BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs | 2 +- .../GameTask/Common/Map/Maps/Base/DisplayMapTypes.cs | 3 +++ BetterGenshinImpact/ViewModel/Windows/MapViewerViewModel.cs | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs b/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs index 8e5ea498..c7bed5f3 100644 --- a/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs +++ b/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs @@ -894,7 +894,7 @@ public class TpTask if (matchRect == null) { Logger.LogWarning("切换区域失败:{Country}", areaName); - if (areaName == MapTypes.TheChasm.GetDescription() || areaName == MapTypes.Enkanomiya.GetDescription() || areaName == MapTypes.SeaOfBygoneEras.GetDescription()) + if (areaName == MapTypes.TheChasm.GetDescription() || areaName == MapTypes.Enkanomiya.GetDescription() || areaName == MapTypes.SeaOfBygoneEras.GetDescription() || areaName == MapTypes.AncientSacredMountain.GetDescription()) { throw new Exception($"切换独立地图区域[{areaName}]失败"); } diff --git a/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/DisplayMapTypes.cs b/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/DisplayMapTypes.cs index 98b5cb3f..057bad86 100644 --- a/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/DisplayMapTypes.cs +++ b/BetterGenshinImpact/GameTask/Common/Map/Maps/Base/DisplayMapTypes.cs @@ -16,4 +16,7 @@ public enum DisplayMapTypes [Description("旧日之海")] SeaOfBygoneEras, + + [Description("远古圣山")] + AncientSacredMountain, } \ No newline at end of file diff --git a/BetterGenshinImpact/ViewModel/Windows/MapViewerViewModel.cs b/BetterGenshinImpact/ViewModel/Windows/MapViewerViewModel.cs index a5bd8fe6..53c7c1cd 100644 --- a/BetterGenshinImpact/ViewModel/Windows/MapViewerViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Windows/MapViewerViewModel.cs @@ -102,6 +102,10 @@ public partial class MapViewerViewModel : ObservableObject { _mapImage = new Mat(Global.Absolute(@"Assets/Map/SeaOfBygoneEras/SeaOfBygoneEras_0_1024.png")); } + else if (mapName == MapTypes.AncientSacredMountain.ToString()) + { + _mapImage = new Mat(Global.Absolute(@"Assets/Map/AncientSacredMountain/AncientSacredMountain_0_1024.png")); + } else { throw new Exception("暂时不支持展示路径的地图类型:" + mapName); From b4a1e9a2ab44d1afccbbed20f68d834c27cc0a24 Mon Sep 17 00:00:00 2001 From: Jamis Date: Tue, 23 Dec 2025 00:24:46 +0800 Subject: [PATCH 70/73] try to not interrupt pathing (#2532) --- .../GameTask/AutoPathing/PathExecutor.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs index 01fbca79..e322031e 100644 --- a/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs +++ b/BetterGenshinImpact/GameTask/AutoPathing/PathExecutor.cs @@ -721,6 +721,7 @@ public class PathExecutor var fastMode = false; var prevPositions = new List(); var fastModeColdTime = DateTime.MinValue; + var prevNotTooFarPosition = position; int num = 0, distanceTooFarRetryCount = 0, consecutiveRotationCountBeyondAngle = 0; // 按下w,一直走 @@ -790,10 +791,22 @@ public class PathExecutor { Logger.LogWarning($"距离过远({position.X},{position.Y})->({waypoint.X},{waypoint.Y})={distance},重试"); } + // 取余减少判断频率 + if (distanceTooFarRetryCount % 10 == 0) + { + await ResolveAnomalies(screen); + Logger.LogInformation($"重置到上次正确识别的坐标 ({prevNotTooFarPosition.X},{prevNotTooFarPosition.Y})"); + Navigation.SetPrevPosition(prevNotTooFarPosition.X, prevNotTooFarPosition.Y); + // 淡入淡出特效 + await Delay(500, ct); + } await Delay(50, ct); continue; } } + } else + { + prevNotTooFarPosition = position; } // 非攀爬状态下,检测是否卡死(脱困触发器) From 88bcf9b1514fa39ca3606bfc04cf3d16c1a16797 Mon Sep 17 00:00:00 2001 From: DarkFlameMaster <1004452714@qq.com> Date: Tue, 23 Dec 2025 00:25:49 +0800 Subject: [PATCH 71/73] =?UTF-8?q?=E6=9A=B4=E9=9C=B2=E9=94=AE=E9=BC=A0?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E7=BB=99js=E5=B1=82=20(#2571)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eavina <147073068+Eavina@users.noreply.github.com> --- .../Core/Monitor/MouseKeyMonitor.cs | 35 +- .../Core/Script/Dependence/KeyMouseHook.cs | 386 ++++++++++++++++++ .../Core/Script/EngineExtend.cs | 4 +- 3 files changed, 415 insertions(+), 10 deletions(-) create mode 100644 BetterGenshinImpact/Core/Script/Dependence/KeyMouseHook.cs diff --git a/BetterGenshinImpact/Core/Monitor/MouseKeyMonitor.cs b/BetterGenshinImpact/Core/Monitor/MouseKeyMonitor.cs index acc09573..79b0c4ea 100644 --- a/BetterGenshinImpact/Core/Monitor/MouseKeyMonitor.cs +++ b/BetterGenshinImpact/Core/Monitor/MouseKeyMonitor.cs @@ -6,6 +6,7 @@ using BetterGenshinImpact.Model; using Gma.System.MouseKeyHook; using System; using System.Diagnostics; +using System.Threading; using System.Windows.Forms; using Vanara.PInvoke; using Timer = System.Timers.Timer; @@ -41,21 +42,38 @@ public class MouseKeyMonitor /// private DateTime _firstSpaceKeyDownTime = DateTime.MaxValue; - private IKeyboardMouseEvents? _globalHook; + private static IKeyboardMouseEvents? _globalHook; + private static readonly object GlobalHookLock = new object(); + public static IKeyboardMouseEvents GlobalHook + { + get + { + if (_globalHook == null) + { + lock (GlobalHookLock) + { + if (_globalHook == null) + { + _globalHook = Hook.GlobalEvents(); + } + } + } + return _globalHook; + } + } private nint _hWnd; public void Subscribe(nint gameHandle) { _hWnd = gameHandle; // Note: for the application hook, use the Hook.AppEvents() instead - _globalHook = Hook.GlobalEvents(); - _globalHook.KeyDown += GlobalHookKeyDown; - _globalHook.KeyUp += GlobalHookKeyUp; - _globalHook.MouseDownExt += GlobalHookMouseDownExt; - _globalHook.MouseUpExt += GlobalHookMouseUpExt; - _globalHook.MouseMoveExt += GlobalHookMouseMoveExt; - _globalHook.MouseWheelExt += GlobalHookMouseWheelExt; + GlobalHook.KeyDown += GlobalHookKeyDown; + GlobalHook.KeyUp += GlobalHookKeyUp; + GlobalHook.MouseDownExt += GlobalHookMouseDownExt; + GlobalHook.MouseUpExt += GlobalHookMouseUpExt; + GlobalHook.MouseMoveExt += GlobalHookMouseMoveExt; + GlobalHook.MouseWheelExt += GlobalHookMouseWheelExt; //_globalHook.KeyPress += GlobalHookKeyPress; _pickUpKey = TaskContext.Instance().Config.KeyBindingsConfig.PickUpOrInteract.ToWinFormKeys(); @@ -200,6 +218,7 @@ public class MouseKeyMonitor _globalHook.MouseWheelExt -= GlobalHookMouseWheelExt; //_globalHook.KeyPress -= GlobalHookKeyPress; _globalHook.Dispose(); + _globalHook = null; } } } diff --git a/BetterGenshinImpact/Core/Script/Dependence/KeyMouseHook.cs b/BetterGenshinImpact/Core/Script/Dependence/KeyMouseHook.cs new file mode 100644 index 00000000..5f492f28 --- /dev/null +++ b/BetterGenshinImpact/Core/Script/Dependence/KeyMouseHook.cs @@ -0,0 +1,386 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using BetterGenshinImpact.Core.Monitor; +using Gma.System.MouseKeyHook; +using Microsoft.ClearScript; +using Microsoft.Extensions.Logging; + +namespace BetterGenshinImpact.Core.Script.Dependence; + +public class KeyMouseHook: IDisposable +{ + private IKeyboardMouseEvents? _appEvents; + private IKeyboardMouseEvents AppHook => _appEvents ??= MouseKeyMonitor.GlobalHook; + + private readonly List _keyDownDataCallbacks = new(); + private readonly List _keyUpDataCallbacks = new(); + private readonly List _keyDownCodeCallbacks = new(); + private readonly List _keyUpCodeCallbacks = new(); + private readonly List _mouseDownCallbacks = new(); + private readonly List _mouseUpCallbacks = new(); + private readonly List _mouseMoveCallbacks = new(); + private readonly List _mouseWheelCallbacks = new(); + + /// + /// 存储每个鼠标移动回调的间隔时间(毫秒) + /// + private readonly Dictionary _mouseMoveCallbackIntervals = new(); + + /// + /// 存储每个鼠标移动回调的上次调用时间 + /// + private readonly Dictionary _lastMouseMoveCallbackTimes = new(); + + private KeyEventHandler? _keyDownHandler; + private KeyEventHandler? _keyUpHandler; + private EventHandler? _mouseDownExtHandler; + private EventHandler? _mouseUpExtHandler; + private EventHandler? _mouseMoveExtHandler; + private EventHandler? _mouseWheelExtHandler; + + private readonly ILogger _logger = App.GetLogger(); + + public KeyMouseHook() + { + // 初始化事件处理程序 + _keyDownHandler = (_, args) => + { + // 创建回调列表的副本,避免迭代期间修改集合导致异常 + var keyDownDataCallbacksCopy = new List(_keyDownDataCallbacks); + var keyDownCodeCallbacksCopy = new List(_keyDownCodeCallbacks); + + // 调用KeyData回调 + foreach (var callback in keyDownDataCallbacksCopy) + { + try + { + callback.InvokeAsFunction(args.KeyData.ToString()); + } + catch (InvalidOperationException ex) when (ex.Message.Contains("V8 object has been released")) + { + _logger.LogDebug("V8对象已释放,清除所有回调"); + RemoveAllListeners(); + return; + } + catch (Exception ex) + { + _logger.LogError(ex, "执行键盘按下事件回调时发生错误"); + // 忽略单个回调执行异常,不影响其他回调 + } + } + + // 调用KeyCode回调 + foreach (var callback in keyDownCodeCallbacksCopy) + { + try + { + callback.InvokeAsFunction(args.KeyCode.ToString()); + } + catch (InvalidOperationException ex) when (ex.Message.Contains("V8 object has been released")) + { + _logger.LogDebug("V8对象已释放,清除所有回调"); + RemoveAllListeners(); + return; + } + catch (Exception ex) + { + _logger.LogError(ex, "执行键盘按下事件回调时发生错误"); + // 忽略单个回调执行异常,不影响其他回调 + } + } + }; + + _keyUpHandler = (_, args) => + { + // 创建回调列表的副本,避免迭代期间修改集合导致异常 + var keyUpDataCallbacksCopy = new List(_keyUpDataCallbacks); + var keyUpCodeCallbacksCopy = new List(_keyUpCodeCallbacks); + + // 调用KeyData回调 + foreach (var callback in keyUpDataCallbacksCopy) + { + try + { + callback.InvokeAsFunction(args.KeyData.ToString()); + } + catch (InvalidOperationException ex) when (ex.Message.Contains("V8 object has been released")) + { + _logger.LogDebug("V8对象已释放,清除所有回调"); + RemoveAllListeners(); + return; + } + catch (Exception ex) + { + _logger.LogError(ex, "执行键盘释放事件回调时发生错误"); + // 忽略单个回调执行异常,不影响其他回调 + } + } + + // 调用KeyCode回调 + foreach (var callback in keyUpCodeCallbacksCopy) + { + try + { + callback.InvokeAsFunction(args.KeyCode.ToString()); + } + catch (InvalidOperationException ex) when (ex.Message.Contains("V8 object has been released")) + { + _logger.LogDebug("V8对象已释放,清除所有回调"); + RemoveAllListeners(); + return; + } + catch (Exception ex) + { + _logger.LogError(ex, "执行键盘释放事件回调时发生错误"); + // 忽略单个回调执行异常,不影响其他回调 + } + } + }; + + _mouseDownExtHandler = (_, args) => + { + // 创建回调列表的副本,避免迭代期间修改集合导致异常 + var mouseDownCallbacksCopy = new List(_mouseDownCallbacks); + + foreach (var callback in mouseDownCallbacksCopy) + { + try + { + callback.InvokeAsFunction(args.Button.ToString(), args.X, args.Y); + } + catch (InvalidOperationException ex) when (ex.Message.Contains("V8 object has been released")) + { + _logger.LogDebug("V8对象已释放,清除所有回调"); + RemoveAllListeners(); + return; + } + catch (Exception ex) + { + _logger.LogError(ex, "执行鼠标按下事件回调时发生错误"); + // 忽略单个回调执行异常,不影响其他回调 + } + } + }; + + _mouseUpExtHandler = (_, args) => + { + // 创建回调列表的副本,避免迭代期间修改集合导致异常 + var mouseUpCallbacksCopy = new List(_mouseUpCallbacks); + + foreach (var callback in mouseUpCallbacksCopy) + { + try + { + callback.InvokeAsFunction(args.Button.ToString(), args.X, args.Y); + } + catch (InvalidOperationException ex) when (ex.Message.Contains("V8 object has been released")) + { + _logger.LogDebug("V8对象已释放,清除所有回调"); + RemoveAllListeners(); + return; + } + catch (Exception ex) + { + _logger.LogError(ex, "执行鼠标释放事件回调时发生错误"); + // 忽略单个回调执行异常,不影响其他回调 + } + } + }; + + _mouseMoveExtHandler = (_, args) => + { + var now = DateTime.Now; + // 创建回调列表的副本,避免迭代期间修改集合导致异常 + var mouseMoveCallbacksCopy = new List(_mouseMoveCallbacks); + + foreach (var callback in mouseMoveCallbacksCopy) + { + try + { + // 获取回调的间隔时间 + if (_mouseMoveCallbackIntervals.TryGetValue(callback, out var interval)) + { + // 获取上次调用时间 + if (_lastMouseMoveCallbackTimes.TryGetValue(callback, out var lastTime)) + { + // 计算时间差 + var timeSpan = now - lastTime; + // 如果时间差大于等于间隔时间,则执行回调 + if (timeSpan.TotalMilliseconds >= interval) + { + callback.InvokeAsFunction(args.X, args.Y); + // 更新上次调用时间 + _lastMouseMoveCallbackTimes[callback] = now; + } + } + } + } + catch (InvalidOperationException ex) when (ex.Message.Contains("V8 object has been released")) + { + _logger.LogDebug("V8对象已释放,清除所有回调"); + RemoveAllListeners(); + return; + } + catch (Exception ex) + { + _logger.LogError(ex, "执行鼠标移动事件回调时发生错误"); + // 忽略单个回调执行异常,不影响其他回调 + } + } + }; + + _mouseWheelExtHandler = (_, args) => + { + // 创建回调列表的副本,避免迭代期间修改集合导致异常 + var mouseWheelCallbacksCopy = new List(_mouseWheelCallbacks); + + foreach (var callback in mouseWheelCallbacksCopy) + { + try + { + callback.InvokeAsFunction(args.Delta, args.X, args.Y); + } + catch (InvalidOperationException ex) when (ex.Message.Contains("V8 object has been released")) + { + _logger.LogDebug("V8对象已释放,清除所有回调"); + RemoveAllListeners(); + return; + } + catch (Exception ex) + { + _logger.LogError(ex, "执行鼠标滚轮事件回调时发生错误"); + // 忽略单个回调执行异常,不影响其他回调 + } + } + }; + + // 添加事件监听器 + AppHook.KeyDown += _keyDownHandler; + AppHook.KeyUp += _keyUpHandler; + AppHook.MouseDownExt += _mouseDownExtHandler; + AppHook.MouseUpExt += _mouseUpExtHandler; + AppHook.MouseMoveExt += _mouseMoveExtHandler; + AppHook.MouseWheelExt += _mouseWheelExtHandler; + } + + /// + /// 注册键盘按下事件回调 + /// + /// 回调函数 + /// 是否仅返回KeyCode,默认为true(仅返回KeyCode) + public void OnKeyDown(ScriptObject callback, bool useCodeOnly = true) + { + if (useCodeOnly) + _keyDownCodeCallbacks.Add(callback); + else + _keyDownDataCallbacks.Add(callback); + } + + /// + /// 注册键盘释放事件回调 + /// + /// 回调函数 + /// 是否仅返回KeyCode,默认为true(仅返回KeyCode) + public void OnKeyUp(ScriptObject callback, bool useCodeOnly = true) + { + if (useCodeOnly) + _keyUpCodeCallbacks.Add(callback); + else + _keyUpDataCallbacks.Add(callback); + } + + public void OnMouseDown(ScriptObject callback) + { + _mouseDownCallbacks.Add(callback); + } + + public void OnMouseUp(ScriptObject callback) + { + _mouseUpCallbacks.Add(callback); + } + + /// + /// 注册鼠标移动事件回调 + /// + /// 回调函数 + /// 回调间隔时间(毫秒),默认200ms + public void OnMouseMove(ScriptObject callback, int interval = 200) + { + _mouseMoveCallbacks.Add(callback); + _mouseMoveCallbackIntervals[callback] = interval; + _lastMouseMoveCallbackTimes[callback] = DateTime.MinValue; + } + + public void OnMouseWheel(ScriptObject callback) + { + _mouseWheelCallbacks.Add(callback); + } + + public void RemoveAllListeners() + { + _keyDownDataCallbacks.Clear(); + _keyUpDataCallbacks.Clear(); + _keyDownCodeCallbacks.Clear(); + _keyUpCodeCallbacks.Clear(); + _mouseDownCallbacks.Clear(); + _mouseUpCallbacks.Clear(); + _mouseMoveCallbacks.Clear(); + _mouseWheelCallbacks.Clear(); + + _mouseMoveCallbackIntervals.Clear(); + _lastMouseMoveCallbackTimes.Clear(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // 移除所有事件监听器 + if (_keyDownHandler != null) + { + AppHook.KeyDown -= _keyDownHandler; + _keyDownHandler = null; + } + + if (_keyUpHandler != null) + { + AppHook.KeyUp -= _keyUpHandler; + _keyUpHandler = null; + } + + if (_mouseDownExtHandler != null) + { + AppHook.MouseDownExt -= _mouseDownExtHandler; + _mouseDownExtHandler = null; + } + + if (_mouseUpExtHandler != null) + { + AppHook.MouseUpExt -= _mouseUpExtHandler; + _mouseUpExtHandler = null; + } + + if (_mouseMoveExtHandler != null) + { + AppHook.MouseMoveExt -= _mouseMoveExtHandler; + _mouseMoveExtHandler = null; + } + + if (_mouseWheelExtHandler != null) + { + AppHook.MouseWheelExt -= _mouseWheelExtHandler; + _mouseWheelExtHandler = null; + } + + // 清空回调列表 + RemoveAllListeners(); + } + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/Core/Script/EngineExtend.cs b/BetterGenshinImpact/Core/Script/EngineExtend.cs index 841686b8..998744a4 100644 --- a/BetterGenshinImpact/Core/Script/EngineExtend.cs +++ b/BetterGenshinImpact/Core/Script/EngineExtend.cs @@ -35,7 +35,8 @@ public class EngineExtend engine.AddHostObject("file", new LimitedFile(workDir)); // 限制文件访问 engine.AddHostObject("http", new Http()); // 限制文件访问 engine.AddHostObject("notification", new Notification()); - + engine.AddHostObject("keyMouseHook", new KeyMouseHook()); + // 任务调度器 engine.AddHostObject("dispatcher", new Dispatcher(config)); engine.AddHostType("RealtimeTimer", typeof(RealtimeTimer)); @@ -72,7 +73,6 @@ public class EngineExtend engine.AddHostType("AutoFightParam", typeof(AutoFightParam)); - // 添加C#的类型 engine.AddHostType(typeof(Task)); From cced20e8e48ad1c656b5538d1896201b48a5b02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Tue, 23 Dec 2025 00:28:03 +0800 Subject: [PATCH 72/73] Update BetterGI.Assets.Map package version to 1.0.15 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index 2290e0ba..e9eddb39 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -43,7 +43,7 @@ - + From 8cc8d97780599f7083ff9656cce9ed226773e131 Mon Sep 17 00:00:00 2001 From: huiyadanli <15783049+huiyadanli@users.noreply.github.com> Date: Mon, 22 Dec 2025 16:29:58 +0000 Subject: [PATCH 73/73] Update version to 0.54.1-alpha.3 --- BetterGenshinImpact/BetterGenshinImpact.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index e9eddb39..28957116 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -2,7 +2,7 @@ BetterGI - 0.54.1-alpha.2 + 0.54.1-alpha.3 false WinExe net8.0-windows10.0.22621.0