diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 814682220e..9c40acaa62 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -1073,6 +1073,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) // TODO - figure out if this should be moved into the noclobber fields above mThumbnailUUID.setNull(); mFavorite = false; + mPermissions.init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null); // iterate as map to avoid making unnecessary temp copies of everything LLSD::map_const_iterator i, end; @@ -1131,7 +1132,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) if (i->first == INV_PERMISSIONS_LABEL) { - mPermissions = ll_permissions_from_sd(i->second); + mPermissions.importLLSD(i->second); continue; } @@ -1600,53 +1601,68 @@ void LLInventoryCategory::exportLLSD(LLSD& cat_data) const } } -bool LLInventoryCategory::importLLSD(const LLSD& cat_data) +bool LLInventoryCategory::importLLSDMap(const LLSD& cat_data) { - if (cat_data.has(INV_FOLDER_ID_LABEL)) + LLSD::map_const_iterator i, end; + end = cat_data.endMap(); + for ( i = cat_data.beginMap(); i != end; ++i) { - setUUID(cat_data[INV_FOLDER_ID_LABEL].asUUID()); + importLLSD(i->first, i->second); } - if (cat_data.has(INV_PARENT_ID_LABEL)) + return true; +} + +bool LLInventoryCategory::importLLSD(const std::string& label, const LLSD& value) +{ + if (label == INV_FOLDER_ID_LABEL) { - setParent(cat_data[INV_PARENT_ID_LABEL].asUUID()); + setUUID(value.asUUID()); + return true; } - if (cat_data.has(INV_ASSET_TYPE_LABEL)) + else if (label == INV_PARENT_ID_LABEL) { - setType(LLAssetType::lookup(cat_data[INV_ASSET_TYPE_LABEL].asString())); + setParent(value.asUUID()); + return true; } - if (cat_data.has(INV_PREFERRED_TYPE_LABEL)) + else if (label == INV_ASSET_TYPE_LABEL) { - setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString())); + setType(LLAssetType::lookup(value.asString())); + return true; } - if (cat_data.has(INV_THUMBNAIL_LABEL)) + else if (label == INV_PREFERRED_TYPE_LABEL) + { + setPreferredType(LLFolderType::lookup(value.asString())); + return true; + } + else if (label == INV_THUMBNAIL_LABEL) { LLUUID thumbnail_uuid; - const LLSD &thumbnail_data = cat_data[INV_THUMBNAIL_LABEL]; - if (thumbnail_data.has(INV_ASSET_ID_LABEL)) + if (value.has(INV_ASSET_ID_LABEL)) { - thumbnail_uuid = thumbnail_data[INV_ASSET_ID_LABEL].asUUID(); + thumbnail_uuid = value[INV_ASSET_ID_LABEL].asUUID(); } setThumbnailUUID(thumbnail_uuid); + return true; } - if (cat_data.has(INV_FAVORITE_LABEL)) + if (label == INV_FAVORITE_LABEL) { bool favorite = false; - const LLSD& favorite_data = cat_data[INV_FAVORITE_LABEL]; - if (favorite_data.has(INV_TOGGLED_LABEL)) + if (value.has(INV_TOGGLED_LABEL)) { - favorite = favorite_data[INV_TOGGLED_LABEL].asBoolean(); + favorite = value[INV_TOGGLED_LABEL].asBoolean(); } setFavorite(favorite); } - if (cat_data.has(INV_NAME_LABEL)) + else if (label == INV_NAME_LABEL) { - mName = cat_data[INV_NAME_LABEL].asString(); + mName = value.asString(); LLStringUtil::replaceNonstandardASCII(mName, ' '); LLStringUtil::replaceChar(mName, '|', ' '); + return true; } - - return true; + return false; } + ///---------------------------------------------------------------------------- /// Local function definitions for testing purposes ///---------------------------------------------------------------------------- diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 17670d2ea1..181c46226c 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -274,7 +274,8 @@ public: virtual bool exportLegacyStream(std::ostream& output_stream, bool include_asset_key = true) const; virtual void exportLLSD(LLSD& sd) const; - bool importLLSD(const LLSD& cat_data); + bool importLLSDMap(const LLSD& cat_data); + virtual bool importLLSD(const std::string& label, const LLSD& value); //-------------------------------------------------------------------- // Member Variables //-------------------------------------------------------------------- diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp index e6256daa0e..84fde40a1f 100644 --- a/indra/llinventory/llpermissions.cpp +++ b/indra/llinventory/llpermissions.cpp @@ -704,6 +704,79 @@ bool LLPermissions::exportLegacyStream(std::ostream& output_stream) const return true; } +static const std::string PERM_CREATOR_ID_LABEL("creator_id"); +static const std::string PERM_OWNER_ID_LABEL("owner_id"); +static const std::string PERM_LAST_OWNER_ID_LABEL("last_owner_id"); +static const std::string PERM_GROUP_ID_LABEL("group_id"); +static const std::string PERM_IS_OWNER_GROUP_LABEL("is_owner_group"); +static const std::string PERM_BASE_MASK_LABEL("base_mask"); +static const std::string PERM_OWNER_MASK_LABEL("owner_mask"); +static const std::string PERM_GROUP_MASK_LABEL("group_mask"); +static const std::string PERM_EVERYONE_MASK_LABEL("everyone_mask"); +static const std::string PERM_NEXT_OWNER_MASK_LABEL("next_owner_mask"); + +void LLPermissions::importLLSD(const LLSD& sd_perm) +{ + LLSD::map_const_iterator i, end; + end = sd_perm.endMap(); + for (i = sd_perm.beginMap(); i != end; ++i) + { + const std::string& label = i->first; + if (label == PERM_CREATOR_ID_LABEL) + { + mCreator = i->second.asUUID(); + continue; + } + if (label == PERM_OWNER_ID_LABEL) + { + mOwner = i->second.asUUID(); + continue; + } + if (label == PERM_LAST_OWNER_ID_LABEL) + { + mLastOwner = i->second.asUUID(); + continue; + } + if (label == PERM_GROUP_ID_LABEL) + { + mGroup = i->second.asUUID(); + continue; + } + if (label == PERM_BASE_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskBase = mask; + continue; + } + if (label == PERM_OWNER_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskOwner = mask; + continue; + } + if (label == PERM_EVERYONE_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskEveryone = mask; + continue; + } + if (label == PERM_GROUP_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskGroup = mask; + continue; + } + if (label == PERM_NEXT_OWNER_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskNextOwner = mask; + continue; + } + } + + fix(); +} + bool LLPermissions::operator==(const LLPermissions &rhs) const { return @@ -1016,16 +1089,6 @@ std::string mask_to_string(U32 mask, bool isOpenSim /*=false*/) // rem ///---------------------------------------------------------------------------- /// exported functions ///---------------------------------------------------------------------------- -static const std::string PERM_CREATOR_ID_LABEL("creator_id"); -static const std::string PERM_OWNER_ID_LABEL("owner_id"); -static const std::string PERM_LAST_OWNER_ID_LABEL("last_owner_id"); -static const std::string PERM_GROUP_ID_LABEL("group_id"); -static const std::string PERM_IS_OWNER_GROUP_LABEL("is_owner_group"); -static const std::string PERM_BASE_MASK_LABEL("base_mask"); -static const std::string PERM_OWNER_MASK_LABEL("owner_mask"); -static const std::string PERM_GROUP_MASK_LABEL("group_mask"); -static const std::string PERM_EVERYONE_MASK_LABEL("everyone_mask"); -static const std::string PERM_NEXT_OWNER_MASK_LABEL("next_owner_mask"); LLSD ll_create_sd_from_permissions(const LLPermissions& perm) { @@ -1050,25 +1113,6 @@ void ll_fill_sd_from_permissions(LLSD& rv, const LLPermissions& perm) LLPermissions ll_permissions_from_sd(const LLSD& sd_perm) { LLPermissions rv; - rv.init( - sd_perm[PERM_CREATOR_ID_LABEL].asUUID(), - sd_perm[PERM_OWNER_ID_LABEL].asUUID(), - sd_perm[PERM_LAST_OWNER_ID_LABEL].asUUID(), - sd_perm[PERM_GROUP_ID_LABEL].asUUID()); - - // We do a cast to U32 here since LLSD does not attempt to - // represent unsigned ints. - PermissionMask mask; - mask = (U32)(sd_perm[PERM_BASE_MASK_LABEL].asInteger()); - rv.setMaskBase(mask); - mask = (U32)(sd_perm[PERM_OWNER_MASK_LABEL].asInteger()); - rv.setMaskOwner(mask); - mask = (U32)(sd_perm[PERM_EVERYONE_MASK_LABEL].asInteger()); - rv.setMaskEveryone(mask); - mask = (U32)(sd_perm[PERM_GROUP_MASK_LABEL].asInteger()); - rv.setMaskGroup(mask); - mask = (U32)(sd_perm[PERM_NEXT_OWNER_MASK_LABEL].asInteger()); - rv.setMaskNext(mask); - rv.fix(); + rv.importLLSD(sd_perm); return rv; } diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h index 40c78945dc..469eacc5ef 100644 --- a/indra/llinventory/llpermissions.h +++ b/indra/llinventory/llpermissions.h @@ -302,6 +302,8 @@ public: bool importLegacyStream(std::istream& input_stream); bool exportLegacyStream(std::ostream& output_stream) const; + void importLLSD(const LLSD& sd_perm); + bool operator==(const LLPermissions &rhs) const; bool operator!=(const LLPermissions &rhs) const; diff --git a/indra/llinventory/tests/inventorymisc_test.cpp b/indra/llinventory/tests/inventorymisc_test.cpp index e41500b4c5..f11a4c3bf7 100644 --- a/indra/llinventory/tests/inventorymisc_test.cpp +++ b/indra/llinventory/tests/inventorymisc_test.cpp @@ -518,7 +518,7 @@ namespace tut file.close(); LLPointer src2 = new LLInventoryCategory(); - src2->importLLSD(s_item); + src2->importLLSDMap(s_item); ensure_equals("1.item id::getUUID() failed", src1->getUUID(), src2->getUUID()); ensure_equals("2.parent::getParentUUID() failed", src1->getParentUUID(), src2->getParentUUID()); diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index 23b5c69ce8..7b1cfe9d21 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -160,6 +160,16 @@ void LLUrlAction::copyLabelToClipboard(std::string url) } } +std::string LLUrlAction::getURLLabel(std::string url) +{ + LLUrlMatch match; + if (LLUrlRegistry::instance().findUrl(url, match)) + { + return match.getLabel(); + } + return ""; +} + void LLUrlAction::showProfile(std::string url) { // Get id from 'secondlife:///app/{cmd}/{id}/{action}' diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index e18edfc05a..0e0ad7a85a 100644 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -74,6 +74,8 @@ public: /// copy a Url to the clipboard static void copyURLToClipboard(std::string url); + static std::string getURLLabel(std::string url); + /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile static void showProfile(std::string url); static std::string getUserID(std::string url); diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 7aced70e53..ceb47f3f59 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -43,11 +43,6 @@ #include "llexperiencecache.h" #include "v3dmath.h" -// hop:// protocol> -//#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" -#define APP_HEADER_REGEX "(((hop|x-grid-location-info)://[-\\w\\.\\:\\@]+/app)|((hop|secondlife):///app))" -// - // Utility functions std::string localize_slapp_label(const std::string& url, const std::string& full_name); diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index e0ac274f08..6cd83507f2 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -43,6 +43,11 @@ class LLAvatarName; class LLVector3d; +// hop:// protocol> +//#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" +#define APP_HEADER_REGEX "(((hop|x-grid-location-info)://[-\\w\\.\\:\\@]+/app)|((hop|secondlife):///app))" +// + typedef boost::signals2::signal LLUrlLabelSignal; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 4ad873cf4f..c1b9c6002a 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -191,7 +191,7 @@ bool LLFloaterModelPreview::postBuild() for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) { LLComboBox* lod_source_combo = getChild("lod_source_" + lod_name[lod]); - lod_source_combo->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLoDSourceCommit, this, lod, true)); + lod_source_combo->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLoDSourceCommit, this, lod)); lod_source_combo->setCurrentByIndex(mLODMode[lod]); getChild("lod_browse_" + lod_name[lod])->setCommitCallback(boost::bind(&LLFloaterModelPreview::onBrowseLOD, this, lod)); @@ -858,7 +858,7 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) LLComboBox* lod_source_combo = getChild("lod_source_" + lod_name[i]); if (lod_source_combo->getCurrentIndex() == LLModelPreview::USE_LOD_ABOVE) { - onLoDSourceCommit(i, false); + onLoDSourceCommit(i); } else { @@ -1943,7 +1943,7 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible) } } -void LLFloaterModelPreview::onLoDSourceCommit(S32 lod, bool refresh_ui) +void LLFloaterModelPreview::onLoDSourceCommit(S32 lod) { mModelPreview->updateLodControls(lod); @@ -1969,12 +1969,10 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod, bool refresh_ui) // rebuild LoD to update triangle counts onLODParamCommit(lod, true); } - else if (refresh_ui && index == LLModelPreview::USE_LOD_ABOVE) + if (index == LLModelPreview::USE_LOD_ABOVE) { - // Update mUploadData for updateStatusMessages - mModelPreview->rebuildUploadData(); - // Update UI with new triangle values - mModelPreview->updateStatusMessages(); + // refresh to pick triangle counts + mModelPreview->mDirty = true; } } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index b77d8cf1af..1ef81666e9 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -208,7 +208,7 @@ private: void onClickCalculateBtn(); void onJointListSelection(); - void onLoDSourceCommit(S32 lod, bool refresh_ui); + void onLoDSourceCommit(S32 lod); void modelUpdated(bool calculate_visible); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index ea48086180..9b65457fd0 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -4984,6 +4984,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items items.push_back(std::string("Rename")); items.push_back(std::string("thumbnail")); + addInventoryFavoritesMenuOptions(items); addDeleteContextMenuOptions(items, disabled_items); // EXT-4030: disallow deletion of currently worn outfit const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); @@ -5009,6 +5010,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items EMyOutfitsSubfolderType in_my_outfits = myoutfit_object_subfolder_type(model, mUUID, outfits_id); if (in_my_outfits != MY_OUTFITS_NO) { + // Either an outfit or a subfolder inside MY_OUTFITS if (in_my_outfits == MY_OUTFITS_SUBFOLDER) { // Not inside an outfit, but inside 'my outfits' @@ -5018,6 +5020,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items items.push_back(std::string("Rename")); items.push_back(std::string("thumbnail")); + addInventoryFavoritesMenuOptions(items); addDeleteContextMenuOptions(items, disabled_items); } else @@ -5066,14 +5069,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items if (model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) == mUUID) { items.push_back(std::string("Copy outfit list to clipboard")); - if (isFavorite()) - { - items.push_back(std::string("Remove from Favorites")); - } - else - { - items.push_back(std::string("Add to Favorites")); - } + addInventoryFavoritesMenuOptions(items); addOpenFolderMenuOptions(flags, items); } @@ -5393,6 +5389,18 @@ void LLFolderBridge::addOpenFolderMenuOptions(U32 flags, menuentry_vec_t& items) } } +void LLFolderBridge::addInventoryFavoritesMenuOptions(menuentry_vec_t& items) +{ + if (isFavorite()) + { + items.push_back(std::string("Remove from Favorites")); + } + else + { + items.push_back(std::string("Add to Favorites")); + } +} + bool LLFolderBridge::hasChildren() const { LLInventoryModel* model = getInventoryModel(); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 24b0d13b52..bc688bce9c 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -372,6 +372,7 @@ protected: void buildContextMenuOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items); void buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items); void addOpenFolderMenuOptions(U32 flags, menuentry_vec_t& items); + void addInventoryFavoritesMenuOptions(menuentry_vec_t& items); // Inventory favorites, not toolbar favorites //-------------------------------------------------------------------- // Menu callbacks diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 0a1b306706..cb6b4ab1ee 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -94,7 +94,7 @@ // 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 = 4; +const S32 LLInventoryModel::sCurrentInvCacheVersion = 5; bool LLInventoryModel::sFirstTimeInViewer2 = true; S32 LLInventoryModel::sPendingSystemFolders = 0; @@ -3664,7 +3664,7 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, } LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL; - llifstream file(filename.c_str()); + llifstream file(filename.c_str(), std::ifstream::in | std::ifstream::binary); if (!file.is_open()) { @@ -3673,80 +3673,92 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, } is_cache_obsolete = true; // Obsolete until proven current - - //U64 lines_count = 0U; - std::string line; - LLPointer parser = new LLSDNotationParser(); - while (std::getline(file, line)) + U32 value_nbo = 0; + file.read((char*)&value_nbo, sizeof(U32)); + if (file.fail()) { - LLSD s_item; - std::istringstream iss(line); - if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + LL_WARNS(LOG_INV) << "Failed to read cache version. Unable to load inventory from: " << filename << LL_ENDL; + } + else + { + S32 version = (S32)ntohl(value_nbo); + if (version == sCurrentInvCacheVersion) { - LL_WARNS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL; - break; + // Cache is up to date + is_cache_obsolete = false; } - - if (s_item.has("inv_cache_version")) + else { - S32 version = s_item["inv_cache_version"].asInteger(); - if (version == sCurrentInvCacheVersion) - { - // Cache is up to date - is_cache_obsolete = false; - continue; - } - else - { - LL_WARNS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL; - break; - } + LL_WARNS(LOG_INV) << "Inventory cache is out of date" << LL_ENDL; } - else if (s_item.has("cat_id")) - { - if (is_cache_obsolete) - break; + } - LLPointer inv_cat = new LLViewerInventoryCategory(LLUUID::null); - if(inv_cat->importLLSD(s_item)) - { - categories.push_back(inv_cat); - } + LLSD inventory; + if (!is_cache_obsolete) + { + LLPointer parser = new LLSDBinaryParser(); + + if (parser->parse(file, inventory, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) + { + is_cache_obsolete = true; + LL_WARNS(LOG_INV) << "Parsing inventory cache failed" << LL_ENDL; } - else if (s_item.has("item_id")) - { - if (is_cache_obsolete) - break; + } - LLPointer inv_item = new LLViewerInventoryItem; - if( inv_item->fromLLSD(s_item) ) + if (!is_cache_obsolete) + { + const LLSD& llsd_cats = inventory["categories"]; + if (llsd_cats.isArray()) + { + LLSD::array_const_iterator iter = llsd_cats.beginArray(); + LLSD::array_const_iterator end = llsd_cats.endArray(); + for (; iter != end; ++iter) { - if(inv_item->getUUID().isNull()) + LLPointer inv_cat = new LLViewerInventoryCategory(LLUUID::null); + if (inv_cat->importLLSDMap(*iter)) { - LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " - << inv_item->getName() << LL_ENDL; + categories.push_back(inv_cat); } - else + } + } + + const LLSD& llsd_items = inventory["items"]; + if (llsd_items.isArray()) + { + LLSD::array_const_iterator iter = llsd_items.beginArray(); + LLSD::array_const_iterator end = llsd_items.endArray(); + for (; iter != end; ++iter) + { + LLPointer inv_item = new LLViewerInventoryItem; + if (inv_item->fromLLSD(*iter)) { - if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + if (inv_item->getUUID().isNull()) { - cats_to_update.insert(inv_item->getParentUUID()); + LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " + << inv_item->getName() << LL_ENDL; } else { - items.push_back(inv_item); + if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + { + cats_to_update.insert(inv_item->getParentUUID()); + } + else + { + items.push_back(inv_item); + } } } + + // TODO(brad) - figure out how to reenable this without breaking everything else + // static constexpr U64 BATCH_SIZE = 512U; + // if ((++lines_count % BATCH_SIZE) == 0) + // { + // // SL-19968 - make sure message system code gets a chance to run every so often + // pump_idle_startup_network(); + // } } } - -// TODO(brad) - figure out how to reenable this without breaking everything else -// static constexpr U64 BATCH_SIZE = 512U; -// if ((++lines_count % BATCH_SIZE) == 0) -// { -// // SL-19968 - make sure message system code gets a chance to run every so often -// pump_idle_startup_network(); -// } } file.close(); @@ -3769,58 +3781,54 @@ bool LLInventoryModel::saveToFile(const std::string& filename, try { - llofstream fileXML(filename.c_str()); - if (!fileXML.is_open()) + llofstream fileSD(filename.c_str(), std::ios_base::out | std::ios_base::binary); + if (!fileSD.is_open()) { LL_WARNS(LOG_INV) << "Failed to open file. Unable to save inventory to: " << filename << LL_ENDL; return false; } - - LLSD cache_ver; - cache_ver["inv_cache_version"] = sCurrentInvCacheVersion; - - if (fileXML.fail()) + U32 value_nbo = htonl(sCurrentInvCacheVersion); + fileSD.write((const char*)(&value_nbo), sizeof(U32)); + if (fileSD.fail()) { - LL_WARNS(LOG_INV) << "Failed to write cache version to file. Unable to save inventory to: " << filename << LL_ENDL; + LL_WARNS(LOG_INV) << "Failed to write cache. Unable to save inventory to: " << filename << LL_ENDL; return false; } - fileXML << LLSDOStreamer(cache_ver) << std::endl; + LLSD inventory; + inventory["categories"] = LLSD::emptyArray(); + LLSD& cat_array = inventory["categories"]; S32 cat_count = 0; for (auto& cat : categories) { if (cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { - LLSD sd = LLSD::emptyMap(); + LLSD sd; cat->exportLLSD(sd); - fileXML << LLSDOStreamer(sd) << std::endl; + cat_array.append(sd); cat_count++; } - - if (fileXML.fail()) - { - LL_WARNS(LOG_INV) << "Failed to write a folder to file. Unable to save inventory to: " << filename << LL_ENDL; - return false; - } } + inventory["items"] = LLSD::emptyArray(); + LLSD& item_array = inventory["items"]; auto it_count = items.size(); for (auto& item : items) { - LLSD sd = LLSD::emptyMap(); + LLSD sd; item->asLLSD(sd); - fileXML << LLSDOStreamer(sd) << std::endl; - - if (fileXML.fail()) - { - LL_WARNS(LOG_INV) << "Failed to write an item to file. Unable to save inventory to: " << filename << LL_ENDL; - return false; - } + item_array.append(sd); } - fileXML.flush(); + fileSD << LLSDOStreamer(inventory) << std::endl; + if (fileSD.fail()) + { + LL_WARNS(LOG_INV) << "Failed to write cache. Unable to save inventory to: " << filename << LL_ENDL; + return false; + } + fileSD.flush(); - fileXML.close(); + fileSD.close(); LL_INFOS(LOG_INV) << "Inventory saved: " << (S32)cat_count << " categories, " << (S32)it_count << " items." << LL_ENDL; } diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 5a480c3c4b..7542011523 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -32,6 +32,8 @@ #include "lllogchat.h" #include "llregex.h" #include "lltrans.h" +#include "llurlaction.h" +#include "llurlentry.h" #include "llviewercontrol.h" #include "lldiriterator.h" @@ -445,13 +447,29 @@ void LLLogChat::saveHistory(const std::string& filename, return; } + std::string altered_line = line; + + // avoid costly regex calls + if (line.find("/mention") != std::string::npos) + { + static const boost::regex mention_regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/mention", boost::regex::perl | boost::regex::icase); + + // replace mention URL with [@username](URL) + altered_line = boost::regex_replace(line, mention_regex, [](const boost::smatch& match) -> std::string + { + std::string url = match[0].str(); + std::string username = LLUrlAction::getURLLabel(url); + return "[" + username + "](" + url + ")"; + }); + } + LLSD item; if (gSavedPerAccountSettings.getBOOL("LogTimestamp")) item["time"] = LLLogChat::timestamp2LogString(0, gSavedPerAccountSettings.getBOOL("LogTimestampDate")); item["from_id"] = from_id; - item["message"] = line; + item["message"] = altered_line; //adding "Second Life:" for all system messages to make chat log history parsing more reliable if (from.empty() && from_id.isNull()) @@ -563,6 +581,19 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list& m std::string line(remove_utf8_bom(buffer)); + + // fast heuristic test for a mention URL in a string + // this is used to avoid costly regex calls + if (line.find("/mention)") != std::string::npos) + { + // restore original mention URL from [@username](URL) format + static const boost::regex altered_mention_regex("\\[@([^\\]]+)\\]\\((" APP_HEADER_REGEX "/agent/[\\da-f-]+/mention)\\)", + boost::regex::perl | boost::regex::icase); + + // $2 captures the URL part + line = boost::regex_replace(line, altered_mention_regex, "$2"); + } + //updated 1.23 plain text log format requires a space added before subsequent lines in a multilined message if (' ' == line[0]) { diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 8302010ac9..4a39fb7b5f 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -2395,6 +2395,7 @@ void LLSelectMgr::selectionRevertGLTFMaterials() { // Restore base material LLUUID asset_id = nodep->mSavedGLTFMaterialIds[te]; + LLUUID old_asset_id = objectp->getRenderMaterialID(te); // Update material locally objectp->setRenderMaterialID(te, asset_id, false /*wait for LLGLTFMaterialList update*/); @@ -2405,18 +2406,29 @@ void LLSelectMgr::selectionRevertGLTFMaterials() objectp->setTEGLTFMaterialOverride(te, material); } - // Enqueue update to server - if (asset_id.notNull() && material) - { - // Restore overrides and base material - LLGLTFMaterialList::queueApply(objectp, te, asset_id, material); - } - else + if (asset_id.isNull() || !material) { //blank override out LLGLTFMaterialList::queueApply(objectp, te, asset_id); } - + if (old_asset_id != asset_id) + { + // Restore overrides and base material + // Note: might not work reliably if asset is already there, might + // have a server sided problem where servers applies override + // first then resets it by adding asset, in which case need + // to create a server ticket and chain asset then override + // application. + LLGLTFMaterialList::queueApply(objectp, te, asset_id, material); + } + else + { + // Enqueue override update to server + // Note: this is suboptimal, better to send asset id as well + // but there seems to be a server problem with queueApply + // that ignores override in some cases + LLGLTFMaterialList::queueModify(objectp, te, material); + } } return true; } diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index cf77133408..14316f7f7e 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1139,28 +1139,33 @@ void set_texture_to_material(LLViewerObject* hit_obj, case LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR: default: { - material->setBaseColorId(asset_id); + material->setBaseColorId(asset_id, true); } break; case LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS: { - material->setOcclusionRoughnessMetallicId(asset_id); + material->setOcclusionRoughnessMetallicId(asset_id, true); } break; case LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE: { - material->setEmissiveId(asset_id); + material->setEmissiveId(asset_id, true); } break; case LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL: { - material->setNormalId(asset_id); + material->setNormalId(asset_id, true); } break; } + // Update viewer side, needed for updating mSavedGLTFOverrideMaterials. + // Also for parity, we are immediately setting textures and materials, + // so we should immediate set overrides to. + hit_obj->setTEGLTFMaterialOverride(hit_face, material); + // update server LLGLTFMaterialList::queueModify(hit_obj, hit_face, material); } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index a7a860edce..06ad736893 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -851,18 +851,23 @@ void LLViewerInventoryCategory::exportLLSD(LLSD & cat_data) const cat_data[INV_VERSION] = mVersion; } -bool LLViewerInventoryCategory::importLLSD(const LLSD& cat_data) +bool LLViewerInventoryCategory::importLLSD(const std::string& label, const LLSD& value) { - LLInventoryCategory::importLLSD(cat_data); - if (cat_data.has(INV_OWNER_ID)) + if (LLInventoryCategory::importLLSD(label, value)) { - mOwnerID = cat_data[INV_OWNER_ID].asUUID(); + return true; } - if (cat_data.has(INV_VERSION)) + else if (label == INV_OWNER_ID) { - setVersion(cat_data[INV_VERSION].asInteger()); + mOwnerID = value.asUUID(); + return true; } - return true; + else if (label == INV_VERSION) + { + setVersion(value.asInteger()); + return true; + } + return false; } bool LLViewerInventoryCategory::acceptItem(LLInventoryItem* inv_item) diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 5cd31353f8..0dfbf0cced 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -233,7 +233,7 @@ public: S32 getViewerDescendentCount() const; virtual void exportLLSD(LLSD &sd) const; - virtual bool importLLSD(const LLSD& cat_data); + virtual bool importLLSD(const std::string& label, const LLSD& value); void determineFolderType(); void changeType(LLFolderType::EType new_folder_type); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 87689e9555..665fff3233 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -7339,6 +7339,7 @@ const LLUUID& LLVOAvatar::getID() const // getJoint() //----------------------------------------------------------------------------- // RN: avatar joints are multi-rooted to include screen-based attachments +// virtual LLJoint* LLVOAvatar::getJoint(std::string_view name) { LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;