From 5768d826621c055c84c12bdf7e92477c3c5866a6 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Sat, 24 Feb 2024 15:55:06 -0500 Subject: [PATCH 1/3] Add Discord Presence flag to Achievement Settings When enabled, this will send Rich Presence to Discord to be displayed in players' statuses. --- Source/Core/Core/Config/AchievementSettings.cpp | 2 ++ Source/Core/Core/Config/AchievementSettings.h | 1 + 2 files changed, 3 insertions(+) diff --git a/Source/Core/Core/Config/AchievementSettings.cpp b/Source/Core/Core/Config/AchievementSettings.cpp index 38a5bb6166..1e20729bdd 100644 --- a/Source/Core/Core/Config/AchievementSettings.cpp +++ b/Source/Core/Core/Config/AchievementSettings.cpp @@ -22,6 +22,8 @@ const Info RA_UNOFFICIAL_ENABLED{{System::Achievements, "Achievements", "U const Info RA_ENCORE_ENABLED{{System::Achievements, "Achievements", "EncoreEnabled"}, false}; const Info RA_SPECTATOR_ENABLED{{System::Achievements, "Achievements", "SpectatorEnabled"}, false}; +const Info RA_DISCORD_PRESENCE_ENABLED{ + {System::Achievements, "Achievements", "DiscordPresenceEnabled"}, false}; const Info RA_PROGRESS_ENABLED{{System::Achievements, "Achievements", "ProgressEnabled"}, false}; const Info RA_BADGES_ENABLED{{System::Achievements, "Achievements", "BadgesEnabled"}, false}; diff --git a/Source/Core/Core/Config/AchievementSettings.h b/Source/Core/Core/Config/AchievementSettings.h index e448054214..ae2ecbc8b6 100644 --- a/Source/Core/Core/Config/AchievementSettings.h +++ b/Source/Core/Core/Config/AchievementSettings.h @@ -18,6 +18,7 @@ extern const Info RA_HARDCORE_ENABLED; extern const Info RA_UNOFFICIAL_ENABLED; extern const Info RA_ENCORE_ENABLED; extern const Info RA_SPECTATOR_ENABLED; +extern const Info RA_DISCORD_PRESENCE_ENABLED; extern const Info RA_PROGRESS_ENABLED; extern const Info RA_BADGES_ENABLED; } // namespace Config From 57c8ea12ed7cd8669abd101c4628066affecf4d6 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Sat, 24 Feb 2024 15:57:06 -0500 Subject: [PATCH 2/3] Send Rich Presence to Discord If Rich Presence and Discord Presence are enabled in Achievement Settings, the string generated by rcheevos as the player's current Rich Presence will be sent to the Status field in the Discord Presence object. This will be updated whenever Rich Presence updates. --- Source/Core/Core/AchievementManager.cpp | 3 +++ Source/Core/UICommon/DiscordPresence.cpp | 33 +++++++++++++++++++++--- Source/Core/UICommon/DiscordPresence.h | 3 ++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index c1b7e92c58..b1b63726b3 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -22,6 +22,7 @@ #include "Core/PowerPC/MMU.h" #include "Core/System.h" #include "DiscIO/Blob.h" +#include "UICommon/DiscordPresence.h" #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/VideoEvents.h" @@ -227,6 +228,8 @@ void AchievementManager::DoFrame() m_last_rp_time = current_time; rc_client_get_rich_presence_message(m_client, m_rich_presence.data(), RP_SIZE); m_update_callback(UpdatedItems{.rich_presence = true}); + if (Config::Get(Config::RA_DISCORD_PRESENCE_ENABLED)) + Discord::UpdateDiscordPresence(); } } diff --git a/Source/Core/UICommon/DiscordPresence.cpp b/Source/Core/UICommon/DiscordPresence.cpp index eadc229054..67870999aa 100644 --- a/Source/Core/UICommon/DiscordPresence.cpp +++ b/Source/Core/UICommon/DiscordPresence.cpp @@ -21,6 +21,8 @@ #include "Common/HttpRequest.h" #include "Common/StringUtil.h" +#include "Core/AchievementManager.h" +#include "Core/Config/AchievementSettings.h" #include "Core/System.h" #endif @@ -34,6 +36,9 @@ namespace { Handler* event_handler = nullptr; const char* username = ""; +static int64_t s_start_timestamp = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); void HandleDiscordReady(const DiscordUser* user) { @@ -195,7 +200,7 @@ bool UpdateDiscordPresenceRaw(const std::string& details, const std::string& sta } void UpdateDiscordPresence(int party_size, SecretType type, const std::string& secret, - const std::string& current_game) + const std::string& current_game, bool reset_timer) { #ifdef USE_DISCORD_PRESENCE if (!Config::Get(Config::MAIN_USE_DISCORD_PRESENCE)) @@ -224,10 +229,17 @@ void UpdateDiscordPresence(int party_size, SecretType type, const std::string& s discord_presence.smallImageText = "Dolphin is an emulator for the GameCube and the Wii."; } discord_presence.details = title.empty() ? "Not in-game" : title.c_str(); - discord_presence.startTimestamp = std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) - .count(); + if (reset_timer) + { + s_start_timestamp = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + } + discord_presence.startTimestamp = s_start_timestamp; +#ifdef USE_RETRO_ACHIEVEMENTS + std::string state_string; +#endif // USE_RETRO_ACHIEVEMENTS if (party_size > 0) { if (party_size < 4) @@ -244,6 +256,19 @@ void UpdateDiscordPresence(int party_size, SecretType type, const std::string& s // Note: joining still works without partyMax } } +#ifdef USE_RETRO_ACHIEVEMENTS + else if (Config::Get(Config::RA_ENABLED) && Config::Get(Config::RA_DISCORD_PRESENCE_ENABLED)) + { + state_string = AchievementManager::GetInstance().GetRichPresence().data(); + if (state_string.length() >= 128) + { + // 124 characters + 3 dots + null terminator - thanks to Stenzek for format + state_string.resize(124); + state_string += "..."; + } + discord_presence.state = state_string.c_str(); + } +#endif // USE_RETRO_ACHIEVEMENTS std::string party_id; std::string secret_final; diff --git a/Source/Core/UICommon/DiscordPresence.h b/Source/Core/UICommon/DiscordPresence.h index 67da5fd11e..4e628337d8 100644 --- a/Source/Core/UICommon/DiscordPresence.h +++ b/Source/Core/UICommon/DiscordPresence.h @@ -39,7 +39,8 @@ bool UpdateDiscordPresenceRaw(const std::string& details = {}, const std::string const int64_t start_timestamp = 0, const int64_t end_timestamp = 0, const int party_size = 0, const int party_max = 0); void UpdateDiscordPresence(int party_size = 0, SecretType type = SecretType::Empty, - const std::string& secret = {}, const std::string& current_game = {}); + const std::string& secret = {}, const std::string& current_game = {}, + const bool reset_timer = false); std::string CreateSecretFromIPAddress(const std::string& ip_address, int port); void Shutdown(); void SetDiscordPresenceEnabled(bool enabled); From 2328539a76a338d4c3e591e4a96e5ea49a661bb3 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Sat, 24 Feb 2024 16:06:29 -0500 Subject: [PATCH 3/3] Add Discord Presence setting to Achievement Settings dialog Setting is only enabled when Rich Presence is enabled. Toggling either Rich Presence or Discord Presence will immediately update the Discord status. --- .../AchievementSettingsWidget.cpp | 24 +++++++++++++++++++ .../Achievements/AchievementSettingsWidget.h | 2 ++ .../Core/DolphinQt/Settings/GeneralPane.cpp | 3 +++ 3 files changed, 29 insertions(+) diff --git a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp index 807f321bff..62f6a1e0cb 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp @@ -13,9 +13,11 @@ #include "Core/Config/AchievementSettings.h" #include "Core/Config/FreeLookSettings.h" #include "Core/Config/MainSettings.h" +#include "Core/Config/UISettings.h" #include "Core/Core.h" #include "Core/Movie.h" #include "Core/System.h" +#include "UICommon/DiscordPresence.h" #include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h" #include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h" @@ -94,6 +96,10 @@ void AchievementSettingsWidget::CreateLayout() "submitted to the server.

If this is on at game launch, it will not be turned off " "until game close, because a RetroAchievements session will not be created.

If " "this is off at game launch, it can be toggled freely while the game is running.")); + m_common_discord_presence_enabled_input = new ToolTipCheckBox(tr("Enable Discord Presence")); + m_common_discord_presence_enabled_input->SetDescription( + tr("Use RetroAchievements rich presence in your Discord status.

Show Current Game on " + "Discord must be enabled.")); m_common_progress_enabled_input = new ToolTipCheckBox(tr("Enable Progress Notifications")); m_common_progress_enabled_input->SetDescription( tr("Enable progress notifications on achievements.

Displays a brief popup message " @@ -119,6 +125,9 @@ void AchievementSettingsWidget::CreateLayout() m_common_layout->addWidget(m_common_encore_enabled_input); m_common_layout->addWidget(m_common_spectator_enabled_input); m_common_layout->addWidget(new QLabel(tr("Display Settings"))); +#ifdef USE_DISCORD_PRESENCE + m_common_layout->addWidget(m_common_discord_presence_enabled_input); +#endif // USE_DISCORD_PRESENCE m_common_layout->addWidget(m_common_progress_enabled_input); m_common_layout->addWidget(m_common_badges_enabled_input); @@ -140,6 +149,8 @@ void AchievementSettingsWidget::ConnectWidgets() &AchievementSettingsWidget::ToggleEncore); connect(m_common_spectator_enabled_input, &QCheckBox::toggled, this, &AchievementSettingsWidget::ToggleSpectator); + connect(m_common_discord_presence_enabled_input, &QCheckBox::toggled, this, + &AchievementSettingsWidget::ToggleDiscordPresence); connect(m_common_progress_enabled_input, &QCheckBox::toggled, this, &AchievementSettingsWidget::ToggleProgress); connect(m_common_badges_enabled_input, &QCheckBox::toggled, this, @@ -195,6 +206,11 @@ void AchievementSettingsWidget::LoadSettings() ->setChecked(Config::Get(Config::RA_SPECTATOR_ENABLED)); SignalBlocking(m_common_spectator_enabled_input)->setEnabled(enabled); + SignalBlocking(m_common_discord_presence_enabled_input) + ->setChecked(Config::Get(Config::RA_DISCORD_PRESENCE_ENABLED)); + SignalBlocking(m_common_discord_presence_enabled_input) + ->setEnabled(enabled && Config::Get(Config::MAIN_USE_DISCORD_PRESENCE)); + SignalBlocking(m_common_progress_enabled_input) ->setChecked(Config::Get(Config::RA_PROGRESS_ENABLED)); SignalBlocking(m_common_progress_enabled_input)->setEnabled(enabled); @@ -215,6 +231,8 @@ void AchievementSettingsWidget::SaveSettings() Config::SetBaseOrCurrent(Config::RA_ENCORE_ENABLED, m_common_encore_enabled_input->isChecked()); Config::SetBaseOrCurrent(Config::RA_SPECTATOR_ENABLED, m_common_spectator_enabled_input->isChecked()); + Config::SetBaseOrCurrent(Config::RA_DISCORD_PRESENCE_ENABLED, + m_common_discord_presence_enabled_input->isChecked()); Config::SetBaseOrCurrent(Config::RA_PROGRESS_ENABLED, m_common_progress_enabled_input->isChecked()); Config::SetBaseOrCurrent(Config::RA_BADGES_ENABLED, m_common_badges_enabled_input->isChecked()); @@ -279,6 +297,12 @@ void AchievementSettingsWidget::ToggleSpectator() AchievementManager::GetInstance().SetSpectatorMode(); } +void AchievementSettingsWidget::ToggleDiscordPresence() +{ + SaveSettings(); + Discord::UpdateDiscordPresence(); +} + void AchievementSettingsWidget::ToggleProgress() { SaveSettings(); diff --git a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h index 68ba658b8f..b8e848c2d1 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h +++ b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h @@ -36,6 +36,7 @@ private: void ToggleUnofficial(); void ToggleEncore(); void ToggleSpectator(); + void ToggleDiscordPresence(); void ToggleProgress(); void ToggleBadges(); @@ -53,6 +54,7 @@ private: ToolTipCheckBox* m_common_unofficial_enabled_input; ToolTipCheckBox* m_common_encore_enabled_input; ToolTipCheckBox* m_common_spectator_enabled_input; + ToolTipCheckBox* m_common_discord_presence_enabled_input; ToolTipCheckBox* m_common_progress_enabled_input; ToolTipCheckBox* m_common_badges_enabled_input; }; diff --git a/Source/Core/DolphinQt/Settings/GeneralPane.cpp b/Source/Core/DolphinQt/Settings/GeneralPane.cpp index 114a5846a8..fcc4a79ebf 100644 --- a/Source/Core/DolphinQt/Settings/GeneralPane.cpp +++ b/Source/Core/DolphinQt/Settings/GeneralPane.cpp @@ -351,6 +351,9 @@ void GeneralPane::OnSaveConfig() #ifdef USE_DISCORD_PRESENCE Discord::SetDiscordPresenceEnabled(m_checkbox_discord_presence->isChecked()); +#ifdef USE_RETRO_ACHIEVEMENTS + emit Settings::Instance().ConfigChanged(); +#endif // USE_RETRO_ACHIEVEMENTS #endif #if defined(USE_ANALYTICS) && USE_ANALYTICS