void CBulletInfo::Update(const double dt)
{
    // check if the bullet is active
    if(getStatus() == true)
    {
        // Update the position of the bullet
        SetPosition(getPosition() + getDirection() * getSpeed() * static_cast<float>(dt));

        // Update the lifetime
        SetLifetime(getLifetime() - static_cast<float>(dt));

        // check if the lifetime is gone
        if(getLifetime() < 0)
        {
            SetStatus( false);
        }
    }
}
// VectorPuffParticle2D
//---------------------------------------------------------------------------
VectorPuffParticle2D::VectorPuffParticle2D(
    const fXYZ  &pos,
    const fXYZ  &direction,
    float        scaleMin,
    float        scaleRand,
    float        speedMin,
    float        speedRand,
    float        waitMin,
    float        waitRand,
    float        lifetimeMin,
    float        lifetimeRand,
    float        windScale) : WindParticle2D(pos, windScale)
{
    VectorPuffParticle2D::scaleMin  = scaleMin;
    VectorPuffParticle2D::scaleRand = scaleRand;
    VectorPuffParticle2D::isFarAway = isFarAway;

    wait     = ((float(rand()) / float(RAND_MAX)) * waitRand + waitMin);
    velocity = direction * ((float(rand()) / float(RAND_MAX)) * speedRand + speedMin);
    lifetime = getLifetime(lifetimeMin, lifetimeRand);

    waitTime = 0.0f;

} // end VectorPuffParticle2D::VectorPuffParticle2D
Exemplo n.º 3
0
bool Garage::shouldClose() {
    auto player = engine->getPlayer();
    auto plyChar = player->getCharacter();
    auto playerPosition = plyChar->getPosition();
    auto playerVehicle = plyChar->getCurrentVehicle();
    bool playerIsInVehicle = playerVehicle != nullptr;

    switch (type) {
        case Type::Mission: {
            if (!isObjectInsideGarage(static_cast<GameObject*>(plyChar)) &&
                isObjectInsideGarage(target) && !playerIsInVehicle &&
                getDistanceToGarage(playerPosition) >= 2.f) {
                return true;
            }

            return false;
        }

        case Type::BombShop1:
        case Type::BombShop2:
        case Type::BombShop3: {
            if (playerIsInVehicle) {
                if (isObjectInsideGarage(
                        static_cast<GameObject*>(playerVehicle)) &&
                    playerVehicle->isStopped()) {
                    return true;
                }
            }

            return false;
        }

        case Type::Respray: {
            if (playerIsInVehicle) {
                if (isObjectInsideGarage(
                        static_cast<GameObject*>(playerVehicle)) &&
                    playerVehicle->isStopped() && !resprayDone) {
                    return true;
                } else if (!isObjectInsideGarage(
                               static_cast<GameObject*>(playerVehicle)) &&
                           getDistanceToGarage(playerVehicle->getPosition()) >=
                               2.f &&
                           resprayDone) {
                    resprayDone = false;
                }
            }

            return false;
        }

        case Type::CollectCars1:
        case Type::CollectCars2: {
            if (playerIsInVehicle) {
                if (isObjectInsideGarage(
                        static_cast<GameObject*>(playerVehicle))) {
                    if (playerVehicle->getLifetime() !=
                        GameObject::MissionLifetime) {
                        return true;
                    } else {
                        // @todo show message "come back when youre not busy"
                    }
                }
            }

            return false;
        }

        case Type::MissionForCarToComeOut: {
            // @todo unimplemented
            return false;
        }

        case Type::Crusher: {
            // @todo unimplemented
            return false;
        }

        case Type::MissionKeepCar: {
            // @todo unimplemented
            return false;
        }

        case Type::Hideout1:
        case Type::Hideout2:
        case Type::Hideout3: {
            // Not sure about these values
            if ((!playerIsInVehicle &&
                 getDistanceToGarage(playerPosition) >= 5.f) ||
                (playerIsInVehicle &&
                 getDistanceToGarage(playerPosition) >= 10.f)) {
                return true;
            }

            return false;
        }

        case Type::MissionToOpenAndClose: {
            // @todo unimplemented
            return false;
        }

        case Type::MissionForSpecificCar: {
            // @todo unimplemented
            return false;
        }

        case Type::MissionKeepCarAndRemainClosed: {
            // @todo unimplemented
            return false;
        }

        default: { return false; }
    }

    return false;
}
Exemplo n.º 4
0
bool EntityItem::lifetimeHasExpired() const { 
    return isMortal() && (getAge() > getLifetime()); 
}
Exemplo n.º 5
0
void EntityItem::update(const quint64& updateTime) {
    bool wantDebug = false;
    
    if (_lastUpdated == 0) {
        _lastUpdated = updateTime;
    }

    float timeElapsed = (float)(updateTime - _lastUpdated) / (float)(USECS_PER_SECOND);

    if (wantDebug) {
        qDebug() << "********** EntityItem::update()";
        qDebug() << "    entity ID=" << getEntityItemID();
        qDebug() << "    updateTime=" << updateTime;
        qDebug() << "    _lastUpdated=" << _lastUpdated;
        qDebug() << "    timeElapsed=" << timeElapsed;
        qDebug() << "    hasVelocity=" << hasVelocity();
        qDebug() << "    hasGravity=" << hasGravity();
        qDebug() << "    isRestingOnSurface=" << isRestingOnSurface();
        qDebug() << "    hasAngularVelocity=" << hasAngularVelocity();
        qDebug() << "    getAngularVelocity=" << getAngularVelocity();
        qDebug() << "    isMortal=" << isMortal();
        qDebug() << "    getAge()=" << getAge();
        qDebug() << "    getLifetime()=" << getLifetime();


        if (hasVelocity() || (hasGravity() && !isRestingOnSurface())) {
            qDebug() << "    MOVING...=";
            qDebug() << "        hasVelocity=" << hasVelocity();
            qDebug() << "        hasGravity=" << hasGravity();
            qDebug() << "        isRestingOnSurface=" << isRestingOnSurface();
            qDebug() << "        hasAngularVelocity=" << hasAngularVelocity();
            qDebug() << "        getAngularVelocity=" << getAngularVelocity();
        }
        if (hasAngularVelocity()) {
            qDebug() << "    CHANGING...=";
            qDebug() << "        hasAngularVelocity=" << hasAngularVelocity();
            qDebug() << "        getAngularVelocity=" << getAngularVelocity();
        }
        if (isMortal()) {
            qDebug() << "    MORTAL...=";
            qDebug() << "        isMortal=" << isMortal();
            qDebug() << "        getAge()=" << getAge();
            qDebug() << "        getLifetime()=" << getLifetime();
        }
    }

    _lastUpdated = updateTime;

    if (wantDebug) {
        qDebug() << "     ********** EntityItem::update() .... SETTING _lastUpdated=" << _lastUpdated;
    }

    if (hasAngularVelocity()) {
        glm::quat rotation = getRotation();
        glm::vec3 angularVelocity = glm::radians(getAngularVelocity());
        float angularSpeed = glm::length(angularVelocity);
        
        if (angularSpeed < EPSILON_VELOCITY_LENGTH) {
            setAngularVelocity(NO_ANGULAR_VELOCITY);
        } else {
            float angle = timeElapsed * angularSpeed;
            glm::quat  dQ = glm::angleAxis(angle, glm::normalize(angularVelocity));
            rotation = dQ * rotation;
            setRotation(rotation);

            // handle damping for angular velocity
            if (getAngularDamping() > 0.0f) {
                glm::vec3 dampingResistance = getAngularVelocity() * getAngularDamping();
                glm::vec3 newAngularVelocity = getAngularVelocity() - (dampingResistance * timeElapsed);
                setAngularVelocity(newAngularVelocity);
                if (wantDebug) {        
                    qDebug() << "    getDamping():" << getDamping();
                    qDebug() << "    dampingResistance:" << dampingResistance;
                    qDebug() << "    newAngularVelocity:" << newAngularVelocity;
                }
            }
        }
    }

    if (hasVelocity() || hasGravity()) {
        glm::vec3 position = getPosition();
        glm::vec3 velocity = getVelocity();
        glm::vec3 newPosition = position + (velocity * timeElapsed);

        if (wantDebug) {        
            qDebug() << "  EntityItem::update()....";
            qDebug() << "    timeElapsed:" << timeElapsed;
            qDebug() << "    old AACube:" << getMaximumAACube();
            qDebug() << "    old position:" << position;
            qDebug() << "    old velocity:" << velocity;
            qDebug() << "    old getAABox:" << getAABox();
            qDebug() << "    getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity() * (float)TREE_SCALE << " in meters";
            qDebug() << "    newPosition:" << newPosition;
            qDebug() << "    glm::distance(newPosition, position):" << glm::distance(newPosition, position);
        }
        
        position = newPosition;

        // handle bounces off the ground... We bounce at the distance to the bottom of our entity
        if (position.y <= getDistanceToBottomOfEntity()) {
            velocity = velocity * glm::vec3(1,-1,1);

            // if we've slowed considerably, then just stop moving
            if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) {
                velocity = NO_VELOCITY;
            }
            
            position.y = getDistanceToBottomOfEntity();
        }

        // handle gravity....
        if (hasGravity() && !isRestingOnSurface()) {
            velocity += getGravity() * timeElapsed;
        }

        // handle resting on surface case, this is definitely a bit of a hack, and it only works on the
        // "ground" plane of the domain, but for now it
        if (hasGravity() && isRestingOnSurface()) {
            velocity.y = 0.0f;
            position.y = getDistanceToBottomOfEntity();
        }

        // handle damping for velocity
        glm::vec3 dampingResistance = velocity * getDamping();
        if (wantDebug) {        
            qDebug() << "    getDamping():" << getDamping();
            qDebug() << "    dampingResistance:" << dampingResistance;
            qDebug() << "    dampingResistance * timeElapsed:" << dampingResistance * timeElapsed;
        }
        velocity -= dampingResistance * timeElapsed;

        if (wantDebug) {        
            qDebug() << "    velocity AFTER dampingResistance:" << velocity;
            qDebug() << "    glm::length(velocity):" << glm::length(velocity);
            qDebug() << "    EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH;
        }
        
        // round velocity to zero if it's close enough...
        if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) {
            velocity = NO_VELOCITY;
        }

        setPosition(position); // this will automatically recalculate our collision shape
        setVelocity(velocity);
        
        if (wantDebug) {        
            qDebug() << "    new position:" << position;
            qDebug() << "    new velocity:" << velocity;
            qDebug() << "    new AACube:" << getMaximumAACube();
            qDebug() << "    old getAABox:" << getAABox();
        }
    }
}
Exemplo n.º 6
0
OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packetData, EncodeBitstreamParams& params, 
                                            EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData) const {
                                            
    // ALL this fits...
    //    object ID [16 bytes]
    //    ByteCountCoded(type code) [~1 byte]
    //    last edited [8 bytes]
    //    ByteCountCoded(last_edited to last_updated delta) [~1-8 bytes]
    //    PropertyFlags<>( everything ) [1-2 bytes]
    // ~27-35 bytes...
    
    OctreeElement::AppendState appendState = OctreeElement::COMPLETED; // assume the best

    // encode our ID as a byte count coded byte stream
    QByteArray encodedID = getID().toRfc4122();

    // encode our type as a byte count coded byte stream
    ByteCountCoded<quint32> typeCoder = getType();
    QByteArray encodedType = typeCoder;

    quint64 updateDelta = getLastUpdated() <= getLastEdited() ? 0 : getLastUpdated() - getLastEdited();
    ByteCountCoded<quint64> updateDeltaCoder = updateDelta;
    QByteArray encodedUpdateDelta = updateDeltaCoder;
    EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
    EntityPropertyFlags requestedProperties = getEntityProperties(params);
    EntityPropertyFlags propertiesDidntFit = requestedProperties;

    // If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item,
    // then our entityTreeElementExtraEncodeData should include data about which properties we need to append.
    if (entityTreeElementExtraEncodeData && entityTreeElementExtraEncodeData->entities.contains(getEntityItemID())) {
        requestedProperties = entityTreeElementExtraEncodeData->entities.value(getEntityItemID());
    }

    LevelDetails entityLevel = packetData->startLevel();

    quint64 lastEdited = getLastEdited();

    const bool wantDebug = false;
    if (wantDebug) {
        float editedAgo = getEditedAgo();
        QString agoAsString = formatSecondsElapsed(editedAgo);
        qDebug() << "Writing entity " << getEntityItemID() << " to buffer, lastEdited =" << lastEdited 
                        << " ago=" << editedAgo << "seconds - " << agoAsString;
    }

    bool successIDFits = false;
    bool successTypeFits = false;
    bool successCreatedFits = false;
    bool successLastEditedFits = false;
    bool successLastUpdatedFits = false;
    bool successPropertyFlagsFits = false;
    int propertyFlagsOffset = 0;
    int oldPropertyFlagsLength = 0;
    QByteArray encodedPropertyFlags;
    int propertyCount = 0;

    successIDFits = packetData->appendValue(encodedID);
    if (successIDFits) {
        successTypeFits = packetData->appendValue(encodedType);
    }
    if (successTypeFits) {
        successCreatedFits = packetData->appendValue(_created);
    }
    if (successCreatedFits) {
        successLastEditedFits = packetData->appendValue(lastEdited);
    }
    if (successLastEditedFits) {
        successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
    }
    
    if (successLastUpdatedFits) {
        propertyFlagsOffset = packetData->getUncompressedByteOffset();
        encodedPropertyFlags = propertyFlags;
        oldPropertyFlagsLength = encodedPropertyFlags.length();
        successPropertyFlagsFits = packetData->appendValue(encodedPropertyFlags);
    }

    bool headerFits = successIDFits && successTypeFits && successCreatedFits && successLastEditedFits 
                              && successLastUpdatedFits && successPropertyFlagsFits;

    int startOfEntityItemData = packetData->getUncompressedByteOffset();

    if (headerFits) {
        bool successPropertyFits;

        propertyFlags -= PROP_LAST_ITEM; // clear the last item for now, we may or may not set it as the actual item

        // These items would go here once supported....
        //      PROP_PAGED_PROPERTY,
        //      PROP_CUSTOM_PROPERTIES_INCLUDED,

        APPEND_ENTITY_PROPERTY(PROP_POSITION, appendPosition, getPosition());
        APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, appendValue, getDimensions()); // NOTE: PROP_RADIUS obsolete

        if (wantDebug) {
            qDebug() << "    APPEND_ENTITY_PROPERTY() PROP_DIMENSIONS:" << getDimensions();
        }

        APPEND_ENTITY_PROPERTY(PROP_ROTATION, appendValue, getRotation());
        APPEND_ENTITY_PROPERTY(PROP_MASS, appendValue, getMass());
        APPEND_ENTITY_PROPERTY(PROP_VELOCITY, appendValue, getVelocity());
        APPEND_ENTITY_PROPERTY(PROP_GRAVITY, appendValue, getGravity());
        APPEND_ENTITY_PROPERTY(PROP_DAMPING, appendValue, getDamping());
        APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, getLifetime());
        APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, getScript());
        APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, getRegistrationPoint());
        APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, getAngularVelocity());
        APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, appendValue, getAngularDamping());
        APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, getVisible());
        APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, getIgnoreForCollisions());
        APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, getCollisionsWillMove());

        appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
                                requestedProperties,
                                propertyFlags,
                                propertiesDidntFit,
                                propertyCount,
                                appendState);
    }

    if (propertyCount > 0) {
        int endOfEntityItemData = packetData->getUncompressedByteOffset();
        encodedPropertyFlags = propertyFlags;
        int newPropertyFlagsLength = encodedPropertyFlags.length();
        packetData->updatePriorBytes(propertyFlagsOffset, 
                (const unsigned char*)encodedPropertyFlags.constData(), encodedPropertyFlags.length());
        
        // if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet.
        if (newPropertyFlagsLength < oldPropertyFlagsLength) {
            int oldSize = packetData->getUncompressedSize();
            const unsigned char* modelItemData = packetData->getUncompressedData(propertyFlagsOffset + oldPropertyFlagsLength);
            int modelItemDataLength = endOfEntityItemData - startOfEntityItemData;
            int newEntityItemDataStart = propertyFlagsOffset + newPropertyFlagsLength;
            packetData->updatePriorBytes(newEntityItemDataStart, modelItemData, modelItemDataLength);
            int newSize = oldSize - (oldPropertyFlagsLength - newPropertyFlagsLength);
            packetData->setUncompressedSize(newSize);

        } else {
            assert(newPropertyFlagsLength == oldPropertyFlagsLength); // should not have grown
        }
       
        packetData->endLevel(entityLevel);
    } else {
        packetData->discardLevel(entityLevel);
        appendState = OctreeElement::NONE; // if we got here, then we didn't include the item
    }
    
    // If any part of the model items didn't fit, then the element is considered partial
    if (appendState != OctreeElement::COMPLETED) {
        // add this item into our list for the next appendElementData() pass
        entityTreeElementExtraEncodeData->entities.insert(getEntityItemID(), propertiesDidntFit);
    }

    return appendState;
}
Exemplo n.º 7
0
void ExternalLoader::reloadAndUpdate(bool throw_on_error)
{
    reloadFromConfigFiles(throw_on_error);

    /// list of recreated loadable objects to perform delayed removal from unordered_map
    std::list<std::string> recreated_failed_loadable_objects;

    std::unique_lock<std::mutex> all_lock(all_mutex);

    /// retry loading failed loadable objects
    for (auto & failed_loadable_object : failed_loadable_objects)
    {
        if (std::chrono::system_clock::now() < failed_loadable_object.second.next_attempt_time)
            continue;

        const auto & name = failed_loadable_object.first;

        try
        {
            auto loadable_ptr = failed_loadable_object.second.loadable->clone();
            if (const auto exception_ptr = loadable_ptr->getCreationException())
            {
                /// recalculate next attempt time
                std::uniform_int_distribution<UInt64> distribution(
                        0, static_cast<UInt64>(std::exp2(failed_loadable_object.second.error_count)));

                std::chrono::seconds delay(std::min<UInt64>(
                        update_settings.backoff_max_sec,
                        update_settings.backoff_initial_sec + distribution(rnd_engine)));
                failed_loadable_object.second.next_attempt_time = std::chrono::system_clock::now() + delay;

                ++failed_loadable_object.second.error_count;

                std::rethrow_exception(exception_ptr);
            }
            else
            {
                const std::lock_guard<std::mutex> lock{map_mutex};

                const auto & lifetime = loadable_ptr->getLifetime();
                std::uniform_int_distribution<UInt64> distribution{lifetime.min_sec, lifetime.max_sec};
                update_times[name] = std::chrono::system_clock::now() + std::chrono::seconds{distribution(rnd_engine)};

                const auto dict_it = loadable_objects.find(name);

                dict_it->second.loadable.reset();
                dict_it->second.loadable = std::move(loadable_ptr);

                /// clear stored exception on success
                dict_it->second.exception = std::exception_ptr{};

                recreated_failed_loadable_objects.push_back(name);
            }
        }
        catch (...)
        {
            tryLogCurrentException(log, "Failed reloading '" + name + "' " + object_name);

            if (throw_on_error)
                throw;
        }
    }

    /// do not undertake further attempts to recreate these loadable objects
    for (const auto & name : recreated_failed_loadable_objects)
        failed_loadable_objects.erase(name);

    /// periodic update
    for (auto & loadable_object : loadable_objects)
    {
        const auto & name = loadable_object.first;

        try
        {
            /// If the loadable objects failed to load or even failed to initialize from the config.
            if (!loadable_object.second.loadable)
                continue;

            auto current = loadable_object.second.loadable;
            const auto & lifetime = current->getLifetime();

            /// do not update loadable objects with zero as lifetime
            if (lifetime.min_sec == 0 || lifetime.max_sec == 0)
                continue;

            if (current->supportUpdates())
            {
                auto & update_time = update_times[current->getName()];

                /// check that timeout has passed
                if (std::chrono::system_clock::now() < update_time)
                    continue;

                SCOPE_EXIT({
                        /// calculate next update time
                        std::uniform_int_distribution<UInt64> distribution{lifetime.min_sec, lifetime.max_sec};
                        update_time = std::chrono::system_clock::now() + std::chrono::seconds{distribution(rnd_engine)};
                           });

                /// check source modified
                if (current->isModified())
                {
                    /// create new version of loadable object
                    auto new_version = current->clone();

                    if (const auto exception_ptr = new_version->getCreationException())
                        std::rethrow_exception(exception_ptr);

                    loadable_object.second.loadable.reset();
                    loadable_object.second.loadable = std::move(new_version);
                }
            }

            /// erase stored exception on success
            loadable_object.second.exception = std::exception_ptr{};
        }
Exemplo n.º 8
0
void ExternalDictionaries::reloadImpl(const bool throw_on_error)
{
    const auto config_paths = getDictionariesConfigPaths(Poco::Util::Application::instance().config());

    for (const auto & config_path : config_paths)
    {
        try
        {
            reloadFromFile(config_path, throw_on_error);
        }
        catch (...)
        {
            tryLogCurrentException(log, "reloadFromFile has thrown while reading from " + config_path);

            if (throw_on_error)
                throw;
        }
    }

    /// list of recreated dictionaries to perform delayed removal from unordered_map
    std::list<std::string> recreated_failed_dictionaries;

    /// retry loading failed dictionaries
    for (auto & failed_dictionary : failed_dictionaries)
    {
        if (std::chrono::system_clock::now() < failed_dictionary.second.next_attempt_time)
            continue;

        const auto & name = failed_dictionary.first;

        try
        {
            auto dict_ptr = failed_dictionary.second.dict->clone();
            if (const auto exception_ptr = dict_ptr->getCreationException())
            {
                /// recalculate next attempt time
                std::uniform_int_distribution<UInt64> distribution(
                    0, std::exp2(failed_dictionary.second.error_count));

                failed_dictionary.second.next_attempt_time = std::chrono::system_clock::now() +
                    std::chrono::seconds{
                        std::min<UInt64>(backoff_max_sec, backoff_initial_sec + distribution(rnd_engine))};

                ++failed_dictionary.second.error_count;

                std::rethrow_exception(exception_ptr);
            }
            else
            {
                const std::lock_guard<std::mutex> lock{dictionaries_mutex};

                const auto & lifetime = dict_ptr->getLifetime();
                std::uniform_int_distribution<UInt64> distribution{lifetime.min_sec, lifetime.max_sec};
                update_times[name] = std::chrono::system_clock::now() + std::chrono::seconds{distribution(rnd_engine)};

                const auto dict_it = dictionaries.find(name);
                if (dict_it->second.dict)
                    dict_it->second.dict->set(dict_ptr.release());
                else
                    dict_it->second.dict = std::make_shared<MultiVersion<IDictionaryBase>>(dict_ptr.release());

                /// erase stored exception on success
                dict_it->second.exception = std::exception_ptr{};

                recreated_failed_dictionaries.push_back(name);
            }
        }
        catch (...)
        {
            tryLogCurrentException(log, "Failed reloading '" + name + "' dictionary");

            if (throw_on_error)
                throw;
        }
    }

    /// do not undertake further attempts to recreate these dictionaries
    for (const auto & name : recreated_failed_dictionaries)
        failed_dictionaries.erase(name);

    /// periodic update
    for (auto & dictionary : dictionaries)
    {
        const auto & name = dictionary.first;

        try
        {
            /// If the dictionary failed to load or even failed to initialize from the config.
            if (!dictionary.second.dict)
                continue;

            auto current = dictionary.second.dict->get();
            const auto & lifetime = current->getLifetime();

            /// do not update dictionaries with zero as lifetime
            if (lifetime.min_sec == 0 || lifetime.max_sec == 0)
                continue;

            /// update only non-cached dictionaries
            if (!current->isCached())
            {
                auto & update_time = update_times[current->getName()];

                /// check that timeout has passed
                if (std::chrono::system_clock::now() < update_time)
                    continue;

                SCOPE_EXIT({
                    /// calculate next update time
                    std::uniform_int_distribution<UInt64> distribution{lifetime.min_sec, lifetime.max_sec};
                    update_time = std::chrono::system_clock::now() + std::chrono::seconds{distribution(rnd_engine)};
                });

                /// check source modified
                if (current->getSource()->isModified())
                {
                    /// create new version of dictionary
                    auto new_version = current->clone();

                    if (const auto exception_ptr = new_version->getCreationException())
                        std::rethrow_exception(exception_ptr);

                    dictionary.second.dict->set(new_version.release());
                }
            }

            /// erase stored exception on success
            dictionary.second.exception = std::exception_ptr{};
        }