From cc1c8bb9bc2f210d029aa9e056e520ababe2f00e Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 29 Oct 2009 11:19:45 -0400 Subject: EXT-1804: Operations on the current look do not enforce one wearable per type DEV-39346: OUTFITS (Operations) : Restrict one shape per look, and some # of multiwearables per look DEV-38436: OUTFITS : Guarantee every outfit has fully populated links to (one each of) all body parts. Consolidated all paths for replacing or appending to COF, with common enforcement mechanism for counts of body parts, clothing, etc. Several functions are no longer needed after these changes, will clean up in a later pass. --- indra/newview/llappearancemgr.cpp | 200 ++++++++++++++++++++++++++++++++++---- 1 file changed, 179 insertions(+), 21 deletions(-) (limited to 'indra/newview/llappearancemgr.cpp') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 4e022aeb29..8e1f7775d2 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -296,15 +296,28 @@ struct LLWearableHoldingPattern bool append; }; +/* static */ void removeDuplicateItems(LLInventoryModel::item_array_t& items) +{ + LLInventoryModel::item_array_t new_items; + std::set items_seen; + for (S32 i=0; igetLinkedUUID(); + if (items_seen.find(item_id)!=items_seen.end()) + continue; + items_seen.insert(item_id); + new_items.push_back(item); + } + items = new_items; +} void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventoryModel::item_array_t& src) { LLInventoryModel::item_array_t new_dst; std::set mark_inventory; - std::set mark_asset; S32 inventory_dups = 0; - S32 asset_dups = 0; for (LLInventoryModel::item_array_t::const_iterator src_pos = src.begin(); src_pos != src.end(); @@ -312,8 +325,6 @@ void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventory { LLUUID src_item_id = (*src_pos)->getLinkedUUID(); mark_inventory.insert(src_item_id); - LLUUID src_asset_id = (*src_pos)->getAssetUUID(); - mark_asset.insert(src_asset_id); } for (LLInventoryModel::item_array_t::const_iterator dst_pos = dst.begin(); @@ -323,33 +334,22 @@ void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventory LLUUID dst_item_id = (*dst_pos)->getLinkedUUID(); if (mark_inventory.find(dst_item_id) == mark_inventory.end()) - { - } - else - { - inventory_dups++; - } - - LLUUID dst_asset_id = (*dst_pos)->getAssetUUID(); - - if (mark_asset.find(dst_asset_id) == mark_asset.end()) { // Item is not already present in COF. new_dst.put(*dst_pos); - mark_asset.insert(dst_item_id); + mark_inventory.insert(dst_item_id); } else { - asset_dups++; + inventory_dups++; } } llinfos << "removeDups, original " << dst.count() << " final " << new_dst.count() - << " inventory dups " << inventory_dups << " asset_dups " << asset_dups << llendl; + << " inventory dups " << inventory_dups << llendl; dst = new_dst; } - /* static */ LLUUID LLAppearanceManager::getCOF() { @@ -363,6 +363,9 @@ void LLAppearanceManager::changeOutfit(bool proceed, const LLUUID& category, boo if (!proceed) return; +#if 1 + updateCOF(category,append); +#else if (append) { updateCOFFromCategory(category, append); // append is true - add non-duplicates to COF. @@ -380,6 +383,7 @@ void LLAppearanceManager::changeOutfit(bool proceed, const LLUUID& category, boo rebuildCOFFromOutfit(category); } } +#endif } // Append to current COF contents by recursively traversing a folder. @@ -520,6 +524,130 @@ void LLAppearanceManager::shallowCopyCategory(const LLUUID& src_id, const LLUUID } } } +/* static */ void LLAppearanceManager::purgeCategory(const LLUUID& category, bool keep_outfit_links) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(getCOF(), cats, items, + LLInventoryModel::EXCLUDE_TRASH); + for (S32 i = 0; i < items.count(); ++i) + { + LLViewerInventoryItem *item = items.get(i); + if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) + continue; + gInventory.purgeObject(item->getUUID()); + } +} + +// Keep the last N wearables of each type. For viewer 2.0, N is 1 for +// both body parts and clothing items. +/* static */ void LLAppearanceManager::filterWearableItems( + LLInventoryModel::item_array_t& items, S32 max_per_type) +{ + // Divvy items into arrays by wearable type. + std::vector items_by_type(WT_COUNT); + for (S32 i=0; iisWearableType()) + continue; + EWearableType type = item->getWearableType(); + items_by_type[type].push_back(item); + } + + // rebuild items list, retaining the last max_per_type of each array + items.clear(); + for (S32 i=0; i cb) +{ + for (S32 i=0; igetLinkedUUID(), + category, + item->getName(), + LLAssetType::AT_LINK, + cb); + } +} + +/* static */ void LLAppearanceManager::updateCOF(const LLUUID& category, bool append) +{ + const LLUUID cof = getCOF(); + + // Collect and filter descendents to determine new COF contents. + + // - Body parts: always include COF contents as a fallback in case any + // required parts are missing. + LLInventoryModel::item_array_t body_items; + getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false); + getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); + // Reduce body items to max of one per type. + removeDuplicateItems(body_items); + filterWearableItems(body_items, 1); + + // - Wearables: include COF contents only if appending. + LLInventoryModel::item_array_t wear_items; + if (append) + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); + getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false); + // Reduce wearables to max of one per type. + removeDuplicateItems(wear_items); + filterWearableItems(wear_items, 1); + + // - Attachments: include COF contents only if appending. + LLInventoryModel::item_array_t obj_items; + if (append) + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); + getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); + removeDuplicateItems(obj_items); + + // - Gestures: include COF contents only if appending. + LLInventoryModel::item_array_t gest_items; + if (append) + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); + getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false); + removeDuplicateItems(gest_items); + + // Remove current COF contents. + bool keep_outfit_links = append; + purgeCategory(cof, keep_outfit_links); + gInventory.notifyObservers(); + + // Create links to new COF contents. + LLPointer link_waiter = new LLUpdateAppearanceOnDestroy; + + linkAll(cof, body_items, link_waiter); + linkAll(cof, wear_items, link_waiter); + linkAll(cof, obj_items, link_waiter); + linkAll(cof, gest_items, link_waiter); + + // Add link to outfit if category is an outfit. + LLViewerInventoryCategory* catp = gInventory.getCategory(category); + if (!append && catp && catp->getPreferredType() == LLAssetType::AT_OUTFIT) + { + link_inventory_item(gAgent.getID(), category, cof, catp->getName(), + LLAssetType::AT_LINK_FOLDER, link_waiter); + } + +} /* static */ bool LLAppearanceManager::isMandatoryWearableType(EWearableType type) @@ -792,6 +920,22 @@ void LLAppearanceManager::getCOFValidDescendents(const LLUUID& category, follow_folder_links); } +/* static */ +void LLAppearanceManager::getDescendentsOfAssetType(const LLUUID& category, + LLInventoryModel::item_array_t& items, + LLAssetType::EType type, + bool follow_folder_links) +{ + LLInventoryModel::cat_array_t cats; + LLIsType is_of_type(type); + gInventory.collectDescendentsIf(category, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_of_type, + follow_folder_links); +} + /* static */ void LLAppearanceManager::getUserDescendents(const LLUUID& category, LLInventoryModel::item_array_t& wear_items, @@ -998,14 +1142,16 @@ void LLAppearanceManager::removeItemLinks(const LLUUID& item_id, bool do_update) } } +//#define DUMP_CAT_VERBOSE + /* static */ -void LLAppearanceManager::dumpCat(const LLUUID& cat_id, std::string str) +void LLAppearanceManager::dumpCat(const LLUUID& cat_id, const std::string& msg) { LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); -#if 0 +#ifdef DUMP_CAT_VERBOSE llinfos << llendl; llinfos << str << llendl; S32 hitcount = 0; @@ -1017,6 +1163,18 @@ void LLAppearanceManager::dumpCat(const LLUUID& cat_id, std::string str) llinfos << i <<" "<< item->getName() <getName() << llendl; + } + llinfos << llendl; +} -- cgit v1.2.3 From 86b1ee7703bb57c6b1e1c068cda02bfb9ed0721e Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 2 Nov 2009 14:10:56 -0500 Subject: Work in progress on attachment tracking. --- indra/newview/llappearancemgr.cpp | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'indra/newview/llappearancemgr.cpp') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 8e1f7775d2..c297f8db29 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -528,7 +528,7 @@ void LLAppearanceManager::shallowCopyCategory(const LLUUID& src_id, const LLUUID { LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; - gInventory.collectDescendents(getCOF(), cats, items, + gInventory.collectDescendents(category, cats, items, LLInventoryModel::EXCLUDE_TRASH); for (S32 i = 0; i < items.count(); ++i) { @@ -563,7 +563,7 @@ void LLAppearanceManager::shallowCopyCategory(const LLUUID& src_id, const LLUUID S32 size = items_by_type[i].size(); if (size <= 0) continue; - S32 start_index = max(0,size-max_per_type); + S32 start_index = llmax(0,size-max_per_type); for (S32 j = start_index; j LLAppearanceManager::sRegisteredAttachments; + +void dumpAttachmentSet(const std::set& atts, const std::string& msg) +{ + llinfos << msg << llendl; + for (std::set::const_iterator it = atts.begin(); + it != atts.end(); + ++it) + { + LLUUID item_id = *it; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + if (item) + llinfos << "atts " << item->getName() << llendl; + else + llinfos << "atts " << "UNKNOWN[" << item_id.asString() << "]" << llendl; + } + llinfos << llendl; +} + +/* static */ +void LLAppearanceManager::registerAttachment(const LLUUID& item_id) +{ + sRegisteredAttachments.insert(item_id); + dumpAttachmentSet(sRegisteredAttachments,"after register:"); +} + +/* static */ +void LLAppearanceManager::unregisterAttachment(const LLUUID& item_id) +{ + sRegisteredAttachments.erase(item_id); + dumpAttachmentSet(sRegisteredAttachments,"after unregister:"); +} -- cgit v1.2.3 From 9109809fb18968edfcd8e8f01428309fcc2e7578 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 3 Nov 2009 12:22:31 -0500 Subject: For EXT-1591: Current Outfit Folder contains duplicate attachment items after relog. --HG-- branch : avatar-pipeline --- indra/newview/llappearancemgr.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'indra/newview/llappearancemgr.cpp') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index c297f8db29..8d0f11e021 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1181,6 +1181,14 @@ void LLAppearanceManager::dumpItemArray(const LLInventoryModel::item_array_t& it std::set LLAppearanceManager::sRegisteredAttachments; +bool LLAppearanceManager::sAttachmentInvLinkEnabled(false); + +/* static */ +void LLAppearanceManager::setAttachmentInvLinkEnable(bool val) +{ + llinfos << "setAttachmentInvLinkEnable => " << (int) val << llendl; + sAttachmentInvLinkEnabled = val; +} void dumpAttachmentSet(const std::set& atts, const std::string& msg) { @@ -1204,6 +1212,22 @@ void LLAppearanceManager::registerAttachment(const LLUUID& item_id) { sRegisteredAttachments.insert(item_id); dumpAttachmentSet(sRegisteredAttachments,"after register:"); + + if (sAttachmentInvLinkEnabled) + { + LLViewerInventoryItem *item = gInventory.getItem(item_id); + if (item) + { + LLAppearanceManager::dumpCat(LLAppearanceManager::getCOF(),"Adding attachment link:"); + LLAppearanceManager::wearItem(item,false); // Add COF link for item. + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + gInventory.notifyObservers(); + } + } + else + { + llinfos << "no link changes, inv link not enabled" << llendl; + } } /* static */ @@ -1211,4 +1235,17 @@ void LLAppearanceManager::unregisterAttachment(const LLUUID& item_id) { sRegisteredAttachments.erase(item_id); dumpAttachmentSet(sRegisteredAttachments,"after unregister:"); + + if (sAttachmentInvLinkEnabled) + { + LLAppearanceManager::dumpCat(LLAppearanceManager::getCOF(),"Removing attachment link:"); + LLAppearanceManager::removeItemLinks(item_id, false); + // BAP - needs to change for label to track link. + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + gInventory.notifyObservers(); + } + else + { + llinfos << "no link changes, inv link not enabled" << llendl; + } } -- cgit v1.2.3 From ec8e27b8bf3cdc5056ecd1492b515e4ca79ad4f6 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 4 Nov 2009 13:14:57 -0500 Subject: Remove existing wearables of a type when putting on new ones. This will need to be revisited when we go to multi-wearables. --- indra/newview/llappearancemgr.cpp | 40 ++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) (limited to 'indra/newview/llappearancemgr.cpp') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 8d0f11e021..382947e464 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -300,14 +300,25 @@ struct LLWearableHoldingPattern { LLInventoryModel::item_array_t new_items; std::set items_seen; - for (S32 i=0; i tmp_list; + // Traverse from the front and keep the first of each item + // encountered, so we actually keep the *last* of each duplicate + // item. This is needed to give the right priority when adding + // duplicate items to an existing outfit. + for (S32 i=items.count()-1; i>=0; i--) { LLViewerInventoryItem *item = items.get(i); LLUUID item_id = item->getLinkedUUID(); if (items_seen.find(item_id)!=items_seen.end()) continue; items_seen.insert(item_id); - new_items.push_back(item); + tmp_list.push_front(item); + } + for (std::deque::iterator it = tmp_list.begin(); + it != tmp_list.end(); + ++it) + { + new_items.put(*it); } items = new_items; } @@ -1068,9 +1079,21 @@ void LLAppearanceManager::wearOutfitByName(const std::string& name) //dec_busy_count(); } +bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventoryItem *b) +{ + return (a->isWearableType() && b->isWearableType() && + (a->getWearableType() == b->getWearableType())); +} /* static */ void LLAppearanceManager::wearItem( LLInventoryItem* item, bool do_update ) { + LLViewerInventoryItem *vitem = dynamic_cast(item); + if (!vitem) + { + llwarns << "not an llviewerinventoryitem, failed" << llendl; + return; + } + LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; gInventory.collectDescendents(LLAppearanceManager::getCOF(), @@ -1080,12 +1103,19 @@ void LLAppearanceManager::wearItem( LLInventoryItem* item, bool do_update ) bool linked_already = false; for (S32 i=0; igetLinkedUUID() == item->getLinkedUUID()) { linked_already = true; break; } + // Are of same type but are not the same - new item will replace old. + if (areMatchingWearables(vitem,inv_item)) + { + gAgentWearables.removeWearable(inv_item->getWearableType(),true,0); + gInventory.purgeObject(inv_item->getUUID()); + gInventory.notifyObservers(); + } } if (linked_already) { @@ -1096,9 +1126,9 @@ void LLAppearanceManager::wearItem( LLInventoryItem* item, bool do_update ) { LLPointer cb = do_update ? new ModifiedCOFCallback : 0; link_inventory_item( gAgent.getID(), - item->getLinkedUUID(), + vitem->getLinkedUUID(), getCOF(), - item->getName(), + vitem->getName(), LLAssetType::AT_LINK, cb); } -- cgit v1.2.3 From 98a24938b3cd95f7c93283b91dc95582925265f5 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 4 Nov 2009 15:28:07 -0500 Subject: LLAppearanceManager::wearItem() - always check for extra links of same type, even if requested object is already linked. --- indra/newview/llappearancemgr.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'indra/newview/llappearancemgr.cpp') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 382947e464..033df053ad 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1103,14 +1103,16 @@ void LLAppearanceManager::wearItem( LLInventoryItem* item, bool do_update ) bool linked_already = false; for (S32 i=0; igetLinkedUUID() == item->getLinkedUUID()) { linked_already = true; - break; } - // Are of same type but are not the same - new item will replace old. - if (areMatchingWearables(vitem,inv_item)) + // Are these links to different items of the same wearable + // type? If so, new item will replace old. + // MULTI-WEARABLES: revisit if more than one per type is allowed. + else if (areMatchingWearables(vitem,inv_item)) { gAgentWearables.removeWearable(inv_item->getWearableType(),true,0); gInventory.purgeObject(inv_item->getUUID()); -- cgit v1.2.3 From b806edf4ac47d18e1a43fb8dbb5fbcad8d13192f Mon Sep 17 00:00:00 2001 From: Bryan O'Sullivan Date: Wed, 4 Nov 2009 14:59:23 -0800 Subject: Redo Bao's broken merge --- indra/newview/llappearancemgr.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'indra/newview/llappearancemgr.cpp') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 8d0f11e021..80086de3dc 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -130,11 +130,11 @@ void LLOutfitObserver::done() { if(LLInventoryType::IT_GESTURE == item->getInventoryType()) { - pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_GESTURE); + pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); } else { - pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); } break; } @@ -146,7 +146,7 @@ void LLOutfitObserver::done() LLUUID cat_id = gInventory.createNewCategory( pid, - LLAssetType::AT_NONE, + LLFolderType::FT_NONE, name); mCatID = cat_id; LLPointer cb = new LLWearInventoryCategoryCallback(mCatID, mAppend); @@ -353,7 +353,7 @@ void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventory /* static */ LLUUID LLAppearanceManager::getCOF() { - return gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); + return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); } // Update appearance from outfit folder. @@ -373,12 +373,12 @@ void LLAppearanceManager::changeOutfit(bool proceed, const LLUUID& category, boo else { LLViewerInventoryCategory* catp = gInventory.getCategory(category); - if (catp->getPreferredType() == LLAssetType::AT_NONE || - LLAssetType::lookupIsEnsembleCategoryType(catp->getPreferredType())) + if (catp->getPreferredType() == LLFolderType::FT_NONE || + LLFolderType::lookupIsEnsembleType(catp->getPreferredType())) { updateCOFFromCategory(category, append); // append is false - rebuild COF. } - else if (catp->getPreferredType() == LLAssetType::AT_OUTFIT) + else if (catp->getPreferredType() == LLFolderType::FT_OUTFIT) { rebuildCOFFromOutfit(category); } @@ -405,7 +405,7 @@ void LLAppearanceManager::updateCOFFromCategory(const LLUUID& category, bool app return; } - const LLUUID ¤t_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); + const LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); // Processes that take time should show the busy cursor //inc_busy_count(); @@ -503,7 +503,7 @@ void LLAppearanceManager::shallowCopyCategory(const LLUUID& src_id, const LLUUID { LLViewerInventoryCategory *catp = item->getLinkedCategory(); // Skip copying outfit links. - if (catp && catp->getPreferredType() != LLAssetType::AT_OUTFIT) + if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT) { link_inventory_item(gAgent.getID(), item->getLinkedUUID(), @@ -641,7 +641,7 @@ void LLAppearanceManager::shallowCopyCategory(const LLUUID& src_id, const LLUUID // Add link to outfit if category is an outfit. LLViewerInventoryCategory* catp = gInventory.getCategory(category); - if (!append && catp && catp->getPreferredType() == LLAssetType::AT_OUTFIT) + if (!append && catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) { link_inventory_item(gAgent.getID(), category, cof, catp->getName(), LLAssetType::AT_LINK_FOLDER, link_waiter); @@ -732,7 +732,7 @@ void LLAppearanceManager::rebuildCOFFromOutfit(const LLUUID& category) LLNotifications::instance().add("CouldNotPutOnOutfit"); return; } - + // Processes that take time should show the busy cursor //inc_busy_count(); @@ -750,7 +750,7 @@ void LLAppearanceManager::rebuildCOFFromOutfit(const LLUUID& category) // Create a link to the outfit that we wore. LLViewerInventoryCategory* catp = gInventory.getCategory(category); - if (catp && catp->getPreferredType() == LLAssetType::AT_OUTFIT) + if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) { link_inventory_item(gAgent.getID(), category, current_outfit_id, catp->getName(), LLAssetType::AT_LINK_FOLDER, link_waiter); -- cgit v1.2.3