2888 lines
111 KiB
C++
Executable File
2888 lines
111 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 "ppm_handler.h"
|
|
#include "damage_model.h"
|
|
#include <Common/settings.h>
|
|
#include <Common/player_callback.h>
|
|
#include <Common/identifierstruct.h>
|
|
#include <Common/participantinformation.h>
|
|
|
|
#include "rpr/rpr_observer_guez_human_cb_notifier.h"
|
|
#include "rpr/rpr_observer_guez_groundvehicle_cb_notifier.h"
|
|
#include "rpr/rpr_observer_guez_observer_controller_cb_notifier.h"
|
|
|
|
#include "rpr/rpr_observer_guez_minefield_cb_notifier.h"
|
|
#include "rpr/rpr_observer_guez_minefield_breach_cb_notifier.h"
|
|
#include "rpr/rpr_observer_guez_fire_support_single_shot_cb_notifier.h"
|
|
|
|
#include "rpr/rpr_ia_munitiondetonation.h"
|
|
#include "rpr/rpr_ia_weaponfire.h"
|
|
#include "rpr/rpr_ia_guez_hit.h"
|
|
#include "rpr/rpr_ia_guez_init.h"
|
|
#include "rpr/rpr_ia_guez_exconengagement.h"
|
|
#include "rpr/rpr_ia_guez_bitereport.h"
|
|
#include "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;
|
|
|
|
Settings::Orientation orientation = Settings::spatialStructOrientation();
|
|
sss.Orientation.Phi = orientation.phi;
|
|
sss.Orientation.Psi = orientation.psi;
|
|
sss.Orientation.Theta = orientation.theta;
|
|
|
|
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) || participantData.equipmentNo == 0)
|
|
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) || participantData.equipmentNo == 0)
|
|
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) || participantData.equipmentNo == 0)
|
|
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) || participantData.equipmentNo == 0)
|
|
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 = 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;
|
|
}
|
|
|
|
// Hack as Saab returns with GuezHit -> Combat Ready, but doesn't change status if not restockCharges is true:
|
|
restockCharges = true;
|
|
|
|
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::guezMineField(const AreaEffectSimulation::MineArea &data)
|
|
{
|
|
IdentifierStruct is = IdentifierStruct::fromInt64(data.externalId());
|
|
if (!is.isOwnElement())
|
|
return false;
|
|
|
|
rpr2::IPlayerGuezMineFieldObjClass &ic = m_somPlayer->getPlayerGuezMineFieldObjClass();
|
|
const QList<rpr2::IPlayerEnvironmentObjectObjInstance *> icbs = m_environmentObjects.values(data.id());
|
|
|
|
// Check if it is expired or removed (now), then delete the segments.
|
|
if (data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired ||
|
|
data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsRemoved)
|
|
{
|
|
for (rpr2::IPlayerEnvironmentObjectObjInstance *item : icbs)
|
|
item->deleteObjectInstance(ngs::SimTime(true));
|
|
// And we're done. Don't publish anything if called by startup.
|
|
m_environmentObjects.remove(data.id());
|
|
return true;
|
|
}
|
|
|
|
if (data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsCreated &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsPrepared &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsActivated &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsPaused &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsReceived)
|
|
return false;
|
|
|
|
QVector<rpr2::IPlayerGuezMineFieldObjInstance *> minefields;
|
|
minefields.reserve(std::max(icbs.size(), int(data.segments().size())));
|
|
for (rpr2::IPlayerEnvironmentObjectObjInstance *item : icbs)
|
|
minefields.push_back(dynamic_cast<rpr2::IPlayerGuezMineFieldObjInstance *>(item));
|
|
|
|
int offset = 0;
|
|
// If size increased, add the needed segments.
|
|
while (minefields.size() < int(data.segments().size()))
|
|
{
|
|
rpr2::IPlayerGuezMineFieldObjInstance *icb = &ic.newGuezMineFieldObjInstance();
|
|
// Todo: Generate an external ID
|
|
is.setEntityNumber(offset++ + 10 * data.id());
|
|
icb->setObjectIdentifier(is.toEIS());
|
|
icb->setObjectType(dummyEOS());
|
|
minefields.push_back(icb);
|
|
}
|
|
|
|
// If size is reduced, remove those that are too many.
|
|
while (minefields.size() > int(data.segments().size()))
|
|
{
|
|
rpr2::IPlayerGuezMineFieldObjInstance *icb = minefields.takeLast();
|
|
if (icb)
|
|
icb->deleteObjectInstance(ngs::SimTime(true));
|
|
DEBUG_LOG(getLogger("NgsConnector.Outbound.MineField"))
|
|
<< "Minefield: Id: " << is.toString()
|
|
<< ", Name: " << data.name()
|
|
<< ", number of segments reduced, removing earlier published segment";
|
|
}
|
|
|
|
rpr2::ForceIdentifierEnum8::ET forceId = data.partyId().is_set() ? m_ngsHandler->ppmHandler()->forceIdentifierFromPartyId(data.partyId().get()) : rpr2::ForceIdentifierEnum8::Other;
|
|
|
|
m_environmentObjects.remove(data.id());
|
|
for (int i = 0; i < minefields.size(); ++i)
|
|
{
|
|
rpr2::IPlayerGuezMineFieldObjInstance *icb = minefields.at(i);
|
|
if (!icb)
|
|
continue; // should not happen
|
|
|
|
const AreaEffectSimulation::MineSegment &segment = data.segments()[i];
|
|
|
|
icb->setActivationTime(getClockTimeStruct(data.effectStart().is_set() ? data.effectStart().get() : 0));
|
|
icb->setDeactivated(data.effectStateId().underlying() != AreaEffectSimulation::AesEffectState_def::EsActivated);
|
|
if (data.effectStateId().underlying() == AreaEffectSimulation::AesEffectState_def::EsExpired ||
|
|
data.effectStateId().underlying() == AreaEffectSimulation::AesEffectState_def::EsRemoved)
|
|
icb->setPercentComplete(100);
|
|
else
|
|
icb->setPercentComplete(0);
|
|
icb->setAreaEffectSimulationName(rpr2::OMT13string(data.name()));
|
|
icb->setDuration(data.effectDuration() / 1000 / 60 / 60);
|
|
icb->setMineType(getEtsCharge(data.chargeStruct().chargeTypeId()));
|
|
icb->setMineCount((data.density() - 0.1) / 0.008);
|
|
icb->setForceIdentifier(forceId);
|
|
icb->setPointsData(positionArray(mineAreaSegment(segment, data.width(), data.density(), data.isCenterLine())));
|
|
icb->setObjectType(dummyEOS());
|
|
icb->publish(getSimTime(data.sampleTime()));
|
|
DEBUG_LOG(getLogger("NgsConnector.Outbound.MineField"))
|
|
<< "Minefield: Id: " << is.toString()
|
|
<< ", Name: " << data.name()
|
|
<< ". Published Segment.";
|
|
m_environmentObjects.insertMulti(data.id(), icb);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NgsConnector::guezMineFieldBreach(const AreaEffectSimulation::MineCorridor &data)
|
|
{
|
|
IdentifierStruct is = IdentifierStruct::fromInt64(data.externalId());
|
|
if (!is.isOwnElement())
|
|
return false;
|
|
|
|
rpr2::IPlayerGuezMineFieldBreachObjClass &ic = m_somPlayer->getPlayerGuezMineFieldBreachObjClass();
|
|
const QList<rpr2::IPlayerEnvironmentObjectObjInstance *> icbs = m_environmentObjects.values(data.id());
|
|
|
|
// Check if it is expired or removed (now), then delete the segments.
|
|
if (data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired ||
|
|
data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsRemoved)
|
|
{
|
|
for (rpr2::IPlayerEnvironmentObjectObjInstance *item : icbs)
|
|
item->deleteObjectInstance(ngs::SimTime(true));
|
|
m_environmentObjects.remove(data.id());
|
|
// And we're done. Don't publish anything if called by startup.
|
|
return true;
|
|
}
|
|
|
|
if (data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsCreated &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsReceived &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsPrepared &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsActivated &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsPaused)
|
|
return false;
|
|
|
|
QMap<int, rpr2::IPlayerGuezMineFieldBreachObjInstance *> map;
|
|
int c = 0;
|
|
for (rpr2::IPlayerEnvironmentObjectObjInstance *item : icbs)
|
|
map.insert(c++, dynamic_cast<rpr2::IPlayerGuezMineFieldBreachObjInstance *>(item));
|
|
|
|
|
|
// If size increased, add the needed segments.
|
|
if (map.size() < int(data.segments().size()))
|
|
{
|
|
int offset = 0;
|
|
for (int i = map.size(); i < int(data.segments().size()); ++i)
|
|
{
|
|
rpr2::IPlayerGuezMineFieldBreachObjInstance *icb = &ic.newGuezMineFieldBreachObjInstance();
|
|
// TODO: why not is.setEntityNumber(offset++ + 10 * data.id()); as in guezMineField() ?
|
|
const IdentifierStruct isSegment(offset++ + 10 * data.id());
|
|
icb->setObjectIdentifier(isSegment.toEIS());
|
|
map.insert(i, icb);
|
|
}
|
|
}
|
|
|
|
// If size is reduced, remove those that are too many.
|
|
for (int i = int(data.segments().size()); i < map.size(); ++i)
|
|
{
|
|
rpr2::IPlayerGuezMineFieldBreachObjInstance *icb = map.value(i);
|
|
if (icb)
|
|
icb->deleteObjectInstance(ngs::SimTime(true));
|
|
DEBUG_LOG(getLogger("NgsConnector.Outbound.MineFieldBreach"))
|
|
<< "Minefield Breach: Id: " << is.toString()
|
|
<< ", Name: " << data.name()
|
|
<< ", number of segments reduced, removing earlier published segment";
|
|
map.remove(i);
|
|
}
|
|
|
|
m_environmentObjects.remove(data.id());
|
|
|
|
for (int i = 0; i < map.size() - 1; ++i)
|
|
{
|
|
rpr2::IPlayerGuezMineFieldBreachObjInstance *icb = map.value(i);
|
|
if (!icb)
|
|
continue; // should not happen
|
|
icb->setActivationTime(getClockTimeStruct(data.effectStart().is_set() ? data.effectStart().get() : 0));
|
|
icb->setAreaEffectSimulationName(rpr2::OMT13string(data.name()));
|
|
icb->setPointsData(positionArray(mineCorridorSegment(data.segments().at(i), data.segments().at(i + 1), data.width())));
|
|
icb->setDeactivated(data.effectStateId().underlying() != AreaEffectSimulation::AesEffectState_def::EsActivated);
|
|
if (data.effectStateId().underlying() == AreaEffectSimulation::AesEffectState_def::EsExpired ||
|
|
data.effectStateId().underlying() == AreaEffectSimulation::AesEffectState_def::EsRemoved)
|
|
icb->setPercentComplete(100);
|
|
else
|
|
icb->setPercentComplete(0);
|
|
icb->setObjectType(dummyEOS());
|
|
icb->publish(getSimTime(data.sampleTime()));
|
|
DEBUG_LOG(getLogger("NgsConnector.Outbound.MineFieldBreach"))
|
|
<< "Minefield Breach: Id: " << is.toString()
|
|
<< ", Name: " << data.name()
|
|
<< ". Published Segment.";
|
|
m_environmentObjects.insertMulti(data.id(), icb);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool NgsConnector::guezNuclearAgent(const AreaEffectSimulation::NContamination &data)
|
|
{
|
|
IdentifierStruct is = IdentifierStruct::fromInt64(data.externalId());
|
|
if (!is.isOwnElement())
|
|
return false;
|
|
|
|
rpr2::IPlayerGuezNuclearAgentAreaObjClass &ic = m_somPlayer->getPlayerGuezNuclearAgentAreaObjClass();
|
|
rpr2::IPlayerGuezNuclearAgentAreaObjInstance *icb = dynamic_cast<rpr2::IPlayerGuezNuclearAgentAreaObjInstance *>(m_environmentObjects.value(data.id()));
|
|
|
|
// Check if it is expired or removed (now), then delete the segments.
|
|
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;
|
|
}
|
|
|
|
if (data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsCreated &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsReceived &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsPrepared &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsActivated &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsPaused)
|
|
return false;
|
|
|
|
if (!icb)
|
|
icb = &ic.newGuezNuclearAgentAreaObjInstance();
|
|
|
|
ParticipantPosition pos;
|
|
pos.lon = data.impactPosition().lon();
|
|
pos.lat = data.impactPosition().lat();
|
|
|
|
// Todo: Generate an external ID
|
|
is.setEntityNumber(10 * data.id());
|
|
icb->setObjectIdentifier(is.toEIS());
|
|
icb->setActivationTime(getClockTimeStruct(data.effectStart().is_set() ? data.effectStart().get() : 0));
|
|
icb->setAreaEffectSimulationName(rpr2::OMT13string(data.name()));
|
|
icb->setDuration(data.effectDuration());
|
|
icb->setDetonationLocation(pos.toWorldLocation());
|
|
icb->setPointsData(positionArray(nContamination(data)));
|
|
icb->setRadius(data.impactRadius());
|
|
icb->setObjectType(dummyEOS());
|
|
icb->publish(getSimTime(data.sampleTime()));
|
|
m_environmentObjects.insert(data.id(), icb);
|
|
|
|
DEBUG_LOG(getLogger("NgsConnector.Outbound.NuclearAgentArea"))
|
|
<< "Nuclear Agent Area: Id: " << is.toString()
|
|
<< ", Name: " << data.name()
|
|
<< ". Published Area.";
|
|
return true;
|
|
}
|
|
|
|
bool NgsConnector::guezChemicalAgent(const AreaEffectSimulation::BCContamination &data)
|
|
{
|
|
IdentifierStruct is = IdentifierStruct::fromInt64(data.externalId());
|
|
if (!is.isOwnElement())
|
|
return false;
|
|
|
|
rpr2::IPlayerGuezChemicalAgentAreaObjClass &ic = m_somPlayer->getPlayerGuezChemicalAgentAreaObjClass();
|
|
rpr2::IPlayerGuezChemicalAgentAreaObjInstance *icb = dynamic_cast<rpr2::IPlayerGuezChemicalAgentAreaObjInstance *>(m_environmentObjects.value(data.id()));
|
|
|
|
// Check if it is expired or 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;
|
|
}
|
|
|
|
if (data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsCreated &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsReceived &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsPrepared &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsActivated &&
|
|
data.effectStateId() != AreaEffectSimulation::AesEffectState_def::EsPaused)
|
|
return false;
|
|
|
|
if (!icb)
|
|
icb = &ic.newGuezChemicalAgentAreaObjInstance();
|
|
|
|
ParticipantPosition pos;
|
|
pos.lon = data.impactPosition().lon();
|
|
pos.lat = data.impactPosition().lat();
|
|
|
|
// Better: Don't use 400x, obtain volatility type from chargeType-Topic
|
|
rpr2::ChemicalAgentTypeEnum8::ET type = rpr2::ChemicalAgentTypeEnum8::Other;
|
|
switch (data.chargeStruct().chargeTypeId())
|
|
{
|
|
case 341:
|
|
type = rpr2::ChemicalAgentTypeEnum8::Sarin;
|
|
break;
|
|
case 342:
|
|
type = rpr2::ChemicalAgentTypeEnum8::VX;
|
|
break;
|
|
case 343:
|
|
type = rpr2::ChemicalAgentTypeEnum8::SLost;
|
|
break;
|
|
default:
|
|
type = rpr2::ChemicalAgentTypeEnum8::Other;
|
|
}
|
|
is.setEntityNumber(10 * data.id());
|
|
icb->setObjectIdentifier(is.toEIS());
|
|
icb->setDeactivated(data.effectStateId().underlying() != AreaEffectSimulation::AesEffectState_def::EsActivated);
|
|
icb->setActivationTime(getClockTimeStruct(data.effectStart().is_set() ? data.effectStart().get() : 0));
|
|
icb->setAreaEffectSimulationName(rpr2::OMT13string(data.name()));
|
|
icb->setDuration(data.effectDuration() / 1000 / 60); // Duration in Minutes...
|
|
icb->setDetonationLocation(pos.toWorldLocation());
|
|
if (data.effectStateId().underlying() == AreaEffectSimulation::AesEffectState_def::EsExpired ||
|
|
data.effectStateId().underlying() == AreaEffectSimulation::AesEffectState_def::EsRemoved)
|
|
icb->setPercentComplete(100);
|
|
else
|
|
icb->setPercentComplete(0);
|
|
// PointsData will be set by AesItemViewChanged()
|
|
icb->setChemicalAgentType(type);
|
|
icb->setRadius(data.impactRadius());
|
|
rpr2::ForceIdentifierEnum8::ET forceId = data.partyId().is_set() ? m_ngsHandler->ppmHandler()->forceIdentifierFromPartyId(data.partyId().get()) : rpr2::ForceIdentifierEnum8::Other;
|
|
icb->setForceIdentifier(forceId);
|
|
icb->setIsPermanentAgent(type != rpr2::ChemicalAgentTypeEnum8::Sarin);
|
|
icb->setObjectType(dummyEOS());
|
|
icb->publish(getSimTime(data.sampleTime()));
|
|
m_environmentObjects.insert(data.id(), icb);
|
|
|
|
DEBUG_LOG(getLogger("NgsConnector.Outbound.ChemicalAgentArea"))
|
|
<< "Chemical Agent Area: Id: " << is.toString()
|
|
<< ", Name: " << data.name()
|
|
<< ". Published Area.";
|
|
return true;
|
|
}
|
|
bool NgsConnector::setItemForm(int aesItemId, int aesTypeId, const std::vector<Core::GeoPosition> &form)
|
|
{
|
|
if (form.size() == 0)
|
|
m_arealObjectForms.remove(aesItemId);
|
|
else
|
|
m_arealObjectForms.insert(aesItemId, form);
|
|
|
|
if (!m_environmentObjects.contains(aesItemId))
|
|
return true;
|
|
|
|
std::vector<Core::GeoPosition> reducedForm;
|
|
switch (aesTypeId)
|
|
{
|
|
case AesType_def::AtBCContamination:
|
|
reducedForm = bcReduction(form);
|
|
break;
|
|
case AesType_def::AtMineCorridor:
|
|
case AesType_def::AtExplosionArea:
|
|
case AesType_def::AtExplosionSingle:
|
|
case AesType_def::AtMineArea:
|
|
case AesType_def::AtNContamination:
|
|
// Change only occurs when changing base data.
|
|
return true;
|
|
case AesType_def::AtUnknown:
|
|
case AesType_def::AtDangerArea:
|
|
case AesType_def::AtFunctionalArea:
|
|
case AesType_def::AtBorderline:
|
|
case AesType_def::AtTechnicalArea:
|
|
case AesType_def::AtReconArea:
|
|
case AesType_def::AtDusSingleMine:
|
|
case AesType_def::AtExplosionAreaSingleExplosions:
|
|
case AesType_def::AtMineAreaSingleMines:
|
|
case AesType_def::AtGasPipe:
|
|
// Not published.
|
|
return true;
|
|
}
|
|
|
|
|
|
rpr2::IPlayerArealObjectObjInstance *ao = dynamic_cast<rpr2::IPlayerArealObjectObjInstance *>(m_environmentObjects.value(aesItemId));
|
|
if (!ao)
|
|
return false;
|
|
|
|
ao->setPointsData(positionArray(reducedForm));
|
|
ao->publish(getSimTime()); // No time given, take current time
|
|
// Note: Case returns whenever Type is NOT Chemical Agent. If that changes, we have to update the logger channel
|
|
DEBUG_LOG(getLogger("NgsConnector.Outbound.ChemicalAgentArea"))
|
|
<< "Chemical Agent Area: Id: " << aesItemId
|
|
<< ". Shape Changed. Updated on HLA.";
|
|
|
|
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;
|
|
|
|
DEBUG_LOG(getLogger("NgsConnector.Outbound.Player.Orientation"))
|
|
<< "Player: " << eqNo << ", Orientation(Phi, Psi, Theta): "
|
|
<< ss.DeadReckoningAlgorithm__A__Alternatives.SpatialStatic().Orientation.Phi << ", "
|
|
<< ss.DeadReckoningAlgorithm__A__Alternatives.SpatialStatic().Orientation.Psi << ", "
|
|
<< ss.DeadReckoningAlgorithm__A__Alternatives.SpatialStatic().Orientation.Theta;
|
|
|
|
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::mineAreaSegment(const AreaEffectSimulation::MineSegment &segment, double width, double density, bool bIsCenterline)
|
|
{
|
|
if (qFuzzyIsNull(density))
|
|
return QPolygonF();
|
|
|
|
LtsCoordTrans::UtmCoordinate startPositionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(segment.positionStart().lon(), segment.positionStart().lat());
|
|
LtsCoordTrans::UtmCoordinate endPositionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(segment.positionEnd().lon(), segment.positionEnd().lat(), startPositionUtm.zone);
|
|
|
|
const QLineF line({startPositionUtm.x, startPositionUtm.y}, {endPositionUtm.x, endPositionUtm.y});
|
|
|
|
|
|
const auto yOfs1 = bIsCenterline ? (width / 2) : -width;
|
|
const auto yOfs2 = bIsCenterline ? -(width / 2) : 0;
|
|
QPolygonF polyUtm = QPolygonF({QPointF(0, yOfs2),
|
|
QPointF(0, yOfs1),
|
|
QPointF(line.length(), yOfs1),
|
|
QPointF(line.length(), yOfs2)
|
|
});
|
|
|
|
// Compass, not mathematical!
|
|
polyUtm = fromRotation(0.0 - line.angle()).map(polyUtm);
|
|
|
|
const QPolygonF poly(utmToGeogrphic(polyUtm, startPositionUtm));
|
|
return poly;
|
|
}
|
|
|
|
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)
|
|
{
|
|
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.chargeStruct().chargeTypeId(ct.id());
|
|
ma.density(0.008 * minefield->getMineCount() + 0.1); // 0 -> 0.1 , 100 -> 0.9
|
|
ma.effectStart(getMSecsSinceEpoch(minefield->getActivationTime()));
|
|
ma.effectSourceId(ProjectDataManagement::EffectSource::ES_HLA);
|
|
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)
|
|
{
|
|
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.effectSourceId(ProjectDataManagement::EffectSource::ES_HLA);
|
|
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)
|
|
{
|
|
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 = 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) // deactivated
|
|
{
|
|
qint64 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;
|
|
|
|
//
|
|
// create effect at EXCON ...
|
|
//
|
|
|
|
//
|
|
// ... based on ExplosionClusterSingleEffectOnly
|
|
//
|
|
|
|
{
|
|
// try to create an ExplosionCluster 'light' (point geometry, no trajectory)
|
|
ExplosionClusterSingleEffectOnlyRequest request;
|
|
// id
|
|
request.id(0);
|
|
|
|
// externalId
|
|
IdentifierStruct is(interaction.getEventIdentifier().EventCount);
|
|
is.setSiteId(255); // Dummy - Must not be of either site.
|
|
request.externalId(is.toInt64()); // dummy val, inserted to prevent aes_handler from dropping this telegram
|
|
|
|
// effectStart, duration
|
|
request.effectStart(QDateTime::currentDateTimeUtc().toMSecsSinceEpoch() + ACTIVATION_LEAD_TIME);
|
|
|
|
// geometry
|
|
request.impactPosition( ParticipantPosition(interaction.getDetonationLocation()).toGeoPosition2D() );
|
|
|
|
// charge
|
|
const auto ct = m_ngsHandler->ppmHandler()->chargeTypeFromDisEntity(TypeStruct(interaction.getMunitionType()).toString());
|
|
request.chargeTypeId(ct.id());
|
|
|
|
// names
|
|
const QString name = tr("SAAB Fire: %1").arg(interaction.getEventIdentifier().EventCount);
|
|
request.name(name.toStdString()); // ZpNummer
|
|
request.element(request.name()); // element
|
|
|
|
DEBUG_LOG(getLogger("NgsConnector.Inbound.MunitionDetonation"))
|
|
<< "Munition Detonation: "
|
|
<< "Location: " << ParticipantPosition(interaction.getDetonationLocation()).toString()
|
|
<< ", Charge Type: " << ct.disEntity();
|
|
|
|
emit munitionDetonationExplosionClusterSingleEffectOnly(request);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// ... based on ExplosionSingleModifyRequest
|
|
//
|
|
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);
|
|
req.effectSourceId(ProjectDataManagement::EffectSource::ES_HLA);
|
|
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)
|
|
{
|
|
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
|