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.
2323 lines
71 KiB
2323 lines
71 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//============================================================================= |
|
|
|
#include "pch_serverbrowser.h" |
|
|
|
#if defined( _X360 ) |
|
#include "xbox/xbox_win32stubs.h" |
|
#endif |
|
|
|
using namespace vgui; |
|
|
|
#define FILTER_ALLSERVERS 0 |
|
#define FILTER_SECURESERVERSONLY 1 |
|
#define FILTER_INSECURESERVERSONLY 2 |
|
|
|
#define UNIVERSE_OFFICIAL 0 |
|
#define UNIVERSE_CUSTOMGAMES 1 |
|
#define QUICKLIST_FILTER_MIN_PING 0 |
|
|
|
#define MAX_MAP_NAME 128 |
|
const char *COM_GetModDirectory(); |
|
|
|
#undef wcscat |
|
|
|
ConVar sb_mod_suggested_maxplayers( "sb_mod_suggested_maxplayers", "0", FCVAR_HIDDEN ); |
|
ConVar sb_filter_incompatible_versions( "sb_filter_incompatible_versions", |
|
#ifdef STAGING_ONLY |
|
"0", |
|
#else |
|
"1", |
|
#endif |
|
0, "Hides servers running incompatible versions from the server browser. (Internet tab only.)" ); |
|
|
|
bool GameSupportsReplay() |
|
{ |
|
extern IEngineReplay *g_pEngineReplay; |
|
return g_pEngineReplay && g_pEngineReplay->IsSupportedModAndPlatform(); |
|
} |
|
|
|
#ifdef STAGING_ONLY |
|
ConVar sb_fake_app_id( "sb_fake_app_id", "0", 0, "If nonzero, then server browser requests will use this App ID instead" ); |
|
#endif |
|
|
|
//-------------------------------------------------------------------------------------------------------- |
|
bool IsReplayServer( gameserveritem_t &server ) |
|
{ |
|
bool bReplay = false; |
|
|
|
if ( GameSupportsReplay() ) |
|
{ |
|
if ( server.m_szGameTags && server.m_szGameTags[0] ) |
|
{ |
|
CUtlVector<char*> TagList; |
|
V_SplitString( server.m_szGameTags, ",", TagList ); |
|
for ( int i = 0; i < TagList.Count(); i++ ) |
|
{ |
|
if ( Q_stricmp( TagList[i], "replays" ) == 0 ) |
|
{ |
|
bReplay = true; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return bReplay; |
|
} |
|
|
|
//-------------------------------------------------------------------------------------------------------- |
|
inline char *CloneString( const char *str ) |
|
{ |
|
char *cloneStr = new char [ strlen(str)+1 ]; |
|
strcpy( cloneStr, str ); |
|
return cloneStr; |
|
} |
|
|
|
const char *COM_GetModDirectory() |
|
{ |
|
static char modDir[MAX_PATH]; |
|
if ( Q_strlen( modDir ) == 0 ) |
|
{ |
|
const char *gamedir = CommandLine()->ParmValue("-game", CommandLine()->ParmValue( "-defaultgamedir", "hl2" ) ); |
|
Q_strncpy( modDir, gamedir, sizeof(modDir) ); |
|
if ( strchr( modDir, '/' ) || strchr( modDir, '\\' ) ) |
|
{ |
|
Q_StripLastDir( modDir, sizeof(modDir) ); |
|
int dirlen = Q_strlen( modDir ); |
|
Q_strncpy( modDir, gamedir + dirlen, sizeof(modDir) - dirlen ); |
|
} |
|
} |
|
|
|
return modDir; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor |
|
//----------------------------------------------------------------------------- |
|
CGameListPanel::CGameListPanel( CBaseGamesPage *pOuter, const char *pName ) : |
|
BaseClass( pOuter, pName ) |
|
{ |
|
m_pOuter = pOuter; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Forward KEY_ENTER to the CBaseGamesPage. |
|
//----------------------------------------------------------------------------- |
|
void CGameListPanel::OnKeyCodePressed(vgui::KeyCode code) |
|
{ |
|
// Let the outer class handle it. |
|
if ( code == KEY_ENTER && m_pOuter->OnGameListEnterPressed() ) |
|
return; |
|
|
|
BaseClass::OnKeyCodePressed( code ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor |
|
//----------------------------------------------------------------------------- |
|
CBaseGamesPage::CBaseGamesPage( vgui::Panel *parent, const char *name, EPageType eType, const char *pCustomResFilename) |
|
: PropertyPage(parent, name), |
|
m_CallbackFavoritesMsg( this, &CBaseGamesPage::OnFavoritesMsg ), |
|
m_hRequest( NULL ), |
|
m_pCustomResFilename( pCustomResFilename ) |
|
{ |
|
SetSize( 624, 278 ); |
|
m_szGameFilter[0] = 0; |
|
m_szMapFilter[0] = 0; |
|
m_iMaxPlayerFilter = 0; |
|
m_iPingFilter = 0; |
|
m_iServerRefreshCount = 0; |
|
m_bFilterNoFullServers = false; |
|
m_bFilterNoEmptyServers = false; |
|
m_bFilterNoPasswordedServers = false; |
|
m_iSecureFilter = FILTER_ALLSERVERS; |
|
m_hFont = NULL; |
|
m_eMatchMakingType = eType; |
|
m_bFilterReplayServers = false; |
|
SetDefLessFunc( m_mapServers ); |
|
SetDefLessFunc( m_mapServerIP ); |
|
SetDefLessFunc( m_mapGamesFilterItem ); |
|
|
|
// Not always loaded |
|
m_pWorkshopFilter = NULL; |
|
|
|
bool bRunningTF2 = GameSupportsReplay(); |
|
|
|
// get the 'all' text |
|
wchar_t *all = g_pVGuiLocalize->Find("ServerBrowser_All"); |
|
Q_UnicodeToUTF8(all, m_szComboAllText, sizeof(m_szComboAllText)); |
|
|
|
// Init UI |
|
m_pConnect = new Button(this, "ConnectButton", "#ServerBrowser_Connect"); |
|
m_pConnect->SetEnabled(false); |
|
m_pRefreshAll = new Button(this, "RefreshButton", "#ServerBrowser_Refresh"); |
|
m_pRefreshQuick = new Button(this, "RefreshQuickButton", "#ServerBrowser_RefreshQuick"); |
|
m_pAddServer = new Button(this, "AddServerButton", "#ServerBrowser_AddServer"); |
|
m_pAddCurrentServer = new Button(this, "AddCurrentServerButton", "#ServerBrowser_AddCurrentServer"); |
|
m_pGameList = new CGameListPanel(this, "gamelist"); |
|
m_pGameList->SetAllowUserModificationOfColumns(true); |
|
|
|
m_pQuickList = new PanelListPanel(this, "quicklist"); |
|
m_pQuickList->SetFirstColumnWidth( 0 ); |
|
|
|
m_pAddToFavoritesButton = new vgui::Button( this, "AddToFavoritesButton", "" ); |
|
m_pAddToFavoritesButton->SetEnabled( false ); |
|
m_pAddToFavoritesButton->SetVisible( false ); |
|
|
|
// Increment this number if columns are added / removed or some other change is done that requires |
|
// tossing out old saved user configs. |
|
m_pGameList->m_nUserConfigFileVersion = 2; |
|
|
|
// Add the column headers |
|
m_pGameList->AddColumnHeader( k_nColumn_Password, "Password", "#ServerBrowser_Password", 16, ListPanel::COLUMN_FIXEDSIZE | ListPanel::COLUMN_IMAGE); |
|
m_pGameList->AddColumnHeader( k_nColumn_Secure, "Secure", "#ServerBrowser_Secure", 16, ListPanel::COLUMN_FIXEDSIZE | ListPanel::COLUMN_IMAGE); |
|
|
|
int nReplayWidth = 16; |
|
if ( !bRunningTF2 ) |
|
{ |
|
nReplayWidth = 0; |
|
} |
|
|
|
m_pGameList->AddColumnHeader( k_nColumn_Replay, "Replay", "#ServerBrowser_Replay", nReplayWidth, ListPanel::COLUMN_FIXEDSIZE | ListPanel::COLUMN_IMAGE); |
|
m_pGameList->AddColumnHeader( k_nColumn_Name, "Name", "#ServerBrowser_Servers", 50, ListPanel::COLUMN_RESIZEWITHWINDOW | ListPanel::COLUMN_UNHIDABLE); |
|
m_pGameList->AddColumnHeader( k_nColumn_IPAddr, "IPAddr", "#ServerBrowser_IPAddress", 64, ListPanel::COLUMN_HIDDEN); |
|
m_pGameList->AddColumnHeader( k_nColumn_GameDesc, "GameDesc", "#ServerBrowser_Game", 112, |
|
112, // minwidth |
|
300, // maxwidth |
|
0 // flags |
|
); |
|
m_pGameList->AddColumnHeader( k_nColumn_Players, "Players", "#ServerBrowser_Players", 55, ListPanel::COLUMN_FIXEDSIZE); |
|
m_pGameList->AddColumnHeader( k_nColumn_Bots, "Bots", "#ServerBrowser_Bots", 40, ListPanel::COLUMN_FIXEDSIZE); |
|
m_pGameList->AddColumnHeader( k_nColumn_Map, "Map", "#ServerBrowser_Map", 90, |
|
90, // minwidth |
|
300, // maxwidth |
|
0 // flags |
|
); |
|
m_pGameList->AddColumnHeader( k_nColumn_Ping, "Ping", "#ServerBrowser_Latency", 55, ListPanel::COLUMN_FIXEDSIZE); |
|
|
|
m_pGameList->SetColumnHeaderTooltip( k_nColumn_Password, "#ServerBrowser_PasswordColumn_Tooltip"); |
|
m_pGameList->SetColumnHeaderTooltip( k_nColumn_Bots, "#ServerBrowser_BotColumn_Tooltip"); |
|
m_pGameList->SetColumnHeaderTooltip( k_nColumn_Secure, "#ServerBrowser_SecureColumn_Tooltip"); |
|
|
|
if ( bRunningTF2 ) |
|
{ |
|
m_pGameList->SetColumnHeaderTooltip( k_nColumn_Replay, "#ServerBrowser_ReplayColumn_Tooltip"); |
|
} |
|
|
|
// setup fast sort functions |
|
m_pGameList->SetSortFunc( k_nColumn_Password, PasswordCompare); |
|
m_pGameList->SetSortFunc( k_nColumn_Bots, BotsCompare); |
|
m_pGameList->SetSortFunc( k_nColumn_Secure, SecureCompare); |
|
|
|
if ( bRunningTF2 ) |
|
{ |
|
m_pGameList->SetSortFunc( k_nColumn_Replay, ReplayCompare); |
|
} |
|
|
|
m_pGameList->SetSortFunc( k_nColumn_Name, ServerNameCompare); |
|
m_pGameList->SetSortFunc( k_nColumn_IPAddr, IPAddressCompare); |
|
m_pGameList->SetSortFunc( k_nColumn_GameDesc, GameCompare); |
|
m_pGameList->SetSortFunc( k_nColumn_Players, PlayersCompare); |
|
m_pGameList->SetSortFunc( k_nColumn_Map, MapCompare); |
|
m_pGameList->SetSortFunc( k_nColumn_Ping, PingCompare); |
|
|
|
// Sort by ping time by default |
|
m_pGameList->SetSortColumn( k_nColumn_Ping ); |
|
|
|
CreateFilters(); |
|
LoadFilterSettings(); |
|
|
|
m_bAutoSelectFirstItemInGameList = false; |
|
|
|
// In TF2, fill out the max player count so that we sort all >24 player servers below the rest. |
|
if ( bRunningTF2 ) |
|
{ |
|
sb_mod_suggested_maxplayers.SetValue( 24 ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Destructor |
|
//----------------------------------------------------------------------------- |
|
CBaseGamesPage::~CBaseGamesPage() |
|
{ |
|
if ( m_hRequest ) |
|
{ |
|
steamapicontext->SteamMatchmakingServers()->ReleaseRequest( m_hRequest ); |
|
m_hRequest = NULL; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CBaseGamesPage::GetInvalidServerListID() |
|
{ |
|
return m_pGameList->InvalidItemID(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::PerformLayout() |
|
{ |
|
BaseClass::PerformLayout(); |
|
|
|
if ( GetSelectedServerID() == -1 ) |
|
{ |
|
m_pConnect->SetEnabled(false); |
|
} |
|
else |
|
{ |
|
m_pConnect->SetEnabled(true); |
|
} |
|
|
|
|
|
if (SupportsItem(IGameList::GETNEWLIST)) |
|
{ |
|
m_pRefreshQuick->SetVisible(true); |
|
m_pRefreshAll->SetText("#ServerBrowser_RefreshAll"); |
|
} |
|
else |
|
{ |
|
m_pRefreshQuick->SetVisible(false); |
|
m_pRefreshAll->SetText("#ServerBrowser_Refresh"); |
|
} |
|
|
|
if ( SupportsItem(IGameList::ADDSERVER) ) |
|
{ |
|
// m_pFilterString->SetWide( 90 ); // shrink the filter label to fix the add current server button |
|
m_pAddServer->SetVisible(true); |
|
} |
|
else |
|
{ |
|
m_pAddServer->SetVisible(false); |
|
} |
|
|
|
if ( SupportsItem(IGameList::ADDCURRENTSERVER) ) |
|
{ |
|
m_pAddCurrentServer->SetVisible(true); |
|
} |
|
else |
|
{ |
|
m_pAddCurrentServer->SetVisible(false); |
|
} |
|
|
|
if ( IsRefreshing() ) |
|
{ |
|
m_pRefreshAll->SetText( "#ServerBrowser_StopRefreshingList" ); |
|
} |
|
|
|
if (m_pGameList->GetItemCount() > 0) |
|
{ |
|
m_pRefreshQuick->SetEnabled(true); |
|
} |
|
else |
|
{ |
|
m_pRefreshQuick->SetEnabled(false); |
|
} |
|
|
|
if ( !steamapicontext->SteamMatchmakingServers() || !steamapicontext->SteamMatchmaking() ) |
|
{ |
|
m_pAddCurrentServer->SetVisible( false ); |
|
m_pRefreshQuick->SetEnabled( false ); |
|
m_pAddServer->SetEnabled( false ); |
|
m_pConnect->SetEnabled( false ); |
|
m_pRefreshAll->SetEnabled( false ); |
|
m_pAddToFavoritesButton->SetEnabled( false ); |
|
m_pGameList->SetEmptyListText( "#ServerBrowser_SteamRunning" ); |
|
} |
|
|
|
Repaint(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::ApplySchemeSettings(IScheme *pScheme) |
|
{ |
|
BaseClass::ApplySchemeSettings(pScheme); |
|
|
|
// load the password icon |
|
ImageList *imageList = new ImageList(false); |
|
m_nImageIndexPassword = imageList->AddImage(scheme()->GetImage("servers/icon_password", false)); |
|
//imageList->AddImage(scheme()->GetImage("servers/icon_bots", false)); |
|
m_nImageIndexSecure = imageList->AddImage(scheme()->GetImage("servers/icon_robotron", false)); |
|
m_nImageIndexSecureVacBanned = imageList->AddImage(scheme()->GetImage("servers/icon_secure_deny", false)); |
|
m_nImageIndexReplay = imageList->AddImage(scheme()->GetImage("servers/icon_replay", false)); |
|
int passwordColumnImage = imageList->AddImage(scheme()->GetImage("servers/icon_password_column", false)); |
|
//int botColumnImage = imageList->AddImage(scheme()->GetImage("servers/icon_bots_column", false)); |
|
int secureColumnImage = imageList->AddImage(scheme()->GetImage("servers/icon_robotron_column", false)); |
|
int replayColumnImage = imageList->AddImage(scheme()->GetImage("servers/icon_replay_column", false)); |
|
|
|
m_pGameList->SetImageList(imageList, true); |
|
m_hFont = pScheme->GetFont( "ListSmall", IsProportional() ); |
|
if ( !m_hFont ) |
|
m_hFont = pScheme->GetFont( "DefaultSmall", IsProportional() ); |
|
|
|
m_pGameList->SetFont( m_hFont ); |
|
m_pGameList->SetColumnHeaderImage( k_nColumn_Password, passwordColumnImage); |
|
//m_pGameList->SetColumnHeaderImage( k_nColumn_Bots, botColumnImage); |
|
m_pGameList->SetColumnHeaderImage( k_nColumn_Secure, secureColumnImage); |
|
m_pGameList->SetColumnHeaderImage( k_nColumn_Replay, replayColumnImage); |
|
} |
|
|
|
struct serverqualitysort_t |
|
{ |
|
int iIndex; |
|
int iPing; |
|
int iPlayerCount; |
|
int iMaxPlayerCount; |
|
}; |
|
|
|
int ServerQualitySort( const serverqualitysort_t *pSQ1, const serverqualitysort_t *pSQ2 ) |
|
{ |
|
int iMaxP = sb_mod_suggested_maxplayers.GetInt(); |
|
if ( iMaxP && pSQ1->iMaxPlayerCount != pSQ2->iMaxPlayerCount ) |
|
{ |
|
if ( pSQ1->iMaxPlayerCount > iMaxP ) |
|
return 1; |
|
if ( pSQ2->iMaxPlayerCount > iMaxP ) |
|
return -1; |
|
} |
|
|
|
if ( pSQ1->iPing <= 100 && pSQ2->iPing <= 100 && pSQ1->iPlayerCount != pSQ2->iPlayerCount ) |
|
{ |
|
return pSQ2->iPlayerCount - pSQ1->iPlayerCount; |
|
} |
|
|
|
return pSQ1->iPing - pSQ2->iPing; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::SelectQuickListServers( void ) |
|
{ |
|
int iIndex = m_pQuickList->FirstItem(); |
|
|
|
while ( iIndex != m_pQuickList->InvalidItemID() ) |
|
{ |
|
CQuickListPanel *pQuickListPanel = dynamic_cast< CQuickListPanel *> ( m_pQuickList->GetItemPanel( iIndex ) ); |
|
|
|
if ( pQuickListPanel ) |
|
{ |
|
CUtlVector< serverqualitysort_t > vecServerQuality; |
|
|
|
int iElement = m_quicklistserverlist.Find( pQuickListPanel->GetName() ); |
|
|
|
if ( iElement != m_quicklistserverlist.InvalidIndex() ) |
|
{ |
|
CQuickListMapServerList *vecMapServers = &m_quicklistserverlist[iElement]; |
|
|
|
if ( vecMapServers ) |
|
{ |
|
for ( int i =0; i < vecMapServers->Count(); i++ ) |
|
{ |
|
int iListID = vecMapServers->Element( i ); |
|
|
|
serverqualitysort_t serverquality; |
|
|
|
serverquality.iIndex = iListID; |
|
|
|
KeyValues *kv = NULL; |
|
if ( m_pGameList->IsValidItemID( iListID ) ) |
|
{ |
|
kv = m_pGameList->GetItem( iListID ); |
|
} |
|
|
|
if ( kv ) |
|
{ |
|
serverquality.iPing = kv->GetInt( "ping", 0 ); |
|
serverquality.iPlayerCount = kv->GetInt( "PlayerCount", 0 ); |
|
serverquality.iMaxPlayerCount = kv->GetInt( "MaxPlayerCount", 0 ); |
|
} |
|
|
|
vecServerQuality.AddToTail( serverquality ); |
|
} |
|
|
|
vecServerQuality.Sort( ServerQualitySort ); |
|
|
|
serverqualitysort_t bestserver = vecServerQuality.Head(); |
|
|
|
if ( m_pGameList->IsValidItemID( bestserver.iIndex ) ) |
|
{ |
|
pQuickListPanel->SetServerInfo( m_pGameList->GetItem( bestserver.iIndex ), bestserver.iIndex, vecServerQuality.Count() ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
iIndex = m_pQuickList->NextItem( iIndex ); |
|
} |
|
|
|
//Force the connect button to recalculate its state. |
|
OnItemSelected(); |
|
} |
|
|
|
int ServerMapnameSortFunc( const servermaps_t *p1, const servermaps_t *p2 ) |
|
{ |
|
//If they're both on disc OR both missing then sort them alphabetically |
|
if ( (p1->bOnDisk && p2->bOnDisk) || (!p1->bOnDisk && !p2->bOnDisk ) ) |
|
return Q_strcmp( p1->pFriendlyName, p2->pFriendlyName ); |
|
|
|
//Otherwise maps you have show up first |
|
return p2->bOnDisk - p1->bOnDisk; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: prepares all the QuickListPanel map panels... |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::PrepareQuickListMap( const char *pMapName, int iListID ) |
|
{ |
|
char szMapName[ 512 ]; |
|
Q_snprintf( szMapName, sizeof( szMapName ), "%s", pMapName ); |
|
|
|
Q_strlower( szMapName ); |
|
|
|
char path[ 512 ]; |
|
Q_snprintf( path, sizeof( path ), "maps/%s.bsp", szMapName ); |
|
|
|
int iIndex = m_quicklistserverlist.Find( szMapName ); |
|
|
|
if ( m_quicklistserverlist.IsValidIndex( iIndex ) == false ) |
|
{ |
|
CQuickListMapServerList vecMapServers; |
|
iIndex = m_quicklistserverlist.Insert( szMapName, vecMapServers ); |
|
|
|
char szFriendlyName[MAX_MAP_NAME]; |
|
const char *pszFriendlyGameTypeName = ServerBrowser().GetMapFriendlyNameAndGameType( szMapName, szFriendlyName, sizeof(szFriendlyName) ); |
|
|
|
//Add the map to our list of panels. |
|
if ( m_pQuickList ) |
|
{ |
|
servermaps_t servermap; |
|
|
|
servermap.pFriendlyName = CloneString( szFriendlyName ); |
|
servermap.pOriginalName = CloneString( szMapName ); |
|
|
|
char path[ 512 ]; |
|
Q_snprintf( path, sizeof( path ), "maps/%s.bsp", szMapName ); |
|
|
|
servermap.bOnDisk = g_pFullFileSystem->FileExists( path, "MOD" ); |
|
|
|
CQuickListPanel *pQuickListPanel = new CQuickListPanel( m_pQuickList, "QuickListPanel"); |
|
|
|
if ( pQuickListPanel ) |
|
{ |
|
pQuickListPanel->InvalidateLayout(); |
|
pQuickListPanel->SetName( servermap.pOriginalName ); |
|
pQuickListPanel->SetMapName( servermap.pFriendlyName ); |
|
pQuickListPanel->SetImage( servermap.pOriginalName ); |
|
pQuickListPanel->SetGameType( pszFriendlyGameTypeName ); |
|
pQuickListPanel->SetVisible( true ); |
|
pQuickListPanel->SetRefreshing(); |
|
|
|
servermap.iPanelIndex = m_pQuickList->AddItem( NULL, pQuickListPanel ); |
|
} |
|
|
|
m_vecMapNamesFound.AddToTail( servermap ); |
|
m_vecMapNamesFound.Sort( ServerMapnameSortFunc ); |
|
} |
|
|
|
//Now make sure that list is sorted. |
|
CUtlVector<int> *pPanelSort = m_pQuickList->GetSortedVector(); |
|
|
|
if ( pPanelSort ) |
|
{ |
|
pPanelSort->RemoveAll(); |
|
|
|
for ( int i = 0; i < m_vecMapNamesFound.Count(); i++ ) |
|
{ |
|
pPanelSort->AddToTail( m_vecMapNamesFound[i].iPanelIndex ); |
|
} |
|
} |
|
} |
|
|
|
if ( iIndex != m_quicklistserverlist.InvalidIndex() ) |
|
{ |
|
CQuickListMapServerList *vecMapServers = &m_quicklistserverlist[iIndex]; |
|
|
|
if ( vecMapServers ) |
|
{ |
|
if ( vecMapServers->Find( iListID ) == vecMapServers->InvalidIndex() ) |
|
{ |
|
vecMapServers->AddToTail( iListID ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: gets information about specified server |
|
//----------------------------------------------------------------------------- |
|
gameserveritem_t *CBaseGamesPage::GetServer( unsigned int serverID ) |
|
{ |
|
if ( !steamapicontext->SteamMatchmakingServers() ) |
|
return NULL; |
|
|
|
// No point checking for >= 0 when serverID is unsigned. |
|
//if ( serverID >= 0 ) |
|
{ |
|
return steamapicontext->SteamMatchmakingServers()->GetServerDetails( m_hRequest, serverID ); |
|
} |
|
//else |
|
//{ |
|
// Assert( !"Unable to return a useful entry" ); |
|
// return NULL; // bugbug Alfred: temp Favorites/History objects won't return a good value here... |
|
//} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CBaseGamesPage::TagsExclude( void ) |
|
{ |
|
if ( m_pTagsIncludeFilter == NULL ) |
|
return false; |
|
|
|
return m_pTagsIncludeFilter->GetActiveItem(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: What mode the workshop selection is in for pages that use it |
|
//----------------------------------------------------------------------------- |
|
CBaseGamesPage::eWorkshopMode CBaseGamesPage::WorkshopMode() |
|
{ |
|
if ( !m_pWorkshopFilter || !ServerBrowser().IsWorkshopEnabled() ) |
|
{ |
|
return eWorkshop_None; |
|
} |
|
|
|
return (eWorkshopMode)m_pWorkshopFilter->GetActiveItem(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::HideReplayFilter( void ) |
|
{ |
|
if ( m_pReplayFilterCheck && m_pReplayFilterCheck->IsVisible() ) |
|
{ |
|
m_pReplayFilterCheck->SetVisible( false ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::CreateFilters() |
|
{ |
|
m_pFilter = new ToggleButton(this, "Filter", "#ServerBrowser_Filters"); |
|
m_pFilterString = new Label(this, "FilterString", ""); |
|
|
|
if ( Q_stricmp( COM_GetModDirectory(), "cstrike" ) == 0 ) |
|
{ |
|
m_pFilter->SetSelected( false ); |
|
m_bFiltersVisible = false; |
|
} |
|
else |
|
{ |
|
m_pFilter->SetSelected( true ); |
|
m_bFiltersVisible = true; |
|
} |
|
|
|
// filter controls |
|
m_pGameFilter = new ComboBox(this, "GameFilter", 6, false); |
|
|
|
m_pLocationFilter = new ComboBox(this, "LocationFilter", 6, false); |
|
m_pLocationFilter->AddItem("", NULL); |
|
|
|
m_pMapFilter = new TextEntry(this, "MapFilter"); |
|
m_pMaxPlayerFilter = new TextEntry(this, "MaxPlayerFilter"); |
|
m_pPingFilter = new ComboBox(this, "PingFilter", 6, false); |
|
m_pPingFilter->AddItem("#ServerBrowser_All", NULL); |
|
m_pPingFilter->AddItem("#ServerBrowser_LessThan50", NULL); |
|
m_pPingFilter->AddItem("#ServerBrowser_LessThan100", NULL); |
|
m_pPingFilter->AddItem("#ServerBrowser_LessThan150", NULL); |
|
m_pPingFilter->AddItem("#ServerBrowser_LessThan250", NULL); |
|
m_pPingFilter->AddItem("#ServerBrowser_LessThan350", NULL); |
|
m_pPingFilter->AddItem("#ServerBrowser_LessThan600", NULL); |
|
|
|
m_pSecureFilter = new ComboBox(this, "SecureFilter", 3, false); |
|
m_pSecureFilter->AddItem("#ServerBrowser_All", NULL); |
|
m_pSecureFilter->AddItem("#ServerBrowser_SecureOnly", NULL); |
|
m_pSecureFilter->AddItem("#ServerBrowser_InsecureOnly", NULL); |
|
|
|
m_pTagsIncludeFilter = new ComboBox(this, "TagsInclude", 2, false); |
|
m_pTagsIncludeFilter->AddItem("#ServerBrowser_TagsInclude", NULL); |
|
m_pTagsIncludeFilter->AddItem("#ServerBrowser_TagsDoNotInclude", NULL); |
|
m_pTagsIncludeFilter->SetVisible( false ); |
|
|
|
if ( ServerBrowser().IsWorkshopEnabled() ) |
|
{ |
|
m_pWorkshopFilter = new ComboBox(this, "WorkshopFilter", 3, false); |
|
m_pWorkshopFilter->AddItem("#ServerBrowser_All", NULL); |
|
m_pWorkshopFilter->AddItem("#ServerBrowser_WorkshopFilterWorkshopOnly", NULL); |
|
m_pWorkshopFilter->AddItem("#ServerBrowser_WorkshopFilterSubscribed", NULL); |
|
m_pWorkshopFilter->SetVisible( false ); |
|
} |
|
|
|
m_pNoEmptyServersFilterCheck = new CheckButton(this, "ServerEmptyFilterCheck", ""); |
|
m_pNoFullServersFilterCheck = new CheckButton(this, "ServerFullFilterCheck", ""); |
|
m_pNoPasswordFilterCheck = new CheckButton(this, "NoPasswordFilterCheck", ""); |
|
m_pQuickListCheckButton = new CCheckBoxWithStatus(this, "QuickListCheck", ""); |
|
m_pReplayFilterCheck = new CheckButton(this, "ReplayFilterCheck", ""); |
|
|
|
KeyValues *pkv = new KeyValues("mod", "gamedir", "", "appid", NULL ); |
|
m_pGameFilter->AddItem("#ServerBrowser_All", pkv); |
|
|
|
for (int i = 0; i < ModList().ModCount(); i++) |
|
{ |
|
pkv->SetString("gamedir", ModList().GetModDir(i)); |
|
pkv->SetUint64("appid", ModList().GetAppID(i).ToUint64() ); |
|
int iItemID = m_pGameFilter->AddItem(ModList().GetModName(i), pkv); |
|
m_mapGamesFilterItem.Insert( ModList().GetAppID(i).ToUint64(), iItemID ); |
|
} |
|
pkv->deleteThis(); |
|
|
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: loads filter settings from the keyvalues |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::LoadFilterSettings() |
|
{ |
|
KeyValues *filter = ServerBrowserDialog().GetFilterSaveData(GetName()); |
|
|
|
if (ServerBrowserDialog().GetActiveModName()) |
|
{ |
|
Q_strncpy(m_szGameFilter, ServerBrowserDialog().GetActiveModName(), sizeof(m_szGameFilter)); |
|
m_iLimitToAppID = ServerBrowserDialog().GetActiveAppID(); |
|
} |
|
else |
|
{ |
|
Q_strncpy(m_szGameFilter, filter->GetString("game"), sizeof(m_szGameFilter)); |
|
m_iLimitToAppID = CGameID( filter->GetUint64( "appid", 0 ) ); |
|
} |
|
|
|
Q_strncpy(m_szMapFilter, filter->GetString("map"), sizeof(m_szMapFilter)); |
|
m_iMaxPlayerFilter = filter->GetInt("MaxPlayerCount"); |
|
m_iPingFilter = filter->GetInt("ping"); |
|
m_bFilterNoFullServers = filter->GetInt("NoFull"); |
|
m_bFilterNoEmptyServers = filter->GetInt("NoEmpty"); |
|
m_bFilterNoPasswordedServers = filter->GetInt("NoPassword"); |
|
m_bFilterReplayServers = filter->GetInt("Replay"); |
|
m_pQuickListCheckButton->SetSelected( filter->GetInt( "QuickList", 0 ) ); |
|
|
|
int secureFilter = filter->GetInt("Secure"); |
|
m_pSecureFilter->ActivateItem(secureFilter); |
|
|
|
int tagsinclude = filter->GetInt("tagsinclude"); |
|
m_pTagsIncludeFilter->ActivateItem( tagsinclude ); |
|
|
|
if ( m_pWorkshopFilter ) |
|
{ |
|
int workshopFilter = filter->GetInt("workshopfilter"); |
|
m_pWorkshopFilter->ActivateItem( workshopFilter ); |
|
} |
|
|
|
// apply to the controls |
|
UpdateGameFilter(); |
|
m_pMapFilter->SetText(m_szMapFilter); |
|
m_pLocationFilter->ActivateItem(filter->GetInt("location")); |
|
|
|
if (m_iMaxPlayerFilter) |
|
{ |
|
char buf[32]; |
|
Q_snprintf(buf, sizeof(buf), "%d", m_iMaxPlayerFilter); |
|
m_pMaxPlayerFilter->SetText(buf); |
|
} |
|
|
|
if (m_iPingFilter) |
|
{ |
|
char buf[32]; |
|
Q_snprintf(buf, sizeof(buf), "< %d", m_iPingFilter); |
|
m_pPingFilter->SetText(buf); |
|
} |
|
|
|
m_pNoFullServersFilterCheck->SetSelected(m_bFilterNoFullServers); |
|
m_pNoEmptyServersFilterCheck->SetSelected(m_bFilterNoEmptyServers); |
|
m_pNoPasswordFilterCheck->SetSelected(m_bFilterNoPasswordedServers); |
|
m_pReplayFilterCheck->SetSelected(m_bFilterReplayServers); |
|
|
|
OnLoadFilter( filter ); |
|
UpdateFilterSettings(); |
|
|
|
UpdateFilterAndQuickListVisibility(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets the game filter combo box to be the saved setting |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::UpdateGameFilter() |
|
{ |
|
bool bFound = false; |
|
for (int i = 0; i < m_pGameFilter->GetItemCount(); i++) |
|
{ |
|
KeyValues *kv = m_pGameFilter->GetItemUserData(i); |
|
CGameID gameID( kv->GetUint64( "appID", 0 ) ); |
|
const char *pchGameDir = kv->GetString( "gamedir" ); |
|
if ( ( gameID == m_iLimitToAppID || m_iLimitToAppID.AppID() == 0 ) && ( !m_szGameFilter[0] || |
|
( pchGameDir && pchGameDir[0] && !Q_strncmp( pchGameDir, m_szGameFilter, Q_strlen( pchGameDir ) ) ) ) ) |
|
{ |
|
if ( i != m_pGameFilter->GetActiveItem() ) |
|
{ |
|
m_pGameFilter->ActivateItem(i); |
|
} |
|
bFound = true; |
|
break; |
|
} |
|
} |
|
if (!bFound) |
|
{ |
|
// default to empty |
|
if ( 0 != m_pGameFilter->GetActiveItem() ) |
|
{ |
|
m_pGameFilter->ActivateItem(0); |
|
} |
|
} |
|
|
|
// only one mod is allowed in the game |
|
if ( ServerBrowserDialog().GetActiveModName() ) |
|
{ |
|
m_pGameFilter->SetEnabled( false ); |
|
m_pGameFilter->SetText( ServerBrowserDialog().GetActiveGameName() ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handles incoming server refresh data |
|
// updates the server browser with the refreshed information from the server itself |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::ServerResponded( gameserveritem_t &server ) |
|
{ |
|
int nIndex = -1; // start at -1 and work backwards to find the next free slot for this adhoc query |
|
while ( m_mapServers.Find( nIndex ) != m_mapServers.InvalidIndex() ) |
|
nIndex--; |
|
ServerResponded( nIndex, &server ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Callback for ISteamMatchmakingServerListResponse |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::ServerResponded( HServerListRequest hReq, int iServer ) |
|
{ |
|
gameserveritem_t *pServerItem = steamapicontext->SteamMatchmakingServers()->GetServerDetails( hReq, iServer ); |
|
if ( !pServerItem ) |
|
{ |
|
Assert( !"Missing server response" ); |
|
return; |
|
} |
|
|
|
// FIXME(johns): This is a workaround for a steam bug, where it inproperly reads signed bytes out of the |
|
// message. Once the upstream fix makes it into our SteamSDK, this block can be removed. |
|
pServerItem->m_nPlayers = (uint8)(int8)pServerItem->m_nPlayers; |
|
pServerItem->m_nBotPlayers = (uint8)(int8)pServerItem->m_nBotPlayers; |
|
pServerItem->m_nMaxPlayers = (uint8)(int8)pServerItem->m_nMaxPlayers; |
|
|
|
ServerResponded( iServer, pServerItem ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handles incoming server refresh data |
|
// updates the server browser with the refreshed information from the server itself |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::ServerResponded( int iServer, gameserveritem_t *pServerItem ) |
|
{ |
|
int iServerMap = m_mapServers.Find( iServer ); |
|
if ( iServerMap == m_mapServers.InvalidIndex() ) |
|
{ |
|
netadr_t netAdr( pServerItem->m_NetAdr.GetIP(), pServerItem->m_NetAdr.GetConnectionPort() ); |
|
int iServerIP = m_mapServerIP.Find( netAdr ); |
|
if ( iServerIP != m_mapServerIP.InvalidIndex() ) |
|
{ |
|
// if we already had this entry under another index remove the old entry |
|
int iServerMap = m_mapServers.Find( m_mapServerIP[ iServerIP ] ); |
|
if ( iServerMap != m_mapServers.InvalidIndex() ) |
|
{ |
|
serverdisplay_t &server = m_mapServers[ iServerMap ]; |
|
if ( m_pGameList->IsValidItemID( server.m_iListID ) ) |
|
m_pGameList->RemoveItem( server.m_iListID ); |
|
m_mapServers.RemoveAt( iServerMap ); |
|
} |
|
m_mapServerIP.RemoveAt( iServerIP ); |
|
} |
|
|
|
serverdisplay_t serverFind; |
|
serverFind.m_iListID = -1; |
|
serverFind.m_bDoNotRefresh = false; |
|
iServerMap = m_mapServers.Insert( iServer, serverFind ); |
|
m_mapServerIP.Insert( netAdr, iServer ); |
|
} |
|
|
|
serverdisplay_t *pServer = &m_mapServers[ iServerMap ]; |
|
pServer->m_iServerID = iServer; |
|
Assert( pServerItem->m_NetAdr.GetIP() != 0 ); |
|
|
|
// check filters |
|
bool removeItem = false; |
|
if ( !CheckPrimaryFilters( *pServerItem ) ) |
|
{ |
|
// server has been filtered at a primary level |
|
// remove from lists |
|
pServer->m_bDoNotRefresh = true; |
|
|
|
// remove from UI list |
|
removeItem = true; |
|
|
|
if ( m_pGameList->IsValidItemID( pServer->m_iListID ) ) |
|
{ |
|
m_pGameList->RemoveItem( pServer->m_iListID ); |
|
pServer->m_iListID = GetInvalidServerListID(); |
|
} |
|
|
|
return; |
|
} |
|
else if (!CheckSecondaryFilters( *pServerItem )) |
|
{ |
|
// we still ping this server in the future; however it is removed from UI list |
|
removeItem = true; |
|
} |
|
|
|
// update UI |
|
KeyValues *kv; |
|
if ( m_pGameList->IsValidItemID( pServer->m_iListID ) ) |
|
{ |
|
// we're updating an existing entry |
|
kv = m_pGameList->GetItem( pServer->m_iListID ); |
|
m_pGameList->SetUserData( pServer->m_iListID, pServer->m_iServerID ); |
|
} |
|
else |
|
{ |
|
// new entry |
|
kv = new KeyValues("Server"); |
|
} |
|
|
|
kv->SetString("name", pServerItem->GetName()); |
|
kv->SetString("map", pServerItem->m_szMap); |
|
kv->SetString("GameDir", pServerItem->m_szGameDir); |
|
kv->SetString("GameDesc", pServerItem->m_szGameDescription); |
|
kv->SetInt("password", pServerItem->m_bPassword ? m_nImageIndexPassword : 0); |
|
|
|
if ( pServerItem->m_nBotPlayers > 0 ) |
|
kv->SetInt("bots", pServerItem->m_nBotPlayers); |
|
else |
|
kv->SetString("bots", ""); |
|
|
|
if ( pServerItem->m_bSecure ) |
|
{ |
|
// show the denied icon if banned from secure servers, the secure icon otherwise |
|
kv->SetInt("secure", ServerBrowser().IsVACBannedFromGame( pServerItem->m_nAppID ) ? m_nImageIndexSecureVacBanned : m_nImageIndexSecure ); |
|
} |
|
else |
|
{ |
|
kv->SetInt("secure", 0); |
|
} |
|
|
|
kv->SetString( "IPAddr", pServerItem->m_NetAdr.GetConnectionAddressString() ); |
|
|
|
int nAdjustedForBotsPlayers = max( 0, pServerItem->m_nPlayers - pServerItem->m_nBotPlayers ); |
|
|
|
char buf[32]; |
|
Q_snprintf(buf, sizeof(buf), "%d / %d", nAdjustedForBotsPlayers, pServerItem->m_nMaxPlayers ); |
|
kv->SetString("Players", buf); |
|
|
|
kv->SetInt("PlayerCount", nAdjustedForBotsPlayers ); |
|
kv->SetInt("MaxPlayerCount", pServerItem->m_nMaxPlayers ); |
|
|
|
kv->SetInt("Ping", pServerItem->m_nPing); |
|
|
|
kv->SetString("Tags", pServerItem->m_szGameTags ); |
|
|
|
kv->SetInt("Replay", IsReplayServer( *pServerItem ) ? m_nImageIndexReplay : 0); |
|
|
|
if ( pServerItem->m_ulTimeLastPlayed ) |
|
{ |
|
// construct a time string for last played time |
|
struct tm *now; |
|
now = localtime( (time_t*)&pServerItem->m_ulTimeLastPlayed ); |
|
|
|
if ( now ) |
|
{ |
|
char buf[64]; |
|
strftime(buf, sizeof(buf), "%a %d %b %I:%M%p", now); |
|
Q_strlower(buf + strlen(buf) - 4); |
|
kv->SetString("LastPlayed", buf); |
|
} |
|
} |
|
|
|
if ( pServer->m_bDoNotRefresh ) |
|
{ |
|
// clear out the vars |
|
kv->SetString("Ping", ""); |
|
kv->SetWString("GameDesc", g_pVGuiLocalize->Find("#ServerBrowser_NotResponding")); |
|
kv->SetString("Players", ""); |
|
kv->SetString("map", ""); |
|
} |
|
|
|
if ( !m_pGameList->IsValidItemID( pServer->m_iListID ) ) |
|
{ |
|
// new server, add to list |
|
pServer->m_iListID = m_pGameList->AddItem(kv, pServer->m_iServerID, false, false); |
|
if ( m_bAutoSelectFirstItemInGameList && m_pGameList->GetItemCount() == 1 ) |
|
{ |
|
m_pGameList->AddSelectedItem( pServer->m_iListID ); |
|
} |
|
|
|
m_pGameList->SetItemVisible( pServer->m_iListID, !removeItem ); |
|
|
|
kv->deleteThis(); |
|
} |
|
else |
|
{ |
|
// tell the list that we've changed the data |
|
m_pGameList->ApplyItemChanges( pServer->m_iListID ); |
|
m_pGameList->SetItemVisible( pServer->m_iListID, !removeItem ); |
|
} |
|
|
|
PrepareQuickListMap( pServerItem->m_szMap, pServer->m_iListID ); |
|
UpdateStatus(); |
|
m_iServerRefreshCount++; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::UpdateFilterAndQuickListVisibility() |
|
{ |
|
bool showQuickList = m_pQuickListCheckButton->IsSelected(); |
|
bool showFilter = m_pFilter->IsSelected(); |
|
|
|
m_bFiltersVisible = !showQuickList && !m_pCustomResFilename && showFilter; |
|
|
|
int wide, tall; |
|
GetSize( wide, tall ); |
|
SetSize( 624, 278 ); |
|
|
|
UpdateDerivedLayouts(); |
|
UpdateGameFilter(); |
|
|
|
if ( m_hFont ) |
|
{ |
|
SETUP_PANEL( m_pGameList ); |
|
m_pGameList->SetFont( m_hFont ); |
|
} |
|
|
|
SetSize( wide, tall ); |
|
|
|
|
|
m_pQuickList->SetVisible( showQuickList ); |
|
m_pGameList->SetVisible( !showQuickList ); |
|
m_pFilter->SetVisible( !showQuickList ); |
|
m_pFilterString->SetVisible ( !showQuickList ); |
|
|
|
|
|
InvalidateLayout(); |
|
|
|
UpdateFilterSettings(); |
|
ApplyGameFilters(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::SetQuickListEnabled( bool bEnabled ) |
|
{ |
|
m_pQuickListCheckButton->SetSelected( bEnabled ); |
|
|
|
m_pQuickList->SetVisible( m_pQuickListCheckButton->IsSelected() ); |
|
m_pGameList->SetVisible( !m_pQuickListCheckButton->IsSelected() ); |
|
|
|
m_pFilter->SetVisible( !m_pQuickListCheckButton->IsSelected() ); |
|
m_pFilterString->SetVisible( !m_pQuickListCheckButton->IsSelected() ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::SetFiltersVisible( bool bVisible ) |
|
{ |
|
if ( bVisible == m_pFilter->IsSelected() ) |
|
return; |
|
|
|
m_pFilter->SetSelected( bVisible ); |
|
OnButtonToggled( m_pFilter, bVisible ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handles filter dropdown being toggled |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnButtonToggled( Panel *panel, int state ) |
|
{ |
|
UpdateFilterAndQuickListVisibility(); |
|
|
|
|
|
if (panel == m_pNoFullServersFilterCheck || panel == m_pNoEmptyServersFilterCheck || panel == m_pNoPasswordFilterCheck || panel == m_pReplayFilterCheck) |
|
{ |
|
// treat changing these buttons like any other filter has changed |
|
OnTextChanged(panel, ""); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::UpdateDerivedLayouts( void ) |
|
{ |
|
char rgchControlSettings[MAX_PATH]; |
|
if ( m_pCustomResFilename ) |
|
{ |
|
Q_snprintf( rgchControlSettings, sizeof( rgchControlSettings ), "%s", m_pCustomResFilename ); |
|
} |
|
else |
|
{ |
|
if ( m_pFilter->IsSelected() && !m_pQuickListCheckButton->IsSelected() ) |
|
{ |
|
// drop down |
|
V_strncpy( rgchControlSettings, "servers/InternetGamesPage_Filters.res", sizeof( rgchControlSettings ) ); |
|
} |
|
else |
|
{ |
|
// hide filter area |
|
V_strncpy( rgchControlSettings, "servers/InternetGamesPage.res", sizeof( rgchControlSettings ) ); |
|
} |
|
} |
|
|
|
const char *pPathID = "PLATFORM"; |
|
|
|
if ( g_pFullFileSystem->FileExists( rgchControlSettings, "MOD" ) ) |
|
{ |
|
pPathID = "MOD"; |
|
} |
|
|
|
LoadControlSettings( rgchControlSettings, pPathID ); |
|
|
|
if ( !GameSupportsReplay() ) |
|
{ |
|
HideReplayFilter(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called when the game dir combo box is changed |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnTextChanged(Panel *panel, const char *text) |
|
{ |
|
if (!Q_stricmp(text, m_szComboAllText)) |
|
{ |
|
ComboBox *box = dynamic_cast<ComboBox *>(panel); |
|
if (box) |
|
{ |
|
box->SetText(""); |
|
text = ""; |
|
} |
|
} |
|
|
|
// get filter settings from controls |
|
UpdateFilterSettings(); |
|
|
|
// apply settings |
|
ApplyGameFilters(); |
|
|
|
if ( m_bFiltersVisible && ( panel == m_pGameFilter || panel == m_pLocationFilter ) && ServerBrowserDialog().IsVisible() ) |
|
{ |
|
// if they changed games and/or region then cancel the refresh because the old list they are getting |
|
// will be for the wrong game, so stop and start a refresh |
|
StopRefresh(); |
|
GetNewServerList(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: applies only the game filter to the current list |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::ApplyGameFilters() |
|
{ |
|
if ( !steamapicontext->SteamMatchmakingServers() ) |
|
return; |
|
|
|
m_iServersBlacklisted = 0; |
|
|
|
// loop through all the servers checking filters |
|
FOR_EACH_MAP_FAST( m_mapServers, i ) |
|
{ |
|
serverdisplay_t &server = m_mapServers[ i ]; |
|
gameserveritem_t *pServer = steamapicontext->SteamMatchmakingServers()->GetServerDetails( m_hRequest, server.m_iServerID ); |
|
if ( !pServer ) |
|
continue; |
|
|
|
if (!CheckPrimaryFilters( *pServer ) || !CheckSecondaryFilters( *pServer )) |
|
{ |
|
// server failed filtering, remove it |
|
server.m_bDoNotRefresh = true; |
|
if ( m_pGameList->IsValidItemID( server.m_iListID) ) |
|
{ |
|
// don't remove the server from list, just hide since this is a lot faster |
|
m_pGameList->SetItemVisible( server.m_iListID, false ); |
|
} |
|
} |
|
else if ( BShowServer( server ) ) |
|
{ |
|
// server passed filters, so it can be refreshed again |
|
server.m_bDoNotRefresh = false; |
|
|
|
// re-add item to list |
|
if ( !m_pGameList->IsValidItemID( server.m_iListID ) ) |
|
{ |
|
KeyValues *kv = new KeyValues("Server"); |
|
kv->SetString("name", pServer->GetName()); |
|
kv->SetString("map", pServer->m_szMap); |
|
kv->SetString("GameDir", pServer->m_szGameDir); |
|
kv->SetString( "GameTags", pServer->m_szGameTags ); |
|
if ( pServer->m_szGameDescription[0] ) |
|
{ |
|
kv->SetString("GameDesc", pServer->m_szGameDescription ); |
|
} |
|
else |
|
{ |
|
kv->SetWString("GameDesc", g_pVGuiLocalize->Find("#ServerBrowser_PendingPing")); |
|
} |
|
|
|
int nAdjustedForBotsPlayers = max( 0, pServer->m_nPlayers - pServer->m_nBotPlayers ); |
|
|
|
char buf[256]; |
|
Q_snprintf(buf, sizeof(buf), "%d / %d", nAdjustedForBotsPlayers, pServer->m_nMaxPlayers ); |
|
kv->SetString( "Players", buf); |
|
kv->SetInt( "Ping", pServer->m_nPing ); |
|
kv->SetInt( "password", pServer->m_bPassword ? m_nImageIndexPassword : 0); |
|
if ( pServer->m_nBotPlayers > 0 ) |
|
kv->SetInt("bots", pServer->m_nBotPlayers); |
|
else |
|
kv->SetString("bots", ""); |
|
|
|
kv->SetInt("Replay", IsReplayServer( *pServer ) ? m_nImageIndexReplay : 0); |
|
|
|
server.m_iListID = m_pGameList->AddItem(kv, server.m_iServerID, false, false); |
|
kv->deleteThis(); |
|
} |
|
|
|
// make sure the server is visible |
|
m_pGameList->SetItemVisible( server.m_iListID, true ); |
|
} |
|
} |
|
|
|
UpdateStatus(); |
|
m_pGameList->SortList(); |
|
InvalidateLayout(); |
|
Repaint(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Resets UI server count |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::UpdateStatus() |
|
{ |
|
if (m_pGameList->GetItemCount() > 1) |
|
{ |
|
wchar_t header[256]; |
|
wchar_t count[128]; |
|
wchar_t blacklistcount[128]; |
|
|
|
_snwprintf( count, Q_ARRAYSIZE(count), L"%d", m_pGameList->GetItemCount() ); |
|
_snwprintf( blacklistcount, Q_ARRAYSIZE(blacklistcount), L"%d", m_iServersBlacklisted ); |
|
g_pVGuiLocalize->ConstructString( header, sizeof( header ), g_pVGuiLocalize->Find( "#ServerBrowser_ServersCountWithBlacklist"), 2, count, blacklistcount ); |
|
m_pGameList->SetColumnHeaderText( k_nColumn_Name, header); |
|
} |
|
else |
|
{ |
|
m_pGameList->SetColumnHeaderText( k_nColumn_Name, g_pVGuiLocalize->Find("#ServerBrowser_Servers")); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: gets filter settings from controls |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::UpdateFilterSettings() |
|
{ |
|
// game |
|
if ( ServerBrowserDialog().GetActiveModName() ) |
|
{ |
|
// overriding the game filter |
|
Q_strncpy(m_szGameFilter, ServerBrowserDialog().GetActiveModName(), sizeof(m_szGameFilter)); |
|
m_iLimitToAppID = ServerBrowserDialog().GetActiveAppID(); |
|
|
|
|
|
#ifdef STAGING_ONLY |
|
if ( sb_fake_app_id.GetInt() != 0 ) |
|
m_iLimitToAppID = CGameID( sb_fake_app_id.GetInt() ); |
|
#endif |
|
|
|
|
|
RecalculateFilterString(); |
|
UpdateGameFilter(); |
|
} |
|
else |
|
{ |
|
KeyValues *data = m_pGameFilter->GetActiveItemUserData(); |
|
if (data && Q_strlen( data->GetString( "gamedir" ) ) > 0 ) |
|
{ |
|
Q_strncpy( m_szGameFilter, data->GetString( "gamedir" ), sizeof( m_szGameFilter ) ); |
|
if ( Q_strlen( m_szGameFilter ) > 0 ) // if there is a gamedir |
|
{ |
|
m_iLimitToAppID = CGameID( data->GetUint64( "appid", 0 ) ); |
|
} |
|
else |
|
{ |
|
m_iLimitToAppID.Reset(); |
|
} |
|
} |
|
else |
|
{ |
|
m_iLimitToAppID.Reset(); |
|
m_szGameFilter[0] = 0; |
|
} |
|
m_pGameFilter->SetEnabled(true); |
|
} |
|
Q_strlower(m_szGameFilter); |
|
|
|
// map |
|
m_pMapFilter->GetText(m_szMapFilter, sizeof(m_szMapFilter) - 1); |
|
Q_strlower(m_szMapFilter); |
|
|
|
// max player |
|
char buf[256]; |
|
m_pMaxPlayerFilter->GetText(buf, sizeof(buf)); |
|
if (buf[0]) |
|
{ |
|
m_iMaxPlayerFilter = atoi(buf); |
|
} |
|
else |
|
{ |
|
m_iMaxPlayerFilter = 0; |
|
} |
|
|
|
// ping |
|
m_pPingFilter->GetText(buf, sizeof(buf)); |
|
if (buf[0]) |
|
{ |
|
m_iPingFilter = atoi(buf + 2); |
|
} |
|
else |
|
{ |
|
m_iPingFilter = 0; |
|
} |
|
|
|
// players |
|
m_bFilterNoFullServers = m_pNoFullServersFilterCheck->IsSelected(); |
|
m_bFilterNoEmptyServers = m_pNoEmptyServersFilterCheck->IsSelected(); |
|
m_bFilterNoPasswordedServers = m_pNoPasswordFilterCheck->IsSelected(); |
|
m_iSecureFilter = m_pSecureFilter->GetActiveItem(); |
|
|
|
if ( GameSupportsReplay() ) |
|
{ |
|
m_bFilterReplayServers = m_pReplayFilterCheck->IsSelected(); |
|
} |
|
else |
|
{ |
|
m_bFilterReplayServers = false; |
|
} |
|
|
|
m_vecServerFilters.RemoveAll(); |
|
|
|
bool bFilterNoEmpty = m_bFilterNoEmptyServers; |
|
bool bFilterNoFull = m_bFilterNoFullServers; |
|
bool bFilterNoPassword = m_bFilterNoPasswordedServers; |
|
int iFilterSecure = m_iSecureFilter; |
|
|
|
if ( m_pQuickList->IsVisible() == true ) |
|
{ |
|
bFilterNoEmpty = true; |
|
bFilterNoFull = true; |
|
bFilterNoPassword = true; |
|
iFilterSecure = FILTER_SECURESERVERSONLY; |
|
} |
|
|
|
extern IRunGameEngine *g_pRunGameEngine; |
|
if ( sb_filter_incompatible_versions.GetBool() && g_pRunGameEngine != NULL ) |
|
{ |
|
const char *pszVersion = g_pRunGameEngine->GetProductVersionString(); |
|
const char k_VersionFromP4[] = "2000"; // magic version string we use when we're running from P4 |
|
if ( pszVersion && *pszVersion && ( V_strcmp( pszVersion, k_VersionFromP4 ) != 0 ) ) |
|
{ |
|
m_vecServerFilters.AddToTail( MatchMakingKeyValuePair_t( "version_match", pszVersion ) ); |
|
} |
|
} |
|
|
|
// update master filter string text |
|
if (m_szGameFilter[0] && m_iLimitToAppID.AppID() != 1002 ) // HACKHACK: Alfred - don't use a dir filter for RDKF |
|
{ |
|
m_vecServerFilters.AddToTail( MatchMakingKeyValuePair_t( "gamedir", m_szGameFilter ) ); |
|
} |
|
if (bFilterNoEmpty) |
|
{ |
|
m_vecServerFilters.AddToTail( MatchMakingKeyValuePair_t( "empty", "1" ) ); |
|
} |
|
if (bFilterNoFull) |
|
{ |
|
m_vecServerFilters.AddToTail( MatchMakingKeyValuePair_t( "full", "1" ) ); |
|
} |
|
if (iFilterSecure == FILTER_SECURESERVERSONLY) |
|
{ |
|
m_vecServerFilters.AddToTail( MatchMakingKeyValuePair_t( "secure", "1" ) ); |
|
} |
|
int regCode = GetRegionCodeToFilter(); |
|
if ( ( regCode >= 0 ) && ( regCode < 255 ) ) |
|
{ |
|
char szRegCode[ 32 ]; |
|
Q_snprintf( szRegCode, sizeof(szRegCode), "%i", regCode ); |
|
m_vecServerFilters.AddToTail( MatchMakingKeyValuePair_t( "region", szRegCode ) ); |
|
} |
|
|
|
// copy filter settings into filter file |
|
KeyValues *filter = ServerBrowserDialog().GetFilterSaveData(GetName()); |
|
|
|
// only save the game filter if we're not overriding it |
|
if (!ServerBrowserDialog().GetActiveModName()) |
|
{ |
|
filter->SetString("game", m_szGameFilter); |
|
filter->SetUint64( "appid", m_iLimitToAppID.ToUint64() ); |
|
} |
|
|
|
filter->SetString("map", m_szMapFilter); |
|
filter->SetInt("MaxPlayerCount", m_iMaxPlayerFilter); |
|
filter->SetInt("ping", m_iPingFilter); |
|
|
|
if ( m_pLocationFilter->GetItemCount() > 1 ) |
|
{ |
|
// only save this if there are options to choose from |
|
filter->SetInt("location", m_pLocationFilter->GetActiveItem()); |
|
} |
|
|
|
filter->SetInt("NoFull", m_bFilterNoFullServers); |
|
filter->SetInt("NoEmpty", m_bFilterNoEmptyServers); |
|
filter->SetInt("NoPassword", m_bFilterNoPasswordedServers); |
|
filter->SetInt("Secure", m_iSecureFilter); |
|
filter->SetInt("QuickList", m_pQuickListCheckButton->IsSelected() ); |
|
filter->SetInt("tagsinclude", m_pTagsIncludeFilter->GetActiveItem() ); |
|
if ( m_pWorkshopFilter ) |
|
{ |
|
filter->SetInt("workshopfilter", m_pWorkshopFilter->GetActiveItem() ); |
|
} |
|
filter->SetInt("Replay", m_bFilterReplayServers); |
|
|
|
OnSaveFilter(filter); |
|
|
|
RecalculateFilterString(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: allow derived classes access to the saved filter string |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnSaveFilter(KeyValues *filter) |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: allow derived classes access to the saved filter string |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnLoadFilter(KeyValues *filter) |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: reconstructs the filter description string from the current filter settings |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::RecalculateFilterString() |
|
{ |
|
wchar_t unicode[2048], tempUnicode[128], spacerUnicode[8]; |
|
unicode[0] = 0; |
|
int iTempUnicodeSize = sizeof( tempUnicode ); |
|
|
|
Q_UTF8ToUnicode( "; ", spacerUnicode, sizeof( spacerUnicode ) ); |
|
|
|
if (m_szGameFilter[0]) |
|
{ |
|
Q_UTF8ToUnicode( ModList().GetModNameForModDir( m_iLimitToAppID ), tempUnicode, iTempUnicodeSize ); |
|
wcscat( unicode, tempUnicode ); |
|
wcscat( unicode, spacerUnicode ); |
|
} |
|
|
|
if (m_iSecureFilter == FILTER_SECURESERVERSONLY) |
|
{ |
|
wcscat( unicode, g_pVGuiLocalize->Find( "#ServerBrowser_FilterDescSecureOnly" ) ); |
|
wcscat( unicode, spacerUnicode ); |
|
} |
|
else if (m_iSecureFilter == FILTER_INSECURESERVERSONLY) |
|
{ |
|
wcscat( unicode, g_pVGuiLocalize->Find( "#ServerBrowser_FilterDescInsecureOnly" ) ); |
|
wcscat( unicode, spacerUnicode ); |
|
} |
|
|
|
if (m_pLocationFilter->GetActiveItem() > 0) |
|
{ |
|
m_pLocationFilter->GetText(tempUnicode, sizeof(tempUnicode)); |
|
wcscat( unicode, tempUnicode ); |
|
wcscat( unicode, spacerUnicode ); |
|
} |
|
|
|
if (m_iPingFilter) |
|
{ |
|
char tmpBuf[16]; |
|
_snprintf( tmpBuf, sizeof(tmpBuf), "%d", m_iPingFilter ); |
|
|
|
wcscat( unicode, g_pVGuiLocalize->Find( "#ServerBrowser_FilterDescLatency" ) ); |
|
Q_UTF8ToUnicode( " < ", tempUnicode, iTempUnicodeSize ); |
|
wcscat( unicode, tempUnicode ); |
|
Q_UTF8ToUnicode(tmpBuf, tempUnicode, iTempUnicodeSize ); |
|
wcscat( unicode, tempUnicode ); |
|
wcscat( unicode, spacerUnicode ); |
|
} |
|
|
|
if ( m_iMaxPlayerFilter ) |
|
{ |
|
char tmpBuf[16]; |
|
_snprintf( tmpBuf, sizeof(tmpBuf), "%d", m_iMaxPlayerFilter ); |
|
|
|
wcscat( unicode, g_pVGuiLocalize->Find( "#ServerBrowser_FilterDescMaxPlayers" ) ); |
|
Q_UTF8ToUnicode( " <= ", tempUnicode, iTempUnicodeSize ); |
|
wcscat( unicode, tempUnicode ); |
|
Q_UTF8ToUnicode(tmpBuf, tempUnicode, iTempUnicodeSize ); |
|
wcscat( unicode, tempUnicode ); |
|
wcscat( unicode, spacerUnicode ); |
|
} |
|
|
|
if (m_bFilterNoFullServers) |
|
{ |
|
wcscat( unicode, g_pVGuiLocalize->Find( "#ServerBrowser_FilterDescNotFull" ) ); |
|
wcscat( unicode, spacerUnicode ); |
|
} |
|
|
|
if (m_bFilterNoEmptyServers) |
|
{ |
|
wcscat( unicode, g_pVGuiLocalize->Find( "#ServerBrowser_FilterDescNotEmpty" ) ); |
|
wcscat( unicode, spacerUnicode ); |
|
} |
|
|
|
if (m_bFilterNoPasswordedServers) |
|
{ |
|
wcscat( unicode, g_pVGuiLocalize->Find( "#ServerBrowser_FilterDescNoPassword" ) ); |
|
wcscat( unicode, spacerUnicode ); |
|
} |
|
|
|
if (m_bFilterReplayServers) |
|
{ |
|
wcscat( unicode, g_pVGuiLocalize->Find( "#ServerBrowser_FilterDescReplays" ) ); |
|
wcscat( unicode, spacerUnicode ); |
|
} |
|
|
|
if (m_szMapFilter[0]) |
|
{ |
|
Q_UTF8ToUnicode( m_szMapFilter, tempUnicode, iTempUnicodeSize ); |
|
wcscat( unicode, tempUnicode ); |
|
} |
|
|
|
m_pFilterString->SetText(unicode); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Checks to see if the server passes the primary filters |
|
// if the server fails the filters, it will not be refreshed again |
|
//----------------------------------------------------------------------------- |
|
bool CBaseGamesPage::CheckPrimaryFilters( gameserveritem_t &server ) |
|
{ |
|
if (m_szGameFilter[0] && ( server.m_szGameDir[0] || server.m_nPing ) && Q_stricmp(m_szGameFilter, server.m_szGameDir ) ) |
|
{ |
|
return false; |
|
} |
|
|
|
// If it's blacklisted, we ignore it too |
|
if ( ServerBrowserDialog().IsServerBlacklisted( server ) ) |
|
{ |
|
m_iServersBlacklisted++; |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Checks to see if a server passes the secondary set of filters |
|
// server will be continued to be pinged if it fails the filter, since |
|
// the relvent server data is dynamic |
|
//----------------------------------------------------------------------------- |
|
bool CBaseGamesPage::CheckSecondaryFilters( gameserveritem_t &server ) |
|
{ |
|
bool bFilterNoEmpty = m_bFilterNoEmptyServers; |
|
bool bFilterNoFull = m_bFilterNoFullServers; |
|
int iFilterPing = m_iPingFilter; |
|
int iFilterMaxPlayerCount = m_iMaxPlayerFilter; |
|
bool bFilterNoPassword = m_bFilterNoPasswordedServers; |
|
int iFilterSecure = m_iSecureFilter; |
|
|
|
if ( m_pQuickList->IsVisible() == true ) |
|
{ |
|
bFilterNoEmpty = true; |
|
bFilterNoFull = true; |
|
iFilterPing = QUICKLIST_FILTER_MIN_PING; |
|
bFilterNoPassword = true; |
|
iFilterSecure = FILTER_SECURESERVERSONLY; |
|
iFilterMaxPlayerCount = sb_mod_suggested_maxplayers.GetInt(); |
|
} |
|
|
|
if ( bFilterNoEmpty && (server.m_nPlayers - server.m_nBotPlayers) < 1 ) |
|
{ |
|
return false; |
|
} |
|
|
|
if ( bFilterNoFull && server.m_nPlayers >= server.m_nMaxPlayers ) |
|
{ |
|
return false; |
|
} |
|
|
|
if ( iFilterPing && server.m_nPing > iFilterPing ) |
|
{ |
|
return false; |
|
} |
|
|
|
if ( iFilterMaxPlayerCount && server.m_nMaxPlayers > iFilterMaxPlayerCount ) |
|
{ |
|
return false; |
|
} |
|
|
|
if ( bFilterNoPassword && server.m_bPassword ) |
|
{ |
|
return false; |
|
} |
|
|
|
if ( iFilterSecure == FILTER_SECURESERVERSONLY && !server.m_bSecure ) |
|
{ |
|
return false; |
|
} |
|
|
|
if ( iFilterSecure == FILTER_INSECURESERVERSONLY && server.m_bSecure ) |
|
{ |
|
return false; |
|
} |
|
|
|
if ( m_bFilterReplayServers && !IsReplayServer( server ) ) |
|
{ |
|
return false; |
|
} |
|
|
|
if ( m_pQuickList->IsVisible() == false ) |
|
{ |
|
// compare the first few characters of the filter name |
|
int count = Q_strlen( m_szMapFilter ); |
|
if ( count && Q_strnicmp( server.m_szMap, m_szMapFilter, count ) ) |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
return CheckTagFilter( server ) && CheckWorkshopFilter( server ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
uint32 CBaseGamesPage::GetServerFilters( MatchMakingKeyValuePair_t **pFilters ) |
|
{ |
|
*pFilters = m_vecServerFilters.Base(); |
|
return m_vecServerFilters.Count(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: call to let the UI now whether the game list is currently refreshing |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::SetRefreshing(bool state) |
|
{ |
|
if (state) |
|
{ |
|
ServerBrowserDialog().UpdateStatusText("#ServerBrowser_RefreshingServerList"); |
|
|
|
// clear message in panel |
|
m_pGameList->SetEmptyListText(""); |
|
m_pRefreshAll->SetText("#ServerBrowser_StopRefreshingList"); |
|
m_pRefreshAll->SetCommand("stoprefresh"); |
|
m_pRefreshQuick->SetEnabled(false); |
|
} |
|
else |
|
{ |
|
ServerBrowserDialog().UpdateStatusText(""); |
|
if (SupportsItem(IGameList::GETNEWLIST)) |
|
{ |
|
m_pRefreshAll->SetText("#ServerBrowser_RefreshAll"); |
|
} |
|
else |
|
{ |
|
m_pRefreshAll->SetText("#ServerBrowser_Refresh"); |
|
} |
|
m_pRefreshAll->SetCommand("GetNewList"); |
|
|
|
// 'refresh quick' button is only enabled if there are servers in the list |
|
if (m_pGameList->GetItemCount() > 0) |
|
{ |
|
m_pRefreshQuick->SetEnabled(true); |
|
} |
|
else |
|
{ |
|
m_pRefreshQuick->SetEnabled(false); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnCommand(const char *command) |
|
{ |
|
if (!Q_stricmp(command, "Connect")) |
|
{ |
|
OnBeginConnect(); |
|
} |
|
else if (!Q_stricmp(command, "stoprefresh")) |
|
{ |
|
// cancel the existing refresh |
|
StopRefresh(); |
|
} |
|
else if ( !Q_stricmp(command, "refresh") ) |
|
{ |
|
if ( steamapicontext->SteamMatchmakingServers() ) |
|
steamapicontext->SteamMatchmakingServers()->RefreshQuery( m_hRequest ); |
|
SetRefreshing( true ); |
|
m_iServerRefreshCount = 0; |
|
ClearQuickList(); |
|
} |
|
else if (!Q_stricmp(command, "GetNewList")) |
|
{ |
|
GetNewServerList(); |
|
} |
|
else |
|
{ |
|
BaseClass::OnCommand(command); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: called when a row gets selected in the list |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnItemSelected() |
|
{ |
|
if ( GetSelectedServerID() == -1 ) |
|
{ |
|
m_pConnect->SetEnabled(false); |
|
} |
|
else |
|
{ |
|
m_pConnect->SetEnabled(true); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: refreshes server list on F5 |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnKeyCodePressed(vgui::KeyCode code) |
|
{ |
|
if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A ) |
|
{ |
|
m_pConnect->DoClick(); |
|
} |
|
else if ( code == KEY_F5 || code == KEY_XBUTTON_X || code == STEAMCONTROLLER_X ) |
|
{ |
|
StartRefresh(); |
|
} |
|
else if ( m_pGameList->GetItemCount() > 0 && |
|
( code == KEY_XBUTTON_UP || code == KEY_XSTICK1_UP || code == KEY_XSTICK2_UP || code == STEAMCONTROLLER_DPAD_UP || |
|
code == KEY_XBUTTON_DOWN || code == KEY_XSTICK1_DOWN || code == KEY_XSTICK2_DOWN || code == STEAMCONTROLLER_DPAD_DOWN ) ) |
|
{ |
|
m_pGameList->RequestFocus(); |
|
} |
|
else |
|
{ |
|
BaseClass::OnKeyCodePressed(code); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handle enter pressed in the games list page. Return true |
|
// to intercept the message instead of passing it on through vgui. |
|
//----------------------------------------------------------------------------- |
|
bool CBaseGamesPage::OnGameListEnterPressed() |
|
{ |
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Get the # items selected in the game list. |
|
//----------------------------------------------------------------------------- |
|
int CBaseGamesPage::GetSelectedItemsCount() |
|
{ |
|
return m_pGameList->GetSelectedItemsCount(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: adds a server to the favorites |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnAddToFavorites() |
|
{ |
|
if ( !steamapicontext->SteamMatchmakingServers() ) |
|
return; |
|
|
|
// loop through all the selected favorites |
|
for (int i = 0; i < m_pGameList->GetSelectedItemsCount(); i++) |
|
{ |
|
int serverID = m_pGameList->GetItemUserData(m_pGameList->GetSelectedItem(i)); |
|
|
|
gameserveritem_t *pServer = steamapicontext->SteamMatchmakingServers()->GetServerDetails( m_hRequest, serverID ); |
|
if ( pServer ) |
|
{ |
|
// add to favorites list |
|
ServerBrowserDialog().AddServerToFavorites(*pServer); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: adds a server to the blacklist |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnAddToBlacklist() |
|
{ |
|
if ( !steamapicontext->SteamMatchmakingServers() ) |
|
return; |
|
|
|
// loop through all the selected favorites |
|
for (int i = 0; i < m_pGameList->GetSelectedItemsCount(); i++) |
|
{ |
|
int serverID = m_pGameList->GetItemUserData(m_pGameList->GetSelectedItem(i)); |
|
|
|
gameserveritem_t *pServer = steamapicontext->SteamMatchmakingServers()->GetServerDetails( m_hRequest, serverID ); |
|
if ( pServer ) |
|
{ |
|
ServerBrowserDialog().AddServerToBlacklist(*pServer); |
|
} |
|
} |
|
ServerBrowserDialog().BlacklistsChanged(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::ServerFailedToRespond( HServerListRequest hReq, int iServer ) |
|
{ |
|
ServerResponded( hReq, iServer ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: removes the server from the UI list |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::RemoveServer( serverdisplay_t &server ) |
|
{ |
|
if ( m_pGameList->IsValidItemID( server.m_iListID ) ) |
|
{ |
|
// don't remove the server from list, just hide since this is a lot faster |
|
m_pGameList->SetItemVisible( server.m_iListID, false ); |
|
|
|
// find the row in the list and kill |
|
// m_pGameList->RemoveItem(server.listEntryID); |
|
// server.listEntryID = GetInvalidServerListID(); |
|
} |
|
|
|
UpdateStatus(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: refreshes a single server |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnRefreshServer( int serverID ) |
|
{ |
|
if ( !steamapicontext->SteamMatchmakingServers() ) |
|
return; |
|
|
|
// walk the list of selected servers refreshing them |
|
for (int i = 0; i < m_pGameList->GetSelectedItemsCount(); i++) |
|
{ |
|
int serverID = m_pGameList->GetItemUserData(m_pGameList->GetSelectedItem(i)); |
|
|
|
// refresh this server |
|
steamapicontext->SteamMatchmakingServers()->RefreshServer( m_hRequest, serverID ); |
|
} |
|
|
|
SetRefreshing(IsRefreshing()); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: starts the servers refreshing |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::StartRefresh() |
|
{ |
|
if ( !steamapicontext->SteamMatchmakingServers() ) |
|
return; |
|
|
|
ClearServerList(); |
|
MatchMakingKeyValuePair_t *pFilters; |
|
int nFilters = GetServerFilters( &pFilters ); |
|
|
|
if ( m_hRequest ) |
|
{ |
|
steamapicontext->SteamMatchmakingServers()->ReleaseRequest( m_hRequest ); |
|
m_hRequest = NULL; |
|
} |
|
switch ( m_eMatchMakingType ) |
|
{ |
|
case eFavoritesServer: |
|
m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestFavoritesServerList( GetFilterAppID().AppID(), &pFilters, nFilters, this ); |
|
break; |
|
case eHistoryServer: |
|
m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestHistoryServerList( GetFilterAppID().AppID(), &pFilters, nFilters, this ); |
|
break; |
|
case eInternetServer: |
|
m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestInternetServerList( GetFilterAppID().AppID(), &pFilters, nFilters, this ); |
|
break; |
|
case eSpectatorServer: |
|
m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestSpectatorServerList( GetFilterAppID().AppID(), &pFilters, nFilters, this ); |
|
break; |
|
case eFriendsServer: |
|
m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestFriendsServerList( GetFilterAppID().AppID(), &pFilters, nFilters, this ); |
|
break; |
|
case eLANServer: |
|
m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestLANServerList( GetFilterAppID().AppID(), this ); |
|
break; |
|
default: |
|
Assert( !"Unknown server type" ); |
|
break; |
|
} |
|
|
|
SetRefreshing( true ); |
|
|
|
m_iServerRefreshCount = 0; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::ClearQuickList( void ) |
|
{ |
|
m_pQuickList->DeleteAllItems(); |
|
m_vecMapNamesFound.RemoveAll(); |
|
|
|
int iIndex = m_quicklistserverlist.First(); |
|
|
|
while ( iIndex != m_quicklistserverlist.InvalidIndex() ) |
|
{ |
|
CQuickListMapServerList *vecMapServers = &m_quicklistserverlist[iIndex]; |
|
|
|
vecMapServers->RemoveAll(); |
|
|
|
iIndex = m_quicklistserverlist.Next( iIndex ); |
|
} |
|
|
|
m_quicklistserverlist.RemoveAll(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Remove all the servers we currently have |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::ClearServerList() |
|
{ |
|
m_mapServers.RemoveAll(); |
|
m_mapServerIP.RemoveAll(); |
|
m_pGameList->RemoveAll(); |
|
m_iServersBlacklisted = 0; |
|
|
|
ClearQuickList(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: get a new list of servers from the backend |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::GetNewServerList() |
|
{ |
|
StartRefresh(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: stops current refresh/GetNewServerList() |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::StopRefresh() |
|
{ |
|
// clear update states |
|
m_iServerRefreshCount = 0; |
|
|
|
// Stop the server list refreshing |
|
if ( steamapicontext->SteamMatchmakingServers() ) |
|
steamapicontext->SteamMatchmakingServers()->CancelQuery( m_hRequest ); |
|
|
|
// update UI |
|
RefreshComplete( m_hRequest, eServerResponded ); |
|
|
|
// apply settings |
|
ApplyGameFilters(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::RefreshComplete( HServerListRequest hRequest, EMatchMakingServerResponse response ) |
|
{ |
|
SelectQuickListServers(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: returns true if the list is currently refreshing servers |
|
//----------------------------------------------------------------------------- |
|
bool CBaseGamesPage::IsRefreshing() |
|
{ |
|
return steamapicontext->SteamMatchmakingServers() && steamapicontext->SteamMatchmakingServers()->IsRefreshing( m_hRequest ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Activates the page, starts refresh |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnPageShow() |
|
{ |
|
StartRefresh(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called on page hide, stops any refresh |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnPageHide() |
|
{ |
|
StopRefresh(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
vgui::Panel *CBaseGamesPage::GetActiveList( void ) |
|
{ |
|
if ( m_pQuickList->IsVisible() ) |
|
return m_pQuickList; |
|
|
|
return m_pGameList; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CBaseGamesPage::GetSelectedServerID( KeyValues **pKV ) |
|
{ |
|
int serverID = -1; |
|
if ( pKV ) |
|
{ |
|
*pKV = NULL; |
|
} |
|
|
|
if ( m_pQuickList->IsVisible() == true ) |
|
{ |
|
if ( IsRefreshing() == true ) |
|
return -1; |
|
|
|
if ( m_pQuickList->GetSelectedPanel() ) |
|
{ |
|
CQuickListPanel *pQuickPanel = dynamic_cast<CQuickListPanel*>( m_pQuickList->GetSelectedPanel() ); |
|
|
|
if ( pQuickPanel ) |
|
{ |
|
serverID = m_pGameList->GetItemUserData( pQuickPanel->GetListID() ); |
|
if ( pKV ) |
|
{ |
|
*pKV = m_pGameList->GetItem( pQuickPanel->GetListID() ); |
|
} |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
if (!m_pGameList->GetSelectedItemsCount()) |
|
return -1; |
|
|
|
// get the server |
|
serverID = m_pGameList->GetItemUserData( m_pGameList->GetSelectedItem(0) ); |
|
|
|
if ( pKV ) |
|
{ |
|
*pKV = m_pGameList->GetItem( m_pGameList->GetSelectedItem(0) ); |
|
} |
|
} |
|
|
|
return serverID; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Dialog which warns the user about the server they're joining |
|
//----------------------------------------------------------------------------- |
|
class CDialogServerWarning : public vgui::Frame |
|
{ |
|
DECLARE_CLASS_SIMPLE( CDialogServerWarning, vgui::Frame ); |
|
public: |
|
CDialogServerWarning(vgui::Panel *parent, IGameList *gameList, int serverID ); |
|
|
|
virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); |
|
virtual void OnCommand(const char *command); |
|
|
|
MESSAGE_FUNC_PTR_INT( OnButtonToggled, "ButtonToggled", panel, state ); |
|
|
|
private: |
|
IGameList *m_pGameList; |
|
int m_iServerID; |
|
vgui::CheckButton *m_pDontShowThisAgainCheckButton; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor |
|
// Input : *gameList - game list to add specified server to |
|
//----------------------------------------------------------------------------- |
|
CDialogServerWarning::CDialogServerWarning(vgui::Panel *parent, IGameList *gameList, int serverID ) : Frame(parent, "DialogServerWarning") |
|
{ |
|
m_pGameList = gameList; |
|
m_iServerID = serverID; |
|
|
|
m_pDontShowThisAgainCheckButton = new CheckButton(this, "DontShowThisAgainCheckbutton", ""); |
|
|
|
SetDeleteSelfOnClose(true); |
|
SetSizeable( false ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CDialogServerWarning::ApplySchemeSettings( IScheme *pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
LoadControlSettings("Servers/DialogServerWarning.res"); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: button command handler |
|
//----------------------------------------------------------------------------- |
|
void CDialogServerWarning::OnCommand(const char *command) |
|
{ |
|
if ( Q_stricmp(command, "OK") == 0 ) |
|
{ |
|
// mark ourselves to be closed |
|
PostMessage(this, new KeyValues("Close")); |
|
|
|
// join the game |
|
ServerBrowserDialog().JoinGame( m_pGameList, m_iServerID ); |
|
} |
|
else |
|
{ |
|
BaseClass::OnCommand(command); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handles filter dropdown being toggled |
|
//----------------------------------------------------------------------------- |
|
void CDialogServerWarning::OnButtonToggled(Panel *panel, int state) |
|
{ |
|
ConVarRef sb_dontshow_maxplayer_warning( "sb_dontshow_maxplayer_warning", true ); |
|
if ( sb_dontshow_maxplayer_warning.IsValid() ) |
|
{ |
|
sb_dontshow_maxplayer_warning.SetValue( state ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: initiates server connection |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnBeginConnect() |
|
{ |
|
KeyValues *pKV = NULL; |
|
int serverID = GetSelectedServerID( &pKV ); |
|
|
|
if ( serverID == -1 ) |
|
return; |
|
|
|
// Stop the current refresh |
|
StopRefresh(); |
|
|
|
ConVarRef sb_dontshow_maxplayer_warning( "sb_dontshow_maxplayer_warning", true ); |
|
if ( sb_dontshow_maxplayer_warning.IsValid() ) |
|
{ |
|
// If the server is above the suggested maxplayers, warn the player |
|
int iMaxP = sb_mod_suggested_maxplayers.GetInt(); |
|
if ( iMaxP && pKV && !sb_dontshow_maxplayer_warning.GetBool() ) |
|
{ |
|
int iMaxCount = pKV->GetInt( "MaxPlayerCount", 0 ); |
|
if ( iMaxCount > iMaxP ) |
|
{ |
|
CDialogServerWarning *dlg = vgui::SETUP_PANEL( new CDialogServerWarning( this, this, serverID ) ); |
|
dlg->MoveToCenterOfScreen(); |
|
dlg->DoModal(); |
|
|
|
wchar_t wszWarning[512]; |
|
wchar_t wszServerMaxPlayers[12]; |
|
wchar_t wszDesignedMaxPlayers[12]; |
|
wchar_t wszGameName[256]; |
|
_snwprintf( wszServerMaxPlayers, Q_ARRAYSIZE(wszServerMaxPlayers), L"%d", iMaxCount ); |
|
_snwprintf( wszDesignedMaxPlayers, Q_ARRAYSIZE(wszDesignedMaxPlayers), L"%d", iMaxP ); |
|
Q_UTF8ToUnicode( ModList().GetModNameForModDir( m_iLimitToAppID ), wszGameName, Q_ARRAYSIZE(wszGameName) ); |
|
g_pVGuiLocalize->ConstructString( wszWarning, sizeof( wszWarning ), g_pVGuiLocalize->Find( "#ServerBrowser_ServerWarning_MaxPlayers"), 4, wszServerMaxPlayers, wszGameName, wszDesignedMaxPlayers, wszDesignedMaxPlayers ); |
|
dlg->SetDialogVariable( "warning", wszWarning ); |
|
|
|
return; |
|
} |
|
} |
|
} |
|
|
|
// join the game |
|
ServerBrowserDialog().JoinGame(this, serverID); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Displays the current game info without connecting |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnViewGameInfo() |
|
{ |
|
int serverID = GetSelectedServerID(); |
|
|
|
if ( serverID == -1 ) |
|
return; |
|
|
|
// Stop the current refresh |
|
StopRefresh(); |
|
|
|
// join the game |
|
ServerBrowserDialog().OpenGameInfoDialog(this, serverID); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return code to use for tracking how people are connecting to servers |
|
//----------------------------------------------------------------------------- |
|
const char *CBaseGamesPage::GetConnectCode() |
|
{ |
|
// Determine code to use, for the "connect" command. |
|
// |
|
// E.g.: "connect serverbrowser" (This command primarily exists so i can grep the code....) |
|
|
|
const char *pszConnectCode = "serverbrowser"; |
|
switch ( m_eMatchMakingType ) |
|
{ |
|
default: |
|
AssertMsg1( false, "Unknown matchmaking type %d", m_eMatchMakingType ); |
|
break; |
|
|
|
case eInternetServer: |
|
pszConnectCode = "serverbrowser_internet"; |
|
break; |
|
case eLANServer: |
|
pszConnectCode = "serverbrowser_lan"; |
|
break; |
|
case eFriendsServer: |
|
pszConnectCode = "serverbrowser_friends"; |
|
break; |
|
case eFavoritesServer: |
|
pszConnectCode = "serverbrowser_favorites"; |
|
break; |
|
case eHistoryServer: |
|
pszConnectCode = "serverbrowser_history"; |
|
break; |
|
case eSpectatorServer: |
|
pszConnectCode = "serverbrowser_spectator"; |
|
break; |
|
}; |
|
|
|
return pszConnectCode; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Refresh if our favorites list changed |
|
//----------------------------------------------------------------------------- |
|
void CBaseGamesPage::OnFavoritesMsg( FavoritesListChanged_t *pFavListChanged ) |
|
{ |
|
if ( !pFavListChanged->m_nIP ) // a zero for IP means the whole list was reloaded and we need to reload |
|
{ |
|
switch ( m_eMatchMakingType ) |
|
{ |
|
case eInternetServer: |
|
case eLANServer: |
|
case eSpectatorServer: |
|
case eFriendsServer: |
|
return; |
|
case eFavoritesServer: |
|
case eHistoryServer: |
|
// check containing property sheet to see if the page is visible. |
|
// if not, don't bother initiating a server list grab right now - |
|
// it will happen when the dialog is activated later. |
|
if ( reinterpret_cast< PropertySheet* >( GetParent() )->GetActivePage() == this && |
|
GetParent()->IsVisible() && ServerBrowserDialog().IsVisible() ) |
|
{ |
|
GetNewServerList(); |
|
} |
|
return; |
|
default: |
|
Assert( !"unknown matchmaking type" ); |
|
} |
|
return; |
|
} |
|
|
|
switch ( m_eMatchMakingType ) |
|
{ |
|
case eInternetServer: |
|
case eLANServer: |
|
case eSpectatorServer: |
|
case eFriendsServer: |
|
break; |
|
case eFavoritesServer: |
|
case eHistoryServer: |
|
{ |
|
int iIPServer = m_mapServerIP.Find( netadr_t( pFavListChanged->m_nIP, pFavListChanged->m_nConnPort ) ); |
|
if ( iIPServer == m_mapServerIP.InvalidIndex() ) |
|
{ |
|
if ( pFavListChanged->m_bAdd ) |
|
{ |
|
if ( steamapicontext->SteamMatchmakingServers() ) |
|
steamapicontext->SteamMatchmakingServers()->PingServer( pFavListChanged->m_nIP, pFavListChanged->m_nQueryPort, this ); |
|
} |
|
// ignore deletes of fav's we didn't have |
|
} |
|
else |
|
{ |
|
if ( pFavListChanged->m_bAdd ) |
|
{ |
|
if ( m_mapServerIP[ iIPServer ] > 0 ) |
|
ServerResponded( m_hRequest, m_mapServerIP[ iIPServer ] ); |
|
} |
|
else |
|
{ |
|
int iServer = m_mapServers.Find( m_mapServerIP[ iIPServer ] ); |
|
serverdisplay_t &server = m_mapServers[ iServer ]; |
|
RemoveServer( server ); |
|
} |
|
} |
|
} |
|
break; |
|
default: |
|
Assert( !"unknown matchmaking type" ); |
|
}; |
|
} |
|
|
|
void CCheckBoxWithStatus::OnCursorEntered() |
|
{ |
|
ServerBrowserDialog().UpdateStatusText("#ServerBrowser_QuickListExplanation"); |
|
} |
|
|
|
void CCheckBoxWithStatus::OnCursorExited() |
|
{ |
|
ServerBrowserDialog().UpdateStatusText(""); |
|
}
|
|
|