new linked game start #126 #139

This commit is contained in:
huiyadanli 2023-12-10 15:22:38 +08:00
parent 4bf302b013
commit 71095d5724
6 changed files with 233 additions and 149 deletions

View File

@ -50,6 +50,11 @@ namespace BetterGenshinImpact.Core.Config
/// </summary>
public MaskWindowConfig MaskWindowConfig { get; set; } = new();
/// <summary>
/// 原神启动配置
/// </summary>
public GenshinStartConfig GenshinStartConfig { get; set; } = new();
/// <summary>
/// 自动拾取配置
/// </summary>
@ -90,18 +95,14 @@ namespace BetterGenshinImpact.Core.Config
/// </summary>
public HotKeyConfig HotKeyConfig { get; set; } = new();
/// <summary>
/// 原神安装路径
/// </summary>
[ObservableProperty]
private string _installPath = "";
[JsonIgnore] public Action? OnAnyChangedAction { get; set; }
public void InitEvent()
{
this.PropertyChanged += OnAnyPropertyChanged;
MaskWindowConfig.PropertyChanged += OnAnyPropertyChanged;
GenshinStartConfig.PropertyChanged += OnAnyPropertyChanged;
AutoPickConfig.PropertyChanged += OnAnyPropertyChanged;
AutoSkipConfig.PropertyChanged += OnAnyPropertyChanged;
AutoFishingConfig.PropertyChanged += OnAnyPropertyChanged;

View File

@ -9,6 +9,12 @@ namespace BetterGenshinImpact.Core.Config;
[Serializable]
public partial class GenshinStartConfig : ObservableObject
{
/// <summary>
/// 联动启动原神本体
/// </summary>
[ObservableProperty] private bool _linkedStartEnabled = true;
/// <summary>
/// 原神安装路径
/// </summary>

View File

@ -19,23 +19,23 @@ public class SystemControl
public static async Task<nint> StartFromLocalAsync(string path)
{
if (path.EndsWith("YuanShen.exe"))
// 直接exe启动
Process.Start(new ProcessStartInfo(path)
{
DirectStartFromYuanShen(path);
await Task.Delay(10000);
}
UseShellExecute = true,
Arguments = TaskContext.Instance().Config.GenshinStartConfig.GenshinStartArgs
});
if (path.EndsWith("launcher.exe"))
for (var i = 0; i < 5; i++)
{
StartFromLauncher(path);
await Task.Delay(10000);
}
var handle = FindGenshinImpactHandle();
if (handle != 0)
{
return handle;
}
if (path.EndsWith("Genshin Impact Cloud Game.exe"))
{
StartCloudYaunShen(path);
await Task.Delay(3000);
}
return FindGenshinImpactHandle();
}
@ -205,38 +205,32 @@ public class SystemControl
return (exStyle & (int)User32.WindowStylesEx.WS_EX_TOPMOST) != 0;
}
private static void DirectStartFromYuanShen(string path)
{
// 直接exe启动
var process = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
}
private static void StartFromLauncher(string path)
{
// 通过launcher启动
var process = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
Thread.Sleep(1000);
// 获取launcher窗口句柄
var hWnd = FindHandleByProcessName("launcher");
var rect = GetWindowRect(hWnd);
var dpiScale = Helpers.DpiHelper.ScaleY;
// 对于launcher启动按钮的位置时固定的在launcher窗口的右下角
Thread.Sleep(1000);
Simulation.MouseEvent.Click((int)((float)rect.right * dpiScale) - (rect.Width / 5), (int)((float)rect.bottom * dpiScale) - (rect.Height / 8));
}
private static void StartCloudYaunShen(string path)
{
// 通过launcher启动
var process = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
Thread.Sleep(10000);
// 获取launcher窗口句柄
var hWnd = FindHandleByProcessName("Genshin Impact Cloud Game");
var rect = GetWindowRect(hWnd);
var dpiScale = Helpers.DpiHelper.ScaleY;
// 对于launcher启动按钮的位置时固定的在launcher窗口的右下角
Simulation.MouseEvent.Click(rect.right - (rect.Width / 6), rect.bottom - (rect.Height / 13 * 3));
// TODO点完之后有个15s的倒计时好像不处理也没什么问题直接睡个20s吧
Thread.Sleep(20000);
}
// private static void StartFromLauncher(string path)
// {
// // 通过launcher启动
// var process = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
// Thread.Sleep(1000);
// // 获取launcher窗口句柄
// var hWnd = FindHandleByProcessName("launcher");
// var rect = GetWindowRect(hWnd);
// var dpiScale = Helpers.DpiHelper.ScaleY;
// // 对于launcher启动按钮的位置时固定的在launcher窗口的右下角
// Thread.Sleep(1000);
// Simulation.MouseEvent.Click((int)((float)rect.right * dpiScale) - (rect.Width / 5), (int)((float)rect.bottom * dpiScale) - (rect.Height / 8));
// }
//
// private static void StartCloudYaunShen(string path)
// {
// // 通过launcher启动
// var process = Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
// Thread.Sleep(10000);
// // 获取launcher窗口句柄
// var hWnd = FindHandleByProcessName("Genshin Impact Cloud Game");
// var rect = GetWindowRect(hWnd);
// var dpiScale = Helpers.DpiHelper.ScaleY;
// // 对于launcher启动按钮的位置时固定的在launcher窗口的右下角
// Simulation.MouseEvent.Click(rect.right - (rect.Width / 6), rect.bottom - (rect.Height / 13 * 3));
// // TODO点完之后有个15s的倒计时好像不处理也没什么问题直接睡个20s吧
// Thread.Sleep(20000);
// }
}

View File

@ -0,0 +1,59 @@
using Microsoft.Win32;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace BetterGenshinImpact.Genshin.Paths;
internal class GameExePath
{
/// <summary>
/// 游戏路径(云原神除外)
/// </summary>
public static string? GetWithoutCloud()
{
return new[]
{
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\原神",
@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Genshin Impact",
// @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\云·原神",
}.Select(regKey => GetGameExePathFromRegistry(regKey, false)).FirstOrDefault(exePath => !string.IsNullOrEmpty(exePath));
}
/// <summary>
/// 从注册表查找游戏路径
/// </summary>
/// <param name="key"></param>
/// <param name="isCloud">云原神</param>
/// <returns></returns>
private static string? GetGameExePathFromRegistry(string key, bool isCloud)
{
var launcherPath = Registry.GetValue(key, "InstallPath", null) as string;
if (isCloud)
{
var exeName = Registry.GetValue(key, "ExeName", null) as string;
var exePath = Path.Join(launcherPath, exeName);
if (File.Exists(exePath))
{
return exePath;
}
}
else
{
var configPath = Path.Join(launcherPath, "config.ini");
if (File.Exists(configPath))
{
var str = File.ReadAllText(configPath);
var installPath = Regex.Match(str, @"game_install_path=(.+)").Groups[1].Value.Trim();
var exeName = Regex.Match(str, @"game_start_name=(.+)").Groups[1].Value.Trim();
var exePath = Path.Join(installPath, exeName);
if (File.Exists(exePath))
{
return exePath;
}
}
}
return null;
}
}

View File

@ -62,7 +62,7 @@
</Grid>
</Border>
<!-- 原神,启动! -->
<!-- 更好的原神,启动! -->
<ui:CardExpander Margin="0,12,0,12"
ContentPadding="0"
Icon="{ui:SymbolIcon Play24}">
@ -79,13 +79,18 @@
<ui:TextBlock Grid.Row="0"
Grid.Column="0"
FontTypography="Body"
Text="更好的原神,启动!"
Text="BetterGI · 更好的原神,启动!"
TextWrapping="Wrap" />
<ui:TextBlock Grid.Row="1"
Grid.Column="0"
Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}"
Text="启动后才能使用各项功能,点击展开启动相关配置。"
TextWrapping="Wrap" />
TextWrapping="Wrap">
启动后才能使用各项功能,
<Run FontWeight="Bold" TextDecorations="Underline">
点击展开启动相关配置
</Run>
</ui:TextBlock>
<StackPanel Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
@ -103,35 +108,6 @@
</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="{Binding Config.InstallPath, Mode=TwoWay}"
TextWrapping="Wrap" />
<ui:Button
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
Margin="0,0,36,0"
Command="{Binding SelectInstallPathCommand}"
Content="浏览" />
</Grid>
<Separator Margin="-18,0" BorderThickness="0,1,0,0" />
<Grid Margin="16">
<Grid.RowDefinitions>
@ -246,6 +222,101 @@
</StackPanel>
</ui:CardExpander>
<!-- 原神,启动! -->
<ui:CardExpander Margin="0,0,0,12" ContentPadding="0" Icon="{ui:SymbolIcon LinkSquare24}">
<ui:CardExpander.Header>
<Grid>
<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"
TextWrapping="Wrap"
Text="同时启动原神" />
<ui:TextBlock
Grid.Row="1"
Grid.Column="0"
Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}"
TextWrapping="Wrap"
Text="启动 BetterGI 时,如果原神未启动,则自动启动原神。" />
<ui:ToggleSwitch
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
Margin="0,0,24,0"
IsChecked="{Binding Config.GenshinStartConfig.LinkedStartEnabled, Mode=TwoWay}" />
</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="{Binding Config.GenshinStartConfig.InstallPath, Mode=TwoWay}"
TextWrapping="Wrap" />
<ui:Button
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
Margin="0,0,36,0"
Command="{Binding SelectInstallPathCommand}"
Content="浏览" />
</Grid>
<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"
TextWrapping="Wrap"
Text="启动参数" />
<ui:TextBlock
Grid.Row="1"
Grid.Column="0"
Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}"
TextWrapping="Wrap"
Text="如果你不知道什么是启动参数请不要填写。" />
<!--常见启动参数:无边框 -popupwindow 指定分辨率 -screen-width 1920 -screen-height 1080-->
<ui:TextBox
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
MinWidth="300"
Margin="0,0,24,0"
Text="{Binding Config.GenshinStartConfig.GenshinStartArgs, Mode=TwoWay}" />
</Grid>
</StackPanel>
</ui:CardExpander>
<!--<ui:Button x:Name="Test" Margin="0,20,0,0" Content="测试" Command="{Binding TestCommand}" />-->

View File

@ -1,6 +1,7 @@
using BetterGenshinImpact.Core;
using BetterGenshinImpact.Core.Config;
using BetterGenshinImpact.GameTask;
using BetterGenshinImpact.Genshin.Paths;
using BetterGenshinImpact.Helpers;
using BetterGenshinImpact.Service.Interface;
using BetterGenshinImpact.View;
@ -57,23 +58,7 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware
{
_taskDispatcher = taskTriggerDispatcher;
Config = configService.Get();
// 检查用户是否配置了原神安装目录,如果没有,尝试从注册表中读取
if (string.IsNullOrEmpty(Config.InstallPath))
{
string installPath = string.Empty;
if (ReadGameInstallPath(out installPath))
{
// 检查文件是否存在
if (!File.Exists(installPath))
{
System.Windows.MessageBox.Show("未找到原神安装目录,请手动选择!");
}
else
{
Config.InstallPath = installPath;
}
}
}
ReadGameInstallPath();
WeakReferenceMessenger.Default.Register<PropertyChangedMessage<object>>(this, (sender, msg) =>
{
if (msg.PropertyName == "Close")
@ -97,6 +82,7 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware
[RelayCommand]
private void OnLoaded()
{
}
private void OnClosed()
@ -147,9 +133,9 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware
var hWnd = SystemControl.FindGenshinImpactHandle();
if (hWnd == IntPtr.Zero)
{
if (!string.IsNullOrEmpty(Config.InstallPath))
if (!string.IsNullOrEmpty(Config.GenshinStartConfig.InstallPath))
{
hWnd = await SystemControl.StartFromLocalAsync(Config.InstallPath);
hWnd = await SystemControl.StartFromLocalAsync(Config.GenshinStartConfig.InstallPath);
}
if (hWnd == IntPtr.Zero)
{
@ -230,8 +216,10 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware
await Task.Run(() =>
{
// 弹出选择文件夹对话框
var dialog = new Ookii.Dialogs.Wpf.VistaOpenFileDialog();
dialog.Filter = "原神|YuanShen.exe|云原神|Genshin Impact Cloud Game.exe|启动器|launcher.exe|所有文件|*.*";
var dialog = new Ookii.Dialogs.Wpf.VistaOpenFileDialog
{
Filter = "原神|YuanShen.exe|原神国际服|GenshinImpact.exe|所有文件|*.*"
};
if (dialog.ShowDialog() == true)
{
var path = dialog.FileName;
@ -239,9 +227,9 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware
{
return;
}
if (path.EndsWith("YuanShen.exe") || path.EndsWith("Genshin Impact Cloud Game.exe") || path.EndsWith("launcher.exe"))
if (path.EndsWith("YuanShen.exe") || path.EndsWith("GenshinImpact.exe"))
{
Config.InstallPath = path;
Config.GenshinStartConfig.InstallPath = path;
}
else
{
@ -251,51 +239,16 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware
});
}
private bool ReadGameInstallPath(out string installPath)
private void ReadGameInstallPath()
{
// 首先尝试获取原神路径
var path = ReadFromRegistry(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\原神", "InstallPath");
if (!string.IsNullOrEmpty(path))
// 检查用户是否配置了原神安装目录,如果没有,尝试从注册表中读取
if (string.IsNullOrEmpty(Config.GenshinStartConfig.InstallPath))
{
// 这里拿到了launcher的安装目录读取同目录下的config.ini文件获取游戏的安装目录
var configIniPath = Path.Combine(path, "config.ini");
if (File.Exists(configIniPath))
var path = GameExePath.GetWithoutCloud();
if (!string.IsNullOrEmpty(path))
{
var lines = File.ReadAllLines(configIniPath);
var gameInstallPath = lines.FirstOrDefault(x => x.StartsWith("game_install_path"));
if (!string.IsNullOrEmpty(gameInstallPath))
{
installPath = Path.Combine(gameInstallPath.Split('=')[1], "Yuanshen.exe").Replace("/", "\\");
return true;
}
Config.GenshinStartConfig.InstallPath = path;
}
// 如果没读取到就使用launcher的路径
installPath = Path.Combine(path, "launcher.exe");
return true;
}
// 如果没有读取到原神的路径,尝试读取云原神
path = ReadFromRegistry(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\云·原神", "InstallPath");
if (!string.IsNullOrEmpty(path))
{
installPath = Path.Combine(path, "Genshin Impact Cloud Game.exe");
return true;
}
installPath = string.Empty;
return false;
}
private string ReadFromRegistry(string key, string keyName)
{
var regKey = Registry.LocalMachine.OpenSubKey(key);
if (regKey == null)
{
return string.Empty;
}
var value = regKey.GetValue(keyName);
if (value == null)
{
return string.Empty;
}
return value.ToString();
}
}