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.

837 lines
22 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include <windows.h>
  7. #include "SDKLauncherDialog.h"
  8. #include "configs.h"
  9. #include <vgui_controls/ComboBox.h>
  10. #include <vgui_controls/ListPanel.h>
  11. #include <vgui_controls/ProgressBox.h>
  12. #include <vgui_controls/MessageBox.h>
  13. #include <vgui_controls/HTML.h>
  14. #include <vgui_controls/CheckButton.h>
  15. #include <vgui_controls/Divider.h>
  16. #include <vgui_controls/menu.h>
  17. #include <vgui/ISurface.h>
  18. #include <vgui/ILocalize.h>
  19. #include "vgui_controls/button.h"
  20. #include <vgui/ISystem.h>
  21. #include <vgui/IVGui.h>
  22. #include <vgui/iinput.h>
  23. #include <KeyValues.h>
  24. #include <FileSystem.h>
  25. #include <io.h>
  26. #include "CreateModWizard.h"
  27. #include "filesystem_tools.h"
  28. #include "min_footprint_files.h"
  29. #include "ConfigManager.h"
  30. #include "filesystem_tools.h"
  31. #include <iregistry.h>
  32. #include <sys/stat.h>
  33. #include "sdklauncher_main.h"
  34. // memdbgon must be the last include file in a .cpp file!!!
  35. #include <tier0/memdbgon.h>
  36. using namespace vgui;
  37. CSDKLauncherDialog *g_pSDKLauncherDialog = NULL;
  38. CGameConfigManager g_ConfigManager;
  39. char g_engineDir[50];
  40. //-----------------------------------------------------------------------------
  41. // Purpose: Retrieves a URL out of the external localization file and opens it in a
  42. // web browser.
  43. // Input : *lpszLocalName - Localized name of the URL to open via shell execution
  44. //-----------------------------------------------------------------------------
  45. void OpenLocalizedURL( const char *lpszLocalName )
  46. {
  47. // Find and convert the localized unicode string
  48. char pURLStr[MAX_PATH];
  49. wchar_t *pURLUni = g_pVGuiLocalize->Find( lpszLocalName );
  50. g_pVGuiLocalize->ConvertUnicodeToANSI( pURLUni, pURLStr, sizeof( pURLStr ) );
  51. // Open the URL through the shell
  52. vgui::system()->ShellExecute( "open", pURLStr );
  53. }
  54. class CResetConfirmationMessageBox : public vgui::Frame
  55. {
  56. public:
  57. typedef vgui::Frame BaseClass;
  58. CResetConfirmationMessageBox( Panel *pParent, const char *pPanelName )
  59. : BaseClass( pParent, pPanelName )
  60. {
  61. SetSize( 200, 200 );
  62. SetMinimumSize( 250, 100 );
  63. SetSizeable( false );
  64. LoadControlSettings( "resetconfirmbox.res" );
  65. }
  66. void OnCommand( const char *command )
  67. {
  68. if ( Q_stricmp( command, "ResetConfigs" ) == 0 )
  69. {
  70. Close();
  71. if ( GetVParent() )
  72. {
  73. PostMessage( GetVParent(), new KeyValues( "Command", "command", "ResetConfigs"));
  74. }
  75. }
  76. else if ( Q_stricmp( command, "MoreInfo" ) == 0 )
  77. {
  78. OpenLocalizedURL( "URL_Reset_Config" );
  79. }
  80. BaseClass::OnCommand( command );
  81. }
  82. };
  83. class CConversionInfoMessageBox : public vgui::Frame
  84. {
  85. public:
  86. typedef vgui::Frame BaseClass;
  87. CConversionInfoMessageBox( Panel *pParent, const char *pPanelName )
  88. : BaseClass( pParent, pPanelName )
  89. {
  90. SetSize( 200, 200 );
  91. SetMinimumSize( 250, 100 );
  92. SetSizeable( false );
  93. LoadControlSettings( "convinfobox.res" );
  94. }
  95. virtual void OnCommand( const char *command )
  96. {
  97. BaseClass::OnCommand( command );
  98. // For some weird reason, this dialog can
  99. if ( Q_stricmp( command, "ShowFAQ" ) == 0 )
  100. {
  101. OpenLocalizedURL( "URL_Convert_INI" );
  102. }
  103. }
  104. };
  105. class CGameInfoMessageBox : public vgui::Frame
  106. {
  107. public:
  108. typedef vgui::Frame BaseClass;
  109. CGameInfoMessageBox( Panel *pParent, const char *pPanelName )
  110. : BaseClass( pParent, pPanelName )
  111. {
  112. SetSize( 200, 200 );
  113. SetMinimumSize( 250, 100 );
  114. LoadControlSettings( "hl2infobox.res" );
  115. }
  116. virtual void OnCommand( const char *command )
  117. {
  118. BaseClass::OnCommand( command );
  119. // For some weird reason, this dialog can
  120. if ( Q_stricmp( command, "RunAnyway" ) == 0 )
  121. {
  122. m_pDialog->Launch( m_iActiveItem, true );
  123. MarkForDeletion();
  124. }
  125. else if ( Q_stricmp( command, "Troubleshooting" ) == 0 )
  126. {
  127. OpenLocalizedURL( "URL_SDK_FAQ" );
  128. MarkForDeletion();
  129. }
  130. }
  131. CSDKLauncherDialog *m_pDialog;
  132. int m_iActiveItem;
  133. };
  134. class CMinFootprintRefreshConfirmationDialog : public vgui::Frame
  135. {
  136. public:
  137. typedef vgui::Frame BaseClass;
  138. CMinFootprintRefreshConfirmationDialog( Panel *pParent, const char *pPanelName )
  139. : BaseClass( pParent, pPanelName )
  140. {
  141. SetSizeable( false );
  142. LoadControlSettings( "min_footprint_confirm_box.res" );
  143. m_hOldModalSurface = input()->GetAppModalSurface();
  144. input()->SetAppModalSurface( GetVPanel() );
  145. }
  146. ~CMinFootprintRefreshConfirmationDialog()
  147. {
  148. input()->SetAppModalSurface( m_hOldModalSurface );
  149. }
  150. void OnCommand( const char *command )
  151. {
  152. BaseClass::OnCommand( command );
  153. if ( Q_stricmp( command, "Continue" ) == 0 )
  154. {
  155. PostMessage( g_pSDKLauncherDialog, new KeyValues( "Command", "command", "RefreshMinFootprint" ) );
  156. MarkForDeletion();
  157. }
  158. else if ( Q_stricmp( command, "Close" ) == 0 )
  159. {
  160. MarkForDeletion();
  161. }
  162. }
  163. VPANEL m_hOldModalSurface;
  164. };
  165. //-----------------------------------------------------------------------------
  166. // Purpose: Constructor
  167. //-----------------------------------------------------------------------------
  168. CSDKLauncherDialog::CSDKLauncherDialog(vgui::Panel *parent, const char *name) : BaseClass(parent, name)
  169. {
  170. Assert( !g_pSDKLauncherDialog );
  171. g_pSDKLauncherDialog = this;
  172. SetSize(384, 480);
  173. SetMinimumSize(250, 200);
  174. SetMinimizeButtonVisible( true );
  175. m_pImageList = new ImageList( true );
  176. m_pMediaList = new SectionedListPanel(this, "MediaList");
  177. m_pMediaList->AddActionSignalTarget( this );
  178. m_pMediaList->SetImageList( m_pImageList, true );
  179. m_pContextMenu = new Menu( m_pMediaList, "AppsContextMenu" );
  180. m_pCurrentGameCombo = new ComboBox( this, "CurrentGameList", 8, false );
  181. m_pCurrentGameCombo->AddActionSignalTarget( this );
  182. m_pCurrentEngineCombo = new ComboBox( this, "CurrentEngineList", 4, false );
  183. m_pCurrentEngineCombo->AddActionSignalTarget( this );
  184. PopulateMediaList();
  185. LoadControlSettings( "SDKLauncherDialog.res" );
  186. GetEngineVersion( g_engineDir, sizeof( g_engineDir ) );
  187. PopulateCurrentEngineCombo( false );
  188. RefreshConfigs();
  189. }
  190. CSDKLauncherDialog::~CSDKLauncherDialog()
  191. {
  192. delete m_pMediaList;
  193. g_pSDKLauncherDialog = NULL;
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Purpose: kills the whole app on close
  197. //-----------------------------------------------------------------------------
  198. void CSDKLauncherDialog::OnClose()
  199. {
  200. BaseClass::OnClose();
  201. ivgui()->Stop();
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Purpose: loads media list from file
  205. //-----------------------------------------------------------------------------
  206. void CSDKLauncherDialog::PopulateMediaList()
  207. {
  208. KeyValues *dataFile = new KeyValues("Media");
  209. dataFile->UsesEscapeSequences( true );
  210. if (dataFile->LoadFromFile( g_pFullFileSystem, "MediaList.txt", NULL ) )
  211. {
  212. // Load all the images.
  213. KeyValues *pImages = dataFile->FindKey( "Images" );
  214. if ( !pImages )
  215. Error( "MediaList.txt missing Images key." );
  216. for ( KeyValues *pCur=pImages->GetFirstTrueSubKey(); pCur; pCur=pCur->GetNextTrueSubKey() )
  217. {
  218. IImage *pImage = scheme()->GetImage( pCur->GetString( "Image", "" ), false );
  219. int iIndex = pCur->GetInt( "Index", -1 );
  220. if ( pImage && iIndex != -1 )
  221. {
  222. m_pImageList->SetImageAtIndex( iIndex, pImage );
  223. }
  224. }
  225. // Load all the sections.
  226. KeyValues *pSections = dataFile->FindKey( "Sections" );
  227. if ( !pSections )
  228. Error( "MediaList.txt missing Sections key." );
  229. for ( KeyValues *pSection=pSections->GetFirstTrueSubKey(); pSection; pSection=pSection->GetNextTrueSubKey() )
  230. {
  231. int id = pSection->GetInt( "id" );
  232. const char *pName = pSection->GetString( "Name" );
  233. m_pMediaList->AddSection( id, pName );
  234. m_pMediaList->AddColumnToSection( id, "Image", "", SectionedListPanel::COLUMN_IMAGE, 20 );
  235. m_pMediaList->AddColumnToSection( id, "Text", pName, 0, 200 );
  236. // Set all the rows.
  237. for ( KeyValues *kv = pSection->GetFirstTrueSubKey(); kv != NULL; kv=kv->GetNextTrueSubKey() )
  238. {
  239. m_pMediaList->AddItem( id, kv );
  240. }
  241. }
  242. }
  243. dataFile->deleteThis();
  244. }
  245. void CSDKLauncherDialog::Launch( int hActiveListItem, bool bForce )
  246. {
  247. if (!m_pMediaList->IsItemIDValid(hActiveListItem))
  248. return;
  249. // display the file
  250. KeyValues *item = m_pMediaList->GetItemData( hActiveListItem );
  251. if ( !item )
  252. return;
  253. // Is this a ShellExecute or a program they want to run?
  254. const char *pStr = item->GetString( "InlineProgram", NULL );
  255. if ( pStr )
  256. {
  257. if ( Q_stricmp( pStr, "CreateMod" ) == 0 )
  258. {
  259. if ( !V_stricmp( g_engineDir, "ep1" ) || !V_stricmp( g_engineDir, "source2007" ) )
  260. {
  261. RunCreateModWizard( false );
  262. }
  263. else
  264. {
  265. VGUIMessageBox( this, "Unable to Run 'Create A Mod' Wizard", "Support for creating total conversions are not available using this engine versions." );
  266. }
  267. }
  268. else if ( Q_stricmp( pStr, "refresh_min_footprint" ) == 0 )
  269. {
  270. CMinFootprintRefreshConfirmationDialog *pDlg = new CMinFootprintRefreshConfirmationDialog( this, "RefreshConfirmation" );
  271. pDlg->RequestFocus();
  272. pDlg->SetVisible( true );
  273. pDlg->MoveToCenterOfScreen();
  274. }
  275. else if ( Q_stricmp( pStr, "reset_configs" ) == 0 )
  276. {
  277. CResetConfirmationMessageBox *pDlg = new CResetConfirmationMessageBox( this, "ResetConfirmation" );
  278. pDlg->RequestFocus();
  279. pDlg->SetVisible( true );
  280. pDlg->MoveToCenterOfScreen();
  281. input()->SetAppModalSurface( pDlg->GetVPanel() );
  282. }
  283. else
  284. {
  285. Error( "Unknown InlineProgram value: %s", pStr );
  286. }
  287. return;
  288. }
  289. pStr = item->GetString( "ShellExecute", NULL );
  290. if ( pStr )
  291. {
  292. // Replace tokens we know about like %basedir%.
  293. system()->ShellExecute( "open", pStr );
  294. return;
  295. }
  296. pStr = item->GetString( "Program", NULL );
  297. if ( pStr )
  298. {
  299. // Get our current config.
  300. KeyValues *kv = m_pCurrentGameCombo->GetActiveItemUserData();
  301. if ( !kv )
  302. {
  303. VGUIMessageBox( this, "Error", "No game configurations to run with." );
  304. return;
  305. }
  306. const char *pModDir = kv->GetString( "ModDir", NULL );
  307. if ( !pModDir )
  308. {
  309. VGUIMessageBox( this, "Error", "Missing 'ModDir' key/value." );
  310. return;
  311. }
  312. bool bRun = true;
  313. if ( !bForce && Q_stristr( pStr, "%gamedir%" ) )
  314. {
  315. // Make sure the currently-selected gamedir is valid and has a gameinfo.txt in it.
  316. char testStr[MAX_PATH];
  317. Q_strncpy( testStr, pModDir, sizeof( testStr ) );
  318. Q_AppendSlash( testStr, sizeof( testStr ) );
  319. Q_strncat( testStr, "gameinfo.txt", sizeof( testStr ), COPY_ALL_CHARACTERS );
  320. if ( _access( testStr, 0 ) != 0 )
  321. {
  322. CGameInfoMessageBox *dlg = new CGameInfoMessageBox( this, "GameInfoMessageBox" );
  323. dlg->m_pDialog = this;
  324. dlg->m_iActiveItem = hActiveListItem;
  325. dlg->RequestFocus();
  326. dlg->SetVisible( true );
  327. dlg->MoveToCenterOfScreen();
  328. input()->SetAppModalSurface( dlg->GetVPanel() );
  329. bRun = false;
  330. }
  331. }
  332. if ( bRun )
  333. {
  334. // Get the program name and its arguments.
  335. char programNameTemp[1024], programName[1024], launchDirectory[1024];
  336. SubstituteBaseDir( pStr, programNameTemp, sizeof( programNameTemp ) );
  337. V_StrSubst( programNameTemp, "%gamedir%", pModDir, programName, sizeof( programName ) );
  338. V_strncpy( programNameTemp, programName, sizeof( programNameTemp ) );
  339. V_StrSubst( programNameTemp, "%enginedir%", g_engineDir , programName, sizeof( programName ) );
  340. V_strncpy( launchDirectory, GetSDKLauncherBaseDirectory(), sizeof( launchDirectory ) );
  341. V_strncat( launchDirectory, "\\bin\\", sizeof( launchDirectory ) );
  342. V_strncat( launchDirectory, g_engineDir, sizeof( launchDirectory ) );
  343. // Check to see if we're running in tools mode
  344. if ( NULL != V_strstr( programName, "-tools" ) )
  345. {
  346. // We can't run tools mode in engine versions earlier than OB
  347. if ( !V_strcmp( g_engineDir, "ep1" ) )
  348. {
  349. VGUIMessageBox( this, "Error", "Source Engine Tools is not compatible with the selected engine version." );
  350. return;
  351. }
  352. // If we are running the engine tools then change our launch directory to the game directory
  353. V_strncpy( launchDirectory, pModDir, sizeof( launchDirectory ) );
  354. V_StripLastDir( launchDirectory, sizeof( launchDirectory ) );
  355. V_strncat( launchDirectory, "bin", sizeof( launchDirectory ) );
  356. }
  357. STARTUPINFO si;
  358. memset( &si, 0, sizeof( si ) );
  359. si.cb = sizeof( si );
  360. PROCESS_INFORMATION pi;
  361. memset( &pi, 0, sizeof( pi ) );
  362. DWORD dwFlags = 0;
  363. if ( !CreateProcess(
  364. 0,
  365. programName,
  366. NULL, // security
  367. NULL,
  368. TRUE,
  369. dwFlags, // flags
  370. NULL, // environment
  371. launchDirectory, // current directory
  372. &si,
  373. &pi ) )
  374. {
  375. ::MessageBoxA( NULL, GetLastWindowsErrorString(), "Error", MB_OK | MB_ICONINFORMATION | MB_APPLMODAL );
  376. }
  377. }
  378. }
  379. }
  380. void CSDKLauncherDialog::OnCommand( const char *command )
  381. {
  382. if ( Q_stricmp( command, "LaunchButton" ) == 0 )
  383. {
  384. Launch( m_pMediaList->GetSelectedItem(), false );
  385. }
  386. else if ( Q_stricmp( command, "ResetConfigs" ) == 0 )
  387. {
  388. ResetConfigs();
  389. }
  390. else if ( Q_stricmp( command, "RefreshMinFootprint" ) == 0 )
  391. {
  392. DumpMinFootprintFiles( true );
  393. }
  394. BaseClass::OnCommand( command );
  395. }
  396. void CSDKLauncherDialog::OnItemDoubleLeftClick( int iItem )
  397. {
  398. Launch( iItem, false );
  399. }
  400. void CSDKLauncherDialog::OnItemContextMenu( int hActiveListItem )
  401. {
  402. if (!m_pMediaList->IsItemIDValid(hActiveListItem))
  403. return;
  404. // display the file
  405. KeyValues *item = m_pMediaList->GetItemData( hActiveListItem );
  406. if ( !item )
  407. return;
  408. // Build the context menu.
  409. m_pContextMenu->DeleteAllItems();
  410. // Is this a ShellExecute or a program they want to run?
  411. const char *pStr = item->GetString( "ShellExecute", NULL );
  412. if ( pStr )
  413. m_pContextMenu->AddMenuItem( "RunGame", "Open In Web Browser", new KeyValues("ItemDoubleLeftClick", "itemID", hActiveListItem), this);
  414. else
  415. m_pContextMenu->AddMenuItem( "RunGame", "Launch", new KeyValues("ItemDoubleLeftClick", "itemID", hActiveListItem), this);
  416. int menuWide, menuTall;
  417. m_pContextMenu->SetVisible(true);
  418. m_pContextMenu->InvalidateLayout(true);
  419. m_pContextMenu->GetSize(menuWide, menuTall);
  420. // work out where the cursor is and therefore the best place to put the menu
  421. int wide, tall;
  422. surface()->GetScreenSize(wide, tall);
  423. int cx, cy;
  424. input()->GetCursorPos(cx, cy);
  425. if (wide - menuWide > cx)
  426. {
  427. // menu hanging right
  428. if (tall - menuTall > cy)
  429. {
  430. // menu hanging down
  431. m_pContextMenu->SetPos(cx, cy);
  432. }
  433. else
  434. {
  435. // menu hanging up
  436. m_pContextMenu->SetPos(cx, cy - menuTall);
  437. }
  438. }
  439. else
  440. {
  441. // menu hanging left
  442. if (tall - menuTall > cy)
  443. {
  444. // menu hanging down
  445. m_pContextMenu->SetPos(cx - menuWide, cy);
  446. }
  447. else
  448. {
  449. // menu hanging up
  450. m_pContextMenu->SetPos(cx - menuWide, cy - menuTall);
  451. }
  452. }
  453. m_pContextMenu->RequestFocus();
  454. m_pContextMenu->MoveToFront();
  455. }
  456. bool CSDKLauncherDialog::ParseConfigs( CUtlVector<CGameConfig*> &configs )
  457. {
  458. if ( !g_ConfigManager.IsLoaded() )
  459. return false;
  460. // Find the games block of the keyvalues
  461. KeyValues *gameBlock = g_ConfigManager.GetGameBlock();
  462. if ( gameBlock == NULL )
  463. {
  464. return false;
  465. }
  466. // Iterate through all subkeys
  467. for ( KeyValues *pGame=gameBlock->GetFirstTrueSubKey(); pGame; pGame=pGame->GetNextTrueSubKey() )
  468. {
  469. const char *pName = pGame->GetName();
  470. const char *pDir = pGame->GetString( TOKEN_GAME_DIRECTORY );
  471. CGameConfig *newConfig = new CGameConfig();
  472. UtlStrcpy( newConfig->m_Name, pName );
  473. UtlStrcpy( newConfig->m_ModDir, pDir );
  474. configs.AddToTail( newConfig );
  475. }
  476. return true;
  477. }
  478. void CSDKLauncherDialog::PopulateCurrentEngineCombo( bool bSelectLast )
  479. {
  480. int nActiveEngine = 0;
  481. m_pCurrentEngineCombo->DeleteAllItems();
  482. // Add ep1 engine
  483. KeyValues *kv = new KeyValues( "values" );
  484. kv = new KeyValues( "values" );
  485. kv->SetString( "EngineVer", "ep1" );
  486. m_pCurrentEngineCombo->AddItem( "Source Engine 2006", kv );
  487. kv->deleteThis();
  488. if ( !V_strcmp( g_engineDir, "ep1" ) )
  489. {
  490. nActiveEngine = 0;
  491. }
  492. // Add ep2 engine
  493. kv = new KeyValues( "values" );
  494. kv->SetString( "EngineVer", "source2007" );
  495. m_pCurrentEngineCombo->AddItem( "Source Engine 2007", kv );
  496. kv->deleteThis();
  497. if ( !V_strcmp( g_engineDir, "source2007" ) )
  498. {
  499. nActiveEngine = 1;
  500. }
  501. // Add SP engine
  502. kv = new KeyValues( "values" );
  503. kv->SetString( "EngineVer", "source2009" );
  504. m_pCurrentEngineCombo->AddItem( "Source Engine 2009", kv );
  505. kv->deleteThis();
  506. if ( !V_strcmp( g_engineDir, "source2009" ) )
  507. {
  508. nActiveEngine = 2;
  509. }
  510. // Add MP engine
  511. kv = new KeyValues( "values" );
  512. kv->SetString( "EngineVer", "orangebox" );
  513. m_pCurrentEngineCombo->AddItem( "Source Engine MP", kv );
  514. kv->deleteThis();
  515. if ( !V_strcmp( g_engineDir, "orangebox" ) )
  516. {
  517. nActiveEngine = 3;
  518. }
  519. // Determine active configuration
  520. m_pCurrentEngineCombo->ActivateItem( nActiveEngine );
  521. }
  522. void CSDKLauncherDialog::SetCurrentGame( const char* pcCurrentGame )
  523. {
  524. int activeConfig = -1;
  525. for ( int i=0; i < m_pCurrentGameCombo->GetItemCount(); i++ )
  526. {
  527. KeyValues *kv = m_pCurrentGameCombo->GetItemUserData( i );
  528. // Check to see if this is our currently active game
  529. if ( Q_stricmp( kv->GetString( "ModDir" ), pcCurrentGame ) == 0 )
  530. {
  531. activeConfig = i;
  532. continue;
  533. }
  534. }
  535. if ( activeConfig > -1 )
  536. {
  537. // Activate our currently selected game
  538. m_pCurrentGameCombo->ActivateItem( activeConfig );
  539. }
  540. else
  541. {
  542. // If the VCONFIG value for the game is not found then repopulate
  543. PopulateCurrentGameCombo( false );
  544. }
  545. }
  546. void CSDKLauncherDialog::PopulateCurrentGameCombo( bool bSelectLast )
  547. {
  548. m_pCurrentGameCombo->DeleteAllItems();
  549. CUtlVector<CGameConfig*> configs;
  550. ParseConfigs( configs );
  551. char szGame[MAX_PATH];
  552. GetVConfigRegistrySetting( GAMEDIR_TOKEN, szGame, sizeof( szGame ) );
  553. int activeConfig = -1;
  554. CUtlVector<int> itemIDs;
  555. itemIDs.SetSize( configs.Count() );
  556. for ( int i=0; i < configs.Count(); i++ )
  557. {
  558. KeyValues *kv = new KeyValues( "values" );
  559. kv->SetString( "ModDir", configs[i]->m_ModDir.Base() );
  560. kv->SetPtr( "panel", m_pCurrentGameCombo );
  561. // Check to see if this is our currently active game
  562. if ( Q_stricmp( configs[i]->m_ModDir.Base(), szGame ) == 0 )
  563. {
  564. activeConfig = i;
  565. }
  566. itemIDs[i] = m_pCurrentGameCombo->AddItem( configs[i]->m_Name.Base(), kv );
  567. kv->deleteThis();
  568. }
  569. // Activate the correct entry if valid
  570. if ( itemIDs.Count() > 0 )
  571. {
  572. m_pCurrentGameCombo->SetEnabled( true );
  573. if ( bSelectLast )
  574. {
  575. m_pCurrentGameCombo->ActivateItem( itemIDs[itemIDs.Count()-1] );
  576. }
  577. else
  578. {
  579. if ( activeConfig > -1 )
  580. {
  581. // Activate our currently selected game
  582. m_pCurrentGameCombo->ActivateItem( activeConfig );
  583. }
  584. else
  585. {
  586. // Always default to the first otherwise
  587. m_pCurrentGameCombo->ActivateItem( 0 );
  588. }
  589. }
  590. }
  591. else
  592. {
  593. m_pCurrentGameCombo->SetEnabled( false );
  594. }
  595. configs.PurgeAndDeleteElements();
  596. }
  597. //-----------------------------------------------------------------------------
  598. // Purpose: Selection has changed in the active config drop-down, set the environment
  599. //-----------------------------------------------------------------------------
  600. void CSDKLauncherDialog::OnTextChanged( KeyValues *pkv )
  601. {
  602. const vgui::ComboBox* combo = (vgui::ComboBox*)pkv->GetPtr("panel");
  603. if ( combo == m_pCurrentGameCombo)
  604. {
  605. KeyValues *kv = m_pCurrentGameCombo->GetActiveItemUserData();
  606. if ( kv )
  607. {
  608. const char *modDir = kv->GetString( "ModDir" );
  609. SetVConfigRegistrySetting( GAMEDIR_TOKEN, modDir, true );
  610. }
  611. }
  612. else if ( combo == m_pCurrentEngineCombo )
  613. {
  614. KeyValues *kv = m_pCurrentEngineCombo->GetActiveItemUserData();
  615. if ( kv )
  616. {
  617. const char *engineDir = kv->GetString( "EngineVer" );
  618. SetEngineVersion( engineDir );
  619. RefreshConfigs();
  620. }
  621. }
  622. }
  623. //-----------------------------------------------------------------------------
  624. // Purpose: Refresh our configs after a file change outside our process
  625. //-----------------------------------------------------------------------------
  626. void CSDKLauncherDialog::RefreshConfigs( void )
  627. {
  628. char szGameConfigDir[MAX_PATH];
  629. V_strcpy_safe( szGameConfigDir, GetSDKLauncherBinDirectory() );
  630. V_AppendSlash( szGameConfigDir, MAX_PATH );
  631. V_strncat( szGameConfigDir, g_engineDir, MAX_PATH );
  632. V_AppendSlash( szGameConfigDir, MAX_PATH );
  633. V_strncat( szGameConfigDir, "bin", MAX_PATH );
  634. // Set directory in which GameConfig.txt is found
  635. g_ConfigManager.SetBaseDirectory( szGameConfigDir );
  636. // Tell the config manager which games to put in the config by default
  637. if ( !stricmp( g_engineDir, "ep1" ) )
  638. {
  639. g_ConfigManager.SetSDKEpoch( EP1 );
  640. }
  641. else if ( !stricmp( g_engineDir, "source2007" ) )
  642. {
  643. g_ConfigManager.SetSDKEpoch( EP2 );
  644. }
  645. else if ( !stricmp( g_engineDir, "source2009" ) )
  646. {
  647. g_ConfigManager.SetSDKEpoch( SP2009 );
  648. }
  649. else
  650. {
  651. g_ConfigManager.SetSDKEpoch( MP2009 );
  652. }
  653. // Load configurations
  654. if ( g_ConfigManager.LoadConfigs( szGameConfigDir ) == false )
  655. {
  656. m_pCurrentGameCombo->DeleteAllItems();
  657. m_pCurrentGameCombo->SetEnabled( false );
  658. }
  659. else
  660. {
  661. m_pCurrentGameCombo->SetEnabled( true );
  662. if ( g_ConfigManager.WasConvertedOnLoad() )
  663. {
  664. // Notify of a conversion
  665. CConversionInfoMessageBox *pDlg = new CConversionInfoMessageBox( this, "ConversionInfo" );
  666. pDlg->RequestFocus();
  667. pDlg->SetVisible( true );
  668. pDlg->MoveToCenterOfScreen();
  669. input()->SetAppModalSurface( pDlg->GetVPanel() );
  670. }
  671. }
  672. // Dump the current settings and reparse the change
  673. PopulateCurrentGameCombo( false );
  674. }
  675. //-----------------------------------------------------------------------------
  676. // Purpose: Reset our config files
  677. //-----------------------------------------------------------------------------
  678. void CSDKLauncherDialog::ResetConfigs( void )
  679. {
  680. // Reset the configs
  681. g_ConfigManager.ResetConfigs();
  682. // Refresh the listing
  683. PopulateCurrentGameCombo( false );
  684. // Notify the user
  685. VGUIMessageBox( this, "Complete", "Your game configurations have successfully been reset to their default values." );
  686. }
  687. void CSDKLauncherDialog::GetEngineVersion(char* pcEngineVer, int nSize)
  688. {
  689. IRegistry *reg = InstanceRegistry( "Source SDK" );
  690. Assert( reg );
  691. V_strncpy( pcEngineVer, reg->ReadString( "EngineVer", "orangebox" ), nSize );
  692. ReleaseInstancedRegistry( reg );
  693. }
  694. void CSDKLauncherDialog::SetEngineVersion(const char *pcEngineVer)
  695. {
  696. IRegistry *reg = InstanceRegistry( "Source SDK" );
  697. Assert( reg );
  698. reg->WriteString( "EngineVer", pcEngineVer );
  699. ReleaseInstancedRegistry( reg );
  700. // Set the global to the same value as the registry
  701. V_strncpy( g_engineDir, pcEngineVer, sizeof( g_engineDir ) );
  702. }