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;