diff options
author | Cosmic Linden <cosmic@lindenlab.com> | 2023-08-07 14:26:33 -0700 |
---|---|---|
committer | Cosmic Linden <cosmic@lindenlab.com> | 2023-08-11 16:31:01 -0700 |
commit | 76c8cca9363c0ef55bf66a2bbff4a86a02f37acf (patch) | |
tree | 9cfc97ccb55239bc8963ac8a4442d14e7df271ab /indra/newview | |
parent | 6c8ced0edd9e2b86914e3e316ba65ae9492d3e6f (diff) |
SL-20024: Fix author attributions not transferring for saved object materials, fix item not renamed
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/llmaterialeditor.cpp | 178 | ||||
-rw-r--r-- | indra/newview/llmaterialeditor.h | 6 | ||||
-rw-r--r-- | indra/newview/llviewerinventory.cpp | 63 | ||||
-rw-r--r-- | indra/newview/llviewerinventory.h | 4 | ||||
-rw-r--r-- | indra/newview/llviewerobject.cpp | 11 | ||||
-rw-r--r-- | indra/newview/llviewerobject.h | 2 |
6 files changed, 214 insertions, 50 deletions
diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index af40c9e931..bc3d5b88ab 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -37,6 +37,7 @@ #include "llfilesystem.h" #include "llgltfmateriallist.h" #include "llinventorymodel.h" +#include "llinventoryobserver.h" #include "lllocalgltfmaterials.h" #include "llnotificationsutil.h" #include "lltexturectrl.h" @@ -323,6 +324,7 @@ bool LLSelectedTEGetMatData::apply(LLViewerObject* objectp, S32 te_index) LLLocalGLTFMaterial *local_mat = dynamic_cast<LLLocalGLTFMaterial*>(mat); mObject = objectp; + mObjectId = objectp->getID(); if (local_mat) { mLocalMaterial = local_mat; @@ -1293,44 +1295,38 @@ bool LLMaterialEditor::updateInventoryItem(const std::string &buffer, const LLUU return true; } -void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& owner_permissions) +// Callback intended for when an item is copied from an object's inventory and +// needs to be modified to reflect the new asset/name. For example: When saving +// a modified material to the inventory from the build floater. +class LLObjectsMaterialItemCallback : public LLInventoryCallback { - // gen a new uuid for this asset - LLTransactionID tid; - tid.generate(); // timestamp-based randomization + uniquification - LLPermissions final_perm; +public: + LLObjectsMaterialItemCallback(const LLPermissions& permissions, const std::string& asset_data, const std::string& new_name) + : mPermissions(permissions), + mAssetData(asset_data), + mNewName(new_name) { - 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, final_perm.getMaskNextOwner(), - new LLBoostFuncInventoryCallback([output = buffer, final_perm](LLUUID const& inv_item_id) + void fire(const LLUUID& inv_item_id) override { LLViewerInventoryItem* item = gInventory.getItem(inv_item_id); - if (item) + if (!item) { - // create_inventory_item doesn't allow presetting some permissions, fix it now - LLPermissions perm = item->getPermissions(); - perm.accumulate(final_perm); - item->setPermissions(perm); + return; + } - item->updateServer(FALSE); - gInventory.updateItem(item); - gInventory.notifyObservers(); + // 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) + { + LLSD updates; + updates["name"] = mNewName; + update_inventory_item(inv_item_id, updates, NULL); } // from reference in LLSettingsVOBase::createInventoryItem()/updateInventoryItem() @@ -1338,7 +1334,7 @@ void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std: std::make_shared<LLBufferedAssetUploadInfo>( inv_item_id, LLAssetType::AT_MATERIAL, - output, + mAssetData, [](LLUUID item_id, LLUUID new_asset_id, LLUUID new_item_id, LLSD response) { // done callback @@ -1357,8 +1353,25 @@ void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std: } LLViewerAssetUpload::EnqueueInventoryUpload(agent_url, uploadInfo); } - }) - ); + } +private: + LLPermissions mPermissions; + std::string mAssetData; + std::string mNewName; +}; + +void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions) +{ + // gen a new uuid for this asset + LLTransactionID tid; + tid.generate(); // timestamp-based randomization + uniquification + LLUUID parent = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL); + const U8 subtype = NO_INV_SUBTYPE; // TODO maybe use AT_SETTINGS and LLSettingsType::ST_MATERIAL ? + + LLPointer<LLObjectsMaterialItemCallback> cb = new LLObjectsMaterialItemCallback(permissions, buffer, name); + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), parent, tid, name, desc, + LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, permissions.getMaskNextOwner(), + cb); } void LLMaterialEditor::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId) @@ -1807,10 +1820,8 @@ void LLMaterialEditor::loadLive() } } -// *NOTE: permissions_out ignores user preferences for new item creation. See -// LLFloaterPerms. Preferences are applied later on in -// LLMaterialEditor::createInventoryItem. -bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<PermissionBit>& ops, LLPermissions& permissions_out) +// *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) { if (!LLMaterialEditor::capabilitiesAvailable()) { @@ -1834,12 +1845,12 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<Pe } } - const LLViewerInventoryItem* item = selected_object->getInventoryItemByAsset(func.mMaterialId); + item_out = selected_object->getInventoryItemByAsset(func.mMaterialId); LLPermissions item_permissions; - if (item) + if (item_out) { - item_permissions.set(item->getPermissions()); + item_permissions.set(item_out->getPermissions()); for (PermissionBit op : ops) { if (!gAgent.allowOperation(op, item_permissions, GP_OBJECT_MANIPULATE)) @@ -1885,12 +1896,19 @@ bool can_use_objects_material(LLSelectedTEGetMatData& func, const std::vector<Pe object_permissions.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")); + 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. + // The server will populate creator info based on the item creation method + // used. permissions_out.accumulate(object_permissions); + permissions_out.accumulate(floater_perm); return true; } @@ -1899,30 +1917,34 @@ bool LLMaterialEditor::canModifyObjectsMaterial() { LLSelectedTEGetMatData func(false); LLPermissions permissions; - return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions); + LLViewerInventoryItem* item_out; + return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions, item_out); } bool LLMaterialEditor::canSaveObjectsMaterial() { LLSelectedTEGetMatData func(false); LLPermissions permissions; - return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions); + LLViewerInventoryItem* item_out; + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item_out); } void LLMaterialEditor::saveObjectsMaterialAs() { LLSelectedTEGetMatData func(false); LLPermissions permissions; - bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions); + LLViewerInventoryItem* item = nullptr; + bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item); if (!allowed) { LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL; return; } - saveMaterialAs(func.mMaterial, func.mLocalMaterial, permissions); + saveObjectsMaterialAs(func.mMaterial, func.mLocalMaterial, permissions, func.mObjectId, item); } -void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, const LLLocalGLTFMaterial *local_material, const LLPermissions& permissions) + +void LLMaterialEditor::saveObjectsMaterialAs(const LLGLTFMaterial* render_material, const LLLocalGLTFMaterial *local_material, const LLPermissions& permissions, const LLUUID& object_id, LLViewerInventoryItem* item) // TODO: item should probably just be an ID at this point { if (local_material) { @@ -2006,10 +2028,65 @@ void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, con } else { - LLNotificationsUtil::add("SaveMaterialAs", args, payload, boost::bind(&LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback, _1, _2, permissions)); + if (item) + { + // 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->getUUID())); + } + 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) + { + 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); + + // TODO: Test + // TODO: Rename the item + 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 void LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback(const LLSD& notification, const LLSD& response, const LLPermissions& permissions) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -2025,6 +2102,11 @@ void LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback(const LLSD& notificati LLSDSerialize::serialize(asset, str, LLSDSerialize::LLSD_BINARY); std::string new_name = response["message"].asString(); + LLInventoryObject::correctInventoryName(new_name); + if (new_name.empty()) + { + return; + } createInventoryItem(str.str(), new_name, std::string(), permissions); } } diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h index 54e59fcdf8..2176f493a9 100644 --- a/indra/newview/llmaterialeditor.h +++ b/indra/newview/llmaterialeditor.h @@ -38,6 +38,7 @@ class LLGLTFMaterial; class LLLocalGLTFMaterial; class LLTextureCtrl; class LLTextBox; +class LLViewerInventoryItem; namespace tinygltf { @@ -115,6 +116,7 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener static bool canModifyObjectsMaterial(); static bool canSaveObjectsMaterial(); 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); @@ -230,10 +232,10 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener static bool capabilitiesAvailable(); private: - static void saveMaterialAs(const LLGLTFMaterial *render_material, const LLLocalGLTFMaterial *local_material, const LLPermissions& permissions); + static void saveObjectsMaterialAs(const LLGLTFMaterial *render_material, const LLLocalGLTFMaterial *local_material, const LLPermissions& permissions, const LLUUID& object_id /* = LLUUID::null */, LLViewerInventoryItem* item /* = nullptr */); static bool updateInventoryItem(const std::string &buffer, const LLUUID &item_id, const LLUUID &task_id); - static void createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& owner_permissions); + static void createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions); void setFromGLTFMaterial(LLGLTFMaterial* mat); bool setFromSelection(); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 518967709d..b722e715b6 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1604,6 +1604,69 @@ 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) +{ + // TODO: Implement + + 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 24b632632b..6c0f1b8d07 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -439,6 +439,10 @@ 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, diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index d21d6f7027..69e62ace97 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3610,6 +3610,17 @@ LLInventoryObject* LLViewerObject::getInventoryObject(const LLUUID& item_id) return rv; } +LLInventoryItem* LLViewerObject::getInventoryItem(const LLUUID& item_id) +{ + LLInventoryObject* iobj = getInventoryObject(item_id); + if (!iobj || iobj->getType() == LLAssetType::AT_CATEGORY) + { + return NULL; + } + LLInventoryItem* item = dynamic_cast<LLInventoryItem*>(iobj); + return item; +} + void LLViewerObject::getInventoryContents(LLInventoryObject::object_list_t& objects) { if(mInventory) diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 3665c64965..ff28937f81 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -494,6 +494,8 @@ public: void updateInventoryLocal(LLInventoryItem* item, U8 key); // Update without messaging. void updateMaterialInventory(LLViewerInventoryItem* item, U8 key, bool is_new); LLInventoryObject* getInventoryObject(const LLUUID& item_id); + // TODO: Decide if this is worth keeping - Returns NULL if item does not exist or is a category + LLInventoryItem* getInventoryItem(const LLUUID& item_id); // Get content except for root category void getInventoryContents(LLInventoryObject::object_list_t& objects); |