SUPERNOVA: Improve save state handling

The saved game files now start with a header and version which allows
to do some sanity check and will allow to change the format in the
future if needed.

Also the MetaEngine can now be queried for the meta infos of a save
state.
This commit is contained in:
Thierry Crozat 2017-09-04 22:48:50 +01:00
parent a4470edb29
commit ed7fa6f7d7
3 changed files with 89 additions and 4 deletions

View file

@ -24,6 +24,7 @@
#include "common/file.h"
#include "common/savefile.h"
#include "common/system.h"
#include "graphics/thumbnail.h"
#include "engines/advancedDetector.h"
#include "supernova/supernova.h"
@ -83,6 +84,7 @@ public:
virtual int getMaximumSaveSlot() const {
return 99;
}
virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
};
bool SupernovaMetaEngine::hasFeature(MetaEngineFeature f) const {
@ -92,6 +94,13 @@ bool SupernovaMetaEngine::hasFeature(MetaEngineFeature f) const {
case kSupportsListSaves:
// fallthrough
case kSupportsDeleteSave:
// fallthrough
case kSavesSupportMetaInfo:
// fallthrough
case kSavesSupportThumbnail:
// fallthrough
case kSavesSupportCreationDate:
// fallthrough
return true;
default:
return false;
@ -120,10 +129,17 @@ SaveStateList SupernovaMetaEngine::listSaves(const char *target) const {
if (saveSlot >= 0 && saveSlot <= getMaximumSaveSlot()) {
Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading(*file);
if (savefile) {
savefile->skip(2);
savefile->read(saveFileDesc, sizeof(saveFileDesc));
uint saveHeader = savefile->readUint32LE();
if (saveHeader == SAVEGAME_HEADER) {
byte saveVersion = savefile->readByte();
if (saveVersion <= SAVEGAME_VERSION) {
int saveFileDescSize = savefile->readSint16LE();
char* saveFileDesc = new char[saveFileDescSize];
savefile->read(saveFileDesc, saveFileDescSize);
saveFileList.push_back(SaveStateDescriptor(saveSlot, saveFileDesc));
delete [] saveFileDesc;
}
}
delete savefile;
}
}
@ -138,6 +154,54 @@ void SupernovaMetaEngine::removeSaveState(const char *target, int slot) const {
g_system->getSavefileManager()->removeSavefile(filename);
}
SaveStateDescriptor SupernovaMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::String fileName = Common::String::format("msn_save.%03d", slot);
Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading(fileName);
if (savefile) {
uint saveHeader = savefile->readUint32LE();
if (saveHeader != SAVEGAME_HEADER) {
delete savefile;
return SaveStateDescriptor();
}
byte saveVersion = savefile->readByte();
if (saveVersion > SAVEGAME_VERSION){
delete savefile;
return SaveStateDescriptor();
}
int descriptionSize = savefile->readSint16LE();
char* description = new char[descriptionSize];
savefile->read(description, descriptionSize);
SaveStateDescriptor desc(slot, description);
delete [] description;
uint32 saveDate = savefile->readUint32LE();
int day = (saveDate >> 24) & 0xFF;
int month = (saveDate >> 16) & 0xFF;
int year = saveDate & 0xFFFF;
desc.setSaveDate(year, month, day);
uint16 saveTime = savefile->readUint16LE();
int hour = (saveTime >> 8) & 0xFF;
int minutes = saveTime & 0xFF;
desc.setSaveTime(hour, minutes);
if (Graphics::checkThumbnailHeader(*savefile)) {
Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*savefile);
desc.setThumbnail(thumbnail);
}
delete savefile;
return desc;
}
return SaveStateDescriptor();
}
#if PLUGIN_ENABLED_DYNAMIC(SUPERNOVA)
REGISTER_PLUGIN_DYNAMIC(SUPERNOVA, PLUGIN_TYPE_ENGINE, SupernovaMetaEngine);
#else

View file

@ -814,6 +814,20 @@ bool SupernovaEngine::loadGame(int slot) {
if (!savefile)
return false;
uint saveHeader = savefile->readUint32LE();
if (saveHeader != SAVEGAME_HEADER) {
warning("No header found in '%s'", filename.c_str());
delete savefile;
return Common::kUnknownError;
}
byte saveVersion = savefile->readByte();
if (saveVersion > SAVEGAME_VERSION) {
warning("Save game version %i not supported", saveVersion);
delete savefile;
return Common::kUnknownError;
}
int descriptionSize = savefile->readSint16LE();
savefile->skip(descriptionSize);
savefile->skip(6);
@ -834,6 +848,9 @@ bool SupernovaEngine::saveGame(int slot, const Common::String &description) {
if (!savefile)
return false;
savefile->writeUint32LE(SAVEGAME_HEADER);
savefile->writeByte(SAVEGAME_VERSION);
TimeDate currentDate;
_system->getTimeAndDate(currentDate);
uint32 saveDate = (currentDate.tm_mday & 0xFF) << 24 | ((currentDate.tm_mon + 1) & 0xFF) << 16 | ((currentDate.tm_year + 1900) & 0xFFFF);

View file

@ -42,6 +42,10 @@
namespace Supernova {
#define SAVEGAME_HEADER MKTAG('M','S','N','1')
#define SAVEGAME_VERSION 1
struct ScreenBuffer {
ScreenBuffer()
: _x(0)