diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index f0461abb97..bdf27f4440 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -11,8 +11,11 @@ //#include -#include "EntityItem.h" #include "SimpleEntitySimulation.h" + +#include + +#include "EntityItem.h" #include "EntitiesLogging.h" const quint64 MIN_SIMULATION_OWNERSHIP_UPDATE_PERIOD = 2 * USECS_PER_SECOND; @@ -40,17 +43,22 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { if (entity->getSimulatorID().isNull()) { // no simulators are volunteering // zero the velocity on this entity so that it doesn't drift far away - entity->setVelocity(glm::vec3(0.0f)); + entity->setVelocity(Vectors::ZERO); + entity->setAngularVelocity(Vectors::ZERO); + entity->setAcceleration(Vectors::ZERO); // remove from list itemItr = _entitiesWithSimulator.erase(itemItr); continue; } else { // the simulator has stopped updating this object // clear ownership and restart timer, giving nearby simulators time to volunteer - qCDebug(entities) << "auto-removing simulation owner " << entity.getSimulatorID(); + qCDebug(entities) << "auto-removing simulation owner " << entity->getSimulatorID(); entity->clearSimulationOwnership(); - entity->markAsChangedOnServer(); } + entity->markAsChangedOnServer(); + // dirty all the tree elements that contain the entity + DirtyOctreeElementOperator op(entity->getElement()); + getEntityTree()->recurseTreeWithOperator(&op); } else if (expiry < _nextSimulationExpiry) { _nextSimulationExpiry = expiry; } diff --git a/libraries/entities/src/SimulationOwner.cpp b/libraries/entities/src/SimulationOwner.cpp index 24f6784954..669d811df9 100644 --- a/libraries/entities/src/SimulationOwner.cpp +++ b/libraries/entities/src/SimulationOwner.cpp @@ -16,11 +16,11 @@ #include -// static +// static const int SimulationOwner::NUM_BYTES_ENCODED = NUM_BYTES_RFC4122_UUID + 1; -SimulationOwner::SimulationOwner(const SimulationOwner& other) +SimulationOwner::SimulationOwner(const SimulationOwner& other) : _id(other._id), _priority(other._priority), _expiry(other._expiry) { } @@ -48,11 +48,6 @@ void SimulationOwner::clear() { void SimulationOwner::setPriority(quint8 priority) { _priority = priority; - if (_priority == 0) { - // when priority is zero we clear everything - _expiry = 0; - _id = QUuid(); - } } void SimulationOwner::promotePriority(quint8 priority) { diff --git a/libraries/entities/src/SimulationOwner.h b/libraries/entities/src/SimulationOwner.h index a848ad6e84..bd17128003 100644 --- a/libraries/entities/src/SimulationOwner.h +++ b/libraries/entities/src/SimulationOwner.h @@ -18,10 +18,10 @@ #include #include -const quint8 NO_PRORITY = 0x00; +const quint8 ZERO_SIMULATION_PRIORITY = 0x00; // Simulation observers will bid to simulate unowned active objects at the lowest possible priority -// which is VOLUNTEER. If the server accepts a VOLUNTEER bid it will automatically bump it +// which is VOLUNTEER. If the server accepts a VOLUNTEER bid it will automatically bump it // to RECRUIT priority so that other volunteers don't accidentally take over. const quint8 VOLUNTEER_SIMULATION_PRIORITY = 0x01; const quint8 RECRUIT_SIMULATION_PRIORITY = VOLUNTEER_SIMULATION_PRIORITY + 1; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 52151b7136..155186e891 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -26,10 +26,7 @@ #include "EntityTree.h" #endif -static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; -static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4; - -const uint32_t LOOPS_FOR_SIMULATION_ORPHAN = 50; +const uint8_t LOOPS_FOR_SIMULATION_ORPHAN = 50; const quint64 USECS_BETWEEN_OWNERSHIP_BIDS = USECS_PER_SECOND / 5; #ifdef WANT_DEBUG_ENTITY_TREE_LOCKS @@ -52,8 +49,6 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer ObjectMotionState(shape), _entityPtr(entity), _entity(entity.get()), - _sentInactive(true), - _lastStep(0), _serverPosition(0.0f), _serverRotation(), _serverVelocity(0.0f), @@ -61,13 +56,16 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer _serverGravity(0.0f), _serverAcceleration(0.0f), _serverActionData(QByteArray()), - _lastMeasureStep(0), _lastVelocity(glm::vec3(0.0f)), _measuredAcceleration(glm::vec3(0.0f)), - _measuredDeltaTime(0.0f), - _accelerationNearlyGravityCount(0), _nextOwnershipBid(0), - _loopsWithoutOwner(0) + _measuredDeltaTime(0.0f), + _lastMeasureStep(0), + _lastStep(0), + _loopsWithoutOwner(0), + _accelerationNearlyGravityCount(0), + _numInactiveUpdates(1), + _outgoingPriority(ZERO_SIMULATION_PRIORITY) { _type = MOTIONSTATE_TYPE_ENTITY; assert(_entity); @@ -102,20 +100,28 @@ bool EntityMotionState::handleEasyChanges(uint32_t& flags) { ObjectMotionState::handleEasyChanges(flags); if (flags & Simulation::DIRTY_SIMULATOR_ID) { - _loopsWithoutOwner = 0; if (_entity->getSimulatorID().isNull()) { // simulation ownership has been removed by an external simulator - // --> clear the ACTIVATION flag and outgoing priority because this object is coming to rest - flags &= ~Simulation::DIRTY_PHYSICS_ACTIVATION; - _body->setActivationState(WANTS_DEACTIVATION); - _outgoingPriority = NO_PRORITY; + if (glm::length2(_entity->getVelocity()) == 0.0f) { + // this object is coming to rest --> clear the ACTIVATION flag and outgoing priority + flags &= ~Simulation::DIRTY_PHYSICS_ACTIVATION; + _body->setActivationState(WANTS_DEACTIVATION); + _outgoingPriority = ZERO_SIMULATION_PRIORITY; + _loopsWithoutOwner = 0; + } else { + // unowned object is still moving --> we should volunteer to own it + // TODO? put a delay in here proportional to distance from object? + setOutgoingPriority(VOLUNTEER_SIMULATION_PRIORITY); + _loopsWithoutOwner = LOOPS_FOR_SIMULATION_ORPHAN; + _nextOwnershipBid = 0; + } } else { // this entity's simulation is owned by someone, so we push its ownership expiry into the future _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; if (Physics::getSessionUUID() == _entity->getSimulatorID() || _entity->getSimulationPriority() >= _outgoingPriority) { // either we already own the simulation or our old outgoing priority momentarily looses to current owner // so we clear it - _outgoingPriority = NO_PRORITY; + _outgoingPriority = ZERO_SIMULATION_PRIORITY; } } } @@ -237,10 +243,11 @@ bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const { assert(_body); assert(_entity); assert(entityTreeIsLocked()); - return _outgoingPriority != NO_PRORITY || sessionID == _entity->getSimulatorID() || _entity->actionDataNeedsTransmit(); + return _outgoingPriority != ZERO_SIMULATION_PRIORITY || sessionID == _entity->getSimulatorID() || _entity->actionDataNeedsTransmit(); } bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { + // NOTE: we only get here if we think we own the simulation assert(_body); // if we've never checked before, our _lastStep will be 0, and we need to initialize our state if (_lastStep == 0) { @@ -251,7 +258,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { _serverAngularVelocity = bulletToGLM(_body->getAngularVelocity()); _lastStep = simulationStep; _serverActionData = _entity->getActionData(); - _sentInactive = true; + _numInactiveUpdates = 1; return false; } @@ -264,16 +271,21 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { int numSteps = simulationStep - _lastStep; float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP; - const float INACTIVE_UPDATE_PERIOD = 0.5f; - if (_sentInactive) { + if (_numInactiveUpdates > 0) { + const uint8_t MAX_NUM_INACTIVE_UPDATES = 3; + if (_numInactiveUpdates > MAX_NUM_INACTIVE_UPDATES) { + // clear local ownership (stop sending updates) and let the server clear itself + _entity->clearSimulationOwnership(); + return false; + } // we resend the inactive update every INACTIVE_UPDATE_PERIOD // until it is removed from the outgoing updates // (which happens when we don't own the simulation and it isn't touching our simulation) + const float INACTIVE_UPDATE_PERIOD = 0.5f; return (dt > INACTIVE_UPDATE_PERIOD); } - bool isActive = _body->isActive(); - if (!isActive) { + if (!_body->isActive()) { // object has gone inactive but our last send was moving --> send non-moving update immediately return true; } @@ -373,11 +385,11 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s if (_entity->getSimulatorID() != sessionID) { // we don't own the simulation - if (_outgoingPriority != NO_PRORITY) { + if (_outgoingPriority != ZERO_SIMULATION_PRIORITY) { // but we would like to own it if (_outgoingPriority < _entity->getSimulationPriority()) { // but our priority loses to remote, so we don't bother trying - _outgoingPriority = NO_PRORITY; + _outgoingPriority = ZERO_SIMULATION_PRIORITY; return false; } return usecTimestampNow() > _nextOwnershipBid; @@ -399,10 +411,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q _entity->setVelocity(zero); _entity->setAngularVelocity(zero); _entity->setAcceleration(zero); - _sentInactive = true; + _numInactiveUpdates++; } else { + const uint8_t STEPS_TO_DECIDE_BALLISTIC = 4; float gravityLength = glm::length(_entity->getGravity()); float accVsGravity = glm::abs(glm::length(_measuredAcceleration) - gravityLength); + const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; if (accVsGravity < ACCELERATION_EQUIVALENT_EPSILON_RATIO * gravityLength) { // acceleration measured during the most recent simulation step was close to gravity. if (getAccelerationNearlyGravityCount() < STEPS_TO_DECIDE_BALLISTIC) { @@ -439,7 +453,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q _entity->setVelocity(zero); _entity->setAngularVelocity(zero); } - _sentInactive = false; + _numInactiveUpdates = 0; } // remember properties for local server prediction @@ -487,12 +501,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID // but we remember that we do still own it... and rely on the server to tell us that we don't properties.clearSimulationOwner(); - _outgoingPriority = NO_PRORITY; + _outgoingPriority = ZERO_SIMULATION_PRIORITY; } // else the ownership is not changing so we don't bother to pack it } else { // we don't own the simulation for this entity yet, but we're sending a bid for it - properties.setSimulationOwner(sessionID, glm::max(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY)); + properties.setSimulationOwner(sessionID, glm::max(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY)); _nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS; } @@ -557,7 +571,7 @@ void EntityMotionState::clearIncomingDirtyFlags() { } // virtual -quint8 EntityMotionState::getSimulationPriority() const { +uint8_t EntityMotionState::getSimulationPriority() const { return _entity->getSimulationPriority(); } @@ -567,7 +581,7 @@ QUuid EntityMotionState::getSimulatorID() const { return _entity->getSimulatorID(); } -void EntityMotionState::bump(quint8 priority) { +void EntityMotionState::bump(uint8_t priority) { setOutgoingPriority(glm::max(VOLUNTEER_SIMULATION_PRIORITY, --priority)); } @@ -600,7 +614,7 @@ void EntityMotionState::measureBodyAcceleration() { if (numSubsteps > PHYSICS_ENGINE_MAX_NUM_SUBSTEPS) { _loopsWithoutOwner = 0; _lastStep = ObjectMotionState::getWorldSimulationStep(); - _sentInactive = false; + _numInactiveUpdates = 0; } } } @@ -630,6 +644,6 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma _entity->computeCollisionGroupAndFinalMask(group, mask); } -void EntityMotionState::setOutgoingPriority(quint8 priority) { - _outgoingPriority = glm::max(_outgoingPriority, priority); +void EntityMotionState::setOutgoingPriority(uint8_t priority) { + _outgoingPriority = glm::max(_outgoingPriority, priority); } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 7e350a4bae..cab8448dd9 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -53,7 +53,7 @@ public: void incrementAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount++; } void resetAccelerationNearlyGravityCount() { _accelerationNearlyGravityCount = 0; } - quint8 getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } + uint8_t getAccelerationNearlyGravityCount() { return _accelerationNearlyGravityCount; } virtual float getObjectRestitution() const override { return _entity->getRestitution(); } virtual float getObjectFriction() const override { return _entity->getFriction(); } @@ -69,9 +69,9 @@ public: virtual const QUuid getObjectID() const override { return _entity->getID(); } - virtual quint8 getSimulationPriority() const override; + virtual uint8_t getSimulationPriority() const override; virtual QUuid getSimulatorID() const override; - virtual void bump(quint8 priority) override; + virtual void bump(uint8_t priority) override; EntityItemPointer getEntity() const { return _entityPtr.lock(); } @@ -83,7 +83,7 @@ public: virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const override; // eternal logic can suggest a simuator priority bid for the next outgoing update - void setOutgoingPriority(quint8 priority); + void setOutgoingPriority(uint8_t priority); friend class PhysicalEntitySimulation; @@ -106,10 +106,6 @@ protected: // Meanwhile we also keep a raw EntityItem* for internal stuff where the pointer is guaranteed valid. EntityItem* _entity; - bool _triedToReleaseOwnership; // true if we tried to release ownership - - // these are for the prediction of the remote server's simple extrapolation - uint32_t _lastStep; // last step of server extrapolation glm::vec3 _serverPosition; // in simulation-frame (not world-frame) glm::quat _serverRotation; glm::vec3 _serverVelocity; @@ -118,15 +114,18 @@ protected: glm::vec3 _serverAcceleration; QByteArray _serverActionData; - uint32_t _lastMeasureStep; glm::vec3 _lastVelocity; glm::vec3 _measuredAcceleration; - float _measuredDeltaTime; - - quint8 _accelerationNearlyGravityCount; quint64 _nextOwnershipBid { 0 }; - quint64 _orphanExpiry { 0 }; - quint8 _outgoingPriority = NO_PRORITY; + + float _measuredDeltaTime; + uint32_t _lastMeasureStep; + uint32_t _lastStep; // last step of server extrapolation + + uint8_t _loopsWithoutOwner; + uint8_t _accelerationNearlyGravityCount; + uint8_t _numInactiveUpdates { 1 }; + uint8_t _outgoingPriority { ZERO_SIMULATION_PRIORITY }; }; #endif // hifi_EntityMotionState_h