From fe73bb9827eed78fda496f0eb23e5e879f7ece5e Mon Sep 17 00:00:00 2001 From: Diavolo Date: Tue, 2 Aug 2022 13:24:22 +0200 Subject: [PATCH] [QuickPatch] Make startsingleplayer command work with iw4x-sp --- src/Components/Modules/FileSystem.cpp | 16 +++++++ src/Components/Modules/FileSystem.hpp | 1 + src/Components/Modules/QuickPatch.cpp | 55 +++++++++++++++--------- src/Components/Modules/QuickPatch.hpp | 2 + src/Game/Functions.cpp | 2 + src/Game/Functions.hpp | 2 + src/STDInclude.hpp | 1 + src/Utils/Library.cpp | 60 ++++++++++++++++++++++++--- src/Utils/Library.hpp | 13 ++++-- src/Utils/String.cpp | 10 ++--- src/Utils/String.hpp | 2 +- 11 files changed, 130 insertions(+), 34 deletions(-) diff --git a/src/Components/Modules/FileSystem.cpp b/src/Components/Modules/FileSystem.cpp index 39816e09..d8b61308 100644 --- a/src/Components/Modules/FileSystem.cpp +++ b/src/Components/Modules/FileSystem.cpp @@ -138,6 +138,22 @@ namespace Components } } + std::filesystem::path FileSystem::GetAppdataPath() + { + PWSTR path; + if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &path))) + { + throw std::runtime_error("Failed to read APPDATA path!"); + } + + auto _0 = gsl::finally([&path] + { + CoTaskMemFree(path); + }); + + return std::filesystem::path(path) / "xlabs"; + } + std::vector FileSystem::GetFileList(const std::string& path, const std::string& extension) { std::vector fileList; diff --git a/src/Components/Modules/FileSystem.hpp b/src/Components/Modules/FileSystem.hpp index e6c17e44..aca27f7a 100644 --- a/src/Components/Modules/FileSystem.hpp +++ b/src/Components/Modules/FileSystem.hpp @@ -89,6 +89,7 @@ namespace Components FileSystem(); ~FileSystem(); + static std::filesystem::path GetAppdataPath(); static std::vector GetFileList(const std::string& path, const std::string& extension); static std::vector GetSysFileList(const std::string& path, const std::string& extension, bool folders = false); static bool DeleteFile(const std::string& folder, const std::string& file); diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index f9b5762c..4672fc79 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -78,14 +78,14 @@ namespace Components mov ecx, [eax] fireWeapon: - push edx - push ecx - push edi - mov eax, 0x4A4D50 // FireWeapon - call eax - add esp, 0Ch - pop edi - pop ecx + push edx + push ecx + push edi + mov eax, 0x4A4D50 // FireWeapon + call eax + add esp, 0Ch + pop edi + pop ecx retn } } @@ -106,13 +106,13 @@ namespace Components mov edx, [eax] fireWeaponMelee: - push edx - push edi - mov eax, 0x4F2470 // FireWeaponMelee - call eax - add esp, 8 - pop edi - pop ecx + push edx + push edi + mov eax, 0x4F2470 // FireWeaponMelee + call eax + add esp, 8 + pop edi + pop ecx retn } } @@ -153,11 +153,11 @@ namespace Components je useCustomRatio; // execute switch statement code - push 0x005063FC; + push 0x5063FC; retn; goToDefaultCase: - push 0x005064FC; + push 0x5064FC; retn; useCustomRatio: @@ -170,7 +170,7 @@ namespace Components mov eax, 1; // continue execution - push 0x00506495; + push 0x506495; retn; } } @@ -240,6 +240,20 @@ namespace Components } } + void QuickPatch::Sys_SpawnQuitProcess_Hk() + { + if (*Game::sys_exitCmdLine[0] == '\0') + { + return; + } + + auto workingDir = std::filesystem::current_path().string(); + auto dir = FileSystem::GetAppdataPath() / "data" / "iw4x" / *Game::sys_exitCmdLine; + + SetEnvironmentVariableA("XLABS_MW2_INSTALL", workingDir.data()); + Utils::Library::LaunchProcess(dir.string(), "-singleplayer", workingDir); + } + Game::dvar_t* QuickPatch::Dvar_RegisterConMinicon(const char* dvarName, [[maybe_unused]] bool value, unsigned __int16 flags, const char* description) { #ifdef _DEBUG @@ -274,7 +288,10 @@ namespace Components Utils::Hook(0x4FA448, QuickPatch::Dvar_RegisterConMinicon, HOOK_CALL).install()->quick(); - Utils::Hook::Set(0x51FCDD, R_AddImageToList_Hk); + Utils::Hook::Set(0x51FCDD, QuickPatch::R_AddImageToList_Hk); + + Utils::Hook::Set(0x41DB8C, "iw4x-sp.exe"); + Utils::Hook(0x4D6989, QuickPatch::Sys_SpawnQuitProcess_Hk, HOOK_CALL).install()->quick(); // protocol version (workaround for hacks) Utils::Hook::Set(0x4FB501, PROTOCOL); diff --git a/src/Components/Modules/QuickPatch.hpp b/src/Components/Modules/QuickPatch.hpp index 210c182e..18de2fa4 100644 --- a/src/Components/Modules/QuickPatch.hpp +++ b/src/Components/Modules/QuickPatch.hpp @@ -30,6 +30,8 @@ namespace Components static void R_AddImageToList_Hk(Game::XAssetHeader header, void* data); + static void Sys_SpawnQuitProcess_Hk(); + static Game::dvar_t* Dvar_RegisterConMinicon(const char* dvarName, bool value, unsigned __int16 flags, const char* description); }; } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index f2e71858..7f3d08c5 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -631,6 +631,8 @@ namespace Game unsigned int* playerCardUIStringIndex = reinterpret_cast(0x62CD7A8); char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38] = reinterpret_cast(0x62CB4F8); + char (*sys_exitCmdLine)[1024] = reinterpret_cast(0x649FB68); + GamerSettingState* gamerSettings = reinterpret_cast(0x107D3E8); void Sys_LockRead(FastCriticalSection* critSect) diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 35986f50..55c839d8 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -1303,6 +1303,8 @@ namespace Game extern unsigned int* playerCardUIStringIndex; extern char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38]; + extern char (*sys_exitCmdLine)[1024]; + extern GamerSettingState* gamerSettings; void Sys_LockRead(FastCriticalSection* critSect); diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index ae15d45c..becd7189 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include diff --git a/src/Utils/Library.cpp b/src/Utils/Library.cpp index 2ff31f9a..178465dc 100644 --- a/src/Utils/Library.cpp +++ b/src/Utils/Library.cpp @@ -19,20 +19,18 @@ namespace Utils return Library(handle); } - Library::Library(const std::string& name, bool _freeOnDestroy) : module_(nullptr), freeOnDestroy(_freeOnDestroy) + Library::Library(const std::string& name, bool freeOnDestroy) : module_(nullptr), freeOnDestroy_(freeOnDestroy) { this->module_ = LoadLibraryExA(name.data(), nullptr, 0); } - Library::Library(const HMODULE handle) + Library::Library(const HMODULE handle) : module_(handle), freeOnDestroy_(true) { - this->module_ = handle; - this->freeOnDestroy = true; } Library::~Library() { - if (this->freeOnDestroy) + if (this->freeOnDestroy_) { this->free(); } @@ -63,6 +61,39 @@ namespace Utils return this->module_; } + std::string Library::getName() const + { + if (!this->isValid()) + return {}; + + auto path = this->getPath(); + const auto pos = path.find_last_of("/\\"); + if (pos == std::string::npos) + return path; + + return path.substr(pos + 1); + } + + std::string Library::getPath() const + { + if (!this->isValid()) + return {}; + + char name[MAX_PATH] = {0}; + GetModuleFileNameA(this->module_, name, sizeof(name)); + + return name; + } + + std::string Library::getFolder() const + { + if (!this->isValid()) + return {}; + + const auto path = std::filesystem::path(this->getPath()); + return path.parent_path().generic_string(); + } + void Library::free() { if (this->isValid()) @@ -72,4 +103,23 @@ namespace Utils this->module_ = nullptr; } + + void Library::LaunchProcess(const std::string& process, const std::string& commandLine, const std::string& currentDir) + { + STARTUPINFOA startup_info; + PROCESS_INFORMATION process_info; + + ZeroMemory(&startup_info, sizeof(startup_info)); + ZeroMemory(&process_info, sizeof(process_info)); + startup_info.cb = sizeof(startup_info); + + CreateProcessA(process.data(), const_cast(commandLine.data()), nullptr, + nullptr, false, NULL, nullptr, currentDir.data(), + &startup_info, &process_info); + + if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) + CloseHandle(process_info.hThread); + if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) + CloseHandle(process_info.hProcess); + } } diff --git a/src/Utils/Library.hpp b/src/Utils/Library.hpp index 8c999f67..bd5eddf3 100644 --- a/src/Utils/Library.hpp +++ b/src/Utils/Library.hpp @@ -9,9 +9,9 @@ namespace Utils static Library Load(const std::filesystem::path& path); static Library GetByAddress(void* address); - Library() : module_(nullptr), freeOnDestroy(false) {}; + Library() : module_(nullptr), freeOnDestroy_(false) {} Library(const std::string& name, bool freeOnDestroy); - explicit Library(const std::string& name) : module_(GetModuleHandleA(name.data())), freeOnDestroy(true) {}; + explicit Library(const std::string& name) : module_(GetModuleHandleA(name.data())), freeOnDestroy_(true) {} explicit Library(HMODULE handle); ~Library(); @@ -23,6 +23,11 @@ namespace Utils bool isValid() const; HMODULE getModule() const; + std::string getName() const; + std::string getPath() const; + std::string getFolder() const; + std::uint8_t* getPtr() const; + void free(); template T getProc(const std::string& process) const @@ -62,10 +67,10 @@ namespace Utils return T(); } - void free(); + static void LaunchProcess(const std::string& process, const std::string& commandLine, const std::string& currentDir); private: HMODULE module_; - bool freeOnDestroy; + bool freeOnDestroy_; }; } diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 55cd12a0..360c5032 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -92,14 +92,14 @@ namespace Utils return elems; } - void Replace(std::string &string, const std::string& find, const std::string& replace) + void Replace(std::string& str, const std::string& from, const std::string& to) { - size_t nPos = 0; + std::size_t nPos = 0; - while ((nPos = string.find(find, nPos)) != std::string::npos) + while ((nPos = str.find(from, nPos)) != std::string::npos) { - string = string.replace(nPos, find.length(), replace); - nPos += replace.length(); + str = str.replace(nPos, from.length(), to); + nPos += to.length(); } } diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index b6b376ba..1f1edd2f 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -78,7 +78,7 @@ namespace Utils std::string ToUpper(std::string text); bool Compare(const std::string& lhs, const std::string& rhs); std::vector Split(const std::string& str, char delim); - void Replace(std::string& string, const std::string& find, const std::string& replace); + void Replace(std::string& str, const std::string& from, const std::string& to); bool StartsWith(const std::string& haystack, const std::string& needle); bool EndsWith(const std::string& haystack, const std::string& needle); bool IsNumber(const std::string& str);