From 8b6f95c3d9f5ccbd2c7900fc0cc534aead247ea1 Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Sat, 6 Jan 2024 15:21:51 +0800 Subject: [PATCH] add package convert check --- .../Snap.Hutao/Core/IO/Ini/IniSerializer.cs | 26 ++++--- .../Game/Configuration/ChannelOptions.cs | 22 +++--- .../Configuration/ChannelOptionsErrorKind.cs | 11 +++ .../GameChannelOptionsService.cs | 21 +++--- .../Snap.Hutao/Service/Game/GameConstants.cs | 1 + .../Snap.Hutao/Service/Game/GameFileSystem.cs | 39 ++++++++++ .../Service/Game/LaunchOptionsExtension.cs | 52 +------------ ...aunchExecutionEnsureGameResourceHandler.cs | 73 +++++++++++++------ ... => LaunchExecutionEnsureSchemeHandler.cs} | 4 +- ...ecutionGameProcessInitializationHandler.cs | 12 ++- ...LaunchExecutionSetChannelOptionsHandler.cs | 24 ++---- .../Game/Launching/LaunchExecutionContext.cs | 29 +++++++- .../Game/Launching/LaunchExecutionInvoker.cs | 2 +- .../Service/Game/Package/PackageConverter.cs | 1 - .../Game/PathAbstraction/GamePathEntry.cs | 6 +- .../{GamePathKind.cs => GamePathEntryKind.cs} | 2 +- .../ViewModel/Game/LaunchGameShared.cs | 14 +--- 17 files changed, 194 insertions(+), 145 deletions(-) create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/ChannelOptionsErrorKind.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Game/GameFileSystem.cs rename src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/{LaunchExecutionEnsureSchemeNotExistsHandler.cs => LaunchExecutionEnsureSchemeHandler.cs} (73%) rename src/Snap.Hutao/Snap.Hutao/Service/Game/PathAbstraction/{GamePathKind.cs => GamePathEntryKind.cs} (87%) diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs index d51ddcfe..b99dd83d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs @@ -11,11 +11,14 @@ namespace Snap.Hutao.Core.IO.Ini; [HighQuality] internal static class IniSerializer { - /// - /// 反序列化 - /// - /// 文件流 - /// Ini 元素集合 + public static List DeserializeFromFile(string filePath) + { + using (FileStream readStream = File.OpenRead(filePath)) + { + return Deserialize(readStream); + } + } + public static List Deserialize(FileStream fileStream) { List results = []; @@ -50,11 +53,14 @@ internal static class IniSerializer return results; } - /// - /// 序列化 - /// - /// 写入的流 - /// 元素 + public static void SerializeToFile(string filePath, IEnumerable elements) + { + using (FileStream writeStream = File.Create(filePath)) + { + Serialize(writeStream, elements); + } + } + public static void Serialize(FileStream fileStream, IEnumerable elements) { using (StreamWriter writer = new(fileStream)) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/ChannelOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/ChannelOptions.cs index db401c8b..b12e7777 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/ChannelOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/ChannelOptions.cs @@ -29,10 +29,9 @@ internal readonly struct ChannelOptions /// public readonly bool IsOversea; - /// - /// 配置文件路径 当不为 null 时则存在文件读写问题 - /// - public readonly string? ConfigFilePath; + public readonly ChannelOptionsErrorKind ErrorKind; + + public readonly string? FilePath; public ChannelOptions(ChannelType channel, SubChannelType subChannel, bool isOversea) { @@ -48,15 +47,20 @@ internal readonly struct ChannelOptions IsOversea = isOversea; } - private ChannelOptions(bool isOversea, string? configFilePath) + private ChannelOptions(ChannelOptionsErrorKind errorKind,string? filePath) { - IsOversea = isOversea; - ConfigFilePath = configFilePath; + ErrorKind = errorKind; + FilePath = filePath; } - public static ChannelOptions FileNotFound(bool isOversea, string configFilePath) + public static ChannelOptions ConfigurationFileNotFound(string filePath) { - return new(isOversea, configFilePath); + return new(ChannelOptionsErrorKind.ConfigurationFileNotFound, filePath); + } + + public static ChannelOptions GamePathNullOrEmpty() + { + return new(ChannelOptionsErrorKind.GamePathNullOrEmpty, string.Empty); } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/ChannelOptionsErrorKind.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/ChannelOptionsErrorKind.cs new file mode 100644 index 00000000..48fd706a --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/ChannelOptionsErrorKind.cs @@ -0,0 +1,11 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Service.Game.Configuration; + +internal enum ChannelOptionsErrorKind +{ + None, + ConfigurationFileNotFound, + GamePathNullOrEmpty, +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/GameChannelOptionsService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/GameChannelOptionsService.cs index f8832249..e201a4f8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/GameChannelOptionsService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Configuration/GameChannelOptionsService.cs @@ -17,25 +17,22 @@ internal sealed partial class GameChannelOptionsService : IGameChannelOptionsSer public ChannelOptions GetChannelOptions() { - if (!launchOptions.TryGetGamePathAndFilePathByName(ConfigFileName, out string gamePath, out string? configPath)) + if (!launchOptions.TryGetGameFileSystem(out GameFileSystem? gameFileSystem)) { - throw ThrowHelper.InvalidOperation($"Invalid game path: {gamePath}"); + return ChannelOptions.GamePathNullOrEmpty(); } - bool isOversea = LaunchScheme.ExecutableIsOversea(Path.GetFileName(gamePath)); + bool isOversea = LaunchScheme.ExecutableIsOversea(gameFileSystem.GameFileName); - if (!File.Exists(configPath)) + if (!File.Exists(gameFileSystem.GameConfigFilePath)) { - return ChannelOptions.FileNotFound(isOversea, configPath); + return ChannelOptions.ConfigurationFileNotFound(gameFileSystem.GameConfigFilePath); } - using (FileStream stream = File.OpenRead(configPath)) - { - List parameters = IniSerializer.Deserialize(stream).OfType().ToList(); - string? channel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.ChannelName)?.Value; - string? subChannel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.SubChannelName)?.Value; + List parameters = IniSerializer.DeserializeFromFile(gameFileSystem.GameConfigFilePath).OfType().ToList(); + string? channel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.ChannelName)?.Value; + string? subChannel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.SubChannelName)?.Value; - return new(channel, subChannel, isOversea); - } + return new(channel, subChannel, isOversea); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameConstants.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameConstants.cs index c910fe12..f76ccc45 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameConstants.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameConstants.cs @@ -10,6 +10,7 @@ namespace Snap.Hutao.Service.Game; internal static class GameConstants { public const string ConfigFileName = "config.ini"; + public const string PCGameSDKFilePath = @"YuanShen_Data\Plugins\PCGameSDK.dll"; public const string YuanShenFileName = "YuanShen.exe"; public const string YuanShenFileNameUpper = "YUANSHEN.EXE"; public const string GenshinImpactFileName = "GenshinImpact.exe"; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/GameFileSystem.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameFileSystem.cs new file mode 100644 index 00000000..32877abb --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/GameFileSystem.cs @@ -0,0 +1,39 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using System.IO; + +namespace Snap.Hutao.Service.Game; + +internal sealed class GameFileSystem +{ + private readonly string gameFilePath; + + private string? gameFileName; + private string? gameDirectory; + private string? gameConfigFilePath; + private string? pcGameSDKFilePath; + + public GameFileSystem(string gameFilePath) + { + this.gameFilePath = gameFilePath; + } + + public string GameFilePath { get => gameFilePath; } + + public string GameFileName { get => gameFileName ??= Path.GetFileName(gameFilePath); } + + public string GameDirectory + { + get + { + gameDirectory ??= Path.GetDirectoryName(gameFilePath); + ArgumentException.ThrowIfNullOrEmpty(gameDirectory); + return gameDirectory; + } + } + + public string GameConfigFilePath { get => gameConfigFilePath ??= Path.Combine(GameDirectory, GameConstants.ConfigFileName); } + + public string PCGameSDKFilePath { get => pcGameSDKFilePath ?? Path.Combine(GameDirectory, GameConstants.PCGameSDKFilePath); } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptionsExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptionsExtension.cs index 06497721..70d12349 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptionsExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/LaunchOptionsExtension.cs @@ -9,64 +9,20 @@ namespace Snap.Hutao.Service.Game; internal static class LaunchOptionsExtension { - public static bool TryGetGamePathAndGameDirectory(this LaunchOptions options, out string gamePath, [NotNullWhen(true)] out string? gameDirectory) - { - gamePath = options.GamePath; - - gameDirectory = Path.GetDirectoryName(gamePath); - if (string.IsNullOrEmpty(gameDirectory)) - { - return false; - } - - return true; - } - - public static bool TryGetGameDirectoryAndGameFileName(this LaunchOptions options, [NotNullWhen(true)] out string? gameDirectory, [NotNullWhen(true)] out string? gameFileName) + public static bool TryGetGameFileSystem(this LaunchOptions options, [NotNullWhen(true)] out GameFileSystem? fileSystem) { string gamePath = options.GamePath; - gameDirectory = Path.GetDirectoryName(gamePath); - if (string.IsNullOrEmpty(gameDirectory)) - { - gameFileName = default; - return false; - } - - gameFileName = Path.GetFileName(gamePath); - if (string.IsNullOrEmpty(gameFileName)) + if (string.IsNullOrEmpty(gamePath)) { + fileSystem = default; return false; } + fileSystem = new GameFileSystem(gamePath); return true; } - public static bool TryGetGamePathAndGameFileName(this LaunchOptions options, out string gamePath, [NotNullWhen(true)] out string? gameFileName) - { - gamePath = options.GamePath; - - gameFileName = Path.GetFileName(gamePath); - if (string.IsNullOrEmpty(gameFileName)) - { - return false; - } - - return true; - } - - public static bool TryGetGamePathAndFilePathByName(this LaunchOptions options, string fileName, out string gamePath, [NotNullWhen(true)] out string? filePath) - { - if (options.TryGetGamePathAndGameDirectory(out gamePath, out string? gameDirectory)) - { - filePath = Path.Combine(gameDirectory, fileName); - return true; - } - - filePath = default; - return false; - } - public static ImmutableList GetGamePathEntries(this LaunchOptions options, out GamePathEntry? entry) { string gamePath = options.GamePath; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionEnsureGameResourceHandler.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionEnsureGameResourceHandler.cs index ecefe3d0..f1d2b29e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionEnsureGameResourceHandler.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionEnsureGameResourceHandler.cs @@ -5,6 +5,7 @@ using Microsoft.Win32.SafeHandles; using Snap.Hutao.Control.Extension; using Snap.Hutao.Factory.ContentDialog; using Snap.Hutao.Factory.Progress; +using Snap.Hutao.Model.Intrinsic; using Snap.Hutao.Service.Game.Package; using Snap.Hutao.Service.Game.PathAbstraction; using Snap.Hutao.View.Dialog; @@ -19,38 +20,68 @@ internal sealed class LaunchExecutionEnsureGameResourceHandler : ILaunchExecutio { public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next) { - IServiceProvider serviceProvider = context.ServiceProvider; - IContentDialogFactory contentDialogFactory = serviceProvider.GetRequiredService(); - IProgressFactory progressFactory = serviceProvider.GetRequiredService(); - - LaunchGamePackageConvertDialog dialog = await contentDialogFactory.CreateInstanceAsync().ConfigureAwait(false); - IProgress convertProgress = progressFactory.CreateForMainThread(state => dialog.State = state); - - using (await dialog.BlockAsync(context.TaskContext).ConfigureAwait(false)) + if (!context.TryGetGameFileSystem(out GameFileSystem? gameFileSystem)) { - if (!await EnsureGameResourceAsync(context, convertProgress).ConfigureAwait(false)) - { - // context.Result is set in EnsureGameResourceAsync - return; - } + return; + } - await context.TaskContext.SwitchToMainThreadAsync(); - ImmutableList gamePathEntries = context.Options.GetGamePathEntries(out GamePathEntry? selected); - context.ViewModel.SetGamePathEntriesAndSelectedGamePathEntry(gamePathEntries, selected); + if (ShouldConvert(context, gameFileSystem)) + { + IServiceProvider serviceProvider = context.ServiceProvider; + IContentDialogFactory contentDialogFactory = serviceProvider.GetRequiredService(); + IProgressFactory progressFactory = serviceProvider.GetRequiredService(); + + LaunchGamePackageConvertDialog dialog = await contentDialogFactory.CreateInstanceAsync().ConfigureAwait(false); + IProgress convertProgress = progressFactory.CreateForMainThread(state => dialog.State = state); + + using (await dialog.BlockAsync(context.TaskContext).ConfigureAwait(false)) + { + if (!await EnsureGameResourceAsync(context, gameFileSystem, convertProgress).ConfigureAwait(false)) + { + // context.Result is set in EnsureGameResourceAsync + return; + } + + await context.TaskContext.SwitchToMainThreadAsync(); + ImmutableList gamePathEntries = context.Options.GetGamePathEntries(out GamePathEntry? selected); + context.ViewModel.SetGamePathEntriesAndSelectedGamePathEntry(gamePathEntries, selected); + } } await next().ConfigureAwait(false); } - private static async ValueTask EnsureGameResourceAsync(LaunchExecutionContext context, IProgress progress) + private static bool ShouldConvert(LaunchExecutionContext context, GameFileSystem gameFileSystem) { - if (!context.Options.TryGetGameDirectoryAndGameFileName(out string? gameFolder, out string? gameFileName)) + // Configuration file changed + if (context.ChannelOptionsChanged) { - context.Result.Kind = LaunchExecutionResultKind.NoActiveGamePath; - context.Result.ErrorMessage = SH.ServiceGameLaunchExecutionGamePathNotValid; - return false; + return true; } + // Executable name not match + if (!context.Scheme.ExecutableMatches(gameFileSystem.GameFileName)) + { + return true; + } + + if (!context.Scheme.IsOversea) + { + // [It's Bilibili channel xor PCGameSDK.dll exists] means we need to convert + if (context.Scheme.Channel is ChannelType.Bili ^ File.Exists(gameFileSystem.PCGameSDKFilePath)) + { + return true; + } + } + + return false; + } + + private static async ValueTask EnsureGameResourceAsync(LaunchExecutionContext context, GameFileSystem gameFileSystem, IProgress progress) + { + string gameFolder = gameFileSystem.GameDirectory; + string gameFileName = gameFileSystem.GameFileName; + context.Logger.LogInformation("Game folder: {GameFolder}", gameFolder); if (!CheckDirectoryPermissions(gameFolder)) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionEnsureSchemeNotExistsHandler.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionEnsureSchemeHandler.cs similarity index 73% rename from src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionEnsureSchemeNotExistsHandler.cs rename to src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionEnsureSchemeHandler.cs index 7dc49fa9..5336e9f2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionEnsureSchemeNotExistsHandler.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionEnsureSchemeHandler.cs @@ -3,7 +3,7 @@ namespace Snap.Hutao.Service.Game.Launching.Handler; -internal sealed class LaunchExecutionEnsureSchemeNotExistsHandler : ILaunchExecutionDelegateHandler +internal sealed class LaunchExecutionEnsureSchemeHandler : ILaunchExecutionDelegateHandler { public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next) { @@ -14,7 +14,7 @@ internal sealed class LaunchExecutionEnsureSchemeNotExistsHandler : ILaunchExecu return; } - context.Logger.LogInformation("Scheme[{Scheme}] is selected", context.Scheme.DisplayName); + context.Logger.LogInformation("Scheme [{Scheme}] is selected", context.Scheme.DisplayName); await next().ConfigureAwait(false); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameProcessInitializationHandler.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameProcessInitializationHandler.cs index ce7cac1a..4c6a3d2f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameProcessInitializationHandler.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionGameProcessInitializationHandler.cs @@ -10,21 +10,19 @@ internal sealed class LaunchExecutionGameProcessInitializationHandler : ILaunchE { public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next) { - if (!context.Options.TryGetGamePathAndGameFileName(out string gamePath, out string? gameFileName)) + if (!context.TryGetGameFileSystem(out GameFileSystem? gameFileSystem)) { - context.Result.Kind = LaunchExecutionResultKind.NoActiveGamePath; - context.Result.ErrorMessage = SH.ServiceGameLaunchExecutionGamePathNotValid; return; } context.Progress.Report(new(LaunchPhase.ProcessInitializing, SH.ServiceGameLaunchPhaseProcessInitializing)); - using (context.Process = InitializeGameProcess(context, gamePath)) + using (context.Process = InitializeGameProcess(context, gameFileSystem)) { await next().ConfigureAwait(false); } } - private static System.Diagnostics.Process InitializeGameProcess(LaunchExecutionContext context, string gamePath) + private static System.Diagnostics.Process InitializeGameProcess(LaunchExecutionContext context, GameFileSystem gameFileSystem) { LaunchOptions launchOptions = context.Options; @@ -51,10 +49,10 @@ internal sealed class LaunchExecutionGameProcessInitializationHandler : ILaunchE StartInfo = new() { Arguments = commandLine, - FileName = gamePath, + FileName = gameFileSystem.GameFilePath, UseShellExecute = true, Verb = "runas", - WorkingDirectory = Path.GetDirectoryName(gamePath), + WorkingDirectory = gameFileSystem.GameDirectory, }, }; } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionSetChannelOptionsHandler.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionSetChannelOptionsHandler.cs index 81125511..7247b4ae 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionSetChannelOptionsHandler.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/Handler/LaunchExecutionSetChannelOptionsHandler.cs @@ -11,22 +11,19 @@ internal sealed class LaunchExecutionSetChannelOptionsHandler : ILaunchExecution { public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next) { - if (!context.Options.TryGetGamePathAndFilePathByName(GameConstants.ConfigFileName, out string gamePath, out string? configPath)) + if (!context.TryGetGameFileSystem(out GameFileSystem? gameFileSystem)) { - context.Result.Kind = LaunchExecutionResultKind.NoActiveGamePath; - context.Result.ErrorMessage = SH.ServiceGameLaunchExecutionGamePathNotValid; + // context.Result is set in TryGetGameFileSystem return; } + string configPath = gameFileSystem.GameConfigFilePath; context.Logger.LogInformation("Game config file path: {ConfigPath}", configPath); List elements = default!; try { - using (FileStream readStream = File.OpenRead(configPath)) - { - elements = [.. IniSerializer.Deserialize(readStream)]; - } + elements = [.. IniSerializer.DeserializeFromFile(configPath)]; } catch (FileNotFoundException) { @@ -47,32 +44,27 @@ internal sealed class LaunchExecutionSetChannelOptionsHandler : ILaunchExecution return; } - bool changed = false; - foreach (IniElement element in elements) { if (element is IniParameter parameter) { if (parameter.Key is ChannelOptions.ChannelName) { - changed = parameter.Set(context.Scheme.Channel.ToString("D")) || changed; + context.ChannelOptionsChanged = parameter.Set(context.Scheme.Channel.ToString("D")) || context.ChannelOptionsChanged; continue; } if (parameter.Key is ChannelOptions.SubChannelName) { - changed = parameter.Set(context.Scheme.SubChannel.ToString("D")) || changed; + context.ChannelOptionsChanged = parameter.Set(context.Scheme.SubChannel.ToString("D")) || context.ChannelOptionsChanged; continue; } } } - if (changed) + if (context.ChannelOptionsChanged) { - using (FileStream writeStream = File.Create(configPath)) - { - IniSerializer.Serialize(writeStream, elements); - } + IniSerializer.SerializeToFile(configPath, elements); } await next().ConfigureAwait(false); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionContext.cs index 7e8023a0..dc0b9bdc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionContext.cs @@ -15,6 +15,8 @@ internal sealed partial class LaunchExecutionContext private readonly ITaskContext taskContext; private readonly LaunchOptions options; + private GameFileSystem? gameFileSystem; + [SuppressMessage("", "SH007")] public LaunchExecutionContext(IServiceProvider serviceProvider, IViewModelSupportLaunchExecution viewModel, LaunchScheme? scheme, GameAccount? account) : this(serviceProvider) @@ -36,13 +38,34 @@ internal sealed partial class LaunchExecutionContext public LaunchOptions Options { get => options; } - public IViewModelSupportLaunchExecution ViewModel { get; set; } = default!; + public IViewModelSupportLaunchExecution ViewModel { get; private set; } = default!; - public LaunchScheme Scheme { get; set; } = default!; + public LaunchScheme Scheme { get; private set; } = default!; - public GameAccount? Account { get; set; } + public GameAccount? Account { get; private set; } + + public bool ChannelOptionsChanged { get; set; } public IProgress Progress { get; set; } = default!; public System.Diagnostics.Process Process { get; set; } = default!; + + public bool TryGetGameFileSystem([NotNullWhen(true)] out GameFileSystem? gameFileSystem) + { + if (this.gameFileSystem is not null) + { + gameFileSystem = this.gameFileSystem; + return true; + } + + if (!Options.TryGetGameFileSystem(out gameFileSystem)) + { + Result.Kind = LaunchExecutionResultKind.NoActiveGamePath; + Result.ErrorMessage = SH.ServiceGameLaunchExecutionGamePathNotValid; + return false; + } + + this.gameFileSystem = gameFileSystem; + return true; + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionInvoker.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionInvoker.cs index 1e746e6b..780c0e10 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionInvoker.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionInvoker.cs @@ -15,7 +15,7 @@ internal sealed class LaunchExecutionInvoker { handlers = []; handlers.Enqueue(new LaunchExecutionEnsureGameNotRunningHandler()); - handlers.Enqueue(new LaunchExecutionEnsureSchemeNotExistsHandler()); + handlers.Enqueue(new LaunchExecutionEnsureSchemeHandler()); handlers.Enqueue(new LaunchExecutionSetChannelOptionsHandler()); handlers.Enqueue(new LaunchExecutionEnsureGameResourceHandler()); handlers.Enqueue(new LaunchExecutionSetGameAccountHandler()); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs index 0742851c..0cb55eb5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs @@ -93,7 +93,6 @@ internal sealed partial class PackageConverter ZipFile.ExtractToDirectory(sdkWebStream, gameFolder, true); } - // TODO: verify sdk md5 if (File.Exists(sdkDllBackup) && File.Exists(sdkVersionBackup)) { File.Delete(sdkDllBackup); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/PathAbstraction/GamePathEntry.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/PathAbstraction/GamePathEntry.cs index 8d8dfd2e..3955a525 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/PathAbstraction/GamePathEntry.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/PathAbstraction/GamePathEntry.cs @@ -9,7 +9,7 @@ internal sealed class GamePathEntry public string Path { get; set; } = default!; [JsonIgnore] - public GamePathKind Kind { get => GetKind(Path); } + public GamePathEntryKind Kind { get => GetKind(Path); } public static GamePathEntry Create(string path) { @@ -19,8 +19,8 @@ internal sealed class GamePathEntry }; } - private static GamePathKind GetKind(string path) + private static GamePathEntryKind GetKind(string path) { - return GamePathKind.None; + return GamePathEntryKind.None; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/PathAbstraction/GamePathKind.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/PathAbstraction/GamePathEntryKind.cs similarity index 87% rename from src/Snap.Hutao/Snap.Hutao/Service/Game/PathAbstraction/GamePathKind.cs rename to src/Snap.Hutao/Snap.Hutao/Service/Game/PathAbstraction/GamePathEntryKind.cs index 3271c606..16b5ed04 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/PathAbstraction/GamePathKind.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/PathAbstraction/GamePathEntryKind.cs @@ -3,7 +3,7 @@ namespace Snap.Hutao.Service.Game.PathAbstraction; -internal enum GamePathKind +internal enum GamePathEntryKind { None, ChineseClient, diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameShared.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameShared.cs index e7a85061..d615baaf 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameShared.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Game/LaunchGameShared.cs @@ -13,17 +13,9 @@ internal static class LaunchGameShared { public static LaunchScheme? GetCurrentLaunchSchemeFromConfigFile(IGameServiceFacade gameService, IInfoBarService infoBarService) { - ChannelOptions options; - try - { - options = gameService.GetChannelOptions(); - } - catch (InvalidOperationException) - { - return default; - } + ChannelOptions options = gameService.GetChannelOptions(); - if (string.IsNullOrEmpty(options.ConfigFilePath)) + if (options.ErrorKind is ChannelOptionsErrorKind.None) { try { @@ -40,7 +32,7 @@ internal static class LaunchGameShared } else { - infoBarService.Warning(SH.FormatViewModelLaunchGameMultiChannelReadFail(options.ConfigFilePath)); + infoBarService.Warning($"{options.ErrorKind}", SH.FormatViewModelLaunchGameMultiChannelReadFail(options.FilePath)); } return default;