From ea94cda5f5bb9a426782ee7c7aebb1095ba444c1 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Tue, 7 Mar 2023 19:30:30 +0200 Subject: [PATCH 01/31] =?UTF-8?q?SL-19356=20bring=20SFV=20to=20the=20top?= =?UTF-8?q?=20instead=20of=20opening=20a=20new=20window=20if=20there?= =?UTF-8?q?=E2=80=99s=20already=20one=20open=20for=20that=20folder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- indra/newview/llpanelmaininventory.cpp | 30 ++++++++++++++++++++++++++ indra/newview/llpanelmaininventory.h | 1 + 2 files changed, 31 insertions(+) diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 6b9e04840d..a3ac64aee8 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -415,8 +415,33 @@ void LLPanelMainInventory::newWindow() } } +//static void LLPanelMainInventory::newFolderWindow(LLUUID folder_id, LLUUID item_to_select) { + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end();) + { + LLFloaterSidePanelContainer* inventory_container = dynamic_cast(*iter++); + if (inventory_container) + { + LLSidepanelInventory* sidepanel_inventory = dynamic_cast(inventory_container->findChild("main_panel", true)); + if (sidepanel_inventory) + { + LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); + if (main_inventory && main_inventory->isSingleFolderMode() + && (main_inventory->getSingleFolderViewRoot() == folder_id)) + { + main_inventory->setFocus(true); + if(item_to_select.notNull()) + { + sidepanel_inventory->getActivePanel()->setSelection(item_to_select, TAKE_FOCUS_YES); + } + return; + } + } + } + } + S32 instance_num = get_instance_num(); LLFloaterSidePanelContainer* inventory_container = LLFloaterReg::showTypedInstance("inventory", LLSD(instance_num)); @@ -1346,6 +1371,11 @@ void LLPanelMainInventory::setSingleFolderViewRoot(const LLUUID& folder_id, bool } } +LLUUID LLPanelMainInventory::getSingleFolderViewRoot() +{ + return mSingleFolderPanelInventory->getSingleFolderRoot(); +} + void LLPanelMainInventory::showActionMenu(LLMenuGL* menu, std::string spawning_view_name) { if (menu) diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 7edaf7db96..b0f520ac5e 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -104,6 +104,7 @@ public: void onBackFolderClicked(); void onForwardFolderClicked(); void setSingleFolderViewRoot(const LLUUID& folder_id, bool clear_nav_history = true); + LLUUID getSingleFolderViewRoot(); bool isSingleFolderMode() { return mSingleFolderMode; } protected: From 783a802abc63efd3b55d5b38c76c03d87d47bf75 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 8 Mar 2023 02:41:11 +0200 Subject: [PATCH 02/31] SL-19359 Show Received Items panel in all new Inventory floaters --- indra/llui/lluictrl.cpp | 9 +++++ indra/llui/lluictrl.h | 1 + indra/newview/app_settings/settings.xml | 11 ------- indra/newview/llsidepanelinventory.cpp | 33 ++++++++++++------- .../default/xui/en/sidepanel_inventory.xml | 2 +- 5 files changed, 33 insertions(+), 23 deletions(-) diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 2196ba201b..21afcae7c3 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -531,6 +531,15 @@ void LLUICtrl::setControlVariable(LLControlVariable* control) } } +void LLUICtrl::removeControlVariable() +{ + if (mControlVariable) + { + mControlConnection.disconnect(); + mControlVariable = NULL; + } +} + //virtual void LLUICtrl::setControlName(const std::string& control_name, LLView *context) { diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 67dd24341c..be1c7dd0b6 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -175,6 +175,7 @@ public: bool setControlValue(const LLSD& value); void setControlVariable(LLControlVariable* control); virtual void setControlName(const std::string& control, LLView *context = NULL); + void removeControlVariable(); LLControlVariable* getControlVariable() { return mControlVariable; } diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 23521351ca..87b0ad8faf 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5001,17 +5001,6 @@ Boolean Value 0 - - InventoryInboxToggleState - - Comment - Stores the open/closed state of inventory Received items panel - Persist - 1 - Type - Boolean - Value - 0 InventoryLinking diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp index 3a0302e531..cfceefed26 100644 --- a/indra/newview/llsidepanelinventory.cpp +++ b/indra/newview/llsidepanelinventory.cpp @@ -73,6 +73,8 @@ static const char * const INBOX_LAYOUT_PANEL_NAME = "inbox_layout_panel"; static const char * const INVENTORY_LAYOUT_STACK_NAME = "inventory_layout_stack"; static const char * const MARKETPLACE_INBOX_PANEL = "marketplace_inbox"; +static bool sLoginCompleted = false; + // // Helpers // @@ -182,22 +184,30 @@ BOOL LLSidepanelInventory::postBuild() inbox_button->setCommitCallback(boost::bind(&LLSidepanelInventory::onToggleInboxBtn, this)); - // Get the previous inbox state from "InventoryInboxToggleState" setting. - bool is_inbox_collapsed = !inbox_button->getToggleState(); + // For main Inventory floater: Get the previous inbox state from "InventoryInboxToggleState" setting. + // For additional Inventory floaters: Collapsed state is default. + bool is_inbox_collapsed = !inbox_button->getToggleState() || sLoginCompleted; // Restore the collapsed inbox panel state mInboxLayoutPanel = getChild(INBOX_LAYOUT_PANEL_NAME); - inv_stack->collapsePanel(mInboxLayoutPanel, is_inbox_collapsed); - if (!is_inbox_collapsed) - { + inv_stack->collapsePanel(mInboxLayoutPanel, is_inbox_collapsed); + if (!is_inbox_collapsed) + { mInboxLayoutPanel->setTargetDim(gSavedPerAccountSettings.getS32("InventoryInboxHeight")); - } + } - // Set the inbox visible based on debug settings (final setting comes from http request below) - enableInbox(gSavedSettings.getBOOL("InventoryDisplayInbox")); - - // Trigger callback for after login so we can setup to track inbox changes after initial inventory load - LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSidepanelInventory::updateInbox, this)); + if (sLoginCompleted) + { + //save the state of Inbox panel only for main Inventory floater + inbox_button->removeControlVariable(); + inbox_button->setToggleState(false); + updateInbox(); + } + else + { + // Trigger callback for after login so we can setup to track inbox changes after initial inventory load + LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSidepanelInventory::updateInbox, this)); + } } gSavedSettings.getControl("InventoryDisplayInbox")->getCommitSignal()->connect(boost::bind(&handleInventoryDisplayInboxChanged)); @@ -207,6 +217,7 @@ BOOL LLSidepanelInventory::postBuild() void LLSidepanelInventory::updateInbox() { + sLoginCompleted = true; // // Track inbox folder changes // diff --git a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml index a4b7f48c5e..dfd3e3bf9d 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml @@ -57,7 +57,7 @@ user_resize="true" follows="left|right|top" name="inbox_layout_panel" - visible="false" + visible="true" min_dim="35" expanded_min_dim="90" height="235"> From fa50ce4b1054a453a97a81d64eb8099cae6f4cb5 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 9 Mar 2023 16:22:50 +0200 Subject: [PATCH 03/31] =?UTF-8?q?SL-19373=20Show=20folder=20name=20in=20fi?= =?UTF-8?q?lter=20floater=E2=80=99s=20title=20bar=20in=20single-folder=20v?= =?UTF-8?q?iew?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- indra/newview/llpanelmaininventory.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index a3ac64aee8..ac188abb05 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -718,7 +718,7 @@ void LLPanelMainInventory::onFilterEdit(const std::string& search_string ) void LLPanelMainInventory::onFilterSelected() { // Find my index - mActivePanel = (LLInventoryPanel*)getChild("inventory filter tabs")->getCurrentPanel(); + mActivePanel = mSingleFolderMode ? getChild("single_folder_inv") : (LLInventoryPanel*)getChild("inventory filter tabs")->getCurrentPanel(); if (!mActivePanel) { @@ -736,6 +736,14 @@ void LLPanelMainInventory::onFilterSelected() if (finder) { finder->changeFilter(&filter); + if (mSingleFolderMode) + { + const LLViewerInventoryCategory* cat = gInventory.getCategory(mSingleFolderPanelInventory->getSingleFolderRoot()); + if (cat) + { + finder->setTitle(cat->getName()); + } + } } if (filter.isActive()) { @@ -897,6 +905,15 @@ void LLPanelMainInventory::toggleFindOptions() parent_floater->addDependentFloater(mFinderHandle); // start background fetch of folders LLInventoryModelBackgroundFetch::instance().start(); + + if (mSingleFolderMode) + { + const LLViewerInventoryCategory* cat = gInventory.getCategory(mSingleFolderPanelInventory->getSingleFolderRoot()); + if (cat) + { + finder->setTitle(cat->getName()); + } + } } else { @@ -1323,6 +1340,7 @@ void LLPanelMainInventory::onViewModeClick() mActivePanel = mSingleFolderMode ? getChild("single_folder_inv") : (LLInventoryPanel*)getChild("inventory filter tabs")->getCurrentPanel(); updateTitle(); + onFilterSelected(); LLSidepanelInventory* sidepanel_inventory = getParentSidepanelInventory(); if (sidepanel_inventory) @@ -1795,6 +1813,11 @@ void LLPanelMainInventory::updateTitle() if (cat) { inventory_floater->setTitle(cat->getName()); + LLFloaterInventoryFinder *finder = getFinder(); + if (finder) + { + finder->setTitle(cat->getName()); + } } } else From e364b90d61b7711c088d9bca7307e3760f28c59d Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Fri, 10 Mar 2023 17:39:24 +0200 Subject: [PATCH 04/31] SL-19335 Switching view (using the switch button) should select appropriate folder --- indra/newview/llinventoryfunctions.cpp | 2 +- indra/newview/llinventorypanel.cpp | 2 +- indra/newview/llpanelmaininventory.cpp | 58 +++++++++++++++++++++++++- indra/newview/llpanelmaininventory.h | 1 + 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 15916ffaba..eaea1ef972 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -810,7 +810,7 @@ void show_item_original(const LLUUID& item_uuid) { if(main_inventory->isSingleFolderMode()) { - main_inventory->onViewModeClick(); + main_inventory->toggleViewMode(); } main_inventory->resetFilters(); } diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 076f002f47..037dda70f0 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1843,7 +1843,7 @@ void LLInventoryPanel::setSFViewAndOpenFolder(const LLInventoryPanel* panel, con LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); if (main_inventory && panel->hasAncestor(main_inventory) && !main_inventory->isSingleFolderMode()) { - main_inventory->onViewModeClick(); + main_inventory->toggleViewMode(); main_inventory->setSingleFolderViewRoot(folder_id, false); } } diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index ac188abb05..f8c1fcb5f5 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -453,7 +453,7 @@ void LLPanelMainInventory::newFolderWindow(LLUUID folder_id, LLUUID item_to_sele LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel(); if (main_inventory) { - main_inventory->onViewModeClick(); + main_inventory->toggleViewMode(); if(folder_id.notNull()) { main_inventory->setSingleFolderViewRoot(folder_id); @@ -1329,7 +1329,7 @@ void LLPanelMainInventory::onAddButtonClick() } } -void LLPanelMainInventory::onViewModeClick() +void LLPanelMainInventory::toggleViewMode() { mSingleFolderMode = !mSingleFolderMode; @@ -1354,7 +1354,61 @@ void LLPanelMainInventory::onViewModeClick() sidepanel_inventory->toggleInbox(); } } +} +void LLPanelMainInventory::onViewModeClick() +{ + LLUUID selected_folder; + LLUUID new_root_folder; + if(mSingleFolderMode) + { + selected_folder = mSingleFolderPanelInventory->getSingleFolderRoot(); + } + else + { + LLFolderView* root = getActivePanel()->getRootFolder(); + std::set selection_set = root->getSelectionList(); + if (selection_set.size() == 1) + { + LLFolderViewItem* current_item = *selection_set.begin(); + if (current_item) + { + const LLUUID& id = static_cast(current_item->getViewModelItem())->getUUID(); + if(gInventory.getCategory(id) != NULL) + { + new_root_folder = id; + } + else + { + const LLViewerInventoryItem* selected_item = gInventory.getItem(id); + if (selected_item && selected_item->getParentUUID().notNull()) + { + new_root_folder = selected_item->getParentUUID(); + selected_folder = id; + } + } + } + } + } + + toggleViewMode(); + + if (mSingleFolderMode && new_root_folder.notNull()) + { + setSingleFolderViewRoot(new_root_folder, true); + if(selected_folder.notNull()) + { + getActivePanel()->setSelection(selected_folder, TAKE_FOCUS_YES); + } + } + else + { + if(selected_folder.notNull()) + { + selectAllItemsPanel(); + getActivePanel()->setSelection(selected_folder, TAKE_FOCUS_YES); + } + } } void LLPanelMainInventory::onUpFolderClicked() diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index b0f520ac5e..5f488539dd 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -100,6 +100,7 @@ public: void resetFilters(); void onViewModeClick(); + void toggleViewMode(); void onUpFolderClicked(); void onBackFolderClicked(); void onForwardFolderClicked(); From a777a0b27ed6adfa99d708e289e704915f2b62b7 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 7 Mar 2023 21:51:14 +0200 Subject: [PATCH 05/31] SL-18629 WIP Replacing UDP creation messages with callback based AIS --- indra/newview/llappearancemgr.cpp | 54 ++++++++----- .../newview/llfloatermarketplacelistings.cpp | 35 ++++++--- indra/newview/llfloateropenobject.cpp | 34 ++------- indra/newview/llfriendcard.cpp | 41 ++++++---- indra/newview/llinventoryfunctions.cpp | 60 +++++++-------- indra/newview/llviewerinventory.cpp | 18 ++++- indra/newview/llviewermessage.cpp | 75 ++++++++++--------- 7 files changed, 172 insertions(+), 145 deletions(-) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index d8e239822e..5595a92b43 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1703,12 +1703,17 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds } // USES UDP PATH // D567 needs to carry over thumbnail info - LLUUID subfolder_id = gInventory.createNewCategory( parent_id, - LLFolderType::FT_NONE, - src_cat->getName()); - shallowCopyCategoryContents(src_id, subfolder_id, cb); + gInventory.createNewCategory( + parent_id, + LLFolderType::FT_NONE, + src_cat->getName(), + [src_id, cb](const LLUUID &new_id) + { + LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_id, new_id, cb); - gInventory.notifyObservers(); + gInventory.notifyObservers(); + } + ); } void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id, @@ -2730,21 +2735,27 @@ void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool ap // UDP PATH // D567 needs to carry over thumbnail info if present - LLUUID new_cat_id = gInventory.createNewCategory( + gInventory.createNewCategory( pid, LLFolderType::FT_NONE, - name); + name, + [cat_id, append](const LLUUID& new_cat_id) + { + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat_id, cats, items); + // Create a CopyMgr that will copy items, manage its own destruction + new LLCallAfterInventoryCopyMgr( + *items, new_cat_id, std::string("wear_inventory_category_callback"), + boost::bind(&LLAppearanceMgr::wearInventoryCategoryOnAvatar, + LLAppearanceMgr::getInstance(), + gInventory.getCategory(new_cat_id), + append)); - // Create a CopyMgr that will copy items, manage its own destruction - new LLCallAfterInventoryCopyMgr( - *items, new_cat_id, std::string("wear_inventory_category_callback"), - boost::bind(&LLAppearanceMgr::wearInventoryCategoryOnAvatar, - LLAppearanceMgr::getInstance(), - gInventory.getCategory(new_cat_id), - append)); - - // BAP fixes a lag in display of created dir. - gInventory.notifyObservers(); + // BAP fixes a lag in display of created dir. + gInventory.notifyObservers(); + } + ); } else { @@ -4004,11 +4015,14 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo { // UDP PATH, should remove // D567 copy thumbnail info from source folder - LLUUID folder_id = gInventory.createNewCategory( + gInventory.createNewCategory( parent_id, LLFolderType::FT_OUTFIT, - new_folder_name); - onOutfitFolderCreated(folder_id, show_panel); + new_folder_name, + [show_panel](const LLUUID &new_cat_id) + { + LLAppearanceMgr::getInstance()->onOutfitFolderCreated(new_cat_id, show_panel); + }); } } diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index 58bd4bc82b..88fff58fc8 100644 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -230,18 +230,31 @@ void LLPanelMarketplaceListings::onTabChange() void LLPanelMarketplaceListings::onAddButtonClicked() { - // Find active panel - LLInventoryPanel* panel = (LLInventoryPanel*)getChild("marketplace_filter_tabs")->getCurrentPanel(); - if (panel) - { - LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); - llassert(marketplacelistings_id.notNull()); - LLFolderType::EType preferred_type = LLFolderType::lookup("category"); - LLUUID category = gInventory.createNewCategory(marketplacelistings_id, preferred_type, LLStringUtil::null); - gInventory.notifyObservers(); - panel->setSelectionByID(category, TRUE); - panel->getRootFolder()->setNeedsAutoRename(TRUE); + LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + llassert(marketplacelistings_id.notNull()); + LLFolderType::EType preferred_type = LLFolderType::lookup("category"); + LLHandle handle = getHandle(); + gInventory.createNewCategory( + marketplacelistings_id, + preferred_type, + LLStringUtil::null, + [handle](const LLUUID &new_cat_id) + { + // Find active panel + LLPanel *marketplace_panel = handle.get(); + if (!marketplace_panel) + { + return; + } + LLInventoryPanel* panel = (LLInventoryPanel*)marketplace_panel->getChild("marketplace_filter_tabs")->getCurrentPanel(); + if (panel) + { + gInventory.notifyObservers(); + panel->setSelectionByID(new_cat_id, TRUE); + panel->getRootFolder()->setNeedsAutoRename(TRUE); + } } + ); } void LLPanelMarketplaceListings::onAuditButtonClicked() diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index 12ad6dcd33..73eaced562 100644 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -165,35 +165,11 @@ void LLFloaterOpenObject::moveToInventory(bool wear, bool replace) inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear,replace); // D567 copy thumbnail info - LLUUID category_id = gInventory.createNewCategory(parent_category_id, - LLFolderType::FT_NONE, - name, - func); - - //If we get a null category ID, we are using a capability in createNewCategory and we will - //handle the following in the callbackCreateInventoryCategory routine. - // D567 review - if ( category_id.notNull() ) - { - LLCatAndWear* data = new LLCatAndWear; - data->mCatID = category_id; - data->mWear = wear; - data->mFolderResponded = false; - data->mReplace = replace; - - // Copy and/or move the items into the newly created folder. - // Ignore any "you're going to break this item" messages. - BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE, - callbackMoveInventory, - (void*)data); - if (!success) - { - delete data; - data = NULL; - - LLNotificationsUtil::add("OpenObjectCannotCopy"); - } - } + gInventory.createNewCategory( + parent_category_id, + LLFolderType::FT_NONE, + name, + func); } // static diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp index e395da7f1e..ce28915d93 100644 --- a/indra/newview/llfriendcard.cpp +++ b/indra/newview/llfriendcard.cpp @@ -478,14 +478,24 @@ void LLFriendCardsManager::ensureFriendsFolderExists() LL_WARNS() << "Failed to find \"" << cat_name << "\" category descendents in Category Tree." << LL_ENDL; } - friends_folder_ID = gInventory.createNewCategory(calling_cards_folder_ID, - LLFolderType::FT_CALLINGCARD, get_friend_folder_name()); - - gInventory.createNewCategory(friends_folder_ID, - LLFolderType::FT_CALLINGCARD, get_friend_all_subfolder_name()); - - // Now when we have all needed folders we can sync their contents with buddies list. - syncFriendsFolder(); + gInventory.createNewCategory( + calling_cards_folder_ID, + LLFolderType::FT_CALLINGCARD, + get_friend_folder_name(), + [](const LLUUID &new_category_id) + { + gInventory.createNewCategory( + new_category_id, + LLFolderType::FT_CALLINGCARD, + get_friend_all_subfolder_name(), + [](const LLUUID &new_category_id) + { + // Now when we have all needed folders we can sync their contents with buddies list. + LLFriendCardsManager::getInstance()->syncFriendsFolder(); + } + ); + } + ); } } @@ -510,11 +520,16 @@ void LLFriendCardsManager::ensureFriendsAllFolderExists() LL_WARNS() << "Failed to find \"" << cat_name << "\" category descendents in Category Tree." << LL_ENDL; } - friends_all_folder_ID = gInventory.createNewCategory(friends_folder_ID, - LLFolderType::FT_CALLINGCARD, get_friend_all_subfolder_name()); - - // Now when we have all needed folders we can sync their contents with buddies list. - syncFriendsFolder(); + gInventory.createNewCategory( + friends_folder_ID, + LLFolderType::FT_CALLINGCARD, + get_friend_all_subfolder_name(), + [](const LLUUID &new_cat_id) + { + // Now when we have all needed folders we can sync their contents with buddies list. + LLFriendCardsManager::getInstance()->syncFriendsFolder(); + } + ); } } diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index eaea1ef972..79d222d904 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -861,22 +861,6 @@ void open_marketplace_listings() LLFloaterReg::showInstance("marketplace_listings"); } -// Create a new folder in destFolderId with the same name as the item name and return the uuid of the new folder -// Note: this is used locally in various situation where we need to wrap an item into a special folder -LLUUID create_folder_for_item(LLInventoryItem* item, const LLUUID& destFolderId) -{ - llassert(item); - llassert(destFolderId.notNull()); - - LLUUID created_folder_id = gInventory.createNewCategory(destFolderId, LLFolderType::FT_NONE, item->getName()); - gInventory.notifyObservers(); - - // *TODO : Create different notifications for the various cases - LLNotificationsUtil::add("OutboxFolderCreated"); - - return created_folder_id; -} - ///---------------------------------------------------------------------------- // Marketplace functions // @@ -1753,28 +1737,36 @@ bool validate_marketplacelistings( } cb(message,depth,LLError::LEVEL_WARN); } - LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, new_folder_type, folder_name); - - // Move each item to the new folder - while (!items_vector_it->second.empty()) + std::vector &uuid_vector = items_vector_it->second; + gInventory.createNewCategory( + parent_uuid, + new_folder_type, + folder_name, + [uuid_vector, cb, indent, depth, parent_uuid, notify_observers](const LLUUID &new_category_id) { - LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back()); - if (cb) + // Move each item to the new folder + std::vector::reverse_iterator iter = uuid_vector.rbegin(); + while (iter != uuid_vector.rend()) { - std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move"); - cb(message,depth,LLError::LEVEL_WARN); + LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(*iter); + if (cb) + { + std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move"); + cb(message, depth, LLError::LEVEL_WARN); + } + gInventory.changeItemParent(viewer_inv_item, new_category_id, true); + iter++; + } + + // Next type + update_marketplace_category(parent_uuid); + update_marketplace_category(new_category_id); + if (notify_observers) + { + gInventory.notifyObservers(); } - gInventory.changeItemParent(viewer_inv_item, folder_uuid, true); - items_vector_it->second.pop_back(); - } - - // Next type - update_marketplace_category(parent_uuid); - update_marketplace_category(folder_uuid); - if (notify_observers) - { - gInventory.notifyObservers(); } + ); items_vector_it++; } } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 27f57bda81..d0832e16d7 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1696,9 +1696,21 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge, parent_id = gInventory.getRootFolderID(); } - LLUUID category = gInventory.createNewCategory(parent_id, preferred_type, LLStringUtil::null); - gInventory.notifyObservers(); - panel->setSelectionByID(category, TRUE); + LLHandle handle = panel->getHandle(); + gInventory.createNewCategory( + parent_id, + preferred_type, + LLStringUtil::null, + [handle](const LLUUID &new_category_id) + { + gInventory.notifyObservers(); + LLInventoryPanel* panel = static_cast(handle.get()); + if (panel) + { + panel->setSelectionByID(new_category_id, TRUE); + } + } + ); } else if ("lsl" == type_name) { diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 5266db5b38..767e092318 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5898,42 +5898,47 @@ void container_inventory_arrived(LLViewerObject* object, { // create a new inventory category to put this in LLUUID cat_id; - cat_id = gInventory.createNewCategory(gInventory.getRootFolderID(), - LLFolderType::FT_NONE, - LLTrans::getString("AcquiredItems")); + gInventory.createNewCategory( + gInventory.getRootFolderID(), + LLFolderType::FT_NONE, + LLTrans::getString("AcquiredItems"), + [inventory](const LLUUID &new_cat_id) + { + LLInventoryObject::object_list_t::const_iterator it = inventory->begin(); + LLInventoryObject::object_list_t::const_iterator end = inventory->end(); + for (; it != end; ++it) + { + if ((*it)->getType() != LLAssetType::AT_CATEGORY) + { + LLInventoryObject* obj = (LLInventoryObject*)(*it); + LLInventoryItem* item = (LLInventoryItem*)(obj); + LLUUID item_id; + item_id.generate(); + time_t creation_date_utc = time_corrected(); + LLPointer new_item + = new LLViewerInventoryItem(item_id, + new_cat_id, + item->getPermissions(), + item->getAssetUUID(), + item->getType(), + item->getInventoryType(), + item->getName(), + item->getDescription(), + LLSaleInfo::DEFAULT, + item->getFlags(), + creation_date_utc); + new_item->updateServer(TRUE); + gInventory.updateItem(new_item); + } + } + gInventory.notifyObservers(); - LLInventoryObject::object_list_t::const_iterator it = inventory->begin(); - LLInventoryObject::object_list_t::const_iterator end = inventory->end(); - for ( ; it != end; ++it) - { - if ((*it)->getType() != LLAssetType::AT_CATEGORY) - { - LLInventoryObject* obj = (LLInventoryObject*)(*it); - LLInventoryItem* item = (LLInventoryItem*)(obj); - LLUUID item_id; - item_id.generate(); - time_t creation_date_utc = time_corrected(); - LLPointer new_item - = new LLViewerInventoryItem(item_id, - cat_id, - item->getPermissions(), - item->getAssetUUID(), - item->getType(), - item->getInventoryType(), - item->getName(), - item->getDescription(), - LLSaleInfo::DEFAULT, - item->getFlags(), - creation_date_utc); - new_item->updateServer(TRUE); - gInventory.updateItem(new_item); - } - } - gInventory.notifyObservers(); - if(active_panel) - { - active_panel->setSelection(cat_id, TAKE_FOCUS_NO); - } + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + if (active_panel) + { + active_panel->setSelection(new_cat_id, TAKE_FOCUS_NO); + } + }); } else if (inventory->size() == 2) { From 811da7dbb1bdbf04a2dceb02ad4d296db4274076 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 7 Mar 2023 22:39:36 +0200 Subject: [PATCH 06/31] SL-18629 WIP Replacing UDP creation messages with callback based AIS #2 findCategory and move_item_to_marketplacelistings --- indra/newview/llappearancemgr.cpp | 2 +- .../newview/llfloatereditenvironmentbase.cpp | 2 +- indra/newview/llfloatergesture.cpp | 2 +- indra/newview/llfloaterlinkreplace.cpp | 4 +- .../newview/llfloatermarketplacelistings.cpp | 49 ++++++-- indra/newview/llfloatermarketplacelistings.h | 1 + indra/newview/llinventorybridge.cpp | 66 +++++------ indra/newview/llinventoryfunctions.cpp | 102 +++++++++-------- indra/newview/llinventorymodel.cpp | 107 +++++++++++++----- indra/newview/llinventorymodel.h | 15 +-- indra/newview/llinventorypanel.cpp | 2 +- indra/newview/llmarketplacefunctions.cpp | 4 +- indra/newview/llpaneloutfitsinventory.cpp | 2 +- indra/newview/llsidepanelinventory.cpp | 2 +- indra/newview/llstartup.cpp | 2 +- indra/newview/lltooldraganddrop.cpp | 6 +- indra/newview/llviewermenu.cpp | 4 +- 17 files changed, 233 insertions(+), 139 deletions(-) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 5595a92b43..1c55113082 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -3213,7 +3213,7 @@ void LLAppearanceMgr::copyLibraryGestures() // Copy gestures LLUUID lib_gesture_cat_id = - gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE,false); + gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE); if (lib_gesture_cat_id.isNull()) { LL_WARNS() << "Unable to copy gestures, source category not found" << LL_ENDL; diff --git a/indra/newview/llfloatereditenvironmentbase.cpp b/indra/newview/llfloatereditenvironmentbase.cpp index 2850951668..cd24d79b7f 100644 --- a/indra/newview/llfloatereditenvironmentbase.cpp +++ b/indra/newview/llfloatereditenvironmentbase.cpp @@ -260,7 +260,7 @@ void LLFloaterEditEnvironmentBase::onSaveAsCommit(const LLSD& notification, cons } else if (mInventoryItem) { - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); LLUUID parent_id = mInventoryItem->getParentUUID(); if (marketplacelistings_id == parent_id || gInventory.isObjectDescendentOf(mInventoryItem->getUUID(), gInventory.getLibraryRootFolderID())) { diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index d17889bed1..f29046c513 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -211,7 +211,7 @@ BOOL LLFloaterGesture::postBuild() getChildView("play_btn")->setVisible( true); getChildView("stop_btn")->setVisible( false); setDefaultBtn("play_btn"); - mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE, false); + mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); uuid_vec_t folders; folders.push_back(mGestureFolderID); diff --git a/indra/newview/llfloaterlinkreplace.cpp b/indra/newview/llfloaterlinkreplace.cpp index 8ee7a72055..b42c49c607 100644 --- a/indra/newview/llfloaterlinkreplace.cpp +++ b/indra/newview/llfloaterlinkreplace.cpp @@ -335,8 +335,8 @@ BOOL LLFloaterLinkReplace::tick() void LLFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items) { const LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); - const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) { diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index 88fff58fc8..9110d9e902 100644 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -230,7 +230,7 @@ void LLPanelMarketplaceListings::onTabChange() void LLPanelMarketplaceListings::onAddButtonClicked() { - LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); llassert(marketplacelistings_id.notNull()); LLFolderType::EType preferred_type = LLFolderType::lookup("category"); LLHandle handle = getHandle(); @@ -375,6 +375,7 @@ LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key) , mInventoryTitle(NULL) , mPanelListings(NULL) , mPanelListingsSet(false) +, mRootFolderCreating(false) { } @@ -460,15 +461,39 @@ void LLFloaterMarketplaceListings::setRootFolder() // If we are *not* a merchant or we have no market place connection established yet, do nothing return; } + if (!gInventory.isInventoryUsable()) + { + return; + } + LLFolderType::EType preferred_type = LLFolderType::FT_MARKETPLACE_LISTINGS; // We are a merchant. Get the Marketplace listings folder, create it if needs be. - LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true); - if (marketplacelistings_id.isNull()) - { - // We should never get there unless the inventory fails badly - LL_ERRS("SLM") << "Inventory problem: failure to create the marketplace listings folder for a merchant!" << LL_ENDL; - return; - } + LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(preferred_type); + + if (marketplacelistings_id.isNull()) + { + if (!mRootFolderCreating) + { + mRootFolderCreating = true; + gInventory.createNewCategory( + gInventory.getRootFolderID(), + preferred_type, + LLStringUtil::null, + [preferred_type](const LLUUID &new_cat_id) + { + LLFloaterMarketplaceListings *marketplace = LLFloaterReg::findTypedInstance("marketplace_listings"); + if (marketplace) + { + // will call setRootFolder again + marketplace->updateView(); + } + } + ); + } + return; + } + + mRootFolderCreating = false; // No longer need to observe new category creation if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) @@ -486,6 +511,7 @@ void LLFloaterMarketplaceListings::setRootFolder() } mRootFolderId = marketplacelistings_id; + mRootFolderCreating = true; } void LLFloaterMarketplaceListings::setPanels() @@ -556,6 +582,11 @@ void LLFloaterMarketplaceListings::updateView() { setRootFolder(); } + if (mRootFolderCreating) + { + // waiting for callback + return; + } // Update the bottom initializing status and progress dial if we are initializing or if we're a merchant and still loading if ((mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) || (is_merchant && (data_fetched <= MarketplaceFetchCodes::MARKET_FETCH_LOADING)) ) @@ -859,7 +890,7 @@ void LLFloaterMarketplaceValidation::onOpen(const LLSD& key) LLUUID cat_id(key.asUUID()); if (cat_id.isNull()) { - cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); } // Validates the folder diff --git a/indra/newview/llfloatermarketplacelistings.h b/indra/newview/llfloatermarketplacelistings.h index 77e855fd2a..085e517a9d 100644 --- a/indra/newview/llfloatermarketplacelistings.h +++ b/indra/newview/llfloatermarketplacelistings.h @@ -140,6 +140,7 @@ private: LLTextBox * mInventoryTitle; LLUUID mRootFolderId; + bool mRootFolderCreating; LLPanelMarketplaceListings * mPanelListings; bool mPanelListingsSet; }; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 0c7f237415..fb92437c3d 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -333,7 +333,7 @@ BOOL LLInvFVBridge::cutToClipboard() const LLInventoryObject* obj = gInventory.getObject(mUUID); if (obj && isItemMovable() && isItemRemovable()) { - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); const BOOL cut_from_marketplacelistings = gInventory.isObjectDescendentOf(mUUID, marketplacelistings_id); if (cut_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(mUUID) || @@ -1286,7 +1286,7 @@ bool LLInvFVBridge::isItemInOutfits() const const LLInventoryModel* model = getInventoryModel(); if(!model) return false; - const LLUUID my_outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + const LLUUID my_outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); return isCOFFolder() || (my_outfits_cat == mUUID) || model->isObjectDescendentOf(mUUID, my_outfits_cat); } @@ -1321,7 +1321,7 @@ BOOL LLInvFVBridge::isCOFFolder() const // *TODO : Suppress isInboxFolder() once Merchant Outbox is fully deprecated BOOL LLInvFVBridge::isInboxFolder() const { - const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false); + const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); if (inbox_id.isNull()) { @@ -1333,7 +1333,7 @@ BOOL LLInvFVBridge::isInboxFolder() const BOOL LLInvFVBridge::isMarketplaceListingsFolder() const { - const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (folder_id.isNull()) { @@ -1633,7 +1633,7 @@ bool LLInvFVBridge::canListOnMarketplaceNow() const { std::string error_msg; LLInventoryModel* model = getInventoryModel(); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplacelistings_id.notNull()) { LLViewerInventoryCategory * master_folder = model->getCategory(marketplacelistings_id); @@ -1792,7 +1792,7 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) { LLInventoryItem* itemp = model->getItem(mUUID); if (!itemp) return; - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); // Note: For a single item, if it's not a copy, then it's a move move_item_to_marketplacelistings(itemp, marketplacelistings_id, ("copy_to_marketplace_listings" == action)); } @@ -2566,8 +2566,8 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, if (!filter) return false; const LLUUID &cat_id = inv_cat->getUUID(); - const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); const LLUUID from_folder_uuid = inv_cat->getParentUUID(); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); @@ -2585,10 +2585,10 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, if (is_agent_inventory) { - const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false); - const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); - const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); - const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND, false); + const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); @@ -2871,7 +2871,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } else { - if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX, false))) + if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX))) { set_dad_inbox_object(cat_id); } @@ -3490,7 +3490,7 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) { LLInventoryCategory * cat = gInventory.getCategory(mUUID); if (!cat) return; - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); move_folder_to_marketplacelistings(cat, marketplacelistings_id, ("move_to_marketplace_listings" != action), (("copy_or_move_to_marketplace_listings" == action))); } } @@ -3740,7 +3740,7 @@ void LLFolderBridge::pasteFromClipboard() LLInventoryModel* model = getInventoryModel(); if (model && isClipboardPasteable()) { - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); const BOOL paste_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); BOOL cut_from_marketplacelistings = FALSE; @@ -3801,11 +3801,11 @@ void LLFolderBridge::perform_pasteFromClipboard() LLInventoryModel* model = getInventoryModel(); if (model && isClipboardPasteable()) { - const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); - const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false); - const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); - const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND, false); + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); @@ -4053,9 +4053,9 @@ void LLFolderBridge::pasteLinkFromClipboard() LLInventoryModel* model = getInventoryModel(); if(model) { - const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); - const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); @@ -4125,8 +4125,8 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); const LLUUID &favorites = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); - const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); if (outfits_id == mUUID) { @@ -4977,7 +4977,7 @@ void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_c { if((inv_item->getInventoryType() == LLInventoryType::IT_TEXTURE) || (inv_item->getInventoryType() == LLInventoryType::IT_SNAPSHOT)) { - const LLUUID &my_outifts_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + const LLUUID &my_outifts_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); if(mUUID != my_outifts_id) { LLFloaterOutfitPhotoPreview* photo_preview = LLFloaterReg::showTypedInstance("outfit_photo_preview", inv_item->getUUID()); @@ -5093,11 +5093,11 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, LLInventoryFilter* filter = getInventoryFilter(); if (!filter) return false; - const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false); - const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); - const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); const LLUUID from_folder_uuid = inv_item->getParentUUID(); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); @@ -5117,7 +5117,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, LLViewerObject* object = NULL; if(LLToolDragAndDrop::SOURCE_AGENT == source) { - const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false); + const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID()); @@ -5278,7 +5278,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, else { // set up observer to select item once drag and drop from inbox is complete - if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false))) + if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX))) { set_dad_inbox_object(inv_item->getUUID()); } diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 79d222d904..6b406c4c9c 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -372,7 +372,7 @@ void update_all_marketplace_count(const LLUUID& cat_id) void update_all_marketplace_count() { // Get the marketplace root and launch the recursive exploration - const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (!marketplace_listings_uuid.isNull()) { update_all_marketplace_count(marketplace_listings_uuid); @@ -875,7 +875,7 @@ S32 depth_nesting_in_marketplace(LLUUID cur_uuid) // Todo: findCategoryUUIDForType is somewhat expensive with large // flat root folders yet we use depth_nesting_in_marketplace at // every turn, find a way to correctly cache this id. - const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplace_listings_uuid.isNull()) { return -1; @@ -1347,6 +1347,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn return accept; } +// Can happen asynhroneously!!! bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy) { // Get the marketplace listings depth of the destination folder, exit with error if not under marketplace @@ -1386,53 +1387,64 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol if (can_move_to_marketplace(inv_item, error_msg, true)) { // When moving an isolated item, we might need to create the folder structure to support it + + LLUUID item_id = inv_item->getUUID(); + std::function callback_create_stock = [copy, item_id](const LLUUID& new_cat_id) + { + // Verify we can have this item in that destination category + LLViewerInventoryCategory* dest_cat = gInventory.getCategory(new_cat_id); + LLViewerInventoryItem * viewer_inv_item = gInventory.getItem(item_id); + if (!dest_cat->acceptItem(viewer_inv_item)) + { + LLSD subs; + subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted"); + LLNotificationsUtil::add("MerchantPasteFailed", subs); + } + + if (copy) + { + // Copy the item + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_id)); + copy_inventory_item( + gAgent.getID(), + viewer_inv_item->getPermissions().getOwner(), + viewer_inv_item->getUUID(), + new_cat_id, + std::string(), + cb); + } + else + { + // Reparent the item + gInventory.changeItemParent(viewer_inv_item, new_cat_id, true); + } + }; + + std::function callback_dest_create = [copy, item_id, callback_create_stock](const LLUUID& new_cat_id) + { + LLViewerInventoryCategory* dest_cat = gInventory.getCategory(new_cat_id); + LLViewerInventoryItem * viewer_inv_item = gInventory.getItem(item_id); + if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && + (dest_cat->getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK)) + { + // We need to create a stock folder to move a no copy item + gInventory.createNewCategory(new_cat_id, LLFolderType::FT_MARKETPLACE_STOCK, viewer_inv_item->getName(), callback_create_stock); + } + else + { + callback_create_stock(new_cat_id); + } + }; + if (depth == 0) { // We need a listing folder - dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName()); - depth++; + gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName(), callback_dest_create); } if (depth == 1) { // We need a version folder - dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName()); - depth++; - } - LLViewerInventoryCategory* dest_cat = gInventory.getCategory(dest_folder); - if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && - (dest_cat->getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK)) - { - // We need to create a stock folder to move a no copy item - dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_MARKETPLACE_STOCK, viewer_inv_item->getName()); - dest_cat = gInventory.getCategory(dest_folder); - depth++; - } - - // Verify we can have this item in that destination category - if (!dest_cat->acceptItem(viewer_inv_item)) - { - LLSD subs; - subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted"); - LLNotificationsUtil::add("MerchantPasteFailed", subs); - return false; - } - - if (copy) - { - // Copy the item - LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, dest_folder)); - copy_inventory_item( - gAgent.getID(), - viewer_inv_item->getPermissions().getOwner(), - viewer_inv_item->getUUID(), - dest_folder, - std::string(), - cb); - } - else - { - // Reparent the item - gInventory.changeItemParent(viewer_inv_item, dest_folder, true); + gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName(), callback_dest_create); } } else @@ -2496,7 +2508,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root if ("delete" == action) { static bool sDisplayedAtSession = false; - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); bool marketplacelistings_item = false; LLAllDescendentsPassedFilter f; for (std::set::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it) @@ -2620,7 +2632,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root if (action == "wear" || action == "wear_add") { const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); std::copy_if(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids), @@ -2873,7 +2885,7 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root) // target listing *and* the original listing. So we need to keep track of both. // Note: do not however put the marketplace listings root itself in this list or the whole marketplace data will be rebuilt. sMarketplaceFolders.clear(); - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplacelistings_id.isNull()) { return; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index fb19994054..b2cfc8584e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -804,10 +804,63 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E } } +void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred_type) +{ + LLUUID rv = LLUUID::null; + LLUUID root_id = gInventory.getRootFolderID(); + if (LLFolderType::FT_ROOT_INVENTORY == preferred_type) + { + rv = root_id; + } + else if (root_id.notNull()) + { + cat_array_t* cats = NULL; + cats = get_ptr_in_map(mParentChildCategoryTree, root_id); + if (cats) + { + S32 count = cats->size(); + for (S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* p_cat = cats->at(i); + if (p_cat && p_cat->getPreferredType() == preferred_type) + { + const LLUUID& folder_id = cats->at(i)->getUUID(); + if (rv.isNull() || folder_id < rv) + { + rv = folder_id; + } + } + } + } + } + + if (rv.isNull() && root_id.notNull()) + { + + if (isInventoryUsable()) + { + createNewCategory( + root_id, + preferred_type, + LLStringUtil::null, + [preferred_type](const LLUUID &new_cat_id) + { + LL_DEBUGS("Inventory") << "Created category: " << new_cat_id + << " for type: " << preferred_type << LL_ENDL; + } + ); + } + else + { + LL_WARNS("Inventory") << "Can't create requested folder, type " << preferred_type + << " because inventory is not usable" << LL_ENDL; + } + } +} + const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( LLFolderType::EType preferred_type, - bool create_folder, - const LLUUID& root_id) + const LLUUID& root_id) const { LLUUID rv = LLUUID::null; if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) @@ -836,18 +889,14 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( } } - if(rv.isNull() && create_folder && root_id.notNull()) + if(rv.isNull() && root_id.notNull() && preferred_type != LLFolderType::FT_MARKETPLACE_LISTINGS) { - - if (isInventoryUsable()) - { - return createNewCategory(root_id, preferred_type, LLStringUtil::null); - } - else - { - LL_WARNS("Inventory") << "Can't create requested folder, type " << preferred_type - << " because inventory is not usable" << LL_ENDL; - } + // if it does not exists, it should either be added + // to createCommonSystemCategories or server should + // have set it + llassert(false); + LL_WARNS("Inventory") << "Tried to find folder, type " << preferred_type + << " but category does not exist" << LL_ENDL; } return rv; } @@ -856,12 +905,12 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( // specifies 'type' as what it defaults to containing. The category is // not necessarily only for that type. *NOTE: This will create a new // inventory category on the fly if one does not exist. -const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder) +const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type) const { - return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getRootFolderID()); + return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getRootFolderID()); } -const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) +const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const { LLUUID cat_id; switch (preferred_type) @@ -892,14 +941,14 @@ const LLUUID LLInventoryModel::findUserDefinedCategoryUUIDForType(LLFolderType:: if (cat_id.isNull() || !getCategory(cat_id)) { - cat_id = findCategoryUUIDForTypeInRoot(preferred_type, true, getRootFolderID()); + cat_id = findCategoryUUIDForTypeInRoot(preferred_type, getRootFolderID()); } return cat_id; } -const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder) +const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type) const { - return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID()); + return findCategoryUUIDForTypeInRoot(preferred_type, gInventory.getLibraryRootFolderID()); } // Convenience function to create a new category. You could call @@ -1556,7 +1605,7 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 mask |= LLInventoryObserver::LABEL; } // Under marketplace, category labels are quite complex and need extra upate - const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplace_id.notNull() && isObjectDescendentOf(cat->getUUID(), marketplace_id)) { mask |= LLInventoryObserver::LABEL; @@ -2881,7 +2930,7 @@ void LLInventoryModel::buildParentChildMap() } } - const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE) != LLUUID::null); + const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) != LLUUID::null); sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); @@ -3101,14 +3150,14 @@ LLCore::HttpHandle LLInventoryModel::requestPost(bool foreground, void LLInventoryModel::createCommonSystemCategories() { - gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH,true); - gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true); - gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD,true); - gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS,true); - gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, true); - gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, true); // folder should exist before user tries to 'landmark this' - gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS, true); - gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, true); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_TRASH); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_FAVORITE); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CALLINGCARD); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MY_OUTFITS); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_LANDMARK); // folder should exist before user tries to 'landmark this' + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_SETTINGS); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_INBOX); } struct LLUUIDAndName diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index b03181d646..1fde5a3b2f 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -303,24 +303,25 @@ public: // Find //-------------------------------------------------------------------- public: + + // Checks if category exists (My Inventory only), if it does not, creates it + void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred_type); + const LLUUID findCategoryUUIDForTypeInRoot( LLFolderType::EType preferred_type, - bool create_folder, - const LLUUID& root_id); + const LLUUID& root_id) const; // Returns the uuid of the category that specifies 'type' as what it // defaults to containing. The category is not necessarily only for that type. // NOTE: If create_folder is true, this will create a new inventory category // on the fly if one does not exist. *NOTE: if find_in_library is true it // will search in the user's library folder instead of "My Inventory" - const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type, - bool create_folder = true); + const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type) const; // will search in the user's library folder instead of "My Inventory" - const LLUUID findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, - bool create_folder = true); + const LLUUID findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type) const; // Returns user specified category for uploads, returns default id if there are no // user specified one or it does not exist, creates default category if it is missing. - const LLUUID findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type); + const LLUUID findUserDefinedCategoryUUIDForType(LLFolderType::EType preferred_type) const; // Get whatever special folder this object is a child of, if any. const LLViewerInventoryCategory *getFirstNondefaultParent(const LLUUID& obj_id) const; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 037dda70f0..7d4abab98f 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -745,7 +745,7 @@ LLUUID LLInventoryPanel::getRootFolderID() LLStringExplicit label(mParams.start_folder.name()); setLabel(label); - root_id = gInventory.findCategoryUUIDForType(preferred_type, false); + root_id = gInventory.findCategoryUUIDForType(preferred_type); if (root_id.isNull()) { LL_WARNS() << "Could not find folder of type " << preferred_type << LL_ENDL; diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 2d726409c6..5b86f2cc4b 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -897,7 +897,7 @@ void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot // Get/Post/Put requests to the SLM Server using the SLM API void LLMarketplaceData::getSLMListings() { - const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); setUpdating(marketplaceFolderId, true); LLCoros::instance().launch("getSLMListings", @@ -1804,7 +1804,7 @@ bool LLMarketplaceData::isUpdating(const LLUUID& folder_id, S32 depth) } else { - const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); std::set::iterator it = mPendingUpdateSet.find(marketplace_listings_uuid); if (it != mPendingUpdateSet.end()) { diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index 531073526b..2274937ea5 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -87,7 +87,7 @@ BOOL LLPanelOutfitsInventory::postBuild() // ( This is only necessary if we want to show a warning if a user deletes an item that has a // a link in an outfit, see "ConfirmItemDeleteHasLinks". ) - const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); if (outfits_cat.notNull()) { LLInventoryModelBackgroundFetch::instance().start(outfits_cat); diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp index cfceefed26..de0330588b 100644 --- a/indra/newview/llsidepanelinventory.cpp +++ b/indra/newview/llsidepanelinventory.cpp @@ -221,7 +221,7 @@ void LLSidepanelInventory::updateInbox() // // Track inbox folder changes // - const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, true); + const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); // Set up observer to listen for creation of inbox if it doesn't exist if (inbox_id.isNull()) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 6883ead5ee..776b9f8279 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2768,7 +2768,7 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, // Not going through the processAgentInitialWearables path, so need to set this here. LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); // Initiate creation of COF, since we're also bypassing that. - gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_CURRENT_OUTFIT); ESex gender; if (gender_name == "male") diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index b16b26b96e..d10b999220 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -764,7 +764,7 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop, if (!handled) { // Disallow drag and drop to 3D from the marketplace - const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplacelistings_id.notNull()) { for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++) @@ -1732,7 +1732,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( return ACCEPT_NO; } - const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX); if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id)) { // Legacy @@ -2159,7 +2159,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( return ACCEPT_NO; } - const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX); if(gInventory.isObjectDescendentOf(category->getUUID(), outbox_id)) { // Legacy diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 015a887e9f..4c51b58474 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -403,14 +403,14 @@ void set_merchant_SLM_menu() LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings"); gToolBarView->enableCommand(command->id(), true); - const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); if (marketplacelistings_id.isNull()) { U32 mkt_status = LLMarketplaceData::instance().getSLMStatus(); bool is_merchant = (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) || (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT); if (is_merchant) { - gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true); + gInventory.ensureCategoryForTypeExists(LLFolderType::FT_MARKETPLACE_LISTINGS); LL_WARNS("SLM") << "Creating the marketplace listings folder for a merchant" << LL_ENDL; } } From ff6ff01c6a3822c8160279fecd3c3f2e636c4349 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 10 Mar 2023 00:12:16 +0200 Subject: [PATCH 07/31] SL-18629 Replacing UDP creation messages with callback based AIS --- indra/newview/llaisapi.cpp | 17 +- .../newview/llfloatermarketplacelistings.cpp | 7 +- indra/newview/llinventorybridge.cpp | 131 ++++++---- indra/newview/llinventoryfunctions.cpp | 231 +++++++++++++----- indra/newview/llinventoryfunctions.h | 47 +++- indra/newview/llinventorymodel.cpp | 110 ++++----- indra/newview/llinventorymodel.h | 2 +- indra/newview/llmarketplacefunctions.cpp | 6 +- 8 files changed, 370 insertions(+), 181 deletions(-) diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index d2c59cfaba..3826da0341 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -93,6 +93,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c if (cap.empty()) { LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + callback(LLUUID::null); return; } @@ -485,13 +486,17 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht { LLUUID id(LLUUID::null); - if (result.has("category_id") && (type == COPYLIBRARYCATEGORY)) + if (type == COPYLIBRARYCATEGORY) { - id = result["category_id"]; + if (result.has("category_id")) + { + id = result["category_id"]; + } //else signal failure callback(id); } if (type == CREATEINVENTORY) { + bool informed_caller = false; if (result.has("_created_categories")) { LLSD& cats = result["_created_categories"]; @@ -500,6 +505,7 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht { LLUUID cat_id = *cat_iter; callback(cat_id); + informed_caller = true; } } if (result.has("_created_items")) @@ -510,8 +516,15 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht { LLUUID item_id = *item_iter; callback(item_id); + informed_caller = true; } } + + if (!informed_caller) + { + // signal failure with null id + callback(id); + } } } diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index 9110d9e902..b547150b56 100644 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -896,8 +896,11 @@ void LLFloaterMarketplaceValidation::onOpen(const LLSD& key) // Validates the folder if (cat_id.notNull()) { - LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); - validate_marketplacelistings(cat, boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3), false); + LLMarketplaceValidator::getInstance()->validateMarketplaceListings( + cat_id, + NULL, + boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3), + false); } // Handle the listing folder being processed diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index fb92437c3d..b4d7762613 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2901,11 +2901,16 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid); if (version_folder_id.notNull()) { - LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id); - if (!validate_marketplacelistings(cat,NULL)) + LLMarketplaceValidator::getInstance()->validateMarketplaceListings( + version_folder_id, + [version_folder_id](bool result) { - LLMarketplaceData::instance().activateListing(version_folder_id,false); + if (!result) + { + LLMarketplaceData::instance().activateListing(version_folder_id, false); + } } + ); } // In all cases, update the listing we moved from so suffix are updated update_marketplace_category(from_folder_uuid); @@ -3371,18 +3376,26 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) if (depth_nesting_in_marketplace(mUUID) == 1) { LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(mUUID); - LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id); mMessage = ""; - if (!validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3))) + + LLMarketplaceValidator::getInstance()->validateMarketplaceListings( + version_folder_id, + [this, version_folder_id](bool result) { - LLSD subs; - subs["[ERROR_CODE]"] = mMessage; - LLNotificationsUtil::add("MerchantListingFailed", subs); - } - else - { - LLMarketplaceData::instance().activateListing(mUUID,true); - } + // todo: might need to ensure bridge/mUUID exists or this will cause crashes + if (!result) + { + LLSD subs; + subs["[ERROR_CODE]"] = mMessage; + LLNotificationsUtil::add("MerchantListingFailed", subs); + } + else + { + LLMarketplaceData::instance().activateListing(mUUID, true); + } + }, + boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3) + ); } return; } @@ -3390,18 +3403,27 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) { if (depth_nesting_in_marketplace(mUUID) == 2) { - LLInventoryCategory* category = gInventory.getCategory(mUUID); mMessage = ""; - if (!validate_marketplacelistings(category,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false,2)) + + LLMarketplaceValidator::getInstance()->validateMarketplaceListings( + mUUID, + [this](bool result) { - LLSD subs; - subs["[ERROR_CODE]"] = mMessage; - LLNotificationsUtil::add("MerchantFolderActivationFailed", subs); - } - else - { - LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID); - } + if (!result) + { + LLSD subs; + subs["[ERROR_CODE]"] = mMessage; + LLNotificationsUtil::add("MerchantFolderActivationFailed", subs); + } + else + { + LLInventoryCategory* category = gInventory.getCategory(mUUID); + LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID); + } + }, + boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3), + false, + 2); } return; } @@ -3424,29 +3446,44 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) } else if ("marketplace_create_listing" == action) { - LLViewerInventoryCategory* cat = gInventory.getCategory(mUUID); mMessage = ""; - bool validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false); - if (!validates) + + // first run vithout fix_hierarchy, second run with fix_hierarchy + LLMarketplaceValidator::getInstance()->validateMarketplaceListings( + mUUID, + [this](bool result) { - mMessage = ""; - validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),true); - if (validates) + if (!result) { - LLNotificationsUtil::add("MerchantForceValidateListing"); + mMessage = ""; + + LLMarketplaceValidator::getInstance()->validateMarketplaceListings( + mUUID, + [this](bool result) + { + if (result) + { + LLNotificationsUtil::add("MerchantForceValidateListing"); + LLMarketplaceData::instance().createListing(mUUID); + } + else + { + LLSD subs; + subs["[ERROR_CODE]"] = mMessage; + LLNotificationsUtil::add("MerchantListingFailed", subs); + } + }, + boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3), + true); } - } + else + { + LLMarketplaceData::instance().createListing(mUUID); + } + }, + boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3), + false); - if (!validates) - { - LLSD subs; - subs["[ERROR_CODE]"] = mMessage; - LLNotificationsUtil::add("MerchantListingFailed", subs); - } - else - { - LLMarketplaceData::instance().createListing(mUUID); - } return; } else if ("marketplace_disassociate_listing" == action) @@ -5296,11 +5333,15 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid); if (version_folder_id.notNull()) { - LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id); - if (!validate_marketplacelistings(cat,NULL)) + LLMarketplaceValidator::getInstance()->validateMarketplaceListings( + version_folder_id, + [version_folder_id](bool result) { - LLMarketplaceData::instance().activateListing(version_folder_id,false); - } + if (!result) + { + LLMarketplaceData::instance().activateListing(version_folder_id, false); + } + }); } } diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 6b406c4c9c..5975cb982b 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -1492,7 +1492,7 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU // Reparent the folder gInventory.changeCategoryParent(viewer_inv_cat, dest_folder, false); // Check the destination folder recursively for no copy items and promote the including folders if any - validate_marketplacelistings(dest_cat); + LLMarketplaceValidator::getInstance()->validateMarketplaceListings(dest_folder); } // Update the modified folders @@ -1517,32 +1517,23 @@ bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCa return cat1->getName().compare(cat2->getName()) < 0; } -void dump_trace(std::string& message, S32 depth, LLError::ELevel log_level) -{ - LL_INFOS() << "validate_marketplacelistings : error = "<< log_level << ", depth = " << depth << ", message = " << message << LL_ENDL; -} - // Make all relevant business logic checks on the marketplace listings starting with the folder as argument. // This function does no deletion of listings but a mere audit and raises issues to the user (through the -// optional callback cb). It also returns a boolean, true if things validate, false if issues are raised. +// optional callback cb). // The only inventory changes that are done is to move and sort folders containing no-copy items to stock folders. -bool validate_marketplacelistings( +// @pending_callbacks - how many callbacks we are waiting for, must be inited before use +// @result - true if things validate, false if issues are raised, must be inited before use +typedef boost::function validation_result_callback_t; +void validate_marketplacelistings( LLInventoryCategory* cat, - validation_callback_t cb, + validation_result_callback_t cb_result, + LLMarketplaceValidator::validation_msg_callback_t cb_msg, bool fix_hierarchy, S32 depth, - bool notify_observers) + bool notify_observers, + S32 &pending_callbacks, + bool &result) { -#if 0 - // Used only for debug - if (!cb) - { - cb = boost::bind(&dump_trace, _1, _2, _3); - } -#endif - // Folder is valid unless issue is raised - bool result = true; - // Get the type and the depth of the folder LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (cat); const LLFolderType::EType folder_type = cat->getPreferredType(); @@ -1574,10 +1565,10 @@ bool validate_marketplacelistings( if (!can_move_folder_to_marketplace(cat, cat, cat, message, 0, fix_hierarchy)) { result = false; - if (cb) + if (cb_msg) { message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + message; - cb(message,depth,LLError::LEVEL_ERROR); + cb_msg(message,depth,LLError::LEVEL_ERROR); } } } @@ -1587,26 +1578,42 @@ bool validate_marketplacelistings( { if (fix_hierarchy) { - if (cb) + if (cb_msg) { std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning") + " " + LLTrans::getString("Marketplace Validation Warning Stock"); - cb(message,depth,LLError::LEVEL_WARN); + cb_msg(message,depth,LLError::LEVEL_WARN); } + // Nest the stock folder one level deeper in a normal folder and restart from there + pending_callbacks++; LLUUID parent_uuid = cat->getParentUUID(); - LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, LLFolderType::FT_NONE, cat->getName()); - LLInventoryCategory* new_cat = gInventory.getCategory(folder_uuid); - gInventory.changeCategoryParent(viewer_cat, folder_uuid, false); - result &= validate_marketplacelistings(new_cat, cb, fix_hierarchy, depth + 1, notify_observers); - return result; + LLUUID cat_uuid = cat->getUUID(); + gInventory.createNewCategory(parent_uuid, + LLFolderType::FT_NONE, + cat->getName(), + [cat_uuid, cb_result, cb_msg, fix_hierarchy, depth, notify_observers](const LLUUID &new_cat_id) + { + LLInventoryCategory * move_cat = gInventory.getCategory(cat_uuid); + LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *)(move_cat); + LLInventoryCategory * new_cat = gInventory.getCategory(new_cat_id); + gInventory.changeCategoryParent(viewer_cat, new_cat_id, false); + S32 pending = 0; + bool result = true; + // notify_observers probably should be true in such case? + validate_marketplacelistings(new_cat, cb_result, cb_msg, fix_hierarchy, depth + 1, notify_observers, pending, result); + cb_result(pending, result); + } + ); + result = false; + return; } else { result = false; - if (cb) + if (cb_msg) { std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + LLTrans::getString("Marketplace Validation Warning Stock"); - cb(message,depth,LLError::LEVEL_ERROR); + cb_msg(message,depth,LLError::LEVEL_ERROR); } } } @@ -1637,10 +1644,10 @@ bool validate_marketplacelistings( if (!can_move_to_marketplace(item, error_msg, false)) { has_bad_items = true; - if (cb && fix_hierarchy) + if (cb_msg && fix_hierarchy) { std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg; - cb(message,depth,LLError::LEVEL_ERROR); + cb_msg(message,depth,LLError::LEVEL_ERROR); } continue; } @@ -1671,35 +1678,35 @@ bool validate_marketplacelistings( if (depth == 2) { // If this is an empty version folder, warn only (listing won't be delivered by AIS, but only AIS should unlist) - if (cb) + if (cb_msg) { std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Version"); - cb(message,depth,LLError::LEVEL_WARN); + cb_msg(message,depth,LLError::LEVEL_WARN); } } else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2)) { // If this is a legit but empty stock folder, warn only (listing must stay searchable when out of stock) - if (cb) + if (cb_msg) { std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Stock"); - cb(message,depth,LLError::LEVEL_WARN); + cb_msg(message,depth,LLError::LEVEL_WARN); } } - else if (cb) + else if (cb_msg) { // We warn if there's nothing in a regular folder (may be it's an under construction listing) std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning Empty"); - cb(message,depth,LLError::LEVEL_WARN); + cb_msg(message,depth,LLError::LEVEL_WARN); } } else { // Done with that folder : Print out the folder name unless we already found an error here - if (cb && result && (depth >= 1)) + if (cb_msg && result && (depth >= 1)) { std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log"); - cb(message,depth,LLError::LEVEL_INFO); + cb_msg(message,depth,LLError::LEVEL_INFO); } } } @@ -1707,10 +1714,10 @@ bool validate_marketplacelistings( else if ((count == 1) && !has_bad_items && (((unique_key == default_key) && (depth > 1)) || ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2) && (cat_array->size() == 0)))) { // Done with that folder : Print out the folder name unless we already found an error here - if (cb && result && (depth >= 1)) + if (cb_msg && result && (depth >= 1)) { std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log"); - cb(message,depth,LLError::LEVEL_INFO); + cb_msg(message,depth,LLError::LEVEL_INFO); } } else @@ -1732,11 +1739,11 @@ bool validate_marketplacelistings( while (items_vector_it != items_vector.end()) { // Create a new folder - LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID()); + const LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID()); LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back()); std::string folder_name = (depth >= 1 ? viewer_cat->getName() : viewer_inv_item->getName()); LLFolderType::EType new_folder_type = (items_vector_it->first == default_key ? LLFolderType::FT_NONE : LLFolderType::FT_MARKETPLACE_STOCK); - if (cb) + if (cb_msg) { std::string message = ""; if (new_folder_type == LLFolderType::FT_MARKETPLACE_STOCK) @@ -1747,24 +1754,31 @@ bool validate_marketplacelistings( { message = indent + folder_name + LLTrans::getString("Marketplace Validation Warning Create Version"); } - cb(message,depth,LLError::LEVEL_WARN); + cb_msg(message,depth,LLError::LEVEL_WARN); } - std::vector &uuid_vector = items_vector_it->second; + + pending_callbacks++; + std::vector uuid_vector = items_vector_it->second; // needs to be a copy for lambda gInventory.createNewCategory( parent_uuid, new_folder_type, folder_name, - [uuid_vector, cb, indent, depth, parent_uuid, notify_observers](const LLUUID &new_category_id) + [uuid_vector, cb_result, cb_msg, depth, parent_uuid, notify_observers](const LLUUID &new_category_id) { // Move each item to the new folder - std::vector::reverse_iterator iter = uuid_vector.rbegin(); + std::vector::const_reverse_iterator iter = uuid_vector.rbegin(); while (iter != uuid_vector.rend()) { LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(*iter); - if (cb) + if (cb_msg) { + std::string indent; + for (int i = 1; i < depth; i++) + { + indent += " "; + } std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move"); - cb(message, depth, LLError::LEVEL_WARN); + cb_msg(message, depth, LLError::LEVEL_WARN); } gInventory.changeItemParent(viewer_inv_item, new_category_id, true); iter++; @@ -1777,6 +1791,7 @@ bool validate_marketplacelistings( { gInventory.notifyObservers(); } + cb_result(0, true); } ); items_vector_it++; @@ -1792,11 +1807,11 @@ bool validate_marketplacelistings( { LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (*iter); gInventory.changeCategoryParent(viewer_cat, parent_uuid, false); - result &= validate_marketplacelistings(viewer_cat, cb, fix_hierarchy, depth, false); + validate_marketplacelistings(viewer_cat, cb_result, cb_msg, fix_hierarchy, depth, false, pending_callbacks, result); } } } - else if (cb) + else if (cb_msg) { // We are not fixing the hierarchy but reporting problems, report everything we can find // Print the folder name @@ -1807,20 +1822,20 @@ bool validate_marketplacelistings( // Report if a stock folder contains a mix of items result = false; std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Mixed Stock"); - cb(message,depth,LLError::LEVEL_ERROR); + cb_msg(message,depth,LLError::LEVEL_ERROR); } else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (cat_array->size() != 0)) { // Report if a stock folder contains subfolders result = false; std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Subfolder In Stock"); - cb(message,depth,LLError::LEVEL_ERROR); + cb_msg(message,depth,LLError::LEVEL_ERROR); } else { // Simply print the folder name std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log"); - cb(message,depth,LLError::LEVEL_INFO); + cb_msg(message,depth,LLError::LEVEL_INFO); } } // Scan each item and report if there's a problem @@ -1835,21 +1850,21 @@ bool validate_marketplacelistings( // Report items that shouldn't be there to start with result = false; std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg; - cb(message,depth,LLError::LEVEL_ERROR); + cb_msg(message,depth,LLError::LEVEL_ERROR); } else if ((!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) && (folder_type != LLFolderType::FT_MARKETPLACE_STOCK)) { // Report stock items that are misplaced result = false; std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error Stock Item"); - cb(message,depth,LLError::LEVEL_ERROR); + cb_msg(message,depth,LLError::LEVEL_ERROR); } else if (depth == 1) { // Report items not wrapped in version folder result = false; std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Unwrapped Item"); - cb(message,depth,LLError::LEVEL_ERROR); + cb_msg(message,depth,LLError::LEVEL_ERROR); } } } @@ -1858,17 +1873,18 @@ bool validate_marketplacelistings( if (viewer_cat->getDescendentCount() == 0) { // Remove the current folder if it ends up empty - if (cb) + if (cb_msg) { std::string message = indent + viewer_cat->getName() + LLTrans::getString("Marketplace Validation Warning Delete"); - cb(message,depth,LLError::LEVEL_WARN); + cb_msg(message,depth,LLError::LEVEL_WARN); } gInventory.removeCategory(cat->getUUID()); if (notify_observers) { gInventory.notifyObservers(); } - return result && !has_bad_items; + result &=!has_bad_items; + return; } } @@ -1881,15 +1897,15 @@ bool validate_marketplacelistings( for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { LLInventoryCategory* category = *iter; - result &= validate_marketplacelistings(category, cb, fix_hierarchy, depth + 1, false); + validate_marketplacelistings(category, cb_result, cb_msg, fix_hierarchy, depth + 1, false, pending_callbacks, result); } - + update_marketplace_category(cat->getUUID(), true, true); if (notify_observers) { gInventory.notifyObservers(); } - return result && !has_bad_items; + result &= !has_bad_items; } void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id) @@ -1989,9 +2005,92 @@ void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::st inventory_func_type func = boost::bind(&move_items_to_folder, _1, selected_uuids); gInventory.createNewCategory(first_item->getParentUUID(), LLFolderType::FT_NONE, folder_name, func); - } +///---------------------------------------------------------------------------- +/// LLMarketplaceValidator implementations +///---------------------------------------------------------------------------- + + +LLMarketplaceValidator::LLMarketplaceValidator() +{ +} +LLMarketplaceValidator::~LLMarketplaceValidator() +{ +} + +void LLMarketplaceValidator::validateMarketplaceListings( + const LLUUID &category_id, + LLMarketplaceValidator::validation_done_callback_t cb_done, + LLMarketplaceValidator::validation_msg_callback_t cb_msg, + bool fix_hierarchy, + S32 depth) +{ + + mValidationQueue.emplace(category_id, cb_done, cb_msg, fix_hierarchy, depth); + if (!mValidationInProgress) + { + start(); + } +} + +void LLMarketplaceValidator::start() +{ + if (mValidationQueue.empty()) + { + mValidationInProgress = false; + return; + } + mValidationInProgress = true; + mPendingCallbacks = 1; // do '1' in case something decides ro callback immediately + const ValidationRequest &first = mValidationQueue.front(); + LLViewerInventoryCategory* cat = gInventory.getCategory(first.mCategoryId); + + validation_result_callback_t result_callback = [](S32 pending, bool result) + { + LLMarketplaceValidator* validator = LLMarketplaceValidator::getInstance(); + validator->mPendingCallbacks--; // we just got a callback + validator->mPendingCallbacks += pending; + validator->mPendingResult &= result; + if (validator->mPendingCallbacks <= 0) + { + llassert(validator->mPendingCallbacks == 0); // shouldn't be below 0 + const ValidationRequest &first = validator->mValidationQueue.front(); + if (first.mCbDone) + { + first.mCbDone(validator->mPendingResult); + } + validator->mValidationQueue.pop(); // done; + validator->start(); + } + }; + + validate_marketplacelistings( + cat, + result_callback, + first.mCbMsg, + first.mFixHierarchy, + first.mDepth, + true, + mPendingCallbacks, + mPendingResult); + + result_callback(mPendingCallbacks, mPendingResult); +} + +LLMarketplaceValidator::ValidationRequest::ValidationRequest( + LLUUID category_id, + validation_done_callback_t cb_done, + validation_msg_callback_t cb_msg, + bool fix_hierarchy, + S32 depth) +: mCategoryId(category_id) +, mCbDone(cb_done) +, mCbMsg(cb_msg) +, mFixHierarchy(fix_hierarchy) +, mDepth(depth) +{} + ///---------------------------------------------------------------------------- /// LLInventoryCollectFunctor implementations ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 56ad6f6496..ec5e53f9a6 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -81,13 +81,12 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode // Generates a string containing the path to the item specified by item_id. void append_path(const LLUUID& id, std::string& path); -typedef boost::function validation_callback_t; bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false); bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size = 1, bool check_items = true, bool from_paste = false); bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy = false); bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, bool copy = false, bool move_no_copy_items = false); -bool validate_marketplacelistings(LLInventoryCategory* inv_cat, validation_callback_t cb = NULL, bool fix_hierarchy = true, S32 depth = -1, bool notify_observers = true); + S32 depth_nesting_in_marketplace(LLUUID cur_uuid); LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth); S32 compute_stock_count(LLUUID cat_uuid, bool force_count = false); @@ -102,6 +101,50 @@ bool is_only_items_selected(const uuid_vec_t& selected_uuids); ** ** *******************************************************************************/ +class LLMarketplaceValidator: public LLSingleton +{ + LLSINGLETON(LLMarketplaceValidator); + ~LLMarketplaceValidator(); + LOG_CLASS(LLMarketplaceValidator); +public: + + typedef boost::function validation_msg_callback_t; + typedef boost::function validation_done_callback_t; + + void validateMarketplaceListings( + const LLUUID &category_id, + validation_done_callback_t cb_done = NULL, + validation_msg_callback_t cb_msg = NULL, + bool fix_hierarchy = true, + S32 depth = -1); + +private: + void start(); + + class ValidationRequest + { + public: + ValidationRequest( + LLUUID category_id, + validation_done_callback_t cb_done, + validation_msg_callback_t cb_msg, + bool fix_hierarchy, + S32 depth); + LLUUID mCategoryId; + validation_done_callback_t mCbDone; + validation_msg_callback_t mCbMsg; + bool mFixHierarchy; + S32 mDepth; + }; + + bool mValidationInProgress; + S32 mPendingCallbacks; + bool mPendingResult; + // todo: might be a good idea to memorize requests by id and + // filter out ones that got multiple validation requests + std::queue mValidationQueue; +}; + /******************************************************************************** ** ** ** INVENTORY COLLECTOR FUNCTIONS diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index b2cfc8584e..774ed051c0 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -954,27 +954,23 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp // Convenience function to create a new category. You could call // updateCategory() with a newly generated UUID category, but this // version will take care of details like what the name should be -// based on preferred type. Returns the UUID of the new category. -// -// On failure, returns a null UUID. -// FIXME: callers do not check for or handle a null results currently. -LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, +// based on preferred type. +void LLInventoryModel::createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, const std::string& pname, inventory_func_type callback) { - LLUUID id; // Initially null. if (!isInventoryUsable()) { LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " << preferred_type << LL_ENDL; - return id; + return; } if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) { LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; - return id; + return; } if (preferred_type != LLFolderType::FT_NONE) @@ -990,24 +986,53 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, { name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); } - + #ifdef USE_AIS_FOR_NC - // D567 currently this doesn't really work due to limitations in - // AIS3, also violates the common caller assumption that we can - // assign the id and return immediately. - if (callback) + // D567 currently this doesn't really work due to limitations in + // AIS3, also violates the common caller assumption that we can + // assign the id and return immediately. + if (callback && AISAPI::isAvailable()) { - // D567 note that we no longer assign the UUID in the viewer, so various workflows need to change. LLSD new_inventory = LLSD::emptyMap(); new_inventory["categories"] = LLSD::emptyArray(); LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID()); LLSD cat_sd = cat.asLLSD(); new_inventory["categories"].append(cat_sd); - AISAPI::CreateInventory(parent_id, new_inventory, callback); + AISAPI::CreateInventory( + parent_id, + new_inventory, + [this, callback, parent_id, preferred_type, name] (const LLUUID& new_category) + { + if (new_category.isNull()) + { + callback(new_category); + return; + } - return LLUUID::null; + LLViewerInventoryCategory* folderp = gInventory.getCategory(new_category); + if (!folderp) + { + // Add the category to the internal representation + LLPointer cat = new LLViewerInventoryCategory( + new_category, + parent_id, + preferred_type, + name, + gAgent.getID()); + + LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); + accountForUpdate(update); + + cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 + cat->setDescendentCount(0); + updateCategory(cat); + } + + callback(new_category); + }); + return; } -#else +#endif LLViewerRegion* viewer_region = gAgent.getRegion(); std::string url; if ( viewer_region ) @@ -1016,7 +1041,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, if (!url.empty() && callback) { //Let's use the new capability. - + LLUUID id; id.generate(); LLSD request, body; body["folder_id"] = id; @@ -1030,48 +1055,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL; LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro", boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback)); - - return LLUUID::null; } -#endif - - - if (!gMessageSystem) - { - return LLUUID::null; - } - - // D567 FIXME this UDP code path needs to be removed. Requires - // reworking many of the callers to use callbacks rather than - // assuming instant success. - - // Add the category to the internal representation - LL_WARNS() << "D567 need to remove this usage" << LL_ENDL; - - id.generate(); - LLPointer cat = - new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); - cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 - cat->setDescendentCount(0); - LLCategoryUpdate update(cat->getParentUUID(), 1); - accountForUpdate(update); - updateCategory(cat); - - LL_DEBUGS(LOG_INV) << "Creating category via UDP message CreateInventoryFolder, type " << preferred_type << LL_ENDL; - - // Create the category on the server. We do this to prevent people - // from munging their protected folders. - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("CreateInventoryFolder"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlock("FolderData"); - cat->packMessage(msg); - gAgent.sendReliableMessage(); - - // return the folder id of the newly created folder - return id; } void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback) @@ -1095,12 +1079,20 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv if (!status) { LL_WARNS() << "HTTP failure attempting to create category." << LL_ENDL; + if (callback) + { + callback(LLUUID::null); + } return; } if (!result.has("folder_id")) { LL_WARNS() << "Malformed response contents" << ll_pretty_print_sd(result) << LL_ENDL; + if (callback) + { + callback(LLUUID::null); + } return; } diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 1fde5a3b2f..5f8db30390 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -477,7 +477,7 @@ public: public: // Returns the UUID of the new category. If you want to use the default // name based on type, pass in a NULL to the 'name' parameter. - LLUUID createNewCategory(const LLUUID& parent_id, + void createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, const std::string& name, inventory_func_type callback = NULL); diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 5b86f2cc4b..4038afc74c 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -700,10 +700,9 @@ void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata) // If it's a folder known to the marketplace, let's check it's in proper shape if (LLMarketplaceData::instance().isListed(*id_it) || LLMarketplaceData::instance().isVersionFolder(*id_it)) { - LLInventoryCategory* cat = (LLInventoryCategory*)(obj); // can trigger notifyObservers // can cause more structural changes - validate_marketplacelistings(cat); + LLMarketplaceValidator::getInstance()->validateMarketplaceListings(obj->getUUID()); } } else @@ -1848,8 +1847,7 @@ void LLMarketplaceData::decrementValidationWaiting(const LLUUID& folder_id, S32 if (found->second <= 0) { mValidationWaitingList.erase(found); - LLInventoryCategory *cat = gInventory.getCategory(folder_id); - validate_marketplacelistings(cat); + LLMarketplaceValidator::getInstance()->validateMarketplaceListings(folder_id); update_marketplace_category(folder_id); gInventory.notifyObservers(); } From 80b33a015735daf08b8904b3581b3edcce9368d3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 10 Mar 2023 20:15:41 +0200 Subject: [PATCH 08/31] SL-18629 Unpack thumbnail asset id --- indra/llinventory/llinventory.cpp | 56 ++++++++++++++++++++++++++++-- indra/newview/llinventorymodel.cpp | 1 + 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index abe1b4dbd3..db18bd4c0e 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -44,6 +44,7 @@ static const std::string INV_ITEM_ID_LABEL("item_id"); static const std::string INV_FOLDER_ID_LABEL("cat_id"); static const std::string INV_PARENT_ID_LABEL("parent_id"); +static const std::string INV_THUMBNAIL_LABEL("thumbnail"); static const std::string INV_THUMBNAIL_ID_LABEL("thumbnail_id"); static const std::string INV_ASSET_TYPE_LABEL("type"); static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type"); @@ -863,6 +864,34 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) { mParentUUID = sd[w]; } + w = INV_THUMBNAIL_LABEL; + if (sd.has(w)) + { + LLSD thumbnail_map = sd[w]; + w = INV_ASSET_ID_LABEL; + if (thumbnail_map.has(w)) + { + mThumbnailUUID = thumbnail_map[w]; + } + /* + asset_id + acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 + perms + 8 + service + 3 + version + 1 + */ + } + else + { + w = INV_THUMBNAIL_ID_LABEL; + if (sd.has(w)) + { + mThumbnailUUID = sd[w]; + } + } w = INV_PERMISSIONS_LABEL; if (sd.has(w)) { @@ -1071,10 +1100,33 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd) { mParentUUID = sd[w]; } - w = INV_THUMBNAIL_ID_LABEL; + w = INV_THUMBNAIL_LABEL; if (sd.has(w)) { - mThumbnailUUID = sd[w]; + LLSD thumbnail_map = sd[w]; + w = INV_ASSET_ID_LABEL; + if (thumbnail_map.has(w)) + { + mThumbnailUUID = thumbnail_map[w]; + } + /* + asset_id + acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 + perms + 8 + service + 3 + version + 1 + */ + } + else + { + w = INV_THUMBNAIL_ID_LABEL; + if (sd.has(w)) + { + mThumbnailUUID = sd[w]; + } } w = INV_ASSET_TYPE_LABEL; if (sd.has(w)) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 774ed051c0..bfff876c96 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -193,6 +193,7 @@ public: titem->unpackMessage(item); LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " << titem->getParentUUID() << LL_ENDL; + // callback id might be no longer supported U32 callback_id = item["callback_id"].asInteger(); if (titem->getUUID().notNull()) From 91c046b41e5e673ff0bd08d7d8ffcfcb33186b7a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 10 Mar 2023 20:27:05 +0200 Subject: [PATCH 09/31] SL-18629 MacOS build fix --- indra/newview/llinventorymodel.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 5f8db30390..3fbf8924b5 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -304,8 +304,8 @@ public: //-------------------------------------------------------------------- public: - // Checks if category exists (My Inventory only), if it does not, creates it - void LLInventoryModel::ensureCategoryForTypeExists(LLFolderType::EType preferred_type); + // Checks if category exists ("My Inventory" only), if it does not, creates it + void ensureCategoryForTypeExists(LLFolderType::EType preferred_type); const LLUUID findCategoryUUIDForTypeInRoot( LLFolderType::EType preferred_type, From e4de43fe5e640a1d30e78c68b90eefdf87b908e2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 10 Mar 2023 21:30:28 +0200 Subject: [PATCH 10/31] SL-18629 Pack thumbnail asset id --- indra/llinventory/llinventory.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index db18bd4c0e..8904d9fb8a 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -812,6 +812,7 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const sd[INV_ITEM_ID_LABEL] = mUUID; sd[INV_PARENT_ID_LABEL] = mParentUUID; sd[INV_PERMISSIONS_LABEL] = ll_create_sd_from_permissions(mPermissions); + sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); U32 mask = mPermissions.getMaskBase(); if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) @@ -867,13 +868,13 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) w = INV_THUMBNAIL_LABEL; if (sd.has(w)) { - LLSD thumbnail_map = sd[w]; + const LLSD &thumbnail_map = sd[w]; w = INV_ASSET_ID_LABEL; if (thumbnail_map.has(w)) { mThumbnailUUID = thumbnail_map[w]; } - /* + /* Example: asset_id acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 perms @@ -1067,7 +1068,7 @@ LLSD LLInventoryCategory::asLLSD() const LLSD sd = LLSD(); sd["item_id"] = mUUID; sd["parent_id"] = mParentUUID; - sd["thumbnail_id"] = mThumbnailUUID; + sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); S8 type = static_cast(mPreferredType); sd["type"] = type; sd["name"] = mName; @@ -1103,22 +1104,12 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd) w = INV_THUMBNAIL_LABEL; if (sd.has(w)) { - LLSD thumbnail_map = sd[w]; + const LLSD &thumbnail_map = sd[w]; w = INV_ASSET_ID_LABEL; if (thumbnail_map.has(w)) { mThumbnailUUID = thumbnail_map[w]; } - /* - asset_id - acc0ec86 - 17f2 - 4b92 - ab41 - 6718b1f755f7 - perms - 8 - service - 3 - version - 1 - */ } else { @@ -1250,6 +1241,7 @@ LLSD LLInventoryCategory::exportLLSD() const cat_data[INV_PARENT_ID_LABEL] = mParentUUID; cat_data[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(mType); cat_data[INV_PREFERRED_TYPE_LABEL] = LLFolderType::lookup(mPreferredType); + cat_data[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); cat_data[INV_NAME_LABEL] = mName; return cat_data; @@ -1273,6 +1265,14 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data) { setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString())); } + if (cat_data.has(INV_THUMBNAIL_LABEL)) + { + const LLSD &thumbnail_data = cat_data[INV_THUMBNAIL_LABEL]; + if (thumbnail_data.has(INV_ASSET_ID_LABEL)) + { + setThumbnailUUID(thumbnail_data[INV_ASSET_ID_LABEL].asUUID()); + } + } if (cat_data.has(INV_NAME_LABEL)) { mName = cat_data[INV_NAME_LABEL].asString(); From 9d90fbc73df9c07deef8737e56cc3f466d2c4d05 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 10 Mar 2023 22:43:40 +0200 Subject: [PATCH 11/31] SL-18629 LLTask thumbnail packing and unpacking --- indra/llinventory/llinventory.cpp | 79 +++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 8904d9fb8a..c6049f3ec4 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -671,6 +671,26 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) { mType = LLAssetType::lookup(valuestr); } + else if (0 == strcmp("metadata", keyword)) + { + LLSD metadata(valuestr); + if (metadata.has("thumbnail")) + { + const LLSD& thumbnail = metadata["thumbnail"]; + if (thumbnail.has("asset_id")) + { + setThumbnailUUID(thumbnail["asset_id"].asUUID()); + } + else + { + setThumbnailUUID(LLUUID::null); + } + } + else + { + setThumbnailUUID(LLUUID::null); + } + } else if(0 == strcmp("inv_type", keyword)) { mInventoryType = LLInventoryType::lookup(std::string(valuestr)); @@ -760,6 +780,13 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu output_stream << "\t\tparent_id\t" << uuid_str << "\n"; mPermissions.exportLegacyStream(output_stream); + if (mThumbnailUUID.notNull()) + { + LLSD metadata; + metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); + output_stream << "\t\tmetadata\t" << metadata << "|\n"; + } + // Check for permissions to see the asset id, and if so write it // out as an asset id. Otherwise, apply our cheesy encryption. if(include_asset_key) @@ -812,7 +839,11 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const sd[INV_ITEM_ID_LABEL] = mUUID; sd[INV_PARENT_ID_LABEL] = mParentUUID; sd[INV_PERMISSIONS_LABEL] = ll_create_sd_from_permissions(mPermissions); - sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); + + if (mThumbnailUUID.notNull()) + { + sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); + } U32 mask = mPermissions.getMaskBase(); if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) @@ -865,6 +896,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) { mParentUUID = sd[w]; } + mThumbnailUUID.setNull(); w = INV_THUMBNAIL_LABEL; if (sd.has(w)) { @@ -890,7 +922,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) w = INV_THUMBNAIL_ID_LABEL; if (sd.has(w)) { - mThumbnailUUID = sd[w]; + mThumbnailUUID = sd[w].asUUID(); } } w = INV_PERMISSIONS_LABEL; @@ -1068,11 +1100,15 @@ LLSD LLInventoryCategory::asLLSD() const LLSD sd = LLSD(); sd["item_id"] = mUUID; sd["parent_id"] = mParentUUID; - sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); S8 type = static_cast(mPreferredType); sd["type"] = type; sd["name"] = mName; + if (mThumbnailUUID.notNull()) + { + sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); + } + return sd; } @@ -1101,6 +1137,7 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd) { mParentUUID = sd[w]; } + mThumbnailUUID.setNull(); w = INV_THUMBNAIL_LABEL; if (sd.has(w)) { @@ -1210,6 +1247,26 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream) LLStringUtil::replaceNonstandardASCII(mName, ' '); LLStringUtil::replaceChar(mName, '|', ' '); } + else if (0 == strcmp("metadata", keyword)) + { + LLSD metadata(valuestr); + if (metadata.has("thumbnail")) + { + const LLSD& thumbnail = metadata["thumbnail"]; + if (thumbnail.has("asset_id")) + { + setThumbnailUUID(thumbnail["asset_id"].asUUID()); + } + else + { + setThumbnailUUID(LLUUID::null); + } + } + else + { + setThumbnailUUID(LLUUID::null); + } + } else { LL_WARNS() << "unknown keyword '" << keyword @@ -1230,6 +1287,12 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL) output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n"; output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n"; output_stream << "\t\tname\t" << mName.c_str() << "|\n"; + if (mThumbnailUUID.notNull()) + { + LLSD metadata; + metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); + output_stream << "\t\tmetadata\t" << metadata << "|\n"; + } output_stream << "\t}\n"; return TRUE; } @@ -1241,9 +1304,13 @@ LLSD LLInventoryCategory::exportLLSD() const cat_data[INV_PARENT_ID_LABEL] = mParentUUID; cat_data[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(mType); cat_data[INV_PREFERRED_TYPE_LABEL] = LLFolderType::lookup(mPreferredType); - cat_data[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); cat_data[INV_NAME_LABEL] = mName; + if (mThumbnailUUID.notNull()) + { + cat_data[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); + } + return cat_data; } @@ -1265,14 +1332,16 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data) { setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString())); } + LLUUID thumbnail_uuid; if (cat_data.has(INV_THUMBNAIL_LABEL)) { const LLSD &thumbnail_data = cat_data[INV_THUMBNAIL_LABEL]; if (thumbnail_data.has(INV_ASSET_ID_LABEL)) { - setThumbnailUUID(thumbnail_data[INV_ASSET_ID_LABEL].asUUID()); + thumbnail_uuid = thumbnail_data[INV_ASSET_ID_LABEL].asUUID(); } } + setThumbnailUUID(thumbnail_uuid); if (cat_data.has(INV_NAME_LABEL)) { mName = cat_data[INV_NAME_LABEL].asString(); From da27311473c2c2cc35440f88aa25c9378fc8f4d4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 10 Mar 2023 23:55:05 +0200 Subject: [PATCH 12/31] SL-18629 Creare items via AIS placeholder --- indra/newview/llappearancemgr.cpp | 31 ++++---------- indra/newview/llviewerinventory.cpp | 64 +++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 1c55113082..4e36a4c351 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -3996,34 +3996,17 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo // First, make a folder in the My Outfits directory. const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - // D567 replace with coros - if (AISAPI::isAvailable()) - { - // cap-based category creation was buggy until recently. use - // existence of AIS as an indicator the fix is present. Does - // not actually use AIS to create the category. - inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel); - // D567 copy thumbnail info from source folder - gInventory.createNewCategory( - parent_id, - LLFolderType::FT_OUTFIT, - new_folder_name, - func); - } - else - { - // UDP PATH, should remove - // D567 copy thumbnail info from source folder - gInventory.createNewCategory( - parent_id, - LLFolderType::FT_OUTFIT, - new_folder_name, - [show_panel](const LLUUID &new_cat_id) + // UDP PATH, should remove + // D567 copy thumbnail info from source folder + gInventory.createNewCategory( + parent_id, + LLFolderType::FT_OUTFIT, + new_folder_name, + [show_panel](const LLUUID &new_cat_id) { LLAppearanceMgr::getInstance()->onOutfitFolderCreated(new_cat_id, show_panel); }); - } } void LLAppearanceMgr::wearBaseOutfit() diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index d0832e16d7..6f7c5d96f5 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1000,13 +1000,18 @@ void create_notecard_cb(const LLUUID& inv_item) LLInventoryCallbackManager gInventoryCallbacks; -void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, - const LLUUID& parent, const LLTransactionID& transaction_id, - const std::string& name, - const std::string& desc, LLAssetType::EType asset_type, - LLInventoryType::EType inv_type, U8 subtype, - U32 next_owner_perm, - LLPointer cb) +void create_inventory_item( + const LLUUID& agent_id, + const LLUUID& session_id, + const LLUUID& parent_id, + const LLTransactionID& transaction_id, + const std::string& name, + const std::string& desc, + LLAssetType::EType asset_type, + LLInventoryType::EType inv_type, + U8 subtype, + U32 next_owner_perm, + LLPointer cb) { //check if name is equal to one of special inventory items names //EXT-5839 @@ -1027,6 +1032,49 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, } } +#ifdef USE_AIS_FOR_NC + // D567 currently this doesn't work due to missing AIS3 support + if (AISAPI::isAvailable()) + { + LLSD new_inventory = LLSD::emptyMap(); + new_inventory["items"] = LLSD::emptyArray(); + + LLPermissions perms; + perms.init( + gAgentID, + gAgentID, + LLUUID::null, + LLUUID::null); + perms.initMasks( + PERM_ALL, + PERM_ALL, + PERM_NONE, + PERM_NONE, + next_owner_perm); + + LLUUID null_id; + LLPointer item = new LLViewerInventoryItem( + null_id, /*don't know yet*/ + parent_id, + perms, + null_id, /*don't know yet*/ + asset_type, + inv_type, + server_name, + desc, + LLSaleInfo(), + 0, + 0 /*don't know yet, whenever server creates it*/); + LLSD item_sd = item->asLLSD(); + new_inventory["items"].append(item_sd); + AISAPI::CreateInventory( + parent_id, + new_inventory, + nullptr); + return; + } +#endif + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_CreateInventoryItem); msg->nextBlock(_PREHASH_AgentData); @@ -1034,7 +1082,7 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, msg->addUUIDFast(_PREHASH_SessionID, session_id); msg->nextBlock(_PREHASH_InventoryBlock); msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); - msg->addUUIDFast(_PREHASH_FolderID, parent); + msg->addUUIDFast(_PREHASH_FolderID, parent_id); msg->addUUIDFast(_PREHASH_TransactionID, transaction_id); msg->addU32Fast(_PREHASH_NextOwnerMask, next_owner_perm); msg->addS8Fast(_PREHASH_Type, (S8)asset_type); From 0d1f7cafcd9db3ffff8e22f898005dc34bca5fcb Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sat, 11 Mar 2023 13:49:28 +0200 Subject: [PATCH 13/31] SL-19109 Fix item updates not getting a callback --- indra/newview/llaisapi.cpp | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 3826da0341..8e20132ede 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -483,20 +483,17 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht gInventory.onAISUpdateReceived("AISCommand", result); if (callback && !callback.empty()) - { + { + bool needs_callback = true; LLUUID id(LLUUID::null); - if (type == COPYLIBRARYCATEGORY) - { - if (result.has("category_id")) - { - id = result["category_id"]; - } //else signal failure - callback(id); + if (type == COPYLIBRARYCATEGORY && result.has("category_id")) + { + id = result["category_id"]; } if (type == CREATEINVENTORY) { - bool informed_caller = false; + // CREATEINVENTORY can have multiple callbacks if (result.has("_created_categories")) { LLSD& cats = result["_created_categories"]; @@ -505,7 +502,7 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht { LLUUID cat_id = *cat_iter; callback(cat_id); - informed_caller = true; + needs_callback = false; } } if (result.has("_created_items")) @@ -516,17 +513,17 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht { LLUUID item_id = *item_iter; callback(item_id); - informed_caller = true; + needs_callback = false; } } - - if (!informed_caller) - { - // signal failure with null id - callback(id); - } } + if (needs_callback) + { + // Call callback at least once regardless of failure. + // UPDATEITEM doesn't expect an id + callback(id); + } } } From 1699bdbea75c47cf763d8a11078897c37c2599a3 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Sat, 11 Mar 2023 14:05:00 +0200 Subject: [PATCH 14/31] mac build fix --- indra/newview/llfloatermarketplacelistings.cpp | 2 +- indra/newview/llinventorybridge.cpp | 2 +- indra/newview/llinventoryfunctions.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index b547150b56..70c0d2aafd 100644 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -479,7 +479,7 @@ void LLFloaterMarketplaceListings::setRootFolder() gInventory.getRootFolderID(), preferred_type, LLStringUtil::null, - [preferred_type](const LLUUID &new_cat_id) + [](const LLUUID &new_cat_id) { LLFloaterMarketplaceListings *marketplace = LLFloaterReg::findTypedInstance("marketplace_listings"); if (marketplace) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index b4d7762613..421c1c9754 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -3380,7 +3380,7 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) LLMarketplaceValidator::getInstance()->validateMarketplaceListings( version_folder_id, - [this, version_folder_id](bool result) + [this](bool result) { // todo: might need to ensure bridge/mUUID exists or this will cause crashes if (!result) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 5975cb982b..c2e9137910 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -1420,7 +1420,7 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol } }; - std::function callback_dest_create = [copy, item_id, callback_create_stock](const LLUUID& new_cat_id) + std::function callback_dest_create = [item_id, callback_create_stock](const LLUUID& new_cat_id) { LLViewerInventoryCategory* dest_cat = gInventory.getCategory(new_cat_id); LLViewerInventoryItem * viewer_inv_item = gInventory.getItem(item_id); From 3c54d6a0371377f65c8eaa7eafffee0decdf4cbf Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Mon, 13 Mar 2023 12:40:52 +0200 Subject: [PATCH 15/31] SL-19386 Double click to open Single folder view should affect only Inventory --- indra/llui/llfolderviewitem.cpp | 25 +++++++++++-------- indra/llui/llfolderviewitem.h | 4 ++- .../default/xui/en/panel_main_inventory.xml | 9 +++++-- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 6d2c346f76..227f1d79e4 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -114,6 +114,7 @@ LLFolderViewItem::Params::Params() text_pad("text_pad", 0), text_pad_right("text_pad_right", 0), single_folder_mode("single_folder_mode", false), + double_click_override("double_click_override", false), arrow_size("arrow_size", 0), max_folder_item_overlap("max_folder_item_overlap", 0) { } @@ -153,7 +154,8 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mTextPadRight(p.text_pad_right), mArrowSize(p.arrow_size), mSingleFolderMode(p.single_folder_mode), - mMaxFolderItemOverlap(p.max_folder_item_overlap) + mMaxFolderItemOverlap(p.max_folder_item_overlap), + mDoubleClickOverride(p.double_click_override) { if (!sColorSetInitialized) { @@ -2077,16 +2079,19 @@ BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask ) } if( !handled ) { - static LLUICachedControl double_click_action("MultiModeDoubleClickFolder", false); - if (double_click_action == 1) + if(mDoubleClickOverride) { - getViewModelItem()->navigateToFolder(true); - return TRUE; - } - if (double_click_action == 2) - { - getViewModelItem()->navigateToFolder(false, true); - return TRUE; + static LLUICachedControl double_click_action("MultiModeDoubleClickFolder", false); + if (double_click_action == 1) + { + getViewModelItem()->navigateToFolder(true); + return TRUE; + } + if (double_click_action == 2) + { + getViewModelItem()->navigateToFolder(false, true); + return TRUE; + } } if(mIndentation < x && x < mIndentation + (isCollapsed() ? 0 : mArrowSize) + mTextPad) { diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index aa9ed0a1e8..b6437ab61d 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -72,7 +72,8 @@ public: text_pad_right, arrow_size, max_folder_item_overlap; - Optional single_folder_mode; + Optional single_folder_mode, + double_click_override; Params(); }; @@ -123,6 +124,7 @@ protected: mAllowWear, mAllowDrop, mSingleFolderMode, + mDoubleClickOverride, mSelectPending, mIsItemCut; diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml index d400835198..af4511a92d 100644 --- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -235,7 +235,9 @@ sort_order_setting="InventorySortOrder" show_item_link_overlays="true" top="16" - width="288" /> + width="288"> + + + width="290"> + + + From cd61492723866ae9a268820d643976693f42b02a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 13 Mar 2023 15:36:50 +0200 Subject: [PATCH 16/31] SL-19109 Fix item updates not getting a callback #2 --- indra/newview/llinventorymodel.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index bfff876c96..ee0dd2422a 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -965,12 +965,20 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, { LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " << preferred_type << LL_ENDL; + if (callback) + { + callback(LLUUID::null); + } return; } if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) { LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; + if (callback) + { + callback(LLUUID::null); + } return; } @@ -992,7 +1000,7 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, // D567 currently this doesn't really work due to limitations in // AIS3, also violates the common caller assumption that we can // assign the id and return immediately. - if (callback && AISAPI::isAvailable()) + if (AISAPI::isAvailable()) { LLSD new_inventory = LLSD::emptyMap(); new_inventory["categories"] = LLSD::emptyArray(); @@ -1006,7 +1014,10 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, { if (new_category.isNull()) { - callback(new_category); + if (callback) + { + callback(new_category); + } return; } @@ -1029,7 +1040,10 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, updateCategory(cat); } - callback(new_category); + if (callback) + { + callback(new_category); + } }); return; } @@ -1039,7 +1053,7 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, if ( viewer_region ) url = viewer_region->getCapability("CreateInventoryCategory"); - if (!url.empty() && callback) + if (!url.empty()) { //Let's use the new capability. LLUUID id; @@ -1056,7 +1070,13 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL; LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro", boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback)); + return; } + + if (callback) + { + callback(LLUUID::null); // Notify about failure + } } void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback) From f14629e690c31b4fb9381430e288f191ef22d23a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 3 Mar 2023 12:15:09 +0200 Subject: [PATCH 17/31] SL-18629 AISv3 draft calls --- indra/newview/llaisapi.cpp | 181 ++++++++++++++++++++++++++++++++++++- indra/newview/llaisapi.h | 15 ++- 2 files changed, 194 insertions(+), 2 deletions(-) diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 8e20132ede..afc307278c 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -368,6 +368,153 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t EnqueueAISCommand("UpdateItem", proc); } +/*static*/ +void AISAPI::FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callback) +{ + + std::string cap; + + cap = (type == INVENTORY) ? getInvCap() : getLibCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + std::string url = cap + std::string("/item/") + itemId.asString(); + + invokationFn_t patchFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6); + + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, patchFn, url, itemId, LLSD(), callback, FETCHITEM)); + + EnqueueAISCommand("FetchItem", proc); +} + +/*static*/ +void AISAPI::FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type, bool recursive, completion_t callback, S32 depth) +{ + std::string cap; + + cap = (type == INVENTORY) ? getInvCap() : getLibCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + std::string url = cap + std::string("/category/") + catId.asString() + "/children"; + + if (recursive) + { + url += "?depth=*"; + } + else + { + url += "?depth=" + std::to_string(depth); + } + + invokationFn_t patchFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6); + + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, patchFn, url, catId, LLSD(), callback, FETCHCATEGORYCHILDREN)); + + EnqueueAISCommand("FetchCategoryChildren", proc); +} + +/*static*/ +void AISAPI::FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type, bool recursive, completion_t callback, S32 depth) +{ + std::string cap; + + cap = (type == INVENTORY) ? getInvCap() : getLibCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + std::string url = cap + std::string("/category/") + catId.asString() + "/categories"; + + if (recursive) + { + url += "?depth=*"; + } + else + { + url += "?depth=" + std::to_string(depth); + } + + invokationFn_t patchFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6); + + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, patchFn, url, catId, LLSD(), callback, FETCHCATEGORYCATEGORIES)); + + EnqueueAISCommand("FetchCategoryCategories", proc); +} + +/*static*/ +void AISAPI::FetchCOF(completion_t callback) +{ + std::string cap; + cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + + std::string url = cap + std::string("/category/") + cof_id.asString() + "/links"; + + //LLUUID root_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ROOT_INVENTORY); + //std::string url = cap + std::string("/category/") + root_id.asString() + "/children?depth=*"; + + invokationFn_t patchFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6); + + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, patchFn, url, cof_id, LLSD(), callback, FETCHCOF)); + + EnqueueAISCommand("FetchCOF", proc); +} + /*static*/ void AISAPI::EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc) { @@ -427,7 +574,12 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest()); LLCore::HttpHeaders::ptr_t httpHeaders; - httpOptions->setTimeout(LLCoreHttpUtil::HTTP_REQUEST_EXPIRY_SECS); + /*if (type == FETCHCATEGORYCHILDREN && (url.find("?depth=*") != std::string::npos)) + { + LL_WARNS() << "testy test start"<< LL_ENDL; + }*/ + + httpOptions->setTimeout(180); LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; @@ -475,9 +627,36 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht } } } + /*else if (status.getType() == 403) + { + if (type == FETCHCATEGORYCHILDREN) + { + if (url.find("?depth=*") != std::string::npos) + { + LL_WARNS() << "too much" << LL_ENDL; + AISAPI::FetchCategoryChildren(gInventory.getRootFolderID(), AISAPI::ITEM_TYPE::INVENTORY, false, boost::bind(&LLInventoryModel::fetchDescendentsDepthOne, &gInventory, targetId)); + + if (result["oversize_inventory"].asBoolean() == true) + { + LL_WARNS("Inventory") << "Can't fetch the oversized inventory folder" << LL_ENDL; + } + } + else + { + if (result["oversize_inventory"].asBoolean() == true) + { + LL_WARNS("Inventory") << "Can't fetch the oversized inventory folder" << LL_ENDL; + } + } + } + }*/ LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL; LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL; } + else if (type == FETCHCOF) + { + //LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL; + } LL_DEBUGS("Inventory") << result << LL_ENDL; gInventory.onAISUpdateReceived("AISCommand", result); diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index 6e9cc19baa..b21edb9f33 100644 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -38,6 +38,11 @@ class AISAPI { public: + typedef enum { + INVENTORY, + LIBRARY + } ITEM_TYPE; + typedef boost::function completion_t; static bool isAvailable(); @@ -50,6 +55,10 @@ public: static void PurgeDescendents(const LLUUID &categoryId, completion_t callback = completion_t()); static void UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback = completion_t()); static void UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback = completion_t()); + static void FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callback = completion_t()); + static void FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0); + static void FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0); + static void FetchCOF(completion_t callback = completion_t()); static void CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback = completion_t()); private: @@ -62,7 +71,11 @@ private: UPDATECATEGORY, UPDATEITEM, COPYLIBRARYCATEGORY, - CREATEINVENTORY + CREATEINVENTORY, + FETCHITEM, + FETCHCATEGORYCHILDREN, + FETCHCATEGORYCATEGORIES, + FETCHCOF, } COMMAND_TYPE; static const std::string INVENTORY_CAP_NAME; From ac145cb21f382b8eab9f770cecfa23ea9d58aac6 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 14 Mar 2023 23:21:26 +0200 Subject: [PATCH 18/31] SL-18629 WIP Fetch Inventory using AIS caps --- indra/newview/llaisapi.cpp | 42 +++- indra/newview/llaisapi.h | 4 +- indra/newview/llinventoryfilter.cpp | 2 +- indra/newview/llinventorymodel.cpp | 13 -- indra/newview/llinventorymodel.h | 3 - .../llinventorymodelbackgroundfetch.cpp | 214 +++++++++++++++--- .../newview/llinventorymodelbackgroundfetch.h | 47 ++-- indra/newview/llstartup.cpp | 1 + indra/newview/llviewerinventory.cpp | 2 +- 9 files changed, 242 insertions(+), 86 deletions(-) diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index afc307278c..87811e9c0b 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -33,6 +33,8 @@ #include "llinventorymodel.h" #include "llsdutil.h" #include "llviewerregion.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llinventoryobserver.h" #include "llviewercontrol.h" @@ -409,6 +411,7 @@ void AISAPI::FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type, bool rec if (cap.empty()) { LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + callback(LLUUID::null); return; } std::string url = cap + std::string("/category/") + catId.asString() + "/children"; @@ -565,6 +568,24 @@ void AISAPI::onIdle(void *userdata) } } +/*static*/ +void AISAPI::onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type) +{ + LLTimer timer; + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + { + dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update); + } + bool is_fetch = (type == FETCHITEM) + || (type == FETCHCATEGORYCHILDREN) + || (type == FETCHCATEGORYCATEGORIES) + || (type == FETCHCOF); + // parse update llsd into stuff to do or parse received items. + AISUpdate ais_update(update, is_fetch); + ais_update.doUpdate(); // execute the updates in the appropriate order. + LL_INFOS("Inventory") << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL; +} + /*static*/ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, invokationFn_t invoke, std::string url, @@ -659,7 +680,7 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht } LL_DEBUGS("Inventory") << result << LL_ENDL; - gInventory.onAISUpdateReceived("AISCommand", result); + onUpdateReceived("AISCommand", result, type); if (callback && !callback.empty()) { @@ -708,7 +729,8 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht } //------------------------------------------------------------------------- -AISUpdate::AISUpdate(const LLSD& update) +AISUpdate::AISUpdate(const LLSD& update, bool fetch) +: mFetch(fetch) { parseUpdate(update); } @@ -849,7 +871,7 @@ void AISUpdate::parseItem(const LLSD& item_map) BOOL rv = new_item->unpackMessage(item_map); if (rv) { - if (curr_item) + if (!mFetch && curr_item) { mItemsUpdated[item_id] = new_item; // This statement is here to cause a new entry with 0 @@ -884,7 +906,7 @@ void AISUpdate::parseLink(const LLSD& link_map) if (rv) { const LLUUID& parent_id = new_link->getParentUUID(); - if (curr_link) + if (!mFetch && curr_link) { mItemsUpdated[item_id] = new_link; // This statement is here to cause a new entry with 0 @@ -951,7 +973,7 @@ void AISUpdate::parseCategory(const LLSD& category_map) //} if (rv) { - if (curr_cat) + if (curr_cat && !mFetch) { mCategoriesUpdated[category_id] = new_cat; // This statement is here to cause a new entry with 0 @@ -1054,7 +1076,7 @@ void AISUpdate::parseEmbeddedLinks(const LLSD& links) { const LLUUID link_id((*linkit).first); const LLSD& link_map = (*linkit).second; - if (mItemIds.end() == mItemIds.find(link_id)) + if (!mFetch && mItemIds.end() == mItemIds.find(link_id)) { LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL; } @@ -1070,7 +1092,7 @@ void AISUpdate::parseEmbeddedItem(const LLSD& item) // a single item (_embedded in a link) if (item.has("item_id")) { - if (mItemIds.end() != mItemIds.find(item["item_id"].asUUID())) + if (mFetch || mItemIds.end() != mItemIds.find(item["item_id"].asUUID())) { parseItem(item); } @@ -1086,7 +1108,7 @@ void AISUpdate::parseEmbeddedItems(const LLSD& items) { const LLUUID item_id((*itemit).first); const LLSD& item_map = (*itemit).second; - if (mItemIds.end() == mItemIds.find(item_id)) + if (!mFetch && mItemIds.end() == mItemIds.find(item_id)) { LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL; } @@ -1102,7 +1124,7 @@ void AISUpdate::parseEmbeddedCategory(const LLSD& category) // a single category (_embedded in a link) if (category.has("category_id")) { - if (mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID())) + if (mFetch || mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID())) { parseCategory(category); } @@ -1118,7 +1140,7 @@ void AISUpdate::parseEmbeddedCategories(const LLSD& categories) { const LLUUID category_id((*categoryit).first); const LLSD& category_map = (*categoryit).second; - if (mCategoryIds.end() == mCategoryIds.find(category_id)) + if (!mFetch && mCategoryIds.end() == mCategoryIds.find(category_id)) { LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL; } diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index b21edb9f33..3de3366a0e 100644 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -86,6 +86,7 @@ private: static void EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc); static void onIdle(void *userdata); // launches postponed AIS commands + static void onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type); static std::string getInvCap(); static std::string getLibCap(); @@ -101,7 +102,7 @@ private: class AISUpdate { public: - AISUpdate(const LLSD& update); + AISUpdate(const LLSD& update, bool fetch); void parseUpdate(const LLSD& update); void parseMeta(const LLSD& update); void parseContent(const LLSD& update); @@ -137,6 +138,7 @@ private: uuid_list_t mObjectsDeletedIds; uuid_list_t mItemIds; uuid_list_t mCategoryIds; + bool mFetch; }; #endif diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index d6110b3cd5..6e09161473 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -202,7 +202,7 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const { // At the moment background fetch only cares about VERSION_UNKNOWN, // so do not check isCategoryComplete that compares descendant count - LLInventoryModelBackgroundFetch::instance().start(folder_id); + LLInventoryModelBackgroundFetch::instance().start(folder_id, false); } } diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index ee0dd2422a..65690228e7 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1754,19 +1754,6 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, notifyObservers(); } -void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update) -{ - LLTimer timer; - if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) - { - dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update); - } - - AISUpdate ais_update(update); // parse update llsd into stuff to do. - ais_update.doUpdate(); // execute the updates in the appropriate order. - LL_INFOS(LOG_INV) << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL; -} - // Does not appear to be used currently. void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version) { diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 3fbf8924b5..5e4319bb12 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -411,9 +411,6 @@ public: // Delete //-------------------------------------------------------------------- public: - - // Update model after an AISv3 update received for any operation. - void onAISUpdateReceived(const std::string& context, const LLSD& update); // Update model after an item is confirmed as removed from // server. Works for categories or items. diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 406c8b89d0..1905a9c9a4 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llinventorymodelbackgroundfetch.h" +#include "llaisapi.h" #include "llagent.h" #include "llappviewer.h" #include "llcallbacklist.h" @@ -184,12 +185,12 @@ const char * const LOG_INV("Inventory"); ///---------------------------------------------------------------------------- LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch(): - mBackgroundFetchActive(FALSE), + mBackgroundFetchActive(false), mFolderFetchActive(false), mFetchCount(0), - mAllFoldersFetched(FALSE), - mRecursiveInventoryFetchStarted(FALSE), - mRecursiveLibraryFetchStarted(FALSE), + mAllFoldersFetched(false), + mRecursiveInventoryFetchStarted(false), + mRecursiveLibraryFetchStarted(false), mMinTimeBetweenFetches(0.3f) {} @@ -241,17 +242,17 @@ BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const return mFolderFetchActive; } -void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category) +void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, bool recursive, bool is_category) { mFetchQueue.push_front(FetchQueueInfo(id, recursive, is_category)); } -void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category) +void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, bool recursive, bool is_category) { mFetchQueue.push_back(FetchQueueInfo(id, recursive, is_category)); } -void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive) +void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) { LLViewerInventoryCategory * cat(gInventory.getCategory(id)); @@ -260,31 +261,57 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive) // it's a folder, do a bulk fetch LL_DEBUGS(LOG_INV) << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL; - mBackgroundFetchActive = TRUE; + mBackgroundFetchActive = true; mFolderFetchActive = true; if (id.isNull()) { if (! mRecursiveInventoryFetchStarted) { mRecursiveInventoryFetchStarted |= recursive; - mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive)); + if (recursive && AISAPI::isAvailable()) + { + mRecursiveFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive)); + } + else + { + mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive)); + } gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } if (! mRecursiveLibraryFetchStarted) { mRecursiveLibraryFetchStarted |= recursive; - mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive)); + if (recursive && AISAPI::isAvailable()) + { + mRecursiveFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive)); + } + else + { + mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive)); + } gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } else { - // Specific folder requests go to front of queue. - if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id) - { - mFetchQueue.push_front(FetchQueueInfo(id, recursive)); - gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); - } + if (recursive && AISAPI::isAvailable()) + { + // AIS does depth requests, recursive requests will need to be prioritizes + if (mRecursiveFetchQueue.empty() || mRecursiveFetchQueue.back().mUUID != id) + { + mRecursiveFetchQueue.push_back(FetchQueueInfo(id, recursive)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } + } + else + { + // Specific folder requests go to front of queue. + if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id) + { + mFetchQueue.push_front(FetchQueueInfo(id, recursive)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } + } if (id == gInventory.getLibraryRootFolderID()) { mRecursiveLibraryFetchStarted |= recursive; @@ -299,7 +326,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive) { if (! itemp->mIsComplete && (mFetchQueue.empty() || mFetchQueue.front().mUUID != id)) { - mBackgroundFetchActive = TRUE; + mBackgroundFetchActive = true; mFetchQueue.push_front(FetchQueueInfo(id, false, false)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); @@ -309,9 +336,9 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive) void LLInventoryModelBackgroundFetch::findLostItems() { - mBackgroundFetchActive = TRUE; + mBackgroundFetchActive = true; mFolderFetchActive = true; - mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE)); + mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, true)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } @@ -320,7 +347,7 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched() if (mRecursiveInventoryFetchStarted && mRecursiveLibraryFetchStarted) { - mAllFoldersFetched = TRUE; + mAllFoldersFetched = true; //LL_INFOS(LOG_INV) << "All folders fetched, validating" << LL_ENDL; //gInventory.validate(); } @@ -338,8 +365,15 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() { if (mBackgroundFetchActive && gAgent.getRegion() && gAgent.getRegion()->capabilitiesReceived()) { - // If we'll be using the capability, we'll be sending batches and the background thing isn't as important. - bulkFetch(); + if (AISAPI::isAvailable()) + { + bulkFetchViaAis(); + } + else + { + // If we'll be using the capability, we'll be sending batches and the background thing isn't as important. + bulkFetch(); + } } } @@ -352,9 +386,118 @@ void LLInventoryModelBackgroundFetch::incrFetchCount(S32 fetching) mFetchCount = 0; } } +void ais_callback(const LLUUID& inv_id) +{ + LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); +} static LLTrace::BlockTimerStatHandle FTM_BULK_FETCH("Bulk Fetch"); +void LLInventoryModelBackgroundFetch::bulkFetchViaAis() +{ + LL_RECORD_BLOCK_TIME(FTM_BULK_FETCH); + //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. + if (gDisconnected) + { + return; + } + + static const S32 max_concurrent_fetches(12); + + if (mFetchCount >= max_concurrent_fetches) + { + return; + } + + // Start with recursive queue since it can get multiple categories + // in a single request and might contain what other requests want + while (!mRecursiveFetchQueue.empty() && mFetchCount < max_concurrent_fetches) + { + const FetchQueueInfo & fetch_info(mRecursiveFetchQueue.front()); + bulkFetchViaAis(fetch_info); + mRecursiveFetchQueue.pop_front(); + } + + while (!mFetchQueue.empty() && mFetchCount < max_concurrent_fetches) + { + const FetchQueueInfo & fetch_info(mFetchQueue.front()); + bulkFetchViaAis(fetch_info); + mFetchQueue.pop_front(); + } + + if (isBulkFetchProcessingComplete()) + { + setAllFoldersFetched(); + } +} + +void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetch_info) +{ + if (fetch_info.mIsCategory) + { + const LLUUID & cat_id(fetch_info.mUUID); + if (cat_id.isNull()) // Lost and found + { + AISAPI::FetchCategoryChildren(LLUUID::null, AISAPI::INVENTORY, false, ais_callback); + mFetchCount++; + } + else + { + const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id)); + + if (cat) + { + if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) + { + if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) + { + AISAPI::FetchCategoryChildren(cat->getUUID(), AISAPI::LIBRARY, fetch_info.mRecursive, ais_callback); + } + else + { + AISAPI::FetchCategoryChildren(cat->getUUID(), AISAPI::INVENTORY, fetch_info.mRecursive, ais_callback); + } + mFetchCount++; + } + else + { + // Already fetched, check if anything inside needs fetching + if (fetch_info.mRecursive) + { + LLInventoryModel::cat_array_t * categories(NULL); + LLInventoryModel::item_array_t * items(NULL); + gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); + } + } + } + } + // else??? + } + } + else + { + LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID)); + + if (itemp) + { + if (itemp->getPermissions().getOwner() == gAgent.getID()) + { + AISAPI::FetchItem(itemp->getUUID(), AISAPI::INVENTORY, ais_callback); + } + else + { + AISAPI::FetchItem(itemp->getUUID(), AISAPI::LIBRARY, ais_callback); + } + mFetchCount++; + } + } +} + // Bundle up a bunch of requests to send all at once. void LLInventoryModelBackgroundFetch::bulkFetch() { @@ -374,13 +517,6 @@ void LLInventoryModelBackgroundFetch::bulkFetch() // inventory more quickly. static const U32 max_batch_size(10); static const S32 max_concurrent_fetches(12); // Outstanding requests, not connections - static const F32 new_min_time(0.05f); // *HACK: Clean this up when old code goes away entirely. - - mMinTimeBetweenFetches = new_min_time; - if (mMinTimeBetweenFetches < new_min_time) - { - mMinTimeBetweenFetches = new_min_time; // *HACK: See above. - } if (mFetchCount) { @@ -394,8 +530,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch() gInventory.notifyObservers(); } - if ((mFetchCount > max_concurrent_fetches) || - (mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches)) + if (mFetchCount > max_concurrent_fetches) { return; } @@ -414,6 +549,13 @@ void LLInventoryModelBackgroundFetch::bulkFetch() LLSD item_request_body; LLSD item_request_body_lib; + if (!mRecursiveFetchQueue.empty()) + { + LL_DEBUGS(LOG_INV) << "Request was sheduled for AIS, using legacy" << LL_ENDL; + mFetchQueue.insert(mFetchQueue.begin(), mRecursiveFetchQueue.begin(), mRecursiveFetchQueue.end()); + mRecursiveFetchQueue.clear(); + } + while (! mFetchQueue.empty() && (item_count + folder_count) < max_batch_size) { @@ -421,14 +563,14 @@ void LLInventoryModelBackgroundFetch::bulkFetch() if (fetch_info.mIsCategory) { const LLUUID & cat_id(fetch_info.mUUID); - if (cat_id.isNull()) //DEV-17797 + if (cat_id.isNull()) //DEV-17797 Lost and found { 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); + folder_sd["fetch_folders"] = LLSD::Boolean(false); + folder_sd["fetch_items"] = LLSD::Boolean(true); folder_request_body["folders"].append(folder_sd); folder_count++; } @@ -444,8 +586,8 @@ void LLInventoryModelBackgroundFetch::bulkFetch() folder_sd["folder_id"] = cat->getUUID(); folder_sd["owner_id"] = cat->getOwnerID(); folder_sd["sort_order"] = LLSD::Integer(sort_order); - folder_sd["fetch_folders"] = LLSD::Boolean(TRUE); //(LLSD::Boolean)sFullFetchStarted; - folder_sd["fetch_items"] = LLSD::Boolean(TRUE); + folder_sd["fetch_folders"] = LLSD::Boolean(true); //(LLSD::Boolean)sFullFetchStarted; + folder_sd["fetch_items"] = LLSD::Boolean(true); if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) { diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index 00d2908c1b..ac1c42e0d7 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -49,7 +49,7 @@ public: // Start and stop background breadth-first fetching of inventory contents. // This gets triggered when performing a filter-search. - void start(const LLUUID& cat_id = LLUUID::null, BOOL recursive = TRUE); + void start(const LLUUID& cat_id = LLUUID::null, bool recursive = true); BOOL folderFetchActive() const; bool isEverythingFetched() const; // completing the fetch once per session should be sufficient @@ -68,10 +68,27 @@ public: bool isBulkFetchProcessingComplete() const; void setAllFoldersFetched(); - void addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category); - void addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category); + void addRequestAtFront(const LLUUID & id, bool recursive, bool is_category); + void addRequestAtBack(const LLUUID & id, bool recursive, bool is_category); protected: + + struct FetchQueueInfo + { + FetchQueueInfo(const LLUUID& id, bool recursive, bool is_category = true) + : mUUID(id), + mIsCategory(is_category), + mRecursive(recursive) + {} + + LLUUID mUUID; + bool mIsCategory; + bool mRecursive; + }; + typedef std::deque fetch_queue_t; + + void bulkFetchViaAis(); + void bulkFetchViaAis(const FetchQueueInfo& fetch_info); void bulkFetch(); void backgroundFetch(); @@ -80,31 +97,19 @@ protected: bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const; private: - BOOL mRecursiveInventoryFetchStarted; - BOOL mRecursiveLibraryFetchStarted; - BOOL mAllFoldersFetched; + bool mRecursiveInventoryFetchStarted; + bool mRecursiveLibraryFetchStarted; + bool mAllFoldersFetched; - BOOL mBackgroundFetchActive; + bool mBackgroundFetchActive; bool mFolderFetchActive; S32 mFetchCount; LLFrameTimer mFetchTimer; F32 mMinTimeBetweenFetches; - - struct FetchQueueInfo - { - FetchQueueInfo(const LLUUID& id, BOOL recursive, bool is_category = true) - : mUUID(id), - mIsCategory(is_category), - mRecursive(recursive) - {} - - LLUUID mUUID; - bool mIsCategory; - BOOL mRecursive; - }; - typedef std::deque fetch_queue_t; fetch_queue_t mFetchQueue; + fetch_queue_t mRecursiveFetchQueue; + }; #endif // LL_LLINVENTORYMODELBACKGROUNDFETCH_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 776b9f8279..842192a62b 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1897,6 +1897,7 @@ bool idle_startup() LLNotificationsUtil::add("InventoryUnusable"); } + LLInventoryModelBackgroundFetch::instance().start(); gInventory.createCommonSystemCategories(); // It's debatable whether this flag is a good idea - sets all diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 6f7c5d96f5..61123e65d7 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -667,7 +667,7 @@ bool LLViewerInventoryCategory::fetch() { LL_WARNS(LOG_INV) << "agent region is null" << LL_ENDL; } - if (!url.empty()) //Capability found. Build up LLSD and use it. + if (!url.empty() || AISAPI::isAvailable()) { LLInventoryModelBackgroundFetch::instance().start(mUUID, false); } From 83811ff846d9c046e694708c209a6d4dc0bb45a3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 15 Mar 2023 03:29:03 +0200 Subject: [PATCH 19/31] SL-18629 WIP Fetch Inventory using AIS caps #2 --- indra/newview/llaisapi.cpp | 113 ++++++------ indra/newview/llaisapi.h | 1 - .../llinventorymodelbackgroundfetch.cpp | 162 ++++++++++++------ .../newview/llinventorymodelbackgroundfetch.h | 10 +- 4 files changed, 163 insertions(+), 123 deletions(-) diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 87811e9c0b..23bb123dee 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -483,41 +483,6 @@ void AISAPI::FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type, bool r EnqueueAISCommand("FetchCategoryCategories", proc); } -/*static*/ -void AISAPI::FetchCOF(completion_t callback) -{ - std::string cap; - cap = getInvCap(); - if (cap.empty()) - { - LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; - return; - } - LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - - std::string url = cap + std::string("/category/") + cof_id.asString() + "/links"; - - //LLUUID root_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ROOT_INVENTORY); - //std::string url = cap + std::string("/category/") + root_id.asString() + "/children?depth=*"; - - invokationFn_t patchFn = boost::bind( - // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. - static_cast - //---- - // _1 -> httpAdapter - // _2 -> httpRequest - // _3 -> url - // _4 -> body - // _5 -> httpOptions - // _6 -> httpHeaders - (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6); - - LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, - _1, patchFn, url, cof_id, LLSD(), callback, FETCHCOF)); - - EnqueueAISCommand("FetchCOF", proc); -} - /*static*/ void AISAPI::EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc) { @@ -578,8 +543,7 @@ void AISAPI::onUpdateReceived(const std::string& context, const LLSD& update, CO } bool is_fetch = (type == FETCHITEM) || (type == FETCHCATEGORYCHILDREN) - || (type == FETCHCATEGORYCATEGORIES) - || (type == FETCHCOF); + || (type == FETCHCATEGORYCATEGORIES); // parse update llsd into stuff to do or parse received items. AISUpdate ais_update(update, is_fetch); ais_update.doUpdate(); // execute the updates in the appropriate order. @@ -648,36 +612,16 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht } } } - /*else if (status.getType() == 403) + else if (status.getType() == 403) { if (type == FETCHCATEGORYCHILDREN) { - if (url.find("?depth=*") != std::string::npos) - { - LL_WARNS() << "too much" << LL_ENDL; - AISAPI::FetchCategoryChildren(gInventory.getRootFolderID(), AISAPI::ITEM_TYPE::INVENTORY, false, boost::bind(&LLInventoryModel::fetchDescendentsDepthOne, &gInventory, targetId)); - - if (result["oversize_inventory"].asBoolean() == true) - { - LL_WARNS("Inventory") << "Can't fetch the oversized inventory folder" << LL_ENDL; - } - } - else - { - if (result["oversize_inventory"].asBoolean() == true) - { - LL_WARNS("Inventory") << "Can't fetch the oversized inventory folder" << LL_ENDL; - } - } + LL_DEBUGS("Inventory") << "Fetch failed, content is over imit" << LL_ENDL; } - }*/ + } LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL; LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL; } - else if (type == FETCHCOF) - { - //LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL; - } LL_DEBUGS("Inventory") << result << LL_ENDL; onUpdateReceived("AISCommand", result, type); @@ -687,7 +631,10 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht bool needs_callback = true; LLUUID id(LLUUID::null); - if (type == COPYLIBRARYCATEGORY && result.has("category_id")) + if ( ( (type == COPYLIBRARYCATEGORY) + || (type == FETCHCATEGORYCATEGORIES) + || (type == FETCHCATEGORYCHILDREN)) + && result.has("category_id")) { id = result["category_id"]; } @@ -871,7 +818,12 @@ void AISUpdate::parseItem(const LLSD& item_map) BOOL rv = new_item->unpackMessage(item_map); if (rv) { - if (!mFetch && curr_item) + if (mFetch) + { + mItemsCreated[item_id] = new_item; + mCatDescendentDeltas[new_item->getParentUUID()]; + } + else if (curr_item) { mItemsUpdated[item_id] = new_item; // This statement is here to cause a new entry with 0 @@ -906,7 +858,19 @@ void AISUpdate::parseLink(const LLSD& link_map) if (rv) { const LLUUID& parent_id = new_link->getParentUUID(); - if (!mFetch && curr_link) + if (mFetch) + { + LLPermissions default_perms; + default_perms.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); + default_perms.initMasks(PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE); + new_link->setPermissions(default_perms); + LLSaleInfo default_sale_info; + new_link->setSaleInfo(default_sale_info); + //LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL; + mItemsCreated[item_id] = new_link; + mCatDescendentDeltas[parent_id]; + } + else if (curr_link) { mItemsUpdated[item_id] = new_link; // This statement is here to cause a new entry with 0 @@ -973,7 +937,28 @@ void AISUpdate::parseCategory(const LLSD& category_map) //} if (rv) { - if (curr_cat && !mFetch) + if (mFetch) + { + // Set version/descendents for newly created categories. + if (category_map.has("version")) + { + S32 version = category_map["version"].asInteger(); + LL_DEBUGS("Inventory") << "Setting version to " << version + << " for new category " << category_id << LL_ENDL; + new_cat->setVersion(version); + } + uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id); + if (mCatDescendentsKnown.end() != lookup_it) + { + S32 descendent_count = lookup_it->second; + LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count + << " for new category " << category_id << LL_ENDL; + new_cat->setDescendentCount(descendent_count); + } + mCategoriesCreated[category_id] = new_cat; + mCatDescendentDeltas[new_cat->getParentUUID()]; + } + else if (curr_cat) { mCategoriesUpdated[category_id] = new_cat; // This statement is here to cause a new entry with 0 diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index 3de3366a0e..58f6a17650 100644 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -75,7 +75,6 @@ private: FETCHITEM, FETCHCATEGORYCHILDREN, FETCHCATEGORYCATEGORIES, - FETCHCOF, } COMMAND_TYPE; static const std::string INVENTORY_CAP_NAME; diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 1905a9c9a4..5ea8fe4cba 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -244,12 +244,14 @@ BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, bool recursive, bool is_category) { - mFetchQueue.push_front(FetchQueueInfo(id, recursive, is_category)); + ERecursionType recursion_type = recursive ? RT_RECURSIVE : RT_NONE; + mFetchQueue.push_front(FetchQueueInfo(id, recursion_type, is_category)); } void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, bool recursive, bool is_category) { - mFetchQueue.push_back(FetchQueueInfo(id, recursive, is_category)); + ERecursionType recursion_type = recursive ? RT_RECURSIVE : RT_NONE; + mFetchQueue.push_back(FetchQueueInfo(id, recursion_type, is_category)); } void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) @@ -263,6 +265,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) mBackgroundFetchActive = true; mFolderFetchActive = true; + ERecursionType recursion_type = recursive ? RT_RECURSIVE : RT_NONE; if (id.isNull()) { if (! mRecursiveInventoryFetchStarted) @@ -270,11 +273,14 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) mRecursiveInventoryFetchStarted |= recursive; if (recursive && AISAPI::isAvailable()) { - mRecursiveFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive)); + // Not only root folder can be massive, but + // most system folders will be requested independently + // so request root folder and content separately + mRecursiveFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), RT_CONTENT)); } else { - mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive)); + mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursion_type)); } gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } @@ -283,11 +289,11 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) mRecursiveLibraryFetchStarted |= recursive; if (recursive && AISAPI::isAvailable()) { - mRecursiveFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive)); + mRecursiveFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursion_type)); } else { - mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive)); + mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursion_type)); } gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } @@ -299,7 +305,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) // AIS does depth requests, recursive requests will need to be prioritizes if (mRecursiveFetchQueue.empty() || mRecursiveFetchQueue.back().mUUID != id) { - mRecursiveFetchQueue.push_back(FetchQueueInfo(id, recursive)); + mRecursiveFetchQueue.push_back(FetchQueueInfo(id, recursion_type)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } @@ -308,7 +314,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) // Specific folder requests go to front of queue. if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id) { - mFetchQueue.push_front(FetchQueueInfo(id, recursive)); + mFetchQueue.push_front(FetchQueueInfo(id, recursion_type)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } @@ -328,7 +334,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) { mBackgroundFetchActive = true; - mFetchQueue.push_front(FetchQueueInfo(id, false, false)); + mFetchQueue.push_front(FetchQueueInfo(id, RT_NONE, false)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } @@ -338,7 +344,7 @@ void LLInventoryModelBackgroundFetch::findLostItems() { mBackgroundFetchActive = true; mFolderFetchActive = true; - mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, true)); + mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, RT_RECURSIVE)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } @@ -386,11 +392,45 @@ void LLInventoryModelBackgroundFetch::incrFetchCount(S32 fetching) mFetchCount = 0; } } -void ais_callback(const LLUUID& inv_id) + +void ais_simple_callback(const LLUUID& inv_id) { LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); } +void LLInventoryModelBackgroundFetch::onAISCalback(const LLUUID &request_id, const LLUUID &response_id, ERecursionType recursion) +{ + incrFetchCount(-1); + if (response_id.isNull()) // Failure + { + if (recursion == RT_RECURSIVE) + { + // A full recursive request failed. + // Try requesting folder and nested content separately + mBackgroundFetchActive = true; + mFolderFetchActive = true; + mRecursiveFetchQueue.push_back(FetchQueueInfo(request_id, RT_CONTENT)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } + } + else + { + if (recursion == RT_CONTENT) + { + // Got the folder, now recursively request content + LLInventoryModel::cat_array_t * categories(NULL); + LLInventoryModel::item_array_t * items(NULL); + gInventory.getDirectDescendentsOf(request_id, categories, items); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mRecursiveFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), RT_RECURSIVE)); + } + } + } +} + static LLTrace::BlockTimerStatHandle FTM_BULK_FETCH("Bulk Fetch"); void LLInventoryModelBackgroundFetch::bulkFetchViaAis() @@ -438,45 +478,54 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc const LLUUID & cat_id(fetch_info.mUUID); if (cat_id.isNull()) // Lost and found { - AISAPI::FetchCategoryChildren(LLUUID::null, AISAPI::INVENTORY, false, ais_callback); + AISAPI::FetchCategoryChildren(LLUUID::null, AISAPI::INVENTORY, false, ais_simple_callback); mFetchCount++; } else { - const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id)); - if (cat) + if (!gInventory.isCategoryComplete(cat_id)) { - if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) + const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id)); + if (cat) { if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) { - AISAPI::FetchCategoryChildren(cat->getUUID(), AISAPI::LIBRARY, fetch_info.mRecursive, ais_callback); + AISAPI::FetchCategoryChildren(cat->getUUID(), AISAPI::LIBRARY, fetch_info.mRecursive == RT_RECURSIVE, ais_simple_callback); } else { - AISAPI::FetchCategoryChildren(cat->getUUID(), AISAPI::INVENTORY, fetch_info.mRecursive, ais_callback); + LLUUID cat_id = cat->getUUID(); + ERecursionType type = fetch_info.mRecursive; + AISAPI::FetchCategoryChildren( + cat_id, + AISAPI::INVENTORY, + type == RT_RECURSIVE, + [cat_id, type](const LLUUID &response_id) + { + LLInventoryModelBackgroundFetch::instance().onAISCalback(cat_id, response_id, type); + }); } mFetchCount++; } - else + // else? + } + else + { + // Already fetched, check if anything inside needs fetching + if (fetch_info.mRecursive) { - // Already fetched, check if anything inside needs fetching - if (fetch_info.mRecursive) + LLInventoryModel::cat_array_t * categories(NULL); + LLInventoryModel::item_array_t * items(NULL); + gInventory.getDirectDescendentsOf(cat_id, categories, items); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) { - LLInventoryModel::cat_array_t * categories(NULL); - LLInventoryModel::item_array_t * items(NULL); - gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items); - for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); - it != categories->end(); - ++it) - { - mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); - } + mRecursiveFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); } } } - // else??? } } else @@ -487,11 +536,11 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc { if (itemp->getPermissions().getOwner() == gAgent.getID()) { - AISAPI::FetchItem(itemp->getUUID(), AISAPI::INVENTORY, ais_callback); + AISAPI::FetchItem(itemp->getUUID(), AISAPI::INVENTORY, ais_simple_callback); } else { - AISAPI::FetchItem(itemp->getUUID(), AISAPI::LIBRARY, ais_callback); + AISAPI::FetchItem(itemp->getUUID(), AISAPI::LIBRARY, ais_simple_callback); } mFetchCount++; } @@ -576,36 +625,37 @@ void LLInventoryModelBackgroundFetch::bulkFetch() } else { - const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id)); - - if (cat) - { - 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"] = LLSD::Boolean(true); //(LLSD::Boolean)sFullFetchStarted; - folder_sd["fetch_items"] = LLSD::Boolean(true); - - if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) - { - folder_request_body_lib["folders"].append(folder_sd); - } - else - { - folder_request_body["folders"].append(folder_sd); - } - folder_count++; - } + if (!gInventory.isCategoryComplete(cat_id)) + { + const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id)); + if (cat) + { + 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"] = LLSD::Boolean(true); //(LLSD::Boolean)sFullFetchStarted; + folder_sd["fetch_items"] = LLSD::Boolean(true); + if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) + { + folder_request_body_lib["folders"].append(folder_sd); + } + else + { + folder_request_body["folders"].append(folder_sd); + } + folder_count++; + } + } + else + { // May already have this folder, but append child folders to list. if (fetch_info.mRecursive) { LLInventoryModel::cat_array_t * categories(NULL); LLInventoryModel::item_array_t * items(NULL); - gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items); + gInventory.getDirectDescendentsOf(cat_id, categories, items); for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index ac1c42e0d7..4c4de6ac7c 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -73,9 +73,14 @@ public: protected: + typedef enum { + RT_NONE = 0, + RT_CONTENT, // request content recursively + RT_RECURSIVE, // request everything recursively + } ERecursionType; struct FetchQueueInfo { - FetchQueueInfo(const LLUUID& id, bool recursive, bool is_category = true) + FetchQueueInfo(const LLUUID& id, ERecursionType recursive, bool is_category = true) : mUUID(id), mIsCategory(is_category), mRecursive(recursive) @@ -83,10 +88,11 @@ protected: LLUUID mUUID; bool mIsCategory; - bool mRecursive; + ERecursionType mRecursive; }; typedef std::deque fetch_queue_t; + void onAISCalback(const LLUUID &request_id, const LLUUID &response_id, ERecursionType recursion); void bulkFetchViaAis(); void bulkFetchViaAis(const FetchQueueInfo& fetch_info); void bulkFetch(); From 7a70d93c437a7065b0c0be7fa63d36f511a9cef2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 15 Mar 2023 20:03:53 +0200 Subject: [PATCH 20/31] SL-18629 Fetch Inventory using AIS caps #3 --- indra/newview/llaisapi.cpp | 28 ++++++++--- .../llinventorymodelbackgroundfetch.cpp | 50 +++++++------------ .../newview/llinventorymodelbackgroundfetch.h | 1 - 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 23bb123dee..bb963d77c9 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -901,7 +901,25 @@ void AISUpdate::parseLink(const LLSD& link_map) void AISUpdate::parseCategory(const LLSD& category_map) { - LLUUID category_id = category_map["category_id"].asUUID(); + LLUUID category_id = category_map["category_id"].asUUID(); + S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN; + + if (category_map.has("version")) + { + version = category_map["version"].asInteger(); + } + + LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id); + + if (curr_cat + && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN + && version > LLViewerInventoryCategory::VERSION_UNKNOWN + && version < curr_cat->getVersion()) + { + LL_WARNS() << "Got stale folder, known: " << curr_cat->getVersion() + << ", received: " << version << LL_ENDL; + return; + } // Check descendent count first, as it may be needed // to populate newly created categories @@ -911,7 +929,6 @@ void AISUpdate::parseCategory(const LLSD& category_map) } LLPointer new_cat; - LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id); if (curr_cat) { // Default to current values where not provided. @@ -940,11 +957,10 @@ void AISUpdate::parseCategory(const LLSD& category_map) if (mFetch) { // Set version/descendents for newly created categories. - if (category_map.has("version")) + if (version > LLViewerInventoryCategory::VERSION_UNKNOWN) { - S32 version = category_map["version"].asInteger(); LL_DEBUGS("Inventory") << "Setting version to " << version - << " for new category " << category_id << LL_ENDL; + << " for category " << category_id << LL_ENDL; new_cat->setVersion(version); } uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id); @@ -952,7 +968,7 @@ void AISUpdate::parseCategory(const LLSD& category_map) { S32 descendent_count = lookup_it->second; LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count - << " for new category " << category_id << LL_ENDL; + << " for category " << category_id << LL_ENDL; new_cat->setDescendentCount(descendent_count); } mCategoriesCreated[category_id] = new_cat; diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 5ea8fe4cba..098ced4ec9 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -276,7 +276,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) // Not only root folder can be massive, but // most system folders will be requested independently // so request root folder and content separately - mRecursiveFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), RT_CONTENT)); + mFetchQueue.push_front(FetchQueueInfo(gInventory.getRootFolderID(), RT_CONTENT)); } else { @@ -287,25 +287,18 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) if (! mRecursiveLibraryFetchStarted) { mRecursiveLibraryFetchStarted |= recursive; - if (recursive && AISAPI::isAvailable()) - { - mRecursiveFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursion_type)); - } - else - { - mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursion_type)); - } + mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursion_type)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } else { - if (recursive && AISAPI::isAvailable()) + if (AISAPI::isAvailable() && !recursive) { - // AIS does depth requests, recursive requests will need to be prioritizes - if (mRecursiveFetchQueue.empty() || mRecursiveFetchQueue.back().mUUID != id) + // Specific folder requests go to front of queue. + if (mFetchQueue.empty() || mFetchQueue.back().mUUID != id) { - mRecursiveFetchQueue.push_back(FetchQueueInfo(id, recursion_type)); + mFetchQueue.push_back(FetchQueueInfo(id, recursion_type)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } @@ -318,6 +311,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } + if (id == gInventory.getLibraryRootFolderID()) { mRecursiveLibraryFetchStarted |= recursive; @@ -409,7 +403,7 @@ void LLInventoryModelBackgroundFetch::onAISCalback(const LLUUID &request_id, con // Try requesting folder and nested content separately mBackgroundFetchActive = true; mFolderFetchActive = true; - mRecursiveFetchQueue.push_back(FetchQueueInfo(request_id, RT_CONTENT)); + mFetchQueue.push_front(FetchQueueInfo(request_id, RT_CONTENT)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } @@ -425,7 +419,13 @@ void LLInventoryModelBackgroundFetch::onAISCalback(const LLUUID &request_id, con it != categories->end(); ++it) { - mRecursiveFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), RT_RECURSIVE)); + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), RT_RECURSIVE)); + } + if (!mFetchQueue.empty()) + { + mBackgroundFetchActive = true; + mFolderFetchActive = true; + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } } @@ -442,22 +442,13 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis() return; } - static const S32 max_concurrent_fetches(12); + static const S32 max_concurrent_fetches(50); if (mFetchCount >= max_concurrent_fetches) { return; } - // Start with recursive queue since it can get multiple categories - // in a single request and might contain what other requests want - while (!mRecursiveFetchQueue.empty() && mFetchCount < max_concurrent_fetches) - { - const FetchQueueInfo & fetch_info(mRecursiveFetchQueue.front()); - bulkFetchViaAis(fetch_info); - mRecursiveFetchQueue.pop_front(); - } - while (!mFetchQueue.empty() && mFetchCount < max_concurrent_fetches) { const FetchQueueInfo & fetch_info(mFetchQueue.front()); @@ -522,7 +513,7 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc it != categories->end(); ++it) { - mRecursiveFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); } } } @@ -598,13 +589,6 @@ void LLInventoryModelBackgroundFetch::bulkFetch() LLSD item_request_body; LLSD item_request_body_lib; - if (!mRecursiveFetchQueue.empty()) - { - LL_DEBUGS(LOG_INV) << "Request was sheduled for AIS, using legacy" << LL_ENDL; - mFetchQueue.insert(mFetchQueue.begin(), mRecursiveFetchQueue.begin(), mRecursiveFetchQueue.end()); - mRecursiveFetchQueue.clear(); - } - while (! mFetchQueue.empty() && (item_count + folder_count) < max_batch_size) { diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index 4c4de6ac7c..14557ea92d 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -114,7 +114,6 @@ private: LLFrameTimer mFetchTimer; F32 mMinTimeBetweenFetches; fetch_queue_t mFetchQueue; - fetch_queue_t mRecursiveFetchQueue; }; From 02a3df31cee5d047dd5ff535b7c6612e37989337 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 16 Mar 2023 00:03:22 +0200 Subject: [PATCH 21/31] SL-19108 Update thumbnail cap names --- indra/newview/llfloatersimplesnapshot.cpp | 36 ++++++++++++++++------- indra/newview/llviewerregion.cpp | 3 +- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/indra/newview/llfloatersimplesnapshot.cpp b/indra/newview/llfloatersimplesnapshot.cpp index 83f4f1ace9..cf596fd82f 100644 --- a/indra/newview/llfloatersimplesnapshot.cpp +++ b/indra/newview/llfloatersimplesnapshot.cpp @@ -31,6 +31,7 @@ #include "llfloaterreg.h" #include "llimagefiltersmanager.h" #include "llinventorymodel.h" +#include "llinventoryobserver.h" #include "llstatusbar.h" // can_afford_transaction() #include "llnotificationsutil.h" #include "llagent.h" @@ -47,8 +48,7 @@ const S32 LLFloaterSimpleSnapshot::THUMBNAIL_SNAPSHOT_DIM_MIN = 64; // Thumbnail posting coro -static const std::string THUMBNAIL_ITEM_UPLOAD_CAP = "InventoryItemThumbnailUpload"; -static const std::string THUMBNAIL_CATEGORY_UPLOAD_CAP = "InventoryCategoryThumbnailUpload"; +static const std::string THUMBNAIL_UPLOAD_CAP = "InventoryThumbnailUpload"; void post_thumbnail_image_coro(std::string cap_url, std::string path_to_image, LLSD first_data) { @@ -132,8 +132,27 @@ void post_thumbnail_image_coro(std::string cap_url, std::string path_to_image, L return; } - // todo: issue an inventory udpate? - //return result["new_asset"].asUUID(); + if (first_data.has("category_id")) + { + LLUUID cat_id = first_data["category_id"].asUUID(); + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + if (cat) + { + cat->setThumbnailUUID(result["new_asset"].asUUID()); + } + gInventory.addChangedMask(LLInventoryObserver::INTERNAL, cat_id); + } + if (first_data.has("item_id")) + { + LLUUID item_id = first_data["item_id"].asUUID(); + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if (item) + { + item->setThumbnailUUID(result["new_asset"].asUUID()); + } + // Are we supposed to get BulkUpdateInventory? + gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id); + } } ///---------------------------------------------------------------------------- @@ -346,6 +365,7 @@ void LLFloaterSimpleSnapshot::onSend() if (previewp->createUploadFile(temp_file, THUMBNAIL_SNAPSHOT_DIM_MAX, THUMBNAIL_SNAPSHOT_DIM_MIN)) { uploadImageUploadFile(temp_file, mInventoryId, mTaskId); + closeFloater(); } else { @@ -380,31 +400,27 @@ void LLFloaterSimpleSnapshot::uploadThumbnail(const std::string &file_path, cons // static void LLFloaterSimpleSnapshot::uploadImageUploadFile(const std::string &temp_file, const LLUUID &inventory_id, const LLUUID &task_id) { - std::string cap_name; LLSD data; if (task_id.notNull()) { - cap_name = THUMBNAIL_ITEM_UPLOAD_CAP; data["item_id"] = inventory_id; data["task_id"] = task_id; } else if (gInventory.getCategory(inventory_id)) { - cap_name = THUMBNAIL_CATEGORY_UPLOAD_CAP; data["category_id"] = inventory_id; } else { - cap_name = THUMBNAIL_ITEM_UPLOAD_CAP; data["item_id"] = inventory_id; } - std::string cap_url = gAgent.getRegionCapability(cap_name); + std::string cap_url = gAgent.getRegionCapability(THUMBNAIL_UPLOAD_CAP); if (cap_url.empty()) { LLSD args; - args["CAPABILITY"] = cap_url; + args["CAPABILITY"] = THUMBNAIL_UPLOAD_CAP; LLNotificationsUtil::add("RegionCapabilityRequestError", args); LL_WARNS("Thumbnail") << "Failed to upload profile image for item " << inventory_id << " " << task_id << ", no cap found" << LL_ENDL; return; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index e5d703a6ee..4e85d31549 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -3024,8 +3024,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("InterestList"); - capabilityNames.append("InventoryCategoryThumbnailUpload"); - capabilityNames.append("InventoryItemThumbnailUpload"); + capabilityNames.append("InventoryThumbnailUpload"); capabilityNames.append("GetDisplayNames"); capabilityNames.append("GetExperiences"); capabilityNames.append("AgentExperiences"); From cb66156a72ad02ce937763a4439de32d05fc10d5 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 16 Mar 2023 21:45:41 +0200 Subject: [PATCH 22/31] SL-19105 Fix menu's opening position --- indra/newview/llpanelmaininventory.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index f8c1fcb5f5..9fab6e4d2e 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -1457,8 +1457,7 @@ void LLPanelMainInventory::showActionMenu(LLMenuGL* menu, std::string spawning_v LLView* spawning_view = getChild (spawning_view_name); S32 menu_x, menu_y; //show menu in co-ordinates of panel - spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this); - menu_y += menu->getRect().getHeight(); + spawning_view->localPointToOtherView(0, 0, &menu_x, &menu_y, this); LLMenuGL::showPopup(this, menu, menu_x, menu_y); } } From 86c46a12296a8f00dd6db33a69fffe55e6520326 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 17 Mar 2023 00:38:39 +0200 Subject: [PATCH 23/31] SL-18674 Remove UDP fallbacks for AIS caps not present --- indra/newview/llviewerinventory.cpp | 49 +++++------------------------ 1 file changed, 8 insertions(+), 41 deletions(-) diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 61123e65d7..07338b7b6b 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1400,25 +1400,10 @@ void remove_inventory_item( gInventory.onObjectDeletedFromServer(item_id); } } - else // no cap - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RemoveInventoryItem); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_ItemID, item_id); - gAgent.sendReliableMessage(); - - // Update inventory and call callback immediately since - // message-based system has no callback mechanism (!) - gInventory.onObjectDeletedFromServer(item_id); - if (cb) - { - cb->fire(item_id); - } - } + else + { + LL_WARNS(LOG_INV) << "Tried to use inventory without AIS API" << LL_ENDL; + } } else { @@ -1547,28 +1532,10 @@ void purge_descendents_of(const LLUUID& id, LLPointer cb) AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); AISAPI::PurgeDescendents(id, cr); } - else // no cap - { - // Fast purge - LL_DEBUGS(LOG_INV) << "purge_descendents_of fast case " << cat->getName() << LL_ENDL; - - // send it upstream - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("PurgeInventoryDescendents"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("InventoryData"); - msg->addUUID("FolderID", id); - gAgent.sendReliableMessage(); - - // Update model immediately because there is no callback mechanism. - gInventory.onDescendentsPurgedFromServer(id); - if (cb) - { - cb->fire(id); - } - } + else + { + LL_WARNS(LOG_INV) << "Tried to use inventory without AIS API" << LL_ENDL; + } } } From 3a5c41a20e6044c8cfa71dfd1583fea0809d6a68 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 17 Mar 2023 03:23:15 +0200 Subject: [PATCH 24/31] SL-18629 Fetch Inventory using AIS caps #4 --- .../llinventorymodelbackgroundfetch.cpp | 28 +++++++++++-------- indra/newview/llstartup.cpp | 5 ++++ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 098ced4ec9..282d234cf3 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -293,23 +293,20 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) } else { - if (AISAPI::isAvailable() && !recursive) + if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id) { - // Specific folder requests go to front of queue. - if (mFetchQueue.empty() || mFetchQueue.back().mUUID != id) + if (AISAPI::isAvailable()) { + // On AIS make sure root goes to the top and follow up recursive + // fetches, not individual requests mFetchQueue.push_back(FetchQueueInfo(id, recursion_type)); - gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } - } - else - { - // Specific folder requests go to front of queue. - if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id) + else { + // Specific folder requests go to front of queue. mFetchQueue.push_front(FetchQueueInfo(id, recursion_type)); - gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } if (id == gInventory.getLibraryRootFolderID()) @@ -419,7 +416,7 @@ void LLInventoryModelBackgroundFetch::onAISCalback(const LLUUID &request_id, con it != categories->end(); ++it) { - mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), RT_RECURSIVE)); + mFetchQueue.push_front(FetchQueueInfo((*it)->getUUID(), RT_RECURSIVE)); } if (!mFetchQueue.empty()) { @@ -449,11 +446,17 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis() return; } - while (!mFetchQueue.empty() && mFetchCount < max_concurrent_fetches) + // Don't loop for too long (in case of large, fully loaded inventory) + F64 curent_time = LLTimer::getTotalSeconds(); + const F64 max_time = 0.006f; // 6 ms + const F64 end_time = curent_time + max_time; + + while (!mFetchQueue.empty() && mFetchCount < max_concurrent_fetches && curent_time < end_time) { const FetchQueueInfo & fetch_info(mFetchQueue.front()); bulkFetchViaAis(fetch_info); mFetchQueue.pop_front(); + curent_time = LLTimer::getTotalSeconds(); } if (isBulkFetchProcessingComplete()) @@ -513,6 +516,7 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc it != categories->end(); ++it) { + // not push_front to not cause an infinite loop mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); } } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 842192a62b..a1f2753ada 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2930,6 +2930,11 @@ void reset_login() LLFloaterReg::hideVisibleInstances(); LLStartUp::setStartupState( STATE_BROWSER_INIT ); + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->terminate(); + } + // Clear any verified certs and verify them again on next login // to ensure cert matches server instead of just getting reused LLPointer store = gSecAPIHandler->getCertificateStore(""); From 9ef9efaa0e843054a18a3957d64499a2ef8b4700 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 17 Mar 2023 14:51:06 +0200 Subject: [PATCH 25/31] SL-19108 Fix folders not showing thumbnails --- indra/newview/llinventorybridge.cpp | 10 ++++++++++ indra/newview/llinventorybridge.h | 1 + 2 files changed, 11 insertions(+) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 421c1c9754..cc8e20485b 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2339,6 +2339,16 @@ LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const return LLFontGL::NORMAL; } +const LLUUID& LLFolderBridge::getThumbnailUUID() const +{ + LLViewerInventoryCategory* cat = getCategory(); + if (cat) + { + return cat->getThumbnailUUID(); + } + return LLUUID::null; +} + void LLFolderBridge::update() { // we know we have children but haven't fetched them (doesn't obey filter) diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 958d284854..eaa7166631 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -299,6 +299,7 @@ public: static LLUIImagePtr getIcon(LLFolderType::EType preferred_type); virtual std::string getLabelSuffix() const; virtual LLFontGL::StyleFlags getLabelStyle() const; + virtual const LLUUID& getThumbnailUUID() const; void setShowDescendantsCount(bool show_count) {mShowDescendantsCount = show_count;} From 4f9f149939cfd79ba6d18ed90202b29225c2969c Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 17 Mar 2023 22:42:14 +0200 Subject: [PATCH 26/31] SL-18629 Try fetching inventory on BulkUpdateInventory to get missing data --- indra/newview/llinventorymodel.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 65690228e7..43bfaf454c 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -3811,10 +3811,20 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit) { gInventory.updateCategory(*cit); + + // Temporary workaround: just fetch the item using AIS to get missing fields. + // If this works fine we might want to extract ids only from the message + // then use AIS as a primary fetcher + AISAPI::FetchCategoryChildren((*cit)->getUUID(), AISAPI::INVENTORY, false); } for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit) { gInventory.updateItem(*iit); + + // Temporary workaround: just fetch the item using AIS to get missing fields. + // If this works fine we might want to extract ids only from the message + // then use AIS as a primary fetcher + AISAPI::FetchItem((*iit)->getUUID(), AISAPI::INVENTORY, false); } gInventory.notifyObservers(); From 70d99cde5826893be4964d4673ff875320b7220f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 17 Mar 2023 23:44:28 +0200 Subject: [PATCH 27/31] SL-18629 Track request depth to be able to distinguish incomplete folder reliably --- indra/newview/llaisapi.cpp | 87 ++++++++++++------- indra/newview/llaisapi.h | 13 +-- .../llinventorymodelbackgroundfetch.cpp | 73 ++++++++-------- indra/newview/llviewerinventory.cpp | 6 +- 4 files changed, 102 insertions(+), 77 deletions(-) diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index bb963d77c9..5e243476d8 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -384,7 +384,7 @@ void AISAPI::FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callba } std::string url = cap + std::string("/item/") + itemId.asString(); - invokationFn_t patchFn = boost::bind( + invokationFn_t getFn = boost::bind( // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. static_cast //---- @@ -397,7 +397,7 @@ void AISAPI::FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callba (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6); LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, - _1, patchFn, url, itemId, LLSD(), callback, FETCHITEM)); + _1, getFn, url, itemId, LLSD(), callback, FETCHITEM)); EnqueueAISCommand("FetchItem", proc); } @@ -425,7 +425,7 @@ void AISAPI::FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type, bool rec url += "?depth=" + std::to_string(depth); } - invokationFn_t patchFn = boost::bind( + invokationFn_t getFn = boost::bind( // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. static_cast //---- @@ -437,8 +437,11 @@ void AISAPI::FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type, bool rec // _6 -> httpHeaders (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6); + // get doesn't use body, can pass additional data + LLSD body; + body["depth"] = recursive ? S32_MAX : depth; LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, - _1, patchFn, url, catId, LLSD(), callback, FETCHCATEGORYCHILDREN)); + _1, getFn, url, catId, body, callback, FETCHCATEGORYCHILDREN)); EnqueueAISCommand("FetchCategoryChildren", proc); } @@ -465,7 +468,7 @@ void AISAPI::FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type, bool r url += "?depth=" + std::to_string(depth); } - invokationFn_t patchFn = boost::bind( + invokationFn_t getFn = boost::bind( // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. static_cast //---- @@ -477,8 +480,11 @@ void AISAPI::FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type, bool r // _6 -> httpHeaders (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6); + // get doesn't use body, can pass additional data + LLSD body; + body["depth"] = depth; LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, - _1, patchFn, url, catId, LLSD(), callback, FETCHCATEGORYCATEGORIES)); + _1, getFn, url, catId, body, callback, FETCHCATEGORYCATEGORIES)); EnqueueAISCommand("FetchCategoryCategories", proc); } @@ -534,7 +540,7 @@ void AISAPI::onIdle(void *userdata) } /*static*/ -void AISAPI::onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type) +void AISAPI::onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type, const LLSD& request_body) { LLTimer timer; if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) @@ -545,7 +551,12 @@ void AISAPI::onUpdateReceived(const std::string& context, const LLSD& update, CO || (type == FETCHCATEGORYCHILDREN) || (type == FETCHCATEGORYCATEGORIES); // parse update llsd into stuff to do or parse received items. - AISUpdate ais_update(update, is_fetch); + S32 depth = 0; + if (is_fetch && request_body.has("depth")) + { + depth = request_body["depth"].asInteger(); + } + AISUpdate ais_update(update, is_fetch, depth); ais_update.doUpdate(); // execute the updates in the appropriate order. LL_INFOS("Inventory") << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL; } @@ -559,11 +570,6 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest()); LLCore::HttpHeaders::ptr_t httpHeaders; - /*if (type == FETCHCATEGORYCHILDREN && (url.find("?depth=*") != std::string::npos)) - { - LL_WARNS() << "testy test start"<< LL_ENDL; - }*/ - httpOptions->setTimeout(180); LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; @@ -624,7 +630,12 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht } LL_DEBUGS("Inventory") << result << LL_ENDL; - onUpdateReceived("AISCommand", result, type); + onUpdateReceived("AISCommand", result, type, body); + + if (type == FETCHITEM) + { + LL_WARNS() << "test" << LL_ENDL; + } if (callback && !callback.empty()) { @@ -638,6 +649,17 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht { id = result["category_id"]; } + if (type == FETCHITEM) + { + if (result.has("item_id")) + { + id = result["item_id"]; + } + if (result.has("linked_id")) + { + id = result["linked_id"]; + } + } if (type == CREATEINVENTORY) { // CREATEINVENTORY can have multiple callbacks @@ -676,8 +698,9 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht } //------------------------------------------------------------------------- -AISUpdate::AISUpdate(const LLSD& update, bool fetch) +AISUpdate::AISUpdate(const LLSD& update, bool fetch, S32 depth) : mFetch(fetch) +, mFetchDepth(depth) { parseUpdate(update); } @@ -794,13 +817,13 @@ void AISUpdate::parseContent(const LLSD& update) if (update.has("category_id")) { - parseCategory(update); + parseCategory(update, mFetchDepth); } else { if (update.has("_embedded")) { - parseEmbedded(update["_embedded"]); + parseEmbedded(update["_embedded"], mFetchDepth); } } } @@ -899,7 +922,7 @@ void AISUpdate::parseLink(const LLSD& link_map) } -void AISUpdate::parseCategory(const LLSD& category_map) +void AISUpdate::parseCategory(const LLSD& category_map, S32 depth) { LLUUID category_id = category_map["category_id"].asUUID(); S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN; @@ -948,17 +971,17 @@ void AISUpdate::parseCategory(const LLSD& category_map) } BOOL rv = new_cat->unpackMessage(category_map); // *NOTE: unpackMessage does not unpack version or descendent count. - //if (category_map.has("version")) - //{ - // mCatVersionsUpdated[category_id] = category_map["version"].asInteger(); - //} if (rv) { if (mFetch) { - // Set version/descendents for newly created categories. - if (version > LLViewerInventoryCategory::VERSION_UNKNOWN) + // set version only if previous one was already known + // or if we are sure this update has full data and embeded items (depth 0+) + // since bulk fetch uses this to decide what still needs fetching + if (version > LLViewerInventoryCategory::VERSION_UNKNOWN + && (depth >= 0 || (curr_cat && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN))) { + // Set version/descendents for newly fetched categories. LL_DEBUGS("Inventory") << "Setting version to " << version << " for category " << category_id << LL_ENDL; new_cat->setVersion(version); @@ -1015,7 +1038,7 @@ void AISUpdate::parseCategory(const LLSD& category_map) // Check for more embedded content. if (category_map.has("_embedded")) { - parseEmbedded(category_map["_embedded"]); + parseEmbedded(category_map["_embedded"], depth - 1); } } @@ -1032,7 +1055,7 @@ void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embe } } -void AISUpdate::parseEmbedded(const LLSD& embedded) +void AISUpdate::parseEmbedded(const LLSD& embedded, S32 depth) { if (embedded.has("links")) // _embedded in a category { @@ -1048,11 +1071,11 @@ void AISUpdate::parseEmbedded(const LLSD& embedded) } if (embedded.has("categories")) // _embedded in a category { - parseEmbeddedCategories(embedded["categories"]); + parseEmbeddedCategories(embedded["categories"], depth); } if (embedded.has("category")) // _embedded in a link { - parseEmbeddedCategory(embedded["category"]); + parseEmbeddedCategory(embedded["category"], depth); } } @@ -1120,19 +1143,19 @@ void AISUpdate::parseEmbeddedItems(const LLSD& items) } } -void AISUpdate::parseEmbeddedCategory(const LLSD& category) +void AISUpdate::parseEmbeddedCategory(const LLSD& category, S32 depth) { // a single category (_embedded in a link) if (category.has("category_id")) { if (mFetch || mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID())) { - parseCategory(category); + parseCategory(category, depth); } } } -void AISUpdate::parseEmbeddedCategories(const LLSD& categories) +void AISUpdate::parseEmbeddedCategories(const LLSD& categories, S32 depth) { // a map of categories (_embedded in a category) for(LLSD::map_const_iterator categoryit = categories.beginMap(), @@ -1147,7 +1170,7 @@ void AISUpdate::parseEmbeddedCategories(const LLSD& categories) } else { - parseCategory(category_map); + parseCategory(category_map, depth); } } } diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index 58f6a17650..93bbbedb3b 100644 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -85,7 +85,7 @@ private: static void EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc); static void onIdle(void *userdata); // launches postponed AIS commands - static void onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type); + static void onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type, const LLSD& request_body); static std::string getInvCap(); static std::string getLibCap(); @@ -101,21 +101,21 @@ private: class AISUpdate { public: - AISUpdate(const LLSD& update, bool fetch); + AISUpdate(const LLSD& update, bool fetch, S32 depth); void parseUpdate(const LLSD& update); void parseMeta(const LLSD& update); void parseContent(const LLSD& update); void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); void parseLink(const LLSD& link_map); void parseItem(const LLSD& link_map); - void parseCategory(const LLSD& link_map); + void parseCategory(const LLSD& link_map, S32 depth); void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded); - void parseEmbedded(const LLSD& embedded); + void parseEmbedded(const LLSD& embedded, S32 depth); void parseEmbeddedLinks(const LLSD& links); void parseEmbeddedItems(const LLSD& items); - void parseEmbeddedCategories(const LLSD& categories); + void parseEmbeddedCategories(const LLSD& categories, S32 depth); void parseEmbeddedItem(const LLSD& item); - void parseEmbeddedCategory(const LLSD& category); + void parseEmbeddedCategory(const LLSD& category, S32 depth); void doUpdate(); private: void clearParseResults(); @@ -138,6 +138,7 @@ private: uuid_list_t mItemIds; uuid_list_t mCategoryIds; bool mFetch; + S32 mFetchDepth; }; #endif diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 282d234cf3..6cae035fcf 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -478,10 +478,10 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc else { - if (!gInventory.isCategoryComplete(cat_id)) + const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id)); + if (cat) { - const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id)); - if (cat) + if (!gInventory.isCategoryComplete(cat_id)) { if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) { @@ -502,25 +502,24 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc } mFetchCount++; } - // else? - } - else - { - // Already fetched, check if anything inside needs fetching - if (fetch_info.mRecursive) + else { - LLInventoryModel::cat_array_t * categories(NULL); - LLInventoryModel::item_array_t * items(NULL); - gInventory.getDirectDescendentsOf(cat_id, categories, items); - for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); - it != categories->end(); - ++it) + // Already fetched, check if anything inside needs fetching + if (fetch_info.mRecursive) { - // not push_front to not cause an infinite loop - mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); + LLInventoryModel::cat_array_t * categories(NULL); + LLInventoryModel::item_array_t * items(NULL); + gInventory.getDirectDescendentsOf(cat_id, categories, items); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + // not push_front to not cause an infinite loop + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); + } } } - } + } // else? } } else @@ -613,10 +612,10 @@ void LLInventoryModelBackgroundFetch::bulkFetch() } else { - if (!gInventory.isCategoryComplete(cat_id)) + const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id)); + if (cat) { - const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id)); - if (cat) + if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) { LLSD folder_sd; folder_sd["folder_id"] = cat->getUUID(); @@ -635,23 +634,23 @@ void LLInventoryModelBackgroundFetch::bulkFetch() } folder_count++; } + else + { + // May already have this folder, but append child folders to list. + if (fetch_info.mRecursive) + { + LLInventoryModel::cat_array_t * categories(NULL); + LLInventoryModel::item_array_t * items(NULL); + gInventory.getDirectDescendentsOf(cat_id, categories, items); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); + } + } + } } - else - { - // May already have this folder, but append child folders to list. - if (fetch_info.mRecursive) - { - LLInventoryModel::cat_array_t * categories(NULL); - LLInventoryModel::item_array_t * items(NULL); - gInventory.getDirectDescendentsOf(cat_id, categories, items); - for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); - it != categories->end(); - ++it) - { - mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); - } - } - } } if (fetch_info.mRecursive) { diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 07338b7b6b..2f2bc3f91f 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1928,11 +1928,13 @@ const LLUUID& LLViewerInventoryItem::getThumbnailUUID() const } if (mThumbnailUUID.isNull() && mType == LLAssetType::AT_LINK) { - return gInventory.getItem(getLinkedUUID())->getThumbnailUUID(); + LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID); + return linked_item ? linked_item->getThumbnailUUID() : LLUUID::null; } if (mThumbnailUUID.isNull() && mType == LLAssetType::AT_LINK_FOLDER) { - return gInventory.getCategory(getLinkedUUID())->getThumbnailUUID(); + LLViewerInventoryCategory *linked_cat = gInventory.getCategory(mAssetUUID); + return linked_cat ? linked_cat->getThumbnailUUID() : LLUUID::null; } return mThumbnailUUID; } From f98c1403fb47990181c504acfbf5d35a393225b7 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sat, 18 Mar 2023 01:15:27 +0200 Subject: [PATCH 28/31] SL-18674 Reenable folder creation via AIS v3 Add item fetching via AIS v3 --- indra/newview/llaisapi.cpp | 5 -- indra/newview/llaisapi.h | 1 - indra/newview/llinventorymodel.cpp | 3 +- indra/newview/llviewerinventory.cpp | 89 ++++++++++++++++------------- 4 files changed, 49 insertions(+), 49 deletions(-) diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 5e243476d8..ece03d6988 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -632,11 +632,6 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht LL_DEBUGS("Inventory") << result << LL_ENDL; onUpdateReceived("AISCommand", result, type, body); - if (type == FETCHITEM) - { - LL_WARNS() << "test" << LL_ENDL; - } - if (callback && !callback.empty()) { bool needs_callback = true; diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index 93bbbedb3b..dd02951cd4 100644 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -58,7 +58,6 @@ public: static void FetchItem(const LLUUID &itemId, ITEM_TYPE type, completion_t callback = completion_t()); static void FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0); static void FetchCategoryCategories(const LLUUID &catId, ITEM_TYPE type = AISAPI::ITEM_TYPE::INVENTORY, bool recursive = false, completion_t callback = completion_t(), S32 depth = 0); - static void FetchCOF(completion_t callback = completion_t()); static void CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback = completion_t()); private: diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 43bfaf454c..52121d644f 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -996,7 +996,6 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); } -#ifdef USE_AIS_FOR_NC // D567 currently this doesn't really work due to limitations in // AIS3, also violates the common caller assumption that we can // assign the id and return immediately. @@ -1047,7 +1046,7 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, }); return; } -#endif + LLViewerRegion* viewer_region = gAgent.getRegion(); std::string url; if ( viewer_region ) diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 2f2bc3f91f..6f18d72be0 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -430,48 +430,50 @@ void LLViewerInventoryItem::fetchFromServer(void) const { if(!mIsComplete) { - std::string url; + if (AISAPI::isAvailable()) // AIS v 3 + { + if (gAgent.getID() != mPermissions.getOwner()) + { + AISAPI::FetchItem(mUUID, AISAPI::LIBRARY); + } + else + { + AISAPI::FetchItem(mUUID, AISAPI::INVENTORY); + } + } + else + { + std::string url; - 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 - { - LL_WARNS(LOG_INV) << "Agent Region is absent" << LL_ENDL; - } + 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 + { + LL_WARNS(LOG_INV) << "Agent Region is absent" << LL_ENDL; + } - if (!url.empty()) - { - LLSD body; - body["agent_id"] = gAgent.getID(); - body["items"][0]["owner_id"] = mPermissions.getOwner(); - body["items"][0]["item_id"] = mUUID; + if (!url.empty()) + { + LLSD body; + body["agent_id"] = gAgent.getID(); + body["items"][0]["owner_id"] = mPermissions.getOwner(); + body["items"][0]["item_id"] = mUUID; - LLCore::HttpHandler::ptr_t handler(new LLInventoryModel::FetchItemHttpHandler(body)); - gInventory.requestPost(true, url, body, handler, "Inventory Item"); - } - else - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("FetchInventory"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("InventoryData"); - msg->addUUID("OwnerID", mPermissions.getOwner()); - msg->addUUID("ItemID", mUUID); - gAgent.sendReliableMessage(); - } + LLCore::HttpHandler::ptr_t handler(new LLInventoryModel::FetchItemHttpHandler(body)); + gInventory.requestPost(true, url, body, handler, "Inventory Item"); + } + } } } @@ -1033,7 +1035,7 @@ void create_inventory_item( } #ifdef USE_AIS_FOR_NC - // D567 currently this doesn't work due to missing AIS3 support + // D567 18.03.2023 not yet implemented within AIS3 if (AISAPI::isAvailable()) { LLSD new_inventory = LLSD::emptyMap(); @@ -1067,12 +1069,17 @@ void create_inventory_item( 0 /*don't know yet, whenever server creates it*/); LLSD item_sd = item->asLLSD(); new_inventory["items"].append(item_sd); + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); AISAPI::CreateInventory( parent_id, new_inventory, - nullptr); + cr); return; } + else + { + LL_WARNS() << "AIS v3 not available" << LL_ENDL; + } #endif LLMessageSystem* msg = gMessageSystem; From 0a2a1b35649ff405bdccf9e499609af435528300 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sat, 18 Mar 2023 01:15:27 +0200 Subject: [PATCH 29/31] SL-18674 Cleanup --- indra/newview/llinventorymodel.cpp | 66 ------------------------------ indra/newview/llinventorymodel.h | 1 - 2 files changed, 67 deletions(-) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 52121d644f..a6f56c3a9c 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -996,9 +996,6 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id, name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); } - // D567 currently this doesn't really work due to limitations in - // AIS3, also violates the common caller assumption that we can - // assign the id and return immediately. if (AISAPI::isAvailable()) { LLSD new_inventory = LLSD::emptyMap(); @@ -3380,9 +3377,6 @@ void LLInventoryModel::registerCallbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem, processRemoveInventoryItem, NULL); - msg->setHandlerFuncFast(_PREHASH_UpdateInventoryFolder, - processUpdateInventoryFolder, - NULL); msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder, processRemoveInventoryFolder, NULL); @@ -3525,66 +3519,6 @@ void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) gInventory.notifyObservers(); } -// static -void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg, - void**) -{ - LL_DEBUGS(LOG_INV) << "LLInventoryModel::processUpdateInventoryFolder()" << LL_ENDL; - LLUUID agent_id, folder_id, parent_id; - //char name[DB_INV_ITEM_NAME_BUF_SIZE]; - msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS(LOG_INV) << "Got an UpdateInventoryFolder for the wrong agent." - << LL_ENDL; - return; - } - LLPointer lastfolder; // hack - cat_array_t folders; - update_map_t update; - S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); - for(S32 i = 0; i < count; ++i) - { - LLPointer tfolder = new LLViewerInventoryCategory(gAgent.getID()); - lastfolder = tfolder; - tfolder->unpackMessage(msg, _PREHASH_FolderData, i); - // make sure it's not a protected folder - tfolder->setPreferredType(LLFolderType::FT_NONE); - folders.push_back(tfolder); - // examine update for changes. - LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID()); - if(folderp) - { - if(tfolder->getParentUUID() == folderp->getParentUUID()) - { - update[tfolder->getParentUUID()]; - } - else - { - ++update[tfolder->getParentUUID()]; - --update[folderp->getParentUUID()]; - } - } - else - { - ++update[tfolder->getParentUUID()]; - } - } - gInventory.accountForUpdate(update); - for (cat_array_t::iterator it = folders.begin(); it != folders.end(); ++it) - { - gInventory.updateCategory(*it); - } - gInventory.notifyObservers(); - - // *HACK: Do the 'show' logic for a new item in the inventory. - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - if (active_panel) - { - active_panel->setSelection(lastfolder->getUUID(), TAKE_FOCUS_NO); - } -} - // static void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, LLMessageSystem* msg) diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 5e4319bb12..d1ee7b6144 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -662,7 +662,6 @@ public: static void processUpdateCreateInventoryItem(LLMessageSystem* msg, void**); static void removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label); static void processRemoveInventoryItem(LLMessageSystem* msg, void**); - static void processUpdateInventoryFolder(LLMessageSystem* msg, void**); static void removeInventoryFolder(LLUUID agent_id, LLMessageSystem* msg); static void processRemoveInventoryFolder(LLMessageSystem* msg, void**); static void processRemoveInventoryObjects(LLMessageSystem* msg, void**); From 7dad882c2f43b53c1618a4b140bd0b35be6fa106 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sat, 18 Mar 2023 03:05:08 +0200 Subject: [PATCH 30/31] SL-18629 MAC build fix --- indra/newview/llinventorymodel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index a6f56c3a9c..c54a59d12f 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -3748,7 +3748,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) // Temporary workaround: just fetch the item using AIS to get missing fields. // If this works fine we might want to extract ids only from the message // then use AIS as a primary fetcher - AISAPI::FetchCategoryChildren((*cit)->getUUID(), AISAPI::INVENTORY, false); + AISAPI::FetchCategoryChildren((*cit)->getUUID(), AISAPI::INVENTORY); } for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit) { @@ -3757,7 +3757,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) // Temporary workaround: just fetch the item using AIS to get missing fields. // If this works fine we might want to extract ids only from the message // then use AIS as a primary fetcher - AISAPI::FetchItem((*iit)->getUUID(), AISAPI::INVENTORY, false); + AISAPI::FetchItem((*iit)->getUUID(), AISAPI::INVENTORY); } gInventory.notifyObservers(); From 72131418aa943b93f61508993d7006b02ebd9c35 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sun, 19 Mar 2023 16:11:21 +0200 Subject: [PATCH 31/31] SL-18629 Rebuild brocken link on fetch compeltion. --- indra/newview/llinventorymodel.cpp | 47 +++++++++++++++++-- indra/newview/llinventorymodel.h | 6 +++ .../llinventorymodelbackgroundfetch.cpp | 10 +++- .../newview/llinventorymodelbackgroundfetch.h | 5 ++ 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index c54a59d12f..b82f0c3ede 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -41,6 +41,7 @@ #include "llinventorypanel.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryobserver.h" #include "llinventorypanel.h" #include "llfloaterpreviewtrash.h" @@ -439,6 +440,7 @@ LLInventoryModel::LLInventoryModel() mIsNotifyObservers(FALSE), mModifyMask(LLInventoryObserver::ALL), mChangedItemIDs(), + mBulckFecthCallbackSlot(), mObservers(), mHttpRequestFG(NULL), mHttpRequestBG(NULL), @@ -470,6 +472,11 @@ void LLInventoryModel::cleanupInventory() mObservers.erase(iter); delete observer; } + + if (mBulckFecthCallbackSlot.connected()) + { + mBulckFecthCallbackSlot.disconnect(); + } mObservers.clear(); // Run down HTTP transport @@ -1750,6 +1757,15 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, notifyObservers(); } +void LLInventoryModel::rebuildBrockenLinks() +{ + for (LLUUID link_id : mPossiblyBrockenLinks) + { + addChangedMask(LLInventoryObserver::REBUILD, link_id); + } + mPossiblyBrockenLinks.clear(); +} + // Does not appear to be used currently. void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version) { @@ -2368,9 +2384,34 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) // The item will show up as a broken link. if (item->getIsBrokenLink()) { - LL_INFOS(LOG_INV) << "Adding broken link [ name: " << item->getName() - << " itemID: " << item->getUUID() - << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL; + if (!LLInventoryModelBackgroundFetch::getInstance()->isEverythingFetched()) + { + // isEverythingFetched is actually 'initial' fetch only. + // Schedule this link for a recheck once inventory gets loaded + mPossiblyBrockenLinks.insert(item->getUUID()); + if (!mBulckFecthCallbackSlot.connected()) + { + // Links might take a while to update this way, and there + // might be a lot of them. A better option might be to check + // links periodically with final check on fetch completion. + mBulckFecthCallbackSlot = + LLInventoryModelBackgroundFetch::getInstance()->setAllFoldersFetchedCallback( + []() + { + gInventory.rebuildBrockenLinks(); + }); + } + LL_DEBUGS(LOG_INV) << "Scheduling a link to be rebuilt later [ name: " << item->getName() + << " itemID: " << item->getUUID() + << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL; + + } + else + { + LL_INFOS(LOG_INV) << "Adding broken link [ name: " << item->getName() + << " itemID: " << item->getUUID() + << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL; + } } if (item->getIsLinkType()) { diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index d1ee7b6144..02278ed957 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -407,6 +407,10 @@ public: const LLUUID& new_parent_id, BOOL restamp); + // Marks links from a "possibly" broken list for a rebuild + // clears the list + void rebuildBrockenLinks(); + //-------------------------------------------------------------------- // Delete //-------------------------------------------------------------------- @@ -574,6 +578,8 @@ private: U32 mModifyMaskBacklog; changed_items_t mChangedItemIDsBacklog; changed_items_t mAddedItemIDsBacklog; + changed_items_t mPossiblyBrockenLinks; + boost::signals2::connection mBulckFecthCallbackSlot; //-------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 6cae035fcf..ea721b3a40 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -347,12 +347,20 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched() mAllFoldersFetched = true; //LL_INFOS(LOG_INV) << "All folders fetched, validating" << LL_ENDL; //gInventory.validate(); + + // For now only informs about initial fetch being done + mAllFoldersFetchedSignal(); } mFolderFetchActive = false; mBackgroundFetchActive = false; LL_INFOS(LOG_INV) << "Inventory background fetch completed" << LL_ENDL; } +boost::signals2::connection LLInventoryModelBackgroundFetch::setAllFoldersFetchedCallback(folders_fetched_callback_t cb) +{ + return mAllFoldersFetchedSignal.connect(cb); +} + void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *) { LLInventoryModelBackgroundFetch::instance().backgroundFetch(); @@ -481,7 +489,7 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id)); if (cat) { - if (!gInventory.isCategoryComplete(cat_id)) + if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) { if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) { diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index 14557ea92d..038b634180 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -68,6 +68,9 @@ public: bool isBulkFetchProcessingComplete() const; void setAllFoldersFetched(); + typedef boost::function folders_fetched_callback_t; + boost::signals2::connection setAllFoldersFetchedCallback(folders_fetched_callback_t cb); + void addRequestAtFront(const LLUUID & id, bool recursive, bool is_category); void addRequestAtBack(const LLUUID & id, bool recursive, bool is_category); @@ -106,6 +109,8 @@ private: bool mRecursiveInventoryFetchStarted; bool mRecursiveLibraryFetchStarted; bool mAllFoldersFetched; + typedef boost::signals2::signal folders_fetched_signal_t; + folders_fetched_signal_t mAllFoldersFetchedSignal; bool mBackgroundFetchActive; bool mFolderFetchActive;