reduce sim ownership priority when releasing grab

This commit is contained in:
Andrew Meadows 2018-05-17 17:25:07 -07:00
parent 926014b43f
commit 00e360aff0
9 changed files with 160 additions and 146 deletions

View file

@ -76,7 +76,7 @@ void addAvatarEntities(const QVariantList& avatarEntities) {
entity->setLastBroadcast(usecTimestampNow());
// since we're creating this object we will immediately volunteer to own its simulation
entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY);
entity->setScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
entityProperties.setLastEdited(entity->getLastEdited());
} else {
qCDebug(entities) << "AvatarEntitiesBookmark failed to add new Entity to local Octree";

View file

@ -353,6 +353,10 @@ int EntityItem::expectedBytes() {
return MINIMUM_HEADER_BYTES;
}
const uint8_t PENDING_STATE_NOTHING = 0;
const uint8_t PENDING_STATE_TAKE = 1;
const uint8_t PENDING_STATE_RELEASE = 2;
// clients use this method to unpack FULL updates from entity-server
int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
setSourceUUID(args.sourceUUID);
@ -664,7 +668,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// setters to ignore what the server says.
filterRejection = newSimOwner.getID().isNull();
if (weOwnSimulation) {
if (newSimOwner.getID().isNull() && !_simulationOwner.pendingRelease(lastEditedFromBufferAdjusted)) {
if (newSimOwner.getID().isNull() && !pendingRelease(lastEditedFromBufferAdjusted)) {
// entity-server is trying to clear our ownership (probably at our own request)
// but we actually want to own it, therefore we ignore this clear event
// and pretend that we own it (e.g. we assume we'll receive ownership soon)
@ -679,32 +683,53 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// recompute weOwnSimulation for later
weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
}
} else if (_simulationOwner.pendingTake(now - maxPingRoundTrip)) {
// we sent a bid already but maybe before this packet was sent from the server
weOwnSimulation = true;
} else if (_pendingOwnershipState == PENDING_STATE_TAKE) {
// we're waiting to receive acceptance of a bid
// this ownership data either satisifies our bid or does not
bool bidIsSatisfied = newSimOwner.getID() == myNodeID &&
(newSimOwner.getPriority() == _pendingOwnershipPriority ||
(_pendingOwnershipPriority == VOLUNTEER_SIMULATION_PRIORITY &&
newSimOwner.getPriority() == RECRUIT_SIMULATION_PRIORITY));
if (newSimOwner.getID().isNull()) {
// the entity-server is trying to clear someone else's ownership
// the entity-server is clearing someone else's ownership
if (!_simulationOwner.isNull()) {
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
somethingChanged = true;
_simulationOwner.clearCurrentOwner();
}
} else if (newSimOwner.getID() == myNodeID) {
// the entity-server is awarding us ownership which is what we want
_simulationOwner.set(newSimOwner);
} else {
if (newSimOwner.getID() != _simulationOwner.getID()) {
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
}
if (_simulationOwner.set(newSimOwner)) {
// the entity-server changed ownership
somethingChanged = true;
}
}
if (bidIsSatisfied || _pendingOwnershipTimestamp < now - maxPingRoundTrip) {
// the bid has been satisfied, or it has been invalidated by data sent AFTER the bid should have been received
// in either case: accept our fate and clear pending state
_pendingOwnershipState = PENDING_STATE_NOTHING;
_pendingOwnershipPriority = 0;
}
weOwnSimulation = bidIsSatisfied || (_simulationOwner.getID() == myNodeID);
} else {
// we are not waiting to take ownership
if (newSimOwner.getID() != _simulationOwner.getID()) {
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
}
if (_simulationOwner.set(newSimOwner)) {
// the entity-server changed ownership...
somethingChanged = true;
if (newSimOwner.getID() == myNodeID) {
// we have recieved ownership
weOwnSimulation = true;
// accept our fate and clear pendingState (just in case)
_pendingOwnershipState = PENDING_STATE_NOTHING;
_pendingOwnershipPriority = 0;
}
}
} else if (newSimOwner.matchesValidID(myNodeID) && !_simulationOwner.pendingTake(now)) {
// entity-server tells us that we have simulation ownership while we never requested this for this EntityItem,
// this could happen when the user reloads the cache and entity tree.
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
somethingChanged = true;
_simulationOwner.clearCurrentOwner();
weOwnSimulation = false;
} else if (_simulationOwner.set(newSimOwner)) {
markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID);
somethingChanged = true;
// recompute weOwnSimulation for later
weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
}
}
@ -1305,6 +1330,7 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c
properties._accelerationChanged = true;
}
/*
void EntityItem::flagForOwnershipBid(uint8_t priority) {
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY);
auto nodeList = DependencyManager::get<NodeList>();
@ -1316,6 +1342,40 @@ void EntityItem::flagForOwnershipBid(uint8_t priority) {
_simulationOwner.setPendingPriority(priority, usecTimestampNow());
}
}
*/
void EntityItem::setScriptSimulationPriority(uint8_t priority) {
uint8_t newPriority = stillHasGrabActions() ? glm::max(priority, SCRIPT_GRAB_SIMULATION_PRIORITY) : priority;
if (newPriority != _scriptSimulationPriority) {
// set the dirty flag to trigger a bid or ownership update
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY);
_scriptSimulationPriority = newPriority;
}
}
void EntityItem::clearScriptSimulationPriority() {
// DO NOT markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY) here, because this
// is only ever called from the code that actually handles the dirty flags, and it knows best.
_scriptSimulationPriority = stillHasGrabActions() ? SCRIPT_GRAB_SIMULATION_PRIORITY : 0;
}
void EntityItem::setPendingOwnershipPriority(uint8_t priority) {
_pendingOwnershipTimestamp = usecTimestampNow();
_pendingOwnershipPriority = priority;
_pendingOwnershipState = (_pendingOwnershipPriority == 0) ? PENDING_STATE_RELEASE : PENDING_STATE_TAKE;
}
bool EntityItem::pendingRelease(uint64_t timestamp) const {
return _pendingOwnershipPriority == 0 &&
_pendingOwnershipState == PENDING_STATE_RELEASE &&
_pendingOwnershipTimestamp >= timestamp;
}
bool EntityItem::stillWaitingToTakeOwnership(uint64_t timestamp) const {
return _pendingOwnershipPriority > 0 &&
_pendingOwnershipState == PENDING_STATE_TAKE &&
_pendingOwnershipTimestamp >= timestamp;
}
bool EntityItem::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
@ -1941,10 +2001,6 @@ void EntityItem::clearSimulationOwnership() {
}
void EntityItem::setPendingOwnershipPriority(uint8_t priority, const quint64& timestamp) {
_simulationOwner.setPendingPriority(priority, timestamp);
}
QString EntityItem::actionsToDebugString() {
QString result;
QVector<QByteArray> serializedActions;
@ -2040,6 +2096,7 @@ bool EntityItem::updateAction(EntitySimulationPointer simulation, const QUuid& a
}
bool EntityItem::removeAction(EntitySimulationPointer simulation, const QUuid& actionID) {
// TODO: some action
bool success = false;
withWriteLock([&] {
checkWaitingToRemove(simulation);

View file

@ -308,14 +308,21 @@ public:
const SimulationOwner& getSimulationOwner() const { return _simulationOwner; }
void setSimulationOwner(const QUuid& id, uint8_t priority);
void setSimulationOwner(const SimulationOwner& owner);
void promoteSimulationPriority(uint8_t priority);
uint8_t getSimulationPriority() const { return _simulationOwner.getPriority(); }
QUuid getSimulatorID() const { return _simulationOwner.getID(); }
void clearSimulationOwnership();
void setPendingOwnershipPriority(uint8_t priority, const quint64& timestamp);
uint8_t getPendingOwnershipPriority() const { return _simulationOwner.getPendingPriority(); }
void rememberHasSimulationOwnershipBid() const;
// TODO: move this "ScriptSimulationPriority" and "PendingOwnership" stuff into EntityMotionState
// but first would need to do some other cleanup. In the meantime these live here as "scratch space"
// to allow libs that don't know about each other to communicate.
void setScriptSimulationPriority(uint8_t priority);
void clearScriptSimulationPriority();
uint8_t getScriptSimulationPriority() const { return _scriptSimulationPriority; }
void setPendingOwnershipPriority(uint8_t priority);
uint8_t getPendingOwnershipPriority() const { return _pendingOwnershipPriority; }
bool pendingRelease(uint64_t timestamp) const;
bool stillWaitingToTakeOwnership(uint64_t timestamp) const;
// Certifiable Properties
QString getItemName() const;
@ -395,7 +402,6 @@ public:
void getAllTerseUpdateProperties(EntityItemProperties& properties) const;
void flagForOwnershipBid(uint8_t priority);
void flagForMotionStateChange() { _flags |= Simulation::DIRTY_MOTION_TYPE; }
QString actionsToDebugString();
@ -654,6 +660,15 @@ protected:
float _boundingRadius { 0.0f };
int32_t _spaceIndex { -1 }; // index to proxy in workload::Space
// TODO: move this "scriptSimulationPriority" and "pendingOwnership" stuff into EntityMotionState
// but first would need to do some other cleanup. In the meantime these live here as "scratch space"
// to allow libs that don't know about each other to communicate.
uint64_t _pendingOwnershipTimestamp { 0 }; // timestamp of last owenership change request
uint8_t _pendingOwnershipPriority { 0 }; // priority of last ownership change request
uint8_t _pendingOwnershipState { 0 }; // TAKE or RELEASE
uint8_t _scriptSimulationPriority { 0 }; // target priority based on script operations
bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera
private:

View file

@ -327,7 +327,7 @@ public:
void clearSimulationOwner();
void setSimulationOwner(const QUuid& id, uint8_t priority);
void setSimulationOwner(const QByteArray& data);
void promoteSimulationPriority(uint8_t priority) { _simulationOwner.promotePriority(priority); }
void setSimulationPriority(uint8_t priority) { _simulationOwner.setPriority(priority); }
void setActionDataDirty() { _actionDataChanged = true; }

View file

@ -277,7 +277,7 @@ 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);
entity->setScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
propertiesWithSimID.setLastEdited(entity->getLastEdited());
} else {
qCDebug(entities) << "script failed to add new Entity to local Octree";
@ -465,7 +465,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
} else {
// we make a bid for simulation ownership
properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY);
entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY);
entity->setScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY);
}
}
if (properties.queryAACubeRelatedPropertyChanged()) {
@ -1334,7 +1334,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
}
action->setIsMine(true);
success = entity->addAction(simulation, action);
entity->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY);
entity->setScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
return false; // Physics will cause a packet to be sent, so don't send from here.
});
if (success) {
@ -1350,7 +1350,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->flagForOwnershipBid(SCRIPT_GRAB_SIMULATION_PRIORITY);
entity->setScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
}
return success;
});
@ -1364,7 +1364,7 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid&
success = entity->removeAction(simulation, actionID);
if (success) {
// reduce from grab to poke
entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY);
entity->setScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY);
}
return false; // Physics will cause a packet to be sent, so don't send from here.
});

View file

@ -16,29 +16,20 @@
#include <NumericalConstants.h>
const uint8_t PENDING_STATE_NOTHING = 0;
const uint8_t PENDING_STATE_TAKE = 1;
const uint8_t PENDING_STATE_RELEASE = 2;
// static
const int SimulationOwner::NUM_BYTES_ENCODED = NUM_BYTES_RFC4122_UUID + 1;
SimulationOwner::SimulationOwner() :
_id(),
_expiry(0),
_pendingBidTimestamp(0),
_priority(0),
_pendingBidPriority(0),
_pendingState(PENDING_STATE_NOTHING)
_priority(0)
{
}
SimulationOwner::SimulationOwner(const QUuid& id, uint8_t priority) :
_id(id),
_expiry(0),
_pendingBidTimestamp(0),
_priority(priority),
_pendingBidPriority(0)
_priority(priority)
{
}
@ -61,22 +52,13 @@ bool SimulationOwner::fromByteArray(const QByteArray& data) {
void SimulationOwner::clear() {
_id = QUuid();
_expiry = 0;
_pendingBidTimestamp = 0;
_priority = 0;
_pendingBidPriority = 0;
_pendingState = PENDING_STATE_NOTHING;
}
void SimulationOwner::setPriority(uint8_t priority) {
_priority = priority;
}
void SimulationOwner::promotePriority(uint8_t priority) {
if (priority > _priority) {
_priority = priority;
}
}
bool SimulationOwner::setID(const QUuid& id) {
if (_id != id) {
_id = id;
@ -101,25 +83,11 @@ bool SimulationOwner::set(const SimulationOwner& owner) {
return setID(owner._id) || oldPriority != _priority;
}
void SimulationOwner::setPendingPriority(uint8_t priority, uint64_t timestamp) {
_pendingBidPriority = priority;
_pendingBidTimestamp = timestamp;
_pendingState = (_pendingBidPriority == 0) ? PENDING_STATE_RELEASE : PENDING_STATE_TAKE;
}
void SimulationOwner::updateExpiry() {
const uint64_t OWNERSHIP_LOCKOUT_EXPIRY = 200 * USECS_PER_MSEC;
_expiry = usecTimestampNow() + OWNERSHIP_LOCKOUT_EXPIRY;
}
bool SimulationOwner::pendingRelease(uint64_t timestamp) {
return _pendingBidPriority == 0 && _pendingState == PENDING_STATE_RELEASE && _pendingBidTimestamp >= timestamp;
}
bool SimulationOwner::pendingTake(uint64_t timestamp) {
return _pendingBidPriority > 0 && _pendingState == PENDING_STATE_TAKE && _pendingBidTimestamp >= timestamp;
}
void SimulationOwner::clearCurrentOwner() {
_id = QUuid();
_expiry = 0;

View file

@ -120,24 +120,18 @@ public:
void clear();
void setPriority(uint8_t priority);
void promotePriority(uint8_t priority);
// return true if id is changed
bool setID(const QUuid& id);
bool set(const QUuid& id, uint8_t priority);
bool set(const SimulationOwner& owner);
void setPendingPriority(uint8_t priority, uint64_t timestamp);
bool isNull() const { return _id.isNull(); }
bool matchesValidID(const QUuid& id) const { return _id == id && !_id.isNull(); }
void updateExpiry();
bool hasExpired() const { return usecTimestampNow() > _expiry; }
uint8_t getPendingPriority() const { return _pendingBidPriority; }
bool pendingRelease(uint64_t timestamp); // return true if valid pending RELEASE
bool pendingTake(uint64_t timestamp); // return true if valid pending TAKE
void clearCurrentOwner();
bool operator>=(uint8_t priority) const { return _priority >= priority; }
@ -154,10 +148,7 @@ public:
private:
QUuid _id; // owner
uint64_t _expiry; // time when ownership can transition at equal priority
uint64_t _pendingBidTimestamp; // time when pending bid was set
uint8_t _priority; // priority of current owner
uint8_t _pendingBidPriority; // priority at which we'd like to own it
uint8_t _pendingState; // NOTHING, TAKE, or RELEASE
};

View file

@ -79,7 +79,6 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
// rather than pass the legit shape pointer to the ObjectMotionState ctor above.
setShape(shape);
_bidPriority = _entity->getPendingOwnershipPriority();
if (_entity->getClientOnly() && _entity->getOwningAvatarID() != Physics::getSessionUUID()) {
// client-only entities are always thus, so we cache this fact in _ownershipState
_ownershipState = EntityMotionState::OwnershipState::Unownable;
@ -140,30 +139,21 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) {
// simulation ownership has been removed
if (glm::length2(_entity->getWorldVelocity()) == 0.0f) {
// TODO: also check angularVelocity
// this object is coming to rest --> clear the ACTIVATION flag and _bidPriority
// this object is coming to rest
flags &= ~Simulation::DIRTY_PHYSICS_ACTIVATION;
_body->setActivationState(WANTS_DEACTIVATION);
_bidPriority = 0;
const float ACTIVATION_EXPIRY = 3.0f; // something larger than the 2.0 hard coded in Bullet
_body->setDeactivationTime(ACTIVATION_EXPIRY);
} else {
// disowned object is still moving --> start timer for ownership bid
// TODO? put a delay in here proportional to distance from object?
computeNewBidPriority(VOLUNTEER_SIMULATION_PRIORITY);
_bumpedPriority = glm::max(_bumpedPriority, VOLUNTEER_SIMULATION_PRIORITY);
_nextBidExpiry = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS;
}
_loopsWithoutOwner = 0;
_numInactiveUpdates = 0;
} else if (isLocallyOwned()) {
// we just received ownership, or the priority of our existing ownership has changed
computeNewBidPriority(_entity->getSimulationPriority());
} else {
} else if (!isLocallyOwned()) {
// the entity is owned by someone else
// we are always willing to volunteer for nearby objects
// otherwise we zero _bidPriority here
// (it's possible _bidPriority will be promoted in subsequent frames
// when local scripts or owned simulation interact with it)
_bidPriority = (_region == workload::Region::R1) ? VOLUNTEER_SIMULATION_PRIORITY : 0;
_nextBidExpiry = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS;
_numInactiveUpdates = 0;
}
@ -172,9 +162,6 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) {
// 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();
computeNewBidPriority(newPriority);
// reset bid expiry so that we bid ASAP
_nextBidExpiry = 0;
}
@ -302,7 +289,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
if (_entity->getSimulatorID().isNull()) {
_loopsWithoutOwner++;
if (_loopsWithoutOwner > LOOPS_FOR_SIMULATION_ORPHAN && usecTimestampNow() > _nextBidExpiry) {
computeNewBidPriority(VOLUNTEER_SIMULATION_PRIORITY);
_bumpedPriority = glm::max(_bumpedPriority, VOLUNTEER_SIMULATION_PRIORITY);
}
}
}
@ -338,11 +325,8 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
// WIP: print info whenever _bidPriority mismatches what is known to the entity
if (_entity->dynamicDataNeedsTransmit()) {
uint8_t priority = _entity->hasActions() ? SCRIPT_GRAB_SIMULATION_PRIORITY : SCRIPT_POKE_SIMULATION_PRIORITY;
computeNewBidPriority(priority);
return true;
}
computeNewBidPriority(_entity->getSimulationPriority());
bool parentTransformSuccess;
Transform localToWorld = _entity->getParentTransform(parentTransformSuccess);
@ -470,6 +454,7 @@ void EntityMotionState::updateSendVelocities() {
if (!_body->isActive()) {
// make sure all derivatives are zero
clearObjectVelocities();
// we pretend we sent the inactive update for this object
_numInactiveUpdates = 1;
} else {
glm::vec3 gravity = _entity->getGravity();
@ -534,10 +519,10 @@ void EntityMotionState::sendBid(OctreeEditPacketSender* packetSender, uint32_t s
properties.setLastEdited(now);
// we don't own the simulation for this entity yet, but we're sending a bid for it
uint8_t bidPriority = glm::max<uint8_t>(_bidPriority, VOLUNTEER_SIMULATION_PRIORITY);
properties.setSimulationOwner(Physics::getSessionUUID(), bidPriority);
// copy _bidPriority into pendingPriority...
_entity->setPendingOwnershipPriority(_bidPriority, now);
uint8_t finalBidPriority = computeFinalBidPriority();
_entity->clearScriptSimulationPriority();
properties.setSimulationOwner(Physics::getSessionUUID(), finalBidPriority);
_entity->setPendingOwnershipPriority(finalBidPriority);
EntityTreeElementPointer element = _entity->getElement();
EntityTreePointer tree = element ? element->getTree() : nullptr;
@ -556,10 +541,10 @@ void EntityMotionState::sendBid(OctreeEditPacketSender* packetSender, uint32_t s
_lastStep = step;
_nextBidExpiry = now + USECS_BETWEEN_OWNERSHIP_BIDS;
// after sending the bid we try to clear _bidPriority
// after sending a bid/update we clear _bumpedPriority
// which might get promoted again next frame (after local script or simulation interaction)
// or we might win the bid
computeNewBidPriority(0);
_bumpedPriority = 0;
}
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step) {
@ -598,22 +583,26 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
properties.setLastEdited(now);
_entity->setSimulationOwnershipExpiry(now + MAX_OUTGOING_SIMULATION_UPDATE_PERIOD);
if (_numInactiveUpdates > 0) {
if (_numInactiveUpdates > 0 && _entity->getScriptSimulationPriority() == 0) {
// the entity is stopped and inactive so we tell the server we're clearing simulatorID
// but we remember we do still own it... and rely on the server to tell us we don't
properties.clearSimulationOwner();
_bidPriority = 0;
_entity->setPendingOwnershipPriority(_bidPriority, now);
} else if (_bidPriority != _entity->getSimulationPriority()) {
// our desired priority has changed
if (_bidPriority == 0) {
// we should release ownership
properties.clearSimulationOwner();
} else {
// we just need to change the priority
properties.setSimulationOwner(Physics::getSessionUUID(), _bidPriority);
_entity->setPendingOwnershipPriority(0);
} else {
uint8_t finalBidPriority = computeFinalBidPriority();
_entity->clearScriptSimulationPriority();
if (finalBidPriority != _entity->getSimulationPriority() &&
!(finalBidPriority == VOLUNTEER_SIMULATION_PRIORITY && _entity->getSimulationPriority() == RECRUIT_SIMULATION_PRIORITY)) {
// our desired priority has changed
if (finalBidPriority == 0) {
// we should release ownership
properties.clearSimulationOwner();
} else {
// we just need to change the priority
properties.setSimulationOwner(Physics::getSessionUUID(), finalBidPriority);
}
_entity->setPendingOwnershipPriority(finalBidPriority);
}
_entity->setPendingOwnershipPriority(_bidPriority, now);
}
EntityItemID id(_entity->getID());
@ -648,6 +637,11 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
});
_lastStep = step;
// after sending a bid/update we clear _bumpedPriority
// which might get promoted again next frame (after local script or simulation interaction)
// or we might win the bid
_bumpedPriority = 0;
}
uint32_t EntityMotionState::getIncomingDirtyFlags() {
@ -694,7 +688,7 @@ uint8_t EntityMotionState::getSimulationPriority() const {
}
void EntityMotionState::slaveBidPriority() {
computeNewBidPriority(_entity->getSimulationPriority());
_bumpedPriority = glm::max(_bumpedPriority, _entity->getSimulationPriority());
}
// virtual
@ -705,7 +699,7 @@ QUuid EntityMotionState::getSimulatorID() const {
void EntityMotionState::bump(uint8_t priority) {
assert(priority != 0);
computeNewBidPriority(glm::max(VOLUNTEER_SIMULATION_PRIORITY, --priority));
_bumpedPriority = glm::max(_bumpedPriority, --priority);
}
void EntityMotionState::resetMeasuredBodyAcceleration() {
@ -771,7 +765,6 @@ void EntityMotionState::setMotionType(PhysicsMotionType motionType) {
resetMeasuredBodyAcceleration();
}
// virtual
QString EntityMotionState::getName() const {
assert(entityTreeIsLocked());
@ -784,15 +777,14 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma
}
bool EntityMotionState::shouldSendBid() {
// NOTE: this method is only ever called when the entity simulation is NOT locally owned
if (_bidPriority > glm::max(_entity->getSimulationPriority(), YIELD_SIMULATION_PRIORITY)) {
return true;
} else {
// NOTE: this 'else' case has a side-effect: it clears _bidPriority
// which might get promoted again next frame (after local script or simulation interaction)
_bidPriority = 0;
return false;
}
// NOTE: this method is only ever called when the entity's simulation is NOT locally owned
return _body->isActive() && (_region == workload::Region::R1) &&
glm::max(glm::max(VOLUNTEER_SIMULATION_PRIORITY, _bumpedPriority), _entity->getScriptSimulationPriority()) >= _entity->getSimulationPriority();
}
uint8_t EntityMotionState::computeFinalBidPriority() const {
return (_region == workload::Region::R1) ?
glm::max(glm::max(VOLUNTEER_SIMULATION_PRIORITY, _bumpedPriority), _entity->getScriptSimulationPriority()) : 0;
}
bool EntityMotionState::isLocallyOwned() const {
@ -802,15 +794,15 @@ bool EntityMotionState::isLocallyOwned() const {
bool EntityMotionState::isLocallyOwnedOrShouldBe() const {
// this method could also be called "shouldGenerateCollisionEventForLocalScripts()"
// because that is the only reason it's used
return (_bidPriority > VOLUNTEER_SIMULATION_PRIORITY && _bidPriority >= _entity->getSimulationPriority()) ||
_entity->getSimulatorID() == Physics::getSessionUUID();
if (_entity->getSimulatorID() == Physics::getSessionUUID()) {
return true;
} else {
return computeFinalBidPriority() > glm::max(VOLUNTEER_SIMULATION_PRIORITY, _entity->getSimulationPriority());
}
}
void EntityMotionState::setRegion(uint8_t region) {
_region = region;
if (_region == workload::Region::R1 && _bidPriority < VOLUNTEER_SIMULATION_PRIORITY && !isLocallyOwned()) {
_bidPriority = VOLUNTEER_SIMULATION_PRIORITY;
}
}
void EntityMotionState::initForBid() {
@ -823,14 +815,6 @@ void EntityMotionState::initForOwned() {
_ownershipState = EntityMotionState::OwnershipState::LocallyOwned;
}
void EntityMotionState::computeNewBidPriority(uint8_t newPriority) {
if (_region == workload::Region::R1) {
_bidPriority = glm::max<uint8_t>(VOLUNTEER_SIMULATION_PRIORITY, glm::max<uint8_t>(_bidPriority, newPriority));
} else {
_bidPriority = glm::min<uint8_t>(YIELD_SIMULATION_PRIORITY, newPriority);
}
}
void EntityMotionState::clearObjectVelocities() const {
// If transform or velocities are flagged as dirty it means a network or scripted change
// occured between the beginning and end of the stepSimulation() and we DON'T want to apply

View file

@ -88,6 +88,8 @@ public:
virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const override;
bool shouldSendBid();
uint8_t computeFinalBidPriority() const;
bool isLocallyOwned() const override;
bool isLocallyOwnedOrShouldBe() const override; // aka shouldEmitCollisionEvents()
@ -105,9 +107,6 @@ protected:
void updateServerPhysicsVariables();
bool remoteSimulationOutOfSync(uint32_t simulationStep);
// computes _bidPriority using newPriority and special case rules
void computeNewBidPriority(uint8_t newPriority);
void slaveBidPriority(); // computeNewBidPriority() with value stored in _entity
void clearObjectVelocities() const;
@ -156,7 +155,7 @@ protected:
uint8_t _loopsWithoutOwner;
mutable uint8_t _accelerationNearlyGravityCount;
uint8_t _numInactiveUpdates { 1 };
uint8_t _bidPriority { 0 };
uint8_t _bumpedPriority { 0 }; // the target simulation priority according to collision history
uint8_t _region { workload::Region::INVALID };
};