optimize code and AchievementAllDataNotify

This commit is contained in:
HolographicHat
2022-06-13 15:02:37 +08:00
parent f753acfc78
commit e847d4c80e
6 changed files with 637 additions and 79 deletions

View File

@@ -9,4 +9,8 @@
<ApplicationManifest>res\app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.21.1" />
</ItemGroup>
</Project>

View File

@@ -1,5 +0,0 @@
namespace YaeAchievement.Events;
public interface IEventBase {
}

View File

@@ -1,14 +0,0 @@
namespace YaeAchievement.Events;
public class PipeRecvEvent : IEventBase {
private readonly byte[] _data;
public PipeRecvEvent(string content) {
_data = Convert.FromBase64String(content);
}
public byte[] GetData() {
return _data;
}
}

View File

@@ -2,67 +2,13 @@
using System.Diagnostics;
using System.IO.Pipes;
using YaeAchievement;
using YaeAchievement.Events;
using YaeAchievement.Win32;
// ReSharper disable once UnusedLocalFunctionReturnValue
Thread StartAndWaitResult(string exePath, Func<IEventBase, bool> onEvent) {
if (!Injector.CreateProcess(exePath, out var hProcess, out var hThread, out var pid)) {
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess fail"));
}
if (Injector.LoadLibraryAndInject(hProcess, GlobalVars.LibName) != 0) {
if (!Native.TerminateProcess(hProcess, 0)) {
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail"));
}
}
if (Native.ResumeThread(hThread) == 0xFFFFFFFF) {
var e = new Win32Exception();
if (!Native.TerminateProcess(hProcess, 0)) {
new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail");
}
Environment.Exit(e.PrintMsgAndReturnErrCode("ResumeThread fail"));
}
if (!Native.CloseHandle(hProcess)) {
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("CloseHandle fail"));
}
var proc = Process.GetProcessById(Convert.ToInt32(pid));
proc.EnableRaisingEvents = true;
proc.Exited += (_, _) => {
if (GlobalVars.UnexpectedExit) {
Console.WriteLine($"Game process exit at {proc.ExitTime:HH:mm:ss}");
Environment.Exit(114514);
}
};
var ts = new ThreadStart(() => {
var server = new NamedPipeServerStream(GlobalVars.PipeName);
server.WaitForConnection();
var reader = new StreamReader(server);
while (true) {
var line = reader.ReadLine();
if (line?.Length > 0) {
if (onEvent(new PipeRecvEvent(line))) {
break;
}
server.Disconnect();
server.WaitForConnection();
}
}
});
var th = new Thread(ts);
th.Start();
return th;
}
StartAndWaitResult(@"D:\Genshin Impact Dev\2.8\YuanShen.exe", evt => {
switch (evt) {
case PipeRecvEvent @event: {
var bytes = @event.GetData();
Utils.StartAndWaitResult(@"D:\Genshin Impact Dev\2.8\YuanShen.exe", str => {
GlobalVars.UnexpectedExit = false;
Console.WriteLine("On PRE");
Console.WriteLine(Convert.ToBase64String(bytes));
//AchievementAllDataNotify.Parser.ParseFrom(Convert.FromBase64String(str)).List;
//var notify = Serializer.Deserialize<AchievementAllDataNotify>(stream)!;
//notify.list;
return false;
}
default:
return false;
}
});

View File

@@ -0,0 +1,572 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: AchievementAllDataNotify.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021, 8981
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
/// <summary>Holder for reflection information generated from AchievementAllDataNotify.proto</summary>
public static partial class AchievementAllDataNotifyReflection {
#region Descriptor
/// <summary>File descriptor for AchievementAllDataNotify.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static AchievementAllDataNotifyReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"Ch5BY2hpZXZlbWVudEFsbERhdGFOb3RpZnkucHJvdG8iugEKC0FjaGlldmVt",
"ZW50EgoKAmlkGAEgASgNEiMKBnN0YXR1cxgCIAEoDjITLkFjaGlldmVtZW50",
"LlN0YXR1cxIPCgdjdXJyZW50GAMgASgNEg8KB3JlcXVpcmUYBCABKA0SEQoJ",
"dGltZXN0YW1wGAUgASgNIkUKBlN0YXR1cxILCgdJTlZBTElEEAASDgoKVU5G",
"SU5JU0hFRBABEgwKCEZJTklTSEVEEAISEAoMUkVXQVJEX1RBS0VOEAMiNgoY",
"QWNoaWV2ZW1lbnRBbGxEYXRhTm90aWZ5EhoKBGxpc3QYBSADKAsyDC5BY2hp",
"ZXZlbWVudGIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::Achievement), global::Achievement.Parser, new[]{ "ID", "Status", "Current", "Require", "Timestamp" }, null, new[]{ typeof(global::Achievement.Types.Status) }, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::AchievementAllDataNotify), global::AchievementAllDataNotify.Parser, new[]{ "List" }, null, null, null, null)
}));
}
#endregion
}
#region Messages
public sealed partial class Achievement : pb::IMessage<Achievement>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<Achievement> _parser = new pb::MessageParser<Achievement>(() => new Achievement());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pb::MessageParser<Achievement> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor {
get { return global::AchievementAllDataNotifyReflection.Descriptor.MessageTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public Achievement() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public Achievement(Achievement other) : this() {
id_ = other.id_;
status_ = other.status_;
current_ = other.current_;
require_ = other.require_;
timestamp_ = other.timestamp_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public Achievement Clone() {
return new Achievement(this);
}
/// <summary>Field number for the "id" field.</summary>
public const int IDFieldNumber = 1;
private uint id_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint ID {
get { return id_; }
set {
id_ = value;
}
}
/// <summary>Field number for the "status" field.</summary>
public const int StatusFieldNumber = 2;
private global::Achievement.Types.Status status_ = global::Achievement.Types.Status.Invalid;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public global::Achievement.Types.Status Status {
get { return status_; }
set {
status_ = value;
}
}
/// <summary>Field number for the "current" field.</summary>
public const int CurrentFieldNumber = 3;
private uint current_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint Current {
get { return current_; }
set {
current_ = value;
}
}
/// <summary>Field number for the "require" field.</summary>
public const int RequireFieldNumber = 4;
private uint require_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint Require {
get { return require_; }
set {
require_ = value;
}
}
/// <summary>Field number for the "timestamp" field.</summary>
public const int TimestampFieldNumber = 5;
private uint timestamp_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint Timestamp {
get { return timestamp_; }
set {
timestamp_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
return Equals(other as Achievement);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool Equals(Achievement other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (ID != other.ID) return false;
if (Status != other.Status) return false;
if (Current != other.Current) return false;
if (Require != other.Require) return false;
if (Timestamp != other.Timestamp) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
if (ID != 0) hash ^= ID.GetHashCode();
if (Status != global::Achievement.Types.Status.Invalid) hash ^= Status.GetHashCode();
if (Current != 0) hash ^= Current.GetHashCode();
if (Require != 0) hash ^= Require.GetHashCode();
if (Timestamp != 0) hash ^= Timestamp.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
if (ID != 0) {
output.WriteRawTag(8);
output.WriteUInt32(ID);
}
if (Status != global::Achievement.Types.Status.Invalid) {
output.WriteRawTag(16);
output.WriteEnum((int) Status);
}
if (Current != 0) {
output.WriteRawTag(24);
output.WriteUInt32(Current);
}
if (Require != 0) {
output.WriteRawTag(32);
output.WriteUInt32(Require);
}
if (Timestamp != 0) {
output.WriteRawTag(40);
output.WriteUInt32(Timestamp);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
if (ID != 0) {
output.WriteRawTag(8);
output.WriteUInt32(ID);
}
if (Status != global::Achievement.Types.Status.Invalid) {
output.WriteRawTag(16);
output.WriteEnum((int) Status);
}
if (Current != 0) {
output.WriteRawTag(24);
output.WriteUInt32(Current);
}
if (Require != 0) {
output.WriteRawTag(32);
output.WriteUInt32(Require);
}
if (Timestamp != 0) {
output.WriteRawTag(40);
output.WriteUInt32(Timestamp);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
if (ID != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(ID);
}
if (Status != global::Achievement.Types.Status.Invalid) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Status);
}
if (Current != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Current);
}
if (Require != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Require);
}
if (Timestamp != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Timestamp);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(Achievement other) {
if (other == null) {
return;
}
if (other.ID != 0) {
ID = other.ID;
}
if (other.Status != global::Achievement.Types.Status.Invalid) {
Status = other.Status;
}
if (other.Current != 0) {
Current = other.Current;
}
if (other.Require != 0) {
Require = other.Require;
}
if (other.Timestamp != 0) {
Timestamp = other.Timestamp;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 8: {
ID = input.ReadUInt32();
break;
}
case 16: {
Status = (global::Achievement.Types.Status) input.ReadEnum();
break;
}
case 24: {
Current = input.ReadUInt32();
break;
}
case 32: {
Require = input.ReadUInt32();
break;
}
case 40: {
Timestamp = input.ReadUInt32();
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 8: {
ID = input.ReadUInt32();
break;
}
case 16: {
Status = (global::Achievement.Types.Status) input.ReadEnum();
break;
}
case 24: {
Current = input.ReadUInt32();
break;
}
case 32: {
Require = input.ReadUInt32();
break;
}
case 40: {
Timestamp = input.ReadUInt32();
break;
}
}
}
}
#endif
#region Nested types
/// <summary>Container for nested types declared in the Achievement message type.</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static partial class Types {
public enum Status {
[pbr::OriginalName("INVALID")] Invalid = 0,
[pbr::OriginalName("UNFINISHED")] Unfinished = 1,
[pbr::OriginalName("FINISHED")] Finished = 2,
[pbr::OriginalName("REWARD_TAKEN")] RewardTaken = 3,
}
}
#endregion
}
public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementAllDataNotify>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<AchievementAllDataNotify> _parser = new pb::MessageParser<AchievementAllDataNotify>(() => new AchievementAllDataNotify());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pb::MessageParser<AchievementAllDataNotify> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor {
get { return global::AchievementAllDataNotifyReflection.Descriptor.MessageTypes[1]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public AchievementAllDataNotify() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public AchievementAllDataNotify(AchievementAllDataNotify other) : this() {
list_ = other.list_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public AchievementAllDataNotify Clone() {
return new AchievementAllDataNotify(this);
}
/// <summary>Field number for the "list" field.</summary>
public const int ListFieldNumber = 5;
private static readonly pb::FieldCodec<global::Achievement> _repeated_list_codec
= pb::FieldCodec.ForMessage(42, global::Achievement.Parser);
private readonly pbc::RepeatedField<global::Achievement> list_ = new pbc::RepeatedField<global::Achievement>();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public pbc::RepeatedField<global::Achievement> List {
get { return list_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
return Equals(other as AchievementAllDataNotify);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool Equals(AchievementAllDataNotify other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!list_.Equals(other.list_)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
hash ^= list_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
list_.WriteTo(output, _repeated_list_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
list_.WriteTo(ref output, _repeated_list_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
size += list_.CalculateSize(_repeated_list_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(AchievementAllDataNotify other) {
if (other == null) {
return;
}
list_.Add(other.list_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 42: {
list_.AddEntriesFrom(input, _repeated_list_codec);
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 42: {
list_.AddEntriesFrom(ref input, _repeated_list_codec);
break;
}
}
}
}
#endif
}
#endregion
#endregion Designer generated code

55
src/Utils.cs Normal file
View File

@@ -0,0 +1,55 @@
using System.ComponentModel;
using System.Diagnostics;
using System.IO.Pipes;
using YaeAchievement.Win32;
namespace YaeAchievement;
public static class Utils {
// ReSharper disable once UnusedMethodReturnValue.Global
public static Thread StartAndWaitResult(string exePath, Func<string, bool> onReceive) {
if (!Injector.CreateProcess(exePath, out var hProcess, out var hThread, out var pid)) {
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess fail"));
}
if (Injector.LoadLibraryAndInject(hProcess, GlobalVars.LibName) != 0) {
if (!Native.TerminateProcess(hProcess, 0)) {
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail"));
}
}
if (Native.ResumeThread(hThread) == 0xFFFFFFFF) {
var e = new Win32Exception();
if (!Native.TerminateProcess(hProcess, 0)) {
new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail");
}
Environment.Exit(e.PrintMsgAndReturnErrCode("ResumeThread fail"));
}
if (!Native.CloseHandle(hProcess)) {
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("CloseHandle fail"));
}
var proc = Process.GetProcessById(Convert.ToInt32(pid));
proc.EnableRaisingEvents = true;
proc.Exited += (_, _) => {
if (GlobalVars.UnexpectedExit) {
Console.WriteLine($"Game process exit at {proc.ExitTime:HH:mm:ss}");
Environment.Exit(114514);
}
};
var ts = new ThreadStart(() => {
var server = new NamedPipeServerStream(GlobalVars.PipeName);
server.WaitForConnection();
using var reader = new StreamReader(server);
while (!proc.HasExited) {
var line = reader.ReadLine();
if (line?.Length > 0) {
if (onReceive(line)) break;
server.Disconnect();
server.WaitForConnection();
}
}
});
var th = new Thread(ts);
th.Start();
return th;
}
}