2014-12-23 15:26:42 +00:00
/*
serverside master heartbeat code
clientside master queries and server ping / polls
*/
2004-08-23 00:15:46 +00:00
2014-12-23 15:26:42 +00:00
# include "quakedef.h"
2004-08-23 00:15:46 +00:00
# include "cl_master.h"
2014-12-23 15:26:42 +00:00
qboolean sb_enablequake2 ;
qboolean sb_enablequake3 ;
qboolean sb_enablenetquake ;
qboolean sb_enabledarkplaces ;
qboolean sb_enablequakeworld ;
void Master_DetermineMasterTypes ( void )
{
if ( com_protocolname . modified )
{
2017-01-13 00:39:50 +00:00
char tok [ MAX_QPATH ] ;
2014-12-23 15:26:42 +00:00
char * prot = com_protocolname . string ;
2017-01-13 00:39:50 +00:00
char * game ;
2014-12-23 15:26:42 +00:00
com_protocolname . modified = 0 ;
sb_enabledarkplaces = true ; //dpmaster is not specific to any single game/mod, so can be left enabled even when running q2 etc, for extra redundancy.
sb_enablequake2 = false ;
sb_enablequake3 = false ;
sb_enablenetquake = false ;
sb_enablequakeworld = false ;
2017-01-13 00:39:50 +00:00
for ( prot = com_protocolname . string ; * prot ; )
{
prot = COM_ParseOut ( prot , tok , sizeof ( tok ) ) ;
game = tok ;
//this is stupid, but hey
if ( ! Q_strncasecmp ( game , " FTE- " , 4 ) )
game + = 4 ;
else if ( ! Q_strncasecmp ( game , " DarkPlaces- " , 11 ) )
game + = 11 ;
if ( ! strcmp ( game , " Quake2 " ) )
sb_enablequake2 = true ;
if ( ! strcmp ( game , " Quake3 " ) )
sb_enablequake3 = true ;
//for DP compatibility, we consider these separate(ish) games.
if ( ! strcmp ( game , " Quake " ) | | ! strcmp ( game , " Hipnotic " ) | | ! strcmp ( game , " Rogue " ) )
sb_enablenetquake = sb_enablequakeworld = true ;
}
2014-12-23 15:26:42 +00:00
}
}
2014-12-23 15:39:39 +00:00
# define MAX_MASTER_ADDRESSES 4 //each master might have multiple dns addresses, typically both ipv4+ipv6. we want to report to both address families so we work with remote single-stack hosts.
2014-12-23 15:26:42 +00:00
# ifndef CLIENTONLY
2015-04-21 04:12:00 +00:00
static void QDECL Net_Masterlist_Callback ( struct cvar_s * var , char * oldvalue ) ;
2014-12-23 15:26:42 +00:00
static void SV_SetMaster_f ( void ) ;
# else
# define Net_Masterlist_Callback NULL
# endif
extern cvar_t sv_public ;
extern cvar_t sv_reportheartbeats ;
extern cvar_t sv_listen_qw ;
extern cvar_t sv_listen_nq ;
extern cvar_t sv_listen_dp ;
extern cvar_t sv_listen_q3 ;
2017-05-18 10:24:09 +00:00
# ifdef HAVE_DTLS
extern cvar_t sv_listen_dtls ;
# endif
2014-12-23 15:26:42 +00:00
typedef struct {
enum masterprotocol_e protocol ;
cvar_t cv ;
char * comment ;
# ifndef CLIENTONLY
qboolean needsresolve ; //set any time the cvar is modified
qboolean resolving ; //set any time the cvar is modified
netadr_t adr [ MAX_MASTER_ADDRESSES ] ;
# endif
} net_masterlist_t ;
net_masterlist_t net_masterlist [ ] = {
2017-02-19 00:15:42 +00:00
# ifndef QUAKETC
2014-12-23 15:26:42 +00:00
//user-specified master lists.
{ MP_QUAKEWORLD , CVARC ( " net_qwmaster1 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKEWORLD , CVARC ( " net_qwmaster2 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKEWORLD , CVARC ( " net_qwmaster3 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKEWORLD , CVARC ( " net_qwmaster4 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKEWORLD , CVARC ( " net_qwmaster5 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKEWORLD , CVARC ( " net_qwmaster6 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKEWORLD , CVARC ( " net_qwmaster7 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKEWORLD , CVARC ( " net_qwmaster8 " , " " , Net_Masterlist_Callback ) } ,
2017-02-19 00:15:42 +00:00
# endif
2014-12-23 15:26:42 +00:00
//dpmaster is the generic non-quake-specific master protocol that we use for custom stand-alone mods.
{ MP_DPMASTER , CVARAFC ( " net_master1 " , " " , " sv_master1 " , 0 , Net_Masterlist_Callback ) } ,
{ MP_DPMASTER , CVARAFC ( " net_master2 " , " " , " sv_master2 " , 0 , Net_Masterlist_Callback ) } ,
{ MP_DPMASTER , CVARAFC ( " net_master3 " , " " , " sv_master3 " , 0 , Net_Masterlist_Callback ) } ,
{ MP_DPMASTER , CVARAFC ( " net_master4 " , " " , " sv_master4 " , 0 , Net_Masterlist_Callback ) } ,
{ MP_DPMASTER , CVARAFC ( " net_master5 " , " " , " sv_master5 " , 0 , Net_Masterlist_Callback ) } ,
{ MP_DPMASTER , CVARAFC ( " net_master6 " , " " , " sv_master6 " , 0 , Net_Masterlist_Callback ) } ,
{ MP_DPMASTER , CVARAFC ( " net_master7 " , " " , " sv_master7 " , 0 , Net_Masterlist_Callback ) } ,
{ MP_DPMASTER , CVARAFC ( " net_master8 " , " " , " sv_master8 " , 0 , Net_Masterlist_Callback ) } ,
2017-02-19 00:15:42 +00:00
# ifdef Q2CLIENT
2014-12-23 15:26:42 +00:00
{ MP_QUAKE2 , CVARC ( " net_q2master1 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKE2 , CVARC ( " net_q2master2 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKE2 , CVARC ( " net_q2master3 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKE2 , CVARC ( " net_q2master4 " , " " , Net_Masterlist_Callback ) } ,
2017-02-19 00:15:42 +00:00
# endif
2014-12-23 15:26:42 +00:00
2017-02-19 00:15:42 +00:00
# ifdef Q3CLIENT
2014-12-23 15:26:42 +00:00
{ MP_QUAKE3 , CVARC ( " net_q3master1 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKE3 , CVARC ( " net_q3master2 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKE3 , CVARC ( " net_q3master3 " , " " , Net_Masterlist_Callback ) } ,
{ MP_QUAKE3 , CVARC ( " net_q3master4 " , " " , Net_Masterlist_Callback ) } ,
2017-02-19 00:15:42 +00:00
# endif
2014-12-23 15:26:42 +00:00
2017-02-19 00:15:42 +00:00
# ifndef QUAKETC
2014-12-23 15:26:42 +00:00
//engine-specified/maintained master lists (so users can be lazy and update the engine without having to rewrite all their configs).
{ MP_QUAKEWORLD , CVARFC ( " net_qwmasterextra1 " , " qwmaster.ocrana.de:27000 " , CVAR_NOSAVE , Net_Masterlist_Callback ) , " Ocrana(2nd) " } , //german. admin unknown
{ MP_QUAKEWORLD , CVARFC ( " net_qwmasterextra2 " , " " /*"masterserver.exhale.de:27000" seems dead*/ , CVAR_NOSAVE , Net_Masterlist_Callback ) } , //german. admin unknown
{ MP_QUAKEWORLD , CVARFC ( " net_qwmasterextra3 " , " asgaard.morphos-team.net:27000 " , CVAR_NOSAVE , Net_Masterlist_Callback ) , " Germany, admin: bigfoot " } ,
{ MP_QUAKEWORLD , CVARFC ( " net_qwmasterextra4 " , " master.quakeservers.net:27000 " , CVAR_NOSAVE , Net_Masterlist_Callback ) , " Germany, admin: raz0? " } ,
{ MP_QUAKEWORLD , CVARFC ( " net_qwmasterextra5 " , " qwmaster.fodquake.net:27000 " , CVAR_NOSAVE , Net_Masterlist_Callback ) , " admin: bigfoot " } ,
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "satan.idsoftware.com:27000", CVAR_NOSAVE, Net_Masterlist_Callback), "Official id Master"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "satan.idsoftware.com:27002", CVAR_NOSAVE, Net_Masterlist_Callback), "Official id Master For CTF Servers"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "satan.idsoftware.com:27003", CVAR_NOSAVE, Net_Masterlist_Callback), "Official id Master For TeamFortress Servers"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "satan.idsoftware.com:27004", CVAR_NOSAVE, Net_Masterlist_Callback), "Official id Master For Miscilaneous Servers"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "satan.idsoftware.com:27006", CVAR_NOSAVE, Net_Masterlist_Callback), "Official id Master For Deathmatch Servers"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "150.254.66.120:27000", CVAR_NOSAVE, Net_Masterlist_Callback), "Poland"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "62.112.145.129:27000", CVAR_NOSAVE, Net_Masterlist_Callback), "Ocrana (original)"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "master.edome.net", CVAR_NOSAVE, Net_Masterlist_Callback), "edome"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "qwmaster.barrysworld.com", CVAR_NOSAVE, Net_Masterlist_Callback), "barrysworld"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "213.221.174.165:27000", CVAR_NOSAVE, Net_Masterlist_Callback), "unknown1"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "195.74.0.8", CVAR_NOSAVE, Net_Masterlist_Callback), "unknown2"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "204.182.161.2", CVAR_NOSAVE, Net_Masterlist_Callback), "unknown5"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "kubus.rulez.pl:27000", CVAR_NOSAVE, Net_Masterlist_Callback), "kubus.rulez.pl"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "telefrag.me:27000", CVAR_NOSAVE, Net_Masterlist_Callback), "telefrag.me"},
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "master.teamdamage.com:27000", CVAR_NOSAVE, Net_Masterlist_Callback), "master.teamdamage.com"},
2017-02-19 00:15:42 +00:00
# endif
2014-12-23 15:26:42 +00:00
2016-09-08 19:04:35 +00:00
{ MP_DPMASTER , CVARFC ( " net_masterextra1 " , " ghdigital.com:27950 207.55.114.154:27950 " , CVAR_NOSAVE , Net_Masterlist_Callback ) } , //207.55.114.154 (was 69.59.212.88 (admin: LordHavoc)
2014-12-23 15:26:42 +00:00
{ MP_DPMASTER , CVARFC ( " net_masterextra2 " , " dpmaster.deathmask.net:27950 107.161.23.68:27950 [2604:180::4ac:98c1]:27950 " , CVAR_NOSAVE , Net_Masterlist_Callback ) } , //107.161.23.68 (admin: Willis)
{ MP_DPMASTER , CVARFC ( " net_masterextra3 " , " dpmaster.tchr.no:27950 92.62.40.73:27950 " , CVAR_NOSAVE , Net_Masterlist_Callback ) } , //92.62.40.73 (admin: tChr)
2017-02-19 00:15:42 +00:00
# ifdef Q2CLIENT
2014-12-23 15:26:42 +00:00
// {MP_QUAKE2, CVARFC("net_q2masterextra1", "satan.idsoftware.com:27900", CVAR_NOSAVE, Net_Masterlist_Callback), "Official Quake2 master server"},
// {MP_QUAKE2, CVARFC("net_q2masterextra1", "master.planetgloom.com:27900", CVAR_NOSAVE, Net_Masterlist_Callback)}, //?
// {MP_QUAKE2, CVARFC("net_q2masterextra1", "master.q2servers.com:27900", CVAR_NOSAVE, Net_Masterlist_Callback)}, //?
{ MP_QUAKE2 , CVARFC ( " net_q2masterextra1 " , " netdome.biz:27900 " , CVAR_NOSAVE , Net_Masterlist_Callback ) } , //?
2017-02-19 00:15:42 +00:00
# endif
2014-12-23 15:26:42 +00:00
2017-02-19 00:15:42 +00:00
# ifdef Q3CLIENT
2014-12-23 15:26:42 +00:00
// {MP_QUAKE3, CVARFC("net_q3masterextra1", "masterserver.exhale.de:27950", CVAR_NOSAVE, Net_Masterlist_Callback), "Official Quake3 master server"},
{ MP_QUAKE3 , CVARFC ( " net_q3masterextra1 " , " master.quake3arena.com:27950 " , CVAR_NOSAVE , Net_Masterlist_Callback ) , " Official Quake3 master server " } ,
2017-02-19 00:15:42 +00:00
# endif
2014-12-23 15:26:42 +00:00
{ MP_UNSPECIFIED , CVAR ( NULL , NULL ) }
} ;
void Net_Master_Init ( void )
{
int i ;
for ( i = 0 ; net_masterlist [ i ] . cv . name ; i + + )
Cvar_Register ( & net_masterlist [ i ] . cv , " master servers " ) ;
# ifndef CLIENTONLY
Cmd_AddCommand ( " setmaster " , SV_SetMaster_f ) ;
# endif
}
# ifndef CLIENTONLY
2015-04-21 04:12:00 +00:00
static void QDECL Net_Masterlist_Callback ( struct cvar_s * var , char * oldvalue )
2014-12-23 15:26:42 +00:00
{
int i ;
for ( i = 0 ; net_masterlist [ i ] . cv . name ; i + + )
{
if ( var = = & net_masterlist [ i ] . cv )
break ;
}
if ( ! net_masterlist [ i ] . cv . name )
return ;
net_masterlist [ i ] . needsresolve = true ;
}
void SV_Master_SingleHeartbeat ( net_masterlist_t * master )
{
char string [ 2048 ] ;
qboolean madeqwstring = false ;
char adr [ MAX_ADR_SIZE ] ;
netadr_t * na ;
int i ;
for ( i = 0 ; i < MAX_MASTER_ADDRESSES ; i + + )
{
na = & master - > adr [ i ] ;
if ( na - > port )
{
switch ( master - > protocol )
{
case MP_QUAKEWORLD :
if ( sv_listen_qw . value )
{
if ( ! madeqwstring )
{
int active , j ;
// count active users
active = 0 ;
for ( j = 0 ; j < svs . allocated_client_slots ; j + + )
if ( svs . clients [ j ] . state = = cs_connected | |
svs . clients [ j ] . state = = cs_spawned )
active + + ;
sprintf ( string , " %c \n %i \n %i \n " , S2M_HEARTBEAT ,
svs . heartbeat_sequence , active ) ;
madeqwstring = true ;
}
if ( sv_reportheartbeats . value )
Con_TPrintf ( " Sending heartbeat to %s (%s) \n " , NET_AdrToString ( adr , sizeof ( adr ) , na ) , master - > cv . string ) ;
NET_SendPacket ( NS_SERVER , strlen ( string ) , string , na ) ;
}
break ;
case MP_QUAKE2 :
if ( svs . gametype = = GT_QUAKE2 & & sv_listen_qw . value ) //set listen to 1 to allow qw connections, 2 to allow nq connections too.
{
if ( sv_reportheartbeats . value )
Con_TPrintf ( " Sending heartbeat to %s (%s) \n " , NET_AdrToString ( adr , sizeof ( adr ) , na ) , master - > cv . string ) ;
{
char * str = " \377 \377 \377 \377 heartbeat \n %s " ;
char * q2statusresp = " " ;
NET_SendPacket ( NS_SERVER , strlen ( str ) , va ( str , q2statusresp ) , na ) ;
}
}
break ;
case MP_DPMASTER :
if ( sv_listen_dp . value | | sv_listen_nq . value ) //set listen to 1 to allow qw connections, 2 to allow nq connections too.
{
if ( sv_reportheartbeats . value )
Con_TPrintf ( " Sending heartbeat to %s (%s) \n " , NET_AdrToString ( adr , sizeof ( adr ) , na ) , master - > cv . string ) ;
{
//darkplaces here refers to the master server protocol, rather than the game protocol
//(specifies that the server responds to infoRequest packets from the master)
char * str = " \377 \377 \377 \377 heartbeat DarkPlaces \x0A " ;
NET_SendPacket ( NS_SERVER , strlen ( str ) , str , na ) ;
}
}
break ;
default :
break ;
}
}
}
}
//main thread
struct thr_res
{
qboolean success ;
netadr_t na [ 8 ] ;
char str [ 1 ] ; //trailing
} ;
void SV_Master_Worker_Resolved ( void * ctx , void * data , size_t a , size_t b )
{
int i ;
struct thr_res * work = data ;
netadr_t * na ;
net_masterlist_t * master = & net_masterlist [ a ] ;
master - > resolving = false ;
//only accept the result if the master wasn't changed while we were still resolving it. no race conditions please.
if ( ! strcmp ( master - > cv . string , work - > str ) )
{
master - > needsresolve = false ;
for ( i = 0 ; i < MAX_MASTER_ADDRESSES ; i + + )
{
na = & master - > adr [ i ] ;
* na = work - > na [ i ] ;
master - > needsresolve = false ;
if ( na - > type = = NA_INVALID )
memset ( na , 0 , sizeof ( * na ) ) ;
else
{
//fix up default ports if not specified
if ( ! na - > port )
{
switch ( master - > protocol )
{
2015-02-02 08:01:53 +00:00
case MP_UNSPECIFIED :
case MP_NETQUAKE :
2014-12-23 15:26:42 +00:00
case MP_DPMASTER : na - > port = BigShort ( 27950 ) ; break ;
case MP_QUAKE2 : na - > port = BigShort ( 27000 ) ; break ; //FIXME: verify
case MP_QUAKE3 : na - > port = BigShort ( 27950 ) ; break ;
case MP_QUAKEWORLD : na - > port = BigShort ( 27000 ) ; break ;
}
}
//some master servers require a ping to get them going or so
if ( sv . state )
{
//tcp masters require a route
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
if ( NET_AddrIsReliable ( na ) )
2014-12-23 15:26:42 +00:00
NET_EnsureRoute ( svs . sockets , master - > cv . name , master - > cv . string , false ) ;
//q2+qw masters are given a ping to verify that they're still up
switch ( master - > protocol )
{
case MP_QUAKE2 :
NET_SendPacket ( NS_SERVER , 8 , " \xff \xff \xff \xff ping " , na ) ;
break ;
case MP_QUAKEWORLD :
//qw does this for some reason, keep the behaviour even though its unreliable thus pointless
NET_SendPacket ( NS_SERVER , 2 , " k \0 " , na ) ;
break ;
default :
break ;
}
}
}
}
if ( ! work - > success )
Con_TPrintf ( " Couldn't resolve master \" %s \" \n " , master - > cv . string ) ;
else
SV_Master_SingleHeartbeat ( master ) ;
}
Z_Free ( work ) ;
}
//worker thread
void SV_Master_Worker_Resolve ( void * ctx , void * data , size_t a , size_t b )
{
char token [ 1024 ] ;
int found = 0 ;
qboolean first = true ;
char * str ;
struct thr_res * work = data ;
str = work - > str ;
while ( str & & * str )
{
str = COM_ParseOut ( str , token , sizeof ( token ) ) ;
if ( * token )
found + = NET_StringToAdr2 ( token , 0 , & work - > na [ found ] , MAX_MASTER_ADDRESSES - found ) ;
if ( first & & found )
break ; //if we found one by name, don't try any fallback ip addresses.
first = false ;
}
work - > success = ! ! found ;
2016-02-15 06:01:17 +00:00
COM_AddWork ( WG_MAIN , SV_Master_Worker_Resolved , NULL , work , a , b ) ;
2014-12-23 15:26:42 +00:00
}
/*
= = = = = = = = = = = = = = = =
Master_Heartbeat
Send a message to the master every few minutes to
let it know we are alive , and log information
= = = = = = = = = = = = = = = =
*/
# define HEARTBEAT_SECONDS 300
void SV_Master_Heartbeat ( void )
{
int i ;
qboolean enabled ;
2015-07-06 14:47:46 +00:00
if ( sv_public . ival < = 0 | | SSV_IsSubServer ( ) )
2014-12-23 15:26:42 +00:00
return ;
if ( realtime - HEARTBEAT_SECONDS - svs . last_heartbeat < HEARTBEAT_SECONDS )
return ; // not time to send yet
svs . last_heartbeat = realtime - HEARTBEAT_SECONDS ;
svs . heartbeat_sequence + + ;
Master_DetermineMasterTypes ( ) ;
// send to group master
for ( i = 0 ; net_masterlist [ i ] . cv . name ; i + + )
{
switch ( net_masterlist [ i ] . protocol )
{
case MP_DPMASTER : enabled = sb_enabledarkplaces ; break ;
case MP_QUAKE2 : enabled = sb_enablequake2 ; break ;
case MP_QUAKE3 : enabled = sb_enablequake3 ; break ;
case MP_QUAKEWORLD : enabled = sb_enablequakeworld ; break ;
default : enabled = false ; break ;
}
if ( ! enabled )
continue ;
if ( net_masterlist [ i ] . resolving )
continue ;
if ( net_masterlist [ i ] . needsresolve )
{
if ( ! * net_masterlist [ i ] . cv . string | | * net_masterlist [ i ] . cv . string = = ' * ' )
memset ( net_masterlist [ i ] . adr , 0 , sizeof ( net_masterlist [ i ] . adr ) ) ;
else
{
struct thr_res * work = Z_Malloc ( sizeof ( * work ) + strlen ( net_masterlist [ i ] . cv . string ) ) ;
strcpy ( work - > str , net_masterlist [ i ] . cv . string ) ;
net_masterlist [ i ] . resolving = true ; //don't spam work
2016-02-15 06:01:17 +00:00
COM_AddWork ( WG_MAIN , SV_Master_Worker_Resolve , NULL , work , i , 0 ) ;
2014-12-23 15:26:42 +00:00
}
}
else
SV_Master_SingleHeartbeat ( & net_masterlist [ i ] ) ;
}
}
static void SV_Master_Add ( int type , char * stringadr )
{
int i ;
for ( i = 0 ; net_masterlist [ i ] . cv . name ; i + + )
{
if ( net_masterlist [ i ] . protocol ! = type )
continue ;
if ( ! * net_masterlist [ i ] . cv . string )
break ;
}
if ( ! net_masterlist [ i ] . cv . name )
{
Con_Printf ( " Too many masters \n " ) ;
return ;
}
Cvar_Set ( & net_masterlist [ i ] . cv , stringadr ) ;
svs . last_heartbeat = - 99999 ;
}
void SV_Master_ClearAll ( void )
{
int i ;
for ( i = 0 ; net_masterlist [ i ] . cv . name ; i + + )
{
Cvar_Set ( & net_masterlist [ i ] . cv , " " ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = =
SV_SetMaster_f
Make a master server current . deprecated in favour of setting numbered masters via configs / engine source code .
only supports qw masters .
= = = = = = = = = = = = = = = = = = = =
*/
static void SV_SetMaster_f ( void )
{
int i ;
SV_Master_ClearAll ( ) ;
if ( ! strcmp ( Cmd_Argv ( 1 ) , " none " ) )
{
if ( cl_warncmd . ival )
Con_Printf ( " Entering no-master mode \n " ) ;
return ;
}
if ( ! strcmp ( Cmd_Argv ( 1 ) , " clear " ) )
return ;
if ( ! strcmp ( Cmd_Argv ( 1 ) , " default " ) )
{
for ( i = 0 ; net_masterlist [ i ] . cv . name ; i + + )
Cvar_Set ( & net_masterlist [ i ] . cv , net_masterlist [ i ] . cv . enginevalue ) ;
return ;
}
Cvar_Set ( & sv_public , " 1 " ) ; //go public.
for ( i = 1 ; i < Cmd_Argc ( ) ; i + + )
{
SV_Master_Add ( MP_QUAKEWORLD , Cmd_Argv ( i ) ) ;
}
svs . last_heartbeat = - 99999 ;
}
void SV_Master_ReResolve ( void )
{
int i ;
for ( i = 0 ; net_masterlist [ i ] . cv . name ; i + + )
{
net_masterlist [ i ] . needsresolve = true ;
}
//trigger a heartbeat at the next available opportunity.
svs . last_heartbeat = - 9999 ;
}
/*
= = = = = = = = = = = = = = = = =
Master_Shutdown
Informs all masters that this server is going down
= = = = = = = = = = = = = = = = =
*/
void SV_Master_Shutdown ( void )
{
char string [ 2048 ] ;
char adr [ MAX_ADR_SIZE ] ;
int i , j ;
netadr_t * na ;
//note that if a master server actually blindly listens to this then its exploitable.
//we send it out anyway as for us its all good.
//master servers ought to try and check up on the status of the server first, if they listen to this.
sprintf ( string , " %c \n " , S2M_SHUTDOWN ) ;
// send to group master
for ( i = 0 ; net_masterlist [ i ] . cv . name ; i + + )
{
for ( j = 0 ; j < MAX_MASTER_ADDRESSES ; j + + )
{
na = & net_masterlist [ i ] . adr [ j ] ;
if ( na - > port )
{
switch ( net_masterlist [ i ] . protocol )
{
case MP_QUAKEWORLD :
if ( sv_reportheartbeats . value )
Con_TPrintf ( " Sending shutdown to %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , na ) ) ;
NET_SendPacket ( NS_SERVER , strlen ( string ) , string , na ) ;
break ;
//dp has no shutdown
default :
break ;
}
}
}
}
}
# endif
# if defined(CL_MASTER) && !defined(SERVERONLY)
2004-08-23 00:15:46 +00:00
# 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.
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
//the number of servers should be limited only by memory.
2016-09-08 19:04:35 +00:00
cvar_t slist_cacheinfo = CVAR ( " slist_cacheinfo " , " 0 " ) ; //this proves dangerous, memory wise.
cvar_t slist_writeserverstxt = CVAR ( " 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 ) ;
2013-10-29 17:58:20 +00:00
int CL_ReadServerInfo ( char * msg , enum masterprotocol_e prototype , qboolean favorite ) ;
2012-11-27 03:23:19 +00:00
void MasterInfo_RemoveAllPlayers ( void ) ;
2004-08-23 00:15:46 +00:00
master_t * master ;
player_t * mplayers ;
serverinfo_t * firstserver ;
2013-03-12 23:09:25 +00:00
struct selectedserver_s selectedserver ;
2004-08-23 00:15:46 +00:00
2005-05-13 10:42:48 +00:00
static serverinfo_t * * visibleservers ;
static int numvisibleservers ;
static int maxvisibleservers ;
static hostcachekey_t sortfield ;
static qboolean decreasingorder ;
typedef struct {
hostcachekey_t fieldindex ;
float operandi ;
2014-03-30 08:55:06 +00:00
const char * operands ;
2005-05-13 10:42:48 +00:00
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 ] ;
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
char pollsocketsBCast [ POLLTOTALSOCKETS ] ;
2009-04-01 22:03:56 +00:00
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 + + ;
}
2016-07-12 00:40:13 +00:00
server - > status & = ~ 2u ;
2005-05-13 10:42:48 +00:00
}
void Master_InsertAt ( serverinfo_t * server , int pos )
{
int i ;
2011-12-23 03:12:29 +00:00
if ( numvisibleservers > = maxvisibleservers )
{
maxvisibleservers = maxvisibleservers + 10 ;
visibleservers = BZ_Realloc ( visibleservers , maxvisibleservers * sizeof ( serverinfo_t * ) ) ;
}
2005-05-13 10:42:48 +00:00
for ( i = numvisibleservers ; i > pos ; i - - )
{
visibleservers [ i ] = visibleservers [ i - 1 ] ;
}
visibleservers [ pos ] = server ;
numvisibleservers + + ;
2016-07-12 00:40:13 +00:00
server - > status | = 2u ;
2005-05-13 10:42:48 +00:00
}
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 ;
2013-03-12 22:47:42 +00:00
case SLIST_TEST_STARTSWITH :
2005-05-13 10:42:48 +00:00
case SLIST_TEST_EQUAL :
return a = = b ;
case SLIST_TEST_GREATER :
return a > b ;
case SLIST_TEST_GREATEREQUAL :
return a > = b ;
2013-03-12 22:47:42 +00:00
case SLIST_TEST_NOTSTARTSWITH :
2005-05-13 10:42:48 +00:00
case SLIST_TEST_NOTEQUAL :
return a ! = b ;
}
return false ;
}
2014-03-30 08:55:06 +00:00
qboolean Master_CompareString ( const char * a , const char * b , slist_test_t rule )
2005-05-13 10:42:48 +00:00
{
switch ( rule )
{
2013-03-12 22:47:42 +00:00
case SLIST_TEST_STARTSWITH :
2015-06-16 23:53:58 +00:00
return Q_strncasecmp ( a , b , strlen ( b ) ) = = 0 ;
2013-03-12 22:47:42 +00:00
case SLIST_TEST_NOTSTARTSWITH :
2015-06-16 23:53:58 +00:00
return Q_strncasecmp ( a , b , strlen ( b ) ) ! = 0 ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_CONTAINS :
2015-06-16 23:53:58 +00:00
return ! ! Q_strcasestr ( a , b ) ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_NOTCONTAIN :
2015-06-16 23:53:58 +00:00
return ! Q_strcasestr ( a , b ) ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_LESSEQUAL :
2015-06-16 23:53:58 +00:00
return Q_strcasecmp ( a , b ) < = 0 ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_LESS :
2015-06-16 23:53:58 +00:00
return Q_strcasecmp ( a , b ) < 0 ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_EQUAL :
2015-06-16 23:53:58 +00:00
return Q_strcasecmp ( a , b ) = = 0 ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_GREATER :
2015-06-16 23:53:58 +00:00
return Q_strcasecmp ( a , b ) > 0 ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_GREATEREQUAL :
2015-06-16 23:53:58 +00:00
return Q_strcasecmp ( a , b ) > = 0 ;
2005-05-13 10:42:48 +00:00
case SLIST_TEST_NOTEQUAL :
2015-06-16 23:53:58 +00:00
return Q_strcasecmp ( 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 :
2015-06-16 23:53:58 +00:00
if ( a - > adr . type ! = b - > adr . type )
return a - > adr . type < b - > adr . type ;
if ( a - > adr . type = = NA_IP )
{
int i ;
for ( i = 0 ; i < 4 ; i + + )
{
if ( a - > adr . address . ip [ i ] ! = b - > adr . address . ip [ i ] )
return a - > adr . address . ip [ i ] < b - > adr . address . ip [ i ] ;
}
}
if ( a - > adr . type = = NA_IPV6 )
{
int i ;
for ( i = 0 ; i < 16 ; i + + )
{
if ( a - > adr . address . ip6 [ i ] ! = b - > adr . address . ip6 [ i ] )
return a - > adr . address . ip6 [ i ] < b - > adr . address . ip6 [ i ] ;
}
}
return false ;
2007-08-07 19:16:32 +00:00
break ;
2006-02-28 00:46:04 +00:00
case SLKEY_BASEGAME :
2014-12-23 15:26:42 +00:00
return Master_CompareInteger ( a - > special & SS_PROTOCOLMASK , b - > special & SS_PROTOCOLMASK , SLIST_TEST_LESS ) ;
case SLKEY_FLAGS :
return Master_CompareInteger ( a - > special & ~ SS_PROTOCOLMASK , b - > special & ~ SS_PROTOCOLMASK , 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 ) ;
2015-06-19 16:56:50 +00:00
case SLKEY_NUMHUMANS :
return Master_CompareInteger ( a - > numhumans , b - > numhumans , SLIST_TEST_LESS ) ;
2015-06-22 11:49:15 +00:00
case SLKEY_NUMSPECTATORS :
return Master_CompareInteger ( a - > numspectators , b - > numspectators , SLIST_TEST_LESS ) ;
2015-06-19 16:56:50 +00:00
case SLKEY_NUMBOTS :
return Master_CompareInteger ( a - > numbots , b - > numbots , SLIST_TEST_LESS ) ;
2007-08-07 19:16:32 +00:00
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 ;
2011-05-15 13:23:13 +00:00
2015-05-03 19:57:46 +00:00
case SLKEY_ISPROXY :
return Master_CompareInteger ( a - > special & SS_PROXY , b - > special & SS_PROXY , SLIST_TEST_LESS ) ;
case SLKEY_ISLOCAL :
return Master_CompareInteger ( a - > special & SS_LOCAL , b - > special & SS_LOCAL , SLIST_TEST_LESS ) ;
case SLKEY_ISFAVORITE :
return Master_CompareInteger ( a - > special & SS_FAVORITE , b - > special & SS_FAVORITE , SLIST_TEST_LESS ) ;
2011-05-15 13:23:13 +00:00
case SLKEY_MOD :
case SLKEY_PROTOCOL :
case SLKEY_QCSTATUS :
2015-05-03 19:57:46 +00:00
case SLKEY_SERVERINFO :
case SLKEY_PLAYER0 :
default :
2011-05-15 13:23:13 +00:00
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 ;
2014-12-23 15:26:42 +00:00
// qboolean enabled;
2005-05-13 10:42:48 +00:00
//always filter out dead unresponsive servers.
if ( ! a - > ping )
return false ;
2014-12-23 15:26:42 +00:00
/* switch(a->special & SS_PROTOCOLMASK)
{
case SS_QUAKE3 : enabled = sb_enablequake3 ; break ;
case SS_QUAKE2 : enabled = sb_enablequake2 ; break ;
case SS_NETQUAKE : enabled = sb_enablenetquake ; break ;
case SS_QUAKEWORLD : enabled = sb_enablequakeworld ; break ;
case SS_DARKPLACES : enabled = sb_enabledarkplaces ; break ;
default : enabled = true ; break ;
}
if ( ! enabled )
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 ;
2015-06-22 11:49:15 +00:00
case SLKEY_NUMSPECTATORS :
res = Master_CompareInteger ( a - > numspectators , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
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 :
2014-12-23 15:26:42 +00:00
res = Master_CompareInteger ( a - > special & SS_PROTOCOLMASK , visrules [ i ] . operandi , visrules [ i ] . compareop ) ;
break ;
case SLKEY_FLAGS :
res = Master_CompareInteger ( a - > special & ~ SS_PROTOCOLMASK , 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 ;
}
2014-03-30 08:55:06 +00:00
void Master_SetMaskString ( qboolean or , hostcachekey_t field , const char * param , slist_test_t testop )
2005-05-13 10:42:48 +00:00
{
if ( numvisrules = = MAX_VISRULES )
return ; //just don't add it.
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.
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 )
{
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 ;
}
2014-05-21 06:21:09 +00:00
if ( decreasingorder )
2005-05-13 10:42:48 +00:00
{
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 )
{
2016-07-12 00:40:13 +00:00
if ( server - > status & 2u )
2005-05-13 10:42:48 +00:00
{
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 )
2016-07-12 00:40:13 +00:00
server - > status & = ~ 2u ;
2005-05-13 10:42:48 +00:00
}
for ( server = firstserver ; server ; server = server - > next )
{
Master_ResortServer ( server ) ;
}
}
serverinfo_t * Master_SortedServer ( int idx )
{
if ( idx < 0 | | idx > = numvisibleservers )
return NULL ;
return visibleservers [ idx ] ;
}
int Master_NumSorted ( void )
{
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 :
2014-12-23 15:26:42 +00:00
return server - > special & SS_PROTOCOLMASK ;
case SLKEY_FLAGS :
return server - > special & ~ SS_PROTOCOLMASK ;
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 ;
2015-06-22 11:49:15 +00:00
case SLKEY_NUMSPECTATORS :
return server - > numspectators ;
2008-11-09 22:29:28 +00:00
case SLKEY_ISFAVORITE :
return ! ! ( server - > special & SS_FAVORITE ) ;
2014-12-23 15:26:42 +00:00
case SLKEY_ISLOCAL :
return ! ! ( server - > special & SS_LOCAL ) ;
case SLKEY_ISPROXY :
return ! ! ( server - > special & SS_PROXY ) ;
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 ;
}
2015-04-27 06:19:33 +00:00
void Master_DecodeColour ( vec3_t ret , int col )
{
if ( col < 16 )
{
col = Sbar_ColorForMap ( col ) ;
VectorSet ( ret , host_basepal [ col * 3 + 0 ] / 255.0 , host_basepal [ col * 3 + 1 ] / 255.0 , host_basepal [ col * 3 + 2 ] / 255.0 ) ;
}
else
VectorSet ( ret , ( ( col & 0xff0000 ) > > 16 ) / 255.0 , ( ( col & 0x00ff00 ) > > 8 ) / 255.0 , ( ( col & 0x0000ff ) > > 0 ) / 255.0 ) ;
}
2005-05-13 10:42:48 +00:00
char * Master_ReadKeyString ( serverinfo_t * server , int keynum )
{
2012-11-27 03:23:19 +00:00
static char adr [ MAX_ADR_SIZE ] ;
2008-06-08 14:37:57 +00:00
2013-12-29 22:48:28 +00:00
if ( ! server )
return " " ;
2015-04-27 06:19:33 +00:00
if ( keynum > = SLKEY_CUSTOM )
{
if ( server - > moreinfo )
{
keynum - = SLKEY_CUSTOM ;
if ( keynum < sizeof ( slist_keyname ) / sizeof ( slist_keyname [ 0 ] ) )
return Info_ValueForKey ( server - > moreinfo - > info , slist_keyname [ keynum ] ) ;
}
else if ( ! ( server - > special & SS_KEEPINFO ) )
{
server - > special | = SS_KEEPINFO ;
server - > sends + + ;
}
}
else if ( keynum > = SLKEY_PLAYER0 )
{
if ( server - > moreinfo )
{
keynum - = SLKEY_PLAYER0 ;
if ( keynum < server - > moreinfo - > numplayers )
{
vec3_t top , bot ;
Master_DecodeColour ( top , server - > moreinfo - > players [ keynum ] . topc ) ;
Master_DecodeColour ( bot , server - > moreinfo - > players [ keynum ] . botc ) ;
return va ( " %i %i %g %i \" %s \" \" %s \" '%g %g %g' '%g %g %g' " , server - > moreinfo - > players [ keynum ] . userid , server - > moreinfo - > players [ keynum ] . frags , server - > moreinfo - > players [ keynum ] . time , server - > moreinfo - > players [ keynum ] . ping , server - > moreinfo - > players [ keynum ] . name , server - > moreinfo - > players [ keynum ] . skin , top [ 0 ] , top [ 1 ] , top [ 2 ] , bot [ 0 ] , bot [ 1 ] , bot [ 2 ] ) ;
}
}
else if ( ! ( server - > special & SS_KEEPINFO ) )
{
server - > special | = SS_KEEPINFO ;
server - > sends + + ;
}
}
else
2005-05-13 10:42:48 +00:00
{
switch ( keynum )
{
case SLKEY_MAP :
return server - > map ;
case SLKEY_NAME :
return server - > name ;
case SLKEY_ADDRESS :
2013-05-03 04:28:08 +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 ;
2015-04-27 06:19:33 +00:00
case SLKEY_SERVERINFO :
return server - > moreinfo - > info ;
2008-11-09 22:29:28 +00:00
2005-05-13 10:42:48 +00:00
default :
{
static char s [ 64 ] ;
sprintf ( s , " %f " , Master_ReadKeyFloat ( server , keynum ) ) ;
return s ;
}
}
}
return " " ;
}
2014-03-30 08:55:06 +00:00
int Master_KeyForName ( const char * keyname )
2005-05-13 10:42:48 +00:00
{
int i ;
if ( ! strcmp ( keyname , " map " ) )
return SLKEY_MAP ;
else if ( ! strcmp ( keyname , " ping " ) )
return SLKEY_PING ;
2013-03-12 22:35:33 +00:00
else if ( ! strcmp ( keyname , " name " ) | | ! strcmp ( keyname , " hostname " ) )
2005-05-13 10:42:48 +00:00
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 ;
2014-12-23 15:26:42 +00:00
else if ( ! strcmp ( keyname , " basegame " ) )
2006-02-28 00:46:04 +00:00
return SLKEY_BASEGAME ;
2014-12-23 15:26:42 +00:00
else if ( ! strcmp ( keyname , " flags " ) )
return SLKEY_FLAGS ;
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 ;
2015-06-22 11:49:15 +00:00
else if ( ! strcmp ( keyname , " numspectators " ) )
return SLKEY_NUMSPECTATORS ;
2008-11-09 22:29:28 +00:00
else if ( ! strcmp ( keyname , " qcstatus " ) )
return SLKEY_QCSTATUS ;
else if ( ! strcmp ( keyname , " isfavorite " ) )
return SLKEY_ISFAVORITE ;
2014-12-23 15:26:42 +00:00
else if ( ! strcmp ( keyname , " islocal " ) )
return SLKEY_ISLOCAL ;
else if ( ! strcmp ( keyname , " isproxy " ) )
return SLKEY_ISPROXY ;
2015-04-27 06:19:33 +00:00
else if ( ! strcmp ( keyname , " serverinfo " ) )
return SLKEY_SERVERINFO ;
else if ( ! strncmp ( keyname , " player " , 6 ) )
return SLKEY_PLAYER0 + atoi ( keyname + 6 ) ;
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 ) ;
2011-05-15 13:23:13 +00:00
2005-05-13 10:42:48 +00:00
slist_customkeys + + ;
return slist_customkeys - 1 + SLKEY_CUSTOM ;
}
}
2015-07-07 02:03:31 +00:00
static void Master_FloodRoute ( serverinfo_t * node )
{
unsigned int i ;
struct peers_s * peer = node - > peers ;
for ( i = 0 ; i < node - > numpeers ; i + + , peer + + )
{
if ( peer - > ping )
if ( ( unsigned int ) ( peer - > peer - > cost ) > ( unsigned int ) ( node - > cost + peer - > ping ) )
{ //we found a shorter route. flood into it.
peer - > peer - > prevpeer = node ;
peer - > peer - > cost = node - > cost + peer - > ping ;
Master_FloodRoute ( peer - > peer ) ;
}
}
}
serverinfo_t * Master_FindRoute ( netadr_t target )
{
serverinfo_t * info , * targ , * prox ;
extern cvar_t cl_proxyaddr ;
targ = Master_InfoForServer ( & target ) ;
if ( ! targ ) //you wot?
return NULL ;
//never flood into a peer if its just going to be more expensive than a direct connection
if ( * cl_proxyaddr . string )
{
//fixme: we don't handle chained proxies properly, as we assume we can directly hop to the named final proxy.
//fixme: we'll find the same route, we just won't display the correct expected ping.
netadr_t pa ;
char * chain = strchr ( cl_proxyaddr . string , ' @ ' ) ;
if ( chain )
* chain = 0 ;
2016-02-15 06:01:17 +00:00
if ( NET_StringToAdr ( cl_proxyaddr . string , 0 , & pa ) )
prox = Master_InfoForServer ( & pa ) ;
else
prox = NULL ;
2015-07-07 02:03:31 +00:00
if ( chain )
* chain = ' @ ' ;
}
else
prox = NULL ;
if ( prox )
{
for ( info = firstserver ; info ; info = info - > next )
{
info - > cost = info - > ping ;
info - > prevpeer = prox ;
}
prox - > cost = prox - > ping ;
prox - > prevpeer = NULL ;
Master_FloodRoute ( prox ) ;
}
else
{
for ( info = firstserver ; info ; info = info - > next )
{
info - > cost = info - > ping ;
info - > prevpeer = NULL ;
}
//flood through all proxies
for ( info = firstserver ; info ; info = info - > next )
Master_FloodRoute ( info ) ;
}
if ( targ - > prevpeer )
return targ ;
return NULL ;
}
int Master_FindBestRoute ( char * server , char * out , size_t outsize , int * directcost , int * chainedcost )
{
serverinfo_t * route ;
netadr_t adr ;
int ret = 0 ;
char buf [ 256 ] ;
* out = 0 ;
* directcost = 0 ;
* chainedcost = 0 ;
if ( ! NET_StringToAdr ( server , 0 , & adr ) )
return - 1 ;
if ( ! firstserver )
{ //routing isn't initialised. you do actually need to refresh the serverbrowser for this junk
Q_strncpyz ( out , server , outsize ) ;
return - 1 ;
}
route = Master_FindRoute ( adr ) ;
if ( ! route )
{ //routing didn't find anything, just go directly.
Q_strncpyz ( out , server , outsize ) ;
return 0 ;
}
* directcost = route - > ping ;
* chainedcost = route - > cost ;
Q_strncatz ( out , NET_AdrToString ( buf , sizeof ( buf ) , & route - > adr ) , outsize ) ;
for ( ret = 0 , route = route - > prevpeer ; route ; route = route - > prevpeer , ret + + )
Q_strncatz ( out , va ( " @%s " , NET_AdrToString ( buf , sizeof ( buf ) , & route - > adr ) ) , outsize ) ;
return ret ;
}
2014-12-23 15:26:42 +00:00
//main thread
void CLMaster_AddMaster_Worker_Resolved ( void * ctx , void * data , size_t a , size_t b )
2004-08-23 00:15:46 +00:00
{
2014-12-23 15:26:42 +00:00
master_t * mast = data ;
master_t * oldmast ;
2004-08-23 00:15:46 +00:00
2014-12-23 15:26:42 +00:00
if ( mast - > adr . type = = NA_INVALID )
2004-08-23 00:15:46 +00:00
{
2014-12-23 15:26:42 +00:00
Con_Printf ( " Failed to resolve master address \" %s \" \n " , mast - > address ) ;
2004-08-23 00:15:46 +00:00
}
2014-12-23 15:26:42 +00:00
else if ( mast - > adr . type ! = NA_IP & & mast - > adr . type ! = NA_IPV6 & & mast - > adr . type ! = NA_IPX )
2008-11-09 22:29:28 +00:00
{
2014-12-23 15:26:42 +00:00
Con_Printf ( " Fixme: unable to poll address family for \" %s \" \n " , mast - > address ) ;
2008-11-09 22:29:28 +00:00
}
2014-12-23 15:26:42 +00:00
else
{
if ( mast - > mastertype = = MT_BCAST ) //broadcasts
{
if ( mast - > adr . type = = NA_IP )
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
memset ( mast - > adr . address . ip + 4 , 0xff , sizeof ( mast - > adr . address . ip ) ) ;
2014-12-23 15:26:42 +00:00
if ( mast - > adr . type = = NA_IPX )
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
{
memset ( mast - > adr . address . ipx + 0 , 0 , 4 ) ;
memset ( mast - > adr . address . ipx + 4 , 0xff , 6 ) ;
}
2014-12-23 15:26:42 +00:00
if ( mast - > adr . type = = NA_IPV6 )
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
{
memset ( mast - > adr . address . ip6 , 0 , sizeof ( mast - > adr . address . ip6 ) ) ;
mast - > adr . address . ip6 [ 0 ] = 0xff ;
mast - > adr . address . ip6 [ 1 ] = 0x02 ;
mast - > adr . address . ip6 [ 15 ] = 0x01 ;
}
2014-12-23 15:26:42 +00:00
}
//fix up default ports if not specified
if ( ! mast - > adr . port )
{
switch ( mast - > protocoltype )
{
case MP_DPMASTER : mast - > adr . port = BigShort ( 27950 ) ; break ;
case MP_QUAKE2 : mast - > adr . port = BigShort ( 27000 ) ; break ; //FIXME: verify
case MP_QUAKE3 : mast - > adr . port = BigShort ( 27950 ) ; break ;
case MP_QUAKEWORLD : mast - > adr . port = BigShort ( 27000 ) ; break ;
}
}
2008-11-09 22:29:28 +00:00
2014-12-23 15:26:42 +00:00
for ( oldmast = master ; oldmast ; oldmast = oldmast - > next )
{
if ( NET_CompareAdr ( & oldmast - > adr , & mast - > adr ) & & oldmast - > mastertype = = mast - > mastertype & & oldmast - > protocoltype = = mast - > protocoltype ) //already exists.
break ;
}
if ( ! oldmast )
{
mast - > next = master ;
master = mast ;
return ;
}
else if ( oldmast - > nosave & & ! mast - > nosave )
oldmast - > nosave = false ;
}
Z_Free ( mast ) ;
}
//worker thread
void CLMaster_AddMaster_Worker_Resolve ( void * ctx , void * data , size_t a , size_t b )
{
netadr_t adrs [ MAX_MASTER_ADDRESSES ] ;
char token [ 1024 ] ;
2015-06-16 23:53:58 +00:00
int found = 0 , j , i ;
// qboolean first = true;
2014-12-23 15:26:42 +00:00
char * str ;
master_t * work = data ;
//resolve all the addresses
str = work - > address ;
while ( str & & * str )
2004-08-23 00:15:46 +00:00
{
2014-12-23 15:26:42 +00:00
str = COM_ParseOut ( str , token , sizeof ( token ) ) ;
if ( * token )
found + = NET_StringToAdr2 ( token , 0 , & adrs [ found ] , MAX_MASTER_ADDRESSES - found ) ;
2015-06-16 23:53:58 +00:00
//we don't do this logic because windows doesn't look up ipv6 names if it only has teredo
//this means an ipv4+teredo client cannot see ivp6-only servers. and that sucks.
// if (first && found)
// break; //if we found one by name, don't try any fallback ip addresses.
// first = false;
2004-08-23 00:15:46 +00:00
}
2014-12-23 15:26:42 +00:00
//add the main ip address
work - > adr = adrs [ 0 ] ;
2016-02-15 06:01:17 +00:00
COM_AddWork ( WG_MAIN , CLMaster_AddMaster_Worker_Resolved , NULL , work , a , b ) ;
2014-12-23 15:26:42 +00:00
//add dupes too (eg: ipv4+ipv6)
2015-06-16 23:53:58 +00:00
for ( i = 1 ; i < found ; i + + )
2004-08-23 00:15:46 +00:00
{
2015-06-18 22:11:30 +00:00
// master_t *alt;
2015-06-17 13:05:20 +00:00
if ( adrs [ i ] . type = = NA_INVALID )
continue ;
2015-06-16 23:53:58 +00:00
//don't add the same ip twice, because that's silly
for ( j = 0 ; j < i ; j + + )
{
if ( NET_CompareAdr ( & adrs [ j ] , & adrs [ i ] ) )
break ;
}
if ( j = = i )
{ //not already added, hurrah
master_t * alt = Z_Malloc ( sizeof ( master_t ) + strlen ( work - > name ) + 1 + strlen ( work - > address ) + 1 ) ;
alt - > address = work - > name + strlen ( work - > name ) + 1 ;
alt - > mastertype = work - > mastertype ;
alt - > protocoltype = work - > protocoltype ;
strcpy ( alt - > name , work - > name ) ;
strcpy ( alt - > address , work - > address ) ;
alt - > sends = 1 ;
alt - > nosave = true ;
alt - > adr = adrs [ i ] ;
2016-02-15 06:01:17 +00:00
COM_AddWork ( WG_MAIN , CLMaster_AddMaster_Worker_Resolved , NULL , alt , a , b ) ;
2015-06-16 23:53:58 +00:00
}
2004-08-23 00:15:46 +00:00
}
2014-12-23 15:26:42 +00:00
}
void Master_AddMaster ( char * address , enum mastertype_e mastertype , enum masterprotocol_e protocol , char * description )
{
master_t * mast ;
if ( ! address | | ! * address )
return ;
if ( ! description )
description = address ;
2005-05-26 12:55:34 +00:00
mast = Z_Malloc ( sizeof ( master_t ) + strlen ( description ) + 1 + strlen ( address ) + 1 ) ;
mast - > address = mast - > name + strlen ( description ) + 1 ;
2013-10-29 17:38:22 +00:00
mast - > mastertype = mastertype ;
mast - > protocoltype = protocol ;
2004-08-23 00:15:46 +00:00
strcpy ( mast - > name , description ) ;
2005-05-26 12:55:34 +00:00
strcpy ( mast - > address , address ) ;
2014-12-23 15:26:42 +00:00
mast - > sends = 1 ;
2005-05-26 12:55:34 +00:00
2016-02-15 06:01:17 +00:00
COM_AddWork ( WG_LOADER , CLMaster_AddMaster_Worker_Resolve , NULL , mast , 0 , 0 ) ;
2005-05-26 12:55:34 +00:00
}
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
void MasterInfo_Shutdown ( void )
{
master_t * mast ;
2012-11-27 03:23:19 +00:00
serverinfo_t * sv ;
MasterInfo_RemoveAllPlayers ( ) ;
while ( firstserver )
{
sv = firstserver ;
firstserver = sv - > next ;
2015-07-07 02:03:31 +00:00
if ( sv - > peers )
Z_Free ( sv - > peers ) ;
2012-11-27 03:23:19 +00:00
Z_Free ( sv ) ;
}
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
while ( master )
{
mast = master ;
master = mast - > next ;
2012-11-27 06:06:25 +00:00
# ifdef WEBCLIENT
2012-11-27 03:23:19 +00:00
if ( mast - > dl )
DL_Close ( mast - > dl ) ;
2012-11-27 06:06:25 +00:00
# endif
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
Z_Free ( mast ) ;
}
2012-11-27 03:23:19 +00:00
maxvisibleservers = 0 ;
numvisibleservers = 0 ;
Z_Free ( visibleservers ) ;
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
}
2013-10-29 17:38:22 +00:00
void Master_AddMasterHTTP ( char * address , int mastertype , int protocoltype , char * description )
2005-05-26 12:55:34 +00:00
{
master_t * mast ;
2013-10-29 17:38:22 +00:00
/* int servertype;
if ( protocoltype = = MP_DP )
servertype = SS_DARKPLACES ;
else if ( protocoltype = = MP_Q2 )
servertype = SS_QUAKE2 ;
else if ( protocoltype = = MP_Q3 )
servertype = SS_QUAKE3 ;
else if ( protocoltype = = MP_NQ )
2006-02-26 09:37:55 +00:00
servertype = SS_NETQUAKE ;
2013-10-29 17:38:22 +00:00
else
servertype = 0 ;
*/
2005-05-26 12:55:34 +00:00
for ( mast = master ; mast ; mast = mast - > next )
{
2013-10-29 17:38:22 +00:00
if ( ! strcmp ( mast - > address , address ) & & mast - > mastertype = = mastertype & & mast - > protocoltype = = protocoltype ) //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 ;
2013-10-29 17:38:22 +00:00
mast - > mastertype = mastertype ;
mast - > protocoltype = protocoltype ;
// mast->servertype = servertype;
2005-05-26 12:55:34 +00:00
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.
2013-10-29 17:38:22 +00:00
qboolean Master_LoadMasterList ( char * filename , qboolean withcomment , int defaulttype , int defaultprotocol , int depth )
2004-08-23 00:15:46 +00:00
{
2005-12-21 03:07:33 +00:00
vfsfile_t * f ;
2004-08-23 00:15:46 +00:00
char line [ 1024 ] ;
2013-10-29 17:38:22 +00:00
char name [ 1024 ] ;
char entry [ 1024 ] ;
char * next , * sep ;
2004-08-23 00:15:46 +00:00
int servertype ;
2013-10-29 17:38:22 +00:00
int protocoltype ;
qboolean favourite ;
2004-08-23 00:15:46 +00:00
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 ;
2013-10-29 17:38:22 +00:00
* name = 0 ;
favourite = false ;
servertype = defaulttype ;
protocoltype = defaultprotocol ;
next = COM_ParseOut ( line , entry , sizeof ( entry ) ) ;
2004-08-23 00:15:46 +00:00
if ( ! * com_token )
continue ;
2013-10-29 17:38:22 +00:00
//special cases. Add a port if you have a server named 'file'... (unlikly)
if ( ! strcmp ( entry , " file " ) )
2004-08-23 00:15:46 +00:00
{
2013-10-29 17:38:22 +00:00
if ( withcomment )
next = COM_ParseOut ( next , name , sizeof ( name ) ) ;
next = COM_ParseOut ( next , entry , sizeof ( entry ) ) ;
2004-08-23 00:15:46 +00:00
if ( ! next )
continue ;
2013-10-29 17:38:22 +00:00
servertype = MT_BAD ;
2004-08-23 00:15:46 +00:00
}
2013-10-29 17:38:22 +00:00
else if ( ! strcmp ( entry , " master " ) )
{
if ( withcomment )
next = COM_ParseOut ( next , name , sizeof ( name ) ) ;
next = COM_ParseOut ( next , entry , sizeof ( entry ) ) ;
if ( ! next )
continue ;
servertype = MT_MASTERUDP ;
}
else if ( ! strcmp ( entry , " url " ) )
2004-08-23 00:15:46 +00:00
{
2013-10-29 17:38:22 +00:00
if ( withcomment )
next = COM_ParseOut ( next , name , sizeof ( name ) ) ;
next = COM_ParseOut ( next , entry , sizeof ( entry ) ) ;
servertype = MT_MASTERHTTP ;
2004-08-23 00:15:46 +00:00
}
2013-10-29 17:38:22 +00:00
next = COM_Parse ( next ) ;
2004-08-23 00:15:46 +00:00
2013-10-29 17:38:22 +00:00
for ( sep = com_token ; sep ; sep = next )
2004-08-23 00:15:46 +00:00
{
2013-10-29 17:38:22 +00:00
next = strchr ( sep , ' : ' ) ;
if ( next )
* next = 0 ;
if ( ! strcmp ( sep , " single " ) )
servertype = MT_SINGLE ;
else if ( ! strcmp ( sep , " master " ) )
servertype = MT_MASTERUDP ;
else if ( ! strcmp ( sep , " masterhttp " ) )
servertype = MT_MASTERHTTP ;
else if ( ! strcmp ( sep , " masterhttpjson " ) )
servertype = MT_MASTERHTTPJSON ;
else if ( ! strcmp ( sep , " bcast " ) )
servertype = MT_BCAST ;
else if ( ! strcmp ( com_token , " qw " ) )
2014-12-23 15:26:42 +00:00
protocoltype = MP_QUAKEWORLD ;
2013-10-29 17:38:22 +00:00
else if ( ! strcmp ( com_token , " q2 " ) )
2014-12-23 15:26:42 +00:00
protocoltype = MP_QUAKE2 ;
2013-10-29 17:38:22 +00:00
else if ( ! strcmp ( com_token , " q3 " ) )
2014-12-23 15:26:42 +00:00
protocoltype = MP_QUAKE3 ;
2013-10-29 17:38:22 +00:00
else if ( ! strcmp ( com_token , " nq " ) )
2014-12-23 15:26:42 +00:00
protocoltype = MP_NETQUAKE ;
2013-10-29 17:38:22 +00:00
else if ( ! strcmp ( com_token , " dp " ) )
2014-12-23 15:26:42 +00:00
protocoltype = MP_DPMASTER ;
2013-10-29 17:38:22 +00:00
//legacy compat
else if ( ! strcmp ( com_token , " httpjson " ) )
{
servertype = MT_MASTERHTTPJSON ;
2014-12-23 15:26:42 +00:00
protocoltype = MP_NETQUAKE ;
2013-10-29 17:38:22 +00:00
}
else if ( ! strcmp ( com_token , " httpnq " ) )
{
servertype = MT_MASTERHTTP ;
2014-12-23 15:26:42 +00:00
protocoltype = MP_NETQUAKE ;
2013-10-29 17:38:22 +00:00
}
else if ( ! strcmp ( com_token , " httpqw " ) )
{
servertype = MT_MASTERHTTP ;
2014-12-23 15:26:42 +00:00
protocoltype = MP_QUAKEWORLD ;
2013-10-29 17:38:22 +00:00
}
2004-08-23 00:15:46 +00:00
2013-10-29 17:38:22 +00:00
else if ( ! strcmp ( com_token , " favourite " ) | | ! strcmp ( com_token , " favorite " ) )
favourite = true ;
}
2004-08-23 00:15:46 +00:00
2014-12-02 02:00:41 +00:00
if ( ! * name & & next )
2004-08-23 00:15:46 +00:00
{
2013-10-29 17:38:22 +00:00
sep = name ;
while ( * next = = ' ' | | * next = = ' \t ' )
next + + ;
while ( * next & & sep < name + sizeof ( name ) - 1 )
* sep + + = * next + + ;
* sep = 0 ;
2004-08-23 00:15:46 +00:00
}
2013-10-29 17:38:22 +00:00
if ( servertype = = MT_BAD )
Master_LoadMasterList ( entry , false , servertype , protocoltype , depth ) ;
2004-08-23 00:15:46 +00:00
else
2006-02-26 09:37:55 +00:00
{
2013-10-29 17:38:22 +00:00
//favourites are added explicitly, with their name and stuff
if ( favourite & & servertype = = MT_SINGLE )
{
if ( NET_StringToAdr ( entry , 0 , & net_from ) )
CL_ReadServerInfo ( va ( " \\ hostname \\ %s " , name ) , - servertype , true ) ;
else
Con_Printf ( " Failed to resolve address - \" %s \" \n " , entry ) ;
}
2006-02-26 09:37:55 +00:00
switch ( servertype )
{
2011-12-23 03:12:29 +00:00
case MT_MASTERHTTPJSON :
2013-10-29 17:38:22 +00:00
case MT_MASTERHTTP :
Master_AddMasterHTTP ( entry , servertype , protocoltype , name ) ;
2006-02-26 09:37:55 +00:00
break ;
default :
2013-10-29 17:38:22 +00:00
Master_AddMaster ( entry , servertype , protocoltype , name ) ;
2011-12-23 03:12:29 +00:00
break ;
2006-02-26 09:37:55 +00:00
}
}
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 )
{
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
unsigned long bcast ;
2004-08-23 00:15:46 +00:00
int ret ;
struct sockaddr_qstorage addr ;
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 )
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
{
pollsocketsList [ FIRSTIPXSOCKET + lastpollsockIPX ] = IPX_OpenSocket ( PORT_ANY ) ;
pollsocketsBCast [ FIRSTIPXSOCKET + lastpollsockIPX ] = false ;
}
2009-04-01 22:03:56 +00:00
if ( pollsocketsList [ FIRSTIPXSOCKET + lastpollsockIPX ] = = INVALID_SOCKET )
return ; //bother
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
bcast = ! memcmp ( to . address . ipx , " \0 \0 \0 \0 \xff \xff \xff \xff \xff \xff " , sizeof ( to . address . ipx ) ) ;
if ( pollsocketsBCast [ FIRSTIPXSOCKET + lastpollsockIPX ] ! = bcast )
{
if ( setsockopt ( pollsocketsList [ FIRSTIPXSOCKET + lastpollsockIPX ] , SOL_SOCKET , SO_BROADCAST , ( char * ) & bcast , sizeof ( bcast ) ) = = - 1 )
return ;
pollsocketsBCast [ FIRSTIPXSOCKET + lastpollsockIPX ] = bcast ;
}
2009-04-01 22:03:56 +00:00
ret = sendto ( pollsocketsList [ FIRSTIPXSOCKET + lastpollsockIPX ] , data , len , 0 , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
}
else
# endif
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
# ifdef HAVE_IPV6
2009-04-01 22:03:56 +00:00
if ( ( ( struct sockaddr * ) & addr ) - > sa_family = = AF_INET6 )
{
lastpollsockUDP6 + + ;
if ( lastpollsockUDP6 > = POLLUDP6SOCKETS )
lastpollsockUDP6 = 0 ;
if ( pollsocketsList [ FIRSTUDP6SOCKET + lastpollsockUDP6 ] = = INVALID_SOCKET )
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
{
pollsocketsList [ FIRSTUDP6SOCKET + lastpollsockUDP6 ] = UDP6_OpenSocket ( PORT_ANY ) ;
pollsocketsBCast [ FIRSTUDP6SOCKET + lastpollsockUDP6 ] = false ;
}
2009-04-01 22:03:56 +00:00
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
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
# ifdef HAVE_IPV4
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 )
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
{
pollsocketsList [ FIRSTUDP4SOCKET + lastpollsockUDP4 ] = UDP_OpenSocket ( PORT_ANY ) ;
pollsocketsBCast [ FIRSTUDP4SOCKET + lastpollsockUDP4 ] = false ;
}
2009-04-01 22:03:56 +00:00
if ( pollsocketsList [ FIRSTUDP4SOCKET + lastpollsockUDP4 ] = = INVALID_SOCKET )
2005-03-18 06:14:07 +00:00
return ; //bother
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
bcast = ! memcmp ( to . address . ip , " \xff \xff \xff \xff " , sizeof ( to . address . ip ) ) ;
if ( pollsocketsBCast [ FIRSTUDP4SOCKET + lastpollsockUDP4 ] ! = bcast )
{
if ( setsockopt ( pollsocketsList [ FIRSTUDP4SOCKET + lastpollsockUDP4 ] , SOL_SOCKET , SO_BROADCAST , ( char * ) & bcast , sizeof ( bcast ) ) = = - 1 )
return ;
pollsocketsBCast [ FIRSTUDP4SOCKET + lastpollsockUDP4 ] = bcast ;
}
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
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
# endif
2008-11-09 22:29:28 +00:00
return ;
2004-08-23 00:15:46 +00:00
if ( ret = = - 1 )
{
2014-02-07 08:38:40 +00:00
int er = neterrno ( ) ;
2004-08-23 00:15:46 +00:00
// wouldblock is silent
2014-02-07 08:38:40 +00:00
if ( er = = NET_EWOULDBLOCK )
2004-08-23 00:15:46 +00:00
return ;
2014-02-07 08:38:40 +00:00
if ( er = = NET_ECONNREFUSED )
2004-08-23 00:15:46 +00:00
return ;
2014-02-07 08:38:40 +00:00
if ( er = = NET_EADDRNOTAVAIL )
Con_DPrintf ( " NET_SendPollPacket Warning: %i \n " , er ) ;
2004-08-23 00:15:46 +00:00
else
2014-02-07 08:38:40 +00:00
Con_Printf ( " NET_SendPollPacket ERROR: %i \n " , er ) ;
2004-08-23 00:15:46 +00:00
}
}
2012-04-09 19:12:12 +00:00
int Master_CheckPollSockets ( void )
2004-08-23 00:15:46 +00:00
{
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 )
{
2014-02-07 08:38:40 +00:00
int e = neterrno ( ) ;
if ( e = = NET_EWOULDBLOCK )
2004-08-23 00:15:46 +00:00
continue ;
2014-02-07 08:38:40 +00:00
if ( e = = NET_EMSGSIZE )
2004-08-23 00:15:46 +00:00
{
SockadrToNetadr ( & from , & net_from ) ;
Con_Printf ( " Warning: Oversize packet from %s \n " ,
2013-05-03 04:28:08 +00:00
NET_AdrToString ( adr , sizeof ( adr ) , & net_from ) ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
2014-02-07 08:38:40 +00:00
if ( e = = NET_ECONNABORTED | | e = = NET_ECONNRESET )
2004-08-23 00:15:46 +00:00
{
// Con_Printf ("Connection lost or aborted\n");
continue ;
}
2014-02-07 08:38:40 +00:00
Con_Printf ( " NET_CheckPollSockets: %i, %s \n " , e , strerror ( e ) ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
SockadrToNetadr ( & from , & net_from ) ;
net_message . cursize = ret ;
if ( ret = = sizeof ( net_message_buffer ) )
{
2013-05-03 04:28:08 +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 " ) )
{
2014-12-23 15:26:42 +00:00
CL_ReadServerInfo ( MSG_ReadString ( ) , MP_QUAKE2 , false ) ;
2004-08-23 00:15:46 +00:00
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
{
2014-12-23 15:26:42 +00:00
CL_ReadServerInfo ( MSG_ReadString ( ) , MP_QUAKE2 , false ) ;
2004-08-23 00:15:46 +00:00
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
{
2014-12-23 15:26:42 +00:00
CL_ReadServerInfo ( MSG_ReadString ( ) , MP_QUAKE3 , false ) ;
2005-08-26 22:56:51 +00:00
continue ;
}
# endif
2009-04-01 22:03:56 +00:00
# ifdef IPPROTO_IPV6
2014-12-23 15:26:42 +00:00
if ( ! strncmp ( s , " getserversResponse6 " , 19 ) & & ( s [ 19 ] = = ' \\ ' | | s [ 19 ] = = ' / ' ) ) //parse a bit more...
2009-04-01 22:03:56 +00:00
{
msg_readcount = c + 19 - 1 ;
CL_MasterListParse ( NA_IPV6 , SS_DARKPLACES , true ) ;
continue ;
}
# endif
2014-12-23 15:26:42 +00:00
if ( ! strncmp ( s , " getserversExtResponse " , 21 ) & & ( s [ 21 ] = = ' \\ ' | | s [ 21 ] = = ' / ' ) ) //parse a bit more...
{
msg_readcount = c + 21 - 1 ;
CL_MasterListParse ( NA_IP , SS_DARKPLACES , true ) ;
continue ;
}
if ( ! strncmp ( s , " getserversResponse " , 18 ) & & ( s [ 18 ] = = ' \\ ' | | s [ 18 ] = = ' / ' ) ) //parse a bit more...
2005-08-26 22:56:51 +00:00
{
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
{
2014-12-23 15:26:42 +00:00
CL_ReadServerInfo ( MSG_ReadString ( ) , MP_DPMASTER , 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 ;
2014-12-23 15:26:42 +00:00
CL_MasterListParse ( NA_IPV6 , SS_QUAKEWORLD , false ) ;
2009-04-01 22:03:56 +00:00
continue ;
}
# endif
2004-08-23 00:15:46 +00:00
msg_readcount = c ;
c = MSG_ReadByte ( ) ;
if ( c = = A2C_PRINT ) //qw server reply.
{
2014-12-23 15:26:42 +00:00
CL_ReadServerInfo ( MSG_ReadString ( ) , MP_QUAKEWORLD , false ) ;
2004-08-23 00:15:46 +00:00
continue ;
}
if ( c = = M2C_MASTER_REPLY ) //qw master reply.
2011-05-15 13:23:13 +00:00
{
2014-12-23 15:26:42 +00:00
CL_MasterListParse ( NA_IP , SS_QUAKEWORLD , 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 ;
2016-09-08 19:04:35 +00:00
int ccrep ;
2004-08-23 00:15:46 +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
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 ;
2016-09-08 19:04:35 +00:00
ccrep = MSG_ReadByte ( ) ;
2004-08-23 00:15:46 +00:00
2016-09-08 19:04:35 +00:00
if ( ccrep = = CCREP_PLAYER_INFO )
2004-08-23 00:15:46 +00:00
{
2016-09-08 19:04:35 +00:00
serverinfo_t * selserver = selectedserver . inuse ? Master_InfoForServer ( & selectedserver . adr ) : NULL ;
serverinfo_t * info = Master_InfoForServer ( & net_from ) ;
info = Master_InfoForServer ( & net_from ) ;
if ( selserver = = info )
{
2017-02-11 16:14:06 +00:00
char playeraddrbuf [ 256 ] ;
2016-09-08 19:04:35 +00:00
int playernum = MSG_ReadByte ( ) ;
char * playername = MSG_ReadString ( ) ;
int playercolor = MSG_ReadLong ( ) ;
int playerfrags = MSG_ReadLong ( ) ;
int secsonserver = MSG_ReadLong ( ) ;
2017-02-11 16:14:06 +00:00
char * playeraddr = MSG_ReadStringBuffer ( playeraddrbuf , sizeof ( playeraddrbuf ) ) ;
2016-09-08 19:04:35 +00:00
if ( msg_badread )
continue ;
2017-02-11 16:14:06 +00:00
//might as well
IPLog_Add ( playeraddr , playername ) ;
2016-09-08 19:04:35 +00:00
selectedserver . lastplayer = playernum + 1 ;
memset ( & info - > moreinfo - > players [ playernum ] , 0 , sizeof ( info - > moreinfo - > players [ playernum ] ) ) ;
info - > moreinfo - > players [ playernum ] . userid = 0 ;
info - > moreinfo - > players [ playernum ] . frags = playerfrags ;
info - > moreinfo - > players [ playernum ] . time = secsonserver ;
info - > moreinfo - > players [ playernum ] . ping = 0 ; //*sigh*
Q_strncpyz ( info - > moreinfo - > players [ playernum ] . name , playername , sizeof ( info - > moreinfo - > players [ playernum ] . name ) ) ;
Q_strncpyz ( info - > moreinfo - > players [ playernum ] . skin , " " , sizeof ( info - > moreinfo - > players [ playernum ] . skin ) ) ;
Q_strncpyz ( info - > moreinfo - > players [ playernum ] . team , " " , sizeof ( info - > moreinfo - > players [ playernum ] . team ) ) ;
info - > moreinfo - > players [ playernum ] . topc = playercolor > > 4 ;
info - > moreinfo - > players [ playernum ] . botc = playercolor & 15 ;
info - > moreinfo - > players [ playernum ] . isspec = false ;
info - > moreinfo - > numplayers = max ( info - > moreinfo - > numplayers , playernum + 1 ) ;
//... and now try to query the next one... because everyone gives up after the first, right?... dude... I hate this shit.
SZ_Clear ( & net_message ) ;
MSG_WriteLong ( & net_message , 0 ) ; // save space for the header, filled in later
MSG_WriteByte ( & net_message , CCREQ_PLAYER_INFO ) ;
MSG_WriteByte ( & net_message , selectedserver . lastplayer ) ;
* ( ( int * ) net_message . data ) = BigLong ( NETFLAG_CTL | ( net_message . cursize & NETFLAG_LENGTH_MASK ) ) ;
NET_SendPollPacket ( net_message . cursize , net_message . data , info - > adr ) ;
SZ_Clear ( & net_message ) ;
}
}
else if ( ccrep = = CCREP_RULE_INFO )
{
serverinfo_t * selserver = selectedserver . inuse ? Master_InfoForServer ( & selectedserver . adr ) : NULL ;
serverinfo_t * info = Master_InfoForServer ( & net_from ) ;
char * s , * old ;
info = Master_InfoForServer ( & net_from ) ;
if ( selserver = = info )
{
s = MSG_ReadString ( ) ;
if ( msg_badread )
continue ;
Q_strncpyz ( selectedserver . lastrule , s , sizeof ( selectedserver . lastrule ) ) ;
s = MSG_ReadString ( ) ;
old = Info_ValueForKey ( info - > moreinfo - > info , selectedserver . lastrule ) ;
2017-01-13 00:39:50 +00:00
if ( strcmp ( s , old ) & & ! strchr ( s , ' \" ' ) & & ! strchr ( s , ' \\ ' ) )
2016-09-08 19:04:35 +00:00
Info_SetValueForStarKey ( info - > moreinfo - > info , selectedserver . lastrule , s , sizeof ( info - > moreinfo - > info ) ) ;
//... and now try to query the next one... because everyone gives up after the first, right?... dude... I hate this shit.
SZ_Clear ( & net_message ) ;
MSG_WriteLong ( & net_message , 0 ) ; // save space for the header, filled in later
MSG_WriteByte ( & net_message , CCREQ_RULE_INFO ) ;
MSG_WriteString ( & net_message , selectedserver . lastrule ) ;
* ( ( int * ) net_message . data ) = BigLong ( NETFLAG_CTL | ( net_message . cursize & NETFLAG_LENGTH_MASK ) ) ;
NET_SendPollPacket ( net_message . cursize , net_message . data , info - > adr ) ;
SZ_Clear ( & net_message ) ;
}
2004-08-23 00:15:46 +00:00
}
2016-09-08 19:04:35 +00:00
else if ( ccrep = = CCREP_SERVER_INFO )
{
/*this is an address string sent from the server. its not usable. if its replying to serverinfos, its possible to send it connect requests, while the address that it claims is 50% bugged*/
MSG_ReadString ( ) ;
Q_strncpyz ( name , MSG_ReadString ( ) , sizeof ( name ) ) ;
Q_strncpyz ( map , MSG_ReadString ( ) , sizeof ( map ) ) ;
users = MSG_ReadByte ( ) ;
maxusers = MSG_ReadByte ( ) ;
if ( MSG_ReadByte ( ) ! = NQ_NETCHAN_VERSION )
{
// Q_strcpy(name, "*");
// Q_strcat(name, name);
}
2004-08-23 00:15:46 +00:00
2016-09-08 19:04:35 +00:00
CL_ReadServerInfo ( va ( " \\ hostname \\ %s \\ map \\ %s \\ maxclients \\ %i \\ clients \\ %i " , name , map , maxusers , users ) , MP_NETQUAKE , false ) ;
}
2004-08-23 00:15:46 +00:00
}
# endif
2011-05-15 13:23:13 +00:00
continue ;
2004-08-23 00:15:46 +00:00
}
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 )
{
2013-05-03 04:28:08 +00:00
if ( NET_CompareAdr ( & selectedserver . adr , & oldserver - > adr ) ) //*(int*)selectedserver.ipaddress == *(int*)server->ipaddress && selectedserver.port == server->port)
2004-08-23 00:15:46 +00:00
{
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 ) ) ;
2011-05-15 13:23:13 +00:00
2004-08-23 00:15:46 +00:00
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
2015-06-28 03:43:10 +00:00
selectedserver . refreshtime = realtime + 4 ;
2005-05-17 02:36:54 +00:00
newserver - > sends + + ;
Master_QueryServer ( newserver ) ;
2016-09-08 19:04:35 +00:00
# ifdef NQPROT
selectedserver . lastplayer = 0 ;
* selectedserver . lastrule = 0 ;
if ( ( newserver - > special & SS_PROTOCOLMASK ) = = SS_NETQUAKE )
{ //start spamming the server to get all of its details. silly protocols.
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_PLAYER_INFO ) ;
MSG_WriteByte ( & net_message , selectedserver . lastplayer ) ;
* ( ( int * ) net_message . data ) = BigLong ( NETFLAG_CTL | ( net_message . cursize & NETFLAG_LENGTH_MASK ) ) ;
NET_SendPollPacket ( net_message . cursize , net_message . data , newserver - > adr ) ;
SZ_Clear ( & net_message ) ;
MSG_WriteLong ( & net_message , 0 ) ; // save space for the header, filled in later
MSG_WriteByte ( & net_message , CCREQ_RULE_INFO ) ;
MSG_WriteString ( & net_message , selectedserver . lastrule ) ;
* ( ( int * ) net_message . data ) = BigLong ( NETFLAG_CTL | ( net_message . cursize & NETFLAG_LENGTH_MASK ) ) ;
NET_SendPollPacket ( net_message . cursize , net_message . data , newserver - > adr ) ;
SZ_Clear ( & net_message ) ;
}
# endif
2004-08-23 00:15:46 +00:00
}
}
2005-05-26 12:55:34 +00:00
# ifdef WEBCLIENT
2013-10-29 17:38:22 +00:00
void MasterInfo_ProcessHTTP ( struct dl_download * dl )
2005-05-26 12:55:34 +00:00
{
2013-10-29 17:38:22 +00:00
master_t * mast = dl - > user_ctx ;
vfsfile_t * file = dl - > file ;
int protocoltype = mast - > protocoltype ;
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 ] ;
2013-10-29 17:38:22 +00:00
mast - > dl = NULL ;
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 ;
2013-03-12 22:53:23 +00:00
if ( ! NET_StringToAdr ( s , 80 , & adr ) )
2005-05-26 12:55:34 +00:00
continue ;
2013-05-03 04:28:08 +00:00
if ( ( info = Master_InfoForServer ( & adr ) ) ) //remove if the server already exists.
2005-05-26 12:55:34 +00:00
{
info - > sends = 1 ; //reset.
}
else
{
info = Z_Malloc ( sizeof ( serverinfo_t ) ) ;
info - > adr = adr ;
info - > sends = 1 ;
2013-10-29 17:38:22 +00:00
2014-12-23 15:26:42 +00:00
info - > special = 0 ;
if ( protocoltype = = MP_DPMASTER )
info - > special | = SS_DARKPLACES ;
else if ( protocoltype = = MP_QUAKE2 )
info - > special | = SS_QUAKE2 ;
else if ( protocoltype = = MP_QUAKE3 )
info - > special | = SS_QUAKE3 ;
else if ( protocoltype = = MP_NETQUAKE )
info - > special | = SS_NETQUAKE ;
2013-10-29 17:38:22 +00:00
2005-05-26 12:55:34 +00:00
info - > refreshtime = 0 ;
2011-12-23 03:12:29 +00:00
info - > ping = 0xffff ;
2005-05-26 12:55:34 +00:00
2013-05-03 04:28:08 +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
2011-12-23 03:12:29 +00:00
char * jsonnode ( int level , char * node )
{
netadr_t adr = { NA_INVALID } ;
char servername [ 256 ] = { 0 } ;
char key [ 256 ] ;
2014-12-23 15:26:42 +00:00
int flags = SS_NETQUAKE ; //assumption
2011-12-23 03:12:29 +00:00
int port = 0 ;
int cp = 0 , mp = 0 ;
if ( * node ! = ' { ' )
return node ;
do
{
node + + ;
node = COM_ParseToken ( node , " ,:{}[] " ) ;
if ( * node ! = ' : ' )
continue ;
node + + ;
if ( * node = = ' [ ' )
{
do
{
node + + ;
node = jsonnode ( level + 1 , node ) ;
if ( ! node )
return NULL ;
if ( * node = = ' ] ' )
{
break ;
}
} while ( * node = = ' , ' ) ;
if ( * node ! = ' ] ' )
return NULL ;
node + + ;
}
else
{
Q_strncpyz ( key , com_token , sizeof ( key ) ) ;
node = COM_ParseToken ( node , " ,:{}[] " ) ;
if ( level = = 1 )
{
if ( ! strcmp ( key , " IPAddress " ) )
2016-02-15 06:01:17 +00:00
{
if ( ! NET_StringToAdr ( com_token , 0 , & adr ) )
adr . type = NA_INVALID ;
}
2011-12-23 03:12:29 +00:00
if ( ! strcmp ( key , " Port " ) )
port = atoi ( com_token ) ;
if ( ! strcmp ( key , " DNS " ) )
Q_strncpyz ( servername , com_token , sizeof ( servername ) ) ;
if ( ! strcmp ( key , " CurrentPlayerCount " ) )
cp = atoi ( com_token ) ;
if ( ! strcmp ( key , " MaxPlayers " ) )
mp = atoi ( com_token ) ;
if ( ! strcmp ( key , " Game " ) )
{
2014-12-23 15:26:42 +00:00
flags & = ~ SS_PROTOCOLMASK ;
2011-12-23 03:12:29 +00:00
if ( ! strcmp ( com_token , " NetQuake " ) )
flags | = SS_NETQUAKE ;
2014-12-23 15:26:42 +00:00
if ( ! strcmp ( com_token , " QuakeWorld " ) )
flags | = SS_QUAKEWORLD ;
2011-12-23 03:12:29 +00:00
if ( ! strcmp ( com_token , " Quake2 " ) )
flags | = SS_QUAKE2 ;
if ( ! strcmp ( com_token , " Quake3 " ) )
flags | = SS_QUAKE3 ;
}
}
}
} while ( * node = = ' , ' ) ;
if ( * node = = ' } ' )
node + + ;
if ( adr . type ! = NA_INVALID )
{
serverinfo_t * info ;
if ( port )
adr . port = htons ( port ) ;
2013-05-03 04:28:08 +00:00
if ( ( info = Master_InfoForServer ( & adr ) ) ) //remove if the server already exists.
2011-12-23 03:12:29 +00:00
{
2014-12-23 15:26:42 +00:00
if ( ! info - > special )
info - > special = flags ;
2011-12-23 03:12:29 +00:00
info - > sends = 1 ; //reset.
}
else
{
info = Z_Malloc ( sizeof ( serverinfo_t ) ) ;
info - > adr = adr ;
info - > sends = 1 ;
info - > special = flags ;
info - > refreshtime = 0 ;
info - > players = cp ;
info - > maxplayers = mp ;
2013-05-03 04:28:08 +00:00
snprintf ( info - > name , sizeof ( info - > name ) , " %s " , * servername ? servername : NET_AdrToString ( servername , sizeof ( servername ) , & info - > adr ) ) ;
2011-12-23 03:12:29 +00:00
info - > next = firstserver ;
firstserver = info ;
Master_ResortServer ( info ) ;
}
}
return node ;
}
void MasterInfo_ProcessHTTPJSON ( struct dl_download * dl )
{
int len ;
char * buf ;
2012-11-27 03:23:19 +00:00
master_t * mast = dl - > user_ctx ;
mast - > dl = NULL ;
2011-12-26 15:19:13 +00:00
if ( dl - > file )
{
len = VFS_GETLEN ( dl - > file ) ;
buf = malloc ( len + 1 ) ;
VFS_READ ( dl - > file , buf , len ) ;
buf [ len ] = 0 ;
jsonnode ( 0 , buf ) ;
free ( buf ) ;
}
else
{
Con_Printf ( " Unable to query master at \" %s \" \n " , dl - > url ) ;
}
2011-12-23 03:12:29 +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
2013-10-29 17:38:22 +00:00
void MasterInfo_Request ( master_t * mast )
2004-08-23 00:15:46 +00:00
{
2011-05-15 13:23:13 +00:00
//static int mastersequence; // warning: unused variable <20> mastersequence<63>
2004-08-23 00:15:46 +00:00
if ( ! mast )
return ;
2011-06-16 02:03:57 +00:00
if ( mast - > sends )
mast - > sends - - ;
2013-10-29 17:38:22 +00:00
//these are generic requests
switch ( mast - > mastertype )
2004-08-23 00:15:46 +00:00
{
2005-05-26 12:55:34 +00:00
# ifdef WEBCLIENT
2011-12-23 03:12:29 +00:00
case MT_MASTERHTTPJSON :
2012-11-27 03:23:19 +00:00
if ( ! mast - > dl )
{
mast - > dl = HTTP_CL_Get ( mast - > address , NULL , MasterInfo_ProcessHTTPJSON ) ;
if ( mast - > dl )
2015-04-21 04:12:00 +00:00
{
2012-11-27 03:23:19 +00:00
mast - > dl - > user_ctx = mast ;
2015-04-21 04:12:00 +00:00
mast - > dl - > isquery = true ;
}
2012-11-27 03:23:19 +00:00
}
2011-12-23 03:12:29 +00:00
break ;
2013-10-29 17:38:22 +00:00
case MT_MASTERHTTP :
2012-11-27 03:23:19 +00:00
if ( ! mast - > dl )
{
2013-10-29 17:38:22 +00:00
mast - > dl = HTTP_CL_Get ( mast - > address , NULL , MasterInfo_ProcessHTTP ) ;
2012-11-27 03:23:19 +00:00
if ( mast - > dl )
2015-04-21 04:12:00 +00:00
{
2012-11-27 03:23:19 +00:00
mast - > dl - > user_ctx = mast ;
2015-04-21 04:12:00 +00:00
mast - > dl - > isquery = true ;
}
2012-11-27 03:23:19 +00:00
}
2006-02-26 09:37:55 +00:00
break ;
2013-10-29 17:38:22 +00:00
# endif
case MT_MASTERUDP :
switch ( mast - > protocoltype )
2012-11-27 03:23:19 +00:00
{
2013-10-29 17:38:22 +00:00
# ifdef Q3CLIENT
2014-12-23 15:26:42 +00:00
case MP_QUAKE3 :
2013-10-29 17:38:22 +00:00
{
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
# ifdef Q2CLIENT
2014-12-23 15:26:42 +00:00
case MP_QUAKE2 :
2013-10-29 17:38:22 +00:00
NET_SendPollPacket ( 6 , " query " , mast - > adr ) ;
break ;
# endif
2014-12-23 15:26:42 +00:00
case MP_QUAKEWORLD :
2013-10-29 17:38:22 +00:00
NET_SendPollPacket ( 3 , " c \n " , mast - > adr ) ;
break ;
# ifdef NQPROT
2014-12-23 15:26:42 +00:00
case MP_NETQUAKE :
2013-10-29 17:38:22 +00:00
//there is no nq udp master protocol
break ;
2014-12-23 15:26:42 +00:00
case MP_DPMASTER :
2013-10-29 17:38:22 +00:00
{
char * str ;
2017-01-13 00:39:50 +00:00
char game [ MAX_QPATH ] ;
char * games = com_protocolname . string ;
while ( * games )
{ //send a request for each game listed.
games = COM_ParseOut ( games , game , sizeof ( game ) ) ;
//for compat with dp, we use the nq netchan version. which is stupid, but whatever
//we ask for ipv6 addresses from ipv6 masters (assuming it resolved okay)
if ( mast - > adr . type = = NA_IPV6 )
str = va ( " %c%c%c%cgetserversExt %s %u empty full ipv6 " /*\x0A\n"*/ , 255 , 255 , 255 , 255 , game , NQ_NETCHAN_VERSION ) ;
else
str = va ( " %c%c%c%cgetservers %s %u empty full " /*\x0A\n"*/ , 255 , 255 , 255 , 255 , game , NQ_NETCHAN_VERSION ) ;
NET_SendPollPacket ( strlen ( str ) , str , mast - > adr ) ;
}
2013-10-29 17:38:22 +00:00
}
break ;
# endif
2012-11-27 03:23:19 +00:00
}
2005-05-26 12:55:34 +00:00
break ;
2013-10-29 17:38:22 +00:00
case MT_BCAST :
case MT_SINGLE : //FIXME: properly add the server and flag it for resending instead of directly pinging it
switch ( mast - > protocoltype )
{
# ifdef Q3CLIENT
2014-12-23 15:26:42 +00:00
case MP_QUAKE3 :
2013-10-29 17:38:22 +00:00
NET_SendPollPacket ( 14 , va ( " %c%c%c%cgetstatus \n " , 255 , 255 , 255 , 255 ) , mast - > adr ) ;
break ;
# endif
# ifdef Q2CLIENT
2014-12-23 15:26:42 +00:00
case MP_QUAKE2 :
2015-06-18 22:11:30 +00:00
NET_SendPollPacket ( 11 , va ( " %c%c%c%cstatus \n " , 255 , 255 , 255 , 255 ) , mast - > adr ) ;
break ;
2013-10-29 17:38:22 +00:00
# endif
2014-12-23 15:26:42 +00:00
case MP_QUAKEWORLD :
2015-06-19 16:56:50 +00:00
NET_SendPollPacket ( 14 , va ( " %c%c%c%cstatus 23 \n " , 255 , 255 , 255 , 255 ) , mast - > adr ) ;
2013-10-29 17:38:22 +00:00
break ;
# ifdef NQPROT
2014-12-23 15:26:42 +00:00
case MP_NETQUAKE :
2013-10-29 17:38:22 +00:00
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
2014-12-23 15:26:42 +00:00
MSG_WriteByte ( & net_message , NQ_NETCHAN_VERSION ) ;
2013-10-29 17:38:22 +00:00
* ( ( 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 ;
2014-12-23 15:26:42 +00:00
case MP_DPMASTER : //fixme
2013-10-29 17:38:22 +00:00
{
char * str ;
str = va ( " %c%c%c%cgetinfo " , 255 , 255 , 255 , 255 ) ;
NET_SendPollPacket ( strlen ( str ) , str , mast - > adr ) ;
}
break ;
2006-02-26 09:37:55 +00:00
# endif
2013-10-29 17:38:22 +00:00
}
break ;
2004-08-23 00:15:46 +00:00
}
}
void MasterInfo_WriteServers ( void )
{
2013-10-29 17:38:22 +00:00
char * typename , * protoname ;
2004-08-23 00:15:46 +00:00
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 ] ;
2011-05-15 13:23:13 +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 )
{
2016-08-25 00:12:14 +00:00
Con_Printf ( CON_ERROR " Couldn't write masters.txt " ) ;
2004-08-23 00:15:46 +00:00
return ;
}
2011-05-15 13:23:13 +00:00
2004-08-23 00:15:46 +00:00
for ( mast = master ; mast ; mast = mast - > next )
{
2014-12-23 15:26:42 +00:00
if ( mast - > nosave )
continue ;
2013-10-29 17:38:22 +00:00
switch ( mast - > mastertype )
2004-08-23 00:15:46 +00:00
{
2013-10-29 17:38:22 +00:00
case MT_MASTERUDP :
typename = " master " ;
2005-09-28 23:37:15 +00:00
break ;
2013-10-29 17:38:22 +00:00
case MT_MASTERHTTP :
typename = " masterhttp " ;
2006-02-26 09:37:55 +00:00
break ;
2013-10-29 17:38:22 +00:00
case MT_MASTERHTTPJSON :
typename = " masterjson " ;
2004-08-23 00:15:46 +00:00
break ;
2013-10-29 17:38:22 +00:00
case MT_BCAST :
typename = " bcast " ;
2004-08-23 00:15:46 +00:00
break ;
2013-10-29 17:38:22 +00:00
case MT_SINGLE :
typename = " single " ;
2005-08-26 22:56:51 +00:00
break ;
2013-10-29 17:38:22 +00:00
default :
typename = " ?? " ;
2004-08-23 00:15:46 +00:00
break ;
2013-10-29 17:38:22 +00:00
}
switch ( mast - > protocoltype )
{
2014-12-23 15:26:42 +00:00
case MP_QUAKEWORLD :
2013-10-29 17:38:22 +00:00
protoname = " :qw " ;
2004-08-23 00:15:46 +00:00
break ;
2014-12-23 15:26:42 +00:00
case MP_QUAKE2 :
2013-10-29 17:38:22 +00:00
protoname = " :q2 " ;
2004-08-23 00:15:46 +00:00
break ;
2014-12-23 15:26:42 +00:00
case MP_QUAKE3 :
2013-10-29 17:38:22 +00:00
protoname = " :q3 " ;
2005-08-26 22:56:51 +00:00
break ;
2014-12-23 15:26:42 +00:00
case MP_NETQUAKE :
2013-10-29 17:38:22 +00:00
protoname = " :nq " ;
2004-08-23 00:15:46 +00:00
break ;
2014-12-23 15:26:42 +00:00
case MP_DPMASTER :
2013-10-29 17:38:22 +00:00
protoname = " :dp " ;
2005-09-28 23:37:15 +00:00
break ;
2004-08-23 00:15:46 +00:00
default :
2013-10-29 17:38:22 +00:00
case MP_UNSPECIFIED :
protoname = " " ;
break ;
2004-08-23 00:15:46 +00:00
}
2005-09-28 23:37:15 +00:00
if ( mast - > address )
2014-02-13 23:54:57 +00:00
VFS_PUTS ( mf , va ( " %s \t %s%s \t %s \n " , mast - > address , typename , protoname , mast - > name ) ) ;
2005-09-28 23:37:15 +00:00
else
2013-05-03 04:28:08 +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
}
2011-05-15 13:23:13 +00:00
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 " ) ) ;
2011-05-15 13:23:13 +00:00
2004-08-23 00:15:46 +00:00
for ( server = firstserver ; server ; server = server - > next )
{
if ( server - > special & SS_FAVORITE )
{
2014-12-23 15:26:42 +00:00
switch ( server - > special & SS_PROTOCOLMASK )
{
case SS_QUAKE3 :
2013-05-03 04:28:08 +00:00
VFS_PUTS ( mf , va ( " %s \t %s \t %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , & server - > adr ) , " favorite:q3 " , server - > name ) ) ;
2014-12-23 15:26:42 +00:00
break ;
case SS_QUAKE2 :
2013-05-03 04:28:08 +00:00
VFS_PUTS ( mf , va ( " %s \t %s \t %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , & server - > adr ) , " favorite:q2 " , server - > name ) ) ;
2014-12-23 15:26:42 +00:00
break ;
case SS_NETQUAKE :
2013-05-03 04:28:08 +00:00
VFS_PUTS ( mf , va ( " %s \t %s \t %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , & server - > adr ) , " favorite:nq " , server - > name ) ) ;
2014-12-23 15:26:42 +00:00
break ;
case SS_QUAKEWORLD :
if ( qws ) //servers.txt doesn't support the extra info, so don't write it if its not needed
VFS_PUTS ( qws , va ( " %s \t %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , & server - > adr ) , server - > name ) ) ;
else
VFS_PUTS ( mf , va ( " %s \t %s \t %s \n " , NET_AdrToString ( adr , sizeof ( adr ) , & server - > adr ) , " favorite:qw " , server - > name ) ) ;
break ;
}
2004-08-23 00:15:46 +00:00
}
}
2011-05-15 13:23:13 +00:00
2004-08-23 00:15:46 +00:00
if ( qws )
2009-04-01 22:03:56 +00:00
VFS_CLOSE ( qws ) ;
2011-05-15 13:23:13 +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.
2011-06-16 02:03:57 +00:00
void MasterInfo_Refresh ( void )
2004-08-23 00:15:46 +00:00
{
master_t * mast ;
2013-10-29 17:38:22 +00:00
qboolean loadedone ;
loadedone = false ;
2014-12-23 15:26:42 +00:00
loadedone | = Master_LoadMasterList ( " masters.txt " , false , MT_MASTERUDP , MP_QUAKEWORLD , 5 ) ; //fte listing
loadedone | = Master_LoadMasterList ( " sources.txt " , true , MT_MASTERUDP , MP_QUAKEWORLD , 5 ) ; //merge with ezquake compat listing
2013-10-29 17:38:22 +00:00
if ( ! loadedone )
2004-08-23 00:15:46 +00:00
{
2014-12-23 15:26:42 +00:00
int i ;
Master_LoadMasterList ( " servers.txt " , false , MT_MASTERUDP , MP_QUAKEWORLD , 1 ) ;
2017-02-19 00:15:42 +00:00
Master_AddMaster ( " 255.255.255.255: " STRINGIFY ( PORT_QWSERVER ) , MT_BCAST , MP_QUAKEWORLD , " Nearby QuakeWorld UDP servers. " ) ;
# ifndef QUAKETC
2014-12-23 15:26:42 +00:00
Master_AddMasterHTTP ( " http://www.gameaholic.com/servers/qspy-quakeworld " , MT_MASTERHTTP , MP_QUAKEWORLD , " gameaholic's QW master " ) ;
2016-07-12 00:40:13 +00:00
Master_AddMasterHTTP ( " https://www.quakeservers.net/lists/servers/global.txt " , MT_MASTERHTTP , MP_QUAKEWORLD , " QuakeServers.net (http) " ) ;
2017-02-19 00:15:42 +00:00
# endif
# ifdef NQPROT
2014-12-23 15:26:42 +00:00
Master_AddMasterHTTP ( " http://www.gameaholic.com/servers/qspy-quake " , MT_MASTERHTTP , MP_NETQUAKE , " gameaholic's NQ master " ) ;
Master_AddMasterHTTP ( " http://servers.quakeone.com/index.php?format=json " , MT_MASTERHTTPJSON , MP_NETQUAKE , " quakeone's server listing " ) ;
Master_AddMaster ( " 255.255.255.255: " STRINGIFY ( PORT_NQSERVER ) , MT_BCAST , MP_NETQUAKE , " Nearby Quake1 servers " ) ;
Master_AddMaster ( " 255.255.255.255: " STRINGIFY ( PORT_NQSERVER ) , MT_BCAST , MP_DPMASTER , " Nearby DarkPlaces servers " ) ;
2017-02-19 00:15:42 +00:00
# endif
# ifdef Q2CLIENT
2014-12-23 15:26:42 +00:00
Master_AddMasterHTTP ( " http://www.gameaholic.com/servers/qspy-quake2 " , MT_MASTERHTTP , MP_QUAKE2 , " gameaholic's Q2 master " ) ;
Master_AddMaster ( " 255.255.255.255:27910 " , MT_BCAST , MP_QUAKE2 , " Nearby Quake2 UDP servers. " ) ;
2017-02-19 00:15:42 +00:00
# endif
# ifdef Q3CLIENT
2014-12-23 15:26:42 +00:00
Master_AddMasterHTTP ( " http://www.gameaholic.com/servers/qspy-quake3 " , MT_MASTERHTTP , MP_QUAKE3 , " gameaholic's Q3 master " ) ;
Master_AddMaster ( " 255.255.255.255: " STRINGIFY ( PORT_Q3SERVER ) , MT_BCAST , MP_QUAKE3 , " Nearby Quake3 UDP servers. " ) ;
2017-02-19 00:15:42 +00:00
# endif
2014-12-23 15:26:42 +00:00
for ( i = 0 ; net_masterlist [ i ] . cv . name ; i + + )
2005-05-26 12:55:34 +00:00
{
2014-12-23 15:26:42 +00:00
Master_AddMaster ( net_masterlist [ i ] . cv . string , MT_MASTERUDP , net_masterlist [ i ] . protocol , net_masterlist [ i ] . comment ) ;
2005-08-26 22:56:51 +00:00
}
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 )
{
2011-06-16 02:03:57 +00:00
mast - > sends = 1 ;
2004-08-23 00:15:46 +00:00
}
2011-06-16 02:03:57 +00:00
Master_SortServers ( ) ;
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 ( ) ;
2014-12-23 15:26:42 +00:00
switch ( server - > special & SS_PROTOCOLMASK )
{
case SS_QUAKE3 :
2011-07-22 15:11:35 +00:00
Q_snprintfz ( data , sizeof ( data ) , " %c%c%c%cgetstatus " , 255 , 255 , 255 , 255 ) ;
2014-12-23 15:26:42 +00:00
break ;
case SS_DARKPLACES :
2016-09-08 19:04:35 +00:00
if ( server - > moreinfo )
Q_snprintfz ( data , sizeof ( data ) , " %c%c%c%cgetstatus " , 255 , 255 , 255 , 255 ) ;
else
Q_snprintfz ( data , sizeof ( data ) , " %c%c%c%cgetinfo " , 255 , 255 , 255 , 255 ) ;
2014-12-23 15:26:42 +00:00
break ;
2005-05-26 12:55:34 +00:00
# ifdef NQPROT
2014-12-23 15:26:42 +00:00
case SS_NETQUAKE :
2005-05-26 12:55:34 +00:00
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
2014-12-23 15:26:42 +00:00
MSG_WriteByte ( & net_message , NQ_NETCHAN_VERSION ) ;
2005-05-26 12:55:34 +00:00
* ( ( 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 ) ;
2014-12-23 15:26:42 +00:00
return ;
2005-05-26 12:55:34 +00:00
# endif
2014-12-23 15:26:42 +00:00
case SS_QUAKEWORLD :
2015-06-19 16:56:50 +00:00
Q_snprintfz ( data , sizeof ( data ) , " %c%c%c%cstatus 23 \n " , 255 , 255 , 255 , 255 ) ;
break ;
2014-12-23 15:26:42 +00:00
case SS_QUAKE2 :
2015-06-19 16:56:50 +00:00
Q_snprintfz ( data , sizeof ( data ) , " %c%c%c%cstatus \n " , 255 , 255 , 255 , 255 ) ;
2014-12-23 15:26:42 +00:00
break ;
default :
2005-05-26 12:55:34 +00:00
return ;
}
2004-08-23 00:15:46 +00:00
NET_SendPollPacket ( strlen ( data ) , data , server - > adr ) ;
}
//send a packet to each server in sequence.
2015-06-18 22:11:30 +00:00
qboolean CL_QueryServers ( void )
2004-08-23 00:15:46 +00:00
{
static int poll ;
int op ;
2011-05-15 13:23:13 +00:00
serverinfo_t * server ;
2011-06-16 02:03:57 +00:00
master_t * mast ;
2006-03-14 01:18:47 +00:00
2014-12-23 15:26:42 +00:00
Master_DetermineMasterTypes ( ) ;
2006-03-14 01:18:47 +00:00
2004-08-23 00:15:46 +00:00
op = poll ;
2011-05-15 13:23:13 +00:00
2011-06-16 02:03:57 +00:00
for ( mast = master ; mast ; mast = mast - > next )
{
2013-10-29 17:38:22 +00:00
switch ( mast - > protocoltype )
2011-06-16 02:03:57 +00:00
{
2013-10-29 17:38:22 +00:00
case MP_UNSPECIFIED :
2011-06-16 02:03:57 +00:00
continue ;
2014-12-23 15:26:42 +00:00
case MP_DPMASTER : //dpmaster allows the client to specify the protocol to query. this means it always matches the current game type, so don't bother allowing the user to disable it.
if ( ! sb_enabledarkplaces )
continue ;
2013-10-29 17:38:22 +00:00
break ;
2014-12-23 15:26:42 +00:00
case MP_NETQUAKE :
if ( ! sb_enablenetquake )
2011-06-16 02:03:57 +00:00
continue ;
break ;
2014-12-23 15:26:42 +00:00
case MP_QUAKEWORLD :
if ( ! sb_enablequakeworld )
2011-06-16 02:03:57 +00:00
continue ;
break ;
2014-12-23 15:26:42 +00:00
case MP_QUAKE2 :
if ( ! sb_enablequake2 )
2011-06-16 02:03:57 +00:00
continue ;
break ;
2014-12-23 15:26:42 +00:00
case MP_QUAKE3 :
if ( ! sb_enablequake3 )
2011-06-16 02:03:57 +00:00
continue ;
break ;
}
if ( mast - > sends > 0 )
2013-10-29 17:38:22 +00:00
MasterInfo_Request ( mast ) ;
2011-06-16 02:03:57 +00:00
}
2004-08-23 00:15:46 +00:00
for ( server = firstserver ; op > 0 & & server ; server = server - > next , op - - ) ;
if ( ! server )
{
poll = 0 ;
2015-06-18 22:11:30 +00:00
return false ;
2004-08-23 00:15:46 +00:00
}
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 )
{
2014-12-23 15:26:42 +00:00
qboolean enabled ;
switch ( server - > special & SS_PROTOCOLMASK )
{
case SS_UNKNOWN : enabled = true ; break ;
case SS_QUAKE3 : enabled = sb_enablequake3 ; break ;
case SS_QUAKE2 : enabled = sb_enablequake2 ; break ;
case SS_NETQUAKE : enabled = sb_enablenetquake ; break ;
case SS_QUAKEWORLD : enabled = sb_enablequakeworld ; break ;
case SS_DARKPLACES : enabled = sb_enabledarkplaces ; break ;
default : enabled = false ; break ;
}
if ( enabled )
2015-06-19 16:56:50 +00:00
{
if ( server & & server - > sends > 0 )
{
Master_QueryServer ( server ) ;
poll + + ;
return true ;
}
}
2006-03-14 01:18:47 +00:00
server = server - > next ;
poll + + ;
}
if ( ! server )
{
2015-06-19 16:56:50 +00:00
poll = 0 ;
2006-03-14 01:18:47 +00:00
server = firstserver ;
while ( server )
{
2014-12-23 15:26:42 +00:00
qboolean enabled ;
switch ( server - > special & SS_PROTOCOLMASK )
{
case SS_UNKNOWN : enabled = true ; break ;
case SS_QUAKE3 : enabled = sb_enablequake3 ; break ;
case SS_QUAKE2 : enabled = sb_enablequake2 ; break ;
case SS_NETQUAKE : enabled = sb_enablenetquake ; break ;
case SS_QUAKEWORLD : enabled = sb_enablequakeworld ; break ;
case SS_DARKPLACES : enabled = sb_enabledarkplaces ; break ;
default : enabled = false ; break ;
}
if ( enabled )
2015-06-19 16:56:50 +00:00
{
if ( server & & server - > sends > 0 )
{
Master_QueryServer ( server ) ;
poll + + ;
return true ;
}
}
2006-03-14 01:18:47 +00:00
server = server - > next ;
poll + + ;
}
}
2004-08-23 00:15:46 +00:00
}
2011-05-15 13:23:13 +00:00
2015-06-18 22:11:30 +00:00
return false ;
2004-08-23 00:15:46 +00:00
}
2011-06-16 02:03:57 +00:00
unsigned int Master_TotalCount ( void )
2004-08-23 00:15:46 +00:00
{
2011-06-16 02:03:57 +00:00
unsigned int count = 0 ;
2004-08-23 00:15:46 +00:00
serverinfo_t * info ;
for ( info = firstserver ; info ; info = info - > next )
{
count + + ;
}
return count ;
}
2011-06-16 02:03:57 +00:00
unsigned int Master_NumPolled ( void )
{
unsigned int count = 0 ;
serverinfo_t * info ;
for ( info = firstserver ; info ; info = info - > next )
{
2015-06-18 22:11:30 +00:00
if ( ! info - > sends )
2011-06-16 02:03:57 +00:00
count + + ;
}
return count ;
}
2016-07-12 00:40:13 +00:00
unsigned int Master_NumAlive ( void )
{
unsigned int count = 0 ;
serverinfo_t * info ;
for ( info = firstserver ; info ; info = info - > next )
{
if ( info - > status & 1u )
count + + ;
}
return count ;
}
2011-06-16 02:03:57 +00:00
2004-08-23 00:15:46 +00:00
//true if server is on a different master's list.
2013-05-03 04:28:08 +00:00
serverinfo_t * Master_InfoForServer ( netadr_t * addr )
2004-08-23 00:15:46 +00:00
{
serverinfo_t * info ;
for ( info = firstserver ; info ; info = info - > next )
{
2013-05-03 04:28:08 +00:00
if ( NET_CompareAdr ( & info - > adr , addr ) )
2004-08-23 00:15:46 +00:00
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 ;
}
2012-11-27 03:23:19 +00:00
void MasterInfo_RemoveAllPlayers ( void )
{
player_t * p ;
while ( mplayers )
{
p = mplayers ;
mplayers = p - > next ;
Z_Free ( p ) ;
}
}
2013-05-03 04:28:08 +00:00
void MasterInfo_RemovePlayers ( netadr_t * adr )
2004-08-23 00:15:46 +00:00
{
player_t * p , * prev ;
prev = NULL ;
for ( p = mplayers ; p ; )
{
2013-05-03 04:28:08 +00:00
if ( NET_CompareAdr ( & p - > adr , adr ) )
2004-08-23 00:15:46 +00:00
{
if ( prev )
prev - > next = p - > next ;
else
mplayers = p - > next ;
Z_Free ( p ) ;
p = prev ;
continue ;
}
else
prev = p ;
p = p - > next ;
}
}
2015-06-18 22:11:30 +00:00
void MasterInfo_AddPlayer ( netadr_t * serveradr , char * name , int ping , int frags , int colours , char * skin , char * team )
2004-08-23 00:15:46 +00:00
{
player_t * p ;
p = Z_Malloc ( sizeof ( player_t ) ) ;
p - > next = mplayers ;
2013-05-03 04:28:08 +00:00
p - > adr = * serveradr ;
2004-08-23 00:15:46 +00:00
p - > colour = colours ;
p - > frags = frags ;
2015-06-18 22:11:30 +00:00
Q_strncpyz ( p - > team , team , sizeof ( p - > team ) ) ;
2004-08-23 00:15:46 +00:00
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
2013-10-29 17:38:22 +00:00
int CL_ReadServerInfo ( char * msg , enum masterprotocol_e prototype , qboolean favorite )
2004-08-23 00:15:46 +00:00
{
serverdetailedinfo_t details ;
char * token ;
char * nl ;
2011-05-15 13:23:13 +00:00
char * name ;
2004-08-23 00:15:46 +00:00
int ping ;
2015-06-22 11:49:15 +00:00
int len , j , k ;
2004-08-23 00:15:46 +00:00
serverinfo_t * info ;
2008-06-08 14:37:57 +00:00
char adr [ MAX_ADR_SIZE ] ;
2004-08-23 00:15:46 +00:00
2013-05-03 04:28:08 +00:00
info = Master_InfoForServer ( & net_from ) ;
2004-08-23 00:15:46 +00:00
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. :(
2010-11-21 03:39:12 +00:00
// if (atoi(Info_ValueForKey(msg, "sv_pure")))
// return false; //we don't support the filesystem hashing. :(
2005-08-26 22:56:51 +00:00
2004-08-23 00:15:46 +00:00
info = Z_Malloc ( sizeof ( serverinfo_t ) ) ;
info - > adr = net_from ;
2013-05-03 04:28:08 +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 ;
2014-12-23 15:26:42 +00:00
//server replied from a broadcast message, make sure we ping it to retrieve its actual ping
info - > sends = 1 ;
info - > ping = 0xffff ; //not known
info - > special | = SS_LOCAL ;
2004-08-23 00:15:46 +00:00
}
else
{
2014-12-23 15:26:42 +00:00
//determine the ping
if ( info - > refreshtime )
{
ping = ( Sys_DoubleTime ( ) - info - > refreshtime ) * 1000 ;
if ( ping > 0xfffe )
info - > ping = 0xfffe ; //highest (that is known)
else
info - > ping = ping ;
}
info - > refreshtime = 0 ;
2004-08-23 00:15:46 +00:00
}
2016-07-12 00:40:13 +00:00
info - > status | = 1u ;
2004-08-23 00:15:46 +00:00
nl = strchr ( msg , ' \n ' ) ;
if ( nl )
{
* nl = ' \0 ' ;
nl + + ;
}
2015-07-07 02:03:31 +00:00
if ( info - > special & SS_PROXY )
{
if ( ! * Info_ValueForKey ( msg , " hostname " ) )
{ //qq, you suck
//this is a proxy peer list, not an actual serverinfo update.
unsigned char * ptr = net_message . data + 5 ;
int remaining = net_message . cursize - 5 ;
struct peers_s * peer ;
netadr_t pa ;
memset ( & pa , 0 , sizeof ( pa ) ) ;
remaining / = 8 ;
NET_AdrToString ( adr , sizeof ( adr ) , & info - > adr ) ;
Z_Free ( info - > peers ) ;
2015-07-07 02:33:00 +00:00
info - > numpeers = 0 ;
peer = info - > peers = Z_Malloc ( sizeof ( * peer ) * remaining ) ;
2015-07-07 02:03:31 +00:00
while ( remaining - - > 0 )
{
pa . type = NA_IP ;
pa . address . ip [ 0 ] = * ptr + + ;
pa . address . ip [ 1 ] = * ptr + + ;
pa . address . ip [ 2 ] = * ptr + + ;
pa . address . ip [ 3 ] = * ptr + + ;
pa . port = * ptr + + < < 8 ;
pa . port | = * ptr + + ;
peer - > ping = * ptr + + ;
peer - > ping | = * ptr + + < < 8 ;
2015-07-07 02:33:00 +00:00
if ( NET_ClassifyAddress ( & pa , NULL ) > = ASCOPE_NET )
2015-07-07 02:03:31 +00:00
{
2015-07-07 02:33:00 +00:00
peer - > peer = Master_InfoForServer ( & pa ) ;
if ( ! peer - > peer )
{
//generate some lame peer node that we can use.
peer - > peer = Z_Malloc ( sizeof ( serverinfo_t ) ) ;
peer - > peer - > adr = pa ;
peer - > peer - > sends = 1 ;
peer - > peer - > special = 0 ;
peer - > peer - > refreshtime = 0 ;
peer - > peer - > ping = 0xffff ;
peer - > peer - > next = firstserver ;
firstserver = peer - > peer ;
}
peer + + ;
info - > numpeers + + ;
2015-07-07 02:03:31 +00:00
}
}
return false ;
}
}
2004-08-23 00:15:46 +00:00
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 ) ) ;
2014-12-23 15:26:42 +00:00
info - > special = info - > special & ( SS_FAVORITE | SS_KEEPINFO | SS_LOCAL ) ; //favorite+local 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 ;
2014-12-23 15:26:42 +00:00
else if ( ! strncmp ( DISTRIBUTION , Info_ValueForKey ( msg , " *version " ) , strlen ( DISTRIBUTION ) ) )
2004-08-23 00:15:46 +00:00
info - > special | = SS_FTESERVER ;
2004-10-10 06:32:29 +00:00
2014-12-23 15:26:42 +00:00
info - > protocol = atoi ( Info_ValueForKey ( msg , " protocol " ) ) ;
info - > special & = ~ SS_PROTOCOLMASK ;
if ( info - > protocol )
2005-08-26 22:56:51 +00:00
{
2014-12-23 15:26:42 +00:00
switch ( info - > protocol )
{
case PROTOCOL_VERSION_QW : info - > special = SS_QUAKEWORLD ; break ;
# ifdef NQPROT
2016-02-15 06:01:17 +00:00
case PROTOCOL_VERSION_NQ : info - > special = SS_NETQUAKE ; break ;
case PROTOCOL_VERSION_H2 : info - > special = SS_NETQUAKE ; break ; //erk
case PROTOCOL_VERSION_NEHD : info - > special = SS_NETQUAKE ; break ;
case PROTOCOL_VERSION_FITZ : info - > special = SS_NETQUAKE ; break ;
case PROTOCOL_VERSION_RMQ : info - > special = SS_NETQUAKE ; break ;
case PROTOCOL_VERSION_DP5 : info - > special = SS_DARKPLACES ; break ; //dp actually says 3... but hey, that's dp being WEIRD.
case PROTOCOL_VERSION_DP6 : info - > special = SS_DARKPLACES ; break ;
case PROTOCOL_VERSION_DP7 : info - > special = SS_DARKPLACES ; break ;
2014-12-23 15:26:42 +00:00
# endif
default :
if ( PROTOCOL_VERSION_Q2 > = info - > protocol & & info - > protocol > = PROTOCOL_VERSION_Q2_MIN )
info - > special | = SS_QUAKE2 ; //q2 has a range!
else if ( info - > protocol > 60 )
info - > special | = SS_QUAKE3 ;
else
info - > special | = SS_DARKPLACES ;
break ;
}
2005-08-26 22:56:51 +00:00
}
2014-12-23 15:26:42 +00:00
else if ( prototype = = MP_QUAKE2 )
2004-08-23 00:15:46 +00:00
info - > special | = SS_QUAKE2 ;
2014-12-23 15:26:42 +00:00
else if ( prototype = = MP_QUAKE3 )
2005-08-26 22:56:51 +00:00
info - > special | = SS_QUAKE3 ;
2014-12-23 15:26:42 +00:00
else if ( prototype = = MP_NETQUAKE )
2004-08-23 00:15:46 +00:00
info - > special | = SS_NETQUAKE ;
2014-12-23 15:26:42 +00:00
else
info - > special | = SS_QUAKEWORLD ;
2004-08-23 00:15:46 +00:00
if ( favorite ) //was specifically named, not retrieved from a master.
info - > special | = SS_FAVORITE ;
info - > players = 0 ;
2014-04-24 01:53:01 +00:00
ping = atoi ( Info_ValueForKey ( msg , " maxclients " ) ) ;
if ( ! ping )
ping = atoi ( Info_ValueForKey ( msg , " sv_maxclients " ) ) ;
info - > maxplayers = bound ( 0 , ping , 255 ) ;
2004-08-23 00:15:46 +00:00
2014-12-23 15:26:42 +00:00
ping = atoi ( Info_ValueForKey ( msg , " timelimit " ) ) ;
info - > tl = bound ( - 327678 , ping , 32767 ) ;
ping = atoi ( Info_ValueForKey ( msg , " fraglimit " ) ) ;
info - > fl = bound ( - 32768 , ping , 32767 ) ;
2004-08-23 00:15:46 +00:00
2014-12-23 15:26:42 +00:00
if ( * Info_ValueForKey ( msg , " *qtv " ) | | * Info_ValueForKey ( msg , " *QTV " ) )
info - > special | = SS_PROXY | SS_FTESERVER ; //qtv
2006-09-17 00:59:22 +00:00
if ( ! strcmp ( Info_ValueForKey ( msg , " *progs " ) , " 666 " ) & & ! strcmp ( Info_ValueForKey ( msg , " *version " ) , " 2.91 " ) )
info - > special | = SS_PROXY ; //qizmo
2014-12-23 15:26:42 +00:00
if ( ! Q_strncmp ( Info_ValueForKey ( msg , " *version " ) , " qwfwd " , 5 ) )
2015-07-07 02:03:31 +00:00
{
char * msg = " \xff \xff \xff \xff pingstatus " ;
NET_SendPollPacket ( strlen ( msg ) , msg , info - > adr ) ;
2014-12-23 15:26:42 +00:00
info - > special | = SS_PROXY ; //qwfwd
2015-07-07 02:03:31 +00:00
}
2014-12-23 15:26:42 +00:00
if ( ! Q_strncasecmp ( Info_ValueForKey ( msg , " *version " ) , " qtv " , 4 ) )
info - > special | = SS_PROXY ; //eztv
token = Info_ValueForKey ( msg , " map " ) ;
if ( ! * token )
token = Info_ValueForKey ( msg , " mapname " ) ;
Q_strncpyz ( info - > map , token , sizeof ( info - > map ) ) ;
token = Info_ValueForKey ( msg , " *gamedir " ) ;
if ( ! * token )
token = Info_ValueForKey ( msg , " gamedir " ) ;
if ( ! * token )
token = Info_ValueForKey ( msg , " modname " ) ;
Q_strncpyz ( info - > gamedir , token , sizeof ( info - > gamedir ) ) ;
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 - > gameversion = atoi ( Info_ValueForKey ( msg , " gameversion " ) ) ;
2015-06-19 16:56:50 +00:00
info - > numbots = 0 ; //atoi(Info_ValueForKey(msg, "bots"));
2008-11-09 22:29:28 +00:00
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 ;
2016-09-08 19:04:35 +00:00
//clear player info. unless its an NQ server, which have some really annoying protocol to find out the players.
if ( ( info - > special & SS_PROTOCOLMASK ) = = SS_NETQUAKE )
{
if ( ! info - > moreinfo & & ( ( slist_cacheinfo . value = = 2 | | NET_CompareAdr ( & info - > adr , & selectedserver . adr ) ) | | ( info - > special & SS_KEEPINFO ) ) )
info - > moreinfo = Z_Malloc ( sizeof ( serverdetailedinfo_t ) ) ;
2015-10-27 15:20:15 +00:00
info - > numhumans = info - > players = atoi ( Info_ValueForKey ( details . info , " clients " ) ) ;
2016-09-08 19:04:35 +00:00
}
2005-06-04 04:20:20 +00:00
else
2004-08-23 00:15:46 +00:00
{
2016-09-08 19:04:35 +00:00
MasterInfo_RemovePlayers ( & info - > adr ) ;
info - > players = details . numplayers = 0 ;
if ( ! strchr ( msg , ' \n ' ) )
info - > numhumans = info - > players = atoi ( Info_ValueForKey ( details . info , " clients " ) ) ;
else
2004-08-23 00:15:46 +00:00
{
2016-09-08 19:04:35 +00:00
int clnum ;
2015-06-22 11:49:15 +00:00
2016-09-08 19:04:35 +00:00
for ( clnum = 0 ; clnum < MAX_CLIENTS ; clnum + + )
2004-08-23 00:15:46 +00:00
{
2016-09-08 19:04:35 +00:00
nl = strchr ( msg , ' \n ' ) ;
if ( ! nl )
2004-08-23 00:15:46 +00:00
break ;
2016-09-08 19:04:35 +00:00
* nl = ' \0 ' ;
2004-08-23 00:15:46 +00:00
2016-09-08 19:04:35 +00:00
details . players [ clnum ] . isspec = 0 ;
details . players [ clnum ] . team [ 0 ] = 0 ;
details . players [ clnum ] . skin [ 0 ] = 0 ;
2004-08-23 00:15:46 +00:00
2016-09-08 19:04:35 +00:00
token = msg ;
2004-08-23 00:15:46 +00:00
if ( ! token )
break ;
2016-09-08 19:04:35 +00:00
details . players [ clnum ] . userid = atoi ( token ) ;
token = strchr ( token + 1 , ' ' ) ;
2004-08-23 00:15:46 +00:00
if ( ! token )
break ;
2016-09-08 19:04:35 +00:00
details . players [ clnum ] . frags = atoi ( token ) ;
token = strchr ( token + 1 , ' ' ) ;
if ( ! token )
2004-08-23 00:15:46 +00:00
break ;
2016-09-08 19:04:35 +00:00
details . players [ clnum ] . time = atoi ( token ) ;
msg = token ;
token = strchr ( msg + 1 , ' ' ) ;
if ( ! token ) //probably q2 response
2015-06-22 11:49:15 +00:00
{
2016-09-08 19:04:35 +00:00
//see if this is actually a Quake2 server.
token = strchr ( msg + 1 , ' \" ' ) ;
if ( ! token ) //it wasn't.
break ;
2004-08-23 00:15:46 +00:00
2016-09-08 19:04:35 +00:00
details . players [ clnum ] . ping = details . players [ clnum ] . frags ;
details . players [ clnum ] . frags = details . players [ clnum ] . userid ;
2004-08-23 00:15:46 +00:00
2016-09-08 19:04:35 +00:00
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 ) ;
2015-06-18 22:11:30 +00:00
2016-09-08 19:04:35 +00:00
details . players [ clnum ] . skin [ 0 ] = ' \0 ' ;
details . players [ clnum ] . topc = 0 ;
details . players [ clnum ] . botc = 0 ;
details . players [ clnum ] . time = 0 ;
}
else //qw response
2015-06-18 22:11:30 +00:00
{
2016-09-08 19:04:35 +00:00
details . players [ clnum ] . ping = atoi ( token ) ;
msg = token ;
token = strchr ( msg + 1 , ' ' ) ;
if ( ! token )
break ;
token = strchr ( token + 1 , ' \" ' ) ;
if ( ! token )
break ;
2015-06-18 22:11:30 +00:00
msg = strchr ( token + 1 , ' \" ' ) ;
2016-09-08 19:04:35 +00:00
if ( ! msg )
break ;
len = msg - token ;
if ( len > = sizeof ( details . players [ clnum ] . name ) )
len = sizeof ( details . players [ clnum ] . name ) ;
if ( ! strncmp ( token , " \" \\ s \\ " , 4 ) )
2015-06-18 22:11:30 +00:00
{
2016-09-08 19:04:35 +00:00
details . players [ clnum ] . isspec | = 1 ;
Q_strncpyz ( details . players [ clnum ] . name , token + 4 , len - 3 ) ;
2015-06-18 22:11:30 +00:00
}
2016-09-08 19:04:35 +00:00
else
Q_strncpyz ( details . players [ clnum ] . name , token + 1 , len ) ;
details . players [ clnum ] . name [ len ] = ' \0 ' ;
2004-08-23 00:15:46 +00:00
2016-09-08 19:04:35 +00:00
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 ) ;
2004-08-23 00:15:46 +00:00
2016-09-08 19:04:35 +00:00
token = strchr ( msg + 1 , ' \" ' ) ;
Q_strncpyz ( details . players [ clnum ] . team , " " , sizeof ( details . players [ clnum ] . team ) ) ;
if ( token )
{
msg = strchr ( token + 1 , ' \" ' ) ;
if ( msg )
{
len = msg - token ;
if ( len > = sizeof ( details . players [ clnum ] . team ) )
len = sizeof ( details . players [ clnum ] . team ) ;
Q_strncpyz ( details . players [ clnum ] . team , token + 1 , len ) ;
details . players [ clnum ] . team [ len ] = ' \0 ' ;
}
}
}
2015-06-22 11:49:15 +00:00
2016-09-08 19:04:35 +00:00
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 , details . players [ clnum ] . team ) ;
//WallFly is some q2 bot
//[ServeMe] is some qw bot
if ( ! strncmp ( details . players [ clnum ] . name , " WallFly " , 7 ) | | ! strcmp ( details . players [ clnum ] . name , " [ServeMe] " ) )
2015-06-22 11:49:15 +00:00
{
2016-09-08 19:04:35 +00:00
//not players nor real people. they don't count towards any metric
details . players [ clnum ] . isspec | = 3 ;
}
//807 excludes the numerous bot names on some annoying qwtf server
//BOT: excludes fte's botclients (which always have a bot: prefix)
else if ( details . players [ clnum ] . ping = = 807 | | ! strncmp ( details . players [ clnum ] . name , " BOT: " , 4 ) )
{
info - > numbots + + ;
details . players [ clnum ] . isspec | = 2 ;
}
else if ( details . players [ clnum ] . isspec & 1 )
{
info - > numspectators + + ;
2015-06-22 11:49:15 +00:00
}
else
2016-09-08 19:04:35 +00:00
info - > numhumans + + ;
2015-06-22 11:49:15 +00:00
2016-09-08 19:04:35 +00:00
for ( k = clnum , j = clnum - 1 ; j > = 0 ; j - - )
{
if ( ( details . players [ k ] . isspec ! = details . players [ j ] . isspec & & ! details . players [ k ] . isspec ) | |
details . players [ k ] . frags > details . players [ j ] . frags )
{
struct serverdetailedplayerinfo_s t = details . players [ j ] ;
details . players [ j ] = details . players [ k ] ;
details . players [ k ] = t ;
k = j ;
}
else
break ;
}
details . numplayers + + ;
info - > players + + ;
2004-08-23 00:15:46 +00:00
2016-09-08 19:04:35 +00:00
msg = nl ;
if ( ! msg )
break ; //erm...
msg + + ;
}
2004-08-23 00:15:46 +00:00
}
2016-09-08 19:04:35 +00:00
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 ;
2004-08-23 00:15:46 +00:00
2016-09-08 19:04:35 +00:00
if ( info - > moreinfo )
memcpy ( info - > moreinfo , & details , sizeof ( serverdetailedinfo_t ) ) ;
}
2004-08-23 00:15:46 +00:00
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
2017-05-18 10:24:09 +00:00
MSG_ReadByte ( ) ; //should be \n
2004-08-23 00:15:46 +00:00
last = firstserver ;
2014-12-23 15:26:42 +00:00
while ( msg_readcount + 1 + 2 < net_message . cursize )
2004-08-23 00:15:46 +00:00
{
2005-05-17 02:36:54 +00:00
if ( slashpad )
{
2014-12-23 15:26:42 +00:00
switch ( MSG_ReadByte ( ) )
{
case ' \\ ' :
adrtype = NA_IP ;
adrlen = 4 ;
break ;
case ' / ' :
adrtype = NA_IPV6 ;
adrlen = 16 ;
2005-05-17 02:36:54 +00:00
break ;
2014-12-23 15:26:42 +00:00
default :
firstserver = last ;
return ;
}
2005-05-17 02:36:54 +00:00
}
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 ;
2013-05-11 05:03:07 +00:00
default :
2011-05-15 13:23:13 +00:00
break ;
2009-04-01 22:03:56 +00:00
}
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 ;
}
2013-05-03 04:28:08 +00:00
if ( ( old = Master_InfoForServer ( & info - > adr ) ) ) //remove if the server already exists.
2004-08-23 00:15:46 +00:00
{
2014-12-23 15:26:42 +00:00
if ( ( old - > special & ( SS_PROTOCOLMASK ) ) ! = ( type & ( SS_PROTOCOLMASK ) ) )
old - > special = type | ( old - > special & ( SS_FAVORITE | SS_LOCAL ) ) ;
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 ;
2013-05-03 04:28:08 +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 ) ;
2011-05-15 13:23:13 +00:00
}
2004-08-23 00:15:46 +00:00
}
firstserver = last ;
}
# endif
2010-03-14 14:35:56 +00:00