Prevent FTE servers from getting mistreated as NQ servers, this should restore the 'observe' option.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6294 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2022-07-28 02:17:27 +00:00
parent ce8155f8a1
commit 62e8bb5774
11 changed files with 146 additions and 67 deletions

View file

@ -493,7 +493,7 @@ void CL_ConnectToDarkPlaces(char *challenge, netadr_t *adr)
connectinfo.time = realtime; // for retransmit requests connectinfo.time = realtime; // for retransmit requests
Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP2 NEHAHRABJP NEHAHRABJP3 QUAKE\\challenge\\%s\\name\\%s", 255, 255, 255, 255, challenge, name.string); Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces "STRINGIFY(NQ_NETCHAN_VERSION)"\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP2 NEHAHRABJP NEHAHRABJP3 QUAKE\\challenge\\%s\\name\\%s", 255, 255, 255, 255, challenge, name.string);
NET_SendPacket (cls.sockets, strlen(data), data, adr); NET_SendPacket (cls.sockets, strlen(data), data, adr);
@ -1160,7 +1160,7 @@ void CL_CheckForResend (void)
else if (1) else if (1)
{ {
net_from = connectinfo.adr[connectinfo.nextadr]; net_from = connectinfo.adr[connectinfo.nextadr];
Q_snprintfz(net_message.data, net_message.maxsize, "xxxxconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP2 NEHAHRABJP NEHAHRABJP3 QUAKE\\challenge\\0x%x\\name\\%s", SV_NewChallenge(), name.string); Q_snprintfz(net_message.data, net_message.maxsize, "xxxxconnect\\protocol\\darkplaces "STRINGIFY(NQ_NETCHAN_VERSION)"\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP2 NEHAHRABJP NEHAHRABJP3 QUAKE\\challenge\\0x%x\\name\\%s", SV_NewChallenge(), name.string);
Cmd_TokenizeString (net_message.data+4, false, false); Cmd_TokenizeString (net_message.data+4, false, false);
SVC_DirectConnect(0); SVC_DirectConnect(0);
} }

View file

@ -22,17 +22,18 @@ enum masterprotocol_e
#define SS_UNKNOWN 0 #define SS_UNKNOWN 0
#define SS_QUAKEWORLD 1 #define SS_QUAKEWORLD 1
#define SS_NETQUAKE 2 #define SS_NETQUAKE 2
#define SS_DARKPLACES 3 #define SS_QUAKE2 3
#define SS_QUAKE2 4 #define SS_QUAKE3 4
#define SS_QUAKE3 5 #define SS_QEPROT 5 //needs dtls and a different ccreq version
//#define SS_UNUSED 6 //#define SS_UNUSED 6
//#define SS_UNUSED 7 //#define SS_UNUSED 7
#define SS_LOCAL (1<<3u) //local servers are ones we detected without being listed on a master server (masters will report public ips, so these may appear as dupes if they're also public) #define SS_LOCAL (1<<3u) //local servers are ones we detected without being listed on a master server (masters will report public ips, so these may appear as dupes if they're also public)
#define SS_FTESERVER (1<<4u) //hehehe... #define SS_FTESERVER (1<<4u) //just highlighting differences, to give some impression of superiority.
#define SS_FAVORITE (1<<5u) //filter all others. #define SS_FAVORITE (1<<5u) //filter all others.
#define SS_KEEPINFO (1<<6u) #define SS_KEEPINFO (1<<6u)
#define SS_PROXY (1<<7u) #define SS_GETINFO (1<<7u) //explicitly query via getinfo
#define SS_PROXY (1<<8u) //qizmo/qwfwd/qtv/eztv
#define PING_DEAD 0xffff //default ping value to denote servers that are not responding. #define PING_DEAD 0xffff //default ping value to denote servers that are not responding.
#define PING_UNKNOWN 0xfffe //these servers are considered up, but we can't query them directly so can't determine the final ping from here. #define PING_UNKNOWN 0xfffe //these servers are considered up, but we can't query them directly so can't determine the final ping from here.

View file

@ -145,7 +145,7 @@ static void SL_TitlesDraw (int x, int y, menucustom_t *ths, emenu_t *menu)
else else
clr = 'B'; clr = 'B';
x = ths->common.width; x = ths->common.width;
if (mx > x || mousecursor_y < y || mousecursor_y >= y+8) if ((mx > x || mousecursor_y < y || mousecursor_y >= y+8) && !serverpreview)
filldraw = true; filldraw = true;
if (sb_showtimelimit.value) {SL_DrawColumnTitle(&x, y, 3*8, mx, "tl", (sf==SLKEY_TIMELIMIT), clr, &filldraw);} if (sb_showtimelimit.value) {SL_DrawColumnTitle(&x, y, 3*8, mx, "tl", (sf==SLKEY_TIMELIMIT), clr, &filldraw);}
if (sb_showfraglimit.value) {SL_DrawColumnTitle(&x, y, 3*8, mx, "fl", (sf==SLKEY_FRAGLIMIT), clr, &filldraw);} if (sb_showfraglimit.value) {SL_DrawColumnTitle(&x, y, 3*8, mx, "fl", (sf==SLKEY_FRAGLIMIT), clr, &filldraw);}
@ -268,8 +268,9 @@ static servertypes_t flagstoservertype(int flags)
switch(flags & SS_PROTOCOLMASK) switch(flags & SS_PROTOCOLMASK)
{ {
case SS_QEPROT:
return ST_NETQUAKE;
case SS_NETQUAKE: case SS_NETQUAKE:
case SS_DARKPLACES:
return ST_NETQUAKE; return ST_NETQUAKE;
case SS_QUAKE2: case SS_QUAKE2:
return ST_QUAKE2; return ST_QUAKE2;
@ -308,7 +309,7 @@ static void SL_ServerDraw (int x, int y, menucustom_t *ths, emenu_t *menu)
serverhighlight[(int)stype][2], serverhighlight[(int)stype][2],
1.0)); 1.0));
} }
else if (thisone == info->scrollpos + (int)(mousecursor_y-info->servers_top)/8 && mousecursor_x < x) else if (thisone == info->scrollpos + (int)(mousecursor_y-info->servers_top)/8 && mousecursor_x < x && !serverpreview)
R2D_ImageColours(SRGBA((sin(realtime*4.4)*0.25)+0.5, (sin(realtime*4.4)*0.25)+0.5, 0.08, sb_alpha.value)); R2D_ImageColours(SRGBA((sin(realtime*4.4)*0.25)+0.5, (sin(realtime*4.4)*0.25)+0.5, 0.08, sb_alpha.value));
else if (selectedserver.inuse && NET_CompareAdr(&si->adr, &selectedserver.adr) && !strcmp(si->brokerid, selectedserver.brokerid)) else if (selectedserver.inuse && NET_CompareAdr(&si->adr, &selectedserver.adr) && !strcmp(si->brokerid, selectedserver.brokerid))
R2D_ImageColours(SRGBA(((sin(realtime*4.4)*0.25)+0.5) * 0.5, ((sin(realtime*4.4)*0.25)+0.5)*0.5, 0.08*0.5, sb_alpha.value)); R2D_ImageColours(SRGBA(((sin(realtime*4.4)*0.25)+0.5) * 0.5, ((sin(realtime*4.4)*0.25)+0.5)*0.5, 0.08*0.5, sb_alpha.value));
@ -852,9 +853,11 @@ dojoin:
} }
//which connect command are we using? //which connect command are we using?
if ((server->special & SS_PROTOCOLMASK) == SS_NETQUAKE) #ifdef NQPROT
Cbuf_AddText("nqconnect ", RESTRICT_LOCAL); if ((server->special & SS_PROTOCOLMASK) == SS_QEPROT)
Cbuf_AddText("connectqe ", RESTRICT_LOCAL);
else else
#endif
Cbuf_AddText("connect ", RESTRICT_LOCAL); Cbuf_AddText("connect ", RESTRICT_LOCAL);
//output the server's address //output the server's address
@ -1108,7 +1111,6 @@ static void CalcFilters(emenu_t *menu)
else else
{ {
if (info->filter[SLFILTER_HIDENETQUAKE]) Master_SetMaskInteger(false, SLKEY_BASEGAME, SS_NETQUAKE, SLIST_TEST_NOTEQUAL); if (info->filter[SLFILTER_HIDENETQUAKE]) Master_SetMaskInteger(false, SLKEY_BASEGAME, SS_NETQUAKE, SLIST_TEST_NOTEQUAL);
if (info->filter[SLFILTER_HIDENETQUAKE]) Master_SetMaskInteger(false, SLKEY_BASEGAME, SS_DARKPLACES, SLIST_TEST_NOTEQUAL);
if (info->filter[SLFILTER_HIDEQUAKEWORLD]) Master_SetMaskInteger(false, SLKEY_BASEGAME, SS_QUAKEWORLD, SLIST_TEST_NOTEQUAL); if (info->filter[SLFILTER_HIDEQUAKEWORLD]) Master_SetMaskInteger(false, SLKEY_BASEGAME, SS_QUAKEWORLD, SLIST_TEST_NOTEQUAL);
} }
if (info->filter[SLFILTER_HIDEPROXIES]) Master_SetMaskInteger(false, SLKEY_FLAGS, SS_PROXY, SLIST_TEST_NOTCONTAIN); if (info->filter[SLFILTER_HIDEPROXIES]) Master_SetMaskInteger(false, SLKEY_FLAGS, SS_PROXY, SLIST_TEST_NOTCONTAIN);
@ -1351,9 +1353,11 @@ static void M_QuickConnect_PreDraw(emenu_t *menu)
{ {
Con_Printf("Quick connect found %s (gamedir %s, players %i/%i/%i, ping %ims)\n", best->name, best->gamedir, best->numhumans, best->players, best->maxplayers, best->ping); Con_Printf("Quick connect found %s (gamedir %s, players %i/%i/%i, ping %ims)\n", best->name, best->gamedir, best->numhumans, best->players, best->maxplayers, best->ping);
if ((best->special & SS_PROTOCOLMASK) == SS_NETQUAKE) #ifdef NQPROT
Cbuf_AddText(va("nqconnect %s\n", Master_ServerToString(adr, sizeof(adr), best)), RESTRICT_LOCAL); if ((best->special & SS_PROTOCOLMASK) == SS_QEPROT)
Cbuf_AddText(va("connectqe %s\n", Master_ServerToString(adr, sizeof(adr), best)), RESTRICT_LOCAL);
else else
#endif
Cbuf_AddText(va("join %s\n", Master_ServerToString(adr, sizeof(adr), best)), RESTRICT_LOCAL); Cbuf_AddText(va("join %s\n", Master_ServerToString(adr, sizeof(adr), best)), RESTRICT_LOCAL);
M_ToggleMenu_f(); M_ToggleMenu_f();

View file

@ -1039,8 +1039,6 @@ char *Master_ServerToString (char *s, int len, serverinfo_t *a)
static int Master_BaseGame(serverinfo_t *a) static int Master_BaseGame(serverinfo_t *a)
{ {
int prot = a->special&SS_PROTOCOLMASK; int prot = a->special&SS_PROTOCOLMASK;
if (prot == SS_DARKPLACES && (a->special&SS_FTESERVER))
prot = SS_QUAKEWORLD;
return prot; return prot;
} }
@ -2256,32 +2254,32 @@ void Master_CheckPollSockets(void)
continue; continue;
} }
#endif #endif
#ifdef Q3CLIENT //#ifdef Q3CLIENT
if (!strcmp(s, "statusResponse")) if (!strcmp(s, "statusResponse"))
{ {
CL_ReadServerInfo(MSG_ReadString(), MP_QUAKE3, false); CL_ReadServerInfo(MSG_ReadString(), MP_QUAKE3, false);
continue; continue;
} }
#endif //#endif
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (!strncmp(s, "getserversResponse6", 19) && (s[19] == '\\' || s[19] == '/')) //parse a bit more... if (!strncmp(s, "getserversResponse6", 19) && (s[19] == '\\' || s[19] == '/')) //parse a bit more...
{ {
net_message.currentbit = (c+19-1)<<3; net_message.currentbit = (c+19-1)<<3;
CL_MasterListParse(NA_IPV6, SS_DARKPLACES, true); CL_MasterListParse(NA_IPV6, SS_GETINFO, true);
continue; continue;
} }
#endif #endif
if (!strncmp(s, "getserversExtResponse", 21) && (s[21] == '\\' || s[21] == '/')) //parse a bit more... if (!strncmp(s, "getserversExtResponse", 21) && (s[21] == '\\' || s[21] == '/')) //parse a bit more...
{ {
net_message.currentbit = (c+21-1)<<3; net_message.currentbit = (c+21-1)<<3;
CL_MasterListParse(NA_IP, SS_DARKPLACES, true); CL_MasterListParse(NA_IP, SS_GETINFO, true);
continue; continue;
} }
if (!strncmp(s, "getserversResponse", 18) && (s[18] == '\\' || s[18] == '/')) //parse a bit more... if (!strncmp(s, "getserversResponse", 18) && (s[18] == '\\' || s[18] == '/')) //parse a bit more...
{ {
net_message.currentbit = (c+18-1)<<3; net_message.currentbit = (c+18-1)<<3;
CL_MasterListParse(NA_IP, SS_DARKPLACES, true); CL_MasterListParse(NA_IP, SS_GETINFO, true);
continue; continue;
} }
if (!strcmp(s, "infoResponse")) //parse a bit more... if (!strcmp(s, "infoResponse")) //parse a bit more...
@ -2495,7 +2493,7 @@ void SListOptionChanged(serverinfo_t *newserver)
#if defined(NQPROT) #if defined(NQPROT)
selectedserver.lastplayer = 0; selectedserver.lastplayer = 0;
*selectedserver.lastrule = 0; *selectedserver.lastrule = 0;
if ((newserver->special&SS_PROTOCOLMASK) == SS_NETQUAKE) if ((newserver->special&(SS_PROTOCOLMASK|SS_GETINFO)) == SS_NETQUAKE)
{ //start spamming the server to get all of its details. silly protocols. { //start spamming the server to get all of its details. silly protocols.
SZ_Clear(&net_message); SZ_Clear(&net_message);
net_message.packing = SZ_RAWBYTES; net_message.packing = SZ_RAWBYTES;
@ -2646,7 +2644,7 @@ static void MasterInfo_ProcessHTTP(struct dl_download *dl)
if (protocoltype == MP_QUAKEWORLD) if (protocoltype == MP_QUAKEWORLD)
info->special |= SS_QUAKEWORLD; info->special |= SS_QUAKEWORLD;
else if (protocoltype == MP_DPMASTER) else if (protocoltype == MP_DPMASTER)
info->special |= SS_DARKPLACES; info->special |= SS_GETINFO;
#if defined(Q2CLIENT) || defined(Q2SERVER) #if defined(Q2CLIENT) || defined(Q2SERVER)
else if (protocoltype == MP_QUAKE2) else if (protocoltype == MP_QUAKE2)
info->special |= SS_QUAKE2; info->special |= SS_QUAKE2;
@ -2925,16 +2923,17 @@ void Master_QueryServer(serverinfo_t *server)
return; //don't even try. we have no direct route. return; //don't even try. we have no direct route.
server->refreshtime = Sys_DoubleTime(); server->refreshtime = Sys_DoubleTime();
switch(server->special & SS_PROTOCOLMASK) if (server->special & SS_GETINFO)
{ {
case SS_QUAKE3:
Q_snprintfz(data, sizeof(data), "%c%c%c%cgetstatus", 255, 255, 255, 255);
break;
case SS_DARKPLACES:
if (server->moreinfo) if (server->moreinfo)
Q_snprintfz(data, sizeof(data), "%c%c%c%cgetstatus", 255, 255, 255, 255); Q_snprintfz(data, sizeof(data), "%c%c%c%cgetstatus", 255, 255, 255, 255);
else else
Q_snprintfz(data, sizeof(data), "%c%c%c%cgetinfo", 255, 255, 255, 255); Q_snprintfz(data, sizeof(data), "%c%c%c%cgetinfo", 255, 255, 255, 255);
}
else switch(server->special & SS_PROTOCOLMASK)
{
case SS_QUAKE3:
Q_snprintfz(data, sizeof(data), "%c%c%c%cgetstatus", 255, 255, 255, 255);
break; break;
#ifdef NQPROT #ifdef NQPROT
case SS_NETQUAKE: case SS_NETQUAKE:
@ -3028,14 +3027,13 @@ qboolean CL_QueryServers(void)
while(server) while(server)
{ {
qboolean enabled; qboolean enabled;
switch(server->special & SS_PROTOCOLMASK) switch(Master_BaseGame(server))
{ {
case SS_UNKNOWN: enabled = true; break; case SS_UNKNOWN: enabled = true; break;
case SS_QUAKE3: enabled = sb_enablequake3; break; case SS_QUAKE3: enabled = sb_enablequake3; break;
case SS_QUAKE2: enabled = sb_enablequake2; break; case SS_QUAKE2: enabled = sb_enablequake2; break;
case SS_NETQUAKE: enabled = sb_enablenetquake; break; case SS_NETQUAKE: enabled = sb_enablenetquake; break;
case SS_QUAKEWORLD: enabled = sb_enablequakeworld; break; case SS_QUAKEWORLD: enabled = sb_enablequakeworld; break;
case SS_DARKPLACES: enabled = sb_enabledarkplaces; break;
default: enabled = false; break; default: enabled = false; break;
} }
if (enabled) if (enabled)
@ -3057,14 +3055,13 @@ qboolean CL_QueryServers(void)
while (server) while (server)
{ {
qboolean enabled; qboolean enabled;
switch(server->special & SS_PROTOCOLMASK) switch(Master_BaseGame(server))
{ {
case SS_UNKNOWN: enabled = true; break; case SS_UNKNOWN: enabled = true; break;
case SS_QUAKE3: enabled = sb_enablequake3; break; case SS_QUAKE3: enabled = sb_enablequake3; break;
case SS_QUAKE2: enabled = sb_enablequake2; break; case SS_QUAKE2: enabled = sb_enablequake2; break;
case SS_NETQUAKE: enabled = sb_enablenetquake; break; case SS_NETQUAKE: enabled = sb_enablenetquake; break;
case SS_QUAKEWORLD: enabled = sb_enablequakeworld; break; case SS_QUAKEWORLD: enabled = sb_enablequakeworld; break;
case SS_DARKPLACES: enabled = sb_enabledarkplaces; break;
default: enabled = false; break; default: enabled = false; break;
} }
if (enabled) if (enabled)
@ -3241,38 +3238,54 @@ static int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolea
if (!*name) if (!*name)
name = Info_ValueForKey(msg, "sv_hostname"); name = Info_ValueForKey(msg, "sv_hostname");
Q_strncpyz(info->name, name, sizeof(info->name)); Q_strncpyz(info->name, name, sizeof(info->name));
info->special = info->special & (SS_FAVORITE | SS_KEEPINFO | SS_LOCAL); //favorite+local is never cleared info->special = info->special & (SS_FAVORITE | SS_KEEPINFO | SS_LOCAL | SS_GETINFO); //favorite+local is never cleared
if (!strcmp(DISTRIBUTION, Info_ValueForKey(msg, "*distrib"))) //outdated if (!strcmp(DISTRIBUTION, Info_ValueForKey(msg, "*distrib"))) //outdated
info->special |= SS_FTESERVER; info->special |= SS_FTESERVER;
else if (!strncmp(DISTRIBUTION, Info_ValueForKey(msg, "*version"), strlen(DISTRIBUTION))) else if (!strncmp(DISTRIBUTION, Info_ValueForKey(msg, "*version"), strlen(DISTRIBUTION)))
info->special |= SS_FTESERVER; info->special |= SS_FTESERVER;
info->protocol = atoi(Info_ValueForKey(msg, "protocol")); info->protocol = strtoul(Info_ValueForKey(msg, "protocol"), &token, 0);
info->special &= ~SS_PROTOCOLMASK;
if (info->protocol) if (info->protocol)
{ {
switch(info->protocol) switch(info->protocol)
{ {
case PROTOCOL_VERSION_QW: info->special = SS_QUAKEWORLD; break; case PROTOCOL_VERSION_QW: info->special |= SS_QUAKEWORLD; break;
#ifdef NQPROT #ifdef NQPROT
case PROTOCOL_VERSION_NQ: info->special = SS_NETQUAKE; break; case PROTOCOL_VERSION_NQ: info->special |= SS_NETQUAKE; break;
case PROTOCOL_VERSION_H2: info->special = SS_NETQUAKE; break; //erk case PROTOCOL_VERSION_H2: info->special |= SS_NETQUAKE; break; //erk
case PROTOCOL_VERSION_NEHD: info->special = SS_NETQUAKE; break; case PROTOCOL_VERSION_NEHD: info->special |= SS_NETQUAKE; break;
case PROTOCOL_VERSION_FITZ: 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_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_DP5: info->special |= SS_NETQUAKE; break; //dp actually says 3... but hey, that's dp being WEIRD.
case PROTOCOL_VERSION_DP6: info->special = SS_DARKPLACES; break; case PROTOCOL_VERSION_DP6: info->special |= SS_NETQUAKE; break;
case PROTOCOL_VERSION_DP7: info->special = SS_DARKPLACES; break; case PROTOCOL_VERSION_DP7: info->special |= SS_NETQUAKE; break;
case NQ_NETCHAN_VERSION_QEX:info->special |= SS_QEPROT; break;
case NQ_NETCHAN_VERSION:
#endif #endif
default: default:
while (*token)
{
if (*token == 'w')
info->special |= SS_QUAKEWORLD;
else if (*token == 'n' || *token == 'd')
info->special |= SS_NETQUAKE;
else if (*token == 'x')
info->special |= SS_QEPROT;
else
continue;
break;
}
if ((info->special&SS_PROTOCOLMASK) == SS_UNKNOWN)
{ //guesses...
if (PROTOCOL_VERSION_Q2 >= info->protocol && info->protocol >= PROTOCOL_VERSION_Q2_MIN) if (PROTOCOL_VERSION_Q2 >= info->protocol && info->protocol >= PROTOCOL_VERSION_Q2_MIN)
info->special |= SS_QUAKE2; //q2 has a range! info->special |= SS_QUAKE2; //q2 has a range!
else if (info->protocol > 60) else if (info->protocol > 60)
info->special |= SS_QUAKE3; info->special |= SS_QUAKE3;
else if (!strcmp(Info_ValueForKey(msg, "gamename"), "DarkPlaces-Quake")) else if (!strcmp(Info_ValueForKey(msg, "gamename"), "DarkPlaces-Quake") || *Info_ValueForKey(msg, "nqprotocol"))
info->special |= SS_DARKPLACES; info->special |= SS_NETQUAKE;
else else
info->special |= SS_DARKPLACES|SS_FTESERVER; //so its listed under qw-servers (but queried using dpmaster getinfo stuff). info->special |= SS_QUAKEWORLD;
}
break; break;
} }
} }
@ -3342,7 +3355,7 @@ static int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolea
msg = msg+strlen(msg)+1; msg = msg+strlen(msg)+1;
//clear player info. unless its an NQ server, which have some really annoying protocol to find out the players. //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->special & (SS_PROTOCOLMASK|SS_GETINFO)) == SS_NETQUAKE)
{ {
if (!info->moreinfo && ((slist_cacheinfo.value == 2 || NET_CompareAdr(&info->adr, &selectedserver.adr)) || (info->special & SS_KEEPINFO))) if (!info->moreinfo && ((slist_cacheinfo.value == 2 || NET_CompareAdr(&info->adr, &selectedserver.adr)) || (info->special & SS_KEEPINFO)))
info->moreinfo = Z_Malloc(sizeof(serverdetailedinfo_t)); info->moreinfo = Z_Malloc(sizeof(serverdetailedinfo_t));
@ -3516,7 +3529,7 @@ static int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolea
msg++; msg++;
} }
} }
if ((info->special & SS_PROTOCOLMASK) == SS_DARKPLACES && !info->numbots) if (!info->numbots)
{ {
info->numbots = atoi(Info_ValueForKey(details.info, "bots")); info->numbots = atoi(Info_ValueForKey(details.info, "bots"));
if (info->numbots > info->players) if (info->numbots > info->players)
@ -3624,7 +3637,7 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad)
} }
if ((old = Master_InfoForServer(&info->adr, NULL))) //remove if the server already exists. if ((old = Master_InfoForServer(&info->adr, NULL))) //remove if the server already exists.
{ {
if ((old->special & (SS_PROTOCOLMASK)) != (type & (SS_PROTOCOLMASK))) if ((old->special & (SS_PROTOCOLMASK|SS_GETINFO)) != (type & (SS_PROTOCOLMASK|SS_GETINFO)))
old->special = type | (old->special & (SS_FAVORITE|SS_LOCAL)); old->special = type | (old->special & (SS_FAVORITE|SS_LOCAL));
old->sends = 1; //reset. old->sends = 1; //reset.
old->status |= SRVSTATUS_GLOBAL; old->status |= SRVSTATUS_GLOBAL;

View file

@ -83,7 +83,7 @@ static cvar_t pr_engine = CVARFD("pr_engine",DISTRIBUTION" "STRINGIFY(SVNREVISI
#endif #endif
cvar_t fs_gamename = CVARAD("com_fullgamename", NULL, "fs_gamename", "The filesystem is trying to run this game"); cvar_t fs_gamename = CVARAD("com_fullgamename", NULL, "fs_gamename", "The filesystem is trying to run this game");
cvar_t com_protocolname = CVARAD("com_protocolname", NULL, "com_gamename", "The protocol game name used for dpmaster queries. For compatibility with DP, you can set this to 'DarkPlaces-Quake' in order to be listed in DP's master server, and to list DP servers."); cvar_t com_protocolname = CVARAD("com_protocolname", NULL, "com_gamename", "The protocol game name used for dpmaster queries. For compatibility with DP, you can set this to 'DarkPlaces-Quake' in order to be listed in DP's master server, and to list DP servers.");
cvar_t com_protocolversion = CVARAD("com_protocolversion", "3", NULL, "The protocol version used for dpmaster queries."); //3 by default, for compat with DP/NQ, even if our QW protocol uses different versions entirely. really it only matters for master servers. cvar_t com_protocolversion = CVARAD("com_protocolversion", "3", NULL, "The protocol version used for dpmaster queries."); //3 as strong default for compat with DP which uses its netchan rather than protocol version here, even if our QW protocol uses different versions entirely. really it only matters for master servers.
cvar_t com_parseutf8 = CVARD("com_parseutf8", "1", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed. cvar_t com_parseutf8 = CVARD("com_parseutf8", "1", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed.
cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active."); cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active.");
cvar_t com_gamedirnativecode = CVARFD("com_gamedirnativecode", "0", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger delayed eremote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 1, as well as ensure that you don't run unsafe clients."); cvar_t com_gamedirnativecode = CVARFD("com_gamedirnativecode", "0", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger delayed eremote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 1, as well as ensure that you don't run unsafe clients.");

View file

@ -297,7 +297,7 @@ void Net_Master_Init(void);
void Netchan_Init (void); void Netchan_Init (void);
int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate); int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate);
void Netchan_OutOfBand (netsrc_t sock, netadr_t *adr, int length, qbyte *data); void Netchan_OutOfBand (netsrc_t sock, netadr_t *adr, int length, const qbyte *data);
void VARGS Netchan_OutOfBandPrint (netsrc_t sock, netadr_t *adr, char *format, ...) LIKEPRINTF(3); void VARGS Netchan_OutOfBandPrint (netsrc_t sock, netadr_t *adr, char *format, ...) LIKEPRINTF(3);
void VARGS Netchan_OutOfBandTPrintf (netsrc_t sock, netadr_t *adr, int language, translation_t text, ...); void VARGS Netchan_OutOfBandTPrintf (netsrc_t sock, netadr_t *adr, int language, translation_t text, ...);
qboolean Netchan_Process (netchan_t *chan); qboolean Netchan_Process (netchan_t *chan);

View file

@ -300,7 +300,7 @@ Netchan_OutOfBand
Sends an out-of-band datagram Sends an out-of-band datagram
================ ================
*/ */
void Netchan_OutOfBand (netsrc_t sock, netadr_t *adr, int length, qbyte *data) void Netchan_OutOfBand (netsrc_t sock, netadr_t *adr, int length, const qbyte *data)
{ {
sizebuf_t send; sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN + PACKET_HEADER]; qbyte send_buf[MAX_QWMSGLEN + PACKET_HEADER];

View file

@ -4349,7 +4349,7 @@ static void FTENET_ICE_Heartbeat(ftenet_ice_connection_t *b)
} }
*info = 0; *info = 0;
Info_SetValueForKey(info, "protocol", com_protocolversion.string, sizeof(info)); Info_SetValueForKey(info, "protocol", SV_GetProtocolVersionString(), sizeof(info));
Info_SetValueForKey(info, "maxclients", maxclients.string, sizeof(info)); Info_SetValueForKey(info, "maxclients", maxclients.string, sizeof(info));
Info_SetValueForKey(info, "clients", va("%i", numclients), sizeof(info)); Info_SetValueForKey(info, "clients", va("%i", numclients), sizeof(info));
Info_SetValueForKey(info, "hostname", hostname.string, sizeof(info)); Info_SetValueForKey(info, "hostname", hostname.string, sizeof(info));

View file

@ -7185,7 +7185,7 @@ static void FTENET_WebRTC_Heartbeat(ftenet_websocket_connection_t *b)
info[1] = info[1] =
info[2] = 0xff; //to the broker rather than any actual client info[2] = 0xff; //to the broker rather than any actual client
info[3] = 0; info[3] = 0;
Info_SetValueForKey(info+3, "protocol", com_protocolversion.string, sizeof(info)-3); Info_SetValueForKey(info+3, "protocol", SV_GetProtocolVersionString(), sizeof(info)-3);
Info_SetValueForKey(info+3, "maxclients", maxclients.string, sizeof(info)-3); Info_SetValueForKey(info+3, "maxclients", maxclients.string, sizeof(info)-3);
Info_SetValueForKey(info+3, "clients", va("%i", numclients), sizeof(info)-3); Info_SetValueForKey(info+3, "clients", va("%i", numclients), sizeof(info)-3);
Info_SetValueForKey(info+3, "hostname", hostname.string, sizeof(info)-3); Info_SetValueForKey(info+3, "hostname", hostname.string, sizeof(info)-3);

View file

@ -1157,6 +1157,7 @@ int SV_CalcPing (client_t *cl, qboolean forcecalc);
void SV_FullClientUpdate (client_t *client, client_t *to); void SV_FullClientUpdate (client_t *client, client_t *to);
char *SV_PlayerPublicAddress(client_t *cl); char *SV_PlayerPublicAddress(client_t *cl);
const char *SV_GetProtocolVersionString(void); //decorate the protocol version field of server queries with extra features...
qboolean SVC_GetChallenge (qboolean respond_dp); qboolean SVC_GetChallenge (qboolean respond_dp);
int SV_NewChallenge (void); int SV_NewChallenge (void);
void SVC_DirectConnect(int expectedreliablesequence); void SVC_DirectConnect(int expectedreliablesequence);

View file

@ -1227,6 +1227,36 @@ static void SVC_Status (void)
} }
#if 1//def NQPROT #if 1//def NQPROT
const char *SV_GetProtocolVersionString(void)
{
char *ret = va("%i", com_protocolversion.ival); //for compat with DP, this is basically locked at 3. our pexts allow this to be mostly graceful.
switch(svs.gametype)
{
case GT_PROGS:
case GT_Q1QVM:
if (sv_listen_qw.ival)
Q_strncatz(ret, "w", 64);
#ifdef NQPROT
if (progstype == PROG_H2)
break; //don't advertise nq protocols when they're blocked.
if (sv_listen_nq.ival)
{
Q_strncatz(ret, "n", 64);
#ifdef HAVE_DTLS
if (*dtls_psk_user.string)
Q_strncatz(ret, "x", 64);
#endif
}
if (sv_listen_dp.ival)
Q_strncatz(ret, "d", 64);
#endif
break;
default:
break; //these do their own thing, with their own protocols. don't be weird.
}
return ret;
}
static void SVC_GetInfo (const char *challenge, int fullstatus) static void SVC_GetInfo (const char *challenge, int fullstatus)
{ {
//dpmaster support //dpmaster support
@ -1289,7 +1319,7 @@ static void SVC_GetInfo (const char *challenge, int fullstatus)
*resp = 0; *resp = 0;
Info_SetValueForKey(resp, "challenge", challenge, sizeof(response) - (resp-response)); //the challenge can be important for the master protocol to prevent poisoning Info_SetValueForKey(resp, "challenge", challenge, sizeof(response) - (resp-response)); //the challenge can be important for the master protocol to prevent poisoning
Info_SetValueForKey(resp, "gamename", protocolname, sizeof(response) - (resp-response));//distinguishes it from other types of games Info_SetValueForKey(resp, "gamename", protocolname, sizeof(response) - (resp-response));//distinguishes it from other types of games
Info_SetValueForKey(resp, "protocol", com_protocolversion.string, sizeof(response) - (resp-response)); //should be an int. Info_SetValueForKey(resp, "protocol", SV_GetProtocolVersionString(), sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "modname", FS_GetGamedir(true), sizeof(response) - (resp-response)); Info_SetValueForKey(resp, "modname", FS_GetGamedir(true), sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "clients", va("%d", numclients), sizeof(response) - (resp-response)); Info_SetValueForKey(resp, "clients", va("%d", numclients), sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "sv_maxclients", maxclients.string, sizeof(response) - (resp-response)); Info_SetValueForKey(resp, "sv_maxclients", maxclients.string, sizeof(response) - (resp-response));
@ -1549,6 +1579,33 @@ qboolean SVC_GetChallenge (qboolean respond_dp)
const qboolean respond_qwoverq3 = false; const qboolean respond_qwoverq3 = false;
#endif #endif
//ioq3clchallenge = atoi(Cmd_Argv(1));
const char *protocols = Cmd_Argv(2);
if (*protocols)
{
const char *pname;
char tprot[64], oprot[64];
while ((protocols=COM_ParseOut(protocols, tprot,sizeof(tprot))))
{
pname = com_protocolname.string;
while ((pname=COM_ParseOut(pname, oprot,sizeof(oprot))))
{
if (!strcmp(tprot, oprot))
break;
}
if (pname)
break;
}
if (!protocols)
{
COM_ParseOut(com_protocolname.string, oprot,sizeof(oprot));
pname = va("print\nGame mismatch: This is a %s server\n", oprot);
Netchan_OutOfBand(NS_SERVER, &net_from, strlen(pname), pname);
return false;
}
}
if (sv_listen_qw.value && !sv_listen_dp.value) if (sv_listen_qw.value && !sv_listen_dp.value)
{ {
respond_std = true; respond_std = true;
@ -3318,7 +3375,7 @@ void SVC_DirectConnect(int expectedreliablesequence)
} }
Q_strncpyz (info.userinfo, net_message.data + 11, sizeof(info.userinfo)-1); Q_strncpyz (info.userinfo, net_message.data + 11, sizeof(info.userinfo)-1);
if (strcmp(Info_ValueForKey(info.userinfo, "protocol"), "darkplaces 3")) if (strcmp(Info_ValueForKey(info.userinfo, "protocol"), "darkplaces "STRINGIFY(NQ_NETCHAN_VERSION)))
{ {
SV_RejectMessage (SCP_BAD, "Server is %s.\n", version_string()); SV_RejectMessage (SCP_BAD, "Server is %s.\n", version_string());
Con_TPrintf ("* rejected connect from incompatible client\n"); Con_TPrintf ("* rejected connect from incompatible client\n");
@ -4165,8 +4222,9 @@ qboolean SV_ConnectionlessPacket (void)
}*/ }*/
else if (!strcmp(c,"getchallenge")) else if (!strcmp(c,"getchallenge"))
{ {
//qw+q2 always sends "\xff\xff\xff\xffgetchallenge\n" //qw+q2 sends "\xff\xff\xff\xffgetchallenge\n"
//dp+q3 always sends "\xff\xff\xff\xffgetchallenge" //dp+q3 sends "\xff\xff\xff\xffgetchallenge"
//ioq3 sends "\xff\xff\xff\xffgetchallenge <clientchallenge> <$com_gamename>"
//its a subtle difference, but means we can avoid wasteful spam for real qw clients. //its a subtle difference, but means we can avoid wasteful spam for real qw clients.
SVC_GetChallenge ((net_message.cursize==16)?true:false); SVC_GetChallenge ((net_message.cursize==16)?true:false);
} }
@ -4407,13 +4465,15 @@ qboolean SVNQ_ConnectionlessPacket(void)
if (SV_ChallengeRecent()) if (SV_ChallengeRecent())
return true; return true;
else if (!strncmp(MSG_ReadString(), "getchallenge", 12) && (sv_listen_qw.ival || sv_listen_dp.ival))
Cmd_TokenizeString (MSG_ReadString(), false, false);
if (!strcmp(Cmd_Argv(0), "getchallenge") && (sv_listen_qw.ival || sv_listen_dp.ival))
{ {
/*dual-stack client, supporting either DP or QW protocols*/ /*dual-stack client, supporting either DP or QW protocols*/
SVC_GetChallenge (false); SVC_GetChallenge (false);
} }
else else
{ { //legacy pure-nq (though often DP).
if (progstype == PROG_H2) if (progstype == PROG_H2)
{ {
SZ_Clear(&sb); SZ_Clear(&sb);