auto skip: backgroud click

This commit is contained in:
辉鸭蛋
2024-06-01 18:09:34 +08:00
parent b75420cd0b
commit cfe963dcae
10 changed files with 226 additions and 83 deletions

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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; }

View File

@@ -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);

View File

@@ -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" />

View File

@@ -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);
}
));
}