summaryrefslogtreecommitdiff
path: root/indra/newview/llappearancemgr.cpp
diff options
context:
space:
mode:
authorErik Kundiman <erik@megapahit.org>2026-06-13 14:20:22 +0800
committerErik Kundiman <erik@megapahit.org>2026-06-13 17:44:11 +0800
commit191669d38d232d2bd61a0dd2252c7a3543a2b467 (patch)
treec1783f307fd217f38b31cebbe830ba0481925f8a /indra/newview/llappearancemgr.cpp
parent47b583e9caa3388cd41f70e8de0a5a950082979d (diff)
parent663bf4d3eba16e1d0a781ac5261541e7e2d6b4f2 (diff)
Merge tag 'Second_Life_Release#663bf4d3-26.3' into 26.3
Diffstat (limited to 'indra/newview/llappearancemgr.cpp')
-rw-r--r--indra/newview/llappearancemgr.cpp189
1 files changed, 107 insertions, 82 deletions
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 614d9fdeb1..9636db21c1 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -703,12 +703,12 @@ public:
void onFetchCompletion();
bool isFetchCompleted();
bool isTimedOut();
+ bool pollStopped();
void checkMissingWearables();
bool pollMissingWearables();
bool isMissingCompleted();
void recoverMissingWearable(LLWearableType::EType type);
- void clearCOFLinksForMissingWearables();
void onWearableAssetFetch(LLViewerWearable *wearable);
void onAllComplete();
@@ -717,7 +717,6 @@ public:
found_list_t& getFoundList();
void eraseTypeToLink(LLWearableType::EType type);
void eraseTypeToRecover(LLWearableType::EType type);
- void setObjItems(const LLInventoryModel::item_array_t& items);
void setGestItems(const LLInventoryModel::item_array_t& items);
bool isMostRecent();
void handleLateArrivals();
@@ -727,7 +726,6 @@ public:
private:
found_list_t mFoundList;
- LLInventoryModel::item_array_t mObjItems;
LLInventoryModel::item_array_t mGestItems;
typedef std::set<S32> type_set_t;
type_set_t mTypesToRecover;
@@ -804,11 +802,6 @@ void LLWearableHoldingPattern::eraseTypeToRecover(LLWearableType::EType type)
mTypesToRecover.erase(type);
}
-void LLWearableHoldingPattern::setObjItems(const LLInventoryModel::item_array_t& items)
-{
- mObjItems = items;
-}
-
void LLWearableHoldingPattern::setGestItems(const LLInventoryModel::item_array_t& items)
{
mGestItems = items;
@@ -914,55 +907,10 @@ void LLWearableHoldingPattern::onAllComplete()
if (isAgentAvatarValid())
{
- LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.size() << " attachments" << LL_ENDL;
- LLAgentWearables::llvo_vec_t objects_to_remove;
- LLAgentWearables::llvo_vec_t objects_to_retain;
- LLInventoryModel::item_array_t items_to_add;
-
- LLAgentWearables::findAttachmentsAddRemoveInfo(mObjItems,
- objects_to_remove,
- objects_to_retain,
- items_to_add);
-
- LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size()
- << " attachments" << LL_ENDL;
-
- // Here we remove the attachment pos overrides for *all*
- // attachments, even those that are not being removed. This is
- // needed to get joint positions all slammed down to their
- // pre-attachment states.
- gAgentAvatarp->clearAttachmentOverrides();
-
- if (objects_to_remove.size() || items_to_add.size())
- {
- LL_DEBUGS("Avatar") << "ATT will remove " << objects_to_remove.size()
- << " and add " << items_to_add.size() << " items" << LL_ENDL;
- }
-
- // Take off the attachments that will no longer be in the outfit.
- LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove);
-
// Update wearables.
LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with "
<< mResolved << " wearable items " << LL_ENDL;
LLAppearanceMgr::instance().updateAgentWearables(this);
-
- // Restore attachment pos overrides for the attachments that
- // are remaining in the outfit.
- for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin();
- it != objects_to_retain.end();
- ++it)
- {
- LLViewerObject *objectp = *it;
- if (!objectp->isAnimatedObject())
- {
- gAgentAvatarp->addAttachmentOverridesForObject(objectp);
- }
- }
-
- // Add new attachments to match those requested.
- LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL;
- LLAgentWearables::userAttachMultipleAttachments(items_to_add);
}
if (isFetchCompleted() && isMissingCompleted())
@@ -1000,6 +948,10 @@ bool LLWearableHoldingPattern::pollFetchCompletion()
{
// runway skip here?
LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
+
+ // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves
+ doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollStopped, this));
+ return true;
}
bool completed = isFetchCompleted();
@@ -1070,6 +1022,9 @@ void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLView
{
// runway skip here?
LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
+
+ // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves
+ return;
}
LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL;
@@ -1120,18 +1075,15 @@ bool LLWearableHoldingPattern::isMissingCompleted()
return mTypesToLink.size()==0 && mTypesToRecover.size()==0;
}
-void LLWearableHoldingPattern::clearCOFLinksForMissingWearables()
+bool LLWearableHoldingPattern::pollStopped()
{
- for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it)
+ // We have to keep on polling until we're sure that all callbacks have completed or they'll cause a crash
+ if (isFetchCompleted() && isMissingCompleted())
{
- LLFoundData &data = *it;
- if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable))
- {
- // Wearable link that was never resolved; remove links to it from COF
- LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL;
- LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID);
- }
+ delete this;
+ return true;
}
+ return false;
}
bool LLWearableHoldingPattern::pollMissingWearables()
@@ -1140,6 +1092,10 @@ bool LLWearableHoldingPattern::pollMissingWearables()
{
// runway skip here?
LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL;
+
+ // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves
+ doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollStopped, this));
+ return true;
}
bool timed_out = isTimedOut();
@@ -1164,14 +1120,6 @@ bool LLWearableHoldingPattern::pollMissingWearables()
gAgentAvatarp->debugWearablesLoaded();
- // BAP - if we don't call clearCOFLinksForMissingWearables()
- // here, we won't have to add the link back in later if the
- // wearable arrives late. This is to avoid corruption of
- // wearable ordering info. Also has the effect of making
- // unworn item links visible in the COF under some
- // circumstances.
-
- //clearCOFLinksForMissingWearables();
onAllComplete();
}
return done;
@@ -1218,13 +1166,6 @@ void LLWearableHoldingPattern::handleLateArrivals()
replaced_types.insert(data.mWearableType);
- // BAP - if we didn't call
- // clearCOFLinksForMissingWearables() earlier, we
- // don't need to restore the link here. Fixes
- // wearable ordering problems.
-
- // LLAppearanceMgr::instance().addCOFItemLink(data.mItemID,false);
-
// BAP failing this means inventory or asset server
// are corrupted in a way we don't handle.
llassert((data.mWearableType < LLWearableType::WT_COUNT) && (wearable->getType() == data.mWearableType));
@@ -2143,15 +2084,23 @@ void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLIn
// Keep the last N wearables of each type. For viewer 2.0, N is 1 for
// both body parts and clothing items.
void LLAppearanceMgr::filterWearableItems(
- LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total)
+ LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total, bool skip_bodyparts)
{
// Restrict by max total items first.
if ((max_total > 0) && (items.size() > max_total))
{
- LLInventoryModel::item_array_t items_to_keep;
- for (S32 i=0; i<max_total; i++)
+ LLInventoryModel::item_array_t items_to_keep; size_t non_body_kept = 0;
+ for (const auto& item : items)
{
- items_to_keep.push_back(items[i]);
+ if (skip_bodyparts && item.get() && item.get()->getType() == LLAssetType::AT_BODYPART)
+ {
+ items_to_keep.push_back(item);
+ }
+ else if (non_body_kept < max_total)
+ {
+ items_to_keep.push_back(item);
+ non_body_kept++;
+ }
}
items = items_to_keep;
}
@@ -2636,6 +2585,11 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
remove_non_link_items(wear_items);
remove_non_link_items(obj_items);
remove_non_link_items(gest_items);
+ // Since we're following folder links we might have picked up new duplicates, or exceeded MAX_CLOTHING_LAYERS
+ removeDuplicateItems(wear_items);
+ removeDuplicateItems(obj_items);
+ removeDuplicateItems(gest_items);
+ filterWearableItems(wear_items, 0, LLAgentWearables::MAX_CLOTHING_LAYERS, true);
dumpItemArray(wear_items,"asset_dump: wear_item");
dumpItemArray(obj_items,"asset_dump: obj_item");
@@ -2647,6 +2601,77 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
<< " descendent_count " << cof->getDescendentCount()
<< " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL;
}
+
+ // Update attachments to match those requested.
+ if (isAgentAvatarValid())
+ {
+ // Include attachments which should be in COF but don't have their link created yet
+ std::set<LLUUID> pendingAttachments;
+ LLAttachmentsMgr::instance().getPendingAttachments(pendingAttachments);
+ for (const LLUUID& idAttachItem : pendingAttachments)
+ {
+ if ( !gAgentAvatarp->isWearingAttachment(idAttachItem) || isLinkedInCOF(idAttachItem) )
+ {
+ LLAttachmentsMgr::instance().clearPendingAttachmentLink(idAttachItem);
+ continue;
+ }
+
+ if (LLViewerInventoryItem* pAttachItem = gInventory.getItem(idAttachItem))
+ {
+ obj_items.push_back(pAttachItem);
+ }
+ }
+
+ LL_DEBUGS("Avatar") << self_av_string() << "Updating " << obj_items.size() << " attachments" << LL_ENDL;
+ LLAgentWearables::llvo_vec_t objects_to_remove;
+ LLAgentWearables::llvo_vec_t objects_to_retain;
+ LLInventoryModel::item_array_t items_to_add;
+
+ LLAgentWearables::findAttachmentsAddRemoveInfo(obj_items,
+ objects_to_remove,
+ objects_to_retain,
+ items_to_add);
+
+ LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size()
+ << " attachments" << LL_ENDL;
+
+ // Here we remove the attachment pos overrides for *all*
+ // attachments, even those that are not being removed. This is
+ // needed to get joint positions all slammed down to their
+ // pre-attachment states.
+ gAgentAvatarp->clearAttachmentOverrides();
+
+ if (objects_to_remove.size() || items_to_add.size())
+ {
+ LL_DEBUGS("Avatar") << "ATT will remove " << objects_to_remove.size()
+ << " and add " << items_to_add.size() << " items" << LL_ENDL;
+ }
+
+ // Take off the attachments that will no longer be in the outfit.
+ // (don't remove attachments until avatar is fully loaded - reduces random attaching/detaching/reattaching at log-on)
+ if (gAgentAvatarp->isFullyLoaded())
+ {
+ LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove);
+ }
+
+ // Restore attachment pos overrides for the attachments that
+ // are remaining in the outfit.
+ for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin();
+ it != objects_to_retain.end();
+ ++it)
+ {
+ LLViewerObject *objectp = *it;
+ if (!objectp->isAnimatedObject())
+ {
+ gAgentAvatarp->addAttachmentOverridesForObject(objectp);
+ }
+ }
+
+ // Add new attachments to match those requested.
+ LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL;
+ LLAgentWearables::userAttachMultipleAttachments(items_to_add);
+ }
+
if(!wear_items.size())
{
LLNotificationsUtil::add("CouldNotPutOnOutfit");
@@ -2661,7 +2686,6 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
LLTimer hp_block_timer;
LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
- holder->setObjItems(obj_items);
holder->setGestItems(gest_items);
// Note: can't do normal iteration, because if all the
@@ -4203,6 +4227,7 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, nul
continue;
}
removeCOFItemLinks(linked_item_id, cb);
+ LLAttachmentsMgr::instance().clearPendingAttachmentLink(linked_item_id);
addDoomedTempAttachment(linked_item_id);
}
}