diff --git a/Data/Sys/tritdb.txt b/Data/Sys/tritdb.txt new file mode 100644 index 000000000000..a397bb041926 --- /dev/null +++ b/Data/Sys/tritdb.txt @@ -0,0 +1,10 @@ +TITLES = (type: Triforce language: EN version: 20210908) +S000 = Triforce Firmware Update For Compact Flash Box (4.01) +SBEY = Virtua Striker 2002 +SBFX = The Key Of Avalon +SBGG = F-Zero AX +SBHZ = Virtua Striker 4 (Asia) +SBJA = Virtua Striker 4 (Export) +SBJN = The Key Of Avalon 2.5: War of the Key +SBLK = Virtua Striker 4 Ver.2006 (Japan) +SBLL = Virtua Striker 4 Ver.2006 (Export) diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index d27ffebee37b..d26ed2479e18 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -95,7 +95,7 @@ void SConfig::LoadSettings() void SConfig::ResetRunningGameMetadata() { - SetRunningGameMetadata("00000000", "", 0, 0, DiscIO::Region::Unknown); + SetRunningGameMetadata("00000000", "", "", 0, 0, DiscIO::Region::Unknown); } void SConfig::SetRunningGameMetadata(const DiscIO::Volume& volume, @@ -104,13 +104,13 @@ void SConfig::SetRunningGameMetadata(const DiscIO::Volume& volume, if (partition == volume.GetGamePartition()) { SetRunningGameMetadata(volume.GetGameID(), volume.GetGameTDBID(), - volume.GetTitleID().value_or(0), volume.GetRevision().value_or(0), - volume.GetRegion()); + volume.GetTriID().value_or(""), volume.GetTitleID().value_or(0), + volume.GetRevision().value_or(0), volume.GetRegion()); } else { SetRunningGameMetadata(volume.GetGameID(partition), volume.GetGameTDBID(), - volume.GetTitleID(partition).value_or(0), + volume.GetTriID().value_or(""), volume.GetTitleID(partition).value_or(0), volume.GetRevision(partition).value_or(0), volume.GetRegion()); } } @@ -127,23 +127,25 @@ void SConfig::SetRunningGameMetadata(const IOS::ES::TMDReader& tmd, DiscIO::Plat !DVDInterface::UpdateRunningGameMetadata(tmd_title_id)) { // If not launching a disc game, just read everything from the TMD. - SetRunningGameMetadata(tmd.GetGameID(), tmd.GetGameTDBID(), tmd_title_id, tmd.GetTitleVersion(), - tmd.GetRegion()); + SetRunningGameMetadata(tmd.GetGameID(), tmd.GetGameTDBID(), "", tmd_title_id, + tmd.GetTitleVersion(), tmd.GetRegion()); } } void SConfig::SetRunningGameMetadata(const std::string& game_id) { - SetRunningGameMetadata(game_id, "", 0, 0, DiscIO::Region::Unknown); + SetRunningGameMetadata(game_id, "", "", 0, 0, DiscIO::Region::Unknown); } void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::string& gametdb_id, - u64 title_id, u16 revision, DiscIO::Region region) + std::string tri_id, u64 title_id, u16 revision, + DiscIO::Region region) { const bool was_changed = m_game_id != game_id || m_gametdb_id != gametdb_id || - m_title_id != title_id || m_revision != revision; + m_tri_id != tri_id || m_title_id != title_id || m_revision != revision; m_game_id = game_id; m_gametdb_id = gametdb_id; + m_tri_id = tri_id; m_title_id = title_id; m_revision = revision; @@ -173,7 +175,7 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri const Core::TitleDatabase title_database; const DiscIO::Language language = GetLanguageAdjustedForRegion(bWii, region); - m_title_name = title_database.GetTitleName(m_gametdb_id, language); + m_title_name = title_database.GetTitleName(m_gametdb_id, m_tri_id, language); m_title_description = title_database.Describe(m_gametdb_id, language); NOTICE_LOG_FMT(CORE, "Active title: {}", m_title_description); Host_TitleChanged(); diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 9da56bd01ea4..cadc29e2cb61 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -61,6 +61,7 @@ struct SConfig const std::string& GetGameTDBID() const { return m_gametdb_id; } const std::string& GetTitleName() const { return m_title_name; } const std::string& GetTitleDescription() const { return m_title_description; } + std::string GetTriID() const { return m_tri_id; } u64 GetTitleID() const { return m_title_id; } u16 GetRevision() const { return m_revision; } void ResetRunningGameMetadata(); @@ -112,12 +113,14 @@ struct SConfig ~SConfig(); void SetRunningGameMetadata(const std::string& game_id, const std::string& gametdb_id, - u64 title_id, u16 revision, DiscIO::Region region); + std::string tri_id, u64 title_id, u16 revision, + DiscIO::Region region); static SConfig* m_Instance; std::string m_game_id; std::string m_gametdb_id; + std::string m_tri_id; std::string m_title_name; std::string m_title_description; u64 m_title_id; diff --git a/Source/Core/Core/TitleDatabase.cpp b/Source/Core/Core/TitleDatabase.cpp index d53a29835016..d2223cce59ce 100644 --- a/Source/Core/Core/TitleDatabase.cpp +++ b/Source/Core/Core/TitleDatabase.cpp @@ -62,6 +62,7 @@ TitleDatabase::TitleDatabase() { // User database const std::string& load_directory = File::GetUserPath(D_LOAD_IDX); + m_trititle_map = LoadMap(load_directory + "tritdb.txt"); m_user_title_map = LoadMap(load_directory + "wiitdb.txt"); if (m_user_title_map.empty()) m_user_title_map = LoadMap(load_directory + "titles.txt"); @@ -91,8 +92,12 @@ TitleDatabase::TitleDatabase() TitleDatabase::~TitleDatabase() = default; const std::string& TitleDatabase::GetTitleName(const std::string& gametdb_id, + const std::string& tri_id, DiscIO::Language language) const { + if (tri_id != "" || NULL) + TitleDatabase::GetTriTitleName(tri_id, language); + auto it = m_user_title_map.find(gametdb_id); if (it != m_user_title_map.end()) return it->second; @@ -120,17 +125,30 @@ const std::string& TitleDatabase::GetTitleName(const std::string& gametdb_id, return EMPTY_STRING; } +const std::string& TitleDatabase::GetTriTitleName(const std::string& tri_id, + DiscIO::Language language) const +{ + if (!Config::Get(Config::MAIN_USE_BUILT_IN_TITLE_DATABASE)) + return EMPTY_STRING; + + auto it = m_trititle_map.find(tri_id); + if (it != m_trititle_map.end()) + return it->second; + + return EMPTY_STRING; +} + const std::string& TitleDatabase::GetChannelName(u64 title_id, DiscIO::Language language) const { const std::string id{ {static_cast((title_id >> 24) & 0xff), static_cast((title_id >> 16) & 0xff), static_cast((title_id >> 8) & 0xff), static_cast(title_id & 0xff)}}; - return GetTitleName(id, language); + return GetTitleName(id, "", language); } std::string TitleDatabase::Describe(const std::string& gametdb_id, DiscIO::Language language) const { - const std::string& title_name = GetTitleName(gametdb_id, language); + const std::string& title_name = GetTitleName(gametdb_id, "", language); if (title_name.empty()) return gametdb_id; return fmt::format("{} ({})", title_name, gametdb_id); diff --git a/Source/Core/Core/TitleDatabase.h b/Source/Core/Core/TitleDatabase.h index 2d26477beae1..c1330969ef99 100644 --- a/Source/Core/Core/TitleDatabase.h +++ b/Source/Core/Core/TitleDatabase.h @@ -25,7 +25,9 @@ class TitleDatabase final // Get a user friendly title name for a GameTDB ID. // This falls back to returning an empty string if none could be found. - const std::string& GetTitleName(const std::string& gametdb_id, DiscIO::Language language) const; + const std::string& GetTitleName(const std::string& gametdb_id, const std::string& tri_id, + DiscIO::Language language) const; + const std::string& GetTriTitleName(const std::string& tri_id, DiscIO::Language language) const; // Same as above, but takes a title ID instead of a GameTDB ID, and only works for channels. const std::string& GetChannelName(u64 title_id, DiscIO::Language language) const; @@ -38,6 +40,7 @@ class TitleDatabase final std::unordered_map>> m_title_maps; + std::unordered_map m_trititle_map; std::unordered_map m_base_map; std::unordered_map m_user_title_map; }; diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index 574afd6f83bf..17d29ff0496d 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -104,6 +104,7 @@ class Volume } virtual std::string GetGameID(const Partition& partition = PARTITION_NONE) const = 0; virtual std::string GetGameTDBID(const Partition& partition = PARTITION_NONE) const = 0; + virtual std::optional GetTriID() const { return {}; } virtual std::string GetMakerID(const Partition& partition = PARTITION_NONE) const = 0; virtual std::optional GetRevision(const Partition& partition = PARTITION_NONE) const = 0; virtual std::string GetInternalName(const Partition& partition = PARTITION_NONE) const = 0; diff --git a/Source/Core/DiscIO/VolumeGC.cpp b/Source/Core/DiscIO/VolumeGC.cpp index 8af7a89bf552..30b6b2ad4d12 100644 --- a/Source/Core/DiscIO/VolumeGC.cpp +++ b/Source/Core/DiscIO/VolumeGC.cpp @@ -3,6 +3,7 @@ #include "DiscIO/VolumeGC.h" +#include #include #include #include @@ -49,11 +50,12 @@ VolumeGC::VolumeGC(std::unique_ptr reader) std::unique_ptr file_info = tmp_fs->FindFileInfo("boot.id"); if (!file_info) return; - u32 triforce_magic; // "BTID" + BootID triforce_header; const u64 file_size = ReadFile(*this, PARTITION_NONE, file_info.get(), - reinterpret_cast(&triforce_magic), sizeof(triforce_magic)); - if (file_size >= 4 && triforce_magic == BTID_MAGIC) + reinterpret_cast(&triforce_header), sizeof(BootID)); + if (file_size >= 4 && triforce_header.magic == BTID_MAGIC) m_is_triforce = true; + m_tri_id = triforce_header.id; } } @@ -82,6 +84,18 @@ std::string VolumeGC::GetGameTDBID(const Partition& partition) const return game_id == "GNHE5d" && IsDatelDisc() ? "" : game_id; } +std::optional VolumeGC::GetTriID() const +{ + if (m_is_triforce) + { + return (std::string(m_tri_id.data(), m_tri_id.size())); + } + else + { + return {}; + } +} + Region VolumeGC::GetRegion() const { return RegionCodeToRegion(m_reader->ReadSwapped(0x458)); diff --git a/Source/Core/DiscIO/VolumeGC.h b/Source/Core/DiscIO/VolumeGC.h index eb56425ce10b..0537b28bdb04 100644 --- a/Source/Core/DiscIO/VolumeGC.h +++ b/Source/Core/DiscIO/VolumeGC.h @@ -34,6 +34,7 @@ class VolumeGC : public VolumeDisc const Partition& partition = PARTITION_NONE) const override; const FileSystem* GetFileSystem(const Partition& partition = PARTITION_NONE) const override; std::string GetGameTDBID(const Partition& partition = PARTITION_NONE) const override; + std::optional GetTriID() const override; std::map GetShortNames() const override; std::map GetLongNames() const override; std::map GetShortMakers() const override; @@ -76,6 +77,13 @@ class VolumeGC : public VolumeDisc // (only one for BNR1 type) }; + struct BootID + { + u32 magic; // "BTID" + u32 padding[11]; + std::array id; + }; + struct ConvertedGCBanner { ConvertedGCBanner(); @@ -105,6 +113,7 @@ class VolumeGC : public VolumeDisc std::unique_ptr m_reader; bool m_is_triforce; + std::array m_tri_id; }; } // namespace DiscIO diff --git a/Source/Core/DolphinQt/Config/InfoWidget.cpp b/Source/Core/DolphinQt/Config/InfoWidget.cpp index 63d5dadd321b..0c0dec27e2ac 100644 --- a/Source/Core/DolphinQt/Config/InfoWidget.cpp +++ b/Source/Core/DolphinQt/Config/InfoWidget.cpp @@ -105,11 +105,13 @@ QGroupBox* InfoWidget::CreateGameDetails() .arg(m_game.GetRevision())); QString game_id_string = QString::fromStdString(m_game.GetGameID()); + QString tri_id_string = QString::fromStdString(m_game.GetTriID()); if (const u64 title_id = m_game.GetTitleID()) game_id_string += QStringLiteral(" (%1)").arg(title_id, 16, 16, QLatin1Char('0')); QLineEdit* game_id = CreateValueDisplay(game_id_string); + QLineEdit* tri_id = CreateValueDisplay(tri_id_string); QLineEdit* country = CreateValueDisplay(DiscIO::GetName(m_game.GetCountry(), true)); @@ -120,6 +122,8 @@ QGroupBox* InfoWidget::CreateGameDetails() m_game.GetMakerID() + ")"); layout->addRow(tr("Name:"), internal_name); + if (m_game.GetPlatform() == DiscIO::Platform::Triforce) + layout->addRow(tr("Boot (Triforce) ID:"), tri_id); layout->addRow(tr("Game ID:"), game_id); layout->addRow(tr("Country:"), country); layout->addRow(tr("Maker:"), maker); diff --git a/Source/Core/UICommon/GameFile.cpp b/Source/Core/UICommon/GameFile.cpp index b9c5db13798c..a28554afd005 100644 --- a/Source/Core/UICommon/GameFile.cpp +++ b/Source/Core/UICommon/GameFile.cpp @@ -141,6 +141,7 @@ GameFile::GameFile(std::string path) : m_file_path(std::move(path)) m_internal_name = volume->GetInternalName(); m_game_id = volume->GetGameID(); m_gametdb_id = volume->GetGameTDBID(); + m_tri_id = volume->GetTriID().value_or(""); m_title_id = volume->GetTitleID().value_or(0); m_maker_id = volume->GetMakerID(); m_revision = volume->GetRevision().value_or(0); @@ -361,6 +362,7 @@ void GameFile::DoState(PointerWrap& p) p.Do(m_internal_name); p.Do(m_game_id); p.Do(m_gametdb_id); + p.Do(m_tri_id); p.Do(m_title_id); p.Do(m_maker_id); @@ -547,7 +549,8 @@ const std::string& GameFile::GetName(const Core::TitleDatabase& title_database) if (IsModDescriptor()) return GetName(Variant::LongAndPossiblyCustom); - const std::string& database_name = title_database.GetTitleName(m_gametdb_id, GetConfigLanguage()); + const std::string& database_name = + title_database.GetTitleName(m_gametdb_id, m_tri_id, GetConfigLanguage()); return database_name.empty() ? GetName(Variant::LongAndPossiblyCustom) : database_name; } diff --git a/Source/Core/UICommon/GameFile.h b/Source/Core/UICommon/GameFile.h index eb1151a28a48..50f9b8edfb8c 100644 --- a/Source/Core/UICommon/GameFile.h +++ b/Source/Core/UICommon/GameFile.h @@ -76,6 +76,7 @@ class GameFile final const std::string& GetInternalName() const { return m_internal_name; } const std::string& GetGameID() const { return m_game_id; } const std::string& GetGameTDBID() const { return m_gametdb_id; } + std::string GetTriID() const { return m_tri_id; } u64 GetTitleID() const { return m_title_id; } const std::string& GetMakerID() const { return m_maker_id; } u16 GetRevision() const { return m_revision; } @@ -157,6 +158,7 @@ class GameFile final std::string m_internal_name; std::string m_game_id; std::string m_gametdb_id; + std::string m_tri_id; u64 m_title_id{}; std::string m_maker_id;