mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:24:00 +02:00
EntitySimulation takes EntityItem* rather than ID
This commit is contained in:
parent
0d98555740
commit
dd3a7b9b9d
10 changed files with 162 additions and 292 deletions
|
@ -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<EntityTreeElement*>(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!
|
||||
|
|
20
libraries/entities/src/EntitySimulation.cpp
Normal file
20
libraries/entities/src/EntitySimulation.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
|
|
@ -14,24 +14,36 @@
|
|||
|
||||
#include <QSet>
|
||||
|
||||
#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<EntityItemID>& 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<EntityItem*>& 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
|
||||
|
|
|
@ -12,13 +12,14 @@
|
|||
#include <PerfStat.h>
|
||||
|
||||
#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<EntityItemID> 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<EntityItemID> entitiesToDelete;
|
||||
updateChangedEntities(now, entitiesToDelete);
|
||||
updateMovingEntities(now, entitiesToDelete);
|
||||
updateMortalEntities(now, entitiesToDelete);
|
||||
|
||||
if (entitiesToDelete.size() > 0) {
|
||||
deleteEntities(entitiesToDelete);
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void EntityTree::updateChangedEntities(quint64 now, QSet<EntityItemID>& 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<EntityItemID>& entitiesToDelete) {
|
||||
PerformanceTimer perfTimer("updateMovingEntities");
|
||||
if (_movingEntities.size() > 0) {
|
||||
MovingEntitiesOperator moveOperator(this);
|
||||
{
|
||||
PerformanceTimer perfTimer("_movingEntities");
|
||||
|
||||
QList<EntityItem*>::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<EntityItem*> entitiesToDelete;
|
||||
_simulation->update(entitiesToDelete);
|
||||
if (entitiesToDelete.size() > 0) {
|
||||
// translate into list of ID's
|
||||
QSet<EntityItemID> 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<EntityItemID>& entitiesToDelete) {
|
||||
QList<EntityItem*>::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
|
||||
|
|
|
@ -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<EntityItemID> 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<EntityItem*>& 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<EntityItemID>& entitiesToDelete);
|
||||
void updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete);
|
||||
void updateMortalEntities(quint64 now, QSet<EntityItemID>& 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<EntityItemID, EntityTreeElement*> _entityToElementMap;
|
||||
|
||||
QList<EntityItem*> _movingEntities; // entities that need to be updated
|
||||
QList<EntityItem*> _mortalEntities; // entities that need to be checked for expiry
|
||||
|
||||
QSet<EntityItem*> _changedEntities; // entities that have changed in the last frame
|
||||
EntitySimulation* _simulation;
|
||||
};
|
||||
|
||||
#endif // hifi_EntityTree_h
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "MovingEntitiesOperator.h"
|
||||
#include "SimpleEntitySimulation.h"
|
||||
|
||||
void SimpleEntitySimulation::update(QSet<EntityItemID>& entitiesToDelete) {
|
||||
void SimpleEntitySimulation::update(QSet<EntityItem*>& 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<EntityItemID>& entitiesToDelete) {
|
||||
void SimpleEntitySimulation::updateChangedEntities(quint64 now, QSet<EntityItem*>& 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<EntityItemI
|
|||
_changedEntities.clear();
|
||||
}
|
||||
|
||||
void SimpleEntitySimulation::updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete) {
|
||||
if (_movingEntities.size() > 0) {
|
||||
void SimpleEntitySimulation::updateMovingEntities(quint64 now, QSet<EntityItem*>& entitiesToDelete) {
|
||||
if (_entityTree && _movingEntities.size() > 0) {
|
||||
PerformanceTimer perfTimer("_movingEntities");
|
||||
MovingEntitiesOperator moveOperator(_myTree);
|
||||
MovingEntitiesOperator moveOperator(_entityTree);
|
||||
QList<EntityItem*>::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, QSet<EntityItemID
|
|||
}
|
||||
if (moveOperator.hasMovingEntities()) {
|
||||
PerformanceTimer perfTimer("recurseTreeWithOperator");
|
||||
_myTree->recurseTreeWithOperator(&moveOperator);
|
||||
_entityTree->recurseTreeWithOperator(&moveOperator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleEntitySimulation::updateMortalEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete) {
|
||||
void SimpleEntitySimulation::updateMortalEntities(quint64 now, QSet<EntityItem*>& entitiesToDelete) {
|
||||
QList<EntityItem*>::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;
|
||||
}
|
||||
|
|
|
@ -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<EntityItemID>& entitiesToDelete);
|
||||
virtual void update(QSet<EntityItem*>& 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<EntityItem*>& getMovingEntities() { return _movingEntities; }
|
||||
|
||||
void updateChangedEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete);
|
||||
void updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete);
|
||||
void updateMortalEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete);
|
||||
void updateChangedEntities(quint64 now, QSet<EntityItem*>& entitiesToDelete);
|
||||
void updateMovingEntities(quint64 now, QSet<EntityItem*>& entitiesToDelete);
|
||||
void updateMortalEntities(quint64 now, QSet<EntityItem*>& entitiesToDelete);
|
||||
|
||||
private:
|
||||
QSet<EntityItem*> _changedEntities; // entities that have changed in the last frame
|
||||
QList<EntityItem*> _movingEntities; // entities that need to be updated
|
||||
QList<EntityItem*> _mortalEntities; // non-moving entities that need to be checked for expiry
|
||||
QSet<EntityItem*> _changedEntities; // entities that have changed in the last frame
|
||||
};
|
||||
|
||||
#endif // hifi_SimpleEntitySimulation_h
|
||||
|
|
Loading…
Reference in a new issue