//========= 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 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 *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(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( 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(""); }