diff --git a/pcsx2-qt/GameList/GameListModel.cpp b/pcsx2-qt/GameList/GameListModel.cpp index 14ccf5e7f1..075199a0f6 100644 --- a/pcsx2-qt/GameList/GameListModel.cpp +++ b/pcsx2-qt/GameList/GameListModel.cpp @@ -341,7 +341,7 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const case Column_Title: case Column_Cover: - return QString::fromStdString(ge->title); + return QString::fromStdString(ge->GetTitleSort()); case Column_FileTitle: return QtUtils::StringViewToQString(Path::GetFileTitle(ge->path)); @@ -438,7 +438,7 @@ bool GameListModel::titlesLessThan(int left_row, int right_row) const const GameList::Entry* left = GameList::GetEntryByIndex(left_row); const GameList::Entry* right = GameList::GetEntryByIndex(right_row); - return (StringUtil::Strcasecmp(left->title.c_str(), right->title.c_str()) < 0); + return (StringUtil::Strcasecmp(left->GetTitleSort().c_str(), right->GetTitleSort().c_str()) < 0); } bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& right_index, int column) const diff --git a/pcsx2/Docs/gamedb-schema.json b/pcsx2/Docs/gamedb-schema.json index 198ebbb274..826d1a40b6 100644 --- a/pcsx2/Docs/gamedb-schema.json +++ b/pcsx2/Docs/gamedb-schema.json @@ -12,6 +12,14 @@ "type": "string", "description": "The name of the game, an arbitrary string" }, + "name-sort": { + "type": "string", + "description": "The name of the game for use in sorting, an arbitrary string" + }, + "name-en": { + "type": "string", + "description": "The name of the game in ASCII, an arbitrary string" + }, "region": { "type": "string", "description": "The region code for the game, for example NTSC-U", diff --git a/pcsx2/GameDatabase.cpp b/pcsx2/GameDatabase.cpp index c7f02efccc..4603c28c84 100644 --- a/pcsx2/GameDatabase.cpp +++ b/pcsx2/GameDatabase.cpp @@ -103,6 +103,14 @@ void GameDatabase::parseAndInsert(const std::string_view& serial, const c4::yml: { node["name"] >> gameEntry.name; } + if (node.has_child("name-sort")) + { + node["name-sort"] >> gameEntry.name_sort; + } + if (node.has_child("name-en")) + { + node["name-en"] >> gameEntry.name_en; + } if (node.has_child("region")) { node["region"] >> gameEntry.region; diff --git a/pcsx2/GameDatabase.h b/pcsx2/GameDatabase.h index 0dcd666ce1..f111c27853 100644 --- a/pcsx2/GameDatabase.h +++ b/pcsx2/GameDatabase.h @@ -104,6 +104,8 @@ namespace GameDatabaseSchema struct GameEntry { std::string name; + std::string name_sort; + std::string name_en; std::string region; Compatibility compat = Compatibility::Unknown; RoundMode eeRoundMode = RoundMode::Undefined; diff --git a/pcsx2/GameList.cpp b/pcsx2/GameList.cpp index eb9e46ac26..2ae4d6fd8c 100644 --- a/pcsx2/GameList.cpp +++ b/pcsx2/GameList.cpp @@ -50,7 +50,7 @@ namespace GameList enum : u32 { GAME_LIST_CACHE_SIGNATURE = 0x45434C47, - GAME_LIST_CACHE_VERSION = 33, + GAME_LIST_CACHE_VERSION = 34, PLAYED_TIME_SERIAL_LENGTH = 32, @@ -340,6 +340,8 @@ bool GameList::GetIsoListEntry(const std::string& path, GameList::Entry* entry) if (const GameDatabaseSchema::GameEntry* db_entry = GameDatabase::findGame(entry->serial)) { entry->title = std::move(db_entry->name); + entry->title_sort = std::move(db_entry->name_sort); + entry->title_en = std::move(db_entry->name_en); entry->compatibility_rating = db_entry->compat; entry->region = ParseDatabaseRegion(db_entry->region); } @@ -443,10 +445,11 @@ bool GameList::LoadEntriesFromCache(std::FILE* stream) u8 compatibility_rating; u64 last_modified_time; - if (!ReadString(stream, &path) || !ReadString(stream, &ge.serial) || !ReadString(stream, &ge.title) || !ReadU8(stream, &type) || - !ReadU8(stream, ®ion) || !ReadU64(stream, &ge.total_size) || !ReadU64(stream, &last_modified_time) || - !ReadU32(stream, &ge.crc) || !ReadU8(stream, &compatibility_rating) || region >= static_cast(Region::Count) || - type >= static_cast(EntryType::Count) || compatibility_rating > static_cast(CompatibilityRating::Perfect)) + if (!ReadString(stream, &path) || !ReadString(stream, &ge.serial) || !ReadString(stream, &ge.title) || !ReadString(stream, &ge.title_sort) || + !ReadString(stream, &ge.title_en) || !ReadU8(stream, &type) || !ReadU8(stream, ®ion) || !ReadU64(stream, &ge.total_size) || + !ReadU64(stream, &last_modified_time) || !ReadU32(stream, &ge.crc) || !ReadU8(stream, &compatibility_rating) || + region >= static_cast(Region::Count) || type >= static_cast(EntryType::Count) || + compatibility_rating > static_cast(CompatibilityRating::Perfect)) { Console.Warning("Game list cache entry is corrupted"); return false; @@ -538,6 +541,8 @@ bool GameList::WriteEntryToCache(const Entry* entry) result &= WriteString(s_cache_write_stream, entry->path); result &= WriteString(s_cache_write_stream, entry->serial); result &= WriteString(s_cache_write_stream, entry->title); + result &= WriteString(s_cache_write_stream, entry->title_sort); + result &= WriteString(s_cache_write_stream, entry->title_en); result &= WriteU8(s_cache_write_stream, static_cast(entry->type)); result &= WriteU8(s_cache_write_stream, static_cast(entry->region)); result &= WriteU64(s_cache_write_stream, entry->total_size); diff --git a/pcsx2/GameList.h b/pcsx2/GameList.h index d4fe181f9a..8003a06afd 100644 --- a/pcsx2/GameList.h +++ b/pcsx2/GameList.h @@ -90,11 +90,16 @@ namespace GameList std::string path; std::string serial; std::string title; + std::string title_sort; + std::string title_en; u64 total_size = 0; std::time_t last_modified_time = 0; std::time_t last_played_time = 0; std::time_t total_played_time = 0; + const std::string& GetTitleEN() const { return title_en.empty() ? title : title_en; } + const std::string& GetTitleSort() const { return title_sort.empty() ? title : title_sort; } + u32 crc = 0; CompatibilityRating compatibility_rating = CompatibilityRating::Unknown;