void AvatarManager::removeDeadAvatarEntities(const SetOfEntities& deadEntities) { auto treeRenderer = DependencyManager::get<EntityTreeRenderer>(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; for (auto entity : deadEntities) { QUuid entityOwnerID = entity->getOwningAvatarID(); AvatarSharedPointer avatar = getAvatarBySessionID(entityOwnerID); const bool REQUIRES_REMOVAL_FROM_TREE = false; if (avatar) { avatar->clearAvatarEntity(entity->getID(), REQUIRES_REMOVAL_FROM_TREE); } if (entityTree && entity->isMyAvatarEntity()) { entityTree->withWriteLock([&] { // We only need to delete the direct children (rather than the descendants) because // when the child is deleted, it will take care of its own children. If the child // is also an avatar-entity, we'll end up back here. If it's not, the entity-server // will take care of it in the usual way. entity->forEachChild([&](SpatiallyNestablePointer child) { EntityItemPointer childEntity = std::dynamic_pointer_cast<EntityItem>(child); if (childEntity) { entityTree->deleteEntity(childEntity->getID(), true, true); if (avatar) { avatar->clearAvatarEntity(childEntity->getID(), REQUIRES_REMOVAL_FROM_TREE); } } }); }); } } }
void AvatarManager::updateOtherAvatars(float deltaTime) { if (_avatarHash.size() < 2 && _avatarFades.isEmpty()) { return; } bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateAvatars()"); PerformanceTimer perfTimer("otherAvatars"); // simulate avatars AvatarHash::iterator avatarIterator = _avatarHash.begin(); while (avatarIterator != _avatarHash.end()) { AvatarSharedPointer sharedAvatar = avatarIterator.value(); Avatar* avatar = reinterpret_cast<Avatar*>(sharedAvatar.data()); if (sharedAvatar == _myAvatar || !avatar->isInitialized()) { // DO NOT update _myAvatar! Its update has already been done earlier in the main loop. // DO NOT update uninitialized Avatars ++avatarIterator; continue; } if (!shouldKillAvatar(sharedAvatar)) { // this avatar's mixer is still around, go ahead and simulate it avatar->simulate(deltaTime); ++avatarIterator; } else { // the mixer that owned this avatar is gone, give it to the vector of fades and kill it avatarIterator = erase(avatarIterator); } } // simulate avatar fades simulateAvatarFades(deltaTime); }
void AvatarManager::removeDeadAvatarEntities(const SetOfEntities& deadEntities) { for (auto entity : deadEntities) { QUuid sessionID = entity->getOwningAvatarID(); AvatarSharedPointer avatar = getAvatarBySessionID(sessionID); if (avatar) { const bool REQUIRES_REMOVAL_FROM_TREE = false; avatar->clearAvatarEntity(entity->getID(), REQUIRES_REMOVAL_FROM_TREE); } } }
void AvatarHashMap::processAvatarBillboardPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer) { int headerSize = numBytesForPacketHeader(packet); QUuid sessionUUID = QUuid::fromRfc4122(QByteArray::fromRawData(packet.constData() + headerSize, NUM_BYTES_RFC4122_UUID)); AvatarSharedPointer matchingAvatar = matchingOrNewAvatar(sessionUUID, mixerWeakPointer); if (matchingAvatar) { QByteArray billboard = packet.mid(headerSize + NUM_BYTES_RFC4122_UUID); if (matchingAvatar->getBillboard() != billboard) { matchingAvatar->setBillboard(billboard); } } }
AvatarSharedPointer AvatarHashMap::matchingOrNewAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) { AvatarSharedPointer matchingAvatar = _avatarHash.value(sessionUUID); if (!matchingAvatar) { // insert the new avatar into our hash matchingAvatar = newSharedAvatar(); qDebug() << "Adding avatar with sessionUUID " << sessionUUID << "to AvatarHashMap."; _avatarHash.insert(sessionUUID, matchingAvatar); matchingAvatar->setOwningAvatarMixer(mixerWeakPointer); } return matchingAvatar; }
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar) { AvatarHashMap::handleRemovedAvatar(removedAvatar); removedAvatar->die(); removeAvatarMotionState(removedAvatar); _avatarFades.push_back(removedAvatar); }
void AvatarHashMap::processAvatarDataPacket(const QByteArray &datagram, const QWeakPointer<Node> &mixerWeakPointer) { int bytesRead = numBytesForPacketHeader(datagram); // enumerate over all of the avatars in this packet // only add them if mixerWeakPointer points to something (meaning that mixer is still around) while (bytesRead < datagram.size() && mixerWeakPointer.data()) { QUuid sessionUUID = QUuid::fromRfc4122(datagram.mid(bytesRead, NUM_BYTES_RFC4122_UUID)); bytesRead += NUM_BYTES_RFC4122_UUID; if (sessionUUID != _lastOwnerSessionUUID) { AvatarSharedPointer matchingAvatarData = matchingOrNewAvatar(sessionUUID, mixerWeakPointer); // have the matching (or new) avatar parse the data from the packet bytesRead += matchingAvatarData->parseDataAtOffset(datagram, bytesRead); } else { // create a dummy AvatarData class to throw this data on the ground AvatarData dummyData; bytesRead += dummyData.parseDataAtOffset(datagram, bytesRead); } } }
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar) { AvatarHashMap::handleRemovedAvatar(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<Avatar*>(removedAvatar.get()); avatar->die(); AvatarMotionState* motionState = avatar->getMotionState(); if (motionState) { _motionStatesThatMightUpdate.remove(motionState); _motionStatesToAddToPhysics.remove(motionState); _motionStatesToRemoveFromPhysics.push_back(motionState); } _avatarFades.push_back(removedAvatar); }
void AvatarHashMap::processAvatarIdentityPacket(const QByteArray &packet, const QWeakPointer<Node>& mixerWeakPointer) { // setup a data stream to parse the packet QDataStream identityStream(packet); identityStream.skipRawData(numBytesForPacketHeader(packet)); QUuid sessionUUID; while (!identityStream.atEnd()) { QUrl faceMeshURL, skeletonURL; QVector<AttachmentData> attachmentData; QString displayName; identityStream >> sessionUUID >> faceMeshURL >> skeletonURL >> attachmentData >> displayName; // mesh URL for a UUID, find avatar in our list AvatarSharedPointer matchingAvatar = matchingOrNewAvatar(sessionUUID, mixerWeakPointer); if (matchingAvatar) { if (matchingAvatar->getFaceModelURL() != faceMeshURL) { matchingAvatar->setFaceModelURL(faceMeshURL); } if (matchingAvatar->getSkeletonModelURL() != skeletonURL) { matchingAvatar->setSkeletonModelURL(skeletonURL); } if (matchingAvatar->getAttachmentData() != attachmentData) { matchingAvatar->setAttachmentData(attachmentData); } if (matchingAvatar->getDisplayName() != displayName) { matchingAvatar->setDisplayName(displayName); } } } }
bool AvatarHashMap::shouldKillAvatar(const AvatarSharedPointer& sharedAvatar) { return (sharedAvatar->getOwningAvatarMixer() == NULL || sharedAvatar->getLastUpdateTimer().elapsed() > AVATAR_SILENCE_THRESHOLD_MSECS); }
void AvatarHashMap::insert(const QUuid& sessionUUID, AvatarSharedPointer avatar) { _avatarHash.insert(sessionUUID, avatar); avatar->setSessionUUID(sessionUUID); }