Implemented some advanced savegame functionality - loading and deleting savegames from the GMM is now possible, and new saved games will also have thumbnails. Saving from the GMM creates corrupted saved games, so it has been disabled for now

svn-id: r44930
This commit is contained in:
Filippos Karapetis 2009-10-11 15:51:43 +00:00
parent ba9a9422b4
commit 1d3118cf42
5 changed files with 191 additions and 6 deletions

View file

@ -768,14 +768,15 @@ bool Console::cmdSaveGame(int argc, const char **argv) {
DebugPrintf("Note: Game state has %d open file handles.\n", result); DebugPrintf("Note: Game state has %d open file handles.\n", result);
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager(); Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
Common::OutSaveFile *out; Common::OutSaveFile *out = saveFileMan->openForSaving(argv[1]);
if (!(out = saveFileMan->openForSaving(argv[1]))) { const char *version = "";
if (!out) {
DebugPrintf("Error opening savegame \"%s\" for writing\n", argv[1]); DebugPrintf("Error opening savegame \"%s\" for writing\n", argv[1]);
return true; return true;
} }
// TODO: enable custom descriptions? force filename into a specific format? // TODO: enable custom descriptions? force filename into a specific format?
if (gamestate_save(_vm->_gamestate, out, "debugging", 0)) { if (gamestate_save(_vm->_gamestate, out, "debugging", version)) {
DebugPrintf("Saving the game state to '%s' failed\n", argv[1]); DebugPrintf("Saving the game state to '%s' failed\n", argv[1]);
} }
@ -792,8 +793,8 @@ bool Console::cmdRestoreGame(int argc, const char **argv) {
EngineState *newstate = NULL; EngineState *newstate = NULL;
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager(); Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
Common::SeekableReadStream *in; Common::SeekableReadStream *in = saveFileMan->openForLoading(argv[1]);
if (!(in = saveFileMan->openForLoading(argv[1]))) { if (in) {
// found a savegame file // found a savegame file
newstate = gamestate_restore(_vm->_gamestate, in); newstate = gamestate_restore(_vm->_gamestate, in);
delete in; delete in;

View file

@ -25,10 +25,14 @@
#include "engines/advancedDetector.h" #include "engines/advancedDetector.h"
#include "base/plugins.h" #include "base/plugins.h"
#include "common/savefile.h"
#include "graphics/thumbnail.h"
#include "sci/sci.h" #include "sci/sci.h"
#include "sci/engine/kernel.h" #include "sci/engine/kernel.h"
#include "sci/engine/savegame.h"
#include "sci/engine/seg_manager.h" #include "sci/engine/seg_manager.h"
#include "sci/engine/state.h"
#include "sci/engine/vm.h" // for convertSierraGameId #include "sci/engine/vm.h" // for convertSierraGameId
namespace Sci { namespace Sci {
@ -161,6 +165,11 @@ public:
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const; virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;
const ADGameDescription *fallbackDetect(const Common::FSList &fslist) const; const ADGameDescription *fallbackDetect(const Common::FSList &fslist) const;
virtual bool hasFeature(MetaEngineFeature f) const;
virtual SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const;
virtual void removeSaveState(const char *target, int slot) const;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
}; };
Common::Language charToScummVMLanguage(const char c) { Common::Language charToScummVMLanguage(const char c) {
@ -373,6 +382,165 @@ bool SciMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameD
return true; return true;
} }
bool SciMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves) ||
//(f == kSupportsLoadingDuringStartup) ||
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSavesSupportCreationDate);
}
bool SciEngine::hasFeature(EngineFeature f) const {
return
//(f == kSupportsRTL) ||
(f == kSupportsLoadingDuringRuntime);
//(f == kSupportsSavingDuringRuntime);
}
SaveStateList SciMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringList filenames;
Common::String pattern = target;
pattern += ".???";
filenames = saveFileMan->listSavefiles(pattern);
sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
int slotNum = 0;
for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
// Obtain the last 3 digits of the filename, since they correspond to the save slot
slotNum = atoi(file->c_str() + file->size() - 3);
if (slotNum >= 0 && slotNum < 999) {
Common::InSaveFile *in = saveFileMan->openForLoading(*file);
if (in) {
SavegameMetadata meta;
if (!get_savegame_metadata(in, &meta)) {
// invalid
delete in;
continue;
}
saveList.push_back(SaveStateDescriptor(slotNum, meta.savegame_name));
delete in;
}
}
}
return saveList;
}
SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::String fileName = Common::String::printf("%s.%03d", target, slot);
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
if (in) {
SavegameMetadata meta;
if (!get_savegame_metadata(in, &meta)) {
// invalid
delete in;
SaveStateDescriptor desc(slot, "Invalid");
return desc;
}
SaveStateDescriptor desc(slot, meta.savegame_name);
Graphics::Surface *thumbnail = new Graphics::Surface();
assert(thumbnail);
if (!Graphics::loadThumbnail(*in, *thumbnail)) {
delete thumbnail;
thumbnail = 0;
}
desc.setThumbnail(thumbnail);
desc.setDeletableFlag(true);
desc.setWriteProtectedFlag(false);
int day = (meta.savegame_date >> 24) & 0xFF;
int month = (meta.savegame_date >> 16) & 0xFF;
int year = meta.savegame_date & 0xFFFF;
desc.setSaveDate(year, month, day);
int hour = (meta.savegame_time >> 16) & 0xFF;
int minutes = (meta.savegame_time >> 8) & 0xFF;
desc.setSaveTime(hour, minutes);
// TODO: played time
delete in;
return desc;
}
return SaveStateDescriptor();
}
int SciMetaEngine::getMaximumSaveSlot() const { return 999; }
void SciMetaEngine::removeSaveState(const char *target, int slot) const {
Common::String fileName = Common::String::printf("%s.%03d", target, slot);
g_system->getSavefileManager()->removeSavefile(fileName);
}
Common::Error SciEngine::loadGameState(int slot) {
EngineState *newstate = NULL;
Common::String fileName = Common::String::printf("%s.%03d", _targetName.c_str(), slot);
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
Common::SeekableReadStream *in = saveFileMan->openForLoading(fileName);
if (in) {
// found a savegame file
newstate = gamestate_restore(_gamestate, in);
delete in;
}
if (newstate) {
_gamestate->successor = newstate; // Set successor
script_abort_flag = 2; // Abort current game with replay
shrink_execution_stack(_gamestate, _gamestate->execution_stack_base + 1);
return Common::kNoError;
} else {
warning("Restoring gamestate '%s' failed.\n", fileName);
return Common::kUnknownError;
}
}
Common::Error SciEngine::saveGameState(int slot, const char *desc) {
// TODO: Savegames created from the GMM are still problematic
#if 0
Common::String fileName = Common::String::printf("%s.%03d", _targetName.c_str(), slot);
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
Common::OutSaveFile *out = saveFileMan->openForSaving(fileName);
const char *version = "";
if (!out) {
warning("Error opening savegame \"%s\" for writing\n", fileName);
return Common::kWritingFailed;
}
if (gamestate_save(_gamestate, out, desc, version)) {
warning("Saving the game state to '%s' failed\n", fileName);
return Common::kUnknownError;
}
#endif
return Common::kNoError; // TODO: return success/failure
}
bool SciEngine::canLoadGameStateCurrently() {
return !_gamestate->execution_stack_base;
}
bool SciEngine::canSaveGameStateCurrently() {
return !_gamestate->execution_stack_base;
}
} // End of namespace Sci } // End of namespace Sci
#if PLUGIN_ENABLED_DYNAMIC(SCI) #if PLUGIN_ENABLED_DYNAMIC(SCI)

View file

@ -27,6 +27,7 @@
#include "common/system.h" #include "common/system.h"
#include "common/func.h" #include "common/func.h"
#include "common/serializer.h" #include "common/serializer.h"
#include "graphics/thumbnail.h"
#include "sci/sci.h" #include "sci/sci.h"
#include "sci/gfx/operations.h" #include "sci/gfx/operations.h"
@ -529,6 +530,7 @@ int gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savename
*/ */
Common::Serializer ser(0, fh); Common::Serializer ser(0, fh);
sync_SavegameMetadata(ser, meta); sync_SavegameMetadata(ser, meta);
Graphics::saveThumbnail(*fh);
s->saveLoadWithSerializer(ser); // FIXME: Error handling? s->saveLoadWithSerializer(ser); // FIXME: Error handling?
return 0; return 0;
@ -724,6 +726,15 @@ EngineState *gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
return NULL; return NULL;
} }
if (meta.savegame_version >= 12) {
// We don't need the thumbnail here, so just read it and discard it
Graphics::Surface *thumbnail = new Graphics::Surface();
assert(thumbnail);
Graphics::loadThumbnail(*fh, *thumbnail);
delete thumbnail;
thumbnail = 0;
}
// FIXME: Do in-place loading at some point, instead of creating a new EngineState instance from scratch. // FIXME: Do in-place loading at some point, instead of creating a new EngineState instance from scratch.
retval = new EngineState(s->resMan, s->_kernel, s->_voc, s->_gui, s->_cursor); retval = new EngineState(s->resMan, s->_kernel, s->_voc, s->_gui, s->_cursor);

View file

@ -36,7 +36,7 @@ namespace Sci {
struct EngineState; struct EngineState;
enum { enum {
CURRENT_SAVEGAME_VERSION = 11, CURRENT_SAVEGAME_VERSION = 12,
MINIMUM_SAVEGAME_VERSION = 9 MINIMUM_SAVEGAME_VERSION = 9
}; };

View file

@ -96,9 +96,14 @@ public:
// Engine APIs // Engine APIs
virtual Common::Error run(); virtual Common::Error run();
bool hasFeature(EngineFeature f) const;
void pauseEngineIntern(bool pause); void pauseEngineIntern(bool pause);
virtual GUI::Debugger *getDebugger(); virtual GUI::Debugger *getDebugger();
Console *getSciDebugger(); Console *getSciDebugger();
Common::Error loadGameState(int slot);
Common::Error saveGameState(int slot, const char *desc);
bool canLoadGameStateCurrently();
bool canSaveGameStateCurrently();
const char* getGameID() const; const char* getGameID() const;
int getResourceVersion() const; int getResourceVersion() const;