Team Fortress 2 Source Code as on 22/4/2020
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.

392 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #include "pch_serverbrowser.h"
  8. using namespace vgui;
  9. //-----------------------------------------------------------------------------
  10. // Purpose: Constructor
  11. // Input : *gameList - game list to add specified server to
  12. //-----------------------------------------------------------------------------
  13. CDialogAddServer::CDialogAddServer(vgui::Panel *parent, IGameList *gameList) : Frame(parent, "DialogAddServer")
  14. {
  15. SetDeleteSelfOnClose(true);
  16. m_pGameList = gameList;
  17. SetTitle("#ServerBrowser_AddServersTitle", true);
  18. SetSizeable( false );
  19. m_pTabPanel = new PropertySheet(this, "GameTabs");
  20. m_pTabPanel->SetTabWidth(72);
  21. m_pDiscoveredGames = new ListPanel( this, "Servers" );
  22. // Add the column headers
  23. m_pDiscoveredGames->AddColumnHeader(0, "Password", "#ServerBrowser_Password", 16, ListPanel::COLUMN_FIXEDSIZE | ListPanel::COLUMN_IMAGE);
  24. m_pDiscoveredGames->AddColumnHeader(1, "Bots", "#ServerBrowser_Bots", 16, ListPanel::COLUMN_FIXEDSIZE | ListPanel::COLUMN_IMAGE | ListPanel::COLUMN_HIDDEN);
  25. m_pDiscoveredGames->AddColumnHeader(2, "Secure", "#ServerBrowser_Secure", 16, ListPanel::COLUMN_FIXEDSIZE | ListPanel::COLUMN_IMAGE);
  26. bool bGameSupportsReplay = GameSupportsReplay();
  27. int nReplayWidth = 16;
  28. if ( !bGameSupportsReplay )
  29. {
  30. nReplayWidth = 0;
  31. }
  32. m_pDiscoveredGames->AddColumnHeader(3, "Replay", "#ServerBrowser_Replay", nReplayWidth, ListPanel::COLUMN_FIXEDSIZE | ListPanel::COLUMN_IMAGE);
  33. m_pDiscoveredGames->AddColumnHeader(4, "Name", "#ServerBrowser_Servers", 20, ListPanel::COLUMN_RESIZEWITHWINDOW | ListPanel::COLUMN_UNHIDABLE);
  34. m_pDiscoveredGames->AddColumnHeader(5, "IPAddr", "#ServerBrowser_IPAddress", 60, ListPanel::COLUMN_HIDDEN);
  35. m_pDiscoveredGames->AddColumnHeader(6, "GameDesc", "#ServerBrowser_Game", 150);
  36. m_pDiscoveredGames->AddColumnHeader(7, "Players", "#ServerBrowser_Players", 60);
  37. m_pDiscoveredGames->AddColumnHeader(8, "Map", "#ServerBrowser_Map", 80);
  38. m_pDiscoveredGames->AddColumnHeader(9, "Ping", "#ServerBrowser_Latency", 60);
  39. m_pDiscoveredGames->SetColumnHeaderTooltip(0, "#ServerBrowser_PasswordColumn_Tooltip");
  40. m_pDiscoveredGames->SetColumnHeaderTooltip(1, "#ServerBrowser_BotColumn_Tooltip");
  41. m_pDiscoveredGames->SetColumnHeaderTooltip(2, "#ServerBrowser_SecureColumn_Tooltip");
  42. if ( bGameSupportsReplay )
  43. {
  44. m_pDiscoveredGames->SetColumnHeaderTooltip(3, "#ServerBrowser_ReplayColumn_Tooltip");
  45. }
  46. // setup fast sort functions
  47. m_pDiscoveredGames->SetSortFunc(0, PasswordCompare);
  48. m_pDiscoveredGames->SetSortFunc(1, BotsCompare);
  49. m_pDiscoveredGames->SetSortFunc(2, SecureCompare);
  50. if ( bGameSupportsReplay )
  51. {
  52. m_pDiscoveredGames->SetSortFunc(3, ReplayCompare);
  53. }
  54. m_pDiscoveredGames->SetSortFunc(4, ServerNameCompare);
  55. m_pDiscoveredGames->SetSortFunc(5, IPAddressCompare);
  56. m_pDiscoveredGames->SetSortFunc(6, GameCompare);
  57. m_pDiscoveredGames->SetSortFunc(7, PlayersCompare);
  58. m_pDiscoveredGames->SetSortFunc(8, MapCompare);
  59. m_pDiscoveredGames->SetSortFunc(9, PingCompare);
  60. m_pDiscoveredGames->SetSortColumn(9); // sort on ping
  61. m_pTextEntry = new vgui::TextEntry( this, "ServerNameText" );
  62. m_pTextEntry->AddActionSignalTarget( this );
  63. m_pTestServersButton = new vgui::Button( this, "TestServersButton", "" );
  64. m_pAddServerButton = new vgui::Button( this, "OKButton", "" );
  65. m_pAddSelectedServerButton = new vgui::Button( this, "SelectedOKButton", "", this, "addselected" );
  66. m_pTabPanel->AddPage( m_pDiscoveredGames, "#ServerBrowser_Servers" );
  67. LoadControlSettings("Servers/DialogAddServer.res");
  68. // Setup the buttons. We leave them disabled until there is text in the textbox.
  69. m_pAddServerButton->SetEnabled( false );
  70. m_pTestServersButton->SetEnabled( false );
  71. m_pAddSelectedServerButton->SetEnabled( false );
  72. m_pAddSelectedServerButton->SetVisible( false );
  73. m_pTabPanel->SetVisible( false );
  74. m_pTextEntry->RequestFocus();
  75. // Initially, we aren't high enough to show the tab panel.
  76. int x, y;
  77. m_pTabPanel->GetPos( x, y );
  78. m_OriginalHeight = m_pTabPanel->GetTall() + y + 50;
  79. SetTall( y );
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose: Destructor
  83. //-----------------------------------------------------------------------------
  84. CDialogAddServer::~CDialogAddServer()
  85. {
  86. FOR_EACH_VEC( m_Queries, i )
  87. {
  88. if ( steamapicontext->SteamMatchmakingServers() )
  89. steamapicontext->SteamMatchmakingServers()->CancelServerQuery( m_Queries[ i ] );
  90. }
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Lets us know when the text entry has changed.
  94. //-----------------------------------------------------------------------------
  95. void CDialogAddServer::OnTextChanged()
  96. {
  97. bool bAnyText = (m_pTextEntry->GetTextLength() > 0);
  98. m_pAddServerButton->SetEnabled( bAnyText );
  99. m_pTestServersButton->SetEnabled( bAnyText );
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Purpose: button command handler
  103. //-----------------------------------------------------------------------------
  104. void CDialogAddServer::OnCommand(const char *command)
  105. {
  106. if ( Q_stricmp(command, "OK") == 0 )
  107. {
  108. OnOK();
  109. }
  110. else if ( Q_stricmp( command, "TestServers" ) == 0 )
  111. {
  112. SetTall( m_OriginalHeight );
  113. m_pTabPanel->SetVisible( true );
  114. m_pAddSelectedServerButton->SetVisible( true );
  115. TestServers();
  116. }
  117. else if ( !Q_stricmp( command, "addselected" ) )
  118. {
  119. if ( m_pDiscoveredGames->GetSelectedItemsCount() )
  120. {
  121. // get the server
  122. int serverID = m_pDiscoveredGames->GetItemUserData( m_pDiscoveredGames->GetSelectedItem(0) );
  123. FinishAddServer( m_Servers[ serverID ] );
  124. m_pDiscoveredGames->RemoveItem( m_pDiscoveredGames->GetSelectedItem(0) ); // as we add to favs remove from the list
  125. m_pDiscoveredGames->SetEmptyListText( "" );
  126. }
  127. }
  128. else
  129. {
  130. BaseClass::OnCommand(command);
  131. }
  132. }
  133. //-----------------------------------------------------------------------------
  134. // Purpose: Handles the OK button being pressed; adds the server to the game list
  135. //-----------------------------------------------------------------------------
  136. void CDialogAddServer::OnOK()
  137. {
  138. // try and parse out IP address
  139. const char *address = GetControlString("ServerNameText", "");
  140. netadr_t netaddr;
  141. netaddr.SetFromString( address, true );
  142. if ( !netaddr.GetPort() && !AllowInvalidIPs() )
  143. {
  144. // use the default port since it was not entered
  145. netaddr.SetPort( 27015 );
  146. }
  147. if ( AllowInvalidIPs() || netaddr.IsValid() )
  148. {
  149. gameserveritem_t server;
  150. memset(&server, 0, sizeof(server));
  151. server.SetName( address );
  152. // We assume here that the query and connection ports are the same. This is why it's much
  153. // better if they click "Servers" and choose a server in there.
  154. server.m_NetAdr.Init( netaddr.GetIPHostByteOrder(), netaddr.GetPort(), netaddr.GetPort() );
  155. server.m_nAppID = 0;
  156. FinishAddServer( server );
  157. }
  158. else
  159. {
  160. // could not parse the ip address, popup an error
  161. MessageBox *dlg = new MessageBox("#ServerBrowser_AddServerErrorTitle", "#ServerBrowser_AddServerError");
  162. dlg->DoModal();
  163. }
  164. // mark ourselves to be closed
  165. PostMessage(this, new KeyValues("Close"));
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose: Ping a particular IP for server presence
  169. //-----------------------------------------------------------------------------
  170. void CDialogAddServer::TestServers()
  171. {
  172. if ( !steamapicontext->SteamMatchmakingServers() )
  173. return;
  174. m_pDiscoveredGames->SetEmptyListText( "" );
  175. m_pDiscoveredGames->RemoveAll();
  176. // If they specified a port, then send a query to that port.
  177. const char *address = GetControlString("ServerNameText", "");
  178. netadr_t netaddr;
  179. netaddr.SetFromString( address, true );
  180. m_Servers.RemoveAll();
  181. CUtlVector<netadr_t> vecAdress;
  182. if ( netaddr.GetPort() == 0 )
  183. {
  184. // No port specified. Go to town on the ports.
  185. CUtlVector<uint16> portsToTry;
  186. GetMostCommonQueryPorts( portsToTry );
  187. for ( int i=0; i < portsToTry.Count(); i++ )
  188. {
  189. netadr_t newAddr = netaddr;
  190. newAddr.SetPort( portsToTry[i] );
  191. vecAdress.AddToTail( newAddr );
  192. }
  193. }
  194. else
  195. {
  196. vecAdress.AddToTail( netaddr );
  197. }
  198. // Change the text on the tab panel..
  199. m_pTabPanel->RemoveAllPages();
  200. wchar_t wstr[512];
  201. if ( address[0] == 0 )
  202. {
  203. Q_wcsncpy( wstr, g_pVGuiLocalize->Find( "#ServerBrowser_ServersRespondingLocal"), sizeof( wstr ) );
  204. }
  205. else
  206. {
  207. wchar_t waddress[512];
  208. Q_UTF8ToUnicode( address, waddress, sizeof( waddress ) );
  209. g_pVGuiLocalize->ConstructString( wstr, sizeof( wstr ), g_pVGuiLocalize->Find( "#ServerBrowser_ServersResponding"), 1, waddress );
  210. }
  211. char str[512];
  212. Q_UnicodeToUTF8( wstr, str, sizeof( str ) );
  213. m_pTabPanel->AddPage( m_pDiscoveredGames, str );
  214. m_pTabPanel->InvalidateLayout();
  215. FOR_EACH_VEC( vecAdress, iAddress )
  216. {
  217. m_Queries.AddToTail( steamapicontext->SteamMatchmakingServers()->PingServer( vecAdress[ iAddress ].GetIPHostByteOrder(), vecAdress[ iAddress ].GetPort(), this ) );
  218. }
  219. }
  220. //-----------------------------------------------------------------------------
  221. // Purpose: A server answered our ping
  222. //-----------------------------------------------------------------------------
  223. void CDialogAddServer::ServerResponded( gameserveritem_t &server )
  224. {
  225. KeyValues *kv = new KeyValues( "Server" );
  226. kv->SetString( "name", server.GetName() );
  227. kv->SetString( "map", server.m_szMap );
  228. kv->SetString( "GameDir", server.m_szGameDir );
  229. kv->SetString( "GameDesc", server.m_szGameDescription );
  230. kv->SetString( "GameTags", server.m_szGameTags );
  231. kv->SetInt( "password", server.m_bPassword ? 1 : 0);
  232. kv->SetInt( "bots", server.m_nBotPlayers ? 2 : 0);
  233. kv->SetInt( "Replay", IsReplayServer( server ) ? 5 : 0 );
  234. if ( server.m_bSecure )
  235. {
  236. // show the denied icon if banned from secure servers, the secure icon otherwise
  237. kv->SetInt("secure", ServerBrowser().IsVACBannedFromGame( server.m_nAppID ) ? 4 : 3);
  238. }
  239. else
  240. {
  241. kv->SetInt("secure", 0);
  242. }
  243. netadr_t reportedIPAddr;
  244. reportedIPAddr.SetIP( server.m_NetAdr.GetIP() );
  245. reportedIPAddr.SetPort( server.m_NetAdr.GetConnectionPort() );
  246. kv->SetString("IPAddr", reportedIPAddr.ToString() );
  247. char buf[32];
  248. Q_snprintf(buf, sizeof(buf), "%d / %d", server.m_nPlayers, server.m_nMaxPlayers);
  249. kv->SetString("Players", buf);
  250. kv->SetInt("Ping", server.m_nPing);
  251. // new server, add to list
  252. int iServer = m_Servers.AddToTail( server );
  253. int iListID = m_pDiscoveredGames->AddItem(kv, iServer, false, false);
  254. if ( m_pDiscoveredGames->GetItemCount() == 1 )
  255. {
  256. m_pDiscoveredGames->AddSelectedItem( iListID );
  257. }
  258. kv->deleteThis();
  259. m_pDiscoveredGames->InvalidateLayout();
  260. }
  261. void CDialogAddServer::ServerFailedToRespond()
  262. {
  263. m_pDiscoveredGames->SetEmptyListText( "#ServerBrowser_ServerNotResponding" );
  264. }
  265. void CDialogAddServer::ApplySchemeSettings( IScheme *pScheme )
  266. {
  267. BaseClass::ApplySchemeSettings( pScheme );
  268. ImageList *imageList = new ImageList(false);
  269. imageList->AddImage(scheme()->GetImage("servers/icon_password", false));
  270. imageList->AddImage(scheme()->GetImage("servers/icon_bots", false));
  271. imageList->AddImage(scheme()->GetImage("servers/icon_robotron", false));
  272. imageList->AddImage(scheme()->GetImage("servers/icon_secure_deny", false));
  273. imageList->AddImage(scheme()->GetImage("servers/icon_replay", false));
  274. int passwordColumnImage = imageList->AddImage(scheme()->GetImage("servers/icon_password_column", false));
  275. int botColumnImage = imageList->AddImage(scheme()->GetImage("servers/icon_bots_column", false));
  276. int secureColumnImage = imageList->AddImage(scheme()->GetImage("servers/icon_robotron_column", false));
  277. int replayColumnImage = imageList->AddImage(scheme()->GetImage("servers/icon_replay_column", false));
  278. m_pDiscoveredGames->SetImageList(imageList, true);
  279. vgui::HFont hFont = pScheme->GetFont( "ListSmall", IsProportional() );
  280. if ( !hFont )
  281. hFont = pScheme->GetFont( "DefaultSmall", IsProportional() );
  282. m_pDiscoveredGames->SetFont( hFont );
  283. m_pDiscoveredGames->SetColumnHeaderImage(0, passwordColumnImage);
  284. m_pDiscoveredGames->SetColumnHeaderImage(1, botColumnImage);
  285. m_pDiscoveredGames->SetColumnHeaderImage(2, secureColumnImage);
  286. m_pDiscoveredGames->SetColumnHeaderImage(3, replayColumnImage);
  287. }
  288. //-----------------------------------------------------------------------------
  289. // Purpose: A server on the listed IP responded
  290. //-----------------------------------------------------------------------------
  291. void CDialogAddServer::OnItemSelected()
  292. {
  293. int nSelectedItem = m_pDiscoveredGames->GetSelectedItem(0);
  294. if( nSelectedItem != -1 )
  295. {
  296. m_pAddSelectedServerButton->SetEnabled( true );
  297. }
  298. else
  299. {
  300. m_pAddSelectedServerButton->SetEnabled( false );
  301. }
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Purpose:
  305. //-----------------------------------------------------------------------------
  306. void CDialogAddServer::FinishAddServer( gameserveritem_t &pServer )
  307. {
  308. ServerBrowserDialog().AddServerToFavorites( pServer );
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Purpose:
  312. //-----------------------------------------------------------------------------
  313. void CDialogAddBlacklistedServer::FinishAddServer( gameserveritem_t &pServer )
  314. {
  315. ServerBrowserDialog().AddServerToBlacklist( pServer );
  316. ServerBrowserDialog().BlacklistsChanged();
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose:
  320. //-----------------------------------------------------------------------------
  321. void CDialogAddBlacklistedServer::ApplySchemeSettings( vgui::IScheme *pScheme )
  322. {
  323. BaseClass::ApplySchemeSettings( pScheme );
  324. m_pAddServerButton->SetText( "#ServerBrowser_AddAddressToBlacklist" );
  325. m_pAddSelectedServerButton->SetText( "#ServerBrowser_AddSelectedToBlacklist" );
  326. }