From 8b2d12e2f743b50e899ab69796e24de11834aba0 Mon Sep 17 00:00:00 2001
From: Seth Alves <seth.alves@gmail.com>
Date: Thu, 9 May 2019 09:00:27 -0700
Subject: [PATCH] when an avatar entity is deleted, also delete its descendants

---
 interface/src/avatar/AvatarManager.cpp | 25 ++++++++++++++++++++++---
 libraries/entities/src/EntityItem.cpp  |  4 ++++
 libraries/entities/src/EntityItem.h    |  1 +
 3 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp
index cea1a4a654..df620b9a08 100755
--- a/interface/src/avatar/AvatarManager.cpp
+++ b/interface/src/avatar/AvatarManager.cpp
@@ -532,13 +532,32 @@ void AvatarManager::handleProcessedPhysicsTransaction(PhysicsEngine::Transaction
 }
 
 void AvatarManager::removeDeadAvatarEntities(const SetOfEntities& deadEntities) {
+    auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
+    EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
     for (auto entity : deadEntities) {
-        QUuid sessionID = entity->getOwningAvatarID();
-        AvatarSharedPointer avatar = getAvatarBySessionID(sessionID);
+        QUuid entityOwnerID = entity->getOwningAvatarID();
+        AvatarSharedPointer avatar = getAvatarBySessionID(entityOwnerID);
+        const bool REQUIRES_REMOVAL_FROM_TREE = false;
         if (avatar) {
-            const bool REQUIRES_REMOVAL_FROM_TREE = false;
             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);
+                        }
+                    }
+                });
+            });
+        }
     }
 }
 
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index d91c11e726..4232e9d1b9 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -3431,6 +3431,10 @@ bool EntityItem::isWearable() const {
         (getParentID() == DependencyManager::get<NodeList>()->getSessionUUID() || getParentID() == AVATAR_SELF_ID);
 }
 
+bool EntityItem::isMyAvatarEntity() const {
+    return _hostType == entity::HostType::AVATAR && Physics::getSessionUUID() == _owningAvatarID;
+};
+
 void EntityItem::addGrab(GrabPointer grab) {
     enableNoBootstrap();
     SpatiallyNestable::addGrab(grab);
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index ea4b11e0b0..a8c3d31344 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -503,6 +503,7 @@ public:
     virtual bool isWearable() const;
     bool isDomainEntity() const { return _hostType == entity::HostType::DOMAIN; }
     bool isAvatarEntity() const { return _hostType == entity::HostType::AVATAR; }
+    bool isMyAvatarEntity() const;
     bool isLocalEntity() const { return _hostType == entity::HostType::LOCAL; }
     entity::HostType getEntityHostType() const { return _hostType; }
     virtual void setEntityHostType(entity::HostType hostType) { _hostType = hostType; }