Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

922 lines
27 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include <windows.h>
  7. #include "interface.h"
  8. #include "tier0/icommandline.h"
  9. #include "filesystem_tools.h"
  10. #include "KeyValues.h"
  11. #include "tier1/utlbuffer.h"
  12. #include <io.h>
  13. #include <fcntl.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <stdio.h>
  17. #include "ConfigManager.h"
  18. #include "SourceAppInfo.h"
  19. #include "steam/steam_api.h"
  20. extern CSteamAPIContext *steamapicontext;
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include <tier0/memdbgon.h>
  23. #define GAME_CONFIG_FILENAME "GameConfig.txt"
  24. #define TOKEN_SDK_VERSION "SDKVersion"
  25. // Version history:
  26. // 0 - Initial release
  27. // 1 - Versioning added, DoD configuration added
  28. // 2 - Ep1 added
  29. // 3 - Ep2, TF2, and Portal added
  30. // 4 - TF2 moved to its own engine
  31. #define SDK_LAUNCHER_VERSION 5
  32. // Half-Life 2
  33. defaultConfigInfo_t HL2Info =
  34. {
  35. "Half-Life 2",
  36. "hl2",
  37. "halflife2.fgd",
  38. "info_player_start",
  39. "hl2.exe",
  40. GetAppSteamAppId( k_App_HL2 )
  41. };
  42. // Counter-Strike: Source
  43. defaultConfigInfo_t CStrikeInfo =
  44. {
  45. "Counter-Strike: Source",
  46. "cstrike",
  47. "cstrike.fgd",
  48. "info_player_terrorist",
  49. "hl2.exe",
  50. GetAppSteamAppId( k_App_CSS )
  51. };
  52. //Half-Life 2: Deathmatch
  53. defaultConfigInfo_t HL2DMInfo =
  54. {
  55. "Half-Life 2: Deathmatch",
  56. "hl2mp",
  57. "hl2mp.fgd",
  58. "info_player_deathmatch",
  59. "hl2.exe",
  60. GetAppSteamAppId( k_App_HL2MP )
  61. };
  62. // Day of Defeat: Source
  63. defaultConfigInfo_t DODInfo =
  64. {
  65. "Day of Defeat: Source",
  66. "dod",
  67. "dod.fgd",
  68. "info_player_allies",
  69. "hl2.exe",
  70. GetAppSteamAppId( k_App_DODS )
  71. };
  72. // Half-Life 2 Episode 1
  73. defaultConfigInfo_t Episode1Info =
  74. {
  75. "Half-Life 2: Episode One",
  76. "episodic",
  77. "halflife2.fgd",
  78. "info_player_start",
  79. "hl2.exe",
  80. GetAppSteamAppId( k_App_HL2_EP1 )
  81. };
  82. // Half-Life 2 Episode 2
  83. defaultConfigInfo_t Episode2Info =
  84. {
  85. "Half-Life 2: Episode Two",
  86. "ep2",
  87. "halflife2.fgd",
  88. "info_player_start",
  89. "hl2.exe",
  90. GetAppSteamAppId( k_App_HL2_EP2 )
  91. };
  92. // Team Fortress 2
  93. defaultConfigInfo_t TF2Info =
  94. {
  95. "Team Fortress 2",
  96. "tf",
  97. "tf.fgd",
  98. "info_player_teamspawn",
  99. "hl2.exe",
  100. GetAppSteamAppId( k_App_TF2 )
  101. };
  102. // Portal
  103. defaultConfigInfo_t PortalInfo =
  104. {
  105. "Portal",
  106. "portal",
  107. "portal.fgd",
  108. "info_player_start",
  109. "hl2.exe",
  110. GetAppSteamAppId( k_App_PORTAL )
  111. };
  112. // Portal
  113. defaultConfigInfo_t SourceTestInfo =
  114. {
  115. "SourceTest",
  116. "sourcetest",
  117. "halflife2.fgd",
  118. "info_player_start",
  119. "hl2.exe",
  120. 243730
  121. };
  122. //-----------------------------------------------------------------------------
  123. // Constructor
  124. //-----------------------------------------------------------------------------
  125. CGameConfigManager::CGameConfigManager( void ) : m_pData( NULL ), m_LoadStatus( LOADSTATUS_NONE )
  126. {
  127. // Start with default directory
  128. GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), m_szBaseDirectory, sizeof( m_szBaseDirectory ) );
  129. Q_StripLastDir( m_szBaseDirectory, sizeof( m_szBaseDirectory ) ); // Get rid of the filename.
  130. Q_StripTrailingSlash( m_szBaseDirectory );
  131. m_eSDKEpoch = (eSDKEpochs) SDK_LAUNCHER_VERSION;
  132. }
  133. //-----------------------------------------------------------------------------
  134. // Destructor
  135. //-----------------------------------------------------------------------------
  136. CGameConfigManager::~CGameConfigManager( void )
  137. {
  138. // Release the keyvalues
  139. if ( m_pData != NULL )
  140. {
  141. m_pData->deleteThis();
  142. }
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Purpose: Config loading interface
  146. // Input : *baseDir - base directory for our file
  147. // Output : Returns true on success, false on failure.
  148. //-----------------------------------------------------------------------------
  149. bool CGameConfigManager::LoadConfigs( const char *baseDir )
  150. {
  151. return LoadConfigsInternal( baseDir, false );
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose: Loads a file into the given utlbuffer.
  155. // Output : Returns true on success, false on failure.
  156. //-----------------------------------------------------------------------------
  157. bool ReadUtlBufferFromFile( CUtlBuffer &buffer, const char *szPath )
  158. {
  159. struct _stat fileInfo;
  160. if ( _stat( szPath, &fileInfo ) == -1 )
  161. {
  162. return false;
  163. }
  164. buffer.EnsureCapacity( fileInfo.st_size );
  165. int nFile = _open( szPath, _O_BINARY | _O_RDONLY );
  166. if ( nFile == -1 )
  167. {
  168. return false;
  169. }
  170. if ( _read( nFile, buffer.Base(), fileInfo.st_size ) != fileInfo.st_size )
  171. {
  172. _close( nFile );
  173. return false;
  174. }
  175. _close( nFile );
  176. buffer.SeekPut( CUtlBuffer::SEEK_HEAD, fileInfo.st_size );
  177. return true;
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose: Loads a file into the given utlbuffer.
  181. // Output : Returns true on success, false on failure.
  182. //-----------------------------------------------------------------------------
  183. bool SaveUtlBufferToFile( CUtlBuffer &buffer, const char *szPath )
  184. {
  185. int nFile = _open( szPath, _O_TEXT | _O_CREAT | _O_TRUNC | _O_RDWR, _S_IWRITE );
  186. if ( nFile == -1 )
  187. {
  188. return false;
  189. }
  190. int nSize = buffer.TellMaxPut();
  191. if ( _write( nFile, buffer.Base(), nSize ) < nSize )
  192. {
  193. _close( nFile );
  194. return false;
  195. }
  196. _close( nFile );
  197. return true;
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Purpose: Load a game configuration file (with fail-safes)
  201. // Output : Returns true on success, false on failure.
  202. //-----------------------------------------------------------------------------
  203. bool CGameConfigManager::LoadConfigsInternal( const char *baseDir, bool bRecursiveCall )
  204. {
  205. // Init the config if it doesn't exist
  206. if ( !IsLoaded() )
  207. {
  208. m_pData = new KeyValues( GAME_CONFIG_FILENAME );
  209. if ( !IsLoaded() )
  210. {
  211. m_LoadStatus = LOADSTATUS_ERROR;
  212. return false;
  213. }
  214. }
  215. // Clear it out
  216. m_pData->Clear();
  217. // Build our default directory
  218. if ( baseDir != NULL && baseDir[0] != NULL )
  219. {
  220. SetBaseDirectory( baseDir );
  221. }
  222. // Make a full path name
  223. char szPath[MAX_PATH];
  224. Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", GetBaseDirectory(), GAME_CONFIG_FILENAME );
  225. bool bLoaded = false;
  226. CUtlBuffer buffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
  227. if ( ReadUtlBufferFromFile( buffer, szPath ) )
  228. {
  229. bLoaded = m_pData->LoadFromBuffer( szPath, buffer, NULL, NULL );
  230. }
  231. if ( !bLoaded )
  232. {
  233. // Attempt to re-create the configs
  234. if ( CreateAllDefaultConfigs() )
  235. {
  236. // Only allow this once
  237. if ( !bRecursiveCall )
  238. return LoadConfigsInternal( baseDir, true );
  239. // Version the config.
  240. VersionConfig();
  241. }
  242. m_LoadStatus = LOADSTATUS_ERROR;
  243. return false;
  244. }
  245. else
  246. {
  247. // Check to see if the gameconfig.txt is up to date.
  248. UpdateConfigsInternal();
  249. }
  250. return true;
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Purpose: Add to the current config.
  254. //-----------------------------------------------------------------------------
  255. void CGameConfigManager::UpdateConfigsInternal( void )
  256. {
  257. // Check to a valid gameconfig.txt file buffer.
  258. if ( !IsLoaded() )
  259. return;
  260. // Check for version first. If the version is up to date, it is assumed to be accurate
  261. if ( IsConfigCurrent() )
  262. return;
  263. KeyValues *pGameBlock = GetGameBlock();
  264. if ( !pGameBlock )
  265. {
  266. // If we don't have a game block, reset the config file.
  267. ResetConfigs();
  268. return;
  269. }
  270. KeyValues *pDefaultBlock = new KeyValues( "DefaultConfigs" );
  271. if ( pDefaultBlock != NULL )
  272. {
  273. // Compile our default configurations
  274. GetDefaultGameBlock( pDefaultBlock );
  275. // Compare our default block to our current configs
  276. KeyValues *pNextSubKey = pDefaultBlock->GetFirstTrueSubKey();
  277. while ( pNextSubKey != NULL )
  278. {
  279. // If we already have the name, we don't care about it
  280. if ( pGameBlock->FindKey( pNextSubKey->GetName() ) )
  281. {
  282. // Advance by one key
  283. pNextSubKey = pNextSubKey->GetNextTrueSubKey();
  284. continue;
  285. }
  286. // Copy the data through to our game block
  287. KeyValues *pKeyCopy = pNextSubKey->MakeCopy();
  288. pGameBlock->AddSubKey( pKeyCopy );
  289. // Advance by one key
  290. pNextSubKey = pNextSubKey->GetNextTrueSubKey();
  291. }
  292. // All done
  293. pDefaultBlock->deleteThis();
  294. }
  295. // Save the new config.
  296. SaveConfigs();
  297. // Add the new version as we have been updated.
  298. VersionConfig();
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Purpose: Update the gameconfig.txt version number.
  302. //-----------------------------------------------------------------------------
  303. void CGameConfigManager::VersionConfig( void )
  304. {
  305. // Check to a valid gameconfig.txt file buffer.
  306. if ( !IsLoaded() )
  307. return;
  308. // Look for the a version key value pair and update it.
  309. KeyValues *pKeyVersion = m_pData->FindKey( TOKEN_SDK_VERSION );
  310. // Update the already existing version key value pair.
  311. if ( pKeyVersion )
  312. {
  313. if ( pKeyVersion->GetInt() == m_eSDKEpoch )
  314. return;
  315. m_pData->SetInt( TOKEN_SDK_VERSION, m_eSDKEpoch );
  316. }
  317. // Create a new version key value pair.
  318. else
  319. {
  320. m_pData->SetInt( TOKEN_SDK_VERSION, m_eSDKEpoch );
  321. }
  322. // Save the configuration.
  323. SaveConfigs();
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Purpose: Check to see if the version of the gameconfig.txt is up to date.
  327. //-----------------------------------------------------------------------------
  328. bool CGameConfigManager::IsConfigCurrent( void )
  329. {
  330. // Check to a valid gameconfig.txt file buffer.
  331. if ( !IsLoaded() )
  332. return false;
  333. KeyValues *pKeyValue = m_pData->FindKey( TOKEN_SDK_VERSION );
  334. if ( !pKeyValue )
  335. return false;
  336. int nVersion = pKeyValue->GetInt();
  337. if ( nVersion == m_eSDKEpoch )
  338. return true;
  339. return false;
  340. }
  341. //-----------------------------------------------------------------------------
  342. // Purpose: Get the base path for a default config's install (handling steam's paths)
  343. //-----------------------------------------------------------------------------
  344. void CGameConfigManager::GetRootGameDirectory( char *out, size_t outLen, const char *rootDir )
  345. {
  346. Q_strncpy( out, rootDir, outLen );
  347. }
  348. //-----------------------------------------------------------------------------
  349. // Purpose: Get the base path for a default config's content sources (handling steam's paths)
  350. //-----------------------------------------------------------------------------
  351. void CGameConfigManager::GetRootContentDirectory( char *out, size_t outLen, const char *rootDir )
  352. {
  353. // Steam install is different
  354. if ( g_pFullFileSystem )
  355. {
  356. Q_snprintf( out, outLen, "%s\\sourcesdk_content", rootDir );
  357. }
  358. else
  359. {
  360. Q_snprintf( out, outLen, "%s\\content", rootDir );
  361. }
  362. }
  363. // Default game configuration template
  364. const char szDefaultConfigText[] =
  365. "\"%gamename%\"\
  366. {\
  367. \"GameDir\" \"%gamedir%\"\
  368. \"Hammer\"\
  369. {\
  370. \"TextureFormat\" \"5\"\
  371. \"MapFormat\" \"4\"\
  372. \"DefaultTextureScale\" \"0.250000\"\
  373. \"DefaultLightmapScale\" \"16\"\
  374. \"DefaultSolidEntity\" \"func_detail\"\
  375. \"DefaultPointEntity\" \"%defaultpointentity%\"\
  376. \"GameExeDir\" \"%gameexe%\"\
  377. \"MapDir\" \"%gamemaps%\"\
  378. \"CordonTexture\" \"tools\\toolsskybox\"\
  379. \"MaterialExcludeCount\" \"0\"\
  380. \"GameExe\" \"%gameEXE%\"\
  381. \"BSP\" \"%bspdir%\"\
  382. \"Vis\" \"%visdir%\"\
  383. \"Light\" \"%lightdir%\"\
  384. }}";
  385. // NOTE: This function could use some re-write, it can't handle non-retail paths well
  386. //-----------------------------------------------------------------------------
  387. // Purpose: Add a templated default configuration with proper paths
  388. // Output : Returns true on success, false on failure.
  389. //-----------------------------------------------------------------------------
  390. bool CGameConfigManager::AddDefaultConfig( const defaultConfigInfo_t &info, KeyValues *out, const char *rootDirectory, const char *gameExeDir )
  391. {
  392. // NOTE: Freed by head keyvalue
  393. KeyValues *newConfig = new KeyValues( info.gameName );
  394. if ( newConfig->LoadFromBuffer( "defaultcfg.txt", szDefaultConfigText ) == false )
  395. return false;
  396. newConfig->SetName( info.gameName );
  397. // Game's root directory (with special steam name handling)
  398. char rootGameDir[MAX_PATH];
  399. GetRootGameDirectory( rootGameDir, sizeof( rootGameDir ), rootDirectory );
  400. // Game's content directory
  401. char contentRootDir[MAX_PATH];
  402. GetRootContentDirectory( contentRootDir, sizeof( contentRootDir ), rootDirectory );
  403. char szPath[MAX_PATH];
  404. // Game directory
  405. Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", rootGameDir, info.gameDir );
  406. if ( !g_pFullFileSystem->IsDirectory( szPath ) )
  407. return false;
  408. newConfig->SetString( "GameDir", szPath );
  409. // Create the Hammer portion of this block
  410. KeyValues *hammerBlock = newConfig->FindKey( "Hammer" );
  411. if ( hammerBlock == NULL )
  412. return false;
  413. hammerBlock->SetString( "GameExeDir", gameExeDir );
  414. // Fill in the proper default point entity
  415. hammerBlock->SetString( "DefaultPointEntity", info.defaultPointEntity );
  416. // Fill in the default VMF directory
  417. char contentMapDir[MAX_PATH];
  418. Q_snprintf( contentMapDir, sizeof( contentMapDir ), "%s\\%s\\mapsrc", contentRootDir, info.gameDir );
  419. hammerBlock->SetString( "MapDir", contentMapDir );
  420. Q_snprintf( szPath, sizeof( szPath ), "%s\\%s\\maps", rootGameDir, info.gameDir );
  421. hammerBlock->SetString( "BSPDir", szPath );
  422. // Fill in the game executable
  423. Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", gameExeDir, info.exeName );
  424. hammerBlock->SetString( "GameEXE", szPath );
  425. //Fill in game FGDs
  426. if ( info.FGD[0] != '\0' )
  427. {
  428. Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", GetBaseDirectory(), info.FGD );
  429. hammerBlock->SetString( "GameData0", szPath );
  430. }
  431. // Fill in the tools path
  432. Q_snprintf( szPath, sizeof( szPath ), "%s\\vbsp.exe", GetBaseDirectory() );
  433. hammerBlock->SetString( "BSP", szPath );
  434. Q_snprintf( szPath, sizeof( szPath ), "%s\\vvis.exe", GetBaseDirectory() );
  435. hammerBlock->SetString( "Vis", szPath );
  436. Q_snprintf( szPath, sizeof( szPath ), "%s\\vrad.exe", GetBaseDirectory() );
  437. hammerBlock->SetString( "Light", szPath );
  438. // Get our insertion point
  439. KeyValues *insertSpot = out->GetFirstTrueSubKey();
  440. // Set this as the sub key if there's nothing already there
  441. if ( insertSpot == NULL )
  442. {
  443. out->AddSubKey( newConfig );
  444. }
  445. else
  446. {
  447. // Find the last subkey
  448. while ( insertSpot->GetNextTrueSubKey() )
  449. {
  450. insertSpot = insertSpot->GetNextTrueSubKey();
  451. }
  452. // Become a peer to it
  453. insertSpot->SetNextKey( newConfig );
  454. }
  455. return true;
  456. }
  457. //-----------------------------------------------------------------------------
  458. // Purpose: Determines whether the requested appID is installed on this computer
  459. // Input : nAppID - ID to verify
  460. // Output : Returns true if installed, false if not.
  461. //-----------------------------------------------------------------------------
  462. bool CGameConfigManager::IsAppSubscribed( int nAppID )
  463. {
  464. bool bIsSubscribed = false;
  465. if ( steamapicontext && steamapicontext->SteamApps() )
  466. {
  467. // See if specified app is installed
  468. bIsSubscribed = steamapicontext->SteamApps()->BIsSubscribedApp( nAppID );
  469. }
  470. else
  471. {
  472. // If we aren't running FileSystem Steam then we must be doing internal development. Give everything.
  473. bIsSubscribed = true;
  474. }
  475. return bIsSubscribed;
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose: Create default configurations for all Valve retail applications
  479. //-----------------------------------------------------------------------------
  480. bool CGameConfigManager::CreateAllDefaultConfigs( void )
  481. {
  482. bool bRetVal = true;
  483. // Start our new block
  484. KeyValues *configBlock = new KeyValues( "Configs" );
  485. KeyValues *gameBlock = configBlock->CreateNewKey();
  486. gameBlock->SetName( "Games" );
  487. GetDefaultGameBlock( gameBlock );
  488. bRetVal = !gameBlock->IsEmpty();
  489. // Make a full path name
  490. char szPath[MAX_PATH];
  491. Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", GetBaseDirectory(), GAME_CONFIG_FILENAME );
  492. CUtlBuffer buffer;
  493. configBlock->RecursiveSaveToFile( buffer, 0 );
  494. SaveUtlBufferToFile( buffer, szPath );
  495. configBlock->deleteThis();
  496. m_LoadStatus = LOADSTATUS_CREATED;
  497. return bRetVal;
  498. }
  499. //-----------------------------------------------------------------------------
  500. // Purpose: Load game information from an INI file
  501. //-----------------------------------------------------------------------------
  502. bool CGameConfigManager::ConvertGameConfigsINI( void )
  503. {
  504. const char *iniFilePath = GetIniFilePath();
  505. // Load our INI file
  506. int nNumConfigs = GetPrivateProfileInt( "Configs", "NumConfigs", 0, iniFilePath );
  507. if ( nNumConfigs <= 0 )
  508. return false;
  509. // Build a new keyvalue file
  510. KeyValues *headBlock = new KeyValues( "Configs" );
  511. // Create the block for games
  512. KeyValues *gamesBlock = headBlock->CreateNewKey( );
  513. gamesBlock->SetName( "Games" );
  514. int i;
  515. int nStrlen;
  516. char szSectionName[MAX_PATH];
  517. char textBuffer[MAX_PATH];
  518. // Parse all the configs
  519. for ( int nConfig = 0; nConfig < nNumConfigs; nConfig++ )
  520. {
  521. // Each came configuration is stored in a different section, named "GameConfig0..GameConfigN".
  522. // If the "Name" key exists in this section, try to load the configuration from this section.
  523. sprintf(szSectionName, "GameConfig%d", nConfig);
  524. int nCount = GetPrivateProfileString(szSectionName, "Name", "", textBuffer, sizeof(textBuffer), iniFilePath);
  525. if (nCount > 0)
  526. {
  527. // Make a new section
  528. KeyValues *subGame = gamesBlock->CreateNewKey();
  529. subGame->SetName( textBuffer );
  530. GetPrivateProfileString( szSectionName, "ModDir", "", textBuffer, sizeof(textBuffer), iniFilePath);
  531. // Add the mod dir
  532. subGame->SetString( "GameDir", textBuffer );
  533. // Start a block for Hammer settings
  534. KeyValues *hammerBlock = subGame->CreateNewKey();
  535. hammerBlock->SetName( "Hammer" );
  536. i = 0;
  537. // Get all FGDs
  538. do
  539. {
  540. char szGameData[MAX_PATH];
  541. sprintf( szGameData, "GameData%d", i );
  542. nStrlen = GetPrivateProfileString( szSectionName, szGameData, "", textBuffer, sizeof(textBuffer), iniFilePath );
  543. if ( nStrlen > 0 )
  544. {
  545. hammerBlock->SetString( szGameData, textBuffer );
  546. i++;
  547. }
  548. } while ( nStrlen > 0 );
  549. hammerBlock->SetInt( "TextureFormat", GetPrivateProfileInt( szSectionName, "TextureFormat", 5 /*FIXME: tfVMT*/, iniFilePath ) );
  550. hammerBlock->SetInt( "MapFormat", GetPrivateProfileInt( szSectionName, "MapFormat", 4 /*FIXME: mfHalfLife2*/, iniFilePath ) );
  551. // Default texture scale
  552. GetPrivateProfileString( szSectionName, "DefaultTextureScale", "1", textBuffer, sizeof(textBuffer), iniFilePath );
  553. float defaultTextureScale = (float) atof( textBuffer );
  554. if ( defaultTextureScale == 0 )
  555. {
  556. defaultTextureScale = 1.0f;
  557. }
  558. hammerBlock->SetFloat( "DefaultTextureScale", defaultTextureScale );
  559. hammerBlock->SetInt( "DefaultLightmapScale", GetPrivateProfileInt( szSectionName, "DefaultLightmapScale", 16 /*FIXME: DEFAULT_LIGHTMAP_SCALE*/, iniFilePath ) );
  560. GetPrivateProfileString( szSectionName, "GameExe", "", textBuffer, sizeof(textBuffer), iniFilePath );
  561. hammerBlock->SetString( "GameExe", textBuffer );
  562. GetPrivateProfileString( szSectionName, "DefaultSolidEntity", "", textBuffer, sizeof(textBuffer), iniFilePath );
  563. hammerBlock->SetString( "DefaultSolidEntity", textBuffer );
  564. GetPrivateProfileString( szSectionName, "DefaultPointEntity", "", textBuffer, sizeof(textBuffer), iniFilePath );
  565. hammerBlock->SetString( "DefaultPointEntity", textBuffer );
  566. GetPrivateProfileString( szSectionName, "BSP", "", textBuffer, sizeof(textBuffer), iniFilePath );
  567. hammerBlock->SetString( "BSP", textBuffer );
  568. GetPrivateProfileString( szSectionName, "Vis", "", textBuffer, sizeof(textBuffer), iniFilePath );
  569. hammerBlock->SetString( "Vis", textBuffer );
  570. GetPrivateProfileString( szSectionName, "Light", "", textBuffer, sizeof(textBuffer), iniFilePath );
  571. hammerBlock->SetString( "Light", textBuffer );
  572. GetPrivateProfileString( szSectionName, "GameExeDir", "", textBuffer, sizeof(textBuffer), iniFilePath );
  573. hammerBlock->SetString( "GameExeDir", textBuffer );
  574. GetPrivateProfileString( szSectionName, "MapDir", "", textBuffer, sizeof(textBuffer), iniFilePath );
  575. hammerBlock->SetString( "MapDir", textBuffer );
  576. GetPrivateProfileString( szSectionName, "BSPDir", "", textBuffer, sizeof(textBuffer), iniFilePath );
  577. hammerBlock->SetString( "BSPDir", textBuffer );
  578. GetPrivateProfileString( szSectionName, "CordonTexture", "", textBuffer, sizeof(textBuffer), iniFilePath );
  579. hammerBlock->SetString( "CordonTexture", textBuffer );
  580. GetPrivateProfileString( szSectionName, "MaterialExcludeCount", "0", textBuffer, sizeof(textBuffer), iniFilePath );
  581. int materialExcludeCount = atoi( textBuffer );
  582. hammerBlock->SetInt( "MaterialExcludeCount", materialExcludeCount );
  583. char excludeDir[MAX_PATH];
  584. // Write out all excluded directories
  585. for( i = 0; i < materialExcludeCount; i++ )
  586. {
  587. sprintf( &excludeDir[0], "-MaterialExcludeDir%d", i );
  588. GetPrivateProfileString( szSectionName, excludeDir, "", textBuffer, sizeof( textBuffer ), iniFilePath );
  589. hammerBlock->SetString( excludeDir, textBuffer );
  590. }
  591. }
  592. }
  593. // Make a full path name
  594. char szPath[MAX_PATH];
  595. Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", GetBaseDirectory(), GAME_CONFIG_FILENAME );
  596. CUtlBuffer buffer;
  597. headBlock->RecursiveSaveToFile( buffer, 0 );
  598. SaveUtlBufferToFile( buffer, szPath );
  599. // Rename the old INI file
  600. char newFilePath[MAX_PATH];
  601. Q_snprintf( newFilePath, sizeof( newFilePath ), "%s.OLD", iniFilePath );
  602. rename( iniFilePath, newFilePath );
  603. // Notify that we were converted
  604. m_LoadStatus = LOADSTATUS_CONVERTED;
  605. return true;
  606. }
  607. //-----------------------------------------------------------------------------
  608. // Purpose: Write out a game configuration file
  609. // Output : Returns true on success, false on failure.
  610. //-----------------------------------------------------------------------------
  611. bool CGameConfigManager::SaveConfigs( const char *baseDir )
  612. {
  613. if ( !IsLoaded() )
  614. return false;
  615. // Build our default directory
  616. if ( baseDir != NULL && baseDir[0] != NULL )
  617. {
  618. SetBaseDirectory( baseDir );
  619. }
  620. // Make a full path name
  621. char szPath[MAX_PATH];
  622. Q_strncpy( szPath, GetBaseDirectory(), sizeof(szPath) );
  623. Q_AppendSlash( szPath, sizeof(szPath) );
  624. Q_strncat( szPath, GAME_CONFIG_FILENAME, sizeof( szPath ), COPY_ALL_CHARACTERS );
  625. CUtlBuffer buffer;
  626. m_pData->RecursiveSaveToFile( buffer, 0 );
  627. return SaveUtlBufferToFile( buffer, szPath );
  628. }
  629. //-----------------------------------------------------------------------------
  630. // Purpose: Find the directory our .exe is based out of
  631. //-----------------------------------------------------------------------------
  632. const char *CGameConfigManager::GetBaseDirectory( void )
  633. {
  634. return m_szBaseDirectory;
  635. }
  636. //-----------------------------------------------------------------------------
  637. // Purpose: Find the root directory
  638. //-----------------------------------------------------------------------------
  639. const char *CGameConfigManager::GetRootDirectory( void )
  640. {
  641. static char path[MAX_PATH] = {0};
  642. if ( path[0] == 0 )
  643. {
  644. Q_strncpy( path, GetBaseDirectory(), sizeof( path ) );
  645. Q_StripLastDir( path, sizeof( path ) ); // Get rid of the 'bin' directory
  646. Q_StripTrailingSlash( path );
  647. }
  648. return path;
  649. }
  650. //-----------------------------------------------------------------------------
  651. // Purpose: Returns the game configuation block
  652. //-----------------------------------------------------------------------------
  653. KeyValues *CGameConfigManager::GetGameBlock( void )
  654. {
  655. if ( !IsLoaded() )
  656. return NULL;
  657. return ( m_pData->FindKey( TOKEN_GAMES, true ) );
  658. }
  659. //-----------------------------------------------------------------------------
  660. // Purpose: Returns a piece of the game configuation block of the given name
  661. // Input : *keyName - name of the block to return
  662. //-----------------------------------------------------------------------------
  663. KeyValues *CGameConfigManager::GetGameSubBlock( const char *keyName )
  664. {
  665. if ( !IsLoaded() )
  666. return NULL;
  667. KeyValues *pGameBlock = GetGameBlock();
  668. if ( pGameBlock == NULL )
  669. return NULL;
  670. // Return the data
  671. KeyValues *pSubBlock = pGameBlock->FindKey( keyName );
  672. return pSubBlock;
  673. }
  674. //-----------------------------------------------------------------------------
  675. // Purpose: Get the gamecfg.ini file for conversion
  676. //-----------------------------------------------------------------------------
  677. const char *CGameConfigManager::GetIniFilePath( void )
  678. {
  679. static char iniFilePath[MAX_PATH] = {0};
  680. if ( iniFilePath[0] == 0 )
  681. {
  682. Q_strncpy( iniFilePath, GetBaseDirectory(), sizeof( iniFilePath ) );
  683. Q_strncat( iniFilePath, "\\gamecfg.ini", sizeof( iniFilePath ), COPY_ALL_CHARACTERS );
  684. }
  685. return iniFilePath;
  686. }
  687. //-----------------------------------------------------------------------------
  688. // Purpose: Deletes the current config and recreates it with default values
  689. //-----------------------------------------------------------------------------
  690. bool CGameConfigManager::ResetConfigs( const char *baseDir /*= NULL*/ )
  691. {
  692. // Build our default directory
  693. if ( baseDir != NULL && baseDir[0] != NULL )
  694. {
  695. SetBaseDirectory( baseDir );
  696. }
  697. // Make a full path name
  698. char szPath[MAX_PATH];
  699. Q_snprintf( szPath, sizeof( szPath ), "%s\\%s", GetBaseDirectory(), GAME_CONFIG_FILENAME );
  700. // Delete the file
  701. if ( unlink( szPath ) )
  702. return false;
  703. // Load the file again (causes defaults to be created)
  704. if ( LoadConfigsInternal( baseDir, false ) == false )
  705. return false;
  706. // Save it out
  707. return SaveConfigs( baseDir );
  708. }
  709. //-----------------------------------------------------------------------------
  710. // Purpose:
  711. //-----------------------------------------------------------------------------
  712. void CGameConfigManager::SetBaseDirectory( const char *pDirectory )
  713. {
  714. // Clear it
  715. if ( pDirectory == NULL || pDirectory[0] == '\0' )
  716. {
  717. m_szBaseDirectory[0] = '\0';
  718. return;
  719. }
  720. // Copy it
  721. Q_strncpy( m_szBaseDirectory, pDirectory, sizeof( m_szBaseDirectory ) );
  722. Q_StripTrailingSlash( m_szBaseDirectory );
  723. }
  724. //-----------------------------------------------------------------------------
  725. // Purpose: Create a block of keyvalues containing our default configurations
  726. // Output : A block of keyvalues
  727. //-----------------------------------------------------------------------------
  728. bool CGameConfigManager::GetDefaultGameBlock( KeyValues *pIn )
  729. {
  730. CUtlVector<defaultConfigInfo_t> defaultConfigs;
  731. // Add HL2 games to list
  732. defaultConfigs.AddToTail( HL2DMInfo );
  733. defaultConfigs.AddToTail( HL2Info );
  734. defaultConfigs.AddToTail( Episode1Info );
  735. defaultConfigs.AddToTail( Episode2Info );
  736. defaultConfigs.AddToTail( PortalInfo );
  737. defaultConfigs.AddToTail( SourceTestInfo );
  738. // Add TF2 games to list
  739. defaultConfigs.AddToTail( TF2Info );
  740. defaultConfigs.AddToTail( DODInfo );
  741. defaultConfigs.AddToTail( CStrikeInfo );
  742. if ( pIn == NULL )
  743. return false;
  744. char szPath[MAX_PATH];
  745. // Add all default configs
  746. int nNumConfigs = defaultConfigs.Count();
  747. for ( int i = 0; i < nNumConfigs; i++ )
  748. {
  749. // If it's installed, add it
  750. if ( IsAppSubscribed( defaultConfigs[i].steamAppID ) )
  751. {
  752. GetRootGameDirectory( szPath, sizeof( szPath ), GetRootDirectory() );
  753. AddDefaultConfig( defaultConfigs[i], pIn, GetRootDirectory(), szPath );
  754. }
  755. }
  756. return true;
  757. }