From e7e565dc6e7e0c666132ffffa4798b2cfc00d6a4 Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Fri, 21 Jul 2023 13:01:11 -0700
Subject: [PATCH] SL-20024: Put material in object inventory when material is
 no-modify or no-transfer

---
 indra/llprimitive/llmaterial.cpp    | 11 ---------
 indra/llprimitive/llmaterial.h      |  2 --
 indra/newview/llpanelface.cpp       |  7 +-----
 indra/newview/llpanelface.h         |  1 -
 indra/newview/llselectmgr.cpp       | 36 +++++++++++++++++++++--------
 indra/newview/llselectmgr.h         | 14 +++++++++--
 indra/newview/lltooldraganddrop.cpp | 20 ++++++++++++++++
 7 files changed, 59 insertions(+), 32 deletions(-)

diff --git a/indra/llprimitive/llmaterial.cpp b/indra/llprimitive/llmaterial.cpp
index f6cb3c8b707..0d146de949e 100644
--- a/indra/llprimitive/llmaterial.cpp
+++ b/indra/llprimitive/llmaterial.cpp
@@ -332,17 +332,6 @@ void LLMaterial::setAlphaMaskCutoff(U8 cutoff)
     mAlphaMaskCutoff = cutoff;
 }
 
-LLUUID LLMaterial::getMaterialID() const
-{
-    // TODO - not null
-    return LLUUID::null;
-}
-
-void LLMaterial::setMaterialID(const LLUUID &material_id)
-{
-    // TODO - set
-}
-
 LLSD LLMaterial::asLLSD() const
 {
     LLSD material_data;
diff --git a/indra/llprimitive/llmaterial.h b/indra/llprimitive/llmaterial.h
index b46d85c2d14..81f41ddc511 100644
--- a/indra/llprimitive/llmaterial.h
+++ b/indra/llprimitive/llmaterial.h
@@ -115,8 +115,6 @@ class LLMaterial : public LLRefCount
     void        setDiffuseAlphaMode(U8 alpha_mode);
     U8          getAlphaMaskCutoff() const;
     void        setAlphaMaskCutoff(U8 cutoff);
-    LLUUID      getMaterialID() const;
-    void        setMaterialID(LLUUID const & material_id);
 
     bool        isNull() const;
     static const LLMaterial null;
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 837217387f1..b633ccc5d5a 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -3093,12 +3093,7 @@ void LLPanelFace::onSelectPbr(const LLSD& data)
         {
             id = pbr_ctrl->getImageAssetID();
         }
-        if (LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id))
-        {
-            LLSelectedTEMaterial::setMaterialID(this, id);
-        }
-        else
-        {
+        if (!LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id))
             refresh();
         }
     }
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index f6a813f9e54..e2d9f65e58c 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -583,7 +583,6 @@ class LLPanelFace : public LLPanel
 		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID);
 		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID);
 		DEF_EDIT_MAT_STATE(LLColor4U,	const LLColor4U&,setSpecularLightColor);
-		DEF_EDIT_MAT_STATE(LLUUID, const LLUUID&, setMaterialID);
 	};
 
 	class LLSelectedTE
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 5c1a3395700..6692d124d8c 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -1773,15 +1773,17 @@ void LLObjectSelection::applyNoCopyTextureToTEs(LLViewerInventoryItem* item)
 	}
 }
 
-void LLObjectSelection::applyNoCopyPbrMaterialToTEs(LLViewerInventoryItem* item)
+bool LLObjectSelection::applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* item)
 {
     if (!item)
     {
-        return;
+        return false;
     }
 
     LLUUID asset_id = item->getAssetUUID();
 
+    bool material_copied_all_faces = true;
+
     for (iterator iter = begin(); iter != end(); ++iter)
     {
         LLSelectNode* node = *iter;
@@ -1797,12 +1799,17 @@ void LLObjectSelection::applyNoCopyPbrMaterialToTEs(LLViewerInventoryItem* item)
         {
             if (node->isTESelected(te))
             {
-                //(no-copy) materials must be moved to the object's inventory only once
+                //(no-copy), (no-modify), and (no-transfer) materials must be moved to the object's inventory only once
                 // without making any copies
                 if (!material_copied && asset_id.notNull())
                 {
-                    LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null);
-                    material_copied = true;
+                    material_copied = (bool)LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null);
+                }
+                if (!material_copied)
+                {
+                    // Applying the material is not possible for this object given the current inventory
+					material_copied_all_faces = false;
+                    break;
                 }
 
                 // apply texture for the selected faces
@@ -1814,6 +1821,8 @@ void LLObjectSelection::applyNoCopyPbrMaterialToTEs(LLViewerInventoryItem* item)
     }
 
     LLGLTFMaterialList::flushUpdates();
+
+    return material_copied_all_faces;
 }
 
 
@@ -1924,6 +1933,8 @@ bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
     {
         LLViewerInventoryItem* mItem;
         LLUUID mMatId;
+        bool material_copied_any_face = false;
+        bool material_copied_all_faces = true;
         f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mMatId(id) {}
         bool apply(LLViewerObject* objectp, S32 te)
         {
@@ -1950,14 +1961,19 @@ bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
         }
     };
 
-    if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()))
+    bool success = true;
+    if (item &&
+            (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) ||
+             !item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()) ||
+             !item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID())
+            ))
     {
-        getSelection()->applyNoCopyPbrMaterialToTEs(item);
+        success = success && getSelection()->applyRestrictedPbrMaterialToTEs(item);
     }
     else
     {
         f setfunc(item, mat_id);
-        getSelection()->applyToTEs(&setfunc);
+        success = success && getSelection()->applyToTEs(&setfunc);
     }
 
     struct g : public LLSelectedObjectFunctor
@@ -1986,11 +2002,11 @@ bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
             return true;
         }
     } sendfunc(item);
-    getSelection()->applyToObjects(&sendfunc);
+    success = success && getSelection()->applyToObjects(&sendfunc);
 
     LLGLTFMaterialList::flushUpdates();
 
-    return true;
+    return success;
 }
 
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 327134a4875..f89209b4375 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -378,7 +378,17 @@ class LLObjectSelection : public LLRefCount
 	 * Then this only texture is used for all selected faces.
 	 */
 	void applyNoCopyTextureToTEs(LLViewerInventoryItem* item);
-    void applyNoCopyPbrMaterialToTEs(LLViewerInventoryItem* item);
+    /*
+     * Multi-purpose function for applying PBR materials to the
+     * selected object or faces, any combination of copy/mod/transfer
+     * permission restrictions. This method moves the restricted
+     * material to the object's inventory and doesn't make a copy of the
+     * material for each face. Then this only material is used for
+     * all selected faces.
+     * Returns false if applying the material failed on one or more selected
+     * faces.
+     */
+    bool applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* item);
 
 	ESelectType getSelectType() const { return mSelectType; }
 
@@ -635,7 +645,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSimpleton<LLSelectMgr>
 	void selectionSetRestitution(F32 restitution);
 	void selectionSetMaterial(U8 material);
 	bool selectionSetImage(const LLUUID& imageid); // could be item or asset id
-    bool selectionSetGLTFMaterial(const LLUUID& mat_id); // could be item or asset id
+    bool selectionSetGLTFMaterial(const LLUUID& mat_id); // material id only
 	void selectionSetColor(const LLColor4 &color);
 	void selectionSetColorOnly(const LLColor4 &color); // Set only the RGB channels
 	void selectionSetAlphaOnly(const F32 alpha); // Set only the alpha channel
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index dd5f607b042..23a6634154a 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1042,6 +1042,26 @@ BOOL LLToolDragAndDrop::handleDropMaterialProtections(LLViewerObject* hit_obj,
 		// we should return false here. This will requre a separate listener
 		// since without listener, we have no way to receive update
 	}
+	else if (LLAssetType::AT_MATERIAL == new_item->getType() &&
+             !item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()))
+	{
+		// Check that we can add the material as inventory to the object
+		if (willObjectAcceptInventory(hit_obj,item) < ACCEPT_YES_COPY_SINGLE )
+		{
+			return FALSE;
+		}
+		// *FIX: may want to make sure agent can paint hit_obj.
+
+		// Add the material item to the target object's inventory.
+        hit_obj->updateMaterialInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
+
+		// Force the object to update and refetch its inventory so it has this material.
+		hit_obj->dirtyInventory();
+		hit_obj->requestInventory();
+		// TODO: Check to see if adding the item was successful; if not, then
+		// we should return false here. This will requre a separate listener
+		// since without listener, we have no way to receive update
+	}
 	return TRUE;
 }
 
-- 
GitLab