From: vortex Date: Wed, 10 Feb 2010 20:05:46 +0000 (+0000) Subject: Experimental feature of saving buffers within savegame files (in extended section... X-Git-Tag: xonotic-v0.1.0preview~230^2~520 X-Git-Url: https://git.xonotic.org/?a=commitdiff_plain;h=f5b7fe803746486111c16946c49798346810e0c8;p=xonotic%2Fdarkplaces.git Experimental feature of saving buffers within savegame files (in extended section). Code needs cleaning (since i'm not really understand concept of expandable arrays). Upgraded buf_create() to optional buf_create(string,float) string being a buffer format (yet another experimental feature that will be tested in future), should be "string" if presented. Second float is buffer flags, currently only flag 1 (save in savegames) are used. There is idea for another buffer flag which will allow buffer to pass across levels, saving handle number and contents (bufhandle could be passed as one of parm*). git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9949 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/host_cmd.c b/host_cmd.c index e04f1a25..ab073c68 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -535,9 +535,11 @@ LOAD / SAVE GAME void Host_Savegame_to (const char *name) { qfile_t *f; - int i, lightstyles = 64; + int i, k, l, lightstyles = 64; char comment[SAVEGAME_COMMENT_LENGTH+1]; + char line[MAX_INPUTLINE]; qboolean isserver; + char *s; // first we have to figure out if this can be saved in 64 lightstyles // (for Quake compatibility) @@ -621,6 +623,51 @@ void Host_Savegame_to (const char *name) for (i=1 ; istringbuffersarray); i++) + { + prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i); + if(stringbuffer && (stringbuffer->flags & STRINGBUFFER_SAVED)) + { + for(k = 0; k < stringbuffer->num_strings; k++) + { + if (!stringbuffer->strings[k]) + continue; + // Parse the string a bit to turn special characters + // (like newline, specifically) into escape codes + s = stringbuffer->strings[k]; + for (l = 0;l < (int)sizeof(line) - 2 && *s;) + { + if (*s == '\n') + { + line[l++] = '\\'; + line[l++] = 'n'; + } + else if (*s == '\r') + { + line[l++] = '\\'; + line[l++] = 'r'; + } + else if (*s == '\\') + { + line[l++] = '\\'; + line[l++] = '\\'; + } + else if (*s == '"') + { + line[l++] = '\\'; + line[l++] = '"'; + } + else + line[l++] = *s; + s++; + } + line[l] = '\0'; + FS_Printf(f,"sv.bufstr %i %i \"%s\"\n", i, k, line); + } + } + } FS_Printf(f,"*/\n"); #endif @@ -687,6 +734,7 @@ void Host_Savegame_f (void) Host_Loadgame_f =============== */ + void Host_Loadgame_f (void) { char filename[MAX_QPATH]; @@ -697,10 +745,12 @@ void Host_Loadgame_f (void) const char *t; char *text; prvm_edict_t *ent; - int i; + int i, k; int entnum; int version; float spawn_parms[NUM_SPAWN_PARMS]; + prvm_stringbuffer_t *stringbuffer; + size_t alloclen; if (Cmd_Argc() != 2) { @@ -950,6 +1000,46 @@ void Host_Loadgame_f (void) else Con_Printf("unsupported sound %i \"%s\"\n", i, com_token); } + else if (!strcmp(com_token, "sv.bufstr")) + { + COM_ParseToken_Simple(&t, false, false); + i = atoi(com_token); + COM_ParseToken_Simple(&t, false, false); + k = atoi(com_token); + COM_ParseToken_Simple(&t, false, false); + 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); + else + { + // code copied from VM_bufstr_set + // expand buffer + if (stringbuffer->max_strings <= i) + { + 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); + } + // 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); + } + } // skip any trailing text or unrecognized commands while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n")) ; diff --git a/progsvm.h b/progsvm.h index 9481800e..938f29ea 100644 --- a/progsvm.h +++ b/progsvm.h @@ -360,12 +360,16 @@ typedef struct prvm_prog_funcoffsets_s } prvm_prog_funcoffsets_t; +// stringbuffer flags +#define STRINGBUFFER_SAVED 1 // saved in savegames + typedef struct prvm_stringbuffer_s { int max_strings; int num_strings; char **strings; const char *origin; + unsigned char flags; } prvm_stringbuffer_t; diff --git a/prvm_cmds.c b/prvm_cmds.c index 48184e51..0e9e94ae 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -4439,19 +4439,34 @@ static int BufStr_SortStringsDOWN (const void *in1, const void *in2) VM_buf_create creates new buffer, and returns it's index, returns -1 if failed float buf_create(void) = #460; +float newbuf(string format, float flags) = #460; ======================== */ + void VM_buf_create (void) { prvm_stringbuffer_t *stringbuffer; int i; - VM_SAFEPARMCOUNT(0, VM_buf_create); + + VM_SAFEPARMCOUNTRANGE(0, 2, VM_buf_create); + + // VorteX: optional parm1 (buffer format) is unfinished, to keep intact with future databuffers extension must be set to "string" + if(prog->argc >= 1 && strcmp(PRVM_G_STRING(OFS_PARM0), "string")) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + return; + } stringbuffer = (prvm_stringbuffer_t *) Mem_ExpandableArray_AllocRecord(&prog->stringbuffersarray); for (i = 0;stringbuffer != Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);i++); stringbuffer->origin = PRVM_AllocationOrigin(); + // optional flags parm + if(prog->argc == 2) + stringbuffer->flags = (int)PRVM_G_FLOAT(OFS_PARM1) & 0xFF; PRVM_G_FLOAT(OFS_RETURN) = i; } + + /* ======================== VM_buf_del diff --git a/zone.c b/zone.c index 889adc9d..e18c6ae5 100644 --- a/zone.c +++ b/zone.c @@ -627,6 +627,44 @@ 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 6caa0390..065f1c0c 100644 --- a/zone.h +++ b/zone.h @@ -122,6 +122,7 @@ 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;