diff options
author | Tofu Linden <tofu.linden@lindenlab.com> | 2010-04-07 13:37:37 +0100 |
---|---|---|
committer | Tofu Linden <tofu.linden@lindenlab.com> | 2010-04-07 13:37:37 +0100 |
commit | 4533d1b59b2e8fc534ad3de7a896aaa8514fe653 (patch) | |
tree | 38b4d2398d66a0e18cd8e4dcd47efba0ad5326a1 /indra/newview/llappearancemgr.cpp | |
parent | 92f630871386bafc4548eb9beb45063e40b6139c (diff) | |
parent | adce2ecdf8f3a0efcd4907699d286012124ac496 (diff) |
merge from viewer-trunk
Diffstat (limited to 'indra/newview/llappearancemgr.cpp')
-rw-r--r-- | indra/newview/llappearancemgr.cpp | 1674 |
1 files changed, 187 insertions, 1487 deletions
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 04a5bcc256..e0f1d5348d 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2,122 +2,54 @@ * @file llappearancemgr.cpp * @brief Manager for initiating appearance changes on the viewer * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, 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. + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * - * 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. + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * - * 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 + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" -#include "llaccordionctrltab.h" #include "llagent.h" -#include "llagentcamera.h" #include "llagentwearables.h" #include "llappearancemgr.h" #include "llcommandhandler.h" -#include "lleventtimer.h" +#include "llfloatercustomize.h" #include "llgesturemgr.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" #include "llinventoryobserver.h" #include "llnotificationsutil.h" -#include "lloutfitobserver.h" -#include "lloutfitslist.h" -#include "llselectmgr.h" #include "llsidepanelappearance.h" #include "llsidetray.h" -#include "llviewerobjectlist.h" #include "llvoavatar.h" #include "llvoavatarself.h" #include "llviewerregion.h" #include "llwearablelist.h" -// RAII thingy to guarantee that a variable gets reset when the Setter -// goes out of scope. More general utility would be handy - TODO: -// check boost. -class BoolSetter -{ -public: - BoolSetter(bool& var): - mVar(var) - { - mVar = true; - } - ~BoolSetter() - { - mVar = false; - } -private: - bool& mVar; -}; - -char ORDER_NUMBER_SEPARATOR('@'); - -class LLOutfitUnLockTimer: public LLEventTimer -{ -public: - LLOutfitUnLockTimer(F32 period) : LLEventTimer(period) - { - // restart timer on BOF changed event - LLOutfitObserver::instance().addBOFChangedCallback(boost::bind( - &LLOutfitUnLockTimer::reset, this)); - stop(); - } - - /*virtual*/ - BOOL tick() - { - if(mEventTimer.hasExpired()) - { - LLAppearanceMgr::instance().setOutfitLocked(false); - } - return FALSE; - } - void stop() { mEventTimer.stop(); } - void start() { mEventTimer.start(); } - void reset() { mEventTimer.reset(); } - BOOL getStarted() { return mEventTimer.getStarted(); } - - LLTimer& getEventTimer() { return mEventTimer;} -}; - -// support for secondlife:///app/appearance SLapps -class LLAppearanceHandler : public LLCommandHandler -{ -public: - // requests will be throttled from a non-trusted browser - LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {} - - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) - { - // support secondlife:///app/appearance/show, but for now we just - // make all secondlife:///app/appearance SLapps behave this way - LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD()); - return true; - } -}; - -LLAppearanceHandler gAppearanceHandler; - - -LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name) +LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name) { LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; @@ -184,26 +116,8 @@ private: bool mAppend; }; - -//Inventory callback updating "dirty" state when destroyed -class LLUpdateDirtyState: public LLInventoryCallback -{ -public: - LLUpdateDirtyState() {} - virtual ~LLUpdateDirtyState() - { - if (LLAppearanceMgr::instanceExists()) - { - LLAppearanceMgr::getInstance()->updateIsDirty(); - } - } - virtual void fire(const LLUUID&) {} -}; - - -LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering): - mFireCount(0), - mUpdateBaseOrder(update_base_outfit_ordering) +LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(): + mFireCount(0) { } @@ -213,17 +127,13 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() if (!LLApp::isExiting()) { - LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder); + LLAppearanceMgr::instance().updateAppearanceFromCOF(); } } void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); - const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; -#ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << llendl; -#endif + llinfos << "callback fired" << llendl; mFireCount++; } @@ -231,31 +141,28 @@ struct LLFoundData { LLFoundData() : mAssetType(LLAssetType::AT_NONE), - mWearableType(LLWearableType::WT_INVALID), + mWearableType(WT_INVALID), mWearable(NULL) {} LLFoundData(const LLUUID& item_id, const LLUUID& asset_id, const std::string& name, const LLAssetType::EType& asset_type, - const LLWearableType::EType& wearable_type, - const bool is_replacement = false + const EWearableType& wearable_type ) : mItemID(item_id), mAssetID(asset_id), mName(name), mAssetType(asset_type), mWearableType(wearable_type), - mIsReplacement(is_replacement), mWearable( NULL ) {} LLUUID mItemID; LLUUID mAssetID; std::string mName; LLAssetType::EType mAssetType; - LLWearableType::EType mWearableType; + EWearableType mWearableType; LLWearable* mWearable; - bool mIsReplacement; }; @@ -273,23 +180,13 @@ public: void checkMissingWearables(); bool pollMissingWearables(); bool isMissingCompleted(); - void recoverMissingWearable(LLWearableType::EType type); + void recoverMissingWearable(EWearableType type); void clearCOFLinksForMissingWearables(); void onWearableAssetFetch(LLWearable *wearable); void onAllComplete(); - - typedef std::list<LLFoundData> found_list_t; - 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(); - void resetTime(F32 timeout); -private: + typedef std::list<LLFoundData> found_list_t; found_list_t mFoundList; LLInventoryModel::item_array_t mObjItems; LLInventoryModel::item_array_t mGestItems; @@ -299,128 +196,63 @@ private: S32 mResolved; LLTimer mWaitTime; bool mFired; - typedef std::set<LLWearableHoldingPattern*> type_set_hp; - static type_set_hp sActiveHoldingPatterns; - bool mIsMostRecent; - std::set<LLWearable*> mLateArrivals; - bool mIsAllComplete; }; -LLWearableHoldingPattern::type_set_hp LLWearableHoldingPattern::sActiveHoldingPatterns; - LLWearableHoldingPattern::LLWearableHoldingPattern(): mResolved(0), - mFired(false), - mIsMostRecent(true), - mIsAllComplete(false) + mFired(false) { - if (sActiveHoldingPatterns.size()>0) - { - llinfos << "Creating LLWearableHoldingPattern when " - << sActiveHoldingPatterns.size() - << " other attempts are active." - << " Flagging others as invalid." - << llendl; - for (type_set_hp::iterator it = sActiveHoldingPatterns.begin(); - it != sActiveHoldingPatterns.end(); - ++it) - { - (*it)->mIsMostRecent = false; - } - - } - sActiveHoldingPatterns.insert(this); } LLWearableHoldingPattern::~LLWearableHoldingPattern() { - sActiveHoldingPatterns.erase(this); -} - -bool LLWearableHoldingPattern::isMostRecent() -{ - return mIsMostRecent; -} - -LLWearableHoldingPattern::found_list_t& LLWearableHoldingPattern::getFoundList() -{ - return mFoundList; -} - -void LLWearableHoldingPattern::eraseTypeToLink(LLWearableType::EType type) -{ - mTypesToLink.erase(type); -} - -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; } bool LLWearableHoldingPattern::isFetchCompleted() { - return (mResolved >= (S32)getFoundList().size()); // have everything we were waiting for? + return (mResolved >= (S32)mFoundList.size()); // have everything we were waiting for? } bool LLWearableHoldingPattern::isTimedOut() { - return mWaitTime.hasExpired(); + static F32 max_wait_time = 60.0; // give up if wearable fetches haven't completed in max_wait_time seconds. + return mWaitTime.getElapsedTimeF32() > max_wait_time; } void LLWearableHoldingPattern::checkMissingWearables() { - if (!isMostRecent()) - { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; - } - - std::vector<S32> found_by_type(LLWearableType::WT_COUNT,0); - std::vector<S32> requested_by_type(LLWearableType::WT_COUNT,0); - for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) + std::vector<S32> found_by_type(WT_COUNT,0); + std::vector<S32> requested_by_type(WT_COUNT,0); + for (found_list_t::iterator it = mFoundList.begin(); it != mFoundList.end(); ++it) { LLFoundData &data = *it; - if (data.mWearableType < LLWearableType::WT_COUNT) + if (data.mWearableType < WT_COUNT) requested_by_type[data.mWearableType]++; if (data.mWearable) found_by_type[data.mWearableType]++; } - for (S32 type = 0; type < LLWearableType::WT_COUNT; ++type) + for (S32 type = 0; type < WT_COUNT; ++type) { - if (requested_by_type[type] > found_by_type[type]) - { - llwarns << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl; - } + llinfos << "type " << type << " requested " << requested_by_type[type] << " found " << found_by_type[type] << llendl; if (found_by_type[type] > 0) continue; if ( - // If at least one wearable of certain types (pants/shirt/skirt) - // was requested but none was found, create a default asset as a replacement. - // In all other cases, don't do anything. - // For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud - // due to logic in LLVOAvatarSelf::getIsCloud(). - // For non-critical types (tatoo, socks, etc.) the wearable will just be missing. - (requested_by_type[type] > 0) && - ((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT))) + // Need to recover if at least one wearable of that type + // was requested but none was found (prevent missing + // pants) + (requested_by_type[type] > 0) || + // or if type is a body part and no wearables were found. + ((type == WT_SHAPE) || (type == WT_SKIN) || (type == WT_HAIR) || (type == WT_EYES))) { mTypesToRecover.insert(type); mTypesToLink.insert(type); - recoverMissingWearable((LLWearableType::EType)type); + recoverMissingWearable((EWearableType)type); llwarns << "need to replace " << type << llendl; } } - resetTime(60.0F); + mWaitTime.reset(); if (!pollMissingWearables()) { doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); @@ -429,11 +261,6 @@ void LLWearableHoldingPattern::checkMissingWearables() void LLWearableHoldingPattern::onAllComplete() { - if (!isMostRecent()) - { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; - } - // Activate all gestures in this folder if (mGestItems.count() > 0) { @@ -469,31 +296,16 @@ void LLWearableHoldingPattern::onAllComplete() // Only safe to delete if all wearable callbacks and all missing wearables completed. delete this; } - else - { - mIsAllComplete = true; - handleLateArrivals(); - } } void LLWearableHoldingPattern::onFetchCompletion() { - if (!isMostRecent()) - { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; - } - checkMissingWearables(); } // Runs as an idle callback until all wearables are fetched (or we time out). bool LLWearableHoldingPattern::pollFetchCompletion() { - if (!isMostRecent()) - { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; - } - bool completed = isFetchCompleted(); bool timed_out = isTimedOut(); bool done = completed || timed_out; @@ -518,7 +330,7 @@ bool LLWearableHoldingPattern::pollFetchCompletion() class RecoveredItemLinkCB: public LLInventoryCallback { public: - RecoveredItemLinkCB(LLWearableType::EType type, LLWearable *wearable, LLWearableHoldingPattern* holder): + RecoveredItemLinkCB(EWearableType type, LLWearable *wearable, LLWearableHoldingPattern* holder): mHolder(holder), mWearable(wearable), mType(type) @@ -526,13 +338,8 @@ public: } void fire(const LLUUID& item_id) { - if (!mHolder->isMostRecent()) - { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; - } - llinfos << "Recovered item link for type " << mType << llendl; - mHolder->eraseTypeToLink(mType); + mHolder->mTypesToLink.erase(mType); // Add wearable to FoundData for actual wearing LLViewerInventoryItem *item = gInventory.getItem(item_id); LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; @@ -544,14 +351,13 @@ public: if (item) { LLFoundData found(linked_item->getUUID(), - linked_item->getAssetUUID(), - linked_item->getName(), - linked_item->getType(), - linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID, - true // is replacement - ); + linked_item->getAssetUUID(), + linked_item->getName(), + linked_item->getType(), + linked_item->isWearableType() ? linked_item->getWearableType() : WT_INVALID + ); found.mWearable = mWearable; - mHolder->getFoundList().push_front(found); + mHolder->mFoundList.push_front(found); } else { @@ -566,13 +372,13 @@ public: private: LLWearableHoldingPattern* mHolder; LLWearable *mWearable; - LLWearableType::EType mType; + EWearableType mType; }; class RecoveredItemCB: public LLInventoryCallback { public: - RecoveredItemCB(LLWearableType::EType type, LLWearable *wearable, LLWearableHoldingPattern* holder): + RecoveredItemCB(EWearableType type, LLWearable *wearable, LLWearableHoldingPattern* holder): mHolder(holder), mWearable(wearable), mType(type) @@ -580,16 +386,11 @@ public: } void fire(const LLUUID& item_id) { - if (!mHolder->isMostRecent()) - { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; - } - llinfos << "Recovered item for type " << mType << llendl; LLViewerInventoryItem *itemp = gInventory.getItem(item_id); mWearable->setItemID(item_id); LLPointer<LLInventoryCallback> cb = new RecoveredItemLinkCB(mType,mWearable,mHolder); - mHolder->eraseTypeToRecover(mType); + mHolder->mTypesToRecover.erase(mType); llassert(itemp); if (itemp) { @@ -597,7 +398,6 @@ public: item_id, LLAppearanceMgr::instance().getCOF(), itemp->getName(), - itemp->getDescription(), LLAssetType::AT_LINK, cb); } @@ -605,19 +405,14 @@ public: private: LLWearableHoldingPattern* mHolder; LLWearable *mWearable; - LLWearableType::EType mType; + EWearableType mType; }; -void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type) +void LLWearableHoldingPattern::recoverMissingWearable(EWearableType type) { - if (!isMostRecent()) - { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; - } - // Try to recover by replacing missing wearable with a new one. LLNotificationsUtil::add("ReplacedMissingWearable"); - lldebugs << "Wearable " << LLWearableType::getTypeLabel(type) + lldebugs << "Wearable " << LLWearableDictionary::getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << llendl; LLWearable* wearable = LLWearableList::instance().createNewWearable(type); @@ -645,10 +440,10 @@ bool LLWearableHoldingPattern::isMissingCompleted() void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() { - for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) + for (found_list_t::iterator it = mFoundList.begin(); it != mFoundList.end(); ++it) { LLFoundData &data = *it; - if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) + if ((data.mWearableType < WT_COUNT) && (!data.mWearable)) { // Wearable link that was never resolved; remove links to it from COF llinfos << "removing link for unresolved item " << data.mItemID.asString() << llendl; @@ -659,144 +454,33 @@ void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() bool LLWearableHoldingPattern::pollMissingWearables() { - if (!isMostRecent()) - { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; - } - bool timed_out = isTimedOut(); bool missing_completed = isMissingCompleted(); bool done = timed_out || missing_completed; - - if (!done) - { - llinfos << "polling missing wearables, waiting for items " << mTypesToRecover.size() - << " links " << mTypesToLink.size() - << " wearables, timed out " << timed_out - << " elapsed " << mWaitTime.getElapsedTimeF32() - << " done " << done << llendl; - } + + llinfos << "polling missing wearables, waiting for items " << mTypesToRecover.size() + << " links " << mTypesToLink.size() + << " wearables, timed out " << timed_out + << " elapsed " << mWaitTime.getElapsedTimeF32() + << " done " << done << llendl; if (done) { - 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(); + clearCOFLinksForMissingWearables(); onAllComplete(); } return done; } -// Handle wearables that arrived after the timeout period expired. -void LLWearableHoldingPattern::handleLateArrivals() -{ - // Only safe to run if we have previously finished the missing - // wearables and other processing - otherwise we could be in some - // intermediate state - but have not been superceded by a later - // outfit change request. - if (mLateArrivals.size() == 0) - { - // Nothing to process. - return; - } - if (!isMostRecent()) - { - llwarns << "Late arrivals not handled - outfit change no longer valid" << llendl; - } - if (!mIsAllComplete) - { - llwarns << "Late arrivals not handled - in middle of missing wearables processing" << llendl; - } - - llinfos << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << llendl; - - // Update mFoundList using late-arriving wearables. - std::set<LLWearableType::EType> replaced_types; - for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); - iter != getFoundList().end(); ++iter) - { - LLFoundData& data = *iter; - for (std::set<LLWearable*>::iterator wear_it = mLateArrivals.begin(); - wear_it != mLateArrivals.end(); - ++wear_it) - { - LLWearable *wearable = *wear_it; - - if(wearable->getAssetID() == data.mAssetID) - { - data.mWearable = wearable; - - 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)); - break; - } - } - } - - // Remove COF links for any default wearables previously used to replace the late arrivals. - // All this pussyfooting around with a while loop and explicit - // iterator incrementing is to allow removing items from the list - // without clobbering the iterator we're using to navigate. - LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); - while (iter != getFoundList().end()) - { - LLFoundData& data = *iter; - - // If an item of this type has recently shown up, removed the corresponding replacement wearable from COF. - if (data.mWearable && data.mIsReplacement && - replaced_types.find(data.mWearableType) != replaced_types.end()) - { - LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID,false); - std::list<LLFoundData>::iterator clobber_ator = iter; - ++iter; - getFoundList().erase(clobber_ator); - } - else - { - ++iter; - } - } - - // Clear contents of late arrivals. - mLateArrivals.clear(); - - // Update appearance based on mFoundList - LLAppearanceMgr::instance().updateAgentWearables(this, false); -} - -void LLWearableHoldingPattern::resetTime(F32 timeout) -{ - mWaitTime.reset(); - mWaitTime.setTimerExpirySec(timeout); -} - void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable) { - if (!isMostRecent()) + mResolved += 1; // just counting callbacks, not successes. + llinfos << "onWearableAssetFetch, resolved count " << mResolved << " of requested " << mFoundList.size() << llendl; + if (wearable) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + llinfos << "wearable found, type " << wearable->getType() << " asset " << wearable->getAssetID() << llendl; } - - mResolved += 1; // just counting callbacks, not successes. - llinfos << "resolved " << mResolved << "/" << getFoundList().size() << llendl; - if (!wearable) + else { llwarns << "no wearable found" << llendl; } @@ -804,14 +488,6 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable) if (mFired) { llwarns << "called after holder fired" << llendl; - if (wearable) - { - mLateArrivals.insert(wearable); - if (mIsAllComplete) - { - handleLateArrivals(); - } - } return; } @@ -820,20 +496,16 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable) return; } - for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin(); - iter != getFoundList().end(); ++iter) + for (LLWearableHoldingPattern::found_list_t::iterator iter = mFoundList.begin(); + iter != mFoundList.end(); ++iter) { LLFoundData& data = *iter; if(wearable->getAssetID() == data.mAssetID) { - // Failing this means inventory or asset server are corrupted in a way we don't handle. - if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType)) - { - llwarns << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl; - break; - } - data.mWearable = wearable; + // Failing this means inventory or asset server are corrupted in a way we don't handle. + llassert((data.mWearableType < WT_COUNT) && (wearable->getType() == data.mWearableType)); + break; } } } @@ -900,13 +572,6 @@ const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink() const LLViewerInventoryCategory *cat = item->getLinkedCategory(); if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT) { - const LLUUID parent_id = cat->getParentUUID(); - LLViewerInventoryCategory* parent_cat = gInventory.getCategory(parent_id); - // if base outfit moved to trash it means that we don't have base outfit - if (parent_cat != NULL && parent_cat->getPreferredType() == LLFolderType::FT_TRASH) - { - return NULL; - } return item; } } @@ -928,92 +593,6 @@ bool LLAppearanceMgr::getBaseOutfitName(std::string& name) return false; } -const LLUUID LLAppearanceMgr::getBaseOutfitUUID() -{ - const LLViewerInventoryItem* outfit_link = getBaseOutfitLink(); - if (!outfit_link || !outfit_link->getIsLinkType()) return LLUUID::null; - - const LLViewerInventoryCategory* outfit_cat = outfit_link->getLinkedCategory(); - if (!outfit_cat) return LLUUID::null; - - if (outfit_cat->getPreferredType() != LLFolderType::FT_OUTFIT) - { - llwarns << "Expected outfit type:" << LLFolderType::FT_OUTFIT << " but got type:" << outfit_cat->getType() << " for folder name:" << outfit_cat->getName() << llendl; - return LLUUID::null; - } - - return outfit_cat->getUUID(); -} - -bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_update, bool replace, LLPointer<LLInventoryCallback> cb) -{ - if (item_id_to_wear.isNull()) return false; - - // *TODO: issue with multi-wearable should be fixed: - // in this case this method will be called N times - loading started for each item - // and than N times will be called - loading completed for each item. - // That means subscribers will be notified that loading is done after first item in a batch is worn. - // (loading indicator disappears for example before all selected items are worn) - // Have not fix this issue for 2.1 because of stability reason. EXT-7777. - - // Disabled for now because it is *not* acceptable to call updateAppearanceFromCOF() multiple times -// gAgentWearables.notifyLoadingStarted(); - - LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear); - if (!item_to_wear) return false; - - if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID())) - { - LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback(replace); - copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(),cb); - return false; - } - else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID())) - { - return false; // not in library and not in agent's inventory - } - else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH))) - { - LLNotificationsUtil::add("CannotWearTrash"); - return false; - } - else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), LLAppearanceMgr::instance().getCOF())) // EXT-84911 - { - return false; - } - - switch (item_to_wear->getType()) - { - case LLAssetType::AT_CLOTHING: - if (gAgentWearables.areWearablesLoaded()) - { - S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType()); - if ((replace && wearable_count != 0) || - (wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) ) - { - removeCOFItemLinks(gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1), false); - } - addCOFItemLink(item_to_wear, do_update, cb); - } - break; - case LLAssetType::AT_BODYPART: - // TODO: investigate wearables may not be loaded at this point EXT-8231 - - // Remove the existing wearables of the same type. - // Remove existing body parts anyway because we must not be able to wear e.g. two skins. - removeCOFLinksOfType(item_to_wear->getWearableType(), false); - - addCOFItemLink(item_to_wear, do_update, cb); - break; - case LLAssetType::AT_OBJECT: - rez_attachment(item_to_wear, NULL); - break; - default: return false;; - } - - return true; -} - // Update appearance from outfit folder. void LLAppearanceMgr::changeOutfit(bool proceed, const LLUUID& category, bool append) { @@ -1022,90 +601,6 @@ void LLAppearanceMgr::changeOutfit(bool proceed, const LLUUID& category, bool ap LLAppearanceMgr::instance().updateCOF(category,append); } -void LLAppearanceMgr::replaceCurrentOutfit(const LLUUID& new_outfit) -{ - LLViewerInventoryCategory* cat = gInventory.getCategory(new_outfit); - wearInventoryCategory(cat, false, false); -} - -// Open outfit renaming dialog. -void LLAppearanceMgr::renameOutfit(const LLUUID& outfit_id) -{ - LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id); - if (!cat) - { - return; - } - - LLSD args; - args["NAME"] = cat->getName(); - - LLSD payload; - payload["cat_id"] = outfit_id; - - LLNotificationsUtil::add("RenameOutfit", args, payload, boost::bind(onOutfitRename, _1, _2)); -} - -// User typed new outfit name. -// static -void LLAppearanceMgr::onOutfitRename(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) return; // canceled - - std::string outfit_name = response["new_name"].asString(); - LLStringUtil::trim(outfit_name); - if (!outfit_name.empty()) - { - LLUUID cat_id = notification["payload"]["cat_id"].asUUID(); - rename_category(&gInventory, cat_id, outfit_name); - } -} - -void LLAppearanceMgr::setOutfitLocked(bool locked) -{ - if (mOutfitLocked == locked) - { - return; - } - - mOutfitLocked = locked; - if (locked) - { - mUnlockOutfitTimer->reset(); - mUnlockOutfitTimer->start(); - } - else - { - mUnlockOutfitTimer->stop(); - } - - LLOutfitObserver::instance().notifyOutfitLockChanged(); -} - -void LLAppearanceMgr::addCategoryToCurrentOutfit(const LLUUID& cat_id) -{ - LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); - wearInventoryCategory(cat, false, true); -} - -void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id) -{ - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false); - - gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector); - - LLInventoryModel::item_array_t::const_iterator it = items.begin(); - const LLInventoryModel::item_array_t::const_iterator it_end = items.end(); - for( ; it_end != it; ++it) - { - LLViewerInventoryItem* item = *it; - removeItemFromAvatar(item->getUUID()); - } -} - // Create a copy of src_id + contents as a subfolder of dst_id. void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id, LLPointer<LLInventoryCallback> cb) @@ -1116,7 +611,6 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds llwarns << "folder not found for src " << src_id.asString() << llendl; return; } - llinfos << "starting, src_id " << src_id << " name " << src_cat->getName() << " dst_id " << dst_id << llendl; LLUUID parent_id = dst_id; if(parent_id.isNull()) { @@ -1137,7 +631,6 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL LLInventoryModel::cat_array_t* cats; LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(src_id, cats, items); - llinfos << "copying " << items->count() << " items" << llendl; for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); iter != items->end(); ++iter) @@ -1147,13 +640,10 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL { case LLAssetType::AT_LINK: { - //LLInventoryItem::getDescription() is used for a new description - //to propagate ordering information saved in descriptions of links link_inventory_item(gAgent.getID(), item->getLinkedUUID(), dst_id, item->getName(), - item->LLInventoryItem::getDescription(), LLAssetType::AT_LINK, cb); break; } @@ -1167,7 +657,6 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL item->getLinkedUUID(), dst_id, item->getName(), - item->getDescription(), LLAssetType::AT_LINK_FOLDER, cb); } break; @@ -1177,7 +666,6 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL case LLAssetType::AT_BODYPART: case LLAssetType::AT_GESTURE: { - llinfos << "copying inventory item " << item->getName() << llendl; copy_inventory_item(gAgent.getID(), item->getPermissions().getOwner(), item->getUUID(), @@ -1198,10 +686,10 @@ BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id) // These are the wearable items that are required for considering this // folder as containing a complete outfit. U32 required_wearables = 0; - required_wearables |= 1LL << LLWearableType::WT_SHAPE; - required_wearables |= 1LL << LLWearableType::WT_SKIN; - required_wearables |= 1LL << LLWearableType::WT_HAIR; - required_wearables |= 1LL << LLWearableType::WT_EYES; + required_wearables |= 1LL << WT_SHAPE; + required_wearables |= 1LL << WT_SKIN; + required_wearables |= 1LL << WT_HAIR; + required_wearables |= 1LL << WT_EYES; // These are the wearables that the folder actually contains. U32 folder_wearables = 0; @@ -1215,7 +703,7 @@ BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id) const LLViewerInventoryItem* item = (*iter); if (item->isWearableType()) { - const LLWearableType::EType wearable_type = item->getWearableType(); + const EWearableType wearable_type = item->getWearableType(); folder_wearables |= 1LL << wearable_type; } } @@ -1224,92 +712,6 @@ BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id) return ((required_wearables & folder_wearables) == required_wearables); } -bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id) -{ - // Disallow removing the base outfit. - if (outfit_cat_id == getBaseOutfitUUID()) - { - return false; - } - - // Check if the outfit folder itself is removable. - if (!get_is_category_removable(&gInventory, outfit_cat_id)) - { - return false; - } - - // Check for the folder's non-removable descendants. - LLFindNonRemovableObjects filter_non_removable; - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLInventoryModel::item_array_t::const_iterator it; - gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_non_removable); - if (!cats.empty() || !items.empty()) - { - return false; - } - - return true; -} - -// static -bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) -{ - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - is_worn); - return items.size() > 0; -} - -// static -bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id) -{ - if (gAgentWearables.isCOFChangeInProgress()) - { - return false; - } - - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - not_worn); - return items.size() > 0; -} - -bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) -{ - // Don't allow wearing anything while we're changing appearance. - if (gAgentWearables.isCOFChangeInProgress()) - { - return false; - } - - // Check whether it's the base outfit. - if (outfit_cat_id.isNull() || outfit_cat_id == getBaseOutfitUUID()) - { - return false; - } - - // Check whether the outfit contains any non-worn wearables. - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ true); - gInventory.collectDescendentsIf(outfit_cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - not_worn); - return items.size() > 0; -} void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category) { @@ -1357,12 +759,25 @@ void LLAppearanceMgr::filterWearableItems( LLInventoryModel::item_array_t& items, S32 max_per_type) { // Divvy items into arrays by wearable type. - std::vector<LLInventoryModel::item_array_t> items_by_type(LLWearableType::WT_COUNT); - divvyWearablesByType(items, items_by_type); + std::vector<LLInventoryModel::item_array_t> items_by_type(WT_COUNT); + for (S32 i=0; i<items.count(); i++) + { + LLViewerInventoryItem *item = items.get(i); + // Ignore non-wearables. + if (!item->isWearableType()) + continue; + EWearableType type = item->getWearableType(); + if(type < 0 || type >= WT_COUNT) + { + LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; + continue; + } + items_by_type[type].push_back(item); + } // rebuild items list, retaining the last max_per_type of each array items.clear(); - for (S32 i=0; i<LLWearableType::WT_COUNT; i++) + for (S32 i=0; i<WT_COUNT; i++) { S32 size = items_by_type[i].size(); if (size <= 0) @@ -1376,7 +791,7 @@ void LLAppearanceMgr::filterWearableItems( } // Create links to all listed items. -void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid, +void LLAppearanceMgr::linkAll(const LLUUID& category, LLInventoryModel::item_array_t& items, LLPointer<LLInventoryCallback> cb) { @@ -1385,17 +800,10 @@ void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid, const LLInventoryItem* item = items.get(i).get(); link_inventory_item(gAgent.getID(), item->getLinkedUUID(), - cat_uuid, + category, item->getName(), - item->LLInventoryItem::getDescription(), LLAssetType::AT_LINK, cb); - - const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid); - const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; -#ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << llendl; -#endif } } @@ -1425,12 +833,9 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // - Body parts: always include COF contents as a fallback in case any // required parts are missing. - // Preserve body parts from COF if appending. LLInventoryModel::item_array_t body_items; getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false); getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); - if (append) - reverse(body_items.begin(), body_items.end()); // Reduce body items to max of one per type. removeDuplicateItems(body_items); filterWearableItems(body_items, 1); @@ -1442,7 +847,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false); // Reduce wearables to max of one per type. removeDuplicateItems(wear_items); - filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE); + filterWearableItems(wear_items, 5); // - Attachments: include COF contents only if appending. LLInventoryModel::item_array_t obj_items; @@ -1465,26 +870,11 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append) // Create links to new COF contents. llinfos << "creating LLUpdateAppearanceOnDestroy" << llendl; - LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(!append); + LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; -#ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking body items" << llendl; -#endif linkAll(cof, body_items, link_waiter); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking wear items" << llendl; -#endif linkAll(cof, wear_items, link_waiter); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking obj items" << llendl; -#endif linkAll(cof, obj_items, link_waiter); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking gesture items" << llendl; -#endif linkAll(cof, gest_items, link_waiter); // Add link to outfit if category is an outfit. @@ -1515,7 +905,7 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLI if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) { - link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "", + link_inventory_item(gAgent.getID(), category, cof, catp->getName(), LLAssetType::AT_LINK_FOLDER, link_waiter); new_outfit_name = catp->getName(); } @@ -1529,17 +919,19 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo LLInventoryItem::item_array_t items; LLDynamicArray< LLWearable* > wearables; - // For each wearable type, find the wearables of that type. - for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) + // For each wearable type, find the first instance in the category + // that we recursed through. + for( S32 i = 0; i < WT_COUNT; i++ ) { - for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->getFoundList().begin(); - iter != holder->getFoundList().end(); ++iter) + for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin(); + iter != holder->mFoundList.end(); ++iter) { LLFoundData& data = *iter; LLWearable* wearable = data.mWearable; if( wearable && ((S32)wearable->getType() == i) ) { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); if( item && (item->getAssetUUID() == wearable->getAssetID()) ) { items.put(item); @@ -1573,104 +965,15 @@ static void remove_non_link_items(LLInventoryModel::item_array_t &items) items = pruned_items; } -//a predicate for sorting inventory items by actual descriptions -bool sort_by_description(const LLInventoryItem* item1, const LLInventoryItem* item2) -{ - if (!item1 || !item2) - { - llwarning("either item1 or item2 is NULL", 0); - return true; - } - - return item1->LLInventoryItem::getDescription() < item2->LLInventoryItem::getDescription(); -} - -void item_array_diff(LLInventoryModel::item_array_t& full_list, - LLInventoryModel::item_array_t& keep_list, - LLInventoryModel::item_array_t& kill_list) - -{ - for (LLInventoryModel::item_array_t::iterator it = full_list.begin(); - it != full_list.end(); - ++it) - { - LLViewerInventoryItem *item = *it; - if (keep_list.find(item) < 0) // Why on earth does LLDynamicArray need to redefine find()? - { - kill_list.push_back(item); - } - } -} - -void LLAppearanceMgr::enforceItemCountLimits() -{ - S32 purge_count = 0; - - LLInventoryModel::item_array_t body_items; - getDescendentsOfAssetType(getCOF(), body_items, LLAssetType::AT_BODYPART, false); - LLInventoryModel::item_array_t curr_body_items = body_items; - removeDuplicateItems(body_items); - filterWearableItems(body_items, 1); - LLInventoryModel::item_array_t kill_body_items; - item_array_diff(curr_body_items,body_items,kill_body_items); - for (LLInventoryModel::item_array_t::iterator it = kill_body_items.begin(); - it != kill_body_items.end(); - ++it) - { - LLViewerInventoryItem *item = *it; - llinfos << "purging dup body part " << item->getName() << llendl; - gInventory.purgeObject(item->getUUID()); - purge_count++; - } - - LLInventoryModel::item_array_t wear_items; - getDescendentsOfAssetType(getCOF(), wear_items, LLAssetType::AT_CLOTHING, false); - LLInventoryModel::item_array_t curr_wear_items = wear_items; - removeDuplicateItems(wear_items); - filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE); - LLInventoryModel::item_array_t kill_wear_items; - item_array_diff(curr_wear_items,wear_items,kill_wear_items); - for (LLInventoryModel::item_array_t::iterator it = kill_wear_items.begin(); - it != kill_wear_items.end(); - ++it) - { - LLViewerInventoryItem *item = *it; - llinfos << "purging excess clothing item " << item->getName() << llendl; - gInventory.purgeObject(item->getUUID()); - purge_count++; - } - - if (purge_count>0) - { - gInventory.notifyObservers(); - } -} - -void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) +void LLAppearanceMgr::updateAppearanceFromCOF() { - if (mIsInUpdateAppearanceFromCOF) - { - llwarns << "Called updateAppearanceFromCOF inside updateAppearanceFromCOF, skipping" << llendl; - return; - } - - BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); - - llinfos << "starting" << llendl; - - //checking integrity of the COF in terms of ordering of wearables, - //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) - updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering); - - // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but - // this should catch anything that gets through. - enforceItemCountLimits(); - // update dirty flag to see if the state of the COF matches // the saved outfit stored as a folder link + llinfos << "starting" << llendl; + updateIsDirty(); - //dumpCat(getCOF(),"COF, start"); + dumpCat(getCOF(),"COF, start"); bool follow_folder_links = true; LLUUID current_outfit_id = getCOF(); @@ -1686,23 +989,16 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) remove_non_link_items(obj_items); remove_non_link_items(gest_items); - dumpItemArray(wear_items,"asset_dump: wear_item"); - dumpItemArray(obj_items,"asset_dump: obj_item"); - if(!wear_items.count()) { LLNotificationsUtil::add("CouldNotPutOnOutfit"); return; } - //preparing the list of wearables in the correct order for LLAgentWearables - sortItemsByActualDescription(wear_items); - - LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; - holder->setObjItems(obj_items); - holder->setGestItems(gest_items); + holder->mObjItems = obj_items; + holder->mGestItems = gest_items; // Note: can't do normal iteration, because if all the // wearables can be resolved immediately, then the @@ -1713,27 +1009,27 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) { LLViewerInventoryItem *item = wear_items.get(i); LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - - // Fault injection: use debug setting to test asset - // fetch failures (should be replaced by new defaults in - // lost&found). - U32 skip_type = gSavedSettings.getU32("ForceAssetFail"); - if (item && item->getIsLinkType() && linked_item) { LLFoundData found(linked_item->getUUID(), linked_item->getAssetUUID(), linked_item->getName(), linked_item->getType(), - linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID + linked_item->isWearableType() ? linked_item->getWearableType() : WT_INVALID ); - if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) +#if 0 + // Fault injection: uncomment this block to test asset + // fetch failures (should be replaced by new defaults in + // lost&found). + if (found.mWearableType == WT_SHAPE || found.mWearableType == WT_JACKET) { found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB + } - //pushing back, not front, to preserve order of wearables for LLAgentWearables - holder->getFoundList().push_back(found); +#endif + + holder->mFoundList.push_front(found); } else { @@ -1748,12 +1044,12 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) } } - for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin(); - it != holder->getFoundList().end(); ++it) + for (LLWearableHoldingPattern::found_list_t::iterator it = holder->mFoundList.begin(); + it != holder->mFoundList.end(); ++it) { LLFoundData& found = *it; - lldebugs << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl; + llinfos << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl; // Fetch the wearables about to be worn. LLWearableList::instance().getAsset(found.mAssetID, @@ -1764,7 +1060,6 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) } - holder->resetTime(gSavedSettings.getF32("MaxWearableWaitTime")); if (!holder->pollFetchCompletion()) { doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder)); @@ -1825,14 +1120,12 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool { if(!category) return; - gAgentWearables.notifyLoadingStarted(); - llinfos << "wearInventoryCategory( " << category->getName() << " )" << llendl; - callAfterCategoryFetch(category->getUUID(), boost::bind(&LLAppearanceMgr::wearCategoryFinal, - &LLAppearanceMgr::instance(), - category->getUUID(), copy, append)); + callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, + &LLAppearanceMgr::instance(), + category->getUUID(), copy, append)); } void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append) @@ -1923,13 +1216,16 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego llinfos << "wearInventoryCategoryOnAvatar( " << category->getName() << " )" << llendl; - if (gAgentCamera.cameraCustomizeAvatar()) + if( gFloaterCustomize ) { - // switching to outfit editor should automagically save any currently edited wearable - LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit")); + gFloaterCustomize->askToSaveIfDirty(boost::bind(&LLAppearanceMgr::changeOutfit, + &LLAppearanceMgr::instance(), + _1, category->getUUID(), append)); + } + else + { + LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } - - LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } void LLAppearanceMgr::wearOutfitByName(const std::string& name) @@ -1988,10 +1284,9 @@ bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventor class LLDeferredCOFLinkObserver: public LLInventoryObserver { public: - LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update, LLPointer<LLInventoryCallback> cb = NULL): + LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update): mItemID(item_id), - mDoUpdate(do_update), - mCallback(cb) + mDoUpdate(do_update) { } @@ -2005,7 +1300,7 @@ public: if (item) { gInventory.removeObserver(this); - LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate,mCallback); + LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate); delete this; } } @@ -2013,27 +1308,26 @@ public: private: const LLUUID mItemID; bool mDoUpdate; - LLPointer<LLInventoryCallback> mCallback; }; // BAP - note that this runs asynchronously if the item is not already loaded from inventory. // Dangerous if caller assumes link will exist after calling the function. -void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update, LLPointer<LLInventoryCallback> cb) +void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update ) { const LLInventoryItem *item = gInventory.getItem(item_id); if (!item) { - LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update, cb); + LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update); gInventory.addObserver(observer); } else { - addCOFItemLink(item, do_update, cb); + addCOFItemLink(item, do_update); } } -void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update, LLPointer<LLInventoryCallback> cb) +void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update ) { const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item); if (!vitem) @@ -2051,39 +1345,25 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update item_array, LLInventoryModel::EXCLUDE_TRASH); bool linked_already = false; - U32 count = 0; for (S32 i=0; i<item_array.count(); i++) { // Are these links to the same object? const LLViewerInventoryItem* inv_item = item_array.get(i).get(); - const LLWearableType::EType wearable_type = inv_item->getWearableType(); - - const bool is_body_part = (wearable_type == LLWearableType::WT_SHAPE) - || (wearable_type == LLWearableType::WT_HAIR) - || (wearable_type == LLWearableType::WT_EYES) - || (wearable_type == LLWearableType::WT_SKIN); - if (inv_item->getLinkedUUID() == vitem->getLinkedUUID()) { linked_already = true; } - // Are these links to different items of the same body part + // Are these links to different items of the same wearable // type? If so, new item will replace old. - else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type)) + // MULTI-WEARABLES: revisit if more than one per type is allowed. + else if (areMatchingWearables(vitem,inv_item)) { - ++count; - if (is_body_part && inv_item->getIsLinkType() && (vitem->getWearableType() == wearable_type)) - { - gInventory.purgeObject(inv_item->getUUID()); - } - else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) + if (inv_item->getIsLinkType()) { - // MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE gInventory.purgeObject(inv_item->getUUID()); } } } - if (linked_already) { if (do_update) @@ -2094,16 +1374,11 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update } else { - if(do_update && cb.isNull()) - { - cb = new ModifiedCOFCallback; - } - const std::string description = vitem->getIsLinkType() ? vitem->getDescription() : ""; + LLPointer<LLInventoryCallback> cb = do_update ? new ModifiedCOFCallback : 0; link_inventory_item( gAgent.getID(), vitem->getLinkedUUID(), getCOF(), vitem->getName(), - description, LLAssetType::AT_LINK, cb); } @@ -2120,7 +1395,6 @@ void LLAppearanceMgr::addEnsembleLink( LLInventoryCategory* cat, bool do_update cat->getLinkedUUID(), getCOF(), cat->getName(), - cat->getDescription(), LLAssetType::AT_LINK_FOLDER, cb); #endif @@ -2150,40 +1424,6 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, bool do_update) } } -void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, bool do_update) -{ - LLFindWearablesOfType filter_wearables_of_type(type); - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLInventoryModel::item_array_t::const_iterator it; - - gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); - for (it = items.begin(); it != items.end(); ++it) - { - const LLViewerInventoryItem* item = *it; - if (item->getIsLinkType()) // we must operate on links only - { - gInventory.purgeObject(item->getUUID()); - } - } - - if (do_update) - { - updateAppearanceFromCOF(); - } -} - -bool sort_by_linked_uuid(const LLViewerInventoryItem* item1, const LLViewerInventoryItem* item2) -{ - if (!item1 || !item2) - { - llwarning("item1, item2 cannot be null, something is very wrong", 0); - return true; - } - - return item1->getLinkedUUID() < item2->getLinkedUUID(); -} - void LLAppearanceMgr::updateIsDirty() { LLUUID cof = getCOF(); @@ -2208,45 +1448,48 @@ void LLAppearanceMgr::updateIsDirty() } else { - LLIsOfAssetType collector = LLIsOfAssetType(LLAssetType::AT_LINK); - LLInventoryModel::cat_array_t cof_cats; LLInventoryModel::item_array_t cof_items; - gInventory.collectDescendentsIf(cof, cof_cats, cof_items, - LLInventoryModel::EXCLUDE_TRASH, collector); + gInventory.collectDescendents(cof, cof_cats, cof_items, + LLInventoryModel::EXCLUDE_TRASH); LLInventoryModel::cat_array_t outfit_cats; LLInventoryModel::item_array_t outfit_items; - gInventory.collectDescendentsIf(base_outfit, outfit_cats, outfit_items, - LLInventoryModel::EXCLUDE_TRASH, collector); + gInventory.collectDescendents(base_outfit, outfit_cats, outfit_items, + LLInventoryModel::EXCLUDE_TRASH); - if(outfit_items.count() != cof_items.count()) + if(outfit_items.count() != cof_items.count() -1) { // Current outfit folder should have one more item than the outfit folder. // this one item is the link back to the outfit folder itself. mOutfitIsDirty = true; - return; } - - //"dirty" - also means a difference in linked UUIDs and/or a difference in wearables order (links' descriptions) - std::sort(cof_items.begin(), cof_items.end(), sort_by_linked_uuid); - std::sort(outfit_items.begin(), outfit_items.end(), sort_by_linked_uuid); - - for (U32 i = 0; i < cof_items.size(); ++i) + else { - LLViewerInventoryItem *item1 = cof_items.get(i); - LLViewerInventoryItem *item2 = outfit_items.get(i); + typedef std::set<LLUUID> item_set_t; + item_set_t cof_set; + item_set_t outfit_set; - if (item1->getLinkedUUID() != item2->getLinkedUUID() || - item1->getName() != item2->getName() || - item1->LLInventoryItem::getDescription() != item2->LLInventoryItem::getDescription()) + // sort COF items by UUID + for (S32 i = 0; i < cof_items.count(); ++i) { - mOutfitIsDirty = true; - return; + LLViewerInventoryItem *item = cof_items.get(i); + // don't add the base outfit link to the list of objects we're comparing + if(item != base_outfit_item) + { + cof_set.insert(item->getLinkedUUID()); + } } - } - mOutfitIsDirty = false; + // sort outfit folder by UUID + for (S32 i = 0; i < outfit_items.count(); ++i) + { + LLViewerInventoryItem *item = outfit_items.get(i); + outfit_set.insert(item->getLinkedUUID()); + } + + mOutfitIsDirty = (outfit_set != cof_set); + } } } @@ -2270,331 +1513,9 @@ void LLAppearanceMgr::autopopulateOutfits() // Handler for anything that's deferred until avatar de-clouds. void LLAppearanceMgr::onFirstFullyVisible() { - gAgentAvatarp->debugAvatarVisible(); autopopulateOutfits(); } -bool LLAppearanceMgr::updateBaseOutfit() -{ - if (isOutfitLocked()) - { - // don't allow modify locked outfit - llassert(!isOutfitLocked()); - return false; - } - setOutfitLocked(true); - - gAgentWearables.notifyLoadingStarted(); - - const LLUUID base_outfit_id = getBaseOutfitUUID(); - if (base_outfit_id.isNull()) return false; - - updateClothingOrderingInfo(); - - // in a Base Outfit we do not remove items, only links - purgeCategory(base_outfit_id, false); - - - LLPointer<LLInventoryCallback> dirty_state_updater = new LLUpdateDirtyState(); - - //COF contains only links so we copy to the Base Outfit only links - shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater); - - return true; -} - -void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type) -{ - items_by_type.reserve(LLWearableType::WT_COUNT); - if (items.empty()) return; - - for (S32 i=0; i<items.count(); i++) - { - LLViewerInventoryItem *item = items.get(i); - // Ignore non-wearables. - if (!item->isWearableType()) - continue; - LLWearableType::EType type = item->getWearableType(); - if(type < 0 || type >= LLWearableType::WT_COUNT) - { - LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; - continue; - } - items_by_type[type].push_back(item); - } -} - -std::string build_order_string(LLWearableType::EType type, U32 i) -{ - std::ostringstream order_num; - order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i; - return order_num.str(); -} - -struct WearablesOrderComparator -{ - WearablesOrderComparator(const LLWearableType::EType type) - { - mControlSize = build_order_string(type, 0).size(); - }; - - bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2) - { - if (!item1 || !item2) - { - llwarning("either item1 or item2 is NULL", 0); - return true; - } - - const std::string& desc1 = item1->LLInventoryItem::getDescription(); - const std::string& desc2 = item2->LLInventoryItem::getDescription(); - - bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]); - bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]); - - if (item1_valid && item2_valid) - return desc1 < desc2; - - //we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions, - //items with ordering information but not for the associated wearables type - if (!item1_valid && item2_valid) - return false; - - return true; - } - - U32 mControlSize; -}; - -void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base_outfit_ordering) -{ - if (cat_id.isNull()) - { - cat_id = getCOF(); - if (update_base_outfit_ordering) - { - const LLUUID base_outfit_id = getBaseOutfitUUID(); - if (base_outfit_id.notNull()) - { - updateClothingOrderingInfo(base_outfit_id,false); - } - } - } - - // COF is processed if cat_id is not specified - LLInventoryModel::item_array_t wear_items; - getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING, false); - - wearables_by_type_t items_by_type(LLWearableType::WT_COUNT); - divvyWearablesByType(wear_items, items_by_type); - - bool inventory_changed = false; - for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++) - { - - U32 size = items_by_type[type].size(); - if (!size) continue; - - //sinking down invalid items which need reordering - std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type)); - - //requesting updates only for those links which don't have "valid" descriptions - for (U32 i = 0; i < size; i++) - { - LLViewerInventoryItem* item = items_by_type[type][i]; - if (!item) continue; - - std::string new_order_str = build_order_string((LLWearableType::EType)type, i); - if (new_order_str == item->LLInventoryItem::getDescription()) continue; - - item->setDescription(new_order_str); - item->setComplete(TRUE); - item->updateServer(FALSE); - gInventory.updateItem(item); - - inventory_changed = true; - } - } - - //*TODO do we really need to notify observers? - if (inventory_changed) gInventory.notifyObservers(); -} - - - - -class LLShowCreatedOutfit: public LLInventoryCallback -{ -public: - LLShowCreatedOutfit(LLUUID& folder_id, bool show_panel = true): mFolderID(folder_id), mShowPanel(show_panel) - {} - - virtual ~LLShowCreatedOutfit() - { - LLSD key; - - //EXT-7727. For new accounts LLShowCreatedOutfit is created during login process - // add may be processed after login process is finished - if (mShowPanel) - { - LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key); - } - LLOutfitsList *outfits_list = - dynamic_cast<LLOutfitsList*>(LLSideTray::getInstance()->getPanel("outfitslist_tab")); - if (outfits_list) - { - outfits_list->setSelectedOutfitByUUID(mFolderID); - } - - LLAppearanceMgr::getInstance()->updateIsDirty(); - gAgentWearables.notifyLoadingFinished(); // New outfit is saved. - LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); - } - - virtual void fire(const LLUUID&) - {} - -private: - LLUUID mFolderID; - bool mShowPanel; -}; - -LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel) -{ - if (!isAgentAvatarValid()) return LLUUID::null; - - gAgentWearables.notifyLoadingStarted(); - - // First, make a folder in the My Outfits directory. - const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - LLUUID folder_id = gInventory.createNewCategory( - parent_id, - LLFolderType::FT_OUTFIT, - new_folder_name); - - updateClothingOrderingInfo(); - - LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id,show_panel); - shallowCopyCategoryContents(getCOF(),folder_id, cb); - createBaseOutfitLink(folder_id, cb); - - dumpCat(folder_id,"COF, new outfit"); - - return folder_id; -} - -void LLAppearanceMgr::wearBaseOutfit() -{ - const LLUUID& base_outfit_id = getBaseOutfitUUID(); - if (base_outfit_id.isNull()) return; - - updateCOF(base_outfit_id); -} - -void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) -{ - LLViewerInventoryItem * item_to_remove = gInventory.getItem(id_to_remove); - if (!item_to_remove) return; - - switch (item_to_remove->getType()) - { - case LLAssetType::AT_CLOTHING: - if (get_is_item_worn(id_to_remove)) - { - //*TODO move here the exact removing code from LLWearableBridge::removeItemFromAvatar in the future - LLWearableBridge::removeItemFromAvatar(item_to_remove); - } - break; - case LLAssetType::AT_OBJECT: - gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_to_remove->getLinkedUUID()); - gMessageSystem->sendReliable( gAgent.getRegion()->getHost()); - - { - // this object might have been selected, so let the selection manager know it's gone now - LLViewerObject *found_obj = gObjectList.findObject(item_to_remove->getLinkedUUID()); - if (found_obj) - { - LLSelectMgr::getInstance()->remove(found_obj); - }; - } - default: break; - } - - // *HACK: Force to remove garbage from COF. - // Unworn links or objects can't be processed by existed removing functionality - // since it is not designed for such cases. As example attachment object can't be removed - // since sever don't sends message _PREHASH_KillObject in that case. - // Also we can't check is link was successfully removed from COF since in case - // deleting attachment link removing performs asynchronously in process_kill_object callback. - removeCOFItemLinks(id_to_remove,false); -} - -bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body) -{ - if (!item || !item->isWearableType()) return false; - if (item->getType() != LLAssetType::AT_CLOTHING) return false; - if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false; - - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesOfType filter_wearables_of_type(item->getWearableType()); - gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type); - if (items.empty()) return false; - - // We assume that the items have valid descriptions. - std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType())); - - if (closer_to_body && items.front() == item) return false; - if (!closer_to_body && items.back() == item) return false; - - LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item); - if (items.end() == it) return false; - - - //swapping descriptions - closer_to_body ? --it : ++it; - LLViewerInventoryItem* swap_item = *it; - if (!swap_item) return false; - std::string tmp = swap_item->LLInventoryItem::getDescription(); - swap_item->setDescription(item->LLInventoryItem::getDescription()); - item->setDescription(tmp); - - - //items need to be updated on a dataserver - item->setComplete(TRUE); - item->updateServer(FALSE); - gInventory.updateItem(item); - - swap_item->setComplete(TRUE); - swap_item->updateServer(FALSE); - gInventory.updateItem(swap_item); - - //to cause appearance of the agent to be updated - bool result = false; - if (result = gAgentWearables.moveWearable(item, closer_to_body)) - { - gAgentAvatarp->wearableUpdated(item->getWearableType(), FALSE); - } - - setOutfitDirty(true); - - //*TODO do we need to notify observers here in such a way? - gInventory.notifyObservers(); - - return result; -} - -//static -void LLAppearanceMgr::sortItemsByActualDescription(LLInventoryModel::item_array_t& items) -{ - if (items.size() < 2) return; - - std::sort(items.begin(), items.end(), sort_by_description); -} - //#define DUMP_CAT_VERBOSE void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg) @@ -2621,33 +1542,19 @@ void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg) void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items, const std::string& msg) { + llinfos << msg << llendl; for (S32 i=0; i<items.count(); i++) { LLViewerInventoryItem *item = items.get(i); - LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - LLUUID asset_id; - if (linked_item) - { - asset_id = linked_item->getAssetUUID(); - } - llinfos << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << llendl; + llinfos << i <<" " << item->getName() << llendl; } llinfos << llendl; } LLAppearanceMgr::LLAppearanceMgr(): mAttachmentInvLinkEnabled(false), - mOutfitIsDirty(false), - mIsInUpdateAppearanceFromCOF(false) + mOutfitIsDirty(false) { - LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); - - // unlock outfit on save operation completed - outfit_observer.addCOFSavedCallback(boost::bind( - &LLAppearanceMgr::setOutfitLocked, this, false)); - - mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32( - "OutfitOperationsTimeout"))); } LLAppearanceMgr::~LLAppearanceMgr() @@ -2685,9 +1592,6 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id) if (mAttachmentInvLinkEnabled) { - // we have to pass do_update = true to call LLAppearanceMgr::updateAppearanceFromCOF. - // it will trigger gAgentWariables.notifyLoadingFinished() - // But it is not acceptable solution. See EXT-7777 LLAppearanceMgr::addCOFItemLink(item_id, false); // Add COF link for item. } else @@ -2728,21 +1632,6 @@ BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const return gInventory.isObjectDescendentOf(obj_id, getCOF()); } -// static -bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id) -{ - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id)); - gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - find_links); - - return !items.empty(); -} - BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const { if (!getIsInCOF(obj_id)) return FALSE; @@ -2770,192 +1659,3 @@ BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const return FALSE; */ } - -// Shim class to allow arbitrary boost::bind -// expressions to be run as one-time idle callbacks. -// -// TODO: rework idle function spec to take a boost::function in the first place. -class OnIdleCallbackOneTime -{ -public: - OnIdleCallbackOneTime(nullary_func_t callable): - mCallable(callable) - { - } - static void onIdle(void *data) - { - gIdleCallbacks.deleteFunction(onIdle, data); - OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data); - self->call(); - delete self; - } - void call() - { - mCallable(); - } -private: - nullary_func_t mCallable; -}; - -void doOnIdleOneTime(nullary_func_t callable) -{ - OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor); -} - -// Shim class to allow generic boost functions to be run as -// recurring idle callbacks. Callable should return true when done, -// false to continue getting called. -// -// TODO: rework idle function spec to take a boost::function in the first place. -class OnIdleCallbackRepeating -{ -public: - OnIdleCallbackRepeating(bool_func_t callable): - mCallable(callable) - { - } - // Will keep getting called until the callable returns true. - static void onIdle(void *data) - { - OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data); - bool done = self->call(); - if (done) - { - gIdleCallbacks.deleteFunction(onIdle, data); - delete self; - } - } - bool call() - { - return mCallable(); - } -private: - bool_func_t mCallable; -}; - -void doOnIdleRepeating(bool_func_t callable) -{ - OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); -} - -class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver -{ -public: - CallAfterCategoryFetchStage2(const uuid_vec_t& ids, - nullary_func_t callable) : - LLInventoryFetchItemsObserver(ids), - mCallable(callable) - { - } - ~CallAfterCategoryFetchStage2() - { - } - virtual void done() - { - llinfos << this << " done with incomplete " << mIncomplete.size() - << " complete " << mComplete.size() << " calling callable" << llendl; - - gInventory.removeObserver(this); - doOnIdleOneTime(mCallable); - delete this; - } -protected: - nullary_func_t mCallable; -}; - -class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver -{ -public: - CallAfterCategoryFetchStage1(const LLUUID& cat_id, nullary_func_t callable) : - LLInventoryFetchDescendentsObserver(cat_id), - mCallable(callable) - { - } - ~CallAfterCategoryFetchStage1() - { - } - virtual void done() - { - // What we do here is get the complete information on the items in - // the library, and set up an observer that will wait for that to - // happen. - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(mComplete.front(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH); - S32 count = item_array.count(); - if(!count) - { - llwarns << "Nothing fetched in category " << mComplete.front() - << llendl; - //dec_busy_count(); - gInventory.removeObserver(this); - - // lets notify observers that loading is finished. - gAgentWearables.notifyLoadingFinished(); - delete this; - return; - } - - llinfos << "stage1 got " << item_array.count() << " items, passing to stage2 " << llendl; - uuid_vec_t ids; - for(S32 i = 0; i < count; ++i) - { - ids.push_back(item_array.get(i)->getUUID()); - } - - gInventory.removeObserver(this); - - // do the fetch - CallAfterCategoryFetchStage2 *stage2 = new CallAfterCategoryFetchStage2(ids, mCallable); - stage2->startFetch(); - if(stage2->isFinished()) - { - // everything is already here - call done. - stage2->done(); - } - else - { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(stage2); - } - delete this; - } -protected: - nullary_func_t mCallable; -}; - -void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb) -{ - CallAfterCategoryFetchStage1 *stage1 = new CallAfterCategoryFetchStage1(cat_id, cb); - stage1->startFetch(); - if (stage1->isFinished()) - { - stage1->done(); - } - else - { - gInventory.addObserver(stage1); - } -} - -void wear_multiple(const uuid_vec_t& ids, bool replace) -{ - LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; - - bool first = true; - uuid_vec_t::const_iterator it; - for (it = ids.begin(); it != ids.end(); ++it) - { - // if replace is requested, the first item worn will replace the current top - // item, and others will be added. - LLAppearanceMgr::instance().wearItemOnAvatar(*it,false,first && replace,cb); - first = false; - } -} - |