QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties properties) {
    EntityItemID entityID(id);
    // If we have a local entity tree set, then also update it.
    if (!_entityTree) {
        queueEntityMessage(PacketType::EntityEdit, entityID, properties);
        return id;
    }

    bool updatedEntity = false;
    _entityTree->withWriteLock([&] {
        updatedEntity = _entityTree->updateEntity(entityID, properties);
    });


    if (!updatedEntity) {
        return QUuid();
    }

    _entityTree->withReadLock([&] {
        EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
        if (entity) {
            // make sure the properties has a type, so that the encode can know which properties to include
            properties.setType(entity->getType());
            bool hasTerseUpdateChanges = properties.hasTerseUpdateChanges();
            bool hasPhysicsChanges = properties.hasMiscPhysicsChanges() || hasTerseUpdateChanges;
            if (hasPhysicsChanges) {
                auto nodeList = DependencyManager::get<NodeList>();
                const QUuid myNodeID = nodeList->getSessionUUID();

                if (entity->getSimulatorID() == myNodeID) {
                    // 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 a 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_EDIT_SIMULATION_PRIORITY) {
                        // we re-assert our simulation ownership at a higher priority
                        properties.setSimulationOwner(myNodeID,
                            glm::max(entity->getSimulationPriority(), SCRIPT_EDIT_SIMULATION_PRIORITY));
                    }
                } else {
                    // we make a bid for simulation ownership
                    properties.setSimulationOwner(myNodeID, SCRIPT_EDIT_SIMULATION_PRIORITY);
                    entity->flagForOwnership();
                }
            }
            entity->setLastBroadcast(usecTimestampNow());
        }
    });
    queueEntityMessage(PacketType::EntityEdit, entityID, properties);
    return id;
}