diff options
-rw-r--r-- | indra/cmake/CMakeLists.txt | 1 | ||||
-rw-r--r-- | indra/cmake/Discord.cmake | 9 | ||||
-rw-r--r-- | indra/newview/CMakeLists.txt | 7 | ||||
-rw-r--r-- | indra/newview/app_settings/settings.xml | 33 | ||||
-rw-r--r-- | indra/newview/llappviewer.cpp | 194 | ||||
-rw-r--r-- | indra/newview/llappviewer.h | 8 | ||||
-rw-r--r-- | indra/newview/llfloaterpreference.cpp | 5 | ||||
-rw-r--r-- | indra/newview/llpanelpeople.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llspeakers.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llstartup.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llviewermessage.cpp | 5 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/panel_preferences_privacy.xml | 69 |
12 files changed, 339 insertions, 4 deletions
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index cc217b0563..0a00ccbb5b 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -20,6 +20,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..2193023a06 --- /dev/null +++ b/indra/cmake/Discord.cmake @@ -0,0 +1,9 @@ +include(Prebuilt) + +add_library(ll::discord INTERFACE IMPORTED) +target_compile_definitions(ll::discord INTERFACE LL_DISCORD=1) + +use_prebuilt_binary(discord) + +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 1672efcf33..7cc26c7716 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) @@ -1995,6 +1998,10 @@ target_link_libraries(${VIEWER_BINARY_NAME} ll::openxr ) +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/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index fc878653e4..b9e3ebf502 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1139,6 +1139,39 @@ <key>Value</key> <integer>1</integer> </map> + <key>EnableDiscord</key> + <map> + <key>Comment</key> + <string>When set, connect to Discord to enable Rich Presence</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>ShowDiscordActivityDetails</key> + <map> + <key>Comment</key> + <string>When set, show avatar name on Discord Rich Presence</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>ShowDiscordActivityState</key> + <map> + <key>Comment</key> + <string>When set, show location on Discord Rich Presence</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>EnableDiskCacheDebugInfo</key> <map> <key>Comment</key> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a896b210f4..a5535d4bcc 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -268,6 +268,16 @@ using namespace LL; #include "glib.h" #endif // (LL_LINUX) && LL_GTK +#ifdef LL_DISCORD +#define DISCORDPP_IMPLEMENTATION +#include <discordpp.h> +static std::shared_ptr<discordpp::Client> gDiscordClient; +static uint64_t gDiscordTimestampsStart; +static std::string gDiscordActivityDetails; +static int32_t gDiscordPartyCurrentSize; +static int32_t gDiscordPartyMaxSize; +#endif + static LLAppViewerListener sAppViewerListener(LLAppViewer::instance); ////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor @@ -1319,6 +1329,13 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { +#ifdef LL_DISCORD + { + LL_PROFILE_ZONE_NAMED("discord_callbacks"); + discordpp::RunCallbacks(); + } +#endif + LL_RECORD_BLOCK_TIME(FTM_FRAME); { // and now adjust the visuals from previous frame. @@ -5862,3 +5879,180 @@ void LLAppViewer::metricsSend(bool enable_reporting) gViewerAssetStats->restart(); } +#ifdef LL_DISCORD + +void LLAppViewer::initDiscordSocial() +{ + gDiscordPartyCurrentSize = 1; + gDiscordPartyMaxSize = 0; + gDiscordTimestampsStart = time(nullptr); + gDiscordClient = std::make_shared<discordpp::Client>(); + gDiscordClient->SetStatusChangedCallback([](discordpp::Client::Status status, discordpp::Client::Error, int32_t) { + if (status == discordpp::Client::Status::Ready) + { + updateDiscordActivity(); + } + }); + if (gSavedSettings.getBOOL("EnableDiscord")) + { + auto credential = gSecAPIHandler->loadCredential("Discord"); + if (credential.notNull()) + { + gDiscordClient->UpdateToken(discordpp::AuthorizationTokenType::Bearer, credential->getAuthenticator()["token"].asString(), [](discordpp::ClientResult result) { + if (result.Successful()) + gDiscordClient->Connect(); + else + LL_WARNS("Discord") << result.Error() << LL_ENDL; + }); + } + else + { + LL_WARNS("Discord") << "Integration was enabled, but no credentials. Disabling integration." << LL_ENDL; + gSavedSettings.setBOOL("EnableDiscord", false); + } + } +} + +void LLAppViewer::toggleDiscordIntegration(const LLSD& value) +{ + static const uint64_t APPLICATION_ID = 1394782217405862001; + if (value.asBoolean()) + { + discordpp::AuthorizationArgs args{}; + args.SetClientId(APPLICATION_ID); + args.SetScopes(discordpp::Client::GetDefaultPresenceScopes()); + auto codeVerifier = gDiscordClient->CreateAuthorizationCodeVerifier(); + args.SetCodeChallenge(codeVerifier.Challenge()); + gDiscordClient->Authorize(args, [codeVerifier](auto result, auto code, auto redirectUri) { + if (result.Successful()) + { + gDiscordClient->GetToken(APPLICATION_ID, code, codeVerifier.Verifier(), redirectUri, [](discordpp::ClientResult result, std::string accessToken, std::string, discordpp::AuthorizationTokenType, int32_t, std::string) { + if (result.Successful()) + { + gDiscordClient->UpdateToken(discordpp::AuthorizationTokenType::Bearer, accessToken, [accessToken](discordpp::ClientResult result) { + if (result.Successful()) + { + LLSD authenticator = LLSD::emptyMap(); + authenticator["token"] = accessToken; + gSecAPIHandler->saveCredential(gSecAPIHandler->createCredential("Discord", LLSD::emptyMap(), authenticator), true); + gDiscordClient->Connect(); + } + else + { + LL_WARNS("Discord") << result.Error() << LL_ENDL; + } + }); + } + else + { + LL_WARNS("Discord") << result.Error() << LL_ENDL; + } + }); + } + else + { + LL_WARNS("Discord") << result.Error() << LL_ENDL; + gSavedSettings.setBOOL("EnableDiscord", false); + } + }); + } + else + { + gDiscordClient->Disconnect(); + auto credential = gSecAPIHandler->loadCredential("Discord"); + if (credential.notNull()) + { + gDiscordClient->RevokeToken(APPLICATION_ID, credential->getAuthenticator()["token"].asString(), [](discordpp::ClientResult result) { + if (result.Successful()) + LL_INFOS("Discord") << "Access token successfully revoked." << LL_ENDL; + else + LL_WARNS("Discord") << "No access token to revoke." << LL_ENDL; + }); + auto cred = new LLCredential("Discord"); + gSecAPIHandler->deleteCredential(cred); + } + else + { + LL_WARNS("Discord") << "Credentials are already nonexistent." << LL_ENDL; + } + } +} + +void LLAppViewer::updateDiscordActivity() +{ + LL_PROFILE_ZONE_SCOPED; + discordpp::Activity activity; + activity.SetType(discordpp::ActivityTypes::Playing); + discordpp::ActivityTimestamps timestamps; + timestamps.SetStart(gDiscordTimestampsStart); + activity.SetTimestamps(timestamps); + + if (gAgent.getID() == LLUUID::null) + { + gDiscordClient->UpdateRichPresence(activity, [](discordpp::ClientResult) {}); + return; + } + + static LLCachedControl<bool> show_details(gSavedSettings, "ShowDiscordActivityDetails", false); + if (show_details) + { + if (gDiscordActivityDetails.empty()) + { + LLAvatarName av_name; + LLAvatarNameCache::get(gAgent.getID(), &av_name); + gDiscordActivityDetails = av_name.getUserName(); + auto displayName = av_name.getDisplayName(); + if (gDiscordActivityDetails != displayName) + gDiscordActivityDetails = displayName + " (" + gDiscordActivityDetails + ")"; + } + activity.SetDetails(gDiscordActivityDetails); + } + + static LLCachedControl<bool> show_state(gSavedSettings, "ShowDiscordActivityState", false); + if (show_state) + { + auto agent_pos_region = gAgent.getPositionAgent(); + S32 pos_x = S32(agent_pos_region.mV[VX] + 0.5f); + S32 pos_y = S32(agent_pos_region.mV[VY] + 0.5f); + S32 pos_z = S32(agent_pos_region.mV[VZ] + 0.5f); + F32 velocity_mag_sq = gAgent.getVelocity().magVecSquared(); + const F32 FLY_CUTOFF = 6.f; + const F32 FLY_CUTOFF_SQ = FLY_CUTOFF * FLY_CUTOFF; + const F32 WALK_CUTOFF = 1.5f; + const F32 WALK_CUTOFF_SQ = WALK_CUTOFF * WALK_CUTOFF; + if (velocity_mag_sq > FLY_CUTOFF_SQ) + { + pos_x -= pos_x % 4; + pos_y -= pos_y % 4; + } + else if (velocity_mag_sq > WALK_CUTOFF_SQ) + { + pos_x -= pos_x % 2; + pos_y -= pos_y % 2; + } + auto location = llformat("%s (%d, %d, %d)", gAgent.getRegion()->getName().c_str(), pos_x, pos_y, pos_z); + activity.SetState(location); + + discordpp::ActivityParty party; + party.SetId(location); + party.SetCurrentSize(gDiscordPartyCurrentSize); + party.SetMaxSize(gDiscordPartyMaxSize); + activity.SetParty(party); + } + + gDiscordClient->UpdateRichPresence(activity, [](discordpp::ClientResult) {}); +} + +void LLAppViewer::updateDiscordPartyCurrentSize(int32_t size) +{ + gDiscordPartyCurrentSize = size; + updateDiscordActivity(); +} + +void LLAppViewer::updateDiscordPartyMaxSize(int32_t size) +{ + gDiscordPartyMaxSize = size; + updateDiscordActivity(); +} + +#endif diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index b4b8e5bac3..0424bdd34f 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -250,6 +250,14 @@ public: // Note: mQuitRequested can be aborted by user. void outOfMemorySoftQuit(); +#ifdef LL_DISCORD + static void initDiscordSocial(); + static void toggleDiscordIntegration(const LLSD& value); + static void updateDiscordActivity(); + static void updateDiscordPartyCurrentSize(int32_t size); + static void updateDiscordPartyMaxSize(int32_t size); +#endif + protected: virtual bool initWindow(); // Initialize the viewer's window. virtual void initLoggingAndGetLastDuration(); // Initialize log files, logging system diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index fdac390e8a..2a6360cef8 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -366,6 +366,11 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance())); mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // <FS:ND/> Hook up for filtering +#ifdef LL_DISCORD + gSavedSettings.getControl("EnableDiscord")->getCommitSignal()->connect(boost::bind(&LLAppViewer::toggleDiscordIntegration, _2)); + gSavedSettings.getControl("ShowDiscordActivityDetails")->getCommitSignal()->connect(boost::bind(&LLAppViewer::updateDiscordActivity)); + gSavedSettings.getControl("ShowDiscordActivityState")->getCommitSignal()->connect(boost::bind(&LLAppViewer::updateDiscordActivity)); +#endif } void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType type ) diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 25672db318..5e6f1e6a0a 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -843,6 +843,10 @@ void LLPanelPeople::updateNearbyList() LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); mNearbyList->setDirty(); +#ifdef LL_DISCORD + if (gSavedSettings.getBOOL("EnableDiscord")) + LLAppViewer::updateDiscordPartyMaxSize(mNearbyList->getIDs().size()); +#endif DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs()); LLActiveSpeakerMgr::instance().update(true); diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 4956c188fb..12a9d5e9b7 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -1026,6 +1026,10 @@ void LLLocalSpeakerMgr::updateSpeakerList() uuid_vec_t avatar_ids; std::vector<LLVector3d> positions; LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS); +#ifdef LL_DISCORD + if (gSavedSettings.getBOOL("EnableDiscord")) + LLAppViewer::updateDiscordPartyCurrentSize(avatar_ids.size()); +#endif for(U32 i=0; i<avatar_ids.size(); i++) { setSpeaker(avatar_ids[i]); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index cc4f49c0b4..0a3870b6f9 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -724,6 +724,10 @@ bool idle_startup() LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL; } +#ifdef LL_DISCORD + LLAppViewer::initDiscordSocial(); +#endif + // // Log on to system // diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7b9331e822..44831aea03 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3052,6 +3052,11 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) } } +#ifdef LL_DISCORD + if (gSavedSettings.getBOOL("EnableDiscord")) + LLAppViewer::updateDiscordActivity(); +#endif + if ( LLTracker::isTracking(NULL) ) { // Check distance to beacon, if < 5m, remove beacon diff --git a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml index 96d36a721f..1c00837073 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml @@ -1,15 +1,31 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<panel + <panel border="true" follows="left|top|right|bottom" - height="408" - label="Communication" + height="438" + label="Privacy" layout="topleft" left="102" - name="im" + name="Privacy panel" top="1" width="517"> + <tab_container + top_pad="0" + enabled="true" + follows="left|top" + height="430" + width="517" + left_delta="0" + name="privacy_tab_container" + tab_position="top" + tab_stop="false"> + <panel + label="General" + name="privacy_preferences_general" + layout="topleft" + follows="top|left"> + <panel.string name="log_in_to_change"> log in to change @@ -134,3 +150,48 @@ (People and/or Objects you have blocked) </text> </panel> + + <panel + label="Discord" + name="privacy_preferences_discord" + layout="topleft" + follows="top|left"> + + <check_box + control_name="EnableDiscord" + height="16" + enabled="true" + label="Enable Discord integration" + layout="topleft" + left="30" + name="enable_discord" + top_pad="20" + width="350" /> + + <check_box + enabled_control="EnableDiscord" + control_name="ShowDiscordActivityDetails" + height="16" + enabled="true" + label="Show avatar name" + layout="topleft" + left="30" + name="show_name" + top_pad="20" + width="350" /> + + <check_box + enabled_control="EnableDiscord" + control_name="ShowDiscordActivityState" + height="16" + enabled="false" + label="Show location" + layout="topleft" + left="30" + name="show_location" + top_pad="20" + width="350" /> + </panel> + </tab_container> + +</panel> |