summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llimage/llimage.cpp16
-rw-r--r--indra/llmessage/llexperiencecache.cpp33
-rw-r--r--indra/llmessage/llexperiencecache.h4
-rw-r--r--indra/newview/VIEWER_VERSION.txt2
-rw-r--r--indra/newview/llfavoritesbar.cpp36
-rw-r--r--indra/newview/llpanelplaceprofile.cpp4
-rw-r--r--indra/newview/llpanelplaceprofile.h2
-rw-r--r--indra/newview/skins/default/xui/en/menu_favorites.xml6
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml11
9 files changed, 91 insertions, 23 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;
+ }
}
}
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<LLCore::HttpRequest>();
@@ -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);
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
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index 377710c170..98b3ca820b 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -1395,6 +1395,19 @@ bool LLFavoritesBarCtrl::enableSelected(const LLSD& userdata)
{
return !LLAgentPicksInfo::getInstance()->isPickLimitReached();
}
+ else if (param == "copy_slurl"
+ || param == "show_on_map")
+ {
+ 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;
}
@@ -1425,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")
{
@@ -1437,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/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
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 @@
<menu_item_call.on_click
function="Favorites.DoToSelected"
parameter="show_on_map" />
+ <menu_item_call.on_enable
+ function="Favorites.EnableSelected"
+ parameter="show_on_map" />
</menu_item_call>
<menu_item_call
label="Copy SLurl"
@@ -43,6 +46,9 @@
<menu_item_call.on_click
function="Favorites.DoToSelected"
parameter="copy_slurl" />
+ <menu_item_call.on_enable
+ function="Favorites.EnableSelected"
+ parameter="copy_slurl" />
</menu_item_call>
<menu_item_call
label="Create Pick"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 5b9144e535..0ac6cb8268 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -2466,6 +2466,17 @@ You already have a landmark for this location.
</notification>
<notification
+ icon="alert.tga"
+ name="LandmarkLocationUnknown"
+ type="alert">
+Viewer wasn't able to get region's location. Region might be temporarily unavailable or was removed.
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ <tag>fail</tag>
+ </notification>
+
+ <notification
icon="alertmodal.tga"
name="CannotCreateLandmarkNotOwner"
type="alertmodal">