From f2f858de15c8ef1a392e783b4b0713c2328696b8 Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Thu, 4 Jan 2024 22:51:58 +0800
Subject: [PATCH] create infrastructure
---
.../Snap.Hutao/Resource/Localization/SH.resx | 3 +
.../ILaunchExecutionDelegateHandler.cs | 11 +++
.../Game/Launching/LaunchExecutionContext.cs | 17 ++++
...chExecutionEnsureSchemeNotExistsHandler.cs | 19 +++++
.../Game/Launching/LaunchExecutionInvoker.cs | 37 +++++++++
.../LaunchExecutionPackageConvertHandler.cs | 11 +++
.../Game/Launching/LaunchExecutionResult.cs | 21 +++++
...LaunchExecutionSetChannelOptionsHandler.cs | 80 +++++++++++++++++++
8 files changed, 199 insertions(+)
create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/ILaunchExecutionDelegateHandler.cs
create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionContext.cs
create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionEnsureSchemeNotExistsHandler.cs
create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionInvoker.cs
create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionPackageConvertHandler.cs
create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionResult.cs
create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionSetChannelOptionsHandler.cs
diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
index bb761610..3e49c037 100644
--- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
+++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx
@@ -875,6 +875,9 @@
游戏文件操作失败:{0}
+
+ 请选择游戏路径
+
游戏进程已退出
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/ILaunchExecutionDelegateHandler.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/ILaunchExecutionDelegateHandler.cs
new file mode 100644
index 00000000..78ff79ad
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/ILaunchExecutionDelegateHandler.cs
@@ -0,0 +1,11 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Service.Game.Launching;
+
+internal delegate ValueTask LaunchExecutionDelegate();
+
+internal interface ILaunchExecutionDelegateHandler
+{
+ ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next);
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionContext.cs
new file mode 100644
index 00000000..0e2e2b86
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionContext.cs
@@ -0,0 +1,17 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Snap.Hutao.Service.Game.Scheme;
+
+namespace Snap.Hutao.Service.Game.Launching;
+
+internal sealed class LaunchExecutionContext
+{
+ public LaunchExecutionResult Result { get; } = new();
+
+ public ILogger Logger { get; set; } = default!;
+
+ public LaunchScheme Scheme { get; set; } = default!;
+
+ public LaunchOptions Options { get; set; } = default!;
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionEnsureSchemeNotExistsHandler.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionEnsureSchemeNotExistsHandler.cs
new file mode 100644
index 00000000..1cc14fe6
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionEnsureSchemeNotExistsHandler.cs
@@ -0,0 +1,19 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Service.Game.Launching;
+
+internal sealed class LaunchExecutionEnsureSchemeNotExistsHandler : ILaunchExecutionDelegateHandler
+{
+ public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
+ {
+ if (context.Scheme is null)
+ {
+ context.Result.Kind = LaunchExecutionResultKind.NoActiveScheme;
+ context.Result.ErrorMessage = SH.ViewModelLaunchGameSchemeNotSelected;
+ return;
+ }
+
+ await next().ConfigureAwait(false);
+ }
+}
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionInvoker.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionInvoker.cs
new file mode 100644
index 00000000..1e2f8829
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionInvoker.cs
@@ -0,0 +1,37 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Service.Game.Launching;
+
+[Injection(InjectAs.Transient)]
+internal sealed class LaunchExecutionInvoker
+{
+ private readonly Queue handlers;
+
+ public LaunchExecutionInvoker()
+ {
+ handlers = [];
+ handlers.Enqueue(new LaunchExecutionEnsureSchemeNotExistsHandler());
+ handlers.Enqueue(new LaunchExecutionSetChannelOptionsHandler());
+ }
+
+ public async ValueTask LaunchAsync(LaunchExecutionContext context)
+ {
+ await ExecuteAsync(context).ConfigureAwait(false);
+ return context.Result;
+ }
+
+ private async ValueTask ExecuteAsync(LaunchExecutionContext context)
+ {
+ if (handlers.TryDequeue(out ILaunchExecutionDelegateHandler? handler))
+ {
+ string handlerName = handler.GetType().Name;
+
+ context.Logger.LogInformation("Handler[{Handler}] begin execute", handlerName);
+ await handler.OnExecutionAsync(context, () => ExecuteAsync(context)).ConfigureAwait(false);
+ context.Logger.LogInformation("Handler[{Handler}] end execute", handlerName);
+ }
+
+ return context;
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionPackageConvertHandler.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionPackageConvertHandler.cs
new file mode 100644
index 00000000..2d7fc6c8
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionPackageConvertHandler.cs
@@ -0,0 +1,11 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Service.Game.Launching;
+
+internal sealed class LaunchExecutionPackageConvertHandler : ILaunchExecutionDelegateHandler
+{
+ public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionResult.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionResult.cs
new file mode 100644
index 00000000..4461cf8d
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionResult.cs
@@ -0,0 +1,21 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+namespace Snap.Hutao.Service.Game.Launching;
+
+internal sealed class LaunchExecutionResult
+{
+ public LaunchExecutionResultKind Kind { get; set; }
+
+ public string ErrorMessage { get; set; } = default!;
+}
+
+internal enum LaunchExecutionResultKind
+{
+ Ok,
+ NoActiveScheme,
+ NoActiveGamePath,
+ GameConfigFileNotFound,
+ GameConfigDirectoryNotFound,
+ GameConfigUnauthorizedAccess,
+}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionSetChannelOptionsHandler.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionSetChannelOptionsHandler.cs
new file mode 100644
index 00000000..60bd081b
--- /dev/null
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Launching/LaunchExecutionSetChannelOptionsHandler.cs
@@ -0,0 +1,80 @@
+// Copyright (c) DGP Studio. All rights reserved.
+// Licensed under the MIT license.
+
+using Snap.Hutao.Core.IO.Ini;
+using Snap.Hutao.Service.Game.Configuration;
+using System.IO;
+
+namespace Snap.Hutao.Service.Game.Launching;
+
+internal sealed class LaunchExecutionSetChannelOptionsHandler : ILaunchExecutionDelegateHandler
+{
+ private const string ConfigFileName = "config.ini";
+
+ public async ValueTask OnExecutionAsync(LaunchExecutionContext context, LaunchExecutionDelegate next)
+ {
+ if (!context.Options.TryGetGamePathAndFilePathByName(ConfigFileName, out string gamePath, out string? configPath))
+ {
+ context.Result.Kind = LaunchExecutionResultKind.NoActiveGamePath;
+ context.Result.ErrorMessage = SH.ServiceGameLaunchExecutionSetChannelOptionsGamePathNotValid;
+ return;
+ }
+
+ List elements = default!;
+ try
+ {
+ using (FileStream readStream = File.OpenRead(configPath))
+ {
+ elements = [.. IniSerializer.Deserialize(readStream)];
+ }
+ }
+ catch (FileNotFoundException)
+ {
+ context.Result.Kind = LaunchExecutionResultKind.GameConfigFileNotFound;
+ context.Result.ErrorMessage = SH.FormatServiceGameSetMultiChannelConfigFileNotFound(configPath);
+ return;
+ }
+ catch (DirectoryNotFoundException)
+ {
+ context.Result.Kind = LaunchExecutionResultKind.GameConfigDirectoryNotFound;
+ context.Result.ErrorMessage = SH.FormatServiceGameSetMultiChannelConfigFileNotFound(configPath);
+ return;
+ }
+ catch (UnauthorizedAccessException)
+ {
+ context.Result.Kind = LaunchExecutionResultKind.GameConfigUnauthorizedAccess;
+ context.Result.ErrorMessage = SH.ServiceGameSetMultiChannelUnauthorizedAccess;
+ 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;
+ continue;
+ }
+
+ if (parameter.Key is ChannelOptions.SubChannelName)
+ {
+ changed = parameter.Set(context.Scheme.SubChannel.ToString("D")) || changed;
+ continue;
+ }
+ }
+ }
+
+ if (changed)
+ {
+ using (FileStream writeStream = File.Create(configPath))
+ {
+ IniSerializer.Serialize(writeStream, elements);
+ }
+ }
+
+ await next().ConfigureAwait(false);
+ }
+}
\ No newline at end of file