Files
qt5-legatus-legacy/Lts/Proxies/HighLevelArchitecture/Hla_test_tool/ngs_connector.cpp
T
2026-08-13 18:33:10 +02:00

2504 lines
95 KiB
C++
Executable File

/**
* Connect to ngs / hla and provide the basic interface
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Ehrlicher, SLSE, 2017-04-07
*/
#include "ngs_connector.h"
#include "ngs_handler.h"
#include "damage_model.h"
#include <Common/settings.h>
#include <Common/player_callback.h>
#include <Common/identifierstruct.h>
#include <Common/participantinformation.h>
#include "../Guez/rpr/rpr_observer_guez_human_cb_notifier.h"
#include "../Guez/rpr/rpr_observer_guez_groundvehicle_cb_notifier.h"
#include "../Guez/rpr/rpr_observer_guez_observer_controller_cb_notifier.h"
#include "../Guez/rpr/rpr_observer_guez_minefield_cb_notifier.h"
#include "../Guez/rpr/rpr_observer_guez_minefield_breach_cb_notifier.h"
#include "../Guez/rpr/rpr_observer_guez_fire_support_single_shot_cb_notifier.h"
#include "../Guez/rpr/rpr_ia_munitiondetonation.h"
#include "../Guez/rpr/rpr_ia_weaponfire.h"
#include "../Guez/rpr/rpr_ia_guez_hit.h"
#include "../Guez/rpr/rpr_ia_guez_init.h"
#include "../Guez/rpr/rpr_ia_guez_exconengagement.h"
#include "../Guez/rpr/rpr_ia_guez_bitereport.h"
#include "../Guez/rpr/rpr_ia_guez_requestbitereport.h"
#include <NGSException.h>
#include <QTimer>
#include <QPolygonF>
#include <QTransform>
#include <QDateTime>
#include <LtsCoordTrans/lts_coord_trans.h>
#include <AreaEffectSimulation/aes_enums.hpp>
#include <SimulatedWorldAPI.h>
#include <EventIdentifierStruct.h>
#include <SpatialStruct.h>
#include <IsPartOfStruct.h>
#include <EnvironmentObjectTypeStruct.h>
#include <BiteResultStruct.h>
#include <IObserverGuezHumanObjClass.h>
#include <IObserverGuezObserverControllerObjClass.h>
#include <IObserverGuezGroundVehicleObjClass.h>
#include <IObserverGuezMineFieldObjClass.h>
#include <IObserverGuezMineFieldBreachObjClass.h>
#include <IObserverMunitionDetonationIntClass.h>
#include <IObserverMunitionDetonationIntInstance.h>
#include <IObserverWeaponFireIntClass.h>
#include <IObserverWeaponFireIntInstance.h>
#include <IObserverGuezHitIntClass.h>
#include <IObserverGuezHitIntInstance.h>
#include <IObserverGuezInitIntClass.h>
#include <IObserverGuezInitIntInstance.h>
#include <IObserverGuezBiteReportIntClass.h>
#include <IObserverGuezRequestBiteReportIntClass.h>
#include <IPlayerGuezHumanObjClass.h>
#include <IPlayerGuezHumanObjInstance.h>
#include <IPlayerGuezObserverControllerObjClass.h>
#include <IPlayerGuezObserverControllerObjInstance.h>
#include <IPlayerGuezGroundVehicleObjClass.h>
#include <IPlayerGuezGroundVehicleObjInstance.h>
#include <IPlayerGuezMineFieldBreachObjClass.h>
#include <IPlayerGuezMineFieldBreachObjInstance.h>
#include <IPlayerGuezMineFieldObjClass.h>
#include <IPlayerGuezMineFieldObjInstance.h>
#include <IPlayerGuezChemicalAgentAreaObjClass.h>
#include <IPlayerGuezChemicalAgentAreaObjInstance.h>
#include <IPlayerGuezNuclearAgentAreaObjClass.h>
#include <IPlayerGuezNuclearAgentAreaObjInstance.h>
#include <IPlayerWeaponFireIntClass.h>
#include <IPlayerWeaponFireIntInstance.h>
#include <IPlayerGuezHitIntClass.h>
#include <IPlayerGuezHitIntInstance.h>
#include <IPlayerMunitionDetonationIntClass.h>
#include <IPlayerMunitionDetonationIntInstance.h>
#include <IPlayerGuezRequestBiteReportIntClass.h>
#include <IPlayerGuezRequestBiteReportIntInstance.h>
#include <IPlayerGuezBiteReportIntClass.h>
#include <IPlayerGuezBiteReportIntInstance.h>
#include <IPlayerGuezInitIntClass.h>
#include <IPlayerGuezInitIntInstance.h>
#include <IPlayerSOM.h>
using namespace AreaEffectSimulation;
namespace HighLevelArchitecture
{
static inline qint64 simTimeToMSec(const ngs::SimTime &st)
{
qint64 mSecs = st.getSeconds() * 1000LL;
mSecs += st.getMicroSeconds() / 1000;
return mSecs;
}
static inline rpr2::SpatialStruct spatialStructFromWorldLocation(const rpr2::WorldLocationStruct &wls)
{
rpr2::SpatialStaticStruct sss;
sss.WorldLocation = wls;
sss.IsFrozen = false;
sss.Orientation.Phi = 3.138309f;
sss.Orientation.Psi = 2.446645f;
sss.Orientation.Theta = -0.879588f;
rpr2::SpatialStruct ss;
ss.DeadReckoningAlgorithm__A__Alternatives.discriminant(rpr2::DeadReckoningAlgorithmEnum8::Static);
ss.DeadReckoningAlgorithm__A__Alternatives.SpatialStatic(sss);
return ss;
}
static inline rpr2::EnvironmentObjectTypeStruct dummyEOS()
{
return {2, 3, 4, 5};
}
//
// NgsConnector
//
NgsConnector::NgsConnector(const QString &fedName, NgsHandler *ngsHandler)
: m_ngsHandler(ngsHandler)
, m_fedName(fedName)
, m_swadmin(&ngs::SimulatedWorldAPI::getSimulatedWorldAdmin())
, m_master(nullptr)
, m_somPlayer(nullptr)
, m_playerCallback(new PlayerCallback())
, m_humanCallback(new ObserverGuezHumanCBNotifier())
, m_observerControllerCallback(new ObserverGuezObserverControllerCBNotifier())
, m_groundVehicleCallback(new ObserverGuezGroundVehicleCBNotifier())
, m_minefieldCallback(new ObserverGuezMineFieldCBNotifier())
, m_minefieldBreachCallback(new ObserverGuezMineFieldBreachCBNotifier())
, m_munitionDetonationCallback(new ObserverMunitionDetonationCBNotifier())
, m_weaponfireCallback(new ObserverWeaponFireCBNotifier())
, m_hitCallback(new ObserverGuezHitCBNotifier())
, m_initCallback(new ObserverGuezInitCBNotifier())
, m_biteReportCallback(new ObserverGuezBiteReportCBNotifier())
, m_requestBiteReportCallback(new ObserverGuezRequestBiteReportCBNotifier())
, m_bInitialized(false)
, m_bCanPublishData(false)
, m_timer(new QTimer(this))
, m_logger(getLogger("NgsConnector"))
{
connect(m_timer, &QTimer::timeout,
this, &NgsConnector::go);
connect(m_playerCallback, &PlayerCallback::firstTick,
this, &NgsConnector::onFirstTickFinished);
// Ground Vehicle
connectObserverGuezGroundVehicleObjectSignals(m_groundVehicleCallback);
// Human
connectObserverGuezHumanObjectSignals(m_humanCallback);
// Observer / Controller
connectObserverGuezObserverControllerObjectSignals(m_observerControllerCallback);
// Mine Field
connectObserverGuezMineFieldObjectSignals(m_minefieldCallback);
// Mine Field Breach
connectObserverGuezMineFieldBreachObjectSignals(m_minefieldBreachCallback);
// Munition Detonation
connect(m_munitionDetonationCallback, &ObserverMunitionDetonationCBNotifier::newMunitionDetonation,
this, &NgsConnector::onNewMunitionDetonation);
// Weapon Fire
connect(m_weaponfireCallback, &ObserverWeaponFireCBNotifier::newWeaponFire,
this, &NgsConnector::onNewWeaponFire);
// Hit
connect(m_hitCallback, &ObserverGuezHitCBNotifier::newGuezHit,
this, &NgsConnector::onNewGuezHit);
// Init
connect(m_initCallback, &ObserverGuezInitCBNotifier::newGuezInit,
this, &NgsConnector::onNewGuezInit);
// Request Bite Report
connect(m_requestBiteReportCallback, &ObserverGuezRequestBiteReportCBNotifier::newGuezRequestBiteReport,
this, &NgsConnector::onNewGuezRequestBiteReport);
// Bite Report
connect(m_biteReportCallback, &ObserverGuezBiteReportCBNotifier::newGuezBiteReport,
this, &NgsConnector::onNewGuezBiteReport);
}
NgsConnector::~NgsConnector()
{
uninitialize();
delete m_playerCallback;
delete m_humanCallback;
delete m_observerControllerCallback;
delete m_groundVehicleCallback;
delete m_minefieldCallback;
delete m_minefieldBreachCallback;
delete m_munitionDetonationCallback;
delete m_weaponfireCallback;
delete m_initCallback;
delete m_hitCallback;
delete m_requestBiteReportCallback;
delete m_biteReportCallback;
delete m_timer;
}
bool NgsConnector::initialize(ngs::IObserver::ProtocolType protocol, const QString &playerName, const QString &appDirPath)
{
QString swconf = appDirPath + QLatin1Char('/') + Settings::swConfFileName();
m_bInitialized = true;
// NGS Initialisation
try
{
m_master = &m_swadmin->getIFederationMaster(protocol, qPrintable(swconf), Settings::fomIdentifier().toStdString(), Settings::rtiIdentifier().toStdString()); // "", "MAK"
}
catch (const ngs::NGSSimWorldException &e)
{
ERROR_LOG(m_logger) << "caught exception during init (getIFederationMaster): " << e.print();
return false;
}
ngs::IPlayer *player = nullptr;
switch (protocol)
{
case ngs::IObserver::HLA:
{
try
{
m_master->createFederation(m_fedName.toStdString());
}
catch (const NGSException &e)
{
ERROR_LOG(m_logger) << "caught exception during init (createFederation): " << e.print();
return false;
}
player = &m_swadmin->getIPlayer(m_fedName.toStdString(), playerName.toStdString(), *m_playerCallback, Settings::swConfFileName().toLatin1().data(), Settings::fomIdentifier().toStdString(), Settings::rtiIdentifier().toStdString());
break;
}
case ngs::IObserver::CORBANOTIFY:
case ngs::IObserver::DIS:
{
unsigned char federationId = m_fedName.toUShort();
m_master->createFederation(federationId);
player = &m_swadmin->getIPlayer(federationId, playerName.toStdString(), *m_playerCallback, protocol, Settings::swConfFileName().toLatin1().data(), Settings::fomIdentifier().toStdString());
break;
}
}
m_somPlayer = dynamic_cast<rpr2::IPlayerSOM *>(player);
m_somPlayer->configureSimTime(ngs::IObserver::REALTIMECLOCK, ngs::SimTime(0, 0));
m_timer->start(10);
return true;
}
void NgsConnector::uninitialize()
{
if (!m_bInitialized)
return;
m_bInitialized = false;
m_timer->stop();
unsubscribeFromNgs();
if (m_swadmin)
m_swadmin->resignInterface();
if (m_somPlayer)
m_somPlayer->resignSimulatedWorld();
if (m_master)
{
m_master->destroyFederation(m_fedName.toStdString());
m_master->resignInterface();
m_master = nullptr;
}
}
void NgsConnector::subscribeAtNgs()
{
m_enitityNumberCounter = 1; // restart
m_eventCount = 1;
INFO_LOG(m_logger) << "Subscribe at NGS - Guez Human Objects";
rpr2::IObserverGuezHumanObjClass &humanObjClass = m_somPlayer->getObserverGuezHumanObjClass(*m_humanCallback);
humanObjClass.subscribeAllAttributes();
humanObjClass.subscribe();
INFO_LOG(m_logger) << "Subscribe at NGS - Guez ObserverController Objects";
rpr2::IObserverGuezObserverControllerObjClass &observerControllerObjClass = m_somPlayer->getObserverGuezObserverControllerObjClass(*m_observerControllerCallback);
observerControllerObjClass.subscribeAllAttributes();
observerControllerObjClass.subscribe();
INFO_LOG(m_logger) << "Subscribe at NGS - Guez GroundVehicle Objects";
rpr2::IObserverGuezGroundVehicleObjClass &groundVehicleObjClass = m_somPlayer->getObserverGuezGroundVehicleObjClass(*m_groundVehicleCallback);
groundVehicleObjClass.subscribeAllAttributes();
groundVehicleObjClass.subscribe();
INFO_LOG(m_logger) << "Subscribe at NGS - Guez MineField Objects";
rpr2::IObserverGuezMineFieldObjClass &minefieldObjClass = m_somPlayer->getObserverGuezMineFieldObjClass(*m_minefieldCallback);
minefieldObjClass.subscribeAllAttributes();
minefieldObjClass.subscribe();
INFO_LOG(m_logger) << "Subscribe at NGS - Guez MineField Breach Objects";
rpr2::IObserverGuezMineFieldBreachObjClass &minefieldBreachObjClass = m_somPlayer->getObserverGuezMineFieldBreachObjClass(*m_minefieldBreachCallback);
minefieldBreachObjClass.subscribeAllAttributes();
minefieldBreachObjClass.subscribe();
rpr2::IObserverMunitionDetonationIntClass &md = m_somPlayer->getObserverMunitionDetonationIntClass(*m_munitionDetonationCallback);
md.subscribe();
rpr2::IObserverWeaponFireIntClass &wfic = m_somPlayer->getObserverWeaponFireIntClass(*m_weaponfireCallback);
wfic.subscribe();
rpr2::IObserverGuezInitIntClass &giic = m_somPlayer->getObserverGuezInitIntClass(*m_initCallback);
giic.subscribe();
rpr2::IObserverGuezHitIntClass &ghic = m_somPlayer->getObserverGuezHitIntClass(*m_hitCallback);
ghic.subscribe();
rpr2::IObserverGuezRequestBiteReportIntClass &grbric = m_somPlayer->getObserverGuezRequestBiteReportIntClass(*m_requestBiteReportCallback);
grbric.subscribe();
rpr2::IObserverGuezBiteReportIntClass &gbric = m_somPlayer->getObserverGuezBiteReportIntClass(*m_biteReportCallback);
gbric.subscribe();
m_timer->start();
m_bCanPublishData = true;
}
void NgsConnector::unsubscribeFromNgs()
{
m_bCanPublishData = false;
if (m_somPlayer)
{
INFO_LOG(m_logger) << "Unsubscribe at NGS - Guez Human Objects";
rpr2::IObserverGuezHumanObjClass &humanObjClass = m_somPlayer->getObserverGuezHumanObjClass(*m_humanCallback);
humanObjClass.unsubscribe();
INFO_LOG(m_logger) << "Unsubscribe at NGS - Guez ObserverController Objects";
rpr2::IObserverGuezObserverControllerObjClass &observerControllerObjClass = m_somPlayer->getObserverGuezObserverControllerObjClass(*m_observerControllerCallback);
observerControllerObjClass.unsubscribe();
INFO_LOG(m_logger) << "Unsubscribe at NGS - Guez GroundVehicle Objects";
rpr2::IObserverGuezGroundVehicleObjClass &groundVehicleObjClass = m_somPlayer->getObserverGuezGroundVehicleObjClass(*m_groundVehicleCallback);
groundVehicleObjClass.unsubscribe();
INFO_LOG(m_logger) << "Unsubscribe at NGS - Guez MineField Objects";
rpr2::IObserverGuezMineFieldObjClass &minefieldObjClass = m_somPlayer->getObserverGuezMineFieldObjClass(*m_minefieldCallback);
minefieldObjClass.unsubscribe();
INFO_LOG(m_logger) << "Unsubscribe at NGS - Guez MineField Breach Objects";
rpr2::IObserverGuezMineFieldBreachObjClass &minefieldBreachObjClass = m_somPlayer->getObserverGuezMineFieldBreachObjClass(*m_minefieldBreachCallback);
minefieldBreachObjClass.unsubscribe();
}
for (rpr2::IPlayerBaseEntityObjInstance *player : qAsConst(m_playerMap))
player->deleteObjectInstance(getSimTime());
m_playerMap.clear();
for (rpr2::IPlayerEnvironmentObjectObjInstance *environmentObject : qAsConst(m_environmentObjects))
environmentObject->deleteObjectInstance(getSimTime());
m_environmentObjects.clear();
for (auto it = m_observerPlayerInstances.cbegin(); it != m_observerPlayerInstances.cend(); ++it)
emit virtualParticipantDeleted(it.key());
for (auto it = m_observerEnvironmentObjects.cbegin(); it != m_observerEnvironmentObjects.cend(); ++it)
emit virtualParticipantDeleted(it.key());
m_observerPositions.clear();
m_newObjectsWithoutParticipantIdSet.clear();
m_observerPlayerInstances.clear();
m_observerEnvironmentObjects.clear();
qDeleteAll(m_damageModelMap);
m_damageModelMap.clear();
m_enitityNumberCounter = 1; // restart
m_eventCount = 1;
}
bool NgsConnector::addHuman(const ParticipantInformation &participantData,
const rpr2::TacticalStatusStruct &state)
{
if (m_playerMap.contains(participantData.equipmentNo))
return false;
DEBUG_LOG(getLogger("NgsConnector.Outbound.Startup"))
<< "addHuman("
<< participantData.equipmentNo << ", "
<< participantData.partyId << ", "
<< participantData.typeStruct.toString() << ", "
<< state.TacticalStatus << ")";
rpr2::IPlayerGuezHumanObjClass &player = m_somPlayer->getPlayerGuezHumanObjClass();
rpr2::IPlayerGuezHumanObjInstance *playerInstance = &player.newGuezHumanObjInstance();
DamageModel dm(state);
playerInstance->setDamageState(dm.damageState(-1));
playerInstance->setImmobilized(dm.immobilized(-1));
playerInstance->setFirePowerDisabled(dm.firePowerDisabled(-1));
playerInstance->setTacticalStatus(state);
return addPhysicalEntity(playerInstance, participantData);
}
bool NgsConnector::addObserverController(const ParticipantInformation &participantData)
{
if (m_playerMap.contains(participantData.equipmentNo))
return false;
DEBUG_LOG(getLogger("NgsConnector.Outbound.Startup"))
<< "addObserverController("
<< participantData.equipmentNo << ", "
<< participantData.partyId << ", "
<< participantData.typeStruct.toString() << ")";
rpr2::IPlayerGuezObserverControllerObjClass &player = m_somPlayer->getPlayerGuezObserverControllerObjClass();
rpr2::IPlayerGuezObserverControllerObjInstance *playerInstance = &player.newGuezObserverControllerObjInstance();
return addPhysicalEntity(playerInstance, participantData);
}
bool NgsConnector::addGroundVehicle(const ParticipantInformation &participantData,
const rpr2::TacticalStatusStruct &state)
{
if (m_playerMap.contains(participantData.equipmentNo))
return false;
DEBUG_LOG(getLogger("NgsConnector.Outbound.Startup"))
<< "addGroundVehicle("
<< participantData.equipmentNo << ", "
<< participantData.partyId << ", "
<< participantData.typeStruct.toString() << ", "
<< state.TacticalStatus << ")";
rpr2::IPlayerGuezGroundVehicleObjClass &player = m_somPlayer->getPlayerGuezGroundVehicleObjClass();
rpr2::IPlayerGuezGroundVehicleObjInstance *playerInstance = &player.newGuezGroundVehicleObjInstance();
DamageModel dm(state);
playerInstance->setDamageState(dm.damageState(-1));
playerInstance->setImmobilized(dm.immobilized(-1));
playerInstance->setFirePowerDisabled(dm.firePowerDisabled(-1));
playerInstance->setTacticalStatus(state);
return addPhysicalEntity(playerInstance, participantData);
}
bool NgsConnector::addBaseEntity(rpr2::IPlayerBaseEntityObjInstance *playerInstance,
const ParticipantInformation &participantData)
{
if (m_playerMap.contains(participantData.equipmentNo))
return false;
if (participantData.equipmentNo == 0)
return false;
IdentifierStruct is(participantData.equipmentNo);
m_playerMap.insert(participantData.equipmentNo, playerInstance);
playerInstance->setEntityType(participantData.typeStruct.toETS());
playerInstance->setEntityIdentifier(is.toEIS());
playerInstance->publish(getSimTime(participantData.position.msec));
DEBUG_LOG(getLogger("NgsConnector.Outbound.Startup")) << "Published Participant " << is.toString();
return true;
}
bool NgsConnector::addPhysicalEntity(rpr2::IPlayerPhysicalEntityObjInstance *playerInstance,
const ParticipantInformation &playerData)
{
rpr2::MarkingStruct ms = toMarkingStruct(playerData.designator);
playerInstance->setMarking(ms);
rpr2::ForceIdentifierEnum8::ET forceId = rpr2::ForceIdentifierEnum8::ET::Other; //// m_ngsHandler->ppmHandler()->forceIdentifierFromPartyId(playerData.partyId);
playerInstance->setForceIdentifier(forceId);
rpr2::SpatialStruct ss(spatialStructFromWorldLocation(playerData.position.toWorldLocation()));
playerInstance->setSpatial(ss);
return addBaseEntity(playerInstance, playerData);
}
bool NgsConnector::removeBaseEntity(int eqNo)
{
if (!m_playerMap.contains(eqNo))
return false;
DEBUG_LOG(getLogger("NgsConnector.Outbound.ShutDonw")) << "Participant " << eqNo << " removed.";
m_playerMap[eqNo]->deleteObjectInstance(getSimTime());
return (m_playerMap.remove(eqNo) > 0);
}
bool NgsConnector::setParticipantName(int eqNo, const QString &designator)
{
rpr2::IPlayerPhysicalEntityObjInstance *playerInstance = dynamic_cast<rpr2::IPlayerPhysicalEntityObjInstance *>(m_playerMap.value(eqNo, nullptr));
if (!playerInstance)
return false;
DEBUG_LOG(getLogger("NgsConnector.Outbound.Participant")) << "Participant " << eqNo << " changed MARKING to " << designator;
playerInstance->setMarking(toMarkingStruct(designator));
playerInstance->publish(getSimTime());
return true;
}
bool NgsConnector::setParticipantForce(int eqNo, const rpr2::ForceIdentifierEnum8::ET forceIdentifier)
{
rpr2::IPlayerPhysicalEntityObjInstance *playerInstance = dynamic_cast<rpr2::IPlayerPhysicalEntityObjInstance *>(m_playerMap.value(eqNo, nullptr));
if (!playerInstance)
return false;
DEBUG_LOG(getLogger("NgsConnector.Outbound.Participant")) << "Participant " << eqNo << "changed FORCE to " << forceIdentifier;
playerInstance->setForceIdentifier(forceIdentifier);
playerInstance->publish(getSimTime());
return true;
}
// DDS -> HLA
//void NgsConnector::sendMunitionDetonation(const ParticipantPosition &pos, int chargeTypeId, rpr2::ForceIdentifierEnum8::ET forceId)
//{
// DEBUG_LOG(getLogger("NgsConnector.Outbound.MunitionDetonation"))
// << "Munition Detonation: "
// << "Location: " << pos.toString()
// << ", Charge Type: " << TypeStruct(getEtsCharge(chargeTypeId)).toString()
// << ", fired by Force " << forceId << " (Force unused)";
// rpr2::IPlayerMunitionDetonationIntClass &icx = m_somPlayer->getPlayerMunitionDetonationIntClass();
// rpr2::IPlayerMunitionDetonationIntInstance *icb = &icx.newMunitionDetonationIntInstance();
// icb->setDetonationLocation(pos.toWorldLocation());
// icb->setDetonationResultCode(rpr2::DetonationResultCodeEnum8::Detonation);
// icb->setEventIdentifier(getEventIdentifierStruct());
// // Todo: Ask Saab if and how we should encode the Party Id
// rpr2::RTIObjectIdStruct os;
// Q_UNUSED(forceId);
// os.ID = std::to_string(IdentifierStruct(0).toInt64()); // Own ExCon
// icb->setFiringObjectIdentifier(os);
// icb->setFuseType(rpr2::FuseTypeEnum16::Contact);
// icb->setMunitionType(getEtsCharge(chargeTypeId));
// icb->setQuantityFired(1);
// icb->setRateOfFire(0);
//// icb.setTargetObjectIdentifier("");
// icb->setWarheadType(rpr2::WarheadTypeEnum16::Kinetic);
// icb->publish(getSimTime(pos.msec));
//}
IdentifierStruct NgsConnector::getIdentifierStructbyEquipmentNo(const int eqId) const
{
const rpr2::IObserverBaseEntityObjInstance *beObject = nullptr;
if (m_observerPlayerInstances.contains(eqId))
beObject = dynamic_cast<const rpr2::IObserverBaseEntityObjInstance *>(m_observerPlayerInstances[eqId]);
else if (m_playerMap.contains(eqId))
beObject = m_playerMap[eqId];
if (!beObject || !beObject->isValidEntityIdentifier())
return IdentifierStruct();
return IdentifierStruct(beObject->getEntityIdentifier());
}
void NgsConnector::sendParticipantInitRequest(const int eqId, bool resetManipulation, bool resetVulnerabilityState, bool restockCharges, qint64 simTimeMSecs)
{
IdentifierStruct is = getIdentifierStructbyEquipmentNo(eqId);
if (is.isNull() || is.isOwnElement())
return;
if (!resetVulnerabilityState)
{
WARNING_LOG(getLogger("NgsConnector.Outbound.GuezInit"))
<< "Request to "
<< (resetManipulation ? "reset Manipulation" : "")
<< (resetManipulation && restockCharges ? " and " : "")
<< (restockCharges ? "restock Charges" : "")
<< " without resetting the Player " << eqId << " to CombatReady. Not supported.";
return;
}
DEBUG_LOG(getLogger("NgsConnector.Outbound.GuezInit"))
<< "Request to "
// << (resetManipulation ? "reset Manipulation" : "")
// << (resetManipulation && restockCharges ? " and " : "")
<< (restockCharges ? "restock Charges" : "")
<< " for Player " << eqId << " to Combat Ready. (Reset Manipulation is implicit for SAAB).";
rpr2::IPlayerGuezInitIntClass &icx = m_somPlayer->getPlayerGuezInitIntClass();
rpr2::IPlayerGuezInitIntInstance *icb = &icx.newGuezInitIntInstance();
icb->setActivateHelmetObservation(rpr2::ActivateHelmetObservationEnum8::NoChange);
icb->setEntityIdentifier(is.toEIS());
icb->setResetPlayer(restockCharges ? rpr2::ResetPlayerEnum8::CombatReadyWithReammunition : rpr2::ResetPlayerEnum8::CombatReadyWithoutReammunition);
icb->publish(getSimTime(simTimeMSecs));
}
void NgsConnector::sendParticipantBiteRequest(const int eqId, bool withSelfTest, qint64 simTimeMsecs)
{
IdentifierStruct is = getIdentifierStructbyEquipmentNo(eqId);
if (is.isNull() || is.isOwnElement())
return;
rpr2::IPlayerGuezRequestBiteReportIntClass &icx = m_somPlayer->getPlayerGuezRequestBiteReportIntClass();
rpr2::IPlayerGuezRequestBiteReportIntInstance *icb = &icx.newGuezRequestBiteReportIntInstance();
icb->setBiteReportType(withSelfTest ? rpr2::BiteReportTypeEnum8::StatusAfterSelftest : rpr2::BiteReportTypeEnum8::CurrentStatus);
icb->setEntityIdentifier(is.toEIS());
icb->publish(getSimTime(simTimeMsecs));
DEBUG_LOG(getLogger("NgsConnector.Outbound.GuezBiteRequest"))
<< "Request for Bite Report for Player " << eqId << " with" << (withSelfTest ? "" : "out") << " selftest.";
}
bool NgsConnector::removeAesItem(int objId)
{
// get access
rpr2::IPlayerGuezMineFieldObjInstance *icb = dynamic_cast<rpr2::IPlayerGuezMineFieldObjInstance *>(m_environmentObjects.value(objId));
if (icb)
{
icb->deleteObjectInstance(); // ??? (ngs::SimTime(true));
m_environmentObjects.remove(objId);
// And we're done. Don't publish anything if called by startup.
return true;
}
}
bool NgsConnector::guezMineField(const WsTelegramMineFieldObject &data)
{
IdentifierStruct is ; //= IdentifierStruct::fromInt64(data.externalId());
const int objId = data.objectId; // assume unique
rpr2::IPlayerGuezMineFieldObjClass &ic = m_somPlayer->getPlayerGuezMineFieldObjClass();
// create/update:
rpr2::IPlayerGuezMineFieldObjInstance *icb = dynamic_cast<rpr2::IPlayerGuezMineFieldObjInstance *>(m_environmentObjects.value(objId));
if (!icb)
icb = &ic.newGuezMineFieldObjInstance();
// // Check for removed (now), then delete the item.
// if (icb &&
// (data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired ||
// data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsRemoved))
// {
// icb->deleteObjectInstance(ngs::SimTime(true));
// m_environmentObjects.remove(data.id());
// // And we're done. Don't publish anything if called by startup.
// return true;
// }
icb->setActivationTime(getClockTimeStruct(data.activationTime));
icb->setDuration(data.duration);
// icb->setMineType(getEtsCharge(data.chargeTypeId()));
// icb->setMineCount((data.density() - 0.1) / 0.008);
rpr2::ForceIdentifierEnum8::ET forceId = rpr2::ForceIdentifierEnum8::Other;
icb->setForceIdentifier(forceId);
// icb->setPointsData(positionArray(mineAreaSegment(segment, data.width(), data.density(), data.isCenterLine())));
// icb->setObjectType(dummyEOS());
// icb->publish(getSimTime(data.sampleTime()));
m_environmentObjects.insert(objId, icb);
return true;
}
//bool NgsConnector::setWorldLocation(int eqNo, const ParticipantPosition &pos, int eqNoHost)
//{
// rpr2::IPlayerPhysicalEntityObjInstance *playerInstance = dynamic_cast<rpr2::IPlayerPhysicalEntityObjInstance *>(m_playerMap.value(eqNo, nullptr));
// if (!playerInstance)
// return false;
// rpr2::SpatialStruct ss(spatialStructFromWorldLocation(pos.toWorldLocation()));
// rpr2::ConstituentPartRelationshipStruct cprs;
// cprs.Nature = rpr2::ConstituentPartNatureEnum16::Other;
// cprs.Position = rpr2::ConstituentPartPositionEnum16::Inside;
// rpr2::RTIObjectIdStruct rtiObjectIdHost;
// rpr2::RelativeRangeBearingStruct rrbs;
// rrbs.Bearing = 0.0;
// rrbs.Range = 0.0;
// // NGS Codegen does not automatically fill structure with 8 Bytes, when NamedLocationStruct is not defined with
// // a valid alternative:
// rpr2::NamedLocationStruct__StationName nlssn(rpr2::ConstituentPartStationNameEnum16::OnStationRangeBearing);
// nlssn.RelativeRangeAndBearing(rrbs);
// rpr2::NamedLocationStruct nlStruct;
// nlStruct.StationNumber = 0;
// nlStruct.StationName__A__Alternatives = nlssn;
// rpr2::EntityIdentifierStruct eis;
// eis.EntityNumber = 0;
// eis.FederateIdentifier.ApplicationID = 0;
// eis.FederateIdentifier.SiteID = 0;
// // Mounted?
// if (eqNoHost > 0)
// {
// // Get host from our players
// const rpr2::IObserverBaseEntityObjInstance *observerInstanceHost = m_playerMap.value(eqNoHost);
// // Not ours? Get from their players (our observed ones)
// if (!observerInstanceHost)
// observerInstanceHost = dynamic_cast<const rpr2::IObserverBaseEntityObjInstance *>(m_observerPlayerInstances.value(eqNoHost));
// // If found and valid data, fill IsPartOf struct and apply to player
// if (observerInstanceHost && observerInstanceHost->isValidObjectName() && observerInstanceHost->isValidEntityIdentifier())
// {
// cprs.Position = rpr2::ConstituentPartPositionEnum16::Inside;
// rtiObjectIdHost.ID = observerInstanceHost->getObjectName();
// eis = observerInstanceHost->getEntityIdentifier();
// }
// }
// rpr2::IsPartOfStruct ipos;
// ipos.HostEntityIdentifier = eis;
// ipos.HostRTIObjectIdentifier = rtiObjectIdHost;
// ipos.NamedLocation = nlStruct;
// ipos.Relationship = cprs;
// playerInstance->setIsPartOf(ipos);
// playerInstance->setSpatial(ss);
// playerInstance->publish(getSimTime(pos.msec));
// DEBUG_LOG(getLogger("NgsConnector.Outbound.Player.Position"))
// << "Player: " << eqNo << ", Position: " << pos.toString() << ", Time: " << pos.msec << ", Mounted on: " << eqNoHost;
// return true;
//}
ngs::SimTime NgsConnector::getSimTime(qint64 msecsSinceEpoch)
{
if (msecsSinceEpoch == 0)
msecsSinceEpoch = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch();
return ngs::SimTime(msecsSinceEpoch / 1000, (msecsSinceEpoch % 1000) * 1000);
}
ngs::SimTime NgsConnector::getSimTime(const QDateTime &dateTime)
{
return getSimTime(dateTime.toMSecsSinceEpoch());
}
void NgsConnector::go()
{
if (!m_somPlayer)
return;
try
{
m_somPlayer->go(ngs::IObserver::GOSTEP);
}
catch (const NGSException &ex)
{
ERROR_LOG(m_logger) << "NGS Exception caught in Event Loop" << ex.print();
}
catch (const std::exception &e)
{
ERROR_LOG(m_logger) << "Standard Exception caught in Event Loop: " << e.what();
}
catch (...)
{
// ERROR_LOG(m_logger) << "Generic Exception caught in Event Loop";
}
}
void NgsConnector::onFirstTickFinished()
{
unsubscribeFromNgs();
m_bCanPublishData = true;
subscribeAtNgs();
emit firstTickFinished();
}
void NgsConnector::connectObserverObjectSignals(ObserverObjectCB *entity)
{
connect(entity, &ObserverObjectCB::newObjectInstance2,
this, &NgsConnector::addObserverObjectInstance, Qt::UniqueConnection);
connect(entity, &ObserverObjectCB::objectInstanceDeleted,
this, &NgsConnector::removeObserverObjectInstance, Qt::UniqueConnection);
}
void NgsConnector::connectObserverBaseEntityObjectSignals(ObserverBaseEntityObjectCB *entity)
{
connectObserverObjectSignals(entity);
connect(entity, &ObserverBaseEntityObjectCB::entityIdentifierChanged,
this, &NgsConnector::onEntityIdentifierChanged, Qt::UniqueConnection);
connect(entity, &ObserverBaseEntityObjectCB::spatialChanged,
this, &NgsConnector::onSpatialChanged, Qt::UniqueConnection);
connect(entity, &ObserverBaseEntityObjectCB::entityTypeChanged,
this, &NgsConnector::onEntityTypeChanged, Qt::UniqueConnection);
connect(entity, &ObserverBaseEntityObjectCB::isPartOfChanged,
this, &NgsConnector::onIsPartOfChanged, Qt::UniqueConnection);
}
void NgsConnector::connectObserverPhysicalEntityObjectSignals(ObserverPhysicalEntityObjectCB *entity)
{
connectObserverBaseEntityObjectSignals(entity);
connect(entity, &ObserverPhysicalEntityObjectCB::markingChanged,
this, &NgsConnector::onMarkingChanged, Qt::UniqueConnection);
connect(entity, &ObserverPhysicalEntityObjectCB::forceIdentifierChanged,
this, &NgsConnector::onForceIdentifierChanged, Qt::UniqueConnection);
}
void NgsConnector::connectObserverPlatformObjectSignals(ObserverPlatformObjectCB *entity)
{
connectObserverPhysicalEntityObjectSignals(entity);
// No extra signals
}
void NgsConnector::connectObserverGroundVehicleObjectSignals(ObserverGroundVehicleObjectCB *entity)
{
connectObserverPlatformObjectSignals(entity);
// No extra signals
}
void NgsConnector::connectObserverGuezGroundVehicleObjectSignals(ObserverGuezGroundVehicleObjectCB *entity)
{
connectObserverGroundVehicleObjectSignals(entity);
connect(entity, &ObserverGuezGroundVehicleObjectCB::tacticalStatusChanged,
this, &NgsConnector::onTacticalStatusChanged, Qt::UniqueConnection);
}
void NgsConnector::connectObserverLifeformObjectSignals(ObserverLifeformObjectCB *entity)
{
connectObserverPhysicalEntityObjectSignals(entity);
// No extra signals
}
void NgsConnector::connectObserverHumanObjectSignals(ObserverHumanObjectCB *entity)
{
connectObserverLifeformObjectSignals(entity);
// No extra signals
}
void NgsConnector::connectObserverGuezHumanObjectSignals(ObserverGuezHumanObjectCB *entity)
{
connectObserverHumanObjectSignals(entity);
connect(entity, &ObserverGuezHumanObjectCB::tacticalStatusChanged,
this, &NgsConnector::onTacticalStatusChanged, Qt::UniqueConnection);
}
void NgsConnector::connectObserverGuezObserverControllerObjectSignals(ObserverGuezObserverControllerObjectCB *entity)
{
connectObserverHumanObjectSignals(entity);
// No extra signals
}
void NgsConnector::connectObserverEnvironmentObjectObjectSignals(ObserverEnvironmentObjectObjectCB *entity)
{
connectObserverObjectSignals(entity);
connect(entity, &ObserverEnvironmentObjectObjectCB::objectIdentifierChanged,
this, &NgsConnector::onObjectIdentifierChanged, Qt::UniqueConnection);
connect(entity, &ObserverEnvironmentObjectObjectCB::forceIdentifierChangedEO,
this, &NgsConnector::onForceIdentifierChangedEO, Qt::UniqueConnection);
connect(entity, &ObserverEnvironmentObjectObjectCB::spatialChanged,
this, &NgsConnector::onSpatialChanged, Qt::UniqueConnection);
}
void NgsConnector::connectObserverArealObjectObjectSignals(ObserverArealObjectObjectCB *entity)
{
connectObserverEnvironmentObjectObjectSignals(entity);
connect(entity, &ObserverArealObjectObjectCB::pointsDataChanged,
this, &NgsConnector::onPointsDataChanged, Qt::UniqueConnection);
connect(entity, &ObserverArealObjectObjectCB::percentCompleteChanged,
this, &NgsConnector::onPercentCompleteChanged, Qt::UniqueConnection);
connect(entity, &ObserverArealObjectObjectCB::deactivatedChanged,
this, &NgsConnector::onDeactivatedChanged, Qt::UniqueConnection);
}
void NgsConnector::connectObserverPointObjectObjectSignals(ObserverPointObjectObjectCB *entity)
{
connectObserverEnvironmentObjectObjectSignals(entity);
}
void NgsConnector::connectObserverOtherArealObjectObjectSignals(ObserverOtherArealObjectObjectCB *entity)
{
connectObserverArealObjectObjectSignals(entity);
}
void NgsConnector::connectObserverOtherPointObjectObjectSignals(ObserverOtherPointObjectObjectCB *entity)
{
connectObserverPointObjectObjectSignals(entity);
}
void NgsConnector::connectObserverGuezMineFieldObjectSignals(ObserverGuezMineFieldObjectCB *entity)
{
connectObserverOtherArealObjectObjectSignals(entity);
connect(entity, &ObserverGuezMineFieldObjectCB::areaEffectSimulationNameChanged,
this, &NgsConnector::onAreaEffectSimulationNameChanged, Qt::UniqueConnection);
connect(entity, &ObserverGuezMineFieldObjectCB::activationTimeChanged,
this, &NgsConnector::onActivationTimeChanged, Qt::UniqueConnection);
connect(entity, &ObserverGuezMineFieldObjectCB::durationChanged,
this, &NgsConnector::onDurationChanged, Qt::UniqueConnection);
connect(entity, &ObserverGuezMineFieldObjectCB::mineTypeChanged,
this, &NgsConnector::onMineTypeChanged, Qt::UniqueConnection);
}
void NgsConnector::connectObserverGuezMineFieldBreachObjectSignals(ObserverGuezMineFieldBreachObjectCB *entity)
{
connectObserverOtherArealObjectObjectSignals(entity);
connect(entity, &ObserverGuezMineFieldBreachObjectCB::areaEffectSimulationNameChanged,
this, &NgsConnector::onAreaEffectSimulationNameChanged, Qt::UniqueConnection);
connect(entity, &ObserverGuezMineFieldBreachObjectCB::activationTimeChanged,
this, &NgsConnector::onActivationTimeChanged, Qt::UniqueConnection);
}
void NgsConnector::addObserverObjectInstance(const ngs::IObserverObjectInstance &obj)
{
// Put it into the Observer list later on, when the slot "onEntityIdentifierChanged()" is called
// Then we can be sure, the EntityIdentifier is definetely set.
const rpr2::IObserverBaseEntityObjInstance *beObject = dynamic_cast<const rpr2::IObserverBaseEntityObjInstance *>(&obj);
if (beObject && beObject->isValidEntityIdentifier())
{
IdentifierStruct is(beObject->getEntityIdentifier());
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player"))
<< "Player: " << is.toString() << " added.";
m_newObjectsWithoutParticipantIdSet.insert(&obj);
onEntityIdentifierChanged(beObject->getEntityIdentifier(), beObject);
}
const rpr2::IObserverEnvironmentObjectObjInstance *eoObject = dynamic_cast<const rpr2::IObserverEnvironmentObjectObjInstance *>(&obj);
if (eoObject && eoObject->isValidObjectIdentifier())
{
IdentifierStruct is(eoObject->getObjectIdentifier());
DEBUG_LOG(getLogger("NgsConnector.Inbound.Object"))
<< "Object: " << is.toString() << " added.";
m_newObjectsWithoutParticipantIdSet.insert(&obj);
onObjectIdentifierChanged(eoObject->getObjectIdentifier(), eoObject);
}
}
void NgsConnector::removeObserverObjectInstance(const ngs::IObserverObjectInstance &obj)
{
const rpr2::IObserverBaseEntityObjInstance *beObject = dynamic_cast<const rpr2::IObserverBaseEntityObjInstance *>(&obj);
const rpr2::IObserverEnvironmentObjectObjInstance *eoObject = dynamic_cast<const rpr2::IObserverEnvironmentObjectObjInstance *>(&obj);
IdentifierStruct is;
if (beObject && beObject->isValidEntityIdentifier())
{
is = IdentifierStruct(beObject->getEntityIdentifier());
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player")) << "Player: " << is.toString() << " removed.";
}
else if (eoObject && eoObject->isValidObjectIdentifier())
{
is = IdentifierStruct(eoObject->getObjectIdentifier());
DEBUG_LOG(getLogger("NgsConnector.Inbound.Object")) << "Object: " << is.toString() << " removed.";
}
else
return;
if (is.isOwnElement())
{
// TODO: handle signal
emit virtualParticipantDeleted(is.entityNumber());
}
// really neccessary?
//int *ptr = static_cast<int *>(obj.getUserObjectID());
//delete[] ptr;
m_newObjectsWithoutParticipantIdSet.remove(&obj);
if (beObject)
{
m_observerPlayerInstances.remove(is.entityNumber());
auto it = m_damageModelMap.find(is.entityNumber());
if (it != m_damageModelMap.end())
{
delete it.value();
m_damageModelMap.erase(it);
}
}
if (eoObject)
{
m_observerEnvironmentObjects.remove(is.entityNumber());
emit aesRemoveItem(is.toInt64());
}
}
void NgsConnector::ensureDamageModelExists(const IdentifierStruct &is)
{
if (m_damageModelMap.contains(is.entityNumber()))
return;
DamageModel *dmgModel(new DamageModel(is));
// connect(dmgModel, &DamageModel::damageStateChanged,
// this, &NgsConnector::onDamageStateChangedTimeout);
connect(dmgModel, &DamageModel::playerManipulationChanged,
this, &NgsConnector::playerManipulationChanged);
m_damageModelMap.insert(is.entityNumber(), dmgModel);
}
rpr2::MarkingStruct NgsConnector::toMarkingStruct(const QString &designator)
{
rpr2::MarkingStruct ms;
const QString string = designator.leftJustified(ms.MarkingData.size(), QLatin1Char('\0'), true);
const QByteArray ba = string.toUtf8();
for (size_t i = 0; i < ms.MarkingData.size(); ++i)
ms.MarkingData[i] = ba.at(i);
// this is wrong but there is no 'UTF8' ...
ms.MarkingEncodingType = rpr2::MarkingEncodingEnum8::ASCII;
return ms;
}
rpr2::ClockTimeStruct NgsConnector::getClockTimeStruct(qint64 msecsSinceEpoch)
{
// Todo: Wrong!
rpr2::ClockTimeStruct cts;
// New:
// cts.Hours = msecsSinceEpoch / (1000LL * 60 * 60);
// qint64 msecsAfterTheHour = msecsSinceEpoch - (cts.Hours * 1000 * 60 * 60);
// double portionOfAnHour = msecsAfterTheHour / (1000 * 60 * 60);
// cts.TimePastTheHour = lrint(portionOfAnHour * (2LL<<31);
cts.Hours = msecsSinceEpoch / (1000 * 60 * 60);
cts.TimePastTheHour = msecsSinceEpoch - (cts.Hours * 1000 * 60 * 60) ; // This is wrong!
return cts;
}
qint64 NgsConnector::getMSecsSinceEpoch(const rpr2::ClockTimeStruct &cts)
{
// Todo: Wrong!
qint64 time = 0;
time += (1000LL * 60 * 60 * cts.Hours);
time += cts.TimePastTheHour; // Contains MSecs at the moment
// New:
// time += 1000LL * 60 * 60 * (cts.TimePastTheHour / (2LL<<31)) ;
return time;
}
//rpr2::EntityTypeStruct NgsConnector::getEtsCharge(int chargeType) const
//{
// const auto ct = m_ngsHandler->ppmHandler()->chargeTypeFromId(chargeType);
// if (ct.disEntity().size() == 0)
// return TypeStruct::fromString(QLatin1String("2.0.0.0.0.0.1")).toETS(); // Default
// return TypeStruct::fromString(QString::fromStdString(ct.disEntity())).toETS();
//}
template<typename T>
rpr2::ArrayOfWorldLocationStructDynamicHLAlengthlessVarArray NgsConnector::positionArray(const T &data)
{
rpr2::ArrayOfWorldLocationStructDynamicHLAlengthlessVarArray positions;
if (data.size() == 0)
return positions;
positions.resize(data.size());
unsigned int i = 0;
for (const auto &item : data)
positions[i++] = ParticipantPosition(item).toWorldLocation();
return positions;
}
//QPolygonF NgsConnector::mineCorridorSegment(const Core::GeoPosition2D &start, const Core::GeoPosition2D &end, double width)
//{
// QPointF startPoint(start.lon(), start.lat());
// QPointF endPoint(end.lon(), end.lat());
// LtsCoordTrans::UtmCoordinate startPositionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(startPoint);
// LtsCoordTrans::UtmCoordinate endPositionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(endPoint, startPositionUtm.zone);
// QLineF lengthVector(QPointF(startPositionUtm.x, startPositionUtm.y),
// QPointF(endPositionUtm.x, endPositionUtm.y));
// QPolygonF segment = QPolygonF({QPointF(0, width),
// QPointF(lengthVector.length(), width),
// QPointF(lengthVector.length(), 0),
// QPointF(0, 0)
// });
// segment.translate(QPointF(0, -(width / 2)));
// segment = fromRotation(0 - lengthVector.angle()).map(segment);
// return utmToGeogrphic(segment, startPositionUtm);
//}
template <class T>
static inline T compass2rad(T degree)
{
static_assert(!std::is_integral<T>::value, "Floating Point Value Required! Integer may be in Centidegree?!?");
return (M_PI / 2.0) - (degree * M_PI / 180.0);
}
template <class T>
static inline T deg2rad(T degree)
{
static_assert(!std::is_integral<T>::value, "Floating Point Value Required! Integer may be in Centidegree?!?");
return degree * M_PI / 180.0;
}
//QPolygonF NgsConnector::nContamination(const AreaEffectSimulation::NContamination &awf)
//{
// // Special Case: BorderLengthInner == 0
// LtsCoordTrans::UtmCoordinate impactPositionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(awf.impactPosition().lon(), awf.impactPosition().lat());
// if (qFuzzyIsNull(awf.borderLengthInner()))
// {
// if (!qFuzzyIsNull(awf.borderLengthOuter()))
// return QPolygonF();
// QPolygonF poly;
// poly.reserve(8);
// for (int i = 0; i < 360; i += 45)
// {
// double angle = compass2rad(double(i));
// poly << impactPositionUtm.geographic(QPointF(cos(angle) * awf.impactRadius(), sin(angle) * awf.impactRadius()));
// }
// return poly;
// }
// if (awf.impactRadius() > awf.borderLengthInner())
// return QPolygonF();
// double halfSpanAngleRad = deg2rad(awf.spanAngle()) / 2.0; // Angle between MCC and MCT at C
// double acos_val = awf.impactRadius() / awf.borderLengthInner(); // Adjacent / Hypotenuse (Angle between SCT and MCT at C)
// double scAngleRad = acos(acos_val) + halfSpanAngleRad; // Thus, Angle between MCC and SCT at C. ("Small Circle Angle")
// // Calculate Points:
// QPointF sct(cos(scAngleRad) * awf.impactRadius(), sin(scAngleRad) * awf.impactRadius());
// QPointF scb(cos(scAngleRad) * awf.impactRadius(), -sin(scAngleRad) * awf.impactRadius());
// QPointF mct(cos(halfSpanAngleRad) * (awf.borderLengthInner()), sin(halfSpanAngleRad) * (awf.borderLengthInner()));
// QPointF mcb(cos(halfSpanAngleRad) * (awf.borderLengthInner()), -sin(halfSpanAngleRad) * (awf.borderLengthInner()));
// QPointF bct(cos(halfSpanAngleRad) * (awf.borderLengthInner() + awf.borderLengthOuter()),
// sin(halfSpanAngleRad) * (awf.borderLengthInner() + awf.borderLengthOuter()));
// QPointF bcb(cos(halfSpanAngleRad) * (awf.borderLengthInner() + awf.borderLengthOuter()),
// -sin(halfSpanAngleRad) * (awf.borderLengthInner() + awf.borderLengthOuter()));
// QPolygonF polyUtm;
// polyUtm.reserve(8);
// polyUtm << sct;
// polyUtm << mct;
// polyUtm << bct; // In For
// polyUtm << QPointF(awf.borderLengthInner() + awf.borderLengthOuter(), 0);
// polyUtm << bcb; // May not be in for, if (spanAngle % steps != 0)
// polyUtm << mcb;
// polyUtm << scb; // In For
// polyUtm << QPointF(-awf.impactRadius(), 0);
// polyUtm = fromRotation(90.0 - awf.rotationAngle()).map(polyUtm); // The cunstructed poly ist heading eastwards but must be rotated as from north
// const QPolygonF poly(utmToGeogrphic(polyUtm, impactPositionUtm));
// return poly;
//}
//std::vector<Core::GeoPosition> NgsConnector::bcReduction(const std::vector<Core::GeoPosition> &form)
//{
// std::vector<Core::GeoPosition> vec;
// vec.resize(8);
// if (form.size() == 72) // 0, 45, 90, 135, 180, 225, 270, 315° (Kreis!)
// {
// vec[0] = form[0];
// vec[1] = form[9];
// vec[2] = form[18];
// vec[3] = form[27];
// vec[4] = form[36];
// vec[5] = form[45];
// vec[6] = form[54];
// vec[7] = form[63];
// }
// else if (form.size() == 74) // 0, 60, 120, 180° (rechts), 180, 240, 300, 360° (links) (Wurscht!)
// {
// vec[0] = form[0];
// vec[1] = form[12];
// vec[2] = form[24];
// vec[3] = form[36];
// vec[4] = form[37];
// vec[5] = form[49];
// vec[6] = form[61];
// vec[7] = form[73];
// }
// return vec;
//}
rpr2::ArrayOfHLAoctetN_slsh_AperfectalwaysN_slsh_ADynamicHLApaddingTo32Array NgsConnector::triggeredImpactsArray(const std::vector<uint8_t> &data)
{
rpr2::ArrayOfHLAoctetN_slsh_AperfectalwaysN_slsh_ADynamicHLApaddingTo32Array impacts;
if (data.size() == 0)
return impacts;
impacts.resize(data.size());
unsigned int i = 0;
for (const auto &item : data)
impacts[i++] = static_cast<ngs::CHAR8>(item);
return impacts;
}
rpr2::HitResultEnum16::ET NgsConnector::getHitResultEnum(const ProjectDataManagement::VulnerabilityState &ts)
{
switch (ts.underlying())
{
case ProjectDataManagement::VulnerabilityState_def::CombatReady:
return rpr2::HitResultEnum16::Reset;
case ProjectDataManagement::VulnerabilityState_def::LightDamage:
return rpr2::HitResultEnum16::LightDamage;
case ProjectDataManagement::VulnerabilityState_def::MediumDamage:
return rpr2::HitResultEnum16::MediumDamage;
case ProjectDataManagement::VulnerabilityState_def::HeavyDamage:
return rpr2::HitResultEnum16::HeavyDamage;
case ProjectDataManagement::VulnerabilityState_def::MobilityKill:
return rpr2::HitResultEnum16::MobilityKill;
case ProjectDataManagement::VulnerabilityState_def::VisibleMobilityKill:
return rpr2::HitResultEnum16::MobilityKillVisible;
case ProjectDataManagement::VulnerabilityState_def::WeaponSystemDamage:
return rpr2::HitResultEnum16::WeaponDamage;
case ProjectDataManagement::VulnerabilityState_def::VisibleWeaponSystemDamage:
return rpr2::HitResultEnum16::WeaponDamageVisible;
case ProjectDataManagement::VulnerabilityState_def::CatastrophicKill:
return rpr2::HitResultEnum16::TotalKill;
case ProjectDataManagement::VulnerabilityState_def::TemporarySeverance:
return rpr2::HitResultEnum16::TemporaryFailure;
case ProjectDataManagement::VulnerabilityState_def::NearMiss:
return rpr2::HitResultEnum16::NearMiss;
case ProjectDataManagement::VulnerabilityState_def::HitWithNoEffect:
return rpr2::HitResultEnum16::HitWithNoEffect;
case ProjectDataManagement::VulnerabilityState_def::NContamination:
case ProjectDataManagement::VulnerabilityState_def::BContamination:
case ProjectDataManagement::VulnerabilityState_def::CContamination:
return rpr2::HitResultEnum16::Contaminated;
default:
return rpr2::HitResultEnum16::Reset;
}
return rpr2::HitResultEnum16::Reset;
}
ProjectDataManagement::VulnerabilityState NgsConnector::getTacticalStatusEnum(const rpr2::HitResultEnum16::ET &hr)
{
switch (hr)
{
case rpr2::HitResultEnum16::Reset:
return ProjectDataManagement::VulnerabilityState_def::CombatReady;
case rpr2::HitResultEnum16::LightDamage:
return ProjectDataManagement::VulnerabilityState_def::LightDamage;
case rpr2::HitResultEnum16::MediumDamage:
return ProjectDataManagement::VulnerabilityState_def::MediumDamage;
case rpr2::HitResultEnum16::HeavyDamage:
return ProjectDataManagement::VulnerabilityState_def::HeavyDamage;
case rpr2::HitResultEnum16::MobilityKill:
return ProjectDataManagement::VulnerabilityState_def::MobilityKill;
case rpr2::HitResultEnum16::MobilityKillVisible:
return ProjectDataManagement::VulnerabilityState_def::VisibleMobilityKill;
case rpr2::HitResultEnum16::WeaponDamage:
return ProjectDataManagement::VulnerabilityState_def::WeaponSystemDamage;
case rpr2::HitResultEnum16::WeaponDamageVisible:
return ProjectDataManagement::VulnerabilityState_def::VisibleWeaponSystemDamage;
case rpr2::HitResultEnum16::TotalKill:
return ProjectDataManagement::VulnerabilityState_def::CatastrophicKill;
case rpr2::HitResultEnum16::CheatingKill:
return ProjectDataManagement::VulnerabilityState_def::CatastrophicKill;
case rpr2::HitResultEnum16::NearMiss:
return ProjectDataManagement::VulnerabilityState_def::NearMiss;
case rpr2::HitResultEnum16::HitWithNoEffect:
return ProjectDataManagement::VulnerabilityState_def::HitWithNoEffect;
case rpr2::HitResultEnum16::Contaminated:
return ProjectDataManagement::VulnerabilityState_def::CContamination;
case rpr2::HitResultEnum16::TemporaryFailure:
return ProjectDataManagement::VulnerabilityState_def::TemporarySeverance;
default:
return ProjectDataManagement::VulnerabilityState_def::NoChange;
}
return ProjectDataManagement::VulnerabilityState_def::NoChange;
}
QPolygonF NgsConnector::utmToGeogrphic(const QPolygonF &polyUtm, const LtsCoordTrans::UtmCoordinate &base)
{
QPolygonF poly;
poly.reserve(polyUtm.size());
for (const QPointF &point : qAsConst(polyUtm))
poly << base.geographic(point);
return poly;
}
void NgsConnector::onEntityIdentifierChanged(const rpr2::EntityIdentifierStruct &eis,
const rpr2::IObserverBaseEntityObjInstance *obj)
{
IdentifierStruct is(eis);
// Own players are irrelevant here
if (is.isOwnElement())
{
m_newObjectsWithoutParticipantIdSet.remove(obj);
return;
}
// We cannot do anything here then. Who was it before?
if (m_observerPlayerInstances.contains(is.entityNumber()))
return;
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player"))
<< "Player: " << is.toString() << " will be added.";
m_observerPlayerInstances.insert(is.entityNumber(), obj);
m_newObjectsWithoutParticipantIdSet.remove(obj);
GuezHitStruct hs;
hs.originatorType = ProjectDataManagement::StateChangeOriginator_def::Initialization;
hs.sampleTime = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch(); // We don't have anything better
hs.targetId = is.entityNumber();
hs.vulnerabilityState = ProjectDataManagement::VulnerabilityState_def::VulnerabilityBitsChanged; // --> Evaluate State from Bits (done in PPM Service).
QTimer::singleShot(STATUS_WAIT_INTERVAL, this, [this, hs, obj]() mutable
{
auto ptr = m_damageModelMap.value(hs.targetId);
if (!ptr)
{
ERROR_LOG(getLogger("NgsConnector.Inbound.Player"))
<< "Damage State of entity " << hs.targetId
<< " didn't exist 50msecs after EntityIdentifier Changed. Setting Initial Status not possible!";
return;
}
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player"))
<< "Player: " << hs.targetId << ". Setting initial Status, initial Position and Manipulation.";
const auto vulnerabilityBits = ptr->totalState(hs.sampleTime);
hs.vulnerabilityBits = (vulnerabilityBits & ~rpr2::TotalStatusEnum32::Manipulation);
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.Status"))
<< "Player: " << hs.targetId
<< " New Total Status: " << hs.vulnerabilityBits;
emit guezHit(hs);
ParticipantPosition pos(obj->getSpatial().DeadReckoningAlgorithm__A__Alternatives.SpatialStatic().WorldLocation);
long time = obj->getLatestTimeStamp().getSeconds() * 1000;
if (time == 0)
time = getSimTime().getSeconds() * 1000;
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.Position"))
<< "Player: " << hs.targetId << ", Initial Position: " << pos.toString() << ", Time: " << pos.msec;
emit spatialChanged(hs.targetId, pos, time);
// That may be too much but better safe than sorry...
// TODO: set to DamageModel, use emit from there?
emit playerManipulationChanged(hs.targetId, vulnerabilityBits & rpr2::TotalStatusEnum32::Manipulation, hs.sampleTime);
});
}
bool NgsConnector::onObjectIdentifierChanged(const rpr2::EntityIdentifierStruct &eis,
const rpr2::IObserverEnvironmentObjectObjInstance *obj)
{
IdentifierStruct is(eis);
// Own players are irrelevant here
if (is.isOwnElement())
{
m_newObjectsWithoutParticipantIdSet.remove(obj);
return false;
}
// Already created -> ignore
if (m_observerEnvironmentObjects.contains(is.entityNumber()))
return true;
DEBUG_LOG(getLogger("NgsConnector.Inbound.Object"))
<< "Object: " << is.toString() << " will be added.";
m_observerEnvironmentObjects.insert(is.entityNumber(), obj);
m_nonpublishedEnvironmentObjects.insert(is.entityNumber());
m_newObjectsWithoutParticipantIdSet.remove(obj);
const rpr2::IObserverGuezMineFieldObjInstance *minefield = dynamic_cast<const rpr2::IObserverGuezMineFieldObjInstance *>(obj);
if (minefield)
return addMinefield(minefield);
const rpr2::IObserverGuezMineFieldBreachObjInstance *minefieldBreach = dynamic_cast<const rpr2::IObserverGuezMineFieldBreachObjInstance *>(obj);
if (minefieldBreach)
return addMinefieldBreach(minefieldBreach);
return false;
}
bool getCorridorSegment(const rpr2::ArrayOfWorldLocationStructDynamicHLAlengthlessVarArray &pointsDataIn,
std::vector<Core::GeoPosition2D> &segmentsOut,
double &widthOut)
{
// P0 P3
// L *-------------------* L
// i | | i
// n * S0 S1 * n
// e | | e
// 1 *-------------------* 2
// P1 P2
// Calculate width = P0->P1
// Calculate S0, S1
if (pointsDataIn.size() != 4)
return false;
ParticipantPosition p0(pointsDataIn[0]);
ParticipantPosition p1(pointsDataIn[1]);
ParticipantPosition p2(pointsDataIn[2]);
ParticipantPosition p3(pointsDataIn[3]);
LtsCoordTrans::UtmCoordinate utmP0 = LtsCoordTrans::UtmCoordinate::fromGeographic(p0.toPoint());
LtsCoordTrans::UtmCoordinate utmP1 = LtsCoordTrans::UtmCoordinate::fromGeographic(p1.toPoint(), utmP0.zone);
LtsCoordTrans::UtmCoordinate utmP2 = LtsCoordTrans::UtmCoordinate::fromGeographic(p2.toPoint(), utmP0.zone);
LtsCoordTrans::UtmCoordinate utmP3 = LtsCoordTrans::UtmCoordinate::fromGeographic(p3.toPoint(), utmP0.zone);
QLineF line1(utmP0.x, utmP0.y, utmP1.x, utmP1.y);
widthOut = line1.length();
line1.setLength(0.5 * line1.length());
LtsCoordTrans::UtmCoordinate utmS0(utmP0.zone, line1.p2().x(), line1.p2().y(), utmP0.northp);
QLineF line2(utmP2.x, utmP2.y, utmP3.x, utmP3.y);
widthOut = line2.length();
line2.setLength(0.5 * line2.length());
LtsCoordTrans::UtmCoordinate utmS1(utmP0.zone, line2.p2().x(), line2.p2().y(), utmP0.northp);
segmentsOut.resize(2);
segmentsOut[0] = Core::GeoPosition2D(utmS0.geographic().x(), utmS0.geographic().y());
segmentsOut[1] = Core::GeoPosition2D(utmS1.geographic().x(), utmS1.geographic().y());
return true;
}
bool NgsConnector::addMinefield(const rpr2::IObserverGuezMineFieldObjInstance *minefield)
{
return false;
/*
int id = minefield->isValidObjectIdentifier() ? IdentifierStruct(minefield->getObjectIdentifier()).entityNumber() : 0;
QTimer::singleShot(STATUS_WAIT_INTERVAL, this, [this, minefield, id]() mutable
{
if (!m_observerEnvironmentObjects.contains(id))
return;
if (!minefield->isValidObjectIdentifier() ||
!minefield->isValidMineType() ||
!minefield->isValidMineCount() ||
!minefield->isValidActivationTime() ||
!minefield->isValidAreaEffectSimulationName() ||
!minefield->isValidForceIdentifier() ||
!minefield->isValidPointsData())
{
ERROR_LOG(getLogger("NgsConnector.Inbound.MineField"))
<< "Wanted to create Minefield but not all necessary data is available yet. :(";
return;
}
if (minefield->isValidPercentComplete() && minefield->getPercentComplete() > 99)
return;
IdentifierStruct is(minefield->getObjectIdentifier());
AreaEffectSimulation::MineAreaModifyRequest ma;
const auto ct = m_ngsHandler->ppmHandler()->chargeTypeFromDisEntity(TypeStruct(minefield->getMineType()).toString());
ma.externalId(is.toInt64());
ma.chargeTypeId(ct.id());
ma.density(0.008 * minefield->getMineCount() + 0.1); // 0 -> 0.1 , 100 -> 0.9
ma.effectStart(getMSecsSinceEpoch(minefield->getActivationTime()));
ma.name(minefield->getAreaEffectSimulationName().str());
if (minefield->isValidDuration())
ma.effectDuration(60LL * 60 * 1000 * minefield->getDuration()); // Hours to MSecs
else
ma.effectDuration(60LL * 60 * 1000 * 4); // 4 Hour Default
int partyId = m_ngsHandler->ppmHandler()->partyIdFromForceIdentifier(minefield->getForceIdentifier());
ma.partyId(partyId);
double width;
std::vector<Core::GeoPosition2D> segments;
if (!getCorridorSegment(minefield->getPointsData(), segments, width))
{
ERROR_LOG(getLogger("NgsConnector.Inbound.MineField"))
<< "Minefield Id: " << is.toString()
<< ", Name: " << ma.name()
<< ". Could not calculate segment from given points data.";
return;
}
DEBUG_LOG(getLogger("NgsConnector.Inbound.MineField"))
<< "Minefield added/changed: Id: " << is.toString()
<< ", Name: " << ma.name();
ma.segments(segments);
ma.width(width);
ma.isCenterLine(true);
emit newMinefield(ma);
m_nonpublishedEnvironmentObjects.remove(id);
});
return true;
*/
}
bool NgsConnector::addMinefieldBreach(const rpr2::IObserverGuezMineFieldBreachObjInstance *minefieldBreach)
{
return false;
/*
QTimer::singleShot(STATUS_WAIT_INTERVAL, this, [this, minefieldBreach]() mutable
{
if (!minefieldBreach->isValidObjectIdentifier() ||
!minefieldBreach->isValidActivationTime() ||
!minefieldBreach->isValidAreaEffectSimulationName() ||
!minefieldBreach->isValidForceIdentifier() ||
!minefieldBreach->isValidPointsData())
return;
IdentifierStruct is(minefieldBreach->getObjectIdentifier());
// If it was deleted, don't do anything!
if (!m_observerEnvironmentObjects.contains(is.entityNumber()))
return;
AreaEffectSimulation::MineCorridorModifyRequest mc;
mc.externalId(is.toInt64());
mc.effectStart(getMSecsSinceEpoch(minefieldBreach->getActivationTime()));
mc.name(minefieldBreach->getAreaEffectSimulationName().str());
std::vector<Core::GeoPosition2D> vec;
double width;
if (!getCorridorSegment(minefieldBreach->getPointsData(), vec, width))
{
ERROR_LOG(getLogger("NgsConnector.Inbound.MineFieldBreach"))
<< "Minefield Breach Id: " << is.toString()
<< ", Name: " << mc.name()
<< ". Could not calculate segment from given points data.";
return;
}
mc.segments(vec);
mc.width(width);
int partyId = m_ngsHandler->ppmHandler()->partyIdFromForceIdentifier(minefieldBreach->getForceIdentifier());
mc.partyId(partyId);
DEBUG_LOG(getLogger("NgsConnector.Inbound.MineFieldBreach"))
<< "Minefield added/changed: Id: " << is.toString()
<< ", Name: " << mc.name();
emit newMinefieldBreach(mc);
m_nonpublishedEnvironmentObjects.remove(is.entityNumber());
});
return true;
*/
}
bool NgsConnector::onSpatialChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::WorldLocationStruct &wl, qint64 simTimeMSecs)
{
return false;
/*
IdentifierStruct is(eis);
ParticipantPosition newParticipantPosition(wl);
if (is.isOwnElement())
return true;
ParticipantPosition &posInMapRef = m_observerPositions[is.entityNumber()];
if (!posInMapRef.hasMoved(newParticipantPosition)) //Hat sich die Position zum letzen Mal signifkant geändert?
return true;
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.Position"))
<< "Player: " << is.toString() << ", Position: " << newParticipantPosition.toString() << ", Time: " << newParticipantPosition.msec;
posInMapRef = newParticipantPosition;
emit spatialChanged(is.entityNumber(), newParticipantPosition, simTimeMSecs);
return true;
*/
}
void NgsConnector::onEntityTypeChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::EntityTypeStruct &ets, qint64 simTimeMSecs)
{
Q_UNUSED(simTimeMSecs);
IdentifierStruct is(eis);
if (is.isOwnElement())
return;
TypeStruct ts(ets);
WARNING_LOG(getLogger("NgsConnector.Inbound.Player"))
<< "Player: " << is.toString() << ". New Entity Type: " << ts.toString() << ". This has no effect!";
// Todo?
}
void NgsConnector::onIsPartOfChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::IsPartOfStruct &ipos, qint64 simTimeMSecs)
{
// We cannot handle Saab players being mounted on GUEZ vehicles and vice versa as on radio the HOST (party A) tells about its mounted players,
// whereas on HLA the player (party B) has to tell where he's mounted on. Party A's Excon cannot publish (IsPartOf) data of the player that
// belongs to party B.
IdentifierStruct is(eis);
if (is.isOwnElement())
return;
int eqNo = is.entityNumber();
int eqNoHost = ipos.HostEntityIdentifier.EntityNumber;
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player"))
<< "Player: " << is.toString() << " is now part of " << IdentifierStruct(ipos.HostEntityIdentifier).toString();
emit isPartOfChanged(eqNo, eqNoHost, simTimeMSecs);
}
bool NgsConnector::onMarkingChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::MarkingStruct &marking, qint64 simTimeMSecs)
{
IdentifierStruct is(eis);
if (is.isOwnElement())
return true;
QByteArray ba;
for (size_t i = 0; i < marking.MarkingData.size(); ++i)
ba += marking.MarkingData[i];
const QString str(QString::fromUtf8(ba));
DEBUG_LOG(getLogger("NgsConnector.Inbound.Object"))
<< "Object: " << is.toString() << " has new Marking: '" << str << "'.";
emit markingChanged(eis.EntityNumber, str, simTimeMSecs);
return true;
}
bool NgsConnector::onPointsDataChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::ArrayOfWorldLocationStructDynamicHLAlengthlessVarArray &points, qint64 simTimeMSecs)
{
IdentifierStruct is(eis);
if (is.isOwnElement())
return true;
if (!m_observerEnvironmentObjects.contains(is.entityNumber()))
return false;
if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber()))
return false;
std::vector<Core::GeoPosition2D> pointsData;
for (size_t i = 0; i < points.size(); ++i)
pointsData.resize(pointsData.size() + 1, ParticipantPosition(points[i]).toGeoPosition2D());
DEBUG_LOG(getLogger("NgsConnector.Inbound.Object"))
<< "Object: " << is.toString() << " has new Points data (not printed) of size " << pointsData.size();
emit aesPointsDataChanged(is.toInt64(), pointsData, simTimeMSecs);
return true;
}
bool NgsConnector::onForceIdentifierChanged(const rpr2::EntityIdentifierStruct &eis, rpr2::ForceIdentifierEnum8::ET identifier, qint64 simTimeMSecs)
{
Q_UNUSED(simTimeMSecs);
IdentifierStruct is(eis);
if (is.isOwnElement())
return true;
WARNING_LOG(getLogger("NgsConnector.Inbound.Player"))
<< "Player: " << is.toString() << " has new Force Identifier: " << identifier << ". This has NO EFFECT.";
return true;
}
bool NgsConnector::onForceIdentifierChangedEO(const rpr2::EntityIdentifierStruct &eis, rpr2::ForceIdentifierEnum8::ET identifier, qint64 simTimeMSecs)
{
Q_UNUSED(simTimeMSecs);
IdentifierStruct is(eis);
if (is.isOwnElement())
return true;
if (!m_observerEnvironmentObjects.contains(is.entityNumber()))
return false;
if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber()))
return false;
DEBUG_LOG(getLogger("NgsConnector.Inbound.Object"))
<< "Object: " << is.toString() << " has new Force Identifier: " << identifier << ". Updating AES Item.";
int partyId = -1; // = m_ngsHandler->ppmHandler()->partyIdFromForceIdentifier(identifier);
emit aesForceIdentifierChanged(is.toInt64(), partyId);
return true;
}
bool NgsConnector::onTacticalStatusChanged(const rpr2::EntityIdentifierStruct &eis,
const rpr2::TacticalStatusStruct &rprStatus,
qint64 simTimeMSecs)
{
IdentifierStruct is(eis);
if (is.isOwnElement())
return true;
ensureDamageModelExists(is);
m_damageModelMap[is.entityNumber()]->setTacticalStatusStruct(rprStatus, simTimeMSecs);
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.Status"))
<< "Player: " << is.toString() << " New Total Status: " << rprStatus.TotalStatus << ", Tactical Status (unused): " << rprStatus.TacticalStatus;
if (rprStatus.TotalStatus == rpr2::TotalStatusEnum32::CombatReady)
{
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.Status")) << "New Status is CombarReady. Therfore we 'init' the player.";
emit participantReceivedInit(is.entityNumber(), simTimeMSecs);
return true;
}
// Todo: Tactical Status Change on SAAB players can occur at any time (without known reason). Therefore, we MUST handle this.
// Change of Tactical Status with no other Interaction cannot be handled (at the moment). The Interaction forwards the status change to PPM.
// Note: We could start a timer per eqNo. If the Timer is not deleted by an interaction that handles it, send it out.
GuezHitStruct hitStruct;
hitStruct.originatorChargeTypeEtsString = TypeStruct::fromDisInt(0).toString();
hitStruct.originatorId = 0;
hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::Unknown;
hitStruct.position = m_observerPositions[is.entityNumber()].toGeoPosition();
hitStruct.sampleTime = simTimeMSecs;
hitStruct.targetId = is.entityNumber();
hitStruct.vulnerabilityState = ProjectDataManagement::VulnerabilityState_def::VulnerabilityBitsChanged; // --> Evaluate State from Bits (done in PPM Service).
hitStruct.vulnerabilityKind = 0;
const auto vulnerabilityBits = m_damageModelMap[is.entityNumber()]->totalState(hitStruct.sampleTime);
hitStruct.vulnerabilityBits = (vulnerabilityBits & ~rpr2::TotalStatusEnum32::Manipulation);
if (m_guezHitActive.contains(hitStruct.targetId))
{
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.StatusChange")) << "Tactical Status changed, but GuezHit was detected before. Not doing anything!";
return true;
}
QTimer::singleShot(Settings::guezHitGraceTimeMSecs(), this, [this, hitStruct]() mutable
{
if (m_guezHitActive.contains(hitStruct.targetId))
{
DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.StatusChange")) << "Tactical Status changed, Timeout happened, but GuezHit was detected before. Not doing anything!";
return;
}
WARNING_LOG(getLogger("NgsConnector.Inbound.Player.StatusChange")) << "Tactical Status changed, Timeout happened. NO corresponding GuezHit detected";
emit guezHit(hitStruct);
});
return true;
}
bool NgsConnector::onDeactivatedChanged(const rpr2::EntityIdentifierStruct &eis, bool state, qint64 simTimeMSecs)
{
Q_UNUSED(simTimeMSecs);
IdentifierStruct is(eis);
if (is.isOwnElement())
return true;
if (!m_observerEnvironmentObjects.contains(is.entityNumber()))
return false;
if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber()))
return false;
DEBUG_LOG(getLogger("NgsConnector.Inbound.Object"))
<< "Object: " << is.toString() << " has changed 'Deactivated' State. New State: " << state;
if (state) // now deactivated
{
emit aesRemoveItem(is.toInt64());
// int activationTime = 0;
// const rpr2::IObserverGuezMineFieldObjInstance *minefield = dynamic_cast<const rpr2::IObserverGuezMineFieldObjInstance * >(m_observerEnvironmentObjects[is.entityNumber()]);
// if (minefield && minefield->isValidActivationTime())
// activationTime = getMSecsSinceEpoch(minefield->getActivationTime());
// const rpr2::IObserverGuezMineFieldBreachObjInstance *minefieldBreach = dynamic_cast<const rpr2::IObserverGuezMineFieldBreachObjInstance * >(m_observerEnvironmentObjects[is.entityNumber()]);
// if (minefieldBreach && minefieldBreach->isValidActivationTime())
// activationTime = getMSecsSinceEpoch(minefieldBreach->getActivationTime());
// // again!
// if (activationTime > 0)
// emit aesRemoveItem(is.toInt64());
}
return true;
}
bool NgsConnector::onPercentCompleteChanged(const rpr2::EntityIdentifierStruct &eis, ngs::UINT32 state, qint64 simTimeMSecs)
{
Q_UNUSED(simTimeMSecs);
IdentifierStruct is(eis);
if (is.isOwnElement())
return true;
DEBUG_LOG(getLogger("NgsConnector.Inbound.Object"))
<< "Object: " << is.toString() << " has changed 'Percent Complete'. New Completeness: " << state;
// Find out, if it was active before
// Todo: This might not work as the instance's deactivated flag most likely already is set...
if (!m_observerEnvironmentObjects.contains(is.entityNumber()))
return false;
if (state > 99)
emit aesRemoveItem(is.toInt64());
return true;
}
// Minefield
// Minefield Breach
void NgsConnector::onAreaEffectSimulationNameChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::OMT13string &value, qint64 simTimeMSecs)
{
Q_UNUSED(simTimeMSecs);
IdentifierStruct is(eis);
if (is.isOwnElement())
return;
if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber()))
return;
if (!m_observerEnvironmentObjects.contains(eis.EntityNumber))
return;
DEBUG_LOG(getLogger("NgsConnector.Inbound.Object"))
<< "Object: " << is.toString() << " has changed Name. New Name: " << QString::fromStdString(value);
emit aesNameChanged(is.toInt64(), value);
}
// Minefield
// Minefield Breach
void NgsConnector::onActivationTimeChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::ClockTimeStruct &value, qint64 simTimeMSecs)
{
Q_UNUSED(simTimeMSecs);
IdentifierStruct is(eis);
if (is.isOwnElement())
return;
if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber()))
return;
if (!m_observerEnvironmentObjects.contains(eis.EntityNumber))
return;
qint64 msecs = getMSecsSinceEpoch(value);
DEBUG_LOG(getLogger("NgsConnector.Inbound.Object"))
<< "Object: " << is.toString() << " has changed Activation Time: " << msecs;
emit aesActivationTimeChanged(is.toInt64(), msecs);
}
// Minefield
void NgsConnector::onDurationChanged(const rpr2::EntityIdentifierStruct &eis, ngs::UINT32 value, qint64 simTimeMSecs)
{
Q_UNUSED(simTimeMSecs);
IdentifierStruct is(eis);
if (is.isOwnElement())
return;
if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber()))
return;
if (!m_observerEnvironmentObjects.contains(eis.EntityNumber))
return;
DEBUG_LOG(getLogger("NgsConnector.Inbound.Object"))
<< "Object: " << is.toString() << " has changed Duration: " << value;
emit aesDurationChanged(is.toInt64(), value);
}
// Minefield
void NgsConnector::onMineTypeChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::EntityTypeStruct &ets, qint64 simTimeMSecs)
{
IdentifierStruct is(eis);
Q_UNUSED(simTimeMSecs);
if (is.isOwnElement())
return;
if (!m_observerEnvironmentObjects.contains(is.entityNumber()))
return;
if (m_observerEnvironmentObjects.contains(eis.EntityNumber))
return;
// const auto ct = m_ngsHandler->ppmHandler()->chargeTypeFromDisEntity(TypeStruct(ets).toString());
// DEBUG_LOG(getLogger("NgsConnector.Inbound.Object"))
// << "Object: " << is.toString() << " has changed Munition: " << ct.disEntity() << " / internal id: " << ct.id();
// emit aesChargeChanged(is.toInt64(), ct.id());
}
// HLA -> DDS
void NgsConnector::onNewMunitionDetonation(const rpr2::IObserverMunitionDetonationIntInstance &interaction)
{
// Own Item?
if (std::stol(interaction.getEventIdentifier().IssuingObjectIdentifier.ID) == IdentifierStruct(0).toInt64())
return;
// AreaEffectSimulation::ExplosionSingleModifyRequest req;
// // req.altitude();
// const auto ct = m_ngsHandler->ppmHandler()->chargeTypeFromDisEntity(TypeStruct(interaction.getMunitionType()).toString());
// req.chargeTypeId(ct.id());
// req.id(0);
// req.effectStart(QDateTime::currentDateTimeUtc().toMSecsSinceEpoch() + ACTIVATION_LEAD_TIME);
// IdentifierStruct is(interaction.getEventIdentifier().EventCount);
// is.setSiteId(255); // Dummy - Must not be of either site.
// req.externalId(is.toInt64()); // dummy val, inserted to prevent aes_handler from dropping this telegram
// req.fireRequestTime(QDateTime::currentDateTimeUtc().toMSecsSinceEpoch());
// req.impactPosition(ParticipantPosition(interaction.getDetonationLocation()).toGeoPosition2D());
// // IdentifierStruct is = IdentifierStruct::fromInt64(QString::fromStdString(interaction.getEventIdentifier().IssuingObjectIdentifier.ID).toLongLong());
// req.name(tr("SAAB Fire: %1").arg(interaction.getEventIdentifier().EventCount).toStdString());
// // Todo: If SAAB sends the Party in interaction.getFiringObjectIdentifier().ID like "F12" -> "ForceIdentifierEnum -> Value 12"
// // req.partyId(interaction.getFiringObjectIdentifier())
// // req.purpose()
// // req.rotation()
// DEBUG_LOG(getLogger("NgsConnector.Inbound.MunitionDetonation"))
// << "Munition Detonation: "
// << "Location: " << ParticipantPosition(interaction.getDetonationLocation()).toString()
// << ", Charge Type: " << ct.disEntity();
// emit munitionDetonation(req);
}
int NgsConnector::getEquipmentNoByRTIObjectId(const std::string &sender) const
{
// Own Players
for (auto it(m_playerMap.cbegin()); it != m_playerMap.cend(); ++it)
{
if (it.value()->isValidObjectName())
{
if (it.value()->getObjectName() == sender)
return it.key();
}
}
// Saab Players
for (auto it(m_observerPlayerInstances.cbegin()); it != m_observerPlayerInstances.cend(); ++it)
{
if (it.value()->isValidObjectName())
{
if (it.value()->getObjectName() == sender)
return it.key();
}
}
return 0;
}
// HLA -> DDS
void NgsConnector::onNewWeaponFire(const rpr2::IObserverWeaponFireIntInstance &interaction)
{
// Self issued?
if (std::stol(interaction.getEventIdentifier().IssuingObjectIdentifier.ID) == IdentifierStruct(0).toInt64())
return;
// TrainingAreaBase::EquipmentGearEvent event;
// event.equipmentNumber(getEquipmentNoByRTIObjectId(interaction.getFiringObjectIdentifier().ID));
// // only send for others, not for own players
// if (m_playerMap.contains(event.equipmentNumber()))
// return;
// TrainingAreaBase::GearCharge charge;
// const auto ct = m_ngsHandler->ppmHandler()->chargeTypeFromDisEntity(TypeStruct(interaction.getMunitionType()).toString());
// charge.chargeTypeId(ct.id());
// // charge.gearId();
// // charge.gearTypeId();
// // charge.remain();
// event.charge(charge);
// event.chargeAmount(interaction.getQuantityFired());
// event.sampleTime(simTimeToMSec(interaction.getReceiveTimeStamp()));
// DEBUG_LOG(getLogger("NgsConnector.Inbound.WeaponFire"))
// << "Weapon Fire: EventID: " << interaction.getEventIdentifier().EventCount
// << ", Charge Type: " << ct.disEntity()
// << ", Shooter: " << event.equipmentNumber()
// << ", Rounds: " << interaction.getQuantityFired() << ")";
// emit weaponFire(event);
}
void NgsConnector::onNewGuezHit(const rpr2::IObserverGuezHitIntInstance &interaction)
{
IdentifierStruct is(interaction.getTargetIdentifier());
if (is.isOwnElement())
return;
if (!m_observerPlayerInstances.contains(is.entityNumber()))
{
ERROR_LOG(getLogger("NgsConnector.Inbound.GuezHit"))
<< "Player: " << is.toString()
<< ", but there's no observer Object for it.";
return;
}
const int eqNo = interaction.getTargetIdentifier().EntityNumber;
auto ptr = m_damageModelMap.value(eqNo);
if (!ptr)
{
WARNING_LOG(getLogger("NgsConnector.Inbound.GuezHit"))
<< "Player: " << eqNo
<< ", Damage Model no longer exists. Not processing GuezHit!";
return;
}
ptr->setTacticalStatus(interaction.getHitResult(), simTimeToMSec(interaction.getReceiveTimeStamp()));
GuezHitStruct hitStruct;
hitStruct.originatorChargeTypeEtsString = TypeStruct(interaction.getMunition()).toString();
hitStruct.originatorId = interaction.getOriginatorIdentifier().EntityNumber;
hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::Unknown;
switch (interaction.getOriginatorType())
{
case rpr2::OriginatorTypeEnum16::Unknown:
hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::Unknown;
break;
case rpr2::OriginatorTypeEnum16::NoMedicalTreatment: // If no medical treatment has been conducted, and there's no originator, he's bleeding for himself...
hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::Participant;
if (hitStruct.originatorId == 0) // for sanity, there can't be a participant with EqId = 0
hitStruct.originatorId = hitStruct.targetId;
break;
case rpr2::OriginatorTypeEnum16::Participant:
hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::Participant;
if (hitStruct.originatorId == 0) // for sanity, there can't be a participant with EqId = 0
hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::ExerciseControl;
break;
case rpr2::OriginatorTypeEnum16::AreaEffectSimulation:
hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::AreaEffectSimulation;
hitStruct.originatorId = IdentifierStruct(interaction.getOriginatorIdentifier()).toInt64();
break;
case rpr2::OriginatorTypeEnum16::ObserverController:
hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::ObserverController;
break;
case rpr2::OriginatorTypeEnum16::ExerciseControl:
hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::ExerciseControl;
break;
}
hitStruct.position = ParticipantPosition(interaction.getTargetLocation()).toGeoPosition();
hitStruct.sampleTime = simTimeToMSec(interaction.getReceiveTimeStamp());
hitStruct.targetId = interaction.getTargetIdentifier().EntityNumber;
// hitStruct.vulnerabilityState = ProjectDataManagement::VulnerabilityState_def::VulnerabilityBitsChanged; // --> Evaluate State from Bits (done in PPM Service).
// hitStruct.vulnerabilityKind = 0;
hitStruct.vulnerabilityState = getTacticalStatusEnum(interaction.getHitResult());
// HAck for resetting a player, whilst SAAB does not send the correct HitResult...
if ((hitStruct.originatorType == ProjectDataManagement::StateChangeOriginator_def::ExerciseControl ||
hitStruct.originatorType == ProjectDataManagement::StateChangeOriginator_def::ObserverController
)
&& hitStruct.vulnerabilityState == ProjectDataManagement::VulnerabilityState_def::HitWithNoEffect)
{
auto ptr = m_damageModelMap.value(eqNo);
if (ptr)
{
hitStruct.vulnerabilityState = ptr->vulnerabilityState(hitStruct.sampleTime);
if (hitStruct.vulnerabilityState == ProjectDataManagement::VulnerabilityState_def::CombatReady)
ptr->setTacticalStatus(rpr2::HitResultEnum16::Reset, simTimeToMSec(interaction.getReceiveTimeStamp()));
}
}
DEBUG_LOG(getLogger("NgsConnector.Inbound.GuezHit"))
<< "Player: " << is.toString()
<< ", Originator Type: " << hitStruct.originatorType
<< ", Originator Id: " << hitStruct.originatorId
<< ", Charge Type: " << hitStruct.originatorChargeTypeEtsString
<< ", HitResult: " << hitStruct.vulnerabilityState;
m_guezHitActive.insert(hitStruct.targetId);
QTimer::singleShot(Settings::guezHitGraceTimeMSecs(), this, [this, hitStruct, eqNo]() mutable
{
auto ptr = m_damageModelMap.value(eqNo);
if (!ptr)
{
WARNING_LOG(getLogger("NgsConnector.Inbound.GuezHit"))
<< "Player: " << eqNo
<< ", Damage Model no longer exists. Not processing GuezHit!";
return;
}
const auto vulnerabilityBits = ptr->totalState(hitStruct.sampleTime);
hitStruct.vulnerabilityBits = (vulnerabilityBits & ~rpr2::TotalStatusEnum32::Manipulation);
DEBUG_LOG(getLogger("NgsConnector.Inbound.GuezHit")) << "vBits: " << vulnerabilityBits;
DEBUG_LOG(getLogger("NgsConnector.Inbound.GuezHit")) << "vState: " << hitStruct.vulnerabilityState;
m_guezHitActive.remove(hitStruct.targetId);
emit guezHit(hitStruct);
});
}
void NgsConnector::onNewGuezInit(const rpr2::IObserverGuezInitIntInstance &interaction)
{
// ExConEngagement FROM HLA TO US! Our Player shall be affected!
IdentifierStruct is(interaction.getEntityIdentifier());
if (!is.isOwnElement())
return;
if (!m_playerMap.contains(is.entityNumber()))
{
ERROR_LOG(getLogger("NgsConnector.Inbound.GuezInit"))
<< "Player: " << is.toString()
<< " is not our player...";
return;
}
rpr2::ResetPlayerEnum8::ET rp = interaction.getResetPlayer();
rpr2::ActivateHelmetObservationEnum8::ET aho = interaction.getActivateHelmetObservation();
bool resetVulnerabilityState = true;
if (rp != rpr2::ResetPlayerEnum8::CombatReadyWithoutReammunition &&
rp != rpr2::ResetPlayerEnum8::CombatReadyWithReammunition)
resetVulnerabilityState = false;
if (aho != rpr2::ActivateHelmetObservationEnum8::NoChange)
{
WARNING_LOG(getLogger("NgsConnector.Inbound.GuezInit"))
<< "Player: " << is.toString()
<< "Incoming Activation Helmet/Vest on GuezInit not supported yet";
}
DEBUG_LOG(getLogger("NgsConnector.Inbound.GuezInit"))
<< "Player: " << is.toString()
<< ", Reset Type: " << rp;
emit guezInit(is.entityNumber(), false, rp == rpr2::ResetPlayerEnum8::CombatReadyWithReammunition, resetVulnerabilityState);
}
void NgsConnector::onNewGuezBiteReport(const rpr2::IObserverGuezBiteReportIntInstance &interaction)
{
IdentifierStruct is(interaction.getEntityIdentifier());
if (is.isOwnElement())
return;
// TrainingAreaBase::EquipmentBite eb;
// QStringList result;
// bool leave = false;
// if (!interaction.isValidBiteResult())
// {
// result << QStringLiteral("BiteResult not valid");
// leave = true;
// }
// if (!interaction.isValidConfigurationComparisonResult())
// {
// result << QStringLiteral("ConfigurationComparison not valid");
// leave = true;
// }
// if (!interaction.isValidDiscoveredDevices())
// {
// result << QStringLiteral("DiscoveredDevices not valid");
// leave = true;
// }
// if (!interaction.isValidEntityIdentifier())
// {
// result << QStringLiteral("EntityIdentifier not valid");
// leave = true;
// }
// if (!interaction.isValidRegistrationType())
// {
// result << QStringLiteral("RegistrationType not valid");
// leave = true;
// }
// if (!interaction.isValidReportTime())
// {
// result << QStringLiteral("ReportTime not valid");
// leave = true;
// }
// if (leave)
// {
// ERROR_LOG(getLogger("NgsConnector.Inbound.GuezBiteReport"))
// << "Player: " << is.toString()
// << ", Cannot process Interaction. Reason(s): " << result.join(QLatin1String(", "));
// return;
// }
// rpr2::BiteResultStruct brs = interaction.getBiteResult();
// eb.configState(brs.DeviceOkay);
// eb.batteryState(brs.BatteryWarning);
// std::vector<TrainingAreaBase::EquipmentBiteError> be;
// be.resize(brs.ErrorCodes.size());
// for (unsigned int i = 0; i < brs.ErrorCodes.size(); ++i)
// be[i].canDeviceNumber(brs.ErrorCodes[i].DeviceId);
// eb.biteErrors(be);
// eb.biteState(interaction.getDiscoveredDevices());
// eb.configError(interaction.getConfigurationComparisonResult());
// eb.equipmentNumber(is.entityNumber());
// eb.registerType(interaction.getRegistrationType());
// eb.sampleTime(getMSecsSinceEpoch(interaction.getReportTime()));
// DEBUG_LOG(getLogger("NgsConnector.Inbound.GuezBiteReport"))
// << "Player: " << is.toString()
// << ", Device Okay: " << brs.DeviceOkay
// << ", Battery Warning: " << brs.BatteryWarning
// << ", Bite Error Count: " << be.size()
// << ", Registration Type: " << eb.registerType()
// << ", Config Error: " << eb.configError();
// emit biteReport(eb);
}
void NgsConnector::onNewGuezRequestBiteReport(const rpr2::IObserverGuezRequestBiteReportIntInstance &interaction)
{
IdentifierStruct is(interaction.getEntityIdentifier());
if (!is.isOwnElement())
return;
DEBUG_LOG(getLogger("NgsConnector.Inbound.GuezBiteRequest"))
<< "Player: " << is.toString()
<< ", Bite Report Type: " << interaction.getBiteReportType();
// TrainingAreaBase::DemandBiteRequest dbr;
// dbr.equipmentNumbers().push_back(is.entityNumber());
// dbr.requestId(1);
// dbr.withSelfTest(interaction.getBiteReportType() == rpr2::BiteReportTypeEnum8::StatusAfterSelftest);
// emit biteRequest(dbr);
}
rpr2::EventIdentifierStruct NgsConnector::getEventIdentifierStruct()
{
rpr2::EventIdentifierStruct evis;
evis.EventCount = m_eventCount++ % std::numeric_limits<ngs::UINT16>::max();
evis.IssuingObjectIdentifier.ID = std::to_string(IdentifierStruct(0).toInt64());
if (m_eventCount > std::numeric_limits<ngs::UINT16>::max())
emit eventCountOverflow();
return evis;
}
rpr2::TacticalStatusStruct NgsConnector::getTacticalStatusFromState(const ParticipantManagement::StateInformation &state)
{
// rpr2::TacticalStatusStruct ts;
// ts.TacticalStatus = static_cast<rpr2::TacticalStatusEnum8::ET>(state.vulnerabilityState().underlying());
// ts.TotalStatus = static_cast<rpr2::TotalStatusEnum32::ET>(state.vulnerabilityBits());
// ts.VulnerabilityKind = state.vulnerabilityKindId();
// return ts;
}
bool NgsConnector::setVulnerabilityState(int eqNo, const ParticipantManagement::StateInformation &state)
{
return false;
/*
rpr2::TacticalStatusStruct ts = getTacticalStatusFromState(state);
rpr2::IPlayerPhysicalEntityObjInstance *playerInstance = dynamic_cast<rpr2::IPlayerPhysicalEntityObjInstance *>(m_playerMap.value(eqNo, nullptr));
if (!playerInstance)
return false;
DamageModel dm(ts);
playerInstance->setDamageState(dm.damageState(-1));
playerInstance->setImmobilized(dm.immobilized(-1));
playerInstance->setFirePowerDisabled(dm.firePowerDisabled(-1));
DEBUG_LOG(getLogger("NgsConnector.Outbound.Player.Status"))
<< "Player: " << eqNo
<< ", New Total Status: " << ts.TotalStatus
<< ", New Tactical Status (shall be unused): " << ts.TacticalStatus;
rpr2::IPlayerGuezHumanObjInstance *humanInstance = dynamic_cast<rpr2::IPlayerGuezHumanObjInstance *>(playerInstance);
if (humanInstance)
{
humanInstance->setTacticalStatus(ts);
playerInstance->publish(getSimTime(state.stateTime()));
return true;
}
rpr2::IPlayerGuezGroundVehicleObjInstance *groundVehicleInstance = dynamic_cast<rpr2::IPlayerGuezGroundVehicleObjInstance *>(playerInstance);
if (groundVehicleInstance)
{
groundVehicleInstance->setTacticalStatus(ts);
playerInstance->publish(getSimTime(state.stateTime()));
return true;
}
ERROR_LOG(getLogger("NgsConnector.Outbound.Player.Status"))
<< "Player: " << eqNo
<< " is not Human or GroundVehicle. Cannot set status.";
return false;
*/
}
// Hit from Participant Management
//bool NgsConnector::setParticipantHit(int eqNo, const ParticipantManagement::StateInformation &state,
// const ParticipantPosition &partPos, int chargeType,
// ProjectDataManagement::StateChangeOriginator originatorType, int originatorEqNo)
//{
// // Set Tactical Status on Player
// auto *playerInstanceDest = m_playerMap.value(eqNo, nullptr);
// if (!playerInstanceDest || !playerInstanceDest->isValidEntityIdentifier())
// return false;
// if (!setVulnerabilityState(eqNo, state))
// return false;
// // Put Munition Detonation on HLA
// rpr2::IPlayerGuezHitIntClass &ic = m_somPlayer->getPlayerGuezHitIntClass();
// rpr2::IPlayerGuezHitIntInstance &icb = ic.newGuezHitIntInstance();
// icb.setMunition(getEtsCharge(chargeType));
// icb.setTargetIdentifier(playerInstanceDest->getEntityIdentifier());
// icb.setTargetLocation(partPos.toWorldLocation());
// icb.setHitResult(getHitResultEnum(state.vulnerabilityState()));
// IdentifierStruct is(0); // own excon
// rpr2::OriginatorTypeEnum16::ET originatorTypeRpr = rpr2::OriginatorTypeEnum16::Unknown;
// switch (originatorType.underlying())
// {
// case ProjectDataManagement::StateChangeOriginator_def::AreaEffectSimulation:
// {
// if (m_environmentObjects.contains(originatorEqNo)) // It's our AesItem, originatorEqNo is AesItemId is Entity Number
// is = IdentifierStruct(10 * originatorEqNo);
// else
// {
// // Obtain ExternalId
// int64_t externalId = m_ngsHandler->aesHandler()->externalId(originatorEqNo);
// // At this map, Entities and Objects are
// if (m_observerPlayerInstances.contains(externalId))
// {
// const rpr2::IObserverBaseEntityObjInstance *instance = dynamic_cast<const rpr2::IObserverBaseEntityObjInstance * >(m_observerPlayerInstances[originatorEqNo]);
// if (instance->isValidEntityIdentifier())
// is = IdentifierStruct(instance->getEntityIdentifier());
// }
// }
// originatorTypeRpr = rpr2::OriginatorTypeEnum16::AreaEffectSimulation;
// break;
// }
// case ProjectDataManagement::StateChangeOriginator_def::ExerciseControl:
// originatorTypeRpr = rpr2::OriginatorTypeEnum16::ExerciseControl;
// break;
// case ProjectDataManagement::StateChangeOriginator_def::ObserverController:
// originatorTypeRpr = rpr2::OriginatorTypeEnum16::ObserverController;
// break;
// case ProjectDataManagement::StateChangeOriginator_def::Participant:
// if (originatorType == ProjectDataManagement::StateChangeOriginator_def::Participant)
// {
// if (m_playerMap.contains(originatorEqNo))
// is = IdentifierStruct(originatorEqNo);
// else if (m_observerPlayerInstances.contains(originatorEqNo))
// {
// // Works as long as externalID == equipmentNo
// const rpr2::IObserverBaseEntityObjInstance *instance = dynamic_cast<const rpr2::IObserverBaseEntityObjInstance * >(m_observerPlayerInstances[originatorEqNo]);
// if (instance->isValidEntityIdentifier())
// is = IdentifierStruct(instance->getEntityIdentifier());
// }
// originatorTypeRpr = rpr2::OriginatorTypeEnum16::Participant;
// break;
// }
// Q_FALLTHROUGH();
// case ProjectDataManagement::StateChangeOriginator_def::Initialization:
// case ProjectDataManagement::StateChangeOriginator_def::FunctionalArea:
// case ProjectDataManagement::StateChangeOriginator_def::MaintainanceDevice:
// case ProjectDataManagement::StateChangeOriginator_def::Unknown:
// case ProjectDataManagement::StateChangeOriginator_def::WoundTreatmentDevice:
// case ProjectDataManagement::StateChangeOriginator_def::MedicalTimeout:
// case ProjectDataManagement::StateChangeOriginator_def::Sanitation:
// // Todo: Check, if IED and DUSMine actually can be handled correctly:
// case ProjectDataManagement::StateChangeOriginator_def::ImprovisedExplosiveDevice:
// case ProjectDataManagement::StateChangeOriginator_def::DusMine:
// originatorTypeRpr = rpr2::OriginatorTypeEnum16::Unknown;
// break;
// }
// icb.setOriginatorIdentifier(is.toEIS());
// icb.setOriginatorType(originatorTypeRpr);
// DEBUG_LOG(getLogger("NgsConnector.Outbound.GuezHit"))
// << "Player: " << eqNo
// << ", Originator Type: " << originatorType
// << ", Originator EIS: " << is.toString()
// << ", Charge Type: " << TypeStruct(getEtsCharge(chargeType)).toString()
// << ", Vulnerability State: " << state.vulnerabilityState();
// try
// {
// icb.publish(getSimTime(state.stateTime()));
// }
// catch (...)
// {
// ERROR_LOG(getLogger("NgsConnector.Outbound.GuezHit"))
// << "Player: " << eqNo
// << ", could not publish GuezHit!";
// }
// return true;
//}
//bool NgsConnector::setWeaponFire(int eqNo, const ParticipantManagement::ParticipantGearEvent &data)
//{
// rpr2::IPlayerWeaponFireIntClass &ic = m_somPlayer->getPlayerWeaponFireIntClass();
// rpr2::IPlayerWeaponFireIntInstance &icb = ic.newWeaponFireIntInstance();
// // FiringInstance ermitteln
// rpr2::RTIObjectIdStruct rSource;
// rSource.ID = std::to_string(IdentifierStruct(0).toInt64()); // Own Excon
// if (eqNo > 0)
// {
// auto *playerInstanceSource = m_playerMap.value(eqNo);
// if (!playerInstanceSource || !playerInstanceSource->isValidObjectName() || !playerInstanceSource->isValidSpatial())
// return false;
// rSource.ID = playerInstanceSource->getObjectName();
// icb.setFiringLocation(playerInstanceSource->getSpatial().DeadReckoningAlgorithm__A__Alternatives.SpatialStatic().WorldLocation);
// }
// icb.setEventIdentifier(getEventIdentifierStruct());
//// icb.setFireControlSolutionRange();
//// icb.setFireMissionIndex();
// icb.setFiringObjectIdentifier(rSource);
// icb.setFuseType(rpr2::FuseTypeEnum16::Other);
// icb.setInitialVelocityVector(rpr2::VelocityVectorStruct());
//// icb.setMunitionObjectIdentifier();
// icb.setMunitionType(getEtsCharge(data.charge().chargeTypeId()));
// icb.setQuantityFired(data.chargeAmount());
//// icb.setRateOfFire();
//// icb.setTargetObjectIdentifier();
// icb.setWarheadType(rpr2::WarheadTypeEnum16::Kinetic);
// icb.publish(getSimTime(data.sampleTime()));
// DEBUG_LOG(getLogger("NgsConnector.Outbound.WeaponFire"))
// << "Weapon Fire: "
// << "Charge Type: " << data.charge().chargeTypeId()
// << ", Shooter: " << eqNo
// << ", Rounds: " << data.chargeAmount();
// return true;
//}
//bool NgsConnector::setEquipmentBite(int eqNo, const TrainingAreaBase::EquipmentBite &data)
//{
// IdentifierStruct is = getIdentifierStructbyEquipmentNo(eqNo);
// if (is.isNull() || !is.isOwnElement())
// return false;
// rpr2::IPlayerGuezBiteReportIntClass &icx = m_somPlayer->getPlayerGuezBiteReportIntClass();
// rpr2::IPlayerGuezBiteReportIntInstance *icb = &icx.newGuezBiteReportIntInstance();
// rpr2::BiteResultStruct brs;
// brs.BatteryWarning = static_cast<rpr2::BatteryWarningEnum32::ET>(data.batteryState());
// brs.DeviceOkay = static_cast<rpr2::CanDeviceEnum32::ET>(data.configState());
// rpr2::ErrorStructVariableArray errorCodes;
// errorCodes.resize(data.biteErrors().size());
// int i = 0;
// for (const auto &error : data.biteErrors())
// {
// errorCodes[i].DeviceId = error.canDeviceNumber();
// errorCodes[i].SubDeviceId = error.subdeviceNumber();
// errorCodes[i].UniqueSubdeviceId = error.uniqueId();
// errorCodes[i].ErrorId = error.errorNumber();
// ++i;
// }
// brs.ErrorCodes = errorCodes;
// icb->setBiteResult(brs);
// icb->setConfigurationComparisonResult(data.configError());
// icb->setDiscoveredDevices(static_cast<rpr2::CanDeviceEnum32::ET>(data.biteState()));
// icb->setEntityIdentifier(is.toEIS());
// icb->setRegistrationType(static_cast<rpr2::RegistrationTypeEnum8::ET>(data.registerType()));
// icb->setReportTime(getClockTimeStruct(data.sampleTime()));
// icb->publish(getSimTime(data.sampleTime()));
// DEBUG_LOG(getLogger("NgsConnector.Outbound.GuezBiteReport"))
// << "Player: " << is.toString()
// << ", Device Okay: " << brs.DeviceOkay
// << ", Battery Warning: " << brs.BatteryWarning
// << ", Bite Error Count: " << errorCodes.size()
// << ", Registration Type: " << data.registerType()
// << ", Config Error: " << data.configError();
// return true;
//}
} // namespace HighLevelArchitecture