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
4242 const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}";
4343
4444 EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :
45− _entityTree(NULL),
45+ _entityTree(nullptr),
4646 _bidOnSimulationOwnership(bidOnSimulationOwnership)
4747 {
4848 auto nodeList = DependencyManager::get<NodeList>();
@@ -352,19 +352,19 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { · 303 unmodified lines
352352 }
353353 }
354354
355−EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) {
356− EntityPropertyFlags noSpecificProperties;
357− return getEntityProperties(identity, noSpecificProperties);
355+EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid entityID) {
356+ const EntityPropertyFlags noSpecificProperties;
357+ return getEntityProperties(entityID, noSpecificProperties);
358358 }
359359
360−EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) {
360+EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid entityID, EntityPropertyFlags desiredProperties) {
361361 PROFILE_RANGE(script_entities, __FUNCTION__);
362362
363363 bool scalesWithParent { false };
364364 EntityItemProperties results;
365365 if (_entityTree) {
366366 _entityTree->withReadLock([&] {
367− EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity));
367+ EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
368368 if (entity) {
369369 scalesWithParent = entity->getScalesWithParent();
370370 if (desiredProperties.getHasProperty(PROP_POSITION) ||
@@ -399,6 +399,136 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit · 28 unmodified lines
399399 return convertPropertiesToScriptSemantics(results, scalesWithParent);
400400 }
401401
402+
403+struct 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)
415+QScriptValue 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+
424+QScriptValue 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+
402532 QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {
403533 PROFILE_RANGE(script_entities, __FUNCTION__);
404534