[Application] Add discord integration shenanigans

Took 21 seconds

Took 16 seconds
This commit is contained in:
Lukas Brübach 2026-04-04 15:37:08 +02:00
parent 3e5124f0c0
commit 094c817206
6 changed files with 180 additions and 1 deletions

View file

@ -325,6 +325,10 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h
src/client/network/integrations/discord_social_manager.cpp
src/client/network/integrations/discord_social_manager.h
src/client/network/integrations/discord_social_client.cpp
src/client/network/integrations/discord_social_client.h
src/single_instance_manager.cpp
src/single_instance_manager.h
)
@ -337,6 +341,12 @@ configure_file(
set(cockatrice_RESOURCES cockatrice.qrc)
# Define some handy Discord Social SDK variables
set(DISCORD_SDK_ROOT "${CMAKE_SOURCE_DIR}/external/discord_social_sdk")
set(DISCORD_SDK_LIB_DIR "${DISCORD_SDK_ROOT}/lib/release")
set(DISCORD_SDK_BIN_DIR "${DISCORD_SDK_ROOT}/bin/release")
set(DISCORD_SDK_INCLUDE_DIR "${DISCORD_SDK_ROOT}/include")
if(UPDATE_TRANSLATIONS)
# Cockatrice main sources
file(GLOB_RECURSE translate_cockatrice_SRCS ${CMAKE_SOURCE_DIR}/cockatrice/src/*.cpp
@ -427,6 +437,19 @@ elseif(Qt5_FOUND)
endif()
endif()
target_include_directories(cockatrice PRIVATE ${DISCORD_SDK_INCLUDE_DIR})
if(WIN32)
set(DISCORD_LIB_PATH "${DISCORD_SDK_LIB_DIR}/discord_partner_sdk.lib")
set(DISCORD_SHARED_LIB "${DISCORD_SDK_BIN_DIR}/discord_partner_sdk.dll")
elseif(APPLE)
set(DISCORD_LIB_PATH "${DISCORD_SDK_LIB_DIR}/libdiscord_partner_sdk.dylib")
set(DISCORD_SHARED_LIB "${DISCORD_SDK_LIB_DIR}/libdiscord_partner_sdk.dylib")
else() # Linux
set(DISCORD_LIB_PATH "${DISCORD_SDK_LIB_DIR}/libdiscord_partner_sdk.so")
set(DISCORD_SHARED_LIB "${DISCORD_SDK_LIB_DIR}/libdiscord_partner_sdk.so")
endif()
if(Qt5_FOUND)
target_link_libraries(
cockatrice
@ -439,6 +462,7 @@ if(Qt5_FOUND)
libcockatrice_rng
libcockatrice_settings
${COCKATRICE_QT_MODULES}
${DISCORD_LIB_PATH}
)
else()
target_link_libraries(
@ -452,9 +476,27 @@ else()
libcockatrice_rng
libcockatrice_settings
${COCKATRICE_QT_MODULES}
${DISCORD_LIB_PATH}
)
endif()
if(UNIX)
# Use RPATH when building
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# Set the RPATH to use the lib directory relative to the executable
set(CMAKE_INSTALL_RPATH "$ORIGIN")
if(APPLE)
set(CMAKE_INSTALL_RPATH "@executable_path")
endif()
endif()
# Copy Social SDK shared library to output directory, so it's available at runtime.
add_custom_command(
TARGET cockatrice
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${DISCORD_SHARED_LIB}" $<TARGET_FILE_DIR:cockatrice>
)
if(UNIX)
if(APPLE)
set(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME}")

View file

@ -0,0 +1,90 @@
#include "discord_social_client.h"
#define DISCORDPP_IMPLEMENTATION
#include "discordpp.h"
#include <QDebug>
#include <QTimer>
const uint64_t APPLICATION_ID = 1489873419875913832;
DiscordSocialClient::DiscordSocialClient(QObject *parent)
{
Q_UNUSED(parent);
auto client = std::make_shared<discordpp::Client>();
client->AddLogCallback(
[](auto message, auto severity) { qInfo() << "[" << EnumToString(severity) << "] " << message; },
discordpp::LoggingSeverity::Info);
client->SetStatusChangedCallback(
[client](discordpp::Client::Status status, discordpp::Client::Error error, int32_t errorDetail) {
qInfo() << "🔄 Status changed: " << discordpp::Client::StatusToString(status);
if (status == discordpp::Client::Status::Ready) {
qInfo() << "✅ Client is ready! You can now call SDK functions.\n";
qInfo() << "👥 Friends Count: " << client->GetRelationships().size();
// Configure rich presence details
discordpp::Activity activity;
activity.SetType(discordpp::ActivityTypes::Playing);
activity.SetState("Coding features");
activity.SetDetails("Working on integrating Discord");
// Update rich presence
client->UpdateRichPresence(activity, [](discordpp::ClientResult result) {
if (result.Successful()) {
qInfo() << "🎮 Rich Presence updated successfully!\n";
} else {
qInfo() << "❌ Rich Presence update failed";
}
});
} else if (error != discordpp::Client::Error::None) {
qInfo() << "❌ Connection Error: " << discordpp::Client::ErrorToString(error)
<< " - Details: " << errorDetail;
}
});
// Generate OAuth2 code verifier for authentication
auto codeVerifier = client->CreateAuthorizationCodeVerifier();
// Set up authentication arguments
discordpp::AuthorizationArgs args{};
args.SetClientId(APPLICATION_ID);
args.SetScopes(discordpp::Client::GetDefaultPresenceScopes());
args.SetCodeChallenge(codeVerifier.Challenge());
// Begin authentication process
client->Authorize(args, [client, codeVerifier](auto result, auto code, auto redirectUri) {
if (!result.Successful()) {
qInfo() << "❌ Authentication Error: " << result.Error();
return;
} else {
qInfo() << "✅ Authorization successful! Getting access token...\n";
// Exchange auth code for access token
client->GetToken(APPLICATION_ID, code, codeVerifier.Verifier(), redirectUri,
[client](discordpp::ClientResult result, std::string accessToken, std::string refreshToken,
discordpp::AuthorizationTokenType tokenType, int32_t expiresIn,
std::string scope) {
Q_UNUSED(result);
Q_UNUSED(expiresIn);
Q_UNUSED(refreshToken);
Q_UNUSED(tokenType);
Q_UNUSED(scope);
qInfo() << "🔓 Access token received! Establishing connection...\n";
client->UpdateToken(discordpp::AuthorizationTokenType::Bearer, accessToken,
[client](discordpp::ClientResult result) {
if (result.Successful()) {
qInfo() << "🔑 Token updated, connecting to Discord...\n";
client->Connect();
}
});
});
}
});
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, []() { discordpp::RunCallbacks(); });
timer->start(10);
}

View file

@ -0,0 +1,13 @@
#ifndef COCKATRICE_DISCORD_SOCIAL_CLIENT_H
#define COCKATRICE_DISCORD_SOCIAL_CLIENT_H
#include "discordpp.h"
#include <QObject>
class DiscordSocialClient : public QObject
{
public:
DiscordSocialClient(QObject *parent = nullptr);
};
#endif // COCKATRICE_DISCORD_SOCIAL_CLIENT_H

View file

@ -0,0 +1,7 @@
#include "discord_social_manager.h"
DiscordSocialClient *DiscordSocialManager::getInstance()
{
static DiscordSocialClient instance(nullptr);
return &instance;
}

View file

@ -0,0 +1,24 @@
#ifndef COCKATRICE_DISCORD_SOCIAL_MANAGER_H
#define COCKATRICE_DISCORD_SOCIAL_MANAGER_H
#include "discord_social_client.h"
class DiscordSocialManager
{
public:
DiscordSocialManager(const DiscordSocialManager &) = delete;
DiscordSocialManager &operator=(const DiscordSocialManager &) = delete;
/**
* @brief Returns the singleton CardDatabase instance.
* @return Pointer to the global CardDatabase.
*/
static DiscordSocialClient *getInstance();
private:
DiscordSocialManager() = default;
~DiscordSocialManager() = default;
};
#endif // COCKATRICE_DISCORD_SOCIAL_MANAGER_H

View file

@ -24,6 +24,7 @@
#include "client/settings/cache_settings.h"
#include "client/sound_engine.h"
#include "database/interface/settings_card_preference_provider.h"
#include "integrations/discord_social_manager.h"
#include "interface/logger.h"
#include "interface/pixel_map_generator.h"
#include "interface/theme_manager.h"
@ -258,6 +259,8 @@ int main(int argc, char *argv[])
CardDatabaseManager::setCardDatabasePathProvider(&SettingsCache::instance());
CardDatabaseManager::setCardSetPriorityController(SettingsCache::instance().cardDatabase());
DiscordSocialManager::getInstance();
qCInfo(MainLog) << "Starting main program";
MainWindow ui;
@ -348,5 +351,5 @@ int main(int argc, char *argv[])
CountryPixmapGenerator::clear();
UserLevelPixmapGenerator::clear();
return 0;
return ret;
}