2267 lines · 96.1 KB · C++
RawDownload
////  EntityScriptingInterface.cpp//  libraries/entities/src////  Created by Brad Hefta-Gaub on 12/6/13.//  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "EntityScriptingInterface.h" #include <glm/gtc/matrix_transform.hpp>#include <glm/gtx/transform.hpp> #include <QFutureWatcher>#include <QtConcurrent/QtConcurrentRun>#include <QJsonObject>#include <QJsonDocument>#include <QJsonArray> #include <shared/QtHelpers.h>#include <VariantMapToScriptValue.h>#include <SharedUtil.h>#include <SpatialParentFinder.h>#include <AvatarHashMap.h> #include "EntityItemID.h"#include "EntitiesLogging.h"#include "EntityDynamicFactoryInterface.h"#include "EntityDynamicInterface.h"#include "EntitySimulation.h"#include "EntityTree.h"#include "LightEntityItem.h"#include "ModelEntityItem.h"#include "QVariantGLM.h"#include "SimulationOwner.h"#include "ZoneEntityItem.h"#include "WebEntityItem.h"#include <EntityScriptClient.h>#include <Profile.h>#include "GrabPropertyGroup.h" const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}";const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}"; EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :    _entityTree(nullptr),    _bidOnSimulationOwnership(bidOnSimulationOwnership){    auto nodeList = DependencyManager::get<NodeList>();    connect(nodeList.data(), &NodeList::isAllowedEditorChanged, this, &EntityScriptingInterface::canAdjustLocksChanged);    connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptingInterface::canRezChanged);    connect(nodeList.data(), &NodeList::canRezTmpChanged, this, &EntityScriptingInterface::canRezTmpChanged);    connect(nodeList.data(), &NodeList::canRezCertifiedChanged, this, &EntityScriptingInterface::canRezCertifiedChanged);    connect(nodeList.data(), &NodeList::canRezTmpCertifiedChanged, this, &EntityScriptingInterface::canRezTmpCertifiedChanged);    connect(nodeList.data(), &NodeList::canWriteAssetsChanged, this, &EntityScriptingInterface::canWriteAssetsChanged);     // If the user clicks somewhere where there is no entity at all, we will release focus    connect(this, &EntityScriptingInterface::mousePressOffEntity, [=]() {        setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);    });     auto& packetReceiver = nodeList->getPacketReceiver();    packetReceiver.registerListener(PacketType::EntityScriptCallMethod, this, "handleEntityScriptCallMethodPacket");} void EntityScriptingInterface::queueEntityMessage(PacketType packetType,                                                  EntityItemID entityID, const EntityItemProperties& properties) {    getEntityPacketSender()->queueEditEntityMessage(packetType, _entityTree, entityID, properties);} void EntityScriptingInterface::resetActivityTracking() {    _activityTracking.addedEntityCount = 0;    _activityTracking.deletedEntityCount = 0;    _activityTracking.editedEntityCount = 0;} bool EntityScriptingInterface::canAdjustLocks() {    auto nodeList = DependencyManager::get<NodeList>();    return nodeList->isAllowedEditor();} bool EntityScriptingInterface::canRez() {    auto nodeList = DependencyManager::get<NodeList>();    return nodeList->getThisNodeCanRez();} bool EntityScriptingInterface::canRezTmp() {    auto nodeList = DependencyManager::get<NodeList>();    return nodeList->getThisNodeCanRezTmp();} bool EntityScriptingInterface::canRezCertified() {    auto nodeList = DependencyManager::get<NodeList>();    return nodeList->getThisNodeCanRezCertified();} bool EntityScriptingInterface::canRezTmpCertified() {    auto nodeList = DependencyManager::get<NodeList>();    return nodeList->getThisNodeCanRezTmpCertified();} bool EntityScriptingInterface::canWriteAssets() {    auto nodeList = DependencyManager::get<NodeList>();    return nodeList->getThisNodeCanWriteAssets();} bool EntityScriptingInterface::canReplaceContent() {    auto nodeList = DependencyManager::get<NodeList>();    return nodeList->getThisNodeCanReplaceContent();} void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) {    if (_entityTree) {        disconnect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity);        disconnect(_entityTree.get(), &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity);        disconnect(_entityTree.get(), &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities);    }     _entityTree = elementTree;     if (_entityTree) {        connect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity);        connect(_entityTree.get(), &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity);        connect(_entityTree.get(), &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities);    }} EntityItemProperties convertPropertiesToScriptSemantics(const EntityItemProperties& entitySideProperties,                                                        bool scalesWithParent) {    // In EntityTree code, properties.position and properties.rotation are relative to the parent.  In javascript,    // they are in world-space.  The local versions are put into localPosition and localRotation and position and    // rotation are converted from local to world space.    EntityItemProperties scriptSideProperties = entitySideProperties;    scriptSideProperties.setLocalPosition(entitySideProperties.getPosition());    scriptSideProperties.setLocalRotation(entitySideProperties.getRotation());    scriptSideProperties.setLocalVelocity(entitySideProperties.getVelocity());    scriptSideProperties.setLocalAngularVelocity(entitySideProperties.getAngularVelocity());    scriptSideProperties.setLocalDimensions(entitySideProperties.getDimensions());     bool success;    glm::vec3 worldPosition = SpatiallyNestable::localToWorld(entitySideProperties.getPosition(),                                                              entitySideProperties.getParentID(),                                                              entitySideProperties.getParentJointIndex(),                                                              scalesWithParent,                                                              success);    glm::quat worldRotation = SpatiallyNestable::localToWorld(entitySideProperties.getRotation(),                                                              entitySideProperties.getParentID(),                                                              entitySideProperties.getParentJointIndex(),                                                              scalesWithParent,                                                              success);    glm::vec3 worldVelocity = SpatiallyNestable::localToWorldVelocity(entitySideProperties.getVelocity(),                                                                      entitySideProperties.getParentID(),                                                                      entitySideProperties.getParentJointIndex(),                                                                      scalesWithParent,                                                                      success);    glm::vec3 worldAngularVelocity = SpatiallyNestable::localToWorldAngularVelocity(entitySideProperties.getAngularVelocity(),                                                                                    entitySideProperties.getParentID(),                                                                                    entitySideProperties.getParentJointIndex(),                                                                                    scalesWithParent,                                                                                    success);    glm::vec3 worldDimensions = SpatiallyNestable::localToWorldDimensions(entitySideProperties.getDimensions(),                                                                          entitySideProperties.getParentID(),                                                                          entitySideProperties.getParentJointIndex(),                                                                          scalesWithParent,                                                                          success);      scriptSideProperties.setPosition(worldPosition);    scriptSideProperties.setRotation(worldRotation);    scriptSideProperties.setVelocity(worldVelocity);    scriptSideProperties.setAngularVelocity(worldAngularVelocity);    scriptSideProperties.setDimensions(worldDimensions);     return scriptSideProperties;}  // TODO: this method looks expensive and should take properties by reference, update it, and return voidEntityItemProperties convertPropertiesFromScriptSemantics(const EntityItemProperties& scriptSideProperties,                                                          bool scalesWithParent) {    // convert position and rotation properties from world-space to local, unless localPosition and localRotation    // are set.  If they are set, they overwrite position and rotation.    EntityItemProperties entitySideProperties = scriptSideProperties;    bool success;     if (scriptSideProperties.localPositionChanged()) {        entitySideProperties.setPosition(scriptSideProperties.getLocalPosition());    } else if (scriptSideProperties.positionChanged()) {        glm::vec3 localPosition = SpatiallyNestable::worldToLocal(entitySideProperties.getPosition(),                                                                  entitySideProperties.getParentID(),                                                                  entitySideProperties.getParentJointIndex(),                                                                  scalesWithParent, success);        entitySideProperties.setPosition(localPosition);    }     if (scriptSideProperties.localRotationChanged()) {        entitySideProperties.setRotation(scriptSideProperties.getLocalRotation());    } else if (scriptSideProperties.rotationChanged()) {        glm::quat localRotation = SpatiallyNestable::worldToLocal(entitySideProperties.getRotation(),                                                                  entitySideProperties.getParentID(),                                                                  entitySideProperties.getParentJointIndex(),                                                                  scalesWithParent, success);        entitySideProperties.setRotation(localRotation);    }     if (scriptSideProperties.localVelocityChanged()) {        entitySideProperties.setVelocity(scriptSideProperties.getLocalVelocity());    } else if (scriptSideProperties.velocityChanged()) {        glm::vec3 localVelocity = SpatiallyNestable::worldToLocalVelocity(entitySideProperties.getVelocity(),                                                                          entitySideProperties.getParentID(),                                                                          entitySideProperties.getParentJointIndex(),                                                                          scalesWithParent, success);        entitySideProperties.setVelocity(localVelocity);    }     if (scriptSideProperties.localAngularVelocityChanged()) {        entitySideProperties.setAngularVelocity(scriptSideProperties.getLocalAngularVelocity());    } else if (scriptSideProperties.angularVelocityChanged()) {        glm::vec3 localAngularVelocity =            SpatiallyNestable::worldToLocalAngularVelocity(entitySideProperties.getAngularVelocity(),                                                           entitySideProperties.getParentID(),                                                           entitySideProperties.getParentJointIndex(),                                                           scalesWithParent, success);        entitySideProperties.setAngularVelocity(localAngularVelocity);    }     if (scriptSideProperties.localDimensionsChanged()) {        entitySideProperties.setDimensions(scriptSideProperties.getLocalDimensions());    } else if (scriptSideProperties.dimensionsChanged()) {        glm::vec3 localDimensions = SpatiallyNestable::worldToLocalDimensions(entitySideProperties.getDimensions(),                                                                              entitySideProperties.getParentID(),                                                                              entitySideProperties.getParentJointIndex(),                                                                              scalesWithParent, success);        entitySideProperties.setDimensions(localDimensions);    }     return entitySideProperties;}  void synchronizeSpatialKey(const GrabPropertyGroup& grabProperties, QJsonObject& grabbableKey, bool& userDataChanged) {    if (grabProperties.equippableLeftPositionChanged() ||        grabProperties.equippableRightPositionChanged() ||        grabProperties.equippableRightRotationChanged() ||        grabProperties.equippableIndicatorURLChanged() ||        grabProperties.equippableIndicatorScaleChanged() ||        grabProperties.equippableIndicatorOffsetChanged()) {         QJsonObject spatialKey = grabbableKey["spatialKey"].toObject();         if (grabProperties.equippableLeftPositionChanged()) {            if (grabProperties.getEquippableLeftPosition() == INITIAL_LEFT_EQUIPPABLE_POSITION) {                spatialKey.remove("leftRelativePosition");            } else {                spatialKey["leftRelativePosition"] =                    QJsonValue::fromVariant(vec3ToQMap(grabProperties.getEquippableLeftPosition()));            }        }        if (grabProperties.equippableRightPositionChanged()) {            if (grabProperties.getEquippableRightPosition() == INITIAL_RIGHT_EQUIPPABLE_POSITION) {                spatialKey.remove("rightRelativePosition");            } else {                spatialKey["rightRelativePosition"] =                    QJsonValue::fromVariant(vec3ToQMap(grabProperties.getEquippableRightPosition()));            }        }        if (grabProperties.equippableLeftRotationChanged()) {            spatialKey["relativeRotation"] =                QJsonValue::fromVariant(quatToQMap(grabProperties.getEquippableLeftRotation()));        } else if (grabProperties.equippableRightRotationChanged()) {            spatialKey["relativeRotation"] =                QJsonValue::fromVariant(quatToQMap(grabProperties.getEquippableRightRotation()));        }         grabbableKey["spatialKey"] = spatialKey;        userDataChanged = true;    }}  void synchronizeGrabbableKey(const GrabPropertyGroup& grabProperties, QJsonObject& userData, bool& userDataChanged) {    if (grabProperties.triggerableChanged() ||        grabProperties.grabbableChanged() ||        grabProperties.grabFollowsControllerChanged() ||        grabProperties.grabKinematicChanged() ||        grabProperties.equippableChanged() ||        grabProperties.equippableLeftPositionChanged() ||        grabProperties.equippableRightPositionChanged() ||        grabProperties.equippableRightRotationChanged()) {         QJsonObject grabbableKey = userData["grabbableKey"].toObject();         if (grabProperties.triggerableChanged()) {            if (grabProperties.getTriggerable()) {                grabbableKey["triggerable"] = true;            } else {                grabbableKey.remove("triggerable");            }        }        if (grabProperties.grabbableChanged()) {            if (grabProperties.getGrabbable()) {                grabbableKey.remove("grabbable");            } else {                grabbableKey["grabbable"] = false;            }        }        if (grabProperties.grabFollowsControllerChanged()) {            if (grabProperties.getGrabFollowsController()) {                grabbableKey.remove("ignoreIK");            } else {                grabbableKey["ignoreIK"] = false;            }        }        if (grabProperties.grabKinematicChanged()) {            if (grabProperties.getGrabKinematic()) {                grabbableKey.remove("kinematic");            } else {                grabbableKey["kinematic"] = false;            }        }        if (grabProperties.equippableChanged()) {            if (grabProperties.getEquippable()) {                grabbableKey["equippable"] = true;            } else {                grabbableKey.remove("equippable");            }        }         if (grabbableKey.contains("spatialKey")) {            synchronizeSpatialKey(grabProperties, grabbableKey, userDataChanged);        }         userData["grabbableKey"] = grabbableKey;        userDataChanged = true;    }} void synchronizeGrabJoints(const GrabPropertyGroup& grabProperties, QJsonObject& joints) {    QJsonArray rightHand = joints["RightHand"].toArray();    QJsonObject rightHandPosition = rightHand.size() > 0 ? rightHand[0].toObject() : QJsonObject();    QJsonObject rightHandRotation = rightHand.size() > 1 ? rightHand[1].toObject() : QJsonObject();    QJsonArray leftHand = joints["LeftHand"].toArray();    QJsonObject leftHandPosition = leftHand.size() > 0 ? leftHand[0].toObject() : QJsonObject();    QJsonObject leftHandRotation = leftHand.size() > 1 ? leftHand[1].toObject() : QJsonObject();     if (grabProperties.equippableLeftPositionChanged()) {        leftHandPosition =            QJsonValue::fromVariant(vec3ToQMap(grabProperties.getEquippableLeftPosition())).toObject();    }    if (grabProperties.equippableRightPositionChanged()) {        rightHandPosition =            QJsonValue::fromVariant(vec3ToQMap(grabProperties.getEquippableRightPosition())).toObject();    }    if (grabProperties.equippableLeftRotationChanged()) {        leftHandRotation =            QJsonValue::fromVariant(quatToQMap(grabProperties.getEquippableLeftRotation())).toObject();    }    if (grabProperties.equippableRightRotationChanged()) {        rightHandRotation =            QJsonValue::fromVariant(quatToQMap(grabProperties.getEquippableRightRotation())).toObject();    }     rightHand = QJsonArray();    rightHand.append(rightHandPosition);    rightHand.append(rightHandRotation);    joints["RightHand"] = rightHand;    leftHand = QJsonArray();    leftHand.append(leftHandPosition);    leftHand.append(leftHandRotation);    joints["LeftHand"] = leftHand;} void synchronizeEquipHotspot(const GrabPropertyGroup& grabProperties, QJsonObject& userData, bool& userDataChanged) {    if (grabProperties.equippableLeftPositionChanged() ||        grabProperties.equippableRightPositionChanged() ||        grabProperties.equippableRightRotationChanged() ||        grabProperties.equippableIndicatorURLChanged() ||        grabProperties.equippableIndicatorScaleChanged() ||        grabProperties.equippableIndicatorOffsetChanged()) {         QJsonArray equipHotspots = userData["equipHotspots"].toArray();        QJsonObject equipHotspot = equipHotspots[0].toObject();        QJsonObject joints = equipHotspot["joints"].toObject();         synchronizeGrabJoints(grabProperties, joints);         if (grabProperties.equippableIndicatorURLChanged()) {            equipHotspot["modelURL"] = grabProperties.getEquippableIndicatorURL();        }        if (grabProperties.equippableIndicatorScaleChanged()) {            QJsonObject scale =                QJsonValue::fromVariant(vec3ToQMap(grabProperties.getEquippableIndicatorScale())).toObject();            equipHotspot["radius"] = scale;            equipHotspot["modelScale"] = scale;         }        if (grabProperties.equippableIndicatorOffsetChanged()) {            equipHotspot["position"] =                QJsonValue::fromVariant(vec3ToQMap(grabProperties.getEquippableIndicatorOffset())).toObject();        }         equipHotspot["joints"] = joints;        equipHotspots = QJsonArray();        equipHotspots.append(equipHotspot);        userData["equipHotspots"] = equipHotspots;        userDataChanged = true;    }} void synchronizeWearable(const GrabPropertyGroup& grabProperties, QJsonObject& userData, bool& userDataChanged) {    if (grabProperties.equippableLeftPositionChanged() ||        grabProperties.equippableRightPositionChanged() ||        grabProperties.equippableRightRotationChanged() ||        grabProperties.equippableIndicatorURLChanged() ||        grabProperties.equippableIndicatorScaleChanged() ||        grabProperties.equippableIndicatorOffsetChanged()) {         QJsonObject wearable = userData["wearable"].toObject();        QJsonObject joints = wearable["joints"].toObject();         synchronizeGrabJoints(grabProperties, joints);         wearable["joints"] = joints;        userData["wearable"] = wearable;        userDataChanged = true;    }} void synchronizeEditedGrabProperties(EntityItemProperties& properties, const QString& previousUserdata) {    // After sufficient warning to content creators, we should be able to remove this.     if (properties.grabbingRelatedPropertyChanged()) {        // This edit touches a new-style grab property, so make userData agree...        GrabPropertyGroup& grabProperties = properties.getGrab();         bool userDataChanged { false };         // if the edit changed userData, use the updated version coming along with the edit.  If not, use        // what was already in the entity.        QByteArray userDataString;        if (properties.userDataChanged()) {            userDataString = properties.getUserData().toUtf8();        } else {            userDataString = previousUserdata.toUtf8();;        }        QJsonObject userData = QJsonDocument::fromJson(userDataString).object();         if (userData.contains("grabbableKey")) {            synchronizeGrabbableKey(grabProperties, userData, userDataChanged);        }        if (userData.contains("equipHotspots")) {            synchronizeEquipHotspot(grabProperties, userData, userDataChanged);        }        if (userData.contains("wearable")) {            synchronizeWearable(grabProperties, userData, userDataChanged);        }         if (userDataChanged) {            properties.setUserData(QJsonDocument(userData).toJson());        }     } else if (properties.userDataChanged()) {        // This edit touches userData (and doesn't touch a new-style grab property).  Check for grabbableKey in the        // userdata and make the new-style grab properties agree        convertGrabUserDataToProperties(properties);    }}  QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties, bool clientOnly) {    PROFILE_RANGE(script_entities, __FUNCTION__);     _activityTracking.addedEntityCount++;     auto nodeList = DependencyManager::get<NodeList>();    const auto sessionID = nodeList->getSessionUUID();     EntityItemProperties propertiesWithSimID = properties;    if (clientOnly) {        propertiesWithSimID.setClientOnly(clientOnly);        propertiesWithSimID.setOwningAvatarID(sessionID);    }     propertiesWithSimID.setLastEditedBy(sessionID);     bool scalesWithParent = propertiesWithSimID.getScalesWithParent();     propertiesWithSimID = convertPropertiesFromScriptSemantics(propertiesWithSimID, scalesWithParent);    propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged());    synchronizeEditedGrabProperties(propertiesWithSimID, QString());     EntityItemID id;    // If we have a local entity tree set, then also update it.    bool success = addLocalEntityCopy(propertiesWithSimID, id);     // queue the packet    if (success) {

Lines 1–500 of 2267.