mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
add package convert check
This commit is contained in:
@@ -11,11 +11,14 @@ namespace Snap.Hutao.Core.IO.Ini;
|
||||
[HighQuality]
|
||||
internal static class IniSerializer
|
||||
{
|
||||
/// <summary>
|
||||
/// 反序列化
|
||||
/// </summary>
|
||||
/// <param name="fileStream">文件流</param>
|
||||
/// <returns>Ini 元素集合</returns>
|
||||
public static List<IniElement> DeserializeFromFile(string filePath)
|
||||
{
|
||||
using (FileStream readStream = File.OpenRead(filePath))
|
||||
{
|
||||
return Deserialize(readStream);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<IniElement> Deserialize(FileStream fileStream)
|
||||
{
|
||||
List<IniElement> results = [];
|
||||
@@ -50,11 +53,14 @@ internal static class IniSerializer
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 序列化
|
||||
/// </summary>
|
||||
/// <param name="fileStream">写入的流</param>
|
||||
/// <param name="elements">元素</param>
|
||||
public static void SerializeToFile(string filePath, IEnumerable<IniElement> elements)
|
||||
{
|
||||
using (FileStream writeStream = File.Create(filePath))
|
||||
{
|
||||
Serialize(writeStream, elements);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Serialize(FileStream fileStream, IEnumerable<IniElement> elements)
|
||||
{
|
||||
using (StreamWriter writer = new(fileStream))
|
||||
|
||||
@@ -29,10 +29,9 @@ internal readonly struct ChannelOptions
|
||||
/// </summary>
|
||||
public readonly bool IsOversea;
|
||||
|
||||
/// <summary>
|
||||
/// 配置文件路径 当不为 null 时则存在文件读写问题
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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<IniParameter> parameters = IniSerializer.Deserialize(stream).OfType<IniParameter>().ToList();
|
||||
string? channel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.ChannelName)?.Value;
|
||||
string? subChannel = parameters.FirstOrDefault(p => p.Key == ChannelOptions.SubChannelName)?.Value;
|
||||
List<IniParameter> parameters = IniSerializer.DeserializeFromFile(gameFileSystem.GameConfigFilePath).OfType<IniParameter>().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);
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
39
src/Snap.Hutao/Snap.Hutao/Service/Game/GameFileSystem.cs
Normal file
39
src/Snap.Hutao/Snap.Hutao/Service/Game/GameFileSystem.cs
Normal file
@@ -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); }
|
||||
}
|
||||
@@ -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<GamePathEntry> GetGamePathEntries(this LaunchOptions options, out GamePathEntry? entry)
|
||||
{
|
||||
string gamePath = options.GamePath;
|
||||
|
||||
@@ -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<IContentDialogFactory>();
|
||||
IProgressFactory progressFactory = serviceProvider.GetRequiredService<IProgressFactory>();
|
||||
|
||||
LaunchGamePackageConvertDialog dialog = await contentDialogFactory.CreateInstanceAsync<LaunchGamePackageConvertDialog>().ConfigureAwait(false);
|
||||
IProgress<PackageConvertStatus> convertProgress = progressFactory.CreateForMainThread<PackageConvertStatus>(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<GamePathEntry> gamePathEntries = context.Options.GetGamePathEntries(out GamePathEntry? selected);
|
||||
context.ViewModel.SetGamePathEntriesAndSelectedGamePathEntry(gamePathEntries, selected);
|
||||
if (ShouldConvert(context, gameFileSystem))
|
||||
{
|
||||
IServiceProvider serviceProvider = context.ServiceProvider;
|
||||
IContentDialogFactory contentDialogFactory = serviceProvider.GetRequiredService<IContentDialogFactory>();
|
||||
IProgressFactory progressFactory = serviceProvider.GetRequiredService<IProgressFactory>();
|
||||
|
||||
LaunchGamePackageConvertDialog dialog = await contentDialogFactory.CreateInstanceAsync<LaunchGamePackageConvertDialog>().ConfigureAwait(false);
|
||||
IProgress<PackageConvertStatus> convertProgress = progressFactory.CreateForMainThread<PackageConvertStatus>(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<GamePathEntry> gamePathEntries = context.Options.GetGamePathEntries(out GamePathEntry? selected);
|
||||
context.ViewModel.SetGamePathEntriesAndSelectedGamePathEntry(gamePathEntries, selected);
|
||||
}
|
||||
}
|
||||
|
||||
await next().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async ValueTask<bool> EnsureGameResourceAsync(LaunchExecutionContext context, IProgress<PackageConvertStatus> 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<bool> EnsureGameResourceAsync(LaunchExecutionContext context, GameFileSystem gameFileSystem, IProgress<PackageConvertStatus> progress)
|
||||
{
|
||||
string gameFolder = gameFileSystem.GameDirectory;
|
||||
string gameFileName = gameFileSystem.GameFileName;
|
||||
|
||||
context.Logger.LogInformation("Game folder: {GameFolder}", gameFolder);
|
||||
|
||||
if (!CheckDirectoryPermissions(gameFolder))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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<IniElement> 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);
|
||||
|
||||
@@ -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<LaunchStatus> 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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace Snap.Hutao.Service.Game.PathAbstraction;
|
||||
|
||||
internal enum GamePathKind
|
||||
internal enum GamePathEntryKind
|
||||
{
|
||||
None,
|
||||
ChineseClient,
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user