diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 37164bd6f6..1e10ff2e48 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -27,6 +27,8 @@ #include "EntityTree.h" #include "EntitySimulation.h" +const quint64 SIMULATOR_CHANGE_LOCKOUT_PERIOD = (quint64)(0.2f * USECS_PER_SECOND); + bool EntityItem::_sendPhysicsUpdates = true; EntityItem::EntityItem(const EntityItemID& entityItemID) : @@ -66,7 +68,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _userData(ENTITY_ITEM_DEFAULT_USER_DATA), _simulatorPriority(0), _simulatorID(ENTITY_ITEM_DEFAULT_SIMULATOR_ID), - _simulatorIDChangedTime(0), + _simulationOwnershipExpiry(0), _marketplaceID(ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), _name(ENTITY_ITEM_DEFAULT_NAME), _href(""), @@ -594,23 +596,24 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // ownership has changed auto nodeList = DependencyManager::get(); if (_simulatorID == nodeList->getSessionUUID()) { - // we think we're the owner but entityServer says otherwise we only relenquish - // ownership if the incoming priority is greater than or equal to ours - if (priority >= _simulatorPriority) { + // we think we're the owner but entityServer says otherwise + // we relenquish ownership if the incoming priority is greater than or equal to ours + // AND we don't have max priority + if (priority >= _simulatorPriority && _simulatorPriority != MAX_SIMULATOR_PRIORITY) { // we're losing simulation ownership _simulatorID = id; _simulatorPriority = priority; - _simulatorIDChangedTime = usecTimestampNow(); + _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; } } else { _simulatorID = id; _simulatorPriority = priority; - _simulatorIDChangedTime = usecTimestampNow(); + _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; } } else if (priority != _simulatorPriority) { - // This should be an uncommon event: priority is changing but simulatorID is not. - // We only accept this change if we are NOT the simulator owner, since otherwise - // we would have initiated this change. + // priority is changing but simulatorID is not. + // only accept this change if we are NOT the simulator owner, since otherwise + // we would have initiated this change auto nodeList = DependencyManager::get(); if (_simulatorID != nodeList->getSessionUUID()) { _simulatorPriority = priority; @@ -1393,14 +1396,16 @@ void EntityItem::updateCreated(uint64_t value) { } void EntityItem::setSimulatorID(const QUuid& value) { - _simulatorID = value; - _simulatorIDChangedTime = usecTimestampNow(); + if (_simulatorID != value) { + _simulatorID = value; + _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; + } } void EntityItem::updateSimulatorID(const QUuid& value) { if (_simulatorID != value) { _simulatorID = value; - _simulatorIDChangedTime = usecTimestampNow(); + _simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD; _dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 135ac78617..fe82870992 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -326,7 +326,7 @@ public: QUuid getSimulatorID() const { return _simulatorID; } void setSimulatorID(const QUuid& value); void updateSimulatorID(const QUuid& value); - quint64 getSimulatorIDChangedTime() const { return _simulatorIDChangedTime; } + const quint64& getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; } const QString& getMarketplaceID() const { return _marketplaceID; } void setMarketplaceID(const QString& value) { _marketplaceID = value; } @@ -433,7 +433,7 @@ protected: QString _userData; uint8_t _simulatorPriority; QUuid _simulatorID; // id of Node which is currently responsible for simulating this Entity - quint64 _simulatorIDChangedTime; // when was _simulatorID last updated? + quint64 _simulationOwnershipExpiry; // time in future when ownership is back up for grabs QString _marketplaceID; QString _name; QString _href; //Hyperlink href diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 752082932b..a3ef5f9261 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -157,6 +157,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI if (entity->getSimulatorID() == senderID) { // We only allow the simulation owner to clear their own simulationID's. simulationBlocked = false; + properties.setSimulatorPriority(0); // clear priority irregardless of priority sent } // else: We assume the sender really did believe it was the simulation owner when it sent } else if (submittedID == senderID) { @@ -165,9 +166,18 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI simulationBlocked = false; } else { // the sender is trying to steal ownership from another simulator - // so we apply the ownership change filter - if (usecTimestampNow() - entity->getSimulatorIDChangedTime() > SIMULATOR_CHANGE_LOCKOUT_PERIOD) { - simulationBlocked = false; + // so we apply the rules for ownership change: + // (1) higher priority wins + // (2) equal priority wins if ownership filter has expired except... + // (3) max priority never loses + uint8_t oldPriority = entity->getSimulatorPriority(); + if (oldPriority != MAX_SIMULATOR_PRIORITY) { + uint8_t newPriority = properties.getSimulatorPriority(); + if (newPriority > oldPriority || + (newPriority == oldPriority && + usecTimestampNow() > entity->getSimulationOwnershipExpiry())) { + simulationBlocked = false; + } } } } else { @@ -177,6 +187,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI } if (simulationBlocked) { // squash the physics-related changes. + properties.setSimulatorPriorityChanged(false); properties.setSimulatorIDChanged(false); properties.setPositionChanged(false); properties.setRotationChanged(false);