From c56a6c44f85e93ad4014607433bb976fda16ba71 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 1 Jun 2017 10:03:50 -0700 Subject: [PATCH 1/4] minor formatting fix --- libraries/entities/src/EntityItem.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 431b87cc61..640eba61d8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -681,7 +681,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // and pretend that we own it (we assume we'll recover it soon) // However, for now, when the server uses a newer time than what we sent, listen to what we're told. - if (overwriteLocalData) weOwnSimulation = false; + if (overwriteLocalData) { + weOwnSimulation = false; + } } else if (_simulationOwner.set(newSimOwner)) { markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID); somethingChanged = true; From e34f979ed925c255eaaaa6e1311105db4256b132 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 1 Jun 2017 10:04:31 -0700 Subject: [PATCH 2/4] add EntityMotionState::isLocallyOwned() for cleaner logic --- libraries/physics/src/EntityMotionState.cpp | 14 +++++++++----- libraries/physics/src/EntityMotionState.h | 1 + libraries/physics/src/ObjectMotionState.h | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index fdd290bfca..50209a2101 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -84,7 +84,7 @@ EntityMotionState::~EntityMotionState() { void EntityMotionState::updateServerPhysicsVariables() { assert(entityTreeIsLocked()); - if (_entity->getSimulatorID() == Physics::getSessionUUID()) { + if (isLocallyOwned()) { // don't slam these values if we are the simulation owner return; } @@ -135,7 +135,7 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) { _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; } _loopsWithoutOwner = 0; - } else if (_entity->getSimulatorID() == Physics::getSessionUUID()) { + } else if (isLocallyOwned()) { // we just inherited ownership, make sure our desired priority matches what we have upgradeOutgoingPriority(_entity->getSimulationPriority()); } else { @@ -315,7 +315,7 @@ bool EntityMotionState::isCandidateForOwnership() const { assert(_entity); assert(entityTreeIsLocked()); return _outgoingPriority != 0 - || Physics::getSessionUUID() == _entity->getSimulatorID() + || isLocallyOwned() || _entity->dynamicDataNeedsTransmit(); } @@ -489,7 +489,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) { return true; } - if (_entity->getSimulatorID() != Physics::getSessionUUID()) { + if (!isLocallyOwned()) { // we don't own the simulation // NOTE: we do not volunteer to own kinematic or static objects @@ -597,7 +597,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.clearSimulationOwner(); _outgoingPriority = 0; _entity->setPendingOwnershipPriority(_outgoingPriority, now); - } else if (Physics::getSessionUUID() != _entity->getSimulatorID()) { + } else if (!isLocallyOwned()) { // we don't own the simulation for this entity yet, but we're sending a bid for it quint8 bidPriority = glm::max(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY); properties.setSimulationOwner(Physics::getSessionUUID(), bidPriority); @@ -786,6 +786,10 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma _entity->computeCollisionGroupAndFinalMask(group, mask); } +bool EntityMotionState::isLocallyOwned() const { + return _entity->getSimulatorID() == Physics::getSessionUUID(); +} + bool EntityMotionState::shouldBeLocallyOwned() const { return (_outgoingPriority > VOLUNTEER_SIMULATION_PRIORITY && _outgoingPriority > _entity->getSimulationPriority()) || _entity->getSimulatorID() == Physics::getSessionUUID(); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 380edf3927..541ad7c93c 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -79,6 +79,7 @@ public: virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const override; + bool isLocallyOwned() const override; bool shouldBeLocallyOwned() const override; friend class PhysicalEntitySimulation; diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 1e582ea854..a12a2eaa01 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -146,6 +146,7 @@ public: void dirtyInternalKinematicChanges() { _hasInternalKinematicChanges = true; } void clearInternalKinematicChanges() { _hasInternalKinematicChanges = false; } + virtual bool isLocallyOwned() const { return false; } virtual bool shouldBeLocallyOwned() const { return false; } friend class PhysicsEngine; From 74827fc4c802ea3c60a4031818dc76502d80d007 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 1 Jun 2017 10:05:26 -0700 Subject: [PATCH 3/4] recently moved static objects added to changelist since static objects are not active this will make the interface release ownership of recently changed static objects --- libraries/physics/src/PhysicsEngine.cpp | 43 +++++++++++-------- libraries/physics/src/PhysicsEngine.h | 3 +- .../physics/src/ThreadSafeDynamicsWorld.h | 2 + 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 3a02e95e7c..1c6faada1d 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -129,6 +129,9 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { } body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); body->updateInertiaTensor(); + if (motionState->isLocallyOwned()) { + _activeStaticBodies.insert(body); + } break; } } @@ -174,19 +177,9 @@ void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) { // frame (because the framerate is faster than our physics simulation rate). When this happens we must scan // _activeStaticBodies for objects that were recently deleted so we don't try to access a dangling pointer. for (auto object : objects) { - btRigidBody* body = object->getRigidBody(); - - std::vector::reverse_iterator itr = _activeStaticBodies.rbegin(); - while (itr != _activeStaticBodies.rend()) { - if (body == *itr) { - if (*itr != *(_activeStaticBodies.rbegin())) { - // swap with rbegin - *itr = *(_activeStaticBodies.rbegin()); - } - _activeStaticBodies.pop_back(); - break; - } - ++itr; + std::set::iterator itr = _activeStaticBodies.find(object->getRigidBody()); + if (itr != _activeStaticBodies.end()) { + _activeStaticBodies.erase(itr); } } } @@ -245,14 +238,16 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob object->clearIncomingDirtyFlags(); } if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) { - _activeStaticBodies.push_back(object->getRigidBody()); + _activeStaticBodies.insert(object->getRigidBody()); } } // active static bodies have changed (in an Easy way) and need their Aabbs updated // but we've configured Bullet to NOT update them automatically (for improved performance) // so we must do it ourselves - for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { - _dynamicsWorld->updateSingleAabb(_activeStaticBodies[i]); + std::set::const_iterator itr = _activeStaticBodies.begin(); + while (itr != _activeStaticBodies.end()) { + _dynamicsWorld->updateSingleAabb(*itr); + ++itr; } return stillNeedChange; } @@ -496,13 +491,23 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() { const VectorOfMotionStates& PhysicsEngine::getChangedMotionStates() { BT_PROFILE("copyOutgoingChanges"); + + _dynamicsWorld->synchronizeMotionStates(); + // Bullet will not deactivate static objects (it doesn't expect them to be active) // so we must deactivate them ourselves - for (size_t i = 0; i < _activeStaticBodies.size(); ++i) { - _activeStaticBodies[i]->forceActivationState(ISLAND_SLEEPING); + std::set::const_iterator itr = _activeStaticBodies.begin(); + while (itr != _activeStaticBodies.end()) { + btRigidBody* body = *itr; + body->forceActivationState(ISLAND_SLEEPING); + ObjectMotionState* motionState = static_cast(body->getUserPointer()); + if (motionState) { + _dynamicsWorld->addChangedMotionState(motionState); + } + ++itr; } _activeStaticBodies.clear(); - _dynamicsWorld->synchronizeMotionStates(); + _hasOutgoingChanges = false; return _dynamicsWorld->getChangedMotionStates(); } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index e9b29a43a4..b20d73f0e6 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -13,6 +13,7 @@ #define hifi_PhysicsEngine_h #include +#include #include #include @@ -114,7 +115,7 @@ private: CollisionEvents _collisionEvents; QHash _objectDynamics; QHash> _objectDynamicsByBody; - std::vector _activeStaticBodies; + std::set _activeStaticBodies; glm::vec3 _originOffset; diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h index b4fcca8cdb..54c3ddb756 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.h +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h @@ -51,6 +51,8 @@ public: const VectorOfMotionStates& getChangedMotionStates() const { return _changedMotionStates; } const VectorOfMotionStates& getDeactivatedMotionStates() const { return _deactivatedStates; } + void addChangedMotionState(ObjectMotionState* motionState) { _changedMotionStates.push_back(motionState); } + private: // call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState() void synchronizeMotionState(btRigidBody* body); From 29a05d7eb4832102b8e6bf65f6a41514c288e63f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 1 Jun 2017 14:17:14 -0700 Subject: [PATCH 4/4] bid immediately when creating new entity also clear EntityMotionState::_numInactiveUpdates on new ownership --- libraries/entities/src/EntityItem.cpp | 20 ++++------------- libraries/entities/src/EntityItem.h | 4 ++-- .../entities/src/EntityScriptingInterface.cpp | 10 +++++---- libraries/entities/src/SimulationFlags.h | 4 +--- libraries/entities/src/SimulationOwner.cpp | 22 +++++++++---------- libraries/entities/src/SimulationOwner.h | 5 +++-- libraries/physics/src/EntityMotionState.cpp | 21 +++++++++--------- 7 files changed, 38 insertions(+), 48 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 640eba61d8..530e356137 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1295,27 +1295,15 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c properties._accelerationChanged = true; } -void EntityItem::pokeSimulationOwnership() { - markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_POKE); +void EntityItem::flagForOwnershipBid(uint8_t priority) { + markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY); auto nodeList = DependencyManager::get(); if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) { // we already own it - _simulationOwner.promotePriority(SCRIPT_POKE_SIMULATION_PRIORITY); + _simulationOwner.promotePriority(priority); } else { // we don't own it yet - _simulationOwner.setPendingPriority(SCRIPT_POKE_SIMULATION_PRIORITY, usecTimestampNow()); - } -} - -void EntityItem::grabSimulationOwnership() { - markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB); - auto nodeList = DependencyManager::get(); - if (_simulationOwner.matchesValidID(nodeList->getSessionUUID())) { - // we already own it - _simulationOwner.promotePriority(SCRIPT_GRAB_SIMULATION_PRIORITY); - } else { - // we don't own it yet - _simulationOwner.setPendingPriority(SCRIPT_GRAB_SIMULATION_PRIORITY, usecTimestampNow()); + _simulationOwner.setPendingPriority(priority, usecTimestampNow()); } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 3243f50556..7c08137a1c 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -321,6 +321,7 @@ public: void updateSimulationOwner(const SimulationOwner& owner); void clearSimulationOwnership(); void setPendingOwnershipPriority(quint8 priority, const quint64& timestamp); + uint8_t getPendingOwnershipPriority() const { return _simulationOwner.getPendingPriority(); } void rememberHasSimulationOwnershipBid() const; QString getMarketplaceID() const; @@ -394,8 +395,7 @@ public: void getAllTerseUpdateProperties(EntityItemProperties& properties) const; - void pokeSimulationOwnership(); - void grabSimulationOwnership(); + void flagForOwnershipBid(uint8_t priority); void flagForMotionStateChange() { _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } QString actionsToDebugString(); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index b184d648da..90dc6893b4 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -230,6 +230,8 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties } entity->setLastBroadcast(usecTimestampNow()); + // since we're creating this object we will immediately volunteer to own its simulation + entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY); propertiesWithSimID.setLastEdited(entity->getLastEdited()); } else { qCDebug(entities) << "script failed to add new Entity to local Octree"; @@ -440,7 +442,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& } else { // we make a bid for simulation ownership properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY); - entity->pokeSimulationOwnership(); + entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY); entity->rememberHasSimulationOwnershipBid(); } } @@ -1194,7 +1196,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, } action->setIsMine(true); success = entity->addAction(simulation, action); - entity->grabSimulationOwnership(); + entity->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY); return false; // Physics will cause a packet to be sent, so don't send from here. }); if (success) { @@ -1210,7 +1212,7 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid& return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { bool success = entity->updateAction(simulation, actionID, arguments); if (success) { - entity->grabSimulationOwnership(); + entity->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY); } return success; }); @@ -1224,7 +1226,7 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid& success = entity->removeAction(simulation, actionID); if (success) { // reduce from grab to poke - entity->pokeSimulationOwnership(); + entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY); } return false; // Physics will cause a packet to be sent, so don't send from here. }); diff --git a/libraries/entities/src/SimulationFlags.h b/libraries/entities/src/SimulationFlags.h index dbcf51afc0..e2b2224b4a 100644 --- a/libraries/entities/src/SimulationFlags.h +++ b/libraries/entities/src/SimulationFlags.h @@ -26,12 +26,10 @@ namespace Simulation { const uint32_t DIRTY_MATERIAL = 0x00400; const uint32_t DIRTY_PHYSICS_ACTIVATION = 0x0800; // should activate object in physics engine const uint32_t DIRTY_SIMULATOR_ID = 0x1000; // the simulatorID has changed - const uint32_t DIRTY_SIMULATION_OWNERSHIP_FOR_POKE = 0x2000; // bid for simulation ownership at "poke" - const uint32_t DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB = 0x4000; // bid for simulation ownership at "grab" + const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = 0x2000; // our own bid priority has changed const uint32_t DIRTY_TRANSFORM = DIRTY_POSITION | DIRTY_ROTATION; const uint32_t DIRTY_VELOCITIES = DIRTY_LINEAR_VELOCITY | DIRTY_ANGULAR_VELOCITY; - const uint32_t DIRTY_SIMULATION_OWNERSHIP_PRIORITY = DIRTY_SIMULATION_OWNERSHIP_FOR_POKE | DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB; }; #endif // hifi_SimulationFlags_h diff --git a/libraries/entities/src/SimulationOwner.cpp b/libraries/entities/src/SimulationOwner.cpp index 77645a9e62..4398582673 100644 --- a/libraries/entities/src/SimulationOwner.cpp +++ b/libraries/entities/src/SimulationOwner.cpp @@ -26,9 +26,9 @@ const int SimulationOwner::NUM_BYTES_ENCODED = NUM_BYTES_RFC4122_UUID + 1; SimulationOwner::SimulationOwner() : _id(), _expiry(0), - _pendingTimestamp(0), + _pendingBidTimestamp(0), _priority(0), - _pendingPriority(0), + _pendingBidPriority(0), _pendingState(PENDING_STATE_NOTHING) { } @@ -36,9 +36,9 @@ SimulationOwner::SimulationOwner() : SimulationOwner::SimulationOwner(const QUuid& id, quint8 priority) : _id(id), _expiry(0), - _pendingTimestamp(0), + _pendingBidTimestamp(0), _priority(priority), - _pendingPriority(0) + _pendingBidPriority(0) { } @@ -61,9 +61,9 @@ bool SimulationOwner::fromByteArray(const QByteArray& data) { void SimulationOwner::clear() { _id = QUuid(); _expiry = 0; - _pendingTimestamp = 0; + _pendingBidTimestamp = 0; _priority = 0; - _pendingPriority = 0; + _pendingBidPriority = 0; _pendingState = PENDING_STATE_NOTHING; } @@ -102,9 +102,9 @@ bool SimulationOwner::set(const SimulationOwner& owner) { } void SimulationOwner::setPendingPriority(quint8 priority, const quint64& timestamp) { - _pendingPriority = priority; - _pendingTimestamp = timestamp; - _pendingState = (_pendingPriority == 0) ? PENDING_STATE_RELEASE : PENDING_STATE_TAKE; + _pendingBidPriority = priority; + _pendingBidTimestamp = timestamp; + _pendingState = (_pendingBidPriority == 0) ? PENDING_STATE_RELEASE : PENDING_STATE_TAKE; } void SimulationOwner::updateExpiry() { @@ -113,11 +113,11 @@ void SimulationOwner::updateExpiry() { } bool SimulationOwner::pendingRelease(const quint64& timestamp) { - return _pendingPriority == 0 && _pendingState == PENDING_STATE_RELEASE && _pendingTimestamp >= timestamp; + return _pendingBidPriority == 0 && _pendingState == PENDING_STATE_RELEASE && _pendingBidTimestamp >= timestamp; } bool SimulationOwner::pendingTake(const quint64& timestamp) { - return _pendingPriority > 0 && _pendingState == PENDING_STATE_TAKE && _pendingTimestamp >= timestamp; + return _pendingBidPriority > 0 && _pendingState == PENDING_STATE_TAKE && _pendingBidTimestamp >= timestamp; } void SimulationOwner::clearCurrentOwner() { diff --git a/libraries/entities/src/SimulationOwner.h b/libraries/entities/src/SimulationOwner.h index 5f940bbe25..94ed1d9a08 100644 --- a/libraries/entities/src/SimulationOwner.h +++ b/libraries/entities/src/SimulationOwner.h @@ -66,6 +66,7 @@ public: bool hasExpired() const { return usecTimestampNow() > _expiry; } + uint8_t getPendingPriority() const { return _pendingBidPriority; } bool pendingRelease(const quint64& timestamp); // return true if valid pending RELEASE bool pendingTake(const quint64& timestamp); // return true if valid pending TAKE void clearCurrentOwner(); @@ -84,9 +85,9 @@ public: private: QUuid _id; // owner quint64 _expiry; // time when ownership can transition at equal priority - quint64 _pendingTimestamp; // time when pending update was set + quint64 _pendingBidTimestamp; // time when pending bid was set quint8 _priority; // priority of current owner - quint8 _pendingPriority; // priority of pendingTake + quint8 _pendingBidPriority; // priority at which we'd like to own it quint8 _pendingState; // NOTHING, TAKE, or RELEASE }; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 50209a2101..d4be72e699 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -65,8 +65,7 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer _lastStep(0), _loopsWithoutOwner(0), _accelerationNearlyGravityCount(0), - _numInactiveUpdates(1), - _outgoingPriority(0) + _numInactiveUpdates(1) { _type = MOTIONSTATE_TYPE_ENTITY; assert(_entity); @@ -75,6 +74,8 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer // we need the side-effects of EntityMotionState::setShape() so we call it explicitly here // rather than pass the legit shape pointer to the ObjectMotionState ctor above. setShape(shape); + + _outgoingPriority = _entity->getPendingOwnershipPriority(); } EntityMotionState::~EntityMotionState() { @@ -135,23 +136,23 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) { _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; } _loopsWithoutOwner = 0; + _numInactiveUpdates = 0; } else if (isLocallyOwned()) { // we just inherited ownership, make sure our desired priority matches what we have upgradeOutgoingPriority(_entity->getSimulationPriority()); } else { _outgoingPriority = 0; _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; + _numInactiveUpdates = 0; } } if (flags & Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) { - // The DIRTY_SIMULATOR_OWNERSHIP_PRIORITY bits really mean "we should bid for ownership because - // a local script has been changing physics properties, or we should adjust our own ownership priority". - // The desired priority is determined by which bits were set. - if (flags & Simulation::DIRTY_SIMULATION_OWNERSHIP_FOR_GRAB) { - _outgoingPriority = SCRIPT_GRAB_SIMULATION_PRIORITY; - } else { - _outgoingPriority = SCRIPT_POKE_SIMULATION_PRIORITY; - } + // The DIRTY_SIMULATOR_OWNERSHIP_PRIORITY bit means one of the following: + // (1) we own it but may need to change the priority OR... + // (2) we don't own it but should bid (because a local script has been changing physics properties) + uint8_t newPriority = isLocallyOwned() ? _entity->getSimulationOwner().getPriority() : _entity->getSimulationOwner().getPendingPriority(); + _outgoingPriority = glm::max(_outgoingPriority, newPriority); + // reset bid expiry so that we bid ASAP _nextOwnershipBid = 0; }