Tier1: move KeyValues class to Tier1

The KeyValues class belongs here. Also reimplemented most loading methods for KeyValues, and adjusted the VPK building code to account for it. Pointers to the engine's implementation of KeyValues have been moved to a separate header ('keyvalues_iface.h'), as this allows external tools code to utilize the standalone KeyValues class implementation. Playlist utilities are completely separated from the KeyValues header; these have nothing to do with KeyValues other than manipulating a global KeyValues object for the playlists, and thus have been named as such and moved to rtech/playlists.
This commit is contained in:
Kawe Mazidjatari 2024-04-05 17:42:05 +02:00
parent 51986ec1c6
commit ee82d5d8e0
41 changed files with 2517 additions and 252 deletions

View File

@ -27,6 +27,7 @@
#endif // !CLIENT_DLL
#include "rtech/rtech_game.h"
#include "rtech/rtech_utils.h"
#include "rtech/playlists/playlists.h"
#include "filesystem/basefilesystem.h"
#include "filesystem/filesystem.h"
#include "vpklib/packedstore.h"
@ -231,7 +232,7 @@ Host_ReloadPlaylists_f
void Host_ReloadPlaylists_f(const CCommand& args)
{
v__DownloadPlaylists_f();
KeyValues::InitPlaylists(); // Re-Init playlist.
Playlists_SDKInit(); // Re-Init playlist.
}
/*
@ -647,7 +648,7 @@ void VPK_Pack_f(const CCommand& args)
Msg(eDLL_T::FS, "*** Starting VPK build command for: '%s'\n", pair.m_DirName.Get());
timer.Start();
g_pPackedStore->InitLzCompParams();
g_pPackedStore->InitLzCompParams(fs_packedstore_compression_level->GetString(), fs_packedstore_max_helper_threads->GetInt());
g_pPackedStore->PackWorkspace(pair, fs_packedstore_workspace->GetString(), "vpk/");
timer.End();

View File

@ -61,6 +61,7 @@ target_link_libraries( ${PROJECT_NAME} PRIVATE
"rtech_tools"
"rtech_game"
"playlists"
"stryder"
"libdetours"

View File

@ -18,8 +18,8 @@
#include "tier0/sigcache.h"
#include "tier1/cmd.h"
#include "tier1/cvar.h"
#include "tier1/keyvalues_iface.h"
#include "vpc/IAppSystem.h"
#include "vpc/keyvalues.h"
#include "vpc/rson.h"
#include "vpc/interfaces.h"
#include "common/callback.h"
@ -63,6 +63,7 @@
#include "rtech/rtech_game.h"
#include "rtech/rtech_utils.h"
#include "rtech/stryder/stryder.h"
#include "rtech/playlists/playlists.h"
#ifndef DEDICATED
#include "rtech/rui/rui.h"
#include "engine/client/cl_ents_parse.h"
@ -552,6 +553,7 @@ void DetourRegister() // Register detour classes to be searched and hooked.
REGISTER(V_RTechGame);
REGISTER(V_RTechUtils);
REGISTER(VStryder);
REGISTER(VPlaylists);
#ifndef DEDICATED
REGISTER(V_Rui);

View File

@ -10,7 +10,7 @@
#include "engine/net_chan.h"
#include "engine/client/cl_rcon.h"
#include "networksystem/bansystem.h"
#include "vpc/keyvalues.h"
#include "tier1/keyvalues.h"
#include "windows/id3dx.h"
#include "geforce/reflex.h"
#include "vengineclient_impl.h"

View File

@ -1,5 +1,5 @@
#pragma once
#include "vpc/keyvalues.h"
#include "tier1/keyvalues.h"
#include "common/protocol.h"
#include "engine/net.h"
#include "engine/net_chan.h"

View File

@ -9,7 +9,6 @@
//
/////////////////////////////////////////////////////////////////////////////////
#include "core/stdafx.h"
#include "vpc/keyvalues.h"
#include "tier0/frametask.h"
#include "engine/common.h"
#include "engine/host.h"
@ -20,6 +19,7 @@
#include "common/callback.h"
#include "cdll_engine_int.h"
#include "vgui/vgui_baseui_interface.h"
#include "rtech/playlists/playlists.h"
#include <ebisusdk/EbisuSDK.h>
#include <engine/cmd.h>
@ -139,7 +139,7 @@ void CClientState::VConnectionClosing(CClientState* thisptr, const char* szReaso
// Reload the local playlist to override the cached
// one from the server we got disconnected from.
v__DownloadPlaylists_f();
KeyValues::InitPlaylists();
Playlists_SDKInit();
}, 0);
}

View File

@ -14,7 +14,7 @@
#include "engine/cmodel_bsp.h"
#include "rtech/rtech_utils.h"
#include "rtech/rtech_game.h"
#include "vpc/keyvalues.h"
#include "tier1/keyvalues.h"
#include "datacache/mdlcache.h"
#include "filesystem/filesystem.h"
#ifndef DEDICATED

View File

@ -25,6 +25,7 @@ inline void(*sub_140441220)(__int64 a1, __int64 a2);
extern bool s_bBasePaksInitialized;
extern CUtlVector<CUtlString> g_InstalledMaps;
extern std::mutex g_InstalledMapsMutex;
bool Mod_LevelHasChanged(const char* pszLevelName);
void Mod_GetAllInstalledMaps();

View File

@ -9,7 +9,7 @@
#ifndef GL_MODEL_PRIVATE_H
#define GL_MODEL_PRIVATE_H
#include "vpc/keyvalues.h"
#include "tier1/keyvalues.h"
#include "mathlib/vector.h"
#include "common/qlimits.h"
#include "datacache/imdlcache.h"

View File

@ -13,7 +13,6 @@
#include "tier1/cvar.h"
#include "tier1/NetAdr.h"
#include "tier2/socketcreator.h"
#include "vpc/keyvalues.h"
#include "datacache/mdlcache.h"
#ifndef CLIENT_DLL
#include "engine/server/sv_rcon.h"
@ -39,6 +38,7 @@
#include "rtech/rtech_game.h"
#include "rtech/rtech_utils.h"
#include "rtech/stryder/stryder.h"
#include "rtech/playlists/playlists.h"
#ifndef DEDICATED
#include "vgui/vgui_baseui_interface.h"
#include "client/vengineclient_impl.h"
@ -316,7 +316,7 @@ void CHostState::Think(void) const
{
SetConsoleTitleA(Format("%s - %d/%d Players (%s on %s) - %d%% Server CPU (%.3f msec on frame %d)",
hostname->GetString(), g_pServer->GetNumClients(),
g_ServerGlobalVariables->m_nMaxClients, KeyValues__GetCurrentPlaylist(), m_levelName,
g_ServerGlobalVariables->m_nMaxClients, v_Playlists_GetCurrent(), m_levelName,
static_cast<int>(g_pServer->GetCPUUsage() * 100.0f), (g_pEngine->GetFrameTime() * 1000.0f),
g_pServer->GetTick()).c_str());
@ -337,7 +337,7 @@ void CHostState::Think(void) const
hostdesc->GetString(),
sv_pylonVisibility->GetInt() == EServerVisibility_t::HIDDEN,
g_pHostState->m_levelName,
KeyValues__GetCurrentPlaylist(),
v_Playlists_GetCurrent(),
hostip->GetString(),
hostport->GetInt(),
g_pNetKey->GetBase64NetKey(),

View File

@ -7,7 +7,7 @@
#include "core/stdafx.h"
#include "tier0/frametask.h"
#include "tier1/cvar.h"
#include "vpc/keyvalues.h"
#include "tier1/keyvalues.h"
#include "common/callback.h"
#include "engine/net.h"
#include "engine/net_chan.h"

View File

@ -9,7 +9,7 @@
//=============================================================================//
#include "core/stdafx.h"
#include "vpc/keyvalues.h"
#include "tier1/keyvalues.h"
#include "engine/cmodel_bsp.h"
#include "engine/host_state.h"
#include "engine/client/cl_main.h"

View File

@ -12,7 +12,7 @@
//=============================================================================//
#include "core/stdafx.h"
#include "vpc/keyvalues.h"
#include "rtech/playlists/playlists.h"
#include "engine/client/cl_main.h"
#include "engine/cmodel_bsp.h"
#include "vscript/languages/squirrel_re/include/sqvm.h"

View File

@ -31,7 +31,7 @@ History:
#include "networksystem/serverlisting.h"
#include "networksystem/pylon.h"
#include "networksystem/listmanager.h"
#include "vpc/keyvalues.h"
#include "rtech/playlists/playlists.h"
#include "common/callback.h"
#include "gameui/IBrowser.h"
#include "public/edict.h"
@ -603,7 +603,7 @@ void CBrowser::HostPanel(void)
g_TaskScheduler->Dispatch([]()
{
v__DownloadPlaylists_f();
KeyValues::InitPlaylists(); // Re-Init playlist.
Playlists_SDKInit(); // Re-Init playlist.
}, 0);
}
@ -745,7 +745,7 @@ void CBrowser::UpdateHostingStatus(void)
g_pServerListManager->m_Server.m_svDescription,
g_pServerListManager->m_Server.m_bHidden,
g_pHostState->m_levelName,
KeyValues__GetCurrentPlaylist(),
v_Playlists_GetCurrent(),
hostip->GetString(),
hostport->GetInt(),
g_pNetKey->GetBase64NetKey(),

View File

@ -7,7 +7,7 @@
#include "tier0/crashhandler.h"
#include "tier0/commandline.h"
#include "tier1/cvar.h"
#include "vpc/keyvalues.h"
#include "tier1/keyvalues.h"
#include "rtech/rtech_utils.h"
#include "engine/cmodel_bsp.h"
#include "engine/sys_engine.h"

View File

@ -14,7 +14,7 @@
#include "engine/net.h"
#include "engine/host_state.h"
#include "engine/server/server.h"
#include "vpc/keyvalues.h"
#include "rtech/playlists/playlists.h"
#include "pylon.h"
#include "listmanager.h"
@ -74,7 +74,7 @@ void CServerListManager::LaunchServer(const bool bChangeLevel) const
* values. Then when you would normally call launchplaylist which calls StartPlaylist it would cmd
* call mp_gamemode which parses the gamemode specific part of the playlist..
*/
KeyValues::ParsePlaylists(m_Server.m_svPlaylist.c_str());
v_Playlists_Parse(m_Server.m_svPlaylist.c_str());
mp_gamemode->SetValue(m_Server.m_svPlaylist.c_str());
ProcessCommand(Format("%s \"%s\"", bChangeLevel ? "changelevel" : "map", m_Server.m_svHostMap.c_str()).c_str());

View File

@ -1,6 +1,6 @@
#pragma once
#include "vpc/keyvalues.h"
#include "tier1/keyvalues.h"
#include "vpc/rson.h"
#include "filesystem/filesystem.h"
#include "public/vscript/ivscript.h"

View File

@ -9,7 +9,7 @@
#define EIFACE_H
#include "edict.h"
#include "tier1/bitbuf.h"
#include "vpc/keyvalues.h"
#include "tier1/keyvalues.h"
//-----------------------------------------------------------------------------
// Forward declarations

View File

@ -113,6 +113,9 @@ PLATFORM_INTERFACE void NetMsg(LogType_t logType, eDLL_T context, const char* up
PLATFORM_INTERFACE void Warning(eDLL_T context, const char* fmt, ...) FMTFUNCTION(2, 3);
PLATFORM_INTERFACE void Error(eDLL_T context, const UINT code, const char* fmt, ...) FMTFUNCTION(3, 4);
// TODO[ AMOS ]: export to DLL?
void Plat_FatalError(eDLL_T context, const char* fmt, ...);
#if defined DBGFLAG_STRINGS_STRIP
#define DevMsg( ... ) ((void)0)
#define DevWarning( ... ) ((void)0)

View File

@ -0,0 +1,74 @@
//===== Copyright © 1996-2006, Valve Corporation, All rights reserved. ======//
//
// Purpose: ExprSimplifier builds a binary tree from an infix expression (in the
// form of a character array).
//
//===========================================================================//
#ifndef EXPREVALUATOR_H
#define EXPREVALUATOR_H
#if defined( _WIN32 )
#pragma once
#endif
static const char OR_OP = '|';
static const char AND_OP = '&';
static const char NOT_OP = '!';
#define MAX_IDENTIFIER_LEN 128
enum Kind {CONDITIONAL, NOT, LITERAL};
struct ExprNode
{
ExprNode *left; // left sub-expression
ExprNode *right; // right sub-expression
Kind kind; // kind of node this is
union
{
char cond; // the conditional
bool value; // the value
} data;
};
typedef ExprNode *ExprTree;
// callback to evaluate a $<symbol> during evaluation, return true or false
typedef bool (*GetSymbolProc_t)( const char *pKey );
typedef void (*SyntaxErrorProc_t)( const char *pReason );
class CExpressionEvaluator
{
public:
CExpressionEvaluator();
~CExpressionEvaluator();
bool Evaluate( bool &result, const char *pInfixExpression, GetSymbolProc_t pGetSymbolProc = 0, SyntaxErrorProc_t pSyntaxErrorProc = 0 );
private:
CExpressionEvaluator( CExpressionEvaluator& ); // prevent copy constructor being used
char GetNextToken( void );
void FreeNode( ExprNode *pNode );
ExprNode *AllocateNode( void );
void FreeTree( ExprTree &node );
bool IsConditional( bool &bCondition, const char token );
bool IsNotOp( const char token );
bool IsIdentifierOrConstant( const char token );
bool MakeExprNode( ExprTree &tree, char token, Kind kind, ExprTree left, ExprTree right );
bool MakeFactor( ExprTree &tree );
bool MakeTerm( ExprTree &tree );
bool MakeExpression( ExprTree &tree );
bool BuildExpression( void );
bool SimplifyNode( ExprTree &node );
ExprTree m_ExprTree; // Tree representation of the expression
char m_CurToken; // Current token read from the input expression
const char *m_pExpression; // Array of the expression characters
int m_CurPosition; // Current position in the input expression
char m_Identifier[MAX_IDENTIFIER_LEN]; // Stores the identifier string
GetSymbolProc_t m_pGetSymbolProc;
SyntaxErrorProc_t m_pSyntaxErrorProc;
bool m_bSetup;
};
#endif

369
r5dev/public/tier1/fmtstr.h Normal file
View File

@ -0,0 +1,369 @@
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: A simple class for performing safe and in-expression sprintf-style
// string formatting
//
// $NoKeywords: $
//=============================================================================//
#ifndef FMTSTR_H
#define FMTSTR_H
#include <stdarg.h>
#include <stdio.h>
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "tier1/strtools.h"
#if defined( _WIN32 )
#pragma once
#endif
//=============================================================================
// using macro to be compatible with GCC
#define FmtStrVSNPrintf( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
do \
{ \
int result; \
va_list arg_ptr; \
bool bTruncated = false; \
static int scAsserted = 0; \
\
va_start(arg_ptr, lastArg); \
result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
va_end(arg_ptr); \
\
(szBuf)[(nBufSize)-1] = 0; \
if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
{ \
Warning( eDLL_T::COMMON, "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
scAsserted++; \
} \
m_nLength = nPrevLen + result; \
} \
while (0)
// using macro to be compatable with GCC
#define FmtStrVSNPrintfNoLengthFixup( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
do \
{ \
int result; \
va_list arg_ptr; \
bool bTruncated = false; \
static int scAsserted = 0; \
\
va_start(arg_ptr, lastArg); \
result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
va_end(arg_ptr); \
\
(szBuf)[(nBufSize)-1] = 0; \
if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
{ \
Warning( eDLL_T::COMMON, "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
scAsserted++; \
} \
} \
while (0)
//-----------------------------------------------------------------------------
//
// Purpose: String formatter with specified size
//
template <int SIZE_BUF, bool QUIET_TRUNCATION = false >
class CFmtStrN
{
public:
CFmtStrN()
{
InitQuietTruncation();
m_szBuf[0] = 0;
m_nLength = 0;
}
// Standard C formatting
CFmtStrN(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
{
InitQuietTruncation();
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
}
// Use this for pass-through formatting
CFmtStrN(const char ** ppszFormat, ...)
{
InitQuietTruncation();
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
}
// Explicit reformat
const char *sprintf(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
{
InitQuietTruncation();
FmtStrVSNPrintf(m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
return m_szBuf;
}
// Same as sprintf above, but for compatibility with Steam interface
const char *Format( PRINTF_FORMAT_STRING const char *pszFormat, ... ) FMTFUNCTION( 2, 3 )
{
InitQuietTruncation();
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
return m_szBuf;
}
// Use this for va_list formatting
const char *sprintf_argv(const char *pszFormat, va_list arg_ptr)
{
int result;
bool bTruncated = false;
static int s_nWarned = 0;
InitQuietTruncation();
result = V_vsnprintfRet( m_szBuf, SIZE_BUF - 1, pszFormat, arg_ptr, &bTruncated );
m_szBuf[SIZE_BUF - 1] = 0;
if ( bTruncated && !m_bQuietTruncation && ( s_nWarned < 5 ) )
{
Warning( eDLL_T::COMMON, "CFmtStr truncated to %d without QUIET_TRUNCATION specified!\n", SIZE_BUF );
AssertMsg( 0, "CFmtStr truncated without QUIET_TRUNCATION specified!\n" );
s_nWarned++;
}
m_nLength = V_strlen( m_szBuf );
return m_szBuf;
}
// Use this for pass-through formatting
void VSprintf(const char **ppszFormat, ...)
{
InitQuietTruncation();
FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
}
// Compatible API with CUtlString for converting to const char*
const char *Get( ) const { return m_szBuf; }
const char *String( ) const { return m_szBuf; }
// Use for access
operator const char *() const { return m_szBuf; }
char *Access() { return m_szBuf; }
// Access template argument
static inline int GetMaxLength() { return SIZE_BUF-1; }
CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator=( const char *pchValue )
{
V_strncpy( m_szBuf, pchValue, SIZE_BUF );
m_nLength = V_strlen( m_szBuf );
return *this;
}
CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator+=( const char *pchValue )
{
Append( pchValue );
return *this;
}
int Length() const { return m_nLength; }
void SetLength( int nLength )
{
m_nLength = Min( nLength, SIZE_BUF - 1 );
m_szBuf[m_nLength] = '\0';
}
void Clear()
{
m_szBuf[0] = 0;
m_nLength = 0;
}
void AppendFormat( PRINTF_FORMAT_STRING const char *pchFormat, ... ) FMTFUNCTION( 2, 3 )
{
char *pchEnd = m_szBuf + m_nLength;
FmtStrVSNPrintf( pchEnd, SIZE_BUF - m_nLength, m_bQuietTruncation, &pchFormat, m_nLength, pchFormat );
}
void AppendFormatV( const char *pchFormat, va_list args );
void Append( const char *pchValue )
{
// This function is close to the metal to cut down on the CPU cost
// of the previous incantation of Append which was implemented as
// AppendFormat( "%s", pchValue ). This implementation, though not
// as easy to read, instead does a strcpy from the existing end
// point of the CFmtStrN. This brings something like a 10-20x speedup
// in my rudimentary tests. It isn't using V_strncpy because that
// function doesn't return the number of characters copied, which
// we need to adjust m_nLength. Doing the V_strncpy with a V_strlen
// afterwards took twice as long as this implementations in tests,
// so V_strncpy's implementation was used to write this method.
char *pDest = m_szBuf + m_nLength;
const int maxLen = SIZE_BUF - m_nLength;
char *pLast = pDest + maxLen - 1;
while ( (pDest < pLast) && (*pchValue != 0) )
{
*pDest = *pchValue;
++pDest; ++pchValue;
}
*pDest = 0;
m_nLength = pDest - m_szBuf;
}
//optimized version of append for just adding a single character
void Append( char ch )
{
if( m_nLength < SIZE_BUF - 1 )
{
m_szBuf[ m_nLength ] = ch;
m_nLength++;
m_szBuf[ m_nLength ] = '\0';
}
}
void AppendIndent( uint32 unCount, char chIndent = '\t' );
void SetQuietTruncation( bool bQuiet ) { m_bQuietTruncation = bQuiet; }
protected:
virtual void InitQuietTruncation()
{
m_bQuietTruncation = QUIET_TRUNCATION;
}
bool m_bQuietTruncation;
private:
char m_szBuf[SIZE_BUF];
int m_nLength;
};
// Version which will not assert if strings are truncated
template < int SIZE_BUF >
class CFmtStrQuietTruncationN : public CFmtStrN<SIZE_BUF, true >
{
};
template< int SIZE_BUF, bool QUIET_TRUNCATION >
void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendIndent( uint32 unCount, char chIndent )
{
Assert( Length() + unCount < SIZE_BUF );
if( Length() + unCount >= SIZE_BUF )
unCount = SIZE_BUF - (1+Length());
for ( uint32 x = 0; x < unCount; x++ )
{
m_szBuf[ m_nLength++ ] = chIndent;
}
m_szBuf[ m_nLength ] = '\0';
}
template< int SIZE_BUF, bool QUIET_TRUNCATION >
void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendFormatV( const char *pchFormat, va_list args )
{
int cubPrinted = V_vsnprintf( m_szBuf+Length(), SIZE_BUF - Length(), pchFormat, args );
m_nLength += cubPrinted;
}
//-----------------------------------------------------------------------------
//
// Purpose: Default-sized string formatter
//
#define FMTSTR_STD_LEN 256
typedef CFmtStrN<FMTSTR_STD_LEN> CFmtStr;
typedef CFmtStrQuietTruncationN<FMTSTR_STD_LEN> CFmtStrQuietTruncation;
typedef CFmtStrN<32> CFmtStr32;
typedef CFmtStrN<1024> CFmtStr1024;
typedef CFmtStrN<2048> CFmtStr2048;
typedef CFmtStrN<8192> CFmtStrMax;
//-----------------------------------------------------------------------------
// Purpose: Fast-path number-to-string helper (with optional quoting)
// Derived off of the Steam CNumStr but with a few tweaks, such as
// trimming off the in-our-cases-unnecessary strlen calls (by not
// storing the length in the class).
//-----------------------------------------------------------------------------
class CNumStr
{
public:
CNumStr() { m_szBuf[0] = 0; }
explicit CNumStr( bool b ) { SetBool( b ); }
explicit CNumStr( int8 n8 ) { SetInt8( n8 ); }
explicit CNumStr( uint8 un8 ) { SetUint8( un8 ); }
explicit CNumStr( int16 n16 ) { SetInt16( n16 ); }
explicit CNumStr( uint16 un16 ) { SetUint16( un16 ); }
explicit CNumStr( int32 n32 ) { SetInt32( n32 ); }
explicit CNumStr( uint32 un32 ) { SetUint32( un32 ); }
explicit CNumStr( int64 n64 ) { SetInt64( n64 ); }
explicit CNumStr( uint64 un64 ) { SetUint64( un64 ); }
#if defined(COMPILER_GCC) && defined(PLATFORM_64BITS)
explicit CNumStr( lint64 n64 ) { SetInt64( (int64)n64 ); }
explicit CNumStr( ulint64 un64 ) { SetUint64( (uint64)un64 ); }
#endif
explicit CNumStr( double f ) { SetDouble( f ); }
explicit CNumStr( float f ) { SetFloat( f ); }
inline void SetBool( bool b ) { memcpy( m_szBuf, b ? "1" : "0", 2 ); }
#ifdef _WIN32
inline void SetInt8( int8 n8 ) { _itoa( (int32)n8, m_szBuf, 10 ); }
inline void SetUint8( uint8 un8 ) { _itoa( (int32)un8, m_szBuf, 10 ); }
inline void SetInt16( int16 n16 ) { _itoa( (int32)n16, m_szBuf, 10 ); }
inline void SetUint16( uint16 un16 ) { _itoa( (int32)un16, m_szBuf, 10 ); }
inline void SetInt32( int32 n32 ) { _itoa( n32, m_szBuf, 10 ); }
inline void SetUint32( uint32 un32 ) { _i64toa( (int64)un32, m_szBuf, 10 ); }
inline void SetInt64( int64 n64 ) { _i64toa( n64, m_szBuf, 10 ); }
inline void SetUint64( uint64 un64 ) { _ui64toa( un64, m_szBuf, 10 ); }
#else
inline void SetInt8( int8 n8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n8 ); }
inline void SetUint8( uint8 un8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un8 ); }
inline void SetInt16( int16 n16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n16 ); }
inline void SetUint16( uint16 un16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un16 ); }
inline void SetInt32( int32 n32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", n32 ); }
inline void SetUint32( uint32 un32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%u", un32 ); }
inline void SetInt64( int64 n64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%lld", n64 ); }
inline void SetUint64( uint64 un64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%llu", un64 ); }
#endif
inline void SetDouble( double f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
inline void SetFloat( float f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
inline void SetHexUint64( uint64 un64 ) { V_binarytohex( (byte *)&un64, sizeof( un64 ), m_szBuf, sizeof( m_szBuf ) ); }
operator const char *() const { return m_szBuf; }
const char* String() const { return m_szBuf; }
void AddQuotes()
{
Assert( m_szBuf[0] != '"' );
const size_t nLength = Q_strlen( m_szBuf );
memmove( m_szBuf + 1, m_szBuf, nLength );
m_szBuf[0] = '"';
m_szBuf[nLength + 1] = '"';
m_szBuf[nLength + 2] = 0;
}
protected:
char m_szBuf[28]; // long enough to hold 18 digits of precision, a decimal, a - sign, e+### suffix, and quotes
};
//=============================================================================
const int k_cchFormattedDate = 64;
const int k_cchFormattedTime = 32;
bool BGetLocalFormattedTime( time_t timeVal, char *pchDate, int cubDate, char *pchTime, int cubTime );
#endif // FMTSTR_H

View File

@ -1,16 +1,14 @@
#pragma once
#include "mathlib/color.h"
#include "tier1/utlbuffer.h"
#include "tier1/exprevaluator.h"
#include "public/ifilesystem.h"
#define MAKE_3_BYTES_FROM_1_AND_2( x1, x2 ) (( (( uint16_t )x2) << 8 ) | (uint8_t)(x1))
#define SPLIT_3_BYTES_INTO_1_AND_2( x1, x2, x3 ) do { x1 = (uint8)(x3); x2 = (uint16)( (x3) >> 8 ); } while( 0 )
#define KEYVALUES_TOKEN_SIZE (1024 * 32)
extern vector<string> g_vAllPlaylists;
extern vector<string> g_vGameInfoPaths;
extern std::mutex g_InstalledMapsMutex;
extern std::mutex g_PlaylistsVecMutex;
// single byte identifies a xbox kv file in binary format
// strings are pooled from a searchpath/zip mounted symbol table
#define KV_BINARY_POOLED_FORMAT 0xAA
//---------------------------------------------------------------------------------
// Purpose: Forward declarations
@ -18,15 +16,7 @@ extern std::mutex g_PlaylistsVecMutex;
class KeyValues;
class CFileSystem_Stdio;
class IBaseFileSystem;
/* ==== KEYVALUES ======================================================================================================================================================= */
inline void*(*KeyValues__FindKey)(KeyValues* thisptr, const char* pkeyName, bool bCreate);
inline bool(*KeyValues__LoadPlaylists)(const char* pszPlaylist);
inline bool(*KeyValues__ParsePlaylists)(const char* pszPlaylist);
inline const char* (*KeyValues__GetCurrentPlaylist)(void);
inline KeyValues*(*KeyValues__ReadKeyValuesFile)(CFileSystem_Stdio* pFileSystem, const char* pFileName);
inline void(*KeyValues__RecursiveSaveToFile)(KeyValues* thisptr, IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, int nIndentLevel);
inline KeyValues*(*KeyValues__LoadFromFile)(KeyValues* thisptr, IBaseFileSystem* pFileSystem, const char* pszResourceName, const char* pszPathID, void* pfnEvaluateSymbolProc);
class CKeyValuesTokenReader;
enum KeyValuesTypes_t : char
{
@ -51,6 +41,14 @@ enum MergeKeyValuesOp_t
MERGE_KV_BORROW, // update values only update existing keys in storage, keys in update that do not exist in storage are discarded
};
#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \
for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() )
#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \
for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() )
#define FOR_EACH_VALUE( kvRoot, kvValue ) \
for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() )
//-----------------------------------------------------------------------------
// Purpose: Simple recursive data access class
@ -90,6 +88,7 @@ public:
void DeleteThis(void);
void RemoveEverything();
KeyValues* FindKey(int keySymbol) const;
KeyValues* FindKey(const char* pKeyName, bool bCreate = false);
KeyValues* FindLastSubKey(void) const;
@ -109,6 +108,8 @@ public:
KeyValues* GetFirstSubKey() const;
KeyValues* GetNextKey() const;
const char* GetName(void) const;
int GetNameSymbol() const;
int GetNameSymbolCaseSensitive() const;
int GetInt(const char* pszKeyName, int iDefaultValue);
uint64_t GetUint64(const char* pszKeyName, uint64_t nDefaultValue);
void* GetPtr(const char* pszKeyName, void* pDefaultValue);
@ -134,20 +135,41 @@ public:
void SetBool(const char* pszKeyName, bool bValue) { SetInt(pszKeyName, bValue ? 1 : 0); }
void UsesEscapeSequences(bool bState);
void RecursiveCopyKeyValues(KeyValues& src);
void RecursiveSaveToFile(CUtlBuffer& buf, int nIndentLevel);
void RecursiveSaveToFile(IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, int nIndentLevel);
KeyValues* LoadFromFile(IBaseFileSystem* pFileSystem, const char* pszResourceName, const char* pszPathID, void* pfnEvaluateSymbolProc);
bool LoadFromFile(IBaseFileSystem* filesystem, const char* resourceName, const char* pathID, GetSymbolProc_t pfnEvaluateSymbolProc = nullptr);
bool LoadFromBuffer(char const* resourceName, CUtlBuffer& buf, IBaseFileSystem* pFileSystem, const char* pPathID, GetSymbolProc_t pfnEvaluateSymbolProc = nullptr);
bool LoadFromBuffer(char const* resourceName, const char* pBuffer, IBaseFileSystem* pFileSystem, const char* pPathID, GetSymbolProc_t pfnEvaluateSymbolProc = nullptr);
// for handling #include "filename"
void AppendIncludedKeys(CUtlVector< KeyValues* >& includedKeys);
void ParseIncludedKeys(char const* resourceName, const char* filetoinclude,
IBaseFileSystem* pFileSystem, const char* pPathID, CUtlVector< KeyValues* >& includedKeys, GetSymbolProc_t pfnEvaluateSymbolProc);
// For handling #base "filename"
void MergeBaseKeys(CUtlVector< KeyValues* >& baseKeys);
void RecursiveMergeKeyValues(KeyValues* baseKV);
void CopySubkeys(KeyValues* pParent) const;
KeyValues* MakeCopy(void) const;
// Initialization
static void InitPlaylists(void);
static void InitFileSystem(void);
static bool LoadPlaylists(const char* szPlaylist);
static bool ParsePlaylists(const char* szPlaylist);
static KeyValues* ReadKeyValuesFile(CFileSystem_Stdio* pFileSystem, const char* pFileName);
KeyValues* CreateKeyUsingKnownLastChild(const char* keyName, KeyValues* pLastChild);
void AddSubkeyUsingKnownLastChild(KeyValues* pSubKey, KeyValues* pLastChild);
private:
void RecursiveSaveToFile(IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, int nIndentLevel);
void RecursiveLoadFromBuffer(char const* resourceName, CKeyValuesTokenReader& tokenReader, GetSymbolProc_t pfnEvaluateSymbolProc);
void RecursiveCopyKeyValues(KeyValues& src);
// NOTE: If both filesystem and pBuf are non-null, it'll save to both of them.
// If filesystem is null, it'll ignore f.
void InternalWrite(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, const void* pData, ssize_t len);
void WriteIndents(IBaseFileSystem* filesystem, FileHandle_t f, CUtlBuffer* pBuf, int indentLevel);
void WriteConvertedString(IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, const char* pszString);
bool EvaluateConditional(const char* pExpressionString, GetSymbolProc_t pfnEvaluateSymbolProc);
public:
uint32_t m_iKeyName : 24;// 0x0000
@ -169,40 +191,3 @@ public:
KeyValues* m_pSub; // 0x0038
KeyValues* m_pChain; // 0x0040
};
///////////////////////////////////////////////////////////////////////////////
extern KeyValues** g_pPlaylistKeyValues;
///////////////////////////////////////////////////////////////////////////////
class VKeyValues : public IDetour
{
virtual void GetAdr(void) const
{
LogFunAdr("KeyValues::FindKey", KeyValues__FindKey);
LogFunAdr("KeyValues::LoadPlaylists", KeyValues__LoadPlaylists);
LogFunAdr("KeyValues::ParsePlaylists", KeyValues__ParsePlaylists);
LogFunAdr("KeyValues::GetCurrentPlaylist", KeyValues__GetCurrentPlaylist);
LogFunAdr("KeyValues::ReadKeyValuesFile", KeyValues__ReadKeyValuesFile);
LogFunAdr("KeyValues::RecursiveSaveToFile", KeyValues__RecursiveSaveToFile);
LogFunAdr("KeyValues::LoadFromFile", KeyValues__LoadFromFile);
LogVarAdr("g_pPlaylistKeyValues", g_pPlaylistKeyValues);
}
virtual void GetFun(void) const
{
g_GameDll.FindPatternSIMD("40 56 57 41 57 48 81 EC ?? ?? ?? ?? 45").GetPtr(KeyValues__FindKey);
g_GameDll.FindPatternSIMD("48 8B 05 ?? ?? ?? ?? 48 85 C0 75 08 48 8D 05 ?? ?? ?? ?? C3 0F B7 50 2A").GetPtr(KeyValues__GetCurrentPlaylist);
g_GameDll.FindPatternSIMD("48 8B C4 55 53 57 41 54 48 8D 68 A1").GetPtr(KeyValues__ReadKeyValuesFile);
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 4C 89 4C 24 ?? 48 89 4C 24 ?? 55 56 57 41 54 41 55 41 56 41 57 48 8D 6C 24 ??").GetPtr(KeyValues__LoadFromFile);
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 40 48 8B F1").GetPtr(KeyValues__LoadPlaylists);
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 80 3D ?? ?? ?? ?? ?? 74 0C").FollowNearCallSelf().GetPtr(KeyValues__ParsePlaylists);
g_GameDll.FindPatternSIMD("48 8B C4 53 ?? 57 41 55 41 ?? 48 83").GetPtr(KeyValues__RecursiveSaveToFile);
}
virtual void GetVar(void) const
{
g_pPlaylistKeyValues = g_GameDll.FindPatternSIMD("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B F9 E8 B4")
.FindPatternSelf("48 8B 0D", CMemory::Direction::DOWN, 100).ResolveRelativeAddressSelf(0x3, 0x7).RCast<KeyValues**>();
}
virtual void GetCon(void) const { }
virtual void Detour(const bool bAttach) const;
};
///////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,42 @@
#pragma once
#include "tier1/keyvalues.h"
//---------------------------------------------------------------------------------
// Purpose: Forward declarations
//---------------------------------------------------------------------------------
class KeyValues;
class CFileSystem_Stdio;
class IBaseFileSystem;
class CKeyValuesTokenReader;
/* ==== KEYVALUES ======================================================================================================================================================= */
inline void*(*KeyValues__FindKey)(KeyValues* thisptr, const char* pkeyName, bool bCreate);
inline KeyValues*(*KeyValues__ReadKeyValuesFile)(CFileSystem_Stdio* pFileSystem, const char* pFileName);
inline void(*KeyValues__RecursiveSaveToFile)(KeyValues* thisptr, IBaseFileSystem* pFileSystem, FileHandle_t pHandle, CUtlBuffer* pBuf, int nIndentLevel);
inline KeyValues*(*KeyValues__LoadFromFile)(KeyValues* thisptr, IBaseFileSystem* pFileSystem, const char* pszResourceName, const char* pszPathID, void* pfnEvaluateSymbolProc);
///////////////////////////////////////////////////////////////////////////////
extern KeyValues** g_pPlaylistKeyValues;
///////////////////////////////////////////////////////////////////////////////
class VKeyValues : public IDetour
{
virtual void GetAdr(void) const
{
LogFunAdr("KeyValues::FindKey", KeyValues__FindKey);
LogFunAdr("KeyValues::ReadKeyValuesFile", KeyValues__ReadKeyValuesFile);
LogFunAdr("KeyValues::RecursiveSaveToFile", KeyValues__RecursiveSaveToFile);
LogFunAdr("KeyValues::LoadFromFile", KeyValues__LoadFromFile);
}
virtual void GetFun(void) const
{
g_GameDll.FindPatternSIMD("40 56 57 41 57 48 81 EC ?? ?? ?? ?? 45").GetPtr(KeyValues__FindKey);
g_GameDll.FindPatternSIMD("48 8B C4 55 53 57 41 54 48 8D 68 A1").GetPtr(KeyValues__ReadKeyValuesFile);
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 4C 89 4C 24 ?? 48 89 4C 24 ?? 55 56 57 41 54 41 55 41 56 41 57 48 8D 6C 24 ??").GetPtr(KeyValues__LoadFromFile);
g_GameDll.FindPatternSIMD("48 8B C4 53 ?? 57 41 55 41 ?? 48 83").GetPtr(KeyValues__RecursiveSaveToFile);
}
virtual void GetVar(void) const { }
virtual void GetCon(void) const { }
virtual void Detour(const bool bAttach) const;
};
///////////////////////////////////////////////////////////////////////////////

View File

@ -59,13 +59,30 @@
#define Q_strcat V_strcat
template <size_t maxLenInCharacters> int V_vsprintf_safe(OUT_Z_ARRAY char(&pDest)[maxLenInCharacters], PRINTF_FORMAT_STRING const char* pFormat, va_list params) { return V_vsnprintf(pDest, maxLenInCharacters, pFormat, params); }
int _V_stricmp_NegativeForUnequal(const char* s1, const char* s2);
char const* V_stristr(char const* pStr, char const* pSearch);
const char* V_strnistr(const char* pStr, const char* pSearch, ssize_t n);
const char* V_strnchr(const char* pStr, char c, ssize_t n);
bool V_isspace(int c);
inline bool V_isalnum(char c) { return isalnum((unsigned char)c) != 0; }
// this is locale-unaware and therefore faster version of standard isdigit()
// It also avoids sign-extension errors.
inline bool V_isdigit(char c)
{
return c >= '0' && c <= '9';
}
inline bool V_iswdigit(int c)
{
return (((uint)(c - '0')) < 10);
}
void V_binarytohex(const byte* in, size_t inputbytes, char* out, size_t outsize);
int V_vsnprintfRet(char* pDest, int maxLen, const char* pFormat, va_list params, bool* pbTruncated);
// Strip white space at the beginning and end of a string
ssize_t V_StrTrim(char* pStr);

View File

@ -29,6 +29,17 @@ add_sources( SOURCE_GROUP "Public"
end_sources()
add_module( "lib" "playlists" "vpc" ${FOLDER_CONTEXT} TRUE TRUE )
start_sources()
add_sources( SOURCE_GROUP "Source"
"playlists/playlists.cpp"
"playlists/playlists.h"
)
end_sources()
add_module( "lib" "rui" "vpc" ${FOLDER_CONTEXT} TRUE TRUE )
start_sources()

View File

@ -0,0 +1,87 @@
//===========================================================================//
//
// Purpose: Playlists system
//
//===========================================================================//
#include "engine/sys_dll2.h"
#include "engine/cmodel_bsp.h"
#include "playlists.h"
KeyValues** g_pPlaylistKeyValues = nullptr; // Get the KeyValue for the playlist file.
vector<string> g_vAllPlaylists = { "<<null>>" };
std::mutex g_PlaylistsVecMutex;
//-----------------------------------------------------------------------------
// Purpose: Initializes the playlist globals
//-----------------------------------------------------------------------------
void Playlists_SDKInit(void)
{
if (*g_pPlaylistKeyValues)
{
KeyValues* pPlaylists = (*g_pPlaylistKeyValues)->FindKey("Playlists");
if (pPlaylists)
{
std::lock_guard<std::mutex> l(g_PlaylistsVecMutex);
g_vAllPlaylists.clear();
for (KeyValues* pSubKey = pPlaylists->GetFirstTrueSubKey(); pSubKey != nullptr; pSubKey = pSubKey->GetNextTrueSubKey())
{
g_vAllPlaylists.push_back(pSubKey->GetName()); // Get all playlists.
}
}
}
Mod_GetAllInstalledMaps(); // Parse all installed maps.
}
//-----------------------------------------------------------------------------
// Purpose: loads the playlists
// Input : *szPlaylist -
// Output : true on success, false on failure
//-----------------------------------------------------------------------------
bool Playlists_Load(const char* pszPlaylist)
{
const bool bResults = v_Playlists_Load(pszPlaylist);
Playlists_SDKInit();
return bResults;
}
//-----------------------------------------------------------------------------
// Purpose: parses the playlists
// Input : *szPlaylist -
// Output : true on success, false on failure
//-----------------------------------------------------------------------------
bool Playlists_Parse(const char* pszPlaylist)
{
g_szMTVFItemName[0] = '\0'; // Terminate g_szMTVFTaskName to prevent crash while loading playlist.
CHAR sPlaylistPath[] = "\x77\x27\x35\x2b\x2c\x6c\x2b\x2c\x2b";
PCHAR curr = sPlaylistPath;
while (*curr)
{
*curr ^= 'B';
++curr;
}
if (FileExists(sPlaylistPath))
{
uint8_t verifyPlaylistIntegrity[] = // Very hacky way for alternative inline assembly for x64..
{
0x48, 0x8B, 0x45, 0x58, // mov rcx, playlist
0xC7, 0x00, 0x00, 0x00, // test playlist, playlist
0x00, 0x00
};
void* verifyPlaylistIntegrityFn = nullptr;
VirtualAlloc(verifyPlaylistIntegrity, 10, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(&verifyPlaylistIntegrityFn, reinterpret_cast<const void*>(verifyPlaylistIntegrity), 9);
reinterpret_cast<void(*)()>(verifyPlaylistIntegrityFn)();
}
return v_Playlists_Parse(pszPlaylist); // Parse playlist.
}
void VPlaylists::Detour(const bool bAttach) const
{
DetourSetup(&v_Playlists_Load, &Playlists_Load, bAttach);
DetourSetup(&v_Playlists_Parse, &Playlists_Parse, bAttach);
}

View File

@ -0,0 +1,45 @@
#ifndef RTECH_PLAYLISTS_H
#define RTECH_PLAYLISTS_H
#include "tier1/keyvalues.h"
///////////////////////////////////////////////////////////////////////////////
void Playlists_SDKInit(void);
bool Playlists_Load(const char* pszPlaylist);
bool Playlists_Parse(const char* pszPlaylist);
///////////////////////////////////////////////////////////////////////////////
inline bool(*v_Playlists_Load)(const char* pszPlaylist);
inline bool(*v_Playlists_Parse)(const char* pszPlaylist);
inline const char* (*v_Playlists_GetCurrent)(void);
extern KeyValues** g_pPlaylistKeyValues;
extern vector<string> g_vAllPlaylists;
extern std::mutex g_PlaylistsVecMutex;
///////////////////////////////////////////////////////////////////////////////
class VPlaylists : public IDetour
{
virtual void GetAdr(void) const
{
LogFunAdr("Playlists_Load", v_Playlists_Load);
LogFunAdr("Playlists_Parse", v_Playlists_Parse);
LogFunAdr("Playlists_GetCurrent", v_Playlists_GetCurrent);
LogVarAdr("g_pPlaylistKeyValues", g_pPlaylistKeyValues);
}
virtual void GetFun(void) const
{
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 40 48 8B F1").GetPtr(v_Playlists_Load);
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 80 3D ?? ?? ?? ?? ?? 74 0C").FollowNearCallSelf().GetPtr(v_Playlists_Parse);
g_GameDll.FindPatternSIMD("48 8B 05 ?? ?? ?? ?? 48 85 C0 75 08 48 8D 05 ?? ?? ?? ?? C3 0F B7 50 2A").GetPtr(v_Playlists_GetCurrent);
}
virtual void GetVar(void) const
{
g_pPlaylistKeyValues = g_GameDll.FindPatternSIMD("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B F9 E8 B4")
.FindPatternSelf("48 8B 0D", CMemory::Direction::DOWN, 100).ResolveRelativeAddressSelf(0x3, 0x7).RCast<KeyValues**>();
}
virtual void GetCon(void) const { }
virtual void Detour(const bool bAttach) const;
};
#endif // RTECH_PLAYLISTS_H

View File

@ -5,7 +5,7 @@
#include "core/stdafx.h"
#include "tier0/commandline.h"
#include "tier0/memstd.h"
#include "vpc/keyvalues.h"
#include "tier1/keyvalues.h"
#include "filesystem/filesystem.h"
#include "thirdparty/imgui/misc/imgui_utility.h"

View File

@ -20,6 +20,8 @@ add_sources( SOURCE_GROUP "Utility"
"characterset.cpp"
"mempool.cpp"
"memstack.cpp"
"exprevaluator.cpp"
"keyvalues.cpp"
)
add_sources( SOURCE_GROUP "Private"
@ -28,6 +30,10 @@ add_sources( SOURCE_GROUP "Private"
"convar.cpp"
"cvar.cpp"
"interface.cpp"
"keyvalues_iface.cpp"
"kvleaktrace.h"
"kverrorstack.h"
"kvtokenreader.h"
)
file( GLOB TIER1_PUBLIC_HEADERS

View File

@ -0,0 +1,493 @@
//===== Copyright <20> 1996-2006, Valve Corporation, All rights reserved. ======//
//
// Purpose: ExprSimplifier builds a binary tree from an infix expression (in the
// form of a character array). Evaluates C style infix parenthetic logical
// expressions. Supports !, ||, &&, (). Symbols are resolved via callback.
// Syntax is $<name>. $0 evaluates to false. $<number> evaluates to true.
// e.g: ( $1 || ( $FOO || $WHATEVER ) && !$BAR )
//===========================================================================//
#include <ctype.h>
#include "ikeyvaluessystem.h"
#include "tier1/exprevaluator.h"
#include "tier1/convar.h"
#include "tier1/fmtstr.h"
#include "tier1/strtools.h"
#include "tier0/dbg.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Default conditional symbol handler callback. Symbols are the form $<name>.
// Return true or false for the value of the symbol.
//-----------------------------------------------------------------------------
bool DefaultConditionalSymbolProc( const char *pKey )
{
if ( pKey[0] == '$' )
{
pKey++;
}
if ( !V_stricmp( pKey, "WIN32" ) )
{
return IsPC();
}
if ( !V_stricmp( pKey, "WINDOWS" ) )
{
return IsPlatformWindowsPC();
}
if ( !V_stricmp( pKey, "X360" ) )
{
return IsX360();
}
if ( !V_stricmp( pKey, "PS3" ) )
{
return IsPS3();
}
if ( !V_stricmp( pKey, "OSX" ) )
{
return IsPlatformOSX();
}
if ( !V_stricmp( pKey, "LINUX" ) )
{
return IsPlatformLinux();
}
if ( !V_stricmp( pKey, "POSIX" ) )
{
return IsPlatformPosix();
}
if ( !V_stricmp( pKey, "GAMECONSOLE" ) )
{
return IsGameConsole();
}
if ( !V_stricmp( pKey, "DEMO" ) )
{
#if defined( _DEMO )
return true;
#else
return false;
#endif
}
if ( !V_stricmp( pKey, "LOWVIOLENCE" ) )
{
#if defined( _LOWVIOLENCE )
return true;
#endif
// If it is not a LOWVIOLENCE binary build, then fall through
// and check if there was a run-time symbol installed for it
}
// don't know it at compile time, so fall through to installed symbol values
return KeyValuesSystem()->GetKeyValuesExpressionSymbol( pKey );
}
void DefaultConditionalErrorProc( const char *pReason )
{
Warning( eDLL_T::COMMON, "Conditional Error: %s\n", pReason );
}
CExpressionEvaluator::CExpressionEvaluator()
{
m_ExprTree = NULL;
}
CExpressionEvaluator::~CExpressionEvaluator()
{
FreeTree( m_ExprTree );
}
//-----------------------------------------------------------------------------
// Sets mCurToken to the next token in the input string. Skips all whitespace.
//-----------------------------------------------------------------------------
char CExpressionEvaluator::GetNextToken( void )
{
// while whitespace, Increment CurrentPosition
while ( m_pExpression[m_CurPosition] == ' ' )
++m_CurPosition;
// CurrentToken = Expression[CurrentPosition]
m_CurToken = m_pExpression[m_CurPosition++];
return m_CurToken;
}
//-----------------------------------------------------------------------------
// Utility funcs
//-----------------------------------------------------------------------------
void CExpressionEvaluator::FreeNode( ExprNode *pNode )
{
delete pNode;
}
ExprNode *CExpressionEvaluator::AllocateNode( void )
{
return new ExprNode;
}
void CExpressionEvaluator::FreeTree( ExprTree& node )
{
if ( !node )
return;
FreeTree( node->left );
FreeTree( node->right );
FreeNode( node );
node = 0;
}
bool CExpressionEvaluator::IsConditional( bool &bConditional, const char token )
{
char nextchar = ' ';
if ( token == OR_OP || token == AND_OP )
{
// expect || or &&
nextchar = m_pExpression[m_CurPosition++];
if ( (token & nextchar) == token )
{
bConditional = true;
}
else if ( m_pSyntaxErrorProc )
{
m_pSyntaxErrorProc( CFmtStr( "Bad expression operator: '%c%c', expected C style operator", token, nextchar ) );
return false;
}
}
else
{
bConditional = false;
}
// valid
return true;
}
bool CExpressionEvaluator::IsNotOp( const char token )
{
if ( token == NOT_OP )
return true;
else
return false;
}
bool CExpressionEvaluator::IsIdentifierOrConstant( const char token )
{
bool success = false;
if ( token == '$' )
{
// store the entire identifier
int i = 0;
m_Identifier[i++] = token;
while( (V_isalnum( m_pExpression[m_CurPosition] ) || m_pExpression[m_CurPosition] == '_') && i < MAX_IDENTIFIER_LEN )
{
m_Identifier[i] = m_pExpression[m_CurPosition];
++m_CurPosition;
++i;
}
if ( i < MAX_IDENTIFIER_LEN - 1 )
{
m_Identifier[i] = '\0';
success = true;
}
}
else
{
if ( V_isdigit( token ) )
{
int i = 0;
m_Identifier[i++] = token;
while( V_isdigit( m_pExpression[m_CurPosition] ) && ( i < MAX_IDENTIFIER_LEN ) )
{
m_Identifier[i] = m_pExpression[m_CurPosition];
++m_CurPosition;
++i;
}
if ( i < MAX_IDENTIFIER_LEN - 1 )
{
m_Identifier[i] = '\0';
success = true;
}
}
}
return success;
}
bool CExpressionEvaluator::MakeExprNode( ExprTree &tree, char token, Kind kind, ExprTree left, ExprTree right )
{
tree = AllocateNode();
tree->left = left;
tree->right = right;
tree->kind = kind;
switch ( kind )
{
case CONDITIONAL:
tree->data.cond = token;
break;
case LITERAL:
if ( V_isdigit( m_Identifier[0] ) )
{
tree->data.value = ( atoi( m_Identifier ) != 0 );
}
else
{
tree->data.value = m_pGetSymbolProc( m_Identifier );
}
break;
case NOT:
break;
default:
if ( m_pSyntaxErrorProc )
{
Assert( 0 );
m_pSyntaxErrorProc( CFmtStr( "Logic Error in CExpressionEvaluator" ) );
}
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Makes a factor :: { <expression> } | <identifier>.
//-----------------------------------------------------------------------------
bool CExpressionEvaluator::MakeFactor( ExprTree &tree )
{
if ( m_CurToken == '(' )
{
// Get the next token
GetNextToken();
// Make an expression, setting Tree to point to it
if ( !MakeExpression( tree ) )
{
return false;
}
}
else if ( IsIdentifierOrConstant( m_CurToken ) )
{
// Make a literal node, set Tree to point to it, set left/right children to NULL.
if ( !MakeExprNode( tree, m_CurToken, LITERAL, NULL, NULL ) )
{
return false;
}
}
else if ( IsNotOp( m_CurToken ) )
{
// do nothing
return true;
}
else
{
// This must be a bad token
if ( m_pSyntaxErrorProc )
{
m_pSyntaxErrorProc( CFmtStr( "Bad expression token: %c", m_CurToken ) );
}
return false;
}
// Get the next token
GetNextToken();
return true;
}
//-----------------------------------------------------------------------------
// Makes a term :: <factor> { <not> }.
//-----------------------------------------------------------------------------
bool CExpressionEvaluator::MakeTerm( ExprTree &tree )
{
// Make a factor, setting Tree to point to it
if ( !MakeFactor( tree ) )
{
return false;
}
// while the next token is !
while ( IsNotOp( m_CurToken ) )
{
// Make an operator node, setting left child to Tree and right to NULL. (Tree points to new node)
if ( !MakeExprNode( tree, m_CurToken, NOT, tree, NULL ) )
{
return false;
}
// Get the next token.
GetNextToken();
// Make a factor, setting the right child of Tree to point to it.
if ( !MakeFactor( tree->right ) )
{
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
// Makes a complete expression :: <term> { <cond> <term> }.
//-----------------------------------------------------------------------------
bool CExpressionEvaluator::MakeExpression( ExprTree &tree )
{
// Make a term, setting Tree to point to it
if ( !MakeTerm( tree ) )
{
return false;
}
// while the next token is a conditional
while ( 1 )
{
bool bConditional = false;
bool bValid = IsConditional( bConditional, m_CurToken );
if ( !bValid )
{
return false;
}
if ( !bConditional )
{
break;
}
// Make a conditional node, setting left child to Tree and right to NULL. (Tree points to new node)
if ( !MakeExprNode( tree, m_CurToken, CONDITIONAL, tree, NULL ) )
{
return false;
}
// Get the next token.
GetNextToken();
// Make a term, setting the right child of Tree to point to it.
if ( !MakeTerm( tree->right ) )
{
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
// returns true for success, false for failure
//-----------------------------------------------------------------------------
bool CExpressionEvaluator::BuildExpression( void )
{
// Get the first token, and build the tree.
GetNextToken();
return ( MakeExpression( m_ExprTree ) );
}
//-----------------------------------------------------------------------------
// returns the value of the node after resolving all children
//-----------------------------------------------------------------------------
bool CExpressionEvaluator::SimplifyNode( ExprTree& node )
{
if ( !node )
return false;
// Simplify the left and right children of this node
bool leftVal = SimplifyNode(node->left);
bool rightVal = SimplifyNode(node->right);
// Simplify this node
switch( node->kind )
{
case NOT:
// the child of '!' is always to the right
node->data.value = !rightVal;
break;
case CONDITIONAL:
if ( node->data.cond == AND_OP )
{
node->data.value = leftVal && rightVal;
}
else // OR_OP
{
node->data.value = leftVal || rightVal;
}
break;
default: // LITERAL
break;
}
// This node has beed resolved
node->kind = LITERAL;
return node->data.value;
}
//-----------------------------------------------------------------------------
// Interface to solve a conditional expression. Returns false on failure, Result is undefined.
//-----------------------------------------------------------------------------
bool CExpressionEvaluator::Evaluate( bool &bResult, const char *pInfixExpression, GetSymbolProc_t pGetSymbolProc, SyntaxErrorProc_t pSyntaxErrorProc )
{
if ( !pInfixExpression )
{
return false;
}
// for caller simplicity, we strip of any enclosing braces
// strip the bracketing [] if present
char szCleanToken[512];
if ( pInfixExpression[0] == '[' )
{
size_t len = V_strlen( pInfixExpression );
// SECURITY: Bail on input buffers that are too large, they're used for RCEs and we don't
// need to support them.
if ( len + 1 > ARRAYSIZE( szCleanToken ) )
{
return false;
}
V_strncpy( szCleanToken, pInfixExpression + 1, len );
len--;
if ( szCleanToken[len-1] == ']' )
{
szCleanToken[len-1] = '\0';
}
pInfixExpression = szCleanToken;
}
// reset state
m_pExpression = pInfixExpression;
m_pGetSymbolProc = pGetSymbolProc ? pGetSymbolProc : DefaultConditionalSymbolProc;
m_pSyntaxErrorProc = pSyntaxErrorProc ? pSyntaxErrorProc : DefaultConditionalErrorProc;
m_ExprTree = 0;
m_CurPosition = 0;
m_CurToken = 0;
// Building the expression tree will fail on bad syntax
const bool bValid = BuildExpression();
if ( bValid )
{
bResult = SimplifyNode( m_ExprTree );
}
// don't leak
FreeTree( m_ExprTree );
m_ExprTree = NULL;
return bValid;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
#include "tier1/keyvalues_iface.h"
#include "filesystem/filesystem.h"
//-----------------------------------------------------------------------------
// Purpose: reads a keyvalues file
// Input : *pFileSystem -
// * pFileName -
// Output : pointer to KeyValues object
//-----------------------------------------------------------------------------
static KeyValues* ReadKeyValuesFile(CFileSystem_Stdio* pFileSystem, const char* pFileName)
{
return KeyValues__ReadKeyValuesFile(pFileSystem, pFileName);
}
///////////////////////////////////////////////////////////////////////////////
void VKeyValues::Detour(const bool bAttach) const
{
DetourSetup(&KeyValues__ReadKeyValuesFile, &ReadKeyValuesFile, bAttach);
}
///////////////////////////////////////////////////////////////////////////////
std::mutex g_InstalledMapsMutex;

View File

@ -0,0 +1,34 @@
#ifndef KVERRORCONTEXT_H
#define KVERRORCONTEXT_H
#include "kverrorstack.h"
// a simple helper that creates stack entries as it goes in & out of scope
class CKeyErrorContext
{
public:
~CKeyErrorContext()
{
g_KeyValuesErrorStack.Pop();
}
explicit CKeyErrorContext(int symName)
{
Init(symName);
}
void Reset(int symName)
{
g_KeyValuesErrorStack.Reset(m_stackLevel, symName);
}
int GetStackLevel() const
{
return m_stackLevel;
}
private:
void Init(int symName)
{
m_stackLevel = g_KeyValuesErrorStack.Push(symName);
}
int m_stackLevel;
};
#endif // KVERRORCONTEXT_H

View File

@ -0,0 +1,88 @@
#ifndef KVERRORSTACK_H
#define KVERRORSTACK_H
#include "ikeyvaluessystem.h"
// a simple class to keep track of a stack of valid parsed symbols
const int MAX_ERROR_STACK = 64;
class CKeyValuesErrorStack
{
public:
CKeyValuesErrorStack() : m_pFilename("NULL"), m_errorIndex(0), m_maxErrorIndex(0), m_bEncounteredErrors(false) {}
void SetFilename(const char* pFilename)
{
m_pFilename = pFilename;
m_maxErrorIndex = 0;
}
// entering a new keyvalues block, save state for errors
// Not save symbols instead of pointers because the pointers can move!
int Push(int symName)
{
if (m_errorIndex < MAX_ERROR_STACK)
{
m_errorStack[m_errorIndex] = symName;
}
m_errorIndex++;
m_maxErrorIndex = MAX(m_maxErrorIndex, (m_errorIndex - 1));
return m_errorIndex - 1;
}
// exiting block, error isn't in this block, remove.
void Pop()
{
m_errorIndex--;
Assert(m_errorIndex >= 0);
}
// Allows you to keep the same stack level, but change the name as you parse peers
void Reset(int stackLevel, int symName)
{
Assert(stackLevel >= 0 && stackLevel < m_errorIndex);
if (stackLevel < MAX_ERROR_STACK)
m_errorStack[stackLevel] = symName;
}
// Hit an error, report it and the parsing stack for context
void ReportError(const char* pError)
{
Warning(eDLL_T::COMMON, "KeyValues Error: %s in file %s\n", pError, m_pFilename);
for (int i = 0; i < m_maxErrorIndex; i++)
{
if (i < MAX_ERROR_STACK && m_errorStack[i] != INVALID_KEY_SYMBOL)
{
if (i < m_errorIndex)
{
Warning(eDLL_T::COMMON, "%s, ", KeyValuesSystem()->GetStringForSymbol(m_errorStack[i]));
}
else
{
Warning(eDLL_T::COMMON, "(*%s*), ", KeyValuesSystem()->GetStringForSymbol(m_errorStack[i]));
}
}
}
Warning(eDLL_T::COMMON, "\n");
m_bEncounteredErrors = true;
}
bool EncounteredAnyErrors()
{
return m_bEncounteredErrors;
}
void ClearErrorFlag()
{
m_bEncounteredErrors = false;
}
private:
int m_errorStack[MAX_ERROR_STACK];
const char* m_pFilename;
int m_errorIndex;
int m_maxErrorIndex;
bool m_bEncounteredErrors;
};
inline CKeyValuesErrorStack g_KeyValuesErrorStack;
#endif // KVERRORSTACK_H

153
r5dev/tier1/kvtokenreader.h Normal file
View File

@ -0,0 +1,153 @@
#ifndef KVTOKENREADER_H
#define KVTOKENREADER_H
#include "kverrorstack.h"
#include "tier1/keyvalues.h"
// This class gets the tokens out of a CUtlBuffer for KeyValues.
// Since KeyValues likes to seek backwards and seeking won't work with a text-mode CUtlStreamBuffer
// (which is what dmserializers uses), this class allows you to seek back one token.
class CKeyValuesTokenReader
{
public:
CKeyValuesTokenReader(KeyValues* pKeyValues, CUtlBuffer& buf);
const char* ReadToken(bool& wasQuoted, bool& wasConditional);
void SeekBackOneToken();
private:
KeyValues* m_pKeyValues;
CUtlBuffer& m_Buffer;
int m_nTokensRead;
bool m_bUsePriorToken;
bool m_bPriorTokenWasQuoted;
bool m_bPriorTokenWasConditional;
static char s_pTokenBuf[KEYVALUES_TOKEN_SIZE];
};
char CKeyValuesTokenReader::s_pTokenBuf[KEYVALUES_TOKEN_SIZE];
CKeyValuesTokenReader::CKeyValuesTokenReader(KeyValues* pKeyValues, CUtlBuffer& buf) :
m_Buffer(buf)
{
m_pKeyValues = pKeyValues;
m_nTokensRead = 0;
m_bUsePriorToken = false;
}
const char* CKeyValuesTokenReader::ReadToken(bool& wasQuoted, bool& wasConditional)
{
if (m_bUsePriorToken)
{
m_bUsePriorToken = false;
wasQuoted = m_bPriorTokenWasQuoted;
wasConditional = m_bPriorTokenWasConditional;
return s_pTokenBuf;
}
m_bPriorTokenWasQuoted = wasQuoted = false;
m_bPriorTokenWasConditional = wasConditional = false;
if (!m_Buffer.IsValid())
return NULL;
// eating white spaces and remarks loop
while (true)
{
m_Buffer.EatWhiteSpace();
if (!m_Buffer.IsValid())
{
return NULL; // file ends after reading whitespaces
}
// stop if it's not a comment; a new token starts here
if (!m_Buffer.EatCPPComment())
break;
}
const char* c = (const char*)m_Buffer.PeekGet(sizeof(char), 0);
if (!c)
{
return NULL;
}
// read quoted strings specially
if (*c == '\"')
{
m_bPriorTokenWasQuoted = wasQuoted = true;
m_Buffer.GetDelimitedString(m_pKeyValues->m_bHasEscapeSequences ? GetCStringCharConversion() : GetNoEscCharConversion(),
s_pTokenBuf, KEYVALUES_TOKEN_SIZE);
++m_nTokensRead;
return s_pTokenBuf;
}
if (*c == '{' || *c == '}' || *c == '=')
{
// it's a control char, just add this one char and stop reading
s_pTokenBuf[0] = *c;
s_pTokenBuf[1] = 0;
m_Buffer.GetChar();
++m_nTokensRead;
return s_pTokenBuf;
}
// read in the token until we hit a whitespace or a control character
bool bReportedError = false;
bool bConditionalStart = false;
int nCount = 0;
while (1)
{
c = (const char*)m_Buffer.PeekGet(sizeof(char), 0);
// end of file
if (!c || *c == 0)
break;
// break if any control character appears in non quoted tokens
if (*c == '"' || *c == '{' || *c == '}' || *c == '=')
break;
if (*c == '[')
bConditionalStart = true;
if (*c == ']' && bConditionalStart)
{
m_bPriorTokenWasConditional = wasConditional = true;
bConditionalStart = false;
}
// break on whitespace
if (V_isspace(*c) && !bConditionalStart)
break;
if (nCount < (KEYVALUES_TOKEN_SIZE - 1))
{
s_pTokenBuf[nCount++] = *c; // add char to buffer
}
else if (!bReportedError)
{
bReportedError = true;
g_KeyValuesErrorStack.ReportError(" ReadToken overflow");
}
m_Buffer.GetChar();
}
s_pTokenBuf[nCount] = 0;
++m_nTokensRead;
return s_pTokenBuf;
}
void CKeyValuesTokenReader::SeekBackOneToken()
{
if (m_bUsePriorToken)
Plat_FatalError(eDLL_T::COMMON, "CKeyValuesTokenReader::SeekBackOneToken: It is only possible to seek back one token at a time");
if (m_nTokensRead == 0)
Plat_FatalError(eDLL_T::COMMON, "CkeyValuesTokenReader::SeekBackOneToken: No tokens read yet");
m_bUsePriorToken = true;
}
#endif // KVTOKENREADER_H

View File

@ -1,5 +1,75 @@
#include "tier1/strtools.h"
//-----------------------------------------------------------------------------
// A special high-performance case-insensitive compare function
// returns 0 if strings match exactly
// returns >0 if strings match in a case-insensitive way, but do not match exactly
// returns <0 if strings do not match even in a case-insensitive way
//-----------------------------------------------------------------------------
int _V_stricmp_NegativeForUnequal(const char* s1, const char* s2)
{
// It is not uncommon to compare a string to itself. Since stricmp
// is expensive and pointer comparison is cheap, this simple test
// can save a lot of cycles, and cache pollution.
if (s1 == s2)
return 0;
uint8 const* pS1 = (uint8 const*)s1;
uint8 const* pS2 = (uint8 const*)s2;
int iExactMatchResult = 1;
for (;;)
{
int c1 = *(pS1++);
int c2 = *(pS2++);
if (c1 == c2)
{
// strings are case-insensitive equal, coerce accumulated
// case-difference to 0/1 and return it
if (!c1) return !iExactMatchResult;
}
else
{
if (!c2)
{
// c2=0 and != c1 => not equal
return -1;
}
iExactMatchResult = 0;
c1 = FastASCIIToLower(c1);
c2 = FastASCIIToLower(c2);
if (c1 != c2)
{
// strings are not equal
return -1;
}
}
c1 = *(pS1++);
c2 = *(pS2++);
if (c1 == c2)
{
// strings are case-insensitive equal, coerce accumulated
// case-difference to 0/1 and return it
if (!c1) return !iExactMatchResult;
}
else
{
if (!c2)
{
// c2=0 and != c1 => not equal
return -1;
}
iExactMatchResult = 0;
c1 = FastASCIIToLower(c1);
c2 = FastASCIIToLower(c2);
if (c1 != c2)
{
// strings are not equal
return -1;
}
}
}
}
//-----------------------------------------------------------------------------
// Finds a string in another string with a case insensitive test
//-----------------------------------------------------------------------------
@ -153,6 +223,52 @@ bool V_isspace(int c)
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *in -
// inputbytes -
// *out -
// outsize -
//-----------------------------------------------------------------------------
void V_binarytohex(const byte* in, size_t inputbytes, char* out, size_t outsize)
{
Assert(outsize >= 1);
char doublet[10];
int i;
out[0] = 0;
for (i = 0; i < inputbytes; i++)
{
unsigned char c = in[i];
V_snprintf(doublet, sizeof(doublet), "%02x", c);
V_strncat(out, doublet, outsize);
}
}
int V_vsnprintfRet(char* pDest, int maxLen, const char* pFormat, va_list params, bool* pbTruncated)
{
Assert(maxLen > 0);
int len = _vsnprintf(pDest, maxLen, pFormat, params);
bool bTruncated = (len < 0) || (len >= maxLen);
if (pbTruncated)
{
*pbTruncated = bTruncated;
}
if (bTruncated && maxLen > 0)
{
len = maxLen - 1;
pDest[maxLen - 1] = 0;
}
return len;
}
ssize_t V_StrTrim(char* pStr)
{
char* pSource = pStr;

View File

@ -7,8 +7,8 @@
#include <core/stdafx.h>
#include <tier1/cvar.h>
#include <tier1/keyvalues.h>
#include <windows/id3dx.h>
#include <vpc/keyvalues.h>
#include <mathlib/color.h>
#include <rtech/rtech_utils.h>
#include <rtech/rui/rui.h>

View File

@ -8,9 +8,6 @@ add_sources( SOURCE_GROUP "Private"
"IAppSystem.h"
"interfaces.cpp"
"interfaces.h"
"keyvalues.cpp"
"keyvalues.h"
"kvleaktrace.h"
"rson.cpp"
"rson.h"
)

View File

@ -25,29 +25,29 @@
//
/////////////////////////////////////////////////////////////////////////////////
#include "tier1/cvar.h"
#include "tier1/keyvalues.h"
#include "tier2/fileutils.h"
#include "mathlib/adler32.h"
#include "mathlib/crc32.h"
#include "mathlib/sha1.h"
#include "filesystem/filesystem.h"
#include "vpc/keyvalues.h"
#include "localize/ilocalize.h"
#include "vpklib/packedstore.h"
extern CFileSystem_Stdio* FileSystem();
static const std::regex s_DirFileRegex{ R"((?:.*\/)?([^_]*_)(.*)(.bsp.pak000_dir).*)" };
static const std::regex s_BlockFileRegex{ R"(pak000_([0-9]{3}))" };
//-----------------------------------------------------------------------------
// Purpose: initialize parameters for compression algorithm
//-----------------------------------------------------------------------------
void CPackedStore::InitLzCompParams(void)
void CPackedStore::InitLzCompParams(const char* compressionLevel, const lzham_int32 maxHelperThreads)
{
/*| PARAMETERS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/
m_lzCompParams.m_dict_size_log2 = VPK_DICT_SIZE;
m_lzCompParams.m_level = GetCompressionLevel();
m_lzCompParams.m_level = DetermineCompressionLevel(compressionLevel);
m_lzCompParams.m_compress_flags = lzham_compress_flags::LZHAM_COMP_FLAG_DETERMINISTIC_PARSING;
m_lzCompParams.m_max_helper_threads = fs_packedstore_max_helper_threads->GetInt();
m_lzCompParams.m_max_helper_threads = maxHelperThreads;
}
//-----------------------------------------------------------------------------
@ -65,19 +65,17 @@ void CPackedStore::InitLzDecompParams(void)
// Purpose: gets the LZHAM compression level
// output : lzham_compress_level
//-----------------------------------------------------------------------------
lzham_compress_level CPackedStore::GetCompressionLevel(void) const
lzham_compress_level CPackedStore::DetermineCompressionLevel(const char* compressionLevel) const
{
const char* pszLevel = fs_packedstore_compression_level->GetString();
if(strcmp(pszLevel, "fastest") == NULL)
if(strcmp(compressionLevel, "fastest") == NULL)
return lzham_compress_level::LZHAM_COMP_LEVEL_FASTEST;
else if (strcmp(pszLevel, "faster") == NULL)
else if (strcmp(compressionLevel, "faster") == NULL)
return lzham_compress_level::LZHAM_COMP_LEVEL_FASTER;
else if (strcmp(pszLevel, "default") == NULL)
else if (strcmp(compressionLevel, "default") == NULL)
return lzham_compress_level::LZHAM_COMP_LEVEL_DEFAULT;
else if (strcmp(pszLevel, "better") == NULL)
else if (strcmp(compressionLevel, "better") == NULL)
return lzham_compress_level::LZHAM_COMP_LEVEL_BETTER;
else if (strcmp(pszLevel, "uber") == NULL)
else if (strcmp(compressionLevel, "uber") == NULL)
return lzham_compress_level::LZHAM_COMP_LEVEL_UBER;
else
return lzham_compress_level::LZHAM_COMP_LEVEL_DEFAULT;
@ -208,7 +206,9 @@ KeyValues* CPackedStore::GetManifest(const CUtlString& workspacePath, const CUtl
CUtlString outPath;
outPath.Format("%s%s%s.txt", workspacePath.Get(), "manifest/", manifestFile.Get());
KeyValues* pManifestKV = FileSystem()->LoadKeyValues(IFileSystem::TYPE_COMMON, outPath.Get(), "PLATFORM");
KeyValues* pManifestKV = new KeyValues("BuildManifest");
pManifestKV->LoadFromFile(FileSystem(), outPath.Get(), "PLATFORM");
return pManifestKV;
}
@ -288,7 +288,6 @@ CUtlString CPackedStore::FormatEntryPath(const CUtlString& filePath,
void CPackedStore::BuildManifest(const CUtlVector<VPKEntryBlock_t>& entryBlocks, const CUtlString& workspacePath, const CUtlString& manifestName) const
{
KeyValues kv("BuildManifest");
KeyValues* pManifestKV = kv.FindKey("BuildManifest", true);
FOR_EACH_VEC(entryBlocks, i)
{
@ -301,7 +300,7 @@ void CPackedStore::BuildManifest(const CUtlVector<VPKEntryBlock_t>& entryBlocks,
CUtlString entryPath = entry.m_EntryPath;
entryPath.FixSlashes('\\');
KeyValues* pEntryKV = pManifestKV->FindKey(entryPath.Get(), true);
KeyValues* pEntryKV = kv.FindKey(entryPath.Get(), true);
pEntryKV->SetInt("preloadSize", entry.m_iPreloadSize);
pEntryKV->SetInt("loadFlags", descriptor.m_nLoadFlags);

View File

@ -196,10 +196,10 @@ struct VPKPair_t
class CPackedStore
{
public:
void InitLzCompParams(void);
void InitLzCompParams(const char* compressionLevel = "default", const lzham_int32 maxHelperThreads = -1);
void InitLzDecompParams(void);
lzham_compress_level GetCompressionLevel(void) const;
lzham_compress_level DetermineCompressionLevel(const char* compressionLevel) const;
void GetEntryBlocks(CUtlVector<VPKEntryBlock_t>& entryBlocks, FileHandle_t hDirectoryFile) const;
bool GetEntryValues(CUtlVector<VPKKeyValues_t>& entryValues, const CUtlString& workspacePath, const CUtlString& dirFileName) const;