|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "stdafx.h"
#include <shlobj.h>
#include "GameConfig.h"
#include "EditGameConfigs.h"
#include "hammer.h"
#include "OPTConfigs.h"
#include "ConfigManager.h"
#include "process.h"
#include "Options.h"
#include "TextureBrowser.h"
#include "tier2/vconfig.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
IMPLEMENT_DYNCREATE(COPTConfigs, CPropertyPage)
//-----------------------------------------------------------------------------
// Purpose: Returns the string value of a registry key
// Input : *pName - name of the subKey to read
// *pReturn - string buffer to receive read string
// size - size of specified buffer
//-----------------------------------------------------------------------------
bool GetPersistentEnvironmentVariable( const char *pName, char *pReturn, int size ) { // Open the key
HKEY hregkey; // Changed to HKEY_CURRENT_USER from HKEY_LOCAL_MACHINE
if ( RegOpenKeyEx( HKEY_CURRENT_USER, VPROJECT_REG_KEY, 0, KEY_QUERY_VALUE, &hregkey ) != ERROR_SUCCESS ) return false; // Get the value
DWORD dwSize = size; if ( RegQueryValueEx( hregkey, pName, NULL, NULL,(LPBYTE) pReturn, &dwSize ) != ERROR_SUCCESS ) return false; // Close the key
RegCloseKey( hregkey );
return true; }
//-----------------------------------------------------------------------------
// Purpose: Set the registry entry to a string value, under the given subKey
// Input : *pName - name of the subKey to set
// *pValue - string value
//-----------------------------------------------------------------------------
void SetPersistentEnvironmentVariable( const char *pName, const char *pValue ) { HKEY hregkey; DWORD dwReturnValue = 0;
// Changed from HKEY_LOCAL_MACHINE to HKEY_CURRENT_USER
if ( RegOpenKeyEx( HKEY_CURRENT_USER, VPROJECT_REG_KEY, 0, KEY_ALL_ACCESS, &hregkey ) != ERROR_SUCCESS ) return; // Set the value to the string passed in
RegSetValueEx( hregkey, pName, 0, REG_SZ, (const unsigned char *)pValue, (int) strlen(pValue) ); // Propagate changes so that environment variables takes immediate effect!
SendMessageTimeout( HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue );
// Close the key
RegCloseKey( hregkey ); }
//-----------------------------------------------------------------------------
// Purpose: Converts a Steam path prefix to %STEAM% and back.
//-----------------------------------------------------------------------------
void EditorUtil_ConvertPath(CString &str, bool bExpand) { CString strSteamDir; g_pGameConfig->GetSteamDir(strSteamDir);
CString strSteamUserDir; g_pGameConfig->GetSteamUserDir(strSteamUserDir);
if (!strSteamDir.GetLength() && !strSteamUserDir.GetLength()) { // Can't do the token replacement.
return; }
const char *szSteamDirToken = "$SteamDir"; const char *szSteamUserDirToken = "$SteamUserDir";
char szPathOut[MAX_PATH];
if (bExpand) { // Replace the tokens with the full strings
if (Q_StrSubst(str, szSteamUserDirToken, strSteamUserDir, szPathOut, sizeof(szPathOut))) { str = szPathOut; }
if (Q_StrSubst(str, szSteamDirToken, strSteamDir, szPathOut, sizeof(szPathOut))) { str = szPathOut; } } else { // Replace the full strings with the tokens
// Go from longest paths to shortest paths to insure the most brief expression.
if (Q_StrSubst(str, strSteamUserDir, szSteamUserDirToken, szPathOut, sizeof(szPathOut))) { str = szPathOut; }
if (Q_StrSubst(str, strSteamDir, szSteamDirToken, szPathOut, sizeof(szPathOut))) { str = szPathOut; } } }
//-----------------------------------------------------------------------------
// Purpose: Exchanges path data between a CString and an edit control, converting
// the Steam path to %STEAM% and back.
//-----------------------------------------------------------------------------
void EditorUtil_TransferPath(CDialog *pDlg, int nIDC, char *szDest, bool bExpand) { CWnd *pwnd = pDlg->GetDlgItem(nIDC); if (!pwnd) return;
CString str;
if (bExpand) { pwnd->GetWindowText(str); EditorUtil_ConvertPath(str, true); strcpy(szDest, str); } else { str = szDest; EditorUtil_ConvertPath(str, false); pwnd->SetWindowText(str); } }
//-----------------------------------------------------------------------------
// Purpose: Constructor.
//-----------------------------------------------------------------------------
COPTConfigs::COPTConfigs(void) : CPropertyPage(COPTConfigs::IDD) { //{{AFX_DATA_INIT(COPTConfigs)
//}}AFX_DATA_INIT
m_pLastSelConfig = NULL; m_pInitialSelectedConfig = NULL; }
//-----------------------------------------------------------------------------
// Purpose: Destructor.
//-----------------------------------------------------------------------------
COPTConfigs::~COPTConfigs(void) { }
//-----------------------------------------------------------------------------
// Purpose:
// Input : pDX -
//-----------------------------------------------------------------------------
void COPTConfigs::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(COPTConfigs)
DDX_Control(pDX, IDC_MAPDIR, m_cMapDir); DDX_Control(pDX, IDC_GAMEEXEDIR, m_cGameExeDir); DDX_Control(pDX, IDC_MODDIR, m_cModDir); DDX_Control(pDX, IDC_MAPFORMAT, m_cMapFormat); DDX_Control(pDX, IDC_CORDON_TEXTURE, m_cCordonTexture); DDX_Control(pDX, IDC_TEXTUREFORMAT, m_cTextureFormat); DDX_Control(pDX, IDC_DEFAULTPOINT, m_cDefaultPoint); DDX_Control(pDX, IDC_DEFAULTENTITY, m_cDefaultSolid); DDX_Control(pDX, IDC_DATAFILES, m_cGDFiles); DDX_Control(pDX, IDC_CONFIGURATIONS, m_cConfigs); DDX_Control(pDX, IDC_DEFAULT_TEXTURE_SCALE, m_cDefaultTextureScale); //}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(COPTConfigs, CPropertyPage) //{{AFX_MSG_MAP(COPTConfigs)
ON_BN_CLICKED(IDC_EDITCONFIGS, OnEditconfigs) ON_BN_CLICKED(IDC_GDFILE_ADD, OnGdfileAdd) ON_BN_CLICKED(IDC_GDFILE_EDIT, OnGdfileEdit) ON_BN_CLICKED(IDC_GDFILE_REMOVE, OnGdfileRemove) ON_CBN_SELCHANGE(IDC_CONFIGURATIONS, OnSelchangeConfigurations) ON_BN_CLICKED(IDC_BROWSEMAPDIR, OnBrowsemapdir) ON_BN_CLICKED(IDC_BROWSEGAMEEXEDIR, OnBrowseGameExeDir) ON_BN_CLICKED(IDC_BROWSEMODDIR, OnBrowseModDir) ON_BN_CLICKED(IDC_BROWSE_CORDON_TEXTURE, OnBrowseCordonTexture) ON_MESSAGE( WM_SETTINGCHANGE, OnSettingChange ) //}}AFX_MSG_MAP
END_MESSAGE_MAP()
void COPTConfigs::OnEditconfigs(void) { SaveInfo(m_pLastSelConfig);
CEditGameConfigs dlg; dlg.DoModal(); UpdateConfigList(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void COPTConfigs::OnGdfileAdd(void) { if (m_pLastSelConfig == NULL) return;
char szAppDir[MAX_PATH]; APP()->GetDirectory(DIR_PROGRAM, szAppDir);
// browse for .FGD files
CFileDialog dlg(TRUE, ".fgd", NULL, OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_FILEMUSTEXIST, "Game Data Files (*.fgd)|*.fgd||"); dlg.m_ofn.lpstrInitialDir = szAppDir; if (dlg.DoModal() != IDOK) return;
CString str = dlg.GetPathName(); EditorUtil_ConvertPath(str, false); m_cGDFiles.AddString(str);
SaveInfo(m_pLastSelConfig); m_pLastSelConfig->LoadGDFiles(); UpdateEntityLists(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void COPTConfigs::OnGdfileEdit(void) { if(m_pLastSelConfig == NULL) return;
// edit the selected FGD file
int iCurSel = m_cGDFiles.GetCurSel(); if(iCurSel == LB_ERR) return;
CString str; m_cGDFiles.GetText(iCurSel, str); EditorUtil_ConvertPath(str, true);
// call editor (notepad!)
char szBuf[MAX_PATH]; GetWindowsDirectory(szBuf, MAX_PATH); strcat(szBuf, "\\notepad.exe"); _spawnl(_P_WAIT, szBuf, szBuf, str, NULL);
m_pLastSelConfig->LoadGDFiles(); UpdateEntityLists(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void COPTConfigs::OnGdfileRemove(void) { if(m_pLastSelConfig == NULL) return;
int iCurSel = m_cGDFiles.GetCurSel(); if(iCurSel == LB_ERR) return;
m_cGDFiles.DeleteString(iCurSel);
SaveInfo(m_pLastSelConfig); m_pLastSelConfig->LoadGDFiles(); UpdateEntityLists(); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pConfig -
//-----------------------------------------------------------------------------
void COPTConfigs::SaveInfo(CGameConfig *pConfig) { if (pConfig == NULL) { return; }
// game data files
pConfig->nGDFiles = 0; pConfig->GDFiles.RemoveAll(); int iSize = m_cGDFiles.GetCount(); for(int i = 0; i < iSize; i++) { CString str; m_cGDFiles.GetText(i, str);
EditorUtil_ConvertPath(str, true);
pConfig->GDFiles.Add(str); ++pConfig->nGDFiles; }
//
// Map file type.
//
int nIndex = m_cMapFormat.GetCurSel(); if (nIndex != CB_ERR) { pConfig->mapformat = (MAPFORMAT)m_cMapFormat.GetItemData(nIndex); } else { pConfig->mapformat = mfHalfLife2; }
//
// WAD file type.
//
nIndex = m_cTextureFormat.GetCurSel(); if (nIndex != CB_ERR) { pConfig->SetTextureFormat((TEXTUREFORMAT)m_cTextureFormat.GetItemData(nIndex)); } else { pConfig->SetTextureFormat(tfVMT); }
m_cDefaultSolid.GetWindowText(pConfig->szDefaultSolid, sizeof pConfig->szDefaultSolid); m_cDefaultPoint.GetWindowText(pConfig->szDefaultPoint, sizeof pConfig->szDefaultPoint);
EditorUtil_TransferPath(this, IDC_GAMEEXEDIR, pConfig->m_szGameExeDir, true); EditorUtil_TransferPath(this, IDC_MODDIR, pConfig->m_szModDir, true); EditorUtil_TransferPath(this, IDC_MAPDIR, pConfig->szMapDir, true);
char szCordonTexture[MAX_PATH]; m_cCordonTexture.GetWindowText(szCordonTexture, sizeof(szCordonTexture)); pConfig->SetCordonTexture(szCordonTexture);
//
// Default texture scale.
//
char szText[100]; m_cDefaultTextureScale.GetWindowText(szText, sizeof(szText)); float fScale = (float)atof(szText); if (fScale == 0) { fScale = 1; } pConfig->SetDefaultTextureScale(fScale);
//
// Default lightmap scale.
//
int nLightmapScale = GetDlgItemInt(IDC_DEFAULT_LIGHTMAP_SCALE, NULL, FALSE); pConfig->SetDefaultLightmapScale(nLightmapScale); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void COPTConfigs::OnSelchangeConfigurations(void) { // save info from controls into last selected config
SaveInfo(m_pLastSelConfig);
m_pLastSelConfig = NULL;
// load info from newly selected config into controls
int iCurSel = m_cConfigs.GetCurSel(); CGameConfig *pConfig = Options.configs.FindConfig(m_cConfigs.GetItemData(iCurSel));
BOOL bKillFields = FALSE; if (pConfig == NULL) { bKillFields = TRUE; }
m_cGDFiles.EnableWindow(!bKillFields); m_cDefaultPoint.EnableWindow(!bKillFields); m_cDefaultSolid.EnableWindow(!bKillFields); m_cTextureFormat.EnableWindow(!bKillFields); m_cMapFormat.EnableWindow(!bKillFields); m_cGameExeDir.EnableWindow(!bKillFields); m_cModDir.EnableWindow(!bKillFields); m_cMapDir.EnableWindow(!bKillFields); m_cCordonTexture.EnableWindow(!bKillFields);
if (pConfig == NULL) { return; }
m_pLastSelConfig = pConfig;
// load game data files
m_cGDFiles.ResetContent(); for (int i = 0; i < pConfig->nGDFiles; i++) { CString str(pConfig->GDFiles[i]); EditorUtil_ConvertPath(str, false); m_cGDFiles.AddString(str); }
//
// Select the correct map format.
//
m_cMapFormat.SetCurSel(0); int nItems = m_cMapFormat.GetCount(); for (int i = 0; i < nItems; i++) { if (pConfig->mapformat == (MAPFORMAT)m_cMapFormat.GetItemData(i)) { m_cMapFormat.SetCurSel(i); break; } }
//
// Select the correct texture format.
//
m_cTextureFormat.SetCurSel(0); nItems = m_cTextureFormat.GetCount(); for (int i = 0; i < nItems; i++) { if (pConfig->GetTextureFormat() == (TEXTUREFORMAT)m_cTextureFormat.GetItemData(i)) { m_cTextureFormat.SetCurSel(i); break; } }
EditorUtil_TransferPath(this, IDC_GAMEEXEDIR, pConfig->m_szGameExeDir, false); EditorUtil_TransferPath(this, IDC_MODDIR, pConfig->m_szModDir, false); EditorUtil_TransferPath(this, IDC_MAPDIR, pConfig->szMapDir, false);
m_cCordonTexture.SetWindowText(pConfig->GetCordonTexture()); char szText[100]; sprintf(szText, "%g", pConfig->GetDefaultTextureScale()); m_cDefaultTextureScale.SetWindowText(szText);
SetDlgItemInt(IDC_DEFAULT_LIGHTMAP_SCALE, pConfig->GetDefaultLightmapScale(), FALSE); // load entity type comboboxes and set strings
UpdateEntityLists(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void COPTConfigs::UpdateEntityLists(void) { if(m_pLastSelConfig == NULL) return;
m_cDefaultPoint.ResetContent(); m_cDefaultSolid.ResetContent();
CGameConfig *pConfig = m_pLastSelConfig;
int nCount = pConfig->GD.GetClassCount(); for (int i = 0; i < nCount; i++) { GDclass *pClass = pConfig->GD.GetClass(i); if (pClass->IsBaseClass()) { continue; } else if (pClass->IsSolidClass()) { m_cDefaultSolid.AddString(pClass->GetName()); } else { m_cDefaultPoint.AddString(pClass->GetName()); } }
if (pConfig->szDefaultSolid[0] != '\0') { m_cDefaultSolid.SetWindowText(pConfig->szDefaultSolid); } else { m_cDefaultSolid.SetCurSel(0); }
if (pConfig->szDefaultPoint[0] != '\0') { m_cDefaultPoint.SetWindowText(pConfig->szDefaultPoint); } else { m_cDefaultPoint.SetCurSel(0); } }
//-----------------------------------------------------------------------------
// Purpose: Fills the combo box with the list of configs. Tries to select the
// config that was selected before coming in or, failing that, the
// currently active config.
//-----------------------------------------------------------------------------
void UpdateConfigList(CComboBox &combo) { int iCurSel = combo.GetCurSel(); DWORD dwSelID = 0xffffffff; if (iCurSel != CB_ERR) { dwSelID = combo.GetItemData(iCurSel); }
combo.ResetContent();
// add configs to the combo box
for (int i = 0; i < Options.configs.nConfigs; i++) { CGameConfig *pConfig = Options.configs.Configs[i];
int iIndex = combo.AddString(pConfig->szName); combo.SetItemData(iIndex, pConfig->dwID); }
if (dwSelID == 0xffffffff) { dwSelID = g_pGameConfig->dwID; }
// Find the item with the given ID.
int nSelIndex = -1; for (int i = 0; i < Options.configs.nConfigs; i++) { DWORD dwData = combo.GetItemData(i); if (dwData == dwSelID) { nSelIndex = i; } }
combo.SetCurSel(nSelIndex == -1 ? 0 : nSelIndex); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void SelectActiveConfig(CComboBox &combo) { char szGameDir[MAX_PATH]; if (GetPersistentEnvironmentVariable(GAMEDIR_TOKEN, szGameDir, sizeof(szGameDir))) { CGameConfig *pConfig = Options.configs.FindConfigForGame(szGameDir); if (pConfig) { // Find the item with the given ID.
int nSelIndex = -1; int nCount = combo.GetCount(); for (int i = 0; i < nCount; i++) { DWORD dwData = combo.GetItemData(i); if (pConfig->dwID == dwData) { nSelIndex = i; break; } }
if (nSelIndex != -1) { combo.SetCurSel(nSelIndex); } } } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void COPTConfigs::UpdateConfigList() { m_pLastSelConfig = NULL;
::UpdateConfigList(m_cConfigs); ::SelectActiveConfig(m_cConfigs);
OnSelchangeConfigurations(); SetModified(); }
//-----------------------------------------------------------------------------
// Purpose: Populates the combo boxes with the map formats and WAD formats, and
// the list of game configurations.
//-----------------------------------------------------------------------------
BOOL COPTConfigs::OnInitDialog(void) { CPropertyPage::OnInitDialog();
int nIndex;
//
// Add map formats.
//
nIndex = m_cMapFormat.AddString("Half-Life 2"); m_cMapFormat.SetItemData(nIndex, mfHalfLife2);
nIndex = m_cMapFormat.AddString("Half-Life / TFC"); m_cMapFormat.SetItemData(nIndex, mfHalfLife);
//
// Add texture formats.
//
nIndex = m_cTextureFormat.AddString("Materials (Half-Life 2)"); m_cTextureFormat.SetItemData(nIndex, tfVMT);
nIndex = m_cTextureFormat.AddString("WAD3 (Half-Life / TFC)"); m_cTextureFormat.SetItemData(nIndex, tfWAD3); UpdateConfigList();
int nCurSel = m_cConfigs.GetCurSel(); m_pInitialSelectedConfig = Options.configs.FindConfig(m_cConfigs.GetItemData(nCurSel));
m_strInitialGameDir.Empty(); if (m_pInitialSelectedConfig) { m_strInitialGameDir = m_pInitialSelectedConfig->m_szModDir; }
return TRUE; }
//-----------------------------------------------------------------------------
// Purpose: Returns true if the given config is different from the one set when
// OnInitDialog was called.
//-----------------------------------------------------------------------------
bool COPTConfigs::ConfigChanged(CGameConfig *pConfig) { if (m_pInitialSelectedConfig != pConfig) return true;
if (pConfig && m_pInitialSelectedConfig) { if (m_pInitialSelectedConfig->dwID != pConfig->dwID) return true;
if (m_strInitialGameDir.CompareNoCase(pConfig->m_szModDir)) return true; }
return false; }
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL COPTConfigs::OnApply(void) { SaveInfo(m_pLastSelConfig);
int nCurSel = m_cConfigs.GetCurSel(); CGameConfig *pConfig = Options.configs.FindConfig(m_cConfigs.GetItemData(nCurSel));
if ( pConfig != NULL && ConfigChanged( pConfig ) ) { SetPersistentEnvironmentVariable("vproject", pConfig->m_szModDir); AfxMessageBox("Your changes to the active configuration will not take effect until the next time you run Hammer."); }
Options.PerformChanges(COptions::secConfigs); return CPropertyPage::OnApply(); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pszTitle -
// *pszDirectory -
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL COPTConfigs::BrowseForFolder(char *pszTitle, char *pszDirectory) { char szTmp[MAX_PATH];
BROWSEINFO bi; memset(&bi, 0, sizeof bi); bi.hwndOwner = m_hWnd; bi.pszDisplayName = szTmp; bi.lpszTitle = pszTitle; bi.ulFlags = BIF_RETURNONLYFSDIRS;
LPITEMIDLIST idl = SHBrowseForFolder(&bi);
if(idl == NULL) return FALSE;
SHGetPathFromIDList(idl, pszDirectory); CoTaskMemFree(idl);
return TRUE; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void COPTConfigs::OnBrowseCordonTexture(void) { CTextureBrowser *pBrowser = new CTextureBrowser(this); if (pBrowser != NULL) { //
// Use the currently selected texture format for browsing.
//
TEXTUREFORMAT eTextureFormat = tfVMT; int nIndex = m_cTextureFormat.GetCurSel(); if (nIndex != LB_ERR) { eTextureFormat = (TEXTUREFORMAT)m_cTextureFormat.GetItemData(nIndex); } pBrowser->SetTextureFormat(eTextureFormat);
//
// Select the current cordon texture in the texture browser.
//
CString strTex; m_cCordonTexture.GetWindowText(strTex); pBrowser->SetInitialTexture(strTex);
if (pBrowser->DoModal() == IDOK) { m_cCordonTexture.SetWindowText(pBrowser->m_cTextureWindow.szCurTexture); }
delete pBrowser; } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void COPTConfigs::OnBrowseGameExeDir(void) { char szTmp[MAX_PATH]; if (!BrowseForFolder("Select Game Executable Directory", szTmp)) { return; }
CString str(szTmp); EditorUtil_ConvertPath(str, false); m_cGameExeDir.SetWindowText(str); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void COPTConfigs::OnBrowseModDir(void) { char szTmp[MAX_PATH]; if (!BrowseForFolder("Select Mod Directory", szTmp)) { return; }
CString str(szTmp); EditorUtil_ConvertPath(str, false); m_cModDir.SetWindowText(str); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void COPTConfigs::OnBrowsemapdir(void) { char szTmp[MAX_PATH]; if (!BrowseForFolder("Select Map Directory", szTmp)) { return; }
CString str(szTmp); EditorUtil_ConvertPath(str, false); m_cMapDir.SetWindowText(str); }
//-----------------------------------------------------------------------------
// Purpose: Handles the notification from the VCONFIG that the active config has changed.
//-----------------------------------------------------------------------------
LRESULT COPTConfigs::OnSettingChange(WPARAM wParam, LPARAM lParam) { const char *changedSection = (const char *)lParam; if ( Q_stricmp( changedSection, "Environment" ) == 0 ) { UpdateConfigList(); //SelectActiveConfig();
}
return 0; }
|