Beispiel #1
0
void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ignoreWarnings) {
    EntityTreeElementPointer containingElement = getContainingElement(entityID);
    if (!containingElement) {
        if (!ignoreWarnings) {
            qCDebug(entities) << "UNEXPECTED!!!!  EntityTree::deleteEntity() entityID doesn't exist!!! entityID=" << entityID;
        }
        return;
    }

    EntityItemPointer existingEntity = containingElement->getEntityWithEntityItemID(entityID);
    if (!existingEntity) {
        if (!ignoreWarnings) {
            qCDebug(entities) << "UNEXPECTED!!!! don't call EntityTree::deleteEntity() on entity items that don't exist. "
                        "entityID=" << entityID;
        }
        return;
    }

    if (existingEntity->getLocked() && !force) {
        if (!ignoreWarnings) {
            qCDebug(entities) << "ERROR! EntityTree::deleteEntity() trying to delete locked entity. entityID=" << entityID;
        }
        return;
    }

    emit deletingEntity(entityID);

    // NOTE: callers must lock the tree before using this method
    DeleteEntityOperator theOperator(getThisPointer(), entityID);
    recurseTreeWithOperator(&theOperator);
    processRemovedEntities(theOperator);
    _isDirty = true;
}
Beispiel #2
0
void EntityTree::deleteEntities(QSet<EntityItemID> entityIDs, bool force, bool ignoreWarnings) {
    // NOTE: callers must lock the tree before using this method
    DeleteEntityOperator theOperator(getThisPointer());
    foreach(const EntityItemID& entityID, entityIDs) {
        EntityTreeElementPointer containingElement = getContainingElement(entityID);
        if (!containingElement) {
            if (!ignoreWarnings) {
                qCDebug(entities) << "UNEXPECTED!!!!  EntityTree::deleteEntities() entityID doesn't exist!!! entityID=" << entityID;
            }
            continue;
        }

        EntityItemPointer existingEntity = containingElement->getEntityWithEntityItemID(entityID);
        if (!existingEntity) {
            if (!ignoreWarnings) {
                qCDebug(entities) << "UNEXPECTED!!!! don't call EntityTree::deleteEntities() on entity items that don't exist. "
                            "entityID=" << entityID;
            }
            continue;
        }

        if (existingEntity->getLocked() && !force) {
            if (!ignoreWarnings) {
                qCDebug(entities) << "ERROR! EntityTree::deleteEntities() trying to delete locked entity. entityID=" << entityID;
            }
            continue;
        }

        // tell our delete operator about this entityID
        theOperator.addEntityIDToDeleteList(entityID);
        emit deletingEntity(entityID);
    }
Beispiel #3
0
void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) {
    quint64 expiresWhen = 0;
    EntityItemPointer ownerEntity = nullptr;

    withReadLock([&]{
        ownerEntity = _ownerEntity.lock();
        expiresWhen = _expires;
    });

    if (!ownerEntity) {
        qCDebug(physics) << "warning -- action [" << _tag << "] with no entity removing self from btCollisionWorld.";
        btDynamicsWorld* dynamicsWorld = static_cast<btDynamicsWorld*>(collisionWorld);
        if (dynamicsWorld) {
            dynamicsWorld->removeAction(this);
        }
        return;
    }

    if (expiresWhen > 0) {
        quint64 now = usecTimestampNow();
        if (now > expiresWhen) {
            QUuid myID;
            withWriteLock([&]{
                _active = false;
                myID = getID();
            });
            if (ownerEntity) {
                ownerEntity->removeAction(nullptr, myID);
            }
        }
    }

    if (!_active) {
        return;
    }

    if (ownerEntity->getLocked()) {
        return;
    }

    updateActionWorker(deltaTimeStep);
}
void EntityScriptingInterface::deleteEntity(QUuid id) {
    EntityItemID entityID(id);
    bool shouldDelete = true;

    // If we have a local entity tree set, then also update it.
    if (_entityTree) {
        _entityTree->withWriteLock([&] {
            EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
            if (entity) {

                auto dimensions = entity->getDimensions();
                float volume = dimensions.x * dimensions.y * dimensions.z;
                auto density = entity->getDensity();
                auto velocity = entity->getVelocity().length();
                float cost = calculateCost(density * volume, velocity, 0);
                cost *= costMultiplier;

                if (cost > _currentAvatarEnergy) {
                    shouldDelete = false;
                    return;
                } else {
                    //debit the avatar energy and continue
                    emit debitEnergySource(cost);
                }

                if (entity->getLocked()) {
                    shouldDelete = false;
                } else {
                    _entityTree->deleteEntity(entityID);
                }
            }
        });
    }

    // if at this point, we know the id, and we should still delete the entity, send the update to the entity server
    if (shouldDelete) {
        getEntityPacketSender()->queueEraseEntityMessage(entityID);
    }
}
void EntityScriptingInterface::deleteEntity(QUuid id) {
    EntityItemID entityID(id);
    bool shouldDelete = true;

    // If we have a local entity tree set, then also update it.
    if (_entityTree) {
        _entityTree->withWriteLock([&] {
            EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
            if (entity) {
                if (entity->getLocked()) {
                    shouldDelete = false;
                } else {
                    _entityTree->deleteEntity(entityID);
                }
            }
        });
    }

    // if at this point, we know the id, and we should still delete the entity, send the update to the entity server
    if (shouldDelete) {
        getEntityPacketSender()->queueEraseEntityMessage(entityID);
    }
}
Beispiel #6
0
bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityItemProperties& origProperties,
                                         EntityTreeElementPointer containingElement, const SharedNodePointer& senderNode) {
    EntityItemProperties properties = origProperties;

    bool allowLockChange;
    QUuid senderID;
    if (senderNode.isNull()) {
        auto nodeList = DependencyManager::get<NodeList>();
        allowLockChange = nodeList->getThisNodeCanAdjustLocks();
        senderID = nodeList->getSessionUUID();
    } else {
        allowLockChange = senderNode->getCanAdjustLocks();
        senderID = senderNode->getUUID();
    }

    if (!allowLockChange && (entity->getLocked() != properties.getLocked())) {
        qCDebug(entities) << "Refusing disallowed lock adjustment.";
        return false;
    }

    // enforce support for locked entities. If an entity is currently locked, then the only
    // property we allow you to change is the locked property.
    if (entity->getLocked()) {
        if (properties.lockedChanged()) {
            bool wantsLocked = properties.getLocked();
            if (!wantsLocked) {
                EntityItemProperties tempProperties;
                tempProperties.setLocked(wantsLocked);
                UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, tempProperties);
                recurseTreeWithOperator(&theOperator);
                _isDirty = true;
            }
        }
    } else {
        if (getIsServer()) {
            bool simulationBlocked = !entity->getSimulatorID().isNull();
            if (properties.simulationOwnerChanged()) {
                QUuid submittedID = properties.getSimulationOwner().getID();
                // a legit interface will only submit their own ID or NULL:
                if (submittedID.isNull()) {
                    if (entity->getSimulatorID() == senderID) {
                        // We only allow the simulation owner to clear their own simulationID's.
                        simulationBlocked = false;
                        properties.clearSimulationOwner(); // clear everything
                    }
                    // else: We assume the sender really did believe it was the simulation owner when it sent
                } else if (submittedID == senderID) {
                    // the sender is trying to take or continue ownership
                    if (entity->getSimulatorID().isNull()) {
                        // the sender it taking ownership
                        properties.promoteSimulationPriority(RECRUIT_SIMULATION_PRIORITY);
                        simulationBlocked = false;
                    } else if (entity->getSimulatorID() == senderID) {
                        // the sender is asserting ownership
                        simulationBlocked = false;
                    } else {
                        // the sender is trying to steal ownership from another simulator
                        // so we apply the rules for ownership change:
                        // (1) higher priority wins
                        // (2) equal priority wins if ownership filter has expired except...
                        uint8_t oldPriority = entity->getSimulationPriority();
                        uint8_t newPriority = properties.getSimulationOwner().getPriority();
                        if (newPriority > oldPriority ||
                             (newPriority == oldPriority && properties.getSimulationOwner().hasExpired())) {
                            simulationBlocked = false;
                        }
                    }
                } else {
                    // the entire update is suspect --> ignore it
                    return false;
                }
            } else {
                simulationBlocked = senderID != entity->getSimulatorID();
            }
            if (simulationBlocked) {
                // squash ownership and physics-related changes.
                properties.setSimulationOwnerChanged(false);
                properties.setPositionChanged(false);
                properties.setRotationChanged(false);
                properties.setVelocityChanged(false);
                properties.setAngularVelocityChanged(false);
                properties.setAccelerationChanged(false);

                if (wantTerseEditLogging()) {
                    qCDebug(entities) << senderNode->getUUID() << "physical edits suppressed";
                }
            }
        }
        // else client accepts what the server says

        QString entityScriptBefore = entity->getScript();
        quint64 entityScriptTimestampBefore = entity->getScriptTimestamp();
        QString collisionSoundURLBefore = entity->getCollisionSoundURL();
        uint32_t preFlags = entity->getDirtyFlags();
        UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, properties);
        recurseTreeWithOperator(&theOperator);
        _isDirty = true;

        uint32_t newFlags = entity->getDirtyFlags() & ~preFlags;
        if (newFlags) {
            if (_simulation) {
                if (newFlags & DIRTY_SIMULATION_FLAGS) {
                    _simulation->changeEntity(entity);
                }
            } else {
                // normally the _simulation clears ALL updateFlags, but since there is none we do it explicitly
                entity->clearDirtyFlags();
            }
        }

        QString entityScriptAfter = entity->getScript();
        quint64 entityScriptTimestampAfter = entity->getScriptTimestamp();
        bool reload = entityScriptTimestampBefore != entityScriptTimestampAfter;
        if (entityScriptBefore != entityScriptAfter || reload) {
            emitEntityScriptChanging(entity->getEntityItemID(), reload); // the entity script has changed
        }
        maybeNotifyNewCollisionSoundURL(collisionSoundURLBefore, entity->getCollisionSoundURL());
     }

    // TODO: this final containingElement check should eventually be removed (or wrapped in an #ifdef DEBUG).
    containingElement = getContainingElement(entity->getEntityItemID());
    if (!containingElement) {
        qCDebug(entities) << "UNEXPECTED!!!! after updateEntity() we no longer have a containing element??? entityID="
                << entity->getEntityItemID();
        return false;
    }

    return true;
}
Beispiel #7
0
bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityItemProperties& origProperties, 
                                         EntityTreeElement* containingElement, const SharedNodePointer& senderNode) {
    EntityItemProperties properties = origProperties;

    bool allowLockChange;
    QUuid senderID;
    if (senderNode.isNull()) {
        auto nodeList = DependencyManager::get<NodeList>();
        allowLockChange = nodeList->getThisNodeCanAdjustLocks();
        senderID = nodeList->getSessionUUID();
    } else {
        allowLockChange = senderNode->getCanAdjustLocks();
        senderID = senderNode->getUUID();
    }

    if (!allowLockChange && (entity->getLocked() != properties.getLocked())) {
        qCDebug(entities) << "Refusing disallowed lock adjustment.";
        return false;
    }

    // enforce support for locked entities. If an entity is currently locked, then the only
    // property we allow you to change is the locked property.
    if (entity->getLocked()) {
        if (properties.lockedChanged()) {
            bool wantsLocked = properties.getLocked();
            if (!wantsLocked) {
                EntityItemProperties tempProperties;
                tempProperties.setLocked(wantsLocked);
                UpdateEntityOperator theOperator(this, containingElement, entity, tempProperties);
                recurseTreeWithOperator(&theOperator);
                _isDirty = true;
            }
        }
    } else {
        if (getIsServer()) {
            bool simulationBlocked = !entity->getSimulatorID().isNull();
            if (properties.simulatorIDChanged()) {
                QUuid submittedID = properties.getSimulatorID();
                // a legit interface will only submit their own ID or NULL:
                if (submittedID.isNull()) {
                    if (entity->getSimulatorID() == senderID) {
                        // We only allow the simulation owner to clear their own simulationID's.
                        simulationBlocked = false;
                    }
                    // else: We assume the sender really did believe it was the simulation owner when it sent
                } else if (submittedID == senderID) {
                    // the sender is trying to take or continue ownership
                    if (entity->getSimulatorID().isNull() || entity->getSimulatorID() == senderID) {
                        simulationBlocked = false;
                    } else {
                        // the sender is trying to steal ownership from another simulator
                        // so we apply the ownership change filter
                        if (usecTimestampNow() - entity->getSimulatorIDChangedTime() > SIMULATOR_CHANGE_LOCKOUT_PERIOD) {
                            simulationBlocked = false;
                        }
                    }
                } else {
                    // the entire update is suspect --> ignore it
                    return false;
                }
            }
            if (simulationBlocked) {
                // squash the physics-related changes.
                properties.setSimulatorIDChanged(false);
                properties.setPositionChanged(false);
                properties.setRotationChanged(false);
            }
        }
        // else client accepts what the server says

        QString entityScriptBefore = entity->getScript();
        QString collisionSoundURLBefore = entity->getCollisionSoundURL();
        uint32_t preFlags = entity->getDirtyFlags();
        UpdateEntityOperator theOperator(this, containingElement, entity, properties);
        recurseTreeWithOperator(&theOperator);
        _isDirty = true;

        uint32_t newFlags = entity->getDirtyFlags() & ~preFlags;
        if (newFlags) {
            if (_simulation) {
                if (newFlags & DIRTY_SIMULATION_FLAGS) {
                    _simulation->lock();
                    _simulation->changeEntity(entity);
                    _simulation->unlock();
                }
            } else {
                // normally the _simulation clears ALL updateFlags, but since there is none we do it explicitly
                entity->clearDirtyFlags();
            }
        }
        
        QString entityScriptAfter = entity->getScript();
        if (entityScriptBefore != entityScriptAfter) {
            emitEntityScriptChanging(entity->getEntityItemID()); // the entity script has changed
        }
        maybeNotifyNewCollisionSoundURL(collisionSoundURLBefore, entity->getCollisionSoundURL());
     }
    
    // TODO: this final containingElement check should eventually be removed (or wrapped in an #ifdef DEBUG).
    containingElement = getContainingElement(entity->getEntityItemID());
    if (!containingElement) {
        qCDebug(entities) << "UNEXPECTED!!!! after updateEntity() we no longer have a containing element??? entityID=" 
                << entity->getEntityItemID();
        return false;
    }
    
    return true;
}