diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 4e3e539dea..e2d5b648bb 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -144,9 +144,16 @@ void AvatarBookmarks::removeBookmark(const QString& bookmarkName) { emit bookmarkDeleted(bookmarkName); } +bool isWearableEntity(const EntityItemPointer& entity) { + return entity->isVisible() && entity->getParentJointIndex() != INVALID_JOINT_INDEX && entity->getParentID() == DependencyManager::get()->getSessionUUID(); +} + void AvatarBookmarks::updateAvatarEntities(const QVariantList &avatarEntities) { auto myAvatar = DependencyManager::get()->getMyAvatar(); - myAvatar->removeAvatarEntities(); + myAvatar->removeAvatarEntities([&](const EntityTreePointer& entityTree, const QUuid& entityID) { + auto entity = entityTree->findEntityByID(entityID); + return entity && isWearableEntity(entity); + }); addAvatarEntities(avatarEntities); } @@ -163,7 +170,10 @@ void AvatarBookmarks::loadBookmark(const QString& bookmarkName) { QVariantMap bookmark = bookmarkEntry.value().toMap(); if (!bookmark.empty()) { auto myAvatar = DependencyManager::get()->getMyAvatar(); - myAvatar->removeAvatarEntities(); + myAvatar->removeAvatarEntities([&](const EntityTreePointer& entityTree, const QUuid& entityID) { + auto entity = entityTree->findEntityByID(entityID); + return entity && isWearableEntity(entity); + }); const QString& avatarUrl = bookmark.value(ENTRY_AVATAR_URL, "").toString(); myAvatar->useFullAvatarURL(avatarUrl); qCDebug(interfaceapp) << "Avatar On " << avatarUrl; @@ -233,6 +243,27 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() { bookmark.insert(ENTRY_AVATAR_URL, avatarUrl); bookmark.insert(ENTRY_AVATAR_SCALE, avatarScale); bookmark.insert(ENTRY_AVATAR_ATTACHMENTS, myAvatar->getAttachmentsVariant()); - bookmark.insert(ENTRY_AVATAR_ENTITIES, myAvatar->getAvatarEntitiesVariant()); + + QScriptEngine scriptEngine; + QVariantList wearableEntities; + auto treeRenderer = DependencyManager::get(); + EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; + auto avatarEntities = myAvatar->getAvatarEntityData(); + for (auto entityID : avatarEntities.keys()) { + auto entity = entityTree->findEntityByID(entityID); + if (!entity || !isWearableEntity(entity)) { + continue; + } + QVariantMap avatarEntityData; + EncodeBitstreamParams params; + auto desiredProperties = entity->getEntityProperties(params); + desiredProperties += PROP_LOCAL_POSITION; + desiredProperties += PROP_LOCAL_ROTATION; + EntityItemProperties entityProperties = entity->getProperties(desiredProperties); + QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(&scriptEngine, entityProperties); + avatarEntityData["properties"] = scriptProperties.toVariant(); + wearableEntities.append(QVariant(avatarEntityData)); + } + bookmark.insert(ENTRY_AVATAR_ENTITIES, wearableEntities); return bookmark; } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index fd121055a1..fa3ce565a3 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1607,14 +1607,16 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { emit skeletonModelURLChanged(); } -void MyAvatar::removeAvatarEntities() { +void MyAvatar::removeAvatarEntities(const std::function& condition) { auto treeRenderer = DependencyManager::get(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; if (entityTree) { entityTree->withWriteLock([&] { AvatarEntityMap avatarEntities = getAvatarEntityData(); for (auto entityID : avatarEntities.keys()) { - entityTree->deleteEntity(entityID, true, true); + if(!condition || condition(entityTree, entityID)) { + entityTree->deleteEntity(entityID, true, true); + } } }); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 9b5ddd360d..dfb4c4ab42 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -33,6 +33,7 @@ #include "MyCharacterController.h" #include "RingBufferHistory.h" #include +#include class AvatarActionHold; class ModelItemID; @@ -926,7 +927,7 @@ public: * @returns {object[]} */ Q_INVOKABLE QVariantList getAvatarEntitiesVariant(); - void removeAvatarEntities(); + void removeAvatarEntities(const std::function& condition = {}); /**jsdoc * @function MyAvatar.isFlying diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index f692128fa3..77fe1ea755 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -29,13 +29,24 @@ function executeLater(callback) { Script.setTimeout(callback, 300); } -function getMyAvatarWearables() { - var wearablesArray = MyAvatar.getAvatarEntitiesVariant(); +var INVALID_JOINT_INDEX = -1 +function isWearable(avatarEntity) { + return avatarEntity.properties.visible === true && avatarEntity.properties.parentJointIndex !== INVALID_JOINT_INDEX && avatarEntity.properties.parentID === MyAvatar.sessionUUID; +} - for(var i = 0; i < wearablesArray.length; ++i) { - var wearable = wearablesArray[i]; - var localRotation = wearable.properties.localRotation; - wearable.properties.localRotationAngles = Quat.safeEulerAngles(localRotation) +function getMyAvatarWearables() { + var entitiesArray = MyAvatar.getAvatarEntitiesVariant(); + var wearablesArray = []; + + for (var i = 0; i < entitiesArray.length; ++i) { + var entity = entitiesArray[i]; + if (!isWearable(entity)) { + continue; + } + + var localRotation = entity.properties.localRotation; + entity.properties.localRotationAngles = Quat.safeEulerAngles(localRotation) + wearablesArray.push(entity); } return wearablesArray;