From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/newview/llattachmentsmgr.cpp | 1094 ++++++++++++++++++------------------ 1 file changed, 547 insertions(+), 547 deletions(-) (limited to 'indra/newview/llattachmentsmgr.cpp') diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index e00ad2cd9f..8f5dd0dab8 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -1,547 +1,547 @@ -/** - * @file llattachmentsmgr.cpp - * @brief Manager for initiating attachments changes on the viewer - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llattachmentsmgr.h" - -#include "llvoavatarself.h" -#include "llagent.h" -#include "llappearancemgr.h" -#include "llinventorymodel.h" -#include "llstartup.h" -#include "lltooldraganddrop.h" // pack_permissions_slam -#include "llviewerinventory.h" -#include "llviewerregion.h" -#include "message.h" - -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; - -LLAttachmentsMgr::LLAttachmentsMgr(): - mAttachmentRequests("attach",MIN_RETRY_REQUEST_TIME), - mDetachRequests("detach",MIN_RETRY_REQUEST_TIME), - mQuestionableCOFLinks("badcof",MAX_BAD_COF_TIME) -{ -} - -LLAttachmentsMgr::~LLAttachmentsMgr() -{ -} - -void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, - const U8 attachment_pt, - const bool add) -{ - 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; - mPendingAttachments.push_back(attachment); - - mAttachmentRequests.addTime(item_id); -} - -void LLAttachmentsMgr::onAttachmentRequested(const LLUUID& item_id) -{ - 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 -void LLAttachmentsMgr::onIdle(void *) -{ - LLAttachmentsMgr::instance().onIdle(); -} - -void LLAttachmentsMgr::onIdle() -{ - // Make sure we got a region before trying anything else - if( !gAgent.getRegion() ) - { - return; - } - - if (LLApp::isExiting()) - { - return; - } - - requestPendingAttachments(); - - linkRecentlyArrivedAttachments(); - - expireOldAttachmentRequests(); - - expireOldDetachRequests(); - - 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; - } - - // Limit number of packets to send - const S32 MAX_PACKETS_TO_SEND = 10; - const S32 OBJECTS_PER_PACKET = 4; - 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()); - - for (S32 i=0; inewMessageFast(_PREHASH_RezMultipleAttachmentsFromInv); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_HeaderData); - msg->addUUIDFast(_PREHASH_CompoundMsgID, compound_msg_id ); - msg->addU8Fast(_PREHASH_TotalObjects, obj_count ); - msg->addBOOLFast(_PREHASH_FirstDetachAll, false ); - } - - const AttachmentsInfo& attachment = attachment_requests.front(); - LLViewerInventoryItem* item = gInventory.getItem(attachment.mItemID); - 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_WARNS("Avatar") << "ATT Attempted to add non-existent item ID:" << attachment.mItemID << LL_ENDL; - } - - if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) ) - { - // End of message chunk - msg->sendReliable( gAgent.getRegion()->getHost() ); - } - attachment_requests.pop_front(); - } -} - -void LLAttachmentsMgr::linkRecentlyArrivedAttachments() -{ - if (mRecentlyArrivedAttachments.size()) - { - // 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; - } - - if (LLAppearanceMgr::instance().getCOFVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) - { - // Wait for cof to load - LL_DEBUGS_ONCE("Avatar") << "Received atachments, but cof isn't loaded yet, postponing processing" << LL_ENDL; - 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) && - !gAgentAvatarp->getWornAttachment(*it)->isTempAttachment() && // Don't link temp attachments in COF! - !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()) - { - 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(); - } -} - -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 && LLStartUp::getStartupState() > STATE_WEARABLES_WAIT) - { - 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) -{ - 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 if (!LLApp::isExiting()) - { - LL_WARNS() << "ATT unexpected detach for " - << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; - } - else - { - LL_DEBUGS("Avatar") << "ATT detach on shutdown for " << (item ? item->getName() : "UNKNOWN") << " " << 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); -} - -bool LLAttachmentsMgr::isAttachmentStateComplete() const -{ - return mPendingAttachments.empty() - && mAttachmentRequests.empty() - && mDetachRequests.empty() - && mRecentlyArrivedAttachments.empty() - && mQuestionableCOFLinks.empty(); -} - -// 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() -{ - if (!gInventory.isInventoryUsable()) - { - return; - } - 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(); - - 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 -} +/** + * @file llattachmentsmgr.cpp + * @brief Manager for initiating attachments changes on the viewer + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llattachmentsmgr.h" + +#include "llvoavatarself.h" +#include "llagent.h" +#include "llappearancemgr.h" +#include "llinventorymodel.h" +#include "llstartup.h" +#include "lltooldraganddrop.h" // pack_permissions_slam +#include "llviewerinventory.h" +#include "llviewerregion.h" +#include "message.h" + +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; + +LLAttachmentsMgr::LLAttachmentsMgr(): + mAttachmentRequests("attach",MIN_RETRY_REQUEST_TIME), + mDetachRequests("detach",MIN_RETRY_REQUEST_TIME), + mQuestionableCOFLinks("badcof",MAX_BAD_COF_TIME) +{ +} + +LLAttachmentsMgr::~LLAttachmentsMgr() +{ +} + +void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, + const U8 attachment_pt, + const bool add) +{ + 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; + mPendingAttachments.push_back(attachment); + + mAttachmentRequests.addTime(item_id); +} + +void LLAttachmentsMgr::onAttachmentRequested(const LLUUID& item_id) +{ + 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 +void LLAttachmentsMgr::onIdle(void *) +{ + LLAttachmentsMgr::instance().onIdle(); +} + +void LLAttachmentsMgr::onIdle() +{ + // Make sure we got a region before trying anything else + if( !gAgent.getRegion() ) + { + return; + } + + if (LLApp::isExiting()) + { + return; + } + + requestPendingAttachments(); + + linkRecentlyArrivedAttachments(); + + expireOldAttachmentRequests(); + + expireOldDetachRequests(); + + 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; + } + + // Limit number of packets to send + const S32 MAX_PACKETS_TO_SEND = 10; + const S32 OBJECTS_PER_PACKET = 4; + 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()); + + for (S32 i=0; inewMessageFast(_PREHASH_RezMultipleAttachmentsFromInv); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_HeaderData); + msg->addUUIDFast(_PREHASH_CompoundMsgID, compound_msg_id ); + msg->addU8Fast(_PREHASH_TotalObjects, obj_count ); + msg->addBOOLFast(_PREHASH_FirstDetachAll, false ); + } + + const AttachmentsInfo& attachment = attachment_requests.front(); + LLViewerInventoryItem* item = gInventory.getItem(attachment.mItemID); + 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_WARNS("Avatar") << "ATT Attempted to add non-existent item ID:" << attachment.mItemID << LL_ENDL; + } + + if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) ) + { + // End of message chunk + msg->sendReliable( gAgent.getRegion()->getHost() ); + } + attachment_requests.pop_front(); + } +} + +void LLAttachmentsMgr::linkRecentlyArrivedAttachments() +{ + if (mRecentlyArrivedAttachments.size()) + { + // 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; + } + + if (LLAppearanceMgr::instance().getCOFVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + // Wait for cof to load + LL_DEBUGS_ONCE("Avatar") << "Received atachments, but cof isn't loaded yet, postponing processing" << LL_ENDL; + 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) && + !gAgentAvatarp->getWornAttachment(*it)->isTempAttachment() && // Don't link temp attachments in COF! + !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()) + { + 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(); + } +} + +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 && LLStartUp::getStartupState() > STATE_WEARABLES_WAIT) + { + 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) +{ + 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 if (!LLApp::isExiting()) + { + LL_WARNS() << "ATT unexpected detach for " + << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << "ATT detach on shutdown for " << (item ? item->getName() : "UNKNOWN") << " " << 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); +} + +bool LLAttachmentsMgr::isAttachmentStateComplete() const +{ + return mPendingAttachments.empty() + && mAttachmentRequests.empty() + && mDetachRequests.empty() + && mRecentlyArrivedAttachments.empty() + && mQuestionableCOFLinks.empty(); +} + +// 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() +{ + if (!gInventory.isInventoryUsable()) + { + return; + } + 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(); + + 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 +} -- cgit v1.3