From ae9f764c7ac4fcc418ca7182163f4e9646f4bc31 Mon Sep 17 00:00:00 2001 From: Bastien Bouclet Date: Thu, 15 Sep 2016 18:43:42 +0200 Subject: ENGINES: Automatically upgrade the targets on launch to add an engine ID --- base/commandLine.cpp | 1 + base/main.cpp | 2 ++ base/plugins.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ engines/metaengine.h | 7 +++++ gui/editgamedialog.cpp | 2 ++ gui/launcher.cpp | 2 ++ 6 files changed, 98 insertions(+) diff --git a/base/commandLine.cpp b/base/commandLine.cpp index 74a5982f32..5c823b2425 100644 --- a/base/commandLine.cpp +++ b/base/commandLine.cpp @@ -769,6 +769,7 @@ static Common::Error listSaves(const Common::String &target) { const Plugin *plugin = nullptr; PlainGameDescriptor game; if (domain) { + EngineMan.upgradeTargetIfNecessary(target); game = EngineMan.findTarget(target, &plugin); } else { game = EngineMan.findGame(target, &plugin); diff --git a/base/main.cpp b/base/main.cpp index 45c8e393b7..85fdbb2986 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -545,6 +545,8 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { while (0 != ConfMan.getActiveDomain()) { saveLastLaunchedTarget(ConfMan.getActiveDomainName()); + EngineMan.upgradeTargetIfNecessary(ConfMan.getActiveDomainName()); + // Try to find a plugin which feels responsible for the specified game. const Plugin *plugin = detectPlugin(); if (plugin) { diff --git a/base/plugins.cpp b/base/plugins.cpp index a64dbdd65c..ac98de4d15 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -675,6 +675,90 @@ PlainGameDescriptor EngineManager::findTarget(const Common::String &target, cons return desc; } +void EngineManager::upgradeTargetIfNecessary(const Common::String &target) const { + Common::ConfigManager::Domain *domain = ConfMan.getDomain(target); + assert(domain); + + if (!domain->contains("engineid")) { + upgradeTargetForEngineId(target); + } +} + +void EngineManager::upgradeTargetForEngineId(const Common::String &target) const { + Common::ConfigManager::Domain *domain = ConfMan.getDomain(target); + assert(domain); + + debug("Target '%s' lacks an engine ID, upgrading...", target.c_str()); + + Common::String oldGameId = domain->getVal("gameid"); + Common::String path = domain->getVal("path"); + + // At this point the game ID and game path must be known + if (oldGameId.empty()) { + warning("The game ID is required to upgrade target '%s'", target.c_str()); + return; + } + if (path.empty()) { + warning("The game path is required to upgrade target '%s'", target.c_str()); + return; + } + + // Game descriptor for the upgraded target + Common::String engineId; + Common::String newGameId; + + // First, try to update entries for engines that previously used the "single id" system + // Search for an engine whose ID is the game ID + const Plugin *plugin = findPlugin(oldGameId); + if (plugin) { + // Run detection on the game path + Common::FSNode dir(path); + Common::FSList files; + if (!dir.getChildren(files, Common::FSNode::kListAll)) { + warning("Failed to access path '%s' when upgrading target '%s'", path.c_str(), target.c_str()); + return; + } + + // Take the first detection entry + const MetaEngine &metaEngine = plugin->get(); + DetectedGames candidates = metaEngine.detectGames(files); + if (candidates.empty()) { + warning("No games supported by the engine '%s' were found in path '%s' when upgrading target '%s'", + metaEngine.getEngineId(), path.c_str(), target.c_str()); + return; + } + + engineId = candidates[0].engineId; + newGameId = candidates[0].gameId; + } + + // Next, try to find an engine with the game ID in its supported games list + if (engineId.empty()) { + PlainGameDescriptor pgd = findGame(oldGameId, &plugin); + if (plugin) { + engineId = plugin->get().getEngineId(); + newGameId = pgd.gameId; + } + } + + if (engineId.empty() || newGameId.empty()) { + warning("No matching engine was found when upgrading target '%s'", target.c_str()); + return; + } + + domain->setVal("engineid", engineId); + domain->setVal("gameid", newGameId); + + // Save a backup of the pre-upgrade gameId to the config file + if (newGameId != oldGameId) { + domain->setVal("oldgameid", oldGameId); + } + + debug("Upgrade complete (engine ID '%s', game ID '%s')", engineId.c_str(), newGameId.c_str()); + + ConfMan.flushToDisk(); +} + // Music plugins #include "audio/musicplugin.h" diff --git a/engines/metaengine.h b/engines/metaengine.h index 89f786f7b0..a6c2c067e2 100644 --- a/engines/metaengine.h +++ b/engines/metaengine.h @@ -295,12 +295,19 @@ public: * Returns the created target name. */ Common::String createTargetForGame(const DetectedGame &game); + + /** Upgrade a target to the current configuration format */ + void upgradeTargetIfNecessary(const Common::String &target) const; + private: /** Find a game across all loaded plugins */ PlainGameDescriptor findGameInLoadedPlugins(const Common::String &gameName, const Plugin **plugin = NULL) const; /** Find a loaded plugin with the given engine ID */ const Plugin *findLoadedPlugin(const Common::String &engineId) const; + + /** Use heuristics to complete a target lacking an engine ID */ + void upgradeTargetForEngineId(const Common::String &target) const; }; /** Convenience shortcut for accessing the engine manager. */ diff --git a/gui/editgamedialog.cpp b/gui/editgamedialog.cpp index ac030d7678..4f3c1647a1 100644 --- a/gui/editgamedialog.cpp +++ b/gui/editgamedialog.cpp @@ -100,6 +100,8 @@ protected: EditGameDialog::EditGameDialog(const String &domain) : OptionsDialog(domain, "GameOptions") { + EngineMan.upgradeTargetIfNecessary(domain); + // Retrieve all game specific options. const Plugin *plugin = nullptr; // To allow for game domains without a gameid. diff --git a/gui/launcher.cpp b/gui/launcher.cpp index c8c2cc0583..a3151a0455 100644 --- a/gui/launcher.cpp +++ b/gui/launcher.cpp @@ -481,6 +481,8 @@ void LauncherDialog::loadGame(int item) { String target = _domains[item]; target.toLowercase(); + EngineMan.upgradeTargetIfNecessary(target); + // Look for the plugin const Plugin *plugin = nullptr; EngineMan.findTarget(target, &plugin); -- cgit v1.2.3