mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-16 19:37:18 +02:00
Merge pull request #1098 from digisomni/feature/security-package-feb-mar-2021
Add avatarEntities permissions
This commit is contained in:
commit
749c2674b0
30 changed files with 549 additions and 53 deletions
assignment-client/src/avatars
domain-server
resources
src
interface
resources/qml/hifi
src
libraries
|
@ -269,7 +269,13 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
|||
// the avatar mixer uses the negative value of the sent version
|
||||
instanceVersionRef = -packetTraitVersion;
|
||||
} else {
|
||||
_avatar->processTraitInstance(traitType, instanceID, message.read(traitSize));
|
||||
// Don't accept avatar entity data for distribution unless sender has rez permissions on the domain.
|
||||
// The sender shouldn't be sending avatar entity data, however this provides a back-up.
|
||||
auto trait = message.read(traitSize);
|
||||
if (sendingNode.getCanRezAvatarEntities()) {
|
||||
_avatar->processTraitInstance(traitType, instanceID, trait);
|
||||
}
|
||||
|
||||
instanceVersionRef = packetTraitVersion;
|
||||
}
|
||||
|
||||
|
@ -290,6 +296,29 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message,
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarMixerClientData::emulateDeleteEntitiesTraitsMessage(const QList<QUuid>& avatarEntityIDs) {
|
||||
// Emulates processSetTraitsMessage() actions on behalf of an avatar whose canRezAvatarEntities permission has been removed.
|
||||
// The source avatar should be removing its avatar entities. However, using this method provides a back-up.
|
||||
|
||||
auto traitType = AvatarTraits::AvatarEntity;
|
||||
for (const auto& entityID : avatarEntityIDs) {
|
||||
auto& instanceVersionRef = _lastReceivedTraitVersions.getInstanceValueRef(traitType, entityID);
|
||||
|
||||
_avatar->processDeletedTraitInstance(traitType, entityID);
|
||||
// Mixer doesn't need deleted IDs.
|
||||
_avatar->getAndClearRecentlyRemovedIDs();
|
||||
|
||||
// to track a deleted instance but keep version information
|
||||
// the avatar mixer uses the negative value of the sent version
|
||||
// Because there is no originating message from an avatar we enlarge the magnitude by 1.
|
||||
// If a user subsequently has canRezAvatarEntities permission granted, they will have to relog in order for their
|
||||
// avatar entities to be visible to others.
|
||||
instanceVersionRef = -instanceVersionRef - 1;
|
||||
}
|
||||
|
||||
_lastReceivedTraitsChange = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
void AvatarMixerClientData::processBulkAvatarTraitsAckMessage(ReceivedMessage& message) {
|
||||
// Avatar Traits flow control marks each outgoing avatar traits packet with a
|
||||
// sequence number. The mixer caches the traits sent in the traits packet.
|
||||
|
|
|
@ -132,6 +132,7 @@ public:
|
|||
int processPackets(const SlaveSharedData& slaveSharedData); // returns number of packets processed
|
||||
|
||||
void processSetTraitsMessage(ReceivedMessage& message, const SlaveSharedData& slaveSharedData, Node& sendingNode);
|
||||
void emulateDeleteEntitiesTraitsMessage(const QList<QUuid>& avatarEntityIDs);
|
||||
void processBulkAvatarTraitsAckMessage(ReceivedMessage& message);
|
||||
void checkSkeletonURLAgainstWhitelist(const SlaveSharedData& slaveSharedData, Node& sendingNode,
|
||||
AvatarTraits::TraitVersion traitVersion);
|
||||
|
|
|
@ -432,6 +432,17 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
|||
}
|
||||
}
|
||||
|
||||
// The source avatar should be removing its avatar entities. However, provide a back-up.
|
||||
if (sendAvatar) {
|
||||
if (!sourceAvatarNode->getCanRezAvatarEntities()) {
|
||||
auto sourceAvatarNodeData = reinterpret_cast<AvatarMixerClientData*>(sourceAvatarNode->getLinkedData());
|
||||
auto avatarEntityIDs = sourceAvatarNodeData->getAvatar().getAvatarEntityIDs();
|
||||
if (avatarEntityIDs.count() > 0) {
|
||||
sourceAvatarNodeData->emulateDeleteEntitiesTraitsMessage(avatarEntityIDs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sendAvatar) {
|
||||
AvatarDataSequenceNumber lastSeqToReceiver = destinationNodeData->getLastBroadcastSequenceNumber(sourceAvatarNode->getLocalID());
|
||||
AvatarDataSequenceNumber lastSeqFromSender = sourceAvatarNodeData->getLastReceivedSequenceNumber();
|
||||
|
|
|
@ -398,7 +398,7 @@ void ScriptableAvatar::setAvatarEntityData(const AvatarEntityMap& avatarEntityDa
|
|||
|
||||
// clear deleted traits
|
||||
for (const auto& id : idsToClear) {
|
||||
clearAvatarEntity(id);
|
||||
clearAvatarEntityInternal(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,7 +408,7 @@ void ScriptableAvatar::updateAvatarEntity(const QUuid& entityID, const QByteArra
|
|||
std::map<QUuid, EntityItemPointer>::iterator itr = _entities.find(entityID);
|
||||
if (itr != _entities.end()) {
|
||||
_entities.erase(itr);
|
||||
clearAvatarEntity(entityID);
|
||||
clearAvatarEntityInternal(entityID);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": 2.4,
|
||||
"version": 2.5,
|
||||
"settings": [
|
||||
{
|
||||
"name": "metaverse",
|
||||
|
@ -295,10 +295,10 @@
|
|||
},
|
||||
{
|
||||
"name": "approved_safe_urls",
|
||||
"label": "Approved Script and QML URLs",
|
||||
"label": "Approved Script and QML URLs (Not Enabled)",
|
||||
"help": "These URLs will be sent to the Interface as safe URLs to allow through the whitelist if the Interface has this security option enabled.",
|
||||
"placeholder": "0",
|
||||
"default": "1",
|
||||
"placeholder": "",
|
||||
"default": "",
|
||||
"advanced": false
|
||||
},
|
||||
{
|
||||
|
@ -338,7 +338,7 @@
|
|||
"name": "standard_permissions",
|
||||
"type": "table",
|
||||
"label": "Domain-Wide User Permissions",
|
||||
"help": "Indicate which types of users can have which <a data-toggle='tooltip' data-html=true title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>domain-wide permissions</a>.",
|
||||
"help": "Indicate which types of users can have which <a data-toggle='tooltip' data-html=true title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Avatar Entities</strong><br />Sets whether a user can use avatar entities on the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>domain-wide permissions</a>.",
|
||||
"caption": "Standard Permissions",
|
||||
"can_add_new_rows": false,
|
||||
"groups": [
|
||||
|
@ -347,8 +347,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>?</a>",
|
||||
"span": 11
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Avatar Entities</strong><br />Sets whether a user can use avatar entities on the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level permissions that might otherwise apply to that user. Additionally, if more than one parameter is applicable to a given user, the permissions given to that user will be the sum of all applicable parameters. For example, let’s say only localhost users can connect and only logged in users can lock and unlock entities. If a user is both logged in and on localhost then they will be able to both connect and lock/unlock entities.</p>'>?</a>",
|
||||
"span": 12
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -363,6 +363,13 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_avatar_entities",
|
||||
"label": "Avatar Entities",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_adjust_locks",
|
||||
"label": "Lock / Unlock",
|
||||
|
@ -439,17 +446,20 @@
|
|||
"default": [
|
||||
{
|
||||
"id_can_connect": true,
|
||||
"id_can_rez_avatar_entities": true,
|
||||
"id_can_rez_tmp_certified": true,
|
||||
"permissions_id": "anonymous"
|
||||
},
|
||||
{
|
||||
"id_can_connect": true,
|
||||
"id_can_rez_avatar_entities": true,
|
||||
"id_can_rez_tmp_certified": true,
|
||||
"permissions_id": "friends"
|
||||
},
|
||||
{
|
||||
"id_can_adjust_locks": true,
|
||||
"id_can_connect": true,
|
||||
"id_can_rez_avatar_entities": true,
|
||||
"id_can_adjust_locks": true,
|
||||
"id_can_connect_past_max_capacity": true,
|
||||
"id_can_kick": true,
|
||||
"id_can_replace_content": true,
|
||||
|
@ -463,6 +473,7 @@
|
|||
},
|
||||
{
|
||||
"id_can_connect": true,
|
||||
"id_can_rez_avatar_entities": true,
|
||||
"id_can_rez_tmp_certified": true,
|
||||
"permissions_id": "logged-in"
|
||||
}
|
||||
|
@ -484,8 +495,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in, as well as permissions from the previous section. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"span": 11
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Avatar Entities</strong><br />Sets whether users in specific groups can use avatar entities on the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users in specific groups can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in, as well as permissions from the previous section. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"span": 12
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -525,6 +536,13 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_avatar_entities",
|
||||
"label": "Avatar Entities",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_adjust_locks",
|
||||
"label": "Lock / Unlock",
|
||||
|
@ -613,8 +631,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users in specific groups can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"span": 11
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Avatar Entities</strong><br />Sets whether users in specific groups can use avatar entities on the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users in specific groups can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users in specific groups can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users in specific groups can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in. Group permissions are only granted if the user doesn’t have their own row in the per-account section, below.</p>'>?</a>",
|
||||
"span": 12
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -651,6 +669,13 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_avatar_entities",
|
||||
"label": "Avatar Entities",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_adjust_locks",
|
||||
"label": "Lock / Unlock",
|
||||
|
@ -734,8 +759,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level or group permissions that might otherwise apply to that user.</p>'>?</a>",
|
||||
"span": 11
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether a user can connect to the domain.</li><li><strong>Avatar Entities</strong><br />Sets whether a user can use avatar entities on the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether a user change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether a user can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether a user can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether a user can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether a user can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether a user can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether a user can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific user will supersede any parameter-level or group permissions that might otherwise apply to that user.</p>'>?</a>",
|
||||
"span": 12
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -750,6 +775,13 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_avatar_entities",
|
||||
"label": "Avatar Entities",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_adjust_locks",
|
||||
"label": "Lock / Unlock",
|
||||
|
@ -833,8 +865,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide IP Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users from specific IPs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific IPs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users from specific IPs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users from specific IPs can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users from specific IPs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users from specific IPs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users from specific IPs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users from specific IPs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users from specific IPs can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific IP will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). IP address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 11
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide IP Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users from specific IPs can connect to the domain.</li><li><strong>Avatar Entities</strong><br />Sets whether users from specific IPs can use avatar entities on the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific IPs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users from specific IPs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users from specific IPs can create new entities with a finite lifetime.</li><li><strong>Rez Temporary</strong><br />Sets whether a user can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users from specific IPs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users from specific IPs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users from specific IPs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users from specific IPs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users from specific IPs can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific IP will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). IP address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 12
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -849,6 +881,13 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_avatar_entities",
|
||||
"label": "Avatar Entities",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_adjust_locks",
|
||||
"label": "Lock / Unlock",
|
||||
|
@ -932,8 +971,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide MAC Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific MACs can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific MACs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific MACs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific MACs can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific MACs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific MACs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific MACs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific MACs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific MACs can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific MAC will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). MAC address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 11
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide MAC Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific MACs can connect to the domain.</li><li><strong>Avatar Entities</strong><br />Sets whether users with specific MACs can use avatar entities on the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific MACs can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific MACs can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific MACs can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific MACs can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific MACs can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific MACs can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific MACs can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific MACs can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific MAC will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). MAC address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 12
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -948,6 +987,13 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_avatar_entities",
|
||||
"label": "Avatar Entities",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_adjust_locks",
|
||||
"label": "Lock / Unlock",
|
||||
|
@ -1031,8 +1077,8 @@
|
|||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide Machine Fingerprint Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific Machine Fingerprints can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific Machine Fingerprints can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific Machine Fingerprints can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific Machine Fingerprints can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific Machine Fingerprints can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific Machine Fingerprints can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific Machine Fingerprints can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific Machine Fingerprint will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). Machine Fingerprint address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 11
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide Machine Fingerprint Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific Machine Fingerprints can connect to the domain.</li><li><strong>Avatar Entities</strong><br />Sets whether users with specific Machine Fingerprints can use avatar entities on the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific Machine Fingerprints can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users with specific Machine Fingerprints can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific Machine Fingerprints can create new entities with a finite lifetime.</li><li><strong>Rez Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities.</li><li><strong>Rez Temporary Certified</strong><br />Sets whether users with specific Machine Fingerprints can create new certified entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific Machine Fingerprints can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific Machine Fingerprints can connect even if the domain has reached or exceeded its maximum allowed agents.</li><li><strong>Replace Content</strong><br>Sets whether users with specific Machine Fingerprints can replace entire content sets by wiping existing domain content.</li><li><strong>Get and Set Private User Data</strong><br>Sets whether a user can get and set the privateUserData entity property.</li></ul><p>Note that permissions assigned to a specific Machine Fingerprint will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). Machine Fingerprint address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 12
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
|
@ -1047,6 +1093,13 @@
|
|||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_avatar_entities",
|
||||
"label": "Avatar Entities",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_adjust_locks",
|
||||
"label": "Lock / Unlock",
|
||||
|
|
|
@ -465,6 +465,7 @@ function savePermissions() {
|
|||
"standard_permissions": [
|
||||
{
|
||||
"id_can_connect": anonymousCanConnect,
|
||||
"id_can_rez_avatar_entities": anonymousCanConnect,
|
||||
"id_can_rez": anonymousCanRez,
|
||||
"id_can_rez_certified": anonymousCanRez,
|
||||
"id_can_rez_tmp": anonymousCanRez,
|
||||
|
@ -473,6 +474,7 @@ function savePermissions() {
|
|||
},
|
||||
{
|
||||
"id_can_connect": friendsCanConnect,
|
||||
"id_can_rez_avatar_entities": friendsCanConnect,
|
||||
"id_can_rez": friendsCanRez,
|
||||
"id_can_rez_certified": friendsCanRez,
|
||||
"id_can_rez_tmp": friendsCanRez,
|
||||
|
@ -481,6 +483,7 @@ function savePermissions() {
|
|||
},
|
||||
{
|
||||
"id_can_connect": loggedInCanConnect,
|
||||
"id_can_rez_avatar_entities": loggedInCanConnect,
|
||||
"id_can_rez": loggedInCanRez,
|
||||
"id_can_rez_certified": loggedInCanRez,
|
||||
"id_can_rez_tmp": loggedInCanRez,
|
||||
|
@ -490,6 +493,7 @@ function savePermissions() {
|
|||
{
|
||||
"id_can_adjust_locks": localhostPermissions,
|
||||
"id_can_connect": localhostPermissions,
|
||||
"id_can_rez_avatar_entities": localhostPermissions,
|
||||
"id_can_connect_past_max_capacity": localhostPermissions,
|
||||
"id_can_kick": localhostPermissions,
|
||||
"id_can_replace_content": localhostPermissions,
|
||||
|
|
|
@ -353,6 +353,7 @@ void DomainGatekeeper::updateNodePermissions() {
|
|||
userPerms.permissions |= NodePermissions::Permission::canWriteToAssetServer;
|
||||
userPerms.permissions |= NodePermissions::Permission::canReplaceDomainContent;
|
||||
userPerms.permissions |= NodePermissions::Permission::canGetAndSetPrivateUserData;
|
||||
userPerms.permissions |= NodePermissions::Permission::canRezAvatarEntities;
|
||||
} else {
|
||||
// at this point we don't have a sending socket for packets from this node - assume it is the active socket
|
||||
// or the public socket if we haven't activated a socket for the node yet
|
||||
|
@ -448,6 +449,7 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo
|
|||
userPerms.permissions |= NodePermissions::Permission::canWriteToAssetServer;
|
||||
userPerms.permissions |= NodePermissions::Permission::canReplaceDomainContent;
|
||||
userPerms.permissions |= NodePermissions::Permission::canGetAndSetPrivateUserData;
|
||||
userPerms.permissions |= NodePermissions::Permission::canRezAvatarEntities;
|
||||
newNode->setPermissions(userPerms);
|
||||
return newNode;
|
||||
}
|
||||
|
|
|
@ -528,6 +528,28 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena
|
|||
*newAdminRoles = adminRoles;
|
||||
}
|
||||
|
||||
if (oldVersion < 2.5) {
|
||||
// Default values for new canRezAvatarEntities permission.
|
||||
unpackPermissions();
|
||||
std::list<std::unordered_map<NodePermissionsKey, NodePermissionsPointer>> permissionsSets{
|
||||
_standardAgentPermissions.get(),
|
||||
_agentPermissions.get(),
|
||||
_ipPermissions.get(),
|
||||
_macPermissions.get(),
|
||||
_machineFingerprintPermissions.get(),
|
||||
_groupPermissions.get(),
|
||||
_groupForbiddens.get()
|
||||
};
|
||||
foreach (auto permissionsSet, permissionsSets) {
|
||||
for (auto entry : permissionsSet) {
|
||||
const auto& userKey = entry.first;
|
||||
if (permissionsSet[userKey]->can(NodePermissions::Permission::canConnectToDomain)) {
|
||||
permissionsSet[userKey]->set(NodePermissions::Permission::canRezAvatarEntities);
|
||||
}
|
||||
}
|
||||
}
|
||||
packPermissions();
|
||||
}
|
||||
|
||||
// write the current description version to our settings
|
||||
*versionVariant = _descriptionVersion;
|
||||
|
@ -1470,6 +1492,8 @@ QJsonObject DomainServerSettingsManager::settingsResponseObjectForType(const QSt
|
|||
SettingsBackupFlag settingsBackupFlag) {
|
||||
QJsonObject responseObject;
|
||||
|
||||
responseObject["version"] = _descriptionVersion; // Domain settings version number.
|
||||
|
||||
if (!typeValue.isEmpty() || authentication == Authenticated) {
|
||||
// convert the string type value to a QJsonValue
|
||||
QJsonValue queryType = typeValue.isEmpty() ? QJsonValue() : QJsonValue(typeValue.toInt());
|
||||
|
|
|
@ -518,7 +518,12 @@ Rectangle {
|
|||
glyphText: "\ue02e"
|
||||
|
||||
onClicked: {
|
||||
adjustWearables.open(currentAvatar);
|
||||
if (!AddressManager.isConnected || Entities.canRezAvatarEntities()) {
|
||||
adjustWearables.open(currentAvatar);
|
||||
} else {
|
||||
Window.alert("You cannot use wearables on this domain.")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,7 +534,11 @@ Rectangle {
|
|||
glyphText: wearablesFrozen ? hifi.glyphs.lock : hifi.glyphs.unlock;
|
||||
|
||||
onClicked: {
|
||||
emitSendToScript({'method' : 'toggleWearablesFrozen'});
|
||||
if (!AddressManager.isConnected || Entities.canRezAvatarEntities()) {
|
||||
emitSendToScript({'method' : 'toggleWearablesFrozen'});
|
||||
} else {
|
||||
Window.alert("You cannot use wearables on this domain.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1306,6 +1306,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
_entityServerConnectionTimer.setSingleShot(true);
|
||||
connect(&_entityServerConnectionTimer, &QTimer::timeout, this, &Application::setFailedToConnectToEntityServer);
|
||||
|
||||
connect(&domainHandler, &DomainHandler::confirmConnectWithoutAvatarEntities,
|
||||
this, &Application::confirmConnectWithoutAvatarEntities);
|
||||
|
||||
connect(&domainHandler, &DomainHandler::connectedToDomain, this, [this]() {
|
||||
if (!isServerlessMode()) {
|
||||
_entityServerConnectionTimer.setInterval(ENTITY_SERVER_ADDED_TIMEOUT);
|
||||
|
@ -9174,6 +9177,32 @@ void Application::setShowBulletConstraintLimits(bool value) {
|
|||
_physicsEngine->setShowBulletConstraintLimits(value);
|
||||
}
|
||||
|
||||
void Application::confirmConnectWithoutAvatarEntities() {
|
||||
|
||||
if (_confirmConnectWithoutAvatarEntitiesDialog) {
|
||||
// Dialog is already displayed.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getMyAvatar()->hasAvatarEntities()) {
|
||||
// No avatar entities so continue with login.
|
||||
DependencyManager::get<NodeList>()->getDomainHandler().setCanConnectWithoutAvatarEntities(true);
|
||||
return;
|
||||
}
|
||||
|
||||
QString continueMessage = "Your wearables will not display on this domain. Continue?";
|
||||
_confirmConnectWithoutAvatarEntitiesDialog = OffscreenUi::asyncQuestion("Continue Without Wearables", continueMessage,
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (_confirmConnectWithoutAvatarEntitiesDialog->getDialogItem()) {
|
||||
QObject::connect(_confirmConnectWithoutAvatarEntitiesDialog, &ModalDialogListener::response, this, [=](QVariant answer) {
|
||||
QObject::disconnect(_confirmConnectWithoutAvatarEntitiesDialog, &ModalDialogListener::response, this, nullptr);
|
||||
_confirmConnectWithoutAvatarEntitiesDialog = nullptr;
|
||||
bool shouldConnect = (static_cast<QMessageBox::StandardButton>(answer.toInt()) == QMessageBox::Yes);
|
||||
DependencyManager::get<NodeList>()->getDomainHandler().setCanConnectWithoutAvatarEntities(shouldConnect);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Application::createLoginDialog() {
|
||||
const glm::vec3 LOGIN_DIMENSIONS { 0.89f, 0.5f, 0.01f };
|
||||
const auto OFFSET = glm::vec2(0.7f, -0.1f);
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include <shared/FileLogger.h>
|
||||
#include <RunningMarker.h>
|
||||
#include <ModerationFlags.h>
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
#include "avatar/MyAvatar.h"
|
||||
#include "FancyCamera.h"
|
||||
|
@ -326,6 +327,8 @@ public:
|
|||
int getOtherAvatarsReplicaCount() { return DependencyManager::get<AvatarHashMap>()->getReplicaCount(); }
|
||||
void setOtherAvatarsReplicaCount(int count) { DependencyManager::get<AvatarHashMap>()->setReplicaCount(count); }
|
||||
|
||||
void confirmConnectWithoutAvatarEntities();
|
||||
|
||||
bool getLoginDialogPoppedUp() const { return _loginDialogPoppedUp; }
|
||||
void createLoginDialog();
|
||||
void updateLoginDialogPosition();
|
||||
|
@ -724,6 +727,8 @@ private:
|
|||
bool _loginDialogPoppedUp{ false };
|
||||
bool _desktopRootItemCreated{ false };
|
||||
|
||||
ModalDialogListener* _confirmConnectWithoutAvatarEntitiesDialog { nullptr };
|
||||
|
||||
bool _developerMenuVisible{ false };
|
||||
QString _previousAvatarSkeletonModel;
|
||||
float _previousAvatarTargetScale;
|
||||
|
|
|
@ -35,6 +35,7 @@ void ConnectionMonitor::init() {
|
|||
connect(&domainHandler, &DomainHandler::connectedToDomain, this, &ConnectionMonitor::stopTimer);
|
||||
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ConnectionMonitor::stopTimer);
|
||||
connect(&domainHandler, &DomainHandler::redirectToErrorDomainURL, this, &ConnectionMonitor::stopTimer);
|
||||
connect(&domainHandler, &DomainHandler::confirmConnectWithoutAvatarEntities, this, &ConnectionMonitor::stopTimer);
|
||||
connect(this, &ConnectionMonitor::setRedirectErrorState, &domainHandler, &DomainHandler::setRedirectErrorState);
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
connect(accountManager.data(), &AccountManager::loginComplete, this, &ConnectionMonitor::startTimer);
|
||||
|
|
|
@ -544,7 +544,7 @@ void AvatarManager::removeDeadAvatarEntities(const SetOfEntities& deadEntities)
|
|||
QUuid entityOwnerID = entity->getOwningAvatarID();
|
||||
AvatarSharedPointer avatar = getAvatarBySessionID(entityOwnerID);
|
||||
if (avatar) {
|
||||
avatar->clearAvatarEntity(entity->getID());
|
||||
avatar->clearAvatarEntityInternal(entity->getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -278,6 +278,9 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
// when we leave a domain we lift whatever restrictions that domain may have placed on our scale
|
||||
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &MyAvatar::leaveDomain);
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
connect(nodeList.data(), &NodeList::canRezAvatarEntitiesChanged, this, &MyAvatar::handleCanRezAvatarEntitiesChanged);
|
||||
|
||||
_bodySensorMatrix = deriveBodyFromHMDSensor();
|
||||
|
||||
using namespace recording;
|
||||
|
@ -365,12 +368,20 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
connect(&(_skeletonModel->getRig()), &Rig::onLoadFailed, this, &MyAvatar::onLoadFailed);
|
||||
|
||||
_characterController.setDensity(_density);
|
||||
|
||||
_addAvatarEntitiesToTreeTimer.setSingleShot(true);
|
||||
connect(&_addAvatarEntitiesToTreeTimer, &QTimer::timeout, [this] {
|
||||
addAvatarEntitiesToTree();
|
||||
});
|
||||
}
|
||||
|
||||
MyAvatar::~MyAvatar() {
|
||||
_lookAtTargetAvatar.reset();
|
||||
delete _scriptEngine;
|
||||
_scriptEngine = nullptr;
|
||||
if (_addAvatarEntitiesToTreeTimer.isActive()) {
|
||||
_addAvatarEntitiesToTreeTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
QString MyAvatar::getDominantHand() const {
|
||||
|
@ -1527,7 +1538,23 @@ void MyAvatar::storeAvatarEntityDataPayload(const QUuid& entityID, const QByteAr
|
|||
|
||||
void MyAvatar::clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree) {
|
||||
// NOTE: the requiresRemovalFromTree argument is unused
|
||||
AvatarData::clearAvatarEntity(entityID);
|
||||
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp) << "Ignoring clearAvatarEntity() because don't have canRezAvatarEntities permission on domain";
|
||||
return;
|
||||
}
|
||||
|
||||
clearAvatarEntityInternal(entityID);
|
||||
}
|
||||
|
||||
void MyAvatar::clearAvatarEntityInternal(const QUuid& entityID) {
|
||||
AvatarData::clearAvatarEntityInternal(entityID);
|
||||
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
// Don't delete potentially non-rezzed avatar entities from cache, otherwise they're removed from settings.
|
||||
return;
|
||||
}
|
||||
|
||||
_avatarEntitiesLock.withWriteLock([&] {
|
||||
_cachedAvatarEntityBlobsToDelete.push_back(entityID);
|
||||
});
|
||||
|
@ -1558,6 +1585,39 @@ void MyAvatar::sanitizeAvatarEntityProperties(EntityItemProperties& properties)
|
|||
properties.markAllChanged();
|
||||
}
|
||||
|
||||
void MyAvatar::addAvatarEntitiesToTree() {
|
||||
AvatarEntityMap::const_iterator constItr = _cachedAvatarEntityBlobs.begin();
|
||||
while (constItr != _cachedAvatarEntityBlobs.end()) {
|
||||
QUuid id = constItr.key();
|
||||
_entitiesToAdd.push_back(id); // worked once: hat shown. then unshown when permissions removed but then entity was deleted somewhere along the line!
|
||||
++constItr;
|
||||
}
|
||||
}
|
||||
|
||||
bool MyAvatar::hasAvatarEntities() const {
|
||||
return _cachedAvatarEntityBlobs.count() > 0;
|
||||
}
|
||||
|
||||
void MyAvatar::handleCanRezAvatarEntitiesChanged(bool canRezAvatarEntities) {
|
||||
if (canRezAvatarEntities) {
|
||||
// Start displaying avatar entities.
|
||||
// Allow time for the avatar mixer to be updated with the user's permissions so that it doesn't discard the avatar
|
||||
// entities sent. In theory, typical worst case would be Interface running on same PC as server and the timings of
|
||||
// Interface and the avatar mixer sending DomainListRequest to the domain server being such that the avatar sends its
|
||||
// DomainListRequest and gets its DomainList response DOMAIN_SERVER_CHECK_IN_MSECS after Interface does. Allow extra
|
||||
// time in case the avatar mixer is bogged down.
|
||||
_addAvatarEntitiesToTreeTimer.start(5 * DOMAIN_SERVER_CHECK_IN_MSECS); // Single-shot.
|
||||
} else {
|
||||
// Cancel any pending addAvatarEntitiesToTree() call.
|
||||
if (_addAvatarEntitiesToTreeTimer.isActive()) {
|
||||
_addAvatarEntitiesToTreeTimer.stop();
|
||||
}
|
||||
|
||||
// Stop displaying avatar entities.
|
||||
removeAvatarEntitiesFromTree();
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::handleChangedAvatarEntityData() {
|
||||
// NOTE: this is a per-frame update
|
||||
if (getID().isNull() ||
|
||||
|
@ -1577,6 +1637,8 @@ void MyAvatar::handleChangedAvatarEntityData() {
|
|||
return;
|
||||
}
|
||||
|
||||
bool canRezAvatarEntites = DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities();
|
||||
|
||||
// We collect changes to AvatarEntities and then handle them all in one spot per frame: handleChangedAvatarEntityData().
|
||||
// Basically this is a "transaction pattern" with an extra complication: these changes can come from two
|
||||
// "directions" and the "authoritative source" of each direction is different, so we maintain two distinct sets
|
||||
|
@ -1663,12 +1725,15 @@ void MyAvatar::handleChangedAvatarEntityData() {
|
|||
continue;
|
||||
}
|
||||
sanitizeAvatarEntityProperties(properties);
|
||||
entityTree->withWriteLock([&] {
|
||||
EntityItemPointer entity = entityTree->addEntity(id, properties);
|
||||
if (entity) {
|
||||
packetSender->queueEditAvatarEntityMessage(entityTree, id);
|
||||
}
|
||||
});
|
||||
if (canRezAvatarEntites) {
|
||||
entityTree->withWriteLock([&] {
|
||||
EntityItemPointer entity = entityTree->addEntity(id, properties);
|
||||
if (entity) {
|
||||
packetSender->queueEditAvatarEntityMessage(entityTree, id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// CHANGE real entities
|
||||
|
@ -1686,7 +1751,7 @@ void MyAvatar::handleChangedAvatarEntityData() {
|
|||
skip = true;
|
||||
}
|
||||
});
|
||||
if (!skip) {
|
||||
if (!skip && canRezAvatarEntites) {
|
||||
sanitizeAvatarEntityProperties(properties);
|
||||
entityTree->withWriteLock([&] {
|
||||
if (entityTree->updateEntity(id, properties)) {
|
||||
|
@ -1828,6 +1893,11 @@ AvatarEntityMap MyAvatar::getAvatarEntityData() const {
|
|||
return data;
|
||||
}
|
||||
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp) << "Ignoring getAvatarEntityData() because don't have canRezAvatarEntities permission on domain";
|
||||
return data;
|
||||
}
|
||||
|
||||
QList<QUuid> avatarEntityIDs;
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
avatarEntityIDs = _packedAvatarEntityData.keys();
|
||||
|
@ -1873,6 +1943,12 @@ void MyAvatar::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) {
|
|||
// avatarEntityData is expected to be a map of QByteArrays that represent EntityItemProperties objects from JavaScript,
|
||||
// aka: unfortunately-formatted-binary-blobs because we store them in non-human-readable format in Settings.
|
||||
//
|
||||
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp) << "Ignoring setAvatarEntityData() because don't have canRezAvatarEntities permission on domain";
|
||||
return;
|
||||
}
|
||||
|
||||
if (avatarEntityData.size() > MAX_NUM_AVATAR_ENTITIES) {
|
||||
// the data is suspect
|
||||
qCDebug(interfaceapp) << "discard suspect AvatarEntityData with size =" << avatarEntityData.size();
|
||||
|
@ -1933,6 +2009,12 @@ void MyAvatar::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) {
|
|||
|
||||
void MyAvatar::updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) {
|
||||
// NOTE: this is an invokable Script call
|
||||
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp) << "Ignoring updateAvatarEntity() because don't have canRezAvatarEntities permission on domain";
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
_avatarEntitiesLock.withWriteLock([&] {
|
||||
auto data = QJsonDocument::fromBinaryData(entityData);
|
||||
|
@ -2525,7 +2607,7 @@ void MyAvatar::removeWornAvatarEntity(const EntityItemID& entityID) {
|
|||
auto entity = entityTree->findEntityByID(entityID);
|
||||
if (entity && isWearableEntity(entity)) {
|
||||
treeRenderer->deleteEntity(entityID);
|
||||
clearAvatarEntity(entityID);
|
||||
clearAvatarEntityInternal(entityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2558,6 +2640,13 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() {
|
|||
QVariantList avatarEntitiesData;
|
||||
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
|
||||
|
||||
if (entityTree && !DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp)
|
||||
<< "Ignoring getAvatarEntitiesVariant() because don't have canRezAvatarEntities permission on domain";
|
||||
return avatarEntitiesData;
|
||||
}
|
||||
|
||||
if (entityTree) {
|
||||
QList<QUuid> avatarEntityIDs;
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
|
@ -2890,6 +2979,11 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
|
|||
);
|
||||
return;
|
||||
}
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp) << "Ignoring attach() because don't have canRezAvatarEntities permission on domain";
|
||||
return;
|
||||
}
|
||||
|
||||
AttachmentData data;
|
||||
data.modelURL = modelURL;
|
||||
data.jointName = jointName;
|
||||
|
@ -2911,6 +3005,11 @@ void MyAvatar::detachOne(const QString& modelURL, const QString& jointName) {
|
|||
);
|
||||
return;
|
||||
}
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp) << "Ignoring detachOne() because don't have canRezAvatarEntities permission on domain";
|
||||
return;
|
||||
}
|
||||
|
||||
QUuid entityID;
|
||||
if (findAvatarEntity(modelURL, jointName, entityID)) {
|
||||
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(entityID);
|
||||
|
@ -2926,6 +3025,11 @@ void MyAvatar::detachAll(const QString& modelURL, const QString& jointName) {
|
|||
);
|
||||
return;
|
||||
}
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp) << "Ignoring detachAll() because don't have canRezAvatarEntities permission on domain";
|
||||
return;
|
||||
}
|
||||
|
||||
QUuid entityID;
|
||||
while (findAvatarEntity(modelURL, jointName, entityID)) {
|
||||
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(entityID);
|
||||
|
@ -2939,6 +3043,11 @@ void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData)
|
|||
Q_ARG(const QVector<AttachmentData>&, attachmentData));
|
||||
return;
|
||||
}
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp) << "Ignoring setAttachmentData() because don't have canRezAvatarEntities permission on domain";
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<EntityItemProperties> newEntitiesProperties;
|
||||
for (auto& data : attachmentData) {
|
||||
QUuid entityID;
|
||||
|
@ -2961,6 +3070,12 @@ void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData)
|
|||
|
||||
QVector<AttachmentData> MyAvatar::getAttachmentData() const {
|
||||
QVector<AttachmentData> attachmentData;
|
||||
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp) << "Ignoring getAttachmentData() because don't have canRezAvatarEntities permission on domain";
|
||||
return attachmentData;
|
||||
}
|
||||
|
||||
QList<QUuid> avatarEntityIDs;
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
avatarEntityIDs = _packedAvatarEntityData.keys();
|
||||
|
@ -2975,6 +3090,13 @@ QVector<AttachmentData> MyAvatar::getAttachmentData() const {
|
|||
|
||||
QVariantList MyAvatar::getAttachmentsVariant() const {
|
||||
QVariantList result;
|
||||
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp)
|
||||
<< "Ignoring getAttachmentsVariant() because don't have canRezAvatarEntities permission on domain";
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const auto& attachment : getAttachmentData()) {
|
||||
result.append(attachment.toVariant());
|
||||
}
|
||||
|
@ -2987,6 +3109,13 @@ void MyAvatar::setAttachmentsVariant(const QVariantList& variant) {
|
|||
Q_ARG(const QVariantList&, variant));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(interfaceapp)
|
||||
<< "Ignoring setAttachmentsVariant() because don't have canRezAvatarEntities permission on domain";
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<AttachmentData> newAttachments;
|
||||
newAttachments.reserve(variant.size());
|
||||
for (const auto& attachmentVar : variant) {
|
||||
|
@ -4058,7 +4187,8 @@ float MyAvatar::getGravity() {
|
|||
void MyAvatar::setSessionUUID(const QUuid& sessionUUID) {
|
||||
QUuid oldSessionID = getSessionUUID();
|
||||
Avatar::setSessionUUID(sessionUUID);
|
||||
bool sendPackets = !DependencyManager::get<NodeList>()->getSessionUUID().isNull();
|
||||
bool sendPackets = !DependencyManager::get<NodeList>()->getSessionUUID().isNull()
|
||||
&& DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities();
|
||||
if (!sendPackets) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1454,6 +1454,7 @@ public:
|
|||
|
||||
void removeWornAvatarEntity(const EntityItemID& entityID);
|
||||
void clearWornAvatarEntities();
|
||||
bool hasAvatarEntities() const;
|
||||
|
||||
/**jsdoc
|
||||
* Checks whether your avatar is flying.
|
||||
|
@ -1939,6 +1940,8 @@ public:
|
|||
|
||||
void avatarEntityDataToJson(QJsonObject& root) const override;
|
||||
|
||||
void storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& payload) override;
|
||||
|
||||
/**jsdoc
|
||||
* @comment Uses the base class's JSDoc.
|
||||
*/
|
||||
|
@ -2277,12 +2280,6 @@ public slots:
|
|||
*/
|
||||
bool getEnableMeshVisible() const override;
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.storeAvatarEntityDataPayload
|
||||
* @deprecated This function is deprecated and will be removed.
|
||||
*/
|
||||
void storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& payload) override;
|
||||
|
||||
/**jsdoc
|
||||
* @comment Uses the base class's JSDoc.
|
||||
*/
|
||||
|
@ -2656,6 +2653,7 @@ private slots:
|
|||
|
||||
protected:
|
||||
void handleChangedAvatarEntityData();
|
||||
void handleCanRezAvatarEntitiesChanged(bool canRezAvatarEntities);
|
||||
virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override;
|
||||
virtual void forgetChild(SpatiallyNestablePointer newChild) const override;
|
||||
virtual void recalculateChildCauterization() const override;
|
||||
|
@ -2710,6 +2708,10 @@ private:
|
|||
void attachmentDataToEntityProperties(const AttachmentData& data, EntityItemProperties& properties);
|
||||
AttachmentData entityPropertiesToAttachmentData(const EntityItemProperties& properties) const;
|
||||
bool findAvatarEntity(const QString& modelURL, const QString& jointName, QUuid& entityID);
|
||||
void addAvatarEntitiesToTree();
|
||||
|
||||
// FIXME: Rename to clearAvatarEntity() once the API call is removed.
|
||||
void clearAvatarEntityInternal(const QUuid& entityID) override;
|
||||
|
||||
bool cameraInsideHead(const glm::vec3& cameraPosition) const;
|
||||
|
||||
|
@ -3107,6 +3109,8 @@ private:
|
|||
|
||||
glm::vec3 _cameraEyesOffset;
|
||||
float _landingAfterJumpTime { 0.0f };
|
||||
|
||||
QTimer _addAvatarEntitiesToTreeTimer;
|
||||
};
|
||||
|
||||
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
||||
|
|
|
@ -2250,7 +2250,7 @@ void AvatarData::processTraitInstance(AvatarTraits::TraitType traitType,
|
|||
|
||||
void AvatarData::processDeletedTraitInstance(AvatarTraits::TraitType traitType, AvatarTraits::TraitInstanceID instanceID) {
|
||||
if (traitType == AvatarTraits::AvatarEntity) {
|
||||
clearAvatarEntity(instanceID);
|
||||
clearAvatarEntityInternal(instanceID);
|
||||
} else if (traitType == AvatarTraits::Grab) {
|
||||
clearAvatarGrabData(instanceID);
|
||||
}
|
||||
|
@ -3038,6 +3038,10 @@ void AvatarData::updateAvatarEntity(const QUuid& entityID, const QByteArray& ent
|
|||
|
||||
void AvatarData::clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree) {
|
||||
// NOTE: requiresRemovalFromTree is unused
|
||||
clearAvatarEntityInternal(entityID);
|
||||
}
|
||||
|
||||
void AvatarData::clearAvatarEntityInternal(const QUuid& entityID) {
|
||||
bool removedEntity = false;
|
||||
_avatarEntitiesLock.withWriteLock([this, &removedEntity, &entityID] {
|
||||
removedEntity = _packedAvatarEntityData.remove(entityID);
|
||||
|
@ -3050,6 +3054,24 @@ void AvatarData::clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFr
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarData::clearAvatarEntities() {
|
||||
QList<QUuid> avatarEntityIDs;
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
avatarEntityIDs = _packedAvatarEntityData.keys();
|
||||
});
|
||||
for (const auto& entityID : avatarEntityIDs) {
|
||||
clearAvatarEntityInternal(entityID);
|
||||
}
|
||||
}
|
||||
|
||||
QList<QUuid> AvatarData::getAvatarEntityIDs() const {
|
||||
QList<QUuid> avatarEntityIDs;
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
avatarEntityIDs = _packedAvatarEntityData.keys();
|
||||
});
|
||||
return avatarEntityIDs;
|
||||
}
|
||||
|
||||
AvatarEntityMap AvatarData::getAvatarEntityData() const {
|
||||
// overridden where needed
|
||||
// NOTE: the return value is expected to be a map of unfortunately-formatted-binary-blobs
|
||||
|
|
|
@ -1186,6 +1186,13 @@ public:
|
|||
* @deprecated This function is deprecated and will be removed.
|
||||
*/
|
||||
Q_INVOKABLE virtual void clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree = true);
|
||||
|
||||
// FIXME: Rename to clearAvatarEntity() once the API call is removed.
|
||||
virtual void clearAvatarEntityInternal(const QUuid& entityID);
|
||||
|
||||
void clearAvatarEntities();
|
||||
|
||||
QList<QUuid> getAvatarEntityIDs() const;
|
||||
|
||||
/**jsdoc
|
||||
* Enables blend shapes set using {@link Avatar.setBlendshape} or {@link MyAvatar.setBlendshape} to be transmitted to other
|
||||
|
|
|
@ -57,6 +57,7 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership
|
|||
connect(nodeList.data(), &NodeList::canRezTmpCertifiedChanged, this, &EntityScriptingInterface::canRezTmpCertifiedChanged);
|
||||
connect(nodeList.data(), &NodeList::canWriteAssetsChanged, this, &EntityScriptingInterface::canWriteAssetsChanged);
|
||||
connect(nodeList.data(), &NodeList::canGetAndSetPrivateUserDataChanged, this, &EntityScriptingInterface::canGetAndSetPrivateUserDataChanged);
|
||||
connect(nodeList.data(), &NodeList::canRezAvatarEntitiesChanged, this, &EntityScriptingInterface::canRezAvatarEntitiesChanged);
|
||||
|
||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::EntityScriptCallMethod,
|
||||
|
@ -114,6 +115,11 @@ bool EntityScriptingInterface::canGetAndSetPrivateUserData() {
|
|||
return nodeList->getThisNodeCanGetAndSetPrivateUserData();
|
||||
}
|
||||
|
||||
bool EntityScriptingInterface::canRezAvatarEntities() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
return nodeList->getThisNodeCanRezAvatarEntities();
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) {
|
||||
if (_entityTree) {
|
||||
disconnect(_entityTree.get(), &EntityTree::addingEntityPointer, this, &EntityScriptingInterface::onAddingEntity);
|
||||
|
@ -481,6 +487,15 @@ QUuid EntityScriptingInterface::addEntityInternal(const EntityItemProperties& pr
|
|||
|
||||
_activityTracking.addedEntityCount++;
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (entityHostType == entity::HostType::AVATAR && !nodeList->getThisNodeCanRezAvatarEntities()) {
|
||||
qCDebug(entities) << "Ignoring addEntity() because don't have canRezAvatarEntities permission on domain";
|
||||
// Only need to intercept methods that may add an avatar entity because avatar entities are removed from the tree when
|
||||
// the user doesn't have canRezAvatarEntities permission.
|
||||
return QUuid();
|
||||
}
|
||||
|
||||
EntityItemProperties propertiesWithSimID = properties;
|
||||
propertiesWithSimID.setEntityHostType(entityHostType);
|
||||
if (entityHostType == entity::HostType::AVATAR) {
|
||||
|
@ -493,7 +508,6 @@ QUuid EntityScriptingInterface::addEntityInternal(const EntityItemProperties& pr
|
|||
}
|
||||
|
||||
// the created time will be set in EntityTree::addEntity by recordCreationTime()
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto sessionID = nodeList->getSessionUUID();
|
||||
propertiesWithSimID.setLastEditedBy(sessionID);
|
||||
|
||||
|
@ -1002,7 +1016,7 @@ void EntityScriptingInterface::deleteEntity(const QUuid& id) {
|
|||
|
||||
for (auto entity : entitiesToDeleteImmediately) {
|
||||
if (entity->isMyAvatarEntity()) {
|
||||
getEntityPacketSender()->getMyAvatar()->clearAvatarEntity(entity->getID(), false);
|
||||
getEntityPacketSender()->getMyAvatar()->clearAvatarEntityInternal(entity->getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -289,6 +289,14 @@ public slots:
|
|||
* <code>privateUserData</code> property of entities, otherwise <code>false</code>.
|
||||
*/
|
||||
Q_INVOKABLE bool canGetAndSetPrivateUserData();
|
||||
|
||||
/**jsdoc
|
||||
* Checks whether or not the script can rez avatar entities.
|
||||
* @function Entities.canRezAvatarEntities
|
||||
* @returns {boolean} <code>true</code> if the domain server will allow the script to rez avatar entities,
|
||||
* otherwise <code>false</code>.
|
||||
*/
|
||||
Q_INVOKABLE bool canRezAvatarEntities();
|
||||
|
||||
/**jsdoc
|
||||
* <p>How an entity is hosted and sent to others for display.</p>
|
||||
|
@ -2255,11 +2263,20 @@ signals:
|
|||
/**jsdoc
|
||||
* Triggered when your ability to get and set private user data changes.
|
||||
* @function Entities.canGetAndSetPrivateUserDataChanged
|
||||
* @param {boolean} canGetAndSetPrivateUserData - <code>true</code> if the script change the <code>privateUserData</code>
|
||||
* @param {boolean} canGetAndSetPrivateUserData - <code>true</code> if the script can change the <code>privateUserData</code>
|
||||
* property of an entity, <code>false</code> if it can't.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void canGetAndSetPrivateUserDataChanged(bool canGetAndSetPrivateUserData);
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when your ability to use avatar entities is changed.
|
||||
* @function Entities.canRezAvatarEntitiesChanged
|
||||
* @param {boolean} canRezAvatarEntities - <code>true</code> if the script can change edit avatar entities,
|
||||
* <code>false</code> if it can't.
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void canRezAvatarEntitiesChanged(bool canRezAvatarEntities);
|
||||
|
||||
|
||||
/**jsdoc
|
||||
|
|
|
@ -415,6 +415,8 @@ void AddressManager::handleLookupString(const QString& lookupString, bool fromSu
|
|||
|
||||
QString sanitizedString = lookupString.trimmed();
|
||||
if (!sanitizedString.isEmpty()) {
|
||||
resetConfirmConnectWithoutAvatarEntities();
|
||||
|
||||
// make this a valid hifi URL and handle it off to handleUrl
|
||||
handleUrl(sanitizedString, fromSuggestions ? Suggestions : UserInput);
|
||||
}
|
||||
|
@ -874,6 +876,11 @@ bool AddressManager::setDomainInfo(const QUrl& domainURL, LookupTrigger trigger)
|
|||
return emitHostChanged;
|
||||
}
|
||||
|
||||
void AddressManager::goToEntry(LookupTrigger trigger) {
|
||||
resetConfirmConnectWithoutAvatarEntities();
|
||||
handleUrl(DEFAULT_VIRCADIA_ADDRESS, trigger);
|
||||
}
|
||||
|
||||
void AddressManager::goToUser(const QString& username, bool shouldMatchOrientation) {
|
||||
QString formattedUsername = QUrl::toPercentEncoding(username);
|
||||
|
||||
|
@ -890,6 +897,11 @@ void AddressManager::goToUser(const QString& username, bool shouldMatchOrientati
|
|||
QByteArray(), nullptr, requestParams);
|
||||
}
|
||||
|
||||
void AddressManager::goToLastAddress() {
|
||||
resetConfirmConnectWithoutAvatarEntities();
|
||||
handleUrl(_lastVisitedURL, LookupTrigger::AttemptedRefresh);
|
||||
}
|
||||
|
||||
bool AddressManager::canGoBack() const {
|
||||
return (_backStack.size() > 0);
|
||||
}
|
||||
|
@ -1024,3 +1036,10 @@ QString AddressManager::getPlaceName() const {
|
|||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void AddressManager::resetConfirmConnectWithoutAvatarEntities() {
|
||||
DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||
if (!domainHandler.isConnected()) {
|
||||
domainHandler.resetConfirmConnectWithoutAvatarEntities();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -301,9 +301,7 @@ public slots:
|
|||
* @param {location.LookupTrigger} trigger=StartupFromSettings - The reason for the function call. Helps ensure that user's
|
||||
* location history is correctly maintained.
|
||||
*/
|
||||
void goToEntry(LookupTrigger trigger = LookupTrigger::StartupFromSettings) {
|
||||
handleUrl(DEFAULT_VIRCADIA_ADDRESS, trigger);
|
||||
}
|
||||
void goToEntry(LookupTrigger trigger = LookupTrigger::StartupFromSettings);
|
||||
|
||||
/**jsdoc
|
||||
* Takes you to the specified user's location.
|
||||
|
@ -318,7 +316,7 @@ public slots:
|
|||
* Takes you to the last address tried. This will be the last URL tried from <code>location.handleLookupString</code>.
|
||||
* @function location.goToLastAddress
|
||||
*/
|
||||
void goToLastAddress() { handleUrl(_lastVisitedURL, LookupTrigger::AttemptedRefresh); }
|
||||
void goToLastAddress();
|
||||
|
||||
/**jsdoc
|
||||
* Checks if going back to the previous location is possible.
|
||||
|
@ -527,6 +525,8 @@ private:
|
|||
|
||||
void addCurrentAddressToHistory(LookupTrigger trigger);
|
||||
|
||||
void resetConfirmConnectWithoutAvatarEntities();
|
||||
|
||||
QUrl _domainURL;
|
||||
QUrl _lastVisitedURL;
|
||||
|
||||
|
|
|
@ -126,6 +126,8 @@ void DomainHandler::hardReset(QString reason) {
|
|||
emit resetting();
|
||||
|
||||
softReset(reason);
|
||||
_haveAskedConnectWithoutAvatarEntities = false;
|
||||
_canConnectWithoutAvatarEntities = false;
|
||||
_isInErrorState = false;
|
||||
emit redirectErrorStateChanged(_isInErrorState);
|
||||
|
||||
|
@ -364,10 +366,14 @@ void DomainHandler::setIsConnected(bool isConnected) {
|
|||
_lastDomainConnectionError = -1;
|
||||
emit connectedToDomain(_domainURL);
|
||||
|
||||
// FIXME: Reinstate the requestDomainSettings() call here in version 2021.2.0 instead of having it in
|
||||
// NodeList::processDomainServerList().
|
||||
/*
|
||||
if (_domainURL.scheme() == URL_SCHEME_HIFI && !_domainURL.host().isEmpty()) {
|
||||
// we've connected to new domain - time to ask it for global settings
|
||||
requestDomainSettings();
|
||||
}
|
||||
*/
|
||||
|
||||
} else {
|
||||
emit disconnectedFromDomain();
|
||||
|
@ -375,6 +381,24 @@ void DomainHandler::setIsConnected(bool isConnected) {
|
|||
}
|
||||
}
|
||||
|
||||
void DomainHandler::setCanConnectWithoutAvatarEntities(bool canConnect) {
|
||||
_canConnectWithoutAvatarEntities = canConnect;
|
||||
_haveAskedConnectWithoutAvatarEntities = true;
|
||||
}
|
||||
|
||||
bool DomainHandler::canConnectWithoutAvatarEntities() {
|
||||
if (!_canConnectWithoutAvatarEntities && !_haveAskedConnectWithoutAvatarEntities) {
|
||||
if (_isConnected) {
|
||||
// Already connected so don't ask. (Permission removed from user while in the domain.)
|
||||
setCanConnectWithoutAvatarEntities(true);
|
||||
} else {
|
||||
// Ask whether to connect to the domain.
|
||||
emit confirmConnectWithoutAvatarEntities();
|
||||
}
|
||||
}
|
||||
return _canConnectWithoutAvatarEntities;
|
||||
}
|
||||
|
||||
void DomainHandler::connectedToServerless(std::map<QString, QString> namedPaths) {
|
||||
_namedPaths = namedPaths;
|
||||
setIsConnected(true);
|
||||
|
|
|
@ -98,6 +98,7 @@ public:
|
|||
Node::LocalID getLocalID() const { return _localID; }
|
||||
void setLocalID(Node::LocalID localID) { _localID = localID; }
|
||||
|
||||
QString getScheme() const { return _domainURL.scheme(); }
|
||||
QString getHostname() const { return _domainURL.host(); }
|
||||
|
||||
QUrl getErrorDomainURL(){ return _errorDomainURL; }
|
||||
|
@ -133,6 +134,9 @@ public:
|
|||
bool isConnected() const { return _isConnected; }
|
||||
void setIsConnected(bool isConnected);
|
||||
|
||||
void setCanConnectWithoutAvatarEntities(bool canConnect);
|
||||
bool canConnectWithoutAvatarEntities();
|
||||
|
||||
bool isServerless() const { return _domainURL.scheme() != URL_SCHEME_HIFI; }
|
||||
bool getInterstitialModeEnabled() const;
|
||||
void setInterstitialModeEnabled(bool enableInterstitialMode);
|
||||
|
@ -159,6 +163,10 @@ public:
|
|||
bool checkInPacketTimeout();
|
||||
void clearPendingCheckins() { _checkInPacketsSinceLastReply = 0; }
|
||||
|
||||
void resetConfirmConnectWithoutAvatarEntities() {
|
||||
_haveAskedConnectWithoutAvatarEntities = false;
|
||||
}
|
||||
|
||||
/**jsdoc
|
||||
* <p>The reasons that you may be refused connection to a domain are defined by numeric values:</p>
|
||||
* <table>
|
||||
|
@ -252,6 +260,7 @@ signals:
|
|||
void completedSocketDiscovery();
|
||||
|
||||
void resetting();
|
||||
void confirmConnectWithoutAvatarEntities();
|
||||
void connectedToDomain(QUrl domainURL);
|
||||
void disconnectedFromDomain();
|
||||
|
||||
|
@ -287,6 +296,8 @@ private:
|
|||
HifiSockAddr _iceServerSockAddr;
|
||||
NetworkPeer _icePeer;
|
||||
bool _isConnected { false };
|
||||
bool _haveAskedConnectWithoutAvatarEntities { false };
|
||||
bool _canConnectWithoutAvatarEntities { false };
|
||||
bool _isInErrorState { false };
|
||||
QJsonObject _settingsObject;
|
||||
QString _pendingPath;
|
||||
|
|
|
@ -198,6 +198,10 @@ void LimitedNodeList::setPermissions(const NodePermissions& newPermissions) {
|
|||
newPermissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData)) {
|
||||
emit canGetAndSetPrivateUserDataChanged(_permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData));
|
||||
}
|
||||
if (originalPermissions.can(NodePermissions::Permission::canRezAvatarEntities) !=
|
||||
newPermissions.can(NodePermissions::Permission::canRezAvatarEntities)) {
|
||||
emit canRezAvatarEntitiesChanged(_permissions.can(NodePermissions::Permission::canRezAvatarEntities));
|
||||
}
|
||||
}
|
||||
|
||||
void LimitedNodeList::setSocketLocalPort(quint16 socketLocalPort) {
|
||||
|
|
|
@ -133,6 +133,7 @@ public:
|
|||
bool getThisNodeCanKick() const { return _permissions.can(NodePermissions::Permission::canKick); }
|
||||
bool getThisNodeCanReplaceContent() const { return _permissions.can(NodePermissions::Permission::canReplaceDomainContent); }
|
||||
bool getThisNodeCanGetAndSetPrivateUserData() const { return _permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData); }
|
||||
bool getThisNodeCanRezAvatarEntities() const { return _permissions.can(NodePermissions::Permission::canRezAvatarEntities); }
|
||||
|
||||
quint16 getSocketLocalPort() const { return _nodeSocket.localPort(); }
|
||||
Q_INVOKABLE void setSocketLocalPort(quint16 socketLocalPort);
|
||||
|
@ -390,6 +391,7 @@ signals:
|
|||
void canKickChanged(bool canKick);
|
||||
void canReplaceContentChanged(bool canReplaceContent);
|
||||
void canGetAndSetPrivateUserDataChanged(bool canGetAndSetPrivateUserData);
|
||||
void canRezAvatarEntitiesChanged(bool canRezAvatarEntities);
|
||||
|
||||
protected slots:
|
||||
void connectedForLocalSocketTest();
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
bool getCanKick() const { return _permissions.can(NodePermissions::Permission::canKick); }
|
||||
bool getCanReplaceContent() const { return _permissions.can(NodePermissions::Permission::canReplaceDomainContent); }
|
||||
bool getCanGetAndSetPrivateUserData() const { return _permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData); }
|
||||
bool getCanRezAvatarEntities() const { return _permissions.can(NodePermissions::Permission::canRezAvatarEntities); }
|
||||
|
||||
using NodesIgnoredPair = std::pair<std::vector<QUuid>, bool>;
|
||||
|
||||
|
|
|
@ -95,6 +95,12 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort)
|
|||
// send a ping punch immediately
|
||||
connect(&_domainHandler, &DomainHandler::icePeerSocketsReceived, this, &NodeList::pingPunchForDomainServer);
|
||||
|
||||
// FIXME: Can remove this temporary work-around in version 2021.2.0. (New protocol version implies a domain server upgrade.)
|
||||
// Adjust our canRezAvatarEntities permissions on older domains that do not have this setting.
|
||||
// DomainServerList and DomainSettings packets can come in either order so need to adjust with both occurrences.
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
connect(&_domainHandler, &DomainHandler::settingsReceived, this, &NodeList::adjustCanRezAvatarEntitiesPerSettings);
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
// assume that we may need to send a new DS check in anytime a new keypair is generated
|
||||
|
@ -727,6 +733,11 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
|
|||
// pull the permissions/right/privileges for this node out of the stream
|
||||
NodePermissions newPermissions;
|
||||
packetStream >> newPermissions;
|
||||
// FIXME: Can remove this temporary work-around in version 2021.2.0. (New protocol version implies a domain server upgrade.)
|
||||
// Adjust our canRezAvatarEntities permissions on older domains that do not have this setting.
|
||||
// DomainServerList and DomainSettings packets can come in either order so need to adjust with both occurrences.
|
||||
bool adjustedPermissions = adjustCanRezAvatarEntitiesPermissions(_domainHandler.getSettingsObject(), newPermissions, false);
|
||||
|
||||
// Is packet authentication enabled?
|
||||
bool isAuthenticated;
|
||||
packetStream >> isAuthenticated;
|
||||
|
@ -782,7 +793,7 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
|
|||
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveDSList);
|
||||
|
||||
if (_domainHandler.isConnected() && _domainHandler.getUUID() != domainUUID) {
|
||||
// Recieved packet from different domain.
|
||||
// Received packet from different domain.
|
||||
qWarning() << "IGNORING DomainList packet from" << domainUUID << "while connected to"
|
||||
<< _domainHandler.getUUID() << ": sent " << pingLagTime << " msec ago.";
|
||||
qWarning(networking) << "DomainList request lag (interface->ds): " << domainServerRequestLag << "msec";
|
||||
|
@ -810,6 +821,23 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
|
|||
setSessionLocalID(newLocalID);
|
||||
setSessionUUID(newUUID);
|
||||
|
||||
// FIXME: Remove this call to requestDomainSettings() and reinstate the one in DomainHandler::setIsConnected(), in version
|
||||
// 2021.2.0. (New protocol version implies a domain server upgrade.)
|
||||
if (!_domainHandler.isConnected()
|
||||
&& _domainHandler.getScheme() == URL_SCHEME_HIFI && !_domainHandler.getHostname().isEmpty()) {
|
||||
// We're about to connect but we need the domain settings (in particular, the node permissions) in order to adjust the
|
||||
// canRezAvatarEntities permission above before using the permissions in determining whether or not to connect without
|
||||
// avatar entities rezzing below.
|
||||
_domainHandler.requestDomainSettings();
|
||||
}
|
||||
|
||||
// Don't continue login to the domain if have avatar entities and don't have permissions to rez them, unless user has OKed
|
||||
// continuing login.
|
||||
if (!newPermissions.can(NodePermissions::Permission::canRezAvatarEntities)
|
||||
&& (!adjustedPermissions || !_domainHandler.canConnectWithoutAvatarEntities())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if this was the first domain-server list from this domain, we've now connected
|
||||
if (!_domainHandler.isConnected()) {
|
||||
_domainHandler.setLocalID(domainLocalID);
|
||||
|
@ -1371,3 +1399,35 @@ void NodeList::setRequestsDomainListData(bool isRequesting) {
|
|||
void NodeList::startThread() {
|
||||
moveToNewNamedThread(this, "NodeList Thread", QThread::TimeCriticalPriority);
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Can remove this work-around in version 2021.2.0. (New protocol version implies a domain server upgrade.)
|
||||
bool NodeList::adjustCanRezAvatarEntitiesPermissions(const QJsonObject& domainSettingsObject,
|
||||
NodePermissions& permissions, bool notify) {
|
||||
|
||||
if (domainSettingsObject.isEmpty()) {
|
||||
// Don't have enough information to adjust yet.
|
||||
return false; // Failed to adjust.
|
||||
}
|
||||
|
||||
const double CANREZAVATARENTITIES_INTRODUCED_VERSION = 2.5;
|
||||
auto version = domainSettingsObject.value("version");
|
||||
if (version.isUndefined() || version.isDouble() && version.toDouble() < CANREZAVATARENTITIES_INTRODUCED_VERSION) {
|
||||
// On domains without the canRezAvatarEntities permission available, set it to the same as canConnectToDomain.
|
||||
if (permissions.can(NodePermissions::Permission::canConnectToDomain)) {
|
||||
if (!permissions.can(NodePermissions::Permission::canRezAvatarEntities)) {
|
||||
permissions.set(NodePermissions::Permission::canRezAvatarEntities);
|
||||
if (notify) {
|
||||
emit canRezAvatarEntitiesChanged(permissions.can(NodePermissions::Permission::canRezAvatarEntities));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true; // Successfully adjusted.
|
||||
}
|
||||
|
||||
// FIXME: Can remove this work-around in version 2021.2.0. (New protocol version implies a domain server upgrade.)
|
||||
void NodeList::adjustCanRezAvatarEntitiesPerSettings(const QJsonObject& domainSettingsObject) {
|
||||
adjustCanRezAvatarEntitiesPermissions(domainSettingsObject, _permissions, true);
|
||||
}
|
||||
|
|
|
@ -123,6 +123,11 @@ public slots:
|
|||
|
||||
void processUsernameFromIDReply(QSharedPointer<ReceivedMessage> message);
|
||||
|
||||
// FIXME: Can remove these work-arounds in version 2021.2.0. (New protocol version implies a domain server upgrade.)
|
||||
bool adjustCanRezAvatarEntitiesPermissions(const QJsonObject& domainSettingsObject, NodePermissions& permissions,
|
||||
bool notify);
|
||||
void adjustCanRezAvatarEntitiesPerSettings(const QJsonObject& domainSettingsObject);
|
||||
|
||||
#if (PR_BUILD || DEV_BUILD)
|
||||
void toggleSendNewerDSConnectVersion(bool shouldSendNewerVersion) { _shouldSendNewerVersion = shouldSendNewerVersion; }
|
||||
#endif
|
||||
|
|
|
@ -57,6 +57,7 @@ NodePermissions::NodePermissions(QMap<QString, QVariant> perms) {
|
|||
|
||||
permissions = NodePermissions::Permissions();
|
||||
permissions |= perms["id_can_connect"].toBool() ? Permission::canConnectToDomain : Permission::none;
|
||||
permissions |= perms["id_can_rez_avatar_entities"].toBool() ? Permission::canRezAvatarEntities : Permission::none;
|
||||
permissions |= perms["id_can_adjust_locks"].toBool() ? Permission::canAdjustLocks : Permission::none;
|
||||
permissions |= perms["id_can_rez"].toBool() ? Permission::canRezPermanentEntities : Permission::none;
|
||||
permissions |= perms["id_can_rez_tmp"].toBool() ? Permission::canRezTemporaryEntities : Permission::none;
|
||||
|
@ -67,7 +68,8 @@ NodePermissions::NodePermissions(QMap<QString, QVariant> perms) {
|
|||
Permission::canConnectPastMaxCapacity : Permission::none;
|
||||
permissions |= perms["id_can_kick"].toBool() ? Permission::canKick : Permission::none;
|
||||
permissions |= perms["id_can_replace_content"].toBool() ? Permission::canReplaceDomainContent : Permission::none;
|
||||
permissions |= perms["id_can_get_and_set_private_user_data"].toBool() ? Permission::canGetAndSetPrivateUserData : Permission::none;
|
||||
permissions |= perms["id_can_get_and_set_private_user_data"].toBool() ?
|
||||
Permission::canGetAndSetPrivateUserData : Permission::none;
|
||||
}
|
||||
|
||||
QVariant NodePermissions::toVariant(QHash<QUuid, GroupRank> groupRanks) {
|
||||
|
@ -86,6 +88,7 @@ QVariant NodePermissions::toVariant(QHash<QUuid, GroupRank> groupRanks) {
|
|||
}
|
||||
}
|
||||
values["id_can_connect"] = can(Permission::canConnectToDomain);
|
||||
values["id_can_rez_avatar_entities"] = can(Permission::canRezAvatarEntities);
|
||||
values["id_can_adjust_locks"] = can(Permission::canAdjustLocks);
|
||||
values["id_can_rez"] = can(Permission::canRezPermanentEntities);
|
||||
values["id_can_rez_tmp"] = can(Permission::canRezTemporaryEntities);
|
||||
|
@ -141,6 +144,9 @@ QDebug operator<<(QDebug debug, const NodePermissions& perms) {
|
|||
if (perms.can(NodePermissions::Permission::canConnectToDomain)) {
|
||||
debug << " connect";
|
||||
}
|
||||
if (perms.can(NodePermissions::Permission::canRezAvatarEntities)) {
|
||||
debug << " rez-avatar-entities";
|
||||
}
|
||||
if (perms.can(NodePermissions::Permission::canAdjustLocks)) {
|
||||
debug << " locks";
|
||||
}
|
||||
|
@ -174,6 +180,7 @@ QDebug operator<<(QDebug debug, const NodePermissions& perms) {
|
|||
debug.nospace() << "]";
|
||||
return debug.nospace();
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const NodePermissionsPointer& perms) {
|
||||
if (perms) {
|
||||
return operator<<(debug, *perms.get());
|
||||
|
|
|
@ -80,7 +80,8 @@ public:
|
|||
canReplaceDomainContent = 128,
|
||||
canRezPermanentCertifiedEntities = 256,
|
||||
canRezTemporaryCertifiedEntities = 512,
|
||||
canGetAndSetPrivateUserData = 1024
|
||||
canGetAndSetPrivateUserData = 1024,
|
||||
canRezAvatarEntities = 2048
|
||||
};
|
||||
Q_DECLARE_FLAGS(Permissions, Permission)
|
||||
Permissions permissions;
|
||||
|
|
Loading…
Reference in a new issue