diff --git a/src/client/cl_download.c b/src/client/cl_download.c index 1fff144e..1e30a226 100644 --- a/src/client/cl_download.c +++ b/src/client/cl_download.c @@ -39,6 +39,9 @@ extern int precache_model_skin; extern byte *precache_model; +// Forces all downloads to UDP. +qboolean forceudp = false; + static const char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; #define PLAYER_MULT 5 @@ -341,19 +344,32 @@ CL_RequestNextDownload(void) } } } - - /* precache phase completed */ - precache_check = ENV_CNT; } + #ifdef USE_CURL /* Wait for pending downloads. */ if (CL_PendingHTTPDownloads()) { return; } + + + if (CL_CheckHTTPError()) + { + /* Mkay, there were download errors. Let's start over, + this time with UDP. This will reuse all files that + succeeded over HTTP. */ + forceudp = true; + CL_ResetPrecacheCheck(); + CL_RequestNextDownload(); + return; + } #endif + /* precache phase completed */ + precache_check = ENV_CNT; + if (precache_check == ENV_CNT) { precache_check = ENV_CNT + 1; @@ -436,6 +452,9 @@ CL_RequestNextDownload(void) } #endif + /* This map was done, allow HTTP again for next map. */ + forceudp = false; + CL_RegisterSounds(); CL_PrepRefresh(); @@ -488,17 +507,31 @@ CL_CheckOrDownloadFile(char *filename) } #ifdef USE_CURL - if (CL_QueueHTTPDownload(filename)) + if (!forceudp) { - /* We return true so that the precache check - keeps feeding us more files. Since we have - multiple HTTP connections we want to - minimize latency and be constantly sending - requests, not one at a time. */ - return true; + if (CL_QueueHTTPDownload(filename)) + { + /* We return true so that the precache check + keeps feeding us more files. Since we have + multiple HTTP connections we want to + minimize latency and be constantly sending + requests, not one at a time. */ + return true; + } + } + else + { + /* There're 2 cases: + - forceudp was set after a 404. In this case we + want to retry that single file over UDP and + all later files over HTTP. + - forceudp was set after another error code. + In that case the HTTP code aborts all HTTP + downloads and CL_QueueHTTPDownload() returns + false. */ + forceudp = false; } #endif - strcpy(cls.downloadname, filename); /* download to a temp name, and only rename diff --git a/src/client/curl/download.c b/src/client/curl/download.c index 30cd45f2..f7abb25f 100644 --- a/src/client/curl/download.c +++ b/src/client/curl/download.c @@ -48,6 +48,7 @@ static int handleCount = 0; static int pendingCount = 0; static int abortDownloads = HTTPDL_ABORT_NONE; static qboolean httpDown = false; +static qboolean downloadError = false; // -------- @@ -582,18 +583,23 @@ static void CL_FinishHTTPDownload(void) { Com_Printf("HTTP download: %s - File Not Found\n", dl->queueEntry->quakePath); - // We got a 404, remove the target file. + // We got a 404, remove the target file... if (isFile) { Sys_Remove(dl->filePath); - isFile = false; } - // ...and remove it from the CURL multihandle. + // ...remove it from the CURL multihandle... qcurl_multi_remove_handle(multi, dl->curl); CL_RemoveFromQueue(dl->queueEntry); dl->queueEntry = NULL; + // ...and communicate the error. + if (isFile) + { + downloadError = true; + isFile = false; + } break; @@ -1050,6 +1056,22 @@ qboolean CL_PendingHTTPDownloads(void) return pendingCount + handleCount; } +/* Checks if there was an error. Returns + * true if yes, and false if not. + */ +qboolean CL_CheckHTTPError() +{ + if (downloadError) + { + downloadError = false; + return true; + } + else + { + return false; + } +} + /* * Calls CURL to perform the actual downloads. * Must be called every frame, otherwise CURL diff --git a/src/client/curl/header/download.h b/src/client/curl/header/download.h index fc6635fe..3cb2f09d 100644 --- a/src/client/curl/header/download.h +++ b/src/client/curl/header/download.h @@ -72,6 +72,7 @@ void CL_RunHTTPDownloads(void); qboolean CL_PendingHTTPDownloads(void); void CL_SetHTTPServer(const char *URL); void CL_HTTP_Cleanup(qboolean fullShutdown); +qboolean CL_CheckHTTPError(); #endif // DOWNLOAD_H #endif // USE_CURL