case SLIF_FREESLOTS:
mask->info.freeslots = number;
break;
+ case SLIF_CATEGORY:
+ mask->info.category = number;
+ break;
case SLIF_ISFAVORITE:
mask->info.isfavorite = number != 0;
break;
*/
static void VM_M_getserverliststring(prvm_prog_t *prog)
{
- serverlist_entry_t *cache;
+ const serverlist_entry_t *cache;
int hostnr;
VM_SAFEPARMCOUNT(2, VM_M_getserverliststring);
hostnr = (int)PRVM_G_FLOAT(OFS_PARM1);
- if(hostnr < 0 || hostnr >= serverlist_viewcount)
+ if(hostnr == -1 && serverlist_callbackentry)
{
- Con_Print("VM_M_getserverliststring: bad hostnr passed!\n");
- return;
+ cache = serverlist_callbackentry;
+ }
+ else
+ {
+ if(hostnr < 0 || hostnr >= serverlist_viewcount)
+ {
+ Con_Print("VM_M_getserverliststring: bad hostnr passed!\n");
+ return;
+ }
+ cache = ServerList_GetViewEntry(hostnr);
}
- cache = ServerList_GetViewEntry(hostnr);
switch( (int) PRVM_G_FLOAT(OFS_PARM0) ) {
case SLIF_CNAME:
PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, cache->info.cname );
*/
static void VM_M_getserverlistnumber(prvm_prog_t *prog)
{
- serverlist_entry_t *cache;
+ const serverlist_entry_t *cache;
int hostnr;
VM_SAFEPARMCOUNT(2, VM_M_getserverliststring);
hostnr = (int)PRVM_G_FLOAT(OFS_PARM1);
- if(hostnr < 0 || hostnr >= serverlist_viewcount)
+ if(hostnr == -1 && serverlist_callbackentry)
{
- Con_Print("VM_M_getserverliststring: bad hostnr passed!\n");
- return;
+ cache = serverlist_callbackentry;
+ }
+ else
+ {
+ if(hostnr < 0 || hostnr >= serverlist_viewcount)
+ {
+ Con_Print("VM_M_getserverliststring: bad hostnr passed!\n");
+ return;
+ }
+ cache = ServerList_GetViewEntry(hostnr);
}
- cache = ServerList_GetViewEntry(hostnr);
switch( (int) PRVM_G_FLOAT(OFS_PARM0) ) {
case SLIF_MAXPLAYERS:
PRVM_G_FLOAT( OFS_RETURN ) = cache->info.maxplayers;
case SLIF_PROTOCOL:
PRVM_G_FLOAT( OFS_RETURN ) = cache->info.protocol;
break;
+ case SLIF_CATEGORY:
+ PRVM_G_FLOAT( OFS_RETURN ) = cache->info.category;
+ break;
case SLIF_ISFAVORITE:
PRVM_G_FLOAT( OFS_RETURN ) = cache->info.isfavorite;
break;
PRVM_G_FLOAT( OFS_RETURN ) = SLIF_FREESLOTS;
else if( !strcmp( key, "protocol" ) )
PRVM_G_FLOAT( OFS_RETURN ) = SLIF_PROTOCOL;
+ else if( !strcmp( key, "category" ) )
+ PRVM_G_FLOAT( OFS_RETURN ) = SLIF_CATEGORY;
else if( !strcmp( key, "isfavorite" ) )
PRVM_G_FLOAT( OFS_RETURN ) = SLIF_ISFAVORITE;
else
{0, NULL, NULL, NULL}
};
+#ifdef CONFIG_MENU
static cvar_t sv_qwmasters [] =
{
{CVAR_SAVE, "sv_qwmaster1", "", "user-chosen qwmaster server 1"},
{0, "sv_qwmasterextra5", "qwmaster.fodquake.net:27000", "Global master server. (admin: unknown)"},
{0, NULL, NULL, NULL}
};
+#endif
static double nextheartbeattime = 0;
challenge_t challenge[MAX_CHALLENGES];
+#ifdef CONFIG_MENU
/// this is only false if there are still servers left to query
static qboolean serverlist_querysleep = true;
static qboolean serverlist_paused = false;
/// reply is received, to avoid issuing queries while master replies are still
/// flooding in (which would make a mess of the ping times)
static double serverlist_querywaittime = 0;
+#endif
static int cl_numsockets;
static lhnetsocket_t *cl_sockets[16];
int sv_net_extresponse_count = 0;
int sv_net_extresponse_last = 0;
+#ifdef CONFIG_MENU
// ServerList interface
serverlist_mask_t serverlist_andmasks[SERVERLIST_ANDMASKCOUNT];
serverlist_mask_t serverlist_ormasks[SERVERLIST_ORMASKCOUNT];
{
int result = 0; // > 0 if for numbers A > B and for text if A < B
- if( serverlist_sortflags & SLSF_FAVORITESFIRST )
+ if( serverlist_sortflags & SLSF_CATEGORIES )
+ {
+ result = A->info.category - B->info.category;
+ if (result != 0)
+ return result < 0;
+ }
+
+ if( serverlist_sortflags & SLSF_FAVORITES )
{
if(A->info.isfavorite != B->info.isfavorite)
return A->info.isfavorite;
}
-
+
switch( serverlist_sortbyfield ) {
case SLIF_PING:
result = A->info.ping - B->info.ping;
case SLIF_QCSTATUS:
result = strcasecmp( B->info.qcstatus, A->info.qcstatus ); // not really THAT useful, though
break;
+ case SLIF_CATEGORY:
+ result = A->info.category - B->info.category;
+ break;
case SLIF_ISFAVORITE:
result = !!B->info.isfavorite - !!A->info.isfavorite;
break;
if( *mask->info.players
&& !_ServerList_CompareStr( info->players, mask->tests[SLIF_PLAYERS], mask->info.players ) )
return false;
+ if( !_ServerList_CompareInt( info->category, mask->tests[SLIF_CATEGORY], mask->info.category ) )
+ return false;
if( !_ServerList_CompareInt( info->isfavorite, mask->tests[SLIF_ISFAVORITE], mask->info.isfavorite ))
return false;
return true;
}
}
+ // refresh the "category"
+ entry->info.category = MR_GetServerListEntryCategory(entry);
+
// FIXME: change this to be more readable (...)
// now check whether it passes through the masks
for( start = 0 ; start < SERVERLIST_ANDMASKCOUNT && serverlist_andmasks[start].active; start++ )
NetConn_QueryMasters(querydp, queryqw);
}
+#endif
// rest
return false;
}
+#ifdef CONFIG_MENU
static int NetConn_ClientParsePacket_ServerList_ProcessReply(const char *addressstring)
{
int n;
serverlist_querysleep = false;
serverlist_querywaittime = realtime + 3;
}
+#endif
static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *data, int length, lhnetaddress_t *peeraddress)
{
qboolean fromserver;
int ret, c;
- const char *s;
- char *string, addressstring2[128], ipstring[32];
+ char *string, addressstring2[128];
char stringbuf[16384];
char senddata[NET_HEADERSIZE+NET_MAXMESSAGE+CRYPTO_HEADERSIZE];
size_t sendlength;
+#ifdef CONFIG_MENU
char infostringvalue[MAX_INPUTLINE];
+ char ipstring[32];
+ const char *s;
+#endif
char vabuf[1024];
// quakeworld ingame packet
#endif
return true;
}
+#ifdef CONFIG_MENU
if (length >= 15 && !memcmp(string, "statusResponse\x0A", 15))
{
serverlist_info_t *info;
serverlist_querywaittime = realtime + 3;
return true;
}
+#endif
if (!strncmp(string, "extResponse ", 12))
{
++cl_net_extresponse_count;
}
if (length > 2 && !memcmp(string, "n\\", 2))
{
+#ifdef CONFIG_MENU
serverlist_info_t *info;
int n;
}
NetConn_ClientParsePacket_ServerList_UpdateCache(n);
-
+#endif
return true;
}
if (string[0] == 'n')
// netquake control packets, supported for compatibility only
if (length >= 5 && BuffBigLong(data) == ((int)NETFLAG_CTL | length) && !ENCRYPTION_REQUIRED)
{
+#ifdef CONFIG_MENU
int n;
serverlist_info_t *info;
+#endif
data += 4;
length -= 4;
case CCREP_SERVER_INFO:
if (developer_extra.integer)
Con_DPrintf("Datagram_ParseConnectionless: received CCREP_SERVER_INFO from %s.\n", addressstring2);
+#ifdef CONFIG_MENU
// LordHavoc: because the quake server may report weird addresses
// we just ignore it and keep the real address
MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
info->protocol = MSG_ReadByte(&cl_message);
NetConn_ClientParsePacket_ServerList_UpdateCache(n);
-
+#endif
break;
case CCREP_RCON: // RocketGuy: ProQuake rcon support
if (developer_extra.integer)
return ret;
}
+#ifdef CONFIG_MENU
void NetConn_QueryQueueFrame(void)
{
int index;
}
}
}
+#endif
void NetConn_ClientFrame(void)
{
// R_TimeReport("clientparsepacket");
}
}
+#ifdef CONFIG_MENU
NetConn_QueryQueueFrame();
+#endif
if (cls.netcon && realtime > cls.netcon->timeout && !sv.active)
{
Con_Print("Connection timed out\n");
LHNET_SleepUntilPacket_Microseconds(microseconds);
}
+#ifdef CONFIG_MENU
void NetConn_QueryMasters(qboolean querydp, qboolean queryqw)
{
int i, j;
{
if (sv_qwmasters[masternum].string && LHNETADDRESS_FromString(&masteraddress, sv_qwmasters[masternum].string, QWMASTER_PORT) && LHNETADDRESS_GetAddressType(&masteraddress) == LHNETADDRESS_GetAddressType(LHNET_AddressFromSocket(cl_sockets[i])))
{
-#ifdef CONFIG_MENU
if (m_state != m_slist)
{
-#endif
char lookupstring[128];
LHNETADDRESS_ToString(&masteraddress, lookupstring, sizeof(lookupstring), true);
Con_Printf("Querying master %s (resolved from %s)\n", lookupstring, sv_qwmasters[masternum].string);
-#ifdef CONFIG_MENU
}
-#endif
masterquerycount++;
NetConn_Write(cl_sockets[i], request, (int)strlen(request) + 1, &masteraddress);
}
if (!masterquerycount)
{
Con_Print("Unable to query master servers, no suitable network sockets active.\n");
-#ifdef CONFIG_MENU
M_Update_Return_Reason("No network");
-#endif
}
}
+#endif
void NetConn_Heartbeat(int priority)
{
PrintStats(conn);
}
+#ifdef CONFIG_MENU
void Net_Refresh_f(void)
{
-#ifdef CONFIG_MENU
if (m_state != m_slist) {
-#endif
Con_Print("Sending new requests to master servers\n");
ServerList_QueryList(false, true, false, true);
Con_Print("Listening for replies...\n");
-#ifdef CONFIG_MENU
} else
ServerList_QueryList(false, true, false, false);
-#endif
}
void Net_Slist_f(void)
ServerList_ResetMasks();
serverlist_sortbyfield = SLIF_PING;
serverlist_sortflags = 0;
-#ifdef CONFIG_MENU
if (m_state != m_slist) {
-#endif
Con_Print("Sending requests to master servers\n");
ServerList_QueryList(true, true, false, true);
Con_Print("Listening for replies...\n");
-#ifdef CONFIG_MENU
} else
ServerList_QueryList(true, true, false, false);
-#endif
}
void Net_SlistQW_f(void)
ServerList_ResetMasks();
serverlist_sortbyfield = SLIF_PING;
serverlist_sortflags = 0;
-#ifdef CONFIG_MENU
if (m_state != m_slist) {
-#endif
Con_Print("Sending requests to master servers\n");
ServerList_QueryList(true, false, true, true);
serverlist_consoleoutput = true;
Con_Print("Listening for replies...\n");
-#ifdef CONFIG_MENU
} else
ServerList_QueryList(true, false, true, false);
-#endif
}
+#endif
void NetConn_Init(void)
{
lhnetaddress_t tempaddress;
netconn_mempool = Mem_AllocPool("network connections", 0, NULL);
Cmd_AddCommand("net_stats", Net_Stats_f, "print network statistics");
+#ifdef CONFIG_MENU
Cmd_AddCommand("net_slist", Net_Slist_f, "query dp master servers and print all server information");
Cmd_AddCommand("net_slistqw", Net_SlistQW_f, "query qw master servers and print all server information");
Cmd_AddCommand("net_refresh", Net_Refresh_f, "query dp master servers and refresh all server information");
+#endif
Cmd_AddCommand("heartbeat", Net_Heartbeat_f, "send a heartbeat to the master server (updates your server information)");
Cvar_RegisterVariable(&net_test);
Cvar_RegisterVariable(&net_usesizelimit);
extern cvar_t hostname;
extern cvar_t developer_networking;
+#ifdef CONFIG_MENU
#define SERVERLIST_VIEWLISTSIZE SERVERLIST_TOTALSIZE
typedef enum serverlist_maskop_e
/// (an integer that is used for filtering incompatible servers,
/// not filterable by QC)
int gameversion;
+
+ // categorized sorting
+ int category;
/// favorite server flag
qboolean isfavorite;
} serverlist_info_t;
SLIF_FREESLOTS,
SLIF_QCSTATUS,
SLIF_PLAYERS,
+ SLIF_CATEGORY,
SLIF_ISFAVORITE,
SLIF_COUNT
} serverlist_infofield_t;
typedef enum
{
SLSF_DESCENDING = 1,
- SLSF_FAVORITESFIRST = 2
+ SLSF_FAVORITES = 2,
+ SLSF_CATEGORIES = 4
} serverlist_sortflags_t;
typedef enum
extern int serverlist_cachecount;
extern serverlist_entry_t *serverlist_cache;
+extern const serverlist_entry_t *serverlist_callbackentry;
extern qboolean serverlist_consoleoutput;
void ServerList_GetPlayerStatistics(int *numplayerspointer, int *maxplayerspointer);
+#endif
//============================================================================
//
extern int sv_net_extresponse_count;
extern int sv_net_extresponse_last;
+#ifdef CONFIG_MENU
extern double masterquerytime;
extern int masterquerycount;
extern int masterreplycount;
extern int serverquerycount;
extern int serverreplycount;
+#endif
extern sizebuf_t cl_message;
extern sizebuf_t sv_message;
void NetConn_ClientFrame(void);
void NetConn_ServerFrame(void);
void NetConn_SleepMicroseconds(int microseconds);
-void NetConn_QueryMasters(qboolean querydp, qboolean queryqw);
void NetConn_Heartbeat(int priority);
-void NetConn_QueryQueueFrame(void);
void Net_Stats_f(void);
+
+#ifdef CONFIG_MENU
+void NetConn_QueryMasters(qboolean querydp, qboolean queryqw);
+void NetConn_QueryQueueFrame(void);
void Net_Slist_f(void);
void Net_SlistQW_f(void);
void Net_Refresh_f(void);
/// called whenever net_slist_favorites changes
void NetConn_UpdateFavorites(void);
+#endif
#define MAX_CHALLENGES 128
typedef struct challenge_s