summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/llpublishedobjectmgr.cpp166
-rw-r--r--indra/newview/llpublishedobjectmgr.h15
-rw-r--r--indra/newview/llscripteditorws.cpp62
-rw-r--r--indra/newview/llscripteditorws.h3
-rw-r--r--indra/newview/llselectmgr.cpp2
5 files changed, 191 insertions, 57 deletions
diff --git a/indra/newview/llpublishedobjectmgr.cpp b/indra/newview/llpublishedobjectmgr.cpp
index 85a9542dce..5cbb7ca76d 100644
--- a/indra/newview/llpublishedobjectmgr.cpp
+++ b/indra/newview/llpublishedobjectmgr.cpp
@@ -32,6 +32,7 @@
#include "llchat.h"
#include "llinventorydefines.h"
#include "llregex.h"
+#include "llsdutil.h"
#include "llselectmgr.h"
#include "llviewerinventory.h"
#include "llviewerobject.h"
@@ -66,7 +67,7 @@ namespace
return std::string(s);
}
- std::string get_prim_name(LLViewerObject* obj)
+ std::string get_prim_name(LLViewerObject* obj, S32 link_number = 1)
{
std::string name = nv_string(obj, "Name");
if (!name.empty())
@@ -85,25 +86,17 @@ namespace
return node->mName;
}
- // Never emit an empty prim/object name to downstream tooling.
- return obj->getID().asString();
+ // Real prim names need a full ObjectProperties reply, which requires selection.
+ return (link_number > 1) ? llformat("Link #%d", link_number) : std::string("Object");
}
void add_object_permissions(LLSD& object_data, LLViewerObject* object)
{
- LLPermissions* permissions =
- LLSelectMgr::getInstance()->findObjectPermissions(object);
- if (!permissions)
+ LLSD permissions = LLPublishedObjectMgr::getObjectPermissionsLLSD(object);
+ if (permissions.isDefined())
{
- return;
+ object_data["permissions"] = permissions;
}
-
- LLSD permission_entry;
- permission_entry["owner"] =
- static_cast<S32>(permissions->getMaskOwner());
- permission_entry["next_owner"] =
- static_cast<S32>(permissions->getMaskNextOwner());
- object_data["permissions"] = permission_entry;
}
}
@@ -742,6 +735,59 @@ LLSD LLPublishedObjectMgr::buildPrimInventoryLLSD(LLViewerObject* object) const
return items;
}
+LLSD LLPublishedObjectMgr::makePermissionsLLSD(U32 owner_mask, U32 next_owner_mask)
+{
+ LLSD permissions;
+ permissions["owner"] = static_cast<S32>(owner_mask);
+ permissions["next_owner"] = static_cast<S32>(next_owner_mask);
+ return permissions;
+}
+
+LLSD LLPublishedObjectMgr::getObjectPermissionsLLSD(LLViewerObject* object)
+{
+ if (!object)
+ {
+ return LLSD();
+ }
+
+ LLPermissions* permissions =
+ LLSelectMgr::getInstance()->findObjectPermissions(object);
+ if (permissions)
+ {
+ return makePermissionsLLSD(permissions->getMaskOwner(), permissions->getMaskNextOwner());
+ }
+
+ // Unselected prims carry no LLPermissions, but object flags still hold this agent's rights.
+ // next_owner is unavailable from flags and is omitted until ObjectProperties arrives.
+ U32 owner_mask = 0;
+ if (object->permModify()) { owner_mask |= PERM_MODIFY; }
+ if (object->permCopy()) { owner_mask |= PERM_COPY; }
+ if (object->permTransfer()) { owner_mask |= PERM_TRANSFER; }
+ if (object->permMove()) { owner_mask |= PERM_MOVE; }
+
+ LLSD permission_entry;
+ permission_entry["owner"] = static_cast<S32>(owner_mask);
+ return permission_entry;
+}
+
+bool LLPublishedObjectMgr::computeCanSaveBack(LLViewerObject* root, LLUUID& source_task_id)
+{
+ source_task_id.setNull();
+ if (!root || root->isAttachment())
+ {
+ return false;
+ }
+
+ LLSelectNode* node = LLSelectMgr::instance().getSelection()->findNode(root);
+ if (!node || !node->mValid || node->mFromTaskID.isNull())
+ {
+ return false;
+ }
+
+ source_task_id = node->mFromTaskID;
+ return true;
+}
+
LLSD LLPublishedObjectMgr::buildPublishedObjectLLSD(LLViewerObject* root) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SCRIPTDEV;
@@ -768,12 +814,13 @@ LLSD LLPublishedObjectMgr::buildPublishedObjectLLSD(LLViewerObject* root) const
{
LLSD link;
link["link_id"] = child->getID();
- link["link_number"] = link_number++;
- link["link_name"] = get_prim_name(child);
+ link["link_number"] = link_number;
+ link["link_name"] = get_prim_name(child, link_number);
link["link_description"] = nv_string(child, "Desc");
add_object_permissions(link, child);
link["inventory"] = buildPrimInventoryLLSD(child);
linked_objects.append(link);
+ ++link_number;
}
if (linked_objects.size() > 0)
{
@@ -1083,25 +1130,37 @@ bool LLPublishedObjectMgr::applyPropertyChange(
if (prim_id == root_id)
{
- bool has_name = !name.empty();
- bool name_changed = has_name && (pub_info->mObjectName != name);
- bool desc_changed = (pub_info->mObjectDescription != desc);
- if (!name_changed && !desc_changed)
- {
- return false;
- }
+ bool changed = false;
- if (name_changed)
+ if (!name.empty() && pub_info->mObjectName != name)
{
pub_info->mObjectName = name;
update["object_name"] = name;
+ changed = true;
}
- if (desc_changed)
+ if (pub_info->mObjectDescription != desc)
{
pub_info->mObjectDescription = desc;
update["object_description"] = desc;
+ changed = true;
}
- return true;
+
+ // Properties arrive after publish, so this field is backfilled here.
+ LLViewerObject* root = gObjectList.findObject(root_id);
+ if (root)
+ {
+ LLUUID source_task_id;
+ const bool can_save_back = computeCanSaveBack(root, source_task_id);
+ if (can_save_back != pub_info->mCanSaveBackToContents)
+ {
+ pub_info->mCanSaveBackToContents = can_save_back;
+ pub_info->mSourceTaskID = source_task_id;
+ update["can_save_back"] = can_save_back;
+ changed = true;
+ }
+ }
+
+ return changed;
}
auto prim_it = std::find_if(pub_info->mPrims.begin(), pub_info->mPrims.end(),
@@ -1135,6 +1194,61 @@ bool LLPublishedObjectMgr::applyPropertyChange(
return true;
}
+bool LLPublishedObjectMgr::applyPermissionsChange(
+ const LLUUID& root_id,
+ const LLUUID& prim_id,
+ const LLUUID& owner_id,
+ U32 owner_mask,
+ U32 next_owner_mask,
+ LLSD& update)
+{
+ PublishedObjectInfo* pub_info = getPublished(root_id);
+ if (!pub_info)
+ {
+ return false;
+ }
+
+ const LLSD permissions = makePermissionsLLSD(owner_mask, next_owner_mask);
+
+ update = LLSD();
+ update["object_id"] = root_id;
+
+ if (prim_id == root_id)
+ {
+ bool changed = false;
+ if (!llsd_equals(permissions, pub_info->mPermissions))
+ {
+ pub_info->mPermissions = permissions;
+ update["permissions"] = permissions;
+ changed = true;
+ }
+ if (owner_id.notNull() && pub_info->mOwnerID != owner_id)
+ {
+ pub_info->mOwnerID = owner_id;
+ update["owner_id"] = owner_id;
+ changed = true;
+ }
+ return changed;
+ }
+
+ auto prim_it = std::find_if(pub_info->mPrims.begin(), pub_info->mPrims.end(),
+ [&](const PublishedPrimInfo& p) { return p.mPrimID == prim_id; });
+ if (prim_it == pub_info->mPrims.end() || llsd_equals(permissions, prim_it->mPermissions))
+ {
+ return false;
+ }
+
+ prim_it->mPermissions = permissions;
+
+ LLSD modified_entry;
+ modified_entry["link_id"] = prim_id;
+ modified_entry["permissions"] = permissions;
+ LLSD modified_arr = LLSD::emptyArray();
+ modified_arr.append(modified_entry);
+ update["changes"]["linked_objects"]["modified"] = modified_arr;
+ return true;
+}
+
bool LLPublishedObjectMgr::hasActiveLinksetFlushTimer(const LLUUID& root_id) const
{
auto it = mLinksetFlushTimers.find(root_id);
diff --git a/indra/newview/llpublishedobjectmgr.h b/indra/newview/llpublishedobjectmgr.h
index 51af129dcb..8a6c8b705c 100644
--- a/indra/newview/llpublishedobjectmgr.h
+++ b/indra/newview/llpublishedobjectmgr.h
@@ -55,6 +55,7 @@ public:
S32 mLinkNumber;
std::string mPrimDescription;
S16 mInventorySerial;
+ LLSD mPermissions;
};
struct PublishedObjectInfo
@@ -73,6 +74,7 @@ public:
std::string mRegionName;
bool mCanSaveBackToContents{ false };
LLUUID mSourceTaskID;
+ LLSD mPermissions;
std::vector<PublishedPrimInfo> mPrims;
std::vector<std::unique_ptr<LLPublishedPrimListener>> mListeners;
};
@@ -256,6 +258,12 @@ public:
LLSD buildPrimInventoryLLSD(LLViewerObject* object) const;
LLSD buildPublishedObjectLLSD(LLViewerObject* root) const;
LLSD buildObjectListLLSD() const;
+
+ // Both depend on a valid LLSelectNode, so they yield nothing until ObjectProperties arrives.
+ static LLSD getObjectPermissionsLLSD(LLViewerObject* object);
+ static bool computeCanSaveBack(LLViewerObject* root, LLUUID& source_task_id);
+ static LLSD makePermissionsLLSD(U32 owner_mask, U32 next_owner_mask);
+
bool buildLinksetUpdateLLSD(const LLUUID& root_id, LLSD& update) const;
bool reconcileLinksetChildAdded(const LLUUID& root_id, LLViewerObject* child, F64 request_start_sec);
bool reconcileLinksetChildRemoved(const LLUUID& root_id, const LLUUID& child_id);
@@ -275,6 +283,13 @@ public:
const std::string& name,
const std::string& desc,
LLSD& update);
+ bool applyPermissionsChange(
+ const LLUUID& root_id,
+ const LLUUID& prim_id,
+ const LLUUID& owner_id,
+ U32 owner_mask,
+ U32 next_owner_mask,
+ LLSD& update);
void beginPendingPublish(const LLUUID& object_id, const std::vector<LLViewerObject*>& prims);
bool hasPendingPublish(const LLUUID& object_id) const;
diff --git a/indra/newview/llscripteditorws.cpp b/indra/newview/llscripteditorws.cpp
index 017d9a5540..8413547935 100644
--- a/indra/newview/llscripteditorws.cpp
+++ b/indra/newview/llscripteditorws.cpp
@@ -2395,7 +2395,7 @@ void LLScriptEditorWSServer::notifyAll(const std::string& method, const LLSD& pa
// static
-std::string LLScriptEditorWSServer::getPrimName(LLViewerObject* obj)
+std::string LLScriptEditorWSServer::getPrimName(LLViewerObject* obj, S32 link_number)
{
std::string name = nv_string(obj, "Name");
if (!name.empty())
@@ -2414,8 +2414,8 @@ std::string LLScriptEditorWSServer::getPrimName(LLViewerObject* obj)
return node->mName;
}
- // Never emit an empty prim/object name to downstream tooling.
- return obj->getID().asString();
+ // Real prim names need a full ObjectProperties reply, which requires selection.
+ return (link_number > 1) ? llformat("Link #%d", link_number) : std::string("Object");
}
bool LLScriptEditorWSServer::publishObject(const LLUUID& object_id)
@@ -2443,12 +2443,8 @@ bool LLScriptEditorWSServer::publishObject(const LLUUID& object_id)
// Collect root + all children
std::vector<LLViewerObject*> prims = collect_linkset(root);
- // Request object properties for each prim in the linkset (root + children),
- // matching the hover path so name/description metadata is refreshed.
- for (LLViewerObject* prim : prims)
- {
- LLSelectMgr::instance().requestObjectPropertiesFamily(prim);
- }
+ // The sim coalesces properties-family requests to the root, so one request covers the linkset.
+ LLSelectMgr::instance().requestObjectPropertiesFamily(root);
// Set up a PendingPublish to coordinate inventory loading across all prims.
// We register a listener and call requestInventory() on every prim.
@@ -2513,24 +2509,14 @@ void LLScriptEditorWSServer::buildAndSendPublish(const LLUUID& object_id)
info.mOwnerID = root->mOwnerID;
info.mObjectName = pub["object_name"].asString();
info.mObjectDescription = pub["object_description"].asString();
+ info.mPermissions = LLPublishedObjectMgr::getObjectPermissionsLLSD(root);
if (root->getRegion())
{
info.mRegionName = root->getRegion()->getName();
}
- LLSelectNode* root_select_node = LLSelectMgr::instance().getSelection()->findNode(root);
- if (root_select_node
- && root_select_node->mValid
- && !root_select_node->mFromTaskID.isNull()
- && !root->isAttachment())
- {
- info.mCanSaveBackToContents = true;
- info.mSourceTaskID = root_select_node->mFromTaskID;
- }
- else
- {
- info.mCanSaveBackToContents = false;
- info.mSourceTaskID.setNull();
- }
+ LLUUID source_task_id;
+ info.mCanSaveBackToContents = LLPublishedObjectMgr::computeCanSaveBack(root, source_task_id);
+ info.mSourceTaskID = source_task_id;
S32 link_num = 1;
std::vector<LLViewerObject*> prims = collect_linkset(root);
@@ -2538,9 +2524,10 @@ void LLScriptEditorWSServer::buildAndSendPublish(const LLUUID& object_id)
{
LLPublishedObjectMgr::PublishedPrimInfo prim_info;
prim_info.mPrimID = prim->getID();
- prim_info.mPrimName = getPrimName(prim); // Use helper with selection fallback
prim_info.mLinkNumber = link_num++;
+ prim_info.mPrimName = getPrimName(prim, prim_info.mLinkNumber);
prim_info.mInventorySerial = static_cast<S16>(prim->getInventorySerial());
+ prim_info.mPermissions = LLPublishedObjectMgr::getObjectPermissionsLLSD(prim);
info.mPrims.push_back(prim_info);
}
@@ -2581,12 +2568,9 @@ void LLScriptEditorWSServer::buildAndSendPublish(const LLUUID& object_id)
<< " (" << pub["object_name"].asString() << ") with "
<< (prims.size() - 1) << " linked prim(s)" << LL_ENDL;
- // Re-request object properties now that the object is published so
- // onObjectPropertyChanged can emit object.update for root and linked prims.
- for (LLViewerObject* prim : prims)
- {
- LLSelectMgr::instance().requestObjectPropertiesFamily(prim);
- }
+ // Re-request now that the object is published so onObjectPropertyChanged can emit
+ // object.update. The sim answers per linkset, so only the root needs asking.
+ LLSelectMgr::instance().requestObjectPropertiesFamily(root);
}
void LLScriptEditorWSServer::onLinksetChildAdded(const LLUUID& root_id, LLViewerObject* child)
@@ -2748,6 +2732,24 @@ void LLScriptEditorWSServer::onObjectPropertyChanged(
}
}
+void LLScriptEditorWSServer::onObjectPermissionsReceived(
+ const LLUUID& prim_id, const LLUUID& owner_id, U32 owner_mask, U32 next_owner_mask)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_SCRIPTDEV;
+ LLViewerObject* prim = gObjectList.findObject(prim_id);
+ if (!prim)
+ {
+ return;
+ }
+
+ LLSD update;
+ if (mPublishedObjectManager.applyPermissionsChange(
+ prim->getRootEdit()->getID(), prim_id, owner_id, owner_mask, next_owner_mask, update))
+ {
+ notifyAll("object.update", update);
+ }
+}
+
void LLScriptEditorWSServer::unpublishObject(const LLUUID& object_id, const std::string& reason)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SCRIPTDEV;
diff --git a/indra/newview/llscripteditorws.h b/indra/newview/llscripteditorws.h
index 6eb8385210..f85c3e6475 100644
--- a/indra/newview/llscripteditorws.h
+++ b/indra/newview/llscripteditorws.h
@@ -225,6 +225,7 @@ public:
void onPrimInventoryReady(const LLUUID& object_id, const LLUUID& prim_id);
void onPrimInventoryChanged(const LLUUID& object_id, const LLUUID& prim_id);
void onObjectPropertyChanged(const LLUUID& prim_id, const std::string& name, const std::string& desc, S16 inventory_serial = -1);
+ void onObjectPermissionsReceived(const LLUUID& prim_id, const LLUUID& owner_id, U32 owner_mask, U32 next_owner_mask);
void onLinksetChildAdded(const LLUUID& root_id, LLViewerObject* child);
void onLinksetChildRemoved(const LLUUID& root_id, const LLUUID& child_id);
@@ -280,7 +281,7 @@ protected:
ValidatedItem validatePublishedItem(const LLSD& params, U32 permMask) const;
// --- Object Content Publishing (helpers) ---
- static std::string getPrimName(LLViewerObject* obj);
+ static std::string getPrimName(LLViewerObject* obj, S32 link_number = 1);
void notifyConnection(U32 connection_id, const std::string& method, const LLSD& params) const;
void notifyAll(const std::string& method, const LLSD& params) const;
void buildAndSendPublish(const LLUUID& object_id);
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 432678b132..f9108fcc64 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -6115,6 +6115,7 @@ void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data
if (ws_server)
{
ws_server->onObjectPropertyChanged(id, name, desc, inv_serial);
+ ws_server->onObjectPermissionsReceived(id, owner_id, owner_mask, next_owner_mask);
}
}
@@ -6215,6 +6216,7 @@ void LLSelectMgr::processObjectPropertiesFamily(LLMessageSystem* msg, void** use
if (auto ws_server = LLScriptEditorWSServer::getServer())
{
ws_server->onObjectPropertyChanged(id, name, desc);
+ ws_server->onObjectPermissionsReceived(id, owner_id, owner_mask, next_owner_mask);
}
}