diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index ef9ecb967..886348d1a 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -64,6 +64,8 @@ LLAgentWearables gAgentWearables; +BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE; + using namespace LLVOAvatarDefines; LLAgentWearables::LLAgentWearables() : mWearablesLoaded(FALSE) @@ -104,8 +106,8 @@ LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCal } LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback( - LLPointer cb, S32 index, LLWearable* wearable, U32 todo) : - mIndex(index), + LLPointer cb, LLWearableType::EType type, LLWearable* wearable, U32 todo) : + mType(type), mWearable(wearable), mTodo(todo), mCB(cb) @@ -118,7 +120,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i if (inv_item.isNull()) return; - gAgentWearables.addWearabletoAgentInventoryDone(mIndex, inv_item, mWearable); + gAgentWearables.addWearabletoAgentInventoryDone(mType, inv_item, mWearable); if (mTodo & CALL_UPDATE) { @@ -133,28 +135,41 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i */ if (mTodo & CALL_CREATESTANDARDDONE) { - gAgentWearables.createStandardWearablesDone(mIndex); + gAgentWearables.createStandardWearablesDone(mType); } if (mTodo & CALL_MAKENEWOUTFITDONE) { - gAgentWearables.makeNewOutfitDone(mIndex); + gAgentWearables.makeNewOutfitDone(mType); } } -void LLAgentWearables::addWearabletoAgentInventoryDone( - S32 index, +void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::EType type, const LLUUID& item_id, LLWearable* wearable) { + llinfos << "type " << type << " item " << item_id.asString() << llendl; + if (item_id.isNull()) return; - LLUUID old_item_id = mWearableEntry[index].mItemID; - mWearableEntry[index].mItemID = item_id; - mWearableEntry[index].mWearable = wearable; - if (old_item_id.notNull()) - gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); + LLUUID old_item_id = getWearableItemID(type); + if (wearable) + { + wearable->setItemID(item_id); + + if (old_item_id.notNull()) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); + setWearable(type,wearable); + } + else + { + pushWearable(type,wearable); + } + } + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + LLViewerInventoryItem* item = gInventory.getItem(item_id); if(item && wearable) { @@ -172,26 +187,27 @@ void LLAgentWearables::addWearabletoAgentInventoryDone( void LLAgentWearables::sendAgentWearablesUpdate() { // First make sure that we have inventory items for each wearable - S32 i; - for(i=0; i < LLWearableType::WT_COUNT; ++i) + for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) { - LLWearable* wearable = mWearableEntry[ i ].mWearable; - if (wearable) { - if( mWearableEntry[ i ].mItemID.isNull() ) + LLWearable* wearable = getWearable((LLWearableType::EType)type); + if (wearable) { - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - i, - wearable, - addWearableToAgentInventoryCallback::CALL_NONE); - addWearableToAgentInventory(cb, wearable); - } - else - { - gInventory.addChangedMask( LLInventoryObserver::LABEL, - mWearableEntry[i].mItemID ); + if (wearable->getItemID().isNull()) + { + LLPointer cb = + new addWearableToAgentInventoryCallback( + LLPointer(NULL), + (LLWearableType::EType)type, + wearable, + addWearableToAgentInventoryCallback::CALL_NONE); + addWearableToAgentInventory(cb, wearable); + } + else + { + gInventory.addChangedMask( LLInventoryObserver::LABEL, + wearable->getItemID()); + } } } } @@ -209,19 +225,19 @@ void LLAgentWearables::sendAgentWearablesUpdate() gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - LL_DEBUGS("Wearables") << "sendAgentWearablesUpdate()" << LL_ENDL; - for(i=0; i < LLWearableType::WT_COUNT; ++i) + lldebugs << "sendAgentWearablesUpdate()" << llendl; + for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) { gMessageSystem->nextBlockFast(_PREHASH_WearableData); - U8 type_u8 = (U8)i; + U8 type_u8 = (U8)type; gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8 ); - LLWearable* wearable = mWearableEntry[ i ].mWearable; + LLWearable* wearable = getWearable((LLWearableType::EType)type); if( wearable ) { - LL_DEBUGS("Wearables") << "Sending wearable " << wearable->getName() << " mItemID = " << mWearableEntry[ i ].mItemID << LL_ENDL; - LLUUID item_id = mWearableEntry[i].mItemID; + LLUUID item_id = wearable->getItemID(); + LL_DEBUGS("Wearables") << "Sending wearable " << wearable->getName() << " mItemID = " << item_id << LL_ENDL; const LLViewerInventoryItem *item = gInventory.getItem(item_id); if (item && item->getIsLinkType()) { @@ -233,26 +249,37 @@ void LLAgentWearables::sendAgentWearablesUpdate() } else { - LL_DEBUGS("Wearables") << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << LL_ENDL; + LL_DEBUGS("Wearables") << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)type) << LL_ENDL; gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null ); } - LL_DEBUGS("Wearables") << " " << LLWearableType::getTypeLabel((LLWearableType::EType)i) << " : " << (wearable ? wearable->getAssetID() : LLUUID::null) << LL_ENDL; + lldebugs << " " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << llendl; } gAgent.sendReliableMessage(); } -void LLAgentWearables::saveWearable( LLWearableType::EType type, BOOL send_update ) +void LLAgentWearables::saveWearable(const LLWearableType::EType type, BOOL send_update, + const std::string new_name) { - LLWearable* old_wearable = mWearableEntry[(S32)type].mWearable; - if( old_wearable && (old_wearable->isDirty() || old_wearable->isOldVersion()) ) + LLWearable* old_wearable = getWearable(type); + if(!old_wearable) return; + bool name_changed = !new_name.empty() && (new_name != old_wearable->getName()); + if (name_changed || old_wearable->isDirty() || old_wearable->isOldVersion()) { - LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable ); - mWearableEntry[(S32)type].mWearable = new_wearable; + LLUUID old_item_id = old_wearable->getItemID(); + LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar( old_wearable ); + new_wearable->setItemID(old_item_id); // should this be in LLWearable::copyDataFrom()? + setWearable(type,new_wearable); - LLInventoryItem* item = gInventory.getItem(mWearableEntry[(S32)type].mItemID); + LLInventoryItem* item = gInventory.getItem(old_item_id); if( item ) { + std::string item_name = item->getName(); + if (name_changed) + { + llinfos << "saveWearable changing name from " << item->getName() << " to " << new_name << llendl; + item_name = new_name; + } // Update existing inventory item LLPointer template_item = new LLViewerInventoryItem(item->getUUID(), @@ -261,7 +288,7 @@ void LLAgentWearables::saveWearable( LLWearableType::EType type, BOOL send_updat new_wearable->getAssetID(), new_wearable->getAssetType(), item->getInventoryType(), - item->getName(), + item_name, item->getDescription(), item->getSaleInfo(), item->getFlags(), @@ -269,6 +296,10 @@ void LLAgentWearables::saveWearable( LLWearableType::EType type, BOOL send_updat template_item->setTransactionID(new_wearable->getTransactionID()); template_item->updateServer(FALSE); gInventory.updateItem(template_item); + if (name_changed) + { + gInventory.notifyObservers(); + } } else { @@ -281,14 +312,14 @@ void LLAgentWearables::saveWearable( LLWearableType::EType type, BOOL send_updat LLPointer cb = new addWearableToAgentInventoryCallback( LLPointer(NULL), - (S32)type, + type, new_wearable, todo); addWearableToAgentInventory(cb, new_wearable); return; } - gAgentAvatarp->wearableUpdated( type ); + gAgentAvatarp->wearableUpdated( type, TRUE ); if( send_update ) { @@ -297,10 +328,9 @@ void LLAgentWearables::saveWearable( LLWearableType::EType type, BOOL send_updat } } -void LLAgentWearables::saveWearableAs( - LLWearableType::EType type, - const std::string& new_name, - BOOL save_in_lost_and_found) +void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, + const std::string& new_name, + BOOL save_in_lost_and_found) { if(!isWearableCopyable(type)) { @@ -313,7 +343,8 @@ void LLAgentWearables::saveWearableAs( llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl; return; } - LLInventoryItem* item = gInventory.getItem(mWearableEntry[type].mItemID); + + LLInventoryItem* item = gInventory.getItem(getWearableItemID(type)); if(!item) { llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl; @@ -321,7 +352,7 @@ void LLAgentWearables::saveWearableAs( } std::string trunc_name(new_name); LLStringUtil::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN); - LLWearable* new_wearable = gWearableList.createCopyFromAvatar( + LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar( old_wearable, trunc_name); LLPointer cb = @@ -356,7 +387,7 @@ void LLAgentWearables::saveWearableAs( { std::string old_name = old_wearable->getName(); old_wearable->setName( new_name ); - LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable ); + LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar( old_wearable ); old_wearable->setName( old_name ); LLUUID category_id; @@ -393,11 +424,13 @@ void LLAgentWearables::saveWearableAs( void LLAgentWearables::revertWearable( LLWearableType::EType type ) { - LLWearable* wearable = mWearableEntry[(S32)type].mWearable; + LLWearable* wearable = getWearable(type); + llassert(wearable); if( wearable ) { wearable->writeToAvatar( TRUE ); } + gAgent.sendAgentSetAppearance(); } @@ -428,14 +461,17 @@ void LLAgentWearables::setWearableName( const LLUUID& item_id, const std::string { for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { - if( mWearableEntry[i].mItemID == item_id ) + LLUUID curr_item_id = getWearableItemID((LLWearableType::EType)i); + if( curr_item_id == item_id ) { - LLWearable* old_wearable = mWearableEntry[i].mWearable; + LLWearable* old_wearable = getWearable((LLWearableType::EType)i); llassert( old_wearable ); + if (!old_wearable) continue; std::string old_name = old_wearable->getName(); old_wearable->setName( new_name ); - LLWearable* new_wearable = gWearableList.createCopy( old_wearable ); + LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable); + new_wearable->setItemID(item_id); LLInventoryItem* item = gInventory.getItem(item_id); if(item) { @@ -443,7 +479,7 @@ void LLAgentWearables::setWearableName( const LLUUID& item_id, const std::string } old_wearable->setName( old_name ); - mWearableEntry[i].mWearable = new_wearable; + setWearable((LLWearableType::EType)i,new_wearable); sendAgentWearablesUpdate(); break; } @@ -459,9 +495,10 @@ BOOL LLAgentWearables::isWearableModifiable(LLWearableType::EType type) const BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const { - if(!item_id.isNull()) + const LLUUID& linked_id = gInventory.getLinkedItemID(item_id); + if (linked_id.notNull()) { - LLInventoryItem* item = gInventory.getItem(item_id); + LLInventoryItem* item = gInventory.getItem(linked_id); if(item && item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID())) { @@ -520,11 +557,13 @@ LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::ETyp const LLWearable* LLAgentWearables::getWearableFromItemID( const LLUUID& item_id ) const { + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { - if( mWearableEntry[i].mItemID == item_id ) + const LLWearable * curr_wearable = getWearable((LLWearableType::EType)i); + if (curr_wearable && (curr_wearable->getItemID() == base_item_id)) { - return mWearableEntry[i].mWearable; + return curr_wearable; } } return NULL; @@ -532,16 +571,30 @@ const LLWearable* LLAgentWearables::getWearableFromItemID( const LLUUID& item_id LLWearable* LLAgentWearables::getWearableFromItemID( const LLUUID& item_id ) { + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { - if( mWearableEntry[i].mItemID == item_id ) + LLWearable * curr_wearable = getWearable((LLWearableType::EType)i); + if (curr_wearable && (curr_wearable->getItemID() == base_item_id)) { - return mWearableEntry[i].mWearable; + return curr_wearable; } } return NULL; } +LLWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_id) +{ + for (S32 i=0; i < LLWearableType::WT_COUNT; i++) + { + LLWearable * curr_wearable = getWearable((LLWearableType::EType)i); + if (curr_wearable && (curr_wearable->getAssetID() == asset_id)) + { + return curr_wearable; + } + } + return NULL; +} void LLAgentWearables::sendAgentWearablesRequest() { @@ -554,23 +607,213 @@ void LLAgentWearables::sendAgentWearablesRequest() // Used to enable/disable menu items. // static -BOOL LLAgentWearables::selfHasWearable( void* userdata ) +BOOL LLAgentWearables::selfHasWearable(LLWearableType::EType type) { - LLWearableType::EType type = (LLWearableType::EType)(intptr_t)userdata; - return gAgentWearables.getWearable( type ) != NULL; -} -LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type) -{ - return (type < LLWearableType::WT_COUNT) ? mWearableEntry[ type ].mWearable : NULL; -} -const LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type) const -{ - return (type < LLWearableType::WT_COUNT) ? mWearableEntry[ type ].mWearable : NULL; + return (gAgentWearables.getWearableCount(type) > 0); } -const LLUUID &LLAgentWearables::getWearableItemID(LLWearableType::EType type) const +LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type) { - return (type < LLWearableType::WT_COUNT) ? mWearableEntry[ type ].mItemID : LLUUID::null; + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + return NULL; + } + U32 index = 0; //Remove when multi-wearables are implemented. + wearableentry_vec_t& wearable_vec = wearable_iter->second; + if (index>=wearable_vec.size()) + { + return NULL; + } + else + { + return wearable_vec[index]; + } +} + +void LLAgentWearables::setWearable(const LLWearableType::EType type, LLWearable *wearable) +{ + + LLWearable *old_wearable = getWearable(type); + if (!old_wearable) + { + pushWearable(type,wearable); + return; + } + + U32 index = 0; //Remove when multi-wearables are implemented. + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + llwarns << "invalid type, type " << type << " index " << index << llendl; + return; + } + wearableentry_vec_t& wearable_vec = wearable_iter->second; + if (index>=wearable_vec.size()) + { + llwarns << "invalid index, type " << type << " index " << index << llendl; + } + else + { + wearable_vec[index] = wearable; + old_wearable->setLabelUpdated(); + wearableUpdated(wearable); + } +} + +U32 LLAgentWearables::pushWearable(const LLWearableType::EType type, LLWearable *wearable) +{ + if (wearable == NULL) + { + // no null wearables please! + llwarns << "Null wearable sent for type " << type << llendl; + return MAX_CLOTHING_PER_TYPE; + } + if (type < LLWearableType::WT_COUNT || mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE) + { + mWearableDatas[type].push_back(wearable); + wearableUpdated(wearable); + return mWearableDatas[type].size()-1; + } + return MAX_CLOTHING_PER_TYPE; +} + +void LLAgentWearables::wearableUpdated(LLWearable *wearable) +{ + gAgentAvatarp->wearableUpdated(wearable->getType(), FALSE); + wearable->refreshName(); + wearable->setLabelUpdated(); +} + +void LLAgentWearables::popWearable(LLWearable *wearable) +{ + if (wearable == NULL) + { + // nothing to do here. move along. + return; + } + + U32 index = 0; //Remove when multi-wearables are implemented. + LLWearableType::EType type = wearable->getType(); + + if (index < MAX_CLOTHING_PER_TYPE && index < getWearableCount(type)) + { + popWearable(type); + } +} + +void LLAgentWearables::popWearable(const LLWearableType::EType type) +{ + LLWearable *wearable = getWearable(type); + if (wearable) + { + mWearableDatas[type].erase(mWearableDatas[type].begin()); + gAgentAvatarp->wearableUpdated(wearable->getType(), TRUE); + wearable->setLabelUpdated(); + } +} + +U32 LLAgentWearables::getWearableIndex(const LLWearable *wearable) const +{ + if (wearable == NULL) + { + return MAX_CLOTHING_PER_TYPE; + } + + const LLWearableType::EType type = wearable->getType(); + wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + llwarns << "tried to get wearable index with an invalid type!" << llendl; + return MAX_CLOTHING_PER_TYPE; + } + const wearableentry_vec_t& wearable_vec = wearable_iter->second; + for(U32 index = 0; index < wearable_vec.size(); index++) + { + if (wearable_vec[index] == wearable) + { + return index; + } + } + + return MAX_CLOTHING_PER_TYPE; +} + + +const LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type) const +{ + wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + return NULL; + } + U32 index = 0; //Remove when multi-wearables are implemented. + const wearableentry_vec_t& wearable_vec = wearable_iter->second; + if (index>=wearable_vec.size()) + { + return NULL; + } + else + { + return wearable_vec[index]; + } +} + +LLWearable* LLAgentWearables::getTopWearable(const LLWearableType::EType type) +{ + U32 count = getWearableCount(type); + if ( count == 0) + { + return NULL; + } + + return getWearable(type); +} + +LLWearable* LLAgentWearables::getBottomWearable(const LLWearableType::EType type) +{ + if (getWearableCount(type) == 0) + { + return NULL; + } + + return getWearable(type); +} + +U32 LLAgentWearables::getWearableCount(const LLWearableType::EType type) const +{ + wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + return 0; + } + const wearableentry_vec_t& wearable_vec = wearable_iter->second; + return wearable_vec.size(); +} + +U32 LLAgentWearables::getWearableCount(const U32 tex_index) const +{ + const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((LLVOAvatarDefines::ETextureIndex)tex_index); + return getWearableCount(wearable_type); +} + + +const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type) const +{ + const LLWearable *wearable = getWearable(type); + if (wearable) + return wearable->getItemID(); + else + return LLUUID(); +} + +const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type) const +{ + const LLWearable *wearable = getWearable(type); + if (wearable) + return wearable->getAssetID(); + else + return LLUUID(); } BOOL LLAgentWearables::isWearingItem( const LLUUID& item_id ) const @@ -583,21 +826,21 @@ BOOL LLAgentWearables::isWearingItem( const LLUUID& item_id ) const void LLAgentWearables::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void** user_data ) { // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates - // that may result from AgentWearablesRequest having been sent more than once. - static bool first = true; - if (!first) return; - first = false; + // that may result from AgentWearablesRequest having been sent more than once. + if (mInitialWearablesUpdateReceived) + return; + mInitialWearablesUpdateReceived = true; LLUUID agent_id; gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); - LLVOAvatar* avatar = gAgentAvatarp; - if( avatar && (agent_id == avatar->getID()) ) + if (isAgentAvatarValid() && (agent_id == gAgentAvatarp->getID())) { - gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum ); + 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 @@ -607,9 +850,8 @@ void LLAgentWearables::processAgentInitialWearablesUpdate( LLMessageSystem* mesg //lldebugs << "processAgentInitialWearablesUpdate()" << llendl; // Add wearables - LLUUID asset_id_array[ LLWearableType::WT_COUNT ]; - S32 i; - for( i=0; i < num_wearables; i++ ) + std::pair asset_id_array[ LLWearableType::WT_COUNT ]; + for (S32 i=0; i < num_wearables; i++) { U8 type_u8 = 0; gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i ); @@ -636,26 +878,29 @@ void LLAgentWearables::processAgentInitialWearablesUpdate( LLMessageSystem* mesg continue; } - gAgentWearables.mWearableEntry[type].mItemID = item_id; - asset_id_array[type] = asset_id; + asset_id_array[type] = std::pair(asset_id,item_id); } - LL_DEBUGS("Wearables") << " " << LLWearableType::getTypeLabel(type) << " " << asset_id << " item id " << gAgentWearables.mWearableEntry[type].mItemID.asString() << LL_ENDL; + LL_DEBUGS("Wearables") << " " << LLWearableType::getTypeLabel(type) << " " << asset_id << " item id " << gAgentWearables.getWearableItemID(type).asString() << LL_ENDL; } LLCOFMgr::instance().fetchCOF(); // now that we have the asset ids...request the wearable assets - for( i = 0; i < LLWearableType::WT_COUNT; i++ ) + for(S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) { - LL_DEBUGS("Wearables") << " fetching " << asset_id_array[i] << LL_ENDL; - if( !gAgentWearables.mWearableEntry[i].mItemID.isNull() ) + LL_DEBUGS("Wearables") << " fetching " << asset_id_array[i].first << LL_ENDL; + const LLUUID item_id = asset_id_array[i].second; + if( !item_id.isNull() ) { - gWearableList.getAsset( - asset_id_array[i], + LLWearableList::instance().getAsset( + asset_id_array[i].first, LLStringUtil::null, LLWearableType::getAssetType( (LLWearableType::EType) i ), - LLAgentWearables::onInitialWearableAssetArrived, (void*)(intptr_t)i ); + LLAgentWearables::onInitialWearableAssetArrived, + //This scary cast is to prevent messing with llwearablelist. Since ItemIDs are now tied to wearables, + // we now need to pass the ids to onInitialWearableAssetArrived so LLWearable::setItemID can be called there. + (void*)(intptr_t)new std::pair((LLWearableType::EType)i,item_id) ); } } @@ -668,7 +913,10 @@ void LLAgentWearables::processAgentInitialWearablesUpdate( LLMessageSystem* mesg // static void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void* userdata ) { - LLWearableType::EType type = (LLWearableType::EType)(intptr_t)userdata; + std::pair* wearable_data = (std::pair*)(intptr_t) userdata; + LLWearableType::EType type = wearable_data->first; + LLUUID item_id = wearable_data->second; + delete wearable_data; LLVOAvatar* avatar = gAgentAvatarp; if( !avatar ) @@ -679,7 +927,8 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void if( wearable ) { llassert( type == wearable->getType() ); - gAgentWearables.mWearableEntry[ type ].mWearable = wearable; + wearable->setItemID(item_id); + gAgentWearables.setWearable(type,wearable); // disable composites if initial textures are baked avatar->setupComposites(); @@ -687,7 +936,7 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void wearable->writeToAvatar( FALSE ); avatar->setCompositeUpdatesEnabled(TRUE); - gInventory.addChangedMask( LLInventoryObserver::LABEL, gAgentWearables.mWearableEntry[type].mItemID ); + gInventory.addChangedMask( LLInventoryObserver::LABEL, item_id ); } else { @@ -703,7 +952,7 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void gAgentWearables.mWearablesLoaded = TRUE; for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) { - if( !gAgentWearables.mWearableEntry[i].mItemID.isNull() && !gAgentWearables.mWearableEntry[i].mWearable ) + if( !gAgentWearables.getWearableItemID((LLWearableType::EType)i).isNull() && !gAgentWearables.getWearable((LLWearableType::EType)i) ) { gAgentWearables.mWearablesLoaded = FALSE; break; @@ -733,21 +982,19 @@ void LLAgentWearables::recoverMissingWearable( LLWearableType::EType type ) // Try to recover by replacing missing wearable with a new one. LLNotificationsUtil::add("ReplacedMissingWearable"); lldebugs << "Wearable " << LLWearableType::getTypeLabel( type ) << " could not be downloaded. Replaced inventory item with default wearable." << llendl; - LLWearable* new_wearable = gWearableList.createNewWearable(type); + LLWearable* new_wearable = LLWearableList::instance().createNewWearable(type); - S32 type_s32 = (S32) type; - mWearableEntry[type_s32].mWearable = new_wearable; + setWearable(type,new_wearable); new_wearable->writeToAvatar( TRUE ); // 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(LLFolderType::FT_LOST_AND_FOUND); + const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); LLPointer cb = new addWearableToAgentInventoryCallback( LLPointer(NULL), - type_s32, + type, new_wearable, addWearableToAgentInventoryCallback::CALL_RECOVERDONE); addWearableToAgentInventory( cb, new_wearable, lost_and_found_id, TRUE); @@ -756,17 +1003,8 @@ void LLAgentWearables::recoverMissingWearable( LLWearableType::EType type ) void LLAgentWearables::recoverMissingWearableDone() { // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated? - mWearablesLoaded = TRUE; - for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) - { - if( !mWearableEntry[i].mItemID.isNull() && !mWearableEntry[i].mWearable ) - { - mWearablesLoaded = FALSE; - break; - } - } - - if( mWearablesLoaded ) + updateWearablesLoaded(); + if (areWearablesLoaded()) { // Make sure that the server's idea of the avatar's wearables actually match the wearables. gAgent.sendAgentSetAppearance(); @@ -818,14 +1056,13 @@ void LLAgentWearables::createStandardWearables(BOOL female) once = true; donecb = new createStandardWearablesAllDoneCallback; } - llassert( mWearableEntry[i].mWearable == NULL ); - LLWearable* wearable = gWearableList.createNewWearable((LLWearableType::EType)i); - mWearableEntry[i].mWearable = wearable; + llassert(getWearableCount((LLWearableType::EType)i) == 0); + LLWearable* wearable = LLWearableList::instance().createNewWearable((LLWearableType::EType)i); // no need to update here... LLPointer cb = new addWearableToAgentInventoryCallback( donecb, - i, + (LLWearableType::EType)i, wearable, addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE); addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE); @@ -834,7 +1071,7 @@ void LLAgentWearables::createStandardWearables(BOOL female) } void LLAgentWearables::createStandardWearablesDone(S32 index) { - LLWearable* wearable = mWearableEntry[index].mWearable; + LLWearable* wearable = getWearable((LLWearableType::EType)index); if (wearable) { @@ -847,8 +1084,7 @@ void LLAgentWearables::createStandardWearablesAllDone() // ... because sendAgentWearablesUpdate will notify inventory // observers. mWearablesLoaded = TRUE; - sendAgentWearablesUpdate(); - gAgent.sendAgentSetAppearance(); + updateServer(); // Treat this as the first texture entry message, if none received yet gAgentAvatarp->onFirstTEMessageReceived(); @@ -890,10 +1126,10 @@ void LLAgentWearables::makeNewOutfit( for( i = 0; i < count; ++i ) { S32 index = wearables_to_include[i]; - LLWearable* old_wearable = mWearableEntry[ index ].mWearable; + LLWearable* old_wearable = getWearable((LLWearableType::EType)index); if( old_wearable ) { - LLViewerInventoryItem* item = gInventory.getItem(mWearableEntry[index].mItemID); + LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((LLWearableType::EType)index)); if (fUseOutfits) { std::string strOrdering = llformat("@%d", item->getWearableType() * 100); @@ -920,7 +1156,7 @@ void LLAgentWearables::makeNewOutfit( if (fUseLinks || isWearableCopyable((LLWearableType::EType)index)) { - LLWearable* new_wearable = gWearableList.createCopy(old_wearable); + LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable); if (rename_clothing) { new_wearable->setName(new_name); @@ -938,7 +1174,7 @@ void LLAgentWearables::makeNewOutfit( LLPointer cb = new addWearableToAgentInventoryCallback( cbdone, - index, + (LLWearableType::EType)index, new_wearable, todo); if (isWearableCopyable((LLWearableType::EType)index)) @@ -1053,9 +1289,9 @@ void LLAgentWearables::makeNewOutfit( } } -void LLAgentWearables::makeNewOutfitDone(S32 index) +void LLAgentWearables::makeNewOutfitDone(S32 type) { - LLUUID first_item_id = mWearableEntry[index].mItemID; + LLUUID first_item_id = getWearableItemID((LLWearableType::EType)type); // Open the inventory and select the first item we added. if( first_item_id.notNull() ) { @@ -1088,15 +1324,19 @@ void LLAgentWearables::addWearableToAgentInventory(LLPointerisDirty() ) @@ -1150,41 +1392,41 @@ bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LL // Called by removeWearable() and onRemoveWearableDialog() to actually do the removal. void LLAgentWearables::removeWearableFinal( LLWearableType::EType type ) { - LLWearable* old_wearable = mWearableEntry[ type ].mWearable; + gInventory.addChangedMask( LLInventoryObserver::LABEL, getWearableItemID(type) ); - gInventory.addChangedMask( LLInventoryObserver::LABEL, mWearableEntry[type].mItemID ); - - mWearableEntry[ type ].mWearable = NULL; - mWearableEntry[ type ].mItemID.setNull(); - - queryWearableCache(); + LLWearable* old_wearable = getWearable(type); + //queryWearableCache(); if( old_wearable ) { + popWearable(old_wearable); old_wearable->removeFromAvatar( TRUE ); } + queryWearableCache(); + // Update the server - sendAgentWearablesUpdate(); - gAgent.sendAgentSetAppearance(); + updateServer(); gInventory.notifyObservers(); } void LLAgentWearables::copyWearableToInventory( LLWearableType::EType type ) { - LLWearable* wearable = mWearableEntry[ type ].mWearable; + LLWearable* wearable = getWearable(type); if( wearable ) { // Save the old wearable if it has changed. if( wearable->isDirty() ) { - wearable = gWearableList.createCopyFromAvatar( wearable ); - mWearableEntry[ type ].mWearable = wearable; + LLWearable * new_wearable = LLWearableList::instance().createCopyFromAvatar( wearable ); + new_wearable->setItemID(wearable->getItemID()); + setWearable(type,new_wearable); + wearable = new_wearable; } // Make a new entry in the inventory. (Put it in the same folder as the original item if possible.) LLUUID category_id; - LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID ); + LLInventoryItem* item = gInventory.getItem( wearable->getItemID() ); if( item ) { category_id = item->getParentUUID(); @@ -1278,37 +1520,55 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it LLPointer new_item = items[i]; llassert(new_wearable); - LLWearableType::EType type = new_wearable->getType(); - wearables_to_remove[type] = FALSE; - - LLWearable* old_wearable = mWearableEntry[ type ].mWearable; - if( old_wearable ) + + if (new_wearable) { - const LLUUID& old_item_id = mWearableEntry[ type ].mItemID; - if( (old_wearable->getAssetID() == new_wearable->getAssetID()) && - (old_item_id == new_item->getUUID()) ) + LLWearableType::EType type = new_wearable->getType(); + wearables_to_remove[type] = FALSE; + + LLWearable* old_wearable = getWearable(type); + if( old_wearable ) { - lldebugs << "No change to wearable asset and item: " << LLWearableType::getTypeName( type ) << llendl; - continue; + const LLUUID& old_item_id = getWearableItemID(type); + if( (old_wearable->getAssetID() == new_wearable->getAssetID()) && + (old_item_id == new_item->getUUID()) ) + { + lldebugs << "No change to wearable asset and item: " << LLWearableType::getTypeName( type ) << llendl; + continue; + } + + gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); + + // Assumes existing wearables are not dirty. + if( old_wearable->isDirty() ) + { + llassert(0); + continue; + } } - gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - - // Assumes existing wearables are not dirty. - if( old_wearable->isDirty() ) + if (isFirstPhysicsWearable(type, new_item, new_wearable)) { - llassert(0); - continue; + return; + } + + new_wearable->setName(new_item->getName()); + new_wearable->setItemID(new_item->getUUID()); + + if (LLWearableType::getAssetType(type) == LLAssetType::AT_BODYPART) + { + // exactly one wearable per body part + setWearable(type,new_wearable); + } + else if(old_wearable) //Remove when multi-wearables are implemented. + { + setWearable(type,new_wearable); + } + else + { + pushWearable(type,new_wearable); } } - - if (isFirstPhysicsWearable(type, new_item, new_wearable)) - { - return; - } - - mWearableEntry[ type ].mItemID = new_item->getUUID(); - mWearableEntry[ type ].mWearable = new_wearable; } std::vector wearables_being_removed; @@ -1317,11 +1577,11 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it { if( wearables_to_remove[i] ) { - wearables_being_removed.push_back(mWearableEntry[ i ].mWearable); - mWearableEntry[ i ].mWearable = NULL; + LLWearable* wearable = getWearable((LLWearableType::EType)i); + wearables_being_removed.push_back(getWearable((LLWearableType::EType)i)); + popWearable(wearable); - gInventory.addChangedMask(LLInventoryObserver::LABEL, mWearableEntry[ i ].mItemID); - mWearableEntry[ i ].mItemID.setNull(); + gInventory.addChangedMask(LLInventoryObserver::LABEL, wearable->getItemID()); } } @@ -1349,8 +1609,8 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // Start rendering & update the server mWearablesLoaded = TRUE; - sendAgentWearablesUpdate(); - gAgent.sendAgentSetAppearance(); + updateServer(); + lldebugs << "setWearableOutfit() end" << llendl; } @@ -1359,9 +1619,14 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // User has picked "wear on avatar" from a menu. void LLAgentWearables::setWearableItem( LLInventoryItem* new_item, LLWearable* new_wearable ) { + //LLAgentDumper dumper("setWearableItem"); + if (isWearingItem(new_item->getUUID())) + { + llwarns << "wearable " << new_item->getUUID() << " is already worn" << llendl; + return; + } LLWearableType::EType type = new_wearable->getType(); - LLWearable* old_wearable = mWearableEntry[ type ].mWearable; // [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.0.0d) // Block if: we can't wear on that layer; or we're already wearing something there we can't take off @@ -1376,9 +1641,10 @@ void LLAgentWearables::setWearableItem( LLInventoryItem* new_item, LLWearable* n return; } + LLWearable* old_wearable = getWearable(type); if( old_wearable ) { - const LLUUID& old_item_id = mWearableEntry[ type ].mItemID; + const LLUUID& old_item_id = old_wearable->getItemID(); if( (old_wearable->getAssetID() == new_wearable->getAssetID()) && (old_item_id == new_item->getUUID()) ) { @@ -1391,7 +1657,7 @@ void LLAgentWearables::setWearableItem( LLInventoryItem* new_item, LLWearable* n // Bring up modal dialog: Save changes? Yes, No, Cancel LLSD payload; payload["item_id"] = new_item->getUUID(); - LLNotificationsUtil::add( "WearableSave", LLSD(), payload, boost::bind(LLAgentWearables::onSetWearableDialog, _1, _2, new_wearable)); + LLNotificationsUtil::add( "WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); return; } } @@ -1440,9 +1706,14 @@ void LLAgentWearables::setWearableFinal( LLInventoryItem* new_item, LLWearable* // Replace the old wearable with a new one. llassert( new_item->getAssetUUID() == new_wearable->getAssetID() ); - LLUUID old_item_id = mWearableEntry[ type ].mItemID; - mWearableEntry[ type ].mItemID = new_item->getUUID(); - mWearableEntry[ type ].mWearable = new_wearable; + LLWearable *old_wearable = getWearable(type); + LLUUID old_item_id; + if (old_wearable) + { + old_item_id = old_wearable->getItemID(); + } + new_wearable->setItemID(new_item->getUUID()); + setWearable(type,new_wearable); if (old_item_id.notNull()) { @@ -1454,9 +1725,7 @@ void LLAgentWearables::setWearableFinal( LLInventoryItem* new_item, LLWearable* queryWearableCache(); new_wearable->writeToAvatar( TRUE ); - // Update the server - sendAgentWearablesUpdate(); - gAgent.sendAgentSetAppearance(); + updateServer(); } void LLAgentWearables::queryWearableCache() @@ -1551,10 +1820,8 @@ LLUUID LLAgentWearables::computeBakedTextureHash(LLVOAvatarDefines::EBakedTextur // User has picked "remove from avatar" from a menu. // static -void LLAgentWearables::userRemoveWearable( void* userdata ) +void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type) { - LLWearableType::EType type = (LLWearableType::EType)(intptr_t)userdata; - if( !(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES) ) //&& //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) ) { @@ -1562,7 +1829,7 @@ void LLAgentWearables::userRemoveWearable( void* userdata ) } } -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 (gAgentCamera.cameraCustomizeAvatar()) @@ -1727,7 +1994,7 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo gMessageSystem->sendReliable(gAgent.getRegionHost()); } -void LLAgentWearables::userRemoveAllAttachments( void* userdata ) +void LLAgentWearables::userRemoveAllAttachments() { if (!isAgentAvatarValid()) return; @@ -1823,3 +2090,22 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra } } } +// MULTI-WEARABLE: DEPRECATED: item pending count relies on old messages that don't support multi-wearables. do not trust to be accurate +void LLAgentWearables::updateWearablesLoaded() +{ + mWearablesLoaded = TRUE; + for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) + { + if( !getWearableItemID((LLWearableType::EType)i).isNull() && !getWearable((LLWearableType::EType)i) ) + { + mWearablesLoaded = FALSE; + break; + } + } + +} +void LLAgentWearables::updateServer() +{ + sendAgentWearablesUpdate(); + gAgent.sendAgentSetAppearance(); +} diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 6d052142b..70f9b0969 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -52,8 +52,6 @@ class LLInitialWearablesFetch; class LLViewerObject; class LLTexLayerTemplate; -typedef std::vector llvo_vec_t; - class LLAgentWearables : public LLInitClass { //-------------------------------------------------------------------- @@ -72,7 +70,7 @@ public: // LLInitClass interface static void initClass(); protected: - void createStandardWearablesDone(S32 index); + void createStandardWearablesDone(S32 type); void createStandardWearablesAllDone(); //-------------------------------------------------------------------- @@ -85,7 +83,7 @@ public: BOOL isWearableCopyable(LLWearableType::EType type) const; BOOL areWearablesLoaded() const; - //void updateWearablesLoaded(); + void updateWearablesLoaded(); //void checkWearablesLoaded() const; //bool canMoveWearable(const LLUUID& item_id, bool closer_to_body); @@ -101,24 +99,23 @@ public: // Accessors //-------------------------------------------------------------------- public: - const LLUUID& getWearableItemID(LLWearableType::EType type ) const; - //const LLUUID getWearableAssetID(LLWearableType::EType type, U32 index /*= 0*/) const; + const LLUUID getWearableItemID(LLWearableType::EType type ) const; + const LLUUID getWearableAssetID(LLWearableType::EType type) const; const LLWearable* getWearableFromItemID(const LLUUID& item_id) const; LLWearable* getWearableFromItemID(const LLUUID& item_id); - //LLWearable* getWearableFromAssetID(const LLUUID& asset_id); + LLWearable* getWearableFromAssetID(const LLUUID& asset_id); LLInventoryItem* getWearableInventoryItem(LLWearableType::EType type); - static BOOL selfHasWearable( void* userdata ); // userdata is LLWearableType::EType + static BOOL selfHasWearable(LLWearableType::EType type); LLWearable* getWearable( const LLWearableType::EType type ); const LLWearable* getWearable( const LLWearableType::EType type ) const; - //const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const; - //LLWearable* getTopWearable(const LLWearableType::EType type); - //LLWearable* getBottomWearable(const LLWearableType::EType type); - //U32 getWearableCount(const LLWearableType::EType type) const; - //U32 getWearableCount(const U32 tex_index) const; + LLWearable* getTopWearable(const LLWearableType::EType type); + LLWearable* getBottomWearable(const LLWearableType::EType type); + U32 getWearableCount(const LLWearableType::EType type) const; + U32 getWearableCount(const U32 tex_index) const; void copyWearableToInventory( LLWearableType::EType type ); - static const U32 MAX_CLOTHING_PER_TYPE = 5; + static const U32 MAX_CLOTHING_PER_TYPE = 1; //-------------------------------------------------------------------- @@ -127,18 +124,18 @@ public: private: // Low-level data structure setter - public access is via setWearableItem, etc. - //void setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable); - //U32 pushWearable(const LLWearableType::EType type, LLWearable *wearable); - //void wearableUpdated(LLWearable *wearable); - //void popWearable(LLWearable *wearable); - //void popWearable(const LLWearableType::EType type, U32 index); + void setWearable(const LLWearableType::EType type, LLWearable *wearable); + U32 pushWearable(const LLWearableType::EType type, LLWearable *wearable); + void wearableUpdated(LLWearable *wearable); + void popWearable(LLWearable *wearable); + void popWearable(const LLWearableType::EType type); public: void setWearableItem(LLInventoryItem* new_item, LLWearable* wearable); void setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLWearable* >& wearables, BOOL remove); void setWearableName(const LLUUID& item_id, const std::string& new_name); //void addLocalTextureObject(const LLWearableType::EType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index); - //U32 getWearableIndex(LLWearable *wearable); + U32 getWearableIndex(const LLWearable *wearable) const; protected: void setWearableFinal( LLInventoryItem* new_item, LLWearable* new_wearable ); @@ -159,8 +156,7 @@ protected: * @param item_id The inventory item id of the new wearable to wear. * @param wearable The actual wearable data. */ - void addWearabletoAgentInventoryDone( - S32 index, + void addWearabletoAgentInventoryDone(const LLWearableType::EType type, const LLUUID& item_id, LLWearable* wearable); @@ -206,8 +202,8 @@ protected: void sendAgentWearablesUpdate(); void sendAgentWearablesRequest(); void queryWearableCache(); - //void updateServer(); - static void onInitialWearableAssetArrived(LLWearable* wearable, void* userdata); + void updateServer(); + static void onInitialWearableAssetArrived(LLWearable* wearable, void* userdata ); //-------------------------------------------------------------------- // Outfits @@ -224,14 +220,15 @@ public: BOOL rename_clothing); private: - void makeNewOutfitDone(S32 index); + void makeNewOutfitDone(S32 type); //-------------------------------------------------------------------- // Save Wearables //-------------------------------------------------------------------- public: - void saveWearableAs( LLWearableType::EType type, const std::string& new_name, BOOL save_in_lost_and_found ); - void saveWearable( LLWearableType::EType type, BOOL send_update = TRUE ); + void saveWearableAs(const LLWearableType::EType type, const std::string& new_name, BOOL save_in_lost_and_found ); + void saveWearable(const LLWearableType::EType type, BOOL send_update = TRUE, + const std::string new_name = ""); void saveAllWearables(); void revertWearable( LLWearableType::EType type ); @@ -241,14 +238,16 @@ public: // Static UI hooks //-------------------------------------------------------------------- public: - static void userRemoveWearable( void* userdata ); // userdata is LLWearableType::EType - static void userRemoveAllClothes( void* userdata ); // userdata is NULL + static void userRemoveWearable(const LLWearableType::EType &type); + static void userRemoveAllClothes(); + + typedef std::vector llvo_vec_t; + // static void userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array); // [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2.0a) | Added: Catznip-2.2.0a // Not the best way to go about this but other attempts changed far too much LL code to be a viable solution static void userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array, bool fAttachOnly = false); // [/SL:KB] - static void userRemoveAllAttachments( void* userdata); // userdata is NULLy); static void userRemoveMultipleAttachments(llvo_vec_t& llvo_array); static void userRemoveAllAttachments(); static void userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array); @@ -276,14 +275,12 @@ private: //-------------------------------------------------------------------- // Member variables //-------------------------------------------------------------------- - struct LLWearableEntry - { - LLWearableEntry() : mItemID( LLUUID::null ), mWearable( NULL ) {} +private: + typedef std::vector wearableentry_vec_t; // all wearables of a certain type (EG all shirts) + typedef std::map wearableentry_map_t; // wearable "categories" arranged by wearable type + wearableentry_map_t mWearableDatas; - LLUUID mItemID; // ID of the inventory item in the agent's inventory. - LLWearable* mWearable; - }; - LLWearableEntry mWearableEntry[ LLWearableType::WT_COUNT ]; + static BOOL mInitialWearablesUpdateReceived; BOOL mWearablesLoaded; //-------------------------------------------------------------------------------- @@ -322,15 +319,14 @@ private: * @param wearable The wearable data. * @param todo Bitmask of actions to take on completion. */ - addWearableToAgentInventoryCallback( - LLPointer cb, - S32 index, - LLWearable* wearable, - U32 todo = CALL_NONE); + addWearableToAgentInventoryCallback(LLPointer cb, + LLWearableType::EType type, + LLWearable* wearable, + U32 todo = CALL_NONE); virtual void fire(const LLUUID& inv_item); private: - S32 mIndex; + LLWearableType::EType mType; LLWearable* mWearable; U32 mTodo; LLPointer mCB; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 11fb33c26..1b3fae454 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3743,6 +3743,7 @@ void LLAppViewer::idle() gEventNotifier.update(); gIdleCallbacks.callFunctions(); + gInventory.idleNotifyObservers(); } if (gDisconnected) diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp index 6063995cf..1bfd2cb9b 100644 --- a/indra/newview/llcallbacklist.cpp +++ b/indra/newview/llcallbacklist.cpp @@ -47,7 +47,7 @@ LLCallbackList gIdleCallbacks; // Member functions // -LLCallbackList::LLCallbackList() : mLoopingOverCallbackList(false) +LLCallbackList::LLCallbackList() { // nothing } @@ -96,15 +96,7 @@ BOOL LLCallbackList::deleteFunction( callback_t func, void *data) callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t); if (iter != mCallbackList.end()) { - if (mLoopingOverCallbackList) - { - iter->first = NULL; // Mark for removal later (when we return to LLCallbackList::callFunctions). - mNeedErase = true; - } - else - { - mCallbackList.erase(iter); - } + mCallbackList.erase(iter); return TRUE; } else @@ -116,39 +108,82 @@ BOOL LLCallbackList::deleteFunction( callback_t func, void *data) void LLCallbackList::deleteAllFunctions() { - llassert(!mLoopingOverCallbackList); // Only called from unit tests. mCallbackList.clear(); } void LLCallbackList::callFunctions() { - llassert(!mLoopingOverCallbackList); - mLoopingOverCallbackList = true; - mNeedErase = false; - for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ++iter) + for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) { - if (iter->first) // Not pending removal? + callback_list_t::iterator curiter = iter++; + curiter->first(curiter->second); + } +} + +// Shim class to allow arbitrary boost::bind +// expressions to be run as one-time idle callbacks. +class OnIdleCallbackOneTime +{ +public: + OnIdleCallbackOneTime(nullary_func_t callable): + mCallable(callable) + { + } + static void onIdle(void *data) + { + gIdleCallbacks.deleteFunction(onIdle, data); + OnIdleCallbackOneTime* self = reinterpret_cast(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. +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(data); + bool done = self->call(); + if (done) { - iter->first(iter->second); // This can theorectically set any iter->first to NULL, which means the entry should be erased. + gIdleCallbacks.deleteFunction(onIdle, data); + delete self; } } - mLoopingOverCallbackList = false; - if (mNeedErase) + bool call() { - callback_list_t::iterator iter = mCallbackList.begin(); - while (iter != mCallbackList.end()) - { - if (!iter->first) - { - iter = mCallbackList.erase(iter); - } - else - { - ++iter; - } - } + 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); } #ifdef _DEBUG diff --git a/indra/newview/llcallbacklist.h b/indra/newview/llcallbacklist.h index 240346478..1819f865a 100644 --- a/indra/newview/llcallbacklist.h +++ b/indra/newview/llcallbacklist.h @@ -34,6 +34,7 @@ #define LL_LLCALLBACKLIST_H #include "llstl.h" +#include class LLCallbackList { @@ -53,13 +54,20 @@ public: protected: // Use a list so that the callbacks are ordered in case that matters - typedef std::pair callback_pair_t; // callback_t is a (function) pointer. If it is NULL it means that the entry should be considered deleted. + typedef std::pair callback_pair_t; typedef std::list callback_list_t; callback_list_t mCallbackList; - bool mLoopingOverCallbackList; // True while looping over mCallbackList and calling the callback_t functions (see callFunctions). - bool mNeedErase; // True when deleteFunction was called while mLoopingOverCallbackList was true. }; +typedef boost::function nullary_func_t; +typedef boost::function bool_func_t; + +// Call a given callable once in idle loop. +void doOnIdleOneTime(nullary_func_t callable); + +// Repeatedly call a callable in idle loop until it returns true. +void doOnIdleRepeating(bool_func_t callable); + extern LLCallbackList gIdleCallbacks; #endif diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 23633d74c..059198597 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -1313,6 +1313,12 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector* return; } } + else + { + static const LLCachedControl draw_orphans("ShyotlDrawOrphanAttachments",false); + if(!draw_orphans) + return; + } } @@ -1385,6 +1391,12 @@ void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update) return; } } + else + { + static const LLCachedControl draw_orphans("ShyotlDrawOrphanAttachments",false); + if(!draw_orphans) + return; + } } LLCamera camera = transformCamera(camera_in); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 1382d6e89..5e6f8f1a5 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -719,7 +719,7 @@ bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const if(avatar) { // Create a new wearable in the default folder for the wearable's asset type. - LLWearable* wearable = gWearableList.createNewWearable( (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger() ); + LLWearable* wearable = LLWearableList::instance().createNewWearable( (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger() ); LLAssetType::EType asset_type = wearable->getAssetType(); LLUUID folder_id; diff --git a/indra/newview/llfloaterdaycycle.cpp b/indra/newview/llfloaterdaycycle.cpp index 0799ca330..02ea83fb2 100644 --- a/indra/newview/llfloaterdaycycle.cpp +++ b/indra/newview/llfloaterdaycycle.cpp @@ -288,7 +288,7 @@ bool LLFloaterDayCycle::isOpen() { if (sDayCycle != NULL) { - return true; + return sDayCycle->getVisible(); } return false; } diff --git a/indra/newview/llfloaterenvsettings.cpp b/indra/newview/llfloaterenvsettings.cpp index 196cf92b7..e021e365c 100644 --- a/indra/newview/llfloaterenvsettings.cpp +++ b/indra/newview/llfloaterenvsettings.cpp @@ -197,7 +197,7 @@ bool LLFloaterEnvSettings::isOpen() { if (sEnvSettings != NULL) { - return true; + return sEnvSettings->getVisible(); } return false; } diff --git a/indra/newview/llfloaterwater.cpp b/indra/newview/llfloaterwater.cpp index e35d7e6c0..3b04f9387 100644 --- a/indra/newview/llfloaterwater.cpp +++ b/indra/newview/llfloaterwater.cpp @@ -316,7 +316,7 @@ void LLFloaterWater::show() bool LLFloaterWater::isOpen() { if (sWaterMenu != NULL) { - return true; + return sWaterMenu->getVisible(); } return false; } diff --git a/indra/newview/llfloaterwindlight.cpp b/indra/newview/llfloaterwindlight.cpp index dba360b88..9ec787a6c 100644 --- a/indra/newview/llfloaterwindlight.cpp +++ b/indra/newview/llfloaterwindlight.cpp @@ -473,7 +473,7 @@ void LLFloaterWindLight::show() bool LLFloaterWindLight::isOpen() { if (sWindLight != NULL) { - return true; + return sWindLight->getVisible(); } return false; } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 0295fa258..c45b05e10 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2917,7 +2917,7 @@ void LLFolderBridge::createWearable(LLFolderBridge* bridge, LLWearableType::ETyp // static void LLFolderBridge::createWearable(LLUUID parent_id, LLWearableType::EType type) { - LLWearable* wearable = gWearableList.createNewWearable(type); + LLWearable* wearable = LLWearableList::instance().createNewWearable(type); LLAssetType::EType asset_type = wearable->getAssetType(); LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE; create_inventory_item(gAgent.getID(), gAgent.getSessionID(), @@ -4148,6 +4148,14 @@ std::string LLObjectBridge::getLabelSuffix() const { std::string attachment_point_name = avatar->getAttachedPointName(mUUID); LLStringUtil::toLower(attachment_point_name); + LLViewerObject* pObj = (rlv_handler_t::isEnabled()) ? avatar->getWornAttachment( mUUID ) : NULL; +// [RLVa:KB] + if ( pObj && (gRlvAttachmentLocks.isLockedAttachment(pObj) || + gRlvAttachmentLocks.isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pObj),RLV_LOCK_REMOVE))) + { + return LLItemBridge::getLabelSuffix() + std::string(" (locked to ") + attachment_point_name + std::string(")"); + } +// [/RLVa:KB] return LLItemBridge::getLabelSuffix() + std::string(" (worn on ") + attachment_point_name + std::string(")"); } else @@ -4155,11 +4163,21 @@ std::string LLObjectBridge::getLabelSuffix() const // testzone attachpt if(avatar) { - std::map::iterator iter = avatar->mUnsupportedAttachmentPoints.begin(); - std::map::iterator end = avatar->mUnsupportedAttachmentPoints.end(); + std::map >::iterator iter = avatar->mUnsupportedAttachmentPoints.begin(); + std::map >::iterator end = avatar->mUnsupportedAttachmentPoints.end(); for( ; iter != end; ++iter) - if((*iter).second == mUUID) + if((*iter).second.first == mUUID) + { +// [RLVa:KB] + LLViewerObject* pObj = (rlv_handler_t::isEnabled()) ? gObjectList.findObject((*iter).second.second) : NULL; + if ( pObj && (gRlvAttachmentLocks.isLockedAttachment(pObj) || + gRlvAttachmentLocks.isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pObj),RLV_LOCK_REMOVE))) + { + return LLItemBridge::getLabelSuffix() + std::string(" (locked to unsupported point %d)", (*iter).first); + } +// [/RLVa:KB] return LLItemBridge::getLabelSuffix() + llformat(" (worn on unsupported point %d)", (*iter).first); + } } // return LLItemBridge::getLabelSuffix(); @@ -4474,7 +4492,7 @@ void wear_inventory_item_on_avatar( LLInventoryItem* item ) lldebugs << "wear_inventory_item_on_avatar( " << item->getName() << " )" << llendl; - gWearableList.getAsset(item->getAssetUUID(), + LLWearableList::instance().getAsset(item->getAssetUUID(), item->getName(), item->getType(), LLWearableBridge::onWearOnAvatarArrived, @@ -4596,8 +4614,8 @@ void LLOutfitObserver::done() name = cat->getName(); } LLViewerInventoryItem* item = NULL; - item_ref_t::iterator it = mComplete.begin(); - item_ref_t::iterator end = mComplete.end(); + uuid_vec_t::iterator it = mComplete.begin(); + uuid_vec_t::iterator end = mComplete.end(); LLUUID pid; for(; it < end; ++it) { @@ -4914,7 +4932,7 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) // [/RLVa:KB] found = found_container.get(i); - gWearableList.getAsset(found->mAssetID, + LLWearableList::instance().getAsset(found->mAssetID, found->mName, found->mAssetType, wear_inventory_category_on_avatar_loop, @@ -5036,7 +5054,7 @@ void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, B //And this code does not handle failed asset uploads properly // if(!wearable->isMatchedToInventoryItem(item )) // { -// wearable = gWearableList.createWearableMatchedToInventoryItem( wearable, item ); +// wearable = LLWearableList::instance().createWearableMatchedToInventoryItem( wearable, item ); // // Now that we have an asset that matches the // // item, update the item to point to the new // // asset. @@ -5152,7 +5170,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) if ( (pWearable) && ( (!rlv_handler_t::isEnabled()) || (gRlvWearableLocks.canRemove(pWearable->getType())) ) ) // [/RLVa:KB] { - gWearableList.getAsset( item->getAssetUUID(), + LLWearableList::instance().getAsset( item->getAssetUUID(), item->getName(), item->getType(), LLWearableBridge::onRemoveFromAvatarArrived, @@ -5223,6 +5241,10 @@ std::string LLWearableBridge::getLabelSuffix() const { if (get_is_item_worn(getItem())) { + if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(getItem())) ) + { + return LLItemBridge::getLabelSuffix() + " (locked)"; + } return LLItemBridge::getLabelSuffix() + " (worn)"; } else @@ -5255,7 +5277,7 @@ void LLWearableBridge::performAction(LLFolderView* folder, LLInventoryModel* mod LLViewerInventoryItem* item = getItem(); if (item) { - gWearableList.getAsset(item->getAssetUUID(), + LLWearableList::instance().getAsset(item->getAssetUUID(), item->getName(), item->getType(), LLWearableBridge::onRemoveFromAvatarArrived, @@ -5470,7 +5492,7 @@ void LLWearableBridge::onWearOnAvatarArrived( LLWearable* wearable, void* userda // if(!wearable->isMatchedToInventoryItem(item)) // { -// LLWearable* new_wearable = gWearableList.createWearableMatchedToInventoryItem( wearable, item ); +// LLWearable* new_wearable = LLWearableList::instance().createWearableMatchedToInventoryItem( wearable, item ); // // // Now that we have an asset that matches the // // item, update the item to point to the new @@ -5549,7 +5571,7 @@ void LLWearableBridge::onRemoveFromAvatar(void* user_data) LLViewerInventoryItem* item = self->getItem(); if (item) { - gWearableList.getAsset(item->getAssetUUID(), + LLWearableList::instance().getAsset(item->getAssetUUID(), item->getName(), item->getType(), onRemoveFromAvatarArrived, diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index c6c205f86..f084a42ac 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -153,7 +153,10 @@ const char* NEW_CATEGORY_NAMES[LLFolderType::FT_COUNT] = "Current Outfit", // FT_CURRENT_OUTFIT = 46, "New Outfit", // FT_OUTFIT = 47, "My Outfits", // FT_MY_OUTFITS = 48, - "Inbox" // FT_INBOX = 49, + "Mesh", // FT_MESH = 49, + "Inbox", // FT_INBOX = 50, + "Outbox", // FT_OUTBOX = 51, + "Basic Root" // FT_BASIC_ROOT = 52 }; struct InventoryIDPtrLess @@ -221,22 +224,40 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) LLInventoryModel gInventory; // Default constructor -LLInventoryModel::LLInventoryModel() : - mModifyMask(LLInventoryObserver::ALL), +LLInventoryModel::LLInventoryModel() +: mModifyMask(LLInventoryObserver::ALL), + mChangedItemIDs(), + mCategoryMap(), + mItemMap(), + mCategoryLock(), + mItemLock(), mLastItem(NULL), + mParentChildCategoryTree(), + mParentChildItemTree(), + mObservers(), + mIsNotifyObservers(FALSE), mIsAgentInvUsable(false) { } // Destroys the object LLInventoryModel::~LLInventoryModel() +{ + cleanupInventory(); +} + +void LLInventoryModel::cleanupInventory() { empty(); - for (observer_list_t::iterator iter = mObservers.begin(); - iter != mObservers.end(); ++iter) + // Deleting one observer might erase others from the list, so always pop off the front + while (!mObservers.empty()) { - delete *iter; + observer_list_t::iterator iter = mObservers.begin(); + LLInventoryObserver* observer = *iter; + mObservers.erase(iter); + delete observer; } + mObservers.clear(); } // This is a convenience function to check if one object has a parent @@ -245,6 +266,7 @@ BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id, const BOOL break_on_recursion) const { + if (obj_id == cat_id) return TRUE; LLInventoryObject* obj = getObject(obj_id); int depthCounter = 0; while(obj) @@ -502,7 +524,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, { name.assign(pname); } - if(preferred_type < LLFolderType::FT_TEXTURE || preferred_type > LLFolderType::FT_INBOX) + else if(preferred_type < (LLFolderType::EType)0 || preferred_type >= LLFolderType::FT_COUNT) name.assign(NEW_CATEGORY_NAME); else name.assign(NEW_CATEGORY_NAMES[preferred_type]); @@ -758,12 +780,23 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) return mask; } + // We're hiding mesh types +#if 0 + if (item->getType() == LLAssetType::AT_MESH) + { + return mask; + } +#endif + LLViewerInventoryItem* old_item = getItem(item->getUUID()); + LLPointer new_item; if(old_item) { - // We already have an old item, modify it's values + // We already have an old item, modify its values + new_item = old_item; LLUUID old_parent_id = old_item->getParentUUID(); LLUUID new_parent_id = item->getParentUUID(); + if(old_parent_id != new_parent_id) { // need to update the parent-child tree @@ -790,7 +823,7 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) else { // Simply add this item - LLPointer new_item = new LLViewerInventoryItem(item); + new_item = new LLViewerInventoryItem(item); addItem(new_item); if(item->getParentUUID().isNull()) @@ -850,11 +883,40 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) } mask |= LLInventoryObserver::ADD; } - if(item->getType() == LLAssetType::AT_CALLINGCARD) + if(new_item->getType() == LLAssetType::AT_CALLINGCARD) { mask |= LLInventoryObserver::CALLING_CARD; + // Handle user created calling cards. + // Target ID is stored in the description field of the card. + LLUUID id; + std::string desc = new_item->getDescription(); + BOOL isId = desc.empty() ? FALSE : id.set(desc, FALSE); + if (isId) + { + // Valid UUID; set the item UUID and rename it + new_item->setCreator(id); + std::string avatar_name; + + if (gCacheName->getFullName(id, avatar_name)) + { + new_item->rename(avatar_name); + mask |= LLInventoryObserver::LABEL; + } + else + { + // Fetch the current name + gCacheName->get(id, FALSE, + boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), + _1, _2, _3)); + } + + } } - addChangedMask(mask, item->getUUID()); + /*else if (new_item->getType() == LLAssetType::AT_GESTURE) + { + mask |= LLInventoryObserver::GESTURE; + }*/ + addChangedMask(mask, new_item->getUUID()); return mask; } @@ -1001,39 +1063,40 @@ void LLInventoryModel::deleteObject(const LLUUID& id) return; } - lldebugs << "Deleting inventory object " << id << llendl; - mLastItem = NULL; - LLUUID parent_id = obj->getParentUUID(); - mCategoryMap.erase(id); - mItemMap.erase(id); - //mInventory.erase(id); - item_array_t* item_list = getUnlockedItemArray(parent_id); - if(item_list) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)((LLInventoryObject*)obj); - item_list->removeObj(item); - } - cat_array_t* cat_list = getUnlockedCatArray(parent_id); - if(cat_list) - { - LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj); - cat_list->removeObj(cat); - } - item_list = getUnlockedItemArray(id); - if(item_list) - { - delete item_list; - mParentChildItemTree.erase(id); - } - cat_list = getUnlockedCatArray(id); - if(cat_list) - { - delete cat_list; - mParentChildCategoryTree.erase(id); - } - addChangedMask(LLInventoryObserver::REMOVE, id); - obj = NULL; // delete obj + lldebugs << "Deleting inventory object " << id << llendl; + mLastItem = NULL; + LLUUID parent_id = obj->getParentUUID(); + mCategoryMap.erase(id); + mItemMap.erase(id); + //mInventory.erase(id); + item_array_t* item_list = getUnlockedItemArray(parent_id); + if(item_list) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)((LLInventoryObject*)obj); + item_list->removeObj(item); } + cat_array_t* cat_list = getUnlockedCatArray(parent_id); + if(cat_list) + { + LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj); + cat_list->removeObj(cat); + } + item_list = getUnlockedItemArray(id); + if(item_list) + { + delete item_list; + mParentChildItemTree.erase(id); + } + cat_list = getUnlockedCatArray(id); + if(cat_list) + { + delete cat_list; + mParentChildCategoryTree.erase(id); + } + addChangedMask(LLInventoryObserver::REMOVE, id); + obj = NULL; // delete obj + gInventory.notifyObservers(); +} // Delete a particular inventory item by ID, and remove it from the server. void LLInventoryModel::purgeObject(const LLUUID &id) @@ -1219,39 +1282,56 @@ BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer) const return mObservers.find(observer) != mObservers.end(); } -// Call this method when it's time to update everyone on a new state, -// by default, the inventory model will not update observers -// automatically. -// The optional argument 'service_name' is used by Agent Inventory Service [DEV-20328] -void LLInventoryModel::notifyObservers(const std::string service_name) +void LLInventoryModel::idleNotifyObservers() { + if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.size() == 0)) + { + return; + } + notifyObservers(); +} + +// Call this method when it's time to update everyone on a new state. +void LLInventoryModel::notifyObservers() +{ + if (mIsNotifyObservers) + { + // Within notifyObservers, something called notifyObservers + // again. This type of recursion is unsafe because it causes items to be + // processed twice, and this can easily lead to infinite loops. + llwarns << "Call was made to notifyObservers within notifyObservers!" << llendl; + return; + } + + mIsNotifyObservers = TRUE; for (observer_list_t::iterator iter = mObservers.begin(); iter != mObservers.end(); ) { LLInventoryObserver* observer = *iter; - if (service_name.empty()) - { - observer->changed(mModifyMask); - } - else - { - observer->mMessageName = service_name; - observer->changed(mModifyMask); - } + observer->changed(mModifyMask); - // safe way to incrament since changed may delete entries! (@!##%@!@&*!) + // safe way to increment since changed may delete entries! (@!##%@!@&*!) iter = mObservers.upper_bound(observer); } mModifyMask = LLInventoryObserver::NONE; mChangedItemIDs.clear(); + mIsNotifyObservers = FALSE; } // store flag for change // and id of object change applies to void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) { + if (mIsNotifyObservers) + { + // Something marked an item for change within a call to notifyObservers + // (which is in the process of processing the list of items marked for change). + // This means the change may fail to be processed. + llwarns << "Adding changed mask within notify observers! Change will likely be lost." << llendl; + } + mModifyMask |= mask; if (referent.notNull()) { @@ -1266,32 +1346,7 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) } } -// This method to prepares a set of mock inventory which provides -// minimal functionality before the actual arrival of inventory. -/* -void LLInventoryModel::mock(const LLUUID& root_id) -{ - llinfos << "LLInventoryModel::mock() " << root_id << llendl; - if(root_id.isNull()) - { - llwarns << "Not a valid root id" << llendl; - return; - } - LLPointer cat = new LLViewerInventoryCategory( - root_id, - LLUUID::null, - LLAssetType::AT_CATEGORY, - NEW_CATEGORY_NAMES[LLFolderType::FT_ROOT_CATEGORY], - gAgent.getID()); - addCategory(cat); - gInventory.buildParentChildMap(); -} -*/ - -//If we get back a normal response, handle it here -// Note: this is the responder used in "fetchInventory" cap, -// this is not responder for "WebFetchInventoryDescendents" or "agent/inventory" cap - +// If we get back a normal response, handle it here void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content) { start_new_inventory_observer(); @@ -1352,16 +1407,16 @@ void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content) { changes |= gInventory.updateItem(*it); } - gInventory.notifyObservers("fetchinventory"); + gInventory.notifyObservers(); gViewerWindow->getWindow()->decBusyCount(); } //If we get back an error (not found, etc...), handle it here void LLInventoryModel::fetchInventoryResponder::error(U32 status, const std::string& reason) { - LL_INFOS("Inventory") << "fetchInventory::error " - << status << ": " << reason << LL_ENDL; - gInventory.notifyObservers("fetchinventory"); + llinfos << "fetchInventory::error " + << status << ": " << reason << llendl; + gInventory.notifyObservers(); } bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const @@ -1462,7 +1517,7 @@ void fetchDescendentsResponder::result(const LLSD& content) titem->setParent(lost_uuid); titem->updateParentOnServer(FALSE); gInventory.updateItem(titem); - gInventory.notifyObservers("fetchDescendents"); + gInventory.notifyObservers(); } } @@ -1539,7 +1594,7 @@ void fetchDescendentsResponder::result(const LLSD& content) LLInventoryModel::stopBackgroundFetch(); } - gInventory.notifyObservers("fetchDescendents"); + gInventory.notifyObservers(); } //If we get back an error (not found, etc...), handle it here @@ -1572,7 +1627,7 @@ void fetchDescendentsResponder::error(U32 status, const std::string& reason) LLInventoryModel::stopBackgroundFetch(); } } - gInventory.notifyObservers("fetchDescendents"); + gInventory.notifyObservers(); } //static Bundle up a bunch of requests to send all at once. @@ -1954,6 +2009,11 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) //llinfos << "LLInventoryModel::addCategory()" << llendl; if(category) { + // We aren't displaying the Meshes folder + if (category->getPreferredType() == LLFolderType::FT_MESH) + { + return; + } // Insert category uniquely into the map mCategoryMap[category->getUUID()] = category; // LLPointer will deref and delete the old one //mInventory[category->getUUID()] = category; @@ -1962,7 +2022,7 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) void LLInventoryModel::addItem(LLViewerInventoryItem* item) { - //llinfos << "LLInventoryModel::addItem()" << llendl; + llassert(item); if(item) { // This can happen if assettype enums from llassettype.h ever change. @@ -2030,8 +2090,8 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const descendents_actual += update.mDescendentDelta; cat->setDescendentCount(descendents_actual); cat->setVersion(++version); - llinfos << "accounted: '" << cat->getName() << "' " - << version << " with " << descendents_actual + lldebugs << "accounted: '" << cat->getName() << "' " + << version << " with " << descendents_actual << " descendents." << llendl; } } @@ -3214,7 +3274,9 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) } LLUUID tid; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid); +#ifndef LL_RELEASE_FOR_DOWNLOAD llinfos << "Bulk inventory: " << tid << llendl; +#endif update_map_t update; cat_array_t folders; @@ -3342,7 +3404,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) LLInventoryView::sWearNewClothing = FALSE; } - if (tid == LLInventoryView::sWearNewClothingTransactionID) + if (tid.notNull() && tid == LLInventoryView::sWearNewClothingTransactionID) { count = wearable_ids.size(); for (i = 0; i < count; ++i) @@ -3428,6 +3490,9 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**) { cat->setVersion(version); cat->setDescendentCount(descendents); + // Get this UUID on the changed list so that whatever's listening for it + // will get triggered. + gInventory.addChangedMask(LLInventoryObserver::INTERNAL, cat->getUUID()); } gInventory.notifyObservers(); } diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index f8e927d4a..d3d525655 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -131,6 +131,7 @@ public: public: LLInventoryModel(); ~LLInventoryModel(); + void cleanupInventory(); // //protected: // @@ -375,7 +376,7 @@ public: LLUUID createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, const std::string& name); - + // Internal methods that add inventory and make sure that all of // the internal data structures are consistent. These methods // should be passed pointers of newly created objects, and the @@ -446,10 +447,13 @@ public: **/ public: - // Call to explicitly update everyone on a new state. The optional argument - // 'service_name' is used by Agent Inventory Service [DEV-20328] - void notifyObservers(const std::string service_name=""); + // Called by the idle loop. Only updates if new state is detected. Call + // notifyObservers() manually to update regardless of whether state change + // has been indicated. + void idleNotifyObservers(); + // Call to explicitly update everyone on a new state. + void notifyObservers(); // Allows outsiders to tell the inventory if something has // been changed 'under the hood', but outside the control of the // inventory. The next notify will include that notification. @@ -459,6 +463,9 @@ protected: // Updates all linked items pointing to this id. void addChangedMaskForLinks(const LLUUID& object_id, U32 mask); private: + // Flag set when notifyObservers is being called, to look for bugs + // where it's called recursively. + BOOL mIsNotifyObservers; // Variables used to track what has changed since the last notify. U32 mModifyMask; changed_items_t mChangedItemIDs; diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index 12e1408e0..b6904308f 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -44,7 +44,7 @@ #include "llcharacter.h" #include "llviewercontrol.h" #include "llviewervisualparam.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "lldriverparam.h" typedef std::map controller_map_t; @@ -497,9 +497,9 @@ BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask) { // Skip if disabled globally. static const LLCachedControl avatar_physics("AvatarPhysics",false); - bool supports_physics = !avatar_physics || (!((LLVOAvatar*)mCharacter)->isSelf() && !((LLVOAvatar*)mCharacter)->mSupportsPhysics); + bool physics_unsupported = !avatar_physics || (!((LLVOAvatar*)mCharacter)->isSelf() && !((LLVOAvatar*)mCharacter)->mSupportsPhysics); //Treat lod 0 as AvatarPhyiscs:FALSE. AvatarPhyiscs setting is superfluous unless we decide to hook it into param sending. - if (supports_physics || !LLVOAvatar::sPhysicsLODFactor) + if (physics_unsupported || !LLVOAvatar::sPhysicsLODFactor) { if(!mIsDefault) { @@ -510,8 +510,8 @@ BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask) } mCharacter->updateVisualParams(); } - if(!supports_physics) //Only use emerald physics if avatarphysiscs is really off, or the client doesn't seem to support new physics. - ((LLVOAvatar*)mCharacter)->idleUpdateBoobEffect(); //Fall back to emerald physics + if(physics_unsupported) //Only use emerald physics if avatarphysiscs is really off, or the client doesn't seem to support new physics. + ((LLVOAvatar*)mCharacter)->idleUpdateBoobEffect(); //Fall back to emerald physics return TRUE; } @@ -758,7 +758,7 @@ BOOL LLPhysicsMotion::onUpdate(F32 time) const F32 area_for_this_setting = area_for_max_settings + (area_for_min_settings-area_for_max_settings)*(1.0-lod_factor); const F32 pixel_area = (F32) sqrt(mCharacter->getPixelArea()); - const BOOL is_self = (dynamic_cast(mCharacter) != NULL && ((LLVOAvatar*)mCharacter)->isSelf()); + const BOOL is_self = (dynamic_cast(mCharacter) != NULL); if ((pixel_area > area_for_this_setting) || is_self) { const F32 position_diff_local = llabs(mPositionLastUpdate_local-position_new_local_clamped); diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 52d538fee..32e7c2777 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -391,6 +391,11 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) object = (LLViewerObject*)object->getParent(); } + if (!object) + { + return TRUE; // unexpected, but escape + } + // Object is an avatar, so check for mute by id. LLVOAvatar* avatar = (LLVOAvatar*)object; std::string name = avatar->getFullname(); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 2a521e018..022398eb9 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1077,3 +1077,9 @@ LLViewerInventoryCategory *LLViewerInventoryItem::getLinkedCategory() const } return NULL; } +void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std::string& name, bool is_group) +{ + rename(name); + gInventory.addChangedMask(LLInventoryObserver::LABEL, getUUID()); + gInventory.notifyObservers(); +} diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 00782eb25..bb63824bb 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -145,6 +145,8 @@ public: LLViewerInventoryItem *getLinkedItem() const; LLViewerInventoryCategory *getLinkedCategory() const; + // callback + void onCallingCardNameLookup(const LLUUID& id, const std::string& name, bool is_group); protected: BOOL mIsComplete; LLTransactionID mTransactionID; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 0577f7b5d..4850d5453 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -2390,7 +2390,7 @@ class LLSelfRemoveAllAttachments : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - LLAgentWearables::userRemoveAllAttachments(NULL); + LLAgentWearables::userRemoveAllAttachments(); return true; } }; @@ -9173,7 +9173,7 @@ class LLEditEnableTakeOff : public view_listener_t if ( !(rlv_handler_t::isEnabled()) || (gRlvWearableLocks.canRemove(type)) ) // [/RLVa:KB] - new_value = LLAgentWearables::selfHasWearable((void *)type); + new_value = LLAgentWearables::selfHasWearable(type); gMenuHolder->findControl(control_name)->setValue(new_value); return false; @@ -9187,14 +9187,14 @@ class LLEditTakeOff : public view_listener_t std::string clothing = userdata.asString(); if (clothing == "all") { - LLAgentWearables::userRemoveAllClothes(NULL); + LLAgentWearables::userRemoveAllClothes(); } else { LLWearableType::EType type = LLWearableType::typeNameToType(clothing); if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) - LLAgentWearables::userRemoveWearable((void*)type); + LLAgentWearables::userRemoveWearable(type); } return true; } diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index a458f8e10..795e4cbcc 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -201,7 +201,7 @@ public: S32 mNumUnknownKills; S32 mNumDeadObjects; S32 mMinNumDeadObjects; -protected: +//protected: std::vector mOrphanParents; // LocalID/ip,port of orphaned objects std::vector mOrphanChildren; // UUID's of orphaned objects S32 mNumOrphans; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 6a25ef73c..2426c75a5 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -190,6 +190,7 @@ #include "llviewerjoystick.h" #include "llviewernetwork.h" #include "llpostprocess.h" +#include "llwearablelist.h" #include "llnotifications.h" #include "llnotificationsutil.h" @@ -575,6 +576,57 @@ public: ypos += y_inc; + S32 total_objects = gObjectList.getNumObjects(); + S32 ID_objects = gObjectList.mUUIDObjectMap.size(); + S32 dead_objects = gObjectList.mNumDeadObjects; + S32 dead_object_list = gObjectList.mDeadObjects.size(); + S32 dead_object_check = 0; + S32 total_avatars = 0; + S32 ID_avatars = gObjectList.mUUIDAvatarMap.size(); + S32 dead_avatar_list = 0; + S32 dead_avatar_check = 0; + + S32 orphan_parents = gObjectList.getOrphanParentCount(); + S32 orphan_parents_check = gObjectList.mOrphanParents.size(); + S32 orphan_children = gObjectList.mOrphanChildren.size(); + S32 orphan_total = gObjectList.getOrphanCount(); + S32 orphan_child_attachments = 0; + + for(U32 i = 0;iisAvatar()) + ++total_avatars; + if(obj->isDead()) + { + ++dead_object_check; + if(obj->isAvatar()) + ++dead_avatar_check; + } + } + } + for(std::set::iterator it = gObjectList.mDeadObjects.begin();it!=gObjectList.mDeadObjects.end();++it) + { + LLViewerObject *obj = gObjectList.findObject(*it); + if(obj && obj->isAvatar()) + ++dead_avatar_list; + } + for(std::vector::iterator it = gObjectList.mOrphanChildren.begin();it!=gObjectList.mOrphanChildren.end();++it) + { + LLViewerObject *obj = gObjectList.findObject(it->mChildInfo); + if(obj && obj->isAttachment()) + ++orphan_child_attachments; + } + addText(xpos,ypos, llformat("%d|%d (%d|%d|%d) Objects", total_objects, ID_objects, dead_objects, dead_object_list,dead_object_check)); + ypos += y_inc; + addText(xpos,ypos, llformat("%d|%d (%d|%d) Avatars", total_avatars, ID_avatars, dead_avatar_list,dead_avatar_check)); + ypos += y_inc; + addText(xpos,ypos, llformat("%d (%d|%d %d %d) Orphans", orphan_total, orphan_parents, orphan_parents_check,orphan_children, orphan_child_attachments)); + + ypos += y_inc; + #if MESH_ENABLED if (gMeshRepo.meshRezEnabled()) { @@ -1941,6 +1993,8 @@ void LLViewerWindow::shutdownGL() gSky.cleanup(); stop_glerror(); + LLWearableList::instance().cleanup() ; + gTextureList.shutdown(); stop_glerror(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 43a4277d1..045e513eb 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -6858,7 +6858,7 @@ BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object) } if(!item_id.isNull()) { - mUnsupportedAttachmentPoints[attachmentID] = item_id; + mUnsupportedAttachmentPoints[attachmentID] = std::pair(item_id,viewer_object->getID()); if (viewer_object->isSelected()) { LLSelectMgr::getInstance()->updateSelectionCenter(); @@ -7128,11 +7128,11 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) } if(!item_id.isNull()) { - std::map::iterator iter = mUnsupportedAttachmentPoints.begin(); - std::map::iterator end = mUnsupportedAttachmentPoints.end(); + std::map >::iterator iter = mUnsupportedAttachmentPoints.begin(); + std::map >::iterator end = mUnsupportedAttachmentPoints.end(); for( ; iter != end; ++iter) { - if((*iter).second == item_id) + if((*iter).second.first == item_id) { mUnsupportedAttachmentPoints.erase((*iter).first); if (isSelf()) @@ -7376,10 +7376,10 @@ BOOL LLVOAvatar::isWearingAttachment( const LLUUID& inv_item_id ) // testzone attachpt BOOL LLVOAvatar::isWearingUnsupportedAttachment( const LLUUID& inv_item_id ) { - std::map::iterator end = mUnsupportedAttachmentPoints.end(); - for(std::map::iterator iter = mUnsupportedAttachmentPoints.begin(); iter != end; ++iter) + std::map >::iterator end = mUnsupportedAttachmentPoints.end(); + for(std::map >::iterator iter = mUnsupportedAttachmentPoints.begin(); iter != end; ++iter) { - if((*iter).second == inv_item_id) + if((*iter).second.first == inv_item_id) { return TRUE; } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 342335b04..07a2da690 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -805,7 +805,7 @@ public: const std::string getAttachedPointName(const LLUUID& inv_item_id); // - std::map mUnsupportedAttachmentPoints; + std::map > mUnsupportedAttachmentPoints; // /** Wearables diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index 3e1069f04..1c18245b1 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -730,7 +730,7 @@ void LLWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake } gAgentAvatarp->updateVisualParams(); - gAgentAvatarp->updateMeshTextures(); + gAgentAvatarp->wearableUpdated(type, FALSE); // if( upload_bake ) // { @@ -797,6 +797,15 @@ void LLWearable::copyDataFrom( LLWearable* src ) } } +void LLWearable::setItemID(const LLUUID& item_id) +{ + mItemID = item_id; +} + +const LLUUID& LLWearable::getItemID() const +{ + return mItemID; +} void LLWearable::setType(LLWearableType::EType type) { mType = type; @@ -859,6 +868,20 @@ void LLWearable::readFromAvatar() } +void LLWearable::setLabelUpdated() const +{ + gInventory.addChangedMask(LLInventoryObserver::LABEL, getItemID()); +} + +void LLWearable::refreshName() +{ + LLUUID item_id = getItemID(); + LLInventoryItem* item = gInventory.getItem(item_id); + if( item ) + { + mName = item->getName(); + } +} struct LLWearableSaveData { diff --git a/indra/newview/llwearable.h b/indra/newview/llwearable.h index c206bc368..1459f4f6a 100644 --- a/indra/newview/llwearable.h +++ b/indra/newview/llwearable.h @@ -108,7 +108,17 @@ public: static void setCurrentDefinitionVersion( S32 version ) { LLWearable::sCurrentDefinitionVersion = version; } friend std::ostream& operator<<(std::ostream &s, const LLWearable &w); + void setItemID(const LLUUID& item_id); + // Something happened that requires the wearable's label to be updated (e.g. worn/unworn). + void setLabelUpdated() const; + + // the wearable was worn. make sure the name of the wearable object matches the LLViewerInventoryItem, + // not the wearable asset itself. + void refreshName(); + +private: + typedef std::map te_map_t; static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml. S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created. @@ -122,8 +132,9 @@ public: typedef std::map param_map_t; param_map_t mVisualParamMap; // maps visual param id to weight - typedef std::map te_map_t; + te_map_t mTEMap; // maps TE to Image ID + LLUUID mItemID; // ID of the inventory item in the agent's inventory }; #endif // LL_LLWEARABLE_H diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index 1e6f65136..535beb3ad 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -43,18 +43,13 @@ #include "llviewerstats.h" #include "llnotificationsutil.h" -// Globals -LLWearableList gWearableList; // Globally constructed; be careful that there's no dependency with gAgent. - - +// Callback struct struct LLWearableArrivedData { - LLWearableArrivedData( - LLAssetType::EType asset_type, + LLWearableArrivedData(LLAssetType::EType asset_type, const std::string& wearable_name, void(*asset_arrived_callback)(LLWearable*, void* userdata), - void* userdata ) - : + void* userdata) : mAssetType( asset_type ), mCallback( asset_arrived_callback ), mUserdata( userdata ), @@ -75,6 +70,11 @@ struct LLWearableArrivedData // LLWearableList LLWearableList::~LLWearableList() +{ + llassert_always(mList.empty()) ; +} + +void LLWearableList::cleanup() { for_each(mList.begin(), mList.end(), DeletePairedPointer()); mList.clear(); @@ -90,8 +90,7 @@ void LLWearableList::getAsset( const LLAssetID& assetID, const std::string& wear } else { - gAssetStorage->getAssetData( - assetID, + gAssetStorage->getAssetData(assetID, asset_type, LLWearableList::processGetAssetReply, (void*)new LLWearableArrivedData( asset_type, wearable_name, asset_arrived_callback, userdata ), @@ -110,8 +109,7 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID { LL_WARNS("Wearable") << "Bad Wearable Asset: missing file." << LL_ENDL; } - else - if( status >= 0 ) + else if (status >= 0) { // read the file LLFILE* fp = LLFile::fopen(std::string(filename), "rb"); /*Flawfinder: ignore*/ @@ -180,7 +178,7 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID if (wearable) // success { - gWearableList.mList[ uuid ] = wearable; + LLWearableList::instance().mList[ uuid ] = wearable; LL_DEBUGS("Wearable") << "processGetAssetReply()" << LL_ENDL; LL_DEBUGS("Wearable") << wearable << LL_ENDL; } diff --git a/indra/newview/llwearablelist.h b/indra/newview/llwearablelist.h index c2a13eb66..890bf18f5 100644 --- a/indra/newview/llwearablelist.h +++ b/indra/newview/llwearablelist.h @@ -37,11 +37,19 @@ #include "lluuid.h" #include "llassetstorage.h" -class LLWearableList +// Globally constructed; be careful that there's no dependency with gAgent. +/* + BUG: mList's system of mapping between assetIDs and wearables is flawed + since LLWearable* has an associated itemID, and you can have multiple + inventory items pointing to the same asset (i.e. more than one ItemID + per assetID). EXT-6252 +*/ +class LLWearableList : public LLSingleton { public: LLWearableList() {} ~LLWearableList(); + void cleanup() ; S32 getLength() { return mList.size(); } @@ -62,9 +70,7 @@ public: protected: LLWearable* generateNewWearable(); // used for the create... functions private: - std::map< LLUUID, LLWearable* > mList; + std::map mList; }; -extern LLWearableList gWearableList; - #endif // LL_LLWEARABLELIST_H diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 2612bf1e2..91ae2427f 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -2382,6 +2382,8 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) root->getVObj()->isAttachment()) { LLDrawable* rootparent = root->getParent(); + static const LLCachedControl draw_orphans("ShyotlDrawOrphanAttachments",false); + if (rootparent) // this IS sometimes NULL { LLViewerObject *vobj = rootparent->getVObj(); @@ -2389,12 +2391,16 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) if (vobj) // this test may not be needed, see above { const LLVOAvatar* av = vobj->asAvatar(); - if (av && av->isImpostor()) + if (av && av->isImpostor() ) { - return; + return; } + else if(!draw_orphans && (!av || av->isDead())) + return; } } + else if(!draw_orphans) + return; } sCull->pushBridge((LLSpatialBridge*) drawablep); } diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 2bd383487..aa61e3640 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -17,6 +17,7 @@ #include "llviewerprecompiledheaders.h" #include "llfloateravatarlist.h" #include "llavatarnamecache.h" +#include "llcallbacklist.h" #include "llfloaterbeacons.h" #include "llfloaterchat.h" #include "llfloaterdaycycle.h" diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index dba0db371..2d264b879 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -845,14 +845,14 @@ void RlvForceWear::done() return; } - // If all the assets are available locally then "pWearData" will be freed *before* the last "gWearableList.getAsset()" call returns + // If all the assets are available locally then "pWearData" will be freed *before* the last "LLWearableList::instance().getAsset()" call returns bool fContinue = true; LLWearableHoldingPattern::found_list_t::const_iterator itWearable = pWearData->mFoundList.begin(); while ( (fContinue) && (itWearable != pWearData->mFoundList.end()) ) { const LLFoundData* pFound = *itWearable; ++itWearable; fContinue = (itWearable != pWearData->mFoundList.end()); - gWearableList.getAsset(pFound->mAssetID, pFound->mName, pFound->mAssetType, wear_inventory_category_on_avatar_loop, (void*)pWearData); + LLWearableList::instance().getAsset(pFound->mAssetID, pFound->mName, pFound->mAssetType, wear_inventory_category_on_avatar_loop, (void*)pWearData); } m_addWearables.clear(); diff --git a/indra/newview/rlvinventory.cpp b/indra/newview/rlvinventory.cpp index 94327cbd9..971140224 100644 --- a/indra/newview/rlvinventory.cpp +++ b/indra/newview/rlvinventory.cpp @@ -16,6 +16,7 @@ #include "llviewerprecompiledheaders.h" #include "llagent.h" +#include "llcallbacklist.h" #include "llstartup.h" #include "llviewerobject.h" #include "llvoavatar.h" @@ -142,7 +143,7 @@ void RlvInventory::fetchWornItems() // Fetch all currently worn clothing layers and body parts for (int type = 0; type < LLWearableType::WT_COUNT; type++) { - const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)type); + const LLUUID idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)type); if (idItem.notNull()) idItems.push_back(idItem); } diff --git a/indra/newview/rlvlocks.cpp b/indra/newview/rlvlocks.cpp index 88f7de3c4..c8c800bcf 100644 --- a/indra/newview/rlvlocks.cpp +++ b/indra/newview/rlvlocks.cpp @@ -181,6 +181,11 @@ void RlvAttachmentLocks::addAttachmentLock(const LLUUID& idAttachObj, const LLUU #endif // RLV_RELEASE m_AttachObjRem.insert(std::pair(idAttachObj, idRlvObj)); + if(LLViewerObject *pObj = gObjectList.findObject(idAttachObj)) //OK + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, pObj->getAttachmentItemID()); + gInventory.notifyObservers(); + } updateLockedHUD(); } @@ -197,6 +202,27 @@ void RlvAttachmentLocks::addAttachmentPointLock(S32 idxAttachPt, const LLUUID& i if (eLock & RLV_LOCK_REMOVE) { m_AttachPtRem.insert(std::pair(idxAttachPt, idRlvObj)); + LLVOAvatar* pAvatar = gAgentAvatarp; + if (pAvatar) + { + bool need_update = false; + LLVOAvatar::attachment_map_t::iterator iter = pAvatar->mAttachmentPoints.find(idxAttachPt); + if (iter != pAvatar->mAttachmentPoints.end()) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = iter->second->mAttachedObjects.begin(); + attachment_iter != iter->second->mAttachedObjects.end();++attachment_iter) + { + LLViewerObject* attached_object = (*attachment_iter); + if(attached_object) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, attached_object->getAttachmentItemID()); + need_update = true; + } + } + } + if(need_update) + gInventory.notifyObservers(); + } updateLockedHUD(); } if (eLock & RLV_LOCK_ADD) @@ -314,6 +340,11 @@ void RlvAttachmentLocks::removeAttachmentLock(const LLUUID& idAttachObj, const L if (idRlvObj == itAttachObj->second) { m_AttachObjRem.erase(itAttachObj); + if(LLViewerObject *pObj = gObjectList.findObject(idAttachObj)) //OK + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, pObj->getAttachmentItemID()); + gInventory.notifyObservers(); + } updateLockedHUD(); break; } @@ -331,6 +362,7 @@ void RlvAttachmentLocks::removeAttachmentPointLock(S32 idxAttachPt, const LLUUID if (eLock & RLV_LOCK_REMOVE) { + bool removed_entry = false; RLV_ASSERT( m_AttachPtRem.lower_bound(idxAttachPt) != m_AttachPtRem.upper_bound(idxAttachPt) ); // The lock should always exist for (rlv_attachptlock_map_t::iterator itAttachPt = m_AttachPtRem.lower_bound(idxAttachPt), endAttachPt = m_AttachPtRem.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt) @@ -338,10 +370,38 @@ void RlvAttachmentLocks::removeAttachmentPointLock(S32 idxAttachPt, const LLUUID if (idRlvObj == itAttachPt->second) { m_AttachPtRem.erase(itAttachPt); + removed_entry = true; updateLockedHUD(); break; } } + if(removed_entry) + { + if(m_AttachPtRem.find(idxAttachPt) == m_AttachPtRem.end()) + { + LLVOAvatar* pAvatar = gAgentAvatarp; + if (pAvatar) + { + bool need_update = false; + LLVOAvatar::attachment_map_t::iterator iter = pAvatar->mAttachmentPoints.find(idxAttachPt); + if (iter != pAvatar->mAttachmentPoints.end()) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = iter->second->mAttachedObjects.begin(); + attachment_iter != iter->second->mAttachedObjects.end();++attachment_iter) + { + LLViewerObject* attached_object = (*attachment_iter); + if(attached_object) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, attached_object->getAttachmentItemID()); + need_update = true; + } + } + if(need_update) + gInventory.notifyObservers(); + } + } + } + } } if (eLock & RLV_LOCK_ADD) { @@ -362,7 +422,7 @@ void RlvAttachmentLocks::removeAttachmentPointLock(S32 idxAttachPt, const LLUUID void RlvAttachmentLocks::updateLockedHUD() { LLVOAvatar* pAvatar = gAgentAvatarp; - if (!pAvatar) + if (!pAvatar || pAvatar->isDead()) return; m_fHasLockedHUD = false; @@ -814,7 +874,15 @@ void RlvWearableLocks::addWearableTypeLock(LLWearableType::EType eType, const LL // NOTE: m_WearableTypeXXX can contain duplicate pairs (ie @remoutfit:shirt=n,remoutfit=n from the same object) if (eLock & RLV_LOCK_REMOVE) + { m_WearableTypeRem.insert(std::pair(eType, idRlvObj)); + LLUUID item_id = gAgentWearables.getWearableItemID(eType); + if(item_id.notNull()) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + gInventory.notifyObservers(); + } + } if (eLock & RLV_LOCK_ADD) m_WearableTypeAdd.insert(std::pair(eType, idRlvObj)); } @@ -889,15 +957,29 @@ void RlvWearableLocks::removeWearableTypeLock(LLWearableType::EType eType, const if (eLock & RLV_LOCK_REMOVE) { RLV_ASSERT( m_WearableTypeRem.lower_bound(eType) != m_WearableTypeRem.upper_bound(eType) ); // The lock should always exist + bool removed_entry = false; for (rlv_wearabletypelock_map_t::iterator itWearableType = m_WearableTypeRem.lower_bound(eType), endWearableType = m_WearableTypeRem.upper_bound(eType); itWearableType != endWearableType; ++itWearableType) { if (idRlvObj == itWearableType->second) { m_WearableTypeRem.erase(itWearableType); + removed_entry = true; break; } } + if(removed_entry) + { + if(m_WearableTypeRem.find(eType) == m_WearableTypeRem.end()) + { + LLUUID item_id = gAgentWearables.getWearableItemID(eType); + if(item_id.notNull()) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + gInventory.notifyObservers(); + } + } + } } if (eLock & RLV_LOCK_ADD) { diff --git a/indra/newview/rlvviewer2.cpp b/indra/newview/rlvviewer2.cpp index 28caf788d..a90f93c80 100644 --- a/indra/newview/rlvviewer2.cpp +++ b/indra/newview/rlvviewer2.cpp @@ -26,78 +26,6 @@ #include "llviewerinventory.h" #include "rlvviewer2.h" -// ============================================================================ -// From llappearancemgr.cpp - -// 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(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(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); -} - // ============================================================================ // From llinventoryobserver.cpp diff --git a/indra/newview/rlvviewer2.h b/indra/newview/rlvviewer2.h index 41892f8b7..28075031e 100644 --- a/indra/newview/rlvviewer2.h +++ b/indra/newview/rlvviewer2.h @@ -29,18 +29,6 @@ #include "boost/function.hpp" -// ============================================================================ -// From llappearancemgr.h - -typedef boost::function nullary_func_t; -typedef boost::function bool_func_t; - -// Call a given callable once in idle loop. -void doOnIdleOneTime(nullary_func_t callable); - -// Repeatedly call a callable in idle loop until it returns true. -void doOnIdleRepeating(bool_func_t callable); - // ============================================================================ // From llinventoryobserver.h