- replaced FILE * with FileReader in savegame code.

FILE* is too inflexible, with FileReader I can plug in a transparent compressor.
This commit is contained in:
Christoph Oelckers 2019-11-08 00:26:14 +01:00
parent d2cbd71dbf
commit 47227fc90f
8 changed files with 128 additions and 136 deletions

View file

@ -325,6 +325,11 @@ public:
virtual long Tell();
virtual long Seek(long offset, int mode);
size_t Printf(const char *fmt, ...) GCCPRINTF(2,3);
void Close()
{
if (File != NULL) fclose(File);
File = nullptr;
}
protected:
@ -343,6 +348,7 @@ public:
BufferWriter() {}
virtual size_t Write(const void *buffer, size_t len) override;
TArray<unsigned char> *GetBuffer() { return &mBuffer; }
TArray<unsigned char>&& TakeBuffer() { return std::move(mBuffer); }
};
#endif

View file

@ -38,7 +38,7 @@ BEGIN_DUKE_NS
char g_firstDemoFile[BMAX_PATH];
buildvfs_FILE g_demo_filePtr{}; // write
FileWriter *g_demo_filePtr{}; // write
FileReader g_demo_recFilePtr; // read
int32_t g_demo_cnt;
@ -163,23 +163,24 @@ void G_OpenDemoWrite(void)
demonum++;
g_demo_filePtr = buildvfs_fopen_read(demofn);
g_demo_filePtr = FileWriter::Open(demofn);
if (g_demo_filePtr == NULL)
break;
MAYBE_FCLOSE_AND_NULL(g_demo_filePtr);
delete g_demo_filePtr;
}
while (1);
g_demo_filePtr = buildvfs_fopen_write(demofn);
g_demo_filePtr = FileWriter::Open(demofn);
if (g_demo_filePtr == NULL)
return;
i=sv_saveandmakesnapshot(g_demo_filePtr, nullptr, -1, demorec_diffs_cvar, demorec_diffcompress_cvar,
i=sv_saveandmakesnapshot(*g_demo_filePtr, nullptr, -1, demorec_diffs_cvar, demorec_diffcompress_cvar,
(demorec_seeds_cvar<<1));
if (i)
{
MAYBE_FCLOSE_AND_NULL(g_demo_filePtr);
delete g_demo_filePtr;
g_demo_filePtr = nullptr;
error_wopen_demo:
Bstrcpy(apStrings[QUOTE_RESERVED4], "FAILED STARTING DEMO RECORDING. SEE CONSOLE FOR DETAILS.");
P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
@ -232,13 +233,13 @@ static void Demo_WriteSync()
{
int16_t tmpreccnt;
buildvfs_fwrite("sYnC", 4, 1, g_demo_filePtr);
g_demo_filePtr->Write("sYnC", 4);
tmpreccnt = (int16_t)ud.reccnt;
buildvfs_fwrite(&tmpreccnt, sizeof(int16_t), 1, g_demo_filePtr);
g_demo_filePtr->Write(&tmpreccnt, sizeof(int16_t));
if (demorec_seeds)
buildvfs_fwrite(g_demo_seedbuf, 1, ud.reccnt, g_demo_filePtr);
g_demo_filePtr->Write(g_demo_seedbuf, ud.reccnt);
buildvfs_fwrite(recsync, sizeof(input_t), ud.reccnt, g_demo_filePtr);
g_demo_filePtr->Write(recsync, sizeof(input_t)* ud.reccnt);
ud.reccnt = 0;
}
@ -275,16 +276,17 @@ void G_CloseDemoWrite(void)
if (ud.reccnt > 0)
Demo_WriteSync();
buildvfs_fwrite("EnD!", 4, 1, g_demo_filePtr);
g_demo_filePtr->Write("EnD!", 4);
// lastly, we need to write the number of written recsyncs to the demo file
if (buildvfs_fseek_abs(g_demo_filePtr, offsetof(savehead_t, reccnt)))
perror("G_CloseDemoWrite: final fseek");
if (g_demo_filePtr->Write(g_demo_filePtr, offsetof(savehead_t, reccnt)))
Printf("G_CloseDemoWrite: final fseek\n");
else
buildvfs_fwrite(&g_demo_cnt, sizeof(g_demo_cnt), 1, g_demo_filePtr);
g_demo_filePtr->Write(&g_demo_cnt, sizeof(g_demo_cnt));
ud.recstat = ud.m_recstat = 0;
MAYBE_FCLOSE_AND_NULL(g_demo_filePtr);
delete g_demo_filePtr;
g_demo_filePtr = nullptr;
sv_freemem();

View file

@ -32,7 +32,7 @@ BEGIN_DUKE_NS
#define DEMOFN_FMT "edemo%03d.edm"
#define MAXDEMOS 1000
extern buildvfs_FILE g_demo_filePtr;
extern FileWriter * g_demo_filePtr;
extern char g_firstDemoFile[BMAX_PATH];
extern int32_t g_demo_cnt;

View file

@ -261,8 +261,11 @@ void G_GameExit(const char *msg)
if (ud.recstat == 1)
G_CloseDemoWrite();
else if (ud.recstat == 2)
MAYBE_FCLOSE_AND_NULL(g_demo_filePtr);
else if (ud.recstat == 2)
{
delete g_demo_filePtr;
g_demo_filePtr = nullptr;
}
// JBF: fixes crash on demo playback
// PK: modified from original

View file

@ -236,34 +236,34 @@ corrupt:
}
// Note that this entire function is totally architecture dependent and needs to be fixed (which won't be easy...)
void Gv_WriteSave(buildvfs_FILE fil)
void Gv_WriteSave(FileWriter &fil)
{
// AddLog("Saving Game Vars to File");
buildvfs_fwrite("BEG: EDuke32", 12, 1, fil);
fil.Write("BEG: EDuke32", 12);
buildvfs_fwrite(&g_gameVarCount,sizeof(g_gameVarCount),1,fil);
fil.Write(&g_gameVarCount,sizeof(g_gameVarCount));
for (bssize_t i = 0; i < g_gameVarCount; i++)
{
buildvfs_fwrite(&(aGameVars[i]), sizeof(gamevar_t), 1, fil);
buildvfs_fwrite(aGameVars[i].szLabel, sizeof(uint8_t) * MAXVARLABEL, 1, fil);
fil.Write(&(aGameVars[i]), sizeof(gamevar_t));
fil.Write(aGameVars[i].szLabel, sizeof(uint8_t) * MAXVARLABEL);
if (aGameVars[i].flags & GAMEVAR_PERPLAYER)
buildvfs_fwrite(aGameVars[i].pValues, sizeof(intptr_t) * MAXPLAYERS, 1, fil);
fil.Write(aGameVars[i].pValues, sizeof(intptr_t) * MAXPLAYERS);
else if (aGameVars[i].flags & GAMEVAR_PERACTOR)
buildvfs_fwrite(aGameVars[i].pValues, sizeof(intptr_t) * MAXSPRITES, 1, fil);
fil.Write(aGameVars[i].pValues, sizeof(intptr_t) * MAXSPRITES);
}
buildvfs_fwrite(&g_gameArrayCount,sizeof(g_gameArrayCount),1,fil);
fil.Write(&g_gameArrayCount,sizeof(g_gameArrayCount));
for (bssize_t i = 0; i < g_gameArrayCount; i++)
{
// write for .size and .dwFlags (the rest are pointers):
buildvfs_fwrite(&aGameArrays[i], sizeof(gamearray_t), 1, fil);
buildvfs_fwrite(aGameArrays[i].szLabel, sizeof(uint8_t) * MAXARRAYLABEL, 1, fil);
fil.Write(&aGameArrays[i], sizeof(gamearray_t));
fil.Write(aGameArrays[i].szLabel, sizeof(uint8_t) * MAXARRAYLABEL);
if ((aGameArrays[i].flags & GAMEARRAY_SYSTEM) != GAMEARRAY_SYSTEM)
buildvfs_fwrite(aGameArrays[i].pValues, Gv_GetArrayAllocSize(i), 1, fil);
fil.Write(aGameArrays[i].pValues, Gv_GetArrayAllocSize(i));
}
uint8_t savedstate[MAXVOLUMES * MAXLEVELS];
@ -273,7 +273,7 @@ void Gv_WriteSave(buildvfs_FILE fil)
if (g_mapInfo[i].savedstate != NULL)
savedstate[i] = 1;
buildvfs_fwrite(savedstate, sizeof(savedstate), 1, fil);
fil.Write(savedstate, sizeof(savedstate));
for (bssize_t i = 0; i < (MAXVOLUMES * MAXLEVELS); i++)
{
@ -281,27 +281,27 @@ void Gv_WriteSave(buildvfs_FILE fil)
mapstate_t &sv = *g_mapInfo[i].savedstate;
buildvfs_fwrite(g_mapInfo[i].savedstate, sizeof(mapstate_t), 1, fil);
fil.Write(g_mapInfo[i].savedstate, sizeof(mapstate_t));
for (bssize_t j = 0; j < g_gameVarCount; j++)
{
if (aGameVars[j].flags & GAMEVAR_NORESET) continue;
if (aGameVars[j].flags & GAMEVAR_PERPLAYER)
buildvfs_fwrite(sv.vars[j], sizeof(intptr_t) * MAXPLAYERS, 1, fil);
fil.Write(sv.vars[j], sizeof(intptr_t) * MAXPLAYERS);
else if (aGameVars[j].flags & GAMEVAR_PERACTOR)
buildvfs_fwrite(sv.vars[j], sizeof(intptr_t) * MAXSPRITES, 1, fil);
fil.Write(sv.vars[j], sizeof(intptr_t) * MAXSPRITES);
}
buildvfs_fwrite(sv.arraysiz, sizeof(sv.arraysiz), 1, fil);
fil.Write(sv.arraysiz, sizeof(sv.arraysiz));
for (bssize_t j = 0; j < g_gameArrayCount; j++)
if (aGameArrays[j].flags & GAMEARRAY_RESTORE)
{
buildvfs_fwrite(sv.arrays[j], Gv_GetArrayAllocSizeForCount(j, sv.arraysiz[j]), 1, fil);
fil.Write(sv.arrays[j], Gv_GetArrayAllocSizeForCount(j, sv.arraysiz[j]));
}
}
buildvfs_fwrite("EOF: EDuke32", 12, 1, fil);
fil.Write("EOF: EDuke32", 12);
}
void Gv_DumpValues(void)

View file

@ -159,7 +159,7 @@ void Gv_InitWeaponPointers(void);
void Gv_RefreshPointers(void);
void Gv_ResetVars(void);
int Gv_ReadSave(FileReader &kFile);
void Gv_WriteSave(buildvfs_FILE fil);
void Gv_WriteSave(FileWriter &fil);
void Gv_Clear(void);
#else
extern int32_t g_noResetVars;

View file

@ -738,92 +738,75 @@ int32_t G_SavePlayer(savebrief_t & sv, bool isAutoSave)
Net_WaitForServer();
ready2send = 0;
char fn[BMAX_PATH];
FString fn;
errno = 0;
buildvfs_FILE fil;
errno = 0;
buildvfs_FILE fil;
if (sv.isValid())
{
if (snprintf(fn, sizeof(fn), "%s%s", M_GetSavegamesPath().GetChars(), sv.path))
{
OSD_Printf("G_SavePlayer: file name \"%s\" too long\n", sv.path);
goto saveproblem;
}
fil = buildvfs_fopen_write(fn);
}
else
{
static char const SaveName[] = "save0000.esv";
int const len = snprintf(fn, ARRAY_SIZE(fn), "%s%s", M_GetSavegamesPath().GetChars(), SaveName);
if (len >= ARRAY_SSIZE(fn)-1)
{
OSD_Printf("G_SavePlayer: could not form automatic save path\n");
goto saveproblem;
}
char * zeros = fn + (len-8);
fil = savecounter.opennextfile(fn, zeros);
savecounter.count++;
// don't copy the mod dir into sv.path
Bstrcpy(sv.path, fn + (len-(ARRAY_SIZE(SaveName)-1)));
}
if (sv.isValid())
{
fn.Format("%s%s", M_GetSavegamesPath().GetChars(), sv.path);
fil = fopen(fn, "wb");
}
else
{
static char const SaveName[] = "save0000.svz";
fn.Format("%s%s", M_GetSavegamesPath().GetChars(), SaveName);
if (!fil)
{
OSD_Printf("G_SavePlayer: failed opening \"%s\" for writing: %s\n",
fn, strerror(errno));
goto saveproblem;
}
auto fnp = fn.LockBuffer();
char* zeros = fnp + (fn.Len() - 8);
fil = savecounter.opennextfile(fnp, zeros);
fn.UnlockBuffer();
savecounter.count++;
// don't copy the mod dir into sv.path
Bstrcpy(sv.path, fn + (fn.Len() - (ARRAY_SIZE(SaveName) - 1)));
}
sv.isExt = 0;
FileWriter fw(fil);
if (!fil)
{
OSD_Printf("G_SavePlayer: failed opening \"%s\" for writing: %s\n",
fn, strerror(errno));
ready2send = 1;
Net_WaitForServer();
// temporary hack
ud.user_map = G_HaveUserMap();
G_RestoreTimers();
ototalclock = totalclock;
return -1;
}
else
{
sv.isExt = 0;
#ifdef POLYMER
if (videoGetRenderMode() == REND_POLYMER)
polymer_resetlights();
#endif
// temporary hack
ud.user_map = G_HaveUserMap();
VM_OnEvent(EVENT_SAVEGAME, g_player[myconnectindex].ps->i, myconnectindex);
VM_OnEvent(EVENT_SAVEGAME, g_player[myconnectindex].ps->i, myconnectindex);
portableBackupSave(sv.path, sv.name, ud.last_stateless_volume, ud.last_stateless_level);
portableBackupSave(sv.path, sv.name, ud.last_stateless_volume, ud.last_stateless_level);
// SAVE!
sv_saveandmakesnapshot(fil, sv.name, 0, 0, 0, 0, isAutoSave);
// SAVE!
sv_saveandmakesnapshot(fw, sv.name, 0, 0, 0, 0, isAutoSave);
buildvfs_fclose(fil);
fw.Close();
if (!g_netServer && ud.multimode < 2)
{
OSD_Printf("Saved: %s\n", fn);
#ifdef LUNATIC
if (!g_savedOK)
Bstrcpy(apStrings[QUOTE_RESERVED4], "^10Failed Saving Game");
else
#endif
Bstrcpy(apStrings[QUOTE_RESERVED4], "Game Saved");
P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
}
if (!g_netServer && ud.multimode < 2)
{
OSD_Printf("Saved: %s\n", fn);
strcpy(apStrings[QUOTE_RESERVED4], "Game Saved");
P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
}
ready2send = 1;
Net_WaitForServer();
ready2send = 1;
Net_WaitForServer();
G_RestoreTimers();
ototalclock = totalclock;
G_RestoreTimers();
ototalclock = totalclock;
VM_OnEvent(EVENT_POSTSAVEGAME, g_player[myconnectindex].ps->i, myconnectindex);
VM_OnEvent(EVENT_POSTSAVEGAME, g_player[myconnectindex].ps->i, myconnectindex);
return 0;
saveproblem:
ready2send = 1;
Net_WaitForServer();
G_RestoreTimers();
ototalclock = totalclock;
return -1;
return 0;
}
}
int32_t G_LoadPlayerMaybeMulti(savebrief_t & sv)
@ -917,7 +900,7 @@ static inline void ds_get(const dataspec_t *spec, void **ptr, int32_t *cnt)
}
// write state to file and/or to dump
static uint8_t *writespecdata(const dataspec_t *spec, buildvfs_FILE fil, uint8_t *dump)
static uint8_t *writespecdata(const dataspec_t *spec, FileWriter *fil, uint8_t *dump)
{
for (; spec->flags != DS_END; spec++)
{
@ -932,7 +915,7 @@ static uint8_t *writespecdata(const dataspec_t *spec, buildvfs_FILE fil, uint8_t
continue;
else if (spec->flags & DS_STRING)
{
buildvfs_fwrite(spec->ptr, Bstrlen((const char *)spec->ptr), 1, fil); // not null-terminated!
fil->Write(spec->ptr, Bstrlen((const char *)spec->ptr)); // not null-terminated!
continue;
}
@ -952,7 +935,7 @@ static uint8_t *writespecdata(const dataspec_t *spec, buildvfs_FILE fil, uint8_t
if (fil)
{
buildvfs_fwrite(ptr, spec->size, cnt, fil);
fil->Write(ptr, spec->size * cnt);
}
if (dump && (spec->flags & (DS_NOCHK|DS_CMP)) == 0)
@ -1522,10 +1505,8 @@ static const dataspec_t svgm_anmisc[] =
{ DS_END, 0, 0, 0 }
};
#if !defined LUNATIC
static dataspec_gv_t *svgm_vars=NULL;
#endif
static uint8_t *dosaveplayer2(buildvfs_FILE fil, uint8_t *mem);
static uint8_t *dosaveplayer2(FileWriter &fil, uint8_t *mem);
static int32_t doloadplayer2(FileReader &fil, uint8_t **memptr);
static void postloadplayer(int32_t savegamep);
@ -1629,7 +1610,7 @@ static void SV_AllocSnap(int32_t allocinit)
}
// make snapshot only if spot < 0 (demo)
int32_t sv_saveandmakesnapshot(buildvfs_FILE fil, char const *name, int8_t spot, int8_t recdiffsp, int8_t diffcompress, int8_t synccompress, bool isAutoSave)
int32_t sv_saveandmakesnapshot(FileWriter &fil, char const *name, int8_t spot, int8_t recdiffsp, int8_t diffcompress, int8_t synccompress, bool isAutoSave)
{
savehead_t h;
@ -1699,24 +1680,24 @@ int32_t sv_saveandmakesnapshot(buildvfs_FILE fil, char const *name, int8_t spot,
// write header
buildvfs_fwrite(&h, sizeof(savehead_t), 1, fil);
fil.Write(&h, sizeof(savehead_t));
// for savegames, the file offset after the screenshot goes here;
// for demos, we keep it 0 to signify that we didn't save one
buildvfs_fwrite("\0\0\0\0", 4, 1, fil);
if (spot >= 0 && tileData(TILE_SAVESHOT))
{
int32_t ofs;
int v = 64000;
fil.Write(&v, 4);
// write the screenshot compressed
buildvfs_fwrite(tileData(TILE_SAVESHOT), 320, 200, fil);
fil.Write(tileData(TILE_SAVESHOT), 320*200);
// write the current file offset right after the header
ofs = buildvfs_ftell(fil);
buildvfs_fseek_abs(fil, sizeof(savehead_t));
buildvfs_fwrite(&ofs, 4, 1, fil);
buildvfs_fseek_abs(fil, ofs);
}
else
{
int v = 64000;
fil.Write(&v, 4);
}
if (spot >= 0)
@ -1883,7 +1864,7 @@ int32_t sv_loadsnapshot(FileReader &fil, int32_t spot, savehead_t *h)
}
uint32_t sv_writediff(buildvfs_FILE fil)
uint32_t sv_writediff(FileWriter *fil)
{
uint8_t *p = svsnapshot;
uint8_t *d = svdiff;
@ -1901,10 +1882,10 @@ uint32_t sv_writediff(buildvfs_FILE fil)
uint32_t const diffsiz = d - svdiff;
buildvfs_fwrite("dIfF",4,1,fil);
buildvfs_fwrite(&diffsiz, sizeof(diffsiz), 1, fil);
fil->Write("dIfF",4);
fil->Write(&diffsiz, sizeof(diffsiz));
buildvfs_fwrite(svdiff, 1, diffsiz, fil);
fil->Write(svdiff, diffsiz);
return diffsiz;
}
@ -2168,19 +2149,19 @@ static void sv_restload()
LUNATIC_CB const char *(*El_SerializeGamevars)(int32_t *slenptr, int32_t levelnum);
#endif
static uint8_t *dosaveplayer2(buildvfs_FILE fil, uint8_t *mem)
static uint8_t *dosaveplayer2(FileWriter &fil, uint8_t *mem)
{
#ifdef DEBUGGINGAIDS
uint8_t *tmem = mem;
int32_t t=timerGetTicks();
#endif
mem=writespecdata(svgm_udnetw, fil, mem); // user settings, players & net
mem=writespecdata(svgm_udnetw, &fil, mem); // user settings, players & net
PRINTSIZE("ud");
mem=writespecdata(svgm_secwsp, fil, mem); // sector, wall, sprite
mem=writespecdata(svgm_secwsp, &fil, mem); // sector, wall, sprite
PRINTSIZE("sws");
mem=writespecdata(svgm_script, fil, mem); // script
mem=writespecdata(svgm_script, &fil, mem); // script
PRINTSIZE("script");
mem=writespecdata(svgm_anmisc, fil, mem); // animates, quotes & misc.
mem=writespecdata(svgm_anmisc, &fil, mem); // animates, quotes & misc.
PRINTSIZE("animisc");
#if !defined LUNATIC

View file

@ -121,10 +121,10 @@ extern uint16_t g_nummenusaves;
int32_t sv_updatestate(int32_t frominit);
int32_t sv_readdiff(FileReader& fil);
uint32_t sv_writediff(buildvfs_FILE fil);
uint32_t sv_writediff(FileWriter *fil);
int32_t sv_loadheader(FileReader &fil, int32_t spot, savehead_t *h);
int32_t sv_loadsnapshot(FileReader &fil, int32_t spot, savehead_t *h);
int32_t sv_saveandmakesnapshot(buildvfs_FILE fil, char const *name, int8_t spot, int8_t recdiffsp, int8_t diffcompress, int8_t synccompress, bool isAutoSave = false);
int32_t sv_saveandmakesnapshot(FileWriter &fil, char const *name, int8_t spot, int8_t recdiffsp, int8_t diffcompress, int8_t synccompress, bool isAutoSave = false);
void sv_freemem();
void G_DeleteSave(savebrief_t const & sv);
void G_DeleteOldSaves(void);