diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 21c99fb60..9d977486d 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -3562,6 +3562,127 @@ void CL_Reconnect_f (void) 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 @@ -3718,14 +3839,16 @@ void CL_ConnectionlessPacket (void) if (!strcmp(com_token, "onnectResponse")) { connectinfo.protocol = CP_QUAKE3; - goto client_connect; + CL_ConnectionlessPacket_Connection(s); + return; } #endif #ifdef Q2CLIENT if (!strcmp(com_token, "lient_connect")) { connectinfo.protocol = CP_QUAKE2; - goto client_connect; + CL_ConnectionlessPacket_Connection(s); + return; } #endif @@ -3991,7 +4114,8 @@ void CL_ConnectionlessPacket (void) *nl = '\0'; } - if (!strcmp(s, "print")) + COM_Parse(s); + if (!strcmp(com_token, "print")) { Con_TPrintf (S_COLOR_GRAY"print\n"); @@ -4001,12 +4125,13 @@ void CL_ConnectionlessPacket (void) Con_Printf ("%s", s); return; } - else if (!strcmp(s, "client_connect")) + else if (!strcmp(com_token, "client_connect")) { 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)) { @@ -4160,95 +4285,11 @@ void CL_ConnectionlessPacket (void) if (c == S2C_CONNECTION) { + s = NULL; connectinfo.protocol = CP_QUAKEWORLD; 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; } #ifdef QUAKESPYAPI diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index b1ac4a40b..b9207c24c 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -980,17 +980,21 @@ qboolean CL_CheckOrEnqueDownloadFile (const char *filename, const char *localnam if (flags & DLLF_ALLOWWEB) { const char *dlURL = InfoBuf_ValueForKey(&cl.serverinfo, "sv_dlURL"); + if (!*dlURL) + dlURL = cls.downloadurl; if (!*dlURL) 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); if (*dlURL && (flags & DLLF_NONGAME) && !strncmp(filename, "package/", 8)) { //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; } else if (*dlURL) { //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; } 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). if (!CL_CheckDLFile(va("textures/%s.wal", 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; } } @@ -1435,11 +1439,6 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload) 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"); endstage(); @@ -1491,6 +1490,11 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload) if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADED) 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(); } diff --git a/engine/client/client.h b/engine/client/client.h index fde4ab33a..ef7227f04 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -477,6 +477,7 @@ typedef struct #endif int protocol_q2; + char downloadurl[MAX_OSPATH]; //where to download files from (for q2pro compat) qboolean findtrack; diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 3e1756d76..1fa190307 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -2067,7 +2067,9 @@ void SV_AcceptMessage(client_t *newcl) break; case SCP_QUAKE2: 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); break;