mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-10 19:18:44 +02:00
don't edit restricted properties unless sim ownership possible
This commit is contained in:
parent
bb51079284
commit
ce81ab1f9d
3 changed files with 128 additions and 74 deletions
|
@ -3258,6 +3258,56 @@ bool EntityItemProperties::hasMiscPhysicsChanges() const {
|
||||||
_compoundShapeURLChanged || _dynamicChanged || _collisionlessChanged || _collisionMaskChanged;
|
_compoundShapeURLChanged || _dynamicChanged || _collisionlessChanged || _collisionMaskChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EntityItemProperties::hasSimulationRestrictedChanges() const {
|
||||||
|
return _positionChanged || _localPositionChanged
|
||||||
|
|| _rotationChanged || _localRotationChanged
|
||||||
|
|| _velocityChanged || _localVelocityChanged
|
||||||
|
|| _angularVelocityChanged || _localAngularVelocityChanged
|
||||||
|
|| _accelerationChanged
|
||||||
|
|| _parentIDChanged || _parentJointIndexChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityItemProperties::copySimulationRestrictedProperties(const EntityItemPointer& entity) {
|
||||||
|
if (!_parentIDChanged) {
|
||||||
|
setParentID(entity->getParentID());
|
||||||
|
}
|
||||||
|
if (!_parentJointIndexChanged) {
|
||||||
|
setParentJointIndex(entity->getParentJointIndex());
|
||||||
|
}
|
||||||
|
if (!_localPositionChanged && !_positionChanged) {
|
||||||
|
setPosition(entity->getWorldPosition());
|
||||||
|
}
|
||||||
|
if (!_localRotationChanged && !_rotationChanged) {
|
||||||
|
setRotation(entity->getWorldOrientation());
|
||||||
|
}
|
||||||
|
if (!_localVelocityChanged && !_velocityChanged) {
|
||||||
|
setVelocity(entity->getWorldVelocity());
|
||||||
|
}
|
||||||
|
if (!_localAngularVelocityChanged && !_angularVelocityChanged) {
|
||||||
|
setAngularVelocity(entity->getWorldAngularVelocity());
|
||||||
|
}
|
||||||
|
if (!_accelerationChanged) {
|
||||||
|
setAcceleration(entity->getAcceleration());
|
||||||
|
}
|
||||||
|
if (!_localDimensionsChanged && !_dimensionsChanged) {
|
||||||
|
setDimensions(entity->getScaledDimensions());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityItemProperties::clearSimulationRestrictedProperties() {
|
||||||
|
_positionChanged = false;
|
||||||
|
_localPositionChanged = false;
|
||||||
|
_rotationChanged = false;
|
||||||
|
_localRotationChanged = false;
|
||||||
|
_velocityChanged = false;
|
||||||
|
_localVelocityChanged = false;
|
||||||
|
_angularVelocityChanged = false;
|
||||||
|
_localAngularVelocityChanged = false;
|
||||||
|
_accelerationChanged = false;
|
||||||
|
_parentIDChanged = false;
|
||||||
|
_parentJointIndexChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
void EntityItemProperties::clearSimulationOwner() {
|
void EntityItemProperties::clearSimulationOwner() {
|
||||||
_simulationOwner.clear();
|
_simulationOwner.clear();
|
||||||
_simulationOwnerChanged = true;
|
_simulationOwnerChanged = true;
|
||||||
|
|
|
@ -352,6 +352,10 @@ public:
|
||||||
bool hasTransformOrVelocityChanges() const;
|
bool hasTransformOrVelocityChanges() const;
|
||||||
bool hasMiscPhysicsChanges() const;
|
bool hasMiscPhysicsChanges() const;
|
||||||
|
|
||||||
|
bool hasSimulationRestrictedChanges() const;
|
||||||
|
void copySimulationRestrictedProperties(const EntityItemPointer& entity);
|
||||||
|
void clearSimulationRestrictedProperties();
|
||||||
|
|
||||||
void clearSimulationOwner();
|
void clearSimulationOwner();
|
||||||
void setSimulationOwner(const QUuid& id, uint8_t priority);
|
void setSimulationOwner(const QUuid& id, uint8_t priority);
|
||||||
void setSimulationOwner(const QByteArray& data);
|
void setSimulationOwner(const QByteArray& data);
|
||||||
|
|
|
@ -174,6 +174,7 @@ EntityItemProperties convertPropertiesToScriptSemantics(const EntityItemProperti
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: this method looks expensive and should take properties by reference, update it, and return void
|
||||||
EntityItemProperties convertPropertiesFromScriptSemantics(const EntityItemProperties& scriptSideProperties,
|
EntityItemProperties convertPropertiesFromScriptSemantics(const EntityItemProperties& scriptSideProperties,
|
||||||
bool scalesWithParent) {
|
bool scalesWithParent) {
|
||||||
// convert position and rotation properties from world-space to local, unless localPosition and localRotation
|
// convert position and rotation properties from world-space to local, unless localPosition and localRotation
|
||||||
|
@ -532,54 +533,80 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
||||||
const auto sessionID = DependencyManager::get<NodeList>()->getSessionUUID();
|
const auto sessionID = DependencyManager::get<NodeList>()->getSessionUUID();
|
||||||
|
|
||||||
EntityItemProperties properties = scriptSideProperties;
|
EntityItemProperties properties = scriptSideProperties;
|
||||||
properties.setLastEditedBy(sessionID);
|
|
||||||
|
|
||||||
EntityItemID entityID(id);
|
EntityItemID entityID(id);
|
||||||
if (!_entityTree) {
|
if (!_entityTree) {
|
||||||
|
properties.setLastEditedBy(sessionID);
|
||||||
queueEntityMessage(PacketType::EntityEdit, entityID, properties);
|
queueEntityMessage(PacketType::EntityEdit, entityID, properties);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
// If we have a local entity tree set, then also update it.
|
|
||||||
|
|
||||||
|
EntityItemPointer entity(nullptr);
|
||||||
|
SimulationOwner simulationOwner;
|
||||||
_entityTree->withReadLock([&] {
|
_entityTree->withReadLock([&] {
|
||||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
|
// make a copy of entity for local logic outside of tree lock
|
||||||
|
entity = _entityTree->findEntityByEntityItemID(entityID);
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity->getClientOnly() && entity->getOwningAvatarID() != sessionID) {
|
if (entity->getClientOnly() && entity->getOwningAvatarID() != sessionID) {
|
||||||
// don't edit other avatar's avatarEntities
|
// don't edit other avatar's avatarEntities
|
||||||
|
properties = EntityItemProperties();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// make a copy of simulationOwner for local logic outside of tree lock
|
||||||
|
simulationOwner = entity->getSimulationOwner();
|
||||||
|
});
|
||||||
|
|
||||||
if (scriptSideProperties.parentRelatedPropertyChanged()) {
|
if (entity) {
|
||||||
// All of parentID, parentJointIndex, position, rotation are needed to make sense of any of them.
|
if (properties.hasSimulationRestrictedChanges()) {
|
||||||
// If any of these changed, pull any missing properties from the entity.
|
if (_bidOnSimulationOwnership) {
|
||||||
|
if (simulationOwner.getID() == sessionID) {
|
||||||
if (!scriptSideProperties.parentIDChanged()) {
|
// we own the simulation --> copy ALL restricted properties
|
||||||
properties.setParentID(entity->getParentID());
|
properties.copySimulationRestrictedProperties(entity);
|
||||||
}
|
//if (ourBidPriority != currentBidPriority) {
|
||||||
if (!scriptSideProperties.parentJointIndexChanged()) {
|
// TODO: figure out how to change simulation ownership priority
|
||||||
properties.setParentJointIndex(entity->getParentJointIndex());
|
//}
|
||||||
}
|
} else {
|
||||||
if (!scriptSideProperties.localPositionChanged() && !scriptSideProperties.positionChanged()) {
|
// we don't own the simulation
|
||||||
properties.setPosition(entity->getWorldPosition());
|
uint8_t desiredPriority = entity->getScriptSimulationPriority();
|
||||||
}
|
if (desiredPriority < simulationOwner.getPriority()) {
|
||||||
if (!scriptSideProperties.localRotationChanged() && !scriptSideProperties.rotationChanged()) {
|
// we don't desire to own it --> clear restricted properties
|
||||||
properties.setRotation(entity->getWorldOrientation());
|
properties.clearSimulationRestrictedProperties();
|
||||||
}
|
} else {
|
||||||
if (!scriptSideProperties.localDimensionsChanged() && !scriptSideProperties.dimensionsChanged()) {
|
// we want to own it --> copy ALL restricted properties
|
||||||
properties.setDimensions(entity->getScaledDimensions());
|
properties.copySimulationRestrictedProperties(entity);
|
||||||
|
// and also store our simulation
|
||||||
|
properties.setSimulationOwner(sessionID, desiredPriority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!simulationOwner.getID().isNull()) {
|
||||||
|
// someone owns this but not us
|
||||||
|
// clear restricted properties
|
||||||
|
properties.clearSimulationRestrictedProperties();
|
||||||
}
|
}
|
||||||
|
// clear the cached simulationPriority level
|
||||||
|
entity->setScriptSimulationPriority(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set these to make EntityItemProperties::getScalesWithParent() work correctly
|
||||||
properties.setClientOnly(entity->getClientOnly());
|
properties.setClientOnly(entity->getClientOnly());
|
||||||
properties.setOwningAvatarID(entity->getOwningAvatarID());
|
properties.setOwningAvatarID(entity->getOwningAvatarID());
|
||||||
});
|
|
||||||
|
// make sure the properties has a type, so that the encode can know which properties to include
|
||||||
|
properties.setType(entity->getType());
|
||||||
|
} else if (_bidOnSimulationOwnership) {
|
||||||
|
// bail when simulation participants don't know about entity
|
||||||
|
return QUuid();
|
||||||
|
}
|
||||||
|
// TODO: it is possible there is no remaining useful changes in properties and we should bail early.
|
||||||
|
// How to check for this cheaply?
|
||||||
|
|
||||||
properties = convertPropertiesFromScriptSemantics(properties, properties.getScalesWithParent());
|
properties = convertPropertiesFromScriptSemantics(properties, properties.getScalesWithParent());
|
||||||
|
properties.setLastEditedBy(sessionID);
|
||||||
|
|
||||||
// TODO: avoid setting properties not allowed to be changed according to simulation ownership rules
|
// done reading and modifying properties --> start write
|
||||||
|
|
||||||
// done reading, start write
|
|
||||||
bool updatedEntity = false;
|
bool updatedEntity = false;
|
||||||
_entityTree->withWriteLock([&] {
|
_entityTree->withWriteLock([&] {
|
||||||
updatedEntity = _entityTree->updateEntity(entityID, properties);
|
updatedEntity = _entityTree->updateEntity(entityID, properties);
|
||||||
|
@ -594,64 +621,37 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
||||||
// return QUuid();
|
// return QUuid();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
bool hasQueryAACubeRelatedChanges = properties.queryAACubeRelatedPropertyChanged();
|
||||||
// done writing, send update
|
// done writing, send update
|
||||||
bool entityFound { false };
|
|
||||||
_entityTree->withReadLock([&] {
|
_entityTree->withReadLock([&] {
|
||||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
|
// find the entity again: maybe it was removed since we last found it
|
||||||
|
entity = _entityTree->findEntityByEntityItemID(entityID);
|
||||||
if (entity) {
|
if (entity) {
|
||||||
entityFound = true;
|
uint64_t now = usecTimestampNow();
|
||||||
// make sure the properties has a type, so that the encode can know which properties to include
|
entity->setLastBroadcast(now);
|
||||||
properties.setType(entity->getType());
|
|
||||||
bool hasTransformOrVelocityChanges = properties.hasTransformOrVelocityChanges();
|
|
||||||
bool hasPhysicsChanges = properties.hasMiscPhysicsChanges() || hasTransformOrVelocityChanges;
|
|
||||||
if (_bidOnSimulationOwnership && hasPhysicsChanges) {
|
|
||||||
if (entity->getSimulatorID() == sessionID) {
|
|
||||||
// we think we already own the simulation, so make sure to send the full transform and all velocities
|
|
||||||
if (hasTransformOrVelocityChanges) {
|
|
||||||
entity->getTransformAndVelocityProperties(properties);
|
|
||||||
}
|
|
||||||
// TODO: if we knew that ONLY transforms and velocities have changed in properties AND the object
|
|
||||||
// is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update
|
|
||||||
// and instead let the physics simulation decide when to send the update. This would remove
|
|
||||||
// the "slide-no-rotate" glitch (and typical double-update) that we see during the "poke rolling
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
if (entity->getSimulationPriority() < SCRIPT_POKE_SIMULATION_PRIORITY) {
|
if (hasQueryAACubeRelatedChanges) {
|
||||||
// we re-assert our simulation ownership at a higher priority
|
|
||||||
properties.setSimulationOwner(sessionID, SCRIPT_POKE_SIMULATION_PRIORITY);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we make a bid for simulation ownership
|
|
||||||
properties.setSimulationOwner(sessionID, SCRIPT_POKE_SIMULATION_PRIORITY);
|
|
||||||
entity->setScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (properties.queryAACubeRelatedPropertyChanged()) {
|
|
||||||
properties.setQueryAACube(entity->getQueryAACube());
|
properties.setQueryAACube(entity->getQueryAACube());
|
||||||
}
|
|
||||||
entity->setLastBroadcast(usecTimestampNow());
|
|
||||||
properties.setLastEdited(entity->getLastEdited());
|
|
||||||
|
|
||||||
// if we've moved an entity with children, check/update the queryAACube of all descendents and tell the server
|
// if we've moved an entity with children, check/update the queryAACube of all descendents and tell the server
|
||||||
// if they've changed.
|
// if they've changed.
|
||||||
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||||
if (descendant->getNestableType() == NestableType::Entity) {
|
if (descendant->getNestableType() == NestableType::Entity) {
|
||||||
if (descendant->updateQueryAACube()) {
|
if (descendant->updateQueryAACube()) {
|
||||||
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
|
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
|
||||||
EntityItemProperties newQueryCubeProperties;
|
EntityItemProperties newQueryCubeProperties;
|
||||||
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
|
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
|
||||||
newQueryCubeProperties.setLastEdited(properties.getLastEdited());
|
newQueryCubeProperties.setLastEdited(properties.getLastEdited());
|
||||||
queueEntityMessage(PacketType::EntityEdit, descendant->getID(), newQueryCubeProperties);
|
queueEntityMessage(PacketType::EntityEdit, descendant->getID(), newQueryCubeProperties);
|
||||||
entityDescendant->setLastBroadcast(usecTimestampNow());
|
entityDescendant->setLastBroadcast(now);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!entityFound) {
|
if (!entity) {
|
||||||
{
|
if (hasQueryAACubeRelatedChanges) {
|
||||||
// Sometimes ESS don't have the entity they are trying to edit in their local tree. In this case,
|
// Sometimes ESS don't have the entity they are trying to edit in their local tree. In this case,
|
||||||
// convertPropertiesFromScriptSemantics doesn't get called and local* edits will get dropped.
|
// convertPropertiesFromScriptSemantics doesn't get called and local* edits will get dropped.
|
||||||
// This is because, on the script side, "position" is in world frame, but in the network
|
// This is because, on the script side, "position" is in world frame, but in the network
|
||||||
|
|
Loading…
Reference in a new issue