2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2011-11-29 21:18:40 +00:00
# include <algorithm> // sort TODO: remove this
2010-05-29 07:25:38 +00:00
2011-01-19 14:54:50 +00:00
# include <base/math.h>
2010-05-29 07:25:38 +00:00
# include <base/system.h>
2011-03-23 12:06:35 +00:00
2010-05-29 07:25:38 +00:00
# include <engine/shared/config.h>
# include <engine/shared/memheap.h>
2011-03-23 12:06:35 +00:00
# include <engine/shared/network.h>
# include <engine/shared/protocol.h>
2010-05-29 07:25:38 +00:00
# include <engine/config.h>
2011-03-23 12:06:35 +00:00
# include <engine/console.h>
# include <engine/friends.h>
# include <engine/masterserver.h>
2010-05-29 07:25:38 +00:00
# include <mastersrv/mastersrv.h>
2011-03-27 16:00:54 +00:00
# include "serverbrowser.h"
2010-05-29 07:25:38 +00:00
class SortWrap
{
typedef bool ( CServerBrowser : : * SortFunc ) ( int , int ) const ;
SortFunc m_pfnSort ;
CServerBrowser * m_pThis ;
public :
SortWrap ( CServerBrowser * t , SortFunc f ) : m_pfnSort ( f ) , m_pThis ( t ) { }
2011-11-29 21:34:47 +00:00
bool operator ( ) ( int a , int b ) { return ( g_Config . m_BrSortOrder ? ( m_pThis - > * m_pfnSort ) ( b , a ) : ( m_pThis - > * m_pfnSort ) ( a , b ) ) ; }
2010-05-29 07:25:38 +00:00
} ;
CServerBrowser : : CServerBrowser ( )
{
m_pMasterServer = 0 ;
m_ppServerlist = 0 ;
m_pSortedServerlist = 0 ;
m_NumFavoriteServers = 0 ;
mem_zero ( m_aServerlistIp , sizeof ( m_aServerlistIp ) ) ;
m_pFirstReqServer = 0 ; // request list
m_pLastReqServer = 0 ;
m_NumRequests = 0 ;
m_NeedRefresh = 0 ;
m_NumSortedServers = 0 ;
m_NumSortedServersCapacity = 0 ;
m_NumServers = 0 ;
m_NumServerCapacity = 0 ;
m_Sorthash = 0 ;
m_aFilterString [ 0 ] = 0 ;
m_aFilterGametypeString [ 0 ] = 0 ;
// the token is to keep server refresh separated from each other
m_CurrentToken = 1 ;
m_ServerlistType = 0 ;
m_BroadcastTime = 0 ;
}
void CServerBrowser : : SetBaseInfo ( class CNetClient * pClient , const char * pNetVersion )
{
m_pNetClient = pClient ;
str_copy ( m_aNetVersion , pNetVersion , sizeof ( m_aNetVersion ) ) ;
m_pMasterServer = Kernel ( ) - > RequestInterface < IMasterServer > ( ) ;
2010-08-17 22:06:00 +00:00
m_pConsole = Kernel ( ) - > RequestInterface < IConsole > ( ) ;
2011-03-23 12:06:35 +00:00
m_pFriends = Kernel ( ) - > RequestInterface < IFriends > ( ) ;
2010-05-29 07:25:38 +00:00
IConfig * pConfig = Kernel ( ) - > RequestInterface < IConfig > ( ) ;
if ( pConfig )
pConfig - > RegisterCallback ( ConfigSaveCallback , this ) ;
}
const CServerInfo * CServerBrowser : : SortedGet ( int Index ) const
{
if ( Index < 0 | | Index > = m_NumSortedServers )
return 0 ;
return & m_ppServerlist [ m_pSortedServerlist [ Index ] ] - > m_Info ;
}
bool CServerBrowser : : SortCompareName ( int Index1 , int Index2 ) const
{
CServerEntry * a = m_ppServerlist [ Index1 ] ;
CServerEntry * b = m_ppServerlist [ Index2 ] ;
2010-08-12 17:29:59 +00:00
// make sure empty entries are listed last
2011-04-13 18:37:12 +00:00
return ( a - > m_GotInfo & & b - > m_GotInfo ) | | ( ! a - > m_GotInfo & & ! b - > m_GotInfo ) ? str_comp ( a - > m_Info . m_aName , b - > m_Info . m_aName ) < 0 :
2010-08-12 17:29:59 +00:00
a - > m_GotInfo ? true : false ;
2010-05-29 07:25:38 +00:00
}
bool CServerBrowser : : SortCompareMap ( int Index1 , int Index2 ) const
{
CServerEntry * a = m_ppServerlist [ Index1 ] ;
CServerEntry * b = m_ppServerlist [ Index2 ] ;
return str_comp ( a - > m_Info . m_aMap , b - > m_Info . m_aMap ) < 0 ;
}
bool CServerBrowser : : SortComparePing ( int Index1 , int Index2 ) const
{
CServerEntry * a = m_ppServerlist [ Index1 ] ;
CServerEntry * b = m_ppServerlist [ Index2 ] ;
return a - > m_Info . m_Latency < b - > m_Info . m_Latency ;
}
bool CServerBrowser : : SortCompareGametype ( int Index1 , int Index2 ) const
{
CServerEntry * a = m_ppServerlist [ Index1 ] ;
CServerEntry * b = m_ppServerlist [ Index2 ] ;
return str_comp ( a - > m_Info . m_aGameType , b - > m_Info . m_aGameType ) < 0 ;
}
bool CServerBrowser : : SortCompareNumPlayers ( int Index1 , int Index2 ) const
{
CServerEntry * a = m_ppServerlist [ Index1 ] ;
CServerEntry * b = m_ppServerlist [ Index2 ] ;
return a - > m_Info . m_NumPlayers < b - > m_Info . m_NumPlayers ;
}
2011-03-20 14:33:49 +00:00
bool CServerBrowser : : SortCompareNumClients ( int Index1 , int Index2 ) const
{
CServerEntry * a = m_ppServerlist [ Index1 ] ;
CServerEntry * b = m_ppServerlist [ Index2 ] ;
return a - > m_Info . m_NumClients < b - > m_Info . m_NumClients ;
}
2010-05-29 07:25:38 +00:00
void CServerBrowser : : Filter ( )
{
int i = 0 , p = 0 ;
m_NumSortedServers = 0 ;
// allocate the sorted list
if ( m_NumSortedServersCapacity < m_NumServers )
{
if ( m_pSortedServerlist )
mem_free ( m_pSortedServerlist ) ;
m_NumSortedServersCapacity = m_NumServers ;
m_pSortedServerlist = ( int * ) mem_alloc ( m_NumSortedServersCapacity * sizeof ( int ) , 1 ) ;
}
// filter the servers
for ( i = 0 ; i < m_NumServers ; i + + )
{
int Filtered = 0 ;
2011-06-26 15:10:13 +00:00
if ( g_Config . m_BrFilterEmpty & & ( ( g_Config . m_BrFilterSpectators & & m_ppServerlist [ i ] - > m_Info . m_NumPlayers = = 0 ) | | m_ppServerlist [ i ] - > m_Info . m_NumClients = = 0 ) )
Filtered = 1 ;
else if ( g_Config . m_BrFilterFull & & ( ( g_Config . m_BrFilterSpectators & & m_ppServerlist [ i ] - > m_Info . m_NumPlayers = = m_ppServerlist [ i ] - > m_Info . m_MaxPlayers ) | |
m_ppServerlist [ i ] - > m_Info . m_NumClients = = m_ppServerlist [ i ] - > m_Info . m_MaxClients ) )
Filtered = 1 ;
else if ( g_Config . m_BrFilterPw & & m_ppServerlist [ i ] - > m_Info . m_Flags & SERVER_FLAG_PASSWORD )
Filtered = 1 ;
else if ( g_Config . m_BrFilterPure & &
( str_comp ( m_ppServerlist [ i ] - > m_Info . m_aGameType , " DM " ) ! = 0 & &
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aGameType , " TDM " ) ! = 0 & &
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aGameType , " CTF " ) ! = 0 ) )
2010-05-29 07:25:38 +00:00
{
2011-03-31 19:22:12 +00:00
Filtered = 1 ;
2010-05-29 07:25:38 +00:00
}
2011-06-26 15:10:13 +00:00
else if ( g_Config . m_BrFilterPureMap & &
! ( str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " dm1 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " dm2 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " dm6 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " dm7 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " dm8 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " dm9 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " ctf1 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " ctf2 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " ctf3 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " ctf4 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " ctf5 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " ctf6 " ) = = 0 | |
str_comp ( m_ppServerlist [ i ] - > m_Info . m_aMap , " ctf7 " ) = = 0 )
)
2011-03-23 12:06:35 +00:00
{
2011-06-26 15:10:13 +00:00
Filtered = 1 ;
}
else if ( g_Config . m_BrFilterPing < m_ppServerlist [ i ] - > m_Info . m_Latency )
Filtered = 1 ;
else if ( g_Config . m_BrFilterCompatversion & & str_comp_num ( m_ppServerlist [ i ] - > m_Info . m_aVersion , m_aNetVersion , 3 ) ! = 0 )
Filtered = 1 ;
else if ( g_Config . m_BrFilterServerAddress [ 0 ] & & ! str_find_nocase ( m_ppServerlist [ i ] - > m_Info . m_aAddress , g_Config . m_BrFilterServerAddress ) )
Filtered = 1 ;
else if ( g_Config . m_BrFilterGametypeStrict & & g_Config . m_BrFilterGametype [ 0 ] & & str_comp_nocase ( m_ppServerlist [ i ] - > m_Info . m_aGameType , g_Config . m_BrFilterGametype ) )
Filtered = 1 ;
else if ( ! g_Config . m_BrFilterGametypeStrict & & g_Config . m_BrFilterGametype [ 0 ] & & ! str_find_nocase ( m_ppServerlist [ i ] - > m_Info . m_aGameType , g_Config . m_BrFilterGametype ) )
Filtered = 1 ;
2011-06-29 20:27:32 +00:00
else
2011-06-26 15:10:13 +00:00
{
2011-06-29 20:27:32 +00:00
if ( g_Config . m_BrFilterCountry )
2011-06-26 15:10:13 +00:00
{
2011-06-29 20:27:32 +00:00
Filtered = 1 ;
// match against player country
for ( p = 0 ; p < m_ppServerlist [ i ] - > m_Info . m_NumClients ; p + + )
{
if ( m_ppServerlist [ i ] - > m_Info . m_aClients [ p ] . m_Country = = g_Config . m_BrFilterCountryIndex )
{
Filtered = 0 ;
break ;
}
}
2011-06-26 15:10:13 +00:00
}
2011-03-18 18:03:13 +00:00
2011-06-29 20:27:32 +00:00
if ( ! Filtered & & g_Config . m_BrFilterString [ 0 ] ! = 0 )
2011-06-26 15:10:13 +00:00
{
2011-06-29 20:27:32 +00:00
int MatchFound = 0 ;
m_ppServerlist [ i ] - > m_Info . m_QuickSearchHit = 0 ;
// match against server name
if ( str_find_nocase ( m_ppServerlist [ i ] - > m_Info . m_aName , g_Config . m_BrFilterString ) )
2011-03-23 12:06:35 +00:00
{
MatchFound = 1 ;
2011-06-29 20:27:32 +00:00
m_ppServerlist [ i ] - > m_Info . m_QuickSearchHit | = IServerBrowser : : QUICK_SERVERNAME ;
2011-03-23 12:06:35 +00:00
}
2011-06-29 20:27:32 +00:00
// match against players
for ( p = 0 ; p < m_ppServerlist [ i ] - > m_Info . m_NumClients ; p + + )
{
if ( str_find_nocase ( m_ppServerlist [ i ] - > m_Info . m_aClients [ p ] . m_aName , g_Config . m_BrFilterString ) | |
str_find_nocase ( m_ppServerlist [ i ] - > m_Info . m_aClients [ p ] . m_aClan , g_Config . m_BrFilterString ) )
{
MatchFound = 1 ;
m_ppServerlist [ i ] - > m_Info . m_QuickSearchHit | = IServerBrowser : : QUICK_PLAYER ;
break ;
}
}
2011-06-26 15:10:13 +00:00
2011-06-29 20:27:32 +00:00
// match against map
if ( str_find_nocase ( m_ppServerlist [ i ] - > m_Info . m_aMap , g_Config . m_BrFilterString ) )
{
MatchFound = 1 ;
m_ppServerlist [ i ] - > m_Info . m_QuickSearchHit | = IServerBrowser : : QUICK_MAPNAME ;
}
if ( ! MatchFound )
Filtered = 1 ;
}
2010-05-29 07:25:38 +00:00
}
if ( Filtered = = 0 )
2011-06-26 15:10:13 +00:00
{
// check for friend
m_ppServerlist [ i ] - > m_Info . m_FriendState = IFriends : : FRIEND_NO ;
for ( p = 0 ; p < m_ppServerlist [ i ] - > m_Info . m_NumClients ; p + + )
{
m_ppServerlist [ i ] - > m_Info . m_aClients [ p ] . m_FriendState = m_pFriends - > GetFriendState ( m_ppServerlist [ i ] - > m_Info . m_aClients [ p ] . m_aName ,
m_ppServerlist [ i ] - > m_Info . m_aClients [ p ] . m_aClan ) ;
m_ppServerlist [ i ] - > m_Info . m_FriendState = max ( m_ppServerlist [ i ] - > m_Info . m_FriendState , m_ppServerlist [ i ] - > m_Info . m_aClients [ p ] . m_FriendState ) ;
}
if ( ! g_Config . m_BrFilterFriends | | m_ppServerlist [ i ] - > m_Info . m_FriendState ! = IFriends : : FRIEND_NO )
m_pSortedServerlist [ m_NumSortedServers + + ] = i ;
}
2010-05-29 07:25:38 +00:00
}
}
int CServerBrowser : : SortHash ( ) const
{
int i = g_Config . m_BrSort & 0xf ;
i | = g_Config . m_BrFilterEmpty < < 4 ;
i | = g_Config . m_BrFilterFull < < 5 ;
2011-03-20 15:09:44 +00:00
i | = g_Config . m_BrFilterSpectators < < 6 ;
2011-03-23 12:06:35 +00:00
i | = g_Config . m_BrFilterFriends < < 7 ;
i | = g_Config . m_BrFilterPw < < 8 ;
i | = g_Config . m_BrSortOrder < < 9 ;
i | = g_Config . m_BrFilterCompatversion < < 10 ;
i | = g_Config . m_BrFilterPure < < 11 ;
i | = g_Config . m_BrFilterPureMap < < 12 ;
2011-04-17 09:57:33 +00:00
i | = g_Config . m_BrFilterGametypeStrict < < 13 ;
2011-06-29 20:27:32 +00:00
i | = g_Config . m_BrFilterCountry < < 14 ;
i | = g_Config . m_BrFilterPing < < 15 ;
2010-05-29 07:25:38 +00:00
return i ;
}
void CServerBrowser : : Sort ( )
{
int i ;
// create filtered list
Filter ( ) ;
// sort
if ( g_Config . m_BrSort = = IServerBrowser : : SORT_NAME )
2011-11-03 03:17:04 +00:00
std : : stable_sort ( m_pSortedServerlist , m_pSortedServerlist + m_NumSortedServers , SortWrap ( this , & CServerBrowser : : SortCompareName ) ) ;
2010-05-29 07:25:38 +00:00
else if ( g_Config . m_BrSort = = IServerBrowser : : SORT_PING )
2011-11-03 03:17:04 +00:00
std : : stable_sort ( m_pSortedServerlist , m_pSortedServerlist + m_NumSortedServers , SortWrap ( this , & CServerBrowser : : SortComparePing ) ) ;
2010-05-29 07:25:38 +00:00
else if ( g_Config . m_BrSort = = IServerBrowser : : SORT_MAP )
2011-11-03 03:17:04 +00:00
std : : stable_sort ( m_pSortedServerlist , m_pSortedServerlist + m_NumSortedServers , SortWrap ( this , & CServerBrowser : : SortCompareMap ) ) ;
2010-05-29 07:25:38 +00:00
else if ( g_Config . m_BrSort = = IServerBrowser : : SORT_NUMPLAYERS )
2011-11-03 03:17:04 +00:00
std : : stable_sort ( m_pSortedServerlist , m_pSortedServerlist + m_NumSortedServers , SortWrap ( this ,
2011-03-20 14:33:49 +00:00
g_Config . m_BrFilterSpectators ? & CServerBrowser : : SortCompareNumPlayers : & CServerBrowser : : SortCompareNumClients ) ) ;
2010-05-29 07:25:38 +00:00
else if ( g_Config . m_BrSort = = IServerBrowser : : SORT_GAMETYPE )
2011-11-03 03:17:04 +00:00
std : : stable_sort ( m_pSortedServerlist , m_pSortedServerlist + m_NumSortedServers , SortWrap ( this , & CServerBrowser : : SortCompareGametype ) ) ;
2010-05-29 07:25:38 +00:00
// set indexes
for ( i = 0 ; i < m_NumSortedServers ; i + + )
m_ppServerlist [ m_pSortedServerlist [ i ] ] - > m_Info . m_SortedIndex = i ;
str_copy ( m_aFilterGametypeString , g_Config . m_BrFilterGametype , sizeof ( m_aFilterGametypeString ) ) ;
str_copy ( m_aFilterString , g_Config . m_BrFilterString , sizeof ( m_aFilterString ) ) ;
m_Sorthash = SortHash ( ) ;
}
void CServerBrowser : : RemoveRequest ( CServerEntry * pEntry )
{
if ( pEntry - > m_pPrevReq | | pEntry - > m_pNextReq | | m_pFirstReqServer = = pEntry )
{
if ( pEntry - > m_pPrevReq )
pEntry - > m_pPrevReq - > m_pNextReq = pEntry - > m_pNextReq ;
else
m_pFirstReqServer = pEntry - > m_pNextReq ;
if ( pEntry - > m_pNextReq )
pEntry - > m_pNextReq - > m_pPrevReq = pEntry - > m_pPrevReq ;
else
m_pLastReqServer = pEntry - > m_pPrevReq ;
pEntry - > m_pPrevReq = 0 ;
pEntry - > m_pNextReq = 0 ;
m_NumRequests - - ;
}
}
CServerBrowser : : CServerEntry * CServerBrowser : : Find ( const NETADDR & Addr )
{
CServerEntry * pEntry = m_aServerlistIp [ Addr . ip [ 0 ] ] ;
for ( ; pEntry ; pEntry = pEntry - > m_pNextIp )
{
if ( net_addr_comp ( & pEntry - > m_Addr , & Addr ) = = 0 )
return pEntry ;
}
return ( CServerEntry * ) 0 ;
}
void CServerBrowser : : QueueRequest ( CServerEntry * pEntry )
{
// add it to the list of servers that we should request info from
pEntry - > m_pPrevReq = m_pLastReqServer ;
if ( m_pLastReqServer )
m_pLastReqServer - > m_pNextReq = pEntry ;
else
m_pFirstReqServer = pEntry ;
m_pLastReqServer = pEntry ;
2013-12-31 01:34:33 +00:00
pEntry - > m_pNextReq = 0 ;
2010-05-29 07:25:38 +00:00
m_NumRequests + + ;
}
void CServerBrowser : : SetInfo ( CServerEntry * pEntry , const CServerInfo & Info )
{
int Fav = pEntry - > m_Info . m_Favorite ;
pEntry - > m_Info = Info ;
pEntry - > m_Info . m_Favorite = Fav ;
pEntry - > m_Info . m_NetAddr = pEntry - > m_Addr ;
// all these are just for nice compability
if ( pEntry - > m_Info . m_aGameType [ 0 ] = = ' 0 ' & & pEntry - > m_Info . m_aGameType [ 1 ] = = 0 )
str_copy ( pEntry - > m_Info . m_aGameType , " DM " , sizeof ( pEntry - > m_Info . m_aGameType ) ) ;
else if ( pEntry - > m_Info . m_aGameType [ 0 ] = = ' 1 ' & & pEntry - > m_Info . m_aGameType [ 1 ] = = 0 )
str_copy ( pEntry - > m_Info . m_aGameType , " TDM " , sizeof ( pEntry - > m_Info . m_aGameType ) ) ;
else if ( pEntry - > m_Info . m_aGameType [ 0 ] = = ' 2 ' & & pEntry - > m_Info . m_aGameType [ 1 ] = = 0 )
str_copy ( pEntry - > m_Info . m_aGameType , " CTF " , sizeof ( pEntry - > m_Info . m_aGameType ) ) ;
/*if(!request)
{
pEntry - > m_Info . latency = ( time_get ( ) - pEntry - > request_time ) * 1000 / time_freq ( ) ;
RemoveRequest ( pEntry ) ;
} */
pEntry - > m_GotInfo = 1 ;
}
CServerBrowser : : CServerEntry * CServerBrowser : : Add ( const NETADDR & Addr )
{
int Hash = Addr . ip [ 0 ] ;
CServerEntry * pEntry = 0 ;
int i ;
// create new pEntry
pEntry = ( CServerEntry * ) m_ServerlistHeap . Allocate ( sizeof ( CServerEntry ) ) ;
mem_zero ( pEntry , sizeof ( CServerEntry ) ) ;
// set the info
pEntry - > m_Addr = Addr ;
pEntry - > m_Info . m_NetAddr = Addr ;
pEntry - > m_Info . m_Latency = 999 ;
2011-12-29 22:36:53 +00:00
net_addr_str ( & Addr , pEntry - > m_Info . m_aAddress , sizeof ( pEntry - > m_Info . m_aAddress ) , true ) ;
2011-03-30 10:08:33 +00:00
str_copy ( pEntry - > m_Info . m_aName , pEntry - > m_Info . m_aAddress , sizeof ( pEntry - > m_Info . m_aName ) ) ;
2010-05-29 07:25:38 +00:00
// check if it's a favorite
for ( i = 0 ; i < m_NumFavoriteServers ; i + + )
{
if ( net_addr_comp ( & Addr , & m_aFavoriteServers [ i ] ) = = 0 )
pEntry - > m_Info . m_Favorite = 1 ;
}
// add to the hash list
pEntry - > m_pNextIp = m_aServerlistIp [ Hash ] ;
m_aServerlistIp [ Hash ] = pEntry ;
if ( m_NumServers = = m_NumServerCapacity )
{
CServerEntry * * ppNewlist ;
m_NumServerCapacity + = 100 ;
ppNewlist = ( CServerEntry * * ) mem_alloc ( m_NumServerCapacity * sizeof ( CServerEntry * ) , 1 ) ;
mem_copy ( ppNewlist , m_ppServerlist , m_NumServers * sizeof ( CServerEntry * ) ) ;
mem_free ( m_ppServerlist ) ;
m_ppServerlist = ppNewlist ;
}
// add to list
m_ppServerlist [ m_NumServers ] = pEntry ;
pEntry - > m_Info . m_ServerIndex = m_NumServers ;
m_NumServers + + ;
return pEntry ;
}
void CServerBrowser : : Set ( const NETADDR & Addr , int Type , int Token , const CServerInfo * pInfo )
{
2013-12-31 01:34:33 +00:00
static int temp = 0 ;
2010-05-29 07:25:38 +00:00
CServerEntry * pEntry = 0 ;
if ( Type = = IServerBrowser : : SET_MASTER_ADD )
{
if ( m_ServerlistType ! = IServerBrowser : : TYPE_INTERNET )
return ;
2013-12-31 01:34:33 +00:00
m_LastPacketTick = 0 ;
2014-01-10 15:19:46 +00:00
+ + temp ;
2010-05-29 07:25:38 +00:00
if ( ! Find ( Addr ) )
{
pEntry = Add ( Addr ) ;
QueueRequest ( pEntry ) ;
}
}
else if ( Type = = IServerBrowser : : SET_FAV_ADD )
{
if ( m_ServerlistType ! = IServerBrowser : : TYPE_FAVORITES )
return ;
if ( ! Find ( Addr ) )
{
pEntry = Add ( Addr ) ;
QueueRequest ( pEntry ) ;
}
}
else if ( Type = = IServerBrowser : : SET_TOKEN )
{
if ( Token ! = m_CurrentToken )
return ;
pEntry = Find ( Addr ) ;
if ( ! pEntry )
pEntry = Add ( Addr ) ;
if ( pEntry )
{
SetInfo ( pEntry , * pInfo ) ;
if ( m_ServerlistType = = IServerBrowser : : TYPE_LAN )
2011-01-19 14:54:50 +00:00
pEntry - > m_Info . m_Latency = min ( static_cast < int > ( ( time_get ( ) - m_BroadcastTime ) * 1000 / time_freq ( ) ) , 999 ) ;
2014-05-03 18:57:19 +00:00
else if ( pEntry - > m_RequestTime > 0 )
{
2011-01-19 14:54:50 +00:00
pEntry - > m_Info . m_Latency = min ( static_cast < int > ( ( time_get ( ) - pEntry - > m_RequestTime ) * 1000 / time_freq ( ) ) , 999 ) ;
2014-05-03 18:57:19 +00:00
pEntry - > m_RequestTime = - 1 ; // Request has been answered
}
2010-05-29 07:25:38 +00:00
RemoveRequest ( pEntry ) ;
}
}
Sort ( ) ;
}
void CServerBrowser : : Refresh ( int Type )
{
// clear out everything
m_ServerlistHeap . Reset ( ) ;
m_NumServers = 0 ;
m_NumSortedServers = 0 ;
mem_zero ( m_aServerlistIp , sizeof ( m_aServerlistIp ) ) ;
m_pFirstReqServer = 0 ;
m_pLastReqServer = 0 ;
m_NumRequests = 0 ;
2013-12-31 02:18:37 +00:00
m_CurrentMaxRequests = g_Config . m_BrMaxRequests ;
2010-05-29 07:25:38 +00:00
// next token
m_CurrentToken = ( m_CurrentToken + 1 ) & 0xff ;
//
m_ServerlistType = Type ;
if ( Type = = IServerBrowser : : TYPE_LAN )
{
unsigned char Buffer [ sizeof ( SERVERBROWSE_GETINFO ) + 1 ] ;
CNetChunk Packet ;
int i ;
mem_copy ( Buffer , SERVERBROWSE_GETINFO , sizeof ( SERVERBROWSE_GETINFO ) ) ;
Buffer [ sizeof ( SERVERBROWSE_GETINFO ) ] = m_CurrentToken ;
2011-03-28 18:11:28 +00:00
/* do the broadcast version */
2010-05-29 07:25:38 +00:00
Packet . m_ClientID = - 1 ;
mem_zero ( & Packet , sizeof ( Packet ) ) ;
2012-03-04 11:47:16 +00:00
Packet . m_Address . type = m_pNetClient - > NetType ( ) | NETTYPE_LINK_BROADCAST ;
2010-05-29 07:25:38 +00:00
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
Packet . m_DataSize = sizeof ( Buffer ) ;
Packet . m_pData = Buffer ;
m_BroadcastTime = time_get ( ) ;
for ( i = 8303 ; i < = 8310 ; i + + )
{
Packet . m_Address . port = i ;
m_pNetClient - > Send ( & Packet ) ;
}
if ( g_Config . m_Debug )
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client_srvbrowse " , " broadcasting for servers " ) ;
2010-05-29 07:25:38 +00:00
}
else if ( Type = = IServerBrowser : : TYPE_INTERNET )
m_NeedRefresh = 1 ;
else if ( Type = = IServerBrowser : : TYPE_FAVORITES )
{
for ( int i = 0 ; i < m_NumFavoriteServers ; i + + )
Set ( m_aFavoriteServers [ i ] , IServerBrowser : : SET_FAV_ADD , - 1 , 0 ) ;
}
}
void CServerBrowser : : RequestImpl ( const NETADDR & Addr , CServerEntry * pEntry ) const
{
2010-12-26 01:37:22 +00:00
unsigned char Buffer [ sizeof ( SERVERBROWSE_GETINFO ) + 1 ] ;
2010-05-29 07:25:38 +00:00
CNetChunk Packet ;
if ( g_Config . m_Debug )
{
2011-03-30 10:08:33 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2011-12-29 22:36:53 +00:00
net_addr_str ( & Addr , aAddrStr , sizeof ( aAddrStr ) , true ) ;
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2011-03-30 10:08:33 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " requesting server info from %s " , aAddrStr ) ;
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client_srvbrowse " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
2010-12-26 01:37:22 +00:00
mem_copy ( Buffer , SERVERBROWSE_GETINFO , sizeof ( SERVERBROWSE_GETINFO ) ) ;
Buffer [ sizeof ( SERVERBROWSE_GETINFO ) ] = m_CurrentToken ;
2010-05-29 07:25:38 +00:00
Packet . m_ClientID = - 1 ;
Packet . m_Address = Addr ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
2010-12-26 01:37:22 +00:00
Packet . m_DataSize = sizeof ( Buffer ) ;
Packet . m_pData = Buffer ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_pNetClient - > Send ( & Packet ) ;
if ( pEntry )
pEntry - > m_RequestTime = time_get ( ) ;
}
2014-01-08 05:15:56 +00:00
void CServerBrowser : : RequestImpl64 ( const NETADDR & Addr , CServerEntry * pEntry ) const
{
unsigned char Buffer [ sizeof ( SERVERBROWSE_GETINFO64 ) + 1 ] ;
CNetChunk Packet ;
if ( g_Config . m_Debug )
{
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
net_addr_str ( & Addr , aAddrStr , sizeof ( aAddrStr ) , true ) ;
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " requesting server info 64 from %s " , aAddrStr ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client_srvbrowse " , aBuf ) ;
}
mem_copy ( Buffer , SERVERBROWSE_GETINFO64 , sizeof ( SERVERBROWSE_GETINFO64 ) ) ;
Buffer [ sizeof ( SERVERBROWSE_GETINFO64 ) ] = m_CurrentToken ;
Packet . m_ClientID = - 1 ;
Packet . m_Address = Addr ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
Packet . m_DataSize = sizeof ( Buffer ) ;
Packet . m_pData = Buffer ;
m_pNetClient - > Send ( & Packet ) ;
if ( pEntry )
pEntry - > m_RequestTime = time_get ( ) ;
}
2010-05-29 07:25:38 +00:00
void CServerBrowser : : Request ( const NETADDR & Addr ) const
{
2014-01-14 20:40:55 +00:00
// Call both because we can't know what kind the server is
RequestImpl64 ( Addr , 0 ) ;
2014-01-11 02:53:50 +00:00
RequestImpl ( Addr , 0 ) ;
2010-05-29 07:25:38 +00:00
}
2011-03-18 18:03:13 +00:00
void CServerBrowser : : Update ( bool ForceResort )
2013-12-31 01:34:33 +00:00
{
2011-03-30 10:08:33 +00:00
int64 Timeout = time_freq ( ) ;
2010-05-29 07:25:38 +00:00
int64 Now = time_get ( ) ;
int Count ;
CServerEntry * pEntry , * pNext ;
2013-12-31 02:18:37 +00:00
2010-05-29 07:25:38 +00:00
// do server list requests
if ( m_NeedRefresh & & ! m_pMasterServer - > IsRefreshing ( ) )
{
NETADDR Addr ;
2013-12-31 01:34:33 +00:00
CNetChunk Packet ;
int i = 0 ;
2010-05-29 07:25:38 +00:00
m_NeedRefresh = 0 ;
2013-12-31 01:34:33 +00:00
m_MasterServerCount = - 1 ;
mem_zero ( & Packet , sizeof ( Packet ) ) ;
Packet . m_ClientID = - 1 ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
Packet . m_DataSize = sizeof ( SERVERBROWSE_GETCOUNT ) ;
Packet . m_pData = SERVERBROWSE_GETCOUNT ;
for ( i = 0 ; i < IMasterServer : : MAX_MASTERSERVERS ; i + + )
{
if ( ! m_pMasterServer - > IsValid ( i ) )
continue ;
2010-05-29 07:25:38 +00:00
2013-12-31 01:34:33 +00:00
Addr = m_pMasterServer - > GetAddr ( i ) ;
m_pMasterServer - > SetCount ( i , - 1 ) ;
Packet . m_Address = Addr ;
2014-01-03 15:14:41 +00:00
m_pNetClient - > Send ( & Packet ) ;
2013-12-31 02:18:37 +00:00
if ( g_Config . m_Debug )
{
dbg_msg ( " client_srvbrowse " , " Count-Request sent to %d " , i ) ;
}
2013-12-31 01:34:33 +00:00
}
}
//Check if all server counts arrived
if ( m_MasterServerCount = = - 1 )
{
m_MasterServerCount = 0 ;
for ( int i = 0 ; i < IMasterServer : : MAX_MASTERSERVERS ; i + + )
{
if ( ! m_pMasterServer - > IsValid ( i ) )
continue ;
int Count = m_pMasterServer - > GetCount ( i ) ;
if ( Count = = - 1 )
{
2014-01-03 15:14:41 +00:00
/* ignore Server
2013-12-31 01:34:33 +00:00
m_MasterServerCount = - 1 ;
2014-01-03 15:14:41 +00:00
return ;
// we don't have the required server information
*/
2013-12-31 01:34:33 +00:00
}
2014-01-03 15:14:41 +00:00
else
2014-05-17 14:15:01 +00:00
m_MasterServerCount + = Count ;
2013-12-31 01:34:33 +00:00
}
//request Server-List
NETADDR Addr ;
2014-05-17 14:15:01 +00:00
CNetChunk Packet ;
2010-05-29 07:25:38 +00:00
mem_zero ( & Packet , sizeof ( Packet ) ) ;
Packet . m_ClientID = - 1 ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
Packet . m_DataSize = sizeof ( SERVERBROWSE_GETLIST ) ;
Packet . m_pData = SERVERBROWSE_GETLIST ;
2013-12-31 01:34:33 +00:00
for ( int i = 0 ; i < IMasterServer : : MAX_MASTERSERVERS ; i + + )
2010-05-29 07:25:38 +00:00
{
2011-03-30 10:08:33 +00:00
if ( ! m_pMasterServer - > IsValid ( i ) )
2010-05-29 07:25:38 +00:00
continue ;
2011-03-30 10:08:33 +00:00
Addr = m_pMasterServer - > GetAddr ( i ) ;
2010-05-29 07:25:38 +00:00
Packet . m_Address = Addr ;
m_pNetClient - > Send ( & Packet ) ;
}
if ( g_Config . m_Debug )
2013-12-31 02:18:37 +00:00
{
dbg_msg ( " client_srvbrowse " , " ServerCount: %d, requesting server list " , m_MasterServerCount ) ;
}
2013-12-31 01:34:33 +00:00
m_LastPacketTick = 0 ;
2014-01-03 15:14:41 +00:00
}
else if ( m_MasterServerCount > - 1 )
{
m_MasterServerCount = 0 ;
for ( int i = 0 ; i < IMasterServer : : MAX_MASTERSERVERS ; i + + )
{
if ( ! m_pMasterServer - > IsValid ( i ) )
continue ;
int Count = m_pMasterServer - > GetCount ( i ) ;
if ( Count = = - 1 )
{
/* ignore Server
m_MasterServerCount = - 1 ;
return ;
// we don't have the required server information
*/
}
else
m_MasterServerCount + = Count ;
}
2014-01-08 06:55:26 +00:00
//if(g_Config.m_Debug)
//{
// dbg_msg("client_srvbrowse", "ServerCount2: %d", m_MasterServerCount);
//}
2014-01-03 15:14:41 +00:00
}
2013-12-31 01:34:33 +00:00
if ( m_MasterServerCount > m_NumRequests + m_LastPacketTick )
2010-05-29 07:25:38 +00:00
{
2013-12-31 01:34:33 +00:00
+ + m_LastPacketTick ;
return ; //wait for more packets
2010-05-29 07:25:38 +00:00
}
pEntry = m_pFirstReqServer ;
Count = 0 ;
while ( 1 )
{
if ( ! pEntry ) // no more entries
break ;
2013-12-31 01:34:33 +00:00
if ( pEntry - > m_RequestTime & & pEntry - > m_RequestTime + Timeout < Now )
{
pEntry = pEntry - > m_pNextReq ;
continue ;
}
2010-05-29 07:25:38 +00:00
// no more then 10 concurrent requests
2013-12-31 01:34:33 +00:00
if ( Count = = m_CurrentMaxRequests )
2010-05-29 07:25:38 +00:00
break ;
if ( pEntry - > m_RequestTime = = 0 )
2014-01-08 05:15:56 +00:00
{
2014-01-14 20:40:55 +00:00
if ( pEntry - > m_Is64 )
2014-01-11 20:38:50 +00:00
RequestImpl64 ( pEntry - > m_Addr , pEntry ) ;
2014-01-14 20:40:55 +00:00
else
RequestImpl ( pEntry - > m_Addr , pEntry ) ;
2014-01-08 05:15:56 +00:00
}
2010-05-29 07:25:38 +00:00
Count + + ;
pEntry = pEntry - > m_pNextReq ;
}
2013-12-31 01:34:33 +00:00
if ( m_pFirstReqServer & & Count = = 0 & & m_CurrentMaxRequests > 1 ) //NO More current Server Requests
{
//reset old ones
pEntry = m_pFirstReqServer ;
while ( 1 )
{
if ( ! pEntry ) // no more entries
break ;
pEntry - > m_RequestTime = 0 ;
pEntry = pEntry - > m_pNextReq ;
}
//update max-requests
2013-12-31 02:18:37 +00:00
m_CurrentMaxRequests = m_CurrentMaxRequests / 2 ;
if ( m_CurrentMaxRequests < 1 )
m_CurrentMaxRequests = 1 ;
2013-12-31 01:34:33 +00:00
}
else if ( Count = = 0 & & m_CurrentMaxRequests = = 1 ) //we reached the limit, just release all left requests. IF a server sends us a packet, a new request will be added automatically, so we can delete all
{
pEntry = m_pFirstReqServer ;
while ( 1 )
{
if ( ! pEntry ) // no more entries
break ;
pNext = pEntry - > m_pNextReq ;
RemoveRequest ( pEntry ) ; //release request
pEntry = pNext ;
2014-01-03 15:14:41 +00:00
}
}
2013-12-31 01:34:33 +00:00
2010-05-29 07:25:38 +00:00
// check if we need to resort
2011-03-18 18:03:13 +00:00
if ( m_Sorthash ! = SortHash ( ) | | ForceResort )
2010-05-29 07:25:38 +00:00
Sort ( ) ;
}
bool CServerBrowser : : IsFavorite ( const NETADDR & Addr ) const
{
// search for the address
int i ;
for ( i = 0 ; i < m_NumFavoriteServers ; i + + )
{
if ( net_addr_comp ( & Addr , & m_aFavoriteServers [ i ] ) = = 0 )
return true ;
}
return false ;
}
void CServerBrowser : : AddFavorite ( const NETADDR & Addr )
{
CServerEntry * pEntry ;
if ( m_NumFavoriteServers = = MAX_FAVORITES )
return ;
// make sure that we don't already have the server in our list
for ( int i = 0 ; i < m_NumFavoriteServers ; i + + )
{
if ( net_addr_comp ( & Addr , & m_aFavoriteServers [ i ] ) = = 0 )
return ;
}
// add the server to the list
m_aFavoriteServers [ m_NumFavoriteServers + + ] = Addr ;
pEntry = Find ( Addr ) ;
if ( pEntry )
pEntry - > m_Info . m_Favorite = 1 ;
2011-04-13 18:37:12 +00:00
if ( g_Config . m_Debug )
2010-08-17 22:06:00 +00:00
{
2011-03-30 10:08:33 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2011-12-29 22:36:53 +00:00
net_addr_str ( & Addr , aAddrStr , sizeof ( aAddrStr ) , true ) ;
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2011-03-30 10:08:33 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " added fav, %s " , aAddrStr ) ;
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client_srvbrowse " , aBuf ) ;
}
2010-05-29 07:25:38 +00:00
}
void CServerBrowser : : RemoveFavorite ( const NETADDR & Addr )
{
int i ;
CServerEntry * pEntry ;
for ( i = 0 ; i < m_NumFavoriteServers ; i + + )
{
if ( net_addr_comp ( & Addr , & m_aFavoriteServers [ i ] ) = = 0 )
{
mem_move ( & m_aFavoriteServers [ i ] , & m_aFavoriteServers [ i + 1 ] , sizeof ( NETADDR ) * ( m_NumFavoriteServers - ( i + 1 ) ) ) ;
m_NumFavoriteServers - - ;
pEntry = Find ( Addr ) ;
if ( pEntry )
pEntry - > m_Info . m_Favorite = 0 ;
return ;
}
}
}
2010-11-17 11:43:24 +00:00
bool CServerBrowser : : IsRefreshing ( ) const
{
return m_pFirstReqServer ! = 0 ;
}
2010-05-29 07:25:38 +00:00
bool CServerBrowser : : IsRefreshingMasters ( ) const
{
return m_pMasterServer - > IsRefreshing ( ) ;
}
2010-10-30 16:56:57 +00:00
int CServerBrowser : : LoadingProgression ( ) const
{
if ( m_NumServers = = 0 )
return 0 ;
2011-04-13 18:37:12 +00:00
2010-10-30 16:56:57 +00:00
int Servers = m_NumServers ;
int Loaded = m_NumServers - m_NumRequests ;
return 100.0f * Loaded / Servers ;
}
2010-05-29 07:25:38 +00:00
void CServerBrowser : : ConfigSaveCallback ( IConfig * pConfig , void * pUserData )
{
CServerBrowser * pSelf = ( CServerBrowser * ) pUserData ;
char aAddrStr [ 128 ] ;
char aBuffer [ 256 ] ;
2011-12-29 22:36:53 +00:00
for ( int i = 0 ; i < pSelf - > m_NumFavoriteServers ; i + + )
2010-05-29 07:25:38 +00:00
{
2011-12-29 22:36:53 +00:00
net_addr_str ( & pSelf - > m_aFavoriteServers [ i ] , aAddrStr , sizeof ( aAddrStr ) , true ) ;
2010-05-29 07:25:38 +00:00
str_format ( aBuffer , sizeof ( aBuffer ) , " add_favorite %s " , aAddrStr ) ;
pConfig - > WriteLine ( aBuffer ) ;
}
}