/** * Connect to ngs / hla and provide the basic interface * $Id$ * $HeadURL$ * $Author$ * Created by Christian Ehrlicher, SLSE, 2017-04-07 */ #include "ngs_connector.h" #include "ngs_handler.h" #include "damage_model.h" #include #include #include #include #include "../Guez/rpr/rpr_observer_guez_human_cb_notifier.h" #include "../Guez/rpr/rpr_observer_guez_groundvehicle_cb_notifier.h" #include "../Guez/rpr/rpr_observer_guez_observer_controller_cb_notifier.h" #include "../Guez/rpr/rpr_observer_guez_minefield_cb_notifier.h" #include "../Guez/rpr/rpr_observer_guez_minefield_breach_cb_notifier.h" #include "../Guez/rpr/rpr_observer_guez_fire_support_single_shot_cb_notifier.h" #include "../Guez/rpr/rpr_ia_munitiondetonation.h" #include "../Guez/rpr/rpr_ia_weaponfire.h" #include "../Guez/rpr/rpr_ia_guez_hit.h" #include "../Guez/rpr/rpr_ia_guez_init.h" #include "../Guez/rpr/rpr_ia_guez_exconengagement.h" #include "../Guez/rpr/rpr_ia_guez_bitereport.h" #include "../Guez/rpr/rpr_ia_guez_requestbitereport.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace AreaEffectSimulation; namespace HighLevelArchitecture { static inline qint64 simTimeToMSec(const ngs::SimTime &st) { qint64 mSecs = st.getSeconds() * 1000LL; mSecs += st.getMicroSeconds() / 1000; return mSecs; } static inline rpr2::SpatialStruct spatialStructFromWorldLocation(const rpr2::WorldLocationStruct &wls) { rpr2::SpatialStaticStruct sss; sss.WorldLocation = wls; sss.IsFrozen = false; sss.Orientation.Phi = 3.138309f; sss.Orientation.Psi = 2.446645f; sss.Orientation.Theta = -0.879588f; rpr2::SpatialStruct ss; ss.DeadReckoningAlgorithm__A__Alternatives.discriminant(rpr2::DeadReckoningAlgorithmEnum8::Static); ss.DeadReckoningAlgorithm__A__Alternatives.SpatialStatic(sss); return ss; } static inline rpr2::EnvironmentObjectTypeStruct dummyEOS() { return {2, 3, 4, 5}; } // // NgsConnector // NgsConnector::NgsConnector(const QString &fedName, NgsHandler *ngsHandler) : m_ngsHandler(ngsHandler) , m_fedName(fedName) , m_swadmin(&ngs::SimulatedWorldAPI::getSimulatedWorldAdmin()) , m_master(nullptr) , m_somPlayer(nullptr) , m_playerCallback(new PlayerCallback()) , m_humanCallback(new ObserverGuezHumanCBNotifier()) , m_observerControllerCallback(new ObserverGuezObserverControllerCBNotifier()) , m_groundVehicleCallback(new ObserverGuezGroundVehicleCBNotifier()) , m_minefieldCallback(new ObserverGuezMineFieldCBNotifier()) , m_minefieldBreachCallback(new ObserverGuezMineFieldBreachCBNotifier()) , m_munitionDetonationCallback(new ObserverMunitionDetonationCBNotifier()) , m_weaponfireCallback(new ObserverWeaponFireCBNotifier()) , m_hitCallback(new ObserverGuezHitCBNotifier()) , m_initCallback(new ObserverGuezInitCBNotifier()) , m_biteReportCallback(new ObserverGuezBiteReportCBNotifier()) , m_requestBiteReportCallback(new ObserverGuezRequestBiteReportCBNotifier()) , m_bInitialized(false) , m_bCanPublishData(false) , m_timer(new QTimer(this)) , m_logger(getLogger("NgsConnector")) { connect(m_timer, &QTimer::timeout, this, &NgsConnector::go); connect(m_playerCallback, &PlayerCallback::firstTick, this, &NgsConnector::onFirstTickFinished); // Ground Vehicle connectObserverGuezGroundVehicleObjectSignals(m_groundVehicleCallback); // Human connectObserverGuezHumanObjectSignals(m_humanCallback); // Observer / Controller connectObserverGuezObserverControllerObjectSignals(m_observerControllerCallback); // Mine Field connectObserverGuezMineFieldObjectSignals(m_minefieldCallback); // Mine Field Breach connectObserverGuezMineFieldBreachObjectSignals(m_minefieldBreachCallback); // Munition Detonation connect(m_munitionDetonationCallback, &ObserverMunitionDetonationCBNotifier::newMunitionDetonation, this, &NgsConnector::onNewMunitionDetonation); // Weapon Fire connect(m_weaponfireCallback, &ObserverWeaponFireCBNotifier::newWeaponFire, this, &NgsConnector::onNewWeaponFire); // Hit connect(m_hitCallback, &ObserverGuezHitCBNotifier::newGuezHit, this, &NgsConnector::onNewGuezHit); // Init connect(m_initCallback, &ObserverGuezInitCBNotifier::newGuezInit, this, &NgsConnector::onNewGuezInit); // Request Bite Report connect(m_requestBiteReportCallback, &ObserverGuezRequestBiteReportCBNotifier::newGuezRequestBiteReport, this, &NgsConnector::onNewGuezRequestBiteReport); // Bite Report connect(m_biteReportCallback, &ObserverGuezBiteReportCBNotifier::newGuezBiteReport, this, &NgsConnector::onNewGuezBiteReport); } NgsConnector::~NgsConnector() { uninitialize(); delete m_playerCallback; delete m_humanCallback; delete m_observerControllerCallback; delete m_groundVehicleCallback; delete m_minefieldCallback; delete m_minefieldBreachCallback; delete m_munitionDetonationCallback; delete m_weaponfireCallback; delete m_initCallback; delete m_hitCallback; delete m_requestBiteReportCallback; delete m_biteReportCallback; delete m_timer; } bool NgsConnector::initialize(ngs::IObserver::ProtocolType protocol, const QString &playerName, const QString &appDirPath) { QString swconf = appDirPath + QLatin1Char('/') + Settings::swConfFileName(); m_bInitialized = true; // NGS Initialisation try { m_master = &m_swadmin->getIFederationMaster(protocol, qPrintable(swconf), Settings::fomIdentifier().toStdString(), Settings::rtiIdentifier().toStdString()); // "", "MAK" } catch (const ngs::NGSSimWorldException &e) { ERROR_LOG(m_logger) << "caught exception during init (getIFederationMaster): " << e.print(); return false; } ngs::IPlayer *player = nullptr; switch (protocol) { case ngs::IObserver::HLA: { try { m_master->createFederation(m_fedName.toStdString()); } catch (const NGSException &e) { ERROR_LOG(m_logger) << "caught exception during init (createFederation): " << e.print(); return false; } player = &m_swadmin->getIPlayer(m_fedName.toStdString(), playerName.toStdString(), *m_playerCallback, Settings::swConfFileName().toLatin1().data(), Settings::fomIdentifier().toStdString(), Settings::rtiIdentifier().toStdString()); break; } case ngs::IObserver::CORBANOTIFY: case ngs::IObserver::DIS: { unsigned char federationId = m_fedName.toUShort(); m_master->createFederation(federationId); player = &m_swadmin->getIPlayer(federationId, playerName.toStdString(), *m_playerCallback, protocol, Settings::swConfFileName().toLatin1().data(), Settings::fomIdentifier().toStdString()); break; } } m_somPlayer = dynamic_cast(player); m_somPlayer->configureSimTime(ngs::IObserver::REALTIMECLOCK, ngs::SimTime(0, 0)); m_timer->start(10); return true; } void NgsConnector::uninitialize() { if (!m_bInitialized) return; m_bInitialized = false; m_timer->stop(); unsubscribeFromNgs(); if (m_swadmin) m_swadmin->resignInterface(); if (m_somPlayer) m_somPlayer->resignSimulatedWorld(); if (m_master) { m_master->destroyFederation(m_fedName.toStdString()); m_master->resignInterface(); m_master = nullptr; } } void NgsConnector::subscribeAtNgs() { m_enitityNumberCounter = 1; // restart m_eventCount = 1; INFO_LOG(m_logger) << "Subscribe at NGS - Guez Human Objects"; rpr2::IObserverGuezHumanObjClass &humanObjClass = m_somPlayer->getObserverGuezHumanObjClass(*m_humanCallback); humanObjClass.subscribeAllAttributes(); humanObjClass.subscribe(); INFO_LOG(m_logger) << "Subscribe at NGS - Guez ObserverController Objects"; rpr2::IObserverGuezObserverControllerObjClass &observerControllerObjClass = m_somPlayer->getObserverGuezObserverControllerObjClass(*m_observerControllerCallback); observerControllerObjClass.subscribeAllAttributes(); observerControllerObjClass.subscribe(); INFO_LOG(m_logger) << "Subscribe at NGS - Guez GroundVehicle Objects"; rpr2::IObserverGuezGroundVehicleObjClass &groundVehicleObjClass = m_somPlayer->getObserverGuezGroundVehicleObjClass(*m_groundVehicleCallback); groundVehicleObjClass.subscribeAllAttributes(); groundVehicleObjClass.subscribe(); INFO_LOG(m_logger) << "Subscribe at NGS - Guez MineField Objects"; rpr2::IObserverGuezMineFieldObjClass &minefieldObjClass = m_somPlayer->getObserverGuezMineFieldObjClass(*m_minefieldCallback); minefieldObjClass.subscribeAllAttributes(); minefieldObjClass.subscribe(); INFO_LOG(m_logger) << "Subscribe at NGS - Guez MineField Breach Objects"; rpr2::IObserverGuezMineFieldBreachObjClass &minefieldBreachObjClass = m_somPlayer->getObserverGuezMineFieldBreachObjClass(*m_minefieldBreachCallback); minefieldBreachObjClass.subscribeAllAttributes(); minefieldBreachObjClass.subscribe(); rpr2::IObserverMunitionDetonationIntClass &md = m_somPlayer->getObserverMunitionDetonationIntClass(*m_munitionDetonationCallback); md.subscribe(); rpr2::IObserverWeaponFireIntClass &wfic = m_somPlayer->getObserverWeaponFireIntClass(*m_weaponfireCallback); wfic.subscribe(); rpr2::IObserverGuezInitIntClass &giic = m_somPlayer->getObserverGuezInitIntClass(*m_initCallback); giic.subscribe(); rpr2::IObserverGuezHitIntClass &ghic = m_somPlayer->getObserverGuezHitIntClass(*m_hitCallback); ghic.subscribe(); rpr2::IObserverGuezRequestBiteReportIntClass &grbric = m_somPlayer->getObserverGuezRequestBiteReportIntClass(*m_requestBiteReportCallback); grbric.subscribe(); rpr2::IObserverGuezBiteReportIntClass &gbric = m_somPlayer->getObserverGuezBiteReportIntClass(*m_biteReportCallback); gbric.subscribe(); m_timer->start(); m_bCanPublishData = true; } void NgsConnector::unsubscribeFromNgs() { m_bCanPublishData = false; if (m_somPlayer) { INFO_LOG(m_logger) << "Unsubscribe at NGS - Guez Human Objects"; rpr2::IObserverGuezHumanObjClass &humanObjClass = m_somPlayer->getObserverGuezHumanObjClass(*m_humanCallback); humanObjClass.unsubscribe(); INFO_LOG(m_logger) << "Unsubscribe at NGS - Guez ObserverController Objects"; rpr2::IObserverGuezObserverControllerObjClass &observerControllerObjClass = m_somPlayer->getObserverGuezObserverControllerObjClass(*m_observerControllerCallback); observerControllerObjClass.unsubscribe(); INFO_LOG(m_logger) << "Unsubscribe at NGS - Guez GroundVehicle Objects"; rpr2::IObserverGuezGroundVehicleObjClass &groundVehicleObjClass = m_somPlayer->getObserverGuezGroundVehicleObjClass(*m_groundVehicleCallback); groundVehicleObjClass.unsubscribe(); INFO_LOG(m_logger) << "Unsubscribe at NGS - Guez MineField Objects"; rpr2::IObserverGuezMineFieldObjClass &minefieldObjClass = m_somPlayer->getObserverGuezMineFieldObjClass(*m_minefieldCallback); minefieldObjClass.unsubscribe(); INFO_LOG(m_logger) << "Unsubscribe at NGS - Guez MineField Breach Objects"; rpr2::IObserverGuezMineFieldBreachObjClass &minefieldBreachObjClass = m_somPlayer->getObserverGuezMineFieldBreachObjClass(*m_minefieldBreachCallback); minefieldBreachObjClass.unsubscribe(); } for (rpr2::IPlayerBaseEntityObjInstance *player : qAsConst(m_playerMap)) player->deleteObjectInstance(getSimTime()); m_playerMap.clear(); for (rpr2::IPlayerEnvironmentObjectObjInstance *environmentObject : qAsConst(m_environmentObjects)) environmentObject->deleteObjectInstance(getSimTime()); m_environmentObjects.clear(); for (auto it = m_observerPlayerInstances.cbegin(); it != m_observerPlayerInstances.cend(); ++it) emit virtualParticipantDeleted(it.key()); for (auto it = m_observerEnvironmentObjects.cbegin(); it != m_observerEnvironmentObjects.cend(); ++it) emit virtualParticipantDeleted(it.key()); m_observerPositions.clear(); m_newObjectsWithoutParticipantIdSet.clear(); m_observerPlayerInstances.clear(); m_observerEnvironmentObjects.clear(); qDeleteAll(m_damageModelMap); m_damageModelMap.clear(); m_enitityNumberCounter = 1; // restart m_eventCount = 1; } bool NgsConnector::addHuman(const ParticipantInformation &participantData, const rpr2::TacticalStatusStruct &state) { if (m_playerMap.contains(participantData.equipmentNo)) return false; DEBUG_LOG(getLogger("NgsConnector.Outbound.Startup")) << "addHuman(" << participantData.equipmentNo << ", " << participantData.partyId << ", " << participantData.typeStruct.toString() << ", " << state.TacticalStatus << ")"; rpr2::IPlayerGuezHumanObjClass &player = m_somPlayer->getPlayerGuezHumanObjClass(); rpr2::IPlayerGuezHumanObjInstance *playerInstance = &player.newGuezHumanObjInstance(); DamageModel dm(state); playerInstance->setDamageState(dm.damageState(-1)); playerInstance->setImmobilized(dm.immobilized(-1)); playerInstance->setFirePowerDisabled(dm.firePowerDisabled(-1)); playerInstance->setTacticalStatus(state); return addPhysicalEntity(playerInstance, participantData); } bool NgsConnector::addObserverController(const ParticipantInformation &participantData) { if (m_playerMap.contains(participantData.equipmentNo)) return false; DEBUG_LOG(getLogger("NgsConnector.Outbound.Startup")) << "addObserverController(" << participantData.equipmentNo << ", " << participantData.partyId << ", " << participantData.typeStruct.toString() << ")"; rpr2::IPlayerGuezObserverControllerObjClass &player = m_somPlayer->getPlayerGuezObserverControllerObjClass(); rpr2::IPlayerGuezObserverControllerObjInstance *playerInstance = &player.newGuezObserverControllerObjInstance(); return addPhysicalEntity(playerInstance, participantData); } bool NgsConnector::addGroundVehicle(const ParticipantInformation &participantData, const rpr2::TacticalStatusStruct &state) { if (m_playerMap.contains(participantData.equipmentNo)) return false; DEBUG_LOG(getLogger("NgsConnector.Outbound.Startup")) << "addGroundVehicle(" << participantData.equipmentNo << ", " << participantData.partyId << ", " << participantData.typeStruct.toString() << ", " << state.TacticalStatus << ")"; rpr2::IPlayerGuezGroundVehicleObjClass &player = m_somPlayer->getPlayerGuezGroundVehicleObjClass(); rpr2::IPlayerGuezGroundVehicleObjInstance *playerInstance = &player.newGuezGroundVehicleObjInstance(); DamageModel dm(state); playerInstance->setDamageState(dm.damageState(-1)); playerInstance->setImmobilized(dm.immobilized(-1)); playerInstance->setFirePowerDisabled(dm.firePowerDisabled(-1)); playerInstance->setTacticalStatus(state); return addPhysicalEntity(playerInstance, participantData); } bool NgsConnector::addBaseEntity(rpr2::IPlayerBaseEntityObjInstance *playerInstance, const ParticipantInformation &participantData) { if (m_playerMap.contains(participantData.equipmentNo)) return false; if (participantData.equipmentNo == 0) return false; IdentifierStruct is(participantData.equipmentNo); m_playerMap.insert(participantData.equipmentNo, playerInstance); playerInstance->setEntityType(participantData.typeStruct.toETS()); playerInstance->setEntityIdentifier(is.toEIS()); playerInstance->publish(getSimTime(participantData.position.msec)); DEBUG_LOG(getLogger("NgsConnector.Outbound.Startup")) << "Published Participant " << is.toString(); return true; } bool NgsConnector::addPhysicalEntity(rpr2::IPlayerPhysicalEntityObjInstance *playerInstance, const ParticipantInformation &playerData) { rpr2::MarkingStruct ms = toMarkingStruct(playerData.designator); playerInstance->setMarking(ms); rpr2::ForceIdentifierEnum8::ET forceId = rpr2::ForceIdentifierEnum8::ET::Other; //// m_ngsHandler->ppmHandler()->forceIdentifierFromPartyId(playerData.partyId); playerInstance->setForceIdentifier(forceId); rpr2::SpatialStruct ss(spatialStructFromWorldLocation(playerData.position.toWorldLocation())); playerInstance->setSpatial(ss); return addBaseEntity(playerInstance, playerData); } bool NgsConnector::removeBaseEntity(int eqNo) { if (!m_playerMap.contains(eqNo)) return false; DEBUG_LOG(getLogger("NgsConnector.Outbound.ShutDonw")) << "Participant " << eqNo << " removed."; m_playerMap[eqNo]->deleteObjectInstance(getSimTime()); return (m_playerMap.remove(eqNo) > 0); } bool NgsConnector::setParticipantName(int eqNo, const QString &designator) { rpr2::IPlayerPhysicalEntityObjInstance *playerInstance = dynamic_cast(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(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(m_observerPlayerInstances[eqId]); else if (m_playerMap.contains(eqId)) beObject = m_playerMap[eqId]; if (!beObject || !beObject->isValidEntityIdentifier()) return IdentifierStruct(); return IdentifierStruct(beObject->getEntityIdentifier()); } void NgsConnector::sendParticipantInitRequest(const int eqId, bool resetManipulation, bool resetVulnerabilityState, bool restockCharges, qint64 simTimeMSecs) { IdentifierStruct is = getIdentifierStructbyEquipmentNo(eqId); if (is.isNull() || is.isOwnElement()) return; if (!resetVulnerabilityState) { WARNING_LOG(getLogger("NgsConnector.Outbound.GuezInit")) << "Request to " << (resetManipulation ? "reset Manipulation" : "") << (resetManipulation && restockCharges ? " and " : "") << (restockCharges ? "restock Charges" : "") << " without resetting the Player " << eqId << " to CombatReady. Not supported."; return; } DEBUG_LOG(getLogger("NgsConnector.Outbound.GuezInit")) << "Request to " // << (resetManipulation ? "reset Manipulation" : "") // << (resetManipulation && restockCharges ? " and " : "") << (restockCharges ? "restock Charges" : "") << " for Player " << eqId << " to Combat Ready. (Reset Manipulation is implicit for SAAB)."; rpr2::IPlayerGuezInitIntClass &icx = m_somPlayer->getPlayerGuezInitIntClass(); rpr2::IPlayerGuezInitIntInstance *icb = &icx.newGuezInitIntInstance(); icb->setActivateHelmetObservation(rpr2::ActivateHelmetObservationEnum8::NoChange); icb->setEntityIdentifier(is.toEIS()); icb->setResetPlayer(restockCharges ? rpr2::ResetPlayerEnum8::CombatReadyWithReammunition : rpr2::ResetPlayerEnum8::CombatReadyWithoutReammunition); icb->publish(getSimTime(simTimeMSecs)); } void NgsConnector::sendParticipantBiteRequest(const int eqId, bool withSelfTest, qint64 simTimeMsecs) { IdentifierStruct is = getIdentifierStructbyEquipmentNo(eqId); if (is.isNull() || is.isOwnElement()) return; rpr2::IPlayerGuezRequestBiteReportIntClass &icx = m_somPlayer->getPlayerGuezRequestBiteReportIntClass(); rpr2::IPlayerGuezRequestBiteReportIntInstance *icb = &icx.newGuezRequestBiteReportIntInstance(); icb->setBiteReportType(withSelfTest ? rpr2::BiteReportTypeEnum8::StatusAfterSelftest : rpr2::BiteReportTypeEnum8::CurrentStatus); icb->setEntityIdentifier(is.toEIS()); icb->publish(getSimTime(simTimeMsecs)); DEBUG_LOG(getLogger("NgsConnector.Outbound.GuezBiteRequest")) << "Request for Bite Report for Player " << eqId << " with" << (withSelfTest ? "" : "out") << " selftest."; } bool NgsConnector::removeAesItem(int objId) { // get access rpr2::IPlayerGuezMineFieldObjInstance *icb = dynamic_cast(m_environmentObjects.value(objId)); if (icb) { icb->deleteObjectInstance(); // ??? (ngs::SimTime(true)); m_environmentObjects.remove(objId); // And we're done. Don't publish anything if called by startup. return true; } } bool NgsConnector::guezMineField(const WsTelegramMineFieldObject &data) { IdentifierStruct is ; //= IdentifierStruct::fromInt64(data.externalId()); const int objId = data.objectId; // assume unique rpr2::IPlayerGuezMineFieldObjClass &ic = m_somPlayer->getPlayerGuezMineFieldObjClass(); // create/update: rpr2::IPlayerGuezMineFieldObjInstance *icb = dynamic_cast(m_environmentObjects.value(objId)); if (!icb) icb = &ic.newGuezMineFieldObjInstance(); // // Check for removed (now), then delete the item. // if (icb && // (data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsExpired || // data.effectStateId() == AreaEffectSimulation::AesEffectState_def::EsRemoved)) // { // icb->deleteObjectInstance(ngs::SimTime(true)); // m_environmentObjects.remove(data.id()); // // And we're done. Don't publish anything if called by startup. // return true; // } icb->setActivationTime(getClockTimeStruct(data.activationTime)); icb->setDuration(data.duration); // icb->setMineType(getEtsCharge(data.chargeTypeId())); // icb->setMineCount((data.density() - 0.1) / 0.008); rpr2::ForceIdentifierEnum8::ET forceId = rpr2::ForceIdentifierEnum8::Other; icb->setForceIdentifier(forceId); // icb->setPointsData(positionArray(mineAreaSegment(segment, data.width(), data.density(), data.isCenterLine()))); // icb->setObjectType(dummyEOS()); // icb->publish(getSimTime(data.sampleTime())); m_environmentObjects.insert(objId, icb); return true; } //bool NgsConnector::setWorldLocation(int eqNo, const ParticipantPosition &pos, int eqNoHost) //{ // rpr2::IPlayerPhysicalEntityObjInstance *playerInstance = dynamic_cast(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(m_observerPlayerInstances.value(eqNoHost)); // // If found and valid data, fill IsPartOf struct and apply to player // if (observerInstanceHost && observerInstanceHost->isValidObjectName() && observerInstanceHost->isValidEntityIdentifier()) // { // cprs.Position = rpr2::ConstituentPartPositionEnum16::Inside; // rtiObjectIdHost.ID = observerInstanceHost->getObjectName(); // eis = observerInstanceHost->getEntityIdentifier(); // } // } // rpr2::IsPartOfStruct ipos; // ipos.HostEntityIdentifier = eis; // ipos.HostRTIObjectIdentifier = rtiObjectIdHost; // ipos.NamedLocation = nlStruct; // ipos.Relationship = cprs; // playerInstance->setIsPartOf(ipos); // playerInstance->setSpatial(ss); // playerInstance->publish(getSimTime(pos.msec)); // DEBUG_LOG(getLogger("NgsConnector.Outbound.Player.Position")) // << "Player: " << eqNo << ", Position: " << pos.toString() << ", Time: " << pos.msec << ", Mounted on: " << eqNoHost; // return true; //} ngs::SimTime NgsConnector::getSimTime(qint64 msecsSinceEpoch) { if (msecsSinceEpoch == 0) msecsSinceEpoch = QDateTime::currentDateTimeUtc().toMSecsSinceEpoch(); return ngs::SimTime(msecsSinceEpoch / 1000, (msecsSinceEpoch % 1000) * 1000); } ngs::SimTime NgsConnector::getSimTime(const QDateTime &dateTime) { return getSimTime(dateTime.toMSecsSinceEpoch()); } void NgsConnector::go() { if (!m_somPlayer) return; try { m_somPlayer->go(ngs::IObserver::GOSTEP); } catch (const NGSException &ex) { ERROR_LOG(m_logger) << "NGS Exception caught in Event Loop" << ex.print(); } catch (const std::exception &e) { ERROR_LOG(m_logger) << "Standard Exception caught in Event Loop: " << e.what(); } catch (...) { // ERROR_LOG(m_logger) << "Generic Exception caught in Event Loop"; } } void NgsConnector::onFirstTickFinished() { unsubscribeFromNgs(); m_bCanPublishData = true; subscribeAtNgs(); emit firstTickFinished(); } void NgsConnector::connectObserverObjectSignals(ObserverObjectCB *entity) { connect(entity, &ObserverObjectCB::newObjectInstance2, this, &NgsConnector::addObserverObjectInstance, Qt::UniqueConnection); connect(entity, &ObserverObjectCB::objectInstanceDeleted, this, &NgsConnector::removeObserverObjectInstance, Qt::UniqueConnection); } void NgsConnector::connectObserverBaseEntityObjectSignals(ObserverBaseEntityObjectCB *entity) { connectObserverObjectSignals(entity); connect(entity, &ObserverBaseEntityObjectCB::entityIdentifierChanged, this, &NgsConnector::onEntityIdentifierChanged, Qt::UniqueConnection); connect(entity, &ObserverBaseEntityObjectCB::spatialChanged, this, &NgsConnector::onSpatialChanged, Qt::UniqueConnection); connect(entity, &ObserverBaseEntityObjectCB::entityTypeChanged, this, &NgsConnector::onEntityTypeChanged, Qt::UniqueConnection); connect(entity, &ObserverBaseEntityObjectCB::isPartOfChanged, this, &NgsConnector::onIsPartOfChanged, Qt::UniqueConnection); } void NgsConnector::connectObserverPhysicalEntityObjectSignals(ObserverPhysicalEntityObjectCB *entity) { connectObserverBaseEntityObjectSignals(entity); connect(entity, &ObserverPhysicalEntityObjectCB::markingChanged, this, &NgsConnector::onMarkingChanged, Qt::UniqueConnection); connect(entity, &ObserverPhysicalEntityObjectCB::forceIdentifierChanged, this, &NgsConnector::onForceIdentifierChanged, Qt::UniqueConnection); } void NgsConnector::connectObserverPlatformObjectSignals(ObserverPlatformObjectCB *entity) { connectObserverPhysicalEntityObjectSignals(entity); // No extra signals } void NgsConnector::connectObserverGroundVehicleObjectSignals(ObserverGroundVehicleObjectCB *entity) { connectObserverPlatformObjectSignals(entity); // No extra signals } void NgsConnector::connectObserverGuezGroundVehicleObjectSignals(ObserverGuezGroundVehicleObjectCB *entity) { connectObserverGroundVehicleObjectSignals(entity); connect(entity, &ObserverGuezGroundVehicleObjectCB::tacticalStatusChanged, this, &NgsConnector::onTacticalStatusChanged, Qt::UniqueConnection); } void NgsConnector::connectObserverLifeformObjectSignals(ObserverLifeformObjectCB *entity) { connectObserverPhysicalEntityObjectSignals(entity); // No extra signals } void NgsConnector::connectObserverHumanObjectSignals(ObserverHumanObjectCB *entity) { connectObserverLifeformObjectSignals(entity); // No extra signals } void NgsConnector::connectObserverGuezHumanObjectSignals(ObserverGuezHumanObjectCB *entity) { connectObserverHumanObjectSignals(entity); connect(entity, &ObserverGuezHumanObjectCB::tacticalStatusChanged, this, &NgsConnector::onTacticalStatusChanged, Qt::UniqueConnection); } void NgsConnector::connectObserverGuezObserverControllerObjectSignals(ObserverGuezObserverControllerObjectCB *entity) { connectObserverHumanObjectSignals(entity); // No extra signals } void NgsConnector::connectObserverEnvironmentObjectObjectSignals(ObserverEnvironmentObjectObjectCB *entity) { connectObserverObjectSignals(entity); connect(entity, &ObserverEnvironmentObjectObjectCB::objectIdentifierChanged, this, &NgsConnector::onObjectIdentifierChanged, Qt::UniqueConnection); connect(entity, &ObserverEnvironmentObjectObjectCB::forceIdentifierChangedEO, this, &NgsConnector::onForceIdentifierChangedEO, Qt::UniqueConnection); connect(entity, &ObserverEnvironmentObjectObjectCB::spatialChanged, this, &NgsConnector::onSpatialChanged, Qt::UniqueConnection); } void NgsConnector::connectObserverArealObjectObjectSignals(ObserverArealObjectObjectCB *entity) { connectObserverEnvironmentObjectObjectSignals(entity); connect(entity, &ObserverArealObjectObjectCB::pointsDataChanged, this, &NgsConnector::onPointsDataChanged, Qt::UniqueConnection); connect(entity, &ObserverArealObjectObjectCB::percentCompleteChanged, this, &NgsConnector::onPercentCompleteChanged, Qt::UniqueConnection); connect(entity, &ObserverArealObjectObjectCB::deactivatedChanged, this, &NgsConnector::onDeactivatedChanged, Qt::UniqueConnection); } void NgsConnector::connectObserverPointObjectObjectSignals(ObserverPointObjectObjectCB *entity) { connectObserverEnvironmentObjectObjectSignals(entity); } void NgsConnector::connectObserverOtherArealObjectObjectSignals(ObserverOtherArealObjectObjectCB *entity) { connectObserverArealObjectObjectSignals(entity); } void NgsConnector::connectObserverOtherPointObjectObjectSignals(ObserverOtherPointObjectObjectCB *entity) { connectObserverPointObjectObjectSignals(entity); } void NgsConnector::connectObserverGuezMineFieldObjectSignals(ObserverGuezMineFieldObjectCB *entity) { connectObserverOtherArealObjectObjectSignals(entity); connect(entity, &ObserverGuezMineFieldObjectCB::areaEffectSimulationNameChanged, this, &NgsConnector::onAreaEffectSimulationNameChanged, Qt::UniqueConnection); connect(entity, &ObserverGuezMineFieldObjectCB::activationTimeChanged, this, &NgsConnector::onActivationTimeChanged, Qt::UniqueConnection); connect(entity, &ObserverGuezMineFieldObjectCB::durationChanged, this, &NgsConnector::onDurationChanged, Qt::UniqueConnection); connect(entity, &ObserverGuezMineFieldObjectCB::mineTypeChanged, this, &NgsConnector::onMineTypeChanged, Qt::UniqueConnection); } void NgsConnector::connectObserverGuezMineFieldBreachObjectSignals(ObserverGuezMineFieldBreachObjectCB *entity) { connectObserverOtherArealObjectObjectSignals(entity); connect(entity, &ObserverGuezMineFieldBreachObjectCB::areaEffectSimulationNameChanged, this, &NgsConnector::onAreaEffectSimulationNameChanged, Qt::UniqueConnection); connect(entity, &ObserverGuezMineFieldBreachObjectCB::activationTimeChanged, this, &NgsConnector::onActivationTimeChanged, Qt::UniqueConnection); } void NgsConnector::addObserverObjectInstance(const ngs::IObserverObjectInstance &obj) { // Put it into the Observer list later on, when the slot "onEntityIdentifierChanged()" is called // Then we can be sure, the EntityIdentifier is definetely set. const rpr2::IObserverBaseEntityObjInstance *beObject = dynamic_cast(&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(&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(&obj); const rpr2::IObserverEnvironmentObjectObjInstance *eoObject = dynamic_cast(&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(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 rpr2::ArrayOfWorldLocationStructDynamicHLAlengthlessVarArray NgsConnector::positionArray(const T &data) { rpr2::ArrayOfWorldLocationStructDynamicHLAlengthlessVarArray positions; if (data.size() == 0) return positions; positions.resize(data.size()); unsigned int i = 0; for (const auto &item : data) positions[i++] = ParticipantPosition(item).toWorldLocation(); return positions; } //QPolygonF NgsConnector::mineCorridorSegment(const Core::GeoPosition2D &start, const Core::GeoPosition2D &end, double width) //{ // QPointF startPoint(start.lon(), start.lat()); // QPointF endPoint(end.lon(), end.lat()); // LtsCoordTrans::UtmCoordinate startPositionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(startPoint); // LtsCoordTrans::UtmCoordinate endPositionUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(endPoint, startPositionUtm.zone); // QLineF lengthVector(QPointF(startPositionUtm.x, startPositionUtm.y), // QPointF(endPositionUtm.x, endPositionUtm.y)); // QPolygonF segment = QPolygonF({QPointF(0, width), // QPointF(lengthVector.length(), width), // QPointF(lengthVector.length(), 0), // QPointF(0, 0) // }); // segment.translate(QPointF(0, -(width / 2))); // segment = fromRotation(0 - lengthVector.angle()).map(segment); // return utmToGeogrphic(segment, startPositionUtm); //} template static inline T compass2rad(T degree) { static_assert(!std::is_integral::value, "Floating Point Value Required! Integer may be in Centidegree?!?"); return (M_PI / 2.0) - (degree * M_PI / 180.0); } template static inline T deg2rad(T degree) { static_assert(!std::is_integral::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 NgsConnector::bcReduction(const std::vector &form) //{ // std::vector 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 &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(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(obj); if (minefield) return addMinefield(minefield); const rpr2::IObserverGuezMineFieldBreachObjInstance *minefieldBreach = dynamic_cast(obj); if (minefieldBreach) return addMinefieldBreach(minefieldBreach); return false; } bool getCorridorSegment(const rpr2::ArrayOfWorldLocationStructDynamicHLAlengthlessVarArray &pointsDataIn, std::vector &segmentsOut, double &widthOut) { // P0 P3 // L *-------------------* L // i | | i // n * S0 S1 * n // e | | e // 1 *-------------------* 2 // P1 P2 // Calculate width = P0->P1 // Calculate S0, S1 if (pointsDataIn.size() != 4) return false; ParticipantPosition p0(pointsDataIn[0]); ParticipantPosition p1(pointsDataIn[1]); ParticipantPosition p2(pointsDataIn[2]); ParticipantPosition p3(pointsDataIn[3]); LtsCoordTrans::UtmCoordinate utmP0 = LtsCoordTrans::UtmCoordinate::fromGeographic(p0.toPoint()); LtsCoordTrans::UtmCoordinate utmP1 = LtsCoordTrans::UtmCoordinate::fromGeographic(p1.toPoint(), utmP0.zone); LtsCoordTrans::UtmCoordinate utmP2 = LtsCoordTrans::UtmCoordinate::fromGeographic(p2.toPoint(), utmP0.zone); LtsCoordTrans::UtmCoordinate utmP3 = LtsCoordTrans::UtmCoordinate::fromGeographic(p3.toPoint(), utmP0.zone); QLineF line1(utmP0.x, utmP0.y, utmP1.x, utmP1.y); widthOut = line1.length(); line1.setLength(0.5 * line1.length()); LtsCoordTrans::UtmCoordinate utmS0(utmP0.zone, line1.p2().x(), line1.p2().y(), utmP0.northp); QLineF line2(utmP2.x, utmP2.y, utmP3.x, utmP3.y); widthOut = line2.length(); line2.setLength(0.5 * line2.length()); LtsCoordTrans::UtmCoordinate utmS1(utmP0.zone, line2.p2().x(), line2.p2().y(), utmP0.northp); segmentsOut.resize(2); segmentsOut[0] = Core::GeoPosition2D(utmS0.geographic().x(), utmS0.geographic().y()); segmentsOut[1] = Core::GeoPosition2D(utmS1.geographic().x(), utmS1.geographic().y()); return true; } bool NgsConnector::addMinefield(const rpr2::IObserverGuezMineFieldObjInstance *minefield) { return false; /* int id = minefield->isValidObjectIdentifier() ? IdentifierStruct(minefield->getObjectIdentifier()).entityNumber() : 0; QTimer::singleShot(STATUS_WAIT_INTERVAL, this, [this, minefield, id]() mutable { if (!m_observerEnvironmentObjects.contains(id)) return; if (!minefield->isValidObjectIdentifier() || !minefield->isValidMineType() || !minefield->isValidMineCount() || !minefield->isValidActivationTime() || !minefield->isValidAreaEffectSimulationName() || !minefield->isValidForceIdentifier() || !minefield->isValidPointsData()) { ERROR_LOG(getLogger("NgsConnector.Inbound.MineField")) << "Wanted to create Minefield but not all necessary data is available yet. :("; return; } if (minefield->isValidPercentComplete() && minefield->getPercentComplete() > 99) return; IdentifierStruct is(minefield->getObjectIdentifier()); AreaEffectSimulation::MineAreaModifyRequest ma; const auto ct = m_ngsHandler->ppmHandler()->chargeTypeFromDisEntity(TypeStruct(minefield->getMineType()).toString()); ma.externalId(is.toInt64()); ma.chargeTypeId(ct.id()); ma.density(0.008 * minefield->getMineCount() + 0.1); // 0 -> 0.1 , 100 -> 0.9 ma.effectStart(getMSecsSinceEpoch(minefield->getActivationTime())); ma.name(minefield->getAreaEffectSimulationName().str()); if (minefield->isValidDuration()) ma.effectDuration(60LL * 60 * 1000 * minefield->getDuration()); // Hours to MSecs else ma.effectDuration(60LL * 60 * 1000 * 4); // 4 Hour Default int partyId = m_ngsHandler->ppmHandler()->partyIdFromForceIdentifier(minefield->getForceIdentifier()); ma.partyId(partyId); double width; std::vector segments; if (!getCorridorSegment(minefield->getPointsData(), segments, width)) { ERROR_LOG(getLogger("NgsConnector.Inbound.MineField")) << "Minefield Id: " << is.toString() << ", Name: " << ma.name() << ". Could not calculate segment from given points data."; return; } DEBUG_LOG(getLogger("NgsConnector.Inbound.MineField")) << "Minefield added/changed: Id: " << is.toString() << ", Name: " << ma.name(); ma.segments(segments); ma.width(width); ma.isCenterLine(true); emit newMinefield(ma); m_nonpublishedEnvironmentObjects.remove(id); }); return true; */ } bool NgsConnector::addMinefieldBreach(const rpr2::IObserverGuezMineFieldBreachObjInstance *minefieldBreach) { return false; /* QTimer::singleShot(STATUS_WAIT_INTERVAL, this, [this, minefieldBreach]() mutable { if (!minefieldBreach->isValidObjectIdentifier() || !minefieldBreach->isValidActivationTime() || !minefieldBreach->isValidAreaEffectSimulationName() || !minefieldBreach->isValidForceIdentifier() || !minefieldBreach->isValidPointsData()) return; IdentifierStruct is(minefieldBreach->getObjectIdentifier()); // If it was deleted, don't do anything! if (!m_observerEnvironmentObjects.contains(is.entityNumber())) return; AreaEffectSimulation::MineCorridorModifyRequest mc; mc.externalId(is.toInt64()); mc.effectStart(getMSecsSinceEpoch(minefieldBreach->getActivationTime())); mc.name(minefieldBreach->getAreaEffectSimulationName().str()); std::vector vec; double width; if (!getCorridorSegment(minefieldBreach->getPointsData(), vec, width)) { ERROR_LOG(getLogger("NgsConnector.Inbound.MineFieldBreach")) << "Minefield Breach Id: " << is.toString() << ", Name: " << mc.name() << ". Could not calculate segment from given points data."; return; } mc.segments(vec); mc.width(width); int partyId = m_ngsHandler->ppmHandler()->partyIdFromForceIdentifier(minefieldBreach->getForceIdentifier()); mc.partyId(partyId); DEBUG_LOG(getLogger("NgsConnector.Inbound.MineFieldBreach")) << "Minefield added/changed: Id: " << is.toString() << ", Name: " << mc.name(); emit newMinefieldBreach(mc); m_nonpublishedEnvironmentObjects.remove(is.entityNumber()); }); return true; */ } bool NgsConnector::onSpatialChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::WorldLocationStruct &wl, qint64 simTimeMSecs) { return false; /* IdentifierStruct is(eis); ParticipantPosition newParticipantPosition(wl); if (is.isOwnElement()) return true; ParticipantPosition &posInMapRef = m_observerPositions[is.entityNumber()]; if (!posInMapRef.hasMoved(newParticipantPosition)) //Hat sich die Position zum letzen Mal signifkant geändert? return true; DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.Position")) << "Player: " << is.toString() << ", Position: " << newParticipantPosition.toString() << ", Time: " << newParticipantPosition.msec; posInMapRef = newParticipantPosition; emit spatialChanged(is.entityNumber(), newParticipantPosition, simTimeMSecs); return true; */ } void NgsConnector::onEntityTypeChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::EntityTypeStruct &ets, qint64 simTimeMSecs) { Q_UNUSED(simTimeMSecs); IdentifierStruct is(eis); if (is.isOwnElement()) return; TypeStruct ts(ets); WARNING_LOG(getLogger("NgsConnector.Inbound.Player")) << "Player: " << is.toString() << ". New Entity Type: " << ts.toString() << ". This has no effect!"; // Todo? } void NgsConnector::onIsPartOfChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::IsPartOfStruct &ipos, qint64 simTimeMSecs) { // We cannot handle Saab players being mounted on GUEZ vehicles and vice versa as on radio the HOST (party A) tells about its mounted players, // whereas on HLA the player (party B) has to tell where he's mounted on. Party A's Excon cannot publish (IsPartOf) data of the player that // belongs to party B. IdentifierStruct is(eis); if (is.isOwnElement()) return; int eqNo = is.entityNumber(); int eqNoHost = ipos.HostEntityIdentifier.EntityNumber; DEBUG_LOG(getLogger("NgsConnector.Inbound.Player")) << "Player: " << is.toString() << " is now part of " << IdentifierStruct(ipos.HostEntityIdentifier).toString(); emit isPartOfChanged(eqNo, eqNoHost, simTimeMSecs); } bool NgsConnector::onMarkingChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::MarkingStruct &marking, qint64 simTimeMSecs) { IdentifierStruct is(eis); if (is.isOwnElement()) return true; QByteArray ba; for (size_t i = 0; i < marking.MarkingData.size(); ++i) ba += marking.MarkingData[i]; const QString str(QString::fromUtf8(ba)); DEBUG_LOG(getLogger("NgsConnector.Inbound.Object")) << "Object: " << is.toString() << " has new Marking: '" << str << "'."; emit markingChanged(eis.EntityNumber, str, simTimeMSecs); return true; } bool NgsConnector::onPointsDataChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::ArrayOfWorldLocationStructDynamicHLAlengthlessVarArray &points, qint64 simTimeMSecs) { IdentifierStruct is(eis); if (is.isOwnElement()) return true; if (!m_observerEnvironmentObjects.contains(is.entityNumber())) return false; if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber())) return false; std::vector pointsData; for (size_t i = 0; i < points.size(); ++i) pointsData.resize(pointsData.size() + 1, ParticipantPosition(points[i]).toGeoPosition2D()); DEBUG_LOG(getLogger("NgsConnector.Inbound.Object")) << "Object: " << is.toString() << " has new Points data (not printed) of size " << pointsData.size(); emit aesPointsDataChanged(is.toInt64(), pointsData, simTimeMSecs); return true; } bool NgsConnector::onForceIdentifierChanged(const rpr2::EntityIdentifierStruct &eis, rpr2::ForceIdentifierEnum8::ET identifier, qint64 simTimeMSecs) { Q_UNUSED(simTimeMSecs); IdentifierStruct is(eis); if (is.isOwnElement()) return true; WARNING_LOG(getLogger("NgsConnector.Inbound.Player")) << "Player: " << is.toString() << " has new Force Identifier: " << identifier << ". This has NO EFFECT."; return true; } bool NgsConnector::onForceIdentifierChangedEO(const rpr2::EntityIdentifierStruct &eis, rpr2::ForceIdentifierEnum8::ET identifier, qint64 simTimeMSecs) { Q_UNUSED(simTimeMSecs); IdentifierStruct is(eis); if (is.isOwnElement()) return true; if (!m_observerEnvironmentObjects.contains(is.entityNumber())) return false; if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber())) return false; DEBUG_LOG(getLogger("NgsConnector.Inbound.Object")) << "Object: " << is.toString() << " has new Force Identifier: " << identifier << ". Updating AES Item."; int partyId = -1; // = m_ngsHandler->ppmHandler()->partyIdFromForceIdentifier(identifier); emit aesForceIdentifierChanged(is.toInt64(), partyId); return true; } bool NgsConnector::onTacticalStatusChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::TacticalStatusStruct &rprStatus, qint64 simTimeMSecs) { IdentifierStruct is(eis); if (is.isOwnElement()) return true; ensureDamageModelExists(is); m_damageModelMap[is.entityNumber()]->setTacticalStatusStruct(rprStatus, simTimeMSecs); DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.Status")) << "Player: " << is.toString() << " New Total Status: " << rprStatus.TotalStatus << ", Tactical Status (unused): " << rprStatus.TacticalStatus; if (rprStatus.TotalStatus == rpr2::TotalStatusEnum32::CombatReady) { DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.Status")) << "New Status is CombarReady. Therfore we 'init' the player."; emit participantReceivedInit(is.entityNumber(), simTimeMSecs); return true; } // Todo: Tactical Status Change on SAAB players can occur at any time (without known reason). Therefore, we MUST handle this. // Change of Tactical Status with no other Interaction cannot be handled (at the moment). The Interaction forwards the status change to PPM. // Note: We could start a timer per eqNo. If the Timer is not deleted by an interaction that handles it, send it out. GuezHitStruct hitStruct; hitStruct.originatorChargeTypeEtsString = TypeStruct::fromDisInt(0).toString(); hitStruct.originatorId = 0; hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::Unknown; hitStruct.position = m_observerPositions[is.entityNumber()].toGeoPosition(); hitStruct.sampleTime = simTimeMSecs; hitStruct.targetId = is.entityNumber(); hitStruct.vulnerabilityState = ProjectDataManagement::VulnerabilityState_def::VulnerabilityBitsChanged; // --> Evaluate State from Bits (done in PPM Service). hitStruct.vulnerabilityKind = 0; const auto vulnerabilityBits = m_damageModelMap[is.entityNumber()]->totalState(hitStruct.sampleTime); hitStruct.vulnerabilityBits = (vulnerabilityBits & ~rpr2::TotalStatusEnum32::Manipulation); if (m_guezHitActive.contains(hitStruct.targetId)) { DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.StatusChange")) << "Tactical Status changed, but GuezHit was detected before. Not doing anything!"; return true; } QTimer::singleShot(Settings::guezHitGraceTimeMSecs(), this, [this, hitStruct]() mutable { if (m_guezHitActive.contains(hitStruct.targetId)) { DEBUG_LOG(getLogger("NgsConnector.Inbound.Player.StatusChange")) << "Tactical Status changed, Timeout happened, but GuezHit was detected before. Not doing anything!"; return; } WARNING_LOG(getLogger("NgsConnector.Inbound.Player.StatusChange")) << "Tactical Status changed, Timeout happened. NO corresponding GuezHit detected"; emit guezHit(hitStruct); }); return true; } bool NgsConnector::onDeactivatedChanged(const rpr2::EntityIdentifierStruct &eis, bool state, qint64 simTimeMSecs) { Q_UNUSED(simTimeMSecs); IdentifierStruct is(eis); if (is.isOwnElement()) return true; if (!m_observerEnvironmentObjects.contains(is.entityNumber())) return false; if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber())) return false; DEBUG_LOG(getLogger("NgsConnector.Inbound.Object")) << "Object: " << is.toString() << " has changed 'Deactivated' State. New State: " << state; if (state) // now deactivated { emit aesRemoveItem(is.toInt64()); // int activationTime = 0; // const rpr2::IObserverGuezMineFieldObjInstance *minefield = dynamic_cast(m_observerEnvironmentObjects[is.entityNumber()]); // if (minefield && minefield->isValidActivationTime()) // activationTime = getMSecsSinceEpoch(minefield->getActivationTime()); // const rpr2::IObserverGuezMineFieldBreachObjInstance *minefieldBreach = dynamic_cast(m_observerEnvironmentObjects[is.entityNumber()]); // if (minefieldBreach && minefieldBreach->isValidActivationTime()) // activationTime = getMSecsSinceEpoch(minefieldBreach->getActivationTime()); // // again! // if (activationTime > 0) // emit aesRemoveItem(is.toInt64()); } return true; } bool NgsConnector::onPercentCompleteChanged(const rpr2::EntityIdentifierStruct &eis, ngs::UINT32 state, qint64 simTimeMSecs) { Q_UNUSED(simTimeMSecs); IdentifierStruct is(eis); if (is.isOwnElement()) return true; DEBUG_LOG(getLogger("NgsConnector.Inbound.Object")) << "Object: " << is.toString() << " has changed 'Percent Complete'. New Completeness: " << state; // Find out, if it was active before // Todo: This might not work as the instance's deactivated flag most likely already is set... if (!m_observerEnvironmentObjects.contains(is.entityNumber())) return false; if (state > 99) emit aesRemoveItem(is.toInt64()); return true; } // Minefield // Minefield Breach void NgsConnector::onAreaEffectSimulationNameChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::OMT13string &value, qint64 simTimeMSecs) { Q_UNUSED(simTimeMSecs); IdentifierStruct is(eis); if (is.isOwnElement()) return; if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber())) return; if (!m_observerEnvironmentObjects.contains(eis.EntityNumber)) return; DEBUG_LOG(getLogger("NgsConnector.Inbound.Object")) << "Object: " << is.toString() << " has changed Name. New Name: " << QString::fromStdString(value); emit aesNameChanged(is.toInt64(), value); } // Minefield // Minefield Breach void NgsConnector::onActivationTimeChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::ClockTimeStruct &value, qint64 simTimeMSecs) { Q_UNUSED(simTimeMSecs); IdentifierStruct is(eis); if (is.isOwnElement()) return; if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber())) return; if (!m_observerEnvironmentObjects.contains(eis.EntityNumber)) return; qint64 msecs = getMSecsSinceEpoch(value); DEBUG_LOG(getLogger("NgsConnector.Inbound.Object")) << "Object: " << is.toString() << " has changed Activation Time: " << msecs; emit aesActivationTimeChanged(is.toInt64(), msecs); } // Minefield void NgsConnector::onDurationChanged(const rpr2::EntityIdentifierStruct &eis, ngs::UINT32 value, qint64 simTimeMSecs) { Q_UNUSED(simTimeMSecs); IdentifierStruct is(eis); if (is.isOwnElement()) return; if (m_nonpublishedEnvironmentObjects.contains(is.entityNumber())) return; if (!m_observerEnvironmentObjects.contains(eis.EntityNumber)) return; DEBUG_LOG(getLogger("NgsConnector.Inbound.Object")) << "Object: " << is.toString() << " has changed Duration: " << value; emit aesDurationChanged(is.toInt64(), value); } // Minefield void NgsConnector::onMineTypeChanged(const rpr2::EntityIdentifierStruct &eis, const rpr2::EntityTypeStruct &ets, qint64 simTimeMSecs) { IdentifierStruct is(eis); Q_UNUSED(simTimeMSecs); if (is.isOwnElement()) return; if (!m_observerEnvironmentObjects.contains(is.entityNumber())) return; if (m_observerEnvironmentObjects.contains(eis.EntityNumber)) return; // const auto ct = m_ngsHandler->ppmHandler()->chargeTypeFromDisEntity(TypeStruct(ets).toString()); // DEBUG_LOG(getLogger("NgsConnector.Inbound.Object")) // << "Object: " << is.toString() << " has changed Munition: " << ct.disEntity() << " / internal id: " << ct.id(); // emit aesChargeChanged(is.toInt64(), ct.id()); } // HLA -> DDS void NgsConnector::onNewMunitionDetonation(const rpr2::IObserverMunitionDetonationIntInstance &interaction) { // Own Item? if (std::stol(interaction.getEventIdentifier().IssuingObjectIdentifier.ID) == IdentifierStruct(0).toInt64()) return; // AreaEffectSimulation::ExplosionSingleModifyRequest req; // // req.altitude(); // const auto ct = m_ngsHandler->ppmHandler()->chargeTypeFromDisEntity(TypeStruct(interaction.getMunitionType()).toString()); // req.chargeTypeId(ct.id()); // req.id(0); // req.effectStart(QDateTime::currentDateTimeUtc().toMSecsSinceEpoch() + ACTIVATION_LEAD_TIME); // IdentifierStruct is(interaction.getEventIdentifier().EventCount); // is.setSiteId(255); // Dummy - Must not be of either site. // req.externalId(is.toInt64()); // dummy val, inserted to prevent aes_handler from dropping this telegram // req.fireRequestTime(QDateTime::currentDateTimeUtc().toMSecsSinceEpoch()); // req.impactPosition(ParticipantPosition(interaction.getDetonationLocation()).toGeoPosition2D()); // // IdentifierStruct is = IdentifierStruct::fromInt64(QString::fromStdString(interaction.getEventIdentifier().IssuingObjectIdentifier.ID).toLongLong()); // req.name(tr("SAAB Fire: %1").arg(interaction.getEventIdentifier().EventCount).toStdString()); // // Todo: If SAAB sends the Party in interaction.getFiringObjectIdentifier().ID like "F12" -> "ForceIdentifierEnum -> Value 12" // // req.partyId(interaction.getFiringObjectIdentifier()) // // req.purpose() // // req.rotation() // DEBUG_LOG(getLogger("NgsConnector.Inbound.MunitionDetonation")) // << "Munition Detonation: " // << "Location: " << ParticipantPosition(interaction.getDetonationLocation()).toString() // << ", Charge Type: " << ct.disEntity(); // emit munitionDetonation(req); } int NgsConnector::getEquipmentNoByRTIObjectId(const std::string &sender) const { // Own Players for (auto it(m_playerMap.cbegin()); it != m_playerMap.cend(); ++it) { if (it.value()->isValidObjectName()) { if (it.value()->getObjectName() == sender) return it.key(); } } // Saab Players for (auto it(m_observerPlayerInstances.cbegin()); it != m_observerPlayerInstances.cend(); ++it) { if (it.value()->isValidObjectName()) { if (it.value()->getObjectName() == sender) return it.key(); } } return 0; } // HLA -> DDS void NgsConnector::onNewWeaponFire(const rpr2::IObserverWeaponFireIntInstance &interaction) { // Self issued? if (std::stol(interaction.getEventIdentifier().IssuingObjectIdentifier.ID) == IdentifierStruct(0).toInt64()) return; // TrainingAreaBase::EquipmentGearEvent event; // event.equipmentNumber(getEquipmentNoByRTIObjectId(interaction.getFiringObjectIdentifier().ID)); // // only send for others, not for own players // if (m_playerMap.contains(event.equipmentNumber())) // return; // TrainingAreaBase::GearCharge charge; // const auto ct = m_ngsHandler->ppmHandler()->chargeTypeFromDisEntity(TypeStruct(interaction.getMunitionType()).toString()); // charge.chargeTypeId(ct.id()); // // charge.gearId(); // // charge.gearTypeId(); // // charge.remain(); // event.charge(charge); // event.chargeAmount(interaction.getQuantityFired()); // event.sampleTime(simTimeToMSec(interaction.getReceiveTimeStamp())); // DEBUG_LOG(getLogger("NgsConnector.Inbound.WeaponFire")) // << "Weapon Fire: EventID: " << interaction.getEventIdentifier().EventCount // << ", Charge Type: " << ct.disEntity() // << ", Shooter: " << event.equipmentNumber() // << ", Rounds: " << interaction.getQuantityFired() << ")"; // emit weaponFire(event); } void NgsConnector::onNewGuezHit(const rpr2::IObserverGuezHitIntInstance &interaction) { IdentifierStruct is(interaction.getTargetIdentifier()); if (is.isOwnElement()) return; if (!m_observerPlayerInstances.contains(is.entityNumber())) { ERROR_LOG(getLogger("NgsConnector.Inbound.GuezHit")) << "Player: " << is.toString() << ", but there's no observer Object for it."; return; } const int eqNo = interaction.getTargetIdentifier().EntityNumber; auto ptr = m_damageModelMap.value(eqNo); if (!ptr) { WARNING_LOG(getLogger("NgsConnector.Inbound.GuezHit")) << "Player: " << eqNo << ", Damage Model no longer exists. Not processing GuezHit!"; return; } ptr->setTacticalStatus(interaction.getHitResult(), simTimeToMSec(interaction.getReceiveTimeStamp())); GuezHitStruct hitStruct; hitStruct.originatorChargeTypeEtsString = TypeStruct(interaction.getMunition()).toString(); hitStruct.originatorId = interaction.getOriginatorIdentifier().EntityNumber; hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::Unknown; switch (interaction.getOriginatorType()) { case rpr2::OriginatorTypeEnum16::Unknown: hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::Unknown; break; case rpr2::OriginatorTypeEnum16::NoMedicalTreatment: // If no medical treatment has been conducted, and there's no originator, he's bleeding for himself... hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::Participant; if (hitStruct.originatorId == 0) // for sanity, there can't be a participant with EqId = 0 hitStruct.originatorId = hitStruct.targetId; break; case rpr2::OriginatorTypeEnum16::Participant: hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::Participant; if (hitStruct.originatorId == 0) // for sanity, there can't be a participant with EqId = 0 hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::ExerciseControl; break; case rpr2::OriginatorTypeEnum16::AreaEffectSimulation: hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::AreaEffectSimulation; hitStruct.originatorId = IdentifierStruct(interaction.getOriginatorIdentifier()).toInt64(); break; case rpr2::OriginatorTypeEnum16::ObserverController: hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::ObserverController; break; case rpr2::OriginatorTypeEnum16::ExerciseControl: hitStruct.originatorType = ProjectDataManagement::StateChangeOriginator_def::ExerciseControl; break; } hitStruct.position = ParticipantPosition(interaction.getTargetLocation()).toGeoPosition(); hitStruct.sampleTime = simTimeToMSec(interaction.getReceiveTimeStamp()); hitStruct.targetId = interaction.getTargetIdentifier().EntityNumber; // hitStruct.vulnerabilityState = ProjectDataManagement::VulnerabilityState_def::VulnerabilityBitsChanged; // --> Evaluate State from Bits (done in PPM Service). // hitStruct.vulnerabilityKind = 0; hitStruct.vulnerabilityState = getTacticalStatusEnum(interaction.getHitResult()); // HAck for resetting a player, whilst SAAB does not send the correct HitResult... if ((hitStruct.originatorType == ProjectDataManagement::StateChangeOriginator_def::ExerciseControl || hitStruct.originatorType == ProjectDataManagement::StateChangeOriginator_def::ObserverController ) && hitStruct.vulnerabilityState == ProjectDataManagement::VulnerabilityState_def::HitWithNoEffect) { auto ptr = m_damageModelMap.value(eqNo); if (ptr) { hitStruct.vulnerabilityState = ptr->vulnerabilityState(hitStruct.sampleTime); if (hitStruct.vulnerabilityState == ProjectDataManagement::VulnerabilityState_def::CombatReady) ptr->setTacticalStatus(rpr2::HitResultEnum16::Reset, simTimeToMSec(interaction.getReceiveTimeStamp())); } } DEBUG_LOG(getLogger("NgsConnector.Inbound.GuezHit")) << "Player: " << is.toString() << ", Originator Type: " << hitStruct.originatorType << ", Originator Id: " << hitStruct.originatorId << ", Charge Type: " << hitStruct.originatorChargeTypeEtsString << ", HitResult: " << hitStruct.vulnerabilityState; m_guezHitActive.insert(hitStruct.targetId); QTimer::singleShot(Settings::guezHitGraceTimeMSecs(), this, [this, hitStruct, eqNo]() mutable { auto ptr = m_damageModelMap.value(eqNo); if (!ptr) { WARNING_LOG(getLogger("NgsConnector.Inbound.GuezHit")) << "Player: " << eqNo << ", Damage Model no longer exists. Not processing GuezHit!"; return; } const auto vulnerabilityBits = ptr->totalState(hitStruct.sampleTime); hitStruct.vulnerabilityBits = (vulnerabilityBits & ~rpr2::TotalStatusEnum32::Manipulation); DEBUG_LOG(getLogger("NgsConnector.Inbound.GuezHit")) << "vBits: " << vulnerabilityBits; DEBUG_LOG(getLogger("NgsConnector.Inbound.GuezHit")) << "vState: " << hitStruct.vulnerabilityState; m_guezHitActive.remove(hitStruct.targetId); emit guezHit(hitStruct); }); } void NgsConnector::onNewGuezInit(const rpr2::IObserverGuezInitIntInstance &interaction) { // ExConEngagement FROM HLA TO US! Our Player shall be affected! IdentifierStruct is(interaction.getEntityIdentifier()); if (!is.isOwnElement()) return; if (!m_playerMap.contains(is.entityNumber())) { ERROR_LOG(getLogger("NgsConnector.Inbound.GuezInit")) << "Player: " << is.toString() << " is not our player..."; return; } rpr2::ResetPlayerEnum8::ET rp = interaction.getResetPlayer(); rpr2::ActivateHelmetObservationEnum8::ET aho = interaction.getActivateHelmetObservation(); bool resetVulnerabilityState = true; if (rp != rpr2::ResetPlayerEnum8::CombatReadyWithoutReammunition && rp != rpr2::ResetPlayerEnum8::CombatReadyWithReammunition) resetVulnerabilityState = false; if (aho != rpr2::ActivateHelmetObservationEnum8::NoChange) { WARNING_LOG(getLogger("NgsConnector.Inbound.GuezInit")) << "Player: " << is.toString() << "Incoming Activation Helmet/Vest on GuezInit not supported yet"; } DEBUG_LOG(getLogger("NgsConnector.Inbound.GuezInit")) << "Player: " << is.toString() << ", Reset Type: " << rp; emit guezInit(is.entityNumber(), false, rp == rpr2::ResetPlayerEnum8::CombatReadyWithReammunition, resetVulnerabilityState); } void NgsConnector::onNewGuezBiteReport(const rpr2::IObserverGuezBiteReportIntInstance &interaction) { IdentifierStruct is(interaction.getEntityIdentifier()); if (is.isOwnElement()) return; // TrainingAreaBase::EquipmentBite eb; // QStringList result; // bool leave = false; // if (!interaction.isValidBiteResult()) // { // result << QStringLiteral("BiteResult not valid"); // leave = true; // } // if (!interaction.isValidConfigurationComparisonResult()) // { // result << QStringLiteral("ConfigurationComparison not valid"); // leave = true; // } // if (!interaction.isValidDiscoveredDevices()) // { // result << QStringLiteral("DiscoveredDevices not valid"); // leave = true; // } // if (!interaction.isValidEntityIdentifier()) // { // result << QStringLiteral("EntityIdentifier not valid"); // leave = true; // } // if (!interaction.isValidRegistrationType()) // { // result << QStringLiteral("RegistrationType not valid"); // leave = true; // } // if (!interaction.isValidReportTime()) // { // result << QStringLiteral("ReportTime not valid"); // leave = true; // } // if (leave) // { // ERROR_LOG(getLogger("NgsConnector.Inbound.GuezBiteReport")) // << "Player: " << is.toString() // << ", Cannot process Interaction. Reason(s): " << result.join(QLatin1String(", ")); // return; // } // rpr2::BiteResultStruct brs = interaction.getBiteResult(); // eb.configState(brs.DeviceOkay); // eb.batteryState(brs.BatteryWarning); // std::vector 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::max(); evis.IssuingObjectIdentifier.ID = std::to_string(IdentifierStruct(0).toInt64()); if (m_eventCount > std::numeric_limits::max()) emit eventCountOverflow(); return evis; } rpr2::TacticalStatusStruct NgsConnector::getTacticalStatusFromState(const ParticipantManagement::StateInformation &state) { // rpr2::TacticalStatusStruct ts; // ts.TacticalStatus = static_cast(state.vulnerabilityState().underlying()); // ts.TotalStatus = static_cast(state.vulnerabilityBits()); // ts.VulnerabilityKind = state.vulnerabilityKindId(); // return ts; } bool NgsConnector::setVulnerabilityState(int eqNo, const ParticipantManagement::StateInformation &state) { return false; /* rpr2::TacticalStatusStruct ts = getTacticalStatusFromState(state); rpr2::IPlayerPhysicalEntityObjInstance *playerInstance = dynamic_cast(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(playerInstance); if (humanInstance) { humanInstance->setTacticalStatus(ts); playerInstance->publish(getSimTime(state.stateTime())); return true; } rpr2::IPlayerGuezGroundVehicleObjInstance *groundVehicleInstance = dynamic_cast(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(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(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(data.batteryState()); // brs.DeviceOkay = static_cast(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(data.biteState())); // icb->setEntityIdentifier(is.toEIS()); // icb->setRegistrationType(static_cast(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