From c0980fabe8eafe350bdb2792c190532aa02e2ff7 Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Sun, 5 Nov 2023 16:03:10 +0800 Subject: [PATCH] impl #1071 --- .../Snap.Hutao/Core/Threading/ITaskContext.cs | 2 +- .../Snap.Hutao/Core/Threading/TaskContext.cs | 4 +- .../ContentDialogFactory.cs | 17 ++-- .../IContentDialogFactory.cs | 8 +- .../{Abstraction => Picker}/IPickerFactory.cs | 2 +- .../Factory/{ => Picker}/PickerFactory.cs | 14 ++-- .../Factory/Progress/IProgressFactory.cs | 6 ++ .../Factory/Progress/ProgressFactory.cs | 19 +++++ .../Model/Entity/SettingEntry.Constant.cs | 2 + .../Snap.Hutao/Resource/Localization/SH.resx | 9 +++ .../Snap.Hutao/Service/AppOptions.cs | 2 + .../Snap.Hutao/Service/AppOptionsExtension.cs | 42 ++++++++++ .../GachaLogQueryManualInputProvider.cs | 2 +- .../Game/Account/GameAccountService.cs | 4 +- .../Service/Game/Account/RegistryInterop.cs | 2 +- .../Service/Game/GameServiceFacade.cs | 1 + .../Snap.Hutao/Service/Game/LaunchOptions.cs | 7 ++ .../Service/Game/Locator/ManualGameLocator.cs | 2 +- .../Game/Package/GamePackageService.cs | 8 +- .../Game/{ => Process}/GameProcessService.cs | 39 +++++---- .../Game/{ => Process}/IGameProcessService.cs | 2 +- .../Service/Game/Process/Starward.cs | 19 +++++ .../Service/Game/Scheme/LaunchScheme.cs | 10 +++ .../Service/Game/Unlocker/GameFpsUnlocker.cs | 10 +-- .../Service/Hutao/HutaoAsAService.cs | 6 +- src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj | 2 +- src/Snap.Hutao/Snap.Hutao/View/MainView.xaml | 2 +- .../Snap.Hutao/View/Page/LaunchGamePage.xaml | 13 +++ .../Achievement/AchievementImporter.cs | 3 +- .../Achievement/AchievementViewModel.cs | 3 +- .../AvatarProperty/AvatarPropertyViewModel.cs | 2 +- .../Cultivation/CultivationViewModel.cs | 2 +- .../ViewModel/DailyNote/DailyNoteViewModel.cs | 2 +- .../ViewModel/GachaLog/GachaLogViewModel.cs | 9 ++- .../ViewModel/GachaLog/HutaoCloudViewModel.cs | 2 +- .../ViewModel/Game/LaunchGameViewModel.cs | 81 ++++++++++--------- .../Setting/HutaoPassportViewModel.cs | 2 +- .../ViewModel/Setting/SettingViewModel.cs | 5 +- .../ViewModel/User/UserViewModel.cs | 2 +- .../ViewModel/Wiki/WikiAvatarViewModel.cs | 2 +- .../ViewModel/Wiki/WikiWeaponViewModel.cs | 2 +- 41 files changed, 257 insertions(+), 116 deletions(-) rename src/Snap.Hutao/Snap.Hutao/Factory/{ => ContentDialog}/ContentDialogFactory.cs (84%) rename src/Snap.Hutao/Snap.Hutao/Factory/{Abstraction => ContentDialog}/IContentDialogFactory.cs (81%) rename src/Snap.Hutao/Snap.Hutao/Factory/{Abstraction => Picker}/IPickerFactory.cs (97%) rename src/Snap.Hutao/Snap.Hutao/Factory/{ => Picker}/PickerFactory.cs (85%) create mode 100644 src/Snap.Hutao/Snap.Hutao/Factory/Progress/IProgressFactory.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Factory/Progress/ProgressFactory.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/AppOptionsExtension.cs rename src/Snap.Hutao/Snap.Hutao/Service/Game/{ => Process}/GameProcessService.cs (67%) rename src/Snap.Hutao/Snap.Hutao/Service/Game/{ => Process}/IGameProcessService.cs (83%) create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Game/Process/Starward.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ITaskContext.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ITaskContext.cs index ab389d0e..10cf42bb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/ITaskContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/ITaskContext.cs @@ -8,7 +8,7 @@ namespace Snap.Hutao.Core.Threading; /// internal interface ITaskContext { - IProgress CreateProgressForMainThread(Action handler); + SynchronizationContext GetSynchronizationContext(); /// /// 在主线程上同步等待执行操作 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskContext.cs b/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskContext.cs index d8aee9cd..44d97e0e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskContext.cs @@ -42,8 +42,8 @@ internal sealed class TaskContext : ITaskContext dispatcherQueue.Invoke(action); } - public IProgress CreateProgressForMainThread(Action handler) + public SynchronizationContext GetSynchronizationContext() { - return new DispatcherQueueProgress(handler, synchronizationContext); + return synchronizationContext; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/ContentDialogFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/ContentDialog/ContentDialogFactory.cs similarity index 84% rename from src/Snap.Hutao/Snap.Hutao/Factory/ContentDialogFactory.cs rename to src/Snap.Hutao/Snap.Hutao/Factory/ContentDialog/ContentDialogFactory.cs index d71f0964..ccc736c8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Factory/ContentDialogFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Factory/ContentDialog/ContentDialogFactory.cs @@ -3,9 +3,8 @@ using Microsoft.UI.Xaml.Controls; using Snap.Hutao.Core.LifeCycle; -using Snap.Hutao.Factory.Abstraction; -namespace Snap.Hutao.Factory; +namespace Snap.Hutao.Factory.ContentDialog; /// [HighQuality] @@ -13,15 +12,15 @@ namespace Snap.Hutao.Factory; [Injection(InjectAs.Singleton, typeof(IContentDialogFactory))] internal sealed partial class ContentDialogFactory : IContentDialogFactory { + private readonly ICurrentWindowReference currentWindowReference; private readonly IServiceProvider serviceProvider; private readonly ITaskContext taskContext; - private readonly ICurrentWindowReference currentWindowReference; /// public async ValueTask CreateForConfirmAsync(string title, string content) { await taskContext.SwitchToMainThreadAsync(); - ContentDialog dialog = new() + Microsoft.UI.Xaml.Controls.ContentDialog dialog = new() { XamlRoot = currentWindowReference.GetXamlRoot(), Title = title, @@ -37,7 +36,7 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory public async ValueTask CreateForConfirmCancelAsync(string title, string content, ContentDialogButton defaultButton = ContentDialogButton.Close) { await taskContext.SwitchToMainThreadAsync(); - ContentDialog dialog = new() + Microsoft.UI.Xaml.Controls.ContentDialog dialog = new() { XamlRoot = currentWindowReference.GetXamlRoot(), Title = title, @@ -51,10 +50,10 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory } /// - public async ValueTask CreateForIndeterminateProgressAsync(string title) + public async ValueTask CreateForIndeterminateProgressAsync(string title) { await taskContext.SwitchToMainThreadAsync(); - ContentDialog dialog = new() + Microsoft.UI.Xaml.Controls.ContentDialog dialog = new() { XamlRoot = currentWindowReference.GetXamlRoot(), Title = title, @@ -65,7 +64,7 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory } public async ValueTask CreateInstanceAsync(params object[] parameters) - where TContentDialog : ContentDialog + where TContentDialog : Microsoft.UI.Xaml.Controls.ContentDialog { await taskContext.SwitchToMainThreadAsync(); TContentDialog contentDialog = serviceProvider.CreateInstance(parameters); @@ -74,7 +73,7 @@ internal sealed partial class ContentDialogFactory : IContentDialogFactory } public TContentDialog CreateInstance(params object[] parameters) - where TContentDialog : ContentDialog + where TContentDialog : Microsoft.UI.Xaml.Controls.ContentDialog { TContentDialog contentDialog = serviceProvider.CreateInstance(parameters); contentDialog.XamlRoot = currentWindowReference.GetXamlRoot(); diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/Abstraction/IContentDialogFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/ContentDialog/IContentDialogFactory.cs similarity index 81% rename from src/Snap.Hutao/Snap.Hutao/Factory/Abstraction/IContentDialogFactory.cs rename to src/Snap.Hutao/Snap.Hutao/Factory/ContentDialog/IContentDialogFactory.cs index b09c2f6f..00c434c3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Factory/Abstraction/IContentDialogFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Factory/ContentDialog/IContentDialogFactory.cs @@ -3,7 +3,7 @@ using Microsoft.UI.Xaml.Controls; -namespace Snap.Hutao.Factory.Abstraction; +namespace Snap.Hutao.Factory.ContentDialog; /// /// 内容对话框工厂 @@ -33,11 +33,11 @@ internal interface IContentDialogFactory /// /// 标题 /// 内容对话框 - ValueTask CreateForIndeterminateProgressAsync(string title); + ValueTask CreateForIndeterminateProgressAsync(string title); TContentDialog CreateInstance(params object[] parameters) - where TContentDialog : ContentDialog; + where TContentDialog : Microsoft.UI.Xaml.Controls.ContentDialog; ValueTask CreateInstanceAsync(params object[] parameters) - where TContentDialog : ContentDialog; + where TContentDialog : Microsoft.UI.Xaml.Controls.ContentDialog; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/Abstraction/IPickerFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/Picker/IPickerFactory.cs similarity index 97% rename from src/Snap.Hutao/Snap.Hutao/Factory/Abstraction/IPickerFactory.cs rename to src/Snap.Hutao/Snap.Hutao/Factory/Picker/IPickerFactory.cs index 7252d9c0..353c6146 100644 --- a/src/Snap.Hutao/Snap.Hutao/Factory/Abstraction/IPickerFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Factory/Picker/IPickerFactory.cs @@ -3,7 +3,7 @@ using Windows.Storage.Pickers; -namespace Snap.Hutao.Factory.Abstraction; +namespace Snap.Hutao.Factory.Picker; /// /// 文件选择器工厂 diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/PickerFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/Picker/PickerFactory.cs similarity index 85% rename from src/Snap.Hutao/Snap.Hutao/Factory/PickerFactory.cs rename to src/Snap.Hutao/Snap.Hutao/Factory/Picker/PickerFactory.cs index bd177eb6..4000235b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Factory/PickerFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Factory/Picker/PickerFactory.cs @@ -4,11 +4,10 @@ using Snap.Hutao.Core; using Snap.Hutao.Core.LifeCycle; using Snap.Hutao.Core.Windowing; -using Snap.Hutao.Factory.Abstraction; using Windows.Storage.Pickers; using WinRT.Interop; -namespace Snap.Hutao.Factory; +namespace Snap.Hutao.Factory.Picker; /// [HighQuality] @@ -18,7 +17,7 @@ internal sealed partial class PickerFactory : IPickerFactory { private const string AnyType = "*"; - private readonly ICurrentWindowReference currentWindow; + private readonly ICurrentWindowReference currentWindowReference; /// public FileOpenPicker GetFileOpenPicker(PickerLocationId location, string commitButton, params string[] fileTypes) @@ -80,10 +79,11 @@ internal sealed partial class PickerFactory : IPickerFactory { // Create a folder picker. T picker = new(); - if (currentWindow.Window is IWindowOptionsSource optionsSource) - { - InitializeWithWindow.Initialize(picker, optionsSource.WindowOptions.Hwnd); - } + nint hwnd = currentWindowReference.Window is IWindowOptionsSource optionsSource + ? (nint)optionsSource.WindowOptions.Hwnd + : WindowNative.GetWindowHandle(currentWindowReference.Window); + + InitializeWithWindow.Initialize(picker, hwnd); return picker; } diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/Progress/IProgressFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/Progress/IProgressFactory.cs new file mode 100644 index 00000000..016c2235 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Factory/Progress/IProgressFactory.cs @@ -0,0 +1,6 @@ +namespace Snap.Hutao.Factory.Progress; + +internal interface IProgressFactory +{ + IProgress CreateForMainThread(Action handler); +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Factory/Progress/ProgressFactory.cs b/src/Snap.Hutao/Snap.Hutao/Factory/Progress/ProgressFactory.cs new file mode 100644 index 00000000..197845e9 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Factory/Progress/ProgressFactory.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Snap.Hutao.Factory.Progress; + +[ConstructorGenerated] +[Injection(InjectAs.Transient, typeof(IProgressFactory))] +internal sealed partial class ProgressFactory : IProgressFactory +{ + private readonly ITaskContext taskContext; + + public IProgress CreateForMainThread(Action handler) + { + return new DispatcherQueueProgress(handler, taskContext.GetSynchronizationContext()); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.Constant.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.Constant.cs index 4c0b1799..b6e00850 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.Constant.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/SettingEntry.Constant.cs @@ -104,6 +104,8 @@ internal sealed partial class SettingEntry public const string LaunchIsMonitorEnabled = "Launch.IsMonitorEnabled"; + public const string LaunchUseStarwardPlayTimeStatistics = "Launch.UseStarwardPlayTimeStatistics"; + /// /// 启动游戏 多倍启动 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index 5f1db962..643e811e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -2021,6 +2021,9 @@ 文件 + + 进程间 + 在指定的显示器上运行 @@ -2036,6 +2039,12 @@ 游戏选项 + + 在游戏启动后尝试启动并使用 Starward 进行游戏时长统计 + + + 时长统计 + 进程 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AppOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/AppOptions.cs index b51db023..3e9834e3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AppOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AppOptions.cs @@ -106,6 +106,8 @@ internal sealed partial class AppOptions : DbStoreOptions /// /// 是否启用高级功能 + /// DO NOT MOVE TO OTHER CLASS + /// We are binding this property in SettingPage /// public bool IsAdvancedLaunchOptionsEnabled { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AppOptionsExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/AppOptionsExtension.cs new file mode 100644 index 00000000..07fccf2f --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/AppOptionsExtension.cs @@ -0,0 +1,42 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using System.IO; + +namespace Snap.Hutao.Service; + +internal static class AppOptionsExtension +{ + public static bool TryGetGameFolderAndFileName(this AppOptions appOptions, [NotNullWhen(true)] out string? gameFolder, [NotNullWhen(true)] out string? gameFileName) + { + string gamePath = appOptions.GamePath; + + gameFolder = Path.GetDirectoryName(gamePath); + if (string.IsNullOrEmpty(gameFolder)) + { + gameFileName = default; + return false; + } + + gameFileName = Path.GetFileName(gamePath); + if (string.IsNullOrEmpty(gameFileName)) + { + return false; + } + + return true; + } + + public static bool TryGetGameFileName(this AppOptions appOptions, [NotNullWhen(true)] out string? gameFileName) + { + string gamePath = appOptions.GamePath; + + gameFileName = Path.GetFileName(gamePath); + if (string.IsNullOrEmpty(gameFileName)) + { + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryManualInputProvider.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryManualInputProvider.cs index 9c797a72..2a2bbc38 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryManualInputProvider.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/QueryProvider/GachaLogQueryManualInputProvider.cs @@ -1,7 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Service.Metadata; using Snap.Hutao.View.Dialog; using Snap.Hutao.Web.Request.QueryString; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/GameAccountService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/GameAccountService.cs index ff717fab..bc5884ca 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/GameAccountService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/GameAccountService.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Core.ExceptionService; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Model.Entity; using Snap.Hutao.View.Dialog; using System.Collections.ObjectModel; @@ -45,8 +45,6 @@ internal sealed partial class GameAccountService : IGameAccountService if (account is null) { - // ContentDialog must be created by main thread. - await taskContext.SwitchToMainThreadAsync(); LaunchGameAccountNameDialog dialog = await contentDialogFactory.CreateInstanceAsync().ConfigureAwait(false); (bool isOk, string name) = await dialog.GetInputNameAsync().ConfigureAwait(false); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/RegistryInterop.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/RegistryInterop.cs index 29e8d129..513fb4a2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/RegistryInterop.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Account/RegistryInterop.cs @@ -55,7 +55,7 @@ internal static class RegistryInterop try { - Process.Start(startInfo)?.WaitForExit(); + System.Diagnostics.Process.Start(startInfo)?.WaitForExit(); } catch (Win32Exception ex) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameServiceFacade.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameServiceFacade.cs index 0de8977b..cb20776b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameServiceFacade.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameServiceFacade.cs @@ -5,6 +5,7 @@ using Snap.Hutao.Model.Entity; using Snap.Hutao.Service.Game.Account; using Snap.Hutao.Service.Game.Configuration; using Snap.Hutao.Service.Game.Package; +using Snap.Hutao.Service.Game.Process; using Snap.Hutao.Service.Game.Scheme; using System.Collections.ObjectModel; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs index 74c72f2b..28d1e743 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptions.cs @@ -37,6 +37,7 @@ internal sealed class LaunchOptions : DbStoreOptions private NameValue? monitor; private bool? isMonitorEnabled; private AspectRatio? selectedAspectRatio; + private bool? useStarwardPlayTimeStatistics; /// /// 构造一个新的启动游戏选项 @@ -183,6 +184,12 @@ internal sealed class LaunchOptions : DbStoreOptions } } + public bool UseStarwardPlayTimeStatistics + { + get => GetOption(ref useStarwardPlayTimeStatistics, SettingEntry.LaunchUseStarwardPlayTimeStatistics, false); + set => SetOption(ref useStarwardPlayTimeStatistics, SettingEntry.LaunchUseStarwardPlayTimeStatistics, value); + } + private static void InitializeMonitors(List> monitors) { // This list can't use foreach diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/ManualGameLocator.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/ManualGameLocator.cs index 7f281662..8e8ec8db 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/ManualGameLocator.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Locator/ManualGameLocator.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Core.IO; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.Picker; using Windows.Storage.Pickers; namespace Snap.Hutao.Service.Game.Locator; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/GamePackageService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/GamePackageService.cs index 831e1c5c..77b99c2b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/GamePackageService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/GamePackageService.cs @@ -20,10 +20,10 @@ internal sealed partial class GamePackageService : IGamePackageService public async ValueTask EnsureGameResourceAsync(LaunchScheme launchScheme, IProgress progress) { - string gamePath = appOptions.GamePath; - string? gameFolder = Path.GetDirectoryName(gamePath); - ArgumentException.ThrowIfNullOrEmpty(gameFolder); - string gameFileName = Path.GetFileName(gamePath); + if (!appOptions.TryGetGameFolderAndFileName(out string? gameFolder, out string? gameFileName)) + { + return false; + } progress.Report(new(SH.ServiceGameEnsureGameResourceQueryResourceInformation)); Response response = await serviceProvider diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameProcessService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Process/GameProcessService.cs similarity index 67% rename from src/Snap.Hutao/Snap.Hutao/Service/Game/GameProcessService.cs rename to src/Snap.Hutao/Snap.Hutao/Service/Game/Process/GameProcessService.cs index dc3e07ec..46d51181 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameProcessService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Process/GameProcessService.cs @@ -2,12 +2,13 @@ // Licensed under the MIT license. using Snap.Hutao.Core; +using Snap.Hutao.Service.Game.Scheme; using Snap.Hutao.Service.Game.Unlocker; -using System.Diagnostics; using System.IO; +using Windows.System; using static Snap.Hutao.Service.Game.GameConstants; -namespace Snap.Hutao.Service.Game; +namespace Snap.Hutao.Service.Game.Process; /// /// 进程互操作 @@ -30,8 +31,8 @@ internal sealed partial class GameProcessService : IGameProcessService return false; } - return Process.GetProcessesByName(YuanShenProcessName).Any() - || Process.GetProcessesByName(GenshinImpactProcessName).Any(); + return System.Diagnostics.Process.GetProcessesByName(YuanShenProcessName).Any() + || System.Diagnostics.Process.GetProcessesByName(GenshinImpactProcessName).Any(); } public async ValueTask LaunchAsync(IProgress progress) @@ -45,7 +46,7 @@ internal sealed partial class GameProcessService : IGameProcessService ArgumentException.ThrowIfNullOrEmpty(gamePath); progress.Report(new(LaunchPhase.ProcessInitializing, SH.ServiceGameLaunchPhaseProcessInitializing)); - using (Process game = InitializeGameProcess(launchOptions, gamePath)) + using (System.Diagnostics.Process game = InitializeGameProcess(gamePath)) { try { @@ -53,12 +54,18 @@ internal sealed partial class GameProcessService : IGameProcessService game.Start(); progress.Report(new(LaunchPhase.ProcessStarted, SH.ServiceGameLaunchPhaseProcessStarted)); + if (launchOptions.UseStarwardPlayTimeStatistics && appOptions.TryGetGameFileName(out string? gameFileName)) + { + bool isOversea = LaunchScheme.ExecutableIsOversea(gameFileName); + await Starward.LaunchForPlayTimeStatisticsAsync(isOversea).ConfigureAwait(false); + } + if (runtimeOptions.IsElevated && appOptions.IsAdvancedLaunchOptionsEnabled && launchOptions.UnlockFps) { progress.Report(new(LaunchPhase.UnlockingFps, SH.ServiceGameLaunchPhaseUnlockingFps)); try { - await UnlockFpsAsync(serviceProvider, game, progress).ConfigureAwait(false); + await UnlockFpsAsync(game, progress).ConfigureAwait(false); } catch (InvalidOperationException) { @@ -85,23 +92,23 @@ internal sealed partial class GameProcessService : IGameProcessService } } - private static Process InitializeGameProcess(LaunchOptions options, string gamePath) + private System.Diagnostics.Process InitializeGameProcess(string gamePath) { string commandLine = string.Empty; - if (options.IsEnabled) + if (launchOptions.IsEnabled) { - Must.Argument(!(options.IsBorderless && options.IsExclusive), "无边框与独占全屏选项无法同时生效"); + Must.Argument(!(launchOptions.IsBorderless && launchOptions.IsExclusive), "无边框与独占全屏选项无法同时生效"); // https://docs.unity.cn/cn/current/Manual/PlayerCommandLineArguments.html // https://docs.unity3d.com/2017.4/Documentation/Manual/CommandLineArguments.html commandLine = new CommandLineBuilder() - .AppendIf("-popupwindow", options.IsBorderless) - .AppendIf("-window-mode", options.IsExclusive, "exclusive") - .Append("-screen-fullscreen", options.IsFullScreen ? 1 : 0) - .AppendIf("-screen-width", options.IsScreenWidthEnabled, options.ScreenWidth) - .AppendIf("-screen-height", options.IsScreenHeightEnabled, options.ScreenHeight) - .AppendIf("-monitor", options.IsMonitorEnabled, options.Monitor.Value) + .AppendIf("-popupwindow", launchOptions.IsBorderless) + .AppendIf("-window-mode", launchOptions.IsExclusive, "exclusive") + .Append("-screen-fullscreen", launchOptions.IsFullScreen ? 1 : 0) + .AppendIf("-screen-width", launchOptions.IsScreenWidthEnabled, launchOptions.ScreenWidth) + .AppendIf("-screen-height", launchOptions.IsScreenHeightEnabled, launchOptions.ScreenHeight) + .AppendIf("-monitor", launchOptions.IsMonitorEnabled, launchOptions.Monitor.Value) .ToString(); } @@ -118,7 +125,7 @@ internal sealed partial class GameProcessService : IGameProcessService }; } - private static ValueTask UnlockFpsAsync(IServiceProvider serviceProvider, Process game, IProgress progress, CancellationToken token = default) + private ValueTask UnlockFpsAsync(System.Diagnostics.Process game, IProgress progress, CancellationToken token = default) { IGameFpsUnlocker unlocker = serviceProvider.CreateInstance(game); UnlockTimingOptions options = new(100, 20000, 3000); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameProcessService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Process/IGameProcessService.cs similarity index 83% rename from src/Snap.Hutao/Snap.Hutao/Service/Game/IGameProcessService.cs rename to src/Snap.Hutao/Snap.Hutao/Service/Game/Process/IGameProcessService.cs index d2c08c07..2f39d442 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/IGameProcessService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Process/IGameProcessService.cs @@ -1,7 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -namespace Snap.Hutao.Service.Game; +namespace Snap.Hutao.Service.Game.Process; internal interface IGameProcessService { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Process/Starward.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Process/Starward.cs new file mode 100644 index 00000000..1a827666 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Process/Starward.cs @@ -0,0 +1,19 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Windows.System; + +namespace Snap.Hutao.Service.Game.Process; + +internal static class Starward +{ + public static async ValueTask LaunchForPlayTimeStatisticsAsync(bool isOversea) + { + string gameBiz = isOversea ? "hk4e_global" : "hk4e_cn"; + Uri starwardPlayTimeUri = $"starward://playtime/{gameBiz}".ToUri(); + if (await Launcher.QueryUriSupportAsync(starwardPlayTimeUri, LaunchQuerySupportType.Uri) is LaunchQuerySupportStatus.Available) + { + await Launcher.LaunchUriAsync(starwardPlayTimeUri); + } + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Scheme/LaunchScheme.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Scheme/LaunchScheme.cs index 69e5698a..f2bf764f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Scheme/LaunchScheme.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Scheme/LaunchScheme.cs @@ -57,6 +57,16 @@ internal class LaunchScheme public bool IsNotCompatOnly { get; private protected set; } = true; + public static bool ExecutableIsOversea(string gameFileName) + { + return gameFileName switch + { + GameConstants.GenshinImpactFileName => true, + GameConstants.YuanShenFileName => false, + _ => throw Requires.Fail("无效的游戏可执行文件名称:{0}", gameFileName), + }; + } + /// /// 多通道相等 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs index 21bba708..e36f515f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Unlocker/GameFpsUnlocker.cs @@ -19,7 +19,7 @@ namespace Snap.Hutao.Service.Game.Unlocker; [HighQuality] internal sealed class GameFpsUnlocker : IGameFpsUnlocker { - private readonly Process gameProcess; + private readonly System.Diagnostics.Process gameProcess; private readonly LaunchOptions launchOptions; private readonly UnlockerStatus status = new(); @@ -33,7 +33,7 @@ internal sealed class GameFpsUnlocker : IGameFpsUnlocker /// /// 服务提供器 /// 游戏进程 - public GameFpsUnlocker(IServiceProvider serviceProvider, Process gameProcess) + public GameFpsUnlocker(IServiceProvider serviceProvider, System.Diagnostics.Process gameProcess) { launchOptions = serviceProvider.GetRequiredService(); this.gameProcess = gameProcess; @@ -57,7 +57,7 @@ internal sealed class GameFpsUnlocker : IGameFpsUnlocker await LoopAdjustFpsAsync(options.AdjustFpsDelay, progress, token).ConfigureAwait(false); } - private static unsafe bool UnsafeReadModulesMemory(Process process, in GameModule moduleEntryInfo, out VirtualMemory memory) + private static unsafe bool UnsafeReadModulesMemory(System.Diagnostics.Process process, in GameModule moduleEntryInfo, out VirtualMemory memory) { ref readonly Module unityPlayer = ref moduleEntryInfo.UnityPlayer; ref readonly Module userAssembly = ref moduleEntryInfo.UserAssembly; @@ -68,7 +68,7 @@ internal sealed class GameFpsUnlocker : IGameFpsUnlocker && ReadProcessMemory((HANDLE)process.Handle, (void*)userAssembly.Address, lpBuffer + unityPlayer.Size, userAssembly.Size); } - private static unsafe bool UnsafeReadProcessMemory(Process process, nuint baseAddress, out nuint value) + private static unsafe bool UnsafeReadProcessMemory(System.Diagnostics.Process process, nuint baseAddress, out nuint value) { ulong temp = 0; bool result = ReadProcessMemory((HANDLE)process.Handle, (void*)baseAddress, (byte*)&temp, 8); @@ -78,7 +78,7 @@ internal sealed class GameFpsUnlocker : IGameFpsUnlocker return result; } - private static unsafe bool UnsafeWriteProcessMemory(Process process, nuint baseAddress, int value) + private static unsafe bool UnsafeWriteProcessMemory(System.Diagnostics.Process process, nuint baseAddress, int value) { return WriteProcessMemory((HANDLE)process.Handle, (void*)baseAddress, &value, sizeof(int)); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoAsAService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoAsAService.cs index 0f8579c7..dddc3381 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoAsAService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Hutao/HutaoAsAService.cs @@ -29,11 +29,11 @@ internal sealed partial class HutaoAsAService : IHutaoAsAService ApplicationDataCompositeValue excludedIds = LocalSetting.Get(SettingKeys.ExcludedAnnouncementIds, new ApplicationDataCompositeValue()); List data = excludedIds.Select(kvp => long.Parse(kvp.Key, CultureInfo.InvariantCulture)).ToList(); - Response> respose = await hutaoAsServiceClient.GetAnnouncementListAsync(data, token).ConfigureAwait(false); + Response> response = await hutaoAsServiceClient.GetAnnouncementListAsync(data, token).ConfigureAwait(false); - if (respose.IsOk()) + if (response.IsOk()) { - List list = respose.Data; + List list = response.Data; list.ForEach(item => item.DismissCommand = dismissCommand); announcements = list.ToObservableCollection(); } diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index 3b267b78..7ac0e919 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -277,7 +277,7 @@ - + all diff --git a/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml b/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml index 0b2f163c..abdb0169 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/MainView.xaml @@ -19,7 +19,7 @@ CompactPaneLength="48" IsBackEnabled="{x:Bind ContentFrame.CanGoBack, Mode=OneWay}" IsPaneOpen="True" - OpenPaneLength="188" + OpenPaneLength="192" PaneDisplayMode="Left" UseLayoutRounding="False"> diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml index 87a87fb2..80c2ca8c 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/LaunchGamePage.xaml @@ -153,6 +153,7 @@ Message="{shcm:ResourceString Name=ViewPageLaunchGameConfigurationSaveHint}" Severity="Informational"/> + + + + + + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementImporter.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementImporter.cs index b91fb822..e5a23ee0 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementImporter.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementImporter.cs @@ -5,7 +5,8 @@ using Microsoft.UI.Xaml.Controls; using Snap.Hutao.Control.Extension; using Snap.Hutao.Core.IO; using Snap.Hutao.Core.IO.DataTransfer; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; +using Snap.Hutao.Factory.Picker; using Snap.Hutao.Model.InterChange.Achievement; using Snap.Hutao.Service.Achievement; using Snap.Hutao.Service.Notification; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs index 8d51141a..35aecde4 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Achievement/AchievementViewModel.cs @@ -5,7 +5,8 @@ using CommunityToolkit.WinUI.Collections; using Microsoft.UI.Xaml.Controls; using Snap.Hutao.Core.IO; using Snap.Hutao.Core.LifeCycle; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; +using Snap.Hutao.Factory.Picker; using Snap.Hutao.Model.InterChange.Achievement; using Snap.Hutao.Service.Achievement; using Snap.Hutao.Service.Metadata; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarPropertyViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarPropertyViewModel.cs index e4a67b0d..5f2181b5 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarPropertyViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarPropertyViewModel.cs @@ -8,7 +8,7 @@ using Microsoft.UI.Xaml.Media.Imaging; using Snap.Hutao.Control.Extension; using Snap.Hutao.Control.Media; using Snap.Hutao.Core.IO.DataTransfer; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Message; using Snap.Hutao.Model.Calculable; using Snap.Hutao.Model.Entity.Primitive; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivationViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivationViewModel.cs index 46883e09..90024897 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivationViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivationViewModel.cs @@ -1,7 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.Metadata.Item; using Snap.Hutao.Model.Primitive; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs index 85e926c2..9ab591a2 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/DailyNote/DailyNoteViewModel.cs @@ -4,7 +4,7 @@ using Microsoft.UI.Xaml.Controls; using Snap.Hutao.Control.Extension; using Snap.Hutao.Core; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Model.Entity; using Snap.Hutao.Service.DailyNote; using Snap.Hutao.Service.Notification; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs index 997e29fe..6dbf21d8 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs @@ -6,7 +6,9 @@ using Snap.Hutao.Control.Extension; using Snap.Hutao.Core.Database; using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Core.IO; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; +using Snap.Hutao.Factory.Picker; +using Snap.Hutao.Factory.Progress; using Snap.Hutao.Model.Entity; using Snap.Hutao.Model.InterChange.GachaLog; using Snap.Hutao.Service.GachaLog; @@ -27,10 +29,11 @@ namespace Snap.Hutao.ViewModel.GachaLog; [Injection(InjectAs.Scoped)] internal sealed partial class GachaLogViewModel : Abstraction.ViewModel { + private readonly HutaoCloudStatisticsViewModel hutaoCloudStatisticsViewModel; private readonly IGachaLogQueryProviderFactory gachaLogQueryProviderFactory; private readonly IContentDialogFactory contentDialogFactory; - private readonly HutaoCloudStatisticsViewModel hutaoCloudStatisticsViewModel; private readonly HutaoCloudViewModel hutaoCloudViewModel; + private readonly IProgressFactory progressFactory; private readonly IGachaLogService gachaLogService; private readonly IInfoBarService infoBarService; private readonly JsonSerializerOptions options; @@ -162,7 +165,7 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel throw; } - IProgress progress = taskContext.CreateProgressForMainThread(dialog.OnReport); + IProgress progress = progressFactory.CreateForMainThread(dialog.OnReport); bool authkeyValid; try diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/HutaoCloudViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/HutaoCloudViewModel.cs index 89a250e2..f7cc4040 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/HutaoCloudViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/HutaoCloudViewModel.cs @@ -3,7 +3,7 @@ using Microsoft.UI.Xaml.Controls; using Snap.Hutao.Control.Extension; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Model.Entity; using Snap.Hutao.Service.GachaLog; using Snap.Hutao.Service.Hutao; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs index 6b5704c2..4fd85dcf 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameViewModel.cs @@ -5,7 +5,8 @@ using Microsoft.Extensions.Caching.Memory; using Snap.Hutao.Control.Extension; using Snap.Hutao.Core; using Snap.Hutao.Core.ExceptionService; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; +using Snap.Hutao.Factory.Progress; using Snap.Hutao.Model.Entity; using Snap.Hutao.Service; using Snap.Hutao.Service.Game; @@ -38,10 +39,11 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel private readonly IContentDialogFactory contentDialogFactory; private readonly LaunchStatusOptions launchStatusOptions; private readonly INavigationService navigationService; + private readonly IProgressFactory progressFactory; private readonly IInfoBarService infoBarService; private readonly ResourceClient resourceClient; + private readonly RuntimeOptions runtimeOptions; private readonly LaunchOptions launchOptions; - private readonly RuntimeOptions hutaoOptions; private readonly IUserService userService; private readonly ITaskContext taskContext; private readonly IGameServiceFacade gameService; @@ -96,7 +98,7 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel /// /// 胡桃选项 /// - public RuntimeOptions HutaoOptions { get => hutaoOptions; } + public RuntimeOptions HutaoOptions { get => runtimeOptions; } /// /// 应用选项 @@ -191,45 +193,44 @@ internal sealed partial class LaunchGameViewModel : Abstraction.ViewModel [Command("LaunchCommand")] private async Task LaunchAsync() { - if (SelectedScheme is not null) - { - try - { - gameService.SetChannelOptions(SelectedScheme); - - // Whether or not the channel options changed, we always ensure game resouces - LaunchGamePackageConvertDialog dialog = await contentDialogFactory.CreateInstanceAsync().ConfigureAwait(false); - IProgress convertProgress = taskContext.CreateProgressForMainThread(state => dialog.State = state); - using (await dialog.BlockAsync(taskContext).ConfigureAwait(false)) - { - if (!await gameService.EnsureGameResourceAsync(SelectedScheme, convertProgress).ConfigureAwait(false)) - { - infoBarService.Warning(SH.ViewModelLaunchGameEnsureGameResourceFail); - return; - } - } - - if (SelectedGameAccount is not null) - { - if (!gameService.SetGameAccount(SelectedGameAccount)) - { - infoBarService.Warning(SH.ViewModelLaunchGameSwitchGameAccountFail); - return; - } - } - - IProgress launchProgress = taskContext.CreateProgressForMainThread(status => launchStatusOptions.LaunchStatus = status); - await gameService.LaunchAsync(launchProgress).ConfigureAwait(false); - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine(ExceptionFormat.Format(ex)); - infoBarService.Error(ex); - } - } - else + if (SelectedScheme is null) { infoBarService.Error(SH.ViewModelLaunchGameSchemeNotSelected); + return; + } + + try + { + // Always ensure game resources + gameService.SetChannelOptions(SelectedScheme); + + LaunchGamePackageConvertDialog dialog = await contentDialogFactory.CreateInstanceAsync().ConfigureAwait(false); + IProgress convertProgress = progressFactory.CreateForMainThread(state => dialog.State = state); + + using (await dialog.BlockAsync(taskContext).ConfigureAwait(false)) + { + if (!await gameService.EnsureGameResourceAsync(SelectedScheme, convertProgress).ConfigureAwait(false)) + { + infoBarService.Warning(SH.ViewModelLaunchGameEnsureGameResourceFail); + return; + } + } + + if (SelectedGameAccount is not null) + { + if (!gameService.SetGameAccount(SelectedGameAccount)) + { + infoBarService.Warning(SH.ViewModelLaunchGameSwitchGameAccountFail); + return; + } + } + + IProgress launchProgress = progressFactory.CreateForMainThread(status => launchStatusOptions.LaunchStatus = status); + await gameService.LaunchAsync(launchProgress).ConfigureAwait(false); + } + catch (Exception ex) + { + infoBarService.Error(ex); } } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Setting/HutaoPassportViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Setting/HutaoPassportViewModel.cs index f0709654..28c619b3 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Setting/HutaoPassportViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Setting/HutaoPassportViewModel.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Core.Setting; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Service.Hutao; using Snap.Hutao.Service.Notification; using Snap.Hutao.View.Dialog; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Setting/SettingViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Setting/SettingViewModel.cs index 523b6e96..131190c7 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Setting/SettingViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Setting/SettingViewModel.cs @@ -11,7 +11,8 @@ using Snap.Hutao.Core.IO.DataTransfer; using Snap.Hutao.Core.Setting; using Snap.Hutao.Core.Shell; using Snap.Hutao.Core.Windowing; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; +using Snap.Hutao.Factory.Picker; using Snap.Hutao.Model; using Snap.Hutao.Service; using Snap.Hutao.Service.GachaLog.QueryProvider; @@ -40,12 +41,12 @@ internal sealed partial class SettingViewModel : Abstraction.ViewModel { private readonly HomeCardOptions homeCardOptions = new(); + private readonly HutaoPassportViewModel hutaoPassportViewModel; private readonly IContentDialogFactory contentDialogFactory; private readonly IGameLocatorFactory gameLocatorFactory; private readonly INavigationService navigationService; private readonly IClipboardInterop clipboardInterop; private readonly IShellLinkInterop shellLinkInterop; - private readonly HutaoPassportViewModel hutaoPassportViewModel; private readonly HutaoUserOptions hutaoUserOptions; private readonly IInfoBarService infoBarService; private readonly RuntimeOptions runtimeOptions; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserViewModel.cs index 96e4fcbe..41fb8a3d 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/User/UserViewModel.cs @@ -7,7 +7,7 @@ using Microsoft.UI.Xaml.Controls.Primitives; using Snap.Hutao.Core; using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Core.IO.DataTransfer; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Service.Navigation; using Snap.Hutao.Service.Notification; using Snap.Hutao.Service.SignIn; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs index b34762c1..d38ca327 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. using CommunityToolkit.WinUI.Collections; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Model.Calculable; using Snap.Hutao.Model.Entity.Primitive; using Snap.Hutao.Model.Intrinsic; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs index d832ca06..dbdd95d8 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. using CommunityToolkit.WinUI.Collections; -using Snap.Hutao.Factory.Abstraction; +using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Model.Calculable; using Snap.Hutao.Model.Entity.Primitive; using Snap.Hutao.Model.Intrinsic;