From b020c794b0b1128112b8f8ad438e7fd3a8f83506 Mon Sep 17 00:00:00 2001 From: qhy040404 Date: Mon, 17 Feb 2025 20:17:19 +0800 Subject: [PATCH] impl part of hutao interop --- BetterGenshinImpact/Hutao/BGINamedPipe.cs | 42 +++++++++++++++---- BetterGenshinImpact/Hutao/HutaoNamedPipe.cs | 34 ++++++++------- .../Hutao/HutaoNamedPipeLogEventSink.cs | 1 + BetterGenshinImpact/Hutao/HutaoRequest.cs | 12 ------ BetterGenshinImpact/Hutao/HutaoRequestKind.cs | 7 ---- .../Hutao/NamedPipeClientStreamExtension.cs | 25 +++++++++++ BetterGenshinImpact/Hutao/PipeRequest.cs | 10 +++++ BetterGenshinImpact/Hutao/PipeRequestKind.cs | 22 ++++++++++ BetterGenshinImpact/Hutao/PipeResponse.cs | 11 +++++ BetterGenshinImpact/Hutao/PipeResponseKind.cs | 11 +++++ .../ViewModel/Pages/HomePageViewModel.cs | 4 +- 11 files changed, 136 insertions(+), 43 deletions(-) delete mode 100644 BetterGenshinImpact/Hutao/HutaoRequest.cs delete mode 100644 BetterGenshinImpact/Hutao/HutaoRequestKind.cs create mode 100644 BetterGenshinImpact/Hutao/NamedPipeClientStreamExtension.cs create mode 100644 BetterGenshinImpact/Hutao/PipeRequest.cs create mode 100644 BetterGenshinImpact/Hutao/PipeRequestKind.cs create mode 100644 BetterGenshinImpact/Hutao/PipeResponse.cs create mode 100644 BetterGenshinImpact/Hutao/PipeResponseKind.cs diff --git a/BetterGenshinImpact/Hutao/BGINamedPipe.cs b/BetterGenshinImpact/Hutao/BGINamedPipe.cs index 08fa5b9c..bf6dddbd 100644 --- a/BetterGenshinImpact/Hutao/BGINamedPipe.cs +++ b/BetterGenshinImpact/Hutao/BGINamedPipe.cs @@ -1,5 +1,4 @@ using BetterGenshinImpact.Helpers; -using BetterGenshinImpact.View.Pages; using BetterGenshinImpact.ViewModel.Pages; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -7,9 +6,9 @@ using System; using System.IO.Pipes; using System.Security.AccessControl; using System.Security.Principal; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using Wpf.Ui; namespace BetterGenshinImpact.Hutao; @@ -86,7 +85,7 @@ internal sealed partial class BGINamedPipe : IDisposable switch ((header.Type, header.Command)) { case (PipePacketType.Request, PipePacketCommand.SnapHutaoToBetterGenshinImpactRequest): - if (serverStream.ReadJsonContent(in header) is { } request) + if (serverStream.ReadJsonContent>(in header) is { } request) { DispatchHutaoRequest(request); } @@ -100,14 +99,43 @@ internal sealed partial class BGINamedPipe : IDisposable } } - private void DispatchHutaoRequest(HutaoRequest request) + private void DispatchHutaoRequest(PipeRequest request) { switch (request.Kind) { - case HutaoRequestKind.StartCapture: - HomePageViewModel home = serviceProvider.GetRequiredService(); - home.Start((nint)request.Data.GetInt64()); + case PipeRequestKind.GetContractVersion: + { + PipeResponse response = new() { Kind = PipeResponseKind.Number, Data = Version }; + serverStream.WritePacketWithJsonContent(Version, PipePacketType.Response, PipePacketCommand.BetterGenshinImpactToSnapHutaoResponse, response); + serverStream.Flush(); + } + break; + + case PipeRequestKind.StartCapture: + { + HomePageViewModel home = serviceProvider.GetRequiredService(); + home.Start((nint)request.Data.GetInt64()); + } + + break; + + case PipeRequestKind.StopCapture: + { + HomePageViewModel home = serviceProvider.GetRequiredService(); + home.Stop(); + } + + break; + + case PipeRequestKind.QueryTaskArray: + throw new NotImplementedException(); + + case PipeRequestKind.StartTask: + throw new NotImplementedException(); + + case PipeRequestKind.EndSwitchToNextGameAccount: + throw new NotImplementedException(); } } } \ No newline at end of file diff --git a/BetterGenshinImpact/Hutao/HutaoNamedPipe.cs b/BetterGenshinImpact/Hutao/HutaoNamedPipe.cs index a6188b55..e6ff1688 100644 --- a/BetterGenshinImpact/Hutao/HutaoNamedPipe.cs +++ b/BetterGenshinImpact/Hutao/HutaoNamedPipe.cs @@ -1,6 +1,7 @@ using System; using System.IO.Pipes; using System.Text; +using System.Text.Json; namespace BetterGenshinImpact.Hutao; @@ -18,18 +19,7 @@ internal sealed partial class HutaoNamedPipe : IDisposable { this.serviceProvider = serviceProvider; - isSupported = new(() => - { - try - { - clientStream.Connect(TimeSpan.Zero); - return true; - } - catch (TimeoutException) - { - return false; - } - }); + isSupported = new(clientStream.TryConnectOnce); } public bool IsSupported @@ -44,9 +34,23 @@ internal sealed partial class HutaoNamedPipe : IDisposable return false; } - byte[] buffer = Encoding.UTF8.GetBytes(log); - clientStream.Write(buffer, 0, buffer.Length); - return true; + if (!clientStream.TryConnectOnce()) + { + return false; + } + + try + { + PipeRequest logRequest = new() { Kind = PipeRequestKind.Log, Data = log, }; + clientStream.WritePacketWithJsonContent(Version, PipePacketType.Request, PipePacketCommand.BetterGenshinImpactToSnapHutaoRequest, logRequest); + clientStream.ReadPacket(out _, out PipeResponse? _); + return true; + } + finally + { + clientStream.WritePacket(Version, PipePacketType.SessionTermination, PipePacketCommand.None); + clientStream.Flush(); + } } public void Dispose() diff --git a/BetterGenshinImpact/Hutao/HutaoNamedPipeLogEventSink.cs b/BetterGenshinImpact/Hutao/HutaoNamedPipeLogEventSink.cs index 8f42bc7b..3a7f3e16 100644 --- a/BetterGenshinImpact/Hutao/HutaoNamedPipeLogEventSink.cs +++ b/BetterGenshinImpact/Hutao/HutaoNamedPipeLogEventSink.cs @@ -30,6 +30,7 @@ internal sealed class HutaoNamedPipeLogEventSink : ILogEventSink public void Emit(LogEvent logEvent) { textFormatter.Format(logEvent, writer); + writer.Flush(); buffer.Position = 0; NamedPipe.TryRedirectLog(reader.ReadToEnd()); buffer.SetLength(0); diff --git a/BetterGenshinImpact/Hutao/HutaoRequest.cs b/BetterGenshinImpact/Hutao/HutaoRequest.cs deleted file mode 100644 index e7abfa11..00000000 --- a/BetterGenshinImpact/Hutao/HutaoRequest.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Text.Json; - -namespace BetterGenshinImpact.Hutao; - -internal sealed class HutaoRequest -{ - // DO NOT RENAME: Json convert compatibility - public HutaoRequestKind Kind { get; set; } - - // DO NOT RENAME: Json convert compatibility - public JsonElement Data { get; set; } -} \ No newline at end of file diff --git a/BetterGenshinImpact/Hutao/HutaoRequestKind.cs b/BetterGenshinImpact/Hutao/HutaoRequestKind.cs deleted file mode 100644 index 97a6febd..00000000 --- a/BetterGenshinImpact/Hutao/HutaoRequestKind.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace BetterGenshinImpact.Hutao; - -internal enum HutaoRequestKind -{ - None = 0, - StartCapture = 1, -} \ No newline at end of file diff --git a/BetterGenshinImpact/Hutao/NamedPipeClientStreamExtension.cs b/BetterGenshinImpact/Hutao/NamedPipeClientStreamExtension.cs new file mode 100644 index 00000000..9d305d63 --- /dev/null +++ b/BetterGenshinImpact/Hutao/NamedPipeClientStreamExtension.cs @@ -0,0 +1,25 @@ +using System; +using System.IO.Pipes; + +namespace BetterGenshinImpact.Hutao; + +internal static class NamedPipeClientStreamExtension +{ + public static bool TryConnectOnce(this NamedPipeClientStream clientStream) + { + if (clientStream.IsConnected) + { + return true; + } + + try + { + clientStream.Connect(TimeSpan.Zero); + return true; + } + catch (TimeoutException) + { + return false; + } + } +} \ No newline at end of file diff --git a/BetterGenshinImpact/Hutao/PipeRequest.cs b/BetterGenshinImpact/Hutao/PipeRequest.cs new file mode 100644 index 00000000..4ec95a64 --- /dev/null +++ b/BetterGenshinImpact/Hutao/PipeRequest.cs @@ -0,0 +1,10 @@ +using System.Text.Json; + +namespace BetterGenshinImpact.Hutao; + +internal sealed class PipeRequest +{ + public required PipeRequestKind Kind { get; set; } + + public T Data { get; set; } +} \ No newline at end of file diff --git a/BetterGenshinImpact/Hutao/PipeRequestKind.cs b/BetterGenshinImpact/Hutao/PipeRequestKind.cs new file mode 100644 index 00000000..4b226b5e --- /dev/null +++ b/BetterGenshinImpact/Hutao/PipeRequestKind.cs @@ -0,0 +1,22 @@ +namespace BetterGenshinImpact.Hutao; + +internal enum PipeRequestKind +{ + None = 0, // ContractVersion 1, Both + GetContractVersion = 1, // ContractVersion 1, Both + StartCapture = 2, // ContractVersion 1, S to B + StopCapture = 3, // ContractVersion 1, S to B + Log = 4, // ContractVersion 1, B to S + QueryTaskArray = 10, // ContractVersion 1, S to B + StartTask = 11, // ContractVersion 1, S to B + CreateOneShotTask = 20, // ContractVersion 1, B to S + CreateSteppedTask = 21, // ContractVersion 1, B to S + RemoveTask = 22, // ContractVersion 1, B to S + UpdateTaskDefinition = 23, // ContractVersion 1, B to S + UpdateTaskStepDefinition = 24, // ContractVersion 1, B to S + UpdateTaskStepIndex = 25, // ContractVersion 1, B to S + AddTaskStepDefinition = 26, // ContractVersion 1, B to S + BeginSwitchToNextGameAccount = 30, // ContractVersion 1, B to S + EndSwitchToNextGameAccount = 31, // ContractVersion 1, S to B + QueryCurrentCultivationProject = 40, // ContractVersion 1, B to S +} \ No newline at end of file diff --git a/BetterGenshinImpact/Hutao/PipeResponse.cs b/BetterGenshinImpact/Hutao/PipeResponse.cs new file mode 100644 index 00000000..c1952498 --- /dev/null +++ b/BetterGenshinImpact/Hutao/PipeResponse.cs @@ -0,0 +1,11 @@ +namespace BetterGenshinImpact.Hutao; + +internal class PipeResponse +{ + public required PipeResponseKind Kind { get; set; } +} + +internal sealed class PipeResponse : PipeResponse +{ + public T? Data { get; set; } +} \ No newline at end of file diff --git a/BetterGenshinImpact/Hutao/PipeResponseKind.cs b/BetterGenshinImpact/Hutao/PipeResponseKind.cs new file mode 100644 index 00000000..bf523f4c --- /dev/null +++ b/BetterGenshinImpact/Hutao/PipeResponseKind.cs @@ -0,0 +1,11 @@ +namespace BetterGenshinImpact.Hutao; + +internal enum PipeResponseKind +{ + None, + Object = 1, + Array = 2, + String = 3, + Number = 4, + Boolean = 5, +} \ No newline at end of file diff --git a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs index 3e707f8a..9cb4e30e 100644 --- a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs @@ -225,7 +225,7 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware, IVi internal void Start(IntPtr hWnd) { - Debug.WriteLine($"原神启动句柄{hWnd}"); + Debug.WriteLine($"原神启动句柄 {hWnd}"); lock (this) { if (Config.TriggerInterval <= 0) @@ -258,7 +258,7 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware, IVi Stop(); } - private void Stop() + internal void Stop() { lock (this) {