summaryrefslogtreecommitdiff
path: root/indra/newview/llagentwearables.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llagentwearables.cpp')
-rwxr-xr-x[-rw-r--r--]indra/newview/llagentwearables.cpp2033
1 files changed, 814 insertions, 1219 deletions
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 223f8779ec..5589ab4aa7 100644..100755
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -2,133 +2,180 @@
* @file llagentwearables.cpp
* @brief LLAgentWearables class implementation
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&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.
+ *
+ * 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.
*
- * 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 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.
*
- * 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.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
-
-#include "llagent.h"
#include "llagentwearables.h"
-#include "llfloatercustomize.h"
-#include "llfloaterinventory.h"
+#include "llaccordionctrltab.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llappearancemgr.h"
+#include "llcallbacklist.h"
+#include "llfloatersidepanelcontainer.h"
+#include "llgesturemgr.h"
#include "llinventorybridge.h"
-#include "llinventorymodel.h"
-#include "llnotify.h"
+#include "llinventoryfunctions.h"
+#include "llinventoryobserver.h"
+#include "llinventorypanel.h"
+#include "lllocaltextureobject.h"
+#include "llmd5.h"
+#include "llnotificationsutil.h"
+#include "lloutfitobserver.h"
+#include "llsidepanelappearance.h"
+#include "lltexlayer.h"
+#include "lltooldraganddrop.h"
#include "llviewerregion.h"
#include "llvoavatarself.h"
-#include "llwearable.h"
+#include "llviewerwearable.h"
#include "llwearablelist.h"
-#include "llgesturemgr.h"
-#include "llappearancemgr.h"
-#include "lltexlayer.h"
+#include "llfloaterperms.h"
#include <boost/scoped_ptr.hpp>
-#define USE_CURRENT_OUTFIT_FOLDER
+LLAgentWearables gAgentWearables;
+
+BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE;
+
+using namespace LLAvatarAppearanceDefines;
+
+///////////////////////////////////////////////////////////////////////////////
-//--------------------------------------------------------------------
-// Classes for fetching initial wearables data
-//--------------------------------------------------------------------
-// Outfit folder fetching callback structure.
-class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver
+// Callback to wear and start editing an item that has just been created.
+void wear_and_edit_cb(const LLUUID& inv_item)
{
-public:
- LLInitialWearablesFetch() {}
- ~LLInitialWearablesFetch() {}
- virtual void done();
+ if (inv_item.isNull()) return;
+
+ LLViewerInventoryItem* item = gInventory.getItem(inv_item);
+ if (!item) return;
- struct InitialWearableData
- {
- EWearableType mType;
- LLUUID mItemID;
- LLUUID mAssetID;
- InitialWearableData(EWearableType type, LLUUID itemID, LLUUID assetID) :
- mType(type), mItemID(itemID), mAssetID(assetID) { }
- };
+ LLPermissions perm = item->getPermissions();
+ perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Wearables"));
+ perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Wearables"));
+ perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Wearables"));
+ item->setPermissions(perm);
- typedef std::vector<InitialWearableData> initial_wearable_data_vec_t;
- initial_wearable_data_vec_t mCOFInitialWearables; // Wearables from the Current Outfit Folder
- initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg
+ item->updateServer(FALSE);
+ gInventory.updateItem(item);
+ gInventory.notifyObservers();
-protected:
- void processWearablesMessage();
-};
+ // Request editing the item after it gets worn.
+ gAgentWearables.requestEditingWearable(inv_item);
+
+ // Wear it.
+ LLAppearanceMgr::instance().wearItemOnAvatar(inv_item,true);
+}
-LLAgentWearables gAgentWearables;
+void wear_cb(const LLUUID& inv_item)
+{
+ if (!inv_item.isNull())
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(inv_item);
+ if (item)
+ {
+ LLPermissions perm = item->getPermissions();
+ perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Wearables"));
+ perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Wearables"));
+ perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Wearables"));
+ item->setPermissions(perm);
+
+ item->updateServer(FALSE);
+ gInventory.updateItem(item);
+ gInventory.notifyObservers();
+ }
+ }
+}
-BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE;
+///////////////////////////////////////////////////////////////////////////////
-using namespace LLVOAvatarDefines;
+// HACK: For EXT-3923: Pants item shows in inventory with skin icon and messes with "current look"
+// Some db items are corrupted, have inventory flags = 0, implying wearable type = shape, even though
+// wearable type stored in asset is some other value.
+// Calling this function whenever a wearable is added to increase visibility if this problem
+// turns up in other inventories.
+void checkWearableAgainstInventory(LLViewerWearable *wearable)
+{
+ if (wearable->getItemID().isNull())
+ return;
+
+ // Check for wearable type consistent with inventory item wearable type.
+ LLViewerInventoryItem *item = gInventory.getItem(wearable->getItemID());
+ if (item)
+ {
+ if (!item->isWearableType())
+ {
+ LL_WARNS() << "wearable associated with non-wearable item" << LL_ENDL;
+ }
+ if (item->getWearableType() != wearable->getType())
+ {
+ LL_WARNS() << "type mismatch: wearable " << wearable->getName()
+ << " has type " << wearable->getType()
+ << " but inventory item " << item->getName()
+ << " has type " << item->getWearableType() << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS() << "wearable inventory item not found" << wearable->getName()
+ << " itemID " << wearable->getItemID().asString() << LL_ENDL;
+ }
+}
void LLAgentWearables::dump()
{
- llinfos << "LLAgentWearablesDump" << llendl;
- for (S32 i = 0; i < WT_COUNT; i++)
+ LL_INFOS() << "LLAgentWearablesDump" << LL_ENDL;
+ for (S32 i = 0; i < LLWearableType::WT_COUNT; i++)
{
- U32 count = getWearableCount((EWearableType)i);
- llinfos << "Type: " << i << " count " << count << llendl;
+ U32 count = getWearableCount((LLWearableType::EType)i);
+ LL_INFOS() << "Type: " << i << " count " << count << LL_ENDL;
for (U32 j=0; j<count; j++)
{
- LLWearable* wearable = getWearable((EWearableType)i,j);
+ LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)i,j);
if (wearable == NULL)
{
- llinfos << " " << j << " NULL wearable" << llendl;
+ LL_INFOS() << " " << j << " NULL wearable" << LL_ENDL;
}
- llinfos << " " << j << " Name " << wearable->getName()
- << " description " << wearable->getDescription() << llendl;
+ LL_INFOS() << " " << j << " Name " << wearable->getName()
+ << " description " << wearable->getDescription() << LL_ENDL;
}
}
- llinfos << "Total items awaiting wearable update " << mItemsAwaitingWearableUpdate.size() << llendl;
- for (std::set<LLUUID>::iterator it = mItemsAwaitingWearableUpdate.begin();
- it != mItemsAwaitingWearableUpdate.end();
- ++it)
- {
- llinfos << (*it).asString() << llendl;
- }
}
-// MULTI-WEARABLE: debugging
struct LLAgentDumper
{
LLAgentDumper(std::string name):
mName(name)
{
- llinfos << llendl;
- llinfos << "LLAgentDumper " << mName << llendl;
+ LL_INFOS() << LL_ENDL;
+ LL_INFOS() << "LLAgentDumper " << mName << LL_ENDL;
gAgentWearables.dump();
}
~LLAgentDumper()
{
- llinfos << llendl;
- llinfos << "~LLAgentDumper " << mName << llendl;
+ LL_INFOS() << LL_ENDL;
+ LL_INFOS() << "~LLAgentDumper " << mName << LL_ENDL;
gAgentWearables.dump();
}
@@ -136,8 +183,9 @@ struct LLAgentDumper
};
LLAgentWearables::LLAgentWearables() :
- mWearablesLoaded(FALSE),
- mAvatarObject(NULL)
+ LLWearableData(),
+ mWearablesLoaded(FALSE)
+, mCOFChangeInProgress(false)
{
}
@@ -148,27 +196,20 @@ LLAgentWearables::~LLAgentWearables()
void LLAgentWearables::cleanup()
{
- mAvatarObject = NULL;
-}
-
-void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar)
-{
- mAvatarObject = avatar;
- if (avatar)
- {
- sendAgentWearablesRequest();
- }
}
-// wearables
-LLAgentWearables::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback()
+// static
+void LLAgentWearables::initClass()
{
- gAgentWearables.createStandardWearablesAllDone();
+ // this can not be called from constructor because its instance is global and is created too early.
+ // Subscribe to "COF is Saved" signal to notify observers about this (Loading indicator for ex.).
+ LLOutfitObserver::instance().addCOFSavedCallback(boost::bind(&LLAgentWearables::notifyLoadingFinished, &gAgentWearables));
}
-LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback()
+void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar)
{
- gAgentWearables.sendAgentWearablesUpdate();
+ llassert(avatar);
+ setAvatarAppearance(avatar);
}
/**
@@ -176,73 +217,73 @@ LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCal
*
* Would like to pass the agent in here, but we can't safely
* count on it being around later. Just use gAgent directly.
- * @param cb callback to execute on completion (??? unused ???)
+ * @param cb callback to execute on completion (? unused ?)
* @param type Type for the wearable in the agent
* @param wearable The wearable data.
* @param todo Bitmask of actions to take on completion.
*/
-LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback(
- LLPointer<LLRefCount> cb, S32 type, U32 index, LLWearable* wearable, U32 todo) :
+LLAgentWearables::AddWearableToAgentInventoryCallback::AddWearableToAgentInventoryCallback(
+ LLPointer<LLRefCount> cb, LLWearableType::EType type, U32 index, LLViewerWearable* wearable, U32 todo, const std::string description) :
mType(type),
mIndex(index),
mWearable(wearable),
mTodo(todo),
- mCB(cb)
+ mCB(cb),
+ mDescription(description)
{
+ LL_INFOS() << "constructor" << LL_ENDL;
}
-void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)
+void LLAgentWearables::AddWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)
{
if (inv_item.isNull())
return;
gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable);
- if (mTodo & CALL_UPDATE)
- {
- gAgentWearables.sendAgentWearablesUpdate();
- }
- if (mTodo & CALL_RECOVERDONE)
- {
- gAgentWearables.recoverMissingWearableDone();
- }
/*
* Do this for every one in the loop
*/
- if (mTodo & CALL_CREATESTANDARDDONE)
- {
- gAgentWearables.createStandardWearablesDone(mType, mIndex);
- }
if (mTodo & CALL_MAKENEWOUTFITDONE)
{
gAgentWearables.makeNewOutfitDone(mType, mIndex);
}
+ if (mTodo & CALL_WEARITEM)
+ {
+ LLAppearanceMgr::instance().addCOFItemLink(inv_item,
+ new LLUpdateAppearanceAndEditWearableOnDestroy(inv_item), mDescription);
+ }
}
-void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type,
+void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::EType type,
const U32 index,
const LLUUID& item_id,
- LLWearable* wearable)
+ LLViewerWearable* wearable)
{
+ LL_INFOS() << "type " << type << " index " << index << " item " << item_id.asString() << LL_ENDL;
+
if (item_id.isNull())
return;
- LLUUID old_item_id = getWearableItemID((EWearableType)type,index);
+ LLUUID old_item_id = getWearableItemID(type,index);
+
if (wearable)
{
wearable->setItemID(item_id);
- }
- if (old_item_id.notNull())
- {
- gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
- setWearable((EWearableType)type,index,wearable);
- }
- else
- {
- pushWearable((EWearableType)type,wearable);
+ if (old_item_id.notNull())
+ {
+ gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
+ setWearable(type,index,wearable);
+ }
+ else
+ {
+ pushWearable(type,wearable);
+ }
}
+
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
+
LLViewerInventoryItem* item = gInventory.getItem(item_id);
if (item && wearable)
{
@@ -257,95 +298,33 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type,
gInventory.notifyObservers();
}
-void LLAgentWearables::sendAgentWearablesUpdate()
+void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index,
+ const std::string new_name)
{
- // MULTI-WEARABLE: call i "type" or something.
- // First make sure that we have inventory items for each wearable
- for (S32 type=0; type < WT_COUNT; ++type)
- {
- for (U32 j=0; j < getWearableCount((EWearableType)type); ++j)
- {
- LLWearable* wearable = getWearable((EWearableType)type,j);
- if (wearable)
- {
- if (wearable->getItemID().isNull())
- {
- LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
- LLPointer<LLRefCount>(NULL),
- type,
- j,
- wearable,
- addWearableToAgentInventoryCallback::CALL_NONE);
- addWearableToAgentInventory(cb, wearable);
- }
- else
- {
- gInventory.addChangedMask(LLInventoryObserver::LABEL,
- wearable->getItemID());
- }
- }
- }
- }
-
- // Then make sure the inventory is in sync with the avatar.
- gInventory.notifyObservers();
-
- // Send the AgentIsNowWearing
- gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing);
-
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-
- lldebugs << "sendAgentWearablesUpdate()" << llendl;
- // MULTI-WEARABLE: update for multi-wearables after server-side support is in.
- for (S32 type=0; type < WT_COUNT; ++type)
- {
- gMessageSystem->nextBlockFast(_PREHASH_WearableData);
-
- U8 type_u8 = (U8)type;
- gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8);
-
- // MULTI-WEARABLE: TODO: hacked index to 0, needs to loop over all once messages support this.
- LLWearable* wearable = getWearable((EWearableType)type, 0);
- if (wearable)
- {
- //llinfos << "Sending wearable " << wearable->getName() << llendl;
- LLUUID item_id = wearable->getItemID();
- const LLViewerInventoryItem *item = gInventory.getItem(item_id);
- if (item && item->getIsLinkType())
- {
- // Get the itemID that this item points to. i.e. make sure
- // we are storing baseitems, not their links, in the database.
- item_id = item->getLinkedUUID();
- }
- gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id);
- }
- else
- {
- //llinfos << "Not wearing wearable type " << LLWearableDictionary::getInstance()->getWearable((EWearableType)i) << llendl;
- gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null);
- }
-
- lldebugs << " " << LLWearableDictionary::getTypeLabel((EWearableType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << llendl;
- }
- gAgent.sendReliableMessage();
-}
-
-void LLAgentWearables::saveWearable(const EWearableType type, const U32 index, BOOL send_update)
-{
- LLWearable* old_wearable = getWearable(type, index);
- if (old_wearable && (old_wearable->isDirty() || old_wearable->isOldVersion()))
+ LLViewerWearable* old_wearable = getViewerWearable(type, index);
+ if(!old_wearable) return;
+ bool name_changed = !new_name.empty() && (new_name != old_wearable->getName());
+ if (name_changed || old_wearable->isDirty() || old_wearable->isOldVersion())
{
LLUUID old_item_id = old_wearable->getItemID();
- LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable);
- new_wearable->setItemID(old_item_id); // should this be in LLWearable::copyDataFrom()?
+ LLViewerWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable);
+ new_wearable->setItemID(old_item_id); // should this be in LLViewerWearable::copyDataFrom()?
setWearable(type,index,new_wearable);
+ // old_wearable may still be referred to by other inventory items. Revert
+ // unsaved changes so other inventory items aren't affected by the changes
+ // that were just saved.
+ old_wearable->revertValues();
+
LLInventoryItem* item = gInventory.getItem(old_item_id);
if (item)
{
+ std::string item_name = item->getName();
+ if (name_changed)
+ {
+ LL_INFOS() << "saveWearable changing name from " << item->getName() << " to " << new_name << LL_ENDL;
+ item_name = new_name;
+ }
// Update existing inventory item
LLPointer<LLViewerInventoryItem> template_item =
new LLViewerInventoryItem(item->getUUID(),
@@ -354,27 +333,22 @@ void LLAgentWearables::saveWearable(const EWearableType type, const U32 index, B
new_wearable->getAssetID(),
new_wearable->getAssetType(),
item->getInventoryType(),
- item->getName(),
+ item_name,
item->getDescription(),
item->getSaleInfo(),
item->getFlags(),
item->getCreationDate());
template_item->setTransactionID(new_wearable->getTransactionID());
- template_item->updateServer(FALSE);
- gInventory.updateItem(template_item);
+ update_inventory_item(template_item, gAgentAvatarp->mEndCustomizeCallback);
}
else
{
// Add a new inventory item (shouldn't ever happen here)
- U32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
- if (send_update)
- {
- todo |= addWearableToAgentInventoryCallback::CALL_UPDATE;
- }
+ U32 todo = AddWearableToAgentInventoryCallback::CALL_NONE;
LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
+ new AddWearableToAgentInventoryCallback(
LLPointer<LLRefCount>(NULL),
- (S32)type,
+ type,
index,
new_wearable,
todo);
@@ -382,55 +356,54 @@ void LLAgentWearables::saveWearable(const EWearableType type, const U32 index, B
return;
}
- gAgent.getAvatarObject()->wearableUpdated( type );
-
- if (send_update)
- {
- sendAgentWearablesUpdate();
- }
+ gAgentAvatarp->wearableUpdated(type);
}
}
-void LLAgentWearables::saveWearableAs(const EWearableType type,
+void LLAgentWearables::saveWearableAs(const LLWearableType::EType type,
const U32 index,
const std::string& new_name,
+ const std::string& description,
BOOL save_in_lost_and_found)
{
if (!isWearableCopyable(type, index))
{
- llwarns << "LLAgent::saveWearableAs() not copyable." << llendl;
+ LL_WARNS() << "LLAgent::saveWearableAs() not copyable." << LL_ENDL;
return;
}
- LLWearable* old_wearable = getWearable(type, index);
+ LLViewerWearable* old_wearable = getViewerWearable(type, index);
if (!old_wearable)
{
- llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl;
+ LL_WARNS() << "LLAgent::saveWearableAs() no old wearable." << LL_ENDL;
return;
}
LLInventoryItem* item = gInventory.getItem(getWearableItemID(type,index));
if (!item)
{
- llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl;
+ LL_WARNS() << "LLAgent::saveWearableAs() no inventory item." << LL_ENDL;
return;
}
std::string trunc_name(new_name);
LLStringUtil::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN);
- LLWearable* new_wearable = LLWearableList::instance().createCopy(
+ LLViewerWearable* new_wearable = LLWearableList::instance().createCopy(
old_wearable,
trunc_name);
+
LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
+ new AddWearableToAgentInventoryCallback(
LLPointer<LLRefCount>(NULL),
type,
index,
new_wearable,
- addWearableToAgentInventoryCallback::CALL_UPDATE);
+ AddWearableToAgentInventoryCallback::CALL_WEARITEM,
+ description
+ );
LLUUID category_id;
if (save_in_lost_and_found)
{
category_id = gInventory.findCategoryUUIDForType(
- LLAssetType::AT_LOST_AND_FOUND);
+ LLFolderType::FT_LOST_AND_FOUND);
}
else
{
@@ -445,14 +418,21 @@ void LLAgentWearables::saveWearableAs(const EWearableType type,
category_id,
new_name,
cb);
+
+ // old_wearable may still be referred to by other inventory items. Revert
+ // unsaved changes so other inventory items aren't affected by the changes
+ // that were just saved.
+ old_wearable->revertValues();
}
-void LLAgentWearables::revertWearable(const EWearableType type, const U32 index)
+void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U32 index)
{
- LLWearable* wearable = getWearable(type, index);
- wearable->revertValues();
-
- gAgent.sendAgentSetAppearance();
+ LLViewerWearable* wearable = getViewerWearable(type, index);
+ llassert(wearable);
+ if (wearable)
+ {
+ wearable->revertValues();
+ }
}
void LLAgentWearables::saveAllWearables()
@@ -462,30 +442,30 @@ void LLAgentWearables::saveAllWearables()
// return;
//}
- for (S32 i=0; i < WT_COUNT; i++)
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
- for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
- saveWearable((EWearableType)i, j, FALSE);
+ for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
+ saveWearable((LLWearableType::EType)i, j);
}
- sendAgentWearablesUpdate();
}
// Called when the user changes the name of a wearable inventory item that is currently being worn.
void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string& new_name)
{
- for (S32 i=0; i < WT_COUNT; i++)
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
- for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
+ for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
{
- LLUUID curr_item_id = getWearableItemID((EWearableType)i,j);
+ LLUUID curr_item_id = getWearableItemID((LLWearableType::EType)i,j);
if (curr_item_id == item_id)
{
- LLWearable* old_wearable = getWearable((EWearableType)i,j);
+ LLViewerWearable* old_wearable = getViewerWearable((LLWearableType::EType)i,j);
llassert(old_wearable);
+ if (!old_wearable) continue;
std::string old_name = old_wearable->getName();
old_wearable->setName(new_name);
- LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable);
+ LLViewerWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable);
new_wearable->setItemID(item_id);
LLInventoryItem* item = gInventory.getItem(item_id);
if (item)
@@ -494,8 +474,7 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string&
}
old_wearable->setName(old_name);
- setWearable((EWearableType)i,j,new_wearable);
- sendAgentWearablesUpdate();
+ setWearable((LLWearableType::EType)i,j,new_wearable);
break;
}
}
@@ -503,12 +482,18 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string&
}
-BOOL LLAgentWearables::isWearableModifiable(EWearableType type, U32 index) const
+BOOL LLAgentWearables::isWearableModifiable(LLWearableType::EType type, U32 index) const
{
LLUUID item_id = getWearableItemID(type, index);
- if (!item_id.isNull())
+ return item_id.notNull() ? isWearableModifiable(item_id) : FALSE;
+}
+
+BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const
+{
+ const LLUUID& linked_id = gInventory.getLinkedItemID(item_id);
+ if (linked_id.notNull())
{
- LLInventoryItem* item = gInventory.getItem(item_id);
+ LLInventoryItem* item = gInventory.getItem(linked_id);
if (item && item->getPermissions().allowModifyBy(gAgent.getID(),
gAgent.getGroupID()))
{
@@ -518,7 +503,7 @@ BOOL LLAgentWearables::isWearableModifiable(EWearableType type, U32 index) const
return FALSE;
}
-BOOL LLAgentWearables::isWearableCopyable(EWearableType type, U32 index) const
+BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index) const
{
LLUUID item_id = getWearableItemID(type, index);
if (!item_id.isNull())
@@ -534,7 +519,7 @@ BOOL LLAgentWearables::isWearableCopyable(EWearableType type, U32 index) const
}
/*
- U32 LLAgentWearables::getWearablePermMask(EWearableType type)
+ U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type)
{
LLUUID item_id = getWearableItemID(type);
if (!item_id.isNull())
@@ -549,7 +534,7 @@ BOOL LLAgentWearables::isWearableCopyable(EWearableType type, U32 index) const
}
*/
-LLInventoryItem* LLAgentWearables::getWearableInventoryItem(EWearableType type, U32 index)
+LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::EType type, U32 index)
{
LLUUID item_id = getWearableItemID(type,index);
LLInventoryItem* item = NULL;
@@ -560,14 +545,15 @@ LLInventoryItem* LLAgentWearables::getWearableInventoryItem(EWearableType type,
return item;
}
-const LLWearable* LLAgentWearables::getWearableFromItemID(const LLUUID& item_id) const
+const LLViewerWearable* LLAgentWearables::getWearableFromItemID(const LLUUID& item_id) const
{
- for (S32 i=0; i < WT_COUNT; i++)
+ const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
- for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
+ for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
{
- const LLWearable * curr_wearable = getWearable((EWearableType)i, j);
- if (curr_wearable && (curr_wearable->getItemID() == item_id))
+ const LLViewerWearable * curr_wearable = getViewerWearable((LLWearableType::EType)i, j);
+ if (curr_wearable && (curr_wearable->getItemID() == base_item_id))
{
return curr_wearable;
}
@@ -576,14 +562,15 @@ const LLWearable* LLAgentWearables::getWearableFromItemID(const LLUUID& item_id)
return NULL;
}
-const LLWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_id) const
+LLViewerWearable* LLAgentWearables::getWearableFromItemID(const LLUUID& item_id)
{
- for (S32 i=0; i < WT_COUNT; i++)
+ const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id);
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
- for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
+ for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
{
- const LLWearable * curr_wearable = getWearable((EWearableType)i, j);
- if (curr_wearable && (curr_wearable->getAssetID() == asset_id))
+ LLViewerWearable * curr_wearable = getViewerWearable((LLWearableType::EType)i, j);
+ if (curr_wearable && (curr_wearable->getItemID() == base_item_id))
{
return curr_wearable;
}
@@ -592,696 +579,281 @@ const LLWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_i
return NULL;
}
-void LLAgentWearables::sendAgentWearablesRequest()
-{
- gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gAgent.sendReliableMessage();
-}
-
-// static
-BOOL LLAgentWearables::selfHasWearable(EWearableType type)
-{
- return (gAgentWearables.getWearableCount(type) > 0);
-}
-
-LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 index)
-{
- wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
- {
- return NULL;
- }
- wearableentry_vec_t& wearable_vec = wearable_iter->second;
- if (index>=wearable_vec.size())
- {
- return NULL;
- }
- else
- {
- return wearable_vec[index];
- }
-}
-
-void LLAgentWearables::setWearable(const EWearableType type, U32 index, LLWearable *wearable)
+LLViewerWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_id)
{
- if (!getWearable(type,index))
- {
- pushWearable(type,wearable);
- return;
- }
- wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
- {
- llwarns << "invalid type, type " << type << " index " << index << llendl;
- return;
- }
- wearableentry_vec_t& wearable_vec = wearable_iter->second;
- if (index>=wearable_vec.size())
- {
- llwarns << "invalid index, type " << type << " index " << index << llendl;
- }
- else
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
- wearable_vec[index] = wearable;
+ for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
+ {
+ LLViewerWearable * curr_wearable = getViewerWearable((LLWearableType::EType)i, j);
+ if (curr_wearable && (curr_wearable->getAssetID() == asset_id))
+ {
+ return curr_wearable;
+ }
+ }
}
+ return NULL;
}
-U32 LLAgentWearables::pushWearable(const EWearableType type, LLWearable *wearable)
+LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/)
{
- if (wearable == NULL)
- {
- // no null wearables please!
- //TODO: insert llwarns
- return MAX_ATTACHMENTS_PER_TYPE;
- }
- if (type < WT_COUNT)
- {
- mWearableDatas[type].push_back(wearable);
- return mWearableDatas[type].size()-1;
- }
- return MAX_ATTACHMENTS_PER_TYPE;
+ return dynamic_cast<LLViewerWearable*> (getWearable(type, index));
}
-void LLAgentWearables::popWearable(const EWearableType type, LLWearable *wearable)
+const LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/) const
{
- U32 index = getWearableIndex(type, wearable);
- if (index < MAX_ATTACHMENTS_PER_TYPE && index < getWearableCount(type))
- {
- popWearable(type, index);
- }
+ return dynamic_cast<const LLViewerWearable*> (getWearable(type, index));
}
-void LLAgentWearables::popWearable(const EWearableType type, U32 index)
+// static
+BOOL LLAgentWearables::selfHasWearable(LLWearableType::EType type)
{
- if (getWearable(type, index))
- {
- mWearableDatas[type].erase(mWearableDatas[type].begin() + index);
- }
+ return (gAgentWearables.getWearableCount(type) > 0);
}
-U32 LLAgentWearables::getWearableIndex(const EWearableType type, LLWearable *wearable)
+// virtual
+void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)
{
- wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
+ if (isAgentAvatarValid())
{
- llwarns << "tried to get wearable index with an invalid type!" << llendl;
- return MAX_ATTACHMENTS_PER_TYPE;
- }
- const wearableentry_vec_t& wearable_vec = wearable_iter->second;
- for(U32 index = 0; index < wearable_vec.size(); index++)
- {
- if (wearable_vec[index] == wearable)
- {
- return index;
- }
+ gAgentAvatarp->wearableUpdated(wearable->getType());
}
- return MAX_ATTACHMENTS_PER_TYPE;
-}
+ LLWearableData::wearableUpdated(wearable, removed);
-const LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 index) const
-{
- wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
- {
- return NULL;
- }
- const wearableentry_vec_t& wearable_vec = wearable_iter->second;
- if (index>=wearable_vec.size())
+ if (!removed)
{
- return NULL;
- }
- else
- {
- return wearable_vec[index];
- }
-}
+ LLViewerWearable* viewer_wearable = dynamic_cast<LLViewerWearable*>(wearable);
+ viewer_wearable->refreshName();
-LLWearable* LLAgentWearables::getTopWearable(const EWearableType type)
-{
- U32 count = getWearableCount(type);
- if ( count == 0)
- {
- return NULL;
- }
-
- return getWearable(type, count-1);
-}
+ // Hack pt 2. If the wearable we just loaded has definition version 24,
+ // then force a re-save of this wearable after slamming the version number to 22.
+ // This number was incorrectly incremented for internal builds before release, and
+ // this fix will ensure that the affected wearables are re-saved with the right version number.
+ // the versions themselves are compatible. This code can be removed before release.
+ if( wearable->getDefinitionVersion() == 24 )
+ {
+ U32 index;
+ if (getWearableIndex(wearable,index))
+ {
+ LL_INFOS() << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << LL_ENDL;
+ wearable->setDefinitionVersion(22);
+ saveWearable(wearable->getType(),index);
+ }
+ }
-U32 LLAgentWearables::getWearableCount(const EWearableType type) const
-{
- wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
- if (wearable_iter == mWearableDatas.end())
- {
- return 0;
+ checkWearableAgainstInventory(viewer_wearable);
}
- const wearableentry_vec_t& wearable_vec = wearable_iter->second;
- return wearable_vec.size();
-}
-
-U32 LLAgentWearables::getWearableCount(const U32 tex_index) const
-{
- const EWearableType wearable_type = LLVOAvatarDictionary::getTEWearableType((LLVOAvatarDefines::ETextureIndex)tex_index);
- return getWearableCount(wearable_type);
-}
-
-
-BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const
-{
- return mItemsAwaitingWearableUpdate.find(item_id) != mItemsAwaitingWearableUpdate.end();
}
-U32 LLAgentWearables::itemUpdatePendingCount() const
+const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const
{
- return mItemsAwaitingWearableUpdate.size();
-}
-
-const LLUUID LLAgentWearables::getWearableItemID(EWearableType type, U32 index) const
-{
- const LLWearable *wearable = getWearable(type,index);
+ const LLViewerWearable *wearable = getViewerWearable(type,index);
if (wearable)
return wearable->getItemID();
else
return LLUUID();
}
-const LLUUID LLAgentWearables::getWearableAssetID(EWearableType type, U32 index) const
+const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type, U32 index) const
{
- const LLWearable *wearable = getWearable(type,index);
+ const LLViewerWearable *wearable = getViewerWearable(type,index);
if (wearable)
return wearable->getAssetID();
else
return LLUUID();
}
-// Warning: include_linked_items = TRUE makes this operation expensive.
-BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id, BOOL include_linked_items) const
+BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const
{
- if (getWearableFromItemID(item_id) != NULL) return TRUE;
- if (include_linked_items)
- {
- LLInventoryModel::item_array_t item_array;
- gInventory.collectLinkedItems(item_id, item_array);
- for (LLInventoryModel::item_array_t::iterator iter = item_array.begin();
- iter != item_array.end();
- iter++)
- {
- LLViewerInventoryItem *linked_item = (*iter);
- const LLUUID &linked_item_id = linked_item->getUUID();
- if (getWearableFromItemID(linked_item_id) != NULL) return TRUE;
- }
- }
- return FALSE;
+ return getWearableFromItemID(item_id) != NULL;
}
-// MULTI-WEARABLE: update for multiple
-// static
-// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume
-// that viewers have a Current Outfit Folder and won't need this message, and thus
-// we can remove/ignore this whole function.
-void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data)
-{
- // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates
- // that may result from AgentWearablesRequest having been sent more than once.
- if (mInitialWearablesUpdateReceived)
- return;
- mInitialWearablesUpdateReceived = true;
-
- LLUUID agent_id;
- gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
-
- LLVOAvatar* avatar = gAgent.getAvatarObject();
- if (avatar && (agent_id == avatar->getID()))
+void LLAgentWearables::addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index)
+{
+ LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)wearable_type, wearable_index);
+ if (!wearable)
{
- gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum);
-
- S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData);
- if (num_wearables < 4)
- {
- // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin).
- // The fact that they don't have any here (only a dummy is sent) implies that this account existed
- // before we had wearables, or that the database has gotten messed up.
- return;
- }
-
- // Get the UUID of the current outfit folder (will be created if it doesn't exist)
- LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
-
- LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch();
-
- //lldebugs << "processAgentInitialWearablesUpdate()" << llendl;
- // Add wearables
- // MULTI-WEARABLE: TODO: update once messages change. Currently use results to populate the zeroth element.
- gAgentWearables.mItemsAwaitingWearableUpdate.clear();
- for (S32 i=0; i < num_wearables; i++)
- {
- // Parse initial wearables data from message system
- U8 type_u8 = 0;
- gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i);
- if (type_u8 >= WT_COUNT)
- {
- continue;
- }
- const EWearableType type = (EWearableType) type_u8;
-
- LLUUID item_id;
- gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i);
-
- LLUUID asset_id;
- gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i);
- if (asset_id.isNull())
- {
- LLWearable::removeFromAvatar(type, FALSE);
- }
- else
- {
- LLAssetType::EType asset_type = LLWearableDictionary::getAssetType(type);
- if (asset_type == LLAssetType::AT_NONE)
- {
- continue;
- }
-
- // MULTI-WEARABLE: TODO: update once messages change. Currently use results to populate the zeroth element.
-
- // Store initial wearables data until we know whether we have the current outfit folder or need to use the data.
- LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id); // MULTI-WEARABLE: update
- outfit->mAgentInitialWearables.push_back(wearable_data);
-
- }
-
- lldebugs << " " << LLWearableDictionary::getTypeLabel(type) << llendl;
- }
-
- // What we do here is get the complete information on the items in
- // the inventory, and set up an observer that will wait for that to
- // happen.
- LLInventoryFetchDescendentsObserver::folder_ref_t folders;
- folders.push_back(current_outfit_id);
- outfit->fetchDescendents(folders);
- if(outfit->isEverythingComplete())
- {
- // everything is already here - call done.
- outfit->done();
- }
- else
- {
- // it's all on it's way - add an observer, and the inventory
- // will call done for us when everything is here.
- gInventory.addObserver(outfit);
- }
+ LL_ERRS() << "Tried to add local texture object to invalid wearable with type " << wearable_type << " and index " << wearable_index << LL_ENDL;
+ return;
}
+ LLLocalTextureObject lto;
+ wearable->setLocalTextureObject(texture_type, lto);
}
-// A single wearable that the avatar was wearing on start-up has arrived from the database.
-// static
-void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* userdata)
+class OnWearableItemCreatedCB: public LLInventoryCallback
{
- boost::scoped_ptr<LLInitialWearablesFetch::InitialWearableData> wear_data((LLInitialWearablesFetch::InitialWearableData*)userdata);
- const EWearableType type = wear_data->mType;
- U32 index = 0;
-
- LLVOAvatarSelf* avatar = gAgent.getAvatarObject();
- if (!avatar)
+public:
+ OnWearableItemCreatedCB():
+ mWearablesAwaitingItems(LLWearableType::WT_COUNT,NULL)
{
- return;
+ LL_INFOS() << "created callback" << LL_ENDL;
}
-
- if (wearable)
+ /* virtual */ void fire(const LLUUID& inv_item)
{
- llassert(type == wearable->getType());
- wearable->setItemID(wear_data->mItemID);
- index = gAgentWearables.pushWearable(type, wearable);
- gAgentWearables.mItemsAwaitingWearableUpdate.erase(wear_data->mItemID);
-
- // disable composites if initial textures are baked
- avatar->setupComposites();
-
- avatar->setCompositeUpdatesEnabled(TRUE);
- gInventory.addChangedMask(LLInventoryObserver::LABEL, wearable->getItemID());
+ LL_INFOS() << "One item created " << inv_item.asString() << LL_ENDL;
+ LLConstPointer<LLInventoryObject> item = gInventory.getItem(inv_item);
+ mItemsToLink.push_back(item);
+ updatePendingWearable(inv_item);
}
- else
+ ~OnWearableItemCreatedCB()
{
- // Somehow the asset doesn't exist in the database.
- gAgentWearables.recoverMissingWearable(type,index);
+ LL_INFOS() << "All items created" << LL_ENDL;
+ LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
+ link_inventory_array(LLAppearanceMgr::instance().getCOF(),
+ mItemsToLink,
+ link_waiter);
}
-
- gInventory.notifyObservers();
-
- // Have all the wearables that the avatar was wearing at log-in arrived?
- // MULTI-WEARABLE: update when multiple wearables can arrive per type.
-
- gAgentWearables.updateWearablesLoaded();
- if (gAgentWearables.areWearablesLoaded())
+ void addPendingWearable(LLViewerWearable *wearable)
{
-
- // Can't query cache until all wearables have arrived, so calling this earlier is a no-op.
- gAgentWearables.queryWearableCache();
-
- // Make sure that the server's idea of the avatar's wearables actually match the wearables.
- gAgent.sendAgentSetAppearance();
-
- // Check to see if there are any baked textures that we hadn't uploaded before we logged off last time.
- // If there are any, schedule them to be uploaded as soon as the layer textures they depend on arrive.
- if (gAgent.cameraCustomizeAvatar())
+ if (!wearable)
{
- avatar->requestLayerSetUploads();
+ LL_WARNS() << "no wearable" << LL_ENDL;
+ return;
+ }
+ LLWearableType::EType type = wearable->getType();
+ if (type<LLWearableType::WT_COUNT)
+ {
+ mWearablesAwaitingItems[type] = wearable;
+ }
+ else
+ {
+ LL_WARNS() << "invalid type " << type << LL_ENDL;
}
}
-}
-
-// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the
-// database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that
-// the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.)
-void LLAgentWearables::recoverMissingWearable(const EWearableType type, U32 index)
-{
- // Try to recover by replacing missing wearable with a new one.
- LLNotifications::instance().add("ReplacedMissingWearable");
- lldebugs << "Wearable " << LLWearableDictionary::getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << llendl;
- LLWearable* new_wearable = LLWearableList::instance().createNewWearable(type);
-
- S32 type_s32 = (S32) type;
- setWearable(type,index,new_wearable);
- //new_wearable->writeToAvatar(TRUE);
-
- // Add a new one in the lost and found folder.
- // (We used to overwrite the "not found" one, but that could potentially
- // destory content.) JC
- LLUUID lost_and_found_id =
- gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
- LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
- LLPointer<LLRefCount>(NULL),
- type_s32,
- index,
- new_wearable,
- addWearableToAgentInventoryCallback::CALL_RECOVERDONE);
- addWearableToAgentInventory(cb, new_wearable, lost_and_found_id, TRUE);
-}
-
-void LLAgentWearables::recoverMissingWearableDone()
-{
- // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated?
- updateWearablesLoaded();
- if (areWearablesLoaded())
- {
- // Make sure that the server's idea of the avatar's wearables actually match the wearables.
- gAgent.sendAgentSetAppearance();
- }
- else
- {
- gInventory.addChangedMask(LLInventoryObserver::LABEL, LLUUID::null);
- gInventory.notifyObservers();
- }
-}
-
-void LLAgentWearables::addLocalTextureObject(const EWearableType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index)
-{
- LLWearable* wearable = getWearable((EWearableType)wearable_type, wearable_index);
- if (!wearable)
- {
- llerrs << "Tried to add local texture object to invalid wearable with type " << wearable_type << " and index " << wearable_index << llendl;
- }
- LLLocalTextureObject* lto = new LLLocalTextureObject();
- wearable->setLocalTextureObject(texture_type, lto);
-}
-
-void LLAgentWearables::createStandardWearables(BOOL female)
-{
- llwarns << "Creating Standard " << (female ? "female" : "male")
- << " Wearables" << llendl;
-
- if (mAvatarObject.isNull())
+ void updatePendingWearable(const LLUUID& inv_item)
{
- return;
- }
-
- mAvatarObject->setSex(female ? SEX_FEMALE : SEX_MALE);
-
- const BOOL create[WT_COUNT] =
+ LLViewerInventoryItem *item = gInventory.getItem(inv_item);
+ if (!item)
{
- TRUE, //WT_SHAPE
- TRUE, //WT_SKIN
- TRUE, //WT_HAIR
- TRUE, //WT_EYES
- TRUE, //WT_SHIRT
- TRUE, //WT_PANTS
- TRUE, //WT_SHOES
- TRUE, //WT_SOCKS
- FALSE, //WT_JACKET
- FALSE, //WT_GLOVES
- TRUE, //WT_UNDERSHIRT
- TRUE, //WT_UNDERPANTS
- FALSE //WT_SKIRT
- };
-
- for (S32 i=0; i < WT_COUNT; i++)
- {
- bool once = false;
- LLPointer<LLRefCount> donecb = NULL;
- if (create[i])
+ LL_WARNS() << "no item found" << LL_ENDL;
+ return;
+ }
+ if (!item->isWearableType())
{
- if (!once)
+ LL_WARNS() << "non-wearable item found" << LL_ENDL;
+ return;
+ }
+ if (item && item->isWearableType())
+ {
+ LLWearableType::EType type = item->getWearableType();
+ if (type < LLWearableType::WT_COUNT)
{
- once = true;
- donecb = new createStandardWearablesAllDoneCallback;
+ LLViewerWearable *wearable = mWearablesAwaitingItems[type];
+ if (wearable)
+ wearable->setItemID(inv_item);
+ }
+ else
+ {
+ LL_WARNS() << "invalid wearable type " << type << LL_ENDL;
}
- llassert(getWearableCount((EWearableType)i) == 0);
- LLWearable* wearable = LLWearableList::instance().createNewWearable((EWearableType)i);
- U32 index = pushWearable((EWearableType)i,wearable);
- // no need to update here...
- LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
- donecb,
- i,
- index,
- wearable,
- addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE);
- addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE);
}
}
-}
+
+private:
+ LLInventoryObject::const_object_list_t mItemsToLink;
+ std::vector<LLViewerWearable*> mWearablesAwaitingItems;
+};
-void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index)
+void LLAgentWearables::createStandardWearables()
{
- if (mAvatarObject)
- {
- mAvatarObject->updateVisualParams();
- }
-}
+ LL_WARNS() << "Creating standard wearables" << LL_ENDL;
-void LLAgentWearables::createStandardWearablesAllDone()
-{
- // ... because sendAgentWearablesUpdate will notify inventory
- // observers.
- mWearablesLoaded = TRUE;
- checkWearablesLoaded();
-
- updateServer();
+ if (!isAgentAvatarValid()) return;
- // Treat this as the first texture entry message, if none received yet
- mAvatarObject->onFirstTEMessageReceived();
-}
+ const BOOL create[LLWearableType::WT_COUNT] =
+ {
+ TRUE, //LLWearableType::WT_SHAPE
+ TRUE, //LLWearableType::WT_SKIN
+ TRUE, //LLWearableType::WT_HAIR
+ TRUE, //LLWearableType::WT_EYES
+ TRUE, //LLWearableType::WT_SHIRT
+ TRUE, //LLWearableType::WT_PANTS
+ TRUE, //LLWearableType::WT_SHOES
+ TRUE, //LLWearableType::WT_SOCKS
+ FALSE, //LLWearableType::WT_JACKET
+ FALSE, //LLWearableType::WT_GLOVES
+ TRUE, //LLWearableType::WT_UNDERSHIRT
+ TRUE, //LLWearableType::WT_UNDERPANTS
+ FALSE //LLWearableType::WT_SKIRT
+ };
-// MULTI-WEARABLE: Properly handle multiwearables later.
-void LLAgentWearables::getAllWearablesArray(LLDynamicArray<S32>& wearables)
-{
- for( S32 i = 0; i < WT_COUNT; ++i )
+ LLPointer<LLInventoryCallback> cb = new OnWearableItemCreatedCB;
+ for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
- if (getWearableCount( (EWearableType) i) != 0 )
+ if (create[i])
{
- wearables.push_back(i);
+ llassert(getWearableCount((LLWearableType::EType)i) == 0);
+ LLViewerWearable* wearable = LLWearableList::instance().createNewWearable((LLWearableType::EType)i, gAgentAvatarp);
+ ((OnWearableItemCreatedCB*)(&(*cb)))->addPendingWearable(wearable);
+ // no need to update here...
+ LLUUID category_id = LLUUID::null;
+ create_inventory_item(gAgent.getID(),
+ gAgent.getSessionID(),
+ category_id,
+ wearable->getTransactionID(),
+ wearable->getName(),
+ wearable->getDescription(),
+ wearable->getAssetType(),
+ LLInventoryType::IT_WEARABLE,
+ wearable->getType(),
+ wearable->getPermissions().getMaskNextOwner(),
+ cb);
}
}
}
-// Note: wearables_to_include should be a list of EWearableType types
-// attachments_to_include should be a list of attachment points
-void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name,
- const LLDynamicArray<S32>& wearables_to_include,
- const LLDynamicArray<S32>& attachments_to_include,
- BOOL rename_clothing)
+// We no longer need this message in the current viewer, but send
+// it for now to maintain compatibility with release viewers. Can
+// remove this function once the SH-3455 changesets are universally deployed.
+void LLAgentWearables::sendDummyAgentWearablesUpdate()
{
- if (mAvatarObject.isNull())
- {
- return;
- }
-
- // First, make a folder in the Clothes directory.
- LLUUID folder_id = gInventory.createNewCategory(
- gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING),
- LLAssetType::AT_NONE,
- new_folder_name);
-
- bool found_first_item = false;
+ LL_DEBUGS("Avatar") << "sendAgentWearablesUpdate()" << LL_ENDL;
- ///////////////////
- // Wearables
-
- if (wearables_to_include.count())
- {
- // Then, iterate though each of the wearables and save copies of them in the folder.
- S32 i;
- S32 count = wearables_to_include.count();
- LLDynamicArray<LLUUID> delete_items;
- LLPointer<LLRefCount> cbdone = NULL;
- for (i = 0; i < count; ++i)
- {
- const S32 type = wearables_to_include[i];
- for (U32 j=0; j<getWearableCount((EWearableType)i); j++)
- {
- LLWearable* old_wearable = getWearable((EWearableType)type, j);
- if (old_wearable)
- {
- std::string new_name;
- LLWearable* new_wearable;
- new_wearable = LLWearableList::instance().createCopy(old_wearable);
- if (rename_clothing)
- {
- new_name = new_folder_name;
- new_name.append(" ");
- new_name.append(old_wearable->getTypeLabel());
- LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
- new_wearable->setName(new_name);
- }
-
- LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((EWearableType)type,j));
- S32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
- if (!found_first_item)
- {
- found_first_item = true;
- /* set the focus to the first item */
- todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE;
- /* send the agent wearables update when done */
- cbdone = new sendAgentWearablesUpdateCallback;
- }
- LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
- cbdone,
- type,
- j,
- new_wearable,
- todo);
- if (isWearableCopyable((EWearableType)type, j))
- {
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- folder_id,
- new_name,
- cb);
- }
- else
- {
- move_inventory_item(
- gAgent.getID(),
- gAgent.getSessionID(),
- item->getUUID(),
- folder_id,
- new_name,
- cb);
- }
- }
- }
- }
- gInventory.notifyObservers();
- }
-
-
- ///////////////////
- // Attachments
-
- if (attachments_to_include.count())
- {
- BOOL msg_started = FALSE;
- LLMessageSystem* msg = gMessageSystem;
- for (S32 i = 0; i < attachments_to_include.count(); i++)
- {
- S32 attachment_pt = attachments_to_include[i];
- LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL);
- if (!attachment) continue;
- 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) 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());
- }
- }
-
- if (msg_started)
- {
- gAgent.sendReliableMessage();
- }
+ // Send the AgentIsNowWearing
+ gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing);
+
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- }
-}
+ // Send 4 standardized nonsense item ids (same as returned by the modified sim, not that it especially matters).
+ gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+ gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(1));
+ gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("db5a4e5f-9da3-44c8-992d-1181c5795498"));
-LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name)
-{
- if (mAvatarObject.isNull())
- {
- return LLUUID::null;
- }
+ gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+ gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(2));
+ gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("6969c7cc-f72f-4a76-a19b-c293cce8ce4f"));
- // First, make a folder in the My Outfits directory.
- LLUUID parent_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_MY_OUTFITS);
- LLUUID folder_id = gInventory.createNewCategory(
- parent_id,
- LLAssetType::AT_OUTFIT,
- new_folder_name);
+ gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+ gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(3));
+ gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("7999702b-b291-48f9-8903-c91dfb828408"));
- LLAppearanceManager::shallowCopyCategory(LLAppearanceManager::getCOF(),folder_id, NULL);
-
-#if 0 // BAP - fix to go into rename state automatically after outfit is created.
- LLViewerInventoryCategory *parent_category = gInventory.getCategory(parent_id);
- if (parent_category)
- {
- parent_category->setSelectionByID(folder_id,TRUE);
- parent_category->setNeedsAutoRename(TRUE);
- }
-#endif
+ gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+ gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(4));
+ gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("566cb59e-ef60-41d7-bfa6-e0f293fbea40"));
- return folder_id;
+ gAgent.sendReliableMessage();
}
void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index)
{
- LLUUID first_item_id = getWearableItemID((EWearableType)type, index);
+ LLUUID first_item_id = getWearableItemID((LLWearableType::EType)type, index);
// Open the inventory and select the first item we added.
if (first_item_id.notNull())
{
- LLFloaterInventory* view = LLFloaterInventory::getActiveInventory();
- if (view)
+ LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
+ if (active_panel)
{
- view->getPanel()->setSelection(first_item_id, TAKE_FOCUS_NO);
+ active_panel->setSelection(first_item_id, TAKE_FOCUS_NO);
}
}
}
void LLAgentWearables::addWearableToAgentInventory(LLPointer<LLInventoryCallback> cb,
- LLWearable* wearable,
+ LLViewerWearable* wearable,
const LLUUID& category_id,
BOOL notify)
{
@@ -1298,15 +870,20 @@ void LLAgentWearables::addWearableToAgentInventory(LLPointer<LLInventoryCallback
cb);
}
-void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_all, U32 index)
+void LLAgentWearables::removeWearable(const LLWearableType::EType type, bool do_remove_all, U32 index)
{
- if ((gAgent.isTeen())
- && (type == WT_UNDERSHIRT || type == WT_UNDERPANTS))
+ if (gAgent.isTeen() &&
+ (type == LLWearableType::WT_UNDERSHIRT || type == LLWearableType::WT_UNDERPANTS))
{
// Can't take off underclothing in simple UI mode or on PG accounts
// TODO: enable the removing of a single undershirt/underpants if multiple are worn. - Nyx
return;
}
+ if (getWearableCount(type) == 0)
+ {
+ // no wearables to remove
+ return;
+ }
if (do_remove_all)
{
@@ -1314,7 +891,7 @@ void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_a
}
else
{
- LLWearable* old_wearable = getWearable(type,index);
+ LLViewerWearable* old_wearable = getViewerWearable(type,index);
if (old_wearable)
{
@@ -1322,8 +899,9 @@ void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_a
{
LLSD payload;
payload["wearable_type"] = (S32)type;
+ payload["wearable_index"] = (S32)index;
// Bring up view-modal dialog: Save changes? Yes, No, Cancel
- LLNotifications::instance().add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog);
+ LLNotificationsUtil::add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog);
return;
}
else
@@ -1335,22 +913,21 @@ void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_a
}
-// MULTI_WEARABLE: assuming one wearable per type.
-// MULTI_WEARABLE: hardwiring 0th elt for now - notification needs to change.
// static
bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LLSD& response)
{
- S32 option = LLNotification::getSelectedOption(notification, response);
- EWearableType type = (EWearableType)notification["payload"]["wearable_type"].asInteger();
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ LLWearableType::EType type = (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger();
+ S32 index = (S32)notification["payload"]["wearable_index"].asInteger();
switch(option)
{
case 0: // "Save"
- gAgentWearables.saveWearable(type, 0);
- gAgentWearables.removeWearableFinal(type, false, 0);
+ gAgentWearables.saveWearable(type, index);
+ gAgentWearables.removeWearableFinal(type, false, index);
break;
case 1: // "Don't Save"
- gAgentWearables.removeWearableFinal(type, false, 0);
+ gAgentWearables.removeWearableFinal(type, false, index);
break;
case 2: // "Cancel"
@@ -1364,182 +941,209 @@ bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LL
}
// Called by removeWearable() and onRemoveWearableDialog() to actually do the removal.
-void LLAgentWearables::removeWearableFinal(const EWearableType type, bool do_remove_all, U32 index)
+void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, bool do_remove_all, U32 index)
{
//LLAgentDumper dumper("removeWearable");
if (do_remove_all)
{
- S32 max_entry = mWearableDatas[type].size()-1;
+ S32 max_entry = getWearableCount(type)-1;
for (S32 i=max_entry; i>=0; i--)
{
- LLWearable* old_wearable = getWearable(type,i);
- gInventory.addChangedMask(LLInventoryObserver::LABEL, getWearableItemID(type,i));
- popWearable(type,i);
-
- //queryWearableCache(); // moved below
+ LLViewerWearable* old_wearable = getViewerWearable(type,i);
if (old_wearable)
{
- old_wearable->removeFromAvatar(TRUE);
+ eraseWearable(old_wearable);
+ old_wearable->removeFromAvatar();
}
}
- mWearableDatas[type].clear();
+ clearWearableType(type);
}
else
{
- LLWearable* old_wearable = getWearable(type, index);
-
- gInventory.addChangedMask(LLInventoryObserver::LABEL, getWearableItemID(type,index));
- popWearable(type, index);
-
- //queryWearableCache(); // moved below
+ LLViewerWearable* old_wearable = getViewerWearable(type, index);
if (old_wearable)
{
- old_wearable->removeFromAvatar(TRUE);
+ eraseWearable(old_wearable);
+ old_wearable->removeFromAvatar();
}
}
- queryWearableCache();
-
- // Update the server
- updateServer();
gInventory.notifyObservers();
}
// Assumes existing wearables are not dirty.
-// MULTI_WEARABLE: assumes one wearable per type.
void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& items,
- const LLDynamicArray< LLWearable* >& wearables,
- BOOL remove)
-{
- lldebugs << "setWearableOutfit() start" << llendl;
-
- BOOL wearables_to_remove[WT_COUNT];
- wearables_to_remove[WT_SHAPE] = FALSE;
- wearables_to_remove[WT_SKIN] = FALSE;
- wearables_to_remove[WT_HAIR] = FALSE;
- wearables_to_remove[WT_EYES] = FALSE;
- wearables_to_remove[WT_SHIRT] = remove;
- wearables_to_remove[WT_PANTS] = remove;
- wearables_to_remove[WT_SHOES] = remove;
- wearables_to_remove[WT_SOCKS] = remove;
- wearables_to_remove[WT_JACKET] = remove;
- wearables_to_remove[WT_GLOVES] = remove;
- wearables_to_remove[WT_UNDERSHIRT] = (!gAgent.isTeen()) & remove;
- wearables_to_remove[WT_UNDERPANTS] = (!gAgent.isTeen()) & remove;
- wearables_to_remove[WT_SKIRT] = remove;
-
- S32 count = wearables.count();
- llassert(items.count() == count);
-
- S32 i;
- for (i = 0; i < count; i++)
- {
- LLWearable* new_wearable = wearables[i];
- LLPointer<LLInventoryItem> new_item = items[i];
+ const std::vector< LLViewerWearable* >& wearables)
+{
+ LL_INFOS() << "setWearableOutfit() start" << LL_ENDL;
- const EWearableType type = new_wearable->getType();
- wearables_to_remove[type] = FALSE;
+ S32 count = wearables.size();
+ llassert(items.size() == count);
- // MULTI_WEARABLE: using 0th
- LLWearable* old_wearable = getWearable(type, 0);
- if (old_wearable)
- {
- const LLUUID& old_item_id = getWearableItemID(type, 0);
- if ((old_wearable->getAssetID() == new_wearable->getAssetID()) &&
- (old_item_id == new_item->getUUID()))
- {
- lldebugs << "No change to wearable asset and item: " << LLWearableDictionary::getInstance()->getWearableEntry(type) << llendl;
- continue;
- }
+ // Check for whether outfit already matches the one requested
+ S32 matched = 0, mismatched = 0;
+ const S32 arr_size = LLWearableType::WT_COUNT;
+ S32 type_counts[arr_size];
+ std::fill(type_counts,type_counts+arr_size,0);
+ for (S32 i = 0; i < count; i++)
+ {
+ LLViewerWearable* new_wearable = wearables[i];
+ LLPointer<LLInventoryItem> new_item = items[i];
- gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
+ const LLWearableType::EType type = new_wearable->getType();
+ if (type < 0 || type>=LLWearableType::WT_COUNT)
+ {
+ LL_WARNS() << "invalid type " << type << LL_ENDL;
+ mismatched++;
+ continue;
+ }
+ S32 index = type_counts[type];
+ type_counts[type]++;
- // Assumes existing wearables are not dirty.
- if (old_wearable->isDirty())
- {
- llassert(0);
- continue;
- }
+ LLViewerWearable *curr_wearable = dynamic_cast<LLViewerWearable*>(getWearable(type,index));
+ if (!new_wearable || !curr_wearable ||
+ new_wearable->getAssetID() != curr_wearable->getAssetID())
+ {
+ LL_DEBUGS("Avatar") << "mismatch, type " << type << " index " << index
+ << " names " << (curr_wearable ? curr_wearable->getName() : "NONE") << ","
+ << " names " << (new_wearable ? new_wearable->getName() : "NONE") << LL_ENDL;
+ mismatched++;
+ continue;
}
- setWearable(type,0,new_wearable);
- if (new_wearable)
- new_wearable->setItemID(new_item->getUUID());
+ // Don't care about this case - ordering of wearables with the same asset id has no effect.
+ // Causes the two-alphas error case in MAINT-4158.
+ // We should actually disallow wearing two wearables with the same asset id.
+#if 0
+ if (curr_wearable->getName() != new_item->getName() ||
+ curr_wearable->getItemID() != new_item->getUUID())
+ {
+ LL_DEBUGS("Avatar") << "mismatch on name or inventory id, names "
+ << curr_wearable->getName() << " vs " << new_item->getName()
+ << " item ids " << curr_wearable->getItemID() << " vs " << new_item->getUUID()
+ << LL_ENDL;
+ mismatched++;
+ continue;
+ }
+#endif
+ // If we got here, everything matches.
+ matched++;
+ }
+ LL_DEBUGS("Avatar") << "matched " << matched << " mismatched " << mismatched << LL_ENDL;
+ for (S32 j=0; j<LLWearableType::WT_COUNT; j++)
+ {
+ LLWearableType::EType type = (LLWearableType::EType) j;
+ if (getWearableCount(type) != type_counts[j])
+ {
+ LL_DEBUGS("Avatar") << "count mismatch for type " << j << " current " << getWearableCount(j) << " requested " << type_counts[j] << LL_ENDL;
+ mismatched++;
+ }
+ }
+ if (mismatched == 0)
+ {
+ LL_DEBUGS("Avatar") << "no changes, bailing out" << LL_ENDL;
+ mCOFChangeInProgress = false;
+ return;
+ }
+
+
+ // TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later
+ // note: shirt is the first non-body part wearable item. Update if wearable order changes.
+ // This loop should remove all clothing, but not any body parts
+ for (S32 j = 0; j < (S32)LLWearableType::WT_COUNT; j++)
+ {
+ if (LLWearableType::getAssetType((LLWearableType::EType)j) == LLAssetType::AT_CLOTHING)
+ {
+ removeWearable((LLWearableType::EType)j, true, 0);
+ }
}
- std::vector<LLWearable*> wearables_being_removed;
-
- for (i = 0; i < WT_COUNT; i++)
+ for (S32 i = 0; i < count; i++)
{
- if (wearables_to_remove[i])
+ LLViewerWearable* new_wearable = wearables[i];
+ LLPointer<LLInventoryItem> new_item = items[i];
+
+ llassert(new_wearable);
+ if (new_wearable)
{
- // MULTI_WEARABLE: assuming 0th
- LLWearable* wearable = getWearable((EWearableType)i, 0);
- gInventory.addChangedMask(LLInventoryObserver::LABEL, getWearableItemID((EWearableType)i,0));
- if (wearable)
+ const LLWearableType::EType type = new_wearable->getType();
+
+ new_wearable->setName(new_item->getName());
+ new_wearable->setItemID(new_item->getUUID());
+
+ if (LLWearableType::getAssetType(type) == LLAssetType::AT_BODYPART)
+ {
+ // exactly one wearable per body part
+ setWearable(type,0,new_wearable);
+ }
+ else
{
- wearables_being_removed.push_back(wearable);
+ pushWearable(type,new_wearable);
}
- removeWearable((EWearableType)i,true,0);
+ const BOOL removed = FALSE;
+ wearableUpdated(new_wearable, removed);
}
}
gInventory.notifyObservers();
- queryWearableCache();
-
- std::vector<LLWearable*>::iterator wearable_iter;
-
- for (wearable_iter = wearables_being_removed.begin();
- wearable_iter != wearables_being_removed.end();
- ++wearable_iter)
+ if (isAgentAvatarValid())
{
- LLWearable* wearablep = *wearable_iter;
- if (wearablep)
+ gAgentAvatarp->setCompositeUpdatesEnabled(TRUE);
+
+ // If we have not yet declouded, we may want to use
+ // baked texture UUIDs sent from the first objectUpdate message
+ // don't overwrite these. If we have already declouded, we've saved
+ // these ids as the last known good textures and can invalidate without
+ // re-clouding.
+ if (!gAgentAvatarp->getIsCloud())
{
- wearablep->removeFromAvatar(TRUE);
+ gAgentAvatarp->invalidateAll();
}
}
- if (mAvatarObject)
- {
- mAvatarObject->updateVisualParams();
- }
-
// Start rendering & update the server
mWearablesLoaded = TRUE;
- checkWearablesLoaded();
- updateServer();
- lldebugs << "setWearableOutfit() end" << llendl;
+ notifyLoadingFinished();
+
+ // Copy wearable params to avatar.
+ gAgentAvatarp->writeWearablesToAvatar();
+
+ // Then update the avatar based on the copied params.
+ gAgentAvatarp->updateVisualParams();
+
+ gAgentAvatarp->dumpAvatarTEs("setWearableOutfit");
+
+ LL_DEBUGS("Avatar") << "setWearableOutfit() end" << LL_ENDL;
}
// User has picked "wear on avatar" from a menu.
-void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append)
+void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append)
{
//LLAgentDumper dumper("setWearableItem");
if (isWearingItem(new_item->getUUID()))
{
- llwarns << "wearable " << new_item->getUUID() << " is already worn" << llendl;
+ LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL;
return;
}
- const EWearableType type = new_wearable->getType();
+ const LLWearableType::EType type = new_wearable->getType();
if (!do_append)
{
// Remove old wearable, if any
// MULTI_WEARABLE: hardwired to 0
- LLWearable* old_wearable = getWearable(type,0);
+ LLViewerWearable* old_wearable = getViewerWearable(type,0);
if (old_wearable)
{
const LLUUID& old_item_id = old_wearable->getItemID();
if ((old_wearable->getAssetID() == new_wearable->getAssetID()) &&
(old_item_id == new_item->getUUID()))
{
- lldebugs << "No change to wearable asset and item: " << LLWearableDictionary::getInstance()->getWearableEntry(type) << llendl;
+ LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL;
return;
}
@@ -1548,7 +1152,7 @@ void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* ne
// Bring up modal dialog: Save changes? Yes, No, Cancel
LLSD payload;
payload["item_id"] = new_item->getUUID();
- LLNotifications::instance().add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable));
+ LLNotificationsUtil::add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable));
return;
}
}
@@ -1558,10 +1162,17 @@ void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* ne
}
// static
-bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLWearable* wearable)
+bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable)
{
- S32 option = LLNotification::getSelectedOption(notification, response);
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID());
+ U32 index;
+ if (!gAgentWearables.getWearableIndex(wearable,index))
+ {
+ LL_WARNS() << "Wearable not found" << LL_ENDL;
+ delete wearable;
+ return false;
+ }
if (!new_item)
{
delete wearable;
@@ -1571,8 +1182,7 @@ bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD&
switch(option)
{
case 0: // "Save"
-// MULTI_WEARABLE: assuming 0th
- gAgentWearables.saveWearable(wearable->getType(),0);
+ gAgentWearables.saveWearable(wearable->getType(),index);
gAgentWearables.setWearableFinal(new_item, wearable);
break;
@@ -1594,23 +1204,25 @@ bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD&
// Called from setWearableItem() and onSetWearableDialog() to actually set the wearable.
// MULTI_WEARABLE: unify code after null objects are gone.
-void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append)
+void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append)
{
- const EWearableType type = new_wearable->getType();
+ const LLWearableType::EType type = new_wearable->getType();
if (do_append && getWearableItemID(type,0).notNull())
{
new_wearable->setItemID(new_item->getUUID());
- mWearableDatas[type].push_back(new_wearable);
- llinfos << "Added additional wearable for type " << type
- << " size is now " << mWearableDatas[type].size() << llendl;
+ const bool trigger_updated = false;
+ pushWearable(type, new_wearable, trigger_updated);
+ LL_INFOS() << "Added additional wearable for type " << type
+ << " size is now " << getWearableCount(type) << LL_ENDL;
+ checkWearableAgainstInventory(new_wearable);
}
else
{
// Replace the old wearable with a new one.
llassert(new_item->getAssetUUID() == new_wearable->getAssetID());
- LLWearable *old_wearable = getWearable(type,0);
+ LLViewerWearable *old_wearable = getViewerWearable(type,0);
LLUUID old_item_id;
if (old_wearable)
{
@@ -1624,150 +1236,58 @@ void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLWearable* n
gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
gInventory.notifyObservers();
}
- llinfos << "Replaced current element 0 for type " << type
- << " size is now " << mWearableDatas[type].size() << llendl;
+ LL_INFOS() << "Replaced current element 0 for type " << type
+ << " size is now " << getWearableCount(type) << LL_ENDL;
}
-
- //llinfos << "LLVOAvatar::setWearableItem()" << llendl;
- queryWearableCache();
- //new_wearable->writeToAvatar(TRUE);
-
- updateServer();
}
-void LLAgentWearables::queryWearableCache()
-{
- if (!areWearablesLoaded())
- {
- return;
- }
-
- // Look up affected baked textures.
- // If they exist:
- // disallow updates for affected layersets (until dataserver responds with cache request.)
- // If cache miss, turn updates back on and invalidate composite.
- // If cache hit, modify baked texture entries.
- //
- // Cache requests contain list of hashes for each baked texture entry.
- // Response is list of valid baked texture assets. (same message)
-
- gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->addS32Fast(_PREHASH_SerialNum, gAgentQueryManager.mWearablesCacheQueryID);
-
- S32 num_queries = 0;
- for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
- {
- const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
- LLUUID hash;
- for (U8 i=0; i < baked_dict->mWearables.size(); i++)
- {
- const EWearableType baked_type = baked_dict->mWearables[i];
- // MULTI_WEARABLE: not order-dependent
- const U32 num_wearables = getWearableCount(baked_type);
- for (U32 index = 0; index < num_wearables; ++index)
- {
- const LLWearable* wearable = getWearable(baked_type,index);
- if (wearable)
- {
- hash ^= wearable->getAssetID();
- }
- }
- }
- if (hash.notNull())
- {
- hash ^= baked_dict->mWearablesHashID;
- num_queries++;
- // *NOTE: make sure at least one request gets packed
-
- //llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl;
- gMessageSystem->nextBlockFast(_PREHASH_WearableData);
- gMessageSystem->addUUIDFast(_PREHASH_ID, hash);
- gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_index);
- }
-
- gAgentQueryManager.mActiveCacheQueries[baked_index] = gAgentQueryManager.mWearablesCacheQueryID;
- }
-
- llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl;
- gMessageSystem->sendReliable(gAgent.getRegion()->getHost());
- gAgentQueryManager.mNumPendingQueries++;
- gAgentQueryManager.mWearablesCacheQueryID++;
-}
-
-// MULTI_WEARABLE: need a way to specify by wearable rather than by type.
// User has picked "remove from avatar" from a menu.
// static
-void LLAgentWearables::userRemoveWearable(void* userdata)
+void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index)
{
- EWearableType type = (EWearableType)(intptr_t)userdata;
-
- if (!(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR)) //&&
- //!((!gAgent.isTeen()) && (type==WT_UNDERPANTS || type==WT_UNDERSHIRT)))
+ if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&&
+ //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT)))
{
- // MULTI_WEARABLE: fixed to 0th for now.
- gAgentWearables.removeWearable(type,false,0);
+ gAgentWearables.removeWearable(type,false,index);
}
}
-// static
-void LLAgentWearables::userRemoveAllClothes(void* userdata)
+//static
+void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type)
{
- // We have to do this up front to avoid having to deal with the case of multiple wearables being dirty.
- if (gFloaterCustomize)
- {
- gFloaterCustomize->askToSaveIfDirty(userRemoveAllClothesStep2);
- }
- else
+ if (!(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES)) //&&
+ //!((!gAgent.isTeen()) && (type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT)))
{
- userRemoveAllClothesStep2(TRUE);
+ gAgentWearables.removeWearable(type,true,0);
}
}
-// static
-void LLAgentWearables::userRemoveAllClothesStep2(BOOL proceed)
-{
- if (proceed)
- {
- gAgentWearables.removeWearable(WT_SHIRT,true,0);
- gAgentWearables.removeWearable(WT_PANTS,true,0);
- gAgentWearables.removeWearable(WT_SHOES,true,0);
- gAgentWearables.removeWearable(WT_SOCKS,true,0);
- gAgentWearables.removeWearable(WT_JACKET,true,0);
- gAgentWearables.removeWearable(WT_GLOVES,true,0);
- gAgentWearables.removeWearable(WT_UNDERSHIRT,true,0);
- gAgentWearables.removeWearable(WT_UNDERPANTS,true,0);
- gAgentWearables.removeWearable(WT_SKIRT,true,0);
- }
-}
-
-// Combines userRemoveAllAttachments() and userAttachMultipleAttachments() logic to
-// get attachments into desired state with minimal number of adds/removes.
-void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array)
+// Given a desired set of attachments, find what objects need to be
+// removed, and what additional inventory items need to be added.
+void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array_t& obj_item_array,
+ llvo_vec_t& objects_to_remove,
+ llvo_vec_t& objects_to_retain,
+ LLInventoryModel::item_array_t& items_to_add)
{
// Possible cases:
// already wearing but not in request set -> take off.
// already wearing and in request set -> leave alone.
// not wearing and in request set -> put on.
- LLVOAvatar* avatarp = gAgent.getAvatarObject();
- if (!avatarp)
- {
- llwarns << "No avatar found." << llendl;
- return;
- }
+ if (!isAgentAvatarValid()) return;
std::set<LLUUID> requested_item_ids;
std::set<LLUUID> current_item_ids;
- for (S32 i=0; i<obj_item_array.count(); i++)
- requested_item_ids.insert(obj_item_array[i].get()->getLinkedUUID());
+ for (S32 i=0; i<obj_item_array.size(); i++)
+ {
+ const LLUUID & requested_id = obj_item_array[i].get()->getLinkedUUID();
+ //LL_INFOS() << "Requested attachment id " << requested_id << LL_ENDL;
+ requested_item_ids.insert(requested_id);
+ }
// Build up list of objects to be removed and items currently attached.
- llvo_vec_t objects_to_remove;
- for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin();
- iter != avatarp->mAttachmentPoints.end();)
+ for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ iter != gAgentAvatarp->mAttachmentPoints.end();)
{
LLVOAvatar::attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
@@ -1778,23 +1298,34 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj
LLViewerObject *objectp = (*attachment_iter);
if (objectp)
{
- LLUUID object_item_id = objectp->getItemID();
+ LLUUID object_item_id = objectp->getAttachmentItemID();
+
+ bool remove_attachment = true;
if (requested_item_ids.find(object_item_id) != requested_item_ids.end())
- {
- // Object currently worn, was requested.
+ { // Object currently worn, was requested to keep it
// Flag as currently worn so we won't have to add it again.
- current_item_ids.insert(object_item_id);
+ remove_attachment = false;
}
- else
+ else if (objectp->isTempAttachment())
+ { // Check if we should keep this temp attachment
+ remove_attachment = LLAppearanceMgr::instance().shouldRemoveTempAttachment(objectp->getID());
+ }
+
+ if (remove_attachment)
{
- // object currently worn, not requested.
+ // LL_INFOS() << "found object to remove, id " << objectp->getID() << ", item " << objectp->getAttachmentItemID() << LL_ENDL;
objects_to_remove.push_back(objectp);
}
+ else
+ {
+ // LL_INFOS() << "found object to keep, id " << objectp->getID() << ", item " << objectp->getAttachmentItemID() << LL_ENDL;
+ current_item_ids.insert(object_item_id);
+ objects_to_retain.push_back(objectp);
+ }
}
}
}
- LLInventoryModel::item_array_t items_to_add;
for (LLInventoryModel::item_array_t::iterator it = obj_item_array.begin();
it != obj_item_array.end();
++it)
@@ -1812,23 +1343,12 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj
}
// S32 remove_count = objects_to_remove.size();
// S32 add_count = items_to_add.size();
- // llinfos << "remove " << remove_count << " add " << add_count << llendl;
-
- // Remove everything in objects_to_remove
- userRemoveMultipleAttachments(objects_to_remove);
-
- // Add everything in items_to_add
- userAttachMultipleAttachments(items_to_add);
+ // LL_INFOS() << "remove " << remove_count << " add " << add_count << LL_ENDL;
}
void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remove)
{
- LLVOAvatar* avatarp = gAgent.getAvatarObject();
- if (!avatarp)
- {
- llwarns << "No avatar found." << llendl;
- return;
- }
+ if (!isAgentAvatarValid()) return;
if (objects_to_remove.empty())
return;
@@ -1843,46 +1363,17 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo
++it)
{
LLViewerObject *objectp = *it;
+ //gAgentAvatarp->resetJointPositionsOnDetach(objectp);
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
}
gMessageSystem->sendReliable(gAgent.getRegionHost());
}
-void LLAgentWearables::userRemoveAllAttachments()
-{
- LLVOAvatar* avatarp = gAgent.getAvatarObject();
- if (!avatarp)
- {
- llwarns << "No avatar found." << llendl;
- return;
- }
-
- llvo_vec_t objects_to_remove;
-
- for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin();
- iter != avatarp->mAttachmentPoints.end();)
- {
- LLVOAvatar::attachment_map_t::iterator curiter = iter++;
- LLViewerJointAttachment* attachment = curiter->second;
- 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);
-}
-
void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array)
{
// Build a compound message to send all the objects that need to be rezzed.
- S32 obj_count = obj_item_array.count();
+ S32 obj_count = obj_item_array.size();
// Limit number of packets to send
const S32 MAX_PACKETS_TO_SEND = 10;
@@ -1913,11 +1404,11 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
msg->addBOOLFast(_PREHASH_FirstDetachAll, false );
}
- const LLInventoryItem* item = obj_item_array.get(i).get();
+ const LLInventoryItem* item = obj_item_array.at(i).get();
msg->nextBlockFast(_PREHASH_ObjectData );
msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
- msg->addU8Fast(_PREHASH_AttachmentPt, 0 ); // Wear at the previous or default attachment point
+ msg->addU8Fast(_PREHASH_AttachmentPt, 0 | ATTACHMENT_ADD); // Wear at the previous or default attachment point
pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
msg->addStringFast(_PREHASH_Name, item->getName());
msg->addStringFast(_PREHASH_Description, item->getDescription());
@@ -1930,102 +1421,206 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
}
}
-void LLAgentWearables::checkWearablesLoaded() const
+// Returns false if the given wearable is already topmost/bottommost
+// (depending on closer_to_body parameter).
+bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body) const
{
-#ifdef SHOW_ASSERT
- U32 item_pend_count = itemUpdatePendingCount();
- if (mWearablesLoaded)
- {
- llassert(item_pend_count==0);
- }
-#endif
+ const LLWearable* wearable = getWearableFromItemID(item_id);
+ if (!wearable) return false;
+
+ LLWearableType::EType wtype = wearable->getType();
+ const LLWearable* marginal_wearable = closer_to_body ? getBottomWearable(wtype) : getTopWearable(wtype);
+ if (!marginal_wearable) return false;
+
+ return wearable != marginal_wearable;
}
BOOL LLAgentWearables::areWearablesLoaded() const
{
- checkWearablesLoaded();
return mWearablesLoaded;
}
-// MULTI-WEARABLE: update for multiple indices.
-void LLAgentWearables::updateWearablesLoaded()
-{
- mWearablesLoaded = (itemUpdatePendingCount()==0);
-}
-
-bool LLAgentWearables::canWearableBeRemoved(const LLWearable* wearable) const
+bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) const
{
if (!wearable) return false;
- EWearableType type = wearable->getType();
+ LLWearableType::EType type = wearable->getType();
// Make sure the user always has at least one shape, skin, eyes, and hair type currently worn.
- return !(((type == WT_SHAPE) || (type == WT_SKIN) || (type == WT_HAIR) || (type == WT_EYES))
+ return !(((type == LLWearableType::WT_SHAPE) || (type == LLWearableType::WT_SKIN) || (type == LLWearableType::WT_HAIR) || (type == LLWearableType::WT_EYES))
&& (getWearableCount(type) <= 1) );
}
+void LLAgentWearables::animateAllWearableParams(F32 delta)
+{
+ for( S32 type = 0; type < LLWearableType::WT_COUNT; ++type )
+ {
+ for (S32 count = 0; count < (S32)getWearableCount((LLWearableType::EType)type); ++count)
+ {
+ LLViewerWearable *wearable = getViewerWearable((LLWearableType::EType)type,count);
+ llassert(wearable);
+ if (wearable)
+ {
+ wearable->animateParams(delta);
+ }
+ }
+ }
+}
-void LLAgentWearables::updateServer()
+bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool closer_to_body)
{
- sendAgentWearablesUpdate();
- gAgent.sendAgentSetAppearance();
+ if (!item) return false;
+ if (!item->isWearableType()) return false;
+
+ LLWearableType::EType type = item->getWearableType();
+ U32 wearable_count = getWearableCount(type);
+ if (0 == wearable_count) return false;
+
+ const LLUUID& asset_id = item->getAssetUUID();
+
+ //nowhere to move if the wearable is already on any boundary (closest to the body/furthest from the body)
+ if (closer_to_body)
+ {
+ LLViewerWearable* bottom_wearable = dynamic_cast<LLViewerWearable*>( getBottomWearable(type) );
+ if (bottom_wearable->getAssetID() == asset_id)
+ {
+ return false;
+ }
+ }
+ else // !closer_to_body
+ {
+ LLViewerWearable* top_wearable = dynamic_cast<LLViewerWearable*>( getTopWearable(type) );
+ if (top_wearable->getAssetID() == asset_id)
+ {
+ return false;
+ }
+ }
+
+ for (U32 i = 0; i < wearable_count; ++i)
+ {
+ LLViewerWearable* wearable = getViewerWearable(type, i);
+ if (!wearable) continue;
+ if (wearable->getAssetID() != asset_id) continue;
+
+ //swapping wearables
+ U32 swap_i = closer_to_body ? i-1 : i+1;
+ swapWearables(type, i, swap_i);
+ return true;
+ }
+
+ return false;
}
-void LLInitialWearablesFetch::done()
+// static
+void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, const LLUUID& parent_id)
{
- // No longer need this observer hanging around.
- gInventory.removeObserver(this);
+ if (type == LLWearableType::WT_INVALID || type == LLWearableType::WT_NONE) return;
- // Fetch the wearable items from the Current Outfit Folder
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t wearable_array;
- LLFindWearables is_wearable;
- gInventory.collectDescendentsIf(mCompleteFolders.front(), cat_array, wearable_array,
- LLInventoryModel::EXCLUDE_TRASH, is_wearable);
-
- if (wearable_array.count() > 0)
+ LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
+ LLAssetType::EType asset_type = wearable->getAssetType();
+ LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE;
+ LLPointer<LLInventoryCallback> cb;
+ if(wear)
+ {
+ cb = new LLBoostFuncInventoryCallback(wear_and_edit_cb);
+ }
+ else
+ {
+ cb = new LLBoostFuncInventoryCallback(wear_cb);
+ }
+
+ LLUUID folder_id;
+
+ if (parent_id.notNull())
{
- LLAppearanceManager::instance().updateAppearanceFromCOF();
+ folder_id = parent_id;
}
else
{
- processWearablesMessage();
+ LLFolderType::EType folder_type = LLFolderType::assetTypeToFolderType(asset_type);
+ folder_id = gInventory.findCategoryUUIDForType(folder_type);
}
- delete this;
+
+ create_inventory_item(gAgent.getID(),
+ gAgent.getSessionID(),
+ folder_id,
+ wearable->getTransactionID(),
+ wearable->getName(),
+ wearable->getDescription(),
+ asset_type, inv_type,
+ wearable->getType(),
+ LLFloaterPerms::getNextOwnerPerms("Wearables"),
+ cb);
}
-void LLInitialWearablesFetch::processWearablesMessage()
+// static
+void LLAgentWearables::editWearable(const LLUUID& item_id)
{
- if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead.
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(item_id);
+ if (!item)
{
- LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
- for (U8 i = 0; i < mAgentInitialWearables.size(); ++i)
- {
- // Populate the current outfit folder with links to the wearables passed in the message
- InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback.
-
- if (wearable_data->mAssetID.notNull())
- {
-#ifdef USE_CURRENT_OUTFIT_FOLDER
- const std::string link_name = "WearableLink"; // Unimportant what this is named, it isn't exposed.
- link_inventory_item(gAgent.getID(), wearable_data->mItemID, current_outfit_id, link_name,
- LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL));
-#endif
- // Fetch the wearables
- LLWearableList::instance().getAsset(wearable_data->mAssetID,
- LLStringUtil::null,
- LLWearableDictionary::getAssetType(wearable_data->mType),
- LLAgentWearables::onInitialWearableAssetArrived, (void*)(wearable_data));
- }
- else
- {
- llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID "
- << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl;
- }
- }
+ LL_WARNS() << "Failed to get linked item" << LL_ENDL;
+ return;
}
- else
+
+ LLViewerWearable* wearable = gAgentWearables.getWearableFromItemID(item_id);
+ if (!wearable)
+ {
+ LL_WARNS() << "Cannot get wearable" << LL_ENDL;
+ return;
+ }
+
+ if (!gAgentWearables.isWearableModifiable(item->getUUID()))
{
- LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL;
+ LL_WARNS() << "Cannot modify wearable" << LL_ENDL;
+ return;
}
+
+ const BOOL disable_camera_switch = LLWearableType::getDisableCameraSwitch(wearable->getType());
+ LLPanel* panel = LLFloaterSidePanelContainer::getPanel("appearance");
+ LLSidepanelAppearance::editWearable(wearable, panel, disable_camera_switch);
}
+// Request editing the item after it gets worn.
+void LLAgentWearables::requestEditingWearable(const LLUUID& item_id)
+{
+ mItemToEdit = gInventory.getLinkedItemID(item_id);
+}
+// Start editing the item if previously requested.
+void LLAgentWearables::editWearableIfRequested(const LLUUID& item_id)
+{
+ if (mItemToEdit.notNull() &&
+ mItemToEdit == gInventory.getLinkedItemID(item_id))
+ {
+ LLAgentWearables::editWearable(item_id);
+ mItemToEdit.setNull();
+ }
+}
+
+boost::signals2::connection LLAgentWearables::addLoadingStartedCallback(loading_started_callback_t cb)
+{
+ return mLoadingStartedSignal.connect(cb);
+}
+
+boost::signals2::connection LLAgentWearables::addLoadedCallback(loaded_callback_t cb)
+{
+ return mLoadedSignal.connect(cb);
+}
+
+bool LLAgentWearables::changeInProgress() const
+{
+ return mCOFChangeInProgress;
+}
+
+void LLAgentWearables::notifyLoadingStarted()
+{
+ mCOFChangeInProgress = true;
+ mCOFChangeTimer.reset();
+ mLoadingStartedSignal();
+}
+
+void LLAgentWearables::notifyLoadingFinished()
+{
+ mCOFChangeInProgress = false;
+ mLoadedSignal();
+}
+// EOF