From 99e1fdd46e227cde5412a21496db593ef6219648 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Sat, 10 Jan 2015 07:44:26 -0800
Subject: [PATCH] fix for EntityServer crash

adding EntityItem::_element backpointer for easier add/remove logic
---
 .../src/EntityTreeRenderer.cpp                |  2 +
 libraries/entities/src/EntityItem.cpp         |  3 +
 libraries/entities/src/EntityItem.h           |  4 ++
 libraries/entities/src/EntityTreeElement.cpp  | 13 ++++-
 .../entities/src/MovingEntitiesOperator.cpp   | 15 +++--
 .../entities/src/UpdateEntityOperator.cpp     | 57 ++++++++-----------
 6 files changed, 55 insertions(+), 39 deletions(-)

diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
index 47e9237ddc..3518e7b75c 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
@@ -98,7 +98,9 @@ void EntityTreeRenderer::init() {
 }
 
 QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID) {
+    _tree->lockForRead();
     EntityItem* entity = static_cast<EntityTree*>(_tree)->findEntityByEntityItemID(entityItemID);
+    _tree->unlock();
     return loadEntityScript(entity);
 }
 
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index a744d39f05..6917dc1e7d 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -95,6 +95,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) {
     _physicsInfo = NULL;
     _dirtyFlags = 0;
     _changedOnServer = 0;
+    _element = NULL;
     initFromEntityItemID(entityItemID);
 }
 
@@ -110,6 +111,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert
     _physicsInfo = NULL;
     _dirtyFlags = 0;
     _changedOnServer = 0;
+    _element = NULL;
     initFromEntityItemID(entityItemID);
     setProperties(properties);
 }
@@ -117,6 +119,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert
 EntityItem::~EntityItem() {
     // be sure to clean up _physicsInfo before calling this dtor
     assert(_physicsInfo == NULL);
+    assert(_element == NULL);
 }
 
 EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index e52be1707a..6d422ab257 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -39,6 +39,7 @@ class EntityTreeElementExtraEncodeData;
 /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate
 /// one directly, instead you must only construct one of it's derived classes with additional features.
 class EntityItem  {
+    friend class EntityTreeElement;
 
 public:
     enum EntityDirtyFlags {
@@ -301,6 +302,7 @@ public:
     void* getPhysicsInfo() const { return _physicsInfo; }
     void setPhysicsInfo(void* data) { _physicsInfo = data; }
     
+    EntityTreeElement* getElement() const { return _element; }
 protected:
 
     virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
@@ -362,6 +364,8 @@ protected:
 
     // DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about.
     uint32_t _dirtyFlags;   // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation
+
+    EntityTreeElement* _element;    // back pointer to containing Element
 };
 
 
diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp
index 5f072164a0..4ced5fe844 100644
--- a/libraries/entities/src/EntityTreeElement.cpp
+++ b/libraries/entities/src/EntityTreeElement.cpp
@@ -682,6 +682,7 @@ void EntityTreeElement::cleanupEntities() {
     uint16_t numberOfEntities = _entityItems->size();
     for (uint16_t i = 0; i < numberOfEntities; i++) {
         EntityItem* entity = (*_entityItems)[i];
+        entity->_element = NULL;
         delete entity;
     }
     _entityItems->clear();
@@ -693,6 +694,7 @@ bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) {
     for (uint16_t i = 0; i < numberOfEntities; i++) {
         if ((*_entityItems)[i]->getEntityItemID() == id) {
             foundEntity = true;
+            (*_entityItems)[i]->_element = NULL;
             _entityItems->removeAt(i);
             break;
         }
@@ -701,7 +703,13 @@ bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) {
 }
 
 bool EntityTreeElement::removeEntityItem(EntityItem* entity) {
-    return _entityItems->removeAll(entity) > 0;
+    int numEntries = _entityItems->removeAll(entity);
+    if (numEntries > 0) {
+        assert(entity->_element == this);
+        entity->_element = NULL;
+        return true;
+    }
+    return false;
 }
 
 
@@ -808,7 +816,10 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
 }
 
 void EntityTreeElement::addEntityItem(EntityItem* entity) {
+    assert(entity);
+    assert(entity->_element == NULL);
     _entityItems->push_back(entity);
+    entity->_element = this;
 }
 
 // will average a "common reduced LOD view" from the the child elements...
diff --git a/libraries/entities/src/MovingEntitiesOperator.cpp b/libraries/entities/src/MovingEntitiesOperator.cpp
index 1ec67967b6..48ba8e4ec2 100644
--- a/libraries/entities/src/MovingEntitiesOperator.cpp
+++ b/libraries/entities/src/MovingEntitiesOperator.cpp
@@ -179,7 +179,7 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) {
 
             // If this is one of the old elements we're looking for, then ask it to remove the old entity
             if (!details.oldFound && entityTreeElement == details.oldContainingElement) {
-                entityTreeElement->removeEntityItem(details.entity);
+                // DO NOT remove the entity here.  It will be removed when added to the destination element.
                 _foundOldCount++;
                 //details.oldFound = true; // TODO: would be nice to add this optimization
                 if (_wantDebug) {
@@ -193,8 +193,15 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) {
             // If this element is the best fit for the new bounds of this entity then add the entity to the element
             if (!details.newFound && entityTreeElement->bestFitBounds(details.newCube)) {
                 EntityItemID entityItemID = details.entity->getEntityItemID();
-                entityTreeElement->addEntityItem(details.entity);
-                _tree->setContainingElement(entityItemID, entityTreeElement);
+                // remove from the old before adding
+                EntityTreeElement* oldElement = details.entity->getElement();
+                if (oldElement != entityTreeElement) {
+                    if (oldElement) {
+                        oldElement->removeEntityItem(details.entity);
+                    }
+                    entityTreeElement->addEntityItem(details.entity);
+                    _tree->setContainingElement(entityItemID, entityTreeElement);
+                }
                 _foundNewCount++;
                 //details.newFound = true; // TODO: would be nice to add this optimization
                 if (_wantDebug) {
@@ -227,7 +234,7 @@ bool MovingEntitiesOperator::postRecursion(OctreeElement* element) {
     
 
 
-    // It's not OK to prune if we have the potential of deleting the original containig element.
+    // It's not OK to prune if we have the potential of deleting the original containing element
     // because if we prune the containing element then new might end up reallocating the same memory later 
     // and that will confuse our logic.
     // 
diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp
index 9cee11d73c..c85c4235de 100644
--- a/libraries/entities/src/UpdateEntityOperator.cpp
+++ b/libraries/entities/src/UpdateEntityOperator.cpp
@@ -231,18 +231,19 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) {
                     qDebug() << "    *** REMOVING from ELEMENT ***";
                 }
 
-                entityTreeElement->removeEntityItem(_existingEntity); // NOTE: only removes the entity, doesn't delete it
+                // the entity knows what element it's in, so we remove it from that one
+                // NOTE: we know we haven't yet added it to its new element because _removeOld is true
+                EntityTreeElement* oldElement = _existingEntity->getElement();
+                oldElement->removeEntityItem(_existingEntity);
+                _tree->setContainingElement(_entityItemID, NULL);
 
-                // If we haven't yet found the new location, then we need to 
-                // make sure to remove our entity to element map, because for
-                // now we're not in that map
-                if (!_foundNew) {
-                    _tree->setContainingElement(_entityItemID, NULL);
-
-                    if (_wantDebug) {
-                        qDebug() << "    *** REMOVING from MAP ***";
-                    }
+                if (oldElement != _containingElement) {
+                    qDebug() << "WARNING entity moved during UpdateEntityOperator recursion";
+                    assert(! _containingElement->removeEntityItem(_existingEntity));
+                }
 
+                if (_wantDebug) {
+                    qDebug() << "    *** REMOVING from MAP ***";
                 }
             }
             _foundOld = true;
@@ -263,7 +264,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) {
             qDebug() << "    entityTreeElement->bestFitBounds(_newEntityBox)=" << entityTreeElement->bestFitBounds(_newEntityBox);
         }
 
-
         // If this element is the best fit for the new entity properties, then add/or update it
         if (entityTreeElement->bestFitBounds(_newEntityBox)) {
 
@@ -271,33 +271,14 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) {
                 qDebug() << "    *** THIS ELEMENT IS BEST FIT ***";
             }
 
+            EntityTreeElement* oldElement = _existingEntity->getElement();
             // if we are the existing containing element, then we can just do the update of the entity properties
-            if (entityTreeElement == _containingElement) {
+            if (entityTreeElement == oldElement) {
 
                 if (_wantDebug) {
                     qDebug() << "    *** This is the same OLD ELEMENT ***";
                 }
             
-                // TODO: We shouldn't be in a remove old case and also be the new best fit. This indicates that
-                // we have some kind of a logic error in this operator. But, it can handle it properly by setting
-                // the new properties for the entity and moving on. Still going to output a warning that if we
-                // see consistently we will want to address this.
-                if (_removeOld) {
-                    qDebug() << "UNEXPECTED - UpdateEntityOperator - "
-                                "we thought we needed to removeOld, but the old entity is our best fit.";
-                    _removeOld = false;
-                    
-                    // if we thought we were supposed to remove the old item, and we already did, then we need
-                    // to repair this case.
-                    if (_foundOld) {
-                        if (_wantDebug) {
-                            qDebug() << "    *** REPAIRING PREVIOUS REMOVAL from ELEMENT and MAP ***";
-                        }
-                        entityTreeElement->addEntityItem(_existingEntity);
-                        _tree->setContainingElement(_entityItemID, entityTreeElement);
-                    }
-                }
-
                 // set the entity properties and mark our element as changed.
                 _existingEntity->setProperties(_properties);
                 if (_wantDebug) {
@@ -305,14 +286,22 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) {
                 }
             } else {
                 // otherwise, this is an add case.
+                if (oldElement) {
+                    oldElement->removeEntityItem(_existingEntity);
+                    if (oldElement != _containingElement) {
+                        qDebug() << "WARNING entity moved during UpdateEntityOperator recursion";
+                    }
+                }
                 entityTreeElement->addEntityItem(_existingEntity);
-                _existingEntity->setProperties(_properties); // still need to update the properties!
                 _tree->setContainingElement(_entityItemID, entityTreeElement);
+
+                _existingEntity->setProperties(_properties); // still need to update the properties!
                 if (_wantDebug) {
                     qDebug() << "    *** ADDING ENTITY to ELEMENT and MAP and SETTING PROPERTIES ***";
                 }
             }
-            _foundNew = true; // we found the new item!
+            _foundNew = true; // we found the new element
+            _removeOld = false; // and it has already been removed from the old
         } else {
             keepSearching = true;
         }