From f40962c80060fc7a6b7f818975e90dc8010b1029 Mon Sep 17 00:00:00 2001 From: Ben McAvoy Date: Tue, 14 Jan 2025 04:09:10 +0000 Subject: [PATCH] feat: modtool support --- CarbonLauncher/CarbonLauncher.vcxproj | 8 +- CarbonLauncher/include/discordmanager.h | 3 - CarbonLauncher/include/guimanager.h | 7 +- .../include/{repomanager.h => modmanager.h} | 27 ++--- .../{gamemanager.h => processmanager.h} | 8 +- CarbonLauncher/include/state.h | 10 +- CarbonLauncher/src/discordmanager.cpp | 4 +- CarbonLauncher/src/guimanager.cpp | 27 +++-- .../src/{repomanager.cpp => modmanager.cpp} | 114 +++++++++++++----- .../{gamemanager.cpp => processmanager.cpp} | 44 ++++--- 10 files changed, 163 insertions(+), 89 deletions(-) rename CarbonLauncher/include/{repomanager.h => modmanager.h} (73%) rename CarbonLauncher/include/{gamemanager.h => processmanager.h} (94%) rename CarbonLauncher/src/{repomanager.cpp => modmanager.cpp} (68%) rename CarbonLauncher/src/{gamemanager.cpp => processmanager.cpp} (83%) diff --git a/CarbonLauncher/CarbonLauncher.vcxproj b/CarbonLauncher/CarbonLauncher.vcxproj index 934aeb0..8ea3752 100644 --- a/CarbonLauncher/CarbonLauncher.vcxproj +++ b/CarbonLauncher/CarbonLauncher.vcxproj @@ -145,10 +145,10 @@ - + - + @@ -163,9 +163,9 @@ - + - + diff --git a/CarbonLauncher/include/discordmanager.h b/CarbonLauncher/include/discordmanager.h index 012f4e5..adb450d 100644 --- a/CarbonLauncher/include/discordmanager.h +++ b/CarbonLauncher/include/discordmanager.h @@ -1,8 +1,5 @@ #pragma once -/*#include -#include */ - #include #include diff --git a/CarbonLauncher/include/guimanager.h b/CarbonLauncher/include/guimanager.h index 6c9d702..9e36343 100644 --- a/CarbonLauncher/include/guimanager.h +++ b/CarbonLauncher/include/guimanager.h @@ -9,6 +9,8 @@ #include +#include "modmanager.h" + namespace Carbon { enum LogColour : WORD { DARKGREEN = 2, @@ -31,9 +33,6 @@ namespace Carbon { GUIManager(); ~GUIManager(); - // Sets the render callback (called every frame on the main thread) - // @param callback The callback to call - // @note This is where you should put your ImGui code void RenderCallback(std::function callback) { this->renderCallback = callback; } @@ -45,6 +44,8 @@ namespace Carbon { GLFWwindow* window; std::function renderCallback; + ModTarget target = ModTarget::Game; + enum class Tab { MyMods, Discover, diff --git a/CarbonLauncher/include/repomanager.h b/CarbonLauncher/include/modmanager.h similarity index 73% rename from CarbonLauncher/include/repomanager.h rename to CarbonLauncher/include/modmanager.h index c24bed5..5a66780 100644 --- a/CarbonLauncher/include/repomanager.h +++ b/CarbonLauncher/include/modmanager.h @@ -31,39 +31,34 @@ namespace Carbon { void Update(); }; - struct Repo { - // The name of the repository (e.g. ScrappySM, Scrap-Mods) - std::string name; - - // The link to the repositories website - std::string link; - - // A list of all the mods - std::vector mods; + enum ModTarget { + Game, // Scrap Mechanic + ModTool, // Scrap Mechanic Mod Tool }; - class RepoManager { + class ModManager { public: // Initializes the RepoManager and downloads the repos.json file - RepoManager(); - ~RepoManager(); + ModManager(); + ~ModManager(); // Converts a JSON object to a Repo object // @param json The JSON object to convert // @return The converted Repo object (`json` -> `Repo`) - std::vector URLToMods(const std::string& url); + std::pair, std::vector> URLToMods(const std::string& url); // Gets all the repos // @return A vector of all the repos - std::vector& GetMods() { + std::vector& GetMods(ModTarget target) { std::lock_guard lock(this->repoMutex); - return this->mods; + return target == ModTarget::Game ? gameMods : modToolMods; } bool hasLoaded = false; private: - std::vector mods; + std::vector gameMods; + std::vector modToolMods; std::optional JSONToMod(const nlohmann::json& jMod); std::mutex repoMutex; diff --git a/CarbonLauncher/include/gamemanager.h b/CarbonLauncher/include/processmanager.h similarity index 94% rename from CarbonLauncher/include/gamemanager.h rename to CarbonLauncher/include/processmanager.h index a4655b0..fe7dd99 100644 --- a/CarbonLauncher/include/gamemanager.h +++ b/CarbonLauncher/include/processmanager.h @@ -13,12 +13,12 @@ namespace Carbon { // Manages the game process including starting and stopping it // along with monitoring the game's executable and loaded modules - class GameManager { + class ProcessManager { public: // Initializes the game manager and starts a thread // listening for the game process - GameManager(); - ~GameManager(); + ProcessManager(); + ~ProcessManager(); // Checks if the game is running // @return True if the game is running, false otherwise @@ -31,7 +31,7 @@ namespace Carbon { // Starts the game and waits for it to be running // This function will block until the game is running // This function spawns a new thread to actually start the game process - void LaunchGame(); + void LaunchProcess(const std::string& name); // Stops the game forcefully void KillGame(); diff --git a/CarbonLauncher/include/state.h b/CarbonLauncher/include/state.h index 54d158f..992ea3a 100644 --- a/CarbonLauncher/include/state.h +++ b/CarbonLauncher/include/state.h @@ -5,9 +5,9 @@ #include "guimanager.h" #include "discordmanager.h" -#include "gamemanager.h" +#include "processmanager.h" #include "pipemanager.h" -#include "repomanager.h" +#include "modmanager.h" namespace Carbon { struct LogMessage { @@ -40,9 +40,9 @@ namespace Carbon { Carbon::GUIManager guiManager; Carbon::DiscordManager discordManager; - Carbon::GameManager gameManager; + Carbon::ProcessManager processManager; Carbon::PipeManager pipeManager; - Carbon::RepoManager repoManager; + Carbon::ModManager modManager; // The settings for the Carbon Launcher Carbon::Settings settings; @@ -52,7 +52,7 @@ namespace Carbon { // The target process to manage (e.g. ScrapMechanic.exe) // This should never be a process that does not have a Contraption // located in the same place as ScrapMechanic.exe - const char* processTarget = "ScrapMechanic.exe"; + // const char* processTarget = "ScrapMechanic.exe"; // const char* processTarget = "DummyGame.exe"; }; }; // namespace Carbon diff --git a/CarbonLauncher/src/discordmanager.cpp b/CarbonLauncher/src/discordmanager.cpp index 2a4d97e..f7257a5 100644 --- a/CarbonLauncher/src/discordmanager.cpp +++ b/CarbonLauncher/src/discordmanager.cpp @@ -101,11 +101,11 @@ void DiscordManager::Update() { case 2: spdlog::trace("In a game!"); - this->UpdateState(fmt::format("In a game! ({} mods loaded)", C.gameManager.GetLoadedCustomModules())); + this->UpdateState(fmt::format("In a game! ({} mods loaded)", C.processManager.GetLoadedCustomModules())); break; case 3: spdlog::trace("In the main menu"); - this->UpdateState(fmt::format("In the main menu with {} mods loaded", C.gameManager.GetLoadedCustomModules())); + this->UpdateState(fmt::format("In the main menu with {} mods loaded", C.processManager.GetLoadedCustomModules())); break; }; diff --git a/CarbonLauncher/src/guimanager.cpp b/CarbonLauncher/src/guimanager.cpp index 9e64c90..092cc0e 100644 --- a/CarbonLauncher/src/guimanager.cpp +++ b/CarbonLauncher/src/guimanager.cpp @@ -227,9 +227,9 @@ void _GUI() { ImGui::BeginChild("Control", ImVec2(0, 64), true); - if (C.gameManager.IsGameRunning()) { + if (C.processManager.IsGameRunning()) { if (ImGui::Button(ICON_FA_STOP " Kill Game", ImVec2(128, 48))) { - C.gameManager.KillGame(); + C.processManager.KillGame(); } if (ImGui::IsItemHovered()) { @@ -240,14 +240,25 @@ void _GUI() { } else { if (ImGui::Button(ICON_FA_PLAY " Launch Game", ImVec2(128, 48))) { - C.gameManager.LaunchGame(); + C.processManager.LaunchProcess(C.guiManager.target == ModTarget::Game ? "ScrapMechanic.exe" : "ModTool.exe"); } } ImGui::SameLine(); + // Combo box for selecting the mod target + static const char* items[] = { "Game", "Mod Tool" }; + static int item_current = 0; + ImGui::SetNextItemWidth(128); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 12); + if (ImGui::Combo("Target", &item_current, items, IM_ARRAYSIZE(items))) { + C.guiManager.target = item_current == 0 ? ModTarget::Game : ModTarget::ModTool; + } + + ImGui::SameLine(); + // Display if the pipe is connected or not if the game is running - if (C.gameManager.IsGameRunning()) { + if (C.processManager.IsGameRunning()) { if (!C.pipeManager.IsConnected()) { static ImVec4 colours[3] = {}; if (colours[0].x == 0) { @@ -274,7 +285,7 @@ void _GUI() { if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); - ImGui::Text("The pipe is disconnected, the game may not be running correctly and Carbon Launcher cannot communicate with it."); + ImGui::Text("The pipe is disconnected, the game may not be running correctly and Carbon Launcher cannot communicate with it, did you launch the game from the launcher?"); ImGui::EndTooltip(); } @@ -337,7 +348,7 @@ void _GUI() { auto renderMod = [&](Mod& mod) -> void { ImGui::BeginChild(mod.ghRepo.c_str(), ImVec2(0, 72), false); - float buttons = mod.wantsUpdate ? 2.75 : 2; + float buttons = mod.wantsUpdate ? 2.75f : 2.0f; ImGui::BeginChild("Details", ImVec2(ImGui::GetContentRegionAvail().x - (64 * buttons), 0), false); ImGui::SetWindowFontScale(1.2f); @@ -420,13 +431,13 @@ void _GUI() { }; auto renderMods = [&](bool mustBeInstalled) -> void { - for (auto& mod : C.repoManager.GetMods()) { + for (auto& mod : C.modManager.GetMods(C.guiManager.target)) { if (mod.installed == mustBeInstalled) { renderMod(mod); } } - if (std::all_of(C.repoManager.GetMods().begin(), C.repoManager.GetMods().end(), [&](Mod& mod) -> bool { + if (std::all_of(C.modManager.GetMods(C.guiManager.target).begin(), C.modManager.GetMods(C.guiManager.target).end(), [&](Mod& mod) -> bool { return mod.installed != mustBeInstalled; })) { if (mustBeInstalled) { diff --git a/CarbonLauncher/src/repomanager.cpp b/CarbonLauncher/src/modmanager.cpp similarity index 68% rename from CarbonLauncher/src/repomanager.cpp rename to CarbonLauncher/src/modmanager.cpp index 27d637e..3bffb7f 100644 --- a/CarbonLauncher/src/repomanager.cpp +++ b/CarbonLauncher/src/modmanager.cpp @@ -1,4 +1,4 @@ -#include "repomanager.h" +#include "modmanager.h" #include "state.h" #include "utils.h" @@ -37,20 +37,50 @@ std::string getDefaultBranch(std::string ghUser, std::string ghRepo) { } } -std::optional RepoManager::JSONToMod(const nlohmann::json& jMod) { - std::string branch = getDefaultBranch(jMod["ghUser"].get(), jMod["ghRepo"].get()); - std::string manifestURL = fmt::format("https://raw.githubusercontent.com/{}/{}/{}/manifest.json", jMod["ghUser"].get(), jMod["ghRepo"].get(), branch); +std::optional ModManager::JSONToMod(const nlohmann::json& jMod) { + std::string branch = ""; + + std::string user = ""; + std::string repo = ""; + + if (jMod.is_string()) { + std::string modRepo = jMod.get(); + user = modRepo.substr(0, modRepo.find('/')); + repo = modRepo.substr(modRepo.find('/') + 1); + } + else { + user = jMod["ghUser"]; + repo = jMod["ghRepo"]; + } + + branch = getDefaultBranch(user, repo); + + std::string manifestURL = fmt::format("https://raw.githubusercontent.com/{}/{}/{}/manifest.json", user, repo, branch); cpr::Response manifest = cpr::Get(cpr::Url{ manifestURL }); bool hasManifest = manifest.status_code == 200; Mod mod; - mod.ghUser = jMod["ghUser"]; - mod.ghRepo = jMod["ghRepo"]; + + std::string ghUser = ""; + std::string ghRepo = ""; + if (jMod.is_string()) { + std::string modRepo = jMod.get(); + ghUser = modRepo.substr(0, modRepo.find('/')); + ghRepo = modRepo.substr(modRepo.find('/') + 1); + + mod.ghUser = ghUser; + mod.ghRepo = ghRepo; + } + else { + mod.ghUser = jMod["ghUser"]; + mod.ghRepo = jMod["ghRepo"]; + ghUser = jMod["ghUser"]; + ghRepo = jMod["ghRepo"]; + } if (hasManifest) { - std::string modRepo = jMod["ghRepo"].get(); - spdlog::trace("Mod {} has a manifest.json!", modRepo); + spdlog::trace("Mod {} has a manifest.json!", ghUser + "/" + ghRepo); auto jManifest = nlohmann::json::parse(manifest.text); mod.name = jManifest["name"]; @@ -68,11 +98,16 @@ std::optional RepoManager::JSONToMod(const nlohmann::json& jMod) { } // Check if the mod is installed - if (std::filesystem::exists(Utils::GetDataDir() + "/mods/" + mod.ghRepo)) { + if (std::filesystem::exists(fmt::format("{}/mods/game/{}", Utils::GetDataDir(), mod.ghRepo)) || std::filesystem::exists(fmt::format("{}/mods/modtool/{}", Utils::GetDataDir(), mod.ghRepo))) { mod.installed = true; // Check if the mod wants an update - std::string tagFile = Utils::GetDataDir() + "/mods/" + mod.ghRepo + "/tag"; + //std::string tagFile = Utils::GetDataDir() + "/mods/" + (mod.ghRepo == "CarbonLauncher" ? "modtool" : "game") + "/" + mod.ghRepo + ".tag"; + std::string tagFile = fmt::format("{}mods/game/{}/tag", Utils::GetDataDir(), mod.ghRepo); + if (!std::filesystem::exists(tagFile)) { + tagFile = fmt::format("{}mods/modtool/{}/tag", Utils::GetDataDir(), mod.ghRepo); + } + spdlog::info("Checking tag file: {}", tagFile); std::ifstream file(tagFile); std::string tag; file >> tag; @@ -104,7 +139,7 @@ std::optional RepoManager::JSONToMod(const nlohmann::json& jMod) { return mod; } -std::vector RepoManager::URLToMods(const std::string& url) { +std::pair, std::vector> ModManager::URLToMods(const std::string& url) { std::chrono::time_point start = std::chrono::system_clock::now(); cpr::Response response = cpr::Get(cpr::Url{ url }); @@ -117,13 +152,26 @@ std::vector RepoManager::URLToMods(const std::string& url) { return {}; } - std::vector mods; std::vector threads; - for (auto& jMod : json["mods"]) { - threads.push_back(std::thread([this, &mods, jMod]() { + std::mutex mtx; + + std::vector gameMods; + for (auto& jMod : json["mods"]["game"]) { + threads.push_back(std::thread([&]() { + auto mod = this->JSONToMod(jMod); + if (mod.has_value()) + std::lock_guard lock(mtx); + gameMods.push_back(mod.value()); + })); + } + + std::vector modToolMods; + for (auto& jMod : json["mods"]["modtool"]) { + threads.push_back(std::thread([&, this]() { auto mod = this->JSONToMod(jMod); if (mod.has_value()) - mods.push_back(mod.value()); + std::lock_guard lock(mtx); + modToolMods.push_back(mod.value()); })); } @@ -133,24 +181,28 @@ std::vector RepoManager::URLToMods(const std::string& url) { std::chrono::time_point end = std::chrono::system_clock::now(); std::chrono::duration elapsed_seconds = end - start; - spdlog::info("Loaded {} mods in {} seconds", mods.size(), elapsed_seconds.count()); + spdlog::info("Loaded {} mods in {} seconds", gameMods.size() + modToolMods.size(), elapsed_seconds.count()); - return mods; + return { gameMods, modToolMods }; } -RepoManager::RepoManager() { +ModManager::ModManager() { std::thread([this]() { // Allow some time for the console to initialize std::this_thread::sleep_for(std::chrono::milliseconds(200)); std::lock_guard lock(this->repoMutex); - this->mods = URLToMods(REPOS_URL); + //this->mods = URLToMods(REPOS_URL); + auto mods = URLToMods(REPOS_URL); + this->gameMods = mods.first; + this->modToolMods = mods.second; this->hasLoaded = true; }).detach(); } -RepoManager::~RepoManager() { - this->mods.clear(); +ModManager::~ModManager() { + this->gameMods.clear(); + this->modToolMods.clear(); } void Mod::Install() { @@ -204,11 +256,14 @@ void Mod::Install() { } // mod dir - std::string modDir = Utils::GetDataDir() + "/mods/" + this->ghRepo + "/"; + //std::string modDir = Utils::GetDataDir() + "/mods/" + this->ghRepo + "/"; + //std::string modDir = Utils::GetDataDir() + "/mods/" + C.guiManager.target == ModTarget::Game ? "game" : "modtool" + "/" + this->ghRepo + "/"; + std::string modDir = fmt::format("{}mods/{}/{}", Utils::GetDataDir(), C.guiManager.target == ModTarget::Game ? "game" : "modtool", this->ghRepo); + spdlog::info("modDir: {}", modDir); std::filesystem::create_directories(modDir); // mod file - std::string modFile = modDir + name; + std::string modFile = modDir + "\\" + name; std::ofstream file(modFile, std::ios::binary); file << download.text; file.close(); @@ -217,7 +272,7 @@ void Mod::Install() { } // Save `tag` file with the tag name - std::string tagFile = Utils::GetDataDir() + "/mods/" + this->ghRepo + "/tag"; + std::string tagFile = fmt::format("{}mods/{}/{}", Utils::GetDataDir(), C.guiManager.target == ModTarget::Game ? "game" : "modtool", this->ghRepo) + "/tag"; std::ofstream file(tagFile); file << tag; file.close(); @@ -229,19 +284,20 @@ void Mod::Install() { } void Mod::Uninstall() { - if (C.gameManager.IsGameRunning()) { + if (C.processManager.IsGameRunning()) { spdlog::error("Game is running, cannot uninstall mod"); return; } - std::string modDir = Utils::GetDataDir() + "/mods/" + this->ghRepo + "/"; + //std::string modDir = Utils::GetDataDir() + "/mods/" + this->ghRepo + "/"; + std::string modDir = fmt::format("{}mods/{}/{}", Utils::GetDataDir(), C.guiManager.target == ModTarget::Game ? "game" : "modtool", this->ghRepo); std::filesystem::remove_all(modDir); this->installed = false; spdlog::info("Uninstalled: {}", this->name); } void Mod::Update() { - if (C.gameManager.IsGameRunning()) { + if (C.processManager.IsGameRunning()) { spdlog::error("Game is running, cannot update mod"); return; } @@ -283,7 +339,7 @@ void Mod::Update() { for (const auto& [name, url] : downloadURLs) { auto download = cpr::Get(cpr::Url{ url }, authHeader); // mod dir - std::string modDir = Utils::GetDataDir() + "/mods/" + this->ghRepo + "/"; + std::string modDir = fmt::format("{}mods/{}/{}", Utils::GetDataDir(), C.guiManager.target == ModTarget::Game ? "game" : "modtool", this->ghRepo); std::filesystem::create_directories(modDir); // mod file std::string modFile = modDir + name; @@ -294,7 +350,7 @@ void Mod::Update() { } // Save `tag` file with the tag name - std::string tagFile = Utils::GetDataDir() + "/mods/" + this->ghRepo + "/tag"; + std::string tagFile = fmt::format("{}mods/{}/{}", Utils::GetDataDir(), C.guiManager.target == ModTarget::Game ? "game" : "modtool", this->ghRepo) + "/tag"; std::ofstream file(tagFile); file << tag; file.close(); diff --git a/CarbonLauncher/src/gamemanager.cpp b/CarbonLauncher/src/processmanager.cpp similarity index 83% rename from CarbonLauncher/src/gamemanager.cpp rename to CarbonLauncher/src/processmanager.cpp index 6881691..1daee87 100644 --- a/CarbonLauncher/src/gamemanager.cpp +++ b/CarbonLauncher/src/processmanager.cpp @@ -1,4 +1,4 @@ -#include "gamemanager.h" +#include "processmanager.h" #include "state.h" #include "utils.h" @@ -14,7 +14,7 @@ using namespace Carbon; -GameManager::GameManager() { +ProcessManager::ProcessManager() { this->gameStatusThread = std::thread([this]() { std::this_thread::sleep_for(std::chrono::milliseconds(500)); @@ -36,7 +36,7 @@ GameManager::GameManager() { bool found = false; do { - std::string target(C.processTarget); + std::string target(C.guiManager.target == ModTarget::Game ? "ScrapMechanic.exe" : "ModTool.exe"); if (std::wstring(entry.szExeFile) == std::wstring(target.begin(), target.end())) { found = true; break; @@ -152,14 +152,14 @@ GameManager::GameManager() { this->moduleHandlerThread.detach(); } -GameManager::~GameManager() {} +ProcessManager::~ProcessManager() {} -bool GameManager::IsGameRunning() { +bool ProcessManager::IsGameRunning() { std::lock_guard lock(this->gameStatusMutex); return this->gameRunning; } -void GameManager::InjectModule(const std::string& modulePath) { +void ProcessManager::InjectModule(const std::string& modulePath) { if (!this->IsGameRunning() || this->pid == 0) { spdlog::warn("Game manager was requested to inject `{}`, but the game is not running", modulePath); return; @@ -190,20 +190,23 @@ void GameManager::InjectModule(const std::string& modulePath) { spdlog::info("Injected module `{}`", modulePath); } -void GameManager::LaunchGame() { +void ProcessManager::LaunchProcess(const std::string& name) { this->gameStartedTime = std::nullopt; this->gameRunning = false; this->pid = 0; this->modules.clear(); std::thread([&]() { - if (C.processTarget == "ScrapMechanic.exe") { + if (name == "ScrapMechanic.exe") { ShellExecute(NULL, L"open", L"steam://rungameid/387990", NULL, NULL, SW_SHOWNORMAL); spdlog::info("Launching Scrap Mechanic via Steam"); } + else if (name == "ModTool.exe") { + ShellExecute(NULL, L"open", L"steam://rungameid/588870", NULL, NULL, SW_SHOWNORMAL); + spdlog::info("Launching Scrap Mechanic Mod Tool via Steam"); + } else { - std::string exePath = Utils::GetDataDir() + C.processTarget; - ShellExecute(NULL, L"open", std::wstring(exePath.begin(), exePath.end()).c_str(), NULL, NULL, SW_SHOWNORMAL); + ShellExecute(NULL, L"open", std::wstring(name.begin(), name.end()).c_str(), NULL, NULL, SW_SHOWNORMAL); spdlog::info("Launching game via ShellExecute"); } @@ -213,13 +216,24 @@ void GameManager::LaunchGame() { this->gameStartedTime = std::chrono::system_clock::now(); std::this_thread::sleep_for(std::chrono::seconds(1)); - this->InjectModule(Utils::GetCurrentModuleDir() + "CarbonSupervisor.dll"); + + if (C.guiManager.target == ModTarget::Game) { + this->InjectModule(Utils::GetCurrentModuleDir() + "CarbonSupervisor.dll"); + } + else { + // Inject every module in the mods directory + for (auto& module : std::filesystem::recursive_directory_iterator(Utils::GetDataDir() + "mods")) { + if (!module.is_regular_file() || module.path().extension() != ".dll") + continue; // Skip directories and non-DLL files + this->InjectModule(module.path().string()); + } + } }).detach(); spdlog::info("Started game in detached thread"); } -void GameManager::KillGame() { +void ProcessManager::KillGame() { auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snapshot == INVALID_HANDLE_VALUE) { return; @@ -231,7 +245,7 @@ void GameManager::KillGame() { return; } do { - std::string target(C.processTarget); + std::string target(C.guiManager.target == ModTarget::Game ? "ScrapMechanic.exe" : "ModTool.exe"); if (std::wstring(entry.szExeFile) == std::wstring(target.begin(), target.end())) { HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, entry.th32ProcessID); if (process) { @@ -247,7 +261,7 @@ void GameManager::KillGame() { } } -bool GameManager::IsModuleLoaded(const std::string& moduleName) const { +bool ProcessManager::IsModuleLoaded(const std::string& moduleName) const { std::vector modules; auto hProcesses = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, this->pid); if (hProcesses == INVALID_HANDLE_VALUE) { @@ -281,7 +295,7 @@ bool GameManager::IsModuleLoaded(const std::string& moduleName) const { return false; } -int GameManager::GetLoadedCustomModules() const { +int ProcessManager::GetLoadedCustomModules() const { while (!this->loadedCustomModules.has_value()) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); }