mirror of
https://github.com/HolographicHat/Yae.git
synced 2025-12-20 05:13:19 +08:00
update
This commit is contained in:
@@ -1,8 +1,18 @@
|
|||||||
namespace YaeAchievement;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace YaeAchievement;
|
||||||
|
|
||||||
|
[SuppressMessage("Usage", "CA2211:非常量字段应当不可见")]
|
||||||
|
[SuppressMessage("ReSharper", "ConvertToConstant.Global")]
|
||||||
|
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Global")]
|
||||||
public static class GlobalVars {
|
public static class GlobalVars {
|
||||||
|
|
||||||
public static bool Verbose = false;
|
public static bool Verbose = false;
|
||||||
public const string LibName = "YaeAchievementLib.dll";
|
|
||||||
public const string PipeName = "YaeAchievementPipe";
|
|
||||||
public static bool UnexpectedExit = true;
|
public static bool UnexpectedExit = true;
|
||||||
|
public static string GamePath = "";
|
||||||
|
|
||||||
|
public const string LibName = "YaeLib.dll";
|
||||||
|
public const string PipeName = "YaeAchievementPipe";
|
||||||
|
public const string ConfigFileName = "YaeAchievement.runtimeconfig.json";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
using System.ComponentModel;
|
using YaeAchievement;
|
||||||
using System.Diagnostics;
|
using static YaeAchievement.Utils;
|
||||||
using System.IO.Pipes;
|
|
||||||
using YaeAchievement;
|
|
||||||
using YaeAchievement.Win32;
|
|
||||||
|
|
||||||
|
InstallExitHook();
|
||||||
Utils.StartAndWaitResult(@"D:\Genshin Impact Dev\2.8\YuanShen.exe", str => {
|
InstallExceptionHook();
|
||||||
|
CheckGenshinIsRunning();
|
||||||
|
LoadConfig();
|
||||||
|
return;
|
||||||
|
StartAndWaitResult(@"D:\Genshin Impact Dev\2.8\YuanShen.exe", str => {
|
||||||
GlobalVars.UnexpectedExit = false;
|
GlobalVars.UnexpectedExit = false;
|
||||||
//AchievementAllDataNotify.Parser.ParseFrom(Convert.FromBase64String(str)).List;
|
//AchievementAllDataNotify.Parser.ParseFrom(Convert.FromBase64String(str)).List;
|
||||||
//var notify = Serializer.Deserialize<AchievementAllDataNotify>(stream)!;
|
//var notify = Serializer.Deserialize<AchievementAllDataNotify>(stream)!;
|
||||||
|
|||||||
72
src/Utils.cs
72
src/Utils.cs
@@ -1,12 +1,82 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO.Pipes;
|
using System.IO.Pipes;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
using YaeAchievement.Win32;
|
using YaeAchievement.Win32;
|
||||||
|
using static YaeAchievement.Win32.OpenFileFlags;
|
||||||
|
|
||||||
namespace YaeAchievement;
|
namespace YaeAchievement;
|
||||||
|
|
||||||
public static class Utils {
|
public static class Utils {
|
||||||
|
|
||||||
|
public static void LoadConfig() {
|
||||||
|
var conf = JsonNode.Parse(File.ReadAllText(GlobalVars.ConfigFileName))!;
|
||||||
|
var path = conf["genshinPath"];
|
||||||
|
if (path == null || CheckGamePathValid(path.GetValue<string>())) {
|
||||||
|
GlobalVars.GamePath = SelectGameExecutable();
|
||||||
|
conf["genshinPath"] = GlobalVars.GamePath;
|
||||||
|
File.WriteAllText(GlobalVars.ConfigFileName, conf.ToJsonString());
|
||||||
|
} else {
|
||||||
|
GlobalVars.GamePath = path.GetValue<string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool CheckGamePathValid(string path) {
|
||||||
|
var dir = Path.GetDirectoryName(path)!;
|
||||||
|
return File.Exists($"{dir}/UnityPlayer.dll") && File.Exists($"{dir}/mhypbase.dll");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string SelectGameExecutable() {
|
||||||
|
var fnPtr = Marshal.AllocHGlobal(32768);
|
||||||
|
var ofn = new OpenFileName {
|
||||||
|
file = fnPtr,
|
||||||
|
size = Marshal.SizeOf<OpenFileName>(),
|
||||||
|
owner = Native.GetConsoleWindow(),
|
||||||
|
flags = Explorer | NoNetworkButton | FileMustExist | NoChangeDir,
|
||||||
|
title = "选择主程序",
|
||||||
|
filter = "国服/国际服主程序 (YuanShen/GenshinImpact.exe)\0YuanShen.exe;GenshinImpact.exe\0",
|
||||||
|
maxFile = 32768
|
||||||
|
};
|
||||||
|
if(!Native.GetOpenFileName(ofn)) {
|
||||||
|
var err = Native.CommDlgExtendedError();
|
||||||
|
if (err != 0) {
|
||||||
|
throw new SystemException($"Dialog error: {err}");
|
||||||
|
}
|
||||||
|
Console.WriteLine("操作被取消");
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
var path = Marshal.PtrToStringAuto(fnPtr)!;
|
||||||
|
Marshal.FreeHGlobal(fnPtr);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CheckGenshinIsRunning() {
|
||||||
|
Process.EnterDebugMode();
|
||||||
|
foreach (var process in Process.GetProcesses()) {
|
||||||
|
if (process.ProcessName is "GenshinImpact" or "YuanShen") {
|
||||||
|
Console.WriteLine("原神正在运行,请关闭后重试");
|
||||||
|
Environment.Exit(301);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Process.LeaveDebugMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InstallExitHook() {
|
||||||
|
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
|
||||||
|
Console.WriteLine("按任意键退出");
|
||||||
|
Console.ReadKey();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InstallExceptionHook() {
|
||||||
|
AppDomain.CurrentDomain.UnhandledException += (_, e) => {
|
||||||
|
Console.WriteLine(e.ExceptionObject.ToString());
|
||||||
|
Console.WriteLine("发生错误,请联系开发者以获取帮助");
|
||||||
|
Environment.Exit(-1);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// ReSharper disable once UnusedMethodReturnValue.Global
|
// ReSharper disable once UnusedMethodReturnValue.Global
|
||||||
public static Thread StartAndWaitResult(string exePath, Func<string, bool> onReceive) {
|
public static Thread StartAndWaitResult(string exePath, Func<string, bool> onReceive) {
|
||||||
if (!Injector.CreateProcess(exePath, out var hProcess, out var hThread, out var pid)) {
|
if (!Injector.CreateProcess(exePath, out var hProcess, out var hThread, out var pid)) {
|
||||||
@@ -31,7 +101,7 @@ public static class Utils {
|
|||||||
proc.EnableRaisingEvents = true;
|
proc.EnableRaisingEvents = true;
|
||||||
proc.Exited += (_, _) => {
|
proc.Exited += (_, _) => {
|
||||||
if (GlobalVars.UnexpectedExit) {
|
if (GlobalVars.UnexpectedExit) {
|
||||||
Console.WriteLine($"Game process exit at {proc.ExitTime:HH:mm:ss}");
|
Console.WriteLine("游戏进程异常退出");
|
||||||
Environment.Exit(114514);
|
Environment.Exit(114514);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public static class Native {
|
|||||||
[SuppressMessage("Globalization", "CA2101:指定对 P/Invoke 字符串参数进行封送处理")]
|
[SuppressMessage("Globalization", "CA2101:指定对 P/Invoke 字符串参数进行封送处理")]
|
||||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
|
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling=true)]
|
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
|
||||||
public static extern IntPtr VirtualAllocEx(
|
public static extern IntPtr VirtualAllocEx(
|
||||||
IntPtr hProcess,
|
IntPtr hProcess,
|
||||||
IntPtr lpAddress,
|
IntPtr lpAddress,
|
||||||
@@ -50,7 +50,7 @@ public static class Native {
|
|||||||
MemoryProtection flProtect
|
MemoryProtection flProtect
|
||||||
);
|
);
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError=true, ExactSpelling=true)]
|
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
|
||||||
public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocationType dwFreeType);
|
public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocationType dwFreeType);
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
@@ -71,4 +71,14 @@ public static class Native {
|
|||||||
uint dwCreationFlags,
|
uint dwCreationFlags,
|
||||||
out IntPtr lpThreadId
|
out IntPtr lpThreadId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
public static extern IntPtr GetConsoleWindow();
|
||||||
|
|
||||||
|
[DllImport("comdlg32.dll", SetLastError = true)]
|
||||||
|
public static extern int CommDlgExtendedError();
|
||||||
|
|
||||||
|
[DllImport("comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||||
|
public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
9
src/Win32/OpenFileFlags.cs
Normal file
9
src/Win32/OpenFileFlags.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace YaeAchievement.Win32;
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum OpenFileFlags : uint {
|
||||||
|
Explorer = 0x00080000,
|
||||||
|
NoChangeDir = 0x00000008,
|
||||||
|
FileMustExist = 0x00001000,
|
||||||
|
NoNetworkButton = 0x00020000,
|
||||||
|
}
|
||||||
32
src/Win32/OpenFileName.cs
Normal file
32
src/Win32/OpenFileName.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable FieldCanBeMadeReadOnly.Global
|
||||||
|
|
||||||
|
namespace YaeAchievement.Win32;
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||||
|
public struct OpenFileName {
|
||||||
|
public int size;
|
||||||
|
public IntPtr owner;
|
||||||
|
public IntPtr instance;
|
||||||
|
public string filter;
|
||||||
|
public IntPtr customFilter;
|
||||||
|
public int maxCustFilter;
|
||||||
|
public int filterIndex;
|
||||||
|
public IntPtr file;
|
||||||
|
public int maxFile;
|
||||||
|
public IntPtr fileTitle;
|
||||||
|
public int maxFileTitle;
|
||||||
|
public string initialDir;
|
||||||
|
public string title;
|
||||||
|
public OpenFileFlags flags;
|
||||||
|
public short fileOffset;
|
||||||
|
public short fileExtension;
|
||||||
|
public string defExt;
|
||||||
|
public IntPtr custData;
|
||||||
|
public IntPtr hook;
|
||||||
|
public string templateName;
|
||||||
|
public IntPtr reservedPtr;
|
||||||
|
public int reservedInt;
|
||||||
|
public int flagsEx;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user