Counter Strike : Global Offensive Source Code
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.

977 lines
28 KiB

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