Support for q2pro's dlserver= stuff.

This commit is contained in:
Shpoike 2023-08-16 05:09:58 +01:00
parent 4f047a2214
commit ed06967318
4 changed files with 149 additions and 101 deletions

View file

@ -3562,6 +3562,127 @@ void CL_Reconnect_f (void)
CL_BeginServerReconnect(); CL_BeginServerReconnect();
} }
static void CL_ConnectionlessPacket_Connection(char *tokens)
{
if (net_from.type == NA_INVALID)
return; //I've found a qizmo demo that contains one of these. its best left ignored.
if (!CL_IsPendingServerAddress(&net_from))
{
if (net_from.type != NA_LOOPBACK)
Con_TPrintf ("ignoring connection\n");
return;
}
if (cls.state >= ca_connected)
{
if (!NET_CompareAdr(&cls.netchan.remote_address, &net_from))
{
#ifdef HAVE_SERVER
if (sv.state != ss_clustermode)
#endif
CL_Disconnect (NULL);
}
else
{
if (cls.demoplayback == DPB_NONE)
Con_TPrintf ("Dup connect received. Ignored.\n");
return;
}
}
if (net_from.type != NA_LOOPBACK)
{
// Con_TPrintf (S_COLOR_GRAY"connection\n");
#ifdef HAVE_SERVER
if (sv.state && sv.state != ss_clustermode)
SV_UnspawnServer();
#endif
}
#if defined(Q2CLIENT)
if (tokens)
{
tokens = COM_Parse(tokens); //skip the client_connect bit
while((tokens = COM_Parse(tokens)))
{
if (!strncmp(com_token, "ac=", 3))
{
if (atoi(com_token+3))
{
CL_ConnectAbort("Server requires anticheat support");
return;
}
}
else if (!strncmp(com_token, "nc=", 3))
{
int type = (cls.protocol_q2 == PROTOCOL_VERSION_R1Q2 || cls.protocol_q2 == PROTOCOL_VERSION_Q2PRO)?1:0;
if (atoi(com_token+3) != type)
{
CL_ConnectAbort("server's netchan type differs from expected.");
return;
}
}
else if (!strncmp(com_token, "map=", 4))
;
else if (!strncmp(com_token, "dlserver=", 9))
Q_strncpyz(cls.downloadurl, com_token+9, sizeof(cls.downloadurl));
else
Con_DPrintf("client_connect: Unknown token \"%s\"\n", com_token);
}
}
#endif
connectinfo.trying = false;
cl.splitclients = 0;
cls.protocol = connectinfo.protocol;
cls.proquake_angles_hack = false;
cls.fteprotocolextensions = connectinfo.ext.fte1;
cls.fteprotocolextensions2 = connectinfo.ext.fte2;
cls.ezprotocolextensions1 = connectinfo.ext.ez1;
cls.challenge = connectinfo.challenge;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport);
if (cls.protocol == CP_QUAKE2)
{
cls.protocol_q2 = connectinfo.subprotocol;
if (cls.protocol_q2 == PROTOCOL_VERSION_R1Q2 || cls.protocol_q2 == PROTOCOL_VERSION_Q2PRO)
cls.netchan.qportsize = 1;
}
cls.netchan.pext_fragmentation = connectinfo.ext.mtu?true:false;
cls.netchan.pext_stunaware = !!(connectinfo.ext.fte2&PEXT2_STUNAWARE);
if (connectinfo.ext.mtu >= 64)
{
cls.netchan.mtu = connectinfo.ext.mtu;
cls.netchan.message.maxsize = sizeof(cls.netchan.message_buf);
}
else
cls.netchan.mtu = MAX_QWMSGLEN;
#ifdef HUFFNETWORK
cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.ext.compresscrc);
#else
cls.netchan.compresstable = NULL;
#endif
CL_ParseEstablished();
#ifdef Q3CLIENT
if (cls.protocol == CP_QUAKE3)
q3->cl.Established();
else
#endif
CL_SendClientCommand(true, "new");
cls.state = ca_connected;
#ifdef QUAKESPYAPI
allowremotecmd = false; // localid required now for remote cmds
#endif
total_loading_size = 100;
current_loading_size = 0;
SCR_SetLoadingStage(LS_CLIENT);
Validation_Apply_Ruleset();
CL_WriteSetDemoMessage();
}
/* /*
================= =================
CL_ConnectionlessPacket CL_ConnectionlessPacket
@ -3718,14 +3839,16 @@ void CL_ConnectionlessPacket (void)
if (!strcmp(com_token, "onnectResponse")) if (!strcmp(com_token, "onnectResponse"))
{ {
connectinfo.protocol = CP_QUAKE3; connectinfo.protocol = CP_QUAKE3;
goto client_connect; CL_ConnectionlessPacket_Connection(s);
return;
} }
#endif #endif
#ifdef Q2CLIENT #ifdef Q2CLIENT
if (!strcmp(com_token, "lient_connect")) if (!strcmp(com_token, "lient_connect"))
{ {
connectinfo.protocol = CP_QUAKE2; connectinfo.protocol = CP_QUAKE2;
goto client_connect; CL_ConnectionlessPacket_Connection(s);
return;
} }
#endif #endif
@ -3991,7 +4114,8 @@ void CL_ConnectionlessPacket (void)
*nl = '\0'; *nl = '\0';
} }
if (!strcmp(s, "print")) COM_Parse(s);
if (!strcmp(com_token, "print"))
{ {
Con_TPrintf (S_COLOR_GRAY"print\n"); Con_TPrintf (S_COLOR_GRAY"print\n");
@ -4001,12 +4125,13 @@ void CL_ConnectionlessPacket (void)
Con_Printf ("%s", s); Con_Printf ("%s", s);
return; return;
} }
else if (!strcmp(s, "client_connect")) else if (!strcmp(com_token, "client_connect"))
{ {
connectinfo.protocol = CP_QUAKE2; connectinfo.protocol = CP_QUAKE2;
goto client_connect; CL_ConnectionlessPacket_Connection(s);
return;
} }
else if (!strcmp(s, "disconnect")) else if (!strcmp(com_token, "disconnect"))
{ {
if (NET_CompareAdr(&net_from, &cls.netchan.remote_address)) if (NET_CompareAdr(&net_from, &cls.netchan.remote_address))
{ {
@ -4160,95 +4285,11 @@ void CL_ConnectionlessPacket (void)
if (c == S2C_CONNECTION) if (c == S2C_CONNECTION)
{ {
s = NULL;
connectinfo.protocol = CP_QUAKEWORLD; connectinfo.protocol = CP_QUAKEWORLD;
connectinfo.subprotocol = PROTOCOL_VERSION_QW; connectinfo.subprotocol = PROTOCOL_VERSION_QW;
#if defined(Q2CLIENT) || defined(Q3CLIENT)
client_connect: //fixme: make function
#endif
if (net_from.type == NA_INVALID)
return; //I've found a qizmo demo that contains one of these. its best left ignored.
if (!CL_IsPendingServerAddress(&net_from))
{
if (net_from.type != NA_LOOPBACK)
Con_TPrintf ("ignoring connection\n");
return;
}
if (cls.state >= ca_connected)
{
if (!NET_CompareAdr(&cls.netchan.remote_address, &net_from))
{
#ifdef HAVE_SERVER
if (sv.state != ss_clustermode)
#endif
CL_Disconnect (NULL);
}
else
{
if (cls.demoplayback == DPB_NONE)
Con_TPrintf ("Dup connect received. Ignored.\n");
return;
}
}
if (net_from.type != NA_LOOPBACK)
{
// Con_TPrintf (S_COLOR_GRAY"connection\n");
#ifdef HAVE_SERVER
if (sv.state && sv.state != ss_clustermode)
SV_UnspawnServer();
#endif
}
connectinfo.trying = false;
cl.splitclients = 0;
cls.protocol = connectinfo.protocol;
cls.proquake_angles_hack = false;
cls.fteprotocolextensions = connectinfo.ext.fte1;
cls.fteprotocolextensions2 = connectinfo.ext.fte2;
cls.ezprotocolextensions1 = connectinfo.ext.ez1;
cls.challenge = connectinfo.challenge;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport);
if (cls.protocol == CP_QUAKE2)
{
cls.protocol_q2 = connectinfo.subprotocol;
if (cls.protocol_q2 == PROTOCOL_VERSION_R1Q2 || cls.protocol_q2 == PROTOCOL_VERSION_Q2PRO)
cls.netchan.qportsize = 1;
}
cls.netchan.pext_fragmentation = connectinfo.ext.mtu?true:false;
cls.netchan.pext_stunaware = !!(connectinfo.ext.fte2&PEXT2_STUNAWARE);
if (connectinfo.ext.mtu >= 64)
{
cls.netchan.mtu = connectinfo.ext.mtu;
cls.netchan.message.maxsize = sizeof(cls.netchan.message_buf);
}
else
cls.netchan.mtu = MAX_QWMSGLEN;
#ifdef HUFFNETWORK
cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.ext.compresscrc);
#else
cls.netchan.compresstable = NULL;
#endif
CL_ParseEstablished();
#ifdef Q3CLIENT
if (cls.protocol == CP_QUAKE3)
q3->cl.Established();
else
#endif
CL_SendClientCommand(true, "new");
cls.state = ca_connected;
#ifdef QUAKESPYAPI
allowremotecmd = false; // localid required now for remote cmds
#endif
total_loading_size = 100;
current_loading_size = 0;
SCR_SetLoadingStage(LS_CLIENT);
Validation_Apply_Ruleset();
CL_WriteSetDemoMessage();
CL_ConnectionlessPacket_Connection(NULL);
return; return;
} }
#ifdef QUAKESPYAPI #ifdef QUAKESPYAPI

View file

@ -980,17 +980,21 @@ qboolean CL_CheckOrEnqueDownloadFile (const char *filename, const char *localnam
if (flags & DLLF_ALLOWWEB) if (flags & DLLF_ALLOWWEB)
{ {
const char *dlURL = InfoBuf_ValueForKey(&cl.serverinfo, "sv_dlURL"); const char *dlURL = InfoBuf_ValueForKey(&cl.serverinfo, "sv_dlURL");
if (!*dlURL)
dlURL = cls.downloadurl;
if (!*dlURL) if (!*dlURL)
dlURL = fs_dlURL.string; dlURL = fs_dlURL.string;
if (strncmp(dlURL, "http://", 7) && strncmp(dlURL, "https://", 8))
dlURL = ""; //only allow http+https here. just paranoid.
flags &= ~(DLLF_TRYWEB|DLLF_ALLOWWEB); flags &= ~(DLLF_TRYWEB|DLLF_ALLOWWEB);
if (*dlURL && (flags & DLLF_NONGAME) && !strncmp(filename, "package/", 8)) if (*dlURL && (flags & DLLF_NONGAME) && !strncmp(filename, "package/", 8))
{ //filename is something like: package/GAMEDIR/foo.pk3 { //filename is something like: package/GAMEDIR/foo.pk3
filename = va("%s/%s", dlURL, filename+8); filename = va("%s%s%s", dlURL, ((dlURL[strlen(dlURL)-1]=='/')?"":"/"), filename+8);
flags |= DLLF_TRYWEB|DLLF_ALLOWWEB; flags |= DLLF_TRYWEB|DLLF_ALLOWWEB;
} }
else if (*dlURL) else if (*dlURL)
{ //we don't really know which gamedir its meant to be for... { //we don't really know which gamedir its meant to be for...
filename = va("%s/%s/%s", dlURL, FS_GetGamedir(true), filename); filename = va("%s%s%s/%s", dlURL, ((dlURL[strlen(dlURL)-1]=='/')?"":"/"), FS_GetGamedir(true), filename);
flags |= DLLF_TRYWEB|DLLF_ALLOWWEB; flags |= DLLF_TRYWEB|DLLF_ALLOWWEB;
} }
else if (*cl_download_mapsrc.string && else if (*cl_download_mapsrc.string &&
@ -1150,7 +1154,7 @@ static qboolean CL_CheckQ2BspWals(char *file)
//we make a special exception for .tga-without-.wal because other q2 engines already expect that, with pre-scaled textures (and thus lightmaps too). //we make a special exception for .tga-without-.wal because other q2 engines already expect that, with pre-scaled textures (and thus lightmaps too).
if (!CL_CheckDLFile(va("textures/%s.wal", tinf[i].texture))) if (!CL_CheckDLFile(va("textures/%s.wal", tinf[i].texture)))
if (!CL_CheckDLFile(va("textures/%s.tga", tinf[i].texture))) if (!CL_CheckDLFile(va("textures/%s.tga", tinf[i].texture)))
if (!CL_CheckOrEnqueDownloadFile(va("textures/%s.wal", tinf[i].texture), NULL, 0)) if (!CL_CheckOrEnqueDownloadFile(va("textures/%s.wal", tinf[i].texture), NULL, DLLF_ALLOWWEB))
gotone = true; gotone = true;
} }
} }
@ -1435,11 +1439,6 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload)
FS_LoadMapPackFile(cl.worldmodel->name, cl.worldmodel->archive); FS_LoadMapPackFile(cl.worldmodel->name, cl.worldmodel->archive);
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2 && cl.worldmodel && cl.worldmodel->checksum != cl.q2mapchecksum)
Host_EndGame("Local map version differs from server: %i != '%i'\n", cl.worldmodel->checksum, cl.q2mapchecksum);
#endif
SCR_SetLoadingFile("csprogs world"); SCR_SetLoadingFile("csprogs world");
endstage(); endstage();
@ -1491,6 +1490,11 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload)
if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADED) if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADED)
Mod_NowLoadExternal(cl.worldmodel); Mod_NowLoadExternal(cl.worldmodel);
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2 && cl.worldmodel && cl.worldmodel->checksum != cl.q2mapchecksum)
Host_EndGame("Local map version differs from server: %i != '%i'\n", cl.worldmodel->checksum, cl.q2mapchecksum);
#endif
endstage(); endstage();
} }

View file

@ -477,6 +477,7 @@ typedef struct
#endif #endif
int protocol_q2; int protocol_q2;
char downloadurl[MAX_OSPATH]; //where to download files from (for q2pro compat)
qboolean findtrack; qboolean findtrack;

View file

@ -2067,7 +2067,9 @@ void SV_AcceptMessage(client_t *newcl)
break; break;
case SCP_QUAKE2: case SCP_QUAKE2:
default: default:
strcpy(string, "client_connect\n"); Q_snprintfz(string, sizeof(string), "client_connect%s\n",
(*fs_dlURL.string?va(" dlserver=%s", fs_dlURL.string):"") //q2pro's dlserver hint
);
len = strlen(string); len = strlen(string);
break; break;