From 6caeb1d238a4c21b448bb609d3481267afb0186f Mon Sep 17 00:00:00 2001 From: x3zF Love U Date: Sun, 12 Mar 2023 16:32:59 +0800 Subject: [PATCH 1/3] Add 'Mult-Start' & fix a start game bug --- .../Snap.Hutao/Model/Entity/SettingEntry.cs | 5 ++ .../Resource/Localization/SH.Designer.cs | 18 ++++ .../Snap.Hutao/Resource/Localization/SH.resx | 6 ++ .../Snap.Hutao/Service/Game/GameService.cs | 82 +++++++++++++++++-- .../Snap.Hutao/Service/Game/LaunchOptions.cs | 35 ++++++++ .../Snap.Hutao/View/Page/LaunchGamePage.xaml | 11 +++ .../ViewModel/Game/LaunchGameViewModel.cs | 2 +- 7 files changed, 153 insertions(+), 6 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs index cacd06f3..0829ff38 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs @@ -86,6 +86,11 @@ internal sealed class SettingEntry /// public const string LaunchMonitor = "Launch.Monitor"; + /// + /// 启动游戏 多倍启动 + /// + public const string MultStart = "MultStart"; + /// /// 语言 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs index 9a58c27a..e3edace1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs @@ -3723,6 +3723,24 @@ namespace Snap.Hutao.Resource.Localization { } } + /// + /// 查找类似 多倍启动你的原神,你可以使用胡桃来多次打开原神并且不受到影响 的本地化字符串。 + /// + internal static string ViewPageLaunchGameMultStartDescription { + get { + return ResourceManager.GetString("ViewPageLaunchGameMultStartDescription", resourceCulture); + } + } + + /// + /// 查找类似 多倍启动 的本地化字符串。 + /// + internal static string ViewPageLaunchGameMultStartHeader { + get { + return ResourceManager.GetString("ViewPageLaunchGameMultStartHeader", resourceCulture); + } + } + /// /// 查找类似 游戏选项 的本地化字符串。 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index f306750c..f7379461 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -1338,6 +1338,12 @@ 显示器 + + 多倍启动你的原神,你可以使用胡桃来多次打开原神并且不受到影响 + + + 多倍启动 + 游戏选项 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs index 46c10a46..d9d467cb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs @@ -8,6 +8,7 @@ using Snap.Hutao.Core; using Snap.Hutao.Core.Database; using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Core.IO.Ini; +using Snap.Hutao.Core.LifeCycle; using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Entity.Database; using Snap.Hutao.Service.Game.Locator; @@ -311,7 +312,7 @@ internal sealed class GameService : IGameService /// public async ValueTask LaunchAsync(LaunchOptions options) { - if (IsGameRunning()) + if (!options.MultStart && IsGameRunning()) { return; } @@ -355,21 +356,92 @@ internal sealed class GameService : IGameService TimeSpan findModuleLimit = TimeSpan.FromMilliseconds(10000); TimeSpan adjustFpsDelay = TimeSpan.FromMilliseconds(2000); - if (game.Start()) + try { - await unlocker.UnlockAsync(findModuleDelay, findModuleLimit, adjustFpsDelay).ConfigureAwait(false); + if (options.MultStart && Activation.GetElevated()) + { + if (!await CloseDllProcessAsync(game, gamePath)) + { + return; + } + + await unlocker.UnlockAsync(findModuleDelay, findModuleLimit, adjustFpsDelay).ConfigureAwait(false); + } + else if (game.Start()) + { + await unlocker.UnlockAsync(findModuleDelay, findModuleLimit, adjustFpsDelay).ConfigureAwait(false); + } + } + catch + { + return; } } else { - if (game.Start()) + try { - await game.WaitForExitAsync().ConfigureAwait(false); + if (options.MultStart && Activation.GetElevated()) + { + if (!await CloseDllProcessAsync(game, gamePath)) + { + return; + } + } + else if (game.Start()) + { + await game.WaitForExitAsync().ConfigureAwait(false); + } + } + catch + { + return; } } } } + /// + /// 为了实现多开 需要修改mhypbase.dll名称 这是必须的步骤 + /// + /// 游戏线程 + /// 游戏路径 + /// 为真时关闭 为假时返回 + public async Task CloseDllProcessAsync(Process gameProcess, string gamePath) + { + if (gamePath == null) + { + return false; + } + + DirectoryInfo directoryInfo = new DirectoryInfo(gamePath); + if (directoryInfo.Parent == null) + { + return false; + } + + string? gameDirectory = directoryInfo.Parent.FullName.ToString(); + string? mhypbasePath = $@"{gameDirectory}\mhypbase.dll"; + string? tempPath = $@"{gameDirectory}\temp.dll"; + if (File.Exists(mhypbasePath)) + { + File.Move(mhypbasePath, tempPath); + } + else if (!File.Exists(tempPath)) + { + return false; + } + + gameProcess.Start(); + + // wait 15sec for loading library files + await Task.Delay(15000); + + File.Move(tempPath, mhypbasePath); + + return false; + } + /// public async ValueTask DetectGameAccountAsync() { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs index 2ce84853..4f290c0e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs @@ -35,6 +35,7 @@ internal sealed class LaunchOptions : ObservableObject, IOptions private bool? unlockFps; private int? targetFps; private NameValue? monitor; + private bool? multStart; /// /// 构造一个新的启动游戏选项 @@ -357,6 +358,40 @@ internal sealed class LaunchOptions : ObservableObject, IOptions } } + /// + /// 多次启动原神 + /// + public bool MultStart + { + get + { + if (multStart == null) + { + using (IServiceScope scope = serviceScopeFactory.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.MultStart)?.Value; + multStart = value != null && bool.Parse(value); + } + } + + return multStart.Value; + } + + set + { + if (SetProperty(ref multStart, value)) + { + using (IServiceScope scope = serviceScopeFactory.CreateScope()) + { + AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); + appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.MultStart); + appDbContext.Settings.AddAndSave(new(SettingEntry.MultStart, value.ToString())); + } + } + } + } + /// public LaunchOptions Value { get => this; } diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml index b8e58b5a..6065beaa 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml @@ -257,6 +257,17 @@ IsOpen="{Binding IsElevated}" Message="{shcm:ResourceString Name=ViewPageLaunchGameAdvanceHint}" Severity="Error"/> + + + + + (); - if (gameService.IsGameRunning()) + if (!Options.MultStart && gameService.IsGameRunning()) { return; } From 29582efaee9812b2cf0ef4bad63bd463a45c2e6a Mon Sep 17 00:00:00 2001 From: x3zF Love U Date: Sun, 12 Mar 2023 18:15:40 +0800 Subject: [PATCH 2/3] reduce the Task waiting time of mult-start --- .../Snap.Hutao/Service/Game/GameService.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs index d9d467cb..0563a8ab 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs @@ -360,7 +360,7 @@ internal sealed class GameService : IGameService { if (options.MultStart && Activation.GetElevated()) { - if (!await CloseDllProcessAsync(game, gamePath)) + if (!await MultStartGameAsync(game, gamePath)) { return; } @@ -383,7 +383,7 @@ internal sealed class GameService : IGameService { if (options.MultStart && Activation.GetElevated()) { - if (!await CloseDllProcessAsync(game, gamePath)) + if (!await MultStartGameAsync(game, gamePath)) { return; } @@ -406,8 +406,8 @@ internal sealed class GameService : IGameService /// /// 游戏线程 /// 游戏路径 - /// 为真时关闭 为假时返回 - public async Task CloseDllProcessAsync(Process gameProcess, string gamePath) + /// 为真时成功 为假时返回 + public async Task MultStartGameAsync(Process gameProcess, string gamePath) { if (gamePath == null) { @@ -434,8 +434,8 @@ internal sealed class GameService : IGameService gameProcess.Start(); - // wait 15sec for loading library files - await Task.Delay(15000); + // wait 12sec for loading library files + await Task.Delay(12000); File.Move(tempPath, mhypbasePath); From a832ea96ea61b9428700d53d6593095e0174b242 Mon Sep 17 00:00:00 2001 From: x3zF Love U Date: Sun, 12 Mar 2023 22:24:29 +0800 Subject: [PATCH 3/3] repair 'LaunchMultipleInstancesGameAsync' --- .../Snap.Hutao/Model/Entity/SettingEntry.cs | 2 +- .../Resource/Localization/SH.Designer.cs | 8 +- .../Snap.Hutao/Resource/Localization/SH.resx | 4 +- .../Snap.Hutao/Service/Game/GameService.cs | 79 ++++++++----------- .../Snap.Hutao/Service/Game/LaunchOptions.cs | 18 ++--- .../Snap.Hutao/View/Page/LaunchGamePage.xaml | 6 +- .../ViewModel/Game/LaunchGameViewModel.cs | 2 +- 7 files changed, 54 insertions(+), 65 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs index 0829ff38..6bda9d53 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.cs @@ -89,7 +89,7 @@ internal sealed class SettingEntry /// /// 启动游戏 多倍启动 /// - public const string MultStart = "MultStart"; + public const string MultipleInstances = "Launch.MultipleInstances"; /// /// 语言 diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs index e3edace1..b3ea980d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs @@ -3726,18 +3726,18 @@ namespace Snap.Hutao.Resource.Localization { /// /// 查找类似 多倍启动你的原神,你可以使用胡桃来多次打开原神并且不受到影响 的本地化字符串。 /// - internal static string ViewPageLaunchGameMultStartDescription { + internal static string ViewPageLaunchGameMultipleInstancesDescription { get { - return ResourceManager.GetString("ViewPageLaunchGameMultStartDescription", resourceCulture); + return ResourceManager.GetString("ViewPageLaunchGameMultipleInstancesDescription", resourceCulture); } } /// /// 查找类似 多倍启动 的本地化字符串。 /// - internal static string ViewPageLaunchGameMultStartHeader { + internal static string ViewPageLaunchGameMultipleInstancesHeader { get { - return ResourceManager.GetString("ViewPageLaunchGameMultStartHeader", resourceCulture); + return ResourceManager.GetString("ViewPageLaunchGameMultipleInstancesHeader", resourceCulture); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index f7379461..52e80233 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -1338,10 +1338,10 @@ 显示器 - + 多倍启动你的原神,你可以使用胡桃来多次打开原神并且不受到影响 - + 多倍启动 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs index 0563a8ab..aa5bdda8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameService.cs @@ -312,7 +312,7 @@ internal sealed class GameService : IGameService /// public async ValueTask LaunchAsync(LaunchOptions options) { - if (!options.MultStart && IsGameRunning()) + if (!options.MultipleInstances && IsGameRunning()) { return; } @@ -348,6 +348,15 @@ internal sealed class GameService : IGameService using (await gameSemaphore.EnterAsync().ConfigureAwait(false)) { + if (options.MultipleInstances && Activation.GetElevated()) + { + await LaunchGameAsync(game, gamePath); + } + else + { + await LaunchGameAsync(game); + } + if (options.UnlockFps) { IGameFpsUnlocker unlocker = new GameFpsUnlocker(game, options.TargetFps); @@ -356,47 +365,7 @@ internal sealed class GameService : IGameService TimeSpan findModuleLimit = TimeSpan.FromMilliseconds(10000); TimeSpan adjustFpsDelay = TimeSpan.FromMilliseconds(2000); - try - { - if (options.MultStart && Activation.GetElevated()) - { - if (!await MultStartGameAsync(game, gamePath)) - { - return; - } - - await unlocker.UnlockAsync(findModuleDelay, findModuleLimit, adjustFpsDelay).ConfigureAwait(false); - } - else if (game.Start()) - { - await unlocker.UnlockAsync(findModuleDelay, findModuleLimit, adjustFpsDelay).ConfigureAwait(false); - } - } - catch - { - return; - } - } - else - { - try - { - if (options.MultStart && Activation.GetElevated()) - { - if (!await MultStartGameAsync(game, gamePath)) - { - return; - } - } - else if (game.Start()) - { - await game.WaitForExitAsync().ConfigureAwait(false); - } - } - catch - { - return; - } + await unlocker.UnlockAsync(findModuleDelay, findModuleLimit, adjustFpsDelay).ConfigureAwait(false); } } } @@ -406,8 +375,8 @@ internal sealed class GameService : IGameService /// /// 游戏线程 /// 游戏路径 - /// 为真时成功 为假时返回 - public async Task MultStartGameAsync(Process gameProcess, string gamePath) + /// 是否成功替换文件 + public async Task LaunchMultipleInstancesGameAsync(Process gameProcess, string? gamePath) { if (gamePath == null) { @@ -422,7 +391,7 @@ internal sealed class GameService : IGameService string? gameDirectory = directoryInfo.Parent.FullName.ToString(); string? mhypbasePath = $@"{gameDirectory}\mhypbase.dll"; - string? tempPath = $@"{gameDirectory}\temp.dll"; + string? tempPath = $@"{gameDirectory}\mhypbase.dll.backup"; if (File.Exists(mhypbasePath)) { File.Move(mhypbasePath, tempPath); @@ -542,4 +511,24 @@ internal sealed class GameService : IGameService return (launchScheme.IsOversea && gameFileName == GenshinImpactFileName) || (!launchScheme.IsOversea && gameFileName == YuanShenFileName); } + + private async Task LaunchGameAsync(Process gameProcess, string? gamePath = null) + { + try + { + if (gamePath == null) + { + gameProcess.Start(); + } + else + { + await LaunchMultipleInstancesGameAsync(gameProcess, gamePath); + return; + } + } + catch + { + return; + } + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs index 4f290c0e..554c4cec 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs @@ -35,7 +35,7 @@ internal sealed class LaunchOptions : ObservableObject, IOptions private bool? unlockFps; private int? targetFps; private NameValue? monitor; - private bool? multStart; + private bool? multipleInstances; /// /// 构造一个新的启动游戏选项 @@ -361,32 +361,32 @@ internal sealed class LaunchOptions : ObservableObject, IOptions /// /// 多次启动原神 /// - public bool MultStart + public bool MultipleInstances { get { - if (multStart == null) + if (multipleInstances == null) { using (IServiceScope scope = serviceScopeFactory.CreateScope()) { AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.MultStart)?.Value; - multStart = value != null && bool.Parse(value); + string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.MultipleInstances)?.Value; + multipleInstances = value != null && bool.Parse(value); } } - return multStart.Value; + return multipleInstances.Value; } set { - if (SetProperty(ref multStart, value)) + if (SetProperty(ref multipleInstances, value)) { using (IServiceScope scope = serviceScopeFactory.CreateScope()) { AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService(); - appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.MultStart); - appDbContext.Settings.AddAndSave(new(SettingEntry.MultStart, value.ToString())); + appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.MultipleInstances); + appDbContext.Settings.AddAndSave(new(SettingEntry.MultipleInstances, value.ToString())); } } } diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml index 6065beaa..d33f1ace 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml @@ -258,13 +258,13 @@ Message="{shcm:ResourceString Name=ViewPageLaunchGameAdvanceHint}" Severity="Error"/> diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs index 6b8b685a..e0776b52 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs @@ -205,7 +205,7 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel { IInfoBarService infoBarService = serviceProvider.GetRequiredService(); - if (!Options.MultStart && gameService.IsGameRunning()) + if (!Options.MultipleInstances && gameService.IsGameRunning()) { return; }