diff options
Diffstat (limited to 'indra/newview/llagentwearables.cpp')
-rw-r--r-- | indra/newview/llagentwearables.cpp | 802 |
1 files changed, 413 insertions, 389 deletions
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index b9a0b4293d..0542e73bfd 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -31,64 +31,72 @@ */ #include "llviewerprecompiledheaders.h" - -#include "llagent.h" #include "llagentwearables.h" +#include "llaccordionctrltab.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llagentwearablesfetch.h" +#include "llappearancemgr.h" +#include "llcallbacklist.h" #include "llfloatercustomize.h" -#include "llfloaterinventory.h" +#include "llfolderview.h" +#include "llgesturemgr.h" #include "llinventorybridge.h" -#include "llinventorymodel.h" -#include "llnotify.h" +#include "llinventoryfunctions.h" +#include "llinventoryobserver.h" +#include "llinventorypanel.h" +#include "llmd5.h" +#include "llnotificationsutil.h" +#include "llpaneloutfitsinventory.h" +#include "llsidetray.h" +#include "lltexlayer.h" #include "llviewerregion.h" #include "llvoavatarself.h" #include "llwearable.h" #include "llwearablelist.h" -#include "llgesturemgr.h" -#include "llappearancemgr.h" -#include "lltexlayer.h" #include <boost/scoped_ptr.hpp> -#define USE_CURRENT_OUTFIT_FOLDER - -//-------------------------------------------------------------------- -// Classes for fetching initial wearables data -//-------------------------------------------------------------------- -// Outfit folder fetching callback structure. -class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver -{ -public: - LLInitialWearablesFetch() {} - ~LLInitialWearablesFetch() {} - virtual void done(); - - struct InitialWearableData - { - EWearableType mType; - LLUUID mItemID; - LLUUID mAssetID; - InitialWearableData(EWearableType type, LLUUID& itemID, LLUUID& assetID) : - mType(type), - mItemID(itemID), - mAssetID(assetID) - {} - }; - - typedef std::vector<InitialWearableData> initial_wearable_data_vec_t; - initial_wearable_data_vec_t mCOFInitialWearables; // Wearables from the Current Outfit Folder - initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg - -protected: - void processWearablesMessage(); -}; - LLAgentWearables gAgentWearables; BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE; using namespace LLVOAvatarDefines; +// HACK: For EXT-3923: Pants item shows in inventory with skin icon and messes with "current look" +// Some db items are corrupted, have inventory flags = 0, implying wearable type = shape, even though +// wearable type stored in asset is some other value. +// Calling this function whenever a wearable is added to increase visibility if this problem +// turns up in other inventories. +void checkWearableAgainstInventory(LLWearable *wearable) +{ + if (wearable->getItemID().isNull()) + return; + + // Check for wearable type consistent with inventory item wearable type. + LLViewerInventoryItem *item = gInventory.getItem(wearable->getItemID()); + if (item) + { + if (!item->isWearableType()) + { + llwarns << "wearable associated with non-wearable item" << llendl; + } + if (item->getWearableType() != wearable->getType()) + { + llwarns << "type mismatch: wearable " << wearable->getName() + << " has type " << wearable->getType() + << " but inventory item " << item->getName() + << " has type " << item->getWearableType() << llendl; + } + } + else + { + llwarns << "wearable inventory item not found" << wearable->getName() + << " itemID " << wearable->getItemID().asString() << llendl; + } +} + void LLAgentWearables::dump() { llinfos << "LLAgentWearablesDump" << llendl; @@ -139,8 +147,7 @@ struct LLAgentDumper }; LLAgentWearables::LLAgentWearables() : - mWearablesLoaded(FALSE), - mAvatarObject(NULL) + mWearablesLoaded(FALSE) { } @@ -151,12 +158,10 @@ LLAgentWearables::~LLAgentWearables() void LLAgentWearables::cleanup() { - mAvatarObject = NULL; } void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar) { - mAvatarObject = avatar; if (avatar) { sendAgentWearablesRequest(); @@ -166,6 +171,7 @@ void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar) // wearables LLAgentWearables::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback() { + llinfos << "destructor - all done?" << llendl; gAgentWearables.createStandardWearablesAllDone(); } @@ -192,10 +198,16 @@ LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInvento mTodo(todo), mCB(cb) { + llinfos << "constructor" << llendl; } void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) { + if (mTodo & CALL_CREATESTANDARDDONE) + { + llinfos << "callback fired, inv_item " << inv_item.asString() << llendl; + } + if (inv_item.isNull()) return; @@ -207,6 +219,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i } if (mTodo & CALL_RECOVERDONE) { + LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); gAgentWearables.recoverMissingWearableDone(); } /* @@ -214,12 +227,17 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i */ if (mTodo & CALL_CREATESTANDARDDONE) { + LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); gAgentWearables.createStandardWearablesDone(mType, mIndex); } if (mTodo & CALL_MAKENEWOUTFITDONE) { gAgentWearables.makeNewOutfitDone(mType, mIndex); } + if (mTodo & CALL_WEARITEM) + { + LLAppearanceMgr::instance().addCOFItemLink(inv_item, true); + } } void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type, @@ -227,25 +245,30 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type, const LLUUID& item_id, LLWearable* wearable) { + llinfos << "type " << type << " index " << index << " item " << item_id.asString() << llendl; + if (item_id.isNull()) return; LLUUID old_item_id = getWearableItemID((EWearableType)type,index); + if (wearable) { wearable->setItemID(item_id); - } - if (old_item_id.notNull()) - { - gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - setWearable((EWearableType)type,index,wearable); - } - else - { - pushWearable((EWearableType)type,wearable); + if (old_item_id.notNull()) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); + setWearable((EWearableType)type,index,wearable); + } + else + { + pushWearable((EWearableType)type,wearable); + } } + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + LLViewerInventoryItem* item = gInventory.getItem(item_id); if (item && wearable) { @@ -346,6 +369,11 @@ void LLAgentWearables::saveWearable(const EWearableType type, const U32 index, B new_wearable->setItemID(old_item_id); // should this be in LLWearable::copyDataFrom()? setWearable(type,index,new_wearable); + // old_wearable may still be referred to by other inventory items. Revert + // unsaved changes so other inventory items aren't affected by the changes + // that were just saved. + old_wearable->revertValues(); + LLInventoryItem* item = gInventory.getItem(old_item_id); if (item) { @@ -385,7 +413,7 @@ void LLAgentWearables::saveWearable(const EWearableType type, const U32 index, B return; } - gAgent.getAvatarObject()->wearableUpdated( type ); + gAgentAvatarp->wearableUpdated( type, TRUE ); if (send_update) { @@ -428,12 +456,12 @@ void LLAgentWearables::saveWearableAs(const EWearableType type, type, index, new_wearable, - addWearableToAgentInventoryCallback::CALL_UPDATE); + addWearableToAgentInventoryCallback::CALL_WEARITEM); LLUUID category_id; if (save_in_lost_and_found) { category_id = gInventory.findCategoryUUIDForType( - LLAssetType::AT_LOST_AND_FOUND); + LLFolderType::FT_LOST_AND_FOUND); } else { @@ -448,6 +476,11 @@ void LLAgentWearables::saveWearableAs(const EWearableType type, category_id, new_name, cb); + + // old_wearable may still be referred to by other inventory items. Revert + // unsaved changes so other inventory items aren't affected by the changes + // that were just saved. + old_wearable->revertValues(); } void LLAgentWearables::revertWearable(const EWearableType type, const U32 index) @@ -579,13 +612,13 @@ const LLWearable* LLAgentWearables::getWearableFromItemID(const LLUUID& item_id) return NULL; } -const LLWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_id) const +LLWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_id) { for (S32 i=0; i < WT_COUNT; i++) { for (U32 j=0; j < getWearableCount((EWearableType)i); j++) { - const LLWearable * curr_wearable = getWearable((EWearableType)i, j); + LLWearable * curr_wearable = getWearable((EWearableType)i, j); if (curr_wearable && (curr_wearable->getAssetID() == asset_id)) { return curr_wearable; @@ -630,11 +663,14 @@ LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 index) void LLAgentWearables::setWearable(const EWearableType type, U32 index, LLWearable *wearable) { - if (!getWearable(type,index)) + + LLWearable *old_wearable = getWearable(type,index); + if (!old_wearable) { pushWearable(type,wearable); return; } + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { @@ -649,7 +685,9 @@ void LLAgentWearables::setWearable(const EWearableType type, U32 index, LLWearab else { wearable_vec[index] = wearable; - mAvatarObject->wearableUpdated(wearable->getType()); + old_wearable->setLabelUpdated(); + wearableUpdated(wearable); + checkWearableAgainstInventory(wearable); } } @@ -664,12 +702,36 @@ U32 LLAgentWearables::pushWearable(const EWearableType type, LLWearable *wearabl if (type < WT_COUNT || mWearableDatas[type].size() < MAX_WEARABLES_PER_TYPE) { mWearableDatas[type].push_back(wearable); - mAvatarObject->wearableUpdated(wearable->getType()); + wearableUpdated(wearable); + checkWearableAgainstInventory(wearable); return mWearableDatas[type].size()-1; } return MAX_WEARABLES_PER_TYPE; } +void LLAgentWearables::wearableUpdated(LLWearable *wearable) +{ + gAgentAvatarp->wearableUpdated(wearable->getType(), TRUE); + wearable->refreshName(); + wearable->setLabelUpdated(); + + wearable->pullCrossWearableValues(); + + // Hack pt 2. If the wearable we just loaded has definition version 24, + // then force a re-save of this wearable after slamming the version number to 22. + // This number was incorrectly incremented for internal builds before release, and + // this fix will ensure that the affected wearables are re-saved with the right version number. + // the versions themselves are compatible. This code can be removed before release. + if( wearable->getDefinitionVersion() == 24 ) + { + wearable->setDefinitionVersion(22); + U32 index = getWearableIndex(wearable); + llinfos << "forcing werable type " << wearable->getType() << " to version 22 from 24" << llendl; + saveWearable(wearable->getType(),index,TRUE); + } + +} + void LLAgentWearables::popWearable(LLWearable *wearable) { if (wearable == NULL) @@ -693,7 +755,8 @@ void LLAgentWearables::popWearable(const EWearableType type, U32 index) if (wearable) { mWearableDatas[type].erase(mWearableDatas[type].begin() + index); - mAvatarObject->wearableUpdated(wearable->getType()); + gAgentAvatarp->wearableUpdated(wearable->getType(), TRUE); + wearable->setLabelUpdated(); } } @@ -824,22 +887,24 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs LLUUID agent_id; gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - LLVOAvatar* avatar = gAgent.getAvatarObject(); - if (avatar && (agent_id == avatar->getID())) + if (isAgentAvatarValid() && (agent_id == gAgentAvatarp->getID())) { gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum); + const S32 NUM_BODY_PARTS = 4; S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData); - if (num_wearables < 4) + if (num_wearables < NUM_BODY_PARTS) { // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin). - // The fact that they don't have any here (only a dummy is sent) implies that this account existed - // before we had wearables, or that the database has gotten messed up. + // The fact that they don't have any here (only a dummy is sent) implies that either: + // 1. This account existed before we had wearables + // 2. The database has gotten messed up + // 3. This is the account's first login (i.e. the wearables haven't been generated yet). return; } // Get the UUID of the current outfit folder (will be created if it doesn't exist) - LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); + const LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch(); @@ -879,17 +944,15 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs // Store initial wearables data until we know whether we have the current outfit folder or need to use the data. LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id); // MULTI-WEARABLE: update - outfit->mAgentInitialWearables.push_back(wearable_data); - + outfit->add(wearable_data); } lldebugs << " " << LLWearableDictionary::getTypeLabel(type) << llendl; } - // What we do here is get the complete information on the items in - // the inventory, and set up an observer that will wait for that to - // happen. - LLInventoryFetchDescendentsObserver::folder_ref_t folders; + // Get the complete information on the items in the inventory and set up an observer + // that will trigger when the complete information is fetched. + uuid_vec_t folders; folders.push_back(current_outfit_id); outfit->fetchDescendents(folders); if(outfit->isEverythingComplete()) @@ -903,63 +966,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs // will call done for us when everything is here. gInventory.addObserver(outfit); } - } -} - -// A single wearable that the avatar was wearing on start-up has arrived from the database. -// static -void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* userdata) -{ - boost::scoped_ptr<LLInitialWearablesFetch::InitialWearableData> wear_data((LLInitialWearablesFetch::InitialWearableData*)userdata); - const EWearableType type = wear_data->mType; - U32 index = 0; - - LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); - if (!avatar) - { - return; - } - - if (wearable) - { - llassert(type == wearable->getType()); - wearable->setItemID(wear_data->mItemID); - index = gAgentWearables.pushWearable(type, wearable); - gAgentWearables.mItemsAwaitingWearableUpdate.erase(wear_data->mItemID); - - // disable composites if initial textures are baked - avatar->setupComposites(); - - avatar->setCompositeUpdatesEnabled(TRUE); - gInventory.addChangedMask(LLInventoryObserver::LABEL, wearable->getItemID()); - } - else - { - // Somehow the asset doesn't exist in the database. - gAgentWearables.recoverMissingWearable(type,index); - } - - gInventory.notifyObservers(); - - // Have all the wearables that the avatar was wearing at log-in arrived? - // MULTI-WEARABLE: update when multiple wearables can arrive per type. - - gAgentWearables.updateWearablesLoaded(); - if (gAgentWearables.areWearablesLoaded()) - { - - // Can't query cache until all wearables have arrived, so calling this earlier is a no-op. - gAgentWearables.queryWearableCache(); - - // Make sure that the server's idea of the avatar's wearables actually match the wearables. - gAgent.sendAgentSetAppearance(); - - // Check to see if there are any baked textures that we hadn't uploaded before we logged off last time. - // If there are any, schedule them to be uploaded as soon as the layer textures they depend on arrive. - if (gAgent.cameraCustomizeAvatar()) - { - avatar->requestLayerSetUploads(); - } + } } @@ -969,7 +976,7 @@ void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* void LLAgentWearables::recoverMissingWearable(const EWearableType type, U32 index) { // Try to recover by replacing missing wearable with a new one. - LLNotifications::instance().add("ReplacedMissingWearable"); + LLNotificationsUtil::add("ReplacedMissingWearable"); lldebugs << "Wearable " << LLWearableDictionary::getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << llendl; LLWearable* new_wearable = LLWearableList::instance().createNewWearable(type); @@ -980,8 +987,7 @@ void LLAgentWearables::recoverMissingWearable(const EWearableType type, U32 inde // Add a new one in the lost and found folder. // (We used to overwrite the "not found" one, but that could potentially // destory content.) JC - LLUUID lost_and_found_id = - gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND); + const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); LLPointer<LLInventoryCallback> cb = new addWearableToAgentInventoryCallback( LLPointer<LLRefCount>(NULL), @@ -1014,22 +1020,94 @@ void LLAgentWearables::addLocalTextureObject(const EWearableType wearable_type, if (!wearable) { llerrs << "Tried to add local texture object to invalid wearable with type " << wearable_type << " and index " << wearable_index << llendl; + return; } - LLLocalTextureObject* lto = new LLLocalTextureObject(); + LLLocalTextureObject lto; wearable->setLocalTextureObject(texture_type, lto); } +class OnWearableItemCreatedCB: public LLInventoryCallback +{ +public: + OnWearableItemCreatedCB(): + mWearablesAwaitingItems(WT_COUNT,NULL) + { + llinfos << "created callback" << llendl; + } + /* virtual */ void fire(const LLUUID& inv_item) + { + llinfos << "One item created " << inv_item.asString() << llendl; + LLViewerInventoryItem *item = gInventory.getItem(inv_item); + mItemsToLink.put(item); + updatePendingWearable(inv_item); + } + ~OnWearableItemCreatedCB() + { + llinfos << "All items created" << llendl; + LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; + LLAppearanceMgr::instance().linkAll(LLAppearanceMgr::instance().getCOF(), + mItemsToLink, + link_waiter); + } + void addPendingWearable(LLWearable *wearable) + { + if (!wearable) + { + llwarns << "no wearable" << llendl; + return; + } + EWearableType type = wearable->getType(); + if (type<WT_COUNT) + { + mWearablesAwaitingItems[type] = wearable; + } + else + { + llwarns << "invalid type " << type << llendl; + } + } + void updatePendingWearable(const LLUUID& inv_item) + { + LLViewerInventoryItem *item = gInventory.getItem(inv_item); + if (!item) + { + llwarns << "no item found" << llendl; + return; + } + if (!item->isWearableType()) + { + llwarns << "non-wearable item found" << llendl; + return; + } + if (item && item->isWearableType()) + { + EWearableType type = item->getWearableType(); + if (type < WT_COUNT) + { + LLWearable *wearable = mWearablesAwaitingItems[type]; + if (wearable) + wearable->setItemID(inv_item); + } + else + { + llwarns << "invalid wearable type " << type << llendl; + } + } + } + +private: + LLInventoryModel::item_array_t mItemsToLink; + std::vector<LLWearable*> mWearablesAwaitingItems; +}; + void LLAgentWearables::createStandardWearables(BOOL female) { llwarns << "Creating Standard " << (female ? "female" : "male") << " Wearables" << llendl; - if (mAvatarObject.isNull()) - { - return; - } + if (!isAgentAvatarValid()) return; - mAvatarObject->setSex(female ? SEX_FEMALE : SEX_MALE); + gAgentAvatarp->setSex(female ? SEX_FEMALE : SEX_MALE); const BOOL create[WT_COUNT] = { @@ -1048,52 +1126,52 @@ void LLAgentWearables::createStandardWearables(BOOL female) FALSE //WT_SKIRT }; + LLPointer<LLInventoryCallback> cb = new OnWearableItemCreatedCB; for (S32 i=0; i < WT_COUNT; i++) { - bool once = false; - LLPointer<LLRefCount> donecb = NULL; if (create[i]) { - if (!once) - { - once = true; - donecb = new createStandardWearablesAllDoneCallback; - } llassert(getWearableCount((EWearableType)i) == 0); LLWearable* wearable = LLWearableList::instance().createNewWearable((EWearableType)i); - U32 index = pushWearable((EWearableType)i,wearable); + ((OnWearableItemCreatedCB*)(&(*cb)))->addPendingWearable(wearable); // no need to update here... - LLPointer<LLInventoryCallback> cb = - new addWearableToAgentInventoryCallback( - donecb, - i, - index, - wearable, - addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE); - addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE); + LLUUID category_id = LLUUID::null; + create_inventory_item(gAgent.getID(), + gAgent.getSessionID(), + category_id, + wearable->getTransactionID(), + wearable->getName(), + wearable->getDescription(), + wearable->getAssetType(), + LLInventoryType::IT_WEARABLE, + wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), + cb); } } } void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index) { - if (mAvatarObject) - { - mAvatarObject->updateVisualParams(); - } + llinfos << "type " << type << " index " << index << llendl; + + if (!isAgentAvatarValid()) return; + gAgentAvatarp->updateVisualParams(); } void LLAgentWearables::createStandardWearablesAllDone() { // ... because sendAgentWearablesUpdate will notify inventory // observers. + llinfos << "all done?" << llendl; + mWearablesLoaded = TRUE; checkWearablesLoaded(); updateServer(); // Treat this as the first texture entry message, if none received yet - mAvatarObject->onFirstTEMessageReceived(); + gAgentAvatarp->onFirstTEMessageReceived(); } // MULTI-WEARABLE: Properly handle multiwearables later. @@ -1115,15 +1193,12 @@ void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name, const LLDynamicArray<S32>& attachments_to_include, BOOL rename_clothing) { - if (mAvatarObject.isNull()) - { - return; - } + if (!isAgentAvatarValid()) return; // First, make a folder in the Clothes directory. LLUUID folder_id = gInventory.createNewCategory( - gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING), - LLAssetType::AT_NONE, + gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING), + LLFolderType::FT_NONE, new_folder_name); bool found_first_item = false; @@ -1175,25 +1250,29 @@ void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name, j, new_wearable, todo); - if (isWearableCopyable((EWearableType)type, j)) + llassert(item); + if (item) { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - folder_id, - new_name, - cb); - } - else - { - move_inventory_item( - gAgent.getID(), - gAgent.getSessionID(), - item->getUUID(), - folder_id, - new_name, - cb); + if (isWearableCopyable((EWearableType)type, j)) + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + folder_id, + new_name, + cb); + } + else + { + move_inventory_item( + gAgent.getID(), + gAgent.getSessionID(), + item->getUUID(), + folder_id, + new_name, + cb); + } } } } @@ -1212,7 +1291,7 @@ void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name, for (S32 i = 0; i < attachments_to_include.count(); i++) { S32 attachment_pt = attachments_to_include[i]; - LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL); + LLViewerJointAttachment* attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL); if (!attachment) continue; for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); attachment_iter != attachment->mAttachedObjects.end(); @@ -1248,30 +1327,57 @@ void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name, } } -LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name) +class LLShowCreatedOutfit: public LLInventoryCallback { - if (mAvatarObject.isNull()) +public: + LLShowCreatedOutfit(LLUUID& folder_id): + mFolderID(folder_id) + { + } + + virtual ~LLShowCreatedOutfit() + { + LLSD key; + LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key); + LLPanelOutfitsInventory *outfit_panel = + dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory")); + if (outfit_panel) + { + outfit_panel->getRootFolder()->clearSelection(); + outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE); + } + LLAccordionCtrlTab* tab_outfits = outfit_panel ? outfit_panel->findChild<LLAccordionCtrlTab>("tab_outfits") : 0; + if (tab_outfits && !tab_outfits->getDisplayChildren()) + { + tab_outfits->changeOpenClose(tab_outfits->getDisplayChildren()); + } + + LLAppearanceMgr::instance().updateIsDirty(); + LLAppearanceMgr::instance().updatePanelOutfitName(""); + } + + virtual void fire(const LLUUID&) { - return LLUUID::null; } + +private: + LLUUID mFolderID; +}; + +LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name) +{ + if (!isAgentAvatarValid()) return LLUUID::null; // First, make a folder in the My Outfits directory. - LLUUID parent_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_MY_OUTFITS); + const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); LLUUID folder_id = gInventory.createNewCategory( parent_id, - LLAssetType::AT_OUTFIT, + LLFolderType::FT_OUTFIT, new_folder_name); - LLAppearanceManager::shallowCopyCategory(LLAppearanceManager::getCOF(),folder_id, NULL); - -#if 0 // BAP - fix to go into rename state automatically after outfit is created. - LLViewerInventoryCategory *parent_category = gInventory.getCategory(parent_id); - if (parent_category) - { - parent_category->setSelectionByID(folder_id,TRUE); - parent_category->setNeedsAutoRename(TRUE); - } -#endif + LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id); + LLAppearanceMgr::instance().shallowCopyCategoryContents(LLAppearanceMgr::instance().getCOF(),folder_id, cb); + LLAppearanceMgr::instance().createBaseOutfitLink(folder_id, cb); return folder_id; } @@ -1282,10 +1388,10 @@ void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) // Open the inventory and select the first item we added. if (first_item_id.notNull()) { - LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); - if (view) + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + if (active_panel) { - view->getPanel()->setSelection(first_item_id, TAKE_FOCUS_NO); + active_panel->setSelection(first_item_id, TAKE_FOCUS_NO); } } } @@ -1338,8 +1444,9 @@ void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_a { LLSD payload; payload["wearable_type"] = (S32)type; + payload["wearable_index"] = (S32)index; // Bring up view-modal dialog: Save changes? Yes, No, Cancel - LLNotifications::instance().add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog); + LLNotificationsUtil::add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog); return; } else @@ -1351,22 +1458,21 @@ void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_a } -// MULTI_WEARABLE: assuming one wearable per type. -// MULTI_WEARABLE: hardwiring 0th elt for now - notification needs to change. // static bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); EWearableType type = (EWearableType)notification["payload"]["wearable_type"].asInteger(); + S32 index = (S32)notification["payload"]["wearable_index"].asInteger(); switch(option) { case 0: // "Save" - gAgentWearables.saveWearable(type, 0); - gAgentWearables.removeWearableFinal(type, false, 0); + gAgentWearables.saveWearable(type, index); + gAgentWearables.removeWearableFinal(type, false, index); break; case 1: // "Don't Save" - gAgentWearables.removeWearableFinal(type, false, 0); + gAgentWearables.removeWearableFinal(type, false, index); break; case 2: // "Cancel" @@ -1389,13 +1495,10 @@ void LLAgentWearables::removeWearableFinal(const EWearableType type, bool do_rem for (S32 i=max_entry; i>=0; i--) { LLWearable* old_wearable = getWearable(type,i); - const LLUUID &item_id = getWearableItemID(type,i); - popWearable(type,i); - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - //queryWearableCache(); // moved below if (old_wearable) { + popWearable(old_wearable); old_wearable->removeFromAvatar(TRUE); } } @@ -1404,15 +1507,11 @@ void LLAgentWearables::removeWearableFinal(const EWearableType type, bool do_rem else { LLWearable* old_wearable = getWearable(type, index); - - const LLUUID &item_id = getWearableItemID(type,index); - popWearable(type, index); - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - //queryWearableCache(); // moved below if (old_wearable) { + popWearable(old_wearable); old_wearable->removeFromAvatar(TRUE); } } @@ -1425,30 +1524,25 @@ void LLAgentWearables::removeWearableFinal(const EWearableType type, bool do_rem } // Assumes existing wearables are not dirty. -// MULTI_WEARABLE: assumes one wearable per type. void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLWearable* >& wearables, BOOL remove) { - lldebugs << "setWearableOutfit() start" << llendl; - - BOOL wearables_to_remove[WT_COUNT]; - wearables_to_remove[WT_SHAPE] = FALSE; - wearables_to_remove[WT_SKIN] = FALSE; - wearables_to_remove[WT_HAIR] = FALSE; - wearables_to_remove[WT_EYES] = FALSE; - wearables_to_remove[WT_SHIRT] = remove; - wearables_to_remove[WT_PANTS] = remove; - wearables_to_remove[WT_SHOES] = remove; - wearables_to_remove[WT_SOCKS] = remove; - wearables_to_remove[WT_JACKET] = remove; - wearables_to_remove[WT_GLOVES] = remove; - wearables_to_remove[WT_UNDERSHIRT] = (!gAgent.isTeen()) & remove; - wearables_to_remove[WT_UNDERPANTS] = (!gAgent.isTeen()) & remove; - wearables_to_remove[WT_SKIRT] = remove; - wearables_to_remove[WT_ALPHA] = remove; - wearables_to_remove[WT_TATTOO] = remove; + llinfos << "setWearableOutfit() start" << llendl; + // TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later + if (remove) + { + // note: shirt is the first non-body part wearable item. Update if wearable order changes. + // This loop should remove all clothing, but not any body parts + for (S32 type = 0; type < (S32)WT_COUNT; type++) + { + if (LLWearableDictionary::getAssetType((EWearableType)type) == LLAssetType::AT_CLOTHING) + { + removeWearable((EWearableType)type, true, 0); + } + } + } S32 count = wearables.count(); llassert(items.count() == count); @@ -1459,78 +1553,41 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it LLWearable* new_wearable = wearables[i]; LLPointer<LLInventoryItem> new_item = items[i]; - const EWearableType type = new_wearable->getType(); - wearables_to_remove[type] = FALSE; - - // MULTI_WEARABLE: using 0th - LLWearable* old_wearable = getWearable(type, 0); - if (old_wearable) + llassert(new_wearable); + if (new_wearable) { - const LLUUID& old_item_id = getWearableItemID(type, 0); - if ((old_wearable->getAssetID() == new_wearable->getAssetID()) && - (old_item_id == new_item->getUUID())) - { - lldebugs << "No change to wearable asset and item: " << LLWearableDictionary::getInstance()->getWearableEntry(type) << llendl; - continue; - } + const EWearableType type = new_wearable->getType(); + + new_wearable->setName(new_item->getName()); + new_wearable->setItemID(new_item->getUUID()); - gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - // Assumes existing wearables are not dirty. - if (old_wearable->isDirty()) + if (LLWearableDictionary::getAssetType(type) == LLAssetType::AT_BODYPART) { - llassert(0); - continue; + // exactly one wearable per body part + setWearable(type,0,new_wearable); } - } - - setWearable(type,0,new_wearable); - if (new_wearable) - new_wearable->setItemID(new_item->getUUID()); - } - - std::vector<LLWearable*> wearables_being_removed; - - for (i = 0; i < WT_COUNT; i++) - { - if (wearables_to_remove[i]) - { - // MULTI_WEARABLE: assuming 0th - LLWearable* wearable = getWearable((EWearableType)i, 0); - const LLUUID &item_id = getWearableItemID((EWearableType)i,0); - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - if (wearable) + else { - wearables_being_removed.push_back(wearable); + pushWearable(type,new_wearable); } - removeWearable((EWearableType)i,true,0); + wearableUpdated(new_wearable); + checkWearableAgainstInventory(new_wearable); } } gInventory.notifyObservers(); - queryWearableCache(); - - std::vector<LLWearable*>::iterator wearable_iter; - - for (wearable_iter = wearables_being_removed.begin(); - wearable_iter != wearables_being_removed.end(); - ++wearable_iter) - { - LLWearable* wearablep = *wearable_iter; - if (wearablep) - { - wearablep->removeFromAvatar(TRUE); - } - } - - if (mAvatarObject) + if (isAgentAvatarValid()) { - mAvatarObject->updateVisualParams(); + gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); + gAgentAvatarp->updateVisualParams(); + gAgentAvatarp->invalidateAll(); } // Start rendering & update the server mWearablesLoaded = TRUE; checkWearablesLoaded(); + queryWearableCache(); updateServer(); lldebugs << "setWearableOutfit() end" << llendl; @@ -1569,7 +1626,7 @@ void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* ne // Bring up modal dialog: Save changes? Yes, No, Cancel LLSD payload; payload["item_id"] = new_item->getUUID(); - LLNotifications::instance().add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); + LLNotificationsUtil::add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); return; } } @@ -1581,8 +1638,9 @@ void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* ne // static bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLWearable* wearable) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); + U32 index = gAgentWearables.getWearableIndex(wearable); if (!new_item) { delete wearable; @@ -1592,8 +1650,7 @@ bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& switch(option) { case 0: // "Save" -// MULTI_WEARABLE: assuming 0th - gAgentWearables.saveWearable(wearable->getType(),0); + gAgentWearables.saveWearable(wearable->getType(),index); gAgentWearables.setWearableFinal(new_item, wearable); break; @@ -1625,6 +1682,7 @@ void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLWearable* n mWearableDatas[type].push_back(new_wearable); llinfos << "Added additional wearable for type " << type << " size is now " << mWearableDatas[type].size() << llendl; + checkWearableAgainstInventory(new_wearable); } else { @@ -1682,30 +1740,35 @@ void LLAgentWearables::queryWearableCache() for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); - LLUUID hash; + LLMD5 hash; + bool hash_computed = false; for (U8 i=0; i < baked_dict->mWearables.size(); i++) { const EWearableType baked_type = baked_dict->mWearables[i]; - // MULTI_WEARABLE: not order-dependent const U32 num_wearables = getWearableCount(baked_type); for (U32 index = 0; index < num_wearables; ++index) { const LLWearable* wearable = getWearable(baked_type,index); if (wearable) { - hash ^= wearable->getAssetID(); + LLUUID asset_id = wearable->getAssetID(); + hash.update((const unsigned char*)asset_id.mData, UUID_BYTES); + hash_computed = true; } } } - if (hash.notNull()) + hash.finalize(); + if (hash_computed) { - hash ^= baked_dict->mWearablesHashID; + LLUUID hash_id; + hash.raw_digest(hash_id.mData); + hash_id ^= baked_dict->mWearablesHashID; num_queries++; // *NOTE: make sure at least one request gets packed //llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl; gMessageSystem->nextBlockFast(_PREHASH_WearableData); - gMessageSystem->addUUIDFast(_PREHASH_ID, hash); + gMessageSystem->addUUIDFast(_PREHASH_ID, hash_id); gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_index); } @@ -1718,23 +1781,29 @@ void LLAgentWearables::queryWearableCache() gAgentQueryManager.mWearablesCacheQueryID++; } -// MULTI_WEARABLE: need a way to specify by wearable rather than by type. // User has picked "remove from avatar" from a menu. // static -void LLAgentWearables::userRemoveWearable(void* userdata) +void LLAgentWearables::userRemoveWearable(const EWearableType &type, const U32 &index) { - EWearableType type = (EWearableType)(intptr_t)userdata; - - if (!(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR)) //&& + if (!(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES)) //&& + //!((!gAgent.isTeen()) && (type==WT_UNDERPANTS || type==WT_UNDERSHIRT))) + { + gAgentWearables.removeWearable(type,false,index); + } +} + +//static +void LLAgentWearables::userRemoveWearablesOfType(const EWearableType &type) +{ + if (!(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES)) //&& //!((!gAgent.isTeen()) && (type==WT_UNDERPANTS || type==WT_UNDERSHIRT))) { - // MULTI_WEARABLE: fixed to 0th for now. - gAgentWearables.removeWearable(type,false,0); + gAgentWearables.removeWearable(type,true,0); } } // static -void LLAgentWearables::userRemoveAllClothes(void* userdata) +void LLAgentWearables::userRemoveAllClothes() { // We have to do this up front to avoid having to deal with the case of multiple wearables being dirty. if (gFloaterCustomize) @@ -1775,12 +1844,7 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj // already wearing and in request set -> leave alone. // not wearing and in request set -> put on. - LLVOAvatar* avatarp = gAgent.getAvatarObject(); - if (!avatarp) - { - llwarns << "No avatar found." << llendl; - return; - } + if (!isAgentAvatarValid()) return; std::set<LLUUID> requested_item_ids; std::set<LLUUID> current_item_ids; @@ -1789,8 +1853,8 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj // Build up list of objects to be removed and items currently attached. llvo_vec_t objects_to_remove; - for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); - iter != avatarp->mAttachmentPoints.end();) + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end();) { LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; @@ -1846,12 +1910,7 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remove) { - LLVOAvatar* avatarp = gAgent.getAvatarObject(); - if (!avatarp) - { - llwarns << "No avatar found." << llendl; - return; - } + if (!isAgentAvatarValid()) return; if (objects_to_remove.empty()) return; @@ -1874,17 +1933,12 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo void LLAgentWearables::userRemoveAllAttachments() { - LLVOAvatar* avatarp = gAgent.getAvatarObject(); - if (!avatarp) - { - llwarns << "No avatar found." << llendl; - return; - } + if (!isAgentAvatarValid()) return; llvo_vec_t objects_to_remove; - for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); - iter != avatarp->mAttachmentPoints.end();) + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end();) { LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; @@ -1985,6 +2039,17 @@ bool LLAgentWearables::canWearableBeRemoved(const LLWearable* wearable) const return !(((type == WT_SHAPE) || (type == WT_SKIN) || (type == WT_HAIR) || (type == WT_EYES)) && (getWearableCount(type) <= 1) ); } +void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake) +{ + for( S32 type = 0; type < WT_COUNT; ++type ) + { + for (S32 count = 0; count < (S32)getWearableCount((EWearableType)type); ++count) + { + LLWearable *wearable = getWearable((EWearableType)type,count); + wearable->animateParams(delta, upload_bake); + } + } +} void LLAgentWearables::updateServer() { @@ -1992,63 +2057,22 @@ void LLAgentWearables::updateServer() gAgent.sendAgentSetAppearance(); } -void LLInitialWearablesFetch::done() -{ - // No longer need this observer hanging around. - gInventory.removeObserver(this); +void LLAgentWearables::populateMyOutfitsFolder(void) +{ + llinfos << "starting outfit population" << llendl; - // Fetch the wearable items from the Current Outfit Folder - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t wearable_array; - LLFindWearables is_wearable; - gInventory.collectDescendentsIf(mCompleteFolders.front(), cat_array, wearable_array, - LLInventoryModel::EXCLUDE_TRASH, is_wearable); + LLLibraryOutfitsFetch* outfits = new LLLibraryOutfitsFetch(); - if (wearable_array.count() > 0) - { - LLAppearanceManager::instance().updateAppearanceFromCOF(); - } - else - { - processWearablesMessage(); - } - delete this; -} + // Get the complete information on the items in the inventory and + // setup an observer that will wait for that to happen. + uuid_vec_t folders; + outfits->mMyOutfitsID = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -void LLInitialWearablesFetch::processWearablesMessage() -{ - if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead. - { - LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); - for (U8 i = 0; i < mAgentInitialWearables.size(); ++i) - { - // Populate the current outfit folder with links to the wearables passed in the message - InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback. - - if (wearable_data->mAssetID.notNull()) - { -#ifdef USE_CURRENT_OUTFIT_FOLDER - const std::string link_name = "WearableLink"; // Unimportant what this is named, it isn't exposed. - link_inventory_item(gAgent.getID(), wearable_data->mItemID, current_outfit_id, link_name, - LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL)); -#endif - // Fetch the wearables - LLWearableList::instance().getAsset(wearable_data->mAssetID, - LLStringUtil::null, - LLWearableDictionary::getAssetType(wearable_data->mType), - LLAgentWearables::onInitialWearableAssetArrived, (void*)(wearable_data)); - } - else - { - llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID " - << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl; - } - } - } - else + folders.push_back(outfits->mMyOutfitsID); + gInventory.addObserver(outfits); + outfits->fetchDescendents(folders); + if (outfits->isEverythingComplete()) { - LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL; + outfits->done(); } } - - |