mirror of
https://github.com/HolographicHat/Yae.git
synced 2025-12-12 17:38:13 +08:00
Fix and optimize game path detect
This commit is contained in:
38
res/App.Designer.cs
generated
38
res/App.Designer.cs
generated
@@ -87,16 +87,7 @@ namespace YaeAchievement.res {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to If correct, input Y; otherwise input N.
|
/// Looks up a localized string similar to You need to login genshin impact before exporting..
|
||||||
/// </summary>
|
|
||||||
internal static string ConfigInitPathConfirm {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("ConfigInitPathConfirm", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to You need start genshin once before exporting..
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ConfigNeedStartGenshin {
|
internal static string ConfigNeedStartGenshin {
|
||||||
get {
|
get {
|
||||||
@@ -264,33 +255,6 @@ namespace YaeAchievement.res {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Operation canceled by user..
|
|
||||||
/// </summary>
|
|
||||||
internal static string SelectCanceled {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("SelectCanceled", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Executable.
|
|
||||||
/// </summary>
|
|
||||||
internal static string SelectFilterName {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("SelectFilterName", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to GenshinPath.
|
|
||||||
/// </summary>
|
|
||||||
internal static string SelectTitle {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("SelectTitle", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Reward not taken.
|
/// Looks up a localized string similar to Reward not taken.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
14
res/App.resx
14
res/App.resx
@@ -68,10 +68,7 @@ Input a number (0-5): </value>
|
|||||||
<value>Reward not taken</value>
|
<value>Reward not taken</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConfigNeedStartGenshin" xml:space="preserve">
|
<data name="ConfigNeedStartGenshin" xml:space="preserve">
|
||||||
<value>You need start genshin once before exporting.</value>
|
<value>You need to login genshin impact before exporting.</value>
|
||||||
</data>
|
|
||||||
<data name="ConfigInitPathConfirm" xml:space="preserve">
|
|
||||||
<value>If correct, input Y; otherwise input N</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="DownloadLink" xml:space="preserve">
|
<data name="DownloadLink" xml:space="preserve">
|
||||||
<value>Download: {0}</value>
|
<value>Download: {0}</value>
|
||||||
@@ -91,15 +88,6 @@ Input a number (0-5): </value>
|
|||||||
<data name="GenshinIsRunning" xml:space="preserve">
|
<data name="GenshinIsRunning" xml:space="preserve">
|
||||||
<value>Please close game before run this application. ({0})</value>
|
<value>Please close game before run this application. ({0})</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SelectCanceled" xml:space="preserve">
|
|
||||||
<value>Operation canceled by user.</value>
|
|
||||||
</data>
|
|
||||||
<data name="SelectTitle" xml:space="preserve">
|
|
||||||
<value>GenshinPath</value>
|
|
||||||
</data>
|
|
||||||
<data name="SelectFilterName" xml:space="preserve">
|
|
||||||
<value>Executable</value>
|
|
||||||
</data>
|
|
||||||
<data name="AnotherInstance" xml:space="preserve">
|
<data name="AnotherInstance" xml:space="preserve">
|
||||||
<value>Please close another instance.</value>
|
<value>Please close another instance.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -62,10 +62,7 @@
|
|||||||
<value>已完成</value>
|
<value>已完成</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConfigNeedStartGenshin" xml:space="preserve">
|
<data name="ConfigNeedStartGenshin" xml:space="preserve">
|
||||||
<value>在导出前你需要先启动一次原神.</value>
|
<value>在导出前你需要先完成一次登入流程.</value>
|
||||||
</data>
|
|
||||||
<data name="ConfigInitPathConfirm" xml:space="preserve">
|
|
||||||
<value>如果确认路径无误,请按 Y ;若有误或需要自行选择,请按 N </value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="DownloadLink" xml:space="preserve">
|
<data name="DownloadLink" xml:space="preserve">
|
||||||
<value>下载地址: {0}</value>
|
<value>下载地址: {0}</value>
|
||||||
@@ -85,15 +82,6 @@
|
|||||||
<data name="GenshinIsRunning" xml:space="preserve">
|
<data name="GenshinIsRunning" xml:space="preserve">
|
||||||
<value>原神正在运行,请关闭后重试 ({0})</value>
|
<value>原神正在运行,请关闭后重试 ({0})</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SelectCanceled" xml:space="preserve">
|
|
||||||
<value>操作被取消</value>
|
|
||||||
</data>
|
|
||||||
<data name="SelectTitle" xml:space="preserve">
|
|
||||||
<value>选择主程序</value>
|
|
||||||
</data>
|
|
||||||
<data name="SelectFilterName" xml:space="preserve">
|
|
||||||
<value>国服/国际服主程序</value>
|
|
||||||
</data>
|
|
||||||
<data name="AnotherInstance" xml:space="preserve">
|
<data name="AnotherInstance" xml:space="preserve">
|
||||||
<value>另一个实例正在运行,请关闭后重试</value>
|
<value>另一个实例正在运行,请关闭后重试</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -8,25 +8,46 @@ public static class AppConfig {
|
|||||||
public static string GamePath { get; private set; } = null!;
|
public static string GamePath { get; private set; } = null!;
|
||||||
|
|
||||||
internal static void Load() {
|
internal static void Load() {
|
||||||
|
var pathCacheFile = new CacheFile("genshin_impact_game_path");
|
||||||
|
if (pathCacheFile.Exists()) {
|
||||||
|
var path = pathCacheFile.Read().Content.ToStringUtf8();
|
||||||
|
if (path != null && File.Exists(path)) {
|
||||||
|
GamePath = path;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||||
var cnLogPath = Path.Combine(appDataPath, @"..\LocalLow\miHoYo\原神\output_log.txt");
|
var cnLogPath = Path.Combine(appDataPath, @"..\LocalLow\miHoYo\原神\output_log.txt");
|
||||||
var osLogPath = Path.Combine(appDataPath, @"..\LocalLow\miHoYo\Genshin Impact\output_log.txt");
|
var osLogPath = Path.Combine(appDataPath, @"..\LocalLow\miHoYo\Genshin Impact\output_log.txt");
|
||||||
if (!File.Exists(cnLogPath) && !File.Exists(osLogPath)) {
|
if (!File.Exists(cnLogPath) && !File.Exists(osLogPath)) {
|
||||||
throw new ApplicationException(App.ConfigNeedStartGenshin);
|
throw new ApplicationException(App.ConfigNeedStartGenshin);
|
||||||
}
|
}
|
||||||
string latestLogPath;
|
string finalLogPath;
|
||||||
if (!File.Exists(osLogPath)) {
|
if (!File.Exists(osLogPath)) {
|
||||||
latestLogPath = cnLogPath;
|
finalLogPath = cnLogPath;
|
||||||
} else if (!File.Exists(cnLogPath)) {
|
} else if (!File.Exists(cnLogPath)) {
|
||||||
latestLogPath = osLogPath;
|
finalLogPath = osLogPath;
|
||||||
} else {
|
} else {
|
||||||
var cnLastWriteTime = File.GetLastWriteTime(cnLogPath);
|
var cnLastWriteTime = File.GetLastWriteTime(cnLogPath);
|
||||||
var osLastWriteTime = File.GetLastWriteTime(osLogPath);
|
var osLastWriteTime = File.GetLastWriteTime(osLogPath);
|
||||||
latestLogPath = cnLastWriteTime > osLastWriteTime ? cnLogPath : osLogPath;
|
finalLogPath = cnLastWriteTime > osLastWriteTime ? cnLogPath : osLogPath;
|
||||||
}
|
}
|
||||||
var content = File.ReadAllText(latestLogPath);
|
GamePath = GetGamePathFromLogFile(finalLogPath)
|
||||||
|
?? GetGamePathFromLogFile($"{finalLogPath}.last")
|
||||||
|
?? throw new ApplicationException(App.ConfigNeedStartGenshin);
|
||||||
|
pathCacheFile.Write(GamePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetGamePathFromLogFile(string path) {
|
||||||
|
if (!File.Exists(path)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var content = File.ReadAllText(path);
|
||||||
var matchResult = Regex.Match(content, @"(?m).:/.+(GenshinImpact_Data|YuanShen_Data)");
|
var matchResult = Regex.Match(content, @"(?m).:/.+(GenshinImpact_Data|YuanShen_Data)");
|
||||||
var entryName = $"{matchResult.Groups["1"].Value.Replace("_Data", null)}.exe";
|
if (!matchResult.Success) {
|
||||||
GamePath = Path.GetFullPath(entryName, $"{matchResult.Value}/../");
|
return null;
|
||||||
|
}
|
||||||
|
var entryName = matchResult.Groups["1"].Value.Replace("_Data", ".exe");
|
||||||
|
return Path.GetFullPath(Path.Combine(matchResult.Value, "..", entryName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,14 +26,18 @@ public class CacheFile {
|
|||||||
return _content;
|
return _content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(byte[] data, string? etag = null) {
|
public void Write(string data, string? etag = null) => Write(ByteString.CopyFromUtf8(data), data.MD5Hash(), etag);
|
||||||
|
|
||||||
|
public void Write(byte[] data, string? etag = null) => Write(ByteString.CopyFrom(data), data.MD5Hash(), etag);
|
||||||
|
|
||||||
|
private void Write(ByteString data, string hash, string? etag = null) {
|
||||||
using var fOut = File.OpenWrite(_cacheName);
|
using var fOut = File.OpenWrite(_cacheName);
|
||||||
using var cOut = new GZipStream(fOut, CompressionLevel.SmallestSize);
|
using var cOut = new GZipStream(fOut, CompressionLevel.SmallestSize);
|
||||||
new CacheItem {
|
new CacheItem {
|
||||||
Etag = etag ?? string.Empty,
|
Etag = etag ?? string.Empty,
|
||||||
Version = 3,
|
Version = 3,
|
||||||
Checksum = data.MD5Hash(),
|
Checksum = hash,
|
||||||
Content = ByteString.CopyFrom(data)
|
Content = data
|
||||||
}.WriteTo(cOut);
|
}.WriteTo(cOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,19 +5,20 @@ namespace YaeAchievement;
|
|||||||
// ReSharper disable InconsistentNaming
|
// ReSharper disable InconsistentNaming
|
||||||
// ReSharper disable ConvertToConstant.Global
|
// ReSharper disable ConvertToConstant.Global
|
||||||
// ReSharper disable FieldCanBeMadeReadOnly.Global
|
// ReSharper disable FieldCanBeMadeReadOnly.Global
|
||||||
#pragma warning disable CA2211
|
|
||||||
|
|
||||||
public static class GlobalVars {
|
public static class GlobalVars {
|
||||||
|
|
||||||
public static bool DebugProxy = false;
|
public static bool DebugProxy => false;
|
||||||
public static bool CheckGamePath = true;
|
public static bool UnexpectedExit { get; set; }= true;
|
||||||
public static bool UnexpectedExit = true;
|
public static Version AppVersion { get; } = Assembly.GetEntryAssembly()!.GetName().Version!;
|
||||||
public static Version AppVersion = Assembly.GetEntryAssembly()!.GetName().Version!;
|
|
||||||
|
private static readonly string DataDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
|
||||||
|
public static readonly string LibPath = Path.Combine(DataDir, "YaeAchievement.dll");
|
||||||
public static readonly string AppPath = AppDomain.CurrentDomain.BaseDirectory;
|
public static readonly string AppPath = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
|
|
||||||
public const uint AppVersionCode = 29;
|
public const uint AppVersionCode = 29;
|
||||||
public const string AppVersionName = "2.1";
|
public const string AppVersionName = "2.1";
|
||||||
public const string LibName = "YaeLib.dll";
|
|
||||||
public const string PipeName = "YaeAchievementPipe";
|
public const string PipeName = "YaeAchievementPipe";
|
||||||
public const string BucketHost = "https://cn-cd-1259389942.file.myqcloud.com";
|
public const string BucketHost = "https://cn-cd-1259389942.file.myqcloud.com";
|
||||||
|
|
||||||
|
|||||||
17
src/Utils.cs
17
src/Utils.cs
@@ -90,7 +90,7 @@ public static class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info.EnableLibDownload) {
|
if (info.EnableLibDownload) {
|
||||||
File.WriteAllBytes(GlobalVars.LibName, GetBucketFileAsByteArray("schicksal/lib.dll"));
|
File.WriteAllBytes(GlobalVars.LibPath, GetBucketFileAsByteArray("schicksal/lib.dll"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +106,7 @@ public static class Utils {
|
|||||||
Process.LeaveDebugMode();
|
Process.LeaveDebugMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once UnusedMethodReturnValue.Global
|
||||||
public static bool ShellOpen(string path) {
|
public static bool ShellOpen(string path) {
|
||||||
try {
|
try {
|
||||||
return new Process {
|
return new Process {
|
||||||
@@ -128,7 +129,10 @@ public static class Utils {
|
|||||||
public static void CheckGenshinIsRunning() {
|
public static void CheckGenshinIsRunning() {
|
||||||
Process.EnterDebugMode();
|
Process.EnterDebugMode();
|
||||||
foreach (var process in Process.GetProcesses()) {
|
foreach (var process in Process.GetProcesses()) {
|
||||||
if (process.ProcessName is "GenshinImpact" or "YuanShen" && !process.HasExited) {
|
if (process.ProcessName is "GenshinImpact" or "YuanShen"
|
||||||
|
&& !process.HasExited
|
||||||
|
&& process.MainWindowHandle != IntPtr.Zero
|
||||||
|
) {
|
||||||
Console.WriteLine(App.GenshinIsRunning, process.Id);
|
Console.WriteLine(App.GenshinIsRunning, process.Id);
|
||||||
Environment.Exit(301);
|
Environment.Exit(301);
|
||||||
}
|
}
|
||||||
@@ -165,26 +169,23 @@ public static class Utils {
|
|||||||
Console.WriteLine(App.UploadError);
|
Console.WriteLine(App.UploadError);
|
||||||
AppCenter.TrackCrash((Exception) e.ExceptionObject);
|
AppCenter.TrackCrash((Exception) e.ExceptionObject);
|
||||||
AppCenter.Upload();
|
AppCenter.Upload();
|
||||||
Environment.Exit(-1);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
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) {
|
||||||
var dataDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
|
|
||||||
var lib = Path.Combine(dataDir, "yae.dll");
|
|
||||||
File.Copy(Path.GetFullPath(GlobalVars.LibName), lib, true);
|
|
||||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
|
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
|
||||||
try {
|
try {
|
||||||
File.Delete(lib);
|
File.Delete(GlobalVars.LibPath);
|
||||||
} catch (Exception) { /* ignored */ }
|
} catch (Exception) { /* ignored */ }
|
||||||
};
|
};
|
||||||
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)) {
|
||||||
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess fail"));
|
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess fail"));
|
||||||
}
|
}
|
||||||
if (Injector.LoadLibraryAndInject(hProcess, lib) != 0) {
|
if (Injector.LoadLibraryAndInject(hProcess, GlobalVars.LibPath) != 0) {
|
||||||
if (!Native.TerminateProcess(hProcess, 0)) {
|
if (!Native.TerminateProcess(hProcess, 0)) {
|
||||||
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail"));
|
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail"));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user