From a5d318567cc5c3e8f2f86fce1132f5883014e14e Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 28 Jul 2023 17:29:09 -0700 Subject: SL-20024: (WIP) (untested) Fix GLTF material permissions in some more edge cases --- indra/newview/llmaterialeditor.cpp | 139 ++++++++++++++++++++----------------- indra/newview/llmaterialeditor.h | 1 + indra/newview/llpanelface.cpp | 57 +++++++++++++-- indra/newview/llpanelface.h | 6 ++ 4 files changed, 134 insertions(+), 69 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 6e043ecee5..af40c9e931 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -293,8 +293,8 @@ bool LLSelectedTEGetMatData::apply(LLViewerObject* objectp, S32 te_index) mTexEmissiveId = tex_emissive_id; mTexNormalId = tex_normal_id; mObjectTE = te_index; - mObjectId = objectp->getID(); mObject = objectp; + mObjectId = objectp->getID(); mFirst = false; } else @@ -322,6 +322,7 @@ bool LLSelectedTEGetMatData::apply(LLViewerObject* objectp, S32 te_index) LLGLTFMaterial *mat = tep->getGLTFMaterial(); LLLocalGLTFMaterial *local_mat = dynamic_cast(mat); + mObject = objectp; if (local_mat) { mLocalMaterial = local_mat; @@ -1297,38 +1298,39 @@ void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std: // gen a new uuid for this asset LLTransactionID tid; tid.generate(); // timestamp-based randomization + uniquification - U32 next_owner_perm = LLFloaterPerms::getNextOwnerPerms("Materials"); + LLPermissions final_perm; + { + final_perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); + + LLPermissions floater_perm; + floater_perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); + floater_perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Materials")); + floater_perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Materials")); + floater_perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Materials")); + + final_perm.accumulate(floater_perm); + final_perm.accumulate(owner_permissions); + } + // NOTE: create_inventory_item doesn't allow presetting some permissions. + // The rest will be fixed after the callback. LLUUID parent = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL); const U8 subtype = NO_INV_SUBTYPE; // TODO maybe use AT_SETTINGS and LLSettingsType::ST_MATERIAL ? create_inventory_item(gAgent.getID(), gAgent.getSessionID(), parent, tid, name, desc, - LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, next_owner_perm, - new LLBoostFuncInventoryCallback([output = buffer, owner_permissions](LLUUID const& inv_item_id) + LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, final_perm.getMaskNextOwner(), + new LLBoostFuncInventoryCallback([output = buffer, final_perm](LLUUID const& inv_item_id) { LLViewerInventoryItem* item = gInventory.getItem(inv_item_id); if (item) { // create_inventory_item doesn't allow presetting some permissions, fix it now LLPermissions perm = item->getPermissions(); - if (perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms("Materials") - || perm.getMaskGroup() != LLFloaterPerms::getGroupPerms("Materials")) - { - LLPermissions floater_perm; - floater_perm.set(perm); - floater_perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Materials")); - floater_perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Materials")); - perm.accumulate(floater_perm); - perm.accumulate(owner_permissions); - // TODO: Decide if these are needed - perm.setCreator(owner_permissions.getCreator()); - perm.setLastOwner(owner_permissions.getLastOwner()); + perm.accumulate(final_perm); + item->setPermissions(perm); - item->setPermissions(perm); - - item->updateServer(FALSE); - gInventory.updateItem(item); - gInventory.notifyObservers(); - } + item->updateServer(FALSE); + gInventory.updateItem(item); + gInventory.notifyObservers(); } // from reference in LLSettingsVOBase::createInventoryItem()/updateInventoryItem() @@ -1805,29 +1807,47 @@ void LLMaterialEditor::loadLive() } } -// *NOTE: permissions_out ignores user preferences for new item creation -// (LLFloaterPerms). Those are applied later on in +// *NOTE: permissions_out ignores user preferences for new item creation. See +// LLFloaterPerms. Preferences are applied later on in // LLMaterialEditor::createInventoryItem. -bool can_save_objects_material(LLSelectedTEGetMatData& func, LLPermissions& permissions_out) +bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector& ops, LLPermissions& permissions_out) { + if (!LLMaterialEditor::capabilitiesAvailable()) + { + return false; + } + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, true /*first applicable*/); LLViewerObject* selected_object = func.mObject; - llassert(selected_object); // Note the function name + if (!selected_object) + { + // LLSelectedTEGetMatData can fail if there are no selected faces + // with materials, but we expect at least some object is selected. + llassert(LLSelectMgr::getInstance()->getSelection()->getFirstObject()); + return false; + } + for (PermissionBit op : ops) + { + if (op == PERM_MODIFY && selected_object->isPermanentEnforced()) + { + return false; + } + } + const LLViewerInventoryItem* item = selected_object->getInventoryItemByAsset(func.mMaterialId); LLPermissions item_permissions; - const bool previous_item_owned = item && item->getPermissions().getLastOwner().notNull(); if (item) { item_permissions.set(item->getPermissions()); - if (!gAgent.allowOperation(PERM_MODIFY, item_permissions, GP_OBJECT_MANIPULATE)) - { - return false; - } - if (!gAgent.allowOperation(PERM_COPY, item_permissions, GP_OBJECT_MANIPULATE)) + for (PermissionBit op : ops) { - return false; + if (!gAgent.allowOperation(op, item_permissions, GP_OBJECT_MANIPULATE)) + { + return false; + } } + // Update flags for new owner if (!item_permissions.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true)) { llassert(false); @@ -1839,20 +1859,21 @@ bool can_save_objects_material(LLSelectedTEGetMatData& func, LLPermissions& perm item_permissions.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); } - LLPermissions* object_permissions_p = LLSelectMgr::getInstance()->findObjectPermissions(selected_object); + // Use root object for permissions checking + LLViewerObject* root_object = selected_object->getRootEdit(); + LLPermissions* object_permissions_p = LLSelectMgr::getInstance()->findObjectPermissions(root_object); LLPermissions object_permissions; - const bool previous_object_owned = object_permissions_p && object_permissions_p->getLastOwner().notNull(); if (object_permissions_p) { object_permissions.set(*object_permissions_p); - if (!gAgent.allowOperation(PERM_MODIFY, object_permissions, GP_OBJECT_MANIPULATE)) + for (PermissionBit op : ops) { - return false; - } - if (!gAgent.allowOperation(PERM_COPY, object_permissions, GP_OBJECT_MANIPULATE)) - { - return false; + if (!gAgent.allowOperation(op, object_permissions, GP_OBJECT_MANIPULATE)) + { + return false; + } } + // Update flags for new owner if (!object_permissions.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true)) { llassert(false); @@ -1865,43 +1886,34 @@ bool can_save_objects_material(LLSelectedTEGetMatData& func, LLPermissions& perm } permissions_out.set(item_permissions); + // *NOTE: A close inspection of LLPermissions::accumulate shows that + // conflicting UUIDs will be unset. This is acceptable behavior for now. + // The server doesn't allow us to create an item while claiming someone + // else was the creator/previous owner. permissions_out.accumulate(object_permissions); - if (previous_item_owned != previous_object_owned) - { - // Likely ownership history conflict. Prefer the item history. Fall - // back to object history if no associated item. - if (previous_item_owned) - { - permissions_out.setCreator(item_permissions.getCreator()); - permissions_out.setLastOwner(item_permissions.getLastOwner()); - } - else if (previous_object_owned) - { - permissions_out.setCreator(object_permissions.getCreator()); - permissions_out.setLastOwner(object_permissions.getLastOwner()); - } - } - - llassert(permissions_out.getOwner() == gAgent.getID()); - llassert(permissions_out.getCreator().notNull()); - llassert(permissions_out.getGroup().isNull()); - return true; } +bool LLMaterialEditor::canModifyObjectsMaterial() +{ + LLSelectedTEGetMatData func(false); + LLPermissions permissions; + return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions); +} + bool LLMaterialEditor::canSaveObjectsMaterial() { LLSelectedTEGetMatData func(false); LLPermissions permissions; - return can_save_objects_material(func, permissions); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions); } void LLMaterialEditor::saveObjectsMaterialAs() { LLSelectedTEGetMatData func(false); LLPermissions permissions; - bool allowed = can_save_objects_material(func, permissions); + bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions); if (!allowed) { LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL; @@ -1986,7 +1998,6 @@ void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, con LLSD args; args["DESC"] = LLTrans::getString("New Material"); - // At this point, last owner, etc should be set. LLFloaterPerms will be honored later on if (local_material) { LLPermissions local_permissions; diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h index 5ee42f65f4..54e59fcdf8 100644 --- a/indra/newview/llmaterialeditor.h +++ b/indra/newview/llmaterialeditor.h @@ -112,6 +112,7 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener static void updateLive(const LLUUID &object_id, S32 te); static void loadLive(); + static bool canModifyObjectsMaterial(); static bool canSaveObjectsMaterial(); static void saveObjectsMaterialAs(); static void onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index b9daf19284..90271b75b2 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -51,6 +51,7 @@ #include "llinventorymodelbackgroundfetch.h" #include "llfloatermediasettings.h" #include "llfloaterreg.h" +#include "llfloatertools.h" #include "lllineeditor.h" #include "llmaterialmgr.h" #include "llmaterialeditor.h" @@ -77,6 +78,7 @@ #include "llviewerregion.h" #include "llviewerstats.h" #include "llvovolume.h" +#include "llvoinventorylistener.h" #include "lluictrlfactory.h" #include "llpluginclassmedia.h" #include "llviewertexturelist.h"// Update sel manager as to which channel we're editing so it can reflect the correct overlay UI @@ -1834,13 +1836,48 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) } } +// One-off listener that updates the build floater UI when the prim inventory updates +class PBRPickerItemListener : public LLVOInventoryListener +{ +protected: + LLViewerObject* mObjectp; +public: + + PBRPickerItemListener(LLViewerObject* object) + : mObjectp(object) + { + registerVOInventoryListener(mObjectp, nullptr); + } + + const LLViewerObject* const getObject() { return mObjectp; } + + void inventoryChanged(LLViewerObject* object, + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void* user_data) override + { + if (gFloaterTools) + { + gFloaterTools->dirty(); + } + removeVOInventoryListener(); + } + + ~PBRPickerItemListener() + { + removeVOInventoryListener(); + } +}; + void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool& has_faces_without_pbr, bool force_set_values) { has_pbr_material = false; - const bool editable = objectp->permModify() && !objectp->isPermanentEnforced(); bool has_pbr_capabilities = LLMaterialEditor::capabilitiesAvailable(); bool identical_pbr = true; + const bool settable = has_pbr_capabilities && objectp->permModify() && !objectp->isPermanentEnforced(); + const bool editable = LLMaterialEditor::canModifyObjectsMaterial(); + const bool saveable = LLMaterialEditor::canSaveObjectsMaterial(); // pbr material LLTextureCtrl* pbr_ctrl = findChild("pbr_control"); @@ -1850,13 +1887,23 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, LLSelectedTE::getPbrMaterialId(pbr_id, identical_pbr, has_pbr_material, has_faces_without_pbr); pbr_ctrl->setTentative(identical_pbr ? FALSE : TRUE); - pbr_ctrl->setEnabled(editable && has_pbr_capabilities); + pbr_ctrl->setEnabled(settable); pbr_ctrl->setImageAssetID(pbr_id); } - getChildView("pbr_from_inventory")->setEnabled(editable && has_pbr_capabilities); - getChildView("edit_selected_pbr")->setEnabled(editable && has_pbr_material && !has_faces_without_pbr && has_pbr_capabilities); - getChildView("save_selected_pbr")->setEnabled(LLMaterialEditor::canSaveObjectsMaterial() && identical_pbr); + const bool inventory_pending = objectp->isInventoryPending(); + getChildView("pbr_from_inventory")->setEnabled(settable); + getChildView("edit_selected_pbr")->setEnabled(editable && !inventory_pending && !has_faces_without_pbr); + getChildView("save_selected_pbr")->setEnabled(saveable && !inventory_pending && identical_pbr); + // TODO: Vet inventory updates and memory management + if (inventory_pending && (!mInventoryListener || mInventoryListener->getObject() != objectp)) + { + mInventoryListener = std::make_unique(objectp); + } + else + { + mInventoryListener = nullptr; + } const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled(); if (show_pbr) diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index e2d9f65e58..d737665ad0 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -35,6 +35,8 @@ #include "lltextureentry.h" #include "llselectmgr.h" +#include + class LLButton; class LLCheckBoxCtrl; class LLColorSwatchCtrl; @@ -51,6 +53,8 @@ class LLMaterialID; class LLMediaCtrl; class LLMenuButton; +class PBRPickerItemListener; + // Represents an edit for use in replicating the op across one or more materials in the selection set. // // The apply function optionally performs the edit which it implements @@ -503,6 +507,8 @@ private: static Selection sMaterialOverrideSelection; + std::unique_ptr mInventoryListener; + public: #if defined(DEF_GET_MAT_STATE) #undef DEF_GET_MAT_STATE -- cgit v1.2.3