diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index a75267312..2c2649a65 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -934,12 +934,15 @@ bool CDROM::CanReadMedia() } bool CDROM::InsertMedia(std::unique_ptr& media, DiscRegion region, std::string_view serial, - std::string_view title, Error* error) + std::string_view title, std::string_view save_title, Error* error) { // Load SBI/LSD first. std::unique_ptr subq; - if (!media->HasSubchannelData() && !CDROMSubQReplacement::LoadForImage(&subq, media.get(), serial, title, error)) + if (!media->HasSubchannelData() && + !CDROMSubQReplacement::LoadForImage(&subq, media.get(), serial, title, save_title, error)) + { return false; + } if (CanReadMedia()) RemoveMedia(true); diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 944d47c5a..02f27f5e5 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -31,7 +31,7 @@ bool IsMediaAudioCD(); bool DoesMediaRegionMatchConsole(); bool InsertMedia(std::unique_ptr& media, DiscRegion region, std::string_view serial, std::string_view title, - Error* error); + std::string_view save_title, Error* error); std::unique_ptr RemoveMedia(bool for_disc_swap); bool PrecacheMedia(); bool HasNonStandardOrReplacementSubQ(); diff --git a/src/core/cdrom_subq_replacement.cpp b/src/core/cdrom_subq_replacement.cpp index 966c3e4cf..5391ae4a1 100644 --- a/src/core/cdrom_subq_replacement.cpp +++ b/src/core/cdrom_subq_replacement.cpp @@ -118,7 +118,8 @@ std::unique_ptr CDROMSubQReplacement::LoadLSD(const std::s } bool CDROMSubQReplacement::LoadForImage(std::unique_ptr* ret, CDImage* image, - std::string_view serial, std::string_view title, Error* error) + std::string_view serial, std::string_view title, std::string_view save_title, + Error* error) { struct FileLoader { @@ -131,25 +132,49 @@ bool CDROMSubQReplacement::LoadForImage(std::unique_ptr* r }; const std::string& image_path = image->GetPath(); + std::string display_name; std::string path; + bool result = true; + + const auto try_path = [&path, &ret, &error, &result](const FileLoader& loader) -> bool { + if (const FileSystem::ManagedCFilePtr fp = FileSystem::OpenManagedCFile(path.c_str(), "rb")) + { + *ret = loader.func(path, fp.get(), error); + result = static_cast(*ret); + if (!result) + Error::AddPrefixFmt(error, "Failed to load subchannel data from {}: ", Path::GetFileName(path)); + return true; + } + + return false; + }; + + const auto search_in_subchannels = [&path, &image_path, &display_name, &ret, &error, + &try_path](std::string_view base_name) -> bool { + if (base_name.empty()) + return false; + + for (const FileLoader& loader : loaders) + { + path = Path::Combine(EmuFolders::Subchannels, TinyString::from_format("{}.{}", base_name, loader.extension)); + if (try_path(loader)) + return true; + } + + return false; + }; // Try sbi/lsd in the directory first. if (!CDImage::IsDeviceName(image_path.c_str())) { - std::string display_name = FileSystem::GetDisplayNameFromPath(image_path); + display_name = FileSystem::GetDisplayNameFromPath(image_path); for (const FileLoader& loader : loaders) { path = Path::BuildRelativePath( image_path, SmallString::from_format("{}.{}", Path::GetFileTitle(display_name), loader.extension)); - if (const FileSystem::ManagedCFilePtr fp = FileSystem::OpenManagedCFile(path.c_str(), "rb")) - { - *ret = loader.func(path, fp.get(), error); - if (!static_cast(*ret)) - Error::AddPrefixFmt(error, "Failed to load subchannel data from {}: ", Path::GetFileName(path)); - - return static_cast(*ret); - } + if (try_path(loader)) + return result; } // For subimages, we need to check the suffix too. @@ -160,49 +185,25 @@ bool CDROMSubQReplacement::LoadForImage(std::unique_ptr* r path = Path::BuildRelativePath(image_path, SmallString::from_format("{}_{}.{}", Path::GetFileTitle(display_name), image->GetCurrentSubImage() + 1, loader.extension)); - if (const FileSystem::ManagedCFilePtr fp = FileSystem::OpenManagedCFile(path.c_str(), "rb")) - { - *ret = loader.func(path, fp.get(), error); - if (!static_cast(*ret)) - Error::AddPrefixFmt(error, "Failed to load subchannel data from {}: ", Path::GetFileName(path)); - - return static_cast(*ret); - } + if (try_path(loader)) + return result; } } + + // Try the file title first inside subchannels (most specific). + if (!display_name.empty() && search_in_subchannels(Path::GetFileTitle(display_name))) + return result; } // If this fails, try the subchannel directory with serial/title. - if (!serial.empty()) - { - for (const FileLoader& loader : loaders) - { - path = Path::Combine(EmuFolders::Subchannels, TinyString::from_format("{}.{}", serial, loader.extension)); - if (const FileSystem::ManagedCFilePtr fp = FileSystem::OpenManagedCFile(path.c_str(), "rb")) - { - *ret = loader.func(path, fp.get(), error); - if (!static_cast(*ret)) - Error::AddPrefixFmt(error, "Failed to load subchannel data from {}: ", Path::GetFileName(path)); + if (search_in_subchannels(serial) || search_in_subchannels(title)) + return result; - return static_cast(*ret); - } - } - } - - if (!title.empty()) + // Try save title next if it's different from title. + if (!save_title.empty() && save_title != title) { - for (const FileLoader& loader : loaders) - { - path = Path::Combine(EmuFolders::Subchannels, TinyString::from_format("{}.{}", title, loader.extension)); - if (const FileSystem::ManagedCFilePtr fp = FileSystem::OpenManagedCFile(path.c_str(), "rb")) - { - *ret = loader.func(path, fp.get(), error); - if (!static_cast(*ret)) - Error::AddPrefixFmt(error, "Failed to load subchannel data from {}: ", Path::GetFileName(path)); - - return static_cast(*ret); - } - } + if (search_in_subchannels(save_title)) + return result; } // Nothing. diff --git a/src/core/cdrom_subq_replacement.h b/src/core/cdrom_subq_replacement.h index 96f36aeee..f4d341d6d 100644 --- a/src/core/cdrom_subq_replacement.h +++ b/src/core/cdrom_subq_replacement.h @@ -16,7 +16,7 @@ public: // NOTE: Can return true if no sbi is available, false means load/parse error. static bool LoadForImage(std::unique_ptr* ret, CDImage* image, std::string_view serial, - std::string_view title, Error* error); + std::string_view title, std::string_view save_title, Error* error); size_t GetReplacementSectorCount() const { return m_replacement_subq.size(); } diff --git a/src/core/system.cpp b/src/core/system.cpp index c6858bfa8..a5aa2a9df 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -199,6 +199,7 @@ static void UpdateInputSettingsLayer(std::string input_profile_name, std::unique static void UpdateRunningGame(const std::string& path, CDImage* image, bool booting); static bool CheckForRequiredSubQ(Error* error); static bool SwitchDiscFromSet(s32 direction, bool show_osd_message); +static std::string_view GetCurrentGameSaveTitle(); static void UpdateControllers(); static void ResetControllers(); @@ -312,7 +313,7 @@ struct ALIGN_TO_CACHE_LINE StateVars std::string running_game_title; std::string exe_override; const GameDatabase::Entry* running_game_entry = nullptr; - GameHash running_game_hash; + GameHash running_game_hash = 0; bool running_game_custom_title = false; std::atomic_bool startup_cancelled{false}; @@ -1948,8 +1949,11 @@ bool System::Initialize(std::unique_ptr disc, DiscRegion disc_region, b return false; // CDROM before GPU, that way we don't modeswitch. - if (disc && !CDROM::InsertMedia(disc, disc_region, s_state.running_game_serial, s_state.running_game_title, error)) + if (disc && !CDROM::InsertMedia(disc, disc_region, s_state.running_game_serial, s_state.running_game_title, + GetCurrentGameSaveTitle(), error)) + { return false; + } // TODO: Drop class g_gpu.Initialize(); @@ -2972,7 +2976,7 @@ bool System::LoadStateFromBuffer(const SaveStateBuffer& buffer, Error* error, bo !new_disc->SwitchSubImage(media_subimage_index, error ? error : &local_error)) || (UpdateRunningGame(buffer.media_path, new_disc.get(), false), !CDROM::InsertMedia(new_disc, new_disc_region, s_state.running_game_serial, s_state.running_game_title, - error ? error : &local_error))) + GetCurrentGameSaveTitle(), error ? error : &local_error))) { if (CDROM::HasMedia()) { @@ -4097,7 +4101,8 @@ bool System::InsertMedia(const char* path) const DiscRegion region = image ? GameList::GetCustomRegionForPath(path).value_or(GetRegionForImage(image.get())) : DiscRegion::NonPS1; if (!image || (UpdateRunningGame(path, image.get(), false), - !CDROM::InsertMedia(image, region, s_state.running_game_serial, s_state.running_game_title, &error))) + !CDROM::InsertMedia(image, region, s_state.running_game_serial, s_state.running_game_title, + GetCurrentGameSaveTitle(), &error))) { Host::AddIconOSDWarning( "DiscInserted", ICON_FA_COMPACT_DISC, @@ -4326,7 +4331,8 @@ bool System::SwitchMediaSubImage(u32 index) title = FileSystem::GetDisplayNameFromPath(image->GetPath()); UpdateRunningGame(image->GetPath(), image.get(), false); ReloadMemoryCardsFromGameChange(); - okay = CDROM::InsertMedia(image, region, s_state.running_game_serial, s_state.running_game_title, &error); + okay = CDROM::InsertMedia(image, region, s_state.running_game_serial, s_state.running_game_title, + GetCurrentGameSaveTitle(), &error); } if (!okay) { @@ -4340,7 +4346,8 @@ bool System::SwitchMediaSubImage(u32 index) const DiscRegion region = GameList::GetCustomRegionForPath(image->GetPath()).value_or(GetRegionForImage(image.get())); UpdateRunningGame(image->GetPath(), image.get(), false); - CDROM::InsertMedia(image, region, s_state.running_game_serial, s_state.running_game_title, nullptr); + CDROM::InsertMedia(image, region, s_state.running_game_serial, s_state.running_game_title, + GetCurrentGameSaveTitle(), nullptr); return false; } @@ -4419,6 +4426,17 @@ bool System::SwitchDiscFromSet(s32 direction, bool display_osd_message) return InsertMedia(entry->path.c_str()); } +std::string_view System::GetCurrentGameSaveTitle() +{ + std::string_view ret; + if (s_state.running_game_custom_title || !s_state.running_game_entry) + ret = s_state.running_game_title; + else + ret = s_state.running_game_entry->GetSaveTitle(); + + return ret; +} + bool System::SwitchToPreviousDisc(bool display_osd_message) { return SwitchDiscFromSet(-1, display_osd_message);