CDROM: Improve subchannel file detection

Look in the subchannels directory for serial, file title, game title and
save title.
pull/3569/head
Stenzek 2 months ago
parent 8a431b7d22
commit bb50fc9056
No known key found for this signature in database

@ -934,12 +934,15 @@ bool CDROM::CanReadMedia()
}
bool CDROM::InsertMedia(std::unique_ptr<CDImage>& 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<CDROMSubQReplacement> 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);

@ -31,7 +31,7 @@ bool IsMediaAudioCD();
bool DoesMediaRegionMatchConsole();
bool InsertMedia(std::unique_ptr<CDImage>& media, DiscRegion region, std::string_view serial, std::string_view title,
Error* error);
std::string_view save_title, Error* error);
std::unique_ptr<CDImage> RemoveMedia(bool for_disc_swap);
bool PrecacheMedia();
bool HasNonStandardOrReplacementSubQ();

@ -118,7 +118,8 @@ std::unique_ptr<CDROMSubQReplacement> CDROMSubQReplacement::LoadLSD(const std::s
}
bool CDROMSubQReplacement::LoadForImage(std::unique_ptr<CDROMSubQReplacement>* 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<CDROMSubQReplacement>* 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<bool>(*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<bool>(*ret))
Error::AddPrefixFmt(error, "Failed to load subchannel data from {}: ", Path::GetFileName(path));
return static_cast<bool>(*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<CDROMSubQReplacement>* 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<bool>(*ret))
Error::AddPrefixFmt(error, "Failed to load subchannel data from {}: ", Path::GetFileName(path));
return static_cast<bool>(*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<bool>(*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<bool>(*ret);
}
}
}
if (!title.empty())
{
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"))
// Try save title next if it's different from title.
if (!save_title.empty() && save_title != title)
{
*ret = loader.func(path, fp.get(), error);
if (!static_cast<bool>(*ret))
Error::AddPrefixFmt(error, "Failed to load subchannel data from {}: ", Path::GetFileName(path));
return static_cast<bool>(*ret);
}
}
if (search_in_subchannels(save_title))
return result;
}
// Nothing.

@ -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<CDROMSubQReplacement>* 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(); }

@ -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<CDImage> 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);

Loading…
Cancel
Save