From ff5237f066127140bcfd98103e31ffcef96a8acf Mon Sep 17 00:00:00 2001
From: Spoike <acceptthis@users.sourceforge.net>
Date: Wed, 30 Oct 2019 14:03:59 +0000
Subject: [PATCH] Try harder to block ezquake's buggy extensions.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5576 fc73d0e0-1445-4013-8a0c-d673dee63da5
---
 engine/common/protocol.h |  1 +
 engine/server/sv_main.c  | 49 ++++++++++++++++++++++++++++++++++++++++
 engine/server/sv_user.c  | 41 +++------------------------------
 3 files changed, 53 insertions(+), 38 deletions(-)

diff --git a/engine/common/protocol.h b/engine/common/protocol.h
index ac501c5a2..816be4e57 100644
--- a/engine/common/protocol.h
+++ b/engine/common/protocol.h
@@ -110,6 +110,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #else
 #define SERVER_SUPPORTED_Z_EXTENSIONS (Z_EXT_PM_TYPE|Z_EXT_PM_TYPE_NEW|Z_EXT_PITCHLIMITS|Z_EXT_JOIN_OBSERVE|Z_EXT_PF_ONGROUND|Z_EXT_VWEP|Z_EXT_PF_SOLID)
 #endif
+#define BUGGY_EZQUAKE_Z_EXTENSIONS    (Z_EXT_PF_ONGROUND|Z_EXT_PF_SOLID) //ezquake bugs out on these when ANY fteextension is present. hack the serverinfo to hide these.
 #define CLIENT_SUPPORTED_Z_EXTENSIONS (SERVER_SUPPORTED_Z_EXTENSIONS|Z_EXT_PF_ONGROUND|Z_EXT_PF_SOLID)
 
 
diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c
index a46805214..27a012f90 100644
--- a/engine/server/sv_main.c
+++ b/engine/server/sv_main.c
@@ -1970,11 +1970,60 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
 	client->fteprotocolextensions  &= Net_PextMask(PROTOCOL_VERSION_FTE1, ISNQCLIENT(client));
 	client->fteprotocolextensions2 &= Net_PextMask(PROTOCOL_VERSION_FTE2, ISNQCLIENT(client));
 	client->ezprotocolextensions1  &= Net_PextMask(PROTOCOL_VERSION_EZQUAKE1, ISNQCLIENT(client)) & EZPEXT1_SERVERADVERTISE;
+	client->zquake_extensions &= SERVER_SUPPORTED_Z_EXTENSIONS;
 
 	//some gamecode can't cope with some extensions for some reasons... and I'm too lazy to fix the code to cope.
 	if (svs.gametype == GT_HALFLIFE)
 		client->fteprotocolextensions2 &= ~PEXT2_REPLACEMENTDELTAS;	//baseline issues
 
+#ifdef HAVE_LEGACY
+	if (ISQWCLIENT(client))
+	{
+		//be prepared to recognise client versions, in order to block known-buggy extensions.
+		const char *s;
+		int ver;
+		extern cvar_t pext_ezquake_nochunks;
+		extern cvar_t pext_ezquake_verfortrans;
+		s = InfoBuf_ValueForKey(&client->userinfo, "*client");
+		if (!strncmp(s, "ezQuake", 7) || !strncmp(s, "FortressOne", 11))
+		{
+			COM_Parse(s);	//skip name-of-fork
+			COM_Parse(s);	//tokenize the version
+			ver = atoi(com_token);
+
+			//this should actually have been resolved now, but for future use...
+			if ((client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS) && pext_ezquake_nochunks.ival)
+			{
+				client->fteprotocolextensions &= ~PEXT_CHUNKEDDOWNLOADS;
+				SV_PrintToClient(client, PRINT_HIGH, "ezQuake's implementation of chunked downloads is blocked on this server.\n");
+			}
+
+			//client fails to read the extra byte when PF_EXTRA_PFS is set, instead checking for the 18th bit in a 16-bit (signed) variable.
+			if ((client->fteprotocolextensions & PEXT_TRANS) && ver < pext_ezquake_verfortrans.ival)
+			{
+				SV_PrintToClient(client, PRINT_HIGH, "ezQuake's implementation of PEXT_TRANS is buggy. Disabling.\n");
+				client->fteprotocolextensions &= ~PEXT_TRANS;
+			}
+			//in order to simultaneously support PF_SOLID+Z_EXT_PF_SOLID and PF_HULLSIZE_Z+Z_EXT_PF_ONGROUND, I had to redefine the protocol when both were enabled.
+			//ezquake does not understand the change.
+			if ((client->zquake_extensions & (Z_EXT_PF_ONGROUND|Z_EXT_PF_SOLID)) && ver < pext_ezquake_verfortrans.ival)
+			{
+				if (client->fteprotocolextensions & PEXT_HULLSIZE)
+					SV_PrintToClient(host_client, PRINT_HIGH, "ezQuake's implementation of PEXT_HULLSIZE conflicts with zquake extensions.\n");
+				if (client->fteprotocolextensions & PEXT_SCALE)
+					SV_PrintToClient(host_client, PRINT_HIGH, "ezQuake's implementation of PEXT_SCALE conflicts with zquake extensions.\n");
+				if (client->fteprotocolextensions & PEXT_FATNESS)
+					SV_PrintToClient(host_client, PRINT_HIGH, "ezQuake's implementation of PEXT_FATNESS conflicts with zquake extensions.\n");
+				if (client->fteprotocolextensions & PEXT_TRANS)
+					SV_PrintToClient(host_client, PRINT_HIGH, "ezQuake's implementation of PEXT_TRANS conflicts with zquake extensions.\n");
+				client->fteprotocolextensions &= ~(PEXT_HULLSIZE|PEXT_TRANS|PEXT_SCALE|PEXT_FATNESS);
+			}
+		}
+
+		//its not that I'm singling out ezquake or anything, but it has too many people using outdated versions that its hard to ignore.
+	}
+#endif
+
 	//
 	client->maxmodels = 256;
 	if (client->fteprotocolextensions & PEXT_256PACKETENTITIES)
diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c
index fe16434d3..7277c71d4 100644
--- a/engine/server/sv_user.c
+++ b/engine/server/sv_user.c
@@ -80,8 +80,8 @@ cvar_t	sv_nqplayerphysics	= CVARAFCD("sv_nqplayerphysics", "auto", "sv_nomsec",
 
 #ifdef HAVE_LEGACY
 static cvar_t	sv_brokenmovetypes	= CVARD("sv_brokenmovetypes", "0", "Emulate vanilla quakeworld by forcing MOVETYPE_WALK on all players. Shouldn't be used for any games other than QuakeWorld.");
-static cvar_t pext_ezquake_nochunks	= CVARD("pext_ezquake_nochunks", "0", "Prevents ezquake clients from being able to use the chunked download extension. This sidesteps numerous ezquake issues, and will make downloads slower but more robust.");
-static cvar_t pext_ezquake_verfortrans	= CVARD("pext_ezquake_verfortrans", "999999999", "ezQuake does not implement PEXT_TRANS properly. This is the version of ezquake required for PEXT_TRANS to be allowed. This was still broken when I wrote this description, hence the large value.");
+cvar_t pext_ezquake_nochunks	= CVARD("pext_ezquake_nochunks", "0", "Prevents ezquake clients from being able to use the chunked download extension. This sidesteps numerous ezquake issues, and will make downloads slower but more robust.");
+cvar_t pext_ezquake_verfortrans	= CVARD("pext_ezquake_verfortrans", "999999999", "ezQuake does not implement PEXT_TRANS properly. This is the version of ezquake required for PEXT_TRANS to be allowed. This was still broken when I wrote this description, hence the large value.");
 #endif
 
 cvar_t	sv_chatfilter	= CVAR("sv_chatfilter", "0");
@@ -320,42 +320,6 @@ void SV_New_f (void)
 		return;
 	}
 
-#ifdef HAVE_LEGACY
-	{
-		//be prepared to recognise client versions, in order to block known-buggy extensions.
-		const char *s;
-		int ver;
-		s = InfoBuf_ValueForKey(&host_client->userinfo, "*client");
-		if (!strncmp(s, "ezQuake", 7) || !strncmp(s, "FortressOne", 11))
-		{
-			COM_Parse(s);	//skip name-of-fork
-			COM_Parse(s);	//tokenize the version
-			ver = atoi(com_token);
-
-			//this should actually have been resolved now, but for future use...
-			if ((host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS) && pext_ezquake_nochunks.ival)
-			{
-				host_client->fteprotocolextensions &= ~PEXT_CHUNKEDDOWNLOADS;
-				SV_PrintToClient(host_client, PRINT_HIGH, "ezQuake's implementation of chunked downloads is blocked on this server.\n");
-			}
-			if ((host_client->zquake_extensions & (Z_EXT_PF_SOLID|Z_EXT_PF_ONGROUND)) && ver < pext_ezquake_verfortrans.ival)
-			{
-				if (host_client->fteprotocolextensions & PEXT_HULLSIZE)
-					SV_PrintToClient(host_client, PRINT_HIGH, "ezQuake's implementation of PEXT_HULLSIZE conflicts with zquake extensions.\n");
-				if (host_client->fteprotocolextensions & PEXT_SCALE)
-					SV_PrintToClient(host_client, PRINT_HIGH, "ezQuake's implementation of PEXT_SCALE conflicts with zquake extensions.\n");
-				if (host_client->fteprotocolextensions & PEXT_FATNESS)
-					SV_PrintToClient(host_client, PRINT_HIGH, "ezQuake's implementation of PEXT_FATNESS conflicts with zquake extensions.\n");
-				if (host_client->fteprotocolextensions & PEXT_TRANS)
-					SV_PrintToClient(host_client, PRINT_HIGH, "ezQuake's implementation of PEXT_TRANS is buggy. Disabling.\n");
-				host_client->fteprotocolextensions &= ~(PEXT_HULLSIZE|PEXT_TRANS|PEXT_SCALE|PEXT_FATNESS);
-			}
-		}
-
-		//its not that I'm singling out ezquake or anything, but it has too many people using outdated versions that its hard to ignore.
-	}
-#endif
-
 	ClientReliableCheckBlock(host_client, 800);	//okay, so it might be longer, but I'm too lazy to work out the real size.
 
 	// send the serverdata
@@ -1094,6 +1058,7 @@ void SV_SendClientPrespawnInfo(client_t *client)
 				if (!ISNQCLIENT(client) || (client->fteprotocolextensions2 & PEXT2_PREDINFO))
 				{	//nq does not normally get serverinfo sent to it.
 					i = InfoBuf_ToString(&svs.info, buffer, sizeof(buffer), NULL, NULL, NULL, &client->infosync, &svs.info);
+					Info_SetValueForStarKey(buffer, "*z_ext", va("%i", client->zquake_extensions), sizeof(buffer)); //should already be in there, so this should only ever make it shorter.
 					ClientReliableWrite_Begin(client, svc_stufftext, 20 + i);
 					ClientReliableWrite_String (client, va("fullserverinfo \"%s\"\n", buffer) );
 				}