mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 02:33:09 +02:00
Merge pull request #14140 from AndrewMeadows/dps-setPos-vs-grab
Make EntityScriptingInterface aware of distributed physics simulation (DPS) rules
This commit is contained in:
commit
81fbb5a332
7 changed files with 207 additions and 120 deletions
|
@ -78,8 +78,10 @@ void addAvatarEntities(const QVariantList& avatarEntities) {
|
||||||
}
|
}
|
||||||
|
|
||||||
entity->setLastBroadcast(usecTimestampNow());
|
entity->setLastBroadcast(usecTimestampNow());
|
||||||
// since we're creating this object we will immediately volunteer to own its simulation
|
if (entityProperties.getDynamic()) {
|
||||||
entity->setScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
|
// since we're creating a dynamic object we volunteer immediately to own its simulation
|
||||||
|
entity->upgradeScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
|
||||||
|
}
|
||||||
entityProperties.setLastEdited(entity->getLastEdited());
|
entityProperties.setLastEdited(entity->getLastEdited());
|
||||||
} else {
|
} else {
|
||||||
qCDebug(entities) << "AvatarEntitiesBookmark failed to add new Entity to local Octree";
|
qCDebug(entities) << "AvatarEntitiesBookmark failed to add new Entity to local Octree";
|
||||||
|
|
|
@ -673,7 +673,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
const QUuid& myNodeID = nodeList->getSessionUUID();
|
const QUuid& myNodeID = nodeList->getSessionUUID();
|
||||||
bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
|
bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
|
||||||
|
|
||||||
// pack SimulationOwner and terse update properties near each other
|
// pack SimulationOwner, transform, and velocity properties near each other
|
||||||
// NOTE: the server is authoritative for changes to simOwnerID so we always unpack ownership data
|
// NOTE: the server is authoritative for changes to simOwnerID so we always unpack ownership data
|
||||||
// even when we would otherwise ignore the rest of the packet.
|
// even when we would otherwise ignore the rest of the packet.
|
||||||
|
|
||||||
|
@ -1358,8 +1358,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) const {
|
void EntityItem::getTransformAndVelocityProperties(EntityItemProperties& properties) const {
|
||||||
// a TerseUpdate includes the transform and its derivatives
|
|
||||||
if (!properties._positionChanged) {
|
if (!properties._positionChanged) {
|
||||||
properties._position = getLocalPosition();
|
properties._position = getLocalPosition();
|
||||||
}
|
}
|
||||||
|
@ -1383,8 +1382,11 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c
|
||||||
properties._accelerationChanged = true;
|
properties._accelerationChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::setScriptSimulationPriority(uint8_t priority) {
|
void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) {
|
||||||
uint8_t newPriority = stillHasGrabActions() ? glm::max(priority, SCRIPT_GRAB_SIMULATION_PRIORITY) : priority;
|
uint8_t newPriority = glm::max(priority, _scriptSimulationPriority);
|
||||||
|
if (newPriority < SCRIPT_GRAB_SIMULATION_PRIORITY && stillHasGrabActions()) {
|
||||||
|
newPriority = SCRIPT_GRAB_SIMULATION_PRIORITY;
|
||||||
|
}
|
||||||
if (newPriority != _scriptSimulationPriority) {
|
if (newPriority != _scriptSimulationPriority) {
|
||||||
// set the dirty flag to trigger a bid or ownership update
|
// set the dirty flag to trigger a bid or ownership update
|
||||||
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY);
|
markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY);
|
||||||
|
@ -1419,7 +1421,7 @@ bool EntityItem::stillWaitingToTakeOwnership(uint64_t timestamp) const {
|
||||||
bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
bool somethingChanged = false;
|
bool somethingChanged = false;
|
||||||
|
|
||||||
// these affect TerseUpdate properties
|
// these affect transform and velocity properties
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPosition);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPosition);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation);
|
||||||
|
@ -3256,3 +3258,26 @@ void EntityItem::setScriptHasFinishedPreload(bool value) {
|
||||||
bool EntityItem::isScriptPreloadFinished() {
|
bool EntityItem::isScriptPreloadFinished() {
|
||||||
return _scriptPreloadFinished;
|
return _scriptPreloadFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityItem::prepareForSimulationOwnershipBid(EntityItemProperties& properties, uint64_t now, uint8_t priority) {
|
||||||
|
if (dynamicDataNeedsTransmit()) {
|
||||||
|
setDynamicDataNeedsTransmit(false);
|
||||||
|
properties.setActionData(getDynamicData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateQueryAACube()) {
|
||||||
|
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
|
||||||
|
properties.setQueryAACube(getQueryAACube());
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the LastEdited of the properties but NOT the entity itself
|
||||||
|
properties.setLastEdited(now);
|
||||||
|
|
||||||
|
clearScriptSimulationPriority();
|
||||||
|
properties.setSimulationOwner(Physics::getSessionUUID(), priority);
|
||||||
|
setPendingOwnershipPriority(priority);
|
||||||
|
|
||||||
|
properties.setClientOnly(getClientOnly());
|
||||||
|
properties.setOwningAvatarID(getOwningAvatarID());
|
||||||
|
setLastBroadcast(now); // for debug/physics status icons
|
||||||
|
}
|
||||||
|
|
|
@ -325,7 +325,7 @@ public:
|
||||||
// TODO: move this "ScriptSimulationPriority" and "PendingOwnership" stuff into EntityMotionState
|
// 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"
|
// 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.
|
// to allow libs that don't know about each other to communicate.
|
||||||
void setScriptSimulationPriority(uint8_t priority);
|
void upgradeScriptSimulationPriority(uint8_t priority);
|
||||||
void clearScriptSimulationPriority();
|
void clearScriptSimulationPriority();
|
||||||
uint8_t getScriptSimulationPriority() const { return _scriptSimulationPriority; }
|
uint8_t getScriptSimulationPriority() const { return _scriptSimulationPriority; }
|
||||||
void setPendingOwnershipPriority(uint8_t priority);
|
void setPendingOwnershipPriority(uint8_t priority);
|
||||||
|
@ -420,7 +420,7 @@ public:
|
||||||
quint64 getLastEditedFromRemote() const { return _lastEditedFromRemote; }
|
quint64 getLastEditedFromRemote() const { return _lastEditedFromRemote; }
|
||||||
void updateLastEditedFromRemote() { _lastEditedFromRemote = usecTimestampNow(); }
|
void updateLastEditedFromRemote() { _lastEditedFromRemote = usecTimestampNow(); }
|
||||||
|
|
||||||
void getAllTerseUpdateProperties(EntityItemProperties& properties) const;
|
void getTransformAndVelocityProperties(EntityItemProperties& properties) const;
|
||||||
|
|
||||||
void flagForMotionStateChange() { _flags |= Simulation::DIRTY_MOTION_TYPE; }
|
void flagForMotionStateChange() { _flags |= Simulation::DIRTY_MOTION_TYPE; }
|
||||||
|
|
||||||
|
@ -535,6 +535,8 @@ public:
|
||||||
|
|
||||||
const GrabPropertyGroup& getGrabProperties() const { return _grabProperties; }
|
const GrabPropertyGroup& getGrabProperties() const { return _grabProperties; }
|
||||||
|
|
||||||
|
void prepareForSimulationOwnershipBid(EntityItemProperties& properties, uint64_t now, uint8_t priority);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void requestRenderUpdate();
|
void requestRenderUpdate();
|
||||||
void spaceUpdate(std::pair<int32_t, glm::vec4> data);
|
void spaceUpdate(std::pair<int32_t, glm::vec4> data);
|
||||||
|
|
|
@ -3244,9 +3244,12 @@ AABox EntityItemProperties::getAABox() const {
|
||||||
return AABox(rotatedExtentsRelativeToRegistrationPoint);
|
return AABox(rotatedExtentsRelativeToRegistrationPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityItemProperties::hasTerseUpdateChanges() const {
|
bool EntityItemProperties::hasTransformOrVelocityChanges() const {
|
||||||
// a TerseUpdate includes the transform and its derivatives
|
return _positionChanged ||_localPositionChanged
|
||||||
return _positionChanged || _velocityChanged || _rotationChanged || _angularVelocityChanged || _accelerationChanged;
|
|| _rotationChanged || _localRotationChanged
|
||||||
|
|| _velocityChanged || _localVelocityChanged
|
||||||
|
|| _angularVelocityChanged || _localAngularVelocityChanged
|
||||||
|
|| _accelerationChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityItemProperties::hasMiscPhysicsChanges() const {
|
bool EntityItemProperties::hasMiscPhysicsChanges() const {
|
||||||
|
@ -3255,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;
|
||||||
|
@ -3273,6 +3326,20 @@ void EntityItemProperties::setSimulationOwner(const QByteArray& data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t EntityItemProperties::computeSimulationBidPriority() const {
|
||||||
|
uint8_t priority = 0;
|
||||||
|
if (_parentIDChanged || _parentJointIndexChanged) {
|
||||||
|
// we need higher simulation ownership priority to chang parenting info
|
||||||
|
priority = SCRIPT_GRAB_SIMULATION_PRIORITY;
|
||||||
|
} else if ( _positionChanged || _localPositionChanged
|
||||||
|
|| _rotationChanged || _localRotationChanged
|
||||||
|
|| _velocityChanged || _localVelocityChanged
|
||||||
|
|| _angularVelocityChanged || _localAngularVelocityChanged) {
|
||||||
|
priority = SCRIPT_POKE_SIMULATION_PRIORITY;
|
||||||
|
}
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
QList<QString> EntityItemProperties::listChangedProperties() {
|
QList<QString> EntityItemProperties::listChangedProperties() {
|
||||||
QList<QString> out;
|
QList<QString> out;
|
||||||
if (containsPositionChange()) {
|
if (containsPositionChange()) {
|
||||||
|
|
|
@ -349,13 +349,18 @@ public:
|
||||||
|
|
||||||
void setCreated(QDateTime& v);
|
void setCreated(QDateTime& v);
|
||||||
|
|
||||||
bool hasTerseUpdateChanges() 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);
|
||||||
void setSimulationPriority(uint8_t priority) { _simulationOwner.setPriority(priority); }
|
void setSimulationPriority(uint8_t priority) { _simulationOwner.setPriority(priority); }
|
||||||
|
uint8_t computeSimulationBidPriority() const;
|
||||||
|
|
||||||
void setActionDataDirty() { _actionDataChanged = true; }
|
void setActionDataDirty() { _actionDataChanged = true; }
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
@ -242,13 +243,12 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
|
||||||
_activityTracking.addedEntityCount++;
|
_activityTracking.addedEntityCount++;
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
auto sessionID = nodeList->getSessionUUID();
|
const auto sessionID = nodeList->getSessionUUID();
|
||||||
|
|
||||||
EntityItemProperties propertiesWithSimID = properties;
|
EntityItemProperties propertiesWithSimID = properties;
|
||||||
if (clientOnly) {
|
if (clientOnly) {
|
||||||
const QUuid myNodeID = sessionID;
|
|
||||||
propertiesWithSimID.setClientOnly(clientOnly);
|
propertiesWithSimID.setClientOnly(clientOnly);
|
||||||
propertiesWithSimID.setOwningAvatarID(myNodeID);
|
propertiesWithSimID.setOwningAvatarID(sessionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
propertiesWithSimID.setLastEditedBy(sessionID);
|
propertiesWithSimID.setLastEditedBy(sessionID);
|
||||||
|
@ -290,7 +290,7 @@ bool EntityScriptingInterface::addLocalEntityCopy(EntityItemProperties& properti
|
||||||
|
|
||||||
entity->setLastBroadcast(usecTimestampNow());
|
entity->setLastBroadcast(usecTimestampNow());
|
||||||
// since we're creating this object we will immediately volunteer to own its simulation
|
// since we're creating this object we will immediately volunteer to own its simulation
|
||||||
entity->setScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
|
entity->upgradeScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY);
|
||||||
properties.setLastEdited(entity->getLastEdited());
|
properties.setLastEdited(entity->getLastEdited());
|
||||||
} else {
|
} else {
|
||||||
qCDebug(entities) << "script failed to add new Entity to local Octree";
|
qCDebug(entities) << "script failed to add new Entity to local Octree";
|
||||||
|
@ -530,54 +530,86 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
||||||
|
|
||||||
_activityTracking.editedEntityCount++;
|
_activityTracking.editedEntityCount++;
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
const auto sessionID = DependencyManager::get<NodeList>()->getSessionUUID();
|
||||||
auto sessionID = 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.
|
|
||||||
|
|
||||||
bool updatedEntity = false;
|
EntityItemPointer entity(nullptr);
|
||||||
_entityTree->withWriteLock([&] {
|
SimulationOwner simulationOwner;
|
||||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
|
_entityTree->withReadLock([&] {
|
||||||
|
// 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() != nodeList->getSessionUUID()) {
|
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) {
|
||||||
|
// flag for simulation ownership, or upgrade existing ownership priority
|
||||||
|
// (actual bids for simulation ownership are sent by the PhysicalEntitySimulation)
|
||||||
|
entity->upgradeScriptSimulationPriority(properties.computeSimulationBidPriority());
|
||||||
|
if (simulationOwner.getID() == sessionID) {
|
||||||
|
// we own the simulation --> copy ALL restricted properties
|
||||||
|
properties.copySimulationRestrictedProperties(entity);
|
||||||
|
} else {
|
||||||
|
// we don't own the simulation but think we would like to
|
||||||
|
|
||||||
if (!scriptSideProperties.parentIDChanged()) {
|
uint8_t desiredPriority = entity->getScriptSimulationPriority();
|
||||||
properties.setParentID(entity->getParentID());
|
if (desiredPriority < simulationOwner.getPriority()) {
|
||||||
}
|
// the priority at which we'd like to own it is not high enough
|
||||||
if (!scriptSideProperties.parentJointIndexChanged()) {
|
// --> assume failure and clear all restricted property changes
|
||||||
properties.setParentJointIndex(entity->getParentJointIndex());
|
properties.clearSimulationRestrictedProperties();
|
||||||
}
|
} else {
|
||||||
if (!scriptSideProperties.localPositionChanged() && !scriptSideProperties.positionChanged()) {
|
// the priority at which we'd like to own it is high enough to win.
|
||||||
properties.setPosition(entity->getWorldPosition());
|
// --> assume success and copy ALL restricted properties
|
||||||
}
|
properties.copySimulationRestrictedProperties(entity);
|
||||||
if (!scriptSideProperties.localRotationChanged() && !scriptSideProperties.rotationChanged()) {
|
}
|
||||||
properties.setRotation(entity->getWorldOrientation());
|
}
|
||||||
}
|
} else if (!simulationOwner.getID().isNull()) {
|
||||||
if (!scriptSideProperties.localDimensionsChanged() && !scriptSideProperties.dimensionsChanged()) {
|
// someone owns this but not us
|
||||||
properties.setDimensions(entity->getScaledDimensions());
|
// clear restricted properties
|
||||||
|
properties.clearSimulationRestrictedProperties();
|
||||||
}
|
}
|
||||||
|
// clear the cached simulationPriority level
|
||||||
|
entity->upgradeScriptSimulationPriority(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());
|
||||||
properties = convertPropertiesFromScriptSemantics(properties, properties.getScalesWithParent());
|
|
||||||
|
// 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.setLastEditedBy(sessionID);
|
||||||
|
|
||||||
|
// done reading and modifying properties --> start write
|
||||||
|
bool updatedEntity = false;
|
||||||
|
_entityTree->withWriteLock([&] {
|
||||||
updatedEntity = _entityTree->updateEntity(entityID, properties);
|
updatedEntity = _entityTree->updateEntity(entityID, properties);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -590,63 +622,37 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
||||||
// return QUuid();
|
// return QUuid();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
bool entityFound { false };
|
bool hasQueryAACubeRelatedChanges = properties.queryAACubeRelatedPropertyChanged();
|
||||||
|
// done writing, send update
|
||||||
_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 hasTerseUpdateChanges = properties.hasTerseUpdateChanges();
|
|
||||||
bool hasPhysicsChanges = properties.hasMiscPhysicsChanges() || hasTerseUpdateChanges;
|
|
||||||
if (_bidOnSimulationOwnership && hasPhysicsChanges) {
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
|
||||||
const QUuid myNodeID = nodeList->getSessionUUID();
|
|
||||||
|
|
||||||
if (entity->getSimulatorID() == myNodeID) {
|
if (hasQueryAACubeRelatedChanges) {
|
||||||
// we think we already own the simulation, so make sure to send ALL TerseUpdate properties
|
|
||||||
if (hasTerseUpdateChanges) {
|
|
||||||
entity->getAllTerseUpdateProperties(properties);
|
|
||||||
}
|
|
||||||
// TODO: if we knew that ONLY TerseUpdate properties 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 a terse 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) {
|
|
||||||
// we re-assert our simulation ownership at a higher priority
|
|
||||||
properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we make a bid for simulation ownership
|
|
||||||
properties.setSimulationOwner(myNodeID, 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
} else {
|
}
|
||||||
|
});
|
||||||
|
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
|
||||||
|
@ -668,8 +674,6 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
||||||
properties.setDimensions(properties.getLocalDimensions());
|
properties.setDimensions(properties.getLocalDimensions());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
if (!entityFound) {
|
|
||||||
// we've made an edit to an entity we don't know about, or to a non-entity. If it's a known non-entity,
|
// we've made an edit to an entity we don't know about, or to a non-entity. If it's a known non-entity,
|
||||||
// print a warning and don't send an edit packet to the entity-server.
|
// print a warning and don't send an edit packet to the entity-server.
|
||||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||||
|
@ -1449,7 +1453,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
|
||||||
}
|
}
|
||||||
action->setIsMine(true);
|
action->setIsMine(true);
|
||||||
success = entity->addAction(simulation, action);
|
success = entity->addAction(simulation, action);
|
||||||
entity->setScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
entity->upgradeScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||||
return false; // Physics will cause a packet to be sent, so don't send from here.
|
return false; // Physics will cause a packet to be sent, so don't send from here.
|
||||||
});
|
});
|
||||||
if (success) {
|
if (success) {
|
||||||
|
@ -1465,7 +1469,7 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid&
|
||||||
return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) {
|
return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) {
|
||||||
bool success = entity->updateAction(simulation, actionID, arguments);
|
bool success = entity->updateAction(simulation, actionID, arguments);
|
||||||
if (success) {
|
if (success) {
|
||||||
entity->setScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
entity->upgradeScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY);
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
});
|
});
|
||||||
|
@ -1479,7 +1483,7 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid&
|
||||||
success = entity->removeAction(simulation, actionID);
|
success = entity->removeAction(simulation, actionID);
|
||||||
if (success) {
|
if (success) {
|
||||||
// reduce from grab to poke
|
// reduce from grab to poke
|
||||||
entity->setScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY);
|
entity->upgradeScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY);
|
||||||
}
|
}
|
||||||
return false; // Physics will cause a packet to be sent, so don't send from here.
|
return false; // Physics will cause a packet to be sent, so don't send from here.
|
||||||
});
|
});
|
||||||
|
|
|
@ -502,36 +502,18 @@ void EntityMotionState::sendBid(OctreeEditPacketSender* packetSender, uint32_t s
|
||||||
properties.setVelocity(linearVelocity);
|
properties.setVelocity(linearVelocity);
|
||||||
properties.setAcceleration(_entity->getAcceleration());
|
properties.setAcceleration(_entity->getAcceleration());
|
||||||
properties.setAngularVelocity(angularVelocity);
|
properties.setAngularVelocity(angularVelocity);
|
||||||
if (_entity->dynamicDataNeedsTransmit()) {
|
|
||||||
_entity->setDynamicDataNeedsTransmit(false);
|
|
||||||
properties.setActionData(_entity->getDynamicData());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_entity->updateQueryAACube()) {
|
|
||||||
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
|
|
||||||
properties.setQueryAACube(_entity->getQueryAACube());
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the LastEdited of the properties but NOT the entity itself
|
|
||||||
quint64 now = usecTimestampNow();
|
|
||||||
properties.setLastEdited(now);
|
|
||||||
|
|
||||||
// we don't own the simulation for this entity yet, but we're sending a bid for it
|
// we don't own the simulation for this entity yet, but we're sending a bid for it
|
||||||
|
quint64 now = usecTimestampNow();
|
||||||
uint8_t finalBidPriority = computeFinalBidPriority();
|
uint8_t finalBidPriority = computeFinalBidPriority();
|
||||||
_entity->clearScriptSimulationPriority();
|
_entity->prepareForSimulationOwnershipBid(properties, now, finalBidPriority);
|
||||||
properties.setSimulationOwner(Physics::getSessionUUID(), finalBidPriority);
|
|
||||||
_entity->setPendingOwnershipPriority(finalBidPriority);
|
|
||||||
|
|
||||||
EntityTreeElementPointer element = _entity->getElement();
|
EntityTreeElementPointer element = _entity->getElement();
|
||||||
EntityTreePointer tree = element ? element->getTree() : nullptr;
|
EntityTreePointer tree = element ? element->getTree() : nullptr;
|
||||||
|
|
||||||
properties.setClientOnly(_entity->getClientOnly());
|
|
||||||
properties.setOwningAvatarID(_entity->getOwningAvatarID());
|
|
||||||
|
|
||||||
EntityItemID id(_entity->getID());
|
EntityItemID id(_entity->getID());
|
||||||
EntityEditPacketSender* entityPacketSender = static_cast<EntityEditPacketSender*>(packetSender);
|
EntityEditPacketSender* entityPacketSender = static_cast<EntityEditPacketSender*>(packetSender);
|
||||||
entityPacketSender->queueEditEntityMessage(PacketType::EntityPhysics, tree, id, properties);
|
entityPacketSender->queueEditEntityMessage(PacketType::EntityPhysics, tree, id, properties);
|
||||||
_entity->setLastBroadcast(now); // for debug/physics status icons
|
|
||||||
|
|
||||||
// NOTE: we don't descend to children for ownership bid. Instead, if we win ownership of the parent
|
// NOTE: we don't descend to children for ownership bid. Instead, if we win ownership of the parent
|
||||||
// then in sendUpdate() we'll walk descendents and send updates for their QueryAACubes if necessary.
|
// then in sendUpdate() we'll walk descendents and send updates for their QueryAACubes if necessary.
|
||||||
|
|
Loading…
Reference in a new issue