mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 09:24:00 +02:00
more work on simulator priority
scripts that edit terse update data try to assert priority physics simulation tries to assert "volunteer" priority max priority rules are applied in entity server
This commit is contained in:
parent
82ba5cd4b6
commit
d0ac3e4514
10 changed files with 104 additions and 46 deletions
|
@ -27,7 +27,8 @@
|
|||
#include "EntityTree.h"
|
||||
#include "EntitySimulation.h"
|
||||
|
||||
const quint64 SIMULATOR_CHANGE_LOCKOUT_PERIOD = (quint64)(0.2f * USECS_PER_SECOND);
|
||||
const quint64 DEFAULT_SIMULATOR_CHANGE_LOCKOUT_PERIOD = (quint64)(0.2f * USECS_PER_SECOND);
|
||||
const quint64 MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD = 2 * USECS_PER_SECOND;
|
||||
|
||||
bool EntityItem::_sendPhysicsUpdates = true;
|
||||
|
||||
|
@ -322,6 +323,7 @@ int EntityItem::expectedBytes() {
|
|||
}
|
||||
|
||||
|
||||
// clients use this method to unpack FULL updates from entity-server
|
||||
int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
|
||||
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {
|
||||
|
@ -596,24 +598,22 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
// ownership has changed
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
if (_simulatorID == nodeList->getSessionUUID()) {
|
||||
// we think we're the owner but entityServer says otherwise
|
||||
// we relenquish ownership if the incoming priority is greater than or equal to ours
|
||||
// we think we're the simulation owner but entity-server says otherwise
|
||||
// we relenquish ownership iff 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;
|
||||
_simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD;
|
||||
}
|
||||
} else {
|
||||
_simulatorID = id;
|
||||
_simulatorPriority = priority;
|
||||
_simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD;
|
||||
}
|
||||
} else if (priority != _simulatorPriority) {
|
||||
// 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
|
||||
// we would have initiated this priority
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
if (_simulatorID != nodeList->getSessionUUID()) {
|
||||
_simulatorPriority = priority;
|
||||
|
@ -1395,21 +1395,51 @@ void EntityItem::updateCreated(uint64_t value) {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityItem::setSimulatorPriority(uint8_t priority) {
|
||||
_simulatorPriority = priority;
|
||||
if (_simulatorPriority == MAX_SIMULATOR_PRIORITY) {
|
||||
// we always extend the the ownership expiry for MAX_SIMULATOR_PRIORITY
|
||||
_simulationOwnershipExpiry = usecTimestampNow() + MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD;
|
||||
} else if (_simulatorPriority == 0) {
|
||||
_simulationOwnershipExpiry = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::setSimulatorID(const QUuid& value) {
|
||||
if (_simulatorID != value) {
|
||||
_simulatorID = value;
|
||||
_simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD;
|
||||
if (!_simulatorID.isNull()) {
|
||||
// Note: this logic only works well if _simulatorPriority is properly set before this point
|
||||
quint64 lockoutPeriod = (_simulatorPriority == MAX_SIMULATOR_PRIORITY)
|
||||
? MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD : DEFAULT_SIMULATOR_CHANGE_LOCKOUT_PERIOD;
|
||||
_simulationOwnershipExpiry = usecTimestampNow() + lockoutPeriod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::updateSimulatorID(const QUuid& value) {
|
||||
if (_simulatorID != value) {
|
||||
_simulatorID = value;
|
||||
_simulationOwnershipExpiry = usecTimestampNow() + SIMULATOR_CHANGE_LOCKOUT_PERIOD;
|
||||
if (!_simulatorID.isNull()) {
|
||||
// Note: this logic only works well if _simulatorPriority is properly set before this point
|
||||
quint64 lockoutPeriod = (_simulatorPriority == MAX_SIMULATOR_PRIORITY)
|
||||
? MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD : DEFAULT_SIMULATOR_CHANGE_LOCKOUT_PERIOD;
|
||||
_simulationOwnershipExpiry = usecTimestampNow() + lockoutPeriod;
|
||||
}
|
||||
_dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::clearSimulationOwnership() {
|
||||
_simulatorPriority = 0;
|
||||
_simulatorID = QUuid();
|
||||
_simulationOwnershipExpiry = 0;
|
||||
// don't bother setting the DIRTY_SIMULATOR_ID flag because clearSimulatorOwnership()
|
||||
// is only ever called entity-server-side and the flags are only used client-side
|
||||
//_dirtyFlags |= EntityItem::DIRTY_SIMULATOR_ID;
|
||||
|
||||
}
|
||||
|
||||
bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer action) {
|
||||
assert(action);
|
||||
const QUuid& actionID = action->getID();
|
||||
|
|
|
@ -60,8 +60,10 @@ const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f;
|
|||
const float ACTIVATION_GRAVITY_DELTA = 0.1f;
|
||||
const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f;
|
||||
|
||||
const uint8_t MIN_SIMULATOR_PRIORITY = 1;
|
||||
const uint8_t VOLUNTEER_SIMULATOR_PRIORITY = 0x01;
|
||||
const uint8_t SCRIPT_EDIT_SIMULATOR_PRIORITY = 0x80;
|
||||
const uint8_t MAX_SIMULATOR_PRIORITY = 0xff;
|
||||
const uint8_t ATTACHMENT_SIMULATOR_PRIORITY = MAX_SIMULATOR_PRIORITY;
|
||||
|
||||
#define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
|
||||
#define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { };
|
||||
|
@ -320,13 +322,14 @@ public:
|
|||
const QString& getUserData() const { return _userData; }
|
||||
void setUserData(const QString& value) { _userData = value; }
|
||||
|
||||
void setSimulatorPriority(uint8_t priority) { _simulatorPriority = priority; }
|
||||
void setSimulatorPriority(uint8_t priority);
|
||||
uint8_t getSimulatorPriority() const { return _simulatorPriority; }
|
||||
|
||||
QUuid getSimulatorID() const { return _simulatorID; }
|
||||
void setSimulatorID(const QUuid& value);
|
||||
void updateSimulatorID(const QUuid& value);
|
||||
const quint64& getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; }
|
||||
void clearSimulationOwnership();
|
||||
|
||||
const QString& getMarketplaceID() const { return _marketplaceID; }
|
||||
void setMarketplaceID(const QString& value) { _marketplaceID = value; }
|
||||
|
|
|
@ -1234,3 +1234,17 @@ bool EntityItemProperties::hasTerseUpdateChanges() const {
|
|||
// a TerseUpdate includes the transform and its derivatives
|
||||
return _positionChanged || _velocityChanged || _rotationChanged || _angularVelocityChanged || _accelerationChanged;
|
||||
}
|
||||
|
||||
void EntityItemProperties::clearSimulatorOwnership() {
|
||||
_simulatorID = QUuid();
|
||||
_simulatorPriority = 0;
|
||||
_simulatorIDChanged = true;
|
||||
_simulatorPriorityChanged = true;
|
||||
}
|
||||
|
||||
void EntityItemProperties::setSimulatorOwnership(const QUuid& id, uint8_t priority) {
|
||||
_simulatorID = id;
|
||||
_simulatorPriority = glm::max(priority, _simulatorPriority);
|
||||
_simulatorIDChanged = true;
|
||||
_simulatorPriorityChanged = true;
|
||||
}
|
||||
|
|
|
@ -207,6 +207,9 @@ public:
|
|||
|
||||
bool hasTerseUpdateChanges() const;
|
||||
|
||||
void clearSimulatorOwnership();
|
||||
void setSimulatorOwnership(const QUuid& id, uint8_t priority);
|
||||
|
||||
private:
|
||||
QUuid _id;
|
||||
bool _idSet;
|
||||
|
|
|
@ -61,16 +61,6 @@ void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) {
|
|||
}
|
||||
}
|
||||
|
||||
void bidForSimulationOwnership(EntityItemProperties& properties) {
|
||||
// We make a bid for simulation ownership by declaring our sessionID as simulation owner
|
||||
// in the outgoing properties. The EntityServer may accept the bid or might not.
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
const QUuid myNodeID = nodeList->getSessionUUID();
|
||||
properties.setSimulatorID(myNodeID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties) {
|
||||
|
||||
EntityItemProperties propertiesWithSimID = properties;
|
||||
|
@ -83,11 +73,15 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
|
|||
_entityTree->lockForWrite();
|
||||
EntityItemPointer entity = _entityTree->addEntity(id, propertiesWithSimID);
|
||||
if (entity) {
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
// This Node is creating a new object. If it's in motion, set this Node as the simulator.
|
||||
bidForSimulationOwnership(propertiesWithSimID);
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
const QUuid myNodeID = nodeList->getSessionUUID();
|
||||
propertiesWithSimID.setSimulatorOwnership(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY);
|
||||
|
||||
// and make note of it now, so we can act on it right away.
|
||||
entity->setSimulatorID(propertiesWithSimID.getSimulatorID());
|
||||
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
} else {
|
||||
qCDebug(entities) << "script failed to add new Entity to local Octree";
|
||||
success = false;
|
||||
|
@ -160,9 +154,14 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties proper
|
|||
// balls" test. However, even if we solve this problem we still need to provide a "slerp the visible
|
||||
// proxy toward the true physical position" feature to hide the final glitches in the remote watcher's
|
||||
// simulation.
|
||||
|
||||
// we re-assert our simulation ownership
|
||||
properties.setSimulatorOwnership(myNodeID,
|
||||
glm::max(entity->getSimulatorPriority(), SCRIPT_EDIT_SIMULATOR_PRIORITY));
|
||||
} else {
|
||||
// we make a bid for simulation ownership
|
||||
properties.setSimulatorOwnership(myNodeID, SCRIPT_EDIT_SIMULATOR_PRIORITY);
|
||||
}
|
||||
// we make a bid for (or assert existing) simulation ownership
|
||||
properties.setSimulatorID(myNodeID);
|
||||
}
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
}
|
||||
|
|
|
@ -169,15 +169,12 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
|
|||
// 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;
|
||||
}
|
||||
uint8_t newPriority = properties.getSimulatorPriority();
|
||||
if (newPriority > oldPriority ||
|
||||
(newPriority == oldPriority &&
|
||||
usecTimestampNow() > entity->getSimulationOwnershipExpiry())) {
|
||||
simulationBlocked = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -23,18 +23,18 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) {
|
|||
// has finished simulating it.
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
SetOfEntities::iterator itemItr = _hasSimulationOwnerEntities.begin();
|
||||
while (itemItr != _hasSimulationOwnerEntities.end()) {
|
||||
SetOfEntities::iterator itemItr = _entitiesWithSimulator.begin();
|
||||
while (itemItr != _entitiesWithSimulator.end()) {
|
||||
EntityItemPointer entity = *itemItr;
|
||||
if (entity->getSimulatorID().isNull()) {
|
||||
itemItr = _hasSimulationOwnerEntities.erase(itemItr);
|
||||
itemItr = _entitiesWithSimulator.erase(itemItr);
|
||||
} else if (now - entity->getLastChangedOnServer() >= AUTO_REMOVE_SIMULATION_OWNER_USEC) {
|
||||
SharedNodePointer ownerNode = nodeList->nodeWithUUID(entity->getSimulatorID());
|
||||
if (ownerNode.isNull() || !ownerNode->isAlive()) {
|
||||
qCDebug(entities) << "auto-removing simulation owner" << entity->getSimulatorID();
|
||||
// TODO: zero velocities when we clear simulatorID?
|
||||
entity->setSimulatorID(QUuid());
|
||||
itemItr = _hasSimulationOwnerEntities.erase(itemItr);
|
||||
entity->clearSimulationOwnership();
|
||||
itemItr = _entitiesWithSimulator.erase(itemItr);
|
||||
} else {
|
||||
++itemItr;
|
||||
}
|
||||
|
@ -47,23 +47,23 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) {
|
|||
void SimpleEntitySimulation::addEntityInternal(EntityItemPointer entity) {
|
||||
EntitySimulation::addEntityInternal(entity);
|
||||
if (!entity->getSimulatorID().isNull()) {
|
||||
_hasSimulationOwnerEntities.insert(entity);
|
||||
_entitiesWithSimulator.insert(entity);
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleEntitySimulation::removeEntityInternal(EntityItemPointer entity) {
|
||||
_hasSimulationOwnerEntities.remove(entity);
|
||||
_entitiesWithSimulator.remove(entity);
|
||||
}
|
||||
|
||||
void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
|
||||
EntitySimulation::changeEntityInternal(entity);
|
||||
if (!entity->getSimulatorID().isNull()) {
|
||||
_hasSimulationOwnerEntities.insert(entity);
|
||||
_entitiesWithSimulator.insert(entity);
|
||||
}
|
||||
entity->clearDirtyFlags();
|
||||
}
|
||||
|
||||
void SimpleEntitySimulation::clearEntitiesInternal() {
|
||||
_hasSimulationOwnerEntities.clear();
|
||||
_entitiesWithSimulator.clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ protected:
|
|||
virtual void changeEntityInternal(EntityItemPointer entity);
|
||||
virtual void clearEntitiesInternal();
|
||||
|
||||
SetOfEntities _hasSimulationOwnerEntities;
|
||||
SetOfEntities _entitiesWithSimulator;
|
||||
};
|
||||
|
||||
#endif // hifi_SimpleEntitySimulation_h
|
||||
|
|
|
@ -97,7 +97,9 @@ void EntityMotionState::handleEasyChanges(uint32_t flags) {
|
|||
assert(entityTreeIsLocked());
|
||||
updateServerPhysicsVariables();
|
||||
ObjectMotionState::handleEasyChanges(flags);
|
||||
|
||||
if (flags & EntityItem::DIRTY_SIMULATOR_ID) {
|
||||
_loopsSinceOwnershipBid = 0;
|
||||
_loopsWithoutOwner = 0;
|
||||
_candidateForOwnership = 0;
|
||||
if (_entity->getSimulatorID().isNull()
|
||||
|
@ -453,14 +455,15 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
|
|||
if (!active) {
|
||||
// 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.setSimulatorID(QUuid());
|
||||
properties.clearSimulatorOwnership();
|
||||
} else {
|
||||
// explicitly set the property's simulatorID so that it is flagged as changed and will be packed
|
||||
properties.setSimulatorID(sessionID);
|
||||
// re-assert the simulation info
|
||||
properties.setSimulatorOwnership(sessionID, _entity->getSimulatorPriority());
|
||||
}
|
||||
} else {
|
||||
// we don't own the simulation for this entity yet, but we're sending a bid for it
|
||||
properties.setSimulatorID(sessionID);
|
||||
properties.setSimulatorOwnership(sessionID, glm::max(_simulatorPriorityHint, VOLUNTEER_SIMULATOR_PRIORITY));
|
||||
_simulatorPriorityHint = 0;
|
||||
}
|
||||
|
||||
if (EntityItem::getSendPhysicsUpdates()) {
|
||||
|
@ -580,3 +583,8 @@ int16_t EntityMotionState::computeCollisionGroup() {
|
|||
}
|
||||
return COLLISION_GROUP_DEFAULT;
|
||||
}
|
||||
|
||||
void EntityMotionState::setSimulatorPriorityHint(uint8_t priority) {
|
||||
_candidateForOwnership = true;
|
||||
_simulatorPriorityHint = priority;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,9 @@ public:
|
|||
|
||||
virtual int16_t computeCollisionGroup();
|
||||
|
||||
// eternal logic can suggest a simuator priority bid for the next outgoing update
|
||||
void setSimulatorPriorityHint(uint8_t priority);
|
||||
|
||||
friend class PhysicalEntitySimulation;
|
||||
|
||||
protected:
|
||||
|
@ -114,6 +117,7 @@ protected:
|
|||
bool _candidateForOwnership;
|
||||
uint32_t _loopsSinceOwnershipBid;
|
||||
uint32_t _loopsWithoutOwner;
|
||||
uint8_t _simulatorPriorityHint;
|
||||
};
|
||||
|
||||
#endif // hifi_EntityMotionState_h
|
||||
|
|
Loading…
Reference in a new issue