From 9f82b907f2f7d57580e17cef89bbd08be90f94fb Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 5 Dec 2025 16:29:04 +0200 Subject: #3612 "Copy SLURL" from Favorites bar not working If region isn't online, can't get region position and form slurl --- indra/newview/llfavoritesbar.cpp | 7 +++++++ indra/newview/skins/default/xui/en/menu_favorites.xml | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 377710c170..acffc856bc 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1395,6 +1395,13 @@ bool LLFavoritesBarCtrl::enableSelected(const LLSD& userdata) { return !LLAgentPicksInfo::getInstance()->isPickLimitReached(); } + else if (param == "copy_slurl" + || param == "show_on_map") + { + LLVector3d posGlobal; + LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); + return !posGlobal.isExactlyZero(); + } return false; } diff --git a/indra/newview/skins/default/xui/en/menu_favorites.xml b/indra/newview/skins/default/xui/en/menu_favorites.xml index 6345394b46..f82f705fb7 100644 --- a/indra/newview/skins/default/xui/en/menu_favorites.xml +++ b/indra/newview/skins/default/xui/en/menu_favorites.xml @@ -35,6 +35,9 @@ + + Date: Fri, 5 Dec 2025 18:01:28 +0200 Subject: #5109 LLExperienceCache crashes on a coroutine --- indra/llmessage/llexperiencecache.cpp | 33 ++++++++++++++++++++------------- indra/llmessage/llexperiencecache.h | 4 ++-- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 149741b9f9..e4c7deb1c5 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -112,9 +112,7 @@ void LLExperienceCache::initSingleton() constexpr size_t CORO_QUEUE_SIZE = 2048; LLCoprocedureManager::instance().initializePool("ExpCache", CORO_QUEUE_SIZE); - LLCoros::instance().launch("LLExperienceCache::idleCoro", - boost::bind(&LLExperienceCache::idleCoro, this)); - + LLCoros::instance().launch("LLExperienceCache::idleCoro", LLExperienceCache::idleCoro); } void LLExperienceCache::cleanup() @@ -246,6 +244,7 @@ const LLExperienceCache::cache_t& LLExperienceCache::getCached() return mCache; } +// static because used by coroutine and can outlive the instance void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, std::string url, RequestQueue_t requests) { LLCore::HttpRequest::ptr_t httpRequest = std::make_shared(); @@ -254,6 +253,13 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + if (sShutdown) + { + return; + } + + LLExperienceCache* self = LLExperienceCache::getInstance(); + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); @@ -265,7 +271,7 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap // build dummy entries for the failed requests for (RequestQueue_t::const_iterator it = requests.begin(); it != requests.end(); ++it) { - LLSD exp = get(*it); + LLSD exp = self->get(*it); //leave the properties alone if we already have a cache entry for this xp if (exp.isUndefined()) { @@ -278,7 +284,7 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap exp["error"] = (LLSD::Integer)status.getType(); exp[QUOTA] = DEFAULT_QUOTA; - processExperience(*it, exp); + self->processExperience(*it, exp); } return; } @@ -294,7 +300,7 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap LL_DEBUGS("ExperienceCache") << "Received result for " << public_key << " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL; - processExperience(public_key, row); + self->processExperience(public_key, row); } LLSD error_ids = result["error_ids"]; @@ -310,7 +316,7 @@ void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdap exp[MISSING] = true; exp[QUOTA] = DEFAULT_QUOTA; - processExperience(id, exp); + self->processExperience(id, exp); LL_WARNS("ExperienceCache") << "LLExperienceResponder::result() error result for " << id << LL_ENDL; } @@ -361,7 +367,7 @@ void LLExperienceCache::requestExperiences() if (mRequestQueue.empty() || (ostr.tellp() > EXP_URL_SEND_THRESHOLD)) { // request is placed in the coprocedure pool for the ExpCache cache. Throttling is done by the pool itself. LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "RequestExperiences", - boost::bind(&LLExperienceCache::requestExperiencesCoro, this, _1, ostr.str(), requests) ); + boost::bind(&LLExperienceCache::requestExperiencesCoro, _1, ostr.str(), requests) ); ostr.str(std::string()); ostr << urlBase << "?page_size=" << PAGE_SIZE1; @@ -393,7 +399,7 @@ void LLExperienceCache::setCapabilityQuery(LLExperienceCache::CapabilityQuery_t mCapability = queryfn; } - +// static, because coro can outlive the instance void LLExperienceCache::idleCoro() { const F32 SECS_BETWEEN_REQUESTS = 0.5f; @@ -402,14 +408,15 @@ void LLExperienceCache::idleCoro() LL_INFOS("ExperienceCache") << "Launching Experience cache idle coro." << LL_ENDL; do { - if (mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT)) + LLExperienceCache* self = LLExperienceCache::getInstance(); + if (self->mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT)) { - eraseExpired(); + self->eraseExpired(); } - if (!mRequestQueue.empty()) + if (!self->mRequestQueue.empty()) { - requestExperiences(); + self->requestExperiences(); } llcoro::suspendUntilTimeout(SECS_BETWEEN_REQUESTS); diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h index 4b344347d5..9ecdb9efca 100644 --- a/indra/llmessage/llexperiencecache.h +++ b/indra/llmessage/llexperiencecache.h @@ -144,9 +144,9 @@ private: std::string mCacheFileName; static bool sShutdown; // control for coroutines, they exist out of LLExperienceCache's scope, so they need a static control - void idleCoro(); + static void idleCoro(); void eraseExpired(); - void requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, RequestQueue_t); + static void requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, RequestQueue_t); void requestExperiences(); void fetchAssociatedExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLUUID, LLUUID, std::string, ExperienceGetFn_t); -- cgit v1.3 From 3fd68bcc8290f2ce156ea8414983e51d2ef74e33 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 5 Dec 2025 18:07:16 +0200 Subject: #4931 Fix missed name cache connection #2 --- indra/newview/llpanelplaceprofile.cpp | 4 ++-- indra/newview/llpanelplaceprofile.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp index 87f05f2028..c380b6860f 100644 --- a/indra/newview/llpanelplaceprofile.cpp +++ b/indra/newview/llpanelplaceprofile.cpp @@ -517,7 +517,7 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel, std::string parcel_owner = LLSLURL("agent", parcel->getOwnerID(), "inspect").getSLURLString(); mParcelOwner->setText(parcel_owner); - LLAvatarNameCache::get(region->getOwner(), boost::bind(&LLPanelPlaceInfo::onAvatarNameCache, _1, _2, mRegionOwnerText)); + mAvatarNameCacheConnection = LLAvatarNameCache::get(region->getOwner(), boost::bind(&LLPanelPlaceInfo::onAvatarNameCache, _1, _2, mRegionOwnerText)); mRegionGroupText->setText( getString("none_text")); } @@ -548,7 +548,7 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel, const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID(); if(auth_buyer_id.notNull()) { - LLAvatarNameCache::get(auth_buyer_id, boost::bind(&LLPanelPlaceInfo::onAvatarNameCache, _1, _2, mSaleToText)); + mAvatarNameCacheConnection = LLAvatarNameCache::get(auth_buyer_id, boost::bind(&LLPanelPlaceInfo::onAvatarNameCache, _1, _2, mSaleToText)); // Show sales info to a specific person or a group he belongs to. if (auth_buyer_id != gAgent.getID() && !gAgent.isInGroup(auth_buyer_id)) diff --git a/indra/newview/llpanelplaceprofile.h b/indra/newview/llpanelplaceprofile.h index f562be0f5d..0c161198f8 100644 --- a/indra/newview/llpanelplaceprofile.h +++ b/indra/newview/llpanelplaceprofile.h @@ -118,6 +118,8 @@ private: LLTextEditor* mResaleText; LLTextBox* mSaleToText; LLAccordionCtrl* mAccordionCtrl; + + boost::signals2::scoped_connection mAvatarNameCacheConnection; }; #endif // LL_LLPANELPLACEPROFILE_H -- cgit v1.3 From 49c73ac7297ec7760a00bf36fa6339f2d0be1f95 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Mon, 8 Dec 2025 12:21:25 +0200 Subject: #3612 "Copy SLURL" from Favorites bar not working #2 --- indra/newview/llfavoritesbar.cpp | 35 ++++++++++++++++++---- .../newview/skins/default/xui/en/notifications.xml | 11 +++++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index acffc856bc..98b3ca820b 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1398,9 +1398,15 @@ bool LLFavoritesBarCtrl::enableSelected(const LLSD& userdata) else if (param == "copy_slurl" || param == "show_on_map") { - LLVector3d posGlobal; - LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); - return !posGlobal.isExactlyZero(); + LLViewerInventoryItem* item = gInventory.getItem(mSelectedItemID); + if (nullptr == item) + return false; // shouldn't happen as it is selected from existing items + + const LLUUID& asset_id = item->getAssetUUID(); + + // Favorites are supposed to be loaded first, it should be here already + LLLandmark* landmark = gLandmarkList.getAsset(asset_id, NULL /*callback*/); + return nullptr != landmark; } return false; @@ -1432,10 +1438,17 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) LLVector3d posGlobal; LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); + // inventory item and asset exist, otherwise + // enableSelected wouldn't have let it get here, + // only need to check location validity if (!posGlobal.isExactlyZero()) { LLLandmarkActions::getSLURLfromPosGlobal(posGlobal, copy_slurl_to_clipboard_cb); } + else + { + LLNotificationsUtil::add("LandmarkLocationUnknown"); + } } else if (action == "show_on_map") { @@ -1444,10 +1457,20 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) LLVector3d posGlobal; LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); - if (!posGlobal.isExactlyZero() && worldmap_instance) + if (worldmap_instance) { - worldmap_instance->trackLocation(posGlobal); - LLFloaterReg::showInstance("world_map", "center"); + // inventory item and asset exist, otherwise + // enableSelected wouldn't have let it get here, + // only need to check location validity + if (!posGlobal.isExactlyZero()) + { + worldmap_instance->trackLocation(posGlobal); + LLFloaterReg::showInstance("world_map", "center"); + } + else + { + LLNotificationsUtil::add("LandmarkLocationUnknown"); + } } } else if (action == "create_pick") diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index dbd513afe8..d0261a930c 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2465,6 +2465,17 @@ You already have a landmark for this location. fail + +Viewer wasn't able to get region's location. Region might be temporarily unavailable or was removed. + + fail + + Date: Mon, 8 Dec 2025 21:15:04 +0200 Subject: #4604 Tweak LLImageBase's 'out of memory' handling --- indra/llimage/llimage.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index ca8a4199e8..35bc7065b1 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -709,8 +709,20 @@ U8* LLImageBase::allocateData(S32 size) mData = (U8*)ll_aligned_malloc_16(size); if (!mData) { - LL_WARNS() << "Failed to allocate image data size [" << size << "]" << LL_ENDL; - mBadBufferAllocation = true; + constexpr S32 MAX_TOLERANCE = 1024 * 1024 * 4; // 4 MB + if (size > MAX_TOLERANCE) + { + // If a big image failed to allocate, tollerate it for now. + // It's insightfull when crash logs without obvious cause are being analyzed, + // so a crash in a random location that normally is a mystery can get proper handling. + LL_WARNS() << "Failed to allocate image data size [" << size << "]" << LL_ENDL; + } + else + { + // We are too far gone if we can't allocate a small buffer. + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS() << "Failed to allocate image data size [" << size << "]" << LL_ENDL; + } } } -- cgit v1.3 From 058ee5c66f850b01c255aa7b1de6342a6bf00c47 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Wed, 10 Dec 2025 20:50:58 +0200 Subject: #5122 update version format --- indra/newview/VIEWER_VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 4703009f54..4df38dcc24 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -2026.01.0 +2026.1.0 -- cgit v1.3