From dd3a7b9b9dc20c396a482973b973aaa741cf4d7d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 26 Nov 2014 12:12:43 -0800 Subject: [PATCH] EntitySimulation takes EntityItem* rather than ID --- .../src/entities}/EntityCollisionSystem.cpp | 0 .../src/entities}/EntityCollisionSystem.h | 0 .../entities/src/DeleteEntityOperator.cpp | 15 +- libraries/entities/src/EntitySimulation.cpp | 20 ++ libraries/entities/src/EntitySimulation.h | 28 +- libraries/entities/src/EntityTree.cpp | 258 ++++-------------- libraries/entities/src/EntityTree.h | 22 +- libraries/entities/src/EntityTreeElement.cpp | 1 - .../entities/src/SimpleEntitySimulation.cpp | 89 +++--- .../entities/src/SimpleEntitySimulation.h | 21 +- 10 files changed, 162 insertions(+), 292 deletions(-) rename {libraries/entities/src => interface/src/entities}/EntityCollisionSystem.cpp (100%) rename {libraries/entities/src => interface/src/entities}/EntityCollisionSystem.h (100%) create mode 100644 libraries/entities/src/EntitySimulation.cpp diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/interface/src/entities/EntityCollisionSystem.cpp similarity index 100% rename from libraries/entities/src/EntityCollisionSystem.cpp rename to interface/src/entities/EntityCollisionSystem.cpp diff --git a/libraries/entities/src/EntityCollisionSystem.h b/interface/src/entities/EntityCollisionSystem.h similarity index 100% rename from libraries/entities/src/EntityCollisionSystem.h rename to interface/src/entities/EntityCollisionSystem.h diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index 5b0ada4ec1..12441e5427 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -48,9 +48,6 @@ void DeleteEntityOperator::addEntityIDToDeleteList(const EntityItemID& searchEnt details.cube = details.containingElement->getAACube(); _entitiesToDelete << details; _lookingCount++; - _tree->trackDeletedEntity(searchEntityID); - // before deleting any entity make sure to remove it from our Mortal, Changing, and Moving lists - _tree->removeEntityFromSimulationLists(searchEntityID); } } } @@ -78,13 +75,9 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { EntityTreeElement* entityTreeElement = static_cast(element); // In Pre-recursion, we're generally deciding whether or not we want to recurse this - // path of the tree. For this operation, we want to recurse the branch of the tree if - // and of the following are true: - // * We have not yet found the old entity, and this branch contains our old entity - // * We have not yet found the new entity, and this branch contains our new entity - // - // Note: it's often the case that the branch in question contains both the old entity - // and the new entity. + // path of the tree. For this operation, we want to recurse the branch of the tree if: + // * We have not yet found the all entities, and + // * this branch contains our some of the entities we're looking for. bool keepSearching = false; // assume we don't need to search any more @@ -100,6 +93,8 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { if (entityTreeElement == details.containingElement) { EntityItemID entityItemID = details.entity->getEntityItemID(); EntityItem* theEntity = entityTreeElement->getEntityWithEntityItemID(entityItemID); // find the actual entity + assert(theEntity); + _tree->trackDeletedEntity(theEntity); entityTreeElement->removeEntityItem(theEntity); // remove it from the element _tree->setContainingElement(entityItemID, NULL); // update or id to element lookup delete theEntity; // now actually delete the entity! diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp new file mode 100644 index 0000000000..8058c2f24e --- /dev/null +++ b/libraries/entities/src/EntitySimulation.cpp @@ -0,0 +1,20 @@ +// +// EntitySimulation.cpp +// libraries/entities/src +// +// Created by Andrew Meadows on 2014.11.24 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "EntitySimulation.h" + +void EntitySimulation::setEntityTree(EntityTree* tree) { + if (_entityTree && _entityTree != tree) { + clearEntities(); + } + _entityTree = tree; +} + diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 230e744a16..770d6ebdb0 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -14,24 +14,36 @@ #include -#include "EntityItemID.h" #include "EntityTree.h" class EntitySimulation { public: - EntitySimulation(EntityTree* tree) : _myTree(tree) { assert(tree); } - virtual ~EntitySimulation() { _myTree = NULL; } + EntitySimulation() : _entityTree(NULL) { } + virtual ~EntitySimulation() {} - /// \sideeffect For each EntityItem* that EntitySimulation puts on entitiesToDelete it will automatically - /// removeEntity() on any internal lists -- no need to call removeEntity() for that one later. - virtual void update(QSet& entitiesToDelete) = 0; + /// \param tree pointer to EntityTree which is stored internally + virtual void setEntityTree(EntityTree* tree); + /// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted. + virtual void update(QSet& entitiesToDelete) = 0; + + /// \param entity pointer to EntityItem to add to the simulation + /// \sideeffect the EntityItem::_simulationState member may be updated to indicate membership to internal list virtual void addEntity(EntityItem* entity) = 0; + + /// \param entity pointer to EntityItem to removed from the simulation + /// \sideeffect the EntityItem::_simulationState member may be updated to indicate non-membership to internal list virtual void removeEntity(EntityItem* entity) = 0; - virtual void updateEntity(EntityItem* entity) = 0; + + /// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation + virtual void entityChanged(EntityItem* entity) = 0; + + virtual void clearEntities() = 0; + + EntityTree* getEntityTree() { return _entityTree; } protected: - EntityTree* _myTree; + EntityTree* _entityTree; }; #endif // hifi_EntitySimulation_h diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index bb201b6f86..5d4c5b0fc4 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -12,13 +12,14 @@ #include #include "EntityTree.h" +#include "EntitySimulation.h" #include "AddEntityOperator.h" #include "DeleteEntityOperator.h" #include "MovingEntitiesOperator.h" #include "UpdateEntityOperator.h" -EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage) { +EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage), _simulation(NULL) { _rootElement = createNewElement(); } @@ -34,14 +35,14 @@ EntityTreeElement* EntityTree::createNewElement(unsigned char * octalCode) { void EntityTree::eraseAllOctreeElements(bool createNewRoot) { // this would be a good place to clean up our entities... + if (_simulation) { + _simulation->clearEntities(); + } foreach (EntityTreeElement* element, _entityToElementMap) { element->cleanupEntities(); } _entityToElementMap.clear(); Octree::eraseAllOctreeElements(createNewRoot); - _movingEntities.clear(); - _mortalEntities.clear(); - _changedEntities.clear(); } bool EntityTree::handlesEditPacketType(PacketType packetType) const { @@ -89,13 +90,14 @@ void EntityTree::addEntityItem(EntityItem* entityItem) { recurseTreeWithOperator(&theOperator); // check to see if we need to simulate this entity.. - updateEntityState(entityItem); + if (_simulation) { + _simulation->addEntity(entityItem); + } _isDirty = true; } bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties) { - // You should not call this on existing entities that are already part of the tree! Call updateEntity() EntityTreeElement* containingElement = getContainingElement(entityID); if (!containingElement) { qDebug() << "UNEXPECTED!!!! EntityTree::updateEntity() entityID doesn't exist!!! entityID=" << entityID; @@ -119,6 +121,9 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp UpdateEntityOperator theOperator(this, containingElement, existingEntity, tempProperties); recurseTreeWithOperator(&theOperator); _isDirty = true; + if (_simulation && existingEntity->getUpdateFlags() != 0) { + _simulation->entityChanged(existingEntity); + } } } } else { @@ -129,13 +134,14 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp recurseTreeWithOperator(&theOperator); _isDirty = true; - updateEntityState(existingEntity); + if (_simulation && existingEntity->getUpdateFlags() != 0) { + _simulation->entityChanged(existingEntity); + } QString entityScriptAfter = existingEntity->getScript(); if (entityScriptBefore != entityScriptAfter) { emitEntityScriptChanging(entityID); // the entity script has changed } - } containingElement = getContainingElement(entityID); @@ -179,13 +185,16 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem } -void EntityTree::trackDeletedEntity(const EntityItemID& entityID) { +void EntityTree::trackDeletedEntity(EntityItem* entity) { + if (_simulation) { + _simulation->removeEntity(entity); + } // this is only needed on the server to send delete messages for recently deleted entities to the viewers if (getIsServer()) { // set up the deleted entities ID quint64 deletedAt = usecTimestampNow(); _recentlyDeletedEntitiesLock.lockForWrite(); - _recentlyDeletedEntityItemIDs.insert(deletedAt, entityID.id); + _recentlyDeletedEntityItemIDs.insert(deletedAt, entity->getEntityItemID().id); _recentlyDeletedEntitiesLock.unlock(); } } @@ -198,6 +207,19 @@ void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) { emit entityScriptChanging(entityItemID); } +void EntityTree::setSimulation(EntitySimulation* simulation) { + if (simulation) { + // assert that the simulation's backpointer has already been properly connected + assert(simulation->getEntityTree() == this); + } + if (_simulation && _simulation != simulation) { + // It's important to clearEntities() on the simulation since taht will update each + // EntityItem::_simulationState correctly so as to not confuse the next _simulation. + _simulation->clearEntities(); + } + _simulation = simulation; +} + void EntityTree::deleteEntity(const EntityItemID& entityID) { emit deletingEntity(entityID); @@ -220,29 +242,6 @@ void EntityTree::deleteEntities(QSet entityIDs) { _isDirty = true; } -void EntityTree::removeEntityFromSimulationLists(const EntityItemID& entityID) { - EntityItem* theEntity = findEntityByEntityItemID(entityID); - - if (theEntity) { - // make sure to remove it from any of our simulation lists - EntityItem::SimulationState theState = theEntity->getSimulationState(); - switch (theState) { - case EntityItem::Moving: - _movingEntities.removeAll(theEntity); - break; - - case EntityItem::Mortal: - _mortalEntities.removeAll(theEntity); - break; - - default: - break; - } - _changedEntities.remove(theEntity); - } -} - - /// This method is used to find and fix entity IDs that are shifting from creator token based to known ID based entity IDs. /// This should only be used on a client side (viewing) tree. The typical usage is that a local editor has been creating /// entities in the local tree, those entities have creatorToken based entity IDs. But those entity edits are also sent up to @@ -575,183 +574,29 @@ void EntityTree::releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncod extraEncodeData->clear(); } -void EntityTree::updateEntityState(EntityItem* entity) { - EntityItem::SimulationState oldState = entity->getSimulationState(); - EntityItem::SimulationState newState = entity->computeSimulationState(); - if (newState != oldState) { - switch (oldState) { - case EntityItem::Moving: - _movingEntities.removeAll(entity); - break; - - case EntityItem::Mortal: - _mortalEntities.removeAll(entity); - break; - - default: - break; - } - - switch (newState) { - case EntityItem::Moving: - _movingEntities.push_back(entity); - break; - - case EntityItem::Mortal: - _mortalEntities.push_back(entity); - break; - - default: - break; - } - entity->setSimulationState(newState); - } -} - -void EntityTree::clearEntityState(EntityItem* entity) { - EntityItem::SimulationState oldState = entity->getSimulationState(); - switch (oldState) { - case EntityItem::Moving: - _movingEntities.removeAll(entity); - break; - - case EntityItem::Mortal: - _mortalEntities.removeAll(entity); - break; - - default: - break; - } - entity->setSimulationState(EntityItem::Static); -} - void EntityTree::entityChanged(EntityItem* entity) { - _changedEntities.insert(entity); + if (_simulation) { + _simulation->entityChanged(entity); + } } void EntityTree::update() { - // our new strategy should be to segregate entities into three classes: - // 1) stationary things that are not changing - most models - // 2) mortal things - these are stationary but have a lifetime - then need to be checked, - // can be touched linearly, and won't change the tree - // 2) changing things - like things animating they can be touched linearly and they don't change the tree - // 3) moving things - these need to scan the tree and update accordingly - // finally - all things that need to be deleted, can be handled on a single delete pass. - // - // TODO: theoretically we could combine the move and delete tree passes... - lockForWrite(); - quint64 now = usecTimestampNow(); - QSet entitiesToDelete; - updateChangedEntities(now, entitiesToDelete); - updateMovingEntities(now, entitiesToDelete); - updateMortalEntities(now, entitiesToDelete); - - if (entitiesToDelete.size() > 0) { - deleteEntities(entitiesToDelete); - } - unlock(); -} - -void EntityTree::updateChangedEntities(quint64 now, QSet& entitiesToDelete) { - foreach (EntityItem* thisEntity, _changedEntities) { - // check to see if the lifetime has expired, for immortal entities this is always false - if (thisEntity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); - entitiesToDelete << thisEntity->getEntityItemID(); - clearEntityState(thisEntity); - } else { - updateEntityState(thisEntity); - } - thisEntity->clearUpdateFlags(); - } - _changedEntities.clear(); -} - -void EntityTree::updateMovingEntities(quint64 now, QSet& entitiesToDelete) { - PerformanceTimer perfTimer("updateMovingEntities"); - if (_movingEntities.size() > 0) { - MovingEntitiesOperator moveOperator(this); - { - PerformanceTimer perfTimer("_movingEntities"); - - QList::iterator item_itr = _movingEntities.begin(); - while (item_itr != _movingEntities.end()) { - EntityItem* thisEntity = *item_itr; - - // always check to see if the lifetime has expired, for immortal entities this is always false - if (thisEntity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); - entitiesToDelete << thisEntity->getEntityItemID(); - // remove thisEntity from the list - item_itr = _movingEntities.erase(item_itr); - thisEntity->setSimulationState(EntityItem::Static); - } else { - AACube oldCube = thisEntity->getMaximumAACube(); - thisEntity->update(now); - AACube newCube = thisEntity->getMaximumAACube(); - - // check to see if this movement has sent the entity outside of the domain. - AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f); - if (!domainBounds.touches(newCube)) { - qDebug() << "Entity " << thisEntity->getEntityItemID() << " moved out of domain bounds."; - entitiesToDelete << thisEntity->getEntityItemID(); - // remove thisEntity from the list - item_itr = _movingEntities.erase(item_itr); - thisEntity->setSimulationState(EntityItem::Static); - } else { - moveOperator.addEntityToMoveList(thisEntity, oldCube, newCube); - EntityItem::SimulationState newState = thisEntity->computeSimulationState(); - if (newState != EntityItem::Moving) { - if (newState == EntityItem::Mortal) { - _mortalEntities.push_back(thisEntity); - } - // remove thisEntity from the list - item_itr = _movingEntities.erase(item_itr); - thisEntity->setSimulationState(newState); - } else { - ++item_itr; - } - } - } + if (_simulation) { + lockForWrite(); + QSet entitiesToDelete; + _simulation->update(entitiesToDelete); + if (entitiesToDelete.size() > 0) { + // translate into list of ID's + QSet idsToDelete; + foreach (EntityItem* entity, entitiesToDelete) { + idsToDelete.insert(entity->getEntityItemID()); } + deleteEntities(idsToDelete); } - if (moveOperator.hasMovingEntities()) { - PerformanceTimer perfTimer("recurseTreeWithOperator"); - recurseTreeWithOperator(&moveOperator); - } + unlock(); } } -void EntityTree::updateMortalEntities(quint64 now, QSet& entitiesToDelete) { - QList::iterator item_itr = _mortalEntities.begin(); - while (item_itr != _mortalEntities.end()) { - EntityItem* thisEntity = *item_itr; - thisEntity->update(now); - // always check to see if the lifetime has expired, for immortal entities this is always false - if (thisEntity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); - entitiesToDelete << thisEntity->getEntityItemID(); - // remove thisEntity from the list - item_itr = _mortalEntities.erase(item_itr); - thisEntity->setSimulationState(EntityItem::Static); - } else { - // check to see if this entity is no longer moving - EntityItem::SimulationState newState = thisEntity->computeSimulationState(); - if (newState != EntityItem::Mortal) { - if (newState == EntityItem::Moving) { - _movingEntities.push_back(thisEntity); - } - // remove thisEntity from the list - item_itr = _mortalEntities.erase(item_itr); - thisEntity->setSimulationState(newState); - } else { - ++item_itr; - } - } - } -} - - bool EntityTree::hasEntitiesDeletedSince(quint64 sinceTime) { // we can probably leverage the ordered nature of QMultiMap to do this quickly... bool hasSomethingNewer = false; @@ -966,19 +811,16 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) /*const*/ { // TODO: do we need to make this thread safe? Or is it acceptable as is - if (_entityToElementMap.contains(entityItemID)) { - return _entityToElementMap.value(entityItemID); - } else if (entityItemID.creatorTokenID != UNKNOWN_ENTITY_TOKEN){ + EntityTreeElement* element = _entityToElementMap.value(entityItemID); + if (!element && entityItemID.creatorTokenID != UNKNOWN_ENTITY_TOKEN){ // check the creator token version too... EntityItemID creatorTokenOnly; creatorTokenOnly.id = UNKNOWN_ENTITY_ID; creatorTokenOnly.creatorTokenID = entityItemID.creatorTokenID; creatorTokenOnly.isKnownID = false; - if (_entityToElementMap.contains(creatorTokenOnly)) { - return _entityToElementMap.value(creatorTokenOnly); - } + element = _entityToElementMap.value(creatorTokenOnly); } - return NULL; + return element; } // TODO: do we need to make this thread safe? Or is it acceptable as is diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 7370ebadc6..db128e4563 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -19,6 +19,7 @@ class Model; +class EntitySimulation; class NewlyCreatedEntityHook { public: @@ -84,7 +85,7 @@ public: bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties); void deleteEntity(const EntityItemID& entityID); void deleteEntities(QSet entityIDs); - void removeEntityFromSimulationLists(const EntityItemID& entityID); + void removeEntityFromSimulation(EntityItem* entity); const EntityItem* findClosestEntity(glm::vec3 position, float targetRadius); EntityItem* findEntityByID(const QUuid& id); @@ -137,18 +138,15 @@ public: void sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z); - void updateEntityState(EntityItem* entity); - void clearEntityState(EntityItem* entity); - void entityChanged(EntityItem* entity); - void trackDeletedEntity(const EntityItemID& entityID); + void trackDeletedEntity(EntityItem* entity); void emitAddingEntity(const EntityItemID& entityItemID); void emitEntityScriptChanging(const EntityItemID& entityItemID); - QList& getMovingEntities() { return _movingEntities; } - + void setSimulation(EntitySimulation* simulation); + signals: void deletingEntity(const EntityItemID& entityID); void addingEntity(const EntityItemID& entityID); @@ -157,10 +155,6 @@ signals: private: - void updateChangedEntities(quint64 now, QSet& entitiesToDelete); - void updateMovingEntities(quint64 now, QSet& entitiesToDelete); - void updateMortalEntities(quint64 now, QSet& entitiesToDelete); - static bool findNearPointOperation(OctreeElement* element, void* extraData); static bool findInSphereOperation(OctreeElement* element, void* extraData); static bool findInCubeOperation(OctreeElement* element, void* extraData); @@ -176,11 +170,7 @@ private: EntityItemFBXService* _fbxService; QHash _entityToElementMap; - - QList _movingEntities; // entities that need to be updated - QList _mortalEntities; // entities that need to be checked for expiry - - QSet _changedEntities; // entities that have changed in the last frame + EntitySimulation* _simulation; }; #endif // hifi_EntityTree_h diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 2646cc0dfd..17f7456670 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -768,7 +768,6 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int addEntityItem(entityItem); // add this new entity to this elements entities entityItemID = entityItem->getEntityItemID(); _myTree->setContainingElement(entityItemID, this); - _myTree->updateEntityState(entityItem); _myTree->emitAddingEntity(entityItemID); // we just added an entity } } diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index d8edfb8ba7..b3316978a9 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -16,7 +16,7 @@ #include "MovingEntitiesOperator.h" #include "SimpleEntitySimulation.h" -void SimpleEntitySimulation::update(QSet& entitiesToDelete) { +void SimpleEntitySimulation::update(QSet& entitiesToDelete) { quint64 now = usecTimestampNow(); updateChangedEntities(now, entitiesToDelete); updateMovingEntities(now, entitiesToDelete); @@ -56,21 +56,32 @@ void SimpleEntitySimulation::removeEntity(EntityItem* entity) { default: break; } + entity->setSimulationState(EntityItem::Static); _changedEntities.remove(entity); } -void SimpleEntitySimulation::updateEntity(EntityItem* entity) { +void SimpleEntitySimulation::entityChanged(EntityItem* entity) { assert(entity); - // we'll deal with thsi change later + // we batch all changes and deal with them in updateChangedEntities() _changedEntities.insert(entity); } + +void SimpleEntitySimulation::clearEntities() { + foreach (EntityItem* entity, _changedEntities) { + entity->clearUpdateFlags(); + entity->setSimulationState(EntityItem::Static); + } + _changedEntities.clear(); + _movingEntities.clear(); + _mortalEntities.clear(); +} -void SimpleEntitySimulation::updateChangedEntities(quint64 now, QSet& entitiesToDelete) { +void SimpleEntitySimulation::updateChangedEntities(quint64 now, QSet& entitiesToDelete) { foreach (EntityItem* entity, _changedEntities) { // check to see if the lifetime has expired, for immortal entities this is always false if (entity->lifetimeHasExpired()) { qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID(); - entitiesToDelete << entity->getEntityItemID(); + entitiesToDelete.insert(entity); clearEntityState(entity); } else { updateEntityState(entity); @@ -80,44 +91,44 @@ void SimpleEntitySimulation::updateChangedEntities(quint64 now, QSet& entitiesToDelete) { - if (_movingEntities.size() > 0) { +void SimpleEntitySimulation::updateMovingEntities(quint64 now, QSet& entitiesToDelete) { + if (_entityTree && _movingEntities.size() > 0) { PerformanceTimer perfTimer("_movingEntities"); - MovingEntitiesOperator moveOperator(_myTree); + MovingEntitiesOperator moveOperator(_entityTree); QList::iterator item_itr = _movingEntities.begin(); while (item_itr != _movingEntities.end()) { - EntityItem* thisEntity = *item_itr; + EntityItem* entity = *item_itr; // always check to see if the lifetime has expired, for immortal entities this is always false - if (thisEntity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); - entitiesToDelete << thisEntity->getEntityItemID(); - // remove thisEntity from the list + if (entity->lifetimeHasExpired()) { + qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID(); + entitiesToDelete.insert(entity); + // remove entity from the list item_itr = _movingEntities.erase(item_itr); - thisEntity->setSimulationState(EntityItem::Static); + entity->setSimulationState(EntityItem::Static); } else { - AACube oldCube = thisEntity->getMaximumAACube(); - thisEntity->update(now); - AACube newCube = thisEntity->getMaximumAACube(); + AACube oldCube = entity->getMaximumAACube(); + entity->update(now); + AACube newCube = entity->getMaximumAACube(); // check to see if this movement has sent the entity outside of the domain. AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f); if (!domainBounds.touches(newCube)) { - qDebug() << "Entity " << thisEntity->getEntityItemID() << " moved out of domain bounds."; - entitiesToDelete << thisEntity->getEntityItemID(); - // remove thisEntity from the list + qDebug() << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; + entitiesToDelete.insert(entity); + // remove entity from the list item_itr = _movingEntities.erase(item_itr); - thisEntity->setSimulationState(EntityItem::Static); + entity->setSimulationState(EntityItem::Static); } else { - moveOperator.addEntityToMoveList(thisEntity, oldCube, newCube); - EntityItem::SimulationState newState = thisEntity->computeSimulationState(); + moveOperator.addEntityToMoveList(entity, oldCube, newCube); + EntityItem::SimulationState newState = entity->computeSimulationState(); if (newState != EntityItem::Moving) { if (newState == EntityItem::Mortal) { - _mortalEntities.push_back(thisEntity); + _mortalEntities.push_back(entity); } - // remove thisEntity from the list + // remove entity from the list item_itr = _movingEntities.erase(item_itr); - thisEntity->setSimulationState(newState); + entity->setSimulationState(newState); } else { ++item_itr; } @@ -126,33 +137,33 @@ void SimpleEntitySimulation::updateMovingEntities(quint64 now, QSetrecurseTreeWithOperator(&moveOperator); + _entityTree->recurseTreeWithOperator(&moveOperator); } } } -void SimpleEntitySimulation::updateMortalEntities(quint64 now, QSet& entitiesToDelete) { +void SimpleEntitySimulation::updateMortalEntities(quint64 now, QSet& entitiesToDelete) { QList::iterator item_itr = _mortalEntities.begin(); while (item_itr != _mortalEntities.end()) { - EntityItem* thisEntity = *item_itr; - thisEntity->update(now); + EntityItem* entity = *item_itr; // always check to see if the lifetime has expired, for immortal entities this is always false - if (thisEntity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); - entitiesToDelete << thisEntity->getEntityItemID(); - // remove thisEntity from the list + if (entity->lifetimeHasExpired()) { + qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID(); + entitiesToDelete.insert(entity); + // remove entity from the list item_itr = _mortalEntities.erase(item_itr); - thisEntity->setSimulationState(EntityItem::Static); + entity->setSimulationState(EntityItem::Static); } else { // check to see if this entity is no longer moving - EntityItem::SimulationState newState = thisEntity->computeSimulationState(); + EntityItem::SimulationState newState = entity->computeSimulationState(); if (newState != EntityItem::Mortal) { if (newState == EntityItem::Moving) { - _movingEntities.push_back(thisEntity); + entity->update(now); + _movingEntities.push_back(entity); } - // remove thisEntity from the list + // remove entity from the list item_itr = _mortalEntities.erase(item_itr); - thisEntity->setSimulationState(newState); + entity->setSimulationState(newState); } else { ++item_itr; } diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index bc79bf9958..7d0e8f0113 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -18,29 +18,30 @@ class SimpleEntitySimulation : public EntitySimulation { public: - SimpleEntitySimulation(EntityTree* tree) : EntitySimulation(tree) { } - virtual ~SimpleEntitySimulation() { } + SimpleEntitySimulation() : EntitySimulation() { } + virtual ~SimpleEntitySimulation() { setEntityTree(NULL); } - virtual void update(QSet& entitiesToDelete); + virtual void update(QSet& entitiesToDelete); virtual void addEntity(EntityItem* entity); virtual void removeEntity(EntityItem* entity); - virtual void updateEntity(EntityItem* entity); + virtual void entityChanged(EntityItem* entity); -private: + virtual void clearEntities(); + +protected: void updateEntityState(EntityItem* entity); void clearEntityState(EntityItem* entity); QList& getMovingEntities() { return _movingEntities; } - void updateChangedEntities(quint64 now, QSet& entitiesToDelete); - void updateMovingEntities(quint64 now, QSet& entitiesToDelete); - void updateMortalEntities(quint64 now, QSet& entitiesToDelete); + void updateChangedEntities(quint64 now, QSet& entitiesToDelete); + void updateMovingEntities(quint64 now, QSet& entitiesToDelete); + void updateMortalEntities(quint64 now, QSet& entitiesToDelete); -private: + QSet _changedEntities; // entities that have changed in the last frame QList _movingEntities; // entities that need to be updated QList _mortalEntities; // non-moving entities that need to be checked for expiry - QSet _changedEntities; // entities that have changed in the last frame }; #endif // hifi_SimpleEntitySimulation_h