From 845d388cbfdeb42b09becab3a24d1630a6b2a1ac Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 28 Nov 2019 13:56:33 +1300 Subject: [PATCH 1/7] Fix AvatarEntityMap string values to be primitives, not objects --- libraries/shared/src/VariantMapToScriptValue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/VariantMapToScriptValue.cpp b/libraries/shared/src/VariantMapToScriptValue.cpp index b3c02d99f4..156a438bd7 100644 --- a/libraries/shared/src/VariantMapToScriptValue.cpp +++ b/libraries/shared/src/VariantMapToScriptValue.cpp @@ -28,7 +28,7 @@ QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine) break; case QVariant::String: case QVariant::Url: - return scriptEngine.newVariant(qValue); + return qValue.toString(); break; case QVariant::Map: { QVariantMap childMap = qValue.toMap(); From 9144e78cb94013b60d7b55a9243f880cc7382301 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 28 Nov 2019 16:30:26 +1300 Subject: [PATCH 2/7] Rename current getAvatarEntityData() method and use internally --- assignment-client/src/avatars/ScriptableAvatar.cpp | 2 +- assignment-client/src/avatars/ScriptableAvatar.h | 3 ++- interface/src/AvatarBookmarks.cpp | 4 ++-- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/avatar/MyAvatar.h | 3 ++- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/AvatarData.h | 4 +++- libraries/avatars/src/ScriptAvatarData.cpp | 2 +- 8 files changed, 13 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 9fcd71cf05..25860863cf 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -279,7 +279,7 @@ void ScriptableAvatar::setJointMappingsFromNetworkReply() { networkReply->deleteLater(); } -AvatarEntityMap ScriptableAvatar::getAvatarEntityData() const { +AvatarEntityMap ScriptableAvatar::getAvatarEntityDataNonDefault() const { // DANGER: Now that we store the AvatarEntityData in packed format this call is potentially Very Expensive! // Avoid calling this method if possible. AvatarEntityMap data; diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index 47f61a2b64..c08b7e2336 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -178,7 +178,8 @@ public: * var avatarEntityData = Avatar.getAvatarEntityData(); * print("Avatar entities: " + JSON.stringify(avatarEntityData)); */ - Q_INVOKABLE AvatarEntityMap getAvatarEntityData() const override; + + AvatarEntityMap getAvatarEntityDataNonDefault() const override; /**jsdoc * Sets all avatar entities from an object. diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 6f6a93ff19..8f666ddbfa 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -154,7 +154,7 @@ void AvatarBookmarks::deleteBookmark() { void AvatarBookmarks::updateAvatarEntities(const QVariantList &avatarEntities) { auto myAvatar = DependencyManager::get()->getMyAvatar(); - auto currentAvatarEntities = myAvatar->getAvatarEntityData(); + auto currentAvatarEntities = myAvatar->getAvatarEntityDataNonDefault(); std::set newAvatarEntities; // Update or add all the new avatar entities @@ -296,7 +296,7 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() { if (entityTree) { QScriptEngine scriptEngine; - auto avatarEntities = myAvatar->getAvatarEntityData(); + auto avatarEntities = myAvatar->getAvatarEntityDataNonDefault(); for (auto entityID : avatarEntities.keys()) { auto entity = entityTree->findEntityByID(entityID); if (!entity || !isWearableEntity(entity)) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c3e4758e50..4287062094 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1810,7 +1810,7 @@ void MyAvatar::prepareAvatarEntityDataForReload() { _reloadAvatarEntityDataFromSettings = true; } -AvatarEntityMap MyAvatar::getAvatarEntityData() const { +AvatarEntityMap MyAvatar::getAvatarEntityDataNonDefault() const { // NOTE: the return value is expected to be a map of unfortunately-formatted-binary-blobs updateStaleAvatarEntityBlobs(); AvatarEntityMap result; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index cc12e4fcee..2e87f5ef94 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1861,7 +1861,8 @@ public: * var avatarEntityData = MyAvatar.getAvatarEntityData(); * print("Avatar entities: " + JSON.stringify(avatarEntityData)); */ - AvatarEntityMap getAvatarEntityData() const override; + + AvatarEntityMap getAvatarEntityDataNonDefault() const override; /**jsdoc * Sets all avatar entities from an object. diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index e670a5437a..0b7ea76f3f 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -3046,7 +3046,7 @@ void AvatarData::clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFr } } -AvatarEntityMap AvatarData::getAvatarEntityData() const { +AvatarEntityMap AvatarData::getAvatarEntityDataNonDefault() const { // overridden where needed // NOTE: the return value is expected to be a map of unfortunately-formatted-binary-blobs return AvatarEntityMap(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index fd15273e15..5b4e959d03 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1390,7 +1390,9 @@ public: /**jsdoc * @comment Documented in derived classes' JSDoc because implementations are different. */ - Q_INVOKABLE virtual AvatarEntityMap getAvatarEntityData() const; + + // Get avatar entity data with non-default property values. Used internally. + virtual AvatarEntityMap getAvatarEntityDataNonDefault() const; /**jsdoc * @comment Documented in derived classes' JSDoc because implementations are different. diff --git a/libraries/avatars/src/ScriptAvatarData.cpp b/libraries/avatars/src/ScriptAvatarData.cpp index 18717c8ca3..a67af18c40 100644 --- a/libraries/avatars/src/ScriptAvatarData.cpp +++ b/libraries/avatars/src/ScriptAvatarData.cpp @@ -278,7 +278,7 @@ AvatarEntityMap ScriptAvatarData::getAvatarEntities() const { AvatarEntityMap scriptEntityData; if (AvatarSharedPointer sharedAvatarData = _avatarData.lock()) { - return sharedAvatarData->getAvatarEntityData(); + return sharedAvatarData->getAvatarEntityDataNonDefault(); } return scriptEntityData; From c7f82a8264a4ffeef7857b01a0d1ae1866e46d1c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 28 Nov 2019 17:10:19 +1300 Subject: [PATCH 3/7] Add new MyAvatar.getAvatarEntityData() implementation for API --- .../src/avatars/ScriptableAvatar.h | 2 +- interface/src/avatar/MyAvatar.cpp | 40 +++++++++++++++++++ interface/src/avatar/MyAvatar.h | 3 +- libraries/avatars/src/AvatarData.cpp | 6 +++ libraries/avatars/src/AvatarData.h | 2 + .../entities/src/EntityItemProperties.cpp | 7 +++- libraries/entities/src/EntityItemProperties.h | 3 +- 7 files changed, 58 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index c08b7e2336..3eae702257 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -173,7 +173,7 @@ public: * Gets details of all avatar entities. *

Warning: Potentially an expensive call. Do not use if possible.

* @function Avatar.getAvatarEntityData - * @returns {AvatarEntityMap} Details of the avatar entities. + * @returns {AvatarEntityMap} Details of all avatar entities. * @example Report the current avatar entities. * var avatarEntityData = Avatar.getAvatarEntityData(); * print("Avatar entities: " + JSON.stringify(avatarEntityData)); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4287062094..fe4980c873 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1810,6 +1810,46 @@ void MyAvatar::prepareAvatarEntityDataForReload() { _reloadAvatarEntityDataFromSettings = true; } +AvatarEntityMap MyAvatar::getAvatarEntityData() const { + // NOTE: the return value is expected to be a map of unfortunately-formatted-binary-blobs + AvatarEntityMap data; + + auto treeRenderer = DependencyManager::get(); + EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; + if (!entityTree) { + return data; + } + + QList avatarEntityIDs; + _avatarEntitiesLock.withReadLock([&] { + avatarEntityIDs = _packedAvatarEntityData.keys(); + }); + for (const auto& entityID : avatarEntityIDs) { + auto entity = entityTree->findEntityByID(entityID); + if (!entity) { + continue; + } + + EncodeBitstreamParams params; + auto desiredProperties = entity->getEntityProperties(params); + desiredProperties += PROP_LOCAL_POSITION; + desiredProperties += PROP_LOCAL_ROTATION; + desiredProperties += PROP_LOCAL_VELOCITY; + desiredProperties += PROP_LOCAL_ANGULAR_VELOCITY; + desiredProperties += PROP_LOCAL_DIMENSIONS; + EntityItemProperties properties = entity->getProperties(desiredProperties); + + QByteArray blob; + { + std::lock_guard guard(_scriptEngineLock); + EntityItemProperties::propertiesToBlob(*_scriptEngine, getID(), properties, blob, true); + } + + data[entityID] = blob; + } + return data; +} + AvatarEntityMap MyAvatar::getAvatarEntityDataNonDefault() const { // NOTE: the return value is expected to be a map of unfortunately-formatted-binary-blobs updateStaleAvatarEntityBlobs(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 2e87f5ef94..e806fe9b3f 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1856,11 +1856,12 @@ public: /**jsdoc * Gets details of all avatar entities. * @function MyAvatar.getAvatarEntityData - * @returns {AvatarEntityMap} Details of the avatar entities. + * @returns {AvatarEntityMap} Details of all avatar entities. * @example Report the current avatar entities. * var avatarEntityData = MyAvatar.getAvatarEntityData(); * print("Avatar entities: " + JSON.stringify(avatarEntityData)); */ + AvatarEntityMap getAvatarEntityData() const override; AvatarEntityMap getAvatarEntityDataNonDefault() const override; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 0b7ea76f3f..adb7222ee3 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -3046,6 +3046,12 @@ void AvatarData::clearAvatarEntity(const QUuid& entityID, bool requiresRemovalFr } } +AvatarEntityMap AvatarData::getAvatarEntityData() const { + // overridden where needed + // NOTE: the return value is expected to be a map of unfortunately-formatted-binary-blobs + return AvatarEntityMap(); +} + AvatarEntityMap AvatarData::getAvatarEntityDataNonDefault() 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 5b4e959d03..981882bf98 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1390,6 +1390,8 @@ public: /**jsdoc * @comment Documented in derived classes' JSDoc because implementations are different. */ + // Get avatar entity data with all property values. Used in API. + Q_INVOKABLE virtual AvatarEntityMap getAvatarEntityData() const; // Get avatar entity data with non-default property values. Used internally. virtual AvatarEntityMap getAvatarEntityDataNonDefault() const; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 319dfc922f..79dc62ce56 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -5097,10 +5097,13 @@ bool EntityItemProperties::blobToProperties(QScriptEngine& scriptEngine, const Q return true; } -void EntityItemProperties::propertiesToBlob(QScriptEngine& scriptEngine, const QUuid& myAvatarID, const EntityItemProperties& properties, QByteArray& blob) { +void EntityItemProperties::propertiesToBlob(QScriptEngine& scriptEngine, const QUuid& myAvatarID, + const EntityItemProperties& properties, QByteArray& blob, bool allProperties) { // DANGER: this method is NOT efficient. // begin recipe for extracting unfortunately-formatted-binary-blob from EntityItem - QScriptValue scriptValue = EntityItemNonDefaultPropertiesToScriptValue(&scriptEngine, properties); + QScriptValue scriptValue = allProperties + ? EntityItemPropertiesToScriptValue(&scriptEngine, properties) + : EntityItemNonDefaultPropertiesToScriptValue(&scriptEngine, properties); QVariant variantProperties = scriptValue.toVariant(); QJsonDocument jsonProperties = QJsonDocument::fromVariant(variantProperties); // the ID of the parent/avatar changes from session to session. use a special UUID to indicate the avatar diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 63d8183899..166b3ba7e8 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -118,7 +118,8 @@ class EntityItemProperties { friend class MaterialEntityItem; public: static bool blobToProperties(QScriptEngine& scriptEngine, const QByteArray& blob, EntityItemProperties& properties); - static void propertiesToBlob(QScriptEngine& scriptEngine, const QUuid& myAvatarID, const EntityItemProperties& properties, QByteArray& blob); + static void propertiesToBlob(QScriptEngine& scriptEngine, const QUuid& myAvatarID, const EntityItemProperties& properties, + QByteArray& blob, bool allProperties = false); EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()); virtual ~EntityItemProperties() = default; From 9d3e9f6a786cfa1e79a36552cadf33f85642c21b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 1 Dec 2019 16:35:05 +1300 Subject: [PATCH 4/7] Add new Avatar.getAvatarEntityData() method for API --- assignment-client/src/avatars/ScriptableAvatar.cpp | 13 ++++++++++++- assignment-client/src/avatars/ScriptableAvatar.h | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 25860863cf..75aa321c28 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -279,7 +279,18 @@ void ScriptableAvatar::setJointMappingsFromNetworkReply() { networkReply->deleteLater(); } +AvatarEntityMap ScriptableAvatar::getAvatarEntityData() const { + auto data = getAvatarEntityDataInternal(true); + return data; +} + AvatarEntityMap ScriptableAvatar::getAvatarEntityDataNonDefault() const { + auto data = getAvatarEntityDataInternal(false); + return data; + +} + +AvatarEntityMap ScriptableAvatar::getAvatarEntityDataInternal(bool allProperties) const { // DANGER: Now that we store the AvatarEntityData in packed format this call is potentially Very Expensive! // Avoid calling this method if possible. AvatarEntityMap data; @@ -290,7 +301,7 @@ AvatarEntityMap ScriptableAvatar::getAvatarEntityDataNonDefault() const { EntityItemPointer entity = itr.second; EntityItemProperties properties = entity->getProperties(); QByteArray blob; - EntityItemProperties::propertiesToBlob(_scriptEngine, sessionID, properties, blob); + EntityItemProperties::propertiesToBlob(_scriptEngine, sessionID, properties, blob, allProperties); data[id] = blob; } }); diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index 3eae702257..500c3f44fb 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -178,9 +178,12 @@ public: * var avatarEntityData = Avatar.getAvatarEntityData(); * print("Avatar entities: " + JSON.stringify(avatarEntityData)); */ + Q_INVOKABLE AvatarEntityMap getAvatarEntityData() const override; AvatarEntityMap getAvatarEntityDataNonDefault() const override; + AvatarEntityMap getAvatarEntityDataInternal(bool allProperties) const; + /**jsdoc * Sets all avatar entities from an object. *

Warning: Potentially an expensive call. Do not use if possible.

From 200ff2499ed0358db99d2b0d93c2e0d135821e34 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 1 Dec 2019 21:24:40 +1300 Subject: [PATCH 5/7] Include localVelocity etc. to match Entity.getEntityProperties() --- assignment-client/src/avatars/ScriptableAvatar.cpp | 11 ++++++++++- interface/src/avatar/MyAvatar.cpp | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 75aa321c28..3e91cd05e8 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -299,7 +299,16 @@ AvatarEntityMap ScriptableAvatar::getAvatarEntityDataInternal(bool allProperties for (const auto& itr : _entities) { QUuid id = itr.first; EntityItemPointer entity = itr.second; - EntityItemProperties properties = entity->getProperties(); + + EncodeBitstreamParams params; + auto desiredProperties = entity->getEntityProperties(params); + desiredProperties += PROP_LOCAL_POSITION; + desiredProperties += PROP_LOCAL_ROTATION; + desiredProperties += PROP_LOCAL_VELOCITY; + desiredProperties += PROP_LOCAL_ANGULAR_VELOCITY; + desiredProperties += PROP_LOCAL_DIMENSIONS; + EntityItemProperties properties = entity->getProperties(desiredProperties); + QByteArray blob; EntityItemProperties::propertiesToBlob(_scriptEngine, sessionID, properties, blob, allProperties); data[id] = blob; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index fe4980c873..f723471b64 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2562,6 +2562,9 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() { auto desiredProperties = entity->getEntityProperties(params); desiredProperties += PROP_LOCAL_POSITION; desiredProperties += PROP_LOCAL_ROTATION; + desiredProperties += PROP_LOCAL_VELOCITY; + desiredProperties += PROP_LOCAL_ANGULAR_VELOCITY; + desiredProperties += PROP_LOCAL_DIMENSIONS; QVariantMap avatarEntityData; avatarEntityData["id"] = entityID; EntityItemProperties entityProperties = entity->getProperties(desiredProperties); From 48680a0fe29be4b2d51f8ebaaafe361cb36b576f Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 1 Dec 2019 21:46:35 +1300 Subject: [PATCH 6/7] Remove now-unnecessary getEntityProperties() call from WebTablet.js --- scripts/system/libraries/WebTablet.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index a92fbf1065..b7593656a3 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -82,9 +82,7 @@ function calcSpawnInfo(hand, landscape) { cleanUpOldMaterialEntities = function() { var avatarEntityData = MyAvatar.getAvatarEntityData(); for (var entityID in avatarEntityData) { - var entityName = Entities.getEntityProperties(entityID, ["name"]).name; - - if (entityName === TABLET_MATERIAL_ENTITY_NAME) { + if (avatarEntityData[entityID].name === TABLET_MATERIAL_ENTITY_NAME) { Entities.deleteEntity(entityID); } } From 91581ef3c5fc0c797008e5d15f07ec7c62293a55 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 1 Dec 2019 21:59:47 +1300 Subject: [PATCH 7/7] Update JSDoc --- interface/src/avatar/MyAvatar.h | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index e806fe9b3f..c144bacc00 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1855,6 +1855,7 @@ public: /**jsdoc * Gets details of all avatar entities. + *

Warning: Potentially an expensive call. Do not use if possible.

* @function MyAvatar.getAvatarEntityData * @returns {AvatarEntityMap} Details of all avatar entities. * @example Report the current avatar entities.