From 60d5bb81f23d8087cb08a986efc61ee2f6836e27 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 18 Jan 2012 17:51:09 -0600 Subject: [PATCH 01/13] Tweak to CannotCopyWarning notification. Updated french notifications.xml a tiny bit. --- indra/newview/llgiveinventory.cpp | 43 +++++++++++-------- .../skins/default/xui/en-us/notifications.xml | 4 +- .../skins/default/xui/fr/notifications.xml | 42 ++++++++++-------- 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp index 8e61b9298..b922f7710 100644 --- a/indra/newview/llgiveinventory.cpp +++ b/indra/newview/llgiveinventory.cpp @@ -219,11 +219,15 @@ bool LLGiveInventory::doGiveInventoryItem(const LLUUID& to_agent, else { // ask if the agent is sure. + LLSD substitutions; + substitutions["ITEMS"] = item->getName(); LLSD payload; payload["agent_id"] = to_agent; - payload["item_id"] = item->getUUID(); - LLNotificationsUtil::add("CannotCopyWarning", LLSD(), payload, - &LLGiveInventory::handleCopyProtectedItem); + LLSD items = LLSD::emptyArray(); + items.append(item->getUUID()); + payload["items"] = items; + LLNotificationsUtil::add("CannotCopyWarning", substitutions, payload, + &LLGiveInventory::handleCopyProtectedItem); res = false; } @@ -302,9 +306,10 @@ void LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im_session_id) { // If this item was given by drag-and-drop into an IM panel, log this action in the IM panel chat. + LLSD args; + args["user_id"] = to_agent; if (im_session_id.notNull()) { - LLSD args; gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); } } @@ -312,24 +317,28 @@ void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im // static bool LLGiveInventory::handleCopyProtectedItem(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + LLSD itmes = notification["payload"]["items"]; LLInventoryItem* item = NULL; switch(option) { case 0: // "Yes" - item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); - if(item) + for (LLSD::array_iterator it = itmes.beginArray(); it != itmes.endArray(); it++) { - LLGiveInventory::commitGiveInventoryItem(notification["payload"]["agent_id"].asUUID(), - item); - // delete it for now - it will be deleted on the server - // quickly enough. - gInventory.deleteObject(notification["payload"]["item_id"].asUUID()); - gInventory.notifyObservers(); - } - else - { - LLNotificationsUtil::add("CannotGiveItem"); + item = gInventory.getItem((*it).asUUID()); + if (item) + { + LLGiveInventory::commitGiveInventoryItem(notification["payload"]["agent_id"].asUUID(), + item); + // delete it for now - it will be deleted on the server + // quickly enough. + gInventory.deleteObject(item->getUUID()); + gInventory.notifyObservers(); + } + else + { + LLNotificationsUtil::add("CannotGiveItem"); + } } break; diff --git a/indra/newview/skins/default/xui/en-us/notifications.xml b/indra/newview/skins/default/xui/en-us/notifications.xml index f67512ab5..cab47b46f 100644 --- a/indra/newview/skins/default/xui/en-us/notifications.xml +++ b/indra/newview/skins/default/xui/en-us/notifications.xml @@ -1266,7 +1266,9 @@ The region [REGION] does not allow terraforming. icon="alertmodal.tga" name="CannotCopyWarning" type="alertmodal"> -You do not have permission to copy this item and will lose it from your inventory if you give it away. Do you really want to offer this item? +You do not have permission to copy the following items: +[ITEMS] +and will lose it from your inventory if you give it away. Do you really want to offer these items? - - Votre version de Second Life ne peut afficher ce message d'erreur. + + Votre version de [APP_NAME] ne peut afficher ce message de notification. Veuillez vous assurer que vous avez bien la toute dernière version du client. -Détails de l'erreur : L'alerte, appelée '[_NAME]' est introuvable dans notifications.xml. +Détails de l'erreur : La notification, appelée '[_NAME]', est introuvable dans notifications.xml. @@ -94,11 +94,11 @@ Détails de l'erreur : L'alerte, appelée '[_NAME]' est int - Une erreur est survenue lors de la mise à jour de Second Life. Veuillez télécharger la dernière version depuis PheonixViewer.com. + Une erreur est survenue lors de la mise à jour de [APP_NAME]. Veuillez télécharger la dernière version depuis SingularityViewer.org. - Erreur réseau : impossible d'établir une connexion. + Erreur réseau : impossible d'établir une connexion à [SECOND_LIFE_GRID]. '[DIAGNOSTIC]' Veuillez vérifier votre connexion. @@ -502,7 +502,9 @@ La qualité des graphiques peut être augmentée à la section Préférences > Le terraformage est interdit dans la région [REGION]. - Vous n'êtes pas autorisé à copier cet objet et il disparaîtra de votre inventaire si vous le donnez. Souhaitez-vous vraiment offrir cet objet ? + Vous n'êtes pas autorisé à copier les articles suivants : +[ITEMS]. +Ceux-ci disparaîtront donc de votre inventaire si vous les donnez. Voulez-vous vraiment offrir ces articles ? @@ -613,6 +615,10 @@ Assurez-vous que le fichier a l'extension correcte. Impossible de trouver les données dans l'en-tête WAV : +[FILE] + + + Taille de fragment incorrecte dans le fichier WAV : [FILE] @@ -643,7 +649,7 @@ Assurez-vous que le fichier a l'extension correcte. Impossible de créer le fichier de sortie : [FILE] - Actuellement, nous ne prenons pas en charge le chargement de lots de fichiers d'animation. + Actuellement, [APP_NAME] ne prend pas en charge le chargement de lots de fichiers d'animation. Impossible de charger [FILE] suite au problème suivant : [REASON] @@ -1217,45 +1223,45 @@ Veuillez choisir un objet à vendre et réessayer. [DOWNLOAD_PATH]. - Une nouvelle version de [SECOND_LIFE] est disponible. + Une nouvelle version de [APP_NAME] est disponible. [MESSAGE] -Pour utiliser [SECOND_LIFE] vous devez télécharger cette mise à jour. +Pour utiliser [APP_NAME], vous devez télécharger cette mise à jour. - Une mise à jour de [SECOND_LIFE] est disponible. + Une mise à jour de [APP_NAME] est disponible. [MESSAGE] Cette mise à jour n'est pas requise mais si vous voulez une meilleure performance et plus de stabilité, nous vous recommandons de l'installer. - Une mise à jour de [SECOND_LIFE] est disponible. + Une mise à jour de [APP_NAME] est disponible. [MESSAGE] Cette mise à jour n'est pas requise mais si vous voulez une meilleure performance et plus de stabilité, nous vous recommandons de l'installer. - Une nouvelle version de [SECOND_LIFE] est disponible. + Une nouvelle version de [APP_NAME] est disponible. [MESSAGE] -Pour utiliser [SECOND_LIFE] vous devez télécharger cette mise à jour. +Pour utiliser [APP_NAME], vous devez télécharger cette mise à jour. -Télécharger vers le dossier Applications ? +Télécharger vers le dossier Applications ? - Une mise à jour de [SECOND_LIFE] est disponible. + Une mise à jour de [APP_NAME] est disponible. [MESSAGE] Cette mise à jour n'est pas requise mais si vous voulez une meilleure performance et plus de stabilité, nous vous recommandons de l'installer. -Télécharger vers le dossier Applications ? +Télécharger vers le dossier Applications ? - Une mise à jour de [SECOND_LIFE] est disponible. + Une mise à jour de [APP_NAME] est disponible. [MESSAGE] Cette mise à jour n'est pas requise mais si vous voulez une meilleure performance et plus de stabilité, nous vous recommandons de l'installer. -Télécharger vers le dossier Applications ? +Télécharger vers le dossier Applications ? From 9837b0ea2e2ad6c05323ea1d04fcc8180da044b1 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 18 Jan 2012 23:23:29 -0600 Subject: [PATCH 02/13] A little bit of code shuffling and member renaming in llinventoryview.cpp to line up with v3 a bit better. TO-DO: Many functions in LLInventoryView need to be migrated to something akin to v3s LLPanelMainInventory class. --- indra/newview/llinventorybridge.cpp | 9 - indra/newview/llinventorybridge.h | 15 -- indra/newview/llinventoryview.cpp | 261 +++++++++++++++++++--------- indra/newview/llinventoryview.h | 53 +++--- 4 files changed, 215 insertions(+), 123 deletions(-) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 08ee59a0c..baa318313 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -193,15 +193,6 @@ struct LLWearInfo // | LLInvFVBridge | // +=================================================+ -/*virtual*/ void LLInventoryPanelObserver::changed(U32 mask) -{ - mIP->modelChanged(mask); -} - -// +=================================================+ -// | LLInvFVBridge | -// +=================================================+ - LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, //LLFolderView* root, const LLUUID& uuid) : diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 0279c850f..381646b39 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -117,21 +117,6 @@ public: } }; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryPanelObserver -// -// Bridge to support knowing when the inventory has changed. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryPanelObserver : public LLInventoryObserver -{ -public: - LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {} - virtual ~LLInventoryPanelObserver() {} - virtual void changed(U32 mask); -protected: - LLInventoryPanel* mIP; -}; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInvFVBridge (& it's derived classes) // diff --git a/indra/newview/llinventoryview.cpp b/indra/newview/llinventoryview.cpp index bbfc1c515..7cb0d5a90 100644 --- a/indra/newview/llinventoryview.cpp +++ b/indra/newview/llinventoryview.cpp @@ -109,6 +109,25 @@ const S32 INV_MIN_HEIGHT = 150; const S32 INV_FINDER_WIDTH = 160; const S32 INV_FINDER_HEIGHT = 408; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryPanelObserver +// +// Bridge to support knowing when the inventory has changed. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryPanelObserver : public LLInventoryObserver +{ +public: + LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {} + virtual ~LLInventoryPanelObserver() {} + virtual void changed(U32 mask) + { + mIP->modelChanged(mask); + } +protected: + LLInventoryPanel* mIP; +}; + ///---------------------------------------------------------------------------- /// LLInventoryViewFinder ///---------------------------------------------------------------------------- @@ -1339,7 +1358,7 @@ LLInventoryPanel::LLInventoryPanel(const std::string& name, LLPanel(name, rect, TRUE), mInventory(inventory), mInventoryObserver(NULL), - mFolders(NULL), + mFolderRoot(NULL), mScroller(NULL), mAllowMultiSelect(allow_multi_select), mSortOrderSetting(sort_order_setting) @@ -1357,19 +1376,19 @@ BOOL LLInventoryPanel::postBuild() 0, getRect().getWidth(), 0); - mFolders = new LLFolderView(getName(), NULL, folder_rect, LLUUID::null, this); - mFolders->setAllowMultiSelect(mAllowMultiSelect); + mFolderRoot = new LLFolderView(getName(), NULL, folder_rect, LLUUID::null, this); + mFolderRoot->setAllowMultiSelect(mAllowMultiSelect); // scroller LLRect scroller_view_rect = getRect(); scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); mScroller = new LLScrollableContainerView(std::string("Inventory Scroller"), scroller_view_rect, - mFolders); + mFolderRoot); mScroller->setFollowsAll(); mScroller->setReserveScrollCorner(TRUE); addChild(mScroller); - mFolders->setScrollContainer(mScroller); + mFolderRoot->setScrollContainer(mScroller); // set up the callbacks from the inventory we're viewing, and then // build everything. @@ -1378,7 +1397,7 @@ BOOL LLInventoryPanel::postBuild() rebuildViewsFor(LLUUID::null, LLInventoryObserver::ADD); // bit of a hack to make sure the inventory is open. - mFolders->openFolder(std::string("My Inventory")); + mFolderRoot->openFolder(std::string("My Inventory")); if (mSortOrderSetting != INHERIT_SORT_ORDER) { @@ -1388,7 +1407,7 @@ BOOL LLInventoryPanel::postBuild() { setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER)); } - mFolders->setSortOrder(mFolders->getFilter()->getSortOrder()); + mFolderRoot->setSortOrder(mFolderRoot->getFilter()->getSortOrder()); return TRUE; @@ -1396,11 +1415,13 @@ BOOL LLInventoryPanel::postBuild() LLInventoryPanel::~LLInventoryPanel() { - // should this be a global setting? - U32 sort_order = mFolders->getSortOrder(); - if (mSortOrderSetting != INHERIT_SORT_ORDER) + if (mFolderRoot) { - gSavedSettings.setU32(mSortOrderSetting, sort_order); + U32 sort_order = mFolderRoot->getSortOrder(); + if (mSortOrderSetting != INHERIT_SORT_ORDER) + { + gSavedSettings.setU32(mSortOrderSetting, sort_order); + } } // LLView destructor will take care of the sub-views. @@ -1416,7 +1437,7 @@ LLXMLNodePtr LLInventoryPanel::getXML(bool save_children) const node->setName(LL_INVENTORY_PANEL_TAG); - node->createChild("allow_multi_select", TRUE)->setBoolValue(mFolders->getAllowMultiSelect()); + node->createChild("allow_multi_select", TRUE)->setBoolValue(mFolderRoot->getAllowMultiSelect()); return node; } @@ -1458,55 +1479,93 @@ void LLInventoryPanel::draw() LLPanel::draw(); } +LLInventoryFilter* LLInventoryPanel::getFilter() +{ + if (mFolderRoot) + { + return mFolderRoot->getFilter(); + } + return NULL; +} + +const LLInventoryFilter* LLInventoryPanel::getFilter() const +{ + if (mFolderRoot) + { + return mFolderRoot->getFilter(); + } + return NULL; +} + void LLInventoryPanel::setFilterTypes(U32 filter_types) { - mFolders->getFilter()->setFilterTypes(filter_types); + getFilter()->setFilterTypes(filter_types); } +U32 LLInventoryPanel::getFilterTypes() const +{ + return mFolderRoot->getFilterTypes(); +} + +U32 LLInventoryPanel::getFilterPermMask() const +{ + return mFolderRoot->getFilterPermissions(); +} + void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) { - mFolders->getFilter()->setFilterPermissions(filter_perm_mask); -} - -void LLInventoryPanel::setFilterSubString(const std::string& string) -{ - mFolders->getFilter()->setFilterSubString(string); + getFilter()->setFilterPermissions(filter_perm_mask); } void LLInventoryPanel::setFilterWorn(bool worn) { - mFolders->getFilter()->setFilterWorn(worn); + getFilter()->setFilterWorn(worn); +} + +void LLInventoryPanel::setFilterSubString(const std::string& string) +{ + getFilter()->setFilterSubString(string); +} + +const std::string LLInventoryPanel::getFilterSubString() +{ + return mFolderRoot->getFilterSubString(); } void LLInventoryPanel::setSortOrder(U32 order) { - mFolders->getFilter()->setSortOrder(order); - if (mFolders->getFilter()->isModified()) + getFilter()->setSortOrder(order); + if (getFilter()->isModified()) { - mFolders->setSortOrder(order); + mFolderRoot->setSortOrder(order); // try to keep selection onscreen, even if it wasn't to start with - mFolders->scrollToShowSelection(); + mFolderRoot->scrollToShowSelection(); } } +U32 LLInventoryPanel::getSortOrder() const +{ + return mFolderRoot->getSortOrder(); +} + void LLInventoryPanel::setSinceLogoff(BOOL sl) { - mFolders->getFilter()->setDateRangeLastLogoff(sl); + getFilter()->setDateRangeLastLogoff(sl); } void LLInventoryPanel::setHoursAgo(U32 hours) { - mFolders->getFilter()->setHoursAgo(hours); + getFilter()->setHoursAgo(hours); } void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) { - mFolders->getFilter()->setShowFolderState(show); + getFilter()->setShowFolderState(show); } LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() { - return mFolders->getFilter()->getShowFolderState(); + return getFilter()->getShowFolderState(); } void LLInventoryPanel::modelChanged(U32 mask) @@ -1529,7 +1588,7 @@ void LLInventoryPanel::modelChanged(U32 mask) { const LLUUID& item_id = (*items_iter); const LLInventoryObject* model_item = model->getObject(item_id); - LLFolderViewItem* view_item = getRootFolder()->getItemByID(item_id); + LLFolderViewItem* view_item = mFolderRoot->getItemByID(item_id); // LLFolderViewFolder is derived from LLFolderViewItem so dynamic_cast from item // to folder is the fast way to get a folder without searching through folders tree. @@ -1609,7 +1668,7 @@ void LLInventoryPanel::modelChanged(U32 mask) // Add the UI element for this item. buildNewViews(item_id); // Select any newly created object that has the auto rename at top of folder root set. - if(getRootFolder()->getRoot()->needsAutoRename()) + if(mFolderRoot->getRoot()->needsAutoRename()) { setSelection(item_id, FALSE); } @@ -1623,7 +1682,7 @@ void LLInventoryPanel::modelChanged(U32 mask) // Don't process the item if it is the root if (view_item->getRoot() != view_item) { - LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getRootFolder()->getItemByID(model_item->getParentUUID()); + LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolderRoot->getItemByID(model_item->getParentUUID()); // Item has been moved. if (view_item->getParentFolder() != new_parent) { @@ -1631,7 +1690,7 @@ void LLInventoryPanel::modelChanged(U32 mask) { // Item is to be moved and we found its new parent in the panel's directory, so move the item's UI. view_item->getParentFolder()->extractItem(view_item); - view_item->addToFolder(new_parent, getRootFolder()); + view_item->addToFolder(new_parent, mFolderRoot); } else { @@ -1655,12 +1714,18 @@ void LLInventoryPanel::modelChanged(U32 mask) } } +LLFolderView* LLInventoryPanel::getRootFolder() +{ + return mFolderRoot; +} +const LLUUID& LLInventoryPanel::getRootFolderID() const +{ + return mFolderRoot->getListener()->getUUID(); +} void LLInventoryPanel::rebuildViewsFor(const LLUUID& id, U32 mask) { - LLFolderViewItem* old_view = NULL; - - // get old LLFolderViewItem - old_view = mFolders->getItemByID(id); + // Destroy the old view for this ID so we can rebuild it. + LLFolderViewItem* old_view = mFolderRoot->getItemByID(id); if (old_view && id.notNull()) { old_view->destroyView(); @@ -1669,19 +1734,41 @@ void LLInventoryPanel::rebuildViewsFor(const LLUUID& id, U32 mask) buildNewViews(id); } +LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge) +{ + return new LLFolderViewFolder( + bridge->getDisplayName(), + bridge->getIcon(), + mFolderRoot, + bridge); +} + +LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge) +{ + return new LLFolderViewItem( + bridge->getDisplayName(), + bridge->getIcon(), + bridge->getCreationDate(), + mFolderRoot, + bridge); +} + void LLInventoryPanel::buildNewViews(const LLUUID& id) { + LLInventoryObject* const objectp = gInventory.getObject(id); LLFolderViewItem* itemp = NULL; - LLInventoryObject* objectp = gInventory.getObject(id); + if (objectp) - { + { + const LLUUID &parent_id = objectp->getParentUUID(); + LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolderRoot->getItemByID(parent_id); if (objectp->getType() <= LLAssetType::AT_NONE || objectp->getType() >= LLAssetType::AT_COUNT) { - llwarns << "LLInventoryPanel::buildNewViews called with objectp->mType == " - << ((S32) objectp->getType()) - << " (shouldn't happen)" << llendl; + llwarns << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : " + << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID() + << llendl; } else if ((objectp->getType() == LLAssetType::AT_CATEGORY) && (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) // build new view for category @@ -1693,13 +1780,9 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) objectp->getUUID()); if (new_listener) - { - LLFolderViewFolder* folderp = new LLFolderViewFolder(new_listener->getDisplayName(), - new_listener->getIcon(), - mFolders, - new_listener); - - folderp->setItemSortOrder(mFolders->getSortOrder()); + { + LLFolderViewFolder* folderp = createFolderViewFolder(new_listener); + folderp->setItemSortOrder(mFolderRoot->getSortOrder()); itemp = folderp; } } @@ -1713,23 +1796,19 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) this, item->getUUID(), item->getFlags()); - if (new_listener) - { - itemp = new LLFolderViewItem(new_listener->getDisplayName(), - new_listener->getIcon(), - new_listener->getCreationDate(), - mFolders, - new_listener); - } + if (new_listener) + { + itemp = createFolderViewItem(new_listener); + } } - LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolders->getItemByID(objectp->getParentUUID()); + if (itemp) { if (parent_folder) { - itemp->addToFolder(parent_folder, mFolders); + itemp->addToFolder(parent_folder, mFolderRoot); } else { @@ -1739,28 +1818,34 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) } } - if ((id.isNull() || - (objectp && objectp->getType() == LLAssetType::AT_CATEGORY))) + // If this is a folder, add the children of the folder and recursively add any + // child folders. + if (id.isNull() + || (objectp + && objectp->getType() == LLAssetType::AT_CATEGORY)) { LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; - mInventory->lockDirectDescendentArrays(id, categories, items); + if(categories) { - S32 count = categories->count(); - for(S32 i = 0; i < count; ++i) + for (LLViewerInventoryCategory::cat_array_t::const_iterator cat_iter = categories->begin(); + cat_iter != categories->end(); + ++cat_iter) { - LLInventoryCategory* cat = categories->get(i); + const LLViewerInventoryCategory* cat = (*cat_iter); buildNewViews(cat->getUUID()); } } + if(items) { - S32 count = items->count(); - for(S32 i = 0; i < count; ++i) + for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items->begin(); + item_iter != items->end(); + ++item_iter) { - LLInventoryItem* item = items->get(i); + const LLViewerInventoryItem* item = (*item_iter); buildNewViews(item->getUUID()); } } @@ -1803,13 +1888,19 @@ protected: void LLInventoryPanel::openSelected() { - LLFolderViewItem* folder_item = mFolders->getCurSelectedItem(); + LLFolderViewItem* folder_item = mFolderRoot->getCurSelectedItem(); if(!folder_item) return; LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); if(!bridge) return; bridge->openItem(); } +void LLInventoryPanel::unSelectAll() +{ + mFolderRoot->setSelection(NULL, FALSE, FALSE); +} + + BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) { BOOL handled = LLView::handleHover(x, y, mask); @@ -1840,7 +1931,7 @@ BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, if (handled) { - mFolders->setDragAndDropThisFrame(); + mFolderRoot->setDragAndDropThisFrame(); } return handled; @@ -1849,26 +1940,26 @@ BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, void LLInventoryPanel::openAllFolders() { - mFolders->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); - mFolders->arrangeAll(); + mFolderRoot->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); + mFolderRoot->arrangeAll(); } void LLInventoryPanel::closeAllFolders() { - mFolders->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); - mFolders->arrangeAll(); + mFolderRoot->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); + mFolderRoot->arrangeAll(); } void LLInventoryPanel::openDefaultFolderForType(LLAssetType::EType type) { LLUUID category_id = mInventory->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(type)); LLOpenFolderByID opener(category_id); - mFolders->applyFunctorRecursively(opener); + mFolderRoot->applyFunctorRecursively(opener); } void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) { - LLFolderViewItem* itemp = mFolders->getItemByID(obj_id); + LLFolderViewItem* itemp = mFolderRoot->getItemByID(obj_id); if(itemp && itemp->getListener()) { itemp->getListener()->arrangeAndSet(itemp, TRUE, take_keyboard_focus); @@ -1881,10 +1972,16 @@ void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_foc mSelectThisID = obj_id; } } - +void LLInventoryPanel::setSelectCallback(LLFolderView::SelectCallback callback, void* user_data) +{ + if (mFolderRoot) + { + mFolderRoot->setSelectCallback(callback, user_data); + } +} void LLInventoryPanel::clearSelection() { - mFolders->clearSelection(); + mFolderRoot->clearSelection(); mSelectThisID.setNull(); } @@ -1916,9 +2013,15 @@ void LLInventoryPanel::createNewItem(const std::string& name, } -// static DEBUG ONLY: +BOOL LLInventoryPanel::getSinceLogoff() +{ + return getFilter()->isSinceLogoff(); +} + +// DEBUG ONLY +// static void LLInventoryPanel::dumpSelectionInformation(void* user_data) { LLInventoryPanel* iv = (LLInventoryPanel*)user_data; - iv->mFolders->dumpSelectionInformation(); + iv->mFolderRoot->dumpSelectionInformation(); } diff --git a/indra/newview/llinventoryview.h b/indra/newview/llinventoryview.h index 24fd127c0..1a48ccd94 100644 --- a/indra/newview/llinventoryview.h +++ b/indra/newview/llinventoryview.h @@ -69,11 +69,6 @@ class LLSearchEditor; class LLInventoryPanel : public LLPanel { public: - static const std::string DEFAULT_SORT_ORDER; - static const std::string RECENTITEMS_SORT_ORDER; - static const std::string WORNITEMS_SORT_ORDER; - static const std::string INHERIT_SORT_ORDER; - LLInventoryPanel(const std::string& name, const std::string& sort_order_setting, const LLRect& rect, @@ -103,38 +98,36 @@ public: void closeAllFolders(); void openDefaultFolderForType(LLAssetType::EType); void setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus); - void setSelectCallback(LLFolderView::SelectCallback callback, void* user_data) { if (mFolders) mFolders->setSelectCallback(callback, user_data); } + void setSelectCallback(LLFolderView::SelectCallback callback, void* user_data); void clearSelection(); - LLInventoryFilter* getFilter() { return mFolders->getFilter(); } + LLInventoryFilter* getFilter(); + const LLInventoryFilter* getFilter() const; void setFilterTypes(U32 filter); - U32 getFilterTypes() const { return mFolders->getFilterTypes(); } + U32 getFilterTypes() const; void setFilterPermMask(PermissionMask filter_perm_mask); - U32 getFilterPermMask() const { return mFolders->getFilterPermissions(); } + U32 getFilterPermMask() const; void setFilterSubString(const std::string& string); - const std::string getFilterSubString() { return mFolders->getFilterSubString(); } + const std::string getFilterSubString(); void setFilterWorn(bool worn); - bool getFilterWorn() const { return mFolders->getFilterWorn(); } + bool getFilterWorn() const { return mFolderRoot->getFilterWorn(); } - void setSortOrder(U32 order); - U32 getSortOrder() { return mFolders->getSortOrder(); } void setSinceLogoff(BOOL sl); void setHoursAgo(U32 hours); - BOOL getSinceLogoff() { return mFolders->getFilter()->isSinceLogoff(); } + BOOL getSinceLogoff(); void setShowFolderState(LLInventoryFilter::EFolderShow show); LLInventoryFilter::EFolderShow getShowFolderState(); - void setAllowMultiSelect(BOOL allow) { mFolders->setAllowMultiSelect(allow); } + void setAllowMultiSelect(BOOL allow) { mFolderRoot->setAllowMultiSelect(allow); } // This method is called when something has changed about the inventory. void modelChanged(U32 mask); - LLFolderView* getRootFolder() { return mFolders; } + LLFolderView* getRootFolder(); LLScrollableContainerView* getScrollableContainer() { return mScroller; } // DEBUG ONLY: static void dumpSelectionInformation(void* user_data); void openSelected(); - - void unSelectAll() { mFolders->setSelection(NULL, FALSE, FALSE); } + void unSelectAll(); protected: // Given the id and the parent, build all of the folder views. @@ -155,11 +148,31 @@ public: protected: LLInventoryModel* mInventory; LLInventoryObserver* mInventoryObserver; - LLFolderView* mFolders; - LLScrollableContainerView* mScroller; + + BOOL mAllowMultiSelect; + LLFolderView* mFolderRoot; + LLScrollableContainerView* mScroller; + //-------------------------------------------------------------------- + // Sorting + //-------------------------------------------------------------------- +public: + static const std::string DEFAULT_SORT_ORDER; + static const std::string RECENTITEMS_SORT_ORDER; + static const std::string WORNITEMS_SORT_ORDER; + static const std::string INHERIT_SORT_ORDER; + + void setSortOrder(U32 order); + U32 getSortOrder() const; +private: const std::string mSortOrderSetting; LLUUID mSelectThisID; // if non null, select this item + +public: + const LLUUID& getRootFolderID() const; +protected: + virtual LLFolderViewFolder* createFolderViewFolder(LLInvFVBridge * bridge); + virtual LLFolderViewItem* createFolderViewItem(LLInvFVBridge * bridge); }; class LLInventoryView; From 7805508e8de4999ad6db799df434da066fe57e69 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 19 Jan 2012 10:36:56 -0600 Subject: [PATCH 03/13] SH-2827 crashfix. https://bitbucket.org/VirLinden/viewer-development-shining-fixes/changeset/806c10f621af --- indra/llrender/llrender.cpp | 2 -- indra/newview/pipeline.cpp | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 133614e0d..5eec0c553 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -1446,8 +1446,6 @@ void LLRender::loadIdentity() flush(); { - llassert_always(mMatrixMode < NUM_MATRIX_MODES) ; - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].make_identity(); mMatHash[mMatrixMode]++; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 71d345192..a75440d0f 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3432,6 +3432,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) gFrameStats.start(LLFrameStats::RENDER_GEOM); // Initialize lots of GL state to "safe" values + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.matrixMode(LLRender::MM_TEXTURE); gGL.loadIdentity(); gGL.matrixMode(LLRender::MM_MODELVIEW); From b33850622945983562bb9c8fe23bc7bbe9cdb44d Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 19 Jan 2012 19:01:44 -0600 Subject: [PATCH 04/13] VBO updates from Vir Lindens shining fixes. VBO mapping perf improvement. Alpha rigged attachments render fix, hopefully. Crashfix in void pushWireframe. --- indra/llrender/llvertexbuffer.cpp | 150 ++++++++++++---------- indra/llrender/llvertexbuffer.h | 62 +++++---- indra/newview/lldrawpoolavatar.cpp | 6 +- indra/newview/llface.cpp | 183 ++++++++++++++++++++------- indra/newview/llselectmgr.cpp | 51 ++++---- indra/newview/llspatialpartition.cpp | 58 +++++++-- indra/newview/llspatialpartition.h | 3 +- indra/newview/llviewerobject.cpp | 5 +- indra/newview/llvosurfacepatch.cpp | 2 +- indra/newview/llvovolume.cpp | 15 ++- indra/newview/llvowater.cpp | 2 +- indra/newview/llvowlsky.cpp | 2 +- 12 files changed, 339 insertions(+), 200 deletions(-) diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 51543c924..2cca1e5e2 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -2,31 +2,25 @@ * @file llvertexbuffer.cpp * @brief LLVertexBuffer implementation * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -155,7 +149,7 @@ U32 wpo2(U32 i) return r; } -U8* LLVBOPool::allocate(U32& name, U32 size) +volatile U8* LLVBOPool::allocate(U32& name, U32 size) { llassert(nhpo2(size) == size); @@ -166,20 +160,24 @@ U8* LLVBOPool::allocate(U32& name, U32 size) mFreeList.resize(i+1); } - U8* ret = NULL; + volatile U8* ret = NULL; if (mFreeList[i].empty()) { //make a new buffer glGenBuffersARB(1, &name); glBindBufferARB(mType, name); - glBufferDataARB(mType, size, 0, mUsage); LLVertexBuffer::sAllocatedBytes += size; - if (LLVertexBuffer::sDisableVBOMapping) + if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) { + glBufferDataARB(mType, size, 0, mUsage); ret = (U8*) ll_aligned_malloc_16(size); } + else + { //always use a true hint of static draw when allocating non-client-backed buffers + glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB); + } glBindBufferARB(mType, 0); } else @@ -195,7 +193,7 @@ U8* LLVBOPool::allocate(U32& name, U32 size) return ret; } -void LLVBOPool::release(U32 name, U8* buffer, U32 size) +void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) { llassert(nhpo2(size) == size); @@ -208,8 +206,15 @@ void LLVBOPool::release(U32 name, U8* buffer, U32 size) rec.mClientData = buffer; sBytesPooled += size; - - mFreeList[i].push_back(rec); + + if (!LLVertexBuffer::sDisableVBOMapping && mUsage == GL_DYNAMIC_DRAW_ARB) + { + glDeleteBuffersARB(1, &rec.mGLName); + } + else + { + mFreeList[i].push_back(rec); + } } void LLVBOPool::cleanup() @@ -228,7 +233,7 @@ void LLVBOPool::cleanup() if (r.mClientData) { - ll_aligned_free_16(r.mClientData); + ll_aligned_free_16((void*) r.mClientData); } l.pop_front(); @@ -543,7 +548,7 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const { validateRange(start, end, count, indices_offset); - + mMappable = FALSE; gGL.syncMatrices(); llassert(mNumVerts >= 0); @@ -598,7 +603,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const { llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - + mMappable = FALSE; gGL.syncMatrices(); llassert(mNumIndices >= 0); @@ -644,7 +649,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - + mMappable = FALSE; gGL.syncMatrices(); llassert(mNumVerts >= 0); @@ -794,9 +799,25 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : if (mUsage && mUsage != GL_STREAM_DRAW_ARB) { //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default - mUsage = GL_DYNAMIC_DRAW_ARB; + if (sDisableVBOMapping) + { //always use stream draw if VBO mapping is disabled + mUsage = GL_STREAM_DRAW_ARB; + } + else + { + mUsage = GL_DYNAMIC_DRAW_ARB; + } } + if (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping) + { + mMappable = TRUE; + } + else + { + mMappable = FALSE; + } + //zero out offsets for (U32 i = 0; i < TYPE_MAX; i++) { @@ -812,6 +833,7 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : sCount++; } +//static S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices) { S32 offset = 0; @@ -944,11 +966,11 @@ void LLVertexBuffer::releaseBuffer() { if (mUsage == GL_STREAM_DRAW_ARB) { - sStreamVBOPool.release(mGLBuffer, /*(U8*)*/mMappedData, mSize); + sStreamVBOPool.release(mGLBuffer, mMappedData, mSize); } else { - sDynamicVBOPool.release(mGLBuffer, /*(U8*)*/mMappedData, mSize); + sDynamicVBOPool.release(mGLBuffer, mMappedData, mSize); } mGLBuffer = 0; @@ -961,11 +983,11 @@ void LLVertexBuffer::releaseIndices() { if (mUsage == GL_STREAM_DRAW_ARB) { - sStreamIBOPool.release(mGLIndices, /*(U8*)*/mMappedIndexData, mIndicesSize); + sStreamIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); } else { - sDynamicIBOPool.release(mGLIndices, /*(U8*)*/mMappedIndexData, mIndicesSize); + sDynamicIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); } mGLIndices = 0; @@ -1048,7 +1070,7 @@ void LLVertexBuffer::destroyGLBuffer() } else { - FREE_MEM(sPrivatePoolp, /*(U8*)*/mMappedData) ; + FREE_MEM(sPrivatePoolp, (void*) mMappedData) ; mMappedData = NULL; mEmpty = TRUE; } @@ -1069,7 +1091,7 @@ void LLVertexBuffer::destroyGLIndices() } else { - FREE_MEM(sPrivatePoolp, /*(U8*)*/mMappedIndexData) ; + FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData) ; mMappedIndexData = NULL; mEmpty = TRUE; } @@ -1289,7 +1311,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) } // Map for data access -/*volatile */U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) +volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) { bindGLBuffer(true); LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); @@ -1304,7 +1326,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) if (useVBOs()) { - if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) + if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) { if (count == -1) { @@ -1329,7 +1351,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) if (!mapped) { //not already mapped, map new region - MappedRegion region(type, !sDisableVBOMapping && map_range ? -1 : index, count); + MappedRegion region(type, mMappable && map_range ? -1 : index, count); mMappedVertexRegions.push_back(region); } } @@ -1345,13 +1367,13 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) sMappedCount++; stop_glerror(); - if(sDisableVBOMapping) + if(!mMappable) { map_range = false; } else { - U8* src = NULL; + volatile U8* src = NULL; waitFence(); if (gGLManager.mHasMapBufferRange) { @@ -1408,7 +1430,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) llassert(src != NULL); - mMappedData = LL_NEXT_ALIGNED_ADDRESS(src); + mMappedData = LL_NEXT_ALIGNED_ADDRESS(src); mAlignedOffset = mMappedData - src; stop_glerror(); @@ -1421,7 +1443,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) //check the availability of memory LLMemory::logMemoryInfo(TRUE) ; - if(!sDisableVBOMapping) + if(mMappable) { //-------------------- //print out more debug info before crash @@ -1453,7 +1475,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) map_range = false; } - if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping) + if (map_range && gGLManager.mHasMapBufferRange && mMappable) { return mMappedData; } @@ -1463,7 +1485,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) } } -/*volatile */U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) +volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) { LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); bindGLIndices(true); @@ -1478,7 +1500,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) if (useVBOs()) { - if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) + if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) { if (count == -1) { @@ -1500,7 +1522,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) if (!mapped) { //not already mapped, map new region - MappedRegion region(TYPE_INDEX, !sDisableVBOMapping && map_range ? -1 : index, count); + MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count); mMappedIndexRegions.push_back(region); } } @@ -1529,13 +1551,13 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) } } - if(sDisableVBOMapping) + if(!mMappable) { map_range = false; } else { - U8* src = NULL; + volatile U8* src = NULL; waitFence(); if (gGLManager.mHasMapBufferRange) { @@ -1592,7 +1614,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) log_glerror(); LLMemory::logMemoryInfo(TRUE) ; - if(!sDisableVBOMapping) + if(mMappable) { GLint buff; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); @@ -1614,7 +1636,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) map_range = false; } - if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping) + if (map_range && gGLManager.mHasMapBufferRange && mMappable) { return mMappedIndexData; } @@ -1639,7 +1661,7 @@ void LLVertexBuffer::unmapBuffer() bindGLBuffer(true); updated_all = mIndexLocked; //both vertex and index buffers done updating - if(sDisableVBOMapping) + if(!mMappable) { if (!mMappedVertexRegions.empty()) { @@ -1649,7 +1671,7 @@ void LLVertexBuffer::unmapBuffer() const MappedRegion& region = mMappedVertexRegions[i]; S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; S32 length = sTypeSize[region.mType]*region.mCount; - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, /*(U8*)*/mMappedData+offset); + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset); stop_glerror(); } @@ -1658,7 +1680,7 @@ void LLVertexBuffer::unmapBuffer() else { stop_glerror(); - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), /*(U8*)*/mMappedData); + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), (U8*) mMappedData); stop_glerror(); } } @@ -1704,7 +1726,7 @@ void LLVertexBuffer::unmapBuffer() if (mMappedIndexData && mIndexLocked) { bindGLIndices(); - if(sDisableVBOMapping) + if(!mMappable) { if (!mMappedIndexRegions.empty()) { @@ -1713,7 +1735,7 @@ void LLVertexBuffer::unmapBuffer() const MappedRegion& region = mMappedIndexRegions[i]; S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; S32 length = sizeof(U16)*region.mCount; - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, /*(U8*)*/mMappedIndexData+offset); + glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset); stop_glerror(); } @@ -1722,7 +1744,7 @@ void LLVertexBuffer::unmapBuffer() else { stop_glerror(); - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), /*(U8*)*/mMappedIndexData); + glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), (U8*) mMappedIndexData); stop_glerror(); } } @@ -1783,7 +1805,7 @@ template struct VertexBufferStrider { if (type == LLVertexBuffer::TYPE_INDEX) { - /*volatile*/ U8* ptr = vbo.mapIndexBuffer(index, count, map_range); + volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range); if (ptr == NULL) { @@ -1798,8 +1820,8 @@ template struct VertexBufferStrider else if (vbo.hasDataType(type)) { S32 stride = LLVertexBuffer::sTypeSize[type]; - - /*volatile */U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range); + + volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range); if (ptr == NULL) { @@ -2117,7 +2139,7 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) { LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); stop_glerror(); - U8* base = useVBOs() ? (U8*)mAlignedOffset : /*(U8*)*/mMappedData; + volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; /*if ((data_mask & mTypeMask) != data_mask) { diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 85ad44693..baff56286 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -2,31 +2,25 @@ * @file llvertexbuffer.h * @brief LLVertexBuffer wrapper for OpengGL vertex buffer objects * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -67,10 +61,10 @@ public: U32 mType; //size MUST be a power of 2 - U8* allocate(U32& name, U32 size); + volatile U8* allocate(U32& name, U32 size); //size MUST be the size provided to allocate that returned the given name - void release(U32 name, U8* buffer, U32 size); + void release(U32 name, volatile U8* buffer, U32 size); //destroy all records in mFreeList void cleanup(); @@ -79,7 +73,7 @@ public: { public: U32 mGLName; - U8* mClientData; + volatile U8* mClientData; }; typedef std::list record_list_t; @@ -215,8 +209,8 @@ public: LLVertexBuffer(U32 typemask, S32 usage); // map for data access - /*volatile */U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range); - /*volatile */U8* mapIndexBuffer(S32 index, S32 count, bool map_range); + volatile U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range); + volatile U8* mapIndexBuffer(S32 index, S32 count, bool map_range); // set for rendering virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0 @@ -251,17 +245,18 @@ public: S32 getNumVerts() const { return mNumVerts; } S32 getNumIndices() const { return mNumIndices; } - /*volatile */U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; } - /*volatile */U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; } + volatile U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; } + volatile U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; } U32 getTypeMask() const { return mTypeMask; } bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); } S32 getSize() const; S32 getIndicesSize() const { return mIndicesSize; } - /*volatile */U8* getMappedData() const { return mMappedData; } - /*volatile */U8* getMappedIndices() const { return mMappedIndexData; } + volatile U8* getMappedData() const { return mMappedData; } + volatile U8* getMappedIndices() const { return mMappedIndexData; } S32 getOffset(S32 type) const { return mOffsets[type]; } S32 getUsage() const { return mUsage; } - + BOOL isWriteable() const { return (mMappable || mUsage == GL_STREAM_DRAW_ARB) ? TRUE : FALSE; } + void draw(U32 mode, U32 count, U32 indices_offset) const; void drawArrays(U32 mode, U32 offset, U32 count) const; void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const; @@ -285,12 +280,13 @@ protected: U32 mGLIndices; // GL IBO handle U32 mGLArray; // GL VAO handle - /*volatile */U8* mMappedData; // pointer to currently mapped data (NULL if unmapped) - /*volatile */U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped) + volatile U8* mMappedData; // pointer to currently mapped data (NULL if unmapped) + volatile U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped) BOOL mVertexLocked; // if TRUE, vertex buffer is being or has been written to in client memory BOOL mIndexLocked; // if TRUE, index buffer is being or has been written to in client memory BOOL mFinal; // if TRUE, buffer can not be mapped again BOOL mEmpty; // if TRUE, client buffer is empty (or NULL). Old values have been discarded. + mutable BOOL mMappable; // if TRUE, use memory mapping to upload data (otherwise doublebuffer and use glBufferSubData) S32 mOffsets[TYPE_MAX]; std::vector mMappedVertexRegions; diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 162c2e33f..b54a1495a 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1301,7 +1301,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face->setGeomIndex(0); face->setIndicesIndex(0); - if (buffer.isNull() || buffer->getTypeMask() != data_mask) + if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable()) { //make a new buffer if (sShaderLevel > 0) { @@ -1335,7 +1335,9 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* LLMatrix3 mat_normal(mat3); //let getGeometryVolume know if alpha should override shiny - if (face->getFaceColor().mV[3] < 1.f) + U32 type = gPipeline.getPoolTypeFromTE(face->getTextureEntry(), face->getTexture()); + + if (type == LLDrawPool::POOL_ALPHA) { face->setPoolType(LLDrawPool::POOL_ALPHA); } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 06d4bdc03..b41481e26 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -695,6 +695,49 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of tex_coord.mV[1] = t; } +// Transform the texture coordinates for this face. +static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVector4Logical& mask, const LLVector4a& rot0, const LLVector4a& rot1, const LLVector4a& offset, const LLVector4a& scale) +{ + //tex coord is two coords, + LLVector4a st; + + // Texture transforms are done about the center of the face. + st.setAdd(tex_coord, trans); + + // Handle rotation + LLVector4a rot_st; + + // + LLVector4a s0; + s0.splat(st, 0); + LLVector4a s1; + s1.splat(st, 2); + LLVector4a ss; + ss.setSelectWithMask(mask, s1, s0); + + LLVector4a a; + a.setMul(rot0, ss); + + // + LLVector4a t0; + t0.splat(st, 1); + LLVector4a t1; + t1.splat(st, 3); + LLVector4a tt; + tt.setSelectWithMask(mask, t1, t0); + + LLVector4a b; + b.setMul(rot1, tt); + + st.setAdd(a,b); + + // Then scale + st.mul(scale); + + // Then offset + tex_coord.setAdd(st, offset); +} + bool less_than_max_mag(const LLVector4a& vec) { @@ -1069,7 +1112,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, updateRebuildFlags(); } - bool map_range = gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange; + + //don't use map range (generates many redundant unmap calls) + bool map_range = false; //gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange; if (mVertexBuffer.notNull()) { @@ -1095,16 +1140,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } LLStrider vert; - LLVector4a* vertices = NULL; LLStrider tex_coords; LLStrider tex_coords2; - LLVector4a* normals = NULL; LLStrider norm; LLStrider colors; - LLVector4a* binormals = NULL; LLStrider binorm; LLStrider indicesp; - LLVector4a* weights = NULL; LLStrider wght; BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME); @@ -1172,7 +1213,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_INDEX); mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, map_range); - __m128i* dst = (__m128i*) indicesp.get(); + volatile __m128i* dst = (__m128i*) indicesp.get(); __m128i* src = (__m128i*) vf.mIndices; __m128i offset = _mm_set1_epi16(index_offset); @@ -1181,12 +1222,17 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, for (S32 i = 0; i < end; i++) { __m128i res = _mm_add_epi16(src[i], offset); - _mm_storeu_si128(dst+i, res); + _mm_storeu_si128((__m128i*) dst++, res); } - for (S32 i = end*8; i < num_indices; ++i) { - indicesp[i] = vf.mIndices[i]+index_offset; + //LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_INDEX_TAIL); + U16* idx = (U16*) dst; + + for (S32 i = end*8; i < num_indices; ++i) + { + *idx++ = vf.mIndices[i]+index_offset; + } } if (map_range) @@ -1351,11 +1397,37 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } else { - for (S32 i = 0; i < num_vertices; i++) + F32* dst = (F32*) tex_coords.get(); + LLVector4a* src = (LLVector4a*) vf.mTexCoords; + + LLVector4a trans; + trans.splat(-0.5f); + + LLVector4a rot0; + rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang); + + LLVector4a rot1; + rot1.set(sin_ang, cos_ang, sin_ang, cos_ang); + + LLVector4a scale; + scale.set(ms, mt, ms, mt); + + LLVector4a offset; + offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f); + + LLVector4Logical mask; + mask.clear(); + mask.setElement<2>(); + mask.setElement<3>(); + + U32 count = num_vertices/2 + num_vertices%2; + + for (U32 i = 0; i < count; i++) { - LLVector2 tc(vf.mTexCoords[i]); - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - *tex_coords++ = tc; + LLVector4a res = *src++; + xform4a(res, trans, mask, rot0, rot1, offset, scale); + res.store4a(dst); + dst += 4; } } } @@ -1526,44 +1598,53 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, llassert(num_vertices > 0); mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range); - vertices = (LLVector4a*) vert.get(); - + + LLMatrix4a mat_vert; mat_vert.loadu(mat_vert_in); LLVector4a* src = vf.mPositions; - LLVector4a* dst = vertices; + volatile F32* dst = (volatile F32*) vert.get(); - LLVector4a* end = dst+num_vertices; - do - { - mat_vert.affineTransform(*src++, *dst++); - } - while(dst < end); + volatile F32* end = dst+num_vertices*4; + LLVector4a res; + + LLVector4a texIdx; F32 index = (F32) (mTextureIndex < 255 ? mTextureIndex : 0); - llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); - F32 *index_dst = (F32*) vertices; - F32 *index_end = (F32*) end; - index_dst += 3; - index_end += 3; - do - { - *index_dst = index; - index_dst += 4; - } - while (index_dst < index_end); + LLVector4Logical mask; + mask.clear(); + mask.setElement<3>(); - S32 aligned_pad_vertices = mGeomCount - num_vertices; - LLVector4a* last_vec = end - 1; - while (aligned_pad_vertices > 0) + texIdx.set(0,0,0,index); + { - --aligned_pad_vertices; - *dst++ = *last_vec; + LLVector4a tmp; + + do + { + mat_vert.affineTransform(*src++, res); + tmp.setSelectWithMask(mask, texIdx, res); + tmp.store4a((F32*) dst); + dst += 4; + } + while(dst < end); } - + + { + S32 aligned_pad_vertices = mGeomCount - num_vertices; + res.set(res[0], res[1], res[2], 0.f); + + while (aligned_pad_vertices > 0) + { + --aligned_pad_vertices; + res.store4a((F32*) dst); + dst += 4; + } + } + if (map_range) { mVertexBuffer->flush(); @@ -1574,14 +1655,15 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_NORMAL); mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range); - normals = (LLVector4a*) norm.get(); + F32* normals = (F32*) norm.get(); for (S32 i = 0; i < num_vertices; i++) { LLVector4a normal; mat_normal.rotate(vf.mNormals[i], normal); normal.normalize3fast(); - normals[i] = normal; + normal.store4a(normals); + normals += 4; } if (map_range) @@ -1594,14 +1676,15 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_BINORMAL); mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range); - binormals = (LLVector4a*) binorm.get(); + F32* binormals = (F32*) binorm.get(); for (S32 i = 0; i < num_vertices; i++) { LLVector4a binormal; mat_normal.rotate(vf.mBinormals[i], binormal); binormal.normalize3fast(); - binormals[i] = binormal; + binormal.store4a(binormals); + binormals += 4; } if (map_range) @@ -1614,8 +1697,8 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { LLFastTimer t(LLFastTimer::FTM_FACE_GEOM_WEIGHTS); mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range); - weights = (LLVector4a*) wght.get(); - LLVector4a::memcpyNonAliased16((F32*) weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); + F32* weights = (F32*) wght.get(); + LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); if (map_range) { mVertexBuffer->flush(); @@ -1634,7 +1717,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, src.loadua((F32*) vec); - LLVector4a* dst = (LLVector4a*) colors.get(); + F32* dst = (F32*) colors.get(); S32 num_vecs = num_vertices/4; if (num_vertices%4 > 0) { @@ -1643,7 +1726,8 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, for (S32 i = 0; i < num_vecs; i++) { - dst[i] = src; + src.store4a(dst); + dst += 4; } if (map_range) @@ -1673,7 +1757,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, src.loadua((F32*) vec); - LLVector4a* dst = (LLVector4a*) emissive.get(); + F32* dst = (F32*) emissive.get(); S32 num_vecs = num_vertices/4; if (num_vertices%4 > 0) { @@ -1682,7 +1766,8 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, for (S32 i = 0; i < num_vecs; i++) { - dst[i] = src; + src.store4a(dst); + dst += 4; } if (map_range) diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 72de68d0c..1733cac0d 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -5571,38 +5571,37 @@ BOOL LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power) //helper function for pushing relevant vertices from drawable to GL void pushWireframe(LLDrawable* drawable) { - if (drawable->isState(LLDrawable::RIGGED)) - { //render straight from rigged volume if this is a rigged attachment - LLVOVolume* vobj = drawable->getVOVolume(); - if (vobj) - { - vobj->updateRiggedVolume(); - LLRiggedVolume* rigged_volume = vobj->getRiggedVolume(); - if (rigged_volume) - { - LLVertexBuffer::unbind(); - gGL.pushMatrix(); - gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix); - for (S32 i = 0; i < rigged_volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = rigged_volume->getVolumeFace(i); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, face.mTexCoords, face.mNumIndices, face.mIndices); - } - gGL.popMatrix(); - } - } - } - else + LLVOVolume* vobj = drawable->getVOVolume(); + if (vobj) { - for (S32 i = 0; i < drawable->getNumFaces(); ++i) + LLVertexBuffer::unbind(); + gGL.pushMatrix(); + gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix); + + LLVolume* volume = NULL; + + if (drawable->isState(LLDrawable::RIGGED)) { - LLFace* face = drawable->getFace(i); - if (face->verify()) + vobj->updateRiggedVolume(); + volume = vobj->getRiggedVolume(); + } + else + { + volume = vobj->getVolume(); + } + + if (volume) + { + for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { - pushVerts(face, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0); + const LLVolumeFace& face = volume->getVolumeFace(i); + LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, face.mTexCoords, face.mNumIndices, face.mIndices); } } + + gGL.popMatrix(); } + } void LLSelectNode::renderOneWireframe(const LLColor4& color) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 83c9833c4..9e766bb2a 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -34,6 +34,10 @@ #include "llspatialpartition.h" +#include "llappviewer.h" +#include "lltexturecache.h" +#include "lltexturefetch.h" +#include "llimageworker.h" #include "llviewerwindow.h" #include "llviewerobjectlist.h" #include "llvovolume.h" @@ -43,14 +47,13 @@ #include "llface.h" #include "llfloatertools.h" #include "llviewercontrol.h" -#include "llagent.h" #include "llviewerregion.h" #include "llcamera.h" #include "pipeline.h" #include "llmeshrepository.h" #include "llrender.h" #include "lloctree.h" -#include "llvoavatar.h" +#include "llphysicsshapebuilderutil.h" #include "llvoavatar.h" #include "llvolumemgr.h" #include "llglslshader.h" @@ -262,7 +265,7 @@ U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center) void LLSpatialGroup::buildOcclusion() { - if (mOcclusionVerts.isNull()) + //if (mOcclusionVerts.isNull()) { mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, @@ -608,7 +611,9 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) if (vertex_count > 0 && index_count > 0) { //create vertex buffer containing volume geometry for this node group->mBuilt = 1.f; - if (group->mVertexBuffer.isNull() || (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs)) + if (group->mVertexBuffer.isNull() || + !group->mVertexBuffer->isWriteable() || + (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs)) { group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage); group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true); @@ -1106,6 +1111,7 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) { mOcclusionQuery[i] = 0; + mOcclusionIssued[i] = 0; mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0; mVisible[i] = 0; } @@ -1440,10 +1446,27 @@ void LLSpatialGroup::checkOcclusion() } else if (isOcclusionState(QUERY_PENDING)) { //otherwise, if a query is pending, read it back + GLuint available = 0; if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) { glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + + if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) + { //query was issued last frame, wait until it's available + S32 max_loop = 1024; + //LLFastTimer t(LLFastTimer::FTM_OCCLUSION_WAIT); + while (!available && max_loop-- > 0) + { + F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f); + //do some usefu work while we wait + LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread + LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread + LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread + + glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + } + } } else { @@ -1549,6 +1572,8 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) { //LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS); + //store which frame this query was issued on + mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount; glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); @@ -2987,11 +3012,7 @@ void renderRaycast(LLDrawable* drawablep) for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { const LLVolumeFace& face = volume->getVolumeFace(i); - if (!face.mOctree) - { - ((LLVolumeFace*) &face)->createOctree(); - } - + gGL.pushMatrix(); gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix); @@ -3014,9 +3035,6 @@ void renderRaycast(LLDrawable* drawablep) LLVector4a dir; dir.setSub(enda, starta); - F32 t = 1.f; - - LLRenderOctreeRaycast render(starta, dir, &t); gGL.flush(); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); @@ -3028,8 +3046,20 @@ void renderRaycast(LLDrawable* drawablep) gGL.syncMatrices(); glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices); } - - render.traverse(face.mOctree); + + if (!volume->isUnique()) + { + F32 t = 1.f; + + if (!face.mOctree) + { + ((LLVolumeFace*) &face)->createOctree(); + } + + LLRenderOctreeRaycast render(starta, dir, &t); + + render.traverse(face.mOctree); + } gGL.popMatrix(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index f43a21d6a..c36b29752 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -46,7 +46,7 @@ #include "lldrawpool.h" #include "llface.h" #include "llviewercamera.h" - +#include "llvector4a.h" #include #define SG_STATE_INHERIT_MASK (OCCLUDED) @@ -368,6 +368,7 @@ protected: U32 mState; U32 mOcclusionState[LLViewerCamera::NUM_CAMERAS]; + U32 mOcclusionIssued[LLViewerCamera::NUM_CAMERAS]; S32 mLODHash; static S32 sLODSeed; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index d7ae2822a..062d0695a 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5457,11 +5457,12 @@ void LLViewerObject::dirtyMesh() { if (mDrawable) { - LLSpatialGroup* group = mDrawable->getSpatialGroup(); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL); + /*LLSpatialGroup* group = mDrawable->getSpatialGroup(); if (group) { group->dirtyMesh(); - } + }*/ } } diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 0381a7c90..d3c1c3421 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -71,7 +71,7 @@ public: return; } - U8* base = useVBOs() ? (U8*) mAlignedOffset : /*(U8*)*/ mMappedData; + volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; //assume tex coords 2 and 3 are present U32 type_mask = mTypeMask | MAP_TEXCOORD2 | MAP_TEXCOORD3; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 79c560088..4b5c0375d 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4052,17 +4052,20 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: //create/delete/resize vertex buffer if needed LLVertexBuffer* buffer = NULL; - LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter); + + { //try to find a buffer to reuse + LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter); - if (found_iter != group->mBufferMap[mask].end()) - { - if ((U32) buffer_index < found_iter->second.size()) + if (found_iter != group->mBufferMap[mask].end()) { - buffer = found_iter->second[buffer_index]; + if ((U32) buffer_index < found_iter->second.size()) + { + buffer = found_iter->second[buffer_index]; + } } } - if (!buffer) + if (!buffer || !buffer->isWriteable()) { //create new buffer if needed buffer = createVertexBuffer(mask, buffer_usage); buffer->allocateBuffer(geom_count, index_count, TRUE); diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 66af97b81..d02229b90 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -171,7 +171,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) indices_per_quad * num_quads); LLVertexBuffer* buff = face->getVertexBuffer(); - if (!buff) + if (!buff || !buff->isWriteable()) { buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB); buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp index bdfe68f2d..eae95e716 100644 --- a/indra/newview/llvowlsky.cpp +++ b/indra/newview/llvowlsky.cpp @@ -775,7 +775,7 @@ BOOL LLVOWLSky::updateStarGeometry(LLDrawable *drawable) LLStrider colorsp; LLStrider texcoordsp; - if (mStarsVerts.isNull()) + if (mStarsVerts.isNull() || !mStarsVerts->isWriteable()) { mStarsVerts = new LLVertexBuffer(LLDrawPoolWLSky::STAR_VERTEX_DATA_MASK, GL_DYNAMIC_DRAW); mStarsVerts->allocateBuffer(getStarsNumVerts()*6, 0, TRUE); From 4c201a9b839f9a503586bb614a3469da720d70f4 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 20 Jan 2012 19:09:44 -0600 Subject: [PATCH 05/13] Inv fetch migrated from LLInventoryModel to LLInventoryModelBackgroundFetch singleton. --- indra/newview/CMakeLists.txt | 2 + indra/newview/floaterao.cpp | 11 +- indra/newview/llfloaterworldmap.cpp | 8 +- indra/newview/llfolderview.cpp | 7 +- indra/newview/llinventoryactions.cpp | 3 +- indra/newview/llinventorybridge.cpp | 3 +- indra/newview/llinventorymodel.cpp | 533 ---------------- indra/newview/llinventorymodel.h | 29 +- .../llinventorymodelbackgroundfetch.cpp | 600 ++++++++++++++++++ .../newview/llinventorymodelbackgroundfetch.h | 94 +++ indra/newview/llinventoryview.cpp | 13 +- indra/newview/llpreviewgesture.cpp | 5 +- indra/newview/llstartup.cpp | 5 +- indra/newview/lltexturectrl.cpp | 7 +- indra/newview/llviewerinventory.cpp | 3 +- .../statemachine/aifetchinventoryfolder.cpp | 3 +- 16 files changed, 740 insertions(+), 586 deletions(-) create mode 100644 indra/newview/llinventorymodelbackgroundfetch.cpp create mode 100644 indra/newview/llinventorymodelbackgroundfetch.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 577b646ff..d360f0392 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -294,6 +294,7 @@ set(viewer_SOURCE_FILES llinventoryfunctions.cpp llinventoryicon.cpp llinventorymodel.cpp + llinventorymodelbackgroundfetch.cpp llinventoryobserver.cpp llinventoryview.cpp lljoystickbutton.cpp @@ -768,6 +769,7 @@ set(viewer_HEADER_FILES llinventoryfunctions.h llinventoryicon.h llinventorymodel.h + llinventorymodelbackgroundfetch.h llinventoryobserver.h llinventoryview.h lljoystickbutton.h diff --git a/indra/newview/floaterao.cpp b/indra/newview/floaterao.cpp index 3d3ee5847..d15b20e92 100644 --- a/indra/newview/floaterao.cpp +++ b/indra/newview/floaterao.cpp @@ -26,6 +26,7 @@ #include "llinventory.h" #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryview.h" #include "roles_constants.h" #include "llviewerregion.h" @@ -126,7 +127,7 @@ BOOL AOInvTimer::tick() if (!(gSavedSettings.getBOOL("AOEnabled"))) return TRUE; if(LLStartUp::getStartupState() >= STATE_INVENTORY_SEND) { - if(gInventory.isEverythingFetched()) + if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) { // cmdline_printchat("Inventory fetched, loading AO."); LLFloaterAO::init(); @@ -667,7 +668,7 @@ void LLFloaterAO::init() if(LLStartUp::getStartupState() >= STATE_INVENTORY_SEND) { - if(gInventory.isEverythingFetched()) + if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) { LLUUID configncitem = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); if (configncitem.notNull()) @@ -964,7 +965,7 @@ BOOL LLFloaterAO::stopMotion(const LLUUID& id, BOOL stop_immediate, BOOL stand) void LLFloaterAO::onClickReloadCard(void* user_data) { - if(gInventory.isEverythingFetched()) + if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) { LLFloaterAO::init(); } @@ -972,7 +973,7 @@ void LLFloaterAO::onClickReloadCard(void* user_data) void LLFloaterAO::onClickOpenCard(void* user_data) { - if(gInventory.isEverythingFetched()) + if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) { LLUUID configncitem = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); if (configncitem.notNull()) @@ -1419,7 +1420,7 @@ private: const LLUUID& LLFloaterAO::getAssetIDByName(const std::string& name) { - if (name.empty() || !(gInventory.isEverythingFetched())) return LLUUID::null; + if (name.empty() || !(LLInventoryModelBackgroundFetch::instance().isEverythingFetched())) return LLUUID::null; LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 6e1db8a0a..62f55dd65 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -52,6 +52,10 @@ #include "lldraghandle.h" #include "llfirstuse.h" #include "llfocusmgr.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llinventoryobserver.h" #include "lllandmarklist.h" #include "llnotificationsutil.h" #include "lllineeditor.h" @@ -70,7 +74,7 @@ #include "llappviewer.h" #include "llmapimagetype.h" #include "llweb.h" -#include "llinventoryfunctions.h" + #include "llglheaders.h" @@ -314,7 +318,7 @@ void LLFloaterWorldMap::show(void*, BOOL center_on_target) // Start speculative download of landmarks LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - gInventory.startBackgroundFetch(landmark_folder_id); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(landmark_folder_id); gFloaterWorldMap->childSetFocus("location", TRUE); gFocusMgr.triggerFocusFlash(); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 16b26bb26..ad0dead06 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -49,6 +49,7 @@ #include "llinventoryclipboard.h" // *TODO: remove this once hack below gone. #include "llinventoryview.h"// hacked in for the bonus context menu items. #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llkeyboard.h" #include "lllineeditor.h" #include "llmenugl.h" @@ -1308,7 +1309,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) // when applying a filter, matching folders get their contents downloaded first if (filter.isNotDefault() && getFiltered(filter.getMinRequiredGeneration()) && (mListener && !gInventory.isCategoryComplete(mListener->getUUID()))) { - gInventory.startBackgroundFetch(mListener->getUUID()); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(mListener->getUUID()); } // now query children @@ -3319,7 +3320,7 @@ void LLFolderView::draw() } else { - if (gInventory.backgroundFetchActive() || mCompletedFilterGeneration < mFilter.getMinRequiredGeneration()) + if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mCompletedFilterGeneration < mFilter.getMinRequiredGeneration()) { mStatusText = std::string("Searching..."); // *TODO:translate sFont->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); @@ -5123,7 +5124,7 @@ std::string LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (!gInventory.backgroundFetchActive() && filtered_by_type && !filtered_by_all_types) + if (!LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() && filtered_by_type && !filtered_by_all_types) { mFilterText += " - "; if (num_filter_types < 5) diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 14cad7cc6..1ff9d6709 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -63,6 +63,7 @@ #include "lliconctrl.h" #include "llinventoryfunctions.h" #include "llinventoryclipboard.h" +#include "llinventorymodelbackgroundfetch.h" #include "lllineeditor.h" #include "llmenugl.h" #include "llpreviewanim.h" @@ -525,7 +526,7 @@ class LLRefreshInvModel : public inventory_listener_t LLInventoryModel* model = mPtr->getPanel()->getModel(); if(!model) return false; model->empty(); - model->startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); return true; } }; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index baa318313..9d9110eb2 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -39,6 +39,7 @@ #include "llinventorydefines.h" #include "llinventoryfunctions.h" #include "llinventoryicon.h" +#include "llinventorymodelbackgroundfetch.h" #include "message.h" @@ -802,7 +803,7 @@ BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const if (*type == DAD_CATEGORY) { - gInventory.startBackgroundFetch(obj->getUUID()); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(obj->getUUID()); } rv = TRUE; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 5745b5704..32e0fc6c2 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -78,22 +78,6 @@ #include "process.h" #endif -const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; -const S32 MAX_FETCH_RETRIES = 10; -BOOL LLInventoryModel::sBackgroundFetchActive = FALSE; -BOOL LLInventoryModel::sAllFoldersFetched = FALSE; -BOOL LLInventoryModel::sFullFetchStarted = FALSE; -S32 LLInventoryModel::sNumFetchRetries = 0; -F32 LLInventoryModel::sMinTimeBetweenFetches = 0.3f; -F32 LLInventoryModel::sMaxTimeBetweenFetches = 10.f; -BOOL LLInventoryModel::sTimelyFetchPending = FALSE; -LLFrameTimer LLInventoryModel::sFetchTimer; -S16 LLInventoryModel::sBulkFetchCount = 0; - -// RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue -static std::deque sFetchQueue; - - // Increment this if the inventory contents change in a non-backwards-compatible way. // For viewers with link items support, former caches are incorrect. const S32 LLInventoryModel::sCurrentInvCacheVersion = 2; @@ -1384,523 +1368,6 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const return cat->fetchDescendents(); } -//Initialize statics. -bool LLInventoryModel::isBulkFetchProcessingComplete() -{ - return ( (sFetchQueue.empty() - && sBulkFetchCount<=0) ? TRUE : FALSE ) ; -} - -class fetchDescendentsResponder: public LLHTTPClient::Responder -{ - public: - fetchDescendentsResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; - //fetchDescendentsResponder() {}; - void result(const LLSD& content); - void error(U32 status, const std::string& reason); - public: - typedef std::vector folder_ref_t; - protected: - LLSD mRequestSD; -}; - -//If we get back a normal response, handle it here -// Note: this is the handler for WebFetchInventoryDescendents and agent/inventory caps -void fetchDescendentsResponder::result(const LLSD& content) -{ - if (content.has("folders")) - { - - for(LLSD::array_const_iterator folder_it = content["folders"].beginArray(); - folder_it != content["folders"].endArray(); - ++folder_it) - { - LLSD folder_sd = *folder_it; - - - //LLUUID agent_id = folder_sd["agent_id"]; - - //if(agent_id != gAgent.getID()) //This should never happen. - //{ - // llwarns << "Got a UpdateInventoryItem for the wrong agent." - // << llendl; - // break; - //} - - LLUUID parent_id = folder_sd["folder_id"]; - LLUUID owner_id = folder_sd["owner_id"]; - S32 version = (S32)folder_sd["version"].asInteger(); - S32 descendents = (S32)folder_sd["descendents"].asInteger(); - LLPointer tcategory = new LLViewerInventoryCategory(owner_id); - - if (parent_id.isNull()) - { - LLPointer titem = new LLViewerInventoryItem; - for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); - item_it != folder_sd["items"].endArray(); - ++item_it) - { - LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - if (lost_uuid.notNull()) - { - LLSD item = *item_it; - titem->unpackMessage(item); - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - titem->setParent(lost_uuid); - titem->updateParentOnServer(FALSE); - gInventory.updateItem(titem); - gInventory.notifyObservers(); - - } - } - } - - LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id); - if (!pcat) - { - continue; - } - - for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray(); - category_it != folder_sd["categories"].endArray(); - ++category_it) - { - LLSD category = *category_it; - tcategory->fromLLSD(category); - - if (LLInventoryModel::sFullFetchStarted) - { - sFetchQueue.push_back(tcategory->getUUID()); - } - else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) ) - { - gInventory.updateCategory(tcategory); - } - - } - LLPointer titem = new LLViewerInventoryItem; - for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); - item_it != folder_sd["items"].endArray(); - ++item_it) - { - LLSD item = *item_it; - titem->unpackMessage(item); - - gInventory.updateItem(titem); - } - - // set version and descendentcount according to message. - LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); - if(cat) - { - cat->setVersion(version); - cat->setDescendentCount(descendents); - } - - } - } - - if (content.has("bad_folders")) - { - for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray(); - folder_it != content["bad_folders"].endArray(); - ++folder_it) - { - LLSD folder_sd = *folder_it; - - //These folders failed on the dataserver. We probably don't want to retry them. - LL_INFOS("Inventory") << "Folder " << folder_sd["folder_id"].asString() - << "Error: " << folder_sd["error"].asString() << LL_ENDL; - } - } - - LLInventoryModel::incrBulkFetch(-1); - - if (LLInventoryModel::isBulkFetchProcessingComplete()) - { - LL_DEBUGS("Inventory") << "Inventory fetch completed" << LL_ENDL; - if (LLInventoryModel::sFullFetchStarted) - { - LLInventoryModel::sAllFoldersFetched = TRUE; - } - LLInventoryModel::stopBackgroundFetch(); - } - - gInventory.notifyObservers(); -} - -//If we get back an error (not found, etc...), handle it here -void fetchDescendentsResponder::error(U32 status, const std::string& reason) -{ - LL_INFOS("Inventory") << "fetchDescendentsResponder::error " - << status << ": " << reason << LL_ENDL; - - LLInventoryModel::incrBulkFetch(-1); - - if (status==499) //timed out. Let's be awesome! - { - for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); - folder_it != mRequestSD["folders"].endArray(); - ++folder_it) - { - LLSD folder_sd = *folder_it; - LLUUID folder_id = folder_sd["folder_id"]; - sFetchQueue.push_front(folder_id); - } - } - else - { - if (LLInventoryModel::isBulkFetchProcessingComplete()) - { - if (LLInventoryModel::sFullFetchStarted) - { - LLInventoryModel::sAllFoldersFetched = TRUE; - } - LLInventoryModel::stopBackgroundFetch(); - } - } - gInventory.notifyObservers(); -} - -//static Bundle up a bunch of requests to send all at once. -void LLInventoryModel::bulkFetch(std::string url) -{ - //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. - //If there are items in sFetchQueue, we want to check the time since the last bulkFetch was - //sent. If it exceeds our retry time, go ahead and fire off another batch. - //Stopbackgroundfetch will be run from the Responder instead of here. - - S16 max_concurrent_fetches=8; - F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely. - if (sMinTimeBetweenFetches < new_min_time) sMinTimeBetweenFetches=new_min_time; //HACK! See above. - - if(gDisconnected - || sBulkFetchCount > max_concurrent_fetches - || sFetchTimer.getElapsedTimeF32() < sMinTimeBetweenFetches) - { - return; // just bail if we are disconnected. - } - - U32 folder_count=0; - U32 max_batch_size=5; - - U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1; - - LLSD body; - LLSD body_lib; - while( !(sFetchQueue.empty() ) && (folder_count < max_batch_size) ) - { - if (sFetchQueue.front().isNull()) //DEV-17797 - { - LLSD folder_sd; - folder_sd["folder_id"] = LLUUID::null.asString(); - folder_sd["owner_id"] = gAgent.getID(); - folder_sd["sort_order"] = (LLSD::Integer)sort_order; - folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE; - folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; - body["folders"].append(folder_sd); - folder_count++; - } - else - { - - - LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front()); - - if (cat) - { - // Pre-emptive strike - //if(!(gInventory.isObjectDescendentOf(cat->getUUID(), gSystemFolderRoot))) - if(true) - { - // - if ( LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) - { - LLSD folder_sd; - folder_sd["folder_id"] = cat->getUUID(); - folder_sd["owner_id"] = cat->getOwnerID(); - folder_sd["sort_order"] = (LLSD::Integer)sort_order; - folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted; - folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; - - LL_DEBUGS("Inventory") << " fetching "<getUUID()<<" with cat owner "<getOwnerID()<<" and agent" << gAgent.getID() << LL_ENDL; - if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) - body_lib["folders"].append(folder_sd); - else - body["folders"].append(folder_sd); - folder_count++; - } - if (sFullFetchStarted) - { //Already have this folder but append child folders to list. - // add all children to queue - parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID()); - if (cat_it != gInventory.mParentChildCategoryTree.end()) - { - cat_array_t* child_categories = cat_it->second; - - for (S32 child_num = 0; child_num < child_categories->count(); child_num++) - { - sFetchQueue.push_back(child_categories->get(child_num)->getUUID()); - } - } - - } - // - } - // - } - } - sFetchQueue.pop_front(); - } - - if (folder_count > 0) - { - sBulkFetchCount++; - if (body["folders"].size()) - { - LLHTTPClient::post(url, body, new fetchDescendentsResponder(body),300.0); - } - if (body_lib["folders"].size()) - { - std::string url_lib; - url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents"); - LLHTTPClient::post(url_lib, body_lib, new fetchDescendentsResponder(body_lib),300.0); - } - sFetchTimer.reset(); - } - else if (isBulkFetchProcessingComplete()) - { - if (sFullFetchStarted) - { - sAllFoldersFetched = TRUE; - } - stopBackgroundFetch(); - } -} - -// static -bool LLInventoryModel::isEverythingFetched() -{ - return (sAllFoldersFetched ? true : false); -} - -//static -BOOL LLInventoryModel::backgroundFetchActive() -{ - return sBackgroundFetchActive; -} - -//static -void LLInventoryModel::startBackgroundFetch(const LLUUID& cat_id) -{ - if (!sAllFoldersFetched) - { - if (cat_id.isNull()) - { - if (!sFullFetchStarted) - { - sFullFetchStarted = TRUE; - sFetchQueue.push_back(gInventory.getLibraryRootFolderID()); - sFetchQueue.push_back(gInventory.getRootFolderID()); - if (!sBackgroundFetchActive) - { - sBackgroundFetchActive = TRUE; - gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL); - } - } - } - else - { - // specific folder requests go to front of queue - // Remove it from the queue first, to avoid getting it twice. - if (!sFetchQueue.empty() && sFetchQueue.front() != cat_id) - { - std::deque::iterator old_entry = std::find(sFetchQueue.begin(), sFetchQueue.end(), cat_id); - if (old_entry != sFetchQueue.end()) - { - sFetchQueue.erase(old_entry); - } - } - sFetchQueue.push_front(cat_id); - if (!sBackgroundFetchActive) - { - sBackgroundFetchActive = TRUE; - gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL); - } - } - } -} - -//static -void LLInventoryModel::findLostItems() -{ - sFetchQueue.push_back(LLUUID::null); - if (!sBackgroundFetchActive) - { - sBackgroundFetchActive = TRUE; - gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL); - } -} - -//static -void LLInventoryModel::stopBackgroundFetch() -{ - if (sBackgroundFetchActive) - { - sBackgroundFetchActive = FALSE; - gIdleCallbacks.deleteFunction(&LLInventoryModel::backgroundFetch, NULL); - sBulkFetchCount=0; - sMinTimeBetweenFetches=0.0f; - if (!sAllFoldersFetched) - { - // We didn't finish this, so set it to FALSE in order to be able to start it again. - sFullFetchStarted=FALSE; - } - } -} - -//static -void LLInventoryModel::backgroundFetch(void*) -{ - if (sBackgroundFetchActive && gAgent.getRegion()) - { - // If we'll be using the capability, we'll be sending batches and the background thing isn't as important. - std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents"); - if (false /*gSavedSettings.getBOOL("UseHTTPInventory")*/ && !url.empty()) - { - bulkFetch(url); - return; - } - -#if 1 - //DEPRECATED OLD CODE FOLLOWS. - // no more categories to fetch, stop fetch process - if (sFetchQueue.empty()) - { - llinfos << "Inventory fetch completed" << llendl; - if (sFullFetchStarted) - { - sAllFoldersFetched = TRUE; - } - stopBackgroundFetch(); - return; - } - - F32 fast_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.1f); - F32 slow_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.5f); - if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() > slow_fetch_time) - { - // double timeouts on failure - sMinTimeBetweenFetches = llmin(sMinTimeBetweenFetches * 2.f, 10.f); - sMaxTimeBetweenFetches = llmin(sMaxTimeBetweenFetches * 2.f, 120.f); - llinfos << "Inventory fetch times grown to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl; - // fetch is no longer considered "timely" although we will wait for full time-out - sTimelyFetchPending = FALSE; - } - - while(1) - { - if (sFetchQueue.empty()) - { - break; - } - - if(gDisconnected) - { - // just bail if we are disconnected. - break; - } - - LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front()); - - // category has been deleted, remove from queue. - if (!cat) - { - sFetchQueue.pop_front(); - continue; - } - - if (sFetchTimer.getElapsedTimeF32() > sMinTimeBetweenFetches && - LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) - { - // category exists but has no children yet, fetch the descendants - // for now, just request every time and rely on retry timer to throttle - if (cat->fetchDescendents()) - { - sFetchTimer.reset(); - sTimelyFetchPending = TRUE; - } - else - { - // The catagory also tracks if it has expired and here it says it hasn't - // yet. Get out of here because nothing is going to happen until we - // update the timers. - break; - } - } - // do I have all my children? - else if (gInventory.isCategoryComplete(sFetchQueue.front())) - { - // finished with this category, remove from queue - sFetchQueue.pop_front(); - - // add all children to queue - parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID()); - if (cat_it != gInventory.mParentChildCategoryTree.end()) - { - cat_array_t* child_categories = cat_it->second; - - for (S32 child_num = 0; child_num < child_categories->count(); child_num++) - { - sFetchQueue.push_back(child_categories->get(child_num)->getUUID()); - } - } - - // we received a response in less than the fast time - if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() < fast_fetch_time) - { - // shrink timeouts based on success - sMinTimeBetweenFetches = llmax(sMinTimeBetweenFetches * 0.8f, 0.3f); - sMaxTimeBetweenFetches = llmax(sMaxTimeBetweenFetches * 0.8f, 10.f); - //llinfos << "Inventory fetch times shrunk to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl; - } - - sTimelyFetchPending = FALSE; - continue; - } - else if (sFetchTimer.getElapsedTimeF32() > sMaxTimeBetweenFetches) - { - // received first packet, but our num descendants does not match db's num descendants - // so try again later - LLUUID fetch_id = sFetchQueue.front(); - sFetchQueue.pop_front(); - - if (sNumFetchRetries++ < MAX_FETCH_RETRIES) - { - // push on back of queue - sFetchQueue.push_back(fetch_id); - } - sTimelyFetchPending = FALSE; - sFetchTimer.reset(); - break; - } - - // not enough time has elapsed to do a new fetch - break; - } - - // - // DEPRECATED OLD CODE - //-------------------------------------------------------------------------------- -#endif - } -} - void LLInventoryModel::cache( const LLUUID& parent_folder_id, const LLUUID& agent_id) diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 95983ffc8..ae4e9451c 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -353,8 +353,6 @@ public: //void mock(const LLUUID& root_id); - // Add categories to a list to be fetched in bulk. - static void bulkFetch(std::string url); // call this method to request the inventory. //void requestFromServer(const LLUUID& agent_id); @@ -368,10 +366,10 @@ public: // name based on type, pass in a NULL to the 'name' parameter. LLUUID createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, - const std::string& namevoid, + const std::string& name, void (*callback)(const LLSD&, void*) = NULL, void* user_data = NULL); - +public: // Internal methods that add inventory and make sure that all of // the internal data structures are consistent. These methods // should be passed pointers of newly created objects, and the @@ -384,6 +382,7 @@ public: typedef std::map response_t; typedef std::vector options_t; + //OGPX really screwed with the login process. This is needed until it's all sorted out. bool loadSkeleton(const options_t& options, const LLUUID& owner_id); /** Mutators @@ -477,14 +476,6 @@ private: typedef std::set observer_list_t; observer_list_t mObservers; -public: - // this gets triggered when performing a filter-search - static void startBackgroundFetch(const LLUUID& cat_id = LLUUID::null); // start fetch process - static void findLostItems(); - static BOOL backgroundFetchActive(); - static bool isEverythingFetched(); - static void backgroundFetch(void*); // background fetch idle function - static void incrBulkFetch(S16 fetching) { sBulkFetchCount+=fetching; if (sBulkFetchCount<0) sBulkFetchCount=0; } /** Notifications ** ** *******************************************************************************/ @@ -551,25 +542,11 @@ private: std::map mCategoryLock; std::map mItemLock; - // completing the fetch once per session should be sufficient - static BOOL sBackgroundFetchActive; - static BOOL sTimelyFetchPending; - static S32 sNumFetchRetries; - static LLFrameTimer sFetchTimer; - static F32 sMinTimeBetweenFetches; - static F32 sMaxTimeBetweenFetches; - static S16 sBulkFetchCount; public: // *NOTE: DEBUG functionality void dumpInventory() const; - static bool isBulkFetchProcessingComplete(); - static void stopBackgroundFetch(); // stop fetch process - - static BOOL sFullFetchStarted; - static BOOL sAllFoldersFetched; - /** Miscellaneous ** ** *******************************************************************************/ diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp new file mode 100644 index 000000000..41a75d727 --- /dev/null +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -0,0 +1,600 @@ +/** + * @file llinventorymodel.cpp + * @brief Implementation of the inventory model used to track agent inventory. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * 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. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llinventorymodelbackgroundfetch.h" + +#include "llagent.h" +#include "llappviewer.h" +#include "llcallbacklist.h" +#include "llinventoryview.h" +#include "llinventorymodel.h" +#include "llviewercontrol.h" +#include "llviewerinventory.h" +#include "llviewermessage.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" + +const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; +const S32 MAX_FETCH_RETRIES = 10; + +LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() : + mBackgroundFetchActive(FALSE), + mAllFoldersFetched(FALSE), + mFullFetchStarted(FALSE), + mNumFetchRetries(0), + mMinTimeBetweenFetches(0.3f), + mMaxTimeBetweenFetches(10.f), + mTimelyFetchPending(FALSE), + mBulkFetchCount(0) +{ +} + +LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch() +{ +} + +bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const +{ + return mFetchQueue.empty() && mBulkFetchCount<=0; +} + +// static +bool LLInventoryModelBackgroundFetch::isEverythingFetched() const +{ + return mAllFoldersFetched; +} + +BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive() const +{ + return mBackgroundFetchActive; +} + +//static +void LLInventoryModelBackgroundFetch::startBackgroundFetch(const LLUUID& cat_id) +{ + if (!mAllFoldersFetched) + { + if (cat_id.isNull()) + { + if (!mFullFetchStarted) + { + mFullFetchStarted = TRUE; + mFetchQueue.push_back(gInventory.getLibraryRootFolderID()); + mFetchQueue.push_back(gInventory.getRootFolderID()); + if (!mBackgroundFetchActive) + { + mBackgroundFetchActive = TRUE; + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } + } + } + else + { + // specific folder requests go to front of queue + // Remove it from the queue first, to avoid getting it twice. + if (!mFetchQueue.empty() && mFetchQueue.front().mCatUUID != cat_id) + { + std::deque::iterator old_entry = std::find(mFetchQueue.begin(), mFetchQueue.end(), FetchQueueInfo(cat_id)); + if (old_entry != mFetchQueue.end()) + { + mFetchQueue.erase(old_entry); + } + } + mFetchQueue.push_front(cat_id); + if (!mBackgroundFetchActive) + { + mBackgroundFetchActive = TRUE; + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } + } + } +} + +//static +void LLInventoryModelBackgroundFetch::findLostItems() +{ + mFetchQueue.push_back(LLUUID::null); + if (!mBackgroundFetchActive) + { + mBackgroundFetchActive = TRUE; + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } +} + +//static +void LLInventoryModelBackgroundFetch::stopBackgroundFetch() +{ + if (mBackgroundFetchActive) + { + mBackgroundFetchActive = FALSE; + gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + mBulkFetchCount=0; + mMinTimeBetweenFetches=0.0f; + if (!mAllFoldersFetched) + { + // We didn't finish this, so set it to FALSE in order to be able to start it again. + mFullFetchStarted=FALSE; + } + } +} + +void LLInventoryModelBackgroundFetch::setAllFoldersFetched() +{ + if (mFullFetchStarted) + { + mAllFoldersFetched = TRUE; + } + stopBackgroundFetch(); +} + +void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *) +{ + LLInventoryModelBackgroundFetch::instance().backgroundFetch(); +} + +//static +void LLInventoryModelBackgroundFetch::backgroundFetch() +{ + if (mBackgroundFetchActive && gAgent.getRegion()) + { + // If we'll be using the capability, we'll be sending batches and the background thing isn't as important. + std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents"); + if (false /*gSavedSettings.getBOOL("UseHTTPInventory")*/ && !url.empty()) + { + bulkFetch(url); + return; + } + +#if 1 + //DEPRECATED OLD CODE FOLLOWS. + // no more categories to fetch, stop fetch process + if (mFetchQueue.empty()) + { + llinfos << "Inventory fetch completed" << llendl; + + setAllFoldersFetched(); + return; + } + + F32 fast_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.1f); + F32 slow_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.5f); + if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() > slow_fetch_time) + { + // double timeouts on failure + mMinTimeBetweenFetches = llmin(mMinTimeBetweenFetches * 2.f, 10.f); + mMaxTimeBetweenFetches = llmin(mMaxTimeBetweenFetches * 2.f, 120.f); + lldebugs << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; + // fetch is no longer considered "timely" although we will wait for full time-out. + mTimelyFetchPending = FALSE; + } + + while(1) + { + if (mFetchQueue.empty()) + { + break; + } + + if(gDisconnected) + { + // just bail if we are disconnected. + break; + } + + const FetchQueueInfo info = mFetchQueue.front(); + LLViewerInventoryCategory* cat = gInventory.getCategory(info.mCatUUID); + + // category has been deleted, remove from queue. + if (!cat) + { + mFetchQueue.pop_front(); + continue; + } + + if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches && + LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) + { + // category exists but has no children yet, fetch the descendants + // for now, just request every time and rely on retry timer to throttle + if (cat->fetchDescendents()) + { + mFetchTimer.reset(); + mTimelyFetchPending = TRUE; + } + else + { + // The catagory also tracks if it has expired and here it says it hasn't + // yet. Get out of here because nothing is going to happen until we + // update the timers. + break; + } + } + // do I have all my children? + else if (gInventory.isCategoryComplete(info.mCatUUID)) + { + // finished with this category, remove from queue + mFetchQueue.pop_front(); + + // Add all children to queue. + LLInventoryModel::cat_array_t* categories; + gInventory.getDirectDescendentsOf(cat->getUUID(), categories); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID())); + } + + // we received a response in less than the fast time + if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time) + { + // shrink timeouts based on success + mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f); + mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f); + lldebugs << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; + } + + mTimelyFetchPending = FALSE; + continue; + } + else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches) + { + // received first packet, but our num descendants does not match db's num descendants + // so try again later. + mFetchQueue.pop_front(); + + if (mNumFetchRetries++ < MAX_FETCH_RETRIES) + { + // push on back of queue + mFetchQueue.push_back(info); + } + mTimelyFetchPending = FALSE; + mFetchTimer.reset(); + break; + } + + // not enough time has elapsed to do a new fetch + break; + } + + // + // DEPRECATED OLD CODE + //-------------------------------------------------------------------------------- +#endif + } +} + +void LLInventoryModelBackgroundFetch::incrBulkFetch(S16 fetching) +{ + mBulkFetchCount += fetching; + if (mBulkFetchCount < 0) + { + mBulkFetchCount = 0; + } +} + + +class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder +{ + public: + LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd) : + mRequestSD(request_sd) + {}; + //LLInventoryModelFetchDescendentsResponder() {}; + void result(const LLSD& content); + void error(U32 status, const std::string& reason); +private: + LLSD mRequestSD; +}; + +//If we get back a normal response, handle it here +// Note: this is the handler for WebFetchInventoryDescendents and agent/inventory caps +void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) +{ + LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); + if (content.has("folders")) + { + + for(LLSD::array_const_iterator folder_it = content["folders"].beginArray(); + folder_it != content["folders"].endArray(); + ++folder_it) + { + LLSD folder_sd = *folder_it; + + + //LLUUID agent_id = folder_sd["agent_id"]; + + //if(agent_id != gAgent.getID()) //This should never happen. + //{ + // llwarns << "Got a UpdateInventoryItem for the wrong agent." + // << llendl; + // break; + //} + + LLUUID parent_id = folder_sd["folder_id"]; + LLUUID owner_id = folder_sd["owner_id"]; + S32 version = (S32)folder_sd["version"].asInteger(); + S32 descendents = (S32)folder_sd["descendents"].asInteger(); + LLPointer tcategory = new LLViewerInventoryCategory(owner_id); + + if (parent_id.isNull()) + { + LLPointer titem = new LLViewerInventoryItem; + for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); + item_it != folder_sd["items"].endArray(); + ++item_it) + { + LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + if (lost_uuid.notNull()) + { + LLSD item = *item_it; + titem->unpackMessage(item); + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + titem->setParent(lost_uuid); + titem->updateParentOnServer(FALSE); + gInventory.updateItem(titem); + gInventory.notifyObservers(); + + } + } + } + + LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id); + if (!pcat) + { + continue; + } + + for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray(); + category_it != folder_sd["categories"].endArray(); + ++category_it) + { + LLSD category = *category_it; + tcategory->fromLLSD(category); + + if (fetcher->mFullFetchStarted) + { + fetcher->mFetchQueue.push_back(LLInventoryModelBackgroundFetch::FetchQueueInfo(tcategory->getUUID())); + } + else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) ) + { + gInventory.updateCategory(tcategory); + } + + } + LLPointer titem = new LLViewerInventoryItem; + for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); + item_it != folder_sd["items"].endArray(); + ++item_it) + { + LLSD item = *item_it; + titem->unpackMessage(item); + + gInventory.updateItem(titem); + } + + // set version and descendentcount according to message. + LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); + if(cat) + { + cat->setVersion(version); + cat->setDescendentCount(descendents); + } + + } + } + + if (content.has("bad_folders")) + { + for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray(); + folder_it != content["bad_folders"].endArray(); + ++folder_it) + { + LLSD folder_sd = *folder_it; + + //These folders failed on the dataserver. We probably don't want to retry them. + llinfos << "Folder " << folder_sd["folder_id"].asString() + << "Error: " << folder_sd["error"].asString() << llendl; + } + } + + fetcher->incrBulkFetch(-1); + + if (fetcher->isBulkFetchProcessingComplete()) + { + llinfos << "Inventory fetch completed" << llendl; + fetcher->setAllFoldersFetched(); + } + + gInventory.notifyObservers(); +} + +//If we get back an error (not found, etc...), handle it here +void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::string& reason) +{ + LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); + + llinfos << "LLInventoryModelFetchDescendentsResponder::error " + << status << ": " << reason << llendl; + + fetcher->incrBulkFetch(-1); + + if (status==499) //timed out. Let's be awesome! + { + for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); + folder_it != mRequestSD["folders"].endArray(); + ++folder_it) + { + LLSD folder_sd = *folder_it; + LLUUID folder_id = folder_sd["folder_id"]; + fetcher->mFetchQueue.push_front(LLInventoryModelBackgroundFetch::FetchQueueInfo(folder_id)); + } + } + else + { + if (fetcher->isBulkFetchProcessingComplete()) + { + fetcher->setAllFoldersFetched(); + } + } + gInventory.notifyObservers(); +} + + +// Bundle up a bunch of requests to send all at once. +// static +void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) +{ + //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. + //If there are items in sFetchQueue, we want to check the time since the last bulkFetch was + //sent. If it exceeds our retry time, go ahead and fire off another batch. + //Stopbackgroundfetch will be run from the Responder instead of here. + + S16 max_concurrent_fetches=8; + F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely. + if (mMinTimeBetweenFetches < new_min_time) + { + mMinTimeBetweenFetches=new_min_time; //HACK! See above. + } + + if (gDisconnected || + (mBulkFetchCount > max_concurrent_fetches) || + (mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches)) + { + return; // just bail if we are disconnected. + } + + U32 folder_count=0; + U32 max_batch_size=5; + + U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1; + + LLSD body; + LLSD body_lib; + + while( !(mFetchQueue.empty() ) && (folder_count < max_batch_size) ) + { + const FetchQueueInfo& fetch_info = mFetchQueue.front(); + const LLUUID &cat_id = fetch_info.mCatUUID; + if (cat_id.isNull()) //DEV-17797 + { + LLSD folder_sd; + folder_sd["folder_id"] = LLUUID::null.asString(); + folder_sd["owner_id"] = gAgent.getID(); + folder_sd["sort_order"] = (LLSD::Integer)sort_order; + folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE; + folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; + body["folders"].append(folder_sd); + folder_count++; + } + else + { + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + + if (cat) + { + // Pre-emptive strike + //if(!(gInventory.isObjectDescendentOf(cat->getUUID(), gSystemFolderRoot))) + if(true) + { + // + if ( LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) + { + LLSD folder_sd; + folder_sd["folder_id"] = cat->getUUID(); + folder_sd["owner_id"] = cat->getOwnerID(); + folder_sd["sort_order"] = (LLSD::Integer)sort_order; + folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted; + folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; + + LL_DEBUGS("Inventory") << " fetching "<getUUID()<<" with cat owner "<getOwnerID()<<" and agent" << gAgent.getID() << LL_ENDL; + if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) + body_lib["folders"].append(folder_sd); + else + body["folders"].append(folder_sd); + folder_count++; + } + // May already have this folder, but append child folders to list. + if (mFullFetchStarted) + { //Already have this folder but append child folders to list. + LLInventoryModel::cat_array_t* categories; + gInventory.getDirectDescendentsOf(cat->getUUID(), categories); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID())); + } + } + // + } + // + } + } + mFetchQueue.pop_front(); + } + + if (folder_count > 0) + { + mBulkFetchCount++; + if (body["folders"].size()) + { + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body); + LLHTTPClient::post(url, body, fetcher, 300.0); + } + if (body_lib["folders"].size()) + { + std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents"); + + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib); + LLHTTPClient::post(url_lib, body_lib, fetcher, 300.0); + } + mFetchTimer.reset(); + } + else if (isBulkFetchProcessingComplete()) + { + setAllFoldersFetched(); + } +} + +bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const +{ + for (fetch_queue_t::const_iterator it = mFetchQueue.begin(); + it != mFetchQueue.end(); ++it) + { + const LLUUID& fetch_id = (*it).mCatUUID; + if (gInventory.isObjectDescendentOf(fetch_id, cat_id)) + return false; + } + return true; +} + diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h new file mode 100644 index 000000000..157cce420 --- /dev/null +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -0,0 +1,94 @@ +/** + * @file llinventorymodelbackgroundfetch.h + * @brief LLInventoryModelBackgroundFetch class header file + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * 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. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLINVENTORYMODELBACKGROUNDFETCH_H +#define LL_LLINVENTORYMODELBACKGROUNDFETCH_H + +#include "llsingleton.h" +#include "lluuid.h" + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryModelBackgroundFetch +// +// This class handles background fetches, which are fetches of +// inventory folder. Fetches can be recursive or not. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryModelBackgroundFetch : public LLSingleton +{ + friend class LLInventoryModelFetchDescendentsResponder; + +public: + LLInventoryModelBackgroundFetch(); + ~LLInventoryModelBackgroundFetch(); + + void startBackgroundFetch(const LLUUID& cat_id = LLUUID::null); // start fetch process + BOOL backgroundFetchActive() const; + bool isEverythingFetched() const; // completing the fetch once per session should be sufficient + void findLostItems(); +protected: + void incrBulkFetch(S16 fetching); + bool isBulkFetchProcessingComplete() const; + void bulkFetch(std::string url); + + void backgroundFetch(); + static void backgroundFetchCB(void*); // background fetch idle function + void stopBackgroundFetch(); // stop fetch process + + void setAllFoldersFetched(); + bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const; +private: + BOOL mFullFetchStarted; + BOOL mAllFoldersFetched; + + // completing the fetch once per session should be sufficient + BOOL mBackgroundFetchActive; + S16 mBulkFetchCount; + BOOL mTimelyFetchPending; + S32 mNumFetchRetries; + + LLFrameTimer mFetchTimer; + F32 mMinTimeBetweenFetches; + F32 mMaxTimeBetweenFetches; + + struct FetchQueueInfo + { + FetchQueueInfo(const LLUUID& id/*, BOOL recursive*/) : + mCatUUID(id)/*, mRecursive(recursive)*/ + { + } + LLUUID mCatUUID; + //BOOL mRecursive; + bool operator ==(const FetchQueueInfo& b) const + { + return mCatUUID == b.mCatUUID; + } + }; + typedef std::deque fetch_queue_t; + fetch_queue_t mFetchQueue; +}; + +#endif // LL_LLINVENTORYMODELBACKGROUNDFETCH_H + diff --git a/indra/newview/llinventoryview.cpp b/indra/newview/llinventoryview.cpp index 7cb0d5a90..86f1e40cb 100644 --- a/indra/newview/llinventoryview.cpp +++ b/indra/newview/llinventoryview.cpp @@ -59,6 +59,7 @@ #include "lliconctrl.h" #include "llinventoryfunctions.h" #include "llinventoryclipboard.h" +#include "llinventorymodelbackgroundfetch.h" #include "lllineeditor.h" #include "llmenugl.h" #include "llpreviewanim.h" @@ -619,7 +620,7 @@ LLInventoryView::~LLInventoryView( void ) void LLInventoryView::draw() { - if (LLInventoryModel::isEverythingFetched()) + if (LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) { LLLocale locale(LLLocale::USER_LOCALE); std::ostringstream title; @@ -729,7 +730,7 @@ void LLInventoryView::changed(U32 mask) { std::ostringstream title; title << "Inventory"; - if (LLInventoryModel::backgroundFetchActive()) + if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive()) { LLLocale locale(LLLocale::USER_LOCALE); std::string item_count_string; @@ -870,7 +871,7 @@ void LLInventoryView::toggleFindOptions() addDependentFloater(mFinderHandle); // start background fetch of folders - gInventory.startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); mFloaterControls[std::string("Inventory.ShowFilters")]->setValue(TRUE); } @@ -946,7 +947,7 @@ void LLInventoryView::onSearchEdit(const std::string& search_string, void* user_ return; } - gInventory.startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); std::string filter_text = search_string; std::string uppercase_search_string = filter_text; @@ -1301,7 +1302,7 @@ void LLInventoryView::onFilterSelected(void* userdata, bool from_click) if (filter->isActive()) { // If our filter is active we may be the first thing requiring a fetch so we better start it here. - gInventory.startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); } self->setFilterTextFromFilter(); self->updateSortControls(); @@ -1907,7 +1908,7 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) if(handled) { ECursorType cursor = getWindow()->getCursor(); - if (LLInventoryModel::backgroundFetchActive() && cursor == UI_CURSOR_ARROW) + if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() && cursor == UI_CURSOR_ARROW) { // replace arrow cursor with arrow and hourglass cursor getWindow()->setCursor(UI_CURSOR_WORKING); diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index ad22dce4c..c81024939 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -56,6 +56,7 @@ #include "llfloatergesture.h" // for some label constants #include "llgesturemgr.h" #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llkeyboard.h" #include "lllineeditor.h" #include "llnotificationsutil.h" @@ -158,10 +159,10 @@ LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& // Start speculative download of sounds and animations LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION); - gInventory.startBackgroundFetch(animation_folder_id); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(animation_folder_id); LLUUID sound_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND); - gInventory.startBackgroundFetch(sound_folder_id); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(sound_folder_id); // this will call refresh when we have everything. LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 4aca35710..80e25e725 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -129,6 +129,7 @@ #include "llimagebmp.h" #include "llimview.h" // for gIMMgr #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryview.h" #include "llkeyboard.h" #include "llloginhandler.h" // gLoginHandler, SLURL support @@ -2712,7 +2713,7 @@ bool idle_startup() ) { // Fetch inventory in the background - gInventory.startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); } // HACK: Inform simulator of window size. @@ -2777,7 +2778,7 @@ bool idle_startup() } //DEV-17797. get null folder. Any items found here moved to Lost and Found - LLInventoryModel::findLostItems(); + LLInventoryModelBackgroundFetch::instance().findLostItems(); LLStartUp::setStartupState( STATE_PRECACHE ); timeout.reset(); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index d09dbdb4c..5a88df2db 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -47,6 +47,7 @@ #include "llfoldervieweventlistener.h" #include "llinventory.h" #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryview.h" #include "lllineeditor.h" #include "llui.h" @@ -1344,7 +1345,7 @@ public: { // We need to find textures in all folders, so get the main // background download going. - gInventory.startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); gInventory.removeObserver(this); delete this; } @@ -1368,9 +1369,9 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask) showPicker(FALSE); //grab textures first... - gInventory.startBackgroundFetch(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE)); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE)); //...then start full inventory fetch. - gInventory.startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); } return handled; } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index b640b34e7..889b7a3d2 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -48,6 +48,7 @@ #include "llinventorybridge.h" #include "llinventorydefines.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryview.h" #include "llviewerregion.h" @@ -507,7 +508,7 @@ bool LLViewerInventoryCategory::fetchDescendents() } if (!url.empty()) //Capability found. Build up LLSD and use it. { - LLInventoryModel::startBackgroundFetch(mUUID); + LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(mUUID); } else { //Deprecated, but if we don't have a capability, use the old system. diff --git a/indra/newview/statemachine/aifetchinventoryfolder.cpp b/indra/newview/statemachine/aifetchinventoryfolder.cpp index 4e8e16456..03ea78ed5 100644 --- a/indra/newview/statemachine/aifetchinventoryfolder.cpp +++ b/indra/newview/statemachine/aifetchinventoryfolder.cpp @@ -33,6 +33,7 @@ #include "aievent.h" #include "llagent.h" #include "llinventoryobserver.h" +#include "llinventorymodelbackgroundfetch.h" enum fetchinventoryfolder_state_type { AIFetchInventoryFolder_checkFolderExists = AIStateMachine::max_state, @@ -154,7 +155,7 @@ void AIFetchInventoryFolder::multiplex_impl(void) // mFolderUUID is now valid. mExists = true; if (!mFetchContents || // No request to fetch contents. - LLInventoryModel::isEverythingFetched()) // No need to fetch contents. + LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) // No need to fetch contents. { // We're done. finish(); From 40400d696b6a52bcc8da6ab2c8c9bf026621538c Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 21 Jan 2012 00:11:19 -0600 Subject: [PATCH 06/13] Updated inv fetching impl. Haven't ticked on new caps. --- indra/newview/llfloaterworldmap.cpp | 2 +- indra/newview/llfolderview.cpp | 2 +- indra/newview/llinventoryactions.cpp | 2 +- indra/newview/llinventorybridge.cpp | 2 +- indra/newview/llinventorymodel.cpp | 3 + .../llinventorymodelbackgroundfetch.cpp | 220 ++++++++++-------- .../newview/llinventorymodelbackgroundfetch.h | 32 ++- indra/newview/llinventoryview.cpp | 6 +- indra/newview/llpreviewgesture.cpp | 4 +- indra/newview/llstartup.cpp | 2 +- indra/newview/lltexturectrl.cpp | 6 +- indra/newview/llviewerinventory.cpp | 2 +- 12 files changed, 163 insertions(+), 120 deletions(-) diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 62f55dd65..5e6ecf2b4 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -318,7 +318,7 @@ void LLFloaterWorldMap::show(void*, BOOL center_on_target) // Start speculative download of landmarks LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(landmark_folder_id); + LLInventoryModelBackgroundFetch::instance().start(landmark_folder_id); gFloaterWorldMap->childSetFocus("location", TRUE); gFocusMgr.triggerFocusFlash(); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index ad0dead06..db3803fe6 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1309,7 +1309,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) // when applying a filter, matching folders get their contents downloaded first if (filter.isNotDefault() && getFiltered(filter.getMinRequiredGeneration()) && (mListener && !gInventory.isCategoryComplete(mListener->getUUID()))) { - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(mListener->getUUID()); + LLInventoryModelBackgroundFetch::instance().start(mListener->getUUID()); } // now query children diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 1ff9d6709..27c9dc56e 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -526,7 +526,7 @@ class LLRefreshInvModel : public inventory_listener_t LLInventoryModel* model = mPtr->getPanel()->getModel(); if(!model) return false; model->empty(); - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); return true; } }; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 9d9110eb2..7cff25975 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -803,7 +803,7 @@ BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const if (*type == DAD_CATEGORY) { - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(obj->getUUID()); + LLInventoryModelBackgroundFetch::instance().start(obj->getUUID()); } rv = TRUE; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 32e0fc6c2..ecccc891e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2126,6 +2126,9 @@ void LLInventoryModel::buildParentChildMap() // The inv tree is built. mIsAgentInvUsable = true; AIEvent::trigger(AIEvent::LLInventoryModel_mIsAgentInvUsable_true); + llinfos << "Inventory initialized, notifying observers" << llendl; + addChangedMask(LLInventoryObserver::ALL, LLUUID::null); + notifyObservers(); } } llinfos << " finished buildParentChildMap " << llendl; diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 41a75d727..0883c4b60 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -44,7 +44,8 @@ const S32 MAX_FETCH_RETRIES = 10; LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() : mBackgroundFetchActive(FALSE), mAllFoldersFetched(FALSE), - mFullFetchStarted(FALSE), + mRecursiveInventoryFetchStarted(FALSE), + mRecursiveLibraryFetchStarted(FALSE), mNumFetchRetries(0), mMinTimeBetweenFetches(0.3f), mMaxTimeBetweenFetches(10.f), @@ -62,7 +63,36 @@ bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const return mFetchQueue.empty() && mBulkFetchCount<=0; } -// static +bool LLInventoryModelBackgroundFetch::libraryFetchStarted() const +{ + return mRecursiveLibraryFetchStarted; +} + +bool LLInventoryModelBackgroundFetch::libraryFetchCompleted() const +{ + return libraryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getLibraryRootFolderID()); +} + +bool LLInventoryModelBackgroundFetch::libraryFetchInProgress() const +{ + return libraryFetchStarted() && !libraryFetchCompleted(); +} + +bool LLInventoryModelBackgroundFetch::inventoryFetchStarted() const +{ + return mRecursiveInventoryFetchStarted; +} + +bool LLInventoryModelBackgroundFetch::inventoryFetchCompleted() const +{ + return inventoryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getRootFolderID()); +} + +bool LLInventoryModelBackgroundFetch::inventoryFetchInProgress() const +{ + return inventoryFetchStarted() && !inventoryFetchCompleted(); +} + bool LLInventoryModelBackgroundFetch::isEverythingFetched() const { return mAllFoldersFetched; @@ -73,43 +103,44 @@ BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive() const return mBackgroundFetchActive; } -//static -void LLInventoryModelBackgroundFetch::startBackgroundFetch(const LLUUID& cat_id) +void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id, BOOL recursive) { - if (!mAllFoldersFetched) + if (!mAllFoldersFetched || cat_id.notNull()) { + LL_DEBUGS("InventoryFetch") << "Start fetching category: " << cat_id << ", recursive: " << recursive << LL_ENDL; + + mBackgroundFetchActive = TRUE; if (cat_id.isNull()) { - if (!mFullFetchStarted) + if (!mRecursiveInventoryFetchStarted) { - mFullFetchStarted = TRUE; - mFetchQueue.push_back(gInventory.getLibraryRootFolderID()); - mFetchQueue.push_back(gInventory.getRootFolderID()); - if (!mBackgroundFetchActive) - { - mBackgroundFetchActive = TRUE; - gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); - } + mRecursiveInventoryFetchStarted |= recursive; + mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } + if (!mRecursiveLibraryFetchStarted) + { + mRecursiveLibraryFetchStarted |= recursive; + mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } else { - // specific folder requests go to front of queue - // Remove it from the queue first, to avoid getting it twice. - if (!mFetchQueue.empty() && mFetchQueue.front().mCatUUID != cat_id) + // Specific folder requests go to front of queue. + if (mFetchQueue.empty() || mFetchQueue.front().mCatUUID != cat_id) { - std::deque::iterator old_entry = std::find(mFetchQueue.begin(), mFetchQueue.end(), FetchQueueInfo(cat_id)); - if (old_entry != mFetchQueue.end()) - { - mFetchQueue.erase(old_entry); - } - } - mFetchQueue.push_front(cat_id); - if (!mBackgroundFetchActive) - { - mBackgroundFetchActive = TRUE; + mFetchQueue.push_front(FetchQueueInfo(cat_id, recursive)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } + if (cat_id == gInventory.getLibraryRootFolderID()) + { + mRecursiveLibraryFetchStarted |= recursive; + } + if (cat_id == gInventory.getRootFolderID()) + { + mRecursiveInventoryFetchStarted |= recursive; + } } } } @@ -117,15 +148,11 @@ void LLInventoryModelBackgroundFetch::startBackgroundFetch(const LLUUID& cat_id) //static void LLInventoryModelBackgroundFetch::findLostItems() { - mFetchQueue.push_back(LLUUID::null); - if (!mBackgroundFetchActive) - { - mBackgroundFetchActive = TRUE; - gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); - } + mBackgroundFetchActive = TRUE; + mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } -//static void LLInventoryModelBackgroundFetch::stopBackgroundFetch() { if (mBackgroundFetchActive) @@ -134,17 +161,13 @@ void LLInventoryModelBackgroundFetch::stopBackgroundFetch() gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); mBulkFetchCount=0; mMinTimeBetweenFetches=0.0f; - if (!mAllFoldersFetched) - { - // We didn't finish this, so set it to FALSE in order to be able to start it again. - mFullFetchStarted=FALSE; - } } } void LLInventoryModelBackgroundFetch::setAllFoldersFetched() { - if (mFullFetchStarted) + if (mRecursiveInventoryFetchStarted && + mRecursiveLibraryFetchStarted) { mAllFoldersFetched = TRUE; } @@ -170,8 +193,11 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() } #if 1 - //DEPRECATED OLD CODE FOLLOWS. - // no more categories to fetch, stop fetch process + //-------------------------------------------------------------------------------- + // DEPRECATED OLD CODE + // + + // No more categories to fetch, stop fetch process. if (mFetchQueue.empty()) { llinfos << "Inventory fetch completed" << llendl; @@ -246,7 +272,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() it != categories->end(); ++it) { - mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID())); + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive)); } // we received a response in less than the fast time @@ -301,19 +327,22 @@ void LLInventoryModelBackgroundFetch::incrBulkFetch(S16 fetching) class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder { public: - LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd) : - mRequestSD(request_sd) - {}; - //LLInventoryModelFetchDescendentsResponder() {}; - void result(const LLSD& content); - void error(U32 status, const std::string& reason); + LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) : + mRequestSD(request_sd), + mRecursiveCatUUIDs(recursive_cats) + {}; + //LLInventoryModelFetchDescendentsResponder() {}; + void result(const LLSD& content); + void error(U32 status, const std::string& reason); +protected: + BOOL getIsRecursive(const LLUUID& cat_id) const; private: - LLSD mRequestSD; + LLSD mRequestSD; + uuid_vec_t mRecursiveCatUUIDs; // hack for storing away which cat fetches are recursive }; -//If we get back a normal response, handle it here -// Note: this is the handler for WebFetchInventoryDescendents and agent/inventory caps -void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) +// If we get back a normal response, handle it here. +void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) { LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); if (content.has("folders")) @@ -380,10 +409,12 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) { LLSD category = *category_it; tcategory->fromLLSD(category); - - if (fetcher->mFullFetchStarted) + + const BOOL recursive = getIsRecursive(tcategory->getUUID()); + + if (recursive) { - fetcher->mFetchQueue.push_back(LLInventoryModelBackgroundFetch::FetchQueueInfo(tcategory->getUUID())); + fetcher->mFetchQueue.push_back(LLInventoryModelBackgroundFetch::FetchQueueInfo(tcategory->getUUID(), recursive)); } else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) ) { @@ -456,7 +487,8 @@ void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::str { LLSD folder_sd = *folder_it; LLUUID folder_id = folder_sd["folder_id"]; - fetcher->mFetchQueue.push_front(LLInventoryModelBackgroundFetch::FetchQueueInfo(folder_id)); + const BOOL recursive = getIsRecursive(folder_id); + fetcher->mFetchQueue.push_front(LLInventoryModelBackgroundFetch::FetchQueueInfo(folder_id, recursive)); } } else @@ -469,6 +501,10 @@ void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::str gInventory.notifyObservers(); } +BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat_id) const +{ + return (std::find(mRecursiveCatUUIDs.begin(),mRecursiveCatUUIDs.end(), cat_id) != mRecursiveCatUUIDs.end()); +} // Bundle up a bunch of requests to send all at once. // static @@ -498,6 +534,8 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1; + uuid_vec_t recursive_cats; + LLSD body; LLSD body_lib; @@ -522,44 +560,38 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) if (cat) { - // Pre-emptive strike - //if(!(gInventory.isObjectDescendentOf(cat->getUUID(), gSystemFolderRoot))) - if(true) - { - // - if ( LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) + if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) + { + LLSD folder_sd; + folder_sd["folder_id"] = cat->getUUID(); + folder_sd["owner_id"] = cat->getOwnerID(); + folder_sd["sort_order"] = (LLSD::Integer)sort_order; + folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted; + folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; + + if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) + body_lib["folders"].append(folder_sd); + else + body["folders"].append(folder_sd); + folder_count++; + } + // May already have this folder, but append child folders to list. + if (fetch_info.mRecursive) + { + LLInventoryModel::cat_array_t* categories; + gInventory.getDirectDescendentsOf(cat->getUUID(), categories); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) { - LLSD folder_sd; - folder_sd["folder_id"] = cat->getUUID(); - folder_sd["owner_id"] = cat->getOwnerID(); - folder_sd["sort_order"] = (LLSD::Integer)sort_order; - folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted; - folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; - - LL_DEBUGS("Inventory") << " fetching "<getUUID()<<" with cat owner "<getOwnerID()<<" and agent" << gAgent.getID() << LL_ENDL; - if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) - body_lib["folders"].append(folder_sd); - else - body["folders"].append(folder_sd); - folder_count++; - } - // May already have this folder, but append child folders to list. - if (mFullFetchStarted) - { //Already have this folder but append child folders to list. - LLInventoryModel::cat_array_t* categories; - gInventory.getDirectDescendentsOf(cat->getUUID(), categories); - for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); - it != categories->end(); - ++it) - { - mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID())); - } - } - // - } - // + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); + } + } } } + if (fetch_info.mRecursive) + recursive_cats.push_back(cat_id); + mFetchQueue.pop_front(); } @@ -568,14 +600,14 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) mBulkFetchCount++; if (body["folders"].size()) { - LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body); + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body, recursive_cats); LLHTTPClient::post(url, body, fetcher, 300.0); } if (body_lib["folders"].size()) { std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents"); - LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib); + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib, recursive_cats); LLHTTPClient::post(url_lib, body_lib, fetcher, 300.0); } mFetchTimer.reset(); diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index 157cce420..0fac2c7a2 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -43,10 +43,22 @@ class LLInventoryModelBackgroundFetch : public LLSingleton fetch_queue_t; fetch_queue_t mFetchQueue; diff --git a/indra/newview/llinventoryview.cpp b/indra/newview/llinventoryview.cpp index 86f1e40cb..116cd440d 100644 --- a/indra/newview/llinventoryview.cpp +++ b/indra/newview/llinventoryview.cpp @@ -871,7 +871,7 @@ void LLInventoryView::toggleFindOptions() addDependentFloater(mFinderHandle); // start background fetch of folders - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); mFloaterControls[std::string("Inventory.ShowFilters")]->setValue(TRUE); } @@ -947,7 +947,7 @@ void LLInventoryView::onSearchEdit(const std::string& search_string, void* user_ return; } - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); std::string filter_text = search_string; std::string uppercase_search_string = filter_text; @@ -1302,7 +1302,7 @@ void LLInventoryView::onFilterSelected(void* userdata, bool from_click) if (filter->isActive()) { // If our filter is active we may be the first thing requiring a fetch so we better start it here. - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); } self->setFilterTextFromFilter(); self->updateSortControls(); diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index c81024939..a968f6e12 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -159,10 +159,10 @@ LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& // Start speculative download of sounds and animations LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION); - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(animation_folder_id); + LLInventoryModelBackgroundFetch::instance().start(animation_folder_id); LLUUID sound_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND); - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(sound_folder_id); + LLInventoryModelBackgroundFetch::instance().start(sound_folder_id); // this will call refresh when we have everything. LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 80e25e725..f940ca151 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2713,7 +2713,7 @@ bool idle_startup() ) { // Fetch inventory in the background - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); } // HACK: Inform simulator of window size. diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 5a88df2db..9826c9e78 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1345,7 +1345,7 @@ public: { // We need to find textures in all folders, so get the main // background download going. - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); gInventory.removeObserver(this); delete this; } @@ -1369,9 +1369,9 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask) showPicker(FALSE); //grab textures first... - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE)); + LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE)); //...then start full inventory fetch. - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(); + LLInventoryModelBackgroundFetch::instance().start(); } return handled; } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 889b7a3d2..8661c05f7 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -508,7 +508,7 @@ bool LLViewerInventoryCategory::fetchDescendents() } if (!url.empty()) //Capability found. Build up LLSD and use it. { - LLInventoryModelBackgroundFetch::instance().startBackgroundFetch(mUUID); + LLInventoryModelBackgroundFetch::instance().start(mUUID, false); } else { //Deprecated, but if we don't have a capability, use the old system. From d7d65df9e05718719b9f056e1090a0cbce9411f1 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 21 Jan 2012 02:37:22 -0600 Subject: [PATCH 07/13] HTTP inventory fetching enabled. --- etc/message.xml | 8 ++++---- indra/newview/app_settings/settings.xml | 11 +++++++++++ indra/newview/llinventorymodelbackgroundfetch.cpp | 6 +++--- indra/newview/llinventoryobserver.cpp | 4 ++-- indra/newview/llviewerinventory.cpp | 6 +++--- indra/newview/llviewerregion.cpp | 10 +++++----- 6 files changed, 28 insertions(+), 17 deletions(-) diff --git a/etc/message.xml b/etc/message.xml index 8dfd75e13..690103bb7 100644 --- a/etc/message.xml +++ b/etc/message.xml @@ -670,19 +670,19 @@ EstateChangeInfo true - FetchInventoryDescendents + FetchInventoryDescendents2 false WebFetchInventoryDescendents false - FetchInventory + FetchInventory2 true - FetchLibDescendents + FetchLibDescendents2 true - FetchLib + FetchLib2 true diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b9c6cae29..71c2f0779 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -14459,6 +14459,17 @@ Value 1 + UseHTTPInventory + + Comment + Allow use of http inventory transfers instead of UDP + Persist + 1 + Type + Boolean + Value + 1 + FloaterUploadRect Comment diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 0883c4b60..e361015c7 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -185,8 +185,8 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() if (mBackgroundFetchActive && gAgent.getRegion()) { // If we'll be using the capability, we'll be sending batches and the background thing isn't as important. - std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents"); - if (false /*gSavedSettings.getBOOL("UseHTTPInventory")*/ && !url.empty()) + std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2"); + if (gSavedSettings.getBOOL("UseHTTPInventory") && !url.empty()) { bulkFetch(url); return; @@ -605,7 +605,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) } if (body_lib["folders"].size()) { - std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents"); + std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib, recursive_cats); LLHTTPClient::post(url_lib, body_lib, fetcher, 300.0); diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index c16e96dbd..e9f8207af 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -262,8 +262,8 @@ void fetch_items_from_llsd(const LLSD& items_llsd) { if (!items_llsd.size() || gDisconnected) return; LLSD body; - body[0]["cap_name"] = "FetchInventory"; - body[1]["cap_name"] = "FetchLib"; + body[0]["cap_name"] = "FetchInventory2"; + body[1]["cap_name"] = "FetchLib2"; for (S32 i=0; igetCapability("FetchLib"); + url = gAgent.getRegion()->getCapability("FetchLib2"); else - url = gAgent.getRegion()->getCapability("FetchInventory"); + url = gAgent.getRegion()->getCapability("FetchInventory2"); if (!url.empty()) { @@ -500,7 +500,7 @@ bool LLViewerInventoryCategory::fetchDescendents() std::string url; if (gAgent.getRegion()) { - url = gAgent.getRegion()->getCapability("FetchInventoryDescendents"); + url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2"); } else { diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 57b53031e..55637a15c 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1501,12 +1501,12 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("ObjectMedia"); capabilityNames.append("ObjectMediaNavigate");*/ - if (false)//gSavedSettings.getBOOL("UseHTTPInventory")) //Caps suffixed with 2 by LL. Don't update until rest of fetch system is updated first. + if (gSavedSettings.getBOOL("UseHTTPInventory")) //Caps suffixed with 2 by LL. Don't update until rest of fetch system is updated first. { - capabilityNames.append("FetchLib"); - capabilityNames.append("FetchLibDescendents"); - capabilityNames.append("FetchInventory"); - capabilityNames.append("FetchInventoryDescendents"); + capabilityNames.append("FetchLib2"); + capabilityNames.append("FetchLibDescendents2"); + capabilityNames.append("FetchInventory2"); + capabilityNames.append("FetchInventoryDescendents2"); } capabilityNames.append("GetDisplayNames"); From 4a4b786a60530356261c89e11341730480fc7d1d Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 21 Jan 2012 04:54:39 -0600 Subject: [PATCH 08/13] New inventory observer implementation. --- indra/newview/cofmgr.cpp | 11 +- indra/newview/llfloatercustomize.cpp | 8 +- indra/newview/llinventorybridge.cpp | 61 +- indra/newview/llinventorymodel.cpp | 2 +- .../llinventorymodelbackgroundfetch.cpp | 2 +- indra/newview/llinventoryobserver.cpp | 643 +++++++++++------- indra/newview/llinventoryobserver.h | 242 ++++--- indra/newview/llstartup.cpp | 7 +- indra/newview/lltexturectrl.cpp | 14 - indra/newview/lltooldraganddrop.cpp | 158 +++-- indra/newview/llviewerinventory.cpp | 37 +- indra/newview/llviewerinventory.h | 2 +- indra/newview/llviewermenu.cpp | 16 +- indra/newview/llviewermessage.cpp | 64 +- indra/newview/rlvinventory.cpp | 26 +- indra/newview/rlvinventory.h | 7 +- .../statemachine/aifetchinventoryfolder.cpp | 20 +- 17 files changed, 781 insertions(+), 539 deletions(-) diff --git a/indra/newview/cofmgr.cpp b/indra/newview/cofmgr.cpp index 3820517ae..3f633f81b 100644 --- a/indra/newview/cofmgr.cpp +++ b/indra/newview/cofmgr.cpp @@ -56,7 +56,7 @@ public: class LLCOFFetcher : public LLInventoryFetchDescendentsObserver { public: - LLCOFFetcher() {} + LLCOFFetcher(const LLUUID& cat_id) : LLInventoryFetchDescendentsObserver(cat_id) {} /*virtual*/ ~LLCOFFetcher() {} /*virtual*/ void done() @@ -216,12 +216,9 @@ void LLCOFMgr::fetchCOF() return; } - LLInventoryFetchDescendentsObserver::folder_ref_t fetchFolders; - fetchFolders.push_back(idCOF); - - LLCOFFetcher* pFetcher = new LLCOFFetcher(); - pFetcher->fetchDescendents(fetchFolders); - if (pFetcher->isEverythingComplete()) + LLCOFFetcher* pFetcher = new LLCOFFetcher(idCOF); + pFetcher->startFetch(); + if (pFetcher->isFinished()) pFetcher->done(); else gInventory.addObserver(pFetcher); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 9fdb2bea4..651185c0a 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -2775,10 +2775,10 @@ bool LLFloaterCustomize::onSaveDialog(const LLSD& notification, const LLSD& resp } // fetch observer -class LLCurrentlyWorn : public LLInventoryFetchObserver +class LLCurrentlyWorn : public LLInventoryFetchItemsObserver { public: - LLCurrentlyWorn() {} + LLCurrentlyWorn(const uuid_vec_t& item_ids) : LLInventoryFetchItemsObserver(item_ids){} ~LLCurrentlyWorn() {} virtual void done() { /* no operation necessary */} }; @@ -2799,8 +2799,8 @@ void LLFloaterCustomize::fetchInventory() // Fire & forget. The mInventoryObserver will catch inventory // updates and correct the UI as necessary. - LLCurrentlyWorn worn; - worn.fetchItems(ids); + LLCurrentlyWorn worn(ids); + worn.startFetch(); } void LLFloaterCustomize::updateInventoryUI() diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 7cff25975..e81d1d183 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1877,13 +1877,17 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, } //Used by LLFolderBridge as callback for directory recursion. -class LLRightClickInventoryFetchObserver : public LLInventoryFetchObserver +class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver { public: - LLRightClickInventoryFetchObserver() : + LLRightClickInventoryFetchObserver(const uuid_vec_t& ids) : + LLInventoryFetchItemsObserver(ids), mCopyItems(false) { }; - LLRightClickInventoryFetchObserver(const LLUUID& cat_id, bool copy_items) : + LLRightClickInventoryFetchObserver(const uuid_vec_t& ids, + const LLUUID& cat_id, + bool copy_items) : + LLInventoryFetchItemsObserver(ids), mCatID(cat_id), mCopyItems(copy_items) { }; @@ -1907,7 +1911,11 @@ protected: class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver { public: - LLRightClickInventoryFetchDescendentsObserver(bool copy_items) : mCopyItems(copy_items) {} + LLRightClickInventoryFetchDescendentsObserver(const uuid_vec_t& ids, + bool copy_items) : + LLInventoryFetchDescendentsObserver(ids), + mCopyItems(copy_items) + {} ~LLRightClickInventoryFetchDescendentsObserver() {} virtual void done(); protected: @@ -1918,7 +1926,7 @@ void LLRightClickInventoryFetchDescendentsObserver::done() { // Avoid passing a NULL-ref as mCompleteFolders.front() down to // gInventory.collectDescendents() - if( mCompleteFolders.empty() ) + if( mComplete.empty() ) { llwarns << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << llendl; dec_busy_count(); @@ -1932,7 +1940,7 @@ void LLRightClickInventoryFetchDescendentsObserver::done() // happen. LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(mCompleteFolders.front(), + gInventory.collectDescendents(mComplete.front(), cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH); @@ -1941,7 +1949,7 @@ void LLRightClickInventoryFetchDescendentsObserver::done() // This early causes a giant menu to get produced, and doesn't seem to be needed. if(!count) { - llwarns << "Nothing fetched in category " << mCompleteFolders.front() + llwarns << "Nothing fetched in category " << mComplete.front() << llendl; dec_busy_count(); gInventory.removeObserver(this); @@ -1956,7 +1964,7 @@ void LLRightClickInventoryFetchDescendentsObserver::done() ids.push_back(item_array.get(i)->getUUID()); } - LLRightClickInventoryFetchObserver* outfit = new LLRightClickInventoryFetchObserver(mCompleteFolders.front(), mCopyItems); + LLRightClickInventoryFetchObserver* outfit = new LLRightClickInventoryFetchObserver(ids, mComplete.front(), mCopyItems); // clean up, and remove this as an observer since the call to the // outfit could notify observers and throw us into an infinite @@ -1970,7 +1978,7 @@ void LLRightClickInventoryFetchDescendentsObserver::done() inc_busy_count(); // do the fetch - outfit->fetchItems(ids); + outfit->startFetch(); outfit->done(); //Not interested in waiting and this will be right 99% of the time. //Uncomment the following code for laggy Inventory UI. /* if(outfit->isEverythingComplete()) @@ -2549,10 +2557,10 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) mMenu = menu.getHandle(); sSelf = getHandle(); - LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(FALSE); - fetch->fetchDescendents(folders); + LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders, FALSE); + fetch->startFetch(); inc_busy_count(); - if(fetch->isEverythingComplete()) + if(fetch->isFinished()) { // everything is already here - call done. fetch->done(); @@ -4358,10 +4366,11 @@ struct LLWearableHoldingPattern */ // [/RLVa:KB] -class LLOutfitObserver : public LLInventoryFetchObserver +class LLOutfitObserver : public LLInventoryFetchItemsObserver { public: - LLOutfitObserver(const LLUUID& cat_id, bool copy_items, bool append) : + LLOutfitObserver(const uuid_vec_t& ids, const LLUUID& cat_id, bool copy_items, bool append) : + LLInventoryFetchItemsObserver(ids), mCatID(cat_id), mCopyItems(copy_items), mAppend(append) @@ -4490,7 +4499,7 @@ void LLOutfitObserver::done() class LLOutfitFetch : public LLInventoryFetchDescendentsObserver { public: - LLOutfitFetch(bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {} + LLOutfitFetch(const LLUUID& id, bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {} ~LLOutfitFetch() {} virtual void done(); protected: @@ -4505,14 +4514,14 @@ void LLOutfitFetch::done() // happen. LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(mCompleteFolders.front(), + gInventory.collectDescendents(mComplete.front(), cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH); S32 count = item_array.count(); if(!count) { - llwarns << "Nothing fetched in category " << mCompleteFolders.front() + llwarns << "Nothing fetched in category " << mComplete.front() << llendl; dec_busy_count(); gInventory.removeObserver(this); @@ -4520,14 +4529,15 @@ void LLOutfitFetch::done() return; } - LLOutfitObserver* outfit; - outfit = new LLOutfitObserver(mCompleteFolders.front(), mCopyItems, mAppend); uuid_vec_t ids; for(S32 i = 0; i < count; ++i) { ids.push_back(item_array.get(i)->getUUID()); } + LLOutfitObserver* outfit = new LLOutfitObserver(ids, mComplete.front(), mCopyItems, mAppend); + + // clean up, and remove this as an observer since the call to the // outfit could notify observers and throw us into an infinite // loop. @@ -4540,8 +4550,8 @@ void LLOutfitFetch::done() inc_busy_count(); // do the fetch - outfit->fetchItems(ids); - if(outfit->isEverythingComplete()) + outfit->startFetch(); + if(outfit->isFinished()) { // everything is already here - call done. outfit->done(); @@ -4610,13 +4620,10 @@ void wear_inventory_category(LLInventoryCategory* category, bool copy, bool appe // 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. - LLOutfitFetch* outfit; - outfit = new LLOutfitFetch(copy, append); - LLInventoryFetchDescendentsObserver::folder_ref_t folders; - folders.push_back(category->getUUID()); - outfit->fetchDescendents(folders); + LLOutfitFetch* outfit = new LLOutfitFetch(category->getUUID(), copy, append); + outfit->startFetch(); inc_busy_count(); - if(outfit->isEverythingComplete()) + if(outfit->isFinished()) { // everything is already here - call done. outfit->done(); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index ecccc891e..5b4dab172 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1365,7 +1365,7 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const //{ // known_descendents += items->count(); //} - return cat->fetchDescendents(); + return cat->fetch(); } void LLInventoryModel::cache( diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index e361015c7..5c67d5017 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -246,7 +246,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() { // category exists but has no children yet, fetch the descendants // for now, just request every time and rely on retry timer to throttle - if (cat->fetchDescendents()) + if (cat->fetch()) { mFetchTimer.reset(); mTimelyFetchPending = TRUE; diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index e9f8207af..887f0a474 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -40,7 +40,7 @@ #include "llfloater.h" #include "llfocusmgr.h" #include "llinventorybridge.h" -//#include "llinventoryfunctions.h" +#include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llviewermessage.h" #include "llviewerwindow.h" @@ -58,7 +58,45 @@ const F32 LLInventoryFetchItemsObserver::FETCH_TIMER_EXPIRY = 60.0f; -void fetch_items_from_llsd(const LLSD& items_llsd); + +LLInventoryObserver::LLInventoryObserver() +{ +} + +// virtual +LLInventoryObserver::~LLInventoryObserver() +{ +} + +LLInventoryFetchObserver::LLInventoryFetchObserver(const LLUUID& id) +{ + mIDs.clear(); + if (id != LLUUID::null) + { + setFetchID(id); + } +} + +LLInventoryFetchObserver::LLInventoryFetchObserver(const uuid_vec_t& ids) +{ + setFetchIDs(ids); +} + +BOOL LLInventoryFetchObserver::isFinished() const +{ + return mIncomplete.empty(); +} + +void LLInventoryFetchObserver::setFetchIDs(const uuid_vec_t& ids) +{ + mIDs = ids; +} +void LLInventoryFetchObserver::setFetchID(const LLUUID& id) +{ + mIDs.clear(); + mIDs.push_back(id); +} + void LLInventoryCompletionObserver::changed(U32 mask) { @@ -74,7 +112,7 @@ void LLInventoryCompletionObserver::changed(U32 mask) it = mIncomplete.erase(it); continue; } - if(item->isComplete()) + if (item->isFinished()) { mComplete.push_back(*it); it = mIncomplete.erase(it); @@ -97,25 +135,18 @@ void LLInventoryCompletionObserver::watchItem(const LLUUID& id) } } -LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const LLUUID& item_id) +LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const LLUUID& item_id) : + LLInventoryFetchObserver(item_id) { mIDs.clear(); - if (item_id != LLUUID::null) - { - mIDs.push_back(item_id); - } + mIDs.push_back(item_id); } -LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids) - : mIDs(item_ids) +LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids) : + LLInventoryFetchObserver(item_ids) { } -BOOL LLInventoryFetchItemsObserver::isFinished() const -{ - return mIncomplete.empty(); -} - void LLInventoryFetchItemsObserver::changed(U32 mask) { lldebugs << this << " remaining incomplete " << mIncomplete.size() @@ -134,7 +165,7 @@ void LLInventoryFetchItemsObserver::changed(U32 mask) { const LLUUID& item_id = (*it); LLViewerInventoryItem* item = gInventory.getItem(item_id); - if (item && item->isComplete()) + if (item && item->isFinished()) { mComplete.push_back(item_id); it = mIncomplete.erase(it); @@ -167,97 +198,6 @@ void LLInventoryFetchItemsObserver::changed(U32 mask) //llinfos << "LLInventoryFetchItemsObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; } -void LLInventoryFetchItemsObserver::startFetch() -{ - LLUUID owner_id; - LLSD items_llsd; - for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if (item) - { - if (item->isComplete()) - { - // It's complete, so put it on the complete container. - mComplete.push_back(*it); - continue; - } - else - { - owner_id = item->getPermissions().getOwner(); - } - } - else - { - // assume it's agent inventory. - owner_id = gAgent.getID(); - } - - // Ignore categories since they're not items. We - // could also just add this to mComplete but not sure what the - // side-effects would be, so ignoring to be safe. - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if (cat) - { - continue; - } - - // It's incomplete, so put it on the incomplete container, and - // pack this on the message. - mIncomplete.push_back(*it); - - // Prepare the data to fetch - LLSD item_entry; - item_entry["owner_id"] = owner_id; - item_entry["item_id"] = (*it); - items_llsd.append(item_entry); - } - - mFetchingPeriod.reset(); - mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY); - - fetch_items_from_llsd(items_llsd); -} - -void LLInventoryFetchObserver::changed(U32 mask) -{ - // scan through the incomplete items and move or erase them as - // appropriate. - if(!mIncomplete.empty()) - { - for(uuid_vec_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - // BUG: This can cause done() to get called prematurely below. - // This happens with the LLGestureInventoryFetchObserver that - // loads gestures at startup. JC - it = mIncomplete.erase(it); - continue; - } - if(item->isComplete()) - { - mComplete.push_back(*it); - it = mIncomplete.erase(it); - continue; - } - ++it; - } - if(mIncomplete.empty()) - { - done(); - } - } - //llinfos << "LLInventoryFetchObserver::changed() mComplete size " << mComplete.size() << llendl; - //llinfos << "LLInventoryFetchObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; -} - -bool LLInventoryFetchObserver::isEverythingComplete() const -{ - return mIncomplete.empty(); -} - void fetch_items_from_llsd(const LLSD& items_llsd) { if (!items_llsd.size() || gDisconnected) return; @@ -328,17 +268,16 @@ void fetch_items_from_llsd(const LLSD& items_llsd) } } -void LLInventoryFetchObserver::fetchItems( - const uuid_vec_t& ids) +void LLInventoryFetchItemsObserver::startFetch() { LLUUID owner_id; LLSD items_llsd; - for(uuid_vec_t::const_iterator it = ids.begin(); it < ids.end(); ++it) + for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) { LLViewerInventoryItem* item = gInventory.getItem(*it); - if(item) + if (item) { - if(item->isComplete()) + if (item->isFinished()) { // It's complete, so put it on the complete container. mComplete.push_back(*it); @@ -354,206 +293,174 @@ void LLInventoryFetchObserver::fetchItems( // assume it's agent inventory. owner_id = gAgent.getID(); } - + + // Ignore categories since they're not items. We + // could also just add this to mComplete but not sure what the + // side-effects would be, so ignoring to be safe. + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if (cat) + { + continue; + } + // It's incomplete, so put it on the incomplete container, and // pack this on the message. mIncomplete.push_back(*it); - + // Prepare the data to fetch LLSD item_entry; item_entry["owner_id"] = owner_id; item_entry["item_id"] = (*it); items_llsd.append(item_entry); } + + mFetchingPeriod.reset(); + mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY); + fetch_items_from_llsd(items_llsd); } + +LLInventoryFetchDescendentsObserver::LLInventoryFetchDescendentsObserver(const LLUUID& cat_id) : + LLInventoryFetchObserver(cat_id) +{ +} + +LLInventoryFetchDescendentsObserver::LLInventoryFetchDescendentsObserver(const uuid_vec_t& cat_ids) : + LLInventoryFetchObserver(cat_ids) +{ +} + // virtual void LLInventoryFetchDescendentsObserver::changed(U32 mask) { - for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) + for (uuid_vec_t::iterator it = mIncomplete.begin(); it < mIncomplete.end();) { LLViewerInventoryCategory* cat = gInventory.getCategory(*it); if(!cat) { - it = mIncompleteFolders.erase(it); + it = mIncomplete.erase(it); continue; } - if(isComplete(cat)) + if (isCategoryComplete(cat)) { - mCompleteFolders.push_back(*it); - it = mIncompleteFolders.erase(it); + mComplete.push_back(*it); + it = mIncomplete.erase(it); continue; } ++it; } - if(mIncompleteFolders.empty()) + if (mIncomplete.empty()) { done(); } } -void LLInventoryFetchDescendentsObserver::fetchDescendents( - const folder_ref_t& ids) +void LLInventoryFetchDescendentsObserver::startFetch() { - for(folder_ref_t::const_iterator it = ids.begin(); it != ids.end(); ++it) + for (uuid_vec_t::const_iterator it = mIDs.begin(); it != mIDs.end(); ++it) { LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if(!cat) continue; - if(!isComplete(cat)) + if (!cat) continue; + if (!isCategoryComplete(cat)) { - cat->fetchDescendents(); //blindly fetch it without seeing if anything else is fetching it. - mIncompleteFolders.push_back(*it); //Add to list of things being downloaded for this observer. + cat->fetch(); //blindly fetch it without seeing if anything else is fetching it. + mIncomplete.push_back(*it); //Add to list of things being downloaded for this observer. } else { - mCompleteFolders.push_back(*it); + mComplete.push_back(*it); } } } -bool LLInventoryFetchDescendentsObserver::isEverythingComplete() const +BOOL LLInventoryFetchDescendentsObserver::isCategoryComplete(const LLViewerInventoryCategory* cat) const { - return mIncompleteFolders.empty(); -} - -bool LLInventoryFetchDescendentsObserver::isComplete(LLViewerInventoryCategory* cat) -{ - S32 version = cat->getVersion(); - S32 descendents = cat->getDescendentCount(); - if((LLViewerInventoryCategory::VERSION_UNKNOWN == version) - || (LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN == descendents)) + const S32 version = cat->getVersion(); + const S32 expected_num_descendents = cat->getDescendentCount(); + if ((version == LLViewerInventoryCategory::VERSION_UNKNOWN) || + (expected_num_descendents == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)) { - return false; + return FALSE; } // it might be complete - check known descendents against // currently available. LLInventoryModel::cat_array_t* cats; LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items); - if(!cats || !items) + if (!cats || !items) { - // bit of a hack - pretend we're done if they are gone or - // incomplete. should never know, but it would suck if this - // kept tight looping because of a corrupt memory state. - return true; + llwarns << "Category '" << cat->getName() << "' descendents corrupted, fetch failed." << llendl; + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + // Unrecoverable, so just return done so that this observer can be cleared + // from memory. + return TRUE; } - S32 known = cats->count() + items->count(); - if(descendents == known) + const S32 current_num_known_descendents = cats->count() + items->count(); + + // Got the number of descendents that we were expecting, so we're done. + if (current_num_known_descendents == expected_num_descendents) { - // hey - we're done. - return true; + return TRUE; } - return false; + + // Error condition, but recoverable. This happens if something was added to the + // category before it was initialized, so accountForUpdate didn't update descendent + // count and thus the category thinks it has fewer descendents than it actually has. + if (current_num_known_descendents >= expected_num_descendents) + { + llwarns << "Category '" << cat->getName() << "' expected descendentcount:" << expected_num_descendents << " descendents but got descendentcount:" << current_num_known_descendents << llendl; + const_cast(cat)->setDescendentCount(current_num_known_descendents); + return TRUE; + } + return FALSE; +} + +LLInventoryFetchComboObserver::LLInventoryFetchComboObserver(const uuid_vec_t& folder_ids, + const uuid_vec_t& item_ids) +{ + mFetchDescendents = new LLInventoryFetchDescendentsObserver(folder_ids); + + uuid_vec_t pruned_item_ids; + for (uuid_vec_t::const_iterator item_iter = item_ids.begin(); + item_iter != item_ids.end(); + ++item_iter) + { + const LLUUID& item_id = (*item_iter); + const LLViewerInventoryItem* item = gInventory.getItem(item_id); + if (item && std::find(folder_ids.begin(), folder_ids.end(), item->getParentUUID()) == folder_ids.end()) + { + continue; + } + pruned_item_ids.push_back(item_id); + } + + mFetchItems = new LLInventoryFetchItemsObserver(pruned_item_ids); + mFetchDescendents = new LLInventoryFetchDescendentsObserver(folder_ids); +} + +LLInventoryFetchComboObserver::~LLInventoryFetchComboObserver() +{ + mFetchItems->done(); + mFetchDescendents->done(); + delete mFetchItems; + delete mFetchDescendents; } void LLInventoryFetchComboObserver::changed(U32 mask) { - if(!mIncompleteItems.empty()) + mFetchItems->changed(mask); + mFetchDescendents->changed(mask); + if (mFetchItems->isFinished() && mFetchDescendents->isFinished()) { - for(item_ref_t::iterator it = mIncompleteItems.begin(); it < mIncompleteItems.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - it = mIncompleteItems.erase(it); - continue; - } - if(item->isComplete()) - { - mCompleteItems.push_back(*it); - it = mIncompleteItems.erase(it); - continue; - } - ++it; - } - } - if(!mIncompleteFolders.empty()) - { - for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if(!cat) - { - it = mIncompleteFolders.erase(it); - continue; - } - if(gInventory.isCategoryComplete(*it)) - { - mCompleteFolders.push_back(*it); - it = mIncompleteFolders.erase(it); - continue; - } - ++it; - } - } - if(!mDone && mIncompleteItems.empty() && mIncompleteFolders.empty()) - { - mDone = true; done(); } } -void LLInventoryFetchComboObserver::fetch( - const folder_ref_t& folder_ids, - const item_ref_t& item_ids) +void LLInventoryFetchComboObserver::startFetch() { - lldebugs << "LLInventoryFetchComboObserver::fetch()" << llendl; - for(folder_ref_t::const_iterator fit = folder_ids.begin(); fit != folder_ids.end(); ++fit) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*fit); - if(!cat) continue; - if(!gInventory.isCategoryComplete(*fit)) - { - cat->fetchDescendents(); - lldebugs << "fetching folder " << *fit <isComplete()) - { - // It's complete, so put it on the complete container. - mCompleteItems.push_back(*iit); - lldebugs << "completing item " << *iit << llendl; - continue; - } - else - { - mIncompleteItems.push_back(*iit); - owner_id = item->getPermissions().getOwner(); - } - if(std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(), item->getParentUUID()) == mIncompleteFolders.end()) - { - LLSD item_entry; - item_entry["owner_id"] = owner_id; - item_entry["item_id"] = (*iit); - items_llsd.append(item_entry); - } - else - { - lldebugs << "not worrying about " << *iit << llendl; - } - } - fetch_items_from_llsd(items_llsd); + mFetchItems->startFetch(); + mFetchDescendents->startFetch(); } void LLInventoryExistenceObserver::watchItem(const LLUUID& id) @@ -587,13 +494,83 @@ void LLInventoryExistenceObserver::changed(U32 mask) } } } -void LLInventoryAddedObserver::changed(U32 mask) + +void LLInventoryAddItemByAssetObserver::changed(U32 mask) { if(!(mask & LLInventoryObserver::ADD)) { return; } + // nothing is watched + if (mWatchedAssets.size() == 0) + { + return; + } + + LLMessageSystem* msg = gMessageSystem; + if (!(msg->getMessageName() && (0 == strcmp(msg->getMessageName(), "UpdateCreateInventoryItem")))) + { + // this is not our message + return; // to prevent a crash. EXT-7921; + } + + LLPointer item = new LLViewerInventoryItem; + S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + for(S32 i = 0; i < num_blocks; ++i) + { + item->unpackMessage(msg, _PREHASH_InventoryData, i); + const LLUUID& asset_uuid = item->getAssetUUID(); + if (item->getUUID().notNull() && asset_uuid.notNull()) + { + if (isAssetWatched(asset_uuid)) + { + LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL; + mAddedItems.push_back(item->getUUID()); + } + } + } + + if (mAddedItems.size() == mWatchedAssets.size()) + { + done(); + LL_DEBUGS("Inventory_Move") << "All watched items are added & processed." << LL_ENDL; + mAddedItems.clear(); + + // Unable to clean watched items here due to somebody can require to check them in current frame. + // set dirty state to clean them while next watch cycle. + mIsDirty = true; + } +} + +void LLInventoryAddItemByAssetObserver::watchAsset(const LLUUID& asset_id) +{ + if(asset_id.notNull()) + { + if (mIsDirty) + { + LL_DEBUGS("Inventory_Move") << "Watched items are dirty. Clean them." << LL_ENDL; + mWatchedAssets.clear(); + mIsDirty = false; + } + + mWatchedAssets.push_back(asset_id); + onAssetAdded(asset_id); + } +} + +bool LLInventoryAddItemByAssetObserver::isAssetWatched( const LLUUID& asset_id ) +{ + return std::find(mWatchedAssets.begin(), mWatchedAssets.end(), asset_id) != mWatchedAssets.end(); +} + +void LLInventoryAddedObserver::changed(U32 mask) +{ + if (!(mask & LLInventoryObserver::ADD)) + { + return; + } + // *HACK: If this was in response to a packet off // the network, figure out which item was updated. LLMessageSystem* msg = gMessageSystem; @@ -627,6 +604,34 @@ void LLInventoryAddedObserver::changed(U32 mask) } } +void LLInventoryCategoryAddedObserver::changed(U32 mask) +{ + if (!(mask & LLInventoryObserver::ADD)) + { + return; + } + + const LLInventoryModel::changed_items_t& changed_ids = gInventory.getChangedIDs(); + + for (LLInventoryModel::changed_items_t::const_iterator cit = changed_ids.begin(); cit != changed_ids.end(); ++cit) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*cit); + + if (cat) + { + mAddedCategories.push_back(cat); + } + } + + if (!mAddedCategories.empty()) + { + done(); + + mAddedCategories.clear(); + } +} + + LLInventoryTransactionObserver::LLInventoryTransactionObserver(const LLTransactionID& transaction_id) : mTransactionID(transaction_id) { @@ -676,4 +681,140 @@ void LLInventoryTransactionObserver::changed(U32 mask) } } } -} \ No newline at end of file +} + +void LLInventoryCategoriesObserver::changed(U32 mask) +{ + if (!mCategoryMap.size()) + return; + + for (category_map_t::iterator iter = mCategoryMap.begin(); + iter != mCategoryMap.end(); + ++iter) + { + const LLUUID& cat_id = (*iter).first; + + LLViewerInventoryCategory* category = gInventory.getCategory(cat_id); + if (!category) + continue; + + const S32 version = category->getVersion(); + const S32 expected_num_descendents = category->getDescendentCount(); + if ((version == LLViewerInventoryCategory::VERSION_UNKNOWN) || + (expected_num_descendents == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)) + { + continue; + } + + // Check number of known descendents to find out whether it has changed. + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat_id, cats, items); + if (!cats || !items) + { + llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl; + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + // Unrecoverable, so just skip this category. + + llassert(cats != NULL && items != NULL); + + continue; + } + + const S32 current_num_known_descendents = cats->count() + items->count(); + + LLCategoryData& cat_data = (*iter).second; + + bool cat_changed = false; + + // If category version or descendents count has changed + // update category data in mCategoryMap + if (version != cat_data.mVersion || current_num_known_descendents != cat_data.mDescendentsCount) + { + cat_data.mVersion = version; + cat_data.mDescendentsCount = current_num_known_descendents; + cat_changed = true; + } + + // If any item names have changed, update the name hash + // Only need to check if (a) name hash has not previously been + // computed, or (b) a name has changed. + if (!cat_data.mIsNameHashInitialized || (mask & LLInventoryObserver::LABEL)) + { + LLMD5 item_name_hash = gInventory.hashDirectDescendentNames(cat_id); + if (cat_data.mItemNameHash != item_name_hash) + { + cat_data.mIsNameHashInitialized = true; + cat_data.mItemNameHash = item_name_hash; + cat_changed = true; + } + } + + // If anything has changed above, fire the callback. + if (cat_changed) + cat_data.mCallback(); + } +} + +bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb) +{ + S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN; + S32 current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN; + bool can_be_added = true; + + LLViewerInventoryCategory* category = gInventory.getCategory(cat_id); + // If category could not be retrieved it might mean that + // inventory is unusable at the moment so the category is + // stored with VERSION_UNKNOWN and DESCENDENT_COUNT_UNKNOWN, + // it may be updated later. + if (category) + { + // Inventory category version is used to find out if some changes + // to a category have been made. + version = category->getVersion(); + + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat_id, cats, items); + if (!cats || !items) + { + llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl; + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + // Unrecoverable, so just return "false" meaning that the category can't be observed. + can_be_added = false; + + llassert(cats != NULL && items != NULL); + } + else + { + current_num_known_descendents = cats->count() + items->count(); + } + } + + if (can_be_added) + { + mCategoryMap.insert(category_map_value_t( + cat_id,LLCategoryData(cat_id, cb, version, current_num_known_descendents))); + } + + return can_be_added; +} + +void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id) +{ + mCategoryMap.erase(cat_id); +} + +LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData( + const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents) + + : mCatID(cat_id) + , mCallback(cb) + , mVersion(version) + , mDescendentsCount(num_descendents) + , mIsNameHashInitialized(false) +{ + mItemNameHash.finalize(); +} diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index e07beabd4..bf45db43d 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -58,49 +58,48 @@ public: GESTURE = 64, ALL = 0xffffffff }; - virtual ~LLInventoryObserver() {}; + LLInventoryObserver(); + virtual ~LLInventoryObserver(); virtual void changed(U32 mask) = 0; }; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryFetchObserver // -// This class is much like the LLInventoryCompletionObserver, except -// that it handles all the the fetching necessary. Override the done() -// method to do the thing you want. +// Abstract class to handle fetching items, folders, etc. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - class LLInventoryFetchObserver : public LLInventoryObserver { public: - LLInventoryFetchObserver() {} - virtual void changed(U32 mask); - - bool isEverythingComplete() const; - void fetchItems(const uuid_vec_t& ids); - virtual void done() = 0; - -protected: - uuid_vec_t mComplete; - uuid_vec_t mIncomplete; -}; - -class LLInventoryFetchItemsObserver : public LLInventoryObserver -{ -public: - LLInventoryFetchItemsObserver(const LLUUID& item_id = LLUUID::null); - LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids); + LLInventoryFetchObserver(const LLUUID& id = LLUUID::null); // single item + LLInventoryFetchObserver(const uuid_vec_t& ids); // multiple items + void setFetchID(const LLUUID& id); + void setFetchIDs(const uuid_vec_t& ids); BOOL isFinished() const; - virtual void startFetch(); - virtual void changed(U32 mask); + virtual void startFetch() = 0; + virtual void changed(U32 mask) = 0; virtual void done() {}; protected: uuid_vec_t mComplete; uuid_vec_t mIncomplete; uuid_vec_t mIDs; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryFetchItemsObserver +// +// Fetches inventory items, calls done() when all inventory has arrived. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryFetchItemsObserver : public LLInventoryFetchObserver +{ +public: + LLInventoryFetchItemsObserver(const LLUUID& item_id = LLUUID::null); + LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids); + + /*virtual*/ void startFetch(); + /*virtual*/ void changed(U32 mask); private: LLTimer mFetchingPeriod; @@ -113,120 +112,147 @@ private: //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryFetchDescendentsObserver // -// This class is much like the LLInventoryCompletionObserver, except -// that it handles fetching based on category. Override the done() -// method to do the thing you want. +// Fetches children of a category/folder, calls done() when all +// inventory has arrived. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryFetchDescendentsObserver : public LLInventoryObserver +class LLInventoryFetchDescendentsObserver : public LLInventoryFetchObserver { public: - LLInventoryFetchDescendentsObserver() {} - virtual void changed(U32 mask); - - typedef std::vector folder_ref_t; - void fetchDescendents(const folder_ref_t& ids); - bool isEverythingComplete() const; - virtual void done() = 0; + LLInventoryFetchDescendentsObserver(const LLUUID& cat_id = LLUUID::null); + LLInventoryFetchDescendentsObserver(const uuid_vec_t& cat_ids); + /*virtual*/ void startFetch(); + /*virtual*/ void changed(U32 mask); protected: - bool isComplete(LLViewerInventoryCategory* cat); - folder_ref_t mIncompleteFolders; - folder_ref_t mCompleteFolders; + BOOL isCategoryComplete(const LLViewerInventoryCategory* cat) const; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryFetchComboObserver // -// This class does an appropriate combination of fetch descendents and -// item fetches based on completion of categories and items. Much like -// the fetch and fetch descendents, this will call done() when everything -// has arrived. +// Does an appropriate combination of fetch descendents and +// item fetches based on completion of categories and items. This is optimized +// to not fetch item_ids that are descendents of any of the folder_ids. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLInventoryFetchComboObserver : public LLInventoryObserver { public: - LLInventoryFetchComboObserver() : mDone(false) {} - virtual void changed(U32 mask); - - typedef std::vector folder_ref_t; - typedef std::vector item_ref_t; - void fetch(const folder_ref_t& folder_ids, const item_ref_t& item_ids); + LLInventoryFetchComboObserver(const uuid_vec_t& folder_ids, + const uuid_vec_t& item_ids); + ~LLInventoryFetchComboObserver(); + /*virtual*/ void changed(U32 mask); + void startFetch(); virtual void done() = 0; - protected: - bool mDone; - folder_ref_t mCompleteFolders; - folder_ref_t mIncompleteFolders; - item_ref_t mCompleteItems; - item_ref_t mIncompleteItems; + LLInventoryFetchItemsObserver *mFetchItems; + LLInventoryFetchDescendentsObserver *mFetchDescendents; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryExistenceObserver // -// This class is used as a base class for doing somethign when all the -// observed item ids exist in the inventory somewhere. You can derive -// a class from this class and implement the done() method to do -// something useful. +// Used as a base class for doing something when all the +// observed item ids exist in the inventory somewhere. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - class LLInventoryExistenceObserver : public LLInventoryObserver { public: LLInventoryExistenceObserver() {} - virtual void changed(U32 mask); + /*virtual*/ void changed(U32 mask); void watchItem(const LLUUID& id); - protected: virtual void done() = 0; - uuid_vec_t mExist; uuid_vec_t mMIA; }; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryMovedObserver +// +// This class is used as a base class for doing something when all the +// item for observed asset ids were added into the inventory. +// Derive a class from this class and implement the done() method to do +// something useful. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryAddItemByAssetObserver : public LLInventoryObserver +{ +public: + LLInventoryAddItemByAssetObserver() : mIsDirty(false) {} + virtual void changed(U32 mask); + + void watchAsset(const LLUUID& asset_id); + bool isAssetWatched(const LLUUID& asset_id); + +protected: + virtual void onAssetAdded(const LLUUID& asset_id) {} + virtual void done() = 0; + + typedef std::vector item_ref_t; + item_ref_t mAddedItems; + item_ref_t mWatchedAssets; + +private: + bool mIsDirty; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryAddedObserver // -// This class is used as a base class for doing something when -// a new item arrives in inventory. -// It does not watch for a certain UUID, rather it acts when anything is added -// Derive a class from this class and implement the done() method to do -// something useful. +// Base class for doing something when a new item arrives in inventory. +// It does not watch for a certain UUID, rather it acts when anything is added //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLInventoryAddedObserver : public LLInventoryObserver { public: LLInventoryAddedObserver() : mAdded() {} - virtual void changed(U32 mask); + /*virtual*/ void changed(U32 mask); protected: virtual void done() = 0; - typedef std::vector item_ref_t; - item_ref_t mAdded; + uuid_vec_t mAdded; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryCategoryAddedObserver +// +// Base class for doing something when a new category is created in the +// inventory. +// It does not watch for a certain UUID, rather it acts when anything is added +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryCategoryAddedObserver : public LLInventoryObserver +{ +public: + + typedef std::vector cat_vec_t; + + LLInventoryCategoryAddedObserver() : mAddedCategories() {} + /*virtual*/ void changed(U32 mask); + +protected: + virtual void done() = 0; + + cat_vec_t mAddedCategories; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryTransactionObserver // -// Class which can be used as a base class for doing something when an -// inventory transaction completes. -// -// *NOTE: This class is not quite complete. Avoid using unless you fix up it's -// functionality gaps. +// Base class for doing something when an inventory transaction completes. +// NOTE: This class is not quite complete. Avoid using unless you fix up its +// functionality gaps. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - class LLInventoryTransactionObserver : public LLInventoryObserver { public: LLInventoryTransactionObserver(const LLTransactionID& transaction_id); - virtual void changed(U32 mask); + /*virtual*/ void changed(U32 mask); protected: - typedef std::vector folder_ref_t; - typedef std::vector item_ref_t; - virtual void done(const folder_ref_t& folders, const item_ref_t& items) = 0; + virtual void done(const uuid_vec_t& folders, const uuid_vec_t& items) = 0; LLTransactionID mTransactionID; }; @@ -234,17 +260,16 @@ protected: //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryCompletionObserver // -// Class which can be used as a base class for doing something when -// when all observed items are locally complete. This class implements -// the changed() method of LLInventoryObserver and declares a new -// method named done() which is called when all watched items have -// complete information in the inventory model. +// Base class for doing something when when all observed items are locally +// complete. Implements the changed() method of LLInventoryObserver +// and declares a new method named done() which is called when all watched items +// have complete information in the inventory model. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLInventoryCompletionObserver : public LLInventoryObserver { public: LLInventoryCompletionObserver() {} - virtual void changed(U32 mask); + /*virtual*/ void changed(U32 mask); void watchItem(const LLUUID& id); @@ -255,4 +280,47 @@ protected: uuid_vec_t mIncomplete; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryCategoriesObserver +// +// This class is used for monitoring a list of inventory categories +// and firing a callback when there are changes in any of them. +// Categories are identified by their UUIDs. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryCategoriesObserver : public LLInventoryObserver +{ +public: + typedef boost::function callback_t; + + LLInventoryCategoriesObserver() {}; + virtual void changed(U32 mask); + + /** + * Add cat_id to the list of observed categories with a + * callback fired on category being changed. + * + * @return "true" if category was added, "false" if it could + * not be found. + */ + bool addCategory(const LLUUID& cat_id, callback_t cb); + void removeCategory(const LLUUID& cat_id); + +protected: + struct LLCategoryData + { + LLCategoryData(const LLUUID& cat_id, callback_t cb, S32 version, S32 num_descendents); + + callback_t mCallback; + S32 mVersion; + S32 mDescendentsCount; + LLMD5 mItemNameHash; + bool mIsNameHashInitialized; + LLUUID mCatID; + }; + + typedef std::map category_map_t; + typedef category_map_t::value_type category_map_value_t; + + category_map_t mCategoryMap; +}; #endif // LL_LLINVENTORYOBSERVERS_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index f940ca151..6a47c0dce 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -323,10 +323,10 @@ namespace }; } -class LLGestureInventoryFetchObserver : public LLInventoryFetchObserver +class LLGestureInventoryFetchObserver : public LLInventoryFetchItemsObserver { public: - LLGestureInventoryFetchObserver() {} + LLGestureInventoryFetchObserver(const uuid_vec_t& item_ids) : LLInventoryFetchItemsObserver(item_ids) {} virtual void done() { // we've downloaded all the items, so repaint the dialog @@ -2690,8 +2690,7 @@ bool idle_startup() } } - LLGestureInventoryFetchObserver* fetch = new LLGestureInventoryFetchObserver(); - fetch->fetchItems(item_ids); + LLGestureInventoryFetchObserver* fetch = new LLGestureInventoryFetchObserver(item_ids); // deletes itself when done gInventory.addObserver(fetch); } diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 9826c9e78..267c838ec 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -1337,20 +1337,6 @@ void LLTextureCtrl::closeFloater() } } -// Allow us to download textures quickly when floater is shown -class LLTextureFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver -{ -public: - virtual void done() - { - // We need to find textures in all folders, so get the main - // background download going. - LLInventoryModelBackgroundFetch::instance().start(); - gInventory.removeObserver(this); - delete this; - } -}; - BOOL LLTextureCtrl::handleHover(S32 x, S32 y, MASK mask) { getWindow()->setCursor(UI_CURSOR_HAND); diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 42ffd4a6b..c4967c2e9 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -190,10 +190,16 @@ bool LLDropCopyableItems::operator()( return allowed; } +// Starts a fetch on folders and items. This is really not used +// as an observer in the traditional sense; we're just using it to +// request a fetch and we don't care about when/if the response arrives. class LLCategoryFireAndForget : public LLInventoryFetchComboObserver { public: - LLCategoryFireAndForget() {} + LLCategoryFireAndForget(const uuid_vec_t& folder_ids, + const uuid_vec_t& item_ids) : + LLInventoryFetchComboObserver(folder_ids, item_ids) + {} ~LLCategoryFireAndForget() {} virtual void done() { @@ -202,11 +208,13 @@ public: } }; -class LLCategoryDropObserver : public LLInventoryFetchObserver +class LLCategoryDropObserver : public LLInventoryFetchItemsObserver { public: LLCategoryDropObserver( + const uuid_vec_t& ids, const LLUUID& obj_id, LLToolDragAndDrop::ESource src) : + LLInventoryFetchItemsObserver(ids), mObjectID(obj_id), mSource(src) {} @@ -243,7 +251,7 @@ void LLCategoryDropObserver::done() } delete this; } - +/* Doesn't seem to be used anymore. class LLCategoryDropDescendentsObserver : public LLInventoryFetchDescendentsObserver { public: @@ -264,8 +272,8 @@ void LLCategoryDropDescendentsObserver::done() { gInventory.removeObserver(this); - folder_ref_t::iterator it = mCompleteFolders.begin(); - folder_ref_t::iterator end = mCompleteFolders.end(); + uuid_vec_t::iterator it = mComplete.begin(); + uuid_vec_t::iterator end = mComplete.end(); LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; for(; it != end; ++it) @@ -302,6 +310,7 @@ void LLCategoryDropDescendentsObserver::done() } delete this; } +*/ // This array is used to more easily control what happens when a 3d // drag and drop event occurs. Since there's an array of drop target @@ -522,8 +531,9 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type, } if(!folder_ids.empty() || !item_ids.empty()) { - LLCategoryFireAndForget fetcher; - fetcher.fetch(folder_ids, item_ids); + LLCategoryFireAndForget *fetcher = new LLCategoryFireAndForget(folder_ids, item_ids); + fetcher->startFetch(); + delete fetcher; } } } @@ -531,7 +541,7 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type, void LLToolDragAndDrop::beginMultiDrag( const std::vector types, - const std::vector& cargo_ids, + const uuid_vec_t& cargo_ids, ESource source, const LLUUID& source_id) { @@ -592,8 +602,7 @@ void LLToolDragAndDrop::beginMultiDrag( uuid_vec_t item_ids; std::back_insert_iterator copier(folder_ids); std::copy(cat_ids.begin(), cat_ids.end(), copier); - LLCategoryFireAndForget fetcher; - fetcher.fetch(folder_ids, item_ids); + LLCategoryFireAndForget fetcher(folder_ids, item_ids); } } } @@ -1256,7 +1265,7 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return; + if (!item || !item->isFinished()) return; if (regionp && (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX)) @@ -1289,9 +1298,8 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, // Check if it's in the trash. bool is_in_trash = false; - LLUUID trash_id; - trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) { is_in_trash = true; remove_from_inventory = TRUE; @@ -1509,8 +1517,8 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL // HACK: downcast LLViewerInventoryItem* vitem = (LLViewerInventoryItem*)item; // - //if(!vitem->isComplete()) return ACCEPT_NO; - if(!vitem->isComplete() && !(gInventory.isObjectDescendentOf(vitem->getUUID(), gSystemFolderRoot))) return ACCEPT_NO; + //if(!vitem->isFinished()) return ACCEPT_NO; + if(!vitem->isFinished() && !(gInventory.isObjectDescendentOf(vitem->getUUID(), gSystemFolderRoot))) return ACCEPT_NO; // if (vitem->getIsLinkType()) return ACCEPT_NO; // No giving away links @@ -1527,7 +1535,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL // gAgent.getGroupID()) // && (obj->mPermModify || obj->mFlagAllowInventoryAdd)); BOOL worn = FALSE; - LLVOAvatar* my_avatar = NULL; + LLVOAvatarSelf* my_avatar = NULL; switch(item->getType()) { case LLAssetType::AT_OBJECT: @@ -1691,10 +1699,10 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; // must not be in the trash - LLUUID trash_id(gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) ) { return ACCEPT_NO; @@ -1768,7 +1776,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; // //LLVOAvatar* my_avatar = gAgentAvatarp; @@ -1804,8 +1812,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( } // Check if it's in the trash. - LLUUID trash_id; - trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) { accept = ACCEPT_YES_SINGLE; @@ -1845,7 +1852,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if(!item || !item->isFinished()) return ACCEPT_NO; // //LLVOAvatar* my_avatar = gAgentAvatarp; //if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) @@ -1897,8 +1904,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( } // Check if it's in the trash. - LLUUID trash_id; - trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) { accept = ACCEPT_YES_SINGLE; @@ -1928,7 +1934,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; EAcceptance rv = willObjectAcceptInventory(obj, item); if(drop && (ACCEPT_YES_SINGLE <= rv)) { @@ -1971,8 +1977,8 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject( LLViewerInventoryCategory* cat; locateInventory(item, cat); // - //if(!item || !item->isComplete()) return ACCEPT_NO; - if( !item || (!item->isComplete() && !(gInventory.isObjectDescendentOf(item->getUUID(), gSystemFolderRoot))) ) return ACCEPT_NO; + //if(!item || !item->isFinished()) return ACCEPT_NO; + if( !item || (!item->isFinished() && !(gInventory.isObjectDescendentOf(item->getUUID(), gSystemFolderRoot))) ) return ACCEPT_NO; // EAcceptance rv = willObjectAcceptInventory(obj, item); if((mask & MASK_CONTROL)) @@ -2003,6 +2009,7 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject( { dropTextureOneFace(obj, face, item, mSource, mSourceID); } + // VEFFECT: SetTexture LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); @@ -2038,7 +2045,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if(!item || !item->isFinished()) return ACCEPT_NO; if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY) { @@ -2100,7 +2107,7 @@ EAcceptance LLToolDragAndDrop::dad3dActivateGesture( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY) { @@ -2164,7 +2171,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( if(mSource == SOURCE_AGENT) { - LLUUID trash_id(gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if( gInventory.isObjectDescendentOf( category->getUUID(), trash_id ) ) { return ACCEPT_NO; @@ -2208,7 +2215,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventory( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; LLViewerObject* root_object = obj; if (obj && obj->getParent()) { @@ -2237,24 +2244,30 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { lldebugs << "LLToolDragAndDrop::dad3dUpdateInventoryCategory()" << llendl; - if (NULL==obj) + if (obj == NULL) { llwarns << "obj is NULL; aborting func with ACCEPT_NO" << llendl; return ACCEPT_NO; } - if (mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY) + if ((mSource != SOURCE_AGENT) && (mSource != SOURCE_LIBRARY)) { return ACCEPT_NO; } - if(obj->isAttachment()) return ACCEPT_NO_LOCKED; - LLViewerInventoryItem* item; - LLViewerInventoryCategory* cat; - locateInventory(item, cat); - if(!cat) return ACCEPT_NO; - EAcceptance rv = ACCEPT_NO; + if (obj->isAttachment()) + { + return ACCEPT_NO_LOCKED; + } - // find all the items in the category + LLViewerInventoryItem* item = NULL; + LLViewerInventoryCategory* cat = NULL; + locateInventory(item, cat); + if (!cat) + { + return ACCEPT_NO; + } + + // Find all the items in the category LLDroppableItem droppable(!obj->permYouOwner()); LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; @@ -2278,29 +2291,40 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( } } + EAcceptance rv = ACCEPT_NO; + // Check for accept - S32 i; - S32 count = cats.count(); - for(i = 0; i < count; ++i) + for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); + cat_iter != cats.end(); + ++cat_iter) { - rv = gInventory.isCategoryComplete(cats.get(i)->getUUID()) ? ACCEPT_YES_MULTI : ACCEPT_NO; + const LLViewerInventoryCategory *cat = (*cat_iter); + rv = gInventory.isCategoryComplete(cat->getUUID()) ? ACCEPT_YES_MULTI : ACCEPT_NO; if(rv < ACCEPT_YES_SINGLE) { - lldebugs << "Category " << cats.get(i)->getUUID() - << "is not complete." << llendl; + lldebugs << "Category " << cat->getUUID() << "is not complete." << llendl; break; } } - if(ACCEPT_YES_COPY_SINGLE <= rv) + if (ACCEPT_YES_COPY_SINGLE <= rv) { - count = items.count(); - for(i = 0; i < count; ++i) + for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) { - rv = willObjectAcceptInventory(root_object, items.get(i)); - if(rv < ACCEPT_YES_COPY_SINGLE) + LLViewerInventoryItem *item = (*item_iter); + /* + // Pass the base objects, not the links. + if (item && item->getIsLinkType()) { - lldebugs << "Object will not accept " - << items.get(i)->getUUID() << llendl; + item = item->getLinkedItem(); + (*item_iter) = item; + } + */ + rv = willObjectAcceptInventory(root_object, item); + if (rv < ACCEPT_YES_COPY_SINGLE) + { + lldebugs << "Object will not accept " << item->getUUID() << llendl; break; } } @@ -2309,17 +2333,17 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( // if every item is accepted, go ahead and send it on. if(drop && (ACCEPT_YES_COPY_SINGLE <= rv)) { - S32 count = items.count(); uuid_vec_t ids; - for(i = 0; i < count; ++i) + for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) { - //dropInventory(root_object, items.get(i), mSource, mSourceID); - ids.push_back(items.get(i)->getUUID()); + const LLViewerInventoryItem *item = (*item_iter); + ids.push_back(item->getUUID()); } - LLCategoryDropObserver* dropper; - dropper = new LLCategoryDropObserver(obj->getID(), mSource); - dropper->fetchItems(ids); - if(dropper->isEverythingComplete()) + LLCategoryDropObserver* dropper = new LLCategoryDropObserver(ids, obj->getID(), mSource); + dropper->startFetch(); + if (dropper->isFinished()) { dropper->done(); } @@ -2350,13 +2374,13 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) { // cannot give away no-transfer objects return ACCEPT_NO; } - LLVOAvatar* avatar = gAgentAvatarp; + LLVOAvatarSelf* avatar = gAgentAvatarp; if(avatar && avatar->isWearingAttachment( item->getUUID() ) ) { // You can't give objects that are attached to you @@ -2385,7 +2409,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventory( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; if(!LLGiveInventory::isInventoryGiveAcceptable(item)) { return ACCEPT_NO; @@ -2424,7 +2448,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand( LLViewerInventoryItem* item = NULL; LLViewerInventoryCategory* cat = NULL; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; if(!gAgent.allowOperation(PERM_COPY, item->getPermissions()) || !item->getPermissions().allowTransferTo(LLUUID::null)) @@ -2445,7 +2469,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject( LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isComplete()) return ACCEPT_NO; + if (!item || !item->isFinished()) return ACCEPT_NO; if((mask & MASK_CONTROL)) { // *HACK: In order to resolve SL-22177, we need to block drags diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index b5ef89b8b..417bbb234 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -219,10 +219,23 @@ void LLViewerInventoryItem::fetchFromServer(void) const { std::string url; - if( ALEXANDRIA_LINDEN_ID.getString() == mPermissions.getOwner().getString()) - url = gAgent.getRegion()->getCapability("FetchLib2"); - else - url = gAgent.getRegion()->getCapability("FetchInventory2"); + LLViewerRegion* region = gAgent.getRegion(); + // we have to check region. It can be null after region was destroyed. See EXT-245 + if (region) + { + if(gAgent.getID() != mPermissions.getOwner()) + { + url = region->getCapability("FetchLib2"); + } + else + { + url = region->getCapability("FetchInventory2"); + } + } + else + { + llwarns << "Agent Region is absent" << llendl; + } if (!url.empty()) { @@ -472,15 +485,16 @@ void LLViewerInventoryCategory::removeFromServer( void ) gAgent.sendReliableMessage(); } -bool LLViewerInventoryCategory::fetchDescendents() +bool LLViewerInventoryCategory::fetch() { // if((mUUID == gSystemFolderRoot) || (gInventory.isObjectDescendentOf(mUUID, gSystemFolderRoot))) return false; // - if (VERSION_UNKNOWN == mVersion && - (!mDescendentsRequested.getStarted() || - mDescendentsRequested.hasExpired())) // Expired check prevents multiple downloads. + if((VERSION_UNKNOWN == mVersion) && + (!mDescendentsRequested.getStarted() || + mDescendentsRequested.hasExpired())) //Expired check prevents multiple downloads. { + LL_DEBUGS("InventoryFetch") << "Fetching category children: " << mName << ", UUID: " << mUUID << LL_ENDL; const F32 FETCH_TIMER_EXPIRY = 10.0f; mDescendentsRequested.start(FETCH_TIMER_EXPIRY); @@ -512,7 +526,7 @@ bool LLViewerInventoryCategory::fetchDescendents() } else { //Deprecated, but if we don't have a capability, use the old system. - //llinfos << "FetchInventoryDescendents capability not found. Using deprecated UDP message." << llendl; + llinfos << "FetchInventoryDescendents2 capability not found. Using deprecated UDP message." << llendl; LLMessageSystem* msg = gMessageSystem; msg->newMessage("FetchInventoryDescendents"); msg->nextBlock("AgentData"); @@ -711,6 +725,11 @@ void ActivateGestureCallback::fire(const LLUUID& inv_item) { if (inv_item.isNull()) return; + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + if (!item) + return; + if (item->getType() != LLAssetType::AT_GESTURE) + return; LLGestureMgr::instance().activateGesture(inv_item); } diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 31f6c6c3f..95b4d1519 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -199,7 +199,7 @@ public: void setVersion(S32 version) { mVersion = version; } // Returns true if a fetch was issued. - bool fetchDescendents(); + bool fetch(); // used to help make cacheing more robust - for example, if // someone is getting 4 packets but logs out after 3. the viewer diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 4836e5323..37d589b2f 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7122,10 +7122,12 @@ class LLAttachmentDetach : public view_listener_t //Adding an observer for a Jira 2422 and needs to be a fetch observer //for Jira 3119 -class LLWornItemFetchedObserver : public LLInventoryFetchObserver +class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver { public: - LLWornItemFetchedObserver() {} + LLWornItemFetchedObserver(const LLUUID& worn_item_id) : + LLInventoryFetchItemsObserver(worn_item_id) + {} virtual ~LLWornItemFetchedObserver() {} protected: @@ -7178,13 +7180,9 @@ class LLAttachmentEnableDrop : public view_listener_t // when the item finishes fetching worst case scenario // if a fetch is already out there (being sent from a slow sim) // we refetch and there are 2 fetches - LLWornItemFetchedObserver* wornItemFetched = new LLWornItemFetchedObserver(); - uuid_vec_t items; //add item to the inventory item to be fetched - - items.push_back((*attachment_iter)->getAttachmentItemID()); - - wornItemFetched->fetchItems(items); - gInventory.addObserver(wornItemFetched); + LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID()); + worn_item_fetched->startFetch(); + gInventory.addObserver(worn_item_fetched); } } } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 163f8a0f8..1bc82e6cc 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -814,10 +814,13 @@ static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_ //----------------------------------------------------------------------------- // Instant Message //----------------------------------------------------------------------------- -class LLOpenAgentOffer : public LLInventoryFetchObserver +class LLOpenAgentOffer : public LLInventoryFetchItemsObserver { public: - LLOpenAgentOffer(const std::string& from_name) : mFromName(from_name) {} + LLOpenAgentOffer(const LLUUID& object_id, + const std::string& from_name) : + LLInventoryFetchItemsObserver(object_id), + mFromName(from_name) {} /*virtual*/ void done() { open_offer(mComplete, mFromName); @@ -856,13 +859,14 @@ void start_new_inventory_observer() } } -class LLDiscardAgentOffer : public LLInventoryFetchComboObserver +class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver { public: LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : + LLInventoryFetchItemsObserver(object_id), mFolderID(folder_id), mObjectID(object_id) {} - virtual ~LLDiscardAgentOffer() {} + virtual void done() { LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL; @@ -875,6 +879,7 @@ public: gInventory.removeObserver(this); delete this; } + protected: LLUUID mFolderID; LLUUID mObjectID; @@ -1299,11 +1304,9 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && (LLAssetType::AT_CATEGORY == mType) && (RlvInventory::instance().getSharedRoot()) && (mDesc.find(RLV_PUTINV_PREFIX) == 0) ) { - RlvGiveToRLVAgentOffer* pOffer = new RlvGiveToRLVAgentOffer(); - LLInventoryFetchComboObserver::folder_ref_t folders; - folders.push_back(mObjectID); - pOffer->fetchDescendents(folders); - if (pOffer->isEverythingComplete()) + RlvGiveToRLVAgentOffer* pOffer = new RlvGiveToRLVAgentOffer(mObjectID); + pOffer->startFetch(); + if (pOffer->isFinished()) pOffer->done(); else gInventory.addObserver(pOffer); @@ -1311,11 +1314,9 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& #endif // RLV_EXTENSION_GIVETORLV_A2A // [/RLVa:KB] - uuid_vec_t items; - items.push_back(mObjectID); - LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(from_string); - open_agent_offer->fetchItems(items); - if(catp || (itemp && itemp->isComplete())) + LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string); + open_agent_offer->startFetch(); + if(catp || (itemp && itemp->isFinished())) { open_agent_offer->done(); } @@ -1382,13 +1383,9 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // request will suffice to discard the item. if(IM_INVENTORY_OFFERED == mIM) { - LLInventoryFetchComboObserver::folder_ref_t folders; - LLInventoryFetchComboObserver::item_ref_t items; - items.push_back(mObjectID); - LLDiscardAgentOffer* discard_agent_offer; - discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); - discard_agent_offer->fetch(folders, items); - if(catp || (itemp && itemp->isComplete())) + LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); + discard_agent_offer->startFetch(); + if (catp || (itemp && itemp->isFinished())) { discard_agent_offer->done(); } @@ -3623,7 +3620,9 @@ void process_teleport_progress(LLMessageSystem* msg, void**) class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver { public: - LLFetchInWelcomeArea() {} + LLFetchInWelcomeArea(const uuid_vec_t &ids) : + LLInventoryFetchDescendentsObserver(ids) + {} virtual void done() { LLIsType is_landmark(LLAssetType::AT_LANDMARK); @@ -3634,8 +3633,8 @@ public: LLInventoryModel::cat_array_t land_cats; LLInventoryModel::item_array_t land_items; - folder_ref_t::iterator it = mCompleteFolders.begin(); - folder_ref_t::iterator end = mCompleteFolders.end(); + uuid_vec_t::iterator it = mComplete.begin(); + uuid_vec_t::iterator end = mComplete.end(); for(; it != end; ++it) { gInventory.collectDescendentsIf( @@ -3696,19 +3695,18 @@ BOOL LLPostTeleportNotifiers::tick() if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) { // get callingcards and landmarks available to the user arriving. - LLInventoryFetchDescendentsObserver::folder_ref_t folders; - LLUUID folder_id; - folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - if(folder_id.notNull()) - folders.push_back(folder_id); - folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + uuid_vec_t folders; + const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); + if(callingcard_id.notNull()) + folders.push_back(callingcard_id); + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); if(folder_id.notNull()) folders.push_back(folder_id); if(!folders.empty()) { - LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea; - fetcher->fetchDescendents(folders); - if(fetcher->isEverythingComplete()) + LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea(folders); + fetcher->startFetch(); + if(fetcher->isFinished()) { fetcher->done(); } diff --git a/indra/newview/rlvinventory.cpp b/indra/newview/rlvinventory.cpp index bd7771c46..39aab4293 100644 --- a/indra/newview/rlvinventory.cpp +++ b/indra/newview/rlvinventory.cpp @@ -44,7 +44,7 @@ const std::string RlvInventory::cstrSharedRoot = RLV_ROOT_FOLDER; class RlvSharedInventoryFetcher : public LLInventoryFetchDescendentsObserver { public: - RlvSharedInventoryFetcher() {} + RlvSharedInventoryFetcher(const uuid_vec_t& cat_ids) : LLInventoryFetchDescendentsObserver(cat_ids) {} virtual ~RlvSharedInventoryFetcher() {} virtual void done() @@ -75,19 +75,19 @@ void RlvInventory::fetchSharedInventory() gInventory.collectDescendents(pRlvRoot->getUUID(), folders, items, FALSE); // Add them to the "to fetch" list - LLInventoryFetchDescendentsObserver::folder_ref_t fetchFolders; + uuid_vec_t fetchFolders; fetchFolders.push_back(pRlvRoot->getUUID()); for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++) fetchFolders.push_back(folders.get(idxFolder)->getUUID()); // Now fetch them all in one go - RlvSharedInventoryFetcher* pFetcher = new RlvSharedInventoryFetcher(); + RlvSharedInventoryFetcher* pFetcher = new RlvSharedInventoryFetcher(fetchFolders); RLV_INFOS << "Starting fetch of " << fetchFolders.size() << " shared folders" << RLV_ENDL; - pFetcher->fetchDescendents(fetchFolders); + pFetcher->startFetch(); m_fFetchStarted = true; - if (pFetcher->isEverythingComplete()) + if (pFetcher->isFinished()) pFetcher->done(); else gInventory.addObserver(pFetcher); @@ -126,8 +126,8 @@ void RlvInventory::fetchSharedLinks() RLV_INFOS << "Starting link target fetch of " << idItems.size() << " items and " << idFolders.size() << " folders" << RLV_ENDL; // Fetch all the link item targets - RlvItemFetcher itemFetcher; - itemFetcher.fetchItems(idItems); + RlvItemFetcher itemFetcher(idItems); + itemFetcher.startFetch(); // Fetch all the link folder targets // TODO! @@ -167,8 +167,8 @@ void RlvInventory::fetchWornItems() } } - RlvItemFetcher itemFetcher; - itemFetcher.fetchItems(idItems); + RlvItemFetcher itemFetcher(idItems); + itemFetcher.startFetch(); } // Checked: 2010-09-27 (RLVa-1.1.3a) | Added: RLVa-1.1.3a @@ -176,10 +176,8 @@ void RlvInventory::fetchWornItem(const LLUUID& idItem) { if (idItem.notNull()) { - uuid_vec_t idItems; - idItems.push_back(idItem); - RlvItemFetcher itemFetcher; - itemFetcher.fetchItems(idItems); + RlvItemFetcher itemFetcher(idItem); + itemFetcher.startFetch(); } } @@ -532,7 +530,7 @@ void RlvGiveToRLVAgentOffer::done() void RlvGiveToRLVAgentOffer::doneIdle() { const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot(); - const LLViewerInventoryCategory* pFolder = (mCompleteFolders.size()) ? gInventory.getCategory(mCompleteFolders[0]) : NULL; + const LLViewerInventoryCategory* pFolder = (mComplete.size()) ? gInventory.getCategory(mComplete[0]) : NULL; if ( (pRlvRoot) && (pFolder) ) { std::string strName = pFolder->getName(); diff --git a/indra/newview/rlvinventory.h b/indra/newview/rlvinventory.h index 87dabd87c..b8dca27b9 100644 --- a/indra/newview/rlvinventory.h +++ b/indra/newview/rlvinventory.h @@ -123,7 +123,7 @@ protected: class RlvGiveToRLVAgentOffer : public LLInventoryFetchDescendentsObserver { public: - RlvGiveToRLVAgentOffer() {} + RlvGiveToRLVAgentOffer(const LLUUID& cat_id) : LLInventoryFetchDescendentsObserver(cat_id) {} virtual void done(); protected: void doneIdle(); @@ -223,10 +223,11 @@ public: virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) { return (pItem) && (pItem->getIsLinkType()); } }; -class RlvItemFetcher : public LLInventoryFetchObserver +class RlvItemFetcher : public LLInventoryFetchItemsObserver { public: - RlvItemFetcher() {} + RlvItemFetcher(const uuid_vec_t& cat_ids) : LLInventoryFetchItemsObserver(cat_ids) {} + RlvItemFetcher(const LLUUID& cat_id) : LLInventoryFetchItemsObserver(cat_id) {} virtual ~RlvItemFetcher() {} virtual void done() {} }; diff --git a/indra/newview/statemachine/aifetchinventoryfolder.cpp b/indra/newview/statemachine/aifetchinventoryfolder.cpp index 03ea78ed5..1302c1a3a 100644 --- a/indra/newview/statemachine/aifetchinventoryfolder.cpp +++ b/indra/newview/statemachine/aifetchinventoryfolder.cpp @@ -57,14 +57,20 @@ class AIInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsOb AIStateMachine* mStateMachine; }; -AIInventoryFetchDescendentsObserver::AIInventoryFetchDescendentsObserver(AIStateMachine* statemachine, LLUUID const& folder) : mStateMachine(statemachine) +AIInventoryFetchDescendentsObserver::AIInventoryFetchDescendentsObserver(AIStateMachine* statemachine, LLUUID const& folder) : + mStateMachine(statemachine), + LLInventoryFetchDescendentsObserver(folder) { - mStateMachine->idle(); - folder_ref_t folders(1, folder); - fetchDescendents(folders); - gInventory.addObserver(this); - if (isEverythingComplete()) - done(); + mStateMachine->idle(); + startFetch(); + if(isFinished()) + { + done(); + } + else + { + gInventory.addObserver(this); + } } void AIFetchInventoryFolder::fetch(std::string const& foldername, bool create, bool fetch_contents) From 51746dc7514aef7240dde75b3ee0a6e6fc198fd5 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 21 Jan 2012 19:02:19 -0600 Subject: [PATCH 09/13] Added wearable index handling to LLAgentWearables to scope out further changes. Index is still always zero for now, so behavior should not have changed. (marked with // TODO: MULTI-WEARABLE) --- indra/newview/cofmgr.cpp | 4 +- indra/newview/llagent.cpp | 2 +- indra/newview/llagentwearables.cpp | 499 +++++++++++++++------------ indra/newview/llagentwearables.h | 57 +-- indra/newview/llfloatercustomize.cpp | 52 +-- indra/newview/llinventorybridge.cpp | 2 +- indra/newview/lltexlayer.cpp | 2 +- indra/newview/llviewermenu.cpp | 2 +- indra/newview/llwearable.cpp | 2 +- indra/newview/llwearablelist.h | 1 + indra/newview/rlvhandler.cpp | 4 +- indra/newview/rlvhelper.cpp | 12 +- indra/newview/rlvinventory.cpp | 2 +- indra/newview/rlvlocks.cpp | 8 +- 14 files changed, 357 insertions(+), 292 deletions(-) diff --git a/indra/newview/cofmgr.cpp b/indra/newview/cofmgr.cpp index 3f633f81b..2b7da5ddf 100644 --- a/indra/newview/cofmgr.cpp +++ b/indra/newview/cofmgr.cpp @@ -84,7 +84,7 @@ public: // Add all currently worn wearables for (S32 idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) { - const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)idxType); + const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)idxType,0); // TODO: MULTI-WEARABLE if (idItem.isNull()) continue; idItems.push_back(idItem); @@ -486,7 +486,7 @@ void LLCOFMgr::synchWearables() uuid_vec_t newItems; for (S32 idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++) { - const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)idxType); + const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)idxType, 0); // TODO: MULTI-WEARABLE if (idItem.isNull()) continue; newItems.push_back(idItem); diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index c432e3a4b..e36cc20bb 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3950,7 +3950,7 @@ void LLAgent::sendAgentSetAppearance() static bool send_physics_params = false; - send_physics_params |= !!gAgentWearables.getWearable(LLWearableType::WT_PHYSICS); + send_physics_params |= !!gAgentWearables.selfHasWearable(LLWearableType::WT_PHYSICS); S32 transmitted_params = 0; for (LLViewerVisualParam* param = (LLViewerVisualParam*)gAgentAvatarp->getFirstVisualParam(); param; diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index e625e1b4c..610c7af61 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -105,22 +105,39 @@ LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCal gAgentWearables.sendAgentWearablesUpdate(); } +/** + * @brief Construct a callback for dealing with the wearables. + * + * 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 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 cb, LLWearableType::EType type, LLWearable* wearable, U32 todo) : + LLPointer cb, LLWearableType::EType type, U32 index, LLWearable* wearable, U32 todo) : mType(type), + mIndex(index), mWearable(wearable), mTodo(todo), mCB(cb) { + llassert_always(index == 0); llinfos << "constructor" << llendl; } void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) { + if (mTodo & CALL_CREATESTANDARDDONE) + { + llinfos << "callback fired, inv_item " << inv_item.asString() << llendl; + } + if (inv_item.isNull()) return; - gAgentWearables.addWearabletoAgentInventoryDone(mType, inv_item, mWearable); + gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable); if (mTodo & CALL_UPDATE) { @@ -135,24 +152,28 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i */ if (mTodo & CALL_CREATESTANDARDDONE) { - gAgentWearables.createStandardWearablesDone(mType); + gAgentWearables.createStandardWearablesDone(mType, mIndex); } if (mTodo & CALL_MAKENEWOUTFITDONE) { - gAgentWearables.makeNewOutfitDone(mType); + gAgentWearables.makeNewOutfitDone(mType, mIndex); } } void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::EType type, - const LLUUID& item_id, - LLWearable* wearable) + const U32 index, + const LLUUID& item_id, + LLWearable* wearable) { - llinfos << "type " << type << " item " << item_id.asString() << llendl; + llassert_always(index == 0); + + llinfos << "type " << type << " index " << index << " item " << item_id.asString() << llendl; if (item_id.isNull()) return; + + LLUUID old_item_id = getWearableItemID(type,index); - LLUUID old_item_id = getWearableItemID(type); if (wearable) { wearable->setItemID(item_id); @@ -160,7 +181,7 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy if (old_item_id.notNull()) { gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - setWearable(type,wearable); + setWearable(type,index,wearable); } else { @@ -189,8 +210,9 @@ void LLAgentWearables::sendAgentWearablesUpdate() // First make sure that we have inventory items for each wearable for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) { + for (U32 index=0; index < getWearableCount((LLWearableType::EType)type); ++index) { - LLWearable* wearable = getWearable((LLWearableType::EType)type); + LLWearable* wearable = getWearable((LLWearableType::EType)type,index); if (wearable) { if (wearable->getItemID().isNull()) @@ -199,6 +221,7 @@ void LLAgentWearables::sendAgentWearablesUpdate() new addWearableToAgentInventoryCallback( LLPointer(NULL), (LLWearableType::EType)type, + index, wearable, addWearableToAgentInventoryCallback::CALL_NONE); addWearableToAgentInventory(cb, wearable); @@ -226,18 +249,19 @@ void LLAgentWearables::sendAgentWearablesUpdate() gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); lldebugs << "sendAgentWearablesUpdate()" << llendl; - for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) + // MULTI-WEARABLE: DEPRECATED: HACK: index to 0- server database tables don't support concept of multiwearables. + for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) { gMessageSystem->nextBlockFast(_PREHASH_WearableData); U8 type_u8 = (U8)type; gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8 ); - LLWearable* wearable = getWearable((LLWearableType::EType)type); + LLWearable* wearable = getWearable((LLWearableType::EType)type, 0); if( wearable ) { + //llinfos << "Sending wearable " << wearable->getName() << llendl; LLUUID item_id = wearable->getItemID(); - LL_DEBUGS("Wearables") << "Sending wearable " << wearable->getName() << " mItemID = " << item_id << LL_ENDL; const LLViewerInventoryItem *item = gInventory.getItem(item_id); if (item && item->getIsLinkType()) { @@ -249,8 +273,8 @@ void LLAgentWearables::sendAgentWearablesUpdate() } else { - LL_DEBUGS("Wearables") << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)type) << LL_ENDL; - gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null ); + //llinfos << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << llendl; + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null); } lldebugs << " " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << llendl; @@ -258,10 +282,11 @@ void LLAgentWearables::sendAgentWearablesUpdate() gAgent.sendReliableMessage(); } -void LLAgentWearables::saveWearable(const LLWearableType::EType type, BOOL send_update, +void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update, const std::string new_name) { - LLWearable* old_wearable = getWearable(type); + llassert_always(index == 0); + LLWearable* old_wearable = getWearable(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()) @@ -269,7 +294,7 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, BOOL send_ LLUUID old_item_id = old_wearable->getItemID(); LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar( old_wearable ); new_wearable->setItemID(old_item_id); // should this be in LLWearable::copyDataFrom()? - setWearable(type,new_wearable); + setWearable(type,index,new_wearable); LLInventoryItem* item = gInventory.getItem(old_item_id); if( item ) @@ -313,6 +338,7 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, BOOL send_ new addWearableToAgentInventoryCallback( LLPointer(NULL), type, + index, new_wearable, todo); addWearableToAgentInventory(cb, new_wearable); @@ -329,23 +355,25 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, BOOL send_ } void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, + const U32 index, const std::string& new_name, BOOL save_in_lost_and_found) { - if(!isWearableCopyable(type)) + llassert_always(index == 0); + if (!isWearableCopyable(type, index)) { llwarns << "LLAgent::saveWearableAs() not copyable." << llendl; return; } - LLWearable* old_wearable = getWearable(type); - if(!old_wearable) + LLWearable* old_wearable = getWearable(type, index); + if (!old_wearable) { llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl; return; } - LLInventoryItem* item = gInventory.getItem(getWearableItemID(type)); - if(!item) + LLInventoryItem* item = gInventory.getItem(getWearableItemID(type,index)); + if (!item) { llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl; return; @@ -359,6 +387,7 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, new addWearableToAgentInventoryCallback( LLPointer(NULL), type, + index, new_wearable, addWearableToAgentInventoryCallback::CALL_UPDATE); LLUUID category_id; @@ -422,9 +451,10 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, */ } -void LLAgentWearables::revertWearable( LLWearableType::EType type ) +void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U32 index) { - LLWearable* wearable = getWearable(type); + llassert_always(index == 0); + LLWearable* wearable = getWearable(type, index); llassert(wearable); if( wearable ) { @@ -438,7 +468,8 @@ void LLAgentWearables::revertAllWearables() { for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { - revertWearable( (LLWearableType::EType)i ); + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) + revertWearable( (LLWearableType::EType)i, j); } } @@ -451,7 +482,8 @@ void LLAgentWearables::saveAllWearables() for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { - saveWearable( (LLWearableType::EType)i, FALSE ); + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) + saveWearable((LLWearableType::EType)i, j, FALSE); } sendAgentWearablesUpdate(); } @@ -461,35 +493,39 @@ void LLAgentWearables::setWearableName( const LLUUID& item_id, const std::string { for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { - LLUUID curr_item_id = getWearableItemID((LLWearableType::EType)i); - if( curr_item_id == item_id ) + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) { - LLWearable* old_wearable = getWearable((LLWearableType::EType)i); - 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); - new_wearable->setItemID(item_id); - LLInventoryItem* item = gInventory.getItem(item_id); - if(item) + LLUUID curr_item_id = getWearableItemID((LLWearableType::EType)i,j); + if (curr_item_id == item_id) { - new_wearable->setPermissions(item->getPermissions()); - } - old_wearable->setName( old_name ); + LLWearable* old_wearable = getWearable((LLWearableType::EType)i,j); + llassert(old_wearable); + if (!old_wearable) continue; - setWearable((LLWearableType::EType)i,new_wearable); - sendAgentWearablesUpdate(); - break; + std::string old_name = old_wearable->getName(); + old_wearable->setName(new_name); + LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable); + new_wearable->setItemID(item_id); + LLInventoryItem* item = gInventory.getItem(item_id); + if (item) + { + new_wearable->setPermissions(item->getPermissions()); + } + old_wearable->setName(old_name); + + setWearable((LLWearableType::EType)i,j,new_wearable); + sendAgentWearablesUpdate(); + break; + } } } } -BOOL LLAgentWearables::isWearableModifiable(LLWearableType::EType type) const +BOOL LLAgentWearables::isWearableModifiable(LLWearableType::EType type, U32 index) const { - LLUUID item_id = getWearableItemID(type); + llassert_always(index == 0); + LLUUID item_id = getWearableItemID(type, index); return item_id.notNull() ? isWearableModifiable(item_id) : FALSE; } @@ -508,10 +544,11 @@ BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const return FALSE; } -BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type) const +BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index) const { - LLUUID item_id = getWearableItemID(type); - if(!item_id.isNull()) + llassert_always(index == 0); + LLUUID item_id = getWearableItemID(type, index); + if (!item_id.isNull()) { LLInventoryItem* item = gInventory.getItem(item_id); if(item && item->getPermissions().allowCopyBy(gAgent.getID(), @@ -530,7 +567,7 @@ BOOL LLAgentWearables::areWearablesLoaded() const return mWearablesLoaded; } -U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type) const +/*U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type) const { LLUUID item_id = getWearableItemID(type); if(!item_id.isNull()) @@ -543,10 +580,12 @@ U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type) const } return PERM_NONE; } +*/ -LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::EType type) +LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::EType type, U32 index) { - LLUUID item_id = getWearableItemID(type); + llassert_always(index == 0); + LLUUID item_id = getWearableItemID(type,index); LLInventoryItem* item = NULL; if(item_id.notNull()) { @@ -558,12 +597,15 @@ LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::ETyp const LLWearable* LLAgentWearables::getWearableFromItemID( const LLUUID& item_id ) const { const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) + for (S32 i=0; i < LLWearableType::WT_COUNT; i++) { - const LLWearable * curr_wearable = getWearable((LLWearableType::EType)i); - if (curr_wearable && (curr_wearable->getItemID() == base_item_id)) + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) { - return curr_wearable; + const LLWearable * curr_wearable = getWearable((LLWearableType::EType)i, j); + if (curr_wearable && (curr_wearable->getItemID() == base_item_id)) + { + return curr_wearable; + } } } return NULL; @@ -572,12 +614,15 @@ const LLWearable* LLAgentWearables::getWearableFromItemID( const LLUUID& item_id LLWearable* LLAgentWearables::getWearableFromItemID( const LLUUID& item_id ) { const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) + for (S32 i=0; i < LLWearableType::WT_COUNT; i++) { - LLWearable * curr_wearable = getWearable((LLWearableType::EType)i); - if (curr_wearable && (curr_wearable->getItemID() == base_item_id)) + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) { - return curr_wearable; + LLWearable * curr_wearable = getWearable((LLWearableType::EType)i, j); + if (curr_wearable && (curr_wearable->getItemID() == base_item_id)) + { + return curr_wearable; + } } } return NULL; @@ -587,10 +632,13 @@ LLWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_id) { for (S32 i=0; i < LLWearableType::WT_COUNT; i++) { - LLWearable * curr_wearable = getWearable((LLWearableType::EType)i); - if (curr_wearable && (curr_wearable->getAssetID() == asset_id)) + for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) { - return curr_wearable; + LLWearable * curr_wearable = getWearable((LLWearableType::EType)i, j); + if (curr_wearable && (curr_wearable->getAssetID() == asset_id)) + { + return curr_wearable; + } } } return NULL; @@ -612,14 +660,14 @@ BOOL LLAgentWearables::selfHasWearable(LLWearableType::EType type) return (gAgentWearables.getWearableCount(type) > 0); } -LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type) +LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type, U32 index) { + llassert_always(index == 0); wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { return NULL; } - U32 index = 0; //Remove when multi-wearables are implemented. wearableentry_vec_t& wearable_vec = wearable_iter->second; if (index>=wearable_vec.size()) { @@ -631,17 +679,16 @@ LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type) } } -void LLAgentWearables::setWearable(const LLWearableType::EType type, LLWearable *wearable) +void LLAgentWearables::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable) { - - LLWearable *old_wearable = getWearable(type); + llassert_always(index == 0); + LLWearable *old_wearable = getWearable(type,index); if (!old_wearable) { pushWearable(type,wearable); return; } - U32 index = 0; //Remove when multi-wearables are implemented. wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { @@ -692,22 +739,23 @@ void LLAgentWearables::popWearable(LLWearable *wearable) // nothing to do here. move along. return; } - - U32 index = 0; //Remove when multi-wearables are implemented. + + U32 index = getWearableIndex(wearable); LLWearableType::EType type = wearable->getType(); if (index < MAX_CLOTHING_PER_TYPE && index < getWearableCount(type)) { - popWearable(type); + popWearable(type, index); } } -void LLAgentWearables::popWearable(const LLWearableType::EType type) +void LLAgentWearables::popWearable(const LLWearableType::EType type, U32 index) { - LLWearable *wearable = getWearable(type); + llassert_always(index == 0); + LLWearable *wearable = getWearable(type, index); if (wearable) { - mWearableDatas[type].erase(mWearableDatas[type].begin()); + mWearableDatas[type].erase(mWearableDatas[type].begin() + index); gAgentAvatarp->wearableUpdated(wearable->getType(), TRUE); wearable->setLabelUpdated(); } @@ -739,15 +787,14 @@ U32 LLAgentWearables::getWearableIndex(const LLWearable *wearable) const return MAX_CLOTHING_PER_TYPE; } - -const LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type) const +const LLWearable* LLAgentWearables::getWearable(const LLWearableType::EType type, U32 index) const { + llassert_always(index == 0); wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { return NULL; } - U32 index = 0; //Remove when multi-wearables are implemented. const wearableentry_vec_t& wearable_vec = wearable_iter->second; if (index>=wearable_vec.size()) { @@ -767,7 +814,7 @@ LLWearable* LLAgentWearables::getTopWearable(const LLWearableType::EType type) return NULL; } - return getWearable(type); + return getWearable(type, count-1); } LLWearable* LLAgentWearables::getBottomWearable(const LLWearableType::EType type) @@ -777,7 +824,7 @@ LLWearable* LLAgentWearables::getBottomWearable(const LLWearableType::EType type return NULL; } - return getWearable(type); + return getWearable(type, 0); } U32 LLAgentWearables::getWearableCount(const LLWearableType::EType type) const @@ -798,18 +845,20 @@ U32 LLAgentWearables::getWearableCount(const U32 tex_index) const } -const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type) const +const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const { - const LLWearable *wearable = getWearable(type); + llassert_always(index == 0); + const LLWearable *wearable = getWearable(type,index); if (wearable) return wearable->getItemID(); else return LLUUID(); } -const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type) const +const LLUUID LLAgentWearables::getWearableAssetID(LLWearableType::EType type, U32 index) const { - const LLWearable *wearable = getWearable(type); + llassert_always(index == 0); + const LLWearable *wearable = getWearable(type,index); if (wearable) return wearable->getAssetID(); else @@ -822,8 +871,12 @@ BOOL LLAgentWearables::isWearingItem( const LLUUID& item_id ) const return (getWearableFromItemID(base_item_id) != NULL); } +// MULTI-WEARABLE: DEPRECATED (see backwards compatibility) // static -void LLAgentWearables::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void** user_data ) +// ! 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. EXCEPT gAgentWearables.notifyLoadingStarted +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. @@ -881,7 +934,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate( LLMessageSystem* mesg asset_id_array[type] = std::pair(asset_id,item_id); } - LL_DEBUGS("Wearables") << " " << LLWearableType::getTypeLabel(type) << " " << asset_id << " item id " << gAgentWearables.getWearableItemID(type).asString() << LL_ENDL; + LL_DEBUGS("Wearables") << " " << LLWearableType::getTypeLabel(type) << " " << asset_id << " item id " << gAgentWearables.getWearableItemID(type, 0).asString() << LL_ENDL; } LLCOFMgr::instance().fetchCOF(); @@ -928,7 +981,7 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void { llassert( type == wearable->getType() ); wearable->setItemID(item_id); - gAgentWearables.setWearable(type,wearable); + gAgentWearables.setWearable(type,0,wearable); // disable composites if initial textures are baked avatar->setupComposites(); @@ -941,7 +994,7 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void else { // Somehow the asset doesn't exist in the database. - gAgentWearables.recoverMissingWearable( type ); + gAgentWearables.recoverMissingWearable( type, 0 ); } gInventory.notifyObservers(); @@ -952,7 +1005,7 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void gAgentWearables.mWearablesLoaded = TRUE; for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) { - if( !gAgentWearables.getWearableItemID((LLWearableType::EType)i).isNull() && !gAgentWearables.getWearable((LLWearableType::EType)i) ) + if( !gAgentWearables.getWearableItemID((LLWearableType::EType)i, 0).isNull() && !gAgentWearables.getWearable((LLWearableType::EType)i, 0) ) { gAgentWearables.mWearablesLoaded = FALSE; break; @@ -977,14 +1030,15 @@ void LLAgentWearables::onInitialWearableAssetArrived( LLWearable* wearable, void // 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( LLWearableType::EType type ) +void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, U32 index) { + llassert_always(index == 0); // Try to recover by replacing missing wearable with a new one. LLNotificationsUtil::add("ReplacedMissingWearable"); lldebugs << "Wearable " << LLWearableType::getTypeLabel( type ) << " could not be downloaded. Replaced inventory item with default wearable." << llendl; LLWearable* new_wearable = LLWearableList::instance().createNewWearable(type); - setWearable(type,new_wearable); + setWearable(type,index,new_wearable); new_wearable->writeToAvatar( TRUE ); // Add a new one in the lost and found folder. @@ -995,6 +1049,7 @@ void LLAgentWearables::recoverMissingWearable( LLWearableType::EType type ) new addWearableToAgentInventoryCallback( LLPointer(NULL), type, + index, new_wearable, addWearableToAgentInventoryCallback::CALL_RECOVERDONE); addWearableToAgentInventory( cb, new_wearable, lost_and_found_id, TRUE); @@ -1063,15 +1118,16 @@ void LLAgentWearables::createStandardWearables(BOOL female) new addWearableToAgentInventoryCallback( donecb, (LLWearableType::EType)i, + 0, wearable, addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE); addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE); } } } -void LLAgentWearables::createStandardWearablesDone(S32 index) +void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index) { - LLWearable* wearable = getWearable((LLWearableType::EType)index); + LLWearable* wearable = getWearable((LLWearableType::EType)type, index); if (wearable) { @@ -1126,10 +1182,10 @@ void LLAgentWearables::makeNewOutfit( for( i = 0; i < count; ++i ) { S32 index = wearables_to_include[i]; - LLWearable* old_wearable = getWearable((LLWearableType::EType)index); + LLWearable* old_wearable = getWearable((LLWearableType::EType)index, 0); if( old_wearable ) { - LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((LLWearableType::EType)index)); + LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((LLWearableType::EType)index, 0)); llassert(item); if (!item) continue; @@ -1157,7 +1213,7 @@ void LLAgentWearables::makeNewOutfit( LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN); } - if (fUseLinks || isWearableCopyable((LLWearableType::EType)index)) + if (fUseLinks || isWearableCopyable((LLWearableType::EType)index, 0)) { LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable); if (rename_clothing) @@ -1178,9 +1234,10 @@ void LLAgentWearables::makeNewOutfit( new addWearableToAgentInventoryCallback( cbdone, (LLWearableType::EType)index, + 0, new_wearable, todo); - if (isWearableCopyable((LLWearableType::EType)index)) + if (isWearableCopyable((LLWearableType::EType)index, 0)) { copy_inventory_item( gAgent.getID(), @@ -1292,9 +1349,9 @@ void LLAgentWearables::makeNewOutfit( } } -void LLAgentWearables::makeNewOutfitDone(S32 type) +void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) { - LLUUID first_item_id = getWearableItemID((LLWearableType::EType)type); + LLUUID first_item_id = getWearableItemID((LLWearableType::EType)type, index); // Open the inventory and select the first item we added. if( first_item_id.notNull() ) { @@ -1325,15 +1382,16 @@ void LLAgentWearables::addWearableToAgentInventory(LLPointerisDirty() ) + removeWearableFinal(type, do_remove_all, index); + } + else + { + LLWearable* old_wearable = getWearable(type,index); + + if (old_wearable) { - LLSD payload; - payload["wearable_type"] = (S32)type; - // Bring up view-modal dialog: Save changes? Yes, No, Cancel - LLNotificationsUtil::add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog); - return; - } - else - { - removeWearableFinal( type ); + if (old_wearable->isDirty()) + { + LLSD payload; + payload["wearable_type"] = (S32)type; + payload["wearable_index"] = (S32)index; + // Bring up view-modal dialog: Save changes? Yes, No, Cancel + LLNotificationsUtil::add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog); + return; + } + else + { + removeWearableFinal(type, do_remove_all, index); + } } } } + // static -bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LLSD& response ) +bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLWearableType::EType type = (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger(); - switch( option ) + S32 index = (S32)notification["payload"]["wearable_index"].asInteger(); + switch(option) { - case 0: // "Save" - gAgentWearables.saveWearable( type ); - gAgentWearables.removeWearableFinal( type ); - break; + case 0: // "Save" + gAgentWearables.saveWearable(type, index); + gAgentWearables.removeWearableFinal(type, false, index); + break; - case 1: // "Don't Save" - gAgentWearables.removeWearableFinal( type ); - break; + case 1: // "Don't Save" + gAgentWearables.removeWearableFinal(type, false, index); + break; case 2: // "Cancel" break; @@ -1393,17 +1460,35 @@ bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LL } // Called by removeWearable() and onRemoveWearableDialog() to actually do the removal. -void LLAgentWearables::removeWearableFinal( LLWearableType::EType type ) +void LLAgentWearables::removeWearableFinal( LLWearableType::EType type, bool do_remove_all, U32 index) { - gInventory.addChangedMask( LLInventoryObserver::LABEL, getWearableItemID(type) ); - - LLWearable* old_wearable = getWearable(type); - //queryWearableCache(); - - if( old_wearable ) + llassert_always(index == 0); + gInventory.addChangedMask( LLInventoryObserver::LABEL, getWearableItemID(type, index) ); + if (do_remove_all) { - popWearable(old_wearable); - old_wearable->removeFromAvatar( TRUE ); + S32 max_entry = mWearableDatas[type].size()-1; + for (S32 i=max_entry; i>=0; i--) + { + LLWearable* old_wearable = getWearable(type,i); + //queryWearableCache(); // moved below + if (old_wearable) + { + popWearable(old_wearable); + old_wearable->removeFromAvatar(TRUE); + } + } + mWearableDatas[type].clear(); + } + else + { + LLWearable* old_wearable = getWearable(type, index); + //queryWearableCache(); // moved below + + if (old_wearable) + { + popWearable(old_wearable); + old_wearable->removeFromAvatar(TRUE); + } } queryWearableCache(); @@ -1413,47 +1498,6 @@ void LLAgentWearables::removeWearableFinal( LLWearableType::EType type ) gInventory.notifyObservers(); } -void LLAgentWearables::copyWearableToInventory( LLWearableType::EType type ) -{ - LLWearable* wearable = getWearable(type); - if( wearable ) - { - // Save the old wearable if it has changed. - if( wearable->isDirty() ) - { - LLWearable * new_wearable = LLWearableList::instance().createCopyFromAvatar( wearable ); - new_wearable->setItemID(wearable->getItemID()); - setWearable(type,new_wearable); - wearable = new_wearable; - } - - // Make a new entry in the inventory. (Put it in the same folder as the original item if possible.) - LLUUID category_id; - LLInventoryItem* item = gInventory.getItem( wearable->getItemID() ); - if( item ) - { - category_id = item->getParentUUID(); - wearable->setPermissions(item->getPermissions()); - } - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - type, - wearable); - addWearableToAgentInventory(cb, wearable, category_id); - } -} - - -// A little struct to let setWearable() communicate more than one value with onSetWearableDialog(). -struct LLSetWearableData -{ - LLSetWearableData( const LLUUID& new_item_id, LLWearable* new_wearable ) : - mNewItemID( new_item_id ), mNewWearable( new_wearable ) {} - LLUUID mNewItemID; - LLWearable* mNewWearable; -}; - static bool isFirstPhysicsWearable(LLWearableType::EType type, LLInventoryItem *new_item, LLWearable *new_wearable) { if (type == LLWearableType::WT_PHYSICS && gSavedSettings.getWarning("FirstPhysicsWearable")) @@ -1529,10 +1573,10 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it LLWearableType::EType type = new_wearable->getType(); wearables_to_remove[type] = FALSE; - LLWearable* old_wearable = getWearable(type); + LLWearable* old_wearable = getWearable(type, 0); if( old_wearable ) { - const LLUUID& old_item_id = getWearableItemID(type); + const LLUUID& old_item_id = getWearableItemID(type, 0); if( (old_wearable->getAssetID() == new_wearable->getAssetID()) && (old_item_id == new_item->getUUID()) ) { @@ -1561,11 +1605,11 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it if (LLWearableType::getAssetType(type) == LLAssetType::AT_BODYPART) { // exactly one wearable per body part - setWearable(type,new_wearable); + setWearable(type,0,new_wearable); } else if(old_wearable) //Remove when multi-wearables are implemented. { - setWearable(type,new_wearable); + setWearable(type,0,new_wearable); } else { @@ -1580,8 +1624,8 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it { if( wearables_to_remove[i] ) { - LLWearable* wearable = getWearable((LLWearableType::EType)i); - wearables_being_removed.push_back(getWearable((LLWearableType::EType)i)); + LLWearable* wearable = getWearable((LLWearableType::EType)i, 0); + wearables_being_removed.push_back(getWearable((LLWearableType::EType)i, 0)); popWearable(wearable); gInventory.addChangedMask(LLInventoryObserver::LABEL, wearable->getItemID()); @@ -1644,7 +1688,7 @@ void LLAgentWearables::setWearableItem( LLInventoryItem* new_item, LLWearable* n return; } - LLWearable* old_wearable = getWearable(type); + LLWearable* old_wearable = getWearable(type,0); if( old_wearable ) { const LLUUID& old_item_id = old_wearable->getItemID(); @@ -1673,6 +1717,7 @@ bool LLAgentWearables::onSetWearableDialog( const LLSD& notification, const LLSD { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLInventoryItem* new_item = gInventory.getItem( notification["payload"]["item_id"].asUUID()); + U32 index = gAgentWearables.getWearableIndex(wearable); if( !new_item ) { delete wearable; @@ -1682,7 +1727,7 @@ bool LLAgentWearables::onSetWearableDialog( const LLSD& notification, const LLSD switch( option ) { case 0: // "Save" - gAgentWearables.saveWearable( wearable->getType() ); + gAgentWearables.saveWearable(wearable->getType(),index); gAgentWearables.setWearableFinal( new_item, wearable ); break; @@ -1707,24 +1752,29 @@ void LLAgentWearables::setWearableFinal( LLInventoryItem* new_item, LLWearable* { const LLWearableType::EType type = new_wearable->getType(); - // Replace the old wearable with a new one. - llassert( new_item->getAssetUUID() == new_wearable->getAssetID() ); - LLWearable *old_wearable = getWearable(type); - LLUUID old_item_id; - if (old_wearable) { - old_item_id = old_wearable->getItemID(); - } - new_wearable->setItemID(new_item->getUUID()); - setWearable(type,new_wearable); + // Replace the old wearable with a new one. + llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); - if (old_item_id.notNull()) - { - gInventory.addChangedMask( LLInventoryObserver::LABEL, old_item_id ); - gInventory.notifyObservers(); + LLWearable *old_wearable = getWearable(type,0); + LLUUID old_item_id; + if (old_wearable) + { + old_item_id = old_wearable->getItemID(); + } + new_wearable->setItemID(new_item->getUUID()); + setWearable(type,0,new_wearable); + + if (old_item_id.notNull()) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); + gInventory.notifyObservers(); + } + llinfos << "Replaced current element 0 for type " << type + << " size is now " << mWearableDatas[type].size() << llendl; } - //llinfos << "LLVOAvatar::setWearable()" << llendl; + //llinfos << "LLVOAvatar::setWearableItem()" << llendl; queryWearableCache(); new_wearable->writeToAvatar( TRUE ); @@ -1793,13 +1843,16 @@ LLUUID LLAgentWearables::computeBakedTextureHash(LLVOAvatarDefines::EBakedTextur for (U8 i=0; i < baked_dict->mWearables.size(); i++) { const LLWearableType::EType baked_type = baked_dict->mWearables[i]; - //TO-DO: MULTI-WEARABLE - const LLWearable* wearable = getWearable(baked_type); - if (wearable) + const U32 num_wearables = getWearableCount(baked_type); + for (U32 index = 0; index < num_wearables; ++index) { - LLUUID asset_id = wearable->getAssetID(); - hash.update((const unsigned char*)asset_id.mData, UUID_BYTES); - hash_computed = true; + const LLWearable* wearable = getWearable(baked_type,index); + if (wearable) + { + LLUUID asset_id = wearable->getAssetID(); + hash.update((const unsigned char*)asset_id.mData, UUID_BYTES); + hash_computed = true; + } } } if (hash_computed) @@ -1823,12 +1876,22 @@ LLUUID LLAgentWearables::computeBakedTextureHash(LLVOAvatarDefines::EBakedTextur // User has picked "remove from avatar" from a menu. // static -void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type) +void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index) { if( !(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES) ) //&& //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) ) { - gAgentWearables.removeWearable( type ); + gAgentWearables.removeWearable(type,false,index); + } +} + +//static +void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &type) +{ + 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))) + { + gAgentWearables.removeWearable(type,true,0); } } @@ -1849,18 +1912,18 @@ void LLAgentWearables::userRemoveAllClothesStep2( BOOL proceed, void* userdata ) { if( proceed ) { - gAgentWearables.removeWearable( LLWearableType::WT_SHIRT ); - gAgentWearables.removeWearable( LLWearableType::WT_PANTS ); - gAgentWearables.removeWearable( LLWearableType::WT_SHOES ); - gAgentWearables.removeWearable( LLWearableType::WT_SOCKS ); - gAgentWearables.removeWearable( LLWearableType::WT_JACKET ); - gAgentWearables.removeWearable( LLWearableType::WT_GLOVES ); - gAgentWearables.removeWearable( LLWearableType::WT_UNDERSHIRT ); - gAgentWearables.removeWearable( LLWearableType::WT_UNDERPANTS ); - gAgentWearables.removeWearable( LLWearableType::WT_SKIRT ); - gAgentWearables.removeWearable( LLWearableType::WT_ALPHA ); - gAgentWearables.removeWearable( LLWearableType::WT_TATTOO ); - gAgentWearables.removeWearable( LLWearableType::WT_PHYSICS ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SHIRT ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_PANTS ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SHOES ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SOCKS ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_JACKET ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_GLOVES ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_UNDERSHIRT ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_UNDERPANTS ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_SKIRT ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_ALPHA ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_TATTOO ); + gAgentWearables.userRemoveWearablesOfType( LLWearableType::WT_PHYSICS ); } } @@ -2099,7 +2162,7 @@ void LLAgentWearables::updateWearablesLoaded() mWearablesLoaded = TRUE; for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) { - if( !getWearableItemID((LLWearableType::EType)i).isNull() && !getWearable((LLWearableType::EType)i) ) + if( !getWearableItemID((LLWearableType::EType)i, 0).isNull() && !getWearable((LLWearableType::EType)i, 0) ) { mWearablesLoaded = FALSE; break; diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 70f9b0969..630d57525 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -70,7 +70,7 @@ public: // LLInitClass interface static void initClass(); protected: - void createStandardWearablesDone(S32 type); + void createStandardWearablesDone(S32 type, U32 index/* = 0*/); void createStandardWearablesAllDone(); //-------------------------------------------------------------------- @@ -78,10 +78,10 @@ protected: //-------------------------------------------------------------------- public: BOOL isWearingItem(const LLUUID& item_id) const; - BOOL isWearableModifiable(LLWearableType::EType type) const; + BOOL isWearableModifiable(LLWearableType::EType type, U32 index /*= 0*/) const; BOOL isWearableModifiable(const LLUUID& item_id) const; - BOOL isWearableCopyable(LLWearableType::EType type) const; + BOOL isWearableCopyable(LLWearableType::EType type, U32 index /*= 0*/) const; BOOL areWearablesLoaded() const; void updateWearablesLoaded(); //void checkWearablesLoaded() const; @@ -93,28 +93,26 @@ public: //void animateAllWearableParams(F32 delta, BOOL upload_bake); BOOL needsReplacement(LLWearableType::EType wearableType, S32 remove); - U32 getWearablePermMask(LLWearableType::EType type) const; + //U32 getWearablePermMask(LLWearableType::EType type) const; //-------------------------------------------------------------------- // Accessors //-------------------------------------------------------------------- public: - const LLUUID getWearableItemID(LLWearableType::EType type ) const; - const LLUUID getWearableAssetID(LLWearableType::EType type) const; + const LLUUID getWearableItemID(LLWearableType::EType type, U32 index /*= 0*/) const; + const LLUUID getWearableAssetID(LLWearableType::EType type, U32 index /*= 0*/) const; const LLWearable* getWearableFromItemID(const LLUUID& item_id) const; - LLWearable* getWearableFromItemID(const LLUUID& item_id); - LLWearable* getWearableFromAssetID(const LLUUID& asset_id); - LLInventoryItem* getWearableInventoryItem(LLWearableType::EType type); + LLWearable* getWearableFromItemID(const LLUUID& item_id); + LLWearable* getWearableFromAssetID(const LLUUID& asset_id); + LLInventoryItem* getWearableInventoryItem(LLWearableType::EType type, U32 index /*= 0*/); static BOOL selfHasWearable(LLWearableType::EType type); - LLWearable* getWearable( const LLWearableType::EType type ); - const LLWearable* getWearable( const LLWearableType::EType type ) const; - LLWearable* getTopWearable(const LLWearableType::EType type); + LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/); + const LLWearable* getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const; + LLWearable* getTopWearable(const LLWearableType::EType type); LLWearable* getBottomWearable(const LLWearableType::EType type); U32 getWearableCount(const LLWearableType::EType type) const; U32 getWearableCount(const U32 tex_index) const; - void copyWearableToInventory( LLWearableType::EType type ); - static const U32 MAX_CLOTHING_PER_TYPE = 1; @@ -124,11 +122,11 @@ public: private: // Low-level data structure setter - public access is via setWearableItem, etc. - void setWearable(const LLWearableType::EType type, LLWearable *wearable); + void setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable); U32 pushWearable(const LLWearableType::EType type, LLWearable *wearable); void wearableUpdated(LLWearable *wearable); void popWearable(LLWearable *wearable); - void popWearable(const LLWearableType::EType type); + void popWearable(const LLWearableType::EType type, U32 index); public: void setWearableItem(LLInventoryItem* new_item, LLWearable* wearable); @@ -156,11 +154,11 @@ protected: * @param item_id The inventory item id of the new wearable to wear. * @param wearable The actual wearable data. */ - void addWearabletoAgentInventoryDone(const LLWearableType::EType type, - const LLUUID& item_id, - LLWearable* wearable); - - void recoverMissingWearable(LLWearableType::EType type); + void addWearabletoAgentInventoryDone(const LLWearableType::EType type, + const U32 index, + const LLUUID& item_id, + LLWearable* wearable); + void recoverMissingWearable(const LLWearableType::EType type, U32 index /*= 0*/); void recoverMissingWearableDone(); //-------------------------------------------------------------------- @@ -182,9 +180,9 @@ private: // Removing wearables //-------------------------------------------------------------------- public: - void removeWearable( LLWearableType::EType type ); + void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); private: - void removeWearableFinal( LLWearableType::EType type ); + void removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); protected: static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response); static void userRemoveAllClothesStep2(BOOL proceed, void* userdata ); // userdata is NULL @@ -220,25 +218,26 @@ public: BOOL rename_clothing); private: - void makeNewOutfitDone(S32 type); + void makeNewOutfitDone(S32 type, U32 index); //-------------------------------------------------------------------- // Save Wearables //-------------------------------------------------------------------- public: - void saveWearableAs(const LLWearableType::EType type, const std::string& new_name, BOOL save_in_lost_and_found ); - void saveWearable(const LLWearableType::EType type, BOOL send_update = TRUE, + void saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found ); + void saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE, const std::string new_name = ""); void saveAllWearables(); - void revertWearable( LLWearableType::EType type ); + void revertWearable( LLWearableType::EType type, const U32 index); void revertAllWearables(); //-------------------------------------------------------------------- // Static UI hooks //-------------------------------------------------------------------- public: - static void userRemoveWearable(const LLWearableType::EType &type); + static void userRemoveWearable(const LLWearableType::EType &type, const U32 &index); + static void userRemoveWearablesOfType(const LLWearableType::EType &type); static void userRemoveAllClothes(); typedef std::vector llvo_vec_t; @@ -321,12 +320,14 @@ private: */ addWearableToAgentInventoryCallback(LLPointer cb, LLWearableType::EType type, + U32 index, LLWearable* wearable, U32 todo = CALL_NONE); virtual void fire(const LLUUID& inv_item); private: LLWearableType::EType mType; + U32 mIndex; LLWearable* mWearable; U32 mTodo; LLPointer mCB; diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 651185c0a..fc72e7e17 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -590,7 +590,7 @@ void LLPanelEditWearable::setSubpart( ESubpart subpart ) LLVOAvatar* avatar = gAgentAvatarp; ESex avatar_sex = avatar->getSex(); LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType); + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType,0); // TODO: MULTI-WEARABLE U32 perm_mask = 0x0; BOOL is_complete = FALSE; bool can_export = false; @@ -656,27 +656,27 @@ void LLPanelEditWearable::onBtnTakeOff( void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLWearable* wearable = gAgentWearables.getWearable( self->mType ); + LLWearable* wearable = gAgentWearables.getWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE if( !wearable ) { return; } - gAgentWearables.removeWearable( self->mType ); + gAgentWearables.removeWearable( self->mType, false, 0 ); // TODO: MULTI-WEARABLE } // static void LLPanelEditWearable::onBtnSave( void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.saveWearable( self->mType ); + gAgentWearables.saveWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE } // static void LLPanelEditWearable::onBtnSaveAs( void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLWearable* wearable = gAgentWearables.getWearable( self->getType() ); + LLWearable* wearable = gAgentWearables.getWearable( self->getType(), 0 ); // TODO: MULTI-WEARABLE if( wearable ) { LLWearableSaveAsDialog* save_as_dialog = new LLWearableSaveAsDialog( wearable->getName(), onSaveAsCommit, self ); @@ -692,7 +692,7 @@ void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog LLVOAvatar* avatar = gAgentAvatarp; if( avatar ) { - gAgentWearables.saveWearableAs( self->getType(), save_as_dialog->getItemName(), FALSE ); + gAgentWearables.saveWearableAs( self->getType(), 0, save_as_dialog->getItemName(), FALSE ); // TODO: MULTI-WEARABLE } } @@ -701,7 +701,7 @@ void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog void LLPanelEditWearable::onBtnRevert( void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.revertWearable( self->mType ); + gAgentWearables.revertWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE } // static @@ -740,7 +740,7 @@ bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const bool LLPanelEditWearable::textureIsInvisible(ETextureIndex te) { - if (gAgentWearables.getWearable(mType)) + if (gAgentWearables.getWearable(mType, 0)) // TODO: MULTI-WEARABLE { LLVOAvatar *avatar = gAgentAvatarp; if (avatar) @@ -876,7 +876,7 @@ void LLPanelEditWearable::addTextureDropTarget( ETextureIndex te, const std::str LLVOAvatar* avatar = gAgentAvatarp; if (avatar) { - LLWearable* wearable = gAgentWearables.getWearable(mType); + LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE if (wearable && mType == LLWearableType::WT_ALPHA) { const LLTextureEntry* current_te = avatar->getTE(te); @@ -906,7 +906,7 @@ void LLPanelEditWearable::onTextureCommit( LLUICtrl* ctrl, void* userdata ) image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); } self->mTextureList[ctrl->getName()] = te; - if (gAgentWearables.getWearable(self->mType)) + if (gAgentWearables.getWearable(self->mType, 0)) // TODO: MULTI-WEARABLE { avatar->setLocTexTE(te, image, TRUE); avatar->wearableUpdated(self->mType, FALSE); @@ -958,14 +958,14 @@ void LLPanelEditWearable::draw() return; } - LLWearable* wearable = gAgentWearables.getWearable( mType ); + LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE BOOL has_wearable = (wearable != NULL ); BOOL is_dirty = isDirty(); BOOL is_modifiable = FALSE; BOOL is_copyable = FALSE; BOOL is_complete = FALSE; LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType); + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType, 0); // TODO: MULTI-WEARABLE if(item) { const LLPermissions& perm = item->getPermissions(); @@ -1041,7 +1041,7 @@ void LLPanelEditWearable::draw() childSetTextArg("title_loading", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType() ); + const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE append_path(item_id, path); childSetVisible("path", TRUE); childSetTextArg("path", "[PATH]", path); @@ -1054,7 +1054,7 @@ void LLPanelEditWearable::draw() childSetTextArg("title", "[DESC]", wearable->getName() ); std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType() ); + const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE append_path(item_id, path); childSetVisible("path", TRUE); childSetTextArg("path", "[PATH]", path); @@ -1201,7 +1201,7 @@ void LLPanelEditWearable::setVisible(BOOL visible) BOOL LLPanelEditWearable::isDirty() const { - LLWearable* wearable = gAgentWearables.getWearable( mType ); + LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE if( !wearable ) { return FALSE; @@ -1226,7 +1226,7 @@ void LLPanelEditWearable::onCommitSexChange( LLUICtrl*, void* userdata ) return; } - if( !gAgentWearables.isWearableModifiable(self->mType)) + if( !gAgentWearables.isWearableModifiable(self->mType, 0)) // TODO: MULTI-WEARABLE { return; } @@ -1936,10 +1936,10 @@ void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { is_modifiable = FALSE; - LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i); + LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if( old_wearable ) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i); + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if(item) { const LLPermissions& perm = item->getPermissions(); @@ -1960,10 +1960,10 @@ void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) for( S32 i=0; i < LLWearableType::WT_COUNT; i++ ) { is_modifiable = FALSE; - LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i); + LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if( old_wearable ) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i); + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if(item) { const LLPermissions& perm = item->getPermissions(); @@ -2015,7 +2015,7 @@ void LLFloaterCustomize::onBtnMakeOutfit( void* userdata ) for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) { - BOOL enabled = (gAgentWearables.getWearable( (LLWearableType::EType) i ) != NULL); + BOOL enabled = (gAgentWearables.getWearable( (LLWearableType::EType) i, 0 ) != NULL); // TODO: MULTI-WEARABLE BOOL selected = (enabled && (LLWearableType::WT_SHIRT <= i) && (i < LLWearableType::WT_COUNT)); // only select clothing by default if (gAgent.isTeen() && !edit_wearable_for_teens((LLWearableType::EType)i)) @@ -2748,13 +2748,13 @@ bool LLFloaterCustomize::onSaveDialog(const LLSD& notification, const LLSD& resp switch( option ) { case 0: // "Save" - gAgentWearables.saveWearable( cur ); + gAgentWearables.saveWearable( cur, 0 ); // TODO: MULTI-WEARABLE proceed = TRUE; break; case 1: // "Don't Save" { - gAgentWearables.revertWearable( cur ); + gAgentWearables.revertWearable( cur, 0 ); // TODO: MULTI-WEARABLE proceed = TRUE; } break; @@ -2790,7 +2790,7 @@ void LLFloaterCustomize::fetchInventory() LLUUID item_id; for(S32 type = (S32)LLWearableType::WT_SHAPE; type < (S32)LLWearableType::WT_COUNT; ++type) { - item_id = gAgentWearables.getWearableItemID((LLWearableType::EType)type); + item_id = gAgentWearables.getWearableItemID((LLWearableType::EType)type, 0); // TODO: MULTI-WEARABLE if(item_id.notNull()) { ids.push_back(item_id); @@ -2816,7 +2816,7 @@ void LLFloaterCustomize::updateInventoryUI() panel = mWearablePanelList[i]; if(panel) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType()); + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType(), 0); // TODO: MULTI-WEARABLE } if(item) { @@ -2851,7 +2851,7 @@ void LLFloaterCustomize::updateScrollingPanelUI() LLPanelEditWearable* panel = mWearablePanelList[sCurrentWearableType]; if(panel) { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType()); + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType(), 0); // TODO: MULTI-WEARABLE if(item) { U32 perm_mask = item->getPermissions().getMaskOwner(); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index e81d1d183..84d47a3f2 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -5422,7 +5422,7 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, if( !(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES) ) //&& //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) ) { - gAgentWearables.removeWearable( type ); + gAgentWearables.removeWearable( type, false, 0 ); // TODO: MULTI-WEARABLE } } } diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 795d1433f..06f72c774 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -84,7 +84,7 @@ LLBakedUploadData::LLBakedUploadData( LLVOAvatar* avatar, mStartTime = LLFrameTimer::getTotalTime(); // Record starting time for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ ) { - LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)i); + LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if( wearable ) { mWearableAssets[i] = wearable->getAssetID(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 37d589b2f..658c62ec1 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9184,7 +9184,7 @@ class LLEditTakeOff : public view_listener_t LLWearableType::EType type = LLWearableType::typeNameToType(clothing); if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) - LLAgentWearables::userRemoveWearable(type); + LLAgentWearables::userRemoveWearable(type,0); // TODO: MULTI-WEARABLE } return true; } diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index cf8157c64..5f7c79786 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -659,7 +659,7 @@ void LLWearable::writeToAvatar( BOOL set_by_user ) if( gFloaterCustomize ) { LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gInventory.getItem(gAgentWearables.getWearableItemID(mType)); + item = (LLViewerInventoryItem*)gInventory.getItem(gAgentWearables.getWearableItemID(mType, 0)); // TODO: MULTI-WEARABLE U32 perm_mask = PERM_NONE; BOOL is_complete = FALSE; if(item) diff --git a/indra/newview/llwearablelist.h b/indra/newview/llwearablelist.h index 890bf18f5..6f64549ae 100644 --- a/indra/newview/llwearablelist.h +++ b/indra/newview/llwearablelist.h @@ -33,6 +33,7 @@ #ifndef LL_LLWEARABLELIST_H #define LL_LLWEARABLELIST_H +#include "llmemory.h" #include "llwearable.h" #include "lluuid.h" #include "llassetstorage.h" diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 475e0c821..0d4d623a6 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -2005,7 +2005,7 @@ ERlvCmdRet RlvHandler::onGetOutfit(const RlvCommand& rlvCmd, std::string& strRep { // We never hide body parts, even if they're "locked" and we're hiding locked layers // (nor do we hide a layer if the issuing object is the only one that has this layer locked) - bool fWorn = (gAgentWearables.getWearable(wtRlvTypes[idxType])) && + bool fWorn = (gAgentWearables.getWearable(wtRlvTypes[idxType], 0)) && // TODO: MULTI-WEARABLE ( (!RlvSettings::getHideLockedLayers()) || (LLAssetType::AT_BODYPART == LLWearableType::getAssetType(wtRlvTypes[idxType])) || (RlvForceWear::isForceRemovable(wtRlvTypes[idxType], true, rlvCmd.getObjectID())) ); @@ -2033,7 +2033,7 @@ ERlvCmdRet RlvHandler::onGetOutfitNames(const RlvCommand& rlvCmd, std::string& s switch (rlvCmd.getBehaviourType()) { case RLV_BHVR_GETOUTFITNAMES: // Every layer that's worn - fAdd = (gAgentWearables.getWearable(wtType) != NULL); + fAdd = (gAgentWearables.getWearable(wtType, 0) != NULL); // TODO: MULTI-WEARABLE break; /* case RLV_BHVR_GETADDOUTFITNAMES: // Every layer that can be worn on (but ignore any locks set by the issuer) diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index 6f5a00e11..671b640b1 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -213,7 +213,7 @@ RlvCommandOptionGetPath::RlvCommandOptionGetPath(const RlvCommand& rlvCmd) if (rlvCmdOption.isWearableType()) //