diff --git a/r5dev/common/sdktypes.h b/r5dev/common/sdktypes.h new file mode 100644 index 00000000..0d6c096e --- /dev/null +++ b/r5dev/common/sdktypes.h @@ -0,0 +1,15 @@ +#ifndef SDKTYPES_H +#define SDKTYPES_H + +// Common type declarations to reduce code verbosity. +using std::string; +using std::vector; +using std::fstream; +using std::ifstream; +using std::ofstream; +using std::ostringstream; + +namespace fs = std::filesystem; +typedef const unsigned char* rsig_t; + +#endif // SDKTYPES_H diff --git a/r5dev/core/init.cpp b/r5dev/core/init.cpp index 581038be..7365a86e 100644 --- a/r5dev/core/init.cpp +++ b/r5dev/core/init.cpp @@ -13,12 +13,13 @@ #include "tier0/IConVar.h" #include "vpc/IAppSystem.h" #include "vpc/keyvalues.h" -#include "vpc/basefilesystem.h" #include "vpc/interfaces.h" #include "common/opcodes.h" #include "common/netmessages.h" #include "launcher/IApplication.h" #include "launcher/prx.h" +#include "filesystem/basefilesystem.h" +#include "filesystem/filesystem.h" #include "ebisusdk/EbisuSDK.h" #ifndef DEDICATED #include "milessdk/win64_rrthreads.h" diff --git a/r5dev/core/stdafx.h b/r5dev/core/stdafx.h index 66d08fd1..8f0fce7a 100644 --- a/r5dev/core/stdafx.h +++ b/r5dev/core/stdafx.h @@ -63,10 +63,7 @@ #include "tier0/basetypes.h" #include "tier0/platform.h" #include "common/pseudodefs.h" - -// Common type declarations to reduce code verbosity. -using std::string; -using std::vector; +#include "common/sdktypes.h" #if !defined(SDKLAUNCHER) && !defined (NETCONSOLE) namespace @@ -80,6 +77,7 @@ namespace MODULE g_mGameDll = MODULE("r5apex_ds.exe"); #endif // !DEDICATED } +#define VAR_NAME(varName) #varName #define MEMBER_AT_OFFSET(varType, varName, offset) \ varType& varName() \ diff --git a/r5dev/filesystem/basefilesystem.cpp b/r5dev/filesystem/basefilesystem.cpp new file mode 100644 index 00000000..b595bf1f --- /dev/null +++ b/r5dev/filesystem/basefilesystem.cpp @@ -0,0 +1,172 @@ +#include "core/stdafx.h" +#include "core/logdef.h" +#include "tier0/cvar.h" +#include "filesystem/basefilesystem.h" +#include "filesystem/filesystem.h" +#ifndef DEDICATED +#include "gameui/IConsole.h" +#endif // !DEDICATED + +//--------------------------------------------------------------------------------- +// Purpose: reads data from memory +// Input : *pOutput - +// nSize - +// hFile - +// Output : lenght of read data +//--------------------------------------------------------------------------------- +int CBaseFileSystem::Read(void* pOutput, int nSize, FileHandle_t hFile) +{ + int index = 0; + return CallVFunc(index, this, pOutput, nSize, hFile); +} + +//--------------------------------------------------------------------------------- +// Purpose: open file +// Input : *pFileName - +// *pOptions - +// *pPathID - +// unknown +// Output : Handle to file on success, NULL on failure +//--------------------------------------------------------------------------------- +FileHandle_t CBaseFileSystem::Open(const char* pFileName, const char* pOptions, const char* pPathID, int64_t unknown) +{ + int index = 2; + return CallVFunc(index, this, pFileName, pOptions, pPathID, unknown); +} + +//--------------------------------------------------------------------------------- +// Purpose: checks if file exists in all searchpaths and pak files +// Input : *pFileName - +// *pPathID - +// Output : true if file exists, false otherwise +//--------------------------------------------------------------------------------- +bool CBaseFileSystem::FileExists(const char* pFileName, const char* pPathID) +{ + int index = 10; + return CallVFunc(index, this, pFileName, pPathID); +} + +//--------------------------------------------------------------------------------- +// Purpose: close file by handle +// Input : file - +//--------------------------------------------------------------------------------- +void CBaseFileSystem::Close(FileHandle_t file) +{ + int index = 3; + CallVFunc(index, this, file); +} +//--------------------------------------------------------------------------------- +// Purpose: prints the output of the filesystem based on the warning level +// Input : *this - +// level - +// *pFmt - +//--------------------------------------------------------------------------------- +void CBaseFileSystem::Warning(CBaseFileSystem* pFileSystem, FileWarningLevel_t level, const char* pFmt, ...) +{ + if (fs_warning_level_sdk->GetInt() < (int)level) + { + return; + } + + static char szBuf[1024] = {}; + + static std::shared_ptr iconsole = spdlog::get("game_console"); + static std::shared_ptr wconsole = spdlog::get("win_console"); + static std::shared_ptr fslogger = spdlog::get("filesystem_warn_logger"); + + {///////////////////////////// + va_list args{}; + va_start(args, pFmt); + + vsnprintf(szBuf, sizeof(szBuf), pFmt, args); + + szBuf[sizeof(szBuf) - 1] = 0; + va_end(args); + }///////////////////////////// + + fslogger->debug(szBuf); + + if (fs_show_warning_output->GetBool()) + { + wconsole->debug(szBuf); +#ifndef DEDICATED + g_spd_sys_w_oss.str(""); + g_spd_sys_w_oss.clear(); + + iconsole->debug(szBuf); + + std::string s = g_spd_sys_w_oss.str(); + + g_pIConsole->m_ivConLog.push_back(Strdup(s.c_str())); +#endif // !DEDICATED + } +} + +//--------------------------------------------------------------------------------- +// Purpose: attempts to load files from disk if exist before loading from VPK +// Input : *pVpk - +// *pResults - +// *pszFilePath - +// Output : Handle to file on success, NULL on failure +//--------------------------------------------------------------------------------- +FileHandle_t CBaseFileSystem::ReadFromVPK(CBaseFileSystem* pVpk, std::int64_t* pResults, char* pszFilePath) +{ + std::string svFilePath = ConvertToWinPath(pszFilePath); + + if (strstr(svFilePath.c_str(), "\\\*\\")) + { + // Erase '//*/'. + svFilePath.erase(0, 4); + } + + // TODO: obtain 'mod' SearchPath's instead. + svFilePath.insert(0, "platform\\"); + + if (::FileExists(svFilePath.c_str()) /*|| FileExists(pszFilePath)*/) + { + *pResults = -1; + return (void*)pResults; + } + return CBaseFileSystem_LoadFromVPK(pVpk, pResults, pszFilePath); +} + +//--------------------------------------------------------------------------------- +// Purpose: attempts to load files from disk if exist before loading from cache +// Input : *pFileSystem - +// *pszFilePath - +// *pResults - +// Output : true if file exists, false otherwise +//--------------------------------------------------------------------------------- +bool CBaseFileSystem::ReadFromCache(CBaseFileSystem* pFileSystem, char* pszFilePath, void* pResults) +{ + std::string svFilePath = ConvertToWinPath(pszFilePath); + + if (strstr(svFilePath.c_str(), "\\\*\\")) + { + // Erase '//*/'. + svFilePath.erase(0, 4); + } + + // TODO: obtain 'mod' SearchPath's instead. + svFilePath.insert(0, "platform\\"); + + if (::FileExists(svFilePath.c_str()) /*|| FileExists(pszFilePath)*/) + { + return false; + } + return CBaseFileSystem_LoadFromCache(pFileSystem, pszFilePath, pResults); +} + +void CBaseFileSystem_Attach() +{ + DetourAttach((LPVOID*)&CBaseFileSystem_Warning, &CBaseFileSystem::Warning); + DetourAttach((LPVOID*)&CBaseFileSystem_LoadFromVPK, &CBaseFileSystem::ReadFromVPK); + DetourAttach((LPVOID*)&CBaseFileSystem_LoadFromCache, &CBaseFileSystem::ReadFromCache); +} + +void CBaseFileSystem_Detach() +{ + DetourDetach((LPVOID*)&CBaseFileSystem_Warning, &CBaseFileSystem::Warning); + DetourDetach((LPVOID*)&CBaseFileSystem_LoadFromVPK, &CBaseFileSystem::ReadFromVPK); + DetourDetach((LPVOID*)&CBaseFileSystem_LoadFromCache, &CBaseFileSystem::ReadFromCache); +} diff --git a/r5dev/vpc/basefilesystem.h b/r5dev/filesystem/basefilesystem.h similarity index 65% rename from r5dev/vpc/basefilesystem.h rename to r5dev/filesystem/basefilesystem.h index 5c04523c..a6aa3ff0 100644 --- a/r5dev/vpc/basefilesystem.h +++ b/r5dev/filesystem/basefilesystem.h @@ -1,17 +1,17 @@ #pragma once +#include "filesystem/filesystem.h" -typedef void* FileHandle_t; -enum class FileWarningLevel_t : int +class CBaseFileSystem { - FILESYSTEM_WARNING = -1, // A problem! - FILESYSTEM_WARNING_QUIET = 0, // Don't print anything - FILESYSTEM_WARNING_REPORTUNCLOSED, // On shutdown, report names of files left unclosed - FILESYSTEM_WARNING_REPORTUSAGE, // Report number of times a file was opened, closed - FILESYSTEM_WARNING_REPORTALLACCESSES, // Report all open/close events to console ( !slow! ) - FILESYSTEM_WARNING_REPORTALLACCESSES_READ, // Report all open/close/read events to the console ( !slower! ) - FILESYSTEM_WARNING_REPORTALLACCESSES_READWRITE, // Report all open/close/read/write events to the console ( !slower! ) - FILESYSTEM_WARNING_REPORTALLACCESSES_ASYNC // Report all open/close/read/write events and all async I/O file events to the console ( !slower(est)! ) +public: + int Read(void* pOutput, int nSize, FileHandle_t hFile); + FileHandle_t Open(const char* pFileName, const char* pOptions, const char* pPathID, int64_t unknown); + void Close(FileHandle_t file); + bool FileExists(const char* pFileName, const char* pPathID); + static void Warning(CBaseFileSystem* pFileSystem, FileWarningLevel_t level, const char* fmt, ...); + static FileHandle_t ReadFromVPK(CBaseFileSystem* pVpk, std::int64_t* pResults, char* pszFilePath); + static bool ReadFromCache(CBaseFileSystem* pFileSystem, char* pszFilePath, void* pResults); }; namespace @@ -25,6 +25,9 @@ namespace ADDRESS p_CBaseFileSystem_LoadFromCache = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x40\x53\x48\x81\xEC\x00\x00\x00\x00\x80\x3D\x00\x00\x00\x00\x00\x49\x8B\xD8", "xxxxx????xx?????xxx"); bool(*CBaseFileSystem_LoadFromCache)(void* pFileSystem, char* pszAssetName, void* pResults) = (bool(*)(void*, char*, void*))p_CBaseFileSystem_LoadFromCache.GetPtr(); /*40 53 48 81 EC ? ? ? ? 80 3D ? ? ? ? ? 49 8B D8*/ + + CBaseFileSystem* g_pFileSystem = g_mGameDll.FindPatternSIMD((uint8_t*)"\x48\x83\xEC\x28\xE8\x00\x00\x00\x00\x48\x8D\x05\x00\x00\x00\x00", "xxxxx????xxx????") + .Offset(0x20).FindPatternSelf("48 89 05", ADDRESS::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); } /////////////////////////////////////////////////////////////////////////////// @@ -36,9 +39,10 @@ class HBaseFileSystem : public IDetour { virtual void debugp() { - std::cout << "| FUN: CBaseFileSystem::Warning : 0x" << std::hex << std::uppercase << p_CBaseFileSystem_Warning.GetPtr() << std::setw(npad) << " |" << std::endl; - std::cout << "| FUN: CBaseFileSystem::LoadFromVPK : 0x" << std::hex << std::uppercase << p_CBaseFileSystem_LoadFromVPK.GetPtr() << std::setw(npad) << " |" << std::endl; - std::cout << "| FUN: CBaseFileSystem::LoadFromCache : 0x" << std::hex << std::uppercase << p_CBaseFileSystem_LoadFromCache.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: CBaseFileSystem::Warning : 0x" << std::hex << std::uppercase << p_CBaseFileSystem_Warning.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: CBaseFileSystem::LoadFromVPK : 0x" << std::hex << std::uppercase << p_CBaseFileSystem_LoadFromVPK.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: CBaseFileSystem::LoadFromCache : 0x" << std::hex << std::uppercase << p_CBaseFileSystem_LoadFromCache.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| VAR: g_pFileSystem : 0x" << std::hex << std::uppercase << g_pFileSystem << std::setw(0) << " |" << std::endl; std::cout << "+----------------------------------------------------------------+" << std::endl; } }; diff --git a/r5dev/filesystem/filesystem.cpp b/r5dev/filesystem/filesystem.cpp new file mode 100644 index 00000000..fb24d03f --- /dev/null +++ b/r5dev/filesystem/filesystem.cpp @@ -0,0 +1,38 @@ +#include "core/stdafx.h" +#include "vpklib/packedstore.h" +#include "filesystem/filesystem.h" + +//----------------------------------------------------------------------------- +// Purpose: create the search path. +// Input : *pPath - +// *pPathID - +// addType - +//----------------------------------------------------------------------------- +void CFileSystem_Stdio::AddSearchPath(const char* pPath, const char* pPathID, SearchPathAdd_t addType) +{ + static int index = 12; + CallVFunc(index, this, pPath, pPathID, addType); +} + +//----------------------------------------------------------------------------- +// Purpose: read file from cache. +// Input : *pPath - +// *pResult - +// Output : true if exists, false otherwise. +//----------------------------------------------------------------------------- +bool CFileSystem_Stdio::ReadFromCache(const char* pPath, void* pResult) +{ + static int index = 76; + return CallVFunc(index, this, pPath, pResult); +} + +//----------------------------------------------------------------------------- +// Purpose: mount specified VPK file (to access data). +// Input : *pPath - +// Output : *VPKData_t (information about mounted VPK file) +//----------------------------------------------------------------------------- +VPKData_t* CFileSystem_Stdio::MountVPK(const char* pPath) +{ + static int index = 92; + return CallVFunc(index, this, pPath); +} diff --git a/r5dev/filesystem/filesystem.h b/r5dev/filesystem/filesystem.h new file mode 100644 index 00000000..239d8ff0 --- /dev/null +++ b/r5dev/filesystem/filesystem.h @@ -0,0 +1,52 @@ +#ifndef FILESYSTEM_H +#define FILESYSTEM_H +#include "vpklib/packedstore.h" + +typedef void* FileHandle_t; + +enum class SearchPathAdd_t : int +{ + PATH_ADD_TO_HEAD, // First path searched + PATH_ADD_TO_TAIL, // Last path searched + PATH_ADD_TO_TAIL_ATINDEX, // First path searched +}; + +enum class FileWarningLevel_t : int +{ + FILESYSTEM_WARNING = -1, // A problem! + FILESYSTEM_WARNING_QUIET = 0, // Don't print anything + FILESYSTEM_WARNING_REPORTUNCLOSED, // On shutdown, report names of files left unclosed + FILESYSTEM_WARNING_REPORTUSAGE, // Report number of times a file was opened, closed + FILESYSTEM_WARNING_REPORTALLACCESSES, // Report all open/close events to console ( !slow! ) + FILESYSTEM_WARNING_REPORTALLACCESSES_READ, // Report all open/close/read events to the console ( !slower! ) + FILESYSTEM_WARNING_REPORTALLACCESSES_READWRITE, // Report all open/close/read/write events to the console ( !slower! ) + FILESYSTEM_WARNING_REPORTALLACCESSES_ASYNC // Report all open/close/read/write events and all async I/O file events to the console ( !slower(est)! ) +}; + +class CFileSystem_Stdio +{ +public: + void AddSearchPath(const char* pPath, const char* pathID, SearchPathAdd_t addType); + bool ReadFromCache(const char* pPath, void* pResult); + VPKData_t* MountVPK(const char* vpkPath); +}; + +namespace +{ + CFileSystem_Stdio* g_pFileSystem_Stdio = g_mGameDll.FindPatternSIMD((uint8_t*)"\x40\x53\x48\x83\xEC\x20\x48\x8B\xD9\xFF\x15\x00\x00\x00\x00\x48\x8D\x05\x00\x00\x00\x00", "xxxxxxxxxxx????xxx????") + .FindPatternSelf("48 8D", ADDRESS::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); +} + +/////////////////////////////////////////////////////////////////////////////// +class HFileSystem_Stdio : public IDetour +{ + virtual void debugp() + { + std::cout << "| VAR: g_pFileSystem_Stdio : 0x" << std::hex << std::uppercase << g_pFileSystem_Stdio << std::setw(0) << " |" << std::endl; + std::cout << "+----------------------------------------------------------------+" << std::endl; + } +}; +/////////////////////////////////////////////////////////////////////////////// + +REGISTER(HFileSystem_Stdio); +#endif // !FILESYSTEM_H diff --git a/r5dev/launcher/IApplication.cpp b/r5dev/launcher/IApplication.cpp index cb0b037d..c7657a6f 100644 --- a/r5dev/launcher/IApplication.cpp +++ b/r5dev/launcher/IApplication.cpp @@ -6,6 +6,7 @@ #include "core/stdafx.h" #include "tier0/cvar.h" +#include "vpc/interfaces.h" #include "launcher/IApplication.h" #include "ebisusdk/EbisuSDK.h" #include "engine/sys_engine.h" @@ -47,7 +48,6 @@ int HModAppSystemGroup_Main(CModAppSystemGroup* modAppSystemGroup) SV_ShutdownGameDLL(); } } - return nRunResult; #endif } @@ -61,13 +61,14 @@ bool HModAppSystemGroup_Create(CModAppSystemGroup* modAppSystemGroup) * g_bDedicated = true; #endif // DEDICATED g_pConCommand->Init(); + g_pFactory->GetFactoriesFromRegister(); for (auto& map : g_pCVar->DumpToMap()) { g_vsvCommandBases.push_back(map.first.c_str()); } - g_bAppSystemInit = true; + g_bAppSystemInit = true; return CModAppSystemGroup_Create(modAppSystemGroup); } diff --git a/r5dev/public/include/memaddr.h b/r5dev/public/include/memaddr.h index 87d9f182..31fa88b7 100644 --- a/r5dev/public/include/memaddr.h +++ b/r5dev/public/include/memaddr.h @@ -458,7 +458,7 @@ public: return ADDRESS(latestOccurence); } - ADDRESS FindPatternSIMD(std::uint8_t* szPattern, const char* szMask) + ADDRESS FindPatternSIMD(const std::uint8_t* szPattern, const char* szMask) { ModuleSections mInfo = GetSectionByName(".text"); // Get the .text section. if (!mInfo.IsSectionValid()) diff --git a/r5dev/tier0/cmd.cpp b/r5dev/tier0/cmd.cpp index 642df652..9f7328a0 100644 --- a/r5dev/tier0/cmd.cpp +++ b/r5dev/tier0/cmd.cpp @@ -120,40 +120,41 @@ void ConCommand::Init(void) { //------------------------------------------------------------------------- // SERVER DLL | - ConCommand* script = new ConCommand("script", "Run input code as SERVER script on the VM.", FCVAR_GAMEDLL | FCVAR_CHEAT, _SQVM_ServerScript_f_CompletionFunc, nullptr); - ConCommand* sv_kick = new ConCommand("sv_kick", "Kick a client from the server by name. | Usage: kick \"\".", FCVAR_RELEASE, _Kick_f_CompletionFunc, nullptr); - ConCommand* sv_kickid = new ConCommand("sv_kickid", "Kick a client from the server by UserID or OriginID | Usage: kickid \"\"/\"\".", FCVAR_RELEASE, _KickID_f_CompletionFunc, nullptr); - ConCommand* sv_ban = new ConCommand("sv_ban", "Bans a client from the server by name. | Usage: ban .", FCVAR_RELEASE, _Ban_f_CompletionFunc, nullptr); - ConCommand* sv_banid = new ConCommand("sv_banid", "Bans a client from the server by OriginID, UserID or IPAddress | Usage: banid \"\"/\"/\".", FCVAR_RELEASE, _BanID_f_CompletionFunc, nullptr); - ConCommand* sv_unban = new ConCommand("sv_unban", "Unbans a client from the Server by IPAddress or OriginID | Usage: unban \"\"/\"\".", FCVAR_RELEASE, _Unban_f_CompletionFunc, nullptr); - ConCommand* sv_reloadbanlist = new ConCommand("sv_reloadbanlist", "Reloads the ban list from the disk.", FCVAR_RELEASE, _ReloadBanList_f_CompletionFunc, nullptr); + new ConCommand("script", "Run input code as SERVER script on the VM.", FCVAR_GAMEDLL | FCVAR_CHEAT, _SQVM_ServerScript_f_CompletionFunc, nullptr); + new ConCommand("sv_kick", "Kick a client from the server by name. | Usage: kick \"\".", FCVAR_RELEASE, _Kick_f_CompletionFunc, nullptr); + new ConCommand("sv_kickid", "Kick a client from the server by UserID or OriginID | Usage: kickid \"\"/\"\".", FCVAR_RELEASE, _KickID_f_CompletionFunc, nullptr); + new ConCommand("sv_ban", "Bans a client from the server by name. | Usage: ban .", FCVAR_RELEASE, _Ban_f_CompletionFunc, nullptr); + new ConCommand("sv_banid", "Bans a client from the server by OriginID, UserID or IPAddress | Usage: banid \"\"/\"/\".", FCVAR_RELEASE, _BanID_f_CompletionFunc, nullptr); + new ConCommand("sv_unban", "Unbans a client from the Server by IPAddress or OriginID | Usage: unban \"\"/\"\".", FCVAR_RELEASE, _Unban_f_CompletionFunc, nullptr); + new ConCommand("sv_reloadbanlist", "Reloads the ban list from the disk.", FCVAR_RELEASE, _ReloadBanList_f_CompletionFunc, nullptr); #ifndef DEDICATED //------------------------------------------------------------------------- // CLIENT DLL | - ConCommand* script_client = new ConCommand("script_client", "Run input code as CLIENT script on the VM.", FCVAR_CLIENTDLL | FCVAR_CHEAT, _SQVM_ClientScript_f_CompletionFunc, nullptr); - ConCommand* cl_showconsole = new ConCommand("cl_showconsole", "Opens the game console.", FCVAR_CLIENTDLL | FCVAR_RELEASE, _CGameConsole_f_CompletionFunc, nullptr); - ConCommand* cl_showbrowser = new ConCommand("cl_showbrowser", "Opens the server browser.", FCVAR_CLIENTDLL | FCVAR_RELEASE, _CCompanion_f_CompletionFunc, nullptr); - ConCommand* rcon = new ConCommand("rcon", "Forward RCON query to remote server. | Usage: rcon \"\".", FCVAR_CLIENTDLL | FCVAR_RELEASE, _RCON_CmdQuery_f_CompletionFunc, nullptr); - ConCommand* rcon_disconnect = new ConCommand("rcon_disconnect", "Disconnect from RCON server.", FCVAR_CLIENTDLL | FCVAR_RELEASE, _RCON_Disconnect_f_CompletionFunc, nullptr); + new ConCommand("script_client", "Run input code as CLIENT script on the VM.", FCVAR_CLIENTDLL | FCVAR_CHEAT, _SQVM_ClientScript_f_CompletionFunc, nullptr); + new ConCommand("cl_showconsole", "Opens the game console.", FCVAR_CLIENTDLL | FCVAR_RELEASE, _CGameConsole_f_CompletionFunc, nullptr); + new ConCommand("cl_showbrowser", "Opens the server browser.", FCVAR_CLIENTDLL | FCVAR_RELEASE, _CCompanion_f_CompletionFunc, nullptr); + new ConCommand("rcon", "Forward RCON query to remote server. | Usage: rcon \"\".", FCVAR_CLIENTDLL | FCVAR_RELEASE, _RCON_CmdQuery_f_CompletionFunc, nullptr); + new ConCommand("rcon_disconnect", "Disconnect from RCON server.", FCVAR_CLIENTDLL | FCVAR_RELEASE, _RCON_Disconnect_f_CompletionFunc, nullptr); //------------------------------------------------------------------------- // UI DLL | - ConCommand* script_ui = new ConCommand("script_ui", "Run input code as UI script on the VM.", FCVAR_CLIENTDLL | FCVAR_CHEAT, _SQVM_UIScript_f_CompletionFunc, nullptr); + new ConCommand("script_ui", "Run input code as UI script on the VM.", FCVAR_CLIENTDLL | FCVAR_CHEAT, _SQVM_UIScript_f_CompletionFunc, nullptr); #endif // !DEDICATED //------------------------------------------------------------------------- // FILESYSTEM API | - ConCommand* fs_decompress_pak = new ConCommand("fs_decompress_pak", "Decompresses user specified 'vpk_dir' file.", FCVAR_DEVELOPMENTONLY, _VPK_Decompress_f_CompletionFunc, nullptr); + new ConCommand("fs_unpack_vpk", "Unpacks all files from user specified VPK file.", FCVAR_DEVELOPMENTONLY, _VPK_Unpack_f_CompletionFunc, nullptr); + new ConCommand("fs_mount_vpk", "Mounts user specified VPK file for FileSystem usage.", FCVAR_DEVELOPMENTONLY, _VPK_Mount_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_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 by 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); + new ConCommand("rtech_strtoguid", "Calculates the GUID from input data.", FCVAR_DEVELOPMENTONLY, _RTech_StringToGUID_f_CompletionFunc, nullptr); + new ConCommand("pak_requestload", "Requests asynchronous load for specified RPAK file.", FCVAR_DEVELOPMENTONLY, _Pak_RequestLoad_f_CompletionFunc, nullptr); + new ConCommand("pak_requestunload", "Requests unload for specified RPAK by ID.", FCVAR_DEVELOPMENTONLY, _Pak_RequestUnload_f_CompletionFunc, nullptr); + new ConCommand("pak_decompress", "Decompresses the specified RPAK file.", FCVAR_DEVELOPMENTONLY, _RTech_Decompress_f_CompletionFunc, nullptr); + 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); - ConCommand* net_setkey = new ConCommand("net_setkey", "Sets user specified base64 net key.", FCVAR_RELEASE, _NET_SetKey_f_CompletionFunc, nullptr); - ConCommand* net_generatekey = new ConCommand("net_generatekey", "Generates and sets a random base64 net key.", FCVAR_RELEASE, _NET_GenerateKey_f_CompletionFunc, nullptr); + 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); + new ConCommand("net_setkey", "Sets user specified base64 net key.", FCVAR_RELEASE, _NET_SetKey_f_CompletionFunc, nullptr); + new ConCommand("net_generatekey", "Generates and sets a random base64 net key.", FCVAR_RELEASE, _NET_GenerateKey_f_CompletionFunc, nullptr); #ifndef DEDICATED //------------------------------------------------------------------------- // MATERIAL SYSTEM diff --git a/r5dev/tier0/completion.cpp b/r5dev/tier0/completion.cpp index 134ff38e..7f4bc815 100644 --- a/r5dev/tier0/completion.cpp +++ b/r5dev/tier0/completion.cpp @@ -18,6 +18,8 @@ #include "engine/baseclient.h" #include "rtech/rtech_game.h" #include "rtech/rtech_utils.h" +#include "filesystem/basefilesystem.h" +#include "filesystem/filesystem.h" #include "vpklib/packedstore.h" #include "squirrel/sqvm.h" #ifndef DEDICATED @@ -599,7 +601,7 @@ _VPK_Decompress_f_CompletionFunc dumps the output to '\vpk'. ===================== */ -void _VPK_Decompress_f_CompletionFunc(const CCommand& args) +void _VPK_Unpack_f_CompletionFunc(const CCommand& args) { if (args.ArgC() < 2) { @@ -612,7 +614,7 @@ void _VPK_Decompress_f_CompletionFunc(const CCommand& args) DevMsg(eDLL_T::FS, "] FS_DECOMPRESS ----------------------------------------------\n"); DevMsg(eDLL_T::FS, "] Processing: '%s'\n", args.Arg(1)); - vpk_dir_h vpk = g_pPackedStore->GetPackDirFile(args.Arg(1)); + VPKDir_t vpk = g_pPackedStore->GetPackDirFile(args.Arg(1)); g_pPackedStore->InitLzDecompParams(); std::thread th([&] { g_pPackedStore->UnpackAll(vpk, szPathOut); }); @@ -628,6 +630,39 @@ void _VPK_Decompress_f_CompletionFunc(const CCommand& args) DevMsg(eDLL_T::FS, "--------------------------------------------------------------\n"); } +/* +===================== +_VPK_Mount_f_CompletionFunc + + Mounts input VPK file for + internal FileSystem usage +===================== +*/ +void _VPK_Mount_f_CompletionFunc(const CCommand& args) +{ + if (args.ArgC() < 2) + { + return; + } + + if (g_pFileSystem_Stdio) + { + VPKData_t* pPakData = g_pFileSystem_Stdio->MountVPK(args.Arg(1)); + if (pPakData) + { + DevMsg(eDLL_T::FS, "Mounted VPK file '%s' with handle '%d'\n", args.Arg(1), pPakData->m_nHandle); + } + else + { + Warning(eDLL_T::FS, "Unable to mount VPK file '%s': non-existent VPK file\n", args.Arg(1)); + } + } + else + { + Warning(eDLL_T::FS, "Unable to mount VPK file '%s': '%s' is not initalized\n", args.Arg(1), VAR_NAME(g_pFileSystem)); + } +} + /* ===================== _NET_SetKey_f_CompletionFunc diff --git a/r5dev/tier0/completion.h b/r5dev/tier0/completion.h index 3a82b99e..94a11c05 100644 --- a/r5dev/tier0/completion.h +++ b/r5dev/tier0/completion.h @@ -31,7 +31,8 @@ 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_Decompress_f_CompletionFunc(const CCommand& args); -void _VPK_Decompress_f_CompletionFunc(const CCommand& args); +void _VPK_Unpack_f_CompletionFunc(const CCommand& args); +void _VPK_Mount_f_CompletionFunc(const CCommand& args); void _NET_TraceNetChan_f_CompletionFunc(const CCommand& args); void _NET_SetKey_f_CompletionFunc(const CCommand& args); void _NET_GenerateKey_f_CompletionFunc(const CCommand& args); diff --git a/r5dev/vpc/basefilesystem.cpp b/r5dev/vpc/basefilesystem.cpp deleted file mode 100644 index 403f2a78..00000000 --- a/r5dev/vpc/basefilesystem.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "core/stdafx.h" -#include "core/logdef.h" -#include "tier0/cvar.h" -#include "vpc/basefilesystem.h" -#ifndef DEDICATED -#include "gameui/IConsole.h" -#endif // !DEDICATED - -//--------------------------------------------------------------------------------- -// Purpose: prints the output of the filesystem based on the warning level -//--------------------------------------------------------------------------------- -void HCBaseFileSystem_Warning(void* thisptr, FileWarningLevel_t level, const char* fmt, ...) -{ - if (fs_warning_level_sdk->GetInt() < (int)level) - { - return; - } - - static char buf[1024] = {}; - - static std::shared_ptr iconsole = spdlog::get("game_console"); - static std::shared_ptr wconsole = spdlog::get("win_console"); - static std::shared_ptr fslogger = spdlog::get("filesystem_warn_logger"); - - {///////////////////////////// - va_list args{}; - va_start(args, fmt); - - vsnprintf(buf, sizeof(buf), fmt, args); - - buf[sizeof(buf) - 1] = 0; - va_end(args); - }///////////////////////////// - - fslogger->debug(buf); - - if (fs_show_warning_output->GetBool()) - { - wconsole->debug(buf); -#ifndef DEDICATED - g_spd_sys_w_oss.str(""); - g_spd_sys_w_oss.clear(); - - iconsole->debug(buf); - - std::string s = g_spd_sys_w_oss.str(); - - g_pIConsole->m_ivConLog.push_back(Strdup(s.c_str())); -#endif // !DEDICATED - } -} - -//--------------------------------------------------------------------------------- -// Purpose: attempts to load files from disk if exist before loading from VPK -//--------------------------------------------------------------------------------- -FileHandle_t HCBaseFileSystem_ReadFromVPK(void* pVpk, std::int64_t* pResults, char* pszFilePath) -{ - std::string svFilePath = ConvertToWinPath(pszFilePath); - - if (strstr(svFilePath.c_str(), "\\\*\\")) - { - // Erase '//*/'. - svFilePath.erase(0, 4); - } - - // TODO: obtain 'mod' SearchPath's instead. - svFilePath.insert(0, "platform\\"); - - if (FileExists(svFilePath.c_str()) /*|| FileExists(pszFilePath)*/) - { - *pResults = -1; - return (void*)pResults; - } - return CBaseFileSystem_LoadFromVPK(pVpk, pResults, pszFilePath); -} - -//--------------------------------------------------------------------------------- -// Purpose: attempts to load files from disk if exist before loading from cache -//--------------------------------------------------------------------------------- -bool HCBaseFileSystem_ReadFromCache(void* pFileSystem, char* pszFilePath, void* pResults) -{ - std::string svFilePath = ConvertToWinPath(pszFilePath); - - if (strstr(svFilePath.c_str(), "\\\*\\")) - { - // Erase '//*/'. - svFilePath.erase(0, 4); - } - - // TODO: obtain 'mod' SearchPath's instead. - svFilePath.insert(0, "platform\\"); - - if (FileExists(svFilePath.c_str()) /*|| FileExists(pszFilePath)*/) - { - return false; - } - return CBaseFileSystem_LoadFromCache(pFileSystem, pszFilePath, pResults); -} - -void CBaseFileSystem_Attach() -{ - DetourAttach((LPVOID*)&CBaseFileSystem_Warning, &HCBaseFileSystem_Warning); - DetourAttach((LPVOID*)&CBaseFileSystem_LoadFromVPK, &HCBaseFileSystem_ReadFromVPK); - DetourAttach((LPVOID*)&CBaseFileSystem_LoadFromCache, &HCBaseFileSystem_ReadFromCache); -} - -void CBaseFileSystem_Detach() -{ - DetourDetach((LPVOID*)&CBaseFileSystem_Warning, &HCBaseFileSystem_Warning); - DetourDetach((LPVOID*)&CBaseFileSystem_LoadFromVPK, &HCBaseFileSystem_ReadFromVPK); - DetourDetach((LPVOID*)&CBaseFileSystem_LoadFromCache, &HCBaseFileSystem_ReadFromCache); -} diff --git a/r5dev/vpc/interfaces.cpp b/r5dev/vpc/interfaces.cpp index 39f83d94..47b4380c 100644 --- a/r5dev/vpc/interfaces.cpp +++ b/r5dev/vpc/interfaces.cpp @@ -7,57 +7,87 @@ #include "core/stdafx.h" #include "vpc/interfaces.h" +//--------------------------------------------------------------------------------- +// Purpose: add a factory to the factories vector +// Inout : factoryInfo - +//--------------------------------------------------------------------------------- +void CFactory::AddFactory(const string& svFactoryName, void* pFactory) +{ + int nVersionIndex = GetVersionIndex(svFactoryName); + FactoryInfo factoryInfo = FactoryInfo(svFactoryName, svFactoryName.substr(0, nVersionIndex), + svFactoryName.substr(nVersionIndex), reinterpret_cast(pFactory)); + + m_vFactories.push_back(factoryInfo); // Push factory info back into the vector. +} + +//--------------------------------------------------------------------------------- +// Purpose: add a factory to the factories vector +// Inout : factoryInfo - +//--------------------------------------------------------------------------------- +void CFactory::AddFactory(FactoryInfo factoryInfo) +{ + m_vFactories.push_back(factoryInfo); // Push factory info back into the vector. +} + +//--------------------------------------------------------------------------------- +// Purpose: get the version index from interface name +// Input : svInterfaceName - +// Output : index of version in input interface string +//--------------------------------------------------------------------------------- +int CFactory::GetVersionIndex(const string& svInterfaceName) const +{ + int nVersionIndex = 0; + for (int i = 0; i < svInterfaceName.length(); i++) // Loop through each charater to find the start of interface version. + { + if (std::isdigit(svInterfaceName[i])) + { + nVersionIndex = i; + break; + } + } + return nVersionIndex; +} + //--------------------------------------------------------------------------------- // Purpose: get all factory registered in the global s_pInterfacesRegs //--------------------------------------------------------------------------------- -void IFactory::GetFactoriesFromRegister() +void CFactory::GetFactoriesFromRegister(void) { - for (InterfaceGlobals_t* it = s_pInterfacesRegs; it; it = it->m_pNextInterfacePtr) // Loop till we go out of scope. + for (InterfaceGlobals_t* it = s_pInterfacesRegs.GetValue(); + it; it = it->m_pNextInterfacePtr) // Loop till we go out of scope. { - std::string interfaceName = it->m_pInterfaceName; // Get copy of the name. - int indexOfVersionStart = 0; - for (int i = 0; i < interfaceName.length(); i++) // Loop through each charater to find the start of interface version. - { - if (std::isdigit(interfaceName[i])) - { - indexOfVersionStart = i; - break; - } - } + string svInterfaceName = it->m_pInterfaceName; // Get copy of the name. + int nVersionIndex = GetVersionIndex(svInterfaceName); // Push back the interface. - AddFactory(FactoryInfo(interfaceName, interfaceName.substr(0, indexOfVersionStart), interfaceName.substr(indexOfVersionStart), reinterpret_cast(it->m_pInterfacePtr()))); + AddFactory(FactoryInfo(svInterfaceName, svInterfaceName.substr(0, nVersionIndex), + svInterfaceName.substr(nVersionIndex), reinterpret_cast(it->m_pInterfacePtr()))); } } //--------------------------------------------------------------------------------- -// Purpose: get factory pointer from factoryName from factories vector +// Purpose: get factory pointer with factoryname input from factories vector +// Input : svFactoryName - +// bVersionLess - +// Output : ADDRESS //--------------------------------------------------------------------------------- -ADDRESS IFactory::GetFactoryPtr(const std::string& factoryName, bool versionLess) +ADDRESS CFactory::GetFactoryPtr(const string& svFactoryName, bool bVersionLess) const { - for (auto& it : factories) // Loop through the whole vector. + for (auto& it : m_vFactories) // Loop through the whole vector. { - if (versionLess) + if (bVersionLess) { - if (it.m_szFactoryName == factoryName) // Name match? - return it.m_pFactoryPtr; // Return factory. + if (it.m_szFactoryName == svFactoryName) + return it.m_pFactoryPtr; } else { - if (it.m_szFactoryFullName == factoryName) // Name match? - return it.m_pFactoryPtr; // Return factory. + if (it.m_szFactoryFullName == svFactoryName) + return it.m_pFactoryPtr; } } return ADDRESS(); } -//--------------------------------------------------------------------------------- -// Purpose: add a factory to the factories vector -//--------------------------------------------------------------------------------- -void IFactory::AddFactory(FactoryInfo factoryInfo) -{ - factories.push_back(factoryInfo); // Push factory info back into the vector. -} - -IFactory* g_pFactory = new IFactory(); \ No newline at end of file +CFactory* g_pFactory = new CFactory(); \ No newline at end of file diff --git a/r5dev/vpc/interfaces.h b/r5dev/vpc/interfaces.h index fb121b33..ca8f680e 100644 --- a/r5dev/vpc/interfaces.h +++ b/r5dev/vpc/interfaces.h @@ -3,6 +3,46 @@ /*----------------------------------------------------------------------------- * _interfaces.h *-----------------------------------------------------------------------------*/ +#define VENGINE_LAUNCHER_API_VERSION "VENGINE_LAUNCHER_API_VERSION004" +#define VENGINE_GAMEUIFUNCS_VERSION "VENGINE_GAMEUIFUNCS_VERSION005" + +#define VENGINE_RENDERVIEW_INTERFACE_VERSION "VEngineRenderView014" +#define VENGINE_RANDOM_INTERFACE_VERSION "VEngineRandom001" +#define VENGINE_HUDMODEL_INTERFACE_VERSION "VEngineModel016" +#define MATERIALSYSTEM_CONFIG_VERSION "VMaterialSystemConfig004" + +#define SERVER_DLL_SHARED_APPSYSTEMS "VServerDllSharedAppSystems001" +#define INTERFACEVERSION_SERVERGAMECLIENTS "ServerGameClients004" +#define INTERFACEVERSION_SERVERGAMEENTS "ServerGameEnts002" +#define INTERFACEVERSION_SERVERGAMEDLL "ServerGameDLL005" + +#define VCLIENT_PREDICTION_INTERFACE_VERSION "VClientPrediction001" +#define VCLIENTENTITYLIST_INTERFACE_VERSION "VClientEntityList003" +#define CLIENT_DLL_INTERFACE_VERSION "VClient018" +#define CLIENTRENDERTARGETS_INTERFACE_VERSION "ClientRenderTargets001" +#define INTERFACEVERSION_ENGINETRACE_CLIENT "EngineTraceClient004" +#define INTERFACEVERSION_ENGINETRACEDECALS_CLIENT "EngineTraceClientDecals004" + +#define VGUI_SYSTEM_INTERFACE_VERSION "VGUI_System010" +#define GAMEUI_INTERFACE_VERSION "GameUI011" + +#define RUNGAMEENGINE_INTERFACE_VERSION "RunGameEngine005" +#define EVENTSYSTEM_INTERFACE_VERSION "EventSystem001" + +#define CVAR_QUERY_INTERFACE_VERSION "VCvarQuery001" +#define VPHYSICS_DEBUG_OVERLAY_INTERFACE_VERSION "VPhysicsDebugOverlay001" +#define VDEBUG_OVERLAY_INTERFACE_VERSION "VDebugOverlay004" +#define SOUNDCARD_INTERFACE_VERSION "ISoundC002" + +#define SHADERSYSTEM_INTERFACE_VERSION "ShaderSystem002" +#define FILESYSTEM_INTERFACE_VERSION "VFileSystem017" + //----------------------------------------------------------------------------- + +enum class InterfaceStatus_t : int +{ + IFACE_OK = 0, + IFACE_FAILED +}; //----------------------------------------------------------------------------- // Mapping of interface string to globals @@ -14,38 +54,44 @@ struct InterfaceGlobals_t const char* m_pInterfaceName; InterfaceGlobals_t* m_pNextInterfacePtr; }; +//----------------------------------------------------------------------------- struct FactoryInfo { ADDRESS m_pFactoryPtr; - std::string m_szFactoryFullName; - std::string m_szFactoryName; - std::string m_szFactoryVersion; + string m_szFactoryFullName; + string m_szFactoryName; + string m_szFactoryVersion; - FactoryInfo() : m_szFactoryFullName(std::string()), m_szFactoryName(std::string()), m_szFactoryVersion(std::string()), m_pFactoryPtr(nullptr) {} - FactoryInfo(std::string factoryFullName, std::string factoryName, std::string factoryVersion, std::uintptr_t factoryPtr) : m_szFactoryFullName(factoryFullName), m_szFactoryName(factoryName), m_szFactoryVersion(factoryVersion), m_pFactoryPtr(factoryPtr) {} - FactoryInfo(std::string factoryFullName, std::uintptr_t factoryPtr) : m_szFactoryFullName(factoryFullName), m_szFactoryName(std::string()), m_szFactoryVersion(std::string()), m_pFactoryPtr(factoryPtr) {} + FactoryInfo() : m_szFactoryFullName(string()), m_szFactoryName(string()), m_szFactoryVersion(string()), m_pFactoryPtr(nullptr) {} + FactoryInfo(string factoryFullName, string factoryName, string factoryVersion, uintptr_t factoryPtr) : + m_szFactoryFullName(factoryFullName), m_szFactoryName(factoryName), m_szFactoryVersion(factoryVersion), m_pFactoryPtr(factoryPtr) {} + FactoryInfo(string factoryFullName, uintptr_t factoryPtr) : + m_szFactoryFullName(factoryFullName), m_szFactoryName(string()), m_szFactoryVersion(string()), m_pFactoryPtr(factoryPtr) {} }; //----------------------------------------------------------------------------- // Class to hold all factories (interfaces) //----------------------------------------------------------------------------- -class IFactory +class CFactory { public: - - void GetFactoriesFromRegister(); + void AddFactory(const string& svFactoryName, void* pFactory); void AddFactory(FactoryInfo factoryInfo); - ADDRESS GetFactoryPtr(const std::string& factoryName, bool versionLess = true); + int GetVersionIndex(const string& svInterfaceName) const; + void GetFactoriesFromRegister(void); + ADDRESS GetFactoryPtr(const string& factoryName, bool versionLess = true) const; - std::vector factories = {}; +private: + vector m_vFactories; }; -extern IFactory* g_pFactory; +extern CFactory* g_pFactory; namespace { /* ==== s_pInterfaceRegs ==================================================================================================================================================== */ - InterfaceGlobals_t* s_pInterfacesRegs = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\xE9\x00\x00\x00\x00\xCC\xCC\x89\x91\x00\x00\x00\x00", "x????xxxx????").FollowNearCallSelf().FindPatternSelf("48 8B 1D", ADDRESS::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).DerefSelf().RCast(); + ADDRESS s_pInterfacesRegs = g_mGameDll.FindPatternSIMD(reinterpret_cast("\xE9\x00\x00\x00\x00\xCC\xCC\x89\x91\x00\x00\x00\x00"), "x????xxxx????") + .FollowNearCallSelf().FindPatternSelf("48 8B 1D", ADDRESS::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7); } /////////////////////////////////////////////////////////////////////////////// @@ -53,7 +99,7 @@ class HFactory : public IDetour { virtual void debugp() { - std::cout << "| VAR: s_pInterfacesRegs : 0x" << std::hex << std::uppercase << s_pInterfacesRegs << std::setw(0) << " |" << std::endl; + std::cout << "| VAR: s_pInterfacesRegs : 0x" << std::hex << std::uppercase << s_pInterfacesRegs.GetPtr() << std::setw(npad) << " |" << std::endl; std::cout << "+----------------------------------------------------------------+" << std::endl; } }; diff --git a/r5dev/vpklib/packedstore.cpp b/r5dev/vpklib/packedstore.cpp index 31d41f0f..c7791cf0 100644 --- a/r5dev/vpklib/packedstore.cpp +++ b/r5dev/vpklib/packedstore.cpp @@ -37,14 +37,14 @@ void CPackedStore::InitLzDecompParams(void) //----------------------------------------------------------------------------- // Purpose: obtains archive chunk path for specific file //----------------------------------------------------------------------------- -std::string CPackedStore::GetPackChunkFile(std::string svPackDirFile, int iArchiveIndex) +string CPackedStore::GetPackChunkFile(string svPackDirFile, int iArchiveIndex) { /*| ARCHIVES ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ - std::string svPackChunkFile = StripLocalePrefix(svPackDirFile); - std::ostringstream oss; + string svPackChunkFile = StripLocalePrefix(svPackDirFile); + ostringstream oss; oss << std::setw(3) << std::setfill('0') << iArchiveIndex; - std::string svPackChunkIndex = "pak000_" + oss.str(); + string svPackChunkIndex = "pak000_" + oss.str(); StringReplace(svPackChunkFile, "pak000_dir", svPackChunkIndex); return svPackChunkFile; @@ -53,7 +53,7 @@ std::string CPackedStore::GetPackChunkFile(std::string svPackDirFile, int iArchi //----------------------------------------------------------------------------- // Purpose: returns populated pack dir struct for specified pack dir file //----------------------------------------------------------------------------- -vpk_dir_h CPackedStore::GetPackDirFile(std::string svPackDirFile) +VPKDir_t CPackedStore::GetPackDirFile(string svPackDirFile) { /*| PACKDIRFILE |||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ std::regex rgArchiveRegex("pak000_([0-9]{3})"); @@ -73,7 +73,7 @@ vpk_dir_h CPackedStore::GetPackDirFile(std::string svPackDirFile) { if (strstr(svPackDirFile.c_str(), DIR_LIBRARY_PREFIX[j].c_str())) { - std::string svPackDirPrefix = DIR_LOCALE_PREFIX[i] + DIR_LOCALE_PREFIX[i]; + string svPackDirPrefix = DIR_LOCALE_PREFIX[i] + DIR_LOCALE_PREFIX[i]; StringReplace(svPackDirFile, DIR_LOCALE_PREFIX[i].c_str(), svPackDirPrefix.c_str()); goto escape; } @@ -82,26 +82,26 @@ vpk_dir_h CPackedStore::GetPackDirFile(std::string svPackDirFile) }escape:; } - vpk_dir_h vpk_dir(svPackDirFile); + VPKDir_t vpk_dir(svPackDirFile); return vpk_dir; } //----------------------------------------------------------------------------- // Purpose: obtains and returns the entry block to the vector //----------------------------------------------------------------------------- -std::vector CPackedStore::GetEntryBlocks(CIOStream* reader) +vector CPackedStore::GetEntryBlocks(CIOStream* reader) { /*| ENTRYBLOCKS |||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ - std::string svName, svPath, svExtension; - std::vector vBlocks; + string svName, svPath, svExtension; + vector vBlocks; while (!(svExtension = reader->readString()).empty()) { while (!(svPath = reader->readString()).empty()) { while (!(svName = reader->readString()).empty()) { - std::string svFilePath = FormatBlockPath(svName, svPath, svExtension); - vBlocks.push_back(vpk_entry_block(reader, svFilePath)); + string svFilePath = FormatBlockPath(svName, svPath, svExtension); + vBlocks.push_back(VPKEntryBlock_t(reader, svFilePath)); } } } @@ -111,7 +111,7 @@ std::vector CPackedStore::GetEntryBlocks(CIOStream* reader) //----------------------------------------------------------------------------- // Purpose: formats the entry block path //----------------------------------------------------------------------------- -std::string CPackedStore::FormatBlockPath(std::string svName, std::string svPath, std::string svExtension) +string CPackedStore::FormatBlockPath(string svName, string svPath, string svExtension) { if (!svPath.empty()) { @@ -123,10 +123,10 @@ std::string CPackedStore::FormatBlockPath(std::string svName, std::string svPath //----------------------------------------------------------------------------- // Purpose: strips locale prefix from file path //----------------------------------------------------------------------------- -std::string CPackedStore::StripLocalePrefix(std::string svPackDirFile) +string CPackedStore::StripLocalePrefix(string svPackDirFile) { std::filesystem::path fspPackDirFile(svPackDirFile); - std::string svFileName = fspPackDirFile.filename().u8string(); + string svFileName = fspPackDirFile.filename().u8string(); for (int i = 0; i < LANGUAGE_PACKS; i++) { @@ -142,14 +142,14 @@ std::string CPackedStore::StripLocalePrefix(std::string svPackDirFile) //----------------------------------------------------------------------------- // Purpose: validates extraction result with precomputed ADLER32 hash //----------------------------------------------------------------------------- -void CPackedStore::ValidateAdler32PostDecomp(std::string svAssetFile) +void CPackedStore::ValidateAdler32PostDecomp(string svAssetFile) { uint32_t adler_init = {}; - std::ifstream istream(svAssetFile, std::fstream::binary); + ifstream istream(svAssetFile, fstream::binary); - istream.seekg(0, std::fstream::end); + istream.seekg(0, fstream::end); m_vHashBuffer.resize(istream.tellg()); - istream.seekg(0, std::fstream::beg); + istream.seekg(0, fstream::beg); istream.read((char*)m_vHashBuffer.data(), m_vHashBuffer.size()); m_nAdler32 = adler32::update(adler_init, m_vHashBuffer.data(), m_vHashBuffer.size()); @@ -168,14 +168,14 @@ void CPackedStore::ValidateAdler32PostDecomp(std::string svAssetFile) //----------------------------------------------------------------------------- // Purpose: validates extraction result with precomputed CRC32 hash //----------------------------------------------------------------------------- -void CPackedStore::ValidateCRC32PostDecomp(std::string svDirAsset) +void CPackedStore::ValidateCRC32PostDecomp(string svDirAsset) { uint32_t crc32_init = {}; - std::ifstream istream(svDirAsset, std::fstream::binary); + ifstream istream(svDirAsset, fstream::binary); - istream.seekg(0, std::fstream::end); + istream.seekg(0, fstream::end); m_vHashBuffer.resize(istream.tellg()); - istream.seekg(0, std::fstream::beg); + istream.seekg(0, fstream::beg); istream.read((char*)m_vHashBuffer.data(), m_vHashBuffer.size()); m_nCrc32 = crc32::update(crc32_init, m_vHashBuffer.data(), m_vHashBuffer.size()); @@ -194,29 +194,29 @@ void CPackedStore::ValidateCRC32PostDecomp(std::string svDirAsset) //----------------------------------------------------------------------------- // Purpose: extracts all files from specified vpk file //----------------------------------------------------------------------------- -void CPackedStore::UnpackAll(vpk_dir_h vpk_dir, std::string svPathOut) +void CPackedStore::UnpackAll(VPKDir_t vpk_dir, string svPathOut) { for (int i = 0; i < vpk_dir.m_vsvArchives.size(); i++) { std::filesystem::path fspVpkPath(vpk_dir.m_svDirPath); - std::string svPath = fspVpkPath.parent_path().u8string() + "\\" + vpk_dir.m_vsvArchives[i]; - std::ifstream packChunkStream(svPath, std::ios_base::binary); // Create stream to read from each archive. + string svPath = fspVpkPath.parent_path().u8string() + "\\" + vpk_dir.m_vsvArchives[i]; + ifstream packChunkStream(svPath, std::ios_base::binary); // Create stream to read from each archive. - for ( vpk_entry_block block : vpk_dir.m_vvEntryBlocks) + for ( VPKEntryBlock_t block : vpk_dir.m_vvEntryBlocks) { // Escape if block archive index is not part of the extracting archive chunk index. if (block.m_iArchiveIndex != i) { goto escape; } else { - std::string svFilePath = CreateDirectories(svPathOut + "\\" + block.m_svBlockPath); - std::ofstream outFileStream(svFilePath, std::ios_base::binary | std::ios_base::out); + string svFilePath = CreateDirectories(svPathOut + "\\" + block.m_svBlockPath); + ofstream outFileStream(svFilePath, std::ios_base::binary | std::ios_base::out); if (!outFileStream.is_open()) { Error(eDLL_T::FS, "Error: unable to access file '%s'!\n", svFilePath.c_str()); } outFileStream.clear(); // Make sure file is empty before writing. - for (vpk_entry_h entry : block.m_vvEntries) + for (VPKEntryDescr_t entry : block.m_vvEntries) { char* pCompressedData = new char[entry.m_nCompressedSize]; memset(pCompressedData, 0, entry.m_nCompressedSize); // Compressed region. @@ -288,7 +288,7 @@ void CPackedStore::UnpackAll(vpk_dir_h vpk_dir, std::string svPathOut) //----------------------------------------------------------------------------- // Purpose: 'vpk_entry_block' constructor //----------------------------------------------------------------------------- -vpk_entry_block::vpk_entry_block(CIOStream* reader, std::string svPath) +VPKEntryBlock_t::VPKEntryBlock_t(CIOStream* reader, string svPath) { std::replace(svPath.begin(), svPath.end(), '/', '\\'); // Flip forward slashes in filepath to windows-style backslash. @@ -299,7 +299,7 @@ vpk_entry_block::vpk_entry_block(CIOStream* reader, std::string svPath) do // Loop through all entries in the block and push them to the vector. { - vpk_entry_h entry(reader); + VPKEntryDescr_t entry(reader); this->m_vvEntries.push_back(entry); } while (reader->readR() != 65535); } @@ -307,7 +307,7 @@ vpk_entry_block::vpk_entry_block(CIOStream* reader, std::string svPath) //----------------------------------------------------------------------------- // Purpose: 'vpk_entry_h' constructor //----------------------------------------------------------------------------- -vpk_entry_h::vpk_entry_h(CIOStream* reader) +VPKEntryDescr_t::VPKEntryDescr_t(CIOStream* reader) { reader->read(this->m_nEntryFlags); // reader->read(this->m_nTextureFlags); // @@ -320,7 +320,7 @@ vpk_entry_h::vpk_entry_h(CIOStream* reader) //----------------------------------------------------------------------------- // Purpose: 'vpk_dir_h' constructor //----------------------------------------------------------------------------- -vpk_dir_h::vpk_dir_h(std::string svPath) +VPKDir_t::VPKDir_t(string svPath) { CIOStream reader; @@ -349,7 +349,7 @@ vpk_dir_h::vpk_dir_h(std::string svPath) this->m_vvEntryBlocks = g_pPackedStore->GetEntryBlocks(&reader); this->m_svDirPath = svPath; // Set path to vpk_dir file. - for (vpk_entry_block block : this->m_vvEntryBlocks) + for (VPKEntryBlock_t block : this->m_vvEntryBlocks) { if (block.m_iArchiveIndex > this->m_iArchiveCount) { @@ -362,7 +362,7 @@ vpk_dir_h::vpk_dir_h(std::string svPath) for (int i = 0; i < this->m_iArchiveCount + 1; i++) { - std::string svArchivePath = g_pPackedStore->GetPackChunkFile(svPath, i); + string svArchivePath = g_pPackedStore->GetPackChunkFile(svPath, i); DevMsg(eDLL_T::FS, "] '%s'\n", svArchivePath.c_str()); this->m_vsvArchives.push_back(svArchivePath); } diff --git a/r5dev/vpklib/packedstore.h b/r5dev/vpklib/packedstore.h index bd9194f5..82313f2c 100644 --- a/r5dev/vpklib/packedstore.h +++ b/r5dev/vpklib/packedstore.h @@ -10,7 +10,28 @@ constexpr unsigned int RVPK_DIR_MAGIC = 'U const std::string DIR_LIBRARY_PREFIX[LIBRARY_PACKS] = { "server", "client" }; const std::string DIR_LOCALE_PREFIX[LANGUAGE_PACKS] = { "english", "french", "german", "italian", "japanese", "korean", "polish", "portuguese", "russian", "spanish", "tchinese" }; -struct vpk_entry_h +#pragma pack(push, 1) +struct VPKFileEntry_t +{ + char* directory; + char* filename; + char* extension; + uint8_t unknown[0x38]; +}; + +struct VPKData_t +{ + int m_nHandle; + char pad[1]; + char m_szPath[255]; + uint8_t unknown2[0x134]; + int32_t m_nEntries; + uint8_t unknown3[12]; + VPKFileEntry_t* m_pEntries; +}; +#pragma pack(pop) + +struct VPKEntryDescr_t { uint32_t m_nEntryFlags {}; // Entry flags. uint16_t m_nTextureFlags {}; // Texture flags (only used if the entry is a vtf). @@ -19,39 +40,39 @@ struct vpk_entry_h uint64_t m_nUncompressedSize{}; // Uncompressed size of entry. bool m_bIsCompressed = false; - vpk_entry_h(CIOStream* reader); + VPKEntryDescr_t(CIOStream* reader); }; -struct vpk_entry_block +struct VPKEntryBlock_t { uint32_t m_nCrc32 {}; // Crc32 for the uncompressed block. uint16_t m_nPreloadBytes{}; // Preload bytes. uint16_t m_iArchiveIndex{}; // Index of the archive that contains this block. - std::vector m_vvEntries {}; // Vector of all the entries of a given block (entries have a size limit of 1 MiB, so anything over is split into separate entries within the same block). - std::string m_svBlockPath {}; // Path to block within vpk. + vector m_vvEntries {}; // Vector of all the entries of a given block (entries have a size limit of 1 MiB, so anything over is split into separate entries within the same block). + string m_svBlockPath {}; // Path to block within vpk. - vpk_entry_block(CIOStream* reader, std::string path); + VPKEntryBlock_t(CIOStream* reader, string path); }; -struct vpk_dir_h +struct VPKDir_t { uint32_t m_nFileMagic {}; // File magic. uint16_t m_nMajorVersion{}; // Vpk major version. uint16_t m_nMinorVersion{}; // Vpk minor version. uint32_t m_nTreeSize {}; // Directory tree size. uint32_t m_nFileDataSize{}; // File data section size. - std::vector m_vvEntryBlocks{}; // Vector of entry blocks. + vector m_vvEntryBlocks{}; // Vector of entry blocks. uint16_t m_iArchiveCount{}; // Highest archive index (archive count-1). - std::vector m_vsvArchives {}; // Vector of archive file names. - std::string m_svDirPath {}; // Path to vpk_dir file. + vector m_vsvArchives {}; // Vector of archive file names. + string m_svDirPath {}; // Path to vpk_dir file. - vpk_dir_h(std::string path); + VPKDir_t(string path); }; class CPackedStore { - std::vector m_vHashBuffer {}; // Buffer for post decomp file validation. - std::size_t m_nEntryCount {}; // Entry per-block incrementor. + vector m_vHashBuffer {}; // Buffer for post decomp file validation. + size_t m_nEntryCount {}; // Entry per-block incrementor. lzham_uint32 m_nAdler32_Internal{}; // Internal operation Adler32 file checksum. lzham_uint32 m_nAdler32 {}; // Pre/post operation Adler32 file checksum. lzham_uint32 m_nCrc32_Internal {}; // Internal operation Crc32 file checksum. @@ -64,14 +85,14 @@ class CPackedStore public: void InitLzCompParams(void); void InitLzDecompParams(void); - vpk_dir_h GetPackDirFile(std::string svPackDirFile); - std::string GetPackChunkFile(std::string svPackDirFile, int iArchiveIndex); - std::vector GetEntryBlocks(CIOStream* reader); - std::string FormatBlockPath(std::string svName, std::string svPath, std::string svExtension); - std::string StripLocalePrefix(std::string svPackDirFile); - void UnpackAll(vpk_dir_h vpk, std::string svPathOut = ""); - void ValidateAdler32PostDecomp(std::string svDirAsset); - void ValidateCRC32PostDecomp(std::string svDirAsset); + VPKDir_t GetPackDirFile(string svPackDirFile); + string GetPackChunkFile(string svPackDirFile, int iArchiveIndex); + vector GetEntryBlocks(CIOStream* reader); + string FormatBlockPath(string svName, string svPath, string svExtension); + string StripLocalePrefix(string svPackDirFile); + void UnpackAll(VPKDir_t vpk, string svPathOut = ""); + void ValidateAdler32PostDecomp(string svDirAsset); + void ValidateCRC32PostDecomp(string svDirAsset); }; /////////////////////////////////////////////////////////////////////////////// extern CPackedStore* g_pPackedStore; diff --git a/r5dev/vproj/clientsdk.vcxproj b/r5dev/vproj/clientsdk.vcxproj index 6fa7c52a..4ba61bf5 100644 --- a/r5dev/vproj/clientsdk.vcxproj +++ b/r5dev/vproj/clientsdk.vcxproj @@ -40,6 +40,8 @@ + + @@ -87,7 +89,6 @@ - @@ -109,6 +110,7 @@ + @@ -135,6 +137,8 @@ + + @@ -337,7 +341,6 @@ - diff --git a/r5dev/vproj/clientsdk.vcxproj.filters b/r5dev/vproj/clientsdk.vcxproj.filters index 7478b085..a5341f3e 100644 --- a/r5dev/vproj/clientsdk.vcxproj.filters +++ b/r5dev/vproj/clientsdk.vcxproj.filters @@ -163,6 +163,9 @@ {0b043c41-b53e-44f5-9cbe-7501fcf22478} + + {a61ad720-d7da-4aee-a9ca-f87f827423ea} + @@ -246,9 +249,6 @@ sdk\vpc - - sdk\vpc - sdk\vphysics @@ -396,6 +396,12 @@ sdk\client + + sdk\filesystem + + + sdk\filesystem + @@ -833,9 +839,6 @@ sdk\vpc - - sdk\vpc - sdk\vphysics @@ -1142,6 +1145,15 @@ sdk\game\client + + sdk\filesystem + + + sdk\filesystem + + + sdk\common + diff --git a/r5dev/vproj/dedicated.vcxproj b/r5dev/vproj/dedicated.vcxproj index 29b65d1c..86665ecf 100644 --- a/r5dev/vproj/dedicated.vcxproj +++ b/r5dev/vproj/dedicated.vcxproj @@ -130,6 +130,7 @@ + @@ -155,6 +156,8 @@ + + @@ -342,7 +345,6 @@ - @@ -379,6 +381,8 @@ + + @@ -422,7 +426,6 @@ - diff --git a/r5dev/vproj/dedicated.vcxproj.filters b/r5dev/vproj/dedicated.vcxproj.filters index 62ebde8d..8ca456dc 100644 --- a/r5dev/vproj/dedicated.vcxproj.filters +++ b/r5dev/vproj/dedicated.vcxproj.filters @@ -136,6 +136,9 @@ {3e3725c1-9a0d-44c7-86dc-8e146bb38eca} + + {ac641995-20c7-43a8-ae66-809b349b1de7} + @@ -534,9 +537,6 @@ sdk\vpc - - sdk\vpc - sdk\vphysics @@ -828,6 +828,15 @@ sdk\client + + sdk\filesystem + + + sdk\filesystem + + + sdk\common + @@ -902,9 +911,6 @@ sdk\vpc - - sdk\vpc - sdk\vphysics @@ -1037,6 +1043,12 @@ sdk\game\server + + sdk\filesystem + + + sdk\filesystem + diff --git a/r5dev/vproj/gamesdk.vcxproj b/r5dev/vproj/gamesdk.vcxproj index d4d4d138..bf708eed 100644 --- a/r5dev/vproj/gamesdk.vcxproj +++ b/r5dev/vproj/gamesdk.vcxproj @@ -42,6 +42,8 @@ + + @@ -95,7 +97,6 @@ - @@ -117,6 +118,7 @@ + @@ -145,6 +147,8 @@ + + @@ -356,7 +360,6 @@ - diff --git a/r5dev/vproj/gamesdk.vcxproj.filters b/r5dev/vproj/gamesdk.vcxproj.filters index 02147ef0..26710028 100644 --- a/r5dev/vproj/gamesdk.vcxproj.filters +++ b/r5dev/vproj/gamesdk.vcxproj.filters @@ -169,6 +169,9 @@ {be813705-b786-4439-b785-eff6bb5f194f} + + {9fbd3a16-56a4-4794-bfa6-680f41002c24} + @@ -258,9 +261,6 @@ sdk\vpc - - sdk\vpc - sdk\vphysics @@ -426,6 +426,12 @@ sdk\game\server + + sdk\filesystem + + + sdk\filesystem + @@ -869,9 +875,6 @@ sdk\vpc - - sdk\vpc - sdk\vphysics @@ -1205,6 +1208,15 @@ sdk\game\client + + sdk\filesystem + + + sdk\filesystem + + + core +