implemented csprogs.dat downloading with special dlcache/name.size.crc file naming...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 22 Jan 2007 22:01:27 +0000 (22:01 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 22 Jan 2007 22:01:27 +0000 (22:01 +0000)
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
cl_parse.c
client.h
csprogs.c
csprogs.h
fs.c
fs.h
server.h
sv_main.c

index 6cad103..e1eae11 100644 (file)
--- 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"};
index 06595e9..4c7161a 100644 (file)
@@ -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;
        }
 
index 1a6ac79..df05ea4 100644 (file)
--- 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
index 735adbb..17c1a4a 100644 (file)
--- 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
index 11890b3..996782f 100644 (file)
--- 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 d11ea28..8f284b8 100644 (file)
--- 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 8d2f406..c790e73 100644 (file)
--- 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
index 76b7d41..d835aee 100644 (file)
--- 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
index 5f2a691..8897544 100644 (file)
--- 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);
        }
 }