diff options
| -rw-r--r-- | indra/llcommon/indra_constants.h | 4 | ||||
| -rw-r--r-- | indra/llprimitive/llprimitive.h | 4 | ||||
| -rw-r--r-- | indra/newview/llagent.cpp | 17 | ||||
| -rw-r--r-- | indra/newview/llagentwearables.cpp | 81 | ||||
| -rw-r--r-- | indra/newview/llfloaterinventory.cpp | 35 | ||||
| -rw-r--r-- | indra/newview/llinventorybridge.cpp | 26 | ||||
| -rw-r--r-- | indra/newview/llselectmgr.cpp | 3 | ||||
| -rw-r--r-- | indra/newview/llselectmgr.h | 2 | ||||
| -rw-r--r-- | indra/newview/llviewerjointattachment.cpp | 247 | ||||
| -rw-r--r-- | indra/newview/llviewerjointattachment.h | 26 | ||||
| -rw-r--r-- | indra/newview/llviewermenu.cpp | 149 | ||||
| -rw-r--r-- | indra/newview/llviewerobject.cpp | 3 | ||||
| -rw-r--r-- | indra/newview/llviewerobject.h | 6 | ||||
| -rw-r--r-- | indra/newview/llviewerobjectlist.cpp | 26 | ||||
| -rw-r--r-- | indra/newview/llvoavatar.cpp | 236 | ||||
| -rw-r--r-- | indra/newview/llvoavatar.h | 5 | ||||
| -rw-r--r-- | indra/newview/llvoavatarself.cpp | 40 | ||||
| -rw-r--r-- | indra/newview/llvoavatarself.h | 4 | ||||
| -rw-r--r-- | indra/newview/pipeline.cpp | 67 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/notifications.xml | 8 | 
20 files changed, 613 insertions, 376 deletions
| diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 4836d41fb3..6b75a720af 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -253,6 +253,10 @@ const U8 SIM_ACCESS_MAX 	= SIM_ACCESS_ADULT;  // group constants  const S32 MAX_AGENT_GROUPS = 25; +// attachment constants +const S32 MAX_AGENT_ATTACHMENTS = 38; +const U8  ATTACHMENT_ADD = 0x80; +  // god levels  const U8 GOD_MAINTENANCE = 250;  const U8 GOD_FULL = 200; diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 53095cc925..4f828186cb 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -263,9 +263,9 @@ public:  	bool fromLLSD(LLSD& sd);  	void setSculptTexture(const LLUUID& id) { mSculptTexture = id; } -	LLUUID getSculptTexture()               { return mSculptTexture; } +	LLUUID getSculptTexture() const         { return mSculptTexture; }  	void setSculptType(U8 type)             { mSculptType = type; } -	U8 getSculptType()                      { return mSculptType; } +	U8 getSculptType() const                { return mSculptType; }  };  class LLLightImageParams : public LLNetworkData diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index fa60c5afc1..c67beda361 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3378,13 +3378,18 @@ void LLAgent::updateCamera()  		{  			LLVOAvatar::attachment_map_t::iterator curiter = iter++;  			LLViewerJointAttachment* attachment = curiter->second; -			LLViewerObject *attached_object = attachment->getObject(); -			if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull()) +			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +				 attachment_iter != attachment->mAttachedObjects.end(); +				 ++attachment_iter)  			{ -				// clear any existing "early" movements of attachment -				attached_object->mDrawable->clearState(LLDrawable::EARLY_MOVE); -				gPipeline.updateMoveNormalAsync(attached_object->mDrawable); -				attached_object->updateText(); +				LLViewerObject *attached_object = (*attachment_iter); +				if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull()) +				{ +					// clear any existing "early" movements of attachment +					attached_object->mDrawable->clearState(LLDrawable::EARLY_MOVE); +					gPipeline.updateMoveNormalAsync(attached_object->mDrawable); +					attached_object->updateText(); +				}  			}  		} diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index a26b799d3d..223f8779ec 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -1203,25 +1203,30 @@ void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name,  			S32 attachment_pt = attachments_to_include[i];  			LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL);  			if (!attachment) continue; -			LLViewerObject* attached_object = attachment->getObject(); -			if (!attached_object) continue; -			const LLUUID& item_id = attachment->getItemID(); -			if (item_id.isNull()) continue; -			LLInventoryItem* item = gInventory.getItem(item_id); -			if (!item) continue; -			if (!msg_started) +			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +				 attachment_iter != attachment->mAttachedObjects.end(); +				 ++attachment_iter)  			{ -				msg_started = TRUE; -				msg->newMessage("CreateNewOutfitAttachments"); -				msg->nextBlock("AgentData"); -				msg->addUUID("AgentID", gAgent.getID()); -				msg->addUUID("SessionID", gAgent.getSessionID()); -				msg->nextBlock("HeaderData"); -				msg->addUUID("NewFolderID", folder_id); +				LLViewerObject *attached_object = (*attachment_iter); +				if(!attached_object) continue; +				const LLUUID& item_id = (*attachment_iter)->getItemID(); +				if(item_id.isNull()) continue; +				LLInventoryItem* item = gInventory.getItem(item_id); +				if(!item) continue; +				if(!msg_started) +				{ +					msg_started = TRUE; +					msg->newMessage("CreateNewOutfitAttachments"); +					msg->nextBlock("AgentData"); +					msg->addUUID("AgentID", gAgent.getID()); +					msg->addUUID("SessionID", gAgent.getSessionID()); +					msg->nextBlock("HeaderData"); +					msg->addUUID("NewFolderID", folder_id); +				} +				msg->nextBlock("ObjectData"); +				msg->addUUID("OldItemID", item_id); +				msg->addUUID("OldFolderID", item->getParentUUID());  			} -			msg->nextBlock("ObjectData"); -			msg->addUUID("OldItemID", item_id); -			msg->addUUID("OldFolderID", item->getParentUUID());  		}  		if (msg_started) @@ -1766,20 +1771,25 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj  	{  		LLVOAvatar::attachment_map_t::iterator curiter = iter++;  		LLViewerJointAttachment* attachment = curiter->second; -		LLViewerObject* objectp = attachment->getObject(); -		if (objectp) +		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +			 attachment_iter != attachment->mAttachedObjects.end(); +			 ++attachment_iter)  		{ -			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 +			LLViewerObject *objectp = (*attachment_iter); +			if (objectp)  			{ -				// object currently worn, not requested. -				objects_to_remove.push_back(objectp); +				LLUUID object_item_id = objectp->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); +				}  			}  		}  	} @@ -1855,9 +1865,16 @@ void LLAgentWearables::userRemoveAllAttachments()  	{  		LLVOAvatar::attachment_map_t::iterator curiter = iter++;  		LLViewerJointAttachment* attachment = curiter->second; -		LLViewerObject* objectp = attachment->getObject(); -		if (objectp) -			objects_to_remove.push_back(objectp); +		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +			 attachment_iter != attachment->mAttachedObjects.end(); +			 ++attachment_iter) +		{ +			LLViewerObject *attached_object = (*attachment_iter); +			if (attached_object) +			{ +				objects_to_remove.push_back(attached_object); +			} +		}  	}  	userRemoveMultipleAttachments(objects_to_remove);  } diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp index 126dcc6f76..a8ab4303ba 100644 --- a/indra/newview/llfloaterinventory.cpp +++ b/indra/newview/llfloaterinventory.cpp @@ -1837,7 +1837,6 @@ bool LLInventoryPanel::attachObject(const LLSD& userdata)  {  	std::set<LLUUID> selected_items;  	mFolders->getSelectionList(selected_items); -	LLUUID id = *selected_items.begin();  	std::string joint_name = userdata.asString();  	LLVOAvatar *avatarp = static_cast<LLVOAvatar*>(gAgent.getAvatarObject()); @@ -1857,22 +1856,28 @@ bool LLInventoryPanel::attachObject(const LLSD& userdata)  	{  		return true;  	} -	LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id); -	if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())) +	for (std::set<LLUUID>::const_iterator set_iter = selected_items.begin();  +		 set_iter != selected_items.end();  +		 ++set_iter)  	{ -		rez_attachment(item, attachmentp); -	} -	else if(item && item->isComplete()) -	{ -		// must be in library. copy it to our inventory and put it on. -		LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(attachmentp); -		copy_inventory_item(gAgent.getID(), -							item->getPermissions().getOwner(), -							item->getUUID(), -							LLUUID::null, -							std::string(), -							cb); +		const LLUUID &id = *set_iter; +		LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id); +		if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())) +		{ +			rez_attachment(item, attachmentp); +		} +		else if(item && item->isComplete()) +		{ +			// must be in library. copy it to our inventory and put it on. +			LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(attachmentp); +			copy_inventory_item(gAgent.getID(), +								item->getPermissions().getOwner(), +								item->getUUID(), +								LLUUID::null, +								std::string(), +								cb); +		}  	}  	gFocusMgr.setKeyboardFocus(NULL); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 5067f88e58..e807240e4e 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -3737,11 +3737,13 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach  	payload["attachment_point"] = attach_pt; -	if (attachment && attachment->getObject()) +#if !ENABLE_MULTIATTACHMENTS +	if (attachment && attachment->getNumObjects() > 0)  	{  		LLNotifications::instance().add("ReplaceAttachment", LLSD(), payload, confirm_replace_attachment_rez);  	}  	else +#endif  	{  		LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/);  	} @@ -3749,6 +3751,16 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach  bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response)  { +	LLVOAvatar *avatarp = gAgent.getAvatarObject(); +		 +	if (!avatarp->canAttachMoreObjects()) +	{ +		LLSD args; +		args["MAX_ATTACHMENTS"] = llformat("%d", MAX_AGENT_ATTACHMENTS); +		LLNotifications::instance().add("MaxAttachmentsOnOutfit", args); +		return false; +	} +  	S32 option = LLNotification::getSelectedOption(notification, response);  	if (option == 0/*YES*/)  	{ @@ -3764,7 +3776,11 @@ bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& respon  			msg->nextBlockFast(_PREHASH_ObjectData);  			msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID());  			msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner()); -			msg->addU8Fast(_PREHASH_AttachmentPt, notification["payload"]["attachment_point"].asInteger()); +			U8 attachment_pt = notification["payload"]["attachment_point"].asInteger(); +#if ENABLE_MULTIATTACHMENTS +			attachment_pt |= ATTACHMENT_ADD; +#endif +			msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt);  			pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions());  			msg->addStringFast(_PREHASH_Name, itemp->getName());  			msg->addStringFast(_PREHASH_Description, itemp->getDescription()); @@ -3825,6 +3841,12 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)  				// commented out for DEV-32347  				//items.push_back(std::string("Restore to Last Position")); +				if (!avatarp->canAttachMoreObjects()) +				{ +					disabled_items.push_back(std::string("Object Wear")); +					disabled_items.push_back(std::string("Attach To")); +					disabled_items.push_back(std::string("Attach To HUD")); +				}  				LLMenuGL* attach_menu = menu.findChildMenuByName("Attach To", TRUE);  				LLMenuGL* attach_hud_menu = menu.findChildMenuByName("Attach To HUD", TRUE);  				LLVOAvatar *avatarp = gAgent.getAvatarObject(); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 288cf728b9..5630e8a0e9 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -3590,6 +3590,9 @@ void LLSelectMgr::sendAttach(U8 attachment_point)  		return;  	} +#if ENABLE_MULTIATTACHMENTS +	attachment_point |= ATTACHMENT_ADD; +#endif  	BOOL build_mode = LLToolMgr::getInstance()->inEdit();  	// Special case: Attach to default location for this object.  	if (0 == attachment_point || diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 296502ff16..6e757ef976 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -660,7 +660,7 @@ private:  	static void packDeRezHeader(void* user_data);  	static void packObjectID(	LLSelectNode* node, void *);  	static void packObjectIDAsParam(LLSelectNode* node, void *); -	static void packObjectIDAndRotation(	LLSelectNode* node, void *); +	static void packObjectIDAndRotation(LLSelectNode* node, void *);  	static void packObjectLocalID(LLSelectNode* node, void *);  	static void packObjectClickAction(LLSelectNode* node, void* data);  	static void packObjectIncludeInSearch(LLSelectNode* node, void* data); diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 63c63e5546..2b4b78d82d 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -57,14 +57,14 @@ extern LLPipeline gPipeline;  // LLViewerJointAttachment()  //-----------------------------------------------------------------------------  LLViewerJointAttachment::LLViewerJointAttachment() : -mAttachedObject(NULL), -mVisibleInFirst(FALSE), -mGroup(0), -mIsHUDAttachment(FALSE), -mPieSlice(-1) +	mVisibleInFirst(FALSE), +	mGroup(0), +	mIsHUDAttachment(FALSE), +	mPieSlice(-1)  {  	mValid = FALSE;  	mUpdateXform = FALSE; +	mAttachedObjects.clear();  }  //----------------------------------------------------------------------------- @@ -103,36 +103,43 @@ U32 LLViewerJointAttachment::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_  	return 0;  } -void LLViewerJointAttachment::setupDrawable(LLDrawable* drawablep) +void LLViewerJointAttachment::setupDrawable(LLViewerObject *object)  { -	drawablep->mXform.setParent(&mXform); // LLViewerJointAttachment::lazyAttach -	drawablep->makeActive(); -	LLVector3 current_pos = mAttachedObject->getRenderPosition(); -	LLQuaternion current_rot = mAttachedObject->getRenderRotation(); -	LLQuaternion attachment_pt_inv_rot = ~getWorldRotation(); +	if (!object->mDrawable) +		return; +	if (object->mDrawable->isActive()) +	{ +		object->mDrawable->makeStatic(FALSE); +	} + +	object->mDrawable->mXform.setParent(getXform()); // LLViewerJointAttachment::lazyAttach +	object->mDrawable->makeActive(); +	LLVector3 current_pos = object->getRenderPosition(); +	LLQuaternion current_rot = object->getRenderRotation(); +	LLQuaternion attachment_pt_inv_rot = ~(getWorldRotation());  	current_pos -= getWorldPosition();  	current_pos.rotVec(attachment_pt_inv_rot);  	current_rot = current_rot * attachment_pt_inv_rot; -	drawablep->mXform.setPosition(current_pos); -	drawablep->mXform.setRotation(current_rot); -	gPipeline.markMoved(drawablep); -	gPipeline.markTextured(drawablep); // face may need to change draw pool to/from POOL_HUD -	drawablep->setState(LLDrawable::USE_BACKLIGHT); +	object->mDrawable->mXform.setPosition(current_pos); +	object->mDrawable->mXform.setRotation(current_rot); +	gPipeline.markMoved(object->mDrawable); +	gPipeline.markTextured(object->mDrawable); // face may need to change draw pool to/from POOL_HUD +	object->mDrawable->setState(LLDrawable::USE_BACKLIGHT);  	if(mIsHUDAttachment)  	{ -		for (S32 face_num = 0; face_num < drawablep->getNumFaces(); face_num++) +		for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++)  		{ -			drawablep->getFace(face_num)->setState(LLFace::HUD_RENDER); +			object->mDrawable->getFace(face_num)->setState(LLFace::HUD_RENDER);  		}  	} -	LLViewerObject::const_child_list_t& child_list = mAttachedObject->getChildren(); +	LLViewerObject::const_child_list_t& child_list = object->getChildren();  	for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); -		 iter != child_list.end(); iter++) +		 iter != child_list.end(); ++iter)  	{  		LLViewerObject* childp = *iter;  		if (childp && childp->mDrawable.notNull()) @@ -157,27 +164,13 @@ void LLViewerJointAttachment::setupDrawable(LLDrawable* drawablep)  //-----------------------------------------------------------------------------  BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)  { -	if (mAttachedObject) +	if (isObjectAttached(object))  	{ -		llwarns << "Attempted to attach object where an attachment already exists!" << llendl; -		 -		if (mAttachedObject == object) { -			llinfos << "(same object re-attached)" << llendl; -			removeObject(mAttachedObject); -			// Pass through anyway to let setupDrawable() -			// re-connect object to the joint correctly -		} -		else { -			llinfos << "(objects differ, removing existing object)" << llendl; -			// Rather hacky, but no-one can think of something -			// better to do for this case. -			gObjectList.killObject(mAttachedObject); -			// Proceed with new object attachment -		} +		llinfos << "(same object re-attached)" << llendl; +		removeObject(object); +		// Pass through anyway to let setupDrawable() +		// re-connect object to the joint correctly  	} -	mAttachedObject = object; -	 -	LLUUID item_id;  	// Find the inventory item ID of the attached object  	LLNameValue* item_id_nv = object->getNVPair("AttachItemID"); @@ -186,26 +179,15 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)  		const char* s = item_id_nv->getString();  		if( s )  		{ -			item_id.set( s ); +			LLUUID item_id; +			item_id.set(s); +			object->setItemID(item_id);  			lldebugs << "getNVPair( AttachItemID ) = " << item_id << llendl;  		}  	} - -	mItemID = item_id; - -	LLDrawable* drawablep = object->mDrawable; - -	if (drawablep) -	{ -		//if object is active, make it static -		if(drawablep->isActive()) -		{ -			drawablep->makeStatic(FALSE) ; -		} - -		setupDrawable(drawablep); -	} - +	mAttachedObjects.push_back(object); +	setupDrawable(object); +	  	if (mIsHUDAttachment)  	{  		if (object->mText.notNull()) @@ -214,7 +196,7 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)  		}  		LLViewerObject::const_child_list_t& child_list = object->getChildren();  		for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); -			 iter != child_list.end(); iter++) +			 iter != child_list.end(); ++iter)  		{  			LLViewerObject* childp = *iter;  			if (childp && childp->mText.notNull()) @@ -234,15 +216,33 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object)  //-----------------------------------------------------------------------------  void LLViewerJointAttachment::removeObject(LLViewerObject *object)  { +	attachedobjs_vec_t::iterator iter; +	for (iter = mAttachedObjects.begin(); +		 iter != mAttachedObjects.end(); +		 ++iter) +	{ +		LLViewerObject *attached_object = (*iter); +		if (attached_object == object) +		{ +			break; +		} +	} +	if (iter == mAttachedObjects.end()) +	{ +		llwarns << "Could not find object to detach" << llendl; +		return; +	} +  	// force object visibile  	setAttachmentVisibility(TRUE); +	mAttachedObjects.erase(iter);  	if (object->mDrawable.notNull())  	{  		//if object is active, make it static  		if(object->mDrawable->isActive())  		{ -			object->mDrawable->makeStatic(FALSE) ; +			object->mDrawable->makeStatic(FALSE);  		}  		LLVector3 cur_position = object->getRenderPosition(); @@ -265,7 +265,7 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)  	LLViewerObject::const_child_list_t& child_list = object->getChildren();  	for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); -		 iter != child_list.end(); iter++) +		 iter != child_list.end(); ++iter)  	{  		LLViewerObject* childp = *iter;  		if (childp && childp->mDrawable.notNull()) @@ -290,7 +290,7 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)  		}  		LLViewerObject::const_child_list_t& child_list = object->getChildren();  		for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); -			 iter != child_list.end(); iter++) +			 iter != child_list.end(); ++iter)  		{  			LLViewerObject* childp = *iter;  			if (childp->mText.notNull()) @@ -299,10 +299,11 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)  			}  		}  	} - -	mAttachedObject = NULL; -	mUpdateXform = FALSE; -	mItemID.setNull(); +	if (mAttachedObjects.size() == 0) +	{ +		mUpdateXform = FALSE; +	} +	object->setItemID(LLUUID::null);  }  //----------------------------------------------------------------------------- @@ -310,20 +311,26 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)  //-----------------------------------------------------------------------------  void LLViewerJointAttachment::setAttachmentVisibility(BOOL visible)  { -	if (!mAttachedObject || mAttachedObject->mDrawable.isNull() ||  -		!(mAttachedObject->mDrawable->getSpatialBridge())) -		return; - -	if (visible) -	{ -		// Hack to make attachments not visible by disabling their type mask! -		// This will break if you can ever attach non-volumes! - djs 02/14/03 -		mAttachedObject->mDrawable->getSpatialBridge()->mDrawableType =  -			mAttachedObject->isHUDAttachment() ? LLPipeline::RENDER_TYPE_HUD : LLPipeline::RENDER_TYPE_VOLUME; -	} -	else +	for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); +		 iter != mAttachedObjects.end(); +		 ++iter)  	{ -		mAttachedObject->mDrawable->getSpatialBridge()->mDrawableType = 0; +		LLViewerObject *attached_obj = (*iter); +		if (!attached_obj || attached_obj->mDrawable.isNull() ||  +			!(attached_obj->mDrawable->getSpatialBridge())) +			continue; +		 +		if (visible) +		{ +			// Hack to make attachments not visible by disabling their type mask! +			// This will break if you can ever attach non-volumes! - djs 02/14/03 +			attached_obj->mDrawable->getSpatialBridge()->mDrawableType =  +				attached_obj->isHUDAttachment() ? LLPipeline::RENDER_TYPE_HUD : LLPipeline::RENDER_TYPE_VOLUME; +		} +		else +		{ +			attached_obj->mDrawable->getSpatialBridge()->mDrawableType = 0; +		}  	}  } @@ -341,14 +348,19 @@ void LLViewerJointAttachment::setOriginalPosition(LLVector3& position)  //-----------------------------------------------------------------------------  void LLViewerJointAttachment::clampObjectPosition()  { -	if (mAttachedObject) +	for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); +		 iter != mAttachedObjects.end(); +		 ++iter)  	{ -		// *NOTE: object can drift when hitting maximum radius -		LLVector3 attachmentPos = mAttachedObject->getPosition(); -		F32 dist = attachmentPos.normVec(); -		dist = llmin(dist, MAX_ATTACHMENT_DIST); -		attachmentPos *= dist; -		mAttachedObject->setPosition(attachmentPos); +		if (LLViewerObject *attached_object = (*iter)) +		{ +			// *NOTE: object can drift when hitting maximum radius +			LLVector3 attachmentPos = attached_object->getPosition(); +			F32 dist = attachmentPos.normVec(); +			dist = llmin(dist, MAX_ATTACHMENT_DIST); +			attachmentPos *= dist; +			attached_object->setPosition(attachmentPos); +		}  	}  } @@ -357,14 +369,23 @@ void LLViewerJointAttachment::clampObjectPosition()  //-----------------------------------------------------------------------------  void LLViewerJointAttachment::calcLOD()  { -	F32 maxarea = mAttachedObject->getMaxScale() * mAttachedObject->getMidScale(); -	LLViewerObject::const_child_list_t& child_list = mAttachedObject->getChildren(); -	for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); -		 iter != child_list.end(); iter++) +	F32 maxarea = 0; +	for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); +		 iter != mAttachedObjects.end(); +		 ++iter)  	{ -		LLViewerObject* childp = *iter; -		F32 area = childp->getMaxScale() * childp->getMidScale(); -		maxarea = llmax(maxarea, area); +		if (LLViewerObject *attached_object = (*iter)) +		{ +			maxarea = llmax(maxarea,attached_object->getMaxScale() * attached_object->getMidScale()); +			LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); +			for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); +				 iter != child_list.end(); ++iter) +			{ +				LLViewerObject* childp = *iter; +				F32 area = childp->getMaxScale() * childp->getMidScale(); +				maxarea = llmax(maxarea, area); +			} +		}  	}  	maxarea = llclamp(maxarea, .01f*.01f, 1.f);  	F32 avatar_area = (4.f * 4.f); // pixels for an avatar sized attachment @@ -386,3 +407,47 @@ BOOL LLViewerJointAttachment::updateLOD(F32 pixel_area, BOOL activate)  	return res;  } +BOOL LLViewerJointAttachment::isObjectAttached(const LLViewerObject *viewer_object) const +{ +	for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); +		 iter != mAttachedObjects.end(); +		 ++iter) +	{ +		const LLViewerObject* attached_object = (*iter); +		if (attached_object == viewer_object) +		{ +			return TRUE; +		} +	} +	return FALSE; +} + +const LLViewerObject *LLViewerJointAttachment::getAttachedObject(const LLUUID &object_id) const +{ +	for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); +		 iter != mAttachedObjects.end(); +		 ++iter) +	{ +		const LLViewerObject* attached_object = (*iter); +		if (attached_object->getItemID() == object_id) +		{ +			return attached_object; +		} +	} +	return NULL; +} + +LLViewerObject *LLViewerJointAttachment::getAttachedObject(const LLUUID &object_id) +{ +	for (attachedobjs_vec_t::iterator iter = mAttachedObjects.begin(); +		 iter != mAttachedObjects.end(); +		 ++iter) +	{ +		LLViewerObject* attached_object = (*iter); +		if (attached_object->getItemID() == object_id) +		{ +			return attached_object; +		} +	} +	return NULL; +} diff --git a/indra/newview/llviewerjointattachment.h b/indra/newview/llviewerjointattachment.h index c003579684..221b5460f1 100644 --- a/indra/newview/llviewerjointattachment.h +++ b/indra/newview/llviewerjointattachment.h @@ -82,9 +82,9 @@ public:  	S32 getGroup() const { return mGroup; }  	S32 getPieSlice() const { return mPieSlice; } -	LLViewerObject *getObject() const { return mAttachedObject; } -	S32	getNumObjects() const { return (mAttachedObject ? 1 : 0); } -	const LLUUID& getItemID() const { return mItemID; } +	S32	getNumObjects() const { return mAttachedObjects.size(); } + +	void clampObjectPosition();  	//  	// unique methods @@ -92,21 +92,27 @@ public:  	BOOL addObject(LLViewerObject* object);  	void removeObject(LLViewerObject *object); -	void setupDrawable(LLDrawable* drawable); -	void clampObjectPosition(); +	//  +	// attachments operations +	// +	BOOL isObjectAttached(const LLViewerObject *viewer_object) const; +	const LLViewerObject *getAttachedObject(const LLUUID &object_id) const; +	LLViewerObject *getAttachedObject(const LLUUID &object_id); + +	// list of attachments for this joint +	typedef std::vector<LLViewerObject *> attachedobjs_vec_t; +	attachedobjs_vec_t mAttachedObjects;  protected:  	void calcLOD(); -	 -protected: -	// Backlink only; don't make this an LLPointer. -	LLViewerObject*	mAttachedObject; +	void setupDrawable(LLViewerObject *object); + +private:  	BOOL			mVisibleInFirst;  	LLVector3		mOriginalPos;  	S32				mGroup;  	BOOL			mIsHUDAttachment;  	S32				mPieSlice; -	LLUUID			mItemID;			// Inventory item id of the attached item (null if not in inventory)  };  #endif // LL_LLVIEWERJOINTATTACHMENT_H diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 2e45a61f1b..9652a7104d 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -2806,7 +2806,7 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t  			{  				LLVOAvatar::attachment_map_t::iterator curiter = iter++;  				LLViewerJointAttachment* attachment = curiter->second; -				if (attachment->getObject()) +				if (attachment->getNumObjects() > 0)  				{  					new_value = true;  					break; @@ -3063,7 +3063,7 @@ class LLAvatarDebug : public view_listener_t  			strings.push_back(avatar->getID().asString());  			LLUUID invoice;  			send_generic_message("dumptempassetdata", strings, invoice); -			LLFloaterReg::showInstance( "avatar_tetures", LLSD(avatar->getID()) ); +			LLFloaterReg::showInstance( "avatar_textures", LLSD(avatar->getID()) );  		}  		return true;  	} @@ -5897,12 +5897,12 @@ void near_attach_object(BOOL success, void *user_data)  {  	if (success)  	{ -		LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data; +		const LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data;  		U8 attachment_id = 0;  		if (attachment)  		{ -			for (LLVOAvatar::attachment_map_t::iterator iter = gAgent.getAvatarObject()->mAttachmentPoints.begin(); +			for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgent.getAvatarObject()->mAttachmentPoints.begin();  				 iter != gAgent.getAvatarObject()->mAttachmentPoints.end(); ++iter)  			{  				if (iter->second == attachment) @@ -6002,24 +6002,27 @@ class LLAttachmentDrop : public view_listener_t  class LLAttachmentDetachFromPoint : public view_listener_t  {  	bool handleEvent(const LLSD& user_data) -{ -		LLViewerJointAttachment *attachment = get_if_there(gAgent.getAvatarObject()->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); -	 -		LLViewerObject* attached_object = attachment ? attachment->getObject() : NULL; - -	if (attached_object)  	{ -		gMessageSystem->newMessage("ObjectDetach"); -		gMessageSystem->nextBlockFast(_PREHASH_AgentData); -		gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); -		gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - -		gMessageSystem->nextBlockFast(_PREHASH_ObjectData); -		gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID()); -		gMessageSystem->sendReliable( gAgent.getRegionHost() ); -	} +		const LLViewerJointAttachment *attachment = get_if_there(gAgent.getAvatarObject()->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); +		if (attachment->getNumObjects() > 0) +		{ +			gMessageSystem->newMessage("ObjectDetach"); +			gMessageSystem->nextBlockFast(_PREHASH_AgentData); +			gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); +			gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +			 +			for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin(); +				 iter != attachment->mAttachedObjects.end(); +				 iter++) +			{ +				LLViewerObject *attached_object = (*iter); +				gMessageSystem->nextBlockFast(_PREHASH_ObjectData); +				gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID()); +			} +			gMessageSystem->sendReliable( gAgent.getRegionHost() ); +		}  		return true; -} +	}  };  static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) @@ -6028,25 +6031,31 @@ static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data)  	LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl);  	if (menu)  	{ -		LLViewerJointAttachment *attachmentp = get_if_there(gAgent.getAvatarObject()->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL); -	if (attachmentp) -	{ -			label = data["label"].asString(); -		if (attachmentp->getObject()) +		const LLViewerJointAttachment *attachment = get_if_there(gAgent.getAvatarObject()->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL); +		if (attachment)  		{ -			LLViewerInventoryItem* itemp = gInventory.getItem(attachmentp->getItemID()); -			if (itemp) +			label = data["label"].asString(); +			for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin(); +				 attachment_iter != attachment->mAttachedObjects.end(); +				 ++attachment_iter)  			{ -				label += std::string(" (") + itemp->getName() + std::string(")"); +				const LLViewerObject* attached_object = (*attachment_iter); +				if (attached_object) +				{ +					LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getItemID()); +					if (itemp) +					{ +						label += std::string(" (") + itemp->getName() + std::string(")"); +						break; +					} +				}  			}  		} -	}  		menu->setLabel(label); -} +	}  	return true;  } -  class LLAttachmentDetach : public view_listener_t  {  	bool handleEvent(const LLSD& userdata) @@ -6133,33 +6142,37 @@ class LLAttachmentEnableDrop : public view_listener_t  		// item is in your inventory  		LLViewerObject*              object         = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); -		LLViewerJointAttachment*     attachment_pt  = NULL; +		LLViewerJointAttachment*     attachment     = NULL;  		LLInventoryItem*             item           = NULL; -		if ( object ) +		if (object)  		{      		S32 attachmentID  = ATTACHMENT_ID_FROM_STATE(object->getState()); -			attachment_pt = get_if_there(gAgent.getAvatarObject()->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); +			attachment = get_if_there(gAgent.getAvatarObject()->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); -			if ( attachment_pt ) +			if (attachment)  			{ -				// make sure item is in your inventory (it could be a delayed attach message being sent from the sim) -				// so check to see if the item is in the inventory already -				item = gInventory.getItem(attachment_pt->getItemID()); -				 -				if ( !item ) +				for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +					 attachment_iter != attachment->mAttachedObjects.end(); +					 ++attachment_iter)  				{ -					// Item does not exist, make an observer to enable the pie menu  -					// when the item finishes fetching worst case scenario  -					// if a fetch is already out there (being sent from a slow sim) -					// we refetch and there are 2 fetches -					LLWornItemFetchedObserver* wornItemFetched = new LLWornItemFetchedObserver(); -					LLInventoryFetchObserver::item_ref_t items; //add item to the inventory item to be fetched - -					items.push_back(attachment_pt->getItemID()); -				 -					wornItemFetched->fetchItems(items); -					gInventory.addObserver(wornItemFetched); +					// make sure item is in your inventory (it could be a delayed attach message being sent from the sim) +					// so check to see if the item is in the inventory already +					item = gInventory.getItem((*attachment_iter)->getItemID()); +					if (!item) +					{ +						// Item does not exist, make an observer to enable the pie menu  +						// when the item finishes fetching worst case scenario  +						// if a fetch is already out there (being sent from a slow sim) +						// we refetch and there are 2 fetches +						LLWornItemFetchedObserver* wornItemFetched = new LLWornItemFetchedObserver(); +						LLInventoryFetchObserver::item_ref_t items; //add item to the inventory item to be fetched +						 +						items.push_back((*attachment_iter)->getItemID()); +						 +						wornItemFetched->fetchItems(items); +						gInventory.addObserver(wornItemFetched); +					}  				}  			}  		} @@ -6262,11 +6275,11 @@ class LLAttachmentPointFilled : public view_listener_t  		bool enable = false;  		LLVOAvatar::attachment_map_t::iterator found_it = gAgent.getAvatarObject()->mAttachmentPoints.find(user_data.asInteger());  		if (found_it != gAgent.getAvatarObject()->mAttachmentPoints.end()) -{ -			enable = found_it->second->getObject() != NULL; +		{ +			enable = found_it->second->getNumObjects() > 0;  		}  		return enable; -} +	}  };  class LLAvatarSendIM : public view_listener_t @@ -6489,17 +6502,23 @@ void handle_dump_attachments(void*)  		LLVOAvatar::attachment_map_t::iterator curiter = iter++;  		LLViewerJointAttachment* attachment = curiter->second;  		S32 key = curiter->first; -		BOOL visible = (attachment->getObject() != NULL && -						attachment->getObject()->mDrawable.notNull() &&  -						!attachment->getObject()->mDrawable->isRenderType(0)); -		LLVector3 pos; -		if (visible) pos = attachment->getObject()->mDrawable->getPosition(); -		llinfos << "ATTACHMENT " << key << ": item_id=" << attachment->getItemID() -				<< (attachment->getObject() ? " present " : " absent ") -				<< (visible ? "visible " : "invisible ") -				<<  " at " << pos -				<< " and " << (visible ? attachment->getObject()->getPosition() : LLVector3::zero) -				<< llendl; +		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +			 attachment_iter != attachment->mAttachedObjects.end(); +			 ++attachment_iter) +		{ +			LLViewerObject *attached_object = (*attachment_iter); +			BOOL visible = (attached_object != NULL && +							attached_object->mDrawable.notNull() &&  +							!attached_object->mDrawable->isRenderType(0)); +			LLVector3 pos; +			if (visible) pos = attached_object->mDrawable->getPosition(); +			llinfos << "ATTACHMENT " << key << ": item_id=" << attached_object->getItemID() +					<< (attached_object ? " present " : " absent ") +					<< (visible ? "visible " : "invisible ") +					<<  " at " << pos +					<< " and " << (visible ? attached_object->getPosition() : LLVector3::zero) +					<< llendl; +		}  	}  } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 1f4f1322fd..20cd516fa0 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -219,7 +219,8 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe  	mJointInfo(NULL),  	mState(0),  	mMedia(NULL), -	mClickAction(0) +	mClickAction(0), +	mAttachmentItemID(LLUUID::null)  {  	if(!is_global)  	{ diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index bec36f9da7..b8ae31118c 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -676,6 +676,12 @@ protected:  private:	  	static S32 sNumObjects; + +public: +	const LLUUID &getItemID() const { return mAttachmentItemID; } +	void setItemID(const LLUUID &id) { mAttachmentItemID = id; } +private: +	LLUUID mAttachmentItemID; // ItemID when item is in user inventory.  };  /////////////////// diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 1d982265ca..2927ca5292 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1216,21 +1216,25 @@ void LLViewerObjectList::generatePickList(LLCamera &camera)  				 iter != avatarp->mAttachmentPoints.end(); )  			{  				LLVOAvatar::attachment_map_t::iterator curiter = iter++; -				LLViewerJointAttachment* attachmentp = curiter->second; -				if (attachmentp->getIsHUDAttachment()) +				LLViewerJointAttachment* attachment = curiter->second; +				if (attachment->getIsHUDAttachment())  				{ -					LLViewerObject* objectp = attachmentp->getObject(); -					if (objectp) +					for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +						 attachment_iter != attachment->mAttachedObjects.end(); +						 ++attachment_iter)  					{ -						mSelectPickList.insert(objectp);		 -						LLViewerObject::const_child_list_t& child_list = objectp->getChildren(); -						for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); -							 iter != child_list.end(); iter++) +						if (LLViewerObject* attached_object = (*attachment_iter))  						{ -							LLViewerObject* childp = *iter; -							if (childp) +							mSelectPickList.insert(attached_object); +							LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); +							for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); +								 iter != child_list.end(); iter++)  							{ -								mSelectPickList.insert(childp); +								LLViewerObject* childp = *iter; +								if (childp) +								{ +									mSelectPickList.insert(childp); +								}  							}  						}  					} diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 2c578ebd2b..398c311808 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -612,7 +612,7 @@ F32 LLVOAvatar::sGreyUpdateTime = 0.f;  // Helper functions  //-----------------------------------------------------------------------------  static F32 calc_bouncy_animation(F32 x); -static U32 calc_shame(LLVOVolume* volume, std::set<LLUUID> &textures); +static U32 calc_shame(const LLVOVolume* volume, std::set<LLUUID> &textures);  //-----------------------------------------------------------------------------  // LLVOAvatar() @@ -1346,27 +1346,32 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)  			continue ;  		} -		LLViewerObject* object = attachment->getObject(); -		if (object && !object->isHUDAttachment()) +		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +			 attachment_iter != attachment->mAttachedObjects.end(); +			 ++attachment_iter)  		{ -			LLDrawable* drawable = object->mDrawable; -			if (drawable) +			const LLViewerObject* attached_object = (*attachment_iter); +			if (attached_object && !attached_object->isHUDAttachment())  			{ -				LLSpatialBridge* bridge = drawable->getSpatialBridge(); -				if (bridge) +				LLDrawable* drawable = attached_object->mDrawable; +				if (drawable)  				{ -					const LLVector3* ext = bridge->getSpatialExtents(); -					LLVector3 distance = (ext[1] - ext[0]); -					 -					// Only add the prim to spatial extents calculations if it isn't a megaprim. -					// max_attachment_span calculated at the start of the function  -					// (currently 5 times our max prim size)  -					if (distance.mV[0] < max_attachment_span  -						&& distance.mV[1] < max_attachment_span -						&& distance.mV[2] < max_attachment_span) +					LLSpatialBridge* bridge = drawable->getSpatialBridge(); +					if (bridge)  					{ -						update_min_max(newMin,newMax,ext[0]); -						update_min_max(newMin,newMax,ext[1]); +						const LLVector3* ext = bridge->getSpatialExtents(); +						LLVector3 distance = (ext[1] - ext[0]); +						 +						// Only add the prim to spatial extents calculations if it isn't a megaprim. +						// max_attachment_span calculated at the start of the function  +						// (currently 5 times our max prim size)  +						if (distance.mV[0] < max_attachment_span  +							&& distance.mV[1] < max_attachment_span +							&& distance.mV[2] < max_attachment_span) +						{ +							update_min_max(newMin,newMax,ext[0]); +							update_min_max(newMin,newMax,ext[1]); +						}  					}  				}  			} @@ -2316,30 +2321,35 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)  		{  			attachment_map_t::iterator curiter = iter++;  			LLViewerJointAttachment* attachment = curiter->second; -			LLViewerObject *attached_object = attachment->getObject(); - -			BOOL visibleAttachment = visible || (attached_object &&  -												 !(attached_object->mDrawable->getSpatialBridge() && -												   attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); -			if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid()) +			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +				 attachment_iter != attachment->mAttachedObjects.end(); +				 ++attachment_iter)  			{ -				// if selecting any attachments, update all of them as non-damped -				if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment()) -				{ -					gPipeline.updateMoveNormalAsync(attached_object->mDrawable); -				} -				else -				{ -					gPipeline.updateMoveDampedAsync(attached_object->mDrawable); -				} - -				LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge(); -				if (bridge) +				LLViewerObject* attached_object = (*attachment_iter); +				BOOL visibleAttachment = visible || (attached_object &&  +													 !(attached_object->mDrawable->getSpatialBridge() && +													   attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); +				 +				if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid())  				{ -					gPipeline.updateMoveNormalAsync(bridge); +					// if selecting any attachments, update all of them as non-damped +					if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment()) +					{ +						gPipeline.updateMoveNormalAsync(attached_object->mDrawable); +					} +					else +					{ +						gPipeline.updateMoveDampedAsync(attached_object->mDrawable); +					} +					 +					LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge(); +					if (bridge) +					{ +						gPipeline.updateMoveNormalAsync(bridge); +					} +					attached_object->updateText();	  				} -				attached_object->updateText();	  			}  		}  	} @@ -3537,15 +3547,21 @@ void LLVOAvatar::updateVisibility()  			{  				attachment_map_t::iterator curiter = iter++;  				LLViewerJointAttachment* attachment = curiter->second; -				if (attachment->getObject()) + +				for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +					 attachment_iter != attachment->mAttachedObjects.end(); +					 ++attachment_iter)  				{ -					if(attachment->getObject()->mDrawable->isVisible()) +					if (LLViewerObject *attached_object = (*attachment_iter))  					{ -						llinfos << attachment->getName() << " visible" << llendl; -					} -					else -					{ -						llinfos << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << llendl; +						if(attached_object->mDrawable->isVisible()) +						{ +							llinfos << attachment->getName() << " visible" << llendl; +						} +						else +						{ +							llinfos << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << llendl; +						}  					}  				}  			} @@ -5385,7 +5401,10 @@ void LLVOAvatar::addChild(LLViewerObject *childp)  void LLVOAvatar::removeChild(LLViewerObject *childp)  {  	LLViewerObject::removeChild(childp); -	detachObject(childp); +	if (!detachObject(childp)) +	{ +		llwarns << "Calling detach on non-attached object " << llendl; +	}  }  LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object) @@ -5405,7 +5424,7 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi  //-----------------------------------------------------------------------------  // attachObject()  //----------------------------------------------------------------------------- -LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object) +const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object)  {  	LLViewerJointAttachment* attachment = getTargetAttachmentPoint(viewer_object); @@ -5424,6 +5443,30 @@ LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object)  }  //----------------------------------------------------------------------------- +// attachObject() +//----------------------------------------------------------------------------- +U32 LLVOAvatar::getNumAttachments() const +{ +	U32 num_attachments = 0; +	for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); +		 iter != mAttachmentPoints.end(); +		 iter++) +	{ +		const LLViewerJointAttachment *attachment_pt = (*iter).second; +		num_attachments += attachment_pt->getNumObjects(); +	} +	return num_attachments; +} + +//----------------------------------------------------------------------------- +// canAttachMoreObjects() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::canAttachMoreObjects() const +{ +	return (getNumAttachments() < MAX_AGENT_ATTACHMENTS); +} + +//-----------------------------------------------------------------------------  // lazyAttach()  //-----------------------------------------------------------------------------  void LLVOAvatar::lazyAttach() @@ -5454,10 +5497,15 @@ void LLVOAvatar::resetHUDAttachments()  		LLViewerJointAttachment* attachment = curiter->second;  		if (attachment->getIsHUDAttachment())  		{ -			LLViewerObject* obj = attachment->getObject(); -			if (obj && obj->mDrawable.notNull()) +			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +				 attachment_iter != attachment->mAttachedObjects.end(); +				 ++attachment_iter)  			{ -				gPipeline.markMoved(obj->mDrawable); +				const LLViewerObject* attached_object = (*attachment_iter); +				if (attached_object && attached_object->mDrawable.notNull()) +				{ +					gPipeline.markMoved(attached_object->mDrawable); +				}  			}  		}  	} @@ -5473,19 +5521,19 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)  	{  		attachment_map_t::iterator curiter = iter++;  		LLViewerJointAttachment* attachment = curiter->second; -		// only one object per attachment point for now -		if (attachment->getObject() == viewer_object) + +		if (attachment->isObjectAttached(viewer_object))  		{ -			LLUUID item_id = attachment->getItemID(); +			LLUUID item_id = viewer_object->getItemID();  			attachment->removeObject(viewer_object);  			if (isSelf())  			{  				// the simulator should automatically handle  				// permission revocation - +				  				stopMotionFromSource(viewer_object->getID());  				LLFollowCamMgr::setCameraActive(viewer_object->getID(), FALSE); - +				  				LLViewerObject::const_child_list_t& child_list = viewer_object->getChildren();  				for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();  					 iter != child_list.end(); iter++) @@ -5493,17 +5541,16 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)  					LLViewerObject* child_objectp = *iter;  					// the simulator should automatically handle  					// permissions revocation - +					  					stopMotionFromSource(child_objectp->getID());  					LLFollowCamMgr::setCameraActive(child_objectp->getID(), FALSE);  				} -  			}  			lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl;  			if (isSelf())  			{  				// Then make sure the inventory is in sync with the avatar. - +				  				// Update COF contents, don't trigger appearance update.  				if (gAgent.getAvatarObject() == NULL)  				{ @@ -5513,9 +5560,8 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)  				{  					LLAppearanceManager::dumpCat(LLAppearanceManager::getCOF(),"Removing attachment link:");  					LLAppearanceManager::removeItemLinks(item_id, false); -  				} - +				  				// BAP - needs to change for label to track link.  				gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);  				gInventory.notifyObservers(); @@ -5523,7 +5569,6 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)  			return TRUE;  		}  	} -  	return FALSE;  } @@ -6319,7 +6364,7 @@ BOOL LLVOAvatar::hasHUDAttachment() const  	{  		attachment_map_t::const_iterator curiter = iter++;  		LLViewerJointAttachment* attachment = curiter->second; -		if (attachment->getIsHUDAttachment() && attachment->getObject()) +		if (attachment->getIsHUDAttachment() && attachment->getNumObjects() > 0)  		{  			return TRUE;  		} @@ -6335,20 +6380,24 @@ LLBBox LLVOAvatar::getHUDBBox() const  	{  		attachment_map_t::const_iterator curiter = iter++;  		LLViewerJointAttachment* attachment = curiter->second; -		if (attachment->getIsHUDAttachment() && attachment->getObject()) +		if (attachment->getIsHUDAttachment())  		{ -			LLViewerObject* hud_object = attachment->getObject(); - -			// initialize bounding box to contain identity orientation and center point for attached object -			bbox.addPointLocal(hud_object->getPosition()); -			// add rotated bounding box for attached object -			bbox.addBBoxAgent(hud_object->getBoundingBoxAgent()); -			LLViewerObject::const_child_list_t& child_list = hud_object->getChildren(); -			for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); -				 iter != child_list.end(); iter++) +			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +				 attachment_iter != attachment->mAttachedObjects.end(); +				 ++attachment_iter)  			{ -				LLViewerObject* child_objectp = *iter; -				bbox.addBBoxAgent(child_objectp->getBoundingBoxAgent()); +				const LLViewerObject* attached_object = (*attachment_iter); +				// initialize bounding box to contain identity orientation and center point for attached object +				bbox.addPointLocal(attached_object->getPosition()); +				// add rotated bounding box for attached object +				bbox.addBBoxAgent(attached_object->getBoundingBoxAgent()); +				LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); +				for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); +					 iter != child_list.end(); iter++) +				{ +					const LLViewerObject* child_objectp = *iter; +					bbox.addBBoxAgent(child_objectp->getBoundingBoxAgent()); +				}  			}  		}  	} @@ -7582,21 +7631,26 @@ void LLVOAvatar::idleUpdateRenderCost()  		 ++iter)  	{  		LLViewerJointAttachment* attachment = iter->second; -		LLViewerObject* object = attachment->getObject(); -		if (object && !object->isHUDAttachment()) +		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +			 attachment_iter != attachment->mAttachedObjects.end(); +			 ++attachment_iter)  		{ -			LLDrawable* drawable = object->mDrawable; -			if (drawable) +			const LLViewerObject* attached_object = (*attachment_iter); +			if (attached_object && !attached_object->isHUDAttachment())  			{ -				shame += 10; -				LLVOVolume* volume = drawable->getVOVolume(); -				if (volume) +				const LLDrawable* drawable = attached_object->mDrawable; +				if (drawable)  				{ -					shame += calc_shame(volume, textures); +					shame += 10; +					const LLVOVolume* volume = drawable->getVOVolume(); +					if (volume) +					{ +						shame += calc_shame(volume, textures); +					}  				}  			}  		} -	}	 +	}  	shame += textures.size() * 5; @@ -7644,7 +7698,7 @@ const std::string LLVOAvatar::getBakedStatusForPrintout() const  } -U32 calc_shame(LLVOVolume* volume, std::set<LLUUID> &textures) +U32 calc_shame(const LLVOVolume* volume, std::set<LLUUID> &textures)  {  	if (!volume)  	{ @@ -7676,20 +7730,20 @@ U32 calc_shame(LLVOVolume* volume, std::set<LLUUID> &textures)  	const LLVector3& sc = volume->getScale();  	scale += (U32) sc.mV[0] + (U32) sc.mV[1] + (U32) sc.mV[2]; -	LLDrawable* drawablep = volume->mDrawable; +	const LLDrawable* drawablep = volume->mDrawable;  	if (volume->isSculpted())  	{ -		LLSculptParams *sculpt_params = (LLSculptParams *) volume->getParameterEntry(LLNetworkData::PARAMS_SCULPT); +		const LLSculptParams *sculpt_params = (LLSculptParams *) volume->getParameterEntry(LLNetworkData::PARAMS_SCULPT);  		LLUUID sculpt_id = sculpt_params->getSculptTexture();  		textures.insert(sculpt_id);  	}  	for (S32 i = 0; i < drawablep->getNumFaces(); ++i)  	{ -		LLFace* face = drawablep->getFace(i); +		const LLFace* face = drawablep->getFace(i);  		const LLTextureEntry* te = face->getTextureEntry(); -		LLViewerTexture* img = face->getTexture(); +		const LLViewerTexture* img = face->getTexture();  		textures.insert(img->getID()); @@ -7733,11 +7787,11 @@ U32 calc_shame(LLVOVolume* volume, std::set<LLUUID> &textures)  	for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();  		 iter != child_list.end(); iter++)  	{ -		LLViewerObject* child_objectp = *iter; -		LLDrawable* child_drawablep = child_objectp->mDrawable; +		const LLViewerObject* child_objectp = *iter; +		const LLDrawable* child_drawablep = child_objectp->mDrawable;  		if (child_drawablep)  		{ -			LLVOVolume* child_volumep = child_drawablep->getVOVolume(); +			const LLVOVolume* child_volumep = child_drawablep->getVOVolume();  			if (child_volumep)  			{  				shame += calc_shame(child_volumep, textures); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 1529beeac9..1180d43438 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -648,7 +648,7 @@ public:  	//--------------------------------------------------------------------  public:  	void 				clampAttachmentPositions(); -	virtual LLViewerJointAttachment* attachObject(LLViewerObject *viewer_object); +	virtual const LLViewerJointAttachment* attachObject(LLViewerObject *viewer_object);  	BOOL 				detachObject(LLViewerObject *viewer_object);  	static LLVOAvatar*  findAvatarFromAttachment(LLViewerObject* obj);  protected: @@ -672,6 +672,9 @@ public:  	LLBBox 				getHUDBBox() const;  	void 				rebuildHUD();  	void 				resetHUDAttachments(); +	BOOL				canAttachMoreObjects() const; +protected: +	U32					getNumAttachments() const; // O(N), not O(1)  /**                    Wearables   **                                                                            ** diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 457c6fe93e..03f9bd4b7c 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -976,7 +976,7 @@ BOOL LLVOAvatarSelf::isWearingAttachment( const LLUUID& inv_item_id , BOOL inclu  	{  		attachment_map_t::const_iterator curiter = iter++;  		const LLViewerJointAttachment* attachment = curiter->second; -		if( attachment->getItemID() == inv_item_id ) +		if (attachment->getAttachedObject(inv_item_id))  		{  			return TRUE;  		} @@ -997,7 +997,7 @@ BOOL LLVOAvatarSelf::isWearingAttachment( const LLUUID& inv_item_id , BOOL inclu  			{  				attachment_map_t::const_iterator curiter = iter++;  				const LLViewerJointAttachment* attachment = curiter->second; -				if( attachment->getItemID() == item_id ) +				if (attachment->getAttachedObject(item_id))  				{  					return TRUE;  				} @@ -1011,16 +1011,16 @@ BOOL LLVOAvatarSelf::isWearingAttachment( const LLUUID& inv_item_id , BOOL inclu  //-----------------------------------------------------------------------------  // getWornAttachment()  //----------------------------------------------------------------------------- -LLViewerObject* LLVOAvatarSelf::getWornAttachment( const LLUUID& inv_item_id ) const +LLViewerObject* LLVOAvatarSelf::getWornAttachment( const LLUUID& inv_item_id )  { -	for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();  +	for (attachment_map_t::iterator iter = mAttachmentPoints.begin();   		 iter != mAttachmentPoints.end(); )  	{ -		attachment_map_t::const_iterator curiter = iter++; -		const LLViewerJointAttachment* attachment = curiter->second; -		if( attachment->getItemID() == inv_item_id ) +		attachment_map_t::iterator curiter = iter++; +		LLViewerJointAttachment* attachment = curiter->second; + 		if (LLViewerObject *attached_object = attachment->getAttachedObject(inv_item_id))  		{ -			return attachment->getObject(); +			return attached_object;  		}  	}  	return NULL; @@ -1033,7 +1033,7 @@ const std::string LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id  	{  		attachment_map_t::const_iterator curiter = iter++;  		const LLViewerJointAttachment* attachment = curiter->second; -		if( attachment->getItemID() == inv_item_id ) +		if (attachment->getAttachedObject(inv_item_id))  		{  			return attachment->getName();  		} @@ -1043,9 +1043,9 @@ const std::string LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id  }  //virtual -LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *viewer_object) +const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *viewer_object)  { -	LLViewerJointAttachment *attachment = LLVOAvatar::attachObject(viewer_object); +	const LLViewerJointAttachment *attachment = LLVOAvatar::attachObject(viewer_object);  	if (!attachment)  	{  		return 0; @@ -1054,14 +1054,20 @@ LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *viewer_obj  	updateAttachmentVisibility(gAgent.getCameraMode());  	// Then make sure the inventory is in sync with the avatar. -	LLViewerInventoryItem *item = gInventory.getItem(attachment->getItemID()); -	if (item) -	{ -		LLAppearanceManager::dumpCat(LLAppearanceManager::getCOF(),"Adding attachment link:"); -		LLAppearanceManager::wearItem(item,false);  // Add COF link for item. +	// Should just be the last object added +	if (attachment->isObjectAttached(viewer_object)) +	{ +		const LLUUID& attachment_id = viewer_object->getItemID(); +		LLViewerInventoryItem *item = gInventory.getItem(attachment_id); +		if (item) +		{ +			LLAppearanceManager::dumpCat(LLAppearanceManager::getCOF(),"Adding attachment link:"); +			LLAppearanceManager::wearItem(item,false);  // Add COF link for item. +			gInventory.addChangedMask(LLInventoryObserver::LABEL, attachment_id); +		}  	} -	gInventory.addChangedMask(LLInventoryObserver::LABEL, attachment->getItemID()); +  	gInventory.notifyObservers();  	return attachment; diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 88eb491f35..0b76d3e960 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -276,9 +276,9 @@ public:  public:  	void 				updateAttachmentVisibility(U32 camera_mode);  	BOOL 				isWearingAttachment(const LLUUID& inv_item_id, BOOL include_linked_items = FALSE) const; -	LLViewerObject* 	getWornAttachment(const LLUUID& inv_item_id ) const; +	LLViewerObject* 	getWornAttachment(const LLUUID& inv_item_id );  	const std::string   getAttachedPointName(const LLUUID& inv_item_id) const; -	/*virtual*/ LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object); +	/*virtual*/ const LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object);  	void				getAllAttachmentsArray(LLDynamicArray<S32>& attachments);  	//-------------------------------------------------------------------- diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 3800b9223d..b50e71bf48 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3872,44 +3872,48 @@ void LLPipeline::renderForSelect(std::set<LLViewerObject*>& objects, BOOL render  			 iter != avatarp->mAttachmentPoints.end(); )  		{  			LLVOAvatar::attachment_map_t::iterator curiter = iter++; -			LLViewerJointAttachment* attachmentp = curiter->second; -			if (attachmentp->getIsHUDAttachment()) +			LLViewerJointAttachment* attachment = curiter->second; +			if (attachment->getIsHUDAttachment())  			{ -				LLViewerObject* objectp = attachmentp->getObject(); -				if (objectp) +				for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +					 attachment_iter != attachment->mAttachedObjects.end(); +					 ++attachment_iter)  				{ -					LLDrawable* drawable = objectp->mDrawable; -					if (drawable->isDead()) +					if (LLViewerObject* attached_object = (*attachment_iter))  					{ -						continue; -					} - -					for (S32 j = 0; j < drawable->getNumFaces(); ++j) -					{ -						LLFace* facep = drawable->getFace(j); -						if (!facep->getPool()) +						LLDrawable* drawable = attached_object->mDrawable; +						if (drawable->isDead())  						{ -							facep->renderForSelect(prim_mask); +							continue;  						} -					} - -					//render child faces -					LLViewerObject::const_child_list_t& child_list = objectp->getChildren(); -					for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); -						 iter != child_list.end(); iter++) -					{ -						LLViewerObject* child = *iter; -						LLDrawable* child_drawable = child->mDrawable; -						for (S32 l = 0; l < child_drawable->getNumFaces(); ++l) +							 +						for (S32 j = 0; j < drawable->getNumFaces(); ++j)  						{ -							LLFace* facep = child_drawable->getFace(l); +							LLFace* facep = drawable->getFace(j);  							if (!facep->getPool())  							{  								facep->renderForSelect(prim_mask);  							}  						} +							 +						//render child faces +						LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); +						for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); +							 iter != child_list.end(); iter++) +						{ +							LLViewerObject* child = *iter; +							LLDrawable* child_drawable = child->mDrawable; +							for (S32 l = 0; l < child_drawable->getNumFaces(); ++l) +							{ +								LLFace* facep = child_drawable->getFace(l); +								if (!facep->getPool()) +								{ +									facep->renderForSelect(prim_mask); +								} +							} +						}  					} -				}	 +				}  			}  		} @@ -8682,10 +8686,15 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)  		iter != avatar->mAttachmentPoints.end();  		++iter)  	{ -		LLViewerObject* object = iter->second->getObject(); -		if (object) +		LLViewerJointAttachment *attachment = iter->second; +		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); +			 attachment_iter != attachment->mAttachedObjects.end(); +			 ++attachment_iter)  		{ -			markVisible(object->mDrawable->getSpatialBridge(), *LLViewerCamera::getInstance()); +			if (LLViewerObject* attached_object = (*attachment_iter)) +			{ +				markVisible(attached_object->mDrawable->getSpatialBridge(), *LLViewerCamera::getInstance()); +			}  		}  	} diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 95dd8677b4..4d987dbc90 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -757,6 +757,14 @@ You can not wear clothes or body parts that are in the trash    <notification     icon="alertmodal.tga" +   name="MaxAttachmentsOnOutfit" +   type="alertmodal"> +Could not attach object. +Exceeds the attachments limit of [MAX_ATTACHMENTS] objects. Please detach another object first. +  </notification> + +  <notification +   icon="alertmodal.tga"     name="CannotWearInfoNotComplete"     type="alertmodal">  You can not wear that item because it has not yet loaded. Please try again in a minute. | 
