1024 lines
36 KiB
C++
Executable File
1024 lines
36 KiB
C++
Executable File
/**
|
|
* 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 <Common/participantinformation.h>
|
|
|
|
#include <LtsUtilsGuiDds/request_helper.h>
|
|
#include <EntityTypeStruct.h>
|
|
#include <Proxies/TrainingAreaBase/tab.hpp>
|
|
|
|
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<NgsConnector> 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<ParticipantManagement::GearInformation> oldGear = m_dynPartData.value(data.participantId()).gear();
|
|
const std::vector<ParticipantManagement::GearInformation> &newGear = data.gear();
|
|
// check if sth. changed
|
|
if (oldGear != newGear)
|
|
{
|
|
// Something to do? Gear not necessary on HLA...?
|
|
}
|
|
const std::vector<ParticipantManagement::ManipulationInformation> oldMani = m_dynPartData.value(data.participantId()).manipulation();
|
|
const std::vector<ParticipantManagement::ManipulationInformation> &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<rti::core::int64> 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<rpr2::TacticalStatusEnum8::ET>(sh.at(idxCurrent).vulnerabilityState().underlying());
|
|
ts.VulnerabilityKind = sh.at(idxCurrent).vulnerabilityKindId();
|
|
ts.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(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<ParticipantManagement::GearInformation> PpmHandler::currentParticipantGearInformation(int participantId) const
|
|
{
|
|
auto itPartData = m_dynPartData.find(participantId);
|
|
if (itPartData != m_dynPartData.end())
|
|
return itPartData.value().gear();
|
|
return std::vector<ParticipantManagement::GearInformation>();
|
|
}
|
|
|
|
std::vector<ParticipantManagement::ManipulationInformation> PpmHandler::currentParticipantManipulationInformation(int participantId) const
|
|
{
|
|
auto itPartData = m_dynPartData.find(participantId);
|
|
if (itPartData != m_dynPartData.end())
|
|
return itPartData.value().manipulation();
|
|
return std::vector<ParticipantManagement::ManipulationInformation>();
|
|
}
|
|
|
|
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<int32_t>();
|
|
// 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
|