History

API function for retrieving multiple entity properties with better performance

Thijs Wenker committed 8 years ago

Commit 06491ef1 parent 3b1e0dc34 files · +278 −75Browse files

Showing the changes to libraries/entities/src/EntityScriptingInterface.cpp (1 of 34 files). Show all

Unified · Split

libraries/entities/src/EntityScriptingInterface.cpp+136−6
@@ -42,7 +42,7 @@ const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}"; · 41 unmodified lines
42const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}";42const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}";
43 43
44EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :44EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :
45 _entityTree(NULL),45 _entityTree(nullptr),
46 _bidOnSimulationOwnership(bidOnSimulationOwnership)46 _bidOnSimulationOwnership(bidOnSimulationOwnership)
47{47{
48 auto nodeList = DependencyManager::get<NodeList>();48 auto nodeList = DependencyManager::get<NodeList>();
@@ -352,19 +352,19 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { · 303 unmodified lines
352 }352 }
353}353}
354 354
355EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) {355EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid entityID) {
356 EntityPropertyFlags noSpecificProperties;356 const EntityPropertyFlags noSpecificProperties;
357 return getEntityProperties(identity, noSpecificProperties);357 return getEntityProperties(entityID, noSpecificProperties);
358}358}
359 359
360EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) {360EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid entityID, EntityPropertyFlags desiredProperties) {
361 PROFILE_RANGE(script_entities, __FUNCTION__);361 PROFILE_RANGE(script_entities, __FUNCTION__);
362 362
363 bool scalesWithParent { false };363 bool scalesWithParent { false };
364 EntityItemProperties results;364 EntityItemProperties results;
365 if (_entityTree) {365 if (_entityTree) {
366 _entityTree->withReadLock([&] {366 _entityTree->withReadLock([&] {
367 EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity));367 EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
368 if (entity) {368 if (entity) {
369 scalesWithParent = entity->getScalesWithParent();369 scalesWithParent = entity->getScalesWithParent();
370 if (desiredProperties.getHasProperty(PROP_POSITION) ||370 if (desiredProperties.getHasProperty(PROP_POSITION) ||
@@ -399,6 +399,136 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit · 28 unmodified lines
399 return convertPropertiesToScriptSemantics(results, scalesWithParent);399 return convertPropertiesToScriptSemantics(results, scalesWithParent);
400}400}
401 401
402
403struct EntityPropertiesResult {
404 EntityPropertiesResult(const EntityItemProperties& properties, bool scalesWithParent) :
405 properties(properties),
406 scalesWithParent(scalesWithParent) {
407 }
408 EntityPropertiesResult() = default;
409 EntityItemProperties properties;
410 bool scalesWithParent{ false };
411};
412
413// Static method to make sure that we have the right script engine.
414// Using sender() or QtScriptable::engine() does not work for classes used by multiple threads (script-engines)
415QScriptValue EntityScriptingInterface::getMultipleEntityProperties(QScriptContext* context, QScriptEngine* engine) {
416 const int ARGUMENT_ENTITY_IDS = 0;
417 const int ARGUMENT_EXTENDED_DESIRED_PROPERTIES = 1;
418
419 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
420 const auto entityIDs = qScriptValueToValue<QVector<QUuid>>(context->argument(ARGUMENT_ENTITY_IDS));
421 return entityScriptingInterface->getMultipleEntityPropertiesInternal(engine, entityIDs, context->argument(ARGUMENT_EXTENDED_DESIRED_PROPERTIES));
422}
423
424QScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(QScriptEngine* engine, QVector<QUuid> entityIDs, const QScriptValue& extendedDesiredProperties) {
425 PROFILE_RANGE(script_entities, __FUNCTION__);
426
427 EntityPsuedoPropertyFlags psuedoPropertyFlags;
428 const auto readExtendedPropertyStringValue = [&](QScriptValue extendedProperty) {
429 const auto extendedPropertyString = extendedProperty.toString();
430 if (extendedPropertyString == QString("id")) {
431 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::id;
432 } else if (extendedPropertyString == QString("type")) {
433 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::type;
434 } else if (extendedPropertyString == QString("created")) {
435 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::created;
436 } else if (extendedPropertyString == QString("age")) {
437 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::age;
438 } else if (extendedPropertyString == QString("ageAsText")) {
439 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::ageAsText;
440 } else if (extendedPropertyString == QString("lastEdited")) {
441 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::lastEdited;
442 } else if (extendedPropertyString == QString("boundingBox")) {
443 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::boundingBox;
444 } else if (extendedPropertyString == QString("originalTextures")) {
445 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::originalTextures;
446 } else if (extendedPropertyString == QString("renderInfo")) {
447 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::renderInfo;
448 } else if (extendedPropertyString == QString("clientOnly")) {
449 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::clientOnly;
450 } else if (extendedPropertyString == QString("owningAvatarID")) {
451 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::owningAvatarID;
452 }
453 };
454
455 if (extendedDesiredProperties.isString()) {
456 readExtendedPropertyStringValue(extendedDesiredProperties);
457 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::flagsActive;
458 } else if (extendedDesiredProperties.isArray()) {
459 const quint32 length = extendedDesiredProperties.property("length").toInt32();
460 for (quint32 i = 0; i < length; i++) {
461 readExtendedPropertyStringValue(extendedDesiredProperties.property(i));
462 }
463 psuedoPropertyFlags |= EntityPsuedoPropertyFlag::flagsActive;
464 }
465
466 EntityPropertyFlags desiredProperties = qScriptValueToValue<EntityPropertyFlags>(extendedDesiredProperties);
467 bool needsScriptSymantics = desiredProperties.getHasProperty(PROP_POSITION) ||
468 desiredProperties.getHasProperty(PROP_ROTATION) ||
469 desiredProperties.getHasProperty(PROP_LOCAL_POSITION) ||
470 desiredProperties.getHasProperty(PROP_LOCAL_ROTATION) ||
471 desiredProperties.getHasProperty(PROP_LOCAL_VELOCITY) ||
472 desiredProperties.getHasProperty(PROP_LOCAL_ANGULAR_VELOCITY) ||
473 desiredProperties.getHasProperty(PROP_LOCAL_DIMENSIONS);
474 if (needsScriptSymantics) {
475 // if we are explicitly getting position or rotation, we need parent information to make sense of them.
476 desiredProperties.setHasProperty(PROP_PARENT_ID);
477 desiredProperties.setHasProperty(PROP_PARENT_JOINT_INDEX);
478 }
479 QVector<EntityPropertiesResult> resultProperties;
480 if (_entityTree) {
481 PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Obtaining Properties");
482 int i = 0;
483 const int lockAmount = 500;
484 int size = entityIDs.size();
485 while (i < size) {
486 _entityTree->withReadLock([&] {
487 for (int j = 0; j < lockAmount && i < size; ++i, ++j) {
488 const auto& entityID = entityIDs.at(i);
489 const EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
490 if (entity) {
491 if (!psuedoPropertyFlags && desiredProperties.isEmpty()) {
492 // these are left out of EntityItem::getEntityProperties so that localPosition and localRotation
493 // don't end up in json saves, etc. We still want them here, though.
494 EncodeBitstreamParams params; // unknown
495 desiredProperties = entity->getEntityProperties(params);
496 desiredProperties.setHasProperty(PROP_LOCAL_POSITION);
497 desiredProperties.setHasProperty(PROP_LOCAL_ROTATION);
498 desiredProperties.setHasProperty(PROP_LOCAL_VELOCITY);
499 desiredProperties.setHasProperty(PROP_LOCAL_ANGULAR_VELOCITY);
500 desiredProperties.setHasProperty(PROP_LOCAL_DIMENSIONS);
501 psuedoPropertyFlags = EntityPsuedoPropertyFlag::all;
502 needsScriptSymantics = true;
503 }
504
505 auto properties = entity->getProperties(desiredProperties, true);
506 EntityPropertiesResult result(properties, entity->getScalesWithParent());
507 resultProperties.append(result);
508 }
509 }
510 });
511 }
512 }
513 QScriptValue finalResult = engine->newArray(resultProperties.size());
514 quint32 i = 0;
515 {
516 if (needsScriptSymantics) {
517 PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Script Semantics");
518 foreach(auto result, resultProperties) {
519 finalResult.setProperty(i++, convertPropertiesToScriptSemantics(result.properties, result.scalesWithParent)
520 .copyToScriptValue(engine, false, false, false, psuedoPropertyFlags));
521 }
522 } else {
523 PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Skip Script Semantics");
524 foreach(auto result, resultProperties) {
525 finalResult.setProperty(i++, result.properties.copyToScriptValue(engine, false, false, false, psuedoPropertyFlags));
526 }
527 }
528 }
529 return finalResult;
530}
531
402QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {532QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {
403 PROFILE_RANGE(script_entities, __FUNCTION__);533 PROFILE_RANGE(script_entities, __FUNCTION__);
404 534