From 62dc115ffbd80bada22150e057ce3d0a9c2cb15e Mon Sep 17 00:00:00 2001 From: vortex Date: Thu, 28 Mar 2013 20:24:13 +0000 Subject: [PATCH] Rewritten SVQC stringbuffer saving routines (which is part of yet unfinished databuffers extension). Changes are backwards compatible with old savefile format. Now, once saved stringbuffers are found in extended savegame section, all string buffers allocated by worldspawn()/entityspawn (which is processed prior to savegame parsing) are deleted, and stringbuffers are restored from savegamefile with their original handles. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11930 d7cf8633-e32d-0410-b094-e92efae38249 ::stable-branch::merge=a57871c2f86386e3bed44f645aac4ef15c3024cf --- host_cmd.c | 93 +++++++++++++++++++++++---------------- progsvm.h | 4 +- prvm_cmds.c | 122 +++++++++++++++++++++++++++++++++++++++------------- zone.c | 38 ---------------- zone.h | 1 - 5 files changed, 152 insertions(+), 106 deletions(-) diff --git a/host_cmd.c b/host_cmd.c index 6a56f78c..6a0b9914 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -551,7 +551,7 @@ LOAD / SAVE GAME void Host_Savegame_to(prvm_prog_t *prog, const char *name) { qfile_t *f; - int i, k, l, lightstyles = 64; + int i, k, l, numbuffers, lightstyles = 64; char comment[SAVEGAME_COMMENT_LENGTH+1]; char line[MAX_INPUTLINE]; qboolean isserver; @@ -641,11 +641,13 @@ void Host_Savegame_to(prvm_prog_t *prog, const char *name) FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]); // darkplaces extension - save buffers - for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); i++) + numbuffers = Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); + for (i = 0; i < numbuffers; i++) { prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i); if(stringbuffer && (stringbuffer->flags & STRINGBUFFER_SAVED)) { + FS_Printf(f,"sv.buffer %i %i \"string\"\n", i, stringbuffer->flags & STRINGBUFFER_QCFLAGS); for(k = 0; k < stringbuffer->num_strings; k++) { if (!stringbuffer->strings[k]) @@ -753,6 +755,11 @@ Host_Loadgame_f =============== */ +prvm_stringbuffer_t *BufStr_FindCreateReplace (prvm_prog_t *prog, int bufindex, int flags, char *format); +void BufStr_Set(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer, int strindex, const char *str); +void BufStr_Del(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer); +void BufStr_Flush(prvm_prog_t *prog); + static void Host_Loadgame_f (void) { prvm_prog_t *prog = SVVM_prog; @@ -764,12 +771,11 @@ static void Host_Loadgame_f (void) const char *t; char *text; prvm_edict_t *ent; - int i, k; + int i, k, numbuffers; int entnum; int version; float spawn_parms[NUM_SPAWN_PARMS]; prvm_stringbuffer_t *stringbuffer; - size_t alloclen; if (Cmd_Argc() != 2) { @@ -988,6 +994,8 @@ static void Host_Loadgame_f (void) memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles)); memset(sv.model_precache[0], 0, sizeof(sv.model_precache)); memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache)); + BufStr_Flush(prog); + while (COM_ParseToken_Simple(&t, false, false, true)) { if (!strcmp(com_token, "sv.lightstyles")) @@ -1023,44 +1031,48 @@ static void Host_Loadgame_f (void) else Con_Printf("unsupported sound %i \"%s\"\n", i, com_token); } + else if (!strcmp(com_token, "sv.buffer")) + { + if (COM_ParseToken_Simple(&t, false, false, true)) + { + i = atoi(com_token); + if (i >= 0) + { + k = STRINGBUFFER_SAVED; + if (COM_ParseToken_Simple(&t, false, false, true)) + k |= atoi(com_token); + if (!BufStr_FindCreateReplace(prog, i, k, "string")) + Con_Printf("failed to create stringbuffer %i\n", i); + } + else + Con_Printf("unsupported stringbuffer index %i \"%s\"\n", i, com_token); + } + else + Con_Printf("unexpected end of line when parsing sv.buffer (expected buffer index)\n"); + } else if (!strcmp(com_token, "sv.bufstr")) { - COM_ParseToken_Simple(&t, false, false, true); - i = atoi(com_token); - COM_ParseToken_Simple(&t, false, false, true); - k = atoi(com_token); - COM_ParseToken_Simple(&t, false, false, true); - stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i); - // VorteX: nasty code, cleanup required - // create buffer at this index - if(!stringbuffer) - stringbuffer = (prvm_stringbuffer_t *) Mem_ExpandableArray_AllocRecordAtIndex(&prog->stringbuffersarray, i); - if (!stringbuffer) - Con_Printf("cant write string %i into buffer %i\n", k, i); + if (!COM_ParseToken_Simple(&t, false, false, true)) + Con_Printf("unexpected end of line when parsing sv.bufstr\n"); else { - // code copied from VM_bufstr_set - // expand buffer - if (stringbuffer->max_strings <= i) + i = atoi(com_token); + stringbuffer = BufStr_FindCreateReplace(prog, i, STRINGBUFFER_SAVED, "string"); + if (stringbuffer) { - char **oldstrings = stringbuffer->strings; - stringbuffer->max_strings = max(stringbuffer->max_strings * 2, 128); - while (stringbuffer->max_strings <= i) - stringbuffer->max_strings *= 2; - stringbuffer->strings = (char **) Mem_Alloc(prog->progs_mempool, stringbuffer->max_strings * sizeof(stringbuffer->strings[0])); - if (stringbuffer->num_strings > 0) - memcpy(stringbuffer->strings, oldstrings, stringbuffer->num_strings * sizeof(stringbuffer->strings[0])); - if (oldstrings) - Mem_Free(oldstrings); + if (COM_ParseToken_Simple(&t, false, false, true)) + { + k = atoi(com_token); + if (COM_ParseToken_Simple(&t, false, false, true)) + BufStr_Set(prog, stringbuffer, k, com_token); + else + Con_Printf("unexpected end of line when parsing sv.bufstr (expected string)\n"); + } + else + Con_Printf("unexpected end of line when parsing sv.bufstr (expected strindex)\n"); } - // allocate string - stringbuffer->num_strings = max(stringbuffer->num_strings, k + 1); - if(stringbuffer->strings[k]) - Mem_Free(stringbuffer->strings[k]); - stringbuffer->strings[k] = NULL; - alloclen = strlen(com_token) + 1; - stringbuffer->strings[k] = (char *)Mem_Alloc(prog->progs_mempool, alloclen); - memcpy(stringbuffer->strings[k], com_token, alloclen); + else + Con_Printf("failed to create stringbuffer %i \"%s\"\n", i, com_token); } } // skip any trailing text or unrecognized commands @@ -1071,6 +1083,15 @@ static void Host_Loadgame_f (void) } Mem_Free(text); + // remove all temporary flagged string buffers (ones created with BufStr_FindCreateReplace) + numbuffers = Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); + for (i = 0; i < numbuffers; i++) + { + if ( (stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i)) ) + if (stringbuffer->flags & STRINGBUFFER_TEMP) + BufStr_Del(prog, stringbuffer); + } + if(developer_entityparsing.integer) Con_Printf("Host_Loadgame_f: finished\n"); diff --git a/progsvm.h b/progsvm.h index c4e0f3d1..406a9eb2 100644 --- a/progsvm.h +++ b/progsvm.h @@ -513,7 +513,9 @@ typedef struct prvm_prog_funcoffsets_s prvm_prog_funcoffsets_t; // stringbuffer flags -#define STRINGBUFFER_SAVED 1 // saved in savegames +#define STRINGBUFFER_SAVED 1 // saved in savegames +#define STRINGBUFFER_QCFLAGS 1 // allowed to be set by QC +#define STRINGBUFFER_TEMP 128 // internal use ONLY typedef struct prvm_stringbuffer_s { int max_strings; diff --git a/prvm_cmds.c b/prvm_cmds.c index ce699306..c9f55279 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -4629,6 +4629,94 @@ static int BufStr_SortStringsDOWN (const void *in1, const void *in2) return strncmp(b, a, stringbuffers_sortlength); } +prvm_stringbuffer_t *BufStr_FindCreateReplace (prvm_prog_t *prog, int bufindex, int flags, char *format) +{ + prvm_stringbuffer_t *stringbuffer; + int i; + + if (bufindex < 0) + return NULL; + + // find buffer with wanted index + if (bufindex < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray)) + { + if ( (stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, bufindex)) ) + { + if (stringbuffer->flags & STRINGBUFFER_TEMP) + stringbuffer->flags = flags; // created but has not been used yet + return stringbuffer; + } + return NULL; + } + + // allocate new buffer with wanted index + while(1) + { + stringbuffer = (prvm_stringbuffer_t *) Mem_ExpandableArray_AllocRecord(&prog->stringbuffersarray); + stringbuffer->flags = STRINGBUFFER_TEMP; + for (i = 0;stringbuffer != Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);i++); + if (i == bufindex) + { + stringbuffer->flags = flags; // mark as used + break; + } + } + return stringbuffer; +} + +void BufStr_Set(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer, int strindex, const char *str) +{ + size_t alloclen; + + if (!stringbuffer || strindex < 0) + return; + + BufStr_Expand(prog, stringbuffer, strindex); + stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1); + if (stringbuffer->strings[strindex]) + Mem_Free(stringbuffer->strings[strindex]); + stringbuffer->strings[strindex] = NULL; + + if (str) + { + // not the NULL string! + alloclen = strlen(str) + 1; + stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen); + memcpy(stringbuffer->strings[strindex], str, alloclen); + } + + BufStr_Shrink(prog, stringbuffer); +} + +void BufStr_Del(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer) +{ + int i; + + if (!stringbuffer) + return; + + for (i = 0;i < stringbuffer->num_strings;i++) + if (stringbuffer->strings[i]) + Mem_Free(stringbuffer->strings[i]); + if (stringbuffer->strings) + Mem_Free(stringbuffer->strings); + if(stringbuffer->origin) + PRVM_Free((char *)stringbuffer->origin); + Mem_ExpandableArray_FreeRecord(&prog->stringbuffersarray, stringbuffer); +} + +void BufStr_Flush(prvm_prog_t *prog) +{ + prvm_stringbuffer_t *stringbuffer; + int i, numbuffers; + + numbuffers = Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); + for (i = 0; i < numbuffers; i++) + if ( (stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i)) ) + BufStr_Del(prog, stringbuffer); + Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64); +} + /* ======================== VM_buf_create @@ -4656,7 +4744,7 @@ void VM_buf_create (prvm_prog_t *prog) stringbuffer->origin = PRVM_AllocationOrigin(prog); // optional flags parm if (prog->argc >= 2) - stringbuffer->flags = (int)PRVM_G_FLOAT(OFS_PARM1) & 0xFF; + stringbuffer->flags = (int)PRVM_G_FLOAT(OFS_PARM1) & STRINGBUFFER_QCFLAGS; PRVM_G_FLOAT(OFS_RETURN) = i; } @@ -4675,17 +4763,7 @@ void VM_buf_del (prvm_prog_t *prog) VM_SAFEPARMCOUNT(1, VM_buf_del); stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0)); if (stringbuffer) - { - int i; - for (i = 0;i < stringbuffer->num_strings;i++) - if (stringbuffer->strings[i]) - Mem_Free(stringbuffer->strings[i]); - if (stringbuffer->strings) - Mem_Free(stringbuffer->strings); - if(stringbuffer->origin) - PRVM_Free((char *)stringbuffer->origin); - Mem_ExpandableArray_FreeRecord(&prog->stringbuffersarray, stringbuffer); - } + BufStr_Del(prog, stringbuffer); else { VM_Warning(prog, "VM_buf_del: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), prog->name); @@ -4885,7 +4963,6 @@ void bufstr_set(float bufhandle, float string_index, string str) = #466; */ void VM_bufstr_set (prvm_prog_t *prog) { - size_t alloclen; int strindex; prvm_stringbuffer_t *stringbuffer; const char *news; @@ -4905,23 +4982,8 @@ void VM_bufstr_set (prvm_prog_t *prog) return; } - BufStr_Expand(prog, stringbuffer, strindex); - stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1); - - if(stringbuffer->strings[strindex]) - Mem_Free(stringbuffer->strings[strindex]); - stringbuffer->strings[strindex] = NULL; - - if(PRVM_G_INT(OFS_PARM2)) - { - // not the NULL string! - news = PRVM_G_STRING(OFS_PARM2); - alloclen = strlen(news) + 1; - stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen); - memcpy(stringbuffer->strings[strindex], news, alloclen); - } - - BufStr_Shrink(prog, stringbuffer); + news = PRVM_G_STRING(OFS_PARM2); + BufStr_Set(prog, stringbuffer, strindex, news); } /* diff --git a/zone.c b/zone.c index 16386369..2c72c113 100644 --- a/zone.c +++ b/zone.c @@ -697,44 +697,6 @@ void Mem_ExpandableArray_FreeArray(memexpandablearray_t *l) memset(l, 0, sizeof(*l)); } -// VorteX: hacked Mem_ExpandableArray_AllocRecord, it does allocate record at certain index -void *Mem_ExpandableArray_AllocRecordAtIndex(memexpandablearray_t *l, size_t index) -{ - size_t j; - if (index >= l->numarrays) - { - if (l->numarrays == l->maxarrays) - { - memexpandablearray_array_t *oldarrays = l->arrays; - l->maxarrays = max(l->maxarrays * 2, 128); - l->arrays = (memexpandablearray_array_t*) Mem_Alloc(l->mempool, l->maxarrays * sizeof(*l->arrays)); - if (oldarrays) - { - memcpy(l->arrays, oldarrays, l->numarrays * sizeof(*l->arrays)); - Mem_Free(oldarrays); - } - } - l->arrays[index].numflaggedrecords = 0; - l->arrays[index].data = (unsigned char *) Mem_Alloc(l->mempool, (l->recordsize + 1) * l->numrecordsperarray); - l->arrays[index].allocflags = l->arrays[index].data + l->recordsize * l->numrecordsperarray; - l->numarrays++; - } - if (l->arrays[index].numflaggedrecords < l->numrecordsperarray) - { - for (j = 0;j < l->numrecordsperarray;j++) - { - if (!l->arrays[index].allocflags[j]) - { - l->arrays[index].allocflags[j] = true; - l->arrays[index].numflaggedrecords++; - memset(l->arrays[index].data + l->recordsize * j, 0, l->recordsize); - return (void *)(l->arrays[index].data + l->recordsize * j); - } - } - } - return NULL; -} - void *Mem_ExpandableArray_AllocRecord(memexpandablearray_t *l) { size_t i, j; diff --git a/zone.h b/zone.h index 065f1c0c..6caa0390 100644 --- a/zone.h +++ b/zone.h @@ -122,7 +122,6 @@ memexpandablearray_t; void Mem_ExpandableArray_NewArray(memexpandablearray_t *l, mempool_t *mempool, size_t recordsize, int numrecordsperarray); void Mem_ExpandableArray_FreeArray(memexpandablearray_t *l); void *Mem_ExpandableArray_AllocRecord(memexpandablearray_t *l); -void *Mem_ExpandableArray_AllocRecordAtIndex(memexpandablearray_t *l, size_t index); void Mem_ExpandableArray_FreeRecord(memexpandablearray_t *l, void *record); size_t Mem_ExpandableArray_IndexRange(const memexpandablearray_t *l) DP_FUNC_PURE; void *Mem_ExpandableArray_RecordAtIndex(const memexpandablearray_t *l, size_t index) DP_FUNC_PURE; -- 2.39.2