source-engine/common/ConfigManager.cpp
FluorescentCIAAfricanAmerican 3bf9df6b27 1
2020-04-22 12:56:21 -04:00

923 lines
27 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include <windows.h>
#include "interface.h"
#include "tier0/icommandline.h"
#include "filesystem_tools.h"
#include "KeyValues.h"
#include "tier1/utlbuffer.h"
#include <io.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include "ConfigManager.h"
#include "SourceAppInfo.h"
#include "steam/steam_api.h"
extern CSteamAPIContext *steamapicontext;
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
#define GAME_CONFIG_FILENAME "GameConfig.txt"
#define TOKEN_SDK_VERSION "SDKVersion"
// Version history:
// 0 - Initial release
// 1 - Versioning added, DoD configuration added
// 2 - Ep1 added
// 3 - Ep2, TF2, and Portal added
// 4 - TF2 moved to its own engine
#define SDK_LAUNCHER_VERSION 5
// Half-Life 2
defaultConfigInfo_t HL2Info =
{
"Half-Life 2",
"hl2",
"halflife2.fgd",
"info_player_start",
"hl2.exe",
GetAppSteamAppId( k_App_HL2 )
};
// Counter-Strike: Source
defaultConfigInfo_t CStrikeInfo =
{
"Counter-Strike: Source",
"cstrike",
"cstrike.fgd",
"info_player_terrorist",
"hl2.exe",
GetAppSteamAppId( k_App_CSS )
};
//Half-Life 2: Deathmatch
defaultConfigInfo_t HL2DMInfo =
{
"Half-Life 2: Deathmatch",
"hl2mp",
"hl2mp.fgd",
"info_player_deathmatch",
"hl2.exe",
GetAppSteamAppId( k_App_HL2MP )
};
// Day of Defeat: Source
defaultConfigInfo_t DODInfo =
{
"Day of Defeat: Source",
"dod",
"dod.fgd",
"info_player_allies",
"hl2.exe",
GetAppSteamAppId( k_App_DODS )
};
// Half-Life 2 Episode 1
defaultConfigInfo_t Episode1Info =
{
"Half-Life 2: Episode One",
"episodic",
"halflife2.fgd",
"info_player_start",
"hl2.exe",
GetAppSteamAppId( k_App_HL2_EP1 )
};
// Half-Life 2 Episode 2
defaultConfigInfo_t Episode2Info =
{
"Half-Life 2: Episode Two",
"ep2",
"halflife2.fgd",
"info_player_start",
"hl2.exe",
GetAppSteamAppId( k_App_HL2_EP2 )
};
// Team Fortress 2
defaultConfigInfo_t TF2Info =
{
"Team Fortress 2",
"tf",
"tf.fgd",
"info_player_teamspawn",
"hl2.exe",
GetAppSteamAppId( k_App_TF2 )
};
// Portal
defaultConfigInfo_t PortalInfo =
{
"Portal",
"portal",
"portal.fgd",
"info_player_start",
"hl2.exe",
GetAppSteamAppId( k_App_PORTAL )
};
// Portal
defaultConfigInfo_t SourceTestInfo =
{
"SourceTest",
"sourcetest",
"halflife2.fgd",
"info_player_start",
"hl2.exe",
243730
};
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CGameConfigManager::CGameConfigManager( void ) : m_pData( NULL ), m_LoadStatus( LOADSTATUS_NONE )
{
// Start with default directory
GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), m_szBaseDirectory, sizeof( m_szBaseDirectory ) );
Q_StripLastDir( m_szBaseDirectory, sizeof( m_szBaseDirectory ) ); // Get rid of the filename.
Q_StripTrailingSlash( m_szBaseDirectory );
m_eSDKEpoch = (eSDKEpochs) SDK_LAUNCHER_VERSION;
}
//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
CGameConfigManager::~CGameConfigManager( void )
{
// Release the keyvalues
if ( m_pData != NULL )
{
m_pData->deleteThis();
}
}
//-----------------------------------------------------------------------------
// Purpose: Config loading interface
// Input : *baseDir - base directory for our file
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CGameConfigManager::LoadConfigs( const char *baseDir )
{
return LoadConfigsInternal( baseDir, false );
}
//-----------------------------------------------------------------------------
// Purpose: Loads a file into the given utlbuffer.
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool ReadUtlBufferFromFile( CUtlBuffer &buffer, const char *szPath )
{
struct _stat fileInfo;
if ( _stat( szPath, &fileInfo ) == -1 )
{
return false;
}
buffer.EnsureCapacity( fileInfo.st_size );
int nFile = _open( szPath, _O_BINARY | _O_RDONLY );
if ( nFile == -1 )
{
return false;
}
if ( _read( nFile, buffer.Base(), fileInfo.st_size ) != fileInfo.st_size )
{
_close( nFile );
return false;
}
_close( nFile );
buffer.SeekPut( CUtlBuffer::SEEK_HEAD, fileInfo.st_size );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Loads a file into the given utlbuffer.
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool SaveUtlBufferToFile( CUtlBuffer &buffer, const char *szPath )
{
int nFile = _open( szPath, _O_TEXT | _O_CREAT | _O_TRUNC | _O_RDWR, _S_IWRITE );
if ( nFile == -1 )
{
return false;
}
int nSize = buffer.TellMaxPut();
if ( _write( nFile, buffer.Base(), nSize ) < nSize )
{
_close( nFile );
return false;
}
_close( nFile );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Load a game configuration file (with fail-safes)
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CGameConfigManager::LoadConfigsInternal( const char *baseDir, bool bRecursiveCall )
{
// Init the config if it doesn't exist
if ( !IsLoaded() )
{
m_pData = new KeyValues( GAME_CONFIG_FILENAME );
if ( !IsLoaded() )
{
m_LoadStatus = LOADSTATUS_ERROR;
return false;
}
}
// Clear it out
m_pData->Clear();
// Build our default directory
if ( baseDir != NULL && baseDir[0] != NULL )
{
SetBaseDirectory( baseDir );
}
// Make a full path name
char szPath[MAX_PATH];
Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", GetBaseDirectory(), GAME_CONFIG_FILENAME );
bool bLoaded = false;
CUtlBuffer buffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
if ( ReadUtlBufferFromFile( buffer, szPath ) )
{
bLoaded = m_pData->LoadFromBuffer( szPath, buffer, NULL, NULL );
}
if ( !bLoaded )
{
// Attempt to re-create the configs
if ( CreateAllDefaultConfigs() )
{
// Only allow this once
if ( !bRecursiveCall )
return LoadConfigsInternal( baseDir, true );
// Version the config.
VersionConfig();
}
m_LoadStatus = LOADSTATUS_ERROR;
return false;
}
else
{
// Check to see if the gameconfig.txt is up to date.
UpdateConfigsInternal();
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Add to the current config.
//-----------------------------------------------------------------------------
void CGameConfigManager::UpdateConfigsInternal( void )
{
// Check to a valid gameconfig.txt file buffer.
if ( !IsLoaded() )
return;
// Check for version first. If the version is up to date, it is assumed to be accurate
if ( IsConfigCurrent() )
return;
KeyValues *pGameBlock = GetGameBlock();
if ( !pGameBlock )
{
// If we don't have a game block, reset the config file.
ResetConfigs();
return;
}
KeyValues *pDefaultBlock = new KeyValues( "DefaultConfigs" );
if ( pDefaultBlock != NULL )
{
// Compile our default configurations
GetDefaultGameBlock( pDefaultBlock );
// Compare our default block to our current configs
KeyValues *pNextSubKey = pDefaultBlock->GetFirstTrueSubKey();
while ( pNextSubKey != NULL )
{
// If we already have the name, we don't care about it
if ( pGameBlock->FindKey( pNextSubKey->GetName() ) )
{
// Advance by one key
pNextSubKey = pNextSubKey->GetNextTrueSubKey();
continue;
}
// Copy the data through to our game block
KeyValues *pKeyCopy = pNextSubKey->MakeCopy();
pGameBlock->AddSubKey( pKeyCopy );
// Advance by one key
pNextSubKey = pNextSubKey->GetNextTrueSubKey();
}
// All done
pDefaultBlock->deleteThis();
}
// Save the new config.
SaveConfigs();
// Add the new version as we have been updated.
VersionConfig();
}
//-----------------------------------------------------------------------------
// Purpose: Update the gameconfig.txt version number.
//-----------------------------------------------------------------------------
void CGameConfigManager::VersionConfig( void )
{
// Check to a valid gameconfig.txt file buffer.
if ( !IsLoaded() )
return;
// Look for the a version key value pair and update it.
KeyValues *pKeyVersion = m_pData->FindKey( TOKEN_SDK_VERSION );
// Update the already existing version key value pair.
if ( pKeyVersion )
{
if ( pKeyVersion->GetInt() == m_eSDKEpoch )
return;
m_pData->SetInt( TOKEN_SDK_VERSION, m_eSDKEpoch );
}
// Create a new version key value pair.
else
{
m_pData->SetInt( TOKEN_SDK_VERSION, m_eSDKEpoch );
}
// Save the configuration.
SaveConfigs();
}
//-----------------------------------------------------------------------------
// Purpose: Check to see if the version of the gameconfig.txt is up to date.
//-----------------------------------------------------------------------------
bool CGameConfigManager::IsConfigCurrent( void )
{
// Check to a valid gameconfig.txt file buffer.
if ( !IsLoaded() )
return false;
KeyValues *pKeyValue = m_pData->FindKey( TOKEN_SDK_VERSION );
if ( !pKeyValue )
return false;
int nVersion = pKeyValue->GetInt();
if ( nVersion == m_eSDKEpoch )
return true;
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Get the base path for a default config's install (handling steam's paths)
//-----------------------------------------------------------------------------
void CGameConfigManager::GetRootGameDirectory( char *out, size_t outLen, const char *rootDir )
{
Q_strncpy( out, rootDir, outLen );
}
//-----------------------------------------------------------------------------
// Purpose: Get the base path for a default config's content sources (handling steam's paths)
//-----------------------------------------------------------------------------
void CGameConfigManager::GetRootContentDirectory( char *out, size_t outLen, const char *rootDir )
{
// Steam install is different
if ( g_pFullFileSystem )
{
Q_snprintf( out, outLen, "%s\\sourcesdk_content", rootDir );
}
else
{
Q_snprintf( out, outLen, "%s\\content", rootDir );
}
}
// Default game configuration template
const char szDefaultConfigText[] =
"\"%gamename%\"\
{\
\"GameDir\" \"%gamedir%\"\
\"Hammer\"\
{\
\"TextureFormat\" \"5\"\
\"MapFormat\" \"4\"\
\"DefaultTextureScale\" \"0.250000\"\
\"DefaultLightmapScale\" \"16\"\
\"DefaultSolidEntity\" \"func_detail\"\
\"DefaultPointEntity\" \"%defaultpointentity%\"\
\"GameExeDir\" \"%gameexe%\"\
\"MapDir\" \"%gamemaps%\"\
\"CordonTexture\" \"tools\\toolsskybox\"\
\"MaterialExcludeCount\" \"0\"\
\"GameExe\" \"%gameEXE%\"\
\"BSP\" \"%bspdir%\"\
\"Vis\" \"%visdir%\"\
\"Light\" \"%lightdir%\"\
}}";
// NOTE: This function could use some re-write, it can't handle non-retail paths well
//-----------------------------------------------------------------------------
// Purpose: Add a templated default configuration with proper paths
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CGameConfigManager::AddDefaultConfig( const defaultConfigInfo_t &info, KeyValues *out, const char *rootDirectory, const char *gameExeDir )
{
// NOTE: Freed by head keyvalue
KeyValues *newConfig = new KeyValues( info.gameName );
if ( newConfig->LoadFromBuffer( "defaultcfg.txt", szDefaultConfigText ) == false )
return false;
newConfig->SetName( info.gameName );
// Game's root directory (with special steam name handling)
char rootGameDir[MAX_PATH];
GetRootGameDirectory( rootGameDir, sizeof( rootGameDir ), rootDirectory );
// Game's content directory
char contentRootDir[MAX_PATH];
GetRootContentDirectory( contentRootDir, sizeof( contentRootDir ), rootDirectory );
char szPath[MAX_PATH];
// Game directory
Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", rootGameDir, info.gameDir );
if ( !g_pFullFileSystem->IsDirectory( szPath ) )
return false;
newConfig->SetString( "GameDir", szPath );
// Create the Hammer portion of this block
KeyValues *hammerBlock = newConfig->FindKey( "Hammer" );
if ( hammerBlock == NULL )
return false;
hammerBlock->SetString( "GameExeDir", gameExeDir );
// Fill in the proper default point entity
hammerBlock->SetString( "DefaultPointEntity", info.defaultPointEntity );
// Fill in the default VMF directory
char contentMapDir[MAX_PATH];
Q_snprintf( contentMapDir, sizeof( contentMapDir ), "%s\\%s\\mapsrc", contentRootDir, info.gameDir );
hammerBlock->SetString( "MapDir", contentMapDir );
Q_snprintf( szPath, sizeof( szPath ), "%s\\%s\\maps", rootGameDir, info.gameDir );
hammerBlock->SetString( "BSPDir", szPath );
// Fill in the game executable
Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", gameExeDir, info.exeName );
hammerBlock->SetString( "GameEXE", szPath );
//Fill in game FGDs
if ( info.FGD[0] != '\0' )
{
Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", GetBaseDirectory(), info.FGD );
hammerBlock->SetString( "GameData0", szPath );
}
// Fill in the tools path
Q_snprintf( szPath, sizeof( szPath ), "%s\\vbsp.exe", GetBaseDirectory() );
hammerBlock->SetString( "BSP", szPath );
Q_snprintf( szPath, sizeof( szPath ), "%s\\vvis.exe", GetBaseDirectory() );
hammerBlock->SetString( "Vis", szPath );
Q_snprintf( szPath, sizeof( szPath ), "%s\\vrad.exe", GetBaseDirectory() );
hammerBlock->SetString( "Light", szPath );
// Get our insertion point
KeyValues *insertSpot = out->GetFirstTrueSubKey();
// Set this as the sub key if there's nothing already there
if ( insertSpot == NULL )
{
out->AddSubKey( newConfig );
}
else
{
// Find the last subkey
while ( insertSpot->GetNextTrueSubKey() )
{
insertSpot = insertSpot->GetNextTrueSubKey();
}
// Become a peer to it
insertSpot->SetNextKey( newConfig );
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Determines whether the requested appID is installed on this computer
// Input : nAppID - ID to verify
// Output : Returns true if installed, false if not.
//-----------------------------------------------------------------------------
bool CGameConfigManager::IsAppSubscribed( int nAppID )
{
bool bIsSubscribed = false;
if ( steamapicontext && steamapicontext->SteamApps() )
{
// See if specified app is installed
bIsSubscribed = steamapicontext->SteamApps()->BIsSubscribedApp( nAppID );
}
else
{
// If we aren't running FileSystem Steam then we must be doing internal development. Give everything.
bIsSubscribed = true;
}
return bIsSubscribed;
}
//-----------------------------------------------------------------------------
// Purpose: Create default configurations for all Valve retail applications
//-----------------------------------------------------------------------------
bool CGameConfigManager::CreateAllDefaultConfigs( void )
{
bool bRetVal = true;
// Start our new block
KeyValues *configBlock = new KeyValues( "Configs" );
KeyValues *gameBlock = configBlock->CreateNewKey();
gameBlock->SetName( "Games" );
GetDefaultGameBlock( gameBlock );
bRetVal = !gameBlock->IsEmpty();
// Make a full path name
char szPath[MAX_PATH];
Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", GetBaseDirectory(), GAME_CONFIG_FILENAME );
CUtlBuffer buffer;
configBlock->RecursiveSaveToFile( buffer, 0 );
SaveUtlBufferToFile( buffer, szPath );
configBlock->deleteThis();
m_LoadStatus = LOADSTATUS_CREATED;
return bRetVal;
}
//-----------------------------------------------------------------------------
// Purpose: Load game information from an INI file
//-----------------------------------------------------------------------------
bool CGameConfigManager::ConvertGameConfigsINI( void )
{
const char *iniFilePath = GetIniFilePath();
// Load our INI file
int nNumConfigs = GetPrivateProfileInt( "Configs", "NumConfigs", 0, iniFilePath );
if ( nNumConfigs <= 0 )
return false;
// Build a new keyvalue file
KeyValues *headBlock = new KeyValues( "Configs" );
// Create the block for games
KeyValues *gamesBlock = headBlock->CreateNewKey( );
gamesBlock->SetName( "Games" );
int i;
int nStrlen;
char szSectionName[MAX_PATH];
char textBuffer[MAX_PATH];
// Parse all the configs
for ( int nConfig = 0; nConfig < nNumConfigs; nConfig++ )
{
// Each came configuration is stored in a different section, named "GameConfig0..GameConfigN".
// If the "Name" key exists in this section, try to load the configuration from this section.
sprintf(szSectionName, "GameConfig%d", nConfig);
int nCount = GetPrivateProfileString(szSectionName, "Name", "", textBuffer, sizeof(textBuffer), iniFilePath);
if (nCount > 0)
{
// Make a new section
KeyValues *subGame = gamesBlock->CreateNewKey();
subGame->SetName( textBuffer );
GetPrivateProfileString( szSectionName, "ModDir", "", textBuffer, sizeof(textBuffer), iniFilePath);
// Add the mod dir
subGame->SetString( "GameDir", textBuffer );
// Start a block for Hammer settings
KeyValues *hammerBlock = subGame->CreateNewKey();
hammerBlock->SetName( "Hammer" );
i = 0;
// Get all FGDs
do
{
char szGameData[MAX_PATH];
sprintf( szGameData, "GameData%d", i );
nStrlen = GetPrivateProfileString( szSectionName, szGameData, "", textBuffer, sizeof(textBuffer), iniFilePath );
if ( nStrlen > 0 )
{
hammerBlock->SetString( szGameData, textBuffer );
i++;
}
} while ( nStrlen > 0 );
hammerBlock->SetInt( "TextureFormat", GetPrivateProfileInt( szSectionName, "TextureFormat", 5 /*FIXME: tfVMT*/, iniFilePath ) );
hammerBlock->SetInt( "MapFormat", GetPrivateProfileInt( szSectionName, "MapFormat", 4 /*FIXME: mfHalfLife2*/, iniFilePath ) );
// Default texture scale
GetPrivateProfileString( szSectionName, "DefaultTextureScale", "1", textBuffer, sizeof(textBuffer), iniFilePath );
float defaultTextureScale = (float) atof( textBuffer );
if ( defaultTextureScale == 0 )
{
defaultTextureScale = 1.0f;
}
hammerBlock->SetFloat( "DefaultTextureScale", defaultTextureScale );
hammerBlock->SetInt( "DefaultLightmapScale", GetPrivateProfileInt( szSectionName, "DefaultLightmapScale", 16 /*FIXME: DEFAULT_LIGHTMAP_SCALE*/, iniFilePath ) );
GetPrivateProfileString( szSectionName, "GameExe", "", textBuffer, sizeof(textBuffer), iniFilePath );
hammerBlock->SetString( "GameExe", textBuffer );
GetPrivateProfileString( szSectionName, "DefaultSolidEntity", "", textBuffer, sizeof(textBuffer), iniFilePath );
hammerBlock->SetString( "DefaultSolidEntity", textBuffer );
GetPrivateProfileString( szSectionName, "DefaultPointEntity", "", textBuffer, sizeof(textBuffer), iniFilePath );
hammerBlock->SetString( "DefaultPointEntity", textBuffer );
GetPrivateProfileString( szSectionName, "BSP", "", textBuffer, sizeof(textBuffer), iniFilePath );
hammerBlock->SetString( "BSP", textBuffer );
GetPrivateProfileString( szSectionName, "Vis", "", textBuffer, sizeof(textBuffer), iniFilePath );
hammerBlock->SetString( "Vis", textBuffer );
GetPrivateProfileString( szSectionName, "Light", "", textBuffer, sizeof(textBuffer), iniFilePath );
hammerBlock->SetString( "Light", textBuffer );
GetPrivateProfileString( szSectionName, "GameExeDir", "", textBuffer, sizeof(textBuffer), iniFilePath );
hammerBlock->SetString( "GameExeDir", textBuffer );
GetPrivateProfileString( szSectionName, "MapDir", "", textBuffer, sizeof(textBuffer), iniFilePath );
hammerBlock->SetString( "MapDir", textBuffer );
GetPrivateProfileString( szSectionName, "BSPDir", "", textBuffer, sizeof(textBuffer), iniFilePath );
hammerBlock->SetString( "BSPDir", textBuffer );
GetPrivateProfileString( szSectionName, "CordonTexture", "", textBuffer, sizeof(textBuffer), iniFilePath );
hammerBlock->SetString( "CordonTexture", textBuffer );
GetPrivateProfileString( szSectionName, "MaterialExcludeCount", "0", textBuffer, sizeof(textBuffer), iniFilePath );
int materialExcludeCount = atoi( textBuffer );
hammerBlock->SetInt( "MaterialExcludeCount", materialExcludeCount );
char excludeDir[MAX_PATH];
// Write out all excluded directories
for( i = 0; i < materialExcludeCount; i++ )
{
sprintf( &excludeDir[0], "-MaterialExcludeDir%d", i );
GetPrivateProfileString( szSectionName, excludeDir, "", textBuffer, sizeof( textBuffer ), iniFilePath );
hammerBlock->SetString( excludeDir, textBuffer );
}
}
}
// Make a full path name
char szPath[MAX_PATH];
Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", GetBaseDirectory(), GAME_CONFIG_FILENAME );
CUtlBuffer buffer;
headBlock->RecursiveSaveToFile( buffer, 0 );
SaveUtlBufferToFile( buffer, szPath );
// Rename the old INI file
char newFilePath[MAX_PATH];
Q_snprintf( newFilePath, sizeof( newFilePath ), "%s.OLD", iniFilePath );
rename( iniFilePath, newFilePath );
// Notify that we were converted
m_LoadStatus = LOADSTATUS_CONVERTED;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Write out a game configuration file
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CGameConfigManager::SaveConfigs( const char *baseDir )
{
if ( !IsLoaded() )
return false;
// Build our default directory
if ( baseDir != NULL && baseDir[0] != NULL )
{
SetBaseDirectory( baseDir );
}
// Make a full path name
char szPath[MAX_PATH];
Q_strncpy( szPath, GetBaseDirectory(), sizeof(szPath) );
Q_AppendSlash( szPath, sizeof(szPath) );
Q_strncat( szPath, GAME_CONFIG_FILENAME, sizeof( szPath ), COPY_ALL_CHARACTERS );
CUtlBuffer buffer;
m_pData->RecursiveSaveToFile( buffer, 0 );
return SaveUtlBufferToFile( buffer, szPath );
}
//-----------------------------------------------------------------------------
// Purpose: Find the directory our .exe is based out of
//-----------------------------------------------------------------------------
const char *CGameConfigManager::GetBaseDirectory( void )
{
return m_szBaseDirectory;
}
//-----------------------------------------------------------------------------
// Purpose: Find the root directory
//-----------------------------------------------------------------------------
const char *CGameConfigManager::GetRootDirectory( void )
{
static char path[MAX_PATH] = {0};
if ( path[0] == 0 )
{
Q_strncpy( path, GetBaseDirectory(), sizeof( path ) );
Q_StripLastDir( path, sizeof( path ) ); // Get rid of the 'bin' directory
Q_StripTrailingSlash( path );
}
return path;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the game configuation block
//-----------------------------------------------------------------------------
KeyValues *CGameConfigManager::GetGameBlock( void )
{
if ( !IsLoaded() )
return NULL;
return ( m_pData->FindKey( TOKEN_GAMES, true ) );
}
//-----------------------------------------------------------------------------
// Purpose: Returns a piece of the game configuation block of the given name
// Input : *keyName - name of the block to return
//-----------------------------------------------------------------------------
KeyValues *CGameConfigManager::GetGameSubBlock( const char *keyName )
{
if ( !IsLoaded() )
return NULL;
KeyValues *pGameBlock = GetGameBlock();
if ( pGameBlock == NULL )
return NULL;
// Return the data
KeyValues *pSubBlock = pGameBlock->FindKey( keyName );
return pSubBlock;
}
//-----------------------------------------------------------------------------
// Purpose: Get the gamecfg.ini file for conversion
//-----------------------------------------------------------------------------
const char *CGameConfigManager::GetIniFilePath( void )
{
static char iniFilePath[MAX_PATH] = {0};
if ( iniFilePath[0] == 0 )
{
Q_strncpy( iniFilePath, GetBaseDirectory(), sizeof( iniFilePath ) );
Q_strncat( iniFilePath, "\\gamecfg.ini", sizeof( iniFilePath ), COPY_ALL_CHARACTERS );
}
return iniFilePath;
}
//-----------------------------------------------------------------------------
// Purpose: Deletes the current config and recreates it with default values
//-----------------------------------------------------------------------------
bool CGameConfigManager::ResetConfigs( const char *baseDir /*= NULL*/ )
{
// Build our default directory
if ( baseDir != NULL && baseDir[0] != NULL )
{
SetBaseDirectory( baseDir );
}
// Make a full path name
char szPath[MAX_PATH];
Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", GetBaseDirectory(), GAME_CONFIG_FILENAME );
// Delete the file
if ( unlink( szPath ) )
return false;
// Load the file again (causes defaults to be created)
if ( LoadConfigsInternal( baseDir, false ) == false )
return false;
// Save it out
return SaveConfigs( baseDir );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameConfigManager::SetBaseDirectory( const char *pDirectory )
{
// Clear it
if ( pDirectory == NULL || pDirectory[0] == '\0' )
{
m_szBaseDirectory[0] = '\0';
return;
}
// Copy it
Q_strncpy( m_szBaseDirectory, pDirectory, sizeof( m_szBaseDirectory ) );
Q_StripTrailingSlash( m_szBaseDirectory );
}
//-----------------------------------------------------------------------------
// Purpose: Create a block of keyvalues containing our default configurations
// Output : A block of keyvalues
//-----------------------------------------------------------------------------
bool CGameConfigManager::GetDefaultGameBlock( KeyValues *pIn )
{
CUtlVector<defaultConfigInfo_t> defaultConfigs;
// Add HL2 games to list
defaultConfigs.AddToTail( HL2DMInfo );
defaultConfigs.AddToTail( HL2Info );
defaultConfigs.AddToTail( Episode1Info );
defaultConfigs.AddToTail( Episode2Info );
defaultConfigs.AddToTail( PortalInfo );
defaultConfigs.AddToTail( SourceTestInfo );
// Add TF2 games to list
defaultConfigs.AddToTail( TF2Info );
defaultConfigs.AddToTail( DODInfo );
defaultConfigs.AddToTail( CStrikeInfo );
if ( pIn == NULL )
return false;
char szPath[MAX_PATH];
// Add all default configs
int nNumConfigs = defaultConfigs.Count();
for ( int i = 0; i < nNumConfigs; i++ )
{
// If it's installed, add it
if ( IsAppSubscribed( defaultConfigs[i].steamAppID ) )
{
GetRootGameDirectory( szPath, sizeof( szPath ), GetRootDirectory() );
AddDefaultConfig( defaultConfigs[i], pIn, GetRootDirectory(), szPath );
}
}
return true;
}