summaryrefslogtreecommitdiff
path: root/indra/newview/llappearancemgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llappearancemgr.cpp')
-rw-r--r--indra/newview/llappearancemgr.cpp200
1 files changed, 179 insertions, 21 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<LLUUID> items_seen;
+ for (S32 i=0; i<items.count(); 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);
+ }
+ items = new_items;
+}
void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventoryModel::item_array_t& src)
{
LLInventoryModel::item_array_t new_dst;
std::set<LLUUID> mark_inventory;
- std::set<LLUUID> 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();
@@ -324,32 +335,21 @@ void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventory
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<LLInventoryModel::item_array_t> items_by_type(WT_COUNT);
+ for (S32 i=0; i<items.count(); i++)
+ {
+ LLViewerInventoryItem *item = items.get(i);
+ // Ignore non-wearables.
+ if (!item->isWearableType())
+ continue;
+ EWearableType type = item->getWearableType();
+ 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<WT_COUNT; i++)
+ {
+ S32 size = items_by_type[i].size();
+ if (size <= 0)
+ continue;
+ S32 start_index = max(0,size-max_per_type);
+ for (S32 j = start_index; j<size; j++)
+ {
+ items.push_back(items_by_type[i][j]);
+ }
+ }
+}
+
+// Create links to all listed items.
+/* static */ void LLAppearanceManager::linkAll(const LLUUID& category,
+ LLInventoryModel::item_array_t& items,
+ LLPointer<LLInventoryCallback> cb)
+{
+ for (S32 i=0; i<items.count(); i++)
+ {
+ const LLInventoryItem* item = items.get(i).get();
+ link_inventory_item(gAgent.getID(),
+ item->getLinkedUUID(),
+ 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<LLInventoryCallback> 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() <<llendl;
}
#endif
- llinfos << str << " count " << items.count() << llendl;
+ llinfos << msg << " count " << items.count() << llendl;
}
+/* static */
+void LLAppearanceManager::dumpItemArray(const LLInventoryModel::item_array_t& items,
+ const std::string& msg)
+{
+ llinfos << msg << llendl;
+ for (S32 i=0; i<items.count(); i++)
+ {
+ LLViewerInventoryItem *item = items.get(i);
+ llinfos << i <<" " << item->getName() << llendl;
+ }
+ llinfos << llendl;
+}