2005-02-28 07:16:19 +00:00
# include "quakedef.h"
2004-08-23 00:15:46 +00:00
# ifdef CL_MASTER
# include "cl_master.h"
# define NET_GAMENAME_NQ "QUAKE"
//rename to cl_master.c sometime
//the networking operates seperatly from the main code. This is so we can have full control over all parts of the server sending prints.
//when we send status to the server, it replys with a print command. The text to print contains the serverinfo.
//Q2's print command is a compleate 'print', while qw is just a 'p', thus we can distinguish the two easily.
//save favorites and allow addition of new ones from game?
//add filters some time
//remove dead servers.
//master was polled a minute ago and server was not on list - server on multiple masters would be awkward.
# ifdef _WIN32
# include "winquake.h"
# define USEIPX
# else
typedef int SOCKET ;
# endif
2006-04-16 02:49:39 +00:00
# include "netinc.h"
2006-04-16 02:46:26 +00:00
2004-08-23 00:15:46 +00:00
# ifdef AF_IPX
# define USEIPX
# endif
//the number of servers should be limited only by memory.
2006-02-11 02:09:43 +00:00
cvar_t slist_cacheinfo = SCVAR ( " slist_cacheinfo " , " 0 " ) ; //this proves dangerous, memory wise.
cvar_t slist_writeserverstxt = SCVAR ( " slist_writeservers " , " 0 " ) ;
2004-08-23 00:15:46 +00:00
2009-04-01 22:03:56 +00:00
void CL_MasterListParse ( netadrtype_t adrtype , int type , qboolean slashpad ) ;
2004-08-23 00:15:46 +00:00
void CL_QueryServers ( void ) ;
int CL_ReadServerInfo ( char * msg , int servertype , qboolean favorite ) ;
master_t * master ;
player_t * mplayers ;
serverinfo_t * firstserver ;
2005-05-13 10:42:48 +00:00
static serverinfo_t * * visibleservers ;
static int numvisibleservers ;
static int maxvisibleservers ;
2008-11-09 22:29:28 +00:00
static double nextsort ;
2005-05-13 10:42:48 +00:00
static hostcachekey_t sortfield ;
static qboolean decreasingorder ;
typedef struct {
hostcachekey_t fieldindex ;
float operandi ;
char * operands ;
qboolean or ;
int compareop ;
} visrules_t ;
# define MAX_VISRULES 8
visrules_t visrules [ MAX_VISRULES ] ;
int numvisrules ;
# define SLIST_MAXKEYS 64
char slist_keyname [ SLIST_MAXKEYS ] [ MAX_INFO_KEY ] ;
int slist_customkeys ;
2005-09-08 02:05:36 +00:00
# ifndef INVALID_SOCKET
# define INVALID_SOCKET -1
# endif
2005-05-13 10:42:48 +00:00
2004-08-23 00:15:46 +00:00
2009-04-01 22:03:56 +00:00
# define POLLUDP4SOCKETS 64 //it's big so we can have lots of messages when behind a firewall. Basically if a firewall only allows replys, and only remembers 3 servers per socket, we need this big cos it can take a while for a packet to find a fast optimised route and we might be waiting for a few secs for a reply the first time around.
int lastpollsockUDP4 ;
# ifdef IPPROTO_IPV6
# define POLLUDP6SOCKETS 4 //it's non-zero so we can have lots of messages when behind a firewall. Basically if a firewall only allows replys, and only remembers 3 servers per socket, we need this big cos it can take a while for a packet to find a fast optimised route and we might be waiting for a few secs for a reply the first time around.
int lastpollsockUDP6 ;
# else
# define POLLUDP6SOCKETS 0
# endif
2004-08-23 00:15:46 +00:00
# ifdef USEIPX
2009-04-01 22:03:56 +00:00
# define POLLIPXSOCKETS 2 //ipx isn't used as much. In fact, we only expect local servers to be using it. I'm not sure why I implemented it anyway. You might see a q2 server using it. Rarely.
2004-08-23 00:15:46 +00:00
int lastpollsockIPX ;
# else
# define POLLIPXSOCKETS 0
# endif
2009-04-01 22:03:56 +00:00
# define FIRSTIPXSOCKET (0)
# define FIRSTUDP4SOCKET (FIRSTIPXSOCKET+POLLIPXSOCKETS)
# define FIRSTUDP6SOCKET (FIRSTUDP4SOCKET+POLLUDP4SOCKETS)
# define POLLTOTALSOCKETS (FIRSTUDP6SOCKET+POLLUDP6SOCKETS)
SOCKET pollsocketsList [ POLLTOTALSOCKETS ] ;
2005-10-07 16:27:20 +00:00
void Master_SetupSockets ( void )
2005-09-08 02:05:36 +00:00
{
int i ;
2009-04-01 22:03:56 +00:00
for ( i = 0 ; i < POLLTOTALSOCKETS ; i + + )
pollsocketsList [ i ] = INVALID_SOCKET ;
2005-09-08 02:05:36 +00:00
}
2005-05-13 10:42:48 +00:00
void Master_HideServer ( serverinfo_t * server )
{
int i , j ;
for ( i = 0 ; i < numvisibleservers ; )
{
if ( visibleservers [ i ] = = server )
{
for ( j = i ; j < numvisibleservers - 1 ; j + + )
visibleservers [ j ] = visibleservers [ j + 1 ] ;
visibleservers - - ;
}
else
i + + ;
}
server - > insortedlist = false ;
}
void Master_InsertAt ( serverinfo_t * server , int pos )
{
int i ;
for ( i = numvisibleservers ; i > pos ; i - - )
{
visibleservers [ i ] = visibleservers [ i - 1 ] ;
}
visibleservers [ pos ] = server ;
numvisibleservers + + ;
server - > insortedlist = true ;
}
qboolean Master_CompareInteger ( int a , int b , slist_test_t rule )
{
switch ( rule )
{
case SLIST_TEST_CONTAINS :
2006-02-28 00:46:04 +00:00
return ! ! ( a & b ) ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_NOTCONTAIN :
return ! ( a & b ) ;
case SLIST_TEST_LESSEQUAL :
return a < = b ;
case SLIST_TEST_LESS :
return a < b ;
case SLIST_TEST_EQUAL :
return a = = b ;
case SLIST_TEST_GREATER :
return a > b ;
case SLIST_TEST_GREATEREQUAL :
return a > = b ;
case SLIST_TEST_NOTEQUAL :
return a ! = b ;
}
return false ;
}
qboolean Master_CompareString ( char * a , char * b , slist_test_t rule )
{
switch ( rule )
{
case SLIST_TEST_CONTAINS :
return ! ! strstr ( a , b ) ;
case SLIST_TEST_NOTCONTAIN :
return ! strstr ( a , b ) ;
case SLIST_TEST_LESSEQUAL :
2006-09-17 00:59:22 +00:00
return stricmp ( a , b ) < = 0 ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_LESS :
2006-09-17 00:59:22 +00:00
return stricmp ( a , b ) < 0 ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_EQUAL :
2006-09-17 00:59:22 +00:00
return stricmp ( a , b ) = = 0 ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_GREATER :
2006-09-17 00:59:22 +00:00
return stricmp ( a , b ) > 0 ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_GREATEREQUAL :
2006-09-17 00:59:22 +00:00
return stricmp ( a , b ) > = 0 ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_NOTEQUAL :
2006-09-17 00:59:22 +00:00
return stricmp ( a , b ) ! = 0 ;
2005-05-13 10:42:48 +00:00
}
return false ;
}
qboolean Master_ServerIsGreater ( serverinfo_t * a , serverinfo_t * b )
{
switch ( sortfield )
{
2007-08-07 19:16:32 +00:00
case SLKEY_ADDRESS :
break ;
2006-02-28 00:46:04 +00:00
case SLKEY_BASEGAME :
return Master_CompareInteger ( a - > special , b - > special , SLIST_TEST_LESS ) ;
2007-08-07 19:16:32 +00:00
case SLKEY_CUSTOM :
break ;
2006-03-14 01:18:47 +00:00
case SLKEY_FRAGLIMIT :
return Master_CompareInteger ( a - > fl , b - > fl , SLIST_TEST_LESS ) ;
2007-08-07 19:16:32 +00:00
case SLKEY_FREEPLAYERS :
return Master_CompareInteger ( a - > maxplayers - a - > players , b - > maxplayers - b - > players , SLIST_TEST_LESS ) ;
2005-05-13 10:42:48 +00:00
case SLKEY_GAMEDIR :
return Master_CompareString ( a - > gamedir , b - > gamedir , SLIST_TEST_LESS ) ;
2007-08-07 19:16:32 +00:00
case SLKEY_MAP :
return Master_CompareString ( a - > map , b - > map , SLIST_TEST_LESS ) ;
case SLKEY_MAXPLAYERS :
return Master_CompareInteger ( a - > maxplayers , b - > maxplayers , SLIST_TEST_LESS ) ;
2005-05-13 10:42:48 +00:00
case SLKEY_NAME :
return Master_CompareString ( a - > name , b - > name , SLIST_TEST_LESS ) ;
2007-08-07 19:16:32 +00:00
case SLKEY_NUMPLAYERS :
return Master_CompareInteger ( a - > players , b - > players , SLIST_TEST_LESS ) ;
case SLKEY_PING :
return Master_CompareInteger ( a - > ping , b - > ping , SLIST_TEST_LESS ) ;
case SLKEY_TIMELIMIT :
return Master_CompareInteger ( a - > tl , b - > tl , SLIST_TEST_LESS ) ;
case SLKEY_TOOMANY :
break ;
2005-05-13 10:42:48 +00:00
}
return false ;
}
qboolean Master_PassesMasks ( serverinfo_t * a )
{
int i ;
2006-02-28 00:46:04 +00:00
qboolean val , res ;
2005-05-13 10:42:48 +00:00
//always filter out dead unresponsive servers.
if ( ! a - > ping )
return false ;
2006-02-28 00:46:04 +00:00
val = 1 ;
2005-05-13 10:42:48 +00:00
for ( i = 0 ; i < numvisrules ; i + + )
{
switch ( visrules [ i ] . fieldindex )
{
case SLKEY_PING :
2006-02-28 00:46:04 +00:00
res = Master_CompareInteger ( a - > ping , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
case SLKEY_NUMPLAYERS :
2006-02-28 00:46:04 +00:00
res = Master_CompareInteger ( a - > players , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
case SLKEY_MAXPLAYERS :
2006-02-28 00:46:04 +00:00
res = Master_CompareInteger ( a - > maxplayers , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
break ;
case SLKEY_FREEPLAYERS :
2008-11-09 22:29:28 +00:00
res = Master_CompareInteger ( a - > freeslots , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
break ;
case SLKEY_NUMBOTS :
res = Master_CompareInteger ( a - > numbots , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
break ;
case SLKEY_NUMHUMANS :
res = Master_CompareInteger ( a - > numhumans , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
2006-03-14 01:18:47 +00:00
case SLKEY_TIMELIMIT :
res = Master_CompareInteger ( a - > tl , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
break ;
case SLKEY_FRAGLIMIT :
res = Master_CompareInteger ( a - > fl , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
break ;
2008-11-09 22:29:28 +00:00
case SLKEY_PROTOCOL :
res = Master_CompareInteger ( a - > fl , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
break ;
2005-05-13 10:42:48 +00:00
case SLKEY_MAP :
2006-02-28 00:46:04 +00:00
res = Master_CompareString ( a - > map , visrules [ i ] . operands , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
case SLKEY_NAME :
2006-02-28 00:46:04 +00:00
res = Master_CompareString ( a - > name , visrules [ i ] . operands , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
case SLKEY_GAMEDIR :
2006-02-28 00:46:04 +00:00
res = Master_CompareString ( a - > gamedir , visrules [ i ] . operands , visrules [ i ] . compareop ) ;
break ;
case SLKEY_BASEGAME :
res = Master_CompareInteger ( a - > special , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
2005-05-13 10:42:48 +00:00
break ;
2008-11-09 22:29:28 +00:00
case SLKEY_MOD :
res = Master_CompareString ( a - > modname , visrules [ i ] . operands , visrules [ i ] . compareop ) ;
break ;
case SLKEY_QCSTATUS :
res = Master_CompareString ( a - > qcstatus , visrules [ i ] . operands , visrules [ i ] . compareop ) ;
break ;
2006-02-28 00:46:04 +00:00
default :
continue ;
2005-05-13 10:42:48 +00:00
}
2006-02-28 00:46:04 +00:00
if ( visrules [ i ] . or )
val | = res ;
else
val & = res ;
2005-05-13 10:42:48 +00:00
}
2006-02-28 00:46:04 +00:00
return val ;
2005-05-13 10:42:48 +00:00
}
void Master_ClearMasks ( void )
{
numvisrules = 0 ;
}
void Master_SetMaskString ( qboolean or , hostcachekey_t field , char * param , slist_test_t testop )
{
if ( numvisrules = = MAX_VISRULES )
return ; //just don't add it.
2008-11-09 22:29:28 +00:00
nextsort = 0 ;
2005-05-13 10:42:48 +00:00
visrules [ numvisrules ] . fieldindex = field ;
visrules [ numvisrules ] . compareop = testop ;
visrules [ numvisrules ] . operands = param ;
visrules [ numvisrules ] . or = or ;
numvisrules + + ;
}
void Master_SetMaskInteger ( qboolean or , hostcachekey_t field , int param , slist_test_t testop )
{
if ( numvisrules = = MAX_VISRULES )
return ; //just don't add it.
2008-11-09 22:29:28 +00:00
nextsort = 0 ;
2005-05-13 10:42:48 +00:00
visrules [ numvisrules ] . fieldindex = field ;
visrules [ numvisrules ] . compareop = testop ;
visrules [ numvisrules ] . operandi = param ;
visrules [ numvisrules ] . or = or ;
numvisrules + + ;
}
void Master_SetSortField ( hostcachekey_t field , qboolean descending )
{
2008-11-09 22:29:28 +00:00
nextsort = 0 ;
2005-05-13 10:42:48 +00:00
sortfield = field ;
decreasingorder = descending ;
}
hostcachekey_t Master_GetSortField ( void )
{
return sortfield ;
}
qboolean Master_GetSortDescending ( void )
{
return decreasingorder ;
}
void Master_ShowServer ( serverinfo_t * server )
{
int i ;
if ( ! numvisibleservers )
{
Master_InsertAt ( server , 0 ) ;
return ;
}
if ( ! decreasingorder )
{
for ( i = 0 ; i < numvisibleservers ; i + + )
{
if ( ! Master_ServerIsGreater ( server , visibleservers [ i ] ) )
{
Master_InsertAt ( server , i ) ;
return ;
}
}
}
else
{
for ( i = 0 ; i < numvisibleservers ; i + + )
{
if ( Master_ServerIsGreater ( server , visibleservers [ i ] ) )
{
Master_InsertAt ( server , i ) ;
return ;
}
}
}
Master_InsertAt ( server , numvisibleservers ) ;
}
void Master_ResortServer ( serverinfo_t * server )
{
if ( server - > insortedlist )
{
if ( ! Master_PassesMasks ( server ) )
Master_HideServer ( server ) ;
}
else
{
if ( Master_PassesMasks ( server ) )
Master_ShowServer ( server ) ;
}
}
void Master_SortServers ( void )
{
serverinfo_t * server ;
int total = Master_TotalCount ( ) ;
if ( maxvisibleservers < total )
{
maxvisibleservers = total ;
visibleservers = BZ_Realloc ( visibleservers , maxvisibleservers * sizeof ( serverinfo_t * ) ) ;
}
{
numvisibleservers = 0 ;
for ( server = firstserver ; server ; server = server - > next )
server - > insortedlist = false ;
}
for ( server = firstserver ; server ; server = server - > next )
{
Master_ResortServer ( server ) ;
}
2008-11-09 22:29:28 +00:00
nextsort = Sys_DoubleTime ( ) + 8 ;
2005-05-13 10:42:48 +00:00
}
serverinfo_t * Master_SortedServer ( int idx )
{
2008-11-09 22:29:28 +00:00
// if (nextsort < Sys_DoubleTime())
// Master_SortServers();
2005-05-13 10:42:48 +00:00
if ( idx < 0 | | idx > = numvisibleservers )
return NULL ;
return visibleservers [ idx ] ;
}
int Master_NumSorted ( void )
{
2008-11-09 22:29:28 +00:00
if ( nextsort < Sys_DoubleTime ( ) )
2005-05-13 10:42:48 +00:00
Master_SortServers ( ) ;
return numvisibleservers ;
}
float Master_ReadKeyFloat ( serverinfo_t * server , int keynum )
{
if ( ! server )
return - 1 ;
else if ( keynum < SLKEY_CUSTOM )
{
switch ( keynum )
{
case SLKEY_PING :
return server - > ping ;
case SLKEY_NUMPLAYERS :
return server - > players ;
case SLKEY_MAXPLAYERS :
return server - > maxplayers ;
2006-02-28 00:46:04 +00:00
case SLKEY_FREEPLAYERS :
return server - > maxplayers - server - > players ;
case SLKEY_BASEGAME :
return server - > special ;
2006-03-14 01:18:47 +00:00
case SLKEY_TIMELIMIT :
return server - > tl ;
case SLKEY_FRAGLIMIT :
return server - > fl ;
2008-11-09 22:29:28 +00:00
case SLKEY_PROTOCOL :
return server - > protocol ;
case SLKEY_NUMBOTS :
return server - > numbots ;
case SLKEY_NUMHUMANS :
return server - > numhumans ;
case SLKEY_ISFAVORITE :
return ! ! ( server - > special & SS_FAVORITE ) ;
2005-05-13 10:42:48 +00:00
default :
return atof ( Master_ReadKeyString ( server , keynum ) ) ;
}
}
else if ( server - > moreinfo )
return atof ( Info_ValueForKey ( server - > moreinfo - > info , slist_keyname [ keynum - SLKEY_CUSTOM ] ) ) ;
return 0 ;
}
char * Master_ReadKeyString ( serverinfo_t * server , int keynum )
{
2008-06-08 14:37:57 +00:00
char adr [ MAX_ADR_SIZE ] ;
2005-05-13 10:42:48 +00:00
if ( keynum < SLKEY_CUSTOM )
{
switch ( keynum )
{
case SLKEY_MAP :
return server - > map ;
case SLKEY_NAME :
return server - > name ;
case SLKEY_ADDRESS :
2008-06-08 14:37:57 +00:00
return NET_AdrToString ( adr , sizeof ( adr ) , server - > adr ) ;
2005-05-13 10:42:48 +00:00
case SLKEY_GAMEDIR :
return server - > gamedir ;
2008-11-09 22:29:28 +00:00
case SLKEY_MOD :
return server - > modname ;
case SLKEY_QCSTATUS :
return server - > qcstatus ;
2005-05-13 10:42:48 +00:00
default :
{
static char s [ 64 ] ;
sprintf ( s , " %f " , Master_ReadKeyFloat ( server , keynum ) ) ;
return s ;
}
}
}
else if ( server - > moreinfo )
return Info_ValueForKey ( server - > moreinfo - > info , slist_keyname [ keynum - SLKEY_CUSTOM ] ) ;
return " " ;
}
int Master_KeyForName ( char * keyname )
{
int i ;
if ( ! strcmp ( keyname , " map " ) )
return SLKEY_MAP ;
else if ( ! strcmp ( keyname , " ping " ) )
return SLKEY_PING ;
else if ( ! strcmp ( keyname , " name " ) )
return SLKEY_NAME ;
else if ( ! strcmp ( keyname , " address " ) | | ! strcmp ( keyname , " cname " ) )
return SLKEY_ADDRESS ;
else if ( ! strcmp ( keyname , " maxplayers " ) )
return SLKEY_MAXPLAYERS ;
else if ( ! strcmp ( keyname , " numplayers " ) )
return SLKEY_NUMPLAYERS ;
2008-11-09 22:29:28 +00:00
else if ( ! strcmp ( keyname , " freeplayers " ) | | ! strcmp ( keyname , " freeslots " ) )
2006-02-28 00:46:04 +00:00
return SLKEY_FREEPLAYERS ;
2008-11-09 22:29:28 +00:00
else if ( ! strcmp ( keyname , " gamedir " ) | | ! strcmp ( keyname , " game " ) | | ! strcmp ( keyname , " *gamedir " ) )
2005-05-13 10:42:48 +00:00
return SLKEY_GAMEDIR ;
2006-02-28 00:46:04 +00:00
else if ( ! strcmp ( keyname , " special " ) )
return SLKEY_BASEGAME ;
2008-11-09 22:29:28 +00:00
else if ( ! strcmp ( keyname , " mod " ) )
return SLKEY_MOD ;
else if ( ! strcmp ( keyname , " protocol " ) )
return SLKEY_PROTOCOL ;
else if ( ! strcmp ( keyname , " numbots " ) )
return SLKEY_NUMBOTS ;
else if ( ! strcmp ( keyname , " numhumans " ) )
return SLKEY_NUMHUMANS ;
else if ( ! strcmp ( keyname , " qcstatus " ) )
return SLKEY_QCSTATUS ;
else if ( ! strcmp ( keyname , " isfavorite " ) )
return SLKEY_ISFAVORITE ;
2005-05-13 10:42:48 +00:00
else if ( slist_customkeys = = SLIST_MAXKEYS )
return SLKEY_TOOMANY ;
else
{
for ( i = 0 ; i < slist_customkeys ; i + + )
{
if ( ! strcmp ( slist_keyname [ i ] , keyname ) )
{
return i + SLKEY_CUSTOM ;
}
}
Q_strncpyz ( slist_keyname [ slist_customkeys ] , keyname , MAX_INFO_KEY ) ;
slist_customkeys + + ;
return slist_customkeys - 1 + SLKEY_CUSTOM ;
}
}
2004-08-23 00:15:46 +00:00
void Master_AddMaster ( char * address , int type , char * description )
{
netadr_t adr ;
master_t * mast ;
if ( ! NET_StringToAdr ( address , & adr ) )
{
Con_Printf ( " Failed to resolve address \" %s \" \n " , address ) ;
2005-03-15 22:51:01 +00:00
return ;
2004-08-23 00:15:46 +00:00
}
2005-05-26 12:55:34 +00:00
2008-11-09 22:29:28 +00:00
# pragma message("Master_AddMaster: add ipv6. don't care about tcp / irc.")
if ( adr . type ! = NA_IP & & adr . type ! = NA_IPX )
{
2009-11-04 21:16:50 +00:00
Con_Printf ( " Fixme: unable to poll address family for \" %s \" \n " , address ) ;
2008-11-09 22:29:28 +00:00
return ;
}
2004-08-23 00:15:46 +00:00
if ( type < MT_SINGLEQW ) //broadcasts
{
if ( adr . type = = NA_IP )
adr . type = NA_BROADCAST_IP ;
if ( adr . type = = NA_IPX )
adr . type = NA_BROADCAST_IPX ;
2009-04-01 22:03:56 +00:00
if ( adr . type = = NA_IPV6 )
adr . type = NA_BROADCAST_IP6 ;
2004-08-23 00:15:46 +00:00
}
for ( mast = master ; mast ; mast = mast - > next )
{
2005-05-17 02:36:54 +00:00
if ( NET_CompareAdr ( mast - > adr , adr ) & & mast - > type = = type ) //already exists.
2004-08-23 00:15:46 +00:00
return ;
}
2005-05-26 12:55:34 +00:00
mast = Z_Malloc ( sizeof ( master_t ) + strlen ( description ) + 1 + strlen ( address ) + 1 ) ;
2004-08-23 00:15:46 +00:00
mast - > adr = adr ;
2005-05-26 12:55:34 +00:00
mast - > address = mast - > name + strlen ( description ) + 1 ;
2004-08-23 00:15:46 +00:00
mast - > type = type ;
strcpy ( mast - > name , description ) ;
2005-05-26 12:55:34 +00:00
strcpy ( mast - > address , address ) ;
mast - > next = master ;
master = mast ;
}
2006-02-26 09:37:55 +00:00
void Master_AddMasterHTTP ( char * address , int mastertype , char * description )
2005-05-26 12:55:34 +00:00
{
master_t * mast ;
2006-02-26 09:37:55 +00:00
int servertype ;
if ( mastertype = = MT_MASTERHTTPQW )
servertype = 0 ;
else
servertype = SS_NETQUAKE ;
2005-05-26 12:55:34 +00:00
for ( mast = master ; mast ; mast = mast - > next )
{
2006-02-26 09:37:55 +00:00
if ( ! strcmp ( mast - > address , address ) & & mast - > type = = mastertype ) //already exists.
2005-05-26 12:55:34 +00:00
return ;
}
mast = Z_Malloc ( sizeof ( master_t ) + strlen ( description ) + 1 + strlen ( address ) + 1 ) ;
mast - > address = mast - > name + strlen ( description ) + 1 ;
2006-02-26 09:37:55 +00:00
mast - > type = mastertype ;
2005-05-26 12:55:34 +00:00
mast - > servertype = servertype ;
strcpy ( mast - > name , description ) ;
strcpy ( mast - > address , address ) ;
2004-08-23 00:15:46 +00:00
mast - > next = master ;
master = mast ;
}
//build a linked list of masters. Doesn't duplicate addresses.
qboolean Master_LoadMasterList ( char * filename , int defaulttype , int depth )
{
2005-12-21 03:07:33 +00:00
vfsfile_t * f ;
2004-08-23 00:15:46 +00:00
char line [ 1024 ] ;
char file [ 1024 ] ;
char * name , * next ;
int servertype ;
if ( depth < = 0 )
return false ;
depth - - ;
2008-12-23 02:55:20 +00:00
f = FS_OpenVFS ( filename , " rb " , FS_ROOT ) ;
2004-08-23 00:15:46 +00:00
if ( ! f )
return false ;
2005-12-21 03:07:33 +00:00
while ( VFS_GETS ( f , line , sizeof ( line ) - 1 ) )
2004-08-23 00:15:46 +00:00
{
if ( * line = = ' # ' ) //comment
continue ;
next = COM_Parse ( line ) ;
if ( ! * com_token )
continue ;
if ( ! strcmp ( com_token , " file " ) ) //special case. Add a port if you have a server named 'file'... (unlikly)
{
next = COM_Parse ( next ) ;
if ( ! next )
continue ;
Q_strncpyz ( file , com_token , sizeof ( file ) ) ;
}
else
* file = ' \0 ' ;
* next = ' \0 ' ;
next + + ;
name = COM_Parse ( next ) ;
servertype = - 1 ;
if ( ! strcmp ( com_token , " single:qw " ) )
servertype = MT_SINGLEQW ;
else if ( ! strcmp ( com_token , " single:q2 " ) )
servertype = MT_SINGLEQ2 ;
2005-08-26 22:56:51 +00:00
else if ( ! strcmp ( com_token , " single:q3 " ) )
servertype = MT_SINGLEQ3 ;
2005-05-17 02:36:54 +00:00
else if ( ! strcmp ( com_token , " single:dp " ) )
servertype = MT_SINGLEDP ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " single:nq " ) | | ! strcmp ( com_token , " single:q1 " ) )
servertype = MT_SINGLENQ ;
else if ( ! strcmp ( com_token , " single " ) )
servertype = MT_SINGLEQW ;
2005-05-17 02:36:54 +00:00
else if ( ! strcmp ( com_token , " master:dp " ) )
servertype = MT_MASTERDP ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " master:qw " ) )
servertype = MT_MASTERQW ;
else if ( ! strcmp ( com_token , " master:q2 " ) )
servertype = MT_MASTERQ2 ;
2005-08-26 22:56:51 +00:00
else if ( ! strcmp ( com_token , " master:q3 " ) )
servertype = MT_MASTERQ3 ;
2006-02-26 09:37:55 +00:00
else if ( ! strcmp ( com_token , " master:http " ) )
servertype = MT_MASTERHTTP ;
else if ( ! strcmp ( com_token , " master:httpqw " ) )
servertype = MT_MASTERHTTPQW ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " master " ) ) //any other sort of master, assume it's a qw master.
servertype = MT_MASTERQW ;
else if ( ! strcmp ( com_token , " bcast:qw " ) )
servertype = MT_BCASTQW ;
else if ( ! strcmp ( com_token , " bcast:q2 " ) )
servertype = MT_BCASTQ2 ;
2005-08-26 22:56:51 +00:00
else if ( ! strcmp ( com_token , " bcast:q3 " ) )
servertype = MT_BCASTQ3 ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " bcast:nq " ) )
servertype = MT_BCASTNQ ;
2005-05-17 02:36:54 +00:00
else if ( ! strcmp ( com_token , " bcast:dp " ) )
servertype = MT_BCASTDP ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " bcast " ) )
servertype = MT_BCASTQW ;
else if ( ! strcmp ( com_token , " favorite:qw " ) )
servertype = - MT_SINGLEQW ;
else if ( ! strcmp ( com_token , " favorite:q2 " ) )
servertype = - MT_SINGLEQ2 ;
2005-08-26 22:56:51 +00:00
else if ( ! strcmp ( com_token , " favorite:q3 " ) )
servertype = - MT_SINGLEQ3 ;
2004-08-23 00:15:46 +00:00
else if ( ! strcmp ( com_token , " favorite:nq " ) )
servertype = - MT_SINGLENQ ;
else if ( ! strcmp ( com_token , " favorite " ) )
servertype = - MT_SINGLEQW ;
else
{
name = next ; //go back one token.
servertype = defaulttype ;
}
while ( * name < = ' ' & & * name ! = 0 ) //skip whitespace
name + + ;
next = name + strlen ( name ) - 1 ;
while ( * next < = ' ' & & next > name )
{
* next = ' \0 ' ;
next - - ;
}
if ( * file )
Master_LoadMasterList ( file , servertype , depth ) ;
else if ( servertype < 0 )
{
if ( NET_StringToAdr ( line , & net_from ) )
CL_ReadServerInfo ( va ( " \\ hostname \\ %s " , name ) , - servertype , true ) ;
else
Con_Printf ( " Failed to resolve address - \" %s \" \n " , line ) ;
}
else
2006-02-26 09:37:55 +00:00
{
switch ( servertype )
{
case MT_MASTERHTTP :
case MT_MASTERHTTPQW :
Master_AddMasterHTTP ( line , servertype , name ) ;
break ;
default :
Master_AddMaster ( line , servertype , name ) ;
}
}
2004-08-23 00:15:46 +00:00
}
2005-12-21 03:07:33 +00:00
VFS_CLOSE ( f ) ;
2004-08-23 00:15:46 +00:00
return true ;
}
void NET_SendPollPacket ( int len , void * data , netadr_t to )
{
int ret ;
struct sockaddr_qstorage addr ;
2008-11-09 22:29:28 +00:00
# pragma message("NET_SendPollPacket: no support for ipv6")
2004-08-23 00:15:46 +00:00
NetadrToSockadr ( & to , & addr ) ;
# ifdef USEIPX
2005-01-29 02:26:42 +00:00
if ( ( ( struct sockaddr * ) & addr ) - > sa_family = = AF_IPX )
2004-08-23 00:15:46 +00:00
{
lastpollsockIPX + + ;
if ( lastpollsockIPX > = POLLIPXSOCKETS )
lastpollsockIPX = 0 ;
2009-04-01 22:03:56 +00:00
if ( pollsocketsList [ FIRSTIPXSOCKET + lastpollsockIPX ] = = INVALID_SOCKET )
pollsocketsList [ FIRSTIPXSOCKET + lastpollsockIPX ] = IPX_OpenSocket ( PORT_ANY , true ) ;
if ( pollsocketsList [ FIRSTIPXSOCKET + lastpollsockIPX ] = = INVALID_SOCKET )
return ; //bother
ret = sendto ( pollsocketsList [ FIRSTIPXSOCKET + lastpollsockIPX ] , data , len , 0 , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
}
else
# endif
# ifdef IPPROTO_IPV6
if ( ( ( struct sockaddr * ) & addr ) - > sa_family = = AF_INET6 )
{
lastpollsockUDP6 + + ;
if ( lastpollsockUDP6 > = POLLUDP6SOCKETS )
lastpollsockUDP6 = 0 ;
if ( pollsocketsList [ FIRSTUDP6SOCKET + lastpollsockUDP6 ] = = INVALID_SOCKET )
pollsocketsList [ FIRSTUDP6SOCKET + lastpollsockUDP6 ] = UDP6_OpenSocket ( PORT_ANY , true ) ;
if ( pollsocketsList [ FIRSTUDP6SOCKET + lastpollsockUDP6 ] = = INVALID_SOCKET )
2005-03-18 06:14:07 +00:00
return ; //bother
2009-04-01 22:03:56 +00:00
ret = sendto ( pollsocketsList [ FIRSTUDP6SOCKET + lastpollsockUDP6 ] , data , len , 0 , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
2004-08-23 00:15:46 +00:00
}
else
# endif
2008-11-09 22:29:28 +00:00
if ( ( ( struct sockaddr * ) & addr ) - > sa_family = = AF_INET )
2004-08-23 00:15:46 +00:00
{
2009-04-01 22:03:56 +00:00
lastpollsockUDP4 + + ;
if ( lastpollsockUDP4 > = POLLUDP4SOCKETS )
lastpollsockUDP4 = 0 ;
if ( pollsocketsList [ FIRSTUDP4SOCKET + lastpollsockUDP4 ] = = INVALID_SOCKET )
pollsocketsList [ FIRSTUDP4SOCKET + lastpollsockUDP4 ] = UDP_OpenSocket ( PORT_ANY , true ) ;
if ( pollsocketsList [ FIRSTUDP4SOCKET + lastpollsockUDP4 ] = = INVALID_SOCKET )
2005-03-18 06:14:07 +00:00
return ; //bother
2009-04-01 22:03:56 +00:00
ret = sendto ( pollsocketsList [ FIRSTUDP4SOCKET + lastpollsockUDP4 ] , data , len , 0 , ( struct sockaddr * ) & addr , sizeof ( struct sockaddr_in ) ) ;
2004-08-23 00:15:46 +00:00
}
2008-11-09 22:29:28 +00:00
else
return ;
2004-08-23 00:15:46 +00:00
if ( ret = = - 1 )
{
// wouldblock is silent
if ( qerrno = = EWOULDBLOCK )
return ;
if ( qerrno = = ECONNREFUSED )
return ;
if ( qerrno = = EADDRNOTAVAIL )
2005-03-18 06:14:07 +00:00
Con_DPrintf ( " NET_SendPollPacket Warning: %i \n " , qerrno ) ;
2004-08-23 00:15:46 +00:00
else
2005-03-18 06:14:07 +00:00
Con_Printf ( " NET_SendPollPacket ERROR: %i \n " , qerrno ) ;
2004-08-23 00:15:46 +00:00
}
}
int NET_CheckPollSockets ( void )
{
# define MAX_UDP_PACKET 8192 // one more than msg + header
extern qbyte net_message_buffer [ MAX_UDP_PACKET ] ;
int sock ;
SOCKET usesocket ;
2008-06-08 14:37:57 +00:00
char adr [ MAX_ADR_SIZE ] ;
2009-04-01 22:03:56 +00:00
for ( sock = 0 ; sock < POLLTOTALSOCKETS ; sock + + )
2004-08-23 00:15:46 +00:00
{
int ret ;
struct sockaddr_qstorage from ;
int fromlen ;
2009-04-01 22:03:56 +00:00
usesocket = pollsocketsList [ sock ] ;
2004-08-23 00:15:46 +00:00
2005-09-08 02:05:36 +00:00
if ( usesocket = = INVALID_SOCKET )
2004-08-23 00:15:46 +00:00
continue ;
fromlen = sizeof ( from ) ;
ret = recvfrom ( usesocket , ( char * ) net_message_buffer , sizeof ( net_message_buffer ) , 0 , ( struct sockaddr * ) & from , & fromlen ) ;
if ( ret = = - 1 )
{
if ( qerrno = = EWOULDBLOCK )
continue ;
if ( qerrno = = EMSGSIZE )
{
SockadrToNetadr ( & from , & net_from ) ;
Con_Printf ( " Warning: Oversize packet from %s \n " ,
2008-06-08 14:37:57 +00:00
NET_AdrToString ( adr , sizeof ( adr ) , net_from ) ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
if ( qerrno = = ECONNABORTED | | qerrno = = ECONNRESET )
{
// Con_Printf ("Connection lost or aborted\n");
continue ;
}
2005-08-27 04:23:22 +00:00
Con_Printf ( " NET_CheckPollSockets: %i, %s \n " , qerrno , strerror ( qerrno ) ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
SockadrToNetadr ( & from , & net_from ) ;
net_message . cursize = ret ;
if ( ret = = sizeof ( net_message_buffer ) )
{
2008-06-08 14:37:57 +00:00
Con_Printf ( " Oversize packet from %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , net_from ) ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
if ( * ( int * ) net_message . data = = - 1 )
{
int c ;
char * s ;
2005-08-26 22:56:51 +00:00
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
MSG_BeginReading ( msg_nullnetprim ) ;
2004-08-23 00:15:46 +00:00
MSG_ReadLong ( ) ; // skip the -1
c = msg_readcount ;
s = MSG_ReadStringLine ( ) ; //peek for q2 messages.
2005-08-26 22:56:51 +00:00
# ifdef Q2CLIENT
2004-08-23 00:15:46 +00:00
if ( ! strcmp ( s , " print " ) )
{
CL_ReadServerInfo ( MSG_ReadString ( ) , MT_SINGLEQ2 , false ) ;
continue ;
}
2005-08-26 22:56:51 +00:00
if ( ! strcmp ( s , " info " ) ) //parse a bit more...
2004-08-23 00:15:46 +00:00
{
CL_ReadServerInfo ( MSG_ReadString ( ) , MT_SINGLEQ2 , false ) ;
continue ;
}
2009-04-01 22:03:56 +00:00
# ifdef IPPROTO_IPV6
if ( ! strncmp ( s , " server6 " , 7 ) ) //parse a bit more...
{
msg_readcount = c + 7 ;
CL_MasterListParse ( NA_IPV6 , SS_QUAKE2 , false ) ;
continue ;
}
# endif
if ( ! strncmp ( s , " servers " , 7 ) ) //parse a bit more...
2005-05-17 02:36:54 +00:00
{
2005-08-26 22:56:51 +00:00
msg_readcount = c + 7 ;
2009-04-01 22:03:56 +00:00
CL_MasterListParse ( NA_IP , SS_QUAKE2 , false ) ;
2005-05-17 02:36:54 +00:00
continue ;
}
2005-08-26 22:56:51 +00:00
# endif
# ifdef Q3CLIENT
if ( ! strcmp ( s , " statusResponse " ) )
2004-08-23 00:15:46 +00:00
{
2005-08-26 22:56:51 +00:00
CL_ReadServerInfo ( MSG_ReadString ( ) , MT_SINGLEQ3 , false ) ;
continue ;
}
# endif
2009-04-01 22:03:56 +00:00
# ifdef IPPROTO_IPV6
if ( ! strncmp ( s , " getserversResponse6 \\ " , 20 ) ) //parse a bit more...
{
msg_readcount = c + 19 - 1 ;
CL_MasterListParse ( NA_IPV6 , SS_DARKPLACES , true ) ;
continue ;
}
# endif
2005-08-26 22:56:51 +00:00
if ( ! strncmp ( s , " getserversResponse \\ " , 19 ) ) //parse a bit more...
{
msg_readcount = c + 18 - 1 ;
2009-04-01 22:03:56 +00:00
CL_MasterListParse ( NA_IP , SS_DARKPLACES , true ) ;
2005-05-17 02:36:54 +00:00
continue ;
}
2005-08-26 22:56:51 +00:00
if ( ! strcmp ( s , " infoResponse " ) ) //parse a bit more...
2005-05-17 02:36:54 +00:00
{
CL_ReadServerInfo ( MSG_ReadString ( ) , MT_SINGLEDP , false ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
2009-04-01 22:03:56 +00:00
# ifdef IPPROTO_IPV6
if ( ! strncmp ( s , " qw_slist6 \\ " , 10 ) ) //parse a bit more...
{
msg_readcount = c + 9 - 1 ;
CL_MasterListParse ( NA_IPV6 , SS_GENERICQUAKEWORLD , false ) ;
continue ;
}
# endif
2004-08-23 00:15:46 +00:00
msg_readcount = c ;
c = MSG_ReadByte ( ) ;
if ( c = = A2C_PRINT ) //qw server reply.
{
CL_ReadServerInfo ( MSG_ReadString ( ) , MT_SINGLEQW , false ) ;
continue ;
}
if ( c = = M2C_MASTER_REPLY ) //qw master reply.
{
2009-04-01 22:03:56 +00:00
CL_MasterListParse ( NA_IP , SS_GENERICQUAKEWORLD , false ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
}
# ifdef NQPROT
else
{ //connected packet? Must be a NQ packet.
char name [ 32 ] ;
char map [ 16 ] ;
int users , maxusers ;
int control ;
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
MSG_BeginReading ( msg_nullnetprim ) ;
2004-08-23 00:15:46 +00:00
control = BigLong ( * ( ( int * ) net_message . data ) ) ;
MSG_ReadLong ( ) ;
if ( control = = - 1 )
continue ;
if ( ( control & ( ~ NETFLAG_LENGTH_MASK ) ) ! = NETFLAG_CTL )
continue ;
if ( ( control & NETFLAG_LENGTH_MASK ) ! = ret )
continue ;
if ( MSG_ReadByte ( ) ! = CCREP_SERVER_INFO )
continue ;
NET_StringToAdr ( MSG_ReadString ( ) , & net_from ) ;
Q_strncpyz ( name , MSG_ReadString ( ) , sizeof ( name ) ) ;
Q_strncpyz ( map , MSG_ReadString ( ) , sizeof ( map ) ) ;
users = MSG_ReadByte ( ) ;
maxusers = MSG_ReadByte ( ) ;
if ( MSG_ReadByte ( ) ! = NET_PROTOCOL_VERSION )
{
// Q_strcpy(name, "*");
// Q_strcat(name, name);
}
2009-04-01 22:03:56 +00:00
CL_ReadServerInfo ( va ( " \\ hostname \\ %s \\ map \\ %s \\ maxclients \\ %i \\ clients \\ %i " , name , map , maxusers , users ) , MT_SINGLENQ , false ) ;
2004-08-23 00:15:46 +00:00
}
# endif
continue ;
}
return 0 ;
}
void Master_RemoveKeepInfo ( serverinfo_t * sv )
{
sv - > special & = ~ SS_KEEPINFO ;
if ( sv - > moreinfo )
{
Z_Free ( sv - > moreinfo ) ;
sv - > moreinfo = NULL ;
}
}
void SListOptionChanged ( serverinfo_t * newserver )
{
if ( selectedserver . inuse )
{
serverinfo_t * oldserver ;
selectedserver . detail = NULL ;
if ( ! slist_cacheinfo . value ) //we have to flush it. That's the rules.
{
for ( oldserver = firstserver ; oldserver ; oldserver = oldserver - > next )
{
if ( NET_CompareAdr ( selectedserver . adr , oldserver - > adr ) ) //*(int*)selectedserver.ipaddress == *(int*)server->ipaddress && selectedserver.port == server->port)
{
if ( oldserver - > moreinfo )
{
Z_Free ( oldserver - > moreinfo ) ;
oldserver - > moreinfo = NULL ;
}
break ;
}
}
}
if ( ! newserver )
return ;
selectedserver . adr = newserver - > adr ;
if ( newserver - > moreinfo ) //we cached it.
{
selectedserver . detail = newserver - > moreinfo ;
return ;
}
//we don't know all the info, so send a request for it.
selectedserver . detail = newserver - > moreinfo = Z_Malloc ( sizeof ( serverdetailedinfo_t ) ) ;
newserver - > moreinfo - > numplayers = newserver - > players ;
strcpy ( newserver - > moreinfo - > info , " " ) ;
Info_SetValueForKey ( newserver - > moreinfo - > info , " hostname " , newserver - > name , sizeof ( newserver - > moreinfo - > info ) ) ;
2005-05-17 02:36:54 +00:00
newserver - > sends + + ;
Master_QueryServer ( newserver ) ;
2004-08-23 00:15:46 +00:00
}
}
2005-05-26 12:55:34 +00:00
# ifdef WEBCLIENT
2010-03-14 14:35:56 +00:00
void MasterInfo_ProcessHTTP ( vfsfile_t * file , int type )
2005-05-26 12:55:34 +00:00
{
netadr_t adr ;
char * s ;
char * el ;
serverinfo_t * info ;
2008-06-08 14:37:57 +00:00
char adrbuf [ MAX_ADR_SIZE ] ;
2010-03-14 14:35:56 +00:00
char linebuffer [ 2048 ] ;
2008-06-08 14:37:57 +00:00
2010-03-14 14:35:56 +00:00
if ( ! file )
2005-05-26 12:55:34 +00:00
return ;
2010-03-14 14:35:56 +00:00
while ( VFS_GETS ( file , linebuffer , sizeof ( linebuffer ) ) )
2005-05-26 12:55:34 +00:00
{
2010-03-14 14:35:56 +00:00
s = linebuffer ;
while ( * s = = ' \t ' | | * s = = ' ' )
2005-05-26 12:55:34 +00:00
s + + ;
2010-03-14 14:35:56 +00:00
el = s + strlen ( s ) ;
if ( el > s & & el [ - 1 ] = = ' \r ' )
2005-05-26 12:55:34 +00:00
el [ - 1 ] = ' \0 ' ;
if ( * s = = ' # ' ) //hash is a comment, apparently.
continue ;
if ( ! NET_StringToAdr ( s , & adr ) )
continue ;
if ( ( info = Master_InfoForServer ( adr ) ) ) //remove if the server already exists.
{
info - > sends = 1 ; //reset.
}
else
{
info = Z_Malloc ( sizeof ( serverinfo_t ) ) ;
info - > adr = adr ;
info - > sends = 1 ;
2006-02-26 09:37:55 +00:00
info - > special = type ;
2005-05-26 12:55:34 +00:00
info - > refreshtime = 0 ;
2008-06-08 14:37:57 +00:00
snprintf ( info - > name , sizeof ( info - > name ) , " %s " , NET_AdrToString ( adrbuf , sizeof ( adrbuf ) , info - > adr ) ) ;
2005-05-26 12:55:34 +00:00
info - > next = firstserver ;
firstserver = info ;
2008-11-09 22:29:28 +00:00
Master_ResortServer ( info ) ;
2005-05-26 12:55:34 +00:00
}
}
}
2006-02-26 09:37:55 +00:00
// wrapper functions for the different server types
2010-03-14 14:35:56 +00:00
void MasterInfo_ProcessHTTPNQ ( struct dl_download * dl )
2006-02-26 09:37:55 +00:00
{
2010-03-14 14:35:56 +00:00
MasterInfo_ProcessHTTP ( dl - > file , SS_NETQUAKE ) ;
2006-02-26 09:37:55 +00:00
}
2010-03-14 14:35:56 +00:00
void MasterInfo_ProcessHTTPQW ( struct dl_download * dl )
2006-02-26 09:37:55 +00:00
{
2010-03-14 14:35:56 +00:00
MasterInfo_ProcessHTTP ( dl - > file , SS_GENERICQUAKEWORLD ) ;
2006-02-26 09:37:55 +00:00
}
2005-05-26 12:55:34 +00:00
# endif
2004-08-23 00:15:46 +00:00
//don't try sending to servers we don't support
2005-03-18 06:14:07 +00:00
void MasterInfo_Request ( master_t * mast , qboolean evenifwedonthavethefiles )
2004-08-23 00:15:46 +00:00
{
2005-05-26 12:55:34 +00:00
static int mastersequence ;
2004-08-23 00:15:46 +00:00
if ( ! mast )
return ;
switch ( mast - > type )
{
2005-08-26 22:56:51 +00:00
# ifdef Q3CLIENT
case MT_BCASTQ3 :
case MT_SINGLEQ3 :
NET_SendPollPacket ( 14 , va ( " %c%c%c%cgetstatus \n " , 255 , 255 , 255 , 255 ) , mast - > adr ) ;
break ;
case MT_MASTERQ3 :
{
char * str ;
str = va ( " %c%c%c%cgetservers %u empty full \x0A \n " , 255 , 255 , 255 , 255 , 68 ) ;
NET_SendPollPacket ( strlen ( str ) , str , mast - > adr ) ;
}
break ;
# endif
2004-08-23 00:15:46 +00:00
# ifdef Q2CLIENT
case MT_BCASTQ2 :
case MT_SINGLEQ2 :
# endif
case MT_SINGLEQW :
case MT_BCASTQW :
NET_SendPollPacket ( 11 , va ( " %c%c%c%cstatus \n " , 255 , 255 , 255 , 255 ) , mast - > adr ) ;
break ;
# ifdef NQPROT
case MT_BCASTNQ :
case MT_SINGLENQ :
SZ_Clear ( & net_message ) ;
2004-12-25 00:55:01 +00:00
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
2004-08-23 00:15:46 +00:00
MSG_WriteLong ( & net_message , 0 ) ; // save space for the header, filled in later
MSG_WriteByte ( & net_message , CCREQ_SERVER_INFO ) ;
MSG_WriteString ( & net_message , NET_GAMENAME_NQ ) ; //look for either sort of server
MSG_WriteByte ( & net_message , NET_PROTOCOL_VERSION ) ;
* ( ( int * ) net_message . data ) = BigLong ( NETFLAG_CTL | ( net_message . cursize & NETFLAG_LENGTH_MASK ) ) ;
NET_SendPollPacket ( net_message . cursize , net_message . data , mast - > adr ) ;
SZ_Clear ( & net_message ) ;
break ;
2005-05-17 02:36:54 +00:00
case MT_MASTERDP :
2005-05-26 12:55:34 +00:00
{
char * str ;
str = va ( " %c%c%c%cgetservers %s %u empty full \x0A \n " , 255 , 255 , 255 , 255 , com_gamename . string , 3 ) ;
NET_SendPollPacket ( strlen ( str ) , str , mast - > adr ) ;
}
2005-05-17 02:36:54 +00:00
break ;
case MT_SINGLEDP :
case MT_BCASTDP :
2005-05-26 12:55:34 +00:00
{
char * str ;
str = va ( " %c%c%c%cgetinfo " , 255 , 255 , 255 , 255 ) ;
NET_SendPollPacket ( strlen ( str ) , str , mast - > adr ) ;
}
2005-05-17 02:36:54 +00:00
break ;
2004-08-23 00:15:46 +00:00
# endif
case MT_MASTERQW :
NET_SendPollPacket ( 3 , " c \n " , mast - > adr ) ;
break ;
# ifdef Q2CLIENT
case MT_MASTERQ2 :
2005-03-18 06:14:07 +00:00
if ( evenifwedonthavethefiles | | COM_FDepthFile ( " pics/colormap.pcx " , true ) ! = 0x7fffffff ) //only query this master if we expect to be able to load it's maps.
2004-08-23 00:15:46 +00:00
NET_SendPollPacket ( 6 , " query " , mast - > adr ) ;
break ;
# endif
2005-05-26 12:55:34 +00:00
# ifdef WEBCLIENT
2006-02-26 09:37:55 +00:00
case MT_MASTERHTTP :
2010-03-25 22:56:11 +00:00
HTTP_CL_Get ( mast - > address , NULL , MasterInfo_ProcessHTTPNQ ) ;
2006-02-26 09:37:55 +00:00
break ;
case MT_MASTERHTTPQW :
2010-03-25 22:56:11 +00:00
HTTP_CL_Get ( mast - > address , NULL , MasterInfo_ProcessHTTPQW ) ;
2005-05-26 12:55:34 +00:00
break ;
2006-02-26 09:37:55 +00:00
# endif
2004-08-23 00:15:46 +00:00
}
}
void MasterInfo_WriteServers ( void )
{
char * typename ;
master_t * mast ;
serverinfo_t * server ;
2009-04-01 22:03:56 +00:00
vfsfile_t * mf , * qws ;
2008-06-08 14:37:57 +00:00
char adr [ MAX_ADR_SIZE ] ;
2004-08-23 00:15:46 +00:00
2009-04-01 22:03:56 +00:00
mf = FS_OpenVFS ( " masters.txt " , " wt " , FS_ROOT ) ;
2004-08-23 00:15:46 +00:00
if ( ! mf )
{
Con_Printf ( " Couldn't write masters.txt " ) ;
return ;
}
for ( mast = master ; mast ; mast = mast - > next )
{
switch ( mast - > type )
{
case MT_MASTERQW :
typename = " master:qw " ;
break ;
case MT_MASTERQ2 :
typename = " master:q2 " ;
break ;
2005-08-26 22:56:51 +00:00
case MT_MASTERQ3 :
typename = " master:q3 " ;
break ;
2005-05-17 02:36:54 +00:00
case MT_MASTERDP :
typename = " master:dp " ;
break ;
2005-09-28 23:37:15 +00:00
case MT_MASTERHTTP :
typename = " master:http " ;
break ;
2006-02-26 09:37:55 +00:00
case MT_MASTERHTTPQW :
typename = " master:httpqw " ;
break ;
2004-08-23 00:15:46 +00:00
case MT_BCASTQW :
typename = " bcast:qw " ;
break ;
case MT_BCASTQ2 :
typename = " bcast:q2 " ;
break ;
2005-08-26 22:56:51 +00:00
case MT_BCASTQ3 :
typename = " bcast:q3 " ;
break ;
2004-08-23 00:15:46 +00:00
case MT_BCASTNQ :
typename = " bcast:nq " ;
break ;
case MT_SINGLEQW :
typename = " single:qw " ;
break ;
case MT_SINGLEQ2 :
typename = " single:q2 " ;
break ;
2005-08-26 22:56:51 +00:00
case MT_SINGLEQ3 :
typename = " single:q3 " ;
break ;
2004-08-23 00:15:46 +00:00
case MT_SINGLENQ :
typename = " single:nq " ;
break ;
2005-09-28 23:37:15 +00:00
case MT_SINGLEDP :
typename = " single:dp " ;
break ;
2004-08-23 00:15:46 +00:00
default :
typename = " writeerror " ;
}
2005-09-28 23:37:15 +00:00
if ( mast - > address )
2009-04-01 22:03:56 +00:00
VFS_PUTS ( mf , va ( " %s \t %s \t %s \n " , mast - > address , typename , mast - > name ) ) ;
2005-09-28 23:37:15 +00:00
else
2009-04-01 22:03:56 +00:00
VFS_PUTS ( mf , va ( " %s \t %s \t %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , mast - > adr ) , typename , mast - > name ) ) ;
2004-08-23 00:15:46 +00:00
}
if ( slist_writeserverstxt . value )
2009-04-01 22:03:56 +00:00
qws = FS_OpenVFS ( " servers.txt " , " wt " , FS_ROOT ) ;
2004-08-23 00:15:46 +00:00
else
qws = NULL ;
if ( qws )
2009-04-01 22:03:56 +00:00
VFS_PUTS ( mf , va ( " \n %s \t %s \t %s \n \n " , " file servers.txt " , " favorite:qw " , " personal server list " ) ) ;
2004-08-23 00:15:46 +00:00
for ( server = firstserver ; server ; server = server - > next )
{
if ( server - > special & SS_FAVORITE )
{
2005-08-26 22:56:51 +00:00
if ( server - > special & SS_QUAKE3 )
2009-04-01 22:03:56 +00:00
VFS_PUTS ( mf , va ( " %s \t %s \t %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , server - > adr ) , " favorite:q3 " , server - > name ) ) ;
2005-08-26 22:56:51 +00:00
else if ( server - > special & SS_QUAKE2 )
2009-04-01 22:03:56 +00:00
VFS_PUTS ( mf , va ( " %s \t %s \t %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , server - > adr ) , " favorite:q2 " , server - > name ) ) ;
2004-08-23 00:15:46 +00:00
else if ( server - > special & SS_NETQUAKE )
2009-04-01 22:03:56 +00:00
VFS_PUTS ( mf , va ( " %s \t %s \t %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , server - > adr ) , " favorite:nq " , server - > name ) ) ;
2004-08-23 00:15:46 +00:00
else if ( qws ) //servers.txt doesn't support the extra info.
2009-04-01 22:03:56 +00:00
VFS_PUTS ( qws , va ( " %s \t %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , server - > adr ) , server - > name ) ) ;
2004-08-23 00:15:46 +00:00
else //read only? damn them!
2009-04-01 22:03:56 +00:00
VFS_PUTS ( mf , va ( " %s \t %s \t %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , server - > adr ) , " favorite:qw " , server - > name ) ) ;
2004-08-23 00:15:46 +00:00
}
}
if ( qws )
2009-04-01 22:03:56 +00:00
VFS_CLOSE ( qws ) ;
2004-08-23 00:15:46 +00:00
2009-04-01 22:03:56 +00:00
VFS_CLOSE ( mf ) ;
2004-08-23 00:15:46 +00:00
}
//poll master servers for server lists.
void MasterInfo_Begin ( void )
{
master_t * mast ;
if ( ! Master_LoadMasterList ( " masters.txt " , MT_MASTERQW , 5 ) )
{
Master_LoadMasterList ( " servers.txt " , MT_SINGLEQW , 1 ) ;
2005-05-26 12:55:34 +00:00
// if (q1servers) //qw master servers
2004-08-23 00:15:46 +00:00
{
2006-02-26 09:37:55 +00:00
Master_AddMasterHTTP ( " http://www.gameaholic.com/servers/qspy-quakeworld " , MT_MASTERHTTPQW , " gameaholic's QW master " ) ;
2004-08-23 00:15:46 +00:00
Master_AddMaster ( " 192.246.40.37:27000 " , MT_MASTERQW , " id Limbo " ) ;
Master_AddMaster ( " 192.246.40.37:27002 " , MT_MASTERQW , " id CTF " ) ;
Master_AddMaster ( " 192.246.40.37:27003 " , MT_MASTERQW , " id TeamFortress " ) ;
Master_AddMaster ( " 192.246.40.37:27004 " , MT_MASTERQW , " id Miscilaneous " ) ;
Master_AddMaster ( " 192.246.40.37:27006 " , MT_MASTERQW , " id Deathmatch Only " ) ;
Master_AddMaster ( " 150.254.66.120:27000 " , MT_MASTERQW , " Poland's master server. " ) ;
Master_AddMaster ( " 62.112.145.129:27000 " , MT_MASTERQW , " Ocrana master server. " ) ;
2006-12-25 18:19:45 +00:00
// Master_AddMaster("master.edome.net", MT_MASTERQW, "edome master server.");
2007-06-20 00:02:54 +00:00
//down Master_AddMaster("qwmaster.barrysworld.com", MT_MASTERQW, "barrysworld master server.");
2005-12-21 03:07:33 +00:00
Master_AddMaster ( " qwmaster.ocrana.de:27000 " , MT_MASTERQW , " Ocrana2 master server. " ) ;
2005-11-14 01:28:05 +00:00
Master_AddMaster ( " 213.221.174.165:27000 " , MT_MASTERQW , " unknown1 master server. " ) ;
Master_AddMaster ( " 195.74.0.8 " , MT_MASTERQW , " unknown2 master server. " ) ;
Master_AddMaster ( " 204.182.161.2 " , MT_MASTERQW , " unknown5 master server. " ) ;
2009-07-06 01:20:20 +00:00
Master_AddMaster ( " asgaard.morphos-team.net:27000 " , MT_MASTERQW , " Asgaard " ) ;
Master_AddMaster ( " master.quakeservers.net:27000 " , MT_MASTERQW , " QuakeServers.net " ) ;
2005-05-26 12:55:34 +00:00
Master_AddMaster ( " 255.255.255.255:27500 " , MT_BCASTQW , " Nearby QuakeWorld UDP servers. " ) ;
2004-08-23 00:15:46 +00:00
}
2005-05-26 12:55:34 +00:00
// if (q1servers) //nq master servers
{
2006-02-26 09:37:55 +00:00
Master_AddMasterHTTP ( " http://www.gameaholic.com/servers/qspy-quake " , MT_MASTERHTTP , " gameaholic's NQ master " ) ;
2005-05-26 12:55:34 +00:00
Master_AddMaster ( " 255.255.255.255:26000 " , MT_BCASTNQ , " Nearby Quake1 servers " ) ;
2005-05-17 02:36:54 +00:00
2005-05-26 12:55:34 +00:00
Master_AddMaster ( " ghdigital.com:27950 " , MT_MASTERDP , " DarkPlaces Master 1 " ) ;
Master_AddMaster ( " dpmaster.deathmask.net:27950 " , MT_MASTERDP , " DarkPlaces Master 2 " ) ;
Master_AddMaster ( " 12.166.196.192:27950 " , MT_MASTERDP , " DarkPlaces Master 3 " ) ;
2005-05-17 02:36:54 +00:00
2005-05-26 12:55:34 +00:00
Master_AddMaster ( " 255.255.255.255:26000 " , MT_BCASTDP , " Nearby DarkPlaces servers " ) ;
}
2005-05-17 02:36:54 +00:00
2005-05-26 12:55:34 +00:00
// if (q2servers) //q2
{
Master_AddMaster ( " 255.255.255.255:27910 " , MT_BCASTQ2 , " Nearby Quake2 UDP servers. " ) ;
Master_AddMaster ( " 00000000:ffffffffffff:27910 " , MT_BCASTQ2 , " Nearby Quake2 IPX servers. " ) ;
Master_AddMaster ( " 192.246.40.37:27900 " , MT_MASTERQ2 , " id q2 Master. " ) ;
}
2005-08-26 22:56:51 +00:00
//q3
{
Master_AddMaster ( " 255.255.255.255:27960 " , MT_BCASTQ3 , " Nearby Quake3 UDP servers. " ) ;
Master_AddMaster ( " master.quake3arena.com:27950 " , MT_MASTERQ3 , " Quake3 master server. " ) ;
}
2004-08-23 00:15:46 +00:00
}
2006-02-26 09:37:55 +00:00
2004-08-23 00:15:46 +00:00
for ( mast = master ; mast ; mast = mast - > next )
{
2005-03-18 06:14:07 +00:00
MasterInfo_Request ( mast , false ) ;
2004-08-23 00:15:46 +00:00
}
}
void Master_QueryServer ( serverinfo_t * server )
{
char data [ 2048 ] ;
2005-05-13 10:42:48 +00:00
server - > sends - - ;
2004-08-23 00:15:46 +00:00
server - > refreshtime = Sys_DoubleTime ( ) ;
2005-08-26 22:56:51 +00:00
if ( server - > special & SS_QUAKE3 )
sprintf ( data , " %c%c%c%cgetstatus " , 255 , 255 , 255 , 255 ) ;
else if ( server - > special & SS_DARKPLACES )
2005-05-17 02:36:54 +00:00
sprintf ( data , " %c%c%c%cgetinfo " , 255 , 255 , 255 , 255 ) ;
2005-05-26 12:55:34 +00:00
else if ( server - > special & SS_NETQUAKE )
{
# ifdef NQPROT
SZ_Clear ( & net_message ) ;
net_message . packing = SZ_RAWBYTES ;
net_message . currentbit = 0 ;
MSG_WriteLong ( & net_message , 0 ) ; // save space for the header, filled in later
MSG_WriteByte ( & net_message , CCREQ_SERVER_INFO ) ;
MSG_WriteString ( & net_message , NET_GAMENAME_NQ ) ; //look for either sort of server
MSG_WriteByte ( & net_message , NET_PROTOCOL_VERSION ) ;
* ( ( int * ) net_message . data ) = BigLong ( NETFLAG_CTL | ( net_message . cursize & NETFLAG_LENGTH_MASK ) ) ;
NET_SendPollPacket ( net_message . cursize , net_message . data , server - > adr ) ;
SZ_Clear ( & net_message ) ;
# endif
return ;
}
2005-05-17 02:36:54 +00:00
else
sprintf ( data , " %c%c%c%cstatus " , 255 , 255 , 255 , 255 ) ;
2004-08-23 00:15:46 +00:00
NET_SendPollPacket ( strlen ( data ) , data , server - > adr ) ;
}
//send a packet to each server in sequence.
void CL_QueryServers ( void )
{
static int poll ;
int op ;
serverinfo_t * server ;
2006-03-14 01:18:47 +00:00
extern cvar_t sb_hidequake2 ;
extern cvar_t sb_hidequake3 ;
extern cvar_t sb_hidenetquake ;
extern cvar_t sb_hidequakeworld ;
2004-08-23 00:15:46 +00:00
op = poll ;
for ( server = firstserver ; op > 0 & & server ; server = server - > next , op - - ) ;
if ( ! server )
{
poll = 0 ;
return ;
}
if ( op = = 0 )
{
2006-03-14 01:18:47 +00:00
//we only want to send poll packets to servers which will not be filtered (otherwise it's pointless)
while ( server )
{
if ( server - > special & SS_QUAKE3 & & ! sb_hidequake3 . value )
break ;
if ( server - > special & SS_QUAKE2 & & ! sb_hidequake2 . value )
break ;
if ( ( server - > special & ( SS_NETQUAKE | SS_DARKPLACES ) ) & & ! sb_hidenetquake . value )
break ;
if ( ( server - > special & ( SS_QUAKE3 | SS_QUAKE2 | SS_DARKPLACES | SS_NETQUAKE ) ) = = 0 & & ! sb_hidequakeworld . value )
break ;
server = server - > next ;
poll + + ;
}
if ( ! server )
{
server = firstserver ;
while ( server )
{
if ( server - > special & SS_QUAKE3 & & ! sb_hidequake3 . value )
break ;
if ( server - > special & SS_QUAKE2 & & ! sb_hidequake2 . value )
break ;
if ( ( server - > special & ( SS_NETQUAKE | SS_DARKPLACES ) ) & & ! sb_hidenetquake . value )
break ;
if ( ( server - > special & ( SS_QUAKE3 | SS_QUAKE2 | SS_DARKPLACES | SS_NETQUAKE ) ) = = 0 & & ! sb_hidequakeworld . value )
break ;
server = server - > next ;
poll + + ;
}
}
if ( server & & server - > sends > 0 )
2004-08-23 00:15:46 +00:00
{
Master_QueryServer ( server ) ;
}
poll + + ;
return ;
}
poll = 0 ;
}
int Master_TotalCount ( void )
{
int count = 0 ;
serverinfo_t * info ;
for ( info = firstserver ; info ; info = info - > next )
{
count + + ;
}
return count ;
}
//true if server is on a different master's list.
serverinfo_t * Master_InfoForServer ( netadr_t addr )
{
serverinfo_t * info ;
for ( info = firstserver ; info ; info = info - > next )
{
if ( NET_CompareAdr ( info - > adr , addr ) )
return info ;
}
return NULL ;
}
serverinfo_t * Master_InfoForNum ( int num )
{
serverinfo_t * info ;
for ( info = firstserver ; info ; info = info - > next )
{
if ( num - - < = 0 )
return info ;
}
return NULL ;
}
void MasterInfo_RemovePlayers ( netadr_t adr )
{
player_t * p , * prev ;
prev = NULL ;
for ( p = mplayers ; p ; )
{
if ( NET_CompareAdr ( p - > adr , adr ) )
{
if ( prev )
prev - > next = p - > next ;
else
mplayers = p - > next ;
Z_Free ( p ) ;
p = prev ;
continue ;
}
else
prev = p ;
p = p - > next ;
}
}
void MasterInfo_AddPlayer ( netadr_t serveradr , char * name , int ping , int frags , int colours , char * skin )
{
player_t * p ;
p = Z_Malloc ( sizeof ( player_t ) ) ;
p - > next = mplayers ;
p - > adr = serveradr ;
p - > colour = colours ;
p - > frags = frags ;
Q_strncpyz ( p - > name , name , sizeof ( p - > name ) ) ;
Q_strncpyz ( p - > skin , skin , sizeof ( p - > skin ) ) ;
mplayers = p ;
}
//we got told about a server, parse it's info
int CL_ReadServerInfo ( char * msg , int servertype , qboolean favorite )
{
serverdetailedinfo_t details ;
char * token ;
char * nl ;
char * name ;
int ping ;
int len ;
serverinfo_t * info ;
2008-06-08 14:37:57 +00:00
char adr [ MAX_ADR_SIZE ] ;
2004-08-23 00:15:46 +00:00
info = Master_InfoForServer ( net_from ) ;
if ( ! info ) //not found...
{
2005-08-26 22:56:51 +00:00
if ( atoi ( Info_ValueForKey ( msg , " sv_punkbuster " ) ) )
return false ; //never add servers that require punkbuster. :(
if ( atoi ( Info_ValueForKey ( msg , " sv_pure " ) ) )
return false ; //we don't support the filesystem hashing. :(
2004-08-23 00:15:46 +00:00
info = Z_Malloc ( sizeof ( serverinfo_t ) ) ;
info - > adr = net_from ;
2008-06-08 14:37:57 +00:00
snprintf ( info - > name , sizeof ( info - > name ) , " %s " , NET_AdrToString ( adr , sizeof ( adr ) , info - > adr ) ) ;
2004-08-23 00:15:46 +00:00
info - > next = firstserver ;
firstserver = info ;
}
else
{
MasterInfo_RemovePlayers ( info - > adr ) ;
}
nl = strchr ( msg , ' \n ' ) ;
if ( nl )
{
* nl = ' \0 ' ;
nl + + ;
}
name = Info_ValueForKey ( msg , " hostname " ) ;
2005-08-26 22:56:51 +00:00
if ( ! * name )
name = Info_ValueForKey ( msg , " sv_hostname " ) ;
2004-08-23 00:15:46 +00:00
Q_strncpyz ( info - > name , name , sizeof ( info - > name ) ) ;
info - > special = info - > special & ( SS_FAVORITE | SS_KEEPINFO ) ; //favorite is never cleared
2005-11-14 01:28:05 +00:00
if ( ! strcmp ( DISTRIBUTION , Info_ValueForKey ( msg , " *distrib " ) ) )
2004-08-23 00:15:46 +00:00
info - > special | = SS_FTESERVER ;
2005-11-14 01:28:05 +00:00
else if ( ! strncmp ( DISTRIBUTION , Info_ValueForKey ( msg , " *version " ) , 3 ) )
2004-08-23 00:15:46 +00:00
info - > special | = SS_FTESERVER ;
2004-10-10 06:32:29 +00:00
2005-05-17 02:36:54 +00:00
if ( servertype = = MT_SINGLEDP )
2005-08-26 22:56:51 +00:00
{
if ( atoi ( Info_ValueForKey ( msg , " protocol " ) ) > 60 )
info - > special | = SS_QUAKE3 ;
else
info - > special | = SS_DARKPLACES ;
}
2005-05-17 02:36:54 +00:00
else if ( servertype = = MT_SINGLEQ2 )
2004-08-23 00:15:46 +00:00
info - > special | = SS_QUAKE2 ;
2005-08-26 22:56:51 +00:00
else if ( servertype = = MT_SINGLEQ3 )
info - > special | = SS_QUAKE3 ;
2004-08-23 00:15:46 +00:00
else if ( servertype = = MT_SINGLENQ )
info - > special | = SS_NETQUAKE ;
if ( favorite ) //was specifically named, not retrieved from a master.
info - > special | = SS_FAVORITE ;
ping = ( Sys_DoubleTime ( ) - info - > refreshtime ) * 1000 ;
if ( ping > 0xffff )
info - > ping = 0xffff ;
else
info - > ping = ping ;
info - > players = 0 ;
info - > maxplayers = atoi ( Info_ValueForKey ( msg , " maxclients " ) ) ;
2005-05-26 12:55:34 +00:00
if ( ! info - > maxplayers )
info - > maxplayers = atoi ( Info_ValueForKey ( msg , " sv_maxclients " ) ) ;
2004-08-23 00:15:46 +00:00
info - > tl = atoi ( Info_ValueForKey ( msg , " timelimit " ) ) ;
info - > fl = atoi ( Info_ValueForKey ( msg , " fraglimit " ) ) ;
2005-09-28 23:37:15 +00:00
if ( * Info_ValueForKey ( msg , " *qtv " ) )
2006-09-17 00:59:22 +00:00
info - > special | = SS_PROXY | SS_FTESERVER ;
if ( ! strcmp ( Info_ValueForKey ( msg , " *progs " ) , " 666 " ) & & ! strcmp ( Info_ValueForKey ( msg , " *version " ) , " 2.91 " ) )
info - > special | = SS_PROXY ; //qizmo
2005-09-28 23:37:15 +00:00
2005-08-26 22:56:51 +00:00
if ( servertype = = MT_SINGLEQ3 | | servertype = = MT_SINGLEQ2 | | servertype = = MT_SINGLEDP )
2004-08-23 00:15:46 +00:00
{
Q_strncpyz ( info - > gamedir , Info_ValueForKey ( msg , " gamename " ) , sizeof ( info - > gamedir ) ) ;
Q_strncpyz ( info - > map , Info_ValueForKey ( msg , " mapname " ) , sizeof ( info - > map ) ) ;
}
else
{
Q_strncpyz ( info - > gamedir , Info_ValueForKey ( msg , " *gamedir " ) , sizeof ( info - > gamedir ) ) ;
Q_strncpyz ( info - > map , Info_ValueForKey ( msg , " map " ) , sizeof ( info - > map ) ) ;
}
2008-11-09 22:29:28 +00:00
Q_strncpyz ( info - > qcstatus , Info_ValueForKey ( msg , " qcstatus " ) , sizeof ( info - > qcstatus ) ) ;
Q_strncpyz ( info - > modname , Info_ValueForKey ( msg , " modname " ) , sizeof ( info - > modname ) ) ;
info - > protocol = atoi ( Info_ValueForKey ( msg , " protocol " ) ) ;
info - > gameversion = atoi ( Info_ValueForKey ( msg , " gameversion " ) ) ;
info - > numbots = atoi ( Info_ValueForKey ( msg , " bots " ) ) ;
info - > numhumans = info - > players - info - > numbots ;
info - > freeslots = info - > maxplayers - info - > players ;
2004-08-23 00:15:46 +00:00
2005-06-04 04:20:20 +00:00
strcpy ( details . info , msg ) ;
msg = msg + strlen ( msg ) + 1 ;
info - > players = details . numplayers = 0 ;
if ( ! strchr ( msg , ' \n ' ) )
info - > players = atoi ( Info_ValueForKey ( details . info , " clients " ) ) ;
else
2004-08-23 00:15:46 +00:00
{
int clnum ;
for ( clnum = 0 ; clnum < MAX_CLIENTS ; clnum + + )
{
nl = strchr ( msg , ' \n ' ) ;
if ( ! nl )
break ;
* nl = ' \0 ' ;
token = msg ;
if ( ! token )
break ;
details . players [ clnum ] . userid = atoi ( token ) ;
token = strchr ( token + 1 , ' ' ) ;
if ( ! token )
break ;
details . players [ clnum ] . frags = atoi ( token ) ;
token = strchr ( token + 1 , ' ' ) ;
if ( ! token )
break ;
details . players [ clnum ] . time = atoi ( token ) ;
msg = token ;
token = strchr ( msg + 1 , ' ' ) ;
if ( ! token ) //probably q2 response
{
//see if this is actually a Quake2 server.
token = strchr ( msg + 1 , ' \" ' ) ;
if ( ! token ) //it wasn't.
break ;
details . players [ clnum ] . ping = details . players [ clnum ] . frags ;
details . players [ clnum ] . frags = details . players [ clnum ] . userid ;
msg = strchr ( token + 1 , ' \" ' ) ;
if ( ! msg )
break ;
len = msg - token ;
if ( len > = sizeof ( details . players [ clnum ] . name ) )
len = sizeof ( details . players [ clnum ] . name ) ;
Q_strncpyz ( details . players [ clnum ] . name , token + 1 , len ) ;
details . players [ clnum ] . skin [ 0 ] = ' \0 ' ;
details . players [ clnum ] . topc = 0 ;
details . players [ clnum ] . botc = 0 ;
details . players [ clnum ] . time = 0 ;
}
else //qw responce
{
details . players [ clnum ] . time = atoi ( token ) ;
msg = token ;
token = strchr ( msg + 1 , ' ' ) ;
if ( ! token )
break ;
details . players [ clnum ] . ping = atoi ( token ) ;
token = strchr ( token + 1 , ' \" ' ) ;
if ( ! token )
break ;
msg = strchr ( token + 1 , ' \" ' ) ;
if ( ! msg )
break ;
len = msg - token ;
if ( len > = sizeof ( details . players [ clnum ] . name ) )
len = sizeof ( details . players [ clnum ] . name ) ;
Q_strncpyz ( details . players [ clnum ] . name , token + 1 , len ) ;
details . players [ clnum ] . name [ len ] = ' \0 ' ;
token = strchr ( msg + 1 , ' \" ' ) ;
if ( ! token )
break ;
msg = strchr ( token + 1 , ' \" ' ) ;
if ( ! msg )
break ;
len = msg - token ;
if ( len > = sizeof ( details . players [ clnum ] . skin ) )
len = sizeof ( details . players [ clnum ] . skin ) ;
Q_strncpyz ( details . players [ clnum ] . skin , token + 1 , len ) ;
details . players [ clnum ] . skin [ len ] = ' \0 ' ;
token = strchr ( msg + 1 , ' ' ) ;
if ( ! token )
break ;
details . players [ clnum ] . topc = atoi ( token ) ;
token = strchr ( token + 1 , ' ' ) ;
if ( ! token )
break ;
details . players [ clnum ] . botc = atoi ( token ) ;
}
MasterInfo_AddPlayer ( info - > adr , details . players [ clnum ] . name , details . players [ clnum ] . ping , details . players [ clnum ] . frags , details . players [ clnum ] . topc * 4 | details . players [ clnum ] . botc , details . players [ clnum ] . skin ) ;
info - > players = + + details . numplayers ;
msg = nl ;
if ( ! msg )
break ; //erm...
msg + + ;
}
}
if ( ! info - > moreinfo & & ( ( slist_cacheinfo . value = = 2 | | NET_CompareAdr ( info - > adr , selectedserver . adr ) ) | | ( info - > special & SS_KEEPINFO ) ) )
info - > moreinfo = Z_Malloc ( sizeof ( serverdetailedinfo_t ) ) ;
if ( NET_CompareAdr ( info - > adr , selectedserver . adr ) )
selectedserver . detail = info - > moreinfo ;
if ( info - > moreinfo )
memcpy ( info - > moreinfo , & details , sizeof ( serverdetailedinfo_t ) ) ;
return true ;
}
//rewrite to scan for existing server instead of wiping all.
2009-04-01 22:03:56 +00:00
void CL_MasterListParse ( netadrtype_t adrtype , int type , qboolean slashpad )
2004-08-23 00:15:46 +00:00
{
serverinfo_t * info ;
serverinfo_t * last , * old ;
2009-04-01 22:03:56 +00:00
int adrlen ;
2004-08-23 00:15:46 +00:00
int p1 , p2 ;
2008-06-08 14:37:57 +00:00
char adr [ MAX_ADR_SIZE ] ;
2009-04-01 22:03:56 +00:00
int i ;
switch ( adrtype )
{
case NA_IP :
adrlen = 4 ;
break ;
case NA_IPV6 :
adrlen = 16 ;
break ;
case NA_IPX :
adrlen = 10 ;
break ;
default :
return ;
}
2008-06-08 14:37:57 +00:00
2004-08-23 00:15:46 +00:00
MSG_ReadByte ( ) ;
last = firstserver ;
2009-04-01 22:03:56 +00:00
while ( msg_readcount + adrlen + 2 < net_message . cursize )
2004-08-23 00:15:46 +00:00
{
2005-05-17 02:36:54 +00:00
if ( slashpad )
{
if ( MSG_ReadByte ( ) ! = ' \\ ' )
break ;
}
2004-08-23 00:15:46 +00:00
info = Z_Malloc ( sizeof ( serverinfo_t ) ) ;
2009-04-01 22:03:56 +00:00
info - > adr . type = adrtype ;
switch ( adrtype )
{
case NA_IP :
case NA_IPV6 :
case NA_IPX :
//generic fixed-length addresses
for ( i = 0 ; i < adrlen ; i + + )
( ( qbyte * ) & info - > adr . address ) [ i ] = MSG_ReadByte ( ) ;
break ;
}
2004-08-23 00:15:46 +00:00
p1 = MSG_ReadByte ( ) ;
p2 = MSG_ReadByte ( ) ;
2005-05-26 12:55:34 +00:00
info - > adr . port = htons ( ( unsigned short ) ( ( p1 < < 8 ) | p2 ) ) ;
2005-05-17 02:36:54 +00:00
if ( ! info - > adr . port )
{
Z_Free ( info ) ;
break ;
}
2004-08-23 00:15:46 +00:00
if ( ( old = Master_InfoForServer ( info - > adr ) ) ) //remove if the server already exists.
{
2005-05-13 10:42:48 +00:00
old - > sends = 1 ; //reset.
2004-08-23 00:15:46 +00:00
Z_Free ( info ) ;
}
else
{
2005-05-17 02:36:54 +00:00
info - > sends = 1 ;
info - > special = type ;
2004-08-23 00:15:46 +00:00
info - > refreshtime = 0 ;
2008-06-08 14:37:57 +00:00
snprintf ( info - > name , sizeof ( info - > name ) , " %s " , NET_AdrToString ( adr , sizeof ( adr ) , info - > adr ) ) ;
2004-08-23 00:15:46 +00:00
info - > next = last ;
last = info ;
2008-11-09 22:29:28 +00:00
Master_ResortServer ( info ) ;
2004-08-23 00:15:46 +00:00
}
}
firstserver = last ;
}
# endif
2010-03-14 14:35:56 +00:00