diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4736362fcb..749b617dbe 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -972,7 +972,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) { recorder->recordFrame(FRAME_TYPE, toFrame(*this)); } - locationChanged(true, false); + locationChanged(true, true); // if a entity-child of this avatar has moved outside of its queryAACube, update the cube and tell the entity server. auto entityTreeRenderer = qApp->getEntities(); EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr; @@ -981,16 +981,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) { entityTree->withWriteLock([&] { zoneInteractionProperties = entityTreeRenderer->getZoneInteractionProperties(); EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender(); - forEachDescendant([&](SpatiallyNestablePointer object) { - locationChanged(true, false); - // we need to update attached queryAACubes in our own local tree so point-select always works - // however we don't want to flood the update pipeline with AvatarEntity updates, so we assume - // others have all info required to properly update queryAACube of AvatarEntities on their end - EntityItemPointer entity = std::dynamic_pointer_cast(object); - bool iShouldTellServer = !(entity && entity->isAvatarEntity()); - const bool force = false; - entityTree->updateEntityQueryAACube(object, packetSender, force, iShouldTellServer); - }); + entityTree->updateEntityQueryAACube(shared_from_this(), packetSender, false, true); }); bool isPhysicsEnabled = qApp->isPhysicsEnabled(); bool zoneAllowsFlying = zoneInteractionProperties.first; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 1c1b3a41f5..fedda7a42e 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -3194,21 +3194,30 @@ glm::vec3 EntityTree::getUnscaledDimensionsForID(const QUuid& id) { return glm::vec3(1.0f); } -void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender, +AACube EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender, MovingEntitiesOperator& moveOperator, bool force, bool tellServer) { + glm::vec3 min(FLT_MAX); + glm::vec3 max(-FLT_MAX); + // if the queryBox has changed, tell the entity-server EntityItemPointer entity = std::dynamic_pointer_cast(object); if (entity) { bool queryAACubeChanged = false; if (!entity->hasChildren()) { - // updateQueryAACube will also update all ancestors' AACubes, so we only need to call this for leaf nodes - queryAACubeChanged = entity->updateQueryAACube(); + queryAACubeChanged = entity->updateQueryAACube(false); + AACube entityAACube = entity->getQueryAACube(); + min = glm::min(min, entityAACube.getMinimumPoint()); + max = glm::max(max, entityAACube.getMaximumPoint()); } else { - AACube oldCube = entity->getQueryAACube(); object->forEachChild([&](SpatiallyNestablePointer descendant) { - updateEntityQueryAACubeWorker(descendant, packetSender, moveOperator, force, tellServer); + AACube entityAACube = updateEntityQueryAACubeWorker(descendant, packetSender, moveOperator, force, tellServer); + min = glm::min(min, entityAACube.getMinimumPoint()); + max = glm::max(max, entityAACube.getMaximumPoint()); }); - queryAACubeChanged = oldCube != entity->getQueryAACube(); + queryAACubeChanged = entity->updateQueryAACubeWithDescendantAACube(AACube(Extents(min, max)), false); + AACube newCube = entity->getQueryAACube(); + min = glm::min(min, newCube.getMinimumPoint()); + max = glm::max(max, newCube.getMaximumPoint()); } if (queryAACubeChanged || force) { @@ -3217,9 +3226,10 @@ void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, if (success) { moveOperator.addEntityToMoveList(entity, newCube); } - // send an edit packet to update the entity-server about the queryAABox. We do this for domain-hosted - // entities as well as for avatar-entities; the packet-sender will route the update accordingly - if (tellServer && packetSender && (entity->isDomainEntity() || entity->isAvatarEntity())) { + // send an edit packet to update the entity-server about the queryAABox. We only do this for domain-hosted + // entities, as we don't want to flood the update pipeline with AvatarEntity updates, so we assume + // others have all info required to properly update queryAACube of AvatarEntities on their end + if (tellServer && packetSender && entity->isDomainEntity()) { quint64 now = usecTimestampNow(); EntityItemProperties properties = entity->getProperties(); properties.setQueryAACubeDirty(); @@ -3234,7 +3244,16 @@ void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, entity->markDirtyFlags(Simulation::DIRTY_POSITION); entityChanged(entity); } + } else { + // if we're called on a non-entity, we might still have entity descendants + object->forEachChild([&](SpatiallyNestablePointer descendant) { + AACube entityAACube = updateEntityQueryAACubeWorker(descendant, packetSender, moveOperator, force, tellServer); + min = glm::min(min, entityAACube.getMinimumPoint()); + max = glm::max(max, entityAACube.getMaximumPoint()); + }); } + + return AACube(Extents(min, max)); } void EntityTree::updateEntityQueryAACube(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender, diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 3662f6acf0..2d5119d626 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -400,8 +400,9 @@ private: std::map _namedPaths; - void updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender, - MovingEntitiesOperator& moveOperator, bool force, bool tellServer); + // Return an AACube containing object and all its entity descendants + AACube updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender, + MovingEntitiesOperator& moveOperator, bool force, bool tellServer); }; void convertGrabUserDataToProperties(EntityItemProperties& properties); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 8387270905..c1c1fd38d9 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -1144,7 +1144,7 @@ AACube SpatiallyNestable::calculateInitialQueryAACube(bool& success) { } } -bool SpatiallyNestable::updateQueryAACube() { +bool SpatiallyNestable::updateQueryAACube(bool updateParent) { if (!queryAACubeNeedsUpdate()) { return false; } @@ -1171,9 +1171,39 @@ bool SpatiallyNestable::updateQueryAACube() { _queryAACubeSet = true; - auto parent = getParentPointer(success); - if (success && parent) { - parent->updateQueryAACube(); + if (updateParent) { + auto parent = getParentPointer(success); + if (success && parent) { + parent->updateQueryAACube(); + } + } + + return true; +} + +bool SpatiallyNestable::updateQueryAACubeWithDescendantAACube(const AACube& descendantAACube, bool updateParent) { + if (!queryAACubeNeedsUpdateWithDescendantAACube(descendantAACube)) { + return false; + } + + bool success; + AACube initialQueryAACube = calculateInitialQueryAACube(success); + if (!success) { + return false; + } + _queryAACube = initialQueryAACube; + _queryAACubeIsPuffed = shouldPuffQueryAACube(); + + _queryAACube += descendantAACube.getMinimumPoint(); + _queryAACube += descendantAACube.getMaximumPoint(); + + _queryAACubeSet = true; + + if (updateParent) { + auto parent = getParentPointer(success); + if (success && parent) { + parent->updateQueryAACube(); + } } return true; @@ -1216,6 +1246,24 @@ bool SpatiallyNestable::queryAACubeNeedsUpdate() const { return childNeedsUpdate; } +bool SpatiallyNestable::queryAACubeNeedsUpdateWithDescendantAACube(const AACube& descendantAACube) const { + if (!_queryAACubeSet) { + return true; + } + + bool success; + AACube maxAACube = getMaximumAACube(success); + if (success && !_queryAACube.contains(maxAACube)) { + return true; + } + + if (shouldPuffQueryAACube() != _queryAACubeIsPuffed) { + return true; + } + + return !_queryAACube.contains(descendantAACube); +} + AACube SpatiallyNestable::getQueryAACube(bool& success) const { if (_queryAACubeSet) { success = true; diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index f52dc4bf8b..01e3b045ad 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -117,8 +117,10 @@ public: virtual void setQueryAACube(const AACube& queryAACube); virtual bool queryAACubeNeedsUpdate() const; + virtual bool queryAACubeNeedsUpdateWithDescendantAACube(const AACube& descendantAACube) const; virtual bool shouldPuffQueryAACube() const { return false; } - bool updateQueryAACube(); + bool updateQueryAACube(bool updateParent = true); + bool updateQueryAACubeWithDescendantAACube(const AACube& descendentAACube, bool updateParent = true); void forceQueryAACubeUpdate() { _queryAACubeSet = false; } virtual AACube getQueryAACube(bool& success) const; virtual AACube getQueryAACube() const;