From 711354c2f526421b7cd2918f584731624a9995e5 Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Thu, 2 Nov 2023 09:55:44 -0700
Subject: SL-20553: Save material button in build floater now depends on agent
 inventory rather than object inventory

---
 indra/newview/llmaterialeditor.cpp | 92 +++++++++++++++++++++++++++++++++-----
 indra/newview/llpanelface.cpp      | 65 ++++++++++++++++++++++++---
 indra/newview/llpanelface.h        |  6 ++-
 3 files changed, 142 insertions(+), 21 deletions(-)

diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index 5be1aa08ab..bae4afb7e6 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -38,6 +38,7 @@
 #include "llgltfmateriallist.h"
 #include "llinventorymodel.h"
 #include "llinventoryobserver.h"
+#include "llinventoryfunctions.h"
 #include "lllocalgltfmaterials.h"
 #include "llnotificationsutil.h"
 #include "lltexturectrl.h"
@@ -1796,8 +1797,49 @@ void LLMaterialEditor::loadLive()
     }
 }
 
+namespace
+{
+    // Which inventory to consult for item permissions
+    enum class ItemSource
+    {
+        // Consult the permissions of the item in the object's inventory. If
+        // the item is not present, then usage of the asset is allowed.
+        OBJECT,
+        // Consult the permissions of the item in the agent's inventory. If
+        // the item is not present, then usage of the asset is not allowed.
+        AGENT
+    };
+
+    class LLAssetIDMatchesWithPerms : public LLInventoryCollectFunctor
+    {
+    public:
+        LLAssetIDMatchesWithPerms(const LLUUID& asset_id, const std::vector<PermissionBit>& ops) : mAssetID(asset_id), mOps(ops) {}
+        virtual ~LLAssetIDMatchesWithPerms() {}
+        bool operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+        {
+            if (!item || item->getAssetUUID() != mAssetID)
+            {
+                return false;
+            }
+            LLPermissions item_permissions = item->getPermissions();
+            for (PermissionBit op : mOps)
+            {
+                if (!gAgent.allowOperation(op, item_permissions, GP_OBJECT_MANIPULATE))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+    protected:
+        LLUUID mAssetID;
+        std::vector<PermissionBit> mOps;
+    };
+};
+
 // *NOTE: permissions_out includes user preferences for new item creation (LLFloaterPerms)
-bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<PermissionBit>& ops, LLPermissions& permissions_out, LLViewerInventoryItem*& item_out)
+bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<PermissionBit>& ops, const ItemSource item_source, LLPermissions& permissions_out, LLViewerInventoryItem*& item_out)
 {
     if (!LLMaterialEditor::capabilitiesAvailable())
     {
@@ -1830,19 +1872,45 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<Pe
         }
     }
 
-    item_out = selected_object->getInventoryItemByAsset(func.mMaterialId);
-
-    LLPermissions item_permissions;
-    if (item_out)
+    // Look for the item to base permissions off of
+    item_out = nullptr;
+    if (func.mMaterialId != LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID)
     {
-        item_permissions.set(item_out->getPermissions());
-        for (PermissionBit op : ops)
+        LLAssetIDMatchesWithPerms item_has_perms(func.mMaterialId, ops);
+        if (item_source == ItemSource::OBJECT)
         {
-            if (!gAgent.allowOperation(op, item_permissions, GP_OBJECT_MANIPULATE))
+            item_out = selected_object->getInventoryItemByAsset(func.mMaterialId);
+            if (item_out && !item_has_perms(nullptr, item_out))
             {
                 return false;
             }
         }
+        else
+        {
+            llassert(item_source == ItemSource::AGENT);
+
+            LLViewerInventoryCategory::cat_array_t cats;
+            LLViewerInventoryItem::item_array_t items;
+            gInventory.collectDescendentsIf(LLUUID::null,
+                                    cats,
+                                    items,
+                                    // *NOTE: PBRPickerAgentListener will need
+                                    // to be changed if checking the trash is
+                                    // disabled
+                                    LLInventoryModel::INCLUDE_TRASH,
+                                    item_has_perms);
+            if (items.empty())
+            {
+                return false;
+            }
+            item_out = items[0];
+        }
+    }
+
+    LLPermissions item_permissions;
+    if (item_out)
+    {
+        item_permissions = item_out->getPermissions();
         // Update flags for new owner
         if (!item_permissions.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true))
         {
@@ -1913,7 +1981,7 @@ bool LLMaterialEditor::canModifyObjectsMaterial()
     LLSelectedTEGetMatData func(true);
     LLPermissions permissions;
     LLViewerInventoryItem* item_out;
-    return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions, item_out);
+    return can_use_objects_material(func, std::vector({PERM_MODIFY}), ItemSource::OBJECT, permissions, item_out);
 }
 
 bool LLMaterialEditor::canSaveObjectsMaterial()
@@ -1921,7 +1989,7 @@ bool LLMaterialEditor::canSaveObjectsMaterial()
     LLSelectedTEGetMatData func(true);
     LLPermissions permissions;
     LLViewerInventoryItem* item_out;
-    return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item_out);
+    return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item_out);
 }
 
 bool LLMaterialEditor::canClipboardObjectsMaterial()
@@ -1947,7 +2015,7 @@ bool LLMaterialEditor::canClipboardObjectsMaterial()
     LLSelectedTEGetMatData func(true);
     LLPermissions permissions;
     LLViewerInventoryItem* item_out;
-    return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), permissions, item_out);
+    return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), ItemSource::OBJECT, permissions, item_out);
 }
 
 void LLMaterialEditor::saveObjectsMaterialAs()
@@ -1955,7 +2023,7 @@ void LLMaterialEditor::saveObjectsMaterialAs()
     LLSelectedTEGetMatData func(true);
     LLPermissions permissions;
     LLViewerInventoryItem* item = nullptr;
-    bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item);
+    bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item);
     if (!allowed)
     {
         LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL;
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 9150b89de3..02c00e7f87 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -1880,15 +1880,55 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
 	}
 }
 
+// One-off listener that updates the build floater UI when the agent inventory adds or removes an item
+class PBRPickerAgentListener : public LLInventoryObserver
+{
+protected:
+    bool mChangePending = true;
+public:
+	PBRPickerAgentListener() : LLInventoryObserver()
+    {
+        gInventory.addObserver(this);
+    }
+
+    const bool isListening()
+    {
+        return mChangePending;
+    }
+
+	void changed(U32 mask) override
+    {
+        if (!(mask & (ADD | REMOVE)))
+        {
+            return;
+        }
+
+        if (gFloaterTools)
+        {
+            gFloaterTools->dirty();
+        }
+        gInventory.removeObserver(this);
+        mChangePending = false;
+    }
+
+    ~PBRPickerAgentListener() override
+    {
+        gInventory.removeObserver(this);
+        mChangePending = false;
+
+        LLInventoryObserver::~LLInventoryObserver();
+    }
+};
+
 // One-off listener that updates the build floater UI when the prim inventory updates
-class PBRPickerItemListener : public LLVOInventoryListener
+class PBRPickerObjectListener : public LLVOInventoryListener
 {
 protected:
     LLViewerObject* mObjectp;
     bool mChangePending = true;
 public:
 
-    PBRPickerItemListener(LLViewerObject* object)
+    PBRPickerObjectListener(LLViewerObject* object)
     : mObjectp(object)
     {
         registerVOInventoryListener(mObjectp, nullptr);
@@ -1912,7 +1952,7 @@ public:
         mChangePending = false;
     }
 
-    ~PBRPickerItemListener()
+    ~PBRPickerObjectListener()
     {
         removeVOInventoryListener();
         mChangePending = false;
@@ -1931,9 +1971,9 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material,
 
     // pbr material
     LLTextureCtrl* pbr_ctrl = findChild<LLTextureCtrl>("pbr_control");
+    LLUUID pbr_id;
     if (pbr_ctrl)
     {
-        LLUUID pbr_id;
         LLSelectedTE::getPbrMaterialId(pbr_id, identical_pbr, has_pbr_material, has_faces_without_pbr);
 
         pbr_ctrl->setTentative(identical_pbr ? FALSE : TRUE);
@@ -1956,14 +1996,25 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material,
     if (objectp->isInventoryPending())
     {
         // Reuse the same listener when possible
-        if (!mInventoryListener || !mInventoryListener->isListeningFor(objectp))
+        if (!mVOInventoryListener || !mVOInventoryListener->isListeningFor(objectp))
         {
-            mInventoryListener = std::make_unique<PBRPickerItemListener>(objectp);
+            mVOInventoryListener = std::make_unique<PBRPickerObjectListener>(objectp);
         }
     }
     else
     {
-        mInventoryListener = nullptr;
+        mVOInventoryListener = nullptr;
+    }
+    if (!identical_pbr || pbr_id.isNull() || pbr_id == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID)
+    {
+        mAgentInventoryListener = nullptr;
+    }
+    else
+    {
+        if (!mAgentInventoryListener || !mAgentInventoryListener->isListening())
+        {
+            mAgentInventoryListener = std::make_unique<PBRPickerAgentListener>();
+        }
     }
 
     const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled();
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index d36662c11b..5ca6a95699 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -53,7 +53,8 @@ class LLMaterialID;
 class LLMediaCtrl;
 class LLMenuButton;
 
-class PBRPickerItemListener;
+class PBRPickerAgentListener;
+class PBRPickerObjectListener;
 
 // Represents an edit for use in replicating the op across one or more materials in the selection set.
 //
@@ -508,7 +509,8 @@ private:
 
     static Selection sMaterialOverrideSelection;
 
-    std::unique_ptr<PBRPickerItemListener> mInventoryListener;
+    std::unique_ptr<PBRPickerAgentListener> mAgentInventoryListener;
+    std::unique_ptr<PBRPickerObjectListener> mVOInventoryListener;
 
 public:
 	#if defined(DEF_GET_MAT_STATE)
-- 
cgit v1.2.3


From 2d69611c470e8ca0f85f6ad5857799ca2536f193 Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Fri, 3 Nov 2023 09:57:19 -0700
Subject: SL-20553: Fix save material to inventory not working with new
 agent-based permissions

---
 indra/newview/llmaterialeditor.cpp | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index bae4afb7e6..cc7e69d60c 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -1852,6 +1852,10 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<Pe
     llassert(func.mIsOverride);
     LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, true /*first applicable*/);
 
+    if (item_source == ItemSource::AGENT)
+    {
+        func.mObjectId = LLUUID::null;
+    }
     LLViewerObject* selected_object = func.mObject;
     if (!selected_object)
     {
@@ -1879,11 +1883,12 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<Pe
         LLAssetIDMatchesWithPerms item_has_perms(func.mMaterialId, ops);
         if (item_source == ItemSource::OBJECT)
         {
-            item_out = selected_object->getInventoryItemByAsset(func.mMaterialId);
-            if (item_out && !item_has_perms(nullptr, item_out))
+            LLViewerInventoryItem* item = selected_object->getInventoryItemByAsset(func.mMaterialId);
+            if (item && !item_has_perms(nullptr, item))
             {
                 return false;
             }
+            item_out = item;
         }
         else
         {
@@ -2118,8 +2123,9 @@ void LLMaterialEditor::saveObjectsMaterialAs(const LLGLTFMaterial* render_materi
     }
     else
     {
-        if (item_id.notNull())
+        if (item_id.notNull() && object_id.notNull())
         {
+            llassert(false); // *TODO: Remove this code path if unused
             // Copy existing item from object inventory, and create new composite asset on top of it
             LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onCopyObjectsMaterialAsMsgCallback, _1, _2, permissions, object_id, item_id));
         }
-- 
cgit v1.2.3


From ee8b96f3ef55d10f5b84e368c052692a362ebcbc Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Fri, 3 Nov 2023 13:49:47 -0700
Subject: SL-20553: Clean up dead code

---
 indra/newview/llmaterialeditor.cpp  | 58 ++---------------------------------
 indra/newview/llmaterialeditor.h    |  1 -
 indra/newview/llviewerinventory.cpp | 61 -------------------------------------
 indra/newview/llviewerinventory.h   |  5 ---
 4 files changed, 2 insertions(+), 123 deletions(-)

diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index cc7e69d60c..958925c9e4 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -2123,63 +2123,9 @@ void LLMaterialEditor::saveObjectsMaterialAs(const LLGLTFMaterial* render_materi
     }
     else
     {
-        if (item_id.notNull() && object_id.notNull())
-        {
-            llassert(false); // *TODO: Remove this code path if unused
-            // Copy existing item from object inventory, and create new composite asset on top of it
-            LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onCopyObjectsMaterialAsMsgCallback, _1, _2, permissions, object_id, item_id));
-        }
-        else
-        {
-            LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback, _1, _2, permissions));
-        }
-    }
-}
-
-// static
-void LLMaterialEditor::onCopyObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions, const LLUUID& object_id, const LLUUID& item_id)
-{
-    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-    if (0 != option)
-    {
-        return;
+        llassert(object_id.isNull()); // Case for copying item from object inventory is no longer implemented
+        LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback, _1, _2, permissions));
     }
-
-    LLSD asset;
-    asset["version"] = LLGLTFMaterial::ASSET_VERSION;
-    asset["type"] = LLGLTFMaterial::ASSET_TYPE;
-    // This is the string serialized from LLGLTFMaterial::asJSON
-    asset["data"] = notification["payload"]["data"];
-
-    std::ostringstream str;
-    LLSDSerialize::serialize(asset, str, LLSDSerialize::LLSD_BINARY);
-
-    LLViewerObject* object = gObjectList.findObject(object_id);
-    if (!object)
-    {
-        return;
-    }
-    const LLInventoryItem* item = object->getInventoryItem(item_id);
-    if (!item)
-    {
-        return;
-    }
-
-    std::string new_name = response["message"].asString();
-    LLInventoryObject::correctInventoryName(new_name);
-    if (new_name.empty())
-    {
-        return;
-    }
-
-    const LLUUID destination_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL);
-
-    LLPointer<LLInventoryCallback> cb = new LLObjectsMaterialItemCallback(permissions, str.str(), new_name);
-    // NOTE: This should be an item copy. Saving a material to an inventory should be disabled when the associated material is no-copy.
-    move_or_copy_inventory_from_object(destination_id,
-                                       object_id,
-                                       item_id,
-                                       cb);
 }
 
 // static
diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h
index 1c40fcc348..2e25a9ca3d 100644
--- a/indra/newview/llmaterialeditor.h
+++ b/indra/newview/llmaterialeditor.h
@@ -116,7 +116,6 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
     static bool canSaveObjectsMaterial();
     static bool canClipboardObjectsMaterial();
     static void saveObjectsMaterialAs();
-    static void onCopyObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions, const LLUUID& object_id, const LLUUID& item_id);
     static void onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions);
 
     static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status);
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 5ee613d49d..1b70e5f84f 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -1658,67 +1658,6 @@ void copy_inventory_from_notecard(const LLUUID& destination_id,
     }
 }
 
-void move_or_copy_inventory_from_object(const LLUUID& destination_id,
-                                        const LLUUID& object_id,
-                                        const LLUUID& item_id,
-                                        LLPointer<LLInventoryCallback> cb)
-{
-    LLViewerObject* object = gObjectList.findObject(object_id);
-    if (!object)
-    {
-        return;
-    }
-    const LLInventoryItem* item = object->getInventoryItem(item_id);
-    if (!item)
-    {
-        return;
-    }
-
-    class LLItemAddedObserver : public LLInventoryObserver
-    {
-    public:
-        LLItemAddedObserver(const LLUUID& copied_asset_id, LLPointer<LLInventoryCallback> cb)
-        : LLInventoryObserver(),
-          mAssetId(copied_asset_id),
-          mCallback(cb)
-        {
-        }
-
-        void changed(U32 mask) override
-        {
-            if((mask & (LLInventoryObserver::ADD)) == 0)
-            {
-                return;
-            }
-            for (const LLUUID& changed_id : gInventory.getChangedIDs())
-            {
-                LLViewerInventoryItem* changed_item = gInventory.getItem(changed_id);
-                if (changed_item->getAssetUUID() == mAssetId)
-                {
-                    changeComplete(changed_item->getUUID());
-                    return;
-                }
-            }
-        }
-
-    private:
-        void changeComplete(const LLUUID& item_id)
-        {
-			mCallback->fire(item_id);
-            gInventory.removeObserver(this);
-            delete this;
-        }
-
-        LLUUID mAssetId;
-        LLPointer<LLInventoryCallback> mCallback;
-    };
-
-	const LLUUID& asset_id = item->getAssetUUID();
-    LLItemAddedObserver* observer = new LLItemAddedObserver(asset_id, cb);
-    gInventory.addObserver(observer);
-    object->moveInventory(destination_id, item_id);
-}
-
 void create_new_item(const std::string& name,
 				   const LLUUID& parent_id,
 				   LLAssetType::EType asset_type,
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index bce8da0a69..e043285ffb 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -463,11 +463,6 @@ void copy_inventory_from_notecard(const LLUUID& destination_id,
 								  const LLInventoryItem *src,
 								  U32 callback_id = 0);
 
-void move_or_copy_inventory_from_object(const LLUUID& destination_id,
-                                        const LLUUID& object_id,
-                                        const LLUUID& item_id,
-                                        LLPointer<LLInventoryCallback> cb);
-
 void menu_create_inventory_item(LLInventoryPanel* root,
 								LLFolderBridge* bridge,
 								const LLSD& userdata,
-- 
cgit v1.2.3


From 6ba5954d66523cedf5e69928e223f9820bd141ac Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Fri, 3 Nov 2023 13:54:05 -0700
Subject: SL-20553: Permissions touch-up

---
 indra/newview/llmaterialeditor.cpp | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index 958925c9e4..2f31889f32 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -1968,13 +1968,24 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<Pe
     // creation history when there's no material item present. In that case,
     // the agent who saved the material will be considered the creator.
     // -Cosmic,2023-08-07
-    if (item_out)
+    if (item_source == ItemSource::AGENT)
     {
+        llassert(item_out);
+
         permissions_out.set(item_permissions);
     }
     else
     {
-        permissions_out.set(object_permissions);
+        llassert(item_source == ItemSource::OBJECT);
+
+        if (item_out)
+        {
+            permissions_out.set(item_permissions);
+        }
+        else
+        {
+            permissions_out.set(object_permissions);
+        }
     }
     permissions_out.accumulate(floater_perm);
 
-- 
cgit v1.2.3


From 0d50f29697f999c91a4bed702b9bae281b247250 Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Tue, 7 Nov 2023 17:33:00 -0800
Subject: SL-20553: Fix inventory item not updating with correct permission
 label in UI

---
 indra/newview/llinventorymodel.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 74a5442586..ca13b9eb03 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -1465,6 +1465,10 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask)
 		{
 			mask |= LLInventoryObserver::LABEL;
 		}
+        if (old_item->getPermissions() != item->getPermissions())
+        {
+            mask |= LLInventoryObserver::INTERNAL;
+        }
 		old_item->copyViewerItem(item);
 		if (update_parent_on_server)
 		{
-- 
cgit v1.2.3


From 4ad7e250f3302a6158378a5acbf88ac27dd95ced Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Wed, 8 Nov 2023 14:51:48 -0800
Subject: SL-20553: Fix assert

---
 indra/newview/llmaterialeditor.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index 2f31889f32..2f4c29446e 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -1878,7 +1878,8 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<Pe
 
     // Look for the item to base permissions off of
     item_out = nullptr;
-    if (func.mMaterialId != LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID)
+    const bool blank_material = func.mMaterialId == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID;
+    if (!blank_material)
     {
         LLAssetIDMatchesWithPerms item_has_perms(func.mMaterialId, ops);
         if (item_source == ItemSource::OBJECT)
@@ -1970,7 +1971,7 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<Pe
     // -Cosmic,2023-08-07
     if (item_source == ItemSource::AGENT)
     {
-        llassert(item_out);
+        llassert(blank_material || item_out); // See comment at ItemSource::AGENT definition
 
         permissions_out.set(item_permissions);
     }
-- 
cgit v1.2.3


From a66a990165a2ade9cba26963fe0c7b4a21b9dcac Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Wed, 8 Nov 2023 16:23:36 -0800
Subject: SL-20553: Fix new material item still sometimes not updating in UI

---
 indra/newview/llmaterialeditor.cpp | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index 2f4c29446e..8f016b9125 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -1313,16 +1313,22 @@ public:
             return;
         }
 
+        // Name may or may not have already been applied
+        const bool changed_name = item->getName() != mNewName;
         // create_inventory_item/copy_inventory_item don't allow presetting some permissions, fix it now
-        item->setPermissions(mPermissions);
-        item->updateServer(FALSE);
-        gInventory.updateItem(item);
-        gInventory.notifyObservers();
-
-        if (item->getName() != mNewName)
+        const bool changed_permissions = item->getPermissions() != mPermissions;
+        const bool changed = changed_name || changed_permissions;
+        LLSD updates;
+        if (changed)
         {
-            LLSD updates;
-            updates["name"] = mNewName;
+            if (changed_name)
+            {
+                updates["name"] = mNewName;
+            }
+            if (changed_permissions)
+            {
+                updates["permissions"] = ll_create_sd_from_permissions(mPermissions);
+            }
             update_inventory_item(inv_item_id, updates, NULL);
         }
 
@@ -1332,10 +1338,16 @@ public:
                 inv_item_id,
                 LLAssetType::AT_MATERIAL,
                 mAssetData,
-                [](LLUUID item_id, LLUUID new_asset_id, LLUUID new_item_id, LLSD response)
+                [changed, updates](LLUUID item_id, LLUUID new_asset_id, LLUUID new_item_id, LLSD response)
                 {
                     // done callback
                     LL_INFOS("Material") << "inventory item uploaded.  item: " << item_id << " new_item_id: " << new_item_id << " response: " << response << LL_ENDL;
+
+                    // *HACK: Sometimes permissions do not stick in the UI. They are correct on the server-side, though.
+                    if (changed)
+                    {
+                        update_inventory_item(new_item_id, updates, NULL);
+                    }
                 },
                 nullptr // failure callback, floater already closed
             );
-- 
cgit v1.2.3