/** * Handler for all exercise objects * $Id$ * $HeadURL$ * $Author$ * Created by Hanna E. Rathje, SLSE, 2015-09-03 */ #include "handler_effect_show.h" #include "handler_ppm_data.h" #include "handler_tab_data.h" #include "handler_mdm_data.h" #include "object_effect_show.h" #include "effect_show_explosion_area.h" #include "effect_show_explosion_cluster.h" #include "effect_show_effect_cluster.h" #include "effect_show_mine_area.h" #include "initialization.h" #include #include namespace EffectShowManagement { //============================================================================= HandlerEffectShow::HandlerEffectShow(Initialization *mainHandler, QObject *parent) : QObject(parent) , EffectShowModifyRequestHandler(mainHandler->dds()->fts()) , EffectShowRemoveRequestHandler(mainHandler->dds()->fts()) , m_cleanupTimer(new QTimer(this)) , m_timerMeteoData(new QTimer(this)) , m_mainHandler(mainHandler) , m_logger(getLogger("HandlerEffectShow")) {} // end of ctor() //============================================================================= HandlerEffectShow::~HandlerEffectShow() { qDeleteAll(m_effectShowObjMap); m_effectShowObjMap.clear(); } // end of dtor() //============================================================================= bool HandlerEffectShow::init() { bool bRet = true; // create Effect Show Objects auto cbEffectShow = [this, &bRet](const Database::EsmEffectShow & data) { ObjectEffectShow *ifs(new ObjectEffectShow(m_mainHandler, this)); Core::FunctionReplyObject ret = ifs->createObject(data); if (ret.error()) { delete ifs; ERROR_LOG(m_logger) << ret(); bRet = false; return; } m_effectShowObjMap.insert(ifs->getId(), ifs); }; if (!m_mainHandler->db()->select(cbEffectShow) || !bRet) { ERROR_LOG(m_logger) << "Error reading data from database 'esm_effect_show!"; return false; } // provision of timer for meteo data connect(m_timerMeteoData, &QTimer::timeout, this, &HandlerEffectShow::onSendMeteoData); m_timerMeteoData->start(HandlerEffectShow::meteoDataSendInterval); //cleanupTimer connect(m_cleanupTimer, &QTimer::timeout, this, &HandlerEffectShow::onCleanUp); m_cleanupTimer->start(CLEANUPTIME); //10 minutes DEBUG_LOG(m_logger) << "m_effectShowObjMap.size() = " << m_effectShowObjMap.size(); return true; } // end of init() //============================================================================= void HandlerEffectShow::onExplosionAreaChanged(const AreaEffectSimulation::ExplosionArea &data, KindOfModification_e kindOfModification) { INFO_LOG(m_logger) << "onExplosionAreaChanged: " << data << ", kindOfModification: " << enumToString(kindOfModification); switch (kindOfModification) { case KindOfModification_e::Added: createEffectShowsRelatedToExplosionArea(data); break; case KindOfModification_e::ModifiedArea: modifyEffectShowsRelatedToExplosionArea(data); break; case KindOfModification_e::ModifiedData: updateEffectShowsRelatedToExplosionArea(data); updateEffectShowOrdersRelatedToAes(data.id()); break; case KindOfModification_e::Removed: if(data.effectStateId() == AreaEffectSimulation::AesEffectState::EsRemoved) removeEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::Paused: updateEffectShowsRelatedToExplosionArea(data); updateEffectShowOrdersRelatedToAes(data.id()); //pauseEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::Continued: updateEffectShowsRelatedToExplosionArea(data); updateEffectShowOrdersRelatedToAes(data.id()); //continueEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::None: break; } } void HandlerEffectShow::onExplosionClusterChanged(const AreaEffectSimulation::ExplosionCluster &data, HandlerEffectShow::KindOfModification_e kindOfModification) { INFO_LOG(m_logger) << "onExplosionClusterChanged: " << data << ", kindOfModification: " << enumToString(kindOfModification); switch (kindOfModification) { case KindOfModification_e::Added: createEffectShowsRelatedToExplosionCluster(data); break; case KindOfModification_e::ModifiedArea: modifyEffectShowsRelatedToExplosionCluster(data); break; case KindOfModification_e::ModifiedData: updateEffectShowsRelatedToExplosionCluster(data); updateEffectShowOrdersRelatedToAes(data.id()); break; case KindOfModification_e::Removed: if(data.effectStateId() == AreaEffectSimulation::AesEffectState::EsRemoved) removeEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::Paused: updateEffectShowsRelatedToExplosionCluster(data); updateEffectShowOrdersRelatedToAes(data.id()); //pauseEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::Continued: updateEffectShowsRelatedToExplosionCluster(data); updateEffectShowOrdersRelatedToAes(data.id()); //continueEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::None: break; } } void HandlerEffectShow::onEffectClusterChanged(const AreaEffectSimulation::EffectCluster &data, KindOfModification_e kindOfModification) { INFO_LOG(m_logger) << "onEffectClusterChanged: " << data << ", kindOfModification: " << enumToString(kindOfModification); switch (kindOfModification) { case KindOfModification_e::Added: createEffectShowsRelatedToEffectCluster(data); break; case KindOfModification_e::ModifiedArea: modifyEffectShowsRelatedToEffectCluster(data); break; case KindOfModification_e::ModifiedData: updateEffectShowsRelatedToEffectCluster(data); updateEffectShowOrdersRelatedToAes(data.id()); break; case KindOfModification_e::Removed: if(data.effectStateId() == AreaEffectSimulation::AesEffectState::EsRemoved) removeEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::Paused: updateEffectShowsRelatedToEffectCluster(data); updateEffectShowOrdersRelatedToAes(data.id()); //pauseEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::Continued: updateEffectShowsRelatedToEffectCluster(data); updateEffectShowOrdersRelatedToAes(data.id()); //continueEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::None: break; } } // end of onExplosionClusterChanged() //============================================================================= void HandlerEffectShow::onMineAreaChanged(const AreaEffectSimulation::MineArea &data, KindOfModification_e kindOfModification) { INFO_LOG(m_logger) << "onMineAreaChanged: " << data << ", kindOfModification: " << enumToString(kindOfModification); switch (kindOfModification) { case KindOfModification_e::Added: createEffectShowsRelatedToMineArea(data); break; case KindOfModification_e::ModifiedArea: modifyEffectShowsRelatedToMineArea(data); break; case KindOfModification_e::ModifiedData: updateEffectShowsRelatedToMineArea(data); updateEffectShowOrdersRelatedToAes(data.id()); break; case KindOfModification_e::Removed: if(data.effectStateId() == AreaEffectSimulation::AesEffectState::EsRemoved) removeEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::Paused: updateEffectShowsRelatedToMineArea(data); updateEffectShowOrdersRelatedToAes(data.id()); // pauseEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::Continued: updateEffectShowsRelatedToMineArea(data); updateEffectShowOrdersRelatedToAes(data.id()); //continueEffectShowsRelatedToAes(data.id()); break; case KindOfModification_e::None: break; } } // end of onMineAreaChanged() //============================================================================= void HandlerEffectShow::effectShowOrderConfirmationReceived(const ConvertFromTab::OrderConfirmation_t &orderConfirmation) { DEBUG_LOG(m_logger) << "onEffectShowConfirmationReceived()"; ObjectEffectShow *ifs = m_effectShowObjMap.value(orderConfirmation.orderId); if (ifs == nullptr) { WARNING_LOG(m_logger) << "Error receiving effect show ID not known: " << orderConfirmation.orderId; return; } const auto oldId = ifs->getData().orderConfirmation; // add confirmation data ifs->updateObject(orderConfirmation); if (oldId != ifs->getData().orderConfirmation && ifs->getData().orderConfirmation == EffectShowManagement::OrderConfirmation_e::FiringReadiness) { DEBUG_LOG(m_logger) << "effectShowOrderConfirmationReceived Got Fire Readyness, send to aes for " << ifs->getId(); AreaEffectSimulation::SetAesItemEffectorStateRequest req; req.aesId(ifs->getIdAES()); req.newEffectorState(AreaEffectSimulation::AesEffectorState::EsReadyToFire); req.participantId(ifs->getData().esmParticipantId); m_mainHandler->dds()->ftcAes()->setAesItemEffectorStateRequest(req, this); } switch (orderConfirmation.confirmation.underlying()) { case EffectShowManagement::OrderConfirmation_e_def::DriveOff: case EffectShowManagement::OrderConfirmation_e_def::FiringReadiness: case EffectShowManagement::OrderConfirmation_e_def::InterruptExecution: case EffectShowManagement::OrderConfirmation_e_def::PositionReached: { triggerMeteoData(ifs); // send meteo data for effect show position break; } default: break; } } // end of onEffectShowConfirmationReceived() //============================================================================= void HandlerEffectShow::createEffectShow(const Database::EsmEffectShow &data, bool bForceUpdateDb) { ObjectEffectShow *ifs(new ObjectEffectShow(m_mainHandler)); Core::FunctionReplyObject ret = ifs->createObject(data, bForceUpdateDb); if (ret.error()) { delete ifs; ERROR_LOG(m_logger) << ret(); } else { m_effectShowObjMap.insert(ifs->getId(), ifs); triggerEffectShowOrder(ifs); } } // end of createEffectShow //----------------------------------------------------------------------------- void HandlerEffectShow::onEffectShowModifyRequest( const rti::core::SampleIdentity &cookie, const EffectShow &request) { DEBUG_LOG(m_logger) << "onEffectShowModifyRequest: " << request.id(); if (request.id() <= 0) { ERROR_LOG(m_logger) << "Illegal Effect Show Id: " << request.id(); return; } // Sende Feuerbereitschaft zum SAA // m_mainHandler->handlerTabData()->sendAdlerFqFb(request.idAreaEffectSimulation()); auto ret = effectShowModifyRequest(request); if (ret.error()) ERROR_LOG(m_logger) << ret(); m_mainHandler->dds()->fts()->effectShowModifyReply(cookie, ret); } // end of onEffectShowModifyRequest() //------------------------------------------------------------------------------- Core::FunctionReplyObject HandlerEffectShow::effectShowModifyRequest(const EffectShow &request) { ObjectEffectShow *ifs = m_effectShowObjMap.value(request.id()); if (ifs == nullptr) return Core::FunctionReplyObject(request.id(), tr_lts("dds", "EffectShow with id %1 not found")).arg(request.id()); Core::FunctionReplyObject ret; auto idCurrent = ifs->getData().esmParticipantId; if ((idCurrent != -1) && (request.esmParticipantId() != idCurrent)) { triggerRetractOrder(ifs); // trigger retract order to current effect show actor, if needed ret = ifs->updateObject(request); // update effect show if (!ret.error()) ifs->resetOrderConfirmation(); // reset confirmation status } else { ret = ifs->updateObject(request); // update effect show } if (!ret.error() && ifs->getData().esmParticipantId != -1) triggerEffectShowOrder(ifs); // trigger effect show order to effect show actor if (ret.error()) WARNING_LOG(m_logger) << ret(); return ret; } //------------------------------------------------------------------------------- void HandlerEffectShow::onEffectShowRemoveRequest(const rti::core::SampleIdentity &cookie, const Core::RemoveElementRequest &request) { DEBUG_LOG(m_logger) << "onEffectShowRemoveRequest: " << request.id(); ObjectEffectShow *ifs = m_effectShowObjMap.value(request.id()); Core::FunctionReplyObject ret; if (ifs == nullptr) { ret = Core::FunctionReplyObject(request.id(), tr_lts("dds", "EffectShow id %1 is not valid")).arg(request.id()); m_mainHandler->dds()->fts()->effectShowRemoveReply(cookie, ret); return; } EffectShowManagement::EffectShow ddsData; ddsData.id(ifs->getId()); if (m_mainHandler->dds()->topicLockMaster()->isLocked(ddsData, m_mainHandler->exerciseId())) { ret = Core::FunctionReplyObject(request.id(), tr_lts("dds", "EffectShow '%1' is used by another user!")).arg(ifs->getName()); m_mainHandler->dds()->fts()->effectShowRemoveReply(cookie, ret); return; } ret = removeEffectShow(ifs); // trigger retract order if needed, before object remove m_mainHandler->dds()->fts()->effectShowRemoveReply(cookie, ret); } //------------------------------------------------------------------------------- static std::string toString(const Database::EsmEffectShow &esmEffectShow) { std::ostringstream oss; oss << "Created Effect Show " << "\n ID: " << esmEffectShow.id << "\n Name: " << esmEffectShow.name << "\n Start time: " << esmEffectShow.startTime << "\n Duration: " << esmEffectShow.duration << "\n ID AES: " << esmEffectShow.idAreaEffectSimulation << "\n ID Effect Show Actor: " << esmEffectShow.esmParticipantId << "\n numOfVOlley" << esmEffectShow.numOfVolley << "\n shotsPervolley" << esmEffectShow.shotsPerVolley; return oss.str(); } //------------------------------------------------------------------------------- void HandlerEffectShow::createEffectShowsRelatedToMineArea(const AreaEffectSimulation::MineArea &data) { const auto esmEffectShows = createEffectShowDbDataRelatedToMineArea(data); for (const auto &esmEffectShow : esmEffectShows) { createEffectShow(esmEffectShow); DEBUG_LOG(m_logger) << toString(esmEffectShow); } } //------------------------------------------------------------------------------- void HandlerEffectShow::createEffectShowsRelatedToExplosionArea(const AreaEffectSimulation::ExplosionArea &data) { const auto esmEffectShows = createEffectShowDbDataRelatedToExplosionArea(data); for (const auto &esmEffectShow : esmEffectShows) { createEffectShow(esmEffectShow); DEBUG_LOG(m_logger) << toString(esmEffectShow); } } void HandlerEffectShow::createEffectShowsRelatedToExplosionCluster(const AreaEffectSimulation::ExplosionCluster &data) { const auto esmEffectShows = createEffectShowDbDataRelatedToExplosionCluster(data); for (const auto &esmEffectShow : esmEffectShows) { createEffectShow(esmEffectShow); DEBUG_LOG(m_logger) << toString(esmEffectShow); } } void HandlerEffectShow::createEffectShowsRelatedToEffectCluster(const AreaEffectSimulation::EffectCluster &data) { const auto esmEffectShows = createEffectShowDbDataRelatedToEffectCluster(data); for (const auto &esmEffectShow : esmEffectShows) { createEffectShow(esmEffectShow); DEBUG_LOG(m_logger) << toString(esmEffectShow); } } //------------------------------------------------------------------------------- QVector HandlerEffectShow::createEffectShowDbDataRelatedToMineArea(const AreaEffectSimulation::MineArea &data) { QVector ret; DEBUG_LOG(m_logger) << "createEffectShowDbDataRelatedToExplosionArea: "; EffectShowMineArea effectShowMineArea(data); Database::EsmEffectShow esmEffectShow = effectShowMineArea.getEffectShow(); ret.push_back(esmEffectShow); return ret; } //------------------------------------------------------------------------------- QVector HandlerEffectShow::createEffectShowDbDataRelatedToExplosionArea(const AreaEffectSimulation::ExplosionArea &data) { QVector ret; DEBUG_LOG(m_logger) << "createEffectShowDbDataRelatedToExplosionArea: "; EffectShowExplosionArea effectShowExplosionArea(data, m_mainHandler->handlerPdmData()); if (m_mainHandler->handlerPdmData()->isSmoke(data.chargeStruct())) { //create exact 1 ret.reserve(1); Database::EsmEffectShow esmEffectShow = effectShowExplosionArea.getEffectShow(0); DEBUG_LOG(m_logger) << toString(esmEffectShow); ret.push_back(std::move(esmEffectShow)); } else { int max = effectShowExplosionArea.getNumOfEffectShows() > MAX_EFFECT_SHOWS ? MAX_EFFECT_SHOWS : effectShowExplosionArea.getNumOfEffectShows(); std::random_device rd; //Will be used to obtain a seed for the random number engine std::mt19937 gen(rd()); std::uniform_int_distribution dist(0, effectShowExplosionArea.getNumOfEffectShows() - 1); QSet taken; // only create MAX_EFFECT_SHOWS orders even there are more needed for this area ret.reserve(max); for (int i = 0; i < max; ++i) { int randomNr = dist(gen); Database::EsmEffectShow esmEffectShow = effectShowExplosionArea.getEffectShow(randomNr); while (taken.contains(randomNr)) { randomNr = dist(gen); esmEffectShow = effectShowExplosionArea.getEffectShow(randomNr); } taken.insert(randomNr); int shootsPerArea = effectShowExplosionArea.getShotsPerArea(max); esmEffectShow.numOfVolley = effectShowExplosionArea.getNumberOfVolley(shootsPerArea); esmEffectShow.shotsPerVolley = effectShowExplosionArea.getShotsPerArea(); if (esmEffectShow.shotsPerVolley < esmEffectShow.numOfVolley) esmEffectShow.shotsPerVolley = esmEffectShow.numOfVolley; // set minimum shots per volley DEBUG_LOG(m_logger) << toString(esmEffectShow); ret.push_back(std::move(esmEffectShow)); } } return ret; } QVector HandlerEffectShow::createEffectShowDbDataRelatedToExplosionCluster(const AreaEffectSimulation::ExplosionCluster &data) { EffectShowExplosionCluster effectShowExplosionCluster(data, m_mainHandler->handlerPdmData()); QVector ret; if (m_mainHandler->handlerPdmData()->isSmoke(data.chargeStruct())) { //create exact 1 ret.reserve(1); Database::EsmEffectShow esmEffectShow = effectShowExplosionCluster.getEffectShow(0); if(data.esmParticipantIds().size() > 0) esmEffectShow.esmParticipantId = data.esmParticipantIds().at(0); // TODO handle vector DEBUG_LOG(m_logger) << toString(esmEffectShow); ret.push_back(std::move(esmEffectShow)); } else { int max = effectShowExplosionCluster.getNumOfEffectShows() > MAX_EFFECT_SHOWS ? MAX_EFFECT_SHOWS : effectShowExplosionCluster.getNumOfEffectShows(); std::random_device rd; //Will be used to obtain a seed for the random number engine std::mt19937 gen(rd()); std::uniform_int_distribution dist(0, effectShowExplosionCluster.getNumOfEffectShows() - 1); QSet taken; // only create MAX_EFFECT_SHOWS orders even there are more needed for this area ret.reserve(max); for (int i = 0; i < max; ++i) { int randomNr = dist(gen); Database::EsmEffectShow esmEffectShow = effectShowExplosionCluster.getEffectShow(randomNr); while (taken.contains(randomNr)) { randomNr = dist(gen); esmEffectShow = effectShowExplosionCluster.getEffectShow(randomNr); } taken.insert(randomNr); int shootsPerArea = effectShowExplosionCluster.getShotsPerArea(max); esmEffectShow.numOfVolley = effectShowExplosionCluster.getNumberOfVolley(shootsPerArea); esmEffectShow.shotsPerVolley = effectShowExplosionCluster.getShotsPerArea(); if (esmEffectShow.shotsPerVolley < esmEffectShow.numOfVolley) esmEffectShow.shotsPerVolley = esmEffectShow.numOfVolley; // set minimum shots per volley DEBUG_LOG(m_logger) << toString(esmEffectShow); // Evlt. nicht bei DM42 (dann ist max > 1) if(data.esmParticipantIds().size() > 0) esmEffectShow.esmParticipantId = data.esmParticipantIds().at(0); // TODO handle vector ret.push_back(std::move(esmEffectShow)); } } return ret; } QVector HandlerEffectShow::createEffectShowDbDataRelatedToEffectCluster(const AreaEffectSimulation::EffectCluster &data) { EffectShowEffectCluster effectShowEffectCluster(data, m_mainHandler->handlerPdmData()); QVector ret; if (m_mainHandler->handlerPdmData()->isSmoke(data.chargeStruct())) { //create exact 1 ret.reserve(1); Database::EsmEffectShow esmEffectShow = effectShowEffectCluster.getEffectShow(0); if(data.esmParticipantIds().size() > 0) esmEffectShow.esmParticipantId = data.esmParticipantIds().at(0); // TODO handle vector DEBUG_LOG(m_logger) << toString(esmEffectShow); ret.push_back(std::move(esmEffectShow)); } else { int max = effectShowEffectCluster.getNumOfEffectShows() > MAX_EFFECT_SHOWS ? MAX_EFFECT_SHOWS : effectShowEffectCluster.getNumOfEffectShows(); std::random_device rd; //Will be used to obtain a seed for the random number engine std::mt19937 gen(rd()); std::uniform_int_distribution dist(0, effectShowEffectCluster.getNumOfEffectShows() - 1); QSet taken; // only create MAX_EFFECT_SHOWS orders even there are more needed for this area ret.reserve(max); for (int i = 0; i < max; ++i) { int randomNr = dist(gen); Database::EsmEffectShow esmEffectShow = effectShowEffectCluster.getEffectShow(randomNr); while (taken.contains(randomNr)) { randomNr = dist(gen); esmEffectShow = effectShowEffectCluster.getEffectShow(randomNr); } taken.insert(randomNr); int shootsPerArea = effectShowEffectCluster.getShotsPerArea(max); esmEffectShow.numOfVolley = effectShowEffectCluster.getNumberOfVolley(shootsPerArea); esmEffectShow.shotsPerVolley = effectShowEffectCluster.getShotsPerArea(); if (esmEffectShow.shotsPerVolley < esmEffectShow.numOfVolley) esmEffectShow.shotsPerVolley = esmEffectShow.numOfVolley; // set minimum shots per volley //DEBUG_LOG(m_logger) << toString(esmEffectShow); // Evlt. nicht bei DM42 (dann ist max > 1) if(data.esmParticipantIds().size() > (size_t)i) esmEffectShow.esmParticipantId = data.esmParticipantIds().at(i); // TODO handle vector DEBUG_LOG(m_logger) << toString(esmEffectShow); ret.push_back(std::move(esmEffectShow)); } } return ret; } //------------------------------------------------------------------------------- void HandlerEffectShow::removeEffectShowsRelatedToAes(int idAes, bool retract) { DEBUG_LOG(m_logger) << "removeEffectShowsRelatedToAes(" << idAes << ")"; auto it = m_effectShowObjMap.begin(); while (it != m_effectShowObjMap.end()) { bool remove = false; if (it.value()->getIdAES() == idAes) { if ((it.value()->getData().orderConfirmation != EffectShowManagement::OrderConfirmation_e_def::Execution) && (it.value()->getData().orderConfirmation != EffectShowManagement::OrderConfirmation_e_def::OrderCarriedOut)) remove = true; else INFO_LOG(m_logger) << "Effect Show: " << it.value()->getId() << " not removed due to EXECUTION / ORDER CARRIED OUT"; } if (remove) { ObjectEffectShow *objToDelete = it.value(); ++it; removeEffectShow(objToDelete, true, retract); // trigger retract order if needed, before object remove } else ++it; } } // end of removeEffectShowsRelatedToAes() //------------------------------------------------------------------------------- void HandlerEffectShow::updateEffectShowsRelatedToMineArea(const AreaEffectSimulation::MineArea &data) { for (ObjectEffectShow *obj : qAsConst(m_effectShowObjMap)) { if (obj->getIdAES() == data.id()) { Database::EsmEffectShow esmEffectShow = obj->getData(); EffectShowMineArea effectShowMineArea(data); effectShowMineArea.updateEffectShow(esmEffectShow); obj->updateObject(esmEffectShow); } } } //------------------------------------------------------------------------------- void HandlerEffectShow::updateEffectShowsRelatedToExplosionArea(const AreaEffectSimulation::ExplosionArea &data) { for (ObjectEffectShow *obj : qAsConst(m_effectShowObjMap)) { if (obj->getIdAES() == data.id()) { Database::EsmEffectShow esmEffectShow = obj->getData(); EffectShowExplosionArea effectShowExplosionArea(data, m_mainHandler->handlerPdmData()); effectShowExplosionArea.updateEffectShow(esmEffectShow); obj->updateObject(esmEffectShow); } } } void HandlerEffectShow::updateEffectShowsRelatedToExplosionCluster(const AreaEffectSimulation::ExplosionCluster &data) { for (ObjectEffectShow *obj : qAsConst(m_effectShowObjMap)) { if (obj->getIdAES() == data.id()) { Database::EsmEffectShow esmEffectShow = obj->getData(); EffectShowExplosionCluster effectShowExplosionCluster(data, m_mainHandler->handlerPdmData()); effectShowExplosionCluster.updateEffectShow(esmEffectShow); obj->updateObject(esmEffectShow); } } } void HandlerEffectShow::updateEffectShowsRelatedToEffectCluster(const AreaEffectSimulation::EffectCluster &data) { for (ObjectEffectShow *obj : qAsConst(m_effectShowObjMap)) { if (obj->getIdAES() == data.id()) { Database::EsmEffectShow esmEffectShow = obj->getData(); EffectShowEffectCluster effectShowEffectCluster(data, m_mainHandler->handlerPdmData()); effectShowEffectCluster.updateEffectShow(esmEffectShow); obj->updateObject(esmEffectShow); } } } static void copyOldActorData(Database::EsmEffectShow &newData, const Database::EsmEffectShow &oldData) { newData.id = oldData.id; newData.orderConfirmation = oldData.orderConfirmation; newData.answerText = oldData.answerText; newData.esmParticipantId = oldData.esmParticipantId; } //------------------------------------------------------------------------------- void HandlerEffectShow::modifyEffectShowsRelatedToMineArea(const AreaEffectSimulation::MineArea &data) { // even there can currently only be one object we use the same logic as for // modifyEffectShowsRelatedToExplosionArea for convenience modifyEffectShows(createEffectShowDbDataRelatedToMineArea(data), data.id()); } //------------------------------------------------------------------------------- void HandlerEffectShow::modifyEffectShowsRelatedToExplosionArea(const AreaEffectSimulation::ExplosionArea &data) { modifyEffectShows(createEffectShowDbDataRelatedToExplosionArea(data), data.id()); } void HandlerEffectShow::modifyEffectShowsRelatedToExplosionCluster(const AreaEffectSimulation::ExplosionCluster &data) { modifyEffectShows(createEffectShowDbDataRelatedToExplosionCluster(data), data.id()); } void HandlerEffectShow::modifyEffectShowsRelatedToEffectCluster(const AreaEffectSimulation::EffectCluster &data) { modifyEffectShows(createEffectShowDbDataRelatedToEffectCluster(data), data.id()); } //------------------------------------------------------------------------------- void HandlerEffectShow::modifyEffectShows(const QVector &esmEffectShows, int aesId) { // a lot of stuff might have changed - therefore we recalculate the effect shows, // use the old ids and send out a complete update // first retrieve all objects for the area QVector objects = removeFromEffectShowMapByAesId(aesId); // fewer objects than before -> remove the superfluous ones while (objects.size() > esmEffectShows.size()) removeEffectShow(objects.takeLast(), false, false); // update all for the existing objects, create new ones if needed for (int i = 0; i < esmEffectShows.size(); ++i) { auto esmEffectShow = esmEffectShows.at(i); if (objects.size() > i) { auto oldObj = objects.at(i); copyOldActorData(esmEffectShow, oldObj->getData()); oldObj->setRemoveFromDdsOnDestruction(false); delete oldObj; } createEffectShow(esmEffectShow, true); } updateEffectShowOrdersRelatedToAes(aesId); } //------------------------------------------------------------------------------- void HandlerEffectShow::updateEffectShowOrdersRelatedToAes(int idAes) { for (ObjectEffectShow *obj : qAsConst(m_effectShowObjMap)) { if (obj->getIdAES() == idAes) triggerEffectShowOrder(obj); } } //------------------------------------------------------------------------------- void HandlerEffectShow::pauseEffectShowsRelatedToAes(int idAes) { for (ObjectEffectShow *obj : qAsConst(m_effectShowObjMap)) { if (obj->getIdAES() == idAes) triggerEffectShowStop(obj); } } //------------------------------------------------------------------------------- void HandlerEffectShow::continueEffectShowsRelatedToAes(int idAes) { for (ObjectEffectShow *obj : qAsConst(m_effectShowObjMap)) { if (obj->getIdAES() == idAes) triggerEffectShowContinue(obj); } } //------------------------------------------------------------------------------- QVector HandlerEffectShow::removeFromEffectShowMapByAesId(int aesId) { QVector ret; for (auto it = m_effectShowObjMap.begin(); it != m_effectShowObjMap.end();) { ObjectEffectShow *obj = it.value(); if (obj->getIdAES() == aesId) { ret += obj; it = m_effectShowObjMap.erase(it); } else ++it; } // in modifyEffectShowsRelatedToFOO we want to remove the last objects first when no longer needed std::sort(ret.begin(), ret.end(), [](const ObjectEffectShow * a, const ObjectEffectShow * b) { return a->getId() < b->getId();}); return ret; } //------------------------------------------------------------------------------- Core::FunctionReplyObject HandlerEffectShow::removeEffectShow(ObjectEffectShow *ifs, bool bWarnWhenNotInMap, bool retract) { const int effectShowId = ifs->getId(); // retract order if needed if (retract) triggerRetractOrder(ifs); // remove from data base Core::FunctionReplyObject ret = ifs->removeObject(); if (ret.error()) { ERROR_LOG(m_logger) << ret(); return ret; } // delete object and remove from data distribution delete ifs; // remove from map if (!m_effectShowObjMap.remove(effectShowId) && bWarnWhenNotInMap) WARNING_LOG(m_logger) << "Remove of EffectShow(" << effectShowId << ") failed."; else DEBUG_LOG(m_logger) << "EffectShow(" << effectShowId << ") removed."; return ret; } //------------------------------------------------------------------------------- void HandlerEffectShow::triggerEffectShowOrder(const ObjectEffectShow *ifs) { const Database::EsmEffectShow &effectShow = ifs->getData(); INFO_LOG(m_logger) << "triggerEffectShowOrder for id " << ifs->getId() << ", aesId: " << ifs->getIdAES() << ", actor: " << effectShow.esmParticipantId; if (effectShow.esmParticipantId == -1) return; // no effect show actor allocated // trigger effect show order int equipmentNumber = m_mainHandler->handlerPpmData()->getEquipmentNumber(effectShow.esmParticipantId); m_mainHandler->handlerTabData()->effectShowOrder(equipmentNumber, effectShow.esmParticipantId, ifs->getEffectShowOrder()); } //------------------------------------------------------------------------------- void HandlerEffectShow::triggerRetractOrder(const ObjectEffectShow *ifs) { const Database::EsmEffectShow &effectShow = ifs->getData(); INFO_LOG(m_logger) << "triggerRetractOrder for id " << ifs->getId() << ", aesId: " << ifs->getIdAES() << ", actor: " << effectShow.esmParticipantId; if (effectShow.esmParticipantId == -1) return; // up to now no actor allocated if (effectShow.orderConfirmation >= EffectShowManagement::OrderConfirmation_e_def::OrderCarriedOut) return; // order obsolete // trigger retract order int equipmentNumber = m_mainHandler->handlerPpmData()->getEquipmentNumber(effectShow.esmParticipantId); m_mainHandler->handlerTabData()->retractOrder(equipmentNumber, effectShow.esmParticipantId, ifs->getRetractOrder()); } //----------------------------------------------------------------------------- void HandlerEffectShow::triggerEffectShowStop(const ObjectEffectShow *ifs) { const Database::EsmEffectShow &effectShow = ifs->getData(); INFO_LOG(m_logger) << "triggerEffectShowStop for id " << ifs->getId() << ", aesId: " << ifs->getIdAES() << ", actor: " << effectShow.esmParticipantId; if (effectShow.esmParticipantId == -1) return; // up to now no actor allocated // trigger effect show stop int equipmentNumber = m_mainHandler->handlerPpmData()->getEquipmentNumber(effectShow.esmParticipantId); m_mainHandler->handlerTabData()->effectShowStop(equipmentNumber, effectShow.esmParticipantId, ifs->getId()); } //----------------------------------------------------------------------------- void HandlerEffectShow::triggerEffectShowContinue(const ObjectEffectShow *ifs) { const Database::EsmEffectShow &effectShow = ifs->getData(); INFO_LOG(m_logger) << "triggerEffectShowContinue for id " << ifs->getId() << ", aesId: " << ifs->getIdAES() << ", actor: " << effectShow.esmParticipantId; if (effectShow.esmParticipantId == -1) return; // up to now no actor allocated // trigger retract order int equipmentNumber = m_mainHandler->handlerPpmData()->getEquipmentNumber(effectShow.esmParticipantId); m_mainHandler->handlerTabData()->effectShowContinue(equipmentNumber, effectShow.esmParticipantId, ifs->getContinueOrder()); } //----------------------------------------------------------------------------- void HandlerEffectShow::triggerMeteoData(const ObjectEffectShow *ifs) { const Database::EsmEffectShow &effectShow = ifs->getData(); // get weather near to the effect show position Core::GeoPosition2D pos(effectShow.centerPosition.x(), effectShow.centerPosition.y()); MeteoDataManagement::MeteoData meteoData; if (m_mainHandler->handlerMdmData()->getNearestWeather(pos, meteoData)) { if (!meteoData.windOk() && !meteoData.climateOk()) { WARNING_LOG(m_logger) << "Found MeteoStation but no weather Data available, try again in 1 minute"; QTimer::singleShot(6000, this, &HandlerEffectShow::onSendMeteoData); return; } // trigger meteo data to effect show vehicle int equipmentNumber = m_mainHandler->handlerPpmData()->getEquipmentNumber(effectShow.esmParticipantId); m_mainHandler->handlerTabData()->meteoData(equipmentNumber, effectShow.esmParticipantId, meteoData); // meteo data available qint64 deltaTime = m_mainHandler->dds()->currentPartitionTime() - meteoData.timeStamp(); if (deltaTime > (60 * 15 * 1000)) WARNING_LOG(m_logger) << "Age of meteo data=" << (deltaTime / 60000) << "min for vehicle: " << equipmentNumber; } else { int equipmentNumber = m_mainHandler->handlerPpmData()->getEquipmentNumber(effectShow.esmParticipantId); WARNING_LOG(m_logger) << "Meteo data not available for effect show vehicle: " << equipmentNumber; } } //----------------------------------------------------------------------------- void HandlerEffectShow::onSendMeteoData() { for (ObjectEffectShow *obj : qAsConst(m_effectShowObjMap)) { const Database::EsmEffectShow &effectShow = obj->getData(); if (effectShow.esmParticipantId == -1) continue; // no actor allocated if ((effectShow.orderConfirmation < EffectShowManagement::OrderConfirmation_e_def::DriveOff) || (effectShow.orderConfirmation >= EffectShowManagement::OrderConfirmation_e_def::OrderCarriedOut)) continue; // effect show not processed triggerMeteoData(obj); } } void HandlerEffectShow::onCleanUp() { DEBUG_LOG(m_logger) << "Start Cleanup "; QVector objects; for (ObjectEffectShow *obj : qAsConst(m_effectShowObjMap)) { const Database::EsmEffectShow &effectShow = obj->getData(); if (effectShow.orderConfirmation == OrderConfirmation_e::OrderCarriedOut || effectShow.startTime <= 0 || effectShow.id <= 0) continue; DEBUG_LOG(m_logger) << "Effect show with ID " << effectShow.id << " will expire at: " << QDateTime::fromMSecsSinceEpoch(effectShow.startTime + effectShow.duration + CLEANUPTIME).toString() << " current time: " << QDateTime::fromMSecsSinceEpoch(m_mainHandler->dds()->currentPartitionTime()).toString(); if ((effectShow.startTime + effectShow.duration + CLEANUPTIME) < m_mainHandler->dds()->currentPartitionTime()) { //remove object DEBUG_LOG(m_logger) << "Remove Effect Show " << effectShow.id ; objects.append(obj); } } while (objects.size() > 0) removeEffectShow(objects.takeLast(), false, true); } QString HandlerEffectShow::enumToString(HandlerEffectShow::KindOfModification_e mod) { switch (mod) { case HandlerEffectShow::KindOfModification_e::Added: return QLatin1String("KindOfModification_e::Added"); case HandlerEffectShow::KindOfModification_e::ModifiedArea: return QLatin1String("KindOfModification_e::ModifiedArea"); case HandlerEffectShow::KindOfModification_e::ModifiedData: return QLatin1String("KindOfModification_e::ModifiedData"); case HandlerEffectShow::KindOfModification_e::Removed: return QLatin1String("KindOfModification_e::Removed"); case HandlerEffectShow::KindOfModification_e::Paused: return QLatin1String("KindOfModification_e::Paused"); case HandlerEffectShow::KindOfModification_e::Continued: return QLatin1String("KindOfModification_e::Continued"); case HandlerEffectShow::KindOfModification_e::None: return QLatin1String("KindOfModification_e::None"); } Q_ASSERT(false); return QStringLiteral("Unknown KindOfModification_e (%1)").arg(int(mod)); } //----------------------------------------------------------------------------- } // namespace EffectShowManagement