diff --git a/src/core/commands/BoolCommand.cpp b/src/core/commands/BoolCommand.cpp index 5cf945a..d65c0bb 100644 --- a/src/core/commands/BoolCommand.cpp +++ b/src/core/commands/BoolCommand.cpp @@ -34,14 +34,21 @@ namespace YimMenu void BoolCommand::SetState(bool state) { if (state && !m_State) + { FiberPool::Push([this] { OnEnable(); + m_Ready = true; }); + } else if (!state && m_State) + { FiberPool::Push([this] { OnDisable(); + m_Ready = true; }); + } + m_Ready = false; m_State = state; MarkDirty(); } @@ -49,10 +56,12 @@ namespace YimMenu void BoolCommand::Initialize() { OnEnable(); + m_Ready = true; } void BoolCommand::Shutdown() { + m_Ready = false; OnDisable(); } } \ No newline at end of file diff --git a/src/core/commands/BoolCommand.hpp b/src/core/commands/BoolCommand.hpp index c07910f..3111167 100644 --- a/src/core/commands/BoolCommand.hpp +++ b/src/core/commands/BoolCommand.hpp @@ -13,11 +13,14 @@ namespace YimMenu virtual void LoadState(nlohmann::json& value) override; bool m_State = false; + bool m_Ready = false; public: BoolCommand(std::string name, std::string label, std::string description, bool def_value = false); bool GetState(); void SetState(bool state); void Initialize(); void Shutdown(); + // returns true unless there's a pending OnEnable()/OnDisable() call that hasn't run yet + inline bool IsReady() { return m_Ready; } }; } \ No newline at end of file diff --git a/src/core/commands/Commands.cpp b/src/core/commands/Commands.cpp index 6ca23f1..7b1e5b1 100644 --- a/src/core/commands/Commands.cpp +++ b/src/core/commands/Commands.cpp @@ -45,7 +45,7 @@ namespace YimMenu void Commands::RunLoopedCommandsImpl() { for (auto& command : m_LoopedCommands) - if (command->GetState()) + if (command->GetState() && command->IsReady()) command->Tick(); } diff --git a/src/core/memory/BytePatches.hpp b/src/core/memory/BytePatches.hpp index 0556a82..266fc06 100644 --- a/src/core/memory/BytePatches.hpp +++ b/src/core/memory/BytePatches.hpp @@ -23,16 +23,16 @@ namespace YimMenu m_Address(address), m_Applied(false) { - m_Size = sizeof(std::remove_pointer_t>); + m_Size = sizeof(std::remove_pointer_t>); m_OriginalBytes = std::make_unique(m_Size); - m_Value = std::make_unique(m_Size); + m_Value = std::make_unique(m_Size); memcpy(m_OriginalBytes.get(), m_Address, m_Size); memcpy(m_Value.get(), &value, m_Size); } Patch(void* address, std::span const values) : - m_Address((void*)address), + m_Address(address), m_Applied(false) { m_Size = values.size(); @@ -54,17 +54,20 @@ namespace YimMenu }; private: - static inline std::vector> m_Patches; + static inline std::vector> m_Patches{}; + static inline std::mutex m_Mutex; public: template static std::shared_ptr Add(TAddr address, std::remove_pointer_t> value) { + std::lock_guard lock(m_Mutex); return m_Patches.emplace_back(std::make_shared(address, value)); } static std::shared_ptr Add(void* address, std::span const values) { + std::lock_guard lock(m_Mutex); return m_Patches.emplace_back(std::make_shared(address, values)); } diff --git a/src/core/memory/ModuleMgr.cpp b/src/core/memory/ModuleMgr.cpp index 59da5bc..d835de0 100644 --- a/src/core/memory/ModuleMgr.cpp +++ b/src/core/memory/ModuleMgr.cpp @@ -22,6 +22,8 @@ namespace YimMenu { m_CachedModules.clear(); + m_ManualMapped = true; + const auto peb = reinterpret_cast(NtCurrentTeb()->ProcessEnvironmentBlock); if (!peb) return false; @@ -42,6 +44,9 @@ namespace YimMenu { auto module = std::make_unique(tableEntry); + if (module->Base() == reinterpret_cast(g_DllInstance)) + m_ManualMapped = false; + m_CachedModules.insert({Joaat(module->Name()), std::move(module)}); } } @@ -53,4 +58,9 @@ namespace YimMenu { return m_CachedModules; } + + bool ModuleMgr::IsManualMapped() + { + return m_ManualMapped; + } } \ No newline at end of file diff --git a/src/core/memory/ModuleMgr.hpp b/src/core/memory/ModuleMgr.hpp index 1edef53..a433358 100644 --- a/src/core/memory/ModuleMgr.hpp +++ b/src/core/memory/ModuleMgr.hpp @@ -27,8 +27,10 @@ namespace YimMenu */ bool LoadModules(); std::unordered_multimap>& GetModules(); + bool IsManualMapped(); private: + bool m_ManualMapped = false; std::unordered_multimap> m_CachedModules; }; diff --git a/src/core/memory/PatternScanner.cpp b/src/core/memory/PatternScanner.cpp index 583377d..cd69c24 100644 --- a/src/core/memory/PatternScanner.cpp +++ b/src/core/memory/PatternScanner.cpp @@ -1,6 +1,7 @@ #include "PatternScanner.hpp" #include "Module.hpp" +#include "ModuleMgr.hpp" #include "core/backend/PatternCache.hpp" #include @@ -18,19 +19,29 @@ namespace YimMenu if (!m_Module || !m_Module->Valid()) return false; - std::vector> jobs; - for (const auto& [pattern, func] : m_Patterns) - { - jobs.emplace_back(std::async(&PatternScanner::ScanInternal, this, pattern, func)); - } - bool scanSuccess = true; - for (auto& job : jobs) - { - job.wait(); - if (scanSuccess) - scanSuccess = job.get(); + if (!ModuleMgr.IsManualMapped()) + { + std::vector> jobs; + for (const auto& [pattern, func] : m_Patterns) + { + jobs.emplace_back(std::async(&PatternScanner::ScanInternal, this, pattern, func)); + } + + for (auto& job : jobs) + { + job.wait(); + + if (scanSuccess) + scanSuccess = job.get(); + } + } + else + { + // spawning threads seems to throw STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED when manual mapping + for (const auto& [pattern, func] : m_Patterns) + scanSuccess = scanSuccess && PatternScanner::ScanInternal(pattern, func); } return scanSuccess; @@ -45,7 +56,7 @@ namespace YimMenu auto offset = PatternCache::GetCachedOffset(pattern->Hash().Update(m_Module->Size())); if (offset.has_value()) { - LOG(INFO) << "Using cached pattern [" << pattern->Name() << "] : [" << HEX(m_Module->Base() + offset.value()) << "]"; + LOGF(INFO, "Using cached pattern [{}] : [{:X}] [Hash(): {:X}]", pattern->Name(), m_Module->Base() + offset.value(), pattern->Hash().Update(m_Module->Size()).m_Hash); std::invoke(func, m_Module->Base() + offset.value()); return true; } diff --git a/src/game/backend/AnticheatBypass.cpp b/src/game/backend/AnticheatBypass.cpp index 57a8bc3..03824b3 100644 --- a/src/game/backend/AnticheatBypass.cpp +++ b/src/game/backend/AnticheatBypass.cpp @@ -77,12 +77,12 @@ namespace YimMenu if (m_BattlEyeRunning) LOGF(WARNING, "If you are not running an actual BattlEye bypass, exit the game immediately and ensure that BE is properly disabled"); - if (!m_IsFSLLoaded) + if (!m_FSLProvidesBEBypass) Pointers.BattlEyeStatusUpdatePatch->Apply(); while (true) { - if (!m_IsFSLLoaded) + if (!m_FSLProvidesBEBypass) { *Pointers.BERestartStatus = 0; *Pointers.NeedsBERestart = false; diff --git a/src/game/backend/AnticheatBypass.hpp b/src/game/backend/AnticheatBypass.hpp index ac6f854..a867c4d 100644 --- a/src/game/backend/AnticheatBypass.hpp +++ b/src/game/backend/AnticheatBypass.hpp @@ -15,9 +15,9 @@ namespace YimMenu bool m_IsFSLLoaded = false; bool m_BattlEyeRunning = false; - int m_FSLVersion = -1; + int m_FSLVersion = -1; bool m_FSLProvidesLocalSaves = false; - bool m_FSLProvidesBEBypass = false; + bool m_FSLProvidesBEBypass = false; public: static void RunScript() diff --git a/src/game/frontend/Menu.cpp b/src/game/frontend/Menu.cpp index f392acc..d73af58 100644 --- a/src/game/frontend/Menu.cpp +++ b/src/game/frontend/Menu.cpp @@ -17,6 +17,8 @@ #include "submenus/Debug.hpp" #include "submenus/World.hpp" #include "core/filemgr/FileMgr.hpp" +#include "core/memory/ModuleMgr.hpp" + namespace YimMenu { void Menu::Init() @@ -42,7 +44,8 @@ namespace YimMenu ImGui::SetNextWindowSize(ImVec2((*Pointers.ScreenResX / 2.5), (*Pointers.ScreenResY / 2.5)), ImGuiCond_Once); if (ImGui::Begin("YimMenuV2", nullptr, ImGuiWindowFlags_NoDecoration)) { - //ImGui::BeginDisabled(*Pointers.IsSessionStarted); + // TODO: should we just remove unload? + ImGui::BeginDisabled(*Pointers.IsSessionStarted || ModuleMgr.IsManualMapped()); if (ImGui::Button("Unload", ImVec2(120, 0))) { if (true) @@ -57,7 +60,7 @@ namespace YimMenu g_Running = false; } } - //ImGui::EndDisabled(); + ImGui::EndDisabled(); UIManager::Draw(); } diff --git a/src/main.cpp b/src/main.cpp index 4bb402e..909968b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,6 +38,9 @@ namespace YimMenu if (!ModuleMgr.LoadModules()) goto EARLY_UNLOAD; + if (ModuleMgr.IsManualMapped()) + LOGF(WARNING, "Manual mapping detected, switch to normal injection if you're having issues"); + if (!Pointers.Init()) goto EARLY_UNLOAD; @@ -99,8 +102,9 @@ EARLY_UNLOAD: BOOL WINAPI DllMain(HINSTANCE dllInstance, DWORD reason, void*) { using namespace YimMenu; - - DisableThreadLibraryCalls(dllInstance); + + if (dllInstance) + DisableThreadLibraryCalls(dllInstance); if (reason == DLL_PROCESS_ATTACH) {