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 ++++++++++++++++++++++++++++++++++---- indra/newview/llappearancemgr.h | 15 ++- 2 files changed, 193 insertions(+), 22 deletions(-) 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; +} diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 828af32101..ea3ebdf4ea 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -46,6 +46,7 @@ public: static void updateAppearanceFromCOF(); static bool needToSaveCOF(); static void changeOutfit(bool proceed, const LLUUID& category, bool append); + static void updateCOF(const LLUUID& category, bool append = false); static void updateCOFFromCategory(const LLUUID& category, bool append); static void rebuildCOFFromOutfit(const LLUUID& category); static void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); @@ -65,9 +66,20 @@ public: static void removeItemLinks(const LLUUID& item_id, bool do_update = true); // For debugging - could be moved elsewhere. - static void dumpCat(const LLUUID& cat_id, std::string str); + static void dumpCat(const LLUUID& cat_id, const std::string& msg); + static void dumpItemArray(const LLInventoryModel::item_array_t& items, const std::string& msg); private: + static void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type); + static void linkAll(const LLUUID& category, + LLInventoryModel::item_array_t& items, + LLPointer cb); + + static void getDescendentsOfAssetType(const LLUUID& category, + LLInventoryModel::item_array_t& items, + LLAssetType::EType type, + bool follow_folder_links); + static void getCOFValidDescendents(const LLUUID& category, LLInventoryModel::item_array_t& items); @@ -81,6 +93,7 @@ private: static bool isMandatoryWearableType(EWearableType type); static void checkMandatoryWearableTypes(const LLUUID& category, std::set& types_found); static void purgeCOFBeforeRebuild(const LLUUID& category); + static void purgeCategory(const LLUUID& category, bool keep_outfit_links); }; #define SUPPORT_ENSEMBLES 0 -- cgit v1.2.3