mirror of
https://github.com/stenzek/duckstation.git
synced 2026-02-11 08:54:33 +00:00
CDROM: Improve subchannel file detection
Look in the subchannels directory for serial, file title, game title and save title.
This commit is contained in:
@@ -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())
|
||||
if (search_in_subchannels(serial) || search_in_subchannels(title))
|
||||
return result;
|
||||
|
||||
// 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("{}.{}", 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));
|
||||
|
||||
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"))
|
||||
{
|
||||
*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);
|
||||
|
||||
Reference in New Issue
Block a user