From 38ce446a02375a46db08c1e1176ec4c9c60e3814 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 17 Dec 2020 15:23:04 +0000 Subject: [PATCH 001/286] SL-14570 - detailed breakdown of system folder issues in inventory validation. More info about expected state of system folders in llfoldertype --- indra/llinventory/llfoldertype.cpp | 117 +++++++---- indra/llinventory/llfoldertype.h | 2 + indra/newview/llinventorymodel.cpp | 300 +++++++++++++++++++++-------- indra/newview/llinventorymodel.h | 20 +- indra/newview/llstartup.cpp | 11 ++ 5 files changed, 335 insertions(+), 115 deletions(-) diff --git a/indra/llinventory/llfoldertype.cpp b/indra/llinventory/llfoldertype.cpp index 7241b3c0c2..675da65af2 100644 --- a/indra/llinventory/llfoldertype.cpp +++ b/indra/llinventory/llfoldertype.cpp @@ -37,15 +37,22 @@ struct FolderEntry : public LLDictionaryEntry { FolderEntry(const std::string &type_name, // 8 character limit! - bool is_protected) // can the viewer change categories of this type? + bool is_protected, // can the viewer change categories of this type? + bool is_automatic, // always made before first login? + bool is_singleton // should exist as a unique copy under root + ) : LLDictionaryEntry(type_name), - mIsProtected(is_protected) + mIsProtected(is_protected), + mIsAutomatic(is_automatic), + mIsSingleton(is_singleton) { llassert(type_name.length() <= 8); } const bool mIsProtected; + const bool mIsAutomatic; + const bool mIsSingleton; }; class LLFolderDictionary : public LLSingleton, @@ -59,50 +66,64 @@ protected: } }; +// Folder types +// +// PROTECTED means that folders of this type can't be moved, deleted +// or otherwise modified by the viewer. +// +// SINGLETON means that there should always be exactly one folder of +// this type, and it should be the root or a child of the root. This +// is true for most types of folders. +// +// AUTOMATIC means that a copy of this folder should be created under +// the root before the user ever logs in, and should never be created +// from the viewer. A missing AUTOMATIC folder should be treated as a +// fatal error by the viewer, since it indicates either corrupted +// inventory or a failure in the inventory services. +// LLFolderDictionary::LLFolderDictionary() { - // TYPE NAME PROTECTED - // |-----------|---------| - addEntry(LLFolderType::FT_TEXTURE, new FolderEntry("texture", TRUE)); - addEntry(LLFolderType::FT_SOUND, new FolderEntry("sound", TRUE)); - addEntry(LLFolderType::FT_CALLINGCARD, new FolderEntry("callcard", TRUE)); - addEntry(LLFolderType::FT_LANDMARK, new FolderEntry("landmark", TRUE)); - addEntry(LLFolderType::FT_CLOTHING, new FolderEntry("clothing", TRUE)); - addEntry(LLFolderType::FT_OBJECT, new FolderEntry("object", TRUE)); - addEntry(LLFolderType::FT_NOTECARD, new FolderEntry("notecard", TRUE)); - addEntry(LLFolderType::FT_ROOT_INVENTORY, new FolderEntry("root_inv", TRUE)); - addEntry(LLFolderType::FT_LSL_TEXT, new FolderEntry("lsltext", TRUE)); - addEntry(LLFolderType::FT_BODYPART, new FolderEntry("bodypart", TRUE)); - addEntry(LLFolderType::FT_TRASH, new FolderEntry("trash", TRUE)); - addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new FolderEntry("snapshot", TRUE)); - addEntry(LLFolderType::FT_LOST_AND_FOUND, new FolderEntry("lstndfnd", TRUE)); - addEntry(LLFolderType::FT_ANIMATION, new FolderEntry("animatn", TRUE)); - addEntry(LLFolderType::FT_GESTURE, new FolderEntry("gesture", TRUE)); - addEntry(LLFolderType::FT_FAVORITE, new FolderEntry("favorite", TRUE)); + // TYPE NAME, PROTECTED, AUTOMATIC, SINGLETON + addEntry(LLFolderType::FT_TEXTURE, new FolderEntry("texture", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_SOUND, new FolderEntry("sound", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_CALLINGCARD, new FolderEntry("callcard", TRUE, TRUE, FALSE)); + addEntry(LLFolderType::FT_LANDMARK, new FolderEntry("landmark", TRUE, FALSE, FALSE)); + addEntry(LLFolderType::FT_CLOTHING, new FolderEntry("clothing", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_OBJECT, new FolderEntry("object", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_NOTECARD, new FolderEntry("notecard", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_ROOT_INVENTORY, new FolderEntry("root_inv", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_LSL_TEXT, new FolderEntry("lsltext", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_BODYPART, new FolderEntry("bodypart", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_TRASH, new FolderEntry("trash", TRUE, FALSE, TRUE)); + addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new FolderEntry("snapshot", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_LOST_AND_FOUND, new FolderEntry("lstndfnd", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_ANIMATION, new FolderEntry("animatn", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_GESTURE, new FolderEntry("gesture", TRUE, TRUE, TRUE)); + addEntry(LLFolderType::FT_FAVORITE, new FolderEntry("favorite", TRUE, FALSE, TRUE)); for (S32 ensemble_num = S32(LLFolderType::FT_ENSEMBLE_START); ensemble_num <= S32(LLFolderType::FT_ENSEMBLE_END); ensemble_num++) { - addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE)); + addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE, FALSE, FALSE)); // Not used } - addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE)); - addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE)); - addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE)); + addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE, FALSE, TRUE)); + addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE, FALSE, FALSE)); + addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE, FALSE, TRUE)); - addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE)); + addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE, FALSE, FALSE)); // Not used? - addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE)); - addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE)); + addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE, FALSE, TRUE)); + addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE, FALSE, FALSE)); - addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE)); + addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE, FALSE, FALSE)); - addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new FolderEntry("merchant", FALSE)); - addEntry(LLFolderType::FT_MARKETPLACE_STOCK, new FolderEntry("stock", FALSE)); - addEntry(LLFolderType::FT_MARKETPLACE_VERSION, new FolderEntry("version", FALSE)); + addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new FolderEntry("merchant", FALSE, FALSE, FALSE)); + addEntry(LLFolderType::FT_MARKETPLACE_STOCK, new FolderEntry("stock", FALSE, FALSE, FALSE)); + addEntry(LLFolderType::FT_MARKETPLACE_VERSION, new FolderEntry("version", FALSE, FALSE, FALSE)); - addEntry(LLFolderType::FT_SETTINGS, new FolderEntry("settings", TRUE)); + addEntry(LLFolderType::FT_SETTINGS, new FolderEntry("settings", TRUE, FALSE, TRUE)); - addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE)); + addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE, FALSE, FALSE)); }; // static @@ -126,8 +147,8 @@ const std::string &LLFolderType::lookup(LLFolderType::EType folder_type) } // static -// Only ensembles and plain folders aren't protected. "Protected" means -// you can't change certain properties such as their type. +// Only plain folders and a few other types aren't protected. "Protected" means +// you can't move, deleted, or change certain properties such as their type. bool LLFolderType::lookupIsProtectedType(EType folder_type) { const LLFolderDictionary *dict = LLFolderDictionary::getInstance(); @@ -138,6 +159,32 @@ bool LLFolderType::lookupIsProtectedType(EType folder_type) } return true; } + +// static +// Is this folder type automatically created outside the viewer? +bool LLFolderType::lookupIsAutomaticType(EType folder_type) +{ + const LLFolderDictionary *dict = LLFolderDictionary::getInstance(); + const FolderEntry *entry = dict->lookup(folder_type); + if (entry) + { + return entry->mIsAutomatic; + } + return true; +} + +// static +// Should this folder always exist as a single copy under (or as) the root? +bool LLFolderType::lookupIsSingletonType(EType folder_type) +{ + const LLFolderDictionary *dict = LLFolderDictionary::getInstance(); + const FolderEntry *entry = dict->lookup(folder_type); + if (entry) + { + return entry->mIsSingleton; + } + return true; +} // static bool LLFolderType::lookupIsEnsembleType(EType folder_type) diff --git a/indra/llinventory/llfoldertype.h b/indra/llinventory/llfoldertype.h index 85b86f9ce5..1f174520da 100644 --- a/indra/llinventory/llfoldertype.h +++ b/indra/llinventory/llfoldertype.h @@ -102,6 +102,8 @@ public: static const std::string& lookup(EType folder_type); static bool lookupIsProtectedType(EType folder_type); + static bool lookupIsAutomaticType(EType folder_type); + static bool lookupIsSingletonType(EType folder_type); static bool lookupIsEnsembleType(EType folder_type); static LLAssetType::EType folderTypeToAssetType(LLFolderType::EType folder_type); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 28db6a5808..1da5a71710 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -67,6 +67,9 @@ #include "process.h" #endif +#include +#include + // Increment this if the inventory contents change in a non-backwards-compatible way. // For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect. const S32 LLInventoryModel::sCurrentInvCacheVersion = 2; @@ -128,6 +131,27 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) return rv; } +///---------------------------------------------------------------------------- +/// Class LLInventoryValidationInfo +///---------------------------------------------------------------------------- +LLInventoryValidationInfo::LLInventoryValidationInfo(): + mFatalErrorCount(0), + mWarningCount(0) +{ +} + +void LLInventoryValidationInfo::toOstream(std::ostream& os) const +{ + os << "mFatalErrorCount " << mFatalErrorCount << " mWarningCount " << mWarningCount; +} + +std::ostream& operator<<(std::ostream& os, const LLInventoryValidationInfo& v) +{ + v.toOstream(os); + return os; +} + + ///---------------------------------------------------------------------------- /// Class LLInventoryModel ///---------------------------------------------------------------------------- @@ -568,20 +592,29 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, const std::string& pname, inventory_func_type callback) { - LLUUID id; if(!isInventoryUsable()) { LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + // FIXME failing but still returning an id? return id; } if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) { LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; + // FIXME failing but still returning an id? return id; } + if (preferred_type != LLFolderType::FT_NONE) + { + // Ultimately this should only be done for non-singleton + // types. Requires back-end changes to guarantee that others + // already exist. + LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL; + } + id.generate(); std::string name = pname; if(!pname.empty()) @@ -611,7 +644,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, request["message"] = "CreateInventoryCategory"; request["payload"] = body; - LL_DEBUGS(LOG_INV) << "create category request: " << ll_pretty_print_sd(request) << LL_ENDL; + 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)); @@ -623,6 +656,10 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, return LLUUID::null; } + // 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 LLPointer cat = new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); @@ -632,6 +669,8 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, 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; @@ -2576,11 +2615,6 @@ void LLInventoryModel::buildParentChildMap() // observers start firing. } } - - if (!gInventory.validate()) - { - LL_WARNS(LOG_INV) << "model failed validity check!" << LL_ENDL; - } } // Would normally do this at construction but that's too early @@ -3701,57 +3735,84 @@ void LLInventoryModel::dumpInventory() const LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL; } -// Do various integrity checks on model, logging issues found and -// returning an overall good/bad flag. -bool LLInventoryModel::validate() const +std::string get_full_path(const LLInventoryObject *cat) { - bool valid = true; + std::vector path_elts; + std::map visited; + while (cat != NULL && !visited[cat->getUUID()]) + { + path_elts.push_back(cat->getName()); + // avoid infinite loop in the unlikely event of a cycle + visited[cat->getUUID()] = true; + cat = gInventory.getObject(cat->getParentUUID()); + } + std::stringstream s; + std::string delim("/"); + std::reverse(path_elts.begin(), path_elts.end()); + std::string result = "/" + boost::algorithm::join(path_elts, delim); + return result; +} + +// Do various integrity checks on model, logging issues found and +// returning an overall good/bad flag. +LLPointer LLInventoryModel::validate() const +{ + LLPointer validation_info = new LLInventoryValidationInfo; + S32 fatalities = 0; + S32 warnings = 0; if (getRootFolderID().isNull()) { - LL_WARNS() << "no root folder id" << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "no root folder id" << LL_ENDL; + fatalities++; } if (getLibraryRootFolderID().isNull()) { - LL_WARNS() << "no root folder id" << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "no library root folder id" << LL_ENDL; + fatalities++; } if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) { // ParentChild should be one larger because of the special entry for null uuid. - LL_INFOS() << "unexpected sizes: cat map size " << mCategoryMap.size() - << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; - valid = false; + LL_INFOS("Inventory") << "unexpected sizes: cat map size " << mCategoryMap.size() + << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; + warnings++; } S32 cat_lock = 0; S32 item_lock = 0; S32 desc_unknown_count = 0; S32 version_unknown_count = 0; + + typedef std::map ft_count_map; + ft_count_map ft_counts_under_root; + ft_count_map ft_counts_elsewhere; + + // Loop over all categories and check. for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) { const LLUUID& cat_id = cit->first; const LLViewerInventoryCategory *cat = cit->second; if (!cat) { - LL_WARNS() << "invalid cat" << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "null cat" << LL_ENDL; + warnings++; continue; } if (cat_id != cat->getUUID()) { - LL_WARNS() << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; + warnings++; } if (cat->getParentUUID().isNull()) { if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) { - LL_WARNS() << "cat " << cat_id << " has no parent, but is not root (" - << getRootFolderID() << ") or library root (" - << getLibraryRootFolderID() << ")" << LL_ENDL; + LL_WARNS("Inventory") << "cat " << cat_id << " has no parent, but is not root (" + << getRootFolderID() << ") or library root (" + << getLibraryRootFolderID() << ")" << LL_ENDL; + warnings++; } } cat_array_t* cats; @@ -3759,8 +3820,8 @@ bool LLInventoryModel::validate() const getDirectDescendentsOf(cat_id,cats,items); if (!cats || !items) { - LL_WARNS() << "invalid direct descendents for " << cat_id << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "invalid direct descendents for " << cat_id << LL_ENDL; + warnings++; continue; } if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) @@ -3769,12 +3830,12 @@ bool LLInventoryModel::validate() const } else if (cats->size() + items->size() != cat->getDescendentCount()) { - LL_WARNS() << "invalid desc count for " << cat_id << " name [" << cat->getName() - << "] parent " << cat->getParentUUID() - << " cached " << cat->getDescendentCount() - << " expected " << cats->size() << "+" << items->size() - << "=" << cats->size() +items->size() << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "invalid desc count for " << cat_id << " name [" << cat->getName() + << "] parent " << cat->getParentUUID() + << " cached " << cat->getDescendentCount() + << " expected " << cats->size() << "+" << items->size() + << "=" << cats->size() +items->size() << LL_ENDL; + warnings++; } if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) { @@ -3794,8 +3855,8 @@ bool LLInventoryModel::validate() const if (!item) { - LL_WARNS() << "null item at index " << i << " for cat " << cat_id << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "null item at index " << i << " for cat " << cat_id << LL_ENDL; + warnings++; continue; } @@ -3803,10 +3864,10 @@ bool LLInventoryModel::validate() const if (item->getParentUUID() != cat_id) { - LL_WARNS() << "wrong parent for " << item_id << " found " - << item->getParentUUID() << " expected " << cat_id - << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "wrong parent for " << item_id << " found " + << item->getParentUUID() << " expected " << cat_id + << LL_ENDL; + warnings++; } @@ -3814,17 +3875,17 @@ bool LLInventoryModel::validate() const item_map_t::const_iterator it = mItemMap.find(item_id); if (it == mItemMap.end()) { - LL_WARNS() << "item " << item_id << " found as child of " - << cat_id << " but not in top level mItemMap" << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "item " << item_id << " found as child of " + << cat_id << " but not in top level mItemMap" << LL_ENDL; + warnings++; } else { LLViewerInventoryItem *top_item = it->second; if (top_item != item) { - LL_WARNS() << "item mismatch, item_id " << item_id - << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; + LL_WARNS("Inventory") << "item mismatch, item_id " << item_id + << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; } } @@ -3833,19 +3894,19 @@ bool LLInventoryModel::validate() const bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); if (!found) { - LL_WARNS() << "unable to find topmost ancestor for " << item_id << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "unable to find topmost ancestor for " << item_id << LL_ENDL; + warnings++; } else { if (topmost_ancestor_id != getRootFolderID() && topmost_ancestor_id != getLibraryRootFolderID()) { - LL_WARNS() << "unrecognized top level ancestor for " << item_id - << " got " << topmost_ancestor_id - << " expected " << getRootFolderID() - << " or " << getLibraryRootFolderID() << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "unrecognized top level ancestor for " << item_id + << " got " << topmost_ancestor_id + << " expected " << getRootFolderID() + << " or " << getLibraryRootFolderID() << LL_ENDL; + warnings++; } } } @@ -3859,9 +3920,9 @@ bool LLInventoryModel::validate() const getDirectDescendentsOf(parent_id,cats,items); if (!cats) { - LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; + warnings++; } else { @@ -3877,27 +3938,56 @@ bool LLInventoryModel::validate() const } if (!found) { - LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() - << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + LL_WARNS("Inventory") << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + } + } + } + + // Update count of preferred types + LLFolderType::EType folder_type = cat->getPreferredType(); + bool cat_is_in_library = false; + LLUUID topmost_id; + if (getObjectTopmostAncestor(cat->getUUID(),topmost_id) && topmost_id == getLibraryRootFolderID()) + { + cat_is_in_library = true; + } + if (!cat_is_in_library) + { + if (getRootFolderID().notNull() && (cat->getUUID()==getRootFolderID() || cat->getParentUUID()==getRootFolderID())) + { + ft_counts_under_root[folder_type]++; + if (folder_type != LLFolderType::FT_NONE) + { + LL_DEBUGS("Inventory") << "Under root cat: " << get_full_path(cat) << " folder_type " << folder_type << LL_ENDL; + } + } + else + { + ft_counts_elsewhere[folder_type]++; + if (folder_type != LLFolderType::FT_NONE) + { + LL_DEBUGS("Inventory") << "Elsewhere cat: " << get_full_path(cat) << " folder_type " << folder_type << LL_ENDL; } } } } + // Loop over all items and check for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) { const LLUUID& item_id = iit->first; LLViewerInventoryItem *item = iit->second; if (item->getUUID() != item_id) { - LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; - valid = false; + LL_WARNS("Inventory") << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; + warnings++; } const LLUUID& parent_id = item->getParentUUID(); if (parent_id.isNull()) { - LL_WARNS() << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; } else { @@ -3906,8 +3996,8 @@ bool LLInventoryModel::validate() const getDirectDescendentsOf(parent_id,cats,items); if (!items) { - LL_WARNS() << "item " << item_id << " name [" << item->getName() - << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() + << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; } else { @@ -3922,8 +4012,8 @@ bool LLInventoryModel::validate() const } if (!found) { - LL_WARNS() << "item " << item_id << " name [" << item->getName() - << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; + LL_WARNS("Inventory") << "item " << item_id << " name [" << item->getName() + << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; } } @@ -3938,30 +4028,30 @@ bool LLInventoryModel::validate() const // Linked-to UUID should have back reference to this link. if (!hasBacklinkInfo(link_id, target_id)) { - LL_WARNS() << "link " << item->getUUID() << " type " << item->getActualType() - << " missing backlink info at target_id " << target_id - << LL_ENDL; + LL_WARNS("Inventory") << "link " << item->getUUID() << " type " << item->getActualType() + << " missing backlink info at target_id " << target_id + << LL_ENDL; } // Links should have referents. if (item->getActualType() == LLAssetType::AT_LINK && !target_item) { - LL_WARNS() << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + LL_WARNS("Inventory") << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; } else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) { - LL_WARNS() << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + LL_WARNS("Inventory") << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; } if (target_item && target_item->getIsLinkType()) { - LL_WARNS() << "link " << item->getName() << " references a link item " - << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; + LL_WARNS("Inventory") << "link " << item->getName() << " references a link item " + << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; } // Links should not have backlinks. std::pair range = mBacklinkMMap.equal_range(link_id); if (range.first != range.second) { - LL_WARNS() << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; + LL_WARNS("Inventory") << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; } } else @@ -3975,15 +4065,66 @@ bool LLInventoryModel::validate() const LLViewerInventoryItem *link_item = getItem(link_id); if (!link_item || !link_item->getIsLinkType()) { - LL_WARNS() << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; + LL_WARNS("Inventory") << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; } } } } - + + // Check system folders + for (auto fit=ft_counts_under_root.begin(); fit != ft_counts_under_root.end(); ++fit) + { + LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " under root" << LL_ENDL; + } + for (auto fit=ft_counts_elsewhere.begin(); fit != ft_counts_elsewhere.end(); ++fit) + { + LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " elsewhere" << LL_ENDL; + } + for (S32 ft=LLFolderType::FT_TEXTURE; ft(ft); + if (LLFolderType::lookup(folder_type)==LLFolderType::badLookup()) + { + continue; + } + bool is_automatic = LLFolderType::lookupIsAutomaticType(folder_type); + bool is_singleton = LLFolderType::lookupIsSingletonType(folder_type); + S32 count_under_root = ft_counts_under_root[folder_type]; + S32 count_elsewhere = ft_counts_elsewhere[folder_type]; + if (is_singleton) + { + if (count_under_root==0) + { + LL_WARNS("Inventory") << "Expected system folder type " << ft << " was not found under root" << LL_ENDL; + // Need to create, if allowed. + if (is_automatic) + { + LL_WARNS("Inventory") << "Cannot create system folder of type " << ft << LL_ENDL; + fatalities++; + } + else + { + // Can create, and will when needed. + warnings++; + } + } + else if (count_under_root > 1) + { + LL_WARNS("Inventory") << "System folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; + fatalities++; + } + if (count_elsewhere > 0) + { + LL_WARNS("Inventory") << "Found " << count_elsewhere << " extra folders of type " << ft << " outside of root" << LL_ENDL; + warnings++; + } + } + } + + if (cat_lock > 0 || item_lock > 0) { - LL_INFOS() << "Found locks on some categories: sub-cat arrays " + LL_INFOS("Inventory") << "Found locks on some categories: sub-cat arrays " << cat_lock << ", item arrays " << item_lock << LL_ENDL; } if (desc_unknown_count != 0) @@ -3992,12 +4133,17 @@ bool LLInventoryModel::validate() const } if (version_unknown_count != 0) { - LL_INFOS() << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; + LL_INFOS("Inventory") << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; } - LL_INFOS() << "Validate done, valid = " << (U32) valid << LL_ENDL; + // FIXME need to fail login and tell user to retry, contact support if problem persists. + bool valid = (fatalities + warnings == 0); + LL_INFOS("Inventory") << "Validate done, valid = " << (U32) valid << LL_ENDL; - return valid; + validation_info->mFatalErrorCount = fatalities; + validation_info->mWarningCount = warnings; + + return validation_info; } ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index a4326aaeed..687d2d497c 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -55,7 +55,21 @@ class LLInventoryCategory; class LLMessageSystem; class LLInventoryCollectFunctor; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +///---------------------------------------------------------------------------- +/// LLInventoryValidationInfo +///---------------------------------------------------------------------------- +class LLInventoryValidationInfo: public LLRefCount +{ +public: + LLInventoryValidationInfo(); + void toOstream(std::ostream& os) const; + + S32 mFatalErrorCount; + S32 mWarningCount; +}; +std::ostream& operator<<(std::ostream& s, const LLInventoryValidationInfo& v); + +///---------------------------------------------------------------------------- // LLInventoryModel // // Represents a collection of inventory, and provides efficient ways to access @@ -63,7 +77,7 @@ class LLInventoryCollectFunctor; // NOTE: This class could in theory be used for any place where you need // inventory, though it optimizes for time efficiency - not space efficiency, // probably making it inappropriate for use on tasks. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +///---------------------------------------------------------------------------- class LLInventoryModel { LOG_CLASS(LLInventoryModel); @@ -656,7 +670,7 @@ private: //-------------------------------------------------------------------- public: void dumpInventory() const; - bool validate() const; + LLPointer validate() const; /** Miscellaneous ** ** diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 17777c3ceb..603f790815 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1807,6 +1807,13 @@ bool idle_startup() // This method MUST be called before gInventory.findCategoryUUIDForType because of // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. gInventory.buildParentChildMap(); + + // If inventory is unusable, need to flag this and + // bail out. In particular, must not trigger creation of new system + // categories. + LLPointer validation_info = gInventory.validate(); + // FIXME add handling of unfixable corruption here - need to exit and get support to fix. + gInventory.createCommonSystemCategories(); // It's debatable whether this flag is a good idea - sets all @@ -1850,6 +1857,10 @@ bool idle_startup() display_startup(); LLStartUp::setStartupState( STATE_MISC ); display_startup(); + + // Update status check after various system folders created. + validation_info = gInventory.validate(); + return FALSE; } From da982a227ab69cb91e2c87efcabc0ce11a0c2fa5 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 17 Dec 2020 17:06:07 +0000 Subject: [PATCH 002/286] SL-14570 - added getFullPath(), cleaned up logging at bit --- indra/newview/llinventorymodel.cpp | 66 ++++++++++++++++-------------- indra/newview/llinventorymodel.h | 1 + 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 1da5a71710..e5ff96095a 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2286,11 +2286,11 @@ bool LLInventoryModel::loadSkeleton( } } - LL_INFOS(LOG_INV) << "Attempted to add " << bad_link_count - << " cached link items without baseobj present. " - << good_link_count << " link items were successfully added. " - << recovered_link_count << " links added in recovery. " - << "The corresponding categories were invalidated." << LL_ENDL; + LL_DEBUGS(LOG_INV) << "Attempted to add " << bad_link_count + << " cached link items without baseobj present. " + << good_link_count << " link items were successfully added. " + << recovered_link_count << " links added in recovery. " + << "The corresponding categories were invalidated." << LL_ENDL; } } @@ -2316,7 +2316,10 @@ bool LLInventoryModel::loadSkeleton( cat->setVersion(NO_VERSION); LL_DEBUGS(LOG_INV) << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << LL_ENDL; } - LL_INFOS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; + if (invalid_categories.size() > 0) + { + LL_DEBUGS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; + } // At this point, we need to set the known descendents for each // category which successfully cached so that we do not @@ -3735,24 +3738,6 @@ void LLInventoryModel::dumpInventory() const LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL; } -std::string get_full_path(const LLInventoryObject *cat) -{ - std::vector path_elts; - std::map visited; - while (cat != NULL && !visited[cat->getUUID()]) - { - path_elts.push_back(cat->getName()); - // avoid infinite loop in the unlikely event of a cycle - visited[cat->getUUID()] = true; - cat = gInventory.getObject(cat->getParentUUID()); - } - std::stringstream s; - std::string delim("/"); - std::reverse(path_elts.begin(), path_elts.end()); - std::string result = "/" + boost::algorithm::join(path_elts, delim); - return result; -} - // Do various integrity checks on model, logging issues found and // returning an overall good/bad flag. LLPointer LLInventoryModel::validate() const @@ -3841,11 +3826,13 @@ LLPointer LLInventoryModel::validate() const { version_unknown_count++; } - if (mCategoryLock.count(cat_id)) + auto cat_lock_it = mCategoryLock.find(cat_id); + if (cat_lock_it != mCategoryLock.end() && cat_lock_it->second) { cat_lock++; } - if (mItemLock.count(cat_id)) + auto item_lock_it = mItemLock.find(cat_id); + if (item_lock_it != mItemLock.end() && item_lock_it->second) { item_lock++; } @@ -3959,7 +3946,7 @@ LLPointer LLInventoryModel::validate() const ft_counts_under_root[folder_type]++; if (folder_type != LLFolderType::FT_NONE) { - LL_DEBUGS("Inventory") << "Under root cat: " << get_full_path(cat) << " folder_type " << folder_type << LL_ENDL; + LL_DEBUGS("Inventory") << "Under root cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; } } else @@ -3967,7 +3954,7 @@ LLPointer LLInventoryModel::validate() const ft_counts_elsewhere[folder_type]++; if (folder_type != LLFolderType::FT_NONE) { - LL_DEBUGS("Inventory") << "Elsewhere cat: " << get_full_path(cat) << " folder_type " << folder_type << LL_ENDL; + LL_DEBUGS("Inventory") << "Elsewhere cat: " << getFullPath(cat) << " folder_type " << folder_type << LL_ENDL; } } } @@ -4129,11 +4116,11 @@ LLPointer LLInventoryModel::validate() const } if (desc_unknown_count != 0) { - LL_INFOS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; + LL_DEBUGS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; } if (version_unknown_count != 0) { - LL_INFOS("Inventory") << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; + LL_DEBUGS("Inventory") << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; } // FIXME need to fail login and tell user to retry, contact support if problem persists. @@ -4146,6 +4133,25 @@ LLPointer LLInventoryModel::validate() const return validation_info; } +// Provides a unix-style path from root, like "/My Inventory/Clothing/.../myshirt" +std::string LLInventoryModel::getFullPath(const LLInventoryObject *obj) const +{ + std::vector path_elts; + std::map visited; + while (obj != NULL && !visited[obj->getUUID()]) + { + path_elts.push_back(obj->getName()); + // avoid infinite loop in the unlikely event of a cycle + visited[obj->getUUID()] = true; + obj = getObject(obj->getParentUUID()); + } + std::stringstream s; + std::string delim("/"); + std::reverse(path_elts.begin(), path_elts.end()); + std::string result = "/" + boost::algorithm::join(path_elts, delim); + return result; +} + ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 687d2d497c..caba78988e 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -671,6 +671,7 @@ private: public: void dumpInventory() const; LLPointer validate() const; + std::string getFullPath(const LLInventoryObject *obj) const; /** Miscellaneous ** ** From 9156c22f73b6706a3f480d0fd72ed04a7de8187b Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 17 Dec 2020 20:33:19 +0000 Subject: [PATCH 003/286] SL-14570 - error reporting and prevention --- indra/newview/llattachmentsmgr.cpp | 112 +++++++++++++++-------------- indra/newview/llinventorymodel.cpp | 33 ++++++--- indra/newview/llstartup.cpp | 13 ++-- 3 files changed, 88 insertions(+), 70 deletions(-) diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index d3e66289d1..443c5ae02f 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -99,22 +99,22 @@ void LLAttachmentsMgr::onIdle() return; } - if (LLApp::isExiting()) - { - return; - } + if (LLApp::isExiting()) + { + return; + } requestPendingAttachments(); - linkRecentlyArrivedAttachments(); + linkRecentlyArrivedAttachments(); - expireOldAttachmentRequests(); + expireOldAttachmentRequests(); - expireOldDetachRequests(); + expireOldDetachRequests(); - checkInvalidCOFLinks(); - - spamStatusInfo(); + checkInvalidCOFLinks(); + + spamStatusInfo(); } void LLAttachmentsMgr::requestPendingAttachments() @@ -452,51 +452,55 @@ bool LLAttachmentsMgr::isAttachmentStateComplete() const // void LLAttachmentsMgr::checkInvalidCOFLinks() { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), - cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); - for (S32 i=0; igetLinkedUUID(); - if (inv_item->getType() == LLAssetType::AT_OBJECT) - { - LLTimer timer; - bool is_flagged_questionable = mQuestionableCOFLinks.getTime(item_id,timer); - bool is_wearing_attachment = isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item_id); - if (is_wearing_attachment && is_flagged_questionable) - { - LL_DEBUGS("Avatar") << "ATT was flagged questionable but is now " - << (is_wearing_attachment ? "attached " : "") - <<"removing flag after " - << timer.getElapsedTimeF32() << " item " - << inv_item->getName() << " id " << item_id << LL_ENDL; - mQuestionableCOFLinks.removeTime(item_id); - } - } - } + if (!gInventory.isInventoryUsable()) + { + return; + } + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), + cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); + for (S32 i=0; igetLinkedUUID(); + if (inv_item->getType() == LLAssetType::AT_OBJECT) + { + LLTimer timer; + bool is_flagged_questionable = mQuestionableCOFLinks.getTime(item_id,timer); + bool is_wearing_attachment = isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item_id); + if (is_wearing_attachment && is_flagged_questionable) + { + LL_DEBUGS("Avatar") << "ATT was flagged questionable but is now " + << (is_wearing_attachment ? "attached " : "") + <<"removing flag after " + << timer.getElapsedTimeF32() << " item " + << inv_item->getName() << " id " << item_id << LL_ENDL; + mQuestionableCOFLinks.removeTime(item_id); + } + } + } - for(LLItemRequestTimes::iterator it = mQuestionableCOFLinks.begin(); - it != mQuestionableCOFLinks.end(); ) - { - LLItemRequestTimes::iterator curr_it = it; - ++it; - const LLUUID& item_id = curr_it->first; - LLViewerInventoryItem *inv_item = gInventory.getItem(item_id); - if (curr_it->second.getElapsedTimeF32() > MAX_BAD_COF_TIME) - { - if (LLAppearanceMgr::instance().isLinkedInCOF(item_id)) - { - LL_DEBUGS("Avatar") << "ATT Linked in COF but not attached or requested, deleting link after " - << curr_it->second.getElapsedTimeF32() << " seconds for " - << (inv_item ? inv_item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; - LLAppearanceMgr::instance().removeCOFItemLinks(item_id); - } - mQuestionableCOFLinks.erase(curr_it); - continue; - } - } + for(LLItemRequestTimes::iterator it = mQuestionableCOFLinks.begin(); + it != mQuestionableCOFLinks.end(); ) + { + LLItemRequestTimes::iterator curr_it = it; + ++it; + const LLUUID& item_id = curr_it->first; + LLViewerInventoryItem *inv_item = gInventory.getItem(item_id); + if (curr_it->second.getElapsedTimeF32() > MAX_BAD_COF_TIME) + { + if (LLAppearanceMgr::instance().isLinkedInCOF(item_id)) + { + LL_DEBUGS("Avatar") << "ATT Linked in COF but not attached or requested, deleting link after " + << curr_it->second.getElapsedTimeF32() << " seconds for " + << (inv_item ? inv_item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + LLAppearanceMgr::instance().removeCOFItemLinks(item_id); + } + mQuestionableCOFLinks.erase(curr_it); + continue; + } + } } void LLAttachmentsMgr::spamStatusInfo() diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index e5ff96095a..741c3317f5 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -523,12 +523,18 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( } } - if(rv.isNull() && isInventoryUsable() && create_folder) + if(rv.isNull() && create_folder && root_id.notNull()) { - if(root_id.notNull()) + + 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; + } } return rv; } @@ -593,9 +599,10 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, inventory_func_type callback) { LLUUID id; - if(!isInventoryUsable()) + if (!isInventoryUsable()) { - LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; + LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " + << preferred_type << LL_ENDL; // FIXME failing but still returning an id? return id; } @@ -2607,10 +2614,20 @@ void LLInventoryModel::buildParentChildMap() } } - // 'My Inventory', - // root of the agent's inv found. - // The inv tree is built. - mIsAgentInvUsable = true; + LLPointer validation_info = validate(); + if (validation_info->mFatalErrorCount > 0) + { + // Fatal inventory error. Will not be able to engage in many inventory operations. + // This should be followed by an error dialog leading to logout. + LL_WARNS("Inventory") << "Fatal errors were found in validate(): unable to initialize inventory! " + << "Will not be able to do normal inventory operations in this session." + << LL_ENDL; + mIsAgentInvUsable = false; + } + else + { + mIsAgentInvUsable = true; + } // notifyObservers() has been moved to // llstartup/idle_startup() after this func completes. diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 603f790815..51a96b2b10 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1808,11 +1808,11 @@ bool idle_startup() // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. gInventory.buildParentChildMap(); - // If inventory is unusable, need to flag this and - // bail out. In particular, must not trigger creation of new system - // categories. - LLPointer validation_info = gInventory.validate(); - // FIXME add handling of unfixable corruption here - need to exit and get support to fix. + // If buildParentChildMap succeeded, inventory will now be in + // a usable state and gInventory.isInventoryUsable() will be + // true. + + // FIXME if inventory is unusable, we need to bail out. gInventory.createCommonSystemCategories(); @@ -1858,9 +1858,6 @@ bool idle_startup() LLStartUp::setStartupState( STATE_MISC ); display_startup(); - // Update status check after various system folders created. - validation_info = gInventory.validate(); - return FALSE; } From d9ba2a8100f1fa6b6844f58b884595c123770a8a Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 18 Dec 2020 20:45:04 +0000 Subject: [PATCH 004/286] SL-14570 - error messages, avoid a couple of warnings caused by attempts to create folders before inventory is loaded --- indra/newview/llfavoritesbar.cpp | 10 +++++++++- indra/newview/llinventorymodel.cpp | 32 +++++++++++++++++++----------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 347997a69a..d258bea519 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1859,9 +1859,17 @@ BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) pref_changed |= mRecreateFavoriteStorage; mRecreateFavoriteStorage = false; + // Can get called before inventory is done initializing. + if (!gInventory.isInventoryUsable()) + { + return FALSE; + } + LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); if (favorite_folder.isNull()) - return FALSE; + { + return FALSE; + } LLInventoryModel::item_array_t items; LLInventoryModel::cat_array_t cats; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 741c3317f5..ff007c2f39 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -3765,12 +3765,12 @@ LLPointer LLInventoryModel::validate() const if (getRootFolderID().isNull()) { - LL_WARNS("Inventory") << "no root folder id" << LL_ENDL; + LL_WARNS("Inventory") << "Fatal inventory corruption: no root folder id" << LL_ENDL; fatalities++; } if (getLibraryRootFolderID().isNull()) { - LL_WARNS("Inventory") << "no library root folder id" << LL_ENDL; + LL_WARNS("Inventory") << "Fatal inventory corruption: no library root folder id" << LL_ENDL; fatalities++; } @@ -3801,6 +3801,9 @@ LLPointer LLInventoryModel::validate() const warnings++; continue; } + LLUUID topmost_ancestor_id; + // Will leave as null uuid on failure + getObjectTopmostAncestor(cat_id, topmost_ancestor_id); if (cat_id != cat->getUUID()) { LL_WARNS("Inventory") << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; @@ -3832,12 +3835,17 @@ LLPointer LLInventoryModel::validate() const } else if (cats->size() + items->size() != cat->getDescendentCount()) { - LL_WARNS("Inventory") << "invalid desc count for " << cat_id << " name [" << cat->getName() - << "] parent " << cat->getParentUUID() - << " cached " << cat->getDescendentCount() - << " expected " << cats->size() << "+" << items->size() - << "=" << cats->size() +items->size() << LL_ENDL; - warnings++; + // In the case of library this is not unexpected, since + // different user accounts may be getting the library + // contents from different inventory hosts. + if (topmost_ancestor_id.isNull() || topmost_ancestor_id != getLibraryRootFolderID()) + { + LL_WARNS("Inventory") << "invalid desc count for " << cat_id << " [" << getFullPath(cat) << "]" + << " cached " << cat->getDescendentCount() + << " expected " << cats->size() << "+" << items->size() + << "=" << cats->size() +items->size() << LL_ENDL; + warnings++; + } } if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) { @@ -4103,7 +4111,7 @@ LLPointer LLInventoryModel::validate() const // Need to create, if allowed. if (is_automatic) { - LL_WARNS("Inventory") << "Cannot create system folder of type " << ft << LL_ENDL; + LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; fatalities++; } else @@ -4114,7 +4122,7 @@ LLPointer LLInventoryModel::validate() const } else if (count_under_root > 1) { - LL_WARNS("Inventory") << "System folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; + LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; fatalities++; } if (count_elsewhere > 0) @@ -4141,8 +4149,8 @@ LLPointer LLInventoryModel::validate() const } // FIXME need to fail login and tell user to retry, contact support if problem persists. - bool valid = (fatalities + warnings == 0); - LL_INFOS("Inventory") << "Validate done, valid = " << (U32) valid << LL_ENDL; + bool valid = (fatalities == 0); + LL_INFOS("Inventory") << "Validate done, fatal errors: " << fatalities << ", warnings: " << warnings << ", valid: " << valid << LL_ENDL; validation_info->mFatalErrorCount = fatalities; validation_info->mWarningCount = warnings; From 3639e4ee775700cbccb6d2f602de6c5e23e5c86e Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 26 Jan 2021 14:16:56 +0000 Subject: [PATCH 005/286] SL-14570 - inventory validation info to ViewerStats, added QA mode setting to exercise failure cases --- indra/newview/app_settings/settings.xml | 13 ++++++- indra/newview/llinventorymodel.cpp | 47 +++++++++++++++++++++++-- indra/newview/llinventorymodel.h | 8 ++++- indra/newview/llviewerstats.cpp | 6 ++++ 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 52dc4744f2..535f1d24e1 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8315,7 +8315,18 @@ QAModeMetrics Comment - "Enables QA features (logging, faster cycling) for metrics collector" + Enables QA features (logging, faster cycling) for metrics collector + Persist + 1 + Type + Boolean + Value + 0 + + QAModeFakeSystemFolderIssues + + Comment + Simulates system folder issues in inventory Persist 1 Type diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index ff007c2f39..6e30a31e6d 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include +#include #include "llinventorymodel.h" @@ -136,7 +137,8 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) ///---------------------------------------------------------------------------- LLInventoryValidationInfo::LLInventoryValidationInfo(): mFatalErrorCount(0), - mWarningCount(0) + mWarningCount(0), + mInitialized(false) { } @@ -145,12 +147,38 @@ void LLInventoryValidationInfo::toOstream(std::ostream& os) const os << "mFatalErrorCount " << mFatalErrorCount << " mWarningCount " << mWarningCount; } + std::ostream& operator<<(std::ostream& os, const LLInventoryValidationInfo& v) { v.toOstream(os); return os; } +void LLInventoryValidationInfo::asLLSD(LLSD& sd) const +{ + sd["fatal_error_count"] = mFatalErrorCount; + sd["warning_count"] = mWarningCount; + sd["initialized"] = mInitialized; + sd["missing_system_folders_count"] = LLSD::Integer(mMissingRequiredSystemFolders.size()); + if (mMissingRequiredSystemFolders.size()>0) + { + sd["missing_system_folders"] = LLSD::emptyArray(); + for(auto ft: mMissingRequiredSystemFolders) + { + sd["missing_system_folders"].append(LLFolderType::lookup(ft)); + } + } + sd["duplicate_system_folders_count"] = LLSD::Integer(mDuplicateRequiredSystemFolders.size()); + if (mDuplicateRequiredSystemFolders.size()>0) + { + sd["duplicate_system_folders"] = LLSD::emptyArray(); + for(auto ft: mDuplicateRequiredSystemFolders) + { + sd["duplicate_system_folders"].append(LLFolderType::lookup(ft)); + } + } + +} ///---------------------------------------------------------------------------- /// Class LLInventoryModel @@ -184,7 +212,8 @@ LLInventoryModel::LLInventoryModel() mHttpPriorityFG(0), mHttpPriorityBG(0), mCategoryLock(), - mItemLock() + mItemLock(), + mValidationInfo(new LLInventoryValidationInfo) {} @@ -2628,6 +2657,8 @@ void LLInventoryModel::buildParentChildMap() { mIsAgentInvUsable = true; } + validation_info->mInitialized = true; + mValidationInfo = validation_info; // notifyObservers() has been moved to // llstartup/idle_startup() after this func completes. @@ -4092,6 +4123,10 @@ LLPointer LLInventoryModel::validate() const { LL_DEBUGS("Inventory") << "Folder type " << fit->first << " count " << fit->second << " elsewhere" << LL_ENDL; } + + static LLCachedControl fake_system_folder_issues(gSavedSettings, "QAModeFakeSystemFolderIssues", false); + static std::default_random_engine e{}; + static std::uniform_int_distribution<> distrib(0, 1); for (S32 ft=LLFolderType::FT_TEXTURE; ft(ft); @@ -4103,6 +4138,12 @@ LLPointer LLInventoryModel::validate() const bool is_singleton = LLFolderType::lookupIsSingletonType(folder_type); S32 count_under_root = ft_counts_under_root[folder_type]; S32 count_elsewhere = ft_counts_elsewhere[folder_type]; + if (fake_system_folder_issues) + { + // Force all counts to be either 0 or 2, thus flagged as an error. + count_under_root = 2*distrib(e); + count_elsewhere = 2*distrib(e); + } if (is_singleton) { if (count_under_root==0) @@ -4113,6 +4154,7 @@ LLPointer LLInventoryModel::validate() const { LL_WARNS("Inventory") << "Fatal inventory corruption: cannot create system folder of type " << ft << LL_ENDL; fatalities++; + validation_info->mMissingRequiredSystemFolders.insert(LLFolderType::EType(ft)); } else { @@ -4123,6 +4165,7 @@ LLPointer LLInventoryModel::validate() const else if (count_under_root > 1) { LL_WARNS("Inventory") << "Fatal inventory corruption: system folder type has excess copies under root, type " << ft << " count " << count_under_root << LL_ENDL; + validation_info->mDuplicateRequiredSystemFolders.insert(LLFolderType::EType(ft)); fatalities++; } if (count_elsewhere > 0) diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index caba78988e..bddaf3a147 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -56,16 +56,21 @@ class LLMessageSystem; class LLInventoryCollectFunctor; ///---------------------------------------------------------------------------- -/// LLInventoryValidationInfo +/// LLInventoryValidationInfo ///---------------------------------------------------------------------------- class LLInventoryValidationInfo: public LLRefCount { public: LLInventoryValidationInfo(); void toOstream(std::ostream& os) const; + void asLLSD(LLSD& sd) const; + S32 mFatalErrorCount; S32 mWarningCount; + bool mInitialized; + std::set mMissingRequiredSystemFolders; + std::set mDuplicateRequiredSystemFolders; }; std::ostream& operator<<(std::ostream& s, const LLInventoryValidationInfo& v); @@ -671,6 +676,7 @@ private: public: void dumpInventory() const; LLPointer validate() const; + LLPointer mValidationInfo; std::string getFullPath(const LLInventoryObject *obj) const; /** Miscellaneous diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index f7ded00318..fc706c6f2c 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -62,6 +62,7 @@ #include "llsdserialize.h" #include "llcorehttputil.h" #include "llvoicevivox.h" +#include "llinventorymodel.h" namespace LLStatViewer { @@ -573,6 +574,11 @@ void send_stats() fail["off_circuit"] = (S32) gMessageSystem->mOffCircuitPackets; fail["invalid"] = (S32) gMessageSystem->mInvalidOnCircuitPackets; + LLSD &inventory = body["inventory"]; + inventory["usable"] = gInventory.isInventoryUsable(); + LLSD& validation_info = inventory["validation_info"]; + gInventory.mValidationInfo->asLLSD(validation_info); + body["stats"]["voice"] = LLVoiceVivoxStats::getInstance()->read(); // Misc stats, two strings and two ints From 360b66bdc1f710104c088f4c0948af3b3a8c474e Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 27 Jan 2021 20:30:52 +0000 Subject: [PATCH 006/286] SL-14570 - test 64-bit toolchain for build issues --- BuildParams | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BuildParams b/BuildParams index c5f96d5ee3..bf0eba3e66 100755 --- a/BuildParams +++ b/BuildParams @@ -35,6 +35,8 @@ buildscripts_shared_more_NAMEs="build_secrets build_variables" # should use a viewer_channel that begins with "Second Life" ################################################################ viewer_channel = "Second Life Test" +PreferredToolArchitecture = "x64" + ################################################################ # Special packaging parameters. From dad963eadc3498d2ca8c13b9586f2a4472a824e8 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 29 Jan 2021 20:36:47 +0000 Subject: [PATCH 007/286] SL-14570 - moving windows 64-bit toolchain setting to build config params --- BuildParams | 1 - 1 file changed, 1 deletion(-) diff --git a/BuildParams b/BuildParams index bf0eba3e66..e55c0c7bda 100755 --- a/BuildParams +++ b/BuildParams @@ -35,7 +35,6 @@ buildscripts_shared_more_NAMEs="build_secrets build_variables" # should use a viewer_channel that begins with "Second Life" ################################################################ viewer_channel = "Second Life Test" -PreferredToolArchitecture = "x64" ################################################################ From aff37221dd26bc939b58ab959c8183cd36647aa6 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 29 Jan 2021 23:03:04 +0200 Subject: [PATCH 008/286] SL-14794 Group floater not focusing when clicking on 'more info' or 'view profile' --- indra/newview/llgroupactions.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index d2bd716f55..65c91b54b7 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -366,6 +366,11 @@ void LLGroupActions::show(const LLUUID& group_id) params["open_tab_name"] = "panel_group_info_sidetray"; LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params); + LLFloater *floater = LLFloaterReg::getTypedInstance("people"); + if (!floater->isFrontmost()) + { + floater->setVisibleAndFrontmost(TRUE, params); + } } void LLGroupActions::refresh_notices() From 811d2fcb1ea8952b5e06dac0afffb835a952938f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 25 Feb 2021 23:28:25 +0200 Subject: [PATCH 009/286] SL-14879 "Play sounds from gestures" should not affect own sounds --- indra/newview/llviewermessage.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 458fc3b13d..1d79261cff 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3852,7 +3852,12 @@ void process_sound_trigger(LLMessageSystem *msg, void **) } // Don't play sounds from gestures if they are not enabled. - if (object_id == owner_id && !gSavedSettings.getBOOL("EnableGestureSounds")) + // Do play sounds triggered by avatar, since muting your own + // gesture sounds and your own sounds played inworld from + // Inventory can cause confusion. + if (object_id == owner_id + && owner_id != gAgentID + && !gSavedSettings.getBOOL("EnableGestureSounds")) { return; } From d38c2d8cd8b5588263b0bd01bfcb122282fb6af9 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 24 Mar 2021 22:20:28 +0200 Subject: [PATCH 010/286] SL-14992 Replaced LLAPRFile's isExist with LLDirUtil's fileExists in fmodstudio This particular case of LLAPRFile crashes due to thread issues (and if it doesn't it might be affecting some other apr call due to using default pool). Function is not opening the .dsf file in question and LLAPRFile won't ensure that file exists till the end of the function, it just checks that file exists at a given moment. No point to overcomplicate things by adding thread safe pool, so replaced with dirutil. --- indra/llaudio/llaudioengine_fmodstudio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 70b3a08473..b0c87b0208 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -661,7 +661,7 @@ bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename) return false; } - if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) + if (!gDirUtilp->fileExists(filename)) { // File not found, abort. return false; From b2d339ff066340add19092a3f79b3f48d5ade957 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 25 Mar 2021 22:58:26 +0200 Subject: [PATCH 011/286] SL-14855 Disable edit button for uneditable items --- indra/newview/llpanellandmarkinfo.cpp | 5 +++++ indra/newview/llpanellandmarkinfo.h | 1 + indra/newview/llpanelplaces.cpp | 7 ++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp index 6751c25fb9..5b24800038 100644 --- a/indra/newview/llpanellandmarkinfo.cpp +++ b/indra/newview/llpanellandmarkinfo.cpp @@ -360,6 +360,11 @@ void LLPanelLandmarkInfo::toggleLandmarkEditMode(BOOL enabled) setFocus(TRUE); } +void LLPanelLandmarkInfo::setCanEdit(BOOL enabled) +{ + getChild("edit_btn")->setEnabled(enabled); +} + const std::string& LLPanelLandmarkInfo::getLandmarkTitle() const { return mLandmarkTitleEditor->getText(); diff --git a/indra/newview/llpanellandmarkinfo.h b/indra/newview/llpanellandmarkinfo.h index 9712736182..f303d87ccf 100644 --- a/indra/newview/llpanellandmarkinfo.h +++ b/indra/newview/llpanellandmarkinfo.h @@ -51,6 +51,7 @@ public: void displayItemInfo(const LLInventoryItem* pItem); void toggleLandmarkEditMode(BOOL enabled); + void setCanEdit(BOOL enabled); const std::string& getLandmarkTitle() const; const std::string getLandmarkNotes() const; diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 53870fb5c7..5dfeb7f619 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -430,10 +430,15 @@ void LLPanelPlaces::onOpen(const LLSD& key) { mLandmarkInfo->setInfoType(LLPanelPlaceInfo::LANDMARK); - LLInventoryItem* item = gInventory.getItem(key["id"].asUUID()); + LLUUID id = key["id"].asUUID(); + LLInventoryItem* item = gInventory.getItem(id); if (!item) return; + BOOL is_editable = gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID()) + && item->getPermissions().allowModifyBy(gAgent.getID()); + mLandmarkInfo->setCanEdit(is_editable); + setItem(item); } else if (mPlaceInfoType == REMOTE_PLACE_INFO_TYPE) From a106d6cf78833a3e24f8d478807f6363e4af5652 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 29 Mar 2021 21:30:40 +0300 Subject: [PATCH 012/286] SL-13182 Turn on openmp paralellization on Windows --- indra/cmake/00-Common.cmake | 4 ++-- indra/llui/llnotifications.cpp | 5 ----- indra/llui/llnotifications.h | 4 ---- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 8aea50e02b..289d65e975 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -72,10 +72,10 @@ if (WINDOWS) endif() set(CMAKE_CXX_FLAGS_RELWITHDEBINFO - "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo" + "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /openmp /Zo" CACHE STRING "C++ compiler release-with-debug options" FORCE) set(CMAKE_CXX_FLAGS_RELEASE - "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /Zo" + "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /openmp /Zo" CACHE STRING "C++ compiler release options" FORCE) # zlib has assembly-language object files incompatible with SAFESEH set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE /SAFESEH:NO /NODEFAULTLIB:LIBCMT /IGNORE:4099") diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 06ec648178..34f25ad9fa 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -1784,11 +1784,6 @@ LLNotificationPtr LLNotifications::find(LLUUID uuid) } } -void LLNotifications::forEachNotification(NotificationProcess process) -{ - std::for_each(mItems.begin(), mItems.end(), process); -} - std::string LLNotifications::getGlobalString(const std::string& key) const { GlobalStringMap::const_iterator it = mGlobalStrings.find(key); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 2f4578da17..184a0ad83d 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -916,10 +916,6 @@ public: void update(const LLNotificationPtr pNotif); LLNotificationPtr find(LLUUID uuid); - - typedef boost::function NotificationProcess; - - void forEachNotification(NotificationProcess process); // This is all stuff for managing the templates // take your template out From c2711f2d763cfbf96d8db48b0809dd7a6e65a73e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 31 Mar 2021 23:46:08 +0300 Subject: [PATCH 013/286] Revert "SL-13182 Turn on openmp paralellization on Windows" This reverts commit a106d6cf78833a3e24f8d478807f6363e4af5652. --- indra/cmake/00-Common.cmake | 4 ++-- indra/llui/llnotifications.cpp | 5 +++++ indra/llui/llnotifications.h | 4 ++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 289d65e975..8aea50e02b 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -72,10 +72,10 @@ if (WINDOWS) endif() set(CMAKE_CXX_FLAGS_RELWITHDEBINFO - "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /openmp /Zo" + "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo" CACHE STRING "C++ compiler release-with-debug options" FORCE) set(CMAKE_CXX_FLAGS_RELEASE - "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /openmp /Zo" + "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /Zo" CACHE STRING "C++ compiler release options" FORCE) # zlib has assembly-language object files incompatible with SAFESEH set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE /SAFESEH:NO /NODEFAULTLIB:LIBCMT /IGNORE:4099") diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 34f25ad9fa..06ec648178 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -1784,6 +1784,11 @@ LLNotificationPtr LLNotifications::find(LLUUID uuid) } } +void LLNotifications::forEachNotification(NotificationProcess process) +{ + std::for_each(mItems.begin(), mItems.end(), process); +} + std::string LLNotifications::getGlobalString(const std::string& key) const { GlobalStringMap::const_iterator it = mGlobalStrings.find(key); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 184a0ad83d..2f4578da17 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -916,6 +916,10 @@ public: void update(const LLNotificationPtr pNotif); LLNotificationPtr find(LLUUID uuid); + + typedef boost::function NotificationProcess; + + void forEachNotification(NotificationProcess process); // This is all stuff for managing the templates // take your template out From 7ddbf118f5d1fde24c10b93432209fbe44d91345 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 24 Mar 2021 01:53:45 +0200 Subject: [PATCH 014/286] SL-13182 Split buildNewViews over frames --- indra/llui/llfolderviewitem.cpp | 14 +- indra/llui/llfolderviewitem.h | 15 +- indra/newview/llconversationview.cpp | 1 + indra/newview/llfolderviewmodelinventory.cpp | 2 +- indra/newview/llinventorybridge.cpp | 19 +- indra/newview/llinventorypanel.cpp | 182 +++++++++++++++++-- indra/newview/llinventorypanel.h | 17 +- indra/newview/llsidepanelinventory.cpp | 7 +- 8 files changed, 219 insertions(+), 38 deletions(-) diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 1c6c7b1b35..f4a6053b57 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -132,7 +132,6 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mCutGeneration(0), mLabelStyle( LLFontGL::NORMAL ), mHasVisibleChildren(FALSE), - mIsFolderComplete(true), mLocalIndentation(p.folder_indentation), mIndentation(0), mItemHeight(p.item_height), @@ -1002,11 +1001,11 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ): mCurHeight(0.f), mTargetHeight(0.f), mAutoOpenCountdown(0.f), + mIsFolderComplete(false), // folder might have children that are not loaded yet. + mAreChildrenInited(false), // folder might have children that are not built yet. mLastArrangeGeneration( -1 ), mLastCalculatedWidth(0) { - // folder might have children that are not loaded yet. Mark it as incomplete until chance to check it. - mIsFolderComplete = false; } void LLFolderViewFolder::updateLabelRotation() @@ -1062,13 +1061,16 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height ) { // Sort before laying out contents // Note that we sort from the root (CHUI-849) - getRoot()->getFolderViewModel()->sort(this); + if (mAreChildrenInited) + { + getRoot()->getFolderViewModel()->sort(this); + } LL_RECORD_BLOCK_TIME(FTM_ARRANGE); // evaluate mHasVisibleChildren mHasVisibleChildren = false; - if (getViewModelItem()->descendantsPassedFilter()) + if (mAreChildrenInited && getViewModelItem()->descendantsPassedFilter()) { // We have to verify that there's at least one child that's not filtered out bool found = false; @@ -1094,7 +1096,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height ) mHasVisibleChildren = found; } - if (!mIsFolderComplete) + if (!mIsFolderComplete && mAreChildrenInited) { mIsFolderComplete = getFolderViewModel()->isFolderComplete(this); } diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index da09d139e9..9df58d4478 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -116,7 +116,6 @@ protected: F32 mControlLabelRotation; LLFolderView* mRoot; bool mHasVisibleChildren, - mIsFolderComplete, // indicates that some children were not loaded/added yet mIsCurSelection, mDragAndDropTarget, mIsMouseOverTitle, @@ -219,7 +218,10 @@ public: BOOL hasVisibleChildren() { return mHasVisibleChildren; } // true if object can't have children - BOOL isFolderComplete() { return mIsFolderComplete; } + virtual bool isFolderComplete() { return true; } + // true if object can't have children + virtual bool areChildrenInited() { return true; } + virtual void setChildrenInited(bool inited) { } // Call through to the viewed object and return true if it can be // removed. Returns true if it's removed. @@ -334,6 +336,8 @@ protected: S32 mLastArrangeGeneration; S32 mLastCalculatedWidth; bool mNeedsSort; + bool mIsFolderComplete; // indicates that some children were not loaded/added yet + bool mAreChildrenInited; // indicates that no children were initialized public: typedef enum e_recurse_type @@ -385,6 +389,13 @@ public: // destroys this folder, and all children virtual void destroyView(); + // whether known children are fully loaded (arrange sets to true) + virtual bool isFolderComplete() { return mIsFolderComplete; } + + // whether known children are fully built + virtual bool areChildrenInited() { return mAreChildrenInited; } + virtual void setChildrenInited(bool inited) { mAreChildrenInited = inited; } + // extractItem() removes the specified item from the folder, but // doesn't delete it. virtual void extractItem( LLFolderViewItem* item ); diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 093e772abe..46a0a0b37a 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -88,6 +88,7 @@ LLConversationViewSession::LLConversationViewSession(const LLConversationViewSes mFlashStarted(false) { mFlashTimer = new LLFlashTimer(); + mAreChildrenInited = true; // inventory only } LLConversationViewSession::~LLConversationViewSession() diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index d40a7234e2..117e2534cb 100644 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -66,7 +66,7 @@ void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder ) { LL_RECORD_BLOCK_TIME(FTM_INVENTORY_SORT); - if (!needsSort(folder->getViewModelItem())) return; + if (!folder->areChildrenInited() || !needsSort(folder->getViewModelItem())) return; LLFolderViewModelItemInventory* modelp = static_cast(folder->getViewModelItem()); if (modelp->getUUID().isNull()) return; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index d35d8456be..15c3f10436 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -3437,9 +3437,22 @@ void LLFolderBridge::copyOutfitToClipboard() void LLFolderBridge::openItem() { LL_DEBUGS() << "LLFolderBridge::openItem()" << LL_ENDL; - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - if(mUUID.isNull()) return; + + LLInventoryPanel* panel = mInventoryPanel.get(); + if (!panel) + { + return; + } + LLInventoryModel* model = getInventoryModel(); + if (!model) + { + return; + } + if (mUUID.isNull()) + { + return; + } + panel->onFolderOpening(mUUID); bool fetching_inventory = model->fetchDescendentsOf(mUUID); // Only change folder type if we have the folder contents. if (!fetching_inventory) diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 74d9e895c2..09a94c1c09 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -282,17 +282,18 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this)); mInventory->addObserver(mCompletionObserver); - if (mBuildViewsOnInit) + if (mBuildViewsOnInit && mViewsInitialized == VIEWS_UNINITIALIZED) { // Build view of inventory if we need default full hierarchy and inventory is ready, otherwise do in onIdle. // Initializing views takes a while so always do it onIdle if viewer already loaded. - if (mInventory->isInventoryUsable() - && mViewsInitialized == VIEWS_UNINITIALIZED + if (mInventory->isInventoryUsable() && LLStartUp::getStartupState() <= STATE_WEARABLES_WAIT) { - initializeViews(); + // Usually this happens on login, so we have less time constraits, but too long and we can cause a disconnect + const F64 max_time = 20.f; + initializeViews(max_time); } - else if (mViewsInitialized != VIEWS_INITIALIZING) + else { mViewsInitialized = VIEWS_INITIALIZING; gIdleCallbacks.addFunction(onIdle, (void*)this); @@ -497,6 +498,23 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve view_folder = dynamic_cast(view_item); } + // if folder is not fully initialized (likely due to delayed load on idle) + // and we are not rebuilding, try updating children + if (view_folder + && !view_folder->areChildrenInited() + && ( (mask & LLInventoryObserver::REBUILD) == 0)) + { + LLInventoryObject const* objectp = mInventory->getObject(item_id); + if (objectp) + { + // Time is low since we only need the item itself and children views. + // Any value bigger than zero will do to init children, everything else + // will be processed on idle. + const F64 max_time = 0.0001f; + view_item = buildNewViewsWithTimeLimit(item_id, objectp, view_item, max_time); + } + } + ////////////////////////////// // LABEL Operation // Empty out the display name for relabel. @@ -536,8 +554,13 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve LLInventoryObject const* objectp = mInventory->getObject(item_id); if (objectp) { + // Time is low since we only need the item itself and children views. + // Any value bigger than zero will do to init children, everything else + // will be processed on idle. + const F64 max_time = 0.0001f; + // providing NULL directly avoids unnessesary getItemByID calls - view_item = buildNewViews(item_id, objectp, NULL); + view_item = buildNewViewsWithTimeLimit(item_id, objectp, NULL, max_time); } else { @@ -589,8 +612,13 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve LLInventoryObject const* objectp = mInventory->getObject(item_id); if (objectp) { + // Time is low since we only need the item itself and children views. + // Any value bigger than zero will do to init children, everything else + // will be processed on idle. + const F64 max_time = 0.0001f; + // providing NULL directly avoids unnessesary getItemByID calls - buildNewViews(item_id, objectp, NULL); + buildNewViewsWithTimeLimit(item_id, objectp, NULL, max_time); } // Select any newly created object that has the auto rename at top of folder root set. @@ -742,12 +770,12 @@ void LLInventoryPanel::onIdle(void *userdata) return; LLInventoryPanel *self = (LLInventoryPanel*)userdata; - // Inventory just initialized, do complete build - if (self->mViewsInitialized != VIEWS_INITIALIZED) + if (self->mViewsInitialized <= VIEWS_INITIALIZING) { - self->initializeViews(); + const F64 max_time = 0.001f; // 1 ms, in this case we need only root folders + self->initializeViews(max_time); // Shedules LLInventoryPanel::idle() } - if (self->mViewsInitialized == VIEWS_INITIALIZED) + if (self->mViewsInitialized >= VIEWS_BUILDING) { gIdleCallbacks.deleteFunction(onIdle, (void*)self); } @@ -782,6 +810,49 @@ void LLInventoryPanel::idle(void* user_data) } + bool in_visible_chain = panel->isInVisibleChain(); + + if (!panel->mBuildViewsQueue.empty()) + { + const F64 max_time = in_visible_chain ? 0.006f : 0.001f; // 6 ms + F64 curent_time = LLTimer::getTotalSeconds(); + panel->mBuildViewsEndTime = curent_time + max_time; + + // things added last are closer to root thus of higher priority + std::deque priority_list; + priority_list.swap(panel->mBuildViewsQueue); + + while (curent_time < panel->mBuildViewsEndTime + && !priority_list.empty()) + { + LLUUID item_id = priority_list.back(); + priority_list.pop_back(); + + LLInventoryObject const* objectp = panel->mInventory->getObject(item_id); + if (objectp && panel->typedViewsFilter(item_id, objectp)) + { + LLFolderViewItem* folder_view_item = panel->getItemByID(item_id); + if (!folder_view_item || !folder_view_item->areChildrenInited()) + { + const LLUUID &parent_id = objectp->getParentUUID(); + LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)panel->getItemByID(parent_id); + panel->buildViewsTree(item_id, parent_id, objectp, folder_view_item, parent_folder); + } + } + curent_time = LLTimer::getTotalSeconds(); + } + while (!priority_list.empty()) + { + // items in priority_list are of higher priority + panel->mBuildViewsQueue.push_back(priority_list.front()); + priority_list.pop_front(); + } + if (panel->mBuildViewsQueue.empty()) + { + panel->mViewsInitialized = VIEWS_INITIALIZED; + } + } + // Take into account the fact that the root folder might be invalidated if (panel->mFolderRoot.get()) { @@ -812,10 +883,16 @@ void LLInventoryPanel::idle(void* user_data) } -void LLInventoryPanel::initializeViews() +void LLInventoryPanel::initializeViews(F64 max_time) { if (!gInventory.isInventoryUsable()) return; + mViewsInitialized = VIEWS_BUILDING; + + F64 curent_time = LLTimer::getTotalSeconds(); + mBuildViewsEndTime = curent_time + max_time; + + // init everything LLUUID root_id = getRootFolderID(); if (root_id.notNull()) { @@ -823,14 +900,18 @@ void LLInventoryPanel::initializeViews() } else { - // Default case: always add "My Inventory" first, "Library" second + // Default case: always add "My Inventory" root first, "Library" root second + // If we run out of time, this still should create root folders buildNewViews(gInventory.getRootFolderID()); // My Inventory buildNewViews(gInventory.getLibraryRootFolderID()); // Library } - gIdleCallbacks.addFunction(idle, this); + if (mBuildViewsQueue.empty()) + { + mViewsInitialized = VIEWS_INITIALIZED; + } - mViewsInitialized = VIEWS_INITIALIZED; + gIdleCallbacks.addFunction(idle, this); openStartFolderOrMyInventory(); @@ -930,6 +1011,12 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryO return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder); } +LLFolderViewItem* LLInventoryPanel::buildNewViewsWithTimeLimit(const LLUUID& id, LLInventoryObject const* objectp, LLFolderViewItem *folder_view_item, F64 max_time) +{ + mBuildViewsEndTime = LLTimer::getTotalSeconds() + max_time; + return buildNewViews(id, objectp, folder_view_item); +} + LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, const LLUUID& parent_id, LLInventoryObject const* objectp, @@ -1035,9 +1122,33 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, } } + bool create_children = folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY; + + if (create_children) + { + F64 curent_time = LLTimer::getTotalSeconds(); + // If function is out of time, we want to shedule it into mBuildViewsQueue + // If we have time, no matter how little, create views for all children + // + // This creates children in 'bulk' to make sure folder has either + // 'empty and incomplete' or 'complete' states with nothing in between. + // Folders are marked as mIsFolderComplete == false by default, + // later arrange() will update mIsFolderComplete by child count + if (mBuildViewsEndTime < curent_time) + { + create_children = false; + // run it again for the sake of creating children + mBuildViewsQueue.push_back(id); + } + else if (folder_view_item) + { + folder_view_item->setChildrenInited(true); + } + } + // If this is a folder, add the children of the folder and recursively add any // child folders. - if (folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY) + if (create_children) { LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; @@ -1053,7 +1164,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, ++cat_iter) { const LLViewerInventoryCategory* cat = (*cat_iter); - if (typedViewsFilter(cat->getUUID(), cat)) + if (typedViewsFilter(cat->getUUID(), cat)) { if (has_folders) { @@ -1077,17 +1188,16 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, item_iter != items->end(); ++item_iter) { + // At the moment we have to build folder's items in bulk and ignore mBuildViewsEndTime const LLViewerInventoryItem* item = (*item_iter); if (typedViewsFilter(item->getUUID(), item)) { - // This can be optimized: we don't need to call getItemByID() // each time, especially since content is growing, we can just // iter over copy of mItemMap in some way LLFolderViewItem* view_itemp = getItemByID(item->getUUID()); buildViewsTree(item->getUUID(), id, item, view_itemp, parentp); } - } } mInventory->unlockDirectDescendentArrays(id); @@ -1200,6 +1310,18 @@ void LLInventoryPanel::onFocusReceived() LLPanel::onFocusReceived(); } +void LLInventoryPanel::onFolderOpening(const LLUUID &id) +{ + LLFolderViewItem* folder = getItemByID(id); + if (folder && !folder->areChildrenInited()) + { + // Last item in list will be processed first. + // This might result in dupplicates in list, but it + // isn't critical, views won't be created twice + mBuildViewsQueue.push_back(id); + } +} + bool LLInventoryPanel::addBadge(LLBadge * badge) { bool badge_added = false; @@ -1221,7 +1343,7 @@ void LLInventoryPanel::openAllFolders() void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) { // Don't select objects in COF (e.g. to prevent refocus when items are worn). - const LLInventoryObject *obj = gInventory.getObject(obj_id); + const LLInventoryObject *obj = mInventory->getObject(obj_id); if (obj && obj->getParentUUID() == LLAppearanceMgr::instance().getCOF()) { return; @@ -1257,6 +1379,12 @@ void LLInventoryPanel::onSelectionChange(const std::deque& it if (view_model) { LLUUID id = view_model->getUUID(); + if (!(*it)->areChildrenInited()) + { + const F64 max_time = 0.0001f; + mBuildViewsEndTime = LLTimer::getTotalSeconds() + max_time; + buildNewViews(id); + } LLViewerInventoryItem* inv_item = mInventory->getItem(id); if (inv_item && !inv_item->isFinished()) @@ -1714,6 +1842,20 @@ LLFolderViewFolder* LLInventoryPanel::getFolderByID(const LLUUID& id) void LLInventoryPanel::setSelectionByID( const LLUUID& obj_id, BOOL take_keyboard_focus ) { LLFolderViewItem* itemp = getItemByID(obj_id); + + if (itemp && !itemp->areChildrenInited()) + { + LLInventoryObject const* objectp = mInventory->getObject(obj_id); + if (objectp) + { + // Time is low since we only need the item itself and children views. + // Any value bigger than zero will do to init children, everything else + // will be processed on idle. + const F64 max_time = 0.0001f; + buildNewViewsWithTimeLimit(obj_id, objectp, itemp, max_time); + } + } + if(itemp && itemp->getViewModelItem()) { itemp->arrangeAndSet(TRUE, take_keyboard_focus); diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index ad6010f09c..06547ebf0e 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -171,6 +171,7 @@ public: // LLUICtrl methods /*virtual*/ void onFocusLost(); /*virtual*/ void onFocusReceived(); + void onFolderOpening(const LLUUID &id); // LLBadgeHolder methods bool addBadge(LLBadge * badge); @@ -317,12 +318,9 @@ private: //-------------------------------------------------------------------- public: void addHideFolderType(LLFolderType::EType folder_type); - -public: - bool getViewsInitialized() const { return mViewsInitialized == VIEWS_INITIALIZED; } protected: // Builds the UI. Call this once the inventory is usable. - void initializeViews(); + void initializeViews(F64 max_time); // Specific inventory colors static bool sColorSetInitialized; @@ -330,13 +328,19 @@ protected: static LLUIColor sDefaultHighlightColor; static LLUIColor sLibraryColor; static LLUIColor sLinkColor; - + + // All buildNewViews() expect time limit mBuildViewsEndTime to be set LLFolderViewItem* buildNewViews(const LLUUID& id); LLFolderViewItem* buildNewViews(const LLUUID& id, LLInventoryObject const* objectp); LLFolderViewItem* buildNewViews(const LLUUID& id, LLInventoryObject const* objectp, LLFolderViewItem *target_view); + + LLFolderViewItem* buildNewViewsWithTimeLimit(const LLUUID& id, + LLInventoryObject const* objectp, + LLFolderViewItem *folder_view_item, + F64 max_time); // if certain types are not allowed, no reason to create views virtual bool typedViewsFilter(const LLUUID& id, LLInventoryObject const* objectp) { return true; } @@ -359,11 +363,14 @@ private: { VIEWS_UNINITIALIZED = 0, VIEWS_INITIALIZING, + VIEWS_BUILDING, // Root folder exists VIEWS_INITIALIZED, } EViewsInitializationState; bool mBuildViewsOnInit; EViewsInitializationState mViewsInitialized; // Whether views have been generated + F64 mBuildViewsEndTime; // Stop building views past this timestamp + std::deque mBuildViewsQueue; }; diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp index ea7e649792..a5dcdc41ed 100644 --- a/indra/newview/llsidepanelinventory.cpp +++ b/indra/newview/llsidepanelinventory.cpp @@ -653,7 +653,12 @@ bool LLSidepanelInventory::canWearSelected() LLInventoryItem *LLSidepanelInventory::getSelectedItem() { - LLFolderViewItem* current_item = mPanelMainInventory->getActivePanel()->getRootFolder()->getCurSelectedItem(); + LLFolderView* root = mPanelMainInventory->getActivePanel()->getRootFolder(); + if (!root) + { + return NULL; + } + LLFolderViewItem* current_item = root->getCurSelectedItem(); if (!current_item) { From 7d31436009b5578f75c862f970437bf583a97017 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 2 Apr 2021 21:40:09 +0300 Subject: [PATCH 015/286] SL-13182 Expanded buildNewViews with build modes --- indra/newview/llinventorypanel.cpp | 112 +++++++++++++++-------------- indra/newview/llinventorypanel.h | 21 ++++-- 2 files changed, 74 insertions(+), 59 deletions(-) diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 09a94c1c09..033c4c9a58 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -507,11 +507,7 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve LLInventoryObject const* objectp = mInventory->getObject(item_id); if (objectp) { - // Time is low since we only need the item itself and children views. - // Any value bigger than zero will do to init children, everything else - // will be processed on idle. - const F64 max_time = 0.0001f; - view_item = buildNewViewsWithTimeLimit(item_id, objectp, view_item, max_time); + view_item = buildNewViews(item_id, objectp, view_item, BUILD_ONE_FOLDER); } } @@ -554,13 +550,8 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve LLInventoryObject const* objectp = mInventory->getObject(item_id); if (objectp) { - // Time is low since we only need the item itself and children views. - // Any value bigger than zero will do to init children, everything else - // will be processed on idle. - const F64 max_time = 0.0001f; - // providing NULL directly avoids unnessesary getItemByID calls - view_item = buildNewViewsWithTimeLimit(item_id, objectp, NULL, max_time); + view_item = buildNewViews(item_id, objectp, NULL, BUILD_ONE_FOLDER); } else { @@ -612,13 +603,8 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve LLInventoryObject const* objectp = mInventory->getObject(item_id); if (objectp) { - // Time is low since we only need the item itself and children views. - // Any value bigger than zero will do to init children, everything else - // will be processed on idle. - const F64 max_time = 0.0001f; - // providing NULL directly avoids unnessesary getItemByID calls - buildNewViewsWithTimeLimit(item_id, objectp, NULL, max_time); + buildNewViews(item_id, objectp, NULL, BUILD_ONE_FOLDER); } // Select any newly created object that has the auto rename at top of folder root set. @@ -836,7 +822,7 @@ void LLInventoryPanel::idle(void* user_data) { const LLUUID &parent_id = objectp->getParentUUID(); LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)panel->getItemByID(parent_id); - panel->buildViewsTree(item_id, parent_id, objectp, folder_view_item, parent_folder); + panel->buildViewsTree(item_id, parent_id, objectp, folder_view_item, parent_folder, BUILD_TIMELIMIT); } } curent_time = LLTimer::getTotalSeconds(); @@ -990,10 +976,13 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryO LLFolderViewItem* folder_view_item = getItemByID(id); LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id); - return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder); + return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder, BUILD_TIMELIMIT); } -LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryObject const* objectp, LLFolderViewItem *folder_view_item) +LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, + LLInventoryObject const* objectp, + LLFolderViewItem *folder_view_item, + const EBuildModes &mode) { if (!objectp) { @@ -1008,20 +997,15 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryO const LLUUID &parent_id = objectp->getParentUUID(); LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id); - return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder); -} - -LLFolderViewItem* LLInventoryPanel::buildNewViewsWithTimeLimit(const LLUUID& id, LLInventoryObject const* objectp, LLFolderViewItem *folder_view_item, F64 max_time) -{ - mBuildViewsEndTime = LLTimer::getTotalSeconds() + max_time; - return buildNewViews(id, objectp, folder_view_item); + return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder, mode); } LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, const LLUUID& parent_id, LLInventoryObject const* objectp, LLFolderViewItem *folder_view_item, - LLFolderViewFolder *parent_folder) + LLFolderViewFolder *parent_folder, + const EBuildModes &mode) { // Force the creation of an extra root level folder item if required by the inventory panel (default is "false") bool allow_drop = true; @@ -1126,23 +1110,51 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, if (create_children) { - F64 curent_time = LLTimer::getTotalSeconds(); - // If function is out of time, we want to shedule it into mBuildViewsQueue - // If we have time, no matter how little, create views for all children - // - // This creates children in 'bulk' to make sure folder has either - // 'empty and incomplete' or 'complete' states with nothing in between. - // Folders are marked as mIsFolderComplete == false by default, - // later arrange() will update mIsFolderComplete by child count - if (mBuildViewsEndTime < curent_time) + switch (mode) { - create_children = false; - // run it again for the sake of creating children - mBuildViewsQueue.push_back(id); - } - else if (folder_view_item) - { - folder_view_item->setChildrenInited(true); + case BUILD_TIMELIMIT: + { + F64 curent_time = LLTimer::getTotalSeconds(); + // If function is out of time, we want to shedule it into mBuildViewsQueue + // If we have time, no matter how little, create views for all children + // + // This creates children in 'bulk' to make sure folder has either + // 'empty and incomplete' or 'complete' states with nothing in between. + // Folders are marked as mIsFolderComplete == false by default, + // later arrange() will update mIsFolderComplete by child count + if (mBuildViewsEndTime < curent_time) + { + create_children = false; + // run it again for the sake of creating children + mBuildViewsQueue.push_back(id); + } + else if (folder_view_item) + { + folder_view_item->setChildrenInited(true); + } + break; + } + case BUILD_NO_CHILDREN: + { + create_children = false; + // run it to create children, current caller is only interested in current view + mBuildViewsQueue.push_back(id); + break; + } + case BUILD_ONE_FOLDER: + { + // This view loads chindren, following ones don't + // Note: Might be better idea to do 'depth' instead, + // It also will help to prioritize root folder's content + create_children = true; + break; + } + case BUILD_NO_LIMIT: + default: + { + // keep working till everything exists + create_children = true; + } } } @@ -1172,11 +1184,11 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, // each time, especially since content is growing, we can just // iter over copy of mItemMap in some way LLFolderViewItem* view_itemp = getItemByID(cat->getUUID()); - buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp); + buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode)); } else { - buildViewsTree(cat->getUUID(), id, cat, NULL, parentp); + buildViewsTree(cat->getUUID(), id, cat, NULL, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode)); } } } @@ -1196,7 +1208,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, // each time, especially since content is growing, we can just // iter over copy of mItemMap in some way LLFolderViewItem* view_itemp = getItemByID(item->getUUID()); - buildViewsTree(item->getUUID(), id, item, view_itemp, parentp); + buildViewsTree(item->getUUID(), id, item, view_itemp, parentp, mode); } } } @@ -1848,11 +1860,7 @@ void LLInventoryPanel::setSelectionByID( const LLUUID& obj_id, BOOL take_keyb LLInventoryObject const* objectp = mInventory->getObject(obj_id); if (objectp) { - // Time is low since we only need the item itself and children views. - // Any value bigger than zero will do to init children, everything else - // will be processed on idle. - const F64 max_time = 0.0001f; - buildNewViewsWithTimeLimit(obj_id, objectp, itemp, max_time); + buildNewViews(obj_id, objectp, itemp, BUILD_ONE_FOLDER); } } diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 06547ebf0e..5fc3a55a36 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -329,18 +329,24 @@ protected: static LLUIColor sLibraryColor; static LLUIColor sLinkColor; - // All buildNewViews() expect time limit mBuildViewsEndTime to be set + enum EBuildModes + { + BUILD_NO_LIMIT, + BUILD_TIMELIMIT, // requires mBuildViewsEndTime + BUILD_ONE_FOLDER, + BUILD_NO_CHILDREN, + }; + + // All buildNewViews() use BUILD_TIMELIMIT by default + // and expect time limit mBuildViewsEndTime to be set LLFolderViewItem* buildNewViews(const LLUUID& id); LLFolderViewItem* buildNewViews(const LLUUID& id, LLInventoryObject const* objectp); LLFolderViewItem* buildNewViews(const LLUUID& id, LLInventoryObject const* objectp, - LLFolderViewItem *target_view); + LLFolderViewItem *target_view, + const EBuildModes &mode = BUILD_TIMELIMIT); - LLFolderViewItem* buildNewViewsWithTimeLimit(const LLUUID& id, - LLInventoryObject const* objectp, - LLFolderViewItem *folder_view_item, - F64 max_time); // if certain types are not allowed, no reason to create views virtual bool typedViewsFilter(const LLUUID& id, LLInventoryObject const* objectp) { return true; } @@ -357,7 +363,8 @@ private: const LLUUID& parent_id, LLInventoryObject const* objectp, LLFolderViewItem *target_view, - LLFolderViewFolder *parent_folder_view); + LLFolderViewFolder *parent_folder_view, + const EBuildModes &mode); typedef enum e_views_initialization_state { From 820ac72f8c4a07bc4310b9daac6966f2f2f2ee98 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 2 Apr 2021 22:40:56 +0300 Subject: [PATCH 016/286] SL-13182 Fix excessive resorting --- indra/newview/llfolderviewmodelinventory.cpp | 23 ++++++++++++-------- indra/newview/llfolderviewmodelinventory.h | 1 + 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index 117e2534cb..4544b083ed 100644 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -140,15 +140,20 @@ void LLFolderViewModelItemInventory::requestSort() { folderp->requestArrange(); } - if (static_cast(mRootViewModel).getSorter().isByDate()) - { - // sort by date potentially affects parent folders which use a date - // derived from newest item in them - if (mParent) - { - mParent->requestSort(); - } - } + LLInventorySort sorter = static_cast(mRootViewModel).getSorter(); + + if (sorter.isByDate()) + { + // Sort by date potentially affects parent folders which use a date + // derived from newest item in them + // + // if this is an item, parent needs to be resorted (this case shouldn't happen) + // if this is a folder, check sort rules for folder first + if (mParent && (!folderp || !sorter.isFoldersByName())) + { + mParent->requestSort(); + } + } } void LLFolderViewModelItemInventory::setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset, std::string::size_type string_size) diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h index 06a908cccc..8ee3f75002 100644 --- a/indra/newview/llfolderviewmodelinventory.h +++ b/indra/newview/llfolderviewmodelinventory.h @@ -82,6 +82,7 @@ public: } bool isByDate() const { return mByDate; } + bool isFoldersByName() const { return (!mByDate || mFoldersByName) && !mFoldersByWeight; } U32 getSortOrder() const { return mSortOrder; } void toParams(Params& p) { p.order(mSortOrder);} void fromParams(Params& p) From 2be5baf70dcf4e55fcac3935e304828ced202123 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sat, 3 Apr 2021 00:15:44 +0300 Subject: [PATCH 017/286] SL-13182 Fix excessive resorting #2 Don't resort whole branch of inventory if created(loaded) item is not newer. Should also stabilize fetch phase a bit. --- indra/newview/llfolderviewmodelinventory.cpp | 38 +++++++++++++++----- indra/newview/llfolderviewmodelinventory.h | 3 ++ indra/newview/llinventorybridge.cpp | 6 ++-- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index 4544b083ed..b6d856e31b 100644 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -132,6 +132,16 @@ bool LLFolderViewModelInventory::isFolderComplete(LLFolderViewFolder* folder) return false; } +//virtual +void LLFolderViewModelItemInventory::addChild(LLFolderViewModelItem* child) +{ + LLFolderViewModelItemInventory* model_child = static_cast(child); + mLastAddedChildCreationDate = model_child->getCreationDate(); + + // this will requestSort() + LLFolderViewModelItemCommon::addChild(child); +} + void LLFolderViewModelItemInventory::requestSort() { LLFolderViewModelItemCommon::requestSort(); @@ -142,18 +152,29 @@ void LLFolderViewModelItemInventory::requestSort() } LLInventorySort sorter = static_cast(mRootViewModel).getSorter(); - if (sorter.isByDate()) + // Sort by date potentially affects parent folders which use a date + // derived from newest item in them + if (sorter.isByDate() && mParent) { - // Sort by date potentially affects parent folders which use a date - // derived from newest item in them - // - // if this is an item, parent needs to be resorted (this case shouldn't happen) - // if this is a folder, check sort rules for folder first - if (mParent && (!folderp || !sorter.isFoldersByName())) + // If this is an item, parent needs to be resorted + // This case shouldn't happen, unless someone calls item->requestSort() + if (!folderp) { mParent->requestSort(); } + // if this is a folder, check sort rules for folder first + else if (sorter.isFoldersByDate()) + { + if (mLastAddedChildCreationDate == -1 // nothing was added, some other reason for resort + || mLastAddedChildCreationDate > getCreationDate()) // newer child + { + LLFolderViewModelItemInventory* model_parent = static_cast(mParent); + model_parent->mLastAddedChildCreationDate = mLastAddedChildCreationDate; + mParent->requestSort(); + } + } } + mLastAddedChildCreationDate = -1; } void LLFolderViewModelItemInventory::setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset, std::string::size_type string_size) @@ -392,6 +413,7 @@ bool LLInventorySort::operator()(const LLFolderViewModelItemInventory* const& a, LLFolderViewModelItemInventory::LLFolderViewModelItemInventory( class LLFolderViewModelInventory& root_view_model ) : LLFolderViewModelItemCommon(root_view_model), - mPrevPassedAllFilters(false) + mPrevPassedAllFilters(false), + mLastAddedChildCreationDate(-1) { } diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h index 8ee3f75002..4cb62583cc 100644 --- a/indra/newview/llfolderviewmodelinventory.h +++ b/indra/newview/llfolderviewmodelinventory.h @@ -46,6 +46,7 @@ public: virtual void showProperties(void) = 0; virtual BOOL isItemInTrash( void) const { return FALSE; } // TODO: make into pure virtual. virtual BOOL isUpToDate() const = 0; + virtual void addChild(LLFolderViewModelItem* child); virtual bool hasChildren() const = 0; virtual LLInventoryType::EType getInventoryType() const = 0; virtual void performAction(LLInventoryModel* model, std::string action) = 0; @@ -62,6 +63,7 @@ public: virtual LLToolDragAndDrop::ESource getDragSource() const = 0; protected: bool mPrevPassedAllFilters; + time_t mLastAddedChildCreationDate; // -1 if nothing was added }; class LLInventorySort @@ -83,6 +85,7 @@ public: bool isByDate() const { return mByDate; } bool isFoldersByName() const { return (!mByDate || mFoldersByName) && !mFoldersByWeight; } + bool isFoldersByDate() const { return mByDate && !mFoldersByName && !mFoldersByWeight; } U32 getSortOrder() const { return mSortOrder; } void toParams(Params& p) { p.order(mSortOrder);} void fromParams(Params& p) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 15c3f10436..923a06b324 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1905,7 +1905,8 @@ void LLItemBridge::buildDisplayName() const LLStringUtil::toUpper(mSearchableName); //Name set, so trigger a sort - if(mParent) + LLInventorySort sorter = static_cast(mRootViewModel).getSorter(); + if(mParent && !sorter.isByDate()) { mParent->requestSort(); } @@ -2204,7 +2205,8 @@ void LLFolderBridge::buildDisplayName() const LLStringUtil::toUpper(mSearchableName); //Name set, so trigger a sort - if(mParent) + LLInventorySort sorter = static_cast(mRootViewModel).getSorter(); + if(mParent && sorter.isFoldersByName()) { mParent->requestSort(); } From 77147012fff0673fc5c8ab9ffe654bd32305ad1a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 6 Apr 2021 20:12:28 +0300 Subject: [PATCH 018/286] SL-14770 Sorting group notices by date disconnects the viewer. getItemIndex() on each insertion can be very expensive, use std::set's find instead --- indra/newview/llpanelgroupnotices.cpp | 38 +++++++++++---------------- indra/newview/llpanelgroupnotices.h | 1 + 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index c63d04cd55..ab32ea3956 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -305,8 +305,11 @@ BOOL LLPanelGroupNotices::postBuild() void LLPanelGroupNotices::activate() { - if(mNoticesList) - mNoticesList->deleteAllItems(); + if (mNoticesList) + { + mNoticesList->deleteAllItems(); + mKnownNoticeIds.clear(); + } mPrevSelectedNotice = LLUUID(); @@ -413,6 +416,7 @@ void LLPanelGroupNotices::onClickSendMessage(void* data) row["columns"][4]["value"] = llformat( "%u", timestamp); self->mNoticesList->addElement(row, ADD_BOTTOM); + self->mKnownNoticeIds.insert(id); self->mCreateMessage->clear(); self->mCreateSubject->clear(); @@ -443,27 +447,13 @@ void LLPanelGroupNotices::onClickNewMessage(void* data) void LLPanelGroupNotices::refreshNotices() { onClickRefreshNotices(this); - /* - LL_DEBUGS() << "LLPanelGroupNotices::onClickGetPastNotices" << LL_ENDL; - - mNoticesList->deleteAllItems(); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GroupNoticesListRequest"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID",gAgent.getID()); - msg->addUUID("SessionID",gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("GroupID",self->mGroupID); - gAgent.sendReliableMessage(); - */ - } void LLPanelGroupNotices::clearNoticeList() { mPrevSelectedNotice = mNoticesList->getStringUUIDSelectedItem(); mNoticesList->deleteAllItems(); + mKnownNoticeIds.clear(); } void LLPanelGroupNotices::onClickRefreshNotices(void* data) @@ -541,13 +531,14 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg) return; } - //with some network delays we can receive notice list more then once... - //so add only unique notices - S32 pos = mNoticesList->getItemIndex(id); + // Due to some network delays we can receive notice list more than once... + // So add only unique notices + if (mKnownNoticeIds.find(id) != mKnownNoticeIds.end()) + { + // If items with this ID already in the list - skip it + continue; + } - if(pos!=-1)//if items with this ID already in the list - skip it - continue; - msg->getString("Data","Subject",subj,i); msg->getString("Data","FromName",name,i); msg->getBOOL("Data","HasAttachment",has_attachment,i); @@ -582,6 +573,7 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg) row["columns"][4]["value"] = llformat( "%u", timestamp); mNoticesList->addElement(row, ADD_BOTTOM); + mKnownNoticeIds.insert(id); } mNoticesList->setNeedsSort(save_sort); diff --git a/indra/newview/llpanelgroupnotices.h b/indra/newview/llpanelgroupnotices.h index 46c8c241c6..55319cb9ae 100644 --- a/indra/newview/llpanelgroupnotices.h +++ b/indra/newview/llpanelgroupnotices.h @@ -110,6 +110,7 @@ private: LLIconCtrl *mViewInventoryIcon; LLScrollListCtrl *mNoticesList; + std::set mKnownNoticeIds; // Dupplicate avoidance, to avoid searching and inserting dupplciates into mNoticesList std::string mNoNoticesStr; From 8215fff0c2a1c895ef916837847cf7526ae61ef9 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Fri, 2 Apr 2021 19:55:34 +0300 Subject: [PATCH 019/286] SL-14717 Ability to trigger left clicks (and more) on animesh objects Contribution by Rohacan Hirons SL-14717 Follow ups SL-14717 Using the cached setting in LLToolPie::handleHover() --- doc/contributions.txt | 2 ++ indra/newview/llagentcamera.cpp | 8 ++++++++ indra/newview/lltoolface.cpp | 2 +- indra/newview/lltoolfocus.cpp | 2 +- indra/newview/lltoolpie.cpp | 31 ++++++++++++++++++++++++++++--- indra/newview/pipeline.cpp | 1 + 6 files changed, 41 insertions(+), 5 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index bbdfaf655d..7a3fa2f95b 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -1251,6 +1251,8 @@ Robin Cornelius VWR-12763 VWR-12995 VWR-20911 +Rohacan Hirons + SL-14717 Rosco Teardrop Rose Evans Rudee Voom diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index ed6c3c307f..e10244aad6 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -2501,8 +2501,16 @@ void LLAgentCamera::setFocusGlobal(const LLPickInfo& pick) { // focus on object plus designated offset // which may or may not be same as pick.mPosGlobal + // except for rigged items to prevent wrong focus position + if (objectp->isRiggedMesh()) + { + setFocusGlobal(pick.mPosGlobal, pick.mObjectID); + } + else + { setFocusGlobal(objectp->getPositionGlobal() + LLVector3d(pick.mObjectOffset), pick.mObjectID); } + } else { // focus directly on point where user clicked diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp index a00ac10698..71986d21f9 100644 --- a/indra/newview/lltoolface.cpp +++ b/indra/newview/lltoolface.cpp @@ -73,7 +73,7 @@ BOOL LLToolFace::handleDoubleClick(S32 x, S32 y, MASK mask) BOOL LLToolFace::handleMouseDown(S32 x, S32 y, MASK mask) { - gViewerWindow->pickAsync(x, y, mask, pickCallback); + gViewerWindow->pickAsync(x, y, mask, pickCallback, false, gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick")); return TRUE; } diff --git a/indra/newview/lltoolfocus.cpp b/indra/newview/lltoolfocus.cpp index 07f46c5fbe..d8cb70dd3c 100644 --- a/indra/newview/lltoolfocus.cpp +++ b/indra/newview/lltoolfocus.cpp @@ -135,7 +135,7 @@ BOOL LLToolCamera::handleMouseDown(S32 x, S32 y, MASK mask) gViewerWindow->hideCursor(); - gViewerWindow->pickAsync(x, y, mask, pickCallback, /*BOOL pick_transparent*/ FALSE, /*BOOL pick_rigged*/ FALSE, /*BOOL pick_unselectable*/ TRUE); + gViewerWindow->pickAsync(x, y, mask, pickCallback, /*BOOL pick_transparent*/ FALSE, /*BOOL pick_rigged*/ gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"), /*BOOL pick_unselectable*/ TRUE); return TRUE; } diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 322d0bc727..c3f85c0008 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -78,6 +78,10 @@ static void handle_click_action_play(); static void handle_click_action_open_media(LLPointer objectp); static ECursorType cursor_from_parcel_media(U8 click_action); +BOOL rigged_hovering_keep_hand = false; +U64 last_rigged_hovering_check_clock_count = 0; +U64 last_rigged_pick_clock_count = 0; + LLToolPie::LLToolPie() : LLTool(std::string("Pie")), mMouseButtonDown( false ), @@ -112,7 +116,7 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) mMouseDownX = x; mMouseDownY = y; LLTimer pick_timer; - BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); + BOOL pick_rigged = gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); LLPickInfo transparent_pick = gViewerWindow->pickImmediate(x, y, TRUE /*includes transparent*/, pick_rigged); LLPickInfo visible_pick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged); LLViewerObject *transp_object = transparent_pick.getObject(); @@ -173,7 +177,9 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) mMouseButtonDown = true; - return handleLeftClickPick(); + handleLeftClickPick(); + + return TRUE; } // Spawn context menus on right mouse down so you can drag over and select @@ -722,7 +728,21 @@ void LLToolPie::selectionPropertiesReceived() BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) { - BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); + // prevent rigged item hovering causing FPS to drop by faking we're still hovering it for 0.25 seconds + U64 current_clock_count = LLTimer::getCurrentClockCount(); + if (current_clock_count - last_rigged_pick_clock_count < 2500000) { + if(rigged_hovering_keep_hand) gViewerWindow->setCursor(UI_CURSOR_HAND); + return TRUE; + } + rigged_hovering_keep_hand = 0; + + static LLCachedControl pick_rigged_setting(gSavedSettings, "AnimatedObjectsAllowLeftClick"); + BOOL pick_rigged = pick_rigged_setting; + if (pick_rigged) { + pick_rigged = (current_clock_count - last_rigged_hovering_check_clock_count > 1000000); // only 10 per seconds + if (pick_rigged) last_rigged_hovering_check_clock_count = current_clock_count; + } + mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged); LLViewerObject *parent = NULL; LLViewerObject *object = mHoverPick.getObject(); @@ -730,6 +750,10 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) if (object) { parent = object->getRootEdit(); + // Update gLastRiggedPickClockCount if we're hovering a rigged item + if (object->isRiggedMesh()) { + last_rigged_pick_clock_count = current_clock_count; + } } // Show screen-space highlight glow effect @@ -794,6 +818,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) { show_highlight = true; gViewerWindow->setCursor(UI_CURSOR_HAND); + rigged_hovering_keep_hand = true; LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } else diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 7ba7e545f4..ffca8896a6 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -7184,6 +7184,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, if (!sPickAvatar) { + pick_rigged = false; //save hit info in case we need to restore //due to attachment override LLVector4a local_normal; From 08566b1ac1bc726dcf80297b982de13cf958df6a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 7 Apr 2021 19:36:47 +0300 Subject: [PATCH 020/286] SL-14457 Make "Single click on land" default to "No action" --- indra/newview/app_settings/key_bindings.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/indra/newview/app_settings/key_bindings.xml b/indra/newview/app_settings/key_bindings.xml index 4f6deb1f98..1a5157838c 100644 --- a/indra/newview/app_settings/key_bindings.xml +++ b/indra/newview/app_settings/key_bindings.xml @@ -126,7 +126,6 @@ - From 55a357bb12856c9725ebb9f5ab24d9d534370eae Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 7 Apr 2021 19:41:15 +0300 Subject: [PATCH 021/286] SL-14457 Removed legacy 'click on land' setting support By the time this will release, enough time should have passed for smooth transition. Alternative to removing this is to make it check build id for anything older than 6.4.17.557391 --- indra/newview/llappviewer.cpp | 114 -------------------------------- indra/newview/llkeyconflict.cpp | 67 +------------------ 2 files changed, 2 insertions(+), 179 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 5a64f5e01c..a94bcfd653 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4428,120 +4428,6 @@ void LLAppViewer::addOnIdleCallback(const boost::function& cb) void LLAppViewer::loadKeyBindings() { std::string key_bindings_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "key_bindings.xml"); -#if 1 - // Legacy support - // Remove #if-#endif section half a year after DRTVWR-501 releases. - // Mouse actions are part of keybinding file since DRTVWR-501 instead of being stored in - // settings.xml. To support legacy viewers that were storing in settings.xml we need to - // transfer old variables to new format. - // Also part of backward compatibility is present in LLKeyConflictHandler to modify - // legacy variables on changes in new system (to make sure we won't enforce - // legacy values again if user dropped to defaults in new system) - if (LLVersionInfo::getInstance()->getChannelAndVersion() != gLastRunVersion - || !gDirUtilp->fileExists(key_bindings_file)) // if file is missing, assume that there were no changes by user yet - { - // copy mouse actions and voice key changes to new file - LL_INFOS("InitInfo") << "Converting legacy mouse bindings to new format" << LL_ENDL; - // Load settings from file - LLKeyConflictHandler third_person_view(LLKeyConflictHandler::MODE_THIRD_PERSON); - LLKeyConflictHandler sitting_view(LLKeyConflictHandler::MODE_SITTING); - - // Since we are only modifying keybindings if personal file doesn't exist yet, - // it should be safe to just overwrite the value - // If key is already in use somewhere by default, LLKeyConflictHandler should resolve it. - BOOL value = gSavedSettings.getBOOL("DoubleClickAutoPilot"); - third_person_view.registerControl("walk_to", - 0, - value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, - KEY_NONE, - MASK_NONE, - value); - - U32 index = value ? 1 : 0; // we can store multiple combinations per action, so if first is in use by doubleclick, go to second - value = gSavedSettings.getBOOL("ClickToWalk"); - third_person_view.registerControl("walk_to", - index, - value ? EMouseClickType::CLICK_LEFT : EMouseClickType::CLICK_NONE, - KEY_NONE, - MASK_NONE, - value); - - value = gSavedSettings.getBOOL("DoubleClickTeleport"); - third_person_view.registerControl("teleport_to", - 0, - value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, - KEY_NONE, - MASK_NONE, - value); - - // sitting also supports teleport - sitting_view.registerControl("teleport_to", - 0, - value ? EMouseClickType::CLICK_DOUBLELEFT : EMouseClickType::CLICK_NONE, - KEY_NONE, - MASK_NONE, - value); - - std::string key_string = gSavedSettings.getString("PushToTalkButton"); - EMouseClickType mouse = EMouseClickType::CLICK_NONE; - KEY key = KEY_NONE; - if (key_string == "MiddleMouse") - { - mouse = EMouseClickType::CLICK_MIDDLE; - } - else if (key_string == "MouseButton4") - { - mouse = EMouseClickType::CLICK_BUTTON4; - } - else if (key_string == "MouseButton5") - { - mouse = EMouseClickType::CLICK_BUTTON5; - } - else - { - LLKeyboard::keyFromString(key_string, &key); - } - - value = gSavedSettings.getBOOL("PushToTalkToggle"); - std::string control_name = value ? "toggle_voice" : "voice_follow_key"; - third_person_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); - sitting_view.registerControl(control_name, 0, mouse, key, MASK_NONE, true); - - if (third_person_view.hasUnsavedChanges()) - { - // calls loadBindingsXML() - third_person_view.saveToSettings(); - } - - if (sitting_view.hasUnsavedChanges()) - { - // calls loadBindingsXML() - sitting_view.saveToSettings(); - } - - // in case of voice we need to repeat this in other modes - - for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) - { - // edit and first person modes; MODE_SAVED_SETTINGS not in use at the moment - if (i != LLKeyConflictHandler::MODE_THIRD_PERSON && i != LLKeyConflictHandler::MODE_SITTING) - { - LLKeyConflictHandler handler((LLKeyConflictHandler::ESourceMode)i); - - handler.registerControl(control_name, 0, mouse, key, MASK_NONE, true); - - if (handler.hasUnsavedChanges()) - { - // calls loadBindingsXML() - handler.saveToSettings(); - } - } - } - } - // since something might have gone wrong or there might have been nothing to save - // (and because otherwise following code will have to be encased in else{}), - // load everything one last time -#endif if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerInput.loadBindingsXML(key_bindings_file)) { // Failed to load custom bindings, try default ones diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index b6107eeedf..b5ac94b1cd 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -619,74 +619,11 @@ void LLKeyConflictHandler::saveToSettings(bool temporary) } } -#if 1 - // Legacy support - // Remove #if-#endif section half a year after DRTVWR-501 releases. - // Update legacy settings in settings.xml - // We only care for third person view since legacy settings can't store - // more than one mode. - // We are saving this even if we are in temporary mode - preferences - // will restore values on cancel - if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges) - { - bool value = canHandleMouse("walk_to", CLICK_DOUBLELEFT, MASK_NONE); - gSavedSettings.setBOOL("DoubleClickAutoPilot", value); - - value = canHandleMouse("walk_to", CLICK_LEFT, MASK_NONE); - gSavedSettings.setBOOL("ClickToWalk", value); - - // new method can save both toggle and push-to-talk values simultaneously, - // but legacy one can save only one. It also doesn't support mask. - LLKeyData data = getControl("toggle_voice", 0); - bool can_toggle = !data.isEmpty(); - if (!can_toggle) - { - data = getControl("voice_follow_key", 0); - } - - gSavedSettings.setBOOL("PushToTalkToggle", can_toggle); - if (data.isEmpty()) - { - // legacy viewer has a bug that might crash it if NONE value is assigned. - // just reset to default - gSavedSettings.getControl("PushToTalkButton")->resetToDefault(false); - } - else - { - if (data.mKey != KEY_NONE) - { - gSavedSettings.setString("PushToTalkButton", LLKeyboard::stringFromKey(data.mKey)); - } - else - { - std::string ctrl_value; - switch (data.mMouse) - { - case CLICK_MIDDLE: - ctrl_value = "MiddleMouse"; - break; - case CLICK_BUTTON4: - ctrl_value = "MouseButton4"; - break; - case CLICK_BUTTON5: - ctrl_value = "MouseButton5"; - break; - default: - ctrl_value = "MiddleMouse"; - break; - } - gSavedSettings.setString("PushToTalkButton", ctrl_value); - } - } - } -#endif - if (mLoadMode == MODE_THIRD_PERSON && mHasUnsavedChanges) { // Map floater should react to doubleclick if doubleclick for teleport is set - // Todo: Seems conterintuitive for map floater to share inworld controls - // after these changes release, discuss with UI UX engineer if this should just - // be set to 1 by default (before release this also doubles as legacy support) + // Todo: Seems conterintuitive for map floater to share inworld controls, + // discuss with UI UX engineer if this should just be set to 1 by default bool value = canHandleMouse("teleport_to", CLICK_DOUBLELEFT, MASK_NONE); gSavedSettings.setBOOL("DoubleClickTeleport", value); } From 378855253a4cd65ee0b5f52f2bd887f2795cc99f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 7 Apr 2021 20:57:02 +0300 Subject: [PATCH 022/286] SL-13182 Fix root folder's state --- indra/newview/llinventorypanel.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 033c4c9a58..1998fca89d 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -256,6 +256,7 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) // Determine the root folder in case specified, and // build the views starting with that folder. LLFolderView* folder_view = createFolderRoot(root_id); + folder_view->setChildrenInited(true); // assume that root folder's children are loaded, most of the time we do not load it the normal way mFolderRoot = folder_view->getHandle(); addItemID(root_id, mFolderRoot.get()); @@ -1102,6 +1103,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, if (create_root) { folder_view_item->setOpen(TRUE); + parent_folder->setChildrenInited(true); } } } @@ -1128,12 +1130,13 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, // run it again for the sake of creating children mBuildViewsQueue.push_back(id); } - else if (folder_view_item) + else { + create_children = true; folder_view_item->setChildrenInited(true); } break; - } + } case BUILD_NO_CHILDREN: { create_children = false; @@ -1147,6 +1150,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, // Note: Might be better idea to do 'depth' instead, // It also will help to prioritize root folder's content create_children = true; + folder_view_item->setChildrenInited(true); break; } case BUILD_NO_LIMIT: @@ -1154,6 +1158,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, { // keep working till everything exists create_children = true; + folder_view_item->setChildrenInited(true); } } } From 0e7403df70d3298ba39f2269b999dbda574ea117 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 8 Apr 2021 21:37:12 +0300 Subject: [PATCH 023/286] SL-14076 Preview should show more data about motions --- indra/llcharacter/llkeyframemotion.h | 9 ++ indra/llcharacter/llmotion.h | 3 + indra/newview/llpreviewanim.cpp | 47 ++++++- indra/newview/llpreviewanim.h | 8 +- .../xui/en/floater_preview_animation.xml | 122 +++++++++++++----- 5 files changed, 153 insertions(+), 36 deletions(-) diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index 15c5c7c6c0..ad20d71a86 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -116,6 +116,15 @@ public: else return LLJoint::LOW_PRIORITY; } + virtual S32 getNumJointMotions() + { + if (mJointMotionList) + { + return mJointMotionList->getNumJointMotions(); + } + return 0; + } + virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } // called to determine when a motion should be activated/deactivated based on avatar pixel coverage diff --git a/indra/llcharacter/llmotion.h b/indra/llcharacter/llmotion.h index 2dfc3afc7f..aaa9a146d7 100644 --- a/indra/llcharacter/llmotion.h +++ b/indra/llcharacter/llmotion.h @@ -129,6 +129,9 @@ public: // motions must report their priority level virtual LLJoint::JointPriority getPriority() = 0; + // amount of affected joints + virtual S32 getNumJointMotions() { return 0; }; + // motions must report their blend type virtual LLMotionBlendType getBlendType() = 0; diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index 12ac9e6fc5..d29609fc1e 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -35,14 +35,17 @@ #include "llkeyframemotion.h" #include "llfilepicker.h" #include "lllineeditor.h" +#include "lltrans.h" #include "lluictrlfactory.h" #include "lluictrlfactory.h" #include "lldatapacker.h" extern LLAgent gAgent; +const S32 ADVANCED_VPAD = 3; LLPreviewAnim::LLPreviewAnim(const LLSD& key) - : LLPreview( key ) + : LLPreview( key ), + pMotion(NULL) { mCommitCallbackRegistrar.add("PreviewAnim.Play", boost::bind(&LLPreviewAnim::play, this, _2)); } @@ -53,12 +56,19 @@ BOOL LLPreviewAnim::postBuild() const LLInventoryItem* item = getItem(); if(item) { - gAgentAvatarp->createMotion(item->getAssetUUID()); // preload the animation + pMotion = gAgentAvatarp->createMotion(item->getAssetUUID()); // preload the animation getChild("desc")->setValue(item->getDescription()); } childSetCommitCallback("desc", LLPreview::onText, this); getChild("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe); + getChild("adv_trigger")->setClickedCallback(boost::bind(&LLPreviewAnim::showAdvanced, this)); + pAdvancedStatsTextBox = getChild("AdvancedStats"); + + // Assume that advanced stats start visible (for XUI preview tool's purposes) + pAdvancedStatsTextBox->setVisible(FALSE); + LLRect rect = getRect(); + reshape(rect.getWidth(), rect.getHeight() - pAdvancedStatsTextBox->getRect().getHeight() - ADVANCED_VPAD, FALSE); return LLPreview::postBuild(); } @@ -167,8 +177,8 @@ void LLPreviewAnim::cleanup() this->mDidStart = false; getChild("Inworld")->setValue(FALSE); getChild("Locally")->setValue(FALSE); - getChild("Inworld")->setEnabled(true); - getChild("Locally")->setEnabled(true); + getChild("Inworld")->setEnabled(TRUE); + getChild("Locally")->setEnabled(TRUE); } // virtual @@ -182,3 +192,32 @@ void LLPreviewAnim::onClose(bool app_quitting) gAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_STOP); } } + +void LLPreviewAnim::showAdvanced() +{ + BOOL was_visible = pAdvancedStatsTextBox->getVisible(); + + if (was_visible) + { + pAdvancedStatsTextBox->setVisible(FALSE); + LLRect rect = getRect(); + reshape(rect.getWidth(), rect.getHeight() - pAdvancedStatsTextBox->getRect().getHeight() - ADVANCED_VPAD, FALSE); + } + else + { + pAdvancedStatsTextBox->setVisible(TRUE); + LLRect rect = getRect(); + reshape(rect.getWidth(), rect.getHeight() + pAdvancedStatsTextBox->getRect().getHeight() + ADVANCED_VPAD, FALSE); + + // set text + if (pMotion) + { + pAdvancedStatsTextBox->setTextArg("[PRIORITY]", llformat("%d", pMotion->getPriority())); + pAdvancedStatsTextBox->setTextArg("[DURATION]", llformat("%.2f", pMotion->getDuration())); + pAdvancedStatsTextBox->setTextArg("[EASE_IN]", llformat("%.2f", pMotion->getEaseInDuration())); + pAdvancedStatsTextBox->setTextArg("[EASE_OUT]", llformat("%.2f", pMotion->getEaseOutDuration())); + pAdvancedStatsTextBox->setTextArg("[IS_LOOP]", (pMotion->getLoop() ? LLTrans::getString("PermYes") : LLTrans::getString("PermNo"))); + pAdvancedStatsTextBox->setTextArg("[NUM_JOINTS]", llformat("%d", pMotion->getNumJointMotions())); + } + } +} diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h index 8eaed6ca1f..ebeee367f7 100644 --- a/indra/newview/llpreviewanim.h +++ b/indra/newview/llpreviewanim.h @@ -30,6 +30,9 @@ #include "llpreview.h" #include "llcharacter.h" +class LLMotion; +class LLTextBox; + class LLPreviewAnim : public LLPreview { public: @@ -40,11 +43,14 @@ public: void draw(); void cleanup(); void play(const LLSD& param); - + void showAdvanced(); + protected: LLUUID mItemID; bool mDidStart; + LLMotion* pMotion; + LLTextBox* pAdvancedStatsTextBox; }; #endif // LL_LLPREVIEWANIM_H diff --git a/indra/newview/skins/default/xui/en/floater_preview_animation.xml b/indra/newview/skins/default/xui/en/floater_preview_animation.xml index 3ea5f54f2c..d1f8da55be 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_animation.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_animation.xml @@ -1,15 +1,71 @@ + width="320"> Animation: [NAME] + + + Other people can see + + + + Only you can see + Description: @@ -30,37 +86,41 @@ font="SansSerifSmall" height="19" layout="topleft" - left_delta="95" + left="10" + right="-10" max_length_bytes="127" name="desc" - top="19" - width="170" /> - - + left="10" + name="AdvancedStats" + top_pad="3" + width="200"> +Priority: [PRIORITY] +Duration: [DURATION]s +Ease In: [EASE_IN]s +Ease Out: [EASE_OUT]s +Loop: [IS_LOOP] +Joints: [NUM_JOINTS] + From 5e134b4732e5224b1a5da929a4b12ac63ec120b4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 9 Apr 2021 17:19:43 +0300 Subject: [PATCH 024/286] SL-13182 Fix root folder's state --- indra/llui/llfolderview.cpp | 2 ++ indra/newview/llinventorypanel.cpp | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 0c1dcc301b..bcca4d78a0 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -257,6 +257,8 @@ LLFolderView::LLFolderView(const Params& p) mPopupMenuHandle = menu->getHandle(); mViewModelItem->openItem(); + + mAreChildrenInited = true; // root folder is a special case due to not being loaded normally, assume that it's inited. } // Destroys the object diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 1998fca89d..f181e30d93 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -256,7 +256,6 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) // Determine the root folder in case specified, and // build the views starting with that folder. LLFolderView* folder_view = createFolderRoot(root_id); - folder_view->setChildrenInited(true); // assume that root folder's children are loaded, most of the time we do not load it the normal way mFolderRoot = folder_view->getHandle(); addItemID(root_id, mFolderRoot.get()); @@ -1103,7 +1102,6 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, if (create_root) { folder_view_item->setOpen(TRUE); - parent_folder->setChildrenInited(true); } } } From 52a8e6292cfbfd1d9b006eeeff74e5c4a6a687a8 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 9 Apr 2021 22:19:55 +0300 Subject: [PATCH 025/286] SL-15100 Crash rebulding faces According to bugsplat's "Locals", viewer tried to iterate through 536018048 faces LLVolume pointer seemed to be valid but data in LLVolume wasn't, so likely vobj was invalid --- indra/newview/llvovolume.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 95cfe29a80..05e8bd4cae 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -6048,14 +6048,25 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) LLVOVolume* vobj = drawablep->getVOVolume(); if (debugLoggingEnabled("AnimatedObjectsLinkset")) { - if (vobj->isAnimatedObject() && vobj->isRiggedMesh()) + if (vobj && vobj->isAnimatedObject() && vobj->isRiggedMesh()) { std::string vobj_name = llformat("Vol%p", vobj); F32 est_tris = vobj->getEstTrianglesMax(); - LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL; + LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL; } } - if (vobj->isNoLOD()) continue; + + if (!vobj || vobj->isNoLOD()) + { + continue; + } + + LLVolume* volume = vobj->getVolume(); + + if (!volume) + { + continue; + } vobj->preRebuild(); @@ -6064,7 +6075,6 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) vobj->updateRelativeXform(true); } - LLVolume* volume = vobj->getVolume(); for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { LLFace* face = drawablep->getFace(i); From 4bab66a4b8982ca6cd0685f9f5ec6ce210d658cf Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 9 Apr 2021 23:31:51 +0300 Subject: [PATCH 026/286] SL-15100 Crash rebulding faces #2 All preRebuild crashes appear to be LLVolumeImplFlexible --- indra/newview/llflexibleobject.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index e075a311c2..a24d1d1436 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -734,11 +734,14 @@ void LLVolumeImplFlexible::preRebuild() void LLVolumeImplFlexible::doFlexibleRebuild(bool rebuild_volume) { LLVolume* volume = mVO->getVolume(); - if(rebuild_volume) - { - volume->setDirty(); - } - volume->regen(); + if (volume) + { + if (rebuild_volume) + { + volume->setDirty(); + } + volume->regen(); + } mUpdated = TRUE; } From 8511e9cd6d3481922a138b9bb5938baea948240b Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 12 Apr 2021 12:20:28 +0200 Subject: [PATCH 027/286] Make the advanced animation preview really advanced --- indra/newview/llpreviewanim.cpp | 85 +++++++----- indra/newview/llpreviewanim.h | 6 +- .../xui/de/floater_preview_animation.xml | 15 ++- .../xui/en/floater_preview_animation.xml | 125 +++++++----------- 4 files changed, 115 insertions(+), 116 deletions(-) diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index d29609fc1e..29accdb074 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -41,7 +41,7 @@ #include "lldatapacker.h" extern LLAgent gAgent; -const S32 ADVANCED_VPAD = 3; +//const S32 ADVANCED_VPAD = 3; // Improved animation preview LLPreviewAnim::LLPreviewAnim(const LLSD& key) : LLPreview( key ), @@ -62,13 +62,26 @@ BOOL LLPreviewAnim::postBuild() childSetCommitCallback("desc", LLPreview::onText, this); getChild("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe); - getChild("adv_trigger")->setClickedCallback(boost::bind(&LLPreviewAnim::showAdvanced, this)); - pAdvancedStatsTextBox = getChild("AdvancedStats"); + // Improved animation preview + //getChild("adv_trigger")->setClickedCallback(boost::bind(&LLPreviewAnim::showAdvanced, this)); + //pAdvancedStatsTextBox = getChild("AdvancedStats"); - // Assume that advanced stats start visible (for XUI preview tool's purposes) - pAdvancedStatsTextBox->setVisible(FALSE); - LLRect rect = getRect(); - reshape(rect.getWidth(), rect.getHeight() - pAdvancedStatsTextBox->getRect().getHeight() - ADVANCED_VPAD, FALSE); + //// Assume that advanced stats start visible (for XUI preview tool's purposes) + //pAdvancedStatsTextBox->setVisible(FALSE); + //LLRect rect = getRect(); + //reshape(rect.getWidth(), rect.getHeight() - pAdvancedStatsTextBox->getRect().getHeight() - ADVANCED_VPAD, FALSE); + if (pMotion) + { + LLTextBox* stats_box_left = getChild("AdvancedStatsLeft"); + LLTextBox* stats_box_right = getChild("AdvancedStatsRight"); + stats_box_left->setTextArg("[PRIORITY]", llformat("%d", pMotion->getPriority())); + stats_box_left->setTextArg("[DURATION]", llformat("%.2f", pMotion->getDuration())); + stats_box_left->setTextArg("[IS_LOOP]", (pMotion->getLoop() ? LLTrans::getString("PermYes") : LLTrans::getString("PermNo"))); + stats_box_right->setTextArg("[EASE_IN]", llformat("%.2f", pMotion->getEaseInDuration())); + stats_box_right->setTextArg("[EASE_OUT]", llformat("%.2f", pMotion->getEaseOutDuration())); + stats_box_right->setTextArg("[NUM_JOINTS]", llformat("%d", pMotion->getNumJointMotions())); + } + // return LLPreview::postBuild(); } @@ -193,31 +206,33 @@ void LLPreviewAnim::onClose(bool app_quitting) } } -void LLPreviewAnim::showAdvanced() -{ - BOOL was_visible = pAdvancedStatsTextBox->getVisible(); - - if (was_visible) - { - pAdvancedStatsTextBox->setVisible(FALSE); - LLRect rect = getRect(); - reshape(rect.getWidth(), rect.getHeight() - pAdvancedStatsTextBox->getRect().getHeight() - ADVANCED_VPAD, FALSE); - } - else - { - pAdvancedStatsTextBox->setVisible(TRUE); - LLRect rect = getRect(); - reshape(rect.getWidth(), rect.getHeight() + pAdvancedStatsTextBox->getRect().getHeight() + ADVANCED_VPAD, FALSE); - - // set text - if (pMotion) - { - pAdvancedStatsTextBox->setTextArg("[PRIORITY]", llformat("%d", pMotion->getPriority())); - pAdvancedStatsTextBox->setTextArg("[DURATION]", llformat("%.2f", pMotion->getDuration())); - pAdvancedStatsTextBox->setTextArg("[EASE_IN]", llformat("%.2f", pMotion->getEaseInDuration())); - pAdvancedStatsTextBox->setTextArg("[EASE_OUT]", llformat("%.2f", pMotion->getEaseOutDuration())); - pAdvancedStatsTextBox->setTextArg("[IS_LOOP]", (pMotion->getLoop() ? LLTrans::getString("PermYes") : LLTrans::getString("PermNo"))); - pAdvancedStatsTextBox->setTextArg("[NUM_JOINTS]", llformat("%d", pMotion->getNumJointMotions())); - } - } -} +// Improved animation preview +//void LLPreviewAnim::showAdvanced() +//{ +// BOOL was_visible = pAdvancedStatsTextBox->getVisible(); +// +// if (was_visible) +// { +// pAdvancedStatsTextBox->setVisible(FALSE); +// LLRect rect = getRect(); +// reshape(rect.getWidth(), rect.getHeight() - pAdvancedStatsTextBox->getRect().getHeight() - ADVANCED_VPAD, FALSE); +// } +// else +// { +// pAdvancedStatsTextBox->setVisible(TRUE); +// LLRect rect = getRect(); +// reshape(rect.getWidth(), rect.getHeight() + pAdvancedStatsTextBox->getRect().getHeight() + ADVANCED_VPAD, FALSE); +// +// // set text +// if (pMotion) +// { +// pAdvancedStatsTextBox->setTextArg("[PRIORITY]", llformat("%d", pMotion->getPriority())); +// pAdvancedStatsTextBox->setTextArg("[DURATION]", llformat("%.2f", pMotion->getDuration())); +// pAdvancedStatsTextBox->setTextArg("[EASE_IN]", llformat("%.2f", pMotion->getEaseInDuration())); +// pAdvancedStatsTextBox->setTextArg("[EASE_OUT]", llformat("%.2f", pMotion->getEaseOutDuration())); +// pAdvancedStatsTextBox->setTextArg("[IS_LOOP]", (pMotion->getLoop() ? LLTrans::getString("PermYes") : LLTrans::getString("PermNo"))); +// pAdvancedStatsTextBox->setTextArg("[NUM_JOINTS]", llformat("%d", pMotion->getNumJointMotions())); +// } +// } +//} +// diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h index ebeee367f7..df5ad99187 100644 --- a/indra/newview/llpreviewanim.h +++ b/indra/newview/llpreviewanim.h @@ -43,14 +43,16 @@ public: void draw(); void cleanup(); void play(const LLSD& param); - void showAdvanced(); + // Improved animation preview + //void showAdvanced(); protected: LLUUID mItemID; bool mDidStart; LLMotion* pMotion; - LLTextBox* pAdvancedStatsTextBox; + // Improved animation preview + //LLTextBox* pAdvancedStatsTextBox; }; #endif // LL_LLPREVIEWANIM_H diff --git a/indra/newview/skins/default/xui/de/floater_preview_animation.xml b/indra/newview/skins/default/xui/de/floater_preview_animation.xml index 2dd47a27ad..51a29edf70 100644 --- a/indra/newview/skins/default/xui/de/floater_preview_animation.xml +++ b/indra/newview/skins/default/xui/de/floater_preview_animation.xml @@ -3,10 +3,21 @@ Animation: [NAME] - + Beschreibung: - + - - Other people can see - - - - Only you can see - Description: @@ -88,25 +32,40 @@ font="SansSerifSmall" height="19" layout="topleft" - left="10" - right="-10" + left_pad="5" max_length_bytes="127" name="desc" - top_pad="0" /> - + + + + width="150"> Priority: [PRIORITY] Duration: [DURATION]s +Loop: [IS_LOOP] + + Ease In: [EASE_IN]s Ease Out: [EASE_OUT]s -Loop: [IS_LOOP] Joints: [NUM_JOINTS] From 105416600e27a3d8a850617520ce86ca215222a1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 12 Apr 2021 18:05:51 +0300 Subject: [PATCH 028/286] SL-15107 Fix some typos in llsetkeybinddialog --- indra/newview/llsetkeybinddialog.cpp | 10 +++++----- indra/newview/llsetkeybinddialog.h | 2 +- .../skins/default/xui/en/floater_select_key.xml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp index 4b36822e9a..74844a80e8 100644 --- a/indra/newview/llsetkeybinddialog.cpp +++ b/indra/newview/llsetkeybinddialog.cpp @@ -96,7 +96,7 @@ BOOL LLSetKeyBindDialog::postBuild() getChild("Cancel")->setFocus(TRUE); pCheckBox = getChild("apply_all"); - pDesription = getChild("descritption"); + pDescription = getChild("description"); gFocusMgr.setKeystrokesOnly(TRUE); @@ -160,8 +160,8 @@ void LLSetKeyBindDialog::setParent(LLKeyBindResponderInterface* parent, LLView* } input += getString("keyboard"); } - pDesription->setText(getString("basic_description")); - pDesription->setTextArg("[INPUT]", input); + pDescription->setText(getString("basic_description")); + pDescription->setTextArg("[INPUT]", input); } // static @@ -257,8 +257,8 @@ bool LLSetKeyBindDialog::recordAndHandleKey(KEY key, MASK mask, BOOL down) if (LLKeyConflictHandler::isReservedByMenu(key, mask)) { - pDesription->setText(getString("reserved_by_menu")); - pDesription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key)); + pDescription->setText(getString("reserved_by_menu")); + pDescription->setTextArg("[KEYSTR]", LLKeyboard::stringFromAccelerator(mask,key)); mLastMaskKey = 0; return true; } diff --git a/indra/newview/llsetkeybinddialog.h b/indra/newview/llsetkeybinddialog.h index a34b952233..461965720a 100644 --- a/indra/newview/llsetkeybinddialog.h +++ b/indra/newview/llsetkeybinddialog.h @@ -83,7 +83,7 @@ private: void setKeyBind(EMouseClickType click, KEY key, MASK mask, bool all_modes); LLKeyBindResponderInterface *pParent; LLCheckBoxCtrl *pCheckBox; - LLTextBase *pDesription; + LLTextBase *pDescription; U32 mKeyFilterMask; Updater *pUpdater; diff --git a/indra/newview/skins/default/xui/en/floater_select_key.xml b/indra/newview/skins/default/xui/en/floater_select_key.xml index 48d9eee4cd..998948fca1 100644 --- a/indra/newview/skins/default/xui/en/floater_select_key.xml +++ b/indra/newview/skins/default/xui/en/floater_select_key.xml @@ -33,7 +33,7 @@ Combination [KEYSTR] is reserved by menu. height="30" layout="topleft" left="30" - name="descritption" + name="description" top="25" word_wrap="true" width="212"> From d0ac1505a7aebc98219fb5f60f6bfb73df6586ec Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 13 Apr 2021 00:40:00 +0300 Subject: [PATCH 029/286] SL-15102 Crash at load_face_from_dom_triangles --- indra/llprimitive/lldaeloader.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index dfa29fb539..33e90555fa 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -198,6 +198,17 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector& fa } LLVolumeFace::VertexMapData::PointMap point_map; + + if (idx_stride <= 0 + || (pos_source && pos_offset >= idx_stride) + || (tc_source && tc_offset >= idx_stride) + || (norm_source && norm_offset >= idx_stride)) + { + // Looks like these offsets should fit inside idx_stride + // Might be good idea to also check idx.getCount()%idx_stride != 0 + LL_WARNS() << "Invalid pos_offset " << pos_offset << ", tc_offset " << tc_offset << " or norm_offset " << norm_offset << LL_ENDL; + return LLModel::BAD_ELEMENT; + } for (U32 i = 0; i < idx.getCount(); i += idx_stride) { From 45f3b6ed175397fbfbc2a31e927b2b4b25d3bc8c Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 14 Apr 2021 17:59:44 +0300 Subject: [PATCH 030/286] SL-15107 Fix a typo in floater_model_preview --- indra/newview/skins/default/xui/en/floater_model_preview.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 02a21764ce..bb61549592 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1624,7 +1624,7 @@ Analysed: wrap="true" width="462" visible="true"> - You dont have rights to upload mesh models. [[VURL] Find out how] to get certified. + You don't have rights to upload mesh models. [[VURL] Find out how] to get certified. Date: Fri, 16 Apr 2021 22:52:11 +0300 Subject: [PATCH 031/286] SL-15129 Restore translated argument --- .../skins/default/xui/es/floater_buy_contents.xml | 2 +- .../skins/default/xui/es/floater_import_collada.xml | 10 +++++----- indra/newview/skins/default/xui/es/notifications.xml | 8 ++++---- indra/newview/skins/default/xui/es/strings.xml | 10 +++++----- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/indra/newview/skins/default/xui/es/floater_buy_contents.xml b/indra/newview/skins/default/xui/es/floater_buy_contents.xml index 3563d4bd0f..d078868db2 100644 --- a/indra/newview/skins/default/xui/es/floater_buy_contents.xml +++ b/indra/newview/skins/default/xui/es/floater_buy_contents.xml @@ -1,7 +1,7 @@ - <nolink>[NOMBRE]</nolink> contiene: + <nolink>[NAME]</nolink> contiene: ¿Comprar por [AMOUNT] L$ a [NAME]? diff --git a/indra/newview/skins/default/xui/es/floater_import_collada.xml b/indra/newview/skins/default/xui/es/floater_import_collada.xml index 7e9a00797a..24df8e41a3 100644 --- a/indra/newview/skins/default/xui/es/floater_import_collada.xml +++ b/indra/newview/skins/default/xui/es/floater_import_collada.xml @@ -1,13 +1,13 @@ - Redes: [RECUENTO] + Redes: [COUNT] - Texturas: [RECUENTO] + Texturas: [COUNT] - Estado: [ESTADO] + Estado: [STATUS] + + From fea2d7bacca421be87794f3ece5c1e6a8fa7414b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 8 Oct 2021 00:41:26 +0300 Subject: [PATCH 088/286] SL-16152 _Allocate failed --- indra/llmath/llvolume.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index e085fa6ada..2393f8acc0 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -5295,22 +5295,23 @@ bool LLVolumeFace::cacheOptimize() { triangle_data.resize(mNumIndices / 3); vertex_data.resize(mNumVertices); - } - catch (std::bad_alloc&) - { - LL_WARNS("LLVOLUME") << "Resize failed" << LL_ENDL; - return false; - } - for (U32 i = 0; i < mNumIndices; i++) - { //populate vertex data and triangle data arrays - U16 idx = mIndices[i]; - U32 tri_idx = i/3; + for (U32 i = 0; i < mNumIndices; i++) + { //populate vertex data and triangle data arrays + U16 idx = mIndices[i]; + U32 tri_idx = i / 3; - vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx])); - vertex_data[idx].mIdx = idx; - triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]); - } + vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx])); + vertex_data[idx].mIdx = idx; + triangle_data[tri_idx].mVertex[i % 3] = &(vertex_data[idx]); + } + } + catch (std::bad_alloc&) + { + // resize or push_back failed + LL_WARNS("LLVOLUME") << "Resize for " << mNumVertices << " vertices failed" << LL_ENDL; + return false; + } /*F32 pre_acmr = 1.f; //measure cache misses from before rebuild From bdb4a90e7c8f05001cf084e30832cedde1b4a03e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 8 Oct 2021 02:12:28 +0300 Subject: [PATCH 089/286] SL-16157 Crash at LLFontGL::maxDrawableChars --- indra/llui/lltextbase.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 20bea7fe24..ea2d357d5d 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1558,11 +1558,14 @@ void LLTextBase::reflow() { // find first element whose end comes after start_index line_list_t::iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), start_index, line_end_compare()); - line_start_index = iter->mDocIndexStart; - line_count = iter->mLineNum; - cur_top = iter->mRect.mTop; - getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset); - mLineInfoList.erase(iter, mLineInfoList.end()); + if (iter != mLineInfoList.end()) + { + line_start_index = iter->mDocIndexStart; + line_count = iter->mLineNum; + cur_top = iter->mRect.mTop; + getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset); + mLineInfoList.erase(iter, mLineInfoList.end()); + } } S32 line_height = 0; From 404c498795c0bbc2ef86a6436f700986e4dbc651 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 8 Oct 2021 17:58:52 +0300 Subject: [PATCH 090/286] SL-14664 Fix missed resource declaration --- indra/newview/res/viewerRes.rc | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc index ff2d8b4943..4ee26a312a 100755 --- a/indra/newview/res/viewerRes.rc +++ b/indra/newview/res/viewerRes.rc @@ -99,6 +99,7 @@ END TOOLGRAB CURSOR "lltoolgrab.cur" TOOLLAND CURSOR "lltoolland.cur" TOOLZOOMIN CURSOR "lltoolzoomin.cur" +TOOLZOOMOUT CURSOR "lltoolzoomout.cur" TOOLCREATE CURSOR "lltoolcreate.cur" ARROWDRAG CURSOR "llarrowdrag.cur" ARROW CURSOR "llarrow.cur" From c1943e5efb18a0786a538237eee4bee8a7330e56 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 8 Oct 2021 23:56:43 +0300 Subject: [PATCH 091/286] SL-16161 Don't process new plugin messages on shutdown Some pending messages might try to update non-existing view or cause a pop up, neither should be avaliable by this point, so just don't process them --- indra/llplugin/llpluginprocessparent.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 73327ce2ee..7a704b71f3 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -192,6 +192,7 @@ void LLPluginProcessParent::shutdown() && state != STATE_ERROR) { (*it).second->setState(STATE_GOODBYE); + (*it).second->mOwner = NULL; } if (state != STATE_DONE) { @@ -407,7 +408,10 @@ void LLPluginProcessParent::idle(void) mMessagePipe->pumpOutput(); // Only do input processing here if this instance isn't in a pollset. - if(!mPolledInput) + // If we are shutting down plugin, owner is null and we can't process + // input, we are here only to send shutdown_plugin message + if(!mPolledInput + && mState != STATE_GOODBYE) { mMessagePipe->pumpInput(); } From 66b5e49a7950962a1d1793c21f2714b125f8c47d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 11 Oct 2021 19:26:45 +0300 Subject: [PATCH 092/286] SL-16161 Don't process new plugin messages on shutdown #2 --- indra/llplugin/llpluginprocessparent.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 7a704b71f3..c39ac815c0 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -408,10 +408,10 @@ void LLPluginProcessParent::idle(void) mMessagePipe->pumpOutput(); // Only do input processing here if this instance isn't in a pollset. - // If we are shutting down plugin, owner is null and we can't process - // input, we are here only to send shutdown_plugin message + // If viewer and plugin are both shutting down, don't process further + // input, viewer won't be able to handle it. if(!mPolledInput - && mState != STATE_GOODBYE) + && !(mState >= STATE_GOODBYE && LLApp::isExiting())) { mMessagePipe->pumpInput(); } From e45d695cc836b3a0acd6c5351654d9ae96c5e1b6 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 11 Oct 2021 19:34:16 +0300 Subject: [PATCH 093/286] SL-15079 Fix group recognition In god mode isInGroup always returns true even if id belongs not to a group, but to an agent. But for some cases function is used to determine if session is a group or an agent. --- indra/newview/llimview.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 1509e5ddab..3017d927e5 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -900,7 +900,7 @@ bool LLIMModel::LLIMSession::isOutgoingAdHoc() const bool LLIMModel::LLIMSession::isAdHoc() { - return IM_SESSION_CONFERENCE_START == mType || (IM_SESSION_INVITE == mType && !gAgent.isInGroup(mSessionID)); + return IM_SESSION_CONFERENCE_START == mType || (IM_SESSION_INVITE == mType && !gAgent.isInGroup(mSessionID, TRUE)); } bool LLIMModel::LLIMSession::isP2P() @@ -910,7 +910,7 @@ bool LLIMModel::LLIMSession::isP2P() bool LLIMModel::LLIMSession::isGroupChat() { - return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID)); + return IM_SESSION_GROUP_START == mType || (IM_SESSION_INVITE == mType && gAgent.isInGroup(mSessionID, TRUE)); } bool LLIMModel::LLIMSession::isOtherParticipantAvaline() @@ -2035,7 +2035,7 @@ void LLCallDialog::setIcon(const LLSD& session_id, const LLSD& participant_id) // *NOTE: 12/28/2009: check avaline calls: LLVoiceClient::isParticipantAvatar returns false for them bool participant_is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); - bool is_group = participant_is_avatar && gAgent.isInGroup(session_id); + bool is_group = participant_is_avatar && gAgent.isInGroup(session_id, TRUE); LLAvatarIconCtrl* avatar_icon = getChild("avatar_icon"); LLGroupIconCtrl* group_icon = getChild("group_icon"); @@ -2330,7 +2330,7 @@ BOOL LLIncomingCallDialog::postBuild() } std::string call_type; - if (gAgent.isInGroup(session_id)) + if (gAgent.isInGroup(session_id, TRUE)) { LLStringUtil::format_map_t args; LLGroupData data; @@ -2507,8 +2507,8 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload switch(type){ case IM_SESSION_CONFERENCE_START: case IM_SESSION_GROUP_START: - case IM_SESSION_INVITE: - if (gAgent.isInGroup(session_id)) + case IM_SESSION_INVITE: + if (gAgent.isInGroup(session_id, TRUE)) { LLGroupData data; if (!gAgent.getGroupData(session_id, data)) break; @@ -3055,7 +3055,7 @@ void LLIMMgr::inviteToSession( notify_box_type = "VoiceInviteP2P"; voice_invite = TRUE; } - else if ( gAgent.isInGroup(session_id) ) + else if ( gAgent.isInGroup(session_id, TRUE) ) { //only really old school groups have voice invitations notify_box_type = "VoiceInviteGroup"; From 7fa5a578f943016ee784d74a6e1e375bef94f8bf Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 12 Oct 2021 12:48:22 +0200 Subject: [PATCH 094/286] Update German translation --- .../newview/skins/default/xui/de/panel_preferences_setup.xml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/indra/newview/skins/default/xui/de/panel_preferences_setup.xml b/indra/newview/skins/default/xui/de/panel_preferences_setup.xml index 1773e0ea3a..45d50b2f36 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_setup.xml @@ -39,10 +39,7 @@