From 70c3bb2748827cffb7bd0f60402a752af31e2c1c Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Tue, 10 Sep 2019 15:38:20 +0300 Subject: [PATCH 1/2] Emit an event when failing to load an avatar. Previously, MyAvatar only emitted an event (onLoadComplete) if the load succeeded. Now it also emits an event (onLoadFailed) if the load failed. --- interface/src/avatar/MyAvatar.cpp | 5 ++++- interface/src/avatar/MyAvatar.h | 9 ++++++++- libraries/animation/src/Rig.cpp | 6 +++++- libraries/animation/src/Rig.h | 1 + 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6e0bfab69b..4392505fb3 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -349,7 +349,8 @@ MyAvatar::MyAvatar(QThread* thread) : } }); - connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SIGNAL(onLoadComplete())); + connect(&(_skeletonModel->getRig()), &Rig::onLoadComplete, this, &MyAvatar::onLoadComplete); + connect(&(_skeletonModel->getRig()), &Rig::onLoadFailed, this, &MyAvatar::onLoadFailed); _characterController.setDensity(_density); } @@ -2626,6 +2627,8 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN if (urlString.isEmpty() || (fullAvatarURL != getSkeletonModelURL())) { setSkeletonModelURL(fullAvatarURL); UserActivityLogger::getInstance().changedModel("skeleton", urlString); + } else { + emit onLoadComplete(); } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 081fd00d5b..4c7f0c4a75 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -2435,10 +2435,17 @@ signals: /**jsdoc * Triggered when the avatar's model finishes loading. * @function MyAvatar.onLoadComplete - * @returns {Signal} + * @returns {Signal} */ void onLoadComplete(); + /**jsdoc + * Triggered when the avatar's model has failed to load. + * @function MyAvatar.onLoadFailed + * @returns {Signal} + */ + void onLoadFailed(); + /**jsdoc * Triggered when your avatar changes from being active to being away. * @function MyAvatar.wentAway diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index fac4e04ce9..fc1885ea2b 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -2353,6 +2353,7 @@ void Rig::initAnimGraph(const QUrl& url) { // abort load if the previous skeleton was deleted. auto sharedSkeletonPtr = weakSkeletonPtr.lock(); if (!sharedSkeletonPtr) { + emit onLoadFailed(); return; } @@ -2386,8 +2387,9 @@ void Rig::initAnimGraph(const QUrl& url) { } emit onLoadComplete(); }); - connect(_animLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) { + connect(_animLoader.get(), &AnimNodeLoader::error, [this, url](int error, QString str) { qCritical(animation) << "Error loading: code = " << error << "str =" << str; + emit onLoadFailed(); }); connect(_networkLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr, networkUrl](AnimNode::Pointer nodeIn) { @@ -2415,6 +2417,8 @@ void Rig::initAnimGraph(const QUrl& url) { connect(_networkLoader.get(), &AnimNodeLoader::error, [networkUrl](int error, QString str) { qCritical(animation) << "Error loading: code = " << error << "str =" << str; }); + } else { + emit onLoadComplete(); } } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 8570ae4441..b2b9ecd5b4 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -260,6 +260,7 @@ public: signals: void onLoadComplete(); + void onLoadFailed(); protected: bool isIndexValid(int index) const { return _animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints(); } From 7953e3889f4f04b458a09d0a899730f158b605a3 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Tue, 10 Sep 2019 11:48:05 +0300 Subject: [PATCH 2/2] Wait for the avatar skeleton to finish loading before adding the avatar entities --- interface/src/AvatarBookmarks.cpp | 42 ++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index d9ac522dc8..2ebe769bec 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -212,22 +212,36 @@ void AvatarBookmarks::loadBookmark(const QString& bookmarkName) { auto myAvatar = DependencyManager::get()->getMyAvatar(); auto treeRenderer = DependencyManager::get(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; - myAvatar->clearWornAvatarEntities(); + + // Once the skeleton URL has been loaded, add the Avatar Entities. + // We have to wait, because otherwise the avatar entities will try to get attached to the joints + // of the *current* avatar at first. But the current avatar might have a different joints scheme + // from the new avatar, and that would cause the entities to be attached to the wrong joints. + + std::shared_ptr connection1 = std::make_shared(); + *connection1 = connect(myAvatar.get(), &MyAvatar::onLoadComplete, [this, bookmark, bookmarkName, myAvatar, connection1]() { + qCDebug(interfaceapp) << "Finish loading avatar bookmark" << bookmarkName; + QObject::disconnect(*connection1); + myAvatar->clearWornAvatarEntities(); + const float& qScale = bookmark.value(ENTRY_AVATAR_SCALE, 1.0f).toFloat(); + myAvatar->setAvatarScale(qScale); + QList attachments = bookmark.value(ENTRY_AVATAR_ATTACHMENTS, QList()).toList(); + myAvatar->setAttachmentsVariant(attachments); + QVariantList avatarEntities = bookmark.value(ENTRY_AVATAR_ENTITIES, QVariantList()).toList(); + addAvatarEntities(avatarEntities); + emit bookmarkLoaded(bookmarkName); + }); + + std::shared_ptr connection2 = std::make_shared(); + *connection2 = connect(myAvatar.get(), &MyAvatar::onLoadFailed, [this, bookmarkName, connection2]() { + qCDebug(interfaceapp) << "Failed to load avatar bookmark" << bookmarkName; + QObject::disconnect(*connection2); + }); + + qCDebug(interfaceapp) << "Start loading avatar bookmark" << bookmarkName; + const QString& avatarUrl = bookmark.value(ENTRY_AVATAR_URL, "").toString(); myAvatar->useFullAvatarURL(avatarUrl); - qCDebug(interfaceapp) << "Avatar On"; - const QList& attachments = bookmark.value(ENTRY_AVATAR_ATTACHMENTS, QList()).toList(); - - qCDebug(interfaceapp) << "Attach " << attachments; - myAvatar->setAttachmentsVariant(attachments); - - const float& qScale = bookmark.value(ENTRY_AVATAR_SCALE, 1.0f).toFloat(); - myAvatar->setAvatarScale(qScale); - - const QVariantList& avatarEntities = bookmark.value(ENTRY_AVATAR_ENTITIES, QVariantList()).toList(); - addAvatarEntities(avatarEntities); - - emit bookmarkLoaded(bookmarkName); } } }