diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a59560860d..582bf1aea7 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1513,6 +1513,7 @@ void MyAvatar::sanitizeAvatarEntityProperties(EntityItemProperties& properties) } void MyAvatar::updateAvatarEntities() { + // NOTE: this is a per-frame update if (getID().isNull() || getID() == AVATAR_SELF_ID || DependencyManager::get()->getSessionUUID() == QUuid()) { @@ -1765,16 +1766,25 @@ AvatarEntityMap MyAvatar::getAvatarEntityData() const { } void MyAvatar::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) { - // NOTE: the argument is expected to be a map of unfortunately-formatted-binary-blobs + // Note: this is an invokable Script call + // The argument 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 (avatarEntityData.size() > MAX_NUM_AVATAR_ENTITIES) { // the data is suspect qCDebug(interfaceapp) << "discard suspect AvatarEntityData with size =" << avatarEntityData.size(); return; } - if (!avatarEntityData.empty() && !_cachedAvatarEntityBlobs.empty()) { - _needToSaveAvatarEntitySettings = true; - } + // this overwrites ALL AvatarEntityData so we clear pending operations + _avatarEntitiesLock.withWriteLock([&] { + _packedAvatarEntityData.clear(); + _entitiesToDelete.clear(); + _entitiesToAdd.clear(); + _entitiesToUpdate.clear(); + }); + _needToSaveAvatarEntitySettings = true; + _avatarEntitiesLock.withWriteLock([&] { // find new and updated IDs AvatarEntityMap::const_iterator constItr = avatarEntityData.begin(); @@ -1821,6 +1831,23 @@ void MyAvatar::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) { }); } +void MyAvatar::updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) { + // NOTE: this is an invokable Script call + // TODO: we should handle the case where entityData is corrupt or invalid + // BEFORE we store into _cachedAvatarEntityBlobs + _needToSaveAvatarEntitySettings = true; + _avatarEntitiesLock.withWriteLock([&] { + AvatarEntityMap::iterator itr = _cachedAvatarEntityBlobs.find(entityID); + if (itr != _cachedAvatarEntityBlobs.end()) { + _entitiesToUpdate.push_back(entityID); + itr.value() = entityData; + } else { + _entitiesToAdd.push_back(entityID); + _cachedAvatarEntityBlobs.insert(entityID, entityData); + } + }); +} + void MyAvatar::avatarEntityDataToJson(QJsonObject& root) const { _avatarEntitiesLock.withReadLock([&] { if (!_cachedAvatarEntityBlobs.empty()) { @@ -1879,6 +1906,7 @@ void MyAvatar::loadData() { } void MyAvatar::loadAvatarEntityDataFromSettings() { + // this overwrites ALL AvatarEntityData so we clear pending operations _avatarEntitiesLock.withWriteLock([&] { _packedAvatarEntityData.clear(); _entitiesToDelete.clear(); @@ -1886,6 +1914,7 @@ void MyAvatar::loadAvatarEntityDataFromSettings() { _entitiesToUpdate.clear(); }); _reloadAvatarEntityDataFromSettings = false; + _needToSaveAvatarEntitySettings = false; int numEntities = _avatarEntityCountSetting.get(0); if (numEntities == 0) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 3804df977e..44f0c29b0b 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1210,6 +1210,7 @@ public: AvatarEntityMap getAvatarEntityData() const override; void setAvatarEntityData(const AvatarEntityMap& avatarEntityData) override; + void updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) override; void avatarEntityDataToJson(QJsonObject& root) const override; public slots: diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index e0f2b02d51..4f50333505 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -2766,7 +2766,7 @@ void AvatarData::storeAvatarEntityDataPayload(const QUuid& entityID, const QByte void AvatarData::updateAvatarEntity(const QUuid& entityID, const QByteArray& entityData) { // overridden where needed - // NOTE: expects 'data' to be an unfortunately-formatted-binary-blob + // expects 'entityData' to be a JavaScript EntityItemProperties Object in QByteArray form } void AvatarData::clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFromTree) {