summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorBrad Payne (Vir Linden) <vir@lindenlab.com>2009-10-29 11:19:45 -0400
committerBrad Payne (Vir Linden) <vir@lindenlab.com>2009-10-29 11:19:45 -0400
commitcc1c8bb9bc2f210d029aa9e056e520ababe2f00e (patch)
tree88224a9b550382912c59db8dfe5905de36b59d0b /indra
parent13184abdc3b7ed1801dc7e0b82b2b618c080047f (diff)
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.
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/llappearancemgr.cpp200
-rw-r--r--indra/newview/llappearancemgr.h15
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<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;
+}
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<LLInventoryCallback> 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<EWearableType>& types_found);
static void purgeCOFBeforeRebuild(const LLUUID& category);
+ static void purgeCategory(const LLUUID& category, bool keep_outfit_links);
};
#define SUPPORT_ENSEMBLES 0