mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
G_DirtyGameData: Dirty bit only applied in I_Error and signal handlers, nowhere else
- Unfortunately, the way this system previously worked, the unlock was given to you for free if you accidentially opened two copies of the game at once.
- Instead, open the file in r+ mode, shimmy along 5 bytes, and write a `true` to be read later.
- Far more memory safe than rewriting the entire gamedata out on crash.
ALSO:
- crashflags has been split into boolean evercrashed and UINT8 musicflags.
- We don't need to track if the LAST session was a crash, at least not right now.
- Opens the floor up to other music like Loser Club happening on the Challenges menu.
This commit is contained in:
parent
c33ae4ae62
commit
3e900d7f57
18 changed files with 86 additions and 49 deletions
|
|
@ -1051,7 +1051,7 @@ void D_ClearState(void)
|
|||
cursongcredit.def = NULL;
|
||||
|
||||
if (gamedata && gamedata->deferredsave)
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
|
||||
G_SetGamestate(GS_NULL);
|
||||
wipegamestate = GS_NULL;
|
||||
|
|
|
|||
|
|
@ -2931,7 +2931,7 @@ void readmaincfg(MYFILE *f, boolean mainfile)
|
|||
if (!GoodDataFileName(word2))
|
||||
I_Error("Maincfg: bad data file name '%s'\n", word2);
|
||||
|
||||
G_SaveGameData(false); // undirty your old gamedata
|
||||
G_SaveGameData();
|
||||
strlcpy(gamedatafilename, word2, sizeof (gamedatafilename));
|
||||
strlwr(gamedatafilename);
|
||||
savemoddata = true;
|
||||
|
|
|
|||
|
|
@ -1084,7 +1084,7 @@ void F_GameEvaluationTicker(void)
|
|||
++gamedata->timesBeaten;
|
||||
|
||||
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4196,7 +4196,7 @@ void G_SaveDemo(void)
|
|||
{
|
||||
gamedata->eversavedreplay = true;
|
||||
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
61
src/g_game.c
61
src/g_game.c
|
|
@ -3834,7 +3834,7 @@ static void G_UpdateVisited(void)
|
|||
CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
|
||||
|
||||
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
|
||||
static boolean CanSaveLevel(INT32 mapnum)
|
||||
|
|
@ -3926,7 +3926,7 @@ static void G_GetNextMap(void)
|
|||
{
|
||||
gamedata->everseenspecial = true;
|
||||
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4161,7 +4161,7 @@ static void G_DoCompleted(void)
|
|||
}
|
||||
|
||||
if (gamedata->deferredsave)
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
|
||||
legitimateexit = false;
|
||||
|
||||
|
|
@ -4567,6 +4567,11 @@ void G_LoadGameData(void)
|
|||
gridunusable = true;
|
||||
}
|
||||
|
||||
if (versionMinor > 1)
|
||||
{
|
||||
gamedata->evercrashed = (boolean)READUINT8(save.p);
|
||||
}
|
||||
|
||||
gamedata->totalplaytime = READUINT32(save.p);
|
||||
|
||||
if (versionMinor > 1)
|
||||
|
|
@ -4583,10 +4588,6 @@ void G_LoadGameData(void)
|
|||
gamedata->keyspending = READUINT8(save.p);
|
||||
gamedata->chaokeys = READUINT16(save.p);
|
||||
|
||||
gamedata->crashflags = READUINT8(save.p);
|
||||
if (gamedata->crashflags & GDCRASH_LAST)
|
||||
gamedata->crashflags |= GDCRASH_ANY;
|
||||
|
||||
gamedata->everloadedaddon = (boolean)READUINT8(save.p);
|
||||
gamedata->eversavedreplay = (boolean)READUINT8(save.p);
|
||||
gamedata->everseenspecial = (boolean)READUINT8(save.p);
|
||||
|
|
@ -4782,9 +4783,34 @@ void G_LoadGameData(void)
|
|||
}
|
||||
}
|
||||
|
||||
// G_DirtyGameData
|
||||
// Modifies the gamedata as little as possible to maintain safety in a crash event, while still recording it.
|
||||
void G_DirtyGameData(void)
|
||||
{
|
||||
FILE *handle = NULL;
|
||||
const UINT8 writebytesource = true;
|
||||
|
||||
if (gamedata)
|
||||
gamedata->evercrashed = true;
|
||||
|
||||
//if (FIL_WriteFileOK(name))
|
||||
handle = fopen(va(pandf, srb2home, gamedatafilename), "r+");
|
||||
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
// Write a dirty byte immediately after the gamedata check + minor version.
|
||||
if (fseek(handle, 5, SEEK_SET) != -1)
|
||||
fwrite(&writebytesource, 1, 1, handle);
|
||||
|
||||
fclose(handle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// G_SaveGameData
|
||||
// Saves the main data file, which stores information such as emblems found, etc.
|
||||
void G_SaveGameData(boolean dirty)
|
||||
void G_SaveGameData(void)
|
||||
{
|
||||
size_t length;
|
||||
INT32 i, j, numcups;
|
||||
|
|
@ -4805,10 +4831,11 @@ void G_SaveGameData(boolean dirty)
|
|||
return;
|
||||
}
|
||||
|
||||
length = (4+1+4+4+
|
||||
length = (4+1+1+
|
||||
4+4+
|
||||
(4*GDGT_MAX)+
|
||||
4+1+1+2+
|
||||
1+1+1+1+
|
||||
1+1+1+
|
||||
4+
|
||||
(MAXEMBLEMS+(MAXUNLOCKABLES*2)+MAXCONDITIONSETS)+
|
||||
4+2);
|
||||
|
|
@ -4836,6 +4863,13 @@ void G_SaveGameData(boolean dirty)
|
|||
|
||||
WRITEUINT32(save.p, GD_VERSIONCHECK); // 4
|
||||
WRITEUINT8(save.p, GD_VERSIONMINOR); // 1
|
||||
|
||||
// Crash dirtiness
|
||||
// cannot move, see G_DirtyGameData
|
||||
WRITEUINT8(save.p, gamedata->evercrashed); // 1
|
||||
|
||||
// Statistics
|
||||
|
||||
WRITEUINT32(save.p, gamedata->totalplaytime); // 4
|
||||
WRITEUINT32(save.p, gamedata->totalrings); // 4
|
||||
|
||||
|
|
@ -4849,13 +4883,6 @@ void G_SaveGameData(boolean dirty)
|
|||
WRITEUINT8(save.p, gamedata->keyspending); // 1
|
||||
WRITEUINT16(save.p, gamedata->chaokeys); // 2
|
||||
|
||||
{
|
||||
UINT8 crashflags = (gamedata->crashflags & GDCRASH_ANY);
|
||||
if (dirty)
|
||||
crashflags |= GDCRASH_LAST;
|
||||
WRITEUINT8(save.p, crashflags); // 1
|
||||
}
|
||||
|
||||
WRITEUINT8(save.p, gamedata->everloadedaddon); // 1
|
||||
WRITEUINT8(save.p, gamedata->eversavedreplay); // 1
|
||||
WRITEUINT8(save.p, gamedata->everseenspecial); // 1
|
||||
|
|
|
|||
|
|
@ -175,7 +175,8 @@ boolean G_IsTitleCardAvailable(void);
|
|||
// Can be called by the startup code or M_Responder, calls P_SetupLevel.
|
||||
void G_LoadGame(UINT32 slot, INT16 mapoverride);
|
||||
|
||||
void G_SaveGameData(boolean dirty);
|
||||
void G_SaveGameData(void);
|
||||
void G_DirtyGameData(void);
|
||||
|
||||
void G_SaveGame(UINT32 slot, INT16 mapnum);
|
||||
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ void M_PlayMenuJam(void)
|
|||
{
|
||||
menu_t *refMenu = (menuactive ? currentMenu : restoreMenu);
|
||||
static boolean loserclubpermitted = false;
|
||||
boolean loserclub = (loserclubpermitted && (gamedata->crashflags & GDCRASH_LOSERCLUB));
|
||||
boolean loserclub = (loserclubpermitted && (gamedata->musicflags & GDMUSIC_LOSERCLUB));
|
||||
|
||||
if (challengesmenu.pending)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ void K_FinishCeremony(void)
|
|||
|
||||
// Play the noise now
|
||||
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -339,7 +339,7 @@ void K_ResetCeremony(void)
|
|||
grandprixinfo.cup->windata[i].got_emerald = true;
|
||||
|
||||
// Save before playing the noise
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ void K_CashInPowerLevels(void)
|
|||
if (gamedataupdate)
|
||||
{
|
||||
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
|
||||
//CONS_Printf("========\n");
|
||||
|
|
@ -644,6 +644,6 @@ void K_PlayerForfeit(UINT8 playerNum, boolean pointLoss)
|
|||
pr->powerlevels[powerType] = yourPower + inc;
|
||||
|
||||
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -529,7 +529,8 @@ void M_ClearStats(void)
|
|||
gamedata->everloadedaddon = false;
|
||||
gamedata->eversavedreplay = false;
|
||||
gamedata->everseenspecial = false;
|
||||
gamedata->crashflags = 0;
|
||||
gamedata->evercrashed = false;
|
||||
gamedata->musicflags = 0;
|
||||
}
|
||||
|
||||
void M_ClearSecrets(void)
|
||||
|
|
@ -764,9 +765,9 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
|
|||
case UC_REPLAY:
|
||||
return (gamedata->eversavedreplay == true);
|
||||
case UC_CRASH:
|
||||
if (gamedata->crashflags & (GDCRASH_LAST|GDCRASH_ANY))
|
||||
if (gamedata->evercrashed)
|
||||
{
|
||||
gamedata->crashflags |= GDCRASH_LOSERCLUB;
|
||||
gamedata->musicflags |= GDMUSIC_LOSERCLUB;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -1224,7 +1225,7 @@ static const char *M_GetConditionString(condition_t *cn)
|
|||
case UC_REPLAY:
|
||||
return "save a replay after finishing a round";
|
||||
case UC_CRASH:
|
||||
if (gamedata->crashflags & (GDCRASH_LAST|GDCRASH_ANY))
|
||||
if (gamedata->evercrashed)
|
||||
return "launch \"Dr. Robotnik's Ring Racers\" again after a game crash";
|
||||
return NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -217,9 +217,7 @@ typedef enum
|
|||
#endif
|
||||
#define challengegridloops (gamedata->challengegridwidth >= CHALLENGEGRIDLOOPWIDTH)
|
||||
|
||||
#define GDCRASH_LAST 0x01
|
||||
#define GDCRASH_ANY 0x02
|
||||
#define GDCRASH_LOSERCLUB 0x04
|
||||
#define GDMUSIC_LOSERCLUB 0x01
|
||||
|
||||
// This is the largest number of 9s that will fit in UINT32 and UINT16 respectively.
|
||||
#define GDMAX_RINGS 999999999
|
||||
|
|
@ -281,7 +279,8 @@ struct gamedata_t
|
|||
boolean everloadedaddon;
|
||||
boolean eversavedreplay;
|
||||
boolean everseenspecial;
|
||||
UINT8 crashflags;
|
||||
boolean evercrashed;
|
||||
UINT8 musicflags;
|
||||
};
|
||||
|
||||
extern gamedata_t *gamedata;
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ void M_ChallengesTick(void)
|
|||
{
|
||||
// All done! Let's save the unlocks we've busted open.
|
||||
challengesmenu.pending = challengesmenu.chaokeyadd = false;
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
}
|
||||
else if (challengesmenu.pending)
|
||||
|
|
|
|||
|
|
@ -7501,7 +7501,7 @@ static void P_InitGametype(void)
|
|||
|
||||
// Started a game? Move on to the next jam when you go back to the title screen
|
||||
CV_SetValue(&cv_menujam_update, 1);
|
||||
gamedata->crashflags &= ~GDCRASH_LOSERCLUB;
|
||||
gamedata->musicflags = 0;
|
||||
}
|
||||
|
||||
struct minimapinfo minimapinfo;
|
||||
|
|
@ -7995,7 +7995,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
mapheaderinfo[gamemap-1]->mapvisited |= MV_VISITED;
|
||||
|
||||
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
|
||||
G_AddMapToBuffer(gamemap-1);
|
||||
|
|
|
|||
|
|
@ -620,7 +620,7 @@ void P_Ticker(boolean run)
|
|||
// TODO would this be laggy with more conditions in play...
|
||||
if (((!demo.playback && leveltime > introtime && M_UpdateUnlockablesAndExtraEmblems(true, false))
|
||||
|| (gamedata && gamedata->deferredsave)))
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
|
||||
// Keep track of how long they've been playing!
|
||||
|
|
|
|||
|
|
@ -328,6 +328,7 @@ FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num)
|
|||
{
|
||||
D_QuitNetGame(); // Fix server freezes
|
||||
CL_AbortDownloadResume();
|
||||
G_DirtyGameData();
|
||||
#ifdef UNIXBACKTRACE
|
||||
write_backtrace(num);
|
||||
#endif
|
||||
|
|
@ -1448,7 +1449,7 @@ void I_Quit(void)
|
|||
if (Playing())
|
||||
K_PlayerForfeit(consoleplayer, true);
|
||||
|
||||
G_SaveGameData(false); // Tails 12-08-2002 -- undirty your save
|
||||
G_SaveGameData(); // Tails 12-08-2002
|
||||
//added:16-02-98: when recording a demo, should exit using 'q' key,
|
||||
// but sometimes we forget and use 'F10'.. so save here too.
|
||||
|
||||
|
|
@ -1532,7 +1533,8 @@ void I_Error(const char *error, ...)
|
|||
if (errorcount == 8)
|
||||
{
|
||||
M_SaveConfig(NULL);
|
||||
G_SaveGameData(true);
|
||||
G_DirtyGameData(); // done first in case an error is in G_SaveGameData
|
||||
G_SaveGameData();
|
||||
}
|
||||
if (errorcount > 20)
|
||||
{
|
||||
|
|
@ -1563,7 +1565,8 @@ void I_Error(const char *error, ...)
|
|||
|
||||
M_SaveConfig(NULL); // save game config, cvars..
|
||||
D_SaveBan(); // save the ban list
|
||||
G_SaveGameData(true); // Tails 12-08-2002
|
||||
G_DirtyGameData(); // done first in case an error is in G_SaveGameData
|
||||
G_SaveGameData(); // Tails 12-08-2002
|
||||
|
||||
// Shutdown. Here might be other errors.
|
||||
|
||||
|
|
|
|||
|
|
@ -357,6 +357,7 @@ static void signal_handler(INT32 num)
|
|||
sigmsg = sigdef;
|
||||
}
|
||||
|
||||
G_DirtyGameData();
|
||||
I_OutputMsg("signal_handler() error: %s\n", sigmsg);
|
||||
signal(num, SIG_DFL); //default signal action
|
||||
raise(num);
|
||||
|
|
@ -2983,7 +2984,7 @@ void I_Quit(void)
|
|||
if (Playing())
|
||||
K_PlayerForfeit(consoleplayer, true);
|
||||
|
||||
G_SaveGameData(false); // Tails 12-08-2002 -- undirty your save
|
||||
G_SaveGameData(); // Tails 12-08-2002
|
||||
//added:16-02-98: when recording a demo, should exit using 'q' key,
|
||||
// but sometimes we forget and use 'F10'.. so save here too.
|
||||
|
||||
|
|
@ -3078,7 +3079,8 @@ void I_Error(const char *error, ...)
|
|||
if (errorcount == 9)
|
||||
{
|
||||
M_SaveConfig(NULL);
|
||||
G_SaveGameData(true);
|
||||
G_DirtyGameData(); // done first in case an error is in G_SaveGameData
|
||||
G_SaveGameData();
|
||||
}
|
||||
if (errorcount > 20)
|
||||
{
|
||||
|
|
@ -3142,7 +3144,8 @@ void I_Error(const char *error, ...)
|
|||
#ifndef NONET
|
||||
D_SaveBan(); // save the ban list
|
||||
#endif
|
||||
G_SaveGameData(true); // Tails 12-08-2002
|
||||
G_DirtyGameData(); // done first in case an error is in G_SaveGameData
|
||||
G_SaveGameData(); // Tails 12-08-2002
|
||||
|
||||
// Shutdown. Here might be other errors.
|
||||
if (demorecording)
|
||||
|
|
|
|||
|
|
@ -819,7 +819,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
|
|||
{
|
||||
gamedata->everloadedaddon = true;
|
||||
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
||||
G_SaveGameData(true);
|
||||
G_SaveGameData();
|
||||
}
|
||||
|
||||
switch(type = ResourceFileDetect(filename))
|
||||
|
|
|
|||
|
|
@ -469,6 +469,7 @@ static void signal_handler(int num)
|
|||
char sigdef[64];
|
||||
|
||||
D_QuitNetGame(); // Fix server freezes
|
||||
G_DirtyGameData();
|
||||
I_ShutdownSystem();
|
||||
|
||||
switch (num)
|
||||
|
|
@ -607,7 +608,8 @@ void I_Error(const char *error, ...)
|
|||
if (errorcount == 7)
|
||||
{
|
||||
M_SaveConfig(NULL);
|
||||
G_SaveGameData(true);
|
||||
G_DirtyGameData(); // done first in case an error is in G_SaveGameData
|
||||
G_SaveGameData();
|
||||
}
|
||||
if (errorcount > 20)
|
||||
{
|
||||
|
|
@ -636,7 +638,8 @@ void I_Error(const char *error, ...)
|
|||
if (!errorcount)
|
||||
{
|
||||
M_SaveConfig(NULL); // save game config, cvars..
|
||||
G_SaveGameData(true);
|
||||
G_DirtyGameData(); // done first in case an error is in G_SaveGameData
|
||||
G_SaveGameData();
|
||||
}
|
||||
|
||||
// save demo, could be useful for debug
|
||||
|
|
@ -726,7 +729,7 @@ void I_Quit(void)
|
|||
G_CheckDemoStatus();
|
||||
|
||||
M_SaveConfig(NULL); // save game config, cvars..
|
||||
G_SaveGameData(false); // undirty your save
|
||||
G_SaveGameData(); // undirty your save
|
||||
|
||||
// maybe it needs that the ticcount continues,
|
||||
// or something else that will be finished by I_ShutdownSystem(),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue