diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index c685198921..fe83f93cd3 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -297,6 +297,27 @@ void AvatarMixerClientData::processSetTraitsMessage(ReceivedMessage& message, } } +void AvatarMixerClientData::emulateDeleteEntitiesTraitsMessage(QList& 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, this provides a back-up. + + for (const auto& entityID : avatarEntityIDs) { + auto traitType = AvatarTraits::AvatarEntity; + 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. + 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. diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 98c8d7e15b..1e2e4518d4 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -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(QList& avatarEntityIDs); void processBulkAvatarTraitsAckMessage(ReceivedMessage& message); void checkSkeletonURLAgainstWhitelist(const SlaveSharedData& slaveSharedData, Node& sendingNode, AvatarTraits::TraitVersion traitVersion); diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index b253aaf437..9a3ef3d0b5 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -432,10 +432,14 @@ 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(sourceAvatarNode->getLinkedData()); - sourceAvatarNodeData->getAvatar().clearAvatarEntities(); + auto avatarEntityIDs = sourceAvatarNodeData->getAvatar().getAvatarEntityIDs(); + if (avatarEntityIDs.count() > 0) { + sourceAvatarNodeData->emulateDeleteEntitiesTraitsMessage(avatarEntityIDs); + } } } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 9308ccba84..234cc67c72 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -3056,6 +3056,14 @@ void AvatarData::clearAvatarEntities() { } } +QList AvatarData::getAvatarEntityIDs() const { + QList 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 diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 758d90b4a6..fffe8460f1 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1189,6 +1189,8 @@ public: void clearAvatarEntities(); + QList getAvatarEntityIDs() const; + /**jsdoc * Enables blend shapes set using {@link Avatar.setBlendshape} or {@link MyAvatar.setBlendshape} to be transmitted to other * users so that they can see the animation of your avatar's face.