From c163301344c938caca1a0832674e64eb19a95509 Mon Sep 17 00:00:00 2001 From: EricPlayZ Date: Sun, 3 Nov 2024 19:27:40 +0200 Subject: [PATCH] removed PlayerObjProperties class (it is the same as PlayerDI_PH), better multi-threading safety --- EGameTools/EGameTools.vcxproj | 2 - EGameTools/pch/pch.h | 1 + EGameTools/source/core.cpp | 38 ++++++++++++---- EGameTools/source/core.h | 3 +- .../source/game/Engine/CoPhysicsProperty.cpp | 8 ++-- EGameTools/source/game/GamePH/LevelDI.cpp | 4 +- EGameTools/source/game/GamePH/PlayerDI_PH.h | 5 +++ .../game/GamePH/PlayerObjProperties.cpp | 20 --------- .../source/game/GamePH/PlayerObjProperties.h | 19 -------- EGameTools/source/menu/camera.cpp | 6 +-- EGameTools/source/menu/debug.cpp | 2 - EGameTools/source/offsets.h | 2 +- EGameTools/source/utils/hook.h | 45 ++++++++++++++----- 13 files changed, 81 insertions(+), 74 deletions(-) delete mode 100644 EGameTools/source/game/GamePH/PlayerObjProperties.cpp delete mode 100644 EGameTools/source/game/GamePH/PlayerObjProperties.h diff --git a/EGameTools/EGameTools.vcxproj b/EGameTools/EGameTools.vcxproj index 79b7906..bde176c 100644 --- a/EGameTools/EGameTools.vcxproj +++ b/EGameTools/EGameTools.vcxproj @@ -45,7 +45,6 @@ - @@ -158,7 +157,6 @@ - diff --git a/EGameTools/pch/pch.h b/EGameTools/pch/pch.h index 1677226..5da84ab 100644 --- a/EGameTools/pch/pch.h +++ b/EGameTools/pch/pch.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include diff --git a/EGameTools/source/core.cpp b/EGameTools/source/core.cpp index c523539..010438b 100644 --- a/EGameTools/source/core.cpp +++ b/EGameTools/source/core.cpp @@ -38,7 +38,9 @@ namespace Core { #pragma endregion // Core - bool exiting = false; + std::atomic exiting = false; + static std::vector threads{}; + static HANDLE keepAliveEvent{}; int rendererAPI = 0; DWORD gameVer = 0; @@ -232,36 +234,52 @@ namespace Core { spdlog::warn("Initializing config"); Config::InitConfig(); - std::thread(Config::ConfigLoop).detach(); + threads.emplace_back(Config::ConfigLoop); CreateSymlinkForLoadingFiles(); for (auto& hook : *Utils::Hook::HookBase::GetInstances()) { - std::thread([&hook]() { + threads.emplace_back([&hook]() { maxHookThreads.acquire(); - spdlog::warn("Hooking \"{}\"", hook->name.data()); - if (hook->HookLoop()) + if (hook->isHooking) { + spdlog::warn("Hooking \"{}\"", hook->name.data()); + while (hook->isHooking) + Sleep(10); + + if (hook->isHooked) + spdlog::info("Hooked \"{}\"!", hook->name.data()); + } else if (hook->isHooked) spdlog::info("Hooked \"{}\"!", hook->name.data()); + else { + spdlog::warn("Hooking \"{}\"", hook->name.data()); + if (hook->HookLoop()) + spdlog::info("Hooked \"{}\"!", hook->name.data()); + } maxHookThreads.release(); }).detach(); } spdlog::warn("Sorting Player Variables"); - std::thread([]() { + threads.emplace_back([]() { GamePH::PlayerVariables::SortPlayerVars(); spdlog::info("Player Variables sorted"); }).detach(); spdlog::warn("Hooking DX11/DX12 renderer"); - std::thread([]() { + threads.emplace_back([]() { LoopHookRenderer(); spdlog::info("Hooked \"DX11/DX12 renderer\"!"); }).detach(); - const HANDLE proc = GetCurrentProcess(); - WaitForSingleObject(proc, INFINITE); + keepAliveEvent = CreateEventA(nullptr, TRUE, FALSE, nullptr); + WaitForSingleObject(keepAliveEvent, INFINITE); + + for (auto& thread : threads) { + if (thread.joinable()) + thread.join(); + } return TRUE; } @@ -278,5 +296,7 @@ namespace Core { MH_DisableHook(MH_ALL_HOOKS); MH_Uninitialize(); spdlog::info("Unhooked everything"); + + SetEvent(keepAliveEvent); } } diff --git a/EGameTools/source/core.h b/EGameTools/source/core.h index a5ccc0c..0f28666 100644 --- a/EGameTools/source/core.h +++ b/EGameTools/source/core.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "..\utils\values.h" #ifndef VK_NONE @@ -225,7 +226,7 @@ private: }; namespace Core { - extern bool exiting; + extern std::atomic exiting; extern int rendererAPI; extern DWORD gameVer; diff --git a/EGameTools/source/game/Engine/CoPhysicsProperty.cpp b/EGameTools/source/game/Engine/CoPhysicsProperty.cpp index 61e6c33..b347674 100644 --- a/EGameTools/source/game/Engine/CoPhysicsProperty.cpp +++ b/EGameTools/source/game/Engine/CoPhysicsProperty.cpp @@ -1,15 +1,15 @@ #include -#include "..\GamePH\PlayerObjProperties.h" +#include "..\GamePH\PlayerDI_PH.h" #include "CoPhysicsProperty.h" namespace Engine { CoPhysicsProperty* CoPhysicsProperty::Get() { __try { - GamePH::PlayerObjProperties* pPlayerObjProperties = GamePH::PlayerObjProperties::Get(); - if (!pPlayerObjProperties) + GamePH::PlayerDI_PH* pPlayerDI_PH = GamePH::PlayerDI_PH::Get(); + if (!pPlayerDI_PH) return nullptr; - CoPhysicsProperty* ptr = pPlayerObjProperties->pCoPhysicsProperty; + CoPhysicsProperty* ptr = pPlayerDI_PH->pCoPhysicsProperty; if (!Utils::Memory::IsValidPtrMod(ptr, "engine_x64_rwdi.dll")) return nullptr; diff --git a/EGameTools/source/game/GamePH/LevelDI.cpp b/EGameTools/source/game/GamePH/LevelDI.cpp index d088ee1..a70ac27 100644 --- a/EGameTools/source/game/GamePH/LevelDI.cpp +++ b/EGameTools/source/game/GamePH/LevelDI.cpp @@ -2,7 +2,7 @@ #include "..\Engine\CLevel.h" #include "..\offsets.h" #include "LevelDI.h" -#include "PlayerObjProperties.h" +#include "PlayerDI_PH.h" namespace GamePH { bool LevelDI::IsLoading() { @@ -20,7 +20,7 @@ namespace GamePH { static Utils::Time::Timer loadTimer{ 7500 }; static bool isStillLoading = false; - if (IsLoading() || !GamePH::PlayerObjProperties::Get()) { + if (IsLoading() || !GamePH::PlayerDI_PH::Get()) { isStillLoading = true; return false; } diff --git a/EGameTools/source/game/GamePH/PlayerDI_PH.h b/EGameTools/source/game/GamePH/PlayerDI_PH.h index e71e9fe..c370449 100644 --- a/EGameTools/source/game/GamePH/PlayerDI_PH.h +++ b/EGameTools/source/game/GamePH/PlayerDI_PH.h @@ -3,10 +3,15 @@ #include "InventoryItem.h" #include "InventoryContainerDI.h" +namespace Engine { + class CoPhysicsProperty; +} + namespace GamePH { class PlayerDI_PH { public: union { + buffer<0xF0, Engine::CoPhysicsProperty*> pCoPhysicsProperty; buffer<0x35E9, bool> enableTPPModel1; buffer<0x35EA, bool> enableTPPModel2; }; diff --git a/EGameTools/source/game/GamePH/PlayerObjProperties.cpp b/EGameTools/source/game/GamePH/PlayerObjProperties.cpp deleted file mode 100644 index 163aa57..0000000 --- a/EGameTools/source/game/GamePH/PlayerObjProperties.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include "..\offsets.h" -#include "PlayerObjProperties.h" - -namespace GamePH { - PlayerObjProperties* PlayerObjProperties::Get() { - __try { - if (!Offsets::Get_g_PlayerObjProperties()) - return nullptr; - - PlayerObjProperties* ptr = *reinterpret_cast(Offsets::Get_g_PlayerObjProperties()); - if (!Utils::Memory::IsValidPtrMod(ptr, "gamedll_ph_x64_rwdi.dll")) - return nullptr; - - return ptr; - } __except (EXCEPTION_EXECUTE_HANDLER) { - return nullptr; - } - } -} \ No newline at end of file diff --git a/EGameTools/source/game/GamePH/PlayerObjProperties.h b/EGameTools/source/game/GamePH/PlayerObjProperties.h deleted file mode 100644 index d9e9695..0000000 --- a/EGameTools/source/game/GamePH/PlayerObjProperties.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "..\buffer.h" - -namespace Engine { - class CoPhysicsProperty; -} - -namespace GamePH { - class PlayerObjProperties { - public: - union { - buffer<0xF0, Engine::CoPhysicsProperty*> pCoPhysicsProperty; - //buffer<0x2E80, bool> isOutOfBounds; - //buffer<0x2E84, float> outOfBoundsTimer; - }; - - static PlayerObjProperties* Get(); - }; -} \ No newline at end of file diff --git a/EGameTools/source/menu/camera.cpp b/EGameTools/source/menu/camera.cpp index bf498ac..d77447d 100644 --- a/EGameTools/source/menu/camera.cpp +++ b/EGameTools/source/menu/camera.cpp @@ -6,7 +6,7 @@ #include "..\game\GamePH\GameDI_PH.h" #include "..\game\GamePH\LevelDI.h" #include "..\game\GamePH\PlayerVariables.h" -#include "..\game\GamePH\PlayerObjProperties.h" +#include "..\game\GamePH\PlayerDI_PH.h" #include "..\game\GamePH\gameph_misc.h" #include "..\offsets.h" #include "camera.h" @@ -149,8 +149,8 @@ namespace Menu { if (!iLevel || !iLevel->IsLoaded()) return; - GamePH::PlayerObjProperties* playerObjProperties = GamePH::PlayerObjProperties::Get(); - if (playerObjProperties) { + GamePH::PlayerDI_PH* pPlayerDI_PH = GamePH::PlayerDI_PH::Get(); + if (pPlayerDI_PH) { if (Menu::Camera::freeCam.GetValue() && !iLevel->IsTimerFrozen()) GamePH::ShowTPPModel(true); else if (Menu::Camera::freeCam.GetValue() && iLevel->IsTimerFrozen() && !photoMode.GetValue()) diff --git a/EGameTools/source/menu/debug.cpp b/EGameTools/source/menu/debug.cpp index a82631a..6ab945a 100644 --- a/EGameTools/source/menu/debug.cpp +++ b/EGameTools/source/menu/debug.cpp @@ -10,7 +10,6 @@ #include "..\game\GamePH\LogicalPlayer.h" #include "..\game\GamePH\PlayerDI_PH.h" #include "..\game\GamePH\PlayerHealthModule.h" -#include "..\game\GamePH\PlayerObjProperties.h" #include "..\game\GamePH\PlayerState.h" #include "..\game\GamePH\PlayerVariables.h" #include "..\game\GamePH\SessionCooperativeDI.h" @@ -41,7 +40,6 @@ namespace Menu { { "LogicalPlayer", reinterpret_cast(&GamePH::LogicalPlayer::Get) }, { "PlayerDI_PH", reinterpret_cast(&GamePH::PlayerDI_PH::Get) }, { "PlayerHealthModule", reinterpret_cast(&GamePH::PlayerHealthModule::Get) }, - { "PlayerObjProperties", reinterpret_cast(&GamePH::PlayerObjProperties::Get) }, { "PlayerState", reinterpret_cast(&GamePH::PlayerState::Get) }, { "PlayerVariables", reinterpret_cast(&GamePH::PlayerVariables::Get) }, { "SessionCooperativeDI", reinterpret_cast(&GamePH::SessionCooperativeDI::Get) }, diff --git a/EGameTools/source/offsets.h b/EGameTools/source/offsets.h index 55fbf36..d408a5b 100644 --- a/EGameTools/source/offsets.h +++ b/EGameTools/source/offsets.h @@ -71,7 +71,7 @@ struct Offsets { AddStaticOffset(allowVelocityMod_offset, 0x5C) AddStaticOffset(disableHeadCorrection_offset, 0x108) AddOffset(CLobbySteam, "engine_x64_rwdi.dll", "48 8B 05 [?? ?? ?? ?? 48 85 C0 74 ?? 48 83 C0", Utils::SigScan::PatternType::RelativePointer, LPVOID) - AddOffset(g_PlayerObjProperties, "gamedll_ph_x64_rwdi.dll", "48 89 0D [?? ?? ?? ?? E8 ?? ?? ?? ?? 48 85 C0", Utils::SigScan::PatternType::RelativePointer, LPVOID) + //AddOffset(g_PlayerDI_PH, "gamedll_ph_x64_rwdi.dll", "48 89 0D [?? ?? ?? ?? E8 ?? ?? ?? ?? 48 85 C0", Utils::SigScan::PatternType::RelativePointer, LPVOID) // also PlayerObjProperties AddOffset(g_DayNightCycle, "gamedll_ph_x64_rwdi.dll", "48 8B 0D [?? ?? ?? ?? 48 85 C9 74 ?? E8 ?? ?? ?? ?? 84 C0 74 ?? B0 ?? 48 83 C4 ?? C3 32 C0", Utils::SigScan::PatternType::RelativePointer, LPVOID) //AddOffset(g_CameraFPPDI, "gamedll_ph_x64_rwdi.dll", "48 89 05 [?? ?? ?? ?? 40 84 FF", PatternType::RelativePointer, DWORD64*) AddOffset(g_FreeCamera, "gamedll_ph_x64_rwdi.dll", "48 89 05 [?? ?? ?? ?? 48 89 4C 24", Utils::SigScan::PatternType::RelativePointer, DWORD64*) diff --git a/EGameTools/source/utils/hook.h b/EGameTools/source/utils/hook.h index fce2e43..26181d8 100644 --- a/EGameTools/source/utils/hook.h +++ b/EGameTools/source/utils/hook.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include "..\MinHook\MinHook.h" namespace Utils { @@ -30,7 +31,9 @@ namespace Utils { virtual bool HookLoop() { return false; }; - const std::string_view name; + const std::string_view name{}; + std::atomic isHooking = false; + std::atomic isHooked = false; }; template class ByteHook : HookBase { @@ -38,13 +41,18 @@ namespace Utils { ByteHook(const std::string_view& name, GetTargetOffsetRetType(*pGetOffsetFunc)(), unsigned char* patchBytes, size_t bytesAmount, Option* optionRef = nullptr) : HookBase(name), pGetOffsetFunc(pGetOffsetFunc), patchBytes(patchBytes), bytesAmount(bytesAmount), optionRef(optionRef) {} bool HookLoop() override { - if (hooked || (optionRef && !optionRef->GetValue())) + if (isHooked || (optionRef && !optionRef->GetValue())) return true; + if (isHooking) + return true; + + isHooking = true; timeSpentHooking = Utils::Time::Timer(120000); while (true) { if (timeSpentHooking.DidTimePass()) { spdlog::error("Failed hooking \"{}\" after 120 seconds", name); + isHooking = false; return false; } if (!pGetOffsetFunc || !pGetOffsetFunc()) @@ -60,7 +68,8 @@ namespace Utils { } memcpy_s(pGetOffsetFunc(), bytesAmount, patchBytes, bytesAmount); VirtualProtect(pGetOffsetFunc(), bytesAmount, originalProtection, &oldProtection); - hooked = true; + isHooked = true; + isHooking = false; return true; Sleep(10); @@ -68,7 +77,7 @@ namespace Utils { } void Enable() { - if (hooked) + if (isHooked) return; DWORD originalProtection = 0; @@ -81,10 +90,10 @@ namespace Utils { } memcpy_s(pGetOffsetFunc(), bytesAmount, patchBytes, bytesAmount); VirtualProtect(pGetOffsetFunc(), bytesAmount, originalProtection, &oldProtection); - hooked = true; + isHooked = true; } void Disable() { - if (!hooked) + if (!isHooked) return; DWORD originalProtection = 0; @@ -93,11 +102,11 @@ namespace Utils { VirtualProtect(pGetOffsetFunc(), bytesAmount, PAGE_EXECUTE_READWRITE, &originalProtection); memcpy_s(pGetOffsetFunc(), bytesAmount, origBytes, bytesAmount); VirtualProtect(pGetOffsetFunc(), bytesAmount, originalProtection, &oldProtection); - hooked = false; + isHooked = false; } void Toggle() { if (!optionRef) { - hooked ? Disable() : Enable(); + isHooked ? Disable() : Enable(); return; } @@ -111,8 +120,6 @@ namespace Utils { unsigned char* patchBytes = nullptr; size_t bytesAmount = 0; - bool hooked = false; - Utils::Time::Timer timeSpentHooking{ 120000 }; }; template @@ -123,11 +130,16 @@ namespace Utils { bool HookLoop() override { if (pOriginal) return true; + if (isHooking) + return true; + + isHooking = true; timeSpentHooking = Utils::Time::Timer(120000); while (true) { if (timeSpentHooking.DidTimePass()) { spdlog::error("Failed hooking function \"{}\" after 120 seconds", name); + isHooking = false; return false; } if (!pGetOffsetFunc) @@ -137,6 +149,8 @@ namespace Utils { pTarget = reinterpret_cast(pGetOffsetFunc()); else if (!pOriginal && MH_CreateHook(pTarget, pDetour, reinterpret_cast(&pOriginal)) == MH_OK) { MH_EnableHook(pTarget); + isHooked = true; + isHooking = false; return true; } @@ -160,11 +174,16 @@ namespace Utils { bool HookLoop() override { if (pOriginal) return true; + if (isHooking) + return true; + + isHooking = true; timeSpentHooking = Utils::Time::Timer(120000); while (true) { if (timeSpentHooking.DidTimePass()) { spdlog::error("Failed hooking function \"{}\" after 120 seconds", name); + isHooking = false; return false; } if (!pGetOffsetFunc) @@ -174,7 +193,11 @@ namespace Utils { pInstance = pGetOffsetFunc(); else if (!pOriginal) { HookVT(pInstance, pDetour, reinterpret_cast(&pOriginal), offset); - return true; + if (pOriginal) { + isHooked = true; + isHooking = false; + return true; + } } Sleep(10);