From 5655b8c7594298fb7e67bd416da3f75dc76e82f6 Mon Sep 17 00:00:00 2001 From: PixieCore <41352111+PixieCore@users.noreply.github.com> Date: Thu, 19 May 2022 00:47:16 +0200 Subject: [PATCH] Implementation for rpak swap. Read description. * RTech::GetPakLoadedInfo returns a reference now instead of a copy. Make sure to check the pointer is valid from now on if dealing with the returned pak entry. * RTech::GetPakLoadedInfo now has a overloaded function that takes string as argument for searching an pak entry. * new ConCommand pak_swap which has Pak_Swap_f as callback. * Pak_Swap_f performs pak unload and then load again. * pak_requestunload can now be used with pak name --- r5dev/rtech/rtech_game.cpp | 13 ++++--- r5dev/rtech/rtech_utils.cpp | 36 +++++++++++++++--- r5dev/rtech/rtech_utils.h | 3 +- r5dev/tier1/cmd.cpp | 3 +- r5dev/vstdlib/callback.cpp | 76 +++++++++++++++++++++++++++++++++++-- r5dev/vstdlib/callback.h | 1 + 6 files changed, 116 insertions(+), 16 deletions(-) diff --git a/r5dev/rtech/rtech_game.cpp b/r5dev/rtech/rtech_game.cpp index 623c80b1..a9d882ff 100644 --- a/r5dev/rtech/rtech_game.cpp +++ b/r5dev/rtech/rtech_game.cpp @@ -69,14 +69,17 @@ RPakHandle_t CPakFile::AsyncLoad(const char* szPakFileName, uintptr_t pMalloc, i //----------------------------------------------------------------------------- void CPakFile::Unload(RPakHandle_t handle) { - RPakLoadedInfo_t pakInfo = g_pRTech->GetPakLoadedInfo(handle); + RPakLoadedInfo_t* pakInfo = g_pRTech->GetPakLoadedInfo(handle); - if (pakInfo.m_pszFileName) + if (pakInfo) { - DevMsg(eDLL_T::RTECH, "Unloading pak file: '%s'\n", pakInfo.m_pszFileName); + if (pakInfo->m_pszFileName) + { + DevMsg(eDLL_T::RTECH, "Unloading pak file: '%s'\n", pakInfo->m_pszFileName); - if (strcmp(pakInfo.m_pszFileName, "mp_lobby.rpak") == 0) - s_bBasePaksInitialized = false; + if (strcmp(pakInfo->m_pszFileName, "mp_lobby.rpak") == 0) + s_bBasePaksInitialized = false; + } } CPakFile_Unload(handle); diff --git a/r5dev/rtech/rtech_utils.cpp b/r5dev/rtech/rtech_utils.cpp index 4836199e..be4e0960 100644 --- a/r5dev/rtech/rtech_utils.cpp +++ b/r5dev/rtech/rtech_utils.cpp @@ -498,22 +498,48 @@ std::uint8_t __fastcall RTech::DecompressPakFile(RPakDecompState_t* state, std:: } //----------------------------------------------------------------------------- -// Purpose: gets information about loaded pak file +// Purpose: gets copied information about loaded pak file via pak ID //----------------------------------------------------------------------------- -RPakLoadedInfo_t RTech::GetPakLoadedInfo(int nPakId) +RPakLoadedInfo_t* RTech::GetPakLoadedInfo(int nPakId) { for (int i = 0; i < *s_pLoadedPakCount; ++i) { - RPakLoadedInfo_t info = g_pLoadedPakInfo[i]; + RPakLoadedInfo_t* info = &g_pLoadedPakInfo[i]; + if (!info) + continue; - if (info.m_nPakId != nPakId) + if (info->m_nPakId != nPakId) continue; return info; } Warning(eDLL_T::RTECH, "%s - Failed getting RPakLoadInfo_t for PakId '%d'\n", __FUNCTION__, nPakId); - return RPakLoadedInfo_t(); + return nullptr; +} + +//----------------------------------------------------------------------------- +// Purpose: gets copied information about loaded pak file via pak name +//----------------------------------------------------------------------------- +RPakLoadedInfo_t* RTech::GetPakLoadedInfo(const char* szPakName) +{ + for (int i = 0; i < *s_pLoadedPakCount; ++i) + { + RPakLoadedInfo_t* info = &g_pLoadedPakInfo[i]; + if (!info) + continue; + + if (!info->m_pszFileName || !*info->m_pszFileName) + continue; + + if (strcmp(szPakName, info->m_pszFileName) != 0) + continue; + + return info; + } + + Warning(eDLL_T::RTECH, "%s - Failed getting RPakLoadInfo_t for Pak '%s'\n", __FUNCTION__, szPakName); + return nullptr; } /////////////////////////////////////////////////////////////////////////////// RTech* g_pRTech = new RTech(); diff --git a/r5dev/rtech/rtech_utils.h b/r5dev/rtech/rtech_utils.h index c49ed43b..15d807c4 100644 --- a/r5dev/rtech/rtech_utils.h +++ b/r5dev/rtech/rtech_utils.h @@ -172,7 +172,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); + RPakLoadedInfo_t* GetPakLoadedInfo(int nPakId); + RPakLoadedInfo_t* GetPakLoadedInfo(const char* szPakName); }; diff --git a/r5dev/tier1/cmd.cpp b/r5dev/tier1/cmd.cpp index 138fdce5..b4ff14dd 100644 --- a/r5dev/tier1/cmd.cpp +++ b/r5dev/tier1/cmd.cpp @@ -154,7 +154,8 @@ void ConCommand::Init(void) // RTECH API | new ConCommand("rtech_strtoguid", "Calculates the GUID from input data.", FCVAR_DEVELOPMENTONLY, RTech_StringToGUID_f, nullptr); new ConCommand("pak_requestload", "Requests asynchronous load for specified RPAK file.", FCVAR_DEVELOPMENTONLY, Pak_RequestLoad_f, nullptr); - new ConCommand("pak_requestunload", "Requests unload for specified RPAK by ID.", FCVAR_DEVELOPMENTONLY, Pak_RequestUnload_f, nullptr); + new ConCommand("pak_requestunload", "Requests unload for specified RPAK file or ID.", FCVAR_DEVELOPMENTONLY, Pak_RequestUnload_f, nullptr); + new ConCommand("pak_swap", "Requests dwap for specified RPAK file or ID", FCVAR_DEVELOPMENTONLY, Pak_Swap_f, nullptr); new ConCommand("pak_decompress", "Decompresses the specified RPAK file.", FCVAR_DEVELOPMENTONLY, RTech_Decompress_f, nullptr); new ConCommand("pak_listpaks", "Display a list of the loaded Pak files.", FCVAR_DEVELOPMENTONLY, Pak_ListPaks_f, nullptr); //------------------------------------------------------------------------- diff --git a/r5dev/vstdlib/callback.cpp b/r5dev/vstdlib/callback.cpp index 72634bfe..ede0701d 100644 --- a/r5dev/vstdlib/callback.cpp +++ b/r5dev/vstdlib/callback.cpp @@ -378,18 +378,31 @@ void Pak_RequestUnload_f(const CCommand& args) if (args.HasOnlyDigits(1)) { RPakHandle_t 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); + RPakLoadedInfo_t* pakInfo = g_pRTech->GetPakLoadedInfo(nPakId); + if (!pakInfo) + { + throw std::exception("Found no Pak entry for specified ID."); + } + + string pakName = pakInfo->m_pszFileName; + !pakName.empty() ? DevMsg(eDLL_T::RTECH, "Requested Pak Unload for '%s'\n", pakName.c_str()) : DevMsg(eDLL_T::RTECH, "Requested Pak Unload for '%d'\n", nPakId); g_pakLoadApi->Unload(nPakId); } else { - throw std::exception("Please provide a number as an arg."); + RPakLoadedInfo_t* pakInfo = g_pRTech->GetPakLoadedInfo(args.Arg(1)); + if (!pakInfo) + { + throw std::exception("Found no Pak entry for specified name."); + } + + DevMsg(eDLL_T::RTECH, "Requested Pak Unload for '%s'\n", args.Arg(1)); + g_pakLoadApi->Unload(pakInfo->m_nPakId); } } catch (std::exception& e) { - Error(eDLL_T::RTECH, "RequestUnload Error: %s", e.what()); + Error(eDLL_T::RTECH, "%s - %s", __FUNCTION__, e.what()); return; } #endif // GAMEDLL_S3 @@ -405,6 +418,61 @@ void Pak_RequestLoad_f(const CCommand& args) g_pakLoadApi->AsyncLoad(args.Arg(1)); } + +/* +===================== +Pak_Swap_f +===================== +*/ +void Pak_Swap_f(const CCommand& args) +{ +#ifdef GAMEDLL_S3 + try + { + RPakHandle_t nPakId = 0; + RPakLoadedInfo_t* pakInfo = nullptr; + string pakName = std::string(); + + if (args.HasOnlyDigits(1)) + { + nPakId = std::stoi(args.Arg(1)); + pakInfo = g_pRTech->GetPakLoadedInfo(nPakId); + if (!pakInfo) + { + throw std::exception("Found no Pak entry for specified ID."); + } + + pakName = pakInfo->m_pszFileName; + } + else + { + pakName = args.Arg(1); + pakInfo = g_pRTech->GetPakLoadedInfo(args.Arg(1)); + if (!pakInfo) + { + throw std::exception("Found no Pak entry for specified name."); + } + + nPakId = pakInfo->m_nPakId; + } + + !pakName.empty() ? DevMsg(eDLL_T::RTECH, "Requested Pak Swap for '%s'\n", pakName.c_str()) : DevMsg(eDLL_T::RTECH, "Requested Pak Swap for '%d'\n", nPakId); + + g_pakLoadApi->Unload(nPakId); + + while (pakInfo->m_nStatus != RPakStatus_t::PAK_STATUS_FREED) // Wait till this slot gets free'd. + std::this_thread::sleep_for(std::chrono::seconds(1)); + + g_pakLoadApi->AsyncLoad(pakName.c_str()); + } + catch (std::exception& e) + { + Error(eDLL_T::RTECH, "%s - %s", __FUNCTION__, e.what()); + return; + } +#endif// GAMEDLL_S3 +} + /* ===================== RTech_StringToGUID_f diff --git a/r5dev/vstdlib/callback.h b/r5dev/vstdlib/callback.h index 527c8db6..965e6a0b 100644 --- a/r5dev/vstdlib/callback.h +++ b/r5dev/vstdlib/callback.h @@ -26,6 +26,7 @@ void Host_ReloadBanList_f(const CCommand& args); void Pak_ListPaks_f(const CCommand& args); void Pak_RequestUnload_f(const CCommand& args); void Pak_RequestLoad_f(const CCommand& args); +void Pak_Swap_f(const CCommand& args); void RTech_StringToGUID_f(const CCommand& args); void RTech_Decompress_f(const CCommand& args); void VPK_Unpack_f(const CCommand& args);