summaryrefslogtreecommitdiff
path: root/common/ConfigManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'common/ConfigManager.cpp')
-rw-r--r--common/ConfigManager.cpp922
1 files changed, 922 insertions, 0 deletions
diff --git a/common/ConfigManager.cpp b/common/ConfigManager.cpp
new file mode 100644
index 0000000..08183a7
--- /dev/null
+++ b/common/ConfigManager.cpp
@@ -0,0 +1,922 @@
+//========= 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;
+}