From 91ac7574d2cf16d0ac4a4e60de2fd7d41fd3b09d Mon Sep 17 00:00:00 2001 From: Des Date: Mon, 5 Aug 2024 08:58:59 -0300 Subject: [PATCH] Crude port from demo rerecording code from quakespasm/proquake. Outputs a working demo, with problems (no hud?, mby more). --- cl_demo.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ common.c | 64 +++++++++++++++++++++++++++++++++++++++++ common.h | 20 +++++++++++++ 3 files changed, 169 insertions(+) diff --git a/cl_demo.c b/cl_demo.c index f44e539f..077f9770 100644 --- a/cl_demo.c +++ b/cl_demo.c @@ -27,6 +27,10 @@ extern cvar_t cl_capturevideo_demo_stop; static void CL_FinishTimeDemo (void); +// from ProQuake: space to fill out the demo header for record at any tim +static unsigned char *demo_head; +static int *demo_head_sizes; + /* ============================================================================== @@ -116,6 +120,11 @@ void CL_WriteDemoMessage (sizebuf_t *message) if (cls.demopaused) // LadyHavoc: pausedemo return; + if (cls.signon < 2) + { + Vec_Append ((void**)&demo_head, 1, message->data, message->cursize); + VEC_PUSH (demo_head_sizes, message->cursize); + } len = LittleLong (message->cursize); FS_Write (cls.demofile, &len, 4); for (i=0 ; i<3 ; i++) @@ -365,12 +374,16 @@ void CL_Record_f(cmd_state_t *cmd) if (c == 2 && cls.state == ca_connected) { +#if 0 Con_Print("Can not record - already connected to server\nClient demo recording must be started before connecting\n"); return; +#endif } +#if 0 if (cls.state == ca_connected) CL_Disconnect(); +#endif // write the forced cd track number, or -1 if (c == 4) @@ -408,6 +421,78 @@ void CL_Record_f(cmd_state_t *cmd) cls.demorecording = true; cls.demo_lastcsprogssize = -1; cls.demo_lastcsprogscrc = -1; + + // from ProQuake: initialize the demo file if we're already connected + if (c == 2 && cls.state == ca_connected) + { + sizebuf_t buf; + unsigned char tmpbuf[NET_MAXMESSAGE]; + int cursize = buf.cursize; + int maxsize = buf.maxsize; + int i, count; + + buf.data = demo_head; + for (i = 0, count = VEC_SIZE (demo_head_sizes); i < count; i++) + { + buf.cursize = demo_head_sizes[i]; + CL_WriteDemoMessage(&buf); + buf.data += buf.cursize; + } + + buf.data = tmpbuf; + buf.maxsize = sizeof (tmpbuf); + SZ_Clear (&buf); + + // current names, colors, and frag counts + for (i = 0; i < cl.maxclients; i++) + { + MSG_WriteByte (&buf, svc_updatename); + MSG_WriteByte (&buf, i); + MSG_WriteString (&buf, cl.scores[i].name); + MSG_WriteByte (&buf, svc_updatefrags); + MSG_WriteByte (&buf, i); + MSG_WriteShort (&buf, cl.scores[i].frags); + MSG_WriteByte (&buf, svc_updatecolors); + MSG_WriteByte (&buf, i); + MSG_WriteByte (&buf, cl.scores[i].colors); + } + + // send all current light styles + for (i = 0; i < MAX_LIGHTSTYLES; i++) + { + MSG_WriteByte (&buf, svc_lightstyle); + MSG_WriteByte (&buf, i); + MSG_WriteString (&buf, cl.lightstyle[i].map); + } + + // what about the CD track or SVC fog... future consideration. + MSG_WriteByte (&buf, svc_updatestat); + MSG_WriteByte (&buf, STAT_TOTALSECRETS); + MSG_WriteLong (&buf, cl.stats[STAT_TOTALSECRETS]); + + MSG_WriteByte (&buf, svc_updatestat); + MSG_WriteByte (&buf, STAT_TOTALMONSTERS); + MSG_WriteLong (&buf, cl.stats[STAT_TOTALMONSTERS]); + + MSG_WriteByte (&buf, svc_updatestat); + MSG_WriteByte (&buf, STAT_SECRETS); + MSG_WriteLong (&buf, cl.stats[STAT_SECRETS]); + + MSG_WriteByte (&buf, svc_updatestat); + MSG_WriteByte (&buf, STAT_MONSTERS); + MSG_WriteLong (&buf, cl.stats[STAT_MONSTERS]); + + // view entity + MSG_WriteByte (&buf, svc_setview); + MSG_WriteShort (&buf, cl.viewentity); + + // signon + MSG_WriteByte (&buf, svc_signonnum); + MSG_WriteByte (&buf, 3); + + CL_WriteDemoMessage(&buf); + + } } void CL_PlayDemo(const char *demo) diff --git a/common.c b/common.c index f0f2fcce..c5c33cf1 100644 --- a/common.c +++ b/common.c @@ -1498,3 +1498,67 @@ size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen) } return blocks * 4; } + + +/* +============================================================================ + + DYNAMIC VECTORS + +============================================================================ +*/ + +void Vec_Grow (void **pvec, size_t element_size, size_t count) +{ + vec_header_t header; + if (*pvec) + header = VEC_HEADER(*pvec); + else + header.size = header.capacity = 0; + + if (header.size + count > header.capacity) + { + void *new_buffer; + size_t total_size; + + header.capacity = header.size + count; + header.capacity += header.capacity >> 1; + if (header.capacity < 16) + header.capacity = 16; + total_size = sizeof(vec_header_t) + header.capacity * element_size; + + if (*pvec) + new_buffer = realloc (((vec_header_t*)*pvec) - 1, total_size); + else + new_buffer = malloc (total_size); + if (!new_buffer) + Sys_Error ("Vec_Grow: failed to allocate %lu bytes\n", (unsigned long)total_size); + + *pvec = 1 + (vec_header_t*)new_buffer; + VEC_HEADER(*pvec) = header; + } +} + +void Vec_Append (void **pvec, size_t element_size, const void *data, size_t count) +{ + if (!count) + return; + Vec_Grow (pvec, element_size, count); + memcpy ((unsigned char *)*pvec + VEC_HEADER(*pvec).size, data, count * element_size); + VEC_HEADER(*pvec).size += count; +} + +void Vec_Clear (void **pvec) +{ + if (*pvec) + VEC_HEADER(*pvec).size = 0; +} + +void Vec_Free (void **pvec) +{ + if (*pvec) + { + free(&VEC_HEADER(*pvec)); + *pvec = NULL; + } +} diff --git a/common.h b/common.h index cde830dc..0e012a30 100644 --- a/common.h +++ b/common.h @@ -75,6 +75,26 @@ void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf); void COM_Init_Commands(void); +//============================================================================ +// void* Vector +//============================================================================ +typedef struct vec_header_t { + size_t capacity; + size_t size; +} vec_header_t; + +#define VEC_HEADER(v) (((vec_header_t*)(v))[-1]) + +#define VEC_PUSH(v,n) do { Vec_Grow((void**)&(v), sizeof((v)[0]), 1); (v)[VEC_HEADER(v).size++] = (n); } while (0) +#define VEC_SIZE(v) ((v) ? VEC_HEADER(v).size : 0) +#define VEC_FREE(v) Vec_Free((void**)&(v)) +#define VEC_CLEAR(v) Vec_Clear((void**)&(v)) + +void Vec_Grow (void **pvec, size_t element_size, size_t count); +void Vec_Append (void **pvec, size_t element_size, const void *data, size_t count); +void Vec_Clear (void **pvec); +void Vec_Free (void **pvec); + //============================================================================ // Endianess handling //============================================================================ -- 2.39.2