summaryrefslogtreecommitdiff
path: root/indra/newview/llappearancemgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llappearancemgr.cpp')
-rw-r--r--indra/newview/llappearancemgr.cpp199
1 files changed, 104 insertions, 95 deletions
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 63315ce2ae..ed5e8ceee3 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -2,31 +2,25 @@
* @file llappearancemgr.cpp
* @brief Manager for initiating appearance changes on the viewer
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -37,6 +31,7 @@
#include "llagentcamera.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
+#include "llattachmentsmgr.h"
#include "llcommandhandler.h"
#include "lleventtimer.h"
#include "llgesturemgr.h"
@@ -1012,7 +1007,7 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up
addCOFItemLink(item_to_wear, do_update, cb);
break;
case LLAssetType::AT_OBJECT:
- rez_attachment(item_to_wear, NULL);
+ rez_attachment(item_to_wear, NULL, replace);
break;
default: return false;;
}
@@ -1275,6 +1270,11 @@ bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id)
// static
bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id)
{
+ if (gAgentWearables.isCOFChangeInProgress())
+ {
+ return false;
+ }
+
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false);
@@ -1286,6 +1286,24 @@ bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id)
return items.size() > 0;
}
+bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
+{
+ // Don't allow wearing anything while we're changing appearance.
+ if (gAgentWearables.isCOFChangeInProgress())
+ {
+ return false;
+ }
+
+ // Check whether it's the base outfit.
+ if (outfit_cat_id.isNull() || outfit_cat_id == getBaseOutfitUUID())
+ {
+ return false;
+ }
+
+ // Check whether the outfit contains the full set of body parts (shape+skin+hair+eyes).
+ return getCanMakeFolderIntoOutfit(outfit_cat_id);
+}
+
void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)
{
LLInventoryModel::cat_array_t cats;
@@ -1577,46 +1595,56 @@ void item_array_diff(LLInventoryModel::item_array_t& full_list,
}
}
-void LLAppearanceMgr::enforceItemCountLimits()
+S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,
+ LLAssetType::EType type,
+ S32 max_items,
+ LLInventoryModel::item_array_t& items_to_kill)
{
- S32 purge_count = 0;
-
- LLInventoryModel::item_array_t body_items;
- getDescendentsOfAssetType(getCOF(), body_items, LLAssetType::AT_BODYPART, false);
- LLInventoryModel::item_array_t curr_body_items = body_items;
- removeDuplicateItems(body_items);
- filterWearableItems(body_items, 1);
- LLInventoryModel::item_array_t kill_body_items;
- item_array_diff(curr_body_items,body_items,kill_body_items);
- for (LLInventoryModel::item_array_t::iterator it = kill_body_items.begin();
- it != kill_body_items.end();
- ++it)
+ S32 to_kill_count = 0;
+
+ LLInventoryModel::item_array_t items;
+ getDescendentsOfAssetType(cat_id, items, type, false);
+ LLInventoryModel::item_array_t curr_items = items;
+ removeDuplicateItems(items);
+ if (max_items > 0)
{
- LLViewerInventoryItem *item = *it;
- llinfos << "purging dup body part " << item->getName() << llendl;
- gInventory.purgeObject(item->getUUID());
- purge_count++;
+ filterWearableItems(items, max_items);
}
-
- LLInventoryModel::item_array_t wear_items;
- getDescendentsOfAssetType(getCOF(), wear_items, LLAssetType::AT_CLOTHING, false);
- LLInventoryModel::item_array_t curr_wear_items = wear_items;
- removeDuplicateItems(wear_items);
- filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
- LLInventoryModel::item_array_t kill_wear_items;
- item_array_diff(curr_wear_items,wear_items,kill_wear_items);
- for (LLInventoryModel::item_array_t::iterator it = kill_wear_items.begin();
- it != kill_wear_items.end();
+ LLInventoryModel::item_array_t kill_items;
+ item_array_diff(curr_items,items,kill_items);
+ for (LLInventoryModel::item_array_t::iterator it = kill_items.begin();
+ it != kill_items.end();
++it)
{
- LLViewerInventoryItem *item = *it;
- llinfos << "purging excess clothing item " << item->getName() << llendl;
- gInventory.purgeObject(item->getUUID());
- purge_count++;
+ items_to_kill.push_back(*it);
+ to_kill_count++;
}
+ return to_kill_count;
+}
+
+
+void LLAppearanceMgr::enforceItemRestrictions()
+{
+ S32 purge_count = 0;
+ LLInventoryModel::item_array_t items_to_kill;
- if (purge_count>0)
+ purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_BODYPART,
+ 1, items_to_kill);
+ purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_CLOTHING,
+ LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill);
+ purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_OBJECT,
+ -1, items_to_kill);
+
+ if (items_to_kill.size()>0)
{
+ for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin();
+ it != items_to_kill.end();
+ ++it)
+ {
+ LLViewerInventoryItem *item = *it;
+ llinfos << "purging duplicate or excess item " << item->getName() << llendl;
+ gInventory.purgeObject(item->getUUID());
+ }
gInventory.notifyObservers();
}
}
@@ -1639,7 +1667,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
// Remove duplicate or excess wearables. Should normally be enforced at the UI level, but
// this should catch anything that gets through.
- enforceItemCountLimits();
+ enforceItemRestrictions();
// update dirty flag to see if the state of the COF matches
// the saved outfit stored as a folder link
@@ -2280,12 +2308,17 @@ bool LLAppearanceMgr::updateBaseOutfit()
void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type)
{
- items_by_type.reserve(LLWearableType::WT_COUNT);
+ items_by_type.resize(LLWearableType::WT_COUNT);
if (items.empty()) return;
for (S32 i=0; i<items.count(); i++)
{
LLViewerInventoryItem *item = items.get(i);
+ if (!item)
+ {
+ LL_WARNS("Appearance") << "NULL item found" << llendl;
+ continue;
+ }
// Ignore non-wearables.
if (!item->isWearableType())
continue;
@@ -2308,6 +2341,7 @@ std::string build_order_string(LLWearableType::EType type, U32 i)
struct WearablesOrderComparator
{
+ LOG_CLASS(WearablesOrderComparator);
WearablesOrderComparator(const LLWearableType::EType type)
{
mControlSize = build_order_string(type, 0).size();
@@ -2473,29 +2507,17 @@ void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
switch (item_to_remove->getType())
{
- case LLAssetType::AT_CLOTHING:
- if (get_is_item_worn(id_to_remove))
- {
- //*TODO move here the exact removing code from LLWearableBridge::removeItemFromAvatar in the future
- LLWearableBridge::removeItemFromAvatar(item_to_remove);
- }
- break;
- case LLAssetType::AT_OBJECT:
- gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_to_remove->getLinkedUUID());
- gMessageSystem->sendReliable( gAgent.getRegion()->getHost());
-
- {
- // this object might have been selected, so let the selection manager know it's gone now
- LLViewerObject *found_obj = gObjectList.findObject(item_to_remove->getLinkedUUID());
- if (found_obj)
+ case LLAssetType::AT_CLOTHING:
+ if (get_is_item_worn(id_to_remove))
{
- LLSelectMgr::getInstance()->remove(found_obj);
- };
- }
- default: break;
+ //*TODO move here the exact removing code from LLWearableBridge::removeItemFromAvatar in the future
+ LLWearableBridge::removeItemFromAvatar(item_to_remove);
+ }
+ break;
+ case LLAssetType::AT_OBJECT:
+ LLVOAvatarSelf::detachAttachmentIntoInventory(item_to_remove->getLinkedUUID());
+ default:
+ break;
}
// *HACK: Force to remove garbage from COF.
@@ -2623,6 +2645,8 @@ LLAppearanceMgr::LLAppearanceMgr():
mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32(
"OutfitOperationsTimeout")));
+
+ gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle,NULL);
}
LLAppearanceMgr::~LLAppearanceMgr()
@@ -2635,7 +2659,6 @@ void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val)
mAttachmentInvLinkEnabled = val;
}
-// BAP TODO - mRegisteredAttachments is currently maintained but not used for anything. Consider yanking.
void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg)
{
llinfos << msg << llendl;
@@ -2655,7 +2678,6 @@ void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg)
void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)
{
- mRegisteredAttachments.insert(item_id);
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
if (mAttachmentInvLinkEnabled)
@@ -2673,7 +2695,6 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)
void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)
{
- mRegisteredAttachments.erase(item_id);
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
if (mAttachmentInvLinkEnabled)
@@ -2686,18 +2707,6 @@ void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)
}
}
-void LLAppearanceMgr::linkRegisteredAttachments()
-{
- for (std::set<LLUUID>::iterator it = mRegisteredAttachments.begin();
- it != mRegisteredAttachments.end();
- ++it)
- {
- LLUUID item_id = *it;
- addCOFItemLink(item_id, false);
- }
- mRegisteredAttachments.clear();
-}
-
BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const
{
return gInventory.isObjectDescendentOf(obj_id, getCOF());
@@ -2710,8 +2719,8 @@ bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id)
LLInventoryModel::item_array_t items;
LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id));
gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(),
- cats,
- items,
+ cats,
+ items,
LLInventoryModel::EXCLUDE_TRASH,
find_links);