From af86d09b4559d051748bb1131c6e8a719d65fac2 Mon Sep 17 00:00:00 2001 From: collecting Date: Thu, 2 Oct 2025 07:10:58 +0000 Subject: [PATCH] Edit discord_impl.cpp --- src/citron/discord_impl.cpp | 188 +++++++++++++++++++----------------- 1 file changed, 97 insertions(+), 91 deletions(-) diff --git a/src/citron/discord_impl.cpp b/src/citron/discord_impl.cpp index 35224cf99..225128f56 100644 --- a/src/citron/discord_impl.cpp +++ b/src/citron/discord_impl.cpp @@ -2,121 +2,127 @@ // SPDX-FileCopyrightText: 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include - -#include - -#include - -#include - -#include - #include +#include +#include +#include +#include +#include +#include #include #include "common/common_types.h" - #include "common/string_util.h" - #include "core/core.h" - #include "core/loader/loader.h" - #include "citron/discord_impl.h" - #include "citron/uisettings.h" +static void OnDiscordReady(const DiscordUser* request) { + fmt::print("\n[DISCORD CALLBACK] SUCCESS: Connected to Discord as {}#{}\n\n", request->username, request->discriminator); +} +static void OnDiscordDisconnected(int errcode, const char* message) { + fmt::print("\n[DISCORD CALLBACK] ERROR: Disconnected from Discord. Code: {}, Message: {}\n\n", errcode, message); +} +static void OnDiscordError(int errcode, const char* message) { + fmt::print("\n[DISCORD CALLBACK] ERROR: An error occurred. Code: {}, Message: {}\n\n", errcode, message); +} + namespace DiscordRPC { -DiscordImpl::DiscordImpl(Core::System & system_): system { -system_ -} { -DiscordEventHandlers handlers {}; -// The number is the client ID for citron, it's used for images and the -// application name -Discord_Initialize("1361252452329848892", & handlers, 1, nullptr); -} + DiscordImpl::DiscordImpl(Core::System& system_) : system{system_} { + DiscordEventHandlers handlers{}; + handlers.ready = OnDiscordReady; + handlers.disconnected = OnDiscordDisconnected; + handlers.errored = OnDiscordError; -DiscordImpl::~DiscordImpl() { -Discord_ClearPresence(); -Discord_Shutdown(); -} + Discord_Initialize("1361252452329848892", &handlers, 1, nullptr); -void DiscordImpl::Pause() { -Discord_ClearPresence(); -} + discord_thread_running = true; + discord_thread = std::thread(&DiscordImpl::ThreadRun, this); + } -void DiscordImpl::UpdateGameStatus(bool use_default) { -const std::string default_text = "Citron Is A Homebrew Emulator For The Nintendo Switch"; -const std::string default_image = "citron_logo"; -const std::string tinfoil_base_url = "https://tinfoil.media/ti/"; -s64 start_time = std::chrono::duration_cast < std::chrono::seconds > ( -std::chrono::system_clock::now().time_since_epoch()) -.count(); -DiscordRichPresence presence {}; + DiscordImpl::~DiscordImpl() { + if (discord_thread_running) { + discord_thread_running = false; + if (discord_thread.joinable()) { + discord_thread.join(); + } + } + Discord_ClearPresence(); + Discord_Shutdown(); + } -// Store the URL string to prevent it from being destroyed -if (!game_title_id.empty()) { -game_url = fmt::format("{}{}/256/256", tinfoil_base_url, game_title_id); -// Make sure the string stays alive for the duration of the presence -cached_url = game_url; -presence.largeImageKey = cached_url.c_str(); -} else { -presence.largeImageKey = cached_url.c_str(); -} + void DiscordImpl::Pause() { + Discord_ClearPresence(); + } -presence.largeImageText = game_title.c_str(); -presence.smallImageKey = default_image.c_str(); -presence.smallImageText = default_text.c_str(); -// Remove title ID from display, only show game title -presence.state = game_title.c_str(); -presence.details = "Currently in game"; -presence.startTimestamp = start_time; -Discord_UpdatePresence( & presence); -} + void DiscordImpl::UpdateGameStatus(bool use_default) { + const std::string default_text = "Citron Is A Homebrew Emulator For The Nintendo Switch"; + const std::string default_image = "citron_logo"; + s64 start_time = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + DiscordRichPresence presence{}; -void DiscordImpl::Update() { -const std::string default_text = "Citron Is A Homebrew Emulator For The Nintendo Switch"; -const std::string default_image = "citron_logo"; + if (!use_default && !game_title_id.empty()) { + game_url = fmt::format("{}{}/256/256", "https://tinfoil.media/ti/", game_title_id); + cached_url = game_url; + presence.largeImageKey = cached_url.c_str(); + } else { + presence.largeImageKey = default_image.c_str(); + } -if (system.IsPoweredOn()) { -system.GetAppLoader().ReadTitle(game_title); -system.GetAppLoader().ReadProgramId(program_id); -game_title_id = fmt::format("{:016X}", program_id); + presence.largeImageText = game_title.c_str(); + presence.smallImageKey = default_image.c_str(); + presence.smallImageText = default_text.c_str(); + presence.details = game_title.c_str(); + presence.state = "Currently in game"; + presence.startTimestamp = start_time; + Discord_UpdatePresence(&presence); + } -fmt::print("Title ID: {}\n", game_title_id); + void DiscordImpl::Update() { + const std::string default_text = "Citron Is A Homebrew Emulator For The Nintendo Switch"; + const std::string default_image = "citron_logo"; -QNetworkAccessManager manager; -QNetworkRequest request; -request.setUrl(QUrl(QString::fromStdString( -fmt::format("https://tinfoil.media/ti/{}/256/256", game_title_id)))); -request.setTransferTimeout(10000); -QNetworkReply * reply = manager.head(request); -QEventLoop request_event_loop; -QObject::connect(reply, & QNetworkReply::finished, & request_event_loop, & QEventLoop::quit); -request_event_loop.exec(); + if (system.IsPoweredOn()) { + system.GetAppLoader().ReadTitle(game_title); + system.GetAppLoader().ReadProgramId(program_id); + game_title_id = fmt::format("{:016X}", program_id); -if (reply -> error()) { -fmt::print("Failed to fetch game image: {} ({})\n", reply -> errorString().toStdString(), -program_id); -} + QNetworkAccessManager manager; + QNetworkRequest request; + request.setUrl(QUrl(QString::fromStdString( + fmt::format("https://tinfoil.media/ti/{}/256/256", game_title_id)))); + request.setTransferTimeout(5000); // 5 second timeout + QNetworkReply* reply = manager.head(request); + QEventLoop request_event_loop; + QObject::connect(reply, &QNetworkReply::finished, &request_event_loop, &QEventLoop::quit); + request_event_loop.exec(); -UpdateGameStatus(reply -> error()); -reply -> deleteLater(); -return; -} + UpdateGameStatus(reply->error() != QNetworkReply::NoError); + reply->deleteLater(); + } else { + s64 start_time = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + DiscordRichPresence presence{}; + presence.largeImageKey = default_image.c_str(); + presence.largeImageText = default_text.c_str(); + presence.details = "Currently not in game"; + presence.startTimestamp = start_time; + Discord_UpdatePresence(&presence); + } + } -s64 start_time = std::chrono::duration_cast < std::chrono::seconds > ( -std::chrono::system_clock::now().time_since_epoch()) -.count(); + void DiscordImpl::ThreadRun() { + while (discord_thread_running) { + Update(); // This is the line that was likely missing. + Discord_RunCallbacks(); + std::this_thread::sleep_for(std::chrono::seconds(15)); + } + } -DiscordRichPresence presence {}; -presence.largeImageKey = default_image.c_str(); -presence.largeImageText = default_text.c_str(); -presence.details = "Currently not in game"; -presence.startTimestamp = start_time; -Discord_UpdatePresence( & presence); -} } // namespace DiscordRPC