mirror of
https://github.com/overte-org/overte.git
synced 2025-07-23 07:44:09 +02:00
lock the entity tree during physics operations that access then entity tree. if the simulation and entity-tree are both going to be locked, be sure to lock the entity tree first (and unlock it last), because this is what the network-reading thread does
This commit is contained in:
parent
63812f28ad
commit
a0d77c061c
3 changed files with 95 additions and 22 deletions
|
@ -2496,24 +2496,45 @@ void Application::update(float deltaTime) {
|
||||||
|
|
||||||
_entitySimulation.lock();
|
_entitySimulation.lock();
|
||||||
_physicsEngine.deleteObjects(_entitySimulation.getObjectsToDelete());
|
_physicsEngine.deleteObjects(_entitySimulation.getObjectsToDelete());
|
||||||
|
_entitySimulation.unlock();
|
||||||
|
|
||||||
|
_entities.getTree()->lockForWrite();
|
||||||
|
_entitySimulation.lock();
|
||||||
_physicsEngine.addObjects(_entitySimulation.getObjectsToAdd());
|
_physicsEngine.addObjects(_entitySimulation.getObjectsToAdd());
|
||||||
|
_entitySimulation.unlock();
|
||||||
|
_entities.getTree()->unlock();
|
||||||
|
|
||||||
|
_entities.getTree()->lockForWrite();
|
||||||
|
_entitySimulation.lock();
|
||||||
_physicsEngine.changeObjects(_entitySimulation.getObjectsToChange());
|
_physicsEngine.changeObjects(_entitySimulation.getObjectsToChange());
|
||||||
|
_entitySimulation.unlock();
|
||||||
|
_entities.getTree()->unlock();
|
||||||
|
|
||||||
|
_entitySimulation.lock();
|
||||||
_entitySimulation.applyActionChanges();
|
_entitySimulation.applyActionChanges();
|
||||||
_entitySimulation.unlock();
|
_entitySimulation.unlock();
|
||||||
|
|
||||||
|
|
||||||
AvatarManager* avatarManager = DependencyManager::get<AvatarManager>().data();
|
AvatarManager* avatarManager = DependencyManager::get<AvatarManager>().data();
|
||||||
_physicsEngine.deleteObjects(avatarManager->getObjectsToDelete());
|
_physicsEngine.deleteObjects(avatarManager->getObjectsToDelete());
|
||||||
_physicsEngine.addObjects(avatarManager->getObjectsToAdd());
|
_physicsEngine.addObjects(avatarManager->getObjectsToAdd());
|
||||||
_physicsEngine.changeObjects(avatarManager->getObjectsToChange());
|
_physicsEngine.changeObjects(avatarManager->getObjectsToChange());
|
||||||
|
|
||||||
|
_entities.getTree()->lockForWrite();
|
||||||
_physicsEngine.stepSimulation();
|
_physicsEngine.stepSimulation();
|
||||||
|
_entities.getTree()->unlock();
|
||||||
|
|
||||||
if (_physicsEngine.hasOutgoingChanges()) {
|
if (_physicsEngine.hasOutgoingChanges()) {
|
||||||
|
_entities.getTree()->lockForWrite();
|
||||||
_entitySimulation.lock();
|
_entitySimulation.lock();
|
||||||
_entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges(), _physicsEngine.getSessionID());
|
_entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges(), _physicsEngine.getSessionID());
|
||||||
_entitySimulation.unlock();
|
_entitySimulation.unlock();
|
||||||
|
_entities.getTree()->unlock();
|
||||||
|
|
||||||
|
_entities.getTree()->lockForWrite();
|
||||||
avatarManager->handleOutgoingChanges(_physicsEngine.getOutgoingChanges());
|
avatarManager->handleOutgoingChanges(_physicsEngine.getOutgoingChanges());
|
||||||
|
_entities.getTree()->unlock();
|
||||||
|
|
||||||
auto collisionEvents = _physicsEngine.getCollisionEvents();
|
auto collisionEvents = _physicsEngine.getCollisionEvents();
|
||||||
avatarManager->handleCollisionEvents(collisionEvents);
|
avatarManager->handleCollisionEvents(collisionEvents);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
#include "PhysicsHelpers.h"
|
#include "PhysicsHelpers.h"
|
||||||
#include "PhysicsLogging.h"
|
#include "PhysicsLogging.h"
|
||||||
|
|
||||||
|
#ifdef WANT_DEBUG_ENTITY_TREE_LOCKS
|
||||||
|
#include "EntityTree.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f;
|
static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f;
|
||||||
static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4;
|
static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4;
|
||||||
|
|
||||||
|
@ -42,6 +46,7 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
|
||||||
{
|
{
|
||||||
_type = MOTIONSTATE_TYPE_ENTITY;
|
_type = MOTIONSTATE_TYPE_ENTITY;
|
||||||
assert(_entity != nullptr);
|
assert(_entity != nullptr);
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
setMass(_entity->computeMass());
|
setMass(_entity->computeMass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +55,35 @@ EntityMotionState::~EntityMotionState() {
|
||||||
assert(!_entity);
|
assert(!_entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WANT_DEBUG_ENTITY_TREE_LOCKS
|
||||||
|
bool EntityMotionState::entityTreeIsLocked() const {
|
||||||
|
EntityTreeElement* element = _entity ? _entity->getElement() : nullptr;
|
||||||
|
EntityTree* tree = element ? element->getTree() : nullptr;
|
||||||
|
if (tree) {
|
||||||
|
bool readSuccess = tree->tryLockForRead();
|
||||||
|
if (readSuccess) {
|
||||||
|
tree->unlock();
|
||||||
|
}
|
||||||
|
bool writeSuccess = tree->tryLockForWrite();
|
||||||
|
if (writeSuccess) {
|
||||||
|
tree->unlock();
|
||||||
|
}
|
||||||
|
if (readSuccess && writeSuccess) {
|
||||||
|
return false; // if we can take either kind of lock, there was no tree lock.
|
||||||
|
}
|
||||||
|
return true; // either read or write failed, so there is some lock in place.
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
bool EntityMotionState::entityTreeIsLocked() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void EntityMotionState::updateServerPhysicsVariables() {
|
void EntityMotionState::updateServerPhysicsVariables() {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
_serverPosition = _entity->getPosition();
|
_serverPosition = _entity->getPosition();
|
||||||
_serverRotation = _entity->getRotation();
|
_serverRotation = _entity->getRotation();
|
||||||
_serverVelocity = _entity->getVelocity();
|
_serverVelocity = _entity->getVelocity();
|
||||||
|
@ -60,6 +93,7 @@ void EntityMotionState::updateServerPhysicsVariables() {
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void EntityMotionState::handleEasyChanges(uint32_t flags) {
|
void EntityMotionState::handleEasyChanges(uint32_t flags) {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
updateServerPhysicsVariables();
|
updateServerPhysicsVariables();
|
||||||
ObjectMotionState::handleEasyChanges(flags);
|
ObjectMotionState::handleEasyChanges(flags);
|
||||||
if (flags & EntityItem::DIRTY_SIMULATOR_ID) {
|
if (flags & EntityItem::DIRTY_SIMULATOR_ID) {
|
||||||
|
@ -101,6 +135,7 @@ MotionType EntityMotionState::computeObjectMotionType() const {
|
||||||
if (!_entity) {
|
if (!_entity) {
|
||||||
return MOTION_TYPE_STATIC;
|
return MOTION_TYPE_STATIC;
|
||||||
}
|
}
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
if (_entity->getCollisionsWillMove()) {
|
if (_entity->getCollisionsWillMove()) {
|
||||||
return MOTION_TYPE_DYNAMIC;
|
return MOTION_TYPE_DYNAMIC;
|
||||||
}
|
}
|
||||||
|
@ -108,6 +143,7 @@ MotionType EntityMotionState::computeObjectMotionType() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityMotionState::isMoving() const {
|
bool EntityMotionState::isMoving() const {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
return _entity && _entity->isMoving();
|
return _entity && _entity->isMoving();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +156,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
|
||||||
if (!_entity) {
|
if (!_entity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
if (_motionType == MOTION_TYPE_KINEMATIC) {
|
if (_motionType == MOTION_TYPE_KINEMATIC) {
|
||||||
// This is physical kinematic motion which steps strictly by the subframe count
|
// This is physical kinematic motion which steps strictly by the subframe count
|
||||||
// of the physics simulation.
|
// of the physics simulation.
|
||||||
|
@ -140,6 +177,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
||||||
if (!_entity) {
|
if (!_entity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
measureBodyAcceleration();
|
measureBodyAcceleration();
|
||||||
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
|
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
|
||||||
_entity->setRotation(bulletToGLM(worldTrans.getRotation()));
|
_entity->setRotation(bulletToGLM(worldTrans.getRotation()));
|
||||||
|
@ -164,9 +202,12 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
qCDebug(physics) << "EntityMotionState::setWorldTransform()... changed entity:" << _entity->getEntityItemID();
|
qCDebug(physics) << "EntityMotionState::setWorldTransform()... changed entity:" << _entity->getEntityItemID();
|
||||||
qCDebug(physics) << " last edited:" << _entity->getLastEdited() << formatUsecTime(now - _entity->getLastEdited()) << "ago";
|
qCDebug(physics) << " last edited:" << _entity->getLastEdited()
|
||||||
qCDebug(physics) << " last simulated:" << _entity->getLastSimulated() << formatUsecTime(now - _entity->getLastSimulated()) << "ago";
|
<< formatUsecTime(now - _entity->getLastEdited()) << "ago";
|
||||||
qCDebug(physics) << " last updated:" << _entity->getLastUpdated() << formatUsecTime(now - _entity->getLastUpdated()) << "ago";
|
qCDebug(physics) << " last simulated:" << _entity->getLastSimulated()
|
||||||
|
<< formatUsecTime(now - _entity->getLastSimulated()) << "ago";
|
||||||
|
qCDebug(physics) << " last updated:" << _entity->getLastUpdated()
|
||||||
|
<< formatUsecTime(now - _entity->getLastUpdated()) << "ago";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,6 +215,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
||||||
btCollisionShape* EntityMotionState::computeNewShape() {
|
btCollisionShape* EntityMotionState::computeNewShape() {
|
||||||
if (_entity) {
|
if (_entity) {
|
||||||
ShapeInfo shapeInfo;
|
ShapeInfo shapeInfo;
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
_entity->computeShapeInfo(shapeInfo);
|
_entity->computeShapeInfo(shapeInfo);
|
||||||
return getShapeManager()->getShape(shapeInfo);
|
return getShapeManager()->getShape(shapeInfo);
|
||||||
}
|
}
|
||||||
|
@ -184,6 +226,7 @@ bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const {
|
||||||
if (!_body || !_entity) {
|
if (!_body || !_entity) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
return _candidateForOwnership || sessionID == _entity->getSimulatorID();
|
return _candidateForOwnership || sessionID == _entity->getSimulatorID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,6 +340,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s
|
||||||
// after doesNotNeedToSendUpdate() returns false and that call should return 'true' if _entity or _body are NULL.
|
// after doesNotNeedToSendUpdate() returns false and that call should return 'true' if _entity or _body are NULL.
|
||||||
assert(_entity);
|
assert(_entity);
|
||||||
assert(_body);
|
assert(_body);
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
|
|
||||||
if (!remoteSimulationOutOfSync(simulationStep)) {
|
if (!remoteSimulationOutOfSync(simulationStep)) {
|
||||||
_candidateForOwnership = false;
|
_candidateForOwnership = false;
|
||||||
|
@ -326,6 +370,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s
|
||||||
|
|
||||||
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) {
|
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) {
|
||||||
assert(_entity);
|
assert(_entity);
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
|
|
||||||
bool active = _body->isActive();
|
bool active = _body->isActive();
|
||||||
if (!active) {
|
if (!active) {
|
||||||
|
@ -436,6 +481,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() {
|
uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
uint32_t dirtyFlags = 0;
|
uint32_t dirtyFlags = 0;
|
||||||
if (_body && _entity) {
|
if (_body && _entity) {
|
||||||
dirtyFlags = _entity->getDirtyFlags();
|
dirtyFlags = _entity->getDirtyFlags();
|
||||||
|
@ -455,6 +501,7 @@ uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() {
|
||||||
// virtual
|
// virtual
|
||||||
QUuid EntityMotionState::getSimulatorID() const {
|
QUuid EntityMotionState::getSimulatorID() const {
|
||||||
if (_entity) {
|
if (_entity) {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
return _entity->getSimulatorID();
|
return _entity->getSimulatorID();
|
||||||
}
|
}
|
||||||
return QUuid();
|
return QUuid();
|
||||||
|
@ -514,6 +561,7 @@ void EntityMotionState::setMotionType(MotionType motionType) {
|
||||||
// virtual
|
// virtual
|
||||||
QString EntityMotionState::getName() {
|
QString EntityMotionState::getName() {
|
||||||
if (_entity) {
|
if (_entity) {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
return _entity->getName();
|
return _entity->getName();
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -83,6 +83,10 @@ public:
|
||||||
friend class PhysicalEntitySimulation;
|
friend class PhysicalEntitySimulation;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
#ifdef WANT_DEBUG_ENTITY_TREE_LOCKS
|
||||||
|
bool entityTreeIsLocked() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
virtual btCollisionShape* computeNewShape();
|
virtual btCollisionShape* computeNewShape();
|
||||||
virtual void clearObjectBackPointer();
|
virtual void clearObjectBackPointer();
|
||||||
virtual void setMotionType(MotionType motionType);
|
virtual void setMotionType(MotionType motionType);
|
||||||
|
|
Loading…
Reference in a new issue