From 66d385232d83995cf275d1193ff64fa244965c20 Mon Sep 17 00:00:00 2001
From: Kitty Barnett <none@none>
Date: Tue, 31 Aug 2010 00:38:29 +0200
Subject: [PATCH] - internal : added support for "force wear add" vs "force
 wear replace"     -> partial commit of support 'framework' *only* (completely
 untested so force wearing is probably very broken/non-functional right now)  
   -> an (unintended) side-effect of the current implementation is that
 "nostrip" *wearables* won't get replaced on a force-replace wear, revisit
 later

--HG--
branch : RLVa
---
 indra/newview/llappearancemgr.cpp |  10 +-
 indra/newview/llappearancemgr.h   |   2 +-
 indra/newview/rlvdefines.h        |   1 -
 indra/newview/rlvhandler.cpp      |  89 +++++++++--------
 indra/newview/rlvhandler.h        |   3 +-
 indra/newview/rlvhelper.cpp       | 159 +++++++++++++++++++++---------
 indra/newview/rlvhelper.h         |  40 ++++++--
 7 files changed, 193 insertions(+), 111 deletions(-)

diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index def02105d6..81b893ef9a 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1490,15 +1490,14 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 	getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING, false);
 	getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT, false);
 	getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE, false);
-	updateCOF(body_items_new, wear_items_new, obj_items_new, gest_items_new, append, LLAgentWearables::MAX_CLOTHING_PER_TYPE, category);
+	updateCOF(body_items_new, wear_items_new, obj_items_new, gest_items_new, append, category);
 }
 
 void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, 
 								LLInventoryModel::item_array_t& wear_items_new, 
 								LLInventoryModel::item_array_t& obj_items_new,
 								LLInventoryModel::item_array_t& gest_items_new,
-								bool append /*=false*/, U32 cntMaxPerType /*=LLAgentWearables::MAX_CLOTHING_PER_TYPE*/,
-								const LLUUID& idOutfit /*=LLUUID::null*/)
+								bool append /*=false*/, const LLUUID& idOutfit /*=LLUUID::null*/)
 // [/RLVa:KB]
 {
 //	LLViewerInventoryCategory *pcat = gInventory.getCategory(category);
@@ -1569,10 +1568,7 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new,
 // [/RLVa:KB]
 	// Reduce wearables to max of one per type.
 	removeDuplicateItems(wear_items);
-//	filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
-// [RLVa:KB] - Checked: 2010-08-09 (RLVa-1.2.0i) | Added: RLVa-1.2.0i
-	filterWearableItems(wear_items, cntMaxPerType);
-// [/RLVa:KB]
+	filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
 
 	//
 	// - Attachments: include COF contents only if appending.
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 5e9d27a57b..bf95ec88a8 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -54,7 +54,7 @@ public:
 // [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
 	void updateCOF(LLInventoryModel::item_array_t& body_items_new, LLInventoryModel::item_array_t& wear_items_new,
 				   LLInventoryModel::item_array_t& obj_items_new, LLInventoryModel::item_array_t& gest_items_new,
-				   bool append = false, U32 cntMaxPerType = LLAgentWearables::MAX_CLOTHING_PER_TYPE, const LLUUID& idOutfit = LLUUID::null);
+				   bool append = false, const LLUUID& idOutfit = LLUUID::null);
 // [/RLVa:KB]
 	void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append);
 	void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append);
diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h
index 5251252aa0..72a56a6f62 100644
--- a/indra/newview/rlvdefines.h
+++ b/indra/newview/rlvdefines.h
@@ -59,7 +59,6 @@
 
 // Workarounds
 #define RLV_WORKAROUND_REZMULTIPLEATTACH	// See http://jira.secondlife.com/browse/SVC-5383 ; disables "Shared Wear"
-#define RLV_WORKAROUND_SHAREDINVREPLACE		// Keeps shared inventory working the way it did before multi-wearables/multi-attachments
 
 // ============================================================================
 // Defines
diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp
index e220c5a610..eeece1a827 100644
--- a/indra/newview/rlvhandler.cpp
+++ b/indra/newview/rlvhandler.cpp
@@ -1277,10 +1277,14 @@ ERlvCmdRet RlvHandler::processForceCommand(const RlvCommand& rlvCmd) const
 	ERlvCmdRet eRet = RLV_RET_SUCCESS;
 	switch (rlvCmd.getBehaviourType())
 	{
-		case RLV_BHVR_DETACH:		// @detach[:<option>]=force				- Checked: 2009-12-21 (RLVa-1.1.0k) | Modified: RLVa-1.1.0j
-			eRet = onForceRemAttach(rlvCmd);
-			if (RLV_RET_SUCCESS != eRet)
-				eRet = onForceWear(rlvCmd.getOption(), false, false);
+		case RLV_BHVR_DETACH:		// @detach[:<option>]=force				- Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+			{
+				RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption());
+				if (rlvCmdOption.isSharedFolder())
+					eRet = onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourType());
+				else
+					eRet = onForceRemAttach(rlvCmd);
+			}
 			break;
 		case RLV_BHVR_REMATTACH:	// @remattach[:<option>]=force
 			eRet = onForceRemAttach(rlvCmd);
@@ -1325,27 +1329,13 @@ ERlvCmdRet RlvHandler::processForceCommand(const RlvCommand& rlvCmd) const
 			break;
 		case RLV_BHVR_ADDOUTFIT:	// @addoutfit:<option>=force <- synonym of @attach:<option>=force
 		case RLV_BHVR_ATTACH:		// @attach:<option>=force				- Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
-			{
-				RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption());
-				VERIFY_OPTION(rlvCmdOption.isSharedFolder());
-
-				eRet = onForceWear(rlvCmdOption.getSharedFolder(), true, false);	// Force attach single folder
-			}
-			break;
 		case RLV_BHVR_ATTACHALL:	// @attachall:<option>=force			- Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
-			{
-				RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption());
-				VERIFY_OPTION(rlvCmdOption.isSharedFolder());
-
-				eRet = onForceWear(rlvCmdOption.getSharedFolder(), true, true);		// Force attach nested folders
-			}
-			break;
 		case RLV_BHVR_DETACHALL:	// @detachall:<option>=force			- Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
 			{
 				RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption());
 				VERIFY_OPTION(rlvCmdOption.isSharedFolder());
 
-				eRet = onForceWear(rlvCmdOption.getSharedFolder(), false, true);	// Force detach nested folders
+				eRet = onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourType());
 			}
 			break;
 		case RLV_BHVR_ATTACHTHIS:	// @attachthis[:<option>]=force			- Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
@@ -1359,13 +1349,8 @@ ERlvCmdRet RlvHandler::processForceCommand(const RlvCommand& rlvCmd) const
 				LLInventoryModel::cat_array_t folders;
 				if (RlvInventory::instance().getPath(rlvGetPathOption.getItemIDs(), folders))
 				{
-					ERlvBehaviour eBehaviour = rlvCmd.getBehaviourType();
 					for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++)
-					{
-						onForceWear(folders.get(idxFolder), 
-							(RLV_BHVR_ATTACHTHIS == eBehaviour) || (RLV_BHVR_ATTACHALLTHIS == eBehaviour), 
-							(RLV_BHVR_ATTACHALLTHIS == eBehaviour) || (RLV_BHVR_DETACHALLTHIS == eBehaviour));
-					}
+						onForceWear(folders.get(idxFolder), rlvCmd.getBehaviourType());
 				}
 			}
 			break;
@@ -1480,29 +1465,47 @@ ERlvCmdRet RlvHandler::onForceSit(const RlvCommand& rlvCmd) const
 	return RLV_RET_SUCCESS;
 }
 
-// Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i
-ERlvCmdRet RlvHandler::onForceWear(const std::string& strPath, bool fAttach, bool fMatchAll) const
-{
-	const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot();
-	const LLViewerInventoryCategory* pFolder = (pRlvRoot) ? RlvInventory::instance().getSharedFolder(strPath) : NULL;
-	if ( (!pFolder)	|| (pFolder->getUUID() == pRlvRoot->getUUID()) )
-		return (pRlvRoot != NULL) ? RLV_RET_FAILED_OPTION : RLV_RET_FAILED_NOSHAREDROOT;
-
-	RlvForceWear::instance().forceFolder(pFolder, 
-		(fAttach) ? RlvForceWear::ACTION_ATTACH : RlvForceWear::ACTION_DETACH, 
-		(fMatchAll) ? (RlvForceWear::eWearFlags)(RlvForceWear::FLAG_DEFAULT | RlvForceWear::FLAG_MATCHALL) : (RlvForceWear::FLAG_DEFAULT));
-	return RLV_RET_SUCCESS;
-}
-
 // Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
-ERlvCmdRet RlvHandler::onForceWear(const LLViewerInventoryCategory* pFolder, bool fAttach, bool fMatchAll) const
+ERlvCmdRet RlvHandler::onForceWear(const LLViewerInventoryCategory* pFolder, ERlvBehaviour eBhvr) const
 {
 	if ( (pFolder) && (!RlvInventory::instance().isSharedFolder(pFolder->getUUID())) )
 		return RLV_RET_FAILED_OPTION;
 
-	RlvForceWear::instance().forceFolder(pFolder, 
-		(fAttach) ? RlvForceWear::ACTION_ATTACH : RlvForceWear::ACTION_DETACH, 
-		(fMatchAll) ? (RlvForceWear::eWearFlags)(RlvForceWear::FLAG_DEFAULT | RlvForceWear::FLAG_MATCHALL) : (RlvForceWear::FLAG_DEFAULT));
+	RlvForceWear::EWearAction eAction;
+	switch (eBhvr)
+	{
+		case RLV_BHVR_ATTACH:
+		case RLV_BHVR_ATTACHALL:
+		case RLV_BHVR_ATTACHTHIS:
+		case RLV_BHVR_ATTACHALLTHIS:
+		case RLV_BHVR_ADDOUTFIT:
+			eAction = RlvForceWear::ACTION_WEAR_REPLACE;
+			break;
+		case RLV_BHVR_DETACH:
+		case RLV_BHVR_DETACHALL:
+		case RLV_BHVR_DETACHTHIS:
+		case RLV_BHVR_DETACHALLTHIS:
+			eAction = RlvForceWear::ACTION_REMOVE;
+			break;
+		default:
+			RLV_ASSERT(false);
+			return RLV_RET_FAILED_UNKNOWN;
+	}
+
+	RlvForceWear::EWearFlags eFlags = RlvForceWear::FLAG_DEFAULT;
+	switch (eBhvr)
+	{
+		case RLV_BHVR_ATTACHALL:
+		case RLV_BHVR_ATTACHALLTHIS:
+		case RLV_BHVR_DETACHALL:
+		case RLV_BHVR_DETACHALLTHIS:
+			eFlags = (RlvForceWear::EWearFlags)(eFlags | RlvForceWear::FLAG_MATCHALL);
+			break;
+		default:
+			break;
+	}
+
+	RlvForceWear::instance().forceFolder(pFolder, eAction, eFlags);
 	return RLV_RET_SUCCESS;
 }
 
diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h
index 4447219cb3..306c8ba39e 100644
--- a/indra/newview/rlvhandler.h
+++ b/indra/newview/rlvhandler.h
@@ -162,8 +162,7 @@ protected:
 	ERlvCmdRet onForceRemAttach(const RlvCommand& rlvCmd) const;
 	ERlvCmdRet onForceRemOutfit(const RlvCommand& rlvCmd) const;
 	ERlvCmdRet onForceSit(const RlvCommand& rlvCmd) const;
-	ERlvCmdRet onForceWear(const std::string& strPath, bool fAttach, bool fMatchAll) const;
-	ERlvCmdRet onForceWear(const LLViewerInventoryCategory* pFolder, bool fAttach, bool fMatchAll) const;
+	ERlvCmdRet onForceWear(const LLViewerInventoryCategory* pFolder, ERlvBehaviour eBhvr) const;
 	// Command handlers (RLV_TYPE_REPLY)
 	ERlvCmdRet processReplyCommand(const RlvCommand& rlvCmd) const;
 	ERlvCmdRet onFindFolder(const RlvCommand& rlvCmd, std::string& strReply) const;
diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp
index 6d1a003e19..35465f4cb4 100644
--- a/indra/newview/rlvhelper.cpp
+++ b/indra/newview/rlvhelper.cpp
@@ -317,7 +317,7 @@ bool RlvForceWear::isWearingItem(const LLInventoryItem* pItem)
 }
 
 // Checked: 2010-03-21 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
-void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, eWearAction eAction, eWearFlags eFlags)
+void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, EWearAction eAction, EWearFlags eFlags)
 {
 	// [See LLWearableBridge::wearOnAvatar(): don't wear anything until initial wearables are loaded, can destroy clothing items]
 	if (!gAgentWearables.areWearablesLoaded())
@@ -330,7 +330,7 @@ void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, eWearAc
 
 	// Grab a list of all the items we'll be wearing/attaching
 	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
-	RlvWearableItemCollector f(pFolder->getUUID(), (ACTION_ATTACH == eAction), (FLAG_MATCHALL & eFlags));
+	RlvWearableItemCollector f(pFolder->getUUID(), isWearAction(eAction), (eFlags & FLAG_MATCHALL));
 	gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f);
 
 	for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++)
@@ -347,13 +347,13 @@ void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, eWearAc
 		switch (pItem->getType())
 		{
 			case LLAssetType::AT_BODYPART:
-				RLV_ASSERT(ACTION_ATTACH == eAction);	// RlvWearableItemCollector shouldn't be supplying us with body parts on detach
+				RLV_ASSERT(isWearAction(eAction));	// RlvWearableItemCollector shouldn't be supplying us with body parts on detach
 			case LLAssetType::AT_CLOTHING:
-				if (ACTION_ATTACH == eAction)
+				if (isWearAction(eAction))
 				{
 					// The check for whether we're replacing a currently worn composite item happens in onWearableArrived()
 					if (!isAddWearable(pItem))
-						addWearable(pRlvItem);
+						addWearable(pRlvItem, eAction);
 				}
 				else
 				{
@@ -364,7 +364,7 @@ void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, eWearAc
 				break;
 
 			case LLAssetType::AT_OBJECT:
-				if (ACTION_ATTACH == eAction)
+				if (isWearAction(eAction))
 				{
 					if ( (gRlvAttachmentLocks.canAttach(pRlvItem)) || (RlvSettings::getEnableSharedWear()) )
 					{
@@ -388,7 +388,7 @@ void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, eWearAc
 							else
 							#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
 							{
-								addAttachment(pRlvItem);
+								addAttachment(pRlvItem, eAction);
 							}
 						}
 					}
@@ -403,7 +403,7 @@ void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, eWearAc
 
 			#ifdef RLV_EXTENSION_FORCEWEAR_GESTURES
 			case LLAssetType::AT_GESTURE:
-				if (ACTION_ATTACH == eAction)
+				if (isWearAction(eAction))
 				{
 					if (std::find_if(m_addGestures.begin(), m_addGestures.end(), RlvPredIsEqualOrLinkedItem(pRlvItem)) == m_addGestures.end())
 						m_addGestures.push_back(pRlvItem);
@@ -600,28 +600,69 @@ bool RlvForceWear::isStrippable(const LLInventoryItem* pItem)
 }
 #endif // RLV_EXTENSION_FLAG_NOSTRIP
 
-// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
-void RlvForceWear::addAttachment(const LLViewerInventoryItem* pItem)
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvForceWear::addAttachment(const LLViewerInventoryItem* pItem, EWearAction eAction)
 {
 	// Remove it from 'm_remAttachments' if it's queued for detaching
 	const LLViewerObject* pAttachObj = (isAgentAvatarValid()) ? gAgentAvatarp->getWornAttachment(pItem->getLinkedUUID()) : NULL;
 	if ( (pAttachObj) && (isRemAttachment(pAttachObj)) )
 		m_remAttachments.erase(std::remove(m_remAttachments.begin(), m_remAttachments.end(), pAttachObj), m_remAttachments.end());
 
-	// Add it to 'm_addAttachments' if it's not already there
-	if (!isAddAttachment(pItem))
-		m_addAttachments.push_back((LLViewerInventoryItem*)pItem);
+	S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pItem, true);
+	if (ACTION_WEAR_ADD == eAction)
+	{
+		// Insert it at the back if it's not already there
+		idxAttachPt |= ATTACHMENT_ADD;
+		if (!isAddAttachment(pItem))
+		{
+			addattachments_map_t::iterator itAddAttachments = m_addAttachments.find(idxAttachPt);
+			if (itAddAttachments == m_addAttachments.end())
+			{
+				m_addAttachments.insert(addattachment_pair_t(idxAttachPt, LLInventoryModel::item_array_t()));
+				itAddAttachments = m_addAttachments.find(idxAttachPt);
+			}
+			itAddAttachments->second.push_back((LLViewerInventoryItem*)pItem);
+		}
+	}
+	else if (ACTION_WEAR_REPLACE == eAction)
+	{
+		// Replace all pending attachments on this attachment point with the specified item (don't clear if it's the default attach point)
+		addattachments_map_t::iterator itAddAttachments = m_addAttachments.find(idxAttachPt | ATTACHMENT_ADD);
+		if ( (0 != idxAttachPt) && (itAddAttachments != m_addAttachments.end()) )
+			itAddAttachments->second.clear();
+
+		itAddAttachments = m_addAttachments.find(idxAttachPt);
+		if (itAddAttachments == m_addAttachments.end())
+		{
+			m_addAttachments.insert(addattachment_pair_t(idxAttachPt, LLInventoryModel::item_array_t()));
+			itAddAttachments = m_addAttachments.find(idxAttachPt);
+		}
+
+		if (0 != idxAttachPt)
+			itAddAttachments->second.clear();
+		itAddAttachments->second.push_back((LLViewerInventoryItem*)pItem);
+	}
 }
 
-// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
 void RlvForceWear::remAttachment(const LLViewerObject* pAttachObj)
 {
 	// Remove it from 'm_addAttachments' if it's queued for attaching
 	const LLViewerInventoryItem* pItem = (pAttachObj->isAttachment()) ? gInventory.getItem(pAttachObj->getAttachmentItemID()) : NULL;
-	if ( (pItem) && (isAddAttachment(pItem)) )
+	if (pItem)
 	{
-		m_addAttachments.erase(
-			std::remove_if(m_addAttachments.begin(), m_addAttachments.end(), RlvPredIsEqualOrLinkedItem(pItem)), m_addAttachments.end());
+		addattachments_map_t::iterator itAddAttachments = m_addAttachments.begin();
+		while (itAddAttachments != m_addAttachments.end())
+		{
+			LLInventoryModel::item_array_t& wearItems = itAddAttachments->second;
+			if (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end())
+				wearItems.erase(std::remove_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), wearItems.end());
+
+			if (wearItems.empty())
+				m_addAttachments.erase(itAddAttachments++);
+			else
+				++itAddAttachments;
+		}
 	}
 
 	// Add it to 'm_remAttachments' if it's not already there
@@ -629,28 +670,49 @@ void RlvForceWear::remAttachment(const LLViewerObject* pAttachObj)
 		m_remAttachments.push_back(pAttachObj);
 }
 
-// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
-void RlvForceWear::addWearable(const LLViewerInventoryItem* pItem)
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvForceWear::addWearable(const LLViewerInventoryItem* pItem, EWearAction eAction)
 {
-	// Remove it from 'm_remWearables' if it's queued for removal
+	// When replacing remove all currently worn wearables of this type
+	if (ACTION_WEAR_REPLACE == eAction)
+		forceRemove(pItem->getWearableType());
+	// Remove it from 'm_remWearables' if it's pending removal
 	const LLWearable* pWearable = gAgentWearables.getWearableFromItemID(pItem->getLinkedUUID());;
 	if ( (pWearable) && (isRemWearable(pWearable)) )
 		m_remWearables.erase(std::remove(m_remWearables.begin(), m_remWearables.end(), pWearable), m_remWearables.end());
 
-	// Add it to 'm_addWearables' if it's not already there
-	if (!isAddWearable(pItem))
-		m_addWearables.push_back((LLViewerInventoryItem*)pItem);
+	addwearables_map_t::iterator itAddWearables = m_addWearables.find(pItem->getWearableType());
+	if (itAddWearables == m_addWearables.end())
+	{
+		m_addWearables.insert(addwearable_pair_t(pItem->getWearableType(), LLInventoryModel::item_array_t()));
+		itAddWearables = m_addWearables.find(pItem->getWearableType());
+	}
+
+	if (ACTION_WEAR_ADD == eAction)				// Add it at the back if it's not already there
+	{
+		if (!isAddWearable(pItem))
+			itAddWearables->second.push_back((LLViewerInventoryItem*)pItem);
+	}
+	else if (ACTION_WEAR_REPLACE == eAction)	// Replace all pending wearables of this type with the specified item
+	{
+		itAddWearables->second.clear();
+		itAddWearables->second.push_back((LLViewerInventoryItem*)pItem);
+	}
 }
 
-// Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
 void RlvForceWear::remWearable(const LLWearable* pWearable)
 {
 	// Remove it from 'm_addWearables' if it's queued for wearing
 	const LLViewerInventoryItem* pItem = gInventory.getItem(pWearable->getItemID());
 	if ( (pItem) && (isAddWearable(pItem)) )
 	{
-		m_addWearables.erase(
-			std::remove_if(m_addWearables.begin(), m_addWearables.end(), RlvPredIsEqualOrLinkedItem(pItem)), m_addWearables.end());
+		addwearables_map_t::iterator itAddWearables = m_addWearables.find(pItem->getWearableType());
+
+		LLInventoryModel::item_array_t& wearItems = itAddWearables->second;
+		wearItems.erase(std::remove_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), wearItems.end());
+		if (wearItems.empty())
+			m_addWearables.erase(itAddWearables);
 	}
 
 	// Add it to 'm_remWearables' if it's not already there
@@ -730,45 +792,46 @@ void RlvForceWear::done()
 
 	// Wearables need to be split into AT_BODYPART and AT_CLOTHING for COF
 	LLInventoryModel::item_array_t addBodyParts, addClothing;
-	for (S32 idxItem = 0, cntItem = m_addWearables.count(); idxItem < cntItem; idxItem++)
+	for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.begin(); itAddWearables != m_addWearables.end(); ++itAddWearables)
 	{
-		LLViewerInventoryItem* pItem = m_addWearables.get(idxItem);
-		if (LLAssetType::AT_BODYPART == pItem->getType())
-			addBodyParts.push_back(pItem);
-		else
-			addClothing.push_back(pItem);
+		const LLInventoryModel::item_array_t& wearItems = itAddWearables->second;
+		for (S32 idxItem = 0, cntItem = wearItems.count(); idxItem < cntItem; idxItem++)
+		{
+			LLViewerInventoryItem* pItem = wearItems.get(idxItem);
+			if (LLAssetType::AT_BODYPART == pItem->getType())
+				addBodyParts.push_back(pItem);
+			else
+				addClothing.push_back(pItem);
+		}
 	}
 
-#ifdef RLV_WORKAROUND_REZMULTIPLEATTACH
-	// Until SVC-5383 gets fixed we need to handle adding attachments ourselves instead of relying on COF
+	// Until LL provides a way for updateCOF to selectively attach add/replace we have to deal with attachments ourselves
 	if (m_addAttachments.size())
 	{
-		for (S32 idxItem = 0, cntItem = m_addAttachments.count(); idxItem < cntItem; idxItem++)
+		for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.begin(); 
+				itAddAttachments != m_addAttachments.end(); ++itAddAttachments)
 		{
-			const LLViewerInventoryItem* pItem = m_addAttachments.get(idxItem);
-
-			S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pItem, true);
-			if (0 != idxAttachPt)
+			const LLInventoryModel::item_array_t& wearItems = itAddAttachments->second;
+			for (S32 idxItem = 0, cntItem = wearItems.count(); idxItem < cntItem; idxItem++)
 			{
+				const LLUUID& idItem = wearItems.get(idxItem)->getLinkedUUID();
+				if (gAgentAvatarp->attachmentWasRequested(idItem))
+					continue;
+				gAgentAvatarp->addAttachmentRequest(idItem);
+
 				LLSD payload;
-				payload["item_id"] = pItem->getLinkedUUID();
-				payload["attachment_point"] = idxAttachPt;
+				payload["item_id"] = idItem;
+				payload["attachment_point"] = itAddAttachments->first;
 				LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/);
 			}
 		}
-
 		m_addAttachments.clear();
 	}
-#endif // RLV_WORKAROUND_REZMULTIPLEATTACH
 
 	// If there are additions we need to call LLAppearanceManager::updateCOF(), otherwise LLAppearanceManager::updateAppearanceFromCOF()
 	if ( (!m_addWearables.empty()) || (!m_addAttachments.empty()) || (!m_addGestures.empty()) )
 	{
-#ifndef RLV_WORKAROUND_SHAREDINVREPLACE
-		pAppearanceMgr->updateCOF(addBodyParts, addClothing, m_addAttachments, m_addGestures, true);
-#else
-		pAppearanceMgr->updateCOF(addBodyParts, addClothing, m_addAttachments, m_addGestures, true, 1);
-#endif // RLV_WORKAROUND_SHAREDINVREPLACE
+		pAppearanceMgr->updateCOF(addBodyParts, addClothing, LLInventoryModel::item_array_t(), m_addGestures, true);
 
 		m_addWearables.clear();
 		m_addAttachments.clear();
diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h
index 0839dd2401..ade4b58b16 100644
--- a/indra/newview/rlvhelper.h
+++ b/indra/newview/rlvhelper.h
@@ -218,11 +218,12 @@ protected:
 
 public:
 	// Folders
-	enum eWearAction { ACTION_ATTACH, ACTION_DETACH };
-	enum eWearFlags { FLAG_NONE = 0x00, FLAG_MATCHALL = 0x01, FLAG_DEFAULT = FLAG_NONE };
-	void forceFolder(const LLViewerInventoryCategory* pFolder, eWearAction eAction, eWearFlags eFlags);
+	enum EWearAction { ACTION_WEAR_REPLACE, ACTION_WEAR_ADD, ACTION_REMOVE };
+	enum EWearFlags { FLAG_NONE = 0x00, FLAG_MATCHALL = 0x01, FLAG_DEFAULT = FLAG_NONE };
+	void forceFolder(const LLViewerInventoryCategory* pFolder, EWearAction eAction, EWearFlags eFlags);
 
 	// Generic
+	static bool isWearAction(EWearAction eAction) { return (ACTION_WEAR_REPLACE == eAction) || (ACTION_WEAR_ADD == eAction); }
 	static bool isWearableItem(const LLInventoryItem* pItem);
 	static bool isWearingItem(const LLInventoryItem* pItem);
 
@@ -245,15 +246,22 @@ public:
 public:
 	void done();
 protected:
-	void addAttachment(const LLViewerInventoryItem* pItem);
+	void addAttachment(const LLViewerInventoryItem* pItem, EWearAction eAction);
 	void remAttachment(const LLViewerObject* pAttachObj);
-	void addWearable(const LLViewerInventoryItem* pItem);
+	void addWearable(const LLViewerInventoryItem* pItem, EWearAction eAction);
 	void remWearable(const LLWearable* pWearable);
 
 	// Convenience (prevents long lines that run off the screen elsewhere)
 	bool isAddAttachment(const LLViewerInventoryItem* pItem) const
 	{
-		return std::find_if(m_addAttachments.begin(), m_addAttachments.end(), RlvPredIsEqualOrLinkedItem(pItem)) != m_addAttachments.end();
+		bool fFound = false;
+		for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.begin(); 
+				(!fFound) && (itAddAttachments != m_addAttachments.end()); ++itAddAttachments)
+		{
+			const LLInventoryModel::item_array_t& wearItems = itAddAttachments->second;
+			fFound = (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end());
+		}
+		return fFound;
 	}
 	bool isRemAttachment(const LLViewerObject* pAttachObj) const
 	{
@@ -261,7 +269,14 @@ protected:
 	}
 	bool isAddWearable(const LLViewerInventoryItem* pItem) const
 	{
-		return std::find_if(m_addWearables.begin(), m_addWearables.end(), RlvPredIsEqualOrLinkedItem(pItem)) != m_addWearables.end();
+		bool fFound = false;
+		for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.begin(); 
+				(!fFound) && (itAddWearables != m_addWearables.end()); ++itAddWearables)
+		{
+			const LLInventoryModel::item_array_t& wearItems = itAddWearables->second;
+			fFound = (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end());
+		}
+		return fFound;
 	}
 	bool isRemWearable(const LLWearable* pWearable) const
 	{
@@ -269,9 +284,16 @@ protected:
 	}
 
 protected:
-	LLInventoryModel::item_array_t m_addAttachments, m_addWearables, m_addGestures, m_remGestures;
+	typedef std::pair<LLWearableType::EType, LLInventoryModel::item_array_t> addwearable_pair_t;
+	typedef std::map<LLWearableType::EType, LLInventoryModel::item_array_t> addwearables_map_t;
+	addwearables_map_t               m_addWearables;
+	typedef std::pair<S32, LLInventoryModel::item_array_t> addattachment_pair_t;
+	typedef std::map<S32, LLInventoryModel::item_array_t> addattachments_map_t;
+	addattachments_map_t             m_addAttachments;
+	LLInventoryModel::item_array_t   m_addGestures;
 	std::list<const LLViewerObject*> m_remAttachments;
-	std::list<const LLWearable*> m_remWearables;
+	std::list<const LLWearable*>     m_remWearables;
+	LLInventoryModel::item_array_t   m_remGestures;
 
 private:
 	friend class LLSingleton<RlvForceWear>;
-- 
GitLab