diff --git a/Source/Core/DolphinQt/GameList/GameListModel.cpp b/Source/Core/DolphinQt/GameList/GameListModel.cpp index a930d66607..c70a870c23 100644 --- a/Source/Core/DolphinQt/GameList/GameListModel.cpp +++ b/Source/Core/DolphinQt/GameList/GameListModel.cpp @@ -92,14 +92,14 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const { QString name = QString::fromStdString(game.GetName(m_title_database)); - // Add disc numbers > 1 to title if not present. - const int disc_nr = game.GetDiscNumber() + 1; - if (disc_nr > 1) + const int disc_number = game.GetDiscNumber() + 1; + if (disc_number > 1 || game.IsTwoDiscGame()) { - if (!name.contains(QRegularExpression(QStringLiteral("disc ?%1").arg(disc_nr), + // Add disc number to title if not present. + if (!name.contains(QRegularExpression(QStringLiteral("disc ?%1").arg(disc_number), QRegularExpression::CaseInsensitiveOption))) { - name.append(tr(" (Disc %1)").arg(disc_nr)); + name.append(tr(" (Disc %1)").arg(disc_number)); } } diff --git a/Source/Core/UICommon/GameFile.cpp b/Source/Core/UICommon/GameFile.cpp index 470016d1bd..7603463138 100644 --- a/Source/Core/UICommon/GameFile.cpp +++ b/Source/Core/UICommon/GameFile.cpp @@ -135,6 +135,7 @@ GameFile::GameFile(std::string path) : m_file_path(std::move(path)) m_maker_id = volume->GetMakerID(); m_revision = volume->GetRevision().value_or(0); m_disc_number = volume->GetDiscNumber().value_or(0); + m_is_two_disc_game = CheckIfTwoDiscGame(m_game_id); m_apploader_date = volume->GetApploaderDate(); m_volume_banner.buffer = volume->GetBanner(&m_volume_banner.width, &m_volume_banner.height); @@ -321,6 +322,7 @@ void GameFile::DoState(PointerWrap& p) p.Do(m_compression_method); p.Do(m_revision); p.Do(m_disc_number); + p.Do(m_is_two_disc_game); p.Do(m_apploader_date); p.Do(m_custom_name); @@ -547,6 +549,77 @@ std::vector GameFile::GetLanguages() const return languages; } +bool GameFile::CheckIfTwoDiscGame(const std::string& game_id) const +{ + constexpr size_t GAME_ID_PREFIX_SIZE = 3; + if (game_id.size() < GAME_ID_PREFIX_SIZE) + return false; + + static constexpr std::array two_disc_game_id_prefixes = { + // Resident Evil + "DBJ", + // The Lord of the Rings: The Third Age + "G3A", + // Teenage Mutant Ninja Turtles 3: Mutant Nightmare + "G3Q", + // Resident Evil 4 + "G4B", + // Tiger Woods PGA Tour 2005 + "G5T", + // Resident Evil + "GBI", + // Resident Evil Zero + "GBZ", + // Conan + "GC9", + // Resident Evil Code: Veronica X + "GCD", + // Tom Clancy's Splinter Cell: Chaos Theory + "GCJ", + // Freaky Flyers + "GFF", + // GoldenEye: Rogue Agent + "GGI", + // Metal Gear Solid: The Twin Snakes + "GGS", + // Baten Kaitos Origins + "GK4", + // Killer7 + "GK7", + // Baten Kaitos: Eternal Wings and the Lost Ocean + "GKB", + // Lupin the 3rd: Lost Treasure by the Sea + "GL3", + // Enter the Matrix + "GMX", + // Teenage Mutant Ninja Turtles 2: Battle Nexus + "GNI", + // GoldenEye: Rogue Agent + "GOY", + // Tales of Symphonia + "GQS", + // Medal of Honor: Rising Sun + "GR8", + "GRZ", + // Tales of Symphonia + "GTO", + // Tiger Woods PGA Tour 2004 + "GW4", + // Tom Clancy's Splinter Cell: Double Agent (GC) + "GWY", + // Dragon Quest X: Mezameshi Itsutsu no Shuzoku Online + "S4M", + "S4S", + "S6T", + "SDQ", + }; + static_assert(std::is_sorted(two_disc_game_id_prefixes.begin(), two_disc_game_id_prefixes.end())); + + std::string_view game_id_prefix(game_id.data(), GAME_ID_PREFIX_SIZE); + return std::binary_search(two_disc_game_id_prefixes.begin(), two_disc_game_id_prefixes.end(), + game_id_prefix); +} + std::string GameFile::GetNetPlayName(const Core::TitleDatabase& title_database) const { std::vector info; diff --git a/Source/Core/UICommon/GameFile.h b/Source/Core/UICommon/GameFile.h index 32fb9278aa..e43950143b 100644 --- a/Source/Core/UICommon/GameFile.h +++ b/Source/Core/UICommon/GameFile.h @@ -81,6 +81,7 @@ public: u16 GetRevision() const { return m_revision; } // 0 is the first disc, 1 is the second disc u8 GetDiscNumber() const { return m_disc_number; } + bool IsTwoDiscGame() const { return m_is_two_disc_game; } std::string GetNetPlayName(const Core::TitleDatabase& title_database) const; // This function is slow @@ -134,6 +135,7 @@ private: bool ReadXMLMetadata(const std::string& path); bool ReadPNGBanner(const std::string& path); bool TryLoadGameModDescriptorBanner(); + bool CheckIfTwoDiscGame(const std::string& game_id) const; // IMPORTANT: Nearly all data members must be save/restored in DoState. // If anything is changed, make sure DoState handles it properly and @@ -168,6 +170,7 @@ private: std::string m_compression_method{}; u16 m_revision{}; u8 m_disc_number{}; + bool m_is_two_disc_game{}; std::string m_apploader_date; std::string m_custom_name; diff --git a/Source/Core/UICommon/GameFileCache.cpp b/Source/Core/UICommon/GameFileCache.cpp index 2838d331d8..d5b970d29c 100644 --- a/Source/Core/UICommon/GameFileCache.cpp +++ b/Source/Core/UICommon/GameFileCache.cpp @@ -26,7 +26,7 @@ namespace UICommon { -static constexpr u32 CACHE_REVISION = 24; // Last changed in PR 11557 +static constexpr u32 CACHE_REVISION = 25; // Last changed in PR 12702 std::vector FindAllGamePaths(const std::vector& directories_to_scan, bool recursive_scan)