From ba8620b644ae4c26796cda59ccd8a51fa20c9194 Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Wed, 9 Jan 2019 13:51:40 -0800 Subject: [PATCH 1/8] updating user activity logging --- .../qml/LoginDialog/CompleteProfileBody.qml | 37 +++++++++- .../qml/LoginDialog/LinkAccountBody.qml | 57 +++++++++++++-- .../qml/LoginDialog/LoggingInBody.qml | 73 ++++++++++++++++++- .../resources/qml/LoginDialog/SignUpBody.qml | 39 +++++++--- .../qml/LoginDialog/UsernameCollisionBody.qml | 39 +++++++++- interface/src/Application.cpp | 2 +- 6 files changed, 221 insertions(+), 26 deletions(-) diff --git a/interface/resources/qml/LoginDialog/CompleteProfileBody.qml b/interface/resources/qml/LoginDialog/CompleteProfileBody.qml index 6859b7ab3d..144b91063f 100644 --- a/interface/resources/qml/LoginDialog/CompleteProfileBody.qml +++ b/interface/resources/qml/LoginDialog/CompleteProfileBody.qml @@ -29,6 +29,8 @@ Item { readonly property bool withSteam: withSteam property string errorString: errorString + readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp() + QtObject { id: d readonly property int minWidth: 480 @@ -123,6 +125,13 @@ Item { fontSize: completeProfileBody.fontSize fontBold: completeProfileBody.fontBold onClicked: { + if (completeProfileBody.loginDialogPoppedUp) { + var data = { + "action": "user clicked cancel on the complete profile screen" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } + bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader }); } } @@ -142,6 +151,12 @@ Item { fontSize: completeProfileBody.fontSize fontBold: completeProfileBody.fontBold onClicked: { + if (completeProfileBody.loginDialogPoppedUp) { + var data = { + "action": "user clicked create profile" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } loginErrorMessage.visible = false; loginDialog.createAccountFromSteam(); } @@ -253,13 +268,29 @@ Item { onHandleCreateCompleted: { console.log("Create Succeeded") - loginDialog.loginThroughSteam(); - bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": true, "linkSteam": false }); + if (completeProfileBody.withSteam) { + if (completeProfileBody.loginDialogPoppedUp) { + var data = { + "action": "user created a profile with Steam successfully from the complete profile screen" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } + loginDialog.loginThroughSteam(); + } + bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam, "linkSteam": false }); } onHandleCreateFailed: { console.log("Create Failed: " + error); + if (completeProfileBody.withSteam) { + if (completeProfileBody.loginDialogPoppedUp) { + var data = { + "action": "user failed to create a profile with Steam from the complete profile screen" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } + } - bodyLoader.setSource("UsernameCollisionBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader }); + bodyLoader.setSource("UsernameCollisionBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": completeProfileBody.withSteam }); } } diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 987c5b08e4..5048bf0278 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -42,6 +42,8 @@ Item { property string errorString: errorString property bool lostFocus: false + readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp() + QtObject { id: d readonly property int minWidth: 480 @@ -68,6 +70,20 @@ Item { function login() { loginDialog.login(emailField.text, passwordField.text); + if (linkAccountBody.loginDialogPoppedUp) { + var data; + if (linkAccountBody.linkSteam) { + data = { + "action": "user linking hifi account with Steam" + }; + } else { + data = { + "action": "user logging in" + }; + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } + bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam }); } @@ -294,6 +310,14 @@ Item { topMargin: hifi.dimensions.contentSpacing.y } onClicked: { + if (linkAccountBody.loginDialogPoppedUp) { + var data = { + "action": "user clicked cancel at link account screen" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + loginDialog.dismissLoginDialog(); + } + bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "errorString": "" }); } } @@ -310,7 +334,7 @@ Item { topMargin: hifi.dimensions.contentSpacing.y } onClicked: { - linkAccountBody.login() + linkAccountBody.login(); } } TextMetrics { @@ -373,7 +397,12 @@ Item { lightboxPopup.visible = false; } lightboxPopup.visible = true; - // bodyLoader.setSource("CantAccessBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader }); + if (linkAccountBody.loginDialogPoppedUp) { + var data = { + "action": "user clicked can't access account" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + } } } HifiControlsUit.Button { @@ -402,6 +431,19 @@ Item { linkAccountBody.withSteam = true; loginDialog.loginThroughSteam(); } + if (linkAccountBody.loginDialogPoppedUp) { + var data; + if (linkAccountBody.withOculus) { + data = { + "action": "user clicked login through Oculus" + }; + } else if (linkAccountBody.withSteam) { + data = { + "action": "user clicked login through Steam" + }; + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam }); @@ -470,6 +512,12 @@ Item { linkColor: hifi.colors.blueAccent onLinkActivated: { Tablet.playSound(TabletEnums.ButtonClick); + if (linkAccountBody.loginDialogPoppedUp) { + var data = { + "action": "user clicked sign up button" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + } bodyLoader.setSource("SignUpBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": "", "linkSteam": linkAccountBody.linkSteam }); } @@ -495,10 +543,9 @@ Item { fontFamily: linkAccountBody.fontFamily fontSize: linkAccountBody.fontSize fontBold: linkAccountBody.fontBold - visible: loginDialog.getLoginDialogPoppedUp() && !linkAccountBody.linkSteam; + visible: linkAccountBody.loginDialogPoppedUp && !linkAccountBody.linkSteam; onClicked: { - if (loginDialog.getLoginDialogPoppedUp()) { - console.log("[ENCOURAGELOGINDIALOG]: user dismissed login screen") + if (linkAccountBody.loginDialogPoppedUp) { var data = { "action": "user dismissed login screen" }; diff --git a/interface/resources/qml/LoginDialog/LoggingInBody.qml b/interface/resources/qml/LoginDialog/LoggingInBody.qml index 355f89667b..65693deccd 100644 --- a/interface/resources/qml/LoginDialog/LoggingInBody.qml +++ b/interface/resources/qml/LoginDialog/LoggingInBody.qml @@ -30,6 +30,8 @@ Item { property bool withOculus: withOculus property bool linkSteam: linkSteam + readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp() + QtObject { id: d readonly property int minWidth: 480 @@ -62,8 +64,12 @@ Item { running: false; repeat: false; onTriggered: { - if (loginDialog.getLoginDialogPoppedUp()) { + if (loggingInBody.loginDialogPoppedUp) { loginDialog.dismissLoginDialog(); + var data = { + "action": "user logged in successfully"; + }; + UserActivityLogger.logAction("encourageLoginDialog", data); } root.tryDestroy(); } @@ -107,6 +113,12 @@ Item { loggingInText.x = 0; loggingInText.anchors.centerIn = loggingInHeader; loggedInGlyph.visible = true; + if (loggingInBody.loginDialogPoppedUp) { + var data = { + "action": "user logged in with Steam successfully" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + } } else if (loggingInBody.withOculus) { // reset the flag. loggingInGlyph.visible = false; @@ -115,8 +127,21 @@ Item { loggingInText.anchors.centerIn = loggingInHeader; loggedInGlyph.text = hifi.glyphs.oculus; loggedInGlyph.visible = true; + if (loggingInBody.loginDialogPoppedUp) { + var data = { + "action": "user logged in with Oculus successfully" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + } } else { loggingInText.text = "You are now logged in!"; + if (loggingInBody.loginDialogPoppedUp) { + var data = { + "action": "user logged in successfully" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + } + } successTimer.start(); } @@ -234,11 +259,28 @@ Item { target: loginDialog onHandleLinkCompleted: { console.log("Link Succeeded"); - loggingInBody.linkSteam = false; - loggingInBody.loadingSuccess(); + if (loggingInBody.linkSteam) { + loggingInBody.linkSteam = false; + if (loggingInBody.loginDialogPoppedUp) { + var data = { + "action": "user linked Steam with their hifi account credentials successfully" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + } + + loggingInBody.loadingSuccess(); + } } onHandleLinkFailed: { console.log("Link Failed: " + error); + if (loggingInBody.linkSteam) { + if (loggingInBody.loginDialogPoppedUp) { + var data = { + "action": "user linked Steam unsuccessfully" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + } + } bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": true, "errorString": error }); } @@ -253,18 +295,43 @@ Item { var errorString = ""; if (loggingInBody.linkSteam && loggingInBody.withSteam) { errorString = "Username or password is incorrect."; + if (loggingInBody.loginDialogPoppedUp) { + var data = { + "action": "user failed to link Steam with their hifi account credentials" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + } bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam, "linkSteam": loggingInBody.linkSteam, "errorString": errorString }); } else if (loggingInBody.withSteam) { loggingInGlyph.visible = false; errorString = "Your Steam authentication has failed. Please make sure you are logged into Steam and try again."; + if (loggingInBody.loginDialogPoppedUp) { + var data = { + "action": "user failed to authenticate with Steam to log in" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + } bodyLoader.setSource("CompleteProfileBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": loggingInBody.withSteam, "errorString": errorString }); } else if (loggingInBody.withOculus) { loggingInGlyph.visible = false; errorString = "Your Oculus authentication has failed. Please make sure you are logged into Oculus and try again." + if (loggingInBody.loginDialogPoppedUp) { + var data = { + "action": "user failed to authenticate with Oculus to log in" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + } bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": errorString }); } else { errorString = "Username or password is incorrect."; + if (loggingInBody.loginDialogPoppedUp) { + var data = { + "action": "user failed at logging in" + }; + UserActivityLogger.logAction("encourageLoginDialog", data); + } + bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "errorString": errorString }); } } diff --git a/interface/resources/qml/LoginDialog/SignUpBody.qml b/interface/resources/qml/LoginDialog/SignUpBody.qml index 5e0e955330..3ba66391e6 100644 --- a/interface/resources/qml/LoginDialog/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/SignUpBody.qml @@ -40,6 +40,8 @@ Item { property bool linkSteam: linkSteam property bool lostFocus: false + readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp() + QtObject { id: d readonly property int minWidth: 480 @@ -345,6 +347,12 @@ Item { fontSize: signUpBody.fontSize fontBold: signUpBody.fontBold onClicked: { + if (signUpBody.loginDialogPoppedUp) { + var data = { + "action": "user clicked cancel button at sign up screen" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } bodyLoader.setSource("LinkAccountBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "linkSteam": signUpBody.linkSteam }); } } @@ -363,23 +371,18 @@ Item { } onClicked: { + if (signUpBody.loginDialogPoppedUp) { + var data = { + "action": "user clicked sign up button" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } signUpBody.signup(); } } } } - MouseArea { - z: -2 - anchors.fill: parent - acceptedButtons: Qt.LeftButton - onClicked: { - if (!usernameField.focus && !emailField.focus && !passwordField.focus) { - usernameField.focus = true; - } - } - } - Component.onCompleted: { //but rise Tablet's one instead for Tablet interface root.keyboardEnabled = HMD.active; @@ -408,12 +411,26 @@ Item { onHandleSignupCompleted: { console.log("Sign Up Completed"); + if (signUpBody.loginDialogPoppedUp) { + var data = { + "action": "user signed up successfully" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } + loginDialog.login(usernameField.text, passwordField.text); bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": false, "linkSteam": false }); } onHandleSignupFailed: { console.log("Sign Up Failed") + if (signUpBody.loginDialogPoppedUp) { + var data = { + "action": "user signed up unsuccessfully" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } + if (errorString !== "") { loginErrorMessage.visible = true; var errorStringEdited = errorString.replace(/[\n\r]+/g, "\n"); diff --git a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml index d44f5b733c..af46fc0223 100644 --- a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml +++ b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml @@ -26,6 +26,10 @@ Item { readonly property int textFieldFontSize: 18 readonly property bool fontBold: true + readonly property bool withSteam: withSteam + + readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp() + function create() { mainTextContainer.visible = false loginDialog.createAccountFromSteam(textField.text); @@ -197,18 +201,40 @@ Item { target: loginDialog onHandleCreateCompleted: { console.log("Create Succeeded"); - loginDialog.loginThroughSteam(); - bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": true, "linkSteam": false }) + if (usernameCollisionBody.withSteam) { + if (usernameCollisionBody.loginDialogPoppedUp) { + var data = { + "action": "user created a profile with Steam successfully in the username collision screen" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } + + loginDialog.loginThroughSteam(); + } + + bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": usernameCollisionBody.withSteam, "linkSteam": false }) } onHandleCreateFailed: { console.log("Create Failed: " + error) + if (usernameCollisionBody.loginDialogPoppedUp) { + var data = { + "action": "user failed to create account from the username collision screen" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } + mainTextContainer.visible = true mainTextContainer.text = "\"" + textField.text + qsTr("\" is invalid or already taken."); } onHandleLoginCompleted: { console.log("Login Succeeded"); - if (loginDialog.getLoginDialogPoppedUp()) { + if (usernameCollisionBody.loginDialogPoppedUp) { + var data = { + "action": "user logged in successfully from the username collision screen" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + loginDialog.dismissLoginDialog(); } root.tryDestroy(); @@ -216,6 +242,13 @@ Item { onHandleLoginFailed: { console.log("Login Failed") + if (usernameCollisionBody.loginDialogPoppedUp) { + var data = { + "action": "user failed to log in from the username collision screen" + } + UserActivityLogger.logAction("encourageLoginDialog", data); + } + mainTextContainer.text = "Login Failed"; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d306c77cce..6f5a0b2e54 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2864,7 +2864,7 @@ void Application::showLoginScreen() { dialogsManager->showLoginDialog(); emit loginDialogFocusEnabled(); QJsonObject loginData = {}; - loginData["action"] = "login dialog shown"; + loginData["action"] = "login dialog popped up"; UserActivityLogger::getInstance().logAction("encourageLoginDialog", loginData); _window->setWindowTitle("High Fidelity Interface"); } else { From 8252481ce77b65f495522918c3f5dba78e1ef630 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 11 Jan 2019 09:01:54 -0800 Subject: [PATCH 2/8] Delete domain entities only --- interface/src/Application.cpp | 9 ++-- interface/src/Application.h | 2 +- .../src/EntityTreeRenderer.cpp | 41 +++++++++++++++++-- .../src/EntityTreeRenderer.h | 2 + libraries/entities/src/EntityTree.cpp | 33 +++++++++++++++ libraries/entities/src/EntityTree.h | 2 + libraries/entities/src/EntityTreeElement.cpp | 17 ++++++++ libraries/entities/src/EntityTreeElement.h | 1 + libraries/octree/src/Octree.h | 1 + libraries/octree/src/OctreeProcessor.cpp | 8 ++++ libraries/octree/src/OctreeProcessor.h | 1 + 11 files changed, 109 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0e70375e47..db29892798 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6755,7 +6755,7 @@ void Application::updateWindowTitle() const { DependencyManager::get< MessagesClient >()->sendLocalMessage("Toolbar-DomainChanged", ""); } -void Application::clearDomainOctreeDetails() { +void Application::clearDomainOctreeDetails(bool clearAll) { // before we delete all entities get MyAvatar's AvatarEntityData ready getMyAvatar()->prepareAvatarEntityDataForReload(); @@ -6774,7 +6774,8 @@ void Application::clearDomainOctreeDetails() { }); // reset the model renderer - getEntities()->clear(); + qDebug() << "-----> clearAll: " << clearAll; + clearAll ? getEntities()->clear() : getEntities()->clearDomainEntities(); auto skyStage = DependencyManager::get()->getSkyStage(); @@ -6812,7 +6813,7 @@ void Application::goToErrorDomainURL(QUrl errorDomainURL) { void Application::resettingDomain() { _notifiedPacketVersionMismatchThisDomain = false; - clearDomainOctreeDetails(); + clearDomainOctreeDetails(false); } void Application::nodeAdded(SharedNodePointer node) const { @@ -6898,7 +6899,7 @@ void Application::nodeKilled(SharedNodePointer node) { QMetaObject::invokeMethod(DependencyManager::get().data(), "audioMixerKilled"); } else if (node->getType() == NodeType::EntityServer) { // we lost an entity server, clear all of the domain octree details - clearDomainOctreeDetails(); + clearDomainOctreeDetails(false); } else if (node->getType() == NodeType::AssetServer) { // asset server going away - check if we have the asset browser showing diff --git a/interface/src/Application.h b/interface/src/Application.h index 4c6d45b8c3..05d6135a93 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -469,7 +469,7 @@ private slots: void onDesktopRootItemCreated(QQuickItem* qmlContext); void onDesktopRootContextCreated(QQmlContext* qmlContext); void showDesktop(); - void clearDomainOctreeDetails(); + void clearDomainOctreeDetails(bool clearAll = true); void onAboutToQuit(); void onPresent(quint32 frameCount); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 380998321f..23b2bda555 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -197,9 +197,8 @@ void EntityTreeRenderer::resetEntitiesScriptEngine() { }); } -void EntityTreeRenderer::clear() { - leaveAllEntities(); - +void EntityTreeRenderer::stopEntityScripts() { + leaveAllEntities(); // unload and stop the engine if (_entitiesScriptEngine) { // do this here (instead of in deleter) to avoid marshalling unload signals back to this thread @@ -211,6 +210,42 @@ void EntityTreeRenderer::clear() { if (_wantScripts && !_shuttingDown) { resetEntitiesScriptEngine(); } +} + +void EntityTreeRenderer::clearDomainEntities() { + stopEntityScripts(); + + std::unordered_map savedEntities; + // remove all entities from the scene + _space->clear(); + auto scene = _viewState->getMain3DScene(); + if (scene) { + render::Transaction transaction; + for (const auto& entry : _entitiesInScene) { + const auto& renderer = entry.second; + const EntityItemPointer& entityItem = renderer->getEntity(); + if (entityItem->isDomainEntity()) { + renderer->removeFromScene(scene, transaction); + } else { + savedEntities[entry.first] = entry.second; + } + } + scene->enqueueTransaction(transaction); + } else { + qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene, possibly during application shutdown"; + } + _entitiesInScene.clear(); + _renderablesToUpdate = savedEntities; + _entitiesInScene = savedEntities; + + // reset the zone to the default (while we load the next scene) + _layeredZones.clear(); + + OctreeProcessor::clearDomainEntities(); +} + +void EntityTreeRenderer::clear() { + stopEntityScripts(); // remove all entities from the scene _space->clear(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index b4f0bda703..03d8ca9ff3 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -86,6 +86,7 @@ public: virtual void init() override; /// clears the tree + virtual void clearDomainEntities() override; virtual void clear() override; /// reloads the entity scripts, calling unload and preload @@ -161,6 +162,7 @@ private: bool findBestZoneAndMaybeContainingEntities(QVector* entitiesContainingAvatar = nullptr); bool applyLayeredZones(); + void stopEntityScripts(); void checkAndCallPreload(const EntityItemID& entityID, bool reload = false, bool unloadFirst = false); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index fb1a11d43f..a603d0004b 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -70,6 +70,39 @@ OctreeElementPointer EntityTree::createNewElement(unsigned char* octalCode) { return std::static_pointer_cast(newElement); } +void EntityTree::eraseDomainEntities() { + emit clearingEntities(); + + if (_simulation) { + _simulation->clearEntities(); + } + _staleProxies.clear(); + QHash localMap; + localMap.swap(_entityMap); + QHash savedEntities; + this->withWriteLock([&] { + foreach(EntityItemPointer entity, localMap) { + EntityTreeElementPointer element = entity->getElement(); + if (element) { + element->cleanupDomainEntities(); + } + + if (!entity->isDomainEntity()) { + savedEntities[entity->getEntityItemID()] = entity; + } + } + }); + localMap.clear(); + _entityMap = savedEntities; + + resetClientEditStats(); + clearDeletedEntities(); + + { + QWriteLocker locker(&_needsParentFixupLock); + _needsParentFixup.clear(); + } +} void EntityTree::eraseAllOctreeElements(bool createNewRoot) { emit clearingEntities(); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 9181a4851c..efd994acd2 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -74,6 +74,8 @@ public: return std::static_pointer_cast(_rootElement); } + + virtual void eraseDomainEntities() override; virtual void eraseAllOctreeElements(bool createNewRoot = true) override; virtual void readBitstreamToTree(const unsigned char* bitstream, diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 2ece6835ea..8c65dd1c45 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -683,6 +683,23 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI return foundEntity; } +void EntityTreeElement::cleanupDomainEntities() { + withWriteLock([&] { + EntityItems savedEntities; + foreach(EntityItemPointer entity, _entityItems) { + if (entity->isDomainEntity()) { + entity->preDelete(); + entity->_element = NULL; + } else { + savedEntities.push_back(entity); + } + } + + _entityItems = savedEntities; + }); + bumpChangedContent(); +} + void EntityTreeElement::cleanupEntities() { withWriteLock([&] { foreach(EntityItemPointer entity, _entityItems) { diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index aed19eed15..34947fae5c 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -189,6 +189,7 @@ public: EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const; void getEntitiesInside(const AACube& box, QVector& foundEntities); + void cleanupDomainEntities(); void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities bool removeEntityItem(EntityItemPointer entity, bool deletion = false); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index eef23493f6..200b3ebd60 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -149,6 +149,7 @@ public: OctreeElementPointer getRoot() { return _rootElement; } + virtual void eraseDomainEntities() { _isDirty = true; }; virtual void eraseAllOctreeElements(bool createNewRoot = true); virtual void readBitstreamToTree(const unsigned char* bitstream, uint64_t bufferSizeBytes, ReadBitstreamToTreeParams& args); diff --git a/libraries/octree/src/OctreeProcessor.cpp b/libraries/octree/src/OctreeProcessor.cpp index 206ff399d9..b3ae0ed113 100644 --- a/libraries/octree/src/OctreeProcessor.cpp +++ b/libraries/octree/src/OctreeProcessor.cpp @@ -197,6 +197,14 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe } } + +void OctreeProcessor::clearDomainEntities() { + if (_tree) { + _tree->withWriteLock([&] { + _tree->eraseDomainEntities(); + }); + } +} void OctreeProcessor::clear() { if (_tree) { _tree->withWriteLock([&] { diff --git a/libraries/octree/src/OctreeProcessor.h b/libraries/octree/src/OctreeProcessor.h index 1bc3bd10f9..a65531a4d7 100644 --- a/libraries/octree/src/OctreeProcessor.h +++ b/libraries/octree/src/OctreeProcessor.h @@ -43,6 +43,7 @@ public: virtual void init(); /// clears the tree + virtual void clearDomainEntities(); virtual void clear(); float getAverageElementsPerPacket() const { return _elementsPerPacket.getAverage(); } From e7d38446203761abf41fade7de28261f06ac5252 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 11 Jan 2019 15:57:09 -0800 Subject: [PATCH 3/8] making pre review requests --- interface/src/Application.cpp | 3 +- .../src/EntityTreeRenderer.cpp | 135 ++++++++++++------ .../src/EntityTreeRenderer.h | 6 +- .../entities/src/EntityScriptingInterface.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 16 ++- libraries/entities/src/EntityTree.h | 2 +- libraries/entities/src/EntityTreeElement.cpp | 4 +- libraries/entities/src/EntityTreeElement.h | 2 +- libraries/octree/src/Octree.h | 2 +- libraries/octree/src/OctreeProcessor.cpp | 34 ++--- libraries/octree/src/OctreeProcessor.h | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 5 + libraries/script-engine/src/ScriptEngine.h | 3 + 13 files changed, 144 insertions(+), 72 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index db29892798..d9e196f55e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6774,8 +6774,7 @@ void Application::clearDomainOctreeDetails(bool clearAll) { }); // reset the model renderer - qDebug() << "-----> clearAll: " << clearAll; - clearAll ? getEntities()->clear() : getEntities()->clearDomainEntities(); + clearAll ? getEntities()->clear() : getEntities()->clearNonLocalEntities(); auto skyStage = DependencyManager::get()->getSkyStage(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 23b2bda555..8656a000e4 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -197,8 +197,57 @@ void EntityTreeRenderer::resetEntitiesScriptEngine() { }); } -void EntityTreeRenderer::stopEntityScripts() { - leaveAllEntities(); +void EntityTreeRenderer::stopNonLocalEntityScripts() { + leaveNonLocalEntities(); + // unload and stop the engine + if (_entitiesScriptEngine) { + QList entitiesWithEntityScripts = _entitiesScriptEngine->getListOfEntityScriptIDs(); + + foreach (EntityItemID entityID, entitiesWithEntityScripts) { + EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID); + + if (entityItem) { + if (!entityItem->isLocalEntity()) { + _entitiesScriptEngine->unloadEntityScript(entityID, true); + } + } + } + } +} + +void EntityTreeRenderer::clearNonLocalEntities() { + stopNonLocalEntityScripts(); + + std::unordered_map savedEntities; + // remove all entities from the scene + _space->clear(); + auto scene = _viewState->getMain3DScene(); + if (scene) { + render::Transaction transaction; + for (const auto& entry : _entitiesInScene) { + const auto& renderer = entry.second; + const EntityItemPointer& entityItem = renderer->getEntity(); + if (!entityItem->isLocalEntity()) { + renderer->removeFromScene(scene, transaction); + } else { + savedEntities[entry.first] = entry.second; + } + } + scene->enqueueTransaction(transaction); + } else { + qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene, possibly during application shutdown"; + } + + _renderablesToUpdate = savedEntities; + _entitiesInScene = savedEntities; + + _layeredZones.clearNonLocalLayeredZones(); + + OctreeProcessor::clearNonLocalEntities(); +} + +void EntityTreeRenderer::clear() { + leaveAllEntities(); // unload and stop the engine if (_entitiesScriptEngine) { // do this here (instead of in deleter) to avoid marshalling unload signals back to this thread @@ -210,44 +259,8 @@ void EntityTreeRenderer::stopEntityScripts() { if (_wantScripts && !_shuttingDown) { resetEntitiesScriptEngine(); } -} - -void EntityTreeRenderer::clearDomainEntities() { - stopEntityScripts(); - - std::unordered_map savedEntities; // remove all entities from the scene - _space->clear(); - auto scene = _viewState->getMain3DScene(); - if (scene) { - render::Transaction transaction; - for (const auto& entry : _entitiesInScene) { - const auto& renderer = entry.second; - const EntityItemPointer& entityItem = renderer->getEntity(); - if (entityItem->isDomainEntity()) { - renderer->removeFromScene(scene, transaction); - } else { - savedEntities[entry.first] = entry.second; - } - } - scene->enqueueTransaction(transaction); - } else { - qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene, possibly during application shutdown"; - } - _entitiesInScene.clear(); - _renderablesToUpdate = savedEntities; - _entitiesInScene = savedEntities; - // reset the zone to the default (while we load the next scene) - _layeredZones.clear(); - - OctreeProcessor::clearDomainEntities(); -} - -void EntityTreeRenderer::clear() { - stopEntityScripts(); - - // remove all entities from the scene _space->clear(); auto scene = _viewState->getMain3DScene(); if (scene) { @@ -542,8 +555,7 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector(_tree); // FIXME - if EntityTree had a findEntitiesContainingPoint() this could theoretically be a little faster - entityTree->evalEntitiesInSphere(_avatarPosition, radius, - PickFilter(PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES)), entityIDs); + entityTree->evalEntitiesInSphere(_avatarPosition, radius, PickFilter(), entityIDs); LayeredZones oldLayeredZones(std::move(_layeredZones)); _layeredZones.clear(); @@ -649,6 +661,26 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() { return didUpdate; } +void EntityTreeRenderer::leaveNonLocalEntities() { + if (_tree && !_shuttingDown) { + QVector currentLocalEntitiesInside; + foreach (EntityItemID entityID, _currentEntitiesInside) { + EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID); + if (!entityItem->isLocalEntity()) { + emit leaveEntity(entityID); + if (_entitiesScriptEngine) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); + } + } else { + currentLocalEntitiesInside.push_back(entityID); + } + } + + _currentEntitiesInside = currentLocalEntitiesInside; + forceRecheckEntities(); + } +} + void EntityTreeRenderer::leaveAllEntities() { if (_tree && !_shuttingDown) { @@ -1171,6 +1203,29 @@ EntityTreeRenderer::LayeredZones::LayeredZones(LayeredZones&& other) { } } +void EntityTreeRenderer::LayeredZones::clearNonLocalLayeredZones() { + std::set localLayeredZones; + std::map newMap; + + for (auto iter = begin(); iter != end(); iter++) { + LayeredZone layeredZone = *iter; + + if (layeredZone.zone->isLocalEntity()) { + bool success; + iterator it; + std::tie(it, success) = localLayeredZones.insert(layeredZone); + + if (success) { + newMap.emplace(layeredZone.id, it); + } + } + } + + std::set::operator=(localLayeredZones); + _map = newMap; + _skyboxLayer = empty() ? end() : begin(); +} + void EntityTreeRenderer::LayeredZones::clear() { std::set::clear(); _map.clear(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 03d8ca9ff3..d9f594a20b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -86,7 +86,7 @@ public: virtual void init() override; /// clears the tree - virtual void clearDomainEntities() override; + virtual void clearNonLocalEntities() override; virtual void clear() override; /// reloads the entity scripts, calling unload and preload @@ -162,7 +162,7 @@ private: bool findBestZoneAndMaybeContainingEntities(QVector* entitiesContainingAvatar = nullptr); bool applyLayeredZones(); - void stopEntityScripts(); + void stopNonLocalEntityScripts(); void checkAndCallPreload(const EntityItemID& entityID, bool reload = false, bool unloadFirst = false); @@ -171,6 +171,7 @@ private: QScriptValueList createEntityArgs(const EntityItemID& entityID); bool checkEnterLeaveEntities(); + void leaveNonLocalEntities(); void leaveAllEntities(); void forceRecheckEntities(); @@ -221,6 +222,7 @@ private: LayeredZones& operator=(LayeredZones&&) = delete; void clear(); + void clearNonLocalLayeredZones(); std::pair insert(const LayeredZone& layer); void update(std::shared_ptr zone); bool contains(const LayeredZones& other); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 697d583de7..286f0dd650 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -986,7 +986,7 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { shouldSendDeleteToServer = false; } else { // only delete local entities, server entities will round trip through the server filters - if (entity->isAvatarEntity() || _entityTree->isServerlessMode()) { + if (!entity->isDomainEntity() || _entityTree->isServerlessMode()) { shouldSendDeleteToServer = false; _entityTree->deleteEntity(entityID); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a603d0004b..a2515519eb 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -70,7 +70,7 @@ OctreeElementPointer EntityTree::createNewElement(unsigned char* octalCode) { return std::static_pointer_cast(newElement); } -void EntityTree::eraseDomainEntities() { +void EntityTree::eraseNonLocalEntities() { emit clearingEntities(); if (_simulation) { @@ -84,10 +84,10 @@ void EntityTree::eraseDomainEntities() { foreach(EntityItemPointer entity, localMap) { EntityTreeElementPointer element = entity->getElement(); if (element) { - element->cleanupDomainEntities(); + element->cleanupNonLocalEntities(); } - if (!entity->isDomainEntity()) { + if (entity->isLocalEntity()) { savedEntities[entity->getEntityItemID()] = entity; } } @@ -100,7 +100,15 @@ void EntityTree::eraseDomainEntities() { { QWriteLocker locker(&_needsParentFixupLock); - _needsParentFixup.clear(); + QVector localEntitiesNeedsParentFixup; + + foreach (EntityItemWeakPointer entityItem, _needsParentFixup) { + if (!entityItem.expired() && entityItem.lock()->isLocalEntity()) { + localEntitiesNeedsParentFixup.push_back(entityItem); + } + } + + _needsParentFixup = localEntitiesNeedsParentFixup; } } void EntityTree::eraseAllOctreeElements(bool createNewRoot) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index efd994acd2..f9b7b8d67f 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -75,7 +75,7 @@ public: } - virtual void eraseDomainEntities() override; + virtual void eraseNonLocalEntities() override; virtual void eraseAllOctreeElements(bool createNewRoot = true) override; virtual void readBitstreamToTree(const unsigned char* bitstream, diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 8c65dd1c45..d51ffcd10a 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -683,11 +683,11 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI return foundEntity; } -void EntityTreeElement::cleanupDomainEntities() { +void EntityTreeElement::cleanupNonLocalEntities() { withWriteLock([&] { EntityItems savedEntities; foreach(EntityItemPointer entity, _entityItems) { - if (entity->isDomainEntity()) { + if (!entity->isLocalEntity()) { entity->preDelete(); entity->_element = NULL; } else { diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index 34947fae5c..3f1fda57bd 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -189,7 +189,7 @@ public: EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const; void getEntitiesInside(const AACube& box, QVector& foundEntities); - void cleanupDomainEntities(); + void cleanupNonLocalEntities(); void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities bool removeEntityItem(EntityItemPointer entity, bool deletion = false); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 200b3ebd60..aac29201f1 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -149,7 +149,7 @@ public: OctreeElementPointer getRoot() { return _rootElement; } - virtual void eraseDomainEntities() { _isDirty = true; }; + virtual void eraseNonLocalEntities() { _isDirty = true; }; virtual void eraseAllOctreeElements(bool createNewRoot = true); virtual void readBitstreamToTree(const unsigned char* bitstream, uint64_t bufferSizeBytes, ReadBitstreamToTreeParams& args); diff --git a/libraries/octree/src/OctreeProcessor.cpp b/libraries/octree/src/OctreeProcessor.cpp index b3ae0ed113..18c8630391 100644 --- a/libraries/octree/src/OctreeProcessor.cpp +++ b/libraries/octree/src/OctreeProcessor.cpp @@ -51,15 +51,15 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe bool showTimingDetails = false; // Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showTimingDetails, "OctreeProcessor::processDatagram()", showTimingDetails); - + if (message.getType() == getExpectedPacketType()) { PerformanceWarning warn(showTimingDetails, "OctreeProcessor::processDatagram expected PacketType", showTimingDetails); // if we are getting inbound packets, then our tree is also viewing, and we should remember that fact. _tree->setIsViewing(true); - + OCTREE_PACKET_FLAGS flags; message.readPrimitive(&flags); - + OCTREE_PACKET_SEQUENCE sequence; message.readPrimitive(&sequence); @@ -68,7 +68,7 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); - + OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); qint64 clockSkew = sourceNode ? sourceNode->getClockSkewUsec() : 0; qint64 flightTime = arrivedAt - sentAt + clockSkew; @@ -79,27 +79,27 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe qCDebug(octree) << "OctreeProcessor::processDatagram() ... " "Got Packet Section color:" << packetIsColored << "compressed:" << packetIsCompressed << - "sequence: " << sequence << + "sequence: " << sequence << "flight: " << flightTime << " usec" << "size:" << message.getSize() << "data:" << message.getBytesLeftToRead(); } - + _packetsInLastWindow++; - + int elementsPerPacket = 0; int entitiesPerPacket = 0; - + quint64 totalWaitingForLock = 0; quint64 totalUncompress = 0; quint64 totalReadBitsteam = 0; const QUuid& sourceUUID = sourceNode->getUUID(); - + int subsection = 1; - + bool error = false; - + while (message.getBytesLeftToRead() > 0 && !error) { if (packetIsCompressed) { if (message.getBytesLeftToRead() > (qint64) sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE)) { @@ -111,7 +111,7 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe } else { sectionLength = message.getBytesLeftToRead(); } - + if (sectionLength) { // ask the VoxelTree to read the bitstream into the tree ReadBitstreamToTreeParams args(WANT_EXISTS_BITS, NULL, @@ -149,7 +149,7 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe qCDebug(octree) << "OctreeProcessor::processDatagram() ******* END _tree->readBitstreamToTree()..."; } }); - + // seek forwards in packet message.seek(message.getPosition() + sectionLength); @@ -172,13 +172,13 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe _waitLockPerPacket.updateAverage(totalWaitingForLock); _uncompressPerPacket.updateAverage(totalUncompress); _readBitstreamPerPacket.updateAverage(totalReadBitsteam); - + quint64 now = usecTimestampNow(); if (_lastWindowAt == 0) { _lastWindowAt = now; } quint64 sinceLastWindow = now - _lastWindowAt; - + if (sinceLastWindow > USECS_PER_SECOND) { float packetsPerSecondInWindow = (float)_packetsInLastWindow / (float)(sinceLastWindow / USECS_PER_SECOND); float elementsPerSecondInWindow = (float)_elementsInLastWindow / (float)(sinceLastWindow / USECS_PER_SECOND); @@ -198,10 +198,10 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe } -void OctreeProcessor::clearDomainEntities() { +void OctreeProcessor::clearNonLocalEntities() { if (_tree) { _tree->withWriteLock([&] { - _tree->eraseDomainEntities(); + _tree->eraseNonLocalEntities(); }); } } diff --git a/libraries/octree/src/OctreeProcessor.h b/libraries/octree/src/OctreeProcessor.h index a65531a4d7..bc5618e657 100644 --- a/libraries/octree/src/OctreeProcessor.h +++ b/libraries/octree/src/OctreeProcessor.h @@ -43,7 +43,7 @@ public: virtual void init(); /// clears the tree - virtual void clearDomainEntities(); + virtual void clearNonLocalEntities(); virtual void clear(); float getAverageElementsPerPacket() const { return _elementsPerPacket.getAverage(); } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 8dad5932be..be17ba04fa 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -2393,6 +2393,11 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldR } } +QList ScriptEngine::getListOfEntityScriptIDs() { + QReadLocker locker{ &_entityScriptsLock }; + return _entityScripts.keys(); +} + void ScriptEngine::unloadAllEntityScripts() { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 8fe50aee78..db7d72fff8 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -145,6 +145,9 @@ public: QString getFilename() const; + + QList getListOfEntityScriptIDs(); + /**jsdoc * Stop the current script. * @function Script.stop From 68e15c6c074e7d55e11b66efb2d01ad63dd5eedb Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 14 Jan 2019 13:36:21 -0800 Subject: [PATCH 4/8] fixes from 78 --- .../qml/hifi/avatarapp/AdjustWearables.qml | 7 +- interface/src/AvatarBookmarks.cpp | 29 +++++- interface/src/avatar/MyAvatar.cpp | 93 +++++++++---------- interface/src/avatar/MyAvatar.h | 2 +- libraries/avatars/src/AvatarData.cpp | 17 ++-- .../entities/src/EntityItemProperties.cpp | 4 +- scripts/system/avatarapp.js | 8 +- 7 files changed, 92 insertions(+), 68 deletions(-) diff --git a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml index 493bfa2a30..b3cdd28a94 100644 --- a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml +++ b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml @@ -177,8 +177,9 @@ Rectangle { repeat: true onTriggered: { var currentWearable = getCurrentWearable(); - var soft = currentWearable ? currentWearable.relayParentJoints : false; - var softEnabled = currentWearable ? entityHasAvatarJoints(currentWearable.id) : false; + var hasSoft = currentWearable && currentWearable.relayParentJoints !== undefined; + var soft = hasSoft ? currentWearable.relayParentJoints : false; + var softEnabled = hasSoft ? entityHasAvatarJoints(currentWearable.id) : false; isSoft.set(soft); isSoft.enabled = softEnabled; } @@ -511,7 +512,7 @@ Rectangle { function set(value) { notify = false; - checked = value + checked = value; notify = true; } diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 1d003f19c1..ba53db5350 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -55,7 +55,7 @@ void addAvatarEntities(const QVariantList& avatarEntities) { QVariantMap asMap = variantProperties.toMap(); QScriptValue scriptProperties = variantMapToScriptValue(asMap, scriptEngine); EntityItemProperties entityProperties; - EntityItemPropertiesFromScriptValueHonorReadOnly(scriptProperties, entityProperties); + EntityItemPropertiesFromScriptValueIgnoreReadOnly(scriptProperties, entityProperties); entityProperties.setParentID(myNodeID); entityProperties.setEntityHostType(entity::HostType::AVATAR); @@ -151,8 +151,29 @@ void AvatarBookmarks::removeBookmark(const QString& bookmarkName) { void AvatarBookmarks::updateAvatarEntities(const QVariantList &avatarEntities) { auto myAvatar = DependencyManager::get()->getMyAvatar(); - myAvatar->removeWearableAvatarEntities(); - addAvatarEntities(avatarEntities); + auto currentAvatarEntities = myAvatar->getAvatarEntityData(); + std::set newAvatarEntities; + + // Update or add all the new avatar entities + for (auto& avatarEntityVariant : avatarEntities) { + auto avatarEntityVariantMap = avatarEntityVariant.toMap(); + auto idItr = avatarEntityVariantMap.find("id"); + if (idItr != avatarEntityVariantMap.end()) { + auto propertiesItr = avatarEntityVariantMap.find("properties"); + if (propertiesItr != avatarEntityVariantMap.end()) { + EntityItemID id = idItr.value().toUuid(); + newAvatarEntities.insert(id); + myAvatar->updateAvatarEntity(id, QJsonDocument::fromVariant(propertiesItr.value()).toBinaryData()); + } + } + } + + // Remove any old entities not in the new list + for (auto& avatarEntityID : currentAvatarEntities.keys()) { + if (newAvatarEntities.find(avatarEntityID) == newAvatarEntities.end()) { + myAvatar->removeAvatarEntity(avatarEntityID); + } + } } void AvatarBookmarks::loadBookmark(const QString& bookmarkName) { @@ -176,7 +197,7 @@ void AvatarBookmarks::loadBookmark(const QString& bookmarkName) { auto myAvatar = DependencyManager::get()->getMyAvatar(); auto treeRenderer = DependencyManager::get(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; - myAvatar->removeWearableAvatarEntities(); + myAvatar->clearAvatarEntities(); const QString& avatarUrl = bookmark.value(ENTRY_AVATAR_URL, "").toString(); myAvatar->useFullAvatarURL(avatarUrl); qCDebug(interfaceapp) << "Avatar On"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 91ea8f0291..8848647894 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1610,10 +1610,12 @@ void MyAvatar::handleChangedAvatarEntityData() { skip = true; } }); - sanitizeAvatarEntityProperties(properties); - entityTree->withWriteLock([&] { - entityTree->updateEntity(id, properties); - }); + if (!skip) { + sanitizeAvatarEntityProperties(properties); + entityTree->withWriteLock([&] { + entityTree->updateEntity(id, properties); + }); + } } // DELETE cached blobs @@ -1810,19 +1812,27 @@ 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; + bool changed = false; _avatarEntitiesLock.withWriteLock([&] { - AvatarEntityMap::iterator itr = _cachedAvatarEntityBlobs.find(entityID); - if (itr != _cachedAvatarEntityBlobs.end()) { - _entitiesToUpdate.push_back(entityID); - itr.value() = entityData; + auto data = QJsonDocument::fromBinaryData(entityData); + if (data.isEmpty() || data.isNull() || !data.isObject() || data.object().isEmpty()) { + qDebug() << "ERROR! Trying to update with invalid avatar entity data. Skipping." << data; } else { - _entitiesToAdd.push_back(entityID); - _cachedAvatarEntityBlobs.insert(entityID, entityData); + auto itr = _cachedAvatarEntityBlobs.find(entityID); + if (itr == _cachedAvatarEntityBlobs.end()) { + _entitiesToAdd.push_back(entityID); + _cachedAvatarEntityBlobs.insert(entityID, entityData); + changed = true; + } else { + _entitiesToUpdate.push_back(entityID); + itr.value() = entityData; + changed = true; + } } }); + if (changed) { + _needToSaveAvatarEntitySettings = true; + } } void MyAvatar::avatarEntityDataToJson(QJsonObject& root) const { @@ -2362,50 +2372,36 @@ bool isWearableEntity(const EntityItemPointer& entity) { || entity->getParentID() == AVATAR_SELF_ID); } -void MyAvatar::clearAvatarEntities() { +void MyAvatar::removeAvatarEntity(const EntityItemID& entityID) { auto treeRenderer = DependencyManager::get(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; - QList avatarEntityIDs; - _avatarEntitiesLock.withReadLock([&] { - avatarEntityIDs = _packedAvatarEntityData.keys(); - }); - for (const auto& entityID : avatarEntityIDs) { - entityTree->withWriteLock([&entityID, &entityTree] { - // remove this entity first from the entity tree - entityTree->deleteEntity(entityID, true, true); - }); - - // remove the avatar entity from our internal list - // (but indicate it doesn't need to be pulled from the tree) - clearAvatarEntity(entityID, false); - } -} - -void MyAvatar::removeWearableAvatarEntities() { - auto treeRenderer = DependencyManager::get(); - EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; if (entityTree) { - QList avatarEntityIDs; - _avatarEntitiesLock.withReadLock([&] { - avatarEntityIDs = _packedAvatarEntityData.keys(); - }); - for (const auto& entityID : avatarEntityIDs) { - auto entity = entityTree->findEntityByID(entityID); - if (entity && isWearableEntity(entity)) { - entityTree->withWriteLock([&entityID, &entityTree] { - // remove this entity first from the entity tree - entityTree->deleteEntity(entityID, true, true); - }); + auto entity = entityTree->findEntityByID(entityID); + if (entity && isWearableEntity(entity)) { + entityTree->withWriteLock([&entityID, &entityTree] { + // remove this entity first from the entity tree + entityTree->deleteEntity(entityID, true, true); + }); - // remove the avatar entity from our internal list - // (but indicate it doesn't need to be pulled from the tree) - clearAvatarEntity(entityID, false); - } + // remove the avatar entity from our internal list + // (but indicate it doesn't need to be pulled from the tree) + clearAvatarEntity(entityID, false); } } } +void MyAvatar::clearAvatarEntities() { + QList avatarEntityIDs; + _avatarEntitiesLock.withReadLock([&] { + avatarEntityIDs = _packedAvatarEntityData.keys(); + }); + for (auto entityID : avatarEntityIDs) { + removeAvatarEntity(entityID); + } +} + + QVariantList MyAvatar::getAvatarEntitiesVariant() { // NOTE: this method is NOT efficient QVariantList avatarEntitiesData; @@ -2428,6 +2424,7 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() { desiredProperties += PROP_LOCAL_ROTATION; EntityItemProperties entityProperties = entity->getProperties(desiredProperties); QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(_myScriptEngine, entityProperties); + avatarEntityData["id"] = entityID; avatarEntityData["properties"] = scriptProperties.toVariant(); avatarEntitiesData.append(QVariant(avatarEntityData)); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 67a449b274..90e4d22713 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -968,8 +968,8 @@ public: * @returns {object[]} */ Q_INVOKABLE QVariantList getAvatarEntitiesVariant(); + void removeAvatarEntity(const EntityItemID& entityID); void clearAvatarEntities(); - void removeWearableAvatarEntities(); /**jsdoc * Check whether your avatar is flying or not. diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 21e0a6aba2..24e30d20c1 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -2744,23 +2744,28 @@ void AvatarData::setAttachmentsVariant(const QVariantList& variant) { } void AvatarData::storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& data) { + bool changed = false; _avatarEntitiesLock.withWriteLock([&] { - PackedAvatarEntityMap::iterator itr = _packedAvatarEntityData.find(entityID); + auto itr = _packedAvatarEntityData.find(entityID); if (itr == _packedAvatarEntityData.end()) { if (_packedAvatarEntityData.size() < MAX_NUM_AVATAR_ENTITIES) { _packedAvatarEntityData.insert(entityID, data); + changed = true; } } else { itr.value() = data; + changed = true; } }); - _avatarEntityDataChanged = true; + if (changed) { + _avatarEntityDataChanged = true; - if (_clientTraitsHandler) { - // we have a client traits handler, so we need to mark this instanced trait as changed - // so that changes will be sent next frame - _clientTraitsHandler->markInstancedTraitUpdated(AvatarTraits::AvatarEntity, entityID); + if (_clientTraitsHandler) { + // we have a client traits handler, so we need to mark this instanced trait as changed + // so that changes will be sent next frame + _clientTraitsHandler->markInstancedTraitUpdated(AvatarTraits::AvatarEntity, entityID); + } } } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 3b1e9a3e2b..1fdff19e38 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -4616,14 +4616,14 @@ bool EntityItemProperties::blobToProperties(QScriptEngine& scriptEngine, const Q // DANGER: this method is NOT efficient. // begin recipe for converting unfortunately-formatted-binary-blob to EntityItemProperties QJsonDocument jsonProperties = QJsonDocument::fromBinaryData(blob); - if (!jsonProperties.isObject()) { + if (jsonProperties.isEmpty() || jsonProperties.isNull() || !jsonProperties.isObject() || jsonProperties.object().isEmpty()) { qCDebug(entities) << "bad avatarEntityData json" << QString(blob.toHex()); return false; } QVariant variant = jsonProperties.toVariant(); QVariantMap variantMap = variant.toMap(); QScriptValue scriptValue = variantMapToScriptValue(variantMap, scriptEngine); - EntityItemPropertiesFromScriptValueHonorReadOnly(scriptValue, properties); + EntityItemPropertiesFromScriptValueIgnoreReadOnly(scriptValue, properties); // end recipe return true; } diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 2b9a738202..631c0e03e8 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -70,9 +70,9 @@ function getMyAvatarSettings() { } } -function updateAvatarWearables(avatar, callback) { +function updateAvatarWearables(avatar, callback, wearablesOverride) { executeLater(function() { - var wearables = getMyAvatarWearables(); + var wearables = wearablesOverride ? wearablesOverride : getMyAvatarWearables(); avatar[ENTRY_AVATAR_ENTITIES] = wearables; sendToQml({'method' : 'wearablesUpdated', 'wearables' : wearables}) @@ -210,7 +210,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See break; case 'adjustWearable': if(message.properties.localRotationAngles) { - message.properties.localRotation = Quat.fromVec3Degrees(message.properties.localRotationAngles) + message.properties.localRotation = Quat.fromVec3Degrees(message.properties.localRotationAngles); } Entities.editEntity(message.entityID, message.properties); @@ -235,7 +235,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See // revert changes using snapshot of wearables if(currentAvatarWearablesBackup !== null) { AvatarBookmarks.updateAvatarEntities(currentAvatarWearablesBackup); - updateAvatarWearables(currentAvatar); + updateAvatarWearables(currentAvatar, null, currentAvatarWearablesBackup); } } else { sendToQml({'method' : 'updateAvatarInBookmarks'}); From 4ab730866929121115b08e47bda96ff3c1c73012 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 14 Jan 2019 14:04:01 -0800 Subject: [PATCH 5/8] addressing code review requests --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 4 ++-- libraries/entities/src/EntityTree.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 8656a000e4..c71b296a74 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -203,7 +203,7 @@ void EntityTreeRenderer::stopNonLocalEntityScripts() { if (_entitiesScriptEngine) { QList entitiesWithEntityScripts = _entitiesScriptEngine->getListOfEntityScriptIDs(); - foreach (EntityItemID entityID, entitiesWithEntityScripts) { + foreach (const EntityItemID& entityID, entitiesWithEntityScripts) { EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID); if (entityItem) { @@ -664,7 +664,7 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() { void EntityTreeRenderer::leaveNonLocalEntities() { if (_tree && !_shuttingDown) { QVector currentLocalEntitiesInside; - foreach (EntityItemID entityID, _currentEntitiesInside) { + foreach (const EntityItemID& entityID, _currentEntitiesInside) { EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID); if (!entityItem->isLocalEntity()) { emit leaveEntity(entityID); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a2515519eb..b8babc60b8 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -74,6 +74,8 @@ void EntityTree::eraseNonLocalEntities() { emit clearingEntities(); if (_simulation) { + // This will clear all entities host types including local entities, because local entities + // are not in the physics simulation _simulation->clearEntities(); } _staleProxies.clear(); From 3b913db60903f432a717f4a2c5f9e4bc52f36b73 Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Tue, 15 Jan 2019 14:21:37 -0800 Subject: [PATCH 6/8] fixing typo --- interface/resources/qml/LoginDialog/LoggingInBody.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/LoginDialog/LoggingInBody.qml b/interface/resources/qml/LoginDialog/LoggingInBody.qml index 65693deccd..5e4a6c4cb3 100644 --- a/interface/resources/qml/LoginDialog/LoggingInBody.qml +++ b/interface/resources/qml/LoginDialog/LoggingInBody.qml @@ -67,7 +67,7 @@ Item { if (loggingInBody.loginDialogPoppedUp) { loginDialog.dismissLoginDialog(); var data = { - "action": "user logged in successfully"; + "action": "user logged in successfully" }; UserActivityLogger.logAction("encourageLoginDialog", data); } From 1104e56bc35a95d02644682fcaa1089fa5a2be1b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 16 Jan 2019 13:23:27 -0800 Subject: [PATCH 7/8] fix bug that caused tablet to be constantly hooked and unhooked from avatar at SpatiallyNestable level --- libraries/avatars/src/AvatarData.h | 2 -- libraries/shared/src/SpatiallyNestable.cpp | 3 ++- libraries/shared/src/SpatiallyNestable.h | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index ec5ea4a5d0..bd17233dbf 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -465,8 +465,6 @@ public: static const QUrl& defaultFullAvatarModelUrl(); - virtual bool isMyAvatar() const { return false; } - const QUuid getSessionUUID() const { return getID(); } glm::vec3 getHandPosition() const; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 8805205361..c524e3183b 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -108,7 +108,8 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer(bool& success) cons return nullptr; } - if (parent && parent->getID() == parentID) { + if (parent && (parent->getID() == parentID || + (parentID == AVATAR_SELF_ID && parent->isMyAvatar()))) { // parent pointer is up-to-date if (!_parentKnowsMe) { SpatialParentTree* parentTree = parent->getParentTree(); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index a55f32896b..319f07236b 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -47,6 +47,8 @@ public: virtual const QUuid getParentID() const; virtual void setParentID(const QUuid& parentID); + virtual bool isMyAvatar() const { return false; } + virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex); From 9727c8fd381a7511df4d472ceae1e4b2711fb56e Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 16 Jan 2019 14:14:01 -0800 Subject: [PATCH 8/8] CR --- interface/src/AvatarBookmarks.cpp | 4 ++-- interface/src/avatar/MyAvatar.cpp | 10 +++++----- interface/src/avatar/MyAvatar.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index ba53db5350..5fe35bd23f 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -171,7 +171,7 @@ void AvatarBookmarks::updateAvatarEntities(const QVariantList &avatarEntities) { // Remove any old entities not in the new list for (auto& avatarEntityID : currentAvatarEntities.keys()) { if (newAvatarEntities.find(avatarEntityID) == newAvatarEntities.end()) { - myAvatar->removeAvatarEntity(avatarEntityID); + myAvatar->removeWornAvatarEntity(avatarEntityID); } } } @@ -197,7 +197,7 @@ void AvatarBookmarks::loadBookmark(const QString& bookmarkName) { auto myAvatar = DependencyManager::get()->getMyAvatar(); auto treeRenderer = DependencyManager::get(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; - myAvatar->clearAvatarEntities(); + myAvatar->clearWornAvatarEntities(); const QString& avatarUrl = bookmark.value(ENTRY_AVATAR_URL, "").toString(); myAvatar->useFullAvatarURL(avatarUrl); qCDebug(interfaceapp) << "Avatar On"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8848647894..ea6ddbfde3 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2372,7 +2372,7 @@ bool isWearableEntity(const EntityItemPointer& entity) { || entity->getParentID() == AVATAR_SELF_ID); } -void MyAvatar::removeAvatarEntity(const EntityItemID& entityID) { +void MyAvatar::removeWornAvatarEntity(const EntityItemID& entityID) { auto treeRenderer = DependencyManager::get(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; @@ -2391,13 +2391,13 @@ void MyAvatar::removeAvatarEntity(const EntityItemID& entityID) { } } -void MyAvatar::clearAvatarEntities() { +void MyAvatar::clearWornAvatarEntities() { QList avatarEntityIDs; _avatarEntitiesLock.withReadLock([&] { avatarEntityIDs = _packedAvatarEntityData.keys(); }); for (auto entityID : avatarEntityIDs) { - removeAvatarEntity(entityID); + removeWornAvatarEntity(entityID); } } @@ -2803,8 +2803,8 @@ void MyAvatar::setAttachmentData(const QVector& attachmentData) newEntitiesProperties.push_back(properties); } - // clear any existing avatar entities - clearAvatarEntities(); + // clear any existing wearables + clearWornAvatarEntities(); for (auto& properties : newEntitiesProperties) { DependencyManager::get()->addEntity(properties, true); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 90e4d22713..0337175fc1 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -968,8 +968,8 @@ public: * @returns {object[]} */ Q_INVOKABLE QVariantList getAvatarEntitiesVariant(); - void removeAvatarEntity(const EntityItemID& entityID); - void clearAvatarEntities(); + void removeWornAvatarEntity(const EntityItemID& entityID); + void clearWornAvatarEntities(); /**jsdoc * Check whether your avatar is flying or not.