Navigation Menu

Skip to content

Commit

Permalink
TitleDatabase: Don't merge multiple languages into same map
Browse files Browse the repository at this point in the history
Instead of selecting languages based on the user config at the time
of TitleDatabase creation and merging the different languages into one
map for GC and one map for Wii, have one map for each language, and
have the caller supply the language they want. This makes us not need
the IsGCTitle function, which is inaccurate for IDs that start with D.
  • Loading branch information
JosJuice committed Feb 25, 2019
1 parent 8842a0f commit 9df763b
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 134 deletions.
2 changes: 1 addition & 1 deletion Source/Core/Core/ConfigManager.cpp
Expand Up @@ -749,7 +749,7 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri
} }


const Core::TitleDatabase title_database; const Core::TitleDatabase title_database;
m_title_description = title_database.Describe(m_gametdb_id); m_title_description = title_database.Describe(m_gametdb_id, GetCurrentLanguage(bWii));
NOTICE_LOG(CORE, "Active title: %s", m_title_description.c_str()); NOTICE_LOG(CORE, "Active title: %s", m_title_description.c_str());


Config::AddLayer(ConfigLoaders::GenerateGlobalGameConfigLoader(game_id, revision)); Config::AddLayer(ConfigLoaders::GenerateGlobalGameConfigLoader(game_id, revision));
Expand Down
174 changes: 58 additions & 116 deletions Source/Core/Core/TitleDatabase.cpp
Expand Up @@ -21,47 +21,15 @@ namespace Core
{ {
static const std::string EMPTY_STRING; static const std::string EMPTY_STRING;


static std::string GetLanguageCode(DiscIO::Language language)
{
switch (language)
{
case DiscIO::Language::Japanese:
return "ja";
case DiscIO::Language::English:
return "en";
case DiscIO::Language::German:
return "de";
case DiscIO::Language::French:
return "fr";
case DiscIO::Language::Spanish:
return "es";
case DiscIO::Language::Italian:
return "it";
case DiscIO::Language::Dutch:
return "nl";
case DiscIO::Language::SimplifiedChinese:
return "zh_CN";
case DiscIO::Language::TraditionalChinese:
return "zh_TW";
case DiscIO::Language::Korean:
return "ko";
default:
return "en";
}
}

using Map = std::unordered_map<std::string, std::string>; using Map = std::unordered_map<std::string, std::string>;


// Note that this function will not overwrite entries that already are in the maps static Map LoadMap(const std::string& file_path)
static bool LoadMap(const std::string& file_path, Map& map,
std::function<bool(const std::string& game_id)> predicate)
{ {
Map map;

std::ifstream txt; std::ifstream txt;
File::OpenFStream(txt, file_path, std::ios::in); File::OpenFStream(txt, file_path, std::ios::in);


if (!txt.is_open())
return false;

std::string line; std::string line;
while (std::getline(txt, line)) while (std::getline(txt, line))
{ {
Expand All @@ -72,119 +40,93 @@ static bool LoadMap(const std::string& file_path, Map& map,
if (equals_index != std::string::npos) if (equals_index != std::string::npos)
{ {
const std::string game_id = StripSpaces(line.substr(0, equals_index)); const std::string game_id = StripSpaces(line.substr(0, equals_index));
if (game_id.length() >= 4 && predicate(game_id)) if (game_id.length() >= 4)
map.emplace(game_id, StripSpaces(line.substr(equals_index + 1))); map.emplace(game_id, StripSpaces(line.substr(equals_index + 1)));
} }
} }
return true; return map;
}

// This should only be used with the common game ID format (used by WiiTDBs), not Dolphin's.
// Otherwise, TurboGrafx-16 VC games (with the system ID P) will be misdetected as GameCube titles.
// The formats differ in that Dolphin's uses 6 characters for non-disc titles instead of 4.
static bool IsGCTitle(const std::string& game_id)
{
const char system_id = game_id[0];
return game_id.length() == 6 &&
(system_id == 'G' || system_id == 'D' || system_id == 'U' || system_id == 'P');
}

static bool IsWiiTitle(const std::string& game_id)
{
// Assume that any non-GameCube title is a Wii title.
return !IsGCTitle(game_id);
}

static bool IsJapaneseGCTitle(const std::string& game_id)
{
if (!IsGCTitle(game_id))
return false;

return DiscIO::CountryCodeToCountry(game_id[3], DiscIO::Platform::GameCubeDisc) ==
DiscIO::Country::Japan;
} }


static bool IsNonJapaneseGCTitle(const std::string& game_id) void TitleDatabase::AddLazyMap(DiscIO::Language language, const std::string& language_code)
{ {
if (!IsGCTitle(game_id)) m_title_maps[language] = [language_code]() -> Map {
return false; return LoadMap(File::GetSysDirectory() + "wiitdb-" + language_code + ".txt");

};
return DiscIO::CountryCodeToCountry(game_id[3], DiscIO::Platform::GameCubeDisc) !=
DiscIO::Country::Japan;
}

// Note that this function will not overwrite entries that already are in the maps
static bool LoadMap(const std::string& file_path, Map& gc_map, Map& wii_map)
{
Map map;
if (!LoadMap(file_path, map, [](const auto& game_id) { return true; }))
return false;

for (auto& entry : map)
{
auto& destination_map = IsGCTitle(entry.first) ? gc_map : wii_map;
destination_map.emplace(std::move(entry));
}
return true;
} }


TitleDatabase::TitleDatabase() TitleDatabase::TitleDatabase()
{ {
// Load the user databases. // User database
const std::string& load_directory = File::GetUserPath(D_LOAD_IDX); const std::string& load_directory = File::GetUserPath(D_LOAD_IDX);
if (!LoadMap(load_directory + "wiitdb.txt", m_gc_title_map, m_wii_title_map)) m_user_title_map = LoadMap(load_directory + "wiitdb.txt");
LoadMap(load_directory + "titles.txt", m_gc_title_map, m_wii_title_map); if (m_user_title_map.empty())

m_user_title_map = LoadMap(load_directory + "titles.txt");
if (!SConfig::GetInstance().m_use_builtin_title_database)
return; // Pre-defined databases (one per language)

AddLazyMap(DiscIO::Language::Japanese, "ja");
// Load the database in the console language. AddLazyMap(DiscIO::Language::English, "en");
// Note: The GameCube language setting can't be set to Japanese, AddLazyMap(DiscIO::Language::German, "de");
// so instead, we use Japanese names iff the games are NTSC-J. AddLazyMap(DiscIO::Language::French, "fr");
const std::string gc_code = GetLanguageCode(SConfig::GetInstance().GetCurrentLanguage(false)); AddLazyMap(DiscIO::Language::Spanish, "es");
const std::string wii_code = GetLanguageCode(SConfig::GetInstance().GetCurrentLanguage(true)); AddLazyMap(DiscIO::Language::Italian, "it");
LoadMap(File::GetSysDirectory() + "wiitdb-ja.txt", m_gc_title_map, IsJapaneseGCTitle); AddLazyMap(DiscIO::Language::Dutch, "nl");
if (gc_code != "en") AddLazyMap(DiscIO::Language::SimplifiedChinese, "zh_CN");
{ AddLazyMap(DiscIO::Language::TraditionalChinese, "zh_TW");
LoadMap(File::GetSysDirectory() + "wiitdb-" + gc_code + ".txt", m_gc_title_map, AddLazyMap(DiscIO::Language::Korean, "ko");
IsNonJapaneseGCTitle);
}
if (wii_code != "en")
LoadMap(File::GetSysDirectory() + "wiitdb-" + wii_code + ".txt", m_wii_title_map, IsWiiTitle);

// Load the English database as the base database.
LoadMap(File::GetSysDirectory() + "wiitdb-en.txt", m_gc_title_map, m_wii_title_map);


// Titles that cannot be part of the Wii TDB, // Titles that cannot be part of the Wii TDB,
// but common enough to justify having entries for them. // but common enough to justify having entries for them.


// i18n: "Wii Menu" (or System Menu) refers to the Wii's main menu, // i18n: "Wii Menu" (or System Menu) refers to the Wii's main menu,
// which is (usually) the first thing users see when a Wii console starts. // which is (usually) the first thing users see when a Wii console starts.
m_wii_title_map.emplace("0000000100000002", GetStringT("Wii Menu")); m_base_map.emplace("0000000100000002", GetStringT("Wii Menu"));
for (const auto& id : {"HAXX", "JODI", "00010001af1bf516", "LULZ", "OHBC"}) for (const auto& id : {"HAXX", "JODI", "00010001af1bf516", "LULZ", "OHBC"})
m_wii_title_map.emplace(id, "The Homebrew Channel"); m_base_map.emplace(id, "The Homebrew Channel");
} }


TitleDatabase::~TitleDatabase() = default; TitleDatabase::~TitleDatabase() = default;


const std::string& TitleDatabase::GetTitleName(const std::string& gametdb_id) const const std::string& TitleDatabase::GetTitleName(const std::string& gametdb_id,
DiscIO::Language language) const
{ {
const auto& map = IsWiiTitle(gametdb_id) ? m_wii_title_map : m_gc_title_map; auto it = m_user_title_map.find(gametdb_id);
const auto iterator = map.find(gametdb_id); if (it != m_user_title_map.end())
return iterator != map.end() ? iterator->second : EMPTY_STRING; return it->second;

if (!SConfig::GetInstance().m_use_builtin_title_database)
return EMPTY_STRING;

const Map& map = *m_title_maps.at(language);
it = map.find(gametdb_id);
if (it != map.end())
return it->second;

if (language != DiscIO::Language::English)
{
const Map& english_map = *m_title_maps.at(DiscIO::Language::English);
it = english_map.find(gametdb_id);
if (it != english_map.end())
return it->second;
}

it = m_base_map.find(gametdb_id);
if (it != m_base_map.end())
return it->second;

return EMPTY_STRING;
} }


const std::string& TitleDatabase::GetChannelName(u64 title_id) const const std::string& TitleDatabase::GetChannelName(u64 title_id, DiscIO::Language language) const
{ {
const std::string id{ const std::string id{
{static_cast<char>((title_id >> 24) & 0xff), static_cast<char>((title_id >> 16) & 0xff), {static_cast<char>((title_id >> 24) & 0xff), static_cast<char>((title_id >> 16) & 0xff),
static_cast<char>((title_id >> 8) & 0xff), static_cast<char>(title_id & 0xff)}}; static_cast<char>((title_id >> 8) & 0xff), static_cast<char>(title_id & 0xff)}};
return GetTitleName(id); return GetTitleName(id, language);
} }


std::string TitleDatabase::Describe(const std::string& gametdb_id) const std::string TitleDatabase::Describe(const std::string& gametdb_id, DiscIO::Language language) const
{ {
const std::string& title_name = GetTitleName(gametdb_id); const std::string& title_name = GetTitleName(gametdb_id, language);
if (title_name.empty()) if (title_name.empty())
return gametdb_id; return gametdb_id;
return StringFromFormat("%s (%s)", title_name.c_str(), gametdb_id.c_str()); return StringFromFormat("%s (%s)", title_name.c_str(), gametdb_id.c_str());
Expand Down
20 changes: 15 additions & 5 deletions Source/Core/Core/TitleDatabase.h
Expand Up @@ -8,6 +8,12 @@
#include <unordered_map> #include <unordered_map>


#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Lazy.h"

namespace DiscIO
{
enum class Language;
}


namespace Core namespace Core
{ {
Expand All @@ -20,16 +26,20 @@ class TitleDatabase final


// Get a user friendly title name for a GameTDB ID. // Get a user friendly title name for a GameTDB ID.
// This falls back to returning an empty string if none could be found. // This falls back to returning an empty string if none could be found.
const std::string& GetTitleName(const std::string& gametdb_id) const; const std::string& GetTitleName(const std::string& gametdb_id, DiscIO::Language language) const;


// Same as above, but takes a title ID instead of a GameTDB ID, and only works for channels. // Same as above, but takes a title ID instead of a GameTDB ID, and only works for channels.
const std::string& GetChannelName(u64 title_id) const; const std::string& GetChannelName(u64 title_id, DiscIO::Language language) const;


// Get a description for a GameTDB ID (title name if available + GameTDB ID). // Get a description for a GameTDB ID (title name if available + GameTDB ID).
std::string Describe(const std::string& gametdb_id) const; std::string Describe(const std::string& gametdb_id, DiscIO::Language language) const;


private: private:
std::unordered_map<std::string, std::string> m_wii_title_map; void AddLazyMap(DiscIO::Language language, const std::string& language_code);
std::unordered_map<std::string, std::string> m_gc_title_map;
std::unordered_map<DiscIO::Language, Common::Lazy<std::unordered_map<std::string, std::string>>>
m_title_maps;
std::unordered_map<std::string, std::string> m_base_map;
std::unordered_map<std::string, std::string> m_user_title_map;
}; };
} // namespace Core } // namespace Core
4 changes: 3 additions & 1 deletion Source/Core/DolphinQt/MenuBar.cpp
Expand Up @@ -43,6 +43,7 @@
#include "Core/TitleDatabase.h" #include "Core/TitleDatabase.h"
#include "Core/WiiUtils.h" #include "Core/WiiUtils.h"


#include "DiscIO/Enums.h"
#include "DiscIO/NANDImporter.h" #include "DiscIO/NANDImporter.h"
#include "DiscIO/WiiSaveBanner.h" #include "DiscIO/WiiSaveBanner.h"


Expand Down Expand Up @@ -1038,11 +1039,12 @@ void MenuBar::CheckNAND()
{ {
std::string title_listings; std::string title_listings;
Core::TitleDatabase title_db; Core::TitleDatabase title_db;
const DiscIO::Language language = SConfig::GetInstance().GetCurrentLanguage(true);
for (const u64 title_id : result.titles_to_remove) for (const u64 title_id : result.titles_to_remove)
{ {
title_listings += StringFromFormat("%016" PRIx64, title_id); title_listings += StringFromFormat("%016" PRIx64, title_id);


const std::string database_name = title_db.GetChannelName(title_id); const std::string database_name = title_db.GetChannelName(title_id, language);
if (!database_name.empty()) if (!database_name.empty())
{ {
title_listings += " - " + database_name; title_listings += " - " + database_name;
Expand Down
25 changes: 14 additions & 11 deletions Source/Core/UICommon/GameFile.cpp
Expand Up @@ -50,14 +50,25 @@ static const std::string EMPTY_STRING;
static bool UseGameCovers() static bool UseGameCovers()
{ {
// We ifdef this out on Android because accessing the config before emulation start makes us crash. // We ifdef this out on Android because accessing the config before emulation start makes us crash.
// The Android GUI doesn't support covers anyway, so this doesn't make us lose out on functionality. // The Android GUI handles covers in Java anyway, so this doesn't make us lose any functionality.
#ifdef ANDROID #ifdef ANDROID
return false; return false;
#else #else
return Config::Get(Config::MAIN_USE_GAME_COVERS); return Config::Get(Config::MAIN_USE_GAME_COVERS);
#endif #endif
} }


DiscIO::Language GameFile::GetConfigLanguage() const
{
#ifdef ANDROID
// TODO: Make the Android app load the config at app start instead of emulation start
// so that we can access the user's preference here
return DiscIO::Language::English;
#else
return SConfig::GetInstance().GetCurrentLanguage(DiscIO::IsWii(m_platform));
#endif
}

bool operator==(const GameBanner& lhs, const GameBanner& rhs) bool operator==(const GameBanner& lhs, const GameBanner& rhs)
{ {
return std::tie(lhs.buffer, lhs.width, lhs.height) == std::tie(rhs.buffer, rhs.width, rhs.height); return std::tie(lhs.buffer, lhs.width, lhs.height) == std::tie(rhs.buffer, rhs.width, rhs.height);
Expand Down Expand Up @@ -94,15 +105,7 @@ const std::string& GameFile::Lookup(DiscIO::Language language,
const std::string& const std::string&
GameFile::LookupUsingConfigLanguage(const std::map<DiscIO::Language, std::string>& strings) const GameFile::LookupUsingConfigLanguage(const std::map<DiscIO::Language, std::string>& strings) const
{ {
#ifdef ANDROID return Lookup(GetConfigLanguage(), strings);
// TODO: Make the Android app load the config at app start instead of emulation start
// so that we can access the user's preference here
const DiscIO::Language language = DiscIO::Language::English;
#else
const bool wii = DiscIO::IsWii(m_platform);
const DiscIO::Language language = SConfig::GetInstance().GetCurrentLanguage(wii);
#endif
return Lookup(language, strings);
} }


GameFile::GameFile(const std::string& path) GameFile::GameFile(const std::string& path)
Expand Down Expand Up @@ -422,7 +425,7 @@ void GameFile::CustomBannerCommit()


const std::string& GameFile::GetName(const Core::TitleDatabase& title_database) const const std::string& GameFile::GetName(const Core::TitleDatabase& title_database) const
{ {
const std::string& custom_name = title_database.GetTitleName(m_gametdb_id); const std::string& custom_name = title_database.GetTitleName(m_gametdb_id, GetConfigLanguage());
return custom_name.empty() ? GetName() : custom_name; return custom_name.empty() ? GetName() : custom_name;
} }


Expand Down
1 change: 1 addition & 0 deletions Source/Core/UICommon/GameFile.h
Expand Up @@ -96,6 +96,7 @@ class GameFile final
void CustomCoverCommit(); void CustomCoverCommit();


private: private:
DiscIO::Language GetConfigLanguage() const;
static const std::string& Lookup(DiscIO::Language language, static const std::string& Lookup(DiscIO::Language language,
const std::map<DiscIO::Language, std::string>& strings); const std::map<DiscIO::Language, std::string>& strings);
const std::string& const std::string&
Expand Down

0 comments on commit 9df763b

Please sign in to comment.