From 64cdb85e04fe54b7614860bd27f7bbd53bdcaedb Mon Sep 17 00:00:00 2001 From: divverent Date: Sun, 2 May 2010 12:16:28 +0000 Subject: [PATCH] Add QC/cfg facilities to control deletion of automatically recorded demos MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10112 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_demo.c | 8 +++++++- cl_main.c | 2 ++ cl_parse.c | 3 +++ client.h | 1 + fs.c | 18 ++++++++++++++++++ fs.h | 1 + progsvm.h | 1 + prvm_edict.c | 1 + sv_demo.c | 17 ++++++++++++++++- sv_main.c | 2 ++ 10 files changed, 52 insertions(+), 2 deletions(-) diff --git a/cl_demo.c b/cl_demo.c index 08f84745..7b678b7f 100644 --- 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"); } /* diff --git a/cl_main.c b/cl_main.c index 66964ea4..a254ca58 100644 --- 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)"); diff --git a/cl_parse.c b/cl_parse.c index 96109e54..2adedb05 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -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) { diff --git a/client.h b/client.h index e177b76e..69c2fcc1 100644 --- 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 40f78f0a..01581988 100644 --- 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 65ee54ec..f8d813cb 100644 --- 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); diff --git a/progsvm.h b/progsvm.h index dc7f192a..ddbd75d0 100644 --- 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 diff --git a/prvm_edict.c b/prvm_edict.c index 56a1e3f4..56171616 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -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"); diff --git a/sv_demo.c b/sv_demo.c index 81f169bb..acea7b01 100644 --- 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) diff --git a/sv_main.c b/sv_main.c index 40d7e6dd..cda3379f 100644 --- 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); -- 2.39.2