diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index dff4622866..01b2892b89 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -27,11 +27,13 @@ #include "llviewerprecompiledheaders.h" #include "llagentwearables.h" +#include "llattachmentsmgr.h" #include "llagent.h" #include "llagentcamera.h" #include "llagentwearablesfetch.h" #include "llappearancemgr.h" #include "llcallbacklist.h" +#include "llfloatercustomize.h" #include "llfolderview.h" #include "llgesturemgr.h" #include "llinventorybridge.h" @@ -51,7 +53,6 @@ #include "llwearablelist.h" #include "lllocaltextureobject.h" -#include "llfloatercustomize.h" #include "llfloaterperms.h" @@ -246,7 +247,7 @@ void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar) * * Would like to pass the agent in here, but we can't safely * count on it being around later. Just use gAgent directly. - * @param cb callback to execute on completion (??? unused ???) + * @param cb callback to execute on completion (? unused ?) * @param type Type for the wearable in the agent * @param wearable The wearable data. * @param todo Bitmask of actions to take on completion. @@ -413,7 +414,6 @@ void LLAgentWearables::sendAgentWearablesUpdate() void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update, const std::string new_name) { - //llassert_always(index == 0); LLViewerWearable* old_wearable = getViewerWearable(type, index); if(!old_wearable) return; bool name_changed = !new_name.empty() && (new_name != old_wearable->getName()); @@ -641,7 +641,6 @@ void LLAgentWearables::nameOrDescriptionChanged(LLUUID const& item_id) BOOL LLAgentWearables::isWearableModifiable(LLWearableType::EType type, U32 index) const { - //llassert_always(index == 0); LLUUID item_id = getWearableItemID(type, index); return item_id.notNull() ? isWearableModifiable(item_id) : FALSE; } @@ -652,7 +651,7 @@ BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const if (linked_id.notNull()) { LLInventoryItem* item = gInventory.getItem(linked_id); - if(item && item->getPermissions().allowModifyBy(gAgent.getID(), + if (item && item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID())) { return TRUE; @@ -663,12 +662,11 @@ BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index) const { - //llassert_always(index == 0); LLUUID item_id = getWearableItemID(type, index); if (!item_id.isNull()) { LLInventoryItem* item = gInventory.getItem(item_id); - if(item && item->getPermissions().allowCopyBy(gAgent.getID(), + if (item && item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID())) { return TRUE; @@ -681,24 +679,23 @@ BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index) U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type) { LLUUID item_id = getWearableItemID(type); - if(!item_id.isNull()) + if (!item_id.isNull()) { LLInventoryItem* item = gInventory.getItem(item_id); - if(item) + if (item) { return item->getPermissions().getMaskOwner(); } } return PERM_NONE; -} + } */ LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::EType type, U32 index) { - //llassert_always(index == 0); LLUUID item_id = getWearableItemID(type,index); LLInventoryItem* item = NULL; - if(item_id.notNull()) + if (item_id.notNull()) { item = gInventory.getItem(item_id); } @@ -785,8 +782,7 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed) { if (isAgentAvatarValid()) { - const BOOL upload_result = removed; - gAgentAvatarp->wearableUpdated(wearable->getType(), upload_result); + gAgentAvatarp->wearableUpdated(wearable->getType(), removed); } LLWearableData::wearableUpdated(wearable, removed); @@ -821,7 +817,6 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed) checkWearableAgainstInventory(viewer_wearable); } - } @@ -1225,7 +1220,6 @@ void LLAgentWearables::createStandardWearablesAllDone() LL_INFOS() << "all done?" << LL_ENDL; mWearablesLoaded = TRUE; - checkWearablesLoaded(); notifyLoadingFinished(); updateServer(); @@ -1340,14 +1334,13 @@ bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LL // Called by removeWearable() and onRemoveWearableDialog() to actually do the removal. void LLAgentWearables::removeWearableFinal( LLWearableType::EType type, bool do_remove_all, U32 index) { - //llassert_always(index == 0); + //LLAgentDumper dumper("removeWearable"); if (do_remove_all) { S32 max_entry = getWearableCount(type)-1; for (S32 i=max_entry; i>=0; i--) { LLViewerWearable* old_wearable = getViewerWearable(type,i); - //queryWearableCache(); // moved below if (old_wearable) { eraseWearable(old_wearable); @@ -1363,7 +1356,6 @@ void LLAgentWearables::removeWearableFinal( LLWearableType::EType type, bool do_ else { LLViewerWearable* old_wearable = getViewerWearable(type, index); - //queryWearableCache(); // moved below if (old_wearable) { @@ -1459,7 +1451,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it << curr_wearable->getName() << " vs " << new_item->getName() << " item ids " << curr_wearable->getItemID() << " vs " << new_item->getUUID() << LL_ENDL; - mismatched++; + update_inventory = TRUE; continue; } #endif @@ -1488,6 +1480,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it return; } + // updating inventory // TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later // note: shirt is the first non-body part wearable item. Update if wearable order changes. @@ -1538,7 +1531,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // Start rendering & update the server mWearablesLoaded = TRUE; - checkWearablesLoaded(); + // [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-09-22 (Catznip-2.2) if (!mInitialWearablesLoaded) { @@ -1556,141 +1549,119 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // User has picked "wear on avatar" from a menu. -/*void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) -{ - //LLAgentDumper dumper("setWearableItem"); - if (isWearingItem(new_item->getUUID())) - { - LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL; - return; - } - - const LLWearableType::EType type = new_wearable->getType(); - -// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0g - // TODO-RLVa: [RLVa-1.2.1] This looks like dead code in SL-2.0.2 so we can't really check to see if it works :| - if (rlv_handler_t::isEnabled()) - { - ERlvWearMask eWear = gRlvWearableLocks.canWear(type); - if ( (RLV_WEAR_LOCKED == eWear) || ((!do_append) && (!(eWear & RLV_WEAR_REPLACE))) ) - return; - } -// [/RLVa:KB] - - if (!do_append) - { - // Remove old wearable, if any - // MULTI_WEARABLE: hardwired to 0 - LLViewerWearable* old_wearable = getViewerWearable(type,0); - if( old_wearable ) - { - const LLUUID& old_item_id = old_wearable->getItemID(); - if( (old_wearable->getAssetID() == new_wearable->getAssetID()) && - (old_item_id == new_item->getUUID()) ) - { - LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName( type ) << LL_ENDL; - return; - } - - if( old_wearable->isDirty() ) - { - // Bring up modal dialog: Save changes? Yes, No, Cancel - LLSD payload; - payload["item_id"] = new_item->getUUID(); - LLNotificationsUtil::add( "WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); - return; - } - } - } - - setWearableFinal(new_item, new_wearable, do_append); -}*/ +//void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) +//{ +// //LLAgentDumper dumper("setWearableItem"); +// if (isWearingItem(new_item->getUUID())) +// { +// LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL; +// return; +// } +// +// const LLWearableType::EType type = new_wearable->getType(); +// +// if (!do_append) +// { +// // Remove old wearable, if any +// // MULTI_WEARABLE: hardwired to 0 +// LLViewerWearable* old_wearable = getViewerWearable(type,0); +// if (old_wearable) +// { +// const LLUUID& old_item_id = old_wearable->getItemID(); +// if ((old_wearable->getAssetID() == new_wearable->getAssetID()) && +// (old_item_id == new_item->getUUID())) +// { +// LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL; +// return; +// } +// +// if (old_wearable->isDirty()) +// { +// // Bring up modal dialog: Save changes? Yes, No, Cancel +// LLSD payload; +// payload["item_id"] = new_item->getUUID(); +// LLNotificationsUtil::add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); +// return; +// } +// } +// } +// +// setWearableFinal(new_item, new_wearable, do_append); +//} // static -bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLInventoryItem* new_item = gInventory.getItem( notification["payload"]["item_id"].asUUID()); - U32 index; - if (!gAgentWearables.getWearableIndex(wearable,index)) - { - LL_WARNS() << "Wearable not found" << LL_ENDL; - delete wearable; - return false; - } - if( !new_item ) - { - delete wearable; - return false; - } - - switch( option ) - { - case 0: // "Save" - gAgentWearables.saveWearable(wearable->getType(),index); - gAgentWearables.setWearableFinal( new_item, wearable ); - break; - - case 1: // "Don't Save" - gAgentWearables.setWearableFinal( new_item, wearable ); - break; - - case 2: // "Cancel" - break; - - default: - llassert(0); - break; - } - - delete wearable; - return false; -} +//bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable) +//{ +// S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +// LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); +// U32 index; +// if (!gAgentWearables.getWearableIndex(wearable,index)) +// { +// LL_WARNS() << "Wearable not found" << LL_ENDL; +// delete wearable; +// return false; +// } +// switch(option) +// { +// case 0: // "Save" +// gAgentWearables.saveWearable(wearable->getType(),index); +// gAgentWearables.setWearableFinal(new_item, wearable); +// break; +// +// case 1: // "Don't Save" +// gAgentWearables.setWearableFinal(new_item, wearable); +// break; +// +// case 2: // "Cancel" +// break; +// +// default: +// llassert(0); +// break; +// } +// +// delete wearable; +// return false; +//} // Called from setWearableItem() and onSetWearableDialog() to actually set the wearable. // MULTI_WEARABLE: unify code after null objects are gone. -void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) -{ - const LLWearableType::EType type = new_wearable->getType(); - - if (do_append && getWearableItemID(type,0).notNull()) - { - new_wearable->setItemID(new_item->getUUID()); - const bool trigger_updated = false; - pushWearable(type, new_wearable, trigger_updated); - LL_INFOS() << "Added additional wearable for type " << type - << " size is now " << getWearableCount(type) << LL_ENDL; - checkWearableAgainstInventory(new_wearable); - } - else - { - // Replace the old wearable with a new one. - llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); - - LLViewerWearable *old_wearable = getViewerWearable(type,0); - LLUUID old_item_id; - if (old_wearable) - { - old_item_id = old_wearable->getItemID(); - } - new_wearable->setItemID(new_item->getUUID()); - setWearable(type,0,new_wearable); - - if (old_item_id.notNull()) - { - gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - gInventory.notifyObservers(); - } - LL_INFOS() << "Replaced current element 0 for type " << type - << " size is now " << getWearableCount(type) << LL_ENDL; - } - - //LL_INFOS() << "LLVOAvatar::setWearableItem()" << LL_ENDL; - queryWearableCache(); - //new_wearable->writeToAvatar(TRUE); - - updateServer(); -} +//void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) +//{ +// const LLWearableType::EType type = new_wearable->getType(); +// +// if (do_append && getWearableItemID(type,0).notNull()) +// { +// new_wearable->setItemID(new_item->getUUID()); +// const bool trigger_updated = false; +// pushWearable(type, new_wearable, trigger_updated); +// LL_INFOS() << "Added additional wearable for type " << type +// << " size is now " << getWearableCount(type) << LL_ENDL; +// checkWearableAgainstInventory(new_wearable); +// } +// else +// { +// // Replace the old wearable with a new one. +// llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); +// +// LLViewerWearable *old_wearable = getViewerWearable(type,0); +// LLUUID old_item_id; +// if (old_wearable) +// { +// old_item_id = old_wearable->getItemID(); +// } +// new_wearable->setItemID(new_item->getUUID()); +// setWearable(type,0,new_wearable); +// +// if (old_item_id.notNull()) +// { +// gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); +// gInventory.notifyObservers(); +// } +// LL_INFOS() << "Replaced current element 0 for type " << type +// << " size is now " << getWearableCount(type) << LL_ENDL; +// } +//} void LLAgentWearables::queryWearableCache() { @@ -1749,17 +1720,28 @@ void LLAgentWearables::queryWearableCache() } } -// virtual -void LLAgentWearables::invalidateBakedTextureHash(LLMD5& hash) const -{ - // Add some garbage into the hash so that it becomes invalid. - if (isAgentAvatarValid()) - { - hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES); - } -} - -/// Given a desired set of attachments, find what objects need to be +// User has picked "remove from avatar" from a menu. +// static +//void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index) +//{ +// if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&& +// //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT))) +// { +// gAgentWearables.removeWearable(type,false,index); +// } +//} + +//static +//void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type) +//{ +// if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&& +// //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT))) +// { +// gAgentWearables.removeWearable(type,true,0); +// } +//} + +// Given a desired set of attachments, find what objects need to be // removed, and what additional inventory items need to be added. void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array_t& obj_item_array, llvo_vec_t& objects_to_remove, @@ -1859,7 +1841,7 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo itObj = objects_to_remove.erase(itObj); // Fall-back code: re-add the attachment if it got removed from COF somehow (compensates for possible bugs elsewhere) - bool fInCOF = LLAppearanceMgr::isLinkInCOF(pAttachObj->getAttachmentItemID()); + bool fInCOF = LLAppearanceMgr::instance().isLinkedInCOF(pAttachObj->getAttachmentItemID()); RLV_ASSERT(fInCOF); if (!fInCOF) { @@ -1877,6 +1859,7 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo if (objects_to_remove.empty()) return; + LL_DEBUGS("Avatar") << "ATT [ObjectDetach] removing " << objects_to_remove.size() << " objects" << LL_ENDL; gMessageSystem->newMessage("ObjectDetach"); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); @@ -1887,8 +1870,13 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo ++it) { LLViewerObject *objectp = *it; + //gAgentAvatarp->resetJointPositionsOnDetach(objectp); gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID()); + const LLUUID& item_id = objectp->getAttachmentItemID(); + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT removing object, item is " << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + LLAttachmentsMgr::instance().onDetachRequested(item_id); } gMessageSystem->sendReliable(gAgent.getRegionHost()); } @@ -1960,24 +1948,21 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra // End of message chunk msg->sendReliable( gAgent.getRegion()->getHost() ); } - } + + + for(LLInventoryModel::item_array_t::const_iterator it = obj_item_array.begin(); + it != obj_item_array.end(); + ++it) + { + const LLInventoryItem* item = *it; + LLAttachmentsMgr::instance().addAttachmentRequest(item->getLinkedUUID(), 0, TRUE); + } // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) sInitialAttachmentsRequested = true; // [/RLVa:KB] } -void LLAgentWearables::checkWearablesLoaded() const -{ -#ifdef SHOW_ASSERT - U32 item_pend_count = itemUpdatePendingCount(); - if (mWearablesLoaded) - { - llassert(item_pend_count==0); - } -#endif -} - // Returns false if the given wearable is already topmost/bottommost // (depending on closer_to_body parameter). bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body) const @@ -1994,7 +1979,6 @@ bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_bod BOOL LLAgentWearables::areWearablesLoaded() const { - checkWearablesLoaded(); return mWearablesLoaded; } diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 09284bda27..b5276244f0 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -170,7 +170,6 @@ class LLAgentWearables : public LLInitClass, public LLWearable protected: - /*virtual*/ void invalidateBakedTextureHash(LLMD5& hash) const; void sendAgentWearablesUpdate(); void sendAgentWearablesRequest(); void queryWearableCache(); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index bcdb57e65e..cc54f85be3 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2588,6 +2588,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, << " descendent_count " << cof->getDescendentCount() << " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL; } + // [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2) // Update attachments to match those requested. if (isAgentAvatarValid()) diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index 6f2f4d7d27..21ca02e387 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -27,7 +27,9 @@ #include "llviewerprecompiledheaders.h" #include "llattachmentsmgr.h" +#include "llvoavatarself.h" #include "llagent.h" +#include "llappearancemgr.h" #include "llinventorymodel.h" #include "lltooldraganddrop.h" // pack_permissions_slam #include "llviewerinventory.h" @@ -38,7 +40,35 @@ #include "rlvlocks.h" // [/RLVa:KB] -LLAttachmentsMgr::LLAttachmentsMgr() +const F32 COF_LINK_BATCH_TIME = 5.0F; +const F32 MAX_ATTACHMENT_REQUEST_LIFETIME = 30.0F; +const F32 MIN_RETRY_REQUEST_TIME = 5.0F; +const F32 MAX_BAD_COF_TIME = 30.0F; + +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7) +class LLRegisterAttachmentCallback : public LLRequestServerAppearanceUpdateOnDestroy +{ +public: + LLRegisterAttachmentCallback() + : LLRequestServerAppearanceUpdateOnDestroy() + { + } + + /*virtual*/ ~LLRegisterAttachmentCallback() + { + } + + /*virtual*/ void fire(const LLUUID& idItem) + { + LLAttachmentsMgr::instance().onRegisterAttachmentComplete(idItem); + } +}; +// [/SL:KB] + +LLAttachmentsMgr::LLAttachmentsMgr(): + mAttachmentRequests("attach",MIN_RETRY_REQUEST_TIME), + mDetachRequests("detach",MIN_RETRY_REQUEST_TIME) +// , mQuestionableCOFLinks("badcof",MAX_BAD_COF_TIME) { } @@ -46,20 +76,34 @@ LLAttachmentsMgr::~LLAttachmentsMgr() { } -void LLAttachmentsMgr::addAttachment(const LLUUID& item_id, - const U8 attachment_pt, +//void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, +// const U8 attachment_pt, // const BOOL add) // [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1) +void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, + const U8 attachment_pt, const BOOL add, const BOOL fRlvForce /*=FALSE*/) // [/RLVa:KB] { + LLViewerInventoryItem *item = gInventory.getItem(item_id); + + if (mAttachmentRequests.wasRequestedRecently(item_id)) + { + LL_DEBUGS("Avatar") << "ATT not adding attachment to mPendingAttachments, recent request is already pending: " + << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + return; + } + + LL_DEBUGS("Avatar") << "ATT adding attachment to mPendingAttachments " + << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + AttachmentsInfo attachment; attachment.mItemID = item_id; attachment.mAttachmentPt = attachment_pt; attachment.mAdd = add; // [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1) - if ( (rlv_handler_t::isEnabled()) && (!fRlvForce) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + if ( (rlv_handler_t::isEnabled()) && (!fRlvForce) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) && (gAgentWearables.areInitialAttachmentsRequested()) ) { const LLInventoryItem* pItem = gInventory.getItem(item_id); if (!pItem) @@ -78,6 +122,21 @@ void LLAttachmentsMgr::addAttachment(const LLUUID& item_id, // [/RLVa:KB] mPendingAttachments.push_back(attachment); + + mAttachmentRequests.addTime(item_id); +} + +void LLAttachmentsMgr::onAttachmentRequested(const LLUUID& item_id) +{ +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7) + if (item_id.isNull()) + return; +// [/SL:KB] + + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT attachment was requested " + << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + mAttachmentRequests.addTime(item_id); } // static @@ -88,10 +147,55 @@ void LLAttachmentsMgr::onIdle(void *) void LLAttachmentsMgr::onIdle() { - if(!gAgent.getRegion()) + // Make sure we got a region before trying anything else + if( !gAgent.getRegion() ) + { return; + } + + if (LLApp::isExiting()) + { + return; + } + + requestPendingAttachments(); + + linkRecentlyArrivedAttachments(); + + expireOldAttachmentRequests(); + + expireOldDetachRequests(); - S32 obj_count = mPendingAttachments.size(); +// checkInvalidCOFLinks(); + + spamStatusInfo(); +} + +void LLAttachmentsMgr::requestPendingAttachments() +{ + if (mPendingAttachments.size()) + { + requestAttachments(mPendingAttachments); + } +} + +// Send request(s) for a group of attachments. As coded, this can +// request at most 40 attachments and the rest will be +// ignored. Currently the max attachments per avatar is 38, so the 40 +// limit should not be hit in practice. +void LLAttachmentsMgr::requestAttachments(attachments_vec_t& attachment_requests) +{ + // Make sure we got a region before trying anything else + if( !gAgent.getRegion() ) + { + return; + } + + // For unknown reasons, requesting many attachments at once causes + // frequent server-side failures. Here we're limiting the number + // of attachments requested per idle loop. + const S32 max_objects_per_request = 5; + S32 obj_count = llmin((S32)attachment_requests.size(),max_objects_per_request); if (obj_count == 0) { return; @@ -103,18 +207,24 @@ void LLAttachmentsMgr::onIdle() const S32 MAX_OBJECTS_TO_SEND = MAX_PACKETS_TO_SEND * OBJECTS_PER_PACKET; if( obj_count > MAX_OBJECTS_TO_SEND ) { + LL_WARNS() << "ATT Too many attachments requested: " << obj_count + << " exceeds limit of " << MAX_OBJECTS_TO_SEND << LL_ENDL; + obj_count = MAX_OBJECTS_TO_SEND; } + LL_DEBUGS("Avatar") << "ATT [RezMultipleAttachmentsFromInv] attaching multiple from attachment_requests," + " total obj_count " << obj_count << LL_ENDL; + LLUUID compound_msg_id; compound_msg_id.generate(); LLMessageSystem* msg = gMessageSystem; + // by construction above, obj_count <= attachment_requests.size(), so no + // check against attachment_requests.empty() is needed. + llassert(obj_count <= attachment_requests.size()); - S32 i = 0; - for (attachments_vec_t::const_iterator iter = mPendingAttachments.begin(); - iter != mPendingAttachments.end(); - ++iter) + for (S32 i=0; iaddBOOLFast(_PREHASH_FirstDetachAll, false ); } - const AttachmentsInfo &attachment = (*iter); + const AttachmentsInfo& attachment = attachment_requests.front(); LLViewerInventoryItem* item = gInventory.getItem(attachment.mItemID); - if (!item) + if (item) + { + LL_DEBUGS("Avatar") << "ATT requesting from attachment_requests " << item->getName() + << " " << item->getLinkedUUID() << LL_ENDL; + S32 attachment_pt = attachment.mAttachmentPt; + if (attachment.mAdd) + attachment_pt |= ATTACHMENT_ADD; + + msg->nextBlockFast(_PREHASH_ObjectData ); + msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID()); + msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner()); + msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt); + pack_permissions_slam(msg, item->getFlags(), item->getPermissions()); + msg->addStringFast(_PREHASH_Name, item->getName()); + msg->addStringFast(_PREHASH_Description, item->getDescription()); + } + else { - LL_INFOS() << "Attempted to add non-existant item ID:" << attachment.mItemID << LL_ENDL; - continue; + LL_WARNS("Avatar") << "ATT Attempted to add non-existent item ID:" << attachment.mItemID << LL_ENDL; } - S32 attachment_pt = attachment.mAttachmentPt; - if (attachment.mAdd) - attachment_pt |= ATTACHMENT_ADD; - - msg->nextBlockFast(_PREHASH_ObjectData ); - msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID()); - msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner()); - msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt); - pack_permissions_slam(msg, item->getFlags(), item->getPermissions()); - msg->addStringFast(_PREHASH_Name, item->getName()); - msg->addStringFast(_PREHASH_Description, item->getDescription()); if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) ) { // End of message chunk msg->sendReliable( gAgent.getRegion()->getHost() ); } - i++; + attachment_requests.pop_front(); } +} + +void LLAttachmentsMgr::linkRecentlyArrivedAttachments() +{ + if (mRecentlyArrivedAttachments.size()) + { + // [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7) + if (!LLAppearanceMgr::instance().getAttachmentInvLinkEnable()) + { + return; + } +// [/SL:KB] + + // One or more attachments have arrived but have not yet been + // processed for COF links + if (mAttachmentRequests.empty()) + { + // Not waiting for any more. + LL_DEBUGS("Avatar") << "ATT all pending attachments have arrived after " + << mCOFLinkBatchTimer.getElapsedTimeF32() << " seconds" << LL_ENDL; + } + else if (mCOFLinkBatchTimer.getElapsedTimeF32() > COF_LINK_BATCH_TIME) + { + LL_DEBUGS("Avatar") << "ATT " << mAttachmentRequests.size() + << " pending attachments have not arrived, but wait time exceeded" << LL_ENDL; + } + else + { + return; + } + + LL_DEBUGS("Avatar") << "ATT checking COF linkability for " << mRecentlyArrivedAttachments.size() + << " recently arrived items" << LL_ENDL; + + uuid_vec_t ids_to_link; + for (std::set::iterator it = mRecentlyArrivedAttachments.begin(); + it != mRecentlyArrivedAttachments.end(); ++it) + { + if (isAgentAvatarValid() && + gAgentAvatarp->isWearingAttachment(*it) && + !LLAppearanceMgr::instance().isLinkedInCOF(*it)) + { + LLUUID item_id = *it; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT adding COF link for attachment " + << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + ids_to_link.push_back(item_id); + } + } + if (ids_to_link.size()) + { +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7) + LLPointer cb = new LLRegisterAttachmentCallback(); + for (const LLUUID& idAttach : ids_to_link) + { + if (std::find(mPendingAttachLinks.begin(), mPendingAttachLinks.end(), idAttach) == mPendingAttachLinks.end()) + { + LLAppearanceMgr::instance().addCOFItemLink(idAttach, cb); + mPendingAttachLinks.insert(idAttach); + } + } +// [/SL:KB] +// LLPointer cb = new LLRequestServerAppearanceUpdateOnDestroy(); +// for (uuid_vec_t::const_iterator uuid_it = ids_to_link.begin(); +// uuid_it != ids_to_link.end(); ++uuid_it) +// { +// LLAppearanceMgr::instance().addCOFItemLink(*uuid_it, cb); +// } + } + mRecentlyArrivedAttachments.clear(); + } +} + +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-18 (Catznip-2.2) +bool LLAttachmentsMgr::getPendingAttachments(std::set& ids) const +{ + ids.clear(); + + // Returns the union of the LL maintained list of attachments that are waiting for link creation and our maintained list of attachments that are pending link creation + set_union(mRecentlyArrivedAttachments.begin(), mRecentlyArrivedAttachments.end(), mPendingAttachLinks.begin(), mPendingAttachLinks.end(), std::inserter(ids, ids.begin())); + + return !ids.empty(); +} + +void LLAttachmentsMgr::clearPendingAttachmentLink(const LLUUID& idItem) +{ + mPendingAttachLinks.erase(idItem); +} + +void LLAttachmentsMgr::onRegisterAttachmentComplete(const LLUUID& idAttachLink) +{ + const LLViewerInventoryItem* pAttachLink = gInventory.getItem(idAttachLink); + if (!pAttachLink) + return; + + const LLUUID& idAttachBase = pAttachLink->getLinkedUUID(); + + // Remove the attachment from the pending list + clearPendingAttachmentLink(idAttachBase); + + // It may have been detached already in which case we should remove the COF link + if ( (isAgentAvatarValid()) && (!gAgentAvatarp->isWearingAttachment(idAttachBase)) ) + { + LLAppearanceMgr::instance().removeCOFItemLinks(idAttachBase, NULL, true); + } +} +// [/SL:KB] + +LLAttachmentsMgr::LLItemRequestTimes::LLItemRequestTimes(const std::string& op_name, F32 timeout): + mOpName(op_name), + mTimeout(timeout) +{ +} + +void LLAttachmentsMgr::LLItemRequestTimes::addTime(const LLUUID& inv_item_id) +{ + LLInventoryItem *item = gInventory.getItem(inv_item_id); + LL_DEBUGS("Avatar") << "ATT " << mOpName << " adding request time " << (item ? item->getName() : "UNKNOWN") << " " << inv_item_id << LL_ENDL; + LLTimer current_time; + (*this)[inv_item_id] = current_time; +} + +void LLAttachmentsMgr::LLItemRequestTimes::removeTime(const LLUUID& inv_item_id) +{ + LLInventoryItem *item = gInventory.getItem(inv_item_id); + S32 remove_count = (*this).erase(inv_item_id); + if (remove_count) + { + LL_DEBUGS("Avatar") << "ATT " << mOpName << " removing request time " + << (item ? item->getName() : "UNKNOWN") << " " << inv_item_id << LL_ENDL; + } +} + +BOOL LLAttachmentsMgr::LLItemRequestTimes::getTime(const LLUUID& inv_item_id, LLTimer& timer) const +{ + std::map::const_iterator it = (*this).find(inv_item_id); + if (it != (*this).end()) + { + timer = it->second; + return TRUE; + } + return FALSE; +} + +BOOL LLAttachmentsMgr::LLItemRequestTimes::wasRequestedRecently(const LLUUID& inv_item_id) const +{ + LLTimer request_time; + if (getTime(inv_item_id, request_time)) + { + F32 request_time_elapsed = request_time.getElapsedTimeF32(); + return request_time_elapsed < mTimeout; + } + else + { + return FALSE; + } +} + +// If we've been waiting for an attachment a long time, we want to +// forget the request, because if the request is invalid (say the +// object does not exist), the existence of a request that never goes +// away will gum up the COF batch logic, causing it to always wait for +// the timeout. Expiring a request means if the item does show up +// late, the COF link request may not get properly batched up, but +// behavior will be no worse than before we had the batching mechanism +// in place; the COF link will still be created, but extra +// requestServerAppearanceUpdate() calls may occur. +void LLAttachmentsMgr::expireOldAttachmentRequests() +{ + for (std::map::iterator it = mAttachmentRequests.begin(); + it != mAttachmentRequests.end(); ) + { + std::map::iterator curr_it = it; + ++it; + if (curr_it->second.getElapsedTimeF32() > MAX_ATTACHMENT_REQUEST_LIFETIME) + { + LLInventoryItem *item = gInventory.getItem(curr_it->first); + LL_WARNS("Avatar") << "ATT expiring request for attachment " + << (item ? item->getName() : "UNKNOWN") << " item_id " << curr_it->first + << " after " << MAX_ATTACHMENT_REQUEST_LIFETIME << " seconds" << LL_ENDL; + mAttachmentRequests.erase(curr_it); + } + } +} + +void LLAttachmentsMgr::expireOldDetachRequests() +{ + for (std::map::iterator it = mDetachRequests.begin(); + it != mDetachRequests.end(); ) + { + std::map::iterator curr_it = it; + ++it; + if (curr_it->second.getElapsedTimeF32() > MAX_ATTACHMENT_REQUEST_LIFETIME) + { + LLInventoryItem *item = gInventory.getItem(curr_it->first); + LL_WARNS("Avatar") << "ATT expiring request for detach " + << (item ? item->getName() : "UNKNOWN") << " item_id " << curr_it->first + << " after " << MAX_ATTACHMENT_REQUEST_LIFETIME << " seconds" << LL_ENDL; + mDetachRequests.erase(curr_it); + } + } +} + +// When an attachment arrives, we want to stop waiting for it, and add +// it to the set of recently arrived items. +void LLAttachmentsMgr::onAttachmentArrived(const LLUUID& inv_item_id) +{ + LLTimer timer; + bool expected = mAttachmentRequests.getTime(inv_item_id, timer); + if (!expected) + { + LLInventoryItem *item = gInventory.getItem(inv_item_id); + LL_WARNS() << "ATT Attachment was unexpected or arrived after " << MAX_ATTACHMENT_REQUEST_LIFETIME << " seconds: " + << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; + } + mAttachmentRequests.removeTime(inv_item_id); + if (expected && mAttachmentRequests.empty()) + { + // mAttachmentRequests just emptied out + LL_DEBUGS("Avatar") << "ATT all active attachment requests have completed" << LL_ENDL; + } + if (mRecentlyArrivedAttachments.empty()) + { + // Start the timer for sending off a COF link batch. + mCOFLinkBatchTimer.reset(); + } + mRecentlyArrivedAttachments.insert(inv_item_id); +} + +void LLAttachmentsMgr::onDetachRequested(const LLUUID& inv_item_id) +{ + mDetachRequests.addTime(inv_item_id); +} + +void LLAttachmentsMgr::onDetachCompleted(const LLUUID& inv_item_id) +{ +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-10-05 (Catznip-2.2) + // (mRecentlyArrivedAttachments doesn't need pruning since it'll check the attachment is actually worn before linking) + clearPendingAttachmentLink(inv_item_id); +// [/SL:KB] + + LLTimer timer; + LLInventoryItem *item = gInventory.getItem(inv_item_id); + if (mDetachRequests.getTime(inv_item_id, timer)) + { + LL_DEBUGS("Avatar") << "ATT detach completed after " << timer.getElapsedTimeF32() + << " seconds for " << (item ? item->getName() : "UNKNOWN") << " " << inv_item_id << LL_ENDL; + mDetachRequests.removeTime(inv_item_id); + if (mDetachRequests.empty()) + { + LL_DEBUGS("Avatar") << "ATT all detach requests have completed" << LL_ENDL; + } + } + else + { + LL_WARNS() << "ATT unexpected detach for " + << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; + } + +// LL_DEBUGS("Avatar") << "ATT detached item flagging as questionable for COF link checking " +// << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; +// mQuestionableCOFLinks.addTime(inv_item_id); +} + +// Check for attachments that are (a) linked in COF and (b) not +// attached to the avatar. This is a rotten function to have to +// include, because it runs the risk of either repeatedly spamming out +// COF link removals if they're failing for some reason, or getting +// into a tug of war with some other sequence of events that's in the +// process of adding the attachment in question. However, it's needed +// because we have no definitive source of authority for what things +// are actually supposed to be attached. Scripts, run on the server +// side, can remove an attachment without our expecting it. If this +// happens to an attachment that's just been added, then the COF link +// creation may still be in flight, and we will have to delete the +// link after it shows up. +// +// Note that we only flag items for possible link removal if they have +// been previously detached. This means that an attachment failure +// will leave the link in the COF, where it will hopefully resolve +// correctly on relog. +// +// See related: MAINT-5070, MAINT-4409 +// +//void LLAttachmentsMgr::checkInvalidCOFLinks() +//{ +// LLInventoryModel::cat_array_t cat_array; +// LLInventoryModel::item_array_t item_array; +// gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), +// cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); +// for (S32 i=0; igetLinkedUUID(); +// if (inv_item->getType() == LLAssetType::AT_OBJECT) +// { +// LLTimer timer; +// bool is_flagged_questionable = mQuestionableCOFLinks.getTime(item_id,timer); +// bool is_wearing_attachment = isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item_id); +// if (is_wearing_attachment && is_flagged_questionable) +// { +// LL_DEBUGS("Avatar") << "ATT was flagged questionable but is now " +// << (is_wearing_attachment ? "attached " : "") +// <<"removing flag after " +// << timer.getElapsedTimeF32() << " item " +// << inv_item->getName() << " id " << item_id << LL_ENDL; +// mQuestionableCOFLinks.removeTime(item_id); +// } +// } +// } +// +// for(LLItemRequestTimes::iterator it = mQuestionableCOFLinks.begin(); +// it != mQuestionableCOFLinks.end(); ) +// { +// LLItemRequestTimes::iterator curr_it = it; +// ++it; +// const LLUUID& item_id = curr_it->first; +// LLViewerInventoryItem *inv_item = gInventory.getItem(item_id); +// if (curr_it->second.getElapsedTimeF32() > MAX_BAD_COF_TIME) +// { +// if (LLAppearanceMgr::instance().isLinkedInCOF(item_id)) +// { +// LL_DEBUGS("Avatar") << "ATT Linked in COF but not attached or requested, deleting link after " +// << curr_it->second.getElapsedTimeF32() << " seconds for " +// << (inv_item ? inv_item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; +// LLAppearanceMgr::instance().removeCOFItemLinks(item_id); +// } +// mQuestionableCOFLinks.erase(curr_it); +// continue; +// } +// } +//} + +void LLAttachmentsMgr::spamStatusInfo() +{ +#if 0 + static LLTimer spam_timer; + const F32 spam_frequency = 100.0F; + + if (spam_timer.getElapsedTimeF32() > spam_frequency) + { + spam_timer.reset(); - mPendingAttachments.clear(); + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), + cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); + for (S32 i=0; igetType() == LLAssetType::AT_OBJECT) + { + LL_DEBUGS("Avatar") << "item_id: " << inv_item->getUUID() + << " linked_item_id: " << inv_item->getLinkedUUID() + << " name: " << inv_item->getName() + << " parent: " << inv_item->getParentUUID() + << LL_ENDL; + } + } + } +#endif } diff --git a/indra/newview/llattachmentsmgr.h b/indra/newview/llattachmentsmgr.h index 997db59d22..cd516adbfd 100644 --- a/indra/newview/llattachmentsmgr.h +++ b/indra/newview/llattachmentsmgr.h @@ -32,45 +32,120 @@ class LLViewerInventoryItem; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//-------------------------------------------------------------------------------- // LLAttachmentsMgr // -// The sole purpose of this class is to take attachment -// requests, queue them up, and send them all at once. -// This handles situations where the viewer may request -// a bunch of attachments at once in a short period of -// time, where each of the requests would normally be -// sent as a separate message versus being batched into -// one single message. +// This class manages batching up of requests at two stages of +// attachment rezzing. // -// The intent of this batching is to reduce viewer->server -// traffic. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// First, attachments requested to rez get saved in +// mPendingAttachments and sent as a single +// RezMultipleAttachmentsFromInv request. This batching is needed +// mainly because of weaknessing the UI element->inventory item +// handling, such that we don't always know when we are requesting +// multiple items. Now they just pile up and get swept into a single +// request during the idle loop. +// +// Second, after attachments arrive, we need to generate COF links for +// them. There are both efficiency and UI correctness reasons why it +// is better to request all the COF links at once and run a single +// callback after they all complete. Given the vagaries of the +// attachment system, there is no guarantee that we will get all the +// attachments we ask for, but we frequently do. So in the common case +// that all the desired attachments arrive fairly quickly, we generate +// a single batched request for COF links. If attachments arrive late +// or not at all, we will still issue COF link requests once a timeout +// value has been exceeded. +// +// To handle attachments that never arrive, we forget about requests +// that exceed a timeout value. +//-------------------------------------------------------------------------------- class LLAttachmentsMgr: public LLSingleton { public: + // Stores info for attachments that will be requested during idle. + struct AttachmentsInfo + { + LLUUID mItemID; + U8 mAttachmentPt; + BOOL mAdd; + }; + typedef std::deque attachments_vec_t; + LLAttachmentsMgr(); virtual ~LLAttachmentsMgr(); - void addAttachment(const LLUUID& item_id, +// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1) + void addAttachmentRequest(const LLUUID& item_id, const U8 attachment_pt, -// const BOOL add); -// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1c) | Added: RLVa-1.2.1c const BOOL add, const BOOL fRlvForce = FALSE); // [/RLVa:KB] +// void addAttachmentRequest(const LLUUID& item_id, +// const U8 attachment_pt, +// const BOOL add); + void onAttachmentRequested(const LLUUID& item_id); + void requestAttachments(attachments_vec_t& attachment_requests); static void onIdle(void *); + + void onAttachmentArrived(const LLUUID& inv_item_id); + + void onDetachRequested(const LLUUID& inv_item_id); + void onDetachCompleted(const LLUUID& inv_item_id); + +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-18 (Catznip-2.1) +public: + void clearPendingAttachmentLink(const LLUUID& idItem); + bool getPendingAttachments(std::set& ids) const; protected: - void onIdle(); + void onRegisterAttachmentComplete(const LLUUID& idAttachLink); + friend class LLRegisterAttachmentCallback; +// [/SL:KB] + private: - struct AttachmentsInfo + + class LLItemRequestTimes: public std::map { - LLUUID mItemID; - U8 mAttachmentPt; - BOOL mAdd; + public: + LLItemRequestTimes(const std::string& op_name, F32 timeout); + void addTime(const LLUUID& inv_item_id); + void removeTime(const LLUUID& inv_item_id); + BOOL wasRequestedRecently(const LLUUID& item_id) const; + BOOL getTime(const LLUUID& inv_item_id, LLTimer& timer) const; + + private: + F32 mTimeout; + std::string mOpName; }; - typedef std::vector attachments_vec_t; + void removeAttachmentRequestTime(const LLUUID& inv_item_id); + void onIdle(); + void requestPendingAttachments(); + void linkRecentlyArrivedAttachments(); + void expireOldAttachmentRequests(); + void expireOldDetachRequests(); +// void checkInvalidCOFLinks(); + void spamStatusInfo(); + + // Attachments that we are planning to rez but haven't requested from the server yet. attachments_vec_t mPendingAttachments; + + // Attachments that have been requested from server but have not arrived yet. + LLItemRequestTimes mAttachmentRequests; + + // Attachments that have been requested to detach but have not gone away yet. + LLItemRequestTimes mDetachRequests; + + // Attachments that have arrived but have not been linked in the COF yet. + std::set mRecentlyArrivedAttachments; + LLTimer mCOFLinkBatchTimer; + +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-18 (Catznip-2.1) + // Attachments that have pending link creation + std::set mPendingAttachLinks; +// [/SL:KB] + +// // Attachments that are linked in the COF but may be invalid. +// LLItemRequestTimes mQuestionableCOFLinks; }; #endif diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index d198b767b4..53ba2b01b9 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -5545,9 +5545,8 @@ bool confirm_attachment_rez(const LLSD& notification, const LLSD& response) U8 attachment_pt = notification["payload"]["attachment_point"].asInteger(); BOOL is_add = notification["payload"]["is_add"].asBoolean(); - LLAttachmentsMgr::instance().addAttachment(item_id, - attachment_pt, - is_add); + LL_DEBUGS("Avatar") << "ATT calling addAttachmentRequest " << (itemp ? itemp->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + LLAttachmentsMgr::instance().addAttachmentRequest(item_id, attachment_pt, is_add); } } return false;