diff options
Diffstat (limited to 'common/ConfigManager.cpp')
| -rw-r--r-- | common/ConfigManager.cpp | 922 |
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; +} |