mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-22 12:41:21 +00:00
Implement fallback logic from HTTP downloading to UDP.
This looks easy, but is rather hacky... Downloading is implemented through the precacher. The server sends an asset list, while loading the map another one is generated. CL_RequestNextDownload() goes through this list, in the order models / maps -> sounds -> images, calls CL_CheckOrDownloadFile() for each file. CL_CheckOrDownloadFile() checks if the file is already there, return true if it is and false if not. If the return code is false CL_RequestNextDownload() itself returns, it's called again by CL_ParseDownload() as soon as the just queued file finished downloading. This way all missing files are downloaded one after the other, when CL_RequestNextDownload() finally reaches it's end (all files are there) it send 'begin' to the server, thus putting the client into the game. HTTP downloads are parallel, so CL_RequestNextDownload() cannot track which files are there and which are missing. The work around for that is to queue the file but have CL_CheckOrDownloadFile() return true. So CL_RequestNextDownload() thinks the file is already there, continues with the next one, until all missing files are queued. After that it polls CL_PendingHTTPDownloads() and sends the 'begin' as soon as all HTTP downloads are finished. If a HTTP download fails we cannot just queue it as UDP download, because the precacher things that the file is already there. And we can't tell the precacher that it's not because the precacher tracks files only by the number of downloaded files per asste type and not their name. Just decreasing the number of downloaded files isn't possible since the precacher may have progressed to the next asset type. So: On the HTTP side it's tracked if there was an error or not. After CL_RequestNextDownload() has queued all files and waited for all HTTP downloads to finish it checks the HTTP error status. If there was an error the precacher state is reset and CL_RequestNextDownload() recurses into itself to take another run. All files that couldn't be downloaded are queued again, this time as UDP downloads.
This commit is contained in:
parent
78366472f9
commit
eb048e8611
3 changed files with 70 additions and 14 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue