mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Merge pull request #598 from GashByte/main
Add 'Mult-Start' & fix a start game bug
This commit is contained in:
@@ -86,6 +86,11 @@ internal sealed class SettingEntry
|
||||
/// </summary>
|
||||
public const string LaunchMonitor = "Launch.Monitor";
|
||||
|
||||
/// <summary>
|
||||
/// 启动游戏 多倍启动
|
||||
/// </summary>
|
||||
public const string MultipleInstances = "Launch.MultipleInstances";
|
||||
|
||||
/// <summary>
|
||||
/// 语言
|
||||
/// </summary>
|
||||
|
||||
@@ -3723,6 +3723,24 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 多倍启动你的原神,你可以使用胡桃来多次打开原神并且不受到影响 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageLaunchGameMultipleInstancesDescription {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageLaunchGameMultipleInstancesDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 多倍启动 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageLaunchGameMultipleInstancesHeader {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageLaunchGameMultipleInstancesHeader", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 游戏选项 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -1338,6 +1338,12 @@
|
||||
<data name="ViewPageLaunchGameMonitorsHeader" xml:space="preserve">
|
||||
<value>显示器</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameMultipleInstancesDescription" xml:space="preserve">
|
||||
<value>多倍启动你的原神,你可以使用胡桃来多次打开原神并且不受到影响</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameMultipleInstancesHeader" xml:space="preserve">
|
||||
<value>多倍启动</value>
|
||||
</data>
|
||||
<data name="ViewPageLaunchGameOptionsHeader" xml:space="preserve">
|
||||
<value>游戏选项</value>
|
||||
</data>
|
||||
|
||||
@@ -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
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask LaunchAsync(LaunchOptions options)
|
||||
{
|
||||
if (IsGameRunning())
|
||||
if (!options.MultipleInstances && IsGameRunning())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -347,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);
|
||||
@@ -355,21 +365,52 @@ internal sealed class GameService : IGameService
|
||||
TimeSpan findModuleLimit = TimeSpan.FromMilliseconds(10000);
|
||||
TimeSpan adjustFpsDelay = TimeSpan.FromMilliseconds(2000);
|
||||
|
||||
if (game.Start())
|
||||
{
|
||||
await unlocker.UnlockAsync(findModuleDelay, findModuleLimit, adjustFpsDelay).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (game.Start())
|
||||
{
|
||||
await game.WaitForExitAsync().ConfigureAwait(false);
|
||||
}
|
||||
await unlocker.UnlockAsync(findModuleDelay, findModuleLimit, adjustFpsDelay).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为了实现多开 需要修改mhypbase.dll名称 这是必须的步骤
|
||||
/// </summary>
|
||||
/// <param name="gameProcess">游戏线程</param>
|
||||
/// <param name="gamePath">游戏路径</param>
|
||||
/// <returns>是否成功替换文件</returns>
|
||||
public async Task<bool> LaunchMultipleInstancesGameAsync(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}\mhypbase.dll.backup";
|
||||
if (File.Exists(mhypbasePath))
|
||||
{
|
||||
File.Move(mhypbasePath, tempPath);
|
||||
}
|
||||
else if (!File.Exists(tempPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
gameProcess.Start();
|
||||
|
||||
// wait 12sec for loading library files
|
||||
await Task.Delay(12000);
|
||||
|
||||
File.Move(tempPath, mhypbasePath);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask DetectGameAccountAsync()
|
||||
{
|
||||
@@ -470,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ internal sealed class LaunchOptions : ObservableObject, IOptions<LaunchOptions>
|
||||
private bool? unlockFps;
|
||||
private int? targetFps;
|
||||
private NameValue<int>? monitor;
|
||||
private bool? multipleInstances;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的启动游戏选项
|
||||
@@ -357,6 +358,40 @@ internal sealed class LaunchOptions : ObservableObject, IOptions<LaunchOptions>
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 多次启动原神
|
||||
/// </summary>
|
||||
public bool MultipleInstances
|
||||
{
|
||||
get
|
||||
{
|
||||
if (multipleInstances == null)
|
||||
{
|
||||
using (IServiceScope scope = serviceScopeFactory.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
string? value = appDbContext.Settings.SingleOrDefault(e => e.Key == SettingEntry.MultipleInstances)?.Value;
|
||||
multipleInstances = value != null && bool.Parse(value);
|
||||
}
|
||||
}
|
||||
|
||||
return multipleInstances.Value;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref multipleInstances, value))
|
||||
{
|
||||
using (IServiceScope scope = serviceScopeFactory.CreateScope())
|
||||
{
|
||||
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
appDbContext.Settings.ExecuteDeleteWhere(e => e.Key == SettingEntry.MultipleInstances);
|
||||
appDbContext.Settings.AddAndSave(new(SettingEntry.MultipleInstances, value.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public LaunchOptions Value { get => this; }
|
||||
|
||||
|
||||
@@ -257,6 +257,17 @@
|
||||
IsOpen="{Binding IsElevated}"
|
||||
Message="{shcm:ResourceString Name=ViewPageLaunchGameAdvanceHint}"
|
||||
Severity="Error"/>
|
||||
<wsc:Setting
|
||||
Description="{shcm:ResourceString Name=ViewPageLaunchGameMultipleInstancesDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageLaunchGameMultipleInstancesHeader}"
|
||||
Icon="">
|
||||
<wsc:Setting.ActionContent>
|
||||
<ToggleSwitch
|
||||
Width="120"
|
||||
IsOn="{Binding Options.MultipleInstances, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchSettingStyle}"/>
|
||||
</wsc:Setting.ActionContent>
|
||||
</wsc:Setting>
|
||||
<wsc:Setting
|
||||
Description="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsDescription}"
|
||||
Header="{shcm:ResourceString Name=ViewPageLaunchGameUnlockFpsHeader}"
|
||||
|
||||
@@ -205,7 +205,7 @@ internal sealed class LaunchGameViewModel : Abstraction.ViewModel
|
||||
{
|
||||
IInfoBarService infoBarService = serviceProvider.GetRequiredService<IInfoBarService>();
|
||||
|
||||
if (gameService.IsGameRunning())
|
||||
if (!Options.MultipleInstances && gameService.IsGameRunning())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user