summaryrefslogtreecommitdiff
path: root/indra/newview/llagentwearables.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llagentwearables.cpp')
-rw-r--r--indra/newview/llagentwearables.cpp340
1 files changed, 280 insertions, 60 deletions
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 79ba3fb51d..c21cdf9508 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -95,18 +95,38 @@ public:
enum ELibraryOutfitFetchStep {
LOFS_FOLDER = 0,
LOFS_OUTFITS,
+ LOFS_LIBRARY,
+ LOFS_IMPORTED,
LOFS_CONTENTS
};
- LLLibraryOutfitsFetch() : mCurrFetchStep(LOFS_FOLDER), mOutfitsPopulated(false) {}
+ LLLibraryOutfitsFetch() : mCurrFetchStep(LOFS_FOLDER), mOutfitsPopulated(false)
+ {
+ mMyOutfitsID = LLUUID::null;
+ mClothingID = LLUUID::null;
+ mLibraryClothingID = LLUUID::null;
+ mImportedClothingID = LLUUID::null;
+ mImportedClothingName = "Imported Library Clothing";
+ }
~LLLibraryOutfitsFetch() {}
- virtual void done();
+ virtual void done();
+ void doneIdle();
+ LLUUID mMyOutfitsID;
+ void importedFolderFetch();
protected:
void folderDone(void);
void outfitsDone(void);
+ void libraryDone(void);
+ void importedFolderDone(void);
void contentsDone(void);
enum ELibraryOutfitFetchStep mCurrFetchStep;
- std::vector< std::pair< LLUUID, std::string > > mOutfits;
+ typedef std::vector< std::pair< LLUUID, std::string > > cloth_folder_vec_t;
+ cloth_folder_vec_t mLibraryClothingFolders;
+ cloth_folder_vec_t mImportedClothingFolders;
bool mOutfitsPopulated;
+ LLUUID mClothingID;
+ LLUUID mLibraryClothingID;
+ LLUUID mImportedClothingID;
+ std::string mImportedClothingName;
};
LLAgentWearables gAgentWearables;
@@ -115,6 +135,39 @@ 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(LLWearable *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())
+ {
+ llwarns << "wearable associated with non-wearable item" << llendl;
+ }
+ if (item->getWearableType() != wearable->getType())
+ {
+ llwarns << "type mismatch: wearable " << wearable->getName()
+ << " has type " << wearable->getType()
+ << " but inventory item " << item->getName()
+ << " has type " << item->getWearableType() << llendl;
+ }
+ }
+ else
+ {
+ llwarns << "wearable inventory item not found" << wearable->getName()
+ << " itemID " << wearable->getItemID().asString() << llendl;
+ }
+}
+
void LLAgentWearables::dump()
{
llinfos << "LLAgentWearablesDump" << llendl;
@@ -656,6 +709,7 @@ LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 index)
void LLAgentWearables::setWearable(const EWearableType type, U32 index, LLWearable *wearable)
{
+
LLWearable *old_wearable = getWearable(type,index);
if (!old_wearable)
{
@@ -679,6 +733,7 @@ void LLAgentWearables::setWearable(const EWearableType type, U32 index, LLWearab
wearable_vec[index] = wearable;
old_wearable->setLabelUpdated();
wearableUpdated(wearable);
+ checkWearableAgainstInventory(wearable);
}
}
@@ -694,6 +749,7 @@ U32 LLAgentWearables::pushWearable(const EWearableType type, LLWearable *wearabl
{
mWearableDatas[type].push_back(wearable);
wearableUpdated(wearable);
+ checkWearableAgainstInventory(wearable);
return mWearableDatas[type].size()-1;
}
return MAX_WEARABLES_PER_TYPE;
@@ -874,7 +930,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
// If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account)
// then auto-populate outfits from the library into the My Outfits folder.
- if (LLInventoryModel::getIsFirstTimeInViewer2())
+ if (LLInventoryModel::getIsFirstTimeInViewer2() || gSavedSettings.getBOOL("MyOutfitsAutofill"))
{
gAgentWearables.populateMyOutfitsFolder();
}
@@ -1308,15 +1364,15 @@ void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name,
}
}
-class LLAutoRenameFolder: public LLInventoryCallback
+class LLShowCreatedOutfit: public LLInventoryCallback
{
public:
- LLAutoRenameFolder(LLUUID& folder_id):
+ LLShowCreatedOutfit(LLUUID& folder_id):
mFolderID(folder_id)
{
}
- virtual ~LLAutoRenameFolder()
+ virtual ~LLShowCreatedOutfit()
{
LLSD key;
LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key);
@@ -1326,13 +1382,15 @@ public:
{
outfit_panel->getRootFolder()->clearSelection();
outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE);
- outfit_panel->getRootFolder()->setNeedsAutoRename(TRUE);
}
LLAccordionCtrlTab* tab_outfits = outfit_panel ? outfit_panel->findChild<LLAccordionCtrlTab>("tab_outfits") : 0;
if (tab_outfits && !tab_outfits->getDisplayChildren())
{
tab_outfits->changeOpenClose(tab_outfits->getDisplayChildren());
}
+
+ LLAppearanceManager::instance().updateIsDirty();
+ LLAppearanceManager::instance().updatePanelOutfitName("");
}
virtual void fire(const LLUUID&)
@@ -1357,9 +1415,10 @@ LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name)
LLFolderType::FT_OUTFIT,
new_folder_name);
- LLPointer<LLInventoryCallback> cb = new LLAutoRenameFolder(folder_id);
+ LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id);
LLAppearanceManager::instance().shallowCopyCategory(LLAppearanceManager::instance().getCOF(),folder_id, cb);
-
+ LLAppearanceManager::instance().createBaseOutfitLink(folder_id, cb);
+
return folder_id;
}
@@ -1704,6 +1763,7 @@ void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLWearable* n
mWearableDatas[type].push_back(new_wearable);
llinfos << "Added additional wearable for type " << type
<< " size is now " << mWearableDatas[type].size() << llendl;
+ checkWearableAgainstInventory(new_wearable);
}
else
{
@@ -2084,83 +2144,95 @@ void LLAgentWearables::populateMyOutfitsFolder(void)
{
LLLibraryOutfitsFetch* outfits = new LLLibraryOutfitsFetch();
- // 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.
+ // Get the complete information on the items in the inventory and
+ // setup an observer that will wait for that to happen.
LLInventoryFetchDescendentsObserver::folder_ref_t folders;
- const LLUUID my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ outfits->mMyOutfitsID = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
- folders.push_back(my_outfits_id);
+ folders.push_back(outfits->mMyOutfitsID);
+ gInventory.addObserver(outfits);
outfits->fetchDescendents(folders);
- if(outfits->isEverythingComplete())
+ if (outfits->isEverythingComplete())
{
- // everything is already here - call done.
outfits->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(outfits);
- }
}
void LLLibraryOutfitsFetch::done()
{
- switch (mCurrFetchStep){
+ // Delay this until idle() routine, since it's a heavy operation and
+ // we also can't have it run within notifyObservers.
+ doOnIdle(boost::bind(&LLLibraryOutfitsFetch::doneIdle,this));
+ gInventory.removeObserver(this); // Prevent doOnIdle from being added twice.
+}
+
+void LLLibraryOutfitsFetch::doneIdle()
+{
+ gInventory.addObserver(this); // Add this back in since it was taken out during ::done()
+
+ switch (mCurrFetchStep)
+ {
case LOFS_FOLDER:
- mCurrFetchStep = LOFS_OUTFITS;
folderDone();
+ mCurrFetchStep = LOFS_OUTFITS;
break;
case LOFS_OUTFITS:
- mCurrFetchStep = LOFS_CONTENTS;
outfitsDone();
+ mCurrFetchStep = LOFS_LIBRARY;
+ break;
+ case LOFS_LIBRARY:
+ libraryDone();
+ mCurrFetchStep = LOFS_IMPORTED;
+ break;
+ case LOFS_IMPORTED:
+ importedFolderDone();
+ mCurrFetchStep = LOFS_CONTENTS;
break;
case LOFS_CONTENTS:
- // No longer need this observer hanging around.
- gInventory.removeObserver(this);
contentsDone();
break;
default:
- gInventory.removeObserver(this);
- delete this;
- return;
+ llwarns << "Got invalid state for outfit fetch: " << mCurrFetchStep << llendl;
+ mOutfitsPopulated = TRUE;
+ break;
}
+
+ // We're completely done. Cleanup.
if (mOutfitsPopulated)
{
+ gInventory.removeObserver(this);
delete this;
+ return;
}
}
void LLLibraryOutfitsFetch::folderDone(void)
{
- // Early out if we already have items in My Outfits.
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
- gInventory.collectDescendents(mCompleteFolders.front(), cat_array, wearable_array,
+ gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH);
+
+ // Early out if we already have items in My Outfits.
if (cat_array.count() > 0 || wearable_array.count() > 0)
{
mOutfitsPopulated = true;
- gInventory.removeObserver(this);
return;
}
- // Get the UUID of the library's clothing folder
- const LLUUID library_clothing_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING, false, true);
+ mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
+ mLibraryClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING, false, true);
mCompleteFolders.clear();
- // 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.
+ // Get the complete information on the items in the inventory.
LLInventoryFetchDescendentsObserver::folder_ref_t folders;
- folders.push_back(library_clothing_id);
+ folders.push_back(mClothingID);
+ folders.push_back(mLibraryClothingID);
fetchDescendents(folders);
- if(isEverythingComplete())
+ if (isEverythingComplete())
{
- // everything is already here - call done.
- outfitsDone();
+ done();
}
}
@@ -2168,39 +2240,185 @@ void LLLibraryOutfitsFetch::outfitsDone(void)
{
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t wearable_array;
- gInventory.collectDescendents(mCompleteFolders.front(), cat_array, wearable_array,
+ LLInventoryFetchDescendentsObserver::folder_ref_t folders;
+
+ // Collect the contents of the Library's Clothing folder
+ gInventory.collectDescendents(mLibraryClothingID, cat_array, wearable_array,
LLInventoryModel::EXCLUDE_TRASH);
- LLInventoryFetchDescendentsObserver::folder_ref_t folders;
- for(S32 i = 0; i < cat_array.count(); ++i)
+ llassert(cat_array.count() > 0);
+ for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin();
+ iter != cat_array.end();
+ ++iter)
{
- if (cat_array.get(i)->getName() != "More Outfits" && cat_array.get(i)->getName() != "Ruth"){
- folders.push_back(cat_array.get(i)->getUUID());
- mOutfits.push_back( std::make_pair(cat_array.get(i)->getUUID(), cat_array.get(i)->getName() ));
+ const LLViewerInventoryCategory *cat = iter->get();
+
+ // Get the names and id's of every outfit in the library, except for ruth and other "misc" outfits.
+ if (cat->getName() != "More Outfits" && cat->getName() != "Ruth")
+ {
+ // Get the name of every outfit in the library
+ folders.push_back(cat->getUUID());
+ mLibraryClothingFolders.push_back(std::make_pair(cat->getUUID(), cat->getName()));
}
}
+
+ // Collect the contents of your Inventory Clothing folder
+ cat_array.clear();
+ wearable_array.clear();
+ gInventory.collectDescendents(mClothingID, cat_array, wearable_array,
+ LLInventoryModel::EXCLUDE_TRASH);
+
+ // Check if you already have an "Imported Library Clothing" folder
+ for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin();
+ iter != cat_array.end();
+ ++iter)
+ {
+ const LLViewerInventoryCategory *cat = iter->get();
+ if (cat->getName() == mImportedClothingName)
+ {
+ mImportedClothingID = cat->getUUID();
+ }
+ }
+
mCompleteFolders.clear();
+
fetchDescendents(folders);
- if(isEverythingComplete())
+ if (isEverythingComplete())
{
- // everything is already here - call done.
- contentsDone();
+ done();
}
}
-void LLLibraryOutfitsFetch::contentsDone(void)
+class LLLibraryOutfitsCopyDone: public LLInventoryCallback
{
- for(S32 i = 0; i < (S32)mOutfits.size(); ++i)
+public:
+ LLLibraryOutfitsCopyDone(LLLibraryOutfitsFetch * fetcher):
+ mFireCount(0), mLibraryOutfitsFetcher(fetcher)
+ {
+ }
+
+ virtual ~LLLibraryOutfitsCopyDone()
+ {
+ if (mLibraryOutfitsFetcher)
+ {
+ gInventory.addObserver(mLibraryOutfitsFetcher);
+ mLibraryOutfitsFetcher->done();
+ }
+ }
+
+ /* virtual */ void fire(const LLUUID& inv_item)
+ {
+ mFireCount++;
+ }
+private:
+ U32 mFireCount;
+ LLLibraryOutfitsFetch * mLibraryOutfitsFetcher;
+};
+
+void LLLibraryOutfitsFetch::libraryDone(void)
+{
+ // Copy the clothing folders from the library into the imported clothing folder if necessary.
+ if (mImportedClothingID == LLUUID::null)
+ {
+ gInventory.removeObserver(this);
+ LLPointer<LLInventoryCallback> copy_waiter = new LLLibraryOutfitsCopyDone(this);
+ mImportedClothingID = gInventory.createNewCategory(mClothingID,
+ LLFolderType::FT_NONE,
+ mImportedClothingName);
+
+ for (cloth_folder_vec_t::const_iterator iter = mLibraryClothingFolders.begin();
+ iter != mLibraryClothingFolders.end();
+ ++iter)
+ {
+ LLUUID folder_id = gInventory.createNewCategory(mImportedClothingID,
+ LLFolderType::FT_NONE,
+ iter->second);
+ LLAppearanceManager::getInstance()->shallowCopyCategory(iter->first, folder_id, copy_waiter);
+ }
+ }
+ else
+ {
+ // Skip straight to fetching the contents of the imported folder
+ importedFolderFetch();
+ }
+}
+
+void LLLibraryOutfitsFetch::importedFolderFetch(void)
+{
+ // Fetch the contents of the Imported Clothing Folder
+ LLInventoryFetchDescendentsObserver::folder_ref_t folders;
+ folders.push_back(mImportedClothingID);
+
+ mCompleteFolders.clear();
+
+ fetchDescendents(folders);
+ if (isEverythingComplete())
+ {
+ done();
+ }
+}
+
+void LLLibraryOutfitsFetch::importedFolderDone(void)
+{
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t wearable_array;
+ LLInventoryFetchDescendentsObserver::folder_ref_t folders;
+
+ // Collect the contents of the Imported Clothing folder
+ gInventory.collectDescendents(mImportedClothingID, cat_array, wearable_array,
+ LLInventoryModel::EXCLUDE_TRASH);
+
+ for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin();
+ iter != cat_array.end();
+ ++iter)
+ {
+ const LLViewerInventoryCategory *cat = iter->get();
+
+ // Get the name of every imported outfit
+ folders.push_back(cat->getUUID());
+ mImportedClothingFolders.push_back(std::make_pair(cat->getUUID(), cat->getName()));
+ }
+
+ mCompleteFolders.clear();
+ fetchDescendents(folders);
+ if (isEverythingComplete())
+ {
+ done();
+ }
+}
+
+void LLLibraryOutfitsFetch::contentsDone(void)
+{
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t wearable_array;
+
+ for (cloth_folder_vec_t::const_iterator folder_iter = mImportedClothingFolders.begin();
+ folder_iter != mImportedClothingFolders.end();
+ ++folder_iter)
{
// First, make a folder in the My Outfits directory.
- const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
- LLUUID folder_id = gInventory.createNewCategory(parent_id,
- LLFolderType::FT_OUTFIT,
- mOutfits[i].second);
+ LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, folder_iter->second);
- LLAppearanceManager::getInstance()->shallowCopyCategory(mOutfits[i].first, folder_id, NULL);
- gInventory.notifyObservers();
+ cat_array.clear();
+ wearable_array.clear();
+ // Collect the contents of each imported clothing folder, so we can create new outfit links for it
+ gInventory.collectDescendents(folder_iter->first, cat_array, wearable_array,
+ LLInventoryModel::EXCLUDE_TRASH);
+
+ for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin();
+ wearable_iter != wearable_array.end();
+ ++wearable_iter)
+ {
+ const LLViewerInventoryItem *item = wearable_iter->get();
+ link_inventory_item(gAgent.getID(),
+ item->getLinkedUUID(),
+ new_outfit_folder_id,
+ item->getName(),
+ LLAssetType::AT_LINK,
+ NULL);
+ }
}
+
mOutfitsPopulated = true;
}
@@ -2242,6 +2460,8 @@ void LLInitialWearablesFetch::processContents()
}
else
{
+ // if we're constructing the COF from the wearables message, we don't have a proper outfit link
+ LLAppearanceManager::instance().setOutfitDirty(true);
processWearablesMessage();
}
delete this;