diff --git a/Data/Sys/ApprovedInis.json b/Data/Sys/ApprovedInis.json index 9d3b37c8d9..a73ed032f0 100644 --- a/Data/Sys/ApprovedInis.json +++ b/Data/Sys/ApprovedInis.json @@ -932,10 +932,6 @@ "title": "Region Select", "AD12237401ABE9FE4A545AADB5C5AE10355E2076": "RSAPatch" }, - "RELJAB": { - "title": "SegaBoot", - "130F3594CAB57B85616F95C7126F4748AAC5867D": "DI Seed Blanker" - }, "RGQE70": { "title": "Ghostbusters", "5F4CF8D4DA19A0FF74FF9EB925AC0236069BFD59": "crashfix" diff --git a/Data/Sys/GameSettings/GVS.ini b/Data/Sys/GameSettings/GVS.ini index 780267fa56..90641b1723 100644 --- a/Data/Sys/GameSettings/GVS.ini +++ b/Data/Sys/GameSettings/GVS.ini @@ -1,4 +1,5 @@ -# GVSE8P, GVSP8P - Virtua Striker 3 ver. 2002 +# GVSP8P, GVSE8P, GVSJ8P - Virtua Striker 2002 (GC) +# GVSJ8P - Virtua Striker 2002 (Triforce), Virtua Striker 4, Virtua Striker 4 ver. 2006 [Core] # Values set here will override the main Dolphin settings. @@ -10,3 +11,7 @@ FPRF = True [ActionReplay] # Add action replay cheats here. +[Video] +# Add memory patches to be applied every frame here. + +[Video_Settings] diff --git a/Data/Sys/GameSettings/GVS46E.ini b/Data/Sys/GameSettings/GVS46E.ini deleted file mode 100644 index 40061416f8..0000000000 --- a/Data/Sys/GameSettings/GVS46E.ini +++ /dev/null @@ -1,18 +0,0 @@ -# GVS46E, GVS46J - Virtua Striker 4 ver. 2006 -# Because Triforce games have weird IDs, properties are inherited from GVS.ini (Virtua Striker 3 ver. 2002)! - -[Core] -# Values set here will override the main Dolphin settings. -FPRF = True - -[OnFrame] -# Add memory patches to be applied every frame here. - -[ActionReplay] -# Add action replay cheats here. - -[Video] -# Add memory patches to be applied every frame here. - -[Video_Settings] - diff --git a/Data/Sys/GameSettings/GVS46J.ini b/Data/Sys/GameSettings/GVS46J.ini deleted file mode 100644 index 40061416f8..0000000000 --- a/Data/Sys/GameSettings/GVS46J.ini +++ /dev/null @@ -1,18 +0,0 @@ -# GVS46E, GVS46J - Virtua Striker 4 ver. 2006 -# Because Triforce games have weird IDs, properties are inherited from GVS.ini (Virtua Striker 3 ver. 2002)! - -[Core] -# Values set here will override the main Dolphin settings. -FPRF = True - -[OnFrame] -# Add memory patches to be applied every frame here. - -[ActionReplay] -# Add action replay cheats here. - -[Video] -# Add memory patches to be applied every frame here. - -[Video_Settings] - diff --git a/Data/Sys/GameSettings/RELJAB.ini b/Data/Sys/GameSettings/RELJAB.ini deleted file mode 100644 index 872c654b6e..0000000000 --- a/Data/Sys/GameSettings/RELJAB.ini +++ /dev/null @@ -1,18 +0,0 @@ -# RELJAB - SegaBoot - -[Core] -# Values set here will override the main Dolphin settings. - -[OnFrame] -# Add memory patches to be applied every frame here. -$DI Seed Blanker -0x80000000:dword:0x00000000 -0x80000004:dword:0x00000000 -0x80000008:dword:0x00000000 - -[Patches_RetroAchievements_Verified] -$DI Seed Blanker - -[ActionReplay] -# Add action replay cheats here. - diff --git a/Data/Sys/Resources/Platform_Triforce.png b/Data/Sys/Resources/Platform_Triforce.png new file mode 100644 index 0000000000..e6a3b26b76 Binary files /dev/null and b/Data/Sys/Resources/Platform_Triforce.png differ diff --git a/Data/Sys/Resources/Platform_Triforce@2x.png b/Data/Sys/Resources/Platform_Triforce@2x.png new file mode 100644 index 0000000000..3efae35bd5 Binary files /dev/null and b/Data/Sys/Resources/Platform_Triforce@2x.png differ diff --git a/Data/Sys/Resources/Platform_Triforce@4x.png b/Data/Sys/Resources/Platform_Triforce@4x.png new file mode 100644 index 0000000000..85bf7c272d Binary files /dev/null and b/Data/Sys/Resources/Platform_Triforce@4x.png differ diff --git a/Data/Sys/triforcetdb-en.txt b/Data/Sys/triforcetdb-en.txt new file mode 100644 index 0000000000..a397bb0419 --- /dev/null +++ b/Data/Sys/triforcetdb-en.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/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java index c7401c2bc5..f13578d7ae 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java @@ -30,8 +30,8 @@ import java.util.Set; public final class FileBrowserHelper { public static final HashSet GAME_EXTENSIONS = new HashSet<>(Arrays.asList( - "gcm", "tgc", "iso", "ciso", "gcz", "wbfs", "wia", "rvz", "nfs", "wad", "dol", "elf", - "json")); + "gcm", "tgc", "bin", "iso", "ciso", "gcz", "wbfs", "wia", "rvz", "nfs", "wad", "dol", + "elf", "json")); public static final HashSet GAME_LIKE_EXTENSIONS = new HashSet<>(GAME_EXTENSIONS); diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index f46b7e9da3..dfa6bb535e 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -80,8 +80,8 @@ public: static constexpr std::string_view BLUE = "#0B71C1"; static constexpr std::string_view APPROVED_LIST_FILENAME = "ApprovedInis.json"; static const inline Common::SHA1::Digest APPROVED_LIST_HASH = { - 0x4F, 0x45, 0xB7, 0xA3, 0xC4, 0x6E, 0xAF, 0x80, 0x58, 0xA5, - 0x53, 0x99, 0xF8, 0x05, 0xC3, 0x83, 0x22, 0xA4, 0x5F, 0x65}; + 0xE1, 0x29, 0xD1, 0x33, 0x4D, 0xF2, 0xF8, 0xA8, 0x4E, 0xCA, + 0xF6, 0x87, 0xE6, 0xEC, 0xEC, 0xB3, 0x18, 0x69, 0x34, 0x45}; struct LeaderboardEntry { diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 1340d19c84..e95984f122 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -236,7 +236,8 @@ std::unique_ptr BootParameters::GenerateFromFile(std::vector disc_image_extensions = { - {".gcm", ".iso", ".tgc", ".wbfs", ".ciso", ".gcz", ".wia", ".rvz", ".nfs", ".dol", ".elf"}}; + {".gcm", ".bin", ".iso", ".tgc", ".wbfs", ".ciso", ".gcz", ".wia", ".rvz", ".nfs", ".dol", + ".elf"}}; if (disc_image_extensions.contains(extension)) { std::unique_ptr disc = DiscIO::CreateDisc(path); @@ -406,6 +407,7 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename) constexpr u32 PAL_v1_0 = 0x4F319F43; // DOL-101(EUR) (PAL Revision 1.2) constexpr u32 PAL_v1_2 = 0xAD1B7F16; + constexpr u32 Triforce = 0xD1883221; // The Triforce's special IPL // Load the IPL ROM dump, limited to 2MiB which is the size of the official IPLs. constexpr size_t max_ipl_size = 2 * 1024 * 1024; @@ -423,6 +425,7 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename) const u32 ipl_hash = Common::ComputeCRC32(data.data(), data.size()); bool known_ipl = false; bool pal_ipl = false; + bool triforce_ipl = false; switch (ipl_hash) { case NTSC_v1_0: @@ -437,6 +440,9 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename) pal_ipl = true; known_ipl = true; break; + case Triforce: + known_ipl = true; + triforce_ipl = true; default: PanicAlertFmtT("The IPL file is not a known good dump. (CRC32: {0:x})", ipl_hash); break; diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index baf2079677..884a11bd87 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -227,6 +227,13 @@ bool CBoot::RunApploader(Core::System& system, const Core::CPUThreadGuard& guard ppc_state.pc = ppc_state.gpr[3]; branch_watch.SetRecordingActive(guard, resume_branch_watch); + // Blank out session key (https://debugmo.de/2008/05/part-2-dumping-the-media-board/) + if (volume.GetVolumeType() == DiscIO::Platform::Triforce) + { + auto& memory = system.GetMemory(); + + memory.Memset(0, 0, 12); + } return true; } diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index b4437747e8..09b69a620e 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -203,6 +203,8 @@ add_library(core HW/EXI/EXI_DeviceAD16.h HW/EXI/EXI_DeviceAGP.cpp HW/EXI/EXI_DeviceAGP.h + HW/EXI/EXI_DeviceBaseboard.cpp + HW/EXI/EXI_DeviceBaseboard.h HW/EXI/EXI_DeviceDummy.cpp HW/EXI/EXI_DeviceDummy.h HW/EXI/EXI_DeviceEthernet.cpp diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 37f2a6054e..7af0fd2766 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -437,6 +437,7 @@ const Info MAIN_GAMELIST_LIST_WAD{{System::Main, "GameList", "ListWad"}, t const Info MAIN_GAMELIST_LIST_ELF_DOL{{System::Main, "GameList", "ListElfDol"}, true}; const Info MAIN_GAMELIST_LIST_WII{{System::Main, "GameList", "ListWii"}, true}; const Info MAIN_GAMELIST_LIST_GC{{System::Main, "GameList", "ListGC"}, true}; +const Info MAIN_GAMELIST_LIST_TRI{{System::Main, "GameList", "ListTriforce"}, true}; const Info MAIN_GAMELIST_LIST_JPN{{System::Main, "GameList", "ListJap"}, true}; const Info MAIN_GAMELIST_LIST_PAL{{System::Main, "GameList", "ListPal"}, true}; const Info MAIN_GAMELIST_LIST_USA{{System::Main, "GameList", "ListUsa"}, true}; diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 51aa7ec8aa..344263ba10 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -269,6 +269,7 @@ extern const Info MAIN_GAMELIST_LIST_WAD; extern const Info MAIN_GAMELIST_LIST_ELF_DOL; extern const Info MAIN_GAMELIST_LIST_WII; extern const Info MAIN_GAMELIST_LIST_GC; +extern const Info MAIN_GAMELIST_LIST_TRI; extern const Info MAIN_GAMELIST_LIST_JPN; extern const Info MAIN_GAMELIST_LIST_PAL; extern const Info MAIN_GAMELIST_LIST_USA; diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 9101df907a..e005e78341 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -126,6 +126,12 @@ const std::string SConfig::GetTitleDescription() const return m_title_description; } +std::string SConfig::GetTriforceID() const +{ + std::lock_guard lock(m_metadata_lock); + return m_triforce_id; +} + u64 SConfig::GetTitleID() const { std::lock_guard lock(m_metadata_lock); @@ -141,7 +147,7 @@ u16 SConfig::GetRevision() const void SConfig::ResetRunningGameMetadata() { std::lock_guard lock(m_metadata_lock); - SetRunningGameMetadata("00000000", "", 0, 0, DiscIO::Region::Unknown); + SetRunningGameMetadata("00000000", "", "", 0, 0, DiscIO::Region::Unknown); } void SConfig::SetRunningGameMetadata(const DiscIO::Volume& volume, @@ -150,14 +156,14 @@ void SConfig::SetRunningGameMetadata(const DiscIO::Volume& volume, std::lock_guard lock(m_metadata_lock); if (partition == volume.GetGamePartition()) { - SetRunningGameMetadata(volume.GetGameID(), volume.GetGameTDBID(), + SetRunningGameMetadata(volume.GetGameID(), volume.GetGameTDBID(), volume.GetTriforceID(), volume.GetTitleID().value_or(0), volume.GetRevision().value_or(0), volume.GetRegion()); } else { SetRunningGameMetadata(volume.GetGameID(partition), volume.GetGameTDBID(partition), - volume.GetTitleID(partition).value_or(0), + volume.GetTriforceID(), volume.GetTitleID(partition).value_or(0), volume.GetRevision(partition).value_or(0), volume.GetRegion()); } } @@ -175,25 +181,28 @@ void SConfig::SetRunningGameMetadata(const IOS::ES::TMDReader& tmd, DiscIO::Plat !Core::System::GetInstance().GetDVDInterface().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) { std::lock_guard lock(m_metadata_lock); - 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 triforce_id, u64 title_id, u16 revision, + DiscIO::Region region) { std::lock_guard lock(m_metadata_lock); const bool was_changed = m_game_id != game_id || m_gametdb_id != gametdb_id || - m_title_id != title_id || m_revision != revision; + m_triforce_id != triforce_id || m_title_id != title_id || + m_revision != revision; m_game_id = game_id; m_gametdb_id = gametdb_id; + m_triforce_id = triforce_id; m_title_id = title_id; m_revision = revision; @@ -226,7 +235,7 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri const Core::TitleDatabase title_database; auto& system = Core::System::GetInstance(); const DiscIO::Language language = GetLanguageAdjustedForRegion(system.IsWii(), region); - m_title_name = title_database.GetTitleName(m_gametdb_id, language); + m_title_name = title_database.GetTitleName(m_gametdb_id, m_triforce_id, language); m_title_description = title_database.Describe(m_gametdb_id, language); NOTICE_LOG_FMT(CORE, "Active title: {}", m_title_description); Host_TitleChanged(); @@ -298,6 +307,7 @@ void SConfig::LoadDefaults() auto& system = Core::System::GetInstance(); system.SetIsWii(false); + system.SetIsTriforce(false); ResetRunningGameMetadata(); } @@ -321,6 +331,7 @@ struct SetGameMetadata { *region = disc.volume->GetRegion(); system.SetIsWii(disc.volume->GetVolumeType() == DiscIO::Platform::WiiDisc); + system.SetIsTriforce(disc.volume->GetVolumeType() == DiscIO::Platform::Triforce); config->m_disc_booted_from_game_list = true; config->SetRunningGameMetadata(*disc.volume, disc.volume->GetGamePartition()); return true; diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 84be081b64..f441cd888b 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -67,6 +67,7 @@ struct SConfig const std::string GetGameTDBID() const; const std::string GetTitleName() const; const std::string GetTitleDescription() const; + std::string GetTriforceID() const; u64 GetTitleID() const; u16 GetRevision() const; void ResetRunningGameMetadata(); @@ -121,13 +122,15 @@ private: static void ReloadTextures(Core::System& system); void SetRunningGameMetadata(const std::string& game_id, const std::string& gametdb_id, - u64 title_id, u16 revision, DiscIO::Region region); + std::string triforce_id, u64 title_id, u16 revision, + DiscIO::Region region); static SConfig* m_Instance; mutable std::recursive_mutex m_metadata_lock; std::string m_game_id; std::string m_gametdb_id; + std::string m_triforce_id; std::string m_title_name; std::string m_title_description; u64 m_title_id; diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp index babb500902..f6e7954b02 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp @@ -753,6 +753,15 @@ void DVDInterface::ExecuteCommand(ReplyType reply_type) DIInterruptType interrupt_type = DIInterruptType::TCINT; bool command_handled_by_thread = false; + // Swaps endian of Triforce DI commands, and zeroes out random bytes to prevent unknown read + // subcommand errors + auto& dvd_thread = m_system.GetDVDThread(); + if (dvd_thread.GetDiscType() == DiscIO::Platform::Triforce) + { + // TODO(C++23): Use std::byteswap and a bitwise AND for increased clarity + m_DICMDBUF[0] <<= 24; + } + // DVDLowRequestError needs access to the error code set by the previous command if (static_cast(m_DICMDBUF[0] >> 24) != DICommand::RequestError) SetDriveError(DriveError::None); diff --git a/Source/Core/Core/HW/EXI/EXI.cpp b/Source/Core/Core/HW/EXI/EXI.cpp index 303191c574..d676dc4845 100644 --- a/Source/Core/Core/HW/EXI/EXI.cpp +++ b/Source/Core/Core/HW/EXI/EXI.cpp @@ -66,6 +66,18 @@ void ExpansionInterfaceManager::AddMemoryCard(Slot slot) m_channels[SlotToEXIChannel(slot)]->AddDevice(memorycard_device, SlotToEXIDevice(slot)); } +void ExpansionInterfaceManager::AddSP1Device() +{ + EXIDeviceType sp1_device = EXIDeviceType::Baseboard; + auto& system = Core::System::GetInstance(); + if (system.IsTriforce()) + { + sp1_device = Config::Get(Config::MAIN_SERIAL_PORT_1); + } + + m_channels[0]->AddDevice(sp1_device, SlotToEXIDevice(Slot::SP1)); +} + u8 SlotToEXIChannel(Slot slot) { switch (slot) @@ -145,6 +157,7 @@ void ExpansionInterfaceManager::Init(const Sram* override_sram) AddMemoryCard(slot); m_channels[0]->AddDevice(EXIDeviceType::MaskROM, 1); + AddSP1Device(); m_channels[SlotToEXIChannel(Slot::SP1)]->AddDevice(Config::Get(Config::MAIN_SERIAL_PORT_1), SlotToEXIDevice(Slot::SP1)); m_channels[SlotToEXIChannel(Slot::SP2)]->AddDevice(Config::Get(Config::MAIN_SERIAL_PORT_2), diff --git a/Source/Core/Core/HW/EXI/EXI.h b/Source/Core/Core/HW/EXI/EXI.h index 7ded905b98..f0ea5fbfb5 100644 --- a/Source/Core/Core/HW/EXI/EXI.h +++ b/Source/Core/Core/HW/EXI/EXI.h @@ -89,6 +89,7 @@ public: private: void AddMemoryCard(Slot slot); + void AddSP1Device(); static void ChangeDeviceCallback(Core::System& system, u64 userdata, s64 cycles_late); static void UpdateInterruptsCallback(Core::System& system, u64 userdata, s64 cycles_late); diff --git a/Source/Core/Core/HW/EXI/EXI_Device.cpp b/Source/Core/Core/HW/EXI/EXI_Device.cpp index 6c416d5387..ac92c7b723 100644 --- a/Source/Core/Core/HW/EXI/EXI_Device.cpp +++ b/Source/Core/Core/HW/EXI/EXI_Device.cpp @@ -9,6 +9,7 @@ #include "Common/MsgHandler.h" #include "Core/HW/EXI/EXI_DeviceAD16.h" #include "Core/HW/EXI/EXI_DeviceAGP.h" +#include "Core/HW/EXI/EXI_DeviceBaseboard.h" #include "Core/HW/EXI/EXI_DeviceDummy.h" #include "Core/HW/EXI/EXI_DeviceEthernet.h" #include "Core/HW/EXI/EXI_DeviceGecko.h" @@ -171,7 +172,10 @@ std::unique_ptr EXIDevice_Create(Core::System& system, const EXIDevi result = std::make_unique(system, slot); break; - case EXIDeviceType::AMBaseboard: + case EXIDeviceType::Baseboard: + result = std::make_unique(system); + break; + case EXIDeviceType::None: default: result = std::make_unique(system); diff --git a/Source/Core/Core/HW/EXI/EXI_Device.h b/Source/Core/Core/HW/EXI/EXI_Device.h index db74306df0..25263af425 100644 --- a/Source/Core/Core/HW/EXI/EXI_Device.h +++ b/Source/Core/Core/HW/EXI/EXI_Device.h @@ -30,9 +30,7 @@ enum class EXIDeviceType : int AD16, Microphone, Ethernet, - // Was used for Triforce in the past, but the implementation is no longer in Dolphin. - // It's kept here so that values below will stay constant. - AMBaseboard, + Baseboard, Gecko, // Only used when creating a device by EXIDevice_Create. // Converted to MemoryCard internally. @@ -98,7 +96,7 @@ struct fmt::formatter _trans("AD16"), _trans("Microphone"), _trans("Broadband Adapter (TAP)"), - _trans("Triforce AM Baseboard"), + _trans("Triforce Baseboard"), _trans("USB Gecko"), _trans("GCI Folder"), _trans("Advance Game Port"), diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.cpp new file mode 100644 index 0000000000..a9200ac85a --- /dev/null +++ b/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.cpp @@ -0,0 +1,57 @@ +// Copyright 2013 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "Core/HW/EXI/EXI_DeviceBaseboard.h" + +#include "Common/Assert.h" +#include "Common/ChunkFile.h" +#include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" + +namespace ExpansionInterface +{ +CEXIBaseboard::CEXIBaseboard(Core::System& system) : IEXIDevice(system) +{ +} + +void CEXIBaseboard::SetCS(int cs) +{ + if (cs) + m_position = 0; +} + +bool CEXIBaseboard::IsPresent() const +{ + return true; +} + +void CEXIBaseboard::TransferByte(u8& byte) +{ + if (m_position == 0) + { + m_command = byte; + } + else + { + switch (m_command) + { + case 0x00: + { + static constexpr std::array ID = {0x06, 0x04, 0x10, 0x00}; + byte = ID[(m_position - 2) & 3]; + break; + } + default: + ERROR_LOG_FMT(EXPANSIONINTERFACE, "EXI BASEBOARD: Unhandled command {:#x} {:#x}", m_command, + m_position); + } + } + m_position++; +} + +void CEXIBaseboard::DoState(PointerWrap& p) +{ + p.Do(m_position); + p.Do(m_command); +} +} // namespace ExpansionInterface diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.h b/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.h new file mode 100644 index 0000000000..4c534428c9 --- /dev/null +++ b/Source/Core/Core/HW/EXI/EXI_DeviceBaseboard.h @@ -0,0 +1,27 @@ +// Copyright 2013 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "Core/HW/EXI/EXI_Device.h" + +class PointerWrap; + +namespace ExpansionInterface +{ +class CEXIBaseboard : public IEXIDevice +{ +public: + CEXIBaseboard(Core::System& system); + void SetCS(int cs) override; + bool IsPresent() const override; + void DoState(PointerWrap& p) override; + +private: + // STATE_TO_SAVE + u32 m_position = 0; + u32 m_command = 0; + + void TransferByte(u8& byte) override; +}; +} // namespace ExpansionInterface diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 44465b3f42..9620cfccd4 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -99,7 +99,7 @@ static size_t s_state_writes_in_queue; static std::condition_variable s_state_write_queue_is_empty; // Don't forget to increase this after doing changes on the savestate system -constexpr u32 STATE_VERSION = 172; // Last changed in PR 13385 +constexpr u32 STATE_VERSION = 173; // Last changed in PR 10084 // Increase this if the StateExtendedHeader definition changes constexpr u32 EXTENDED_HEADER_VERSION = 1; // Last changed in PR 12217 diff --git a/Source/Core/Core/System.h b/Source/Core/Core/System.h index 9ec8391ff0..0ab86e658d 100644 --- a/Source/Core/Core/System.h +++ b/Source/Core/Core/System.h @@ -141,10 +141,12 @@ public: bool IsMMUMode() const { return m_mmu_enabled; } bool IsPauseOnPanicMode() const { return m_pause_on_panic_enabled; } bool IsMIOS() const { return m_is_mios; } + bool IsTriforce() const { return m_is_triforce; } bool IsWii() const { return m_is_wii; } bool IsBranchWatchIgnoreApploader() { return m_branch_watch_ignore_apploader; } void SetIsMIOS(bool is_mios) { m_is_mios = is_mios; } + void SetIsTriforce(bool is_triforce) { m_is_triforce = is_triforce; } void SetIsWii(bool is_wii) { m_is_wii = is_wii; } void SetIsBranchWatchIgnoreApploader(bool enable) { m_branch_watch_ignore_apploader = enable; } @@ -205,6 +207,7 @@ private: bool m_mmu_enabled = false; bool m_pause_on_panic_enabled = false; bool m_is_mios = false; + bool m_is_triforce = false; bool m_is_wii = false; bool m_branch_watch_ignore_apploader = false; }; diff --git a/Source/Core/Core/TitleDatabase.cpp b/Source/Core/Core/TitleDatabase.cpp index 391a0dc044..4609cfddb1 100644 --- a/Source/Core/Core/TitleDatabase.cpp +++ b/Source/Core/Core/TitleDatabase.cpp @@ -56,6 +56,9 @@ void TitleDatabase::AddLazyMap(DiscIO::Language language, const std::string& lan m_title_maps[language] = [language_code]() -> Map { return LoadMap(File::GetSysDirectory() + "wiitdb-" + language_code + ".txt"); }; + m_triforce_title_maps[language] = [language_code]() -> Map { + return LoadMap(File::GetSysDirectory() + "triforcetdb-" + language_code + ".txt"); + }; } TitleDatabase::TitleDatabase() @@ -91,8 +94,32 @@ TitleDatabase::TitleDatabase() TitleDatabase::~TitleDatabase() = default; const std::string& TitleDatabase::GetTitleName(const std::string& gametdb_id, + const std::string& triforce_id, DiscIO::Language language) const { + if (triforce_id != "") + { + const Map& map = *m_triforce_title_maps.at(DiscIO::Language::English); + auto it = map.find(triforce_id); + if (it != map.end()) + return it->second; + + // This code has been commented out as there is currently only a english title map, and all + // Triforce games are detected as Japanese. + + // if (language != DiscIO::Language::English) + //{ + // const Map& english_triforce_map = *m_triforce_title_maps.at(DiscIO::Language::English); + // it = english_triforce_map.find(triforce_id); + // if (it != english_triforce_map.end()) + // return it->second; + //} + + // it = m_base_map.find(triforce_id); + // if (it != m_base_map.end()) + // return it->second; + } + auto it = m_user_title_map.find(gametdb_id); if (it != m_user_title_map.end()) return it->second; @@ -125,12 +152,12 @@ const std::string& TitleDatabase::GetChannelName(u64 title_id, DiscIO::Language 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 2d26477bea..dff9a56dfe 100644 --- a/Source/Core/Core/TitleDatabase.h +++ b/Source/Core/Core/TitleDatabase.h @@ -25,7 +25,8 @@ public: // 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& triforce_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 +39,8 @@ private: std::unordered_map>> m_title_maps; + std::unordered_map>> + m_triforce_title_maps; std::unordered_map m_base_map; std::unordered_map m_user_title_map; }; diff --git a/Source/Core/DiscIO/Enums.cpp b/Source/Core/DiscIO/Enums.cpp index 2d6f22d164..28487d346e 100644 --- a/Source/Core/DiscIO/Enums.cpp +++ b/Source/Core/DiscIO/Enums.cpp @@ -139,7 +139,8 @@ std::string GetName(Region region, bool translate) bool IsDisc(Platform volume_type) { - return volume_type == Platform::GameCubeDisc || volume_type == Platform::WiiDisc; + return volume_type == Platform::GameCubeDisc || volume_type == Platform::Triforce || + volume_type == Platform::WiiDisc; } bool IsWii(Platform volume_type) diff --git a/Source/Core/DiscIO/Enums.h b/Source/Core/DiscIO/Enums.h index 4881a8d980..9b5e274de9 100644 --- a/Source/Core/DiscIO/Enums.h +++ b/Source/Core/DiscIO/Enums.h @@ -15,6 +15,7 @@ namespace DiscIO enum class Platform { GameCubeDisc = 0, + Triforce, WiiDisc, WiiWAD, ELFOrDOL, diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index 838ae28984..a7273b0f0e 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -96,6 +96,7 @@ public: } virtual std::string GetGameID(const Partition& partition = PARTITION_NONE) const = 0; virtual std::string GetGameTDBID(const Partition& partition = PARTITION_NONE) const = 0; + virtual std::string GetTriforceID() 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 8a95e0bb31..8cc255570a 100644 --- a/Source/Core/DiscIO/VolumeGC.cpp +++ b/Source/Core/DiscIO/VolumeGC.cpp @@ -29,7 +29,8 @@ namespace DiscIO { -VolumeGC::VolumeGC(std::unique_ptr reader) : m_reader(std::move(reader)) +VolumeGC::VolumeGC(std::unique_ptr reader) + : m_reader(std::move(reader)), m_is_triforce(false) { ASSERT(m_reader); @@ -39,6 +40,23 @@ VolumeGC::VolumeGC(std::unique_ptr reader) : m_reader(std::move(read }; m_converted_banner = [this] { return LoadBannerFile(); }; + + constexpr u32 BTID_MAGIC = 0x44495442; + auto tmp_fs = GetFileSystem(PARTITION_NONE); + if (tmp_fs) + { + std::unique_ptr file_info = tmp_fs->FindFileInfo("boot.id"); + if (!file_info) + return; + BootID triforce_header; + const u64 file_size = ReadFile(*this, PARTITION_NONE, file_info.get(), + reinterpret_cast(&triforce_header), sizeof(BootID)); + if (file_size >= 4 && triforce_header.magic == BTID_MAGIC) + { + m_is_triforce = true; + m_triforce_id = triforce_header.id; + } + } } VolumeGC::~VolumeGC() = default; @@ -75,6 +93,14 @@ std::string VolumeGC::GetGameTDBID(const Partition& partition) const return GetGameID(partition); } +std::string VolumeGC::GetTriforceID() const +{ + if (m_is_triforce) + return (std::string(m_triforce_id.data(), m_triforce_id.size())); + else + return ""; +} + Region VolumeGC::GetRegion() const { return RegionCodeToRegion(m_reader->ReadSwapped(0x458)); @@ -139,7 +165,10 @@ const BlobReader& VolumeGC::GetBlobReader() const Platform VolumeGC::GetVolumeType() const { - return Platform::GameCubeDisc; + if (m_is_triforce) + return Platform::Triforce; + else + return Platform::GameCubeDisc; } bool VolumeGC::IsDatelDisc() const diff --git a/Source/Core/DiscIO/VolumeGC.h b/Source/Core/DiscIO/VolumeGC.h index d877bc7719..5cf4ea0eed 100644 --- a/Source/Core/DiscIO/VolumeGC.h +++ b/Source/Core/DiscIO/VolumeGC.h @@ -34,6 +34,7 @@ public: 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::string GetTriforceID() const override; std::map GetShortNames() const override; std::map GetLongNames() const override; std::map GetShortMakers() const override; @@ -76,6 +77,13 @@ private: // (only one for BNR1 type) }; + struct BootID + { + u32 magic; // "BTID" + u32 padding[11]; + std::array id; + }; + struct ConvertedGCBanner { ConvertedGCBanner(); @@ -103,6 +111,9 @@ private: Common::Lazy> m_file_system; std::unique_ptr m_reader; + + bool m_is_triforce; + std::array m_triforce_id; }; } // namespace DiscIO diff --git a/Source/Core/DiscIO/VolumeVerifier.cpp b/Source/Core/DiscIO/VolumeVerifier.cpp index 414e4ae3a1..bbe02e7d22 100644 --- a/Source/Core/DiscIO/VolumeVerifier.cpp +++ b/Source/Core/DiscIO/VolumeVerifier.cpp @@ -402,6 +402,7 @@ void VolumeVerifier::Start() m_is_tgc = m_volume.GetBlobType() == BlobType::TGC; m_is_datel = m_volume.IsDatelDisc(); + m_is_triforce = m_volume.GetVolumeType() == Platform::Triforce; m_is_not_retail = (m_volume.GetVolumeType() == Platform::WiiDisc && !m_volume.HasWiiHashes()) || IsDebugSigned(); @@ -1373,6 +1374,13 @@ void VolumeVerifier::Finish() return; } + if (m_is_triforce) + { + m_result.summary_text = + Common::GetStringT("Dolphin is currently unable to verify Triforce games."); + return; + } + if (m_result.redump.status == RedumpVerifier::Status::BadDump && highest_severity <= Severity::Low) { diff --git a/Source/Core/DiscIO/VolumeVerifier.h b/Source/Core/DiscIO/VolumeVerifier.h index 934e60b7b1..7a5c342e1b 100644 --- a/Source/Core/DiscIO/VolumeVerifier.h +++ b/Source/Core/DiscIO/VolumeVerifier.h @@ -165,6 +165,7 @@ private: Result m_result; bool m_is_tgc = false; bool m_is_datel = false; + bool m_is_triforce = false; bool m_is_not_retail = false; bool m_redump_verification; diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 388367afd1..4c7764202d 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -281,6 +281,7 @@ + @@ -948,6 +949,7 @@ + diff --git a/Source/Core/DolphinQt/Config/InfoWidget.cpp b/Source/Core/DolphinQt/Config/InfoWidget.cpp index a13b31ea34..6a41b7de12 100644 --- a/Source/Core/DolphinQt/Config/InfoWidget.cpp +++ b/Source/Core/DolphinQt/Config/InfoWidget.cpp @@ -93,6 +93,7 @@ QGroupBox* InfoWidget::CreateGameDetails() const QString game_name = QString::fromStdString(m_game.GetInternalName()); bool is_disc_based = m_game.GetPlatform() == DiscIO::Platform::GameCubeDisc || + m_game.GetPlatform() == DiscIO::Platform::Triforce || m_game.GetPlatform() == DiscIO::Platform::WiiDisc; QLineEdit* internal_name = @@ -105,11 +106,13 @@ QGroupBox* InfoWidget::CreateGameDetails() .arg(m_game.GetRevision())); QString game_id_string = QString::fromStdString(m_game.GetGameID()); + QString triforce_id_string = QString::fromStdString(m_game.GetTriforceID()); 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* triforce_id = CreateValueDisplay(triforce_id_string); QLineEdit* country = CreateValueDisplay(DiscIO::GetName(m_game.GetCountry(), true)); @@ -120,6 +123,8 @@ QGroupBox* InfoWidget::CreateGameDetails() m_game.GetMakerID() + ")"); layout->addRow(tr("Name:"), internal_name); + if (m_game.GetPlatform() == DiscIO::Platform::Triforce) + layout->addRow(tr("Triforce ID:"), triforce_id); layout->addRow(tr("Game ID:"), game_id); layout->addRow(tr("Country:"), country); layout->addRow(tr("Maker:"), maker); diff --git a/Source/Core/DolphinQt/GameList/GameListModel.cpp b/Source/Core/DolphinQt/GameList/GameListModel.cpp index c8c1d8b165..42a911ce49 100644 --- a/Source/Core/DolphinQt/GameList/GameListModel.cpp +++ b/Source/Core/DolphinQt/GameList/GameListModel.cpp @@ -303,6 +303,8 @@ bool GameListModel::ShouldDisplayGameListItem(int index) const { case DiscIO::Platform::GameCubeDisc: return Config::Get(Config::MAIN_GAMELIST_LIST_GC); + case DiscIO::Platform::Triforce: + return Config::Get(Config::MAIN_GAMELIST_LIST_TRI); case DiscIO::Platform::WiiDisc: return Config::Get(Config::MAIN_GAMELIST_LIST_WII); case DiscIO::Platform::WiiWAD: diff --git a/Source/Core/DolphinQt/GameList/GameTracker.cpp b/Source/Core/DolphinQt/GameList/GameTracker.cpp index 9428729997..6031d37a32 100644 --- a/Source/Core/DolphinQt/GameList/GameTracker.cpp +++ b/Source/Core/DolphinQt/GameList/GameTracker.cpp @@ -22,13 +22,13 @@ // NOTE: Qt likes to be case-sensitive here even though it shouldn't be thus this ugly regex hack static const QStringList game_filters{ - QStringLiteral("*.[gG][cC][mM]"), QStringLiteral("*.[iI][sS][oO]"), - QStringLiteral("*.[tT][gG][cC]"), QStringLiteral("*.[cC][iI][sS][oO]"), - QStringLiteral("*.[gG][cC][zZ]"), QStringLiteral("*.[wW][bB][fF][sS]"), - QStringLiteral("*.[wW][iI][aA]"), QStringLiteral("*.[rR][vV][zZ]"), - QStringLiteral("hif_000000.nfs"), QStringLiteral("*.[wW][aA][dD]"), - QStringLiteral("*.[eE][lL][fF]"), QStringLiteral("*.[dD][oO][lL]"), - QStringLiteral("*.[jJ][sS][oO][nN]")}; + QStringLiteral("*.[gG][cC][mM]"), QStringLiteral("*.[bB][iI][nN]"), + QStringLiteral("*.[iI][sS][oO]"), QStringLiteral("*.[tT][gG][cC]"), + QStringLiteral("*.[cC][iI][sS][oO]"), QStringLiteral("*.[gG][cC][zZ]"), + QStringLiteral("*.[wW][bB][fF][sS]"), QStringLiteral("*.[wW][iI][aA]"), + QStringLiteral("*.[rR][vV][zZ]"), QStringLiteral("hif_000000.nfs"), + QStringLiteral("*.[wW][aA][dD]"), QStringLiteral("*.[eE][lL][fF]"), + QStringLiteral("*.[dD][oO][lL]"), QStringLiteral("*.[jJ][sS][oO][nN]")}; GameTracker::GameTracker(QObject* parent) : QFileSystemWatcher(parent) { diff --git a/Source/Core/DolphinQt/Info.plist.in b/Source/Core/DolphinQt/Info.plist.in index ddd2ed4182..0550533969 100644 --- a/Source/Core/DolphinQt/Info.plist.in +++ b/Source/Core/DolphinQt/Info.plist.in @@ -7,6 +7,7 @@ CFBundleTypeExtensions + bin ciso dol elf diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 93ad16a59e..6cb0a39a06 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -787,7 +787,7 @@ QStringList MainWindow::PromptFileNames() QStringList paths = DolphinFileDialog::getOpenFileNames( this, tr("Select a File"), settings.value(QStringLiteral("mainwindow/lastdir"), QString{}).toString(), - QStringLiteral("%1 (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wia *.rvz " + QStringLiteral("%1 (*.elf *.dol *.gcm *.bin *.iso *.tgc *.wbfs *.ciso *.gcz *.wia *.rvz " "hif_000000.nfs *.wad *.dff *.m3u *.json);;%2 (*)") .arg(tr("All GC/Wii files")) .arg(tr("All Files"))); diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 24c6cc2d04..a4e2b17c0d 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -726,6 +726,7 @@ void MenuBar::AddShowPlatformsMenu(QMenu* view_menu) static const QMap*> platform_map{ {tr("Show Wii"), &Config::MAIN_GAMELIST_LIST_WII}, {tr("Show GameCube"), &Config::MAIN_GAMELIST_LIST_GC}, + {tr("Show Triforce"), &Config::MAIN_GAMELIST_LIST_TRI}, {tr("Show WAD"), &Config::MAIN_GAMELIST_LIST_WAD}, {tr("Show ELF/DOL"), &Config::MAIN_GAMELIST_LIST_ELF_DOL}}; diff --git a/Source/Core/DolphinQt/Resources.cpp b/Source/Core/DolphinQt/Resources.cpp index 84fbcc8df8..015074142d 100644 --- a/Source/Core/DolphinQt/Resources.cpp +++ b/Source/Core/DolphinQt/Resources.cpp @@ -80,7 +80,7 @@ void Resources::Init() m_svg_supported = QImageReader::supportedImageFormats().contains("svg"); for (std::string_view platform : - {"Platform_Gamecube", "Platform_Wii", "Platform_Wad", "Platform_File"}) + {"Platform_Gamecube", "Platform_Triforce", "Platform_Wii", "Platform_Wad", "Platform_File"}) { m_platforms.append(GetResourceIcon(platform)); } diff --git a/Source/Core/DolphinQt/Settings/PathPane.cpp b/Source/Core/DolphinQt/Settings/PathPane.cpp index 8d91e31d50..bcbcbf3248 100644 --- a/Source/Core/DolphinQt/Settings/PathPane.cpp +++ b/Source/Core/DolphinQt/Settings/PathPane.cpp @@ -45,7 +45,7 @@ void PathPane::BrowseDefaultGame() { QString file = QDir::toNativeSeparators(DolphinFileDialog::getOpenFileName( this, tr("Select a Game"), Settings::Instance().GetDefaultGame(), - QStringLiteral("%1 (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wia *.rvz " + QStringLiteral("%1 (*.elf *.dol *.gcm *.bin *.iso *.tgc *.wbfs *.ciso *.gcz *.wia *.rvz " "hif_000000.nfs *.wad *.m3u *.json);;%2 (*)") .arg(tr("All GC/Wii files")) .arg(tr("All Files")))); diff --git a/Source/Core/UICommon/GameFile.cpp b/Source/Core/UICommon/GameFile.cpp index b35349b8b0..66fb5a3a57 100644 --- a/Source/Core/UICommon/GameFile.cpp +++ b/Source/Core/UICommon/GameFile.cpp @@ -131,6 +131,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_triforce_id = volume->GetTriforceID(); m_title_id = volume->GetTitleID().value_or(0); m_maker_id = volume->GetMakerID(); m_revision = volume->GetRevision().value_or(0); @@ -311,6 +312,7 @@ void GameFile::DoState(PointerWrap& p) p.Do(m_internal_name); p.Do(m_game_id); p.Do(m_gametdb_id); + p.Do(m_triforce_id); p.Do(m_title_id); p.Do(m_maker_id); @@ -499,7 +501,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_triforce_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 e43950143b..f015fa9725 100644 --- a/Source/Core/UICommon/GameFile.h +++ b/Source/Core/UICommon/GameFile.h @@ -76,6 +76,7 @@ public: 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 GetTriforceID() const { return m_triforce_id; } u64 GetTitleID() const { return m_title_id; } const std::string& GetMakerID() const { return m_maker_id; } u16 GetRevision() const { return m_revision; } @@ -159,6 +160,7 @@ private: std::string m_internal_name; std::string m_game_id; std::string m_gametdb_id; + std::string m_triforce_id; u64 m_title_id{}; std::string m_maker_id; diff --git a/Source/Core/UICommon/GameFileCache.cpp b/Source/Core/UICommon/GameFileCache.cpp index 90dd0c63fc..f72f47c11e 100644 --- a/Source/Core/UICommon/GameFileCache.cpp +++ b/Source/Core/UICommon/GameFileCache.cpp @@ -26,14 +26,14 @@ namespace UICommon { -static constexpr u32 CACHE_REVISION = 25; // Last changed in PR 12702 +static constexpr u32 CACHE_REVISION = 26; // Last changed in PR 10084 std::vector FindAllGamePaths(const std::vector& directories_to_scan, bool recursive_scan) { static const std::vector search_extensions = { - ".gcm", ".tgc", ".iso", ".ciso", ".gcz", ".wbfs", ".wia", - ".rvz", ".nfs", ".wad", ".dol", ".elf", ".json"}; + ".gcm", ".tgc", ".bin", ".iso", ".ciso", ".gcz", ".wbfs", + ".wia", ".rvz", ".nfs", ".wad", ".dol", ".elf", ".json"}; // TODO: We could process paths iteratively as they are found return Common::DoFileSearch(directories_to_scan, search_extensions, recursive_scan);