24 Commits
2.9.0 ... 3.2.0

Author SHA1 Message Date
HolographicHat
feb7ac44da 4.2 2023-11-09 21:39:05 +08:00
HolographicHat
3924129560 Merge pull request #74 from Lightczx/master
Disable marshalling
2023-10-30 14:04:24 +08:00
Lightczx
4f7f0cdfd2 disable marshalling 2023-10-30 13:51:01 +08:00
HolographicHat
cf0753c676 Merge pull request #73 from BTMuli/master
🐛 修复 TeyvatGuide 链接错误
2023-10-16 13:42:22 +08:00
BTMuli
0b895d47ca 🐛 修复 TeyvatGuide 链接错误 2023-10-16 12:39:32 +08:00
HolographicHat
78d2722e20 Merge pull request #72 from BTMuli/master
更新文档
2023-10-15 01:16:19 +08:00
BTMuli
385c673323 🚨 revert,删除多余空格 2023-10-15 00:31:18 +08:00
BTMuli
50beb2cce7 🚨 修复 CI 报错 2023-10-15 00:18:39 +08:00
BTMuli
324a4153e0 📝 删除混入其中的表格文件 2023-10-14 23:56:24 +08:00
BTMuli
3de459aceb 📝 更新部分信息 2023-10-14 23:54:49 +08:00
BTMuli
295bb89177 📝 更新导出说明 2023-10-14 23:50:31 +08:00
HolographicHat
baaf4e8227 rollback 2023-10-13 21:22:54 +08:00
HolographicHat
f41fe6fb12 4.1
* #71
2023-09-28 18:48:00 +08:00
HolographicHat
78bda3f49c Merge pull request #70 from BTMuli/master
#67
2023-09-23 00:00:30 +08:00
BTMuli
a10dc22461 🎨 修正检测方式 2023-09-22 23:39:37 +08:00
HolographicHat
74dda750ef Merge pull request #69 from Masterain98/master
Update GitLab CI configuration
2023-09-22 21:15:21 +08:00
Masterain
099270ad29 Update .gitlab-ci.yml 2023-09-21 23:42:47 -07:00
Masterain
fe5b2c0c12 Update .gitlab-ci.yml 2023-09-21 23:35:17 -07:00
HolographicHat
ed5d99745c Merge pull request #68 from Masterain98/master
Create GitLab CI Config File
2023-09-21 23:46:58 +08:00
Masterain
7175cd7427 Create .gitlab-ci.yml 2023-09-21 00:01:13 -07:00
HolographicHat
73747bcce5 #67 2023-09-19 22:28:58 +08:00
HolographicHat
b12c3209d7 fix ci 2023-08-27 11:39:40 +08:00
HolographicHat
5805070627 4.0.1 (fix #64) 2023-08-24 00:16:44 +08:00
HolographicHat
811daba164 4.0 2023-08-16 20:00:06 +08:00
23 changed files with 277 additions and 2444 deletions

View File

@@ -20,7 +20,7 @@ jobs:
- name: Restore dependencies - name: Restore dependencies
run: dotnet restore run: dotnet restore
- name: Build - name: Build
run: dotnet build --no-restore run: dotnet build -c Release --no-restore
- name: Publish - name: Publish
run: dotnet publish --property:OutputPath=.\publish\ run: dotnet publish --property:OutputPath=.\publish\
- name: Upload artifact - name: Upload artifact

64
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,64 @@
stages:
- test
- build
- release
Test:
stage: test
image: mcr.microsoft.com/windows/server
tags:
- windows
script:
- dotnet restore
- dotnet build -c Release --no-restore
- dotnet publish --property:OutputPath=.\publish\
- Move-Item -Path .\publish\publish\*.exe -Destination ..\ -Force
Build:
stage: build
only:
- tags
tags:
- windows
needs:
- job: Test
script:
- echo "This is build stage."
- Move-Item -Path ..\YaeAchievement.exe .\ -Force
after_script:
- echo "Current Job ID is $CI_JOB_ID"
- echo "THIS_JOB_ID=$CI_JOB_ID" >> build.env
artifacts:
paths:
- .\*.exe
expire_in: 90 days
reports:
dotenv: build.env
release:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
only:
- tags
needs:
- job: Build
artifacts: true
variables:
TAG: '$CI_COMMIT_TAG'
script:
- echo "Create Release $TAG"
- echo "$THIS_JOB_ID"
release:
name: '$TAG'
tag_name: '$TAG'
ref: '$TAG'
description: 'Release $TAG by CI'
assets:
links:
- name: "YaeAchievement.exe"
url: "https://$CI_SERVER_SHELL_SSH_HOST/$CI_PROJECT_PATH/-/jobs/$THIS_JOB_ID/artifacts/raw/YaeAchievement.exe?inline=false"
link_type: package
- name: ".NET 7.0 Desktop Runtime"
url: "https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/runtime-desktop-7.0.11-windows-x64-installer"
link_type: other

View File

@@ -9,9 +9,22 @@
- 支持导出所有类别的成就 - 支持导出所有类别的成就
- 支持官服,渠道服与国际服 - 支持官服,渠道服与国际服
- 支持导出至[椰羊](https://cocogoat.work/achievement)、[Snap·HuTao](https://github.com/DGP-Studio/Snap.HuTao)、[Paimon.moe](https://paimon.moe/achievement/)、[Seelie.me](https://seelie.me/achievements)、[寻空](https://github.com/xunkong/xunkong)和表格文件(csv)
- 没有窗口大小、游戏语言等要求 - 没有窗口大小、游戏语言等要求
## 导出支持
> 按照数字键选择导出方式,<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) → [Tutorial.md](Tutorial.md)

View File

@@ -13,9 +13,22 @@
- Support for exporting all categories of achievements - Support for exporting all categories of achievements
- Supports all versions of Genshin Impact - Supports all versions of Genshin Impact
- Support for exporting to [Cocogoat](https://cocogoat.work/achievement), [Snap·HuTao](https://github.com/DGP-Studio/Snap.HuTao), [Paimon.moe](https://paimon.moe/achievement/), [Seelie.me](https://seelie.me/achievements)、[XunKong](https://github.com/xunkong/xunkong) and form files (csv)
- There are no requirements for window size, game language, etc. - There are no requirements for window size, game language, etc.
## Export support
> Select the export method according to the number keys, <kbd>0</kbd> is the default export method
0. [Cocogoat](https://cocogoat.work/achievement)
1. [Snap HuTao](https://github.com/DGP-Studio/Snap.HuTao)
2. [Paimon.moe](https://paimon.moe/achievement/)
3. [Seelie.me](https://seelie.me/achievements)
4. Form File `.csv`
5. [XunKong](https://github.com/xunkong/xunkong)
6. [YuanmoTools](https://apps.apple.com/app/id1663989619)
7. [TeyvatGuide](https://github.com/BTMuli/TeyvatGuide)
8. [UIAF](https://uigf.org/standards/UIAF.html) JSON file
## Instructions for Use: ## Instructions for Use:
→ [Tutorial_EN.md](Tutorial_EN.md) → [Tutorial_EN.md](Tutorial_EN.md)

View File

@@ -71,11 +71,11 @@
### 各种工具的介绍烦请移步至各工具的官方页面进行查看(下方序号对应导出序号) ### 各种工具的介绍烦请移步至各工具的官方页面进行查看(下方序号对应导出序号)
0. [椰羊](https://cocogoat.work/achievement) 0. [椰羊](https://cocogoat.work/achievement)
1. [胡桃工具箱](https://github.com/DGP-Studio/Snap.HuTao)
1. [Snap·HuTao](https://github.com/DGP-Studio/Snap.HuTao)
2. [Paimon.moe](https://paimon.moe/achievement/) 2. [Paimon.moe](https://paimon.moe/achievement/)
3. [Seelie.me](https://seelie.me/achievements) 3. [Seelie.me](https://seelie.me/achievements)
4. ~~表格文件 `.csv`~~
4. [寻空](https://github.com/xunkong/xunkong) 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 文件

View File

@@ -65,9 +65,12 @@ At this time, you can select the Achievements in the left column to view the imp
### For the introduction of different tools, please visit the official page of each tool to see: ### For the introduction of different tools, please visit the official page of each tool to see:
1. [Snap·HuTao](https://github.com/DGP-Studio/Snap.HuTao) 0. [Cocogoat](https://cocogoat.work/achievement)
1. [Snap HuTao](https://github.com/DGP-Studio/Snap.HuTao)
2. [Paimon.moe](https://paimon.moe/achievement/) 2. [Paimon.moe](https://paimon.moe/achievement/)
3. [Seelie.me](https://seelie.me/achievements) 3. [Seelie.me](https://seelie.me/achievements)
4. ~~Form File `.csv`~~
5. [XunKong](https://github.com/xunkong/xunkong)
6. [YuanmoTools](https://apps.apple.com/app/id1663989619)
7. [Teyvat Guide](https://github.com/BTMuli/TeyvatGuide)
8. [UIAF](https://uigf.org/standards/UIAF.html) JSON file

View File

@@ -8,8 +8,8 @@ using std::to_string;
HWND unityWnd = nullptr; HWND unityWnd = nullptr;
HANDLE hPipe = nullptr; HANDLE hPipe = nullptr;
// Allow Protocol: GetPlayerToken, PlayerLogin, AchievementAllDataNotify, Ping, PlayerForceExit // Allow Protocol: GetPlayerTokenRsp, PlayerLoginRsp, AchievementAllDataNotify, PingRsp
std::set<UINT16> PacketWhitelist = { 6929, 7187, 4356, 6011, 1268, 24845, 24404, 29313 }; std::set<UINT16> PacketWhitelist = { 1574, 1548, 29462, 2794 };
bool OnPacket(KcpPacket* pkt) { bool OnPacket(KcpPacket* pkt) {
if (pkt->data == nullptr) return true; if (pkt->data == nullptr) return true;
@@ -30,11 +30,10 @@ bool OnPacket(KcpPacket* pkt) {
return false; return false;
} }
printf("Passed cmdid: %d\n", ReadMapped<UINT16>(data->vector, 2)); printf("Passed cmdid: %d\n", ReadMapped<UINT16>(data->vector, 2));
if (ReadMapped<UINT16>(data->vector, 2) == 1268) { if (ReadMapped<UINT16>(data->vector, 2) == 29462) {
auto headLength = ReadMapped<UINT16>(data->vector, 4); const auto headLength = ReadMapped<UINT16>(data->vector, 4);
auto dataLength = ReadMapped<UINT32>(data->vector, 6); const auto dataLength = ReadMapped<UINT32>(data->vector, 6);
auto iStr = Genshin::ToBase64String(data, 10 + headLength, dataLength, nullptr); const auto cStr = base64_encode(data->vector + 10 + headLength, dataLength) + "\n";
auto cStr = ToString(iStr) + "\n";
WriteFile(hPipe, cStr.c_str(), cStr.length(), nullptr, nullptr); WriteFile(hPipe, cStr.c_str(), cStr.length(), nullptr, nullptr);
CloseHandle(hPipe); CloseHandle(hPipe);
auto manager = Genshin::GetSingletonInstance(Genshin::GetSingletonManager(), il2cpp_string_new("GameManager")); auto manager = Genshin::GetSingletonInstance(Genshin::GetSingletonManager(), il2cpp_string_new("GameManager"));
@@ -48,18 +47,14 @@ std::string checksum;
namespace Hook { namespace Hook {
int KcpSend(void* client, KcpPacket* pkt, void* method) {
return OnPacket(pkt) ? CALL_ORIGIN(KcpSend, client, pkt, method) : 0;
}
void SetVersion(void* obj, Il2CppString* value, void* method) { void SetVersion(void* obj, Il2CppString* value, void* method) {
auto version = ToString(value); const auto version = ToString(value);
value = string_new(version + " YaeAchievement"); value = string_new(version + " YaeAchievement");
CALL_ORIGIN(SetVersion, obj, value, method); CALL_ORIGIN(SetVersion, obj, value, method);
} }
bool KcpRecv(void* client, ClientKcpEvent* evt, void* method) { bool KcpRecv(void* client, ClientKcpEvent* evt, void* method) {
auto result = CALL_ORIGIN(KcpRecv, client, evt, method); const auto result = CALL_ORIGIN(KcpRecv, client, evt, method);
if (result == 0 || evt->fields.type != KcpEventType::EventRecvMsg) { if (result == 0 || evt->fields.type != KcpEventType::EventRecvMsg) {
return result; return result;
} }
@@ -67,7 +62,7 @@ namespace Hook {
} }
ByteArray* UnityEngine_RecordUserData(INT type) { ByteArray* UnityEngine_RecordUserData(INT type) {
return Genshin::GetBytes(Genshin::GetDefaultEncoding(), il2cpp_string_new("")); return new ByteArray {};
} }
VOID SetChecksum(LPVOID obj, Il2CppString* value) { VOID SetChecksum(LPVOID obj, Il2CppString* value) {
@@ -84,20 +79,16 @@ namespace Hook {
void Run(HMODULE* phModule) { void Run(HMODULE* phModule) {
//AllocConsole(); //AllocConsole();
//freopen_s((FILE**)stdout, "CONOUT$", "w", stdout); //freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
while ( while ((unityWnd = FindMainWindowByPID(GetCurrentProcessId())) == nullptr) {
GetModuleHandle("UserAssembly.dll") == nullptr ||
(unityWnd = FindMainWindowByPID(GetCurrentProcessId())) == nullptr
) {
Sleep(1000); Sleep(1000);
} }
Sleep(5000); Sleep(5000);
DisableVMProtect(); DisableVMProtect();
InitIL2CPP(); InitIL2CPP();
auto enc = Genshin::GetDefaultEncoding();
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
checksum += ToString(Genshin::GetString(enc, Genshin::RecordUserData(i))); const auto result = Genshin::RecordUserData(i);
checksum += string(reinterpret_cast<char*>(&result->vector[0]), result->max_length);
} }
HookManager::install(Genshin::KcpSend, Hook::KcpSend);
HookManager::install(Genshin::KcpRecv, Hook::KcpRecv); HookManager::install(Genshin::KcpRecv, Hook::KcpRecv);
HookManager::install(Genshin::SetVersion, Hook::SetVersion); HookManager::install(Genshin::SetVersion, Hook::SetVersion);
HookManager::install(Genshin::RequestLogin, Hook::RequestLogin); HookManager::install(Genshin::RequestLogin, Hook::RequestLogin);

View File

@@ -1 +1 @@
DO_API(0x941c20, 0x93e230, Il2CppString*, il2cpp_string_new, (const char* str)); DO_API(0x4243d0, 0x420bf0, Il2CppString*, il2cpp_string_new, (const char* str));

View File

@@ -2,30 +2,20 @@ using namespace Genshin;
// DO_APP_FUNC(CN_OFFSET, OS_OFFSET, RETURN, FUNC_NAME, (ARGS...)); // DO_APP_FUNC(CN_OFFSET, OS_OFFSET, RETURN, FUNC_NAME, (ARGS...));
DO_APP_FUNC(0x728b850, 0x7247520, Il2CppString*, ToBase64String, (ByteArray* value, int offset, int length, void* method)); DO_APP_FUNC(0x1929870, 0x1922c30, void, SetVersion, (void* obj, Il2CppString* value, void* method));
DO_APP_FUNC(0x215d110, 0x214d7a0, void, SetVersion, (void* obj, Il2CppString* value, void* method)); DO_APP_FUNC(0x6e7d020, 0x6e38a10, ByteArray*, RecordUserData, (int32_t nType));
DO_APP_FUNC(0x7b4dc00, 0x7afe4e0, ByteArray*, RecordUserData, (int32_t nType)); DO_APP_FUNC(0x2b13f40, 0x2b09ce0, void, XorEncrypt, (ByteArray** data, int length, void* method));
DO_APP_FUNC(0x166e5d0, 0x1662f60, void, XorEncrypt, (ByteArray** data, int length, void* method)); DO_APP_FUNC(0x2d79560, 0x2d6e6f0, bool, KcpRecv, (void* client, ClientKcpEvent* evt, void* method));
DO_APP_FUNC(0xf71860, 0xf69870, int, KcpSend, (void* client, KcpPacket* pkt, void* method)); DO_APP_FUNC(0x20004f0, 0x1ff8530, VOID, RequestLogin, (LPVOID obj, LPVOID token, UINT uid));
DO_APP_FUNC(0x433e670, 0x4315590, bool, KcpRecv, (void* client, ClientKcpEvent* evt, void* method)); DO_APP_FUNC(0x130ead0, 0x1b90950, VOID, SetChecksum, (LPVOID obj, Il2CppString* value));
DO_APP_FUNC(0x75627b0, 0x751a960, LPVOID, GetDefaultEncoding, ()); DO_APP_FUNC(0x2266e40, 0x225eb50, VOID, ForceQuit, (LPVOID obj));
DO_APP_FUNC(0x7561ff0, 0x751a1c0, Il2CppString*, GetString, (LPVOID encoding, LPVOID bytes)); DO_APP_FUNC(0x60af410, 0x60735f0, LPVOID, GetSingletonManager, ());
DO_APP_FUNC(0x7560d90, 0x7518f90, ByteArray*, GetBytes, (LPVOID encoding, LPVOID str)); DO_APP_FUNC(0x60af140, 0x6073320, LPVOID, GetSingletonInstance, (LPVOID obj, Il2CppString* value));
DO_APP_FUNC(0x1349850, 0x13415f0, VOID, RequestLogin, (LPVOID obj, LPVOID token, UINT uid));
DO_APP_FUNC(0x11ab1d0, 0x3e9f710, VOID, SetChecksum, (LPVOID obj, Il2CppString* value));
DO_APP_FUNC(0xd4e730, 0xd49dd0, VOID, ForceQuit, (LPVOID obj));
DO_APP_FUNC(0x607fbf0, 0x6044870, LPVOID, GetSingletonManager, ());
DO_APP_FUNC(0x607f920, 0x60445a0, LPVOID, GetSingletonInstance, (LPVOID obj, Il2CppString* value));

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,3 @@
using namespace Genshin; using namespace Genshin;
DO_UNI_FUNC(0x100560, 0x100560, ByteArray*, UnityEngine_RecordUserData, (int32_t nType)); DO_UNI_FUNC(0x105550, 0x105550, ByteArray*, UnityEngine_RecordUserData, (int32_t nType));

View File

@@ -68,3 +68,38 @@ HWND FindMainWindowByPID(DWORD pid) {
} }
#pragma endregion #pragma endregion
static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string base64_encode(BYTE const* buf, unsigned int bufLen) {
std::string ret;
int i = 0;
BYTE char_array_3[3];
BYTE char_array_4[4];
while (bufLen--) {
char_array_3[i++] = *buf++;
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; (i < 4); i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i) {
int j;
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; j < i + 1; j++)
ret += base64_chars[char_array_4[j]];
while (i++ < 3)
ret += '=';
}
return ret;
}

View File

@@ -6,6 +6,7 @@ VOID DisableVMProtect();
bool IsLittleEndian(); bool IsLittleEndian();
HWND FindMainWindowByPID(DWORD pid); HWND FindMainWindowByPID(DWORD pid);
string ToString(Il2CppString* str, UINT codePage = CP_ACP); string ToString(Il2CppString* str, UINT codePage = CP_ACP);
std::string base64_encode(BYTE const* buf, unsigned int bufLen);
#define cstring_new(str) il2cpp_string_new(str) #define cstring_new(str) il2cpp_string_new(str)
#define string_new(str) cstring_new((str).c_str()) #define string_new(str) cstring_new((str).c_str())

22
res/App.Designer.cs generated
View File

@@ -121,7 +121,9 @@ namespace YaeAchievement.res {
///[3] Seelie.me ///[3] Seelie.me
///[4] Csv file ///[4] Csv file
///[5] Xunkong ///[5] Xunkong
///Input a number (0-5): . ///[7] Teyvat Guide
///[8] UIAF JSON File
///Input a number (0-8): .
/// </summary> /// </summary>
internal static string ExportChoose { internal static string ExportChoose {
get { get {
@@ -174,6 +176,24 @@ namespace YaeAchievement.res {
} }
} }
/// <summary>
/// Looks up a localized string similar to Please launch/update Teyvat Guide and retry..
/// </summary>
internal static string ExportToTauriFail {
get {
return ResourceManager.GetString("ExportToTauriFail", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Successfully exported to Teyvat Guide..
/// </summary>
internal static string ExportToTauriSuccess {
get {
return ResourceManager.GetString("ExportToTauriSuccess", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to {0}. /// Looks up a localized string similar to {0}.
/// </summary> /// </summary>

View File

@@ -32,7 +32,9 @@
[3] Seelie.me [3] Seelie.me
[4] Csv file [4] Csv file
[5] Xunkong [5] Xunkong
Input a number (0-5): </value> [7] Teyvat Guide
[8] UIAF JSON File
Input a number (0-8): </value>
</data> </data>
<data name="ExportToCocogoatSuccess" xml:space="preserve"> <data name="ExportToCocogoatSuccess" xml:space="preserve">
<value>Successfully exported to cocogoat.</value> <value>Successfully exported to cocogoat.</value>
@@ -129,4 +131,10 @@ Input a number (0-5): </value>
<data name="NoWritePermission" xml:space="preserve"> <data name="NoWritePermission" xml:space="preserve">
<value>No write permission on {0}.</value> <value>No write permission on {0}.</value>
</data> </data>
<data name="ExportToTauriSuccess" xml:space="preserve">
<value>Successfully exported to Teyvat Guide.</value>
</data>
<data name="ExportToTauriFail" xml:space="preserve">
<value>Please launch/update Teyvat Guide and retry.</value>
</data>
</root> </root>

View File

@@ -26,8 +26,9 @@
[4] 表格文件 [4] 表格文件
[5] 寻空 [5] 寻空
[6] 原魔工具箱 [6] 原魔工具箱
[7] UIAF JSON 文件 [7] Teyvat Guide
输入一个数字 (0-7): </value> [8] UIAF JSON 文件
输入一个数字 (0-8): </value>
</data> </data>
<data name="ExportToCocogoatSuccess" xml:space="preserve"> <data name="ExportToCocogoatSuccess" xml:space="preserve">
<value>在浏览器内进行下一步操作</value> <value>在浏览器内进行下一步操作</value>
@@ -115,9 +116,15 @@
<value>网络错误,请检查网络后重试 ({0}: {1})</value> <value>网络错误,请检查网络后重试 ({0}: {1})</value>
</data> </data>
<data name="GenshinHashError" xml:space="preserve"> <data name="GenshinHashError" xml:space="preserve">
<value>请将原神更新至最新版本后重试</value> <value>当前适配版本不匹配,请更新原神至最新版本后重试或等待工具更新。</value>
</data> </data>
<data name="NoWritePermission" xml:space="preserve"> <data name="NoWritePermission" xml:space="preserve">
<value>无法写入文件,请更换软件所在目录后重试</value> <value>无法写入文件,请更换软件所在目录后重试</value>
</data> </data>
<data name="ExportToTauriFail" xml:space="preserve">
<value>启动 Teyvat Guide 或更新 Teyvat Guide 至最新版本后重试</value>
</data>
<data name="ExportToTauriSuccess" xml:space="preserve">
<value>在 Teyvat Guide 进行下一步操作</value>
</data>
</root> </root>

View File

@@ -9,13 +9,13 @@ message Achievement {
FINISHED = 2; FINISHED = 2;
REWARD_TAKEN = 3; REWARD_TAKEN = 3;
} }
uint32 timestamp = 3; uint32 timestamp = 11;
uint32 current = 9; uint32 current = 12;
uint32 total = 11; uint32 total = 3;
uint32 id = 14; uint32 id = 15;
Status status = 10; Status status = 7;
} }
message AchievementAllDataNotify { message AchievementAllDataNotify {
repeated Achievement list = 3; repeated Achievement list = 8;
} }

View File

@@ -32,8 +32,9 @@ public static class Export {
4 => ToCSV, 4 => ToCSV,
5 => ToXunkong, 5 => ToXunkong,
6 => ToWxApp1, 6 => ToWxApp1,
7 => ToUIAFJson, 7 => ToTeyvatGuide,
8 => ToRawJson, 8 => ToUIAFJson,
9 => ToRawJson,
_ => ToCocogoat _ => ToCocogoat
})).Invoke(data); })).Invoke(data);
} }
@@ -77,19 +78,38 @@ public static class Export {
} }
private static void ToHuTao(AchievementAllDataNotify data) { private static void ToHuTao(AchievementAllDataNotify data) {
if (CheckWinUIAppScheme("hutao")) if (CheckWinUIAppScheme("hutao")) {
{
Utils.CopyToClipboard(JsonSerializer.Serialize(ExportToUIAFApp(data))); Utils.CopyToClipboard(JsonSerializer.Serialize(ExportToUIAFApp(data)));
Utils.ShellOpen("hutao://achievement/import"); Utils.ShellOpen("hutao://achievement/import");
Console.WriteLine(App.ExportToSnapGenshinSuccess); Console.WriteLine(App.ExportToSnapGenshinSuccess);
} } else {
else
{
Console.WriteLine(App.ExportToSnapGenshinNeedUpdate); Console.WriteLine(App.ExportToSnapGenshinNeedUpdate);
Utils.ShellOpen("ms-windows-store://pdp/?productid=9PH4NXJ2JN52"); Utils.ShellOpen("ms-windows-store://pdp/?productid=9PH4NXJ2JN52");
} }
} }
private static void ToXunkong(AchievementAllDataNotify data) {
if (CheckWinUIAppScheme("xunkong")) {
Utils.CopyToClipboard(JsonSerializer.Serialize(ExportToUIAFApp(data)));
Utils.ShellOpen("xunkong://import-achievement?caller=YaeAchievement&from=clipboard");
Console.WriteLine(App.ExportToXunkongSuccess);
} else {
Console.WriteLine(App.ExportToXunkongNeedUpdate);
Utils.ShellOpen("ms-windows-store://pdp/?productid=9N2SVG0JMT12");
}
}
private static void ToTeyvatGuide(AchievementAllDataNotify data) {
if (Process.GetProcessesByName("TeyvatGuide").Any()) {
Utils.CopyToClipboard(JsonSerializer.Serialize(ExportToUIAFApp(data)));
Utils.ShellOpen("teyvatguide://import_uigf?app=YaeAchievement");
Console.WriteLine(App.ExportToTauriSuccess);
} else {
Console.WriteLine(App.ExportToTauriFail);
Utils.ShellOpen("ms-windows-store://pdp/?productid=9NLBNNNBNSJN");
}
}
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
private static void ToUIAFJson(AchievementAllDataNotify data) { private static void ToUIAFJson(AchievementAllDataNotify data) {
var path = Path.GetFullPath($"uiaf-{DateTime.Now:yyyyMMddHHmmss}.json"); var path = Path.GetFullPath($"uiaf-{DateTime.Now:yyyyMMddHHmmss}.json");
@@ -168,17 +188,6 @@ public static class Export {
} }
} }
private static void ToXunkong(AchievementAllDataNotify data) {
if (CheckWinUIAppScheme("xunkong")) {
Utils.CopyToClipboard(JsonSerializer.Serialize(ExportToUIAFApp(data)));
Utils.ShellOpen("xunkong://import-achievement?caller=YaeAchievement&from=clipboard");
Console.WriteLine(App.ExportToXunkongSuccess);
} else {
Console.WriteLine(App.ExportToXunkongNeedUpdate);
Utils.ShellOpen("ms-windows-store://pdp/?productid=9N2SVG0JMT12");
}
}
private static void ToRawJson(AchievementAllDataNotify data) { private static void ToRawJson(AchievementAllDataNotify data) {
var path = Path.GetFullPath($"export-{DateTime.Now:yyyyMMddHHmmss}-raw.json"); var path = Path.GetFullPath($"export-{DateTime.Now:yyyyMMddHHmmss}-raw.json");
var text = JsonSerializer.Serialize(data, new JsonSerializerOptions { var text = JsonSerializer.Serialize(data, new JsonSerializerOptions {

View File

@@ -20,8 +20,8 @@ public static class GlobalVars {
public static readonly string CachePath = Path.Combine(DataPath, "cache"); public static readonly string CachePath = Path.Combine(DataPath, "cache");
public static readonly string LibFilePath = Path.Combine(DataPath, "YaeAchievement.dll"); public static readonly string LibFilePath = Path.Combine(DataPath, "YaeAchievement.dll");
public const uint AppVersionCode = 39; public const uint AppVersionCode = 42;
public const string AppVersionName = "2.9"; public const string AppVersionName = "3.2";
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";

View File

@@ -45,7 +45,7 @@ public static class Injector {
return new Win32Exception().PrintMsgAndReturnErrCode("WriteProcessMemory fail"); return new Win32Exception().PrintMsgAndReturnErrCode("WriteProcessMemory fail");
} }
} }
var lpStartAddress = pLoadLibrary.CreateDelegate<LPTHREAD_START_ROUTINE>(); var lpStartAddress = (delegate* unmanaged[Stdcall]<void*, uint>)pLoadLibrary.Value; //THREAD_START_ROUTINE
var hThread = Native.CreateRemoteThread(hProc, default, 0, lpStartAddress, pBase, 0); var hThread = Native.CreateRemoteThread(hProc, default, 0, lpStartAddress, pBase, 0);
if (hThread.IsNull) { if (hThread.IsNull) {
var e = new Win32Exception(); var e = new Win32Exception();

View File

@@ -1,6 +1,6 @@
{ {
"$schema": "https://aka.ms/CsWin32.schema.json", "$schema": "https://aka.ms/CsWin32.schema.json",
"className": "Native", "className": "Native",
"allowMarshaling": true, "allowMarshaling": false,
"public": true "public": true
} }

View File

@@ -1,21 +1,21 @@
CreateProcess CloseClipboard
CreateProcess
CreateRemoteThread
EmptyClipboard
GetConsoleMode
GetDC
GetDeviceCaps
GetModuleHandle GetModuleHandle
GetProcAddress GetProcAddress
VirtualAllocEx
WriteProcessMemory
CreateRemoteThread
VirtualFreeEx
WaitForSingleObject
OpenClipboard
EmptyClipboard
GlobalLock
SetClipboardData
GlobalUnlock
CloseClipboard
GetStdHandle GetStdHandle
GetConsoleMode GlobalLock
GlobalUnlock
OpenClipboard
ResumeThread
SetClipboardData
SetConsoleMode SetConsoleMode
TerminateProcess TerminateProcess
ResumeThread VirtualAllocEx
GetDeviceCaps VirtualFreeEx
GetDC WaitForSingleObject
WriteProcessMemory

View File

@@ -92,7 +92,7 @@ public static class Utils {
public static void CheckUpdate(bool useLocalLib) { public static void CheckUpdate(bool useLocalLib) {
var info = UpdateInfo.Parser.ParseFrom(GetBucketFileAsByteArray("schicksal/version"))!; var info = UpdateInfo.Parser.ParseFrom(GetBucketFileAsByteArray("schicksal/version"))!;
if (GlobalVars.AppVersionCode != info.VersionCode) { if (GlobalVars.AppVersionCode < info.VersionCode) {
Console.WriteLine(App.UpdateNewVersion, GlobalVars.AppVersionName, info.VersionName); Console.WriteLine(App.UpdateNewVersion, GlobalVars.AppVersionName, info.VersionName);
Console.WriteLine(App.UpdateDescription, info.Description); Console.WriteLine(App.UpdateDescription, info.Description);
if (info.EnableAutoDownload) { if (info.EnableAutoDownload) {