summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorBen Millwood <thebenmachine@gmail.com>2009-10-03 13:15:37 +0000
committerTim Angus <tim@ngus.net>2013-01-03 00:16:37 +0000
commit7199e8ddded777709df090973cab53c040592b72 (patch)
tree309ae026f25034903d1e09d37f01fca2f13ecc36 /src/client
parent39a04df7a0477708c11dae6e45e99c6da33e20d7 (diff)
* Featured server system
- The new master server sends some server records with an additional flag for the client to mark them as featured - they will then appear in a separate list.
Diffstat (limited to 'src/client')
-rw-r--r--src/client/cl_main.c164
-rw-r--r--src/client/cl_ui.c11
-rw-r--r--src/client/client.h11
3 files changed, 168 insertions, 18 deletions
diff --git a/src/client/cl_main.c b/src/client/cl_main.c
index 16ddcffc..47cf0196 100644
--- a/src/client/cl_main.c
+++ b/src/client/cl_main.c
@@ -2240,6 +2240,7 @@ void CL_InitServerInfo( serverInfo_t *server, netadr_t *address ) {
server->clients = 0;
server->hostName[0] = '\0';
server->mapName[0] = '\0';
+ server->label = NULL;
server->maxClients = 0;
server->maxPing = 0;
server->minPing = 0;
@@ -2249,6 +2250,102 @@ void CL_InitServerInfo( serverInfo_t *server, netadr_t *address ) {
server->netType = 0;
}
+/*
+===================
+CL_GSRSequenceInformation
+
+Parses this packet's index and the number of packets from a master server's
+response. Updates the packet count and returns the index. Advances the data
+pointer as appropriate (but only when parsing was successful)
+
+The sequencing information isn't terribly useful at present (we can skip
+duplicate packets, but we don't bother to make sure we've got all of them).
+===================
+*/
+int CL_GSRSequenceInformation( byte **data )
+{
+ char *p = (char *)*data, *e;
+ int ind, num;
+ // '\0'-delimited fields: this packet's index, total number of packets
+ if( *p++ != '\0' )
+ return -1;
+
+ ind = strtol( p, (char **)&e, 10 );
+ if( *e++ != '\0' )
+ return -1;
+
+ num = strtol( e, (char **)&p, 10 );
+ if( *p++ != '\0' )
+ return -1;
+
+ if( num <= 0 || ind <= 0 || ind > num )
+ return -1; // nonsensical response
+
+ if( cls.numMasterPackets > 0 && num != cls.numMasterPackets )
+ {
+ // Assume we sent two getservers and somehow they changed in
+ // between - only use the results that arrive later
+ Com_DPrintf( "Master changed its mind about packet count!\n" );
+ cls.receivedMasterPackets = 0;
+ cls.numglobalservers = 0;
+ cls.numGlobalServerAddresses = 0;
+ }
+ cls.numMasterPackets = num;
+
+ // successfully parsed
+ *data = (byte *)p;
+ return ind;
+}
+
+/*
+===================
+CL_GSRFeaturedLabel
+
+Parses from the data an arbitrary text string labelling the servers in the
+following getserversresponse packet.
+Either this matches an existing label, or it is copied into a new one.
+The relevant buffer, or NULL, is returned, and *data is advanced as appropriate
+===================
+*/
+char *CL_GSRFeaturedLabel( byte **data )
+{
+ char label[ MAX_FEATLABEL_CHARS ] = { 0 }, *l = label;
+ int i;
+
+ // copy until '\0' which indicates field break
+ // or slash which indicates beginning of server list
+ while( **data && **data != '\\' && **data != '/' )
+ {
+ if( l < &label[ sizeof( label ) - 1 ] )
+ *l = **data;
+ else if( l == &label[ sizeof( label ) - 1 ] )
+ Com_DPrintf( S_COLOR_YELLOW "Warning: "
+ "CL_GSRFeaturedLabel: overflow\n" );
+ l++, (*data)++;
+ }
+
+ if( !label[ 0 ] )
+ return NULL;
+
+ // find the label in the stored array
+ for( i = 0; i < cls.numFeaturedServerLabels; i++ )
+ {
+ l = cls.featuredServerLabels[ i ];
+ if( strcmp( label, l ) == 0 )
+ return l;
+ }
+ if( i == MAX_FEATURED_LABELS )
+ {
+ Com_DPrintf( S_COLOR_YELLOW "Warning: CL_GSRFeaturedLabel: "
+ "ran out of label space, dropping %s\n", label );
+ return NULL;
+ }
+ if( i == 0 )
+ l = cls.featuredServerLabels[ 0 ];
+ Q_strncpyz( l, label, sizeof( *cls.featuredServerLabels ) );
+ return l;
+}
+
#define MAX_SERVERSPERPACKET 256
/*
@@ -2262,13 +2359,18 @@ void CL_ServersResponsePacket( const netadr_t* from, msg_t *msg, qboolean extend
int numservers;
byte* buffptr;
byte* buffend;
+ char *label = NULL;
- Com_Printf("CL_ServersResponsePacket\n");
+ Com_DPrintf("CL_ServersResponsePacket%s\n",
+ (extended) ? " (extended)" : "");
if (cls.numglobalservers == -1) {
// state to detect lack of servers or lack of response
cls.numglobalservers = 0;
cls.numGlobalServerAddresses = 0;
+ cls.numMasterPackets = 0;
+ cls.receivedMasterPackets = 0;
+ cls.numFeaturedServerLabels = 0;
}
// parse through server response string
@@ -2276,14 +2378,47 @@ void CL_ServersResponsePacket( const netadr_t* from, msg_t *msg, qboolean extend
buffptr = msg->data;
buffend = buffptr + msg->cursize;
+ // skip header
+ buffptr += 4;
+
// advance to initial token
- do
+ // I considered using strchr for this but I don't feel like relying
+ // on its behaviour with '\0'
+ while( *buffptr && *buffptr != '\\' && *buffptr != '/' )
{
- if(*buffptr == '\\' || (extended && *buffptr == '/'))
- break;
-
buffptr++;
- } while (buffptr < buffend);
+
+ if( buffptr >= buffend )
+ break;
+ }
+
+ if( *buffptr == '\0' )
+ {
+ int ind = CL_GSRSequenceInformation( &buffptr );
+ if( ind >= 0 )
+ {
+ // this denotes the start of new-syntax stuff
+ // have we already received this packet?
+ if( cls.receivedMasterPackets & ( 1 << ( ind - 1 ) ) )
+ {
+ Com_DPrintf( "CL_ServersResponsePacket: "
+ "received packet %d again, ignoring\n",
+ ind );
+ return;
+ }
+ // TODO: detect dropped packets and make another
+ // request
+ Com_DPrintf( "CL_ServersResponsePacket: packet "
+ "%d of %d\n", ind, cls.numMasterPackets );
+ cls.receivedMasterPackets |= ( 1 << ( ind - 1 ) );
+
+ label = CL_GSRFeaturedLabel( &buffptr );
+ Com_DPrintf( "CL_GSRFeaturedLabel: %s\n", label );
+ }
+ // now skip to the server list
+ for(; buffptr < buffend && *buffptr != '\\' && *buffptr != '/';
+ buffptr++ );
+ }
while (buffptr + 1 < buffend)
{
@@ -2339,6 +2474,7 @@ void CL_ServersResponsePacket( const netadr_t* from, msg_t *msg, qboolean extend
serverInfo_t *server = &cls.globalServers[count];
CL_InitServerInfo( server, &addresses[i] );
+ server->label = label;
// advance to next slot
count++;
}
@@ -3725,7 +3861,6 @@ void CL_GlobalServers_f( void ) {
netadr_t to;
int count, i, masterNum;
char command[1024], *masteraddress;
- char *cmdname;
if ((count = Cmd_Argc()) < 3 || (masterNum = atoi(Cmd_Argv(1))) < 0 || masterNum > 4)
{
@@ -3760,17 +3895,10 @@ void CL_GlobalServers_f( void ) {
cls.numglobalservers = -1;
cls.pingUpdateSource = AS_GLOBAL;
- // Use the extended query for IPv6 masters
- if (to.type == NA_IP6 || to.type == NA_MULTICAST6)
- {
- cmdname = "getserversExt " GAMENAME_FOR_MASTER;
-
- // TODO: test if we only have an IPv6 connection. If it's the case,
- // request IPv6 servers only by appending " ipv6" to the command
- }
- else
- cmdname = "getservers";
- Com_sprintf( command, sizeof(command), "%s %s", cmdname, Cmd_Argv(2) );
+ // TODO: test if we only have an IPv6 connection. If it's the case,
+ // request IPv6 servers only by appending " ipv6" to the command
+ Com_sprintf( command, sizeof(command), "getserversExt "
+ GAMENAME_FOR_MASTER " %s", Cmd_Argv(2) );
for (i=3; i < count; i++)
{
diff --git a/src/client/cl_ui.c b/src/client/cl_ui.c
index 49719824..34ae04ea 100644
--- a/src/client/cl_ui.c
+++ b/src/client/cl_ui.c
@@ -285,6 +285,8 @@ static void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) {
buf[0] = '\0';
Info_SetValueForKey( info, "hostname", server->hostName);
Info_SetValueForKey( info, "mapname", server->mapName);
+ if( server->label )
+ Info_SetValueForKey( info, "label", server->label);
Info_SetValueForKey( info, "clients", va("%i",server->clients));
Info_SetValueForKey( info, "sv_maxclients", va("%i",server->maxClients));
Info_SetValueForKey( info, "ping", va("%i",server->ping));
@@ -375,6 +377,15 @@ static int LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int
return 0;
}
+ // featured servers on top
+ // this is not so that they are more noticeable but that codewise it
+ // makes it much simpler to have them contiguous in the list
+ // so changing this also requires changing the feederID counting and
+ // similar code that depends on them coming first
+ res = Q_stricmpn( server1->label, server2->label, MAX_FEATLABEL_CHARS );
+ if( res )
+ return -res;
+
res = 0;
switch( sortKey ) {
case SORT_HOST:
diff --git a/src/client/client.h b/src/client/client.h
index f19c6230..5a1106b4 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -288,6 +288,7 @@ typedef struct {
char hostName[MAX_HOSTNAME_LENGTH];
char mapName[MAX_NAME_LENGTH];
char game[MAX_NAME_LENGTH];
+ char *label; // for featured servers, NULL otherwise
int netType;
int gameType;
int clients;
@@ -298,6 +299,9 @@ typedef struct {
qboolean visible;
} serverInfo_t;
+#define MAX_FEATURED_LABELS 8
+#define MAX_FEATLABEL_CHARS 1024
+
typedef struct {
connstate_t state; // connection status
@@ -318,6 +322,10 @@ typedef struct {
int realtime; // ignores pause
int realFrametime; // ignoring pause, so console always works
+ // master server sequence information
+ int numMasterPackets;
+ unsigned int receivedMasterPackets; // bitfield
+
int numlocalservers;
serverInfo_t localServers[MAX_OTHER_SERVERS];
@@ -330,6 +338,9 @@ typedef struct {
int numfavoriteservers;
serverInfo_t favoriteServers[MAX_OTHER_SERVERS];
+ int numFeaturedServerLabels;
+ char featuredServerLabels[ MAX_FEATURED_LABELS ][ MAX_FEATLABEL_CHARS ];
+
int pingUpdateSource; // source currently pinging or updating
// update server info