hl2_src-leak-2017/src/sdklauncher/SDKLauncherDialog.cpp

838 lines
22 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include <windows.h>
#include "SDKLauncherDialog.h"
#include "configs.h"
#include <vgui_controls/ComboBox.h>
#include <vgui_controls/ListPanel.h>
#include <vgui_controls/ProgressBox.h>
#include <vgui_controls/MessageBox.h>
#include <vgui_controls/HTML.h>
#include <vgui_controls/CheckButton.h>
#include <vgui_controls/Divider.h>
#include <vgui_controls/menu.h>
#include <vgui/ISurface.h>
#include <vgui/ILocalize.h>
#include "vgui_controls/button.h"
#include <vgui/ISystem.h>
#include <vgui/IVGui.h>
#include <vgui/iinput.h>
#include <KeyValues.h>
#include <FileSystem.h>
#include <io.h>
#include "CreateModWizard.h"
#include "filesystem_tools.h"
#include "min_footprint_files.h"
#include "ConfigManager.h"
#include "filesystem_tools.h"
#include <iregistry.h>
#include <sys/stat.h>
#include "sdklauncher_main.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
using namespace vgui;
CSDKLauncherDialog *g_pSDKLauncherDialog = NULL;
CGameConfigManager g_ConfigManager;
char g_engineDir[50];
//-----------------------------------------------------------------------------
// Purpose: Retrieves a URL out of the external localization file and opens it in a
// web browser.
// Input : *lpszLocalName - Localized name of the URL to open via shell execution
//-----------------------------------------------------------------------------
void OpenLocalizedURL( const char *lpszLocalName )
{
// Find and convert the localized unicode string
char pURLStr[MAX_PATH];
wchar_t *pURLUni = g_pVGuiLocalize->Find( lpszLocalName );
g_pVGuiLocalize->ConvertUnicodeToANSI( pURLUni, pURLStr, sizeof( pURLStr ) );
// Open the URL through the shell
vgui::system()->ShellExecute( "open", pURLStr );
}
class CResetConfirmationMessageBox : public vgui::Frame
{
public:
typedef vgui::Frame BaseClass;
CResetConfirmationMessageBox( Panel *pParent, const char *pPanelName )
: BaseClass( pParent, pPanelName )
{
SetSize( 200, 200 );
SetMinimumSize( 250, 100 );
SetSizeable( false );
LoadControlSettings( "resetconfirmbox.res" );
}
void OnCommand( const char *command )
{
if ( Q_stricmp( command, "ResetConfigs" ) == 0 )
{
Close();
if ( GetVParent() )
{
PostMessage( GetVParent(), new KeyValues( "Command", "command", "ResetConfigs"));
}
}
else if ( Q_stricmp( command, "MoreInfo" ) == 0 )
{
OpenLocalizedURL( "URL_Reset_Config" );
}
BaseClass::OnCommand( command );
}
};
class CConversionInfoMessageBox : public vgui::Frame
{
public:
typedef vgui::Frame BaseClass;
CConversionInfoMessageBox( Panel *pParent, const char *pPanelName )
: BaseClass( pParent, pPanelName )
{
SetSize( 200, 200 );
SetMinimumSize( 250, 100 );
SetSizeable( false );
LoadControlSettings( "convinfobox.res" );
}
virtual void OnCommand( const char *command )
{
BaseClass::OnCommand( command );
// For some weird reason, this dialog can
if ( Q_stricmp( command, "ShowFAQ" ) == 0 )
{
OpenLocalizedURL( "URL_Convert_INI" );
}
}
};
class CGameInfoMessageBox : public vgui::Frame
{
public:
typedef vgui::Frame BaseClass;
CGameInfoMessageBox( Panel *pParent, const char *pPanelName )
: BaseClass( pParent, pPanelName )
{
SetSize( 200, 200 );
SetMinimumSize( 250, 100 );
LoadControlSettings( "hl2infobox.res" );
}
virtual void OnCommand( const char *command )
{
BaseClass::OnCommand( command );
// For some weird reason, this dialog can
if ( Q_stricmp( command, "RunAnyway" ) == 0 )
{
m_pDialog->Launch( m_iActiveItem, true );
MarkForDeletion();
}
else if ( Q_stricmp( command, "Troubleshooting" ) == 0 )
{
OpenLocalizedURL( "URL_SDK_FAQ" );
MarkForDeletion();
}
}
CSDKLauncherDialog *m_pDialog;
int m_iActiveItem;
};
class CMinFootprintRefreshConfirmationDialog : public vgui::Frame
{
public:
typedef vgui::Frame BaseClass;
CMinFootprintRefreshConfirmationDialog( Panel *pParent, const char *pPanelName )
: BaseClass( pParent, pPanelName )
{
SetSizeable( false );
LoadControlSettings( "min_footprint_confirm_box.res" );
m_hOldModalSurface = input()->GetAppModalSurface();
input()->SetAppModalSurface( GetVPanel() );
}
~CMinFootprintRefreshConfirmationDialog()
{
input()->SetAppModalSurface( m_hOldModalSurface );
}
void OnCommand( const char *command )
{
BaseClass::OnCommand( command );
if ( Q_stricmp( command, "Continue" ) == 0 )
{
PostMessage( g_pSDKLauncherDialog, new KeyValues( "Command", "command", "RefreshMinFootprint" ) );
MarkForDeletion();
}
else if ( Q_stricmp( command, "Close" ) == 0 )
{
MarkForDeletion();
}
}
VPANEL m_hOldModalSurface;
};
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CSDKLauncherDialog::CSDKLauncherDialog(vgui::Panel *parent, const char *name) : BaseClass(parent, name)
{
Assert( !g_pSDKLauncherDialog );
g_pSDKLauncherDialog = this;
SetSize(384, 480);
SetMinimumSize(250, 200);
SetMinimizeButtonVisible( true );
m_pImageList = new ImageList( true );
m_pMediaList = new SectionedListPanel(this, "MediaList");
m_pMediaList->AddActionSignalTarget( this );
m_pMediaList->SetImageList( m_pImageList, true );
m_pContextMenu = new Menu( m_pMediaList, "AppsContextMenu" );
m_pCurrentGameCombo = new ComboBox( this, "CurrentGameList", 8, false );
m_pCurrentGameCombo->AddActionSignalTarget( this );
m_pCurrentEngineCombo = new ComboBox( this, "CurrentEngineList", 4, false );
m_pCurrentEngineCombo->AddActionSignalTarget( this );
PopulateMediaList();
LoadControlSettings( "SDKLauncherDialog.res" );
GetEngineVersion( g_engineDir, sizeof( g_engineDir ) );
PopulateCurrentEngineCombo( false );
RefreshConfigs();
}
CSDKLauncherDialog::~CSDKLauncherDialog()
{
delete m_pMediaList;
g_pSDKLauncherDialog = NULL;
}
//-----------------------------------------------------------------------------
// Purpose: kills the whole app on close
//-----------------------------------------------------------------------------
void CSDKLauncherDialog::OnClose()
{
BaseClass::OnClose();
ivgui()->Stop();
}
//-----------------------------------------------------------------------------
// Purpose: loads media list from file
//-----------------------------------------------------------------------------
void CSDKLauncherDialog::PopulateMediaList()
{
KeyValues *dataFile = new KeyValues("Media");
dataFile->UsesEscapeSequences( true );
if (dataFile->LoadFromFile( g_pFullFileSystem, "MediaList.txt", NULL ) )
{
// Load all the images.
KeyValues *pImages = dataFile->FindKey( "Images" );
if ( !pImages )
Error( "MediaList.txt missing Images key." );
for ( KeyValues *pCur=pImages->GetFirstTrueSubKey(); pCur; pCur=pCur->GetNextTrueSubKey() )
{
IImage *pImage = scheme()->GetImage( pCur->GetString( "Image", "" ), false );
int iIndex = pCur->GetInt( "Index", -1 );
if ( pImage && iIndex != -1 )
{
m_pImageList->SetImageAtIndex( iIndex, pImage );
}
}
// Load all the sections.
KeyValues *pSections = dataFile->FindKey( "Sections" );
if ( !pSections )
Error( "MediaList.txt missing Sections key." );
for ( KeyValues *pSection=pSections->GetFirstTrueSubKey(); pSection; pSection=pSection->GetNextTrueSubKey() )
{
int id = pSection->GetInt( "id" );
const char *pName = pSection->GetString( "Name" );
m_pMediaList->AddSection( id, pName );
m_pMediaList->AddColumnToSection( id, "Image", "", SectionedListPanel::COLUMN_IMAGE, 20 );
m_pMediaList->AddColumnToSection( id, "Text", pName, 0, 200 );
// Set all the rows.
for ( KeyValues *kv = pSection->GetFirstTrueSubKey(); kv != NULL; kv=kv->GetNextTrueSubKey() )
{
m_pMediaList->AddItem( id, kv );
}
}
}
dataFile->deleteThis();
}
void CSDKLauncherDialog::Launch( int hActiveListItem, bool bForce )
{
if (!m_pMediaList->IsItemIDValid(hActiveListItem))
return;
// display the file
KeyValues *item = m_pMediaList->GetItemData( hActiveListItem );
if ( !item )
return;
// Is this a ShellExecute or a program they want to run?
const char *pStr = item->GetString( "InlineProgram", NULL );
if ( pStr )
{
if ( Q_stricmp( pStr, "CreateMod" ) == 0 )
{
if ( !V_stricmp( g_engineDir, "ep1" ) || !V_stricmp( g_engineDir, "source2007" ) )
{
RunCreateModWizard( false );
}
else
{
VGUIMessageBox( this, "Unable to Run 'Create A Mod' Wizard", "Support for creating total conversions are not available using this engine versions." );
}
}
else if ( Q_stricmp( pStr, "refresh_min_footprint" ) == 0 )
{
CMinFootprintRefreshConfirmationDialog *pDlg = new CMinFootprintRefreshConfirmationDialog( this, "RefreshConfirmation" );
pDlg->RequestFocus();
pDlg->SetVisible( true );
pDlg->MoveToCenterOfScreen();
}
else if ( Q_stricmp( pStr, "reset_configs" ) == 0 )
{
CResetConfirmationMessageBox *pDlg = new CResetConfirmationMessageBox( this, "ResetConfirmation" );
pDlg->RequestFocus();
pDlg->SetVisible( true );
pDlg->MoveToCenterOfScreen();
input()->SetAppModalSurface( pDlg->GetVPanel() );
}
else
{
Error( "Unknown InlineProgram value: %s", pStr );
}
return;
}
pStr = item->GetString( "ShellExecute", NULL );
if ( pStr )
{
// Replace tokens we know about like %basedir%.
system()->ShellExecute( "open", pStr );
return;
}
pStr = item->GetString( "Program", NULL );
if ( pStr )
{
// Get our current config.
KeyValues *kv = m_pCurrentGameCombo->GetActiveItemUserData();
if ( !kv )
{
VGUIMessageBox( this, "Error", "No game configurations to run with." );
return;
}
const char *pModDir = kv->GetString( "ModDir", NULL );
if ( !pModDir )
{
VGUIMessageBox( this, "Error", "Missing 'ModDir' key/value." );
return;
}
bool bRun = true;
if ( !bForce && Q_stristr( pStr, "%gamedir%" ) )
{
// Make sure the currently-selected gamedir is valid and has a gameinfo.txt in it.
char testStr[MAX_PATH];
Q_strncpy( testStr, pModDir, sizeof( testStr ) );
Q_AppendSlash( testStr, sizeof( testStr ) );
Q_strncat( testStr, "gameinfo.txt", sizeof( testStr ), COPY_ALL_CHARACTERS );
if ( _access( testStr, 0 ) != 0 )
{
CGameInfoMessageBox *dlg = new CGameInfoMessageBox( this, "GameInfoMessageBox" );
dlg->m_pDialog = this;
dlg->m_iActiveItem = hActiveListItem;
dlg->RequestFocus();
dlg->SetVisible( true );
dlg->MoveToCenterOfScreen();
input()->SetAppModalSurface( dlg->GetVPanel() );
bRun = false;
}
}
if ( bRun )
{
// Get the program name and its arguments.
char programNameTemp[1024], programName[1024], launchDirectory[1024];
SubstituteBaseDir( pStr, programNameTemp, sizeof( programNameTemp ) );
V_StrSubst( programNameTemp, "%gamedir%", pModDir, programName, sizeof( programName ) );
V_strncpy( programNameTemp, programName, sizeof( programNameTemp ) );
V_StrSubst( programNameTemp, "%enginedir%", g_engineDir , programName, sizeof( programName ) );
V_strncpy( launchDirectory, GetSDKLauncherBaseDirectory(), sizeof( launchDirectory ) );
V_strncat( launchDirectory, "\\bin\\", sizeof( launchDirectory ) );
V_strncat( launchDirectory, g_engineDir, sizeof( launchDirectory ) );
// Check to see if we're running in tools mode
if ( NULL != V_strstr( programName, "-tools" ) )
{
// We can't run tools mode in engine versions earlier than OB
if ( !V_strcmp( g_engineDir, "ep1" ) )
{
VGUIMessageBox( this, "Error", "Source Engine Tools is not compatible with the selected engine version." );
return;
}
// If we are running the engine tools then change our launch directory to the game directory
V_strncpy( launchDirectory, pModDir, sizeof( launchDirectory ) );
V_StripLastDir( launchDirectory, sizeof( launchDirectory ) );
V_strncat( launchDirectory, "bin", sizeof( launchDirectory ) );
}
STARTUPINFO si;
memset( &si, 0, sizeof( si ) );
si.cb = sizeof( si );
PROCESS_INFORMATION pi;
memset( &pi, 0, sizeof( pi ) );
DWORD dwFlags = 0;
if ( !CreateProcess(
0,
programName,
NULL, // security
NULL,
TRUE,
dwFlags, // flags
NULL, // environment
launchDirectory, // current directory
&si,
&pi ) )
{
::MessageBoxA( NULL, GetLastWindowsErrorString(), "Error", MB_OK | MB_ICONINFORMATION | MB_APPLMODAL );
}
}
}
}
void CSDKLauncherDialog::OnCommand( const char *command )
{
if ( Q_stricmp( command, "LaunchButton" ) == 0 )
{
Launch( m_pMediaList->GetSelectedItem(), false );
}
else if ( Q_stricmp( command, "ResetConfigs" ) == 0 )
{
ResetConfigs();
}
else if ( Q_stricmp( command, "RefreshMinFootprint" ) == 0 )
{
DumpMinFootprintFiles( true );
}
BaseClass::OnCommand( command );
}
void CSDKLauncherDialog::OnItemDoubleLeftClick( int iItem )
{
Launch( iItem, false );
}
void CSDKLauncherDialog::OnItemContextMenu( int hActiveListItem )
{
if (!m_pMediaList->IsItemIDValid(hActiveListItem))
return;
// display the file
KeyValues *item = m_pMediaList->GetItemData( hActiveListItem );
if ( !item )
return;
// Build the context menu.
m_pContextMenu->DeleteAllItems();
// Is this a ShellExecute or a program they want to run?
const char *pStr = item->GetString( "ShellExecute", NULL );
if ( pStr )
m_pContextMenu->AddMenuItem( "RunGame", "Open In Web Browser", new KeyValues("ItemDoubleLeftClick", "itemID", hActiveListItem), this);
else
m_pContextMenu->AddMenuItem( "RunGame", "Launch", new KeyValues("ItemDoubleLeftClick", "itemID", hActiveListItem), this);
int menuWide, menuTall;
m_pContextMenu->SetVisible(true);
m_pContextMenu->InvalidateLayout(true);
m_pContextMenu->GetSize(menuWide, menuTall);
// work out where the cursor is and therefore the best place to put the menu
int wide, tall;
surface()->GetScreenSize(wide, tall);
int cx, cy;
input()->GetCursorPos(cx, cy);
if (wide - menuWide > cx)
{
// menu hanging right
if (tall - menuTall > cy)
{
// menu hanging down
m_pContextMenu->SetPos(cx, cy);
}
else
{
// menu hanging up
m_pContextMenu->SetPos(cx, cy - menuTall);
}
}
else
{
// menu hanging left
if (tall - menuTall > cy)
{
// menu hanging down
m_pContextMenu->SetPos(cx - menuWide, cy);
}
else
{
// menu hanging up
m_pContextMenu->SetPos(cx - menuWide, cy - menuTall);
}
}
m_pContextMenu->RequestFocus();
m_pContextMenu->MoveToFront();
}
bool CSDKLauncherDialog::ParseConfigs( CUtlVector<CGameConfig*> &configs )
{
if ( !g_ConfigManager.IsLoaded() )
return false;
// Find the games block of the keyvalues
KeyValues *gameBlock = g_ConfigManager.GetGameBlock();
if ( gameBlock == NULL )
{
return false;
}
// Iterate through all subkeys
for ( KeyValues *pGame=gameBlock->GetFirstTrueSubKey(); pGame; pGame=pGame->GetNextTrueSubKey() )
{
const char *pName = pGame->GetName();
const char *pDir = pGame->GetString( TOKEN_GAME_DIRECTORY );
CGameConfig *newConfig = new CGameConfig();
UtlStrcpy( newConfig->m_Name, pName );
UtlStrcpy( newConfig->m_ModDir, pDir );
configs.AddToTail( newConfig );
}
return true;
}
void CSDKLauncherDialog::PopulateCurrentEngineCombo( bool bSelectLast )
{
int nActiveEngine = 0;
m_pCurrentEngineCombo->DeleteAllItems();
// Add ep1 engine
KeyValues *kv = new KeyValues( "values" );
kv = new KeyValues( "values" );
kv->SetString( "EngineVer", "ep1" );
m_pCurrentEngineCombo->AddItem( "Source Engine 2006", kv );
kv->deleteThis();
if ( !V_strcmp( g_engineDir, "ep1" ) )
{
nActiveEngine = 0;
}
// Add ep2 engine
kv = new KeyValues( "values" );
kv->SetString( "EngineVer", "source2007" );
m_pCurrentEngineCombo->AddItem( "Source Engine 2007", kv );
kv->deleteThis();
if ( !V_strcmp( g_engineDir, "source2007" ) )
{
nActiveEngine = 1;
}
// Add SP engine
kv = new KeyValues( "values" );
kv->SetString( "EngineVer", "source2009" );
m_pCurrentEngineCombo->AddItem( "Source Engine 2009", kv );
kv->deleteThis();
if ( !V_strcmp( g_engineDir, "source2009" ) )
{
nActiveEngine = 2;
}
// Add MP engine
kv = new KeyValues( "values" );
kv->SetString( "EngineVer", "orangebox" );
m_pCurrentEngineCombo->AddItem( "Source Engine MP", kv );
kv->deleteThis();
if ( !V_strcmp( g_engineDir, "orangebox" ) )
{
nActiveEngine = 3;
}
// Determine active configuration
m_pCurrentEngineCombo->ActivateItem( nActiveEngine );
}
void CSDKLauncherDialog::SetCurrentGame( const char* pcCurrentGame )
{
int activeConfig = -1;
for ( int i=0; i < m_pCurrentGameCombo->GetItemCount(); i++ )
{
KeyValues *kv = m_pCurrentGameCombo->GetItemUserData( i );
// Check to see if this is our currently active game
if ( Q_stricmp( kv->GetString( "ModDir" ), pcCurrentGame ) == 0 )
{
activeConfig = i;
continue;
}
}
if ( activeConfig > -1 )
{
// Activate our currently selected game
m_pCurrentGameCombo->ActivateItem( activeConfig );
}
else
{
// If the VCONFIG value for the game is not found then repopulate
PopulateCurrentGameCombo( false );
}
}
void CSDKLauncherDialog::PopulateCurrentGameCombo( bool bSelectLast )
{
m_pCurrentGameCombo->DeleteAllItems();
CUtlVector<CGameConfig*> configs;
ParseConfigs( configs );
char szGame[MAX_PATH];
GetVConfigRegistrySetting( GAMEDIR_TOKEN, szGame, sizeof( szGame ) );
int activeConfig = -1;
CUtlVector<int> itemIDs;
itemIDs.SetSize( configs.Count() );
for ( int i=0; i < configs.Count(); i++ )
{
KeyValues *kv = new KeyValues( "values" );
kv->SetString( "ModDir", configs[i]->m_ModDir.Base() );
kv->SetPtr( "panel", m_pCurrentGameCombo );
// Check to see if this is our currently active game
if ( Q_stricmp( configs[i]->m_ModDir.Base(), szGame ) == 0 )
{
activeConfig = i;
}
itemIDs[i] = m_pCurrentGameCombo->AddItem( configs[i]->m_Name.Base(), kv );
kv->deleteThis();
}
// Activate the correct entry if valid
if ( itemIDs.Count() > 0 )
{
m_pCurrentGameCombo->SetEnabled( true );
if ( bSelectLast )
{
m_pCurrentGameCombo->ActivateItem( itemIDs[itemIDs.Count()-1] );
}
else
{
if ( activeConfig > -1 )
{
// Activate our currently selected game
m_pCurrentGameCombo->ActivateItem( activeConfig );
}
else
{
// Always default to the first otherwise
m_pCurrentGameCombo->ActivateItem( 0 );
}
}
}
else
{
m_pCurrentGameCombo->SetEnabled( false );
}
configs.PurgeAndDeleteElements();
}
//-----------------------------------------------------------------------------
// Purpose: Selection has changed in the active config drop-down, set the environment
//-----------------------------------------------------------------------------
void CSDKLauncherDialog::OnTextChanged( KeyValues *pkv )
{
const vgui::ComboBox* combo = (vgui::ComboBox*)pkv->GetPtr("panel");
if ( combo == m_pCurrentGameCombo)
{
KeyValues *kv = m_pCurrentGameCombo->GetActiveItemUserData();
if ( kv )
{
const char *modDir = kv->GetString( "ModDir" );
SetVConfigRegistrySetting( GAMEDIR_TOKEN, modDir, true );
}
}
else if ( combo == m_pCurrentEngineCombo )
{
KeyValues *kv = m_pCurrentEngineCombo->GetActiveItemUserData();
if ( kv )
{
const char *engineDir = kv->GetString( "EngineVer" );
SetEngineVersion( engineDir );
RefreshConfigs();
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Refresh our configs after a file change outside our process
//-----------------------------------------------------------------------------
void CSDKLauncherDialog::RefreshConfigs( void )
{
char szGameConfigDir[MAX_PATH];
V_strcpy_safe( szGameConfigDir, GetSDKLauncherBinDirectory() );
V_AppendSlash( szGameConfigDir, MAX_PATH );
V_strncat( szGameConfigDir, g_engineDir, MAX_PATH );
V_AppendSlash( szGameConfigDir, MAX_PATH );
V_strncat( szGameConfigDir, "bin", MAX_PATH );
// Set directory in which GameConfig.txt is found
g_ConfigManager.SetBaseDirectory( szGameConfigDir );
// Tell the config manager which games to put in the config by default
if ( !stricmp( g_engineDir, "ep1" ) )
{
g_ConfigManager.SetSDKEpoch( EP1 );
}
else if ( !stricmp( g_engineDir, "source2007" ) )
{
g_ConfigManager.SetSDKEpoch( EP2 );
}
else if ( !stricmp( g_engineDir, "source2009" ) )
{
g_ConfigManager.SetSDKEpoch( SP2009 );
}
else
{
g_ConfigManager.SetSDKEpoch( MP2009 );
}
// Load configurations
if ( g_ConfigManager.LoadConfigs( szGameConfigDir ) == false )
{
m_pCurrentGameCombo->DeleteAllItems();
m_pCurrentGameCombo->SetEnabled( false );
}
else
{
m_pCurrentGameCombo->SetEnabled( true );
if ( g_ConfigManager.WasConvertedOnLoad() )
{
// Notify of a conversion
CConversionInfoMessageBox *pDlg = new CConversionInfoMessageBox( this, "ConversionInfo" );
pDlg->RequestFocus();
pDlg->SetVisible( true );
pDlg->MoveToCenterOfScreen();
input()->SetAppModalSurface( pDlg->GetVPanel() );
}
}
// Dump the current settings and reparse the change
PopulateCurrentGameCombo( false );
}
//-----------------------------------------------------------------------------
// Purpose: Reset our config files
//-----------------------------------------------------------------------------
void CSDKLauncherDialog::ResetConfigs( void )
{
// Reset the configs
g_ConfigManager.ResetConfigs();
// Refresh the listing
PopulateCurrentGameCombo( false );
// Notify the user
VGUIMessageBox( this, "Complete", "Your game configurations have successfully been reset to their default values." );
}
void CSDKLauncherDialog::GetEngineVersion(char* pcEngineVer, int nSize)
{
IRegistry *reg = InstanceRegistry( "Source SDK" );
Assert( reg );
V_strncpy( pcEngineVer, reg->ReadString( "EngineVer", "orangebox" ), nSize );
ReleaseInstancedRegistry( reg );
}
void CSDKLauncherDialog::SetEngineVersion(const char *pcEngineVer)
{
IRegistry *reg = InstanceRegistry( "Source SDK" );
Assert( reg );
reg->WriteString( "EngineVer", pcEngineVer );
ReleaseInstancedRegistry( reg );
// Set the global to the same value as the registry
V_strncpy( g_engineDir, pcEngineVer, sizeof( g_engineDir ) );
}