remove entities from physics before we delete them

This commit is contained in:
Andrew Meadows 2015-12-29 11:05:02 -08:00
parent b34df211df
commit f5d24a87ca
5 changed files with 58 additions and 38 deletions

View file

@ -337,6 +337,8 @@ public:
bool isMoving() const; bool isMoving() const;
bool isSimulated() const { return _simulated; }
void* getPhysicsInfo() const { return _physicsInfo; } void* getPhysicsInfo() const { return _physicsInfo; }
void setPhysicsInfo(void* data) { _physicsInfo = data; } void setPhysicsInfo(void* data) { _physicsInfo = data; }
@ -391,6 +393,8 @@ public:
protected: protected:
void setSimulated(bool simulated) { _simulated = simulated; }
const QByteArray getActionDataInternal() const; const QByteArray getActionDataInternal() const;
void setActionDataInternal(QByteArray actionData); void setActionDataInternal(QByteArray actionData);

View file

@ -53,16 +53,15 @@ void EntitySimulation::removeEntityInternal(EntityItemPointer entity) {
_entitiesToSort.remove(entity); _entitiesToSort.remove(entity);
_simpleKinematicEntities.remove(entity); _simpleKinematicEntities.remove(entity);
_allEntities.remove(entity); _allEntities.remove(entity);
entity->_simulated = false; entity->setSimulated(false);
} }
void EntitySimulation::prepareEntityForDelete(EntityItemPointer entity) { void EntitySimulation::prepareEntityForDelete(EntityItemPointer entity) {
assert(entity); assert(entity);
if (entity->_simulated) { assert(entity->isSimulated());
entity->clearActions(this); entity->clearActions(this);
_entitiesToDelete.insert(entity); removeEntityInternal(entity);
removeEntityInternal(entity); _entitiesToDelete.insert(entity);
}
} }
void EntitySimulation::addEntityInternal(EntityItemPointer entity) { void EntitySimulation::addEntityInternal(EntityItemPointer entity) {
@ -166,7 +165,7 @@ void EntitySimulation::addEntity(EntityItemPointer entity) {
addEntityInternal(entity); addEntityInternal(entity);
_allEntities.insert(entity); _allEntities.insert(entity);
entity->_simulated = true; entity->setSimulated(true);
// DirtyFlags are used to signal changes to entities that have already been added, // DirtyFlags are used to signal changes to entities that have already been added,
// so we can clear them for this entity which has just been added. // so we can clear them for this entity which has just been added.
@ -176,7 +175,7 @@ void EntitySimulation::addEntity(EntityItemPointer entity) {
void EntitySimulation::changeEntity(EntityItemPointer entity) { void EntitySimulation::changeEntity(EntityItemPointer entity) {
QMutexLocker lock(&_mutex); QMutexLocker lock(&_mutex);
assert(entity); assert(entity);
if (!entity->_simulated) { if (!entity->isSimulated()) {
// This entity was either never added to the simulation or has been removed // This entity was either never added to the simulation or has been removed
// (probably for pending delete), so we don't want to keep a pointer to it // (probably for pending delete), so we don't want to keep a pointer to it
// on any internal lists. // on any internal lists.
@ -232,7 +231,7 @@ void EntitySimulation::clearEntities() {
clearEntitiesInternal(); clearEntitiesInternal();
for (auto entityItr : _allEntities) { for (auto entityItr : _allEntities) {
entityItr->_simulated = false; entityItr->setSimulated(false);
} }
_allEntities.clear(); _allEntities.clear();
} }

View file

@ -101,6 +101,9 @@ protected:
QList<EntityActionPointer> _actionsToAdd; QList<EntityActionPointer> _actionsToAdd;
QSet<QUuid> _actionsToRemove; QSet<QUuid> _actionsToRemove;
protected:
SetOfEntities _entitiesToDelete; // entities simulation decided needed to be deleted (EntityTree will actually delete)
private: private:
void moveSimpleKinematics(); void moveSimpleKinematics();
@ -115,7 +118,6 @@ private:
SetOfEntities _entitiesToUpdate; // entities that need to call EntityItem::update() SetOfEntities _entitiesToUpdate; // entities that need to call EntityItem::update()
SetOfEntities _entitiesToDelete; // entities simulation decided needed to be deleted (EntityTree will actually delete)
}; };

View file

@ -47,7 +47,7 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) {
if (entity->shouldBePhysical()) { if (entity->shouldBePhysical()) {
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo()); EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
if (!motionState) { if (!motionState) {
_pendingAdds.insert(entity); _entitiesToAddToPhysics.insert(entity);
} }
} else if (entity->isMoving()) { } else if (entity->isMoving()) {
_simpleKinematicEntities.insert(entity); _simpleKinematicEntities.insert(entity);
@ -56,14 +56,17 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) {
void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) { void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) {
EntitySimulation::removeEntityInternal(entity); EntitySimulation::removeEntityInternal(entity);
_entitiesToAddToPhysics.remove(entity);
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo()); EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
if (motionState) { if (motionState) {
motionState->clearObjectBackPointer(); motionState->clearObjectBackPointer();
entity->setPhysicsInfo(nullptr); entity->setPhysicsInfo(nullptr);
_pendingRemoves.insert(motionState);
_outgoingChanges.remove(motionState); _outgoingChanges.remove(motionState);
_entitiesToRemoveFromPhysics.insert(entity);
} else {
_entitiesToDelete.insert(entity);
} }
_pendingAdds.remove(entity);
} }
void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) { void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
@ -75,8 +78,8 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
// the entity should be removed from the physical simulation // the entity should be removed from the physical simulation
_pendingChanges.remove(motionState); _pendingChanges.remove(motionState);
_physicalObjects.remove(motionState); _physicalObjects.remove(motionState);
_pendingRemoves.insert(motionState);
_outgoingChanges.remove(motionState); _outgoingChanges.remove(motionState);
_entitiesToRemoveFromPhysics.insert(entity);
if (entity->isMoving()) { if (entity->isMoving()) {
_simpleKinematicEntities.insert(entity); _simpleKinematicEntities.insert(entity);
} }
@ -86,7 +89,7 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
} else if (entity->shouldBePhysical()) { } else if (entity->shouldBePhysical()) {
// The intent is for this object to be in the PhysicsEngine, but it has no MotionState yet. // The intent is for this object to be in the PhysicsEngine, but it has no MotionState yet.
// Perhaps it's shape has changed and it can now be added? // Perhaps it's shape has changed and it can now be added?
_pendingAdds.insert(entity); _entitiesToAddToPhysics.insert(entity);
_simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic _simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic
} else if (entity->isMoving()) { } else if (entity->isMoving()) {
_simpleKinematicEntities.insert(entity); _simpleKinematicEntities.insert(entity);
@ -115,43 +118,53 @@ void PhysicalEntitySimulation::clearEntitiesInternal() {
// finally clear all lists (which now have only dangling pointers) // finally clear all lists (which now have only dangling pointers)
_physicalObjects.clear(); _physicalObjects.clear();
_pendingRemoves.clear(); _entitiesToRemoveFromPhysics.clear();
_pendingAdds.clear(); _entitiesToAddToPhysics.clear();
_pendingChanges.clear(); _pendingChanges.clear();
_outgoingChanges.clear(); _outgoingChanges.clear();
} }
// end EntitySimulation overrides
// virtual
void PhysicalEntitySimulation::prepareEntityForDelete(EntityItemPointer entity) {
assert(entity);
assert(entity->isSimulated());
entity->clearActions(this);
removeEntityInternal(entity);
// the PhysicalEntitySimulation must pull the corresponding object out of the PhysicsEngine
// before the Entity is ready to delete so we first put them on this list
_entitiesToRemoveFromPhysics.insert(entity);
}
// end EntitySimulation overrides
void PhysicalEntitySimulation::getObjectsToDelete(VectorOfMotionStates& result) { void PhysicalEntitySimulation::getObjectsToDelete(VectorOfMotionStates& result) {
result.clear(); result.clear();
QMutexLocker lock(&_mutex); QMutexLocker lock(&_mutex);
for (auto stateItr : _pendingRemoves) { for (auto entity: _entitiesToRemoveFromPhysics) {
EntityMotionState* motionState = &(*stateItr); EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
_pendingChanges.remove(motionState); if (motionState) {
_physicalObjects.remove(motionState); _pendingChanges.remove(motionState);
_physicalObjects.remove(motionState);
EntityItemPointer entity = motionState->getEntity();
if (entity) {
_pendingAdds.remove(entity);
entity->setPhysicsInfo(nullptr);
motionState->clearObjectBackPointer(); motionState->clearObjectBackPointer();
result.push_back(motionState);
} }
result.push_back(motionState); _entitiesToAddToPhysics.remove(entity);
entity->setPhysicsInfo(nullptr);
_entitiesToDelete.insert(entity);
} }
_pendingRemoves.clear(); _entitiesToRemoveFromPhysics.clear();
} }
void PhysicalEntitySimulation::getObjectsToAdd(VectorOfMotionStates& result) { void PhysicalEntitySimulation::getObjectsToAdd(VectorOfMotionStates& result) {
result.clear(); result.clear();
QMutexLocker lock(&_mutex); QMutexLocker lock(&_mutex);
SetOfEntities::iterator entityItr = _pendingAdds.begin(); SetOfEntities::iterator entityItr = _entitiesToAddToPhysics.begin();
while (entityItr != _pendingAdds.end()) { while (entityItr != _entitiesToAddToPhysics.end()) {
EntityItemPointer entity = *entityItr; EntityItemPointer entity = *entityItr;
assert(!entity->getPhysicsInfo()); assert(!entity->getPhysicsInfo());
if (!entity->shouldBePhysical()) { if (!entity->shouldBePhysical()) {
// this entity should no longer be on the internal _pendingAdds // this entity should no longer be on the internal _entitiesToAddToPhysics
entityItr = _pendingAdds.erase(entityItr); entityItr = _entitiesToAddToPhysics.erase(entityItr);
if (entity->isMoving()) { if (entity->isMoving()) {
_simpleKinematicEntities.insert(entity); _simpleKinematicEntities.insert(entity);
} }
@ -164,7 +177,7 @@ void PhysicalEntitySimulation::getObjectsToAdd(VectorOfMotionStates& result) {
entity->setPhysicsInfo(static_cast<void*>(motionState)); entity->setPhysicsInfo(static_cast<void*>(motionState));
_physicalObjects.insert(motionState); _physicalObjects.insert(motionState);
result.push_back(motionState); result.push_back(motionState);
entityItr = _pendingAdds.erase(entityItr); entityItr = _entitiesToAddToPhysics.erase(entityItr);
} else { } else {
//qDebug() << "Warning! Failed to generate new shape for entity." << entity->getName(); //qDebug() << "Warning! Failed to generate new shape for entity." << entity->getName();
++entityItr; ++entityItr;

View file

@ -44,6 +44,8 @@ protected: // only called by EntitySimulation
virtual void clearEntitiesInternal() override; virtual void clearEntitiesInternal() override;
public: public:
virtual void prepareEntityForDelete(EntityItemPointer entity) override;
void getObjectsToDelete(VectorOfMotionStates& result); void getObjectsToDelete(VectorOfMotionStates& result);
void getObjectsToAdd(VectorOfMotionStates& result); void getObjectsToAdd(VectorOfMotionStates& result);
void setObjectsToChange(const VectorOfMotionStates& objectsToChange); void setObjectsToChange(const VectorOfMotionStates& objectsToChange);
@ -55,12 +57,12 @@ public:
EntityEditPacketSender* getPacketSender() { return _entityPacketSender; } EntityEditPacketSender* getPacketSender() { return _entityPacketSender; }
private: private:
// incoming changes // incoming changes to physics simulation
SetOfEntityMotionStates _pendingRemoves; // EntityMotionStates to be removed from PhysicsEngine (and deleted) SetOfEntities _entitiesToRemoveFromPhysics;
SetOfEntities _pendingAdds; // entities to be be added to PhysicsEngine (and a their EntityMotionState created) SetOfEntities _entitiesToAddToPhysics; // entities to be be added to PhysicsEngine (and a their EntityMotionState created)
SetOfEntityMotionStates _pendingChanges; // EntityMotionStates already in PhysicsEngine that need their physics changed SetOfEntityMotionStates _pendingChanges; // EntityMotionStates already in PhysicsEngine that need their physics changed
// outgoing changes // outgoing changes from physics simulation
SetOfEntityMotionStates _outgoingChanges; // EntityMotionStates for which we need to send updates to entity-server SetOfEntityMotionStates _outgoingChanges; // EntityMotionStates for which we need to send updates to entity-server
SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine