From 4c631e77f52b498eac83b825cec76e0223239280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 1 Jun 2025 11:34:59 +0200 Subject: [PATCH] RetroAchievements: Show region when showing the info popu. Refactor region detection a little. --- Core/ELF/ParamSFO.cpp | 53 +++++++++++++++++++++++++++++++++++--- Core/ELF/ParamSFO.h | 39 +++++++++++++++++++--------- Core/RetroAchievements.cpp | 14 ++++++++-- UI/GameInfoCache.cpp | 33 +++--------------------- UI/GameInfoCache.h | 14 +--------- UI/GameScreen.cpp | 16 +++--------- UI/MainScreen.cpp | 13 +++++----- assets/lang/sv_SE.ini | 2 +- 8 files changed, 103 insertions(+), 81 deletions(-) diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index fe732d5cfe..33eacb6ba6 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -61,25 +61,25 @@ void ParamSFOData::SetValue(const std::string &key, const u8 *value, unsigned in values[key].max_size = max_size; } -int ParamSFOData::GetValueInt(const std::string &key) const { +int ParamSFOData::GetValueInt(std::string_view key) const { std::map::const_iterator it = values.find(key); if (it == values.end() || it->second.type != VT_INT) return 0; return it->second.i_value; } -std::string ParamSFOData::GetValueString(const std::string &key) const { +std::string ParamSFOData::GetValueString(std::string_view key) const { std::map::const_iterator it = values.find(key); if (it == values.end() || (it->second.type != VT_UTF8)) return ""; return it->second.s_value; } -bool ParamSFOData::HasKey(const std::string &key) const { +bool ParamSFOData::HasKey(std::string_view key) const { return values.find(key) != values.end(); } -const u8 *ParamSFOData::GetValueData(const std::string &key, unsigned int *size) const { +const u8 *ParamSFOData::GetValueData(std::string_view key, unsigned int *size) const { std::map::const_iterator it = values.find(key); if (it == values.end() || (it->second.type != VT_UTF8_SPE)) { return 0; @@ -353,3 +353,48 @@ std::string ParamSFOData::GenerateFakeID(const Path &filename) const { std::string fakeID = file + StringFromFormat("%05d", sumOfAllLetters); return fakeID; } + +GameRegion DetectGameRegionFromID(std::string_view id_version) { + if (id_version.size() >= 4) { + std::string_view regStr = id_version.substr(0, 4); + + // Guesswork + switch (regStr[2]) { + case 'E': return GameRegion::EUROPE; break; + case 'U': return GameRegion::USA; break; + case 'J': return GameRegion::JAPAN; break; + case 'H': return GameRegion::HONGKONG; break; + case 'A': return GameRegion::ASIA; break; + case 'K': return GameRegion::KOREA; break; + default: return GameRegion::OTHER; + } + /* + if (regStr == "NPEZ" || regStr == "NPEG" || regStr == "ULES" || regStr == "UCES" || + regStr == "NPEX") { + region = GameRegion::EUROPE; + } else if (regStr == "NPUG" || regStr == "NPUZ" || regStr == "ULUS" || regStr == "UCUS") { + region = GameRegion::USA; + } else if (regStr == "NPJH" || regStr == "NPJG" || regStr == "ULJM"|| regStr == "ULJS") { + region = GameRegion::JAPAN; + } else if (regStr == "NPHG") { + region = GameRegion::HONGKONG; + } else if (regStr == "UCAS") { + region = GameRegion::CHINA; + }*/ + } else { + return GameRegion::OTHER; + } +} + +std::string_view GameRegionToString(GameRegion region) { + switch (region) { + case GameRegion::JAPAN: return "Japan"; + case GameRegion::USA: return "USA"; + case GameRegion::EUROPE: return "Europe"; + case GameRegion::HONGKONG: return "Hong Kong"; + case GameRegion::ASIA: return "Asia"; + case GameRegion::KOREA: return "Korea"; + case GameRegion::HOMEBREW: return "Homebrew"; + default: return "Other"; + } +} diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h index c60bf3a090..1d7636635d 100644 --- a/Core/ELF/ParamSFO.h +++ b/Core/ELF/ParamSFO.h @@ -17,7 +17,7 @@ #pragma once -#include +#include #include #include @@ -26,17 +26,16 @@ class Path; -class ParamSFOData -{ +class ParamSFOData { public: void SetValue(const std::string &key, unsigned int value, int max_size); void SetValue(const std::string &key, const std::string &value, int max_size); void SetValue(const std::string &key, const u8 *value, unsigned int size, int max_size); - int GetValueInt(const std::string &key) const; - std::string GetValueString(const std::string &key) const; - bool HasKey(const std::string &key) const; - const u8 *GetValueData(const std::string &key, unsigned int *size) const; + int GetValueInt(std::string_view key) const; + std::string GetValueString(std::string_view key) const; + bool HasKey(std::string_view key) const; + const u8 *GetValueData(std::string_view key, unsigned int *size) const; std::vector GetKeys() const; std::string GenerateFakeID(const Path &filename) const; @@ -63,15 +62,13 @@ public: void Clear(); private: - enum ValueType - { + enum ValueType { VT_INT, VT_UTF8, VT_UTF8_SPE // raw data in u8 }; - class ValueData - { + class ValueData { public: ValueType type = VT_INT; int max_size = 0; @@ -88,6 +85,24 @@ private: } }; - std::map values; + std::map> values; }; +// Utilities for parsing the information. + +// Guessed from GameID, not necessarily accurate +// Can't change the order of these. +enum class GameRegion { + JAPAN, + USA, + EUROPE, + HONGKONG, + ASIA, + KOREA, + COUNT, + HOMEBREW = COUNT, // Like other but we actually know it's homebrew. + OTHER, +}; + +GameRegion DetectGameRegionFromID(std::string_view id_version); +std::string_view GameRegionToString(GameRegion region); // These strings can be looked up I18NCat::GAME. diff --git a/Core/RetroAchievements.cpp b/Core/RetroAchievements.cpp index 3f5eaf7c71..d7a1083a25 100644 --- a/Core/RetroAchievements.cpp +++ b/Core/RetroAchievements.cpp @@ -41,8 +41,8 @@ #include "Common/Serialize/Serializer.h" #include "Common/Serialize/SerializeFuncs.h" #include "Common/StringUtils.h" -#include "Common/Crypto/md5.h" #include "Common/UI/IconCache.h" +#include "Core/ELF/ParamSFO.h" #include "Core/MemMap.h" #include "Core/Config.h" @@ -945,7 +945,17 @@ void identify_and_load_callback(int result, const char *error_message, rc_client if (RC_OK == rc_client_game_get_image_url(gameInfo, temp, sizeof(temp))) { Achievements::DownloadImageIfMissing(cacheId, std::string(temp)); } - g_OSD.Show(OSDType::MESSAGE_INFO, std::string(gameInfo->title), GetGameAchievementSummary(), cacheId, 5.0f); + + GameRegion region = DetectGameRegionFromID(g_paramSFO.GetDiscID()); + auto ga = GetI18NCategory(I18NCat::GAME); + std::string_view regionStr = ga->T(GameRegionToString(region)); + std::string title(gameInfo->title); + if (region != GameRegion::OTHER) { + title += " ("; + title += regionStr; + title += ")"; + } + g_OSD.Show(OSDType::MESSAGE_INFO, title, GetGameAchievementSummary(), cacheId, 5.0f); break; } case RC_NO_GAME_LOADED: diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index cd59be0685..64cf61b241 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -366,34 +366,7 @@ void GameInfo::ParseParamSFO() { disc_total = paramSFO.GetValueInt("DISC_TOTAL"); disc_number = paramSFO.GetValueInt("DISC_NUMBER"); // region = paramSFO.GetValueInt("REGION"); // Always seems to be 32768? - - region = GAMEREGION_OTHER; - if (id_version.size() >= 4) { - std::string regStr = id_version.substr(0, 4); - - // Guesswork - switch (regStr[2]) { - case 'E': region = GAMEREGION_EUROPE; break; - case 'U': region = GAMEREGION_USA; break; - case 'J': region = GAMEREGION_JAPAN; break; - case 'H': region = GAMEREGION_HONGKONG; break; - case 'A': region = GAMEREGION_ASIA; break; - case 'K': region = GAMEREGION_KOREA; break; - } - /* - if (regStr == "NPEZ" || regStr == "NPEG" || regStr == "ULES" || regStr == "UCES" || - regStr == "NPEX") { - region = GAMEREGION_EUROPE; - } else if (regStr == "NPUG" || regStr == "NPUZ" || regStr == "ULUS" || regStr == "UCUS") { - region = GAMEREGION_USA; - } else if (regStr == "NPJH" || regStr == "NPJG" || regStr == "ULJM"|| regStr == "ULJS") { - region = GAMEREGION_JAPAN; - } else if (regStr == "NPHG") { - region = GAMEREGION_HONGKONG; - } else if (regStr == "UCAS") { - region = GAMEREGION_CHINA; - }*/ - } + region = DetectGameRegionFromID(id); } std::string GameInfo::GetTitle() { @@ -601,7 +574,7 @@ public: && info_->fileType == IdentifiedFileType::PSP_PBP_DIRECTORY) { info_->id = g_paramSFO.GenerateFakeID(gamePath_); info_->id_version = info_->id + "_1.00"; - info_->region = GAMEREGION_COUNT + 1; // Homebrew + info_->region = GameRegion::HOMEBREW; // Homebrew } info_->MarkReadyNoLock(GameInfoFlags::PARAM_SFO); } @@ -664,7 +637,7 @@ handleELF: if (flags_ & GameInfoFlags::PARAM_SFO) { info_->id = g_paramSFO.GenerateFakeID(gamePath_); info_->id_version = info_->id + "_1.00"; - info_->region = GAMEREGION_COUNT + 1; // Homebrew + info_->region = GameRegion::HOMEBREW; // Homebrew } if (flags_ & GameInfoFlags::ICON) { diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index 303375a2b6..9a8d3dff2f 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -38,18 +38,6 @@ namespace Draw { // A GameInfo object can also represent a piece of savedata. -// Guessed from GameID, not necessarily accurate -enum GameRegion { - GAMEREGION_JAPAN, - GAMEREGION_USA, - GAMEREGION_EUROPE, - GAMEREGION_HONGKONG, - GAMEREGION_ASIA, - GAMEREGION_KOREA, - GAMEREGION_OTHER, - GAMEREGION_COUNT, -}; - enum class GameInfoFlags { FILE_TYPE = 0x01, // Don't need to specify this, always included. PARAM_SFO = 0x02, @@ -158,7 +146,7 @@ public: std::string id_version; int disc_total = 0; int disc_number = 0; - int region = -1; + GameRegion region = GameRegion::OTHER; IdentifiedFileType fileType; bool hasConfig = false; diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index 3d25edc1ea..8d2e830332 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -294,7 +294,7 @@ void GameScreen::CreateViews() { btnSetBackground_->OnClick.Handle(this, &GameScreen::OnSetBackground); btnSetBackground_->SetVisibility(V_GONE); - isHomebrew_ = info && info->region > GAMEREGION_COUNT; + isHomebrew_ = info && info->region == GameRegion::HOMEBREW; if (fileTypeSupportCRC && !isHomebrew_ && !Reporting::HasCRC(gamePath_) ) { btnCalcCRC_ = rightColumnItems->Add(new ChoiceWithValueDisplay(&CRC32string, ga->T("Calculate CRC"), I18NCat::NONE)); btnCalcCRC_->OnClick.Handle(this, &GameScreen::OnDoCRC32); @@ -381,18 +381,10 @@ ScreenRenderFlags GameScreen::render(ScreenRenderMode mode) { } if (tvRegion_) { - if (info->region >= 0 && info->region < GAMEREGION_COUNT && info->region != GAMEREGION_OTHER) { - static const char *regionNames[GAMEREGION_COUNT] = { - "Japan", - "USA", - "Europe", - "Hong Kong", - "Asia", - "Korea" - }; - tvRegion_->SetText(ga->T(regionNames[info->region])); - } else if (info->region > GAMEREGION_COUNT) { + if (info->region == GameRegion::OTHER) { tvRegion_->SetText(ga->T("Homebrew")); + } else { + tvRegion_->SetText(ga->T(GameRegionToString(info->region))); } } diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index fbf767552f..9d2c4e082c 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -382,24 +382,23 @@ void GameButton::Draw(UIContext &dc) { } } } - const int region = ginfo->region; - if (g_Config.bShowRegionOnGameIcon && region >= 0 && region < GAMEREGION_COUNT && region != GAMEREGION_OTHER) { - const ImageID regionIcons[GAMEREGION_COUNT] = { + const int regionIndex = (int)ginfo->region; + if (g_Config.bShowRegionOnGameIcon && regionIndex >= 0 && regionIndex < (int)GameRegion::COUNT) { + const ImageID regionIcons[(int)GameRegion::COUNT] = { ImageID("I_FLAG_JP"), ImageID("I_FLAG_US"), ImageID("I_FLAG_EU"), ImageID("I_FLAG_HK"), ImageID("I_FLAG_AS"), ImageID("I_FLAG_KO"), - ImageID::invalid(), }; - const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(regionIcons[region]); + const AtlasImage *image = dc.Draw()->GetAtlas()->getImage(regionIcons[regionIndex]); if (image) { if (gridStyle_) { - dc.Draw()->DrawImage(regionIcons[region], x + w - (image->w + 5)*g_Config.fGameGridScale, + dc.Draw()->DrawImage(regionIcons[regionIndex], x + w - (image->w + 5)*g_Config.fGameGridScale, y + h - (image->h + 5)*g_Config.fGameGridScale, g_Config.fGameGridScale); } else { - dc.Draw()->DrawImage(regionIcons[region], x - 2 - image->w - 3, y + h - image->h - 5, 1.0f); + dc.Draw()->DrawImage(regionIcons[regionIndex], x - 2 - image->w - 3, y + h - image->h - 5, 1.0f); } } } diff --git a/assets/lang/sv_SE.ini b/assets/lang/sv_SE.ini index 31740bbdef..d80d3b0ab6 100644 --- a/assets/lang/sv_SE.ini +++ b/assets/lang/sv_SE.ini @@ -557,7 +557,7 @@ Create Shortcut = Skapa genväg Delete Game = Ta bort spel Delete Game Config = Ta bort spelconfig Delete Save Data = Ta bort sparad data -Europe = Europe +Europe = Europa File size incorrect, bad or modified ISO = Filstorlek inkorrekt, eller korrupt ISO Game = Spel Game ID unknown - not in the ReDump database = Spel-ID okänt - ej i ReDump's databas