From 8b37a3a674013f693250d761388cbf39265a0d42 Mon Sep 17 00:00:00 2001 From: havoc Date: Mon, 22 Jan 2007 22:01:27 +0000 Subject: [PATCH] implemented csprogs.dat downloading with special dlcache/name.size.crc file naming, this is in need of testing added csqc_progsize cvar to csqc signon process (still compatible with old servers) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6732 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_main.c | 1 + cl_parse.c | 46 +++++++++++++++++++++++++++++++++++++++++----- client.h | 1 + csprogs.c | 24 +++++++++++++++++------- csprogs.h | 1 + fs.c | 21 +++++++++++++++++++++ fs.h | 1 + server.h | 1 + sv_main.c | 19 +++++++++++-------- 9 files changed, 95 insertions(+), 20 deletions(-) diff --git a/cl_main.c b/cl_main.c index 6cad103b..e1eae117 100644 --- a/cl_main.c +++ b/cl_main.c @@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. cvar_t csqc_progname = {0, "csqc_progname","csprogs.dat","name of csprogs.dat file to load"}; //[515]: csqc crc check and right csprogs name according to progs.dat cvar_t csqc_progcrc = {CVAR_READONLY, "csqc_progcrc","-1","CRC of csprogs.dat file to load (-1 is none), only used during level changes and then reset to -1"}; +cvar_t csqc_progsize = {CVAR_READONLY, "csqc_progsize","-1","file size of csprogs.dat file to load (-1 is none), only used during level changes and then reset to -1"}; cvar_t cl_shownet = {0, "cl_shownet","0","1 = print packet size, 2 = print packet message list"}; cvar_t cl_nolerp = {0, "cl_nolerp", "0","network update smoothing"}; diff --git a/cl_parse.c b/cl_parse.c index 06595e9a..4c7161a9 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -897,6 +897,21 @@ void CL_BeginDownloads(qboolean aborteddownload) // TODO: this would be a good place to do curl downloads + if (cl.downloadcsqc) + { + size_t progsize; + cl.downloadcsqc = false; + if (cls.netcon + && !sv.active + && csqc_progname.string + && csqc_progname.string[0] + && csqc_progcrc.integer >= 0 + && cl_serverextension_download.integer + && (FS_CRCFile(csqc_progname.string, &progsize) != csqc_progcrc.integer || ((int)progsize != csqc_progsize.integer && csqc_progsize.integer != -1)) + && !FS_FileExists(va("dlcache/%s.%i.%i", csqc_progname.string, csqc_progsize.integer, csqc_progcrc.integer))) + Cmd_ForwardStringToServer(va("download %s", csqc_progname.string)); + } + if (cl.loadmodel_current < cl.loadmodel_total) { // loading models @@ -1072,17 +1087,37 @@ void CL_StopDownload(int size, int crc) { if (cls.qw_downloadmemory && cls.qw_downloadmemorycursize == size && CRC_Block(cls.qw_downloadmemory, size) == crc) { + int existingcrc; + size_t existingsize; + const char *extension; + // finished file // save to disk only if we don't already have it // (this is mainly for playing back demos) - if (!FS_FileExists(cls.qw_downloadname)) + existingcrc = FS_CRCFile(cls.qw_downloadname, &existingsize); + if (existingsize) { - const char *extension; - + if ((int)existingsize != size || existingcrc != crc) + { + // we have a mismatching file, pick another name for it + char name[MAX_QPATH*2]; + dpsnprintf(name, sizeof(name), "dlcache/%s.%i.%i", cls.qw_downloadname, size, crc); + if (!FS_FileExists(name)) + { + Con_Printf("Downloaded \"%s\" (%i bytes, %i CRC)\n", name, size, crc); + FS_WriteFile(name, cls.qw_downloadmemory, cls.qw_downloadmemorycursize); + } + } + } + else + { + // we either don't have it or have a mismatching file... + // so it's time to accept the file + // but if we already have a mismatching file we need to rename + // this new one, and if we already have this file in renamed form, + // we do nothing Con_Printf("Downloaded \"%s\" (%i bytes, %i CRC)\n", cls.qw_downloadname, size, crc); - FS_WriteFile(cls.qw_downloadname, cls.qw_downloadmemory, cls.qw_downloadmemorycursize); - extension = FS_FileExtension(cls.qw_downloadname); if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3")) FS_Rescan(); @@ -1446,6 +1481,7 @@ void CL_ParseServerInfo (void) cl.loadsound_current = 1; cl.downloadsound_current = 1; cl.loadsound_total = numsounds; + cl.downloadcsqc = true; cl.loadfinished = false; } diff --git a/client.h b/client.h index 1a6ac795..df05ea43 100644 --- a/client.h +++ b/client.h @@ -894,6 +894,7 @@ typedef struct client_state_s int loadsound_current; int downloadsound_current; int loadsound_total; + qboolean downloadcsqc; qboolean loadfinished; // quakeworld stuff diff --git a/csprogs.c b/csprogs.c index 735adbb2..17c1a4ae 100644 --- a/csprogs.c +++ b/csprogs.c @@ -112,6 +112,7 @@ void CL_VM_Error (const char *format, ...) //[515]: hope it will be never execut Mem_FreePool(&csqc_mempool); Cvar_SetValueQuick(&csqc_progcrc, -1); + Cvar_SetValueQuick(&csqc_progsize, -1); // Host_AbortCurrentFrame(); //[515]: hmmm... if server says it needs csqc then client MUST disconnect Host_Error(va("CL_VM_Error: %s", errorstring)); @@ -358,10 +359,13 @@ void CL_VM_Parse_StuffCmd (const char *msg) // if this is setting a csqc variable, deprotect csqc_progcrc // temporarily so that it can be set by the cvar command, // and then reprotect it afterwards - int flags = csqc_progcrc.flags; + int crcflags = csqc_progcrc.flags; + int sizeflags = csqc_progcrc.flags; csqc_progcrc.flags &= ~CVAR_READONLY; + csqc_progsize.flags &= ~CVAR_READONLY; Cmd_ExecuteString (msg, src_command); - csqc_progcrc.flags = flags; + csqc_progcrc.flags = crcflags; + csqc_progsize.flags = sizeflags; return; } if(!csqc_loaded || !CSQC_Parse_StuffCmd) @@ -488,12 +492,15 @@ void CL_VM_Init (void) unsigned char *csprogsdata; fs_offset_t csprogsdatasize; int csprogsdatacrc, requiredcrc; + int requiredsize; entity_t *ent; // reset csqc_progcrc after reading it, so that changing servers doesn't // expect csqc on the next server requiredcrc = csqc_progcrc.integer; + requiredsize = csqc_progsize.integer; Cvar_SetValueQuick(&csqc_progcrc, -1); + Cvar_SetValueQuick(&csqc_progsize, -1); csqc_loaded = false; memset(cl.csqc_model_precache, 0, sizeof(cl.csqc_model_precache)); @@ -505,21 +512,23 @@ void CL_VM_Init (void) // see if the requested csprogs.dat file matches the requested crc csprogsdatacrc = -1; - csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize); + csprogsdata = FS_LoadFile(va("dlcache/%s.%i.%i", csqc_progname.string, requiredsize, requiredcrc), tempmempool, true, &csprogsdatasize); + if (!csprogsdata) + csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize); if (csprogsdata) { csprogsdatacrc = CRC_Block(csprogsdata, csprogsdatasize); Mem_Free(csprogsdata); - if (csprogsdatacrc != requiredcrc) + if (csprogsdatacrc != requiredcrc || csprogsdatasize != requiredsize) { if (cls.demoplayback) { - Con_Printf("^1Warning: Your %s is not the same version as the demo was recorded with (CRC is %i but should be %i)\n", csqc_progname.string, csprogsdatacrc, requiredcrc); + Con_Printf("^1Warning: Your %s is not the same version as the demo was recorded with (CRC/size are %i/%i but should be %i/%i)\n", csqc_progname.string, csprogsdatacrc, (int)csprogsdatasize, requiredcrc, requiredsize); return; } else { - Con_Printf("^1Your %s is not the same version as the server (CRC is %i but should be %i)\n", csqc_progname.string, csprogsdatacrc, requiredcrc); + Con_Printf("^1Your %s is not the same version as the server (CRC is %i/%i but should be %i/%i)\n", csqc_progname.string, csprogsdatacrc, (int)csprogsdatasize, requiredcrc, requiredsize); CL_Disconnect(); return; } @@ -560,7 +569,7 @@ void CL_VM_Init (void) PRVM_LoadProgs(csqc_progname.string, cl_numrequiredfunc, cl_required_func, 0, NULL); if(prog->loaded) - Con_Printf("CSQC ^5loaded (crc=%i)\n", csprogsdatacrc); + Con_Printf("CSQC ^5loaded (crc=%i, size=%i)\n", csprogsdatacrc, (int)csprogsdatasize); else { CL_VM_Error("CSQC ^2failed to load\n"); @@ -606,6 +615,7 @@ void CL_VM_ShutDown (void) { Cmd_ClearCsqcFuncs(); Cvar_SetValueQuick(&csqc_progcrc, -1); + Cvar_SetValueQuick(&csqc_progsize, -1); if(!csqc_loaded) return; CSQC_BEGIN diff --git a/csprogs.h b/csprogs.h index 11890b3d..996782fe 100644 --- a/csprogs.h +++ b/csprogs.h @@ -59,6 +59,7 @@ extern int csqc_fieldoff_tag_index; extern int csqc_fieldoff_dphitcontentsmask; extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat extern cvar_t csqc_progcrc; +extern cvar_t csqc_progsize; extern qboolean csqc_usecsqclistener; extern matrix4x4_t csqc_listenermatrix; diff --git a/fs.c b/fs.c index d11ea28e..8f284b81 100644 --- a/fs.c +++ b/fs.c @@ -2729,3 +2729,24 @@ qboolean FS_IsRegisteredQuakePack(const char *name) return false; } + +int FS_CRCFile(const char *filename, size_t *filesizepointer) +{ + int crc = -1; + unsigned char *filedata; + fs_offset_t filesize; + if (filesizepointer) + *filesizepointer = 0; + if (!filename || !*filename) + return crc; + filedata = FS_LoadFile(filename, tempmempool, true, &filesize); + if (filedata) + { + if (filesizepointer) + *filesizepointer = filesize; + crc = CRC_Block(filedata, filesize); + Mem_Free(filedata); + } + return crc; +} + diff --git a/fs.h b/fs.h index 8d2f4069..c790e734 100644 --- a/fs.h +++ b/fs.h @@ -72,6 +72,7 @@ int FS_CheckNastyPath (const char *path, qboolean isgamedir); qboolean FS_CheckGameDir(const char *gamedir); qboolean FS_ChangeGameDirs(int numgamedirs, char gamedirs[][MAX_QPATH], qboolean complain, qboolean failmissing); qboolean FS_IsRegisteredQuakePack(const char *name); +int FS_CRCFile(const char *filename, size_t *filesizepointer); void FS_Rescan(void); typedef struct fssearch_s diff --git a/server.h b/server.h index 76b7d418..d835aeef 100644 --- a/server.h +++ b/server.h @@ -70,6 +70,7 @@ typedef struct server_s // crc of clientside progs at time of level start int csqc_progcrc; // -1 = no progs + int csqc_progsize; // -1 = no progs char csqc_progname[MAX_QPATH]; // copied from csqc_progname at level start // map name diff --git a/sv_main.c b/sv_main.c index 5f2a6911..8897544c 100644 --- a/sv_main.c +++ b/sv_main.c @@ -91,8 +91,10 @@ void SV_Init (void) // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black] extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat extern cvar_t csqc_progcrc; + extern cvar_t csqc_progsize; Cvar_RegisterVariable (&csqc_progname); Cvar_RegisterVariable (&csqc_progcrc); + Cvar_RegisterVariable (&csqc_progsize); Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)"); Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)"); @@ -361,15 +363,17 @@ void SV_SendServerinfo (client_t *client) MSG_WriteString (&client->netconnection->message,message); //[515]: init csprogs according to version of svprogs, check the crc, etc. - if (sv.csqc_progcrc >= 0) + if (sv.csqc_progname[0]) { prvm_eval_t *val; - Con_DPrintf("sending csqc info to client (\"%s\" with crc %i)\n", sv.csqc_progname, sv.csqc_progcrc); + Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc); //[515]: init stufftext string (it is sent before svc_serverinfo) val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd")); MSG_WriteByte (&client->netconnection->message, svc_stufftext); MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname)); MSG_WriteByte (&client->netconnection->message, svc_stufftext); + MSG_WriteString (&client->netconnection->message, va("csqc_progsize %i\n", sv.csqc_progsize)); + MSG_WriteByte (&client->netconnection->message, svc_stufftext); MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc)); if (val) { @@ -2541,6 +2545,7 @@ void SV_VM_Setup(void) { extern cvar_t csqc_progname; //[515]: csqc crc check and right csprogs name according to progs.dat extern cvar_t csqc_progcrc; + extern cvar_t csqc_progsize; unsigned char *csprogsdata; fs_offset_t csprogsdatasize; PRVM_Begin; @@ -2580,15 +2585,13 @@ void SV_VM_Setup(void) PRVM_End; // see if there is a csprogs.dat installed, and if so, set the csqc_progcrc accordingly, this will be sent to connecting clients to tell them to only load a matching csprogs.dat file - sv.csqc_progcrc = -1; sv.csqc_progname[0] = 0; - csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize); - if (csprogsdata) + sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize); + sv.csqc_progsize = csprogsdatasize; + if (sv.csqc_progsize > 0) { strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname)); - sv.csqc_progcrc = CRC_Block(csprogsdata, csprogsdatasize); - Mem_Free(csprogsdata); - Con_DPrintf("server detected csqc progs file \"%s\" with crc %i\n", sv.csqc_progname, sv.csqc_progcrc); + Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc); } } -- 2.39.2