Skip to content
This repository has been archived by the owner on Jun 8, 2022. It is now read-only.

Commit

Permalink
MYST3: Implement the new autosave system
Browse files Browse the repository at this point in the history
Fixes autosaves being performed too often.
  • Loading branch information
bgK committed May 14, 2020
1 parent 6fed848 commit b333691
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 38 deletions.
7 changes: 6 additions & 1 deletion engines/myst3/detection.cpp
Expand Up @@ -290,8 +290,13 @@ class Myst3MetaEngine : public AdvancedMetaEngine {
saveInfos.setSaveTime(data.saveHour, data.saveMinute);
}

if (data.saveDescription != "")
if (data.saveDescription != "") {
saveInfos.setDescription(data.saveDescription);
}

if (s.getVersion() >= 150) {
saveInfos.setAutosave(data.isAutosave);
}

delete saveFile;

Expand Down
4 changes: 2 additions & 2 deletions engines/myst3/menu.cpp
Expand Up @@ -646,7 +646,7 @@ void PagingMenu::saveMenuSave() {
if (fileExists && _vm->openDialog(dialogIdFromType(kConfirmOverwrite)) != 1)
return;

Common::Error saveError = _vm->saveGameState(_saveName, _saveThumbnail.get());
Common::Error saveError = _vm->saveGameState(_saveName, _saveThumbnail.get(), false);
if (saveError.getCode() != Common::kNoError) {
GUI::MessageDialog dialog(saveError.getDesc());
dialog.runModal();
Expand Down Expand Up @@ -998,7 +998,7 @@ void AlbumMenu::saveMenuSave() {
if (saveFiles.contains(selectedSave) && _vm->openDialog(dialogIdFromType(kConfirmOverwrite)) != 1)
return;

Common::Error saveError = _vm->saveGameState(saveName, _saveThumbnail.get());
Common::Error saveError = _vm->saveGameState(saveName, _saveThumbnail.get(), false);
if (saveError.getCode() != Common::kNoError) {
GUI::MessageDialog dialog(saveError.getDesc());
dialog.runModal();
Expand Down
34 changes: 7 additions & 27 deletions engines/myst3/myst3.cpp
Expand Up @@ -71,7 +71,7 @@ Myst3Engine::Myst3Engine(OSystem *syst, const Myst3GameDescription *version) :
_inputSpacePressed(false), _inputEnterPressed(false),
_inputEscapePressed(false), _inputTildePressed(false),
_inputEscapePressedNotConsumed(false),
_interactive(false), _lastSaveTime(0),
_interactive(false),
_menuAction(0), _projectorBackground(0),
_shakeEffect(0), _rotationEffect(0),
_backgroundSoundScriptLastRoomId(0),
Expand Down Expand Up @@ -215,7 +215,6 @@ Common::Error Myst3Engine::run() {
drawFrame();
}

tryAutoSaving(); //Attempt to autosave before exiting
unloadNode();

_archiveNode->close();
Expand Down Expand Up @@ -533,10 +532,6 @@ void Myst3Engine::processInput(bool interactive) {
interactWithHoveredElement();
}

if (shouldPerformAutoSave(_lastSaveTime)) {
tryAutoSaving();
}

// Open main menu
// This is not checked directly in the event handling code
// because menu open requests done while in lookOnly mode
Expand Down Expand Up @@ -1518,23 +1513,6 @@ bool Myst3Engine::canLoadGameStateCurrently() {
return _interactive;
}

void Myst3Engine::tryAutoSaving() {
if (!canSaveGameStateCurrently()) {
return; // Can't save right now, try again on the next frame
}

_lastSaveTime = _system->getMillis();

// Get a thumbnail of the game screen
if (!_menu->isOpen())
_menu->generateSaveThumbnail();

Common::Error result = saveGameState(0, "Autosave");
if (result.getCode() != Common::kNoError) {
warning("Unable to autosave: %s.", result.getDesc().c_str());
}
}

Common::Error Myst3Engine::loadGameState(int slot) {
Common::StringArray filenames = Saves::list(_saveFileMan, getPlatform());
return loadGameState(filenames[slot], kTransitionNone);
Expand Down Expand Up @@ -1604,13 +1582,15 @@ Common::Error Myst3Engine::saveGameState(int slot, const Common::String &desc, b
// Try to use an already generated thumbnail
const Graphics::Surface *thumbnail = _menu->borrowSaveThumbnail();
if (!thumbnail) {
return Common::Error(Common::kUnknownError, "No thumbnail");
_menu->generateSaveThumbnail();
}
thumbnail = _menu->borrowSaveThumbnail();
assert(thumbnail);

return saveGameState(desc, thumbnail);
return saveGameState(desc, thumbnail, isAutosave);
}

Common::Error Myst3Engine::saveGameState(const Common::String &desc, const Graphics::Surface *thumbnail) {
Common::Error Myst3Engine::saveGameState(const Common::String &desc, const Graphics::Surface *thumbnail, bool isAutosave) {
// Strip extension
Common::String saveName = desc;
if (desc.hasSuffixIgnoreCase(".M3S") || desc.hasSuffixIgnoreCase(".M3X")) {
Expand All @@ -1625,7 +1605,7 @@ Common::Error Myst3Engine::saveGameState(const Common::String &desc, const Graph
return Common::kCreatingFileFailed;
}

Common::Error saveError = _state->save(save.get(), saveName, thumbnail);
Common::Error saveError = _state->save(save.get(), saveName, thumbnail, isAutosave);
if (saveError.getCode() != Common::kNoError) {
return saveError;
}
Expand Down
5 changes: 1 addition & 4 deletions engines/myst3/myst3.h
Expand Up @@ -121,11 +121,10 @@ class Myst3Engine : public Engine {

bool canSaveGameStateCurrently() override;
bool canLoadGameStateCurrently() override;
void tryAutoSaving();
Common::Error loadGameState(int slot) override;
Common::Error loadGameState(Common::String fileName, TransitionType transition);
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
Common::Error saveGameState(const Common::String &desc, const Graphics::Surface *thumbnail);
Common::Error saveGameState(const Common::String &desc, const Graphics::Surface *thumbnail, bool isAutosave);

ResourceDescription getFileDescription(const Common::String &room, uint32 index, uint16 face,
Archive::ResourceType type);
Expand Down Expand Up @@ -224,8 +223,6 @@ class Myst3Engine : public Engine {

bool _interactive;

uint32 _lastSaveTime;

uint32 _backgroundSoundScriptLastRoomId;
uint32 _backgroundSoundScriptLastAgeId;

Expand Down
27 changes: 25 additions & 2 deletions engines/myst3/state.cpp
Expand Up @@ -78,6 +78,7 @@ GameState::StateData::StateData() {
saveYear = 0;
saveHour = 0;
saveMinute = 0;
isAutosave = false;
}

GameState::GameState(const Common::Platform platform, Database *database):
Expand Down Expand Up @@ -474,6 +475,7 @@ Common::Error GameState::StateData::syncWithSaveGame(Common::Serializer &s) {
s.syncAsByte(saveHour, 149);
s.syncAsByte(saveMinute, 149);
s.syncString(saveDescription, 149);
s.syncAsUint32LE(isAutosave, 150);

return Common::kNoError;
}
Expand Down Expand Up @@ -547,7 +549,7 @@ Common::Error GameState::load(Common::InSaveFile *saveFile) {
return Common::kNoError;
}

Common::Error GameState::save(Common::OutSaveFile *saveFile, const Common::String &description, const Graphics::Surface *thumbnail) {
Common::Error GameState::save(Common::OutSaveFile *saveFile, const Common::String &description, const Graphics::Surface *thumbnail, bool isAutosave) {
Common::Serializer s = Common::Serializer(0, saveFile);

// Update save creation info
Expand All @@ -559,6 +561,7 @@ Common::Error GameState::save(Common::OutSaveFile *saveFile, const Common::Strin
_data.saveHour = t.tm_hour;
_data.saveMinute = t.tm_min;
_data.saveDescription = description;
_data.isAutosave = isAutosave;

_data.gameRunning = false;

Expand Down Expand Up @@ -818,12 +821,32 @@ Common::String Saves::buildName(const char *name, Common::Platform platform) {
return Common::String::format(format, name);
}

struct AutosaveFirstComparator {
bool operator()(const Common::String &x, const Common::String &y) const {
if (x.hasPrefixIgnoreCase("autosave.")) {
return true;
}

if (y.hasPrefixIgnoreCase("autosave.")) {
return false;
}

return x < y;
}
};

Common::StringArray Saves::list(Common::SaveFileManager *saveFileManager, Common::Platform platform) {
Common::String searchPattern = Saves::buildName("*", platform);
Common::StringArray filenames = saveFileManager->listSavefiles(searchPattern);

// The saves are sorted alphabetically
Common::sort(filenames.begin(), filenames.end());
Common::sort(filenames.begin(), filenames.end(), AutosaveFirstComparator());

// The MetaEngine save system expects the Autosave to be in slot 0
// if we don't have an autosave (yet), insert a fake one.
if (!filenames.empty() && !filenames[0].hasPrefixIgnoreCase("autosave.")) {
filenames.insert_at(0, buildName("Autosave", platform));
}

return filenames;
}
Expand Down
6 changes: 4 additions & 2 deletions engines/myst3/state.h
Expand Up @@ -53,7 +53,7 @@ class GameState {

void newGame();
Common::Error load(Common::InSaveFile *saveFile);
Common::Error save(Common::OutSaveFile *saveFile, const Common::String &description, const Graphics::Surface *thumbnail);
Common::Error save(Common::OutSaveFile *saveFile, const Common::String &description, const Graphics::Surface *thumbnail, bool isAutosave);

int32 getVar(uint16 var);
void setVar(uint16 var, int32 value);
Expand Down Expand Up @@ -379,6 +379,8 @@ class GameState {

Common::String saveDescription;

bool isAutosave;

StateData();
Common::Error syncWithSaveGame(Common::Serializer &s);
};
Expand All @@ -395,7 +397,7 @@ class GameState {
const Common::Platform _platform;
Database *_db;

static const uint32 kSaveVersion = 149;
static const uint32 kSaveVersion = 150;

StateData _data;

Expand Down

0 comments on commit b333691

Please sign in to comment.