mirror of
https://github.com/HolographicHat/Yae.git
synced 2025-12-09 16:08:14 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21af4de1a6 | ||
|
|
8e0fd2d27c | ||
|
|
0348cfa365 | ||
|
|
494eda32c2 | ||
|
|
975638c1ee | ||
|
|
793ad075fe | ||
|
|
c82a10353f |
84
README.md
84
README.md
@@ -1,42 +1,42 @@
|
||||
<div align="center"><img width="100" src="https://github.com/HolographicHat/YaeAchievement/blob/master/icon.ico">
|
||||
|
||||
# YaeAchievement
|
||||
|
||||
    
|
||||
|
||||
简体中文 | [English](README_EN.md)
|
||||
</div>
|
||||
|
||||
- 支持导出所有类别的成就
|
||||
- 支持官服,渠道服与国际服
|
||||
- 没有窗口大小、游戏语言等要求
|
||||
|
||||
## 导出支持
|
||||
|
||||
> 按照数字键选择导出方式,<kbd>0</kbd> 为默认导出方式
|
||||
|
||||
0. [椰羊](https://cocogoat.work/achievement)
|
||||
1. [胡桃工具箱](https://github.com/DGP-Studio/Snap.HuTao)
|
||||
2. [Paimon.moe](https://paimon.moe/achievement/)
|
||||
3. [Seelie.me](https://seelie.me/achievements)
|
||||
4. 表格文件 `.csv`
|
||||
5. [寻空](https://github.com/xunkong/xunkong)
|
||||
6. [原魔工具箱](https://apps.apple.com/app/id1663989619)
|
||||
7. [TeyvatGuide](https://github.com/BTMuli/TeyvatGuide)
|
||||
8. [UIAF](https://uigf.org/standards/UIAF.html) JSON 文件
|
||||
|
||||
## 使用说明
|
||||
→ [Tutorial.md](Tutorial.md)
|
||||
|
||||
## 下载地址
|
||||
[releases/latest](https://github.com/HolographicHat/YaeAchievement/releases/latest)
|
||||
|
||||
## 问题反馈
|
||||
[issues](https://github.com/HolographicHat/YaeAchievement/issues)或[QQ群: 913777414](https://qm.qq.com/cgi-bin/qm/qr?k=9UGz-chQVTjZa4b82RA_A41vIcBVNpms&jump_from=webapi)
|
||||
|
||||
## 常见问题
|
||||
0. Q: 打不开
|
||||
A: 安装 [.NET Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-8.0.4-windows-x64-installer)
|
||||
|
||||
1. Q: 原神启动时报错: 数据异常(31-4302)
|
||||
A: 不要把软件和原神主程序放一起
|
||||
<div align="center"><img width="100" src="https://github.com/HolographicHat/YaeAchievement/blob/master/icon.ico">
|
||||
|
||||
# YaeAchievement
|
||||
|
||||
    
|
||||
|
||||
简体中文 | [English](README_EN.md) | [日本語](README_JP.md)
|
||||
</div>
|
||||
|
||||
- 支持导出所有类别的成就
|
||||
- 支持官服,渠道服与国际服
|
||||
- 没有窗口大小、游戏语言等要求
|
||||
|
||||
## 导出支持
|
||||
|
||||
> 按照数字键选择导出方式,<kbd>0</kbd> 为默认导出方式
|
||||
|
||||
0. [椰羊](https://cocogoat.work/achievement)
|
||||
1. [胡桃工具箱](https://github.com/DGP-Studio/Snap.HuTao)
|
||||
2. [Paimon.moe](https://paimon.moe/achievement/)
|
||||
3. [Seelie.me](https://seelie.me/achievements)
|
||||
4. 表格文件 `.csv`
|
||||
5. [寻空](https://github.com/xunkong/xunkong)
|
||||
6. [原魔工具箱](https://apps.apple.com/app/id1663989619)
|
||||
7. [TeyvatGuide](https://github.com/BTMuli/TeyvatGuide)
|
||||
8. [UIAF](https://uigf.org/standards/UIAF.html) JSON 文件
|
||||
|
||||
## 使用说明
|
||||
→ [Tutorial.md](Tutorial.md)
|
||||
|
||||
## 下载地址
|
||||
[releases/latest](https://github.com/HolographicHat/YaeAchievement/releases/latest)
|
||||
|
||||
## 问题反馈
|
||||
[issues](https://github.com/HolographicHat/YaeAchievement/issues)或[QQ群: 913777414](https://qm.qq.com/cgi-bin/qm/qr?k=9UGz-chQVTjZa4b82RA_A41vIcBVNpms&jump_from=webapi)
|
||||
|
||||
## 常见问题
|
||||
0. Q: 打不开
|
||||
A: 安装 [.NET Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-8.0.4-windows-x64-installer)
|
||||
|
||||
1. Q: 原神启动时报错: 数据异常(31-4302)
|
||||
A: 不要把软件和原神主程序放一起
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
    
|
||||
|
||||
[简体中文](README.md) | English
|
||||
[简体中文](README.md) | English | [日本語](README_JP.md)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
44
README_JP.md
Normal file
44
README_JP.md
Normal file
@@ -0,0 +1,44 @@
|
||||
<div align="center"><img width="100" src="https://github.com/HolographicHat/YaeAchievement/blob/master/icon.ico">
|
||||
|
||||
# YaeAchievement
|
||||
|
||||
    
|
||||
|
||||
[简体中文](README.md) | [English](README_EN.md) | 日本語
|
||||
|
||||
</div>
|
||||
|
||||
- すべてのカテゴリの実績のエクスポートをサポート
|
||||
- すべてのバージョンの原神をサポート
|
||||
- ウィンドウサイズ、ゲーム言語などの要件はありません
|
||||
|
||||
## エクスポートサポート
|
||||
|
||||
> 数字キーに従ってエクスポート方法を選択します。<kbd>0</kbd> はデフォルトのエクスポート方法です
|
||||
|
||||
0. [椰羊](https://cocogoat.work/achievement)
|
||||
1. [胡桃ツールボックス](https://github.com/DGP-Studio/Snap.HuTao)
|
||||
2. [Paimon.moe](https://paimon.moe/achievement/)
|
||||
3. [Seelie.me](https://seelie.me/achievements)
|
||||
4. フォームファイル `.csv`
|
||||
5. [尋空](https://github.com/xunkong/xunkong)
|
||||
6. [原魔ツールボックス](https://apps.apple.com/app/id1663989619)
|
||||
7. [TeyvatGuide](https://github.com/BTMuli/TeyvatGuide)
|
||||
8. [UIAF](https://uigf.org/standards/UIAF.html) JSONファイル
|
||||
|
||||
## 使用説明書:
|
||||
→ [Tutorial_JP.md](Tutorial_JP.md)
|
||||
|
||||
## ダウンロード: [こちら](https://github.com/HolographicHat/YaeAchievement/releases/latest)
|
||||
|
||||
## フィードバックや問題?
|
||||
[issues](https://github.com/HolographicHat/YaeAchievement/issues) または [QQ群: 913777414](https://qm.qq.com/cgi-bin/qm/qr?k=9UGz-chQVTjZa4b82RA_A41vIcBVNpms&jump_from=webapi)
|
||||
|
||||
## よくある質問
|
||||
0. Q: 起動できない
|
||||
A: [.NET Runtime 7](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-8.0.4-windows-x64-installer) をダウンロードしてインストールするか、`winget install Microsoft.DotNet.Runtime.8` を実行してください。
|
||||
|
||||
|
||||
1. Q: 原神を起動中にエラーが発生しました: データ例外 (31-4302)
|
||||
A: ソフトウェアを原神のディレクトリに配置しないでください。
|
||||
|
||||
75
Tutorial_JP.md
Normal file
75
Tutorial_JP.md
Normal file
@@ -0,0 +1,75 @@
|
||||
## 使用説明書
|
||||
|
||||
1. YaeAchievement(最新バージョン)をダウンロード:
|
||||
|
||||
こちらをクリック:https://github.com/HolographicHat/YaeAchievement/releases
|
||||
|
||||
赤枠で囲まれた「YaeAchievement.exe」という名前のファイルをクリックすると、自動的にポップアップしてダウンロードされます。このファイルをデスクトップや他の見やすいフォルダに保存することをお勧めします。
|
||||
|
||||

|
||||
|
||||
2. .NET Runtime 7をインストール(ランタイムが既にインストールされている場合はこのステップを無視できます)
|
||||
|
||||
こちらをクリック:https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-8.0.4-windows-x64-installer .
|
||||
|
||||
または、Windows 11を使用しているか、Wingetがインストールされている場合は、`winget install Microsoft.DotNet.Runtime.7`を実行します。
|
||||
|
||||
ウェブページにアクセスすると、ブラウザが自動的にポップアップしてダウンロードされます。ファイルをデスクトップや他の見やすいフォルダに保存します。
|
||||
|
||||
ダウンロードが完了したら、dotnet-runtime-x.x.x-win-x64.exeという名前のファイルを開くと、インストールウィンドウがポップアップします。以下の図のように表示されます。
|
||||
|
||||

|
||||
|
||||
インストールをクリックするだけです。
|
||||
|
||||
3. メインプログラムを開くための操作と実績エクスポートのオプション
|
||||
|
||||
最初のステップでダウンロードした「YaeAchievement.exe」という名前のファイルをダブルクリックして開くと、原神が起動していることを示します。以下の図のように表示されます。
|
||||
|
||||

|
||||
|
||||
原神の起動が完了したら、ゲームに入ります。
|
||||
|
||||
ゲームに入ると、ツールがどのツールにエクスポートするかを選択するように促します。以下の図のように表示されます。
|
||||
|
||||

|
||||
|
||||
グローバルユーザーの場合、[3] Seelie.meまたは[4] csvファイルにエクスポートを選択する必要があります。
|
||||
|
||||
選択後、各ページは次のようにツールをエクスポートします:
|
||||
|
||||
#### Snap.Hutao:
|
||||
|
||||

|
||||
|
||||
#### Seelie.me:
|
||||
|
||||
この時点で、Yae Achievementは実績データがエクスポートされたことを通知します。Yae Achievement保存ディレクトリにexport-20xxxxxxxxxxxx-seelie.jsonという名前のファイルを見つけてください。
|
||||
|
||||

|
||||
|
||||
次に、URL:https://seelie.me/settings をクリックし、ウェブサイトにアクセスしてインポートアカウントを選択します。以下の図のように表示されます。
|
||||
|
||||

|
||||
|
||||
インポートをクリックした後、export-20xxxxxxxxxxxx-seelie.jsonという名前のファイルを選択します。以下の図のように表示されます。
|
||||
|
||||

|
||||
|
||||
以下の図のようなプロンプトが表示されたら、インポートプロセスは成功です。
|
||||
|
||||

|
||||
|
||||
この時点で、左側の列のAchievementsを選択して、インポートされた実績データを表示できます。
|
||||
|
||||
### 各ツールの紹介については、各ツールの公式ページをご覧ください:
|
||||
|
||||
0. [椰羊](https://cocogoat.work/achievement)
|
||||
1. [胡桃ツールボックス](https://github.com/DGP-Studio/Snap.HuTao)
|
||||
2. [Paimon.moe](https://paimon.moe/achievement/)
|
||||
3. [Seelie.me](https://seelie.me/achievements)
|
||||
4. ~~フォームファイル `.csv`~~
|
||||
5. [尋空](https://github.com/xunkong/xunkong)
|
||||
6. [原魔ツールボックス](https://apps.apple.com/app/id1663989619)
|
||||
7. [TeyvatGuide](https://github.com/BTMuli/TeyvatGuide)
|
||||
8. [UIAF](https://uigf.org/standards/UIAF.html) JSONファイル
|
||||
@@ -32,7 +32,7 @@ namespace Hook {
|
||||
|
||||
uint16_t BitConverter_ToUInt16(ByteArray* val, const int startIndex) {
|
||||
const auto ret = CALL_ORIGIN(BitConverter_ToUInt16, val, startIndex);
|
||||
if (ret == 0xAB89 && ReadMapped<UINT16>(val->vector, 2) == 7450) {
|
||||
if (ret == 0xAB89 && ReadMapped<UINT16>(val->vector, 2) == 259) {
|
||||
const auto headLength = ReadMapped<UINT16>(val->vector, 4);
|
||||
const auto dataLength = ReadMapped<UINT32>(val->vector, 6);
|
||||
const auto cStr = base64_encode(val->vector + 10 + headLength, dataLength) + "\n";
|
||||
@@ -45,27 +45,21 @@ namespace Hook {
|
||||
}
|
||||
|
||||
void Run(HMODULE* phModule) {
|
||||
AllocConsole();
|
||||
freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
|
||||
//AllocConsole();
|
||||
//freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
|
||||
while ((unityWnd = FindMainWindowByPID(GetCurrentProcessId())) == nullptr) {
|
||||
Sleep(1000);
|
||||
}
|
||||
Sleep(5000);
|
||||
DisableVMProtect();
|
||||
void* ppRecordUserData = nullptr;
|
||||
InitIL2CPP(ppRecordUserData);
|
||||
if (!ppRecordUserData) {
|
||||
ErrorDialog("ppRecordUserData == nullptr\n");
|
||||
ExitProcess(-1);
|
||||
}
|
||||
InitIL2CPP();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
const auto result = Genshin::RecordUserData(i);
|
||||
checksum += string(reinterpret_cast<char*>(&result->vector[0]), result->max_length);
|
||||
baClass = result->klass;
|
||||
}
|
||||
printf("Checksum=%s\n", checksum.c_str());
|
||||
HookManager::install(Genshin::RecordUserData, Hook::UnityEngine_RecordUserData);
|
||||
HookManager::install(Genshin::BitConverter_ToUInt16, Hook::BitConverter_ToUInt16);
|
||||
*(void**) ppRecordUserData = (void*) &Hook::UnityEngine_RecordUserData;
|
||||
hPipe = CreateFile(R"(\\.\pipe\YaeAchievementPipe)", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hPipe == INVALID_HANDLE_VALUE) {
|
||||
Win32ErrorDialog(1001);
|
||||
|
||||
@@ -2,8 +2,8 @@ using namespace Genshin;
|
||||
|
||||
// DO_APP_FUNC(CN_OFFSET, OS_OFFSET, RETURN, FUNC_NAME, (ARGS...));
|
||||
|
||||
DO_APP_FUNC(0x005DDC40, 0x006A2A90, ByteArray*, il2cpp_array_new_specific, (void* arrayTypeInfo, uint64_t length));
|
||||
DO_APP_FUNC(0x00572860, 0x0056DB70, ByteArray*, il2cpp_array_new_specific, (void* arrayTypeInfo, uint64_t length));
|
||||
|
||||
DO_APP_FUNC(0x06F7D5B0, 0x06C68BE0, ByteArray*, RecordUserData, (int32_t nType));
|
||||
DO_APP_FUNC(0x01663180, 0x0165E180, ByteArray*, RecordUserData, (int32_t nType));
|
||||
|
||||
DO_APP_FUNC(0x0D1C10F0, 0x0D1BA490, uint16_t, BitConverter_ToUInt16, (ByteArray* val, int startIndex));
|
||||
DO_APP_FUNC(0x10986650, 0x10981A40, uint16_t, BitConverter_ToUInt16, (ByteArray* val, int startIndex));
|
||||
|
||||
@@ -15,20 +15,13 @@ namespace Genshin {
|
||||
|
||||
using std::string;
|
||||
|
||||
void InitIL2CPP(void* &ppRecordUserData) {
|
||||
void InitIL2CPP() {
|
||||
TCHAR szFileName[MAX_PATH];
|
||||
GetModuleFileName(nullptr, szFileName, MAX_PATH);
|
||||
const auto isCN = strstr(szFileName, "YuanShen.exe");
|
||||
const auto uBase = reinterpret_cast<uint64_t>(GetModuleHandle("UserAssembly.dll"));
|
||||
_strupr_s(szFileName);
|
||||
const auto isCN = strstr(szFileName, "YUANSHEN.EXE");
|
||||
const auto uBase = reinterpret_cast<uint64_t>(GetModuleHandle(isCN ? "YuanShen.exe" : "GenshinImpact.exe"));
|
||||
#define DO_APP_FUNC(ca, oa, r, n, p) n = (r (*) p)(uBase + (isCN ? ca : oa))
|
||||
#include "il2cpp-functions.h"
|
||||
#undef DO_APP_FUNC
|
||||
auto sPtr = reinterpret_cast<uint8_t*>(RecordUserData);
|
||||
for (int i = 0; i < 0x64; ++i) {
|
||||
if ((*(uint32_t*) sPtr & 0xFFFFFF) == 0x25FF48) { // 48 FF 25 ??
|
||||
ppRecordUserData = sPtr + 7 + *(int*) (sPtr + 3);
|
||||
break;
|
||||
}
|
||||
sPtr += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
// IL2CPP application initializer
|
||||
void InitIL2CPP(void* &ppRecordUserData);
|
||||
void InitIL2CPP();
|
||||
|
||||
90
res/App.Designer.cs
generated
90
res/App.Designer.cs
generated
@@ -9,8 +9,8 @@
|
||||
|
||||
namespace YaeAchievement.res {
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
@@ -22,15 +22,15 @@ namespace YaeAchievement.res {
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class App {
|
||||
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal App() {
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
@@ -44,7 +44,7 @@ namespace YaeAchievement.res {
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
@@ -58,7 +58,7 @@ namespace YaeAchievement.res {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to all achievement.
|
||||
/// </summary>
|
||||
@@ -67,7 +67,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("AllAchievement", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please close another instance..
|
||||
/// </summary>
|
||||
@@ -76,7 +76,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("AnotherInstance", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to YaeAchievement ({0}).
|
||||
/// </summary>
|
||||
@@ -85,7 +85,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("AppBanner", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You need to login genshin impact before exporting..
|
||||
/// </summary>
|
||||
@@ -94,7 +94,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ConfigNeedStartGenshin", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Download: {0}.
|
||||
/// </summary>
|
||||
@@ -103,7 +103,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("DownloadLink", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Network error ({0}: {1}).
|
||||
/// </summary>
|
||||
@@ -112,9 +112,9 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExceptionNetwork", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Export to:
|
||||
/// Looks up a localized string similar to Export to:
|
||||
///[0] Cocogoat (https://cocogoat.work/achievement, Default)
|
||||
///[1] Snap.HuTao
|
||||
///[2] Paimon.moe
|
||||
@@ -130,7 +130,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportChoose", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Fail, please contact developer to get help information.
|
||||
/// </summary>
|
||||
@@ -139,7 +139,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToCocogoatFail", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Successfully exported to cocogoat..
|
||||
/// </summary>
|
||||
@@ -148,7 +148,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToCocogoatSuccess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Successfully exported to {0}.
|
||||
/// </summary>
|
||||
@@ -157,7 +157,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToFileSuccess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please update Snap Hutao and retry..
|
||||
/// </summary>
|
||||
@@ -166,7 +166,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToSnapGenshinNeedUpdate", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Successfully exported to Snap Hutao..
|
||||
/// </summary>
|
||||
@@ -175,7 +175,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToSnapGenshinSuccess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please launch/update Teyvat Guide and retry..
|
||||
/// </summary>
|
||||
@@ -184,7 +184,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToTauriFail", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Successfully exported to Teyvat Guide..
|
||||
/// </summary>
|
||||
@@ -193,7 +193,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToTauriSuccess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0}.
|
||||
/// </summary>
|
||||
@@ -202,7 +202,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToWxApp1Success", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please update xunkong and retry..
|
||||
/// </summary>
|
||||
@@ -211,7 +211,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToXunkongNeedUpdate", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Successfully exported to xunkong..
|
||||
/// </summary>
|
||||
@@ -220,7 +220,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("ExportToXunkongSuccess", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Game process start ({0}).
|
||||
/// </summary>
|
||||
@@ -229,7 +229,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("GameLoading", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Game exited..
|
||||
/// </summary>
|
||||
@@ -238,7 +238,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("GameProcessExit", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please update genshin and retry..
|
||||
/// </summary>
|
||||
@@ -247,7 +247,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("GenshinHashError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please close game before run this application. ({0}).
|
||||
/// </summary>
|
||||
@@ -256,7 +256,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("GenshinIsRunning", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Network error:.
|
||||
/// </summary>
|
||||
@@ -265,7 +265,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("NetworkError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to No write permission on {0}..
|
||||
/// </summary>
|
||||
@@ -274,7 +274,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("NoWritePermission", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Press any key to exit..
|
||||
/// </summary>
|
||||
@@ -283,7 +283,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("PressKeyToExit", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Reward not taken.
|
||||
/// </summary>
|
||||
@@ -292,7 +292,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("StatusFinished", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid.
|
||||
/// </summary>
|
||||
@@ -301,7 +301,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("StatusInvalid", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Finished.
|
||||
/// </summary>
|
||||
@@ -310,7 +310,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("StatusRewardTaken", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unfinished.
|
||||
/// </summary>
|
||||
@@ -319,9 +319,9 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("StatusUnfinished", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Description:
|
||||
/// Looks up a localized string similar to Description:
|
||||
///{0}.
|
||||
/// </summary>
|
||||
internal static string UpdateDescription {
|
||||
@@ -329,7 +329,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("UpdateDescription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Downloading update package....
|
||||
/// </summary>
|
||||
@@ -338,7 +338,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("UpdateDownloading", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Has update: {0} => {1}.
|
||||
/// </summary>
|
||||
@@ -347,7 +347,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("UpdateNewVersion", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Byte[].
|
||||
/// </summary>
|
||||
@@ -357,7 +357,7 @@ namespace YaeAchievement.res {
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Upload error to appcenter....
|
||||
/// </summary>
|
||||
@@ -366,7 +366,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("UploadError", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use previous fetched data? (yes|no).
|
||||
/// </summary>
|
||||
@@ -375,7 +375,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("UsePreviousData", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Downloading Visual C++ Redistributable....
|
||||
/// </summary>
|
||||
@@ -384,7 +384,7 @@ namespace YaeAchievement.res {
|
||||
return ResourceManager.GetString("VcRuntimeDownload", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Installing Visual C++ Redistributable....
|
||||
/// </summary>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI,无需
|
||||
选择加入。选择加入此设置的 Windows 窗体应用程序(面向 .NET Framework 4.6)还应
|
||||
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。
|
||||
|
||||
|
||||
将应用程序设为感知长路径。请参阅 https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
|
||||
@@ -9,11 +9,11 @@ message Achievement {
|
||||
FINISHED = 2;
|
||||
REWARD_TAKEN = 3;
|
||||
}
|
||||
uint32 timestamp = 13;
|
||||
uint32 current = 15;
|
||||
uint32 total = 9;
|
||||
uint32 id = 14;
|
||||
Status status = 8;
|
||||
uint32 timestamp = 8;
|
||||
uint32 current = 3;
|
||||
uint32 total = 4;
|
||||
uint32 id = 15;
|
||||
Status status = 9;
|
||||
}
|
||||
|
||||
message AchievementAllDataNotify {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using YaeAchievement.res;
|
||||
|
||||
namespace YaeAchievement;
|
||||
namespace YaeAchievement;
|
||||
|
||||
public static partial class AppConfig {
|
||||
|
||||
|
||||
public static string GamePath { get; private set; } = null!;
|
||||
|
||||
internal static void Load(string argumentPath) {
|
||||
@@ -36,8 +36,8 @@ public static partial class AppConfig {
|
||||
var osLastWriteTime = File.GetLastWriteTime(osLogPath);
|
||||
finalLogPath = cnLastWriteTime > osLastWriteTime ? cnLogPath : osLogPath;
|
||||
}
|
||||
GamePath = GetGamePathFromLogFile(finalLogPath)
|
||||
?? GetGamePathFromLogFile($"{finalLogPath}.last")
|
||||
GamePath = GetGamePathFromLogFile(finalLogPath)
|
||||
?? GetGamePathFromLogFile($"{finalLogPath}.last")
|
||||
?? throw new ApplicationException(App.ConfigNeedStartGenshin);
|
||||
pathCacheFile.Write(GamePath);
|
||||
}
|
||||
@@ -62,5 +62,5 @@ public static partial class AppConfig {
|
||||
|
||||
[GeneratedRegex(@"(?m).:/.+(GenshinImpact_Data|YuanShen_Data)", RegexOptions.IgnoreCase)]
|
||||
private static partial Regex GamePathRegex();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
using Google.Protobuf;
|
||||
using Proto;
|
||||
|
||||
namespace YaeAchievement;
|
||||
namespace YaeAchievement;
|
||||
|
||||
public class CacheFile(string identifier) {
|
||||
|
||||
private readonly string _cacheName = Path.Combine(GlobalVars.CachePath, $"{identifier.MD5Hash()[..16]}.miko");
|
||||
private CacheItem? _content;
|
||||
|
||||
|
||||
public DateTime LastWriteTime => Exists() ? File.GetLastWriteTimeUtc(_cacheName) : DateTime.UnixEpoch;
|
||||
|
||||
public bool Exists() => File.Exists(_cacheName);
|
||||
@@ -25,7 +25,7 @@ public class CacheFile(string identifier) {
|
||||
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) {
|
||||
using var fOut = File.OpenWrite(_cacheName);
|
||||
using var cOut = new GZipStream(fOut, CompressionLevel.SmallestSize);
|
||||
|
||||
@@ -9,7 +9,7 @@ using Proto;
|
||||
using YaeAchievement.res;
|
||||
using static Proto.Achievement.Types;
|
||||
|
||||
namespace YaeAchievement;
|
||||
namespace YaeAchievement;
|
||||
|
||||
public static class Export {
|
||||
|
||||
@@ -45,7 +45,7 @@ public static class Export {
|
||||
private class CocogoatResponse {
|
||||
[JsonPropertyName("key")] public string Code { get; init; } = null!;
|
||||
}
|
||||
|
||||
|
||||
private static void ToCocogoat(AchievementAllDataNotify data) {
|
||||
var result = JsonSerializer.Serialize(ExportToUIAFApp(data));
|
||||
using var request = new HttpRequestMessage();
|
||||
@@ -63,7 +63,7 @@ public static class Export {
|
||||
? App.ExportToCocogoatSuccess
|
||||
: $"https://cocogoat.work/achievement?memo={responseJson.Code}");
|
||||
}
|
||||
|
||||
|
||||
private static void ToWxApp1(AchievementAllDataNotify data) {
|
||||
var id = Guid.NewGuid().ToString("N").Substring(20, 8);
|
||||
var result = JsonSerializer.Serialize(new Dictionary<string, object> {
|
||||
@@ -88,7 +88,7 @@ public static class Export {
|
||||
Utils.ShellOpen("ms-windows-store://pdp/?productid=9PH4NXJ2JN52");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void ToXunkong(AchievementAllDataNotify data) {
|
||||
if (CheckWinUIAppScheme("xunkong")) {
|
||||
Utils.CopyToClipboard(JsonSerializer.Serialize(ExportToUIAFApp(data)));
|
||||
@@ -139,7 +139,7 @@ public static class Export {
|
||||
Console.WriteLine(App.ExportToFileSuccess, path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void ToSeelie(AchievementAllDataNotify data) {
|
||||
var output = new Dictionary<uint, Dictionary<string, bool>>();
|
||||
foreach (var ach in data.List.Where(a => a.Status is Status.Finished or Status.RewardTaken)) {
|
||||
@@ -227,7 +227,7 @@ public static class Export {
|
||||
private static string JoinToString(this IEnumerable<object> list, string separator) {
|
||||
return string.Join(separator, list);
|
||||
}
|
||||
|
||||
|
||||
private static readonly List<uint> UnusedAchievement = [ 84517 ];
|
||||
|
||||
private static string ToDesc(this Status status) {
|
||||
|
||||
@@ -10,21 +10,21 @@ public static class Extensions {
|
||||
private static readonly Lazy<MD5> md5 = new (MD5.Create);
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static readonly Lazy<SHA1> sha1 = new (SHA1.Create);
|
||||
|
||||
|
||||
public static byte[] ToBytes(this string text) {
|
||||
return Encoding.UTF8.GetBytes(text);
|
||||
}
|
||||
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static string MD5Hash(this string text) {
|
||||
return text.ToBytes().MD5Hash();
|
||||
}
|
||||
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static string MD5Hash(this byte[] data) {
|
||||
return md5.Value.ComputeHash(data).ToHex().ToLower();
|
||||
}
|
||||
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static string SHA1Hash(this string text, bool base64 = true) {
|
||||
var bytes = sha1.Value.ComputeHash(text.ToBytes());
|
||||
@@ -34,7 +34,7 @@ public static class Extensions {
|
||||
public static string ToHex(this byte[] bytes) {
|
||||
return Convert.ToHexString(bytes);
|
||||
}
|
||||
|
||||
|
||||
public static string ToBase64(this byte[] bytes) {
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace YaeAchievement;
|
||||
namespace YaeAchievement;
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
// ReSharper disable ConvertToConstant.Global
|
||||
@@ -8,21 +8,21 @@ namespace YaeAchievement;
|
||||
// ReSharper disable once MemberCanBePrivate.Global
|
||||
|
||||
public static class GlobalVars {
|
||||
|
||||
|
||||
public static bool DebugProxy => false;
|
||||
public static bool UnexpectedExit { get; set; } = true;
|
||||
public static bool PauseOnExit { get; set; } = true;
|
||||
public static Version AppVersion { get; } = Assembly.GetEntryAssembly()!.GetName().Version!;
|
||||
|
||||
|
||||
public static readonly string AppPath = AppDomain.CurrentDomain.BaseDirectory;
|
||||
private static readonly string CommonData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
|
||||
public static readonly string DataPath = Path.Combine(CommonData, "Yae");
|
||||
public static readonly string CachePath = Path.Combine(DataPath, "cache");
|
||||
public static readonly string LibFilePath = Path.Combine(DataPath, "YaeAchievement.dll");
|
||||
|
||||
public const uint AppVersionCode = 47;
|
||||
public const string AppVersionName = "3.7";
|
||||
|
||||
|
||||
public const uint AppVersionCode = 50;
|
||||
public const string AppVersionName = "4.0";
|
||||
|
||||
public const string PipeName = "YaeAchievementPipe";
|
||||
public const string BucketHost = "https://cn-cd-1259389942.file.myqcloud.com";
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ using Windows.Win32.System.Threading;
|
||||
namespace YaeAchievement;
|
||||
|
||||
public static class Injector {
|
||||
|
||||
|
||||
public static unsafe bool CreateProcess(string path, out HANDLE hProc, out HANDLE hThread, out uint pid) {
|
||||
Span<char> cmdLines = stackalloc char[1]; // "\0"
|
||||
var si = new STARTUPINFOW {
|
||||
|
||||
16
src/Utils.cs
16
src/Utils.cs
@@ -62,7 +62,7 @@ public static class Utils {
|
||||
public static uint? ToUIntOrNull(string? value) {
|
||||
return value != null ? uint.TryParse(value, out var result) ? result : null : null;
|
||||
}
|
||||
|
||||
|
||||
public static bool ToBooleanOrFalse(string? value) {
|
||||
return value != null && bool.TryParse(value, out var result) && result;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ public static class Utils {
|
||||
|
||||
// ReSharper disable once NotAccessedField.Local
|
||||
private static UpdateInfo _updateInfo = null!;
|
||||
|
||||
|
||||
public static void CheckUpdate(bool useLocalLib) {
|
||||
var info = UpdateInfo.Parser.ParseFrom(GetBucketFileAsByteArray("schicksal/version"))!;
|
||||
if (GlobalVars.AppVersionCode < info.VersionCode) {
|
||||
@@ -160,8 +160,8 @@ public static class Utils {
|
||||
public static void CheckGenshinIsRunning() {
|
||||
Process.EnterDebugMode();
|
||||
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 != nint.Zero
|
||||
) {
|
||||
Console.WriteLine(App.GenshinIsRunning, process.Id);
|
||||
@@ -170,10 +170,10 @@ public static class Utils {
|
||||
}
|
||||
Process.LeaveDebugMode();
|
||||
}
|
||||
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static Process? proc;
|
||||
|
||||
|
||||
public static void InstallExitHook() {
|
||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
|
||||
proc?.Kill();
|
||||
@@ -222,7 +222,7 @@ public static class Utils {
|
||||
Environment.Exit(0);
|
||||
}
|
||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
|
||||
try {
|
||||
try {
|
||||
File.Delete(GlobalVars.LibFilePath);
|
||||
} catch (Exception) { /* ignored */ }
|
||||
};
|
||||
@@ -293,7 +293,7 @@ public static class Utils {
|
||||
}
|
||||
})
|
||||
.Select(item => item?.GetValue("DisplayName") as string ?? string.Empty)
|
||||
.Any(name => name.Contains("Microsoft Visual C++ 2022 X64 "));
|
||||
.Any(name => name.Contains("Microsoft Visual C++ 2022 X64 ") || name.Contains("Microsoft Visual C++ 2015-2022 Redistributable (x64)"));
|
||||
if (!installed) {
|
||||
Console.WriteLine(App.VcRuntimeDownload);
|
||||
var pkgPath = Path.Combine(GlobalVars.DataPath, "vc_redist.x64.exe");
|
||||
|
||||
Reference in New Issue
Block a user