/** * 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_dtcTab.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_dtcTab = TrainingAreaBase::Interface::Dtc::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); connect(m_dtcPpm.get(), &ParticipantManagement::Interface::Dtc::participantGearEventChanged, this, &PpmHandler::onParticipantGearEventChanged); m_dtcPpm->enableType(); m_dtcPpm->enableDynamicParticipantData(); m_dtcPpm->enableParticipant(); m_dtcPpm->enableParticipantPosition(); m_dtcPpm->enableParty(); m_dtcPpm->enableParticipantGearEvent(); 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->enableEquipmentBite()) ) { ERROR_LOG(m_logger) << "Enabling TAB DTS Data-Topics failed."; return false; } // TAB TDC connect(m_dtcTab.get(), &TrainingAreaBase::Interface::Dtc::equipmentBiteChanged, this, &PpmHandler::onEquipmentBiteChanged); m_dtcTab->enableEquipmentBite(); // TAB FTC m_ftcTab->enableDemandInit(); m_ftcTab->enableDemandParticipantMode(); m_ftcTab->enableDemandBite(); // 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::guezHit, this, &PpmHandler::onParticipantHit); connect(conn, &NgsConnector::participantReceivedInit, this, &PpmHandler::onParticipantReceivedInit); connect(conn, &NgsConnector::guezInit, this, &PpmHandler::onParticipantInit); connect(conn, &NgsConnector::biteReport, this, &PpmHandler::onBiteReport); connect(conn, &NgsConnector::biteRequest, this, &PpmHandler::onBiteRequest); connect(conn, &NgsConnector::weaponFire, this, &PpmHandler::onWeaponFire); connect(conn, &NgsConnector::isPartOfChanged, this, &PpmHandler::onIsPartOfChanged); 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()); } } const std::vector oldGear = m_dynPartData.value(data.participantId()).gear(); const std::vector &newGear = data.gear(); // check if sth. changed if (oldGear != newGear) { // Something to do? Gear not necessary on HLA...? } const std::vector oldMani = m_dynPartData.value(data.participantId()).manipulation(); const std::vector &newMani = data.manipulation(); // check if sth. changed if (oldMani != newMani) { // Todo: Compare each to each? How to delete Manipulations? // for (const auto x : newMani) // conn->setManipulation(data.participantId(), x); } 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())); if (m_partData[data.id()].partyId() != data.partyId() && data.equipmentNumber().is_set()) m_ngsHandler->ngsConnector()->setParticipantForce(data.equipmentNumber().get(), forceIdentifierFromPartyId(data.partyId())); 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()); int mountedOnEqNo = data.mountedOn().is_set() ? getEquipmentNo(data.mountedOn().get()) : 0; m_ngsHandler->ngsConnector()->setWorldLocation(eqNo, pos, mountedOnEqNo); } 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); } // HLA -> DDS void PpmHandler::onParticipantReceivedInit(int eqId, qint64 simTimeMSecs) { TrainingAreaBase::EquipmentState init; init.equipmentNumber(eqId); init.sampleTime(simTimeMSecs); init.vulnerabilityBits(1); init.vulnerabilityState(ProjectDataManagement::VulnerabilityState_def::CombatReady); init.originatorType(ProjectDataManagement::StateChangeOriginator_def::ExerciseControl); m_dtsTab->publish(init); } 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; } } void PpmHandler::onParticipantGearEventChanged(const ParticipantManagement::ParticipantGearEvent &data, DataModification modType) { if (modType != DataModification::eRemoved) m_ngsHandler->ngsConnector()->setWeaponFire(getEquipmentNo(data.participantId()), data); } // 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::onEquipmentBiteChanged(const TrainingAreaBase::EquipmentBite &data, DataModification modType) { if (modType != DataModification::eRemoved) m_ngsHandler->ngsConnector()->setEquipmentBite(data.equipmentNumber(), data); } 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); } void PpmHandler::participantBiteRequest(const TrainingAreaBase::TetraIcd::DemandBite &request) { m_ngsHandler->ngsConnector()->sendParticipantBiteRequest(request.header.equipmentNumber, request.withSelfTest, request.header.timeStamp); } void PpmHandler::createParticipant(const ParticipantManagement::Participant &participant) { // Only create participants that have no external ID. if (participant.externalId() > 0 || !participant.equipmentNumber().is_set() || participant.isDeleted() || participant.equipmentNumber().get() == 0) 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::SupportEntity: bCreated = createObserverController(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::createHuman(const ParticipantManagement::Participant &participant) { const ParticipantInformation pi(participant, getTypestruct(participant.typeId()), getParticipantPosition(participant.id())); return m_ngsHandler->ngsConnector()->addHuman(pi, currentTacticalStatus(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, currentTacticalStatus(participant.id())); } bool PpmHandler::createObserverController(const ParticipantManagement::Participant &participant) { const ParticipantInformation pi(participant, getTypestruct(participant.typeId()), getParticipantPosition(participant.id())); return m_ngsHandler->ngsConnector()->addObserverController(pi); } TypeStruct PpmHandler::getTypestruct(int typeId) { std::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(); } rpr2::TacticalStatusStruct PpmHandler::currentTacticalStatus(int participantId) const { rpr2::TacticalStatusStruct ts; ts.VulnerabilityKind = rpr2::TacticalStatusEnum8::ET::CombatReady; ts.TotalStatus = rpr2::TotalStatusEnum32::ET::CombatReady; 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.TacticalStatus = static_cast(sh.at(idxCurrent).vulnerabilityState().underlying()); ts.VulnerabilityKind = sh.at(idxCurrent).vulnerabilityKindId(); ts.TotalStatus = static_cast(sh.at(idxCurrent).vulnerabilityBits()); return ts; } } ts.TacticalStatus = rpr2::TacticalStatusEnum8::TemporaryFailure; 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); } std::vector PpmHandler::currentParticipantGearInformation(int participantId) const { auto itPartData = m_dynPartData.find(participantId); if (itPartData != m_dynPartData.end()) return itPartData.value().gear(); return std::vector(); } std::vector PpmHandler::currentParticipantManipulationInformation(int participantId) const { auto itPartData = m_dynPartData.find(participantId); if (itPartData != m_dynPartData.end()) return itPartData.value().manipulation(); return std::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); m_dtcPdm = nullptr; } 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(); m_dtcPdm = nullptr; } for (const auto &item : qAsConst(m_chargeTypes)) { if (item.disEntity() == disEntity) return item; } return ProjectDataManagement::ChargeType(); } 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::onDemandBiteReply(const Core::FunctionReplyObject &reply) { m_requestHelper->requestReply(reply); } void PpmHandler::onSendParticipantModeReply(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 & 0xffff) / 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::onManipulationChanged(int eqNo, bool playerIsManipulated, qint64 sampleTime) { // Set Manipulation: TrainingAreaBase::EquipmentOperationalState eos; eos.equipmentNumber(eqNo); eos.isManipulation(playerIsManipulated); eos.sampleTime(sampleTime); m_dtsTab->publish(eos); } void PpmHandler::onWeaponFire(const TrainingAreaBase::EquipmentGearEvent &event) { m_dtsTab->publish(event); } void PpmHandler::onIsPartOfChanged(int eqNo, int eqNoHost, qint64 simTimeMSecs) { // Look up the old host - if any. int eqNoOldHost = m_isMountedOn.value(eqNo, 0); if (eqNoOldHost == eqNoHost) return; // Store the new host - to be the old host next time if (eqNoHost == 0) m_isMountedOn.remove(eqNo); else m_isMountedOn.insert(eqNo, eqNoHost); // Has a (new) host now? (Aufgesessen?) if (eqNoHost > 0) { // Get new Host TrainingAreaBase::EquipmentPosition &newHost = m_observerPositions[eqNoHost]; // Add Participant to Host, no ref here auto mountedParticipants = newHost.mountedParticipants().is_set() ? newHost.mountedParticipants().get() : std::vector(); // We assume, he wasn't mounted on the same before, so we simply add him to the party. mountedParticipants.push_back(eqNo); // Re-insert the mounted participants to new Host newHost.mountedParticipants(mountedParticipants); // Update Timestamp and fire newHost.sampleTime(simTimeMSecs); m_dtsTab->publish(newHost); } // Had an old host? (Abgesessen?) if (eqNoOldHost > 0) { TrainingAreaBase::EquipmentPosition &oldHost = m_observerPositions[eqNoOldHost]; // Get old Host if (!oldHost.mountedParticipants().is_set()) return; // Remove Participant from host, ref here auto &mountedParticipants = oldHost.mountedParticipants().get(); auto newEnd = std::remove(mountedParticipants.begin(), mountedParticipants.end(), eqNo); auto distance = std::distance(newEnd, mountedParticipants.end()); // If nothing is removed, skip further processing if (distance == 0) return; // Crop to actual length mountedParticipants.resize(mountedParticipants.size() - distance); // No re-inserting necessary. We work on references! // Update Timestamp and fire oldHost.sampleTime(simTimeMSecs); m_dtsTab->publish(oldHost); } } bool PpmHandler::onExconInit(int eqNo, rpr2::ResetPlayerEnum8::ET rp, rpr2::ActivateHelmetObservationEnum8::ET aho ) { TrainingAreaBase::DemandInitRequest req; req.equipmentNumbers().push_back(eqNo); req.resetVulnerabilityState(true); req.restockCharges(rp == rpr2::ResetPlayerEnum8::CombatReadyWithReammunition); if (rp != rpr2::ResetPlayerEnum8::NoChange) { m_requestHelper->addRequest([this, req]() { return m_ftcTab->demandInitRequest(req, this); }); } ProjectDataManagement::WphMode helmet = ProjectDataManagement::WphMode_def::NoChange;; ProjectDataManagement::WphMode vest = ProjectDataManagement::WphMode_def::NoChange; bool bNoChange = false; switch (aho) { case rpr2::ActivateHelmetObservationEnum8::WithoutHelmetWithoutVest: helmet = ProjectDataManagement::WphMode_def::Without; vest = ProjectDataManagement::WphMode_def::Without; break; case rpr2::ActivateHelmetObservationEnum8::HelmetWithoutVest: helmet = ProjectDataManagement::WphMode_def::With; vest = ProjectDataManagement::WphMode_def::Without; break; case rpr2::ActivateHelmetObservationEnum8::HelmetAndVest: helmet = ProjectDataManagement::WphMode_def::With; vest = ProjectDataManagement::WphMode_def::With; break; case rpr2::ActivateHelmetObservationEnum8::NoChange: helmet = ProjectDataManagement::WphMode_def::NoChange; vest = ProjectDataManagement::WphMode_def::NoChange; bNoChange = true; break; } if (!bNoChange) { TrainingAreaBase::SendParticipantModeRequest mreq; mreq.protectionModeHelmet(helmet); mreq.protectionModeVest(vest); mreq.equipmentNumber(eqNo); m_requestHelper->addRequest([this, mreq]() { return m_ftcTab->sendParticipantModeRequest(mreq, this); }); } return m_requestHelper->startRequests(); } bool PpmHandler::onBiteReport(const TrainingAreaBase::EquipmentBite &report) { DEBUG_LOG(m_logger) << "Attempting to Forward Bite Report to DDS. dtsTab: " << m_dtsTab << ", report for EqId: " << report.equipmentNumber(); if (!m_dtsTab) return false; return m_dtsTab->publish(report); } bool PpmHandler::onBiteRequest(const TrainingAreaBase::DemandBiteRequest &request) { if (!m_ftcTab) return false; return m_ftcTab->demandBiteRequest(request, this); } } // namespace HighLevelArchitecture