Use KeyValues system for level settings file instead

Previously we used Json, however the rest of the game features KeyValues. I changed the system to feature KeyValues instead, to maintain consistency. Also improved the logic behind loading/parsing so we don't reparse the same level settings file if the pointer is still valid and we are on the same level.
This commit is contained in:
Kawe Mazidjatari 2022-11-24 11:10:46 +01:00
parent d3b2893cdc
commit a7c33d4df3
4 changed files with 74 additions and 79 deletions

View File

@ -10,6 +10,7 @@
#include "tier0/jobthread.h"
#include "engine/sys_dll2.h"
#include "engine/host_cmd.h"
#include "engine/host_state.h"
#include "engine/cmodel_bsp.h"
#include "rtech/rtech_utils.h"
#include "rtech/rtech_game.h"
@ -17,18 +18,20 @@
#include "datacache/mdlcache.h"
#include "filesystem/filesystem.h"
string g_svLevelName;
vector<string> g_vAllMaps;
string s_svLevelName;
bool s_bLevelResourceInitialized = false;
bool s_bBasePaksInitialized = false;
KeyValues* s_pLevelSetKV = nullptr;
//-----------------------------------------------------------------------------
// Purpose: checks if level has changed
// Input : &svLevelName -
// Input : *pszLevelName -
// Output : true if level name deviates from previous level
//-----------------------------------------------------------------------------
bool MOD_LevelHasChanged(const string& svLevelName)
bool MOD_LevelHasChanged(const char* pszLevelName)
{
return (g_svLevelName.compare(svLevelName) != 0);
return (s_svLevelName.compare(pszLevelName) != 0);
}
//-----------------------------------------------------------------------------
@ -240,6 +243,9 @@ void MOD_ProcessPakQueue()
g_pakLoadApi->UnloadPak(*(RPakHandle_t*)v10);
MOD_UnloadPakFile(); // Unload mod pak files.
s_pLevelSetKV->DeleteThis(); // Delete current level settings if we drop all paks..
s_pLevelSetKV = nullptr;
}
if (v13 && (unsigned int)(v13 - 13) > 1)
return;
@ -315,7 +321,7 @@ void MOD_ProcessPakQueue()
if (s_bBasePaksInitialized && !s_bLevelResourceInitialized)
{
s_bLevelResourceInitialized = true;
MOD_PreloadPakFile(g_svLevelName);
MOD_PreloadLevelPaks(g_pHostState->m_levelName);
}
*(_DWORD*)v15 = g_pakLoadApi->LoadAsync(v17, g_pMallocPool.GetPtr(), 4, 0);
@ -352,60 +358,65 @@ bool MOD_LoadPakForMap(const char* szLevelName)
if (MOD_LevelHasChanged(szLevelName))
s_bLevelResourceInitialized = false;
g_svLevelName = szLevelName;
s_svLevelName = szLevelName;
return v_MOD_LoadPakForMap(szLevelName);
}
//-----------------------------------------------------------------------------
// Purpose: loads required pakfile assets for specified BSP
// Purpose: loads the level settings file, returns current if level hasn't changed.
// Input : *pszLevelName -
// Output : KeyValues*
//-----------------------------------------------------------------------------
KeyValues* MOD_GetLevelSettings(const char* pszLevelName)
{
if (s_pLevelSetKV)
{
if (!MOD_LevelHasChanged(pszLevelName))
{
return s_pLevelSetKV;
}
s_pLevelSetKV->DeleteThis();
}
char szPathBuffer[MAX_PATH];
snprintf(szPathBuffer, sizeof(szPathBuffer), "scripts/levels/settings/%s.kv", pszLevelName);
s_pLevelSetKV = FileSystem()->LoadKeyValues(IFileSystem::TYPE_LEVELSETTINGS, szPathBuffer, "GAME");
return s_pLevelSetKV;
}
//-----------------------------------------------------------------------------
// Purpose: loads required pakfile assets for specified BSP level
// Input : &svSetFile -
//-----------------------------------------------------------------------------
void MOD_PreloadPakFile(const string& svLevelName)
void MOD_PreloadLevelPaks(const char* pszLevelName)
{
ostringstream ostream;
ostream << "scripts/levels/settings/" << svLevelName << ".json";
KeyValues* pSettingsKV = MOD_GetLevelSettings(pszLevelName);
FileHandle_t pFile = FileSystem()->Open(ostream.str().c_str(), "rt");
if (!pFile)
if (!pSettingsKV)
return;
uint32_t nLen = FileSystem()->Size(pFile);
uint8_t* pBuf = MemAllocSingleton()->Alloc<uint8_t>(nLen);
KeyValues* pPakListKV = pSettingsKV->FindKey("PakList");
int nRead = FileSystem()->Read(pBuf, nLen, pFile);
FileSystem()->Close(pFile);
if (!pPakListKV)
return;
pBuf[nRead] = '\0';
char szPathBuffer[MAX_PATH];
try
for (KeyValues* pSubKey = pPakListKV->GetFirstSubKey(); pSubKey != nullptr; pSubKey = pSubKey->GetNextKey())
{
nlohmann::json jsIn = nlohmann::json::parse(pBuf);
if (!jsIn.is_null())
{
if (!jsIn["rpak"].is_null())
{
for (auto& it : jsIn["rpak"])
{
if (it.is_string())
{
string svToLoad = it.get<string>() + ".rpak";
RPakHandle_t nPakId = g_pakLoadApi->LoadAsync(svToLoad.c_str(), g_pMallocPool.GetPtr(), 4, 0);
if (!pSubKey->GetBool())
continue;
if (nPakId == INVALID_PAK_HANDLE)
Error(eDLL_T::ENGINE, NO_ERROR, "%s: unable to load pak '%s' results '%d'\n", __FUNCTION__, svToLoad.c_str(), nPakId);
else
g_vLoadedPakHandle.push_back(nPakId);
}
}
}
}
}
catch (const std::exception& ex)
{
Warning(eDLL_T::RTECH, "Exception while parsing RPak load list: '%s'\n", ex.what());
}
snprintf(szPathBuffer, sizeof(szPathBuffer), "%s.rpak", pSubKey->GetName());
RPakHandle_t nPakId = g_pakLoadApi->LoadAsync(szPathBuffer, g_pMallocPool.GetPtr(), 4, 0);
MemAllocSingleton()->Free(pBuf);
if (nPakId == INVALID_PAK_HANDLE)
Error(eDLL_T::ENGINE, NO_ERROR, "%s: unable to load pak '%s' results '%d'\n", __FUNCTION__, szPathBuffer, nPakId);
else
g_vLoadedPakHandle.push_back(nPakId);
}
}
//-----------------------------------------------------------------------------

View File

@ -1,6 +1,11 @@
#pragma once
#include "tier0/jobthread.h"
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
class KeyValues;
inline CMemory p_MOD_LoadPakForMap;
inline auto v_MOD_LoadPakForMap = p_MOD_LoadPakForMap.RCast<bool(*)(const char* szLevelName)>();
@ -24,12 +29,12 @@ inline auto sub_14045A1D0 = p_MOD_ProcessPakQueue.RCast<__int64(*)(unsigned __in
inline auto sub_140441220 = p_MOD_ProcessPakQueue.RCast<void(*)(__int64 a1, __int64 a2)>();
extern bool s_bBasePaksInitialized;
extern string g_svLevelName;
extern vector<string> g_vAllMaps;
bool MOD_LevelHasChanged(const string& svLevelName);
bool MOD_LevelHasChanged(const char* pszLevelName);
void MOD_GetAllInstalledMaps();
void MOD_PreloadPakFile(const string& svLevelName);
KeyValues* MOD_GetLevelSettings(const char* pszLevelName);
void MOD_PreloadLevelPaks(const char* pszLevelName);
void MOD_UnloadPakFile(void);
void CModelBsp_Attach();

View File

@ -5,8 +5,9 @@
//===========================================================================//
#include "core/stdafx.h"
#include "tier1/cvar.h"
#include "vpc/keyvalues.h"
#include "rtech/rtech_utils.h"
#include "filesystem/filesystem.h"
#include "engine/cmodel_bsp.h"
#include "materialsystem/cmaterialglue.h"
#include "materialsystem/cmaterialsystem.h"
@ -18,46 +19,23 @@
//---------------------------------------------------------------------------------
void StreamDB_Init(const char* pszLevelName)
{
ostringstream ostream;
ostream << "scripts/levels/settings/" << pszLevelName << ".json";
KeyValues* pSettingsKV = MOD_GetLevelSettings(pszLevelName);
FileHandle_t pFile = FileSystem()->Open(ostream.str().c_str(), "rt");
if (pFile)
if (pSettingsKV)
{
uint32_t nLen = FileSystem()->Size(pFile);
uint8_t* pBuf = MemAllocSingleton()->Alloc<uint8_t>(nLen);
KeyValues* pStreamKV = pSettingsKV->FindKey("StreamDB");
int nRead = FileSystem()->Read(pBuf, nLen, pFile);
FileSystem()->Close(pFile);
pBuf[nRead] = '\0';
try
if (pStreamKV)
{
nlohmann::json jsIn = nlohmann::json::parse(pBuf);
if (!jsIn.is_null())
{
if (!jsIn[STREAM_DB_EXT].is_null())
{
string svStreamDBFile = jsIn[STREAM_DB_EXT].get<string>();
DevMsg(eDLL_T::MS, "%s: Loading override STBSP file '%s.%s'\n", __FUNCTION__, svStreamDBFile.c_str(), STREAM_DB_EXT);
const char* pszColumnName = pStreamKV->GetString();
DevMsg(eDLL_T::MS, "%s: Loading override STBSP file '%s.stbsp'\n", __FUNCTION__, pszColumnName);
v_StreamDB_Init(svStreamDBFile.c_str());
MemAllocSingleton()->Free(pBuf);
return;
}
}
v_StreamDB_Init(pszColumnName);
return;
}
catch (const std::exception& ex)
{
Warning(eDLL_T::MS, "%s: Exception while parsing STBSP override:\n%s\n", __FUNCTION__, ex.what());
}
MemAllocSingleton()->Free(pBuf);
}
DevMsg(eDLL_T::MS, "%s: Loading STBSP file '%s.%s'\n", __FUNCTION__, pszLevelName, STREAM_DB_EXT);
DevMsg(eDLL_T::MS, "%s: Loading STBSP file '%s.stbsp'\n", __FUNCTION__, pszLevelName);
v_StreamDB_Init(pszLevelName);
}

View File

@ -364,6 +364,7 @@ public:
TYPE_SOUNDEMITTER,
TYPE_SOUNDSCAPE,
TYPE_SOUNDOPERATORS,
TYPE_LEVELSETTINGS,
TYPE_COMMON,
NUM_PRELOAD_TYPES
};