From dd665424895d4612f58dbf86ef2a8e054603c428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=AF=E5=A4=A7=E4=BE=A0?= Date: Tue, 13 Dec 2022 06:31:46 +0800 Subject: [PATCH] Steam/Epic Achievements Unlock (#468) * Steam/Epic Achievements Unlock * cleaning --- AmongUsMenu.vcxproj | 1 + AmongUsMenu.vcxproj.filters | 5 ++- appdata/il2cpp-functions.h | 2 + appdata/il2cpp-types.h | 86 +++++++++++++++++++++++++++++++++++++ framework/il2cpp-helpers.h | 11 +++++ gui/tabs/settings_tab.cpp | 15 +++---- user/achievements.cpp | 55 ++++++++++++++++++++++++ user/achievements.hpp | 38 ++-------------- user/game.cpp | 8 ++-- user/game.h | 8 ++-- 10 files changed, 177 insertions(+), 52 deletions(-) create mode 100644 user/achievements.cpp diff --git a/AmongUsMenu.vcxproj b/AmongUsMenu.vcxproj index d2ae7227..cc947eae 100644 --- a/AmongUsMenu.vcxproj +++ b/AmongUsMenu.vcxproj @@ -80,6 +80,7 @@ + NotUsing diff --git a/AmongUsMenu.vcxproj.filters b/AmongUsMenu.vcxproj.filters index 146339d5..51883a79 100644 --- a/AmongUsMenu.vcxproj.filters +++ b/AmongUsMenu.vcxproj.filters @@ -67,7 +67,7 @@ hooks - + hooks @@ -301,6 +301,9 @@ gui + + user + diff --git a/appdata/il2cpp-functions.h b/appdata/il2cpp-functions.h index 6e71f5b8..992df93e 100644 --- a/appdata/il2cpp-functions.h +++ b/appdata/il2cpp-functions.h @@ -213,6 +213,8 @@ DO_APP_FUNC(String*, GameData_PlayerInfo_get_PlayerName, (GameData_PlayerInfo* _ DO_APP_FUNC(void, AccountManager_UpdateKidAccountDisplay, (AccountManager* __this, MethodInfo* method), "Assembly-CSharp, System.Void AccountManager::UpdateKidAccountDisplay()"); DO_APP_FUNC(void, PlayerStorageManager_OnReadPlayerPrefsComplete, (PlayerStorageManager* __this, void* data, MethodInfo* method), "Assembly-CSharp, System.Void PlayerStorageManager::OnReadPlayerPrefsComplete(Epic.OnlineServices.PlayerDataStorage.ReadFileCallbackInfo)"); +DO_APP_FUNC(void, AchievementManager_1_UnlockAchievement, (AchievementManager_1* __this, String* key, MethodInfo* method), "Assembly-CSharp, System.Void AchievementManager::UnlockAchievement(System.String)"); + // 2022.10.25s DO_APP_FUNC(PlayerData*, DataManager_get_Player, (MethodInfo* method), "Assembly-CSharp, AmongUs.Data.Player.PlayerData AmongUs.Data.DataManager::get_Player()"); DO_APP_FUNC(String*, PlayerCustomizationData_get_Name, (PlayerCustomizationData* __this, MethodInfo* method), "Assembly-CSharp, System.String AmongUs.Data.Player.PlayerCustomizationData::get_Name()"); diff --git a/appdata/il2cpp-types.h b/appdata/il2cpp-types.h index 0fb3b6ec..054d0847 100644 --- a/appdata/il2cpp-types.h +++ b/appdata/il2cpp-types.h @@ -12579,6 +12579,92 @@ namespace app }; #pragma endregion +#pragma region AchievementManager + struct GameModes__Enum__Array { + void* klass; + MonitorData* monitor; + Il2CppArrayBounds* bounds; + il2cpp_array_size_t max_length; + GameModes__Enum vector[32]; + }; + + struct __declspec(align(4)) List_1_AmongUs_GameOptions_GameModes___Fields { + struct GameModes__Enum__Array* _items; + int32_t _size; + int32_t _version; + struct Object* _syncRoot; + }; + + struct List_1_AmongUs_GameOptions_GameModes_ { + void* klass; + MonitorData* monitor; + struct List_1_AmongUs_GameOptions_GameModes___Fields fields; + }; + + struct __declspec(align(4)) Dictionary_2_System_String_List_1_AmongUs_GameOptions_GameModes___Fields { + struct Int32__Array* buckets; + struct Dictionary_2_TKey_TValue_Entry_System_String_List_1_AmongUs_GameOptions_GameModes___Array* entries; + int32_t count; + int32_t version; + int32_t freeList; + int32_t freeCount; + void* comparer; + void* keys; + void* values; + struct Object* _syncRoot; + }; + + struct Dictionary_2_System_String_List_1_AmongUs_GameOptions_GameModes_ { + void* klass; + MonitorData* monitor; + struct Dictionary_2_System_String_List_1_AmongUs_GameOptions_GameModes___Fields fields; + }; + + struct Dictionary_2_TKey_TValue_Entry_System_String_List_1_AmongUs_GameOptions_GameModes_ { + int32_t hashCode; + int32_t next; + struct String* key; + struct List_1_AmongUs_GameOptions_GameModes_* value; + }; + + struct Dictionary_2_TKey_TValue_Entry_System_String_List_1_AmongUs_GameOptions_GameModes___Array { + void* klass; + MonitorData* monitor; + Il2CppArrayBounds* bounds; + il2cpp_array_size_t max_length; + struct Dictionary_2_TKey_TValue_Entry_System_String_List_1_AmongUs_GameOptions_GameModes_ vector[32]; + }; + + struct AchievementManager_1 { + struct AchievementManager_1__Class* klass; + MonitorData* monitor; + //struct AchievementManager_1__Fields fields; + }; + + struct AchievementManager_1__VTable { + VirtualInvokeData Equals; + VirtualInvokeData Finalize; + VirtualInvokeData GetHashCode; + VirtualInvokeData ToString; + VirtualInvokeData Awake; + VirtualInvokeData OnDestroy; + }; + + struct AchievementManager_1__StaticFields { + struct Dictionary_2_System_String_List_1_AmongUs_GameOptions_GameModes_* AchievementGameModeKey; + struct Dictionary_2_System_String_List_1_AmongUs_GameOptions_GameModes_* StatsGameModeKey; + }; + + struct AchievementManager_1__Class { + Il2CppClass_0 _0; + Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets; + struct AchievementManager_1__StaticFields* static_fields; + const Il2CppRGCTXData* rgctx_data; + Il2CppClass_1 _1; + struct AchievementManager_1__VTable vtable; + }; +#pragma endregion + typedef Il2CppObject PlayerData; typedef Il2CppObject PlayerCustomizationData; typedef Il2CppObject PlayerPurchasesData; diff --git a/framework/il2cpp-helpers.h b/framework/il2cpp-helpers.h index 68da0024..16e478be 100644 --- a/framework/il2cpp-helpers.h +++ b/framework/il2cpp-helpers.h @@ -75,6 +75,7 @@ namespace app { class List { public: using iterator = decltype(&E::fields._items->vector[0]); + using value_type = std::remove_cvref_tvector[0])>; constexpr List(E* list) : _Ptr(list) {} constexpr size_t size() const { if (!_Ptr) return 0; @@ -91,6 +92,16 @@ namespace app { auto pList = (List_1_PlayerTask_*)_Ptr; ((void(*)(void*, size_t, const void*))(pList->klass->vtable.RemoveAt.methodPtr))(pList, _Pos, pList->klass->vtable.RemoveAt.method); } + constexpr void add(value_type item) { + if (!_Ptr) return; + auto pList = (List_1_PlayerTask_*)_Ptr; + ((void(*)(void*, value_type, const void*))(pList->klass->vtable.Add.methodPtr))(pList, item, pList->klass->vtable.Add.method); + } + constexpr bool contains(value_type item) const { + if (!_Ptr) return false; + auto pList = (List_1_PlayerTask_*)_Ptr; + return ((bool(*)(void*, value_type, const void*))(pList->klass->vtable.Contains.methodPtr))(pList, item, pList->klass->vtable.Contains.method); + } constexpr iterator begin() const { if (!_Ptr) return nullptr; return _Ptr->fields._items->vector; diff --git a/gui/tabs/settings_tab.cpp b/gui/tabs/settings_tab.cpp index 7161cb9c..494cd234 100644 --- a/gui/tabs/settings_tab.cpp +++ b/gui/tabs/settings_tab.cpp @@ -62,19 +62,16 @@ namespace SettingsTab { State.userName = std::string(*nameBuffer); } } - /* + ImGui::Dummy(ImVec2(7, 7) * State.dpiScale); ImGui::Separator(); ImGui::Dummy(ImVec2(7, 7) * State.dpiScale); - - if (ImGui::Button("Unlock all Steam achievements")) + + if (Achievements::IsSupported() + && ImGui::Button("Unlock all achievements")) { - for (const char* achievement : steamAchievements) - { - Game::SteamUserStats_SetAchievement(convert_to_string(std::string(achievement))); - } - Game::SteamUserStats_StoreStats(); - }*/ + Achievements::UnlockAll(); + } ImGui::EndTabItem(); } diff --git a/user/achievements.cpp b/user/achievements.cpp new file mode 100644 index 00000000..cc1ff0ce --- /dev/null +++ b/user/achievements.cpp @@ -0,0 +1,55 @@ +#include "pch-il2cpp.h" +#include "utility.h" +#include "achievements.hpp" +#include "logger.h" + +namespace Achievements { + + _Ret_maybenull_ AchievementManager_1* GetAchievementManager() { + static AchievementManager_1* manager = nullptr; + if (!manager) { + static AccountManager* accountManager = nullptr; + if (!accountManager) { + Type* AccountManagerType = app::Type_GetType(convert_to_string(translate_type_name("AccountManager, Assembly-CSharp")), NULL); + LOG_ASSERT(AccountManagerType != nullptr); + il2cpp::Array results = app::Object_1_FindObjectsOfType(AccountManagerType, NULL); + if (results.size() == 0) + return nullptr; + accountManager = reinterpret_cast(results[0]); + } + + if (accountManager->fields.prevLoggedInStatus == EOSManager_AccountLoginStatus__Enum::Offline) + return nullptr; + + Type* AchievementManagerType = app::Type_GetType(convert_to_string(translate_type_name("AchievementManager, Assembly-CSharp")), NULL); + LOG_ASSERT(AchievementManagerType != nullptr); + il2cpp::Array results = app::Object_1_FindObjectsOfType(AchievementManagerType, NULL); + if (results.size() == 0) + return nullptr; + manager = reinterpret_cast(results[0]); + } + return manager; + } + + bool IsSupported() { + return GetAchievementManager() != nullptr; + } + + void UnlockAll() { + auto manager = GetAchievementManager(); + if (!manager) return; + + ScopedThreadAttacher managedThreadAttached; + il2cpp::Dictionary achievementGameModeKey = manager->klass->static_fields->AchievementGameModeKey; + for (auto pair : achievementGameModeKey) { + il2cpp::List list = pair.value; + if (!list.contains(app::GameModes__Enum::Normal)) { + list.add(app::GameModes__Enum::Normal); + } + if (!list.contains(app::GameModes__Enum::HideNSeek)) { + list.add(app::GameModes__Enum::HideNSeek); + } + app::AchievementManager_1_UnlockAchievement(manager, pair.key, nullptr); + } + } +} \ No newline at end of file diff --git a/user/achievements.hpp b/user/achievements.hpp index 87b7ec3d..fc76071f 100644 --- a/user/achievements.hpp +++ b/user/achievements.hpp @@ -1,35 +1,5 @@ #pragma once -#include - -std::vector steamAchievements = { - "task_complete_easy", - "task_complete_medium", - "task_complete_hard", - "card_first_try", - "kill_during_lights", - "no_vents_impostor_win", - "kills_first", - "kills_easy", - "kills_medium", - "kills_hard", - "wins_skeld", - "wins_mira", - "wins_polus", - "wins_airship", - "survive_two_impostors", - "win_all_tasks", - "win_sabotage", - "win_kills", - "win_impostor_vote", - "survive_crewmate", - "die_during_medscan", - "fix_own_sabotage", - "three_kills_before_meeting", - "win_always_correct_votes", - "impostorKills", - "tasksCompleted", - "MapWinsSkeld", - "MapWinsPolus", - "MapWinsMira", - "MapWinsAirship" -}; \ No newline at end of file +namespace Achievements { + bool IsSupported(); + void UnlockAll(); +} \ No newline at end of file diff --git a/user/game.cpp b/user/game.cpp index 35764648..98c72a9d 100644 --- a/user/game.cpp +++ b/user/game.cpp @@ -11,12 +11,12 @@ namespace Game { LobbyBehaviour** pLobbyBehaviour = nullptr; RoleManager** pRoleManager = nullptr; - STEAMUSERSTATS_SETACHIEVEMENT* SteamUserStats_SetAchievement = nullptr; - STEAMUSERSTATS_STORESTATS* SteamUserStats_StoreStats = nullptr; + //STEAMUSERSTATS_SETACHIEVEMENT* SteamUserStats_SetAchievement = nullptr; + //STEAMUSERSTATS_STORESTATS* SteamUserStats_StoreStats = nullptr; void scanGameFunctions() { - SteamUserStats_SetAchievement = SignatureScan("E8 ? ? ? ? 6A 00 E8 ? ? ? ? 83 C4 0C 5D C3 A1 ? ? ? ? F6 80 ? ? ? ? ? 74 0F 83 78 74 00 75 09 50 E8 ? ? ? ? 83 C4 04 6A 00 FF 35 ? ? ? ? E8 ? ? ? ? 83 C4 08 5D C3 CC", GetModuleHandleA("GameAssembly.dll")).ResolveCall(); - SteamUserStats_StoreStats = SignatureScan("E8 ? ? ? ? 83 C4 0C 5D C3 A1 ? ? ? ? F6 80 ? ? ? ? ? 74 0F 83 78 74 00 75 09 50 E8 ? ? ? ? 83 C4 04 6A 00 FF 35 ? ? ? ? E8 ? ? ? ? 83 C4 08 5D C3 CC", GetModuleHandleA("GameAssembly.dll")).ResolveCall(); + //SteamUserStats_SetAchievement = SignatureScan("E8 ? ? ? ? 6A 00 E8 ? ? ? ? 83 C4 0C 5D C3 A1 ? ? ? ? F6 80 ? ? ? ? ? 74 0F 83 78 74 00 75 09 50 E8 ? ? ? ? 83 C4 04 6A 00 FF 35 ? ? ? ? E8 ? ? ? ? 83 C4 08 5D C3 CC", GetModuleHandleA("GameAssembly.dll")).ResolveCall(); + //SteamUserStats_StoreStats = SignatureScan("E8 ? ? ? ? 83 C4 0C 5D C3 A1 ? ? ? ? F6 80 ? ? ? ? ? 74 0F 83 78 74 00 75 09 50 E8 ? ? ? ? 83 C4 04 6A 00 FF 35 ? ? ? ? E8 ? ? ? ? 83 C4 08 5D C3 CC", GetModuleHandleA("GameAssembly.dll")).ResolveCall(); } } \ No newline at end of file diff --git a/user/game.h b/user/game.h index 97823816..251c87df 100644 --- a/user/game.h +++ b/user/game.h @@ -28,11 +28,11 @@ namespace Game { extern LobbyBehaviour** pLobbyBehaviour; extern RoleManager** pRoleManager; - typedef bool STEAMUSERSTATS_SETACHIEVEMENT(String* pchName); - typedef bool STEAMUSERSTATS_STORESTATS(); + //typedef bool STEAMUSERSTATS_SETACHIEVEMENT(String* pchName); + //typedef bool STEAMUSERSTATS_STORESTATS(); - extern STEAMUSERSTATS_SETACHIEVEMENT* SteamUserStats_SetAchievement; - extern STEAMUSERSTATS_STORESTATS* SteamUserStats_StoreStats; + //extern STEAMUSERSTATS_SETACHIEVEMENT* SteamUserStats_SetAchievement; + //extern STEAMUSERSTATS_STORESTATS* SteamUserStats_StoreStats; extern void scanGameFunctions(); } \ No newline at end of file