From 0df7838ee197d93e1c58c59f3d9e3018267cb647 Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Sat, 28 Jan 2023 05:29:26 +0300
Subject: [PATCH 01/17] WIP: initial masterserver client implementation

---
 common/proto_oob.h           |  24 +-
 engine/baseclientstate.cpp   |   3 +
 engine/baseserver.cpp        |   3 +
 engine/host.cpp              |   5 +-
 engine/master.h              |  63 +++++
 engine/masterserver.cpp      | 502 +++++++++++++++++++++++++++++++++++
 engine/net_chan.cpp          |   5 +
 engine/net_ws.cpp            |  14 +-
 engine/sv_steamauth.cpp      |   2 +-
 engine/wscript               |   3 +-
 public/engine/iserversinfo.h |  97 +++++++
 11 files changed, 703 insertions(+), 18 deletions(-)
 create mode 100644 engine/master.h
 create mode 100644 engine/masterserver.cpp
 create mode 100644 public/engine/iserversinfo.h

diff --git a/common/proto_oob.h b/common/proto_oob.h
index dbeeb60f..a6c70152 100644
--- a/common/proto_oob.h
+++ b/common/proto_oob.h
@@ -16,6 +16,8 @@
 // This is used, unless overridden in the registry
 #define VALVE_MASTER_ADDRESS "207.173.177.10:27011"
 
+#define HB_TIMEOUT 15
+
 #define PORT_RCON			27015	// defualt RCON port, TCP
 #define	PORT_MASTER			27011	// Default master port, UDP
 #define PORT_CLIENT			27005	// Default client port, UDP/TCP
@@ -29,6 +31,8 @@
 #endif // ENABLE_RPT
 #define PORT_REPLAY			27040	// Default replay port
 
+#define PORT_SERVERSINFO	27069	// Default matchmaking port
+
 // out of band message id bytes
 
 // M = master, S = server, C = client, A = any
@@ -80,16 +84,17 @@
 
 
 // A user is requesting the list of master servers, auth servers, and titan dir servers from the Client Master server
-#define A2M_GETMASTERSERVERS	'v' // + byte (type of request, TYPE_CLIENT_MASTER or TYPE_SERVER_MASTER)
 
 // Master server list response
-#define M2A_MASTERSERVERS		'w'	// + byte type + 6 byte IP/Port List
+#define S2M_GETCHALLENGE		'w' // + dword challenge
+#define S2M_HEARTBEAT			'y'
+#define S2M_SHUTDOWN			'z' // Master peering message
+#define M2S_CHALLENGE			'x' // + dword challenge
+#define M2C_QUERY				'J'	// request module from master
+#define C2M_CLIENTQUERY			'1' // New style server query
 
-#define A2M_GETACTIVEMODS		'x' // + string Request to master to provide mod statistics ( current usage ).  "1" for first mod.
-
-#define M2A_ACTIVEMODS			'y' // response:  modname\r\nusers\r\nservers
-
-#define M2M_MSG					'z' // Master peering message
+#define C2S_INFOREQUEST			'v'
+#define S2C_INFOREPLY			'K'
 
 // SERVER TO CLIENT/ANY
 
@@ -106,9 +111,6 @@
 #define S2A_INFO_SRC			'I' // + Address, hostname, map, gamedir, gamedescription, active players, maxplayers, protocol
 #define S2A_INFO_GOLDSRC		'm' // Reserved for use by goldsrc servers
 
-#define S2M_GETFILE				'J'	// request module from master
-#define M2S_SENDFILE			'K'	// send module to server
-
 #define S2C_REDIRECT			'L'	// + IP x.x.x.x:port, redirect client to other server/proxy 
 
 #define	C2M_CHECKMD5			'M'	// player client asks secure master if Module MD5 is valid
@@ -133,8 +135,6 @@
 
 #define A2S_KEY_STRING		"Source Engine Query" // required postfix to a A2S_INFO query
 
-#define A2M_GET_SERVERS_BATCH2	'1' // New style server query
-
 #define A2M_GETACTIVEMODS2		'2' // New style mod info query
 
 #define C2S_AUTHREQUEST1        '3' // 
diff --git a/engine/baseclientstate.cpp b/engine/baseclientstate.cpp
index bb0d3de3..ed001afd 100644
--- a/engine/baseclientstate.cpp
+++ b/engine/baseclientstate.cpp
@@ -37,6 +37,7 @@
 #include "sv_plugin.h"
 #include "sys_dll.h"
 #include "host.h"
+#include "master.h"
 #if defined( REPLAY_ENABLED )
 #include "replay_internal.h"
 #include "replayserver.h"
@@ -875,6 +876,8 @@ bool CBaseClientState::ProcessConnectionlessPacket( netpacket_t *packet )
 
 	Assert( packet );
 
+	master->ProcessConnectionlessPacket( packet );
+
 	bf_read &msg = packet->message;	// handy shortcut 
 
 	int c = msg.ReadByte();
diff --git a/engine/baseserver.cpp b/engine/baseserver.cpp
index b0acee7c..d9c61a96 100644
--- a/engine/baseserver.cpp
+++ b/engine/baseserver.cpp
@@ -56,6 +56,7 @@
 #include "sv_ipratelimit.h"
 #include "cl_steamauth.h"
 #include "sv_filter.h"
+#include "master.h"
 
 #if defined( _X360 )
 #include "xbox/xbox_win32stubs.h"
@@ -663,6 +664,8 @@ bool CBaseServer::ValidInfoChallenge( netadr_t & adr, const char *nugget )
 
 bool CBaseServer::ProcessConnectionlessPacket(netpacket_t * packet)
 {
+	master->ProcessConnectionlessPacket( packet );
+
 	bf_read msg = packet->message;	// handy shortcut 
 
 	char c = msg.ReadChar();
diff --git a/engine/host.cpp b/engine/host.cpp
index 9ebdc928..2e22474f 100644
--- a/engine/host.cpp
+++ b/engine/host.cpp
@@ -40,6 +40,7 @@
 #include "steam/steam_api.h"
 #include "LoadScreenUpdate.h"
 #include "datacache/idatacache.h"
+#include "master.h"
 
 #if !defined SWDS
 #include "voice.h"
@@ -1820,6 +1821,8 @@ void Host_ShutdownServer( void )
 	if ( !sv.IsActive() )
 		return;
 
+	master->ShutdownConnection();
+
 	Host_AllowQueuedMaterialSystem( false );
 	// clear structures
 #if !defined( SWDS )
@@ -4951,7 +4954,7 @@ void Host_Shutdown(void)
 	TRACESHUTDOWN( HLTV_Shutdown() );
 
 	TRACESHUTDOWN( g_Log.Shutdown() );
-	
+
 	TRACESHUTDOWN( g_GameEventManager.Shutdown() );
 
 	TRACESHUTDOWN( sv.Shutdown() );
diff --git a/engine/master.h b/engine/master.h
new file mode 100644
index 00000000..eddb39e0
--- /dev/null
+++ b/engine/master.h
@@ -0,0 +1,63 @@
+//======== (C) Copyright 1999, 2000 Valve, L.L.C. All rights reserved. ========
+//
+// The copyright to the contents herein is the property of Valve, L.L.C.
+// The contents may be used and/or copied only with the written permission of
+// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
+// the agreement/contract under which the contents have been supplied.
+//
+// Purpose: 
+//
+// $Workfile:     $
+// $Date:         $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================
+#ifndef MASTER_H
+#define MASTER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "engine/iserversinfo.h"
+
+#define DEFAULT_MASTER_ADDRESS "185.192.97.130:27010"
+
+//-----------------------------------------------------------------------------
+// Purpose: Implements a master server interface.
+//-----------------------------------------------------------------------------
+class IMaster
+{
+public:
+	// Allow master server to register cvars/commands
+	virtual void Init( void ) = 0;
+	// System is shutting down
+	virtual void Shutdown( void ) = 0;
+	// Server is shutting down
+	virtual void ShutdownConnection( void ) = 0;
+	// Sends the actual heartbeat to the master ( after challenge value is parsed )
+	virtual void SendHeartbeat( struct adrlist_s *p ) = 0;
+	// Add server to global master list
+	virtual void AddServer( struct netadr_s *adr ) = 0;
+	// If parsing for server, etc. fails, always have at least one server around to use.
+	virtual void UseDefault ( void ) = 0;
+	// See if it's time to send the next heartbeat
+	virtual void CheckHeartbeat( void ) = 0;
+	// Master sent back a challenge value, read it and send the actual heartbeat
+	virtual void RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg ) = 0;
+	// Console command to set/remove master server
+	virtual void SetMaster_f( void ) = 0;
+	// Force a heartbeat to be issued right away
+	virtual void Heartbeat_f( void ) = 0;
+
+	virtual void ProcessConnectionlessPacket( netpacket_t *packet ) = 0;
+
+	virtual void RunFrame( void ) = 0;
+};
+
+extern IMaster *master;
+extern IServersInfo *g_pServersInfo;
+
+#endif // MASTER_H
diff --git a/engine/masterserver.cpp b/engine/masterserver.cpp
new file mode 100644
index 00000000..62d7e614
--- /dev/null
+++ b/engine/masterserver.cpp
@@ -0,0 +1,502 @@
+//======177== (C) Copyright 1999, 2000 Valve, L.L.C. All rights reserved. ========
+//
+// The copyright to the contents herein is the property of Valve, L.L.C.
+// The contents may be used and/or copied only with the written permission of
+// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
+// the agreement/contract under which the contents have been supplied.
+//
+// Purpose: 
+//
+// $Workfile:     $
+// $Date:         $
+// $NoKeywords: $
+//=============================================================================
+#include "quakedef.h"
+#include "server.h"
+#include "master.h"
+#include "proto_oob.h"
+#include "host.h"
+
+extern ConVar sv_lan;
+
+//-----------------------------------------------------------------------------
+// Purpose: List of master servers and some state info about them
+//-----------------------------------------------------------------------------
+typedef struct adrlist_s
+{
+	// Next master in chain
+	struct adrlist_s	*next;
+	// Challenge request sent to master
+	qboolean			heartbeatwaiting;
+	// Challenge request send time
+	float				heartbeatwaitingtime; 
+	// Last one is Main master
+	int					heartbeatchallenge;
+	// Time we sent last heartbeat
+	double				last_heartbeat;
+	// Master server address
+	netadr_t			adr;
+} adrlist_t;
+
+//-----------------------------------------------------------------------------
+// Purpose: Implements the master server interface
+//-----------------------------------------------------------------------------
+class CMaster : public IMaster, public IServersInfo
+{
+public:
+	CMaster( void );
+	virtual ~CMaster( void );
+
+	// Heartbeat functions.
+	void Init( void );
+	void Shutdown( void );
+	// Sets up master address
+	void ShutdownConnection(void);
+	void SendHeartbeat( struct adrlist_s *p );
+	void AddServer( struct netadr_s *adr );
+	void UseDefault ( void );
+	void CheckHeartbeat (void);
+	void RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg );
+
+	void ProcessConnectionlessPacket( netpacket_t *packet );
+
+	void SetMaster_f( void );
+	void Heartbeat_f( void );
+
+	void RunFrame();
+	void RequestServersInfo();
+
+	// SeversInfo
+	void RequestInternetServerList( const char *gamedir, IServerListResponse *response );
+	void RequestLANServerList( const char *gamedir, IServerListResponse *response );
+	void AddServerAddresses( netadr_t **adr, int count );
+private:
+	// List of known master servers
+	adrlist_t *m_pMasterAddresses;
+
+	bool m_bInitialized;
+
+	// If nomaster is true, the server will not send heartbeats to the master server
+	bool	m_bNoMasters;
+
+	CUtlLinkedList<netadr_t> m_serverAddresses;
+};
+
+static CMaster s_MasterServer;
+IMaster *master = (IMaster *)&s_MasterServer;
+
+IServersInfo *g_pServersInfo = (IServersInfo*)&s_MasterServer;
+
+#define	HEARTBEAT_SECONDS	140.0
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CMaster::CMaster( void )
+{
+	m_pMasterAddresses	= NULL;
+	m_bNoMasters		= false;
+	m_bInitialized = false;
+	Init();
+}
+
+CMaster::~CMaster( void )
+{
+}
+
+void CMaster::RunFrame()
+{
+	CheckHeartbeat();
+}
+
+void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
+{
+	static ALIGN4 char string[2048] ALIGN4_POST;    // Buffer for sending heartbeat
+
+	uint ip; uint16 port;
+
+	bf_read msg = packet->message;
+	char c = msg.ReadChar();
+
+	if ( c == 0  )
+		return;
+
+	switch( c )
+	{
+		case M2S_CHALLENGE:
+		{
+			RespondToHeartbeatChallenge( packet->from, msg );
+			break;
+		}
+		case M2C_QUERY:
+		{
+			if( m_serverAddresses.Count() > 0 )
+				m_serverAddresses.RemoveAll();
+
+			ip = msg.ReadLong();
+			port = msg.ReadShort();
+
+			while( ip != 0 && port != 0 )
+			{
+				netadr_t adr(ip, port);
+
+				m_serverAddresses.AddToHead(adr);
+
+				ip = msg.ReadLong();
+				port = msg.ReadShort();
+			}
+
+			RequestServersInfo();
+			break;
+		}
+		case C2S_INFOREQUEST:
+		{
+			bf_write p(string, sizeof(string));
+			p.WriteLong(CONNECTIONLESS_HEADER);
+			p.WriteByte(S2C_INFOREPLY);
+			p.WriteString(sv.GetName());
+
+			NET_SendPacket(NULL, NS_SERVER, packet->from, p.GetData(), p.GetNumBytesWritten());
+
+			break;
+		}
+		case S2C_INFOREPLY:
+		{
+			char hostname[1024];
+			msg.ReadString(hostname, sizeof(hostname));
+
+			break;
+		}
+	}
+}
+
+void CMaster::RequestServersInfo()
+{
+	static ALIGN4 char string[256] ALIGN4_POST;    // Buffer for sending heartbeat
+
+	bf_write msg( string, sizeof(string) );
+
+	FOR_EACH_LL( m_serverAddresses, i )
+	{
+		const netadr_t adr = m_serverAddresses[i];
+
+		msg.WriteLong( CONNECTIONLESS_HEADER );
+		msg.WriteByte( C2S_INFOREQUEST );
+
+		NET_SendPacket( NULL, NS_CLIENT, adr, msg.GetData(), msg.GetNumBytesWritten() );
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sends a heartbeat to the master server
+// Input  : *p - x00\x00\x00\x00\x00\x00
+//-----------------------------------------------------------------------------
+void CMaster::SendHeartbeat ( adrlist_t *p )
+{
+	static ALIGN4 char string[256] ALIGN4_POST;    // Buffer for sending heartbeat
+	char        szGD[ MAX_OSPATH ];
+
+	if ( !p )
+		return;
+
+	// Still waiting on challenge response?
+	if ( p->heartbeatwaiting )
+		return;
+
+	// Waited too long
+	if ( (realtime - p->heartbeatwaitingtime ) >= HB_TIMEOUT )
+		return;
+
+	// Send to master
+	// TODO(nillerusr): send engine version in this packet
+	Q_FileBase( com_gamedir, szGD, sizeof( szGD ) );
+
+	bf_write buf( string, sizeof(string) );
+	buf.WriteByte( S2M_HEARTBEAT );
+	buf.WriteLong( p->heartbeatchallenge );
+	buf.WriteShort( PROTOCOL_VERSION );
+	buf.WriteString( szGD );
+
+	NET_SendPacket( NULL, NS_SERVER, p->adr, buf.GetData(), buf.GetNumBytesWritten() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Requests a challenge so we can then send a heartbeat
+//-----------------------------------------------------------------------------
+void CMaster::CheckHeartbeat (void)
+{
+	adrlist_t *p;
+	ALIGN4 char buf[256] ALIGN4_POST;
+
+	if ( m_bNoMasters ||      // We are ignoring heartbeats
+		sv_lan.GetInt() ||           // Lan servers don't heartbeat
+		(sv.GetMaxClients() <= 1) ||  // not a multiplayer server.
+		!sv.IsActive() )			  // only heartbeat if a server is running.
+		return;
+
+	p = m_pMasterAddresses;
+	while ( p )
+	{
+		// Time for another try?
+		if ( ( realtime - p->last_heartbeat) < HEARTBEAT_SECONDS)  // not time to send yet
+		{
+			p = p->next;
+			continue;
+		}
+
+		// Should we resend challenge request?
+		if ( p->heartbeatwaiting &&
+			( ( realtime - p->heartbeatwaitingtime ) < HB_TIMEOUT ) )
+		{
+			p = p->next;
+			continue;
+		}
+
+		int32 challenge = RandomInt( 0, INT_MAX );
+
+		p->heartbeatwaiting     = true;
+		p->heartbeatwaitingtime = realtime;
+
+		p->last_heartbeat       = realtime;  // Flag at start so we don't just keep trying for hb's when
+		p->heartbeatchallenge = challenge;
+
+		bf_write msg("Master Join", buf, sizeof(buf));
+
+		msg.WriteByte( S2M_GETCHALLENGE );
+		msg.WriteLong( challenge );
+
+		// Send to master asking for a challenge #
+		NET_SendPacket( NULL, NS_SERVER, p->adr, msg.GetData(), msg.GetNumBytesWritten() );
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Server is shutting down, unload master servers list, tell masters that we are closing the server
+//-----------------------------------------------------------------------------
+void CMaster::ShutdownConnection( void )
+{
+	adrlist_t *p;
+
+	if ( !host_initialized )
+		return;
+
+	if ( m_bNoMasters ||      // We are ignoring heartbeats
+		sv_lan.GetInt() ||           // Lan servers don't heartbeat
+		(sv.GetMaxClients() <= 1) )   // not a multiplayer server.
+		return;
+
+	const char packet = S2M_SHUTDOWN;
+
+	p = m_pMasterAddresses;
+	while ( p )
+	{
+		NET_SendPacket( NULL, NS_SERVER, p->adr, (unsigned char*)&packet, 1);
+		p->last_heartbeat = -99999.0;
+		p = p->next;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add server to the master list
+// Input  : *adr - 
+//-----------------------------------------------------------------------------
+void CMaster::AddServer( netadr_t *adr )
+{
+	adrlist_t *n;
+
+	// See if it's there
+	n = m_pMasterAddresses;
+	while ( n )
+	{
+		if ( n->adr.CompareAdr( *adr ) )
+			break;
+		n = n->next;
+	}
+
+	// Found it in the list.
+	if ( n )
+		return;
+
+	n = ( adrlist_t * ) malloc ( sizeof( adrlist_t ) );
+	if ( !n )
+		Sys_Error( "Error allocating %i bytes for master address.", sizeof( adrlist_t ) );
+
+	memset( n, 0, sizeof( adrlist_t ) );
+
+	n->adr = *adr;
+
+	// Queue up a full heartbeat to all master servers.
+	n->last_heartbeat = -99999.0;
+
+	// Link it in.
+	n->next = m_pMasterAddresses;
+	m_pMasterAddresses = n;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add built-in default master if woncomm.lst doesn't parse
+//-----------------------------------------------------------------------------
+void CMaster::UseDefault ( void )
+{
+	netadr_t adr;
+
+	// Convert to netadr_t
+	if ( NET_StringToAdr ( DEFAULT_MASTER_ADDRESS, &adr ) )
+	{
+		// Add to master list
+		AddServer( &adr );
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: 
+//-----------------------------------------------------------------------------
+void CMaster::RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg )
+{
+	adrlist_t *p;
+	uint challenge, challenge2;
+
+	// No masters, just ignore.
+	if ( !m_pMasterAddresses )
+		return;
+
+	p = m_pMasterAddresses;
+	while ( p )
+	{
+		if ( from.CompareAdr( p->adr ) )
+			break;
+
+		p = p->next;
+	}
+
+	// Not a known master server.
+	if ( !p )
+		return;
+
+	challenge = msg.ReadLong();
+	challenge2 = msg.ReadLong();
+
+	if( p->heartbeatchallenge != challenge2 )
+	{
+		Warning("unexpected master server info query packet (wrong challenge!)\n");
+		return;
+	}
+
+	// Kill timer
+	p->heartbeatwaiting   = false;
+	p->heartbeatchallenge = challenge;
+
+	// Send the actual heartbeat request to this master server.
+	SendHeartbeat( p );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add/remove master servers
+//-----------------------------------------------------------------------------
+void CMaster::SetMaster_f (void)
+{
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Send a new heartbeat to the master
+//-----------------------------------------------------------------------------
+void CMaster::Heartbeat_f (void)
+{
+	adrlist_t *p;
+
+	p = m_pMasterAddresses;
+	while ( p )
+	{
+		// Queue up a full hearbeat
+		p->last_heartbeat = -9999.0;
+		p->heartbeatwaitingtime = -9999.0;
+		p = p->next;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: 
+//-----------------------------------------------------------------------------
+void SetMaster_f( void )
+{
+	master->SetMaster_f();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: 
+//-----------------------------------------------------------------------------
+void Heartbeat1_f( void )
+{
+	master->Heartbeat_f();
+}
+
+static ConCommand setmaster("setmaster", SetMaster_f );
+static ConCommand heartbeat("heartbeat", Heartbeat1_f, "Force heartbeat of master servers" ); 
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds master server console commands
+//-----------------------------------------------------------------------------
+void CMaster::Init( void )
+{
+	// Already able to initialize at least once?
+	if ( m_bInitialized )
+		return;
+
+	// So we don't do this a send time.sv_mas
+	m_bInitialized = true;
+
+	UseDefault();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: 
+//-----------------------------------------------------------------------------
+void CMaster::Shutdown(void)
+{
+	adrlist_t *p, *n;
+
+	// Free the master list now.
+	p = m_pMasterAddresses;
+	while ( p )
+	{
+		n = p->next;
+		free( p );
+		p = n;
+	}
+
+	m_pMasterAddresses = NULL;
+}
+
+// ServersInfo
+void CMaster::RequestInternetServerList(const char *gamedir, IServerListResponse *response)
+{
+	if( m_bNoMasters ) return;
+
+	ALIGN4 char buf[256] ALIGN4_POST;
+	bf_write msg(buf, sizeof(buf));
+
+	msg.WriteByte( C2M_CLIENTQUERY );
+	msg.WriteString(gamedir);
+
+	// TODO(nillerusr): add switching between masters?
+	NET_SendPacket(NULL, NS_CLIENT, m_pMasterAddresses->adr, msg.GetData(), msg.GetNumBytesWritten() );
+}
+
+void CMaster::RequestLANServerList(const char *gamedir, IServerListResponse *response)
+{
+
+}
+
+void CMaster::AddServerAddresses( netadr_t **adr, int count )
+{
+
+}
+
+void Master_Request_f()
+{
+	g_pServersInfo->RequestInternetServerList("cstrike", NULL);
+}
+
+ConCommand master_request( "master_request", Master_Request_f );
diff --git a/engine/net_chan.cpp b/engine/net_chan.cpp
index bccf0073..e722bc02 100644
--- a/engine/net_chan.cpp
+++ b/engine/net_chan.cpp
@@ -64,10 +64,15 @@ extern int  NET_ReceiveStream( int nSock, char * buf, int len, int flags );
 // We only need to checksum packets on the PC and only when we're actually sending them over the network.
 static bool ShouldChecksumPackets()
 {
+	// nillerusr: temporary solution for testing
+	return false;
+
+#if 0
 	if ( !IsPC() )
 		return false;
 
 	return NET_IsMultiplayer();
+#endif
 }
 
 bool CNetChan::IsLoopback() const
diff --git a/engine/net_ws.cpp b/engine/net_ws.cpp
index ba3a791e..b2680f1a 100644
--- a/engine/net_ws.cpp
+++ b/engine/net_ws.cpp
@@ -13,6 +13,7 @@
 #include "net_ws_headers.h"
 #include "net_ws_queued_packet_sender.h"
 #include "fmtstr.h"
+#include "master.h"
 
 // memdbgon must be the last include file in a .cpp file!!!
 #include "tier0/memdbgon.h"
@@ -1644,7 +1645,7 @@ netpacket_t *NET_GetPacket (int sock, byte *scratch )
 	// Check loopback first
 	if ( !NET_GetLoopPacket( &inpacket ) )
 	{
-		if ( !NET_IsMultiplayer() )
+		if ( !NET_IsMultiplayer() && sock != NS_CLIENT )
 		{
 			return NULL;
 		}
@@ -2351,7 +2352,7 @@ int NET_SendPacket ( INetChannel *chan, int sock,  const netadr_t &to, const uns
 		Msg("UDP -> %s: sz=%i OOB '%c'\n", to.ToString(), length, data[4] );
 	}
 
-	if ( !NET_IsMultiplayer() || to.type == NA_LOOPBACK || ( to.IsLocalhost() && !net_usesocketsforloopback.GetBool() ) )
+	if ( (!NET_IsMultiplayer() && sock != NS_CLIENT) || to.type == NA_LOOPBACK || ( to.IsLocalhost() && !net_usesocketsforloopback.GetBool() ) )
 	{
 		Assert( !pVoicePayload );
 
@@ -2988,6 +2989,8 @@ void NET_RunFrame( double flRealtime )
 
 #endif // SWDS
 
+	master->RunFrame();
+
 #ifdef _X360
 	if ( net_logserver.GetInt() )
 	{
@@ -3110,7 +3113,7 @@ void NET_ListenSocket( int sock, bool bListen )
 		NET_CloseSocket( netsock->hTCP, sock );
 	}
 
-	if ( !NET_IsMultiplayer() || net_notcp )
+	if ( (!NET_IsMultiplayer() && sock != NS_CLIENT) || net_notcp )
 		return;
 
 	if ( bListen )
@@ -3296,6 +3299,11 @@ void NET_Init( bool bIsDedicated )
 		ipname.SetValue( ip );  // update the cvar right now, this will get overwritten by "stuffcmds" later
 	}
 
+	const int nProtocol = X360SecureNetwork() ? IPPROTO_VDP : IPPROTO_UDP;
+
+	// open client socket for masterserver
+	OpenSocketInternal( NS_CLIENT, clientport.GetInt(), PORT_SERVER, "client", nProtocol, true );
+
 	if ( bIsDedicated )
 	{
 		// set dedicated MP mode
diff --git a/engine/sv_steamauth.cpp b/engine/sv_steamauth.cpp
index 144ae775..caa14cea 100644
--- a/engine/sv_steamauth.cpp
+++ b/engine/sv_steamauth.cpp
@@ -1005,7 +1005,7 @@ void Heartbeat_f()
 	}
 }
 
-static ConCommand heartbeat( "heartbeat", Heartbeat_f, "Force heartbeat of master servers", 0 );
+//static ConCommand heartbeat( "heartbeat", Heartbeat_f, "Force heartbeat of master servers", 0 );
 
 
 //-----------------------------------------------------------------------------
diff --git a/engine/wscript b/engine/wscript
index 6ef0bc77..81456630 100755
--- a/engine/wscript
+++ b/engine/wscript
@@ -329,7 +329,8 @@ def build(bld):
 			'vgui_texturebudgetpanel.cpp',
 			'vgui_vprofgraphpanel.cpp',
 			'vgui_vprofpanel.cpp',
-			'toolframework.cpp'
+			'toolframework.cpp',
+			'masterserver.cpp',
 		]
 		
 		if bld.env.DEST_OS != 'win32':
diff --git a/public/engine/iserversinfo.h b/public/engine/iserversinfo.h
new file mode 100644
index 00000000..663feb75
--- /dev/null
+++ b/public/engine/iserversinfo.h
@@ -0,0 +1,97 @@
+//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. =======
+//
+// Purpose: interface to steam managing game server/client match making
+//
+//=============================================================================
+
+#ifndef ISERVERSINFO_H
+#define ISERVERSINFO_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#define MAX_GAME_DESCRIPTION 8192
+#define MAX_SERVER_NAME 2048
+
+enum ServerResponse
+{
+	ServerResponded = 0,
+	ServerFailedToRespond,
+	NoServersListedOnMasterServer,
+};
+
+class newgameserver_t
+{
+public:
+	newgameserver_t() = default;
+
+	const char* GetName() const;
+	void SetName( const char *pName );
+
+	netadr_t m_NetAdr;								///< IP/Query Port/Connection Port for this server
+	int m_nPing;											///< current ping time in milliseconds
+	bool m_bHadSuccessfulResponse;	///< server has responded successfully in the past
+	bool m_bDoNotRefresh;						///< server is marked as not responding and should no longer be refreshed
+	char m_szGameDir[MAX_PATH];				 ///< current game directory
+	char m_szMap[MAX_PATH];					///< current map
+	char m_szGameDescription[MAX_GAME_DESCRIPTION]; ///< game description
+
+	int m_nPlayers;
+	int m_nMaxPlayers;										///< Maximum players that can join this server
+	int m_nBotPlayers;										///< Number of bots (i.e simulated players) on this server
+	bool m_bPassword;										///< true if this server needs a password to join
+private:
+	/// Game server name
+	char m_szServerName[MAX_SERVER_NAME];
+};
+
+class IServerListResponse
+{
+public:
+	// Server has responded ok with updated data
+	virtual void ServerResponded( newgameserver_t &server ) = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Callback interface for receiving responses after pinging an individual server 
+//
+class IServerPingResponse
+{
+public:
+	// Server has responded successfully and has updated data
+	virtual void ServerResponded( newgameserver_t &server ) = 0;
+};
+//-----------------------------------------------------------------------------
+// Purpose: Callback interface for receiving responses after requesting details on
+// who is playing on a particular server.
+//
+class IServerPlayersResponse
+{
+public:
+	// Got data on a new player on the server -- you'll get this callback once per player
+	// on the server which you have requested player data on.
+	virtual void AddPlayerToList( const char *pchName, int nScore, float flTimePlayed ) = 0;
+
+	// The server failed to respond to the request for player details
+	virtual void PlayersFailedToRespond() = 0;
+
+	// The server has finished responding to the player details request
+	virtual void PlayersRefreshComplete() = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Functions for match making services for clients to get to game lists and details
+//-----------------------------------------------------------------------------
+class IServersInfo
+{
+public:
+	virtual void RequestInternetServerList( const char *gamedir, IServerListResponse *response ) = 0;
+	virtual void RequestLANServerList( const char *gamedir, IServerListResponse *response ) = 0;
+
+	//virtual HServerQuery PingServer( uint32 unIP, uint16 usPort, ISteamMatchmakingPingResponse *pRequestServersResponse ) = 0; 
+	//virtual HServerQuery PlayerDetails( uint32 unIP, uint16 usPort, ISteamMatchmakingPlayersResponse *pRequestServersResponse ) = 0;
+
+};
+#define SERVERLIST_INTERFACE_VERSION "ServerList001"
+
+#endif // ISERVERSINFO_H

From 548be38a0b564c5624eff521c1e88bfe1062f4bb Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Sat, 28 Jan 2023 05:36:57 +0300
Subject: [PATCH 02/17] engine: restore checksum check

---
 engine/net_chan.cpp | 8 --------
 engine/wscript      | 2 +-
 2 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/engine/net_chan.cpp b/engine/net_chan.cpp
index e722bc02..080c727c 100644
--- a/engine/net_chan.cpp
+++ b/engine/net_chan.cpp
@@ -64,15 +64,7 @@ extern int  NET_ReceiveStream( int nSock, char * buf, int len, int flags );
 // We only need to checksum packets on the PC and only when we're actually sending them over the network.
 static bool ShouldChecksumPackets()
 {
-	// nillerusr: temporary solution for testing
-	return false;
-
-#if 0
-	if ( !IsPC() )
-		return false;
-
 	return NET_IsMultiplayer();
-#endif
 }
 
 bool CNetChan::IsLoopback() const
diff --git a/engine/wscript b/engine/wscript
index 81456630..54ffdc4e 100755
--- a/engine/wscript
+++ b/engine/wscript
@@ -196,6 +196,7 @@ def build(bld):
 		'EngineSoundServer.cpp',
 		'audio/voice_wavefile.cpp',
 		'audio/vox.cpp',
+		'masterserver.cpp',
 
 		#'audio/snd_dev_xaudio.cpp',[$X360]
 		#'audio/snd_wave_mixer_xma.cpp',	[$X360]
@@ -330,7 +331,6 @@ def build(bld):
 			'vgui_vprofgraphpanel.cpp',
 			'vgui_vprofpanel.cpp',
 			'toolframework.cpp',
-			'masterserver.cpp',
 		]
 		
 		if bld.env.DEST_OS != 'win32':

From 41aa50e66ef1c832e0b9f3a9da83575e00e12e1c Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Sun, 29 Jan 2023 19:26:04 +0300
Subject: [PATCH 03/17] WIP: Begin rewriting serverbrowser

---
 engine/masterserver.cpp                       |  16 ++
 serverbrowser/BaseGamesPage.cpp               | 243 ++++++++++++------
 serverbrowser/BaseGamesPage.h                 |  28 +-
 serverbrowser/DialogAddServer.cpp             |  20 --
 serverbrowser/DialogAddServer.h               |  14 -
 serverbrowser/DialogGameInfo.cpp              |  30 +--
 serverbrowser/FavoriteGames.cpp               |   4 +-
 serverbrowser/FavoriteGames.h                 |   2 +-
 serverbrowser/HistoryGames.cpp                |  20 +-
 serverbrowser/HistoryGames.h                  |   2 +-
 serverbrowser/InternetGames.cpp               |  23 +-
 serverbrowser/InternetGames.h                 |   6 +-
 serverbrowser/LanGames.cpp                    |   4 +-
 serverbrowser/LanGames.h                      |   2 +-
 serverbrowser/ServerBrowser.cpp               |  14 +-
 serverbrowser/ServerBrowserDialog.cpp         | 141 ++--------
 serverbrowser/ServerBrowserDialog.h           |  15 +-
 serverbrowser/pch_serverbrowser.h             |   6 +-
 .../{ => unused}/BlacklistedServers.cpp       |   0
 .../{ => unused}/BlacklistedServers.h         |   0
 serverbrowser/{ => unused}/CustomGames.cpp    |   0
 serverbrowser/{ => unused}/CustomGames.h      |   0
 serverbrowser/{ => unused}/FriendsGames.cpp   |   0
 serverbrowser/{ => unused}/FriendsGames.h     |   0
 serverbrowser/{ => unused}/SpectateGames.cpp  |   0
 serverbrowser/{ => unused}/SpectateGames.h    |   0
 serverbrowser/wscript                         |   8 +-
 27 files changed, 265 insertions(+), 333 deletions(-)
 rename serverbrowser/{ => unused}/BlacklistedServers.cpp (100%)
 rename serverbrowser/{ => unused}/BlacklistedServers.h (100%)
 rename serverbrowser/{ => unused}/CustomGames.cpp (100%)
 rename serverbrowser/{ => unused}/CustomGames.h (100%)
 rename serverbrowser/{ => unused}/FriendsGames.cpp (100%)
 rename serverbrowser/{ => unused}/FriendsGames.h (100%)
 rename serverbrowser/{ => unused}/SpectateGames.cpp (100%)
 rename serverbrowser/{ => unused}/SpectateGames.h (100%)

diff --git a/engine/masterserver.cpp b/engine/masterserver.cpp
index 62d7e614..f3803d45 100644
--- a/engine/masterserver.cpp
+++ b/engine/masterserver.cpp
@@ -80,6 +80,8 @@ private:
 	bool	m_bNoMasters;
 
 	CUtlLinkedList<netadr_t> m_serverAddresses;
+
+	IServerListResponse *m_serverListResponse;
 };
 
 static CMaster s_MasterServer;
@@ -87,6 +89,8 @@ IMaster *master = (IMaster *)&s_MasterServer;
 
 IServersInfo *g_pServersInfo = (IServersInfo*)&s_MasterServer;
 
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CMaster, IServersInfo, SERVERLIST_INTERFACE_VERSION, s_MasterServer );
+
 #define	HEARTBEAT_SECONDS	140.0
 
 //-----------------------------------------------------------------------------
@@ -97,6 +101,9 @@ CMaster::CMaster( void )
 	m_pMasterAddresses	= NULL;
 	m_bNoMasters		= false;
 	m_bInitialized = false;
+
+	m_serverListResponse = NULL;
+
 	Init();
 }
 
@@ -165,6 +172,11 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 			char hostname[1024];
 			msg.ReadString(hostname, sizeof(hostname));
 
+			newgameserver_t s;
+			s.m_NetAdr = packet->from;
+			s.SetName( hostname );
+
+			m_serverListResponse->ServerResponded( s );
 			break;
 		}
 	}
@@ -180,6 +192,8 @@ void CMaster::RequestServersInfo()
 	{
 		const netadr_t adr = m_serverAddresses[i];
 
+		Msg("Request server info %s\n", adr.ToString());
+
 		msg.WriteLong( CONNECTIONLESS_HEADER );
 		msg.WriteByte( C2S_INFOREQUEST );
 
@@ -474,6 +488,8 @@ void CMaster::RequestInternetServerList(const char *gamedir, IServerListResponse
 {
 	if( m_bNoMasters ) return;
 
+	m_serverListResponse = response;
+
 	ALIGN4 char buf[256] ALIGN4_POST;
 	bf_write msg(buf, sizeof(buf));
 
diff --git a/serverbrowser/BaseGamesPage.cpp b/serverbrowser/BaseGamesPage.cpp
index 6cef8827..e0f80b63 100644
--- a/serverbrowser/BaseGamesPage.cpp
+++ b/serverbrowser/BaseGamesPage.cpp
@@ -322,7 +322,7 @@ void CBaseGamesPage::PerformLayout()
 		m_pRefreshQuick->SetEnabled(false);
 	}
 
-	if ( !steamapicontext->SteamMatchmakingServers() || !steamapicontext->SteamMatchmaking() )
+/*	if ( !steamapicontext->SteamMatchmakingServers() || !steamapicontext->SteamMatchmaking() )
 	{
 		m_pAddCurrentServer->SetVisible( false );
 		m_pRefreshQuick->SetEnabled( false );
@@ -331,7 +331,7 @@ void CBaseGamesPage::PerformLayout()
 		m_pRefreshAll->SetEnabled( false );
 		m_pAddToFavoritesButton->SetEnabled( false );
 		m_pGameList->SetEmptyListText( "#ServerBrowser_SteamRunning" );
-	}
+	}*/
 
 	Repaint();
 }
@@ -797,19 +797,19 @@ void CBaseGamesPage::UpdateGameFilter()
 // Purpose: Handles incoming server refresh data
 //			updates the server browser with the refreshed information from the server itself
 //-----------------------------------------------------------------------------
-void CBaseGamesPage::ServerResponded( gameserveritem_t &server )
+/*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 )
+/*void CBaseGamesPage::ServerResponded( HServerListRequest hReq, int iServer )
 {
 	gameserveritem_t *pServerItem = steamapicontext->SteamMatchmakingServers()->GetServerDetails( hReq, iServer );
 	if ( !pServerItem )
@@ -825,15 +825,17 @@ void CBaseGamesPage::ServerResponded( HServerListRequest hReq, int iServer )
 	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 )
 {
+#if 0
 	int iServerMap = m_mapServers.Find( iServer );
 	if ( iServerMap == m_mapServers.InvalidIndex() )
 	{
@@ -988,6 +990,7 @@ void CBaseGamesPage::ServerResponded( int iServer, gameserveritem_t *pServerItem
 	PrepareQuickListMap( pServerItem->m_szMap, pServer->m_iListID );
 	UpdateStatus();
 	m_iServerRefreshCount++;
+#endif
 }
 
 //-----------------------------------------------------------------------------
@@ -1143,11 +1146,10 @@ void CBaseGamesPage::OnTextChanged(Panel *panel, const char *text)
 //-----------------------------------------------------------------------------
 void CBaseGamesPage::ApplyGameFilters()
 {
+#if 0
 	if ( !steamapicontext->SteamMatchmakingServers() )
 		return;
 
-	m_iServersBlacklisted = 0;
-
 	// loop through all the servers checking filters
 	FOR_EACH_MAP_FAST( m_mapServers, i )
 	{
@@ -1215,6 +1217,7 @@ void CBaseGamesPage::ApplyGameFilters()
 	m_pGameList->SortList();
 	InvalidateLayout();
 	Repaint();
+#endif
 }
 
 //-----------------------------------------------------------------------------
@@ -1224,14 +1227,10 @@ void CBaseGamesPage::UpdateStatus()
 {
 	if (m_pGameList->GetItemCount() > 1)
 	{
-		wchar_t header[256];
-		wchar_t count[128];
-		wchar_t blacklistcount[128];
+		wchar_t msg[256];
 
-		_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);
+		_snwprintf( msg, Q_ARRAYSIZE(msg), L"%S( %d )", g_pVGuiLocalize->Find( "#ServerBrowser_Servers"), m_pGameList->GetItemCount() );
+		m_pGameList->SetColumnHeaderText( k_nColumn_Name, msg);
 	}
 	else
 	{
@@ -1529,19 +1528,12 @@ void CBaseGamesPage::RecalculateFilterString()
 // 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 )
+bool CBaseGamesPage::CheckPrimaryFilters( newgameserver_t &server )
 {
-	if (m_szGameFilter[0] && ( server.m_szGameDir[0] || server.m_nPing ) && Q_stricmp(m_szGameFilter, server.m_szGameDir ) ) 
+	if (m_szGameFilter[0] && server.m_szGameDir[0] && 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;
 }
@@ -1551,7 +1543,7 @@ bool CBaseGamesPage::CheckPrimaryFilters( gameserveritem_t &server )
 //			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 CBaseGamesPage::CheckSecondaryFilters( newgameserver_t &server )
 {
 	bool bFilterNoEmpty = m_bFilterNoEmptyServers;
 	bool bFilterNoFull = m_bFilterNoFullServers;
@@ -1595,7 +1587,7 @@ bool CBaseGamesPage::CheckSecondaryFilters( gameserveritem_t &server )
 		return false;
 	}
 
-	if ( iFilterSecure == FILTER_SECURESERVERSONLY && !server.m_bSecure )
+	/*if ( iFilterSecure == FILTER_SECURESERVERSONLY && !server.m_bSecure )
 	{
 		return false;
 	}
@@ -1608,7 +1600,7 @@ bool CBaseGamesPage::CheckSecondaryFilters( gameserveritem_t &server )
 	if ( m_bFilterReplayServers && !IsReplayServer( server ) )
 	{
 		return false;
-	}
+	}*/
 
 	if ( m_pQuickList->IsVisible() == false )
 	{
@@ -1787,37 +1779,15 @@ void CBaseGamesPage::OnAddToFavorites()
 	}
 }
 
-//-----------------------------------------------------------------------------
-// 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: 
 //-----------------------------------------------------------------------------
+#if 0
 void CBaseGamesPage::ServerFailedToRespond( HServerListRequest hReq, int iServer )
 {
 	ServerResponded( hReq, iServer );
 }
-
+#endif
 
 //-----------------------------------------------------------------------------
 // Purpose: removes the server from the UI list
@@ -1864,41 +1834,37 @@ void CBaseGamesPage::OnRefreshServer( int serverID )
 //-----------------------------------------------------------------------------
 void CBaseGamesPage::StartRefresh()
 {
-	if ( !steamapicontext->SteamMatchmakingServers() )
-		return;
-
 	ClearServerList();
 	MatchMakingKeyValuePair_t *pFilters;
 	int nFilters = GetServerFilters( &pFilters );
 
-	if ( m_hRequest )
+/*	if ( m_hRequest )
 	{
 		steamapicontext->SteamMatchmakingServers()->ReleaseRequest( m_hRequest );
 		m_hRequest = NULL;
-	}
+	}*/
 	switch ( m_eMatchMakingType )
 	{
-	case eFavoritesServer:
+/*	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;
+		break;*/
 	case eInternetServer:
-		m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestInternetServerList( GetFilterAppID().AppID(), &pFilters, nFilters, this );
+		Msg("RequestInternetServerList\n");
+		g_pServersInfo->RequestInternetServerList(COM_GetModDirectory(), this);
+		//m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestInternetServerList( GetFilterAppID().AppID(), &pFilters, nFilters, this );
 		break;
-	case eSpectatorServer:
+/*	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;
+		break;*/
 	}
 
 	SetRefreshing( true );
@@ -1936,7 +1902,6 @@ void CBaseGamesPage::ClearServerList()
 	m_mapServers.RemoveAll(); 
 	m_mapServerIP.RemoveAll();
 	m_pGameList->RemoveAll();
-	m_iServersBlacklisted = 0;
 
 	ClearQuickList();
 }
@@ -1964,7 +1929,7 @@ void CBaseGamesPage::StopRefresh()
 		steamapicontext->SteamMatchmakingServers()->CancelQuery( m_hRequest );
 
 	// update UI
-	RefreshComplete( m_hRequest, eServerResponded );
+	RefreshComplete( nServerResponded );
 
 	// apply settings
 	ApplyGameFilters();
@@ -1973,7 +1938,7 @@ void CBaseGamesPage::StopRefresh()
 //-----------------------------------------------------------------------------
 // Purpose: 
 //-----------------------------------------------------------------------------
-void CBaseGamesPage::RefreshComplete( HServerListRequest hRequest, EMatchMakingServerResponse response )
+void CBaseGamesPage::RefreshComplete( NServerResponse response )
 {
 	SelectQuickListServers();
 }
@@ -2116,7 +2081,7 @@ void CDialogServerWarning::OnCommand(const char *command)
 		PostMessage(this, new KeyValues("Close"));
 
 		// join the game
-		ServerBrowserDialog().JoinGame( m_pGameList, m_iServerID );
+		//ServerBrowserDialog().JoinGame( m_pGameList, m_iServerID );
 	}
 	else
 	{
@@ -2142,16 +2107,16 @@ void CDialogServerWarning::OnButtonToggled(Panel *panel, int state)
 void CBaseGamesPage::OnBeginConnect()
 {
 	KeyValues *pKV = NULL;
-	int serverID = GetSelectedServerID( &pKV );
+	int iServerIndex = GetSelectedServerID( &pKV );
 	
-	if ( serverID == -1 )
+	if ( iServerIndex == -1 )
 		return;
 
 	// Stop the current refresh
 	StopRefresh();
 
 	ConVarRef sb_dontshow_maxplayer_warning( "sb_dontshow_maxplayer_warning", true );
-	if ( sb_dontshow_maxplayer_warning.IsValid() )
+/*	if ( sb_dontshow_maxplayer_warning.IsValid() )
 	{
 		// If the server is above the suggested maxplayers, warn the player
 		int iMaxP = sb_mod_suggested_maxplayers.GetInt();
@@ -2177,10 +2142,10 @@ void CBaseGamesPage::OnBeginConnect()
 				return;
 			}
 		}
-	}
+	}*/
 
 	// join the game
-	ServerBrowserDialog().JoinGame(this, serverID);
+	ServerBrowserDialog().JoinGame(this, &m_serversInfo[iServerIndex]);
 }
 
 //-----------------------------------------------------------------------------
@@ -2197,7 +2162,7 @@ void CBaseGamesPage::OnViewGameInfo()
 	StopRefresh();
 
 	// join the game
-	ServerBrowserDialog().OpenGameInfoDialog(this, serverID);
+	//ServerBrowserDialog().OpenGameInfoDialog(this, serverID);
 }
 
 //-----------------------------------------------------------------------------
@@ -2222,9 +2187,6 @@ const char *CBaseGamesPage::GetConnectCode()
 		case eLANServer:
 			pszConnectCode = "serverbrowser_lan";
 			break;
-		case eFriendsServer:
-			pszConnectCode = "serverbrowser_friends";
-			break;
 		case eFavoritesServer:
 			pszConnectCode = "serverbrowser_favorites";
 			break;
@@ -2239,6 +2201,119 @@ const char *CBaseGamesPage::GetConnectCode()
 	return pszConnectCode;
 }
 
+void CBaseGamesPage::ServerResponded( newgameserver_t &server )
+{
+	Msg("Serverbrowser: hostname %s\n", server.GetName());
+
+	Assert( server.m_NetAdr.GetIP() != 0 );
+
+	newgameserver_t *pServerItem = &server;
+
+	// check filters
+	bool removeItem = false;
+#if 0
+	if ( !CheckPrimaryFilters( server ) )
+	{
+		// server has been filtered at a primary level
+		// remove from lists
+		//pServer->m_bDoNotRefresh = true;
+
+		// remove from UI list
+		//removeItem = true;
+		return;
+	}
+	else if (!CheckSecondaryFilters( server ))
+	{
+		// we still ping this server in the future; however it is removed from UI list
+		return;
+	}
+#endif
+
+	// new entry
+	KeyValues *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", "");
+
+
+	kv->SetInt("secure", 0);
+
+	kv->SetString( "IPAddr", pServerItem->m_NetAdr.ToString() );
+
+	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", "");
+
+	kv->SetInt("Replay", 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", "");
+	}
+
+	int iServerIndex = m_serversInfo.AddToTail( server );
+
+	//if ( !m_pGameList->IsValidItemID( pServer->m_iListID ) )
+
+		// new server, add to list
+		int iListID = m_pGameList->AddItem(kv, iServerIndex, false, false);
+		/*if ( m_bAutoSelectFirstItemInGameList && m_pGameList->GetItemCount() == 1 )
+		{
+			m_pGameList->AddSelectedItem( pServer->m_iListID );
+		}*/
+
+		m_pGameList->SetItemVisible( iListID, true );
+
+		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, iListID );
+	UpdateStatus();
+	m_iServerRefreshCount++;
+
+}
 
 //-----------------------------------------------------------------------------
 // Purpose: Refresh if our favorites list changed
@@ -2252,8 +2327,6 @@ void CBaseGamesPage::OnFavoritesMsg( FavoritesListChanged_t *pFavListChanged )
 		case eInternetServer:
 		case eLANServer:
 		case eSpectatorServer:
-		case eFriendsServer:
-			return;
 		case eFavoritesServer:
 		case eHistoryServer:
 			// check containing property sheet to see if the page is visible.
@@ -2276,8 +2349,6 @@ void CBaseGamesPage::OnFavoritesMsg( FavoritesListChanged_t *pFavListChanged )
 	case eInternetServer:
 	case eLANServer:
 	case eSpectatorServer:
-	case eFriendsServer:
-		break;
 	case eFavoritesServer:
 	case eHistoryServer:
 		{
@@ -2286,8 +2357,10 @@ void CBaseGamesPage::OnFavoritesMsg( FavoritesListChanged_t *pFavListChanged )
 		{
 			if ( pFavListChanged->m_bAdd )	
 			{
-				if ( steamapicontext->SteamMatchmakingServers() )
-					steamapicontext->SteamMatchmakingServers()->PingServer( pFavListChanged->m_nIP, pFavListChanged->m_nQueryPort, this );
+
+			// TODO(nillerusr): implement this
+			//	if ( steamapicontext->SteamMatchmakingServers() )
+			//		steamapicontext->SteamMatchmakingServers()->PingServer( pFavListChanged->m_nIP, pFavListChanged->m_nQueryPort, this );
 			}
 			// ignore deletes of fav's we didn't have
 		}
@@ -2295,8 +2368,8 @@ void CBaseGamesPage::OnFavoritesMsg( FavoritesListChanged_t *pFavListChanged )
 		{
 			if ( pFavListChanged->m_bAdd )	
 			{
-				if ( m_mapServerIP[ iIPServer ] > 0 )
-					ServerResponded( m_hRequest, m_mapServerIP[ iIPServer ] );
+			//	if ( m_mapServerIP[ iIPServer ] > 0 )
+			//		ServerResponded( m_hRequest, m_mapServerIP[ iIPServer ] );
 			}
 			else
 			{
diff --git a/serverbrowser/BaseGamesPage.h b/serverbrowser/BaseGamesPage.h
index 2d69b1d1..fca73685 100644
--- a/serverbrowser/BaseGamesPage.h
+++ b/serverbrowser/BaseGamesPage.h
@@ -12,6 +12,7 @@
 #endif
 
 #include "tier1/utldict.h"
+#include "engine/iserversinfo.h"
 
 class CBaseGamesPage;
 
@@ -82,7 +83,7 @@ struct gametypes_t
 //-----------------------------------------------------------------------------
 // Purpose: Base property page for all the games lists (internet/favorites/lan/etc.)
 //-----------------------------------------------------------------------------
-class CBaseGamesPage : public vgui::PropertyPage, public IGameList, public ISteamMatchmakingServerListResponse, public ISteamMatchmakingPingResponse
+class CBaseGamesPage : public vgui::PropertyPage, public IGameList, public IServerListResponse //, public ISteamMatchmakingPingResponse
 {
 	DECLARE_CLASS_SIMPLE( CBaseGamesPage, vgui::PropertyPage );
 
@@ -138,7 +139,6 @@ public:
 
 	// adds a server to the favorites
 	MESSAGE_FUNC( OnAddToFavorites, "AddToFavorites" );
-	MESSAGE_FUNC( OnAddToBlacklist, "AddToBlacklist" );
 
 	virtual void StartRefresh();
 
@@ -173,14 +173,14 @@ protected:
 	void UpdateStatus();
 
 	// ISteamMatchmakingServerListResponse callbacks
-	virtual void ServerResponded( HServerListRequest hReq, int iServer );
-	virtual void ServerResponded( int iServer, gameserveritem_t *pServerItem );
-	virtual void ServerFailedToRespond( HServerListRequest hReq, int iServer );
-	virtual void RefreshComplete( HServerListRequest hReq, EMatchMakingServerResponse response ) = 0;
+	virtual void ServerResponded( newgameserver_t &server );
+	virtual void RefreshComplete( NServerResponse response );
 
 	// ISteamMatchmakingPingResponse callbacks
-	virtual void ServerResponded( gameserveritem_t &server );
-	virtual void ServerFailedToRespond() {}
+	//virtual void ServerResponded( gameserveritem_t &server );
+	//virtual void ServerFailedToRespond() {}
+
+	virtual void ServerResponded( int iServer, gameserveritem_t *pServerItem );
 
 	// Removes server from list
 	void RemoveServer( serverdisplay_t &server );
@@ -190,10 +190,10 @@ protected:
 
 	// filtering methods
 	// returns true if filters passed; false if failed
-	virtual bool CheckPrimaryFilters( gameserveritem_t &server);
-	virtual bool CheckSecondaryFilters( gameserveritem_t &server );
-	virtual bool CheckTagFilter( gameserveritem_t &server ) { return true; }
-	virtual bool CheckWorkshopFilter( gameserveritem_t &server ) { return true; }
+	virtual bool CheckPrimaryFilters( newgameserver_t &server);
+	virtual bool CheckSecondaryFilters( newgameserver_t &server );
+	virtual bool CheckTagFilter( newgameserver_t &server ) { return true; }
+	virtual bool CheckWorkshopFilter( newgameserver_t &server ) { return true; }
 	virtual int GetInvalidServerListID();
 
 	virtual void OnSaveFilter(KeyValues *filter);
@@ -236,6 +236,9 @@ protected:
 	CUtlMap<uint64, int> m_mapGamesFilterItem;
 	CUtlMap<int, serverdisplay_t> m_mapServers;
 	CUtlMap<netadr_t, int> m_mapServerIP;
+
+	CUtlVector<newgameserver_t> m_serversInfo;
+
 	CUtlVector<MatchMakingKeyValuePair_t> m_vecServerFilters;
 	CUtlDict< CQuickListMapServerList, int > m_quicklistserverlist;
 	int m_iServerRefreshCount;
@@ -316,7 +319,6 @@ private:
 	bool m_bFilterNoEmptyServers;
 	bool m_bFilterNoPasswordedServers;
 	int m_iSecureFilter;
-	int m_iServersBlacklisted;
 	bool m_bFilterReplayServers;
 
 	CGameID m_iLimitToAppID;
diff --git a/serverbrowser/DialogAddServer.cpp b/serverbrowser/DialogAddServer.cpp
index cbba58eb..5dbc9ed5 100644
--- a/serverbrowser/DialogAddServer.cpp
+++ b/serverbrowser/DialogAddServer.cpp
@@ -370,23 +370,3 @@ void CDialogAddServer::FinishAddServer( gameserveritem_t &pServer )
 {
 	ServerBrowserDialog().AddServerToFavorites( pServer );
 }
-
-//-----------------------------------------------------------------------------
-// Purpose: 
-//-----------------------------------------------------------------------------
-void CDialogAddBlacklistedServer::FinishAddServer( gameserveritem_t &pServer )
-{
-	ServerBrowserDialog().AddServerToBlacklist( pServer );
-	ServerBrowserDialog().BlacklistsChanged();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: 
-//-----------------------------------------------------------------------------
-void CDialogAddBlacklistedServer::ApplySchemeSettings( vgui::IScheme *pScheme )
-{
-	BaseClass::ApplySchemeSettings( pScheme );
-
-	m_pAddServerButton->SetText( "#ServerBrowser_AddAddressToBlacklist" );
-	m_pAddSelectedServerButton->SetText( "#ServerBrowser_AddSelectedToBlacklist" );
-}
diff --git a/serverbrowser/DialogAddServer.h b/serverbrowser/DialogAddServer.h
index 7abaee1a..c340904b 100644
--- a/serverbrowser/DialogAddServer.h
+++ b/serverbrowser/DialogAddServer.h
@@ -58,18 +58,4 @@ protected:
 	CUtlVector<HServerQuery> m_Queries;
 };
 
-class CDialogAddBlacklistedServer : public CDialogAddServer 
-{
-	DECLARE_CLASS_SIMPLE( CDialogAddBlacklistedServer, CDialogAddServer );
-public:
-	CDialogAddBlacklistedServer( vgui::Panel *parent, IGameList *gameList) :
-		CDialogAddServer( parent, gameList )
-	{
-	}
-
-	virtual void FinishAddServer( gameserveritem_t &pServer );
-	void ApplySchemeSettings( vgui::IScheme *pScheme );
-	virtual bool AllowInvalidIPs( void ) { return true; }
-};
-
 #endif // DIALOGADDSERVER_H
diff --git a/serverbrowser/DialogGameInfo.cpp b/serverbrowser/DialogGameInfo.cpp
index fc0ed36c..ce54f477 100644
--- a/serverbrowser/DialogGameInfo.cpp
+++ b/serverbrowser/DialogGameInfo.cpp
@@ -293,7 +293,10 @@ void CDialogGameInfo::PerformLayout()
 	}
 	SetControlString("PlayersText", buf);
 
-	if ( m_Server.m_NetAdr.GetIP() && m_Server.m_NetAdr.GetQueryPort() )
+	SetControlString("ServerIPText", m_Server.m_NetAdr.GetConnectionAddressString() );
+	m_pConnectButton->SetEnabled(true);
+
+/*	if ( m_Server.m_NetAdr.GetIP() && m_Server.m_NetAdr.GetQueryPort() )
 	{
 		SetControlString("ServerIPText", m_Server.m_NetAdr.GetConnectionAddressString() );
 		m_pConnectButton->SetEnabled(true);
@@ -312,7 +315,7 @@ void CDialogGameInfo::PerformLayout()
 	{
 		SetControlString("ServerIPText", "");
 		m_pConnectButton->SetEnabled(false);
-	}
+	}*/
 
 	if ( m_Server.m_bHadSuccessfulResponse )
 	{
@@ -405,7 +408,11 @@ void CDialogGameInfo::OnConnect()
 
 	// need to refresh server before attempting to connect, to make sure there is enough room on the server
 	m_iRequestRetry = 0;
-	RequestInfo();
+
+	ConnectToServer();
+
+	//TODO(nillerusr): restore this later
+	//RequestInfo();
 }
 
 //-----------------------------------------------------------------------------
@@ -633,17 +640,6 @@ void CDialogGameInfo::ConnectToServer()
 {
 	m_bConnecting = false;
 
-	// check VAC status
-	if ( m_Server.m_bSecure && ServerBrowser().IsVACBannedFromGame( m_Server.m_nAppID ) )
-	{
-		// refuse the user
-		CVACBannedConnRefusedDialog *pDlg = new CVACBannedConnRefusedDialog( GetVParent(), "VACBannedConnRefusedDialog" );
-		pDlg->Activate();
-		Close();
-		return;
-	}
-
-
 	// check to see if we need a password
 	if ( m_Server.m_bPassword && !m_szPassword[0] )
 	{
@@ -654,7 +650,9 @@ void CDialogGameInfo::ConnectToServer()
 	}
 
 	// check the player count
-	if ( m_Server.m_nPlayers >= m_Server.m_nMaxPlayers )
+
+	// nillerusr
+	/*if ( m_Server.m_nPlayers >= m_Server.m_nMaxPlayers )
 	{
 		// mark why we cannot connect
 		m_bServerFull = true;
@@ -662,7 +660,7 @@ void CDialogGameInfo::ConnectToServer()
 		m_bShowAutoRetryToggle = true;
 		InvalidateLayout();
 		return;
-	}
+	}*/
 
 	// tell the engine to connect
 	const char *gameDir = m_Server.m_szGameDir;
diff --git a/serverbrowser/FavoriteGames.cpp b/serverbrowser/FavoriteGames.cpp
index 0149baf1..a9306cc2 100644
--- a/serverbrowser/FavoriteGames.cpp
+++ b/serverbrowser/FavoriteGames.cpp
@@ -73,7 +73,7 @@ bool CFavoriteGames::SupportsItem(InterfaceItem_e item)
 //-----------------------------------------------------------------------------
 // Purpose: called when the current refresh list is complete
 //-----------------------------------------------------------------------------
-void CFavoriteGames::RefreshComplete( HServerListRequest hReq, EMatchMakingServerResponse response )
+void CFavoriteGames::RefreshComplete( NServerResponse response )
 {
 	SetRefreshing(false);
 	if ( steamapicontext->SteamMatchmaking() && steamapicontext->SteamMatchmaking()->GetFavoriteGameCount() == 0 )
@@ -88,7 +88,7 @@ void CFavoriteGames::RefreshComplete( HServerListRequest hReq, EMatchMakingServe
 	}
 	m_pGameList->SortList();
 
-	BaseClass::RefreshComplete( hReq, response );
+	BaseClass::RefreshComplete( response );
 }
 
 //-----------------------------------------------------------------------------
diff --git a/serverbrowser/FavoriteGames.h b/serverbrowser/FavoriteGames.h
index 8355005a..242670ea 100644
--- a/serverbrowser/FavoriteGames.h
+++ b/serverbrowser/FavoriteGames.h
@@ -30,7 +30,7 @@ public:
 	virtual bool SupportsItem(InterfaceItem_e item);
 
 	// called when the current refresh list is complete
-	virtual void RefreshComplete( HServerListRequest hReq, EMatchMakingServerResponse response );
+	virtual void RefreshComplete( NServerResponse response );
 
 	// passed from main server browser window instead of messages
 	void OnConnectToGame();
diff --git a/serverbrowser/HistoryGames.cpp b/serverbrowser/HistoryGames.cpp
index 565c313e..ad93e3da 100644
--- a/serverbrowser/HistoryGames.cpp
+++ b/serverbrowser/HistoryGames.cpp
@@ -18,16 +18,6 @@ CHistoryGames::CHistoryGames(vgui::Panel *parent) :
 	m_pGameList->AddColumnHeader(10, "LastPlayed", "#ServerBrowser_LastPlayed", 100);
 	m_pGameList->SetSortFunc(10, LastPlayedCompare);
 	m_pGameList->SetSortColumn(10);
-
-	if ( !IsSteamGameServerBrowsingEnabled() )
-	{
-		m_pGameList->SetEmptyListText("#ServerBrowser_OfflineMode");
-		m_pConnect->SetEnabled( false );
-		m_pRefreshAll->SetEnabled( false );
-		m_pRefreshQuick->SetEnabled( false );
-		m_pAddServer->SetEnabled( false );
-		m_pFilter->SetEnabled( false );
-	}
 }
 
 //-----------------------------------------------------------------------------
@@ -42,12 +32,6 @@ CHistoryGames::~CHistoryGames()
 //-----------------------------------------------------------------------------
 void CHistoryGames::LoadHistoryList()
 {
-	if ( IsSteamGameServerBrowsingEnabled() )
-	{
-		// set empty message
-		m_pGameList->SetEmptyListText("#ServerBrowser_NoServersPlayed");
-	}
-
 	if ( m_bRefreshOnListReload )
 	{
 		m_bRefreshOnListReload = false;
@@ -77,13 +61,13 @@ bool CHistoryGames::SupportsItem(InterfaceItem_e item)
 //-----------------------------------------------------------------------------
 // Purpose: called when the current refresh list is complete
 //-----------------------------------------------------------------------------
-void CHistoryGames::RefreshComplete( HServerListRequest hReq, EMatchMakingServerResponse response )
+void CHistoryGames::RefreshComplete( NServerResponse response )
 {
 	SetRefreshing(false);
 	m_pGameList->SetEmptyListText("#ServerBrowser_NoServersPlayed");
 	m_pGameList->SortList();
 
-	BaseClass::RefreshComplete( hReq, response );
+	BaseClass::RefreshComplete( response );
 }
 
 //-----------------------------------------------------------------------------
diff --git a/serverbrowser/HistoryGames.h b/serverbrowser/HistoryGames.h
index 6dbbf447..14af807c 100644
--- a/serverbrowser/HistoryGames.h
+++ b/serverbrowser/HistoryGames.h
@@ -30,7 +30,7 @@ public:
 	virtual bool SupportsItem(InterfaceItem_e item);
 
 	// called when the current refresh list is complete
-	virtual void RefreshComplete( HServerListRequest hReq, EMatchMakingServerResponse response );
+	virtual void RefreshComplete( NServerResponse response );
 
 	void SetRefreshOnReload() { m_bRefreshOnListReload = true; }
 
diff --git a/serverbrowser/InternetGames.cpp b/serverbrowser/InternetGames.cpp
index 208bea45..afe94f90 100644
--- a/serverbrowser/InternetGames.cpp
+++ b/serverbrowser/InternetGames.cpp
@@ -23,7 +23,7 @@ CInternetGames::CInternetGames(vgui::Panel *parent, const char *panelName, EPage
 	m_fLastSort = 0.0f;
 	m_bDirty = false;
 	m_bRequireUpdate = true;
-	m_bOfflineMode = !IsSteamGameServerBrowsingEnabled();
+	m_bOfflineMode = false; //ro!IsSteamGameServerBrowsingEnabled();
 
 	m_bAnyServersRetrievedFromMaster = false;
 	m_bNoServersListedOnMaster = false;
@@ -124,19 +124,20 @@ void CInternetGames::OnTick()
 // Purpose: Handles incoming server refresh data
 //			updates the server browser with the refreshed information from the server itself
 //-----------------------------------------------------------------------------
-void CInternetGames::ServerResponded( HServerListRequest hReq, int iServer )
+void CInternetGames::ServerResponded( newgameserver_t &server )
 {
 	m_bDirty = true;
-	BaseClass::ServerResponded( hReq, iServer );
+	Msg("InternetGames::ServerResponded hostname = %s\n", server.GetName());
+
+	BaseClass::ServerResponded( server );
 	m_bAnyServersRespondedToQuery = true;
 	m_bAnyServersRetrievedFromMaster = true;
 }
 
-
 //-----------------------------------------------------------------------------
 // Purpose: 
 //-----------------------------------------------------------------------------
-void CInternetGames::ServerFailedToRespond( HServerListRequest hReq, int iServer )
+/*void CInternetGames::ServerFailedToRespond( HServerListRequest hReq, int iServer )
 {
 	m_bDirty = true;
 	gameserveritem_t *pServer = steamapicontext->SteamMatchmakingServers()->GetServerDetails( hReq, iServer );
@@ -145,7 +146,7 @@ void CInternetGames::ServerFailedToRespond( HServerListRequest hReq, int iServer
 	if ( pServer->m_bHadSuccessfulResponse )
 	{
 		// if it's had a successful response in the past, leave it on
-		ServerResponded( hReq, iServer );
+		//ServerResponded( hReq, iServer );
 	}
 	else
 	{
@@ -155,24 +156,24 @@ void CInternetGames::ServerFailedToRespond( HServerListRequest hReq, int iServer
 		// we've never had a good response from this server, remove it from the list
 		m_iServerRefreshCount++;
 	}
-}
+}*/
 
 
 //-----------------------------------------------------------------------------
 // Purpose: Called when server refresh has been completed
 //-----------------------------------------------------------------------------
-void CInternetGames::RefreshComplete( HServerListRequest hReq, EMatchMakingServerResponse response )
+void CInternetGames::RefreshComplete( NServerResponse response )
 {
 	SetRefreshing(false);
 	UpdateFilterSettings();
 
-	if ( response != eServerFailedToRespond )
+	if ( response != nServerFailedToRespond )
 	{
 		if ( m_bAnyServersRespondedToQuery )
 		{
 			m_pGameList->SetEmptyListText( GetStringNoUnfilteredServers() );
 		}
-		else if ( response == eNoServersListedOnMasterServer )
+		else if ( response == nNoServersListedOnMasterServer )
 		{
 			m_pGameList->SetEmptyListText( GetStringNoUnfilteredServersOnMaster() );
 		}
@@ -196,7 +197,7 @@ void CInternetGames::RefreshComplete( HServerListRequest hReq, EMatchMakingServe
 
 	UpdateStatus();
 
-	BaseClass::RefreshComplete( hReq, response );
+	BaseClass::RefreshComplete( response );
 }
 
 
diff --git a/serverbrowser/InternetGames.h b/serverbrowser/InternetGames.h
index 8779d1f2..3f17d296 100644
--- a/serverbrowser/InternetGames.h
+++ b/serverbrowser/InternetGames.h
@@ -35,9 +35,9 @@ public:
 	MESSAGE_FUNC( GetNewServerList, "GetNewServerList" );
 
 	// serverlist refresh responses
-	virtual void ServerResponded( HServerListRequest hReq, int iServer );
-	virtual void ServerFailedToRespond( HServerListRequest hReq, int iServer );
-	virtual void RefreshComplete( HServerListRequest hReq, EMatchMakingServerResponse response );
+	virtual void ServerResponded( newgameserver_t &server );
+	//virtual void ServerFailedToRespond( HServerListRequest hReq, int iServer );
+	virtual void RefreshComplete( NServerResponse response );
 	MESSAGE_FUNC_INT( OnRefreshServer, "RefreshServer", serverID );
 
 	virtual int GetRegionCodeToFilter();
diff --git a/serverbrowser/LanGames.cpp b/serverbrowser/LanGames.cpp
index c375845d..131869cb 100644
--- a/serverbrowser/LanGames.cpp
+++ b/serverbrowser/LanGames.cpp
@@ -127,7 +127,7 @@ void CLanGames::ServerFailedToRespond( HServerListRequest hReq, int iServer )
 //-----------------------------------------------------------------------------
 // Purpose: called when the current refresh list is complete
 //-----------------------------------------------------------------------------
-void CLanGames::RefreshComplete( HServerListRequest hReq, EMatchMakingServerResponse response )
+void CLanGames::RefreshComplete( NServerResponse response )
 {
 	SetRefreshing( false );
 	m_pGameList->SortList();
@@ -135,7 +135,7 @@ void CLanGames::RefreshComplete( HServerListRequest hReq, EMatchMakingServerResp
 	m_pGameList->SetEmptyListText("#ServerBrowser_NoLanServers");
 	SetEmptyListText();
 
-	BaseClass::RefreshComplete( hReq, response );
+	BaseClass::RefreshComplete( response );
 }
 
 void CLanGames::SetEmptyListText()
diff --git a/serverbrowser/LanGames.h b/serverbrowser/LanGames.h
index f1e3afaa..8ff2233d 100644
--- a/serverbrowser/LanGames.h
+++ b/serverbrowser/LanGames.h
@@ -49,7 +49,7 @@ public:
 	virtual void ServerFailedToRespond( HServerListRequest hReq, int iServer );
 
 	// called when the current refresh list is complete
-	virtual void RefreshComplete( HServerListRequest hReq, EMatchMakingServerResponse response );
+	virtual void RefreshComplete( NServerResponse response );
 
 	// Tell the game list what to put in there when there are no games found.
 	virtual void SetEmptyListText();
diff --git a/serverbrowser/ServerBrowser.cpp b/serverbrowser/ServerBrowser.cpp
index ff66bbbf..20268a2f 100644
--- a/serverbrowser/ServerBrowser.cpp
+++ b/serverbrowser/ServerBrowser.cpp
@@ -19,6 +19,7 @@ CServerBrowser &ServerBrowser()
 }
 
 IRunGameEngine *g_pRunGameEngine = NULL;
+IServersInfo *g_pServersInfo = NULL;
 
 static CSteamAPIContext g_SteamAPIContext;
 CSteamAPIContext *steamapicontext = &g_SteamAPIContext;
@@ -79,11 +80,12 @@ bool CServerBrowser::Initialize(CreateInterfaceFn *factorylist, int factoryCount
 	for ( int i = 0; i < factoryCount; ++i )
 	{
 		if ( !g_pEngineReplay )
-		{
 			g_pEngineReplay = ( IEngineReplay * )factorylist[ i ]( ENGINE_REPLAY_INTERFACE_VERSION, NULL );
-		}
+		if( !g_pServersInfo )
+			g_pServersInfo = ( IServersInfo * )factorylist[ i ]( SERVERLIST_INTERFACE_VERSION, NULL );
 	}
 	
+
 	SteamAPI_InitSafe();
 	SteamAPI_SetTryCatchCallbacks( false ); // We don't use exceptions, so tell steam not to use try/catch in callback handlers
 	steamapicontext->Init();
@@ -304,7 +306,7 @@ void CServerBrowser::Shutdown()
 //-----------------------------------------------------------------------------
 bool CServerBrowser::OpenGameInfoDialog( uint64 ulSteamIDFriend, const char *pszConnectCode )
 {
-#if !defined( _X360 ) // X360TBD: SteamFriends()
+#if 0
 	if ( m_hInternetDlg.Get() )
 	{
 		// activate an already-existing dialog
@@ -337,11 +339,11 @@ bool CServerBrowser::OpenGameInfoDialog( uint64 ulSteamIDFriend, const char *psz
 //-----------------------------------------------------------------------------
 bool CServerBrowser::JoinGame( uint64 ulSteamIDFriend, const char *pszConnectCode )
 {
-	if ( OpenGameInfoDialog( ulSteamIDFriend, pszConnectCode ) )
+/*	if ( OpenGameInfoDialog( ulSteamIDFriend, pszConnectCode ) )
 	{
 		CDialogGameInfo *pDialogGameInfo = m_hInternetDlg->GetDialogGameInfoForFriend( ulSteamIDFriend );
 		pDialogGameInfo->Connect();
-	}
+	}*/
 
 	return false;
 }
@@ -362,11 +364,13 @@ bool CServerBrowser::JoinGame( uint32 unGameIP, uint16 usGamePort, const char *p
 //-----------------------------------------------------------------------------
 void CServerBrowser::CloseGameInfoDialog( uint64 ulSteamIDFriend )
 {
+#if 0
 	CDialogGameInfo *pDialogGameInfo = m_hInternetDlg->GetDialogGameInfoForFriend( ulSteamIDFriend );
 	if ( pDialogGameInfo )
 	{
 		pDialogGameInfo->Close();
 	}
+#endif
 }
 
 
diff --git a/serverbrowser/ServerBrowserDialog.cpp b/serverbrowser/ServerBrowserDialog.cpp
index dc2ca162..b3e9738b 100644
--- a/serverbrowser/ServerBrowserDialog.cpp
+++ b/serverbrowser/ServerBrowserDialog.cpp
@@ -66,20 +66,17 @@ CServerBrowserDialog::CServerBrowserDialog(vgui::Panel *parent) : Frame(parent,
 	m_pSavedData = NULL;
 	m_pFilterData = NULL;
 	m_pFavorites = NULL;
-	m_pBlacklist = NULL;
 	m_pHistory = NULL;
 
-	// Do this before LoadUserData() so it loads the blacklist file properly
-	m_pBlacklist = new CBlacklistedServers(this);
-
 	LoadUserData();
 
-	m_pInternetGames = new CCustomGames(this);
+	m_pInternetGames = new CInternetGames(this);
 	m_pFavorites = new CFavoriteGames(this);
 	m_pHistory = new CHistoryGames(this);
-	m_pSpectateGames = new CSpectateGames(this);
+
+	// TODO(nillerusr): implement spectate games without steam
+	//m_pSpectateGames = new CSpectateGames(this);
 	m_pLanGames = new CLanGames(this);
-	m_pFriendsGames = new CFriendsGames(this);
 
 	SetMinimumSize( 640, 384 );
 	SetSize( 640, 384 );
@@ -94,13 +91,9 @@ CServerBrowserDialog::CServerBrowserDialog(vgui::Panel *parent) : Frame(parent,
 	m_pTabPanel->AddPage(m_pInternetGames, "#ServerBrowser_InternetTab");
 	m_pTabPanel->AddPage(m_pFavorites, "#ServerBrowser_FavoritesTab");
 	m_pTabPanel->AddPage(m_pHistory, "#ServerBrowser_HistoryTab");
-	m_pTabPanel->AddPage(m_pSpectateGames, "#ServerBrowser_SpectateTab");
+	//m_pTabPanel->AddPage(m_pSpectateGames, "#ServerBrowser_SpectateTab");
 	m_pTabPanel->AddPage(m_pLanGames, "#ServerBrowser_LanTab");
-	m_pTabPanel->AddPage(m_pFriendsGames, "#ServerBrowser_FriendsTab");
-	if ( m_pBlacklist )
-	{
-		m_pTabPanel->AddPage(m_pBlacklist, "#ServerBrowser_BlacklistTab");
-	}
+
 	m_pTabPanel->AddActionSignalTarget(this);
 
 	m_pStatusLabel = new Label(this, "StatusLabel", "");
@@ -112,11 +105,12 @@ CServerBrowserDialog::CServerBrowserDialog(vgui::Panel *parent) : Frame(parent,
 	// load current tab
 	const char *gameList = m_pSavedData->GetString("GameList");
 
-	if (!Q_stricmp(gameList, "spectate"))
+/*	if (!Q_stricmp(gameList, "spectate"))
 	{
 		m_pTabPanel->SetActivePage(m_pSpectateGames);
 	}
-	else if (!Q_stricmp(gameList, "favorites"))
+	else */
+	if (!Q_stricmp(gameList, "favorites"))
 	{
 		m_pTabPanel->SetActivePage(m_pFavorites);
 	}
@@ -128,14 +122,6 @@ CServerBrowserDialog::CServerBrowserDialog(vgui::Panel *parent) : Frame(parent,
 	{
 		m_pTabPanel->SetActivePage(m_pLanGames);
 	}
-	else if (!Q_stricmp(gameList, "friends"))
-	{
-		m_pTabPanel->SetActivePage(m_pFriendsGames);
-	}
-	else if (!Q_stricmp(gameList, "blacklist"))
-	{
-		m_pTabPanel->SetActivePage(m_pBlacklist);
-	}
 	else
 	{
 		m_pTabPanel->SetActivePage(m_pInternetGames);
@@ -254,11 +240,6 @@ void CServerBrowserDialog::LoadUserData()
 			m_pFavorites->StartRefresh();
 	}
 
-	if ( m_pBlacklist )
-	{
-		m_pBlacklist->LoadBlacklistedList();
-	}
-
 	InvalidateLayout();
 	Repaint();
 }
@@ -272,11 +253,12 @@ void CServerBrowserDialog::SaveUserData()
 	m_pSavedData->LoadFromFile( g_pFullFileSystem, "ServerBrowser.vdf", "CONFIG");
 
 	// set the current tab
-	if (m_pGameList == m_pSpectateGames)
+	/*if (m_pGameList == m_pSpectateGames)
 	{
 		m_pSavedData->SetString("GameList", "spectate");
 	}
-	else if (m_pGameList == m_pFavorites)
+	else */
+	if (m_pGameList == m_pFavorites)
 	{
 		m_pSavedData->SetString("GameList", "favorites");
 	}
@@ -284,10 +266,6 @@ void CServerBrowserDialog::SaveUserData()
 	{
 		m_pSavedData->SetString("GameList", "lan");
 	}
-	else if (m_pGameList == m_pFriendsGames)
-	{
-		m_pSavedData->SetString("GameList", "friends");
-	}
 	else if (m_pGameList == m_pHistory)
 	{
 		m_pSavedData->SetString("GameList", "history");
@@ -301,11 +279,6 @@ void CServerBrowserDialog::SaveUserData()
 	m_pSavedData->AddSubKey( m_pFilterData->MakeCopy() );
 	m_pSavedData->SaveToFile( g_pFullFileSystem, "ServerBrowser.vdf", "CONFIG");
 
-	if ( m_pBlacklist )
-	{
-		m_pBlacklist->SaveBlacklistedList();
-	}
-
 	// save per-page config
 	SaveUserConfig();
 }
@@ -321,14 +294,6 @@ void CServerBrowserDialog::RefreshCurrentPage()
 	}
 }
 
-//-----------------------------------------------------------------------------
-// Purpose: 
-//-----------------------------------------------------------------------------
-void CServerBrowserDialog::BlacklistsChanged()
-{
-	m_pInternetGames->ApplyGameFilters();
-}
-
 //-----------------------------------------------------------------------------
 // Purpose: Updates status test at bottom of window
 //-----------------------------------------------------------------------------
@@ -409,38 +374,9 @@ void CServerBrowserDialog::AddServerToFavorites(gameserveritem_t &server)
 			server.m_NetAdr.GetQueryPort(), 
 			k_unFavoriteFlagFavorite, 
 			time( NULL ) );
-
-		if ( GameSupportsReplay() )
-		{
-			// send command to propagate to the client so the client can send it on to the GC
-			char command[ 256 ];
-			Q_snprintf( command, Q_ARRAYSIZE( command ), "rfgc %s\n", server.m_NetAdr.GetConnectionAddressString() );
-			g_pRunGameEngine->AddTextCommand( command );
-		}
 	}
 }
 
-//-----------------------------------------------------------------------------
-// Purpose: Adds a server to our list of blacklisted servers
-//-----------------------------------------------------------------------------
-void CServerBrowserDialog::AddServerToBlacklist(gameserveritem_t &server)
-{
-	if ( m_pBlacklist )
-	{
-		m_pBlacklist->AddServer( server );
-	}
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: 
-//-----------------------------------------------------------------------------
-bool CServerBrowserDialog::IsServerBlacklisted(gameserveritem_t &server)
-{
-	if ( m_pBlacklist )
-		return m_pBlacklist->IsServerBlacklisted( server );
-	return false;
-}
-
 //-----------------------------------------------------------------------------
 // Purpose: 
 //-----------------------------------------------------------------------------
@@ -469,10 +405,10 @@ CServerContextMenu *CServerBrowserDialog::GetContextMenu(vgui::Panel *pPanel)
 // Purpose: begins the process of joining a server from a game list
 //			the game info dialog it opens will also update the game list
 //-----------------------------------------------------------------------------
-CDialogGameInfo *CServerBrowserDialog::JoinGame(IGameList *gameList, unsigned int serverIndex)
+CDialogGameInfo *CServerBrowserDialog::JoinGame(IGameList *gameList, newgameserver_t *pServer)
 {
 	// open the game info dialog, then mark it to attempt to connect right away
-	CDialogGameInfo *gameDialog = OpenGameInfoDialog(gameList, serverIndex);
+	CDialogGameInfo *gameDialog = OpenGameInfoDialog(gameList, pServer);
 
 	// set the dialog name to be the server name
 	gameDialog->Connect();
@@ -497,16 +433,12 @@ CDialogGameInfo *CServerBrowserDialog::JoinGame(int serverIP, int serverPort, co
 //-----------------------------------------------------------------------------
 // Purpose: opens a game info dialog from a game list
 //-----------------------------------------------------------------------------
-CDialogGameInfo *CServerBrowserDialog::OpenGameInfoDialog( IGameList *gameList, unsigned int serverIndex )
+CDialogGameInfo *CServerBrowserDialog::OpenGameInfoDialog( IGameList *gameList, newgameserver_t *pServer )
 {
-	gameserveritem_t *pServer = gameList->GetServer( serverIndex );
-	if ( !pServer )
-		return NULL;
-
-	CDialogGameInfo *gameDialog = new CDialogGameInfo( NULL, pServer->m_NetAdr.GetIP(), pServer->m_NetAdr.GetQueryPort(), pServer->m_NetAdr.GetConnectionPort(), gameList->GetConnectCode() );
+	CDialogGameInfo *gameDialog = new CDialogGameInfo( NULL, pServer->m_NetAdr.GetIPHostByteOrder(), 0, pServer->m_NetAdr.GetPort(), gameList->GetConnectCode() );
 	gameDialog->SetParent(GetVParent());
 	gameDialog->AddActionSignalTarget(this);
-	gameDialog->Run( pServer->GetName() );
+	gameDialog->Run( "Test" /*pServer->GetName()*/ );
 	int i = m_GameInfoDialogs.AddToTail();
 	m_GameInfoDialogs[i] = gameDialog;
 	return gameDialog;
@@ -541,23 +473,6 @@ void CServerBrowserDialog::CloseAllGameInfoDialogs()
 	}
 }
 
-
-//-----------------------------------------------------------------------------
-// Purpose: finds a dialog
-//-----------------------------------------------------------------------------
-CDialogGameInfo *CServerBrowserDialog::GetDialogGameInfoForFriend( uint64 ulSteamIDFriend )
-{
-	FOR_EACH_VEC( m_GameInfoDialogs, i )
-	{
-		CDialogGameInfo *pDlg = m_GameInfoDialogs[i];
-		if ( pDlg && pDlg->GetAssociatedFriend() == ulSteamIDFriend )
-		{
-			return pDlg;
-		}
-	}
-	return NULL;
-}
-
 //-----------------------------------------------------------------------------
 // Purpose: accessor to the filter save data
 //-----------------------------------------------------------------------------
@@ -612,10 +527,9 @@ void CServerBrowserDialog::OnActiveGameName( KeyValues *pKV )
 void CServerBrowserDialog::ReloadFilterSettings()
 {
 	m_pInternetGames->LoadFilterSettings();
-	m_pSpectateGames->LoadFilterSettings();
+	//m_pSpectateGames->LoadFilterSettings();
 	m_pFavorites->LoadFilterSettings();
 	m_pLanGames->LoadFilterSettings();
-	m_pFriendsGames->LoadFilterSettings();
 	m_pHistory->LoadFilterSettings();
 }
 
@@ -659,27 +573,19 @@ void CServerBrowserDialog::OnConnectToGame( KeyValues *pMessageValues )
 
 	// forward to favorites
 	m_pFavorites->OnConnectToGame();
-	if ( m_pBlacklist )
-	{
-		m_pBlacklist->OnConnectToGame();
-	}
 
 	m_bCurrentlyConnected = true;
 
 	// Now we want to track which tabs have the quick list button checked
 	int iQuickListBitField = 0;
-	if ( m_pFriendsGames && m_pFriendsGames->IsQuickListButtonChecked() )
-	{
-		iQuickListBitField |= ( 1 << 0 );
-	}
 	if ( m_pLanGames && m_pLanGames->IsQuickListButtonChecked() )
 	{
 		iQuickListBitField |= ( 1 << 1 );
 	}
-	if ( m_pSpectateGames && m_pSpectateGames->IsQuickListButtonChecked() )
+/*	if ( m_pSpectateGames && m_pSpectateGames->IsQuickListButtonChecked() )
 	{
 		iQuickListBitField |= ( 1 << 2 );
-	}
+	}*/
 	if ( m_pHistory && m_pHistory->IsQuickListButtonChecked() )
 	{
 		iQuickListBitField |= ( 1 << 3 );
@@ -720,10 +626,6 @@ void CServerBrowserDialog::OnDisconnectFromGame( void )
 
 	// forward to favorites
 	m_pFavorites->OnDisconnectFromGame();
-	if ( m_pBlacklist )
-	{
-		m_pBlacklist->OnDisconnectFromGame();
-	}
 }
 
 //-----------------------------------------------------------------------------
@@ -732,10 +634,9 @@ void CServerBrowserDialog::OnDisconnectFromGame( void )
 void CServerBrowserDialog::OnLoadingStarted( void )
 {
 	m_pInternetGames->OnLoadingStarted();
-	m_pSpectateGames->OnLoadingStarted();
+//	m_pSpectateGames->OnLoadingStarted();
 	m_pFavorites->OnLoadingStarted();
 	m_pLanGames->OnLoadingStarted();
-	m_pFriendsGames->OnLoadingStarted();
 	m_pHistory->OnLoadingStarted();
 }
 
diff --git a/serverbrowser/ServerBrowserDialog.h b/serverbrowser/ServerBrowserDialog.h
index 2b251867..8180a9f1 100644
--- a/serverbrowser/ServerBrowserDialog.h
+++ b/serverbrowser/ServerBrowserDialog.h
@@ -50,26 +50,22 @@ public:
 
 	// Adds a server to the list of favorites
 	void AddServerToFavorites(gameserveritem_t &server);
-	// Adds a server to our list of blacklisted servers
-	void AddServerToBlacklist(gameserveritem_t &server);
-	bool IsServerBlacklisted(gameserveritem_t &server); 
 
 	// begins the process of joining a server from a game list
 	// the game info dialog it opens will also update the game list
-	CDialogGameInfo *JoinGame(IGameList *gameList, unsigned int serverIndex);
+	CDialogGameInfo *JoinGame(IGameList *gameList, newgameserver_t *pServer);
 
 	// joins a game by a specified IP, not attached to any game list
 	CDialogGameInfo *JoinGame(int serverIP, int serverPort, const char *pszConnectCode);
 
 	// opens a game info dialog from a game list
-	CDialogGameInfo *OpenGameInfoDialog(IGameList *gameList, unsigned int serverIndex);
+	CDialogGameInfo *OpenGameInfoDialog(IGameList *gameList, newgameserver_t *pServer);
 
 	// opens a game info dialog by a specified IP, not attached to any game list
 	CDialogGameInfo *OpenGameInfoDialog( int serverIP, uint16 connPort, uint16 queryPort, const char *pszConnectCode );
 
 	// closes all the game info dialogs
 	void CloseAllGameInfoDialogs();
-	CDialogGameInfo *GetDialogGameInfoForFriend( uint64 ulSteamIDFriend );
 
 	// accessor to the filter save data
 	KeyValues *GetFilterSaveData(const char *filterSet);
@@ -91,9 +87,6 @@ public:
 		return &m_CurrentConnection;
 	}
 
-	void		BlacklistsChanged();
-	CBlacklistedServers *GetBlacklistPage( void ) { return m_pBlacklist; }
-
 private:
 
 	// current game list change
@@ -126,12 +119,10 @@ private:
 	// property sheet
 	vgui::PropertySheet *m_pTabPanel;
 	CFavoriteGames *m_pFavorites;
-	CBlacklistedServers *m_pBlacklist;
 	CHistoryGames *m_pHistory;
 	CInternetGames *m_pInternetGames;
-	CSpectateGames *m_pSpectateGames;
+	//CSpectateGames *m_pSpectateGames;
 	CLanGames *m_pLanGames;
-	CFriendsGames *m_pFriendsGames;
 
 	KeyValues *m_pSavedData;
 	KeyValues *m_pFilterData;
diff --git a/serverbrowser/pch_serverbrowser.h b/serverbrowser/pch_serverbrowser.h
index 575382e4..8e44f2ba 100644
--- a/serverbrowser/pch_serverbrowser.h
+++ b/serverbrowser/pch_serverbrowser.h
@@ -57,15 +57,11 @@
 
 // game list
 #include "BaseGamesPage.h"
-#include "BlacklistedServers.h"
 #include "InternetGames.h"
 #include "FavoriteGames.h"
-#include "SpectateGames.h"
+//#include "SpectateGames.h"
 #include "LanGames.h"
-#include "FriendsGames.h"
 #include "HistoryGames.h"
-#include "SpectateGames.h"
-#include "CustomGames.h"
 #include "ServerBrowserDialog.h"
 #include "QuickListPanel.h"
 #include "vgui_controls/PanelListPanel.h"
diff --git a/serverbrowser/BlacklistedServers.cpp b/serverbrowser/unused/BlacklistedServers.cpp
similarity index 100%
rename from serverbrowser/BlacklistedServers.cpp
rename to serverbrowser/unused/BlacklistedServers.cpp
diff --git a/serverbrowser/BlacklistedServers.h b/serverbrowser/unused/BlacklistedServers.h
similarity index 100%
rename from serverbrowser/BlacklistedServers.h
rename to serverbrowser/unused/BlacklistedServers.h
diff --git a/serverbrowser/CustomGames.cpp b/serverbrowser/unused/CustomGames.cpp
similarity index 100%
rename from serverbrowser/CustomGames.cpp
rename to serverbrowser/unused/CustomGames.cpp
diff --git a/serverbrowser/CustomGames.h b/serverbrowser/unused/CustomGames.h
similarity index 100%
rename from serverbrowser/CustomGames.h
rename to serverbrowser/unused/CustomGames.h
diff --git a/serverbrowser/FriendsGames.cpp b/serverbrowser/unused/FriendsGames.cpp
similarity index 100%
rename from serverbrowser/FriendsGames.cpp
rename to serverbrowser/unused/FriendsGames.cpp
diff --git a/serverbrowser/FriendsGames.h b/serverbrowser/unused/FriendsGames.h
similarity index 100%
rename from serverbrowser/FriendsGames.h
rename to serverbrowser/unused/FriendsGames.h
diff --git a/serverbrowser/SpectateGames.cpp b/serverbrowser/unused/SpectateGames.cpp
similarity index 100%
rename from serverbrowser/SpectateGames.cpp
rename to serverbrowser/unused/SpectateGames.cpp
diff --git a/serverbrowser/SpectateGames.h b/serverbrowser/unused/SpectateGames.h
similarity index 100%
rename from serverbrowser/SpectateGames.h
rename to serverbrowser/unused/SpectateGames.h
diff --git a/serverbrowser/wscript b/serverbrowser/wscript
index 755ae062..abeb6297 100755
--- a/serverbrowser/wscript
+++ b/serverbrowser/wscript
@@ -21,13 +21,13 @@ def configure(conf):
 def build(bld):
 	source = [
 		'BaseGamesPage.cpp',
-		'BlacklistedServers.cpp',
-		'CustomGames.cpp',
+#		'BlacklistedServers.cpp',
+#		'CustomGames.cpp',
 		'DialogAddServer.cpp',
 		'DialogGameInfo.cpp',
 		'DialogServerPassword.cpp',
 		'FavoriteGames.cpp',
-		'FriendsGames.cpp',
+#		'FriendsGames.cpp',
 		'HistoryGames.cpp',
 		'InternetGames.cpp',
 		'LanGames.cpp',
@@ -36,7 +36,7 @@ def build(bld):
 		'ServerBrowserDialog.cpp',
 		'ServerContextMenu.cpp',
 		'ServerListCompare.cpp',
-		'SpectateGames.cpp',
+#		'SpectateGames.cpp',
 		'VACBannedConnRefusedDialog.cpp',
 		'QuickListPanel.cpp',
 		'../public/vgui_controls/vgui_controls.cpp',

From c4b93b30d7baa4747fa2f2e84c6967a3070d9d28 Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Sun, 29 Jan 2023 20:57:04 +0300
Subject: [PATCH 04/17] WIP(serverbrowser): update IServersInfo interface

---
 public/engine/iserversinfo.h | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/public/engine/iserversinfo.h b/public/engine/iserversinfo.h
index 663feb75..8e80d0c4 100644
--- a/public/engine/iserversinfo.h
+++ b/public/engine/iserversinfo.h
@@ -13,11 +13,11 @@
 #define MAX_GAME_DESCRIPTION 8192
 #define MAX_SERVER_NAME 2048
 
-enum ServerResponse
+enum NServerResponse
 {
-	ServerResponded = 0,
-	ServerFailedToRespond,
-	NoServersListedOnMasterServer,
+	nServerResponded = 0,
+	nServerFailedToRespond,
+	nNoServersListedOnMasterServer,
 };
 
 class newgameserver_t
@@ -25,8 +25,11 @@ class newgameserver_t
 public:
 	newgameserver_t() = default;
 
-	const char* GetName() const;
-	void SetName( const char *pName );
+	const char* GetName() const { return m_szServerName; }
+	void SetName( const char *pName )
+	{
+		strncpy( m_szServerName, pName, sizeof(m_szServerName) );
+	}
 
 	netadr_t m_NetAdr;								///< IP/Query Port/Connection Port for this server
 	int m_nPing;											///< current ping time in milliseconds
@@ -50,6 +53,7 @@ class IServerListResponse
 public:
 	// Server has responded ok with updated data
 	virtual void ServerResponded( newgameserver_t &server ) = 0;
+	virtual void RefreshComplete( NServerResponse response ) = 0;
 };
 
 //-----------------------------------------------------------------------------
@@ -94,4 +98,6 @@ public:
 };
 #define SERVERLIST_INTERFACE_VERSION "ServerList001"
 
+extern IServersInfo *g_pServersInfo;
+
 #endif // ISERVERSINFO_H

From 64f7bf9f96070ee91ffd9ac7fbfb1b270d2b655e Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Sun, 29 Jan 2023 21:48:36 +0300
Subject: [PATCH 05/17] vgui_controls: fix SetParent function

---
 serverbrowser/BaseGamesPage.cpp | 2 +-
 vgui2/vgui_controls/Panel.cpp   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/serverbrowser/BaseGamesPage.cpp b/serverbrowser/BaseGamesPage.cpp
index e0f80b63..6bdba32f 100644
--- a/serverbrowser/BaseGamesPage.cpp
+++ b/serverbrowser/BaseGamesPage.cpp
@@ -2205,7 +2205,7 @@ void CBaseGamesPage::ServerResponded( newgameserver_t &server )
 {
 	Msg("Serverbrowser: hostname %s\n", server.GetName());
 
-	Assert( server.m_NetAdr.GetIP() != 0 );
+	Assert( server.m_NetAdr.GetIPHostByteOrder() != 0 );
 
 	newgameserver_t *pServerItem = &server;
 
diff --git a/vgui2/vgui_controls/Panel.cpp b/vgui2/vgui_controls/Panel.cpp
index 3adbf7ed..ec2c5653 100644
--- a/vgui2/vgui_controls/Panel.cpp
+++ b/vgui2/vgui_controls/Panel.cpp
@@ -1465,7 +1465,7 @@ void Panel::SetParent(VPANEL newParent)
 		if( ipanel()->IsProportional(GetVParent()) )
 			SetProportional(true);
 
-		if( IsPopup() )
+		if( !IsPopup() )
 		{
 			// most of the time KBInput == parents kbinput
 			if (ipanel()->IsKeyBoardInputEnabled(GetVParent()) != IsKeyBoardInputEnabled())

From a08b6ae7bf12093ce7cb5fe0b94b02f99cf29cb5 Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Mon, 30 Jan 2023 22:16:48 +0300
Subject: [PATCH 06/17] engine: update server info reply

---
 engine/masterserver.cpp         | 101 ++++++++++++++++++++++++++++----
 public/engine/iserversinfo.h    |  12 ++--
 serverbrowser/BaseGamesPage.cpp |  13 +---
 serverbrowser/InternetGames.cpp |   1 -
 4 files changed, 95 insertions(+), 32 deletions(-)

diff --git a/engine/masterserver.cpp b/engine/masterserver.cpp
index f3803d45..43262e73 100644
--- a/engine/masterserver.cpp
+++ b/engine/masterserver.cpp
@@ -16,9 +16,14 @@
 #include "master.h"
 #include "proto_oob.h"
 #include "host.h"
+#include "eiface.h"
+#include "server.h"
 
+extern ConVar sv_tags;
 extern ConVar sv_lan;
 
+#define S2A_EXTRA_DATA_HAS_GAMETAG_DATA                         0x01            // Next bytes are the game tag string
+
 //-----------------------------------------------------------------------------
 // Purpose: List of master servers and some state info about them
 //-----------------------------------------------------------------------------
@@ -65,6 +70,8 @@ public:
 
 	void RunFrame();
 	void RequestServersInfo();
+	void ReplyInfo( const netadr_t &adr );
+	newgameserver_t &ProcessInfo( bf_read &buf );
 
 	// SeversInfo
 	void RequestInternetServerList( const char *gamedir, IServerListResponse *response );
@@ -116,6 +123,79 @@ void CMaster::RunFrame()
 	CheckHeartbeat();
 }
 
+void CMaster::ReplyInfo( const netadr_t &adr )
+{
+	static char gamedir[MAX_OSPATH];
+	Q_FileBase( com_gamedir, gamedir, sizeof( gamedir ) );
+
+	CUtlBuffer buf;
+	buf.EnsureCapacity( 2048 );
+
+	buf.PutUnsignedInt( LittleDWord( CONNECTIONLESS_HEADER ) );
+	buf.PutUnsignedChar( S2C_INFOREPLY );
+
+	buf.PutUnsignedChar( PROTOCOL_VERSION ); // Hardcoded protocol version number
+	buf.PutString( sv.GetName() );
+	buf.PutString( sv.GetMapName() );
+	buf.PutString( gamedir );
+	buf.PutString( serverGameDLL->GetGameDescription() );
+
+	// player info
+	buf.PutUnsignedChar( sv.GetNumClients() );
+	buf.PutUnsignedChar( sv.GetMaxClients() );
+	buf.PutUnsignedChar( sv.GetNumFakeClients() );
+
+	// Password?
+	buf.PutUnsignedChar( sv.GetPassword() != NULL ? 1 : 0 );
+
+	// Write a byte with some flags that describe what is to follow.
+	const char *pchTags = sv_tags.GetString();
+	int nFlags = 0;
+
+	if ( pchTags && pchTags[0] != '\0' )
+		nFlags |= S2A_EXTRA_DATA_HAS_GAMETAG_DATA;
+
+	buf.PutUnsignedInt( nFlags );
+
+	if ( nFlags & S2A_EXTRA_DATA_HAS_GAMETAG_DATA )
+	{
+		buf.PutString( pchTags );
+	}
+
+	NET_SendPacket( NULL, NS_SERVER, adr, (unsigned char *)buf.Base(), buf.TellPut() );
+}
+
+newgameserver_t &CMaster::ProcessInfo(bf_read &buf)
+{
+	static newgameserver_t s;
+	memset( &s, 0, sizeof(s) );
+
+	s.m_nProtocolVersion = buf.ReadByte();
+
+	buf.ReadString( s.m_szServerName, sizeof(s.m_szServerName) );
+	buf.ReadString( s.m_szMap, sizeof(s.m_szMap) );
+	buf.ReadString( s.m_szGameDir, sizeof(s.m_szGameDir) );
+
+	buf.ReadString( s.m_szGameDescription, sizeof(s.m_szGameDescription) );
+
+	// player info
+	s.m_nPlayers = buf.ReadByte();
+	s.m_nMaxPlayers = buf.ReadByte();
+	s.m_nBotPlayers = buf.ReadByte();
+
+	// Password?
+	s.m_bPassword = buf.ReadByte();
+
+	s.m_iFlags = buf.ReadLong();
+
+	if( s.m_iFlags & S2A_EXTRA_DATA_HAS_GAMETAG_DATA )
+	{
+		buf.ReadString( s.m_szGameTags, sizeof(s.m_szGameTags) );
+	}
+
+	return s;
+}
+
 void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 {
 	static ALIGN4 char string[2048] ALIGN4_POST;    // Buffer for sending heartbeat
@@ -158,27 +238,24 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 		}
 		case C2S_INFOREQUEST:
 		{
-			bf_write p(string, sizeof(string));
-			p.WriteLong(CONNECTIONLESS_HEADER);
-			p.WriteByte(S2C_INFOREPLY);
-			p.WriteString(sv.GetName());
-
-			NET_SendPacket(NULL, NS_SERVER, packet->from, p.GetData(), p.GetNumBytesWritten());
-
+			ReplyInfo(packet->from);
 			break;
 		}
 		case S2C_INFOREPLY:
 		{
-			char hostname[1024];
-			msg.ReadString(hostname, sizeof(hostname));
+			newgameserver_t &s = ProcessInfo( msg );
+			Msg("hostname = %s\nplayers: %d/%d\nbots: %d\n", s.m_szServerName, s.m_nPlayers, s.m_nMaxPlayers, s.m_nBotPlayers);
 
-			newgameserver_t s;
 			s.m_NetAdr = packet->from;
-			s.SetName( hostname );
-
 			m_serverListResponse->ServerResponded( s );
 			break;
 		}
+		case A2A_PING:
+		{
+			const char p = A2A_ACK;
+			NET_SendPacket( NULL, NS_SERVER, packet->from, (unsigned char*)&p, 1);
+			break;
+		}
 	}
 }
 
diff --git a/public/engine/iserversinfo.h b/public/engine/iserversinfo.h
index 8e80d0c4..e2fd07de 100644
--- a/public/engine/iserversinfo.h
+++ b/public/engine/iserversinfo.h
@@ -25,25 +25,23 @@ class newgameserver_t
 public:
 	newgameserver_t() = default;
 
-	const char* GetName() const { return m_szServerName; }
-	void SetName( const char *pName )
-	{
-		strncpy( m_szServerName, pName, sizeof(m_szServerName) );
-	}
-
 	netadr_t m_NetAdr;								///< IP/Query Port/Connection Port for this server
 	int m_nPing;											///< current ping time in milliseconds
+	int m_nProtocolVersion;
 	bool m_bHadSuccessfulResponse;	///< server has responded successfully in the past
 	bool m_bDoNotRefresh;						///< server is marked as not responding and should no longer be refreshed
 	char m_szGameDir[MAX_PATH];				 ///< current game directory
 	char m_szMap[MAX_PATH];					///< current map
+	char m_szGameTags[MAX_PATH];
 	char m_szGameDescription[MAX_GAME_DESCRIPTION]; ///< game description
 
 	int m_nPlayers;
 	int m_nMaxPlayers;										///< Maximum players that can join this server
 	int m_nBotPlayers;										///< Number of bots (i.e simulated players) on this server
 	bool m_bPassword;										///< true if this server needs a password to join
-private:
+
+	int m_iFlags;
+
 	/// Game server name
 	char m_szServerName[MAX_SERVER_NAME];
 };
diff --git a/serverbrowser/BaseGamesPage.cpp b/serverbrowser/BaseGamesPage.cpp
index 6bdba32f..5f76f78d 100644
--- a/serverbrowser/BaseGamesPage.cpp
+++ b/serverbrowser/BaseGamesPage.cpp
@@ -2203,8 +2203,6 @@ const char *CBaseGamesPage::GetConnectCode()
 
 void CBaseGamesPage::ServerResponded( newgameserver_t &server )
 {
-	Msg("Serverbrowser: hostname %s\n", server.GetName());
-
 	Assert( server.m_NetAdr.GetIPHostByteOrder() != 0 );
 
 	newgameserver_t *pServerItem = &server;
@@ -2232,7 +2230,7 @@ void CBaseGamesPage::ServerResponded( newgameserver_t &server )
 	// new entry
 	KeyValues *kv = new KeyValues("Server");
 
-	kv->SetString("name", pServerItem->GetName());
+	kv->SetString("name", pServerItem->m_szServerName);
 	kv->SetString("map", pServerItem->m_szMap);
 	kv->SetString("GameDir", pServerItem->m_szGameDir);
 	kv->SetString("GameDesc", pServerItem->m_szGameDescription);
@@ -2278,15 +2276,6 @@ void CBaseGamesPage::ServerResponded( newgameserver_t &server )
 		}
 	}*/
 
-//	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", "");
-	}
-
 	int iServerIndex = m_serversInfo.AddToTail( server );
 
 	//if ( !m_pGameList->IsValidItemID( pServer->m_iListID ) )
diff --git a/serverbrowser/InternetGames.cpp b/serverbrowser/InternetGames.cpp
index afe94f90..2e77e0ab 100644
--- a/serverbrowser/InternetGames.cpp
+++ b/serverbrowser/InternetGames.cpp
@@ -127,7 +127,6 @@ void CInternetGames::OnTick()
 void CInternetGames::ServerResponded( newgameserver_t &server )
 {
 	m_bDirty = true;
-	Msg("InternetGames::ServerResponded hostname = %s\n", server.GetName());
 
 	BaseClass::ServerResponded( server );
 	m_bAnyServersRespondedToQuery = true;

From 12716fd07f089fc25b4da5eb3be24c9f9a067365 Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Fri, 10 Feb 2023 22:45:36 +0300
Subject: [PATCH 07/17] engine(masterserver): Add sequence for requesting
 server info, implement StopRefresh and use it on timeout

---
 engine/masterserver.cpp      | 104 +++++++++++++++++++++++++++++------
 public/engine/iserversinfo.h |   1 +
 public/tier0/threadtools.h   |  44 ++-------------
 public/tier1/memhelpers.h    |  16 ++++--
 tier0/threadtools.cpp        |  53 ++++++++++++++++++
 vstdlib/jobthread.cpp        |  20 +++++--
 6 files changed, 171 insertions(+), 67 deletions(-)

diff --git a/engine/masterserver.cpp b/engine/masterserver.cpp
index 43262e73..e7580773 100644
--- a/engine/masterserver.cpp
+++ b/engine/masterserver.cpp
@@ -18,11 +18,14 @@
 #include "host.h"
 #include "eiface.h"
 #include "server.h"
+#include "utlmap.h"
 
 extern ConVar sv_tags;
 extern ConVar sv_lan;
 
 #define S2A_EXTRA_DATA_HAS_GAMETAG_DATA                         0x01            // Next bytes are the game tag string
+#define RETRY_INFO_REQUEST_TIME 0.4 // seconds
+#define INFO_REQUEST_TIMEOUT 5.0 // seconds
 
 //-----------------------------------------------------------------------------
 // Purpose: List of master servers and some state info about them
@@ -62,6 +65,7 @@ public:
 	void UseDefault ( void );
 	void CheckHeartbeat (void);
 	void RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg );
+	void PingServer( netadr_t &svadr );
 
 	void ProcessConnectionlessPacket( netpacket_t *packet );
 
@@ -70,23 +74,35 @@ public:
 
 	void RunFrame();
 	void RequestServersInfo();
-	void ReplyInfo( const netadr_t &adr );
+
+	void ReplyInfo( const netadr_t &adr, uint sequence );
 	newgameserver_t &ProcessInfo( bf_read &buf );
 
 	// SeversInfo
 	void RequestInternetServerList( const char *gamedir, IServerListResponse *response );
 	void RequestLANServerList( const char *gamedir, IServerListResponse *response );
 	void AddServerAddresses( netadr_t **adr, int count );
+	void StopRefresh();
+
 private:
 	// List of known master servers
 	adrlist_t *m_pMasterAddresses;
 
 	bool m_bInitialized;
+	bool m_bWaitingForReplys;
+
+	int m_iServersResponded;
+
+	double m_flStartRequestTime;
+	double m_flRetryRequestTime;
+
+	uint m_iInfoSequence;
 
 	// If nomaster is true, the server will not send heartbeats to the master server
 	bool	m_bNoMasters;
 
-	CUtlLinkedList<netadr_t> m_serverAddresses;
+	CUtlMap<netadr_t, bool> m_serverAddresses;
+	CUtlMap<uint, double> m_serversRequestTime;
 
 	IServerListResponse *m_serverListResponse;
 };
@@ -108,8 +124,13 @@ CMaster::CMaster( void )
 	m_pMasterAddresses	= NULL;
 	m_bNoMasters		= false;
 	m_bInitialized = false;
+	m_iServersResponded = 0;
 
 	m_serverListResponse = NULL;
+	SetDefLessFunc( m_serverAddresses );
+	SetDefLessFunc( m_serversRequestTime );
+	m_bWaitingForReplys = false;
+	m_iInfoSequence = 0;
 
 	Init();
 }
@@ -121,9 +142,34 @@ CMaster::~CMaster( void )
 void CMaster::RunFrame()
 {
 	CheckHeartbeat();
+
+	if( !m_bWaitingForReplys )
+		return;
+
+	if( m_serverListResponse &&
+		m_flStartRequestTime < Plat_FloatTime()-INFO_REQUEST_TIMEOUT   )
+	{
+		m_serverListResponse->RefreshComplete( NServerResponse::nServerFailedToRespond );
+		m_bWaitingForReplys = false;
+	}
+
+	if( m_flRetryRequestTime < Plat_FloatTime() - RETRY_INFO_REQUEST_TIME )
+	{
+		m_flRetryRequestTime = Plat_FloatTime();
+
+		if( m_iServersResponded < m_serverAddresses.Count() )
+			RequestServersInfo();
+	}
 }
 
-void CMaster::ReplyInfo( const netadr_t &adr )
+void CMaster::StopRefresh()
+{
+	m_bWaitingForReplys = false;
+	m_serverAddresses.RemoveAll();
+	m_serversRequestTime.RemoveAll();
+}
+
+void CMaster::ReplyInfo( const netadr_t &adr, uint sequence )
 {
 	static char gamedir[MAX_OSPATH];
 	Q_FileBase( com_gamedir, gamedir, sizeof( gamedir ) );
@@ -134,6 +180,7 @@ void CMaster::ReplyInfo( const netadr_t &adr )
 	buf.PutUnsignedInt( LittleDWord( CONNECTIONLESS_HEADER ) );
 	buf.PutUnsignedChar( S2C_INFOREPLY );
 
+	buf.PutUnsignedInt(sequence);
 	buf.PutUnsignedChar( PROTOCOL_VERSION ); // Hardcoded protocol version number
 	buf.PutString( sv.GetName() );
 	buf.PutString( sv.GetMapName() );
@@ -217,8 +264,7 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 		}
 		case M2C_QUERY:
 		{
-			if( m_serverAddresses.Count() > 0 )
-				m_serverAddresses.RemoveAll();
+			m_serverAddresses.RemoveAll();
 
 			ip = msg.ReadLong();
 			port = msg.ReadShort();
@@ -227,33 +273,48 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 			{
 				netadr_t adr(ip, port);
 
-				m_serverAddresses.AddToHead(adr);
+				m_serverAddresses.Insert(adr, false);
 
 				ip = msg.ReadLong();
 				port = msg.ReadShort();
 			}
 
+			m_iServersResponded = 0;
 			RequestServersInfo();
+			m_flRetryRequestTime = m_flStartRequestTime = Plat_FloatTime();
 			break;
 		}
 		case C2S_INFOREQUEST:
 		{
-			ReplyInfo(packet->from);
+			ReplyInfo(packet->from, msg.ReadLong());
 			break;
 		}
 		case S2C_INFOREPLY:
 		{
+			uint sequence = msg.ReadLong();
 			newgameserver_t &s = ProcessInfo( msg );
-			Msg("hostname = %s\nplayers: %d/%d\nbots: %d\n", s.m_szServerName, s.m_nPlayers, s.m_nMaxPlayers, s.m_nBotPlayers);
 
+			unsigned short index = m_serverAddresses.Find(packet->from);
+			unsigned short rindex = m_serversRequestTime.Find(sequence);
+
+			if( index == m_serverAddresses.InvalidIndex() ||
+				rindex == m_serversRequestTime.InvalidIndex() )
+				break;
+
+			double requestTime = m_serversRequestTime[rindex];
+
+			m_serverAddresses[index] = true;
+			s.m_nPing = (packet->received-requestTime)*1000.0;
 			s.m_NetAdr = packet->from;
 			m_serverListResponse->ServerResponded( s );
-			break;
-		}
-		case A2A_PING:
-		{
-			const char p = A2A_ACK;
-			NET_SendPacket( NULL, NS_SERVER, packet->from, (unsigned char*)&p, 1);
+
+			m_iServersResponded++;
+
+			if( m_iServersResponded >= m_serverAddresses.Count() )
+			{
+				StopRefresh();
+				m_serverListResponse->RefreshComplete( NServerResponse::nServerResponded );
+			}
 			break;
 		}
 	}
@@ -265,17 +326,24 @@ void CMaster::RequestServersInfo()
 
 	bf_write msg( string, sizeof(string) );
 
-	FOR_EACH_LL( m_serverAddresses, i )
+	FOR_EACH_MAP_FAST( m_serverAddresses, i )
 	{
-		const netadr_t adr = m_serverAddresses[i];
+		bool bResponded = m_serverAddresses.Element(i);
+		if( bResponded )
+			continue;
 
-		Msg("Request server info %s\n", adr.ToString());
+		const netadr_t adr = m_serverAddresses.Key(i);
 
 		msg.WriteLong( CONNECTIONLESS_HEADER );
 		msg.WriteByte( C2S_INFOREQUEST );
+		msg.WriteLong( m_iInfoSequence );
+		m_serversRequestTime.Insert(m_iInfoSequence, net_time);
 
+		m_iInfoSequence++;
 		NET_SendPacket( NULL, NS_CLIENT, adr, msg.GetData(), msg.GetNumBytesWritten() );
 	}
+
+	m_bWaitingForReplys = true;
 }
 
 //-----------------------------------------------------------------------------
@@ -410,7 +478,7 @@ void CMaster::AddServer( netadr_t *adr )
 
 	n = ( adrlist_t * ) malloc ( sizeof( adrlist_t ) );
 	if ( !n )
-		Sys_Error( "Error allocating %i bytes for master address.", sizeof( adrlist_t ) );
+		Sys_Error( "Error allocating %zd bytes for master address.", sizeof( adrlist_t ) );
 
 	memset( n, 0, sizeof( adrlist_t ) );
 
diff --git a/public/engine/iserversinfo.h b/public/engine/iserversinfo.h
index e2fd07de..d892cf2c 100644
--- a/public/engine/iserversinfo.h
+++ b/public/engine/iserversinfo.h
@@ -89,6 +89,7 @@ class IServersInfo
 public:
 	virtual void RequestInternetServerList( const char *gamedir, IServerListResponse *response ) = 0;
 	virtual void RequestLANServerList( const char *gamedir, IServerListResponse *response ) = 0;
+	virtual void StopRefresh() = 0;
 
 	//virtual HServerQuery PingServer( uint32 unIP, uint16 usPort, ISteamMatchmakingPingResponse *pRequestServersResponse ) = 0; 
 	//virtual HServerQuery PlayerDetails( uint32 unIP, uint16 usPort, ISteamMatchmakingPlayersResponse *pRequestServersResponse ) = 0;
diff --git a/public/tier0/threadtools.h b/public/tier0/threadtools.h
index b7216193..2b18dda7 100644
--- a/public/tier0/threadtools.h
+++ b/public/tier0/threadtools.h
@@ -52,12 +52,6 @@
 #pragma once
 #pragma warning(push)
 #pragma warning(disable:4251)
-
-extern "C"
-{
-	void __declspec(dllimport) __stdcall Sleep( unsigned long );
-}
-
 #endif
 
 #ifdef COMPILER_MSVC64
@@ -200,6 +194,8 @@ PLATFORM_INTERFACE bool ReleaseThreadHandle( ThreadHandle_t );
 
 //-----------------------------------------------------------------------------
 
+PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0);
+PLATFORM_INTERFACE void ThreadNanoSleep(unsigned ns);
 PLATFORM_INTERFACE ThreadId_t ThreadGetCurrentId();
 PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle();
 PLATFORM_INTERFACE int ThreadGetPriority( ThreadHandle_t hThread = NULL );
@@ -233,10 +229,10 @@ inline void ThreadPause()
 {
 #if defined( COMPILER_PS3 )
 	__db16cyc();
-#elif defined( COMPILER_GCC ) && (defined( __i386__ ) || defined( __x86_64__ ))
-	__asm __volatile( "pause" );
-#elif defined( POSIX )
+#elif defined(__arm__) || defined(__aarch64__)
         sched_yield();
+#elif defined( COMPILER_GCC )
+	__asm __volatile( "pause" );
 #elif defined ( COMPILER_MSVC64 )
 	_mm_pause();
 #elif defined( COMPILER_MSVC32 )
@@ -251,36 +247,6 @@ inline void ThreadPause()
 #endif
 }
 
-inline void ThreadSleep(unsigned nMilliseconds = 0)
-{
-	if( nMilliseconds == 0 )
-	{
-		ThreadPause();
-		return;
-        }
-
-#ifdef _WIN32
-
-#ifdef _WIN32_PC
-        static bool bInitialized = false;
-        if ( !bInitialized )
-        {
-                bInitialized = true;
-                // Set the timer resolution to 1 ms (default is 10.0, 15.6, 2.5, 1.0 or
-                // some other value depending on hardware and software) so that we can
-                // use Sleep( 1 ) to avoid wasting CPU time without missing our frame
-                // rate.
-                timeBeginPeriod( 1 );
-        }
-#endif
-	Sleep( nMilliseconds );
-#elif PS3
-	sys_timer_usleep( nMilliseconds * 1000 );
-#elif defined(POSIX)
-        usleep( nMilliseconds * 1000 );
-#endif
-}
-
 PLATFORM_INTERFACE bool ThreadJoin( ThreadHandle_t, unsigned timeout = TT_INFINITE );
 
 PLATFORM_INTERFACE void ThreadSetDebugName( ThreadHandle_t hThread, const char *pszName );
diff --git a/public/tier1/memhelpers.h b/public/tier1/memhelpers.h
index 35cd513e..898cafb2 100644
--- a/public/tier1/memhelpers.h
+++ b/public/tier1/memhelpers.h
@@ -11,15 +11,21 @@ namespace memutils
 	template<typename T>
 	inline void copy( T *dest, const T *src, size_t n )
 	{
-		for(; n; n--)
-			*(dest++) = *(src++);
+		do
+		{
+			--n;
+			*(dest+n) = *(src+n);
+	        } while( n );
 	}
 
 	template<typename T>
-	inline void set( T *dest, const T& value, size_t n )
+	inline void set( T *dest, T value, size_t n )
 	{
-		for(; n; n--)
-			*(dest++) = value;
+		do
+		{
+			--n;
+			*(dest+n) = value;
+		} while( n );
 	}
 }
 
diff --git a/tier0/threadtools.cpp b/tier0/threadtools.cpp
index 06c8296f..b0dbb645 100644
--- a/tier0/threadtools.cpp
+++ b/tier0/threadtools.cpp
@@ -485,6 +485,59 @@ bool ReleaseThreadHandle( ThreadHandle_t hThread )
 //
 //-----------------------------------------------------------------------------
 
+void ThreadSleep(unsigned nMilliseconds)
+{
+#ifdef _WIN32
+
+#ifdef _WIN32_PC
+	static bool bInitialized = false;
+	if ( !bInitialized )
+	{
+		bInitialized = true;
+		// Set the timer resolution to 1 ms (default is 10.0, 15.6, 2.5, 1.0 or
+		// some other value depending on hardware and software) so that we can
+		// use Sleep( 1 ) to avoid wasting CPU time without missing our frame
+		// rate.
+		timeBeginPeriod( 1 );
+	}
+#endif
+
+	Sleep( nMilliseconds );
+#elif PS3
+	if( nMilliseconds == 0 )
+	{
+		// sys_ppu_thread_yield doesn't seem to function properly, so sleep instead.
+//		sys_timer_usleep( 60 );
+		sys_ppu_thread_yield();
+	}
+	else
+	{
+		sys_timer_usleep( nMilliseconds * 1000 );
+	}
+#elif defined(POSIX)
+   usleep( nMilliseconds * 1000 ); 
+#endif
+}
+
+//-----------------------------------------------------------------------------
+void ThreadNanoSleep(unsigned ns)
+{
+#ifdef _WIN32
+	// ceil
+	Sleep( ( ns + 999 ) / 1000 );
+#elif PS3
+	sys_timer_usleep( ns );
+#elif defined(POSIX)
+	struct timespec tm;
+	tm.tv_sec = 0;
+	tm.tv_nsec = ns;
+	nanosleep( &tm, NULL ); 
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+
 #ifndef ThreadGetCurrentId
 ThreadId_t ThreadGetCurrentId()
 {
diff --git a/vstdlib/jobthread.cpp b/vstdlib/jobthread.cpp
index 634d5358..922b770f 100644
--- a/vstdlib/jobthread.cpp
+++ b/vstdlib/jobthread.cpp
@@ -214,11 +214,7 @@ public:
 	//-----------------------------------------------------
 	virtual int YieldWait( CThreadEvent **pEvents, int nEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE );
 	virtual int YieldWait( CJob **, int nJobs, bool bWaitAll = true, unsigned timeout = TT_INFINITE );
-	inline void Yield( unsigned timeout )
-	{
-		Assert( ThreadInMainThread() );
-		ThreadSleep( timeout );
-	}
+	void Yield( unsigned timeout );
 
 	//-----------------------------------------------------
 	// Add a native job to the queue (master thread)
@@ -660,6 +656,20 @@ int CThreadPool::YieldWait( CJob **ppJobs, int nJobs, bool bWaitAll, unsigned ti
 	return YieldWait( handles.Base(), handles.Count(), bWaitAll, timeout);
 }
 
+//---------------------------------------------------------
+
+void CThreadPool::Yield( unsigned timeout )
+{
+	// @MULTICORE (toml 10/24/2006): not implemented
+	Assert( ThreadInMainThread() );
+	if ( !ThreadInMainThread() )
+	{
+		ThreadSleep( timeout );
+		return;
+	}
+	ThreadSleep( timeout );
+}
+
 //---------------------------------------------------------
 // Add a job to the queue
 //---------------------------------------------------------

From bca8a497ad181d819ba46b5208d898e3a0267c8a Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Sat, 11 Feb 2023 15:56:06 +0300
Subject: [PATCH 08/17] engine: set net_usesocketsforloopback 0 by default( 1
 breaks singleplayer mode )

---
 engine/net_ws.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/engine/net_ws.cpp b/engine/net_ws.cpp
index b2680f1a..6f3c656b 100644
--- a/engine/net_ws.cpp
+++ b/engine/net_ws.cpp
@@ -45,7 +45,7 @@ static ConVar droppackets	( "net_droppackets", "0", FCVAR_CHEAT, "Drops next n p
 static ConVar fakejitter	( "net_fakejitter", "0", FCVAR_CHEAT, "Jitter fakelag packet time" );
 
 static ConVar net_compressvoice( "net_compressvoice", "0", 0, "Attempt to compress out of band voice payloads (360 only)." );
-ConVar net_usesocketsforloopback( "net_usesocketsforloopback", "1", 0, "Use network sockets layer even for listen server local player's packets (multiplayer only)." );
+ConVar net_usesocketsforloopback( "net_usesocketsforloopback", "0", 0, "Use network sockets layer even for listen server local player's packets (multiplayer only)." );
 
 #ifdef _DEBUG
 static ConVar fakenoise		( "net_fakenoise", "0", FCVAR_CHEAT, "Simulate corrupt network packets (changes n bits per packet randomly)" ); 

From 70cc94bd0125c56fff8cf06487ad67b8f45bad10 Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Sat, 11 Feb 2023 15:57:06 +0300
Subject: [PATCH 09/17] engine(masterserver): fix latency calculation

---
 engine/masterserver.cpp | 39 +++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/engine/masterserver.cpp b/engine/masterserver.cpp
index e7580773..fe3b5389 100644
--- a/engine/masterserver.cpp
+++ b/engine/masterserver.cpp
@@ -24,7 +24,7 @@ extern ConVar sv_tags;
 extern ConVar sv_lan;
 
 #define S2A_EXTRA_DATA_HAS_GAMETAG_DATA                         0x01            // Next bytes are the game tag string
-#define RETRY_INFO_REQUEST_TIME 0.4 // seconds
+#define RETRY_INFO_REQUEST_TIME 0.3 // seconds
 #define INFO_REQUEST_TIMEOUT 5.0 // seconds
 
 //-----------------------------------------------------------------------------
@@ -97,6 +97,7 @@ private:
 	double m_flRetryRequestTime;
 
 	uint m_iInfoSequence;
+	char m_szGameDir[256];
 
 	// If nomaster is true, the server will not send heartbeats to the master server
 	bool	m_bNoMasters;
@@ -130,7 +131,7 @@ CMaster::CMaster( void )
 	SetDefLessFunc( m_serverAddresses );
 	SetDefLessFunc( m_serversRequestTime );
 	m_bWaitingForReplys = false;
-	m_iInfoSequence = 0;
+	m_iInfoSequence = 1;
 
 	Init();
 }
@@ -150,13 +151,19 @@ void CMaster::RunFrame()
 		m_flStartRequestTime < Plat_FloatTime()-INFO_REQUEST_TIMEOUT   )
 	{
 		m_serverListResponse->RefreshComplete( NServerResponse::nServerFailedToRespond );
-		m_bWaitingForReplys = false;
+		StopRefresh();
 	}
 
 	if( m_flRetryRequestTime < Plat_FloatTime() - RETRY_INFO_REQUEST_TIME )
 	{
 		m_flRetryRequestTime = Plat_FloatTime();
 
+		if( m_serverAddresses.Count() == 0 ) // Retry masterserver request
+		{
+			g_pServersInfo->RequestInternetServerList(m_szGameDir, NULL);
+			return;
+		}
+
 		if( m_iServersResponded < m_serverAddresses.Count() )
 			RequestServersInfo();
 	}
@@ -164,6 +171,9 @@ void CMaster::RunFrame()
 
 void CMaster::StopRefresh()
 {
+	if( !m_bWaitingForReplys )
+		return;
+
 	m_bWaitingForReplys = false;
 	m_serverAddresses.RemoveAll();
 	m_serversRequestTime.RemoveAll();
@@ -264,7 +274,8 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 		}
 		case M2C_QUERY:
 		{
-			m_serverAddresses.RemoveAll();
+			if( m_serverAddresses.Count() > 0 )
+				break;
 
 			ip = msg.ReadLong();
 			port = msg.ReadShort();
@@ -281,7 +292,6 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 
 			m_iServersResponded = 0;
 			RequestServersInfo();
-			m_flRetryRequestTime = m_flStartRequestTime = Plat_FloatTime();
 			break;
 		}
 		case C2S_INFOREQUEST:
@@ -303,8 +313,11 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 
 			double requestTime = m_serversRequestTime[rindex];
 
+			if( m_serverAddresses[index] ) // shit happens
+				return;
+
 			m_serverAddresses[index] = true;
-			s.m_nPing = (packet->received-requestTime)*1000.0;
+			s.m_nPing = (Plat_FloatTime()-requestTime)*1000.0;
 			s.m_NetAdr = packet->from;
 			m_serverListResponse->ServerResponded( s );
 
@@ -337,13 +350,11 @@ void CMaster::RequestServersInfo()
 		msg.WriteLong( CONNECTIONLESS_HEADER );
 		msg.WriteByte( C2S_INFOREQUEST );
 		msg.WriteLong( m_iInfoSequence );
-		m_serversRequestTime.Insert(m_iInfoSequence, net_time);
+		m_serversRequestTime.Insert(m_iInfoSequence, Plat_FloatTime());
 
 		m_iInfoSequence++;
 		NET_SendPacket( NULL, NS_CLIENT, adr, msg.GetData(), msg.GetNumBytesWritten() );
 	}
-
-	m_bWaitingForReplys = true;
 }
 
 //-----------------------------------------------------------------------------
@@ -633,7 +644,15 @@ void CMaster::RequestInternetServerList(const char *gamedir, IServerListResponse
 {
 	if( m_bNoMasters ) return;
 
-	m_serverListResponse = response;
+	strncpy( m_szGameDir, gamedir, sizeof(m_szGameDir) );
+
+	if( response )
+	{
+		StopRefresh();
+		m_bWaitingForReplys = true;
+		m_serverListResponse = response;
+		m_flRetryRequestTime = m_flStartRequestTime = Plat_FloatTime();
+	}
 
 	ALIGN4 char buf[256] ALIGN4_POST;
 	bf_write msg(buf, sizeof(buf));

From dda12fcec6017d130e356d2f62e52729f7a1d4fe Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Sat, 11 Feb 2023 19:17:57 +0300
Subject: [PATCH 10/17] engine(masterserver): add additional masterserver,
 implement setmaster command

---
 engine/master.h         |   4 +-
 engine/masterserver.cpp | 103 +++++++++++++++++++++++++---------------
 2 files changed, 65 insertions(+), 42 deletions(-)

diff --git a/engine/master.h b/engine/master.h
index eddb39e0..34a86ffe 100644
--- a/engine/master.h
+++ b/engine/master.h
@@ -23,8 +23,6 @@
 
 #include "engine/iserversinfo.h"
 
-#define DEFAULT_MASTER_ADDRESS "185.192.97.130:27010"
-
 //-----------------------------------------------------------------------------
 // Purpose: Implements a master server interface.
 //-----------------------------------------------------------------------------
@@ -48,7 +46,7 @@ public:
 	// Master sent back a challenge value, read it and send the actual heartbeat
 	virtual void RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg ) = 0;
 	// Console command to set/remove master server
-	virtual void SetMaster_f( void ) = 0;
+	virtual void SetMaster_f( const CCommand &args ) = 0;
 	// Force a heartbeat to be issued right away
 	virtual void Heartbeat_f( void ) = 0;
 
diff --git a/engine/masterserver.cpp b/engine/masterserver.cpp
index fe3b5389..9356425a 100644
--- a/engine/masterserver.cpp
+++ b/engine/masterserver.cpp
@@ -24,9 +24,15 @@ extern ConVar sv_tags;
 extern ConVar sv_lan;
 
 #define S2A_EXTRA_DATA_HAS_GAMETAG_DATA                         0x01            // Next bytes are the game tag string
-#define RETRY_INFO_REQUEST_TIME 0.3 // seconds
+#define RETRY_INFO_REQUEST_TIME 0.4 // seconds
 #define INFO_REQUEST_TIMEOUT 5.0 // seconds
 
+static char g_MasterServers[][64] =
+{
+	"185.192.97.130:27010",
+	"168.138.92.21:27016"
+};
+
 //-----------------------------------------------------------------------------
 // Purpose: List of master servers and some state info about them
 //-----------------------------------------------------------------------------
@@ -69,11 +75,11 @@ public:
 
 	void ProcessConnectionlessPacket( netpacket_t *packet );
 
-	void SetMaster_f( void );
+	void SetMaster_f( const CCommand &args );
 	void Heartbeat_f( void );
 
 	void RunFrame();
-	void RequestServersInfo();
+	void RetryServersInfoRequest();
 
 	void ReplyInfo( const netadr_t &adr, uint sequence );
 	newgameserver_t &ProcessInfo( bf_read &buf );
@@ -83,6 +89,7 @@ public:
 	void RequestLANServerList( const char *gamedir, IServerListResponse *response );
 	void AddServerAddresses( netadr_t **adr, int count );
 	void StopRefresh();
+	void RequestServerInfo( const netadr_t &adr );
 
 private:
 	// List of known master servers
@@ -165,7 +172,7 @@ void CMaster::RunFrame()
 		}
 
 		if( m_iServersResponded < m_serverAddresses.Count() )
-			RequestServersInfo();
+			RetryServersInfoRequest();
 	}
 }
 
@@ -174,6 +181,7 @@ void CMaster::StopRefresh()
 	if( !m_bWaitingForReplys )
 		return;
 
+	m_iServersResponded = 0;
 	m_bWaitingForReplys = false;
 	m_serverAddresses.RemoveAll();
 	m_serversRequestTime.RemoveAll();
@@ -274,9 +282,6 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 		}
 		case M2C_QUERY:
 		{
-			if( m_serverAddresses.Count() > 0 )
-				break;
-
 			ip = msg.ReadLong();
 			port = msg.ReadShort();
 
@@ -284,14 +289,20 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 			{
 				netadr_t adr(ip, port);
 
+				unsigned short index = m_serverAddresses.Find(adr);
+				if( index != m_serverAddresses.InvalidIndex() )
+				{
+					ip = msg.ReadLong();
+					port = msg.ReadShort();
+					continue;
+				}
+
 				m_serverAddresses.Insert(adr, false);
+				RequestServerInfo(adr);
 
 				ip = msg.ReadLong();
 				port = msg.ReadShort();
 			}
-
-			m_iServersResponded = 0;
-			RequestServersInfo();
 			break;
 		}
 		case C2S_INFOREQUEST:
@@ -333,12 +344,22 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 	}
 }
 
-void CMaster::RequestServersInfo()
+void CMaster::RequestServerInfo( const netadr_t &adr )
 {
 	static ALIGN4 char string[256] ALIGN4_POST;    // Buffer for sending heartbeat
-
 	bf_write msg( string, sizeof(string) );
 
+	msg.WriteLong( CONNECTIONLESS_HEADER );
+	msg.WriteByte( C2S_INFOREQUEST );
+	msg.WriteLong( m_iInfoSequence );
+	m_serversRequestTime.Insert(m_iInfoSequence, Plat_FloatTime());
+
+	m_iInfoSequence++;
+	NET_SendPacket( NULL, NS_CLIENT, adr, msg.GetData(), msg.GetNumBytesWritten() );
+}
+
+void CMaster::RetryServersInfoRequest()
+{
 	FOR_EACH_MAP_FAST( m_serverAddresses, i )
 	{
 		bool bResponded = m_serverAddresses.Element(i);
@@ -346,14 +367,7 @@ void CMaster::RequestServersInfo()
 			continue;
 
 		const netadr_t adr = m_serverAddresses.Key(i);
-
-		msg.WriteLong( CONNECTIONLESS_HEADER );
-		msg.WriteByte( C2S_INFOREQUEST );
-		msg.WriteLong( m_iInfoSequence );
-		m_serversRequestTime.Insert(m_iInfoSequence, Plat_FloatTime());
-
-		m_iInfoSequence++;
-		NET_SendPacket( NULL, NS_CLIENT, adr, msg.GetData(), msg.GetNumBytesWritten() );
+		RequestServerInfo( adr );
 	}
 }
 
@@ -378,8 +392,7 @@ void CMaster::SendHeartbeat ( adrlist_t *p )
 		return;
 
 	// Send to master
-	// TODO(nillerusr): send engine version in this packet
-	Q_FileBase( com_gamedir, szGD, sizeof( szGD ) );
+		Q_FileBase( com_gamedir, szGD, sizeof( szGD ) );
 
 	bf_write buf( string, sizeof(string) );
 	buf.WriteByte( S2M_HEARTBEAT );
@@ -510,11 +523,14 @@ void CMaster::UseDefault ( void )
 {
 	netadr_t adr;
 
-	// Convert to netadr_t
-	if ( NET_StringToAdr ( DEFAULT_MASTER_ADDRESS, &adr ) )
+	for( int i = 0; i < ARRAYSIZE(g_MasterServers);i++ )
 	{
-		// Add to master list
-		AddServer( &adr );
+		// Convert to netadr_t
+		if ( NET_StringToAdr ( g_MasterServers[i], &adr ) )
+		{
+			// Add to master list
+			AddServer( &adr );
+		}
 	}
 }
 
@@ -563,9 +579,19 @@ void CMaster::RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg )
 //-----------------------------------------------------------------------------
 // Purpose: Add/remove master servers
 //-----------------------------------------------------------------------------
-void CMaster::SetMaster_f (void)
+void CMaster::SetMaster_f ( const CCommand &args )
 {
+	CUtlString cmd( ( args.ArgC() > 1 ) ? args[ 1 ] : "" );
 
+	netadr_t adr;
+
+	if( !NET_StringToAdr(cmd.String(), &adr) )
+	{
+		Warning("Invalid address\n");
+		return;
+	}
+
+	this->AddServer(&adr);
 }
 
 
@@ -589,9 +615,9 @@ void CMaster::Heartbeat_f (void)
 //-----------------------------------------------------------------------------
 // Purpose: 
 //-----------------------------------------------------------------------------
-void SetMaster_f( void )
+void SetMaster_f( const CCommand &args )
 {
-	master->SetMaster_f();
+	master->SetMaster_f( args );
 }
 
 //-----------------------------------------------------------------------------
@@ -643,7 +669,6 @@ void CMaster::Shutdown(void)
 void CMaster::RequestInternetServerList(const char *gamedir, IServerListResponse *response)
 {
 	if( m_bNoMasters ) return;
-
 	strncpy( m_szGameDir, gamedir, sizeof(m_szGameDir) );
 
 	if( response )
@@ -660,8 +685,15 @@ void CMaster::RequestInternetServerList(const char *gamedir, IServerListResponse
 	msg.WriteByte( C2M_CLIENTQUERY );
 	msg.WriteString(gamedir);
 
-	// TODO(nillerusr): add switching between masters?
-	NET_SendPacket(NULL, NS_CLIENT, m_pMasterAddresses->adr, msg.GetData(), msg.GetNumBytesWritten() );
+	adrlist_t *p;
+
+	p = m_pMasterAddresses;
+	while ( p )
+	{
+		Msg("master server %s request\n", p->adr.ToString());
+		NET_SendPacket(NULL, NS_CLIENT, p->adr, msg.GetData(), msg.GetNumBytesWritten() );
+		p = p->next;
+	}
 }
 
 void CMaster::RequestLANServerList(const char *gamedir, IServerListResponse *response)
@@ -673,10 +705,3 @@ void CMaster::AddServerAddresses( netadr_t **adr, int count )
 {
 
 }
-
-void Master_Request_f()
-{
-	g_pServersInfo->RequestInternetServerList("cstrike", NULL);
-}
-
-ConCommand master_request( "master_request", Master_Request_f );

From efbcaf7820e4864baf339f205de252b1508df142 Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Sat, 11 Feb 2023 19:36:39 +0300
Subject: [PATCH 11/17] engine(masterserver): add master request timeout

---
 engine/masterserver.cpp | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/engine/masterserver.cpp b/engine/masterserver.cpp
index 9356425a..300ffb39 100644
--- a/engine/masterserver.cpp
+++ b/engine/masterserver.cpp
@@ -25,6 +25,7 @@ extern ConVar sv_lan;
 
 #define S2A_EXTRA_DATA_HAS_GAMETAG_DATA                         0x01            // Next bytes are the game tag string
 #define RETRY_INFO_REQUEST_TIME 0.4 // seconds
+#define MASTER_RESPONSE_TIMEOUT 1.5 // seconds
 #define INFO_REQUEST_TIMEOUT 5.0 // seconds
 
 static char g_MasterServers[][64] =
@@ -102,6 +103,7 @@ private:
 
 	double m_flStartRequestTime;
 	double m_flRetryRequestTime;
+	double m_flMasterRequestTime;
 
 	uint m_iInfoSequence;
 	char m_szGameDir[256];
@@ -161,6 +163,15 @@ void CMaster::RunFrame()
 		StopRefresh();
 	}
 
+	if( m_iServersResponded > 0 &&
+			m_iServersResponded >= m_serverAddresses.Count() &&
+			m_flMasterRequestTime < Plat_FloatTime() - MASTER_RESPONSE_TIMEOUT )
+	{
+		StopRefresh();
+		m_serverListResponse->RefreshComplete( NServerResponse::nServerResponded );
+		return;
+	}
+
 	if( m_flRetryRequestTime < Plat_FloatTime() - RETRY_INFO_REQUEST_TIME )
 	{
 		m_flRetryRequestTime = Plat_FloatTime();
@@ -250,7 +261,7 @@ newgameserver_t &CMaster::ProcessInfo(bf_read &buf)
 
 	// Password?
 	s.m_bPassword = buf.ReadByte();
-
+m_iServersResponded
 	s.m_iFlags = buf.ReadLong();
 
 	if( s.m_iFlags & S2A_EXTRA_DATA_HAS_GAMETAG_DATA )
@@ -333,12 +344,6 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 			m_serverListResponse->ServerResponded( s );
 
 			m_iServersResponded++;
-
-			if( m_iServersResponded >= m_serverAddresses.Count() )
-			{
-				StopRefresh();
-				m_serverListResponse->RefreshComplete( NServerResponse::nServerResponded );
-			}
 			break;
 		}
 	}
@@ -676,7 +681,7 @@ void CMaster::RequestInternetServerList(const char *gamedir, IServerListResponse
 		StopRefresh();
 		m_bWaitingForReplys = true;
 		m_serverListResponse = response;
-		m_flRetryRequestTime = m_flStartRequestTime = Plat_FloatTime();
+		m_flRetryRequestTime = m_flStartRequestTime = m_flMasterRequestTime = Plat_FloatTime();
 	}
 
 	ALIGN4 char buf[256] ALIGN4_POST;
@@ -690,7 +695,6 @@ void CMaster::RequestInternetServerList(const char *gamedir, IServerListResponse
 	p = m_pMasterAddresses;
 	while ( p )
 	{
-		Msg("master server %s request\n", p->adr.ToString());
 		NET_SendPacket(NULL, NS_CLIENT, p->adr, msg.GetData(), msg.GetNumBytesWritten() );
 		p = p->next;
 	}

From 2b2ca63b4869dc6d2f7e5956abe840910dba9a88 Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Sat, 11 Feb 2023 19:39:01 +0300
Subject: [PATCH 12/17] serverbrowser: rewrite according my expectations

---
 serverbrowser/BaseGamesPage.cpp       | 326 ++++++--------------------
 serverbrowser/BaseGamesPage.h         |  14 +-
 serverbrowser/DialogAddServer.cpp     |  34 +--
 serverbrowser/DialogAddServer.h       |   8 +-
 serverbrowser/InternetGames.cpp       |   4 +-
 serverbrowser/ServerBrowserDialog.cpp |  53 +++--
 serverbrowser/ServerBrowserDialog.h   |   9 +-
 serverbrowser/ServerListCompare.cpp   |  75 ++----
 serverbrowser/igamelist.h             |   4 +-
 serverbrowser/pch_serverbrowser.h     |   2 +-
 10 files changed, 155 insertions(+), 374 deletions(-)

diff --git a/serverbrowser/BaseGamesPage.cpp b/serverbrowser/BaseGamesPage.cpp
index 5f76f78d..d87900c0 100644
--- a/serverbrowser/BaseGamesPage.cpp
+++ b/serverbrowser/BaseGamesPage.cpp
@@ -46,13 +46,13 @@ bool GameSupportsReplay()
 #endif
 
 //--------------------------------------------------------------------------------------------------------
-bool IsReplayServer( gameserveritem_t &server )
+bool IsReplayServer( newgameserver_t &server )
 {
 	bool bReplay = false;
 
 	if ( GameSupportsReplay() )
 	{
-		if ( server.m_szGameTags && server.m_szGameTags[0] )
+		if ( server.m_szGameTags[0] )
 		{
 			CUtlVector<char*> TagList;
 			V_SplitString( server.m_szGameTags, ",", TagList );
@@ -156,11 +156,11 @@ CBaseGamesPage::CBaseGamesPage( vgui::Panel *parent, const char *name, EPageType
 	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_pRefreshQuick = new Button(this, "RefreshQuickButton", "#ServerBrowser_RefreshQuick");
 
 	m_pQuickList = new PanelListPanel(this, "quicklist");
 	m_pQuickList->SetFirstColumnWidth( 0 );
@@ -191,14 +191,14 @@ CBaseGamesPage::CBaseGamesPage( vgui::Panel *parent, const char *name, EPageType
 		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_Players, "Players", "#ServerBrowser_Players", 80, ListPanel::COLUMN_FIXEDSIZE);
+	m_pGameList->AddColumnHeader( k_nColumn_Bots, "Bots", "#ServerBrowser_Bots", 60, 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->AddColumnHeader( k_nColumn_Ping, "Ping", "#ServerBrowser_Latency", 55, ListPanel::COLUMN_RESIZEWITHWINDOW);
 
 	m_pGameList->SetColumnHeaderTooltip( k_nColumn_Password, "#ServerBrowser_PasswordColumn_Tooltip");
 	m_pGameList->SetColumnHeaderTooltip( k_nColumn_Bots, "#ServerBrowser_BotColumn_Tooltip");
@@ -280,12 +280,10 @@ void CBaseGamesPage::PerformLayout()
 
 	if (SupportsItem(IGameList::GETNEWLIST))
 	{
-		m_pRefreshQuick->SetVisible(true);
 		m_pRefreshAll->SetText("#ServerBrowser_RefreshAll");
 	}
 	else
 	{
-		m_pRefreshQuick->SetVisible(false);
 		m_pRefreshAll->SetText("#ServerBrowser_Refresh");
 	}
 
@@ -313,25 +311,8 @@ void CBaseGamesPage::PerformLayout()
 		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" );
-	}*/
+	m_pRefreshQuick->SetVisible( false );
+	m_pFilter->SetVisible(false);
 
 	Repaint();
 }
@@ -378,20 +359,6 @@ struct serverqualitysort_t
 
 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;
 }
 
@@ -400,156 +367,72 @@ int ServerQualitySort( const serverqualitysort_t *pSQ1, const serverqualitysort_
 //-----------------------------------------------------------------------------
 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 )
+int ServerPingSortFunc( const serverping_t *p1,  const serverping_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;
+	return p1->m_nPing - p2->m_nPing;
 }
 
 //-----------------------------------------------------------------------------
 // Purpose: prepares all the QuickListPanel map panels...
 //-----------------------------------------------------------------------------
-void CBaseGamesPage::PrepareQuickListMap( const char *pMapName, int iListID )
+void CBaseGamesPage::PrepareQuickListMap( newgameserver_t *server, int iListID )
 {
 	char szMapName[ 512 ];
-	Q_snprintf( szMapName, sizeof( szMapName ), "%s",  pMapName );
+	Q_snprintf( szMapName, sizeof( szMapName ), "%s", server->m_szMap );
 
 	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 )
+	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 )
 	{
-		CQuickListMapServerList vecMapServers;
-		iIndex = m_quicklistserverlist.Insert( szMapName, vecMapServers );
+		serverping_t serverping;
+		const char *pFriendlyName = CloneString( szFriendlyName );
+		const char *pOriginalName = CloneString( szMapName );
 
-		char szFriendlyName[MAX_MAP_NAME];
-		const char *pszFriendlyGameTypeName = ServerBrowser().GetMapFriendlyNameAndGameType( szMapName, szFriendlyName, sizeof(szFriendlyName) );
+		char path[ 512 ];
+		Q_snprintf( path, sizeof( path ), "maps/%s.bsp", szMapName );
 
-		//Add the map to our list of panels.
-		if ( m_pQuickList )
+		CQuickListPanel *pQuickListPanel = new CQuickListPanel( m_pQuickList, "QuickListPanel");
+
+		if ( pQuickListPanel )
 		{
-			servermaps_t servermap;
+			pQuickListPanel->InvalidateLayout();
+			pQuickListPanel->SetName( pOriginalName );
+			pQuickListPanel->SetMapName( pFriendlyName );
+			pQuickListPanel->SetImage( pOriginalName );
+			pQuickListPanel->SetGameType( pszFriendlyGameTypeName );
+			pQuickListPanel->SetVisible( true );
+			pQuickListPanel->SetRefreshing();
+			pQuickListPanel->SetServerInfo( m_pGameList->GetItem( iListID ), iListID, 1 );
 
-			servermap.pFriendlyName = CloneString( szFriendlyName );
-			servermap.pOriginalName = CloneString( szMapName );
+			serverping.iPanelIndex = m_pQuickList->AddItem( NULL, pQuickListPanel );
 
-			char path[ 512 ];
-			Q_snprintf( path, sizeof( path ), "maps/%s.bsp", szMapName );
+			serverping.m_nPing = server->m_nPing;
 
-			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 );
+			m_vecServersFound.AddToTail( serverping );
+			m_vecServersFound.Sort( ServerPingSortFunc );
 		}
 
-		//Now make sure that list is sorted.
-		CUtlVector<int> *pPanelSort = m_pQuickList->GetSortedVector();
-
-		if ( pPanelSort )
-		{
-			pPanelSort->RemoveAll();
-
-			for ( int i = 0; i < m_vecMapNamesFound.Count(); i++ )
-			{
-				pPanelSort->AddToTail( m_vecMapNamesFound[i].iPanelIndex );
-			}
-		}
 	}
 
-	if ( iIndex != m_quicklistserverlist.InvalidIndex() )
-	{
-		CQuickListMapServerList *vecMapServers = &m_quicklistserverlist[iIndex];
+	//Now make sure that list is sorted.
+	CUtlVector<int> *pPanelSort = m_pQuickList->GetSortedVector();
 
-		if ( vecMapServers )
+	if ( pPanelSort )
+	{
+		pPanelSort->RemoveAll();
+
+		for ( int i = 0; i < m_vecServersFound.Count(); i++ )
 		{
-			if ( vecMapServers->Find( iListID ) == vecMapServers->InvalidIndex() )
-			{
-				 vecMapServers->AddToTail( iListID );
-			}
+			pPanelSort->AddToTail( m_vecServersFound[i].iPanelIndex );
 		}
 	}
 }
@@ -557,21 +440,10 @@ void CBaseGamesPage::PrepareQuickListMap( const char *pMapName, int iListID )
 //-----------------------------------------------------------------------------
 // Purpose: gets information about specified server
 //-----------------------------------------------------------------------------
-gameserveritem_t *CBaseGamesPage::GetServer( unsigned int serverID )
+newgameserver_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...
-	//}
+	if( serverID >= m_serversInfo.Count() ) return NULL;
+	return &m_serversInfo[serverID];
 }
 
 //-----------------------------------------------------------------------------
@@ -680,8 +552,8 @@ void CBaseGamesPage::CreateFilters()
 		int iItemID = m_pGameFilter->AddItem(ModList().GetModName(i), pkv);
 		m_mapGamesFilterItem.Insert( ModList().GetAppID(i).ToUint64(), iItemID );
 	}
-	pkv->deleteThis();
 
+	pkv->deleteThis();
 }
 
 
@@ -710,7 +582,7 @@ void CBaseGamesPage::LoadFilterSettings()
 	m_bFilterNoEmptyServers = filter->GetInt("NoEmpty");
 	m_bFilterNoPasswordedServers = filter->GetInt("NoPassword");
 	m_bFilterReplayServers = filter->GetInt("Replay");
-	m_pQuickListCheckButton->SetSelected( filter->GetInt( "QuickList", 0 ) );
+	m_pQuickListCheckButton->SetSelected( filter->GetInt( "QuickList", IsAndroid() ) );
 
 	int secureFilter = filter->GetInt("Secure");
 	m_pSecureFilter->ActivateItem(secureFilter);
@@ -1005,7 +877,13 @@ void CBaseGamesPage::UpdateFilterAndQuickListVisibility()
 	
 	int wide, tall;
 	GetSize( wide, tall );
-	SetSize( 624, 278 );
+
+	int w = 640; int h = 384;
+
+	w = IsProportional() ? vgui::scheme()->GetProportionalScaledValue(w) : w;
+	h = IsProportional() ? vgui::scheme()->GetProportionalScaledValue(h) : h;
+
+	SetSize( w, h );
 
 	UpdateDerivedLayouts();		
 	UpdateGameFilter();
@@ -1018,12 +896,10 @@ void CBaseGamesPage::UpdateFilterAndQuickListVisibility()
 
 	SetSize( wide, tall );
 
-	
 	m_pQuickList->SetVisible( showQuickList );
 	m_pGameList->SetVisible( !showQuickList );
 	m_pFilter->SetVisible( !showQuickList );
-	m_pFilterString->SetVisible ( !showQuickList );		
-
+	m_pFilterString->SetVisible ( !showQuickList );
 
 	InvalidateLayout();
 
@@ -1638,7 +1514,6 @@ void CBaseGamesPage::SetRefreshing(bool state)
 		m_pGameList->SetEmptyListText("");
 		m_pRefreshAll->SetText("#ServerBrowser_StopRefreshingList");
 		m_pRefreshAll->SetCommand("stoprefresh");
-		m_pRefreshQuick->SetEnabled(false);
 	}
 	else
 	{
@@ -1654,14 +1529,6 @@ void CBaseGamesPage::SetRefreshing(bool state)
 		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);
-		}
 	}
 }
 
@@ -1762,7 +1629,7 @@ int CBaseGamesPage::GetSelectedItemsCount()
 //-----------------------------------------------------------------------------
 void CBaseGamesPage::OnAddToFavorites()
 {
-	if ( !steamapicontext->SteamMatchmakingServers() )
+/*	if ( !steamapicontext->SteamMatchmakingServers() )
 		return;
 
 	// loop through all the selected favorites
@@ -1776,7 +1643,7 @@ void CBaseGamesPage::OnAddToFavorites()
 			// add to favorites list
 			ServerBrowserDialog().AddServerToFavorites(*pServer);
 		}
-	}
+	}*/
 }
 
 //-----------------------------------------------------------------------------
@@ -1838,6 +1705,8 @@ void CBaseGamesPage::StartRefresh()
 	MatchMakingKeyValuePair_t *pFilters;
 	int nFilters = GetServerFilters( &pFilters );
 
+	m_serversInfo.SetCount(0);
+
 /*	if ( m_hRequest )
 	{
 		steamapicontext->SteamMatchmakingServers()->ReleaseRequest( m_hRequest );
@@ -1852,7 +1721,6 @@ void CBaseGamesPage::StartRefresh()
 		m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestHistoryServerList( GetFilterAppID().AppID(), &pFilters, nFilters, this );
 		break;*/
 	case eInternetServer:
-		Msg("RequestInternetServerList\n");
 		g_pServersInfo->RequestInternetServerList(COM_GetModDirectory(), this);
 		//m_hRequest = steamapicontext->SteamMatchmakingServers()->RequestInternetServerList( GetFilterAppID().AppID(), &pFilters, nFilters, this );
 		break;
@@ -1878,20 +1746,7 @@ void CBaseGamesPage::StartRefresh()
 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();
+	m_vecServersFound.RemoveAll();
 }
 
 //-----------------------------------------------------------------------------
@@ -1925,8 +1780,7 @@ void CBaseGamesPage::StopRefresh()
 	m_iServerRefreshCount = 0;
 
 	// Stop the server list refreshing
-	if ( steamapicontext->SteamMatchmakingServers() )
-		steamapicontext->SteamMatchmakingServers()->CancelQuery( m_hRequest );
+	g_pServersInfo->StopRefresh();
 
 	// update UI
 	RefreshComplete( nServerResponded );
@@ -1940,7 +1794,8 @@ void CBaseGamesPage::StopRefresh()
 //-----------------------------------------------------------------------------
 void CBaseGamesPage::RefreshComplete( NServerResponse response )
 {
-	SelectQuickListServers();
+	//Force the connect button to recalculate its state.
+	OnItemSelected();
 }
 
 //-----------------------------------------------------------------------------
@@ -2235,12 +2090,7 @@ void CBaseGamesPage::ServerResponded( newgameserver_t &server )
 	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", "");
-
+	kv->SetInt("bots", pServerItem->m_nBotPlayers);
 
 	kv->SetInt("secure", 0);
 
@@ -2257,51 +2107,21 @@ void CBaseGamesPage::ServerResponded( newgameserver_t &server )
 
 	kv->SetInt("Ping", pServerItem->m_nPing);
 
-	kv->SetString("Tags", "");
+	kv->SetString("Tags", pServerItem->m_szGameTags);
 
 	kv->SetInt("Replay", 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);
-		}
-	}*/
-
 	int iServerIndex = m_serversInfo.AddToTail( server );
 
-	//if ( !m_pGameList->IsValidItemID( pServer->m_iListID ) )
+	// new server, add to list
+	int iListID = m_pGameList->AddItem(kv, iServerIndex, false, false);
 
-		// new server, add to list
-		int iListID = m_pGameList->AddItem(kv, iServerIndex, false, false);
-		/*if ( m_bAutoSelectFirstItemInGameList && m_pGameList->GetItemCount() == 1 )
-		{
-			m_pGameList->AddSelectedItem( pServer->m_iListID );
-		}*/
+	m_pGameList->SetItemVisible( iListID, true );
+	kv->deleteThis();
 
-		m_pGameList->SetItemVisible( iListID, true );
-
-		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, iListID );
+	PrepareQuickListMap( &server, iListID );
 	UpdateStatus();
 	m_iServerRefreshCount++;
-
 }
 
 //-----------------------------------------------------------------------------
diff --git a/serverbrowser/BaseGamesPage.h b/serverbrowser/BaseGamesPage.h
index fca73685..d3e0ce87 100644
--- a/serverbrowser/BaseGamesPage.h
+++ b/serverbrowser/BaseGamesPage.h
@@ -66,12 +66,10 @@ public:
 	virtual void OnCursorExited();
 };
 
-struct servermaps_t
+struct serverping_t
 {
-	const char *pOriginalName;
-	const char *pFriendlyName;
-	int			iPanelIndex;
-	bool		bOnDisk;
+	int	m_nPing;
+	int	iPanelIndex;
 };
 
 struct gametypes_t
@@ -120,7 +118,7 @@ public:
 	virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
 
 	// gets information about specified server
-	virtual gameserveritem_t *GetServer(unsigned int serverID);
+	virtual newgameserver_t *GetServer(unsigned int serverID);
 	virtual const char *GetConnectCode();
 
 	uint32 GetServerFilters( MatchMakingKeyValuePair_t **pFilters );
@@ -144,7 +142,7 @@ public:
 
 	virtual void UpdateDerivedLayouts( void );
 	
-	void		PrepareQuickListMap( const char *pMapName, int iListID );
+	void		PrepareQuickListMap( newgameserver_t *server, int iListID );
 	void		SelectQuickListServers( void );
 	vgui::Panel *GetActiveList( void );
 	virtual bool IsQuickListButtonChecked()
@@ -242,7 +240,7 @@ protected:
 	CUtlVector<MatchMakingKeyValuePair_t> m_vecServerFilters;
 	CUtlDict< CQuickListMapServerList, int > m_quicklistserverlist;
 	int m_iServerRefreshCount;
-	CUtlVector< servermaps_t > m_vecMapNamesFound;
+	CUtlVector<serverping_t> m_vecServersFound;
 	
 
 	EPageType m_eMatchMakingType;
diff --git a/serverbrowser/DialogAddServer.cpp b/serverbrowser/DialogAddServer.cpp
index 5dbc9ed5..50ce17ca 100644
--- a/serverbrowser/DialogAddServer.cpp
+++ b/serverbrowser/DialogAddServer.cpp
@@ -177,15 +177,13 @@ void CDialogAddServer::OnOK()
 
 	if ( AllowInvalidIPs() || netaddr.IsValid() )
 	{
-		gameserveritem_t server;
+		newgameserver_t server;
 		memset(&server, 0, sizeof(server));
-		server.SetName( address );
+		strncpy( server.m_szServerName, address, sizeof(server.m_szServerName) );
 
 		// We assume here that the query and connection ports are the same. This is why it's much
 		// better if they click "Servers" and choose a server in there.
-		server.m_NetAdr.Init( netaddr.GetIPHostByteOrder(), netaddr.GetPort(), netaddr.GetPort() );
-
-		server.m_nAppID = 0;
+		server.m_NetAdr = netaddr;
 		FinishAddServer( server );
 	}
 	else
@@ -257,21 +255,21 @@ void CDialogAddServer::TestServers()
 	m_pTabPanel->AddPage( m_pDiscoveredGames, str );
 	m_pTabPanel->InvalidateLayout();
 	
-	FOR_EACH_VEC( vecAdress, iAddress )
+/*	FOR_EACH_VEC( vecAdress, iAddress )
 	{
 		m_Queries.AddToTail( steamapicontext->SteamMatchmakingServers()->PingServer( vecAdress[ iAddress ].GetIPHostByteOrder(), vecAdress[ iAddress ].GetPort(), this ) );
-	}
+	}*/
 }
 
 
 //-----------------------------------------------------------------------------
 // Purpose: A server answered our ping
 //-----------------------------------------------------------------------------
-void CDialogAddServer::ServerResponded( gameserveritem_t &server )
+void CDialogAddServer::ServerResponded( newgameserver_t &server )
 {
 	KeyValues *kv = new KeyValues( "Server" );
 
-	kv->SetString( "name", server.GetName() );
+	kv->SetString( "name", server.m_szServerName );
 	kv->SetString( "map", server.m_szMap );
 	kv->SetString( "GameDir", server.m_szGameDir );
 	kv->SetString( "GameDesc", server.m_szGameDescription );
@@ -279,21 +277,9 @@ void CDialogAddServer::ServerResponded( gameserveritem_t &server )
 	kv->SetInt( "password", server.m_bPassword ? 1 : 0);
 	kv->SetInt( "bots", server.m_nBotPlayers ? 2 : 0);
 	kv->SetInt( "Replay", IsReplayServer( server ) ? 5 : 0 );
+	kv->SetInt("secure", 0);
 
-	if ( server.m_bSecure )
-	{
-		// show the denied icon if banned from secure servers, the secure icon otherwise
-		kv->SetInt("secure", ServerBrowser().IsVACBannedFromGame( server.m_nAppID ) ?  4 : 3);
-	}
-	else
-	{
-		kv->SetInt("secure", 0);
-	}
-
-	netadr_t reportedIPAddr;
-	reportedIPAddr.SetIP( server.m_NetAdr.GetIP() );
-	reportedIPAddr.SetPort( server.m_NetAdr.GetConnectionPort() );
-	kv->SetString("IPAddr", reportedIPAddr.ToString() );
+	kv->SetString("IPAddr", server.m_NetAdr.ToString() );
 
 	char buf[32];
 	Q_snprintf(buf, sizeof(buf), "%d / %d", server.m_nPlayers, server.m_nMaxPlayers);
@@ -366,7 +352,7 @@ void CDialogAddServer::OnItemSelected()
 //-----------------------------------------------------------------------------
 // Purpose: 
 //-----------------------------------------------------------------------------
-void CDialogAddServer::FinishAddServer( gameserveritem_t &pServer )
+void CDialogAddServer::FinishAddServer( newgameserver_t &pServer )
 {
 	ServerBrowserDialog().AddServerToFavorites( pServer );
 }
diff --git a/serverbrowser/DialogAddServer.h b/serverbrowser/DialogAddServer.h
index c340904b..6128561c 100644
--- a/serverbrowser/DialogAddServer.h
+++ b/serverbrowser/DialogAddServer.h
@@ -17,7 +17,7 @@ class IGameList;
 //-----------------------------------------------------------------------------
 // Purpose: Dialog which lets the user add a server by IP address
 //-----------------------------------------------------------------------------
-class CDialogAddServer : public vgui::Frame, public ISteamMatchmakingPingResponse
+class CDialogAddServer : public vgui::Frame //, public ISteamMatchmakingPingResponse
 {
 	DECLARE_CLASS_SIMPLE( CDialogAddServer, vgui::Frame );
 	friend class CAddServerGameList;
@@ -26,7 +26,7 @@ public:
 	CDialogAddServer(vgui::Panel *parent, IGameList *gameList);
 	~CDialogAddServer();
 
-	void ServerResponded( gameserveritem_t &server );
+	void ServerResponded( newgameserver_t &server );
 	void ServerFailedToRespond();
 
 	void ApplySchemeSettings( vgui::IScheme *pScheme );
@@ -40,7 +40,7 @@ private:
 	void TestServers();
 	MESSAGE_FUNC( OnTextChanged, "TextChanged" );
 
-	virtual void FinishAddServer( gameserveritem_t &pServer );
+	virtual void FinishAddServer( newgameserver_t &pServer );
 	virtual bool AllowInvalidIPs( void ) { return false; }
 
 protected:
@@ -54,7 +54,7 @@ protected:
 	vgui::TextEntry *m_pTextEntry;
 	vgui::ListPanel *m_pDiscoveredGames;
 	int m_OriginalHeight;
-	CUtlVector<gameserveritem_t> m_Servers;
+	CUtlVector<newgameserver_t> m_Servers;
 	CUtlVector<HServerQuery> m_Queries;
 };
 
diff --git a/serverbrowser/InternetGames.cpp b/serverbrowser/InternetGames.cpp
index 2e77e0ab..00a46ccf 100644
--- a/serverbrowser/InternetGames.cpp
+++ b/serverbrowser/InternetGames.cpp
@@ -23,7 +23,7 @@ CInternetGames::CInternetGames(vgui::Panel *parent, const char *panelName, EPage
 	m_fLastSort = 0.0f;
 	m_bDirty = false;
 	m_bRequireUpdate = true;
-	m_bOfflineMode = false; //ro!IsSteamGameServerBrowsingEnabled();
+	m_bOfflineMode = false;
 
 	m_bAnyServersRetrievedFromMaster = false;
 	m_bNoServersListedOnMaster = false;
@@ -311,7 +311,7 @@ int CInternetGames::GetRegionCodeToFilter()
 bool CInternetGames::CheckTagFilter( gameserveritem_t &server )
 {
 	// Servers without tags go in the official games, servers with tags go in custom games
-	bool bOfficialServer = !( server.m_szGameTags && server.m_szGameTags[0] );
+	bool bOfficialServer = !server.m_szGameTags[0];
 	if ( !bOfficialServer )
 		return false;
 
diff --git a/serverbrowser/ServerBrowserDialog.cpp b/serverbrowser/ServerBrowserDialog.cpp
index b3e9738b..2ba47348 100644
--- a/serverbrowser/ServerBrowserDialog.cpp
+++ b/serverbrowser/ServerBrowserDialog.cpp
@@ -59,6 +59,7 @@ void GetMostCommonQueryPorts( CUtlVector<uint16> &ports )
 //-----------------------------------------------------------------------------
 CServerBrowserDialog::CServerBrowserDialog(vgui::Panel *parent) : Frame(parent, "CServerBrowserDialog")
 {
+	SetProportional( NeedProportional() );
 	s_InternetDlg = this;
 
 	m_szGameName[0] = 0;
@@ -67,19 +68,25 @@ CServerBrowserDialog::CServerBrowserDialog(vgui::Panel *parent) : Frame(parent,
 	m_pFilterData = NULL;
 	m_pFavorites = NULL;
 	m_pHistory = NULL;
+	m_pLanGames = NULL;
 
 	LoadUserData();
 
 	m_pInternetGames = new CInternetGames(this);
+/*
 	m_pFavorites = new CFavoriteGames(this);
 	m_pHistory = new CHistoryGames(this);
-
-	// TODO(nillerusr): implement spectate games without steam
-	//m_pSpectateGames = new CSpectateGames(this);
+	m_pSpectateGames = new CSpectateGames(this);
 	m_pLanGames = new CLanGames(this);
+*/
 
-	SetMinimumSize( 640, 384 );
-	SetSize( 640, 384 );
+	int w = 640; int h = 384;
+
+	w = IsProportional() ? vgui::scheme()->GetProportionalScaledValue(w) : w;
+	h = IsProportional() ? vgui::scheme()->GetProportionalScaledValue(h) : h;
+
+	SetMinimumSize( w, h );
+	SetSize( w, h );
 
 	m_pGameList = m_pInternetGames;
 
@@ -89,10 +96,10 @@ CServerBrowserDialog::CServerBrowserDialog(vgui::Panel *parent) : Frame(parent,
 	m_pTabPanel = new PropertySheet(this, "GameTabs");
 	m_pTabPanel->SetTabWidth(72);
 	m_pTabPanel->AddPage(m_pInternetGames, "#ServerBrowser_InternetTab");
-	m_pTabPanel->AddPage(m_pFavorites, "#ServerBrowser_FavoritesTab");
-	m_pTabPanel->AddPage(m_pHistory, "#ServerBrowser_HistoryTab");
+	//m_pTabPanel->AddPage(m_pFavorites, "#ServerBrowser_FavoritesTab");
+	//m_pTabPanel->AddPage(m_pHistory, "#ServerBrowser_HistoryTab");
 	//m_pTabPanel->AddPage(m_pSpectateGames, "#ServerBrowser_SpectateTab");
-	m_pTabPanel->AddPage(m_pLanGames, "#ServerBrowser_LanTab");
+	//m_pTabPanel->AddPage(m_pLanGames, "#ServerBrowser_LanTab");
 
 	m_pTabPanel->AddActionSignalTarget(this);
 
@@ -109,7 +116,7 @@ CServerBrowserDialog::CServerBrowserDialog(vgui::Panel *parent) : Frame(parent,
 	{
 		m_pTabPanel->SetActivePage(m_pSpectateGames);
 	}
-	else */
+	else 
 	if (!Q_stricmp(gameList, "favorites"))
 	{
 		m_pTabPanel->SetActivePage(m_pFavorites);
@@ -122,7 +129,7 @@ CServerBrowserDialog::CServerBrowserDialog(vgui::Panel *parent) : Frame(parent,
 	{
 		m_pTabPanel->SetActivePage(m_pLanGames);
 	}
-	else
+	else*/
 	{
 		m_pTabPanel->SetActivePage(m_pInternetGames);
 	}
@@ -160,7 +167,7 @@ void CServerBrowserDialog::Initialize()
 //-----------------------------------------------------------------------------
 // Purpose: returns a server in the list
 //-----------------------------------------------------------------------------
-gameserveritem_t *CServerBrowserDialog::GetServer( unsigned int serverID )
+newgameserver_t *CServerBrowserDialog::GetServer( unsigned int serverID )
 {
 	if (m_pGameList)
 		return m_pGameList->GetServer( serverID );
@@ -257,7 +264,7 @@ void CServerBrowserDialog::SaveUserData()
 	{
 		m_pSavedData->SetString("GameList", "spectate");
 	}
-	else */
+	else
 	if (m_pGameList == m_pFavorites)
 	{
 		m_pSavedData->SetString("GameList", "favorites");
@@ -270,7 +277,7 @@ void CServerBrowserDialog::SaveUserData()
 	{
 		m_pSavedData->SetString("GameList", "history");
 	}
-	else
+	else*/
 	{
 		m_pSavedData->SetString("GameList", "internet");
 	}
@@ -363,9 +370,9 @@ CServerBrowserDialog *CServerBrowserDialog::GetInstance()
 //-----------------------------------------------------------------------------
 // Purpose: Adds a server to the list of favorites
 //-----------------------------------------------------------------------------
-void CServerBrowserDialog::AddServerToFavorites(gameserveritem_t &server)
+void CServerBrowserDialog::AddServerToFavorites(newgameserver_t &server)
 {
-	if ( steamapicontext->SteamMatchmaking() )
+/*	if ( steamapicontext->SteamMatchmaking() )
 	{
 		steamapicontext->SteamMatchmaking()->AddFavoriteGame( 
 			server.m_nAppID, 
@@ -374,7 +381,7 @@ void CServerBrowserDialog::AddServerToFavorites(gameserveritem_t &server)
 			server.m_NetAdr.GetQueryPort(), 
 			k_unFavoriteFlagFavorite, 
 			time( NULL ) );
-	}
+	}*/
 }
 
 //-----------------------------------------------------------------------------
@@ -527,10 +534,10 @@ void CServerBrowserDialog::OnActiveGameName( KeyValues *pKV )
 void CServerBrowserDialog::ReloadFilterSettings()
 {
 	m_pInternetGames->LoadFilterSettings();
-	//m_pSpectateGames->LoadFilterSettings();
+	/*m_pSpectateGames->LoadFilterSettings();
 	m_pFavorites->LoadFilterSettings();
 	m_pLanGames->LoadFilterSettings();
-	m_pHistory->LoadFilterSettings();
+	m_pHistory->LoadFilterSettings();*/
 }
 
 //-----------------------------------------------------------------------------
@@ -572,7 +579,7 @@ void CServerBrowserDialog::OnConnectToGame( KeyValues *pMessageValues )
 	}
 
 	// forward to favorites
-	m_pFavorites->OnConnectToGame();
+	//m_pFavorites->OnConnectToGame();
 
 	m_bCurrentlyConnected = true;
 
@@ -582,7 +589,7 @@ void CServerBrowserDialog::OnConnectToGame( KeyValues *pMessageValues )
 	{
 		iQuickListBitField |= ( 1 << 1 );
 	}
-/*	if ( m_pSpectateGames && m_pSpectateGames->IsQuickListButtonChecked() )
+	/*if ( m_pSpectateGames && m_pSpectateGames->IsQuickListButtonChecked() )
 	{
 		iQuickListBitField |= ( 1 << 2 );
 	}*/
@@ -625,7 +632,7 @@ void CServerBrowserDialog::OnDisconnectFromGame( void )
 	memset( &m_CurrentConnection, 0, sizeof(gameserveritem_t) );
 
 	// forward to favorites
-	m_pFavorites->OnDisconnectFromGame();
+	//m_pFavorites->OnDisconnectFromGame();
 }
 
 //-----------------------------------------------------------------------------
@@ -634,10 +641,10 @@ void CServerBrowserDialog::OnDisconnectFromGame( void )
 void CServerBrowserDialog::OnLoadingStarted( void )
 {
 	m_pInternetGames->OnLoadingStarted();
-//	m_pSpectateGames->OnLoadingStarted();
+/*	m_pSpectateGames->OnLoadingStarted();
 	m_pFavorites->OnLoadingStarted();
 	m_pLanGames->OnLoadingStarted();
-	m_pHistory->OnLoadingStarted();
+	m_pHistory->OnLoadingStarted();*/
 }
 
 //-----------------------------------------------------------------------------
diff --git a/serverbrowser/ServerBrowserDialog.h b/serverbrowser/ServerBrowserDialog.h
index 8180a9f1..dfd4955f 100644
--- a/serverbrowser/ServerBrowserDialog.h
+++ b/serverbrowser/ServerBrowserDialog.h
@@ -31,7 +31,7 @@ public:
 	void		Open( void );
 
 	// gets server info
-	gameserveritem_t *GetServer(unsigned int serverID);
+	newgameserver_t *GetServer(unsigned int serverID);
 	// called every frame
 	virtual void OnTick();
 
@@ -49,7 +49,7 @@ public:
 	static CServerBrowserDialog *GetInstance();
 
 	// Adds a server to the list of favorites
-	void AddServerToFavorites(gameserveritem_t &server);
+	void AddServerToFavorites(newgameserver_t &server);
 
 	// begins the process of joining a server from a game list
 	// the game info dialog it opens will also update the game list
@@ -118,11 +118,12 @@ private:
 
 	// property sheet
 	vgui::PropertySheet *m_pTabPanel;
-	CFavoriteGames *m_pFavorites;
-	CHistoryGames *m_pHistory;
+
 	CInternetGames *m_pInternetGames;
 	//CSpectateGames *m_pSpectateGames;
 	CLanGames *m_pLanGames;
+	CFavoriteGames *m_pFavorites;
+	CHistoryGames *m_pHistory;
 
 	KeyValues *m_pSavedData;
 	KeyValues *m_pFilterData;
diff --git a/serverbrowser/ServerListCompare.cpp b/serverbrowser/ServerListCompare.cpp
index f17678bd..6e195f59 100644
--- a/serverbrowser/ServerListCompare.cpp
+++ b/serverbrowser/ServerListCompare.cpp
@@ -7,15 +7,15 @@
 
 #include "pch_serverbrowser.h"
 
-bool IsReplayServer( gameserveritem_t &server );
+bool IsReplayServer( newgameserver_t &server );
 
 //-----------------------------------------------------------------------------
 // Purpose: List password column sort function
 //-----------------------------------------------------------------------------
 int __cdecl PasswordCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
+	newgameserver_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
+	newgameserver_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
 
 	if ( !s1 && s2 ) 
 		return -1;
@@ -37,8 +37,8 @@ int __cdecl PasswordCompare(ListPanel *pPanel, const ListPanelItem &p1, const Li
 //-----------------------------------------------------------------------------
 int __cdecl BotsCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
+	newgameserver_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
+	newgameserver_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
 
 	if ( !s1 && s2 ) 
 		return -1;
@@ -60,21 +60,6 @@ int __cdecl BotsCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPa
 //-----------------------------------------------------------------------------
 int __cdecl SecureCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
-
-	if ( !s1 && s2 ) 
-		return -1;
-	if ( !s2 && s1 )
-		return 1;
-	if ( !s1 && !s2 )
-		return 0;
-
-	if ( s1->m_bSecure < s2->m_bSecure )
-		return 1;
-	else if ( s1->m_bSecure > s2->m_bSecure )
-		return -1;
-
 	return 0;
 }
 
@@ -83,8 +68,8 @@ int __cdecl SecureCompare(ListPanel *pPanel, const ListPanelItem &p1, const List
 //-----------------------------------------------------------------------------
 int __cdecl IPAddressCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
+	newgameserver_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
+	newgameserver_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
 
 	if ( !s1 && s2 ) 
 		return -1;
@@ -106,8 +91,8 @@ int __cdecl IPAddressCompare(ListPanel *pPanel, const ListPanelItem &p1, const L
 //-----------------------------------------------------------------------------
 int __cdecl PingCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
+	newgameserver_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
+	newgameserver_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
 
 	if ( !s1 && s2 ) 
 		return -1;
@@ -132,8 +117,8 @@ int __cdecl PingCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPa
 //-----------------------------------------------------------------------------
 int __cdecl MapCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
+	newgameserver_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
+	newgameserver_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
 
 	if ( !s1 && s2 ) 
 		return -1;
@@ -150,8 +135,8 @@ int __cdecl MapCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPan
 //-----------------------------------------------------------------------------
 int __cdecl GameCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
+	newgameserver_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
+	newgameserver_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
 
 	if ( !s1 && s2 ) 
 		return -1;
@@ -171,8 +156,8 @@ int __cdecl GameCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPa
 //-----------------------------------------------------------------------------
 int __cdecl ServerNameCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
+	newgameserver_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
+	newgameserver_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
 
 	if ( !s1 && s2 ) 
 		return -1;
@@ -181,7 +166,7 @@ int __cdecl ServerNameCompare(ListPanel *pPanel, const ListPanelItem &p1, const
 	if ( !s1 && !s2 )
 		return 0;
 
-	return Q_stricmp( s1->GetName(), s2->GetName() );
+	return Q_stricmp( s1->m_szServerName, s2->m_szServerName );
 }
 
 //-----------------------------------------------------------------------------
@@ -189,8 +174,8 @@ int __cdecl ServerNameCompare(ListPanel *pPanel, const ListPanelItem &p1, const
 //-----------------------------------------------------------------------------
 int __cdecl PlayersCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
+	newgameserver_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
+	newgameserver_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
 
 	if ( !s1 && s2 ) 
 		return -1;
@@ -224,22 +209,6 @@ int __cdecl PlayersCompare(ListPanel *pPanel, const ListPanelItem &p1, const Lis
 //-----------------------------------------------------------------------------
 int __cdecl LastPlayedCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer( p1.userData );
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer( p2.userData );
-
-	if ( !s1 && s2 ) 
-		return -1;
-	if ( !s2 && s1 )
-		return 1;
-	if ( !s1 && !s2 )
-		return 0;
-
-	// compare number of players
-	if ( s1->m_ulTimeLastPlayed > s2->m_ulTimeLastPlayed )
-		return -1;
-	if ( s1->m_ulTimeLastPlayed < s2->m_ulTimeLastPlayed )
-		return 1;
-
 	return 0;
 }
 
@@ -248,8 +217,8 @@ int __cdecl LastPlayedCompare(ListPanel *pPanel, const ListPanelItem &p1, const
 //-----------------------------------------------------------------------------
 int __cdecl TagsCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
+	newgameserver_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
+	newgameserver_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
 
 	if ( !s1 && s2 ) 
 		return -1;
@@ -266,8 +235,8 @@ int __cdecl TagsCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPa
 //-----------------------------------------------------------------------------
 int __cdecl ReplayCompare(ListPanel *pPanel, const ListPanelItem &p1, const ListPanelItem &p2)
 {
-	gameserveritem_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
-	gameserveritem_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
+	newgameserver_t *s1 = ServerBrowserDialog().GetServer(p1.userData);
+	newgameserver_t *s2 = ServerBrowserDialog().GetServer(p2.userData);
 
 	if ( !s1 && s2 ) 
 		return -1;
diff --git a/serverbrowser/igamelist.h b/serverbrowser/igamelist.h
index 3944c9b0..3be6fcda 100644
--- a/serverbrowser/igamelist.h
+++ b/serverbrowser/igamelist.h
@@ -20,7 +20,7 @@ class gameserveritem_t;
 #include "FindSteamServers.h"
 #endif
 #include "netadr.h"
-
+#include "engine/iserversinfo.h"
 
 typedef enum
 {
@@ -75,7 +75,7 @@ public:
 	virtual bool IsRefreshing() = 0;
 
 	// gets information about specified server
-	virtual gameserveritem_t *GetServer(unsigned int serverID) = 0;
+	virtual newgameserver_t *GetServer(unsigned int serverID) = 0;
 
 	// called when Connect button is pressed
 	virtual void OnBeginConnect() = 0;
diff --git a/serverbrowser/pch_serverbrowser.h b/serverbrowser/pch_serverbrowser.h
index 8e44f2ba..6812359c 100644
--- a/serverbrowser/pch_serverbrowser.h
+++ b/serverbrowser/pch_serverbrowser.h
@@ -69,7 +69,7 @@
 #include "replay/ienginereplay.h"
 
 extern bool GameSupportsReplay();
-extern bool IsReplayServer( gameserveritem_t &server );
+extern bool IsReplayServer( newgameserver_t &server );
 
 #pragma warning( disable: 4355 )  //  warning C4355: 'this' : used in base member initializer list
 

From 67ef35bb783b610c9ab511f8c03ea018e058d33a Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Sat, 11 Feb 2023 20:34:22 +0300
Subject: [PATCH 13/17] engine(masterserver): typo fix

---
 engine/masterserver.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/engine/masterserver.cpp b/engine/masterserver.cpp
index 300ffb39..42eb37ca 100644
--- a/engine/masterserver.cpp
+++ b/engine/masterserver.cpp
@@ -261,7 +261,6 @@ newgameserver_t &CMaster::ProcessInfo(bf_read &buf)
 
 	// Password?
 	s.m_bPassword = buf.ReadByte();
-m_iServersResponded
 	s.m_iFlags = buf.ReadLong();
 
 	if( s.m_iFlags & S2A_EXTRA_DATA_HAS_GAMETAG_DATA )

From c3417ca08da09a837a4fc5ce65db65ce487291bb Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Mon, 13 Feb 2023 00:27:40 +0300
Subject: [PATCH 14/17] engine: fix cmdrate/updaterate values

---
 engine/baseclient.cpp   | 2 +-
 engine/masterserver.cpp | 1 +
 engine/sv_client.cpp    | 4 ++--
 engine/sv_main.cpp      | 4 ++--
 4 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/engine/baseclient.cpp b/engine/baseclient.cpp
index ed81068f..4ec46652 100644
--- a/engine/baseclient.cpp
+++ b/engine/baseclient.cpp
@@ -1431,7 +1431,7 @@ void CBaseClient::UpdateUserSettings()
 	SetRate( rate, false );
 
 	// set server to client update rate
-	SetUpdateRate( m_ConVars->GetInt( "cl_updaterate", 20), false );
+	SetUpdateRate( m_ConVars->GetInt( "cl_updaterate", 60), false );
 
 	SetMaxRoutablePayloadSize( m_ConVars->GetInt( "net_maxroutable", MAX_ROUTABLE_PAYLOAD ) );
 
diff --git a/engine/masterserver.cpp b/engine/masterserver.cpp
index 42eb37ca..ced9aa81 100644
--- a/engine/masterserver.cpp
+++ b/engine/masterserver.cpp
@@ -161,6 +161,7 @@ void CMaster::RunFrame()
 	{
 		m_serverListResponse->RefreshComplete( NServerResponse::nServerFailedToRespond );
 		StopRefresh();
+		return;
 	}
 
 	if( m_iServersResponded > 0 &&
diff --git a/engine/sv_client.cpp b/engine/sv_client.cpp
index 6279a267..566cbeee 100644
--- a/engine/sv_client.cpp
+++ b/engine/sv_client.cpp
@@ -41,8 +41,8 @@ static ConVar	sv_timeout( "sv_timeout", "65", 0, "After this many seconds withou
 static ConVar	sv_maxrate( "sv_maxrate", "0", FCVAR_REPLICATED, "Max bandwidth rate allowed on server, 0 == unlimited" );
 static ConVar	sv_minrate( "sv_minrate", "3500", FCVAR_REPLICATED, "Min bandwidth rate allowed on server, 0 == unlimited" );
        
-       ConVar	sv_maxupdaterate( "sv_maxupdaterate", "66", FCVAR_REPLICATED, "Maximum updates per second that the server will allow" );
-	   ConVar	sv_minupdaterate( "sv_minupdaterate", "10", FCVAR_REPLICATED, "Minimum updates per second that the server will allow" );
+       ConVar	sv_maxupdaterate( "sv_maxupdaterate", "100", FCVAR_REPLICATED, "Maximum updates per second that the server will allow" );
+	   ConVar	sv_minupdaterate( "sv_minupdaterate", "20", FCVAR_REPLICATED, "Minimum updates per second that the server will allow" );
 
 	   ConVar	sv_stressbots("sv_stressbots", "0", FCVAR_DEVELOPMENTONLY, "If set to 1, the server calculates data and fills packets to bots. Used for perf testing.");
 static ConVar	sv_allowdownload ("sv_allowdownload", "1", 0, "Allow clients to download files");
diff --git a/engine/sv_main.cpp b/engine/sv_main.cpp
index 1456e44d..1d104966 100644
--- a/engine/sv_main.cpp
+++ b/engine/sv_main.cpp
@@ -218,8 +218,8 @@ static ConVar sv_voicecodec( "sv_voicecodec", "vaudio_opus", 0,
                              "steam - Use Steam voice API" );
 
 
-ConVar  sv_mincmdrate( "sv_mincmdrate", "10", FCVAR_REPLICATED, "This sets the minimum value for cl_cmdrate. 0 == unlimited." );
-ConVar  sv_maxcmdrate( "sv_maxcmdrate", "66", FCVAR_REPLICATED, "(If sv_mincmdrate is > 0), this sets the maximum value for cl_cmdrate." );
+ConVar  sv_mincmdrate( "sv_mincmdrate", "20", FCVAR_REPLICATED, "This sets the minimum value for cl_cmdrate. 0 == unlimited." );
+ConVar  sv_maxcmdrate( "sv_maxcmdrate", "100", FCVAR_REPLICATED, "(If sv_mincmdrate is > 0), this sets the maximum value for cl_cmdrate." );
 ConVar  sv_client_cmdrate_difference( "sv_client_cmdrate_difference", "20", FCVAR_REPLICATED, 
 	"cl_cmdrate is moved to within sv_client_cmdrate_difference units of cl_updaterate before it "
 	"is clamped between sv_mincmdrate and sv_maxcmdrate." );

From e10f29854ee2139901ee45e0c90f42da65f52ae7 Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Tue, 14 Feb 2023 20:22:18 +0300
Subject: [PATCH 15/17] engine(masterserver): fix servers duplication

---
 engine/master.h         |  2 +-
 engine/masterserver.cpp | 36 ++++++++++++++++++++----------------
 2 files changed, 21 insertions(+), 17 deletions(-)

diff --git a/engine/master.h b/engine/master.h
index 34a86ffe..1d5c5ad4 100644
--- a/engine/master.h
+++ b/engine/master.h
@@ -46,7 +46,7 @@ public:
 	// Master sent back a challenge value, read it and send the actual heartbeat
 	virtual void RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg ) = 0;
 	// Console command to set/remove master server
-	virtual void SetMaster_f( const CCommand &args ) = 0;
+	virtual void AddMaster_f( const CCommand &args ) = 0;
 	// Force a heartbeat to be issued right away
 	virtual void Heartbeat_f( void ) = 0;
 
diff --git a/engine/masterserver.cpp b/engine/masterserver.cpp
index ced9aa81..acdcf272 100644
--- a/engine/masterserver.cpp
+++ b/engine/masterserver.cpp
@@ -76,7 +76,7 @@ public:
 
 	void ProcessConnectionlessPacket( netpacket_t *packet );
 
-	void SetMaster_f( const CCommand &args );
+	void AddMaster_f( const CCommand &args );
 	void Heartbeat_f( void );
 
 	void RunFrame();
@@ -89,15 +89,15 @@ public:
 	void RequestInternetServerList( const char *gamedir, IServerListResponse *response );
 	void RequestLANServerList( const char *gamedir, IServerListResponse *response );
 	void AddServerAddresses( netadr_t **adr, int count );
-	void StopRefresh();
 	void RequestServerInfo( const netadr_t &adr );
+	void StopRefresh();
 
 private:
 	// List of known master servers
 	adrlist_t *m_pMasterAddresses;
 
 	bool m_bInitialized;
-	bool m_bWaitingForReplys;
+	bool m_bRefreshing;
 
 	int m_iServersResponded;
 
@@ -139,7 +139,7 @@ CMaster::CMaster( void )
 	m_serverListResponse = NULL;
 	SetDefLessFunc( m_serverAddresses );
 	SetDefLessFunc( m_serversRequestTime );
-	m_bWaitingForReplys = false;
+	m_bRefreshing = false;
 	m_iInfoSequence = 1;
 
 	Init();
@@ -153,14 +153,14 @@ void CMaster::RunFrame()
 {
 	CheckHeartbeat();
 
-	if( !m_bWaitingForReplys )
+	if( !m_bRefreshing )
 		return;
 
 	if( m_serverListResponse &&
-		m_flStartRequestTime < Plat_FloatTime()-INFO_REQUEST_TIMEOUT   )
+		m_flStartRequestTime < Plat_FloatTime()-INFO_REQUEST_TIMEOUT )
 	{
-		m_serverListResponse->RefreshComplete( NServerResponse::nServerFailedToRespond );
 		StopRefresh();
+		m_serverListResponse->RefreshComplete( NServerResponse::nServerFailedToRespond );
 		return;
 	}
 
@@ -190,11 +190,11 @@ void CMaster::RunFrame()
 
 void CMaster::StopRefresh()
 {
-	if( !m_bWaitingForReplys )
+	if( !m_bRefreshing )
 		return;
 
 	m_iServersResponded = 0;
-	m_bWaitingForReplys = false;
+	m_bRefreshing = false;
 	m_serverAddresses.RemoveAll();
 	m_serversRequestTime.RemoveAll();
 }
@@ -235,9 +235,7 @@ void CMaster::ReplyInfo( const netadr_t &adr, uint sequence )
 	buf.PutUnsignedInt( nFlags );
 
 	if ( nFlags & S2A_EXTRA_DATA_HAS_GAMETAG_DATA )
-	{
 		buf.PutString( pchTags );
-	}
 
 	NET_SendPacket( NULL, NS_SERVER, adr, (unsigned char *)buf.Base(), buf.TellPut() );
 }
@@ -293,6 +291,9 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 		}
 		case M2C_QUERY:
 		{
+			if( !m_bRefreshing )
+				break;
+
 			ip = msg.ReadLong();
 			port = msg.ReadShort();
 
@@ -323,6 +324,9 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
 		}
 		case S2C_INFOREPLY:
 		{
+			if( !m_bRefreshing )
+				break;
+
 			uint sequence = msg.ReadLong();
 			newgameserver_t &s = ProcessInfo( msg );
 
@@ -584,7 +588,7 @@ void CMaster::RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg )
 //-----------------------------------------------------------------------------
 // Purpose: Add/remove master servers
 //-----------------------------------------------------------------------------
-void CMaster::SetMaster_f ( const CCommand &args )
+void CMaster::AddMaster_f ( const CCommand &args )
 {
 	CUtlString cmd( ( args.ArgC() > 1 ) ? args[ 1 ] : "" );
 
@@ -620,9 +624,9 @@ void CMaster::Heartbeat_f (void)
 //-----------------------------------------------------------------------------
 // Purpose: 
 //-----------------------------------------------------------------------------
-void SetMaster_f( const CCommand &args )
+void AddMaster_f( const CCommand &args )
 {
-	master->SetMaster_f( args );
+	master->AddMaster_f( args );
 }
 
 //-----------------------------------------------------------------------------
@@ -633,7 +637,7 @@ void Heartbeat1_f( void )
 	master->Heartbeat_f();
 }
 
-static ConCommand setmaster("setmaster", SetMaster_f );
+static ConCommand setmaster("addmaster", AddMaster_f );
 static ConCommand heartbeat("heartbeat", Heartbeat1_f, "Force heartbeat of master servers" ); 
 
 //-----------------------------------------------------------------------------
@@ -679,7 +683,7 @@ void CMaster::RequestInternetServerList(const char *gamedir, IServerListResponse
 	if( response )
 	{
 		StopRefresh();
-		m_bWaitingForReplys = true;
+		m_bRefreshing = true;
 		m_serverListResponse = response;
 		m_flRetryRequestTime = m_flStartRequestTime = m_flMasterRequestTime = Plat_FloatTime();
 	}

From e4f5549cbd4f5c9eaa8b952f3a1db40fdf8942e1 Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Thu, 16 Feb 2023 17:16:35 +0300
Subject: [PATCH 16/17] serverbrowser: copy gametype to map name in quicklist

---
 serverbrowser/QuickListPanel.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/serverbrowser/QuickListPanel.cpp b/serverbrowser/QuickListPanel.cpp
index 0b08ca02..19c17bb0 100644
--- a/serverbrowser/QuickListPanel.cpp
+++ b/serverbrowser/QuickListPanel.cpp
@@ -165,16 +165,16 @@ void CQuickListPanel::SetMapName( const char *pMapName )
 //-----------------------------------------------------------------------------
 void CQuickListPanel::SetGameType( const char *pGameType )
 {
-	if ( strlen ( pGameType ) == 0 )
-	{
-		m_pGameTypeLabel->SetVisible( false );
+	m_pGameTypeLabel->SetVisible( false );
+
+	if ( strlen ( pGameType ) == 0 || !m_pMapNameLabel )
 		return;
-	}
 
 	char gametype[ 512 ];
-	Q_snprintf( gametype, sizeof( gametype ), "(%s)", pGameType );
+	Q_snprintf( gametype, sizeof( gametype ), "%s (%s)", m_szMapName, pGameType );
 
-	m_pGameTypeLabel->SetText( gametype );
+	m_pMapNameLabel->SetText( gametype );
+	m_pMapNameLabel->SizeToContents();
 }
 
 //-----------------------------------------------------------------------------

From 2aa14bb24c8f7b4f60bd22ad3667627f837d8974 Mon Sep 17 00:00:00 2001
From: nillerusr <nillerusr@gmail.com>
Date: Thu, 16 Feb 2023 17:30:53 +0300
Subject: [PATCH 17/17] restore threadtools and vstdlib from 12716fd commit

---
 public/tier0/threadtools.h | 44 +++++++++++++++++++++++++++----
 tier0/threadtools.cpp      | 53 --------------------------------------
 vstdlib/jobthread.cpp      | 20 ++++----------
 3 files changed, 44 insertions(+), 73 deletions(-)

diff --git a/public/tier0/threadtools.h b/public/tier0/threadtools.h
index 2b18dda7..b7216193 100644
--- a/public/tier0/threadtools.h
+++ b/public/tier0/threadtools.h
@@ -52,6 +52,12 @@
 #pragma once
 #pragma warning(push)
 #pragma warning(disable:4251)
+
+extern "C"
+{
+	void __declspec(dllimport) __stdcall Sleep( unsigned long );
+}
+
 #endif
 
 #ifdef COMPILER_MSVC64
@@ -194,8 +200,6 @@ PLATFORM_INTERFACE bool ReleaseThreadHandle( ThreadHandle_t );
 
 //-----------------------------------------------------------------------------
 
-PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0);
-PLATFORM_INTERFACE void ThreadNanoSleep(unsigned ns);
 PLATFORM_INTERFACE ThreadId_t ThreadGetCurrentId();
 PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle();
 PLATFORM_INTERFACE int ThreadGetPriority( ThreadHandle_t hThread = NULL );
@@ -229,10 +233,10 @@ inline void ThreadPause()
 {
 #if defined( COMPILER_PS3 )
 	__db16cyc();
-#elif defined(__arm__) || defined(__aarch64__)
-        sched_yield();
-#elif defined( COMPILER_GCC )
+#elif defined( COMPILER_GCC ) && (defined( __i386__ ) || defined( __x86_64__ ))
 	__asm __volatile( "pause" );
+#elif defined( POSIX )
+        sched_yield();
 #elif defined ( COMPILER_MSVC64 )
 	_mm_pause();
 #elif defined( COMPILER_MSVC32 )
@@ -247,6 +251,36 @@ inline void ThreadPause()
 #endif
 }
 
+inline void ThreadSleep(unsigned nMilliseconds = 0)
+{
+	if( nMilliseconds == 0 )
+	{
+		ThreadPause();
+		return;
+        }
+
+#ifdef _WIN32
+
+#ifdef _WIN32_PC
+        static bool bInitialized = false;
+        if ( !bInitialized )
+        {
+                bInitialized = true;
+                // Set the timer resolution to 1 ms (default is 10.0, 15.6, 2.5, 1.0 or
+                // some other value depending on hardware and software) so that we can
+                // use Sleep( 1 ) to avoid wasting CPU time without missing our frame
+                // rate.
+                timeBeginPeriod( 1 );
+        }
+#endif
+	Sleep( nMilliseconds );
+#elif PS3
+	sys_timer_usleep( nMilliseconds * 1000 );
+#elif defined(POSIX)
+        usleep( nMilliseconds * 1000 );
+#endif
+}
+
 PLATFORM_INTERFACE bool ThreadJoin( ThreadHandle_t, unsigned timeout = TT_INFINITE );
 
 PLATFORM_INTERFACE void ThreadSetDebugName( ThreadHandle_t hThread, const char *pszName );
diff --git a/tier0/threadtools.cpp b/tier0/threadtools.cpp
index b0dbb645..06c8296f 100644
--- a/tier0/threadtools.cpp
+++ b/tier0/threadtools.cpp
@@ -485,59 +485,6 @@ bool ReleaseThreadHandle( ThreadHandle_t hThread )
 //
 //-----------------------------------------------------------------------------
 
-void ThreadSleep(unsigned nMilliseconds)
-{
-#ifdef _WIN32
-
-#ifdef _WIN32_PC
-	static bool bInitialized = false;
-	if ( !bInitialized )
-	{
-		bInitialized = true;
-		// Set the timer resolution to 1 ms (default is 10.0, 15.6, 2.5, 1.0 or
-		// some other value depending on hardware and software) so that we can
-		// use Sleep( 1 ) to avoid wasting CPU time without missing our frame
-		// rate.
-		timeBeginPeriod( 1 );
-	}
-#endif
-
-	Sleep( nMilliseconds );
-#elif PS3
-	if( nMilliseconds == 0 )
-	{
-		// sys_ppu_thread_yield doesn't seem to function properly, so sleep instead.
-//		sys_timer_usleep( 60 );
-		sys_ppu_thread_yield();
-	}
-	else
-	{
-		sys_timer_usleep( nMilliseconds * 1000 );
-	}
-#elif defined(POSIX)
-   usleep( nMilliseconds * 1000 ); 
-#endif
-}
-
-//-----------------------------------------------------------------------------
-void ThreadNanoSleep(unsigned ns)
-{
-#ifdef _WIN32
-	// ceil
-	Sleep( ( ns + 999 ) / 1000 );
-#elif PS3
-	sys_timer_usleep( ns );
-#elif defined(POSIX)
-	struct timespec tm;
-	tm.tv_sec = 0;
-	tm.tv_nsec = ns;
-	nanosleep( &tm, NULL ); 
-#endif
-}
-
-
-//-----------------------------------------------------------------------------
-
 #ifndef ThreadGetCurrentId
 ThreadId_t ThreadGetCurrentId()
 {
diff --git a/vstdlib/jobthread.cpp b/vstdlib/jobthread.cpp
index 922b770f..634d5358 100644
--- a/vstdlib/jobthread.cpp
+++ b/vstdlib/jobthread.cpp
@@ -214,7 +214,11 @@ public:
 	//-----------------------------------------------------
 	virtual int YieldWait( CThreadEvent **pEvents, int nEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE );
 	virtual int YieldWait( CJob **, int nJobs, bool bWaitAll = true, unsigned timeout = TT_INFINITE );
-	void Yield( unsigned timeout );
+	inline void Yield( unsigned timeout )
+	{
+		Assert( ThreadInMainThread() );
+		ThreadSleep( timeout );
+	}
 
 	//-----------------------------------------------------
 	// Add a native job to the queue (master thread)
@@ -656,20 +660,6 @@ int CThreadPool::YieldWait( CJob **ppJobs, int nJobs, bool bWaitAll, unsigned ti
 	return YieldWait( handles.Base(), handles.Count(), bWaitAll, timeout);
 }
 
-//---------------------------------------------------------
-
-void CThreadPool::Yield( unsigned timeout )
-{
-	// @MULTICORE (toml 10/24/2006): not implemented
-	Assert( ThreadInMainThread() );
-	if ( !ThreadInMainThread() )
-	{
-		ThreadSleep( timeout );
-		return;
-	}
-	ThreadSleep( timeout );
-}
-
 //---------------------------------------------------------
 // Add a job to the queue
 //---------------------------------------------------------