diff --git a/r5dev/engine/host_state.cpp b/r5dev/engine/host_state.cpp index c251c1ea..77c1117b 100644 --- a/r5dev/engine/host_state.cpp +++ b/r5dev/engine/host_state.cpp @@ -27,6 +27,7 @@ #include "engine/baseserver.h" #endif // !CLIENT_DLL #include "rtech/rtech_game.h" +#include "rtech/rtech_utils.h" #ifndef DEDICATED #include "vgui/vgui_baseui_interface.h" #endif // DEDICATED @@ -284,8 +285,15 @@ FORCEINLINE void CHostState::UnloadPakFile(void) { for (auto& it : g_nLoadedPakFileId) { - if (it >= 0) // [ PIXIE ] TODO: Create RTech function to get RPakLoadedInfo by ID and print which rpak is getting unloaded. + if (it >= 0) { +#ifdef GAMEDLL_S3 + RPakLoadedInfo_t pakInfo = g_pRTech->GetPakLoadedInfo(it); + if (pakInfo.m_pszFileName) + { + DevMsg(eDLL_T::RTECH, "Unloading PakFile '%s' now.", pakInfo.m_pszFileName); + } +#endif // GAMEDLL_S3 RTech_UnloadPak(it); } } diff --git a/r5dev/public/include/memaddr.h b/r5dev/public/include/memaddr.h index 74dcd386..87d9f182 100644 --- a/r5dev/public/include/memaddr.h +++ b/r5dev/public/include/memaddr.h @@ -458,7 +458,7 @@ public: return ADDRESS(latestOccurence); } - ADDRESS FindPatternSIMD(uint8_t* szPattern, const char* szMask) + ADDRESS FindPatternSIMD(std::uint8_t* szPattern, const char* szMask) { ModuleSections mInfo = GetSectionByName(".text"); // Get the .text section. if (!mInfo.IsSectionValid()) diff --git a/r5dev/rtech/rtech_game.cpp b/r5dev/rtech/rtech_game.cpp index 346f577c..c580aba0 100644 --- a/r5dev/rtech/rtech_game.cpp +++ b/r5dev/rtech/rtech_game.cpp @@ -35,7 +35,7 @@ void HRTech_UnloadAsset(std::int64_t a1, std::int64_t a2) // This ain't related //----------------------------------------------------------------------------- // Purpose: load user-requested pak files on-demand //----------------------------------------------------------------------------- -void HRtech_AsyncLoad(std::string svPakFileName) +void HRTech_AsyncLoad(std::string svPakFileName) { std::string svPakFilePathMod = "paks\\Win32\\" + svPakFileName; std::string svPakFilePathBase = "paks\\Win64\\" + svPakFileName; diff --git a/r5dev/rtech/rtech_game.h b/r5dev/rtech/rtech_game.h index 6fd2d87e..2422d706 100644 --- a/r5dev/rtech/rtech_game.h +++ b/r5dev/rtech/rtech_game.h @@ -33,7 +33,7 @@ namespace ADDRESS p_RTech_UnloadAsset = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x83\xEC\x28\x48\x85\xD2\x74\x40\x48\x8B\x05\x00\x00\x00\x00", "xxxxxxxxxxxx????"); void (*RTech_UnloadAsset)(std::int64_t a1, std::int64_t a2) = (void (*)(std::int64_t, std::int64_t))p_RTech_UnloadAsset.GetPtr(); /*48 83 EC 28 48 85 D2 74 40 48 8B 05 ? ? ? ?*/ - ADDRESS p_RTech_LoadPak = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x4C\x24\x00\x56\x41\x55", "xxxx?xxx"); /*48 89 4C 24 ? 56 41 55*/ + ADDRESS p_RTech_LoadPak = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x4C\x24\x00\x56\x41\x55", "xxxx?xxx"); /*48 89 4C 24 ? 56 41 55*/ unsigned int (*RTech_LoadPak)(void* thisptr, void* a2, std::uint64_t a3) = (unsigned int (*)(void*, void*, std::uint64_t))p_RTech_LoadPak.GetPtr(); ADDRESS p_RTech_LoadMapPak = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x81\xEC\x00\x00\x00\x00\x0F\xB6\x05\x00\x00\x00\x00\x4C\x8D\x05\x00\x00\x00\x00\x84\xC0", "xxx????xxx????xxx????xx"); @@ -53,7 +53,7 @@ namespace void* (*RTech_UnloadPak)(int nPakId) = (void* (*)(int nPakId))p_RTech_UnloadPak.GetPtr();/*48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 30 8B C1*/ } void HRTech_UnloadAsset(std::int64_t a1, std::int64_t a2); -void HRtech_AsyncLoad(std::string svPakFileName); +void HRTech_AsyncLoad(std::string svPakFileName); void RTech_Game_Attach(); void RTech_Game_Detach(); diff --git a/r5dev/rtech/rtech_utils.cpp b/r5dev/rtech/rtech_utils.cpp index d56b3ffd..fcc0c675 100644 --- a/r5dev/rtech/rtech_utils.cpp +++ b/r5dev/rtech/rtech_utils.cpp @@ -14,6 +14,7 @@ History: - 10:09:2021 | 18:22 : Implement 'StringToGuid' method - 12:11:2021 | 14:41 : Add decompression method to ConCommand callback - 25:12:2021 | 23:20 : Made everything more readable thanks to bezdna5-rs +- 28:03:2021 | 18:00 : Added getting pak info by PakID. ******************************************************************************/ @@ -495,5 +496,24 @@ std::uint8_t __fastcall RTech::DecompressPakFile(RPakDecompState_t* state, std:: return result; } + +RPakLoadedInfo_t RTech::GetPakLoadedInfo(int nPakId) +{ +#ifdef GAMEDLL_S3 + for (int i = 0; i < *s_pLoadedPakCount; ++i) + { + RPakLoadedInfo_t info = g_pLoadedPakInfo[i]; + + if (info.m_nPakId != nPakId) + continue; + + return info; + } + + Warning(eDLL_T::RTECH, "Failed getting RPakLoadInfo_t for PakId '%d'", nPakId); +#endif // GAMEDLL_S3 + + return RPakLoadedInfo_t(); +} /////////////////////////////////////////////////////////////////////////////// -RTech* g_pRtech = new RTech(); +RTech* g_pRTech = new RTech(); diff --git a/r5dev/rtech/rtech_utils.h b/r5dev/rtech/rtech_utils.h index 9bf1b083..4ab8c297 100644 --- a/r5dev/rtech/rtech_utils.h +++ b/r5dev/rtech/rtech_utils.h @@ -165,11 +165,12 @@ public: namespace { /* ==== RTECH =========================================================================================================================================================== */ - //DWORD64 p_RTech_Decompress = FindPatternV2("r5apex.exe", (const unsigned char*)"\x4C\x89\x44\x24\x18\x48\x89\x54\x24\x10\x53\x48\x83\xEC\x50\x48", "xxxxxxxxxxxxxxxx"); - //char (*RTech_Decompress)(int64_t* parameter, std::uint64_t input, std::uint64_t output) = (char (*)(std::int64_t*, std::uint64_t, std::uint64_t))p_RTech_Decompress; /*4C 89 44 24 18 48 89 54 24 10 53 48 83 EC 50 48*/ +#ifdef GAMEDLL_S3 + ADDRESS UnloadRoutine = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x30\x8B\xC1", "xxxx?xxxx?xxxxxxx"); /*48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 30 8B C1*/ - //DWORD64 p_RTech_DecompressedSize = FindPatternV2("r5apex.exe", (const unsigned char*)"\x48\x89\x5C\x24\x08\x48\x89\x6C\x24\x18\x48\x89\x74\x24\x20\x48\x89\x54\x24\x10\x57\x41\x54\x41\x55\x41\x56\x41\x57\x4C\x8B\x74", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - //std::int64_t (*RTech_DecompressedSize)(std::int64_t parameter, std::uint8_t* input, std::int64_t magic, std::int64_t a4, std::int64_t a5) = (std::int64_t (*)(std::int64_t, std::uint8_t*, std::int64_t, std::int64_t, std::int64_t))p_RTech_DecompressedSize; /*48 89 5C 24 08 48 89 6C 24 18 48 89 74 24 20 48 89 54 24 10 57 41 54 41 55 41 56 41 57 4C 8B 74*/ + RPakLoadedInfo_t* g_pLoadedPakInfo = UnloadRoutine.FindPatternSelf("48 8D 05", ADDRESS::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); + std::int16_t* s_pLoadedPakCount = UnloadRoutine.FindPatternSelf("66 89", ADDRESS::Direction::DOWN, 450).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); +#endif // GAMEDLL_S3 } class RTech @@ -178,7 +179,8 @@ public: std::uint64_t __fastcall StringToGuid(const char* pData); std::uint8_t __fastcall DecompressPakFile(RPakDecompState_t* state, std::uint64_t inLen, std::uint64_t outLen); std::uint32_t __fastcall DecompressPakFileInit(RPakDecompState_t* state, std::uint8_t* fileBuffer, std::int64_t fileSize, std::int64_t offNoHeader, std::int64_t headerSize); + RPakLoadedInfo_t GetPakLoadedInfo(int nPakId); }; /////////////////////////////////////////////////////////////////////////////// -extern RTech* g_pRtech; +extern RTech* g_pRTech; diff --git a/r5dev/tier0/cmd.cpp b/r5dev/tier0/cmd.cpp index 66503408..1355e2bf 100644 --- a/r5dev/tier0/cmd.cpp +++ b/r5dev/tier0/cmd.cpp @@ -69,6 +69,23 @@ const char* CCommand::operator[](int nIndex) const return Arg(nIndex); } +//----------------------------------------------------------------------------- +// Purpose: return boolean depending on if the string only has digits in it +// Input : svString - +//----------------------------------------------------------------------------- +bool CCommand::HasOnlyDigits(int nIndex) const +{ + std::string svString = Arg(nIndex); + for (const char& character : svString) + { + if (std::isdigit(character) == 0) + { + return false; + } + } + return true; +} + //----------------------------------------------------------------------------- // Purpose: construct/allocate //----------------------------------------------------------------------------- @@ -122,10 +139,11 @@ void ConCommand::Init(void) ConCommand* fs_decompress_pak = new ConCommand("fs_decompress_pak", "Decompresses user specified 'vpk_dir' file.", FCVAR_DEVELOPMENTONLY, _VPK_Decompress_f_CompletionFunc, nullptr); //------------------------------------------------------------------------- // RTECH API | - ConCommand* rtech_strtoguid = new ConCommand("rtech_strtoguid", "Calculates the GUID from input data.", FCVAR_DEVELOPMENTONLY, _RTech_StringToGUID_f_CompletionFunc, nullptr); - ConCommand* pak_asyncload = new ConCommand("pak_asyncload", "Loads the specified RPAK file asynchronously.", FCVAR_DEVELOPMENTONLY, _RTech_AsyncLoad_f_CompletionFunc, nullptr); - ConCommand* pak_decompress = new ConCommand("pak_decompress", "Decompresses the specified RPAK file.", FCVAR_DEVELOPMENTONLY, _RTech_Decompress_f_CompletionFunc, nullptr); - ConCommand* pak_listpaks = new ConCommand("pak_listpaks", "Display a list of the loaded Pak files.", FCVAR_DEVELOPMENTONLY, _Pak_ListPaks_f_CompletionFunc, nullptr); + ConCommand* rtech_strtoguid = new ConCommand("rtech_strtoguid", "Calculates the GUID from input data.", FCVAR_DEVELOPMENTONLY, _RTech_StringToGUID_f_CompletionFunc, nullptr); + ConCommand* pak_requestload = new ConCommand("pak_requestload", "Requests asynchronous load for specified RPAK FILE.", FCVAR_DEVELOPMENTONLY, _Pak_RequestLoad_f_CompletionFunc, nullptr); + ConCommand* pak_requestunload = new ConCommand("pak_requestunload", "Requests unload for specified RPAK ID.", FCVAR_DEVELOPMENTONLY, _Pak_RequestUnload_f_CompletionFunc, nullptr); + ConCommand* pak_decompress = new ConCommand("pak_decompress", "Decompresses the specified RPAK file.", FCVAR_DEVELOPMENTONLY, _RTech_Decompress_f_CompletionFunc, nullptr); + ConCommand* pak_listpaks = new ConCommand("pak_listpaks", "Display a list of the loaded Pak files.", FCVAR_DEVELOPMENTONLY, _Pak_ListPaks_f_CompletionFunc, nullptr); //------------------------------------------------------------------------- // NETCHANNEL | ConCommand* net_toggletrace = new ConCommand("net_toggletrace", "Logs the sending and receiving datagram to a file on the disk.", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, _NET_TraceNetChan_f_CompletionFunc, nullptr); diff --git a/r5dev/tier0/cmd.h b/r5dev/tier0/cmd.h index 6cbaa441..c00fb4eb 100644 --- a/r5dev/tier0/cmd.h +++ b/r5dev/tier0/cmd.h @@ -66,6 +66,8 @@ public: const char* Arg(int nIndex) const; const char* operator[](int nIndex) const; + bool HasOnlyDigits(int nIndex) const; + private: int m_nQueuedVal; int m_nArgc; diff --git a/r5dev/tier0/completion.cpp b/r5dev/tier0/completion.cpp index 7c70998d..cc77b537 100644 --- a/r5dev/tier0/completion.cpp +++ b/r5dev/tier0/completion.cpp @@ -45,7 +45,7 @@ void _CGameConsole_f_CompletionFunc(const CCommand& args) _CCompanion_f_CompletionFunc ===================== */ -void _CCompanion_f_CompletionFunc(const CCommand& cmd) +void _CCompanion_f_CompletionFunc(const CCommand& args) { g_pIBrowser->m_bActivate = !g_pIBrowser->m_bActivate; } @@ -100,18 +100,6 @@ _KickID_f_CompletionFunc */ void _KickID_f_CompletionFunc(const CCommand& args) { - static auto HasOnlyDigits = [](const std::string& string) - { - for (const char& character : string) - { - if (std::isdigit(character) == 0) - { - return false; - } - } - return true; - }; - if (args.ArgC() < 2) // Do we atleast have 2 arguments? { return; @@ -119,7 +107,7 @@ void _KickID_f_CompletionFunc(const CCommand& args) try { - bool onlyDigits = HasOnlyDigits(args.Arg(1)); + bool onlyDigits = args.HasOnlyDigits(1); for (int i = 0; i < MAX_PLAYERS; i++) { CBaseClient* client = g_pClient->GetClient(i); @@ -250,18 +238,6 @@ _BanID_f_CompletionFunc */ void _BanID_f_CompletionFunc(const CCommand& args) { - static auto HasOnlyDigits = [](const std::string& string) - { - for (const char& character : string) - { - if (std::isdigit(character) == 0) - { - return false; - } - } - return true; - }; - if (args.ArgC() < 2) { return; @@ -269,7 +245,7 @@ void _BanID_f_CompletionFunc(const CCommand& args) try { - bool onlyDigits = HasOnlyDigits(args.Arg(1)); + bool onlyDigits = args.HasOnlyDigits(1); for (int i = 0; i < MAX_PLAYERS; i++) { CBaseClient* client = g_pClient->GetClient(i); @@ -347,18 +323,6 @@ _Unban_f_CompletionFunc */ void _Unban_f_CompletionFunc(const CCommand& args) { - static auto HasOnlyDigits = [](const std::string& string) - { - for (const char& character : string) - { - if (std::isdigit(character) == 0) - { - return false; - } - } - return true; - }; - if (args.ArgC() < 2) { return; @@ -366,7 +330,7 @@ void _Unban_f_CompletionFunc(const CCommand& args) try { - if (HasOnlyDigits(args.Arg(1))) // Check if we have an ip address or origin ID. + if (args.HasOnlyDigits(1)) // Check if we have an ip address or origin ID. { g_pBanSystem->DeleteEntry("noIP", std::stoll(args.Arg(1))); // Delete ban entry. g_pBanSystem->Save(); // Save modified vector to file. @@ -399,15 +363,11 @@ void _ReloadBanList_f_CompletionFunc(const CCommand& args) _Pak_ListPaks_f_CompletionFunc ===================== */ -void _Pak_ListPaks_f_CompletionFunc(const CCommand& cmd) +void _Pak_ListPaks_f_CompletionFunc(const CCommand& args) { #ifdef GAMEDLL_S3 - // [ PIXIE ]: TODO pattern scan these. - static std::int16_t* s_pLoadedPakCount = ADDRESS(0x167ED7C6C).RCast(); - static RPakLoadedInfo_t* g_pLoadedPakInfo = ADDRESS(0x167D40B70).RCast(); - - DevMsg(eDLL_T::RTECH, "| id | name | status | asset count |\n"); - DevMsg(eDLL_T::RTECH, "|----|----------------------------------|--------------------------------------|-------------|\n"); + DevMsg(eDLL_T::RTECH, "| id | name | status | asset count |\n"); + DevMsg(eDLL_T::RTECH, "|----|----------------------------------------------------|--------------------------------------|-------------|\n"); std::uint32_t nActuallyLoaded = 0; @@ -425,13 +385,58 @@ void _Pak_ListPaks_f_CompletionFunc(const CCommand& cmd) rpakStatus = it->second; // todo: make status into a string from an array/vector - DevMsg(eDLL_T::RTECH, "| %02i | %-32s | %-36s | %11i |\n", info.m_nPakId, info.m_pszFileName, rpakStatus.c_str(), info.m_nAssetCount); + DevMsg(eDLL_T::RTECH, "| %02i | %-50s | %-36s | %11i |\n", info.m_nPakId, info.m_pszFileName, rpakStatus.c_str(), info.m_nAssetCount); nActuallyLoaded++; } - DevMsg(eDLL_T::RTECH, "|----|----------------------------------|--------------------------------------|-------------|\n"); - DevMsg(eDLL_T::RTECH, "| %16i loaded paks. |\n", nActuallyLoaded); - DevMsg(eDLL_T::RTECH, "|----|----------------------------------|--------------------------------------|-------------|\n"); -#endif + DevMsg(eDLL_T::RTECH, "|----|----------------------------------------------------|--------------------------------------|-------------|\n"); + DevMsg(eDLL_T::RTECH, "| %16i loaded paks. |\n", nActuallyLoaded); + DevMsg(eDLL_T::RTECH, "|----|----------------------------------------------------|--------------------------------------|-------------|\n"); +#endif // GAMEDLL_S3 +} + +/* +===================== + _Pak_RequestUnload_f_CompletionFunc +===================== +*/ +void _Pak_RequestUnload_f_CompletionFunc(const CCommand& args) +{ +#ifdef GAMEDLL_S3 + if (args.ArgC() < 2) + { + return; + } + + try + { + if (args.HasOnlyDigits(1)) + { + int nPakId = std::stoi(args.Arg(1)); + RPakLoadedInfo_t pakInfo = g_pRTech->GetPakLoadedInfo(nPakId); + pakInfo.m_pszFileName ? DevMsg(eDLL_T::RTECH, "Requested Pak Unload for '%s'\n", pakInfo.m_pszFileName) : DevMsg(eDLL_T::RTECH, "Requested Pak Unload for '%d'\n", nPakId); + RTech_UnloadPak(nPakId); + } + else + { + throw std::exception("Please provide a number as an arg."); + } + } + catch (std::exception& e) + { + Error(eDLL_T::RTECH, "RequestUnload Error: %s", e.what()); + return; + } +#endif // GAMEDLL_S3 +} + +/* +===================== +_Pak_RequestLoad_f_CompletionFunc +===================== +*/ +void _Pak_RequestLoad_f_CompletionFunc(const CCommand& args) +{ + HRTech_AsyncLoad(args.Arg(1)); } /* @@ -446,23 +451,13 @@ void _RTech_StringToGUID_f_CompletionFunc(const CCommand& args) return; } - unsigned long long guid = g_pRtech->StringToGuid(args.Arg(1)); + unsigned long long guid = g_pRTech->StringToGuid(args.Arg(1)); DevMsg(eDLL_T::RTECH, "______________________________________________________________\n"); DevMsg(eDLL_T::RTECH, "] RTECH_HASH -------------------------------------------------\n"); DevMsg(eDLL_T::RTECH, "] GUID: '0x%llX'\n", guid); } -/* -===================== -_RTech_AsyncLoad_f_CompletionFunc -===================== -*/ -void _RTech_AsyncLoad_f_CompletionFunc(const CCommand& args) -{ - HRtech_AsyncLoad(args.Arg(1)); -} - /* ===================== _RTech_Decompress_f_CompletionFunc @@ -538,7 +533,7 @@ void _RTech_Decompress_f_CompletionFunc(const CCommand& args) } RPakDecompState_t state; - std::uint32_t decompSize = g_pRtech->DecompressPakFileInit(&state, upak.data(), upak.size(), 0, PAK_HEADER_SIZE); + std::uint32_t decompSize = g_pRTech->DecompressPakFileInit(&state, upak.data(), upak.size(), 0, PAK_HEADER_SIZE); if (decompSize == rheader->m_nSizeDisk) { @@ -555,7 +550,7 @@ void _RTech_Decompress_f_CompletionFunc(const CCommand& args) state.m_nOutMask = UINT64_MAX; state.m_nOut = uint64_t(pakBuf.data()); - std::uint8_t decompResult = g_pRtech->DecompressPakFile(&state, upak.size(), pakBuf.size()); + std::uint8_t decompResult = g_pRTech->DecompressPakFile(&state, upak.size(), pakBuf.size()); if (decompResult != 1) { Error(eDLL_T::RTECH, "Error: decompression failed for '%s' return value: '%u'!\n", pakNameIn.c_str(), +decompResult); diff --git a/r5dev/tier0/completion.h b/r5dev/tier0/completion.h index ddc494f6..9e004736 100644 --- a/r5dev/tier0/completion.h +++ b/r5dev/tier0/completion.h @@ -17,8 +17,8 @@ namespace /////////////////////////////////////////////////////////////////////////////// #ifndef DEDICATED -void _CGameConsole_f_CompletionFunc(const CCommand& cmd); -void _CCompanion_f_CompletionFunc(const CCommand& cmd); +void _CGameConsole_f_CompletionFunc(const CCommand& args); +void _CCompanion_f_CompletionFunc(const CCommand& args); #endif // !DEDICATED void _Kick_f_CompletionFunc(const CCommand& args); void _KickID_f_CompletionFunc(const CCommand& args); @@ -26,9 +26,10 @@ void _Ban_f_CompletionFunc(const CCommand& args); void _BanID_f_CompletionFunc(const CCommand& args); void _Unban_f_CompletionFunc(const CCommand& args); void _ReloadBanList_f_CompletionFunc(const CCommand& args); -void _Pak_ListPaks_f_CompletionFunc(const CCommand& cmd); +void _Pak_ListPaks_f_CompletionFunc(const CCommand& args); +void _Pak_RequestUnload_f_CompletionFunc(const CCommand& args); +void _Pak_RequestLoad_f_CompletionFunc(const CCommand& args); void _RTech_StringToGUID_f_CompletionFunc(const CCommand& args); -void _RTech_AsyncLoad_f_CompletionFunc(const CCommand& args); void _RTech_Decompress_f_CompletionFunc(const CCommand& args); void _VPK_Decompress_f_CompletionFunc(const CCommand& args); void _NET_TraceNetChan_f_CompletionFunc(const CCommand& args);