System: Remove use of CDImage title metadata

This way memory card filenames are consistent regardless of the
image format.

Also make GetGameMemoryCardPath() and GetMemoryCardForSlot()
behave the same.
This commit is contained in:
Stenzek
2025-09-09 13:17:19 +10:00
parent caa865628d
commit 6e4da72552
10 changed files with 56 additions and 138 deletions

View File

@@ -1182,12 +1182,6 @@ void Achievements::GameChanged(CDImage* image)
bool Achievements::IdentifyGame(CDImage* image)
{
if (s_state.game_path == (image ? std::string_view(image->GetPath()) : std::string_view()))
{
WARNING_LOG("Game path is unchanged.");
return false;
}
std::optional<GameHash> game_hash;
if (image)
{

View File

@@ -358,10 +358,7 @@ bool GameList::GetDiscListEntry(const std::string& path, Entry* entry)
if (cdi->HasSubImages())
{
entry->type = EntryType::Playlist;
std::string image_title(cdi->GetMetadata("title"));
if (!image_title.empty())
entry->title = std::move(image_title);
entry->title = Path::GetFileTitle(FileSystem::GetDisplayNameFromPath(path));
// get the size of all the subimages
const u32 subimage_count = cdi->GetSubImageCount();

View File

@@ -200,7 +200,7 @@ static bool SwitchDiscFromSet(s32 direction, bool show_osd_message);
static void UpdateControllers();
static void ResetControllers();
static void UpdatePerGameMemoryCards();
static void ReloadMemoryCardsFromGameChange();
static std::unique_ptr<MemoryCard> GetMemoryCardForSlot(u32 slot, MemoryCardType type);
static void UpdateMultitaps();
@@ -498,7 +498,10 @@ bool System::ProcessStartup(Error* error)
#ifdef __linux__
// Running DuckStation out of /usr/lib is not supported and makes no sense.
if (std::memcmp(EmuFolders::AppRoot.data(), "/usr/""lib", 8) == 0)
if (std::memcmp(EmuFolders::AppRoot.data(),
"/usr/"
"lib",
8) == 0)
return false;
#endif
@@ -2984,8 +2987,7 @@ bool System::LoadStateFromBuffer(const SaveStateBuffer& buffer, Error* error, bo
}
// ensure the correct card is loaded
if (g_settings.HasAnyPerGameMemoryCards())
UpdatePerGameMemoryCards();
ReloadMemoryCardsFromGameChange();
ClearMemorySaveStates(false, false);
@@ -3812,17 +3814,12 @@ std::unique_ptr<MemoryCard> System::GetMemoryCardForSlot(u32 slot, MemoryCardTyp
else
{
const std::string_view game_title = (s_state.running_game_custom_title || !s_state.running_game_entry) ?
s_state.running_game_title :
std::string_view(s_state.running_game_title) :
s_state.running_game_entry->GetSaveTitle();
std::string card_path;
// Playlist - use title if different.
if (HasMediaSubImages() && s_state.running_game_entry && s_state.running_game_title != game_title)
{
card_path = g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(s_state.running_game_title), slot);
}
// Multi-disc game - use disc set name.
else if (s_state.running_game_entry && s_state.running_game_entry->disc_set)
if (s_state.running_game_entry && s_state.running_game_entry->disc_set)
{
card_path = g_settings.GetGameMemoryCardPath(
Path::SanitizeFileName(s_state.running_game_entry->disc_set->GetSaveTitle()), slot);
@@ -3912,8 +3909,14 @@ void System::UpdateMemoryCardTypes()
}
}
void System::UpdatePerGameMemoryCards()
void System::ReloadMemoryCardsFromGameChange()
{
if (!g_settings.HasAnyPerGameMemoryCards())
return;
Host::AddIconOSDMessage("ReloadMemoryCardsFromGameChange", ICON_PF_MEMORY_CARD,
TRANSLATE_STR("System", "Game changed, reloading memory cards."), Host::OSD_INFO_DURATION);
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
{
const MemoryCardType type = g_settings.memory_card_types[i];
@@ -4097,13 +4100,7 @@ bool System::InsertMedia(const char* path)
s_state.running_game_title, s_state.running_game_serial),
Host::OSD_INFO_DURATION);
if (g_settings.HasAnyPerGameMemoryCards())
{
Host::AddIconOSDMessage("ReloadMemoryCardsFromGameChange", ICON_PF_MEMORY_CARD,
TRANSLATE_STR("System", "Game changed, reloading memory cards."), Host::OSD_INFO_DURATION);
UpdatePerGameMemoryCards();
}
ReloadMemoryCardsFromGameChange();
return true;
}
@@ -4115,9 +4112,6 @@ void System::RemoveMedia()
void System::UpdateRunningGame(const std::string& path, CDImage* image, bool booting)
{
if (!booting && s_state.running_game_path == path)
return;
const std::string prev_serial = std::move(s_state.running_game_serial);
s_state.running_game_path.clear();
@@ -4195,16 +4189,6 @@ void System::UpdateRunningGame(const std::string& path, CDImage* image, bool boo
if (s_state.running_game_title.empty() && !CDImage::IsDeviceName(path.c_str()))
s_state.running_game_title = Path::GetFileTitle(FileSystem::GetDisplayNameFromPath(path));
}
if (image->HasSubImages())
{
std::string image_title = image->GetMetadata("title");
if (!image_title.empty())
{
s_state.running_game_title = std::move(image_title);
s_state.running_game_custom_title = false;
}
}
}
else
{
@@ -4296,29 +4280,13 @@ u32 System::GetMediaSubImageIndex()
return cdi ? cdi->GetCurrentSubImage() : 0;
}
u32 System::GetMediaSubImageIndexForTitle(std::string_view title)
{
const CDImage* cdi = CDROM::GetMedia();
if (!cdi)
return 0;
const u32 count = cdi->GetSubImageCount();
for (u32 i = 0; i < count; i++)
{
if (title == cdi->GetSubImageMetadata(i, "title"))
return i;
}
return std::numeric_limits<u32>::max();
}
std::string System::GetMediaSubImageTitle(u32 index)
{
const CDImage* cdi = CDROM::GetMedia();
if (!cdi)
return {};
return cdi->GetSubImageMetadata(index, "title");
return cdi->GetSubImageTitle(index);
}
bool System::SwitchMediaSubImage(u32 index)
@@ -4338,9 +4306,10 @@ bool System::SwitchMediaSubImage(u32 index)
{
const DiscRegion region =
GameList::GetCustomRegionForPath(image->GetPath()).value_or(GetRegionForImage(image.get()));
subimage_title = image->GetSubImageMetadata(index, "title");
title = image->GetMetadata("title");
subimage_title = image->GetSubImageTitle(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);
}
if (!okay)
@@ -5781,22 +5750,24 @@ std::string System::GetGameMemoryCardPath(std::string_view serial, std::string_v
case MemoryCardType::PerGameTitle:
{
const std::string custom_title = GameList::GetCustomTitleForPath(path);
const GameDatabase::Entry* entry = GameDatabase::GetEntryForSerial(serial);
if (entry)
{
ret = g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(entry->GetSaveTitle()), slot);
const std::string_view game_title =
(!custom_title.empty() || !entry) ? std::string_view(custom_title) : entry->GetSaveTitle();
// Use disc set name if there isn't a per-disc card present.
// Multi-disc game - use disc set name.
if (entry && entry->disc_set)
ret = g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(entry->disc_set->GetSaveTitle()), slot);
// But prefer a disc-specific card if one already exists.
std::string disc_card_path = g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(game_title), slot);
if (disc_card_path != ret)
{
const bool global_use_playlist_title = Host::GetBaseBoolSettingValue(section, "UsePlaylistTitle", true);
const bool use_playlist_title =
ini ? ini->GetBoolValue(section, "UsePlaylistTitle", global_use_playlist_title) : global_use_playlist_title;
if (entry->disc_set && use_playlist_title && !FileSystem::FileExists(ret.c_str()))
ret = g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(entry->disc_set->GetSaveTitle()), slot);
}
else
{
ret = g_settings.GetGameMemoryCardPath(
Path::SanitizeFileName(Path::GetFileTitle(FileSystem::GetDisplayNameFromPath(path))), slot);
if (ret.empty() || !use_playlist_title || FileSystem::FileExists(disc_card_path.c_str()))
ret = std::move(disc_card_path);
}
}
break;

View File

@@ -323,9 +323,6 @@ u32 GetMediaSubImageCount();
/// Returns the current image from the media/disc playlist.
u32 GetMediaSubImageIndex();
/// Returns the index of the specified path in the playlist, or UINT32_MAX if it does not exist.
u32 GetMediaSubImageIndexForTitle(std::string_view title);
/// Returns the path to the specified playlist index.
std::string GetMediaSubImageTitle(u32 index);

View File

@@ -1287,6 +1287,7 @@ void MainWindow::onChangeDiscMenuAboutToShow()
if (!s_system_valid)
return;
// NOTE: This is terrible and a race condition. But nobody should be using m3u files anyway.
if (System::HasMediaSubImages())
{
const u32 count = System::GetMediaSubImageCount();

View File

@@ -304,18 +304,6 @@ bool CDImage::HasSubchannelData() const
return false;
}
std::string CDImage::GetMetadata(std::string_view type) const
{
std::string result;
if (type == "title")
{
const std::string display_name(FileSystem::GetDisplayNameFromPath(m_filename));
result = Path::StripExtension(display_name);
}
return result;
}
bool CDImage::HasSubImages() const
{
return false;
@@ -336,7 +324,7 @@ bool CDImage::SwitchSubImage(u32 index, Error* error)
return false;
}
std::string CDImage::GetSubImageMetadata(u32 index, std::string_view type) const
std::string CDImage::GetSubImageTitle(u32 index) const
{
return {};
}

View File

@@ -290,9 +290,6 @@ public:
// Reads a single sector from an index.
virtual bool ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_in_index) = 0;
// Retrieve image metadata.
virtual std::string GetMetadata(std::string_view type) const;
// Returns true if this image type has sub-images (e.g. m3u).
virtual bool HasSubImages() const;
@@ -306,7 +303,7 @@ public:
virtual bool SwitchSubImage(u32 index, Error* error);
// Retrieve sub-image metadata.
virtual std::string GetSubImageMetadata(u32 index, std::string_view type) const;
virtual std::string GetSubImageTitle(u32 index) const;
// Returns true if the source supports precaching, which may be more optimal than an in-memory copy.
virtual PrecacheResult Precache(ProgressCallback* progress = ProgressCallback::NullProgressCallback);

View File

@@ -33,7 +33,7 @@ public:
bool HasSubImages() const override;
u32 GetSubImageCount() const override;
u32 GetCurrentSubImage() const override;
std::string GetSubImageMetadata(u32 index, std::string_view type) const override;
std::string GetSubImageTitle(u32 index) const override;
bool SwitchSubImage(u32 index, Error* error) override;
protected:
@@ -159,17 +159,13 @@ bool CDImageM3u::SwitchSubImage(u32 index, Error* error)
return true;
}
std::string CDImageM3u::GetSubImageMetadata(u32 index, std::string_view type) const
std::string CDImageM3u::GetSubImageTitle(u32 index) const
{
if (index >= m_entries.size())
return {};
std::string ret;
if (index < m_entries.size())
ret = m_entries[index].title;
if (type == "title")
return m_entries[index].title;
else if (type == "file_title")
return std::string(Path::GetFileTitle(m_entries[index].filename));
return CDImage::GetSubImageMetadata(index, type);
return ret;
}
bool CDImageM3u::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_in_index)

View File

@@ -139,8 +139,7 @@ public:
u32 GetSubImageCount() const override;
u32 GetCurrentSubImage() const override;
bool SwitchSubImage(u32 index, Error* error) override;
std::string GetMetadata(std::string_view type) const override;
std::string GetSubImageMetadata(u32 index, std::string_view type) const override;
std::string GetSubImageTitle(u32 index) const override;
protected:
bool ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_in_index) override;
@@ -336,7 +335,8 @@ bool CDImagePBP::LoadSFOTable(Error* error)
}
else
{
Error::SetStringFmt(error, "Unhandled SFO data type 0x{:04X} found in SFO table for entry {}", m_sfo_index_table[i].data_type, i);
Error::SetStringFmt(error, "Unhandled SFO data type 0x{:04X} found in SFO table for entry {}",
m_sfo_index_table[i].data_type, i);
return false;
}
}
@@ -871,18 +871,6 @@ bool CDImagePBP::HasSubImages() const
return m_disc_offsets.size() > 1;
}
std::string CDImagePBP::GetMetadata(std::string_view type) const
{
if (type == "title")
{
const std::string* title = LookupStringSFOTableEntry("TITLE", m_sfo_table);
if (title && !title->empty())
return *title;
}
return CDImage::GetMetadata(type);
}
u32 CDImagePBP::GetSubImageCount() const
{
return static_cast<u32>(m_disc_offsets.size());
@@ -909,16 +897,15 @@ bool CDImagePBP::SwitchSubImage(u32 index, Error* error)
return true;
}
std::string CDImagePBP::GetSubImageMetadata(u32 index, std::string_view type) const
std::string CDImagePBP::GetSubImageTitle(u32 index) const
{
if (type == "title")
{
const std::string* title = LookupStringSFOTableEntry("TITLE", m_sfo_table);
if (title && !title->empty())
return fmt::format("{} (Disc {})", *title, index + 1);
}
std::string ret;
return CDImage::GetSubImageMetadata(index, type);
const std::string* title = LookupStringSFOTableEntry("TITLE", m_sfo_table);
if (title && !title->empty())
ret = fmt::format("{} (Disc {})", *title, index + 1);
return ret;
}
s64 CDImagePBP::GetSizeOnDisk() const

View File

@@ -35,8 +35,7 @@ public:
bool HasSubchannelData() const override;
s64 GetSizeOnDisk() const override;
std::string GetMetadata(std::string_view type) const override;
std::string GetSubImageMetadata(u32 index, std::string_view type) const override;
std::string GetSubImageTitle(u32 index) const override;
PrecacheResult Precache(ProgressCallback* progress = ProgressCallback::NullProgressCallback) override;
@@ -420,19 +419,10 @@ bool CDImagePPF::HasSubchannelData() const
return m_parent_image->HasSubchannelData();
}
std::string CDImagePPF::GetMetadata(std::string_view type) const
{
return m_parent_image->GetMetadata(type);
}
std::string CDImagePPF::GetSubImageMetadata(u32 index, std::string_view type) const
std::string CDImagePPF::GetSubImageTitle(u32 index) const
{
// We only support a single sub-image for patched games.
std::string ret;
if (index == 0)
ret = m_parent_image->GetSubImageMetadata(index, type);
return ret;
return (index == 0) ? m_parent_image->GetSubImageTitle(index) : std::string();
}
CDImage::PrecacheResult CDImagePPF::Precache(ProgressCallback* progress /*= ProgressCallback::NullProgressCallback*/)