summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Kundiman <erik@megapahit.org>2025-07-12 21:49:15 +0800
committerErik Kundiman <erik@megapahit.org>2025-07-12 21:49:15 +0800
commit74b0178b7b4d672c7f6b317102b0ecd26f1ea033 (patch)
tree64f0f01a6b47b534c42d7f4b085b8724e639937a
parentb1d2961edb593393da5ae88e275be7bb2568969b (diff)
Rich Presence support using Discord Social SDKHEADmain
Download DiscordSocialSdk-1.4.9649.zip https://discord.com/developers/applications/1393451183741599796/social-sdk/downloads to your ~/Downloads folder. Add -DUSE_DISCORD:BOOL=ON to your cmake line. The authorisation is triggered by selecting Help > Discord Social. It seems that the user will need to do this every time they want Rich Presence support on the viewer while using Discord. The Discord app is still set to be a public client in the OAuth2 tab, I'm going to try to make it work with the app set to be a confidential client, next. All Discord-related code are contained within one file, llstartup.cpp, and other classes access it through some opaque layer, static functions, otherwise we'd get these "duplicate symbol" linking errors.
-rw-r--r--indra/cmake/CMakeLists.txt1
-rw-r--r--indra/cmake/Discord.cmake45
-rw-r--r--indra/newview/CMakeLists.txt7
-rw-r--r--indra/newview/FixBundle.cmake.in1
-rw-r--r--indra/newview/FixPackage.cmake.in1
-rw-r--r--indra/newview/ViewerInstall.cmake13
-rw-r--r--indra/newview/llappviewer.cpp4
-rw-r--r--indra/newview/llstartup.cpp45
-rw-r--r--indra/newview/llstartup.h6
-rw-r--r--indra/newview/llviewermenu.cpp10
-rw-r--r--indra/newview/skins/default/xui/en/floater_about.xml2
-rw-r--r--indra/newview/skins/default/xui/en/menu_login.xml7
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml7
13 files changed, 149 insertions, 0 deletions
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 5525ac9f24..a77e0fca06 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -19,6 +19,7 @@ set(cmake_SOURCE_FILES
Copy3rdPartyLibs.cmake
DBusGlib.cmake
DeploySharedLibs.cmake
+ Discord.cmake
DragDrop.cmake
EXPAT.cmake
FindAutobuild.cmake
diff --git a/indra/cmake/Discord.cmake b/indra/cmake/Discord.cmake
new file mode 100644
index 0000000000..52c0765ae7
--- /dev/null
+++ b/indra/cmake/Discord.cmake
@@ -0,0 +1,45 @@
+include(Prebuilt)
+
+add_library(ll::discord INTERFACE IMPORTED)
+target_compile_definitions(ll::discord INTERFACE LL_DISCORD=1)
+
+if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/discord_installed OR NOT ${discord_installed} EQUAL 0)
+ file(ARCHIVE_EXTRACT
+ INPUT $ENV{HOME}/Downloads/DiscordSocialSdk-1.4.9649.zip
+ DESTINATION ${CMAKE_BINARY_DIR}
+ )
+ file(
+ COPY
+ ${CMAKE_BINARY_DIR}/discord_social_sdk/include/cdiscord.h
+ ${CMAKE_BINARY_DIR}/discord_social_sdk/include/discordpp.h
+ DESTINATION ${LIBS_PREBUILT_DIR}/include
+ )
+ if (WINDOWS)
+ file(
+ COPY ${CMAKE_BINARY_DIR}/discord_social_sdk/bin/release/discord_partner_sdk.dll
+ DESTINATION ${LIBS_PREBUILT_DIR}/bin/release
+ )
+ set(LIBRARY_EXTENSION lib)
+ else ()
+ set(LIBRARY_PREFIX lib)
+ set(LIBRARY_EXTENSION so)
+ endif ()
+ if (DARWIN)
+ execute_process(
+ COMMAND lipo
+ libdiscord_partner_sdk.dylib
+ -thin ${CMAKE_OSX_ARCHITECTURES}
+ -output ${ARCH_PREBUILT_DIRS_RELEASE}/libdiscord_partner_sdk.dylib
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/discord_social_sdk/lib/release
+ )
+ else ()
+ file(
+ COPY ${CMAKE_BINARY_DIR}/discord_social_sdk/lib/release/${LIBRARY_PREFIX}discord_partner_sdk.${LIBRARY_EXTENSION}
+ DESTINATION ${ARCH_PREBUILT_DIRS_RELEASE}
+ )
+ endif ()
+ file(WRITE ${PREBUILD_TRACKING_DIR}/discord_installed "0")
+endif ()
+
+target_include_directories(ll::discord SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
+target_link_libraries(ll::discord INTERFACE discord_partner_sdk)
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 5e9a59a0e5..7f509d38de 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -15,6 +15,9 @@ include(CMakeCopyIfDifferent)
include(CubemapToEquirectangularJS)
#include(DBusGlib)
include(DragDrop)
+if (USE_DISCORD)
+ include(Discord)
+endif ()
include(EXPAT)
include(Hunspell)
include(JPEGEncoderBasic)
@@ -2141,6 +2144,10 @@ if (ENABLE_MEDIA_PLUGINS)
endif ()
endif ()
+if (USE_DISCORD)
+ target_link_libraries(${VIEWER_BINARY_NAME} ll::discord )
+endif ()
+
if( TARGET ll::intel_memops )
target_link_libraries(${VIEWER_BINARY_NAME} ll::intel_memops )
endif()
diff --git a/indra/newview/FixBundle.cmake.in b/indra/newview/FixBundle.cmake.in
index 829c19e5e4..1d460a9b45 100644
--- a/indra/newview/FixBundle.cmake.in
+++ b/indra/newview/FixBundle.cmake.in
@@ -293,6 +293,7 @@ execute_process(
Frameworks/libbrotlicommon.1.1.0.dylib
Frameworks/libbrotlidec.1.1.0.dylib
Frameworks/libbz2.1.0.8.dylib
+ Frameworks/libdiscord_partner_sdk.dylib
Frameworks/libexpat.1.10.0.dylib
Frameworks/libfreetype.6.dylib
Frameworks/libhunspell-1.7.0.dylib
diff --git a/indra/newview/FixPackage.cmake.in b/indra/newview/FixPackage.cmake.in
index 49f7b75b4d..23d52a9ef9 100644
--- a/indra/newview/FixPackage.cmake.in
+++ b/indra/newview/FixPackage.cmake.in
@@ -293,6 +293,7 @@ execute_process(
Frameworks/libbrotlicommon.1.1.0.dylib
Frameworks/libbrotlidec.1.1.0.dylib
Frameworks/libbz2.1.0.8.dylib
+ Frameworks/libdiscord_partner_sdk.dylib
Frameworks/libexpat.1.10.0.dylib
Frameworks/libfreetype.6.dylib
Frameworks/libhunspell-1.7.0.dylib
diff --git a/indra/newview/ViewerInstall.cmake b/indra/newview/ViewerInstall.cmake
index 343c3fb9c7..aaa0c21fa5 100644
--- a/indra/newview/ViewerInstall.cmake
+++ b/indra/newview/ViewerInstall.cmake
@@ -169,6 +169,13 @@ elseif (WINDOWS)
DESTINATION .
)
+ if (USE_DISCORD)
+ install(
+ PROGRAMS ${LIBS_PREBUILT_DIR}/bin/release/discord_partner_sdk.dll
+ DESTINATION .
+ )
+ endif ()
+
install(
PROGRAMS
${prefix_result}/../bin/boost_context-vc143-mt-${BOOST_PLATFORM}-1_88.dll
@@ -193,6 +200,12 @@ if (LINUX)
else ()
set(_LIB lib)
endif ()
+ if (USE_DISCORD)
+ install(
+ FILES ${ARCH_PREBUILT_DIRS_RELEASE}/libdiscord_partner_sdk.so
+ DESTINATION ${_LIB}
+ )
+ endif ()
if (USE_FMODSTUDIO)
install(FILES
${ARCH_PREBUILT_DIRS_RELEASE}/libfmod.so
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index d9596164eb..419d2cb842 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1348,6 +1348,10 @@ bool LLAppViewer::doFrame()
U64 fpsLimitSleepFor = 0;
TimePoint fpsLimitFrameStartTime = std::chrono::steady_clock::now();
+#ifdef LL_DISCORD
+ LLStartUp::runDiscordCallbacks();
+#endif
+
LL_RECORD_BLOCK_TIME(FTM_FRAME);
{
// and now adjust the visuals from previous frame.
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 3450792d30..834b99555e 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -217,6 +217,11 @@
#include "fsfloatersearch.h"
+#ifdef LL_DISCORD
+#define DISCORDPP_IMPLEMENTATION
+#include <discordpp.h>
+static std::shared_ptr<discordpp::Client> gDiscordClient;
+#endif
//
// exported globals
@@ -752,6 +757,17 @@ bool idle_startup()
LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL;
}
+#ifdef LL_DISCORD
+ gDiscordClient = std::make_shared<discordpp::Client>();
+ gDiscordClient->SetStatusChangedCallback([](discordpp::Client::Status status, discordpp::Client::Error, int32_t) {
+ if (status == discordpp::Client::Status::Ready) {
+ discordpp::Activity activity;
+ activity.SetType(discordpp::ActivityTypes::Playing);
+ gDiscordClient->UpdateRichPresence(activity, [](discordpp::ClientResult) {});
+ }
+ });
+#endif
+
//
// Log on to system
//
@@ -3431,6 +3447,35 @@ bool LLStartUp::startLLProxy()
return proxy_ok;
}
+#ifdef LL_DISCORD
+
+void LLStartUp::runDiscordCallbacks()
+{
+ discordpp::RunCallbacks();
+}
+
+void LLStartUp::handleDiscordSocial()
+{
+ static const uint64_t DISCORD_APPLICATION_ID = 1393451183741599796;
+ discordpp::AuthorizationArgs discordAuthArgs{};
+ discordAuthArgs.SetClientId(DISCORD_APPLICATION_ID);
+ discordAuthArgs.SetScopes(discordpp::Client::GetDefaultPresenceScopes());
+ auto discordCodeVerifier = gDiscordClient->CreateAuthorizationCodeVerifier();
+ discordAuthArgs.SetCodeChallenge(discordCodeVerifier.Challenge());
+ gDiscordClient->Authorize(discordAuthArgs, [discordCodeVerifier](auto result, auto code, auto redirectUri) {
+ if (result.Successful()) {
+ gDiscordClient->GetToken(DISCORD_APPLICATION_ID, code, discordCodeVerifier.Verifier(), redirectUri, [](discordpp::ClientResult result, std::string accessToken, std::string, discordpp::AuthorizationTokenType, int32_t, std::string) {
+ gDiscordClient->UpdateToken(discordpp::AuthorizationTokenType::Bearer, accessToken, [](discordpp::ClientResult result) {
+ if (result.Successful())
+ gDiscordClient->Connect();
+ });
+ });
+ }
+ });
+}
+
+#endif
+
bool login_alert_done(const LLSD& notification, const LLSD& response)
{
LLPanelLogin::giveFocus();
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index a827fbc487..cf1d38bb18 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -128,6 +128,12 @@ public:
static bool startLLProxy(); // Initialize the SOCKS 5 proxy
static LLViewerStats::PhaseMap& getPhases() { return *sPhases; }
+
+#ifdef LL_DISCORD
+ static void runDiscordCallbacks();
+ static void handleDiscordSocial();
+#endif
+
private:
friend class LLStartupListener;
static LLSLURL sStartSLURL;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index c3bb8ef4c4..4383fc87e5 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -8942,6 +8942,13 @@ void handle_report_bug(const LLSD& param)
LLWeb::loadURLExternal(url);
}
+#ifdef LL_DISCORD
+void handle_discord_social(const LLSD& param)
+{
+ LLStartUp::handleDiscordSocial();
+}
+#endif
+
void handle_buy_currency_test()
{
std::string url =
@@ -9920,6 +9927,9 @@ void initialize_menus()
commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater
commit.add("Advanced.ShowURL", boost::bind(&handle_show_url, _2));
commit.add("Advanced.ReportBug", boost::bind(&handle_report_bug, _2));
+#ifdef LL_DISCORD
+ commit.add("Advanced.DiscordSocial", boost::bind(&handle_discord_social, _2));
+#endif
view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest");
view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr");
view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory");
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index a251b3c5c5..8b92b83472 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -206,6 +206,8 @@ Collada DOM Copyright 2006 Sony Computer Entertainment Inc.
cURL Copyright (C) 1996-2010, Daniel Stenberg, (daniel@haxx.se)
+Discord Social SDK Copyright (c) 2025, Discord, Inc.
+
expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml
index 5fff9b7bc0..04514e8a52 100644
--- a/indra/newview/skins/default/xui/en/menu_login.xml
+++ b/indra/newview/skins/default/xui/en/menu_login.xml
@@ -110,6 +110,13 @@
</menu_item_call>
<menu_item_separator/>
<menu_item_call
+ label="Discord Social"
+ name="Discord Social">
+ <menu_item_call.on_click
+ function="Advanced.DiscordSocial"/>
+ </menu_item_call>
+ <menu_item_separator/>
+ <menu_item_call
label="About [APP_NAME]"
name="About Second Life">
<menu_item_call.on_click
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 1ec59bf2eb..56261ce874 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1818,6 +1818,13 @@ function="World.EnvPreset"
</menu_item_call>
<menu_item_separator/>
+ <menu_item_call
+ label="Discord Social"
+ name="Discord Social">
+ <menu_item_call.on_click
+ function="Advanced.DiscordSocial"/>
+ </menu_item_call>
+ <menu_item_separator/>
<menu_item_call
label="Bumps, Pushes &amp; Hits"
name="Bumps, Pushes &amp;amp; Hits">