From b0957e64599b6ea5648a539fdff84487c7a730a9 Mon Sep 17 00:00:00 2001 From: Bart Trzynadlowski Date: Fri, 31 Mar 2017 05:23:04 +0000 Subject: [PATCH] Smarter game selection when a zip file contains multiple games (prefer child when parent is also present in zip) --- Src/GameLoader.cpp | 59 ++++++++++++++++++++++++++++++++++++---------- Src/GameLoader.h | 3 ++- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/Src/GameLoader.cpp b/Src/GameLoader.cpp index bb374c3..cc207b5 100644 --- a/Src/GameLoader.cpp +++ b/Src/GameLoader.cpp @@ -276,6 +276,15 @@ bool GameLoader::ParseXML(const Util::Config::Node &xml) return false; } +bool GameLoader::LoadDefinitionXML(const std::string &filename) +{ + m_xml_filename = filename; + Util::Config::Node xml("xml"); + if (Util::Config::FromXMLFile(&xml, filename)) + return true; + return ParseXML(xml); +} + std::set GameLoader::IdentifyCompleteGamesInZipArchive(const ZipArchive &zip) const { std::set complete_games; @@ -490,15 +499,6 @@ bool GameLoader::LoadROMs(ROMSet *rom_set, const std::string &game_name, const Z return error; } -bool GameLoader::LoadDefinitionXML(const std::string &filename) -{ - m_xml_filename = filename; - Util::Config::Node xml("xml"); - if (Util::Config::FromXMLFile(&xml, filename)) - return true; - return ParseXML(xml); -} - std::string StripFilename(const std::string &filepath) { // Search for last '/' or '\', if any @@ -520,6 +520,36 @@ std::string StripFilename(const std::string &filepath) return std::string(filepath, 0, last_slash + 1); } +// A heuristic is used that favors child sets with present parent +std::string GameLoader::ChooseGame(const std::set &games_found) const +{ + // Identify children sets and parent sets + std::set parents; + std::set children; + for (auto &game_name: games_found) + { + auto it = m_game_info_by_game.find(game_name); + const Game &game = it->second; + if (game.parent.empty()) + parents.insert(game_name); + else + children.insert(game_name); + } + + // Find the first child set whose parent is also present + for (auto &child: children) + { + auto it = m_game_info_by_game.find(child); + const Game &game = it->second; + const std::string &parent = game.parent; + if (parents.count(parent) > 0) + return child; + } + + // Otherwise, just grab whatever is first + return *games_found.begin(); +} + bool GameLoader::Load(Game *game, ROMSet *rom_set, const std::string &zipfilename) { *game = Game(); @@ -534,11 +564,14 @@ bool GameLoader::Load(Game *game, ROMSet *rom_set, const std::string &zipfilenam ErrorLog("No complete Model 3 games found in '%s'.", zipfilename.c_str()); return true; } - else if (games_found.size() > 1) - ErrorLog("Multiple games found in '%s' (%s). Loading '%s'.", zipfilename.c_str(), std::string(Util::Format(", ").Join(games_found)).c_str(), games_found.begin()->c_str()); - // Pick the first game in the first zip file - *game = m_game_info_by_game[*games_found.begin()]; + // Pick the game to load (if there are multiple games present) + std::string chosen_game = ChooseGame(games_found); + if (games_found.size() > 1) + ErrorLog("Multiple games found in '%s' (%s). Loading '%s'.", zipfilename.c_str(), std::string(Util::Format(", ").Join(games_found)).c_str(), chosen_game.c_str()); + + // Return game information to caller + *game = m_game_info_by_game[chosen_game]; // If there is a parent ROM set, determine where it is 1) contained in the // same zip file or 2) try loading it from the same directory diff --git a/Src/GameLoader.h b/Src/GameLoader.h index 15ed01f..9599db5 100644 --- a/Src/GameLoader.h +++ b/Src/GameLoader.h @@ -68,11 +68,12 @@ private: const ZippedFile *LookupFile(const File::ptr_t &file, const ZipArchive &zip) const; static bool MissingAttrib(const GameLoader &loader, const Util::Config::Node &node, const std::string &attribute); bool ParseXML(const Util::Config::Node &xml); + bool LoadDefinitionXML(const std::string &filename); std::set IdentifyCompleteGamesInZipArchive(const ZipArchive &zip) const; bool ComputeRegionSize(uint32_t *region_size, const Region::ptr_t ®ion, const ZipArchive &zip) const; bool LoadRegion(ROM *buffer, const GameLoader::Region::ptr_t ®ion, const ZipArchive &zip); bool LoadROMs(ROMSet *rom_set, const std::string &game_name, const ZipArchive *zip, const std::string &parent_name, const ZipArchive *parent_zip); - bool LoadDefinitionXML(const std::string &filename); + std::string ChooseGame(const std::set &games_found) const; public: GameLoader(const std::string &xml_file);