diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ab3ba206f2..4f8cc6655e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -115,8 +115,6 @@ Avatar::Avatar(QThread* thread, RigPointer rig) : } Avatar::~Avatar() { - assert(isDead()); // mark dead before calling the dtor - auto treeRenderer = DependencyManager::get(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; if (entityTree) { @@ -447,6 +445,24 @@ float Avatar::getSimulationRate(const QString& rateName) const { return 0.0f; } +void Avatar::getIdentity(Identity& identity) const { + identity.uuid = getSessionUUID(); + identity.skeletonModelURL = _skeletonModelURL; + identity.attachmentData = _attachmentData; + identity.displayName = _displayName; + identity.sessionDisplayName = _sessionDisplayName; + identity.avatarEntityData = _avatarEntityData; +} + +void Avatar::setIdentity(const Identity& identity) { + assert(identity.uuid == getSessionUUID()); + setSkeletonModelURL(identity.skeletonModelURL); + _attachmentData = identity.attachmentData; + _displayName = identity.displayName; + _sessionDisplayName = identity.sessionDisplayName; + _avatarEntityData = identity.avatarEntityData; +} + bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { const float HEAD_SPHERE_RADIUS = 0.1f; glm::vec3 theirLookAt = dynamic_pointer_cast(avatar)->getHead()->getLookAtPosition(); @@ -510,12 +526,13 @@ static TextRenderer3D* textRenderer(TextRendererType type) { void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) { auto avatarPayload = new render::Payload(self); auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload); - _renderItemID = scene->allocateID(); - transaction.resetItem(_renderItemID, avatarPayloadPointer); - _skeletonModel->addToScene(scene, transaction); + if (_skeletonModel->addToScene(scene, transaction)) { + _renderItemID = scene->allocateID(); + transaction.resetItem(_renderItemID, avatarPayloadPointer); - for (auto& attachmentModel : _attachmentModels) { - attachmentModel->addToScene(scene, transaction); + for (auto& attachmentModel : _attachmentModels) { + attachmentModel->addToScene(scene, transaction); + } } } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 8c055885fd..3b9bb7e0f2 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -238,6 +238,9 @@ public: return (lerpValue*(4.0f - 2.0f * lerpValue) - 1.0f); } + void getIdentity(Identity& identity) const; + void setIdentity(const Identity& identity); + public slots: // FIXME - these should be migrated to use Pose data instead diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 6f9793ad34..e3293a7874 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -214,11 +214,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } avatar->animateScaleChanges(deltaTime); - if (avatar->shouldDie()) { - avatar->die(); - removeAvatar(avatar->getID()); - } - const float OUT_OF_VIEW_THRESHOLD = 0.5f * AvatarData::OUT_OF_VIEW_PENALTY; uint64_t now = usecTimestampNow(); if (now < updateExpiry) { @@ -331,35 +326,14 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() { return std::make_shared(qApp->thread(), std::make_shared()); } -void AvatarManager::processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode) { - PerformanceTimer perfTimer("receiveAvatar"); - // enumerate over all of the avatars in this packet - // only add them if mixerWeakPointer points to something (meaning that mixer is still around) - while (message->getBytesLeftToRead()) { - AvatarSharedPointer avatarData = parseAvatarData(message, sendingNode); - if (avatarData) { - auto avatar = std::static_pointer_cast(avatarData); - if (avatar->isInScene()) { - if (!_shouldRender) { - // rare transition so we process the transaction immediately - const render::ScenePointer& scene = qApp->getMain3DScene(); - render::Transaction transaction; - avatar->removeFromScene(avatar, scene, transaction); - if (scene) { - scene->enqueueTransaction(transaction); - } - } - } else if (_shouldRender) { - // very rare transition so we process the transaction immediately - const render::ScenePointer& scene = qApp->getMain3DScene(); - render::Transaction transaction; - avatar->addToScene(avatar, scene, transaction); - if (scene) { - scene->enqueueTransaction(transaction); - } - } - } +AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { + AvatarSharedPointer avatarData = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer); + QMap::iterator itr = _identityCache.find(sessionUUID); + if (itr != _identityCache.end()) { + auto avatar = std::static_pointer_cast(avatarData); + avatar->setIdentity(*itr); } + return avatarData; } void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { @@ -367,8 +341,13 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar // removedAvatar is a shared pointer to an AvatarData but we need to get to the derived Avatar // class in this context so we can call methods that don't exist at the base class. - Avatar* avatar = static_cast(removedAvatar.get()); - avatar->die(); + auto avatar = std::static_pointer_cast(removedAvatar); + + // there is no way to request identity data from the avatar-mixer + // therefore whenever we remove an avatar we cache the identity in case we need it later + AvatarData::Identity identity; + avatar->getIdentity(identity); + _identityCache[avatar->getSessionUUID()] = identity; AvatarMotionState* motionState = avatar->getMotionState(); if (motionState) { @@ -404,14 +383,11 @@ void AvatarManager::clearOtherAvatars() { if (avatar->isInScene()) { avatar->removeFromScene(avatar, scene, transaction); } - AvatarMotionState* motionState = avatar->getMotionState(); - if (motionState) { - _motionStatesThatMightUpdate.remove(motionState); - _motionStatesToAddToPhysics.remove(motionState); - _motionStatesToRemoveFromPhysics.push_back(motionState); - } + handleRemovedAvatar(avatar); + avatarIterator = _avatarHash.erase(avatarIterator); + } else { + ++avatarIterator; } - ++avatarIterator; } scene->enqueueTransaction(transaction); _myAvatar->clearLookAtTargetAvatar(); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 6eabbd081f..af372f7627 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -98,9 +98,6 @@ public slots: void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } void updateAvatarRenderStatus(bool shouldRenderAvatars); -protected slots: - void processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode) override; - private: explicit AvatarManager(QObject* parent = 0); explicit AvatarManager(const AvatarManager& other); @@ -108,6 +105,7 @@ private: void simulateAvatarFades(float deltaTime); AvatarSharedPointer newSharedAvatar() override; + AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) override; void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override; QVector _avatarsToFade; @@ -120,6 +118,7 @@ private: quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate. QVector _localLights; + QMap _identityCache; bool _shouldShowReceiveStats = false; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a4ea016e79..e75f801885 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1521,9 +1521,6 @@ void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityC setAvatarEntityData(identity.avatarEntityData); identityChanged = true; } - // flag this avatar as non-stale by updating _averageBytesReceived - const int BOGUS_NUM_BYTES = 1; - _averageBytesReceived.updateAverage(BOGUS_NUM_BYTES); // use the timestamp from this identity, since we want to honor the updated times in "server clock" // this will overwrite any changes we made locally to this AvatarData's _identityUpdatedAt diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 7b24ae6cd7..036e862b1d 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -110,9 +110,7 @@ const char LEFT_HAND_POINTING_FLAG = 1; const char RIGHT_HAND_POINTING_FLAG = 2; const char IS_FINGER_POINTING_FLAG = 4; -const qint64 AVATAR_UPDATE_TIMEOUT = 5 * USECS_PER_SECOND; - -// AvatarData state flags - we store the details about the packet encoding in the first byte, +// AvatarData state flags - we store the details about the packet encoding in the first byte, // before the "header" structure const char AVATARDATA_FLAGS_MINIMUM = 0; @@ -568,7 +566,6 @@ public: void setOwningAvatarMixer(const QWeakPointer& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; } - int getUsecsSinceLastUpdate() const { return _averageBytesReceived.getUsecsSinceLastEvent(); } int getAverageBytesReceivedPerSecond() const; int getReceiveRate() const; @@ -604,9 +601,6 @@ public: return _lastSentJointData; } - - bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_UPDATE_TIMEOUT; } - static const float OUT_OF_VIEW_PENALTY; static void sortAvatars( @@ -631,7 +625,7 @@ public: signals: void displayNameChanged(); - + public slots: void sendAvatarDataPacket(); void sendIdentityPacket(); diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index e944c7c887..21ea8081c7 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -57,7 +57,7 @@ public slots: protected slots: void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID); - virtual void processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode); + void processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode); void processAvatarIdentityPacket(QSharedPointer message, SharedNodePointer sendingNode); void processKillAvatar(QSharedPointer message, SharedNodePointer sendingNode); void processExitingSpaceBubble(QSharedPointer message, SharedNodePointer sendingNode);