Add QC/cfg facilities to control deletion of automatically recorded demos
authordivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 2 May 2010 12:16:28 +0000 (12:16 +0000)
committerdivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 2 May 2010 12:16:28 +0000 (12:16 +0000)
This patch adds two new cvars, cl_autodemo_delete and
sv_autodemo_perclient_discardable, as well as an entity field for use
by game code, .float discardabledemo.  See the cvar descriptions for
more details.

From: Jānis Rūcis <parasti@gmail.com>

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10112 d7cf8633-e32d-0410-b094-e92efae38249

cl_demo.c
cl_main.c
cl_parse.c
client.h
fs.c
fs.h
progsvm.h
prvm_edict.c
sv_demo.c
sv_main.c

index 08f8474..7b678b7 100644 (file)
--- a/cl_demo.c
+++ b/cl_demo.c
@@ -306,10 +306,16 @@ void CL_Stop_f (void)
        CL_WriteDemoMessage(&buf);
 
 // finish up
+       if (cl_autodemo.integer && ((cl_autodemo_delete.integer & 1) ^ ((cl_autodemo_delete.integer >> 1) & 1))) // bit 0 XOR bit 1
+       {
+               FS_RemoveOnClose(cls.demofile);
+               Con_Print("Completed and deleted demo\n");
+       }
+       else
+               Con_Print("Completed demo\n");
        FS_Close (cls.demofile);
        cls.demofile = NULL;
        cls.demorecording = false;
-       Con_Print("Completed demo\n");
 }
 
 /*
index 66964ea..a254ca5 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -57,6 +57,7 @@ cvar_t freelook = {CVAR_SAVE, "freelook", "1","mouse controls pitch instead of f
 
 cvar_t cl_autodemo = {CVAR_SAVE, "cl_autodemo", "0", "records every game played, using the date/time and map name to name the demo file" };
 cvar_t cl_autodemo_nameformat = {CVAR_SAVE, "cl_autodemo_nameformat", "autodemos/%Y-%m-%d_%H-%M", "The format of the cl_autodemo filename, followed by the map name (the date is encoded using strftime escapes)" };
+cvar_t cl_autodemo_delete = {0, "cl_autodemo_delete", "0", "Delete demos after recording.  This is a bitmask, bit 1 gives the default, bit 0 inverts the meaning of bit 1 for the current demo.  Thus, the values are: 0 = disabled; 1 = delete current demo only; 2 = delete all demos from this point on; 3 = delete all demos except the current demo" };
 
 cvar_t r_draweffects = {0, "r_draweffects", "1","renders temporary sprite effects"};
 
@@ -2380,6 +2381,7 @@ void CL_Init (void)
 
        Cvar_RegisterVariable (&cl_autodemo);
        Cvar_RegisterVariable (&cl_autodemo_nameformat);
+       Cvar_RegisterVariable (&cl_autodemo_delete);
 
        Cmd_AddCommand ("fog", CL_Fog_f, "set global fog parameters (density red green blue [alpha [mindist [maxdist [top [fadedepth]]]]])");
        Cmd_AddCommand ("fog_heighttexture", CL_Fog_HeightTexture_f, "set global fog parameters (density red green blue alpha mindist maxdist top depth textures/mapname/fogheight.tga)");
index 96109e5..2adedb0 100644 (file)
@@ -1828,6 +1828,9 @@ void CL_ParseServerInfo (void)
 
                Con_Printf ("Auto-recording to %s.\n", demofile);
 
+               // Clear the invert flag for every new demo
+               Cvar_SetValueQuick(&cl_autodemo_delete, cl_autodemo_delete.integer & ~0x1);
+
                cls.demofile = FS_OpenRealFile(demofile, "wb", false);
                if (cls.demofile)
                {
index e177b76..69c2fcc 100644 (file)
--- a/client.h
+++ b/client.h
@@ -1276,6 +1276,7 @@ extern cvar_t m_side;
 
 extern cvar_t cl_autodemo;
 extern cvar_t cl_autodemo_nameformat;
+extern cvar_t cl_autodemo_delete;
 
 extern cvar_t r_draweffects;
 
diff --git a/fs.c b/fs.c
index 40f78f0..0158198 100644 (file)
--- a/fs.c
+++ b/fs.c
@@ -188,6 +188,8 @@ typedef struct
 #define QFILE_FLAG_DEFLATED (1 << 1)
 /// file is actually already loaded data
 #define QFILE_FLAG_DATA (1 << 2)
+/// real file will be removed on close
+#define QFILE_FLAG_REMOVE (1 << 3)
 
 #define FILE_BUFF_SIZE 2048
 typedef struct
@@ -215,6 +217,8 @@ struct qfile_s
        ztoolkit_t*             ztk;    ///< For zipped files.
 
        const unsigned char *data;      ///< For data files.
+
+       const char *filename; ///< Kept around for QFILE_FLAG_REMOVE, unused otherwise
 };
 
 
@@ -1924,6 +1928,8 @@ static qfile_t* FS_SysOpen (const char* filepath, const char* mode, qboolean non
                return NULL;
        }
 
+       file->filename = Mem_strdup(fs_mempool, filepath);
+
        file->real_length = lseek (file->handle, 0, SEEK_END);
 
        // For files opened in append mode, we start at the end of the file
@@ -2389,6 +2395,14 @@ int FS_Close (qfile_t* file)
        if (close (file->handle))
                return EOF;
 
+       if (file->filename)
+       {
+               if (file->flags & QFILE_FLAG_REMOVE)
+                       remove(file->filename);
+
+               Mem_Free((void *) file->filename);
+       }
+
        if (file->ztk)
        {
                qz_inflateEnd (&file->ztk->zstream);
@@ -2399,6 +2413,10 @@ int FS_Close (qfile_t* file)
        return 0;
 }
 
+void FS_RemoveOnClose(qfile_t* file)
+{
+       file->flags |= QFILE_FLAG_REMOVE;
+}
 
 /*
 ====================
diff --git a/fs.h b/fs.h
index 65ee54e..f8d813c 100644 (file)
--- a/fs.h
+++ b/fs.h
@@ -62,6 +62,7 @@ qfile_t* FS_OpenRealFile (const char* filepath, const char* mode, qboolean quiet
 qfile_t* FS_OpenVirtualFile (const char* filepath, qboolean quiet);
 qfile_t* FS_FileFromData (const unsigned char *data, const size_t size, qboolean quiet);
 int FS_Close (qfile_t* file);
+void FS_RemoveOnClose(qfile_t* file);
 fs_offset_t FS_Write (qfile_t* file, const void* data, size_t datasize);
 fs_offset_t FS_Read (qfile_t* file, void* buffer, size_t buffersize);
 int FS_Print(qfile_t* file, const char *msg);
index dc7f192..ddbd75d 100644 (file)
--- a/progsvm.h
+++ b/progsvm.h
@@ -187,6 +187,7 @@ typedef struct prvm_prog_fieldoffsets_s
        int dimension_hit; // ssqc / csqc
        int dimension_solid; // ssqc / csqc
        int disableclientprediction; // ssqc
+       int discardabledemo; // ssqc
        int dphitcontentsmask; // ssqc / csqc
        int drawonlytoclient; // ssqc
        int effects; // ssqc / csqc
index 56a1e3f..5617161 100644 (file)
@@ -1575,6 +1575,7 @@ void PRVM_FindOffsets(void)
        prog->fieldoffsets.dimension_hit                  = PRVM_ED_FindFieldOffset("dimension_hit");
        prog->fieldoffsets.dimension_solid                = PRVM_ED_FindFieldOffset("dimension_solid");
        prog->fieldoffsets.disableclientprediction        = PRVM_ED_FindFieldOffset("disableclientprediction");
+       prog->fieldoffsets.discardabledemo                = PRVM_ED_FindFieldOffset("discardabledemo");
        prog->fieldoffsets.dphitcontentsmask              = PRVM_ED_FindFieldOffset("dphitcontentsmask");
        prog->fieldoffsets.drawonlytoclient               = PRVM_ED_FindFieldOffset("drawonlytoclient");
        prog->fieldoffsets.exteriormodeltoclient          = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
index 81f169b..acea7b0 100644 (file)
--- a/sv_demo.c
+++ b/sv_demo.c
@@ -1,9 +1,12 @@
 #include "quakedef.h"
 #include "sv_demo.h"
 
+extern cvar_t sv_autodemo_perclient_discardable;
+
 void SV_StartDemoRecording(client_t *client, const char *filename, int forcetrack)
 {
        char name[MAX_QPATH];
+       prvm_eval_t *val;
 
        if(client->sv_demo_file != NULL)
                return; // we already have a demo
@@ -13,6 +16,10 @@ void SV_StartDemoRecording(client_t *client, const char *filename, int forcetrac
 
        Con_Printf("Recording demo for # %d (%s) to %s\n", PRVM_NUM_FOR_EDICT(client->edict), client->netaddress, name);
 
+       // Reset discardable flag for every new demo.
+       if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.discardabledemo)))
+               val->_float = 0;
+
        client->sv_demo_file = FS_OpenRealFile(name, "wb", false);
        if(!client->sv_demo_file)
        {
@@ -49,6 +56,7 @@ void SV_StopDemoRecording(client_t *client)
 {
        sizebuf_t buf;
        unsigned char bufdata[64];
+       prvm_eval_t *val;
 
        if(client->sv_demo_file == NULL)
                return;
@@ -59,9 +67,16 @@ void SV_StopDemoRecording(client_t *client)
        MSG_WriteByte(&buf, svc_disconnect);
        SV_WriteDemoMessage(client, &buf, false);
 
+       if (sv_autodemo_perclient_discardable.integer && (val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.discardabledemo)) && val->_float)
+       {
+               FS_RemoveOnClose(client->sv_demo_file);
+               Con_Printf("Stopped recording discardable demo for # %d (%s)\n", PRVM_NUM_FOR_EDICT(client->edict), client->netaddress);
+       }
+       else
+               Con_Printf("Stopped recording demo for # %d (%s)\n", PRVM_NUM_FOR_EDICT(client->edict), client->netaddress);
+
        FS_Close(client->sv_demo_file);
        client->sv_demo_file = NULL;
-       Con_Printf("Stopped recording demo for # %d (%s)\n", PRVM_NUM_FOR_EDICT(client->edict), client->netaddress);
 }
 
 void SV_WriteNetnameIntoDemo(client_t *client)
index 40d7e6d..cda3379 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -175,6 +175,7 @@ cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be use
 
 cvar_t sv_autodemo_perclient = {CVAR_SAVE, "sv_autodemo_perclient", "0", "set to 1 to enable autorecorded per-client demos (they'll start to record at the beginning of a match); set it to 2 to also record client->server packets (for debugging)"};
 cvar_t sv_autodemo_perclient_nameformat = {CVAR_SAVE, "sv_autodemo_perclient_nameformat", "sv_autodemos/%Y-%m-%d_%H-%M", "The format of the sv_autodemo_perclient filename, followed by the map name, the client number and the IP address + port number, separated by underscores (the date is encoded using strftime escapes)" };
+cvar_t sv_autodemo_perclient_discardable = {CVAR_SAVE, "sv_autodemo_perclient_discardable", "0", "Allow game code to decide whether a demo should be kept or discarded."};
 
 cvar_t halflifebsp = {0, "halflifebsp", "0", "indicates the current map is hlbsp format (useful to know because of different bounding box sizes)"};
 
@@ -492,6 +493,7 @@ void SV_Init (void)
 
        Cvar_RegisterVariable (&sv_autodemo_perclient);
        Cvar_RegisterVariable (&sv_autodemo_perclient_nameformat);
+       Cvar_RegisterVariable (&sv_autodemo_perclient_discardable);
 
        Cvar_RegisterVariable (&halflifebsp);