From d8ba04f97bdbe2cabd53b5b0554cbab98ca4c6df Mon Sep 17 00:00:00 2001 From: xoipz <85264015+xoipz@users.noreply.github.com> Date: Sun, 10 Aug 2025 13:48:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E6=97=B6=E8=A7=A6=E5=8F=91=20-=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=90=83=E8=8D=AF=EF=BC=88=E7=A7=98=E5=A2=83?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E8=87=AA=E5=8A=A8=E5=90=83=E8=8D=AF=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E6=94=B9=E8=BF=9B=E4=BD=9C=E4=B8=BA=E5=AE=9E=E6=97=B6?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=8A=9F=E8=83=BD=20(#1993)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 辉鸭蛋 --- .gitignore | 4 +- .../BetterGenshinImpact.csproj | 2 + BetterGenshinImpact/Core/Config/AllConfig.cs | 7 + .../Core/Config/PathingConditionConfig.cs | 4 + .../Core/Config/PathingPartyConfig.cs | 7 +- .../GameTask/AutoDomain/AutoDomainTask.cs | 6 +- .../AutoEat/Assets/1920x1080/Recovery.png | Bin 0 -> 1173 bytes .../AutoEat/Assets/1920x1080/Resurrection.png | Bin 0 -> 934 bytes .../GameTask/AutoEat/Assets/AutoEatAssets.cs | 37 +++++ .../GameTask/AutoEat/AutoEatConfig.cs | 36 +++++ .../GameTask/AutoEat/AutoEatParam.cs | 37 +++++ .../GameTask/AutoEat/AutoEatTask.cs | 131 +++++++++++++++++ .../GameTask/AutoEat/AutoEatTrigger.cs | 139 ++++++++++++++++++ .../GameTask/GameTaskManager.cs | 8 + BetterGenshinImpact/GameTask/TaskRunner.cs | 3 + .../Model/Enum/NotificationEvent.cs | 3 + .../View/Pages/TaskSettingsPage.xaml | 1 + .../View/Pages/TriggerSettingsPage.xaml | 62 ++++++++ .../View/Pages/View/PathingConfigView.xaml | 29 ++++ .../Pages/View/ScriptGroupConfigView.xaml | 24 +++ 20 files changed, 535 insertions(+), 5 deletions(-) create mode 100644 BetterGenshinImpact/GameTask/AutoEat/Assets/1920x1080/Recovery.png create mode 100644 BetterGenshinImpact/GameTask/AutoEat/Assets/1920x1080/Resurrection.png create mode 100644 BetterGenshinImpact/GameTask/AutoEat/Assets/AutoEatAssets.cs create mode 100644 BetterGenshinImpact/GameTask/AutoEat/AutoEatConfig.cs create mode 100644 BetterGenshinImpact/GameTask/AutoEat/AutoEatParam.cs create mode 100644 BetterGenshinImpact/GameTask/AutoEat/AutoEatTask.cs create mode 100644 BetterGenshinImpact/GameTask/AutoEat/AutoEatTrigger.cs diff --git a/.gitignore b/.gitignore index 5de9c4d3..db7561af 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,6 @@ node_modules/ # Rider .idea -.trae \ No newline at end of file +.trae +.claude +CLAUDE.md \ No newline at end of file diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index c8c2f519..808b0cc0 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -163,6 +163,8 @@ Always + + Always Always diff --git a/BetterGenshinImpact/Core/Config/AllConfig.cs b/BetterGenshinImpact/Core/Config/AllConfig.cs index d1624e3b..742043f2 100644 --- a/BetterGenshinImpact/Core/Config/AllConfig.cs +++ b/BetterGenshinImpact/Core/Config/AllConfig.cs @@ -21,6 +21,7 @@ using BetterGenshinImpact.GameTask.AutoTrackPath; using BetterGenshinImpact.GameTask.AutoArtifactSalvage; using BetterGenshinImpact.GameTask.AutoStygianOnslaught; using BetterGenshinImpact.GameTask.GetGridIcons; +using BetterGenshinImpact.GameTask.AutoEat; namespace BetterGenshinImpact.Core.Config; @@ -165,6 +166,11 @@ public partial class AllConfig : ObservableObject /// public AutoArtifactSalvageConfig AutoArtifactSalvageConfig { get; set; } = new(); + /// + /// 自动吃药配置 + /// + public AutoEatConfig AutoEatConfig { get; set; } = new(); + /// /// 截取物品图标配置 /// @@ -247,6 +253,7 @@ public partial class AllConfig : ObservableObject AutoDomainConfig.PropertyChanged += OnAnyPropertyChanged; AutoStygianOnslaughtConfig.PropertyChanged += OnAnyPropertyChanged; AutoArtifactSalvageConfig.PropertyChanged += OnAnyPropertyChanged; + AutoEatConfig.PropertyChanged += OnAnyPropertyChanged; AutoMusicGameConfig.PropertyChanged += OnAnyPropertyChanged; TpConfig.PropertyChanged += OnAnyPropertyChanged; ScriptConfig.PropertyChanged += OnAnyPropertyChanged; diff --git a/BetterGenshinImpact/Core/Config/PathingConditionConfig.cs b/BetterGenshinImpact/Core/Config/PathingConditionConfig.cs index cee56ae1..47a5d6ea 100644 --- a/BetterGenshinImpact/Core/Config/PathingConditionConfig.cs +++ b/BetterGenshinImpact/Core/Config/PathingConditionConfig.cs @@ -29,6 +29,10 @@ public partial class PathingConditionConfig : ObservableObject // 使用小道具的间隔时间(ms) [ObservableProperty] private int _useGadgetIntervalMs = 0; + + // 启用自动吃药功能 + [ObservableProperty] + private bool _autoEatEnabled = true; public static PathingConditionConfig Default => new() { diff --git a/BetterGenshinImpact/Core/Config/PathingPartyConfig.cs b/BetterGenshinImpact/Core/Config/PathingPartyConfig.cs index 72f55a27..432ce486 100644 --- a/BetterGenshinImpact/Core/Config/PathingPartyConfig.cs +++ b/BetterGenshinImpact/Core/Config/PathingPartyConfig.cs @@ -92,6 +92,10 @@ public partial class PathingPartyConfig : ObservableObject [ObservableProperty] private bool _autoRunEnabled = true; + // 启用自动吃药功能 + [ObservableProperty] + private bool _autoEatEnabled = true; + //在连续执行时是否隐藏 [ObservableProperty] private bool _hideOnRepeat = false; @@ -120,7 +124,8 @@ public partial class PathingPartyConfig : ObservableObject return new PathingPartyConfig { OnlyInTeleportRecover = pathingConditionConfig.OnlyInTeleportRecover, - UseGadgetIntervalMs = pathingConditionConfig.UseGadgetIntervalMs + UseGadgetIntervalMs = pathingConditionConfig.UseGadgetIntervalMs, + AutoEatEnabled = pathingConditionConfig.AutoEatEnabled }; } } diff --git a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs index 0fc98ffb..9d0deeac 100644 --- a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs +++ b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs @@ -667,11 +667,11 @@ public class AutoDomainTask : ISoloTask // 对局结束检测 var domainEndTask = DomainEndDetectionTask(cts); // 自动吃药 - var autoEatRecoveryHpTask = AutoEatRecoveryHpTask(cts.Token); + // var autoEatRecoveryHpTask = AutoEatRecoveryHpTask(cts.Token); combatTask.Start(); domainEndTask.Start(); - autoEatRecoveryHpTask.Start(); - return Task.WhenAll(combatTask, domainEndTask, autoEatRecoveryHpTask); + // autoEatRecoveryHpTask.Start(); + return Task.WhenAll(combatTask, domainEndTask); } private void EndFightWait() diff --git a/BetterGenshinImpact/GameTask/AutoEat/Assets/1920x1080/Recovery.png b/BetterGenshinImpact/GameTask/AutoEat/Assets/1920x1080/Recovery.png new file mode 100644 index 0000000000000000000000000000000000000000..a1b0c82c0b6f2adf88694fe08487b898eeb61ab8 GIT binary patch literal 1173 zcmV;G1Zw+Px(Pf0{UR5(wSlx=91RT#&A=YD&hwa0C4*0j`>@8%1pQdkCs1xl7$21d28APou% zzedofAXJnfghWBe3c?)L5Q(gXluJn68fxU*z?{sv&AmL&eV=o#IOmzueTll@+?;dn z`~F{V|No^P-SVY`NkYC*AXlg)SD8nK+Q_NDFr|KMrZHAAWG7Qnvr%Cc7>h-LfPaV} zBB0!bLM_?6TY@MisdRt^Dhg1SKg!w_{nU*Q++P?Y96Mq7@#In@nTfR)u^`qzu*Ud( zpcE*Ddg!e^qEG};L==a_;Wg$@KgEXUD?Fe#f%dbSrk@s&#t*u$u@WF4#%PPxg`>Pa(_d) za4yj>5bA0}8m79Mx|?$Py?vUC7gJn@{%af3*AFM!?}Liv1i3s>F7d2TP3PW}>gwA) z`L8=gM5Zk}cXrcta|IQZRpbj*#JL>m@TEb-nd^oZgf$sz^#`xYr=J<(>pa^xRg<-~U3y+(e1?jW&9ih11Wl;RUbaQPB2|lmpH6l(JgHYOqBN zj&^wvg{aUe6jXp(`O!C0(gx*xIJ)RQrceBp#ut+jMLAVLN4w_xBa=vi3Dj0YR?IPw zLLt&rBq5i2hPhreq{OIo+YU;a37HnOS42P4>VKhe{aDa5r$a9MF`4yGt!BZjdGz%5 z(S4(z`nnqKuC1n}^(3DiI>v>85cTpWO)@ZSNR42%Ww_MKOdn}(Or&SpLTdC%o_lf? zVGxo;t4VqX48_zfi+foe9_FQWF%47lUO_I4mX?fpwa>EV ziB-OKNgR&?8Y`q}%Ex;S&~jO$#81~j_WgW{{YN_q5C#T1QPN8wH~oBc#Semem|8QA zcb<8g#j|EZ?sk;gSXzE-WA}H*xoWFWM>|^O(?jPOEDG8P!^I4jm>=YBbBh2$h_XXG zP&LfvRV!FDZ#GFBQA#sf+y7*D^Kq`~0-6NXxb-XPA2Jk2nw9C1iE$_GN2ubiLNe-; z5^I*t<&lMRXgSeF^T|u}NC6YL<|@?M4?h>Jh188M&j5GrWH>sY$`SiH>?WD=3aw<2 n3RPq%tfUxMp@IPM(hc|rOEoF)4aKL;00000NkvXXu0mjfn<6nh literal 0 HcmV?d00001 diff --git a/BetterGenshinImpact/GameTask/AutoEat/Assets/1920x1080/Resurrection.png b/BetterGenshinImpact/GameTask/AutoEat/Assets/1920x1080/Resurrection.png new file mode 100644 index 0000000000000000000000000000000000000000..d50b9546d9c2224ace7fd2fdf044098bbd6812b2 GIT binary patch literal 934 zcmV;X16lluP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGqB>(^xB>_oNB=7(L13O7XK~y+TZIkOy zn`Icr-+#!2F$ZqhoY|ZbBXKgPewkZ@v8XshLrTXe?c74e9)PxM3ln4&?K&03I5}i( z>9ETJqldAWp};mKQVs>$!rPV}ex~pAOMLzQ#!xB1$$ybB%=4tGniwJ9*QQTe&?KeI^)B76r z<`NpLyHIt$fbFXWzW&~T((n>0>n;?Q5}IrW&<&iT_ojyM?*W8Dp}lbU(BnEsBC$>p<9B{UsXIuoyOHI!1+uvviBDxjgb}|R|Ls9G<1x0j<9zATa;g0U z5B`{xOhs&q3G7ZKhORTr%mpbF@hO%a$mO!n=A~;-hP`MF@9~Sr$;@n! zABL_VG@1AEskIWV@ok1YeWWwuvsoF%sS_a&n)WwnwY`PLdJsWvE0wn1-QP%TV@WoP zxfMd|pEDM%Wi=i8Pto;33(cMTX|b0gsO_a(xO|B5I|H&Iliwh|GfOb0lM0r^fW+kr z8A*?=N71$)qs6uxL1`;RXFtk=*(teTdh;@o4HJQtdd8M(3C3C_E|$43>FG=gM_(i7 z%;gAYEhV%$-emsqZ*oB~^nYhj^hm>QM~R?7OO~qNiC+hh;vW&oeaI zi?VGW=beWUx*|2Guf2@Yc!W`Zzx+(I`EC9Z1I#CXVmlj^!&CRXoHxFX!nPOFt#_Xm zSSL=RzIKF0a|Pf2Y~j!7oIJ6J;)h#`K4x&lPP6qW^|o>hzT-H;)d-GIHN}#ya1E^^ zRn+PC^GQnu9aj|G@H!dtx#;fK(xj`Tu5}+O*Q-)c%0z1T8*##1^#7Lt{r~^~07*qo IM6N<$g7;UwR{#J2 literal 0 HcmV?d00001 diff --git a/BetterGenshinImpact/GameTask/AutoEat/Assets/AutoEatAssets.cs b/BetterGenshinImpact/GameTask/AutoEat/Assets/AutoEatAssets.cs new file mode 100644 index 00000000..bc55e1d7 --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoEat/Assets/AutoEatAssets.cs @@ -0,0 +1,37 @@ +using BetterGenshinImpact.Core.Recognition; +using BetterGenshinImpact.Core.Recognition.OpenCv; +using BetterGenshinImpact.GameTask.Model; +using OpenCvSharp; + +namespace BetterGenshinImpact.GameTask.AutoEat.Assets; + +public class AutoEatAssets : BaseAssets +{ + public RecognitionObject RecoveryIconRa; + public RecognitionObject ResurrectionIconRa; + + private AutoEatAssets() + { + var s = TaskContext.Instance().SystemInfo.AssetScale; + + RecoveryIconRa = new RecognitionObject + { + Name = "RecoveryIcon", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage("AutoEat", "Recovery.png"), + Threshold = 0.8, + RegionOfInterest = new Rect((int)(1810 * s), (int)(778 * s), (int)(23 * s), (int)(23 * s)), + DrawOnWindow = false + }.InitTemplate(); + + ResurrectionIconRa = new RecognitionObject + { + Name = "ResurrectionIcon", + RecognitionType = RecognitionTypes.TemplateMatch, + TemplateImageMat = GameTaskManager.LoadAssetImage("AutoEat", "Resurrection.png"), + Threshold = 0.8, + RegionOfInterest = new Rect((int)(1810 * s), (int)(778 * s), (int)(18 * s), (int)(19 * s)), + DrawOnWindow = false + }.InitTemplate(); + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoEat/AutoEatConfig.cs b/BetterGenshinImpact/GameTask/AutoEat/AutoEatConfig.cs new file mode 100644 index 00000000..3f11bcb2 --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoEat/AutoEatConfig.cs @@ -0,0 +1,36 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using System; + +namespace BetterGenshinImpact.GameTask.AutoEat; + +/// +/// 自动吃药配置 +/// +[Serializable] +public partial class AutoEatConfig : ObservableObject +{ + /// + /// 是否启用自动吃药 + /// + [ObservableProperty] + private bool _enabled = true; + + /// + /// 是否显示吃药通知 + /// + [ObservableProperty] + private bool _showNotification = true; + + /// + /// 检测间隔时间(毫秒) + /// + [ObservableProperty] + private int _checkInterval = 500; + + /// + /// 吃药间隔时间(毫秒) + /// 防止频繁吃药 + /// + [ObservableProperty] + private int _eatInterval = 2000; +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoEat/AutoEatParam.cs b/BetterGenshinImpact/GameTask/AutoEat/AutoEatParam.cs new file mode 100644 index 00000000..1777886d --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoEat/AutoEatParam.cs @@ -0,0 +1,37 @@ +using BetterGenshinImpact.GameTask.Model; + +namespace BetterGenshinImpact.GameTask.AutoEat; + +/// +/// 自动吃药任务参数 +/// +public class AutoEatParam : BaseTaskParam +{ + /// + /// 是否显示通知 + /// + public bool ShowNotification { get; set; } + + /// + /// 检测间隔(毫秒) + /// + public int CheckInterval { get; set; } + + /// + /// 吃药间隔(毫秒) + /// + public int EatInterval { get; set; } + + public AutoEatParam() + { + SetDefault(); + } + + public void SetDefault() + { + var config = TaskContext.Instance().Config.AutoEatConfig; + ShowNotification = config.ShowNotification; + CheckInterval = config.CheckInterval; + EatInterval = config.EatInterval; + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoEat/AutoEatTask.cs b/BetterGenshinImpact/GameTask/AutoEat/AutoEatTask.cs new file mode 100644 index 00000000..90b151ba --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoEat/AutoEatTask.cs @@ -0,0 +1,131 @@ +using BetterGenshinImpact.Core.Recognition.OCR; +using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; +using BetterGenshinImpact.GameTask.Common.BgiVision; +using BetterGenshinImpact.GameTask.Common.Element.Assets; +using BetterGenshinImpact.GameTask.Model; +using BetterGenshinImpact.Service.Notification; +using BetterGenshinImpact.Service.Notification.Model.Enum; +using Microsoft.Extensions.Logging; +using System; +using System.Threading; +using System.Threading.Tasks; +using static BetterGenshinImpact.GameTask.Common.TaskControl; + +namespace BetterGenshinImpact.GameTask.AutoEat; + +/// +/// 自动吃药任务 +/// 检测红血自动使用便携营养袋 +/// +public class AutoEatTask : BaseIndependentTask, ISoloTask +{ + public string Name => "自动吃药"; + + private readonly AutoEatParam _taskParam; + private readonly AutoEatConfig _config; + private CancellationToken _ct; + + public AutoEatTask(AutoEatParam taskParam) + { + _taskParam = taskParam; + _config = TaskContext.Instance().Config.AutoEatConfig; + } + + public async Task Start(CancellationToken ct) + { + _ct = ct; + + Init(); + Logger.LogInformation("自动吃药任务启动"); + + if (!IsTakeFood()) + { + Logger.LogWarning("未装备 \"{Tool}\",无法启用自动吃药功能", "便携营养袋"); + return; + } + + try + { + await AutoEatLoop(); + } + catch (Exception e) + { + Logger.LogError(e, "自动吃药任务发生异常"); + throw; + } + finally + { + Logger.LogInformation("自动吃药任务结束"); + } + } + + private void Init() + { + Logger.LogInformation("→ {Text} 检测间隔: {Interval}ms", "自动吃药,", _config.CheckInterval); + Logger.LogInformation("→ {Text} 吃药间隔: {Interval}ms", "自动吃药,", _config.EatInterval); + } + + /// + /// 自动吃药主循环 + /// + private async Task AutoEatLoop() + { + var lastEatTime = DateTime.MinValue; + + while (!_ct.IsCancellationRequested) + { + try + { + // 检测当前角色是否红血 + if (Bv.CurrentAvatarIsLowHp(CaptureToRectArea())) + { + var now = DateTime.Now; + // 检查是否超过吃药间隔时间,避免重复吃药 + if ((now - lastEatTime).TotalMilliseconds >= _config.EatInterval) + { + // 模拟按键 "Z" 使用便携营养袋 + Simulation.SendInput.SimulateAction(GIActions.QuickUseGadget); + lastEatTime = now; + + Logger.LogInformation("检测到红血,自动吃药"); + } + } + + await Delay(_config.CheckInterval, _ct); + } + catch (OperationCanceledException) + { + // 任务被取消,正常退出 + break; + } + catch (Exception e) + { + Logger.LogDebug(e, "自动吃药检测时发生异常"); + await Delay(1000, _ct); // 异常时稍作等待 + } + } + } + + /// + /// 检测是否装备了便携营养袋 + /// + private bool IsTakeFood() + { + try + { + // 获取图像 + using var ra = CaptureToRectArea(); + // 识别道具图标下是否是数字 + var s = TaskContext.Instance().SystemInfo.AssetScale; + var countArea = ra.DeriveCrop(1800 * s, 845 * s, 40 * s, 20 * s); + var count = OcrFactory.Paddle.OcrWithoutDetector(countArea.CacheGreyMat); + return int.TryParse(count, out _); + } + catch (Exception e) + { + Logger.LogDebug(e, "检测便携营养袋时发生异常"); + return false; + } + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoEat/AutoEatTrigger.cs b/BetterGenshinImpact/GameTask/AutoEat/AutoEatTrigger.cs new file mode 100644 index 00000000..9d1ed670 --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoEat/AutoEatTrigger.cs @@ -0,0 +1,139 @@ +using BetterGenshinImpact.Core.Simulator; +using BetterGenshinImpact.Core.Simulator.Extensions; +using BetterGenshinImpact.GameTask.Common; +using BetterGenshinImpact.GameTask.Common.BgiVision; +using BetterGenshinImpact.GameTask.Model.Area; +using BetterGenshinImpact.GameTask.AutoEat.Assets; +using BetterGenshinImpact.Service.Notification; +using BetterGenshinImpact.Service.Notification.Model.Enum; +using Microsoft.Extensions.Logging; +using System; +using static BetterGenshinImpact.GameTask.Common.TaskControl; +using static Vanara.PInvoke.User32; + +namespace BetterGenshinImpact.GameTask.AutoEat; + +/// +/// 自动吃药触发器 +/// 检测红血状态时自动使用Recovery.png,检测到Resurrection.png时按z复活 +/// +public class AutoEatTrigger : ITaskTrigger +{ + private readonly ILogger _logger = App.GetLogger(); + + public string Name => "自动吃药"; + public bool IsEnabled { get; set; } + public int Priority => 25; // 中等优先级 + public bool IsExclusive => false; + + private readonly AutoEatConfig _config; + private DateTime _lastRecoveryCheckTime = DateTime.MinValue; + private DateTime _lastResurrectionTime = DateTime.MinValue; + private DateTime _lastEatTime = DateTime.MinValue; + private bool _recoveryDetected = false; + + public AutoEatTrigger() + { + _config = TaskContext.Instance().Config.AutoEatConfig; + } + + public void Init() + { + IsEnabled = _config.Enabled; + } + + public void OnCapture(CaptureContent content) + { + if (!IsEnabled) + return; + + try + { + using var ra = TaskControl.CaptureToRectArea(); + var now = DateTime.Now; + + // 优先检测复活图标,添加2秒CD + if (CheckResurrection(ra)) + { + // 检查复活CD(2秒) + if ((now - _lastResurrectionTime).TotalSeconds >= 2) + { + // 按z键复活 + Simulation.SendInput.Keyboard.KeyPress(VK.VK_Z); + _lastResurrectionTime = now; + _logger.LogInformation("检测到复活图标,自动复活"); + } + return; + } + + // 检测角色是否红血 + if (Bv.CurrentAvatarIsLowHp(ra)) + { + // 检查Recovery缓存是否过期(30秒) + if ((now - _lastRecoveryCheckTime).TotalSeconds >= 30) + { + _recoveryDetected = false; + _lastRecoveryCheckTime = now; + } + + // 如果Recovery还在缓存期内,或者重新检测到Recovery + if (_recoveryDetected || CheckRecovery(ra)) + { + if (!_recoveryDetected) + { + _recoveryDetected = true; + _lastRecoveryCheckTime = now; + } + + // 检查吃药间隔,防止频繁吃药 + if ((now - _lastEatTime).TotalMilliseconds >= _config.EatInterval) + { + // 使用便携营养袋 + Simulation.SendInput.SimulateAction(GIActions.QuickUseGadget); + _lastEatTime = now; + + _logger.LogInformation("检测到红血且Recovery可用,自动吃药"); + } + } + } + } + catch (Exception e) + { + _logger.LogDebug(e, "自动吃药检测时发生异常"); + } + } + + /// + /// 检测Recovery.png图标 + /// + private bool CheckRecovery(ImageRegion imageRegion) + { + try + { + var result = imageRegion.Find(AutoEatAssets.Instance.RecoveryIconRa); + return result.IsExist(); + } + catch (Exception e) + { + _logger.LogDebug(e, "检测Recovery图标时发生异常"); + return false; + } + } + + /// + /// 检测Resurrection.png图标 + /// + private bool CheckResurrection(ImageRegion imageRegion) + { + try + { + var result = imageRegion.Find(AutoEatAssets.Instance.ResurrectionIconRa); + return result.IsExist(); + } + catch (Exception e) + { + _logger.LogDebug(e, "检测Resurrection图标时发生异常"); + return false; + } + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/GameTaskManager.cs b/BetterGenshinImpact/GameTask/GameTaskManager.cs index ccf8b735..c7a583f3 100644 --- a/BetterGenshinImpact/GameTask/GameTaskManager.cs +++ b/BetterGenshinImpact/GameTask/GameTaskManager.cs @@ -7,6 +7,7 @@ using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Assets; using BetterGenshinImpact.GameTask.AutoPick.Assets; using BetterGenshinImpact.GameTask.AutoSkip.Assets; using BetterGenshinImpact.GameTask.AutoWood.Assets; +using BetterGenshinImpact.GameTask.AutoEat.Assets; using BetterGenshinImpact.GameTask.Common.Element.Assets; using BetterGenshinImpact.GameTask.GameLoading; using BetterGenshinImpact.GameTask.GameLoading.Assets; @@ -45,6 +46,7 @@ internal class GameTaskManager TriggerDictionary.TryAdd("AutoSkip", new AutoSkip.AutoSkipTrigger()); TriggerDictionary.TryAdd("AutoFish", new AutoFishing.AutoFishingTrigger()); TriggerDictionary.TryAdd("AutoCook", new AutoCook.AutoCookTrigger()); + TriggerDictionary.TryAdd("AutoEat", new AutoEat.AutoEatTrigger()); return ConvertToTriggerList(); } @@ -94,6 +96,10 @@ internal class GameTaskManager triggerName = "AutoSkip"; trigger = new AutoSkip.AutoSkipTrigger(); break; + case "AutoEat": + triggerName = "AutoEat"; + trigger = new AutoEat.AutoEatTrigger(); + break; } if (triggerName == null || trigger == null) @@ -114,6 +120,7 @@ internal class GameTaskManager TriggerDictionary.GetValueOrDefault("QuickTeleport")?.Init(); // TriggerDictionary.GetValueOrDefault("GameLoading")?.Init(); TriggerDictionary.GetValueOrDefault("AutoCook")?.Init(); + TriggerDictionary.GetValueOrDefault("AutoEat")?.Init(); // 清理画布 VisionContext.Instance().DrawContent.ClearAll(); } @@ -134,6 +141,7 @@ internal class GameTaskManager QuickSereniteaPotAssets.DestroyInstance(); GameLoadingAssets.DestroyInstance(); MapLazyAssets.DestroyInstance(); + AutoEatAssets.DestroyInstance(); } /// diff --git a/BetterGenshinImpact/GameTask/TaskRunner.cs b/BetterGenshinImpact/GameTask/TaskRunner.cs index b2c4c532..4dbc0489 100644 --- a/BetterGenshinImpact/GameTask/TaskRunner.cs +++ b/BetterGenshinImpact/GameTask/TaskRunner.cs @@ -133,6 +133,9 @@ public class TaskRunner // 清空实时任务触发器 TaskTriggerDispatcher.Instance().ClearTriggers(); + // 重新加载基础触发器(包括自动吃药等实时功能) + var basicTriggers = GameTaskManager.LoadInitialTriggers(); + TaskTriggerDispatcher.Instance().SetTriggers(basicTriggers); // 激活原神窗口 var maskWindow = MaskWindow.Instance(); diff --git a/BetterGenshinImpact/Service/Notification/Model/Enum/NotificationEvent.cs b/BetterGenshinImpact/Service/Notification/Model/Enum/NotificationEvent.cs index 79c3b3fc..ec1a82de 100644 --- a/BetterGenshinImpact/Service/Notification/Model/Enum/NotificationEvent.cs +++ b/BetterGenshinImpact/Service/Notification/Model/Enum/NotificationEvent.cs @@ -21,6 +21,9 @@ public class NotificationEvent(string code, string msg) public static readonly NotificationEvent DailyReward = new("daily.reward", "检查每日奖励领取状态"); public static readonly NotificationEvent JsCustom = new("js.custom", "JS自定义事件"); public static readonly NotificationEvent JsError = new("js.error", "JS运行时错误"); + public static readonly NotificationEvent AutoEatStart = new("autoeat.start", "自动吃药启动"); + public static readonly NotificationEvent AutoEatEnd = new("autoeat.end", "自动吃药结束"); + public static readonly NotificationEvent AutoEatInfo = new("autoeat.info", "自动吃药信息"); public string Code { get; private set; } = code; public string Msg { get; private set; } = msg; diff --git a/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml b/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml index a0fdf3b0..9ef5895b 100644 --- a/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml +++ b/BetterGenshinImpact/View/Pages/TaskSettingsPage.xaml @@ -1001,6 +1001,7 @@ + diff --git a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml index d422a037..a6565ea9 100644 --- a/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml +++ b/BetterGenshinImpact/View/Pages/TriggerSettingsPage.xaml @@ -643,6 +643,68 @@ + + + + + + + + + + + + + + + + + + 检测角色红血状态,自动使用便携营养袋回复生命值 + + + + + + + + + + + + + + + + + + + + + diff --git a/BetterGenshinImpact/View/Pages/View/PathingConfigView.xaml b/BetterGenshinImpact/View/Pages/View/PathingConfigView.xaml index 06c76a95..754c9c8a 100644 --- a/BetterGenshinImpact/View/Pages/View/PathingConfigView.xaml +++ b/BetterGenshinImpact/View/Pages/View/PathingConfigView.xaml @@ -231,6 +231,35 @@ TextWrapping="NoWrap" /> + + + + + + + + + + + + + + + + + + + diff --git a/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml b/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml index be3c980e..9c2bbb18 100644 --- a/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml +++ b/BetterGenshinImpact/View/Pages/View/ScriptGroupConfigView.xaml @@ -75,6 +75,30 @@ Grid.Column="1" IsChecked="{Binding PathingConfig.AutoPickEnabled}" /> + + + + + + + + + + + + +