summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorCosmic Linden <cosmic@lindenlab.com>2023-08-07 14:26:33 -0700
committerCosmic Linden <cosmic@lindenlab.com>2023-08-11 16:31:01 -0700
commit76c8cca9363c0ef55bf66a2bbff4a86a02f37acf (patch)
tree9cfc97ccb55239bc8963ac8a4442d14e7df271ab /indra
parent6c8ced0edd9e2b86914e3e316ba65ae9492d3e6f (diff)
SL-20024: Fix author attributions not transferring for saved object materials, fix item not renamed
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/llmaterialeditor.cpp178
-rw-r--r--indra/newview/llmaterialeditor.h6
-rw-r--r--indra/newview/llviewerinventory.cpp63
-rw-r--r--indra/newview/llviewerinventory.h4
-rw-r--r--indra/newview/llviewerobject.cpp11
-rw-r--r--indra/newview/llviewerobject.h2
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);