mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-03-15 07:43:20 +08:00
auto skip: backgroud click
This commit is contained in:
@@ -65,6 +65,16 @@ public class PostMessageSimulator
|
||||
return this;
|
||||
}
|
||||
|
||||
public PostMessageSimulator LeftButtonClickBackground()
|
||||
{
|
||||
User32.PostMessage(_hWnd, User32.WindowMessage.WM_ACTIVATE, 1, 0);
|
||||
IntPtr p = (16 << 16) | 16;
|
||||
User32.PostMessage(_hWnd, WM_LBUTTONDOWN, IntPtr.Zero, p);
|
||||
Thread.Sleep(100);
|
||||
User32.PostMessage(_hWnd, WM_LBUTTONUP, IntPtr.Zero, p);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认位置左键按下
|
||||
/// </summary>
|
||||
|
||||
@@ -1,78 +1,82 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
|
||||
namespace BetterGenshinImpact.GameTask.AutoSkip
|
||||
namespace BetterGenshinImpact.GameTask.AutoSkip;
|
||||
|
||||
/// <summary>
|
||||
/// 自动跳过剧情配置
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public partial class AutoSkipConfig : ObservableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 自动跳过剧情配置
|
||||
/// 触发器是否启用
|
||||
/// 启用后:
|
||||
/// 1. 快速跳过对话
|
||||
/// 2. 自动点击一个识别到的选项
|
||||
/// 3. 黑屏过长自动点击跳过
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public partial class AutoSkipConfig : ObservableObject
|
||||
[ObservableProperty] private bool _enabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// 快速跳过对话
|
||||
/// </summary>
|
||||
[ObservableProperty] private bool _quicklySkipConversationsEnabled = true;
|
||||
|
||||
public int ChatOptionTextWidth { get; set; } = 280;
|
||||
|
||||
public int ExpeditionOptionTextWidth { get; set; } = 130;
|
||||
|
||||
/// <summary>
|
||||
/// 选择选项前的延迟(毫秒)
|
||||
/// </summary>
|
||||
[ObservableProperty] private int _afterChooseOptionSleepDelay = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 自动领取每日委托奖励
|
||||
/// </summary>
|
||||
[ObservableProperty] private bool _autoGetDailyRewardsEnabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// 自动重新派遣
|
||||
/// </summary>
|
||||
[ObservableProperty] private bool _autoReExploreEnabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// 自动重新派遣使用角色配置,逗号分割
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
[ObservableProperty] private string _autoReExploreCharacter = "";
|
||||
|
||||
/// <summary>
|
||||
/// 优先选择第一个选项
|
||||
/// 优先选择最后一个选项
|
||||
/// 不选择选项
|
||||
/// </summary>
|
||||
[ObservableProperty] private string _clickChatOption = "优先选择最后一个选项";
|
||||
|
||||
/// <summary>
|
||||
/// 自动邀约启用
|
||||
/// </summary>
|
||||
[ObservableProperty] private bool _autoHangoutEventEnabled = false;
|
||||
|
||||
/// <summary>
|
||||
/// 自动邀约启用
|
||||
/// </summary>
|
||||
[ObservableProperty] private string _autoHangoutEndChoose = string.Empty;
|
||||
|
||||
public bool IsClickFirstChatOption()
|
||||
{
|
||||
/// <summary>
|
||||
/// 触发器是否启用
|
||||
/// 启用后:
|
||||
/// 1. 快速跳过对话
|
||||
/// 2. 自动点击一个识别到的选项
|
||||
/// 3. 黑屏过长自动点击跳过
|
||||
/// </summary>
|
||||
[ObservableProperty] private bool _enabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// 快速跳过对话
|
||||
/// </summary>
|
||||
[ObservableProperty] private bool _quicklySkipConversationsEnabled = true;
|
||||
|
||||
public int ChatOptionTextWidth { get; set; } = 280;
|
||||
|
||||
public int ExpeditionOptionTextWidth { get; set; } = 130;
|
||||
|
||||
/// <summary>
|
||||
/// 选择选项前的延迟(毫秒)
|
||||
/// </summary>
|
||||
[ObservableProperty] private int _afterChooseOptionSleepDelay = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 自动领取每日委托奖励
|
||||
/// </summary>
|
||||
[ObservableProperty] private bool _autoGetDailyRewardsEnabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// 自动重新派遣
|
||||
/// </summary>
|
||||
[ObservableProperty] private bool _autoReExploreEnabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// 自动重新派遣使用角色配置,逗号分割
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
[ObservableProperty] private string _autoReExploreCharacter = "";
|
||||
|
||||
/// <summary>
|
||||
/// 优先选择第一个选项
|
||||
/// 优先选择最后一个选项
|
||||
/// 不选择选项
|
||||
/// </summary>
|
||||
[ObservableProperty] private string _clickChatOption = "优先选择最后一个选项";
|
||||
|
||||
/// <summary>
|
||||
/// 自动邀约启用
|
||||
/// </summary>
|
||||
[ObservableProperty] private bool _autoHangoutEventEnabled = false;
|
||||
|
||||
/// <summary>
|
||||
/// 自动邀约启用
|
||||
/// </summary>
|
||||
[ObservableProperty] private string _autoHangoutEndChoose = string.Empty;
|
||||
|
||||
public bool IsClickFirstChatOption()
|
||||
{
|
||||
return ClickChatOption == "优先选择第一个选项";
|
||||
}
|
||||
|
||||
public bool IsClickNoneChatOption()
|
||||
{
|
||||
return ClickChatOption == "不选择选项";
|
||||
}
|
||||
return ClickChatOption == "优先选择第一个选项";
|
||||
}
|
||||
|
||||
public bool IsClickNoneChatOption()
|
||||
{
|
||||
return ClickChatOption == "不选择选项";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 后台运行
|
||||
/// </summary>
|
||||
[ObservableProperty] private bool _runBackgroundEnabled = false;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BetterGenshinImpact.Core.Config;
|
||||
using BetterGenshinImpact.Core.Recognition;
|
||||
using BetterGenshinImpact.Core.Recognition.OCR;
|
||||
using BetterGenshinImpact.Core.Recognition.OpenCv;
|
||||
using BetterGenshinImpact.Core.Simulator;
|
||||
@@ -6,12 +7,12 @@ using BetterGenshinImpact.GameTask.AutoSkip.Assets;
|
||||
using BetterGenshinImpact.GameTask.AutoSkip.Model;
|
||||
using BetterGenshinImpact.GameTask.Common;
|
||||
using BetterGenshinImpact.GameTask.Common.Element.Assets;
|
||||
using BetterGenshinImpact.GameTask.Model.Area;
|
||||
using BetterGenshinImpact.Helpers;
|
||||
using BetterGenshinImpact.Service;
|
||||
using BetterGenshinImpact.View.Drawable;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OpenCvSharp;
|
||||
using Sdcb.PaddleOCR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@@ -20,8 +21,6 @@ using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using BetterGenshinImpact.Core.Recognition;
|
||||
using BetterGenshinImpact.GameTask.Model.Area;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace BetterGenshinImpact.GameTask.AutoSkip;
|
||||
@@ -38,6 +37,8 @@ public class AutoSkipTrigger : ITaskTrigger
|
||||
public int Priority => 20;
|
||||
public bool IsExclusive => false;
|
||||
|
||||
public bool IsBackgroundRunning { get; set; }
|
||||
|
||||
private readonly AutoSkipAssets _autoSkipAssets;
|
||||
|
||||
private readonly AutoSkipConfig _config;
|
||||
@@ -57,6 +58,8 @@ public class AutoSkipTrigger : ITaskTrigger
|
||||
/// </summary>
|
||||
private List<string> _selectList = new();
|
||||
|
||||
private PostMessageSimulator? _postMessageSimulator;
|
||||
|
||||
public AutoSkipTrigger()
|
||||
{
|
||||
_autoSkipAssets = AutoSkipAssets.Instance;
|
||||
@@ -65,7 +68,9 @@ public class AutoSkipTrigger : ITaskTrigger
|
||||
|
||||
public void Init()
|
||||
{
|
||||
IsEnabled = TaskContext.Instance().Config.AutoSkipConfig.Enabled;
|
||||
IsEnabled = _config.Enabled;
|
||||
IsBackgroundRunning = _config.RunBackgroundEnabled;
|
||||
_postMessageSimulator = TaskContext.Instance().PostMessageSimulator;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -182,7 +187,14 @@ public class AutoSkipTrigger : ITaskTrigger
|
||||
_prevPlayingTime = DateTime.Now;
|
||||
if (TaskContext.Instance().Config.AutoSkipConfig.QuicklySkipConversationsEnabled)
|
||||
{
|
||||
Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE);
|
||||
if (IsBackgroundRunning)
|
||||
{
|
||||
_postMessageSimulator?.KeyPressBackground(User32.VK.VK_SPACE);
|
||||
}
|
||||
else
|
||||
{
|
||||
Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
// 对话选项选择
|
||||
@@ -392,7 +404,7 @@ public class AutoSkipTrigger : ITaskTrigger
|
||||
using var exclamationIconRa = region.Find(_autoSkipAssets.ExclamationIconRo);
|
||||
if (!exclamationIconRa.IsEmpty())
|
||||
{
|
||||
TaskControl.Sleep(_config.AfterChooseOptionSleepDelay);
|
||||
Thread.Sleep(_config.AfterChooseOptionSleepDelay);
|
||||
exclamationIconRa.Click();
|
||||
AutoSkipLog("点击感叹号选项");
|
||||
return true;
|
||||
@@ -515,7 +527,7 @@ public class AutoSkipTrigger : ITaskTrigger
|
||||
}
|
||||
|
||||
// 没OCR到文字,直接选择气泡选项
|
||||
TaskControl.Sleep(_config.AfterChooseOptionSleepDelay);
|
||||
Thread.Sleep(_config.AfterChooseOptionSleepDelay);
|
||||
clickRect.Click();
|
||||
var msg = _config.IsClickFirstChatOption() ? "第一个" : "最后一个";
|
||||
AutoSkipLog($"点击{msg}气泡选项");
|
||||
@@ -531,9 +543,20 @@ public class AutoSkipTrigger : ITaskTrigger
|
||||
{
|
||||
if (string.IsNullOrEmpty(optionType))
|
||||
{
|
||||
TaskControl.Sleep(_config.AfterChooseOptionSleepDelay);
|
||||
Thread.Sleep(_config.AfterChooseOptionSleepDelay);
|
||||
}
|
||||
if (IsBackgroundRunning && !SystemControl.IsGenshinImpactActive())
|
||||
{
|
||||
User32.GetCursorPos(out var p);
|
||||
region.Move(); // 必须移动实际鼠标
|
||||
_postMessageSimulator?.LeftButtonClickBackground();
|
||||
Thread.Sleep(10);
|
||||
DesktopRegion.DesktopRegionMove(p.X, p.Y); // 鼠标移动回原来位置
|
||||
}
|
||||
else
|
||||
{
|
||||
region.Click();
|
||||
}
|
||||
region.Click();
|
||||
AutoSkipLog(region.Text);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/// * 也可以是任务的本身
|
||||
///
|
||||
/// 需要短时间内持续循环获取游戏图像的,使用触发器;
|
||||
/// 需要休眠等待且有一定流程的,应该使用<see cref="BaseTaskThread"/>
|
||||
/// 需要休眠等待且有一定流程的,应自行实现Task
|
||||
/// </summary>
|
||||
public interface ITaskTrigger
|
||||
{
|
||||
@@ -14,6 +14,7 @@ public interface ITaskTrigger
|
||||
/// 触发器名称
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否处于启用状态
|
||||
/// </summary>
|
||||
@@ -29,6 +30,11 @@ public interface ITaskTrigger
|
||||
/// </summary>
|
||||
bool IsExclusive { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 处于可以后台运行的状态(原神窗口不处于激活状态)
|
||||
/// </summary>
|
||||
bool IsBackgroundRunning => false;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
@@ -39,4 +45,4 @@ public interface ITaskTrigger
|
||||
/// </summary>
|
||||
/// <param name="content">捕获的图片等内容</param>
|
||||
void OnCapture(CaptureContent content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,12 @@ public class DesktopRegion() : Region(0, 0, PrimaryScreen.WorkingArea.Width, Pri
|
||||
(y + (h * 1d / 2)) * 65535 / Height).LeftButtonClick().Sleep(50).LeftButtonUp();
|
||||
}
|
||||
|
||||
public void DesktopRegionMove(int x, int y, int w, int h)
|
||||
{
|
||||
Simulation.SendInput.Mouse.MoveMouseTo((x + (w * 1d / 2)) * 65535 / Width,
|
||||
(y + (h * 1d / 2)) * 65535 / Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 静态方法,每次都会重新计算屏幕大小
|
||||
/// </summary>
|
||||
|
||||
@@ -111,6 +111,41 @@ public class Region : IDisposable
|
||||
res.TargetRegion.DesktopRegionClick(res.X, res.Y, res.Width, res.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移动到【自己】的中心
|
||||
/// region.Derive(x,y).Move() 等效于 region.MoveTo(x,y)
|
||||
/// </summary>
|
||||
public void Move()
|
||||
{
|
||||
// 相对自己是 0, 0 坐标
|
||||
MoveTo(0, 0, Width, Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移动到区域内【指定位置】
|
||||
/// region.Derive(x,y).Move() 等效于 region.MoveTo(x,y)
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
public void MoveTo(int x, int y)
|
||||
{
|
||||
MoveTo(x, y, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移动到区域内【指定矩形区域】的中心
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <param name="w"></param>
|
||||
/// <param name="h"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void MoveTo(int x, int y, int w, int h)
|
||||
{
|
||||
var res = ConvertRes<DesktopRegion>.ConvertPositionToTargetRegion(x, y, w, h, this);
|
||||
res.TargetRegion.DesktopRegionMove(res.X, res.Y, res.Width, res.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接在遮罩窗口绘制【自己】
|
||||
/// </summary>
|
||||
|
||||
@@ -5,6 +5,7 @@ using BetterGenshinImpact.Helpers;
|
||||
using BetterGenshinImpact.Service;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using BetterGenshinImpact.Core.Simulator;
|
||||
|
||||
namespace BetterGenshinImpact.GameTask
|
||||
{
|
||||
@@ -32,6 +33,7 @@ namespace BetterGenshinImpact.GameTask
|
||||
public void Init(IntPtr hWnd)
|
||||
{
|
||||
GameHandle = hWnd;
|
||||
PostMessageSimulator = Simulation.PostMessage(GameHandle);
|
||||
SystemInfo = new SystemInfo(hWnd);
|
||||
DpiScale = DpiHelper.ScaleY;
|
||||
//MaskWindowHandle = new WindowInteropHelper(MaskWindow.Instance()).Handle;
|
||||
@@ -42,6 +44,8 @@ namespace BetterGenshinImpact.GameTask
|
||||
|
||||
public IntPtr GameHandle { get; set; }
|
||||
|
||||
public PostMessageSimulator PostMessageSimulator { get; private set; }
|
||||
|
||||
//public IntPtr MaskWindowHandle { get; set; }
|
||||
|
||||
public float DpiScale { get; set; }
|
||||
|
||||
@@ -268,6 +268,7 @@ namespace BetterGenshinImpact.GameTask
|
||||
}
|
||||
|
||||
// 检查游戏是否在前台
|
||||
var hasBackgroundTriggerToRun = false;
|
||||
var active = SystemControl.IsGenshinImpactActive();
|
||||
if (!active)
|
||||
{
|
||||
@@ -291,7 +292,24 @@ namespace BetterGenshinImpact.GameTask
|
||||
}
|
||||
|
||||
_prevGameActive = active;
|
||||
return;
|
||||
|
||||
if (_triggers != null)
|
||||
{
|
||||
var exclusive = _triggers.FirstOrDefault(t => t is { IsEnabled: true, IsExclusive: true });
|
||||
if (exclusive != null)
|
||||
{
|
||||
hasBackgroundTriggerToRun = exclusive.IsBackgroundRunning;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasBackgroundTriggerToRun = _triggers.Any(t => t is { IsEnabled: true, IsBackgroundRunning: true });
|
||||
}
|
||||
}
|
||||
if (!hasBackgroundTriggerToRun)
|
||||
{
|
||||
// 没有后台运行的触发器,这次不再进行截图
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -342,7 +360,7 @@ namespace BetterGenshinImpact.GameTask
|
||||
|
||||
// 循环执行所有触发器 有独占状态的触发器的时候只执行独占触发器
|
||||
var content = new CaptureContent(bitmap, _frameIndex, _timer.Interval);
|
||||
var exclusiveTrigger = _triggers.FirstOrDefault(t => t is { IsEnabled: true, IsExclusive: true });
|
||||
var exclusiveTrigger = _triggers!.FirstOrDefault(t => t is { IsEnabled: true, IsExclusive: true });
|
||||
if (exclusiveTrigger != null)
|
||||
{
|
||||
exclusiveTrigger.OnCapture(content);
|
||||
@@ -350,7 +368,13 @@ namespace BetterGenshinImpact.GameTask
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var trigger in _triggers.Where(trigger => trigger.IsEnabled))
|
||||
var runningTriggers = _triggers.Where(t => t.IsEnabled);
|
||||
if (hasBackgroundTriggerToRun)
|
||||
{
|
||||
runningTriggers = runningTriggers.Where(t => t.IsBackgroundRunning);
|
||||
}
|
||||
|
||||
foreach (var trigger in runningTriggers)
|
||||
{
|
||||
trigger.OnCapture(content);
|
||||
speedTimer.Record(trigger.Name);
|
||||
|
||||
@@ -222,6 +222,31 @@
|
||||
</Grid>
|
||||
</ui:CardExpander.Header>
|
||||
<StackPanel>
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ui:TextBlock Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
FontTypography="Body"
|
||||
Text="后台时依旧点击对话选项"
|
||||
TextWrapping="Wrap" />
|
||||
<ui:TextBlock Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}"
|
||||
Text="游戏请不要最小化,不在对话中的时候鼠标会自动吸附回游戏中"
|
||||
TextWrapping="Wrap" />
|
||||
<ui:ToggleSwitch Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="1"
|
||||
Margin="0,0,36,0"
|
||||
IsChecked="{Binding Config.AutoSkipConfig.RunBackgroundEnabled, Mode=TwoWay}" />
|
||||
</Grid>
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
|
||||
@@ -12,6 +12,7 @@ using BetterGenshinImpact.GameTask.AutoFight;
|
||||
using BetterGenshinImpact.GameTask.AutoTrackPath;
|
||||
using BetterGenshinImpact.GameTask.Common;
|
||||
using BetterGenshinImpact.GameTask.Common.BgiVision;
|
||||
using BetterGenshinImpact.GameTask.Model.Area;
|
||||
using BetterGenshinImpact.Helpers.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using HotKeySettingModel = BetterGenshinImpact.Model.HotKeySettingModel;
|
||||
@@ -385,8 +386,13 @@ public partial class HotKeyPageViewModel : ObservableObject, IViewModel
|
||||
{
|
||||
postMessageSimulator = Simulation.PostMessage(TaskContext.Instance().GameHandle);
|
||||
}
|
||||
User32.GetCursorPos(out var p);
|
||||
Debug.WriteLine($"鼠标位置:{p.X},{p.Y}");
|
||||
// postMessageSimulator.KeyPressBackground(User32.VK.VK_W);
|
||||
GameCaptureRegion.GameRegion1080PPosMove(1340, 655);
|
||||
postMessageSimulator.LeftButtonClickBackground(1340, 655);
|
||||
Thread.Sleep(5);
|
||||
DesktopRegion.DesktopRegionMove(p.X, p.Y);
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user