A few RTech changes.

* Renamed pak_asyncload to pak_requestload
* Added new ConCommand to unload rpaks. It's called pak_requestunload.
* When CHostState requests an rpak unload, it will now print the name of it.
* Turned a few static addresses onto patternscans.
This commit is contained in:
PixieCore 2022-03-28 18:47:11 +02:00
parent 433a3b27a2
commit 56a71aba56
10 changed files with 130 additions and 84 deletions

View File

@ -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);
}
}

View File

@ -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())

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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<RPakLoadedInfo_t*>();
std::int16_t* s_pLoadedPakCount = UnloadRoutine.FindPatternSelf("66 89", ADDRESS::Direction::DOWN, 450).ResolveRelativeAddressSelf(0x3, 0x7).RCast<std::int16_t*>();
#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;

View File

@ -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);

View File

@ -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;

View File

@ -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<std::int16_t*>();
static RPakLoadedInfo_t* g_pLoadedPakInfo = ADDRESS(0x167D40B70).RCast<RPakLoadedInfo_t*>();
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);

View File

@ -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);