r5sdk/r5dev/filesystem/basefilesystem.cpp
Kawe Mazidjatari 609d705a0c Tier1: static construction of ConVar objects during link time
Fully implemented ConVar class so we could statically construct all SDK convars, this avoids a level of indirection, and allows for creating ConVar's everywhere in the project.

This patch also removed the settings tab of the ImGui server browser, as it has threading issues, while it technically never caused a crash yet, it has been removed as there was no point keeping it vs the work required to make it thread save (it only managed 2 convars which are perfectly manageable through cfg's or the in-game console).

Also temporarily disabled the creation of ConVar's in the mod system due to a memory leak, we would allocate and register a convar based on details parsed out of a mod file definition, but never unregister and free it.
2024-04-05 18:13:32 +02:00

216 lines
7.3 KiB
C++

#include "core/stdafx.h"
#include "tier1/cvar.h"
#include "filesystem/basefilesystem.h"
#include "filesystem/filesystem.h"
#include "bspfile.h"
#include "engine/modelloader.h"
static ConVar fs_showWarnings("fs_showWarnings", "0", FCVAR_DEVELOPMENTONLY, "Logs the FileSystem warnings to the console, filtered by 'fs_warning_level' ( !slower! ).", true, 0.f, true, 2.f, "0 = log to file. 1 = 0 + log to console. 2 = 1 + log to notify");
//---------------------------------------------------------------------------------
// 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 (level >= FileWarningLevel_t::FILESYSTEM_WARNING_REPORTALLACCESSES)
{
// Logging reads are very verbose! Explicitly toggle..
if (!fs_showAllReads->GetBool())
{
return;
}
}
va_list args;
va_start(args, pFmt);
CoreMsgV(LogType_t::LOG_WARNING, static_cast<LogLevel_t>(fs_showWarnings.GetInt()), eDLL_T::FS, "filesystem", pFmt, args);
va_end(args);
}
//---------------------------------------------------------------------------------
// Purpose: attempts to load files from disk if exist before loading from VPK/cache
// Input : *pszFilePath -
// Output : handle to file on success, NULL on failure
//---------------------------------------------------------------------------------
bool CBaseFileSystem::VCheckDisk(const char* pszFilePath)
{
// Only load material files from the disk if the mode isn't zero,
// use -novpk to load valve materials from the disk.
if (FileSystem()->CheckVPKMode(0) && V_strstr(pszFilePath, ".vmt"))
{
return false;
}
if (V_IsAbsolutePath(pszFilePath))
{
// Skip absolute file paths.
return false;
}
CUtlString filePath;
filePath.Format("platform/%s", pszFilePath);
filePath.FixSlashes();
filePath = filePath.Replace("\\*\\", "");
if (::FileExists(filePath.Get()))
{
return true;
}
return false;
}
//---------------------------------------------------------------------------------
// Purpose: loads files from VPK
// Input : *this -
// *pResults -
// *pszFilePath -
// Output : handle to file on success, NULL on failure
//---------------------------------------------------------------------------------
FileHandle_t CBaseFileSystem::VReadFromVPK(CBaseFileSystem* pFileSystem, FileHandle_t pResults, const char* pszFilePath)
{
if (VCheckDisk(pszFilePath))
{
*reinterpret_cast<int64_t*>(pResults) = -1;
return pResults;
}
return CBaseFileSystem__LoadFromVPK(pFileSystem, pResults, pszFilePath);
}
//---------------------------------------------------------------------------------
// Purpose: loads files from cache
// Input : *this -
// *pszFilePath -
// *pCache -
// Output : true if file exists, false otherwise
//---------------------------------------------------------------------------------
bool CBaseFileSystem::VReadFromCache(CBaseFileSystem* pFileSystem, const char* pszFilePath, FileSystemCache* pCache)
{
if (VCheckDisk(pszFilePath))
{
return false;
}
bool result = CBaseFileSystem__LoadFromCache(pFileSystem, pszFilePath, pCache);
return result;
}
//---------------------------------------------------------------------------------
// Purpose: mounts a BSP packfile lump as search path
// Input : *this -
// *pPath -
// *pPathID -
// *addType -
//---------------------------------------------------------------------------------
void CBaseFileSystem::VAddMapPackFile(CBaseFileSystem* pFileSystem, const char* pPath, const char* pPathID, SearchPathAdd_t addType)
{
// Since the mounting of the packfile lump is performed before the BSP header
// is loaded and parsed, we have to do it here. The internal 'AddMapPackFile'
// function has been patched to load the fields in the global 's_MapHeader'
// field, instead of the one that is getting initialized (see r5apex.patch).
if (s_MapHeader->ident != IDBSPHEADER || s_MapHeader->version != BSPVERSION)
{
FileHandle_t hBspFile = FileSystem()->Open(pPath, "rb", pPathID);
if (hBspFile != FILESYSTEM_INVALID_HANDLE)
{
memset(s_MapHeader, '\0', sizeof(BSPHeader_t));
FileSystem()->Read(s_MapHeader, sizeof(BSPHeader_t), hBspFile);
}
}
// If a lump exists, replace the path pointer with that of the lump so that
// the internal function loads this instead.
char lumpPathBuf[MAX_PATH];
V_snprintf(lumpPathBuf, sizeof(lumpPathBuf), "%s.%.4X.bsp_lump", pPath, LUMP_PAKFILE);
if (FileSystem()->FileExists(lumpPathBuf, pPathID))
{
pPath = lumpPathBuf;
}
CBaseFileSystem__AddMapPackFile(pFileSystem, pPath, pPathID, addType);
}
//---------------------------------------------------------------------------------
// Purpose: attempts to mount VPK file for filesystem usage
// Input : *this -
// *pszVpkPath -
// Output : pointer to VPK on success, NULL on failure
//---------------------------------------------------------------------------------
VPKData_t* CBaseFileSystem::VMountVPKFile(CBaseFileSystem* pFileSystem, const char* pszVpkPath)
{
int nHandle = CBaseFileSystem__GetMountedVPKHandle(pFileSystem, pszVpkPath);
VPKData_t* pPakData = CBaseFileSystem__MountVPKFile(pFileSystem, pszVpkPath);
if (pPakData)
{
if (nHandle < 0) // Only log if VPK hasn't been mounted yet.
{
::Msg(eDLL_T::FS, "Mounted vpk file: '%s' with handle: '%i'\n", pszVpkPath, pPakData->m_nHandle);
}
}
else // VPK failed to load or does not exist...
{
::Warning(eDLL_T::FS, "Unable to mount vpk file: '%s'\n", pszVpkPath);
}
return pPakData;
}
//---------------------------------------------------------------------------------
// Purpose: unmount a VPK file
// Input : *this -
// *pszVpkPath -
// Output : pointer to formatted VPK path string
//---------------------------------------------------------------------------------
const char* CBaseFileSystem::VUnmountVPKFile(CBaseFileSystem* pFileSystem, const char* pszVpkPath)
{
int nHandle = CBaseFileSystem__GetMountedVPKHandle(pFileSystem, pszVpkPath);
const char* pRet = CBaseFileSystem__UnmountVPKFile(pFileSystem, pszVpkPath);
if (nHandle >= 0)
{
::Msg(eDLL_T::FS, "Unmounted vpk file: '%s' with handle: '%i'\n", pszVpkPath, nHandle);
}
return pRet;
}
//---------------------------------------------------------------------------------
// Purpose: reads a string until its null terminator
// Input : *pFile -
// Output : string
//---------------------------------------------------------------------------------
CUtlString CBaseFileSystem::ReadString(FileHandle_t pFile)
{
CUtlString result;
char c = '\0';
do
{
Read(&c, sizeof(char), pFile);
if (c)
result += c;
} while (c);
return result;
}
void VBaseFileSystem::Detour(const bool bAttach) const
{
DetourSetup(&CBaseFileSystem__Warning, &CBaseFileSystem::Warning, bAttach);
DetourSetup(&CBaseFileSystem__LoadFromVPK, &CBaseFileSystem::VReadFromVPK, bAttach);
DetourSetup(&CBaseFileSystem__LoadFromCache, &CBaseFileSystem::VReadFromCache, bAttach);
DetourSetup(&CBaseFileSystem__AddMapPackFile, &CBaseFileSystem::VAddMapPackFile, bAttach);
DetourSetup(&CBaseFileSystem__MountVPKFile, &CBaseFileSystem::VMountVPKFile, bAttach);
DetourSetup(&CBaseFileSystem__UnmountVPKFile, &CBaseFileSystem::VUnmountVPKFile, bAttach);
}
CBaseFileSystem* g_pFileSystem = nullptr;