- use std::unique_ptr to manage the resource file for loading a savegame because the try/catch handler to ensure its deletion was causing some problems.

This commit is contained in:
Christoph Oelckers 2017-01-22 20:04:38 +01:00
parent f9ef935840
commit f15b051327
1 changed files with 135 additions and 153 deletions

View File

@ -1891,168 +1891,150 @@ void G_DoLoadGame ()
hidecon = gameaction == ga_loadgamehidecon;
gameaction = ga_nothing;
FResourceFile *resfile = FResourceFile::OpenResourceFile(savename.GetChars(), nullptr, true, true);
std::unique_ptr<FResourceFile> resfile(FResourceFile::OpenResourceFile(savename.GetChars(), nullptr, true, true));
if (resfile == nullptr)
{
Printf ("Could not read savegame '%s'\n", savename.GetChars());
return;
}
try
FResourceLump *info = resfile->FindLump("info.json");
if (info == nullptr)
{
FResourceLump *info = resfile->FindLump("info.json");
if (info == nullptr)
{
delete resfile;
Printf("'%s' is not a valid savegame: Missing 'info.json'.\n", savename.GetChars());
return;
}
SaveVersion = 0;
void *data = info->CacheLump();
FSerializer arc;
if (!arc.OpenReader((const char *)data, info->LumpSize))
{
Printf("Failed to access savegame info\n");
delete resfile;
return;
}
// Check whether this savegame actually has been created by a compatible engine.
// Since there are ZDoom derivates using the exact same savegame format but
// with mutual incompatibilities this check simplifies things significantly.
FString savever, engine, map;
arc("Save Version", SaveVersion);
arc("Engine", engine);
arc("Current Map", map);
if (engine.CompareNoCase(GAMESIG) != 0)
{
// Make a special case for the message printed for old savegames that don't
// have this information.
if (engine.IsEmpty())
{
Printf("Savegame is from an incompatible version\n");
}
else
{
Printf("Savegame is from another ZDoom-based engine: %s\n", engine.GetChars());
}
delete resfile;
return;
}
if (SaveVersion < MINSAVEVER || SaveVersion > SAVEVER)
{
delete resfile;
Printf("Savegame is from an incompatible version");
if (SaveVersion < MINSAVEVER)
{
Printf(": %d (%d is the oldest supported)", SaveVersion, MINSAVEVER);
}
else
{
Printf(": %d (%d is the highest supported)", SaveVersion, SAVEVER);
}
Printf("\n");
return;
}
if (!G_CheckSaveGameWads(arc, true))
{
delete resfile;
return;
}
if (map.IsEmpty())
{
Printf("Savegame is missing the current map\n");
delete resfile;
return;
}
// Now that it looks like we can load this save, hide the fullscreen console if it was up
// when the game was selected from the menu.
if (hidecon && gamestate == GS_FULLCONSOLE)
{
gamestate = GS_HIDECONSOLE;
}
// we are done with info.json.
arc.Close();
info = resfile->FindLump("globals.json");
if (info == nullptr)
{
delete resfile;
Printf("'%s' is not a valid savegame: Missing 'globals.json'.\n", savename.GetChars());
return;
}
data = info->CacheLump();
if (!arc.OpenReader((const char *)data, info->LumpSize))
{
Printf("Failed to access savegame info\n");
delete resfile;
return;
}
// Read intermission data for hubs
G_SerializeHub(arc);
bglobal.RemoveAllBots(true);
FString cvar;
arc("importantcvars", cvar);
if (!cvar.IsEmpty())
{
BYTE *vars_p = (BYTE *)cvar.GetChars();
C_ReadCVars(&vars_p);
}
DWORD time[2] = { 1,0 };
arc("ticrate", time[0])
("leveltime", time[1]);
// dearchive all the modifications
level.time = Scale(time[1], TICRATE, time[0]);
G_ReadSnapshots(resfile);
delete resfile; // we no longer need the resource file below this point
resfile = nullptr;
G_ReadVisited(arc);
// load a base level
savegamerestore = true; // Use the player actors in the savegame
bool demoplaybacksave = demoplayback;
G_InitNew(map, false);
demoplayback = demoplaybacksave;
savegamerestore = false;
STAT_Serialize(arc);
FRandom::StaticReadRNGState(arc);
P_ReadACSDefereds(arc);
P_ReadACSVars(arc);
NextSkill = -1;
arc("nextskill", NextSkill);
if (level.info != nullptr)
level.info->Snapshot.Clean();
BackupSaveName = savename;
// At this point, the GC threshold is likely a lot higher than the
// amount of memory in use, so bring it down now by starting a
// collection.
GC::StartCollection();
Printf("'%s' is not a valid savegame: Missing 'info.json'.\n", savename.GetChars());
return;
}
catch (...)
SaveVersion = 0;
void *data = info->CacheLump();
FSerializer arc;
if (!arc.OpenReader((const char *)data, info->LumpSize))
{
// delete the resource file if anything goes wrong in here.
if (resfile != nullptr) delete resfile;
throw;
Printf("Failed to access savegame info\n");
return;
}
// Check whether this savegame actually has been created by a compatible engine.
// Since there are ZDoom derivates using the exact same savegame format but
// with mutual incompatibilities this check simplifies things significantly.
FString savever, engine, map;
arc("Save Version", SaveVersion);
arc("Engine", engine);
arc("Current Map", map);
if (engine.CompareNoCase(GAMESIG) != 0)
{
// Make a special case for the message printed for old savegames that don't
// have this information.
if (engine.IsEmpty())
{
Printf("Savegame is from an incompatible version\n");
}
else
{
Printf("Savegame is from another ZDoom-based engine: %s\n", engine.GetChars());
}
return;
}
if (SaveVersion < MINSAVEVER || SaveVersion > SAVEVER)
{
Printf("Savegame is from an incompatible version");
if (SaveVersion < MINSAVEVER)
{
Printf(": %d (%d is the oldest supported)", SaveVersion, MINSAVEVER);
}
else
{
Printf(": %d (%d is the highest supported)", SaveVersion, SAVEVER);
}
Printf("\n");
return;
}
if (!G_CheckSaveGameWads(arc, true))
{
return;
}
if (map.IsEmpty())
{
Printf("Savegame is missing the current map\n");
return;
}
// Now that it looks like we can load this save, hide the fullscreen console if it was up
// when the game was selected from the menu.
if (hidecon && gamestate == GS_FULLCONSOLE)
{
gamestate = GS_HIDECONSOLE;
}
// we are done with info.json.
arc.Close();
info = resfile->FindLump("globals.json");
if (info == nullptr)
{
Printf("'%s' is not a valid savegame: Missing 'globals.json'.\n", savename.GetChars());
return;
}
data = info->CacheLump();
if (!arc.OpenReader((const char *)data, info->LumpSize))
{
Printf("Failed to access savegame info\n");
return;
}
// Read intermission data for hubs
G_SerializeHub(arc);
bglobal.RemoveAllBots(true);
FString cvar;
arc("importantcvars", cvar);
if (!cvar.IsEmpty())
{
BYTE *vars_p = (BYTE *)cvar.GetChars();
C_ReadCVars(&vars_p);
}
DWORD time[2] = { 1,0 };
arc("ticrate", time[0])
("leveltime", time[1]);
// dearchive all the modifications
level.time = Scale(time[1], TICRATE, time[0]);
G_ReadSnapshots(resfile.get());
resfile.reset(nullptr); // we no longer need the resource file below this point
G_ReadVisited(arc);
// load a base level
savegamerestore = true; // Use the player actors in the savegame
bool demoplaybacksave = demoplayback;
G_InitNew(map, false);
demoplayback = demoplaybacksave;
savegamerestore = false;
STAT_Serialize(arc);
FRandom::StaticReadRNGState(arc);
P_ReadACSDefereds(arc);
P_ReadACSVars(arc);
NextSkill = -1;
arc("nextskill", NextSkill);
if (level.info != nullptr)
level.info->Snapshot.Clean();
BackupSaveName = savename;
// At this point, the GC threshold is likely a lot higher than the
// amount of memory in use, so bring it down now by starting a
// collection.
GC::StartCollection();
}