aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Siakas <nikos.siakas@gmail.com>2020-08-23 13:12:29 +0300
committerNickSiak <nikos.siakas@gmail.com>2022-03-23 20:44:54 +0200
commit0d91930f19527923949d484f9008f87651bd7e86 (patch)
tree50d3099c87772eb5311c7d58cfefc36c5f895dd4
parenta17f77719bd8b5cc85cae82dfc0365851d9f2c8e (diff)
Game Settings: Add login to RetroAchievements
-rw-r--r--addons/resource.language.en_gb/resources/strings.po70
-rwxr-xr-xsystem/settings/settings.xml36
-rw-r--r--xbmc/games/GameSettings.cpp150
-rw-r--r--xbmc/games/GameSettings.h9
4 files changed, 259 insertions, 6 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 17e91bdfd6..8d1b9a5fab 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -8710,7 +8710,17 @@ msgctxt "#15311"
msgid "Path:"
msgstr ""
-#empty strings from id 15312 to 15999
+#. Game settings category name
+#: system/settings/settings.xml
+msgctxt "#15312"
+msgid "Achievements"
+msgstr ""
+
+#. Group label for Achievements category in game settings
+#: system/settings/settings.xml
+msgctxt "#15313"
+msgid "Login to RetroAchievements"
+msgstr ""
#. Label for button in the in-game savestate manager
#: xbmc/games/dialogs/osd/DialogInGameSaves.cpp
@@ -18366,7 +18376,63 @@ msgctxt "#35261"
msgid "New game"
msgstr ""
-#empty strings from id 35262 to 35504
+#. Help text for RetroAchievements username input setting
+#: system/settings/settings.xml
+msgctxt "#35262"
+msgid "Enter your RetroAchievements account username"
+msgstr ""
+
+#. Help text for RetroAchievements password input setting
+#: system/settings/settings.xml
+msgctxt "#35263"
+msgid "Enter your RetroAchievements account password"
+msgstr ""
+
+#. Label for notification events regarding RetroAchievements login
+#: xbmc/games/GameSettings.cpp
+msgctxt "#35264"
+msgid "RetroAchievements"
+msgstr ""
+
+#. Description for notification event regarding unsuccessful RetroAchievements login
+#: xbmc/games/GameSettings.cpp
+msgctxt "#35265"
+msgid "Incorrect User/Password!"
+msgstr ""
+
+#. Description for notification event regarding unsuccessful RetroAchievements login
+#: xbmc/games/GameSettings.cpp
+msgctxt "#35266"
+msgid "Failed to contact server"
+msgstr ""
+
+#. Description for notification event regarding unsuccessful RetroAchievements login
+#: xbmc/games/GameSettings.cpp
+msgctxt "#35267"
+msgid "Invalid response from server"
+msgstr ""
+
+#. Setting to show if the user is logged in to RetroAchievements
+#. Settings -> Games -> Achievements -> Logged in
+#: system/settings/settings.xml
+msgctxt "#35268"
+msgid "Logged in"
+msgstr ""
+
+#. Help text for the setting that shows if the user is logged in to RetroAchievements
+#. Settings -> Games -> Achievements -> Logged in
+#: system/settings/settings.xml
+msgctxt "#35269"
+msgid "Toggle this setting to log in or out of RetroAchievemts."
+msgstr ""
+
+#. Description for notification event regarding unsuccessful RetroAchievements login
+#: xbmc/games/GameSettings.cpp
+msgctxt "#35270"
+msgid "Your account is not verified. Please check your email to complete your sign up."
+msgstr ""
+
+#empty strings from id 35271 to 35504
#. connection state "host unreachable"
#: xbmc/pvr/addons/PVRClients.cpp
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 36b2f7fa47..549cd40af6 100755
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -2416,6 +2416,42 @@
</setting>
</group>
</category>
+ <category id="gamesachievements" label="15312">
+ <group id="1" label="15313">
+ <setting id="gamesachievements.username" type="string" label="1048" help="35262">
+ <level>0</level>
+ <default></default>
+ <constraints>
+ <allowempty>true</allowempty>
+ </constraints>
+ <control type="edit" format="string"/>
+ </setting>
+ <setting id="gamesachievements.password" type="string" label="733" help="35263">
+ <level>0</level>
+ <default></default>
+ <constraints>
+ <allowempty>true</allowempty>
+ </constraints>
+ <control type="edit" format="string">
+ <hidden>true</hidden>
+ </control>
+ </setting>
+ <setting id="gamesachievements.token" type="string">
+ <visible>false</visible>
+ <default></default>
+ <constraints>
+ <allowempty>true</allowempty>
+ </constraints>
+ <control type="edit" format="string"/>
+ </setting>
+ <setting id="gamesachievements.loggedin" type="boolean" label="35268" help="35269">
+ <visible>true</visible>
+ <level>0</level>
+ <default>false</default>
+ <control type="toggle" />
+ </setting>
+ </group>
+ </category>
</section>
<section id="system" label="13000" help="36349">
<category id="display" label="14220" help="36603">
diff --git a/xbmc/games/GameSettings.cpp b/xbmc/games/GameSettings.cpp
index fb57b815a3..acbccdc6fb 100644
--- a/xbmc/games/GameSettings.cpp
+++ b/xbmc/games/GameSettings.cpp
@@ -9,11 +9,20 @@
#include "GameSettings.h"
#include "ServiceBroker.h"
+#include "URL.h"
+#include "events/EventLog.h"
+#include "events/NotificationEvent.h"
+#include "filesystem/File.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
#include "settings/lib/Setting.h"
+#include "utils/JSONVariantParser.h"
+#include "utils/StringUtils.h"
+#include "utils/Variant.h"
+#include "utils/log.h"
#include <algorithm>
+#include <vector>
using namespace KODI;
using namespace GAME;
@@ -25,16 +34,27 @@ const std::string SETTING_GAMES_SHOW_OSD_HELP = "gamesgeneral.showosdhelp";
const std::string SETTING_GAMES_ENABLEAUTOSAVE = "gamesgeneral.enableautosave";
const std::string SETTING_GAMES_ENABLEREWIND = "gamesgeneral.enablerewind";
const std::string SETTING_GAMES_REWINDTIME = "gamesgeneral.rewindtime";
+const std::string SETTING_GAMES_ACHIEVEMENTS_USERNAME = "gamesachievements.username";
+const std::string SETTING_GAMES_ACHIEVEMENTS_PASSWORD = "gamesachievements.password";
+const std::string SETTING_GAMES_ACHIEVEMENTS_TOKEN = "gamesachievements.token";
+const std::string SETTING_GAMES_ACHIEVEMENTS_LOGGED_IN = "gamesachievements.loggedin";
+
+constexpr auto LOGIN_TO_RETRO_ACHIEVEMENTS_URL_TEMPLATE =
+ "http://retroachievements.org/dorequest.php?r=login&u={}&p={}";
+constexpr auto GET_PATCH_DATA_URL_TEMPLATE =
+ "http://retroachievements.org/dorequest.php?r=patch&u={}&t={}&g=0";
+constexpr auto SUCCESS = "Success";
+constexpr auto TOKEN = "Token";
} // namespace
CGameSettings::CGameSettings()
{
m_settings = CServiceBroker::GetSettingsComponent()->GetSettings();
- m_settings->RegisterCallback(this, {
- SETTING_GAMES_ENABLEREWIND,
- SETTING_GAMES_REWINDTIME,
- });
+ m_settings->RegisterCallback(this, {SETTING_GAMES_ENABLEREWIND, SETTING_GAMES_REWINDTIME,
+ SETTING_GAMES_ACHIEVEMENTS_USERNAME,
+ SETTING_GAMES_ACHIEVEMENTS_PASSWORD,
+ SETTING_GAMES_ACHIEVEMENTS_LOGGED_IN});
}
CGameSettings::~CGameSettings()
@@ -85,6 +105,16 @@ unsigned int CGameSettings::MaxRewindTimeSec()
return static_cast<unsigned int>(std::max(rewindTimeSec, 0));
}
+std::string CGameSettings::GetRAUsername() const
+{
+ return m_settings->GetString(SETTING_GAMES_ACHIEVEMENTS_USERNAME);
+}
+
+std::string CGameSettings::GetRAToken() const
+{
+ return m_settings->GetString(SETTING_GAMES_ACHIEVEMENTS_TOKEN);
+}
+
void CGameSettings::OnSettingChanged(const std::shared_ptr<const CSetting>& setting)
{
if (setting == nullptr)
@@ -97,4 +127,116 @@ void CGameSettings::OnSettingChanged(const std::shared_ptr<const CSetting>& sett
SetChanged();
NotifyObservers(ObservableMessageSettingsChanged);
}
+ else if (settingId == SETTING_GAMES_ACHIEVEMENTS_LOGGED_IN &&
+ std::dynamic_pointer_cast<const CSettingBool>(setting)->GetValue())
+ {
+ const std::string username = m_settings->GetString(SETTING_GAMES_ACHIEVEMENTS_USERNAME);
+ const std::string password = m_settings->GetString(SETTING_GAMES_ACHIEVEMENTS_PASSWORD);
+ std::string token = m_settings->GetString(SETTING_GAMES_ACHIEVEMENTS_TOKEN);
+
+ token = LoginToRA(username, password, std::move(token));
+
+ m_settings->SetString(SETTING_GAMES_ACHIEVEMENTS_TOKEN, token);
+
+ if (!token.empty())
+ {
+ m_settings->SetBool(SETTING_GAMES_ACHIEVEMENTS_LOGGED_IN, true);
+ }
+ else
+ {
+ if (settingId == SETTING_GAMES_ACHIEVEMENTS_PASSWORD)
+ m_settings->SetString(SETTING_GAMES_ACHIEVEMENTS_PASSWORD, "");
+ m_settings->SetBool(SETTING_GAMES_ACHIEVEMENTS_LOGGED_IN, false);
+ }
+
+ m_settings->Save();
+ }
+ else if (settingId == SETTING_GAMES_ACHIEVEMENTS_LOGGED_IN &&
+ !std::dynamic_pointer_cast<const CSettingBool>(setting)->GetValue())
+ {
+ m_settings->SetString(SETTING_GAMES_ACHIEVEMENTS_TOKEN, "");
+ m_settings->Save();
+ }
+ else if (settingId == SETTING_GAMES_ACHIEVEMENTS_USERNAME ||
+ settingId == SETTING_GAMES_ACHIEVEMENTS_PASSWORD)
+ {
+ m_settings->SetBool(SETTING_GAMES_ACHIEVEMENTS_LOGGED_IN, false);
+ m_settings->SetString(SETTING_GAMES_ACHIEVEMENTS_TOKEN, "");
+ m_settings->Save();
+ }
+}
+
+std::string CGameSettings::LoginToRA(const std::string& username,
+ const std::string& password,
+ std::string token) const
+{
+ if (username.empty() || password.empty())
+ return token;
+
+ XFILE::CFile request;
+ const CURL loginUrl(
+ StringUtils::Format(LOGIN_TO_RETRO_ACHIEVEMENTS_URL_TEMPLATE, username, password));
+
+ std::vector<uint8_t> response;
+ if (request.LoadFile(loginUrl, response) > 0)
+ {
+ std::string strResponse(response.begin(), response.end());
+ CVariant data(CVariant::VariantTypeObject);
+ if (CJSONVariantParser::Parse(strResponse, data))
+ {
+ if (data[SUCCESS].asBoolean())
+ {
+ token = data[TOKEN].asString();
+ if (!IsAccountVerified(username, token))
+ {
+ token.clear();
+ // "RetroAchievements", "Your account is not verified, please check your emails to complete your sign up"
+ CServiceBroker::GetEventLog()->AddWithNotification(
+ EventPtr(new CNotificationEvent(35264, 35270, EventLevel::Error)));
+ }
+ }
+ else
+ {
+ token.clear();
+
+ // "RetroAchievements", "Incorrect User/Password!"
+ CServiceBroker::GetEventLog()->AddWithNotification(
+ EventPtr(new CNotificationEvent(35264, 35265, EventLevel::Error)));
+ }
+ }
+ else
+ {
+ // "RetroAchievements", "Invalid response from server"
+ CServiceBroker::GetEventLog()->AddWithNotification(
+ EventPtr(new CNotificationEvent(35264, 35267, EventLevel::Error)));
+
+ CLog::Log(LOGERROR, "Invalid server response: {}", strResponse);
+ }
+ }
+ else
+ {
+ // "RetroAchievements", "Failed to contact server"
+ CServiceBroker::GetEventLog()->AddWithNotification(
+ EventPtr(new CNotificationEvent(35264, 35266, EventLevel::Error)));
+ }
+ return token;
+}
+
+bool CGameSettings::IsAccountVerified(const std::string& username, const std::string& token) const
+{
+ XFILE::CFile request;
+ const CURL getPatchFileUrl(StringUtils::Format(GET_PATCH_DATA_URL_TEMPLATE, username, token));
+ std::vector<uint8_t> response;
+ if (request.LoadFile(getPatchFileUrl, response) > 0)
+ {
+ std::string strResponse(response.begin(), response.end());
+ CVariant data(CVariant::VariantTypeObject);
+
+ if (CJSONVariantParser::Parse(strResponse, data))
+ {
+ return data[SUCCESS].asBoolean();
+ }
+ }
+
+ return false;
}
diff --git a/xbmc/games/GameSettings.h b/xbmc/games/GameSettings.h
index 59acac1975..63ee67b379 100644
--- a/xbmc/games/GameSettings.h
+++ b/xbmc/games/GameSettings.h
@@ -11,6 +11,8 @@
#include "settings/lib/ISettingCallback.h"
#include "utils/Observer.h"
+#include <string>
+
class CSetting;
class CSettings;
@@ -33,11 +35,18 @@ public:
bool AutosaveEnabled();
bool RewindEnabled();
unsigned int MaxRewindTimeSec();
+ std::string GetRAUsername() const;
+ std::string GetRAToken() const;
// Inherited from ISettingCallback
void OnSettingChanged(const std::shared_ptr<const CSetting>& setting) override;
private:
+ std::string LoginToRA(const std::string& username,
+ const std::string& password,
+ std::string token) const;
+ bool IsAccountVerified(const std::string& username, const std::string& token) const;
+
// Construction parameters
std::shared_ptr<CSettings> m_settings;
};