summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/llagentwearables.cpp107
-rw-r--r--indra/newview/llagentwearables.h6
-rw-r--r--indra/newview/llappearancemgr.cpp26
3 files changed, 115 insertions, 24 deletions
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 6eb248ef74..50d378335e 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -1684,7 +1684,80 @@ void LLAgentWearables::userRemoveAllClothesStep2(BOOL proceed)
}
}
-void LLAgentWearables::userRemoveAllAttachments()
+// Combines userRemoveAllAttachments() and userAttachMultipleAttachments() logic to
+// get attachments into desired state with minimal number of adds/removes.
+void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array)
+{
+ // Possible cases:
+ // already wearing but not in request set -> take off.
+ // already wearing and in request set -> leave alone.
+ // not wearing and in request set -> put on.
+
+ LLVOAvatar* avatarp = gAgent.getAvatarObject();
+ if (!avatarp)
+ {
+ llwarns << "No avatar found." << llendl;
+ return;
+ }
+
+ std::set<LLUUID> requested_item_ids;
+ std::set<LLUUID> current_item_ids;
+ for (S32 i=0; i<obj_item_array.count(); i++)
+ requested_item_ids.insert(obj_item_array[i].get()->getLinkedUUID());
+
+ // Build up list of objects to be removed and items currently attached.
+ llvo_vec_t objects_to_remove;
+ for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin();
+ iter != avatarp->mAttachmentPoints.end();)
+ {
+ LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+ LLViewerJointAttachment* attachment = curiter->second;
+ LLViewerObject* objectp = attachment->getObject();
+ if (objectp)
+ {
+ LLUUID object_item_id = attachment->getItemID();
+ if (requested_item_ids.find(object_item_id) != requested_item_ids.end())
+ {
+ // Object currently worn, was requested.
+ // Flag as currently worn so we won't have to add it again.
+ current_item_ids.insert(object_item_id);
+ }
+ else
+ {
+ // object currently worn, not requested.
+ objects_to_remove.push_back(objectp);
+ }
+ }
+ }
+
+ LLInventoryModel::item_array_t items_to_add;
+ for (LLInventoryModel::item_array_t::iterator it = obj_item_array.begin();
+ it != obj_item_array.end();
+ ++it)
+ {
+ LLUUID linked_id = (*it).get()->getLinkedUUID();
+ if (current_item_ids.find(linked_id) != current_item_ids.end())
+ {
+ // Requested attachment is already worn.
+ }
+ else
+ {
+ // Requested attachment is not worn yet.
+ items_to_add.push_back(*it);
+ }
+ }
+ // S32 remove_count = objects_to_remove.size();
+ // S32 add_count = items_to_add.size();
+ // llinfos << "remove " << remove_count << " add " << add_count << llendl;
+
+ // Remove everything in objects_to_remove
+ userRemoveMultipleAttachments(objects_to_remove);
+
+ // Add everything in items_to_add
+ userAttachMultipleAttachments(items_to_add);
+}
+
+void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remove)
{
LLVOAvatar* avatarp = gAgent.getAvatarObject();
if (!avatarp)
@@ -1693,11 +1766,36 @@ void LLAgentWearables::userRemoveAllAttachments()
return;
}
+ if (objects_to_remove.empty())
+ return;
+
gMessageSystem->newMessage("ObjectDetach");
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+ for (llvo_vec_t::iterator it = objects_to_remove.begin();
+ it != objects_to_remove.end();
+ ++it)
+ {
+ LLViewerObject *objectp = *it;
+ gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+ gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
+ }
+ gMessageSystem->sendReliable(gAgent.getRegionHost());
+}
+void LLAgentWearables::userRemoveAllAttachments()
+{
+ LLVOAvatar* avatarp = gAgent.getAvatarObject();
+ if (!avatarp)
+ {
+ llwarns << "No avatar found." << llendl;
+ return;
+ }
+
+ llvo_vec_t objects_to_remove;
+
for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin();
iter != avatarp->mAttachmentPoints.end();)
{
@@ -1705,12 +1803,9 @@ void LLAgentWearables::userRemoveAllAttachments()
LLViewerJointAttachment* attachment = curiter->second;
LLViewerObject* objectp = attachment->getObject();
if (objectp)
- {
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
- }
+ objects_to_remove.push_back(objectp);
}
- gMessageSystem->sendReliable(gAgent.getRegionHost());
+ userRemoveMultipleAttachments(objects_to_remove);
}
void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array)
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index f34b23e220..701ce7f05a 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -44,6 +44,7 @@ class LLInventoryItem;
class LLVOAvatarSelf;
class LLWearable;
class LLInitialWearablesFetch;
+class LLViewerObject;
class LLAgentWearables
{
@@ -181,6 +182,11 @@ public:
// MULTI-WEARABLE: assuming one wearable per type. Need upstream changes.
static void userRemoveWearable(void* userdata); // userdata is EWearableType
static void userRemoveAllClothes(void* userdata); // userdata is NULL
+
+ typedef std::vector<LLViewerObject*> llvo_vec_t;
+
+ static void userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array);
+ static void userRemoveMultipleAttachments(llvo_vec_t& llvo_array);
static void userRemoveAllAttachments();
static void userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array);
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index dfed1cb57a..3831846e2e 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -416,11 +416,11 @@ void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventory
if (!append && total_links > 0)
{
- // Remove all current outfit folder links since we're now replacing the contents.
for (S32 i = 0; i < cof_items.count(); ++i)
{
gInventory.purgeObject(cof_items.get(i)->getUUID());
}
+ gInventory.notifyObservers();
}
LLPointer<LLUpdateAppearanceOnDestroy> link_waiter = new LLUpdateAppearanceOnDestroy;
@@ -532,19 +532,19 @@ void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventory
const LLUUID &current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
// Processes that take time should show the busy cursor
//inc_busy_count();
-
+
LLInventoryModel::cat_array_t cof_cats;
LLInventoryModel::item_array_t cof_items;
gInventory.collectDescendents(current_outfit_id, cof_cats, cof_items,
LLInventoryModel::EXCLUDE_TRASH);
-
+
if (items.count() > 0)
{
- // Remove all current outfit folder links since we're now replacing the contents.
for (S32 i = 0; i < cof_items.count(); ++i)
{
gInventory.purgeObject(cof_items.get(i)->getUUID());
}
+ gInventory.notifyObservers();
}
LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
@@ -696,21 +696,11 @@ void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder,
}
}
-
- //If the folder doesn't contain only gestures, take off all attachments.
- if (!(wear_items.count() == 0 && obj_items.count() == 0 && gest_items.count() > 0) )
+ // Update attachments to match those requested.
+ LLVOAvatar* avatar = gAgent.getAvatarObject();
+ if( avatar )
{
- LLAgentWearables::userRemoveAllAttachments();
- }
-
- if( obj_items.count() > 0 )
- {
- // We've found some attachments. Add these.
- LLVOAvatar* avatar = gAgent.getAvatarObject();
- if( avatar )
- {
- LLAgentWearables::userAttachMultipleAttachments(obj_items);
- }
+ LLAgentWearables::userUpdateAttachments(obj_items);
}
}