Пример #1
0
int EntityServer::sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) {
    int totalBytes = 0;

    EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
    if (nodeData) {
        quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
        quint64 deletePacketSentAt = usecTimestampNow();

        EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
        bool hasMoreToSend = true;

        packetsSent = 0;

        while (hasMoreToSend) {
            auto specialPacket = tree->encodeEntitiesDeletedSince(queryNode->getSequenceNumber(), deletedEntitiesSentAt,
                                                                  hasMoreToSend);

            queryNode->packetSent(*specialPacket);

            totalBytes += specialPacket->getDataSize();
            packetsSent++;

            DependencyManager::get<NodeList>()->sendPacket(std::move(specialPacket), *node);
        }

        nodeData->setLastDeletedEntitiesSentAt(deletePacketSentAt);
    }

    // TODO: caller is expecting a packetLength, what if we send more than one packet??
    return totalBytes;
}
Пример #2
0
void OctreeTests::elementAddChildTests() {
    EntityTreePointer tree = std::make_shared<EntityTree>();
    auto elem = tree->createNewElement();
    QCOMPARE((bool)elem->getChildAtIndex(0), false);
    elem->addChildAtIndex(0);
    QCOMPARE((bool)elem->getChildAtIndex(0), true);

    const int MAX_CHILD_INDEX = 8;
    for (int i = 0; i < MAX_CHILD_INDEX; i++) {
        for (int j = 0; j < MAX_CHILD_INDEX; j++) {
            auto e = tree->createNewElement();

            // add a single child.
            auto firstChild = e->addChildAtIndex(i);
            QCOMPARE(e->getChildAtIndex(i), firstChild);

            if (i != j) {
                // add a second child.
                auto secondChild = e->addChildAtIndex(j);
                QCOMPARE(e->getChildAtIndex(i), firstChild);
                QCOMPARE(e->getChildAtIndex(j), secondChild);

                // remove scecond child.
                e->removeChildAtIndex(j);

                QCOMPARE((bool)e->getChildAtIndex(j), false);
            }

            QCOMPARE(e->getChildAtIndex(i), firstChild);
        }
    }
}
Пример #3
0
void AvatarManager::removeDeadAvatarEntities(const SetOfEntities& deadEntities) {
    auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
    EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
    for (auto entity : deadEntities) {
        QUuid entityOwnerID = entity->getOwningAvatarID();
        AvatarSharedPointer avatar = getAvatarBySessionID(entityOwnerID);
        const bool REQUIRES_REMOVAL_FROM_TREE = false;
        if (avatar) {
            avatar->clearAvatarEntity(entity->getID(), REQUIRES_REMOVAL_FROM_TREE);
        }
        if (entityTree && entity->isMyAvatarEntity()) {
            entityTree->withWriteLock([&] {
                // We only need to delete the direct children (rather than the descendants) because
                // when the child is deleted, it will take care of its own children.  If the child
                // is also an avatar-entity, we'll end up back here.  If it's not, the entity-server
                // will take care of it in the usual way.
                entity->forEachChild([&](SpatiallyNestablePointer child) {
                    EntityItemPointer childEntity = std::dynamic_pointer_cast<EntityItem>(child);
                    if (childEntity) {
                        entityTree->deleteEntity(childEntity->getID(), true, true);
                        if (avatar) {
                            avatar->clearAvatarEntity(childEntity->getID(), REQUIRES_REMOVAL_FROM_TREE);
                        }
                    }
                });
            });
        }
    }
}
void EntityTreeHeadlessViewer::update() {
    if (_tree) {
        EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
        tree->withTryWriteLock([&] {
            tree->update();
        });
    }
}
Пример #5
0
EntityServer::~EntityServer() {
    if (_pruneDeletedEntitiesTimer) {
        _pruneDeletedEntitiesTimer->stop();
        _pruneDeletedEntitiesTimer->deleteLater();
    }

    EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
    tree->removeNewlyCreatedHook(this);
}
void EntityTreeHeadlessViewer::init() {
    OctreeHeadlessViewer::init();
    if (!_simulation) {
        SimpleEntitySimulationPointer simpleSimulation { new SimpleEntitySimulation() };
        EntityTreePointer entityTree = std::static_pointer_cast<EntityTree>(_tree);
        simpleSimulation->setEntityTree(entityTree);
        entityTree->setSimulation(simpleSimulation);
        _simulation = simpleSimulation;
    }
}
Пример #7
0
bool EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectionObject) {
    bool wantEditLogging = false;
    readOptionBool(QString("wantEditLogging"), settingsSectionObject, wantEditLogging);
    qDebug("wantEditLogging=%s", debug::valueOf(wantEditLogging));


    EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
    tree->setWantEditLogging(wantEditLogging);

    return true;
}
Пример #8
0
void addAvatarEntities(const QVariantList& avatarEntities) {
    auto nodeList = DependencyManager::get<NodeList>();
    const QUuid myNodeID = nodeList->getSessionUUID();
    EntityTreePointer entityTree = DependencyManager::get<EntityTreeRenderer>()->getTree();
    if (!entityTree) {
        return;
    }
    EntitySimulationPointer entitySimulation = entityTree->getSimulation();
    PhysicalEntitySimulationPointer physicalEntitySimulation = std::static_pointer_cast<PhysicalEntitySimulation>(entitySimulation);
    EntityEditPacketSender* entityPacketSender = physicalEntitySimulation->getPacketSender();
    QScriptEngine scriptEngine;
    for (int index = 0; index < avatarEntities.count(); index++) {
        const QVariantMap& avatarEntityProperties = avatarEntities.at(index).toMap();
        QVariant variantProperties = avatarEntityProperties["properties"];
        QVariantMap asMap = variantProperties.toMap();
        QScriptValue scriptProperties = variantMapToScriptValue(asMap, scriptEngine);
        EntityItemProperties entityProperties;
        EntityItemPropertiesFromScriptValueHonorReadOnly(scriptProperties, entityProperties);

        entityProperties.setParentID(myNodeID);
        entityProperties.setClientOnly(true);
        entityProperties.setOwningAvatarID(myNodeID);
        entityProperties.setSimulationOwner(myNodeID, AVATAR_ENTITY_SIMULATION_PRIORITY);
        entityProperties.markAllChanged();

        EntityItemID id = EntityItemID(QUuid::createUuid());
        bool success = true;
        entityTree->withWriteLock([&] {
            EntityItemPointer entity = entityTree->addEntity(id, entityProperties);
            if (entity) {
                if (entityProperties.queryAACubeRelatedPropertyChanged()) {
                    // due to parenting, the server may not know where something is in world-space, so include the bounding cube.
                    bool success;
                    AACube queryAACube = entity->getQueryAACube(success);
                    if (success) {
                        entityProperties.setQueryAACube(queryAACube);
                    }
                }

                entity->setLastBroadcast(usecTimestampNow());
                // since we're creating this object we will immediately volunteer to own its simulation
                entity->flagForOwnershipBid(VOLUNTEER_SIMULATION_PRIORITY);
                entityProperties.setLastEdited(entity->getLastEdited());
            } else {
                qCDebug(entities) << "AvatarEntitiesBookmark failed to add new Entity to local Octree";
                success = false;
            }
        });

        if (success) {
            entityPacketSender->queueEditEntityMessage(PacketType::EntityAdd, entityTree, id, entityProperties);
        }
    }
}
Пример #9
0
void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
    auto currentCompoundShapeURL = getCompoundShapeURL();
    ModelEntityItem::setCompoundShapeURL(url);

    if (getCompoundShapeURL() != currentCompoundShapeURL || !_model) {
        EntityTreePointer tree = getTree();
        if (tree) {
            QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID()));
        }
    }
}
Пример #10
0
void RenderableModelEntityItem::setModelURL(const QString& url) {
    auto& currentURL = getParsedModelURL();
    ModelEntityItem::setModelURL(url);

    if (currentURL != getParsedModelURL() || !_model) {
        EntityTreePointer tree = getTree();
        if (tree) {
            QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID()));
        }
    }
}
Пример #11
0
OctreePointer EntityServer::createTree() {
    EntityTreePointer tree = EntityTreePointer(new EntityTree(true));
    tree->createRootElement();
    tree->addNewlyCreatedHook(this);
    if (!_entitySimulation) {
        SimpleEntitySimulation* simpleSimulation = new SimpleEntitySimulation();
        simpleSimulation->setEntityTree(tree);
        tree->setSimulation(simpleSimulation);
        _entitySimulation = simpleSimulation;
    }
    return tree;
}
Пример #12
0
EntityItemPointer ObjectDynamic::getEntityByID(EntityItemID entityID) const {
    EntityItemPointer ownerEntity;
    withReadLock([&]{
        ownerEntity = _ownerEntity.lock();
    });
    EntityTreeElementPointer element = ownerEntity ? ownerEntity->getElement() : nullptr;
    EntityTreePointer tree = element ? element->getTree() : nullptr;
    if (!tree) {
        return nullptr;
    }
    return tree->findEntityByID(entityID);
}
Пример #13
0
// EntityServer will use the "special packets" to send list of recently deleted entities
bool EntityServer::hasSpecialPacketsToSend(const SharedNodePointer& node) {
    bool shouldSendDeletedEntities = false;

    // check to see if any new entities have been added since we last sent to this node...
    EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
    if (nodeData) {
        quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();

        EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
        shouldSendDeletedEntities = tree->hasEntitiesDeletedSince(deletedEntitiesSentAt);
    }

    return shouldSendDeletedEntities;
}
Пример #14
0
OctreePointer EntityServer::createTree() {
    EntityTreePointer tree = EntityTreePointer(new EntityTree(true));
    tree->createRootElement();
    tree->addNewlyCreatedHook(this);
    if (!_entitySimulation) {
        SimpleEntitySimulationPointer simpleSimulation { new SimpleEntitySimulation() };
        simpleSimulation->setEntityTree(tree);
        tree->setSimulation(simpleSimulation);
        _entitySimulation = simpleSimulation;
    }

    DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
    DependencyManager::set<AssignmentParentFinder>(tree);

    return tree;
}
Пример #15
0
void EntityServer::pruneDeletedEntities() {
    EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
    if (tree->hasAnyDeletedEntities()) {

        quint64 earliestLastDeletedEntitiesSent = usecTimestampNow() + 1; // in the future
        DependencyManager::get<NodeList>()->eachNode([&earliestLastDeletedEntitiesSent](const SharedNodePointer& node) {
            if (node->getLinkedData()) {
                EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
                quint64 nodeLastDeletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
                if (nodeLastDeletedEntitiesSentAt < earliestLastDeletedEntitiesSent) {
                    earliestLastDeletedEntitiesSent = nodeLastDeletedEntitiesSentAt;
                }
            }
        });
        tree->forgetEntitiesDeletedBefore(earliestLastDeletedEntitiesSent);
    }
}
Пример #16
0
SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID, bool& success, SpatialParentTree* entityTree) const {
    SpatiallyNestableWeakPointer parent;

    if (parentID.isNull()) {
        success = true;
        return parent;
    }

    // search entities
    if (entityTree) {
        parent = entityTree->findByID(parentID);
    } else {
        auto treeRenderer = qApp->getEntities();
        EntityTreePointer tree = treeRenderer ? treeRenderer->getTree() : nullptr;
        parent = tree ? tree->findEntityByEntityItemID(parentID) : nullptr;
    }
    if (!parent.expired()) {
        success = true;
        return parent;
    }

    // search avatars
    QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();
    parent = avatarManager->getAvatarBySessionID(parentID);
    if (!parent.expired()) {
        success = true;
        return parent;
    }
    if (parentID == AVATAR_SELF_ID) {
        success = true;
        return avatarManager->getMyAvatar();
    }

    // search overlays
    auto& overlays = qApp->getOverlays();
    auto overlay = overlays.getOverlay(parentID);
    parent = std::dynamic_pointer_cast<SpatiallyNestable>(overlay); // this will return nullptr for non-3d overlays
    if (!parent.expired()) {
        success = true;
        return parent;
    }

    success = false;
    return parent;
}
Пример #17
0
// EntityServer will use the "special packets" to send list of recently deleted entities
bool EntityServer::hasSpecialPacketsToSend(const SharedNodePointer& node) {
    bool shouldSendDeletedEntities = false;

    // check to see if any new entities have been added since we last sent to this node...
    EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
    if (nodeData) {
        quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
        EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
        shouldSendDeletedEntities = tree->hasEntitiesDeletedSince(deletedEntitiesSentAt);

        #ifdef EXTRA_ERASE_DEBUGGING
            if (shouldSendDeletedEntities) {
                int elapsed = usecTimestampNow() - deletedEntitiesSentAt;
                qDebug() << "shouldSendDeletedEntities to node:" << node->getUUID() << "deletedEntitiesSentAt:" << deletedEntitiesSentAt << "elapsed:" << elapsed;
            }
        #endif
    }

    return shouldSendDeletedEntities;
}
Пример #18
0
bool RenderableModelEntityItem::isReadyToComputeShape() {
    ShapeType type = getShapeType();

    if (type == SHAPE_TYPE_COMPOUND) {
        if (!_model || _model->getCollisionURL().isEmpty()) {
            EntityTreePointer tree = getTree();
            if (tree) {
                QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID()));
            }
            return false;
        }

        if (_model->getURL().isEmpty()) {
            // we need a render geometry with a scale to proceed, so give up.
            return false;
        }

        const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
        const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();

        if ((collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) &&
            (renderNetworkGeometry && renderNetworkGeometry->isLoaded())) {
            // we have both URLs AND both geometries AND they are both fully loaded.

            if (_needsInitialSimulation) {
                // the _model's offset will be wrong until _needsInitialSimulation is false
                PerformanceTimer perfTimer("_model->simulate");
                _model->simulate(0.0f);
                _needsInitialSimulation = false;
            }

            return true;
        }

        // the model is still being downloaded.
        return false;
    }
    return true;
}
Пример #19
0
void EntityEditPacketSender::queueEditAvatarEntityMessage(PacketType type,
        EntityTreePointer entityTree,
        EntityItemID entityItemID,
        const EntityItemProperties& properties) {
    if (!_shouldSend) {
        return; // bail early
    }

    if (properties.getOwningAvatarID() != _myAvatar->getID()) {
        return; // don't send updates for someone else's avatarEntity
    }

    assert(properties.getClientOnly());

    // this is an avatar-based entity.  update our avatar-data rather than sending to the entity-server
    assert(_myAvatar);

    if (!entityTree) {
        qCDebug(entities) << "EntityEditPacketSender::queueEditEntityMessage null entityTree.";
        return;
    }
    EntityItemPointer entity = entityTree->findEntityByEntityItemID(entityItemID);
    if (!entity) {
        qCDebug(entities) << "EntityEditPacketSender::queueEditEntityMessage can't find entity.";
        return;
    }

    // the properties that get serialized into the avatar identity packet should be the entire set
    // rather than just the ones being edited.
    EntityItemProperties entityProperties = entity->getProperties();
    entityProperties.merge(properties);

    QScriptValue scriptProperties = EntityItemNonDefaultPropertiesToScriptValue(&_scriptEngine, entityProperties);
    QVariant variantProperties = scriptProperties.toVariant();
    QJsonDocument jsonProperties = QJsonDocument::fromVariant(variantProperties);

    // the ID of the parent/avatar changes from session to session.  use a special UUID to indicate the avatar
    QJsonObject jsonObject = jsonProperties.object();
    if (QUuid(jsonObject["parentID"].toString()) == _myAvatar->getID()) {
        jsonObject["parentID"] = AVATAR_SELF_ID.toString();
    }
    jsonProperties = QJsonDocument(jsonObject);

    QByteArray binaryProperties = jsonProperties.toBinaryData();
    _myAvatar->updateAvatarEntity(entityItemID, binaryProperties);

    entity->setLastBroadcast(usecTimestampNow());
    return;
}
Пример #20
0
void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectionObject) {
    bool wantEditLogging = false;
    readOptionBool(QString("wantEditLogging"), settingsSectionObject, wantEditLogging);
    qDebug("wantEditLogging=%s", debug::valueOf(wantEditLogging));

    bool wantTerseEditLogging = false;
    readOptionBool(QString("wantTerseEditLogging"), settingsSectionObject, wantTerseEditLogging);
    qDebug("wantTerseEditLogging=%s", debug::valueOf(wantTerseEditLogging));

    EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);

    int maxTmpEntityLifetime;
    if (readOptionInt("maxTmpLifetime", settingsSectionObject, maxTmpEntityLifetime)) {
        tree->setEntityMaxTmpLifetime(maxTmpEntityLifetime);
    } else {
        tree->setEntityMaxTmpLifetime(EntityTree::DEFAULT_MAX_TMP_ENTITY_LIFETIME);
    }

    int minTime;
    if (readOptionInt("dynamicDomainVerificationTimeMin", settingsSectionObject, minTime)) {
        _MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = minTime * 1000;
    }

    int maxTime;
    if (readOptionInt("dynamicDomainVerificationTimeMax", settingsSectionObject, maxTime)) {
        _MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS = maxTime * 1000;
    }

    startDynamicDomainVerification();

    tree->setWantEditLogging(wantEditLogging);
    tree->setWantTerseEditLogging(wantTerseEditLogging);

    QString entityScriptSourceWhitelist;
    if (readOptionString("entityScriptSourceWhitelist", settingsSectionObject, entityScriptSourceWhitelist)) {
        tree->setEntityScriptSourceWhitelist(entityScriptSourceWhitelist);
    } else {
        tree->setEntityScriptSourceWhitelist("");
    }
    
    auto entityEditFilters = DependencyManager::get<EntityEditFilters>();
    
    QString filterURL;
    if (readOptionString("entityEditFilter", settingsSectionObject, filterURL) && !filterURL.isEmpty()) {
        // connect the filterAdded signal, and block edits until you hear back
        connect(entityEditFilters.data(), &EntityEditFilters::filterAdded, this, &EntityServer::entityFilterAdded);
        
        entityEditFilters->addFilter(EntityItemID(), filterURL);
    }
}
Пример #21
0
    SpatiallyNestableWeakPointer find(QUuid parentID, bool& success, SpatialParentTree* entityTree = nullptr) const override {
        SpatiallyNestableWeakPointer parent;

        if (parentID.isNull()) {
            success = true;
            return parent;
        }

        // search entities
        if (entityTree) {
            parent = entityTree->findByID(parentID);
        } else {
            parent = _tree ? _tree->findEntityByEntityItemID(parentID) : nullptr;
        }

        if (!parent.expired()) {
            success = true;
            return parent;
        }

        success = false;
        return parent;
    }
Пример #22
0
void OverlayPanel::applyTransformTo(Transform& transform, bool force) {
    if (force || usecTimestampNow() > _transformExpiry) {
        PanelAttachable::applyTransformTo(transform, true);
        if (!getParentPanel()) {
            if (_anchorPositionBindMyAvatar) {
                transform.setTranslation(DependencyManager::get<AvatarManager>()->getMyAvatar()
                                         ->getPosition());
            } else if (!_anchorPositionBindEntity.isNull()) {
                EntityTreePointer entityTree = DependencyManager::get<EntityScriptingInterface>()->getEntityTree();
                entityTree->withReadLock([&] {
                    EntityItemPointer foundEntity = entityTree->findEntityByID(_anchorPositionBindEntity);
                    if (foundEntity) {
                        transform.setTranslation(foundEntity->getPosition());
                    }
                });
            } else {
                transform.setTranslation(getAnchorPosition());
            }

            if (_anchorRotationBindMyAvatar) {
                transform.setRotation(DependencyManager::get<AvatarManager>()->getMyAvatar()
                                      ->getOrientation());
            } else if (!_anchorRotationBindEntity.isNull()) {
                EntityTreePointer entityTree = DependencyManager::get<EntityScriptingInterface>()->getEntityTree();
                entityTree->withReadLock([&] {
                    EntityItemPointer foundEntity = entityTree->findEntityByID(_anchorRotationBindEntity);
                    if (foundEntity) {
                        transform.setRotation(foundEntity->getRotation());
                    }
                });
            } else {
                transform.setRotation(getAnchorRotation());
            }

            transform.setScale(getAnchorScale());

            transform.postTranslate(getOffsetPosition());
            transform.postRotate(getOffsetRotation());
            transform.postScale(getOffsetScale());
        }
        pointTransformAtCamera(transform, getOffsetRotation());
    }
}
Пример #23
0
void EntityServer::startDynamicDomainVerification() {
    qCDebug(entities) << "Starting Dynamic Domain Verification...";

    QString thisDomainID = DependencyManager::get<AddressManager>()->getDomainID().remove(QRegExp("\\{|\\}"));

    EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
    QHash<QString, EntityItemID> localMap(tree->getEntityCertificateIDMap());

    QHashIterator<QString, EntityItemID> i(localMap);
    qCDebug(entities) << localMap.size() << "entities in _entityCertificateIDMap";
    while (i.hasNext()) {
        i.next();

        EntityItemPointer entity = tree->findEntityByEntityItemID(i.value());

        if (entity) {
            if (!entity->getProperties().verifyStaticCertificateProperties()) {
                qCDebug(entities) << "During Dynamic Domain Verification, a certified entity with ID" << i.value() << "failed"
                    << "static certificate verification.";
                // Delete the entity if it doesn't pass static certificate verification
                tree->deleteEntity(i.value(), true);
            } else {

                QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
                QNetworkRequest networkRequest;
                networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
                networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
                QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
                requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/location");
                QJsonObject request;
                request["certificate_id"] = i.key();
                networkRequest.setUrl(requestURL);

                QNetworkReply* networkReply = NULL;
                networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());

                connect(networkReply, &QNetworkReply::finished, [=]() {
                    QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
                    jsonObject = jsonObject["data"].toObject();

                    if (networkReply->error() == QNetworkReply::NoError) {
                        if (jsonObject["domain_id"].toString() != thisDomainID) {
                            qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString()
                                << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value();
                            tree->deleteEntity(i.value(), true);
                        } else {
                            qCDebug(entities) << "Entity passed dynamic domain verification:" << i.value();
                        }
                    } else {
                        qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; deleting entity" << i.value()
                            << "More info:" << jsonObject;
                        tree->deleteEntity(i.value(), true);
                    }

                    networkReply->deleteLater();
                });
            }
        } else {
            qCWarning(entities) << "During DDV, an entity with ID" << i.value() << "was NOT found in the Entity Tree!";
        }
    }

    int nextInterval = qrand() % ((_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS + 1) - _MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS) + _MINIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS;
    qCDebug(entities) << "Restarting Dynamic Domain Verification timer for" << nextInterval / 1000 << "seconds";
    _dynamicDomainVerificationTimer.start(nextInterval);
}
Пример #24
0
void EntityServer::nodeKilled(SharedNodePointer node) {
    EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
    tree->deleteDescendantsOfAvatar(node->getUUID());
    tree->forgetAvatarID(node->getUUID());
    OctreeServer::nodeKilled(node);
}
Пример #25
0
void EntityServer::nodeAdded(SharedNodePointer node) {
    EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
    tree->knowAvatarID(node->getUUID());
    OctreeServer::nodeAdded(node);
}
Пример #26
0
// FIXME - most of the old code for this was encapsulated in EntityTree, I liked that design from a data
// hiding and object oriented perspective. But that didn't really allow us to handle the case of lots
// of entities being deleted at the same time. I'd like to look to move this back into EntityTree but
// for now this works and addresses the bug.
int EntityServer::sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) {
    int totalBytes = 0;

    EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
    if (nodeData) {

        quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
        quint64 considerEntitiesSince = EntityTree::getAdjustedConsiderSince(deletedEntitiesSentAt);

        quint64 deletePacketSentAt = usecTimestampNow();
        EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
        auto recentlyDeleted = tree->getRecentlyDeletedEntityIDs();

        packetsSent = 0;

        // create a new special packet
        std::unique_ptr<NLPacket> deletesPacket = NLPacket::create(PacketType::EntityErase);

        // pack in flags
        OCTREE_PACKET_FLAGS flags = 0;
        deletesPacket->writePrimitive(flags);

        // pack in sequence number
        auto sequenceNumber = queryNode->getSequenceNumber();
        deletesPacket->writePrimitive(sequenceNumber);

        // pack in timestamp
        OCTREE_PACKET_SENT_TIME now = usecTimestampNow();
        deletesPacket->writePrimitive(now);

        // figure out where we are now and pack a temporary number of IDs
        uint16_t numberOfIDs = 0;
        qint64 numberOfIDsPos = deletesPacket->pos();
        deletesPacket->writePrimitive(numberOfIDs);

        // we keep a multi map of entity IDs to timestamps, we only want to include the entity IDs that have been
        // deleted since we last sent to this node
        auto it = recentlyDeleted.constBegin();
        while (it != recentlyDeleted.constEnd()) {

            // if the timestamp is more recent then out last sent time, include it
            if (it.key() > considerEntitiesSince) {

                // get all the IDs for this timestamp
                const auto& entityIDsFromTime = recentlyDeleted.values(it.key());

                for (const auto& entityID : entityIDsFromTime) {

                    // check to make sure we have room for one more ID, if we don't have more
                    // room, then send out this packet and create another one
                    if (NUM_BYTES_RFC4122_UUID > deletesPacket->bytesAvailableForWrite()) {

                        // replace the count for the number of included IDs
                        deletesPacket->seek(numberOfIDsPos);
                        deletesPacket->writePrimitive(numberOfIDs);

                        // Send the current packet
                        queryNode->packetSent(*deletesPacket);
                        auto thisPacketSize = deletesPacket->getDataSize();
                        totalBytes += thisPacketSize;
                        packetsSent++;
                        DependencyManager::get<NodeList>()->sendPacket(std::move(deletesPacket), *node);

                        #ifdef EXTRA_ERASE_DEBUGGING
                            qDebug() << "EntityServer::sendSpecialPackets() sending packet packetsSent[" << packetsSent << "] size:" << thisPacketSize;
                        #endif


                        // create another packet
                        deletesPacket = NLPacket::create(PacketType::EntityErase);

                        // pack in flags
                        deletesPacket->writePrimitive(flags);

                        // pack in sequence number
                        sequenceNumber = queryNode->getSequenceNumber();
                        deletesPacket->writePrimitive(sequenceNumber);

                        // pack in timestamp
                        deletesPacket->writePrimitive(now);

                        // figure out where we are now and pack a temporary number of IDs
                        numberOfIDs = 0;
                        numberOfIDsPos = deletesPacket->pos();
                        deletesPacket->writePrimitive(numberOfIDs);
                    }

                    // FIXME - we still seem to see cases where incorrect EntityIDs get sent from the server
                    // to the client. These were causing "lost" entities like flashlights and laser pointers
                    // now that we keep around some additional history of the erased entities and resend that
                    // history for a longer time window, these entities are not "lost". But we haven't yet
                    // found/fixed the underlying issue that caused bad UUIDs to be sent to some users.
                    deletesPacket->write(entityID.toRfc4122());
                    ++numberOfIDs;

                    #ifdef EXTRA_ERASE_DEBUGGING
                        qDebug() << "EntityTree::encodeEntitiesDeletedSince() including:" << entityID;
                    #endif
                } // end for (ids)

            } // end if (it.val > sinceLast)


            ++it;
        } // end while

        // replace the count for the number of included IDs
        deletesPacket->seek(numberOfIDsPos);
        deletesPacket->writePrimitive(numberOfIDs);

        // Send the current packet
        queryNode->packetSent(*deletesPacket);
        auto thisPacketSize = deletesPacket->getDataSize();
        totalBytes += thisPacketSize;
        packetsSent++;
        DependencyManager::get<NodeList>()->sendPacket(std::move(deletesPacket), *node);
        #ifdef EXTRA_ERASE_DEBUGGING
            qDebug() << "EntityServer::sendSpecialPackets() sending packet packetsSent[" << packetsSent << "] size:" << thisPacketSize;
        #endif

        nodeData->setLastDeletedEntitiesSentAt(deletePacketSentAt);
    }

    #ifdef EXTRA_ERASE_DEBUGGING
        if (packetsSent > 0) {
            qDebug() << "EntityServer::sendSpecialPackets() sent " << packetsSent << "special packets of " 
                        << totalBytes << " total bytes to node:" << node->getUUID();
        }
    #endif

    // TODO: caller is expecting a packetLength, what if we send more than one packet??
    return totalBytes;
}