Rewrite the savegame format in terms of the generic saving/loading system.

This makes savegames practically the same as the initial snapshot of a demo.
Saves are now named 'dukesavX.esv' (demos: 'edemoX.edm').
Additionally, many changes that couldn't/needn't be cleanly separated are added
with this commit:
 - make spriteext_t have the same size across 32/64 bit platforms (actor_t partially)
 - prevent saving/loading in MP games (it certainly didn't work and still doesn't)
 - it's time we start using assertions! Define NDEBUG for releasse builds.
 - reset savegame major and minor versions (we have a new magic string, so no conflict)

git-svn-id: https://svn.eduke32.com/eduke32@2207 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2011-12-25 15:34:06 +00:00
parent 61257b0f6b
commit b3474c75b2
10 changed files with 768 additions and 316 deletions

View file

@ -84,6 +84,8 @@ ifneq (0,$(RELEASE))
endif endif
ifeq (0,$(DEBUGANYWAY)) ifeq (0,$(DEBUGANYWAY))
debug+= -fomit-frame-pointer debug+= -fomit-frame-pointer
else
debug+= -DNDEBUG
endif endif
ifneq (0,$(LTO)) ifneq (0,$(LTO))
LIBS+= -flto LIBS+= -flto

View file

@ -240,10 +240,13 @@ typedef struct {
uint8_t filler; uint8_t filler;
float alpha; float alpha;
spritetype *tspr; spritetype *tspr;
#if defined LUNATIC_ENABLE && UINTPTR_MAX == 0xffffffff #if !defined UINTPTR_MAX
# error Need UINTPTR_MAX define to select between 32- and 64-bit structs
#endif
#if UINTPTR_MAX == 0xffffffff
/* On a 32-bit build, pad the struct so it has the same size everywhere. /* On a 32-bit build, pad the struct so it has the same size everywhere.
* REMINDER: Will break savegames. */ * REMINDER: Will break savegames. */
void *dummy_; const intptr_t dummy_;
#endif #endif
} spriteext_t; } spriteext_t;

View file

@ -85,7 +85,7 @@ typedef struct {
int8_t filler[6]; // 6b int8_t filler[6]; // 6b
} projectile_t; } projectile_t;
// (+ 40 8 6 16 16 4 8 6 4 4 16) // (+ 40 8 6 16 16 4 8 6 4 20)
typedef struct { typedef struct {
#ifdef SAMESIZE_ACTOR_T #ifdef SAMESIZE_ACTOR_T
int32_t t_data[10]; // 40b sometimes used to hold offsets to con code int32_t t_data[10]; // 40b sometimes used to hold offsets to con code
@ -108,12 +108,16 @@ typedef struct {
void *lightptr; void *lightptr;
#endif #endif
#if !defined SAMESIZE_ACTOR_T || UINTPTR_MAX == 0xffffffff // pad struct to 128 bytes
/* 32-bit or old, same-declaration version */ #if !defined UINTPTR_MAX
int8_t filler[24]; // pad struct to 128 bytes # error Need UINTPTR_MAX define to select between 32- and 64-bit structs
#endif
#if UINTPTR_MAX == 0xffffffff
/* 32-bit */
const int8_t filler[20];
#else #else
/* 64-bit, will break older savegames */ /* 64-bit */
int8_t filler[16]; const int8_t filler[12];
#endif #endif
} actor_t; } actor_t;

View file

@ -25,6 +25,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "menus.h" #include "menus.h"
#include "savegame.h" #include "savegame.h"
#include <assert.h>
char firstdemofile[BMAX_PATH]; char firstdemofile[BMAX_PATH];
FILE *g_demo_filePtr = (FILE *)NULL; FILE *g_demo_filePtr = (FILE *)NULL;
@ -35,7 +37,7 @@ int32_t g_demo_soundToggle;
int32_t g_demo_paused=0; int32_t g_demo_paused=0;
int32_t g_demo_rewind=0; int32_t g_demo_rewind=0;
int32_t g_demo_showStats=1; int32_t g_demo_showStats=1;
int32_t g_demo_recFilePtr; int32_t g_demo_recFilePtr = -1;
static int32_t demo_hasdiffs, demorec_diffs=1, demorec_difftics = 2*(TICRATE/TICSPERFRAME); static int32_t demo_hasdiffs, demorec_diffs=1, demorec_difftics = 2*(TICRATE/TICSPERFRAME);
int32_t demoplay_diffs=1; int32_t demoplay_diffs=1;
@ -69,11 +71,13 @@ void demo_preparewarp(void)
} }
int32_t G_OpenDemoRead(int32_t g_whichDemo) // 0 = mine static int32_t G_OpenDemoRead(int32_t g_whichDemo) // 0 = mine
{ {
char d[14]; char d[14];
int32_t i; int32_t i;
savehead_t saveh;
Bstrcpy(d, "edemo_.edm"); Bstrcpy(d, "edemo_.edm");
if (g_whichDemo == 10) if (g_whichDemo == 10)
@ -87,40 +91,36 @@ int32_t G_OpenDemoRead(int32_t g_whichDemo) // 0 = mine
} }
else if ((g_demo_recFilePtr = kopen4loadfrommod(d,g_loadFromGroupOnly)) == -1) return(0); else if ((g_demo_recFilePtr = kopen4loadfrommod(d,g_loadFromGroupOnly)) == -1) return(0);
i=sv_loadsnapshot(g_demo_recFilePtr, &demo_hasdiffs, &g_demo_totalCnt, &demo_synccompress); assert(g_whichDemo >= 1);
if (i==0) i = sv_loadsnapshot(g_demo_recFilePtr, -g_whichDemo, &saveh);
{ if (i)
demo_hasseeds = demo_synccompress&2;
demo_synccompress &= 1;
i = g_demo_totalCnt/(TICRATE/TICSPERFRAME);
OSD_Printf("demo duration: %d min %d sec\n", i/60, i%60);
g_demo_cnt=1;
ud.reccnt = 0;
ud.god = ud.cashman = ud.eog = ud.showallmap = 0;
ud.clipping = ud.scrollmode = ud.overhead_on = 0; //= ud.pause_on = 0;
// G_NewGame(ud.volume_number,ud.level_number,ud.player_skill);
// G_ResetTimers();
totalclock = ototalclock = lockclock = 0;
return 1;
}
else
{ {
OSD_Printf(OSD_ERROR "There were errors opening demo %d (code: %d).\n", g_whichDemo, i); OSD_Printf(OSD_ERROR "There were errors opening demo %d (code: %d).\n", g_whichDemo, i);
kclose(g_demo_recFilePtr); kclose(g_demo_recFilePtr); g_demo_recFilePtr = -1;
return 0; return 0;
} }
#if 0
corrupt: demo_hasdiffs = saveh.recdiffsp;
OSD_Printf(OSD_ERROR "Demo %d header is corrupt.\n",g_whichDemo); g_demo_totalCnt = saveh.reccnt;
demo_synccompress = saveh.synccompress;
demo_hasseeds = demo_synccompress&2;
demo_synccompress &= 1;
i = g_demo_totalCnt/(TICRATE/TICSPERFRAME);
OSD_Printf("demo duration: %d min %d sec\n", i/60, i%60);
g_demo_cnt=1;
ud.reccnt = 0; ud.reccnt = 0;
kclose(g_demo_recFilePtr);
return 0; ud.god = ud.cashman = ud.eog = ud.showallmap = 0;
#endif ud.clipping = ud.scrollmode = ud.overhead_on = 0; //= ud.pause_on = 0;
// G_NewGame(ud.volume_number,ud.level_number,ud.player_skill);
// G_ResetTimers();
totalclock = ototalclock = lockclock = 0;
return 1;
} }
#if KRANDDEBUG #if KRANDDEBUG
@ -133,7 +133,11 @@ void G_OpenDemoWrite(void)
char d[14]; char d[14];
int32_t i, demonum=1; int32_t i, demonum=1;
if (ud.recstat == 2) kclose(g_demo_recFilePtr); if (ud.recstat == 2)
{
kclose(g_demo_recFilePtr);
g_demo_recFilePtr = -1;
}
if ((g_player[myconnectindex].ps->gm&MODE_GAME) && g_player[myconnectindex].ps->dead_flag) if ((g_player[myconnectindex].ps->gm&MODE_GAME) && g_player[myconnectindex].ps->dead_flag)
{ {
@ -178,7 +182,7 @@ void G_OpenDemoWrite(void)
if ((g_demo_filePtr = Bfopen(d,"wb")) == NULL) return; if ((g_demo_filePtr = Bfopen(d,"wb")) == NULL) return;
i=sv_saveandmakesnapshot(g_demo_filePtr, demorec_diffs_cvar, demorec_diffcompress_cvar, i=sv_saveandmakesnapshot(g_demo_filePtr, -1, demorec_diffs_cvar, demorec_diffcompress_cvar,
demorec_synccompress_cvar|(demorec_seeds_cvar<<1)); demorec_synccompress_cvar|(demorec_seeds_cvar<<1));
if (i) if (i)
{ {
@ -260,8 +264,9 @@ void G_CloseDemoWrite(void)
fwrite("EnD!", 4, 1, g_demo_filePtr); fwrite("EnD!", 4, 1, g_demo_filePtr);
if (fseek(g_demo_filePtr, 20, SEEK_SET)) // lastly, we need to write the number of written recsyncs to the demo file
perror("G_CloseDemoWrite: fseek"); if (fseek(g_demo_filePtr, offsetof(savehead_t, reccnt), SEEK_SET))
perror("G_CloseDemoWrite: final fseek");
else else
fwrite(&g_demo_cnt, sizeof(g_demo_cnt), 1, g_demo_filePtr); fwrite(&g_demo_cnt, sizeof(g_demo_cnt), 1, g_demo_filePtr);
@ -411,7 +416,6 @@ RECHECK:
} }
else else
{ {
// j = sv_loadsnapshot(g_demo_recFilePtr, &g_demo_totalCnt);
j = doupdatestate(1); j = doupdatestate(1);
if (!j) if (!j)
{ {
@ -486,7 +490,7 @@ corrupt:
nextdemo: nextdemo:
foundemo = 0; foundemo = 0;
ud.reccnt = 0; ud.reccnt = 0;
kclose(g_demo_recFilePtr); kclose(g_demo_recFilePtr); g_demo_recFilePtr = -1;
g_player[myconnectindex].ps->gm |= MODE_MENU; g_player[myconnectindex].ps->gm |= MODE_MENU;
if (g_demo_goalCnt>0) if (g_demo_goalCnt>0)
{ {
@ -502,7 +506,7 @@ nextdemo:
TRAVERSE_CONNECT(j) TRAVERSE_CONNECT(j)
{ {
copybufbyte(&recsync[bigi], &inputfifo[0][j], sizeof(input_t)); Bmemcpy(&inputfifo[0][j], &recsync[bigi], sizeof(input_t));
bigi++; bigi++;
ud.reccnt--; ud.reccnt--;
} }
@ -663,13 +667,13 @@ nextdemo:
#if KRANDDEBUG #if KRANDDEBUG
krd_print("krandplay.log"); krd_print("krandplay.log");
#endif #endif
kclose(g_demo_recFilePtr); kclose(g_demo_recFilePtr); g_demo_recFilePtr = -1;
} }
return 0; return 0;
} }
} }
ud.multimode = numplayers; // fixes 2 infinite loops after watching demo ud.multimode = numplayers; // fixes 2 infinite loops after watching demo
kclose(g_demo_recFilePtr); kclose(g_demo_recFilePtr); g_demo_recFilePtr = -1;
#if 0 #if 0
{ {

View file

@ -43,7 +43,6 @@ extern int32_t g_demo_showStats;
extern int32_t g_demo_soundToggle; extern int32_t g_demo_soundToggle;
extern int32_t g_demo_totalCnt; extern int32_t g_demo_totalCnt;
int32_t G_OpenDemoRead(int32_t g_whichDemo);
int32_t G_PlaybackDemo(void); int32_t G_PlaybackDemo(void);
void demo_preparewarp(void); void demo_preparewarp(void);
void G_CloseDemoWrite(void); void G_CloseDemoWrite(void);

View file

@ -7784,9 +7784,16 @@ FAKE_F3:
/* inputloc = Bstrlen(&ud.savegame[g_lastSaveSlot][0]); /* inputloc = Bstrlen(&ud.savegame[g_lastSaveSlot][0]);
g_currentMenu = 360+g_lastSaveSlot; g_currentMenu = 360+g_lastSaveSlot;
probey = g_lastSaveSlot; */ probey = g_lastSaveSlot; */
if ((g_netServer || ud.multimode > 1)) if (g_netServer || ud.multimode > 1)
G_SavePlayer(-1-(g_lastSaveSlot)); {
else G_SavePlayer(g_lastSaveSlot); Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "MULTIPLAYER SAVING NOT SUPPORTED YET");
P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
//G_SavePlayer(-1-(g_lastSaveSlot));
}
else
{
G_SavePlayer(g_lastSaveSlot);
}
} }
} }
@ -7844,10 +7851,13 @@ FAKE_F3:
KB_ClearKeysDown(); KB_ClearKeysDown();
FX_StopAllSounds(); FX_StopAllSounds();
if ((g_netServer || ud.multimode > 1)) if (g_netServer || ud.multimode > 1)
{ {
G_LoadPlayer(-1-g_lastSaveSlot); Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "MULTIPLAYER LOADING NOT SUPPORTED YET");
g_player[myconnectindex].ps->gm = MODE_GAME; P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
// G_LoadPlayer(-1-g_lastSaveSlot);
// g_player[myconnectindex].ps->gm = MODE_GAME;
} }
else else
{ {

View file

@ -34,7 +34,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <sys/stat.h> #include <sys/stat.h>
extern char inputloc; extern char inputloc;
extern int32_t g_demo_recFilePtr;
int16_t g_skillSoundID=-1; int16_t g_skillSoundID=-1;
int32_t probey=0; int32_t probey=0;
static int32_t lastsavehead=0,last_menu_pos=0,last_menu,sh,onbar,buttonstat; static int32_t lastsavehead=0,last_menu_pos=0,last_menu,sh,onbar,buttonstat;
@ -472,10 +471,11 @@ static void modval(int32_t min, int32_t max,int32_t *p,int32_t dainc,int32_t dam
#define MWIN(X) rotatesprite( 320<<15,200<<15,X,0,MENUSCREEN,-16,0,10+64,0,0,xdim-1,ydim-1) #define MWIN(X) rotatesprite( 320<<15,200<<15,X,0,MENUSCREEN,-16,0,10+64,0,0,xdim-1,ydim-1)
#define MWINXY(X,OX,OY) rotatesprite( ( 320+(OX) )<<15, ( 200+(OY) )<<15,X,0,MENUSCREEN,-16,0,10+64,0,0,xdim-1,ydim-1) #define MWINXY(X,OX,OY) rotatesprite( ( 320+(OX) )<<15, ( 200+(OY) )<<15,X,0,MENUSCREEN,-16,0,10+64,0,0,xdim-1,ydim-1)
extern int32_t G_LoadSaveHeader(char spot,struct savehead_ *saveh); //extern int32_t G_LoadSaveHeader(char spot,struct savehead_ *saveh);
#pragma pack(push,1) #pragma pack(push,1)
static struct savehead_ savehead; static savehead_t savehead;
//static struct savehead_ savehead;
#pragma pack(pop) #pragma pack(pop)
//static int32_t volnum,levnum,plrskl,numplr; //static int32_t volnum,levnum,plrskl,numplr;
@ -559,7 +559,7 @@ void G_CheckPlayerColor(int32_t *color, int32_t prev_color)
static void Menus_LoadSave_DisplayCommon1(void) static void Menus_LoadSave_DisplayCommon1(void)
{ {
if (lastsavehead != probey) if (lastsavehead != probey)
G_LoadSaveHeader(probey,&savehead); G_LoadSaveHeaderNew(probey, &savehead);
lastsavehead = probey; lastsavehead = probey;
rotatesprite(101<<16,97<<16,65536L>>1,512,TILE_LOADSHOT,-32,0,4+10+64,0,0,xdim-1,ydim-1); rotatesprite(101<<16,97<<16,65536L>>1,512,TILE_LOADSHOT,-32,0,4+10+64,0,0,xdim-1,ydim-1);
@ -567,9 +567,9 @@ static void Menus_LoadSave_DisplayCommon1(void)
if (ud.savegame[probey][20] == 32) if (ud.savegame[probey][20] == 32)
{ {
menutext(40,70,0,0,"OLD VERSION"); menutext(40,70,0,0,"OLD VERSION");
Bsprintf(tempbuf,"SAVED: %d", savehead.byteversion); Bsprintf(tempbuf,"SAVED: %d.%d.%d", savehead.majorver, savehead.minorver, savehead.bytever);
mgametext(40,82,tempbuf,0,2+8+16); mgametext(40,82,tempbuf,0,2+8+16);
Bsprintf(tempbuf,"OUR: %d", BYTEVERSION); Bsprintf(tempbuf,"OUR: %d.%d.%d", SV_MAJOR_VER, SV_MINOR_VER, BYTEVERSION);
mgametext(40+16,92,tempbuf,0,2+8+16); mgametext(40+16,92,tempbuf,0,2+8+16);
} }
} }
@ -1342,10 +1342,13 @@ void M_DisplayMenus(void)
KB_ClearKeysDown(); KB_ClearKeysDown();
FX_StopAllSounds(); FX_StopAllSounds();
if ((g_netServer || ud.multimode > 1)) if (g_netServer || ud.multimode > 1)
{ {
G_LoadPlayer(-1-g_lastSaveSlot); Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "MULTIPLAYER LOADING NOT SUPPORTED YET");
g_player[myconnectindex].ps->gm = MODE_GAME; P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
// G_LoadPlayer(-1-g_lastSaveSlot);
// g_player[myconnectindex].ps->gm = MODE_GAME;
} }
else else
{ {
@ -1477,10 +1480,11 @@ void M_DisplayMenus(void)
M_DisplaySaveGameList(); M_DisplaySaveGameList();
Bsprintf(tempbuf,"PLAYERS: %-2d ",savehead.numplr); Bsprintf(tempbuf,"PLAYERS: %-2d ",savehead.numplayers);
mgametext(160,156,tempbuf,0,2+8+16); mgametext(160,156,tempbuf,0,2+8+16);
Bsprintf(tempbuf,"EPISODE: %-2d / LEVEL: %-2d / SKILL: %-2d",1+savehead.volnum,1+savehead.levnum,savehead.plrskl); Bsprintf(tempbuf,"EPISODE: %-2d / LEVEL: %-2d / SKILL: %-2d",
1+savehead.volnum, 1+savehead.levnum, savehead.skill);
mgametext(160,168,tempbuf,0,2+8+16); mgametext(160,168,tempbuf,0,2+8+16);
if (savehead.volnum == 0 && savehead.levnum == 7) if (savehead.volnum == 0 && savehead.levnum == 7)
@ -4740,9 +4744,16 @@ cheat_for_port_credits:
ud.savegame[g_currentMenu-360][20] = 127; ud.savegame[g_currentMenu-360][20] = 127;
} }
if ((g_netServer || ud.multimode > 1)) if (g_netServer || ud.multimode > 1)
G_SavePlayer(-1-(g_currentMenu-360)); {
else G_SavePlayer(g_currentMenu-360); Bstrcpy(ScriptQuotes[QUOTE_RESERVED4], "MULTIPLAYER SAVING NOT SUPPORTED YET");
P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
//G_SavePlayer(-1-(g_currentMenu-360));
}
else
{
G_SavePlayer(g_currentMenu-360);
}
g_lastSaveSlot = g_currentMenu-360; g_lastSaveSlot = g_currentMenu-360;
g_player[myconnectindex].ps->gm = MODE_GAME; g_player[myconnectindex].ps->gm = MODE_GAME;
@ -4773,9 +4784,10 @@ cheat_for_port_credits:
{ {
Menus_LoadSave_DisplayCommon1(); Menus_LoadSave_DisplayCommon1();
Bsprintf(tempbuf,"PLAYERS: %-2d ",savehead.numplr); Bsprintf(tempbuf,"PLAYERS: %-2d ", savehead.numplayers);
mgametext(160,156,tempbuf,0,2+8+16); mgametext(160,156,tempbuf,0,2+8+16);
Bsprintf(tempbuf,"EPISODE: %-2d / LEVEL: %-2d / SKILL: %-2d",1+savehead.volnum,1+savehead.levnum,savehead.plrskl); Bsprintf(tempbuf,"EPISODE: %-2d / LEVEL: %-2d / SKILL: %-2d",
1+savehead.volnum, 1+savehead.levnum, savehead.skill);
mgametext(160,168,tempbuf,0,2+8+16); mgametext(160,168,tempbuf,0,2+8+16);
if (savehead.volnum == 0 && savehead.levnum == 7) if (savehead.volnum == 0 && savehead.levnum == 7)
mgametext(160,180,savehead.boardfn,0,2+8+16); mgametext(160,180,savehead.boardfn,0,2+8+16);

View file

@ -27,14 +27,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern char inputloc; extern char inputloc;
extern int16_t g_skillSoundID; extern int16_t g_skillSoundID;
extern int32_t g_demo_recFilePtr;
extern int32_t g_lastSaveSlot; extern int32_t g_lastSaveSlot;
extern int32_t g_quitDeadline; extern int32_t g_quitDeadline;
extern int32_t probey; extern int32_t probey;
extern int32_t voting; extern int32_t voting;
int32_t G_LoadSaveHeader(char spot,struct savehead_ *saveh);
int32_t menutext_(int32_t x,int32_t y,int32_t s,int32_t p,char *t,int32_t bits); int32_t menutext_(int32_t x,int32_t y,int32_t s,int32_t p,char *t,int32_t bits);
void ChangeToMenu(int32_t cm); void ChangeToMenu(int32_t cm);
void G_CheckPlayerColor(int32_t *color,int32_t prev_color); void G_CheckPlayerColor(int32_t *color,int32_t prev_color);
void M_DisplayMenus(void); void M_DisplayMenus(void);
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef __savegame_h__ #ifndef __savegame_h__
#define __savegame_h__ #define __savegame_h__
#define SV_MAJOR_VER 1
#define SV_MINOR_VER 1
#pragma pack(push,1) #pragma pack(push,1)
# if 0
struct savehead_ struct savehead_
{ {
char name[21]; char name[21];
@ -31,17 +35,41 @@ struct savehead_
int32_t numplr,volnum,levnum,plrskl; int32_t numplr,volnum,levnum,plrskl;
char boardfn[BMAX_PATH]; char boardfn[BMAX_PATH];
}; };
# endif
typedef struct
{
char headerstr[11];
uint8_t majorver, minorver, ptrsize;
uint16_t bytever;
// 16 bytes
uint8_t comprthres;
uint8_t recdiffsp, diffcompress, synccompress;
// 4 bytes
int32_t reccnt, snapsiz;
// 8 bytes
char savename[22]; // should be of the same length as ud.savegame[i]
uint8_t numplayers, volnum, levnum, skill;
char boardfn[256]; // BMAX_PATH
// 282 bytes
} savehead_t; // 310 bytes
#pragma pack(pop) #pragma pack(pop)
int32_t sv_updatestate(int32_t frominit); int32_t sv_updatestate(int32_t frominit);
int32_t sv_readdiff(int32_t fil); int32_t sv_readdiff(int32_t fil);
uint32_t sv_writediff(FILE *fil); uint32_t sv_writediff(FILE *fil);
int32_t sv_loadsnapshot(int32_t fil,int32_t *ret_hasdiffs,int32_t *ret_demoticcnt,int32_t *ret_synccompress); int32_t sv_loadheader(int32_t fil, int32_t spot, savehead_t *h);
int32_t sv_saveandmakesnapshot(FILE *fil,int32_t recdiffs,int32_t diffcompress,int32_t synccompress); int32_t sv_loadsnapshot(int32_t fil, int32_t spot, savehead_t *h);
int32_t sv_saveandmakesnapshot(FILE *fil, int8_t spot, int8_t recdiffsp, int8_t diffcompress, int8_t synccompress);
void sv_freemem(); void sv_freemem();
int32_t G_SavePlayer(int32_t spot); int32_t G_SavePlayer(int32_t spot);
int32_t G_LoadPlayer(int32_t spot); int32_t G_LoadPlayer(int32_t spot);
int32_t G_LoadSaveHeader(char spot,struct savehead_ *saveh); int32_t G_LoadSaveHeaderNew(int32_t spot, savehead_t *saveh);
//int32_t G_LoadSaveHeader(char spot,struct savehead_ *saveh);
void ReadSaveGameHeaders(void); void ReadSaveGameHeaders(void);
extern char *bitptr; extern char *bitptr;