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.
 
 
 
 
 
 

1426 lines
48 KiB

//======= Copyright (c) 1996-2009, Valve Corporation, All rights reserved. ======
//
// Purpose: Video configuration management (split out from tier2)
//
//===============================================================================
#include "tier2/fileutils.h"
#include "tier2/tier2.h"
#include "videocfg.h"
#include "tier1/tier1.h"
#include "tier1/strtools.h"
#include "filesystem.h"
#include "tier1/keyvalues.h"
#include "utlbuffer.h"
#include "mathlib/IceKey.H"
#include "tier0/icommandline.h"
// Video Config Filenames
#ifdef POSIX
#define VIDEOCONFIG_DEFAULT_FILENAME "cfg/videodefaults.txt"
#define VIDEOCONFIG_FILENAME "cfg/video.txt"
#define VIDEOCONFIG_FILENAME_BACKUP "cfg/video.bak"
#else
#define VIDEOCONFIG_DEFAULT_FILENAME "cfg\\videodefaults.txt"
#define VIDEOCONFIG_FILENAME "cfg\\video.txt"
#define VIDEOCONFIG_FILENAME_BACKUP "cfg\\video.bak"
#endif
#define VIDEOCONFIG_PATHID "USRLOCAL"
static void WriteVideoCfgDataToFile( char const *pszFile, CUtlBuffer &buf )
{
// Video defaults and video settings detection runs very early, so we need to create cfg path in USRLOCAL storage
g_pFullFileSystem->CreateDirHierarchy( "cfg", "USRLOCAL" );
g_pFullFileSystem->WriteFile( pszFile, VIDEOCONFIG_PATHID, buf );
}
enum AspectRatioMode_t
{
ASPECT_RATIO_OTHER = -1,
ASPECT_RATIO_4x3 = 0,
ASPECT_RATIO_16x9,
ASPECT_RATIO_16x10,
};
struct VideoConfigSetting_t
{
const char *m_pSettingVar;
bool m_bChooseLower;
bool m_bSaved;
bool m_bConVar;
bool m_bUseAutoOption;
};
struct RatioToAspectMode_t
{
AspectRatioMode_t m_Mode;
int m_nWidth;
int m_nHeight;
};
static VideoConfigSetting_t s_pVideoConfigSettingsWhitelist[] =
{
// ConVars.
{ "setting.cpu_level", true, true, true, true },
{ "setting.gpu_level", true, true, true, true },
{ "setting.mat_antialias", true, true, true, true },
{ "setting.mat_aaquality", true, true, true, true },
{ "setting.mat_forceaniso", true, true, true, true },
{ "setting.mat_vsync", true, true, true },
{ "setting.mat_triplebuffered", true, true, true },
{ "setting.mat_grain_scale_override", true, true, true },
// { "setting.mat_monitorgamma", true, true, true },
{ "setting.gpu_mem_level", true, true, true, true },
{ "setting.mem_level", true, true, true },
{ "setting.videoconfig_version", true, true, true },
{ "setting.mat_queue_mode", true, true, true },
{ "setting.mat_tonemapping_occlusion_use_stencil", false, false, true },
{ "setting.csm_quality_level", true, true, true, true },
{ "setting.mat_software_aa_strength", true, true, true },
{ "setting.mat_motion_blur_enabled", true, true, true },
// Settings.
{ "setting.fullscreen", true, true, false },
{ "setting.nowindowborder", true, true, false },
{ "setting.aspectratiomode", true, true, false },
{ "setting.defaultres", true, true, false },
{ "setting.defaultresheight", true, true, false },
{ "setting.dxlevel", true, false, false },
{ "setting.mindxlevel", true, false, false },
{ "setting.maxdxlevel", true, false, false },
{ "setting.preferhardwaresync", true, false, false },
{ "setting.centroidhack", true, false, false },
{ "setting.preferzprepass", true, false, false },
{ "setting.prefertexturesinhwmemory", true, false, false },
{ "setting.laptop", true, false, false },
{ "setting.suppresspixelshadercentroidhackfixup", true, false, false },
{ "setting.nouserclipplanes", true, false, false },
{ "setting.unsupported", true, false, false },
};
static VideoConfigSetting_t const * VideoConfigSettingFindWhitelistEntryByName( char const *szSettingName )
{
for ( int k = 0; k < Q_ARRAYSIZE( s_pVideoConfigSettingsWhitelist ); ++ k )
{
if ( !V_stricmp( szSettingName, s_pVideoConfigSettingsWhitelist[k].m_pSettingVar ) )
return &s_pVideoConfigSettingsWhitelist[k];
}
return NULL;
}
static RatioToAspectMode_t g_pRatioToAspectModes[] =
{
{ ASPECT_RATIO_4x3, 4, 3 },
{ ASPECT_RATIO_16x9, 16, 9 },
{ ASPECT_RATIO_16x10, 16, 10 },
};
//--------------------------------------------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
static AspectRatioMode_t GetScreenAspectMode( int width, int height )
{
for (int i = 0; i < ARRAYSIZE(g_pRatioToAspectModes); i++)
{
int nFactor = width / g_pRatioToAspectModes[i].m_nWidth;
if ( nFactor * g_pRatioToAspectModes[i].m_nHeight == height )
return g_pRatioToAspectModes[i].m_Mode;
}
return ASPECT_RATIO_OTHER;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
static inline int ReadHexValue( KeyValues *pVal, const char *pName )
{
const char *pString = pVal->GetString( pName, NULL );
if (!pString)
{
return -1;
}
char *pTemp;
int nVal = strtol( pString, &pTemp, 16 );
return (pTemp != pString) ? nVal : -1;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
void AddNewKeysUsingVideoWhitelist( KeyValues *pModKeys, KeyValues *pConfigKeys )
{
for( KeyValues *pSubKey = pModKeys->GetFirstSubKey(); pSubKey; pSubKey = pSubKey->GetNextKey() )
{
const char *pSubKeyName = pSubKey->GetName();
// Find all the "setting" keys that are white-listed and add them to the
// Video Config keys.
int iVar;
bool bWhiteListedVar = false;
int nVideoConfigCount = ARRAYSIZE( s_pVideoConfigSettingsWhitelist );
for ( iVar = 0; iVar < nVideoConfigCount; ++iVar )
{
if ( !V_stricmp( s_pVideoConfigSettingsWhitelist[iVar].m_pSettingVar, pSubKeyName ) )
{
bWhiteListedVar = true;
break;
}
}
// This is not a valid key.
if ( !bWhiteListedVar )
continue;
// See if the key already exists - if it doesn't add it.
if ( pConfigKeys->FindKey( pSubKeyName ) )
continue;
const char *pValue = pSubKey->GetString();
pConfigKeys->SetString( pSubKeyName, pValue );
}
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
void CopySettingKeysUsingVideoWhitelist( KeyValues *pModKeys, KeyValues *pConfigKeys )
{
for( KeyValues *pSubKey = pModKeys->GetFirstSubKey(); pSubKey; pSubKey = pSubKey->GetNextKey() )
{
const char *pSubKeyName = pSubKey->GetName();
// Find all the "setting" keys that are white-listed and add them to the
// Video Config keys.
int iVar;
bool bWhiteListedVar = false;
int nVideoConfigCount = ARRAYSIZE( s_pVideoConfigSettingsWhitelist );
for ( iVar = 0; iVar < nVideoConfigCount; ++iVar )
{
if ( !V_stricmp( s_pVideoConfigSettingsWhitelist[iVar].m_pSettingVar, pSubKeyName ) )
{
bWhiteListedVar = true;
break;
}
}
// This is not a valid key.
if ( !bWhiteListedVar )
continue;
if ( pConfigKeys->FindKey( pSubKeyName ) )
{
float flOldValue = pConfigKeys->GetFloat( pSubKeyName );
float flNewValue = pSubKey->GetFloat();
if ( s_pVideoConfigSettingsWhitelist[iVar].m_bChooseLower )
{
if ( flNewValue >= flOldValue )
continue;
}
else
{
if ( flNewValue <= flOldValue )
continue;
}
}
const char *pValue = pSubKey->GetString();
pConfigKeys->SetString( pSubKeyName, pValue );
}
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Match the CPU data and add all the "setting" data to the Video Config Keys.
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
void AddCPULevelKeys( KeyValues *pModKeys, KeyValues *pVideoConfigKeys )
{
// Get the number of physical processors in the machine.
const CPUInformation &cpuInfo = GetCPUInformation();
int nProcessorCount = cpuInfo.m_nPhysicalProcessors;
// Test all "cpu_level_*" blocks to determine the correct block to copy data from.
for( KeyValues *pModKey = pModKeys->GetFirstSubKey(); pModKey; pModKey = pModKey->GetNextKey() )
{
KeyValues *pMinKey = pModKey->FindKey( "min_processor_count" );
KeyValues *pMaxKey = pModKey->FindKey( "max_processor_count" );
if ( pMinKey && pMaxKey )
{
int nMin = pMinKey->GetInt();
int nMax = pMaxKey->GetInt();
// Is this the correct cpu_level setting.
if ( nMin <= nProcessorCount && nProcessorCount <= nMax )
{
CopySettingKeysUsingVideoWhitelist( pModKey, pVideoConfigKeys );
}
}
}
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
void AddMemoryKeys( KeyValues *pModKeys, int nMemory, KeyValues *pVideoConfigKeys )
{
for( KeyValues *pModKey = pModKeys->GetFirstSubKey(); pModKey; pModKey = pModKey->GetNextKey() )
{
KeyValues *pMinMegabytes = pModKey->FindKey( "min megabytes" );
KeyValues *pMaxMegabytes = pModKey->FindKey( "max megabytes" );
if ( pMinMegabytes && pMaxMegabytes )
{
int nMin = pMinMegabytes->GetInt();
int nMax = pMaxMegabytes->GetInt();
// Is this the correct cpu_level setting.
if ( nMin <= nMemory && nMemory <= nMax )
{
CopySettingKeysUsingVideoWhitelist( pModKey, pVideoConfigKeys );
}
}
}
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
void AddVideoMemoryKeys( KeyValues *pModKeys, int nVidMemory, KeyValues *pVideoConfigKeys )
{
for( KeyValues *pModKey = pModKeys->GetFirstSubKey(); pModKey; pModKey = pModKey->GetNextKey() )
{
KeyValues *pMinMegaTexels = pModKey->FindKey( "min megatexels" );
KeyValues *pMaxMegaTexels = pModKey->FindKey( "max megatexels" );
if ( pMinMegaTexels && pMaxMegaTexels )
{
int nMin = pMinMegaTexels->GetInt();
int nMax = pMaxMegaTexels->GetInt();
// Is this the correct cpu_level setting.
if ( nMin <= nVidMemory && nVidMemory <= nMax )
{
CopySettingKeysUsingVideoWhitelist( pModKey, pVideoConfigKeys );
}
}
}
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Match the device and vendor id and add all the "setting" data to
// the Video Config Keys.
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
bool AddVideoCardKeys( KeyValues *pModKeys, int nVendorID, int nDeviceID, KeyValues *pVideoConfigKeys )
{
bool bFoundDevice = false;
// Test all video card blocks to determine the correct blocks to copy data from.
for( KeyValues *pModKey = pModKeys->GetFirstSubKey(); pModKey; pModKey = pModKey->GetNextKey() )
{
// Get and match the vendor and device id.
int iVender = ReadHexValue( pModKey, "vendorid" );
if ( iVender == -1 )
continue;
int iDeviceMin = ReadHexValue( pModKey, "mindeviceid" );
int iDeviceMax = ReadHexValue( pModKey, "maxdeviceid" );
if ( iDeviceMin == -1 || iDeviceMax == -1 )
continue;
// Only initialize with unknown data if we didn't find the actual card.
bool bUnknownDevice = ( pModKey->FindKey( "makemelast" ) != NULL );
// Fixed for CS:GO - Don't apply this node's keys at all unless the node's vendor ID matches (for example, some NVidia device ID's, such as the 6800's, alias a few Intel ID's).
if ( ( iDeviceMin <= nDeviceID ) && ( nDeviceID <= iDeviceMax ) && ( nVendorID == iVender ) )
{
if ( !bUnknownDevice )
{
CopySettingKeysUsingVideoWhitelist( pModKey, pVideoConfigKeys );
bFoundDevice = true;
}
else
{
AddNewKeysUsingVideoWhitelist( pModKey, pVideoConfigKeys );
}
}
}
return bFoundDevice;
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Match the device and vendor id and add all the "setting" data to
// the Video Config Keys.
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
void AddDXLevelKeys( KeyValues *pModKeys, int nDXLevel, KeyValues *pVideoConfigKeys )
{
// Test all video card blocks to determine the correct blocks to copy data from.
for( KeyValues *pModKey = pModKeys->GetFirstSubKey(); pModKey; pModKey = pModKey->GetNextKey() )
{
KeyValues *pDXLevelKey = pModKey->FindKey( "setting.maxdxlevel" );
if ( !pDXLevelKey )
continue;
if ( pDXLevelKey->GetInt() == nDXLevel )
{
AddNewKeysUsingVideoWhitelist( pModKey, pVideoConfigKeys );
}
}
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
bool ParseConfigKeys( VidMatConfigData_t &configData )
{
// Does the file exist?
bool bFileExists = g_pFullFileSystem->FileExists( configData.szFileName, configData.szPathID );
if ( !bFileExists )
return false;
// Get the key values in the file.
KeyValues *pFileKeys = new KeyValues( "FileKeys" );
if ( !pFileKeys )
return false;
if ( !pFileKeys->LoadFromFile( g_pFullFileSystem, configData.szFileName, configData.szPathID ) )
{
pFileKeys->deleteThis();
return false;
}
#ifdef _DEBUG
Msg( "VIDEOCFG.ParseConfigKeys: (start)\n" );
KeyValuesDumpAsDevMsg( configData.pConfigKeys, 0, 0 );
#endif
// Add Config Keys based on cpu.
AddCPULevelKeys( pFileKeys, configData.pConfigKeys );
#ifdef _DEBUG
Msg( "VIDEOCFG.ParseConfigKeys: (+cpu_level)\n" );
KeyValuesDumpAsDevMsg( configData.pConfigKeys, 0, 0 );
#endif
// Add Config Keys based on memory.
AddMemoryKeys( pFileKeys, configData.nSystemMemory, configData.pConfigKeys );
#ifdef _DEBUG
Msg( "VIDEOCFG.ParseConfigKeys: (+memory)\n" );
KeyValuesDumpAsDevMsg( configData.pConfigKeys, 0, 0 );
#endif
// Add Config Keys based on video memory.
AddVideoMemoryKeys( pFileKeys, configData.nVideoMemory, configData.pConfigKeys );
#ifdef _DEBUG
Msg( "VIDEOCFG.ParseConfigKeys: (+video memory)\n" );
KeyValuesDumpAsDevMsg( configData.pConfigKeys, 0, 0 );
#endif
// Add Config Keys based on video card.
bool bFoundDevice = AddVideoCardKeys( pFileKeys, configData.nVendorID, configData.nDeviceID, configData.pConfigKeys );
#ifdef _DEBUG
Msg( "VIDEOCFG.ParseConfigKeys: (+video card)\n" );
KeyValuesDumpAsDevMsg( configData.pConfigKeys, 0, 0 );
#endif
// Add Config Keys based on DXLevel.
if ( !bFoundDevice )
{
//
// This actually doesn't work for CS:GO the way moddefaults.txt is setup
//
AddDXLevelKeys( pFileKeys, configData.nDXLevel, configData.pConfigKeys );
}
// Destroy the file keys.
pFileKeys->deleteThis();
return true;
}
#endif
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
static bool GetNearestFullscreenResolution( int& nWidth, int& nHeight, VidMatConfigData_t &configData )
{
float flDesiredArea = nWidth * nHeight;
int nBestWidth = 0;
int nBestHeight = 0;
float flBestDelta = FLT_MAX;
AspectRatioMode_t nRequiredAspectMode = GetScreenAspectMode( configData.nPhysicalScreenWidth, configData.nPhysicalScreenHeight );
// Iterate modes, looking for one that is just smaller than currentWidth and currentHeight while retaining the aspect ratio
while ( true )
{
for ( int i = 0; i < configData.displayModes.Count(); i++ )
{
const ShaderDisplayMode_t &mode = configData.displayModes[i];
if ( nRequiredAspectMode != ASPECT_RATIO_OTHER )
{
AspectRatioMode_t nAspectMode = GetScreenAspectMode( mode.m_nWidth, mode.m_nHeight );
if ( nRequiredAspectMode != nAspectMode )
continue;
}
float flArea = mode.m_nWidth * mode.m_nHeight;
if ( flArea > flDesiredArea * 1.35f )
continue;
float flDelta = fabs( flDesiredArea - flArea );
if ( flDelta >= flBestDelta )
continue;
flBestDelta = flDelta;
nBestWidth = mode.m_nWidth;
nBestHeight = mode.m_nHeight;
}
if ( nBestWidth != 0 )
break;
if ( nRequiredAspectMode == ASPECT_RATIO_OTHER )
return false;
nRequiredAspectMode = ASPECT_RATIO_OTHER;
}
nWidth = nBestWidth;
nHeight = nBestHeight;
return true;
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Create the video config file and fill it in with default data.
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
bool CreateDefaultVideoKeyValues( VidMatConfigData_t &configData )
{
// Sets the highest CSM quality level and enabled FXAA, then let the csm_quality_level settings in moddefaults override these settings with lower values.
configData.pConfigKeys->SetInt( "setting.csm_quality_level", CSMQUALITY_HIGH ); //g_pHardwareConfig->GetCSMQuality() );
configData.pConfigKeys->SetInt( "setting.mat_software_aa_strength", 1 );
// Set the vendor and device id key values.
configData.pConfigKeys->SetInt( "VendorID", configData.nVendorID );
configData.pConfigKeys->SetInt( "DeviceID", configData.nDeviceID );
// Initial config always assume v-sync, normal aspect ratio, and fullscreen.
configData.pConfigKeys->SetInt( "setting.fullscreen", 1 );
configData.pConfigKeys->SetInt( "setting.nowindowborder", 0 );
configData.pConfigKeys->SetInt( "setting.aspectratiomode", GetScreenAspectMode( configData.nPhysicalScreenWidth, configData.nPhysicalScreenHeight ) );
configData.pConfigKeys->SetInt( "setting.mat_vsync", IsGameConsole() ? 1 : 0 );
configData.pConfigKeys->SetInt( "setting.mat_triplebuffered", 0 );
configData.pConfigKeys->SetFloat( "setting.mat_monitorgamma", 2.2f );
configData.pConfigKeys->SetInt( "setting.mat_queue_mode", -1 );
// Before, mat_motion_blur_enabled came from gpu_level.csv (it was set to 0 at GPU levels 0 and 1, and 1 at higher levels).
// These GPU levels are not that useful in CS:GO any longer (because we've dumped a bunch of old cards not capable of at least shader model 3), and
// it's now a video option, so we need a better way of defaulting mat_motion_blur_enabled in fresh installs. For now, the safest choice on all cards is
// disabled.
configData.pConfigKeys->SetInt( "setting.mat_motion_blur_enabled", 0 );
// Not all video card DXSupport configs define GPU mem level, default it to High
#if defined( DX_TO_GL_ABSTRACTION )
configData.pConfigKeys->SetInt( "setting.gpu_mem_level", 3 );
#else
configData.pConfigKeys->SetInt( "setting.gpu_mem_level", 2 );
#endif
// Assume if we don't find a GPU level then it's a high level recent GPU
configData.pConfigKeys->SetInt( "setting.gpu_level", 3 );
// Assume if we don't find a lower mat_antialias value then we will run at the highest support MSAA setting
#if defined( DX_TO_GL_ABSTRACTION )
configData.pConfigKeys->SetInt( "setting.mat_antialias", 0 );
#else
if ( materials->SupportsMSAAMode( 8 ) )
configData.pConfigKeys->SetInt( "setting.mat_antialias", 8 );
else if ( materials->SupportsMSAAMode( 4 ) )
configData.pConfigKeys->SetInt( "setting.mat_antialias", 4 );
else if ( materials->SupportsMSAAMode( 2 ) )
configData.pConfigKeys->SetInt( "setting.mat_antialias", 2 );
else
configData.pConfigKeys->SetInt( "setting.mat_antialias", 0 );
#endif
// None of our moddefaults.txt specify CSAA settings, so default quality to zero
configData.pConfigKeys->SetInt( "setting.mat_aaquality", 0 );
// Get the key value you data from the defined file.
if ( !ParseConfigKeys( configData ) )
return false;
// LEGACY: mat_antialias = 1 - if such configuration is found just set it to zero (CS:GO video options interpret NONE that way)
if ( configData.pConfigKeys->GetInt( "setting.mat_antialias", 0 ) == 1 )
configData.pConfigKeys->SetInt( "setting.mat_antialias", 0 );
// Set the default resolution based on the aspect ratio mode
// int nWidth = configData.pConfigKeys->GetInt( "setting.defaultres" );
// int nHeight = configData.pConfigKeys->GetInt( "setting.defaultresheight" );
// Ignore moddefaults configuration that might be outdated, just default to user's desktop resolution
int nWidth = configData.nPhysicalScreenWidth;
int nHeight = configData.nPhysicalScreenHeight;
if ( GetNearestFullscreenResolution( nWidth, nHeight, configData ) )
{
configData.pConfigKeys->SetInt( "setting.defaultres", nWidth );
configData.pConfigKeys->SetInt( "setting.defaultresheight", nHeight );
}
return true;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
static bool VerifyVideoConfigSettingRequired( char const *szSetting )
{
static char const * arrIgnoredSettings[] = { "setting.mem_level" };
for ( int j = 0; j < Q_ARRAYSIZE( arrIgnoredSettings ); ++ j )
{
if ( !V_stricmp( arrIgnoredSettings[j], szSetting ) )
return false;
}
return true;
}
bool VerifyDefaultVideoConfig( VidMatConfigData_t &configData )
{
// Make sure the file exists to verify.
bool bFileExists = g_pFullFileSystem->FileExists( VIDEOCONFIG_DEFAULT_FILENAME, VIDEOCONFIG_PATHID );
if ( !bFileExists )
return false;
// Open the moddefaults.cfg file and load it into key values.
KeyValues *pDefaultKeys = new KeyValues( "DefaultKeys" );
if ( !pDefaultKeys )
return false;
if ( !pDefaultKeys->LoadFromFile( g_pFullFileSystem, VIDEOCONFIG_DEFAULT_FILENAME, VIDEOCONFIG_PATHID ) )
{
pDefaultKeys->deleteThis();
return false;
}
// Derive the default state from dxsupport.cfg and moddefaults.txt.
if ( !CreateDefaultVideoKeyValues( configData ) )
{
pDefaultKeys->deleteThis();
return false;
}
// Diagnostic buffer
CUtlBuffer bufDiagnostic( 0, 0, CUtlBuffer::TEXT_BUFFER );
// Start with the assumption they are the same.
bool bEqual = true;
for( KeyValues *pTestKey = configData.pConfigKeys->GetFirstSubKey(); pTestKey; pTestKey = pTestKey->GetNextKey() )
{
const char *pszTestName = pTestKey->GetName();
KeyValues *pFindKey = pDefaultKeys->FindKey( pszTestName );
if ( !pFindKey )
{
Warning( "The default video config has changed, config key '%s=%s' is no longer default.\n", pszTestName, pTestKey->GetString() );
bufDiagnostic.Printf( "config key '%s=%s' is no longer default.\n", pszTestName, pTestKey->GetString() );
if ( VerifyVideoConfigSettingRequired( pszTestName ) )
bEqual = false;
}
else if ( V_stricmp( pFindKey->GetString(), pTestKey->GetString() ) )
{
Warning( "The default video config has changed, config key '%s=%s' is no longer default '%s'.\n", pszTestName, pTestKey->GetString(), pFindKey->GetString() );
bufDiagnostic.Printf( "config key '%s=%s' is no longer default '%s'.\n", pszTestName, pTestKey->GetString(), pFindKey->GetString() );
if ( VerifyVideoConfigSettingRequired( pszTestName ) )
bEqual = false;
}
}
// If we are still equal - test to see if the default file has any keys that have been removed by the default config.
if ( bEqual )
{
for( KeyValues *pTestKey = pDefaultKeys->GetFirstSubKey(); pTestKey; pTestKey = pTestKey->GetNextKey() )
{
const char *pszTestName = pTestKey->GetName();
KeyValues *pFindKey = configData.pConfigKeys->FindKey( pszTestName );
if ( !pFindKey )
{
Warning( "The default video config has changed, config key '%s=%s' has been added.\n", pszTestName, pTestKey->GetString() );
bufDiagnostic.Printf( "config key '%s=%s' has been added.\n", pszTestName, pTestKey->GetString() );
if ( VerifyVideoConfigSettingRequired( pszTestName ) )
bEqual = false;
}
}
}
// If we are not equal, put up some warning and reset the current video config file.
if ( !bEqual )
{
Warning( "VerifyDefaultVideoConfig: The default video config for the machine has changed, updating the current config to match.\n" );
bufDiagnostic.Printf( "--ConfigData--\n" );
configData.pConfigKeys->RecursiveSaveToFile( bufDiagnostic, 0 );
bufDiagnostic.Printf( "--Defaults--\n" );
pDefaultKeys->RecursiveSaveToFile( bufDiagnostic, 0 );
bufDiagnostic.Printf( "----\n" );
char chBuffer[64] = {};
struct tm tmNow;
Plat_GetLocalTime( &tmNow );
V_sprintf_safe( chBuffer, "cfg\\video.change%u.txt", Plat_timegm( &tmNow ) );
WriteVideoCfgDataToFile( chBuffer, bufDiagnostic );
// Create the file.
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
configData.pConfigKeys->RecursiveSaveToFile( buf, 0 );
WriteVideoCfgDataToFile( VIDEOCONFIG_DEFAULT_FILENAME, buf );
//
// Upgrade user's video preferences with new default autoconfig
//
KeyValues *kvPreviousVideoCfg = new KeyValues( "videocfg" );
if ( kvPreviousVideoCfg->LoadFromFile( g_pFullFileSystem, VIDEOCONFIG_FILENAME, VIDEOCONFIG_PATHID ) )
{
// Preserve all settings that support auto, but user had on a custom setting
for ( int k = 0; k < Q_ARRAYSIZE( s_pVideoConfigSettingsWhitelist ); ++ k )
{
if ( !s_pVideoConfigSettingsWhitelist[k].m_bUseAutoOption ) continue;
int nUserPreferenceValue = kvPreviousVideoCfg->GetInt( s_pVideoConfigSettingsWhitelist[k].m_pSettingVar, 9999999 );
if ( nUserPreferenceValue != 9999999 )
{
// User had explicit value, so store same explicit value in new video config
configData.pConfigKeys->SetInt( s_pVideoConfigSettingsWhitelist[ k ].m_pSettingVar, nUserPreferenceValue );
}
else
{
// User had auto configured value or no value at all, if the new default config has a value then
// make sure it is set on auto here
if ( KeyValues *kvSubKey = configData.pConfigKeys->FindKey( s_pVideoConfigSettingsWhitelist[ k ].m_pSettingVar ) )
{
char chNewAutoName[ 128 ];
// e.g.: "setting.cpu_level" -> "setauto.cpu_level"
V_sprintf_safe( chNewAutoName, "setauto.%s", s_pVideoConfigSettingsWhitelist[ k ].m_pSettingVar + 8 );
kvSubKey->SetName( chNewAutoName );
}
}
}
}
else
{
FOR_EACH_SUBKEY( configData.pConfigKeys, kvSubKey )
{
if ( VideoConfigSetting_t const *pSetting = VideoConfigSettingFindWhitelistEntryByName( kvSubKey->GetName() ) )
{
if ( pSetting->m_bUseAutoOption )
{
char chNewAutoName[ 128 ];
// e.g.: "setting.cpu_level" -> "setauto.cpu_level"
V_sprintf_safe( chNewAutoName, "setauto.%s", pSetting->m_pSettingVar + 8 );
kvSubKey->SetName( chNewAutoName );
}
}
}
}
kvPreviousVideoCfg->deleteThis();
buf.Purge();
configData.pConfigKeys->RecursiveSaveToFile( buf, 0 );
WriteVideoCfgDataToFile( VIDEOCONFIG_FILENAME, buf );
}
// Destroy keys.
configData.pConfigKeys->Clear();
pDefaultKeys->deleteThis();
return true;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
bool CopyDefaultVideoToCurrentVideoConfig( const char *pszDefaultFileName, const char *pszCurrentFileName )
{
bool bFileExists = g_pFullFileSystem->FileExists( pszDefaultFileName, VIDEOCONFIG_PATHID );
if ( !bFileExists )
return false;
// Open the moddefaults.cfg file and load it into key values.
KeyValues *pDefaultKeys = new KeyValues( "DefaultKeys" );
if ( !pDefaultKeys )
return false;
if ( !pDefaultKeys->LoadFromFile( g_pFullFileSystem, pszDefaultFileName, VIDEOCONFIG_PATHID ) )
{
pDefaultKeys->deleteThis();
return false;
}
// Create the file.
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
pDefaultKeys->RecursiveSaveToFile( buf, 0 );
WriteVideoCfgDataToFile( pszCurrentFileName, buf );
// Destroy the keys.
pDefaultKeys->deleteThis();
return true;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
bool CreateDefaultVideoConfig( VidMatConfigData_t &configData )
{
// Create the default video keys.
if ( !CreateDefaultVideoKeyValues( configData ) )
return false;
// Create the file with default settings
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
configData.pConfigKeys->RecursiveSaveToFile( buf, 0 );
WriteVideoCfgDataToFile( VIDEOCONFIG_DEFAULT_FILENAME, buf );
//
// Now write the file with user settings skipping the settings that support "AUTO" in options
//
FOR_EACH_SUBKEY( configData.pConfigKeys, kvSubKey )
{
if ( VideoConfigSetting_t const *pSetting = VideoConfigSettingFindWhitelistEntryByName( kvSubKey->GetName() ) )
{
if ( pSetting->m_bUseAutoOption )
{
char chNewAutoName[128];
// e.g.: "setting.cpu_level" -> "setauto.cpu_level"
V_sprintf_safe( chNewAutoName, "setauto.%s", pSetting->m_pSettingVar + 8 );
kvSubKey->SetName( chNewAutoName );
}
}
}
buf.Purge();
configData.pConfigKeys->RecursiveSaveToFile( buf, 0 );
WriteVideoCfgDataToFile( VIDEOCONFIG_FILENAME, buf );
// Clear out the data after writing the file.
configData.pConfigKeys->Clear();
return true;
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Look for a video config file to setup the system defaults. Create the
// file if one doesn't already exist.
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
bool BLoadUserVideoConfigFileFromDisk( KeyValues *pConfigKeys )
{
// Parse current video file, note that some settings will be on AUTO with setauto
// their values are ensured by code above to match the default autoconfig values
if ( !pConfigKeys->LoadFromFile( g_pFullFileSystem, VIDEOCONFIG_FILENAME, VIDEOCONFIG_PATHID ) )
return false;
// load the default config as well to expand setauto. fields
KeyValues *kvDefaultSettings = new KeyValues( "default" );
if ( !kvDefaultSettings->LoadFromFile( g_pFullFileSystem, VIDEOCONFIG_DEFAULT_FILENAME, VIDEOCONFIG_PATHID ) )
{
kvDefaultSettings->deleteThis();
kvDefaultSettings = NULL;
}
// bloat the AUTO detected settings for compatibility as proper 'setting.' fields
FOR_EACH_SUBKEY( pConfigKeys, kvSubKey )
{
if ( char const *szSetting = StringAfterPrefix( kvSubKey->GetName(), "setauto." ) )
{
char chNewAutoName[ 128 ];
// e.g.: "setauto.cpu_level" -> "setting.cpu_level"
V_sprintf_safe( chNewAutoName, "setting.%s", szSetting );
if ( KeyValues *kvValueDefault = kvDefaultSettings->FindKey( chNewAutoName ) )
{
pConfigKeys->AddSubKey( kvValueDefault->MakeCopy() );
}
}
}
if ( kvDefaultSettings )
{
kvDefaultSettings->deleteThis();
kvDefaultSettings = NULL;
}
return true;
}
bool RecommendedVideoConfig( VidMatConfigData_t &configData )
{
// Get the default video config file if it exists, create it otherwise.
bool bFileExists = g_pFullFileSystem->FileExists( VIDEOCONFIG_DEFAULT_FILENAME, VIDEOCONFIG_PATHID );
if ( !bFileExists )
{
if ( !CreateDefaultVideoConfig( configData ) )
return false;
}
else
{
// Verify the default data is up to date.
VerifyDefaultVideoConfig( configData );
}
return BLoadUserVideoConfigFileFromDisk( configData.pConfigKeys );
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
bool RecommendedConfig( VidMatConfigData_t &configData )
{
// Verify that the file system has been created.
Assert( g_pFullFileSystem != NULL );
// If we are a video - this is a special case.
if ( configData.bIsVideo )
{
return RecommendedVideoConfig( configData );
}
// Parse the configuration keys.
return ParseConfigKeys( configData );
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
bool ResetVideoConfigToDefaults( KeyValues *pConfigKeys )
{
// Copy the defaults settings into the current = Reset.
if ( !CopyDefaultVideoToCurrentVideoConfig( VIDEOCONFIG_DEFAULT_FILENAME, VIDEOCONFIG_FILENAME ) )
return false;
// Copy the new key values if there the config keys exist.
if ( pConfigKeys )
{
return pConfigKeys->LoadFromFile( g_pFullFileSystem, VIDEOCONFIG_FILENAME, VIDEOCONFIG_PATHID );
}
return true;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
bool UpdateCurrentVideoConfig( int nWidth, int nHeight, int nAspectRatioMode, bool bFullscreen, bool bNoWindow, bool bUseRestartConvars )
{
// Create and Init the video config block.
KeyValues *pVideoConfigKeys = new KeyValues( "VideoConfig" );
if ( !pVideoConfigKeys )
return false;
// Go through each of the video settings and save off all necessary data.
int nVideoConfigCount = ARRAYSIZE( s_pVideoConfigSettingsWhitelist );
for ( int iVar = 0; iVar < nVideoConfigCount; ++iVar )
{
// Do we need to save this setting?
if ( !s_pVideoConfigSettingsWhitelist[iVar].m_bSaved )
continue;
// Strip off the "setting." prefix and check for a ConVar
// Strip off the "setting." prefix and check for a ConVar
char szConVarName[256];
int nStringLength = V_strlen( s_pVideoConfigSettingsWhitelist[iVar].m_pSettingVar );
nStringLength -= 8;
if ( nStringLength <= 0 )
continue;
V_StrRight( s_pVideoConfigSettingsWhitelist[iVar].m_pSettingVar, nStringLength, szConVarName, sizeof( szConVarName ) );
bool bAutodetectedSetting = false;
{
char szConVarRestart[ 256 ];
if ( s_pVideoConfigSettingsWhitelist[ iVar ].m_bUseAutoOption )
{
V_snprintf( szConVarRestart, sizeof( szConVarRestart ), "%s_optionsui", szConVarName );
ConVarRef cvOptionsUi( szConVarRestart );
if ( cvOptionsUi.IsValid() )
{
bAutodetectedSetting = ( cvOptionsUi.GetInt() == 9999999 );
}
}
if ( bUseRestartConvars )
{
V_snprintf( szConVarRestart, sizeof( szConVarRestart ), "%s_restart", szConVarName );
if ( g_pCVar->FindVar( szConVarRestart ) )
{
V_strncpy( szConVarName, szConVarRestart, sizeof( szConVarName ) );
}
}
}
// Is it a CVar? If so, get the value.
const ConVar *pVar = g_pCVar->FindVar( szConVarName );
if ( pVar )
{
if ( bAutodetectedSetting )
{
char chSettingAutoName[ 128 ];
V_sprintf_safe( chSettingAutoName, "setauto.%s", s_pVideoConfigSettingsWhitelist[ iVar ].m_pSettingVar + 8 );
pVideoConfigKeys->SetString( chSettingAutoName, pVar->GetString() );
}
else
{
pVideoConfigKeys->SetString( s_pVideoConfigSettingsWhitelist[ iVar ].m_pSettingVar, pVar->GetString() );
}
}
}
// Set these window settings.
pVideoConfigKeys->SetInt( "setting.defaultres", nWidth );
pVideoConfigKeys->SetInt( "setting.defaultresheight", nHeight );
pVideoConfigKeys->SetInt( "setting.aspectratiomode", nAspectRatioMode );
pVideoConfigKeys->SetInt( "setting.fullscreen", static_cast<int>( bFullscreen ) );
pVideoConfigKeys->SetInt( "setting.nowindowborder", static_cast<int>( bNoWindow ) );
// Write out the file.
// Create the file.
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
pVideoConfigKeys->RecursiveSaveToFile( buf, 0 );
WriteVideoCfgDataToFile( VIDEOCONFIG_FILENAME, buf );
// Destroy keys.
pVideoConfigKeys->deleteThis();
return true;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
bool UpdateVideoConfigConVars( KeyValues *pConfigKeys )
{
bool bAllocConfig = false;
if ( !pConfigKeys )
{
// Create and Init the video config block.
pConfigKeys = new KeyValues( "VideoConfig" );
if ( !pConfigKeys )
return false;
if ( !BLoadUserVideoConfigFileFromDisk( pConfigKeys ) )
{
pConfigKeys->deleteThis();
return false;
}
bAllocConfig = true;
}
#ifdef _DEBUG
Msg( "UpdateVideoConfigConVars:\n" );
KeyValuesDumpAsDevMsg( pConfigKeys, 0, 0 );
#endif
ConVar *pVarOptionsUiCallback = g_pCVar->FindVar( "videooptions_optionsui_callback_disabled" );
int nVideoConfigCount = ARRAYSIZE( s_pVideoConfigSettingsWhitelist );
for ( int iVar = 0; iVar < nVideoConfigCount; ++iVar )
{
// Do we need to save this setting?
if ( !s_pVideoConfigSettingsWhitelist[iVar].m_bConVar )
continue;
// Strip off the "setting." prefix and check for a ConVar
char szConVarName[256];
int nStringLength = V_strlen( s_pVideoConfigSettingsWhitelist[iVar].m_pSettingVar );
nStringLength -= 8;
if ( nStringLength <= 0 )
continue;
V_StrRight( s_pVideoConfigSettingsWhitelist[iVar].m_pSettingVar, nStringLength, szConVarName, sizeof( szConVarName ) );
ConVar *pVar = g_pCVar->FindVar( szConVarName );
if ( !pVar )
continue;
KeyValues *pFindKey = pConfigKeys->FindKey( s_pVideoConfigSettingsWhitelist[iVar].m_pSettingVar );
if ( !pFindKey )
continue;
// Always allow the command line to totally override whatever convars come from the videocfg system.
char szOption[256];
V_snprintf( szOption, sizeof( szOption ), "+%s", szConVarName );
if ( CommandLine()->CheckParm( szOption ) )
{
const char *pOverrideValue = CommandLine()->ParmValue( szOption, pFindKey->GetString() );
pVar->SetValue( pOverrideValue );
Warning( "UpdateVideoConfigConVars: Value of convar \"%s\" is being set from the cmd line, so this value will not be set by the video config system\n", szConVarName );
continue;
}
pVar->SetValue( pFindKey->GetString() );
{
char szConVarRestart[ 256 ];
V_sprintf_safe( szConVarRestart, "%s_restart", szConVarName );
if ( ConVar *pVarRestart = g_pCVar->FindVar( szConVarRestart ) )
{
pVarRestart->SetValue( pFindKey->GetString() );
}
}
if ( s_pVideoConfigSettingsWhitelist[iVar].m_bUseAutoOption )
{
char szConVarOptionsUi[ 256 ];
V_sprintf_safe( szConVarOptionsUi, "%s_optionsui", szConVarName );
if ( ConVar *pVarOptionsUi = g_pCVar->FindVar( szConVarOptionsUi ) )
{
if ( pVarOptionsUiCallback )
pVarOptionsUiCallback->SetValue( 1 );
// Check if the config instructs the convar to list as "AUTO"?
char chSettingAutoName[128];
V_sprintf_safe( chSettingAutoName, "setauto.%s", s_pVideoConfigSettingsWhitelist[iVar].m_pSettingVar + 8 );
if ( pConfigKeys->FindKey( chSettingAutoName ) )
pVarOptionsUi->SetValue( 9999999 );
else
pVarOptionsUi->SetValue( pFindKey->GetString() );
if ( pVarOptionsUiCallback )
pVarOptionsUiCallback->SetValue( 0 );
}
}
}
// If we created it - destroy it!
if ( bAllocConfig )
{
pConfigKeys->deleteThis();
}
return true;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#if !defined( _GAMECONSOLE )
bool ReadCurrentVideoConfig( KeyValues *pConfigKeys, bool bDefault )
{
if ( !pConfigKeys )
return false;
if ( !bDefault )
{
// Do we have a current video config file? If not, copy the defaults file.
if ( !g_pFullFileSystem->FileExists( VIDEOCONFIG_FILENAME, VIDEOCONFIG_PATHID ) )
return false;
// Parse current video file.
return BLoadUserVideoConfigFileFromDisk( pConfigKeys );
}
else
{
// Do we have a current video config file? If not, copy the defaults file.
if ( !g_pFullFileSystem->FileExists( VIDEOCONFIG_DEFAULT_FILENAME, VIDEOCONFIG_PATHID ) )
return false;
// Parse current video file.
return pConfigKeys->LoadFromFile( g_pFullFileSystem, VIDEOCONFIG_DEFAULT_FILENAME, VIDEOCONFIG_PATHID );
}
}
#endif
const unsigned char *GetModEncryptionKey( const char *pModName )
{
if ( !V_strnicmp( "left4dead", pModName, V_strlen("left4dead") ) )
return (unsigned char*)"zp14Hi(]";
else if ( !V_strnicmp( "portal2", pModName, V_strlen("portal2") ) )
return (unsigned char *)"UrE66!Ap";
else if ( !V_strnicmp( "csgo", pModName, V_strlen("csgo") ) )
return (unsigned char *)"aY7!rn[z";
else if ( !V_strnicmp( "infested", pModName, V_strlen("infested") ) )
return (unsigned char *)"sW9.JupP";
else if ( !V_strnicmp( "ep2", pModName, V_strlen("ep2") ) )
return (unsigned char *)"Xx81uBl)";
else if ( !V_strnicmp( "tf", pModName, V_strlen("tf") ) )
return (unsigned char *)"E2NcUkG2";
else if ( !V_strnicmp( "nimbus", pModName, V_strlen("nimbus") ) )
return (unsigned char *)"E2NcUkG2";
else if ( !V_strnicmp( "dota", pModName, V_strlen( "dota" ) ) )
return (unsigned char *)"dAIt1IL!";
else
return (unsigned char*)"X8bU2qll";
}
KeyValues* ReadEncryptedKVFile( const char *pRelativePath, const char *pPathID, const char *pModName )
{
// Open the keyvalues, and abort if we can't
FileHandle_t f = g_pFullFileSystem->Open( pRelativePath, "rb", pPathID );
if ( !f )
{
return NULL;
}
// load file into a null-terminated buffer
int fileSize = g_pFullFileSystem->Size( f );
char *buffer = (char*)stackalloc( fileSize + 1 );
g_pFullFileSystem->Read( buffer, fileSize, f );
buffer[fileSize] = 0;
g_pFullFileSystem->Close( f );
DecodeICE( (unsigned char*)buffer, fileSize, GetModEncryptionKey( pModName ) );
KeyValues *pKV = new KeyValues( "kv" );
bool retOK = pKV->LoadFromBuffer( pRelativePath, buffer, g_pFullFileSystem );
if ( !retOK )
{
pKV->deleteThis();
return NULL;
}
return pKV;
}
struct SystemLevelConvar_t
{
const char *m_pConVar;
bool m_bChooseLower;
bool m_bAllowed;
};
SystemLevelConvar_t s_pConVarsAllowedInSystemLevel[] =
{
{ "lower_body", true, true },
{ "r_shadow_half_update_rate", false, true },
{ "r_rainparticledensity", true, true },
{ "cl_particle_fallback_base", false, true },
{ "cl_particle_fallback_multiplier",false, true },
{ "r_flashlightdepthtexture", true, true },
{ "r_shadowrendertotexture", true, true },
{ "r_shadowfromworldlights", true, true },
{ "cl_detaildist", true, true },
{ "cl_detailfade", true, true },
{ "r_drawmodeldecals", true, false }, // force consistency across all levels
#ifndef _PS3
{ "r_decalstaticprops", true, false }, // force consistency across all levels
#endif
{ "ragdoll_sleepaftertime", true, true },
{ "cl_phys_maxticks", true, true },
{ "r_worldlightmin", true, true },
{ "props_break_max_pieces", true, true },
{ "r_worldlights", true, true },
{ "r_decals", true, false }, // force consistency across all levels
{ "r_decal_overlap_count", true, false }, // force consistency across all levels
{ "mat_bumpmap", true, true },
{ "mat_detail_tex", true, true },
{ "mat_specular", true, true },
{ "mat_phong", true, true },
{ "mat_grain_enable", true, true },
{ "mat_local_contrast_enable", true, true },
{ "mat_motion_blur_enabled", true, true },
{ "mat_disablehwmorph", false, true },
{ "r_overlayfademin", true, true },
{ "r_overlayfademax", true, true },
{ "z_mob_simple_shadows", false, true },
{ "cl_ragdoll_maxcount", true, true },
{ "cl_ragdoll_maxcount_gib", true, true },
{ "cl_ragdoll_maxcount_generic", true, true },
{ "cl_ragdoll_maxcount_special", true, true },
{ "sv_ragdoll_maxcount", true, true },
{ "sv_ragdoll_maxcount_gib", true, true },
{ "sv_ragdoll_maxcount_generic", true, true },
{ "sv_ragdoll_maxcount_special", true, true },
{ "z_infected_decals", true, true },
{ "cl_impacteffects_limit_general", true, true },
{ "cl_impacteffects_limit_exit", true, true },
{ "cl_impacteffects_limit_water", true, true },
{ "cl_ragdoll_self_collision", true, true },
{ "cl_player_max_decal_count", true, true },
{ "cl_footstep_fx", true, true },
{ "mp_usehwmvcds", true, true },
{ "mp_usehwmmodels", true, true },
{ "mat_depthfeather_enable", true, true },
{ "mat_dxlevel", true, true },
{ "r_flashlightinfectedfov", true, true },
{ "r_flashlightinfectedfar", true, true },
{ "r_flashlightinfectedlinear", true, true },
{ "r_rootlod", false, true },
{ "mat_picmip", false, true },
{ "mat_force_vertexfog", false, true },
{ "r_simpleworldmodel_waterreflections_fullscreen", false, true },
{ "r_simpleworldmodel_drawforrecursionlevel_fullscreen", true, true },
{ "r_simpleworldmodel_drawbeyonddistance_fullscreen", true, true },
{ "r_simpleworldmodel_waterreflections_splitscreen", true, true },
{ "r_simpleworldmodel_drawforrecursionlevel_splitscreen",true, true },
{ "r_simpleworldmodel_drawbeyonddistance_splitscreen", true, true },
{ "r_simpleworldmodel_waterreflections_pip", true, true },
{ "r_simpleworldmodel_drawforrecursionlevel_pip", true, true },
{ "r_simpleworldmodel_drawbeyonddistance_pip", true, true },
{ "r_lod_switch_scale", true, true },
{ "r_lod", false, true },
{ "r_paintblob_highres_cube", false, true },
{ "r_paintblob_force_single_pass", true, true },
{ "r_paintblob_max_number_of_threads", true, true },
{ "cl_csm_enabled", true, true },
};
void PerformSystemConfiguration( KeyValues *pResult, int nSystemLevel, const char *pConfigFile, const char *pModName, bool bUseSplitScreenCfg, bool bVGUIIsSplitscreen )
{
char pCfgFile[MAX_PATH];
if ( nSystemLevel == CONSOLE_SYSTEM_LEVEL_PS3 )
{
// PS3
Q_snprintf( pCfgFile, sizeof(pCfgFile), "cfg\\%s_ps3", pConfigFile );
}
else
{
// everything else
Q_snprintf( pCfgFile, sizeof(pCfgFile), "cfg\\%s_%d", pConfigFile, nSystemLevel );
}
if ( !IsGameConsole() )
{
Q_strncat( pCfgFile, "_pc", sizeof(pCfgFile) );
}
if ( bUseSplitScreenCfg && bVGUIIsSplitscreen )
{
Q_strncat( pCfgFile, "_ss", sizeof(pCfgFile) );
}
Q_strncat( pCfgFile, ".ekv", sizeof(pCfgFile) );
KeyValues *pKeyValues = ReadEncryptedKVFile( pCfgFile, "GAME", pModName );
if ( !pKeyValues )
{
DevWarning( "PerformSystemConfiguration: Missing %s\n", pCfgFile );
return;
}
for( KeyValues *pKey = pKeyValues->GetFirstSubKey(); pKey; pKey = pKey->GetNextKey() )
{
const char *pCVarName = pKey->GetName();
// Check if legal
int i;
bool bLegalVar = false;
for( i=0; i < ARRAYSIZE( s_pConVarsAllowedInSystemLevel ); i++ )
{
if ( !Q_stricmp( s_pConVarsAllowedInSystemLevel[i].m_pConVar, pCVarName ) )
{
bLegalVar = true;
break;
}
}
if ( !bLegalVar )
{
DevWarning("PerformSystemConfiguration: Bad convar found in %s - %s\n", pConfigFile, pCVarName );
continue;
}
if ( !s_pConVarsAllowedInSystemLevel[i].m_bAllowed )
{
#ifdef _DEBUG
DevWarning("PerformSystemConfiguration: Skipping convar found in %s - %s\n", pConfigFile, pCVarName );
#endif
continue;
}
if ( pResult->FindKey( pCVarName ) )
{
float flOldValue = pResult->GetFloat( pCVarName );
float flNewValue = pKey->GetFloat();
if ( s_pConVarsAllowedInSystemLevel[i].m_bChooseLower )
{
if ( flNewValue >= flOldValue )
continue;
}
else
{
if ( flNewValue <= flOldValue )
continue;
}
}
const char *pValue = pKey->GetString();
pResult->SetString( pCVarName, pValue );
}
pKeyValues->deleteThis();
}
void UpdateSystemLevel( int nCPULevel, int nGPULevel, int nMemLevel, int nGPUMemLevel, bool bVGUIIsSplitscreen, const char *pModName )
{
KeyValues *pKeyValues = new KeyValues( "kv" );
PerformSystemConfiguration( pKeyValues, nCPULevel, "cpu_level", pModName, true, bVGUIIsSplitscreen );
PerformSystemConfiguration( pKeyValues, nGPULevel, "gpu_level", pModName, false, bVGUIIsSplitscreen );
PerformSystemConfiguration( pKeyValues, nMemLevel, "mem_level", pModName, false, bVGUIIsSplitscreen );
PerformSystemConfiguration( pKeyValues, nGPUMemLevel, "gpu_mem_level", pModName, false, bVGUIIsSplitscreen );
for( KeyValues *pKey = pKeyValues->GetFirstSubKey(); pKey; pKey = pKey->GetNextKey() )
{
const char *pCVarName = pKey->GetName();
ConVar *pConVar = g_pCVar->FindVar( pCVarName );
if ( !pConVar )
continue;
// We want this on all platforms now - having the config system always slam convars being defined on the cmd line is just too confusing.
//if ( IsX360() )
{
bool bFound = false;
for ( int i=1; !bFound && i < CommandLine()->ParmCount(); i++ )
{
const char *szParm = CommandLine()->GetParm(i);
if ( szParm && szParm[0] == '+' )
{
bFound = ( V_stricmp( pCVarName, szParm + 1 ) == 0 );
}
}
if ( bFound )
{
// found on command line, ignore any value the script would have set
Warning( "UpdateSystemLevel: System configuration ignoring %s due to command line override\n", pCVarName );
continue;
}
}
if ( pConVar->GetFlags() & ( FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE | FCVAR_CHEAT ) )
{
Warning( "UpdateSystemLevel: ConVar %s controlled by gpu_level/cpu_level must not be marked as FCVAR_ARCHIVE or FCVAR_CHEAT!\n", pCVarName );
continue;
}
pConVar->SetValue( pKey->GetString() );
}
pKeyValues->deleteThis();
}