[QuickPatch] Make startsingleplayer command work with iw4x-sp

This commit is contained in:
Diavolo 2022-08-02 13:24:22 +02:00
parent 0fde17bbb2
commit fe73bb9827
No known key found for this signature in database
GPG Key ID: FA77F074E98D98A5
11 changed files with 130 additions and 34 deletions

View File

@ -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<std::string> FileSystem::GetFileList(const std::string& path, const std::string& extension) std::vector<std::string> FileSystem::GetFileList(const std::string& path, const std::string& extension)
{ {
std::vector<std::string> fileList; std::vector<std::string> fileList;

View File

@ -89,6 +89,7 @@ namespace Components
FileSystem(); FileSystem();
~FileSystem(); ~FileSystem();
static std::filesystem::path GetAppdataPath();
static std::vector<std::string> GetFileList(const std::string& path, const std::string& extension); static std::vector<std::string> GetFileList(const std::string& path, const std::string& extension);
static std::vector<std::string> GetSysFileList(const std::string& path, const std::string& extension, bool folders = false); static std::vector<std::string> GetSysFileList(const std::string& path, const std::string& extension, bool folders = false);
static bool DeleteFile(const std::string& folder, const std::string& file); static bool DeleteFile(const std::string& folder, const std::string& file);

View File

@ -153,11 +153,11 @@ namespace Components
je useCustomRatio; je useCustomRatio;
// execute switch statement code // execute switch statement code
push 0x005063FC; push 0x5063FC;
retn; retn;
goToDefaultCase: goToDefaultCase:
push 0x005064FC; push 0x5064FC;
retn; retn;
useCustomRatio: useCustomRatio:
@ -170,7 +170,7 @@ namespace Components
mov eax, 1; mov eax, 1;
// continue execution // continue execution
push 0x00506495; push 0x506495;
retn; 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) Game::dvar_t* QuickPatch::Dvar_RegisterConMinicon(const char* dvarName, [[maybe_unused]] bool value, unsigned __int16 flags, const char* description)
{ {
#ifdef _DEBUG #ifdef _DEBUG
@ -274,7 +288,10 @@ namespace Components
Utils::Hook(0x4FA448, QuickPatch::Dvar_RegisterConMinicon, HOOK_CALL).install()->quick(); Utils::Hook(0x4FA448, QuickPatch::Dvar_RegisterConMinicon, HOOK_CALL).install()->quick();
Utils::Hook::Set<void(*)(Game::XAssetHeader, void*)>(0x51FCDD, R_AddImageToList_Hk); Utils::Hook::Set<void(*)(Game::XAssetHeader, void*)>(0x51FCDD, QuickPatch::R_AddImageToList_Hk);
Utils::Hook::Set<const char*>(0x41DB8C, "iw4x-sp.exe");
Utils::Hook(0x4D6989, QuickPatch::Sys_SpawnQuitProcess_Hk, HOOK_CALL).install()->quick();
// protocol version (workaround for hacks) // protocol version (workaround for hacks)
Utils::Hook::Set<int>(0x4FB501, PROTOCOL); Utils::Hook::Set<int>(0x4FB501, PROTOCOL);

View File

@ -30,6 +30,8 @@ namespace Components
static void R_AddImageToList_Hk(Game::XAssetHeader header, void* data); 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); static Game::dvar_t* Dvar_RegisterConMinicon(const char* dvarName, bool value, unsigned __int16 flags, const char* description);
}; };
} }

View File

@ -631,6 +631,8 @@ namespace Game
unsigned int* playerCardUIStringIndex = reinterpret_cast<unsigned int*>(0x62CD7A8); unsigned int* playerCardUIStringIndex = reinterpret_cast<unsigned int*>(0x62CD7A8);
char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38] = reinterpret_cast<char(*)[PLAYER_CARD_UI_STRING_COUNT][38]>(0x62CB4F8); char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38] = reinterpret_cast<char(*)[PLAYER_CARD_UI_STRING_COUNT][38]>(0x62CB4F8);
char (*sys_exitCmdLine)[1024] = reinterpret_cast<char(*)[1024]>(0x649FB68);
GamerSettingState* gamerSettings = reinterpret_cast<GamerSettingState*>(0x107D3E8); GamerSettingState* gamerSettings = reinterpret_cast<GamerSettingState*>(0x107D3E8);
void Sys_LockRead(FastCriticalSection* critSect) void Sys_LockRead(FastCriticalSection* critSect)

View File

@ -1303,6 +1303,8 @@ namespace Game
extern unsigned int* playerCardUIStringIndex; extern unsigned int* playerCardUIStringIndex;
extern char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38]; extern char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38];
extern char (*sys_exitCmdLine)[1024];
extern GamerSettingState* gamerSettings; extern GamerSettingState* gamerSettings;
void Sys_LockRead(FastCriticalSection* critSect); void Sys_LockRead(FastCriticalSection* critSect);

View File

@ -16,6 +16,7 @@
#include <Windows.h> #include <Windows.h>
#include <WinSock2.h> #include <WinSock2.h>
#include <ShlObj.h>
#include <timeapi.h> #include <timeapi.h>
#include <shellapi.h> #include <shellapi.h>
#include <WinInet.h> #include <WinInet.h>

View File

@ -19,20 +19,18 @@ namespace Utils
return Library(handle); 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); 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() Library::~Library()
{ {
if (this->freeOnDestroy) if (this->freeOnDestroy_)
{ {
this->free(); this->free();
} }
@ -63,6 +61,39 @@ namespace Utils
return this->module_; 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() void Library::free()
{ {
if (this->isValid()) if (this->isValid())
@ -72,4 +103,23 @@ namespace Utils
this->module_ = nullptr; 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<char*>(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);
}
} }

View File

@ -9,9 +9,9 @@ namespace Utils
static Library Load(const std::filesystem::path& path); static Library Load(const std::filesystem::path& path);
static Library GetByAddress(void* address); static Library GetByAddress(void* address);
Library() : module_(nullptr), freeOnDestroy(false) {}; Library() : module_(nullptr), freeOnDestroy_(false) {}
Library(const std::string& name, bool freeOnDestroy); 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); explicit Library(HMODULE handle);
~Library(); ~Library();
@ -23,6 +23,11 @@ namespace Utils
bool isValid() const; bool isValid() const;
HMODULE getModule() const; HMODULE getModule() const;
std::string getName() const;
std::string getPath() const;
std::string getFolder() const;
std::uint8_t* getPtr() const;
void free();
template <typename T> template <typename T>
T getProc(const std::string& process) const T getProc(const std::string& process) const
@ -62,10 +67,10 @@ namespace Utils
return T(); return T();
} }
void free(); static void LaunchProcess(const std::string& process, const std::string& commandLine, const std::string& currentDir);
private: private:
HMODULE module_; HMODULE module_;
bool freeOnDestroy; bool freeOnDestroy_;
}; };
} }

View File

@ -92,14 +92,14 @@ namespace Utils
return elems; 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); str = str.replace(nPos, from.length(), to);
nPos += replace.length(); nPos += to.length();
} }
} }

View File

@ -78,7 +78,7 @@ namespace Utils
std::string ToUpper(std::string text); std::string ToUpper(std::string text);
bool Compare(const std::string& lhs, const std::string& rhs); bool Compare(const std::string& lhs, const std::string& rhs);
std::vector<std::string> Split(const std::string& str, char delim); std::vector<std::string> 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 StartsWith(const std::string& haystack, const std::string& needle);
bool EndsWith(const std::string& haystack, const std::string& needle); bool EndsWith(const std::string& haystack, const std::string& needle);
bool IsNumber(const std::string& str); bool IsNumber(const std::string& str);