diff --git a/bin/unlockfps.exe b/bin/unlockfps.exe new file mode 100644 index 0000000..122be81 Binary files /dev/null and b/bin/unlockfps.exe differ diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/Process/NullProcess.cs b/src/Snap.Hutao/Snap.Hutao/Factory/Process/NullProcess.cs new file mode 100644 index 0000000..25e084c --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Factory/Process/NullProcess.cs @@ -0,0 +1,45 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.Diagnostics; +using Snap.Hutao.Win32.Foundation; + +namespace Snap.Hutao.Factory.Process; + +internal sealed class NullProcess : IProcess +{ + public int Id => 0; + + public nint Handle => 0; + + public HWND MainWindowHandle => default; + + public bool HasExited => true; + + public int ExitCode => 0; + + public void Start() + { + // Do nothing + } + + public void ResumeMainThread() + { + // Do nothing + } + + public void WaitForExit() + { + // Do nothing + } + + public void Kill() + { + // Do nothing + } + + public void Dispose() + { + // Do nothing + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/WeaponIds.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/WeaponIds.cs index ca5b5eb..a933b8d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/WeaponIds.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/WeaponIds.cs @@ -34,7 +34,7 @@ internal static class WeaponIds 13502U, 13505U, 14501U, 14502U, 15501U, 15502U, - 15515U, 15518U + 15515U, 11518U ]; public static bool IsOrangeStandardWish(in WeaponId weaponId) diff --git a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest index 43f146d..2e373a5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest +++ b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest @@ -1,4 +1,4 @@ - + + Version="1.18.0.0" /> Snap Hutao diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Island/FpsConfigTest.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Island/FpsConfigTest.cs new file mode 100644 index 0000000..240400f --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Island/FpsConfigTest.cs @@ -0,0 +1,55 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.Setting; +using System.IO; + +namespace Snap.Hutao.Service.Game.Island; + +internal static class FpsConfigTest +{ + // 测试用,手动更新FPS配置文件 + public static void TestConfigUpdate() + { + // 直接从LocalSetting读取当前FPS设置 + int currentFps = LocalSetting.Get(SettingKeys.LaunchTargetFps, 60); + + // 配置文件路径 + string configPath = Path.Combine(AppContext.BaseDirectory, "fps_config.ini"); + + // 读取当前配置 + if (File.Exists(configPath)) + { + string[] lines = File.ReadAllLines(configPath); + int configFps = 60; + + foreach (string line in lines) + { + if (line.StartsWith("FPS=")) + { + configFps = int.Parse(line.Substring(4)); + break; + } + } + + System.Diagnostics.Debug.WriteLine($"Current FPS from LocalSetting: {currentFps}"); + System.Diagnostics.Debug.WriteLine($"Current FPS from config file: {configFps}"); + + if (currentFps != configFps) + { + // 更新配置文件 + for (int i = 0; i < lines.Length; i++) + { + if (lines[i].StartsWith("FPS=")) + { + lines[i] = $"FPS={currentFps}"; + break; + } + } + + File.WriteAllLines(configPath, lines); + System.Diagnostics.Debug.WriteLine($"Updated config file with FPS: {currentFps}"); + } + } + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Island/GameFpsUnlockInterop.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Island/GameFpsUnlockInterop.cs new file mode 100644 index 0000000..ff87617 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Island/GameFpsUnlockInterop.cs @@ -0,0 +1,350 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core; +using Snap.Hutao.Core.Diagnostics; +using Snap.Hutao.Core.ExceptionService; +using Snap.Hutao.Core.Setting; +using Snap.Hutao.Service.Game.FileSystem; +using Snap.Hutao.Service.Game.Launching.Context; +using Snap.Hutao.Web.Hutao; +using System.Diagnostics; +using System.IO; +using System.Text; + +namespace Snap.Hutao.Service.Game.Island; + +internal sealed class GameFpsUnlockInterop : IGameIslandInterop, IDisposable +{ + private const string UnlockerExecutableName = "unlockfps.exe"; + private const string UnlockerConfigName = "fps_config.ini"; + + private readonly bool resume; + + private string? unlockerPath; + private string? gamePath; + private Process? unlockerProcess; + + public GameFpsUnlockInterop(bool resume) + { + this.resume = resume; + } + + public async ValueTask BeforeAsync(BeforeLaunchExecutionContext context) + { + if (resume) + { + return; + } + + // 获取unlocker.exe路径,放在Snap.Hutao同一目录下 + string hutaoDirectory = AppContext.BaseDirectory; + unlockerPath = Path.Combine(hutaoDirectory, UnlockerExecutableName); + + if (!File.Exists(unlockerPath)) + { + throw HutaoException.InvalidOperation("未找到unlockfps.exe文件,请将genshin-fps-unlock-master编译后的unlockfps.exe放置在Snap.Hutao同目录下"); + } + + // 获取游戏路径 + gamePath = context.FileSystem.GameFilePath; + + // 验证游戏路径 + SentrySdk.AddBreadcrumb( + $"Game path from Snap.Hutao: {gamePath}", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Info); + + + if (!File.Exists(gamePath)) + { + throw HutaoException.InvalidOperation($"游戏文件不存在: {gamePath}"); + } + + // 创建配置文件 + await CreateUnlockerConfigAsync(context).ConfigureAwait(false); + + // 启动解锁器进程 + await StartUnlockerProcessAsync(context, CancellationToken.None).ConfigureAwait(false); + } + + public async ValueTask WaitForExitAsync(LaunchExecutionContext context, CancellationToken token = default) + { + if (resume) + { + // 恢复模式下,尝试连接已存在的解锁器进程 + await MonitorExistingUnlockerAsync(context, token).ConfigureAwait(false); + return; + } + + // 监控解锁器进程状态(解锁器会自动启动并监控游戏) + await MonitorUnlockerProcessAsync(context, token).ConfigureAwait(false); + } + + private async ValueTask CreateUnlockerConfigAsync(BeforeLaunchExecutionContext context) + { + if (string.IsNullOrEmpty(gamePath)) + { + throw HutaoException.NotSupported("游戏路径未初始化"); + } + + // 直接在unlocker同目录创建配置文件 + string unlockerConfigPath = Path.Combine(Path.GetDirectoryName(unlockerPath)!, UnlockerConfigName); + int targetFps = context.LaunchOptions.TargetFps.Value; + + string configContent = $"[Setting]\nPath={gamePath}\nFPS={targetFps}"; + + // 添加重试机制处理可能的权限问题 + for (int i = 0; i < 3; i++) + { + try + { + await File.WriteAllTextAsync(unlockerConfigPath, configContent).ConfigureAwait(false); + break; // 成功写入,退出循环 + } + catch (UnauthorizedAccessException) + { + if (i == 2) + { + throw HutaoException.InvalidOperation($"无法写入配置文件 {unlockerConfigPath},请检查权限"); + } + await Task.Delay(500).ConfigureAwait(false); + } + catch (IOException) + { + if (i == 2) + { + throw HutaoException.InvalidOperation($"无法写入配置文件 {unlockerConfigPath},文件可能被占用"); + } + await Task.Delay(500).ConfigureAwait(false); + } + } + } + + private async ValueTask StartUnlockerProcessAsync(BeforeLaunchExecutionContext context, CancellationToken token) + { + try + { + + string configPath = Path.Combine(Path.GetDirectoryName(unlockerPath)!, UnlockerConfigName); + if (!File.Exists(configPath)) + { + throw HutaoException.InvalidOperation($"配置文件不存在: {configPath}"); + } + + + string configContent = await File.ReadAllTextAsync(configPath).ConfigureAwait(false); + SentrySdk.AddBreadcrumb( + $"Starting unlocker with config: {configContent}", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Info); + + ProcessStartInfo startInfo = new() + { + FileName = unlockerPath, + WorkingDirectory = Path.GetDirectoryName(unlockerPath), + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + WindowStyle = ProcessWindowStyle.Normal, + }; + + unlockerProcess = new Process { StartInfo = startInfo }; + + + unlockerProcess.Start(); + + + Task outputTask = Task.Run(async () => + { + while (!unlockerProcess.StandardOutput.EndOfStream) + { + string line = await unlockerProcess.StandardOutput.ReadLineAsync().ConfigureAwait(false); + if (line != null) + { + SentrySdk.AddBreadcrumb( + $"Unlocker output: {line}", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Info); + } + } + }); + + Task errorTask = Task.Run(async () => + { + while (!unlockerProcess.StandardError.EndOfStream) + { + string line = await unlockerProcess.StandardError.ReadLineAsync().ConfigureAwait(false); + if (line != null) + { + SentrySdk.AddBreadcrumb( + $"Unlocker error: {line}", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Error); + } + } + }); + + // 等待解锁器初始化 + await Task.Delay(5000).ConfigureAwait(false); + + + } + catch (Exception ex) + { + throw HutaoException.Throw($"启动FPS解锁器失败: {ex.Message}", ex); + } + } + + private async ValueTask MonitorExistingUnlockerAsync(LaunchExecutionContext context, CancellationToken token) + { + // 恢复模式下,检查是否有解锁器进程在运行 + Process[] processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(UnlockerExecutableName)); + if (processes.Length == 0) + { + // 没有找到解锁器进程,但游戏在运行,这是正常情况 + return; + } + + unlockerProcess = processes[0]; + await MonitorUnlockerProcessAsync(context, token).ConfigureAwait(false); + } + + private async ValueTask MonitorUnlockerProcessAsync(LaunchExecutionContext context, CancellationToken token) + { + if (unlockerProcess is null) + { + return; + } + + using (PeriodicTimer timer = new(TimeSpan.FromSeconds(2))) + { + while (await timer.WaitForNextTickAsync(token).ConfigureAwait(false)) + { + // 检查解锁器进程状态 + if (unlockerProcess.HasExited) + { + // 解锁器已退出,这意味着游戏也已退出 + break; + } + + // 同步FPS设置(如果用户在运行时修改了) + await SyncFpsSettingsAsync(context.LaunchOptions).ConfigureAwait(false); + } + } + + // 确保解锁器进程已清理 + CleanupUnlockerProcess(); + } + + private async ValueTask SyncFpsSettingsAsync(LaunchOptions launchOptions) + { + if (unlockerProcess is null || unlockerProcess.HasExited) + { + return; + } + + try + { + string configPath = Path.Combine(Path.GetDirectoryName(unlockerPath)!, UnlockerConfigName); + if (File.Exists(configPath)) + { + string[] lines = await File.ReadAllLinesAsync(configPath).ConfigureAwait(false); + int currentFps = launchOptions.TargetFps.Value; + + bool needsUpdate = false; + for (int i = 0; i < lines.Length; i++) + { + if (lines[i].StartsWith("FPS=")) + { + int configFps = int.Parse(lines[i].Substring(4)); + if (configFps != currentFps) + { + lines[i] = $"FPS={currentFps}"; + needsUpdate = true; + } + break; + } + } + + if (needsUpdate) + { + // 添加重试机制处理可能的权限问题 + for (int i = 0; i < 3; i++) + { + try + { + await File.WriteAllLinesAsync(configPath, lines).ConfigureAwait(false); + break; // 成功写入,退出循环 + } + catch (UnauthorizedAccessException) + { + if (i == 2) // 最后一次尝试 + { + SentrySdk.AddBreadcrumb( + $"无法写入配置文件 {configPath},请检查权限", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Error); + return; + } + await Task.Delay(500).ConfigureAwait(false); // 等待500ms后重试 + } + catch (IOException) + { + if (i == 2) // 最后一次尝试 + { + SentrySdk.AddBreadcrumb( + $"无法写入配置文件 {configPath},文件可能被占用", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Error); + return; + } + await Task.Delay(500).ConfigureAwait(false); // 等待500ms后重试 + } + } + } + } + } + catch (Exception ex) + { + // 同步配置失败,记录但不影响主流程 + SentrySdk.AddBreadcrumb( + $"Failed to sync FPS settings: {ex.Message}", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Warning); + } + } + + + + private void CleanupUnlockerProcess() + { + if (unlockerProcess is not null && !unlockerProcess.HasExited) + { + try + { + unlockerProcess.Kill(); + unlockerProcess.WaitForExit(); + } + catch (Exception ex) + { + // 忽略清理过程中的错误 + SentrySdk.AddBreadcrumb( + $"Failed to cleanup unlocker process: {ex.Message}", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Warning); + } + finally + { + unlockerProcess.Dispose(); + unlockerProcess = null; + } + } + } + + public void Dispose() + { + CleanupUnlockerProcess(); + } +} \ 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 8a447f3..c30747f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs @@ -12,6 +12,8 @@ using Snap.Hutao.Service.Game.FileSystem; using Snap.Hutao.Service.Game.PathAbstraction; using Snap.Hutao.Win32; using System.Collections.Immutable; +using System.IO; +using System.Threading.Tasks; namespace Snap.Hutao.Service.Game; @@ -106,7 +108,7 @@ internal sealed partial class LaunchOptions : DbStoreOptions, IRestrictedGamePat public IObservableProperty IsSetTargetFrameRateEnabled { get => field ??= CreateProperty(SettingKeys.LaunchIsSetTargetFrameRateEnabled, true); } [field: MaybeNull] - public IObservableProperty TargetFps { get => field ??= CreateProperty(SettingKeys.LaunchTargetFps, InitializeTargetFpsWithScreenFps); } + public IObservableProperty TargetFps { get => field ??= CreateProperty(SettingKeys.LaunchTargetFps, InitializeTargetFpsWithScreenFps).WithValueChangedCallback(OnTargetFpsChanged); } [field: MaybeNull] public IObservableProperty RemoveOpenTeamProgress { get => field ??= CreateProperty(SettingKeys.LaunchRemoveOpenTeamProgress, false); } @@ -165,6 +167,98 @@ internal sealed partial class LaunchOptions : DbStoreOptions, IRestrictedGamePat return HutaoNative.Instance.MakeDeviceCapabilities().GetPrimaryScreenVerticalRefreshRate(); } + private static void OnTargetFpsChanged(int newFps) + { + // 异步更新配置文件,避免阻塞UI线程 + Task.Run(async () => + { + try + { + string configPath = Path.Combine(AppContext.BaseDirectory, "fps_config.ini"); + + + if (File.Exists(configPath)) + { + string[] lines = await File.ReadAllLinesAsync(configPath).ConfigureAwait(false); + bool needsUpdate = true; + + + foreach (string line in lines) + { + if (line.StartsWith("FPS=")) + { + int configFps = int.Parse(line.Substring(4)); + if (configFps == newFps) + { + needsUpdate = false; + } + break; + } + } + + // 更新配置文件 + if (needsUpdate) + { + for (int i = 0; i < lines.Length; i++) + { + if (lines[i].StartsWith("FPS=")) + { + lines[i] = $"FPS={newFps}"; + break; + } + } + + + for (int i = 0; i < 3; i++) + { + try + { + await File.WriteAllLinesAsync(configPath, lines).ConfigureAwait(false); + SentrySdk.AddBreadcrumb( + $"Updated fps_config.ini with new FPS: {newFps}", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Info); + break; + } + catch (UnauthorizedAccessException) + { + if (i == 2) + { + SentrySdk.AddBreadcrumb( + $"无法写入配置文件 {configPath},请检查权限", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Error); + return; + } + await Task.Delay(500).ConfigureAwait(false); + } + catch (IOException) + { + if (i == 2) + { + SentrySdk.AddBreadcrumb( + $"无法写入配置文件 {configPath},文件可能被占用", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Error); + return; + } + await Task.Delay(500).ConfigureAwait(false); + } + } + } + } + } + catch (Exception ex) + { + // 记录错误 + SentrySdk.AddBreadcrumb( + $"Failed to update fps_config.ini: {ex.Message}", + category: "fps.unlocker", + level: Sentry.BreadcrumbLevel.Warning); + } + }); + } + private static ImmutableArray> InitializeMonitors() { ImmutableArray>.Builder monitors = ImmutableArray.CreateBuilder>(); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameIslandHandler.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameIslandHandler.cs index 8f91374..00a3c38 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameIslandHandler.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameIslandHandler.cs @@ -8,10 +8,10 @@ using Snap.Hutao.Service.Notification; namespace Snap.Hutao.Service.Game.Launching.Handler; -internal sealed class LaunchExecutionGameIslandHandler : AbstractLaunchExecutionHandler +internal sealed class LaunchExecutionGameIslandHandler : AbstractLaunchExecutionHandler, IDisposable { private readonly bool resume; - private GameIslandInterop? interop; + private GameFpsUnlockInterop? interop; public LaunchExecutionGameIslandHandler(bool resume) { @@ -63,4 +63,9 @@ internal sealed class LaunchExecutionGameIslandHandler : AbstractLaunchExecution GameLifeCycle.IsIslandConnected.Value = false; } } + + public void Dispose() + { + interop?.Dispose(); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameProcessStartHandler.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameProcessStartHandler.cs index 41268d4..44fb52f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameProcessStartHandler.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameProcessStartHandler.cs @@ -26,6 +26,14 @@ internal sealed class LaunchExecutionGameProcessStartHandler : AbstractLaunchExe public override async ValueTask ExecuteAsync(LaunchExecutionContext context) { + // 如果启用了Island(FPS解锁),则跳过启动游戏进程 + // 因为unlockfps.exe会负责启动游戏 + if (context.LaunchOptions.IsIslandEnabled.Value) + { + context.Progress.Report(new(SH.ServiceGameLaunchPhaseProcessStarted)); + return; + } + try { context.Process.Start(); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Invoker/AbstractLaunchExecutionInvoker.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Invoker/AbstractLaunchExecutionInvoker.cs index 3d54608..7e649e9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Invoker/AbstractLaunchExecutionInvoker.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Invoker/AbstractLaunchExecutionInvoker.cs @@ -4,6 +4,7 @@ using Snap.Hutao.Core.Diagnostics; using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Factory.Progress; +using Snap.Hutao.Factory.Process; using Snap.Hutao.Service.Game.FileSystem; using Snap.Hutao.Service.Game.Launching.Context; using Snap.Hutao.Service.Game.Launching.Handler; @@ -100,9 +101,16 @@ internal abstract class AbstractLaunchExecutionInvoker fileSystemReference.Exchange(beforeContext.FileSystem); - using (IProcess? process = CreateProcess(beforeContext)) + // unlockfps.exe会负责启动游戏 + IProcess? process = null; + if (!beforeContext.LaunchOptions.IsIslandEnabled.Value) { - if (process is null) + process = CreateProcess(beforeContext); + } + + using (process) + { + if (process is null && !beforeContext.LaunchOptions.IsIslandEnabled.Value) { return; } @@ -114,7 +122,7 @@ internal abstract class AbstractLaunchExecutionInvoker TaskContext = taskContext, Messenger = context.ServiceProvider.GetRequiredService(), LaunchOptions = context.LaunchOptions, - Process = process, + Process = process ?? new NullProcess(), IsOversea = targetScheme.IsOversea, }; @@ -123,7 +131,8 @@ internal abstract class AbstractLaunchExecutionInvoker await handler.ExecuteAsync(executionContext).ConfigureAwait(false); } - if (process.IsRunning) + // 只有在没有启用Island且进程存在时才等待退出 + if (process is { IsRunning: true }) { progress.Report(new(SH.ServiceGameLaunchPhaseWaitingProcessExit)); try @@ -139,6 +148,12 @@ internal abstract class AbstractLaunchExecutionInvoker return; } } + else if (beforeContext.LaunchOptions.IsIslandEnabled.Value) + { + progress.Report(new(SH.ServiceGameLaunchPhaseWaitingProcessExit)); + await taskContext.SwitchToBackgroundAsync(); + await Task.Delay(30000).ConfigureAwait(false); + } } progress.Report(new(SH.ServiceGameLaunchPhaseProcessExited)); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Invoker/DefaultLaunchExecutionInvoker.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Invoker/DefaultLaunchExecutionInvoker.cs index 03d65b1..7a098c5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Invoker/DefaultLaunchExecutionInvoker.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Invoker/DefaultLaunchExecutionInvoker.cs @@ -16,8 +16,8 @@ internal sealed class DefaultLaunchExecutionInvoker : AbstractLaunchExecutionInv new LaunchExecutionGameResourceHandler(convertOnly: false), new LaunchExecutionGameIdentityHandler(), new LaunchExecutionWindowsHDRHandler(), - new LaunchExecutionGameProcessStartHandler(), new LaunchExecutionGameIslandHandler(resume: false), + new LaunchExecutionGameProcessStartHandler(), new LaunchExecutionOverlayHandler(), new LaunchExecutionStarwardPlayTimeStatisticsHandler(), new LaunchExecutionBetterGenshinImpactAutomationHandler() diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index 8cbe51d..c16c400 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -11,7 +11,7 @@ true False - 1.17.4.0 + 1.18.0.0 False False @@ -71,6 +71,14 @@ + + + + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/LaunchGamePage.xaml b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/LaunchGamePage.xaml index d5a68d9..3d8323b 100644 --- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/LaunchGamePage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/LaunchGamePage.xaml @@ -641,30 +641,31 @@ Grid.Row="0" Grid.Column="0" Header="{shuxm:ResourceString Name=ViewPageLaunchGameTargetFovHotSwitchHeader}" - IsOn="{Binding LaunchOptions.IsSetFieldOfViewEnabled.Value, Mode=TwoWay}" - ToolTipService.ToolTip="{shuxm:ResourceString Name=ViewPageLaunchGameHotSwitchDescription}"/> + IsEnabled="False" + IsOn="False" + ToolTipService.ToolTip=""/> + ToolTipService.ToolTip="" + Value="45"/> + ToolTipService.ToolTip=""/> - + + + + + + + + + IsEnabled="False" + IsOn="False" + ToolTipService.ToolTip=""> @@ -756,10 +763,11 @@ x:Name="HideQuestBannerToggleSwitch" Grid.Row="2" Grid.Column="0" - IsOn="{Binding LaunchOptions.HideQuestBanner.Value, Mode=TwoWay}" + IsEnabled="False" + IsOn="False" OffContent="{shuxm:ResourceString Name=ViewPageLaunchGameDisableFogOff}" OnContent="{shuxm:ResourceString Name=ViewPageLaunchGameDisableFogOn}" - ToolTipService.ToolTip="{shuxm:ResourceString Name=ViewPageLaunchGameHotSwitchDescription}"> + ToolTipService.ToolTip=""> @@ -798,34 +806,38 @@ Grid.Row="2" Grid.Column="1" Header="{shuxm:ResourceString Name=ViewPageLaunchGameRemoveOpenTeamProgressHeader}" - IsOn="{Binding LaunchOptions.RemoveOpenTeamProgress.Value, Mode=TwoWay}" + IsEnabled="False" + IsOn="False" OffContent="{shuxm:ResourceString Name=ViewPageLaunchGameDisableFogOff}" OnContent="{shuxm:ResourceString Name=ViewPageLaunchGameDisableFogOn}" - ToolTipService.ToolTip="{shuxm:ResourceString Name=ViewPageLaunchGameRemoveOpenTeamProgressDescription}"/> + ToolTipService.ToolTip=""/> + ToolTipService.ToolTip=""/> + ToolTipService.ToolTip=""/> + ToolTipService.ToolTip=""> @@ -867,35 +879,46 @@ Grid.Row="3" Grid.Column="2" Header="{shuxm:ResourceString Name=ViewPageLaunchGameIslandUsingTouchScreenHeader}" - IsEnabled="{Binding LaunchOptions.IsGameRunning.Value, Converter={StaticResource BoolNegationConverter}}" - IsOn="{Binding LaunchOptions.UsingTouchScreen.Value, Mode=TwoWay}"/> + IsEnabled="False" + IsOn="False" + ToolTipService.ToolTip=""/> + IsEnabled="False" + IsOn="False" + ToolTipService.ToolTip=""/> + IsEnabled="False" + IsOn="False" + ToolTipService.ToolTip=""/> + IsEnabled="False" + IsOn="False" + ToolTipService.ToolTip=""/> + IsEnabled="False" + IsOn="False" + ToolTipService.ToolTip=""/> + IsEnabled="False" + IsOn="False" + ToolTipService.ToolTip=""/>