Showing the changes to libraries/entities/src/EntityScriptingInterface.cpp (1 of 36 files). Show all
Unified · Split
| @@ -72,23 +72,23 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties · 71 unmodified lines | |||
| 72 | // If we have a local entity tree set, then also update it. | 72 | // If we have a local entity tree set, then also update it. |
| 73 | bool success = true; | 73 | bool success = true; |
| 74 | if (_entityTree) { | 74 | if (_entityTree) { |
| 75 | _entityTree->lockForWrite(); | 75 | _entityTree->withWriteLock([&] { |
| 76 | EntityItemPointer entity = _entityTree->addEntity(id, propertiesWithSimID); | 76 | EntityItemPointer entity = _entityTree->addEntity(id, propertiesWithSimID); |
| 77 | if (entity) { | 77 | if (entity) { |
| 78 | // This Node is creating a new object. If it's in motion, set this Node as the simulator. | 78 | // This Node is creating a new object. If it's in motion, set this Node as the simulator. |
| 79 | auto nodeList = DependencyManager::get<NodeList>(); | 79 | auto nodeList = DependencyManager::get<NodeList>(); |
| 80 | const QUuid myNodeID = nodeList->getSessionUUID(); | 80 | const QUuid myNodeID = nodeList->getSessionUUID(); |
| 81 | propertiesWithSimID.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); | 81 | propertiesWithSimID.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); |
| 82 | 82 | ||
| 83 | // and make note of it now, so we can act on it right away. | 83 | // and make note of it now, so we can act on it right away. |
| 84 | entity->setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); | 84 | entity->setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); |
| 85 | 85 | ||
| 86 | entity->setLastBroadcast(usecTimestampNow()); | 86 | entity->setLastBroadcast(usecTimestampNow()); |
| 87 | } else { | 87 | } else { |
| 88 | qCDebug(entities) << "script failed to add new Entity to local Octree"; | 88 | qCDebug(entities) << "script failed to add new Entity to local Octree"; |
| 89 | success = false; | 89 | success = false; |
| 90 | } | 90 | } |
| 91 | _entityTree->unlock(); | 91 | }); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | // queue the packet | 94 | // queue the packet |
| @@ -102,28 +102,26 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties · 7 unmodified lines | |||
| 102 | EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) { | 102 | EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) { |
| 103 | EntityItemProperties results; | 103 | EntityItemProperties results; |
| 104 | if (_entityTree) { | 104 | if (_entityTree) { |
| 105 | _entityTree->lockForRead(); | 105 | _entityTree->withReadLock([&] { |
| 106 | 106 | EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity)); | |
| 107 | EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity)); | 107 | if (entity) { |
| 108 | 108 | results = entity->getProperties(); | |
| 109 | if (entity) { | 109 | |
| 110 | results = entity->getProperties(); | 110 | // TODO: improve sitting points and naturalDimensions in the future, |
| 111 | 111 | // for now we've included the old sitting points model behavior for entity types that are models | |
| 112 | // TODO: improve sitting points and naturalDimensions in the future, | 112 | // we've also added this hack for setting natural dimensions of models |
| 113 | // for now we've included the old sitting points model behavior for entity types that are models | 113 | if (entity->getType() == EntityTypes::Model) { |
| 114 | // we've also added this hack for setting natural dimensions of models | 114 | const FBXGeometry* geometry = _entityTree->getGeometryForEntity(entity); |
| 115 | if (entity->getType() == EntityTypes::Model) { | 115 | if (geometry) { |
| 116 | const FBXGeometry* geometry = _entityTree->getGeometryForEntity(entity); | 116 | results.setSittingPoints(geometry->sittingPoints); |
| 117 | if (geometry) { | 117 | Extents meshExtents = geometry->getUnscaledMeshExtents(); |
| 118 | results.setSittingPoints(geometry->sittingPoints); | 118 | results.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum); |
| 119 | Extents meshExtents = geometry->getUnscaledMeshExtents(); | 119 | results.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum); |
| 120 | results.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum); | 120 | } |
| 121 | results.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum); | ||
| 122 | } | 121 | } |
| 123 | } | ||
| 124 | 122 | ||
| 125 | } | 123 | } |
| 126 | _entityTree->unlock(); | 124 | }); |
| 127 | } | 125 | } |
| 128 | 126 | ||
| 129 | return results; | 127 | return results; |
| @@ -132,56 +130,59 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit · 2 unmodified lines | |||
| 132 | QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties properties) { | 130 | QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties properties) { |
| 133 | EntityItemID entityID(id); | 131 | EntityItemID entityID(id); |
| 134 | // If we have a local entity tree set, then also update it. | 132 | // If we have a local entity tree set, then also update it. |
| 135 | if (_entityTree) { | 133 | if (!_entityTree) { |
| 136 | _entityTree->lockForWrite(); | 134 | queueEntityMessage(PacketType::EntityEdit, entityID, properties); |
| 137 | bool updatedEntity = _entityTree->updateEntity(entityID, properties); | 135 | return id; |
| 138 | _entityTree->unlock(); | 136 | } |
| 139 | 137 | ||
| 140 | if (updatedEntity) { | 138 | bool updatedEntity = false; |
| 141 | _entityTree->lockForRead(); | 139 | _entityTree->withWriteLock([&] { |
| 142 | EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); | 140 | updatedEntity = _entityTree->updateEntity(entityID, properties); |
| 143 | if (entity) { | 141 | }); |
| 144 | // make sure the properties has a type, so that the encode can know which properties to include | 142 | |
| 145 | properties.setType(entity->getType()); | 143 | |
| 146 | bool hasTerseUpdateChanges = properties.hasTerseUpdateChanges(); | 144 | if (!updatedEntity) { |
| 147 | bool hasPhysicsChanges = properties.hasMiscPhysicsChanges() || hasTerseUpdateChanges; | 145 | return QUuid(); |
| 148 | if (hasPhysicsChanges) { | 146 | } |
| 149 | auto nodeList = DependencyManager::get<NodeList>(); | 147 | |
| 150 | const QUuid myNodeID = nodeList->getSessionUUID(); | 148 | _entityTree->withReadLock([&] { |
| 151 | 149 | EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); | |
| 152 | if (entity->getSimulatorID() == myNodeID) { | 150 | if (entity) { |
| 153 | // we think we already own the simulation, so make sure to send ALL TerseUpdate properties | 151 | // make sure the properties has a type, so that the encode can know which properties to include |
| 154 | if (hasTerseUpdateChanges) { | 152 | properties.setType(entity->getType()); |
| 155 | entity->getAllTerseUpdateProperties(properties); | 153 | bool hasTerseUpdateChanges = properties.hasTerseUpdateChanges(); |
| 156 | } | 154 | bool hasPhysicsChanges = properties.hasMiscPhysicsChanges() || hasTerseUpdateChanges; |
| 157 | // TODO: if we knew that ONLY TerseUpdate properties have changed in properties AND the object | 155 | if (hasPhysicsChanges) { |
| 158 | // is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update | 156 | auto nodeList = DependencyManager::get<NodeList>(); |
| 159 | // and instead let the physics simulation decide when to send a terse update. This would remove | 157 | const QUuid myNodeID = nodeList->getSessionUUID(); |
| 160 | // the "slide-no-rotate" glitch (and typical a double-update) that we see during the "poke rolling | 158 | |
| 161 | // balls" test. However, even if we solve this problem we still need to provide a "slerp the visible | 159 | if (entity->getSimulatorID() == myNodeID) { |
| 162 | // proxy toward the true physical position" feature to hide the final glitches in the remote watcher's | 160 | // we think we already own the simulation, so make sure to send ALL TerseUpdate properties |
| 163 | // simulation. | 161 | if (hasTerseUpdateChanges) { |
| 164 | 162 | entity->getAllTerseUpdateProperties(properties); | |
| 165 | if (entity->getSimulationPriority() < SCRIPT_EDIT_SIMULATION_PRIORITY) { | 163 | } |
| 166 | // we re-assert our simulation ownership at a higher priority | 164 | // TODO: if we knew that ONLY TerseUpdate properties have changed in properties AND the object |
| 167 | properties.setSimulationOwner(myNodeID, | 165 | // is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update |
| 168 | glm::max(entity->getSimulationPriority(), SCRIPT_EDIT_SIMULATION_PRIORITY)); | 166 | // and instead let the physics simulation decide when to send a terse update. This would remove |
| 169 | } | 167 | // the "slide-no-rotate" glitch (and typical a double-update) that we see during the "poke rolling |
| 170 | } else { | 168 | // balls" test. However, even if we solve this problem we still need to provide a "slerp the visible |
| 171 | // we make a bid for simulation ownership | 169 | // proxy toward the true physical position" feature to hide the final glitches in the remote watcher's |
| 172 | properties.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); | 170 | // simulation. |
| 173 | entity->flagForOwnership(); | 171 | |
| 172 | if (entity->getSimulationPriority() < SCRIPT_EDIT_SIMULATION_PRIORITY) { | ||
| 173 | // we re-assert our simulation ownership at a higher priority | ||
| 174 | properties.setSimulationOwner(myNodeID, | ||
| 175 | glm::max(entity->getSimulationPriority(), SCRIPT_EDIT_SIMULATION_PRIORITY)); | ||
| 174 | } | 176 | } |
| 177 | } else { | ||
| 178 | // we make a bid for simulation ownership | ||
| 179 | properties.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY); | ||
| 180 | entity->flagForOwnership(); | ||
| 175 | } | 181 | } |
| 176 | entity->setLastBroadcast(usecTimestampNow()); | ||
| 177 | } | 182 | } |
| 178 | _entityTree->unlock(); | 183 | entity->setLastBroadcast(usecTimestampNow()); |
| 179 | queueEntityMessage(PacketType::EntityEdit, entityID, properties); | ||
| 180 | return id; | ||
| 181 | } | 184 | } |
| 182 | return QUuid(); | 185 | }); |
| 183 | } | ||
| 184 | |||
| 185 | queueEntityMessage(PacketType::EntityEdit, entityID, properties); | 186 | queueEntityMessage(PacketType::EntityEdit, entityID, properties); |
| 186 | return id; | 187 | return id; |
| 187 | } | 188 | } |
| @@ -192,18 +193,16 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { · 4 unmodified lines | |||
| 192 | 193 | ||
| 193 | // If we have a local entity tree set, then also update it. | 194 | // If we have a local entity tree set, then also update it. |
| 194 | if (_entityTree) { | 195 | if (_entityTree) { |
| 195 | _entityTree->lockForWrite(); | 196 | _entityTree->withWriteLock([&] { |
| 196 | 197 | EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); | |
| 197 | EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); | 198 | if (entity) { |
| 198 | if (entity) { | 199 | if (entity->getLocked()) { |
| 199 | if (entity->getLocked()) { | 200 | shouldDelete = false; |
| 200 | shouldDelete = false; | 201 | } else { |
| 201 | } else { | 202 | _entityTree->deleteEntity(entityID); |
| 202 | _entityTree->deleteEntity(entityID); | 203 | } |
| 203 | } | 204 | } |
| 204 | } | 205 | }); |
| 205 | |||
| 206 | _entityTree->unlock(); | ||
| 207 | } | 206 | } |
| 208 | 207 | ||
| 209 | // if at this point, we know the id, and we should still delete the entity, send the update to the entity server | 208 | // if at this point, we know the id, and we should still delete the entity, send the update to the entity server |
| @@ -215,9 +214,10 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { · 5 unmodified lines | |||
| 215 | QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const { | 214 | QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const { |
| 216 | EntityItemID result; | 215 | EntityItemID result; |
| 217 | if (_entityTree) { | 216 | if (_entityTree) { |
| 218 | _entityTree->lockForRead(); | 217 | EntityItemPointer closestEntity; |
| 219 | EntityItemPointer closestEntity = _entityTree->findClosestEntity(center, radius); | 218 | _entityTree->withReadLock([&] { |
| 220 | _entityTree->unlock(); | 219 | closestEntity = _entityTree->findClosestEntity(center, radius); |
| 220 | }); | ||
| 221 | if (closestEntity) { | 221 | if (closestEntity) { |
| 222 | result = closestEntity->getEntityItemID(); | 222 | result = closestEntity->getEntityItemID(); |
| 223 | } | 223 | } |
| @@ -228,19 +228,19 @@ QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float · 4 unmodified lines | |||
| 228 | 228 | ||
| 229 | void EntityScriptingInterface::dumpTree() const { | 229 | void EntityScriptingInterface::dumpTree() const { |
| 230 | if (_entityTree) { | 230 | if (_entityTree) { |
| 231 | _entityTree->lockForRead(); | 231 | _entityTree->withReadLock([&] { |
| 232 | _entityTree->dumpTree(); | 232 | _entityTree->dumpTree(); |
| 233 | _entityTree->unlock(); | 233 | }); |
| 234 | } | 234 | } |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | QVector<QUuid> EntityScriptingInterface::findEntities(const glm::vec3& center, float radius) const { | 237 | QVector<QUuid> EntityScriptingInterface::findEntities(const glm::vec3& center, float radius) const { |
| 238 | QVector<QUuid> result; | 238 | QVector<QUuid> result; |
| 239 | if (_entityTree) { | 239 | if (_entityTree) { |
| 240 | _entityTree->lockForRead(); | ||
| 241 | QVector<EntityItemPointer> entities; | 240 | QVector<EntityItemPointer> entities; |
| 242 | _entityTree->findEntities(center, radius, entities); | 241 | _entityTree->withReadLock([&] { |
| 243 | _entityTree->unlock(); | 242 | _entityTree->findEntities(center, radius, entities); |
| 243 | }); | ||
| 244 | 244 | ||
| 245 | foreach (EntityItemPointer entity, entities) { | 245 | foreach (EntityItemPointer entity, entities) { |
| 246 | result << entity->getEntityItemID(); | 246 | result << entity->getEntityItemID(); |
| @@ -252,11 +252,11 @@ QVector<QUuid> EntityScriptingInterface::findEntities(const glm::vec3& center, f · 5 unmodified lines | |||
| 252 | QVector<QUuid> EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const { | 252 | QVector<QUuid> EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const { |
| 253 | QVector<QUuid> result; | 253 | QVector<QUuid> result; |
| 254 | if (_entityTree) { | 254 | if (_entityTree) { |
| 255 | _entityTree->lockForRead(); | ||
| 256 | AABox box(corner, dimensions); | ||
| 257 | QVector<EntityItemPointer> entities; | 255 | QVector<EntityItemPointer> entities; |
| 258 | _entityTree->findEntities(box, entities); | 256 | _entityTree->withReadLock([&] { |
| 259 | _entityTree->unlock(); | 257 | AABox box(corner, dimensions); |
| 258 | _entityTree->findEntities(box, entities); | ||
| 259 | }); | ||
| 260 | 260 | ||
| 261 | foreach (EntityItemPointer entity, entities) { | 261 | foreach (EntityItemPointer entity, entities) { |
| 262 | result << entity->getEntityItemID(); | 262 | result << entity->getEntityItemID(); |
| @@ -432,9 +432,10 @@ bool EntityScriptingInterface::setVoxels(QUuid entityID, · 169 unmodified lines | |||
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | auto polyVoxEntity = std::dynamic_pointer_cast<PolyVoxEntityItem>(entity); | 434 | auto polyVoxEntity = std::dynamic_pointer_cast<PolyVoxEntityItem>(entity); |
| 435 | _entityTree->lockForWrite(); | 435 | bool result; |
| 436 | bool result = actor(*polyVoxEntity); | 436 | _entityTree->withWriteLock([&] { |
| 437 | _entityTree->unlock(); | 437 | result = actor(*polyVoxEntity); |
| 438 | }); | ||
| 438 | return result; | 439 | return result; |
| 439 | } | 440 | } |
| 440 | 441 | ||
| @@ -457,15 +458,17 @@ bool EntityScriptingInterface::setPoints(QUuid entityID, std::function<bool(Line · 16 unmodified lines | |||
| 457 | auto now = usecTimestampNow(); | 458 | auto now = usecTimestampNow(); |
| 458 | 459 | ||
| 459 | auto lineEntity = std::static_pointer_cast<LineEntityItem>(entity); | 460 | auto lineEntity = std::static_pointer_cast<LineEntityItem>(entity); |
| 460 | _entityTree->lockForWrite(); | 461 | bool success; |
| 461 | bool success = actor(*lineEntity); | 462 | _entityTree->withWriteLock([&] { |
| 462 | entity->setLastEdited(now); | 463 | success = actor(*lineEntity); |
| 463 | entity->setLastBroadcast(now); | 464 | entity->setLastEdited(now); |
| 464 | _entityTree->unlock(); | 465 | entity->setLastBroadcast(now); |
| 465 | 466 | }); | |
| 466 | _entityTree->lockForRead(); | 467 | |
| 467 | EntityItemProperties properties = entity->getProperties(); | 468 | EntityItemProperties properties; |
| 468 | _entityTree->unlock(); | 469 | _entityTree->withReadLock([&] { |
| 470 | properties = entity->getProperties(); | ||
| 471 | }); | ||
| 469 | 472 | ||
| 470 | properties.setLinePointsDirty(); | 473 | properties.setLinePointsDirty(); |
| 471 | properties.setLastEdited(now); | 474 | properties.setLastEdited(now); |
| @@ -543,32 +546,33 @@ bool EntityScriptingInterface::actionWorker(const QUuid& entityID, · 71 unmodified lines | |||
| 543 | return false; | 546 | return false; |
| 544 | } | 547 | } |
| 545 | 548 | ||
| 546 | _entityTree->lockForWrite(); | 549 | EntityItemPointer entity; |
| 547 | 550 | bool success; | |
| 548 | EntitySimulation* simulation = _entityTree->getSimulation(); | 551 | _entityTree->withWriteLock([&] { |
| 549 | EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); | 552 | EntitySimulation* simulation = _entityTree->getSimulation(); |
| 550 | if (!entity) { | 553 | EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); |
| 551 | qDebug() << "actionWorker -- unknown entity" << entityID; | 554 | if (!entity) { |
| 552 | _entityTree->unlock(); | 555 | qDebug() << "actionWorker -- unknown entity" << entityID; |
| 553 | return false; | 556 | return; |
| 554 | } | 557 | } |
| 555 | 558 | ||
| 556 | if (!simulation) { | 559 | if (!simulation) { |
| 557 | qDebug() << "actionWorker -- no simulation" << entityID; | 560 | qDebug() << "actionWorker -- no simulation" << entityID; |
| 558 | _entityTree->unlock(); | 561 | return; |
| 559 | return false; | 562 | } |
| 560 | } | ||
| 561 | 563 | ||
| 562 | bool success = actor(simulation, entity); | 564 | success = actor(simulation, entity); |
| 563 | if (success) { | 565 | if (success) { |
| 564 | _entityTree->entityChanged(entity); | 566 | _entityTree->entityChanged(entity); |
| 565 | } | 567 | } |
| 566 | _entityTree->unlock(); | 568 | }); |
| 567 | 569 | ||
| 568 | // transmit the change | 570 | // transmit the change |
| 569 | _entityTree->lockForRead(); | 571 | EntityItemProperties properties; |
| 570 | EntityItemProperties properties = entity->getProperties(); | 572 | _entityTree->withReadLock([&] { |
| 571 | _entityTree->unlock(); | 573 | properties = entity->getProperties(); |
| 574 | }); | ||
| 575 | |||
| 572 | properties.setActionDataDirty(); | 576 | properties.setActionDataDirty(); |
| 573 | auto now = usecTimestampNow(); | 577 | auto now = usecTimestampNow(); |
| 574 | properties.setLastEdited(now); | 578 | properties.setLastEdited(now); |