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;