34 Commits
3.0.0 ... 3.5.0

Author SHA1 Message Date
HolographicHat
e1429289ad refactor appcenter 2024-03-15 00:08:34 +08:00
HolographicHat
1f311ed987 4.5 2024-03-14 23:55:36 +08:00
HolographicHat
cc346915e3 Merge pull request #85 from BTMuli/master
️ 延长刷新间隔,Y/YES均可使用旧数据(大小写不敏感)
2024-02-06 23:27:16 +08:00
HolographicHat
cd0f49d83d shorten code 2024-02-06 23:19:41 +08:00
目棃
d0b7d15894 Merge branch 'master' into master 2024-02-06 22:54:51 +08:00
目棃
504c8a2a9a 👔 默认不使用旧数据 2024-02-06 22:46:37 +08:00
HolographicHat
b3162052da refactor 2024-02-06 21:31:14 +08:00
目棃
034d999d25 ️ 延长刷新间隔,回车/Y也能使用旧数据了 2024-02-02 19:30:03 +08:00
HolographicHat
45d5620e83 4.4 2024-01-31 12:46:31 +08:00
HolographicHat
fa13f9c8e5 fix 2023-12-25 00:21:48 +08:00
HolographicHat
2210a97d61 4.3 2023-12-24 23:59:24 +08:00
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
45 changed files with 419 additions and 2750 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

@@ -24,13 +24,11 @@
<PackageReference Include="Google.Protobuf" Version="3.22.1" /> <PackageReference Include="Google.Protobuf" Version="3.22.1" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.188-beta"> <PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.188-beta">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Grpc.Tools" Version="2.53.0"> <PackageReference Include="Grpc.Tools" Version="2.53.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -110,12 +110,11 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\HookManager.h" /> <ClInclude Include="src\HookManager.h" />
<ClInclude Include="src\il2cpp-api-functions.h" />
<ClInclude Include="src\il2cpp-appdata.h" /> <ClInclude Include="src\il2cpp-appdata.h" />
<ClInclude Include="src\il2cpp-functions.h" /> <ClInclude Include="src\il2cpp-functions.h" />
<ClInclude Include="src\il2cpp-types-ptr.h" />
<ClInclude Include="src\il2cpp-types.h" /> <ClInclude Include="src\il2cpp-types.h" />
<ClInclude Include="src\il2cpp-init.h" /> <ClInclude Include="src\il2cpp-init.h" />
<ClInclude Include="src\il2cpp-unity-functions.h" />
<ClInclude Include="src\pch.h" /> <ClInclude Include="src\pch.h" />
<ClInclude Include="src\util.h" /> <ClInclude Include="src\util.h" />
</ItemGroup> </ItemGroup>

View File

@@ -1,106 +1,63 @@
#include "pch.h" // ReSharper disable CppCStyleCast
// ReSharper disable CppInconsistentNaming
// ReSharper disable CppClangTidyModernizeUseStdPrint
// ReSharper disable CppClangTidyClangDiagnosticCastAlign
// ReSharper disable CppClangTidyHicppMultiwayPathsCovered
// ReSharper disable CppDefaultCaseNotHandledInSwitchStatement
// ReSharper disable CppClangTidyClangDiagnosticCastFunctionTypeStrict
#include "pch.h"
#include "util.h" #include "util.h"
#include "il2cpp-init.h" #include "il2cpp-init.h"
using Genshin::ByteArray, Genshin::ClientKcpEvent, Genshin::KcpPacket, Genshin::KcpEventType; using Genshin::ByteArray;
using std::to_string;
HWND unityWnd = nullptr; HWND unityWnd = nullptr;
HANDLE hPipe = nullptr; HANDLE hPipe = nullptr;
// Allow Protocol: GetPlayerToken, PlayerLogin, AchievementAllDataNotify, Ping, PlayerForceExit
std::set<UINT16> PacketWhitelist = { 21228, 2407, 25842, 29665, 27422, 5285, 8231, 1819 };
bool OnPacket(KcpPacket* pkt) {
if (pkt->data == nullptr) return true;
auto len = pkt->length;
auto data = (ByteArray*)new BYTE[len + 32];
data->max_length = len;
memcpy(data->vector, pkt->data, len);
Genshin::XorEncrypt(&data, len, nullptr);
if (ReadMapped<UINT16>(data->vector, 0) != 0x4567) {
delete[] data;
return true;
}
if (!PacketWhitelist.contains(ReadMapped<UINT16>(data->vector, 2))) {
//ifdef _DEBUG
printf("Blocked cmdid: %d\n", ReadMapped<UINT16>(data->vector, 2));
//endif
delete[] data;
return false;
}
printf("Passed cmdid: %d\n", ReadMapped<UINT16>(data->vector, 2));
if (ReadMapped<UINT16>(data->vector, 2) == 27422) {
auto headLength = ReadMapped<UINT16>(data->vector, 4);
auto dataLength = ReadMapped<UINT32>(data->vector, 6);
auto iStr = Genshin::ToBase64String(data, 10 + headLength, dataLength, nullptr);
auto cStr = ToString(iStr) + "\n";
WriteFile(hPipe, cStr.c_str(), cStr.length(), nullptr, nullptr);
CloseHandle(hPipe);
auto manager = Genshin::GetSingletonInstance(Genshin::GetSingletonManager(), il2cpp_string_new("GameManager"));
Genshin::ForceQuit(manager);
}
delete[] data;
return true;
}
std::string checksum; std::string checksum;
namespace Hook { namespace Hook {
int KcpSend(void* client, KcpPacket* pkt, void* method) { ByteArray* UnityEngine_RecordUserData(const INT type) {
return OnPacket(pkt) ? CALL_ORIGIN(KcpSend, client, pkt, method) : 0; if (type == 0) {
const auto arr = new ByteArray {};
const auto len = checksum.length();
arr->max_length = len;
memcpy(&arr->vector[0], checksum.data(), len);
return arr;
}
return new ByteArray {};
} }
void SetVersion(void* obj, Il2CppString* value, void* method) { uint16_t BitConverter_ToUInt16(ByteArray* val, const int startIndex) {
auto version = ToString(value); const auto ret = CALL_ORIGIN(BitConverter_ToUInt16, val, startIndex);
value = string_new(version + " YaeAchievement"); if (ret == 0xAB89 && ReadMapped<UINT16>(val->vector, 2) == 20248) {
CALL_ORIGIN(SetVersion, obj, value, method); 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";
WriteFile(hPipe, cStr.c_str(), (DWORD) cStr.length(), nullptr, nullptr);
CloseHandle(hPipe);
ExitProcess(0);
} }
return ret;
bool KcpRecv(void* client, ClientKcpEvent* evt, void* method) {
auto result = CALL_ORIGIN(KcpRecv, client, evt, method);
if (result == 0 || evt->fields.type != KcpEventType::EventRecvMsg) {
return result;
}
return OnPacket(evt->fields.packet) ? result : false;
}
ByteArray* UnityEngine_RecordUserData(INT type) {
return Genshin::GetBytes(Genshin::GetDefaultEncoding(), il2cpp_string_new(""));
}
VOID SetChecksum(LPVOID obj, Il2CppString* value) {
CALL_ORIGIN(SetChecksum, obj, il2cpp_string_new(checksum.c_str()));
}
VOID RequestLogin(LPVOID obj, LPVOID token, UINT32 uid) {
HookManager::install(Genshin::SetChecksum, SetChecksum);
CALL_ORIGIN(RequestLogin, obj, token, uid);
HookManager::detach(SetChecksum);
} }
} }
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::BitConverter_ToUInt16, Hook::BitConverter_ToUInt16);
HookManager::install(Genshin::KcpRecv, Hook::KcpRecv);
HookManager::install(Genshin::SetVersion, Hook::SetVersion);
HookManager::install(Genshin::RequestLogin, Hook::RequestLogin);
HookManager::install(Genshin::UnityEngine_RecordUserData, Hook::UnityEngine_RecordUserData); HookManager::install(Genshin::UnityEngine_RecordUserData, Hook::UnityEngine_RecordUserData);
hPipe = CreateFile(R"(\\.\pipe\YaeAchievementPipe)", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); hPipe = CreateFile(R"(\\.\pipe\YaeAchievementPipe)", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hPipe == INVALID_HANDLE_VALUE) { if (hPipe == INVALID_HANDLE_VALUE) {

View File

@@ -1 +0,0 @@
DO_API(0x9cc850, 0x9ca750, Il2CppString*, il2cpp_string_new, (const char* str));

View File

@@ -1,20 +1,19 @@
// ReSharper disable CppClangTidyBugproneMacroParentheses
#pragma once #pragma once
#include "il2cpp-types.h" #include "il2cpp-types.h"
// IL2CPP APIs
#define DO_API(ca, oa, r, n, p) extern r (*n) p
#include "il2cpp-api-functions.h"
#undef DO_API
// Application-specific functions // Application-specific functions
#define DO_APP_FUNC(ca, oa, r, n, p) extern r (*n) p #define DO_APP_FUNC(ca, oa, r, n, p) extern r (*n) p
#define DO_UNI_FUNC(ca, oa, r, n, p) extern r (*n) p
namespace Genshin { namespace Genshin {
#include "il2cpp-functions.h" #include "il2cpp-functions.h"
} }
#undef DO_UNI_FUNC
#undef DO_APP_FUNC #undef DO_APP_FUNC
#define DO_UNI_FUNC(ca, oa, r, n, p) extern r (*n) p #define DO_TYPEDEF(ca, oa, n) extern n##__Class **n##__TypeInfo
namespace Genshin { namespace Genshin {
#include "il2cpp-unity-functions.h" #include "il2cpp-types-ptr.h"
} }
#undef DO_UNI_FUNC #undef DO_TYPEDEF

View File

@@ -2,30 +2,10 @@ 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(0x7974040, 0x792b560, Il2CppString*, ToBase64String, (ByteArray* value, int offset, int length, void* method)); DO_APP_FUNC(0x569170, 0x568470, LPVOID, il2cpp_object_new, (LPVOID t));
DO_APP_FUNC(0x21e5c10, 0x21bf5c0, void, SetVersion, (void* obj, Il2CppString* value, void* method)); DO_APP_FUNC(0x06C43A80, 0x06775280, ByteArray*, RecordUserData, (int32_t nType));
DO_APP_FUNC(0x81d1a00, 0x818d250, ByteArray*, RecordUserData, (int32_t nType)); DO_APP_FUNC(0x0C87B240, 0x0C89EFB0, uint16_t, BitConverter_ToUInt16, (ByteArray* val, int startIndex));
DO_APP_FUNC(0x3174320, 0x3133880, void, XorEncrypt, (ByteArray** data, int length, void* method)); DO_UNI_FUNC(0x105560, 0x105560, ByteArray*, UnityEngine_RecordUserData, (int32_t nType));
DO_APP_FUNC(0x2d49720, 0x2d103a0, int, KcpSend, (void* client, KcpPacket* pkt, void* method));
DO_APP_FUNC(0x3d6a920, 0x3d11e00, bool, KcpRecv, (void* client, ClientKcpEvent* evt, void* method));
DO_APP_FUNC(0x7c9c9c0, 0x7c56400, LPVOID, GetDefaultEncoding, ());
DO_APP_FUNC(0x7c9c220, 0x7c55c60, Il2CppString*, GetString, (LPVOID encoding, LPVOID bytes));
DO_APP_FUNC(0x7c9b030, 0x7c54a20, ByteArray*, GetBytes, (LPVOID encoding, LPVOID str));
DO_APP_FUNC(0x1d2e480, 0x1d0db20, VOID, RequestLogin, (LPVOID obj, LPVOID token, UINT uid));
DO_APP_FUNC(0x31285b0, 0x32ee9b0, VOID, SetChecksum, (LPVOID obj, Il2CppString* value));
DO_APP_FUNC(0xfa2eb0, 0xf99150, VOID, ForceQuit, (LPVOID obj));
DO_APP_FUNC(0x7257b20, 0x72079f0, LPVOID, GetSingletonManager, ());
DO_APP_FUNC(0x7257850, 0x7207720, LPVOID, GetSingletonInstance, (LPVOID obj, Il2CppString* value));

View File

@@ -1,22 +1,22 @@
// ReSharper disable CppClangTidyBugproneMacroParentheses
#include "pch.h" #include "pch.h"
#include "il2cpp-init.h" #include "il2cpp-init.h"
#define DO_API(ca, oa, r, n, p) r (*n) p
#include "il2cpp-api-functions.h"
#undef DO_API
#define DO_APP_FUNC(ca, oa, r, n, p) r (*n) p #define DO_APP_FUNC(ca, oa, r, n, p) r (*n) p
#define DO_UNI_FUNC(ca, oa, r, n, p) r (*n) p
namespace Genshin { namespace Genshin {
#include "il2cpp-functions.h" #include "il2cpp-functions.h"
} }
#undef DO_UNI_FUNC
#undef DO_APP_FUNC #undef DO_APP_FUNC
#define DO_UNI_FUNC(ca, oa, r, n, p) r (*n) p #define DO_TYPEDEF(ca, oa, n) n##__Class **n##__TypeInfo
namespace Genshin { namespace Genshin {
#include "il2cpp-unity-functions.h" #include "il2cpp-types-ptr.h"
} }
#undef DO_UNI_FUNC #undef DO_TYPEDEF
using std::string; using std::string;
@@ -27,13 +27,12 @@ void InitIL2CPP() {
auto hBase = GetModuleHandle("UserAssembly.dll"); auto hBase = GetModuleHandle("UserAssembly.dll");
auto bAddr = (UINT64)hBase; auto bAddr = (UINT64)hBase;
auto cAddr = (UINT64)GetModuleHandle("UnityPlayer.dll"); auto cAddr = (UINT64)GetModuleHandle("UnityPlayer.dll");
#define DO_API(ca, oa, r, n, p) n = (r (*) p)(bAddr + (isCN ? ca : oa))
#include "il2cpp-api-functions.h"
#undef DO_API
#define DO_APP_FUNC(ca, oa, r, n, p) n = (r (*) p)(bAddr + (isCN ? ca : oa)) #define DO_APP_FUNC(ca, oa, r, n, p) n = (r (*) p)(bAddr + (isCN ? ca : oa))
#include "il2cpp-functions.h"
#undef DO_APP_FUNC
#define DO_UNI_FUNC(ca, oa, r, n, p) n = (r (*) p)(cAddr + (isCN ? ca : oa)) #define DO_UNI_FUNC(ca, oa, r, n, p) n = (r (*) p)(cAddr + (isCN ? ca : oa))
#include "il2cpp-unity-functions.h" #include "il2cpp-functions.h"
#undef DO_UNI_FUNC #undef DO_UNI_FUNC
#undef DO_APP_FUNC
#define DO_TYPEDEF(ca, oa, n) n##__TypeInfo = (n##__Class **)(bAddr + (isCN ? ca : oa))
#include "il2cpp-types-ptr.h"
#undef DO_TYPEDEF
} }

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +0,0 @@
using namespace Genshin;
DO_UNI_FUNC(0x102fa0, 0x102fa0, 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,9 +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 string_new(str) cstring_new((str).c_str())
#define ErrorDialogT(title, msg) MessageBox(unityWnd, msg, title, MB_OK | MB_ICONERROR | MB_SYSTEMMODAL); #define ErrorDialogT(title, msg) MessageBox(unityWnd, msg, title, MB_OK | MB_ICONERROR | MB_SYSTEMMODAL);
#define ErrorDialog(msg) ErrorDialogT("YaeAchievement", msg) #define ErrorDialog(msg) ErrorDialogT("YaeAchievement", msg)

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 = 15; uint32 timestamp = 14;
uint32 current = 14; uint32 current = 13;
uint32 total = 4; uint32 total = 9;
uint32 id = 5; uint32 id = 7;
Status status = 10; Status status = 10;
} }
message AchievementAllDataNotify { message AchievementAllDataNotify {
repeated Achievement list = 9; repeated Achievement list = 15;
} }

View File

@@ -1,5 +1,5 @@
using Newtonsoft.Json; using System.Net;
using System.Net; using System.Net.Http.Json;
using YaeAchievement.AppCenterSDK.Models; using YaeAchievement.AppCenterSDK.Models;
using YaeAchievement.AppCenterSDK.Models.Serialization; using YaeAchievement.AppCenterSDK.Models.Serialization;
@@ -39,12 +39,6 @@ public static class AppCenter {
AppDomain.CurrentDomain.ProcessExit += (_, _) => { AppDomain.CurrentDomain.ProcessExit += (_, _) => {
running = false; running = false;
}; };
LogSerializer.AddLogType(PageLog.JsonIdentifier, typeof(PageLog));
LogSerializer.AddLogType(EventLog.JsonIdentifier, typeof(EventLog));
LogSerializer.AddLogType(HandledErrorLog.JsonIdentifier, typeof(HandledErrorLog));
LogSerializer.AddLogType(ManagedErrorLog.JsonIdentifier, typeof(ManagedErrorLog));
LogSerializer.AddLogType(StartServiceLog.JsonIdentifier, typeof(StartServiceLog));
LogSerializer.AddLogType(StartSessionLog.JsonIdentifier, typeof(StartSessionLog));
} }
// ReSharper restore InconsistentNaming // ReSharper restore InconsistentNaming
@@ -59,8 +53,8 @@ public static class AppCenter {
using var uploadContent = new StringContent(Queue.ToJson()); using var uploadContent = new StringContent(Queue.ToJson());
try { try {
using var response = httpClient.Value.PostAsync(ApiUrl, uploadContent).Result; using var response = httpClient.Value.PostAsync(ApiUrl, uploadContent).Result;
var result = response.Content.ReadAsStringAsync().Result; var result = response.Content.ReadFromJsonAsync<LogUploadResult>().GetAwaiter().GetResult();
uploadStatus = JsonConvert.DeserializeObject<LogUploadResult>(result)!.Status; uploadStatus = result!.Status;
} catch (Exception) { } catch (Exception) {
// ignored // ignored
} }

View File

@@ -1,51 +1,36 @@
using System.Globalization; using System.Globalization;
using System.Reflection; using System.Reflection;
using Newtonsoft.Json;
namespace YaeAchievement.AppCenterSDK.Models; namespace YaeAchievement.AppCenterSDK.Models;
public class Device { public class Device {
[JsonProperty(PropertyName = "sdkName")]
public string SdkName { get; set; } = "appcenter.wpf.netcore"; public string SdkName { get; set; } = "appcenter.wpf.netcore";
[JsonProperty(PropertyName = "sdkVersion")]
public string SdkVersion { get; set; } = "4.5.0"; public string SdkVersion { get; set; } = "4.5.0";
[JsonProperty(PropertyName = "osName")]
public string OsName { get; set; } = "WINDOWS"; public string OsName { get; set; } = "WINDOWS";
[JsonProperty(PropertyName = "osVersion")]
public string OsVersion { get; set; } = DeviceHelper.GetSystemVersion(); public string OsVersion { get; set; } = DeviceHelper.GetSystemVersion();
[JsonProperty(PropertyName = "osBuild")]
public string OsBuild { get; set; } = $"{DeviceHelper.GetSystemVersion()}.{DeviceHelper.GetSystemBuild()}"; public string OsBuild { get; set; } = $"{DeviceHelper.GetSystemVersion()}.{DeviceHelper.GetSystemBuild()}";
[JsonProperty(PropertyName = "model")]
public string? Model { get; set; } = DeviceHelper.GetModel(); public string? Model { get; set; } = DeviceHelper.GetModel();
[JsonProperty(PropertyName = "oemName")]
public string? OemName { get; set; } = DeviceHelper.GetOem(); public string? OemName { get; set; } = DeviceHelper.GetOem();
[JsonProperty(PropertyName = "screenSize")]
public string ScreenSize { get; set; } = DeviceHelper.GetScreenSize(); public string ScreenSize { get; set; } = DeviceHelper.GetScreenSize();
[JsonProperty(PropertyName = "carrierCountry")] public string CarrierCountry { get; set; } = DeviceHelper.GetCountry() ?? "CN";
public string Country { get; set; } = DeviceHelper.GetCountry() ?? "CN";
[JsonProperty(PropertyName = "locale")]
public string Locale { get; set; } = CultureInfo.CurrentCulture.Name; public string Locale { get; set; } = CultureInfo.CurrentCulture.Name;
[JsonProperty(PropertyName = "timeZoneOffset")]
public int TimeZoneOffset { get; set; } = (int) TimeZoneInfo.Local.BaseUtcOffset.TotalMinutes; public int TimeZoneOffset { get; set; } = (int) TimeZoneInfo.Local.BaseUtcOffset.TotalMinutes;
[JsonProperty(PropertyName = "appVersion")]
public string AppVersion { get; set; } = GlobalVars.AppVersionName; public string AppVersion { get; set; } = GlobalVars.AppVersionName;
[JsonProperty(PropertyName = "appBuild")]
public string AppBuild { get; set; } = GlobalVars.AppVersionCode.ToString(); public string AppBuild { get; set; } = GlobalVars.AppVersionCode.ToString();
[JsonProperty(PropertyName = "appNamespace")]
public string AppNamespace { get; set; } = Assembly.GetEntryAssembly()?.EntryPoint?.DeclaringType?.Namespace ?? string.Empty; public string AppNamespace { get; set; } = Assembly.GetEntryAssembly()?.EntryPoint?.DeclaringType?.Namespace ?? string.Empty;
} }

View File

@@ -1,20 +1,14 @@
using Newtonsoft.Json; using YaeAchievement.AppCenterSDK.Models.Serialization;
namespace YaeAchievement.AppCenterSDK.Models; namespace YaeAchievement.AppCenterSDK.Models;
[JsonObject(JsonIdentifier)] [LogId(JsonIdentifier)]
public class EventLog : LogWithProperties { public class EventLog(string name) : LogWithProperties {
public const string JsonIdentifier = "event"; public const string JsonIdentifier = "event";
public EventLog(string name) { public Guid Id { get; set; } = Guid.NewGuid();
Name = name;
}
[JsonProperty(PropertyName = "id")] public string Name { get; set; } = name;
private Guid Id { get; set; } = Guid.NewGuid();
[JsonProperty(PropertyName = "name")]
private string Name { get; set; }
} }

View File

@@ -1,8 +1,8 @@
using Newtonsoft.Json; using YaeAchievement.AppCenterSDK.Models.Serialization;
namespace YaeAchievement.AppCenterSDK.Models; namespace YaeAchievement.AppCenterSDK.Models;
[JsonObject(JsonIdentifier)] [LogId(JsonIdentifier)]
public class HandledErrorLog : LogWithProperties { public class HandledErrorLog : LogWithProperties {
public const string JsonIdentifier = "handledError"; public const string JsonIdentifier = "handledError";
@@ -12,10 +12,8 @@ public class HandledErrorLog : LogWithProperties {
Exception = exception; Exception = exception;
} }
[JsonProperty(PropertyName = "id")]
public Guid? Id { get; set; } public Guid? Id { get; set; }
[JsonProperty(PropertyName = "exception")]
public MException Exception { get; set; } public MException Exception { get; set; }
} }

View File

@@ -1,17 +1,15 @@
using Newtonsoft.Json; using System.Text.Json.Serialization;
namespace YaeAchievement.AppCenterSDK.Models; namespace YaeAchievement.AppCenterSDK.Models;
public abstract class Log { public abstract class Log {
[JsonProperty(PropertyName = "sid")] [JsonPropertyName("sid")]
private Guid? Session { get; set; } = AppCenter.SessionID; public Guid? Session { get; set; } = AppCenter.SessionID;
[JsonProperty(PropertyName = "timestamp")] public DateTime Timestamp { get; set; } = DateTime.UtcNow;
private DateTime Timestamp { get; set; } = DateTime.UtcNow;
[JsonProperty(PropertyName = "device")] public Device Device { get; set; } = AppCenter.DeviceInfo;
private Device Device { get; set; } = AppCenter.DeviceInfo;
[JsonIgnore] [JsonIgnore]
internal LogStatus Status = LogStatus.Pending; internal LogStatus Status = LogStatus.Pending;

View File

@@ -1,6 +1,4 @@
using Newtonsoft.Json; namespace YaeAchievement.AppCenterSDK.Models;
namespace YaeAchievement.AppCenterSDK.Models;
public class LogContainer { public class LogContainer {
@@ -8,7 +6,6 @@ public class LogContainer {
Logs = logs; Logs = logs;
} }
[JsonProperty(PropertyName = "logs")]
public IEnumerable<Log> Logs { get; set; } public IEnumerable<Log> Logs { get; set; }
} }

View File

@@ -1,19 +1,13 @@
using Newtonsoft.Json; namespace YaeAchievement.AppCenterSDK.Models;
namespace YaeAchievement.AppCenterSDK.Models;
public class LogUploadResult { public class LogUploadResult {
[JsonProperty(PropertyName = "status")]
public string Status { get; set; } = null!; public string Status { get; set; } = null!;
[JsonProperty(PropertyName = "validDiagnosticsIds")]
public Guid[] ValidDiagnosticsIds { get; set; } = Array.Empty<Guid>(); public Guid[] ValidDiagnosticsIds { get; set; } = Array.Empty<Guid>();
[JsonProperty(PropertyName = "throttledDiagnosticsIds")]
public Guid[] ThrottledDiagnosticsIds { get; set; } = Array.Empty<Guid>(); public Guid[] ThrottledDiagnosticsIds { get; set; } = Array.Empty<Guid>();
[JsonProperty(PropertyName = "correlationId")]
public Guid CorrelationId { get; set; } public Guid CorrelationId { get; set; }
} }

View File

@@ -1,10 +1,7 @@
using Newtonsoft.Json; namespace YaeAchievement.AppCenterSDK.Models;
namespace YaeAchievement.AppCenterSDK.Models;
public class LogWithProperties : Log { public class LogWithProperties : Log {
[JsonProperty(PropertyName = "properties")]
public IDictionary<string, string> Properties { get; set; } = new Dictionary<string, string>(); public IDictionary<string, string> Properties { get; set; } = new Dictionary<string, string>();
} }

View File

@@ -1,22 +1,15 @@
using Newtonsoft.Json; namespace YaeAchievement.AppCenterSDK.Models;
namespace YaeAchievement.AppCenterSDK.Models;
public class MException { public class MException {
[JsonProperty(PropertyName = "type")]
public string Type { get; set; } = "UnknownType"; public string Type { get; set; } = "UnknownType";
[JsonProperty(PropertyName = "message")]
public string? Message { get; set; } public string? Message { get; set; }
[JsonProperty(PropertyName = "stackTrace")]
public string? StackTrace { get; set; } public string? StackTrace { get; set; }
[JsonProperty(PropertyName = "frames")]
public IList<StackFrame>? Frames { get; set; } public IList<StackFrame>? Frames { get; set; }
[JsonProperty(PropertyName = "innerExceptions")]
public IList<MException>? InnerExceptions { get; set; } public IList<MException>? InnerExceptions { get; set; }
} }

View File

@@ -1,9 +1,9 @@
using System.Diagnostics; using System.Diagnostics;
using Newtonsoft.Json; using YaeAchievement.AppCenterSDK.Models.Serialization;
namespace YaeAchievement.AppCenterSDK.Models; namespace YaeAchievement.AppCenterSDK.Models;
[JsonObject(JsonIdentifier)] [LogId(JsonIdentifier)]
public class ManagedErrorLog : Log { public class ManagedErrorLog : Log {
public const string JsonIdentifier = "managedError"; public const string JsonIdentifier = "managedError";
@@ -23,28 +23,20 @@ public class ManagedErrorLog : Log {
AppLaunchTimestamp = p.StartTime.ToUniversalTime(); AppLaunchTimestamp = p.StartTime.ToUniversalTime();
} }
[JsonProperty(PropertyName = "id")]
public Guid Id { get; set; } public Guid Id { get; set; }
[JsonProperty(PropertyName = "userId")]
public string? UserId { get; set; } public string? UserId { get; set; }
[JsonProperty(PropertyName = "processId")]
public int ProcessId { get; set; } public int ProcessId { get; set; }
[JsonProperty(PropertyName = "processName")]
public string ProcessName { get; set; } public string ProcessName { get; set; }
[JsonProperty(PropertyName = "fatal")]
public bool Fatal { get; set; } public bool Fatal { get; set; }
[JsonProperty(PropertyName = "appLaunchTimestamp")]
public DateTime? AppLaunchTimestamp { get; set; } public DateTime? AppLaunchTimestamp { get; set; }
[JsonProperty(PropertyName = "architecture")]
public string? Architecture { get; set; } public string? Architecture { get; set; }
[JsonProperty(PropertyName = "exception")]
public MException Exception { get; set; } public MException Exception { get; set; }
} }

View File

@@ -1,8 +1,8 @@
using Newtonsoft.Json; using YaeAchievement.AppCenterSDK.Models.Serialization;
namespace YaeAchievement.AppCenterSDK.Models; namespace YaeAchievement.AppCenterSDK.Models;
[JsonObject(JsonIdentifier)] [LogId(JsonIdentifier)]
public class PageLog : LogWithProperties { public class PageLog : LogWithProperties {
public const string JsonIdentifier = "page"; public const string JsonIdentifier = "page";
@@ -11,7 +11,6 @@ public class PageLog : LogWithProperties {
Name = name; Name = name;
} }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; } public string Name { get; set; }
} }

View File

@@ -0,0 +1,8 @@
namespace YaeAchievement.AppCenterSDK.Models.Serialization;
[AttributeUsage(AttributeTargets.Class)]
public sealed class LogIdAttribute(string id) : Attribute {
public string Id { get; } = id;
}

View File

@@ -1,60 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved. using System.Reflection;
// Licensed under the MIT License. using System.Text.Json;
using System.Text.Json.Serialization;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace YaeAchievement.AppCenterSDK.Models.Serialization; namespace YaeAchievement.AppCenterSDK.Models.Serialization;
#pragma warning disable CS8604, CS8765 public class GuidConverter : JsonConverter<Guid> {
public class LogJsonConverter : JsonConverter {
private readonly Dictionary<string, Type> _logTypes = new (); public static GuidConverter Instance { get; } = new ();
private readonly object _jsonConverterLock = new ();
private static readonly JsonSerializerSettings SerializationSettings; public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
throw new NotSupportedException();
}
public override void Write(Utf8JsonWriter writer, Guid value, JsonSerializerOptions options) {
writer.WriteStringValue(value.ToString("D"));
}
}
public class LogJsonConverter : JsonConverter<Log> {
public static LogJsonConverter Instance { get; } = new ();
private static readonly JsonSerializerOptions SerializationSettings;
static LogJsonConverter() { static LogJsonConverter() {
SerializationSettings = new JsonSerializerSettings { SerializationSettings = new JsonSerializerOptions {
Formatting = Formatting.None, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
NullValueHandling = NullValueHandling.Ignore, PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DateFormatHandling = DateFormatHandling.IsoDateFormat, ReferenceHandler = ReferenceHandler.IgnoreCycles,
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
ReferenceLoopHandling = ReferenceLoopHandling.Serialize
}; };
} }
public void AddLogType(string typeName, Type type) { public override bool CanConvert(Type objectType) => typeof(Log).IsAssignableFrom(objectType);
lock (_jsonConverterLock) {
_logTypes[typeName] = type; public override Log Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
} throw new NotSupportedException();
} }
public override bool CanConvert(Type objectType) { public override void Write(Utf8JsonWriter writer, Log value, JsonSerializerOptions options) {
return typeof(Log).IsAssignableFrom(objectType); var attr = value.GetType().GetCustomAttribute<LogIdAttribute>();
if (attr == null) {
throw new JsonException("Log type is missing LogTypeAttribute");
} }
var cNode = JsonSerializer.SerializeToNode((object) value, SerializationSettings)!;
public override object? ReadJson(JsonReader reader, Type t, object o, JsonSerializer s) { cNode["type"] = attr.Id;
Type logType; writer.WriteRawValue(cNode.ToString());
var jsonObject = JObject.Load(reader);
var typeName = jsonObject.GetValue("type")?.ToString();
lock (_jsonConverterLock) {
if (typeName == null || !_logTypes.ContainsKey(typeName)) {
throw new JsonReaderException("Could not identify type of log");
}
logType = _logTypes[typeName];
jsonObject.Remove("type");
}
return jsonObject.ToObject(logType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var info = value.GetType().GetTypeInfo();
if (info.GetCustomAttribute(typeof(JsonObjectAttribute)) is not JsonObjectAttribute attribute) {
throw new JsonWriterException("Log type is missing JsonObjectAttribute");
}
var jsonObject = JObject.FromObject(value, JsonSerializer.CreateDefault(SerializationSettings));
jsonObject.Add("type", JToken.FromObject(attribute.Id));
writer.WriteRawValue(jsonObject.ToString(Formatting.None));
} }
} }

View File

@@ -1,40 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved. using System.Text.Json;
// Licensed under the MIT License. using System.Text.Json.Serialization;
using Newtonsoft.Json;
namespace YaeAchievement.AppCenterSDK.Models.Serialization; namespace YaeAchievement.AppCenterSDK.Models.Serialization;
#pragma warning disable CS8604, CS8765, CS8603
public static class LogSerializer { public static class LogSerializer {
private static readonly JsonSerializerSettings SerializationSettings; private static readonly JsonSerializerOptions SerializationSettings;
private static readonly LogJsonConverter Converter = new ();
static LogSerializer() { static LogSerializer() {
SerializationSettings = new JsonSerializerSettings { SerializationSettings = new JsonSerializerOptions {
Formatting = Formatting.None, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
NullValueHandling = NullValueHandling.Ignore, PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DateFormatHandling = DateFormatHandling.IsoDateFormat, ReferenceHandler = ReferenceHandler.IgnoreCycles,
DateTimeZoneHandling = DateTimeZoneHandling.Utc, Converters = {
ReferenceLoopHandling = ReferenceLoopHandling.Serialize, GuidConverter.Instance,
Converters = { Converter } LogJsonConverter.Instance,
}
}; };
} }
public static void AddLogType(string typeName, Type type) {
Converter.AddLogType(typeName, type);
}
public static string Serialize(LogContainer logContainer) { public static string Serialize(LogContainer logContainer) {
return JsonConvert.SerializeObject(logContainer, SerializationSettings); return JsonSerializer.Serialize(logContainer, SerializationSettings);
}
public static string Serialize(Log log) {
return JsonConvert.SerializeObject(log, SerializationSettings);
}
public static LogContainer? DeserializeLogs(string json) {
return JsonConvert.DeserializeObject<LogContainer>(json, SerializationSettings);
} }
} }

View File

@@ -1,6 +1,4 @@
using Newtonsoft.Json; namespace YaeAchievement.AppCenterSDK.Models;
namespace YaeAchievement.AppCenterSDK.Models;
public class StackFrame { public class StackFrame {
@@ -13,22 +11,16 @@ public class StackFrame {
FileName = fileName; FileName = fileName;
} }
[JsonProperty(PropertyName = "address")]
public string Address { get; set; } public string Address { get; set; }
[JsonProperty(PropertyName = "code")]
public string Code { get; set; } public string Code { get; set; }
[JsonProperty(PropertyName = "className")]
public string ClassName { get; set; } public string ClassName { get; set; }
[JsonProperty(PropertyName = "methodName")]
public string MethodName { get; set; } public string MethodName { get; set; }
[JsonProperty(PropertyName = "lineNumber")]
public int? LineNumber { get; set; } public int? LineNumber { get; set; }
[JsonProperty(PropertyName = "fileName")]
public string FileName { get; set; } public string FileName { get; set; }
} }

View File

@@ -1,8 +1,8 @@
using Newtonsoft.Json; using YaeAchievement.AppCenterSDK.Models.Serialization;
namespace YaeAchievement.AppCenterSDK.Models; namespace YaeAchievement.AppCenterSDK.Models;
[JsonObject(JsonIdentifier)] [LogId(JsonIdentifier)]
public class StartServiceLog : Log { public class StartServiceLog : Log {
public const string JsonIdentifier = "startService"; public const string JsonIdentifier = "startService";
@@ -11,7 +11,6 @@ public class StartServiceLog : Log {
Services = services; Services = services;
} }
[JsonProperty(PropertyName = "services")]
public string[] Services { get; set; } public string[] Services { get; set; }
} }

View File

@@ -1,8 +1,8 @@
using Newtonsoft.Json; using YaeAchievement.AppCenterSDK.Models.Serialization;
namespace YaeAchievement.AppCenterSDK.Models; namespace YaeAchievement.AppCenterSDK.Models;
[JsonObject(JsonIdentifier)] [LogId(JsonIdentifier)]
public class StartSessionLog : Log { public class StartSessionLog : Log {
public const string JsonIdentifier = "startSession"; public const string JsonIdentifier = "startSession";
} }

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 = 40; public const uint AppVersionCode = 45;
public const string AppVersionName = "3.0"; public const string AppVersionName = "3.5";
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

@@ -29,29 +29,27 @@ new EventLog("AppInit") {
{ "SystemVersion", DeviceHelper.GetSystemVersion() } { "SystemVersion", DeviceHelper.GetSystemVersion() }
} }
}.Enqueue(); }.Enqueue();
var usePreviousData = false;
var historyCache = new CacheFile("ExportData"); var historyCache = new CacheFile("ExportData");
if (historyCache.LastWriteTime.AddMinutes(10) > DateTime.UtcNow) {
Console.WriteLine(App.UsePreviousData); AchievementAllDataNotify? data = null;
usePreviousData = Console.ReadLine() == "yes"; try {
}
Export:
if(usePreviousData) {
AchievementAllDataNotify data;
try {
data = AchievementAllDataNotify.Parser.ParseFrom(historyCache.Read().Content); data = AchievementAllDataNotify.Parser.ParseFrom(historyCache.Read().Content);
} catch (Exception) { } catch (Exception) { /* ignored */ }
usePreviousData = false;
goto Export; if (historyCache.LastWriteTime.AddMinutes(60) > DateTime.UtcNow && data != null) {
} Console.WriteLine(App.UsePreviousData);
if (Console.ReadLine()?.ToUpper() is "Y" or "YES") {
Export.Choose(data); Export.Choose(data);
} else { return;
StartAndWaitResult(AppConfig.GamePath, str => { }
}
StartAndWaitResult(AppConfig.GamePath, str => {
GlobalVars.UnexpectedExit = false; GlobalVars.UnexpectedExit = false;
var data = Convert.FromBase64String(str); var bytes = Convert.FromBase64String(str);
var list = AchievementAllDataNotify.Parser.ParseFrom(data); var list = AchievementAllDataNotify.Parser.ParseFrom(bytes);
historyCache.Write(data); historyCache.Write(bytes);
Export.Choose(list); Export.Choose(list);
return true; return true;
}); });
}