diff options
Diffstat (limited to 'indra/newview/llappviewer.cpp')
-rw-r--r-- | indra/newview/llappviewer.cpp | 265 |
1 files changed, 247 insertions, 18 deletions
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f00301e942..66dadf7545 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 @@ -1334,6 +1344,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. @@ -2260,10 +2277,7 @@ void errorCallback(LLError::ELevel level, const std::string &error_string) // Callback for LLError::LLUserWarningMsg void errorHandler(const std::string& title_string, const std::string& message_string, S32 code) { - if (!message_string.empty()) - { - OSMessageBox(message_string, title_string.empty() ? LLTrans::getString("MBFatalError") : title_string, OSMB_OK); - } + // message is going to hang viewer, create marker first switch (code) { case LLError::LLUserWarningMsg::ERROR_OTHER: @@ -2271,6 +2285,10 @@ void errorHandler(const std::string& title_string, const std::string& message_st break; case LLError::LLUserWarningMsg::ERROR_BAD_ALLOC: LLAppViewer::instance()->createErrorMarker(LAST_EXEC_BAD_ALLOC); + // When system run out of memory and errorHandler gets called from a thread, + // main thread might keep going while OSMessageBox freezes the caller. + // Todo: handle it better, but for now disconnect to avoid making things worse + gDisconnected = true; break; case LLError::LLUserWarningMsg::ERROR_MISSING_FILES: LLAppViewer::instance()->createErrorMarker(LAST_EXEC_MISSING_FILES); @@ -2278,6 +2296,10 @@ void errorHandler(const std::string& title_string, const std::string& message_st default: break; } + if (!message_string.empty()) + { + OSMessageBox(message_string, title_string.empty() ? LLTrans::getString("MBFatalError") : title_string, OSMB_OK); + } } void LLAppViewer::initLoggingAndGetLastDuration() @@ -3103,7 +3125,15 @@ bool LLAppViewer::initWindow() .height(gSavedSettings.getU32("WindowHeight")) .min_width(gSavedSettings.getU32("MinWindowWidth")) .min_height(gSavedSettings.getU32("MinWindowHeight")) +#ifdef LL_DARWIN + // Setting it to true causes black screen with no UI displayed. + // Given that it's a DEBUG settings and application goes fullscreen + // on mac simply by expanding it, it was decided to not support/use + // this setting on mac. + .fullscreen(false) +#else // LL_DARWIN .fullscreen(gSavedSettings.getBOOL("FullScreen")) +#endif .ignore_pixel_depth(ignorePixelDepth) .first_run(mIsFirstRun); @@ -4289,8 +4319,8 @@ bool LLAppViewer::initCache() const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName"); const U32 MB = 1024 * 1024; - const uintmax_t MIN_CACHE_SIZE = 256 * MB; - const uintmax_t MAX_CACHE_SIZE = 9984ll * MB; + const uintmax_t MIN_CACHE_SIZE = 896 * MB; + const uintmax_t MAX_CACHE_SIZE = 32768ll * MB; const uintmax_t setting_cache_total_size = uintmax_t(gSavedSettings.getU32("CacheSize")) * MB; const uintmax_t cache_total_size = llclamp(setting_cache_total_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE); const F64 disk_cache_percent = gSavedSettings.getF32("DiskCachePercentOfTotal"); @@ -5694,9 +5724,31 @@ void LLAppViewer::forceErrorThreadCrash() thread->start(); } -void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs) +void LLAppViewer::forceExceptionThreadCrash() +{ + class LLCrashTestThread : public LLThread + { + public: + + LLCrashTestThread() : LLThread("Crash logging test thread") + { + } + + void run() + { + const std::string exception_text = "This is a deliberate exception in a thread"; + throw std::runtime_error(exception_text); + } + }; + + LL_WARNS() << "This is a deliberate exception in a thread" << LL_ENDL; + LLCrashTestThread* thread = new LLCrashTestThread(); + thread->start(); +} + +void LLAppViewer::initMainloopTimeout(std::string_view state, F32 secs) { - if(!mMainloopTimeout) + if (!mMainloopTimeout) { mMainloopTimeout = new LLWatchdogTimeout(); resumeMainloopTimeout(state, secs); @@ -5705,20 +5757,20 @@ void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs) void LLAppViewer::destroyMainloopTimeout() { - if(mMainloopTimeout) + if (mMainloopTimeout) { delete mMainloopTimeout; - mMainloopTimeout = NULL; + mMainloopTimeout = nullptr; } } -void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs) +void LLAppViewer::resumeMainloopTimeout(std::string_view state, F32 secs) { - if(mMainloopTimeout) + if (mMainloopTimeout) { - if(secs < 0.0f) + if (secs < 0.0f) { - static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); + static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60.f); secs = mainloop_timeout; } @@ -5729,19 +5781,19 @@ void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs) void LLAppViewer::pauseMainloopTimeout() { - if(mMainloopTimeout) + if (mMainloopTimeout) { mMainloopTimeout->stop(); } } -void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs) +void LLAppViewer::pingMainloopTimeout(std::string_view state, F32 secs) { LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; - if(mMainloopTimeout) + if (mMainloopTimeout) { - if(secs < 0.0f) + if (secs < 0.0f) { static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); secs = mainloop_timeout; @@ -5869,3 +5921,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 |