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> | 
