/** * Send Participant data to NGS * $Id$ * $HeadURL$ * $Author$ * Created by Christian Ehrlicher, SLSE, 2017-04-07 */ #include "ppm_handler.h" #include "ngs_handler.h" #include #include #include #include namespace HighLevelArchitecture { PpmHandler::PpmHandler(NgsHandler *ngsHandler) : m_ngsHandler(ngsHandler) , m_requestHelper(new LtsUtils::RequestHelper(this)) , m_logger(getLogger("PpmHandler")) {} PpmHandler::~PpmHandler() { m_dtcPpm.reset(); m_ftcPpm.reset(); m_dtcPdm.reset(); m_dtsTab.reset(); m_ftcTab.reset(); m_dtcAes.reset(); } bool PpmHandler::init() { m_dtcPpm = ParticipantManagement::Interface::Dtc::create(m_ngsHandler->ddsHandler()->ddsConnector()); m_ftcPpm = ParticipantManagement::Interface::Ftc::create(m_ngsHandler->ddsHandler()->ddsConnector()); m_dtcPdm = ProjectDataManagement::Interface::Dtc::create(m_ngsHandler->ddsHandler()->ddsConnector()); m_dtsTab = TrainingAreaBase::Interface::Dts::create(m_ngsHandler->ddsHandler()->ddsConnector()); m_ftcTab = TrainingAreaBase::Interface::Ftc::create(m_ngsHandler->ddsHandler()->ddsConnector()); m_dtcAes = AreaEffectSimulation::Interface::Dtc::create(m_ngsHandler->ddsHandler()->ddsConnector()); // PPM DTC connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::typeChanged, this, &PpmHandler::onTypeChanged); connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::dynamicParticipantDataChanged, this, &PpmHandler::onDynamicParticipantDataChanged); connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::participantChanged, this, &PpmHandler::onParticipantChanged); connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::participantPositionChanged, this, &PpmHandler::onParticipantPositionChanged); connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::partyChanged, this, &PpmHandler::onPartyChanged); m_dtcPpm->enableType(); m_dtcPpm->enableDynamicParticipantData(); m_dtcPpm->enableParticipant(); m_dtcPpm->enableParticipantPosition(); m_dtcPpm->enableParty(); m_dtcPpm->enableParticipantGearEvent(); m_dtcPdm->enableGearTypeChargeType(); m_dtcPpm->waitForHistoricalDataParticipant(); // PPM FTC m_ftcPpm->enableModifyParticipantData(); // PDM DTC connect(m_dtcPdm.get(), &ProjectDataManagement::Interface::Dtc::chargeTypeChanged, this, &PpmHandler::onChargeTypeChanged); m_dtcPdm->enableChargeType(); // TAB DTS if (!(m_dtsTab->enableEquipmentPosition() && m_dtsTab->enableEquipmentGearEvent() && m_dtsTab->enableEquipmentState() && m_dtsTab->enableLaserDesignation() && m_dtsTab->enableSpecialSensorData() && m_dtsTab->enableGearCharge() && m_dtsTab->enableEquipmentGearChargeState() && m_dtsTab->enableEquipmentGearAssignment()) ) { ERROR_LOG(m_logger) << "Enabling TAB DTS Data-Topics failed."; return false; } // TAB FTC m_ftcTab->enableDemandInit(); m_ftcTab->enableDemandVulnerabilityStateChange(); m_ftcTab->enableSendCesHitInformation(); // AES DTC // Nothing to do as only aesItemIdFromExternalId is called. // Connect Connector signals to slots here. NgsConnector *conn = m_ngsHandler->ngsConnector().get(); connect(conn, &NgsConnector::firstTickFinished, this, &PpmHandler::startPublishToNgs); connect(conn, &NgsConnector::spatialChanged, this, &PpmHandler::onSpatialChanged); connect(conn, &NgsConnector::markingChanged, this, &PpmHandler::onMarkingChanged); connect(conn, &NgsConnector::exconEngagement, this, &PpmHandler::onExconEngagement); connect(conn, &NgsConnector::weaponFire, this, &PpmHandler::onWeaponFire); connect(conn, &NgsConnector::gearChargeState, this, &PpmHandler::onGearChargeState); connect(conn, &NgsConnector::cesHitInformation, this, &PpmHandler::onParticipantCesHit); connect(conn, &NgsConnector::equipmentState, this, &PpmHandler::onEquipmentState); connect(conn, &NgsConnector::laserDesignation, this, &PpmHandler::onLaserDesignation); connect(conn, &NgsConnector::sensorChanged, this, &PpmHandler::onSensorDataChanged); return true; } ParticipantManagement::Role PpmHandler::roleForPartyId(int partyId) { if (partyId <= 0) return ParticipantManagement::Role_def::Unknown; auto it = m_partyData.constFind(partyId); if (it == m_partyData.constEnd()) { m_dtcPpm->waitForHistoricalDataParty(); m_partyData = m_dtcPpm->partys(); it = m_partyData.constFind(partyId); if (it == m_partyData.constEnd()) return ParticipantManagement::Role_def::Unknown; } return it.value().role(); } // DDS -> own memory void PpmHandler::onTypeChanged(const ParticipantManagement::Type &data, DataModification modType) { switch (modType) { case DataModification::eAdded: case DataModification::eModified: m_types[data.id()] = data; break; case DataModification::eRemoved: m_types.remove(data.id()); break; } } int PpmHandler::getEquipmentNo(int participantId) const { if (!m_partData.contains(participantId)) return 0; const ParticipantManagement::Participant &p = m_partData[participantId]; if (!p.equipmentNumber().is_set()) return 0; return p.equipmentNumber().get(); } int PpmHandler::getParticipantIdByExternalId(int externalId) const { for(const auto &part : qAsConst(m_partData)) { if (part.externalId() == externalId) return part.id(); } return 0; } // DDS -> HLA void PpmHandler::onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data, DataModification modType) { int equipmentNo = getEquipmentNo(data.participantId()); if (equipmentNo == 0) { ERROR_LOG(m_logger) << "Could not find EquipmentNo for Participant " << data.participantId() << ". Cannot send Dynamic Participant Data Modification to HLA."; return; } switch (modType) { case DataModification::eAdded: case DataModification::eModified: { if (!m_ngsHandler->ngsConnector()->canPublishData()) break; std::shared_ptr conn = m_ngsHandler->ngsConnector(); const ParticipantManagement::StateInformation oldStateInfo = currentParticipantStateInformation(m_dynPartData.value(data.participantId())); const ParticipantManagement::StateInformation newStateInfo = currentParticipantStateInformation(data); // Improvement: Pass Originator to Connector, so the source can also be AES. if (oldStateInfo != newStateInfo) { m_dynPartData[data.participantId()] = data; if (newStateInfo.originatorType() == ProjectDataManagement::StateChangeOriginator::AreaEffectSimulation) { // Aes hit conn->setParticipantHit(equipmentNo, newStateInfo, getParticipantPosition(data.participantId()), newStateInfo.originatorChargeTypeId(), newStateInfo.originatorType(), newStateInfo.originatorId()); } else if (newStateInfo.originatorType() == ProjectDataManagement::StateChangeOriginator::Participant) { // direct hit conn->setParticipantHit(equipmentNo, newStateInfo, getParticipantPosition(data.participantId()), newStateInfo.originatorChargeTypeId(), newStateInfo.originatorType(), getEquipmentNo(newStateInfo.originatorId())); } else { // TODO: ProjectDataManagement::StateChangeOriginator::OperatorController, ExerciseControl, WoundTreatmentDevice, MaintainanceDevice // reactivation or something similar conn->setParticipantHit(equipmentNo, newStateInfo, getParticipantPosition(data.participantId()), newStateInfo.originatorChargeTypeId(), newStateInfo.originatorType(), newStateInfo.originatorId()); } } break; } case DataModification::eRemoved: m_dynPartData.remove(data.participantId()); break; } } // DDS -> HLA void PpmHandler::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType) { DEBUG_LOG(m_logger) << "onParticipantChanged: " << data; switch (modType) { case DataModification::eAdded: createParticipant(data); m_partData[data.id()] = data; break; case DataModification::eModified: { // Participant has been deleted if (data.isDeleted() && !m_partData[data.id()].isDeleted()) { removeParticipant(m_partData[data.id()]); // Remove the old Equipment No removeParticipant(data); // If it has a new Equipment No, kill it also. m_partData[data.id()] = data; break; } // Participant is new // Shouldn't happen, as it is the Added case if (!m_partData.contains(data.id())) { createParticipant(data); m_partData[data.id()] = data; break; } // Only create/remove if Equipment Number changed... int oldEqNo = m_partData[data.id()].equipmentNumber().is_set() ? m_partData[data.id()].equipmentNumber().get() : 0; int newEqNo = data.equipmentNumber().is_set() ? data.equipmentNumber().get() : 0; if (oldEqNo != newEqNo) { removeParticipant(m_partData[data.id()]); createParticipant(data); } if (m_partData[data.id()].designator() != data.designator() && data.equipmentNumber().is_set()) m_ngsHandler->ngsConnector()->setParticipantName(data.equipmentNumber().get(), QString::fromStdString(data.designator())); m_partData[data.id()] = data; break; } case DataModification::eRemoved: removeParticipant(data); m_partData.remove(data.id()); break; } auto it = m_externalEquipmentNumbers.find(data.id()); if (it == m_externalEquipmentNumbers.end()) { // not found if (modType == DataModification::eRemoved || !data.equipmentNumber().is_set() || data.externalId() <= 0) return; int equipNo = data.equipmentNumber().get(); m_externalEquipmentNumbers.insert(data.id(), equipNo); emit externalEquipmentNumberAdded(equipNo); } else { // found int oldEquipNo = it.value(); if (modType == DataModification::eRemoved || !data.equipmentNumber().is_set() || data.externalId() <= 0) { m_externalEquipmentNumbers.erase(it); emit externalEquipmentNumberRemoved(oldEquipNo); return; } if (oldEquipNo != data.equipmentNumber().get()) { emit externalEquipmentNumberRemoved(oldEquipNo); emit externalEquipmentNumberAdded(data.equipmentNumber().get()); it.value() = data.equipmentNumber().get(); } } } // DDS -> HLA void PpmHandler::onParticipantPositionChanged(const ParticipantManagement::ParticipantPosition &data, DataModification modType) { DEBUG_LOG(m_logger) << "onParticipantPositionChanged: " << data; switch (modType) { case DataModification::eAdded: case DataModification::eModified: { if (m_ngsHandler->ngsConnector()->canPublishData()) { int eqNo = getEquipmentNo(data.participantId()); if (eqNo == 0) return; ParticipantPosition pos(data.pos(), data.sampleTime()); m_ngsHandler->ngsConnector()->setWorldLocation(eqNo, pos); } m_partPosData[data.participantId()] = data; break; } case DataModification::eRemoved: m_partPosData.remove(data.participantId()); break; } } // HLA -> DDS void PpmHandler::onSpatialChanged(int eqId, const ParticipantPosition &pos, qint64 simTimeMSecs) { // NGSConnector already checked that the position changed significantly TrainingAreaBase::EquipmentPosition &position = m_observerPositions[eqId]; position.position().position() = pos.toGeoPosition(); position.equipmentNumber(eqId); // With SAAB, ExternalId and EqId are the same! position.sampleTime(simTimeMSecs); m_dtsTab->publish(position); } void PpmHandler::onSensorDataChanged(const TrainingAreaBase::SpecialSensorData &event) { m_dtsTab->publish(event); } bool PpmHandler::onMarkingChanged(int eqId, const QString &marking, qint64 simTimeMSecs) { Q_UNUSED(simTimeMSecs); // According to Ulli, the external (fixed) designation shall be the tactIdentifier. The designator thus is freely changeable. ParticipantManagement::ParticipantData p = m_dtcPpm->convertParticipantToParticipantData(m_dtcPpm->participant(m_dtcPpm->participantIdByEquipmentNumber(eqId))); if (p.tacticalIdentifier() == marking.toStdString()) return true; p.tacticalIdentifier(marking.toStdString()); ParticipantManagement::ModifyParticipantDataRequest req; req.data().push_back(std::move(p)); return m_requestHelper->startSingleRequest([this, req]() { return m_ftcPpm->modifyParticipantDataRequest(req, this); }); } // DDS -> own memory void PpmHandler::onPartyChanged(const ParticipantManagement::Party &data, DataModification modType) { switch (modType) { case DataModification::eAdded: case DataModification::eModified: m_partyData[data.id()] = data; break; case DataModification::eRemoved: m_partyData.remove(data.id()); break; } } // DDS -> own memory void PpmHandler::onChargeTypeChanged(const ProjectDataManagement::ChargeType &data, DataModification modType) { switch (modType) { case DataModification::eAdded: case DataModification::eModified: m_chargeTypes[data.id()] = data; break; case DataModification::eRemoved: m_chargeTypes.remove(data.id()); break; } } void PpmHandler::startPublishToNgs() { INFO_LOG(m_logger) << "Recreating all players from scratch due to structure / exercise change"; // 1. Cleanup m_createdParticipantIds.clear(); // 2. Remove all virtual Players from database // not yet supporteed // 4. Recreate players INFO_LOG(m_logger) << "(Re)Adding all players, size: " << m_partData.size(); for (const ParticipantManagement::Participant &participant : qAsConst(m_partData)) createParticipant(participant); } void PpmHandler::participantInitRequest(const TrainingAreaBase::TetraIcd::Init &request) { m_ngsHandler->ngsConnector()->sendParticipantInitRequest(request.header.equipmentNumber, request.resetManipulation, request.resetVulnerabilityState, request.restockCharges, request.header.timeStamp); } rpr2::DetonationResultCodeEnum8::ET PpmHandler::rpr2DetonationResultFromVulnerabilityState(TrainingAreaBase::TetraIcd::VulnerabilityState vulnerabilityState) { // ICE only cares about EntityImpact and EntotyProximateDetonation. Everything else will be discarded rpr2::DetonationResultCodeEnum8::ET status = rpr2::DetonationResultCodeEnum8::None; switch(vulnerabilityState) { case TrainingAreaBase::TetraIcd::VulnerabilityState::CombatReady: status = rpr2::DetonationResultCodeEnum8::None; break; case TrainingAreaBase::TetraIcd::VulnerabilityState::LightDamage: case TrainingAreaBase::TetraIcd::VulnerabilityState::MediumDamage: case TrainingAreaBase::TetraIcd::VulnerabilityState::HeavyDamage: case TrainingAreaBase::TetraIcd::VulnerabilityState::MobilityKill: case TrainingAreaBase::TetraIcd::VulnerabilityState::VisibleMobilityKill: case TrainingAreaBase::TetraIcd::VulnerabilityState::WeaponSystemDamage: case TrainingAreaBase::TetraIcd::VulnerabilityState::VisibleWeaponSystemDamage: status = rpr2::DetonationResultCodeEnum8::AirHit; break; case TrainingAreaBase::TetraIcd::VulnerabilityState::CatastrophicKill: status = rpr2::DetonationResultCodeEnum8::EntityImpact; break; case TrainingAreaBase::TetraIcd::VulnerabilityState::TemporarySeverance: case TrainingAreaBase::TetraIcd::VulnerabilityState::NearMiss: case TrainingAreaBase::TetraIcd::VulnerabilityState::HitWithNoEffect: status = rpr2::DetonationResultCodeEnum8::EntityProximateDetonation; break; case TrainingAreaBase::TetraIcd::VulnerabilityState::VulnerabilityBitsChanged: case TrainingAreaBase::TetraIcd::VulnerabilityState::Reserved: case TrainingAreaBase::TetraIcd::VulnerabilityState::NContamination: case TrainingAreaBase::TetraIcd::VulnerabilityState::BContamination: case TrainingAreaBase::TetraIcd::VulnerabilityState::CContamination: status = rpr2::DetonationResultCodeEnum8::Other; break; } return status; } rpr2::DetonationResultCodeEnum8::ET PpmHandler::rpr2DetonationResultFromPercentage(int percentage) { rpr2::DetonationResultCodeEnum8::ET status = rpr2::DetonationResultCodeEnum8::EntityProximateDetonation; if (percentage > 0) status = rpr2::DetonationResultCodeEnum8::AirHit; if (percentage > 50) status = rpr2::DetonationResultCodeEnum8::EntityImpact; return status; } void PpmHandler::participantVulnerabilityStateRequest(const TrainingAreaBase::TetraIcd::DemandVulnerabilityStateChange &request) { DEBUG_LOG(m_logger) << "Participant Vulnerability State Request"; rpr2::DetonationResultCodeEnum8::ET resCode = rpr2DetonationResultFromVulnerabilityState(request.reqestedState); m_ngsHandler->ngsConnector()->sendMunitionDetonation(request.header.equipmentNumber, ProjectDataManagement::ChargeType(), 0, resCode, request.header.timeStamp); } void PpmHandler::participantCesHitInformationRequest(const TrainingAreaBase::TetraIcd::CesHitInformation &request) { rpr2::DetonationResultCodeEnum8::ET resCode = rpr2DetonationResultFromPercentage(request.effectPercent); ProjectDataManagement::ChargeType ct = chargeTypeFromTasCodeDirect(request.chargeTasCodeDirect); m_ngsHandler->ngsConnector()->sendMunitionDetonation(request.header.equipmentNumber, ct, request.originatorEquipmentNumber, resCode, request.header.timeStamp); } void PpmHandler::createParticipant(const ParticipantManagement::Participant &participant) { // Only create participants that have no external ID. if (participant.externalId() > 0 || participant.equipmentNumber() == 0 || participant.isDeleted()) return; if (!m_ngsHandler->ngsConnector()->canPublishData()) { WARNING_LOG(m_logger) << "Can not publish data ... :("; return; } if (m_createdParticipantIds.contains(participant.id())) return; const ParticipantManagement::Type partType = getParticipantType(participant.typeId()); bool bCreated; switch (partType.typeClass().underlying()) { case ParticipantManagement::TypeClass_def::Human: bCreated = createHuman(participant); break; case ParticipantManagement::TypeClass_def::GroundVehicle: case ParticipantManagement::TypeClass_def::VehicleWithGear: case ParticipantManagement::TypeClass_def::WeaponSystem: bCreated = createGroundVehicle(participant); break; case ParticipantManagement::TypeClass_def::Aircraft: bCreated = createAircraft(participant); break; case ParticipantManagement::TypeClass_def::SupportEntity: case ParticipantManagement::TypeClass_def::Unit: // bCreated = createUnit(participant); // break; case ParticipantManagement::TypeClass_def::Vessel: // bCreated = createVessel(participant); // break; default: bCreated = false; } if (!bCreated) return; m_createdParticipantIds += participant.id(); } bool PpmHandler::removeParticipant(const ParticipantManagement::Participant &participant) { if (!participant.equipmentNumber().is_set() || participant.equipmentNumber().get() == 0) return false; return m_ngsHandler->ngsConnector()->removeBaseEntity(participant.equipmentNumber().get()); } //bool PpmHandler::createUnit(const ParticipantManagement::Participant &participant) //{ // const ParticipantInformation pi(participant2ParticipantInformation(participant)); // return m_ngsHandler->ngsConnector()->addAggregateEntity(pi, participant.inferiorIds()); //} bool PpmHandler::createHuman(const ParticipantManagement::Participant &participant) { const ParticipantInformation pi(participant, getTypestruct(participant.typeId()), getParticipantPosition(participant.id())); return m_ngsHandler->ngsConnector()->addHuman(pi, currentVulnerabilityState(participant.id())); } bool PpmHandler::createGroundVehicle(const ParticipantManagement::Participant &participant) { const ParticipantInformation pi(participant, getTypestruct(participant.typeId()), getParticipantPosition(participant.id())); return m_ngsHandler->ngsConnector()->addGroundVehicle(pi, currentVulnerabilityState(participant.id())); } bool PpmHandler::createAircraft(const ParticipantManagement::Participant &participant) { const ParticipantInformation pi(participant, getTypestruct(participant.typeId()), getParticipantPosition(participant.id())); return m_ngsHandler->ngsConnector()->addLongBowApache(pi, currentVulnerabilityState(participant.id())); } TypeStruct PpmHandler::getTypestruct(int typeId) { dds::core::vector disEntities = getParticipantType(typeId).disEntities(); if (disEntities.size()) return TypeStruct::fromDisInt(disEntities.at(0)); // First is relevant for sending return TypeStruct(); } ParticipantManagement::Type PpmHandler::getParticipantType(int typeId) { auto it = m_types.constFind(typeId); if (it == m_types.constEnd()) { m_dtcPpm->waitForHistoricalDataType(); m_types = m_dtcPpm->types(); it = m_types.constFind(typeId); if (it == m_types.constEnd()) return ParticipantManagement::Type(); } return it.value(); } ProjectDataManagement::VulnerabilityState PpmHandler::currentVulnerabilityState(int participantId) const { ProjectDataManagement::VulnerabilityState ts; auto itPartData = m_dynPartData.find(participantId); if (itPartData != m_dynPartData.end()) { const auto &sh = itPartData.value().stateHistory(); if (sh.size() != 0) { size_t idxCurrent = 0; for (size_t i = 1; i < sh.size(); ++i) { if (sh.at(idxCurrent).stateTime() < sh.at(i).stateTime()) idxCurrent = i; } ts = sh.at(idxCurrent).vulnerabilityState(); return ts; } } ts = ProjectDataManagement::VulnerabilityState_def::TemporarySeverance; return ts; } ParticipantManagement::StateInformation PpmHandler::currentParticipantStateInformation(int participantId) const { auto itPartData = m_dynPartData.find(participantId); if (itPartData != m_dynPartData.end()) return currentParticipantStateInformation(itPartData.value()); return ParticipantManagement::StateInformation(); } ParticipantManagement::StateInformation PpmHandler::currentParticipantStateInformation(const ParticipantManagement::DynamicParticipantData &data) { const auto &sh = data.stateHistory(); if (sh.size() == 0) return ParticipantManagement::StateInformation(); size_t idxCurrent = 0; for (size_t i = 1; i < sh.size(); ++i) { if (sh.at(idxCurrent).stateTime() < sh.at(i).stateTime()) idxCurrent = i; } return sh.at(idxCurrent); } dds::core::vector PpmHandler::currentParticipantGearInformation(int participantId) const { auto itPartData = m_dynPartData.find(participantId); if (itPartData != m_dynPartData.end()) return itPartData.value().gear(); return dds::core::vector(); } dds::core::vector PpmHandler::currentParticipantManipulationInformation(int participantId) const { auto itPartData = m_dynPartData.find(participantId); if (itPartData != m_dynPartData.end()) return itPartData.value().manipulation(); return dds::core::vector(); } ProjectDataManagement::ChargeType PpmHandler::chargeTypeFromId(int chargeTypeId) { auto it = m_chargeTypes.constFind(chargeTypeId); if (it == m_chargeTypes.constEnd() && m_dtcPdm) { m_dtcPdm->waitForHistoricalDataChargeType(); m_chargeTypes = m_dtcPdm->chargeTypes(); it = m_chargeTypes.constFind(chargeTypeId); } return (it == m_chargeTypes.constEnd()) ? ProjectDataManagement::ChargeType() : it.value(); } ProjectDataManagement::ChargeType PpmHandler::chargeTypeFromDisEntity(const std::string &disEntity) { if (m_chargeTypes.isEmpty() && m_dtcPdm) { m_dtcPdm->waitForHistoricalDataChargeType(); m_chargeTypes = m_dtcPdm->chargeTypes(); } for (const auto &item : qAsConst(m_chargeTypes)) { if (item.disEntity() == disEntity) return item; } return ProjectDataManagement::ChargeType(); } ProjectDataManagement::ChargeType PpmHandler::chargeTypeFromTasCodeDirect(int32_t tasCode) { if (m_chargeTypes.isEmpty() && m_dtcPdm) { m_dtcPdm->waitForHistoricalDataChargeType(); m_chargeTypes = m_dtcPdm->chargeTypes(); } for (const auto &item : qAsConst(m_chargeTypes)) { if (item.legacyId() == tasCode) return item; } return ProjectDataManagement::ChargeType(); } int PpmHandler::gearTypeIdFromChargeTypeId(int chargeTypeId) { if (m_gearTypeChargeTypes.isEmpty() && m_dtcPdm) { m_dtcPdm->waitForHistoricalDataGearTypeChargeType(); m_gearTypeChargeTypes = m_dtcPdm->gearTypeChargeTypes(); } int gearTypeId = 999999999; for (const auto &item : qAsConst(m_gearTypeChargeTypes)) { if (item.chargeTypeId() == chargeTypeId) if (item.gearTypeId() < gearTypeId) gearTypeId = item.gearTypeId(); } if (gearTypeId == 999999999) return 0; return gearTypeId; } rpr2::ForceIdentifierEnum8::ET PpmHandler::getRprForceIdentifierFromPpmForceIdentifier(const ParticipantManagement::HlaForceIdentifierEnum& ppmForceIdentifier) const { rpr2::ForceIdentifierEnum8::ET eqfi = rpr2::ForceIdentifierEnum8::Other; switch (ppmForceIdentifier.underlying()) { case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_1: eqfi = rpr2::ForceIdentifierEnum8::Friendly; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_2: eqfi = rpr2::ForceIdentifierEnum8::Friendly_2; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_3: eqfi = rpr2::ForceIdentifierEnum8::Friendly_3; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_4: eqfi = rpr2::ForceIdentifierEnum8::Friendly_4; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_5: eqfi = rpr2::ForceIdentifierEnum8::Friendly_5; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_6: eqfi = rpr2::ForceIdentifierEnum8::Friendly_6; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_7: eqfi = rpr2::ForceIdentifierEnum8::Friendly_7; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_8: eqfi = rpr2::ForceIdentifierEnum8::Friendly_8; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_9: eqfi = rpr2::ForceIdentifierEnum8::Friendly_9; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Friendly_10: eqfi = rpr2::ForceIdentifierEnum8::Friendly_10; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_1: eqfi = rpr2::ForceIdentifierEnum8::Opposing; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_2: eqfi = rpr2::ForceIdentifierEnum8::Opposing_2; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_3: eqfi = rpr2::ForceIdentifierEnum8::Opposing_3; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_4: eqfi = rpr2::ForceIdentifierEnum8::Opposing_4; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_5: eqfi = rpr2::ForceIdentifierEnum8::Opposing_5; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_6: eqfi = rpr2::ForceIdentifierEnum8::Opposing_6; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_7: eqfi = rpr2::ForceIdentifierEnum8::Opposing_7; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_8: eqfi = rpr2::ForceIdentifierEnum8::Opposing_8; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_9: eqfi = rpr2::ForceIdentifierEnum8::Opposing_9; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Opposing_10: eqfi = rpr2::ForceIdentifierEnum8::Opposing_10; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_1: eqfi = rpr2::ForceIdentifierEnum8::Neutral; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_2: eqfi = rpr2::ForceIdentifierEnum8::Neutral_2; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_3: eqfi = rpr2::ForceIdentifierEnum8::Neutral_3; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_4: eqfi = rpr2::ForceIdentifierEnum8::Neutral_4; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_5: eqfi = rpr2::ForceIdentifierEnum8::Neutral_5; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_6: eqfi = rpr2::ForceIdentifierEnum8::Neutral_6; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_7: eqfi = rpr2::ForceIdentifierEnum8::Neutral_7; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_8: eqfi = rpr2::ForceIdentifierEnum8::Neutral_8; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_9: eqfi = rpr2::ForceIdentifierEnum8::Neutral_9; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Neutral_10: eqfi = rpr2::ForceIdentifierEnum8::Neutral_10; break; case ParticipantManagement::HlaForceIdentifierEnum_def::Other: eqfi = rpr2::ForceIdentifierEnum8::Other; break; } return eqfi; } int PpmHandler::partyIdFromForceIdentifier(rpr2::ForceIdentifierEnum8::ET fi) { if (m_partyData.isEmpty() && m_dtcPpm) { m_dtcPpm->waitForHistoricalDataParty(); m_partyData = m_dtcPpm->partys(); } for (const ParticipantManagement::Party &item : qAsConst(m_partyData)) { if (fi == getRprForceIdentifierFromPpmForceIdentifier(item.hlaForceIdentifier())) return item.id(); } return -1; } rpr2::ForceIdentifierEnum8::ET PpmHandler::forceIdentifierFromPartyId(int partyId) { if (m_partyData.isEmpty() && m_dtcPpm) { m_dtcPpm->waitForHistoricalDataParty(); m_partyData = m_dtcPpm->partys(); } if (!m_partyData.contains(partyId)) return rpr2::ForceIdentifierEnum8::Other; return getRprForceIdentifierFromPpmForceIdentifier(m_partyData[partyId].hlaForceIdentifier()); } void PpmHandler::onModifyParticipantDataReply(const Core::FunctionReplyObject &replyObject) { m_requestHelper->requestReply(replyObject); } void PpmHandler::onDemandInitReply(const Core::FunctionReplyObject &reply) { m_requestHelper->requestReply(reply); } void PpmHandler::onDemandVulnerabilityStateChangeReply(const Core::FunctionReplyObject &reply) { m_requestHelper->requestReply(reply); } void PpmHandler::onSendCesHitInformationReply(const Core::FunctionReplyObject &reply) { m_requestHelper->requestReply(reply); } ParticipantPosition PpmHandler::getParticipantPosition(int participantId) const { auto itPartPos = m_partPosData.find(participantId); if (itPartPos == m_partPosData.end()) return ParticipantPosition(); ParticipantPosition pp(itPartPos.value().pos()); pp.msec = itPartPos.value().sampleTime(); return pp; } void PpmHandler::onParticipantHit(const GuezHitStruct &hitStruct) { const auto ct = chargeTypeFromDisEntity(hitStruct.originatorChargeTypeEtsString.toStdString()); TrainingAreaBase::TabPosition pos; pos.position(hitStruct.position); pos.reportingSource(Core::PositionReportingSource_def::External); TrainingAreaBase::EquipmentState es; es.equipmentNumber(hitStruct.targetId); es.originatorChargeTypeId(ct.id()); if (hitStruct.originatorType.underlying() == ProjectDataManagement::StateChangeOriginator_def::AreaEffectSimulation) { int aesItemId = 0; if (m_dtcAes->aesItemIdFromExternalId(hitStruct.originatorId, aesItemId) == AreaEffectSimulation::AesType_def::AtUnknown) es.originatorId(hitStruct.originatorId % 10); // Not found, therefore it is our AesItem that is sent with (AesItemId * 10) else es.originatorId(aesItemId); } else { es.originatorId(hitStruct.originatorId); } es.originatorType(hitStruct.originatorType); es.sampleTime(hitStruct.sampleTime); es.vulnerabilityBits(hitStruct.vulnerabilityBits); es.vulnerabilityKindId(hitStruct.vulnerabilityKind); es.vulnerabilityState(hitStruct.vulnerabilityState); if (!qIsNull(hitStruct.position.lat()) || !qIsNull(hitStruct.position.lon())) es.position(pos); m_dtsTab->publish(es); // Damage Model recognizes change of Manipulation for itself and calls the Slot all by itself. // onManipulationChanged(hitStruct.targetId, hitStruct.vulnerabilityBits & rpr2::TotalStatusEnum32::Manipulation, es.sampleTime()); } void PpmHandler::onParticipantInit(int eqNo, bool resetManipulation, bool resupplyAmmo, bool resetVulnerabilityState) { TrainingAreaBase::DemandInitRequest dir; dir.equipmentNumbers().push_back(eqNo); dir.requestId(1); dir.resetManipulation(resetManipulation); dir.restockCharges(resupplyAmmo); dir.resetVulnerabilityState(resetVulnerabilityState); m_requestHelper->startSingleRequest([this, dir]() { return m_ftcTab->demandInitRequest(dir, this); }); } void PpmHandler::onParticipantCesHit(const TrainingAreaBase::SendCesHitInformation &request) { m_ftcTab->sendCesHitInformationRequest(request, this); } void PpmHandler::onLaserDesignation(const TrainingAreaBase::LaserDesignation &request) { m_dtsTab->publish(request); } void PpmHandler::onWeaponFire(const TrainingAreaBase::EquipmentGearEvent &event) { m_dtsTab->publish(event); } void PpmHandler::onGearChargeState(const TrainingAreaBase::EquipmentGearChargeState &event) { m_dtsTab->publish(event); } void PpmHandler::onGearAssignment(const TrainingAreaBase::EquipmentGearAssignment &event) { m_dtsTab->publish(event); } void PpmHandler::onEquipmentState(const TrainingAreaBase::EquipmentState &event) { m_dtsTab->publish(event); } bool PpmHandler::onExconEngagement(int eqNo, const ProjectDataManagement::VulnerabilityState &state) { if (state != ProjectDataManagement::VulnerabilityState_def::CombatReady) { TrainingAreaBase::DemandVulnerabilityStateChangeRequest req; req.equipmentNumbers().push_back(eqNo); req.requestId(1); // irrelevant req.vulnerabilityState(state); return m_requestHelper->startSingleRequest([this, req]() { return m_ftcTab->demandVulnerabilityStateChangeRequest(req, this); }); } TrainingAreaBase::DemandInitRequest req; req.equipmentNumbers().push_back(eqNo); req.resetVulnerabilityState(true); return m_requestHelper->startSingleRequest([this, req]() { return m_ftcTab->demandInitRequest(req, this); }); } } // namespace HighLevelArchitecture