Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

413 lines
12 KiB

  1. //====== Copyright � 1996-2003, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "pch_serverbrowser.h"
  7. #include <vgui_controls/HTML.h>
  8. #include <vgui_controls/MessageDialog.h>
  9. using namespace vgui;
  10. #define NUM_COMMON_TAGS 20
  11. //-----------------------------------------------------------------------------
  12. // Purpose:
  13. //-----------------------------------------------------------------------------
  14. TagMenuButton::TagMenuButton(Panel *parent, const char *panelName, const char *text) : BaseClass(parent,panelName,text)
  15. {
  16. }
  17. //-----------------------------------------------------------------------------
  18. // Purpose:
  19. //-----------------------------------------------------------------------------
  20. void TagMenuButton::OnShowMenu( vgui::Menu *menu )
  21. {
  22. PostActionSignal(new KeyValues("TagMenuButtonOpened"));
  23. BaseClass::OnShowMenu(menu);
  24. }
  25. //-----------------------------------------------------------------------------
  26. // Purpose:
  27. //-----------------------------------------------------------------------------
  28. class CCustomServerInfoURLQuery : public vgui::QueryBox
  29. {
  30. DECLARE_CLASS_SIMPLE( CCustomServerInfoURLQuery, vgui::QueryBox );
  31. public:
  32. CCustomServerInfoURLQuery(const char *title, const char *queryText,vgui::Panel *parent) : BaseClass( title, queryText, parent )
  33. {
  34. SetOKButtonText( "#ServerBrowser_CustomServerURLButton" );
  35. }
  36. };
  37. DECLARE_BUILD_FACTORY( TagInfoLabel );
  38. //-----------------------------------------------------------------------------
  39. // Purpose:
  40. //-----------------------------------------------------------------------------
  41. TagInfoLabel::TagInfoLabel(Panel *parent, const char *panelName) : BaseClass(parent,panelName, (const char *)NULL, NULL)
  42. {
  43. }
  44. //-----------------------------------------------------------------------------
  45. // Purpose:
  46. //-----------------------------------------------------------------------------
  47. TagInfoLabel::TagInfoLabel(Panel *parent, const char *panelName, const char *text, const char *pszURL) : BaseClass(parent,panelName,text,pszURL)
  48. {
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Purpose: If we were left clicked on, launch the URL
  52. //-----------------------------------------------------------------------------
  53. void TagInfoLabel::OnMousePressed(MouseCode code)
  54. {
  55. if (code == MOUSE_LEFT)
  56. {
  57. if ( GetURL() )
  58. {
  59. // Pop up the dialog with the url in it
  60. CCustomServerInfoURLQuery *qb = new CCustomServerInfoURLQuery( "#ServerBrowser_CustomServerURLWarning", "#ServerBrowser_CustomServerURLOpen", this );
  61. if (qb != NULL)
  62. {
  63. qb->SetOKCommand( new KeyValues("DoOpenCustomServerInfoURL") );
  64. qb->AddActionSignalTarget(this);
  65. qb->MoveToFront();
  66. qb->DoModal();
  67. }
  68. }
  69. }
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Purpose:
  73. //-----------------------------------------------------------------------------
  74. void TagInfoLabel::DoOpenCustomServerInfoURL( void )
  75. {
  76. if ( GetURL() )
  77. {
  78. system()->ShellExecute("open", GetURL() );
  79. }
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose: Constructor
  83. //-----------------------------------------------------------------------------
  84. CCustomGames::CCustomGames(vgui::Panel *parent) :
  85. BaseClass(parent, "CustomGames", eInternetServer )
  86. {
  87. m_pGameList->AddColumnHeader(10, "Tags", "#ServerBrowser_Tags", 200);
  88. m_pGameList->SetSortFunc(10, TagsCompare);
  89. if ( !IsSteamGameServerBrowsingEnabled() )
  90. {
  91. m_pGameList->SetEmptyListText("#ServerBrowser_OfflineMode");
  92. m_pConnect->SetEnabled( false );
  93. m_pRefreshAll->SetEnabled( false );
  94. m_pRefreshQuick->SetEnabled( false );
  95. m_pAddServer->SetEnabled( false );
  96. m_pFilter->SetEnabled( false );
  97. }
  98. m_szTagFilter[0] = 0;
  99. m_pTagFilter = new TextEntry(this, "TagFilter");
  100. m_pTagFilter->SetEnabled( false );
  101. m_pTagFilter->SetMaximumCharCount( MAX_TAG_CHARACTERS );
  102. m_pAddTagList = new TagMenuButton( this, "AddTagList", "#ServerBrowser_AddCommonTags" );
  103. m_pTagListMenu = new Menu( m_pAddTagList, "TagList" );
  104. m_pAddTagList->SetMenu( m_pTagListMenu );
  105. m_pAddTagList->SetOpenDirection( Menu::UP );
  106. m_pAddTagList->SetEnabled( false );
  107. // Still sort by ping
  108. m_pGameList->SetSortColumn( 9 );
  109. }
  110. //-----------------------------------------------------------------------------
  111. // Purpose: Destructor
  112. //-----------------------------------------------------------------------------
  113. CCustomGames::~CCustomGames()
  114. {
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. //-----------------------------------------------------------------------------
  119. void CCustomGames::UpdateDerivedLayouts( void )
  120. {
  121. const char *pPathID = "PLATFORM";
  122. if ( m_pFilter->IsSelected() )
  123. {
  124. if ( g_pFullFileSystem->FileExists( "servers/CustomGamesPage_Filters.res", "MOD" ) )
  125. {
  126. pPathID = "MOD";
  127. }
  128. LoadControlSettings( "servers/CustomGamesPage_Filters.res" , pPathID );
  129. }
  130. else
  131. {
  132. if ( g_pFullFileSystem->FileExists( "servers/CustomGamesPage.res", "MOD" ) )
  133. {
  134. pPathID = "MOD";
  135. }
  136. LoadControlSettings( "servers/CustomGamesPage.res" , pPathID );
  137. }
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Purpose:
  141. //-----------------------------------------------------------------------------
  142. void CCustomGames::OnLoadFilter(KeyValues *filter)
  143. {
  144. BaseClass::OnLoadFilter( filter );
  145. Q_strncpy(m_szTagFilter, filter->GetString("gametype"), sizeof(m_szTagFilter));
  146. if ( m_pTagFilter )
  147. {
  148. m_pTagFilter->SetText(m_szTagFilter);
  149. }
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose:
  153. //-----------------------------------------------------------------------------
  154. bool CCustomGames::CheckTagFilter( gameserveritem_t &server )
  155. {
  156. bool bRetVal = true;
  157. // Custom games substring matches tags with the server's tags
  158. int count = Q_strlen( m_szTagFilter );
  159. if ( count )
  160. {
  161. CSplitString TagList( m_szTagFilter, "," );
  162. for ( int i = 0; i < TagList.Count(); i++ )
  163. {
  164. if ( ( Q_strnistr( server.m_szGameTags, TagList[i], MAX_TAG_CHARACTERS ) > 0 ) == TagsExclude() )
  165. {
  166. bRetVal = false;
  167. break;
  168. }
  169. }
  170. }
  171. return bRetVal;
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose: gets filter settings from controls
  175. //-----------------------------------------------------------------------------
  176. void CCustomGames::OnSaveFilter(KeyValues *filter)
  177. {
  178. BaseClass::OnSaveFilter( filter );
  179. if ( m_pTagFilter )
  180. {
  181. // tags
  182. m_pTagFilter->GetText(m_szTagFilter, sizeof(m_szTagFilter) - 1);
  183. }
  184. if ( m_szTagFilter[0] )
  185. {
  186. Q_strlower(m_szTagFilter);
  187. }
  188. // Need to remove the basegamepage's "notags"
  189. for ( int i = 0; i < m_vecServerFilters.Count(); i++ )
  190. {
  191. if ( !Q_strnicmp( m_vecServerFilters[i].m_szKey, "gametype", 8 ) )
  192. {
  193. m_vecServerFilters.Remove(i);
  194. break;
  195. }
  196. }
  197. if ( TagsExclude() )
  198. {
  199. m_vecServerFilters.AddToTail( MatchMakingKeyValuePair_t( "gametype", "" ) );
  200. }
  201. else
  202. {
  203. m_vecServerFilters.AddToTail( MatchMakingKeyValuePair_t( "gametype", m_szTagFilter ) );
  204. }
  205. filter->SetString("gametype", m_szTagFilter);
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Purpose:
  209. //-----------------------------------------------------------------------------
  210. void CCustomGames::SetRefreshing(bool state)
  211. {
  212. if ( state )
  213. {
  214. m_pAddTagList->SetEnabled( false );
  215. }
  216. BaseClass::SetRefreshing( state );
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose:
  220. //-----------------------------------------------------------------------------
  221. void CCustomGames::ServerResponded( int iServer, gameserveritem_t *pServerItem )
  222. {
  223. CBaseGamesPage::ServerResponded( iServer, pServerItem );
  224. // If we've found a server with some tags, enable the add tag button
  225. if ( pServerItem->m_szGameTags[0] )
  226. {
  227. m_pAddTagList->SetEnabled( true );
  228. }
  229. }
  230. struct tagentry_t
  231. {
  232. const char *pszTag;
  233. int iCount;
  234. };
  235. int __cdecl SortTagsInUse( const tagentry_t *pTag1, const tagentry_t *pTag2 )
  236. {
  237. return (pTag1->iCount < pTag2->iCount);
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Purpose:
  241. //-----------------------------------------------------------------------------
  242. void CCustomGames::RecalculateCommonTags( void )
  243. {
  244. // Regenerate our tag list
  245. m_pTagListMenu->DeleteAllItems();
  246. // Loop through our servers, and build a list of all the tags
  247. CUtlVector<tagentry_t> aTagsInUse;
  248. int iCount = m_pGameList->GetItemCount();
  249. for ( int i = 0; i < iCount; i++ )
  250. {
  251. int serverID = m_pGameList->GetItemUserData( i );
  252. gameserveritem_t *pServer = GetServer( serverID );
  253. if ( pServer && pServer->m_szGameTags && pServer->m_szGameTags[0] )
  254. {
  255. CSplitString TagList( pServer->m_szGameTags, "," );
  256. for ( int iTag = 0; iTag < TagList.Count(); iTag++ )
  257. {
  258. // First make sure it's not already in our list
  259. bool bFound = false;
  260. for ( int iCheck = 0; iCheck < aTagsInUse.Count(); iCheck++ )
  261. {
  262. if ( !Q_strnicmp(TagList[iTag], aTagsInUse[iCheck].pszTag, MAX_TAG_CHARACTERS ) )
  263. {
  264. aTagsInUse[iCheck].iCount++;
  265. bFound = true;
  266. }
  267. }
  268. if ( !bFound )
  269. {
  270. int iIdx = aTagsInUse.AddToTail();
  271. aTagsInUse[iIdx].pszTag = TagList[iTag];
  272. aTagsInUse[iIdx].iCount = 0;
  273. }
  274. }
  275. }
  276. }
  277. aTagsInUse.Sort( SortTagsInUse );
  278. int iTagsToAdd = MIN( aTagsInUse.Count(), NUM_COMMON_TAGS );
  279. for ( int i = 0; i < iTagsToAdd; i++ )
  280. {
  281. const char *pszTag = aTagsInUse[i].pszTag;
  282. m_pTagListMenu->AddMenuItem( pszTag, new KeyValues("AddTag", "tag", pszTag), this, new KeyValues( "data", "tag", pszTag ) );
  283. }
  284. m_pTagListMenu->SetFixedWidth( m_pAddTagList->GetWide() );
  285. m_pTagListMenu->InvalidateLayout( true, false );
  286. m_pTagListMenu->PositionRelativeToPanel( m_pAddTagList, Menu::UP );
  287. }
  288. //-----------------------------------------------------------------------------
  289. // Purpose:
  290. //-----------------------------------------------------------------------------
  291. void CCustomGames::OnTagMenuButtonOpened( void )
  292. {
  293. RecalculateCommonTags();
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Purpose: Sets the text from the message
  297. //-----------------------------------------------------------------------------
  298. void CCustomGames::OnAddTag(KeyValues *params)
  299. {
  300. KeyValues *pkvText = params->FindKey("tag", false);
  301. if (!pkvText)
  302. return;
  303. AddTagToFilterList( pkvText->GetString() );
  304. }
  305. int SortServerTags( char* const *p1, char* const *p2 )
  306. {
  307. return ( Q_strcmp( *p1, *p2 ) > 0 );
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Purpose:
  311. //-----------------------------------------------------------------------------
  312. void CCustomGames::AddTagToFilterList( const char *pszTag )
  313. {
  314. char txt[ 128 ];
  315. m_pTagFilter->GetText( txt, sizeof( txt ) );
  316. CUtlVector<char*> TagList;
  317. V_SplitString( txt, ",", TagList );
  318. if ( txt[0] )
  319. {
  320. for ( int i = 0; i < TagList.Count(); i++ )
  321. {
  322. // Already in the tag list?
  323. if ( !Q_stricmp( TagList[i], pszTag ) )
  324. {
  325. TagList.PurgeAndDeleteElements();
  326. return;
  327. }
  328. }
  329. }
  330. char *pszNewTag = new char[64];
  331. Q_strncpy( pszNewTag, pszTag, 64 );
  332. TagList.AddToHead( pszNewTag );
  333. TagList.Sort( SortServerTags );
  334. // Append it
  335. char tmptags[MAX_TAG_CHARACTERS];
  336. tmptags[0] = '\0';
  337. for ( int i = 0; i < TagList.Count(); i++ )
  338. {
  339. if ( i > 0 )
  340. {
  341. Q_strncat( tmptags, ",", MAX_TAG_CHARACTERS );
  342. }
  343. Q_strncat( tmptags, TagList[i], MAX_TAG_CHARACTERS );
  344. }
  345. m_pTagFilter->SetText( tmptags );
  346. TagList.PurgeAndDeleteElements();
  347. // Update & apply filters now that the tag list has changed
  348. UpdateFilterSettings();
  349. ApplyGameFilters();
  350. }